Skip to content

Commit 28abfc7

Browse files
committed
chore(plan): sync staging while preserving feature gates
2 parents 554683d + b1c1be0 commit 28abfc7

489 files changed

Lines changed: 73473 additions & 10978 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/rules/emcn-components.md‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Never hand-roll the chip pill from raw class strings (they go stale). Compose fr
1717

1818
Canonical look: normal font-weight (never `font-medium`/`font-semibold`), value text `--text-body`, icons `--text-icon` at `size-[14px]`, placeholder `--text-muted`, `transition-colors`, **no focus ring** (the caret marks focus). Filled surface is `--surface-5` light / `--surface-4` dark with a `--border` border (`chip-chrome.ts` still spells it through the legacy alias `--border-1`; new code writes `--border`).
1919

20-
The menu surface intentionally diverges from the pill: `dropdown-menu.tsx` items use `text-small` and `gap-2` (a menu convention, not the chip pill). Keep them distinct.
20+
`MENU_STYLES` in `dropdown-menu/styles.ts` owns the shared dropdown, picker-list, and popover chrome. Its default menu rows are 28px at `text-small`; chip pills remain 30px at `text-sm`. Menus reuse the chip gap, row radius, and search-field surface and typography, with a 12px outer radius, 4px padding, and `shadow-medium`. Compose these tokens instead of overriding chrome at call sites. Within the package, shared initialization-time tokens use private imports to avoid public-barrel cycles; consumers import `MENU_STYLES` from `@sim/emcn`.
2121

2222
## Component catalogue
2323

@@ -26,13 +26,13 @@ The menu surface intentionally diverges from the pill: `dropdown-menu.tsx` items
2626
- **`ChipCopyInput`** — the canonical view-only field: a read-only `ChipInput` at full opacity with a trailing copy-to-clipboard button. View-only is a display mode, not a disabled state — reach for it (or `ChipModalField type='copy'`) over a `disabled` (greyed) input for values the user cannot edit.
2727
- **`ChipTextarea`** — multi-line sibling. `error`, `resizable` (off by default), `viewOnly` (read-only at full opacity with the default cursor — the multi-line counterpart of `ChipCopyInput`).
2828
- **`ChipDropdown`** — pill that opens a menu. Single OR multi-select via the discriminated `multiple` prop (one component, not two). Owns its trailing chevron — no `rightIcon`.
29-
- **`ChipSelect` / `ChipCombobox`** — `Combobox`-backed pickers with search, groups, multi-select; for richer lists than `ChipDropdown`.
29+
- **`ChipSelect` / `ChipCombobox`** — pickers with search, groups, and multi-select. `ChipSelect` uses `DropdownMenu`; `ChipCombobox` uses `Combobox` for editable input, async options, and virtualized lists. Both inherit the shared menu chrome.
3030
- **`ChipModal` + `ChipModalField`** — declarative compact modal. The field's `type` (`input` | `email` | `textarea` | `dropdown` | `copy` | `file` | `emails` | `custom`) picks the control and **owns all chrome** — consumers describe intent, never pass `variant`/`className`/`id` to the inner control. `custom` (with a `title`) is the escape hatch for controls the field doesn't cover. Every body field is a `ChipModalField`; the gutter rhythm that makes this matter is in `sim-styling.md` → "Form / chip-modal layout rhythm".
3131
- **`ChipSwitch`** — segmented pill control (built from `chipVariants`).
3232
- **`ChipTag`** — 20px inline tag/badge (`mono`/`gray`/`invite`), not a pill trigger.
3333
- **`ChipDatePicker`** — chip-styled date field.
3434
- **`ChipTimePicker`** — minute-granular time sibling of `ChipDatePicker`, a `ChipInput` that leniently parses typed input (`9:47`, `947`, `2:05pm`, `14:30`), commits on Enter/blur, and re-renders the canonical `9:47 AM` label.
35-
- **`DropdownMenu`** — the canonical context/action menu (Radix-backed). Not a chip, but the standard menu for command/action lists; reach for it instead of a hand-rolled popover. Its surface intentionally diverges from the chip pill (`text-small`, `gap-2`) — keep them distinct. For a pill that opens a value picker, use `ChipDropdown`/`ChipSelect` instead.
35+
- **`DropdownMenu`** — the canonical context/action menu (Radix-backed), styled through `MENU_STYLES`. Reach for it instead of a hand-rolled popover for command/action lists. For a pill that opens a value picker, use `ChipDropdown`/`ChipSelect` instead.
3636
- **`useScrollEdges` + `scrollFadeClass` / `scrollFadeAttributes`** — the canonical scroll-region edge treatment. The hook reports which edges hide content (tracking scroll and resizes; pass the element itself, held in state, when the region mounts after its owner, e.g. inside a Radix portal); the class and attributes fade a fixed 12px band at an active edge only, so a list that fits or sits at its top is never fogged. A floating control over the top edge sets `--scroll-fade-inset` to its height. A region that scrolls sideways (a tab row, a chip strip) uses `useScrollEdges(ref, { axis: 'x' })` with `scrollFadeXClass`; the attributes helper is shared. Any divider beside the region belongs to the neighboring block (`border-b` above, `border-t` below), never to the masked element, and shows only while that edge is active. Never hand-roll a `mask-image` gradient for a scroll region.
3737
- **`OverflowText`** — the canonical single-line overflow treatment for read-only human labels and titles. It owns `min-w-0`, fade-only clipping (never an ellipsis), the conditional 18px edge mask, and the full-value floating tooltip; consumers pass only layout/typography through `className`. `overflowTextClipClass` and `overflowTextFadeClass` are the complete base/faded treatments for the rare component that must own measurement itself; never pair either with `truncate`, `text-ellipsis`, or hover-time mask removal. Use `DropdownMenuItemLabel` for a menu label beside icons, checks, or actions. A non-editable `Combobox` passes the full visual value through `overlayLabel`; the combobox owns the visual overlay's fade and keeps its one accessible tooltip on the interactive layer. Keep ordinary `truncate` only for editable values, code/log/path content, dense or virtualized grids, and rich composite content that cannot supply a plain tooltip label. Multiline copy uses an intentional `line-clamp-*` treatment instead.
3838

‎.claude/rules/sim-settings-pages.md‎

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
description: Settings page layout and SettingsPanel design-system compliance
33
paths:
44
- "apps/sim/app/workspace/*/settings/**"
5+
- "apps/sim/app/o/*/settings/**"
56
- "apps/sim/app/workspace/*/{integrations,skills,upgrade}/**"
67
- "apps/sim/app/workspace/*/components/{resource-tile,credential-detail}/**"
78
- "apps/sim/components/{settings,permissions}/**"
@@ -10,14 +11,14 @@ paths:
1011

1112
# Settings Pages
1213

13-
The Next.js `settings/[section]/layout.tsx` owns all settings page chrome via
14+
Workspace and organization `settings/[section]/layout.tsx` own page chrome via
1415
`SettingsHeaderShell` — a fixed header bar (a left back chip + right-aligned
1516
action chips), a scroll region, and a centered `max-w-[48rem]` content column led
1617
by a **title + description from navigation metadata**. The chrome stays mounted
1718
across section navigation. Its routed title and description are available before
1819
the section body resolves. Each section renders through the **`SettingsPanel`**
1920
registrar
20-
(`@/app/workspace/[workspaceId]/settings/components/settings-panel`), which feeds
21+
(`@/components/settings/settings-panel`), which feeds
2122
the shell its header data and renders only the section body. Sections supply
2223
**data**, never chrome.
2324

@@ -34,7 +35,7 @@ shell (fed through `SettingsPanel`):
3435
## Canonical page shape
3536

3637
```tsx
37-
import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel'
38+
import { SettingsPanel } from '@/components/settings/settings-panel'
3839

3940
return (
4041
<SettingsPanel
@@ -228,11 +229,14 @@ and — on activatable rows only — the hover band. Never hand-roll any of it,
228229
renders the value paragraph itself; pass a node when the value needs its own
229230
presentation (a control, an icon beside the value, status styling).
230231
- **`SettingsEmptyState`** (`…/components/settings-empty-state`) — the canonical
231-
muted status message, for empty lists, "no results", loading gates, **and
232-
failed loads** (`tone='error'`). `variant='fill'` (default) centers in the
233-
available height; `variant='inline'` sits in flow. Never hand-roll
234-
`<div className='flex h-full items-center justify-center …'>` or
235-
`<div className='py-4 text-center …'>`.
232+
muted status message for empty lists, "no results", loading gates, and failed
233+
reads. `variant='fill'` (default) centers in the available height;
234+
`variant='inline'` sits in flow. Never hand-roll its layout.
235+
- **`SettingsQueryErrorState`** (same module) — the muted read-failure message
236+
with an accessible alert and retry control. Show an initial failure when data
237+
is unavailable; preserve cached content, mounted editors, and unsaved drafts
238+
during background failures, using an inline status. Validation and mutation
239+
failures retain their error styling.
236240
- **`RowActionsMenu`** (`…/components/row-actions-menu`) — the trailing `...`
237241
actions menu for a list row. Pass `label` (aria-label) and
238242
`actions: RowAction[]` (`{ label, onSelect, destructive?, disabled? }`); the
@@ -395,6 +399,6 @@ A settings page is design-system-clean when:
395399
- [ ] Every **resource** list row (a thing with an identity — a tool, a server, a key, a credential) is a `SettingsResourceRow` in a `RESOURCE_LIST_STACK`/`RESOURCE_LIST_GRID` — no wrapper `<button>`/`<Link>`, no hand-passed arrow, no re-derived title/subtitle spans. Rows with a genuinely different shape stay bespoke, and draw their own arrow with `RESOURCE_ROW_ARROW_CLASSES`: multi-line bodies (inbox tasks), tabular columns (billing invoices, credit usage), grids (secrets), and the member rows (see the avatar note above).
396400
- [ ] Rows that open a detail page use `navigable` + `clickLabel`; flat records use `RowActionsMenu`. Not both.
397401
- [ ] Decorative trailing content is in `badge`, not `trailing`.
398-
- [ ] Labeled sections use `SettingsSection`; read-only fields use `SettingsField`; empty/loading/error use `SettingsEmptyState`.
402+
- [ ] Labeled sections use `SettingsSection`; read-only fields use `SettingsField`; empty/loading/read-failure messages use `SettingsEmptyState`, with `SettingsQueryErrorState` when offering retry.
399403
- [ ] Delete is a plain `id:'delete'` header action behind a `ChipConfirmModal`; `destructive` is reserved for bulk actions.
400404
- [ ] The local gate in the root `CLAUDE.md` ("How your work is checked") passes.

‎.cursor/rules/emcn-components.mdc‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Never hand-roll the chip pill from raw class strings (they go stale). Compose fr
1818

1919
Canonical look: normal font-weight (never `font-medium`/`font-semibold`), value text `--text-body`, icons `--text-icon` at `size-[14px]`, placeholder `--text-muted`, `transition-colors`, **no focus ring** (the caret marks focus). Filled surface is `--surface-5` light / `--surface-4` dark with a `--border` border (`chip-chrome.ts` still spells it through the legacy alias `--border-1`; new code writes `--border`).
2020

21-
The menu surface intentionally diverges from the pill: `dropdown-menu.tsx` items use `text-small` and `gap-2` (a menu convention, not the chip pill). Keep them distinct.
21+
`MENU_STYLES` in `dropdown-menu/styles.ts` owns the shared dropdown, picker-list, and popover chrome. Its default menu rows are 28px at `text-small`; chip pills remain 30px at `text-sm`. Menus reuse the chip gap, row radius, and search-field surface and typography, with a 12px outer radius, 4px padding, and `shadow-medium`. Compose these tokens instead of overriding chrome at call sites. Within the package, shared initialization-time tokens use private imports to avoid public-barrel cycles; consumers import `MENU_STYLES` from `@sim/emcn`.
2222

2323
## Component catalogue
2424

@@ -27,13 +27,13 @@ The menu surface intentionally diverges from the pill: `dropdown-menu.tsx` items
2727
- **`ChipCopyInput`** — the canonical view-only field: a read-only `ChipInput` at full opacity with a trailing copy-to-clipboard button. View-only is a display mode, not a disabled state — reach for it (or `ChipModalField type='copy'`) over a `disabled` (greyed) input for values the user cannot edit.
2828
- **`ChipTextarea`** — multi-line sibling. `error`, `resizable` (off by default), `viewOnly` (read-only at full opacity with the default cursor — the multi-line counterpart of `ChipCopyInput`).
2929
- **`ChipDropdown`** — pill that opens a menu. Single OR multi-select via the discriminated `multiple` prop (one component, not two). Owns its trailing chevron — no `rightIcon`.
30-
- **`ChipSelect` / `ChipCombobox`** — `Combobox`-backed pickers with search, groups, multi-select; for richer lists than `ChipDropdown`.
30+
- **`ChipSelect` / `ChipCombobox`** — pickers with search, groups, and multi-select. `ChipSelect` uses `DropdownMenu`; `ChipCombobox` uses `Combobox` for editable input, async options, and virtualized lists. Both inherit the shared menu chrome.
3131
- **`ChipModal` + `ChipModalField`** — declarative compact modal. The field's `type` (`input` | `email` | `textarea` | `dropdown` | `copy` | `file` | `emails` | `custom`) picks the control and **owns all chrome** — consumers describe intent, never pass `variant`/`className`/`id` to the inner control. `custom` (with a `title`) is the escape hatch for controls the field doesn't cover. Every body field is a `ChipModalField`; the gutter rhythm that makes this matter is in `sim-styling.md` → "Form / chip-modal layout rhythm".
3232
- **`ChipSwitch`** — segmented pill control (built from `chipVariants`).
3333
- **`ChipTag`** — 20px inline tag/badge (`mono`/`gray`/`invite`), not a pill trigger.
3434
- **`ChipDatePicker`** — chip-styled date field.
3535
- **`ChipTimePicker`** — minute-granular time sibling of `ChipDatePicker`, a `ChipInput` that leniently parses typed input (`9:47`, `947`, `2:05pm`, `14:30`), commits on Enter/blur, and re-renders the canonical `9:47 AM` label.
36-
- **`DropdownMenu`** — the canonical context/action menu (Radix-backed). Not a chip, but the standard menu for command/action lists; reach for it instead of a hand-rolled popover. Its surface intentionally diverges from the chip pill (`text-small`, `gap-2`) — keep them distinct. For a pill that opens a value picker, use `ChipDropdown`/`ChipSelect` instead.
36+
- **`DropdownMenu`** — the canonical context/action menu (Radix-backed), styled through `MENU_STYLES`. Reach for it instead of a hand-rolled popover for command/action lists. For a pill that opens a value picker, use `ChipDropdown`/`ChipSelect` instead.
3737
- **`useScrollEdges` + `scrollFadeClass` / `scrollFadeAttributes`** — the canonical scroll-region edge treatment. The hook reports which edges hide content (tracking scroll and resizes; pass the element itself, held in state, when the region mounts after its owner, e.g. inside a Radix portal); the class and attributes fade a fixed 12px band at an active edge only, so a list that fits or sits at its top is never fogged. A floating control over the top edge sets `--scroll-fade-inset` to its height. A region that scrolls sideways (a tab row, a chip strip) uses `useScrollEdges(ref, { axis: 'x' })` with `scrollFadeXClass`; the attributes helper is shared. Any divider beside the region belongs to the neighboring block (`border-b` above, `border-t` below), never to the masked element, and shows only while that edge is active. Never hand-roll a `mask-image` gradient for a scroll region.
3838
- **`OverflowText`** — the canonical single-line overflow treatment for read-only human labels and titles. It owns `min-w-0`, fade-only clipping (never an ellipsis), the conditional 18px edge mask, and the full-value floating tooltip; consumers pass only layout/typography through `className`. `overflowTextClipClass` and `overflowTextFadeClass` are the complete base/faded treatments for the rare component that must own measurement itself; never pair either with `truncate`, `text-ellipsis`, or hover-time mask removal. Use `DropdownMenuItemLabel` for a menu label beside icons, checks, or actions. A non-editable `Combobox` passes the full visual value through `overlayLabel`; the combobox owns the visual overlay's fade and keeps its one accessible tooltip on the interactive layer. Keep ordinary `truncate` only for editable values, code/log/path content, dense or virtualized grids, and rich composite content that cannot supply a plain tooltip label. Multiline copy uses an intentional `line-clamp-*` treatment instead.
3939

0 commit comments

Comments
 (0)