Files
js_theme_manager/js/felexdev-theme-manager.js
T

419 lines
31 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 ThemeManager.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` в соответствующее значение.
* @typedef ManagerState
*
* @property {DOMTokenList} clist: список классов ::root
* @property {HTMLElement} element: ::root, тег html
* @property {number} idx: индекс текущей темы
* @property {boolean} isDark: флаг тёмной системной темы
* @property {MediaQueryList} _schemeQuery: Медиа слушатель системной темы
* @property {boolean} _schemeListener: Обработчик изменений системной темы
*/
/**
* @typedef 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: Фактические размеры меню при применении темы в пикселях
*/
/**
* @typedef ThemeMenuSizes - Фактические размеры меню при использовании темы
* @property {string} w: ширина меню в пикселях
* @property {string} h: высота меню в пикселях
*/
/**
* @typedef MenuState
* Состояние меню
*
* @property {DOMTokenList} clist: список классов управляемого элемента classList
* @property {number} idx: индекс текущей темы меню
* @property {number} tmh: таймер сокрытия меню
* @property {number} tms: таймер показа меню
*/
/**
* Меню выбора тем
* @typedef ThemeMenu
* @property {ThemeManager} _tm - Ссылка на класс
* @property {MenuState} _stt - Состояние меню
* @property {[Theme]} _t - Ссылка на массив тем
* @property {()=>void} _tv - Переключает видимость
* @property {HTMLDivElement} div - Управляемый div элемент
* @property {CSSStyleDeclaration} style - Ссылка на стиль управляемого элемента
* @property {()=>void} appendChild - div.appendChild
* @property {(idx: number)=>void} apply - Превью темы
* @property {()=>void} hide - Скрыть меню
* @property {()=>void} show - Показать меню
*/
/**
* Глобальное состояние модуля
*
* @static
* @type {ManagerState}
*/
static #$ = (() => {
let e = {
clist: document.documentElement.classList,
element: document.documentElement,
idx: 0,
isDark: q.matches,
_schemeQuery: window.matchMedia('(prefers-color-scheme: dark)'),
_schemeListener: null
};
e._schemeQuery.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} defautlIcon: Иконка темы по умолчанию
* @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() {
const GLOBAL_PREFIX = 'flxd-tm';
const VISUALY_HIDDEN = 'visualy-hidden';
let c = {
/* Основные настройки модуля */
globalPrefix: 'flxd-tm', // глобальный префикс
storageKey: 'id', // базовое имя ключа в хранилище
toggle: {
id: 'button-toggle-color-scheme', // идентификатор кнопки переключения тем
liveId: 'button-tiggle-live', // идентификатор aria-live блока
liveClass: 'visualy-hidden',
},
theme: {
prefix: 'color-scheme', // корень названия классов темы
},
menu: {
attr: {
'id': 'menu',
'role': 'menu',
},
row: {
attr: {
class: 'entry',
role: 'menuitem',
},
icon: {
attr: {
class: 'icon',
'aria-hidden': 'true'
},
},
},
tmtAppear: 2000,
tmtDisappear: 300,
rowClass: 'row',
iconClass: 'icon',
descClass: 'desc',
ariaLabel: 'theme menu',
},
menuId: 'menu', // базовый идентификатор меню
menuRowClass: 'row', // базовый класс строки меню
menuImageClass: 'image', // базовый класс картинки темы в меню
menuDescriptionClass: 'desc', // базовый класс описательного имени темы в меню
menuAreaLabel: 'theme menu', // описание элемента меню
menuRowAreaLabel: 'row', // описание элемента строки меню
menuIconAreaLabel: 'icon', // описание элемента иконки темы
menuDescAreaLabel: 'description', // описание элемента описания темы
defautlIcon:'<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>',
};
/* Собираем строки */
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}`;
/* Настраиваем ARIA */
c.menuRowAreaLabel = `${c.menuAreaLabel} ${c.menuRowAreaLabel}`;
c.menuIconAreaLabel = `${c.menuRowAreaLabel} ${c.menuIconAreaLabel}`;
c.menuDescAreaLabel = `${c.menuRowAreaLabel} ${c.menuDescAreaLabel}`;
/* Кнопка смены темы оформления */
/* инициализация имени кнопки переключения тем */
c.buttonToggleId = c.globalPrefix + c.buttonToggleId;
/* инициализация префикса классов в селекторе CSS */
/* Тема оформления */
c.colorSchemePrefix = c.globalPrefix + c.colorSchemePrefix + '-';
/* Возвращаем полностью инициализированный объект с динамически скомпонованными строками */
return c;
})();
/**
* Массив тем
*
* @static
* @type {[Theme]}
*/
static #THEMES = [];
/**
* Сохраняет индекс текущей темы в хранилище
*
* @static
* @type {(idx: number) => void}
*/
static #save = (() => {
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 {{ idx: number, clist: DOMTokenList }?} e - JS-объект со следующими обязательными полями: { idx: number, clist: DOMTokenList, }
* @param {[Theme]?} t - Ссылка на массив тем
*/
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);
}
/**
* Меню выбора тем
*
* @static
* @type {ThemeMenu}
*/
static #MENU = (() => {
let menu = {
/* private: */
_сonfig: {
timeout: {
apear: 2000, // таймаут появления меню
disapear: 300, // таймаут исчезновения меню
},
select: {
id: 'menu', // базовый идентификатор меню
row: 'row', // базовый класс строки меню
image: 'image', // базовый класс картинки темы в меню
desc: 'desc', // базовый класс описательного имени темы в меню
},
aria: {
menu: 'меню выбора тем',// описание элемента меню
row: 'тема', // описание элемента строки меню
},
},
/* Свойства */
_tm: this, // ссылка на основной класс1
/* СОстояние */
_stt: {
clist: null, // classList of element
idx: 0, // текущая тема меню
tmh: null, // таймер сокрытия меню
tms: null, // таймер показа меню
},
_t: this.#THEMES, // ссылка на массив тем
/* Методы */
_tv: null, // переключить видимость
/* public: */
/* Методы */
appendChild: null, // `div.appendChild`
apply: null,
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;
})();
/**
* Создаёт и инициализирует новый объект темы
* @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: Пустое или не строковое значение 'name': ${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: 0, // Индекс темы в массиве тем
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.defautlIcon;
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 #findTheme(name) {
let id = -1;
for (let i = 0; i < this.#THEMES.length; i++) {
if (name === this.#THEMES[i].name) {
id = i;
}
}
return id;
}
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);
})();
};
const menu = document.createElement('div');
menu.setAttribute('aria-label', 'меню выбора тем');
menu.setAttribute('role', 'menu');
menu.tabIndex = 0;
for (let n = 1; n < 6; n++) {
let r = document.createElement('div');
let i = document.createElement('div');
let d = document.createElement('div');
r.setAttribute('role', `menuitem`);
r.setAttribute('aria-label', `цветовая схема ` + n);
i.setAttribute('aria-hidden', 'true');
d.setAttribute('aria-hidden', 'true');
r.appendChild(i);
r.appendChild(d);
menu.appendChild(r);
}