Compare commits

...

6 Commits

Author SHA1 Message Date
24812df89b design-surfaces: explicit ::text cast on every query param
Add ::text cast to all $1/$2 parameters so PostgreSQL never needs
to infer types. Split SELECT and UPDATE into separate try/catch blocks
with distinct error labels so logs show exactly which query fails.

Made-with: Cursor
2026-03-06 11:29:57 -08:00
53b098ce6a Fix Lock In 42P18: cast id::text to resolve parameter type ambiguity
PostgreSQL could not determine the type of $2 in 'WHERE id = $2'
when id column type is UUID. Casting the column (id::text = $1)
sidesteps the extended-protocol type inference issue. Also moves
projectId to $1 to match the proven working pattern in other routes.

Made-with: Cursor
2026-03-06 11:23:31 -08:00
69eb3b989c Fix BgLayer SVG gradient reference causing dark rectangle in light mode
- beams: replaced SVG gradient <rect fill='url(#bm-glow)'> with a CSS
  radial-gradient div — browser SVG gradient reference fallback is solid
  black which produced the dark rectangle. Also adapt line colors and
  opacity for light mode.
- meteors: switch tail gradient from white-tip to dark-tip in light mode
  so meteors are visible on a light background.
- wavy: remove SVG linearGradient id references (same black-fill risk);
  use inline hex alpha on fill instead.

Made-with: Cursor
2026-03-06 11:17:13 -08:00
7eaf1ca4f1 Filter color palettes by dark/light mode
- Add themeMode?: 'dark'|'light' to ThemeColor (unset = any mode)
- Tag all DaisyUI themes: 11 dark (synthwave, aqua, luxury, night, etc.)
  and 6 light (light, cupcake, valentine, cyberpunk, retro, winter)
- Tag HeroUI Marketing themes: purple/blue/teal/modern=light, dark=dark
- Aceternity accent palettes stay untagged (work with either mode)
- Filter availableColorThemes in SurfaceSection by designConfig.mode
- Auto-reset active palette when mode switches makes previously
  selected palette incompatible

Made-with: Cursor
2026-03-06 11:03:22 -08:00
5e4cce55de Fix Lock In 500 error: fs_projects has no updated_at column
The PATCH handler used SQL 'updated_at = NOW()' which doesn't exist
on fs_projects (all timestamps live inside the data JSONB blob).
Rewrote to use the same read-merge-write pattern as other working
routes: fetch current data, merge in JS, write back as data::jsonb.

Made-with: Cursor
2026-03-06 10:56:21 -08:00
4eff014ae6 Fix Aceternity gradient background in light mode
BgLayer 'gradient' always rendered rgb(8,0,20) dark base regardless
of mode, covering the container's light bg and making the dark
gradient-text h1 invisible. Split into isDark branches: dark mode
keeps the hard-light blob effect, light mode renders soft pastel
blobs on rgb(248,247,255).

Made-with: Cursor
2026-03-06 10:53:23 -08:00
4 changed files with 110 additions and 84 deletions

View File

@@ -535,11 +535,20 @@ function SurfaceSection({
const activeTheme = surface.themes.find(t => t.id === previewId); const activeTheme = surface.themes.find(t => t.id === previewId);
const ScaffoldComponent = previewId ? SCAFFOLD_REGISTRY[surface.id]?.[previewId] : null; const ScaffoldComponent = previewId ? SCAFFOLD_REGISTRY[surface.id]?.[previewId] : null;
const availableColorThemes: ThemeColor[] = previewId const allColorThemes: ThemeColor[] = previewId
? (THEME_REGISTRY[surface.id]?.[previewId] ?? []) ? (THEME_REGISTRY[surface.id]?.[previewId] ?? [])
: []; : [];
const [selectedColorTheme, setSelectedColorTheme] = useState<ThemeColor | null>(null); const [selectedColorTheme, setSelectedColorTheme] = useState<ThemeColor | null>(null);
const activeColorTheme = selectedColorTheme ?? availableColorThemes[0] ?? null;
// Filter palettes to match the current mode; untagged themes (themeMode undefined) show in any mode
const availableColorThemes = allColorThemes.filter(
ct => !ct.themeMode || ct.themeMode === designConfig.mode
);
// If the selected palette is no longer valid for the new mode, clear it so the
// first compatible one is auto-selected below
const selectedIsCompatible = !selectedColorTheme || availableColorThemes.some(ct => ct.id === selectedColorTheme.id);
const activeColorTheme = (selectedIsCompatible ? selectedColorTheme : null) ?? availableColorThemes[0] ?? null;
// Design config — per-library style choices (mode, background, nav, header, sections, font) // Design config — per-library style choices (mode, background, nav, header, sections, font)
const defaultForLibrary = previewId ? LIBRARY_STYLE_OPTIONS[previewId]?.defaultConfig : undefined; const defaultForLibrary = previewId ? LIBRARY_STYLE_OPTIONS[previewId]?.defaultConfig : undefined;

View File

@@ -3,17 +3,6 @@ import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth/authOptions'; import { authOptions } from '@/lib/auth/authOptions';
import { query } from '@/lib/db-postgres'; import { query } from '@/lib/db-postgres';
async function verifyOwnership(projectId: string, email: string): Promise<boolean> {
const rows = await query<{ id: string }>(
`SELECT p.id FROM fs_projects p
JOIN fs_users u ON u.id = p.user_id
WHERE p.id = $1 AND u.data->>'email' = $2
LIMIT 1`,
[projectId, email]
);
return rows.length > 0;
}
/** /**
* GET — returns surfaces[] and surfaceThemes{} for the project. * GET — returns surfaces[] and surfaceThemes{} for the project.
*/ */
@@ -29,7 +18,7 @@ export async function GET(
const rows = await query<{ data: Record<string, unknown> }>( const rows = await query<{ data: Record<string, unknown> }>(
`SELECT p.data FROM fs_projects p `SELECT p.data FROM fs_projects p
JOIN fs_users u ON u.id = p.user_id JOIN fs_users u ON u.id = p.user_id
WHERE p.id = $1 AND u.data->>'email' = $2 WHERE p.id = $1::text AND u.data->>'email' = $2::text
LIMIT 1`, LIMIT 1`,
[projectId, session.user.email] [projectId, session.user.email]
); );
@@ -63,36 +52,54 @@ export async function PATCH(
const session = await getServerSession(authOptions); const session = await getServerSession(authOptions);
if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); if (!session?.user?.email) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
const owned = await verifyOwnership(projectId, session.user.email); // Step 1: read current data — explicit ::text casts on every param
if (!owned) return NextResponse.json({ error: 'Project not found' }, { status: 404 }); let rows: { data: Record<string, unknown> }[];
try {
rows = await query<{ data: Record<string, unknown> }>(
`SELECT p.data FROM fs_projects p
JOIN fs_users u ON u.id = p.user_id
WHERE p.id = $1::text AND u.data->>'email' = $2::text
LIMIT 1`,
[projectId, session.user.email]
);
} catch (selErr) {
console.error('[design-surfaces PATCH] SELECT failed:', selErr);
return NextResponse.json({ error: 'Internal error (select)' }, { status: 500 });
}
if (rows.length === 0) return NextResponse.json({ error: 'Project not found' }, { status: 404 });
const current = rows[0].data ?? {};
const body = await req.json() as const body = await req.json() as
| { surfaces: string[] } | { surfaces: string[] }
| { surface: string; theme: string }; | { surface: string; theme: string };
let updated: Record<string, unknown>;
if ('surfaces' in body) { if ('surfaces' in body) {
await query( updated = { ...current, surfaces: body.surfaces, updatedAt: new Date().toISOString() };
`UPDATE fs_projects
SET data = data || jsonb_build_object('surfaces', $2::jsonb),
updated_at = NOW()
WHERE id = $1`,
[projectId, JSON.stringify(body.surfaces)]
);
} else if ('surface' in body && 'theme' in body) { } else if ('surface' in body && 'theme' in body) {
await query( const existing = (current.surfaceThemes ?? {}) as Record<string, string>;
`UPDATE fs_projects updated = {
SET data = data || jsonb_build_object( ...current,
'surfaceThemes', surfaceThemes: { ...existing, [body.surface]: body.theme },
COALESCE(data->'surfaceThemes', '{}'::jsonb) || jsonb_build_object($2, $3) updatedAt: new Date().toISOString(),
), };
updated_at = NOW()
WHERE id = $1`,
[projectId, body.surface, body.theme]
);
} else { } else {
return NextResponse.json({ error: 'Invalid body' }, { status: 400 }); return NextResponse.json({ error: 'Invalid body' }, { status: 400 });
} }
// Step 2: write back — explicit ::text cast on id param, ::jsonb on data param
try {
await query(
`UPDATE fs_projects SET data = $1::jsonb WHERE id = $2::text`,
[JSON.stringify(updated), projectId]
);
} catch (updErr) {
console.error('[design-surfaces PATCH] UPDATE failed:', updErr);
return NextResponse.json({ error: 'Internal error (update)' }, { status: 500 });
}
return NextResponse.json({ success: true }); return NextResponse.json({ success: true });
} catch (err) { } catch (err) {
console.error('[design-surfaces PATCH]', err); console.error('[design-surfaces PATCH]', err);

View File

@@ -515,7 +515,18 @@ export function MarketingAceternity({ themeColor, config }: { themeColor?: Theme
const border= isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.1)"; const border= isDark ? "rgba(255,255,255,0.08)" : "rgba(0,0,0,0.1)";
const BgLayer = () => { const BgLayer = () => {
if (bgStyle === "gradient") return ( if (bgStyle === "gradient") {
if (!isDark) return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0, background: "rgb(248,247,255)" }}>
<div style={{ position: "absolute", inset: 0, filter: "blur(70px)", opacity: 0.55 }}>
<div style={{ position: "absolute", width: "70%", height: "70%", top: "5%", left: "10%", borderRadius: "50%", background: `radial-gradient(circle, rgba(196,181,253,0.7) 0%, transparent 65%)`, animation: "ace-blob1 22s ease infinite" }} />
<div style={{ position: "absolute", width: "65%", height: "65%", top: "-10%", left: "-5%", borderRadius: "50%", background: `radial-gradient(circle, rgba(147,197,253,0.6) 0%, transparent 65%)`, animation: "ace-blob2 18s reverse infinite" }} />
<div style={{ position: "absolute", width: "55%", height: "55%", bottom: "10%", right: "10%", borderRadius: "50%", background: `radial-gradient(circle, rgba(216,180,254,0.5) 0%, transparent 65%)`, animation: "ace-blob3 28s linear infinite" }} />
<div style={{ position: "absolute", width: "50%", height: "50%", bottom: "-10%", left: "30%", borderRadius: "50%", background: `radial-gradient(circle, ${p}40 0%, transparent 65%)`, animation: "ace-blob4 24s ease infinite" }} />
</div>
</div>
);
return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0, background: "rgb(8,0,20)" }}> <div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0, background: "rgb(8,0,20)" }}>
<div style={{ position: "absolute", inset: 0, filter: "blur(55px)", mixBlendMode: "hard-light" }}> <div style={{ position: "absolute", inset: 0, filter: "blur(55px)", mixBlendMode: "hard-light" }}>
<div style={{ position: "absolute", width: "70%", height: "70%", top: "5%", left: "10%", borderRadius: "50%", background: `radial-gradient(circle, rgba(18,113,255,0.85) 0%, transparent 65%)`, animation: "ace-blob1 22s ease infinite" }} /> <div style={{ position: "absolute", width: "70%", height: "70%", top: "5%", left: "10%", borderRadius: "50%", background: `radial-gradient(circle, rgba(18,113,255,0.85) 0%, transparent 65%)`, animation: "ace-blob1 22s ease infinite" }} />
@@ -525,6 +536,7 @@ export function MarketingAceternity({ themeColor, config }: { themeColor?: Theme
</div> </div>
</div> </div>
); );
}
if (bgStyle === "shader") return ( if (bgStyle === "shader") return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0 }}> <div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0 }}>
<div style={{ position: "absolute", inset: 0, background: "linear-gradient(135deg, #7c3aed 0%, #db2777 35%, #ea580c 65%, #ca8a04 100%)", opacity: 0.92 }} /> <div style={{ position: "absolute", inset: 0, background: "linear-gradient(135deg, #7c3aed 0%, #db2777 35%, #ea580c 65%, #ca8a04 100%)", opacity: 0.92 }} />
@@ -534,21 +546,19 @@ export function MarketingAceternity({ themeColor, config }: { themeColor?: Theme
); );
if (bgStyle === "beams") return ( if (bgStyle === "beams") return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0 }}> <div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0 }}>
{/* CSS radial glow — no SVG gradient ID reference (avoids black-fill fallback) */}
<div style={{ position: "absolute", top: 0, left: "50%", transform: "translateX(-50%)", width: "80%", height: "60%", background: `radial-gradient(ellipse at 50% 0%, ${p}${isDark ? "30" : "18"}, transparent 70%)`, pointerEvents: "none" }} />
<svg style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }} viewBox="0 0 400 700" preserveAspectRatio="xMidYMid slice"> <svg style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }} viewBox="0 0 400 700" preserveAspectRatio="xMidYMid slice">
<defs>
<radialGradient id="bm-glow" cx="50%" cy="0%" r="75%">
<stop offset="0%" stopColor={p} stopOpacity="0.18" />
<stop offset="100%" stopColor={p} stopOpacity="0" />
</radialGradient>
</defs>
<rect width="400" height="700" fill="url(#bm-glow)" />
{Array.from({ length: 14 }).map((_, i) => { {Array.from({ length: 14 }).map((_, i) => {
const x = 200 + (i - 7) * 32; const x = 200 + (i - 7) * 32;
const lineColor = isDark
? (i % 3 === 0 ? p : i % 3 === 1 ? "#3b82f6" : "#06b6d4")
: (i % 3 === 0 ? p : i % 3 === 1 ? "#6366f1" : "#0891b2");
return ( return (
<line key={i} x1={200} y1={0} x2={x} y2={700} <line key={i} x1={200} y1={0} x2={x} y2={700}
stroke={i % 3 === 0 ? p : i % 3 === 1 ? "#3b82f6" : "#06b6d4"} stroke={lineColor}
strokeWidth={i % 4 === 0 ? 0.7 : 0.35} strokeWidth={i % 4 === 0 ? 0.7 : 0.35}
strokeOpacity={0.12 + (i % 3) * 0.05} strokeOpacity={isDark ? (0.12 + (i % 3) * 0.05) : (0.18 + (i % 3) * 0.06)}
style={{ animation: `ace-beam-pulse ${3 + i * 0.4}s ease-in-out ${i * 0.22}s infinite` }} style={{ animation: `ace-beam-pulse ${3 + i * 0.4}s ease-in-out ${i * 0.22}s infinite` }}
/> />
); );
@@ -558,14 +568,16 @@ export function MarketingAceternity({ themeColor, config }: { themeColor?: Theme
); );
if (bgStyle === "meteors") return ( if (bgStyle === "meteors") return (
<div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0 }}> <div style={{ position: "absolute", inset: 0, overflow: "hidden", zIndex: 0 }}>
<div style={{ position: "absolute", inset: 0, background: `radial-gradient(ellipse 55% 35% at 50% 0%, ${p}15, transparent)` }} /> <div style={{ position: "absolute", inset: 0, background: `radial-gradient(ellipse 55% 35% at 50% 0%, ${p}${isDark ? "20" : "12"}, transparent)` }} />
{Array.from({ length: 12 }).map((_, i) => ( {Array.from({ length: 12 }).map((_, i) => (
<div key={i} style={{ <div key={i} style={{
position: "absolute", position: "absolute",
top: `${(i * 31 + 5) % 65}%`, top: `${(i * 31 + 5) % 65}%`,
right: `${(i * 47) % 90}%`, right: `${(i * 47) % 90}%`,
width: `${36 + i * 8}px`, height: "1.5px", width: `${36 + i * 8}px`, height: "1.5px",
background: `linear-gradient(90deg, ${p}ee, rgba(255,255,255,0.8), transparent)`, background: isDark
? `linear-gradient(90deg, ${p}ee, rgba(255,255,255,0.8), transparent)`
: `linear-gradient(90deg, ${p}cc, rgba(0,0,0,0.15), transparent)`,
transform: "rotate(-35deg)", transform: "rotate(-35deg)",
animation: `ace-meteor ${1.2 + (i % 5) * 0.5}s linear ${i * 0.55}s infinite`, animation: `ace-meteor ${1.2 + (i % 5) * 0.5}s linear ${i * 0.55}s infinite`,
borderRadius: "50%", borderRadius: "50%",
@@ -602,14 +614,8 @@ export function MarketingAceternity({ themeColor, config }: { themeColor?: Theme
if (bgStyle === "wavy") return ( if (bgStyle === "wavy") return (
<div style={{ position: "absolute", top: 0, left: 0, right: 0, height: "55%", zIndex: 0, overflow: "hidden" }}> <div style={{ position: "absolute", top: 0, left: 0, right: 0, height: "55%", zIndex: 0, overflow: "hidden" }}>
<svg viewBox="0 0 400 120" preserveAspectRatio="none" style={{ width: "100%", height: "100%" }}> <svg viewBox="0 0 400 120" preserveAspectRatio="none" style={{ width: "100%", height: "100%" }}>
<defs> <path d="M0,40 Q50,10 100,40 T200,40 T300,40 T400,40 L400,120 L0,120 Z" fill={`${p}${isDark ? "20" : "14"}`} />
<linearGradient id="wg1" x1="0%" y1="0%" x2="100%" y2="0%"> <path d="M0,65 Q70,35 140,65 T280,65 T400,65 L400,120 L0,120 Z" fill={`${p}${isDark ? "0e" : "07"}`} />
<stop offset="0%" stopColor={p} stopOpacity="0.14" />
<stop offset="100%" stopColor="#3b82f6" stopOpacity="0.08" />
</linearGradient>
</defs>
<path d="M0,40 Q50,10 100,40 T200,40 T300,40 T400,40 L400,120 L0,120 Z" fill="url(#wg1)" />
<path d="M0,65 Q70,35 140,65 T280,65 T400,65 L400,120 L0,120 Z" fill={`${p}07`} />
</svg> </svg>
</div> </div>
); );

View File

@@ -17,6 +17,8 @@ export interface ThemeColor {
textColor?: string; textColor?: string;
borderColor?: string; borderColor?: string;
mutedText?: string; mutedText?: string;
/** If set, only show this palette when the user's mode matches. Unset = show for any mode. */
themeMode?: "dark" | "light";
} }
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@@ -93,24 +95,26 @@ export const TREMOR_THEMES: ThemeColor[] = [
]; ];
export const DAISY_THEMES: ThemeColor[] = [ export const DAISY_THEMES: ThemeColor[] = [
{ id: "dark", label: "Dark", primary: "#793ef9", primaryFg: "#fff", activeBg: "rgba(121,62,249,0.2)", activeFg: "#a78bfa", ring: "#4c1d95", bg: "#1d232a", cardBg: "#191e24", textColor: "#a6adba", borderColor: "#2a323c", mutedText: "#6b7280" }, // — dark backgrounds —
{ id: "light", label: "Light", primary: "#570df8", primaryFg: "#fff", activeBg: "#f3f0ff", activeFg: "#4c1d95", ring: "#ddd6fe", bg: "#fff", cardBg: "#fff", textColor: "#1f2937", borderColor: "#e5e7eb", mutedText: "#6b7280" }, { id: "dark", label: "Dark", themeMode: "dark", primary: "#793ef9", primaryFg: "#fff", activeBg: "rgba(121,62,249,0.2)", activeFg: "#a78bfa", ring: "#4c1d95", bg: "#1d232a", cardBg: "#191e24", textColor: "#a6adba", borderColor: "#2a323c", mutedText: "#6b7280" },
{ id: "cupcake", label: "Cupcake", primary: "#65c3c8", primaryFg: "#291334", activeBg: "#d9f5f6", activeFg: "#0e6b70", ring: "#a7eaec", bg: "#faf7f5", cardBg: "#fff", textColor: "#291334", borderColor: "#e9e3df", mutedText: "#9ca3af" }, { id: "synthwave", label: "Synthwave", themeMode: "dark", primary: "#e779c1", primaryFg: "#2d1b69", activeBg: "rgba(231,121,193,0.2)", activeFg: "#f0abdc", ring: "#701a75", bg: "#1a103c", cardBg: "#221551", textColor: "#e2e8f0", borderColor: "#4c3585", mutedText: "#a78bfa" },
{ id: "synthwave", label: "Synthwave", primary: "#e779c1", primaryFg: "#2d1b69", activeBg: "rgba(231,121,193,0.2)", activeFg: "#f0abdc", ring: "#701a75", bg: "#1a103c", cardBg: "#221551", textColor: "#e2e8f0", borderColor: "#4c3585", mutedText: "#a78bfa" }, { id: "halloween", label: "Halloween", themeMode: "dark", primary: "#f28c18", primaryFg: "#fff", activeBg: "rgba(242,140,24,0.15)", activeFg: "#f28c18", ring: "rgba(242,140,24,0.4)", bg: "#212121", cardBg: "#2a2a2a", textColor: "#f4f4f4", borderColor: "#383838", mutedText: "#888" },
{ id: "cyberpunk", label: "Cyberpunk", primary: "#ff7598", primaryFg: "#1a103d", activeBg: "rgba(255,117,152,0.2)", activeFg: "#ff7598", ring: "rgba(255,117,152,0.5)", bg: "#ffff00", cardBg: "#ffef00", textColor: "#1a103d", borderColor: "#ff7598", mutedText: "rgba(26,16,61,0.55)" }, { id: "aqua", label: "Aqua", themeMode: "dark", primary: "#09ecf3", primaryFg: "#1a1a1a", activeBg: "rgba(9,236,243,0.15)", activeFg: "#09ecf3", ring: "rgba(9,236,243,0.4)", bg: "#0f172a", cardBg: "#1e293b", textColor: "#e2e8f0", borderColor: "#334155", mutedText: "#94a3b8" },
{ id: "halloween", label: "Halloween", primary: "#f28c18", primaryFg: "#fff", activeBg: "rgba(242,140,24,0.15)", activeFg: "#f28c18", ring: "rgba(242,140,24,0.4)", bg: "#212121", cardBg: "#2a2a2a", textColor: "#f4f4f4", borderColor: "#383838", mutedText: "#888" }, { id: "luxury", label: "Luxury", themeMode: "dark", primary: "#dca54c", primaryFg: "#09090b", activeBg: "rgba(220,165,76,0.15)", activeFg: "#dca54c", ring: "rgba(220,165,76,0.4)", bg: "#09090b", cardBg: "#171717", textColor: "#f5f5f4", borderColor: "#262626", mutedText: "#737373" },
{ id: "valentine", label: "Valentine", primary: "#e96d7b", primaryFg: "#fff", activeBg: "rgba(233,109,123,0.1)", activeFg: "#e96d7b", ring: "rgba(233,109,123,0.3)", bg: "#fae6eb", cardBg: "#fff5f7", textColor: "#632935", borderColor: "#f4c2cb", mutedText: "#9a5468" }, { id: "night", label: "Night", themeMode: "dark", primary: "#38bdf8", primaryFg: "#0c1a2a", activeBg: "rgba(56,189,248,0.15)", activeFg: "#38bdf8", ring: "rgba(56,189,248,0.4)", bg: "#0f1923", cardBg: "#1a2535", textColor: "#cbd5e1", borderColor: "#1e3a5f", mutedText: "#64748b" },
{ id: "aqua", label: "Aqua", primary: "#09ecf3", primaryFg: "#1a1a1a", activeBg: "rgba(9,236,243,0.15)", activeFg: "#09ecf3", ring: "rgba(9,236,243,0.4)", bg: "#0f172a", cardBg: "#1e293b", textColor: "#e2e8f0", borderColor: "#334155", mutedText: "#94a3b8" }, { id: "coffee", label: "Coffee", themeMode: "dark", primary: "#db924b", primaryFg: "#fff", activeBg: "rgba(219,146,75,0.15)", activeFg: "#db924b", ring: "rgba(219,146,75,0.4)", bg: "#20100e", cardBg: "#2c1810", textColor: "#e8d5c4", borderColor: "#3d2319", mutedText: "#8b6355" },
{ id: "luxury", label: "Luxury", primary: "#dca54c", primaryFg: "#09090b", activeBg: "rgba(220,165,76,0.15)", activeFg: "#dca54c", ring: "rgba(220,165,76,0.4)", bg: "#09090b", cardBg: "#171717", textColor: "#f5f5f4", borderColor: "#262626", mutedText: "#737373" }, { id: "dracula", label: "Dracula", themeMode: "dark", primary: "#ff79c6", primaryFg: "#282a36", activeBg: "rgba(255,121,198,0.15)", activeFg: "#ff79c6", ring: "#bd93f9", bg: "#282a36", cardBg: "#343746", textColor: "#f8f8f2", borderColor: "#44475a", mutedText: "#6272a4" },
{ id: "night", label: "Night", primary: "#38bdf8", primaryFg: "#0c1a2a", activeBg: "rgba(56,189,248,0.15)", activeFg: "#38bdf8", ring: "rgba(56,189,248,0.4)", bg: "#0f1923", cardBg: "#1a2535", textColor: "#cbd5e1", borderColor: "#1e3a5f", mutedText: "#64748b" }, { id: "forest", label: "Forest", themeMode: "dark", primary: "#1eb854", primaryFg: "#fff", activeBg: "rgba(30,184,84,0.15)", activeFg: "#1eb854", ring: "#15803d", bg: "#171212", cardBg: "#1d1d1d", textColor: "#d1d5db", borderColor: "#292929", mutedText: "#4b5563" },
{ id: "coffee", label: "Coffee", primary: "#db924b", primaryFg: "#fff", activeBg: "rgba(219,146,75,0.15)", activeFg: "#db924b", ring: "rgba(219,146,75,0.4)", bg: "#20100e", cardBg: "#2c1810", textColor: "#e8d5c4", borderColor: "#3d2319", mutedText: "#8b6355" }, { id: "nord", label: "Nord", themeMode: "dark", primary: "#5e81ac", primaryFg: "#fff", activeBg: "rgba(94,129,172,0.15)", activeFg: "#88c0d0", ring: "rgba(94,129,172,0.4)", bg: "#2e3440", cardBg: "#3b4252", textColor: "#eceff4", borderColor: "#434c5e", mutedText: "#9198a1" },
{ id: "dracula", label: "Dracula", primary: "#ff79c6", primaryFg: "#282a36", activeBg: "rgba(255,121,198,0.15)", activeFg: "#ff79c6", ring: "#bd93f9", bg: "#282a36", cardBg: "#343746", textColor: "#f8f8f2", borderColor: "#44475a", mutedText: "#6272a4" }, { id: "dim", label: "Dim", themeMode: "dark", primary: "#9fb8d8", primaryFg: "#1c2638", activeBg: "rgba(159,184,216,0.15)", activeFg: "#9fb8d8", ring: "rgba(159,184,216,0.4)", bg: "#2a303c", cardBg: "#242933", textColor: "#c6cdd8", borderColor: "#3d4451", mutedText: "#717d8a" },
{ id: "forest", label: "Forest", primary: "#1eb854", primaryFg: "#fff", activeBg: "rgba(30,184,84,0.15)", activeFg: "#1eb854", ring: "#15803d", bg: "#171212", cardBg: "#1d1d1d", textColor: "#d1d5db", borderColor: "#292929", mutedText: "#4b5563" }, { id: "sunset", label: "Sunset", themeMode: "dark", primary: "#ff865b", primaryFg: "#fff", activeBg: "rgba(255,134,91,0.15)", activeFg: "#ff865b", ring: "rgba(255,134,91,0.4)", bg: "#1a0a00", cardBg: "#270f00", textColor: "#f4c09a", borderColor: "#3d1a00", mutedText: "#8b5a3a" },
{ id: "retro", label: "Retro", primary: "#ef9995", primaryFg: "#282425", activeBg: "#fde8e7", activeFg: "#7f1d1d", ring: "#fca5a5", bg: "#e4d8b4", cardBg: "#f7f0d8", textColor: "#282425", borderColor: "#d4b483", mutedText: "#6b5745" }, // — light backgrounds —
{ id: "nord", label: "Nord", primary: "#5e81ac", primaryFg: "#fff", activeBg: "rgba(94,129,172,0.15)", activeFg: "#88c0d0", ring: "rgba(94,129,172,0.4)", bg: "#2e3440", cardBg: "#3b4252", textColor: "#eceff4", borderColor: "#434c5e", mutedText: "#9198a1" }, { id: "light", label: "Light", themeMode: "light", primary: "#570df8", primaryFg: "#fff", activeBg: "#f3f0ff", activeFg: "#4c1d95", ring: "#ddd6fe", bg: "#fff", cardBg: "#fff", textColor: "#1f2937", borderColor: "#e5e7eb", mutedText: "#6b7280" },
{ id: "dim", label: "Dim", primary: "#9fb8d8", primaryFg: "#1c2638", activeBg: "rgba(159,184,216,0.15)", activeFg: "#9fb8d8", ring: "rgba(159,184,216,0.4)", bg: "#2a303c", cardBg: "#242933", textColor: "#c6cdd8", borderColor: "#3d4451", mutedText: "#717d8a" }, { id: "cupcake", label: "Cupcake", themeMode: "light", primary: "#65c3c8", primaryFg: "#291334", activeBg: "#d9f5f6", activeFg: "#0e6b70", ring: "#a7eaec", bg: "#faf7f5", cardBg: "#fff", textColor: "#291334", borderColor: "#e9e3df", mutedText: "#9ca3af" },
{ id: "winter", label: "Winter", primary: "#047aed", primaryFg: "#fff", activeBg: "#e0f0ff", activeFg: "#0369a1", ring: "#bae6fd", bg: "#fff", cardBg: "#f0f9ff", textColor: "#1e3a5f", borderColor: "#bae6fd", mutedText: "#64748b" }, { id: "valentine", label: "Valentine", themeMode: "light", primary: "#e96d7b", primaryFg: "#fff", activeBg: "rgba(233,109,123,0.1)", activeFg: "#e96d7b", ring: "rgba(233,109,123,0.3)", bg: "#fae6eb", cardBg: "#fff5f7", textColor: "#632935", borderColor: "#f4c2cb", mutedText: "#9a5468" },
{ id: "sunset", label: "Sunset", primary: "#ff865b", primaryFg: "#fff", activeBg: "rgba(255,134,91,0.15)", activeFg: "#ff865b", ring: "rgba(255,134,91,0.4)", bg: "#1a0a00", cardBg: "#270f00", textColor: "#f4c09a", borderColor: "#3d1a00", mutedText: "#8b5a3a" }, { id: "cyberpunk", label: "Cyberpunk", themeMode: "light", primary: "#ff7598", primaryFg: "#1a103d", activeBg: "rgba(255,117,152,0.2)", activeFg: "#ff7598", ring: "rgba(255,117,152,0.5)", bg: "#ffff00", cardBg: "#ffef00", textColor: "#1a103d", borderColor: "#ff7598", mutedText: "rgba(26,16,61,0.55)" },
{ id: "retro", label: "Retro", themeMode: "light", primary: "#ef9995", primaryFg: "#282425", activeBg: "#fde8e7", activeFg: "#7f1d1d", ring: "#fca5a5", bg: "#e4d8b4", cardBg: "#f7f0d8", textColor: "#282425", borderColor: "#d4b483", mutedText: "#6b5745" },
{ id: "winter", label: "Winter", themeMode: "light", primary: "#047aed", primaryFg: "#fff", activeBg: "#e0f0ff", activeFg: "#0369a1", ring: "#bae6fd", bg: "#fff", cardBg: "#f0f9ff", textColor: "#1e3a5f", borderColor: "#bae6fd", mutedText: "#64748b" },
]; ];
// Aceternity UI accent colour palettes // Aceternity UI accent colour palettes
@@ -123,9 +127,9 @@ export const ACETERNITY_THEMES: ThemeColor[] = [
]; ];
export const HEROUI_MARKETING_THEMES: ThemeColor[] = [ export const HEROUI_MARKETING_THEMES: ThemeColor[] = [
{ id: "purple", label: "Purple", primary: "#7c3aed", primaryFg: "#fff", activeBg: "rgba(124,58,237,0.08)", activeFg: "#7c3aed", ring: "rgba(124,58,237,0.15)", bg: "#fff" }, { id: "purple", label: "Purple", themeMode: "light", primary: "#7c3aed", primaryFg: "#fff", activeBg: "rgba(124,58,237,0.08)", activeFg: "#7c3aed", ring: "rgba(124,58,237,0.15)", bg: "#fff" },
{ id: "blue", label: "Blue", primary: "#2563eb", primaryFg: "#fff", activeBg: "rgba(37,99,235,0.08)", activeFg: "#2563eb", ring: "rgba(37,99,235,0.15)", bg: "#fff" }, { id: "blue", label: "Blue", themeMode: "light", primary: "#2563eb", primaryFg: "#fff", activeBg: "rgba(37,99,235,0.08)", activeFg: "#2563eb", ring: "rgba(37,99,235,0.15)", bg: "#fff" },
{ id: "teal", label: "Teal", primary: "#0d9488", primaryFg: "#fff", activeBg: "rgba(13,148,136,0.08)", activeFg: "#0d9488", ring: "rgba(13,148,136,0.15)", bg: "#fff" }, { id: "teal", label: "Teal", themeMode: "light", primary: "#0d9488", primaryFg: "#fff", activeBg: "rgba(13,148,136,0.08)", activeFg: "#0d9488", ring: "rgba(13,148,136,0.15)", bg: "#fff" },
{ id: "dark", label: "Dark", primary: "#7c3aed", primaryFg: "#fff", activeBg: "rgba(124,58,237,0.2)", activeFg: "#c084fc", ring: "rgba(124,58,237,0.3)", bg: "#09090b", cardBg: "#18181b", textColor: "#f4f4f5", borderColor: "#27272a", mutedText: "#71717a" }, { id: "dark", label: "Dark", themeMode: "dark", primary: "#7c3aed", primaryFg: "#fff", activeBg: "rgba(124,58,237,0.2)", activeFg: "#c084fc", ring: "rgba(124,58,237,0.3)", bg: "#09090b", cardBg: "#18181b", textColor: "#f4f4f5", borderColor: "#27272a", mutedText: "#71717a" },
{ id: "modern", label: "Modern", primary: "#06b6d4", primaryFg: "#fff", activeBg: "rgba(6,182,212,0.08)", activeFg: "#06b6d4", ring: "rgba(6,182,212,0.15)", bg: "#fff" }, { id: "modern", label: "Modern", themeMode: "light", primary: "#06b6d4", primaryFg: "#fff", activeBg: "rgba(6,182,212,0.08)", activeFg: "#06b6d4", ring: "rgba(6,182,212,0.15)", bg: "#fff" },
]; ];