juxscript 1.1.398 → 1.1.399
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/README.md +428 -200
- package/bin/cli.js +2 -212
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/shapes/flex.d.ts +49 -0
- package/dist/shapes/flex.d.ts.map +1 -0
- package/dist/shapes/flex.js +122 -0
- package/dist/shapes/flex.js.map +1 -0
- package/dist/widgets/calendar.d.ts +74 -0
- package/dist/widgets/calendar.d.ts.map +1 -0
- package/dist/widgets/calendar.js +308 -0
- package/dist/widgets/calendar.js.map +1 -0
- package/dist/widgets/sidebar.d.ts +90 -0
- package/dist/widgets/sidebar.d.ts.map +1 -0
- package/dist/widgets/sidebar.js +353 -0
- package/dist/widgets/sidebar.js.map +1 -0
- package/package.json +3 -2
- package/components/calendar/calendar-usage.jux +0 -0
- package/components/calendar/calendar.jux +0 -0
- package/components/sidebar/index.jux +0 -272
- package/components/sidebar/usage.jux +0 -7
|
@@ -1,272 +0,0 @@
|
|
|
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 + '-' + path.replace(/^\//, '').replace(/[^a-z0-9]/gi, '-').toLowerCase() || id + '-home', 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
|
-
var fullSlug = itemPath.replace(/^\//, '').replace(/[^a-z0-9]/gi, '-').toLowerCase() || 'home';
|
|
37
|
-
return {
|
|
38
|
-
id: item.id || id + '-' + fullSlug,
|
|
39
|
-
label: item.label || item.name || seg.charAt(0).toUpperCase() + seg.slice(1),
|
|
40
|
-
path: itemPath,
|
|
41
|
-
icon: item.icon
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function normalizeSections(input) {
|
|
46
|
-
if (!input || !Array.isArray(input) || input.length === 0) return [];
|
|
47
|
-
var isFlat = input.every(function (i) { return typeof i === 'string' || (typeof i === 'object' && !i.items); });
|
|
48
|
-
if (isFlat) return [{ items: input.map(normalizeItem) }];
|
|
49
|
-
return input.map(function (s) {
|
|
50
|
-
if (typeof s === 'string') return { items: [normalizeItem(s)] };
|
|
51
|
-
return { label: s.label, items: (s.items || []).map(normalizeItem) };
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function ensureShell() {
|
|
56
|
-
if (_rendered) return;
|
|
57
|
-
_rendered = true;
|
|
58
|
-
injectStyles();
|
|
59
|
-
var sidebarClass = 'jux-sidebar jux-sidebar--' + _density;
|
|
60
|
-
if (_collapsed) sidebarClass += ' jux-sidebar--collapsed';
|
|
61
|
-
|
|
62
|
-
// If the target container already has our ID, reuse it instead of nesting
|
|
63
|
-
var existingEl = document.getElementById(id);
|
|
64
|
-
if (_target === id && existingEl) {
|
|
65
|
-
existingEl.className = sidebarClass;
|
|
66
|
-
existingEl.style.width = _collapsed ? _collapsedWidth : _width;
|
|
67
|
-
} else {
|
|
68
|
-
jux.div(id, { class: sidebarClass, style: 'width:' + (_collapsed ? _collapsedWidth : _width), target: _target });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
jux.div(id + '-header', { class: 'jux-sidebar-header', target: id });
|
|
72
|
-
jux.div(id + '-header-link', { class: 'jux-sidebar-header-link', target: id + '-header' });
|
|
73
|
-
jux.div(id + '-logo', { class: 'jux-sidebar-logo', target: id + '-header-link' });
|
|
74
|
-
renderLogo();
|
|
75
|
-
jux.span(id + '-title', { class: 'jux-sidebar-title-text', content: _title, target: id + '-header-link' });
|
|
76
|
-
|
|
77
|
-
// Make header link navigate to root
|
|
78
|
-
var headerLinkEl = document.getElementById(id + '-header-link');
|
|
79
|
-
if (headerLinkEl) {
|
|
80
|
-
headerLinkEl.addEventListener('click', function () {
|
|
81
|
-
if (window.navigateTo) {
|
|
82
|
-
window.navigateTo('/');
|
|
83
|
-
} else {
|
|
84
|
-
window.location.href = '/';
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (_collapsible) {
|
|
90
|
-
jux.div(id + '-collapse-btn', {
|
|
91
|
-
class: 'jux-sidebar-collapse-btn',
|
|
92
|
-
target: id + '-header'
|
|
93
|
-
});
|
|
94
|
-
var btnEl = document.getElementById(id + '-collapse-btn');
|
|
95
|
-
if (btnEl) btnEl.innerHTML = _collapsed ? COLLAPSE_ICON_CLOSED : COLLAPSE_ICON_OPEN;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function renderLogo() {
|
|
100
|
-
var logoEl = document.getElementById(id + '-logo');
|
|
101
|
-
if (!logoEl) return;
|
|
102
|
-
if (_logo.startsWith('<svg') || _logo.startsWith('<SVG')) {
|
|
103
|
-
logoEl.innerHTML = _logo;
|
|
104
|
-
} else if (_logo.startsWith('/') || _logo.startsWith('http') || _logo.startsWith('data:')) {
|
|
105
|
-
logoEl.innerHTML = '<img src="' + _logo + '" alt="logo" class="jux-sidebar-logo-img" />';
|
|
106
|
-
} else {
|
|
107
|
-
logoEl.textContent = _logo;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function renderSection(section) {
|
|
112
|
-
ensureShell();
|
|
113
|
-
var i = _sectionCount++;
|
|
114
|
-
if (i > 0) jux.div(id + '-divider-' + i, { class: 'jux-sidebar-divider', target: id });
|
|
115
|
-
if (section.label) jux.div(id + '-label-' + i, { class: 'jux-sidebar-label', content: section.label, target: id });
|
|
116
|
-
jux.nav(id + '-nav-' + i, { target: id, items: section.items });
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
function renderFooter() {
|
|
120
|
-
if (_footerRendered || !_footer) return;
|
|
121
|
-
_footerRendered = true;
|
|
122
|
-
jux.div(id + '-footer', { class: 'jux-sidebar-footer', content: _footer, target: id });
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function applyCollapsed(collapsed) {
|
|
126
|
-
_collapsed = collapsed;
|
|
127
|
-
var el = document.getElementById(id);
|
|
128
|
-
if (!el) return;
|
|
129
|
-
if (_collapsed) {
|
|
130
|
-
el.classList.add('jux-sidebar--collapsed');
|
|
131
|
-
el.style.width = _collapsedWidth;
|
|
132
|
-
} else {
|
|
133
|
-
el.classList.remove('jux-sidebar--collapsed');
|
|
134
|
-
el.style.width = _width;
|
|
135
|
-
}
|
|
136
|
-
if (_collapsible) {
|
|
137
|
-
var btnEl = document.getElementById(id + '-collapse-btn');
|
|
138
|
-
if (btnEl) btnEl.innerHTML = _collapsed ? COLLAPSE_ICON_CLOSED : COLLAPSE_ICON_OPEN;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function injectStyles() {
|
|
143
|
-
var appPadding = {
|
|
144
|
-
dense: '10px',
|
|
145
|
-
normal: '16px',
|
|
146
|
-
inflated: '24px'
|
|
147
|
-
};
|
|
148
|
-
var currentWidth = _collapsed ? _collapsedWidth : _width;
|
|
149
|
-
jux.style('sidebar-styles', '\
|
|
150
|
-
body { margin: 0; }\
|
|
151
|
-
#app { left: '+ currentWidth + '; position: fixed; top: 0; width: calc(100% - ' + currentWidth + '); height: 100vh; padding: ' + appPadding[_density] + '; box-sizing: border-box; transition: left 0.2s ease, width 0.2s ease, padding 0.2s ease; overflow-y: auto; }\
|
|
152
|
-
.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; }\
|
|
153
|
-
.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; }\
|
|
154
|
-
.jux-sidebar-header-link { display:flex; align-items:center; gap:8px; cursor:pointer; flex:1; min-width:0; text-decoration:none; color:inherit; }\
|
|
155
|
-
.jux-sidebar-header-link:hover { opacity:0.8; }\
|
|
156
|
-
.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; }\
|
|
157
|
-
.jux-sidebar-logo-img { width:100%; height:100%; object-fit:cover; border-radius:inherit; }\
|
|
158
|
-
.jux-sidebar-logo svg { width:14px; height:14px; }\
|
|
159
|
-
.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; }\
|
|
160
|
-
.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; }\
|
|
161
|
-
.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; }\
|
|
162
|
-
.jux-sidebar-divider { height:1px; background:hsl(var(--border)); margin:4px 8px; }\
|
|
163
|
-
.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; }\
|
|
164
|
-
.jux-nav-item:hover { background:hsl(var(--accent)); color:hsl(var(--accent-foreground)); }\
|
|
165
|
-
.jux-nav-item--active { background:hsl(var(--accent)); color:hsl(var(--accent-foreground)); font-weight:600; }\
|
|
166
|
-
.jux-nav-item-icon { text-align:center; flex-shrink:0; }\
|
|
167
|
-
.jux-nav-item-text { white-space:nowrap; overflow:hidden; text-overflow:ellipsis; transition:opacity 0.2s ease; }\
|
|
168
|
-
\
|
|
169
|
-
.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; }\
|
|
170
|
-
.jux-sidebar-collapse-btn:hover { background:hsl(var(--accent)); color:hsl(var(--accent-foreground)); }\
|
|
171
|
-
.jux-sidebar-collapse-btn svg { display:block; }\
|
|
172
|
-
\
|
|
173
|
-
.jux-sidebar--collapsed .jux-sidebar-header { flex-direction:column; align-items:center; gap:4px; padding-left:4px!important; padding-right:4px!important; }\
|
|
174
|
-
.jux-sidebar--collapsed .jux-sidebar-title-text { opacity:0; max-width:0; height:0; overflow:hidden; margin:0; }\
|
|
175
|
-
.jux-sidebar--collapsed .jux-sidebar-label { opacity:0; max-height:0; padding-top:0!important; padding-bottom:0!important; margin:0; }\
|
|
176
|
-
.jux-sidebar--collapsed .jux-sidebar-footer { opacity:0; height:0; padding:0!important; border:none; }\
|
|
177
|
-
.jux-sidebar--collapsed .jux-nav-item-text { opacity:0; width:0; overflow:hidden; }\
|
|
178
|
-
.jux-sidebar--collapsed .jux-nav-item { justify-content:center; gap:0!important; }\
|
|
179
|
-
.jux-sidebar--collapsed .jux-sidebar-collapse-btn { margin-left:0; width:24px; height:24px; }\
|
|
180
|
-
.jux-sidebar--collapsed .jux-sidebar-collapse-btn svg { width:14px; height:14px; }\
|
|
181
|
-
.jux-sidebar--collapsed .jux-sidebar-logo { margin:0; }\
|
|
182
|
-
.jux-sidebar--collapsed ~ #app, .jux-sidebar--collapsed + #app { left: ' + _collapsedWidth + '; width: calc(100% - ' + _collapsedWidth + '); }\
|
|
183
|
-
\
|
|
184
|
-
.jux-sidebar--dense .jux-sidebar-header { padding:' + DENSITY.dense.headerPad + '; }\
|
|
185
|
-
.jux-sidebar--dense .jux-sidebar-label { padding:' + DENSITY.dense.labelPad + '; }\
|
|
186
|
-
.jux-sidebar--dense .jux-sidebar-footer { padding:' + DENSITY.dense.footerPad + '; }\
|
|
187
|
-
.jux-sidebar--dense .jux-nav-item { padding:' + DENSITY.dense.itemPad + '; margin:' + DENSITY.dense.gap + ' 0; font-size:' + DENSITY.dense.fontSize + '; gap:8px; }\
|
|
188
|
-
.jux-sidebar--dense .jux-nav-item-icon { width:16px; font-size:' + DENSITY.dense.iconSize + '; }\
|
|
189
|
-
.jux-sidebar--dense ~ #app, .jux-sidebar--dense + #app { padding: ' + appPadding.dense + '; }\
|
|
190
|
-
\
|
|
191
|
-
.jux-sidebar--normal .jux-sidebar-header { padding:' + DENSITY.normal.headerPad + '; }\
|
|
192
|
-
.jux-sidebar--normal .jux-sidebar-label { padding:' + DENSITY.normal.labelPad + '; }\
|
|
193
|
-
.jux-sidebar--normal .jux-sidebar-footer { padding:' + DENSITY.normal.footerPad + '; }\
|
|
194
|
-
.jux-sidebar--normal .jux-nav-item { padding:' + DENSITY.normal.itemPad + '; margin:' + DENSITY.normal.gap + ' 0; font-size:' + DENSITY.normal.fontSize + '; gap:10px; }\
|
|
195
|
-
.jux-sidebar--normal .jux-nav-item-icon { width:18px; font-size:' + DENSITY.normal.iconSize + '; }\
|
|
196
|
-
.jux-sidebar--normal ~ #app, .jux-sidebar--normal + #app { padding: ' + appPadding.normal + '; }\
|
|
197
|
-
\
|
|
198
|
-
.jux-sidebar--inflated .jux-sidebar-header { padding:' + DENSITY.inflated.headerPad + '; }\
|
|
199
|
-
.jux-sidebar--inflated .jux-sidebar-label { padding:' + DENSITY.inflated.labelPad + '; }\
|
|
200
|
-
.jux-sidebar--inflated .jux-sidebar-footer { padding:' + DENSITY.inflated.footerPad + '; }\
|
|
201
|
-
.jux-sidebar--inflated .jux-nav-item { padding:' + DENSITY.inflated.itemPad + '; margin:' + DENSITY.inflated.gap + ' 0; font-size:' + DENSITY.inflated.fontSize + '; gap:12px; }\
|
|
202
|
-
.jux-sidebar--inflated .jux-nav-item-icon { width:20px; font-size:' + DENSITY.inflated.iconSize + '; }\
|
|
203
|
-
.jux-sidebar--inflated ~ #app, .jux-sidebar--inflated + #app { padding: ' + appPadding.inflated + '; }\
|
|
204
|
-
');
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
var api = {
|
|
208
|
-
id: id,
|
|
209
|
-
title: function (val) { _title = val; return api; },
|
|
210
|
-
logo: function (val) { _logo = val; return api; },
|
|
211
|
-
footer: function (val) {
|
|
212
|
-
_footer = val;
|
|
213
|
-
if (_rendered) renderFooter();
|
|
214
|
-
return api;
|
|
215
|
-
},
|
|
216
|
-
width: function (val) { _width = val; return api; },
|
|
217
|
-
collapsedWidth: function (val) { _collapsedWidth = val; return api; },
|
|
218
|
-
target: function (val) { _target = val; return api; },
|
|
219
|
-
density: function (val) { _density = val; return api; },
|
|
220
|
-
collapsible: function (val) { _collapsible = val !== undefined ? val : true; return api; },
|
|
221
|
-
|
|
222
|
-
section: function (label, items) {
|
|
223
|
-
renderSection({ label: label, items: (items || []).map(normalizeItem) });
|
|
224
|
-
return api;
|
|
225
|
-
},
|
|
226
|
-
|
|
227
|
-
items: function (items) {
|
|
228
|
-
renderSection({ items: (items || []).map(normalizeItem) });
|
|
229
|
-
return api;
|
|
230
|
-
},
|
|
231
|
-
|
|
232
|
-
render: function () {
|
|
233
|
-
ensureShell();
|
|
234
|
-
renderFooter();
|
|
235
|
-
if (_collapsible) {
|
|
236
|
-
pageState.__watch(function () {
|
|
237
|
-
if (pageState[id + '-collapse-btn'].click) {
|
|
238
|
-
api.toggleCollapse();
|
|
239
|
-
}
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
return api;
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
addSection: function (label, items) { return api.section(label, items); },
|
|
246
|
-
setTitle: function (val) { pageState[id + '-title'].content = val; return api; },
|
|
247
|
-
setFooter: function (val) { pageState[id + '-footer'].content = val; return api; },
|
|
248
|
-
show: function () { pageState[id].visible = true; return api; },
|
|
249
|
-
hide: function () { pageState[id].visible = false; return api; },
|
|
250
|
-
toggle: function () { pageState[id].visible = !pageState[id].visible; return api; },
|
|
251
|
-
collapse: function () { applyCollapsed(true); return api; },
|
|
252
|
-
expand: function () { applyCollapsed(false); return api; },
|
|
253
|
-
toggleCollapse: function () { applyCollapsed(!_collapsed); return api; },
|
|
254
|
-
isCollapsed: function () { return _collapsed; },
|
|
255
|
-
getElement: function () { return document.getElementById(id); }
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
if (sections && Array.isArray(sections) && sections.length > 0) {
|
|
259
|
-
var normalized = normalizeSections(sections);
|
|
260
|
-
normalized.forEach(renderSection);
|
|
261
|
-
renderFooter();
|
|
262
|
-
if (_collapsible) {
|
|
263
|
-
pageState.__watch(function () {
|
|
264
|
-
if (pageState[id + '-collapse-btn'].click) {
|
|
265
|
-
api.toggleCollapse();
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
return api;
|
|
272
|
-
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { jux } from 'juxscript';
|
|
2
|
-
import { juxSidebar } from './index.jux';
|
|
3
|
-
const allRoutes = jux.routes.all();
|
|
4
|
-
// ['/route/path', '/another/route']
|
|
5
|
-
juxSidebar('my-sidebar', allRoutes,
|
|
6
|
-
{ title: 'Simple App', logo: 'J', footer: 'v1.0', density: 'inflated', collapsible: true });
|
|
7
|
-
|