Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion agents/auth/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -794,7 +794,7 @@ export class AuthAgent extends Agent<Env, AuthAgentState> {
// choosing inside a mail our own verified sender delivers. The plain
// text part needs no escaping; the subject is stripped of the line
// breaks a header injection would need.
const html = `<div style="font-family:system-ui,sans-serif;max-width:560px;margin:auto"><h1 style="font-size:22px">${escapeHtml(action)}</h1><p>${escapeHtml(intro)}</p><p><a href="${escapeHtml(message.url)}" style="display:inline-block;background:#f6821f;color:white;padding:12px 18px;border-radius:8px;text-decoration:none">${escapeHtml(action)}</a></p><p style="color:#666;font-size:13px">If you did not request this, you can ignore this email.</p></div>`;
const html = `<div style="font-family:system-ui,sans-serif;max-width:560px;margin:auto"><h1 style="font-size:22px">${escapeHtml(action)}</h1><p>${escapeHtml(intro)}</p><p><a href="${escapeHtml(message.url)}" style="display:inline-block;background:#2f8fe0;color:white;padding:12px 18px;border-radius:8px;text-decoration:none">${escapeHtml(action)}</a></p><p style="color:#666;font-size:13px">If you did not request this, you can ignore this email.</p></div>`;

try {
await this.deliverEmail(message.to, headerSafe(`${action} · Frostbase`), text, html);
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"demo:video": "node scripts/demo-video.mjs",
"demo:live": "node scripts/demo-video.mjs --live",
"build": "vite build",
"brand:generate": "node scripts/brand-generate.mjs",
"preview": "npm run build && wrangler dev",
"prepare": "svelte-kit sync || echo ''",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
Expand Down
60 changes: 60 additions & 0 deletions scripts/brand-generate.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Renders every raster brand asset from the SVG sources in static/, so a
// colour or wordmark change is one edit plus `npm run brand:generate`.
//
// static/favicon.svg -> favicon-16x16, favicon-32x32, icon-192, icon-512
// (transparent: the cube's faces are punched out)
// static/brand/mark.svg -> apple-touch-icon (cube on the dark tile) and
// brand/app-icon (cube on white, dark faces)
// static/brand/github-header.svg, social-preview.svg -> same-named PNGs
import { readFile } from 'node:fs/promises';
import sharp from 'sharp';

const DARK = '#0b0c0f';
const FACES = '#13151a';

const favicon = await readFile('static/favicon.svg', 'utf8');
const mark = await readFile('static/brand/mark.svg', 'utf8');

/** The mark's inner body (defs + paths), for re-placing on a tile. */
const markBody = mark
.replace(/^[\s\S]*?<svg[^>]*>/, '')
.replace(/<\/svg>\s*$/, '')
.replace(/<title>[\s\S]*?<\/title>/, '')
.replace(/<!--[\s\S]*?-->/g, '');

/** The cube centred on a square tile, filling `scale` of its width. */
function tile(size, background, scale, faces) {
const inset = (64 / scale - 64) / 2;
const view = 64 + inset * 2;
const fill = faces ? `<path d="M32 15 18 23v17l14 8 14-8V23l-14-8Z" fill="${faces}"/>` : '';
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="${-inset} ${-inset} ${view} ${view}">
<rect x="${-inset}" y="${-inset}" width="${view}" height="${view}" fill="${background}"/>
${fill}${markBody}</svg>`;
}

const jobs = [
...[16, 32].map((size) => [favicon, size, `static/favicon-${size}x${size}.png`]),
...[192, 512].map((size) => [favicon, size, `static/icon-${size}.png`]),
[tile(180, DARK, 0.72), 180, 'static/apple-touch-icon.png'],
[tile(1254, '#ffffff', 0.66, FACES), 1254, 'static/brand/app-icon.png'],
[
await readFile('static/brand/github-header.svg', 'utf8'),
null,
'static/brand/github-header.png'
],
[
await readFile('static/brand/social-preview.svg', 'utf8'),
null,
'static/brand/social-preview.png'
]
];

for (const [svg, size, out] of jobs) {
// Render dense for crisp edges, then land on the exact target: the square
// size for icons, the SVG's own width/height for the banners.
const width = size ?? Number(svg.match(/<svg[^>]*\swidth="(\d+)"/)?.[1]);
const height = size ?? Number(svg.match(/<svg[^>]*\sheight="(\d+)"/)?.[1]);
const image = sharp(Buffer.from(svg), { density: 384 }).resize(width, height);
await image.png({ compressionLevel: 9 }).toFile(out);
console.log(`wrote ${out}`);
}
6 changes: 3 additions & 3 deletions src/lib/components/console-shell.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* carries the positioning rather than decoration.
*
* The panel follows the theme; only the terminal card inside it is
* theme-stable espresso, via a scoped `dark` class that makes the shadcn
* theme-stable glacier-night, via a scoped `dark` class that makes the shadcn
* tokens inside the card resolve dark in both themes (a terminal is
* naturally dark). Never touches the root theme state.
*
Expand Down Expand Up @@ -67,9 +67,9 @@
</p>

<!-- A terminal is naturally dark: the scoped `dark` class keeps this
card espresso in both themes while the panel follows the theme. -->
card glacier-night in both themes while the panel follows the theme. -->
<div
class="dark space-y-1.5 rounded-lg border bg-card p-4 font-mono text-xs leading-relaxed text-foreground shadow-[0_10px_26px_-14px_oklch(0.1_0.01_60/60%)]"
class="dark space-y-1.5 rounded-lg border bg-card p-4 font-mono text-xs leading-relaxed text-foreground shadow-[0_10px_26px_-14px_oklch(0.1_0.015_255/60%)]"
>
<p><span class="text-primary">$</span> npx frostbase init</p>
<p><span class="text-primary">$</span> frostbase key create server --env-file</p>
Expand Down
2 changes: 1 addition & 1 deletion src/routes/(app)/login/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@

<Button
type="submit"
class="w-full bg-linear-to-b from-[oklch(0.745_0.168_55)] to-[oklch(0.695_0.172_51)] shadow-[0_1px_2px_oklch(0.5_0.15_53/35%),0_4px_18px_-6px_oklch(0.7163_0.1706_53.45/50%),inset_0_1px_0_oklch(1_0_0/22%)] transition-[filter] hover:brightness-105"
class="w-full bg-linear-to-b from-[oklch(0.67_0.148_246)] to-[oklch(0.6_0.152_251)] shadow-[0_1px_2px_oklch(0.45_0.14_252/35%),0_4px_18px_-6px_oklch(0.6341_0.1498_248.54/50%),inset_0_1px_0_oklch(1_0_0/22%)] transition-[filter] hover:brightness-105"
disabled={submitting}
data-testid="console-submit"
>
Expand Down
4 changes: 2 additions & 2 deletions src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<link rel="manifest" href="/site.webmanifest" />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#faf7f1" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#0a0705" />
<meta name="theme-color" media="(prefers-color-scheme: light)" content="#f5f7fa" />
<meta name="theme-color" media="(prefers-color-scheme: dark)" content="#070b12" />
<meta property="og:site_name" content="Frostbase" />
<meta property="og:type" content="website" />
<meta property="og:url" content={shareUrl} />
Expand Down
136 changes: 69 additions & 67 deletions src/routes/layout.css
Original file line number Diff line number Diff line change
Expand Up @@ -8,88 +8,90 @@
@plugin '@tailwindcss/typography';

/*
* Cloudflare-coherent palette on a warm "linen" paper ground.
* Brand anchors: orange #F6821F → oklch(0.7163 0.1706 53.45)
* gold #FAAD3F → oklch(0.8056 0.1493 72.15)
* blue #0051C3 → oklch(0.45 0.19 262) (dashboard/link blue)
* Light mode sits on a warm "linen" off-white ground (hue ~76–85, chroma
* ≤0.022) instead of pure white; cards are *lighter* than the background so
* elevation still reads on tinted paper. `accent` stays a *subtle* hover
* surface (shadcn semantics), tinted warm - never the loud gold (charts only).
* Frost palette on a cool "ice" paper ground.
* Brand anchors: Glacier #2F8FE0 → oklch(0.6341 0.1498 248.54) (primary)
* ice #22B3E8 → oklch(0.719 0.1357 229.56)
* deep #2463EB → oklch(0.5459 0.2154 262.75)
* Light mode sits on a cool off-white ground (hue ~240-250, chroma <=0.02)
* instead of pure white; cards are *lighter* than the background so elevation
* still reads on tinted paper. `accent` stays a *subtle* hover surface (shadcn
* semantics), tinted cool - never a loud brand fill. Charts keep one warm
* series (amber) so five series stay distinguishable on an all-blue brand.
*/
:root {
--background: oklch(0.976 0.008 80);
--foreground: oklch(0.155 0.008 55);
--card: oklch(0.993 0.005 85);
--card-foreground: oklch(0.155 0.008 55);
--popover: oklch(0.993 0.005 85);
--popover-foreground: oklch(0.155 0.008 55);
--primary: oklch(0.7163 0.1706 53.45);
--background: oklch(0.976 0.006 240);
--foreground: oklch(0.16 0.014 255);
--card: oklch(0.994 0.003 240);
--card-foreground: oklch(0.16 0.014 255);
--popover: oklch(0.994 0.003 240);
--popover-foreground: oklch(0.16 0.014 255);
--primary: oklch(0.6341 0.1498 248.54);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.942 0.012 78);
--secondary-foreground: oklch(0.24 0.012 55);
--muted: oklch(0.945 0.01 78);
--muted-foreground: oklch(0.53 0.016 60);
--accent: oklch(0.928 0.022 70);
--accent-foreground: oklch(0.24 0.026 50);
--secondary: oklch(0.944 0.01 242);
--secondary-foreground: oklch(0.24 0.016 255);
--muted: oklch(0.946 0.009 242);
--muted-foreground: oklch(0.52 0.02 252);
--accent: oklch(0.93 0.022 240);
--accent-foreground: oklch(0.24 0.03 255);
--destructive: oklch(0.577 0.245 27.325);
--border: oklch(0.893 0.013 76);
--input: oklch(0.893 0.013 76);
--ring: oklch(0.7163 0.1706 53.45);
--chart-1: oklch(0.7163 0.1706 53.45);
--chart-2: oklch(0.8056 0.1493 72.15);
--chart-3: oklch(0.45 0.19 262);
--border: oklch(0.895 0.012 245);
--input: oklch(0.895 0.012 245);
--ring: oklch(0.6341 0.1498 248.54);
--chart-1: oklch(0.6341 0.1498 248.54);
--chart-2: oklch(0.719 0.1357 229.56);
--chart-3: oklch(0.5459 0.2154 262.75);
--chart-4: oklch(0.35 0.07 260);
--chart-5: oklch(0.47 0.157 37.304);
--chart-5: oklch(0.78 0.15 75);
--radius: 0.625rem;
--sidebar: oklch(0.962 0.01 78);
--sidebar-foreground: oklch(0.155 0.008 55);
--sidebar-primary: oklch(0.7163 0.1706 53.45);
--sidebar: oklch(0.962 0.009 242);
--sidebar-foreground: oklch(0.16 0.014 255);
--sidebar-primary: oklch(0.6341 0.1498 248.54);
--sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.928 0.022 70);
--sidebar-accent-foreground: oklch(0.24 0.026 50);
--sidebar-border: oklch(0.893 0.013 76);
--sidebar-ring: oklch(0.7163 0.1706 53.45);
--sidebar-accent: oklch(0.93 0.022 240);
--sidebar-accent-foreground: oklch(0.24 0.03 255);
--sidebar-border: oklch(0.895 0.012 245);
--sidebar-ring: oklch(0.6341 0.1498 248.54);
}

/*
* Dark linen: the same warm hue family as the light ground (~58–80), pushed
* dark - espresso rather than gray. Deeper background with cards lifted
* further off it and brighter muted text for contrast; borders are warm
* paper at low alpha so hairlines never read cold.
* Dark frost: the same cool hue family as the light ground, pushed dark -
* deep glacier-night rather than neutral gray. Cards lift further off the
* background, muted text brightens for contrast, and borders are pale ice at
* low alpha so hairlines stay cool. Primary brightens slightly so the accent
* keeps its contrast on the darker ground.
*/
.dark {
--background: oklch(0.132 0.008 65);
--foreground: oklch(0.982 0.005 80);
--card: oklch(0.205 0.012 68);
--card-foreground: oklch(0.982 0.005 80);
--popover: oklch(0.205 0.012 68);
--popover-foreground: oklch(0.982 0.005 80);
--primary: oklch(0.7163 0.1706 53.45);
--background: oklch(0.14 0.014 255);
--foreground: oklch(0.982 0.005 240);
--card: oklch(0.205 0.018 255);
--card-foreground: oklch(0.982 0.005 240);
--popover: oklch(0.205 0.018 255);
--popover-foreground: oklch(0.982 0.005 240);
--primary: oklch(0.68 0.145 246);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.275 0.014 66);
--secondary-foreground: oklch(0.982 0.005 80);
--muted: oklch(0.268 0.012 66);
--muted-foreground: oklch(0.735 0.018 72);
--accent: oklch(0.298 0.028 58);
--accent-foreground: oklch(0.985 0.008 75);
--secondary: oklch(0.275 0.02 255);
--secondary-foreground: oklch(0.982 0.005 240);
--muted: oklch(0.268 0.018 255);
--muted-foreground: oklch(0.74 0.022 245);
--accent: oklch(0.3 0.035 250);
--accent-foreground: oklch(0.985 0.008 240);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(0.93 0.03 80 / 12%);
--input: oklch(0.93 0.03 80 / 16%);
--ring: oklch(0.7163 0.1706 53.45);
--chart-1: oklch(0.7163 0.1706 53.45);
--chart-2: oklch(0.8056 0.1493 72.15);
--chart-3: oklch(0.62 0.17 258);
--chart-4: oklch(0.75 0.09 250);
--chart-5: oklch(0.65 0.14 40);
--sidebar: oklch(0.185 0.011 66);
--sidebar-foreground: oklch(0.982 0.005 80);
--sidebar-primary: oklch(0.7163 0.1706 53.45);
--border: oklch(0.93 0.03 240 / 12%);
--input: oklch(0.93 0.03 240 / 16%);
--ring: oklch(0.68 0.145 246);
--chart-1: oklch(0.68 0.145 246);
--chart-2: oklch(0.78 0.12 228);
--chart-3: oklch(0.62 0.19 262);
--chart-4: oklch(0.75 0.06 250);
--chart-5: oklch(0.8 0.14 75);
--sidebar: oklch(0.185 0.016 255);
--sidebar-foreground: oklch(0.982 0.005 240);
--sidebar-primary: oklch(0.68 0.145 246);
--sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.298 0.028 58);
--sidebar-accent-foreground: oklch(0.985 0.008 75);
--sidebar-border: oklch(0.93 0.03 80 / 12%);
--sidebar-ring: oklch(0.7163 0.1706 53.45);
--sidebar-accent: oklch(0.3 0.035 250);
--sidebar-accent-foreground: oklch(0.985 0.008 240);
--sidebar-border: oklch(0.93 0.03 240 / 12%);
--sidebar-ring: oklch(0.68 0.145 246);
}

@theme inline {
Expand Down
Binary file modified static/apple-touch-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/brand/app-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/brand/github-header.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions static/brand/github-header.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions static/brand/mark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/brand/social-preview.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions static/brand/social-preview.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions static/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/icon-192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified static/icon-512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading