fix(emcn): normalize MoreHorizontal and TerminalWindow geometry (#6265)

MoreVertical was migrated to the house geometry; MoreHorizontal was left
on its original 0 0 12 3 fill construction. Because that box is far wider
than it is tall, a square size class scales it by 14/12 and the dots
stretch edge to edge: 3.17px dots across a 14px span, where MoreVertical
draws 1.78px dots across 8.78px. The two are the same glyph rotated 90deg
and sit in the same overflow-menu role, so the mismatch is visible on any
row carrying one.

Redraw MoreHorizontal as the exact transpose of MoreVertical about
(10.25, 9.75). Both now measure 8.80px.

TerminalWindow had the same problem in the resource registry tab strip,
where ten icons render side by side at size-[14px]: it drew 14.00px
filled against neighbours at 10.30-12.05px on a 0.90px stroke. Redraw it
on the 24-box keeping its character - a window, a title bar, three chrome
dots. Now 10.85px.

Three call sites needed updating alongside the viewBox change:

- panel.tsx passed no size and sat in a Button, which does not force-size
  its svg children, so the icon would have jumped to its new 24x24
  intrinsic size inside a 30px button.
- The two sidebar size-[9px] values were compensations for the oversized
  glyph (9px against a 12-wide box happens to yield a ~9px span). Against
  the 24-box they would render 5.64px, so they move to size-[14px], which
  lands at 8.78px - exactly MoreVertical.
This commit is contained in:
Waleed
2026-08-04 14:37:03 -07:00
committed by GitHub
parent f0e57cb73f
commit b98dd8ba5e
4 changed files with 36 additions and 28 deletions
@@ -693,7 +693,7 @@ export const Panel = memo(function Panel() {
<DropdownMenu open={isMenuOpen} onOpenChange={setIsMenuOpen}>
<DropdownMenuTrigger asChild>
<Button className='size-[30px] rounded-[5px]'>
<MoreHorizontal />
<MoreHorizontal className='size-[14px]' />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align='start' side='bottom' sideOffset={8}>
@@ -271,7 +271,7 @@ const SidebarChatItem = memo(function SidebarChatItem({
isMenuOpen && 'opacity-100'
)}
>
<MoreHorizontal className='size-[9px] text-[var(--text-icon)]' />
<MoreHorizontal className='size-[14px] text-[var(--text-icon)]' />
</button>
</div>
)}
@@ -1612,7 +1612,7 @@ export const Sidebar = memo(function Sidebar({
{isImporting || isCreatingFolder ? (
<Loader className='h-[16px] w-[16px]' animate />
) : (
<MoreHorizontal className='size-[9px]' />
<MoreHorizontal className='size-[14px]' />
)}
</Button>
</DropdownMenuTrigger>
+16 -15
View File
@@ -2,31 +2,32 @@ import type { SVGProps } from 'react'
/**
* MoreHorizontal icon component (three horizontal dots)
*
* The exact transpose of {@link MoreVertical} about (10.25, 9.75) — same radius,
* same stroke, same 6-unit spacing. The two are the same glyph rotated 90deg and
* appear in the same overflow-menu role, so they must match by construction
* rather than by coincidence.
*
* @param props - SVG properties including className, fill, etc.
*/
export function MoreHorizontal(props: SVGProps<SVGSVGElement>) {
return (
<svg
width='12'
height='3'
viewBox='0 0 12 3'
width='24'
height='24'
viewBox='-1 -2 24 24'
fill='none'
stroke='currentColor'
strokeWidth='1.55'
strokeLinecap='round'
strokeLinejoin='round'
xmlns='http://www.w3.org/2000/svg'
aria-hidden='true'
{...props}
>
<path
d='M10.64 2.72C10.46 2.72 10.29 2.68 10.122 2.61C9.96 2.54 9.81 2.44 9.68 2.32C9.56 2.19 9.46 2.04 9.39 1.88C9.32 1.71 9.28 1.54 9.28 1.36C9.28 1.18 9.32 1 9.39 0.84C9.45 0.67 9.55 0.52 9.68 0.4C9.81 0.27 9.96 0.17 10.12 0.1C10.286 0.04 10.46 5.74e-05 10.641 7.02e-08C11 0 11.35 0.14 11.6 0.4C11.86 0.65 12 1 12 1.36C12 1.72 11.86 2.06 11.6 2.32C11.35 2.57 11 2.72 10.64 2.72Z'
fill='currentColor'
/>
<path
d='M6 2.72C6.75 2.72 7.36 2.11 7.36 1.36C7.36 0.61 6.75 0 6 0C5.25 0 4.64 0.61 4.64 1.36C4.64 2.11 5.25 2.72 6 2.72Z'
fill='currentColor'
/>
<path
d='M1.36 2.72C2.11 2.72 2.72 2.11 2.72 1.36C2.72 0.61 2.11 0 1.36 0C0.61 0 0 0.61 0 1.36C0 2.11 0.61 2.72 1.36 2.72Z'
fill='currentColor'
/>
<circle cx='4.25' cy='9.75' r='0.75' />
<circle cx='10.25' cy='9.75' r='0.75' />
<circle cx='16.25' cy='9.75' r='0.75' />
</svg>
)
}
+17 -10
View File
@@ -2,26 +2,33 @@ import type { SVGProps } from 'react'
/**
* Terminal window icon component
*
* Redrawn on the house geometry (24-box, 1.55 stroke, round joins) so it sits at
* the weight of the icons it shares the resource registry tab strip with. The
* original character is kept: a window with a title bar and three chrome dots.
*
* @param props - SVG properties including className, fill, etc.
*/
export function TerminalWindow(props: SVGProps<SVGSVGElement>) {
return (
<svg
width='16'
height='14'
viewBox='0 0 16 14'
width='24'
height='24'
viewBox='-1 -2 24 24'
fill='none'
stroke='currentColor'
strokeWidth='1.55'
strokeLinecap='round'
strokeLinejoin='round'
xmlns='http://www.w3.org/2000/svg'
aria-hidden='true'
{...props}
>
<path
d='M3 0C1.34 0 0 1.34 0 3V11C0 12.66 1.34 14 3 14H13C14.66 14 16 12.66 16 11V3C16 1.34 14.66 0 13 0H3ZM1 3C1 1.9 1.9 1 3 1H13C14.1 1 15 1.9 15 3V4H1V3ZM1 5H15V11C15 12.1 14.1 13 13 13H3C1.9 13 1 12.1 1 11V5Z'
fill='currentColor'
/>
<circle cx='3.5' cy='2.5' r='0.75' fill='currentColor' />
<circle cx='5.75' cy='2.5' r='0.75' fill='currentColor' />
<circle cx='8' cy='2.5' r='0.75' fill='currentColor' />
<path d='M3.75 2.75H16.75A2 2 0 0 1 18.75 4.75V14.75A2 2 0 0 1 16.75 16.75H3.75A2 2 0 0 1 1.75 14.75V4.75A2 2 0 0 1 3.75 2.75Z' />
<path d='M1.75 6.75H18.75' />
<circle cx='4.5' cy='4.75' r='0.5' />
<circle cx='7' cy='4.75' r='0.5' />
<circle cx='9.5' cy='4.75' r='0.5' />
</svg>
)
}