/* ============================================================
流·Studio · Shell renderer
渲染 sidebar / topbar / 网格背景装饰 / Toast / Modal helpers
每个页面调用 Shell.render({ active, crumbs, balance, topActions })
============================================================ */
const NAV = [
{
id: 'dashboard', label: '工作台', href: 'index.html',
icon: ''
},
{
id: 'products', label: '商品库', href: 'products.html', badge: '12',
icon: ''
},
{
id: 'projects', label: '视频项目', href: 'projects.html',
icon: ''
},
{
id: 'library', label: '资产库', href: 'library.html',
icon: ''
},
{
id: 'account', label: '账户', href: 'account.html',
icon: ''
},
{
id: 'settings', label: '设置', href: '#',
icon: ''
}
];
const TEAM_NAV = {
label: '团队', icon:
'',
badge: 'V1.5'
};
window.Shell = {
render({ active = '', crumbs = [], balance = '¥327.40', topActions = '' } = {}) {
const navHtml = NAV.map(n => `
${n.icon}
${n.label}
${n.badge ? `${n.badge}` : ''}
`).join('');
const sidebar = `
`;
const crumbHtml = crumbs.length ? `
${crumbs.map((c, i) => {
const last = i === crumbs.length - 1;
const sep = i > 0 ? '
/' : '';
if (last) return `${sep}
${c.label}`;
return `${sep}
${c.label}`;
}).join('')}
` : '';
const topbar = `
${crumbHtml}
余额 ${balance}
${topActions}
`;
const decorations = `
· · +
· +XX+
+XXXX·
+X·
+ · ·
XX· ·
·XXXX·+
·++·
· +
+·XX·
·X+ ·
·
+X·
·XX·
+·X·+
[ 200 OK ]
[ /v2 ]
[ .MP4 · 9:16 ]
[ STUDIO ]
`;
const toastHtml = `
`;
const app = document.createElement('div');
app.className = 'app';
app.innerHTML = sidebar + `${decorations}${topbar}`;
const src = document.getElementById('page');
document.body.prepend(app);
if (src) {
document.getElementById('page-content').innerHTML = src.innerHTML;
src.remove();
}
document.body.insertAdjacentHTML('beforeend', toastHtml);
document.addEventListener('keydown', e => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
document.getElementById('global-search')?.focus();
}
});
},
toast(text, mono) {
const t = document.getElementById('__toast');
const txt = document.getElementById('__toast-txt');
if (!t || !txt) return;
txt.innerHTML = text + (mono ? `[ ${mono} ]` : '');
t.classList.add('show');
clearTimeout(this._tt);
this._tt = setTimeout(() => t.classList.remove('show'), 2400);
},
openModal(id) { document.getElementById(id)?.classList.add('show'); },
closeModal(id) { document.getElementById(id)?.classList.remove('show'); },
openDrawer(id) {
document.getElementById(id)?.classList.add('show');
document.getElementById(id + '-bg')?.classList.add('show');
},
closeDrawer(id) {
document.getElementById(id)?.classList.remove('show');
document.getElementById(id + '-bg')?.classList.remove('show');
}
};