Skip to content

Commit ffeea3a

Browse files
committed
improvement(ui): share sidebar overflow and action overlays
1 parent fae85a0 commit ffeea3a

13 files changed

Lines changed: 275 additions & 267 deletions

File tree

‎apps/sim/app/o/[organizationId]/components/organization-sidebar/components/chats-section/chats-section.tsx‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,20 @@
11
'use client'
22

3-
import { chipVariants, cn, DropdownMenuItem, OverflowText } from '@sim/emcn'
3+
import {
4+
chipVariants,
5+
cn,
6+
DropdownMenuItem,
7+
OverflowText,
8+
RowActions,
9+
rowActionsGroupClass,
10+
} from '@sim/emcn'
411
import { MoreHorizontal, Pin, Task } from '@sim/emcn/icons'
512
import type { OrganizationChat } from '@/app/o/[organizationId]/components/organization-sidebar/hooks'
613
import { useOrganizationChatActions } from '@/app/o/[organizationId]/components/organization-sidebar/hooks/use-organization-chat-actions'
714
import {
815
ChatNavigationLink,
916
CollapsedChatFlyoutItem,
1017
CollapsedSidebarMenu,
11-
SidebarRowActions,
1218
SidebarSection,
1319
} from '@/app/workspace/[workspaceId]/w/components/sidebar/components'
1420
import { SidebarRenameRow } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-rename-row'
@@ -51,12 +57,12 @@ function ChatRow({
5157
isCurrentRoute={isCurrentRoute}
5258
className={cn(
5359
chipVariants({ active: isCurrentRoute || isMenuOpen, fullWidth: true }),
54-
'group/sidebar-row'
60+
rowActionsGroupClass
5561
)}
5662
onContextMenu={(e) => onContextMenu(e, chat.id)}
5763
>
5864
<OverflowText label={chat.name} className='flex-1 text-[var(--text-body)]' />
59-
<SidebarRowActions
65+
<RowActions
6066
open={isMenuOpen}
6167
indicator={
6268
showStatusDot ? (
@@ -81,7 +87,7 @@ function ChatRow({
8187
>
8288
<MoreHorizontal className='size-[14px] text-[var(--text-icon)]' />
8389
</SidebarRowAction>
84-
</SidebarRowActions>
90+
</RowActions>
8591
</ChatNavigationLink>
8692
)
8793
}

‎apps/sim/app/o/[organizationId]/components/organization-sidebar/components/workspaces-section/workspace-list.tsx‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
DropdownMenuItem,
88
DropdownMenuItemAction,
99
OverflowText,
10+
RowActions,
11+
rowActionsGroupClass,
1012
toast,
1113
} from '@sim/emcn'
1214
import { MoreHorizontal, Pin } from '@sim/emcn/icons'
@@ -17,10 +19,7 @@ import { WorkspaceContextMenu } from '@/components/workspaces/workspace-context-
1719
import { getWorkspaceInitial } from '@/lib/workspaces/initials'
1820
import { useOrganizationWorkspaces } from '@/app/o/[organizationId]/components/organization-sidebar/hooks/use-organization-workspaces'
1921
import { SidebarRenameRow } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-rename-row'
20-
import {
21-
SidebarRowAction,
22-
SidebarRowActions,
23-
} from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions'
22+
import { SidebarRowAction } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions'
2423
import { useFlyoutInlineRename } from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-flyout-inline-rename'
2524
import type { useHoverMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/hooks/use-hover-menu'
2625
import { useToggleWorkspacePin, useUpdateWorkspace } from '@/hooks/queries/workspace'
@@ -176,12 +175,12 @@ export function WorkspaceList({ organizationId, pathname, flyout }: WorkspaceLis
176175
href={href}
177176
className={cn(
178177
chipVariants({ active: isActive || isMenuOpen, fullWidth: true }),
179-
'group/sidebar-row'
178+
rowActionsGroupClass
180179
)}
181180
onContextMenu={(event) => openMenu(event, workspace.id)}
182181
>
183182
{label}
184-
<SidebarRowActions
183+
<RowActions
185184
open={isMenuOpen}
186185
indicator={
187186
isPinned ? (
@@ -201,7 +200,7 @@ export function WorkspaceList({ organizationId, pathname, flyout }: WorkspaceLis
201200
>
202201
<MoreHorizontal className='size-[14px] text-[var(--text-icon)]' />
203202
</SidebarRowAction>
204-
</SidebarRowActions>
203+
</RowActions>
205204
</SettingsGuardedLink>
206205
)
207206
})}

‎apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/index.ts‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export { SidebarRowActions } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions'
21
export { ChatNavigationLink } from './chat-navigation-link/chat-navigation-link'
32
export {
43
CollapsedChatFlyoutItem,

‎apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions.tsx‎

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,4 @@
1-
import { type ButtonHTMLAttributes, forwardRef, type ReactNode } from 'react'
2-
import { cn } from '@sim/emcn'
3-
4-
interface SidebarRowActionsProps {
5-
children: ReactNode
6-
indicator?: ReactNode
7-
open?: boolean
8-
revealOnHover?: boolean
9-
}
10-
11-
/** Reclaims idle action space while retaining indicators and touch/keyboard access. */
12-
export function SidebarRowActions({
13-
children,
14-
indicator,
15-
open = false,
16-
revealOnHover = true,
17-
}: SidebarRowActionsProps) {
18-
return (
19-
<div
20-
className={cn(
21-
'relative size-[18px] shrink-0 items-center justify-center gap-1.5 [@media(hover:none)]:w-auto',
22-
indicator || open ? 'flex' : 'hidden',
23-
revealOnHover &&
24-
'group-focus-within/sidebar-row:flex group-hover/sidebar-row:flex [@media(hover:none)]:flex'
25-
)}
26-
>
27-
{indicator && (
28-
<span
29-
className={cn(
30-
'pointer-events-none flex size-[18px] shrink-0 items-center justify-center transition-opacity',
31-
open && '[@media(hover:hover)]:opacity-0',
32-
revealOnHover &&
33-
'[@media(hover:hover)]:group-focus-within/sidebar-row:opacity-0 [@media(hover:hover)]:group-hover/sidebar-row:opacity-0'
34-
)}
35-
>
36-
{indicator}
37-
</span>
38-
)}
39-
<div
40-
className={cn(
41-
'pointer-events-none absolute inset-0 flex items-center justify-center opacity-0 transition-opacity [@media(hover:none)]:static',
42-
open && 'pointer-events-auto opacity-100',
43-
revealOnHover &&
44-
'group-focus-within/sidebar-row:pointer-events-auto group-focus-within/sidebar-row:opacity-100 group-hover/sidebar-row:pointer-events-auto group-hover/sidebar-row:opacity-100 [@media(hover:none)]:pointer-events-auto [@media(hover:none)]:opacity-100'
45-
)}
46-
>
47-
{children}
48-
</div>
49-
</div>
50-
)
51-
}
1+
import { type ButtonHTMLAttributes, forwardRef } from 'react'
522

533
interface SidebarRowActionProps
544
extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'type'> {

‎apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/folder-item/folder-item.tsx‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
cn,
88
disclosureChevronClass,
99
OverflowText,
10+
RowActions,
11+
rowActionsGroupClass,
1012
toast,
1113
} from '@sim/emcn'
1214
import { ChevronRight, Folder, FolderOpen, Lock, MoreHorizontal } from '@sim/emcn/icons'
@@ -17,10 +19,7 @@ import { useRouter } from 'next/navigation'
1719
import { SIM_RESOURCES_DRAG_TYPE } from '@/lib/mothership/resource-types'
1820
import { generateSubfolderName } from '@/lib/workspaces/naming'
1921
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
20-
import {
21-
SidebarRowAction,
22-
SidebarRowActions,
23-
} from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions'
22+
import { SidebarRowAction } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions'
2423
import { ContextMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/context-menu/context-menu'
2524
import { DeleteModal } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/delete-modal/delete-modal'
2625
import {
@@ -504,7 +503,7 @@ export const FolderItem = memo(function FolderItem({ workspaceId, folder }: Fold
504503
aria-label={`${folder.name} folder, ${isExpanded ? 'expanded' : 'collapsed'}`}
505504
className={cn(
506505
chipVariants({ active: isSelected || isContextMenuOpen, fullWidth: true }),
507-
'group/sidebar-row',
506+
rowActionsGroupClass,
508507
(isDragging || (isAnyDragActive && isSelected)) && 'opacity-50'
509508
)}
510509
onClick={handleFolderSelect}
@@ -550,7 +549,7 @@ export const FolderItem = memo(function FolderItem({ workspaceId, folder }: Fold
550549
>
551550
<OverflowText label={folder.name} className='flex-1 text-[var(--text-body)]' />
552551
</div>
553-
<SidebarRowActions
552+
<RowActions
554553
open={isContextMenuOpen}
555554
revealOnHover={!isAnyDragActive}
556555
indicator={
@@ -571,7 +570,7 @@ export const FolderItem = memo(function FolderItem({ workspaceId, folder }: Fold
571570
>
572571
<MoreHorizontal className='size-[16px] text-[var(--text-icon)]' />
573572
</SidebarRowAction>
574-
</SidebarRowActions>
573+
</RowActions>
575574
</div>
576575
)}
577576
</div>

‎apps/sim/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/workflow-item.tsx‎

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
'use client'
22

33
import { memo, useCallback, useMemo, useRef, useState } from 'react'
4-
import { chipVariants, cn, OverflowText } from '@sim/emcn'
4+
import { chipVariants, cn, OverflowText, RowActions, rowActionsGroupClass } from '@sim/emcn'
55
import { Lock, MoreHorizontal } from '@sim/emcn/icons'
66
import Link from 'next/link'
77
import { SIM_RESOURCES_DRAG_TYPE } from '@/lib/mothership/resource-types'
88
import { useUserPermissionsContext } from '@/app/workspace/[workspaceId]/providers/workspace-permissions-provider'
9-
import {
10-
SidebarRowAction,
11-
SidebarRowActions,
12-
} from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions'
9+
import { SidebarRowAction } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/sidebar-row-actions'
1310
import { ContextMenu } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/context-menu/context-menu'
1411
import { DeleteModal } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/delete-modal/delete-modal'
1512
import { Avatars } from '@/app/workspace/[workspaceId]/w/components/sidebar/components/workflow-list/components/workflow-item/avatars/avatars'
@@ -414,7 +411,7 @@ export const WorkflowItem = memo(function WorkflowItem({
414411
active: active || isContextMenuOpen || (isSelected && selectedWorkflows.size > 1),
415412
fullWidth: true,
416413
}),
417-
'group/sidebar-row',
414+
rowActionsGroupClass,
418415
(isDragging || (isAnyDragActive && isSelected)) && 'opacity-50'
419416
)}
420417
draggable={!isEditing && !dragDisabled && !effectiveLocked}
@@ -453,7 +450,7 @@ export const WorkflowItem = memo(function WorkflowItem({
453450
</div>
454451
</div>
455452
{!isEditing && (
456-
<SidebarRowActions
453+
<RowActions
457454
open={isContextMenuOpen}
458455
revealOnHover={!isAnyDragActive}
459456
indicator={
@@ -474,7 +471,7 @@ export const WorkflowItem = memo(function WorkflowItem({
474471
>
475472
<MoreHorizontal className='size-[16px] text-[var(--text-icon)]' />
476473
</SidebarRowAction>
477-
</SidebarRowActions>
474+
</RowActions>
478475
)}
479476
</Link>
480477

‎apps/sim/app/workspace/[workspaceId]/w/components/sidebar/sidebar.tsx‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
Library,
1616
Loader,
1717
OverflowText,
18+
RowActions,
19+
rowActionsGroupClass,
1820
scrollFadeAttributes,
1921
scrollFadeClass,
2022
Tooltip,
@@ -75,7 +77,6 @@ import {
7577
SidebarFooter,
7678
SidebarNavChip,
7779
type SidebarNavItemData,
78-
SidebarRowActions,
7980
SidebarSection,
8081
SidebarTooltip,
8182
StatusNotice,
@@ -245,7 +246,7 @@ const SidebarChatItem = memo(function SidebarChatItem({
245246
active: isCurrentRoute || isSelected || isMenuOpen,
246247
fullWidth: true,
247248
}),
248-
'group/sidebar-row'
249+
rowActionsGroupClass
249250
)}
250251
onClick={(e) => {
251252
if (e.metaKey || e.ctrlKey) return
@@ -263,7 +264,7 @@ const SidebarChatItem = memo(function SidebarChatItem({
263264
>
264265
<OverflowText label={chat.name} className='flex-1 text-[var(--text-body)]' />
265266
{chat.id !== 'new' && (
266-
<SidebarRowActions
267+
<RowActions
267268
open={isMenuOpen}
268269
indicator={
269270
showStatusDot ? (
@@ -288,7 +289,7 @@ const SidebarChatItem = memo(function SidebarChatItem({
288289
>
289290
<MoreHorizontal className='size-[14px] text-[var(--text-icon)]' />
290291
</SidebarRowAction>
291-
</SidebarRowActions>
292+
</RowActions>
292293
)}
293294
</ChatNavigationLink>
294295
</SidebarTooltip>

‎packages/emcn/src/components/dropdown-menu/dropdown-menu.tsx‎

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import * as React from 'react'
2424
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
25+
import { RowActions, rowActionsGroupClass } from '@sim/emcn'
2526
import { cva, type VariantProps } from 'class-variance-authority'
2627
import { Check, ChevronRight, Circle, Search } from '../../icons'
2728
import { cn } from '../../lib/cn'
@@ -375,7 +376,7 @@ const DropdownMenuItem = React.forwardRef<
375376
if (action) {
376377
return (
377378
<div
378-
className='group/dropdownitem relative'
379+
className={cn('group/dropdownitem relative', rowActionsGroupClass)}
379380
onKeyDown={(event) => {
380381
if (
381382
event.defaultPrevented ||
@@ -412,7 +413,9 @@ const DropdownMenuItem = React.forwardRef<
412413
actionIndicator || actionOpen
413414
? 'pr-[28px]'
414415
: '[@media(hover:hover)]:group-focus-within/dropdownitem:pr-[28px] [@media(hover:hover)]:group-hover/dropdownitem:pr-[28px]',
415-
actionIndicator ? '[@media(hover:none)]:pr-[52px]' : '[@media(hover:none)]:pr-[28px]',
416+
actionIndicator
417+
? '[@media(any-pointer:coarse)]:pr-[52px] [@media(hover:none)]:pr-[52px]'
418+
: '[@media(any-pointer:coarse)]:pr-[28px] [@media(hover:none)]:pr-[28px]',
416419
inset && 'pl-7',
417420
className
418421
)}
@@ -421,27 +424,14 @@ const DropdownMenuItem = React.forwardRef<
421424
>
422425
{content}
423426
</DropdownMenuPrimitive.Item>
424-
<div className='-translate-y-1/2 pointer-events-none absolute top-1/2 right-1 flex size-[18px] items-center gap-1.5 [@media(hover:none)]:w-auto'>
425-
{actionIndicator && (
426-
<div
427-
className={cn(
428-
'pointer-events-none flex size-[18px] shrink-0 items-center justify-center [@media(hover:hover)]:group-focus-within/dropdownitem:opacity-0 [@media(hover:hover)]:group-hover/dropdownitem:opacity-0',
429-
actionOpen && '[@media(hover:hover)]:opacity-0'
430-
)}
431-
>
432-
{actionIndicator}
433-
</div>
434-
)}
435-
<div
436-
ref={actionRef}
437-
className={cn(
438-
'pointer-events-none absolute inset-0 flex items-center opacity-0 transition-opacity group-focus-within/dropdownitem:pointer-events-auto group-focus-within/dropdownitem:opacity-100 group-hover/dropdownitem:pointer-events-auto group-hover/dropdownitem:opacity-100 [@media(hover:none)]:pointer-events-auto [@media(hover:none)]:static [@media(hover:none)]:opacity-100',
439-
actionOpen && 'pointer-events-auto opacity-100'
440-
)}
441-
>
442-
{action}
443-
</div>
444-
</div>
427+
<RowActions
428+
indicator={actionIndicator}
429+
open={actionOpen}
430+
actionRef={actionRef}
431+
className='-translate-y-1/2 absolute top-1/2 right-1'
432+
>
433+
{action}
434+
</RowActions>
445435
</div>
446436
)
447437
}

‎packages/emcn/src/components/index.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ export {
213213
} from './popover/popover'
214214
export { POPOVER_ANIMATION_CLASSES } from './popover/popover-animation'
215215
export { ProgressItem } from './progress-item/progress-item'
216+
export { RowActions, type RowActionsProps, rowActionsGroupClass } from './row-actions/row-actions'
216217
export { SecretInput } from './secret-input/secret-input'
217218
export { SecretReveal } from './secret-reveal/secret-reveal'
218219
export { WORDMARK_PATHS, WORDMARK_VIEW_BOX } from './sim-wordmark/paths'
@@ -229,7 +230,6 @@ export {
229230
} from './status-page/status-page'
230231
export { Switch } from './switch/switch'
231232
export {
232-
isTabTitleTruncated,
233233
TabStrip,
234234
type TabStripDragContext,
235235
type TabStripItem,

0 commit comments

Comments
 (0)