lutaml 0.10.6 → 0.10.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,9 +10,10 @@ document.addEventListener('alpine:init', () => {
10
10
  config: window.APP_CONFIG || {},
11
11
 
12
12
  // Current State
13
- currentView: 'welcome', // 'welcome' | 'package' | 'class' | 'search'
13
+ currentView: 'welcome', // 'welcome' | 'package' | 'class' | 'search' | 'diagram'
14
14
  currentPackage: null,
15
15
  currentClass: null,
16
+ currentDiagram: null,
16
17
  searchQuery: '',
17
18
  searchResults: [],
18
19
 
@@ -86,6 +87,7 @@ document.addEventListener('alpine:init', () => {
86
87
  this.currentView = 'welcome';
87
88
  this.currentPackage = null;
88
89
  this.currentClass = null;
90
+ this.currentDiagram = null;
89
91
  this.breadcrumbs = [];
90
92
  this.pushState();
91
93
  },
@@ -118,6 +120,21 @@ document.addEventListener('alpine:init', () => {
118
120
  this.pushState();
119
121
  },
120
122
 
123
+ selectDiagram(diagramId) {
124
+ if (!this.data || !this.data.diagrams[diagramId]) {
125
+ console.warn('Diagram not found:', diagramId);
126
+ return;
127
+ }
128
+
129
+ const diag = this.data.diagrams[diagramId];
130
+
131
+ this.currentDiagram = diagramId;
132
+ this.currentPackage = diag.package;
133
+ this.currentView = 'diagram';
134
+ this.updateBreadcrumbs();
135
+ this.pushState();
136
+ },
137
+
121
138
  performSearch(query) {
122
139
  if (!query || query.length < 2) {
123
140
  this.searchResults = [];
@@ -196,6 +213,8 @@ document.addEventListener('alpine:init', () => {
196
213
  this.breadcrumbs = this.buildPackageBreadcrumbs(this.currentPackage);
197
214
  } else if (this.currentView === 'class' && this.currentClass) {
198
215
  this.breadcrumbs = this.buildClassBreadcrumbs(this.currentClass);
216
+ } else if (this.currentView === 'diagram' && this.currentDiagram) {
217
+ this.breadcrumbs = [{ name: `Diagram: ${this.data.diagrams[this.currentDiagram]?.name || ''}`, type: 'diagram' }];
199
218
  } else if (this.currentView === 'search') {
200
219
  this.breadcrumbs = [{ name: `Search: ${this.searchQuery}`, type: 'search' }];
201
220
  }
@@ -275,6 +294,8 @@ document.addEventListener('alpine:init', () => {
275
294
  this.selectPackage(decodeURIComponent(parts[1]));
276
295
  } else if (parts[0] === 'class' && parts[1]) {
277
296
  this.selectClass(decodeURIComponent(parts[1]));
297
+ } else if (parts[0] === 'diagram' && parts[1]) {
298
+ this.selectDiagram(decodeURIComponent(parts[1]));
278
299
  } else if (parts[0] === 'search') {
279
300
  const params = new URLSearchParams(queryString);
280
301
  const query = params.get('q');
@@ -294,6 +315,8 @@ document.addEventListener('alpine:init', () => {
294
315
  hash = `#/package/${encodeURIComponent(this.currentPackage)}`;
295
316
  } else if (this.currentView === 'class' && this.currentClass) {
296
317
  hash = `#/class/${encodeURIComponent(this.currentClass)}`;
318
+ } else if (this.currentView === 'diagram' && this.currentDiagram) {
319
+ hash = `#/diagram/${encodeURIComponent(this.currentDiagram)}`;
297
320
  } else if (this.currentView === 'search' && this.searchQuery) {
298
321
  hash = `#/search?q=${encodeURIComponent(this.searchQuery)}`;
299
322
  }
@@ -370,6 +393,7 @@ function app() {
370
393
  get currentView() { return Alpine.store('app').currentView; },
371
394
  get currentPackage() { return Alpine.store('app').currentPackage; },
372
395
  get currentClass() { return Alpine.store('app').currentClass; },
396
+ get currentDiagram() { return Alpine.store('app').currentDiagram; },
373
397
  get sidebarVisible() {
374
398
  return Alpine.store('app').sidebarVisible;
375
399
  },
@@ -392,6 +416,9 @@ function app() {
392
416
  selectClass(id) {
393
417
  Alpine.store('app').selectClass(id);
394
418
  },
419
+ selectDiagram(id) {
420
+ Alpine.store('app').selectDiagram(id);
421
+ },
395
422
  toggleTheme() {
396
423
  Alpine.store('app').toggleTheme();
397
424
  },
@@ -1,7 +1,7 @@
1
- // Alpine.js Components for Sidebar
1
+ // Sidebar Tree LutaML Branded
2
+ // Compact, clean tree matching lutaml-xsd SchemaTreeNode
2
3
 
3
4
  document.addEventListener('alpine:init', () => {
4
- // Package Tree Component
5
5
  Alpine.data('packageTree', () => ({
6
6
  get data() {
7
7
  return this.$store.app.data;
@@ -9,206 +9,115 @@ document.addEventListener('alpine:init', () => {
9
9
 
10
10
  get rootNodes() {
11
11
  if (!this.data || !this.data.packageTree) return [];
12
-
13
- // Return as array for iteration
14
12
  return [this.data.packageTree];
15
13
  }
16
14
  }));
17
15
 
18
- // Tree Node Component (Recursive)
19
- Alpine.data('treeNode', (node) => ({
20
- node,
21
-
22
- get expanded() {
23
- return this.$store.app.isNodeExpanded(this.node.id);
24
- },
25
-
26
- get hasChildren() {
27
- return (this.node.children && this.node.children.length > 0) ||
28
- (this.node.classes && this.node.classes.length > 0);
29
- },
30
-
31
- get isSelected() {
32
- return this.$store.app.currentPackage === this.node.id;
33
- },
34
-
35
- get currentClass() {
36
- return this.$store.app.currentClass;
37
- },
38
-
39
- toggle() {
40
- this.$store.app.toggleNode(this.node.id);
41
- },
42
-
43
- selectPackage(id) {
44
- this.$store.app.selectPackage(id);
45
- },
46
-
47
- selectClass(id) {
48
- this.$store.app.selectClass(id);
49
- },
50
-
51
- getClass(classId) {
52
- return this.$store.app.data?.classes[classId];
53
- }
54
- }));
55
-
56
- // Sidebar Actions
57
- Alpine.data('sidebarActions', () => ({
58
- expandAll() {
59
- this.$store.app.expandAll();
60
- },
61
-
62
- collapseAll() {
63
- this.$store.app.collapseAll();
64
- }
65
- }));
66
-
67
- // Recursive tree rendering component with full reactivity
68
16
  Alpine.data('renderTree', (rootNode) => ({
69
17
  treeHtml: '',
70
18
  rootNode,
71
19
 
72
20
  init() {
73
21
  this.rebuildTree();
74
-
75
- // Listen for manual rebuild triggers
76
- window.addEventListener('tree-rebuild', () => {
77
- this.rebuildTree();
78
- });
79
-
80
- // Watch for state changes and rebuild tree
81
- this.$watch('$store.app.expandedNodes.size', () => {
82
- this.rebuildTree();
83
- });
84
-
85
- this.$watch('$store.app.currentPackage', () => {
86
- this.rebuildTree();
87
- });
88
-
89
- this.$watch('$store.app.currentClass', () => {
90
- this.rebuildTree();
91
- });
22
+ window.addEventListener('tree-rebuild', () => this.rebuildTree());
23
+ this.$watch('$store.app.expandedNodes.size', () => this.rebuildTree());
24
+ this.$watch('$store.app.currentPackage', () => this.rebuildTree());
25
+ this.$watch('$store.app.currentClass', () => this.rebuildTree());
92
26
  },
93
27
 
94
28
  rebuildTree() {
95
- this.treeHtml = this.buildTreeNode(this.rootNode);
29
+ if (!this.rootNode) { this.treeHtml = ''; return; }
30
+ this.treeHtml = this.buildPackageNode(this.rootNode);
96
31
  },
97
32
 
98
- buildTreeNode(node) {
33
+ buildPackageNode(node) {
99
34
  const store = Alpine.store('app');
100
35
  const expanded = store.isNodeExpanded(node.id);
101
- const isSelected = store.currentPackage === node.id;
36
+ const selected = store.currentPackage === node.id;
102
37
  const hasChildren = (node.children && node.children.length > 0) ||
103
38
  (node.classes && node.classes.length > 0);
104
-
105
- // Get package data for stereotypes
106
39
  const pkg = store.data?.packages[node.id];
107
40
  const stereotypes = pkg?.stereotypes || node.stereotypes || [];
108
41
 
109
- let html = `<div class="tree-node${isSelected ? ' selected' : ''}">`;
110
- html += '<div class="node-header">';
42
+ let h = '<div class="tree-node">';
43
+ h += '<div class="tree-node-content' + (selected ? ' selected' : '') + '">';
111
44
 
112
- // Expand/collapse button - call store method directly and trigger rebuild
45
+ // Expand toggle
113
46
  if (hasChildren) {
114
- html += `<button onclick="Alpine.store('app').toggleNode('${node.id}'); window.dispatchEvent(new CustomEvent('tree-rebuild'));" class="expand-icon${expanded ? ' expanded' : ''}">`;
115
- html += '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">';
116
- html += '<polyline points="9 18 15 12 9 6"></polyline></svg></button>';
47
+ h += '<button onclick="Alpine.store(\'app\').toggleNode(\'' + node.id + '\'); window.dispatchEvent(new CustomEvent(\'tree-rebuild\'));" class="tree-toggle">';
48
+ h += '<svg width="12" height="12" viewBox="0 0 12 12" fill="none"' + (expanded ? ' class="expanded"' : '') + '>';
49
+ h += '<path d="M4 3l3 3-3 3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>';
50
+ h += '</svg></button>';
117
51
  } else {
118
- html += '<span class="no-icon"></span>';
52
+ h += '<span class="tree-toggle-placeholder"></span>';
119
53
  }
120
54
 
121
- // Package icon and label
122
- html += '<svg class="package-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">';
123
- html += '<path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg>';
55
+ // Folder icon
56
+ h += '<span class="tree-icon">';
57
+ h += '<svg width="14" height="14" viewBox="0 0 14 14" fill="none">';
58
+ h += '<path d="M2 5a2 2 0 012-2h2.5L8 4.5h2a2 2 0 012 2v2.5a2 2 0 01-2 2H4a2 2 0 01-2-2V5z" stroke="currentColor" stroke-width="1.1"/>';
59
+ h += '</svg></span>';
124
60
 
125
- html += `<button onclick="Alpine.store('app').selectPackage('${node.id}')" class="node-label${isSelected ? ' active' : ''}" title="${node.path || ''}">`;
126
-
127
- // Add stereotype prefix if present
61
+ // Label
62
+ h += '<button onclick="Alpine.store(\'app\').selectPackage(\'' + node.id + '\')" class="tree-label" title="' + this.esc(node.path || node.name) + '">';
128
63
  if (stereotypes.length > 0) {
129
- html += `<span class="stereotype-prefix">«${this.escapeHtml(stereotypes[0])}»</span> `;
64
+ h += '<span class="tree-stereotype">«' + this.esc(stereotypes[0]) + '» </span>';
130
65
  }
66
+ h += this.esc(node.name) + '</button>';
131
67
 
132
- html += `<span>${this.escapeHtml(node.name)}</span></button>`;
133
-
134
- // Class count badge
68
+ // Count badge
135
69
  if (node.classCount > 0) {
136
- html += `<span class="count-badge" title="${node.classCount} class${node.classCount !== 1 ? 'es' : ''}">${node.classCount}</span>`;
70
+ h += '<span class="tree-count">' + node.classCount + '</span>';
137
71
  }
138
72
 
139
- html += '</div>'; // node-header
73
+ h += '</div>'; // tree-node-content
140
74
 
141
- // Children (packages and classes)
75
+ // Children
142
76
  if (hasChildren && expanded) {
143
- html += '<div class="node-children">';
77
+ h += '<div class="tree-children">';
144
78
 
145
- // Render child packages
146
- if (node.children && node.children.length > 0) {
147
- node.children.forEach(child => {
148
- html += this.buildTreeNode(child);
79
+ if (node.classes && node.classes.length > 0) {
80
+ h += '<div class="tree-group">';
81
+ h += '<div class="tree-group-label">Classes <span class="tree-count">' + node.classes.length + '</span></div>';
82
+ h += '<div class="tree-group-items">';
83
+ node.classes.forEach(cd => {
84
+ const classId = typeof cd === 'string' ? cd : cd.id;
85
+ h += this.buildClassLeaf(classId);
149
86
  });
87
+ h += '</div></div>';
150
88
  }
151
89
 
152
- // Render classes
153
- if (node.classes && node.classes.length > 0) {
154
- node.classes.forEach(classData => {
155
- // classData can be either string ID or object with {id, name, stereotypes}
156
- const classId = typeof classData === 'string' ? classData : classData.id;
157
- const classStereotypes = typeof classData === 'object' ? classData.stereotypes : null;
158
- html += this.buildClassNode(classId, classStereotypes);
90
+ if (node.children && node.children.length > 0) {
91
+ node.children.forEach(child => {
92
+ h += this.buildPackageNode(child);
159
93
  });
160
94
  }
161
95
 
162
- html += '</div>';
96
+ h += '</div>';
163
97
  }
164
98
 
165
- html += '</div>'; // tree-node
166
- return html;
99
+ h += '</div>';
100
+ return h;
167
101
  },
168
102
 
169
- buildClassNode(classId, providedStereotypes = null) {
103
+ buildClassLeaf(classId) {
170
104
  const store = Alpine.store('app');
171
105
  const cls = store.data?.classes[classId];
172
106
  if (!cls) return '';
173
107
 
174
- const isSelected = store.currentClass === classId;
175
- const stereotypes = providedStereotypes || cls.stereotypes || [];
176
-
177
- let html = `<div class="tree-node class-node${isSelected ? ' selected' : ''}">`;
178
- html += '<div class="node-header">';
179
- html += '<span class="no-icon"></span>';
180
-
181
- // Class icon
182
- html += '<svg class="class-icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">';
183
- html += '<rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect>';
184
- html += '<line x1="3" y1="9" x2="21" y2="9"></line>';
185
- html += '<line x1="9" y1="21" x2="9" y2="9"></line>';
186
- html += '</svg>';
187
-
188
- html += `<button onclick="Alpine.store('app').selectClass('${classId}')" class="node-label${isSelected ? ' active' : ''}" title="${this.escapeHtml(cls.qualifiedName || cls.name)}">`;
189
-
190
- // Add stereotype prefix if present
191
- if (stereotypes.length > 0) {
192
- html += `<span class="stereotype-prefix">«${this.escapeHtml(stereotypes[0])}»</span> `;
193
- }
194
-
195
- html += `<span>${this.escapeHtml(cls.name)}</span></button>`;
196
-
197
- html += '</div>'; // node-header
198
- html += '</div>'; // tree-node
108
+ const selected = store.currentClass === classId;
109
+ const typeKey = (cls.type === 'Enumeration' ? 'enum' : cls.type === 'DataType' ? 'datatype' : cls.type === 'Interface' ? 'interface' : 'class');
199
110
 
200
- return html;
111
+ let h = '<div class="tree-item' + (selected ? ' selected' : '') + '" onclick="Alpine.store(\'app\').selectClass(\'' + classId + '\')">';
112
+ h += '<span class="badge badge-' + typeKey + '">' + (cls.type === 'Enumeration' ? 'E' : cls.type === 'DataType' ? 'DT' : cls.type === 'Interface' ? 'I' : 'C') + '</span>';
113
+ h += '<span class="tree-item-label" title="' + this.esc(cls.qualifiedName || cls.name) + '">' + this.esc(cls.name) + '</span>';
114
+ h += '</div>';
115
+ return h;
201
116
  },
202
117
 
203
- escapeHtml(text) {
204
- const map = {
205
- '&': '&amp;',
206
- '<': '&lt;',
207
- '>': '&gt;',
208
- '"': '&quot;',
209
- "'": '&#039;'
210
- };
211
- return String(text).replace(/[&<>"']/g, m => map[m]);
118
+ esc(text) {
119
+ const m = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#039;' };
120
+ return String(text).replace(/[&<>"']/g, c => m[c]);
212
121
  }
213
122
  }));
214
123
  });
@@ -1,144 +1,144 @@
1
- /* CSS Custom Properties for Theming */
1
+ /* LutaML UML Browser Branded Design System */
2
2
 
3
3
  :root {
4
- /* Colors - Light Theme */
5
- --color-bg: #ffffff;
6
- --color-bg-secondary: #f8f9fa;
7
- --color-bg-tertiary: #ecf0f1;
8
- --color-text: #2c3e50;
9
- --color-text-secondary: #7f8c8d;
10
- --color-text-muted: #95a5a6;
11
-
12
- --color-primary: #2c3e50;
13
- --color-accent: #3498db;
14
- --color-success: #27ae60;
15
- --color-warning: #f39c12;
16
- --color-error: #e74c3c;
17
- --color-info: #3498db;
18
-
19
- --color-border: #dcdfe6;
20
- --color-border-light: #e4e7ed;
21
- --color-border-dark: #b3b9bf;
22
-
23
- --color-link: #3498db;
24
- --color-link-hover: #2980b9;
25
-
26
- --color-code-bg: #f8f9fa;
27
- --color-code-text: #e74c3c;
28
-
29
- /* Sidebar */
30
- --color-sidebar-bg: #ffffff;
31
- --color-sidebar-border: #dcdfe6;
32
- --color-sidebar-hover: #f8f9fa;
33
- --color-sidebar-active: #ebf5fb;
34
-
35
- /* Header */
36
- --color-header-bg: #2c3e50;
37
- --color-header-text: #ffffff;
4
+ /* Primary LutaML Blue (#5b9cd4) */
5
+ --color-primary: #5b9cd4;
6
+ --color-primary-light: #7db5e2;
7
+ --color-primary-dark: #26489e;
8
+ --color-primary-alpha: rgba(91, 156, 212, 0.12);
9
+
10
+ /* Accent — Golden Yellow (#dbab3e) */
11
+ --color-accent: #dbab3e;
12
+ --color-accent-light: #f0ca6e;
13
+ --color-accent-alpha: rgba(219, 171, 62, 0.12);
14
+
15
+ /* Semantic */
16
+ --color-teal: #60c3a7;
17
+ --color-teal-alpha: rgba(96, 195, 167, 0.12);
18
+ --color-orange: #ea5624;
19
+ --color-orange-alpha: rgba(234, 86, 36, 0.12);
20
+ --color-red: #b31f24;
21
+ --color-red-alpha: rgba(179, 31, 36, 0.12);
22
+ --color-green: #7cc242;
23
+ --color-green-alpha: rgba(124, 194, 66, 0.12);
24
+
25
+ /* Backgrounds — Warm Stones */
26
+ --bg-primary: #FAFAF9;
27
+ --bg-secondary: #F5F5F4;
28
+ --bg-elevated: #FFFFFF;
29
+ --bg-overlay: rgba(28, 25, 23, 0.5);
30
+ --bg-hover: rgba(28, 25, 23, 0.04);
31
+ --bg-active: rgba(28, 25, 23, 0.06);
32
+
33
+ /* Text — Warm Grays */
34
+ --text-primary: #1C1917;
35
+ --text-secondary: #57534E;
36
+ --text-muted: #A8A29E;
37
+
38
+ /* Borders */
39
+ --border-light: #E7E5E4;
40
+ --border-medium: #D6D3D1;
41
+ --border-focus: #5b9cd4;
42
+
43
+ /* Badge Colors */
44
+ --badge-class: #26489e;
45
+ --badge-class-bg: rgba(38, 72, 158, 0.12);
46
+ --badge-enum: #dbab3e;
47
+ --badge-enum-bg: rgba(219, 171, 62, 0.15);
48
+ --badge-datatype: #60c3a7;
49
+ --badge-datatype-bg: rgba(96, 195, 167, 0.15);
50
+ --badge-interface: #5b9cd4;
51
+ --badge-interface-bg: rgba(91, 156, 212, 0.12);
52
+ --badge-package: #ea5624;
53
+ --badge-package-bg: rgba(234, 86, 36, 0.12);
54
+ --badge-diagram: #7cc242;
55
+ --badge-diagram-bg: rgba(124, 194, 66, 0.12);
56
+ --badge-abstract: #b31f24;
57
+ --badge-abstract-bg: rgba(179, 31, 36, 0.12);
38
58
 
39
- /* Spacing */
40
- --space-xs: 0.25rem;
41
- --space-sm: 0.5rem;
42
- --space-md: 1rem;
43
- --space-lg: 1.5rem;
44
- --space-xl: 2rem;
45
- --space-2xl: 3rem;
59
+ /* Shadows */
60
+ --shadow-sm: 0 1px 2px rgba(28, 25, 23, 0.05);
61
+ --shadow-md: 0 4px 6px -1px rgba(28, 25, 23, 0.07), 0 2px 4px -1px rgba(28, 25, 23, 0.04);
62
+ --shadow-lg: 0 10px 15px -3px rgba(28, 25, 23, 0.08), 0 4px 6px -2px rgba(28, 25, 23, 0.04);
46
63
 
47
64
  /* Typography */
48
- --font-family-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
49
- "Helvetica Neue", Arial, sans-serif;
50
- --font-family-mono: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono",
51
- "Courier New", monospace;
52
-
53
- --font-size-xs: 0.75rem;
54
- --font-size-sm: 0.875rem;
55
- --font-size-base: 1rem;
56
- --font-size-lg: 1.125rem;
57
- --font-size-xl: 1.25rem;
58
- --font-size-2xl: 1.5rem;
59
- --font-size-3xl: 1.875rem;
60
-
61
- --font-weight-normal: 400;
62
- --font-weight-medium: 500;
63
- --font-weight-semibold: 600;
64
- --font-weight-bold: 700;
65
-
66
- --line-height-tight: 1.25;
67
- --line-height-base: 1.5;
68
- --line-height-relaxed: 1.75;
65
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
66
+ --font-mono: 'JetBrains Mono', 'SF Mono', Monaco, 'Consolas', monospace;
67
+
68
+ /* Type Scale */
69
+ --text-xs: 0.75rem;
70
+ --text-sm: 0.875rem;
71
+ --text-base: 1rem;
72
+ --text-lg: 1.125rem;
73
+ --text-xl: 1.25rem;
74
+ --text-2xl: 1.5rem;
75
+ --text-3xl: 1.875rem;
76
+
77
+ /* Line Heights */
78
+ --leading-tight: 1.25;
79
+ --leading-normal: 1.5;
80
+ --leading-relaxed: 1.75;
69
81
 
70
- /* Layout */
71
- --sidebar-width: 320px;
72
- --header-height: 64px;
73
- --border-radius: 4px;
74
- --border-radius-lg: 8px;
75
-
76
- /* Shadows */
77
- --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
78
- --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
79
- --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
80
- --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.15);
82
+ /* Spacing */
83
+ --space-1: 0.25rem;
84
+ --space-2: 0.5rem;
85
+ --space-3: 0.75rem;
86
+ --space-4: 1rem;
87
+ --space-5: 1.25rem;
88
+ --space-6: 1.5rem;
89
+ --space-8: 2rem;
90
+ --space-10: 2.5rem;
91
+ --space-12: 3rem;
92
+
93
+ /* Border Radius */
94
+ --radius-sm: 0.25rem;
95
+ --radius-md: 0.375rem;
96
+ --radius-lg: 0.5rem;
97
+ --radius-xl: 0.75rem;
81
98
 
82
99
  /* Transitions */
83
- --transition-fast: 150ms ease-in-out;
84
- --transition-base: 200ms ease-in-out;
85
- --transition-slow: 300ms ease-in-out;
100
+ --transition-fast: 100ms ease;
101
+ --transition-normal: 150ms ease;
102
+ --transition-slow: 200ms ease-out;
103
+
104
+ /* Layout */
105
+ --sidebar-width: 280px;
106
+ --header-height: 56px;
86
107
 
87
108
  /* Z-index */
88
109
  --z-sidebar: 10;
89
110
  --z-header: 20;
90
- --z-search-overlay: 30;
91
- --z-modal: 40;
111
+ --z-search-overlay: 100;
112
+ --z-modal: 200;
92
113
  }
93
114
 
94
- /* Dark Theme */
115
+ /* Dark Mode */
95
116
  #app.dark {
96
- /* Colors - Dark Theme */
97
- --color-bg: #1e1e1e;
98
- --color-bg-secondary: #252526;
99
- --color-bg-tertiary: #2d2d30;
100
- --color-text: #e0e0e0;
101
- --color-text-secondary: #a0a0a0;
102
- --color-text-muted: #808080;
103
-
104
- --color-primary: #3d5a80;
105
- --color-accent: #5dade2;
106
- --color-success: #52c08d;
107
- --color-warning: #ffa726;
108
- --color-error: #ef5350;
109
- --color-info: #5dade2;
110
-
111
- --color-border: #3e3e42;
112
- --color-border-light: #2d2d30;
113
- --color-border-dark: #4e4e52;
114
-
115
- --color-link: #5dade2;
116
- --color-link-hover: #85c1e9;
117
-
118
- --color-code-bg: #2d2d30;
119
- --color-code-text: #ef5350;
120
-
121
- /* Sidebar */
122
- --color-sidebar-bg: #252526;
123
- --color-sidebar-border: #3e3e42;
124
- --color-sidebar-hover: #2d2d30;
125
- --color-sidebar-active: #37373d;
126
-
127
- /* Header */
128
- --color-header-bg: #1e1e1e;
129
- --color-header-text: #e0e0e0;
130
-
131
- /* Shadows (darker for dark mode) */
132
- --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
133
- --shadow-md: 0 4px 6px rgba(0, 0, 0, 0.4);
134
- --shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.5);
135
- --shadow-xl: 0 20px 25px rgba(0, 0, 0, 0.6);
117
+ --bg-primary: #1a1a24;
118
+ --bg-secondary: #232736;
119
+ --bg-elevated: #2d3344;
120
+ --bg-overlay: rgba(0, 0, 0, 0.7);
121
+ --bg-hover: rgba(255, 255, 255, 0.06);
122
+ --bg-active: rgba(255, 255, 255, 0.10);
123
+
124
+ --text-primary: #e8edf4;
125
+ --text-secondary: #a8b4c8;
126
+ --text-muted: #6b7a8f;
127
+
128
+ --border-light: #3a4256;
129
+ --border-medium: #4a5572;
130
+ --border-focus: #5b9cd4;
131
+
132
+ --badge-class-bg: rgba(91, 156, 212, 0.2);
133
+ --badge-class: #5b9cd4;
134
+ --badge-enum-bg: rgba(219, 171, 62, 0.2);
135
+ --badge-datatype-bg: rgba(96, 195, 167, 0.2);
136
+ --badge-interface-bg: rgba(91, 156, 212, 0.2);
137
+ --badge-package-bg: rgba(234, 86, 36, 0.2);
138
+ --badge-diagram-bg: rgba(124, 194, 66, 0.2);
139
+ --badge-abstract-bg: rgba(179, 31, 36, 0.2);
140
+
141
+ --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
142
+ --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.5), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
143
+ --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.6), 0 4px 6px -2px rgba(0, 0, 0, 0.4);
136
144
  }
137
-
138
- /* Responsive breakpoints (for media queries) */
139
- /* Use these in @media rules:
140
- @media (min-width: 640px) { ... } - Small devices and up
141
- @media (min-width: 768px) { ... } - Tablets and up
142
- @media (min-width: 1024px) { ... } - Desktop and up
143
- @media (min-width: 1280px) { ... } - Large desktop and up
144
- */