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.
- package/.editorconfig +30 -0
- package/.gitattributes +11 -0
- package/.github/FUNDING.yml +8 -0
- package/.github/copilot-instructions.md +103 -0
- package/.github/kimu-copilot-instructions.md +3779 -0
- package/.github/workflows/deploy-demo.yml +39 -0
- package/AUTHORS.md +20 -0
- package/CHANGELOG.md +20 -0
- package/CODE_GUIDELINES.md +165 -0
- package/CODE_OF_CONDUCT.md +47 -0
- package/CONTRIBUTING.md +62 -0
- package/FUNDING.md +31 -0
- package/ISSUE_GUIDELINES.md +74 -0
- package/LICENSE +17 -0
- package/LICENSE.it.md +17 -0
- package/MPL-2.0.txt +373 -0
- package/NOTICE +65 -0
- package/README-KIMU.md +40 -0
- package/README.it.md +208 -0
- package/README.md +266 -0
- package/SECURITY.md +64 -0
- package/docs/get-started-en.md +207 -0
- package/docs/images/icon.svg +64 -0
- package/docs/images/logo_kimu.png +0 -0
- package/docs/index.md +29 -0
- package/env/dev.config.json +6 -0
- package/env/local.config.json +6 -0
- package/env/prod.config.json +6 -0
- package/env/staging.config.json +6 -0
- package/env/test.config.json +4 -0
- package/icon.svg +10 -0
- package/logo_kimu.png +0 -0
- package/package.json +79 -0
- package/public/favicon.svg +64 -0
- package/public/logo_kimu.svg +1 -0
- package/scripts/build-all-config.js +59 -0
- package/scripts/build-all-core.js +65 -0
- package/scripts/build-all-extensions.js +64 -0
- package/scripts/build-all-modules.js +99 -0
- package/scripts/build-extension.js +60 -0
- package/scripts/clear-kimu-build.js +31 -0
- package/scripts/generate-kimu-build-config.js +79 -0
- package/scripts/install-module.js +162 -0
- package/scripts/list-modules.js +109 -0
- package/scripts/minify-css-assets.js +82 -0
- package/scripts/remove-module.js +122 -0
- package/scripts/utils/fix-imports.js +85 -0
- package/src/assets/index.css +43 -0
- package/src/assets/kimu-style.css +84 -0
- package/src/assets/style.css +116 -0
- package/src/config/kimu-base-config.json +5 -0
- package/src/core/index.ts +47 -0
- package/src/core/kimu-app.ts +76 -0
- package/src/core/kimu-asset-manager.ts +167 -0
- package/src/core/kimu-component-element.ts +325 -0
- package/src/core/kimu-component.ts +33 -0
- package/src/core/kimu-engine.ts +188 -0
- package/src/core/kimu-extension-manager.ts +281 -0
- package/src/core/kimu-global-styles.ts +136 -0
- package/src/core/kimu-module-manager.ts +69 -0
- package/src/core/kimu-module.ts +21 -0
- package/src/core/kimu-path-config.ts +127 -0
- package/src/core/kimu-reactive.ts +196 -0
- package/src/core/kimu-render.ts +91 -0
- package/src/core/kimu-store.ts +147 -0
- package/src/core/kimu-types.ts +65 -0
- package/src/extensions/.gitkeep +0 -0
- package/src/extensions/extensions-manifest.json +13 -0
- package/src/extensions/kimu-home/component.ts +80 -0
- package/src/extensions/kimu-home/lang/en.json +5 -0
- package/src/extensions/kimu-home/lang/it.json +5 -0
- package/src/extensions/kimu-home/style.css +61 -0
- package/src/extensions/kimu-home/view.html +51 -0
- package/src/index.html +26 -0
- package/src/main.ts +68 -0
- package/src/modules/.gitkeep +0 -0
- package/src/modules/README.md +79 -0
- package/src/modules/i18n/README.it.md +63 -0
- package/src/modules/i18n/README.md +63 -0
- package/src/modules/i18n/kimu-global-lang.ts +26 -0
- package/src/modules/i18n/kimu-i18n-service.ts +108 -0
- package/src/modules/i18n/manifest.json +22 -0
- package/src/modules/i18n/module.ts +39 -0
- package/src/modules/modules-manifest.json +12 -0
- package/src/modules-repository/README.md +108 -0
- package/src/modules-repository/api-axios/CHANGELOG.md +48 -0
- package/src/modules-repository/api-axios/QUICK-REFERENCE.md +178 -0
- package/src/modules-repository/api-axios/README.md +304 -0
- package/src/modules-repository/api-axios/api-axios-service.ts +355 -0
- package/src/modules-repository/api-axios/examples.ts +293 -0
- package/src/modules-repository/api-axios/index.ts +19 -0
- package/src/modules-repository/api-axios/interfaces.ts +71 -0
- package/src/modules-repository/api-axios/module.ts +41 -0
- package/src/modules-repository/api-core/CHANGELOG.md +42 -0
- package/src/modules-repository/api-core/QUICK-REFERENCE.md +192 -0
- package/src/modules-repository/api-core/README.md +435 -0
- package/src/modules-repository/api-core/api-core-service.ts +289 -0
- package/src/modules-repository/api-core/examples.ts +432 -0
- package/src/modules-repository/api-core/index.ts +8 -0
- package/src/modules-repository/api-core/interfaces.ts +83 -0
- package/src/modules-repository/api-core/module.ts +30 -0
- package/src/modules-repository/event-bus/README.md +273 -0
- package/src/modules-repository/event-bus/event-bus-service.ts +176 -0
- package/src/modules-repository/event-bus/module.ts +30 -0
- package/src/modules-repository/i18n/README.it.md +63 -0
- package/src/modules-repository/i18n/README.md +63 -0
- package/src/modules-repository/i18n/kimu-global-lang.ts +26 -0
- package/src/modules-repository/i18n/kimu-i18n-service.ts +108 -0
- package/src/modules-repository/i18n/manifest.json +22 -0
- package/src/modules-repository/i18n/module.ts +39 -0
- package/src/modules-repository/notification/README.md +423 -0
- package/src/modules-repository/notification/module.ts +30 -0
- package/src/modules-repository/notification/notification-service.ts +436 -0
- package/src/modules-repository/router/README.it.md +39 -0
- package/src/modules-repository/router/README.md +39 -0
- package/src/modules-repository/router/manifest.json +21 -0
- package/src/modules-repository/router/module.ts +23 -0
- package/src/modules-repository/router/router.ts +144 -0
- package/src/modules-repository/state/README.md +409 -0
- package/src/modules-repository/state/module.ts +30 -0
- package/src/modules-repository/state/state-service.ts +296 -0
- package/src/modules-repository/theme/README.md +267 -0
- package/src/modules-repository/theme/module.ts +30 -0
- package/src/modules-repository/theme/pre-build.js +40 -0
- package/src/modules-repository/theme/theme-service.ts +389 -0
- package/src/modules-repository/theme/themes/theme-cherry-blossom.css +78 -0
- package/src/modules-repository/theme/themes/theme-cozy.css +111 -0
- package/src/modules-repository/theme/themes/theme-cyberpunk.css +150 -0
- package/src/modules-repository/theme/themes/theme-dark.css +79 -0
- package/src/modules-repository/theme/themes/theme-forest.css +171 -0
- package/src/modules-repository/theme/themes/theme-gold.css +100 -0
- package/src/modules-repository/theme/themes/theme-high-contrast.css +126 -0
- package/src/modules-repository/theme/themes/theme-lava.css +101 -0
- package/src/modules-repository/theme/themes/theme-lavender.css +90 -0
- package/src/modules-repository/theme/themes/theme-light.css +79 -0
- package/src/modules-repository/theme/themes/theme-matrix.css +103 -0
- package/src/modules-repository/theme/themes/theme-midnight.css +81 -0
- package/src/modules-repository/theme/themes/theme-nord.css +94 -0
- package/src/modules-repository/theme/themes/theme-ocean.css +84 -0
- package/src/modules-repository/theme/themes/theme-retro80s.css +343 -0
- package/src/modules-repository/theme/themes/theme-sunset.css +62 -0
- package/src/modules-repository/theme/themes-config.d.ts +27 -0
- package/src/modules-repository/theme/themes-config.json +213 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +33 -0
- package/vite.config.ts +99 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification Service for KIMU-Core
|
|
3
|
+
*
|
|
4
|
+
* Provides toast notifications, alerts, and user feedback system.
|
|
5
|
+
* Supports different notification types, durations, and positions.
|
|
6
|
+
*
|
|
7
|
+
* @module NotificationService
|
|
8
|
+
* @version 1.0.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export type NotificationType = 'success' | 'error' | 'warning' | 'info';
|
|
12
|
+
export type NotificationPosition = 'top-right' | 'top-left' | 'bottom-right' | 'bottom-left' | 'top-center' | 'bottom-center';
|
|
13
|
+
|
|
14
|
+
export interface NotificationOptions {
|
|
15
|
+
type?: NotificationType;
|
|
16
|
+
duration?: number; // in milliseconds, 0 = no auto-dismiss
|
|
17
|
+
position?: NotificationPosition;
|
|
18
|
+
dismissible?: boolean;
|
|
19
|
+
icon?: string;
|
|
20
|
+
onClick?: () => void;
|
|
21
|
+
onClose?: () => void;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface Notification {
|
|
25
|
+
id: string;
|
|
26
|
+
message: string;
|
|
27
|
+
type: NotificationType;
|
|
28
|
+
duration: number;
|
|
29
|
+
position: NotificationPosition;
|
|
30
|
+
dismissible: boolean;
|
|
31
|
+
icon?: string;
|
|
32
|
+
timestamp: number;
|
|
33
|
+
element?: HTMLElement;
|
|
34
|
+
timeoutId?: number;
|
|
35
|
+
onClick?: () => void;
|
|
36
|
+
onClose?: () => void;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* NotificationService - Toast notifications and alerts
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* import { notificationService } from './modules/notification/notification-service';
|
|
45
|
+
*
|
|
46
|
+
* // Show success notification
|
|
47
|
+
* notificationService.success('Operation completed!');
|
|
48
|
+
*
|
|
49
|
+
* // Show error with custom duration
|
|
50
|
+
* notificationService.error('Something went wrong!', { duration: 5000 });
|
|
51
|
+
*
|
|
52
|
+
* // Show info with custom position
|
|
53
|
+
* notificationService.info('New message received', { position: 'bottom-right' });
|
|
54
|
+
* ```
|
|
55
|
+
*/
|
|
56
|
+
export class NotificationService {
|
|
57
|
+
private notifications: Map<string, Notification> = new Map();
|
|
58
|
+
private container?: HTMLElement;
|
|
59
|
+
private defaultDuration: number = 3000;
|
|
60
|
+
private defaultPosition: NotificationPosition = 'top-right';
|
|
61
|
+
private maxNotifications: number = 5;
|
|
62
|
+
private debugMode: boolean = false;
|
|
63
|
+
|
|
64
|
+
constructor() {
|
|
65
|
+
this.initContainer();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Enable or disable debug mode
|
|
70
|
+
*/
|
|
71
|
+
setDebugMode(enabled: boolean): void {
|
|
72
|
+
this.debugMode = enabled;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Set default notification duration
|
|
77
|
+
*/
|
|
78
|
+
setDefaultDuration(duration: number): void {
|
|
79
|
+
this.defaultDuration = duration;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Set default notification position
|
|
84
|
+
*/
|
|
85
|
+
setDefaultPosition(position: NotificationPosition): void {
|
|
86
|
+
this.defaultPosition = position;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Set maximum number of visible notifications
|
|
91
|
+
*/
|
|
92
|
+
setMaxNotifications(max: number): void {
|
|
93
|
+
this.maxNotifications = max;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Show a success notification
|
|
98
|
+
*/
|
|
99
|
+
success(message: string, options?: NotificationOptions): string {
|
|
100
|
+
return this.show(message, { ...options, type: 'success' });
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Show an error notification
|
|
105
|
+
*/
|
|
106
|
+
error(message: string, options?: NotificationOptions): string {
|
|
107
|
+
return this.show(message, { ...options, type: 'error' });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Show a warning notification
|
|
112
|
+
*/
|
|
113
|
+
warning(message: string, options?: NotificationOptions): string {
|
|
114
|
+
return this.show(message, { ...options, type: 'warning' });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Show an info notification
|
|
119
|
+
*/
|
|
120
|
+
info(message: string, options?: NotificationOptions): string {
|
|
121
|
+
return this.show(message, { ...options, type: 'info' });
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Show a notification with custom options
|
|
126
|
+
*/
|
|
127
|
+
show(message: string, options: NotificationOptions = {}): string {
|
|
128
|
+
const id = this.generateId();
|
|
129
|
+
|
|
130
|
+
const notification: Notification = {
|
|
131
|
+
id,
|
|
132
|
+
message,
|
|
133
|
+
type: options.type || 'info',
|
|
134
|
+
duration: options.duration !== undefined ? options.duration : this.defaultDuration,
|
|
135
|
+
position: options.position || this.defaultPosition,
|
|
136
|
+
dismissible: options.dismissible !== undefined ? options.dismissible : true,
|
|
137
|
+
icon: options.icon || this.getDefaultIcon(options.type || 'info'),
|
|
138
|
+
timestamp: Date.now(),
|
|
139
|
+
onClick: options.onClick,
|
|
140
|
+
onClose: options.onClose
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
if (this.debugMode) {
|
|
144
|
+
console.log('[Notification] Show:', notification);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Remove oldest notification if max limit reached
|
|
148
|
+
if (this.notifications.size >= this.maxNotifications) {
|
|
149
|
+
const oldestId = Array.from(this.notifications.keys())[0];
|
|
150
|
+
this.dismiss(oldestId);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
this.notifications.set(id, notification);
|
|
154
|
+
this.renderNotification(notification);
|
|
155
|
+
|
|
156
|
+
// Auto-dismiss if duration > 0
|
|
157
|
+
if (notification.duration > 0) {
|
|
158
|
+
notification.timeoutId = window.setTimeout(() => {
|
|
159
|
+
this.dismiss(id);
|
|
160
|
+
}, notification.duration);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return id;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Dismiss a specific notification
|
|
168
|
+
*/
|
|
169
|
+
dismiss(id: string): void {
|
|
170
|
+
const notification = this.notifications.get(id);
|
|
171
|
+
if (!notification) return;
|
|
172
|
+
|
|
173
|
+
if (this.debugMode) {
|
|
174
|
+
console.log('[Notification] Dismiss:', id);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Clear timeout
|
|
178
|
+
if (notification.timeoutId) {
|
|
179
|
+
clearTimeout(notification.timeoutId);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Remove element with animation
|
|
183
|
+
if (notification.element) {
|
|
184
|
+
notification.element.classList.add('kimu-notification-exit');
|
|
185
|
+
setTimeout(() => {
|
|
186
|
+
notification.element?.remove();
|
|
187
|
+
}, 300);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Call onClose callback
|
|
191
|
+
if (notification.onClose) {
|
|
192
|
+
notification.onClose();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
this.notifications.delete(id);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Dismiss all notifications
|
|
200
|
+
*/
|
|
201
|
+
dismissAll(): void {
|
|
202
|
+
const ids = Array.from(this.notifications.keys());
|
|
203
|
+
ids.forEach(id => this.dismiss(id));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Get all active notifications
|
|
208
|
+
*/
|
|
209
|
+
getAll(): Notification[] {
|
|
210
|
+
return Array.from(this.notifications.values());
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Get notification count
|
|
215
|
+
*/
|
|
216
|
+
getCount(): number {
|
|
217
|
+
return this.notifications.size;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Private methods
|
|
221
|
+
|
|
222
|
+
private initContainer(): void {
|
|
223
|
+
if (typeof document === 'undefined') return;
|
|
224
|
+
|
|
225
|
+
this.container = document.createElement('div');
|
|
226
|
+
this.container.id = 'kimu-notification-container';
|
|
227
|
+
this.injectStyles();
|
|
228
|
+
document.body.appendChild(this.container);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private renderNotification(notification: Notification): void {
|
|
232
|
+
if (!this.container) return;
|
|
233
|
+
|
|
234
|
+
const element = document.createElement('div');
|
|
235
|
+
element.className = `kimu-notification kimu-notification-${notification.type} kimu-notification-${notification.position}`;
|
|
236
|
+
element.setAttribute('data-id', notification.id);
|
|
237
|
+
|
|
238
|
+
const content = `
|
|
239
|
+
<div class="kimu-notification-content">
|
|
240
|
+
${notification.icon ? `<span class="kimu-notification-icon">${notification.icon}</span>` : ''}
|
|
241
|
+
<span class="kimu-notification-message">${this.escapeHtml(notification.message)}</span>
|
|
242
|
+
</div>
|
|
243
|
+
${notification.dismissible ? '<button class="kimu-notification-close" aria-label="Close">×</button>' : ''}
|
|
244
|
+
`;
|
|
245
|
+
|
|
246
|
+
element.innerHTML = content;
|
|
247
|
+
|
|
248
|
+
// Add click handlers
|
|
249
|
+
if (notification.onClick) {
|
|
250
|
+
element.addEventListener('click', (e) => {
|
|
251
|
+
if (!(e.target as HTMLElement).classList.contains('kimu-notification-close')) {
|
|
252
|
+
notification.onClick!();
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (notification.dismissible) {
|
|
258
|
+
const closeBtn = element.querySelector('.kimu-notification-close');
|
|
259
|
+
closeBtn?.addEventListener('click', (e) => {
|
|
260
|
+
e.stopPropagation();
|
|
261
|
+
this.dismiss(notification.id);
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
notification.element = element;
|
|
266
|
+
this.container.appendChild(element);
|
|
267
|
+
|
|
268
|
+
// Trigger animation
|
|
269
|
+
setTimeout(() => element.classList.add('kimu-notification-enter'), 10);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
private generateId(): string {
|
|
273
|
+
return `notification-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
private getDefaultIcon(type: NotificationType): string {
|
|
277
|
+
const icons = {
|
|
278
|
+
success: '✅',
|
|
279
|
+
error: '❌',
|
|
280
|
+
warning: '⚠️',
|
|
281
|
+
info: 'ℹ️'
|
|
282
|
+
};
|
|
283
|
+
return icons[type];
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
private escapeHtml(text: string): string {
|
|
287
|
+
const div = document.createElement('div');
|
|
288
|
+
div.textContent = text;
|
|
289
|
+
return div.innerHTML;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
private injectStyles(): void {
|
|
293
|
+
if (typeof document === 'undefined') return;
|
|
294
|
+
if (document.getElementById('kimu-notification-styles')) return;
|
|
295
|
+
|
|
296
|
+
const style = document.createElement('style');
|
|
297
|
+
style.id = 'kimu-notification-styles';
|
|
298
|
+
style.textContent = `
|
|
299
|
+
#kimu-notification-container {
|
|
300
|
+
position: fixed;
|
|
301
|
+
z-index: 9999;
|
|
302
|
+
pointer-events: none;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.kimu-notification {
|
|
306
|
+
position: fixed;
|
|
307
|
+
min-width: 280px;
|
|
308
|
+
max-width: 400px;
|
|
309
|
+
padding: 16px 20px;
|
|
310
|
+
margin: 12px;
|
|
311
|
+
background: white;
|
|
312
|
+
border-radius: 8px;
|
|
313
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
314
|
+
display: flex;
|
|
315
|
+
align-items: center;
|
|
316
|
+
justify-content: space-between;
|
|
317
|
+
opacity: 0;
|
|
318
|
+
transform: translateY(-20px);
|
|
319
|
+
transition: all 0.3s ease;
|
|
320
|
+
pointer-events: auto;
|
|
321
|
+
cursor: default;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.kimu-notification-enter {
|
|
325
|
+
opacity: 1;
|
|
326
|
+
transform: translateY(0);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.kimu-notification-exit {
|
|
330
|
+
opacity: 0;
|
|
331
|
+
transform: translateY(-20px);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
.kimu-notification-content {
|
|
335
|
+
display: flex;
|
|
336
|
+
align-items: center;
|
|
337
|
+
gap: 12px;
|
|
338
|
+
flex: 1;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.kimu-notification-icon {
|
|
342
|
+
font-size: 20px;
|
|
343
|
+
line-height: 1;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.kimu-notification-message {
|
|
347
|
+
color: #333;
|
|
348
|
+
font-size: 14px;
|
|
349
|
+
line-height: 1.5;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.kimu-notification-close {
|
|
353
|
+
background: none;
|
|
354
|
+
border: none;
|
|
355
|
+
font-size: 24px;
|
|
356
|
+
line-height: 1;
|
|
357
|
+
color: #999;
|
|
358
|
+
cursor: pointer;
|
|
359
|
+
padding: 0;
|
|
360
|
+
margin-left: 12px;
|
|
361
|
+
transition: color 0.2s;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.kimu-notification-close:hover {
|
|
365
|
+
color: #333;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/* Types */
|
|
369
|
+
.kimu-notification-success {
|
|
370
|
+
background: #f0fdf4;
|
|
371
|
+
border-left: 4px solid #22c55e;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.kimu-notification-error {
|
|
375
|
+
background: #fef2f2;
|
|
376
|
+
border-left: 4px solid #ef4444;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.kimu-notification-warning {
|
|
380
|
+
background: #fffbeb;
|
|
381
|
+
border-left: 4px solid #f59e0b;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.kimu-notification-info {
|
|
385
|
+
background: #eff6ff;
|
|
386
|
+
border-left: 4px solid #3b82f6;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* Positions */
|
|
390
|
+
.kimu-notification-top-right {
|
|
391
|
+
top: 0;
|
|
392
|
+
right: 0;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
.kimu-notification-top-left {
|
|
396
|
+
top: 0;
|
|
397
|
+
left: 0;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.kimu-notification-bottom-right {
|
|
401
|
+
bottom: 0;
|
|
402
|
+
right: 0;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.kimu-notification-bottom-left {
|
|
406
|
+
bottom: 0;
|
|
407
|
+
left: 0;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
.kimu-notification-top-center {
|
|
411
|
+
top: 0;
|
|
412
|
+
left: 50%;
|
|
413
|
+
transform: translateX(-50%) translateY(-20px);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.kimu-notification-top-center.kimu-notification-enter {
|
|
417
|
+
transform: translateX(-50%) translateY(0);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
.kimu-notification-bottom-center {
|
|
421
|
+
bottom: 0;
|
|
422
|
+
left: 50%;
|
|
423
|
+
transform: translateX(-50%) translateY(20px);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
.kimu-notification-bottom-center.kimu-notification-enter {
|
|
427
|
+
transform: translateX(-50%) translateY(0);
|
|
428
|
+
}
|
|
429
|
+
`;
|
|
430
|
+
|
|
431
|
+
document.head.appendChild(style);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Export singleton instance
|
|
436
|
+
export const notificationService = new NotificationService();
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Kimu Router Module
|
|
2
|
+
|
|
3
|
+
Questo modulo fornisce un servizio di routing per kimu-core, permettendo la gestione delle rotte e la navigazione tra componenti/estensioni in base all'URL.
|
|
4
|
+
|
|
5
|
+
## Funzionalità
|
|
6
|
+
- Configurazione centralizzata delle rotte
|
|
7
|
+
- Navigazione tramite history API
|
|
8
|
+
- Callback sugli eventi di cambio rotta
|
|
9
|
+
- API per registrare nuove rotte dinamicamente
|
|
10
|
+
|
|
11
|
+
## Utilizzo
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { KimuRouterService } from './src/modules/router/router';
|
|
15
|
+
|
|
16
|
+
const router = KimuRouterService.getInstance();
|
|
17
|
+
router.configure([
|
|
18
|
+
{ path: '/', component: HomeComponent },
|
|
19
|
+
{ path: '/about', component: AboutComponent },
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
router.onRouteChange((route) => {
|
|
23
|
+
// Logica per gestire il cambio rotta
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Per navigare
|
|
27
|
+
router.navigate('/about');
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Estensione
|
|
31
|
+
- Puoi estendere il sistema per supportare parametri dinamici, fallback, rotte nidificate, ecc.
|
|
32
|
+
- Le estensioni possono registrare le proprie rotte tramite `registerRoute`.
|
|
33
|
+
|
|
34
|
+
## Best practice
|
|
35
|
+
- Mantieni la configurazione delle rotte separata dalla logica di rendering.
|
|
36
|
+
- Documenta sempre le rotte principali e i parametri accettati.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
Autore: UnicoVerso
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Kimu Router Module
|
|
2
|
+
|
|
3
|
+
This module provides a routing service for kimu-core, allowing you to manage routes and navigation between components/extensions based on the URL.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
- Centralized route configuration
|
|
7
|
+
- Navigation via the History API
|
|
8
|
+
- Callback on route change events
|
|
9
|
+
- API to register new routes dynamically
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { KimuRouterService } from './src/modules/router/router';
|
|
15
|
+
|
|
16
|
+
const router = KimuRouterService.getInstance();
|
|
17
|
+
router.configure([
|
|
18
|
+
{ path: '/', component: HomeComponent },
|
|
19
|
+
{ path: '/about', component: AboutComponent },
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
router.onRouteChange((route) => {
|
|
23
|
+
// Logic to handle route change
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// To navigate
|
|
27
|
+
router.navigate('/about');
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Extension
|
|
31
|
+
- You can extend the system to support dynamic parameters, fallback, nested routes, etc.
|
|
32
|
+
- Extensions can register their own routes via `registerRoute`.
|
|
33
|
+
|
|
34
|
+
## Best practices
|
|
35
|
+
- Keep route configuration separated from rendering logic.
|
|
36
|
+
- Always document main routes and accepted parameters.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
Author: UnicoVerso
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "router",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Client-side routing module for KIMU applications with History API support",
|
|
5
|
+
"author": "KIMU Team",
|
|
6
|
+
"license": "MPL-2.0",
|
|
7
|
+
"dependencies": [],
|
|
8
|
+
"kimuCoreVersion": "^0.3.0",
|
|
9
|
+
"keywords": [
|
|
10
|
+
"router",
|
|
11
|
+
"routing",
|
|
12
|
+
"navigation",
|
|
13
|
+
"history-api",
|
|
14
|
+
"spa"
|
|
15
|
+
],
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/UnicoVerso/kimu-core",
|
|
19
|
+
"directory": "src/modules/router"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// KimuRouterModule
|
|
2
|
+
// Provides the routing service as a KimuModule
|
|
3
|
+
// Inspired by the structure of the i18n module
|
|
4
|
+
|
|
5
|
+
import { KimuModule } from '../../core/kimu-module';
|
|
6
|
+
import { KimuRouterService } from './router';
|
|
7
|
+
import { KimuRouterModuleOptions } from './router';
|
|
8
|
+
|
|
9
|
+
export default class KimuRouterModule extends KimuModule {
|
|
10
|
+
private service: KimuRouterService;
|
|
11
|
+
|
|
12
|
+
constructor(name: string = 'router', version: string = '1.0.0', options?: KimuRouterModuleOptions) {
|
|
13
|
+
super(name, version, options);
|
|
14
|
+
this.service = KimuRouterService.getInstance();
|
|
15
|
+
if (options?.routes) {
|
|
16
|
+
this.service.configure(options.routes);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
getService(): KimuRouterService {
|
|
21
|
+
return this.service;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// Kimu Router Module
|
|
2
|
+
// Provides routing service and configuration for kimu-core extensions and core
|
|
3
|
+
// Author: UnicoVerso
|
|
4
|
+
//
|
|
5
|
+
// Usage: Import KimuRouterService and configure routes in your app or extension.
|
|
6
|
+
|
|
7
|
+
// Router module options (extensible for future features)
|
|
8
|
+
import { KimuModuleOptions } from '../../core/kimu-types';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* RouteConfig defines a single route mapping for the router.
|
|
12
|
+
* - path: URL path to match
|
|
13
|
+
* - component: KimuComponentElement to render
|
|
14
|
+
* - name: Optional route name
|
|
15
|
+
* - meta: Optional metadata for custom usage
|
|
16
|
+
*/
|
|
17
|
+
export interface RouteConfig {
|
|
18
|
+
path: string;
|
|
19
|
+
component: any; // Should extend KimuComponentElement
|
|
20
|
+
name?: string;
|
|
21
|
+
meta?: Record<string, any>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Options for initializing the router module.
|
|
26
|
+
* - routes: Array of RouteConfig for initial setup
|
|
27
|
+
*/
|
|
28
|
+
export interface KimuRouterModuleOptions extends KimuModuleOptions {
|
|
29
|
+
routes?: RouteConfig[];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Callback type for route change events.
|
|
34
|
+
* - route: The matched RouteConfig
|
|
35
|
+
* - params: Optional route parameters (future extension)
|
|
36
|
+
*/
|
|
37
|
+
export type RouteChangeCallback = (route: RouteConfig, params?: Record<string, string>) => void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* KimuRouterService provides SPA-like routing for KIMU extensions/components.
|
|
41
|
+
* Use getInstance() for singleton access.
|
|
42
|
+
*/
|
|
43
|
+
export class KimuRouterService {
|
|
44
|
+
/** Singleton instance */
|
|
45
|
+
private static instance: KimuRouterService;
|
|
46
|
+
/** Registered routes */
|
|
47
|
+
private routes: RouteConfig[] = [];
|
|
48
|
+
/** Currently active route */
|
|
49
|
+
private currentRoute: RouteConfig | null = null;
|
|
50
|
+
/** Listeners for route change events */
|
|
51
|
+
private listeners: RouteChangeCallback[] = [];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Private constructor. Sets up popstate listener for browser navigation.
|
|
55
|
+
*/
|
|
56
|
+
private constructor() {
|
|
57
|
+
window.addEventListener('popstate', this.handlePopState.bind(this));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Returns the singleton instance of the router service.
|
|
62
|
+
*/
|
|
63
|
+
public static getInstance(): KimuRouterService {
|
|
64
|
+
if (!KimuRouterService.instance) {
|
|
65
|
+
KimuRouterService.instance = new KimuRouterService();
|
|
66
|
+
}
|
|
67
|
+
return KimuRouterService.instance;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Configure the router with a set of routes.
|
|
72
|
+
* @param routes Array of RouteConfig
|
|
73
|
+
*/
|
|
74
|
+
public configure(routes: RouteConfig[]): void {
|
|
75
|
+
this.routes = routes;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Register a new route at runtime.
|
|
80
|
+
* @param route RouteConfig to add
|
|
81
|
+
*/
|
|
82
|
+
public registerRoute(route: RouteConfig): void {
|
|
83
|
+
this.routes.push(route);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Navigate to a given path, updating browser history and resolving route.
|
|
88
|
+
* @param path URL path to navigate to
|
|
89
|
+
*/
|
|
90
|
+
public navigate(path: string): void {
|
|
91
|
+
history.pushState({}, '', path);
|
|
92
|
+
this.resolveRoute(path);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the currently active route.
|
|
97
|
+
*/
|
|
98
|
+
public getCurrentRoute(): RouteConfig | null {
|
|
99
|
+
return this.currentRoute;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Register a callback for route change events.
|
|
104
|
+
* @param callback Function to call on route change
|
|
105
|
+
*/
|
|
106
|
+
public onRouteChange(callback: RouteChangeCallback): void {
|
|
107
|
+
this.listeners.push(callback);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Handles browser back/forward navigation.
|
|
112
|
+
*/
|
|
113
|
+
private handlePopState(): void {
|
|
114
|
+
this.resolveRoute(window.location.pathname);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Resolves the route for a given path and notifies listeners.
|
|
119
|
+
* @param path URL path to resolve
|
|
120
|
+
*/
|
|
121
|
+
private resolveRoute(path: string): void {
|
|
122
|
+
const match = this.routes.find(r => r.path === path);
|
|
123
|
+
this.currentRoute = match || null;
|
|
124
|
+
this.listeners.forEach(cb => cb(this.currentRoute!, this.extractParams(path)));
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Extracts route parameters from the path (future extension).
|
|
129
|
+
* @param _path URL path
|
|
130
|
+
* @returns Object with route params (currently empty)
|
|
131
|
+
*/
|
|
132
|
+
private extractParams(_path: string): Record<string, string> {
|
|
133
|
+
// Basic implementation, extend for dynamic params
|
|
134
|
+
return {};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Example usage (in app or extension):
|
|
139
|
+
// const router = KimuRouterService.getInstance();
|
|
140
|
+
// router.configure([
|
|
141
|
+
// { path: '/', component: HomeComponent },
|
|
142
|
+
// { path: '/about', component: AboutComponent },
|
|
143
|
+
// ]);
|
|
144
|
+
// router.onRouteChange((route) => { ... });
|