juxscript 1.1.367 → 1.1.369
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/cli.js
CHANGED
|
@@ -289,9 +289,11 @@ Usage:
|
|
|
289
289
|
jux serve Start production server
|
|
290
290
|
jux serve --hot Start dev server with hot reload
|
|
291
291
|
jux comp [name] Add a component preset to your project
|
|
292
|
+
jux comp [name] -f Force overwrite (backs up existing files)
|
|
292
293
|
|
|
293
294
|
Options:
|
|
294
295
|
--help, -h Show this help message
|
|
296
|
+
--force, -f Overwrite existing files (creates .bak backups)
|
|
295
297
|
`);
|
|
296
298
|
}
|
|
297
299
|
|
|
@@ -301,6 +303,7 @@ Options:
|
|
|
301
303
|
// ═══════════════════════════════════════════════════════════════
|
|
302
304
|
async function runComp(compName) {
|
|
303
305
|
const presetsDir = path.join(PACKAGE_ROOT, 'presets');
|
|
306
|
+
const forceFlag = args.includes('--force') || args.includes('-f');
|
|
304
307
|
|
|
305
308
|
if (!fs.existsSync(presetsDir)) {
|
|
306
309
|
console.error('❌ No presets directory found in juxscript package.');
|
|
@@ -342,87 +345,109 @@ async function runComp(compName) {
|
|
|
342
345
|
fs.mkdirSync(targetSrcDir, { recursive: true });
|
|
343
346
|
}
|
|
344
347
|
|
|
345
|
-
//
|
|
346
|
-
const
|
|
348
|
+
// Resolve a safe destination folder name
|
|
349
|
+
const destFolderName = resolveDestFolderName(targetSrcDir, compName);
|
|
350
|
+
const destDir = path.join(targetSrcDir, destFolderName);
|
|
351
|
+
|
|
352
|
+
// List what will be copied
|
|
353
|
+
const presetFiles = listFilesRecursive(presetDir);
|
|
354
|
+
|
|
355
|
+
console.log(`\n📦 Preset: ${compName}`);
|
|
356
|
+
console.log(` Source: presets/${compName}/`);
|
|
357
|
+
console.log(` Target: ${path.relative(process.cwd(), destDir)}/\n`);
|
|
358
|
+
|
|
359
|
+
if (destFolderName !== compName) {
|
|
360
|
+
console.log(` ⚠️ "${compName}" already exists, using "${destFolderName}" instead.\n`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
console.log(` Files to copy:`);
|
|
364
|
+
presetFiles.forEach(f => console.log(` 📄 ${f}`));
|
|
365
|
+
console.log('');
|
|
366
|
+
|
|
367
|
+
// If dest exists (shouldn't with our naming, but just in case with --force)
|
|
368
|
+
if (fs.existsSync(destDir) && !forceFlag) {
|
|
369
|
+
const proceed = await promptYesNo(` Directory "${destFolderName}" exists. Overwrite contents?`);
|
|
370
|
+
if (!proceed) {
|
|
371
|
+
console.log(' Cancelled.\n');
|
|
372
|
+
process.exit(0);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Copy the entire preset folder
|
|
377
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
347
378
|
let copied = 0;
|
|
379
|
+
let backed = 0;
|
|
348
380
|
|
|
349
|
-
for (const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const destPath = path.join(targetSrcDir, entry.name);
|
|
353
|
-
|
|
354
|
-
if (fs.existsSync(destPath)) {
|
|
355
|
-
const overwrite = await promptYesNo(` ⚠️ "${entry.name}" already exists. Overwrite?`);
|
|
356
|
-
if (!overwrite) {
|
|
357
|
-
console.log(` ⏭️ Skipped ${entry.name}`);
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
381
|
+
for (const relFile of presetFiles) {
|
|
382
|
+
const srcPath = path.join(presetDir, relFile);
|
|
383
|
+
const destPath = path.join(destDir, relFile);
|
|
361
384
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
385
|
+
// Ensure subdirectory exists
|
|
386
|
+
const destFileDir = path.dirname(destPath);
|
|
387
|
+
if (!fs.existsSync(destFileDir)) {
|
|
388
|
+
fs.mkdirSync(destFileDir, { recursive: true });
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (fs.existsSync(destPath)) {
|
|
392
|
+
// Backup existing
|
|
393
|
+
const backupPath = destPath + '.bak';
|
|
394
|
+
fs.copyFileSync(destPath, backupPath);
|
|
395
|
+
backed++;
|
|
396
|
+
console.log(` 🔄 ${relFile} (backed up to ${relFile}.bak)`);
|
|
397
|
+
} else {
|
|
398
|
+
console.log(` ✅ ${relFile}`);
|
|
365
399
|
}
|
|
400
|
+
|
|
401
|
+
fs.copyFileSync(srcPath, destPath);
|
|
402
|
+
copied++;
|
|
366
403
|
}
|
|
367
404
|
|
|
368
|
-
console.log(`\n✅
|
|
405
|
+
console.log(`\n✅ Done: ${copied} file(s) copied to ${path.relative(process.cwd(), destDir)}/`);
|
|
406
|
+
if (backed > 0) {
|
|
407
|
+
console.log(` ${backed} existing file(s) backed up with .bak extension`);
|
|
408
|
+
}
|
|
409
|
+
console.log('');
|
|
369
410
|
}
|
|
370
411
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
412
|
+
/**
|
|
413
|
+
* Resolve a safe folder name: compName -> compName-jux -> compName-1, compName-2, ...
|
|
414
|
+
*/
|
|
415
|
+
function resolveDestFolderName(parentDir, baseName) {
|
|
416
|
+
const first = path.join(parentDir, baseName);
|
|
417
|
+
if (!fs.existsSync(first)) return baseName;
|
|
374
418
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
} catch (_) { }
|
|
419
|
+
const juxName = baseName + '-jux';
|
|
420
|
+
const second = path.join(parentDir, juxName);
|
|
421
|
+
if (!fs.existsSync(second)) return juxName;
|
|
422
|
+
|
|
423
|
+
for (let i = 1; i <= 99; i++) {
|
|
424
|
+
const numbered = `${baseName}-${i}`;
|
|
425
|
+
if (!fs.existsSync(path.join(parentDir, numbered))) return numbered;
|
|
383
426
|
}
|
|
384
427
|
|
|
385
|
-
|
|
428
|
+
// Last resort — timestamp
|
|
429
|
+
return `${baseName}-${Date.now()}`;
|
|
386
430
|
}
|
|
387
431
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const files = fs.readdirSync(presetDir).filter(f => !f.startsWith('.'));
|
|
395
|
-
console.log(` ${i + 1}) ${p} (${files.join(', ')})`);
|
|
396
|
-
});
|
|
397
|
-
console.log(` 0) Cancel\n`);
|
|
398
|
-
|
|
399
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
400
|
-
rl.question('Select a preset (number or name): ', (answer) => {
|
|
401
|
-
rl.close();
|
|
402
|
-
const trimmed = answer.trim();
|
|
403
|
-
|
|
404
|
-
// By number
|
|
405
|
-
const num = parseInt(trimmed, 10);
|
|
406
|
-
if (num === 0) return resolve(null);
|
|
407
|
-
if (num >= 1 && num <= presets.length) return resolve(presets[num - 1]);
|
|
408
|
-
|
|
409
|
-
// By name
|
|
410
|
-
if (presets.includes(trimmed)) return resolve(trimmed);
|
|
411
|
-
|
|
412
|
-
console.error(`❌ Invalid selection: "${trimmed}"`);
|
|
413
|
-
resolve(null);
|
|
414
|
-
});
|
|
415
|
-
});
|
|
416
|
-
}
|
|
432
|
+
/**
|
|
433
|
+
* List all files in a directory recursively, returning relative paths
|
|
434
|
+
*/
|
|
435
|
+
function listFilesRecursive(dir, base = '') {
|
|
436
|
+
const results = [];
|
|
437
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
417
438
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
}
|
|
425
|
-
|
|
439
|
+
for (const entry of entries) {
|
|
440
|
+
if (entry.name.startsWith('.')) continue;
|
|
441
|
+
const rel = base ? path.join(base, entry.name) : entry.name;
|
|
442
|
+
|
|
443
|
+
if (entry.isDirectory()) {
|
|
444
|
+
results.push(...listFilesRecursive(path.join(dir, entry.name), rel));
|
|
445
|
+
} else {
|
|
446
|
+
results.push(rel);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return results;
|
|
426
451
|
}
|
|
427
452
|
|
|
428
453
|
// ═══════════════════════════════════════════════════════════════
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "juxscript",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.369",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A JavaScript UX authorship platform",
|
|
6
6
|
"main": "./dist/lib/index.js",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
"dom-structure-map.json",
|
|
25
25
|
"bin",
|
|
26
26
|
"create",
|
|
27
|
+
"presets",
|
|
27
28
|
"machinery",
|
|
28
29
|
"juxconfig.example.js",
|
|
29
30
|
"README.md",
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import { jux, pageState } from 'juxscript';
|
|
2
|
+
|
|
3
|
+
var COLLAPSE_ICON_OPEN = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2"></rect><path d="M9 3v18"></path></svg>';
|
|
4
|
+
var COLLAPSE_ICON_CLOSED = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="transform:scaleX(-1)"><rect width="18" height="18" x="3" y="3" rx="2"></rect><path d="M9 3v18"></path></svg>';
|
|
5
|
+
|
|
6
|
+
export function juxSidebar(id, sections, options) {
|
|
7
|
+
options = options || {};
|
|
8
|
+
var _title = options.title || 'App';
|
|
9
|
+
var _logo = options.logo || _title.charAt(0).toUpperCase();
|
|
10
|
+
var _footer = options.footer || '';
|
|
11
|
+
var _width = options.width || '260px';
|
|
12
|
+
var _collapsedWidth = options.collapsedWidth || '52px';
|
|
13
|
+
var _target = options.target;
|
|
14
|
+
var _density = options.density || 'normal';
|
|
15
|
+
var _collapsible = options.collapsible !== undefined ? options.collapsible : false;
|
|
16
|
+
var _collapsed = options.collapsed || false;
|
|
17
|
+
var _sectionCount = 0;
|
|
18
|
+
var _rendered = false;
|
|
19
|
+
var _footerRendered = false;
|
|
20
|
+
|
|
21
|
+
var DENSITY = {
|
|
22
|
+
dense: { headerPad: '10px', itemPad: '4px 10px', labelPad: '6px 10px 2px', footerPad: '8px 12px', gap: '0px', fontSize: '12px', iconSize: '13px' },
|
|
23
|
+
normal: { headerPad: '16px', itemPad: '8px 12px', labelPad: '8px 12px 4px', footerPad: '12px 16px', gap: '1px', fontSize: '13px', iconSize: '15px' },
|
|
24
|
+
inflated: { headerPad: '20px', itemPad: '12px 16px', labelPad: '12px 16px 6px', footerPad: '16px 20px', gap: '4px', fontSize: '14px', iconSize: '17px' }
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function normalizeItem(item) {
|
|
28
|
+
if (typeof item === 'string') {
|
|
29
|
+
var path = item.startsWith('/') ? item : '/' + item;
|
|
30
|
+
var seg = path.split('/').filter(Boolean).pop() || 'Home';
|
|
31
|
+
return { id: id + '-' + seg.toLowerCase().replace(/[^a-z0-9]/g, '-'), label: seg.charAt(0).toUpperCase() + seg.slice(1), path: path };
|
|
32
|
+
}
|
|
33
|
+
// Support RouteInfo shape { path, name, file } from jux.routes.all()
|
|
34
|
+
var itemPath = item.path || '';
|
|
35
|
+
var seg = itemPath.split('/').filter(Boolean).pop() || 'home';
|
|
36
|
+
return {
|
|
37
|
+
id: item.id || id + '-' + seg.toLowerCase().replace(/[^a-z0-9]/g, '-'),
|
|
38
|
+
label: item.label || item.name || seg.charAt(0).toUpperCase() + seg.slice(1),
|
|
39
|
+
path: itemPath,
|
|
40
|
+
icon: item.icon
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizeSections(input) {
|
|
45
|
+
if (!input || !Array.isArray(input) || input.length === 0) return [];
|
|
46
|
+
var isFlat = input.every(function (i) { return typeof i === 'string' || (typeof i === 'object' && !i.items); });
|
|
47
|
+
if (isFlat) return [{ items: input.map(normalizeItem) }];
|
|
48
|
+
return input.map(function (s) {
|
|
49
|
+
if (typeof s === 'string') return { items: [normalizeItem(s)] };
|
|
50
|
+
return { label: s.label, items: (s.items || []).map(normalizeItem) };
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function ensureShell() {
|
|
55
|
+
if (_rendered) return;
|
|
56
|
+
_rendered = true;
|
|
57
|
+
injectStyles();
|
|
58
|
+
var sidebarClass = 'jux-sidebar jux-sidebar--' + _density;
|
|
59
|
+
if (_collapsed) sidebarClass += ' jux-sidebar--collapsed';
|
|
60
|
+
jux.div(id, { class: sidebarClass, style: 'width:' + (_collapsed ? _collapsedWidth : _width), target: _target });
|
|
61
|
+
jux.div(id + '-header', { class: 'jux-sidebar-header', target: id });
|
|
62
|
+
jux.div(id + '-logo', { class: 'jux-sidebar-logo', target: id + '-header' });
|
|
63
|
+
renderLogo();
|
|
64
|
+
jux.span(id + '-title', { class: 'jux-sidebar-title-text', content: _title, target: id + '-header' });
|
|
65
|
+
if (_collapsible) {
|
|
66
|
+
jux.div(id + '-collapse-btn', {
|
|
67
|
+
class: 'jux-sidebar-collapse-btn',
|
|
68
|
+
target: id + '-header'
|
|
69
|
+
});
|
|
70
|
+
var btnEl = document.getElementById(id + '-collapse-btn');
|
|
71
|
+
if (btnEl) btnEl.innerHTML = _collapsed ? COLLAPSE_ICON_CLOSED : COLLAPSE_ICON_OPEN;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function renderLogo() {
|
|
76
|
+
var logoEl = document.getElementById(id + '-logo');
|
|
77
|
+
if (!logoEl) return;
|
|
78
|
+
if (_logo.startsWith('<svg') || _logo.startsWith('<SVG')) {
|
|
79
|
+
logoEl.innerHTML = _logo;
|
|
80
|
+
} else if (_logo.startsWith('/') || _logo.startsWith('http') || _logo.startsWith('data:')) {
|
|
81
|
+
logoEl.innerHTML = '<img src="' + _logo + '" alt="logo" class="jux-sidebar-logo-img" />';
|
|
82
|
+
} else {
|
|
83
|
+
logoEl.textContent = _logo;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function renderSection(section) {
|
|
88
|
+
ensureShell();
|
|
89
|
+
var i = _sectionCount++;
|
|
90
|
+
if (i > 0) jux.div(id + '-divider-' + i, { class: 'jux-sidebar-divider', target: id });
|
|
91
|
+
if (section.label) jux.div(id + '-label-' + i, { class: 'jux-sidebar-label', content: section.label, target: id });
|
|
92
|
+
jux.nav(id + '-nav-' + i, { target: id, items: section.items });
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function renderFooter() {
|
|
96
|
+
if (_footerRendered || !_footer) return;
|
|
97
|
+
_footerRendered = true;
|
|
98
|
+
jux.div(id + '-footer', { class: 'jux-sidebar-footer', content: _footer, target: id });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function applyCollapsed(collapsed) {
|
|
102
|
+
_collapsed = collapsed;
|
|
103
|
+
var el = document.getElementById(id);
|
|
104
|
+
if (!el) return;
|
|
105
|
+
if (_collapsed) {
|
|
106
|
+
el.classList.add('jux-sidebar--collapsed');
|
|
107
|
+
el.style.width = _collapsedWidth;
|
|
108
|
+
} else {
|
|
109
|
+
el.classList.remove('jux-sidebar--collapsed');
|
|
110
|
+
el.style.width = _width;
|
|
111
|
+
}
|
|
112
|
+
if (_collapsible) {
|
|
113
|
+
var btnEl = document.getElementById(id + '-collapse-btn');
|
|
114
|
+
if (btnEl) btnEl.innerHTML = _collapsed ? COLLAPSE_ICON_CLOSED : COLLAPSE_ICON_OPEN;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function injectStyles() {
|
|
119
|
+
jux.style('menu-styles', '\
|
|
120
|
+
body { margin: 0; }\
|
|
121
|
+
.jux-sidebar { display:flex; flex-direction:column; min-height:100vh; background:hsl(var(--card)); color:hsl(var(--card-foreground)); border-right:1px solid hsl(var(--border)); font-family:var(--font-sans,system-ui,sans-serif); transition:width 0.2s ease; overflow:hidden; }\
|
|
122
|
+
.jux-sidebar-header { display:flex; align-items:center; gap:8px; font-size:14px; font-weight:600; border-bottom:1px solid hsl(var(--border)); min-height:20px; position:relative; }\
|
|
123
|
+
.jux-sidebar-logo { width:20px; height:20px; min-width:20px; border-radius:6px; background:hsl(var(--primary)); display:flex; align-items:center; justify-content:center; color:hsl(var(--primary-foreground)); font-size:11px; font-weight:700; flex-shrink:0; overflow:hidden; }\
|
|
124
|
+
.jux-sidebar-logo-img { width:100%; height:100%; object-fit:cover; border-radius:inherit; }\
|
|
125
|
+
.jux-sidebar-logo svg { width:14px; height:14px; }\
|
|
126
|
+
.jux-sidebar-title-text { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; transition:opacity 0.2s ease, max-width 0.2s ease; max-width:200px; flex:1; }\
|
|
127
|
+
.jux-sidebar-label { font-size:11px; font-weight:500; color:hsl(var(--muted-foreground)); text-transform:uppercase; letter-spacing:0.05em; white-space:nowrap; overflow:hidden; transition:opacity 0.2s ease, max-height 0.2s ease; max-height:30px; }\
|
|
128
|
+
.jux-sidebar-footer { margin-top:auto; border-top:1px solid hsl(var(--border)); font-size:11px; color:hsl(var(--muted-foreground)); white-space:nowrap; overflow:hidden; transition:opacity 0.2s ease; }\
|
|
129
|
+
.jux-sidebar-divider { height:1px; background:hsl(var(--border)); margin:4px 8px; }\
|
|
130
|
+
.jux-nav-item { display:flex; align-items:center; border-radius:var(--radius,6px); font-weight:500; color:hsl(var(--foreground)); cursor:pointer; transition:background 0.15s; user-select:none; text-decoration:none; white-space:nowrap; overflow:hidden; }\
|
|
131
|
+
.jux-nav-item:hover { background:hsl(var(--accent)); color:hsl(var(--accent-foreground)); }\
|
|
132
|
+
.jux-nav-item--active { background:hsl(var(--accent)); color:hsl(var(--accent-foreground)); font-weight:600; }\
|
|
133
|
+
.jux-nav-item-icon { text-align:center; flex-shrink:0; }\
|
|
134
|
+
.jux-nav-item-text { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; transition:opacity 0.2s ease; }\
|
|
135
|
+
\
|
|
136
|
+
.jux-sidebar-collapse-btn { width:28px; height:28px; display:flex; align-items:center; justify-content:center; cursor:pointer; border-radius:6px; color:hsl(var(--muted-foreground)); flex-shrink:0; transition:background 0.15s, color 0.15s; margin-left:auto; }\
|
|
137
|
+
.jux-sidebar-collapse-btn:hover { background:hsl(var(--accent)); color:hsl(var(--accent-foreground)); }\
|
|
138
|
+
.jux-sidebar-collapse-btn svg { display:block; }\
|
|
139
|
+
\
|
|
140
|
+
.jux-sidebar--collapsed .jux-sidebar-header { flex-direction:column; align-items:center; gap:4px; padding-left:4px!important; padding-right:4px!important; }\
|
|
141
|
+
.jux-sidebar--collapsed .jux-sidebar-title-text { opacity:0; max-width:0; height:0; overflow:hidden; margin:0; }\
|
|
142
|
+
.jux-sidebar--collapsed .jux-sidebar-label { opacity:0; max-height:0; padding-top:0!important; padding-bottom:0!important; margin:0; }\
|
|
143
|
+
.jux-sidebar--collapsed .jux-sidebar-footer { opacity:0; height:0; padding:0!important; border:none; }\
|
|
144
|
+
.jux-sidebar--collapsed .jux-nav-item-text { opacity:0; width:0; overflow:hidden; }\
|
|
145
|
+
.jux-sidebar--collapsed .jux-nav-item { justify-content:center; gap:0!important; }\
|
|
146
|
+
.jux-sidebar--collapsed .jux-sidebar-collapse-btn { margin-left:0; width:24px; height:24px; }\
|
|
147
|
+
.jux-sidebar--collapsed .jux-sidebar-collapse-btn svg { width:14px; height:14px; }\
|
|
148
|
+
.jux-sidebar--collapsed .jux-sidebar-logo { margin:0; }\
|
|
149
|
+
\
|
|
150
|
+
.jux-sidebar--dense .jux-sidebar-header { padding:' + DENSITY.dense.headerPad + '; }\
|
|
151
|
+
.jux-sidebar--dense .jux-sidebar-label { padding:' + DENSITY.dense.labelPad + '; }\
|
|
152
|
+
.jux-sidebar--dense .jux-sidebar-footer { padding:' + DENSITY.dense.footerPad + '; }\
|
|
153
|
+
.jux-sidebar--dense .jux-nav-item { padding:' + DENSITY.dense.itemPad + '; margin:' + DENSITY.dense.gap + ' 0; font-size:' + DENSITY.dense.fontSize + '; gap:8px; }\
|
|
154
|
+
.jux-sidebar--dense .jux-nav-item-icon { width:16px; font-size:' + DENSITY.dense.iconSize + '; }\
|
|
155
|
+
\
|
|
156
|
+
.jux-sidebar--normal .jux-sidebar-header { padding:' + DENSITY.normal.headerPad + '; }\
|
|
157
|
+
.jux-sidebar--normal .jux-sidebar-label { padding:' + DENSITY.normal.labelPad + '; }\
|
|
158
|
+
.jux-sidebar--normal .jux-sidebar-footer { padding:' + DENSITY.normal.footerPad + '; }\
|
|
159
|
+
.jux-sidebar--normal .jux-nav-item { padding:' + DENSITY.normal.itemPad + '; margin:' + DENSITY.normal.gap + ' 0; font-size:' + DENSITY.normal.fontSize + '; gap:10px; }\
|
|
160
|
+
.jux-sidebar--normal .jux-nav-item-icon { width:18px; font-size:' + DENSITY.normal.iconSize + '; }\
|
|
161
|
+
\
|
|
162
|
+
.jux-sidebar--inflated .jux-sidebar-header { padding:' + DENSITY.inflated.headerPad + '; }\
|
|
163
|
+
.jux-sidebar--inflated .jux-sidebar-label { padding:' + DENSITY.inflated.labelPad + '; }\
|
|
164
|
+
.jux-sidebar--inflated .jux-sidebar-footer { padding:' + DENSITY.inflated.footerPad + '; }\
|
|
165
|
+
.jux-sidebar--inflated .jux-nav-item { padding:' + DENSITY.inflated.itemPad + '; margin:' + DENSITY.inflated.gap + ' 0; font-size:' + DENSITY.inflated.fontSize + '; gap:12px; }\
|
|
166
|
+
.jux-sidebar--inflated .jux-nav-item-icon { width:20px; font-size:' + DENSITY.inflated.iconSize + '; }\
|
|
167
|
+
');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
var api = {
|
|
171
|
+
id: id,
|
|
172
|
+
title: function (val) { _title = val; return api; },
|
|
173
|
+
logo: function (val) { _logo = val; return api; },
|
|
174
|
+
footer: function (val) {
|
|
175
|
+
_footer = val;
|
|
176
|
+
if (_rendered) renderFooter();
|
|
177
|
+
return api;
|
|
178
|
+
},
|
|
179
|
+
width: function (val) { _width = val; return api; },
|
|
180
|
+
collapsedWidth: function (val) { _collapsedWidth = val; return api; },
|
|
181
|
+
target: function (val) { _target = val; return api; },
|
|
182
|
+
density: function (val) { _density = val; return api; },
|
|
183
|
+
collapsible: function (val) { _collapsible = val !== undefined ? val : true; return api; },
|
|
184
|
+
|
|
185
|
+
section: function (label, items) {
|
|
186
|
+
renderSection({ label: label, items: (items || []).map(normalizeItem) });
|
|
187
|
+
return api;
|
|
188
|
+
},
|
|
189
|
+
|
|
190
|
+
items: function (items) {
|
|
191
|
+
renderSection({ items: (items || []).map(normalizeItem) });
|
|
192
|
+
return api;
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
render: function () {
|
|
196
|
+
ensureShell();
|
|
197
|
+
renderFooter();
|
|
198
|
+
if (_collapsible) {
|
|
199
|
+
pageState.__watch(function () {
|
|
200
|
+
if (pageState[id + '-collapse-btn'].click) {
|
|
201
|
+
api.toggleCollapse();
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return api;
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
addSection: function (label, items) { return api.section(label, items); },
|
|
209
|
+
setTitle: function (val) { pageState[id + '-title'].content = val; return api; },
|
|
210
|
+
setFooter: function (val) { pageState[id + '-footer'].content = val; return api; },
|
|
211
|
+
show: function () { pageState[id].visible = true; return api; },
|
|
212
|
+
hide: function () { pageState[id].visible = false; return api; },
|
|
213
|
+
toggle: function () { pageState[id].visible = !pageState[id].visible; return api; },
|
|
214
|
+
collapse: function () { applyCollapsed(true); return api; },
|
|
215
|
+
expand: function () { applyCollapsed(false); return api; },
|
|
216
|
+
toggleCollapse: function () { applyCollapsed(!_collapsed); return api; },
|
|
217
|
+
isCollapsed: function () { return _collapsed; },
|
|
218
|
+
getElement: function () { return document.getElementById(id); }
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
if (sections && Array.isArray(sections) && sections.length > 0) {
|
|
222
|
+
var normalized = normalizeSections(sections);
|
|
223
|
+
normalized.forEach(renderSection);
|
|
224
|
+
renderFooter();
|
|
225
|
+
if (_collapsible) {
|
|
226
|
+
pageState.__watch(function () {
|
|
227
|
+
if (pageState[id + '-collapse-btn'].click) {
|
|
228
|
+
api.toggleCollapse();
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return api;
|
|
235
|
+
}
|