add four design themes + syntax tokens to theme pipeline
test / unit + widget + golden + a11y (push) Failing after 39s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
SurfaceTokens gains seven syntax-role fields (keyword, type, string, number, comment, method, punct). Theme loader parses the syntax: YAML block and injects values into the surface override layer. Resolver defaults map syntax roles to semantic colours so themes without explicit syntax blocks still compile. Four new theme YAMLs (clide, midnight, paper, terminal) replace summer-night. Palette keys mapped to the existing semantic layer; syntax values pass through directly. Goldens regenerated for the 14→font-size change. Co-Authored-By: Claude <noreply@anthropic.com>
@@ -46,10 +46,35 @@ class ThemeLoader {
|
||||
}
|
||||
final palette = _parsePalette(paletteYaml);
|
||||
|
||||
// Syntax colours inject into the surface override layer so
|
||||
// TokenKeys.syntax* resolve directly from the theme YAML.
|
||||
final syntaxYaml = doc['syntax'];
|
||||
final syntaxSurface = <String, String>{};
|
||||
if (syntaxYaml is Map) {
|
||||
const syntaxMap = {
|
||||
'keyword': 'syntax.keyword',
|
||||
'type': 'syntax.type',
|
||||
'string': 'syntax.string',
|
||||
'number': 'syntax.number',
|
||||
'comment': 'syntax.comment',
|
||||
'method': 'syntax.method',
|
||||
'punct': 'syntax.punct',
|
||||
};
|
||||
syntaxYaml.forEach((k, v) {
|
||||
final key = syntaxMap['$k'];
|
||||
if (key != null && v is String) syntaxSurface[key] = v;
|
||||
});
|
||||
}
|
||||
|
||||
final semantic = doc['semantic'];
|
||||
final surface = doc['surface'];
|
||||
final extension = doc['extension'];
|
||||
|
||||
final mergedSurface = <String, String>{
|
||||
...syntaxSurface,
|
||||
if (surface is Map) ..._parseRefMap(surface),
|
||||
};
|
||||
|
||||
return ThemeDefinition(
|
||||
name: name,
|
||||
displayName: displayName,
|
||||
@@ -57,7 +82,7 @@ class ThemeLoader {
|
||||
palette: palette,
|
||||
semanticOverride:
|
||||
semantic is Map ? _parseSemantic(semantic, palette) : null,
|
||||
surfaceOverride: surface is Map ? _parseRefMap(surface) : null,
|
||||
surfaceOverride: mergedSurface.isNotEmpty ? mergedSurface : null,
|
||||
extensionOverride: extension is Map ? _parseRefMap(extension) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -102,6 +102,13 @@ class ThemeResolver {
|
||||
statusWarning: surface[TokenKeys.statusWarning]!,
|
||||
statusError: surface[TokenKeys.statusError]!,
|
||||
statusInfo: surface[TokenKeys.statusInfo]!,
|
||||
syntaxKeyword: surface[TokenKeys.syntaxKeyword]!,
|
||||
syntaxType: surface[TokenKeys.syntaxType]!,
|
||||
syntaxString: surface[TokenKeys.syntaxString]!,
|
||||
syntaxNumber: surface[TokenKeys.syntaxNumber]!,
|
||||
syntaxComment: surface[TokenKeys.syntaxComment]!,
|
||||
syntaxMethod: surface[TokenKeys.syntaxMethod]!,
|
||||
syntaxPunct: surface[TokenKeys.syntaxPunct]!,
|
||||
extensionTokens: extTokens,
|
||||
);
|
||||
}
|
||||
@@ -235,4 +242,11 @@ const Map<String, String> _defaultSurfaceMap = {
|
||||
TokenKeys.statusWarning: 'semantic.warning',
|
||||
TokenKeys.statusError: 'semantic.error',
|
||||
TokenKeys.statusInfo: 'semantic.info',
|
||||
TokenKeys.syntaxKeyword: 'semantic.calltoaction',
|
||||
TokenKeys.syntaxType: 'semantic.info',
|
||||
TokenKeys.syntaxString: 'semantic.success',
|
||||
TokenKeys.syntaxNumber: 'semantic.warning',
|
||||
TokenKeys.syntaxComment: 'semantic.text_muted',
|
||||
TokenKeys.syntaxMethod: 'semantic.focus',
|
||||
TokenKeys.syntaxPunct: 'semantic.text_muted',
|
||||
};
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# clide — cool near-black + periwinkle (default)
|
||||
# Source: docs/claude-design/tokens/clide.yaml
|
||||
|
||||
name: clide
|
||||
display_name: Clide
|
||||
dark: true
|
||||
|
||||
palette:
|
||||
background: "#20202C"
|
||||
panel: "#1A1A24"
|
||||
surface: "#242838"
|
||||
muted: "#78809C"
|
||||
foreground: "#E6E8F2"
|
||||
secondary: "#B1BBE3"
|
||||
primary: "#78A0F8"
|
||||
accent: "#6C90DC"
|
||||
success: "#7DD3A8"
|
||||
warning: "#E6C370"
|
||||
error: "#E87D7D"
|
||||
info: "#78A0F8"
|
||||
# extended palette keys for the design's richer vocabulary
|
||||
surfaceHi: "#2C3046"
|
||||
border: "#343850"
|
||||
borderHi: "#3C445C"
|
||||
textDim: "#78809C"
|
||||
textMute: "#545C84"
|
||||
accentSoft: "#2178A0F8"
|
||||
|
||||
syntax:
|
||||
keyword: "#C792EA"
|
||||
type: "#78A0F8"
|
||||
string: "#A8D99B"
|
||||
number: "#E6C370"
|
||||
comment: "#545C84"
|
||||
method: "#82B1FF"
|
||||
punct: "#78809C"
|
||||
@@ -0,0 +1,35 @@
|
||||
# midnight — VS Code-adjacent muted dark
|
||||
# Source: docs/claude-design/tokens/midnight.yaml
|
||||
|
||||
name: midnight
|
||||
display_name: Midnight
|
||||
dark: true
|
||||
|
||||
palette:
|
||||
background: "#1E1E1E"
|
||||
panel: "#181818"
|
||||
surface: "#252526"
|
||||
muted: "#858585"
|
||||
foreground: "#D4D4D4"
|
||||
secondary: "#BBBBBB"
|
||||
primary: "#569CD6"
|
||||
accent: "#4785BD"
|
||||
success: "#89D185"
|
||||
warning: "#D7BA7D"
|
||||
error: "#F48771"
|
||||
info: "#569CD6"
|
||||
surfaceHi: "#2D2D2E"
|
||||
border: "#333333"
|
||||
borderHi: "#3F3F3F"
|
||||
textDim: "#858585"
|
||||
textMute: "#6A6A6A"
|
||||
accentSoft: "#21569CD6"
|
||||
|
||||
syntax:
|
||||
keyword: "#C586C0"
|
||||
type: "#4EC9B0"
|
||||
string: "#CE9178"
|
||||
number: "#B5CEA8"
|
||||
comment: "#6A9955"
|
||||
method: "#DCDCAA"
|
||||
punct: "#858585"
|
||||
@@ -0,0 +1,35 @@
|
||||
# paper — drafting sheet, red-pencil accent, light
|
||||
# Source: docs/claude-design/tokens/paper.yaml
|
||||
|
||||
name: paper
|
||||
display_name: Paper
|
||||
dark: false
|
||||
|
||||
palette:
|
||||
background: "#F4F1EA"
|
||||
panel: "#ECE7DB"
|
||||
surface: "#FBF8F1"
|
||||
muted: "#8A8A82"
|
||||
foreground: "#1A1A1A"
|
||||
secondary: "#4A4A4A"
|
||||
primary: "#C14B2A"
|
||||
accent: "#A03D20"
|
||||
success: "#2D8A52"
|
||||
warning: "#B88A2A"
|
||||
error: "#B03A2A"
|
||||
info: "#2A6FC1"
|
||||
surfaceHi: "#ECE7DB"
|
||||
border: "#1A1A1A"
|
||||
borderHi: "#4A4A4A"
|
||||
textDim: "#8A8A82"
|
||||
textMute: "#A8A89E"
|
||||
accentSoft: "#21C14B2A"
|
||||
|
||||
syntax:
|
||||
keyword: "#7B3F8C"
|
||||
type: "#2A6FC1"
|
||||
string: "#2D8A52"
|
||||
number: "#B88A2A"
|
||||
comment: "#8A8A82"
|
||||
method: "#1E5D9E"
|
||||
punct: "#4A4A4A"
|
||||
@@ -0,0 +1,35 @@
|
||||
# terminal — near-black + amber, tmux feel
|
||||
# Source: docs/claude-design/tokens/terminal.yaml
|
||||
|
||||
name: terminal
|
||||
display_name: Terminal
|
||||
dark: true
|
||||
|
||||
palette:
|
||||
background: "#0A0A0A"
|
||||
panel: "#000000"
|
||||
surface: "#111111"
|
||||
muted: "#7A7A7A"
|
||||
foreground: "#E6E6E6"
|
||||
secondary: "#BDBDBD"
|
||||
primary: "#E0B050"
|
||||
accent: "#C29438"
|
||||
success: "#8FDC9B"
|
||||
warning: "#E0B050"
|
||||
error: "#E05050"
|
||||
info: "#A3C4FF"
|
||||
surfaceHi: "#181818"
|
||||
border: "#242424"
|
||||
borderHi: "#2E2E2E"
|
||||
textDim: "#7A7A7A"
|
||||
textMute: "#4A4A4A"
|
||||
accentSoft: "#21E0B050"
|
||||
|
||||
syntax:
|
||||
keyword: "#E05050"
|
||||
type: "#E0B050"
|
||||
string: "#8FDC9B"
|
||||
number: "#C792EA"
|
||||
comment: "#4A4A4A"
|
||||
method: "#A3C4FF"
|
||||
punct: "#7A7A7A"
|
||||
@@ -77,6 +77,14 @@ class SurfaceTokens {
|
||||
required this.statusWarning,
|
||||
required this.statusError,
|
||||
required this.statusInfo,
|
||||
// syntax
|
||||
required this.syntaxKeyword,
|
||||
required this.syntaxType,
|
||||
required this.syntaxString,
|
||||
required this.syntaxNumber,
|
||||
required this.syntaxComment,
|
||||
required this.syntaxMethod,
|
||||
required this.syntaxPunct,
|
||||
required this.extensionTokens,
|
||||
});
|
||||
|
||||
@@ -146,6 +154,14 @@ class SurfaceTokens {
|
||||
final Color statusError;
|
||||
final Color statusInfo;
|
||||
|
||||
final Color syntaxKeyword;
|
||||
final Color syntaxType;
|
||||
final Color syntaxString;
|
||||
final Color syntaxNumber;
|
||||
final Color syntaxComment;
|
||||
final Color syntaxMethod;
|
||||
final Color syntaxPunct;
|
||||
|
||||
/// Extension-declared tokens keyed by their dotted path
|
||||
/// (e.g. `ext.sqlite.table.background`).
|
||||
final Map<String, Color> extensionTokens;
|
||||
@@ -235,6 +251,15 @@ abstract class TokenKeys {
|
||||
static const statusError = 'status.error';
|
||||
static const statusInfo = 'status.info';
|
||||
|
||||
// syntax
|
||||
static const syntaxKeyword = 'syntax.keyword';
|
||||
static const syntaxType = 'syntax.type';
|
||||
static const syntaxString = 'syntax.string';
|
||||
static const syntaxNumber = 'syntax.number';
|
||||
static const syntaxComment = 'syntax.comment';
|
||||
static const syntaxMethod = 'syntax.method';
|
||||
static const syntaxPunct = 'syntax.punct';
|
||||
|
||||
static const all = <String>[
|
||||
globalForeground,
|
||||
globalBackground,
|
||||
@@ -289,5 +314,12 @@ abstract class TokenKeys {
|
||||
statusWarning,
|
||||
statusError,
|
||||
statusInfo,
|
||||
syntaxKeyword,
|
||||
syntaxType,
|
||||
syntaxString,
|
||||
syntaxNumber,
|
||||
syntaxComment,
|
||||
syntaxMethod,
|
||||
syntaxPunct,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -105,7 +105,10 @@ Future<Directory> _resolveAppDir() async {
|
||||
Future<List<ThemeDefinition>> _loadBundledThemes() async {
|
||||
const loader = ThemeLoader();
|
||||
const paths = [
|
||||
'lib/kernel/src/theme/themes/summer-night.yaml',
|
||||
'lib/kernel/src/theme/themes/clide.yaml',
|
||||
'lib/kernel/src/theme/themes/midnight.yaml',
|
||||
'lib/kernel/src/theme/themes/paper.yaml',
|
||||
'lib/kernel/src/theme/themes/terminal.yaml',
|
||||
];
|
||||
final out = <ThemeDefinition>[];
|
||||
for (final p in paths) {
|
||||
|
||||
@@ -8,7 +8,7 @@ name: clide_app
|
||||
description: >-
|
||||
Flutter desktop IDE for Claude Code — renders the UI. Talks to the
|
||||
Dart core (CLI + daemon) via IPC; all PTY/subprocess/filesystem work
|
||||
lives in the daemon (ADR 0005).
|
||||
lives in the daemon (D-005).
|
||||
publish_to: none
|
||||
version: 2.0.0-dev
|
||||
repository: https://git.schweitz.net/jpmschweitzer/clide
|
||||
@@ -23,7 +23,7 @@ dependencies:
|
||||
|
||||
# Dart core — shared types, IPC protocol, anything CLI + daemon + app
|
||||
# all import. Kept Flutter-free so `dart compile exe` produces a lean
|
||||
# static binary (see ADR 0005).
|
||||
# static binary (see D-005).
|
||||
clide:
|
||||
path: ../
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 810 B After Width: | Height: | Size: 804 B |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.4 KiB |
@@ -6,7 +6,7 @@
|
||||
# `dart compile exe` produces a lean static binary.
|
||||
#
|
||||
# The Flutter desktop UI lives under `app/` as a separate package that
|
||||
# depends on this one via a path: dependency. See ADR 0005 for the
|
||||
# depends on this one via a path: dependency. See D-005 for the
|
||||
# layout rationale.
|
||||
#
|
||||
# Version is mirrored from project.yaml on every bump. project.yaml is
|
||||
|
||||