History

Polish the app title bar: quiet Beta tag, no traffic-light overlap (#1207)

Replace the filled Beta pill next to the executor wordmark with quiet muted-mono metadata, matching the registry-minimal design language, and extract a shared Wordmark so the desktop and dashboard shells render the brand identically. Apply the macOS traffic-light offset to the mobile sidebar overlay and the collapsed top bar as well, so the native window controls never land on top of the wordmark when the window is narrow.

Rhys Sullivan committed 4 months ago

Commit c8d9b9d1 parent 5d23cee4 files · +45 −31Browse files

Unified · Split

4 files
  1. .changeset/desktop-titlebar-polish.md +8 −0
  2. packages/app/src/web/shell.tsx +14 −26
  3. packages/react/src/components/wordmark.tsx +20 −0
  4. packages/react/src/multiplayer/shell.tsx +3 −5
.changeset/desktop-titlebar-polish.md+8−0
@@ -0,0 +1,8 @@
1+---
2+"@executor-js/desktop": patch
3+"@executor-js/host-selfhost": patch
4+"@executor-js/host-cloudflare": patch
5+"@executor-js/react": patch
6+---
7+
8+Polish the app's title bar. The release tag beside the `executor` wordmark is now quiet muted-mono metadata instead of a filled pill, matching the registry-minimal design language, and the wordmark is shared across the desktop and dashboard shells so the brand reads identically everywhere. The macOS traffic-light offset is also applied to the mobile sidebar overlay and the collapsed top bar, so the native window controls never sit on top of the wordmark when the window is narrow.
packages/app/src/web/shell.tsx+14−26
@@ -14,6 +14,7 @@ import { IntegrationIconWithAccount } from "@executor-js/react/components/integr · 13 unmodified lines
1414 import { CommandPalette } from "@executor-js/react/components/command-palette";
1515 import { useClientPlugins, useIntegrationPlugins } from "@executor-js/sdk/client";
1616 import { SidebarUpdateCard } from "@executor-js/react/components/update-card";
17+import { Wordmark } from "@executor-js/react/components/wordmark";
1718 import { ServerConnectionMenu } from "./server-connection-menu";
1819
1920 // ── Env ─────────────────────────────────────────────────────────────────
@@ -161,16 +162,8 @@ function SidebarContent(props: { pathname: string; onNavigate?: () => void; show · 141 unmodified lines
161162 <>
162163 {props.showBrand !== false && (
163164 <div className="desktop-macos-titlebar flex h-12 shrink-0 items-center gap-2 border-b border-sidebar-border px-4">
164− <Link
165− to="/{-$orgSlug}"
166− className="desktop-macos-no-drag flex shrink-0 items-center gap-1.5"
167− >
168− <span className="font-mono text-sm font-medium tracking-tight text-foreground">
169− executor
170− </span>
171− <span className="rounded bg-primary/15 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wider text-primary">
172− Beta
173− </span>
165+ <Link to="/{-$orgSlug}" className="desktop-macos-no-drag flex shrink-0 items-center">
166+ <Wordmark />
174167 </Link>
175168 <div className="desktop-macos-no-drag ml-auto flex min-w-0 flex-1 justify-end pl-3">
176169 <ServerConnectionMenu variant="header" />
@@ -312,21 +305,16 @@ export function Shell() { · 135 unmodified lines
312305 onClick={() => setMobileSidebarOpen(false)}
313306 />
314307 <div className="relative flex h-full w-[84vw] max-w-xs flex-col border-r border-sidebar-border bg-sidebar shadow-2xl">
315− <div className="flex h-12 shrink-0 items-center justify-between border-b border-sidebar-border px-4">
316− <Link to="/{-$orgSlug}" className="flex items-center gap-1.5">
317− <span className="font-mono text-sm font-medium tracking-tight text-foreground">
318− executor
319− </span>
320− <span className="rounded bg-primary/15 px-1.5 py-px text-[10px] font-semibold uppercase tracking-wider text-primary">
321− Beta
322− </span>
308+ <div className="desktop-macos-titlebar flex h-12 shrink-0 items-center justify-between border-b border-sidebar-border px-4">
309+ <Link to="/{-$orgSlug}" className="desktop-macos-no-drag flex items-center">
310+ <Wordmark />
323311 </Link>
324312 <Button
325313 variant="ghost"
326314 size="icon-sm"
327315 aria-label="Close navigation"
328316 onClick={() => setMobileSidebarOpen(false)}
329− className="text-sidebar-foreground hover:bg-sidebar-active hover:text-foreground"
317+ className="desktop-macos-no-drag text-sidebar-foreground hover:bg-sidebar-active hover:text-foreground"
330318 >
331319 <svg viewBox="0 0 16 16" className="size-3.5">
332320 <path
@@ -356,14 +344,16 @@ export function Shell() { · 23 unmodified lines
356344 the top and their borders line up with the sidebar header. */}
357345 <div className="desktop-macos-main-titlebar" />
358346
359− {/* Mobile top bar */}
360− <div className="flex h-12 shrink-0 items-center justify-between border-b border-border bg-background px-4 md:hidden">
347+ {/* Mobile top bar. The desktop-macos-titlebar offset keeps the
348+ far-left hamburger clear of the native traffic lights when the macOS
349+ window is forced below the md breakpoint (issue #1125). */}
350+ <div className="desktop-macos-titlebar flex h-12 shrink-0 items-center justify-between border-b border-border bg-background px-4 md:hidden">
361351 <Button
362352 variant="outline"
363353 size="icon-sm"
364354 aria-label="Open navigation"
365355 onClick={() => setMobileSidebarOpen(true)}
366− className="bg-card hover:bg-accent/50"
356+ className="desktop-macos-no-drag bg-card hover:bg-accent/50"
367357 >
368358 <svg viewBox="0 0 16 16" className="size-4">
369359 <path
@@ -374,10 +364,8 @@ export function Shell() { · 4 unmodified lines
374364 />
375365 </svg>
376366 </Button>
377− <Link to="/{-$orgSlug}" className="flex items-center gap-1.5">
378− <span className="font-mono text-sm font-medium tracking-tight text-foreground">
379− executor
380− </span>
367+ <Link to="/{-$orgSlug}" className="desktop-macos-no-drag flex items-center">
368+ <Wordmark />
381369 </Link>
382370 <div className="w-8 shrink-0" />
383371 </div>
packages/react/src/components/wordmark.tsx+20−0
@@ -0,0 +1,20 @@
1+import { cn } from "../lib/utils";
2+
3+/**
4+ * The product wordmark: `executor` set in Geist Mono, with a quiet `beta` tag.
5+ *
6+ * Registry-minimal (see design.md): identity comes from restraint, not
7+ * decoration. The release tag is muted mono metadata sitting next to the
8+ * wordmark, NOT a filled pill or a brand-hued badge. Shared by the desktop/web
9+ * shell and the multiplayer shell so the brand reads identically everywhere.
10+ */
11+export function Wordmark(props: { readonly className?: string }) {
12+ return (
13+ <span className={cn("inline-flex items-baseline gap-1.5", props.className)}>
14+ <span className="font-mono text-sm font-medium tracking-tight text-foreground">executor</span>
15+ <span className="font-mono text-[10px] font-medium uppercase tracking-[0.12em] text-muted-foreground">
16+ beta
17+ </span>
18+ </span>
19+ );
20+}
packages/react/src/multiplayer/shell.tsx+3−5
@@ -22,6 +22,7 @@ import { · 21 unmodified lines
2222 integrationPresetIconUrl,
2323 } from "../components/integration-favicon";
2424 import { CommandPalette } from "../components/command-palette";
25+import { Wordmark } from "../components/wordmark";
2526 import { useClientPlugins, useIntegrationPlugins } from "@executor-js/sdk/client";
2627 import { useAuth } from "./auth-context";
2728
@@ -113,11 +114,8 @@ export interface ShellProps { · 85 unmodified lines
113114
114115 function Brand(props: { onNavigate?: () => void }) {
115116 return (
116− <Link to="/{-$orgSlug}" onClick={props.onNavigate} className="flex items-center gap-1.5">
117− <span className="font-mono text-sm font-medium tracking-tight text-foreground">executor</span>
118− <span className="rounded-sm bg-primary/10 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-primary">
119− Beta
120− </span>
117+ <Link to="/{-$orgSlug}" onClick={props.onNavigate} className="flex items-center">
118+ <Wordmark />
121119 </Link>
122120 );
123121 }