feat(web): unify console + docs on @unom/ui; host OpenAPI via Scalar
apple / swift (push) Successful in 55s
ci / web (push) Successful in 45s
ci / docs-site (push) Successful in 1m18s
ci / rust (push) Successful in 4m14s
deb / build-publish (push) Successful in 2m16s
decky / build-publish (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 23s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
ci / bench (push) Successful in 4m40s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 46s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m35s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m18s
docker / deploy-docs (push) Successful in 19s
android / android (push) Successful in 3m12s
apple / swift (push) Successful in 55s
ci / web (push) Successful in 45s
ci / docs-site (push) Successful in 1m18s
ci / rust (push) Successful in 4m14s
deb / build-publish (push) Successful in 2m16s
decky / build-publish (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 6s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 23s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 3s
ci / bench (push) Successful in 4m40s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 46s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m35s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m18s
docker / deploy-docs (push) Successful in 19s
android / android (push) Successful in 3m12s
Move the management console (web/) off shadcn/ui to the shared @unom/ui design system the marketing site + docs are built on, on the punktfunk violet brand over dark chrome: - Add @unom/ui/@unom/style/motion/radix-ui/zod + Geist; web/.npmrc maps the @unom scope (packages are public-read, so CI needs no npm auth). - styles.css: one dark-violet palette (#141019/#1c1530, brand #6c5bf3 -> #a79ff8) exposed under BOTH the shadcn token names the routes use and @unom/ui's contract, so routes + components both resolve; pulls in @unom/ui's material gloss + easings. - components/ui/* now back onto @unom/ui (AnimatedButton/InputText/Label/ AnimatedCard); brand-mark/wordmark/logo replace the generic Radio icon in the shell + login. - MaterialProvider (specular gloss) at the root. No UI sounds, like the site. docs-site: new /api route renders the host management REST API as an interactive Scalar reference (reads public/openapi.json, a snapshot of docs/api/openapi.json), branded violet and linked from the top nav, the docs sidebar, the landing page, and host-cli.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { Link } from '@tanstack/react-router'
|
||||
import { Activity, Server, Users, KeyRound, LibraryBig, Settings, Radio } from 'lucide-react'
|
||||
import { Activity, Server, Users, KeyRound, LibraryBig, Settings } from 'lucide-react'
|
||||
import { BrandMark } from '@/components/brand-mark'
|
||||
import { Wordmark } from '@/components/wordmark'
|
||||
import { m } from '@/paraglide/messages'
|
||||
import { useLocale, changeLocale, locales, type Locale } from '@/lib/i18n'
|
||||
import { cn } from '@/lib/utils'
|
||||
@@ -21,21 +23,22 @@ export function AppShell({ children }: { children: ReactNode }) {
|
||||
<div className="flex min-h-screen">
|
||||
{/* Desktop sidebar (≥ sm). */}
|
||||
<aside className="hidden w-60 shrink-0 flex-col border-r bg-card/40 p-4 sm:flex">
|
||||
<div className="mb-6 flex items-center gap-2 px-2">
|
||||
<Radio className="size-5 text-[var(--success)]" />
|
||||
<div>
|
||||
<div className="font-semibold leading-tight">{m.app_name()}</div>
|
||||
<div className="text-xs text-muted-foreground">{m.app_tagline()}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Link
|
||||
to="/"
|
||||
aria-label="punktfunk"
|
||||
className="mb-7 flex items-center gap-2 px-2 pt-1"
|
||||
>
|
||||
<BrandMark className="size-7 drop-shadow-[0_2px_12px_rgba(108,91,243,0.45)]" />
|
||||
<Wordmark className="h-4" />
|
||||
</Link>
|
||||
<nav className="flex flex-col gap-1">
|
||||
{NAV.map(({ to, icon: Icon, label }) => (
|
||||
<Link
|
||||
key={to}
|
||||
to={to}
|
||||
activeOptions={{ exact: to === '/' }}
|
||||
className="flex items-center gap-3 rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
|
||||
activeProps={{ className: 'bg-accent text-foreground font-medium' }}
|
||||
className="flex items-center gap-3 rounded-md px-3 py-2 text-sm text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
|
||||
activeProps={{ className: 'bg-primary/15 text-foreground font-medium' }}
|
||||
>
|
||||
<Icon className="size-4" />
|
||||
{label()}
|
||||
@@ -50,8 +53,8 @@ export function AppShell({ children }: { children: ReactNode }) {
|
||||
<div className="flex flex-1 flex-col overflow-x-hidden">
|
||||
{/* Mobile top bar (< sm): brand + language. The sidebar is hidden here. */}
|
||||
<header className="flex items-center gap-2 border-b bg-card/40 px-4 py-3 sm:hidden">
|
||||
<Radio className="size-5 text-[var(--success)]" />
|
||||
<div className="font-semibold leading-tight">{m.app_name()}</div>
|
||||
<BrandMark className="size-6" />
|
||||
<Wordmark className="h-3.5" />
|
||||
<div className="ml-auto">
|
||||
<LanguageSwitcher />
|
||||
</div>
|
||||
@@ -74,7 +77,7 @@ export function AppShell({ children }: { children: ReactNode }) {
|
||||
to={to}
|
||||
activeOptions={{ exact: to === '/' }}
|
||||
className="flex flex-1 flex-col items-center gap-1 py-2 text-[10px] text-muted-foreground transition-colors"
|
||||
activeProps={{ className: 'text-foreground' }}
|
||||
activeProps={{ className: 'text-[var(--brand-light)]' }}
|
||||
>
|
||||
<Icon className="size-5" />
|
||||
<span className="leading-none">{label()}</span>
|
||||
@@ -96,7 +99,7 @@ function LanguageSwitcher() {
|
||||
className={cn(
|
||||
'rounded px-2 py-1 text-xs uppercase transition-colors',
|
||||
l === current
|
||||
? 'bg-secondary text-secondary-foreground font-medium'
|
||||
? 'bg-primary/20 text-foreground font-medium'
|
||||
: 'text-muted-foreground hover:text-foreground',
|
||||
)}
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user