caterium-app/public/core/brand-theme.js

111 lines
28 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.

/* ===== MODULE: brand-theme-v1.js ===== */
/* Sun Catering theme editor v4: simple color presets, staged preview, reliable sidebar apply */
(()=>{
'use strict';
if(window.__sunBrandThemeV4)return;window.__sunBrandThemeV4=true;
// Keep the intermediate legacy layouts out of the first visible frame.
if(document.readyState==='loading'){
document.documentElement.classList.add('sun-app-starting');
document.addEventListener('DOMContentLoaded',()=>requestAnimationFrame(()=>document.documentElement.classList.remove('sun-app-starting')),{once:true});
}
const KEY='sunBrandThemeV1';
const BRAND={sun:'#FFC107',accent:'#FF8A00',text:'#1A1A1A',background:'#FFF7E6',surface:'#F3E8D3',fresh:'#A8C783',success:'#6D8F6A',trust:'#6C7A89',warm:'#C7744D',border:'#E7E7E7'};
const UI_FIRM={background:'#FFF7E6',card:'#FFFFFF',primary:'#1A1A1A',accent:'#FFC107',text:'#1A1A1A',muted:'#6C7A89',border:'#E7E7E7',input:'#FFFFFF',buttonText:'#FFFFFF'};
const UI_STANDARD={background:'#F5F6FA',card:'#FFFFFF',primary:'#15364C',accent:'#C99A32',text:'#203040',muted:'#68717A',border:'#D9DDE0',input:'#FFFFFF',buttonText:'#FFFFFF'};
const SIDEBAR_STANDARD={background:'#32255D',background2:'#171D38',glow:'#9574FF',border:'#4B3C77',icons:'#E9E8F6',iconBackground:'#3A2F68',text:'#E9E8F6',muted:'#A9A8C6',activeBackground:'#463A74',activeText:'#FFFFFF',activeIcon:'#FFE48D',indicator:'#E4B844',toolsBackground:'#3A315F',toolsBorder:'#544A7B',collapseBackground:'#FFFFFF',collapseText:'#433D68',badgeBackground:'#FF6C7C',badgeText:'#FFFFFF'};
const SIDEBAR_FIRM={background:'#1A1A1A',background2:'#2A2A2A',glow:'#FFC107',border:'#3A372F',icons:'#FFC107',iconBackground:'#2A281D',text:'#FFF7E6',muted:'#C9B98E',activeBackground:'#34301F',activeText:'#FFC107',activeIcon:'#FFC107',indicator:'#FF8A00',toolsBackground:'#242424',toolsBorder:'#414141',collapseBackground:'#FFFFFF',collapseText:'#1A1A1A',badgeBackground:'#C7744D',badgeText:'#FFFFFF'};
const SIDEBAR_LIGHT={background:'#FFF7E6',background2:'#F3E8D3',glow:'#FFC107',border:'#E2D5BC',icons:'#C7744D',iconBackground:'#FFFDF9',text:'#1A1A1A',muted:'#6C7A89',activeBackground:'#FFFFFF',activeText:'#C7744D',activeIcon:'#C7744D',indicator:'#FF8A00',toolsBackground:'#FFFFFF',toolsBorder:'#E2D5BC',collapseBackground:'#1A1A1A',collapseText:'#FFFFFF',badgeBackground:'#C7744D',badgeText:'#FFFFFF'};
const SIDEBAR_EMERALD={background:'#123C30',background2:'#071F19',glow:'#FFC107',border:'#285849',icons:'#FFC107',iconBackground:'#173E33',text:'#FFF7E6',muted:'#A8C783',activeBackground:'#1C4C3D',activeText:'#FFF7E6',activeIcon:'#FFC107',indicator:'#FF8A00',toolsBackground:'#16382F',toolsBorder:'#2B5A4B',collapseBackground:'#FFF7E6',collapseText:'#123C30',badgeBackground:'#C7744D',badgeText:'#FFFFFF'};
const SIDEBAR_SUNSET={background:'#49301B',background2:'#1A1A1A',glow:'#FF8A00',border:'#69462A',icons:'#FFC107',iconBackground:'#3A2C1E',text:'#FFF7E6',muted:'#D6BD91',activeBackground:'#62401D',activeText:'#FFF7E6',activeIcon:'#FFC107',indicator:'#FF8A00',toolsBackground:'#34281F',toolsBorder:'#5A4632',collapseBackground:'#FFF7E6',collapseText:'#49301B',badgeBackground:'#C7744D',badgeText:'#FFFFFF'};
const UI_LABELS={background:'Фон приложения',card:'Карточки и окна',primary:'Основные кнопки',accent:'Акцент / обводка',text:'Основной текст',muted:'Вторичный текст',border:'Границы',input:'Поля ввода',buttonText:'Текст основных кнопок'};
const SIDE_LABELS={background:'Основной цвет панели',background2:'Второй цвет / низ панели',glow:'Свечение панели',border:'Граница панели',icons:'Цвет значков',iconBackground:'Фон значков',text:'Основной текст панели',muted:'Подписи групп',activeBackground:'Фон активного пункта',activeText:'Текст активного пункта',activeIcon:'Активный значок',indicator:'Полоса активного пункта',toolsBackground:'Поиск / уведомления',toolsBorder:'Граница служебных кнопок',collapseBackground:'Кнопка свернуть',collapseText:'Стрелка сворачивания',badgeBackground:'Уведомление',badgeText:'Текст уведомления'};
const BRAND_LABELS={sun:'Солнечный',accent:'Оранжевый',text:'Графит',background:'Кремовый фон',surface:'Бежевый',fresh:'Свежий зелёный',success:'Фирменный зелёный',trust:'Серо-синий',warm:'Терракота',border:'Светлая граница'};
const esc=value=>window.SunSafe.escapeHTML(value);
const clone=o=>JSON.parse(JSON.stringify(o));
const isHex=v=>/^#[0-9a-f]{6}$/i.test(String(v||'').trim());
const norm=(v,f)=>isHex(v)?String(v).toUpperCase():f;
const hexRgba=(hex,a=.25)=>{const h=norm(hex,'#000000').slice(1);return `rgba(${parseInt(h.slice(0,2),16)},${parseInt(h.slice(2,4),16)},${parseInt(h.slice(4,6),16)},${a})`};
const defaults=()=>({version:4,palette:{...BRAND},ui:{...UI_FIRM},sidebar:{...SIDEBAR_FIRM}});
const standardState=()=>({version:4,palette:{...BRAND},ui:{...UI_STANDARD},sidebar:{...SIDEBAR_STANDARD}});
const presetState=name=>{
if(name==='standard')return standardState();
const sidebar=name==='light'?SIDEBAR_LIGHT:name==='emerald'?SIDEBAR_EMERALD:name==='sunset'?SIDEBAR_SUNSET:SIDEBAR_FIRM;
return{version:4,palette:{...BRAND},ui:{...UI_FIRM},sidebar:{...sidebar}};
};
function read(){
let raw={};try{raw=JSON.parse(localStorage.getItem(KEY)||'{}')||{}}catch(_){raw={}}
const base=defaults(),palette={...base.palette,...(raw.palette||{})},ui={...base.ui,...(raw.ui||{})},sidebar={...base.sidebar,...(raw.sidebar||{})};
Object.keys(BRAND).forEach(k=>palette[k]=norm(palette[k],BRAND[k]));
Object.keys(UI_FIRM).forEach(k=>ui[k]=norm(ui[k],UI_FIRM[k]));
Object.keys(SIDEBAR_FIRM).forEach(k=>sidebar[k]=norm(sidebar[k],SIDEBAR_FIRM[k]));
if(String(ui.buttonText).toUpperCase()===String(ui.primary).toUpperCase())ui.buttonText='#FFFFFF';
return{version:4,palette,ui,sidebar};
}
let savedState=read(),previewState=clone(savedState),dirty=false;
const persist=()=>localStorage.setItem(KEY,JSON.stringify(savedState));
const style=document.createElement('style');style.id='sun-brand-theme-style-v4';style.textContent=`
:root{--sun-ui-bg:#FFF7E6;--sun-ui-card:#fff;--sun-ui-primary:#1A1A1A;--sun-ui-accent:#FFC107;--sun-ui-text:#1A1A1A;--sun-ui-muted:#6C7A89;--sun-ui-border:#E7E7E7;--sun-ui-input:#fff;--sun-ui-button-text:#fff;--sun-sidebar-bg:#32255D;--sun-sidebar-bg2:#171D38;--sun-sidebar-glow:#9574FF;--sun-sidebar-border:#4B3C77;--sun-sidebar-icons:#E9E8F6;--sun-sidebar-icon-bg:#3A2F68;--sun-sidebar-text:#E9E8F6;--sun-sidebar-muted:#A9A8C6;--sun-sidebar-active-bg:#463A74;--sun-sidebar-active-text:#fff;--sun-sidebar-active-icon:#FFE48D;--sun-sidebar-indicator:#E4B844;--sun-sidebar-tools-bg:#3A315F;--sun-sidebar-tools-border:#544A7B;--sun-sidebar-collapse-bg:#fff;--sun-sidebar-collapse-text:#433D68;--sun-sidebar-badge-bg:#FF6C7C;--sun-sidebar-badge-text:#fff}:root body{background:var(--sun-ui-bg)!important;color:var(--sun-ui-text)!important}:root{--n:var(--sun-ui-primary)!important;--g:var(--sun-ui-accent)!important;--p:var(--sun-ui-bg)!important;--l:var(--sun-ui-border)!important}:root .card,:root .page,:root .enterprise-card,:root .dialog,:root .sun-order-lines-table,:root .dash3-panel{background:var(--sun-ui-card)!important;color:var(--sun-ui-text)!important;border-color:var(--sun-ui-border)!important}:root .page h1,:root .catalog h1,:root .enterprise-card h2,:root .enterprise-card h3{color:var(--sun-ui-primary)!important}:root .hint,:root label,:root .enterprise-card .hint{color:var(--sun-ui-muted)!important}:root input,:root select,:root textarea{background:var(--sun-ui-input)!important;color:var(--sun-ui-text)!important;border-color:var(--sun-ui-border)!important}:root button.primary,:root .primary{background:var(--sun-ui-primary)!important;border-color:var(--sun-ui-primary)!important;color:var(--sun-ui-button-text)!important}:root .primary svg,:root .primary *{color:inherit!important}:root .outline{border-color:var(--sun-ui-accent)!important;color:var(--sun-ui-primary)!important;background:var(--sun-ui-card)!important}
@media(min-width:901px){:root .sun-enterprise-sidebar header .brand{color:var(--sun-sidebar-text)!important;border-bottom-color:color-mix(in srgb,var(--sun-sidebar-text) 12%,transparent)!important}:root .sun-enterprise-sidebar .sun-nav-group{border-bottom-color:color-mix(in srgb,var(--sun-sidebar-text) 10%,transparent)!important}:root .sun-enterprise-sidebar .sun-nav-group::before{color:var(--sun-sidebar-muted)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button{color:var(--sun-sidebar-text)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button::before{background:var(--sun-sidebar-icons)!important;color:var(--sun-sidebar-icons)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button:hover{background:color-mix(in srgb,var(--sun-sidebar-active-bg) 72%,transparent)!important;color:var(--sun-sidebar-text)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button.on{background:var(--sun-sidebar-active-bg)!important;color:var(--sun-sidebar-active-text)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button.on::before{background:var(--sun-sidebar-active-icon)!important;color:var(--sun-sidebar-active-icon)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button.on::after{background:var(--sun-sidebar-indicator)!important;box-shadow:0 0 10px color-mix(in srgb,var(--sun-sidebar-indicator) 42%,transparent)!important}:root .sun-side-tools .sun-side-action{color:var(--sun-sidebar-text)!important;border-color:var(--sun-sidebar-tools-border)!important;background:var(--sun-sidebar-tools-bg)!important}:root .sun-current-user,:root #sunLogoutBtn{color:var(--sun-sidebar-muted)!important}:root .sun-sidebar-collapse{background:var(--sun-sidebar-collapse-bg)!important;color:var(--sun-sidebar-collapse-text)!important;border-color:var(--sun-sidebar-border)!important}:root #sunNotificationsBtn .badge{background:var(--sun-sidebar-badge-bg)!important;color:var(--sun-sidebar-badge-text)!important;border-color:var(--sun-sidebar-bg)!important}}
@media(max-width:900px){:root .sun-enterprise-sidebar header,:root .sun-enterprise-sidebar header nav{background:linear-gradient(165deg,var(--sun-sidebar-bg),var(--sun-sidebar-bg2))!important;color:var(--sun-sidebar-text)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button{color:var(--sun-sidebar-text)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button::before{background:var(--sun-sidebar-icons)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button.on{background:var(--sun-sidebar-active-bg)!important;color:var(--sun-sidebar-active-text)!important}:root .sun-enterprise-sidebar header nav .sun-nav-button.on::before{background:var(--sun-sidebar-active-icon)!important}}:root .sun-brand-settings-card{overflow:hidden}:root .sun-theme-toolbar{display:flex;gap:8px;flex-wrap:wrap;margin:11px 0 14px}:root .sun-theme-sections{display:grid;gap:13px}:root .sun-theme-box{border:1px solid var(--sun-ui-border);border-radius:12px;padding:13px;background:color-mix(in srgb,var(--sun-ui-card) 96%,var(--sun-ui-bg))}:root .sun-theme-box h3{margin:0 0 9px}:root .sun-theme-panel-main{display:grid;grid-template-columns:minmax(250px,.8fr) minmax(340px,1.2fr);gap:14px;align-items:start}:root .sun-theme-preview{min-height:190px;border-radius:16px;background:radial-gradient(circle at 10% 0,color-mix(in srgb,var(--sun-sidebar-glow) 35%,transparent),transparent 35%),linear-gradient(150deg,var(--sun-sidebar-bg),var(--sun-sidebar-bg2));padding:15px;color:var(--sun-sidebar-text);border:1px solid var(--sun-sidebar-border)}:root .sun-theme-preview-head{display:flex;align-items:center;gap:10px;padding-bottom:12px;border-bottom:1px solid color-mix(in srgb,var(--sun-sidebar-text) 13%,transparent)}:root .sun-theme-preview-logo{width:35px;height:35px;border-radius:50%;background:var(--sun-sidebar-icons);box-shadow:0 0 18px color-mix(in srgb,var(--sun-sidebar-glow) 45%,transparent)}:root .sun-theme-preview-menu{display:grid;gap:7px;margin-top:13px}:root .sun-theme-preview-row{height:38px;border-radius:10px;display:flex;align-items:center;gap:10px;padding:0 10px;color:var(--sun-sidebar-text)}:root .sun-theme-preview-row.on{background:var(--sun-sidebar-active-bg);color:var(--sun-sidebar-active-text);box-shadow:inset 3px 0 0 var(--sun-sidebar-indicator)}:root .sun-theme-preview-row i{width:25px;height:25px;display:grid;place-items:center;color:var(--sun-sidebar-icons);font-style:normal}:root .sun-theme-preview-row.on i{color:var(--sun-sidebar-active-icon)}:root .sun-theme-preview small{color:var(--sun-sidebar-muted)}:root .sun-sidebar-core-colors{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px;margin-bottom:12px}:root .sun-brand-setting-grid{display:grid;grid-template-columns:repeat(3,minmax(185px,1fr));gap:8px}:root .sun-brand-color-field{display:grid;grid-template-columns:34px minmax(0,1fr) 82px;gap:7px;align-items:center;padding:7px 8px;border:1px solid var(--sun-ui-border);border-radius:9px;background:var(--sun-ui-card)}:root .sun-brand-color-field label{font-size:10.5px;line-height:1.2}:root .sun-brand-color-field input[type=color]{width:32px!important;height:30px!important;padding:2px!important;border:1px solid var(--sun-ui-border)!important;border-radius:7px!important}:root .sun-brand-color-field input[type=text]{width:82px!important;height:30px!important;padding:4px 6px!important;border-radius:7px!important;font:700 10px ui-monospace,monospace!important;text-transform:uppercase}:root .sun-brand-palette-toggle{margin-top:10px}:root .sun-brand-palette-toggle summary{cursor:pointer;font-weight:750;color:var(--sun-ui-primary)}:root .sun-brand-palette{display:grid;grid-template-columns:repeat(5,minmax(90px,1fr));gap:8px;margin-top:10px}:root .sun-brand-swatch{border:1px solid var(--sun-ui-border);border-radius:10px;background:var(--sun-ui-card);overflow:hidden}:root .sun-brand-swatch-top{height:38px;background:var(--swatch)}:root .sun-brand-swatch-body{padding:6px 7px}:root .sun-brand-swatch-body b{display:block;font-size:10px}:root .sun-brand-swatch-body small{font:700 9px ui-monospace,monospace;color:var(--sun-ui-muted)}:root .sun-theme-savebar{position:sticky;bottom:0;z-index:3;display:flex;align-items:center;justify-content:space-between;gap:10px;margin:15px -13px -13px;padding:12px 13px;background:color-mix(in srgb,var(--sun-ui-card) 94%,transparent);border-top:1px solid var(--sun-ui-border);backdrop-filter:blur(10px)}:root .sun-theme-savebar .actions{display:flex;gap:8px;flex-wrap:wrap}:root .sun-theme-dirty{font-size:11px;color:var(--sun-ui-muted)}:root .sun-theme-dirty strong{color:var(--sun-ui-accent)}:root header .brand.sun-brand-home-link{cursor:pointer!important;border-radius:10px;transition:background .15s ease}:root .sun-enterprise-sidebar header .brand.sun-brand-home-link:hover{background:rgba(255,255,255,.06)!important}:root .sun-brand-home-link:focus-visible{outline:2px solid var(--sun-sidebar-indicator);outline-offset:2px}
@media(max-width:1100px){:root .sun-brand-setting-grid{grid-template-columns:repeat(2,minmax(180px,1fr))}}@media(max-width:760px){:root .sun-theme-panel-main,:root .sun-sidebar-core-colors,:root .sun-brand-setting-grid{grid-template-columns:1fr}:root .sun-brand-palette{grid-template-columns:repeat(2,1fr)}:root .sun-theme-savebar{align-items:flex-start;flex-direction:column}}
:root{background:var(--sun-ui-bg)}
:root body.sun-enterprise-sidebar{background:var(--sun-ui-bg)!important}
:root body>header,:root body.sun-enterprise-sidebar>header{
background:radial-gradient(circle at 12% 0%,var(--sun-sidebar-glow-rgba),transparent 31%),linear-gradient(165deg,var(--sun-sidebar-bg) 0%,var(--sun-sidebar-bg2) 100%)!important;
border-right:1px solid var(--sun-sidebar-border)!important;
box-shadow:9px 0 34px var(--sun-sidebar-shadow)!important;
}
:root.sun-app-starting body{visibility:hidden!important}
:root.sun-app-starting .sun-enterprise-sidebar,:root.sun-app-starting .sun-enterprise-sidebar *,:root.sun-app-starting .sun-enterprise-sidebar *::before,:root.sun-app-starting .sun-enterprise-sidebar *::after{transition:none!important;animation:none!important}
:root.sun-app-starting::after{content:'Caterium';position:fixed;inset:0;display:grid;place-items:center;background:var(--sun-ui-bg);color:var(--sun-ui-text);font:500 32px Georgia,serif;z-index:40000}
`;document.head.appendChild(style);
function applyActual(s=savedState){
document.body?.classList.remove('sun-custom-sidebar-icons');
const root=document.documentElement.style;
Object.entries(s.palette).forEach(([k,v])=>root.setProperty(`--sun-brand-${k}`,v));
Object.entries(s.ui).forEach(([k,v])=>root.setProperty(`--sun-ui-${k.replace(/[A-Z]/g,m=>'-'+m.toLowerCase())}`,v));
const map={background:'--sun-sidebar-bg',background2:'--sun-sidebar-bg2',glow:'--sun-sidebar-glow',border:'--sun-sidebar-border',icons:'--sun-sidebar-icons',iconBackground:'--sun-sidebar-icon-bg',text:'--sun-sidebar-text',muted:'--sun-sidebar-muted',activeBackground:'--sun-sidebar-active-bg',activeText:'--sun-sidebar-active-text',activeIcon:'--sun-sidebar-active-icon',indicator:'--sun-sidebar-indicator',toolsBackground:'--sun-sidebar-tools-bg',toolsBorder:'--sun-sidebar-tools-border',collapseBackground:'--sun-sidebar-collapse-bg',collapseText:'--sun-sidebar-collapse-text',badgeBackground:'--sun-sidebar-badge-bg',badgeText:'--sun-sidebar-badge-text'};
Object.entries(map).forEach(([k,v])=>root.setProperty(v,s.sidebar[k]));
root.setProperty('--sun-ui-bg',s.ui.background);
root.setProperty('--sun-sidebar-glow-rgba',hexRgba(s.sidebar.glow,.30));
root.setProperty('--sun-sidebar-shadow',hexRgba(s.sidebar.background,.22));
window.dispatchEvent(new CustomEvent('sunbrandthemechange',{detail:clone(s)}));
}
function markDirty(){dirty=JSON.stringify(previewState)!==JSON.stringify(savedState);const el=document.querySelector('[data-theme-dirty]');if(el)el.innerHTML=dirty?'<strong>Есть несохранённые изменения</strong> · пока меняется только предпросмотр':'Все изменения сохранены'}
function field(scope,key,label,value){return`<div class="sun-brand-color-field" data-color-scope="${scope}" data-color-key="${key}"><input type="color" value="${esc(value)}" aria-label="${esc(label)}"><label>${esc(label)}</label><input type="text" value="${esc(value)}" maxlength="7" spellcheck="false" aria-label="HEX ${esc(label)}"></div>`}
function paletteHtml(){return Object.keys(BRAND).map(k=>`<div class="sun-brand-swatch" style="--swatch:${esc(BRAND[k])}"><div class="sun-brand-swatch-top"></div><div class="sun-brand-swatch-body"><b>${esc(BRAND_LABELS[k])}</b><small>${esc(BRAND[k])}</small></div></div>`).join('')}
function updatePreviewNode(card){
const p=card.querySelector('.sun-theme-preview');if(!p)return;
const s=previewState.sidebar;
const vars={background:'--sun-sidebar-bg',background2:'--sun-sidebar-bg2',glow:'--sun-sidebar-glow',border:'--sun-sidebar-border',icons:'--sun-sidebar-icons',iconBackground:'--sun-sidebar-icon-bg',text:'--sun-sidebar-text',muted:'--sun-sidebar-muted',activeBackground:'--sun-sidebar-active-bg',activeText:'--sun-sidebar-active-text',activeIcon:'--sun-sidebar-active-icon',indicator:'--sun-sidebar-indicator'};
Object.entries(vars).forEach(([k,v])=>p.style.setProperty(v,s[k]));
}
function cardHtml(){
return`<h2>Цвета интерфейса</h2><p class="hint">Выберите готовый вариант или настройте цвета вручную. Изменения сначала видны в примере. Реальная левая панель меняется только после «Сохранить настройки».</p>
<div class="sun-theme-toolbar"><button class="outline" type="button" data-theme-preset="standard">Стандартная фиолетовая</button><button class="outline" type="button" data-theme-preset="firm">Фирменная тёмная</button><button class="outline" type="button" data-theme-preset="light">Фирменная светлая</button><button class="outline" type="button" data-theme-preset="emerald">Фирменная зелёная</button><button class="outline" type="button" data-theme-preset="sunset">Солнечная графитовая</button></div>
<div class="sun-theme-sections">
<section class="sun-theme-box"><h3>Левая панель</h3><div class="sun-theme-panel-main"><div class="sun-theme-preview"><div class="sun-theme-preview-head"><div class="sun-theme-preview-logo"></div><div><b>Солнце</b><small>Предпросмотр боковой панели</small></div></div><div class="sun-theme-preview-menu"><div class="sun-theme-preview-row"><i>⌂</i>Главная</div><div class="sun-theme-preview-row on"><i>▤</i>Заказы</div><div class="sun-theme-preview-row"><i>⚙</i>Настройки</div></div></div><div><h3 style="margin-top:0">Главные цвета панели</h3><div class="sun-sidebar-core-colors">${field('sidebar','background','Основной цвет панели',previewState.sidebar.background)}${field('sidebar','background2','Низ / второй цвет',previewState.sidebar.background2)}${field('sidebar','icons','Цвет значков',previewState.sidebar.icons)}</div><p class="hint">Основной цвет — это фон всей большой левой панели. Для однотонной панели поставьте одинаковый цвет в первых двух полях.</p></div></div><details style="margin-top:12px"><summary><b>Дополнительные цвета панели</b></summary><div class="sun-brand-setting-grid" style="margin-top:10px">${Object.keys(SIDEBAR_FIRM).filter(k=>!['background','background2','icons'].includes(k)).map(k=>field('sidebar',k,SIDE_LABELS[k],previewState.sidebar[k])).join('')}</div></details></section>
<section class="sun-theme-box"><h3>Основной интерфейс</h3><div class="sun-brand-setting-grid">${Object.keys(UI_FIRM).map(k=>field('ui',k,UI_LABELS[k],previewState.ui[k])).join('')}</div><details class="sun-brand-palette-toggle"><summary>Показать фирменные цвета «Солнца»</summary><div class="sun-brand-palette">${paletteHtml()}</div></details></section>
</div><div class="sun-theme-savebar"><div class="sun-theme-dirty" data-theme-dirty>${dirty?'<strong>Есть несохранённые изменения</strong> · пока меняется только предпросмотр':'Все изменения сохранены'}</div><div class="actions"><button class="outline" type="button" data-theme-cancel>Отменить изменения</button><button class="danger" type="button" data-reset-standard>Вернуть стандартную версию</button><button class="primary" type="button" data-theme-save>Сохранить настройки</button></div></div>`;
}
function rerender(card){card.innerHTML=cardHtml();bind(card);updatePreviewNode(card)}
function bind(card){
card.querySelectorAll('[data-color-scope]').forEach(row=>{const scope=row.dataset.colorScope,key=row.dataset.colorKey,c=row.querySelector('input[type=color]'),t=row.querySelector('input[type=text]');const applyValue=v=>{const fallback=scope==='ui'?UI_FIRM[key]:SIDEBAR_FIRM[key];const val=norm(v,fallback);previewState[scope][key]=val;if(c)c.value=val;if(t)t.value=val;updatePreviewNode(card);markDirty()};c?.addEventListener('input',()=>applyValue(c.value));t?.addEventListener('input',()=>{if(isHex(t.value))applyValue(t.value)});t?.addEventListener('blur',()=>{if(!isHex(t.value))t.value=previewState[scope][key]})});
card.querySelectorAll('[data-theme-preset]').forEach(b=>b.addEventListener('click',()=>{previewState=presetState(b.dataset.themePreset);markDirty();rerender(card)}));
card.querySelector('[data-theme-save]')?.addEventListener('click',()=>{savedState=clone(previewState);savedState.version=4;persist();dirty=false;applyActual(savedState);rerender(card);window.SunEnterprise?.toast?.('Настройки цветов сохранены.','success')});
card.querySelector('[data-theme-cancel]')?.addEventListener('click',()=>{previewState=clone(savedState);dirty=false;rerender(card)});
card.querySelector('[data-reset-standard]')?.addEventListener('click',()=>{if(!confirm('Вернуть стандартную фиолетовую панель и стандартные цвета интерфейса?'))return;savedState=standardState();previewState=clone(savedState);dirty=false;persist();applyActual(savedState);rerender(card);window.SunEnterprise?.toast?.('Стандартная версия восстановлена.','success')});
}
function ensureCard(){const view=document.getElementById('enterprise-settings'),grid=view?.querySelector('.enterprise-grid');if(!grid)return;let card=document.getElementById('sunBrandThemeSettingsCard');if(card&&grid.contains(card)){if(!card.dataset.bound){rerender(card);card.dataset.bound='1'}return}card=document.createElement('section');card.id='sunBrandThemeSettingsCard';card.className='enterprise-card wide sun-brand-settings-card';card.innerHTML=cardHtml();const history=[...grid.children].find(el=>(el.querySelector(':scope > h2')?.textContent||'').trim()==='История изменений');if(history)window.SunSafe.insertBefore(grid,card,history);else grid.appendChild(card);bind(card);updatePreviewNode(card);card.dataset.bound='1'}
function bindBrandHome(){const brand=document.querySelector('header .brand');if(!brand||brand.dataset.sunHomeBound)return;brand.dataset.sunHomeBound='1';brand.classList.add('sun-brand-home-link');brand.setAttribute('role','link');brand.setAttribute('tabindex','0');brand.setAttribute('title','Новый заказ');const go=()=>{const btn=[...document.querySelectorAll('header nav button')].find(b=>String(b.dataset.navLabel||b.textContent||'').trim()==='Новый заказ')||document.querySelector('header nav .nav-new');btn?.click()};brand.addEventListener('click',go);brand.addEventListener('keydown',e=>{if(e.key==='Enter'||e.key===' '){e.preventDefault();go()}})}
function syncFromStorage(){savedState=read();if(!dirty)previewState=clone(savedState);applyActual(savedState);const card=document.getElementById('sunBrandThemeSettingsCard');if(card&&!dirty)rerender(card)}
applyActual(savedState);previewState=clone(savedState);
const boot=()=>{applyActual(savedState);ensureCard();bindBrandHome();const settings=document.getElementById('enterprise-settings');if(settings)new MutationObserver(()=>queueMicrotask(()=>{if(settings.classList.contains('on')&&!document.getElementById('sunBrandThemeSettingsCard'))ensureCard();bindBrandHome()})).observe(settings,{childList:true,subtree:true});document.addEventListener('click',e=>{const b=e.target.closest('header nav button');if(!b)return;const name=String(b.dataset.navLabel||b.textContent||'').trim();if(name!=='Настройки'&&dirty){previewState=clone(savedState);dirty=false;const card=document.getElementById('sunBrandThemeSettingsCard');if(card)rerender(card)}},true);window.addEventListener('resize',()=>applyActual(savedState));window.addEventListener('storage',e=>{if(e.key===KEY)syncFromStorage()});window.addEventListener('suncloudsync',syncFromStorage);window.addEventListener('sun:cloud-state-applied',syncFromStorage)};
if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',boot,{once:true});else boot();
window.SunBrandTheme={get:()=>clone(savedState),preview:()=>clone(previewState),save:()=>{savedState=clone(previewState);persist();dirty=false;applyActual(savedState)},resetStandard:()=>{savedState=standardState();previewState=clone(savedState);persist();dirty=false;applyActual(savedState);ensureCard()},applyPreset:name=>{previewState=presetState(name);dirty=true;ensureCard()}};
})();
;