@reforgium/presentia 1.0.0 → 1.0.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.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { InjectionToken, signal, computed, inject, afterRenderEffect, Injectable, input, TemplateRef, ViewContainerRef, effect, Directive, Pipe, makeEnvironmentProviders, LOCALE_ID, DestroyRef } from '@angular/core';
|
|
3
|
-
import { SELECTED_LANG, SELECTED_THEME, CURRENT_DEVICE, deepEqual } from '@reforgium/internal';
|
|
3
|
+
import { TRANSLATION, SELECTED_LANG, SELECTED_THEME, CURRENT_DEVICE, deepEqual } from '@reforgium/internal';
|
|
4
4
|
import { BreakpointObserver } from '@angular/cdk/layout';
|
|
5
5
|
import { fromEvent, debounceTime, startWith, filter as filter$1, map } from 'rxjs';
|
|
6
6
|
import { HttpClient } from '@angular/common/http';
|
|
@@ -9,67 +9,100 @@ import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
|
|
|
9
9
|
import { filter } from 'rxjs/operators';
|
|
10
10
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Default breakpoints for device type detection.
|
|
14
|
+
*
|
|
15
|
+
* Defines media queries for each device category:
|
|
16
|
+
* - `mobile` — screens up to 719px wide
|
|
17
|
+
* - `tablet` — screens from 720px to 1399px wide
|
|
18
|
+
* - `desktop-s` — small desktop screens from 1400px to 1919px wide
|
|
19
|
+
* - `desktop` — large desktop screens 1920px and wider
|
|
20
|
+
*
|
|
21
|
+
* These breakpoints are used by `AdaptiveService` to determine the current device type.
|
|
22
|
+
*/
|
|
12
23
|
const defaultBreakpoints = {
|
|
13
24
|
'mobile': '(max-width: 719px)',
|
|
14
25
|
'tablet': '(min-width: 720px) and (max-width: 1399px)',
|
|
15
26
|
'desktop-s': '(min-width: 1400px) and (max-width: 1919px)',
|
|
16
27
|
'desktop': '(min-width: 1920px)',
|
|
17
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Injection token for providing custom device breakpoints.
|
|
31
|
+
*
|
|
32
|
+
* By default, provides `defaultBreakpoints`, but can be overridden
|
|
33
|
+
* at any level of the dependency injection tree to customize
|
|
34
|
+
* the device detection behavior.
|
|
35
|
+
*
|
|
36
|
+
* Example of overriding:
|
|
37
|
+
* ```typescript
|
|
38
|
+
* {
|
|
39
|
+
* provide: DEVICE_BREAKPOINTS,
|
|
40
|
+
* useValue: {
|
|
41
|
+
* mobile: '(max-width: 599px)',
|
|
42
|
+
* tablet: '(min-width: 600px) and (max-width: 1199px)',
|
|
43
|
+
* 'desktop-s': '(min-width: 1200px) and (max-width: 1799px)',
|
|
44
|
+
* desktop: '(min-width: 1800px)'
|
|
45
|
+
* }
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* Used by `AdaptiveService` to observe media query changes.
|
|
50
|
+
*/
|
|
18
51
|
const DEVICE_BREAKPOINTS = new InjectionToken('RE_DEVICE_BREAKPOINTS', {
|
|
19
52
|
providedIn: 'root',
|
|
20
53
|
factory: () => defaultBreakpoints,
|
|
21
54
|
});
|
|
22
55
|
|
|
23
56
|
/**
|
|
24
|
-
*
|
|
57
|
+
* The `AdaptiveService` is responsible for determining the device type, window dimensions, and screen orientation.
|
|
25
58
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
59
|
+
* Used for building adaptive interfaces, changing component behavior and styles
|
|
60
|
+
* depending on the current device or screen size.
|
|
28
61
|
*
|
|
29
|
-
*
|
|
30
|
-
* -
|
|
31
|
-
* -
|
|
32
|
-
* -
|
|
62
|
+
* Main features:
|
|
63
|
+
* - Reactive tracking of the current device (`desktop`, `tablet`, `mobile`).
|
|
64
|
+
* - Support for computed properties (`isDesktop`, `isPortrait`).
|
|
65
|
+
* - Automatic updates when the window is resized and breakpoints are crossed.
|
|
33
66
|
*
|
|
34
|
-
*
|
|
35
|
-
* - `BreakpointObserver`
|
|
36
|
-
* - `signal`
|
|
37
|
-
* - `fromEvent(window, 'resize')` —
|
|
67
|
+
* Implementation is based on:
|
|
68
|
+
* - `BreakpointObserver` from Angular CDK — for observing media queries.
|
|
69
|
+
* - `signal` and `computed` — for reactive state without zones.
|
|
70
|
+
* - `fromEvent(window, 'resize')` — for updating window dimensions with debouncing.
|
|
38
71
|
*
|
|
39
|
-
*
|
|
72
|
+
* The service is registered as `providedIn: 'root'` and is available throughout the application.
|
|
40
73
|
*/
|
|
41
74
|
class AdaptiveService {
|
|
42
|
-
/** @internal
|
|
75
|
+
/** @internal Signal of the current device type. */
|
|
43
76
|
#device = signal('desktop', ...(ngDevMode ? [{ debugName: "#device" }] : []));
|
|
44
|
-
/** @internal
|
|
77
|
+
/** @internal Signals of the current window width and height. */
|
|
45
78
|
#width = signal(0, ...(ngDevMode ? [{ debugName: "#width" }] : []));
|
|
46
79
|
#height = signal(0, ...(ngDevMode ? [{ debugName: "#height" }] : []));
|
|
47
80
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
81
|
+
* Current device type (reactive signal).
|
|
82
|
+
* Possible values: `'desktop' | 'tablet' | 'mobile'`.
|
|
50
83
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
84
|
+
* Updates automatically when screen width changes
|
|
85
|
+
* or when specified breakpoints are crossed (`DEVICE_BREAKPOINTS`).
|
|
53
86
|
*/
|
|
54
87
|
device = this.#device.asReadonly();
|
|
55
88
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
89
|
+
* Current browser window width in pixels.
|
|
90
|
+
* Updates reactively on `resize` event.
|
|
58
91
|
*/
|
|
59
92
|
width = this.#width.asReadonly();
|
|
60
93
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
94
|
+
* Current browser window height in pixels.
|
|
95
|
+
* Updates reactively on `resize` event.
|
|
63
96
|
*/
|
|
64
97
|
height = this.#height.asReadonly();
|
|
65
98
|
/**
|
|
66
|
-
*
|
|
67
|
-
*
|
|
99
|
+
* Computed signal indicating whether the current device is a desktop.
|
|
100
|
+
* Used for conditional rendering or layout configuration.
|
|
68
101
|
*/
|
|
69
102
|
isDesktop = computed(() => this.#device() === 'desktop', ...(ngDevMode ? [{ debugName: "isDesktop" }] : []));
|
|
70
103
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
104
|
+
* Computed signal determining whether the screen is in portrait orientation.
|
|
105
|
+
* Returns `true` if window height is greater than width.
|
|
73
106
|
*/
|
|
74
107
|
isPortrait = computed(() => this.#height() > this.#width(), ...(ngDevMode ? [{ debugName: "isPortrait" }] : []));
|
|
75
108
|
deviceBreakpoints = inject(DEVICE_BREAKPOINTS);
|
|
@@ -102,24 +135,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
102
135
|
}], ctorParameters: () => [] });
|
|
103
136
|
|
|
104
137
|
/**
|
|
105
|
-
*
|
|
138
|
+
* Structural directive `*ssIfDevice`.
|
|
106
139
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
140
|
+
* Shows or hides an element based on the current device type,
|
|
141
|
+
* as determined by `AdaptiveService`.
|
|
109
142
|
*
|
|
110
|
-
*
|
|
143
|
+
* Example:
|
|
111
144
|
* ```html
|
|
112
|
-
* <div *ssIfDevice="'desktop'"
|
|
113
|
-
* <div *ssIfDevice="['mobile', 'tablet']"
|
|
114
|
-
* <div *ssIfDevice="'mobile'; inverse: true"
|
|
145
|
+
* <div *ssIfDevice="'desktop'">Desktop only</div>
|
|
146
|
+
* <div *ssIfDevice="['mobile', 'tablet']">For mobile and tablets</div>
|
|
147
|
+
* <div *ssIfDevice="'mobile'; inverse: true"> Hide on mobile</div>
|
|
115
148
|
* ```
|
|
116
149
|
*
|
|
117
|
-
*
|
|
118
|
-
* - `ssIfDevice` —
|
|
119
|
-
* - `inverse` —
|
|
150
|
+
* Parameters:
|
|
151
|
+
* - `ssIfDevice` — one or more `Devices` values (`'desktop' | 'tablet' | 'mobile'`)
|
|
152
|
+
* - `inverse` — inverts the display condition
|
|
120
153
|
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
154
|
+
* Works reactively: when the device type changes in `AdaptiveService`,
|
|
155
|
+
* the template is automatically added or removed from the DOM.
|
|
123
156
|
*/
|
|
124
157
|
class IfDeviceDirective {
|
|
125
158
|
device = input(undefined, { ...(ngDevMode ? { debugName: "device" } : {}), alias: 'ssIfDevice' });
|
|
@@ -162,10 +195,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
162
195
|
}]
|
|
163
196
|
}], ctorParameters: () => [], propDecorators: { device: [{ type: i0.Input, args: [{ isSignal: true, alias: "ssIfDevice", required: false }] }], inverse: [{ type: i0.Input, args: [{ isSignal: true, alias: "inverse", required: false }] }] } });
|
|
164
197
|
|
|
165
|
-
const LANG_CONFIG = new InjectionToken('RE_LANG_CONFIG');
|
|
166
|
-
|
|
167
198
|
const innerLangVal = Symbol('reInnerLangVal');
|
|
168
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Injection token for providing locale configuration to the language module.
|
|
202
|
+
*
|
|
203
|
+
* Used to inject `LocaleConfig` into services and components that require
|
|
204
|
+
* internationalization settings (e.g., locale, date formats, translations).
|
|
205
|
+
*
|
|
206
|
+
* Example:
|
|
207
|
+
* ```typescript
|
|
208
|
+
* providers: [
|
|
209
|
+
* { provide: LANG_CONFIG, useValue: { locale: 'ru', ... } }
|
|
210
|
+
* ]
|
|
211
|
+
* ```
|
|
212
|
+
*
|
|
213
|
+
* The token can be injected using Angular's DI system:
|
|
214
|
+
* ```typescript
|
|
215
|
+
* private config = inject(LANG_CONFIG);
|
|
216
|
+
* ```
|
|
217
|
+
*/
|
|
218
|
+
const LANG_CONFIG = new InjectionToken('RE_LANG_CONFIG');
|
|
219
|
+
|
|
169
220
|
/**
|
|
170
221
|
* LangService provides functionality for managing and tracking language settings
|
|
171
222
|
* and translations in the application. It is designed to handle localization needs,
|
|
@@ -185,11 +236,11 @@ class LangService {
|
|
|
185
236
|
* - If private method `#lang` returns 'ru', this property will return 'ru'.
|
|
186
237
|
* - If `#lang` returns another value, the `config.kgValue` property is checked:
|
|
187
238
|
* - If `config.kgValue` is defined, the property will return its value.
|
|
188
|
-
* - If `config.kgValue` is not defined, the property will return default value 'kg'.
|
|
239
|
+
* - If `config.kgValue` is not defined, the property will return the default value 'kg'.
|
|
189
240
|
*/
|
|
190
241
|
currentLang = computed(() => {
|
|
191
242
|
const lang = this.#lang();
|
|
192
|
-
return lang === 'ru' ? 'ru' : (this.config
|
|
243
|
+
return lang === 'ru' ? 'ru' : (this.config?.kgValue ?? 'kg');
|
|
193
244
|
}, ...(ngDevMode ? [{ debugName: "currentLang" }] : []));
|
|
194
245
|
/**
|
|
195
246
|
* Extracts readonly value from private property `#lang` and assigns it to `innerLangVal`.
|
|
@@ -214,12 +265,12 @@ class LangService {
|
|
|
214
265
|
}
|
|
215
266
|
}
|
|
216
267
|
/**
|
|
217
|
-
* Gets value based on provided query and optionally applies specified parameters.
|
|
268
|
+
* Gets value based on a provided query and optionally applies specified parameters.
|
|
218
269
|
*
|
|
219
270
|
* @param {string} query - Query string used to retrieve desired value.
|
|
220
271
|
* @param {LangParams} [params] - Optional parameters to apply to retrieved value.
|
|
221
272
|
* @return {string} Retrieved value after optional parameter application,
|
|
222
|
-
* or default value if query is not found.
|
|
273
|
+
* or default value if a query is not found.
|
|
223
274
|
*/
|
|
224
275
|
get(query, params) {
|
|
225
276
|
const value = this.getChainedValue(query);
|
|
@@ -229,13 +280,13 @@ class LangService {
|
|
|
229
280
|
return value ?? this.config.defaultValue ?? query;
|
|
230
281
|
}
|
|
231
282
|
/**
|
|
232
|
-
* Observes changes to specified translation key and dynamically computes its value.
|
|
283
|
+
* Observes changes to a specified translation key and dynamically computes its value.
|
|
233
284
|
*
|
|
234
285
|
* @param {string} query - Translation key to observe, typically in format "namespace.key".
|
|
235
286
|
* @param {LangParams} [params] - Optional parameters for interpolation or
|
|
236
287
|
* dynamic content replacement in translation value.
|
|
237
288
|
* @return {Signal<string>} Computed value that dynamically updates
|
|
238
|
-
* with translation matching provided query and parameters.
|
|
289
|
+
* with translation matching a provided query and parameters.
|
|
239
290
|
*/
|
|
240
291
|
observe(query, params) {
|
|
241
292
|
const [ns] = query.split('.');
|
|
@@ -248,8 +299,8 @@ class LangService {
|
|
|
248
299
|
* Loads specified namespace, ensuring its caching and availability for use.
|
|
249
300
|
*
|
|
250
301
|
* @param {string} ns - Namespace name to load.
|
|
251
|
-
* @return {Promise<void>} Promise that resolves on successful namespace load,
|
|
252
|
-
* or rejects when error occurs during process.
|
|
302
|
+
* @return {Promise<void>} Promise that resolves on a successful namespace load,
|
|
303
|
+
* or rejects when error occurs during a process.
|
|
253
304
|
*/
|
|
254
305
|
async loadNamespace(ns) {
|
|
255
306
|
const key = this.makeNamespaceKey(ns);
|
|
@@ -318,16 +369,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
318
369
|
}] });
|
|
319
370
|
|
|
320
371
|
/**
|
|
321
|
-
*
|
|
372
|
+
* Custom Angular pipe that transforms a language key and additional parameters into a localized string.
|
|
322
373
|
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
374
|
+
* The pipe is declared as standalone and impure — meaning it can be used without importing a module
|
|
375
|
+
* and will be recalculated when the state changes (for example, when the language is switched).
|
|
325
376
|
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
377
|
+
* In its operation, the pipe observes and caches language keys to improve performance,
|
|
378
|
+
* using LangService to retrieve translated strings based on the current application language.
|
|
328
379
|
*
|
|
329
|
-
*
|
|
330
|
-
*
|
|
380
|
+
* The transformation involves accepting a key string and optional parameters,
|
|
381
|
+
* forming a cache key, and returning the localized value corresponding to that request.
|
|
331
382
|
*
|
|
332
383
|
* @implements {PipeTransform}
|
|
333
384
|
*/
|
|
@@ -349,22 +400,76 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
349
400
|
args: [{ name: 'lang', standalone: true, pure: false }]
|
|
350
401
|
}] });
|
|
351
402
|
|
|
403
|
+
/**
|
|
404
|
+
* Type-safe mapping of available theme names.
|
|
405
|
+
*
|
|
406
|
+
* Provides a constant record that maps theme identifiers to their corresponding string values.
|
|
407
|
+
* This ensures compile-time safety when referencing theme names throughout the application.
|
|
408
|
+
*
|
|
409
|
+
* Available themes:
|
|
410
|
+
* - `light` - Light theme variant
|
|
411
|
+
* - `dark` - Dark theme variant
|
|
412
|
+
*
|
|
413
|
+
* @example
|
|
414
|
+
* ```typescript
|
|
415
|
+
* const currentTheme = themes.light; // 'light'
|
|
416
|
+
* const isDarkTheme = theme === themes.dark;
|
|
417
|
+
* ```
|
|
418
|
+
*/
|
|
352
419
|
const themes = {
|
|
353
420
|
light: 'light',
|
|
354
421
|
dark: 'dark',
|
|
355
422
|
};
|
|
423
|
+
/**
|
|
424
|
+
* CSS class prefix used for dark theme styling.
|
|
425
|
+
*
|
|
426
|
+
* This constant defines the prefix applied to HTML elements when the dark theme is active.
|
|
427
|
+
* It is typically added to the root element or specific components to enable dark theme styles.
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* ```typescript
|
|
431
|
+
* document.body.classList.add(darkThemePrefix); // Applies 're-dark' class
|
|
432
|
+
* ```
|
|
433
|
+
*/
|
|
356
434
|
const darkThemePrefix = 're-dark';
|
|
357
435
|
|
|
436
|
+
/**
|
|
437
|
+
* Default theme configuration object.
|
|
438
|
+
*
|
|
439
|
+
* Defines the initial theme settings for the application.
|
|
440
|
+
* By default, sets the light theme as the active theme.
|
|
441
|
+
*
|
|
442
|
+
* This configuration can be overridden when providing `THEME_CONFIG` token
|
|
443
|
+
* at the module or application level.
|
|
444
|
+
* ```
|
|
445
|
+
*/
|
|
358
446
|
const defaultThemeConfig = {
|
|
359
447
|
defaultTheme: themes.light,
|
|
360
448
|
};
|
|
449
|
+
/**
|
|
450
|
+
* Injection token for theme configuration.
|
|
451
|
+
*
|
|
452
|
+
* Used to provide custom theme settings via Angular's dependency injection system.
|
|
453
|
+
* The token expects a value of type `ThemeConfig`.
|
|
454
|
+
*
|
|
455
|
+
* Example usage:
|
|
456
|
+
* ```typescript
|
|
457
|
+
* // In providers array:
|
|
458
|
+
* { provide: THEME_CONFIG, useValue: { defaultTheme: themes.dark } }
|
|
459
|
+
*
|
|
460
|
+
* // In service or component:
|
|
461
|
+
* private themeConfig = inject(THEME_CONFIG);
|
|
462
|
+
* ```
|
|
463
|
+
*
|
|
464
|
+
* If not provided, `defaultThemeConfig` will be used as fallback.
|
|
465
|
+
*/
|
|
361
466
|
const THEME_CONFIG = new InjectionToken('RE_THEME_CONFIG');
|
|
362
467
|
|
|
363
468
|
/**
|
|
364
469
|
* Service for managing application theme.
|
|
365
470
|
*
|
|
366
471
|
* Allows getting the current theme and switching between light and dark.
|
|
367
|
-
* Automatically saves selected theme to `localStorage` and applies CSS class to `<html>` element.
|
|
472
|
+
* Automatically saves the selected theme to `localStorage` and applies CSS class to `<html>` element.
|
|
368
473
|
*
|
|
369
474
|
* Example:
|
|
370
475
|
* ```ts
|
|
@@ -402,8 +507,8 @@ class ThemeService {
|
|
|
402
507
|
/**
|
|
403
508
|
* Switches theme.
|
|
404
509
|
*
|
|
405
|
-
* If parameter is not provided — performs toggle between `light` and `dark`.
|
|
406
|
-
* Also automatically updates `<html>` class and saves selection to `localStorage`.
|
|
510
|
+
* If a parameter is not provided — performs toggle between `light` and `dark`.
|
|
511
|
+
* Also, automatically updates `<html>` class and saves selection to `localStorage`.
|
|
407
512
|
*
|
|
408
513
|
* @param theme — explicit theme value (`'light'` or `'dark'`).
|
|
409
514
|
*/
|
|
@@ -424,8 +529,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
424
529
|
}]
|
|
425
530
|
}], ctorParameters: () => [] });
|
|
426
531
|
|
|
532
|
+
/**
|
|
533
|
+
* Provides environment-level providers for Presentia application initialization.
|
|
534
|
+
*
|
|
535
|
+
* This function configures essential application services:
|
|
536
|
+
* - Language and localization settings
|
|
537
|
+
* - Theme configuration
|
|
538
|
+
* - Adaptive/responsive breakpoints
|
|
539
|
+
* - Current device detection
|
|
540
|
+
*
|
|
541
|
+
* @param {AppConfig} config - Configuration object containing locale, theme, and breakpoints settings.
|
|
542
|
+
* @returns {EnvironmentProviders} A collection of Angular providers for the application environment.
|
|
543
|
+
*
|
|
544
|
+
* @example
|
|
545
|
+
* ```typescript
|
|
546
|
+
* export const appConfig: ApplicationConfig = {
|
|
547
|
+
* providers: [
|
|
548
|
+
* provideReInit({
|
|
549
|
+
* locale: { defaultLang: 'en', supportedLangs: ['en', 'ru'] },
|
|
550
|
+
* theme: { defaultTheme: 'dark' },
|
|
551
|
+
* breakpoints: { mobile: 768, tablet: 1024 }
|
|
552
|
+
* })
|
|
553
|
+
* ]
|
|
554
|
+
* };
|
|
555
|
+
* ```
|
|
556
|
+
*/
|
|
427
557
|
function provideReInit(config) {
|
|
428
558
|
return makeEnvironmentProviders([
|
|
559
|
+
{ provide: TRANSLATION, deps: [LangService], useFactory: (ls) => ls },
|
|
429
560
|
{ provide: SELECTED_LANG, deps: [LangService], useFactory: (ls) => ls[innerLangVal] },
|
|
430
561
|
{ provide: SELECTED_THEME, deps: [ThemeService], useFactory: (ls) => ls.theme },
|
|
431
562
|
{ provide: CURRENT_DEVICE, deps: [AdaptiveService], useFactory: (ls) => ls.device },
|
|
@@ -546,11 +677,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.3", ngImpor
|
|
|
546
677
|
type: Injectable
|
|
547
678
|
}] });
|
|
548
679
|
|
|
680
|
+
/**
|
|
681
|
+
* Service that listens to Angular route changes and automatically updates SEO metadata
|
|
682
|
+
* (title, description, Open Graph, Twitter cards, JSON-LD, canonical URL, robots meta tag)
|
|
683
|
+
* based on route data configuration.
|
|
684
|
+
*
|
|
685
|
+
* @example
|
|
686
|
+
* ```typescript
|
|
687
|
+
* const routes: Routes = [{
|
|
688
|
+
* path: 'about',
|
|
689
|
+
* component: AboutComponent,
|
|
690
|
+
* data: {
|
|
691
|
+
* title: 'About Us',
|
|
692
|
+
* description: 'Learn more about our company',
|
|
693
|
+
* robots: 'index,follow'
|
|
694
|
+
* }
|
|
695
|
+
* }];
|
|
696
|
+
* ```
|
|
697
|
+
*/
|
|
549
698
|
class SeoRouteListener {
|
|
550
699
|
router = inject(Router);
|
|
551
700
|
seo = inject(SeoService);
|
|
552
701
|
ar = inject(ActivatedRoute);
|
|
553
702
|
destroyRef = inject(DestroyRef);
|
|
703
|
+
/**
|
|
704
|
+
* Initializes the route listener to monitor navigation events and update SEO metadata.
|
|
705
|
+
* Subscribes to router NavigationEnd events and automatically unsubscribes on component destruction.
|
|
706
|
+
*
|
|
707
|
+
* @param baseUrl - The base URL of the application used for constructing canonical URLs.
|
|
708
|
+
* Trailing slashes will be removed automatically.
|
|
709
|
+
*/
|
|
554
710
|
init(baseUrl) {
|
|
555
711
|
const sub = this.router.events.pipe(filter((e) => e instanceof NavigationEnd)).subscribe(() => {
|
|
556
712
|
const route = this.deepest(this.ar);
|
|
@@ -571,6 +727,13 @@ class SeoRouteListener {
|
|
|
571
727
|
});
|
|
572
728
|
this.destroyRef.onDestroy(() => sub.unsubscribe());
|
|
573
729
|
}
|
|
730
|
+
/**
|
|
731
|
+
* Recursively finds the deepest (most nested) activated route in the route tree.
|
|
732
|
+
* This is used to extract route data from the currently active leaf route.
|
|
733
|
+
*
|
|
734
|
+
* @param r - The root activated route to start traversing from.
|
|
735
|
+
* @returns The deepest child route in the hierarchy.
|
|
736
|
+
*/
|
|
574
737
|
deepest(r) {
|
|
575
738
|
let cur = r;
|
|
576
739
|
while (cur.firstChild) {
|
|
@@ -667,5 +830,5 @@ function joinUrl(segments) {
|
|
|
667
830
|
* Generated bundle index. Do not edit.
|
|
668
831
|
*/
|
|
669
832
|
|
|
670
|
-
export { AdaptiveService, DEVICE_BREAKPOINTS, IfDeviceDirective, LANG_CONFIG, LangPipe, LangService, RouteWatcher, SeoRouteListener, SeoService, THEME_CONFIG, ThemeService, darkThemePrefix, defaultBreakpoints, defaultThemeConfig, provideReInit, themes };
|
|
833
|
+
export { AdaptiveService, DEVICE_BREAKPOINTS, IfDeviceDirective, LANG_CONFIG, LangPipe, LangService, RouteWatcher, SeoRouteListener, SeoService, THEME_CONFIG, ThemeService, darkThemePrefix, defaultBreakpoints, defaultThemeConfig, innerLangVal, provideReInit, themes };
|
|
671
834
|
//# sourceMappingURL=reforgium-presentia.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reforgium-presentia.mjs","sources":["../../../../libs/presentia/src/adaptive/adaptive.provider.ts","../../../../libs/presentia/src/adaptive/adaptive.service.ts","../../../../libs/presentia/src/adaptive/device-type.directive.ts","../../../../libs/presentia/src/lang/locale.provider.ts","../../../../libs/presentia/src/lang/lang.models.ts","../../../../libs/presentia/src/lang/lang.service.ts","../../../../libs/presentia/src/lang/lang.pipe.ts","../../../../libs/presentia/src/theme/themes.constant.ts","../../../../libs/presentia/src/theme/theme.provider.ts","../../../../libs/presentia/src/theme/theme.service.ts","../../../../libs/presentia/src/providers/init.provider.ts","../../../../libs/presentia/src/seo/seo.service.ts","../../../../libs/presentia/src/seo/seo-route.listener.ts","../../../../libs/presentia/src/routes/route-watcher.service.ts","../../../../libs/presentia/src/reforgium-presentia.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\n\r\nimport { DeviceBreakpoints } from './adaptive.models';\r\n\r\nexport const defaultBreakpoints = {\r\n 'mobile': '(max-width: 719px)',\r\n 'tablet': '(min-width: 720px) and (max-width: 1399px)',\r\n 'desktop-s': '(min-width: 1400px) and (max-width: 1919px)',\r\n 'desktop': '(min-width: 1920px)',\r\n};\r\nexport const DEVICE_BREAKPOINTS = new InjectionToken<DeviceBreakpoints>('RE_DEVICE_BREAKPOINTS', {\r\n providedIn: 'root',\r\n factory: () => defaultBreakpoints,\r\n});\r\n","import { BreakpointObserver } from '@angular/cdk/layout';\nimport { afterRenderEffect, computed, inject, Injectable, signal } from '@angular/core';\nimport { debounceTime, fromEvent } from 'rxjs';\n\nimport { Devices } from '@reforgium/internal';\n\n// noinspection ES6PreferShortImport\nimport { DEVICE_BREAKPOINTS } from './adaptive.provider';\n\n/**\n * Сервис `AdaptiveService` отвечает за определение типа устройства, размеров окна и ориентации экрана.\n *\n * Используется для построения адаптивных интерфейсов, изменения поведения компонентов и стилей\n * в зависимости от текущего устройства или размера экрана.\n *\n * Основные возможности:\n * - Реактивное отслеживание текущего устройства (`desktop`, `tablet`, `mobile`).\n * - Поддержка вычисляемых признаков (`isDesktop`, `isPortrait`).\n * - Автоматическое обновление при изменении размера окна и пересечении брейкпоинтов.\n *\n * Реализация основана на:\n * - `BreakpointObserver` из Angular CDK — для наблюдения за медиа-запросами.\n * - `signal` и `computed` — для реактивного состояния без зон.\n * - `fromEvent(window, 'resize')` — для обновления размеров окна с дебаунсом.\n *\n * Сервис зарегистрирован как `providedIn: 'root'` и доступен во всём приложении.\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class AdaptiveService {\n /** @internal Сигнал текущего типа устройства. */\n #device = signal<Devices>('desktop');\n\n /** @internal Сигналы текущей ширины и высоты окна. */\n #width = signal(0);\n #height = signal(0);\n\n /**\n * Текущий тип устройства (reactive signal).\n * Возможные значения: `'desktop' | 'tablet' | 'mobile'`.\n *\n * Обновляется автоматически при изменении ширины экрана\n * или при пересечении заданных брейкпоинтов (`DEVICE_BREAKPOINTS`).\n */\n device = this.#device.asReadonly();\n\n /**\n * Текущая ширина окна браузера в пикселях.\n * Обновляется реактивно при событии `resize`.\n */\n width = this.#width.asReadonly();\n\n /**\n * Текущая высота окна браузера в пикселях.\n * Обновляется реактивно при событии `resize`.\n */\n height = this.#height.asReadonly();\n\n /**\n * Вычисляемый сигнал, показывающий, является ли текущее устройство десктопом.\n * Используется для условного рендера или настройки макета.\n */\n isDesktop = computed(() => this.#device() === 'desktop');\n\n /**\n * Вычисляемый сигнал, определяющий, находится ли экран в портретной ориентации.\n * Возвращает `true`, если высота окна больше ширины.\n */\n isPortrait = computed(() => this.#height() > this.#width());\n\n private deviceBreakpoints = inject(DEVICE_BREAKPOINTS);\n private devicePriority: Devices[] = Object.keys(this.deviceBreakpoints) as Devices[];\n\n private breakpointObserver = inject(BreakpointObserver);\n\n constructor() {\n afterRenderEffect(() => {\n this.#width.set(window.innerWidth);\n this.#height.set(window.innerHeight);\n });\n\n this.breakpointObserver.observe(Object.values(this.deviceBreakpoints)).subscribe((state) => {\n const device = this.devicePriority.find((key) => state.breakpoints[this.deviceBreakpoints[key]]);\n\n this.#device.set(device ?? 'desktop');\n });\n fromEvent(window, 'resize')\n .pipe(debounceTime(100))\n .subscribe(() => {\n this.#width.set(window.innerWidth);\n this.#height.set(window.innerHeight);\n });\n }\n}\n","import { Directive, effect, inject, input, Signal, TemplateRef, ViewContainerRef } from '@angular/core';\n\nimport { Devices } from '@reforgium/internal';\n\n// noinspection ES6PreferShortImport\nimport { AdaptiveService } from './adaptive.service';\n\n/**\n * Структурная директива `*ssIfDevice`.\n *\n * Показывает или скрывает элемент в зависимости от текущего устройства,\n * определяемого через `AdaptiveService`.\n *\n * Пример:\n * ```html\n * <div *ssIfDevice=\"'desktop'\">Только для десктопа</div>\n * <div *ssIfDevice=\"['mobile', 'tablet']\">Для мобильных и планшетов</div>\n * <div *ssIfDevice=\"'mobile'; inverse: true\">Скрыть на мобильных</div>\n * ```\n *\n * Параметры:\n * - `ssIfDevice` — одно или несколько значений `Devices` (`'desktop' | 'tablet' | 'mobile'`)\n * - `inverse` — инвертирует условие показа\n *\n * Работает реактивно: при изменении типа устройства в `AdaptiveService`\n * шаблон автоматически добавляется или удаляется из DOM.\n */\n\n@Directive({\n selector: '[reIfDevice]',\n standalone: true,\n})\nexport class IfDeviceDirective {\n device = input<Devices | Devices[]>(undefined, { alias: 'ssIfDevice' });\n inverse = input<boolean>(false);\n\n private readonly tpl = inject(TemplateRef);\n private readonly vcr = inject(ViewContainerRef);\n private readonly adaptive = inject(AdaptiveService);\n\n private allowedDevices: Devices[] = [];\n private hasView = false;\n\n private readonly currentDevice: Signal<Devices> = this.adaptive.device;\n\n constructor() {\n effect(() => {\n const device = this.device();\n\n if (device) {\n this.allowedDevices = Array.isArray(device) ? device : [device];\n }\n\n this.updateView();\n });\n }\n\n private updateView() {\n const isAllowed = this.allowedDevices.includes(this.currentDevice());\n const shouldShow = this.inverse() ? !isAllowed : isAllowed;\n\n if (shouldShow && !this.hasView) {\n this.vcr.createEmbeddedView(this.tpl);\n this.hasView = true;\n } else if (!shouldShow && this.hasView) {\n this.vcr.clear();\n this.hasView = false;\n }\n }\n}\n","import { InjectionToken } from '@angular/core';\r\n\r\nimport { LocaleConfig } from './lang.models';\r\n\r\nexport const LANG_CONFIG = new InjectionToken<LocaleConfig>('RE_LANG_CONFIG');\r\n","import { Langs } from '@reforgium/internal';\n\n/**\n * Language data model from localization server\n *\n * @description\n * `Model` for translation data\n * `namespace` - git project name\n * `code` - masked query: ${page}.${recordKey}\n * `value` - translation value\n */\nexport interface LangDto {\n namespace: string;\n code: string;\n localization: string;\n}\n\n/**\n * Data model for translation\n *\n * @description\n * `key` - masked query: ${page}.${recordKey}\n * `value` - translation value or nested model\n */\nexport interface LangModel {\n [key: string]: string | LangModel;\n}\n\n/**\n * Parameters for text formatting\n *\n * @description\n * `key` - mask key\n * `value` - mask value\n * example: {{`key1`}} will be replaced with `value1`\n */\nexport type LangParams = Record<string, string>;\n\n/**\n * Represents configuration settings for localization.\n *\n * This interface is used to define the locale configuration structure,\n * which can include URL, resource origin information, default language,\n * and related values for regional or localization settings.\n *\n * Properties:\n * - `url` specifies the localization URL for loading resources.\n * - `isFromAssets` indicates whether resources are loaded from application assets.\n * - `defaultLang` defines optional default language for localization.\n * - `defaultValue` - optional default value for locale resource.\n * - `kgValue` specifies optional localization value with variants `kg` or `ky`.\n */\nexport interface LocaleConfig {\n url: string;\n isFromAssets: boolean;\n defaultLang?: Langs;\n defaultValue?: string;\n kgValue?: 'kg' | 'ky';\n}\n\nexport const innerLangVal = Symbol('reInnerLangVal');\n","import { HttpClient } from '@angular/common/http';\nimport { computed, inject, Injectable, Signal, signal } from '@angular/core';\n\nimport { Langs } from '@reforgium/internal';\n\nimport { innerLangVal, LangDto, LangModel, LangParams } from './lang.models';\n// noinspection ES6PreferShortImport\nimport { LANG_CONFIG } from './locale.provider';\n\n/**\n * LangService provides functionality for managing and tracking language settings\n * and translations in the application. It is designed to handle localization needs,\n * loading language resources, caching translations, and dynamically applying translations\n * throughout the application.\n */\n@Injectable({ providedIn: 'root' })\nexport class LangService {\n private readonly config = inject(LANG_CONFIG);\n private readonly http = inject(HttpClient);\n\n readonly #lang = signal<Langs>(this.getStoredLang());\n readonly #cache = signal<LangModel>({});\n\n readonly #loadedNamespaces = new Set<string>();\n readonly #pendingLoads = new Map<string, Promise<void>>();\n\n /**\n * Computed property determining the current language setting.\n *\n * - If private method `#lang` returns 'ru', this property will return 'ru'.\n * - If `#lang` returns another value, the `config.kgValue` property is checked:\n * - If `config.kgValue` is defined, the property will return its value.\n * - If `config.kgValue` is not defined, the property will return default value 'kg'.\n */\n readonly currentLang = computed(() => {\n const lang = this.#lang();\n\n return lang === 'ru' ? 'ru' : (this.config.kgValue ?? 'kg');\n });\n /**\n * Extracts readonly value from private property `#lang` and assigns it to `innerLangVal`.\n * Expected that property `#lang` has `asReadonly` method that returns immutable representation.\n */\n readonly [innerLangVal] = this.#lang.asReadonly();\n\n /**\n * Sets the current language for the application.\n *\n * @param {Langs | 'ky'} lang - The language to set.\n * Accepts predefined type `Langs` or 'ky' to set Kyrgyz language.\n * @return {void} Returns no value.\n */\n setLang(lang: Langs | 'ky'): void {\n const langVal = lang === 'ky' ? 'kg' : lang;\n\n if (langVal !== this.#lang()) {\n this.#lang.set(langVal);\n localStorage.setItem('lang', langVal);\n\n const namespaces = Array.from(this.#loadedNamespaces.values()).map((key) => key.split('.')[1]);\n\n this.#loadedNamespaces.clear();\n\n namespaces.forEach((ns) => void this.loadNamespace(ns));\n }\n }\n\n /**\n * Gets value based on provided query and optionally applies specified parameters.\n *\n * @param {string} query - Query string used to retrieve desired value.\n * @param {LangParams} [params] - Optional parameters to apply to retrieved value.\n * @return {string} Retrieved value after optional parameter application,\n * or default value if query is not found.\n */\n get(query: string, params?: LangParams): string {\n const value = this.getChainedValue(query);\n\n if (params) {\n return this.applyParams((value ?? query) as string, params);\n }\n\n return (value as string | undefined) ?? this.config.defaultValue ?? query;\n }\n\n /**\n * Observes changes to specified translation key and dynamically computes its value.\n *\n * @param {string} query - Translation key to observe, typically in format \"namespace.key\".\n * @param {LangParams} [params] - Optional parameters for interpolation or\n * dynamic content replacement in translation value.\n * @return {Signal<string>} Computed value that dynamically updates\n * with translation matching provided query and parameters.\n */\n observe(query: string, params?: LangParams): Signal<string> {\n const [ns] = query.split('.');\n\n if (!this.#loadedNamespaces.has(this.makeNamespaceKey(ns))) {\n void this.loadNamespace(ns);\n }\n\n return computed(() => this.get(query, params));\n }\n\n /**\n * Loads specified namespace, ensuring its caching and availability for use.\n *\n * @param {string} ns - Namespace name to load.\n * @return {Promise<void>} Promise that resolves on successful namespace load,\n * or rejects when error occurs during process.\n */\n async loadNamespace(ns: string): Promise<void> {\n const key = this.makeNamespaceKey(ns);\n\n if (this.#loadedNamespaces.has(key)) {\n return;\n }\n\n if (this.#pendingLoads.has(key)) {\n return this.#pendingLoads.get(key)!;\n }\n\n const promise = new Promise<void>((resolve, reject) => {\n this.http.get<LangDto[] | LangModel>(this.makeUrl(ns)).subscribe({\n next: (res) => {\n const existing = this.#cache();\n const resolved = Array.isArray(res) ? this.parseModelToRecord(res) : this.parseAssetToRecord(ns, res);\n\n this.#cache.set({ ...existing, ...resolved });\n this.#loadedNamespaces.add(key);\n resolve();\n },\n error: (err) => {\n this.#pendingLoads.delete(key);\n reject(err);\n },\n complete: () => this.#pendingLoads.delete(key),\n });\n });\n\n this.#pendingLoads.set(key, promise);\n\n return promise;\n }\n\n private parseModelToRecord(model: LangDto[]): LangModel {\n const records: LangModel = {};\n\n for (const item of model) {\n records[item.code] = item.localization;\n }\n\n return records;\n }\n\n private parseAssetToRecord(page: string, data: LangModel): LangModel {\n const records: LangModel = {};\n\n for (const [k, v] of Object.entries(data)) {\n records[`${page}.${k}`] = v;\n }\n\n return records;\n }\n\n private applyParams(text: string, params: LangParams): string {\n return text.replace(/\\{\\{(.*?)}}/g, (_, k) => params[k.trim()] ?? '');\n }\n\n private getChainedValue(query = '', source = this.#cache()) {\n const [page, key, ...normalizedPath] = query.split('.');\n\n return [`${page}.${key}`, ...normalizedPath].reduce<LangModel | string | undefined>(\n (acc, key) => (typeof acc === 'object' ? (acc[key] ?? acc[query]) : undefined),\n source,\n ) as string | undefined;\n }\n\n private getStoredLang(): Langs {\n return (localStorage.getItem('lang') as Langs) || this.config.defaultLang || 'ru';\n }\n\n private makeUrl(ns: string): string {\n const suffix = this.config.isFromAssets ? `.${this.#lang()}.json` : `?language=${this.#lang()}`;\n\n return `${this.config.url}/${ns}${suffix}`;\n }\n\n private makeNamespaceKey(ns: string) {\n return `${this.#lang()}.${ns}`;\n }\n}\n","import { inject, Pipe, PipeTransform } from '@angular/core';\r\n\r\nimport { LangParams } from './lang.models';\r\nimport { LangService } from './lang.service';\r\n\r\n/**\r\n * Кастомный Angular-пайп, который преобразует языковой ключ и дополнительные параметры в локализованную строку.\r\n *\r\n * Пайп объявлен как standalone и impure — то есть он может использоваться без подключения модуля\r\n * и будет пересчитываться при изменении состояния (например, при смене языка).\r\n *\r\n * В своей работе пайп наблюдает и кэширует языковые ключи для повышения производительности,\r\n * используя LangService для получения переведённых строк в зависимости от текущего языка приложения.\r\n *\r\n * Трансформация заключается в том, чтобы принять строку-ключ и необязательные параметры,\r\n * сформировать ключ для кэша и вернуть локализованное значение, соответствующее этому запросу.\r\n *\r\n * @implements {PipeTransform}\r\n */\r\n@Pipe({ name: 'lang', standalone: true, pure: false })\r\nexport class LangPipe implements PipeTransform {\r\n private readonly lang = inject(LangService);\r\n private readonly cache = new Map<string, () => string>();\r\n\r\n transform(query: string, params?: LangParams): string {\r\n const key = query + JSON.stringify(params);\r\n\r\n if (!this.cache.has(key)) {\r\n this.cache.set(key, this.lang.observe(query, params));\r\n }\r\n\r\n return this.cache.get(key)!();\r\n }\r\n}\r\n","import { Themes } from '@reforgium/internal';\n\nexport const themes: Record<Themes, Themes> = {\n light: 'light',\n dark: 'dark',\n} as const;\n\nexport const darkThemePrefix = 're-dark';\n","import { InjectionToken } from '@angular/core';\r\n\r\nimport { ThemeConfig } from './theme.models';\r\n// noinspection ES6PreferShortImport\r\nimport { themes } from './themes.constant';\r\n\r\nexport const defaultThemeConfig = {\r\n defaultTheme: themes.light,\r\n};\r\n\r\nexport const THEME_CONFIG = new InjectionToken<ThemeConfig>('RE_THEME_CONFIG');\r\n","import { computed, effect, inject, Injectable, signal } from '@angular/core';\n\nimport { Themes } from '@reforgium/internal';\n\n// noinspection ES6PreferShortImport\nimport { THEME_CONFIG } from './theme.provider';\n// noinspection ES6PreferShortImport\nimport { darkThemePrefix, themes } from './themes.constant';\n\n/**\n * Service for managing application theme.\n *\n * Allows getting the current theme and switching between light and dark.\n * Automatically saves selected theme to `localStorage` and applies CSS class to `<html>` element.\n *\n * Example:\n * ```ts\n * const theme = inject(ThemeService);\n * theme.switch('dark');\n * console.log(theme.theme()); // 'dark'\n * ```\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class ThemeService {\n private readonly config = inject(THEME_CONFIG);\n private readonly themeDefault = this.config?.defaultTheme || themes.light;\n\n #theme = signal<Themes>(this.themeDefault);\n\n /**\n * Current active theme (`light` or `dark`).\n *\n * Value is reactive — can be used in template or `computed`.\n * ```html\n * <div [class.dark]=\"themeService.theme() === 'dark'\"></div>\n * <div [class]=\"themeService.theme()\"></div>\n * ```\n */\n theme = computed(() => this.#theme());\n\n /**\n * Convenient flag returning `true` if light theme is active.\n * Suitable for conditional style application or resource selection.\n */\n isLight = computed(() => this.#theme() === themes.light);\n\n constructor() {\n effect(() => {\n const theme = (localStorage.getItem('theme') as Themes) || this.themeDefault;\n\n this.switch(theme);\n });\n effect(() => localStorage.setItem('theme', this.#theme()));\n }\n\n /**\n * Switches theme.\n *\n * If parameter is not provided — performs toggle between `light` and `dark`.\n * Also automatically updates `<html>` class and saves selection to `localStorage`.\n *\n * @param theme — explicit theme value (`'light'` or `'dark'`).\n */\n switch(theme?: Themes) {\n const html = document.querySelector('html')!;\n const newTheme = theme ?? (this.#theme() === themes.light ? themes.dark : themes.light);\n\n newTheme === themes.dark && html.classList.add(darkThemePrefix);\n newTheme === themes.light && html.classList.remove(darkThemePrefix);\n this.#theme.set(newTheme);\n }\n}\n","import { EnvironmentProviders, LOCALE_ID, makeEnvironmentProviders } from '@angular/core';\n\nimport { CURRENT_DEVICE, SELECTED_LANG, SELECTED_THEME } from '@reforgium/internal';\n\n// noinspection ES6PreferShortImport\nimport { AdaptiveService, defaultBreakpoints, DEVICE_BREAKPOINTS, DeviceBreakpoints } from '../adaptive';\nimport { LANG_CONFIG, LangService, LocaleConfig } from '../lang';\nimport { innerLangVal } from '../lang/lang.models';\nimport { defaultThemeConfig, THEME_CONFIG, ThemeConfig, ThemeService } from '../theme';\n\nexport interface AppConfig {\n locale: LocaleConfig;\n theme?: ThemeConfig;\n breakpoints?: DeviceBreakpoints;\n}\n\nexport function provideReInit(config: AppConfig): EnvironmentProviders {\n return makeEnvironmentProviders([\n { provide: SELECTED_LANG, deps: [LangService], useFactory: (ls: LangService) => ls[innerLangVal] },\n { provide: SELECTED_THEME, deps: [ThemeService], useFactory: (ls: ThemeService) => ls.theme },\n { provide: CURRENT_DEVICE, deps: [AdaptiveService], useFactory: (ls: AdaptiveService) => ls.device },\n { provide: DEVICE_BREAKPOINTS, useValue: config.breakpoints || defaultBreakpoints },\n { provide: THEME_CONFIG, useValue: config.theme || defaultThemeConfig },\n { provide: LANG_CONFIG, useValue: config.locale || {} },\n { provide: LOCALE_ID, useValue: config.locale.defaultLang ?? 'ru' },\n ]);\n}\n","import { inject, Injectable } from '@angular/core';\r\nimport { Meta, Title } from '@angular/platform-browser';\r\n\r\nimport { OgType, TwitterCardType } from './seo.models';\r\n\r\n/**\r\n * Service for managing page SEO metadata.\r\n *\r\n * Allows centrally setting title, description, keywords,\r\n * Open Graph and Twitter Card tags, canonical link, and JSON-LD schema.\r\n *\r\n * Example:\r\n * ```ts\r\n * const seo = inject(SeoService);\r\n * seo.setTitle('Home Page');\r\n * seo.setDescription('Site Description');\r\n * seo.setOg({ title: 'Home', type: 'website' });\r\n * ```\r\n */\r\n@Injectable()\r\nexport class SeoService {\r\n private title = inject(Title);\r\n private meta = inject(Meta);\r\n\r\n /**\r\n * Sets page title (`<title>`).\r\n * @param value title text\r\n */\r\n setTitle(value: string) {\r\n this.title.setTitle(value);\r\n }\r\n\r\n /**\r\n * Sets page description (`<meta name=\"description\">`).\r\n * @param desc brief content description\r\n */\r\n setDescription(desc: string) {\r\n this.upsert({ name: 'description', content: desc });\r\n }\r\n\r\n /**\r\n * Sets page keywords (`<meta name=\"keywords\">`).\r\n * @param keywords array of keywords\r\n */\r\n setKeywords(keywords: string[]) {\r\n this.upsert({ name: 'keywords', content: keywords.join(', ') });\r\n }\r\n\r\n /**\r\n * Sets directives for search engines (`<meta name=\"robots\">`).\r\n * @param value value, e.g. `\"index,follow\"`\r\n */\r\n setRobots(value: string) {\r\n this.upsert({ name: 'robots', content: value }); // e.g. \"index,follow\"\r\n }\r\n\r\n /**\r\n * Sets canonical link (`<link rel=\"canonical\">`).\r\n * @param url absolute URL of canonical page\r\n */\r\n setCanonical(url: string) {\r\n this.upsertLink('canonical', url);\r\n }\r\n\r\n /**\r\n * Sets Open Graph meta tags.\r\n * @param opts object with Open Graph fields (`title`, `description`, `image`, `url`, `type`, etc.)\r\n */\r\n setOg(opts: OgType) {\r\n for (const [k, v] of Object.entries(opts)) {\r\n v && this.upsert({ property: `og:${k}`, content: v });\r\n }\r\n }\r\n\r\n /**\r\n * Sets Twitter Card meta tags.\r\n * @param opts object with Twitter Card fields (`card`, `title`, `description`, `image`, etc.)\r\n */\r\n setTwitter(opts: TwitterCardType) {\r\n for (const [k, v] of Object.entries(opts)) {\r\n v && this.upsert({ name: `twitter:${k}`, content: v });\r\n }\r\n }\r\n\r\n /**\r\n * Embeds JSON-LD schema (structured data) in `<head>`.\r\n * @param schema schema object (will be serialized to JSON)\r\n */\r\n setJsonLd(schema: object) {\r\n const id = 'app-jsonld';\r\n let el = document.getElementById(id) as HTMLScriptElement | null;\r\n\r\n if (!el) {\r\n el = document.createElement('script');\r\n el.type = 'application/ld+json';\r\n el.id = id;\r\n document.head.appendChild(el);\r\n }\r\n\r\n el.text = JSON.stringify(schema);\r\n }\r\n\r\n private upsert(tag: { name?: string; property?: string; content: string }) {\r\n if (tag.name) {\r\n this.meta.updateTag(tag, `name='${tag.name}'`);\r\n } else if (tag.property) {\r\n this.meta.updateTag(tag, `property='${tag.property}'`);\r\n }\r\n }\r\n\r\n private upsertLink(rel: string, href: string) {\r\n const head = document.head;\r\n let link = head.querySelector<HTMLLinkElement>(`link[rel=\"${rel}\"]`);\r\n\r\n if (!link) {\r\n link = document.createElement('link');\r\n link.rel = rel;\r\n head.appendChild(link);\r\n }\r\n\r\n link.href = href;\r\n }\r\n}\r\n","import { DestroyRef, inject, Injectable } from '@angular/core';\r\nimport { ActivatedRoute, NavigationEnd, Router } from '@angular/router';\r\nimport { filter } from 'rxjs/operators';\r\n\r\nimport { SeoService } from './seo.service';\r\n\r\n@Injectable({ providedIn: 'root' })\r\nexport class SeoRouteListener {\r\n private router = inject(Router);\r\n private seo = inject(SeoService);\r\n private ar = inject(ActivatedRoute);\r\n private destroyRef = inject(DestroyRef);\r\n\r\n init(baseUrl: string) {\r\n const sub = this.router.events.pipe(filter((e) => e instanceof NavigationEnd)).subscribe(() => {\r\n const route = this.deepest(this.ar);\r\n const data = route.snapshot.data as {\r\n title?: string;\r\n description?: string;\r\n robots?: string;\r\n canonical?: string;\r\n og?: Record<string, string>;\r\n twitter?: Record<string, string>;\r\n jsonld?: object;\r\n };\r\n const url = data.canonical ?? baseUrl.replace(/\\/+$/, '') + this.router.url;\r\n\r\n data.title && this.seo.setTitle(data.title);\r\n data.description && this.seo.setDescription(data.description);\r\n data.twitter && this.seo.setTwitter(data.twitter);\r\n data.jsonld && this.seo.setJsonLd(data.jsonld);\r\n\r\n this.seo.setRobots(data.robots ?? 'index,follow');\r\n this.seo.setCanonical(url);\r\n this.seo.setOg({\r\n title: data.title,\r\n description: data.description,\r\n url: url,\r\n ...data.og,\r\n });\r\n });\r\n\r\n this.destroyRef.onDestroy(() => sub.unsubscribe());\r\n }\r\n\r\n private deepest(r: ActivatedRoute): ActivatedRoute {\r\n let cur = r;\r\n\r\n while (cur.firstChild) {\r\n cur = cur.firstChild;\r\n }\r\n\r\n return cur;\r\n }\r\n}\r\n","import { computed, DestroyRef, inject, Injectable, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { NavigationEnd, Router, UrlSegment } from '@angular/router';\nimport { filter, map, startWith } from 'rxjs';\n\nimport { deepEqual } from '@reforgium/internal';\n\n/**\n * Reactive snapshot of the current route (the deepest active route).\n * Updates on every `NavigationEnd` event.\n *\n * Provides:\n * - `params` / `query` — strings (as in Angular Router)\n * - `data` — arbitrary data (from route configuration/resolvers)\n * - `url` — string assembled from `UrlSegment[]`\n * - `fragment` — hash (#section)\n * - `selectData(key)` — type-safe selector for `data`\n * - `state` — combined computed object (convenient for single subscriber)\n */\n@Injectable({ providedIn: 'root' })\nexport class RouteWatcher {\n private readonly router = inject(Router);\n private readonly destroyRef = inject(DestroyRef);\n\n #params = signal<Record<string, string>>({});\n #query = signal<Record<string, string>>({});\n #data = signal<Record<string, unknown>>({});\n #url = signal<string>('');\n #fragment = signal<string | null>(null);\n\n /** Signal for tracking and retrieving URL parameters */\n readonly params = this.#params.asReadonly();\n\n /** Signal for tracking and retrieving query parameters */\n readonly query = this.#query.asReadonly();\n\n /** Signal for tracking and retrieving route data */\n readonly data = this.#data.asReadonly();\n\n /** Signal for tracking and retrieving URL */\n readonly url = this.#url.asReadonly();\n\n /** Signal for tracking and retrieving URL fragment */\n readonly fragment = this.#fragment.asReadonly();\n\n /** Combined computed snapshot (to avoid multiple effects) */\n readonly state = computed(() => ({\n params: this.#params(),\n query: this.#query(),\n data: this.#data(),\n url: this.#url(),\n fragment: this.#fragment(),\n }));\n\n constructor() {\n const read = () => {\n const snap = this.deepestSnapshot();\n const url = joinUrl(snap.url);\n\n !deepEqual(snap.params, this.#params()) && this.#params.set(snap.params as Record<string, string>);\n !deepEqual(snap.queryParams, this.#query()) && this.#query.set(snap.queryParams as Record<string, string>);\n !deepEqual(snap.data, this.#data()) && this.#data.set(snap.data as Record<string, unknown>);\n this.#url() !== url && this.#url.set(url);\n this.#fragment() !== snap.fragment && this.#fragment.set(snap.fragment ?? null);\n };\n\n read();\n\n this.router.events\n .pipe(\n startWith(new NavigationEnd(0, this.router.url, this.router.url)),\n filter((e) => e instanceof NavigationEnd),\n map(() => true),\n takeUntilDestroyed(this.destroyRef),\n )\n .subscribe(() => read());\n }\n\n /** Convenient selector for a data key with type-safe casting */\n selectData<T = unknown>(key: string) {\n return computed<T | undefined>(() => this.#data()[key] as T | undefined);\n }\n\n private deepestSnapshot() {\n // work with snapshot — we need a \"frozen\" point at NavigationEnd moment\n let snap = this.router.routerState.snapshot.root;\n\n while (snap.firstChild) {\n snap = snap.firstChild;\n }\n\n return snap;\n }\n}\n\n/** Joins `UrlSegment[]` into a path string */\nfunction joinUrl(segments: UrlSegment[]): string {\n return segments.length ? segments.map((s) => s.path).join('/') : '';\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["filter"],"mappings":";;;;;;;;;;;AAIO,MAAM,kBAAkB,GAAG;AAChC,IAAA,QAAQ,EAAE,oBAAoB;AAC9B,IAAA,QAAQ,EAAE,4CAA4C;AACtD,IAAA,WAAW,EAAE,6CAA6C;AAC1D,IAAA,SAAS,EAAE,qBAAqB;;MAErB,kBAAkB,GAAG,IAAI,cAAc,CAAoB,uBAAuB,EAAE;AAC/F,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,kBAAkB;AAClC,CAAA;;ACJD;;;;;;;;;;;;;;;;;AAiBG;MAIU,eAAe,CAAA;;AAE1B,IAAA,OAAO,GAAG,MAAM,CAAU,SAAS,mDAAC;;AAGpC,IAAA,MAAM,GAAG,MAAM,CAAC,CAAC,kDAAC;AAClB,IAAA,OAAO,GAAG,MAAM,CAAC,CAAC,mDAAC;AAEnB;;;;;;AAMG;AACH,IAAA,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;AAElC;;;AAGG;AACH,IAAA,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;AAEhC;;;AAGG;AACH,IAAA,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;AAElC;;;AAGG;AACH,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,KAAK,SAAS,qDAAC;AAExD;;;AAGG;AACH,IAAA,UAAU,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,sDAAC;AAEnD,IAAA,iBAAiB,GAAG,MAAM,CAAC,kBAAkB,CAAC;IAC9C,cAAc,GAAc,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAc;AAE5E,IAAA,kBAAkB,GAAG,MAAM,CAAC,kBAAkB,CAAC;AAEvD,IAAA,WAAA,GAAA;QACE,iBAAiB,CAAC,MAAK;YACrB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;AACtC,QAAA,CAAC,CAAC;QAEF,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,KAAI;YACzF,MAAM,MAAM,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC;YAEhG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,IAAI,SAAS,CAAC;AACvC,QAAA,CAAC,CAAC;AACF,QAAA,SAAS,CAAC,MAAM,EAAE,QAAQ;AACvB,aAAA,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC;aACtB,SAAS,CAAC,MAAK;YACd,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,WAAW,CAAC;AACtC,QAAA,CAAC,CAAC;IACN;uGA/DW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAf,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,eAAe,cAFd,MAAM,EAAA,CAAA;;2FAEP,eAAe,EAAA,UAAA,EAAA,CAAA;kBAH3B,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;ACtBD;;;;;;;;;;;;;;;;;;;AAmBG;MAMU,iBAAiB,CAAA;IAC5B,MAAM,GAAG,KAAK,CAAsB,SAAS,mDAAI,KAAK,EAAE,YAAY,EAAA,CAAG;AACvE,IAAA,OAAO,GAAG,KAAK,CAAU,KAAK,mDAAC;AAEd,IAAA,GAAG,GAAG,MAAM,CAAC,WAAW,CAAC;AACzB,IAAA,GAAG,GAAG,MAAM,CAAC,gBAAgB,CAAC;AAC9B,IAAA,QAAQ,GAAG,MAAM,CAAC,eAAe,CAAC;IAE3C,cAAc,GAAc,EAAE;IAC9B,OAAO,GAAG,KAAK;AAEN,IAAA,aAAa,GAAoB,IAAI,CAAC,QAAQ,CAAC,MAAM;AAEtE,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE;YAE5B,IAAI,MAAM,EAAE;AACV,gBAAA,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC;YACjE;YAEA,IAAI,CAAC,UAAU,EAAE;AACnB,QAAA,CAAC,CAAC;IACJ;IAEQ,UAAU,GAAA;AAChB,QAAA,MAAM,SAAS,GAAG,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;AACpE,QAAA,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,SAAS,GAAG,SAAS;AAE1D,QAAA,IAAI,UAAU,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;YAC/B,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,IAAI,CAAC,GAAG,CAAC;AACrC,YAAA,IAAI,CAAC,OAAO,GAAG,IAAI;QACrB;AAAO,aAAA,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE;AACtC,YAAA,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE;AAChB,YAAA,IAAI,CAAC,OAAO,GAAG,KAAK;QACtB;IACF;uGApCW,iBAAiB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAjB,iBAAiB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,YAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,OAAA,EAAA,EAAA,iBAAA,EAAA,SAAA,EAAA,UAAA,EAAA,SAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAjB,iBAAiB,EAAA,UAAA,EAAA,CAAA;kBAJ7B,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,cAAc;AACxB,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;MC3BY,WAAW,GAAG,IAAI,cAAc,CAAe,gBAAgB;;ACwDrE,MAAM,YAAY,GAAG,MAAM,CAAC,gBAAgB,CAAC;;ACnDpD;;;;;AAKG;MAEU,WAAW,CAAA;AACL,IAAA,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC;AAC5B,IAAA,IAAI,GAAG,MAAM,CAAC,UAAU,CAAC;IAEjC,KAAK,GAAG,MAAM,CAAQ,IAAI,CAAC,aAAa,EAAE,iDAAC;AAC3C,IAAA,MAAM,GAAG,MAAM,CAAY,EAAE,kDAAC;AAE9B,IAAA,iBAAiB,GAAG,IAAI,GAAG,EAAU;AACrC,IAAA,aAAa,GAAG,IAAI,GAAG,EAAyB;AAEzD;;;;;;;AAOG;AACM,IAAA,WAAW,GAAG,QAAQ,CAAC,MAAK;AACnC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE;AAEzB,QAAA,OAAO,IAAI,KAAK,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC;AAC7D,IAAA,CAAC,uDAAC;AACF;;;AAGG;IACM,CAAC,YAAY,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;AAEjD;;;;;;AAMG;AACH,IAAA,OAAO,CAAC,IAAkB,EAAA;AACxB,QAAA,MAAM,OAAO,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,GAAG,IAAI;AAE3C,QAAA,IAAI,OAAO,KAAK,IAAI,CAAC,KAAK,EAAE,EAAE;AAC5B,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AACvB,YAAA,YAAY,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC;AAErC,YAAA,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9F,YAAA,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE;AAE9B,YAAA,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;QACzD;IACF;AAEA;;;;;;;AAOG;IACH,GAAG,CAAC,KAAa,EAAE,MAAmB,EAAA;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;QAEzC,IAAI,MAAM,EAAE;AACV,YAAA,OAAO,IAAI,CAAC,WAAW,EAAE,KAAK,IAAI,KAAK,GAAa,MAAM,CAAC;QAC7D;QAEA,OAAQ,KAA4B,IAAI,IAAI,CAAC,MAAM,CAAC,YAAY,IAAI,KAAK;IAC3E;AAEA;;;;;;;;AAQG;IACH,OAAO,CAAC,KAAa,EAAE,MAAmB,EAAA;QACxC,MAAM,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;AAE7B,QAAA,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE;AAC1D,YAAA,KAAK,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC;QAC7B;AAEA,QAAA,OAAO,QAAQ,CAAC,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAChD;AAEA;;;;;;AAMG;IACH,MAAM,aAAa,CAAC,EAAU,EAAA;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAErC,IAAI,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YACnC;QACF;QAEA,IAAI,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;YAC/B,OAAO,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,CAAE;QACrC;QAEA,MAAM,OAAO,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,KAAI;AACpD,YAAA,IAAI,CAAC,IAAI,CAAC,GAAG,CAAwB,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/D,gBAAA,IAAI,EAAE,CAAC,GAAG,KAAI;AACZ,oBAAA,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE;AAC9B,oBAAA,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,kBAAkB,CAAC,EAAE,EAAE,GAAG,CAAC;AAErG,oBAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,EAAE,CAAC;AAC7C,oBAAA,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC;AAC/B,oBAAA,OAAO,EAAE;gBACX,CAAC;AACD,gBAAA,KAAK,EAAE,CAAC,GAAG,KAAI;AACb,oBAAA,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;oBAC9B,MAAM,CAAC,GAAG,CAAC;gBACb,CAAC;gBACD,QAAQ,EAAE,MAAM,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC;AAC/C,aAAA,CAAC;AACJ,QAAA,CAAC,CAAC;QAEF,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC;AAEpC,QAAA,OAAO,OAAO;IAChB;AAEQ,IAAA,kBAAkB,CAAC,KAAgB,EAAA;QACzC,MAAM,OAAO,GAAc,EAAE;AAE7B,QAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;YACxB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,YAAY;QACxC;AAEA,QAAA,OAAO,OAAO;IAChB;IAEQ,kBAAkB,CAAC,IAAY,EAAE,IAAe,EAAA;QACtD,MAAM,OAAO,GAAc,EAAE;AAE7B,QAAA,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YACzC,OAAO,CAAC,GAAG,IAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAE,CAAC,GAAG,CAAC;QAC7B;AAEA,QAAA,OAAO,OAAO;IAChB;IAEQ,WAAW,CAAC,IAAY,EAAE,MAAkB,EAAA;QAClD,OAAO,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;IACvE;IAEQ,eAAe,CAAC,KAAK,GAAG,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,EAAA;AACxD,QAAA,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,cAAc,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC;QAEvD,OAAO,CAAC,GAAG,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,EAAE,GAAG,cAAc,CAAC,CAAC,MAAM,CACjD,CAAC,GAAG,EAAE,GAAG,MAAM,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,EAC9E,MAAM,CACe;IACzB;IAEQ,aAAa,GAAA;AACnB,QAAA,OAAQ,YAAY,CAAC,OAAO,CAAC,MAAM,CAAW,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI;IACnF;AAEQ,IAAA,OAAO,CAAC,EAAU,EAAA;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY,GAAG,CAAA,CAAA,EAAI,IAAI,CAAC,KAAK,EAAE,CAAA,KAAA,CAAO,GAAG,CAAA,UAAA,EAAa,IAAI,CAAC,KAAK,EAAE,CAAA,CAAE;QAE/F,OAAO,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAA,CAAA,EAAI,EAAE,CAAA,EAAG,MAAM,CAAA,CAAE;IAC5C;AAEQ,IAAA,gBAAgB,CAAC,EAAU,EAAA;QACjC,OAAO,CAAA,EAAG,IAAI,CAAC,KAAK,EAAE,CAAA,CAAA,EAAI,EAAE,EAAE;IAChC;uGA9KW,WAAW,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAX,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAW,cADE,MAAM,EAAA,CAAA;;2FACnB,WAAW,EAAA,UAAA,EAAA,CAAA;kBADvB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACVlC;;;;;;;;;;;;;AAaG;MAEU,QAAQ,CAAA;AACF,IAAA,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;AAC1B,IAAA,KAAK,GAAG,IAAI,GAAG,EAAwB;IAExD,SAAS,CAAC,KAAa,EAAE,MAAmB,EAAA;QAC1C,MAAM,GAAG,GAAG,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QAE1C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE;AACxB,YAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACvD;QAEA,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAE,EAAE;IAC/B;uGAZW,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,IAAA,EAAA,CAAA;qGAAR,QAAQ,EAAA,YAAA,EAAA,IAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,KAAA,EAAA,CAAA;;2FAAR,QAAQ,EAAA,UAAA,EAAA,CAAA;kBADpB,IAAI;mBAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE;;;ACjB9C,MAAM,MAAM,GAA2B;AAC5C,IAAA,KAAK,EAAE,OAAO;AACd,IAAA,IAAI,EAAE,MAAM;;AAGP,MAAM,eAAe,GAAG;;ACDxB,MAAM,kBAAkB,GAAG;IAChC,YAAY,EAAE,MAAM,CAAC,KAAK;;MAGf,YAAY,GAAG,IAAI,cAAc,CAAc,iBAAiB;;ACD7E;;;;;;;;;;;;AAYG;MAIU,YAAY,CAAA;AACN,IAAA,MAAM,GAAG,MAAM,CAAC,YAAY,CAAC;IAC7B,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE,YAAY,IAAI,MAAM,CAAC,KAAK;AAEzE,IAAA,MAAM,GAAG,MAAM,CAAS,IAAI,CAAC,YAAY,kDAAC;AAE1C;;;;;;;;AAQG;IACH,KAAK,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,OAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AAErC;;;AAGG;AACH,IAAA,OAAO,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,MAAM,EAAE,KAAK,MAAM,CAAC,KAAK,mDAAC;AAExD,IAAA,WAAA,GAAA;QACE,MAAM,CAAC,MAAK;AACV,YAAA,MAAM,KAAK,GAAI,YAAY,CAAC,OAAO,CAAC,OAAO,CAAY,IAAI,IAAI,CAAC,YAAY;AAE5E,YAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;AACpB,QAAA,CAAC,CAAC;AACF,QAAA,MAAM,CAAC,MAAM,YAAY,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5D;AAEA;;;;;;;AAOG;AACH,IAAA,MAAM,CAAC,KAAc,EAAA;QACnB,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAE;QAC5C,MAAM,QAAQ,GAAG,KAAK,KAAK,IAAI,CAAC,MAAM,EAAE,KAAK,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC;AAEvF,QAAA,QAAQ,KAAK,MAAM,CAAC,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,eAAe,CAAC;AAC/D,QAAA,QAAQ,KAAK,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,eAAe,CAAC;AACnE,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;IAC3B;uGA/CW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,YAAY,cAFX,MAAM,EAAA,CAAA;;2FAEP,YAAY,EAAA,UAAA,EAAA,CAAA;kBAHxB,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;ACRK,SAAU,aAAa,CAAC,MAAiB,EAAA;AAC7C,IAAA,OAAO,wBAAwB,CAAC;QAC9B,EAAE,OAAO,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,EAAe,KAAK,EAAE,CAAC,YAAY,CAAC,EAAE;QAClG,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,YAAY,CAAC,EAAE,UAAU,EAAE,CAAC,EAAgB,KAAK,EAAE,CAAC,KAAK,EAAE;QAC7F,EAAE,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,eAAe,CAAC,EAAE,UAAU,EAAE,CAAC,EAAmB,KAAK,EAAE,CAAC,MAAM,EAAE;QACpG,EAAE,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,MAAM,CAAC,WAAW,IAAI,kBAAkB,EAAE;QACnF,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,CAAC,KAAK,IAAI,kBAAkB,EAAE;QACvE,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,EAAE;AACvD,QAAA,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,IAAI,IAAI,EAAE;AACpE,KAAA,CAAC;AACJ;;ACrBA;;;;;;;;;;;;;AAaG;MAEU,UAAU,CAAA;AACb,IAAA,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;AACrB,IAAA,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;AAE3B;;;AAGG;AACH,IAAA,QAAQ,CAAC,KAAa,EAAA;AACpB,QAAA,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC;IAC5B;AAEA;;;AAGG;AACH,IAAA,cAAc,CAAC,IAAY,EAAA;AACzB,QAAA,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrD;AAEA;;;AAGG;AACH,IAAA,WAAW,CAAC,QAAkB,EAAA;AAC5B,QAAA,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACjE;AAEA;;;AAGG;AACH,IAAA,SAAS,CAAC,KAAa,EAAA;AACrB,QAAA,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD;AAEA;;;AAGG;AACH,IAAA,YAAY,CAAC,GAAW,EAAA;AACtB,QAAA,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,GAAG,CAAC;IACnC;AAEA;;;AAGG;AACH,IAAA,KAAK,CAAC,IAAY,EAAA;AAChB,QAAA,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACzC,YAAA,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAA,GAAA,EAAM,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QACvD;IACF;AAEA;;;AAGG;AACH,IAAA,UAAU,CAAC,IAAqB,EAAA;AAC9B,QAAA,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;AACzC,YAAA,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAA,QAAA,EAAW,CAAC,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;QACxD;IACF;AAEA;;;AAGG;AACH,IAAA,SAAS,CAAC,MAAc,EAAA;QACtB,MAAM,EAAE,GAAG,YAAY;QACvB,IAAI,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,EAAE,CAA6B;QAEhE,IAAI,CAAC,EAAE,EAAE;AACP,YAAA,EAAE,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AACrC,YAAA,EAAE,CAAC,IAAI,GAAG,qBAAqB;AAC/B,YAAA,EAAE,CAAC,EAAE,GAAG,EAAE;AACV,YAAA,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B;QAEA,EAAE,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;IAClC;AAEQ,IAAA,MAAM,CAAC,GAA0D,EAAA;AACvE,QAAA,IAAI,GAAG,CAAC,IAAI,EAAE;AACZ,YAAA,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAA,MAAA,EAAS,GAAG,CAAC,IAAI,CAAA,CAAA,CAAG,CAAC;QAChD;AAAO,aAAA,IAAI,GAAG,CAAC,QAAQ,EAAE;AACvB,YAAA,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,CAAA,UAAA,EAAa,GAAG,CAAC,QAAQ,CAAA,CAAA,CAAG,CAAC;QACxD;IACF;IAEQ,UAAU,CAAC,GAAW,EAAE,IAAY,EAAA;AAC1C,QAAA,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI;QAC1B,IAAI,IAAI,GAAG,IAAI,CAAC,aAAa,CAAkB,CAAA,UAAA,EAAa,GAAG,CAAA,EAAA,CAAI,CAAC;QAEpE,IAAI,CAAC,IAAI,EAAE;AACT,YAAA,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;AACrC,YAAA,IAAI,CAAC,GAAG,GAAG,GAAG;AACd,YAAA,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QACxB;AAEA,QAAA,IAAI,CAAC,IAAI,GAAG,IAAI;IAClB;uGArGW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;2GAAV,UAAU,EAAA,CAAA;;2FAAV,UAAU,EAAA,UAAA,EAAA,CAAA;kBADtB;;;MCZY,gBAAgB,CAAA;AACnB,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC;AACxB,IAAA,EAAE,GAAG,MAAM,CAAC,cAAc,CAAC;AAC3B,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAEvC,IAAA,IAAI,CAAC,OAAe,EAAA;QAClB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,MAAK;YAC5F,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;AACnC,YAAA,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,IAQ3B;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG;AAE3E,YAAA,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;AAC3C,YAAA,IAAI,CAAC,WAAW,IAAI,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,CAAC,WAAW,CAAC;AAC7D,YAAA,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC;AACjD,YAAA,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC;YAE9C,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC;AACjD,YAAA,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC;AAC1B,YAAA,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;gBACb,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,WAAW,EAAE,IAAI,CAAC,WAAW;AAC7B,gBAAA,GAAG,EAAE,GAAG;gBACR,GAAG,IAAI,CAAC,EAAE;AACX,aAAA,CAAC;AACJ,QAAA,CAAC,CAAC;AAEF,QAAA,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,WAAW,EAAE,CAAC;IACpD;AAEQ,IAAA,OAAO,CAAC,CAAiB,EAAA;QAC/B,IAAI,GAAG,GAAG,CAAC;AAEX,QAAA,OAAO,GAAG,CAAC,UAAU,EAAE;AACrB,YAAA,GAAG,GAAG,GAAG,CAAC,UAAU;QACtB;AAEA,QAAA,OAAO,GAAG;IACZ;uGA9CW,gBAAgB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAhB,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,gBAAgB,cADH,MAAM,EAAA,CAAA;;2FACnB,gBAAgB,EAAA,UAAA,EAAA,CAAA;kBAD5B,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;;ACClC;;;;;;;;;;;AAWG;MAEU,YAAY,CAAA;AACN,IAAA,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;AACvB,IAAA,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;AAEhD,IAAA,OAAO,GAAG,MAAM,CAAyB,EAAE,mDAAC;AAC5C,IAAA,MAAM,GAAG,MAAM,CAAyB,EAAE,kDAAC;AAC3C,IAAA,KAAK,GAAG,MAAM,CAA0B,EAAE,iDAAC;AAC3C,IAAA,IAAI,GAAG,MAAM,CAAS,EAAE,gDAAC;AACzB,IAAA,SAAS,GAAG,MAAM,CAAgB,IAAI,qDAAC;;AAG9B,IAAA,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE;;AAGlC,IAAA,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;;AAGhC,IAAA,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE;;AAG9B,IAAA,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;;AAG5B,IAAA,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE;;AAGtC,IAAA,KAAK,GAAG,QAAQ,CAAC,OAAO;AAC/B,QAAA,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE;AACtB,QAAA,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE;AACpB,QAAA,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE;AAClB,QAAA,GAAG,EAAE,IAAI,CAAC,IAAI,EAAE;AAChB,QAAA,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE;AAC3B,KAAA,CAAC,iDAAC;AAEH,IAAA,WAAA,GAAA;QACE,MAAM,IAAI,GAAG,MAAK;AAChB,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,eAAe,EAAE;YACnC,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;YAE7B,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAgC,CAAC;YAClG,CAAC,SAAS,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,WAAqC,CAAC;YAC1G,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAA+B,CAAC;AAC3F,YAAA,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YACzC,IAAI,CAAC,SAAS,EAAE,KAAK,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;AACjF,QAAA,CAAC;AAED,QAAA,IAAI,EAAE;QAEN,IAAI,CAAC,MAAM,CAAC;aACT,IAAI,CACH,SAAS,CAAC,IAAI,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EACjEA,QAAM,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,aAAa,CAAC,EACzC,GAAG,CAAC,MAAM,IAAI,CAAC,EACf,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC;AAEpC,aAAA,SAAS,CAAC,MAAM,IAAI,EAAE,CAAC;IAC5B;;AAGA,IAAA,UAAU,CAAc,GAAW,EAAA;AACjC,QAAA,OAAO,QAAQ,CAAgB,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,CAAkB,CAAC;IAC1E;IAEQ,eAAe,GAAA;;QAErB,IAAI,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI;AAEhD,QAAA,OAAO,IAAI,CAAC,UAAU,EAAE;AACtB,YAAA,IAAI,GAAG,IAAI,CAAC,UAAU;QACxB;AAEA,QAAA,OAAO,IAAI;IACb;uGAxEW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,YAAY,cADC,MAAM,EAAA,CAAA;;2FACnB,YAAY,EAAA,UAAA,EAAA,CAAA;kBADxB,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE;;AA4ElC;AACA,SAAS,OAAO,CAAC,QAAsB,EAAA;AACrC,IAAA,OAAO,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE;AACrE;;AClGA;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"reforgium-presentia.mjs","sources":["../../../../libs/presentia/src/adaptive/adaptive.provider.ts","../../../../libs/presentia/src/adaptive/adaptive.service.ts","../../../../libs/presentia/src/adaptive/device-type.directive.ts","../../../../libs/presentia/src/lang/lang.models.ts","../../../../libs/presentia/src/lang/locale.provider.ts","../../../../libs/presentia/src/lang/lang.service.ts","../../../../libs/presentia/src/lang/lang.pipe.ts","../../../../libs/presentia/src/theme/themes.constant.ts","../../../../libs/presentia/src/theme/theme.provider.ts","../../../../libs/presentia/src/theme/theme.service.ts","../../../../libs/presentia/src/providers/init.provider.ts","../../../../libs/presentia/src/seo/seo.service.ts","../../../../libs/presentia/src/seo/seo-route.listener.ts","../../../../libs/presentia/src/routes/route-watcher.service.ts","../../../../libs/presentia/src/reforgium-presentia.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\r\n\r\nimport { DeviceBreakpoints } from './adaptive.models';\r\n\r\n/**\r\n * Default breakpoints for device type detection.\r\n *\r\n * Defines media queries for each device category:\r\n * - `mobile` — screens up to 719px wide\r\n * - `tablet` — screens from 720px to 1399px wide\r\n * - `desktop-s` — small desktop screens from 1400px to 1919px wide\r\n * - `desktop` — large desktop screens 1920px and wider\r\n *\r\n * These breakpoints are used by `AdaptiveService` to determine the current device type.\r\n */\r\nexport const defaultBreakpoints = {\r\n 'mobile': '(max-width: 719px)',\r\n 'tablet': '(min-width: 720px) and (max-width: 1399px)',\r\n 'desktop-s': '(min-width: 1400px) and (max-width: 1919px)',\r\n 'desktop': '(min-width: 1920px)',\r\n};\r\n/**\r\n * Injection token for providing custom device breakpoints.\r\n *\r\n * By default, provides `defaultBreakpoints`, but can be overridden\r\n * at any level of the dependency injection tree to customize\r\n * the device detection behavior.\r\n *\r\n * Example of overriding:\r\n * ```typescript\r\n * {\r\n * provide: DEVICE_BREAKPOINTS,\r\n * useValue: {\r\n * mobile: '(max-width: 599px)',\r\n * tablet: '(min-width: 600px) and (max-width: 1199px)',\r\n * 'desktop-s': '(min-width: 1200px) and (max-width: 1799px)',\r\n * desktop: '(min-width: 1800px)'\r\n * }\r\n * }\r\n * ```\r\n *\r\n * Used by `AdaptiveService` to observe media query changes.\r\n */\r\nexport const DEVICE_BREAKPOINTS = new InjectionToken<DeviceBreakpoints>('RE_DEVICE_BREAKPOINTS', {\r\n providedIn: 'root',\r\n factory: () => defaultBreakpoints,\r\n});\r\n","import { BreakpointObserver } from '@angular/cdk/layout';\r\nimport { afterRenderEffect, computed, inject, Injectable, signal } from '@angular/core';\r\nimport { debounceTime, fromEvent } from 'rxjs';\r\n\r\nimport { Devices } from '@reforgium/internal';\r\n\r\n// noinspection ES6PreferShortImport\r\nimport { DEVICE_BREAKPOINTS } from './adaptive.provider';\r\n\r\n/**\r\n * The `AdaptiveService` is responsible for determining the device type, window dimensions, and screen orientation.\r\n *\r\n * Used for building adaptive interfaces, changing component behavior and styles\r\n * depending on the current device or screen size.\r\n *\r\n * Main features:\r\n * - Reactive tracking of the current device (`desktop`, `tablet`, `mobile`).\r\n * - Support for computed properties (`isDesktop`, `isPortrait`).\r\n * - Automatic updates when the window is resized and breakpoints are crossed.\r\n *\r\n * Implementation is based on:\r\n * - `BreakpointObserver` from Angular CDK — for observing media queries.\r\n * - `signal` and `computed` — for reactive state without zones.\r\n * - `fromEvent(window, 'resize')` — for updating window dimensions with debouncing.\r\n *\r\n * The service is registered as `providedIn: 'root'` and is available throughout the application.\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class AdaptiveService {\r\n /** @internal Signal of the current device type. */\r\n #device = signal<Devices>('desktop');\r\n\r\n /** @internal Signals of the current window width and height. */\r\n #width = signal(0);\r\n #height = signal(0);\r\n\r\n /**\r\n * Current device type (reactive signal).\r\n * Possible values: `'desktop' | 'tablet' | 'mobile'`.\r\n *\r\n * Updates automatically when screen width changes\r\n * or when specified breakpoints are crossed (`DEVICE_BREAKPOINTS`).\r\n */\r\n device = this.#device.asReadonly();\r\n\r\n /**\r\n * Current browser window width in pixels.\r\n * Updates reactively on `resize` event.\r\n */\r\n width = this.#width.asReadonly();\r\n\r\n /**\r\n * Current browser window height in pixels.\r\n * Updates reactively on `resize` event.\r\n */\r\n height = this.#height.asReadonly();\r\n\r\n /**\r\n * Computed signal indicating whether the current device is a desktop.\r\n * Used for conditional rendering or layout configuration.\r\n */\r\n isDesktop = computed(() => this.#device() === 'desktop');\r\n\r\n /**\r\n * Computed signal determining whether the screen is in portrait orientation.\r\n * Returns `true` if window height is greater than width.\r\n */\r\n isPortrait = computed(() => this.#height() > this.#width());\r\n\r\n private deviceBreakpoints = inject(DEVICE_BREAKPOINTS);\r\n private devicePriority: Devices[] = Object.keys(this.deviceBreakpoints) as Devices[];\r\n\r\n private breakpointObserver = inject(BreakpointObserver);\r\n\r\n constructor() {\r\n afterRenderEffect(() => {\r\n this.#width.set(window.innerWidth);\r\n this.#height.set(window.innerHeight);\r\n });\r\n\r\n this.breakpointObserver.observe(Object.values(this.deviceBreakpoints)).subscribe((state) => {\r\n const device = this.devicePriority.find((key) => state.breakpoints[this.deviceBreakpoints[key]]);\r\n\r\n this.#device.set(device ?? 'desktop');\r\n });\r\n fromEvent(window, 'resize')\r\n .pipe(debounceTime(100))\r\n .subscribe(() => {\r\n this.#width.set(window.innerWidth);\r\n this.#height.set(window.innerHeight);\r\n });\r\n }\r\n}\r\n","import { Directive, effect, inject, input, Signal, TemplateRef, ViewContainerRef } from '@angular/core';\r\n\r\nimport { Devices } from '@reforgium/internal';\r\n\r\n// noinspection ES6PreferShortImport\r\nimport { AdaptiveService } from './adaptive.service';\r\n\r\n/**\r\n * Structural directive `*ssIfDevice`.\r\n *\r\n * Shows or hides an element based on the current device type,\r\n * as determined by `AdaptiveService`.\r\n *\r\n * Example:\r\n * ```html\r\n * <div *ssIfDevice=\"'desktop'\">Desktop only</div>\r\n * <div *ssIfDevice=\"['mobile', 'tablet']\">For mobile and tablets</div>\r\n * <div *ssIfDevice=\"'mobile'; inverse: true\"> Hide on mobile</div>\r\n * ```\r\n *\r\n * Parameters:\r\n * - `ssIfDevice` — one or more `Devices` values (`'desktop' | 'tablet' | 'mobile'`)\r\n * - `inverse` — inverts the display condition\r\n *\r\n * Works reactively: when the device type changes in `AdaptiveService`,\r\n * the template is automatically added or removed from the DOM.\r\n */\r\n@Directive({\r\n selector: '[reIfDevice]',\r\n standalone: true,\r\n})\r\nexport class IfDeviceDirective {\r\n device = input<Devices | Devices[]>(undefined, { alias: 'ssIfDevice' });\r\n inverse = input<boolean>(false);\r\n\r\n private readonly tpl = inject(TemplateRef);\r\n private readonly vcr = inject(ViewContainerRef);\r\n private readonly adaptive = inject(AdaptiveService);\r\n\r\n private allowedDevices: Devices[] = [];\r\n private hasView = false;\r\n\r\n private readonly currentDevice: Signal<Devices> = this.adaptive.device;\r\n\r\n constructor() {\r\n effect(() => {\r\n const device = this.device();\r\n\r\n if (device) {\r\n this.allowedDevices = Array.isArray(device) ? device : [device];\r\n }\r\n\r\n this.updateView();\r\n });\r\n }\r\n\r\n private updateView() {\r\n const isAllowed = this.allowedDevices.includes(this.currentDevice());\r\n const shouldShow = this.inverse() ? !isAllowed : isAllowed;\r\n\r\n if (shouldShow && !this.hasView) {\r\n this.vcr.createEmbeddedView(this.tpl);\r\n this.hasView = true;\r\n } else if (!shouldShow && this.hasView) {\r\n this.vcr.clear();\r\n this.hasView = false;\r\n }\r\n }\r\n}\r\n","import { Langs } from '@reforgium/internal';\n\n/**\n * Language data model from localization server\n *\n * @description\n * `Model` for translation data\n * `namespace` - git project name\n * `code` - masked query: ${page}.${recordKey}\n * `value` - translation value\n */\nexport interface LangDto {\n namespace: string;\n code: string;\n localization: string;\n}\n\n/**\n * Data model for translation\n *\n * @description\n * `key` - masked query: ${page}.${recordKey}\n * `value` - translation value or nested model\n */\nexport interface LangModel {\n [key: string]: string | LangModel;\n}\n\n/**\n * Parameters for text formatting\n *\n * @description\n * `key` - mask key\n * `value` - mask value\n * example: {{`key1`}} will be replaced with `value1`\n */\nexport type LangParams = Record<string, string>;\n\n/**\n * Represents configuration settings for localization.\n *\n * This interface is used to define the locale configuration structure,\n * which can include URL, resource origin information, default language,\n * and related values for regional or localization settings.\n *\n * Properties:\n * - `url` specifies the localization URL for loading resources.\n * - `isFromAssets` indicates whether resources are loaded from application assets.\n * - `defaultLang` defines optional default language for localization.\n * - `defaultValue` - optional default value for locale resource.\n * - `kgValue` specifies optional localization value with variants `kg` or `ky`.\n */\nexport interface LocaleConfig {\n url: string;\n isFromAssets: boolean;\n defaultLang?: Langs;\n defaultValue?: string;\n kgValue?: 'kg' | 'ky';\n}\n\nexport const innerLangVal = Symbol('reInnerLangVal');\n","import { InjectionToken } from '@angular/core';\r\n\r\nimport { LocaleConfig } from './lang.models';\r\n\r\n/**\r\n * Injection token for providing locale configuration to the language module.\r\n *\r\n * Used to inject `LocaleConfig` into services and components that require\r\n * internationalization settings (e.g., locale, date formats, translations).\r\n *\r\n * Example:\r\n * ```typescript\r\n * providers: [\r\n * { provide: LANG_CONFIG, useValue: { locale: 'ru', ... } }\r\n * ]\r\n * ```\r\n *\r\n * The token can be injected using Angular's DI system:\r\n * ```typescript\r\n * private config = inject(LANG_CONFIG);\r\n * ```\r\n */\r\nexport const LANG_CONFIG = new InjectionToken<LocaleConfig>('RE_LANG_CONFIG');\r\n","import { HttpClient } from '@angular/common/http';\r\nimport { computed, inject, Injectable, Signal, signal } from '@angular/core';\r\n\r\nimport { Langs } from '@reforgium/internal';\r\n\r\nimport { innerLangVal, LangDto, LangModel, LangParams } from './lang.models';\r\nimport { LANG_CONFIG } from './locale.provider';\r\n\r\n/**\r\n * LangService provides functionality for managing and tracking language settings\r\n * and translations in the application. It is designed to handle localization needs,\r\n * loading language resources, caching translations, and dynamically applying translations\r\n * throughout the application.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class LangService {\r\n private readonly config = inject(LANG_CONFIG);\r\n private readonly http = inject(HttpClient);\r\n\r\n readonly #lang = signal<Langs>(this.getStoredLang());\r\n readonly #cache = signal<LangModel>({});\r\n\r\n readonly #loadedNamespaces = new Set<string>();\r\n readonly #pendingLoads = new Map<string, Promise<void>>();\r\n\r\n /**\r\n * Computed property determining the current language setting.\r\n *\r\n * - If private method `#lang` returns 'ru', this property will return 'ru'.\r\n * - If `#lang` returns another value, the `config.kgValue` property is checked:\r\n * - If `config.kgValue` is defined, the property will return its value.\r\n * - If `config.kgValue` is not defined, the property will return the default value 'kg'.\r\n */\r\n readonly currentLang = computed(() => {\r\n const lang = this.#lang();\r\n\r\n return lang === 'ru' ? 'ru' : (this.config?.kgValue ?? 'kg');\r\n });\r\n /**\r\n * Extracts readonly value from private property `#lang` and assigns it to `innerLangVal`.\r\n * Expected that property `#lang` has `asReadonly` method that returns immutable representation.\r\n */\r\n readonly [innerLangVal] = this.#lang.asReadonly();\r\n\r\n /**\r\n * Sets the current language for the application.\r\n *\r\n * @param {Langs | 'ky'} lang - The language to set.\r\n * Accepts predefined type `Langs` or 'ky' to set Kyrgyz language.\r\n * @return {void} Returns no value.\r\n */\r\n setLang(lang: Langs | 'ky'): void {\r\n const langVal = lang === 'ky' ? 'kg' : lang;\r\n\r\n if (langVal !== this.#lang()) {\r\n this.#lang.set(langVal);\r\n localStorage.setItem('lang', langVal);\r\n\r\n const namespaces = Array.from(this.#loadedNamespaces.values()).map((key) => key.split('.')[1]);\r\n\r\n this.#loadedNamespaces.clear();\r\n\r\n namespaces.forEach((ns) => void this.loadNamespace(ns));\r\n }\r\n }\r\n\r\n /**\r\n * Gets value based on a provided query and optionally applies specified parameters.\r\n *\r\n * @param {string} query - Query string used to retrieve desired value.\r\n * @param {LangParams} [params] - Optional parameters to apply to retrieved value.\r\n * @return {string} Retrieved value after optional parameter application,\r\n * or default value if a query is not found.\r\n */\r\n get(query: string, params?: LangParams): string {\r\n const value = this.getChainedValue(query);\r\n\r\n if (params) {\r\n return this.applyParams((value ?? query) as string, params);\r\n }\r\n\r\n return (value as string | undefined) ?? this.config.defaultValue ?? query;\r\n }\r\n\r\n /**\r\n * Observes changes to a specified translation key and dynamically computes its value.\r\n *\r\n * @param {string} query - Translation key to observe, typically in format \"namespace.key\".\r\n * @param {LangParams} [params] - Optional parameters for interpolation or\r\n * dynamic content replacement in translation value.\r\n * @return {Signal<string>} Computed value that dynamically updates\r\n * with translation matching a provided query and parameters.\r\n */\r\n observe(query: string, params?: LangParams): Signal<string> {\r\n const [ns] = query.split('.');\r\n\r\n if (!this.#loadedNamespaces.has(this.makeNamespaceKey(ns))) {\r\n void this.loadNamespace(ns);\r\n }\r\n\r\n return computed(() => this.get(query, params));\r\n }\r\n\r\n /**\r\n * Loads specified namespace, ensuring its caching and availability for use.\r\n *\r\n * @param {string} ns - Namespace name to load.\r\n * @return {Promise<void>} Promise that resolves on a successful namespace load,\r\n * or rejects when error occurs during a process.\r\n */\r\n async loadNamespace(ns: string): Promise<void> {\r\n const key = this.makeNamespaceKey(ns);\r\n\r\n if (this.#loadedNamespaces.has(key)) {\r\n return;\r\n }\r\n\r\n if (this.#pendingLoads.has(key)) {\r\n return this.#pendingLoads.get(key)!;\r\n }\r\n\r\n const promise = new Promise<void>((resolve, reject) => {\r\n this.http.get<LangDto[] | LangModel>(this.makeUrl(ns)).subscribe({\r\n next: (res) => {\r\n const existing = this.#cache();\r\n const resolved = Array.isArray(res) ? this.parseModelToRecord(res) : this.parseAssetToRecord(ns, res);\r\n\r\n this.#cache.set({ ...existing, ...resolved });\r\n this.#loadedNamespaces.add(key);\r\n resolve();\r\n },\r\n error: (err) => {\r\n this.#pendingLoads.delete(key);\r\n reject(err);\r\n },\r\n complete: () => this.#pendingLoads.delete(key),\r\n });\r\n });\r\n\r\n this.#pendingLoads.set(key, promise);\r\n\r\n return promise;\r\n }\r\n\r\n private parseModelToRecord(model: LangDto[]): LangModel {\r\n const records: LangModel = {};\r\n\r\n for (const item of model) {\r\n records[item.code] = item.localization;\r\n }\r\n\r\n return records;\r\n }\r\n\r\n private parseAssetToRecord(page: string, data: LangModel): LangModel {\r\n const records: LangModel = {};\r\n\r\n for (const [k, v] of Object.entries(data)) {\r\n records[`${page}.${k}`] = v;\r\n }\r\n\r\n return records;\r\n }\r\n\r\n private applyParams(text: string, params: LangParams): string {\r\n return text.replace(/\\{\\{(.*?)}}/g, (_, k) => params[k.trim()] ?? '');\r\n }\r\n\r\n private getChainedValue(query = '', source = this.#cache()) {\r\n const [page, key, ...normalizedPath] = query.split('.');\r\n\r\n return [`${page}.${key}`, ...normalizedPath].reduce<LangModel | string | undefined>(\r\n (acc, key) => (typeof acc === 'object' ? (acc[key] ?? acc[query]) : undefined),\r\n source,\r\n ) as string | undefined;\r\n }\r\n\r\n private getStoredLang(): Langs {\r\n return (localStorage.getItem('lang') as Langs) || this.config.defaultLang || 'ru';\r\n }\r\n\r\n private makeUrl(ns: string): string {\r\n const suffix = this.config.isFromAssets ? `.${this.#lang()}.json` : `?language=${this.#lang()}`;\r\n\r\n return `${this.config.url}/${ns}${suffix}`;\r\n }\r\n\r\n private makeNamespaceKey(ns: string) {\r\n return `${this.#lang()}.${ns}`;\r\n }\r\n}\r\n","import { inject, Pipe, PipeTransform } from '@angular/core';\r\n\r\nimport { LangParams } from './lang.models';\r\nimport { LangService } from './lang.service';\r\n\r\n/**\r\n * Custom Angular pipe that transforms a language key and additional parameters into a localized string.\r\n *\r\n * The pipe is declared as standalone and impure — meaning it can be used without importing a module\r\n * and will be recalculated when the state changes (for example, when the language is switched).\r\n *\r\n * In its operation, the pipe observes and caches language keys to improve performance,\r\n * using LangService to retrieve translated strings based on the current application language.\r\n *\r\n * The transformation involves accepting a key string and optional parameters,\r\n * forming a cache key, and returning the localized value corresponding to that request.\r\n *\r\n * @implements {PipeTransform}\r\n */\r\n@Pipe({ name: 'lang', standalone: true, pure: false })\r\nexport class LangPipe implements PipeTransform {\r\n private readonly lang = inject(LangService);\r\n private readonly cache = new Map<string, () => string>();\r\n\r\n transform(query: string, params?: LangParams): string {\r\n const key = query + JSON.stringify(params);\r\n\r\n if (!this.cache.has(key)) {\r\n this.cache.set(key, this.lang.observe(query, params));\r\n }\r\n\r\n return this.cache.get(key)!();\r\n }\r\n}\r\n","import { Themes } from '@reforgium/internal';\r\n\r\n/**\r\n * Type-safe mapping of available theme names.\r\n *\r\n * Provides a constant record that maps theme identifiers to their corresponding string values.\r\n * This ensures compile-time safety when referencing theme names throughout the application.\r\n *\r\n * Available themes:\r\n * - `light` - Light theme variant\r\n * - `dark` - Dark theme variant\r\n *\r\n * @example\r\n * ```typescript\r\n * const currentTheme = themes.light; // 'light'\r\n * const isDarkTheme = theme === themes.dark;\r\n * ```\r\n */\r\nexport const themes: Record<Themes, Themes> = {\r\n light: 'light',\r\n dark: 'dark',\r\n} as const;\r\n\r\n/**\r\n * CSS class prefix used for dark theme styling.\r\n *\r\n * This constant defines the prefix applied to HTML elements when the dark theme is active.\r\n * It is typically added to the root element or specific components to enable dark theme styles.\r\n *\r\n * @example\r\n * ```typescript\r\n * document.body.classList.add(darkThemePrefix); // Applies 're-dark' class\r\n * ```\r\n */\r\nexport const darkThemePrefix = 're-dark';\r\n","import { InjectionToken } from '@angular/core';\r\n\r\nimport { ThemeConfig } from './theme.models';\r\n// noinspection ES6PreferShortImport\r\nimport { themes } from './themes.constant';\r\n\r\n/**\r\n * Default theme configuration object.\r\n *\r\n * Defines the initial theme settings for the application.\r\n * By default, sets the light theme as the active theme.\r\n *\r\n * This configuration can be overridden when providing `THEME_CONFIG` token\r\n * at the module or application level.\r\n * ```\r\n */\r\nexport const defaultThemeConfig = {\r\n defaultTheme: themes.light,\r\n};\r\n\r\n/**\r\n * Injection token for theme configuration.\r\n *\r\n * Used to provide custom theme settings via Angular's dependency injection system.\r\n * The token expects a value of type `ThemeConfig`.\r\n *\r\n * Example usage:\r\n * ```typescript\r\n * // In providers array:\r\n * { provide: THEME_CONFIG, useValue: { defaultTheme: themes.dark } }\r\n *\r\n * // In service or component:\r\n * private themeConfig = inject(THEME_CONFIG);\r\n * ```\r\n *\r\n * If not provided, `defaultThemeConfig` will be used as fallback.\r\n */\r\nexport const THEME_CONFIG = new InjectionToken<ThemeConfig>('RE_THEME_CONFIG');\r\n","import { computed, effect, inject, Injectable, signal } from '@angular/core';\r\n\r\nimport { Themes } from '@reforgium/internal';\r\n\r\n// noinspection ES6PreferShortImport\r\nimport { THEME_CONFIG } from './theme.provider';\r\n// noinspection ES6PreferShortImport\r\nimport { darkThemePrefix, themes } from './themes.constant';\r\n\r\n/**\r\n * Service for managing application theme.\r\n *\r\n * Allows getting the current theme and switching between light and dark.\r\n * Automatically saves the selected theme to `localStorage` and applies CSS class to `<html>` element.\r\n *\r\n * Example:\r\n * ```ts\r\n * const theme = inject(ThemeService);\r\n * theme.switch('dark');\r\n * console.log(theme.theme()); // 'dark'\r\n * ```\r\n */\r\n@Injectable({\r\n providedIn: 'root',\r\n})\r\nexport class ThemeService {\r\n private readonly config = inject(THEME_CONFIG);\r\n private readonly themeDefault = this.config?.defaultTheme || themes.light;\r\n\r\n #theme = signal<Themes>(this.themeDefault);\r\n\r\n /**\r\n * Current active theme (`light` or `dark`).\r\n *\r\n * Value is reactive — can be used in template or `computed`.\r\n * ```html\r\n * <div [class.dark]=\"themeService.theme() === 'dark'\"></div>\r\n * <div [class]=\"themeService.theme()\"></div>\r\n * ```\r\n */\r\n theme = computed(() => this.#theme());\r\n\r\n /**\r\n * Convenient flag returning `true` if light theme is active.\r\n * Suitable for conditional style application or resource selection.\r\n */\r\n isLight = computed(() => this.#theme() === themes.light);\r\n\r\n constructor() {\r\n effect(() => {\r\n const theme = (localStorage.getItem('theme') as Themes) || this.themeDefault;\r\n\r\n this.switch(theme);\r\n });\r\n effect(() => localStorage.setItem('theme', this.#theme()));\r\n }\r\n\r\n /**\r\n * Switches theme.\r\n *\r\n * If a parameter is not provided — performs toggle between `light` and `dark`.\r\n * Also, automatically updates `<html>` class and saves selection to `localStorage`.\r\n *\r\n * @param theme — explicit theme value (`'light'` or `'dark'`).\r\n */\r\n switch(theme?: Themes) {\r\n const html = document.querySelector('html')!;\r\n const newTheme = theme ?? (this.#theme() === themes.light ? themes.dark : themes.light);\r\n\r\n newTheme === themes.dark && html.classList.add(darkThemePrefix);\r\n newTheme === themes.light && html.classList.remove(darkThemePrefix);\r\n this.#theme.set(newTheme);\r\n }\r\n}\r\n","import { EnvironmentProviders, LOCALE_ID, makeEnvironmentProviders } from '@angular/core';\r\n\r\nimport { CURRENT_DEVICE, SELECTED_LANG, SELECTED_THEME, TRANSLATION } from '@reforgium/internal';\r\n\r\n// noinspection ES6PreferShortImport\r\nimport { AdaptiveService, defaultBreakpoints, DEVICE_BREAKPOINTS, DeviceBreakpoints } from '../adaptive';\r\nimport { innerLangVal, LANG_CONFIG, LangService, LocaleConfig } from '../lang';\r\nimport { defaultThemeConfig, THEME_CONFIG, ThemeConfig, ThemeService } from '../theme';\r\n\r\n/**\r\n * Configuration object for initializing the Presentia application providers.\r\n *\r\n * @property {LocaleConfig} locale - Locale configuration (required). Defines language and localization settings.\r\n * @property {ThemeConfig} [theme] - Theme configuration (optional). Defines the application theme. Defaults to `defaultThemeConfig` if not provided.\r\n * @property {DeviceBreakpoints} [breakpoints] - Device breakpoints configuration (optional). Defines responsive breakpoints. Defaults to `defaultBreakpoints` if not provided.\r\n */\r\nexport interface AppConfig {\r\n locale: LocaleConfig;\r\n theme?: ThemeConfig;\r\n breakpoints?: DeviceBreakpoints;\r\n}\r\n\r\n/**\r\n * Provides environment-level providers for Presentia application initialization.\r\n *\r\n * This function configures essential application services:\r\n * - Language and localization settings\r\n * - Theme configuration\r\n * - Adaptive/responsive breakpoints\r\n * - Current device detection\r\n *\r\n * @param {AppConfig} config - Configuration object containing locale, theme, and breakpoints settings.\r\n * @returns {EnvironmentProviders} A collection of Angular providers for the application environment.\r\n *\r\n * @example\r\n * ```typescript\r\n * export const appConfig: ApplicationConfig = {\r\n * providers: [\r\n * provideReInit({\r\n * locale: { defaultLang: 'en', supportedLangs: ['en', 'ru'] },\r\n * theme: { defaultTheme: 'dark' },\r\n * breakpoints: { mobile: 768, tablet: 1024 }\r\n * })\r\n * ]\r\n * };\r\n * ```\r\n */\r\nexport function provideReInit(config: AppConfig): EnvironmentProviders {\r\n return makeEnvironmentProviders([\r\n { provide: TRANSLATION, deps: [LangService], useFactory: (ls: LangService) => ls },\r\n { provide: SELECTED_LANG, deps: [LangService], useFactory: (ls: LangService) => ls[innerLangVal] },\r\n { provide: SELECTED_THEME, deps: [ThemeService], useFactory: (ls: ThemeService) => ls.theme },\r\n { provide: CURRENT_DEVICE, deps: [AdaptiveService], useFactory: (ls: AdaptiveService) => ls.device },\r\n { provide: DEVICE_BREAKPOINTS, useValue: config.breakpoints || defaultBreakpoints },\r\n { provide: THEME_CONFIG, useValue: config.theme || defaultThemeConfig },\r\n { provide: LANG_CONFIG, useValue: config.locale || {} },\r\n { provide: LOCALE_ID, useValue: config.locale.defaultLang ?? 'ru' },\r\n ]);\r\n}\r\n","import { inject, Injectable } from '@angular/core';\r\nimport { Meta, Title } from '@angular/platform-browser';\r\n\r\nimport { OgType, TwitterCardType } from './seo.models';\r\n\r\n/**\r\n * Service for managing page SEO metadata.\r\n *\r\n * Allows centrally setting title, description, keywords,\r\n * Open Graph and Twitter Card tags, canonical link, and JSON-LD schema.\r\n *\r\n * Example:\r\n * ```ts\r\n * const seo = inject(SeoService);\r\n * seo.setTitle('Home Page');\r\n * seo.setDescription('Site Description');\r\n * seo.setOg({ title: 'Home', type: 'website' });\r\n * ```\r\n */\r\n@Injectable()\r\nexport class SeoService {\r\n private title = inject(Title);\r\n private meta = inject(Meta);\r\n\r\n /**\r\n * Sets page title (`<title>`).\r\n * @param value title text\r\n */\r\n setTitle(value: string) {\r\n this.title.setTitle(value);\r\n }\r\n\r\n /**\r\n * Sets page description (`<meta name=\"description\">`).\r\n * @param desc brief content description\r\n */\r\n setDescription(desc: string) {\r\n this.upsert({ name: 'description', content: desc });\r\n }\r\n\r\n /**\r\n * Sets page keywords (`<meta name=\"keywords\">`).\r\n * @param keywords array of keywords\r\n */\r\n setKeywords(keywords: string[]) {\r\n this.upsert({ name: 'keywords', content: keywords.join(', ') });\r\n }\r\n\r\n /**\r\n * Sets directives for search engines (`<meta name=\"robots\">`).\r\n * @param value value, e.g. `\"index,follow\"`\r\n */\r\n setRobots(value: string) {\r\n this.upsert({ name: 'robots', content: value }); // e.g. \"index,follow\"\r\n }\r\n\r\n /**\r\n * Sets canonical link (`<link rel=\"canonical\">`).\r\n * @param url absolute URL of canonical page\r\n */\r\n setCanonical(url: string) {\r\n this.upsertLink('canonical', url);\r\n }\r\n\r\n /**\r\n * Sets Open Graph meta tags.\r\n * @param opts object with Open Graph fields (`title`, `description`, `image`, `url`, `type`, etc.)\r\n */\r\n setOg(opts: OgType) {\r\n for (const [k, v] of Object.entries(opts)) {\r\n v && this.upsert({ property: `og:${k}`, content: v });\r\n }\r\n }\r\n\r\n /**\r\n * Sets Twitter Card meta tags.\r\n * @param opts object with Twitter Card fields (`card`, `title`, `description`, `image`, etc.)\r\n */\r\n setTwitter(opts: TwitterCardType) {\r\n for (const [k, v] of Object.entries(opts)) {\r\n v && this.upsert({ name: `twitter:${k}`, content: v });\r\n }\r\n }\r\n\r\n /**\r\n * Embeds JSON-LD schema (structured data) in `<head>`.\r\n * @param schema schema object (will be serialized to JSON)\r\n */\r\n setJsonLd(schema: object) {\r\n const id = 'app-jsonld';\r\n let el = document.getElementById(id) as HTMLScriptElement | null;\r\n\r\n if (!el) {\r\n el = document.createElement('script');\r\n el.type = 'application/ld+json';\r\n el.id = id;\r\n document.head.appendChild(el);\r\n }\r\n\r\n el.text = JSON.stringify(schema);\r\n }\r\n\r\n private upsert(tag: { name?: string; property?: string; content: string }) {\r\n if (tag.name) {\r\n this.meta.updateTag(tag, `name='${tag.name}'`);\r\n } else if (tag.property) {\r\n this.meta.updateTag(tag, `property='${tag.property}'`);\r\n }\r\n }\r\n\r\n private upsertLink(rel: string, href: string) {\r\n const head = document.head;\r\n let link = head.querySelector<HTMLLinkElement>(`link[rel=\"${rel}\"]`);\r\n\r\n if (!link) {\r\n link = document.createElement('link');\r\n link.rel = rel;\r\n head.appendChild(link);\r\n }\r\n\r\n link.href = href;\r\n }\r\n}\r\n","import { DestroyRef, inject, Injectable } from '@angular/core';\r\nimport { ActivatedRoute, NavigationEnd, Router } from '@angular/router';\r\nimport { filter } from 'rxjs/operators';\r\n\r\nimport { SeoService } from './seo.service';\r\n\r\n/**\r\n * Service that listens to Angular route changes and automatically updates SEO metadata\r\n * (title, description, Open Graph, Twitter cards, JSON-LD, canonical URL, robots meta tag)\r\n * based on route data configuration.\r\n *\r\n * @example\r\n * ```typescript\r\n * const routes: Routes = [{\r\n * path: 'about',\r\n * component: AboutComponent,\r\n * data: {\r\n * title: 'About Us',\r\n * description: 'Learn more about our company',\r\n * robots: 'index,follow'\r\n * }\r\n * }];\r\n * ```\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class SeoRouteListener {\r\n private router = inject(Router);\r\n private seo = inject(SeoService);\r\n private ar = inject(ActivatedRoute);\r\n private destroyRef = inject(DestroyRef);\r\n\r\n /**\r\n * Initializes the route listener to monitor navigation events and update SEO metadata.\r\n * Subscribes to router NavigationEnd events and automatically unsubscribes on component destruction.\r\n *\r\n * @param baseUrl - The base URL of the application used for constructing canonical URLs.\r\n * Trailing slashes will be removed automatically.\r\n */\r\n init(baseUrl: string) {\r\n const sub = this.router.events.pipe(filter((e) => e instanceof NavigationEnd)).subscribe(() => {\r\n const route = this.deepest(this.ar);\r\n const data = route.snapshot.data as {\r\n title?: string;\r\n description?: string;\r\n robots?: string;\r\n canonical?: string;\r\n og?: Record<string, string>;\r\n twitter?: Record<string, string>;\r\n jsonld?: object;\r\n };\r\n const url = data.canonical ?? baseUrl.replace(/\\/+$/, '') + this.router.url;\r\n\r\n data.title && this.seo.setTitle(data.title);\r\n data.description && this.seo.setDescription(data.description);\r\n data.twitter && this.seo.setTwitter(data.twitter);\r\n data.jsonld && this.seo.setJsonLd(data.jsonld);\r\n\r\n this.seo.setRobots(data.robots ?? 'index,follow');\r\n this.seo.setCanonical(url);\r\n this.seo.setOg({\r\n title: data.title,\r\n description: data.description,\r\n url: url,\r\n ...data.og,\r\n });\r\n });\r\n\r\n this.destroyRef.onDestroy(() => sub.unsubscribe());\r\n }\r\n\r\n /**\r\n * Recursively finds the deepest (most nested) activated route in the route tree.\r\n * This is used to extract route data from the currently active leaf route.\r\n *\r\n * @param r - The root activated route to start traversing from.\r\n * @returns The deepest child route in the hierarchy.\r\n */\r\n private deepest(r: ActivatedRoute): ActivatedRoute {\r\n let cur = r;\r\n\r\n while (cur.firstChild) {\r\n cur = cur.firstChild;\r\n }\r\n\r\n return cur;\r\n }\r\n}\r\n","import { computed, DestroyRef, inject, Injectable, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { NavigationEnd, Router, UrlSegment } from '@angular/router';\nimport { filter, map, startWith } from 'rxjs';\n\nimport { deepEqual } from '@reforgium/internal';\n\n/**\n * Reactive snapshot of the current route (the deepest active route).\n * Updates on every `NavigationEnd` event.\n *\n * Provides:\n * - `params` / `query` — strings (as in Angular Router)\n * - `data` — arbitrary data (from route configuration/resolvers)\n * - `url` — string assembled from `UrlSegment[]`\n * - `fragment` — hash (#section)\n * - `selectData(key)` — type-safe selector for `data`\n * - `state` — combined computed object (convenient for single subscriber)\n */\n@Injectable({ providedIn: 'root' })\nexport class RouteWatcher {\n private readonly router = inject(Router);\n private readonly destroyRef = inject(DestroyRef);\n\n #params = signal<Record<string, string>>({});\n #query = signal<Record<string, string>>({});\n #data = signal<Record<string, unknown>>({});\n #url = signal<string>('');\n #fragment = signal<string | null>(null);\n\n /** Signal for tracking and retrieving URL parameters */\n readonly params = this.#params.asReadonly();\n\n /** Signal for tracking and retrieving query parameters */\n readonly query = this.#query.asReadonly();\n\n /** Signal for tracking and retrieving route data */\n readonly data = this.#data.asReadonly();\n\n /** Signal for tracking and retrieving URL */\n readonly url = this.#url.asReadonly();\n\n /** Signal for tracking and retrieving URL fragment */\n readonly fragment = this.#fragment.asReadonly();\n\n /** Combined computed snapshot (to avoid multiple effects) */\n readonly state = computed(() => ({\n params: this.#params(),\n query: this.#query(),\n data: this.#data(),\n url: this.#url(),\n fragment: this.#fragment(),\n }));\n\n constructor() {\n const read = () => {\n const snap = this.deepestSnapshot();\n const url = joinUrl(snap.url);\n\n !deepEqual(snap.params, this.#params()) && this.#params.set(snap.params as Record<string, string>);\n !deepEqual(snap.queryParams, this.#query()) && this.#query.set(snap.queryParams as Record<string, string>);\n !deepEqual(snap.data, this.#data()) && this.#data.set(snap.data as Record<string, unknown>);\n this.#url() !== url && this.#url.set(url);\n this.#fragment() !== snap.fragment && this.#fragment.set(snap.fragment ?? null);\n };\n\n read();\n\n this.router.events\n .pipe(\n startWith(new NavigationEnd(0, this.router.url, this.router.url)),\n filter((e) => e instanceof NavigationEnd),\n map(() => true),\n takeUntilDestroyed(this.destroyRef),\n )\n .subscribe(() => read());\n }\n\n /** Convenient selector for a data key with type-safe casting */\n selectData<T = unknown>(key: string) {\n return computed<T | undefined>(() => this.#data()[key] as T | undefined);\n }\n\n private deepestSnapshot() {\n // work with snapshot — we need a \"frozen\" point at NavigationEnd moment\n let snap = this.router.routerState.snapshot.root;\n\n while (snap.firstChild) {\n snap = snap.firstChild;\n }\n\n return snap;\n }\n}\n\n/** Joins `UrlSegment[]` into a path string */\nfunction joinUrl(segments: UrlSegment[]): string {\n return segments.length ? segments.map((s) => s.path).join('/') : '';\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["filter"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -3,63 +3,96 @@ import { InjectionToken, Signal, PipeTransform, EnvironmentProviders } from '@an
|
|
|
3
3
|
import * as _reforgium_internal from '@reforgium/internal';
|
|
4
4
|
import { Devices, Langs, Themes } from '@reforgium/internal';
|
|
5
5
|
|
|
6
|
-
/**
|
|
6
|
+
/** Breakpoints for different device types */
|
|
7
7
|
type DeviceBreakpoints = Record<Devices, string>;
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Default breakpoints for device type detection.
|
|
11
|
+
*
|
|
12
|
+
* Defines media queries for each device category:
|
|
13
|
+
* - `mobile` — screens up to 719px wide
|
|
14
|
+
* - `tablet` — screens from 720px to 1399px wide
|
|
15
|
+
* - `desktop-s` — small desktop screens from 1400px to 1919px wide
|
|
16
|
+
* - `desktop` — large desktop screens 1920px and wider
|
|
17
|
+
*
|
|
18
|
+
* These breakpoints are used by `AdaptiveService` to determine the current device type.
|
|
19
|
+
*/
|
|
9
20
|
declare const defaultBreakpoints: {
|
|
10
21
|
mobile: string;
|
|
11
22
|
tablet: string;
|
|
12
23
|
'desktop-s': string;
|
|
13
24
|
desktop: string;
|
|
14
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Injection token for providing custom device breakpoints.
|
|
28
|
+
*
|
|
29
|
+
* By default, provides `defaultBreakpoints`, but can be overridden
|
|
30
|
+
* at any level of the dependency injection tree to customize
|
|
31
|
+
* the device detection behavior.
|
|
32
|
+
*
|
|
33
|
+
* Example of overriding:
|
|
34
|
+
* ```typescript
|
|
35
|
+
* {
|
|
36
|
+
* provide: DEVICE_BREAKPOINTS,
|
|
37
|
+
* useValue: {
|
|
38
|
+
* mobile: '(max-width: 599px)',
|
|
39
|
+
* tablet: '(min-width: 600px) and (max-width: 1199px)',
|
|
40
|
+
* 'desktop-s': '(min-width: 1200px) and (max-width: 1799px)',
|
|
41
|
+
* desktop: '(min-width: 1800px)'
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* Used by `AdaptiveService` to observe media query changes.
|
|
47
|
+
*/
|
|
15
48
|
declare const DEVICE_BREAKPOINTS: InjectionToken<DeviceBreakpoints>;
|
|
16
49
|
|
|
17
50
|
/**
|
|
18
|
-
*
|
|
51
|
+
* The `AdaptiveService` is responsible for determining the device type, window dimensions, and screen orientation.
|
|
19
52
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
53
|
+
* Used for building adaptive interfaces, changing component behavior and styles
|
|
54
|
+
* depending on the current device or screen size.
|
|
22
55
|
*
|
|
23
|
-
*
|
|
24
|
-
* -
|
|
25
|
-
* -
|
|
26
|
-
* -
|
|
56
|
+
* Main features:
|
|
57
|
+
* - Reactive tracking of the current device (`desktop`, `tablet`, `mobile`).
|
|
58
|
+
* - Support for computed properties (`isDesktop`, `isPortrait`).
|
|
59
|
+
* - Automatic updates when the window is resized and breakpoints are crossed.
|
|
27
60
|
*
|
|
28
|
-
*
|
|
29
|
-
* - `BreakpointObserver`
|
|
30
|
-
* - `signal`
|
|
31
|
-
* - `fromEvent(window, 'resize')` —
|
|
61
|
+
* Implementation is based on:
|
|
62
|
+
* - `BreakpointObserver` from Angular CDK — for observing media queries.
|
|
63
|
+
* - `signal` and `computed` — for reactive state without zones.
|
|
64
|
+
* - `fromEvent(window, 'resize')` — for updating window dimensions with debouncing.
|
|
32
65
|
*
|
|
33
|
-
*
|
|
66
|
+
* The service is registered as `providedIn: 'root'` and is available throughout the application.
|
|
34
67
|
*/
|
|
35
68
|
declare class AdaptiveService {
|
|
36
69
|
#private;
|
|
37
70
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
71
|
+
* Current device type (reactive signal).
|
|
72
|
+
* Possible values: `'desktop' | 'tablet' | 'mobile'`.
|
|
40
73
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
74
|
+
* Updates automatically when screen width changes
|
|
75
|
+
* or when specified breakpoints are crossed (`DEVICE_BREAKPOINTS`).
|
|
43
76
|
*/
|
|
44
77
|
device: _angular_core.Signal<Devices>;
|
|
45
78
|
/**
|
|
46
|
-
*
|
|
47
|
-
*
|
|
79
|
+
* Current browser window width in pixels.
|
|
80
|
+
* Updates reactively on `resize` event.
|
|
48
81
|
*/
|
|
49
82
|
width: _angular_core.Signal<number>;
|
|
50
83
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
84
|
+
* Current browser window height in pixels.
|
|
85
|
+
* Updates reactively on `resize` event.
|
|
53
86
|
*/
|
|
54
87
|
height: _angular_core.Signal<number>;
|
|
55
88
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
89
|
+
* Computed signal indicating whether the current device is a desktop.
|
|
90
|
+
* Used for conditional rendering or layout configuration.
|
|
58
91
|
*/
|
|
59
92
|
isDesktop: _angular_core.Signal<boolean>;
|
|
60
93
|
/**
|
|
61
|
-
*
|
|
62
|
-
*
|
|
94
|
+
* Computed signal determining whether the screen is in portrait orientation.
|
|
95
|
+
* Returns `true` if window height is greater than width.
|
|
63
96
|
*/
|
|
64
97
|
isPortrait: _angular_core.Signal<boolean>;
|
|
65
98
|
private deviceBreakpoints;
|
|
@@ -71,24 +104,24 @@ declare class AdaptiveService {
|
|
|
71
104
|
}
|
|
72
105
|
|
|
73
106
|
/**
|
|
74
|
-
*
|
|
107
|
+
* Structural directive `*ssIfDevice`.
|
|
75
108
|
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
109
|
+
* Shows or hides an element based on the current device type,
|
|
110
|
+
* as determined by `AdaptiveService`.
|
|
78
111
|
*
|
|
79
|
-
*
|
|
112
|
+
* Example:
|
|
80
113
|
* ```html
|
|
81
|
-
* <div *ssIfDevice="'desktop'"
|
|
82
|
-
* <div *ssIfDevice="['mobile', 'tablet']"
|
|
83
|
-
* <div *ssIfDevice="'mobile'; inverse: true"
|
|
114
|
+
* <div *ssIfDevice="'desktop'">Desktop only</div>
|
|
115
|
+
* <div *ssIfDevice="['mobile', 'tablet']">For mobile and tablets</div>
|
|
116
|
+
* <div *ssIfDevice="'mobile'; inverse: true"> Hide on mobile</div>
|
|
84
117
|
* ```
|
|
85
118
|
*
|
|
86
|
-
*
|
|
87
|
-
* - `ssIfDevice` —
|
|
88
|
-
* - `inverse` —
|
|
119
|
+
* Parameters:
|
|
120
|
+
* - `ssIfDevice` — one or more `Devices` values (`'desktop' | 'tablet' | 'mobile'`)
|
|
121
|
+
* - `inverse` — inverts the display condition
|
|
89
122
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
123
|
+
* Works reactively: when the device type changes in `AdaptiveService`,
|
|
124
|
+
* the template is automatically added or removed from the DOM.
|
|
92
125
|
*/
|
|
93
126
|
declare class IfDeviceDirective {
|
|
94
127
|
device: _angular_core.InputSignal<Devices | Devices[] | undefined>;
|
|
@@ -161,6 +194,24 @@ interface LocaleConfig {
|
|
|
161
194
|
}
|
|
162
195
|
declare const innerLangVal: unique symbol;
|
|
163
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Injection token for providing locale configuration to the language module.
|
|
199
|
+
*
|
|
200
|
+
* Used to inject `LocaleConfig` into services and components that require
|
|
201
|
+
* internationalization settings (e.g., locale, date formats, translations).
|
|
202
|
+
*
|
|
203
|
+
* Example:
|
|
204
|
+
* ```typescript
|
|
205
|
+
* providers: [
|
|
206
|
+
* { provide: LANG_CONFIG, useValue: { locale: 'ru', ... } }
|
|
207
|
+
* ]
|
|
208
|
+
* ```
|
|
209
|
+
*
|
|
210
|
+
* The token can be injected using Angular's DI system:
|
|
211
|
+
* ```typescript
|
|
212
|
+
* private config = inject(LANG_CONFIG);
|
|
213
|
+
* ```
|
|
214
|
+
*/
|
|
164
215
|
declare const LANG_CONFIG: InjectionToken<LocaleConfig>;
|
|
165
216
|
|
|
166
217
|
/**
|
|
@@ -179,7 +230,7 @@ declare class LangService {
|
|
|
179
230
|
* - If private method `#lang` returns 'ru', this property will return 'ru'.
|
|
180
231
|
* - If `#lang` returns another value, the `config.kgValue` property is checked:
|
|
181
232
|
* - If `config.kgValue` is defined, the property will return its value.
|
|
182
|
-
* - If `config.kgValue` is not defined, the property will return default value 'kg'.
|
|
233
|
+
* - If `config.kgValue` is not defined, the property will return the default value 'kg'.
|
|
183
234
|
*/
|
|
184
235
|
readonly currentLang: Signal<"ru" | "kg" | "ky">;
|
|
185
236
|
/**
|
|
@@ -196,30 +247,30 @@ declare class LangService {
|
|
|
196
247
|
*/
|
|
197
248
|
setLang(lang: Langs | 'ky'): void;
|
|
198
249
|
/**
|
|
199
|
-
* Gets value based on provided query and optionally applies specified parameters.
|
|
250
|
+
* Gets value based on a provided query and optionally applies specified parameters.
|
|
200
251
|
*
|
|
201
252
|
* @param {string} query - Query string used to retrieve desired value.
|
|
202
253
|
* @param {LangParams} [params] - Optional parameters to apply to retrieved value.
|
|
203
254
|
* @return {string} Retrieved value after optional parameter application,
|
|
204
|
-
* or default value if query is not found.
|
|
255
|
+
* or default value if a query is not found.
|
|
205
256
|
*/
|
|
206
257
|
get(query: string, params?: LangParams): string;
|
|
207
258
|
/**
|
|
208
|
-
* Observes changes to specified translation key and dynamically computes its value.
|
|
259
|
+
* Observes changes to a specified translation key and dynamically computes its value.
|
|
209
260
|
*
|
|
210
261
|
* @param {string} query - Translation key to observe, typically in format "namespace.key".
|
|
211
262
|
* @param {LangParams} [params] - Optional parameters for interpolation or
|
|
212
263
|
* dynamic content replacement in translation value.
|
|
213
264
|
* @return {Signal<string>} Computed value that dynamically updates
|
|
214
|
-
* with translation matching provided query and parameters.
|
|
265
|
+
* with translation matching a provided query and parameters.
|
|
215
266
|
*/
|
|
216
267
|
observe(query: string, params?: LangParams): Signal<string>;
|
|
217
268
|
/**
|
|
218
269
|
* Loads specified namespace, ensuring its caching and availability for use.
|
|
219
270
|
*
|
|
220
271
|
* @param {string} ns - Namespace name to load.
|
|
221
|
-
* @return {Promise<void>} Promise that resolves on successful namespace load,
|
|
222
|
-
* or rejects when error occurs during process.
|
|
272
|
+
* @return {Promise<void>} Promise that resolves on a successful namespace load,
|
|
273
|
+
* or rejects when error occurs during a process.
|
|
223
274
|
*/
|
|
224
275
|
loadNamespace(ns: string): Promise<void>;
|
|
225
276
|
private parseModelToRecord;
|
|
@@ -234,16 +285,16 @@ declare class LangService {
|
|
|
234
285
|
}
|
|
235
286
|
|
|
236
287
|
/**
|
|
237
|
-
*
|
|
288
|
+
* Custom Angular pipe that transforms a language key and additional parameters into a localized string.
|
|
238
289
|
*
|
|
239
|
-
*
|
|
240
|
-
*
|
|
290
|
+
* The pipe is declared as standalone and impure — meaning it can be used without importing a module
|
|
291
|
+
* and will be recalculated when the state changes (for example, when the language is switched).
|
|
241
292
|
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
293
|
+
* In its operation, the pipe observes and caches language keys to improve performance,
|
|
294
|
+
* using LangService to retrieve translated strings based on the current application language.
|
|
244
295
|
*
|
|
245
|
-
*
|
|
246
|
-
*
|
|
296
|
+
* The transformation involves accepting a key string and optional parameters,
|
|
297
|
+
* forming a cache key, and returning the localized value corresponding to that request.
|
|
247
298
|
*
|
|
248
299
|
* @implements {PipeTransform}
|
|
249
300
|
*/
|
|
@@ -255,24 +306,90 @@ declare class LangPipe implements PipeTransform {
|
|
|
255
306
|
static ɵpipe: _angular_core.ɵɵPipeDeclaration<LangPipe, "lang", true>;
|
|
256
307
|
}
|
|
257
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Configuration options for theme management.
|
|
311
|
+
* Defines the default theme and prefix for dark theme variants.
|
|
312
|
+
*/
|
|
258
313
|
interface ThemeConfig {
|
|
314
|
+
/**
|
|
315
|
+
* The default theme to be applied when no other theme is specified.
|
|
316
|
+
* @optional
|
|
317
|
+
*/
|
|
259
318
|
defaultTheme?: Themes;
|
|
319
|
+
/**
|
|
320
|
+
* Prefix string used to identify and apply dark theme variants.
|
|
321
|
+
* @optional
|
|
322
|
+
*/
|
|
260
323
|
darkThemePrefix?: string;
|
|
261
324
|
}
|
|
262
325
|
|
|
326
|
+
/**
|
|
327
|
+
* Type-safe mapping of available theme names.
|
|
328
|
+
*
|
|
329
|
+
* Provides a constant record that maps theme identifiers to their corresponding string values.
|
|
330
|
+
* This ensures compile-time safety when referencing theme names throughout the application.
|
|
331
|
+
*
|
|
332
|
+
* Available themes:
|
|
333
|
+
* - `light` - Light theme variant
|
|
334
|
+
* - `dark` - Dark theme variant
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```typescript
|
|
338
|
+
* const currentTheme = themes.light; // 'light'
|
|
339
|
+
* const isDarkTheme = theme === themes.dark;
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
263
342
|
declare const themes: Record<Themes, Themes>;
|
|
343
|
+
/**
|
|
344
|
+
* CSS class prefix used for dark theme styling.
|
|
345
|
+
*
|
|
346
|
+
* This constant defines the prefix applied to HTML elements when the dark theme is active.
|
|
347
|
+
* It is typically added to the root element or specific components to enable dark theme styles.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* ```typescript
|
|
351
|
+
* document.body.classList.add(darkThemePrefix); // Applies 're-dark' class
|
|
352
|
+
* ```
|
|
353
|
+
*/
|
|
264
354
|
declare const darkThemePrefix = "re-dark";
|
|
265
355
|
|
|
356
|
+
/**
|
|
357
|
+
* Default theme configuration object.
|
|
358
|
+
*
|
|
359
|
+
* Defines the initial theme settings for the application.
|
|
360
|
+
* By default, sets the light theme as the active theme.
|
|
361
|
+
*
|
|
362
|
+
* This configuration can be overridden when providing `THEME_CONFIG` token
|
|
363
|
+
* at the module or application level.
|
|
364
|
+
* ```
|
|
365
|
+
*/
|
|
266
366
|
declare const defaultThemeConfig: {
|
|
267
367
|
defaultTheme: _reforgium_internal.Themes;
|
|
268
368
|
};
|
|
369
|
+
/**
|
|
370
|
+
* Injection token for theme configuration.
|
|
371
|
+
*
|
|
372
|
+
* Used to provide custom theme settings via Angular's dependency injection system.
|
|
373
|
+
* The token expects a value of type `ThemeConfig`.
|
|
374
|
+
*
|
|
375
|
+
* Example usage:
|
|
376
|
+
* ```typescript
|
|
377
|
+
* // In providers array:
|
|
378
|
+
* { provide: THEME_CONFIG, useValue: { defaultTheme: themes.dark } }
|
|
379
|
+
*
|
|
380
|
+
* // In service or component:
|
|
381
|
+
* private themeConfig = inject(THEME_CONFIG);
|
|
382
|
+
* ```
|
|
383
|
+
*
|
|
384
|
+
* If not provided, `defaultThemeConfig` will be used as fallback.
|
|
385
|
+
*/
|
|
269
386
|
declare const THEME_CONFIG: InjectionToken<ThemeConfig>;
|
|
270
387
|
|
|
271
388
|
/**
|
|
272
389
|
* Service for managing application theme.
|
|
273
390
|
*
|
|
274
391
|
* Allows getting the current theme and switching between light and dark.
|
|
275
|
-
* Automatically saves selected theme to `localStorage` and applies CSS class to `<html>` element.
|
|
392
|
+
* Automatically saves the selected theme to `localStorage` and applies CSS class to `<html>` element.
|
|
276
393
|
*
|
|
277
394
|
* Example:
|
|
278
395
|
* ```ts
|
|
@@ -304,8 +421,8 @@ declare class ThemeService {
|
|
|
304
421
|
/**
|
|
305
422
|
* Switches theme.
|
|
306
423
|
*
|
|
307
|
-
* If parameter is not provided — performs toggle between `light` and `dark`.
|
|
308
|
-
* Also automatically updates `<html>` class and saves selection to `localStorage`.
|
|
424
|
+
* If a parameter is not provided — performs toggle between `light` and `dark`.
|
|
425
|
+
* Also, automatically updates `<html>` class and saves selection to `localStorage`.
|
|
309
426
|
*
|
|
310
427
|
* @param theme — explicit theme value (`'light'` or `'dark'`).
|
|
311
428
|
*/
|
|
@@ -314,14 +431,71 @@ declare class ThemeService {
|
|
|
314
431
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ThemeService>;
|
|
315
432
|
}
|
|
316
433
|
|
|
434
|
+
/**
|
|
435
|
+
* Configuration object for initializing the Presentia application providers.
|
|
436
|
+
*
|
|
437
|
+
* @property {LocaleConfig} locale - Locale configuration (required). Defines language and localization settings.
|
|
438
|
+
* @property {ThemeConfig} [theme] - Theme configuration (optional). Defines the application theme. Defaults to `defaultThemeConfig` if not provided.
|
|
439
|
+
* @property {DeviceBreakpoints} [breakpoints] - Device breakpoints configuration (optional). Defines responsive breakpoints. Defaults to `defaultBreakpoints` if not provided.
|
|
440
|
+
*/
|
|
317
441
|
interface AppConfig {
|
|
318
442
|
locale: LocaleConfig;
|
|
319
443
|
theme?: ThemeConfig;
|
|
320
444
|
breakpoints?: DeviceBreakpoints;
|
|
321
445
|
}
|
|
446
|
+
/**
|
|
447
|
+
* Provides environment-level providers for Presentia application initialization.
|
|
448
|
+
*
|
|
449
|
+
* This function configures essential application services:
|
|
450
|
+
* - Language and localization settings
|
|
451
|
+
* - Theme configuration
|
|
452
|
+
* - Adaptive/responsive breakpoints
|
|
453
|
+
* - Current device detection
|
|
454
|
+
*
|
|
455
|
+
* @param {AppConfig} config - Configuration object containing locale, theme, and breakpoints settings.
|
|
456
|
+
* @returns {EnvironmentProviders} A collection of Angular providers for the application environment.
|
|
457
|
+
*
|
|
458
|
+
* @example
|
|
459
|
+
* ```typescript
|
|
460
|
+
* export const appConfig: ApplicationConfig = {
|
|
461
|
+
* providers: [
|
|
462
|
+
* provideReInit({
|
|
463
|
+
* locale: { defaultLang: 'en', supportedLangs: ['en', 'ru'] },
|
|
464
|
+
* theme: { defaultTheme: 'dark' },
|
|
465
|
+
* breakpoints: { mobile: 768, tablet: 1024 }
|
|
466
|
+
* })
|
|
467
|
+
* ]
|
|
468
|
+
* };
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
322
471
|
declare function provideReInit(config: AppConfig): EnvironmentProviders;
|
|
323
472
|
|
|
473
|
+
/**
|
|
474
|
+
* Open Graph meta tags type definition.
|
|
475
|
+
* Used for social media sharing preview configuration.
|
|
476
|
+
* All properties are optional strings representing standard OG protocol tags.
|
|
477
|
+
*
|
|
478
|
+
* @property title - The title of the object as it should appear in the graph
|
|
479
|
+
* @property description - A one to two sentence description of the object
|
|
480
|
+
* @property type - The type of the object (e.g., 'website', 'article')
|
|
481
|
+
* @property url - The canonical URL of the object
|
|
482
|
+
* @property image - An image URL which should represent the object
|
|
483
|
+
* @property site_name - The name of the overall site
|
|
484
|
+
* @property locale - The locale these tags are marked up in (e.g., 'en_US')
|
|
485
|
+
*/
|
|
324
486
|
type OgType = Partial<Record<'title' | 'description' | 'type' | 'url' | 'image' | 'site_name' | 'locale', string>>;
|
|
487
|
+
/**
|
|
488
|
+
* Twitter Card meta tags type definition.
|
|
489
|
+
* Used for controlling how content appears when shared on Twitter.
|
|
490
|
+
* All properties are optional strings representing Twitter Card metadata.
|
|
491
|
+
*
|
|
492
|
+
* @property card - The card type (e.g., 'summary', 'summary_large_image', 'app', 'player')
|
|
493
|
+
* @property title - Title of content (max 70 characters)
|
|
494
|
+
* @property description - Description of content (max 200 characters)
|
|
495
|
+
* @property image - URL of image to use in the card
|
|
496
|
+
* @property site - Twitter @username of website
|
|
497
|
+
* @property creator - Twitter @username of content creator
|
|
498
|
+
*/
|
|
325
499
|
type TwitterCardType = Partial<Record<'card' | 'title' | 'description' | 'image' | 'site' | 'creator', string>>;
|
|
326
500
|
|
|
327
501
|
/**
|
|
@@ -387,12 +561,44 @@ declare class SeoService {
|
|
|
387
561
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<SeoService>;
|
|
388
562
|
}
|
|
389
563
|
|
|
564
|
+
/**
|
|
565
|
+
* Service that listens to Angular route changes and automatically updates SEO metadata
|
|
566
|
+
* (title, description, Open Graph, Twitter cards, JSON-LD, canonical URL, robots meta tag)
|
|
567
|
+
* based on route data configuration.
|
|
568
|
+
*
|
|
569
|
+
* @example
|
|
570
|
+
* ```typescript
|
|
571
|
+
* const routes: Routes = [{
|
|
572
|
+
* path: 'about',
|
|
573
|
+
* component: AboutComponent,
|
|
574
|
+
* data: {
|
|
575
|
+
* title: 'About Us',
|
|
576
|
+
* description: 'Learn more about our company',
|
|
577
|
+
* robots: 'index,follow'
|
|
578
|
+
* }
|
|
579
|
+
* }];
|
|
580
|
+
* ```
|
|
581
|
+
*/
|
|
390
582
|
declare class SeoRouteListener {
|
|
391
583
|
private router;
|
|
392
584
|
private seo;
|
|
393
585
|
private ar;
|
|
394
586
|
private destroyRef;
|
|
587
|
+
/**
|
|
588
|
+
* Initializes the route listener to monitor navigation events and update SEO metadata.
|
|
589
|
+
* Subscribes to router NavigationEnd events and automatically unsubscribes on component destruction.
|
|
590
|
+
*
|
|
591
|
+
* @param baseUrl - The base URL of the application used for constructing canonical URLs.
|
|
592
|
+
* Trailing slashes will be removed automatically.
|
|
593
|
+
*/
|
|
395
594
|
init(baseUrl: string): void;
|
|
595
|
+
/**
|
|
596
|
+
* Recursively finds the deepest (most nested) activated route in the route tree.
|
|
597
|
+
* This is used to extract route data from the currently active leaf route.
|
|
598
|
+
*
|
|
599
|
+
* @param r - The root activated route to start traversing from.
|
|
600
|
+
* @returns The deepest child route in the hierarchy.
|
|
601
|
+
*/
|
|
396
602
|
private deepest;
|
|
397
603
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SeoRouteListener, never>;
|
|
398
604
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<SeoRouteListener>;
|
|
@@ -440,6 +646,6 @@ declare class RouteWatcher {
|
|
|
440
646
|
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RouteWatcher>;
|
|
441
647
|
}
|
|
442
648
|
|
|
443
|
-
export { AdaptiveService, DEVICE_BREAKPOINTS, IfDeviceDirective, LANG_CONFIG, LangPipe, LangService, RouteWatcher, SeoRouteListener, SeoService, THEME_CONFIG, ThemeService, darkThemePrefix, defaultBreakpoints, defaultThemeConfig, provideReInit, themes };
|
|
649
|
+
export { AdaptiveService, DEVICE_BREAKPOINTS, IfDeviceDirective, LANG_CONFIG, LangPipe, LangService, RouteWatcher, SeoRouteListener, SeoService, THEME_CONFIG, ThemeService, darkThemePrefix, defaultBreakpoints, defaultThemeConfig, innerLangVal, provideReInit, themes };
|
|
444
650
|
export type { AppConfig, DeviceBreakpoints, LangDto, LangModel, LangParams, LocaleConfig, OgType, ThemeConfig, TwitterCardType };
|
|
445
651
|
//# sourceMappingURL=reforgium-presentia.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reforgium-presentia.d.ts","sources":["../../../../libs/presentia/src/adaptive/adaptive.models.ts","../../../../libs/presentia/src/adaptive/adaptive.provider.ts","../../../../libs/presentia/src/adaptive/adaptive.service.ts","../../../../libs/presentia/src/adaptive/device-type.directive.ts","../../../../libs/presentia/src/lang/lang.models.ts","../../../../libs/presentia/src/lang/locale.provider.ts","../../../../libs/presentia/src/lang/lang.service.ts","../../../../libs/presentia/src/lang/lang.pipe.ts","../../../../libs/presentia/src/theme/theme.models.ts","../../../../libs/presentia/src/theme/themes.constant.ts","../../../../libs/presentia/src/theme/theme.provider.ts","../../../../libs/presentia/src/theme/theme.service.ts","../../../../libs/presentia/src/providers/init.provider.ts","../../../../libs/presentia/src/seo/seo.models.ts","../../../../libs/presentia/src/seo/seo.service.ts","../../../../libs/presentia/src/seo/seo-route.listener.ts","../../../../libs/presentia/src/routes/route-watcher.service.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"names":[],"mappings":";;;;;AAEA;AACM;;ACCN;;;;;;AAMA;;
|
|
1
|
+
{"version":3,"file":"reforgium-presentia.d.ts","sources":["../../../../libs/presentia/src/adaptive/adaptive.models.ts","../../../../libs/presentia/src/adaptive/adaptive.provider.ts","../../../../libs/presentia/src/adaptive/adaptive.service.ts","../../../../libs/presentia/src/adaptive/device-type.directive.ts","../../../../libs/presentia/src/lang/lang.models.ts","../../../../libs/presentia/src/lang/locale.provider.ts","../../../../libs/presentia/src/lang/lang.service.ts","../../../../libs/presentia/src/lang/lang.pipe.ts","../../../../libs/presentia/src/theme/theme.models.ts","../../../../libs/presentia/src/theme/themes.constant.ts","../../../../libs/presentia/src/theme/theme.provider.ts","../../../../libs/presentia/src/theme/theme.service.ts","../../../../libs/presentia/src/providers/init.provider.ts","../../../../libs/presentia/src/seo/seo.models.ts","../../../../libs/presentia/src/seo/seo.service.ts","../../../../libs/presentia/src/seo/seo-route.listener.ts","../../../../libs/presentia/src/routes/route-watcher.service.ts"],"sourcesContent":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null],"names":[],"mappings":";;;;;AAEA;AACM;;ACCN;;;;;;;;;;AAUG;AACH;;;;;;AAMA;;;;;;;;;;;;;;;;;;;;;AAqBG;AACH;;AClCA;;;;;;;;;;;;;;;;;AAiBG;AACH;;AAWE;;;;;;AAMG;AACH;AAEA;;;AAGG;AACH;AAEA;;;AAGG;AACH;AAEA;;;AAGG;AACH;AAEA;;;AAGG;AACH;;;;;;;AAyBD;;ACvFD;;;;;;;;;;;;;;;;;;;AAmBG;AACH;AAKE;AACA;AAEA;AACA;AACA;;;AAKA;;AAcA;;;AAYD;;AClED;;;;;;;;AAQG;;;;;AAKF;AAED;;;;;;AAMG;;AAED;AACD;AAED;;;;;;;AAOG;AACG;AAEN;;;;;;;;;;;;;AAaG;;;;;;AAMD;AACD;AAED;;ACxDA;;;;;;;;;;;;;;;;;AAiBG;AACH;;ACdA;;;;;AAKG;AACH;;AAEE;AACA;AAQA;;;;;;;AAOG;;AAMH;;;AAGG;AACH;AAEA;;;;;;AAMG;AACH;AAeA;;;;;;;AAOG;;AAWH;;;;;;;;AAQG;AACH;AAUA;;;;;;AAMG;;AAmCH;AAUA;AAUA;AAIA;AASA;AAIA;AAMA;;;AAGD;;ACzLD;;;;;;;;;;;;;AAaG;AACH;AAEE;AACA;;;;AAWD;;AC/BD;;;AAGG;;AAED;;;AAGG;;AAEH;;;AAGG;;AAEJ;;ACfD;;;;;;;;;;;;;;;AAeG;AACH;AAKA;;;;;;;;;;AAUG;AACH;;AC5BA;;;;;;;;;AASG;AACH;;;AAIA;;;;;;;;;;;;;;;;AAgBG;AACH;;AC5BA;;;;;;;;;;;;AAYG;AACH;;AAIE;AACA;AAIA;;;;;;;;AAQG;AACH;AAEA;;;AAGG;AACH;;AAWA;;;;;;;AAOG;AACH;;;AAQD;;AChED;;;;;;AAMG;;;;;AAKF;AAED;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACH;;AC/CA;;;;;;;;;;;;AAYG;AACG;AAIN;;;;;;;;;;;AAWG;AACG;;ACxBN;;;;;;;;;;;;;AAaG;AACH;;;AAKE;;;AAGG;;AAKH;;;AAGG;;AAKH;;;AAGG;AACH;AAIA;;;AAGG;;AAKH;;;AAGG;;AAKH;;;AAGG;;AAOH;;;AAGG;;AAOH;;;AAGG;;AAeH;AAQA;;;AAYD;;ACpHD;;;;;;;;;;;;;;;;;AAiBG;AACH;;;;;AAOE;;;;;;AAMG;;AAiCH;;;;;;AAMG;AACH;;;AASD;;AC/ED;;;;;;;;;;;AAWG;AACH;;AAEE;AACA;;;;;;;;;;;;AAwBA;;;;;;AAMI;;;AA2BJ;AAIA;;;AAUD;;;"}
|