kimu-core 0.4.1

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.
Files changed (146) hide show
  1. package/.editorconfig +30 -0
  2. package/.gitattributes +11 -0
  3. package/.github/FUNDING.yml +8 -0
  4. package/.github/copilot-instructions.md +103 -0
  5. package/.github/kimu-copilot-instructions.md +3779 -0
  6. package/.github/workflows/deploy-demo.yml +39 -0
  7. package/AUTHORS.md +20 -0
  8. package/CHANGELOG.md +20 -0
  9. package/CODE_GUIDELINES.md +165 -0
  10. package/CODE_OF_CONDUCT.md +47 -0
  11. package/CONTRIBUTING.md +62 -0
  12. package/FUNDING.md +31 -0
  13. package/ISSUE_GUIDELINES.md +74 -0
  14. package/LICENSE +17 -0
  15. package/LICENSE.it.md +17 -0
  16. package/MPL-2.0.txt +373 -0
  17. package/NOTICE +65 -0
  18. package/README-KIMU.md +40 -0
  19. package/README.it.md +208 -0
  20. package/README.md +266 -0
  21. package/SECURITY.md +64 -0
  22. package/docs/get-started-en.md +207 -0
  23. package/docs/images/icon.svg +64 -0
  24. package/docs/images/logo_kimu.png +0 -0
  25. package/docs/index.md +29 -0
  26. package/env/dev.config.json +6 -0
  27. package/env/local.config.json +6 -0
  28. package/env/prod.config.json +6 -0
  29. package/env/staging.config.json +6 -0
  30. package/env/test.config.json +4 -0
  31. package/icon.svg +10 -0
  32. package/logo_kimu.png +0 -0
  33. package/package.json +79 -0
  34. package/public/favicon.svg +64 -0
  35. package/public/logo_kimu.svg +1 -0
  36. package/scripts/build-all-config.js +59 -0
  37. package/scripts/build-all-core.js +65 -0
  38. package/scripts/build-all-extensions.js +64 -0
  39. package/scripts/build-all-modules.js +99 -0
  40. package/scripts/build-extension.js +60 -0
  41. package/scripts/clear-kimu-build.js +31 -0
  42. package/scripts/generate-kimu-build-config.js +79 -0
  43. package/scripts/install-module.js +162 -0
  44. package/scripts/list-modules.js +109 -0
  45. package/scripts/minify-css-assets.js +82 -0
  46. package/scripts/remove-module.js +122 -0
  47. package/scripts/utils/fix-imports.js +85 -0
  48. package/src/assets/index.css +43 -0
  49. package/src/assets/kimu-style.css +84 -0
  50. package/src/assets/style.css +116 -0
  51. package/src/config/kimu-base-config.json +5 -0
  52. package/src/core/index.ts +47 -0
  53. package/src/core/kimu-app.ts +76 -0
  54. package/src/core/kimu-asset-manager.ts +167 -0
  55. package/src/core/kimu-component-element.ts +325 -0
  56. package/src/core/kimu-component.ts +33 -0
  57. package/src/core/kimu-engine.ts +188 -0
  58. package/src/core/kimu-extension-manager.ts +281 -0
  59. package/src/core/kimu-global-styles.ts +136 -0
  60. package/src/core/kimu-module-manager.ts +69 -0
  61. package/src/core/kimu-module.ts +21 -0
  62. package/src/core/kimu-path-config.ts +127 -0
  63. package/src/core/kimu-reactive.ts +196 -0
  64. package/src/core/kimu-render.ts +91 -0
  65. package/src/core/kimu-store.ts +147 -0
  66. package/src/core/kimu-types.ts +65 -0
  67. package/src/extensions/.gitkeep +0 -0
  68. package/src/extensions/extensions-manifest.json +13 -0
  69. package/src/extensions/kimu-home/component.ts +80 -0
  70. package/src/extensions/kimu-home/lang/en.json +5 -0
  71. package/src/extensions/kimu-home/lang/it.json +5 -0
  72. package/src/extensions/kimu-home/style.css +61 -0
  73. package/src/extensions/kimu-home/view.html +51 -0
  74. package/src/index.html +26 -0
  75. package/src/main.ts +68 -0
  76. package/src/modules/.gitkeep +0 -0
  77. package/src/modules/README.md +79 -0
  78. package/src/modules/i18n/README.it.md +63 -0
  79. package/src/modules/i18n/README.md +63 -0
  80. package/src/modules/i18n/kimu-global-lang.ts +26 -0
  81. package/src/modules/i18n/kimu-i18n-service.ts +108 -0
  82. package/src/modules/i18n/manifest.json +22 -0
  83. package/src/modules/i18n/module.ts +39 -0
  84. package/src/modules/modules-manifest.json +12 -0
  85. package/src/modules-repository/README.md +108 -0
  86. package/src/modules-repository/api-axios/CHANGELOG.md +48 -0
  87. package/src/modules-repository/api-axios/QUICK-REFERENCE.md +178 -0
  88. package/src/modules-repository/api-axios/README.md +304 -0
  89. package/src/modules-repository/api-axios/api-axios-service.ts +355 -0
  90. package/src/modules-repository/api-axios/examples.ts +293 -0
  91. package/src/modules-repository/api-axios/index.ts +19 -0
  92. package/src/modules-repository/api-axios/interfaces.ts +71 -0
  93. package/src/modules-repository/api-axios/module.ts +41 -0
  94. package/src/modules-repository/api-core/CHANGELOG.md +42 -0
  95. package/src/modules-repository/api-core/QUICK-REFERENCE.md +192 -0
  96. package/src/modules-repository/api-core/README.md +435 -0
  97. package/src/modules-repository/api-core/api-core-service.ts +289 -0
  98. package/src/modules-repository/api-core/examples.ts +432 -0
  99. package/src/modules-repository/api-core/index.ts +8 -0
  100. package/src/modules-repository/api-core/interfaces.ts +83 -0
  101. package/src/modules-repository/api-core/module.ts +30 -0
  102. package/src/modules-repository/event-bus/README.md +273 -0
  103. package/src/modules-repository/event-bus/event-bus-service.ts +176 -0
  104. package/src/modules-repository/event-bus/module.ts +30 -0
  105. package/src/modules-repository/i18n/README.it.md +63 -0
  106. package/src/modules-repository/i18n/README.md +63 -0
  107. package/src/modules-repository/i18n/kimu-global-lang.ts +26 -0
  108. package/src/modules-repository/i18n/kimu-i18n-service.ts +108 -0
  109. package/src/modules-repository/i18n/manifest.json +22 -0
  110. package/src/modules-repository/i18n/module.ts +39 -0
  111. package/src/modules-repository/notification/README.md +423 -0
  112. package/src/modules-repository/notification/module.ts +30 -0
  113. package/src/modules-repository/notification/notification-service.ts +436 -0
  114. package/src/modules-repository/router/README.it.md +39 -0
  115. package/src/modules-repository/router/README.md +39 -0
  116. package/src/modules-repository/router/manifest.json +21 -0
  117. package/src/modules-repository/router/module.ts +23 -0
  118. package/src/modules-repository/router/router.ts +144 -0
  119. package/src/modules-repository/state/README.md +409 -0
  120. package/src/modules-repository/state/module.ts +30 -0
  121. package/src/modules-repository/state/state-service.ts +296 -0
  122. package/src/modules-repository/theme/README.md +267 -0
  123. package/src/modules-repository/theme/module.ts +30 -0
  124. package/src/modules-repository/theme/pre-build.js +40 -0
  125. package/src/modules-repository/theme/theme-service.ts +389 -0
  126. package/src/modules-repository/theme/themes/theme-cherry-blossom.css +78 -0
  127. package/src/modules-repository/theme/themes/theme-cozy.css +111 -0
  128. package/src/modules-repository/theme/themes/theme-cyberpunk.css +150 -0
  129. package/src/modules-repository/theme/themes/theme-dark.css +79 -0
  130. package/src/modules-repository/theme/themes/theme-forest.css +171 -0
  131. package/src/modules-repository/theme/themes/theme-gold.css +100 -0
  132. package/src/modules-repository/theme/themes/theme-high-contrast.css +126 -0
  133. package/src/modules-repository/theme/themes/theme-lava.css +101 -0
  134. package/src/modules-repository/theme/themes/theme-lavender.css +90 -0
  135. package/src/modules-repository/theme/themes/theme-light.css +79 -0
  136. package/src/modules-repository/theme/themes/theme-matrix.css +103 -0
  137. package/src/modules-repository/theme/themes/theme-midnight.css +81 -0
  138. package/src/modules-repository/theme/themes/theme-nord.css +94 -0
  139. package/src/modules-repository/theme/themes/theme-ocean.css +84 -0
  140. package/src/modules-repository/theme/themes/theme-retro80s.css +343 -0
  141. package/src/modules-repository/theme/themes/theme-sunset.css +62 -0
  142. package/src/modules-repository/theme/themes-config.d.ts +27 -0
  143. package/src/modules-repository/theme/themes-config.json +213 -0
  144. package/src/vite-env.d.ts +1 -0
  145. package/tsconfig.json +33 -0
  146. package/vite.config.ts +99 -0
@@ -0,0 +1,296 @@
1
+ /**
2
+ * State Management Service for KIMU-Core
3
+ *
4
+ * Provides reactive state management with observers and computed properties.
5
+ * Allows components to share and react to state changes.
6
+ *
7
+ * @module StateService
8
+ * @version 1.0.0
9
+ */
10
+
11
+ export type StateListener<T = any> = (newValue: T, oldValue: T) => void;
12
+ export type ComputedGetter<T = any> = () => T;
13
+
14
+ /**
15
+ * StateService - Reactive state management for KIMU applications
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { stateService } from './modules/state/state-service';
20
+ *
21
+ * // Set initial state
22
+ * stateService.setState('user', { id: 1, name: 'John' });
23
+ *
24
+ * // Watch for changes
25
+ * stateService.watch('user', (newUser, oldUser) => {
26
+ * console.log('User changed:', newUser);
27
+ * });
28
+ *
29
+ * // Update state
30
+ * stateService.setState('user', { id: 1, name: 'Jane' });
31
+ * ```
32
+ */
33
+ export class StateService {
34
+ private state: Map<string, any> = new Map();
35
+ private observers: Map<string, Set<StateListener>> = new Map();
36
+ private computed: Map<string, ComputedGetter> = new Map();
37
+ private computedCache: Map<string, any> = new Map();
38
+ private debugMode: boolean = false;
39
+
40
+ /**
41
+ * Enable or disable debug mode for state logging
42
+ */
43
+ setDebugMode(enabled: boolean): void {
44
+ this.debugMode = enabled;
45
+ }
46
+
47
+ /**
48
+ * Set a state value
49
+ *
50
+ * @param key - State key
51
+ * @param value - New value
52
+ */
53
+ setState<T = any>(key: string, value: T): void {
54
+ const oldValue = this.state.get(key);
55
+
56
+ // Check if value actually changed
57
+ if (oldValue === value || this.deepEqual(oldValue, value)) {
58
+ return;
59
+ }
60
+
61
+ this.state.set(key, value);
62
+
63
+ if (this.debugMode) {
64
+ console.log(`[State] Set: ${key}`, value);
65
+ }
66
+
67
+ // Notify observers
68
+ this.notifyObservers(key, value, oldValue);
69
+
70
+ // Invalidate computed properties that may depend on this key
71
+ this.invalidateComputedCache();
72
+ }
73
+
74
+ /**
75
+ * Get a state value
76
+ *
77
+ * @param key - State key
78
+ * @param defaultValue - Default value if key doesn't exist
79
+ * @returns Current state value
80
+ */
81
+ getState<T = any>(key: string, defaultValue?: T): T | undefined {
82
+ return this.state.has(key) ? this.state.get(key) : defaultValue;
83
+ }
84
+
85
+ /**
86
+ * Update nested state properties
87
+ *
88
+ * @param key - State key
89
+ * @param updates - Partial updates to merge
90
+ */
91
+ updateState<T = any>(key: string, updates: Partial<T>): void {
92
+ const current = this.getState<T>(key) || {} as T;
93
+ const updated = { ...current, ...updates };
94
+ this.setState(key, updated);
95
+ }
96
+
97
+ /**
98
+ * Delete a state key
99
+ *
100
+ * @param key - State key to delete
101
+ */
102
+ deleteState(key: string): void {
103
+ const oldValue = this.state.get(key);
104
+ this.state.delete(key);
105
+
106
+ if (this.debugMode) {
107
+ console.log(`[State] Deleted: ${key}`);
108
+ }
109
+
110
+ // Notify observers with undefined as new value
111
+ this.notifyObservers(key, undefined, oldValue);
112
+ }
113
+
114
+ /**
115
+ * Check if a state key exists
116
+ *
117
+ * @param key - State key
118
+ * @returns True if key exists
119
+ */
120
+ hasState(key: string): boolean {
121
+ return this.state.has(key);
122
+ }
123
+
124
+ /**
125
+ * Watch for state changes
126
+ *
127
+ * @param key - State key to watch
128
+ * @param listener - Callback when state changes
129
+ * @returns Unwatch function
130
+ */
131
+ watch<T = any>(key: string, listener: StateListener<T>): () => void {
132
+ if (!this.observers.has(key)) {
133
+ this.observers.set(key, new Set());
134
+ }
135
+
136
+ this.observers.get(key)!.add(listener);
137
+
138
+ if (this.debugMode) {
139
+ console.log(`[State] Watching: ${key}`);
140
+ }
141
+
142
+ // Return unwatch function
143
+ return () => this.unwatch(key, listener);
144
+ }
145
+
146
+ /**
147
+ * Stop watching a state key
148
+ *
149
+ * @param key - State key
150
+ * @param listener - Listener to remove
151
+ */
152
+ unwatch(key: string, listener: StateListener): void {
153
+ if (this.observers.has(key)) {
154
+ this.observers.get(key)!.delete(listener);
155
+
156
+ if (this.observers.get(key)!.size === 0) {
157
+ this.observers.delete(key);
158
+ }
159
+
160
+ if (this.debugMode) {
161
+ console.log(`[State] Unwatched: ${key}`);
162
+ }
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Define a computed property
168
+ *
169
+ * @param key - Computed property key
170
+ * @param getter - Function that computes the value
171
+ */
172
+ defineComputed<T = any>(key: string, getter: ComputedGetter<T>): void {
173
+ this.computed.set(key, getter);
174
+ this.computedCache.delete(key); // Invalidate cache
175
+
176
+ if (this.debugMode) {
177
+ console.log(`[State] Computed defined: ${key}`);
178
+ }
179
+ }
180
+
181
+ /**
182
+ * Get a computed property value (cached)
183
+ *
184
+ * @param key - Computed property key
185
+ * @returns Computed value
186
+ */
187
+ getComputed<T = any>(key: string): T | undefined {
188
+ if (!this.computed.has(key)) {
189
+ return undefined;
190
+ }
191
+
192
+ // Return cached value if available
193
+ if (this.computedCache.has(key)) {
194
+ return this.computedCache.get(key);
195
+ }
196
+
197
+ // Compute and cache
198
+ const getter = this.computed.get(key)!;
199
+ const value = getter();
200
+ this.computedCache.set(key, value);
201
+
202
+ if (this.debugMode) {
203
+ console.log(`[State] Computed: ${key}`, value);
204
+ }
205
+
206
+ return value;
207
+ }
208
+
209
+ /**
210
+ * Get all state as a plain object
211
+ */
212
+ getAll(): Record<string, any> {
213
+ return Object.fromEntries(this.state.entries());
214
+ }
215
+
216
+ /**
217
+ * Clear all state
218
+ */
219
+ clear(): void {
220
+ this.state.clear();
221
+ this.observers.clear();
222
+ this.computed.clear();
223
+ this.computedCache.clear();
224
+
225
+ if (this.debugMode) {
226
+ console.log('[State] Cleared all state');
227
+ }
228
+ }
229
+
230
+ /**
231
+ * Reset state to initial values
232
+ *
233
+ * @param initialState - Initial state object
234
+ */
235
+ reset(initialState: Record<string, any> = {}): void {
236
+ this.clear();
237
+ Object.entries(initialState).forEach(([key, value]) => {
238
+ this.setState(key, value);
239
+ });
240
+ }
241
+
242
+ /**
243
+ * Subscribe to multiple state keys
244
+ *
245
+ * @param keys - Array of state keys
246
+ * @param listener - Callback when any key changes
247
+ * @returns Unsubscribe function
248
+ */
249
+ watchMultiple(keys: string[], listener: (key: string, newValue: any, oldValue: any) => void): () => void {
250
+ const unwatchers = keys.map(key =>
251
+ this.watch(key, (newValue, oldValue) => listener(key, newValue, oldValue))
252
+ );
253
+
254
+ return () => unwatchers.forEach(unwatch => unwatch());
255
+ }
256
+
257
+ // Private helpers
258
+
259
+ private notifyObservers(key: string, newValue: any, oldValue: any): void {
260
+ if (this.observers.has(key)) {
261
+ const listeners = Array.from(this.observers.get(key)!);
262
+ listeners.forEach(listener => {
263
+ try {
264
+ listener(newValue, oldValue);
265
+ } catch (error) {
266
+ console.error(`[State] Error in observer for "${key}":`, error);
267
+ }
268
+ });
269
+ }
270
+ }
271
+
272
+ private invalidateComputedCache(): void {
273
+ this.computedCache.clear();
274
+ }
275
+
276
+ private deepEqual(a: any, b: any): boolean {
277
+ if (a === b) return true;
278
+ if (a == null || b == null) return false;
279
+ if (typeof a !== 'object' || typeof b !== 'object') return false;
280
+
281
+ const keysA = Object.keys(a);
282
+ const keysB = Object.keys(b);
283
+
284
+ if (keysA.length !== keysB.length) return false;
285
+
286
+ for (const key of keysA) {
287
+ if (!keysB.includes(key)) return false;
288
+ if (!this.deepEqual(a[key], b[key])) return false;
289
+ }
290
+
291
+ return true;
292
+ }
293
+ }
294
+
295
+ // Export singleton instance
296
+ export const stateService = new StateService();
@@ -0,0 +1,267 @@
1
+ # Theme Module - CSS-Based Theme Management
2
+
3
+ ## Overview
4
+
5
+ The **Theme Module** provides a complete CSS-based theme management system for KIMU-Core applications. It supports multiple predefined themes (Light, Dark, Ocean, Cozy) and allows easy registration of custom themes through external CSS files.
6
+
7
+ ## Architecture
8
+
9
+ The theme module uses **KIMU Global Styles** system to inject theme CSS into all extensions automatically:
10
+
11
+ 1. **KimuGlobalStyles** (core): Manages CSS files that should be injected in all extensions
12
+ 2. **ThemeService**: Registers the active theme CSS as a global style
13
+ 3. **KimuComponentElement**: Automatically injects all global styles into each extension's shadow root
14
+ 4. **themes-config.json**: Configuration file with all available themes
15
+
16
+ This architecture ensures:
17
+ - ✅ Theme module is **optional** - framework works without it (fallback styles in `style.css`)
18
+ - ✅ Themes are automatically applied to **all extensions** (including shadow DOM)
19
+ - ✅ Theme changes propagate to **existing extensions** dynamically
20
+ - ✅ **No hardcoded dependencies** in core framework
21
+ - ✅ **Easy theme management** via JSON configuration file
22
+
23
+ ## Module Structure
24
+
25
+ ```
26
+ src/modules/theme/
27
+ ├── themes/ # Theme source CSS files
28
+ │ ├── theme-light.css
29
+ │ ├── theme-dark.css
30
+ │ ├── theme-ocean.css
31
+ │ ├── theme-cozy.css
32
+ │ ├── theme-nord.css
33
+ │ ├── theme-forest.css
34
+ │ ├── theme-high-contrast.css
35
+ │ └── theme-cyberpunk.css
36
+ ├── themes-config.json # Theme configuration
37
+ ├── pre-build.js # Pre-build script (copies themes to public/)
38
+ ├── theme-service.ts # Main service
39
+ └── README.md # This file
40
+ ```
41
+
42
+ **Build Process**: The pre-build script automatically copies all CSS files from `themes/` to `public/themes/` before compilation.
43
+
44
+ ## Features
45
+
46
+ - 🎨 **CSS-Based Themes**: Each theme is a separate CSS file for maximum flexibility
47
+ - ☀️ **Light Mode**: Clean and bright theme for daytime use
48
+ - 🌙 **Dark Mode**: Dark theme for low-light environments
49
+ - 🌊 **Ocean Theme**: Ocean-inspired dark theme with blue-green tones
50
+ - 🌸 **Cozy Theme**: Warm, feminine and cozy theme with soft colors
51
+ - ❄️ **Nord Theme**: Cold and relaxing Nordic theme for developers
52
+ - 🌲 **Forest Theme**: Natural green theme inspired by nature
53
+ - ⚡ **High Contrast Theme**: WCAG AAA accessible theme
54
+ - 🎮 **Cyberpunk Theme**: Futuristic neon aesthetic
55
+ - 🔄 **Auto Mode**: Automatically follows system color scheme preferences
56
+ - 💾 **Persistence**: User preferences saved in localStorage
57
+ - 🎯 **System Integration**: MediaQuery API for system preference detection
58
+ - 🔌 **Extensible**: Easy registration of custom CSS themes
59
+ - 🌐 **Global Styles**: Themes automatically injected in all extensions via Global Styles system
60
+
61
+ ## Quick Start
62
+
63
+ ### Basic Usage
64
+
65
+ \`\`\`typescript
66
+ import { themeService } from './modules/theme/theme-service';
67
+
68
+ // Set theme
69
+ themeService.setMode('dark'); // Switch to dark theme
70
+ themeService.setMode('light'); // Switch to light theme
71
+ themeService.setMode('ocean'); // Switch to ocean theme
72
+ themeService.setMode('cozy'); // Switch to cozy theme
73
+ themeService.setMode('auto'); // Use system preference
74
+
75
+ // Quick toggle
76
+ themeService.toggle(); // Toggle between light/dark
77
+
78
+ // Get current theme
79
+ const mode = themeService.getMode();
80
+ const themeName = themeService.getCurrentThemeName();
81
+ \`\`\`
82
+
83
+ ### Listen to Theme Changes
84
+
85
+ \`\`\`typescript
86
+ themeService.onChange((themeName: string, mode: string) => {
87
+ console.log(\`Theme changed to: \${themeName}\`);
88
+ });
89
+ \`\`\`
90
+
91
+ ## Available Themes
92
+
93
+ ### 1. Light Theme
94
+ Clean and bright theme optimized for daytime use.
95
+
96
+ ### 2. Dark Theme
97
+ Dark theme for low-light environments and reduced eye strain.
98
+
99
+ ### 3. Ocean Theme
100
+ Ocean-inspired dark theme with blue-green tones.
101
+
102
+ ### 4. Cozy Theme
103
+ Warm, feminine and cozy theme with soft pastel colors.
104
+
105
+ ## Creating Custom Themes
106
+
107
+ ### Step 1: Create CSS File
108
+
109
+ \`\`\`css
110
+ /* my-custom-theme.css */
111
+ :root {
112
+ --kimu-primary: #your-color;
113
+ --kimu-background: #your-background;
114
+ --kimu-text-primary: #your-text-color;
115
+ /* ...other variables... */
116
+ }
117
+ \`\`\`
118
+
119
+ ### Step 2: Register the Theme
120
+
121
+ \`\`\`typescript
122
+ themeService.registerCssTheme({
123
+ name: 'my-theme',
124
+ mode: 'dark',
125
+ cssPath: '/themes/my-custom-theme.css',
126
+ description: 'My awesome custom theme'
127
+ });
128
+ \`\`\`
129
+
130
+ ### Step 3: Apply the Theme
131
+
132
+ \`\`\`typescript
133
+ themeService.setMode('my-theme');
134
+ \`\`\`
135
+
136
+ ## Using CSS Variables
137
+
138
+ \`\`\`css
139
+ .my-component {
140
+ background: var(--kimu-background);
141
+ color: var(--kimu-text-primary);
142
+ border: 1px solid var(--kimu-border);
143
+ }
144
+
145
+ .my-button {
146
+ background: var(--kimu-primary);
147
+ color: white;
148
+ }
149
+ \`\`\`
150
+
151
+ ## Module Independence & Fallback System
152
+
153
+ ### How It Works
154
+
155
+ The theme system is designed to work as an **optional module**:
156
+
157
+ 1. **Without Theme Module**:
158
+ - Default CSS variables are defined in `src/assets/style.css`
159
+ - Application has basic Light theme styling
160
+ - All components work normally with default colors
161
+
162
+ 2. **With Theme Module**:
163
+ - Theme CSS files **override** default values from `style.css`
164
+ - Dynamic theme switching available
165
+ - User preferences persist across sessions
166
+
167
+ ### Architecture
168
+
169
+ \`\`\`
170
+ ┌─────────────────────────────────────────────┐
171
+ │ style.css (ALWAYS loaded) │
172
+ │ :root { --kimu-primary: #667eea; } │ ← DEFAULT values
173
+ └─────────────────────────────────────────────┘
174
+
175
+ ┌─────────────────────────────────────────────┐
176
+ │ theme-dark.css (OPTIONAL, loaded by module)│
177
+ │ :root { --kimu-primary: #818cf8; } │ ← OVERRIDES defaults
178
+ └─────────────────────────────────────────────┘
179
+
180
+ ┌─────────────────────────────────────────────┐
181
+ │ Components use variables │
182
+ │ button { background: var(--kimu-primary); }│ ← Uses active value
183
+ └─────────────────────────────────────────────┘
184
+ \`\`\`
185
+
186
+ ### Benefits
187
+
188
+ ✅ **App works without theme module** - defaults provide basic styling
189
+ ✅ **No breaking changes** - removing theme module doesn't break the app
190
+ ✅ **Gradual adoption** - themes can be added later
191
+ ✅ **Consistent API** - components always use same CSS variables
192
+
193
+ ### CSS Variable Priority
194
+
195
+ When theme module is active:
196
+ \`\`\`
197
+ Theme CSS values > Default style.css values > Browser defaults
198
+ \`\`\`
199
+
200
+ When theme module is NOT installed:
201
+ \`\`\`
202
+ Default style.css values > Browser defaults
203
+ \`\`\`
204
+
205
+ ## Theme Configuration File
206
+
207
+ ### Structure
208
+
209
+ The theme module uses a JSON configuration file (`themes-config.json`) to define available themes:
210
+
211
+ ```json
212
+ {
213
+ "themes": [
214
+ {
215
+ "name": "light",
216
+ "mode": "light",
217
+ "cssPath": "theme-light.css",
218
+ "description": "Clean and bright theme"
219
+ },
220
+ {
221
+ "name": "dark",
222
+ "mode": "dark",
223
+ "cssPath": "theme-dark.css",
224
+ "description": "Dark theme for low-light environments"
225
+ }
226
+ ],
227
+ "defaultTheme": "light"
228
+ }
229
+ ```
230
+
231
+ ### Adding New Themes
232
+
233
+ To add a new theme, simply:
234
+
235
+ 1. Create the CSS file in `src/modules/theme/themes/` (e.g., `theme-nord.css`)
236
+ 2. Add entry to `src/modules/theme/themes-config.json`:
237
+
238
+ ```json
239
+ {
240
+ "name": "nord",
241
+ "mode": "dark",
242
+ "cssPath": "theme-nord.css",
243
+ "description": "Cold and relaxing Nordic theme"
244
+ }
245
+ ```
246
+
247
+ 3. Run `npm run build` to copy themes to `public/themes/` (via pre-build script)
248
+ 4. The pre-build script automatically copies all CSS files from `src/modules/theme/themes/` to `public/themes/`
249
+
250
+ **Benefits of configuration file:**
251
+ - ✅ No code changes needed to add themes
252
+ - ✅ Easy to maintain and extend
253
+ - ✅ Clear separation of configuration and logic
254
+ - ✅ Can be easily customized per deployment
255
+
256
+ ### Theme Configuration Properties
257
+
258
+ | Property | Type | Required | Description |
259
+ |----------|------|----------|-------------|
260
+ | `name` | string | ✅ | Unique theme identifier (used in `setMode()`) |
261
+ | `mode` | 'light' \| 'dark' | ✅ | Base mode for system preference detection |
262
+ | `cssPath` | string | ✅ | CSS file name in `public/themes/` folder |
263
+ | `description` | string | ❌ | Human-readable theme description |
264
+
265
+ ## License
266
+
267
+ This module is part of KIMU-Core and is licensed under the Mozilla Public License 2.0 (MPL-2.0).
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Theme Module for KIMU-Core
3
+ *
4
+ * Provides centralized theme management with dark/light/auto modes.
5
+ *
6
+ * @module ThemeModule
7
+ */
8
+
9
+ import { KimuModule } from '../../core/kimu-module';
10
+ import { themeService } from './theme-service'
11
+ /**
12
+ * ThemeModule - Module class for theme management integration
13
+ */
14
+ export default class ThemeModule extends KimuModule {
15
+ constructor(name = 'theme', version = '1.0.0', options?: any) {
16
+ super(name, version, options);
17
+ }
18
+
19
+ /**
20
+ * Get the theme service instance
21
+ */
22
+ getService() {
23
+ return themeService;
24
+ }
25
+ }
26
+
27
+ // Re-export for convenience
28
+ export { themeService } from './theme-service';
29
+ export { ThemeService } from './theme-service';
30
+ export type { ThemeMode, CssTheme } from './theme-service';
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Pre-Build Script for Theme Module
3
+ *
4
+ * This script runs BEFORE the theme module is compiled.
5
+ * It copies CSS theme files to public/themes/ so they're available
6
+ * during development and will be included in the Vite build.
7
+ *
8
+ * This approach keeps the module self-contained and independent.
9
+ */
10
+ import fs from 'fs';
11
+ import path from 'path';
12
+
13
+ export default async function preBuild({ moduleDir, rootDir }) {
14
+ const themesDir = path.join(moduleDir, 'themes');
15
+
16
+ if (!fs.existsSync(themesDir)) {
17
+ console.log('⚠️ No themes directory found, skipping theme copy');
18
+ return;
19
+ }
20
+
21
+ const cssFiles = fs.readdirSync(themesDir).filter(f => f.endsWith('.css'));
22
+
23
+ if (cssFiles.length === 0) {
24
+ console.log('⚠️ No CSS files found in themes directory');
25
+ return;
26
+ }
27
+
28
+ // Copy to public/themes/ (Vite will include them in build automatically)
29
+ const publicThemesDir = path.join(rootDir, 'public', 'themes');
30
+ fs.mkdirSync(publicThemesDir, { recursive: true });
31
+
32
+ for (const cssFile of cssFiles) {
33
+ fs.copyFileSync(
34
+ path.join(themesDir, cssFile),
35
+ path.join(publicThemesDir, cssFile)
36
+ );
37
+ }
38
+
39
+ console.log(`📄 Theme module: Copied ${cssFiles.length} CSS files to public/themes/`);
40
+ }