Skip to content

Commit 9b6c3ab

Browse files
committed
feat(platform): consolidate controls and redesign integration details
1 parent cdccb5b commit 9b6c3ab

134 files changed

Lines changed: 2255 additions & 1620 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.

‎apps/sim/app/o/[organizationId]/_redesign/rail/help-menu.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ export function HelpMenu() {
2323
{
2424
id: 'documentation',
2525
label: 'Docs',
26-
icon: 'I079',
26+
icon: 'I082',
2727
trailingIcon: 'I030',
2828
separatorBefore: Boolean(desktopUpdate),
2929
onSelect: help.openDocumentation,

‎apps/sim/app/o/[organizationId]/_redesign/rail/name-modal.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export function NameModal({
4040
>
4141
<TextField
4242
label={fieldLabel}
43+
placeholder={fieldLabel}
4344
name='name'
4445
required
4546
maxLength={maxLength}

‎apps/sim/app/o/[organizationId]/_redesign/rail/organization-menu.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export function OrganizationMenu({
127127
>
128128
<Input
129129
label='Organization name'
130+
placeholder='Organization name'
130131
value={draftName}
131132
disabled={renaming}
132133
invalid={Boolean(renameError)}

‎apps/sim/platform/AGENTS.md‎

Lines changed: 7 additions & 5 deletions
Large diffs are not rendered by default.

‎apps/sim/platform/README.md‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ Shared and Platform still own different recipes; `catalog/evidence.json` preserv
7171

7272
Workspace lists, sidebar items, recents and attachment batches accept typed arrays with stable item IDs. Use the named components for these collection masters: a Paper specimen's item count is sample data. An empty array renders zero items, and adding items preserves their registered row/card appearance. Each scroll viewport determines fades and controls from its actual contents. Chart labels, marks, inspected values and legends come from the same series. Supply raw numeric values and their units to data tables. The column schema determines alignment and which columns remain visible as the table narrows.
7373

74-
The full fixture includes twenty sidebar workspaces, sixteen conversations, a twelve-message inbox and a calendar that scrolls from midnight to midnight even on empty days. Home and Chat share a reading width. Home and Integrations share the same heading inset; the shell reserves sidebar opener and native titlebar clearance separately. The shell uses one 12px inset above the organization and on both sides of the profile row. The Home content scrolls through its viewport edge fade. The shell keeps the collapsed sidebar button aligned with the expanded toolbar even as the page scrolls. Platform and Settings navigation scroll independently, with edge fades instead of a visible scrollbar. Calendar events use the muted surface. An event with a provider URL opens in a new tab. Attendees and integration usage share Stack: two photos with names on hover and a passive +N count, compacted for large totals. Now appears when the calendar scrolls away from its resting position or another day is selected. It restores today’s schedule and centers the current time. Scrolling back to that position also hides Now.
74+
The full fixture includes twenty sidebar workspaces, sixteen conversations, a twelve-message inbox and a calendar that scrolls from midnight to midnight even on empty days. All Platform reading pages share PageColumn width and gutters; PageOverflow supplies the common 8px surface overhang. Editor and preview canvases retain their working area. Home and Integrations share the same heading inset; the shell reserves sidebar opener and native titlebar clearance separately. The shell uses one 12px inset above the organization and on both sides of the profile row. The Home content scrolls through its viewport edge fade. The shell keeps the collapsed sidebar button aligned with the expanded toolbar even as the page scrolls. Platform and Settings navigation scroll independently, with edge fades instead of a visible scrollbar. Calendar events use the muted surface. An event with a provider URL opens in a new tab. Attendees and integration usage share Stack: up to three photos with names on hover and a passive +N count, compacted for large totals. Now appears when the calendar scrolls away from its resting position or another day is selected. It restores today’s schedule and centers the current time. Scrolling back to that position also hides Now.
7575

7676
Start with the [component ownership map](docs/component-ownership.md) when choosing a primitive. Sidebar, recents and panel tabs use one row; form and command dialogs use one borderless surface. Copy confirmations and transient notifications last four seconds. The notification count uses the compact Invite button. Expanded notices share one subtle shadow around the list. A new notice pauses its expiry on hover or keyboard focus. Icon color transitions take 120ms and respect reduced motion. The [design contract](AGENTS.md) defines these rules.
7777

@@ -83,7 +83,7 @@ Import [Platform time formatting](lib/time.ts) for dates, relative ages and cloc
8383

8484
### Keyboard and dropdown behavior
8585

86-
Focus places the caret or keyboard target without changing the control’s border, outline, background or shadow. Selection, validation and the highlighted list item retain their Paper treatments. Use the same EMCN value picker and floating surface on the workbench and in a modal. Select handles a fixed set of values, a searchable combobox supports longer lists, and an action menu supports commands and nested menus. The Help menu in the workbench exercises the cascade.
86+
Focus places the caret or keyboard target without changing ordinary field paint. SearchField has one explicit exception: its underline appears on hover or focus. Keyboard focus remains visible on actions. Selection, validation and the highlighted list item retain their Paper treatments. Use the same EMCN value picker and floating surface on the workbench and in a modal. Select handles a fixed set of values, a searchable combobox supports longer lists, and an action menu supports commands and nested menus. The Help menu in the workbench exercises the cascade.
8787

8888
Import the styled EMCN owner from product UI. Its Base UI primitive handles pointer and keyboard interaction, dismissal and collision placement. Nested menus support hovering into the child, arrow-key navigation, and Escape back to the parent. The tests also check form submission, dialog-local placement and focus restoration. [Base UI Select](https://base-ui.com/react/components/select) · [Combobox](https://base-ui.com/react/components/combobox) · [Menu](https://base-ui.com/react/components/menu)
8989

@@ -113,7 +113,14 @@ The Platform type check generates Next.js route types and checks the isolated pr
113113

114114
`bun run --cwd apps/sim test:platform:live` runs `checks/live/` against an app and database you have started, using `PLATFORM_LIVE_ORIGIN`, `PLATFORM_LIVE_EMAIL`, `PLATFORM_LIVE_PASSWORD` and `PLATFORM_LIVE_ORGANIZATION_NAME`. The member needs build access: anyone else lands on a legacy route. Supply `PLATFORM_LIVE_REPORT_PATH` to save its JSON report.
115115

116-
The browser suite starts separate production servers with fixtures enabled and disabled. Supply `PLATFORM_REPORT_PATH` to save JSON, failure screenshots and traces. Next uses webpack for this nested app: the installed Turbopack also discovers the parent Sim project's proxy and instrumentation. Watch for that boundary when upgrading Next.
116+
The default browser suite starts production servers with fixtures enabled and disabled. For the already-running shared preview, use the explicit existing-server mode; it starts no server and leaves the preview process unchanged:
117+
118+
```sh
119+
PLATFORM_E2E_ORIGIN=http://localhost:3125 PLATFORM_REPORT_PATH=<report-path> bun run --cwd apps/sim test:platform:e2e
120+
PLATFORM_E2E_ORIGIN=http://localhost:3125 PLATFORM_DESKTOP_REPORT_PATH=<report-path> bun run --cwd apps/sim test:platform:desktop
121+
```
122+
123+
That local mode runs fixture-enabled browser and Electron coverage. It excludes only `fixtures-off.spec.ts`, whose server gate requires a fixture-disabled process. The default production suite retains those checks; complete them on the exact final commit before shipping. `?state=empty` does not turn fixtures off. Supply `PLATFORM_REPORT_PATH` to save JSON, failure screenshots and traces. Next uses webpack for this nested app: the installed Turbopack also discovers the parent Sim project's proxy and instrumentation. Watch for that boundary when upgrading Next.
117124

118125
The static check covers ownership, styling props, component folders, evidence, tokens, unused variants and dependency direction. It rejects a route CSS Module directly under `_components/`; put it with its component. If it flags a variant used on a real route, verify the call path and add that case to the checker. Review new shared visual variants against at least two independent consumers; semantic independence is a design review, not a count of repeated JSX rows. A workbench example cannot establish product usage. Use the rendered route to verify visual alignment. Compare both themes, keyboard and pointer states, actual overflow, text scaling and widths between approved artboards. Build the standalone app before running the browser suite to test the current sources.
119126

‎apps/sim/platform/app/(shell)/_components/chat/cards/assistant-review.tsx‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,14 @@ function ActionCard({
5656
{editing && field.editable ? (
5757
field.multiline ? (
5858
<TextArea
59+
placeholder={field.label}
5960
label={field.label}
6061
value={value}
6162
onChange={(next) => onEdit(field.name, next)}
6263
/>
6364
) : (
6465
<Input
66+
placeholder={field.label}
6567
label={field.label}
6668
value={value}
6769
onChange={(next) => onEdit(field.name, next)}

‎apps/sim/platform/app/(shell)/_components/chat/cards/live-credential-card.tsx‎

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ export function LiveCredentialCard({
225225
<SecretField
226226
key={controlId}
227227
label={item.name ?? 'Secret'}
228-
placeholder={item.name}
228+
placeholder={item.name ?? 'Enter a secret'}
229229
value={drafts[index] ?? ''}
230230
onChange={(value) => setDrafts((current) => ({ ...current, [index]: value }))}
231231
/>
@@ -245,7 +245,14 @@ export function LiveCredentialCard({
245245
return <FolderRow key={controlId} item={item} />
246246
case 'sim_key':
247247
return item.value ? (
248-
<SecretField key={controlId} label='Sim key' value={item.value} readOnly copyable />
248+
<SecretField
249+
placeholder='Sim API key'
250+
key={controlId}
251+
label='Sim key'
252+
value={item.value}
253+
readOnly
254+
copyable
255+
/>
249256
) : null
250257
default:
251258
return null

‎apps/sim/platform/app/(shell)/_components/chat/conversation/conversation.module.css‎

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,6 @@
3131
gap: var(--ui-product-section-gap);
3232
overflow-wrap: anywhere;
3333
}
34-
.thread,
35-
.dockInner {
36-
inline-size: min(var(--ui-page-max-size), calc(100% - 2 * var(--ui-page-inline-gutter)));
37-
margin-inline: auto;
38-
}
3934
.turn:last-child {
4035
margin-block-end: var(--ui-product-section-gap);
4136
}

‎apps/sim/platform/app/(shell)/_components/chat/conversation/conversation.tsx‎

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import {
1515
IconButton,
1616
InlineNotice,
1717
OverflowText,
18+
PageColumn,
19+
PageOverflow,
1820
Tooltip,
1921
} from '@/platform/design-system/components'
2022
import { useScrollEdges } from '@/platform/design-system/components/scroll-area/use-scroll-edges'
@@ -98,31 +100,33 @@ export function Conversation({ runtime, composer, placeholders, header }: Conver
98100
setEarlier(el.scrollHeight - el.clientHeight - el.scrollTop > FOLLOW_SLACK)
99101
}}
100102
>
101-
<div className={styles.thread} ref={thread}>
102-
{status === 'loading' && (
103-
<p className={styles.turn} data-type='T048' role='status'>
104-
Loading conversation
105-
</p>
106-
)}
107-
{runtime.loadFailed && (
108-
<InlineNotice
109-
intent='danger'
110-
message='This conversation could not load.'
111-
action={
112-
<Button variant='muted' size='compact' onClick={() => window.location.reload()}>
113-
Reload
114-
</Button>
115-
}
116-
/>
117-
)}
118-
{groupExchanges(turns).map((exchange) => (
119-
<article key={exchange[0].id} className={styles.turn}>
120-
{exchange.map((turn) => (
121-
<Turn key={turn.id} turn={turn} />
122-
))}
123-
</article>
124-
))}
125-
</div>
103+
<PageColumn>
104+
<div className={styles.thread} ref={thread}>
105+
{status === 'loading' && (
106+
<p className={styles.turn} data-type='T048' role='status'>
107+
Loading conversation
108+
</p>
109+
)}
110+
{runtime.loadFailed && (
111+
<InlineNotice
112+
intent='danger'
113+
message='This conversation could not load.'
114+
action={
115+
<Button variant='muted' size='compact' onClick={() => window.location.reload()}>
116+
Reload
117+
</Button>
118+
}
119+
/>
120+
)}
121+
{groupExchanges(turns).map((exchange) => (
122+
<article key={exchange[0].id} className={styles.turn}>
123+
{exchange.map((turn) => (
124+
<Turn key={turn.id} turn={turn} />
125+
))}
126+
</article>
127+
))}
128+
</div>
129+
</PageColumn>
126130
</div>
127131
<div className={styles.dock}>
128132
{earlier && (
@@ -137,28 +141,30 @@ export function Conversation({ runtime, composer, placeholders, header }: Conver
137141
</Tooltip>
138142
</div>
139143
)}
140-
<div className={styles.dockInner}>
144+
<PageColumn>
141145
<QueuedMessages runtime={runtime} />
142-
<MessageComposer
143-
composer={composer}
144-
placeholder={
145-
running
146-
? placeholders.running
147-
: turns.length
148-
? placeholders.followUp
149-
: placeholders.first
150-
}
151-
onSubmit={runtime.send}
152-
onStop={running ? runtime.stop : undefined}
153-
onSendQueuedHead={queue.length ? () => runtime.sendQueuedNow() : undefined}
154-
onRecallQueued={() => {
155-
const tail = queue.at(-1)
156-
if (!tail || tail.locked) return false
157-
runtime.editQueued(tail.id)
158-
return true
159-
}}
160-
/>
161-
</div>
146+
<PageOverflow>
147+
<MessageComposer
148+
composer={composer}
149+
placeholder={
150+
running
151+
? placeholders.running
152+
: turns.length
153+
? placeholders.followUp
154+
: placeholders.first
155+
}
156+
onSubmit={runtime.send}
157+
onStop={running ? runtime.stop : undefined}
158+
onSendQueuedHead={queue.length ? () => runtime.sendQueuedNow() : undefined}
159+
onRecallQueued={() => {
160+
const tail = queue.at(-1)
161+
if (!tail || tail.locked) return false
162+
runtime.editQueued(tail.id)
163+
return true
164+
}}
165+
/>
166+
</PageOverflow>
167+
</PageColumn>
162168
</div>
163169
</div>
164170
</ChatRuntimeProvider>

‎apps/sim/platform/app/(shell)/_components/links-page/links-frame.tsx‎

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import type { ReactNode } from 'react'
44
import styles from '@/platform/app/(shell)/_components/links-page/links-page.module.css'
5-
import { ActionMenu, Button, SearchField } from '@/platform/design-system/components'
5+
import { ActionMenu, Button, PageColumn, SearchField } from '@/platform/design-system/components'
66
import type { MenuAction } from '@/platform/design-system/components/menu/action-menu'
77
import { openChromeStore, useLinksHosted } from '@/platform/lib/data/links'
88

@@ -31,32 +31,34 @@ export function LinksFrame({
3131
}: LinksFrameProps) {
3232
const hosted = useLinksHosted()
3333
return (
34-
<main className={styles.page} inert={loading} aria-busy={loading || undefined}>
35-
<header className={styles.heading}>
36-
<h1 data-type='T076'>Links</h1>
37-
<div className={styles.actions}>
38-
{hosted && (
39-
<Button icon='I041' onClick={openChromeStore}>
40-
Install Sim for Chrome
34+
<PageColumn>
35+
<main className={styles.page} inert={loading} aria-busy={loading || undefined}>
36+
<header className={styles.heading}>
37+
<h1 data-type='T076'>Links</h1>
38+
<div className={styles.actions}>
39+
{hosted && (
40+
<Button icon='I041' onClick={openChromeStore}>
41+
Install Sim for Chrome
42+
</Button>
43+
)}
44+
<Button variant='primary' icon='I074' onClick={onCreate}>
45+
New link
4146
</Button>
42-
)}
43-
<Button variant='primary' icon='I074' onClick={onCreate}>
44-
New link
45-
</Button>
47+
</div>
48+
</header>
49+
<div className={styles.options}>
50+
<SearchField
51+
variant='quiet'
52+
label='Search links'
53+
placeholder='Search links...'
54+
value={search}
55+
onValueChange={onSearch}
56+
/>
57+
<ActionMenu label={sortLabel} icon={null} align='end' actions={sortActions} />
4658
</div>
47-
</header>
48-
<div className={styles.options}>
49-
<SearchField
50-
variant='quiet'
51-
label='Search links'
52-
placeholder='Search links...'
53-
value={search}
54-
onValueChange={onSearch}
55-
/>
56-
<ActionMenu label={sortLabel} icon={null} align='end' actions={sortActions} />
57-
</div>
58-
{children}
59-
</main>
59+
{children}
60+
</main>
61+
</PageColumn>
6062
)
6163
}
6264

0 commit comments

Comments
 (0)