@reforgium/presentia 1.0.0
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.
|
@@ -0,0 +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":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"name": "@reforgium/presentia",
|
|
4
|
+
"description": "reforgium State modules",
|
|
5
|
+
"author": "rtommievich",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git"
|
|
10
|
+
},
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"reforgium",
|
|
16
|
+
"state",
|
|
17
|
+
"store",
|
|
18
|
+
"signal",
|
|
19
|
+
"angular"
|
|
20
|
+
],
|
|
21
|
+
"types": "../../dist/@reforgium/presentia/index.d.ts",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"tslib": "^2.8.1"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@angular/common": ">=18.0.0",
|
|
27
|
+
"@angular/core": ">=18.0.0",
|
|
28
|
+
"rxjs": ">=7.0.0"
|
|
29
|
+
},
|
|
30
|
+
"module": "fesm2022/reforgium-presentia.mjs",
|
|
31
|
+
"typings": "types/reforgium-presentia.d.ts",
|
|
32
|
+
"exports": {
|
|
33
|
+
"./package.json": {
|
|
34
|
+
"default": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./types/reforgium-presentia.d.ts",
|
|
38
|
+
"default": "./fesm2022/reforgium-presentia.mjs"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"sideEffects": false
|
|
42
|
+
}
|
|
@@ -0,0 +1,445 @@
|
|
|
1
|
+
import * as _angular_core from '@angular/core';
|
|
2
|
+
import { InjectionToken, Signal, PipeTransform, EnvironmentProviders } from '@angular/core';
|
|
3
|
+
import * as _reforgium_internal from '@reforgium/internal';
|
|
4
|
+
import { Devices, Langs, Themes } from '@reforgium/internal';
|
|
5
|
+
|
|
6
|
+
/** Точки перехода для различных типов устройств */
|
|
7
|
+
type DeviceBreakpoints = Record<Devices, string>;
|
|
8
|
+
|
|
9
|
+
declare const defaultBreakpoints: {
|
|
10
|
+
mobile: string;
|
|
11
|
+
tablet: string;
|
|
12
|
+
'desktop-s': string;
|
|
13
|
+
desktop: string;
|
|
14
|
+
};
|
|
15
|
+
declare const DEVICE_BREAKPOINTS: InjectionToken<DeviceBreakpoints>;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Сервис `AdaptiveService` отвечает за определение типа устройства, размеров окна и ориентации экрана.
|
|
19
|
+
*
|
|
20
|
+
* Используется для построения адаптивных интерфейсов, изменения поведения компонентов и стилей
|
|
21
|
+
* в зависимости от текущего устройства или размера экрана.
|
|
22
|
+
*
|
|
23
|
+
* Основные возможности:
|
|
24
|
+
* - Реактивное отслеживание текущего устройства (`desktop`, `tablet`, `mobile`).
|
|
25
|
+
* - Поддержка вычисляемых признаков (`isDesktop`, `isPortrait`).
|
|
26
|
+
* - Автоматическое обновление при изменении размера окна и пересечении брейкпоинтов.
|
|
27
|
+
*
|
|
28
|
+
* Реализация основана на:
|
|
29
|
+
* - `BreakpointObserver` из Angular CDK — для наблюдения за медиа-запросами.
|
|
30
|
+
* - `signal` и `computed` — для реактивного состояния без зон.
|
|
31
|
+
* - `fromEvent(window, 'resize')` — для обновления размеров окна с дебаунсом.
|
|
32
|
+
*
|
|
33
|
+
* Сервис зарегистрирован как `providedIn: 'root'` и доступен во всём приложении.
|
|
34
|
+
*/
|
|
35
|
+
declare class AdaptiveService {
|
|
36
|
+
#private;
|
|
37
|
+
/**
|
|
38
|
+
* Текущий тип устройства (reactive signal).
|
|
39
|
+
* Возможные значения: `'desktop' | 'tablet' | 'mobile'`.
|
|
40
|
+
*
|
|
41
|
+
* Обновляется автоматически при изменении ширины экрана
|
|
42
|
+
* или при пересечении заданных брейкпоинтов (`DEVICE_BREAKPOINTS`).
|
|
43
|
+
*/
|
|
44
|
+
device: _angular_core.Signal<Devices>;
|
|
45
|
+
/**
|
|
46
|
+
* Текущая ширина окна браузера в пикселях.
|
|
47
|
+
* Обновляется реактивно при событии `resize`.
|
|
48
|
+
*/
|
|
49
|
+
width: _angular_core.Signal<number>;
|
|
50
|
+
/**
|
|
51
|
+
* Текущая высота окна браузера в пикселях.
|
|
52
|
+
* Обновляется реактивно при событии `resize`.
|
|
53
|
+
*/
|
|
54
|
+
height: _angular_core.Signal<number>;
|
|
55
|
+
/**
|
|
56
|
+
* Вычисляемый сигнал, показывающий, является ли текущее устройство десктопом.
|
|
57
|
+
* Используется для условного рендера или настройки макета.
|
|
58
|
+
*/
|
|
59
|
+
isDesktop: _angular_core.Signal<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* Вычисляемый сигнал, определяющий, находится ли экран в портретной ориентации.
|
|
62
|
+
* Возвращает `true`, если высота окна больше ширины.
|
|
63
|
+
*/
|
|
64
|
+
isPortrait: _angular_core.Signal<boolean>;
|
|
65
|
+
private deviceBreakpoints;
|
|
66
|
+
private devicePriority;
|
|
67
|
+
private breakpointObserver;
|
|
68
|
+
constructor();
|
|
69
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<AdaptiveService, never>;
|
|
70
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<AdaptiveService>;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Структурная директива `*ssIfDevice`.
|
|
75
|
+
*
|
|
76
|
+
* Показывает или скрывает элемент в зависимости от текущего устройства,
|
|
77
|
+
* определяемого через `AdaptiveService`.
|
|
78
|
+
*
|
|
79
|
+
* Пример:
|
|
80
|
+
* ```html
|
|
81
|
+
* <div *ssIfDevice="'desktop'">Только для десктопа</div>
|
|
82
|
+
* <div *ssIfDevice="['mobile', 'tablet']">Для мобильных и планшетов</div>
|
|
83
|
+
* <div *ssIfDevice="'mobile'; inverse: true">Скрыть на мобильных</div>
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* Параметры:
|
|
87
|
+
* - `ssIfDevice` — одно или несколько значений `Devices` (`'desktop' | 'tablet' | 'mobile'`)
|
|
88
|
+
* - `inverse` — инвертирует условие показа
|
|
89
|
+
*
|
|
90
|
+
* Работает реактивно: при изменении типа устройства в `AdaptiveService`
|
|
91
|
+
* шаблон автоматически добавляется или удаляется из DOM.
|
|
92
|
+
*/
|
|
93
|
+
declare class IfDeviceDirective {
|
|
94
|
+
device: _angular_core.InputSignal<Devices | Devices[] | undefined>;
|
|
95
|
+
inverse: _angular_core.InputSignal<boolean>;
|
|
96
|
+
private readonly tpl;
|
|
97
|
+
private readonly vcr;
|
|
98
|
+
private readonly adaptive;
|
|
99
|
+
private allowedDevices;
|
|
100
|
+
private hasView;
|
|
101
|
+
private readonly currentDevice;
|
|
102
|
+
constructor();
|
|
103
|
+
private updateView;
|
|
104
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<IfDeviceDirective, never>;
|
|
105
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<IfDeviceDirective, "[reIfDevice]", never, { "device": { "alias": "ssIfDevice"; "required": false; "isSignal": true; }; "inverse": { "alias": "inverse"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Language data model from localization server
|
|
110
|
+
*
|
|
111
|
+
* @description
|
|
112
|
+
* `Model` for translation data
|
|
113
|
+
* `namespace` - git project name
|
|
114
|
+
* `code` - masked query: ${page}.${recordKey}
|
|
115
|
+
* `value` - translation value
|
|
116
|
+
*/
|
|
117
|
+
interface LangDto {
|
|
118
|
+
namespace: string;
|
|
119
|
+
code: string;
|
|
120
|
+
localization: string;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Data model for translation
|
|
124
|
+
*
|
|
125
|
+
* @description
|
|
126
|
+
* `key` - masked query: ${page}.${recordKey}
|
|
127
|
+
* `value` - translation value or nested model
|
|
128
|
+
*/
|
|
129
|
+
interface LangModel {
|
|
130
|
+
[key: string]: string | LangModel;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Parameters for text formatting
|
|
134
|
+
*
|
|
135
|
+
* @description
|
|
136
|
+
* `key` - mask key
|
|
137
|
+
* `value` - mask value
|
|
138
|
+
* example: {{`key1`}} will be replaced with `value1`
|
|
139
|
+
*/
|
|
140
|
+
type LangParams = Record<string, string>;
|
|
141
|
+
/**
|
|
142
|
+
* Represents configuration settings for localization.
|
|
143
|
+
*
|
|
144
|
+
* This interface is used to define the locale configuration structure,
|
|
145
|
+
* which can include URL, resource origin information, default language,
|
|
146
|
+
* and related values for regional or localization settings.
|
|
147
|
+
*
|
|
148
|
+
* Properties:
|
|
149
|
+
* - `url` specifies the localization URL for loading resources.
|
|
150
|
+
* - `isFromAssets` indicates whether resources are loaded from application assets.
|
|
151
|
+
* - `defaultLang` defines optional default language for localization.
|
|
152
|
+
* - `defaultValue` - optional default value for locale resource.
|
|
153
|
+
* - `kgValue` specifies optional localization value with variants `kg` or `ky`.
|
|
154
|
+
*/
|
|
155
|
+
interface LocaleConfig {
|
|
156
|
+
url: string;
|
|
157
|
+
isFromAssets: boolean;
|
|
158
|
+
defaultLang?: Langs;
|
|
159
|
+
defaultValue?: string;
|
|
160
|
+
kgValue?: 'kg' | 'ky';
|
|
161
|
+
}
|
|
162
|
+
declare const innerLangVal: unique symbol;
|
|
163
|
+
|
|
164
|
+
declare const LANG_CONFIG: InjectionToken<LocaleConfig>;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* LangService provides functionality for managing and tracking language settings
|
|
168
|
+
* and translations in the application. It is designed to handle localization needs,
|
|
169
|
+
* loading language resources, caching translations, and dynamically applying translations
|
|
170
|
+
* throughout the application.
|
|
171
|
+
*/
|
|
172
|
+
declare class LangService {
|
|
173
|
+
#private;
|
|
174
|
+
private readonly config;
|
|
175
|
+
private readonly http;
|
|
176
|
+
/**
|
|
177
|
+
* Computed property determining the current language setting.
|
|
178
|
+
*
|
|
179
|
+
* - If private method `#lang` returns 'ru', this property will return 'ru'.
|
|
180
|
+
* - If `#lang` returns another value, the `config.kgValue` property is checked:
|
|
181
|
+
* - 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'.
|
|
183
|
+
*/
|
|
184
|
+
readonly currentLang: Signal<"ru" | "kg" | "ky">;
|
|
185
|
+
/**
|
|
186
|
+
* Extracts readonly value from private property `#lang` and assigns it to `innerLangVal`.
|
|
187
|
+
* Expected that property `#lang` has `asReadonly` method that returns immutable representation.
|
|
188
|
+
*/
|
|
189
|
+
readonly [innerLangVal]: Signal<Langs>;
|
|
190
|
+
/**
|
|
191
|
+
* Sets the current language for the application.
|
|
192
|
+
*
|
|
193
|
+
* @param {Langs | 'ky'} lang - The language to set.
|
|
194
|
+
* Accepts predefined type `Langs` or 'ky' to set Kyrgyz language.
|
|
195
|
+
* @return {void} Returns no value.
|
|
196
|
+
*/
|
|
197
|
+
setLang(lang: Langs | 'ky'): void;
|
|
198
|
+
/**
|
|
199
|
+
* Gets value based on provided query and optionally applies specified parameters.
|
|
200
|
+
*
|
|
201
|
+
* @param {string} query - Query string used to retrieve desired value.
|
|
202
|
+
* @param {LangParams} [params] - Optional parameters to apply to retrieved value.
|
|
203
|
+
* @return {string} Retrieved value after optional parameter application,
|
|
204
|
+
* or default value if query is not found.
|
|
205
|
+
*/
|
|
206
|
+
get(query: string, params?: LangParams): string;
|
|
207
|
+
/**
|
|
208
|
+
* Observes changes to specified translation key and dynamically computes its value.
|
|
209
|
+
*
|
|
210
|
+
* @param {string} query - Translation key to observe, typically in format "namespace.key".
|
|
211
|
+
* @param {LangParams} [params] - Optional parameters for interpolation or
|
|
212
|
+
* dynamic content replacement in translation value.
|
|
213
|
+
* @return {Signal<string>} Computed value that dynamically updates
|
|
214
|
+
* with translation matching provided query and parameters.
|
|
215
|
+
*/
|
|
216
|
+
observe(query: string, params?: LangParams): Signal<string>;
|
|
217
|
+
/**
|
|
218
|
+
* Loads specified namespace, ensuring its caching and availability for use.
|
|
219
|
+
*
|
|
220
|
+
* @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.
|
|
223
|
+
*/
|
|
224
|
+
loadNamespace(ns: string): Promise<void>;
|
|
225
|
+
private parseModelToRecord;
|
|
226
|
+
private parseAssetToRecord;
|
|
227
|
+
private applyParams;
|
|
228
|
+
private getChainedValue;
|
|
229
|
+
private getStoredLang;
|
|
230
|
+
private makeUrl;
|
|
231
|
+
private makeNamespaceKey;
|
|
232
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LangService, never>;
|
|
233
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<LangService>;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Кастомный Angular-пайп, который преобразует языковой ключ и дополнительные параметры в локализованную строку.
|
|
238
|
+
*
|
|
239
|
+
* Пайп объявлен как standalone и impure — то есть он может использоваться без подключения модуля
|
|
240
|
+
* и будет пересчитываться при изменении состояния (например, при смене языка).
|
|
241
|
+
*
|
|
242
|
+
* В своей работе пайп наблюдает и кэширует языковые ключи для повышения производительности,
|
|
243
|
+
* используя LangService для получения переведённых строк в зависимости от текущего языка приложения.
|
|
244
|
+
*
|
|
245
|
+
* Трансформация заключается в том, чтобы принять строку-ключ и необязательные параметры,
|
|
246
|
+
* сформировать ключ для кэша и вернуть локализованное значение, соответствующее этому запросу.
|
|
247
|
+
*
|
|
248
|
+
* @implements {PipeTransform}
|
|
249
|
+
*/
|
|
250
|
+
declare class LangPipe implements PipeTransform {
|
|
251
|
+
private readonly lang;
|
|
252
|
+
private readonly cache;
|
|
253
|
+
transform(query: string, params?: LangParams): string;
|
|
254
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<LangPipe, never>;
|
|
255
|
+
static ɵpipe: _angular_core.ɵɵPipeDeclaration<LangPipe, "lang", true>;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
interface ThemeConfig {
|
|
259
|
+
defaultTheme?: Themes;
|
|
260
|
+
darkThemePrefix?: string;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
declare const themes: Record<Themes, Themes>;
|
|
264
|
+
declare const darkThemePrefix = "re-dark";
|
|
265
|
+
|
|
266
|
+
declare const defaultThemeConfig: {
|
|
267
|
+
defaultTheme: _reforgium_internal.Themes;
|
|
268
|
+
};
|
|
269
|
+
declare const THEME_CONFIG: InjectionToken<ThemeConfig>;
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Service for managing application theme.
|
|
273
|
+
*
|
|
274
|
+
* 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.
|
|
276
|
+
*
|
|
277
|
+
* Example:
|
|
278
|
+
* ```ts
|
|
279
|
+
* const theme = inject(ThemeService);
|
|
280
|
+
* theme.switch('dark');
|
|
281
|
+
* console.log(theme.theme()); // 'dark'
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
declare class ThemeService {
|
|
285
|
+
#private;
|
|
286
|
+
private readonly config;
|
|
287
|
+
private readonly themeDefault;
|
|
288
|
+
/**
|
|
289
|
+
* Current active theme (`light` or `dark`).
|
|
290
|
+
*
|
|
291
|
+
* Value is reactive — can be used in template or `computed`.
|
|
292
|
+
* ```html
|
|
293
|
+
* <div [class.dark]="themeService.theme() === 'dark'"></div>
|
|
294
|
+
* <div [class]="themeService.theme()"></div>
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
theme: _angular_core.Signal<Themes>;
|
|
298
|
+
/**
|
|
299
|
+
* Convenient flag returning `true` if light theme is active.
|
|
300
|
+
* Suitable for conditional style application or resource selection.
|
|
301
|
+
*/
|
|
302
|
+
isLight: _angular_core.Signal<boolean>;
|
|
303
|
+
constructor();
|
|
304
|
+
/**
|
|
305
|
+
* Switches theme.
|
|
306
|
+
*
|
|
307
|
+
* If parameter is not provided — performs toggle between `light` and `dark`.
|
|
308
|
+
* Also automatically updates `<html>` class and saves selection to `localStorage`.
|
|
309
|
+
*
|
|
310
|
+
* @param theme — explicit theme value (`'light'` or `'dark'`).
|
|
311
|
+
*/
|
|
312
|
+
switch(theme?: Themes): void;
|
|
313
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<ThemeService, never>;
|
|
314
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<ThemeService>;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
interface AppConfig {
|
|
318
|
+
locale: LocaleConfig;
|
|
319
|
+
theme?: ThemeConfig;
|
|
320
|
+
breakpoints?: DeviceBreakpoints;
|
|
321
|
+
}
|
|
322
|
+
declare function provideReInit(config: AppConfig): EnvironmentProviders;
|
|
323
|
+
|
|
324
|
+
type OgType = Partial<Record<'title' | 'description' | 'type' | 'url' | 'image' | 'site_name' | 'locale', string>>;
|
|
325
|
+
type TwitterCardType = Partial<Record<'card' | 'title' | 'description' | 'image' | 'site' | 'creator', string>>;
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Service for managing page SEO metadata.
|
|
329
|
+
*
|
|
330
|
+
* Allows centrally setting title, description, keywords,
|
|
331
|
+
* Open Graph and Twitter Card tags, canonical link, and JSON-LD schema.
|
|
332
|
+
*
|
|
333
|
+
* Example:
|
|
334
|
+
* ```ts
|
|
335
|
+
* const seo = inject(SeoService);
|
|
336
|
+
* seo.setTitle('Home Page');
|
|
337
|
+
* seo.setDescription('Site Description');
|
|
338
|
+
* seo.setOg({ title: 'Home', type: 'website' });
|
|
339
|
+
* ```
|
|
340
|
+
*/
|
|
341
|
+
declare class SeoService {
|
|
342
|
+
private title;
|
|
343
|
+
private meta;
|
|
344
|
+
/**
|
|
345
|
+
* Sets page title (`<title>`).
|
|
346
|
+
* @param value title text
|
|
347
|
+
*/
|
|
348
|
+
setTitle(value: string): void;
|
|
349
|
+
/**
|
|
350
|
+
* Sets page description (`<meta name="description">`).
|
|
351
|
+
* @param desc brief content description
|
|
352
|
+
*/
|
|
353
|
+
setDescription(desc: string): void;
|
|
354
|
+
/**
|
|
355
|
+
* Sets page keywords (`<meta name="keywords">`).
|
|
356
|
+
* @param keywords array of keywords
|
|
357
|
+
*/
|
|
358
|
+
setKeywords(keywords: string[]): void;
|
|
359
|
+
/**
|
|
360
|
+
* Sets directives for search engines (`<meta name="robots">`).
|
|
361
|
+
* @param value value, e.g. `"index,follow"`
|
|
362
|
+
*/
|
|
363
|
+
setRobots(value: string): void;
|
|
364
|
+
/**
|
|
365
|
+
* Sets canonical link (`<link rel="canonical">`).
|
|
366
|
+
* @param url absolute URL of canonical page
|
|
367
|
+
*/
|
|
368
|
+
setCanonical(url: string): void;
|
|
369
|
+
/**
|
|
370
|
+
* Sets Open Graph meta tags.
|
|
371
|
+
* @param opts object with Open Graph fields (`title`, `description`, `image`, `url`, `type`, etc.)
|
|
372
|
+
*/
|
|
373
|
+
setOg(opts: OgType): void;
|
|
374
|
+
/**
|
|
375
|
+
* Sets Twitter Card meta tags.
|
|
376
|
+
* @param opts object with Twitter Card fields (`card`, `title`, `description`, `image`, etc.)
|
|
377
|
+
*/
|
|
378
|
+
setTwitter(opts: TwitterCardType): void;
|
|
379
|
+
/**
|
|
380
|
+
* Embeds JSON-LD schema (structured data) in `<head>`.
|
|
381
|
+
* @param schema schema object (will be serialized to JSON)
|
|
382
|
+
*/
|
|
383
|
+
setJsonLd(schema: object): void;
|
|
384
|
+
private upsert;
|
|
385
|
+
private upsertLink;
|
|
386
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SeoService, never>;
|
|
387
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<SeoService>;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
declare class SeoRouteListener {
|
|
391
|
+
private router;
|
|
392
|
+
private seo;
|
|
393
|
+
private ar;
|
|
394
|
+
private destroyRef;
|
|
395
|
+
init(baseUrl: string): void;
|
|
396
|
+
private deepest;
|
|
397
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SeoRouteListener, never>;
|
|
398
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<SeoRouteListener>;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Reactive snapshot of the current route (the deepest active route).
|
|
403
|
+
* Updates on every `NavigationEnd` event.
|
|
404
|
+
*
|
|
405
|
+
* Provides:
|
|
406
|
+
* - `params` / `query` — strings (as in Angular Router)
|
|
407
|
+
* - `data` — arbitrary data (from route configuration/resolvers)
|
|
408
|
+
* - `url` — string assembled from `UrlSegment[]`
|
|
409
|
+
* - `fragment` — hash (#section)
|
|
410
|
+
* - `selectData(key)` — type-safe selector for `data`
|
|
411
|
+
* - `state` — combined computed object (convenient for single subscriber)
|
|
412
|
+
*/
|
|
413
|
+
declare class RouteWatcher {
|
|
414
|
+
#private;
|
|
415
|
+
private readonly router;
|
|
416
|
+
private readonly destroyRef;
|
|
417
|
+
/** Signal for tracking and retrieving URL parameters */
|
|
418
|
+
readonly params: _angular_core.Signal<Record<string, string>>;
|
|
419
|
+
/** Signal for tracking and retrieving query parameters */
|
|
420
|
+
readonly query: _angular_core.Signal<Record<string, string>>;
|
|
421
|
+
/** Signal for tracking and retrieving route data */
|
|
422
|
+
readonly data: _angular_core.Signal<Record<string, unknown>>;
|
|
423
|
+
/** Signal for tracking and retrieving URL */
|
|
424
|
+
readonly url: _angular_core.Signal<string>;
|
|
425
|
+
/** Signal for tracking and retrieving URL fragment */
|
|
426
|
+
readonly fragment: _angular_core.Signal<string | null>;
|
|
427
|
+
/** Combined computed snapshot (to avoid multiple effects) */
|
|
428
|
+
readonly state: _angular_core.Signal<{
|
|
429
|
+
params: Record<string, string>;
|
|
430
|
+
query: Record<string, string>;
|
|
431
|
+
data: Record<string, unknown>;
|
|
432
|
+
url: string;
|
|
433
|
+
fragment: string | null;
|
|
434
|
+
}>;
|
|
435
|
+
constructor();
|
|
436
|
+
/** Convenient selector for a data key with type-safe casting */
|
|
437
|
+
selectData<T = unknown>(key: string): _angular_core.Signal<T | undefined>;
|
|
438
|
+
private deepestSnapshot;
|
|
439
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<RouteWatcher, never>;
|
|
440
|
+
static ɵprov: _angular_core.ɵɵInjectableDeclaration<RouteWatcher>;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export { AdaptiveService, DEVICE_BREAKPOINTS, IfDeviceDirective, LANG_CONFIG, LangPipe, LangService, RouteWatcher, SeoRouteListener, SeoService, THEME_CONFIG, ThemeService, darkThemePrefix, defaultBreakpoints, defaultThemeConfig, provideReInit, themes };
|
|
444
|
+
export type { AppConfig, DeviceBreakpoints, LangDto, LangModel, LangParams, LocaleConfig, OgType, ThemeConfig, TwitterCardType };
|
|
445
|
+
//# sourceMappingURL=reforgium-presentia.d.ts.map
|
|
@@ -0,0 +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;;ACDA;;;;;;;;;;;;;;;;;AAiBG;AACH;;AAWE;;;;;;AAMG;AACH;AAEA;;;AAGG;AACH;AAEA;;;AAGG;AACH;AAEA;;;AAGG;AACH;AAEA;;;AAGG;AACH;;;;;;;AAyBD;;ACvFD;;;;;;;;;;;;;;;;;;;AAmBG;AAEH;AAKE;AACA;AAEA;AACA;AACA;;;AAKA;;AAcA;;;AAYD;;ACnED;;;;;;;;AAQG;;;;;AAKF;AAED;;;;;;AAMG;;AAED;AACD;AAED;;;;;;;AAOG;AACG;AAEN;;;;;;;;;;;;;AAaG;;;;;;AAMD;AACD;AAED;;ACxDA;;ACKA;;;;;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;;AC1LD;;;;;;;;;;;;;AAaG;AACH;AAEE;AACA;;;;AAWD;;;;;AC5BA;;ACHD;AAKA;;ACDA;;;AAIA;;ACDA;;;;;;;;;;;;AAYG;AACH;;AAIE;AACA;AAIA;;;;;;;;AAQG;AACH;AAEA;;;AAGG;AACH;;AAWA;;;;;;;AAOG;AACH;;;AAQD;;;;;;AC3DA;AAED;;AChBM;AAIA;;ACCN;;;;;;;;;;;;;AAaG;AACH;;;AAKE;;;AAGG;;AAKH;;;AAGG;;AAKH;;;AAGG;AACH;AAIA;;;AAGG;;AAKH;;;AAGG;;AAKH;;;AAGG;;AAOH;;;AAGG;;AAOH;;;AAGG;;AAeH;AAQA;;;AAYD;;ACpHD;;;;;;AAuCE;;;AASD;;AC/CD;;;;;;;;;;;AAWG;AACH;;AAEE;AACA;;;;;;;;;;;;AAwBA;;;;;;AAMI;;;AA2BJ;AAIA;;;AAUD;;;"}
|