Skip to content

Commit 5c3a784

Browse files
os-zhuangclaude
andauthored
polish(app-shell): Studio UI consistency + aesthetics (#2094)
Browser-driven polish across the three Studio pillars: - Top tabs gain pillar icons (Data/Automations/Interfaces) + a hover transition. - Interfaces toolbar gains a left surface-context label (label · type · name), matching Data/Automations — all toolbars now read context-left, actions-right. - Inspector panel headers unified: sticky icon + title + a deselect (X) button across all three (Data was non-sticky; Interfaces/Automations lacked the button). Dropped the redundant selection-name chip (the reused inspector already shows the selected item's name + its own controls). eslint 0 / tsc 0. Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent bd9051c commit 5c3a784

1 file changed

Lines changed: 39 additions & 21 deletions

File tree

packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,11 @@ import { useMetadataClient } from '../metadata-admin/useMetadata';
4545
import { AppNavCanvas } from '../metadata-admin/previews/AppNavCanvas';
4646
import { readFields, writeFields, newField } from '../metadata-admin/previews/object-fields-io';
4747

48-
const PILLARS = [
49-
{ key: 'data', label: 'Data' },
50-
{ key: 'automations', label: 'Automations' },
51-
{ key: 'interfaces', label: 'Interfaces' },
52-
] as const;
48+
const PILLARS: ReadonlyArray<{ key: string; label: string; Icon: LucideIcon }> = [
49+
{ key: 'data', label: 'Data', Icon: Database },
50+
{ key: 'automations', label: 'Automations', Icon: Workflow },
51+
{ key: 'interfaces', label: 'Interfaces', Icon: LayoutDashboard },
52+
];
5353

5454
interface Surface {
5555
type: string;
@@ -147,12 +147,13 @@ export function StudioDesignSurface({ aiSlot }: StudioDesignSurfaceProps): React
147147
key={p.key}
148148
to={`/studio/${packageId}/${p.key}`}
149149
className={
150-
'rounded-md px-2.5 py-1 text-xs ' +
150+
'inline-flex items-center gap-1.5 rounded-md px-2.5 py-1 text-xs transition-colors ' +
151151
(tab === p.key
152152
? 'bg-primary/10 font-medium text-primary'
153-
: 'text-muted-foreground hover:bg-muted')
153+
: 'text-muted-foreground hover:bg-muted hover:text-foreground')
154154
}
155155
>
156+
<p.Icon className="h-3.5 w-3.5" />
156157
{p.label}
157158
</Link>
158159
))}
@@ -404,7 +405,17 @@ function InterfacesPillar({ packageId }: { packageId: string }): React.ReactElem
404405

405406
return (
406407
<div className="flex h-full flex-col">
407-
<div className="flex items-center justify-end gap-2 border-b px-3 py-1.5">
408+
<div className="flex items-center gap-2 border-b px-3 py-1.5">
409+
{current ? (
410+
<span className="flex items-center gap-1.5 text-[11px] text-muted-foreground">
411+
<span className="text-[13px] font-medium text-foreground">{current.label}</span>
412+
<span className="rounded bg-muted px-1.5 py-0.5">
413+
{current.type} · {current.name}
414+
</span>
415+
</span>
416+
) : (
417+
<span className="text-[11px] text-muted-foreground">从左侧选择一个菜单项</span>
418+
)}
408419
{hasDraft && (
409420
<span className="rounded bg-amber-400/15 px-2 py-0.5 text-[11px] text-amber-600 dark:text-amber-300">
410421
未发布草稿
@@ -413,7 +424,7 @@ function InterfacesPillar({ packageId }: { packageId: string }): React.ReactElem
413424
<button
414425
onClick={doSave}
415426
disabled={!current || !isEditable || !!saving}
416-
className="inline-flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs hover:bg-muted disabled:opacity-50"
427+
className="ml-auto inline-flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs hover:bg-muted disabled:opacity-50"
417428
>
418429
{saving === 'draft' ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Save className="h-3.5 w-3.5" />}
419430
保存草稿
@@ -566,10 +577,15 @@ function InterfacesPillar({ packageId }: { packageId: string }): React.ReactElem
566577
<header className="sticky top-0 z-10 flex items-center gap-2 border-b bg-background/95 px-3 py-2 backdrop-blur">
567578
<SlidersHorizontal className="h-3.5 w-3.5" />
568579
<span className="text-[13px] font-medium">属性</span>
569-
{selection?.label && (
570-
<span className="truncate rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground">
571-
{selection.label}
572-
</span>
580+
{selection && (
581+
<button
582+
type="button"
583+
onClick={() => setSelection(null)}
584+
className="ml-auto rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground"
585+
aria-label="取消选择"
586+
>
587+
<X className="h-3.5 w-3.5" />
588+
</button>
573589
)}
574590
</header>
575591
<div className="p-3">
@@ -880,12 +896,9 @@ function DataPillar({ packageId }: { packageId: string }): React.ReactElement {
880896
{/* field inspector — full type list + per-type config (reuses ObjectFieldInspector) */}
881897
{current && fieldSel && inspector && (
882898
<aside className="flex w-80 shrink-0 flex-col border-l">
883-
<header className="flex items-center gap-2 border-b px-3 py-2">
899+
<header className="sticky top-0 z-10 flex items-center gap-2 border-b bg-background/95 px-3 py-2 backdrop-blur">
884900
<SlidersHorizontal className="h-3.5 w-3.5" />
885901
<span className="text-[13px] font-medium">字段属性</span>
886-
<span className="truncate rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground">
887-
{fieldSel.id}
888-
</span>
889902
<button
890903
type="button"
891904
onClick={() => setFieldSel(null)}
@@ -1107,10 +1120,15 @@ function AutomationsPillar({ packageId }: { packageId: string }): React.ReactEle
11071120
<header className="sticky top-0 z-10 flex items-center gap-2 border-b bg-background/95 px-3 py-2 backdrop-blur">
11081121
<SlidersHorizontal className="h-3.5 w-3.5" />
11091122
<span className="text-[13px] font-medium">配置</span>
1110-
{selection?.label && (
1111-
<span className="truncate rounded bg-muted px-1.5 py-0.5 text-[11px] text-muted-foreground">
1112-
{selection.label}
1113-
</span>
1123+
{selection && (
1124+
<button
1125+
type="button"
1126+
onClick={() => setSelection(null)}
1127+
className="ml-auto rounded p-0.5 text-muted-foreground hover:bg-muted hover:text-foreground"
1128+
aria-label="取消选择"
1129+
>
1130+
<X className="h-3.5 w-3.5" />
1131+
</button>
11141132
)}
11151133
</header>
11161134
<div className="p-3">

0 commit comments

Comments
 (0)