Theme Development Guide

Texto Theme Development Guide

Theme File Structure

A Texto theme is a CSS file containing three blocks:

/* Light mode: light values for all variables */
:root {
  --background: ...;
  --foreground: ...;
  /* ... all 33 variables + optional --warning */
}

/* Dark mode: dark values for all variables */
.dark {
  --background: ...;
  --foreground: ...;
  /* ... all 33 variables + optional --warning */
}

/* Editor content area: code/highlight/selection styles */
#writer {
  --highlight-color: ...;
  --code-editor-theme-light: ...;
  /* ... editor-specific variables + custom content styles */
}

Variable Reference

Core Color Variables

33 variables total: 32 standard color variables + --color-scheme. The table below also includes the recommended --warning. Grouped by category.

Surface

Variable Purpose Visual Description
--background Deepest app background color Like paper base color
--foreground Default text color on background Body, heading, label colors
--card Card component background Panel base slightly different from background
--card-foreground Text color on card Text color inside cards
--popover Popover, menu, tooltip background Floating layer base color
--popover-foreground Text color on popover Menu item, tooltip text color

Accents

Variable Purpose Visual Description
--primary Primary color for selection, focus, interaction Most prominent accent color
--primary-foreground Text color on primary background Text on primary buttons
--secondary Secondary surface color Panel color slightly different from main background
--secondary-foreground Text color on secondary surface Text in secondary panels
--accent Highlight/accent for hover, selection styles Mouse hover, selected item background
--accent-foreground Text color on accent background Selected item text color
--breathe-color Breathing animation color Pulse animation color for file modification indicators

Feedback

Variable Purpose Visual Description
--destructive Danger/error/delete operation color Red tones for error messages, delete buttons
--warning Warning status color (optional, recommended) Orange/yellow tones for conflicts, warnings
--muted Muted background color Slightly darker/lighter than background for secondary areas
--muted-foreground Muted text color For descriptions, hints, placeholders, secondary text

Boundaries

Variable Purpose Visual Description
--border Default border color for all elements Panel borders, dividers, card strokes
--input Input field border color Text field, dropdown borders
--ring Focus ring color Outer glow when clicking inputs or buttons

Charts

Variable Purpose
--chart-1 Chart color 1
--chart-2 Chart color 2 (also used for title bar "saved" status)
--chart-3 Chart color 3
--chart-4 Chart color 4
--chart-5 Chart color 5

Sidebar

The sidebar has its own independent set of colors, usually slightly darker (light mode) or slightly brighter (dark mode) than the main palette.

Variable Purpose Visual Description
--sidebar Sidebar background color File tree area base color
--sidebar-foreground Sidebar text color File name, directory name colors
--sidebar-primary Sidebar primary color Accent color in sidebar
--sidebar-primary-foreground Text color on sidebar primary
--sidebar-accent Sidebar selection/hover background Selected file, hover item background
--sidebar-accent-foreground Sidebar selected item text color Selected file text color
--sidebar-border Sidebar border color Separator between sidebar and main content
--sidebar-ring Sidebar focus ring color Outer glow when focusing elements in sidebar

Special Variables

Variable Purpose Value
--color-scheme Browser native UI color scheme light or dark (string, not a color value)

Controls the styling of scrollbars, form controls, and other system-native elements.


Editor Content Area Variables (defined inside #writer {})

Variable Purpose
--highlight-color Background color for text highlight (<mark>)
--default-selection Background color for selected text in editor (optional, uses browser default if not defined)
--code-editor-theme-light Syntax highlighting theme name for code blocks in light mode
--code-editor-theme-dark Syntax highlighting theme name for code blocks in dark mode
--source-code-theme-light Syntax highlighting theme name for source editor in light mode
--source-code-theme-dark Syntax highlighting theme name for source editor in dark mode

Available values for --code-editor-theme-* and --source-code-theme-* (syntax highlighting theme names):

oneDark         materialDark    githubDark      githubLight
dracula         atomone         vscodeDark      xcodeDark
xcodeLight      eclipse         sublime         basicLight
tokyoNightDay   bbedit          solarizedLight

Editor Content Area Selectors (defined inside #writer {})

The following selectors can be used to customize the editor content area styles:

#writer h1              /* Level 1 heading */
#writer h2              /* Level 2 heading */
#writer h3              /* Level 3 heading */
#writer h4              /* Level 4 heading */
#writer h5              /* Level 5 heading */
#writer h6              /* Level 6 heading */
#writer p               /* Paragraph */
#writer a               /* Link */
#writer code            /* Inline code */
#writer pre             /* Code block */
#writer pre code        /* Code inside code block (reset inline code styles) */
#writer blockquote      /* Blockquote */
#writer ul              /* Unordered list */
#writer ol              /* Ordered list */
#writer li              /* List item */
#writer ul li::marker   /* Unordered list marker color */
#writer ol li::marker   /* Ordered list number color */
#writer hr              /* Horizontal rule */
#writer table th        /* Table header */
#writer table td        /* Table cell */
#writer mark            /* Highlight mark */
#writer ::selection     /* Text selection style */

Color Formats

Theme CSS files can use hex, hsl, or oklch formats:

--primary: #3b82f6;
--primary: hsl(217, 91%, 60%);
--primary: oklch(0.546 0.245 262.881);

However, the visual theme editor only fully supports oklch format. Hex or hsl values will work in CSS, but they won't be displayed in the editor's grouping panel, and editing them through the color picker will automatically convert them to oklch.

OKLCH is recommended. It more closely matches human perception, has better hue consistency, and supports the color-mix() function.

Recommended tool: OKLCH Converter


Color Design Principles

Each background/foreground variable pair must ensure readability:

--background   / --foreground      Main surface
--card         / --card-foreground  Card surface
--popover      / --popover-foreground  Popover
--primary      / --primary-foreground  Primary accent
--secondary    / --secondary-foreground  Secondary
--muted        / --muted-foreground  Muted
--accent       / --accent-foreground  Interactive highlight
--sidebar      / --sidebar-foreground  Sidebar

Typical relationship references:

  • --foreground on --background: high contrast (e.g. #111 on #fff)
  • --muted-foreground is lighter than --foreground (e.g. #666 on #fff)
  • --muted is slightly darker than --background (e.g. #f5f5f5 on #fff)
  • --border is 10-15% darker than background
  • --primary is the most prominent color in the app
  • --sidebar series is usually slightly distinct from the main palette

Highlight Color (mark tag)

--highlight-color defines a default value in the theme, but users can switch between six preset colors in settings. The presets are:

Yellow  oklch(0.9 0.15 85 / 0.35)
Green   oklch(0.9 0.15 140 / 0.35)
Blue    oklch(0.85 0.1 250 / 0.35)
Pink    oklch(0.9 0.1 350 / 0.35)
Orange  oklch(0.9 0.15 60 / 0.35)
Purple  oklch(0.85 0.12 300 / 0.35)

The --highlight-color defined in the theme only applies when the user has not actively switched it.


Custom Theme Variables

You can define theme-specific CSS variables to organize colors:

:root {
  --mytheme-code-bg: color-mix(in oklch, var(--primary) 10%, var(--background));
  --mytheme-link-color: var(--primary);
  --mytheme-blockquote-bg: var(--muted);
}

.dark {
  --mytheme-code-bg: color-mix(in oklch, var(--primary) 15%, var(--background));
}

#writer code {
  background: var(--mytheme-code-bg);
}

#writer a {
  color: var(--mytheme-link-color);
}

Security Restrictions

The following content will be rejected when importing a theme:

Content Reason
url(http or url(https External resource references not allowed
@import External stylesheet loading not allowed
@font-face Fonts managed through app settings

Color Scheme Tips

  1. Start with --background and --foreground, establish base and text colors
  2. Set --primary and --muted, the two most widely used variables
  3. Use --muted-foreground for secondary text, giving the interface depth
  4. Set --border, 10-15% darker than background
  5. Give the sidebar its own palette, usually slightly darker for visual distinction
  6. Tune --chart-1 through --chart-5 last, ensure all five are distinguishable
  7. Dark mode: Dark is not the inverse of light. Shift hues (usually toward blue), lower saturation, maintain contrast

Complete Theme Template

/**
 * Theme Name
 * Brief description
 */

/* ==================== Light Mode ==================== */

:root {
  /* ---- Surface ---- */
  --background: oklch(1 0 0);
  --foreground: oklch(0.25 0 0);
  --card: oklch(1 0 0);
  --card-foreground: oklch(0.25 0 0);
  --popover: oklch(1 0 0);
  --popover-foreground: oklch(0.25 0 0);

  /* ---- Accents ---- */
  --primary: oklch(0.205 0 0);
  --primary-foreground: oklch(0.985 0 0);
  --secondary: oklch(0.97 0 0);
  --secondary-foreground: oklch(0.205 0 0);
  --accent: oklch(0.97 0 0);
  --accent-foreground: oklch(0.205 0 0);
  --breathe-color: oklch(0.646 0.222 41.116);

  /* ---- Feedback ---- */
  --destructive: oklch(0.577 0.245 27.325);
  --warning: oklch(0.621 0.178 26.1);
  --muted: oklch(0.97 0 0);
  --muted-foreground: oklch(0.556 0 0);

  /* ---- Boundaries ---- */
  --border: oklch(0.922 0 0);
  --input: oklch(0.922 0 0);
  --ring: oklch(0.708 0 0);

  /* ---- Charts ---- */
  --chart-1: oklch(0.646 0.222 41.116);
  --chart-2: oklch(0.6 0.118 184.704);
  --chart-3: oklch(0.398 0.07 227.392);
  --chart-4: oklch(0.828 0.189 84.429);
  --chart-5: oklch(0.769 0.188 70.08);

  /* ---- Sidebar ---- */
  --sidebar: oklch(0.985 0 0);
  --sidebar-foreground: oklch(0.25 0 0);
  --sidebar-primary: oklch(0.205 0 0);
  --sidebar-primary-foreground: oklch(0.985 0 0);
  --sidebar-accent: oklch(0.9 0 0);
  --sidebar-accent-foreground: oklch(0.205 0 0);
  --sidebar-border: oklch(0.922 0 0);
  --sidebar-ring: oklch(0.708 0 0);

  /* ---- Special ---- */
  --color-scheme: light;
}

/* ==================== Dark Mode ==================== */

.dark {
  --background: oklch(0.176 0.014 258.4);
  --foreground: oklch(0.943 0.011 243.7);
  --card: oklch(0.22 0.016 256.8);
  --card-foreground: oklch(0.943 0.011 243.7);
  --popover: oklch(0.22 0.016 256.8);
  --popover-foreground: oklch(0.943 0.011 243.7);
  --primary: oklch(0.922 0 0);
  --primary-foreground: oklch(0.176 0.014 258.4);
  --secondary: oklch(0.267 0.015 256.8);
  --secondary-foreground: oklch(0.943 0.011 243.7);
  --accent: oklch(0.267 0.015 256.8);
  --accent-foreground: oklch(0.943 0.011 243.7);
  --breathe-color: oklch(0.715 0.152 253.3);
  --destructive: oklch(0.586 0.201 26.8);
  --warning: oklch(0.668 0.164 24.7);
  --muted: oklch(0.267 0.015 256.8);
  --muted-foreground: oklch(0.662 0.018 250.9);
  --border: oklch(0.33 0.015 252.3);
  --input: oklch(0.5 0.015 256.8);
  --ring: oklch(0.715 0.152 253.3);
  --chart-1: oklch(0.715 0.152 253.3);
  --chart-2: oklch(0.695 0.181 145.6);
  --chart-3: oklch(0.72 0.14 79.9);
  --chart-4: oklch(0.73 0.15 34.1);
  --chart-5: oklch(0.732 0.167 301.7);
  --sidebar: oklch(0.22 0.016 256.8);
  --sidebar-foreground: oklch(0.943 0.011 243.7);
  --sidebar-primary: oklch(0.715 0.152 253.3);
  --sidebar-primary-foreground: oklch(0.943 0.011 243.7);
  --sidebar-accent: oklch(0.32 0.015 256.8);
  --sidebar-accent-foreground: oklch(0.943 0.011 243.7);
  --sidebar-border: oklch(0.33 0.015 252.3);
  --sidebar-ring: oklch(0.715 0.152 253.3);
  --color-scheme: dark;
}

/* ==================== Editor Content Area ==================== */

#writer {
  --highlight-color: oklch(0.9 0.15 85 / 0.35);
  --default-selection: oklch(0.6 0.25 255 / 0.3);
  --code-editor-theme-light: githubLight;
  --code-editor-theme-dark: githubDark;
  --source-code-theme-light: githubLight;
  --source-code-theme-dark: githubDark;
}

#writer ::selection {
  background: var(--default-selection);
}

/* ---- Custom Content Styles ---- */

#writer h1 {
  position: relative;
  padding-bottom: 0.5em;
  border-bottom: 1px solid var(--border);
}

#writer a {
  color: var(--primary);
  text-decoration: none;
  border-bottom: 1px solid color-mix(in oklch, var(--primary) 25%, transparent);
}

#writer code {
  padding: 0.2em 0.4em;
  background: color-mix(in oklch, var(--foreground) 6%, transparent);
  border-radius: 4px;
  font-size: 0.85em;
}

#writer blockquote {
  border-left: 4px solid var(--border);
  padding: 0 1em;
  color: var(--muted-foreground);
}

#writer hr {
  height: 1px;
  background: var(--border);
  border: 0;
}

#writer table th {
  background: var(--muted);
  font-weight: 600;
}

#writer mark {
  background: var(--highlight-color);
  color: inherit;
}

#writer ul li::marker {
  color: var(--primary);
}

#writer ol li::marker {
  color: var(--primary);
  font-weight: 500;
}

Debugging

  1. Select "Source Code" mode in the theme editor to edit theme CSS directly
  2. Changes take effect immediately after saving
  3. The app ships with three built-in themes (Default in grayscale, Cherry in pink tones, Spring in green tones) for color reference

Exporting and Sharing

Select a theme in the theme editor, click "Export", and save it as a .css file to share with others. They can use the "Import" feature to load it.