Merge remote-tracking branch 'origin/main'
apple / swift (push) Successful in 54s
ci / rust (push) Successful in 1m39s
ci / web (push) Successful in 28s
windows-host / package (push) Successful in 2m25s
ci / docs-site (push) Successful in 40s
android / android (push) Successful in 3m18s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m18s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m15s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 1m0s
deb / build-publish (push) Successful in 3m8s
decky / build-publish (push) Successful in 13s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 1m3s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
ci / bench (push) Successful in 4m56s
flatpak / build-publish (push) Successful in 4m46s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m13s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 7m56s
apple / swift (push) Successful in 54s
ci / rust (push) Successful in 1m39s
ci / web (push) Successful in 28s
windows-host / package (push) Successful in 2m25s
ci / docs-site (push) Successful in 40s
android / android (push) Successful in 3m18s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 1m18s
windows-msix / package (x64, C:\Users\Public\ffmpeg, x86_64-pc-windows-msvc, C:\t) (push) Successful in 1m15s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 1m0s
deb / build-publish (push) Successful in 3m8s
decky / build-publish (push) Successful in 13s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 4s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 5s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 1m3s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 5s
ci / bench (push) Successful in 4m56s
flatpak / build-publish (push) Successful in 4m46s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m13s
docker / deploy-docs (push) Successful in 18s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 7m56s
This commit is contained in:
+764
-11
File diff suppressed because it is too large
Load Diff
@@ -10,8 +10,11 @@
|
|||||||
"lint": "tsc --noEmit"
|
"lint": "tsc --noEmit"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fontsource-variable/geist": "^5.2.9",
|
||||||
"@tanstack/react-router": "^1.121.0",
|
"@tanstack/react-router": "^1.121.0",
|
||||||
"@tanstack/react-start": "^1.121.0",
|
"@tanstack/react-start": "^1.121.0",
|
||||||
|
"@unom/style": "^0.4.4",
|
||||||
|
"@unom/ui": "^0.8.16",
|
||||||
"fumadocs-core": "^16.10.1",
|
"fumadocs-core": "^16.10.1",
|
||||||
"fumadocs-ui": "^16.10.1",
|
"fumadocs-ui": "^16.10.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg width="1000" height="1000" viewBox="0 0 1000 1000" version="1.1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||||
|
<!-- punktfunk brand mark: deep-purple lens of two overlapping circles on the
|
||||||
|
dark icon background. Flattened from clients/apple punktfunk_Logo.icon. -->
|
||||||
|
<rect x="0" y="0" width="1000" height="1000" rx="180" ry="180" fill="#1c1530"/>
|
||||||
|
<path d="M403.037,791.672c107.586,0 194.41,-86.824 194.41,-194.41c0,-107.586 -86.824,-194.41 -194.41,-194.41c-107.586,0 -194.41,86.824 -194.41,194.41c0,107.586 86.824,194.41 194.41,194.41Z" fill="#a79ff8"/>
|
||||||
|
<path d="M735.276,540.321c76.075,-76.075 76.075,-198.862 0,-274.937c-76.075,-76.075 -198.862,-76.075 -274.937,0c-76.075,76.075 -76.075,198.862 0,274.937c76.075,76.075 198.862,76.075 274.937,0Z" fill="#6c5bf3"/>
|
||||||
|
<path d="M647.84,590.737c-64.853,17.403 -136.871,0.597 -187.885,-50.416c-51.013,-51.013 -67.819,-123.032 -50.416,-187.885c64.853,-17.403 136.871,-0.597 187.885,50.416c51.013,51.013 67.819,123.032 50.416,187.885Z" fill="#d2c9fb"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,29 @@
|
|||||||
|
// punktfunk brand mark: two overlapping circles forming a lens — the violet
|
||||||
|
// brand identity. Copied verbatim from the marketing site (flattened from the
|
||||||
|
// clients/apple punktfunk_Logo.icon). Back-to-front: large light-violet circle,
|
||||||
|
// deep-violet circle, light highlight where they overlap.
|
||||||
|
export default function BrandMark({ className }: { className?: string }) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
aria-label="punktfunk"
|
||||||
|
role="img"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 1000 1000"
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
<title>punktfunk</title>
|
||||||
|
<path
|
||||||
|
d="M403.037,791.672c107.586,0 194.41,-86.824 194.41,-194.41c0,-107.586 -86.824,-194.41 -194.41,-194.41c-107.586,0 -194.41,86.824 -194.41,194.41c0,107.586 86.824,194.41 194.41,194.41Z"
|
||||||
|
fill="#a79ff8"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M735.276,540.321c76.075,-76.075 76.075,-198.862 0,-274.937c-76.075,-76.075 -198.862,-76.075 -274.937,0c-76.075,76.075 -76.075,198.862 0,274.937c76.075,76.075 198.862,76.075 274.937,0Z"
|
||||||
|
fill="#6c5bf3"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
d="M647.84,590.737c-64.853,17.403 -136.871,0.597 -187.885,-50.416c-51.013,-51.013 -67.819,-123.032 -50.416,-187.885c64.853,-17.403 136.871,-0.597 187.885,50.416c51.013,51.013 67.819,123.032 50.416,187.885Z"
|
||||||
|
fill="#d2c9fb"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
import { getRouteApi } from '@tanstack/react-router'
|
||||||
|
import type { NavigationLink, NavigationSection } from '@/lib/cms'
|
||||||
|
|
||||||
|
const rootApi = getRouteApi('__root__')
|
||||||
|
|
||||||
|
// The docs share the marketing site's footer (same CMS global). Root-relative
|
||||||
|
// links target the website, so resolve them against its origin — the docs don't
|
||||||
|
// host /legal/* etc. themselves. Mirrors the website Footer, themed for docs.
|
||||||
|
const SITE_URL = 'https://punktfunk.unom.io'
|
||||||
|
const resolve = (to?: string | null) =>
|
||||||
|
to ? (to.startsWith('/') ? `${SITE_URL}${to}` : to) : '#'
|
||||||
|
|
||||||
|
export default function Footer() {
|
||||||
|
const { footer } = rootApi.useLoaderData()
|
||||||
|
const sections: NavigationSection[] = footer?.sections ?? []
|
||||||
|
const tagline = footer?.tagline?.trim()
|
||||||
|
|
||||||
|
if (!sections.length && !tagline) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<footer className="border-t border-fd-border bg-fd-card">
|
||||||
|
<div className="mx-auto flex w-full max-w-6xl flex-row flex-wrap gap-12 px-4 py-12 sm:px-6">
|
||||||
|
{sections.map((group, gi) => (
|
||||||
|
<div key={group.id ?? gi}>
|
||||||
|
{group.title && (
|
||||||
|
<h3 className="mb-2 text-sm font-semibold text-fd-foreground">
|
||||||
|
{group.title}
|
||||||
|
</h3>
|
||||||
|
)}
|
||||||
|
<div className="flex flex-col gap-1">
|
||||||
|
{(group.entries ?? []).map((item: NavigationLink, i) => (
|
||||||
|
<a
|
||||||
|
key={item.id ?? `${item.to}-${i}`}
|
||||||
|
href={resolve(item.to)}
|
||||||
|
className="text-sm text-fd-muted-foreground transition-colors hover:text-fd-foreground"
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</a>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{tagline && (
|
||||||
|
<p className="ml-auto self-end text-sm text-fd-muted-foreground">
|
||||||
|
{tagline}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// The punktfunk "funk" wordmark — vectorised from
|
||||||
|
// Export/Punktfunk_Logo-Text_No-Border_Dark.svg (the white export background is
|
||||||
|
// dropped). Inline SVG using currentColor so it recolours per theme: the
|
||||||
|
// deep-violet brand on light, the light-violet lens highlight on dark (matching
|
||||||
|
// the marketing site). Size via height (e.g. `h-4`); width follows the viewBox.
|
||||||
|
export default function Wordmark({ className = '' }: { className?: string }) {
|
||||||
|
return (
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
aria-label="punktfunk"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox="0 0 579 136"
|
||||||
|
fill="currentColor"
|
||||||
|
className={`w-auto text-[var(--pf-brand)] dark:text-[var(--pf-highlight)] ${className}`}
|
||||||
|
>
|
||||||
|
<title>punktfunk</title>
|
||||||
|
<path d="M16.782,16.051l0,102.687l31.253,0l0,-35.563l73.436,0l0,-23.555l-73.436,0l0,-19.398l77.285,0l0,-24.171l-108.537,0Z" />
|
||||||
|
<path d="M131.785,16.051l0,47.264c0.154,16.627 0.154,16.627 0.308,20.014c0.77,15.087 2.463,21.4 7.544,26.634c7.698,8.16 20.014,10.315 59.272,10.315c23.863,0 34.178,-0.616 43.415,-2.463c11.7,-2.463 19.552,-10.623 21.246,-22.323c0.924,-7.236 1.078,-8.929 1.54,-32.176l0,-47.264l-31.253,0l0,47.264c0,2.155 -0.154,7.082 -0.308,10.623c-0.462,9.699 -1.232,12.47 -3.695,15.087c-3.387,3.695 -9.853,4.619 -31.407,4.619c-26.634,0 -32.638,-1.693 -34.332,-9.853c-0.77,-4.157 -0.77,-4.311 -1.078,-20.476l0,-47.264l-31.253,0Z" />
|
||||||
|
<path d="M271.575,15.943l0,102.687l31.868,0l-0.77,-76.669l3.387,0l54.038,76.669l54.346,0l0,-102.687l-31.868,0l0.77,76.515l-3.233,0l-53.73,-76.515l-54.808,0Z" />
|
||||||
|
<path d="M420.91,15.943l0,102.687l31.253,0l0,-39.258l17.089,0l46.032,39.258l47.418,0l-64.353,-52.344l59.426,-50.959l-47.88,0l-40.644,37.873l-17.089,0l0,-37.257l-31.253,0Z" />
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
// The docs reuse the punktfunk marketing site's footer — the same Payload CMS
|
||||||
|
// global on the shared unom CMS (cms.unom.io). It's a read-only GET, so a plain
|
||||||
|
// typed fetch rather than pulling in the Payload SDK + generated types.
|
||||||
|
const CMS_URL = 'https://cms.unom.io'
|
||||||
|
|
||||||
|
export interface NavigationLink {
|
||||||
|
id?: string | null
|
||||||
|
label?: string | null
|
||||||
|
to?: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NavigationSection {
|
||||||
|
id?: string | null
|
||||||
|
title?: string | null
|
||||||
|
entries?: NavigationLink[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Footer {
|
||||||
|
tagline?: string | null
|
||||||
|
sections?: NavigationSection[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function findFooter(): Promise<Footer> {
|
||||||
|
const res = await fetch(`${CMS_URL}/api/globals/footer?locale=en&depth=1`)
|
||||||
|
if (!res.ok) throw new Error(`CMS footer request failed: ${res.status}`)
|
||||||
|
return res.json() as Promise<Footer>
|
||||||
|
}
|
||||||
@@ -1,10 +1,23 @@
|
|||||||
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'
|
import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared'
|
||||||
|
import BrandMark from '@/components/BrandMark'
|
||||||
|
import Wordmark from '@/components/Wordmark'
|
||||||
|
|
||||||
// Shared chrome (nav title, links) for both the docs layout and the home layout.
|
// Shared chrome (nav title, links) for both the docs layout and the home layout.
|
||||||
|
// The lens mark + wordmark mirror the punktfunk marketing site's header.
|
||||||
export function baseOptions(): BaseLayoutProps {
|
export function baseOptions(): BaseLayoutProps {
|
||||||
return {
|
return {
|
||||||
nav: {
|
nav: {
|
||||||
title: 'punktfunk',
|
title: (
|
||||||
|
<>
|
||||||
|
<BrandMark className="size-6" />
|
||||||
|
<Wordmark className="h-4" />
|
||||||
|
</>
|
||||||
|
),
|
||||||
},
|
},
|
||||||
|
links: [
|
||||||
|
{ text: 'Docs', url: '/docs' },
|
||||||
|
{ text: 'Website', url: 'https://punktfunk.unom.io' },
|
||||||
|
{ text: 'Source code', url: 'https://git.unom.io/unom/punktfunk' },
|
||||||
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,30 @@
|
|||||||
/// <reference types="vite/client" />
|
/// <reference types="vite/client" />
|
||||||
import { createRootRoute, HeadContent, Outlet, Scripts } from '@tanstack/react-router'
|
import { createRootRoute, HeadContent, Outlet, Scripts } from '@tanstack/react-router'
|
||||||
|
import { createServerFn } from '@tanstack/react-start'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { RootProvider } from 'fumadocs-ui/provider/tanstack'
|
import { RootProvider } from 'fumadocs-ui/provider/tanstack'
|
||||||
|
import '@fontsource-variable/geist'
|
||||||
|
import Footer from '@/components/Footer'
|
||||||
|
import { type Footer as FooterData, findFooter } from '@/lib/cms'
|
||||||
import appCss from '@/styles/app.css?url'
|
import appCss from '@/styles/app.css?url'
|
||||||
|
|
||||||
|
// The footer is global and shared with the marketing site (one CMS global).
|
||||||
|
// Fetch it once at the root, server-side, falling back to null so a CMS hiccup
|
||||||
|
// never breaks the page.
|
||||||
|
const getFooter = createServerFn({ method: 'GET' }).handler(
|
||||||
|
async (): Promise<FooterData | null> => {
|
||||||
|
try {
|
||||||
|
return await findFooter()
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
export const Route = createRootRoute({
|
export const Route = createRootRoute({
|
||||||
|
loader: async (): Promise<{ footer: FooterData | null }> => ({
|
||||||
|
footer: await getFooter(),
|
||||||
|
}),
|
||||||
head: () => ({
|
head: () => ({
|
||||||
meta: [
|
meta: [
|
||||||
{ charSet: 'utf-8' },
|
{ charSet: 'utf-8' },
|
||||||
@@ -12,7 +32,10 @@ export const Route = createRootRoute({
|
|||||||
{ name: 'color-scheme', content: 'dark light' },
|
{ name: 'color-scheme', content: 'dark light' },
|
||||||
{ title: 'punktfunk docs' },
|
{ title: 'punktfunk docs' },
|
||||||
],
|
],
|
||||||
links: [{ rel: 'stylesheet', href: appCss }],
|
links: [
|
||||||
|
{ rel: 'stylesheet', href: appCss },
|
||||||
|
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
component: RootComponent,
|
component: RootComponent,
|
||||||
})
|
})
|
||||||
@@ -32,7 +55,10 @@ function RootDocument({ children }: { children: React.ReactNode }) {
|
|||||||
<HeadContent />
|
<HeadContent />
|
||||||
</head>
|
</head>
|
||||||
<body className="flex flex-col min-h-screen">
|
<body className="flex flex-col min-h-screen">
|
||||||
<RootProvider>{children}</RootProvider>
|
<RootProvider>
|
||||||
|
{children}
|
||||||
|
<Footer />
|
||||||
|
</RootProvider>
|
||||||
<Scripts />
|
<Scripts />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { createFileRoute, Link } from '@tanstack/react-router'
|
import { createFileRoute, Link } from '@tanstack/react-router'
|
||||||
import { HomeLayout } from 'fumadocs-ui/layouts/home'
|
import { HomeLayout } from 'fumadocs-ui/layouts/home'
|
||||||
|
import BrandMark from '@/components/BrandMark'
|
||||||
|
import Wordmark from '@/components/Wordmark'
|
||||||
import { baseOptions } from '@/lib/layout.shared'
|
import { baseOptions } from '@/lib/layout.shared'
|
||||||
|
|
||||||
export const Route = createFileRoute('/')({ component: Home })
|
export const Route = createFileRoute('/')({ component: Home })
|
||||||
@@ -8,15 +10,16 @@ function Home() {
|
|||||||
return (
|
return (
|
||||||
<HomeLayout {...baseOptions()}>
|
<HomeLayout {...baseOptions()}>
|
||||||
<main className="flex flex-1 flex-col items-center justify-center gap-6 px-4 py-24 text-center">
|
<main className="flex flex-1 flex-col items-center justify-center gap-6 px-4 py-24 text-center">
|
||||||
<h1 className="text-4xl font-bold tracking-tight">punktfunk</h1>
|
<BrandMark className="size-20 drop-shadow-[0_8px_30px_rgba(108,91,243,0.45)]" />
|
||||||
|
<Wordmark className="h-12 md:h-14" />
|
||||||
<p className="max-w-xl text-fd-muted-foreground">
|
<p className="max-w-xl text-fd-muted-foreground">
|
||||||
A ground-up low-latency desktop and game streaming stack, built Linux-first, with a
|
Linux-first, low-latency desktop and game streaming — a shared Rust protocol
|
||||||
shared Rust protocol core and native clients per platform.
|
core with native clients per platform.
|
||||||
</p>
|
</p>
|
||||||
<Link
|
<Link
|
||||||
to="/docs/$"
|
to="/docs/$"
|
||||||
params={{ _splat: '' }}
|
params={{ _splat: '' }}
|
||||||
className="rounded-lg bg-fd-primary px-5 py-2.5 font-medium text-fd-primary-foreground"
|
className="rounded-lg bg-brand px-5 py-2.5 font-medium text-white transition-colors hover:bg-brand/90"
|
||||||
>
|
>
|
||||||
Read the docs
|
Read the docs
|
||||||
</Link>
|
</Link>
|
||||||
|
|||||||
@@ -1,6 +1,77 @@
|
|||||||
@import 'tailwindcss';
|
@import 'tailwindcss';
|
||||||
@import 'fumadocs-ui/css/neutral.css';
|
@import 'fumadocs-ui/css/purple.css';
|
||||||
@import 'fumadocs-ui/css/preset.css';
|
@import 'fumadocs-ui/css/preset.css';
|
||||||
|
|
||||||
/* Pull Fumadocs UI's own classes into the Tailwind 4 scan so they aren't purged. */
|
/* Pull Fumadocs UI's own classes — and @unom/ui's compiled components — into
|
||||||
|
the Tailwind 4 scan so their utilities aren't purged. @unom/ui is the shared
|
||||||
|
design-token system the punktfunk marketing site also builds on. */
|
||||||
@source '../../node_modules/fumadocs-ui/dist/**/*.js';
|
@source '../../node_modules/fumadocs-ui/dist/**/*.js';
|
||||||
|
@source '../../node_modules/@unom/ui/dist/**/*.{js,mjs}';
|
||||||
|
|
||||||
|
/* ── punktfunk brand ────────────────────────────────────────────────────────
|
||||||
|
The brand colour is the violet lens mark. (The marketing site's blue is just
|
||||||
|
a page background, not the brand.) These values feed both @unom/ui's semantic
|
||||||
|
token contract (--brand/--primary/--accent/--highlight) and the Fumadocs
|
||||||
|
--color-fd-* chrome, so the docs carry the same identity in light and dark. */
|
||||||
|
:root {
|
||||||
|
--pf-brand: #6c5bf3; /* deep violet — primary */
|
||||||
|
--pf-brand-light: #a79ff8; /* light violet */
|
||||||
|
--pf-highlight: #d2c9fb; /* lens highlight */
|
||||||
|
|
||||||
|
/* @unom/ui token contract. */
|
||||||
|
--brand: var(--pf-brand);
|
||||||
|
--primary: var(--pf-brand);
|
||||||
|
--accent: var(--pf-brand);
|
||||||
|
--highlight: var(--pf-highlight);
|
||||||
|
--radius: 0.625rem;
|
||||||
|
|
||||||
|
/* Fumadocs accent → brand violet (light mode). */
|
||||||
|
--color-fd-primary: var(--pf-brand);
|
||||||
|
--color-fd-ring: var(--pf-brand);
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
/* Lighter violet reads better against the dark surface. */
|
||||||
|
--primary: var(--pf-brand-light);
|
||||||
|
--accent: var(--pf-brand-light);
|
||||||
|
|
||||||
|
--color-fd-primary: var(--pf-brand-light);
|
||||||
|
--color-fd-ring: var(--pf-brand-light);
|
||||||
|
|
||||||
|
/* Tint Fumadocs' dark chrome toward the brand's violet-dark (the app-icon
|
||||||
|
surface #1c1530) instead of the default neutral-dark. */
|
||||||
|
--color-fd-background: #141019;
|
||||||
|
--color-fd-card: #1c1530;
|
||||||
|
--color-fd-popover: #1c1530;
|
||||||
|
--color-fd-secondary: #221a36;
|
||||||
|
--color-fd-muted: #1f1830;
|
||||||
|
--color-fd-accent: #241c3d;
|
||||||
|
--color-fd-border: #2a2148;
|
||||||
|
}
|
||||||
|
|
||||||
|
@theme {
|
||||||
|
/* Geist — the punktfunk brand typeface, same as the marketing site
|
||||||
|
(the @fontsource-variable/geist face is loaded in __root.tsx). */
|
||||||
|
--font-sans: 'Geist Variable', ui-sans-serif, system-ui, sans-serif;
|
||||||
|
--font-display: 'Geist Variable', ui-sans-serif, system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expose the shared brand + surface tokens as Tailwind colours (bg-brand,
|
||||||
|
text-primary, bg-neutral…), mirroring @unom/ui's own @theme mapping so its
|
||||||
|
utilities resolve to the docs' current (light/dark) surfaces. */
|
||||||
|
@theme inline {
|
||||||
|
--color-brand: var(--brand);
|
||||||
|
--color-primary: var(--primary);
|
||||||
|
--color-accent: var(--accent);
|
||||||
|
--color-highlight: var(--highlight);
|
||||||
|
--color-main: var(--color-fd-foreground);
|
||||||
|
--color-secondary: var(--color-fd-muted-foreground);
|
||||||
|
--color-neutral: var(--color-fd-background);
|
||||||
|
--color-neutral-accent: var(--color-fd-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
@layer base {
|
||||||
|
body {
|
||||||
|
font-family: var(--font-sans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user