304 lines
27 KiB
JavaScript
304 lines
27 KiB
JavaScript
/**
|
||
* @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);
|
||
})();
|
||
};
|