From 899272c2db17222d59d361d88047df15b230f3c3 Mon Sep 17 00:00:00 2001 From: fullstackjam Date: Thu, 25 Jun 2026 22:46:41 +0800 Subject: [PATCH] style(ui): align pages with OpenBoot redesign mockup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reconcile the pages that had drifted from the terminal-native design's unified card system. - Landing: replace demo.gif with the static ASCII install terminal, use the text "copy" label, and apply the mockup's exact spacing. - ConfigCard: rewrite the un-unified dashboard card (hardcoded colors, big-number stats, embedded terminal) into the unified card — name + visibility badge, cli/apps/installs/date footer, always-visible curl box, and Edit/Share/More action row. - ContextMenu: restyle the trigger into the flush "More" button. - Profile: drop the gradient/noise override, pulse-ring avatar and stat-bars in favour of the flat mockup layout and unified card grid. - Dashboard: add the "> dashboard" eyebrow, widen to 1160px, 3-col grid, and the mockup's header buttons. - Explore: show the install command on cards permanently. Real API data, route-based nav, and the footer are kept (the mockup's hardcoded data / page-switcher / missing footer are preview artifacts). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01BCZEZu9qv2jQNjrYx2rWZ9 --- src/lib/components/ConfigCard.svelte | 416 ++++--------- src/lib/components/ContextMenu.svelte | 29 +- src/routes/+page.svelte | 135 +++- src/routes/[username]/+page.svelte | 861 +++++++++----------------- src/routes/dashboard/+page.svelte | 101 ++- src/routes/explore/+page.svelte | 19 +- 6 files changed, 608 insertions(+), 953 deletions(-) diff --git a/src/lib/components/ConfigCard.svelte b/src/lib/components/ConfigCard.svelte index c2fb6d2..a8d4a1d 100644 --- a/src/lib/components/ConfigCard.svelte +++ b/src/lib/components/ConfigCard.svelte @@ -20,8 +20,6 @@ onaction: (action: string, slug: string) => void; } = $props(); - let copiedCmd = $state(false); - const packages = $derived( Array.isArray(config.packages) ? config.packages.map((p: any) => @@ -30,52 +28,22 @@ : [] ); - const stats = $derived({ - total: packages.length, - apps: packages.filter((p: any) => p.type === 'cask').length, - cli: packages.filter((p: any) => p.type !== 'cask' && p.type !== 'npm').length, - npm: packages.filter((p: any) => p.type === 'npm').length, - }); + const cli = $derived(packages.filter((p: any) => p.type !== 'cask' && p.type !== 'npm').length); + const apps = $derived(packages.filter((p: any) => p.type === 'cask').length); - const installCmd = $derived( - config.alias - ? `openboot install ${config.alias}` - : `openboot install ${username}/${config.slug}` + const installUrl = $derived( + config.alias ? `openboot.dev/${config.alias}` : `openboot.dev/${username}/${config.slug}` ); - // Subtle accent color per card - const ACCENTS = [ - '99, 102, 241', // indigo - '236, 72, 153', // pink - '59, 130, 246', // blue - '16, 185, 129', // emerald - '245, 158, 11', // amber - '139, 92, 246', // violet - '20, 184, 166', // teal - '244, 63, 94', // rose - ]; - - function hashStr(s: string): number { - let h = 0; - for (let i = 0; i < s.length; i++) { - h = ((h << 5) - h) + s.charCodeAt(i); - h |= 0; - } - return Math.abs(h); - } - - const accent = $derived(ACCENTS[hashStr(config.name) % ACCENTS.length]); - - function copyCommand(e: MouseEvent) { - e.stopPropagation(); - navigator.clipboard.writeText(installCmd); - copiedCmd = true; - setTimeout(() => (copiedCmd = false), 2000); + function formatDate(dateStr?: string): string { + if (!dateStr) return ''; + const date = new Date(dateStr.endsWith('Z') ? dateStr : dateStr + 'Z'); + if (isNaN(date.getTime())) return ''; + return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); } const menuItems = $derived([ { label: 'Duplicate', action: 'duplicate' }, - { label: 'Share', action: 'share' }, { label: 'Export JSON', action: 'export' }, ...(config.visibility !== 'public' ? [{ label: 'Push to Community', action: 'push' }] @@ -84,203 +52,106 @@ ]); -
onaction('edit', config.slug)} - onkeydown={(e) => e.key === 'Enter' && onaction('edit', config.slug)} - role="button" - tabindex="0" -> - -
- - -
- -
-
-

{config.name}

- - {#if config.alias} - /{config.alias} - {:else} - /{config.slug} - {/if} - -
-
e.stopPropagation()} role="presentation"> - - {config.visibility} - - onaction(action, config.slug)} /> -
-
+
+
+

{config.name}

+ + {config.visibility} + +
- {#if config.description} -

{config.description}

- {/if} + {#if config.description} +

{config.description}

+ {/if} + +
+ {cli} cli · {apps} apps + + + {config.install_count ?? 0} + + {formatDate(config.updated_at)} +
- -
-
- {stats.total} - packages -
- {#if stats.apps > 0} -
- {stats.apps} - apps -
- {/if} - {#if stats.cli > 0} -
- {stats.cli} - cli -
- {/if} - {#if stats.npm > 0} -
- {stats.npm} - npm -
- {/if} -
+
+ $ curl -fsSL {installUrl} | bash +
- -
e.stopPropagation()} role="presentation"> -
- -
-
- $ {installCmd} - -
-
+
+ + + onaction(action, config.slug)} />
diff --git a/src/lib/components/ContextMenu.svelte b/src/lib/components/ContextMenu.svelte index 9cf3e1c..0b97f22 100644 --- a/src/lib/components/ContextMenu.svelte +++ b/src/lib/components/ContextMenu.svelte @@ -36,13 +36,7 @@
- + {#if open}
- OpenBoot demo — installing dev tools in one command +
Checksum verified · Added to PATH
+
=== OpenBoot Installer v0.20.0 ===
+
[DRY-RUN MODE — no changes will be made]
+
=== Step 1: Git configuration ===
+
Already configured: jam <jam@hey.com>
+
=== Step 2: Preset selection ===
+
Choose your preset
+
developer — Node, Go, Docker, VS Code
+
full — languages, DevOps, databases, AI
+
minimal — CLI essentials only
+
↑ up · ↓ down · / filter · ⏎ submit
@@ -178,7 +179,7 @@ /* ---------- hero ---------- */ .hero { position: relative; - padding: 120px 0 124px; + padding: 108px 0 110px; display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 60px; @@ -194,9 +195,9 @@ linear-gradient(var(--border) 1px, transparent 1px), linear-gradient(90deg, var(--border) 1px, transparent 1px); background-size: 46px 46px; - -webkit-mask-image: radial-gradient(ellipse 75% 55% at 22% 28%, #000 0%, transparent 68%); - mask-image: radial-gradient(ellipse 75% 55% at 22% 28%, #000 0%, transparent 68%); - opacity: 0.4; + -webkit-mask-image: radial-gradient(ellipse 75% 55% at 22% 30%, #000 0%, transparent 68%); + mask-image: radial-gradient(ellipse 75% 55% at 22% 30%, #000 0%, transparent 68%); + opacity: 0.45; } .hero-content { @@ -216,9 +217,9 @@ } .hero-title { - font-size: clamp(2.3rem, 4.6vw, 3.7rem); + font-size: clamp(2.3rem, 4.6vw, 3.4rem); font-weight: 500; - line-height: 1.04; + line-height: 1.05; letter-spacing: -0.04em; color: var(--text-primary); margin: 0 0 26px; @@ -233,14 +234,14 @@ color: var(--text-secondary); line-height: 1.75; margin: 0 0 32px; - max-width: 54ch; + max-width: 52ch; } .features-list { list-style: none; display: grid; gap: 12px; - margin: 0 0 38px; + margin: 0 0 36px; padding: 0; } @@ -269,11 +270,11 @@ background: var(--bg-secondary); border: 1px solid var(--border-hover); border-radius: 10px; - padding: 16px 17px; + padding: 15px 16px; display: flex; align-items: center; gap: 13px; - max-width: 510px; + max-width: 500px; font-size: 0.9rem; transition: border-color 0.18s ease, @@ -306,19 +307,25 @@ background: transparent; border: none; color: var(--text-muted); - padding: 2px; + padding: 0; cursor: pointer; transition: color 0.15s ease; display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; + font-family: inherit; + font-size: 0.78rem; } .copy-btn:hover { color: var(--accent); } + .copy-btn.copied { + color: var(--accent); + } + .install-alt { color: var(--text-muted); font-size: 0.78rem; @@ -340,7 +347,7 @@ .terminal-window { width: 100%; - max-width: 620px; + max-width: 560px; border-radius: 12px; overflow: hidden; background: var(--bg-secondary); @@ -387,21 +394,89 @@ .terminal-body { background: var(--bg-secondary); + padding: 18px 18px 20px; + font-size: 0.76rem; + line-height: 1.85; + color: var(--text-secondary); } - .terminal-body img { - width: 100%; - display: block; + .t-line { + white-space: nowrap; + } + + .t-accent { + color: var(--accent); + } + + .t-muted { + color: var(--text-muted); + } + + .t-strong { + color: var(--text-primary); + } + + .t-head { + color: var(--accent); + margin-top: 10px; + } + + .t-note { + color: var(--text-muted); + margin-top: 8px; + } + + .t-ok { + margin-top: 4px; + } + + .t-prompt-label { + color: var(--amber); + margin-top: 6px; + } + + .t-sel { + margin-top: 2px; + } + + .t-opt { + color: var(--text-muted); + padding-left: 14px; + } + + .t-keys { + color: var(--text-muted); + margin-top: 10px; + } + + .t-caret { + display: inline-block; + width: 7px; + height: 1em; + background: var(--accent); + translate: 0 2px; + animation: ob-blink 1s infinite; + } + + @keyframes ob-blink { + 0%, + 49% { + opacity: 1; + } + 50%, + 100% { + opacity: 0; + } } /* ---------- how it works ---------- */ .how-it-works { - padding: 112px 0; + padding: 104px 0; border-top: 1px solid var(--border); } .section-header { - margin-bottom: 60px; + margin-bottom: 56px; } .section-prompt { @@ -435,7 +510,7 @@ .step { background: var(--bg-primary); - padding: 30px 26px 34px; + padding: 28px 24px 32px; transition: background 0.2s ease; } diff --git a/src/routes/[username]/+page.svelte b/src/routes/[username]/+page.svelte index 8d8ddd5..2ec05d4 100644 --- a/src/routes/[username]/+page.svelte +++ b/src/routes/[username]/+page.svelte @@ -1,11 +1,9 @@ @@ -99,131 +85,91 @@
-
-
- -
+
{#if data.profileUser.avatar_url} - {data.profileUser.username} + {data.profileUser.username} {:else} -
{data.profileUser.username.charAt(0).toUpperCase()}
+ {data.profileUser.username.charAt(0).toLowerCase()} {/if}
- -

@{data.profileUser.username}

- + +

@{data.profileUser.username}

+ - -

Member since {formatDate(data.profileUser.created_at)}

- + +

member since {formatDate(data.profileUser.created_at)}

+
-
-
- {data.configs.length} - Configs +
+
{data.configs.length}
+
configs
-
-
- {formatInstallCount(data.totalInstalls)} - Installs +
+
{formatInstallCount(data.totalInstalls)}
+
installs
-
-
- {totalPackages} - Packages +
+
{totalPackages}
+
packages
{#if data.configs.length === 0}
- - - - - - -

No public configurations yet

This user hasn't shared any public configs.

- - - - - Create your own config - + Create your own config
{:else}
-
-

Public Configurations

-

Setups @{data.profileUser.username} has chosen to share with the community

-
-
- {#each data.configs as config, index} -
-
- -
-

{config.name}

- {config.base_preset} -
- {#if config.description} -

{config.description}

- {/if} -
- - - {getPackageBreakdown(config.packages)} - - - - {config.install_count || 0} installs - - {#if config.updated_at} - - - {formatDate2(config.updated_at)} - +

> public configurations

+
+ {#each data.configs as config (config.id)} + +
+ -
- - - -
-
-
- $ curl -fsSL openboot.dev/{data.profileUser.username}/{config.slug} | bash - + {config.base_preset} +
+

{config.name}

+ {#if config.description} +

{config.description}

+ {/if} + +
+ $ curl -fsSL openboot.dev/{data.profileUser.username}/{config.slug} | bash
-
+ {/each}
{/if} -
-
-
-
-

Create your own config

-

Build custom install scripts for your team or projects in minutes.

-
- - - - - Get Started - +
+
+

Create your own config

+

Build custom install scripts for your team or projects in minutes.

+ Get started
@@ -232,581 +178,358 @@ diff --git a/src/routes/dashboard/+page.svelte b/src/routes/dashboard/+page.svelte index d4028ba..c0ea8e7 100644 --- a/src/routes/dashboard/+page.svelte +++ b/src/routes/dashboard/+page.svelte @@ -262,7 +262,8 @@ {:else} @@ -411,9 +410,9 @@