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
15 changes: 4 additions & 11 deletions apps/server/src/server/static-theme.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import { ICON_COLOR_IDS, type IconColorId } from "../shared/icon-colors.js";

type EmbeddedStaticAsset = {
routePath: string;
contentType: string;
base64: string;
};

export const VALID_ICON_COLORS = [
"teal",
"blue",
"purple",
"red",
"orange",
"amber",
"pink",
"cyan",
] as const;
export const VALID_ICON_COLORS = ICON_COLOR_IDS;

export type IconColor = (typeof VALID_ICON_COLORS)[number];
export type IconColor = IconColorId;

const DEFAULT_ICON_COLOR: IconColor = "teal";

Expand Down
29 changes: 29 additions & 0 deletions apps/server/src/shared/icon-colors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* Brand icon colour palette.
*
* Single source of truth shared by the server (settings validation and the
* static theme runtime), the web client (Appearance settings swatches — see
* apps/web/src/hooks/use-icon-color.ts) and scripts/generate-icon-colors.ts,
* which renders the SVG/PNG variants under apps/web/public/icons/. Web and the
* script import this module directly across the workspace boundary, so keep it
* dependency-free: no node imports, no browser globals.
*
* Order matters — it drives the swatch order rendered in Appearance settings.
*/

export const ICON_COLOR_PALETTE = [
{ id: "teal", primary: "#14B981", dark: "#0D8358" },
{ id: "blue", primary: "#3B82F6", dark: "#2563EB" },
{ id: "purple", primary: "#8B5CF6", dark: "#6D28D9" },
{ id: "red", primary: "#EF4444", dark: "#B91C1C" },
{ id: "orange", primary: "#F97316", dark: "#C2410C" },
{ id: "amber", primary: "#F59E0B", dark: "#B45309" },
{ id: "pink", primary: "#EC4899", dark: "#BE185D" },
{ id: "cyan", primary: "#06B6D4", dark: "#0E7490" },
] as const;

export type IconColorId = (typeof ICON_COLOR_PALETTE)[number]["id"];

export const ICON_COLOR_IDS: readonly IconColorId[] = ICON_COLOR_PALETTE.map(
(color) => color.id
);
51 changes: 30 additions & 21 deletions apps/web/src/hooks/use-icon-color.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,43 @@
import { useCallback } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";

export const ICON_COLORS = [
"teal",
"blue",
"purple",
"red",
"orange",
"amber",
"pink",
"cyan",
] as const;
export type IconColorId = (typeof ICON_COLORS)[number];
/**
* Palette ids and swatch hexes come from the shared server module so the web
* client always matches what the server accepts and what the icon generator
* renders (see apps/server/src/shared/icon-colors.ts). Display labels are
* web-only and live here.
*/
import {
ICON_COLOR_PALETTE,
type IconColorId,
} from "../../../server/src/shared/icon-colors";

export type { IconColorId };

const ICON_COLOR_LABELS: Record<IconColorId, string> = {
teal: "Teal",
blue: "Blue",
purple: "Purple",
red: "Red",
orange: "Orange",
amber: "Amber",
pink: "Pink",
cyan: "Cyan",
};

export type IconColorDefinition = {
id: IconColorId;
label: string;
swatch: string;
};

export const ICON_COLOR_OPTIONS: IconColorDefinition[] = [
{ id: "teal", label: "Teal", swatch: "#14B981" },
{ id: "blue", label: "Blue", swatch: "#3B82F6" },
{ id: "purple", label: "Purple", swatch: "#8B5CF6" },
{ id: "red", label: "Red", swatch: "#EF4444" },
{ id: "orange", label: "Orange", swatch: "#F97316" },
{ id: "amber", label: "Amber", swatch: "#F59E0B" },
{ id: "pink", label: "Pink", swatch: "#EC4899" },
{ id: "cyan", label: "Cyan", swatch: "#06B6D4" },
];
export const ICON_COLOR_OPTIONS: IconColorDefinition[] = ICON_COLOR_PALETTE.map(
(color) => ({
id: color.id,
label: ICON_COLOR_LABELS[color.id],
swatch: color.primary,
})
);

export function useIconColor(): {
iconColor: IconColorId;
Expand Down
12 changes: 2 additions & 10 deletions scripts/generate-icon-colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import fs from "node:fs";
import path from "node:path";
import sharp from "sharp";
import { ICON_COLOR_PALETTE } from "../apps/server/src/shared/icon-colors.js";

const REPO_ROOT = path.resolve(import.meta.dirname, "..");
const PUBLIC_DIR = path.join(REPO_ROOT, "apps/web/public");
Expand All @@ -22,16 +23,7 @@ const ICONS_DIR = path.join(PUBLIC_DIR, "icons");
const ORIGINAL_PRIMARY = "rgb(7.843137%, 72.54902%, 50.588235%)";
const ORIGINAL_DARK = "rgb(5.098039%, 51.372549%, 34.509804%)";

const COLORS = [
{ id: "teal", primary: "#14B981", dark: "#0D8358" },
{ id: "blue", primary: "#3B82F6", dark: "#2563EB" },
{ id: "purple", primary: "#8B5CF6", dark: "#6D28D9" },
{ id: "red", primary: "#EF4444", dark: "#B91C1C" },
{ id: "orange", primary: "#F97316", dark: "#C2410C" },
{ id: "amber", primary: "#F59E0B", dark: "#B45309" },
{ id: "pink", primary: "#EC4899", dark: "#BE185D" },
{ id: "cyan", primary: "#06B6D4", dark: "#0E7490" },
] as const;
const COLORS = ICON_COLOR_PALETTE;

const SIZES = [
{ name: "pwa-512.png", size: 512 },
Expand Down
Loading