|
| 1 | +# Querya custom theme JSON (`querya.theme.v1`) |
| 2 | + |
| 3 | +Querya supports two theme file formats: |
| 4 | + |
| 5 | +| Format | Root marker | Import | Docs | |
| 6 | +|--------|-------------|--------|------| |
| 7 | +| **Querya custom** | `"schema": "querya.theme.v1"` | Planned (theme registry) | this document | |
| 8 | +| **VS Code** | `"colors"` object (no `schema`) | **Supported today** | [theme-import.md](theme-import.md) | |
| 9 | + |
| 10 | +VS Code JSON/JSONC import remains fully supported. The custom format is a first-class |
| 11 | +Querya schema with explicit `shadcn_colors` and `editor_colors` sections instead of |
| 12 | +VS Code workbench key names. |
| 13 | + |
| 14 | +## Purpose |
| 15 | + |
| 16 | +- Ship themes that map directly to Querya runtime models (`ColorScheme`, |
| 17 | + `QueryaEditorTheme`, `QueryaWorkbenchTheme`) without VS Code key indirection. |
| 18 | +- Keep theme list scans lightweight: read metadata and color maps as strings; build |
| 19 | + `QueryaTheme` only when a theme is selected. |
| 20 | +- Scale to 50+ installed themes with predictable fallback behavior. |
| 21 | + |
| 22 | +Implementation (planned): `lib/core/theme/parser/querya_theme_manifest.dart` and |
| 23 | +registry services described in |
| 24 | +[theme-parser-implementation-tasks.md](theme-parser-implementation-tasks.md). |
| 25 | + |
| 26 | +## Root object |
| 27 | + |
| 28 | +### Required fields |
| 29 | + |
| 30 | +| Field | Type | Description | |
| 31 | +|-------|------|-------------| |
| 32 | +| `schema` | string | Must be exactly `querya.theme.v1`. | |
| 33 | +| `id` | string | Stable machine id (slug). Used for filenames and settings. Lowercase letters, digits, hyphens recommended. | |
| 34 | +| `name` | string | Human-readable label shown in Preferences. | |
| 35 | +| `type` | string | `"dark"` or `"light"`. Selects fallback preset (`QueryaTheme.darkDefault` / `QueryaTheme.lightDefault`). | |
| 36 | +| `shadcn_colors` | object | String map → shadcn `ColorScheme` tokens. May be `{}`; missing keys fall back to the preset. | |
| 37 | +| `editor_colors` | object | String map → editor and workbench tokens. May be `{}`; missing keys fall back to the preset. | |
| 38 | + |
| 39 | +### Optional fields |
| 40 | + |
| 41 | +| Field | Type | Description | |
| 42 | +|-------|------|-------------| |
| 43 | +| `tokenColors` | array | VS Code–compatible syntax rules (same shape as VS Code themes). Applied to SQL/JSON highlighting. | |
| 44 | +| `description` | string | Short summary for theme picker / marketplace. | |
| 45 | +| `author` | string | Author or org name. | |
| 46 | +| `version` | string | Theme package version (informational). | |
| 47 | + |
| 48 | +Unknown root fields are ignored. In debug builds the parser may log skipped keys. |
| 49 | + |
| 50 | +## Color string formats |
| 51 | + |
| 52 | +All color values are hex strings. The parser reuses `parseVsCodeColor` (via a thin |
| 53 | +Querya wrapper) and accepts: |
| 54 | + |
| 55 | +| Format | Example | Notes | |
| 56 | +|--------|---------|-------| |
| 57 | +| `#RRGGBB` | `"#22D3EE"` | Most common | |
| 58 | +| `RRGGBB` | `"22D3EE"` | `#` optional | |
| 59 | +| `#RRGGBBAA` | `"#FF22D3EE"` | Alpha last (VS Code style) | |
| 60 | +| `RRGGBBAA` | `"FF22D3EE"` | `#` optional | |
| 61 | +| `#RGB` | `"#F0A"` | Expanded to `#FF00AA` | |
| 62 | +| `#RGBA` | `"#F0A8"` | Expanded to `#FF00AA88` | |
| 63 | + |
| 64 | +Invalid optional color values are **skipped** for that key; the fallback preset value |
| 65 | +is used instead. Empty strings are treated as invalid. |
| 66 | + |
| 67 | +## `shadcn_colors` keys |
| 68 | + |
| 69 | +Maps to `shadcn_flutter.ColorScheme` (see `QueryaTheme.colorScheme`). |
| 70 | + |
| 71 | +| Key | Role | |
| 72 | +|-----|------| |
| 73 | +| `background` | App / page background | |
| 74 | +| `foreground` | Primary text | |
| 75 | +| `card` | Card surface | |
| 76 | +| `cardForeground` | Text on cards | |
| 77 | +| `popover` | Popover / dropdown surface | |
| 78 | +| `popoverForeground` | Text on popovers | |
| 79 | +| `primary` | Primary actions | |
| 80 | +| `primaryForeground` | Text on primary | |
| 81 | +| `secondary` | Secondary surfaces | |
| 82 | +| `secondaryForeground` | Text on secondary | |
| 83 | +| `muted` | Muted surfaces | |
| 84 | +| `mutedForeground` | Muted labels | |
| 85 | +| `accent` | Hover / accent fills | |
| 86 | +| `accentForeground` | Text on accent | |
| 87 | +| `destructive` | Destructive actions | |
| 88 | +| `destructiveForeground` | Text on destructive | |
| 89 | +| `border` | Borders | |
| 90 | +| `input` | Input borders / fills | |
| 91 | +| `ring` | Focus ring | |
| 92 | +| `chart1` … `chart5` | Chart palette | |
| 93 | + |
| 94 | +Brightness comes from `type`, not from individual colors. |
| 95 | + |
| 96 | +## `editor_colors` keys |
| 97 | + |
| 98 | +One map feeds both `QueryaEditorTheme` and `QueryaWorkbenchTheme`. |
| 99 | + |
| 100 | +### Editor (syntax surface) |
| 101 | + |
| 102 | +| Key | Target | |
| 103 | +|-----|--------| |
| 104 | +| `background` | Editor background | |
| 105 | +| `foreground` | Default text | |
| 106 | +| `lineHighlight` | Current line highlight | |
| 107 | +| `selection` | Selection background | |
| 108 | +| `lineNumber` | Gutter numbers | |
| 109 | +| `bracketMatch` | Matching bracket highlight | |
| 110 | +| `widgetBorder` | Editor chrome border | |
| 111 | +| `comment` | Comment token (fallback when no `tokenColors` match) | |
| 112 | +| `keyword` | Keyword token | |
| 113 | +| `string` | String token | |
| 114 | +| `number` | Numeric token | |
| 115 | +| `operator` | Operator token | |
| 116 | +| `function` | Function token | |
| 117 | +| `type` | Type name token | |
| 118 | + |
| 119 | +### Workbench (chrome) |
| 120 | + |
| 121 | +| Key | Target | |
| 122 | +|-----|--------| |
| 123 | +| `canvas` | Main app canvas (title bar, status areas) | |
| 124 | +| `surface` | Raised panels, tabs | |
| 125 | +| `sidebarBackground` | Explorer / sidebar | |
| 126 | +| `editorBackground` | Editor pane chrome (may differ from syntax `background`) | |
| 127 | +| `mutedForeground` | Secondary labels | |
| 128 | +| `accent` | Brand / focus accent | |
| 129 | +| `onAccent` | Text/icons on accent | |
| 130 | +| `borderSubtle` | Subtle dividers | |
| 131 | +| `destructive` | Error / delete emphasis | |
| 132 | +| `success` | Success state | |
| 133 | +| `warning` | Warning state | |
| 134 | +| `gitModified` | Git modified decoration | |
| 135 | +| `gitUntracked` | Git untracked decoration | |
| 136 | + |
| 137 | +If `background` appears without `canvas`, the parser does **not** auto-map it unless |
| 138 | +explicitly documented in a future schema revision. Prefer `canvas` and |
| 139 | +`editorBackground`. |
| 140 | + |
| 141 | +## `tokenColors` |
| 142 | + |
| 143 | +Same structure as VS Code themes: array of objects with `scope` (string or array), |
| 144 | +optional `name`, and `settings.foreground` / `settings.background` / `settings.fontStyle`. |
| 145 | + |
| 146 | +Querya applies these through `TokenStyleResolver` → SQL/JSON highlighters. See |
| 147 | +[theme-import.md](theme-import.md) for behavior notes. |
| 148 | + |
| 149 | +## Fallback and error handling |
| 150 | + |
| 151 | +| Situation | Behavior | |
| 152 | +|-----------|----------| |
| 153 | +| Missing optional color key | Use value from `QueryaTheme.darkDefault` or `QueryaTheme.lightDefault` (based on `type`). | |
| 154 | +| Invalid optional color | Skip key; use fallback value. | |
| 155 | +| Missing required root field (`schema`, `id`, `name`, `type`, `shadcn_colors`, `editor_colors`) | Parsing fails; theme is not loaded. | |
| 156 | +| Wrong `schema` value | Parsing fails. | |
| 157 | +| Invalid `type` | Parsing fails. | |
| 158 | +| Broken file at startup (selected theme) | App starts with **Querya Dark**; error surfaced in Preferences (planned). User setting is not deleted. | |
| 159 | +| Broken file in directory scan | Skipped or shown as disabled in picker (planned); scan does not crash the app. | |
| 160 | + |
| 161 | +## JSONC |
| 162 | + |
| 163 | +Comments and trailing commas are allowed in `.jsonc` files. The shared preprocessor |
| 164 | +`stripJsonc` runs before `jsonDecode` (same as VS Code import). |
| 165 | + |
| 166 | +## Minimal example |
| 167 | + |
| 168 | +Only required fields; all colors come from Querya Dark defaults: |
| 169 | + |
| 170 | +```json |
| 171 | +{ |
| 172 | + "schema": "querya.theme.v1", |
| 173 | + "id": "querya-dark-clone", |
| 174 | + "name": "Querya Dark (minimal)", |
| 175 | + "type": "dark", |
| 176 | + "shadcn_colors": {}, |
| 177 | + "editor_colors": {} |
| 178 | +} |
| 179 | +``` |
| 180 | + |
| 181 | +## Full example (dark) |
| 182 | + |
| 183 | +```json |
| 184 | +{ |
| 185 | + "schema": "querya.theme.v1", |
| 186 | + "id": "cyberpunk-neon", |
| 187 | + "name": "Cyberpunk Neon", |
| 188 | + "type": "dark", |
| 189 | + "description": "Neon cyberpunk preset for Querya workbench and SQL editor.", |
| 190 | + "author": "QueryaHub", |
| 191 | + "version": "1.0.0", |
| 192 | + "shadcn_colors": { |
| 193 | + "background": "#09090B", |
| 194 | + "foreground": "#F8FAFC", |
| 195 | + "card": "#111113", |
| 196 | + "cardForeground": "#F8FAFC", |
| 197 | + "popover": "#111113", |
| 198 | + "popoverForeground": "#F8FAFC", |
| 199 | + "primary": "#00F5FF", |
| 200 | + "primaryForeground": "#020617", |
| 201 | + "secondary": "#18181B", |
| 202 | + "secondaryForeground": "#F8FAFC", |
| 203 | + "muted": "#18181B", |
| 204 | + "mutedForeground": "#94A3B8", |
| 205 | + "accent": "#FF2A6D", |
| 206 | + "accentForeground": "#F8FAFC", |
| 207 | + "destructive": "#EF4444", |
| 208 | + "destructiveForeground": "#F8FAFC", |
| 209 | + "border": "#27272A", |
| 210 | + "input": "#27272A", |
| 211 | + "ring": "#00F5FF", |
| 212 | + "chart1": "#00F5FF", |
| 213 | + "chart2": "#FF2A6D", |
| 214 | + "chart3": "#FCEE09", |
| 215 | + "chart4": "#BD00FF", |
| 216 | + "chart5": "#39FF14" |
| 217 | + }, |
| 218 | + "editor_colors": { |
| 219 | + "background": "#0A0A14", |
| 220 | + "foreground": "#E8F4FF", |
| 221 | + "selection": "#FF2A6D44", |
| 222 | + "lineNumber": "#4A3F7A", |
| 223 | + "bracketMatch": "#00F5FF33", |
| 224 | + "widgetBorder": "#00F5FF66", |
| 225 | + "canvas": "#050508", |
| 226 | + "surface": "#14102A", |
| 227 | + "sidebarBackground": "#0C0820", |
| 228 | + "editorBackground": "#0A0A14", |
| 229 | + "mutedForeground": "#8B7CF8", |
| 230 | + "accent": "#00F5FF", |
| 231 | + "onAccent": "#020617", |
| 232 | + "borderSubtle": "#27272A", |
| 233 | + "destructive": "#EF4444", |
| 234 | + "gitModified": "#FCEE09", |
| 235 | + "gitUntracked": "#39FF14" |
| 236 | + }, |
| 237 | + "tokenColors": [ |
| 238 | + { |
| 239 | + "name": "Comments", |
| 240 | + "scope": ["comment", "comment.line"], |
| 241 | + "settings": { "foreground": "#5C4D8A", "fontStyle": "italic" } |
| 242 | + }, |
| 243 | + { |
| 244 | + "name": "Keywords", |
| 245 | + "scope": ["keyword", "keyword.control"], |
| 246 | + "settings": { "foreground": "#FF2A6D", "fontStyle": "bold" } |
| 247 | + }, |
| 248 | + { |
| 249 | + "name": "Strings", |
| 250 | + "scope": ["string"], |
| 251 | + "settings": { "foreground": "#FCEE09" } |
| 252 | + } |
| 253 | + ] |
| 254 | +} |
| 255 | +``` |
| 256 | + |
| 257 | +## VS Code format vs Querya custom |
| 258 | + |
| 259 | +| | VS Code JSON/JSONC | Querya custom | |
| 260 | +|--|-------------------|---------------| |
| 261 | +| Detection | No `schema`; has `colors` | `"schema": "querya.theme.v1"` | |
| 262 | +| UI colors | VS Code keys (`editor.background`, `sideBar.background`, …) | `shadcn_colors` + `editor_colors` Querya keys | |
| 263 | +| Stable id | File name only | Required `id` field | |
| 264 | +| Import today | **Yes** — Preferences → Import theme | Planned via theme registry | |
| 265 | +| Syntax tokens | `tokenColors` | `tokenColors` (same) | |
| 266 | + |
| 267 | +To convert a VS Code theme manually, map keys using |
| 268 | +[theme-import.md](theme-import.md) and place workbench values into `editor_colors`; |
| 269 | +derive shadcn tokens from your palette or leave `{}` to use preset defaults. |
| 270 | + |
| 271 | +## Related docs |
| 272 | + |
| 273 | +- [Theme import (VS Code)](theme-import.md) |
| 274 | +- [Theme system overview](theme.md) |
| 275 | +- [Implementation plan](theme-parser-implementation-tasks.md) |
| 276 | +- Sample VS Code themes: `themes/samples/cyberpunk-neon.json` |
0 commit comments