Files
js_theme_manager/js/felexdev_theme_manager.js
T
2026-06-19 01:01:23 +05:00

304 lines
27 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file felexdev-theme-manager.js
* @version 1.0.0 dev-in-progress (2026-06-09)
* @author felex67 (admin@felexdev.ru)
* @license Apache2.0
*
* @brief ThemeManager - модуль-переключатель тем
* @details Архитектура singleton-модуля на базе самоинициализирующегося статического класса
*/
class ThemeManager {
/**
* Состояние модуля:
* При инициализации данного объекта создаётся обработчик события изменения системной темы
* автоматически выставляющий поле `.isDark` в соответствующее значение.
*
* @property {DOMTokenList} clist: список классов ::root
* @property {HTMLElement} element: ::root, тег html
* @property {number} idx: индекс текущей темы
* @property {boolean} isDark: флаг тёмной системной темы
* @property {MediaQueryList} _schemeQuery: Медиа слушатель системной темы
* @property {boolean} _schemeListener: Обработчик изменений системной темы
*/
static #$ = (() => {
let q = window.matchMedia('(prefers-color-scheme: dark)');
let e = {
clist: document.documentElement.classList,
element: document.documentElement,
idx: 0,
isDark: q.matches,
_schemeQuery: q,
_schemeListener: null
};
q.addEventListener('change', e._schemeListener = (function(ev) { this.isDark = ev.matches; }).bind(e));
return e;
})();
/**
* Конфигурация/настройки модуля
* @property {string} buttonToggleId: Идентификатор кнопки-переключателя тем. 'button-toggle'
* @property {string} colorSchemePrefix: Префикс селектора CSS. 'color-scheme'
* @property {string} default.Image: Иконка темы по умолчанию
* @property {string} globalPrefix: Глобальный префикс. 'theme-'
* @property {number} menuAppearTimeout: таймаут до появления меню в милисекундах (2000),
* @property {number} menuDisappearTimeout: таймауйт исчезновения меню в милисекудах (300),
* @property {string} menuId: Идентификатор меню. 'theme-menu'
* @property {string} menuRowClass: Класс элементов-строк меню 'theme-menu-row',
* @property {string} menuImageClass: Класс иконки темы 'theme-menu-image',
* @property {string} menuDescriptionClass: Класс описателя темы 'theme-menu-desc',
* @property {string} storageKey: Ключ в хранилище 'theme-id',
*/
static #CONFIG = (function() { let c = {
/* Основные настройки модуля */
buttonToggleId: 'button-toggle', // суффикс кнопки переключения тем
colorSchemePrefix: 'color-scheme', // корень названия классов темы
globalPrefix: 'theme', // глобальный префикс
/* Настройки меню */
menuAppearTimeout: 2000, // таймаут появления меню
menuDisappearTimeout: 300, // таймаут исчезновения меню
menuId: 'menu', // базовый идентификатор меню
menuRowClass: 'row', // базовый класс строки меню
menuImageClass: 'image', // базовый класс картинки темы в меню
menuDescriptionClass: 'desc', // базовый класс описательного имени темы в меню
menuAreaLable: 'menu-select-theme', // описание элемента меню
menuRowAreaLable: 'row', // описание элемента строки меню
menuIconAreaLable: 'icon', // описание элемента иконки темы
menuDescAreaLable: 'description', // описание элемента описания темы
defaultImage:'<svg width="100%"height="100%"viewBox="0 0 135.46666 135.46667"version="1.1"xmlns="http://www.w3.org/2000/svg"xmlns:svg="http://www.w3.org/2000/svg"><path id="path1"style="opacity:100%;fill:currentColor;fill-opacity:1;stroke:#171717;stroke-width:0"d="M 67.777258,12.777515 A 55,55 0 0 0 12.777515,67.777258 55,55 0 0 0 67.777258,122.77752 55,55 0 0 0 122.77752,67.777258 55,55 0 0 0 67.777258,12.777515 Z m -0.128157,4.95577 V 117.73338 A 50,50 0 0 1 17.733285,67.733333 50,50 0 0 1 67.649101,17.733285 Z"/></svg>',
storageKey: 'id', // базовое имя ключа в хранилище
};
/* Собираем строки */
c.globalPrefix += '-';
/* С этого момента globalPrefix = '${c.globalPrefix}-' */
c.storageKey = c.globalPrefix + c.storageKey;
/* Логика инициализации */
/* инициализация классов меню */
c.menuId = c.globalPrefix + c.menuId;
c.menuRowClass = `${c.menuId}-${c.menuRowClass}`;
c.menuImageClass = `${c.menuId}-${c.menuImageClass}`;
c.menuDescriptionClass = `${c.menuId}-${c.menuDescriptionClass}`;
/* инициализация имени кнопки переключения тем */
c.buttonToggleId = c.globalPrefix + c.buttonToggleId;
/* инициализация префикса классов в селекторе CSS */
c.colorSchemePrefix = c.globalPrefix + c.colorSchemePrefix + '-';
/* Возвращаем полностью инициализированный объект с динамически скомпонованными строками */
return c;
})();
static #THEMES = [];
static #save = ((idx) => {
let save = (idx) => {
console.error(this.#CONFIG.globalPrefix + '#save(): It is unavailable to save a theme, the storages are unreachable.');
}
try {
/* Пробуем localStorage */
this.#$.current = parseInt(localStorage.getItem(this.#CONFIG.storageKey)) || 0;
save = (idx) => { localStorage.setItem(this.#CONFIG.storageKey, idx); };
}
catch(e) {
console.log(this.#CONFIG.globalPrefix + '#save-IIFE(): localStorage is unreachable, trying to use cookie.')
try {
let cookie = document.cookie.match(`${this.#CONFIG.storageKey}\\s*=\\s*(\\d+)`);
this.#$.current = cookie ? parseInt(cookie[1]) || 0 : 0;
save = (idx) => { document.cookie = `${this.#CONFIG.storageKey}=${idx}; Max-Age=${31536000}; Path=/`; };
}
catch (e) {
console.log(`${this.#CONFIG.globalPrefix}#save-IIFE: All storages are unreachable('localStorage' & 'document.cookie')`);
}
}
/* Мы не дублируем, а просто навешиваем класс на `::root` ели тема не 'auto'
* Это самый быстрый способ применить тему.
* Не знаю как Вам, а мне - всё понятно =D */
if (this.#$.current < this.#THEMES.length)
this.#$.current > 0
? this.#$.element.classList.add(this.#THEMES[this.#$.current].class)
: this.#$.current
&& (console.error(`${this.#CONFIG.globalPrefix}#save-IIFE: Negative theme index!!!: '${this.#$.current}'. Fallback to 'auto'`)
|| (this.#$.current = 0));
else
console.log(`${this.#CONFIG.globalPrefix}#save-IIFE: Theme index out of range: '${this.#$.current}'. Fallback to 'auto'`);
return save;
})();
/**
* Добавляет/заменяет/удаляет класс старой темы на новый
* @param {number} idx: индекс новой темы
* @param {JSObject} e: JS-объект со следующими обязательными полями: { idx: number, clist: DOMTokenList, }
*/
static #set(idx, e = this.#$, t = this.#THEMES) {
if (idx == e.idx)
return;
if (idx && e.idx)
e.clist.replace(t[e.idx].class, t[idx].class);
else if (idx)
e.clist.add(t[idx].class);
else
e.clist.remove(t[e.idx].class);
this.#save(e.idx = idx);
}
/**
*
*/
/**
* Меню выбора тем
* @property {class} _tm: ссылка на класс
* @property {JSObject} _stt:
* @property {DOMTokenList} clist: список классов управляемого элемента classList
* @property {number} idx: индекс текущей темы меню
* @property {number} tmh: таймер сокрытия меню
* @property {number} tms: таймер показа меню
* @property {JSObject} _t: объект темы
* @property {DOMTokenList} clist: список классов управляемого элемента classList
* @property {number} idx: индекс текущей темы меню
* @property {number} tmh: таймер сокрытия меню
* @property {number} tms: таймер показа меню
*
*/
static #MENU = (() => {
let menu = {
/* private: */
/* Свойства */
_tm: this, // ссылка на основной класс
/**
* {JSObject} `static #MENU._stt`
* Внутреннее состояние меню
* @property {DOMTokenList} clist: список классов управляемого элемента classList
* @property {number} idx: индекс текущей темы меню
* @property {number} tmh: таймер сокрытия меню
* @property {number} tms: таймер показа меню
*/
_stt: {
clist: null, // classList of element
idx: 0, // текущая тема меню
tmh: null, // таймер сокрытия меню
tms: null, // таймер показа меню
},
_t: this.#THEMES, // ссылка на массив тем
/* Методы */
_tv: null, // переключить видимость
/* public: */
/* Методы */
appendChild: null, // `div.appendChild`
div: document.createElement('div'), // ссылка на контролируемый DOM-элемент
hide: null, // спрятать меню
show: null, // показать меню
style: null, // `div.style`
};
/* Инициализируем div-элемент */
menu.div.id = this.#CONFIG.menuId; // устанавливаем id
menu._stt.clist = menu.div.classList; // привязываем список классов
/* Пробрасываем часто нужные методы и поля div-элемента */
menu.appendChild = menu.div.appendChild.bind(menu._state.element);
menu.style = menu._state.element.style;
/* Внутренняя логика меню */
/* Спрятать меню */
menu.hide = (function() {
this.style.width = this.style.height = '0px';
}).bind(menu);
/* Показать меню */
menu.show = (function() {
let s = this._themes[this._manager.#current].sizes;
this.style.visibility = 'visible';
this.style.width = s.w;
this.style.height = s.h;
}).bind(menu);
/* Применяем тему ко всему документу */
menu.apply = (function(idx) {
this._manager.#set(idx, this._state);
this.hide();
/* Это необходимо для того чтобы меню подхватило стиль всего документа */
this._remove(this.themes[this._current].name);
this._current = 0;
}).bind(menu);
return menu;
})();
/**
* @typedef {Object} ThemeMenuSizes - Фактические размеры меню при использовании темы
* @property {string} w: ширина меню в пикселях
* @property {string} h: высота меню в пикселях
*/
/**
* @typedef {Object} Theme
* @property {string} name: Внутреннее название темы `'auto'`
* @property {string} class: Селектор CSS
* @property {number} idx: Индекс темы в массиве `#THEMES`
* @property {HTMLDivElement} row: Строка меню
* @property {HTMLDivElement} icon: Иконка темы
* @property {HTMLDivElement} desc: Описательное имя темы
* @property {ThemeMenuSizes} sizes: Фактические размеры меню при применении темы в пикселях
*/
/**
* Создаёт и инициализирует новый объект темы
* @param {string} name - внутреннее название темы.
* @param {string?} desc - описательное название темы. `{ desc: desc || name, }`
* @param {string?} svg - векторное изображение темы. `{ svg: svg || this.#CONFIG.defaultImg, }`
*
* @returns {Theme} - инициализированный объект темы
*
* @throws {Error} при `!name.length || typeof(name) != 'string'`
* @throws {Error} если тема с таким 'name' уже существует
*/
static #newTheme = (name, desc = null, svg = null) => {
if ((typeof name) != 'string' || !name) {
throw new Error(`${this.#CONFIG.globalPrefix}#newTheme: empty or invalid theme name: type: ${typeof name}, val: '${name}'`)
}
else if (-1 != this.#THEMES.indexOf(name)) {
throw new Error(`${this.#CONFIG.globalPrefix}#newTheme: theme '${name}' allready exists`);
}
let theme = {
menu: this.#MENU,
name: name, // Имя темы
class: this.#CONFIG.colorSchemePrefix + name, // Класс в CSS-селекторе
idx: idx, // Индекс темы в массиве тем
row: document.createElement('div'), // Элемент строки
icon: document.createElement('div'), // Элемент иконки
desc: document.createElement('div'), // Элемент описания
sizes: { w: '0px', h: '0px' }, // Размеры меню при установке темы(для анимации)
};
/* настраиваем классы элементов */
theme.row.classList.add(this.#CONFIG.menuRowClass);
theme.icon.classList.add(this.#CONFIG.menuImageClass);
theme.desc.classList.add(this.#CONFIG.menuDescriptionClass);
/* заполняем иконку и описание */
theme.icon.innerHTML = svg || this.#CONFIG.defaultImage;
theme.desc.innerText = desc || name;
/* собираем строку меню */
theme.row.appendChild(theme.icon);
theme.row.appendChild(theme.desc);
/* настраиваем обработчики */
theme.row.addEventListener('mouseenter', (function () { this.menu.preview(this.idx); }).bind(theme));
theme.row.addEventListener('focusin', (function () { this.menu.preview(this.idx); }).bind(theme));
this.#MENU.appendChild(theme.row);
theme.idx = this.#THEMES.push(theme) - 1;
return theme;
}
static #initDeafultThemes = (() => {
this.#newTheme(
'auto',
'Системная',
'<svg width="100%" height="100%" version="1.1" viewBox="0 0 5.2917 5.2917" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g stroke-width="0"><path style="opacity:1.0;fill:currentColor;" d="m4.4476 2.5745a1.3875 1.3423 19.362 0 0-0.75325-0.21319 1.1274 1.192 39.474 0 1 0.34686 0.1377 1.1274 1.192 39.474 0 1 0.32108 1.5973 1.1274 1.192 39.474 0 1-1.6003 0.4122 1.1274 1.192 39.474 0 1-0.29802-0.27356 1.3875 1.3423 19.362 0 0 0.53957 0.60799 1.3875 1.3423 19.362 0 0 1.901-0.40727 1.3875 1.3423 19.362 0 0-0.457-1.8611z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(.70717 -.70704 .69993 .71421 0 0)" d="m-3.6635 3.708h7.4025v0.067989h-7.4025z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" d="m2.3299 1.4771a0.81545 0.81545 0 0 1-0.81546 0.81546 0.81545 0.81545 0 0 1-0.81545-0.81546 0.81545 0.81545 0 0 1 0.81545-0.81545 0.81545 0.81545 0 0 1 0.81546 0.81545z" opacity=".99169"/></g><g stroke-width="0"><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m2.1854 0.26287c0.03577 0.020652 0.049011 0.064222 0.029688 0.097691l-0.13061 0.22622c-0.019323 0.033469-0.063676 0.043787-0.099447 0.023135-0.03577-0.020652-0.049011-0.064222-0.029688-0.097691l0.13061-0.22622c0.019323-0.033469 0.063677-0.043787 0.099447-0.023135z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m2.6702 0.72792c0.020652 0.03577 0.010334 0.080124-0.023135 0.099447l-0.22622 0.13061c-0.033469 0.019323-0.077039 0.006082-0.097691-0.029688-0.020652-0.03577-0.010334-0.080124 0.023135-0.099447l0.22622-0.13061c0.033469-0.019323 0.077039-0.006082 0.097691 0.029688z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m2.8575 1.3731c0 0.041304-0.031113 0.074556-0.069759 0.074556h-0.26122c-0.038647 0-0.069759-0.033252-0.069759-0.074556s0.031112-0.074556 0.069759-0.074556h0.26122c0.038647 0 0.069759 0.033252 0.069759 0.074556z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m2.6971 2.0254c-0.020652 0.03577-0.064222 0.049011-0.097691 0.029688l-0.22622-0.13061c-0.033469-0.019323-0.043787-0.063677-0.023135-0.099447s0.064222-0.049011 0.097691-0.029688l0.22622 0.13061c0.033469 0.019323 0.043787 0.063677 0.023135 0.099447z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m2.2321 2.5102c-0.03577 0.020652-0.080124 0.010334-0.099447-0.023135l-0.13061-0.22622c-0.019323-0.033469-0.00608-0.077039 0.029688-0.097691 0.03577-0.020652 0.080124-0.010334 0.099447 0.023135l0.13061 0.22622c0.019323 0.033469 0.00608 0.077039-0.029688 0.097691z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m1.5869 2.6975c-0.041304 0-0.074556-0.031113-0.074556-0.069759v-0.26122c0-0.038646 0.033252-0.069759 0.074556-0.069759s0.074556 0.031113 0.074556 0.069759v0.26122c0 0.038647-0.033252 0.069759-0.074556 0.069759z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m0.93459 2.5371c-0.03577-0.020652-0.049011-0.064222-0.029688-0.097691l0.13061-0.22622c0.019323-0.033469 0.063676-0.043787 0.099447-0.023135 0.03577 0.020652 0.049011 0.064222 0.029688 0.097691l-0.13061 0.22622c-0.019323 0.033469-0.063677 0.043787-0.099447 0.023135z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m0.44982 2.0721c-0.020652-0.03577-0.010334-0.080124 0.023135-0.099447l0.22622-0.13061c0.033469-0.019323 0.077039-0.00608 0.097691 0.029688 0.020652 0.03577 0.010334 0.080124-0.023135 0.099447l-0.22622 0.13061c-0.033469 0.019323-0.077039 0.00608-0.097691-0.029688z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m0.26251 1.4269c0-0.041304 0.031112-0.074556 0.069759-0.074556h0.26122c0.038646 0 0.069759 0.033252 0.069759 0.074556s-0.031112 0.074556-0.069759 0.074556h-0.26122c-0.038646 0-0.069759-0.033252-0.069759-0.074556z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m0.42287 0.77459c0.020652-0.03577 0.064222-0.049011 0.097691-0.029688l0.22622 0.13061c0.033469 0.019323 0.043787 0.063676 0.023135 0.099447s-0.064222 0.049011-0.097691 0.029688l-0.22622-0.13061c-0.033469-0.019323-0.043787-0.063677-0.023135-0.099447z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m0.88792 0.28982c0.03577-0.020652 0.080124-0.010334 0.099447 0.023135l0.13061 0.22622c0.019323 0.033469 0.00608 0.077039-0.029688 0.097691-0.03577 0.020652-0.080124 0.010334-0.099447-0.023135l-0.13061-0.22622c-0.019323-0.033469-0.006082-0.077039 0.029688-0.097691z" opacity=".99169"/><path style="opacity:1.0;fill:currentColor;" transform="matrix(1.0395 0 0 1.0359 -.10357 .033596)" d="m1.5331 0.10251c0.041304 0 0.074556 0.031112 0.074556 0.069759v0.26122c0 0.038646-0.033252 0.069759-0.074556 0.069759s-0.074556-0.031112-0.074556-0.069759v-0.26122c0-0.038646 0.033252-0.069759 0.074556-0.069759z" opacity=".99169"/></g></svg>',
);
this.#newTheme(
'light',
'Светлая',
'<svg id="theme-icon-light" width="100%" height="100%" version="1.1" viewBox="0 0 3.7451 3.7688" xmlns="http://www.w3.org/2000/svg"><g style="opacity:1.0;fill:currentColor;" stroke-width="0"><path d="m2.7254 1.8844a0.85289 0.85494 0 0 1-0.85289 0.85494 0.85289 0.85494 0 0 1-0.85289-0.85494 0.85289 0.85494 0 0 1 0.85289-0.85494 0.85289 0.85494 0 0 1 0.85289 0.85494z"/><path d="m2.7453 0.36254c0.037199 0.021529 0.049857 0.06888 0.028379 0.10617l-0.31014 0.53847c-0.021477 0.03729-0.068715 0.049977-0.10592 0.028449-0.0372-0.021529-0.049857-0.068881-0.02838-0.10617l0.31014-0.53847c0.021477-0.037289 0.068714-0.049977 0.10592-0.028448z"/><path d="m3.3875 1.0039c0.021477 0.03729 0.00882 0.08464-0.02838 0.10617l-0.53718 0.31089c-0.037199 0.021527-0.084439 0.00885-0.10592-0.02845-0.021478-0.037289-0.00882-0.084641 0.028379-0.10617l0.53718-0.31089c0.037199-0.021528 0.084439-0.008843 0.10592 0.028448z"/><path d="m3.6237 1.8811c0 0.043057-0.03458 0.07772-0.077536 0.07772h-0.62028c-0.042954 0-0.077536-0.034663-0.077536-0.07772 0-0.043058 0.03458-0.077723 0.077536-0.077723h0.62028c0.042955 0 0.077536 0.034663 0.077535 0.077723z"/><path d="m3.3907 2.7593c-0.021477 0.037289-0.068714 0.049977-0.10592 0.028449l-0.53718-0.31089c-0.037199-0.021528-0.049856-0.068881-0.028379-0.10617 0.021478-0.037289 0.068714-0.049977 0.10592-0.028449l0.53718 0.31089c0.0372 0.021527 0.049857 0.068881 0.028379 0.10617z"/><path d="m2.7509 3.403c-0.037199 0.021527-0.084439 0.00885-0.10592-0.02845l-0.31014-0.53847c-0.021477-0.037289-0.00882-0.084641 0.02838-0.10617 0.037199-0.021529 0.084439-0.00885 0.10592 0.028449l0.31014 0.53847c0.021478 0.037289 0.00882 0.084641-0.028379 0.10617z"/><path d="m1.8758 3.6398c-0.042956 0-0.077536-0.034663-0.077536-0.077721v-0.62177c0-0.043058 0.03458-0.077721 0.077536-0.077721 0.042955 0 0.077536 0.034663 0.077536 0.077721v0.62177c0 0.043058-0.03458 0.077722-0.077536 0.077722z"/><path d="m0.99973 3.4062c-0.0372-0.021528-0.049857-0.068881-0.02838-0.10617l0.31014-0.53847c0.021477-0.037289 0.068714-0.049977 0.10592-0.028449 0.037199 0.021528 0.049858 0.068881 0.02838 0.10617l-0.31014 0.53847c-0.021478 0.037289-0.068715 0.049977-0.10592 0.028448z"/><path d="m0.35757 2.7649c-0.021477-0.037289-0.00882-0.084641 0.02838-0.10617l0.53718-0.31089c0.0372-0.021528 0.084438-0.00885 0.10592 0.028449 0.021478 0.037289 0.00881 0.084642-0.02838 0.10617l-0.53718 0.31088c-0.0372 0.021527-0.084438 0.00885-0.10591-0.028448z"/><path d="m0.12134 1.8876c0-0.043059 0.034581-0.077721 0.077535-0.077721h0.62028c0.042954 0 0.077535 0.034664 0.077535 0.077721s-0.03458 0.077721-0.077535 0.077721h-0.62028c-0.042955 3e-7 -0.077535-0.034664-0.077535-0.077721z"/><path d="m0.35434 1.0095c0.021477-0.03729 0.068716-0.049976 0.10592-0.028448l0.53718 0.31089c0.0372 0.021528 0.049857 0.068881 0.02838 0.10617-0.021478 0.037289-0.068716 0.049977-0.10592 0.028449l-0.53718-0.31089c-0.0372-0.02153-0.049858-0.068882-0.02838-0.10617z"/><path d="m0.99414 0.36578c0.0372-0.021529 0.084439-0.00884 0.10592 0.028448l0.31014 0.53847c0.021479 0.03729 0.00882 0.08464-0.028379 0.10617-0.0372 0.021527-0.084439 0.00885-0.10592-0.028448l-0.31014-0.53847c-0.021477-0.037289-0.00881-0.084641 0.02838-0.10617z"/><path d="m1.8693 0.12898c0.042955 0 0.077536 0.034664 0.077536 0.077722v0.62177c0 0.043058-0.034579 0.077721-0.077536 0.077721-0.042956 0-0.077536-0.034664-0.077536-0.077721v-0.62177c0-0.043058 0.034579-0.077722 0.077536-0.077722z"/></g></svg>',
);
this.#newTheme(
'dark',
'Тёмная',
'<svg width="100%" height="100%" viewBox="0 0 5.291 5.291" version="1.1" id="theme-icon-dark" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cc="http://creativecommons.org/ns#"><path id="path1" style="display:inline;opacity:100%;fill:currentColor;fill-opacity:1;stroke:#171717;stroke-width:0" d="M 3.9317287,1.130201 A 2,2 0 0 0 2.7399338,0.64767413 1.5206705,1.8 40.797111 0 1 3.4192441,0.95205616 1.5206705,1.8 40.797111 0 1 3.394544,3.3083119 1.5206705,1.8 40.797111 0 1 1.0672109,3.6771907 1.5206705,1.8 40.797111 0 1 0.66679518,3.0496732 2,2 0 0 0 1.3183584,4.1581283 2,2 0 0 0 4.1390072,3.9508498 2,2 0 0 0 3.9317287,1.130201 Z" /></svg>',
);
this.#newTheme(
'old-terminal',
'Старый терминал',
'<svg width="100%" height="100%" version="1.1" viewBox="0 0 5.2917 5.2917" xmlns="http://www.w3.org/2000/svg"><g style="opacity:1.0;fill:currentColor;" transform="matrix(1.1692 0 0 1.1544 -.44779 -.40842)" stroke-width="0"><path d="m1.0459 1.1457c-0.277 0-0.50023 0.22323-0.50023 0.50023v1.9999c0 0.277 0.22323 0.50023 0.50023 0.50023h3.1998c0.277 0 0.50023-0.22323 0.50023-0.50023v-1.9999c0-0.277-0.22323-0.50023-0.50023-0.50023zm0 0.30024h3.1998c0.1108 0 0.19999 0.089188 0.19999 0.19999v1.9999c0 0.1108-0.089188 0.19999-0.19999 0.19999h-3.1998c-0.1108 0-0.19999-0.089188-0.19999-0.19999v-1.9999c0-0.1108 0.089188-0.19999 0.19999-0.19999z" opacity=".99169"/><rect x="1.0458" y="1.6458" width="3.2" height="2" rx=".17611" ry=".1752" opacity=".99169"/></g></svg>',
);
});
static #_ = (() => {
this.#initDeafultThemes();
console.log(this.#CONFIG);
console.log(this.#MENU);
})();
};