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,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KIMU Reactive System - Optimized & Minimal
|
|
3
|
+
*
|
|
4
|
+
* Lightweight reactive property decorator for KIMU components.
|
|
5
|
+
* Designed for simplicity, performance, and minimal bundle size.
|
|
6
|
+
*
|
|
7
|
+
* Philosophy: KIMU is intentionally minimal. We focus on doing the essentials
|
|
8
|
+
* perfectly, not everything adequately. For complex reactivity needs, use Vue/React.
|
|
9
|
+
*
|
|
10
|
+
* Usage Example:
|
|
11
|
+
*
|
|
12
|
+
* ```typescript
|
|
13
|
+
* export class MyComponent extends KimuComponentElement {
|
|
14
|
+
* @property({ type: Number })
|
|
15
|
+
* counter = 0;
|
|
16
|
+
*
|
|
17
|
+
* @property({ type: String, reflect: true })
|
|
18
|
+
* label = 'Counter';
|
|
19
|
+
*
|
|
20
|
+
* increment() {
|
|
21
|
+
* this.counter++; // Auto re-render!
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Options for the @property decorator
|
|
29
|
+
*/
|
|
30
|
+
export interface PropertyOptions {
|
|
31
|
+
/**
|
|
32
|
+
* The type of the property. Used for type conversion.
|
|
33
|
+
* Supported types: String, Number, Boolean
|
|
34
|
+
*/
|
|
35
|
+
type?: StringConstructor | NumberConstructor | BooleanConstructor;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Whether the property should reflect to an attribute.
|
|
39
|
+
* If true, changes to the property will update the corresponding HTML attribute.
|
|
40
|
+
*/
|
|
41
|
+
reflect?: boolean;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Convert property name to attribute name (camelCase to kebab-case)
|
|
46
|
+
*/
|
|
47
|
+
const toKebab = (str: string): string => str.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Convert value to specified type
|
|
51
|
+
* @param value - Value to convert
|
|
52
|
+
* @param type - Target type constructor
|
|
53
|
+
* @returns Converted value
|
|
54
|
+
*/
|
|
55
|
+
function convert(value: any, type?: any): any {
|
|
56
|
+
if (!type) return value;
|
|
57
|
+
if (type === Number) return value == null ? 0 : Number(value) || 0;
|
|
58
|
+
if (type === Boolean) return value !== null && value !== 'false' && value !== false;
|
|
59
|
+
if (type === String) return value == null ? '' : String(value);
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Reactive property decorator
|
|
65
|
+
*
|
|
66
|
+
* Transforms a class property into a reactive property that automatically
|
|
67
|
+
* triggers re-rendering when its value changes.
|
|
68
|
+
*
|
|
69
|
+
* @param options - Configuration options for the reactive property
|
|
70
|
+
* @returns Property decorator function
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* export class Counter extends KimuComponentElement {
|
|
75
|
+
* @property({ type: Number })
|
|
76
|
+
* count = 0;
|
|
77
|
+
*
|
|
78
|
+
* @property({ type: String, reflect: true })
|
|
79
|
+
* label = 'Counter';
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export function property(options: PropertyOptions = {}) {
|
|
84
|
+
return function (target: any, propertyKey: string) {
|
|
85
|
+
const privateKey = `__${propertyKey}`;
|
|
86
|
+
const { type, reflect = false } = options;
|
|
87
|
+
const attrName = toKebab(propertyKey);
|
|
88
|
+
|
|
89
|
+
// Store metadata for attribute observation
|
|
90
|
+
const ctor = target.constructor;
|
|
91
|
+
if (!ctor.__kimu_reactive_props__) {
|
|
92
|
+
ctor.__kimu_reactive_props__ = new Map();
|
|
93
|
+
ctor.__kimu_attr_to_prop__ = new Map(); // Inverse map for O(1) lookup
|
|
94
|
+
}
|
|
95
|
+
ctor.__kimu_reactive_props__.set(propertyKey, { type, reflect, attribute: attrName });
|
|
96
|
+
ctor.__kimu_attr_to_prop__.set(attrName, { propertyKey, type }); // Store inverse mapping
|
|
97
|
+
|
|
98
|
+
// Define the reactive property with optimized getter/setter
|
|
99
|
+
Object.defineProperty(target, propertyKey, {
|
|
100
|
+
get() {
|
|
101
|
+
return this[privateKey];
|
|
102
|
+
},
|
|
103
|
+
set(value: any) {
|
|
104
|
+
const oldValue = this[privateKey];
|
|
105
|
+
const newValue = type ? convert(value, type) : value;
|
|
106
|
+
|
|
107
|
+
// Early return if value hasn't changed
|
|
108
|
+
if (oldValue === newValue) return;
|
|
109
|
+
|
|
110
|
+
this[privateKey] = newValue;
|
|
111
|
+
|
|
112
|
+
// Reflect to attribute if enabled (optimized conditionals)
|
|
113
|
+
if (reflect && this instanceof HTMLElement) {
|
|
114
|
+
if (newValue == null || newValue === false) {
|
|
115
|
+
this.removeAttribute(attrName);
|
|
116
|
+
} else {
|
|
117
|
+
this.setAttribute(attrName, type === Boolean ? '' : String(newValue));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Batched re-render using RAF (prevents multiple renders in same frame)
|
|
122
|
+
// Call refresh directly - it already handles RAF batching internally
|
|
123
|
+
if (typeof this.refresh === 'function') {
|
|
124
|
+
this.refresh();
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
enumerable: true,
|
|
128
|
+
configurable: true
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Initialize reactive properties from attributes
|
|
136
|
+
*
|
|
137
|
+
* This should be called in the connectedCallback of components that use @property
|
|
138
|
+
*
|
|
139
|
+
* @param component - The component instance
|
|
140
|
+
*/
|
|
141
|
+
export function initReactiveProperties(component: any): void {
|
|
142
|
+
const props = component.constructor.__kimu_reactive_props__;
|
|
143
|
+
if (!props) return;
|
|
144
|
+
|
|
145
|
+
// Initialize properties from attributes
|
|
146
|
+
props.forEach((options: any, propertyKey: string) => {
|
|
147
|
+
const attrValue = component.getAttribute(options.attribute);
|
|
148
|
+
if (attrValue !== null) {
|
|
149
|
+
(component as any)[propertyKey] = convert(attrValue, options.type);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get observed attributes for reactive properties
|
|
156
|
+
*
|
|
157
|
+
* @param componentClass - The component class
|
|
158
|
+
* @returns Array of observed attributes
|
|
159
|
+
*/
|
|
160
|
+
export function getObservedAttributes(componentClass: any): string[] {
|
|
161
|
+
const props = componentClass.__kimu_reactive_props__;
|
|
162
|
+
if (!props) return [];
|
|
163
|
+
|
|
164
|
+
return Array.from(props.values())
|
|
165
|
+
.map((opts: any) => opts.attribute)
|
|
166
|
+
.filter(Boolean);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Handle attribute changes for reactive properties
|
|
171
|
+
*
|
|
172
|
+
* This should be called from attributeChangedCallback
|
|
173
|
+
*
|
|
174
|
+
* @param component - The component instance
|
|
175
|
+
* @param name - Attribute name
|
|
176
|
+
* @param oldValue - Old attribute value
|
|
177
|
+
* @param newValue - New attribute value
|
|
178
|
+
*/
|
|
179
|
+
export function handleAttributeChange(
|
|
180
|
+
component: any,
|
|
181
|
+
name: string,
|
|
182
|
+
_oldValue: string | null,
|
|
183
|
+
newValue: string | null
|
|
184
|
+
): void {
|
|
185
|
+
const attrMap = component.constructor.__kimu_attr_to_prop__;
|
|
186
|
+
if (!attrMap) return;
|
|
187
|
+
|
|
188
|
+
// O(1) lookup using inverse map
|
|
189
|
+
const propInfo = attrMap.get(name);
|
|
190
|
+
if (propInfo) {
|
|
191
|
+
component[propInfo.propertyKey] = newValue !== null
|
|
192
|
+
? convert(newValue, propInfo.type)
|
|
193
|
+
: null;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { html, render as litRender, TemplateResult } from 'lit';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The `KimuRender` class provides utility methods for reactive rendering and template compilation
|
|
5
|
+
* in the Kimu framework. It leverages the Lit library to enable dynamic and efficient UI updates.
|
|
6
|
+
*
|
|
7
|
+
* Key functionalities:
|
|
8
|
+
* - Performs reactive rendering using Lit.
|
|
9
|
+
* - Loads HTML templates from files and compiles them into Lit rendering functions.
|
|
10
|
+
* - Compiles HTML strings into dynamic Lit rendering functions.
|
|
11
|
+
*/
|
|
12
|
+
export class KimuRender {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Performs reactive rendering using Lit.
|
|
16
|
+
*
|
|
17
|
+
* @param component - The target component where the template will be rendered.
|
|
18
|
+
* @param data - The data to be passed to the rendering function.
|
|
19
|
+
* @param renderFn - The Lit rendering function that generates the template.
|
|
20
|
+
*/
|
|
21
|
+
static render(component: HTMLElement, data: Record<string, any>, renderFn: (html: any, data: Record<string, any>) => TemplateResult): void {
|
|
22
|
+
if (!component.shadowRoot) {
|
|
23
|
+
console.warn('[KimuRender] Shadow DOM not found for component:', component.tagName);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
const template = renderFn(html, data);
|
|
29
|
+
|
|
30
|
+
// Ensure we're working with a valid Lit TemplateResult
|
|
31
|
+
if (!template || !template.strings) {
|
|
32
|
+
console.warn('[KimuRender] Invalid template result from renderFn');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Use Lit's native render function which handles efficient updates
|
|
37
|
+
litRender(template, component.shadowRoot);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('[KimuRender] Error during Lit rendering:', error);
|
|
40
|
+
console.error('Component:', component.tagName);
|
|
41
|
+
console.error('Data:', data);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Loads an HTML template from a file and compiles it into a Lit rendering function.
|
|
47
|
+
*
|
|
48
|
+
* @param template - The HTML template string to be compiled.
|
|
49
|
+
* @returns A compiled Lit rendering function.
|
|
50
|
+
*/
|
|
51
|
+
static async loadTemplate(template: string) {
|
|
52
|
+
return this.compileTemplate(template);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Compiles an HTML string into a dynamic Lit rendering function.
|
|
57
|
+
*
|
|
58
|
+
* @param template - The HTML string to be compiled.
|
|
59
|
+
* @returns A Lit rendering function that can be used for reactive rendering.
|
|
60
|
+
*/
|
|
61
|
+
static compileTemplate(template: string): (html: typeof import('lit').html, data: Record<string, any>) => TemplateResult {
|
|
62
|
+
// Simple and safe template compilation without 'with' statement
|
|
63
|
+
return (html: typeof import('lit').html, data: Record<string, any>) => {
|
|
64
|
+
try {
|
|
65
|
+
// Create a function that has access to data properties as parameters
|
|
66
|
+
const keys = Object.keys(data || {});
|
|
67
|
+
const values = Object.values(data || {});
|
|
68
|
+
|
|
69
|
+
// Create template function with destructured parameters
|
|
70
|
+
const templateFunction = new Function(
|
|
71
|
+
...keys,
|
|
72
|
+
'html',
|
|
73
|
+
`return html\`${template}\`;`
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
// Execute with data values
|
|
77
|
+
return templateFunction(...values, html);
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error('[KimuRender] Template compilation error:', error);
|
|
80
|
+
console.error('Template:', template.slice(0, 200));
|
|
81
|
+
console.error('Data:', data);
|
|
82
|
+
|
|
83
|
+
// Return safe fallback template
|
|
84
|
+
return html`<div class="kimu-template-error">
|
|
85
|
+
<strong>Template Error:</strong> ${error instanceof Error ? error.message : 'Unknown error'}
|
|
86
|
+
</div>`;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { KimuExtensionMeta } from './kimu-types';
|
|
2
|
+
|
|
3
|
+
const DB_NAME = 'kimu-db'; // Name of the IndexedDB database
|
|
4
|
+
const STORE_NAME = 'extensions'; // Name of the store (table) in the database
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The `KimuStore` class provides utility methods for managing extensions in IndexedDB.
|
|
8
|
+
* It acts as a persistent storage layer for saving, retrieving, and managing extension metadata.
|
|
9
|
+
*
|
|
10
|
+
* Key functionalities:
|
|
11
|
+
* - Initializes IndexedDB and creates the store if it does not exist.
|
|
12
|
+
* - Provides methods to check if the database is empty.
|
|
13
|
+
* - Saves, retrieves, and removes extensions from the database.
|
|
14
|
+
* - Clears all extensions from the database.
|
|
15
|
+
*/
|
|
16
|
+
export class KimuStore {
|
|
17
|
+
private static _db: IDBDatabase;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Initializes IndexedDB and creates the store if it does not exist.
|
|
21
|
+
*
|
|
22
|
+
* @returns A promise that resolves when the database is initialized.
|
|
23
|
+
*/
|
|
24
|
+
static async init(): Promise<void> {
|
|
25
|
+
// console.log('[KimuStore] IndexedDB initialize...');
|
|
26
|
+
// Check if IndexedDB is already initialized
|
|
27
|
+
if (this._db) {
|
|
28
|
+
// console.log('[KimuStore] ✅ IndexedDB is already initialized');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// Initialize IndexedDB
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
const request = indexedDB.open(DB_NAME, 1);
|
|
34
|
+
request.onerror = () => reject('❌ IndexedDB is not available');
|
|
35
|
+
request.onsuccess = () => {
|
|
36
|
+
this._db = request.result;
|
|
37
|
+
resolve();
|
|
38
|
+
};
|
|
39
|
+
request.onupgradeneeded = () => {
|
|
40
|
+
const db = request.result;
|
|
41
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
42
|
+
db.createObjectStore(STORE_NAME, { keyPath: 'tag' });
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Checks if the database is empty.
|
|
50
|
+
*
|
|
51
|
+
* @returns A promise that resolves to `true` if the database is empty, otherwise `false`.
|
|
52
|
+
*/
|
|
53
|
+
static async isEmpty(): Promise<boolean> {
|
|
54
|
+
await this.init();
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
const tx = this._db.transaction(STORE_NAME, 'readonly');
|
|
57
|
+
const store = tx.objectStore(STORE_NAME);
|
|
58
|
+
const countRequest = store.count();
|
|
59
|
+
countRequest.onsuccess = () => resolve(countRequest.result === 0);
|
|
60
|
+
countRequest.onerror = () => reject(countRequest.error);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Retrieves all extensions saved in the database.
|
|
66
|
+
*
|
|
67
|
+
* @returns A promise that resolves to an array of extension metadata.
|
|
68
|
+
*/
|
|
69
|
+
static async list(): Promise<KimuExtensionMeta[]> {
|
|
70
|
+
await this.init();
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const tx = this._db.transaction(STORE_NAME, 'readonly');
|
|
73
|
+
const store = tx.objectStore(STORE_NAME);
|
|
74
|
+
const request = store.getAll();
|
|
75
|
+
request.onsuccess = () => resolve(request.result as KimuExtensionMeta[]);
|
|
76
|
+
request.onerror = () => reject(request.error);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Retrieves a specific extension by its tag.
|
|
82
|
+
*
|
|
83
|
+
* @param tag - The tag of the extension to retrieve.
|
|
84
|
+
* @returns A promise that resolves to the extension metadata or `undefined` if not found.
|
|
85
|
+
*/
|
|
86
|
+
static async get(tag: string): Promise<KimuExtensionMeta | undefined> {
|
|
87
|
+
await this.init();
|
|
88
|
+
return new Promise((resolve, reject) => {
|
|
89
|
+
const tx = this._db.transaction(STORE_NAME, 'readonly');
|
|
90
|
+
const store = tx.objectStore(STORE_NAME);
|
|
91
|
+
const request = store.get(tag);
|
|
92
|
+
request.onsuccess = () => resolve(request.result);
|
|
93
|
+
request.onerror = () => reject(request.error);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Saves an extension to the database.
|
|
99
|
+
*
|
|
100
|
+
* @param entry - The extension metadata to save.
|
|
101
|
+
* @returns A promise that resolves when the extension is saved.
|
|
102
|
+
*/
|
|
103
|
+
static async save(entry: KimuExtensionMeta): Promise<void> {
|
|
104
|
+
await this.init();
|
|
105
|
+
return new Promise((resolve, reject) => {
|
|
106
|
+
const tx = this._db.transaction(STORE_NAME, 'readwrite');
|
|
107
|
+
const store = tx.objectStore(STORE_NAME);
|
|
108
|
+
const request = store.put(entry);
|
|
109
|
+
request.onsuccess = () => resolve();
|
|
110
|
+
request.onerror = () => reject(request.error);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Removes an extension from the database by its tag.
|
|
116
|
+
*
|
|
117
|
+
* @param tag - The tag of the extension to remove.
|
|
118
|
+
* @returns A promise that resolves when the extension is removed.
|
|
119
|
+
*/
|
|
120
|
+
static async remove(tag: string): Promise<void> {
|
|
121
|
+
await this.init();
|
|
122
|
+
return new Promise((resolve, reject) => {
|
|
123
|
+
const tx = this._db.transaction(STORE_NAME, 'readwrite');
|
|
124
|
+
const store = tx.objectStore(STORE_NAME);
|
|
125
|
+
const request = store.delete(tag);
|
|
126
|
+
request.onsuccess = () => resolve();
|
|
127
|
+
request.onerror = () => reject(request.error);
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Clears all extensions from the database.
|
|
133
|
+
*
|
|
134
|
+
* @returns A promise that resolves when the database is cleared.
|
|
135
|
+
*/
|
|
136
|
+
static async clear(): Promise<void> {
|
|
137
|
+
await this.init();
|
|
138
|
+
return new Promise((resolve, reject) => {
|
|
139
|
+
const tx = this._db.transaction(STORE_NAME, 'readwrite');
|
|
140
|
+
const store = tx.objectStore(STORE_NAME);
|
|
141
|
+
const request = store.clear();
|
|
142
|
+
request.onsuccess = () => resolve();
|
|
143
|
+
request.onerror = () => reject(request.error);
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This code defines the types and interfaces used in the Kimu framework.
|
|
3
|
+
* It provides structured definitions for assets, languages, and extension metadata,
|
|
4
|
+
* enabling consistent and type-safe management of resources and extensions.
|
|
5
|
+
*
|
|
6
|
+
* Key functionalities:
|
|
7
|
+
* - Defines types for assets (CSS, JS) and their metadata.
|
|
8
|
+
* - Provides interfaces for supported languages and their configurations.
|
|
9
|
+
* - Defines metadata for Kimu extensions, including version, author, dependencies, and more.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// Type to define a single resource to load
|
|
13
|
+
export type KimuAsset = {
|
|
14
|
+
path: string; // Path to the resource (e.g., "style.css")
|
|
15
|
+
id?: string; // Optional ID for the resource (e.g., "kimu-style")
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Type to define external resources to load
|
|
19
|
+
export type KimuGroupAsset = {
|
|
20
|
+
css?: KimuAsset[]; // Array of CSS assets
|
|
21
|
+
js?: KimuAsset[]; // Array of JS assets
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// Type to define a supported language
|
|
25
|
+
export interface KimuLang {
|
|
26
|
+
code: string; // language code e.g., 'it', 'en'
|
|
27
|
+
name?: string; // e.g., 'Italian' (language name)
|
|
28
|
+
file?: string; // e.g., 'custom-name.json' (language file)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Type to define the languages supported by an extension
|
|
32
|
+
export interface KimuExtensionLanguages {
|
|
33
|
+
default: string; // Default language code (e.g., 'en')
|
|
34
|
+
supported: Record<string, KimuLang>; // Map of supported languages
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Interface to define metadata associated with Kimu extensions
|
|
38
|
+
export interface KimuExtensionMeta {
|
|
39
|
+
tag: string; // e.g., "ext-hello" (component tag name)
|
|
40
|
+
name: string; // e.g., "Hello World" (extension name)
|
|
41
|
+
version?: string; // e.g., "1.0.0" (extension version)
|
|
42
|
+
description?: string; // e.g., "Hello World component" (extension description)
|
|
43
|
+
author?: string; // e.g., "UnicoVerso" (extension author)
|
|
44
|
+
icon?: string; // e.g., "icon.png" (extension icon)
|
|
45
|
+
source?: string; // 'local' | 'git' | 'marketplace' (source type)
|
|
46
|
+
link?: string; // Reference to documentation or website
|
|
47
|
+
path?: string; // e.g., "hello" (base path for the extension)
|
|
48
|
+
basePath?: string; // e.g., "extensions/hello" (internal base path for the extension)
|
|
49
|
+
kimuVersion?: string; // e.g., "1.0.0" (minimum required Kimu version)
|
|
50
|
+
enabled?: boolean; // If true, the extension is enabled (default: true)
|
|
51
|
+
installed?: boolean; // If true, the extension is installed (default: false)
|
|
52
|
+
internal?: boolean; // If true, the extension is internal and not visible to the user (default: false)
|
|
53
|
+
template?: string; // e.g., "hello.html" (HTML template for the extension)
|
|
54
|
+
style?: string; // e.g., "hello.css" (CSS file for the extension)
|
|
55
|
+
external?: KimuGroupAsset; // Object defining external resources to load
|
|
56
|
+
dependencies?: string[]; // List of dependent extensions
|
|
57
|
+
languages?: KimuExtensionLanguages; // Object defining supported languages for the extension
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Interface to define options for Kimu modules
|
|
61
|
+
export interface KimuModuleOptions {
|
|
62
|
+
[key: string]: any;
|
|
63
|
+
// Proprietà opzionali per configurare i moduli
|
|
64
|
+
// Esempio: lang?: string; debug?: boolean; resources?: string[];
|
|
65
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
//
|
|
2
|
+
// This file can be freely modified by developers.
|
|
3
|
+
// Changes made to this page are not subject to the publication requirement of the MPL framework license.
|
|
4
|
+
//
|
|
5
|
+
|
|
6
|
+
import { KimuComponent } from '../../core/kimu-component';
|
|
7
|
+
import { KimuComponentElement } from '../../core/kimu-component-element';
|
|
8
|
+
import { KimuGlobalLang, KimuI18nService } from '../../modules/i18n/module';
|
|
9
|
+
|
|
10
|
+
@KimuComponent({
|
|
11
|
+
tag: 'kimu-home',
|
|
12
|
+
path: 'kimu-home',
|
|
13
|
+
name: 'KIMU Home',
|
|
14
|
+
version: '1.0.0',
|
|
15
|
+
description: 'Main interface container',
|
|
16
|
+
icon: '🏠',
|
|
17
|
+
author: 'UnicòVerso',
|
|
18
|
+
kimuVersion: '1.0.0',
|
|
19
|
+
languages: {
|
|
20
|
+
default: 'it',
|
|
21
|
+
supported: {
|
|
22
|
+
it: { code: 'it', name: 'Italian' },
|
|
23
|
+
en: { code: 'en', name: 'English' }
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
export class KimuHomeComponent extends KimuComponentElement {
|
|
28
|
+
|
|
29
|
+
/** I18n service instance for translations */
|
|
30
|
+
private i18n = new KimuI18nService(
|
|
31
|
+
this.getMeta().languages?.default,
|
|
32
|
+
'extensions/' + this.getMeta().path + '/lang',
|
|
33
|
+
this.getMeta().languages
|
|
34
|
+
);
|
|
35
|
+
/** Currently selected language code */
|
|
36
|
+
private selectedLang = KimuGlobalLang.get();
|
|
37
|
+
|
|
38
|
+
/** Versione del framework KIMU */
|
|
39
|
+
private kimuVersion = '';
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Initializes the component, loads the current language, and sets up reactivity.
|
|
43
|
+
*/
|
|
44
|
+
async onInit() {
|
|
45
|
+
this.selectedLang = await KimuGlobalLang.get();
|
|
46
|
+
await this.i18n.setLang(this.selectedLang);
|
|
47
|
+
// Recupera la versione del framework
|
|
48
|
+
const app = await this.getApp();
|
|
49
|
+
this.kimuVersion = app.version;
|
|
50
|
+
this.refresh();
|
|
51
|
+
// React to global language changes
|
|
52
|
+
KimuGlobalLang.onChange(async (lang: string) => {
|
|
53
|
+
await this.i18n.setLang(lang);
|
|
54
|
+
this.selectedLang = KimuGlobalLang.get();
|
|
55
|
+
this.refresh();
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns the data object for template rendering.
|
|
61
|
+
* All properties are precomputed for compatibility with the template engine.
|
|
62
|
+
*/
|
|
63
|
+
getData() {
|
|
64
|
+
return {
|
|
65
|
+
slogan: 'Keep It Minimal UI',
|
|
66
|
+
translate: this.i18n.translate,
|
|
67
|
+
selectedLang: this.selectedLang,
|
|
68
|
+
languages: this.getMeta().languages?.supported,
|
|
69
|
+
version: this.kimuVersion,
|
|
70
|
+
onLangIt: async () => {
|
|
71
|
+
await KimuGlobalLang.set('it');
|
|
72
|
+
this.refresh();
|
|
73
|
+
},
|
|
74
|
+
onLangEn: async () => {
|
|
75
|
+
await KimuGlobalLang.set('en');
|
|
76
|
+
this.refresh();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This file can be freely modified by developers.
|
|
3
|
+
Changes made to this page are not subject to the publication requirement of the MPL framework license.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
:host {
|
|
7
|
+
display: flex;
|
|
8
|
+
width: 100%;
|
|
9
|
+
height: 100%;
|
|
10
|
+
background-color: var(--kimu-bg);
|
|
11
|
+
font-family: var(--kimu-font, sans-serif);
|
|
12
|
+
color: var(--kimu-text);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.container {
|
|
16
|
+
flex: 1;
|
|
17
|
+
display: flex;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
align-items: center;
|
|
20
|
+
justify-content: center;
|
|
21
|
+
text-align: center;
|
|
22
|
+
min-height: 100vh;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.btn-lang {
|
|
26
|
+
display: flex;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
gap: 14px;
|
|
29
|
+
margin-top: 18px;
|
|
30
|
+
margin-bottom: 8px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.logo {
|
|
34
|
+
margin-bottom: 5px;
|
|
35
|
+
display: flex;
|
|
36
|
+
justify-content: center;
|
|
37
|
+
align-items: center;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.logo img {
|
|
41
|
+
width: 200px;
|
|
42
|
+
height: auto;
|
|
43
|
+
display: block;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.kimu-footer {
|
|
47
|
+
margin-top: 32px;
|
|
48
|
+
text-align: center;
|
|
49
|
+
color: #888;
|
|
50
|
+
font-size: 0.92em;
|
|
51
|
+
letter-spacing: 0.01em;
|
|
52
|
+
}
|
|
53
|
+
.kimu-footer a {
|
|
54
|
+
color: #3a7afe;
|
|
55
|
+
text-decoration: none;
|
|
56
|
+
transition: color 0.15s;
|
|
57
|
+
}
|
|
58
|
+
.kimu-footer a:hover {
|
|
59
|
+
color: #1746a0;
|
|
60
|
+
text-decoration: underline;
|
|
61
|
+
}
|