@tolle_/tolle-ui 0.0.2-beta → 0.0.4-beta
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/esm2022/lib/theme.service.mjs +82 -0
- package/esm2022/lib/tolle-config.mjs +8 -4
- package/fesm2022/tolle_-tolle-ui.mjs +85 -5
- package/fesm2022/tolle_-tolle-ui.mjs.map +1 -1
- package/lib/theme.service.d.ts +19 -0
- package/package.json +20 -14
- package/theme.css +69 -103
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Injectable, Inject, PLATFORM_ID, Optional } from '@angular/core';
|
|
2
|
+
import { DOCUMENT, isPlatformBrowser } from '@angular/common';
|
|
3
|
+
import { BehaviorSubject } from 'rxjs';
|
|
4
|
+
import { TOLLE_CONFIG } from './tolle-config';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
export class ThemeService {
|
|
7
|
+
document;
|
|
8
|
+
platformId;
|
|
9
|
+
config;
|
|
10
|
+
renderer;
|
|
11
|
+
isDarkSubject = new BehaviorSubject(false);
|
|
12
|
+
isDark$ = this.isDarkSubject.asObservable();
|
|
13
|
+
constructor(document, platformId, config, rendererFactory) {
|
|
14
|
+
this.document = document;
|
|
15
|
+
this.platformId = platformId;
|
|
16
|
+
this.config = config;
|
|
17
|
+
this.renderer = rendererFactory.createRenderer(null, null);
|
|
18
|
+
this.initializeTheme();
|
|
19
|
+
}
|
|
20
|
+
initializeTheme() {
|
|
21
|
+
if (!isPlatformBrowser(this.platformId))
|
|
22
|
+
return;
|
|
23
|
+
// 1. Determine Initial Mode (Dark/Light)
|
|
24
|
+
const savedTheme = localStorage.getItem('tolle-theme');
|
|
25
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
26
|
+
// Priority: Saved Preference > Config Default > System Preference
|
|
27
|
+
const shouldBeDark = savedTheme
|
|
28
|
+
? savedTheme === 'dark'
|
|
29
|
+
: (this.config?.darkByDefault ?? prefersDark);
|
|
30
|
+
if (shouldBeDark) {
|
|
31
|
+
this.enableDarkMode();
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
this.disableDarkMode();
|
|
35
|
+
}
|
|
36
|
+
// 2. Apply Brand Config (Colors/Radius)
|
|
37
|
+
if (this.config) {
|
|
38
|
+
this.applyBrandConfig(this.config);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
applyBrandConfig(config) {
|
|
42
|
+
const root = this.document.documentElement;
|
|
43
|
+
if (config.primaryColor) {
|
|
44
|
+
this.renderer.setStyle(root, '--primary', config.primaryColor);
|
|
45
|
+
}
|
|
46
|
+
if (config.radius) {
|
|
47
|
+
this.renderer.setStyle(root, '--radius', config.radius);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
toggleTheme() {
|
|
51
|
+
const isDark = this.document.documentElement.classList.contains('dark');
|
|
52
|
+
isDark ? this.disableDarkMode() : this.enableDarkMode();
|
|
53
|
+
}
|
|
54
|
+
enableDarkMode() {
|
|
55
|
+
this.renderer.addClass(this.document.documentElement, 'dark');
|
|
56
|
+
localStorage.setItem('tolle-theme', 'dark');
|
|
57
|
+
this.isDarkSubject.next(true);
|
|
58
|
+
}
|
|
59
|
+
disableDarkMode() {
|
|
60
|
+
this.renderer.removeClass(this.document.documentElement, 'dark');
|
|
61
|
+
localStorage.setItem('tolle-theme', 'light');
|
|
62
|
+
this.isDarkSubject.next(false);
|
|
63
|
+
}
|
|
64
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: TOLLE_CONFIG, optional: true }, { token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
65
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, providedIn: 'root' });
|
|
66
|
+
}
|
|
67
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, decorators: [{
|
|
68
|
+
type: Injectable,
|
|
69
|
+
args: [{ providedIn: 'root' }]
|
|
70
|
+
}], ctorParameters: () => [{ type: Document, decorators: [{
|
|
71
|
+
type: Inject,
|
|
72
|
+
args: [DOCUMENT]
|
|
73
|
+
}] }, { type: Object, decorators: [{
|
|
74
|
+
type: Inject,
|
|
75
|
+
args: [PLATFORM_ID]
|
|
76
|
+
}] }, { type: undefined, decorators: [{
|
|
77
|
+
type: Optional
|
|
78
|
+
}, {
|
|
79
|
+
type: Inject,
|
|
80
|
+
args: [TOLLE_CONFIG]
|
|
81
|
+
}] }, { type: i0.RendererFactory2 }] });
|
|
82
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGhlbWUuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3RvbGxlL3NyYy9saWIvdGhlbWUuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxXQUFXLEVBQUUsUUFBUSxFQUErQixNQUFNLGVBQWUsQ0FBQztBQUN2RyxPQUFPLEVBQUUsUUFBUSxFQUFFLGlCQUFpQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDOUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN2QyxPQUFPLEVBQUUsWUFBWSxFQUFlLE1BQU0sZ0JBQWdCLENBQUM7O0FBRzNELE1BQU0sT0FBTyxZQUFZO0lBTUs7SUFDRztJQUNhO0lBUHBDLFFBQVEsQ0FBWTtJQUNwQixhQUFhLEdBQUcsSUFBSSxlQUFlLENBQVUsS0FBSyxDQUFDLENBQUM7SUFDNUQsT0FBTyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUFFLENBQUM7SUFFNUMsWUFDNEIsUUFBa0IsRUFDZixVQUFrQixFQUNMLE1BQW1CLEVBQzdELGVBQWlDO1FBSFAsYUFBUSxHQUFSLFFBQVEsQ0FBVTtRQUNmLGVBQVUsR0FBVixVQUFVLENBQVE7UUFDTCxXQUFNLEdBQU4sTUFBTSxDQUFhO1FBRzdELElBQUksQ0FBQyxRQUFRLEdBQUcsZUFBZSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLGVBQWUsRUFBRSxDQUFDO0lBQ3pCLENBQUM7SUFFTyxlQUFlO1FBQ3JCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDO1lBQUUsT0FBTztRQUVoRCx5Q0FBeUM7UUFDekMsTUFBTSxVQUFVLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUN2RCxNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLDhCQUE4QixDQUFDLENBQUMsT0FBTyxDQUFDO1FBRTlFLGtFQUFrRTtRQUNsRSxNQUFNLFlBQVksR0FBRyxVQUFVO1lBQzdCLENBQUMsQ0FBQyxVQUFVLEtBQUssTUFBTTtZQUN2QixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLGFBQWEsSUFBSSxXQUFXLENBQUMsQ0FBQztRQUVoRCxJQUFJLFlBQVksRUFBRSxDQUFDO1lBQ2pCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN4QixDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUN6QixDQUFDO1FBRUQsd0NBQXdDO1FBQ3hDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ2hCLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDckMsQ0FBQztJQUNILENBQUM7SUFFTyxnQkFBZ0IsQ0FBQyxNQUFtQjtRQUMxQyxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsQ0FBQztRQUMzQyxJQUFJLE1BQU0sQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN4QixJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNqRSxDQUFDO1FBQ0QsSUFBSSxNQUFNLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDbEIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLFVBQVUsRUFBRSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDMUQsQ0FBQztJQUNILENBQUM7SUFFRCxXQUFXO1FBQ1QsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxlQUFlLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN4RSxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQzFELENBQUM7SUFFTyxjQUFjO1FBQ3BCLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsZUFBZSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzlELFlBQVksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQzVDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ2hDLENBQUM7SUFFTyxlQUFlO1FBQ3JCLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsZUFBZSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ2pFLFlBQVksQ0FBQyxPQUFPLENBQUMsYUFBYSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQzdDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ2pDLENBQUM7d0dBaEVVLFlBQVksa0JBTWIsUUFBUSxhQUNSLFdBQVcsYUFDQyxZQUFZOzRHQVJ2QixZQUFZLGNBREMsTUFBTTs7NEZBQ25CLFlBQVk7a0JBRHhCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFOzswQkFPN0IsTUFBTTsyQkFBQyxRQUFROzswQkFDZixNQUFNOzJCQUFDLFdBQVc7OzBCQUNsQixRQUFROzswQkFBSSxNQUFNOzJCQUFDLFlBQVkiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBJbmplY3QsIFBMQVRGT1JNX0lELCBPcHRpb25hbCwgUmVuZGVyZXIyLCBSZW5kZXJlckZhY3RvcnkyIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBET0NVTUVOVCwgaXNQbGF0Zm9ybUJyb3dzZXIgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBUT0xMRV9DT05GSUcsIFRvbGxlQ29uZmlnIH0gZnJvbSAnLi90b2xsZS1jb25maWcnO1xuXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFRoZW1lU2VydmljZSB7XG4gIHByaXZhdGUgcmVuZGVyZXI6IFJlbmRlcmVyMjtcbiAgcHJpdmF0ZSBpc0RhcmtTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxib29sZWFuPihmYWxzZSk7XG4gIGlzRGFyayQgPSB0aGlzLmlzRGFya1N1YmplY3QuYXNPYnNlcnZhYmxlKCk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChET0NVTUVOVCkgcHJpdmF0ZSBkb2N1bWVudDogRG9jdW1lbnQsXG4gICAgQEluamVjdChQTEFURk9STV9JRCkgcHJpdmF0ZSBwbGF0Zm9ybUlkOiBPYmplY3QsXG4gICAgQE9wdGlvbmFsKCkgQEluamVjdChUT0xMRV9DT05GSUcpIHByaXZhdGUgY29uZmlnOiBUb2xsZUNvbmZpZyxcbiAgICByZW5kZXJlckZhY3Rvcnk6IFJlbmRlcmVyRmFjdG9yeTJcbiAgKSB7XG4gICAgdGhpcy5yZW5kZXJlciA9IHJlbmRlcmVyRmFjdG9yeS5jcmVhdGVSZW5kZXJlcihudWxsLCBudWxsKTtcbiAgICB0aGlzLmluaXRpYWxpemVUaGVtZSgpO1xuICB9XG5cbiAgcHJpdmF0ZSBpbml0aWFsaXplVGhlbWUoKSB7XG4gICAgaWYgKCFpc1BsYXRmb3JtQnJvd3Nlcih0aGlzLnBsYXRmb3JtSWQpKSByZXR1cm47XG5cbiAgICAvLyAxLiBEZXRlcm1pbmUgSW5pdGlhbCBNb2RlIChEYXJrL0xpZ2h0KVxuICAgIGNvbnN0IHNhdmVkVGhlbWUgPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgndG9sbGUtdGhlbWUnKTtcbiAgICBjb25zdCBwcmVmZXJzRGFyayA9IHdpbmRvdy5tYXRjaE1lZGlhKCcocHJlZmVycy1jb2xvci1zY2hlbWU6IGRhcmspJykubWF0Y2hlcztcblxuICAgIC8vIFByaW9yaXR5OiBTYXZlZCBQcmVmZXJlbmNlID4gQ29uZmlnIERlZmF1bHQgPiBTeXN0ZW0gUHJlZmVyZW5jZVxuICAgIGNvbnN0IHNob3VsZEJlRGFyayA9IHNhdmVkVGhlbWVcbiAgICAgID8gc2F2ZWRUaGVtZSA9PT0gJ2RhcmsnXG4gICAgICA6ICh0aGlzLmNvbmZpZz8uZGFya0J5RGVmYXVsdCA/PyBwcmVmZXJzRGFyayk7XG5cbiAgICBpZiAoc2hvdWxkQmVEYXJrKSB7XG4gICAgICB0aGlzLmVuYWJsZURhcmtNb2RlKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZGlzYWJsZURhcmtNb2RlKCk7XG4gICAgfVxuXG4gICAgLy8gMi4gQXBwbHkgQnJhbmQgQ29uZmlnIChDb2xvcnMvUmFkaXVzKVxuICAgIGlmICh0aGlzLmNvbmZpZykge1xuICAgICAgdGhpcy5hcHBseUJyYW5kQ29uZmlnKHRoaXMuY29uZmlnKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFwcGx5QnJhbmRDb25maWcoY29uZmlnOiBUb2xsZUNvbmZpZykge1xuICAgIGNvbnN0IHJvb3QgPSB0aGlzLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcbiAgICBpZiAoY29uZmlnLnByaW1hcnlDb2xvcikge1xuICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShyb290LCAnLS1wcmltYXJ5JywgY29uZmlnLnByaW1hcnlDb2xvcik7XG4gICAgfVxuICAgIGlmIChjb25maWcucmFkaXVzKSB7XG4gICAgICB0aGlzLnJlbmRlcmVyLnNldFN0eWxlKHJvb3QsICctLXJhZGl1cycsIGNvbmZpZy5yYWRpdXMpO1xuICAgIH1cbiAgfVxuXG4gIHRvZ2dsZVRoZW1lKCkge1xuICAgIGNvbnN0IGlzRGFyayA9IHRoaXMuZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnZGFyaycpO1xuICAgIGlzRGFyayA/IHRoaXMuZGlzYWJsZURhcmtNb2RlKCkgOiB0aGlzLmVuYWJsZURhcmtNb2RlKCk7XG4gIH1cblxuICBwcml2YXRlIGVuYWJsZURhcmtNb2RlKCkge1xuICAgIHRoaXMucmVuZGVyZXIuYWRkQ2xhc3ModGhpcy5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsICdkYXJrJyk7XG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3RvbGxlLXRoZW1lJywgJ2RhcmsnKTtcbiAgICB0aGlzLmlzRGFya1N1YmplY3QubmV4dCh0cnVlKTtcbiAgfVxuXG4gIHByaXZhdGUgZGlzYWJsZURhcmtNb2RlKCkge1xuICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlQ2xhc3ModGhpcy5kb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsICdkYXJrJyk7XG4gICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3RvbGxlLXRoZW1lJywgJ2xpZ2h0Jyk7XG4gICAgdGhpcy5pc0RhcmtTdWJqZWN0Lm5leHQoZmFsc2UpO1xuICB9XG59XG4iXX0=
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
import { InjectionToken } from '@angular/core';
|
|
1
|
+
import { APP_INITIALIZER, InjectionToken } from '@angular/core';
|
|
2
|
+
import { ThemeService } from './theme.service';
|
|
2
3
|
export const TOLLE_CONFIG = new InjectionToken('TolleConfig');
|
|
3
4
|
export function provideTolleConfig(config) {
|
|
4
5
|
return [
|
|
6
|
+
{ provide: TOLLE_CONFIG, useValue: config },
|
|
5
7
|
{
|
|
6
|
-
provide:
|
|
7
|
-
|
|
8
|
+
provide: APP_INITIALIZER,
|
|
9
|
+
useFactory: (themeService) => () => themeService, // Just force injection
|
|
10
|
+
deps: [ThemeService],
|
|
11
|
+
multi: true
|
|
8
12
|
}
|
|
9
13
|
];
|
|
10
14
|
}
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
15
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidG9sbGUtY29uZmlnLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvdG9sbGUvc3JjL2xpYi90b2xsZS1jb25maWcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLGVBQWUsRUFBRSxjQUFjLEVBQVcsTUFBTSxlQUFlLENBQUM7QUFDeEUsT0FBTyxFQUFDLFlBQVksRUFBQyxNQUFNLGlCQUFpQixDQUFDO0FBUzdDLE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxJQUFJLGNBQWMsQ0FBYyxhQUFhLENBQUMsQ0FBQztBQUUzRSxNQUFNLFVBQVUsa0JBQWtCLENBQUMsTUFBbUI7SUFDcEQsT0FBTztRQUNMLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFO1FBQzNDO1lBQ0UsT0FBTyxFQUFFLGVBQWU7WUFDeEIsVUFBVSxFQUFFLENBQUMsWUFBMEIsRUFBRSxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsWUFBWSxFQUFFLHVCQUF1QjtZQUN2RixJQUFJLEVBQUUsQ0FBQyxZQUFZLENBQUM7WUFDcEIsS0FBSyxFQUFFLElBQUk7U0FDWjtLQUNGLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtBUFBfSU5JVElBTElaRVIsIEluamVjdGlvblRva2VuLCBQcm92aWRlcn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1RoZW1lU2VydmljZX0gZnJvbSAnLi90aGVtZS5zZXJ2aWNlJztcblxuZXhwb3J0IGludGVyZmFjZSBUb2xsZUNvbmZpZyB7XG4gIHByaW1hcnlDb2xvcj86IHN0cmluZztcbiAgcmFkaXVzPzogc3RyaW5nO1xuICBkZWZhdWx0VG9hc3REdXJhdGlvbj86IG51bWJlcjtcbiAgZGFya0J5RGVmYXVsdD86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBjb25zdCBUT0xMRV9DT05GSUcgPSBuZXcgSW5qZWN0aW9uVG9rZW48VG9sbGVDb25maWc+KCdUb2xsZUNvbmZpZycpO1xuXG5leHBvcnQgZnVuY3Rpb24gcHJvdmlkZVRvbGxlQ29uZmlnKGNvbmZpZzogVG9sbGVDb25maWcpOiBQcm92aWRlcltdIHtcbiAgcmV0dXJuIFtcbiAgICB7IHByb3ZpZGU6IFRPTExFX0NPTkZJRywgdXNlVmFsdWU6IGNvbmZpZyB9LFxuICAgIHtcbiAgICAgIHByb3ZpZGU6IEFQUF9JTklUSUFMSVpFUixcbiAgICAgIHVzZUZhY3Rvcnk6ICh0aGVtZVNlcnZpY2U6IFRoZW1lU2VydmljZSkgPT4gKCkgPT4gdGhlbWVTZXJ2aWNlLCAvLyBKdXN0IGZvcmNlIGluamVjdGlvblxuICAgICAgZGVwczogW1RoZW1lU2VydmljZV0sXG4gICAgICBtdWx0aTogdHJ1ZVxuICAgIH1cbiAgXTtcbn1cbiJdfQ==
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { clsx } from 'clsx';
|
|
2
2
|
import { twMerge } from 'tailwind-merge';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { Component, Input, forwardRef, Injectable, Optional, HostListener, ViewChild, ContentChildren, EventEmitter, Output, Directive, InjectionToken, inject, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector } from '@angular/core';
|
|
4
|
+
import { Component, Input, forwardRef, Injectable, Optional, HostListener, ViewChild, ContentChildren, EventEmitter, Output, Directive, PLATFORM_ID, Inject, InjectionToken, APP_INITIALIZER, inject, ChangeDetectorRef, ChangeDetectionStrategy, TemplateRef, Injector } from '@angular/core';
|
|
5
5
|
import * as i1 from '@angular/common';
|
|
6
|
-
import { CommonModule } from '@angular/common';
|
|
6
|
+
import { CommonModule, isPlatformBrowser, DOCUMENT } from '@angular/common';
|
|
7
7
|
import { cva } from 'class-variance-authority';
|
|
8
8
|
import * as i2 from '@angular/forms';
|
|
9
9
|
import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
|
|
10
10
|
import { autoUpdate, computePosition, offset, flip, shift } from '@floating-ui/dom';
|
|
11
|
-
import { Subject, Subscription } from 'rxjs';
|
|
11
|
+
import { Subject, Subscription, BehaviorSubject } from 'rxjs';
|
|
12
12
|
import { startOfWeek, startOfMonth, endOfWeek, endOfMonth, eachDayOfInterval, subMonths, subYears, addMonths, addYears, isSameMonth, setMonth, setYear, isSameDay, isToday, isBefore, startOfDay, parse, isValid, format, isWithinInterval } from 'date-fns';
|
|
13
13
|
import * as i1$1 from '@angular/cdk/overlay';
|
|
14
14
|
import { OverlayConfig } from '@angular/cdk/overlay';
|
|
@@ -1137,12 +1137,92 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
1137
1137
|
args: [{ providedIn: 'root' }]
|
|
1138
1138
|
}], ctorParameters: () => [] });
|
|
1139
1139
|
|
|
1140
|
+
class ThemeService {
|
|
1141
|
+
document;
|
|
1142
|
+
platformId;
|
|
1143
|
+
config;
|
|
1144
|
+
renderer;
|
|
1145
|
+
isDarkSubject = new BehaviorSubject(false);
|
|
1146
|
+
isDark$ = this.isDarkSubject.asObservable();
|
|
1147
|
+
constructor(document, platformId, config, rendererFactory) {
|
|
1148
|
+
this.document = document;
|
|
1149
|
+
this.platformId = platformId;
|
|
1150
|
+
this.config = config;
|
|
1151
|
+
this.renderer = rendererFactory.createRenderer(null, null);
|
|
1152
|
+
this.initializeTheme();
|
|
1153
|
+
}
|
|
1154
|
+
initializeTheme() {
|
|
1155
|
+
if (!isPlatformBrowser(this.platformId))
|
|
1156
|
+
return;
|
|
1157
|
+
// 1. Determine Initial Mode (Dark/Light)
|
|
1158
|
+
const savedTheme = localStorage.getItem('tolle-theme');
|
|
1159
|
+
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
1160
|
+
// Priority: Saved Preference > Config Default > System Preference
|
|
1161
|
+
const shouldBeDark = savedTheme
|
|
1162
|
+
? savedTheme === 'dark'
|
|
1163
|
+
: (this.config?.darkByDefault ?? prefersDark);
|
|
1164
|
+
if (shouldBeDark) {
|
|
1165
|
+
this.enableDarkMode();
|
|
1166
|
+
}
|
|
1167
|
+
else {
|
|
1168
|
+
this.disableDarkMode();
|
|
1169
|
+
}
|
|
1170
|
+
// 2. Apply Brand Config (Colors/Radius)
|
|
1171
|
+
if (this.config) {
|
|
1172
|
+
this.applyBrandConfig(this.config);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
applyBrandConfig(config) {
|
|
1176
|
+
const root = this.document.documentElement;
|
|
1177
|
+
if (config.primaryColor) {
|
|
1178
|
+
this.renderer.setStyle(root, '--primary', config.primaryColor);
|
|
1179
|
+
}
|
|
1180
|
+
if (config.radius) {
|
|
1181
|
+
this.renderer.setStyle(root, '--radius', config.radius);
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
toggleTheme() {
|
|
1185
|
+
const isDark = this.document.documentElement.classList.contains('dark');
|
|
1186
|
+
isDark ? this.disableDarkMode() : this.enableDarkMode();
|
|
1187
|
+
}
|
|
1188
|
+
enableDarkMode() {
|
|
1189
|
+
this.renderer.addClass(this.document.documentElement, 'dark');
|
|
1190
|
+
localStorage.setItem('tolle-theme', 'dark');
|
|
1191
|
+
this.isDarkSubject.next(true);
|
|
1192
|
+
}
|
|
1193
|
+
disableDarkMode() {
|
|
1194
|
+
this.renderer.removeClass(this.document.documentElement, 'dark');
|
|
1195
|
+
localStorage.setItem('tolle-theme', 'light');
|
|
1196
|
+
this.isDarkSubject.next(false);
|
|
1197
|
+
}
|
|
1198
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, deps: [{ token: DOCUMENT }, { token: PLATFORM_ID }, { token: TOLLE_CONFIG, optional: true }, { token: i0.RendererFactory2 }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1199
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, providedIn: 'root' });
|
|
1200
|
+
}
|
|
1201
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: ThemeService, decorators: [{
|
|
1202
|
+
type: Injectable,
|
|
1203
|
+
args: [{ providedIn: 'root' }]
|
|
1204
|
+
}], ctorParameters: () => [{ type: Document, decorators: [{
|
|
1205
|
+
type: Inject,
|
|
1206
|
+
args: [DOCUMENT]
|
|
1207
|
+
}] }, { type: Object, decorators: [{
|
|
1208
|
+
type: Inject,
|
|
1209
|
+
args: [PLATFORM_ID]
|
|
1210
|
+
}] }, { type: undefined, decorators: [{
|
|
1211
|
+
type: Optional
|
|
1212
|
+
}, {
|
|
1213
|
+
type: Inject,
|
|
1214
|
+
args: [TOLLE_CONFIG]
|
|
1215
|
+
}] }, { type: i0.RendererFactory2 }] });
|
|
1216
|
+
|
|
1140
1217
|
const TOLLE_CONFIG = new InjectionToken('TolleConfig');
|
|
1141
1218
|
function provideTolleConfig(config) {
|
|
1142
1219
|
return [
|
|
1220
|
+
{ provide: TOLLE_CONFIG, useValue: config },
|
|
1143
1221
|
{
|
|
1144
|
-
provide:
|
|
1145
|
-
|
|
1222
|
+
provide: APP_INITIALIZER,
|
|
1223
|
+
useFactory: (themeService) => () => themeService, // Just force injection
|
|
1224
|
+
deps: [ThemeService],
|
|
1225
|
+
multi: true
|
|
1146
1226
|
}
|
|
1147
1227
|
];
|
|
1148
1228
|
}
|