mirror of
https://github.com/jnsahaj/tweakcn.git
synced 2026-08-30 18:10:28 +08:00
632dd42a72
Remove the separate edit mode (ThemeEditActions bar + EditButton) and instead track unsaved changes inline. The preset selector now shows `<name>*` for any preset with unsaved changes. Clicking Save on a saved preset opens a dialog offering to update the existing theme or save as a new one. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
111 lines
4.4 KiB
TypeScript
111 lines
4.4 KiB
TypeScript
import { theme } from "@/db/schema";
|
|
import { InferSelectModel } from "drizzle-orm";
|
|
import { z } from "zod";
|
|
|
|
export const themeStylePropsSchema = z.object({
|
|
background: z.string().describe("The default background color, paired with `foreground`."),
|
|
foreground: z.string().describe("Paired with `background`."),
|
|
card: z.string().describe("The background color for cards, paired with `card-foreground`."),
|
|
"card-foreground": z.string().describe("Paired with `card`."),
|
|
popover: z
|
|
.string()
|
|
.describe("The background color for popovers, paired with `popover-foreground`."),
|
|
"popover-foreground": z.string().describe("Paired with `popover`."),
|
|
primary: z.string().describe("The main color, paired with `primary-foreground`."),
|
|
"primary-foreground": z.string().describe("Paired with `primary`."),
|
|
secondary: z.string().describe("A secondary color, paired with `secondary-foreground`."),
|
|
"secondary-foreground": z.string().describe("Paired with `secondary`."),
|
|
muted: z.string().describe("A muted background color, paired with `muted-foreground`."),
|
|
"muted-foreground": z.string().describe("Paired with `muted`."),
|
|
accent: z
|
|
.string()
|
|
.describe("Subtle color for hover or highlight, paired with `accent-foreground`."),
|
|
"accent-foreground": z.string().describe("Paired with `accent`."),
|
|
destructive: z
|
|
.string()
|
|
.describe("Color for destructive actions, paired with `destructive-foreground`."),
|
|
"destructive-foreground": z.string().describe("Paired with `destructive`."),
|
|
border: z.string().describe("The color for borders."),
|
|
input: z.string().describe("The background color for input fields."),
|
|
ring: z.string().describe("The color for focus rings."),
|
|
"chart-1": z.string(),
|
|
"chart-2": z.string(),
|
|
"chart-3": z.string(),
|
|
"chart-4": z.string(),
|
|
"chart-5": z.string(),
|
|
sidebar: z
|
|
.string()
|
|
.describe("The background color for the sidebar, paired with `sidebar-foreground`."),
|
|
"sidebar-foreground": z.string().describe("Paired with `sidebar`."),
|
|
"sidebar-primary": z
|
|
.string()
|
|
.describe("The primary color for sidebar elements, paired with `sidebar-primary-foreground`."),
|
|
"sidebar-primary-foreground": z.string().describe("Paired with `sidebar-primary`."),
|
|
"sidebar-accent": z
|
|
.string()
|
|
.describe("An accent color for the sidebar, paired with `sidebar-accent-foreground`."),
|
|
"sidebar-accent-foreground": z.string().describe("Paired with `sidebar-accent`."),
|
|
"sidebar-border": z.string().describe("The color for borders within the sidebar."),
|
|
"sidebar-ring": z.string().describe("The color for focus rings within the sidebar."),
|
|
"font-sans": z
|
|
.string()
|
|
.describe(
|
|
"Primary UI font. May be serif, sans, monospace, or display depending on the theme vibe."
|
|
),
|
|
"font-serif": z.string().describe("The preferred serif font family."),
|
|
"font-mono": z.string().describe("The preferred monospace font family. Used for code blocks."),
|
|
radius: z
|
|
.string()
|
|
.describe("The global border-radius for components. Use 0rem for sharp corners."),
|
|
"shadow-color": z.string(),
|
|
"shadow-opacity": z.string(),
|
|
"shadow-blur": z.string(),
|
|
"shadow-spread": z.string(),
|
|
"shadow-offset-x": z.string(),
|
|
"shadow-offset-y": z.string(),
|
|
"letter-spacing": z.string().describe("The global letter spacing for text."),
|
|
spacing: z.string().optional(),
|
|
});
|
|
|
|
export const themeStylesSchema = z.object({
|
|
light: themeStylePropsSchema,
|
|
dark: themeStylePropsSchema,
|
|
});
|
|
|
|
export type ThemeStyleProps = z.infer<typeof themeStylePropsSchema>;
|
|
export type ThemeStyles = z.infer<typeof themeStylesSchema>;
|
|
|
|
export const themeStylePropsSchemaWithoutSpacing = themeStylePropsSchema.omit({
|
|
spacing: true,
|
|
});
|
|
|
|
export const themeStylesSchemaWithoutSpacing = z.object({
|
|
light: themeStylePropsSchemaWithoutSpacing,
|
|
dark: themeStylePropsSchemaWithoutSpacing,
|
|
});
|
|
|
|
export type ThemeStylesWithoutSpacing = z.infer<typeof themeStylesSchemaWithoutSpacing>;
|
|
|
|
export interface ThemeEditorPreviewProps {
|
|
styles: ThemeStyles;
|
|
currentMode: "light" | "dark";
|
|
}
|
|
|
|
export interface ThemeEditorControlsProps {
|
|
styles: ThemeStyles;
|
|
currentMode: "light" | "dark";
|
|
onChange: (styles: ThemeStyles) => void;
|
|
}
|
|
|
|
export type ThemePreset = {
|
|
source?: "SAVED" | "BUILT_IN";
|
|
createdAt?: string;
|
|
label?: string;
|
|
styles: {
|
|
light: Partial<ThemeStyleProps>;
|
|
dark: Partial<ThemeStyleProps>;
|
|
};
|
|
};
|
|
|
|
export type Theme = InferSelectModel<typeof theme>;
|