Files
tolaria/src-tauri/src/theme/defaults.rs
2026-03-11 23:28:24 +01:00

454 lines
18 KiB
Rust

/// Content for the built-in default (light) theme.
pub const DEFAULT_THEME: &str = r##"{
"name": "Default",
"description": "Light theme with warm, paper-like tones",
"colors": {
"background": "#FFFFFF",
"foreground": "#37352F",
"card": "#FFFFFF",
"popover": "#FFFFFF",
"primary": "#155DFF",
"primary-foreground": "#FFFFFF",
"secondary": "#EBEBEA",
"secondary-foreground": "#37352F",
"muted": "#F0F0EF",
"muted-foreground": "#787774",
"accent": "#EBEBEA",
"accent-foreground": "#37352F",
"destructive": "#E03E3E",
"border": "#E9E9E7",
"input": "#E9E9E7",
"ring": "#155DFF",
"sidebar-background": "#F7F6F3",
"sidebar-foreground": "#37352F",
"sidebar-border": "#E9E9E7",
"sidebar-accent": "#EBEBEA"
},
"typography": {
"font-family": "'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
"font-size-base": "14px"
},
"spacing": {
"sidebar-width": "250px"
}
}"##;
/// Content for the built-in dark theme.
pub const DARK_THEME: &str = r##"{
"name": "Dark",
"description": "Dark variant with deep navy tones",
"colors": {
"background": "#0f0f1a",
"foreground": "#e0e0e0",
"card": "#16162a",
"popover": "#1e1e3a",
"primary": "#155DFF",
"primary-foreground": "#FFFFFF",
"secondary": "#2a2a4a",
"secondary-foreground": "#e0e0e0",
"muted": "#1e1e3a",
"muted-foreground": "#888888",
"accent": "#2a2a4a",
"accent-foreground": "#e0e0e0",
"destructive": "#f44336",
"border": "#2a2a4a",
"input": "#2a2a4a",
"ring": "#155DFF",
"sidebar-background": "#1a1a2e",
"sidebar-foreground": "#e0e0e0",
"sidebar-border": "#2a2a4a",
"sidebar-accent": "#2a2a4a"
},
"typography": {
"font-family": "'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
"font-size-base": "14px"
},
"spacing": {
"sidebar-width": "250px"
}
}"##;
/// Content for the built-in minimal theme.
pub const MINIMAL_THEME: &str = r##"{
"name": "Minimal",
"description": "High contrast, minimal chrome",
"colors": {
"background": "#FAFAFA",
"foreground": "#111111",
"card": "#FFFFFF",
"popover": "#FFFFFF",
"primary": "#000000",
"primary-foreground": "#FFFFFF",
"secondary": "#F0F0F0",
"secondary-foreground": "#111111",
"muted": "#F5F5F5",
"muted-foreground": "#666666",
"accent": "#F0F0F0",
"accent-foreground": "#111111",
"destructive": "#CC0000",
"border": "#E0E0E0",
"input": "#E0E0E0",
"ring": "#000000",
"sidebar-background": "#F5F5F5",
"sidebar-foreground": "#111111",
"sidebar-border": "#E0E0E0",
"sidebar-accent": "#E8E8E8"
},
"typography": {
"font-family": "'SF Mono', 'Menlo', monospace",
"font-size-base": "13px"
},
"spacing": {
"sidebar-width": "220px"
}
}"##;
// ---------------------------------------------------------------------------
// Vault-based theme notes (markdown with frontmatter CSS custom properties)
// ---------------------------------------------------------------------------
/// Complete set of CSS variable key-value pairs for the default light vault theme.
/// Includes both UI chrome colours and all editor styling properties from theme.json.
/// Numeric values that need CSS units include the `px` suffix; unitless values
/// (line-height, font-weight) are bare numbers.
pub const DEFAULT_VAULT_THEME_VARS: [(&str, &str); 140] = [
// ── shadcn/ui base colours ──────────────────────────────────────────
("background", "#FFFFFF"),
("foreground", "#37352F"),
("card", "#FFFFFF"),
("popover", "#FFFFFF"),
("primary", "#155DFF"),
("primary-foreground", "#FFFFFF"),
("secondary", "#EBEBEA"),
("secondary-foreground", "#37352F"),
("muted", "#F0F0EF"),
("muted-foreground", "#787774"),
("accent", "#EBEBEA"),
("accent-foreground", "#37352F"),
("destructive", "#E03E3E"),
("border", "#E9E9E7"),
("input", "#E9E9E7"),
("ring", "#155DFF"),
("sidebar", "#F7F6F3"),
("sidebar-foreground", "#37352F"),
("sidebar-border", "#E9E9E7"),
("sidebar-accent", "#EBEBEA"),
// ── Text hierarchy ──────────────────────────────────────────────────
("text-primary", "#37352F"),
("text-secondary", "#787774"),
("text-tertiary", "#B4B4B4"),
("text-muted", "#B4B4B4"),
("text-heading", "#37352F"),
// ── Backgrounds ─────────────────────────────────────────────────────
("bg-primary", "#FFFFFF"),
("bg-card", "#FFFFFF"),
("bg-sidebar", "#F7F6F3"),
("bg-hover", "#EBEBEA"),
("bg-hover-subtle", "#F0F0EF"),
("bg-selected", "#E8F4FE"),
("border-primary", "#E9E9E7"),
// ── Accent colours ──────────────────────────────────────────────────
("accent-blue", "#155DFF"),
("accent-green", "#00B38B"),
("accent-orange", "#D9730D"),
("accent-red", "#E03E3E"),
("accent-purple", "#A932FF"),
("accent-yellow", "#F0B100"),
("accent-blue-light", "#155DFF14"),
("accent-green-light", "#00B38B14"),
("accent-purple-light", "#A932FF14"),
("accent-red-light", "#E03E3E14"),
("accent-yellow-light", "#F0B10014"),
// ── Typography base ─────────────────────────────────────────────────
(
"font-family",
"'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
),
("font-size-base", "14px"),
// ── Editor (from theme.json → editor) ───────────────────────────────
(
"editor-font-family",
"'Inter', -apple-system, BlinkMacSystemFont, sans-serif",
),
("editor-font-size", "15px"),
("editor-line-height", "1.5"),
("editor-max-width", "720px"),
("editor-padding-horizontal", "40px"),
("editor-padding-vertical", "20px"),
("editor-paragraph-spacing", "8px"),
// ── Headings H1 ────────────────────────────────────────────────────
("headings-h1-font-size", "32px"),
("headings-h1-font-weight", "700"),
("headings-h1-line-height", "1.2"),
("headings-h1-margin-top", "32px"),
("headings-h1-margin-bottom", "12px"),
("headings-h1-color", "var(--text-heading)"),
("headings-h1-letter-spacing", "-0.5px"),
// ── Headings H2 ────────────────────────────────────────────────────
("headings-h2-font-size", "27px"),
("headings-h2-font-weight", "600"),
("headings-h2-line-height", "1.4"),
("headings-h2-margin-top", "28px"),
("headings-h2-margin-bottom", "10px"),
("headings-h2-color", "var(--text-heading)"),
("headings-h2-letter-spacing", "-0.5px"),
// ── Headings H3 ────────────────────────────────────────────────────
("headings-h3-font-size", "20px"),
("headings-h3-font-weight", "600"),
("headings-h3-line-height", "1.4"),
("headings-h3-margin-top", "24px"),
("headings-h3-margin-bottom", "8px"),
("headings-h3-color", "var(--text-heading)"),
("headings-h3-letter-spacing", "-0.5px"),
// ── Headings H4 ────────────────────────────────────────────────────
("headings-h4-font-size", "20px"),
("headings-h4-font-weight", "600"),
("headings-h4-line-height", "1.4"),
("headings-h4-margin-top", "20px"),
("headings-h4-margin-bottom", "6px"),
("headings-h4-color", "var(--text-heading)"),
("headings-h4-letter-spacing", "0px"),
// ── Lists ───────────────────────────────────────────────────────────
("lists-bullet-size", "28px"),
("lists-bullet-color", "#177bfd"),
("lists-indent-size", "24px"),
("lists-item-spacing", "4px"),
("lists-padding-left", "8px"),
("lists-bullet-gap", "6px"),
// ── Checkboxes ──────────────────────────────────────────────────────
("checkboxes-size", "18px"),
("checkboxes-border-radius", "3px"),
("checkboxes-checked-color", "var(--accent-blue)"),
("checkboxes-unchecked-border-color", "var(--text-muted)"),
("checkboxes-gap", "8px"),
// ── Inline styles: bold ─────────────────────────────────────────────
("inline-styles-bold-font-weight", "700"),
("inline-styles-bold-color", "var(--text-primary)"),
// ── Inline styles: italic ───────────────────────────────────────────
("inline-styles-italic-font-style", "italic"),
("inline-styles-italic-color", "var(--text-primary)"),
// ── Inline styles: strikethrough ────────────────────────────────────
("inline-styles-strikethrough-color", "var(--text-tertiary)"),
(
"inline-styles-strikethrough-text-decoration",
"line-through",
),
// ── Inline styles: code ─────────────────────────────────────────────
(
"inline-styles-code-font-family",
"'SF Mono', 'Fira Code', monospace",
),
("inline-styles-code-font-size", "14px"),
(
"inline-styles-code-background-color",
"var(--bg-hover-subtle)",
),
("inline-styles-code-padding-horizontal", "4px"),
("inline-styles-code-padding-vertical", "2px"),
("inline-styles-code-border-radius", "3px"),
("inline-styles-code-color", "var(--text-secondary)"),
// ── Inline styles: link ─────────────────────────────────────────────
("inline-styles-link-color", "var(--accent-blue)"),
("inline-styles-link-text-decoration", "underline"),
// ── Inline styles: wikilink ─────────────────────────────────────────
("inline-styles-wikilink-color", "var(--accent-blue)"),
("inline-styles-wikilink-text-decoration", "none"),
(
"inline-styles-wikilink-border-bottom",
"1px dotted currentColor",
),
("inline-styles-wikilink-cursor", "pointer"),
// ── Code blocks ─────────────────────────────────────────────────────
(
"code-blocks-font-family",
"'SF Mono', 'Fira Code', monospace",
),
("code-blocks-font-size", "13px"),
("code-blocks-line-height", "1.5"),
("code-blocks-background-color", "var(--bg-card)"),
("code-blocks-padding-horizontal", "16px"),
("code-blocks-padding-vertical", "12px"),
("code-blocks-border-radius", "6px"),
("code-blocks-margin-vertical", "12px"),
// ── Blockquote ──────────────────────────────────────────────────────
("blockquote-border-left-width", "3px"),
("blockquote-border-left-color", "var(--accent-blue)"),
("blockquote-padding-left", "16px"),
("blockquote-margin-vertical", "12px"),
("blockquote-color", "var(--text-secondary)"),
("blockquote-font-style", "italic"),
// ── Table ───────────────────────────────────────────────────────────
("table-border-color", "var(--border-primary)"),
("table-header-background", "var(--bg-card)"),
("table-cell-padding-horizontal", "12px"),
("table-cell-padding-vertical", "8px"),
("table-font-size", "14px"),
// ── Horizontal rule ─────────────────────────────────────────────────
("horizontal-rule-color", "var(--border-primary)"),
("horizontal-rule-margin-vertical", "24px"),
("horizontal-rule-thickness", "1px"),
// ── Colors (semantic aliases from theme.json → colors) ──────────────
("colors-background", "var(--bg-primary)"),
("colors-text", "var(--text-primary)"),
("colors-text-secondary", "var(--text-secondary)"),
("colors-text-muted", "var(--text-muted)"),
("colors-heading", "var(--text-heading)"),
("colors-accent", "var(--accent-blue)"),
("colors-selection", "var(--bg-selected)"),
("colors-cursor", "var(--text-primary)"),
];
/// UI-colour overrides for the Dark vault theme (keys that differ from default).
const DARK_COLOR_OVERRIDES: &[(&str, &str)] = &[
("background", "#0f0f1a"),
("foreground", "#e0e0e0"),
("card", "#16162a"),
("popover", "#1e1e3a"),
("secondary", "#2a2a4a"),
("secondary-foreground", "#e0e0e0"),
("muted", "#1e1e3a"),
("muted-foreground", "#888888"),
("accent", "#2a2a4a"),
("accent-foreground", "#e0e0e0"),
("destructive", "#f44336"),
("border", "#2a2a4a"),
("input", "#2a2a4a"),
("sidebar", "#1a1a2e"),
("sidebar-foreground", "#e0e0e0"),
("sidebar-border", "#2a2a4a"),
("sidebar-accent", "#2a2a4a"),
("text-primary", "#e0e0e0"),
("text-secondary", "#888888"),
("text-tertiary", "#666666"),
("text-muted", "#666666"),
("text-heading", "#e0e0e0"),
("bg-primary", "#0f0f1a"),
("bg-card", "#16162a"),
("bg-sidebar", "#1a1a2e"),
("bg-hover", "#2a2a4a"),
("bg-hover-subtle", "#1e1e3a"),
("bg-selected", "#155DFF22"),
("border-primary", "#2a2a4a"),
("accent-red", "#f44336"),
("accent-blue-light", "#155DFF33"),
("accent-green-light", "#00B38B33"),
("accent-purple-light", "#A932FF33"),
("accent-red-light", "#f4433633"),
("accent-yellow-light", "#F0B10033"),
("lists-bullet-color", "#155DFF"),
];
/// UI-colour + editor-property overrides for the Minimal vault theme.
const MINIMAL_OVERRIDES: &[(&str, &str)] = &[
("background", "#FAFAFA"),
("foreground", "#111111"),
("primary", "#000000"),
("secondary", "#F0F0F0"),
("secondary-foreground", "#111111"),
("muted", "#F5F5F5"),
("muted-foreground", "#666666"),
("accent", "#F0F0F0"),
("accent-foreground", "#111111"),
("destructive", "#CC0000"),
("border", "#E0E0E0"),
("input", "#E0E0E0"),
("ring", "#000000"),
("sidebar", "#F5F5F5"),
("sidebar-foreground", "#111111"),
("sidebar-border", "#E0E0E0"),
("sidebar-accent", "#E8E8E8"),
("text-primary", "#111111"),
("text-secondary", "#666666"),
("text-tertiary", "#999999"),
("text-muted", "#999999"),
("text-heading", "#111111"),
("bg-primary", "#FAFAFA"),
("bg-card", "#FFFFFF"),
("bg-sidebar", "#F5F5F5"),
("bg-hover", "#EBEBEB"),
("bg-hover-subtle", "#F5F5F5"),
("bg-selected", "#00000014"),
("border-primary", "#E0E0E0"),
("accent-blue", "#000000"),
("accent-green", "#006600"),
("accent-orange", "#996600"),
("accent-red", "#CC0000"),
("accent-purple", "#660099"),
("accent-yellow", "#996600"),
("accent-blue-light", "#00000014"),
("accent-green-light", "#00660014"),
("accent-purple-light", "#66009914"),
("accent-red-light", "#CC000014"),
("accent-yellow-light", "#99660014"),
("font-family", "'SF Mono', 'Menlo', monospace"),
("font-size-base", "13px"),
("editor-font-size", "15px"),
("editor-line-height", "1.6"),
("editor-max-width", "680px"),
("lists-bullet-color", "#000000"),
];
/// Build a vault theme note string from a set of CSS variable pairs.
///
/// Values containing `#`, `'`, `,`, or `(` are YAML-quoted to avoid parse errors.
fn build_vault_theme_note(name: &str, description: &str, vars: &[(&str, &str)]) -> String {
let mut fm = format!("---\ntype: Theme\nDescription: {description}\n");
for (key, value) in vars {
if value.contains('#') || value.contains('\'') || value.contains(',') || value.contains('(')
{
fm.push_str(&format!("{key}: \"{value}\"\n"));
} else {
fm.push_str(&format!("{key}: {value}\n"));
}
}
fm.push_str("---\n\n");
fm.push_str(&format!("# {name} Theme\n\n{description}.\n"));
fm
}
/// Apply overrides on top of DEFAULT_VAULT_THEME_VARS, returning a new Vec.
fn apply_overrides(
overrides: &[(&'static str, &'static str)],
) -> Vec<(&'static str, &'static str)> {
let mut vars: Vec<(&'static str, &'static str)> = DEFAULT_VAULT_THEME_VARS.to_vec();
for &(key, value) in overrides {
if let Some(entry) = vars.iter_mut().find(|e| e.0 == key) {
entry.1 = value;
}
}
vars
}
/// Generate the Default vault theme note content.
pub fn default_vault_theme() -> String {
build_vault_theme_note(
"Default",
"Light theme with warm, paper-like tones",
&DEFAULT_VAULT_THEME_VARS,
)
}
/// Generate the Dark vault theme note content.
pub fn dark_vault_theme() -> String {
let vars = apply_overrides(DARK_COLOR_OVERRIDES);
build_vault_theme_note("Dark", "Dark variant with deep navy tones", &vars)
}
/// Generate the Minimal vault theme note content.
pub fn minimal_vault_theme() -> String {
let vars = apply_overrides(MINIMAL_OVERRIDES);
build_vault_theme_note("Minimal", "High contrast, minimal chrome", &vars)
}
/// Type definition for the Theme note type.
pub const THEME_TYPE_DEFINITION: &str = "---\n\
type: Type\n\
icon: palette\n\
color: purple\n\
order: 50\n\
---\n\
\n\
# Theme\n\
\n\
A visual theme for Laputa. Each theme defines CSS custom properties that control colors, typography, and spacing.\n";