@salla.sa/twilight-bundles 0.1.1
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 +90 -0
- package/bin/tw-component.js +273 -0
- package/dist/twilight-bundles.cjs +23 -0
- package/dist/twilight-bundles.js +707 -0
- package/dist/vite-plugins/build.cjs +1 -0
- package/dist/vite-plugins/build.js +46 -0
- package/dist/vite-plugins/demo.cjs +1560 -0
- package/dist/vite-plugins/demo.js +1678 -0
- package/dist/vite-plugins/index.cjs +1 -0
- package/dist/vite-plugins/index.js +8 -0
- package/dist/vite-plugins/transform.cjs +2 -0
- package/dist/vite-plugins/transform.js +22 -0
- package/package.json +62 -0
- package/scripts/dev.js +63 -0
- package/scripts/preinstall.js +5 -0
- package/src/components/salla-base-component.ts +25 -0
- package/src/components/salla-custom-component.ts +12 -0
- package/src/helpers/helpers.ts +65 -0
- package/src/index.ts +127 -0
- package/src/vite-plugins/build.ts +68 -0
- package/src/vite-plugins/demo/index.ts +161 -0
- package/src/vite-plugins/demo/template.ts +1620 -0
- package/src/vite-plugins/transform.ts +32 -0
- package/tsconfig.json +26 -0
- package/types/global.d.ts +18 -0
- package/types/vite-plugin.d.ts +34 -0
- package/vite-plugins.d.ts +13 -0
- package/vite-plugins.ts +14 -0
- package/vite.config.ts +49 -0
|
@@ -0,0 +1,1678 @@
|
|
|
1
|
+
import { findComponentFiles as I } from "./build.js";
|
|
2
|
+
import * as a from "fs";
|
|
3
|
+
import * as c from "path";
|
|
4
|
+
const L = process.env.TWILIGHT_BUNDLES_URL || "https://cdn.salla.network/js/twilight-bundles/latest/twilight-bundles.js";
|
|
5
|
+
let i = process.env.TWILIGHT_FORM_BUILDER_MOCK_BASE_URL || "https://salla.design";
|
|
6
|
+
i = i.replace(/\/$/, "") + "/api/v1/form-builder-mock";
|
|
7
|
+
function G(t, e) {
|
|
8
|
+
var s, l;
|
|
9
|
+
const o = {
|
|
10
|
+
ar: {
|
|
11
|
+
toggleTheme: "تغيير المظهر",
|
|
12
|
+
toggleLang: "English",
|
|
13
|
+
dir: "rtl",
|
|
14
|
+
lang: "ar",
|
|
15
|
+
title: "حزم العناصر",
|
|
16
|
+
noSettings: "لا توجد إعدادات لهذا العنصر",
|
|
17
|
+
addSettings: "إضافة إعدادات لهذا العنصر",
|
|
18
|
+
saveSettings: "حفظ التغييرات"
|
|
19
|
+
},
|
|
20
|
+
en: {
|
|
21
|
+
toggleTheme: "Toggle Theme",
|
|
22
|
+
toggleLang: "Arabic",
|
|
23
|
+
dir: "ltr",
|
|
24
|
+
lang: "en",
|
|
25
|
+
title: "Twilight Bundles",
|
|
26
|
+
noSettings: "No settings for this component",
|
|
27
|
+
addSettings: "Add settings for this component",
|
|
28
|
+
saveSettings: "Save changes"
|
|
29
|
+
}
|
|
30
|
+
}, r = [
|
|
31
|
+
"https://cdn.assets.salla.network/prod/admin/cp/assets/css/icons/sallaicons/style.css?v0.21-languages2",
|
|
32
|
+
"https://cdn.assets.salla.network/prod/admin/vendor/form-builder/form-builder.a58a1e74d158c6a9cd3aeffe2feb6674.css",
|
|
33
|
+
"https://cdn.assets.salla.network/prod/admin/vendor/theme-dashboard/form-builder-theme.198b7a49c2f8cc9bae22de21569b1f42.css"
|
|
34
|
+
];
|
|
35
|
+
return `<!DOCTYPE html>
|
|
36
|
+
<html lang="ar" dir="rtl">
|
|
37
|
+
<head>
|
|
38
|
+
<meta charset="UTF-8">
|
|
39
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
40
|
+
<title>${o.ar.title}</title>
|
|
41
|
+
<script>
|
|
42
|
+
localStorage.setItem('FormBuilder::debugger', 1);
|
|
43
|
+
window.customComponents = ${JSON.stringify(t.map((n) => n.url))};
|
|
44
|
+
window.customComponentsSchema = ${JSON.stringify(Object.fromEntries(t.map((n) => [n.name, n.schema])))};
|
|
45
|
+
function schemaForComponent(componentName){
|
|
46
|
+
if(localStorage.getItem('form-builder::'+componentName)){
|
|
47
|
+
return htmlSafeString(localStorage.getItem('form-builder::'+componentName));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return htmlSafeString(window.customComponentsSchema[componentName]);
|
|
51
|
+
}
|
|
52
|
+
function getComponentData(componentName){
|
|
53
|
+
return htmlSafeString(localStorage.getItem('form-builder::data_' + componentName));
|
|
54
|
+
}
|
|
55
|
+
function htmlSafeString(str) {
|
|
56
|
+
return str?.replace(/&/g, '&')
|
|
57
|
+
.replace(/</g, '<')
|
|
58
|
+
.replace(/>/g, '>')
|
|
59
|
+
.replace(/"/g, '"')
|
|
60
|
+
.replace(/'/g, ''')||'';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function renderComponent(componentName, existingComponent){
|
|
64
|
+
if(Salla.storage.get('hidden-salla-components', []).includes(componentName)){
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const tempDom = document.createElement('div');
|
|
68
|
+
const config = getComponentData(componentName);
|
|
69
|
+
tempDom.innerHTML=\`<div class="component-card" data-component="\${componentName}">
|
|
70
|
+
<div class="component-card-header">
|
|
71
|
+
<h2>
|
|
72
|
+
<i class="sicon-tag"></i>
|
|
73
|
+
\${componentName}
|
|
74
|
+
</h2>
|
|
75
|
+
<div class="component-card-actions">
|
|
76
|
+
<button class="component-visibility-btn" aria-label="Toggle visibility"
|
|
77
|
+
onclick="hideComponent('\${componentName}')"
|
|
78
|
+
title="Hide component">
|
|
79
|
+
<i class="sicon-eye"></i>
|
|
80
|
+
</button>
|
|
81
|
+
<button class="component-settings-btn" aria-label="Open settings"
|
|
82
|
+
data-component="\${componentName}"
|
|
83
|
+
data-schema="\${config}">
|
|
84
|
+
<i class="sicon-settings"></i>
|
|
85
|
+
</button>
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
<salla-custom-component \${config?'config="'+config+'"':''} component-name="\${componentName}"></salla-custom-component>
|
|
89
|
+
</div>
|
|
90
|
+
</div>\`;
|
|
91
|
+
tempDom.querySelector('.component-settings-btn').addEventListener('click', () => openDrawer(componentName));
|
|
92
|
+
const grid = document.getElementById('componentsGrid');
|
|
93
|
+
existingComponent
|
|
94
|
+
? grid.insertBefore(tempDom.firstElementChild, existingComponent.nextSibling)
|
|
95
|
+
: grid.appendChild(tempDom.firstElementChild);
|
|
96
|
+
tempDom.remove();
|
|
97
|
+
}
|
|
98
|
+
function reRenderComponent(componentName){
|
|
99
|
+
const existingComponent = document.querySelector('.component-card[data-component="' + componentName + '"]');
|
|
100
|
+
renderComponent(componentName, existingComponent);
|
|
101
|
+
existingComponent.remove();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
// Save component visibility to localStorage
|
|
106
|
+
function hideComponent(componentName) {
|
|
107
|
+
const hiddenComponents = Salla.storage.get('hidden-salla-components', []);
|
|
108
|
+
if(!hiddenComponents?.includes(componentName)){
|
|
109
|
+
hiddenComponents.push(componentName);
|
|
110
|
+
}
|
|
111
|
+
Salla.storage.set('hidden-salla-components', hiddenComponents);
|
|
112
|
+
document.querySelector('.component-card[data-component="' + componentName + '"]')?.remove();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function showComponent(componentName) {
|
|
116
|
+
let hiddenComponents = Salla.storage.get('hidden-salla-components', []);
|
|
117
|
+
if(hiddenComponents.includes(componentName)){
|
|
118
|
+
hiddenComponents = hiddenComponents.filter(component => component !== componentName);
|
|
119
|
+
}
|
|
120
|
+
Salla.storage.set('hidden-salla-components', hiddenComponents);
|
|
121
|
+
renderComponent(componentName);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function toggleComponentVisibility(element) {
|
|
125
|
+
const componentName = element.value;
|
|
126
|
+
element.checked = Salla.storage.get('hidden-salla-components', []).includes(componentName);
|
|
127
|
+
element.checked ?showComponent(componentName) : hideComponent(componentName);
|
|
128
|
+
}
|
|
129
|
+
// Get the updated gap value from localStorage
|
|
130
|
+
function getSavedGrid() {
|
|
131
|
+
return Salla.storage.get('salla_demo_grid', {
|
|
132
|
+
columns: '${e.grid.columns}',
|
|
133
|
+
gap: '${e.grid.gap}',
|
|
134
|
+
minWidth: '${e.grid.minWidth}'
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
function getSavedLanguages(){
|
|
138
|
+
return Salla.storage.get('salla_demo_formbuilder', {
|
|
139
|
+
languages: ${JSON.stringify(e.formbuilder.languages)},
|
|
140
|
+
defaultLanguage: ${JSON.stringify(e.formbuilder.defaultLanguage)}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// ==================== BEGIN SETTINGS DRAWER ====================
|
|
145
|
+
function openSettingsDrawer(){
|
|
146
|
+
const settingsDrawer = document.getElementById('settingsDrawer');
|
|
147
|
+
if(!settingsDrawer){
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
settingsDrawer.classList.add('active');
|
|
151
|
+
|
|
152
|
+
drawerOverlay?.classList.add('active');
|
|
153
|
+
document.body.style.overflow = 'hidden';
|
|
154
|
+
|
|
155
|
+
if(settingsDrawer.is_rendered){
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
settingsDrawer.is_rendered = true;
|
|
159
|
+
|
|
160
|
+
// Set current visibility state for components
|
|
161
|
+
settingsDrawer.querySelectorAll('.visibility-checkbox')
|
|
162
|
+
.forEach(checkbox => checkbox.checked = !Salla.storage.get('hidden-salla-components', []).includes(checkbox.value));
|
|
163
|
+
|
|
164
|
+
// Set current grid settings
|
|
165
|
+
const savedGrid = getSavedGrid();
|
|
166
|
+
|
|
167
|
+
// Set grid columns preset
|
|
168
|
+
const gridPresetBtns = document.querySelectorAll('.grid-preset-btn');
|
|
169
|
+
let activePresetFound = false;
|
|
170
|
+
|
|
171
|
+
gridPresetBtns.forEach(btn => {
|
|
172
|
+
btn.classList.remove('active');
|
|
173
|
+
const columns = btn.getAttribute('data-columns');
|
|
174
|
+
|
|
175
|
+
if (columns === savedGrid.columns) {
|
|
176
|
+
btn.classList.add('active');
|
|
177
|
+
activePresetFound = true;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
// If no preset matches, activate custom option
|
|
182
|
+
if (!activePresetFound) {
|
|
183
|
+
const customBtn = document.querySelector('.grid-preset-btn[data-columns="custom"]');
|
|
184
|
+
customBtn?.classList.add('active');
|
|
185
|
+
|
|
186
|
+
// Store the current value as custom value
|
|
187
|
+
const gridColumnsInput = document.getElementById('gridColumns');
|
|
188
|
+
if (gridColumnsInput) {
|
|
189
|
+
gridColumnsInput.setAttribute('data-custom-value', savedGrid.columns);
|
|
190
|
+
gridColumnsInput.readOnly = false;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Initialize grid columns input
|
|
195
|
+
const gridColumnsInput = document.getElementById('gridColumns');
|
|
196
|
+
if (gridColumnsInput) {
|
|
197
|
+
// Initialize with saved value
|
|
198
|
+
gridColumnsInput.value = savedGrid.columns;
|
|
199
|
+
gridColumnsInput.addEventListener('input', () => {
|
|
200
|
+
// Store custom value when user edits
|
|
201
|
+
const customPreset = document.querySelector('.grid-preset-btn[data-columns="custom"]');
|
|
202
|
+
if (customPreset && customPreset.classList.contains('active')) {
|
|
203
|
+
gridColumnsInput.setAttribute('data-custom-value', gridColumnsInput.value);
|
|
204
|
+
}
|
|
205
|
+
// Apply settings immediately for live update
|
|
206
|
+
applySettings();
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const gridGapInput = document.getElementById('gridGapValue');
|
|
210
|
+
const gridGapUnitInput = document.getElementById('gridGapUnit');
|
|
211
|
+
if(gridGapInput && savedGrid.gap){
|
|
212
|
+
gridGapInput.value = savedGrid.gap.match(/[\\d\\.]+/)?.[0];
|
|
213
|
+
gridGapUnitInput.value = savedGrid.gap.match(/[a-z%]+/)?.[0];
|
|
214
|
+
}
|
|
215
|
+
// Add event listeners to grid gap inputs for live updates
|
|
216
|
+
gridGapInput?.addEventListener('input', () => {
|
|
217
|
+
const gridGapValue = gridGapInput?.value || '1';
|
|
218
|
+
const gridGapUnit = gridGapUnitInput?.value || 'rem';
|
|
219
|
+
const gridGap = gridGapValue + gridGapUnit;
|
|
220
|
+
|
|
221
|
+
// Update the gap in real-time
|
|
222
|
+
const grid = document.getElementById('componentsGrid');
|
|
223
|
+
if (grid) {
|
|
224
|
+
grid.style.gap = gridGap;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const savedGrid = getSavedGrid();
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
Salla.storage.set('salla_demo_grid', {...savedGrid, gap: gridGap});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
gridGapUnitInput?.addEventListener('change', () => {
|
|
234
|
+
const gridGapValue = gridGapInput.value || '1';
|
|
235
|
+
const gridGapUnit = gridGapUnitInput.value || 'rem';
|
|
236
|
+
const gridGap = gridGapValue + gridGapUnit;
|
|
237
|
+
|
|
238
|
+
// Update the gap in real-time
|
|
239
|
+
const grid = document.getElementById('componentsGrid');
|
|
240
|
+
if (grid) {
|
|
241
|
+
grid.style.gap = gridGap;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
Salla.storage.set('salla_demo_grid', {...getSavedGrid(), gap: gridGap});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
document.getElementById('customCSS')?.addEventListener('input', debounce(() => {
|
|
248
|
+
applySettings();
|
|
249
|
+
}, 500));
|
|
250
|
+
|
|
251
|
+
document.getElementById('customJS')?.addEventListener('input', debounce(() => {
|
|
252
|
+
applySettings();
|
|
253
|
+
}, 500));
|
|
254
|
+
|
|
255
|
+
document.getElementById('formbuilderLanguages')?.addEventListener('change', () => applySettings());
|
|
256
|
+
document.getElementById('formbuilderDefaultLang')?.addEventListener('change', () => applySettings());
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
// Set current custom CSS and JS
|
|
260
|
+
const customCSS = document.getElementById('customCSS');
|
|
261
|
+
const customJS = document.getElementById('customJS');
|
|
262
|
+
|
|
263
|
+
if (customCSS && customJS) {
|
|
264
|
+
customCSS.value = Salla.storage.get('salla_demo_custom_css', '${((s = e.css) == null ? void 0 : s.replace(/'/g, "\\'")) || ""}');
|
|
265
|
+
customJS.value = Salla.storage.get('salla_demo_custom_js', '${((l = e.js) == null ? void 0 : l.replace(/'/g, "\\'")) || ""}');
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// Set current formbuilder settings
|
|
269
|
+
const savedFormbuilder = getSavedLanguages();
|
|
270
|
+
|
|
271
|
+
// Set language checkboxes
|
|
272
|
+
document.querySelectorAll('#formbuilderLanguages option').forEach(option => option.selected = savedFormbuilder.languages.includes(option.value));
|
|
273
|
+
|
|
274
|
+
document.getElementById('formbuilderDefaultLang').value = savedFormbuilder.defaultLanguage;
|
|
275
|
+
}
|
|
276
|
+
// ==================== END SETTINGS DRAWER ====================
|
|
277
|
+
|
|
278
|
+
function parseValueAndUnit(cssValue) {
|
|
279
|
+
const match = cssValue.match(/^([d.]+)([a-z%]*)$/);
|
|
280
|
+
if (match) {
|
|
281
|
+
return [match[1], match[2] || 'px']; // Default to px if no unit
|
|
282
|
+
}
|
|
283
|
+
return ['0', 'px']; // Default fallback
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Helper function to set selected option in a select element
|
|
287
|
+
function setSelectedUnit(selectElement, unit) {
|
|
288
|
+
for (let i = 0; i < selectElement.options.length; i++) {
|
|
289
|
+
if (selectElement.options[i].value === unit) {
|
|
290
|
+
selectElement.selectedIndex = i;
|
|
291
|
+
break;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function getGridColumns() {
|
|
297
|
+
const gridColumnsInput = document.getElementById('gridColumns');
|
|
298
|
+
return gridColumnsInput?.value || '${e.grid.columns}';
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function updateGridBasedOnItemCount() {
|
|
302
|
+
const grid = document.getElementById('componentsGrid');
|
|
303
|
+
if (!grid) return;
|
|
304
|
+
|
|
305
|
+
const gridItems = grid.querySelectorAll(':scope > *');
|
|
306
|
+
|
|
307
|
+
if (gridItems.length <= 2) {
|
|
308
|
+
// For 1-2 items, use auto-fit with full width
|
|
309
|
+
grid.style.gridTemplateColumns = 'repeat(auto-fit, minmax(0, 1fr))';
|
|
310
|
+
// Reset all items grid-column property
|
|
311
|
+
gridItems.forEach(item => item.style.gridColumn = '');
|
|
312
|
+
} else {
|
|
313
|
+
// For 3+ items, use 3 columns with first item spanning all columns
|
|
314
|
+
grid.style.gridTemplateColumns = 'repeat(3, 1fr)';
|
|
315
|
+
// Reset all items first
|
|
316
|
+
gridItems.forEach(item => item.style.gridColumn = '');
|
|
317
|
+
// Make first item span 3 columns
|
|
318
|
+
if (gridItems[0]) gridItems[0].style.gridColumn = 'span 3';
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function applySettings() {
|
|
323
|
+
const activePreset = document.querySelector('.grid-preset-btn.active');
|
|
324
|
+
const grid = document.getElementById('componentsGrid');
|
|
325
|
+
if (!grid) return;
|
|
326
|
+
|
|
327
|
+
// Apply special auto-fill behavior if selected
|
|
328
|
+
if (activePreset && activePreset.getAttribute('data-columns') === 'auto-fill') {
|
|
329
|
+
updateGridBasedOnItemCount();
|
|
330
|
+
} else {
|
|
331
|
+
// Apply normal grid columns
|
|
332
|
+
const gridColumns = getGridColumns();
|
|
333
|
+
grid.style.gridTemplateColumns = gridColumns;
|
|
334
|
+
// Reset all items grid-column property
|
|
335
|
+
const gridItems = grid.querySelectorAll(':scope > *');
|
|
336
|
+
gridItems.forEach(item => item.style.gridColumn = '');
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Get grid gap with unit
|
|
340
|
+
const gridGapValue = document.getElementById('gridGapValue')?.value || '1';
|
|
341
|
+
const gridGapUnit = document.getElementById('gridGapUnit')?.value || 'rem';
|
|
342
|
+
const gridGap = gridGapValue + gridGapUnit;
|
|
343
|
+
|
|
344
|
+
// Apply grid gap
|
|
345
|
+
if (grid) {
|
|
346
|
+
grid.style.gap = gridGap;
|
|
347
|
+
|
|
348
|
+
// Ensure grid gap is saved in localStorage
|
|
349
|
+
const savedGrid = Salla.storage.get('salla_demo_grid', {
|
|
350
|
+
columns: grid.style.gridTemplateColumns || '${e.grid.columns}',
|
|
351
|
+
gap: '${e.grid.gap}',
|
|
352
|
+
minWidth: '${e.grid.minWidth}'
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// Update only the gap property
|
|
356
|
+
Salla.storage.set('salla_demo_grid', {
|
|
357
|
+
columns: savedGrid.columns,
|
|
358
|
+
gap: gridGap,
|
|
359
|
+
minWidth: savedGrid.minWidth
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Apply custom CSS
|
|
364
|
+
const customCSS = document.getElementById('customCSS')?.value || '';
|
|
365
|
+
let customCSSElement = document.getElementById('custom-css-element');
|
|
366
|
+
if (!customCSSElement) {
|
|
367
|
+
customCSSElement = document.createElement('style');
|
|
368
|
+
customCSSElement.id = 'custom-css-element';
|
|
369
|
+
document.head.appendChild(customCSSElement);
|
|
370
|
+
}
|
|
371
|
+
customCSSElement.textContent = customCSS;
|
|
372
|
+
|
|
373
|
+
// Apply custom JS
|
|
374
|
+
const customJS = document.getElementById('customJS')?.value || '';
|
|
375
|
+
try {
|
|
376
|
+
if (customJS) {
|
|
377
|
+
eval(customJS);
|
|
378
|
+
}
|
|
379
|
+
} catch (error) {
|
|
380
|
+
console.error('Error executing custom JS:', error);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Save settings to localStorage
|
|
384
|
+
Salla.storage.set('salla_demo_grid', {
|
|
385
|
+
columns: activePreset && activePreset.getAttribute('data-columns') === 'auto-fill' ? 'auto-fill' : getGridColumns(),
|
|
386
|
+
gap: gridGap,
|
|
387
|
+
minWidth: '${e.grid.minWidth}' // Use backend value only
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
Salla.storage.set('salla_demo_custom_css', customCSS);
|
|
391
|
+
Salla.storage.set('salla_demo_custom_js', customJS);
|
|
392
|
+
|
|
393
|
+
// Get selected languages from multi-select
|
|
394
|
+
const formbuilderLanguagesSelect = document.getElementById('formbuilderLanguages');
|
|
395
|
+
const selectedLanguages = Array.from(formbuilderLanguagesSelect?.selectedOptions || []).map(option => option.value);
|
|
396
|
+
|
|
397
|
+
// Ensure at least one language is selected
|
|
398
|
+
if (selectedLanguages.length === 0) {
|
|
399
|
+
selectedLanguages.push('ar'); // Default to English if nothing selected
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Get default language
|
|
403
|
+
const formbuilderDefaultLang = document.getElementById('formbuilderDefaultLang')?.value || '${e.formbuilder.defaultLanguage}';
|
|
404
|
+
|
|
405
|
+
// Ensure default language is in the selected languages
|
|
406
|
+
if (!selectedLanguages.includes(formbuilderDefaultLang)) {
|
|
407
|
+
selectedLanguages.push(formbuilderDefaultLang);
|
|
408
|
+
// Also select it in the UI
|
|
409
|
+
const option = Array.from(formbuilderLanguagesSelect?.options || []).find(opt => opt.value === formbuilderDefaultLang);
|
|
410
|
+
if (option) option.selected = true;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// Save formbuilder settings
|
|
414
|
+
Salla.storage.set('salla_demo_formbuilder', {
|
|
415
|
+
languages: selectedLanguages,
|
|
416
|
+
defaultLanguage: formbuilderDefaultLang
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Reset component settings drawer on form-builder changes
|
|
420
|
+
resetComponentSettings();
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
window.addEventListener('FormBuilder::form-builder-3::request-success',async ({detail:payload}) => {
|
|
424
|
+
const ignoredKeys = ['static-', '$','twilight-bundles-component-name'];
|
|
425
|
+
const data = Object.fromEntries(
|
|
426
|
+
Object.entries(payload).filter(([key]) => !ignoredKeys.some(ignoredKey=>key.startsWith(ignoredKey)))
|
|
427
|
+
);
|
|
428
|
+
const componentName = payload['twilight-bundles-component-name'];
|
|
429
|
+
Salla.storage.set('form-builder::data_' + componentName, data);
|
|
430
|
+
if (componentName && window.customComponentsSchema && window.customComponentsSchema[componentName]) {
|
|
431
|
+
// Inject the data into the schema
|
|
432
|
+
const schema = window.customComponentsSchema[componentName];
|
|
433
|
+
await fetch('${i}/schema-injector', {
|
|
434
|
+
method: 'POST',
|
|
435
|
+
headers: {'Content-Type': 'application/json'},
|
|
436
|
+
body: JSON.stringify({ schema, data }),
|
|
437
|
+
}).then(res=>res.json())
|
|
438
|
+
.then(data=>Salla.storage.set('form-builder::'+componentName, data))
|
|
439
|
+
.then(()=>reRenderComponent(componentName))
|
|
440
|
+
.then(()=>closeDrawer())
|
|
441
|
+
.catch(err=>console.error('Error injecting data into schema:', err));
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
<\/script>
|
|
445
|
+
<link rel="icon" type="image/png" media="(prefers-color-scheme: light)" href="https://cdn.salla.network/images/logo/logo-square.png" />
|
|
446
|
+
<link rel="icon" type="image/png" media="(prefers-color-scheme: dark)" href="https://cdn.salla.network/images/logo/logo-light-square.png" />
|
|
447
|
+
<script type="module" src="https://cdn.salla.network/js/twilight/latest/twilight.esm.js" async><\/script>
|
|
448
|
+
<script type="module" src="${L}" demo-mode defer><\/script>
|
|
449
|
+
<link rel="stylesheet" href="https://cdn.salla.network/fonts/pingarlt.css">
|
|
450
|
+
<link rel="stylesheet" href="https://cdn.salla.network/fonts/sallaicons.css?v=2.0.5">
|
|
451
|
+
|
|
452
|
+
<!-- Preload form builder resources for faster loading -->
|
|
453
|
+
|
|
454
|
+
<style>
|
|
455
|
+
:root {
|
|
456
|
+
--font-main: "PingARLT";
|
|
457
|
+
--color-primary-50: rgb(186, 243, 230); /* #BAF3E6 */
|
|
458
|
+
--color-primary-100: rgb(120, 232, 206); /* #78E8CE */
|
|
459
|
+
--color-primary-900: rgb(0, 73, 86); /* #004956 */
|
|
460
|
+
--color-primary: rgb(0, 78, 92);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
:root[data-theme="dark"] {
|
|
464
|
+
--bg-primary: #1E1E1E;
|
|
465
|
+
--bg-secondary: #2A2A2A;
|
|
466
|
+
--text-primary: #FFFFFF;
|
|
467
|
+
--text-secondary: #9CA3AF;
|
|
468
|
+
--border-color: #333333;
|
|
469
|
+
--color-primary: #1d1e20;
|
|
470
|
+
--component-title: #baf3e5;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
:root[data-theme="light"] {
|
|
474
|
+
--bg-primary: #FFFFFF;
|
|
475
|
+
--bg-secondary: #F8F9FA;
|
|
476
|
+
--text-primary: #1E1E1E;
|
|
477
|
+
--text-secondary: #4B5563;
|
|
478
|
+
--border-color: #E5E7EB;
|
|
479
|
+
--component-title: #004e5c;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
* {
|
|
483
|
+
margin: 0;
|
|
484
|
+
padding: 0;
|
|
485
|
+
box-sizing: border-box;
|
|
486
|
+
font-family: var(--font-main);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
body {
|
|
490
|
+
min-height: 100vh;
|
|
491
|
+
background-color: var(--bg-secondary);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
header {
|
|
495
|
+
background-color: var(--color-primary);
|
|
496
|
+
padding: 0.75rem 0;
|
|
497
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
.container {
|
|
501
|
+
max-width: 1200px;
|
|
502
|
+
margin: 0 auto;
|
|
503
|
+
padding: 0 0.75rem;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
.header-content {
|
|
507
|
+
display: flex;
|
|
508
|
+
align-items: center;
|
|
509
|
+
justify-content: space-between;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
.logo-container {
|
|
513
|
+
display: flex;
|
|
514
|
+
align-items: center;
|
|
515
|
+
gap: 1rem;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.logo {
|
|
519
|
+
height: 40px;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.logo img {
|
|
523
|
+
height: 100%;
|
|
524
|
+
width: auto;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.title {
|
|
528
|
+
color: white;
|
|
529
|
+
font-size: 1.25rem;
|
|
530
|
+
font-weight: 500;
|
|
531
|
+
margin: 0;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.actions {
|
|
535
|
+
display: flex;
|
|
536
|
+
gap: 1rem;
|
|
537
|
+
align-items: center;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
.actions button {
|
|
541
|
+
background: transparent;
|
|
542
|
+
border: none;
|
|
543
|
+
color: white;
|
|
544
|
+
cursor: pointer;
|
|
545
|
+
padding: 0.5rem;
|
|
546
|
+
border-radius: 4px;
|
|
547
|
+
transition: color 0.2s ease;
|
|
548
|
+
font-size: 1rem;
|
|
549
|
+
display: flex;
|
|
550
|
+
align-items: center;
|
|
551
|
+
gap: 0.5rem;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.actions button:hover {
|
|
555
|
+
color: rgb(var(--color-primary-100));
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.theme-icon {
|
|
559
|
+
transition: transform 0.3s ease;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
[data-theme="dark"] .theme-icon.moon {
|
|
563
|
+
display: none;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
[data-theme="light"] .theme-icon.sun {
|
|
567
|
+
display: none;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.lang-icon {
|
|
571
|
+
transition: transform 0.3s ease;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
[dir="rtl"] .lang-icon {
|
|
575
|
+
transform: scaleX(-1);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.lang-code {
|
|
579
|
+
font-size: 0.875rem;
|
|
580
|
+
font-weight: 500;
|
|
581
|
+
text-transform: uppercase;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
main {
|
|
585
|
+
padding: 1.5rem 0;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.components-grid {
|
|
589
|
+
display: grid;
|
|
590
|
+
grid-template-columns: ${e.grid.columns};
|
|
591
|
+
gap: ${e.grid.gap};
|
|
592
|
+
margin-top: 0;
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
@media (max-width: ${e.grid.minWidth}) {
|
|
596
|
+
.components-grid {
|
|
597
|
+
grid-template-columns: 1fr;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
.component-card {
|
|
602
|
+
background: var(--bg-primary);
|
|
603
|
+
border: 1px solid var(--border-color);
|
|
604
|
+
border-radius: 8px;
|
|
605
|
+
padding: 0.75rem;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.component-card-header {
|
|
609
|
+
display: flex;
|
|
610
|
+
justify-content: space-between;
|
|
611
|
+
align-items: center;
|
|
612
|
+
margin-bottom: 0.75rem;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.component-card-header h2 {
|
|
616
|
+
color: var(--component-title);
|
|
617
|
+
font-size: 1.125rem;
|
|
618
|
+
margin: 0;
|
|
619
|
+
display: flex;
|
|
620
|
+
align-items: center;
|
|
621
|
+
gap: 0.5rem;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
.component-card-header h2 i {
|
|
625
|
+
font-size: 1.25rem;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.component-card-actions {
|
|
629
|
+
display: flex;
|
|
630
|
+
gap: 0.5rem;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.component-visibility-btn,
|
|
634
|
+
.component-settings-btn {
|
|
635
|
+
background: transparent;
|
|
636
|
+
border: 1px solid var(--border-color);
|
|
637
|
+
color: var(--text-secondary);
|
|
638
|
+
cursor: pointer;
|
|
639
|
+
width: 32px;
|
|
640
|
+
height: 32px;
|
|
641
|
+
border-radius: 4px;
|
|
642
|
+
display: flex;
|
|
643
|
+
align-items: center;
|
|
644
|
+
justify-content: center;
|
|
645
|
+
transition: all 0.2s ease;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.component-visibility-btn:hover,
|
|
649
|
+
.component-settings-btn:hover {
|
|
650
|
+
background-color: var(--bg-secondary);
|
|
651
|
+
color: var(--text-primary);
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
.component-card.hidden {
|
|
655
|
+
opacity: 0.5;
|
|
656
|
+
position: relative;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.component-card.hidden::after {
|
|
660
|
+
content: "Hidden";
|
|
661
|
+
position: absolute;
|
|
662
|
+
top: 0;
|
|
663
|
+
left: 0;
|
|
664
|
+
right: 0;
|
|
665
|
+
bottom: 0;
|
|
666
|
+
display: flex;
|
|
667
|
+
align-items: center;
|
|
668
|
+
justify-content: center;
|
|
669
|
+
background-color: rgba(0, 0, 0, 0.1);
|
|
670
|
+
font-size: 1.5rem;
|
|
671
|
+
font-weight: bold;
|
|
672
|
+
color: var(--text-secondary);
|
|
673
|
+
z-index: 10;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/* Drawer styles */
|
|
677
|
+
.drawer-overlay {
|
|
678
|
+
position: fixed;
|
|
679
|
+
top: 0;
|
|
680
|
+
left: 0;
|
|
681
|
+
right: 0;
|
|
682
|
+
bottom: 0;
|
|
683
|
+
background-color: rgba(0, 0, 0, 0.5);
|
|
684
|
+
z-index: 999;
|
|
685
|
+
opacity: 0;
|
|
686
|
+
visibility: hidden;
|
|
687
|
+
transition: all 0.3s ease;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.drawer-overlay.active {
|
|
691
|
+
opacity: 1;
|
|
692
|
+
visibility: visible;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.drawer {
|
|
696
|
+
position: fixed;
|
|
697
|
+
top: 0;
|
|
698
|
+
bottom: 0;
|
|
699
|
+
background-color: var(--bg-primary);
|
|
700
|
+
width: 400px;
|
|
701
|
+
max-width: 100%;
|
|
702
|
+
z-index: 1000;
|
|
703
|
+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
|
704
|
+
transition: transform 0.3s ease;
|
|
705
|
+
overflow-y: auto;
|
|
706
|
+
opacity: 0;
|
|
707
|
+
visibility: hidden;
|
|
708
|
+
}
|
|
709
|
+
#settingsDrawer {
|
|
710
|
+
width: 500px;
|
|
711
|
+
}
|
|
712
|
+
.drawer.active {
|
|
713
|
+
opacity: 1;
|
|
714
|
+
visibility: visible;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
[dir="ltr"] .drawer {
|
|
718
|
+
right: 0;
|
|
719
|
+
transform: translateX(100%);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
[dir="rtl"] .drawer {
|
|
723
|
+
left: 0;
|
|
724
|
+
transform: translateX(-100%);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.drawer.active {
|
|
728
|
+
transform: translateX(0);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.drawer-header {
|
|
732
|
+
display: flex;
|
|
733
|
+
justify-content: space-between;
|
|
734
|
+
align-items: center;
|
|
735
|
+
padding: 1.25rem 1.5rem;
|
|
736
|
+
border-bottom: 1px solid var(--border-color);
|
|
737
|
+
background-color: var(--bg-secondary);
|
|
738
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
.drawer-header h3 {
|
|
742
|
+
margin: 0;
|
|
743
|
+
color: var(--text-primary);
|
|
744
|
+
flex: 1;
|
|
745
|
+
font-size: 1.25rem;
|
|
746
|
+
font-weight: 600;
|
|
747
|
+
letter-spacing: 0.01em;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
.drawer-actions {
|
|
751
|
+
display: flex;
|
|
752
|
+
align-items: center;
|
|
753
|
+
gap: 0.75rem;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
.drawer-close,
|
|
757
|
+
.drawer-reset {
|
|
758
|
+
background-color: var(--bg-primary);
|
|
759
|
+
border: 1px solid var(--border-color);
|
|
760
|
+
border-radius: 6px;
|
|
761
|
+
cursor: pointer;
|
|
762
|
+
font-size: 1.25rem;
|
|
763
|
+
color: var(--text-secondary);
|
|
764
|
+
padding: 0.5rem;
|
|
765
|
+
width: 36px;
|
|
766
|
+
height: 36px;
|
|
767
|
+
display: flex;
|
|
768
|
+
align-items: center;
|
|
769
|
+
justify-content: center;
|
|
770
|
+
transition: all 0.2s ease;
|
|
771
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.drawer-close:hover,
|
|
775
|
+
.drawer-reset:hover {
|
|
776
|
+
background-color: var(--bg-secondary);
|
|
777
|
+
color: var(--text-primary);
|
|
778
|
+
transform: translateY(-1px);
|
|
779
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
.drawer-close:active,
|
|
783
|
+
.drawer-reset:active {
|
|
784
|
+
transform: translateY(0);
|
|
785
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.drawer-reset {
|
|
789
|
+
color: var(--color-primary);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.drawer-close {
|
|
793
|
+
color: var(--color-danger, var(--text-secondary));
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.drawer-content {
|
|
797
|
+
padding: 1rem;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
/* Filter drawer styles */
|
|
801
|
+
.filter-actions {
|
|
802
|
+
display: flex;
|
|
803
|
+
gap: 1rem;
|
|
804
|
+
margin-bottom: 1rem;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
.btn {
|
|
808
|
+
padding: 0.5rem 1rem;
|
|
809
|
+
border-radius: 4px;
|
|
810
|
+
border: none;
|
|
811
|
+
cursor: pointer;
|
|
812
|
+
font-weight: 500;
|
|
813
|
+
transition: all 0.2s ease;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
.btn-primary {
|
|
817
|
+
background-color: var(--color-primary-100);
|
|
818
|
+
color: var(--color-primary-900);
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.btn-primary:hover {
|
|
822
|
+
background-color: var(--color-primary-50);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
.btn-secondary {
|
|
826
|
+
background-color: var(--bg-secondary);
|
|
827
|
+
color: var(--text-primary);
|
|
828
|
+
border: 1px solid var(--border-color);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
.btn-secondary:hover {
|
|
832
|
+
background-color: var(--bg-primary);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.component-visibility-list {
|
|
836
|
+
display: flex;
|
|
837
|
+
flex-direction: column;
|
|
838
|
+
gap: 0.75rem;
|
|
839
|
+
overflow-y: auto;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
.visibility-item {
|
|
843
|
+
padding: 0.5rem;
|
|
844
|
+
border-radius: 4px;
|
|
845
|
+
transition: background-color 0.2s ease;
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
.visibility-item:hover {
|
|
849
|
+
background-color: var(--bg-secondary);
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.visibility-item label {
|
|
853
|
+
display: flex;
|
|
854
|
+
align-items: center;
|
|
855
|
+
gap: 0.75rem;
|
|
856
|
+
cursor: pointer;
|
|
857
|
+
color: var(--text-primary);
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
.visibility-checkbox {
|
|
861
|
+
width: 1.25rem;
|
|
862
|
+
height: 1.25rem;
|
|
863
|
+
cursor: pointer;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
/* Settings drawer styles */
|
|
867
|
+
.settings-tabs {
|
|
868
|
+
display: flex;
|
|
869
|
+
flex-direction: column;
|
|
870
|
+
gap: 1.5rem;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
.settings-tab-headers {
|
|
874
|
+
display: flex;
|
|
875
|
+
border-bottom: 1px solid var(--border-color);
|
|
876
|
+
margin-bottom: 1rem;
|
|
877
|
+
overflow-x: auto;
|
|
878
|
+
-webkit-overflow-scrolling: touch;
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
.settings-tab-btn {
|
|
882
|
+
padding: 0.75rem 1rem;
|
|
883
|
+
background: none;
|
|
884
|
+
border: none;
|
|
885
|
+
border-bottom: 2px solid transparent;
|
|
886
|
+
color: var(--text-secondary);
|
|
887
|
+
cursor: pointer;
|
|
888
|
+
font-weight: 500;
|
|
889
|
+
white-space: nowrap;
|
|
890
|
+
transition: all 0.2s ease;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
.settings-tab-btn:hover {
|
|
894
|
+
color: var(--text-primary);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
.settings-tab-btn.active {
|
|
898
|
+
color: var(--color-primary);
|
|
899
|
+
border-bottom-color: var(--color-primary);
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
.settings-tab-content {
|
|
903
|
+
display: none;
|
|
904
|
+
animation: fadeIn 0.3s ease;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
.settings-tab-content.active {
|
|
908
|
+
display: block;
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
@keyframes fadeIn {
|
|
912
|
+
from { opacity: 0; }
|
|
913
|
+
to { opacity: 1; }
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.settings-section-title {
|
|
917
|
+
margin: 0 0 0.5rem;
|
|
918
|
+
font-size: 1.1rem;
|
|
919
|
+
font-weight: 600;
|
|
920
|
+
color: var(--text-primary);
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
.settings-section-desc {
|
|
924
|
+
margin: 0 0 1.5rem;
|
|
925
|
+
font-size: 0.9rem;
|
|
926
|
+
color: var(--text-secondary);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
.settings-form-group {
|
|
930
|
+
margin-bottom: 1.25rem;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
.settings-form-group label {
|
|
934
|
+
display: block;
|
|
935
|
+
margin-bottom: 0.5rem;
|
|
936
|
+
font-weight: 500;
|
|
937
|
+
color: var(--text-primary);
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.settings-input,
|
|
941
|
+
.settings-textarea {
|
|
942
|
+
width: 100%;
|
|
943
|
+
padding: 0.75rem;
|
|
944
|
+
border: 1px solid var(--border-color);
|
|
945
|
+
border-radius: 4px;
|
|
946
|
+
background-color: var(--bg-primary);
|
|
947
|
+
color: var(--text-primary);
|
|
948
|
+
font-family: inherit;
|
|
949
|
+
font-size: 0.9rem;
|
|
950
|
+
transition: border-color 0.2s ease;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.settings-input:focus,
|
|
954
|
+
.settings-textarea:focus {
|
|
955
|
+
outline: none;
|
|
956
|
+
border-color: var(--color-primary);
|
|
957
|
+
box-shadow: 0 0 0 2px var(--color-primary-50);
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
.settings-textarea {
|
|
961
|
+
resize: vertical;
|
|
962
|
+
min-height: 100px;
|
|
963
|
+
direction: ltr;
|
|
964
|
+
font-family: monospace;
|
|
965
|
+
color: #888;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.settings-form-group small {
|
|
969
|
+
display: block;
|
|
970
|
+
margin-top: 0.25rem;
|
|
971
|
+
font-size: 0.8rem;
|
|
972
|
+
color: var(--text-secondary);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.settings-actions {
|
|
976
|
+
display: flex;
|
|
977
|
+
justify-content: flex-end;
|
|
978
|
+
gap: 1rem;
|
|
979
|
+
margin-top: 2rem;
|
|
980
|
+
padding-top: 1rem;
|
|
981
|
+
border-top: 1px solid var(--border-color);
|
|
982
|
+
}
|
|
983
|
+
|
|
984
|
+
/* Language selection styles */
|
|
985
|
+
.settings-languages-container {
|
|
986
|
+
max-height: 200px;
|
|
987
|
+
overflow-y: auto;
|
|
988
|
+
border: 1px solid var(--border-color);
|
|
989
|
+
border-radius: 4px;
|
|
990
|
+
background-color: var(--bg-primary);
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
.settings-languages-list {
|
|
994
|
+
display: grid;
|
|
995
|
+
grid-template-columns: repeat(auto-fill, minmax(60px, 1fr));
|
|
996
|
+
gap: 0.5rem;
|
|
997
|
+
padding: 0.75rem;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
.settings-language-item {
|
|
1001
|
+
display: flex;
|
|
1002
|
+
align-items: center;
|
|
1003
|
+
gap: 0.25rem;
|
|
1004
|
+
padding: 0.25rem;
|
|
1005
|
+
border-radius: 4px;
|
|
1006
|
+
cursor: pointer;
|
|
1007
|
+
transition: background-color 0.2s ease;
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
.settings-language-item:hover {
|
|
1011
|
+
background-color: var(--bg-secondary);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
.settings-language-item input {
|
|
1015
|
+
margin: 0;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
.settings-language-item span {
|
|
1019
|
+
font-size: 0.85rem;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
/* Grid presets styles */
|
|
1023
|
+
.grid-columns-presets {
|
|
1024
|
+
display: flex;
|
|
1025
|
+
flex-wrap: wrap;
|
|
1026
|
+
gap: 0.5rem;
|
|
1027
|
+
margin-bottom: 0.75rem;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.grid-preset-btn {
|
|
1031
|
+
display: flex;
|
|
1032
|
+
align-items: center;
|
|
1033
|
+
justify-content: center;
|
|
1034
|
+
width: 60px;
|
|
1035
|
+
height: 40px;
|
|
1036
|
+
border: 1px solid var(--border-color);
|
|
1037
|
+
border-radius: 4px;
|
|
1038
|
+
background-color: var(--bg-primary);
|
|
1039
|
+
cursor: pointer;
|
|
1040
|
+
transition: all 0.2s ease;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
.grid-preset-btn:hover {
|
|
1044
|
+
background-color: var(--bg-secondary);
|
|
1045
|
+
transform: translateY(-1px);
|
|
1046
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
.grid-preset-btn.active {
|
|
1050
|
+
border-color: var(--color-primary);
|
|
1051
|
+
background-color: var(--color-primary-50);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.grid-preset-icon {
|
|
1055
|
+
font-size: 1.25rem;
|
|
1056
|
+
color: var(--text-primary);
|
|
1057
|
+
letter-spacing: -2px;
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
.custom-grid-columns-container {
|
|
1061
|
+
margin-top: 0.75rem;
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
/* Input with unit styles */
|
|
1065
|
+
.settings-input-with-unit {
|
|
1066
|
+
display: flex;
|
|
1067
|
+
align-items: center;
|
|
1068
|
+
gap: 0.5rem;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
.settings-input-number {
|
|
1072
|
+
flex: 1;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
.settings-input-unit {
|
|
1076
|
+
width: 80px;
|
|
1077
|
+
padding: 0.75rem;
|
|
1078
|
+
border: 1px solid var(--border-color);
|
|
1079
|
+
border-radius: 4px;
|
|
1080
|
+
background-color: var(--bg-primary);
|
|
1081
|
+
color: var(--text-primary);
|
|
1082
|
+
font-family: inherit;
|
|
1083
|
+
font-size: 0.9rem;
|
|
1084
|
+
}
|
|
1085
|
+
</style>
|
|
1086
|
+
</head>
|
|
1087
|
+
<body>
|
|
1088
|
+
<header>
|
|
1089
|
+
<div class="container">
|
|
1090
|
+
<div class="header-content">
|
|
1091
|
+
<div class="logo-container">
|
|
1092
|
+
<div class="logo">
|
|
1093
|
+
<img src="https://cdn.salla.network/images/logo/logo-light-wide.png" alt="Salla">
|
|
1094
|
+
</div>
|
|
1095
|
+
<h1 class="title" id="pageTitle">${o.ar.title}</h1>
|
|
1096
|
+
</div>
|
|
1097
|
+
<div class="actions">
|
|
1098
|
+
<button id="toggleSettings" title="Settings" onclick="openSettingsDrawer()" class="sicon-settings"></button>
|
|
1099
|
+
<button id="toggleTheme" title="Toggle theme">
|
|
1100
|
+
<i class="theme-icon moon sicon-moon"></i>
|
|
1101
|
+
<i class="theme-icon sun sicon-lightbulb"></i>
|
|
1102
|
+
</button>
|
|
1103
|
+
<button id="toggleLang" title="Toggle language">
|
|
1104
|
+
<i class="lang-icon sicon-world"></i>
|
|
1105
|
+
<span class="lang-code">EN</span>
|
|
1106
|
+
</button>
|
|
1107
|
+
</div>
|
|
1108
|
+
</div>
|
|
1109
|
+
</div>
|
|
1110
|
+
</header>
|
|
1111
|
+
<main>
|
|
1112
|
+
<div class="container">
|
|
1113
|
+
<div class="components-grid" id="componentsGrid"></div>
|
|
1114
|
+
</div>
|
|
1115
|
+
</main>
|
|
1116
|
+
|
|
1117
|
+
<!-- Drawer overlay -->
|
|
1118
|
+
<div class="drawer-overlay" id="drawerOverlay"></div>
|
|
1119
|
+
|
|
1120
|
+
<!-- Component settings drawer -->
|
|
1121
|
+
<div id="componentDrawer" class="drawer">
|
|
1122
|
+
<div class="drawer-header">
|
|
1123
|
+
<h3 class="drawer-title">Component Settings</h3>
|
|
1124
|
+
<div class="drawer-actions">
|
|
1125
|
+
<button id="resetForm" class="drawer-reset" title="Reset to default">
|
|
1126
|
+
<i class="sicon-rotate"></i>
|
|
1127
|
+
</button>
|
|
1128
|
+
<button id="closeDrawer" class="drawer-close">
|
|
1129
|
+
<i class="sicon-cancel"></i>
|
|
1130
|
+
</button>
|
|
1131
|
+
</div>
|
|
1132
|
+
</div>
|
|
1133
|
+
<div class="drawer-content">
|
|
1134
|
+
<div id="formContainer"></div>
|
|
1135
|
+
</div>
|
|
1136
|
+
</div>
|
|
1137
|
+
|
|
1138
|
+
<!-- Settings drawer -->
|
|
1139
|
+
<div id="settingsDrawer" class="drawer">
|
|
1140
|
+
<div class="drawer-header">
|
|
1141
|
+
<h3>Demo Settings</h3>
|
|
1142
|
+
<div class="drawer-actions">
|
|
1143
|
+
<button class="drawer-close" onclick="closeDrawer()">
|
|
1144
|
+
<i class="sicon-cancel"></i>
|
|
1145
|
+
</button>
|
|
1146
|
+
</div>
|
|
1147
|
+
</div>
|
|
1148
|
+
<div class="drawer-content">
|
|
1149
|
+
<div class="settings-tabs">
|
|
1150
|
+
<div class="settings-tab-headers">
|
|
1151
|
+
<button class="settings-tab-btn active" data-tab="components">Components</button>
|
|
1152
|
+
<button class="settings-tab-btn" data-tab="grid">Grid</button>
|
|
1153
|
+
<button class="settings-tab-btn" data-tab="custom-code">Custom Code</button>
|
|
1154
|
+
<button class="settings-tab-btn" data-tab="formbuilder">Form Builder</button>
|
|
1155
|
+
</div>
|
|
1156
|
+
|
|
1157
|
+
<!-- Components Tab -->
|
|
1158
|
+
<div class="settings-tab-content active" id="components-tab">
|
|
1159
|
+
<h4 class="settings-section-title">Component Visibility</h4>
|
|
1160
|
+
<p class="settings-section-desc">Select which components to display in the demo</p>
|
|
1161
|
+
|
|
1162
|
+
<div class="component-visibility-list">
|
|
1163
|
+
${t.map((n) => `
|
|
1164
|
+
<div class="visibility-item">
|
|
1165
|
+
<label>
|
|
1166
|
+
<input type="checkbox"
|
|
1167
|
+
name="component-visibility"
|
|
1168
|
+
class="visibility-checkbox"
|
|
1169
|
+
value="${n.name}"
|
|
1170
|
+
onchange="toggleComponentVisibility(this)">
|
|
1171
|
+
<span>${n.name}</span>
|
|
1172
|
+
</label>
|
|
1173
|
+
</div>
|
|
1174
|
+
`).join("")}
|
|
1175
|
+
</div>
|
|
1176
|
+
</div>
|
|
1177
|
+
|
|
1178
|
+
<!-- Grid Tab -->
|
|
1179
|
+
<div class="settings-tab-content" id="grid-tab">
|
|
1180
|
+
<h4 class="settings-section-title">Grid Settings</h4>
|
|
1181
|
+
<p class="settings-section-desc">Customize the component grid layout</p>
|
|
1182
|
+
|
|
1183
|
+
<div class="settings-form-group">
|
|
1184
|
+
<label for="gridColumnsPreset">Grid Columns Layout</label>
|
|
1185
|
+
<div class="grid-columns-presets">
|
|
1186
|
+
<button type="button" class="grid-preset-btn" data-columns="repeat(1, 1fr)" title="1 column">
|
|
1187
|
+
<span class="grid-preset-icon sicon-inbox-multi"></span>
|
|
1188
|
+
</button>
|
|
1189
|
+
<button type="button" class="grid-preset-btn" data-columns="repeat(2, 1fr)" title="2 columns">
|
|
1190
|
+
<span class="grid-preset-icon sicon-layout-grid"></span>
|
|
1191
|
+
</button>
|
|
1192
|
+
<button type="button" class="grid-preset-btn" data-columns="repeat(3, 1fr)" title="3 columns">
|
|
1193
|
+
<span class="grid-preset-icon sicon-grid"></span>
|
|
1194
|
+
</button>
|
|
1195
|
+
<button type="button" class="grid-preset-btn" data-columns="repeat(4, 1fr)" title="4 columns">
|
|
1196
|
+
<span class="grid-preset-icon">▮▮▮▮</span>
|
|
1197
|
+
</button>
|
|
1198
|
+
<button type="button" class="grid-preset-btn" data-columns="auto-fill" title="Auto-fill">
|
|
1199
|
+
<span class="grid-preset-icon sicon-window-layout"></span>
|
|
1200
|
+
</button>
|
|
1201
|
+
<button type="button" class="grid-preset-btn grid-preset-custom" data-columns="custom" title="Custom">
|
|
1202
|
+
<span class="grid-preset-icon sicon-settings"></span>
|
|
1203
|
+
</button>
|
|
1204
|
+
</div>
|
|
1205
|
+
<div id="customGridColumnsContainer" class="custom-grid-columns-container">
|
|
1206
|
+
<input type="text" id="gridColumns" dir="ltr" class="settings-input" placeholder="repeat(3, 1fr)" value="${e.grid.columns}" data-custom-value="${e.grid.columns}">
|
|
1207
|
+
<small>CSS grid-template-columns value</small>
|
|
1208
|
+
</div>
|
|
1209
|
+
</div>
|
|
1210
|
+
|
|
1211
|
+
<div class="settings-form-group">
|
|
1212
|
+
<label for="gridGap">Grid Gap</label>
|
|
1213
|
+
<div class="settings-input-with-unit">
|
|
1214
|
+
<input type="number" id="gridGapValue" class="settings-input settings-input-number" placeholder="1" step="0.1" min="0">
|
|
1215
|
+
<select id="gridGapUnit" class="settings-input-unit">
|
|
1216
|
+
<option value="px">px</option>
|
|
1217
|
+
<option value="rem">rem</option>
|
|
1218
|
+
<option value="em">em</option>
|
|
1219
|
+
<option value="%">%</option>
|
|
1220
|
+
</select>
|
|
1221
|
+
</div>
|
|
1222
|
+
<small>Space between grid items</small>
|
|
1223
|
+
</div>
|
|
1224
|
+
|
|
1225
|
+
<!-- Min Width Breakpoint is now handled by backend only -->
|
|
1226
|
+
</div>
|
|
1227
|
+
|
|
1228
|
+
<!-- Custom Code Tab -->
|
|
1229
|
+
<div class="settings-tab-content" id="custom-code-tab">
|
|
1230
|
+
<h4 class="settings-section-title">Custom Code</h4>
|
|
1231
|
+
<p class="settings-section-desc">Add custom CSS and JavaScript</p>
|
|
1232
|
+
|
|
1233
|
+
<div class="settings-form-group">
|
|
1234
|
+
<label for="customCSS">Custom CSS</label>
|
|
1235
|
+
<textarea id="customCSS" dir="ltr" class="settings-textarea" rows="6" placeholder="/* Add your custom CSS here */">${e.css || ""}</textarea>
|
|
1236
|
+
</div>
|
|
1237
|
+
|
|
1238
|
+
<div class="settings-form-group">
|
|
1239
|
+
<label for="customJS">Custom JavaScript</label>
|
|
1240
|
+
<textarea id="customJS" dir="ltr" class="settings-textarea" rows="6" placeholder="// Add your custom JavaScript here">${e.js || ""}</textarea>
|
|
1241
|
+
</div>
|
|
1242
|
+
</div>
|
|
1243
|
+
|
|
1244
|
+
<!-- Form Builder Tab -->
|
|
1245
|
+
<div class="settings-tab-content" id="formbuilder-tab">
|
|
1246
|
+
<h4 class="settings-section-title">Form Builder Settings</h4>
|
|
1247
|
+
<p class="settings-section-desc">Configure form builder options</p>
|
|
1248
|
+
|
|
1249
|
+
<div class="settings-form-group">
|
|
1250
|
+
<label for="formbuilderLanguages">Languages</label>
|
|
1251
|
+
<select id="formbuilderLanguages" class="settings-input" multiple>
|
|
1252
|
+
${["ar", "en", "bg", "cs", "da", "de", "el", "es", "et", "fa", "fi", "fr", "ga", "he", "hi", "hr", "hu", "hy", "ind", "it", "ja", "ko", "lv", "mt", "nl", "pl", "pt", "ro", "ru", "sl", "sq", "sv", "tl", "tr", "uk", "ur", "zh", "bn"].map((n) => `
|
|
1253
|
+
<option value="${n}" ${e.formbuilder.languages.includes(n) ? "selected" : ""}>${n}</option>
|
|
1254
|
+
`).join("")}
|
|
1255
|
+
</select>
|
|
1256
|
+
</div>
|
|
1257
|
+
|
|
1258
|
+
<div class="settings-form-group">
|
|
1259
|
+
<label for="formbuilderDefaultLang">Default Language</label>
|
|
1260
|
+
<select id="formbuilderDefaultLang" class="settings-input">
|
|
1261
|
+
${["ar", "en", "bg", "cs", "da", "de", "el", "es", "et", "fa", "fi", "fr", "ga", "he", "hi", "hr", "hu", "hy", "ind", "it", "ja", "ko", "lv", "mt", "nl", "pl", "pt", "ro", "ru", "sl", "sq", "sv", "tl", "tr", "uk", "ur", "zh", "bn"].map((n) => `
|
|
1262
|
+
<option value="${n}" ${e.formbuilder.defaultLanguage === n ? "selected" : ""}>${n}</option>
|
|
1263
|
+
`).join("")}
|
|
1264
|
+
</select>
|
|
1265
|
+
<small>Default language for the form builder</small>
|
|
1266
|
+
</div>
|
|
1267
|
+
</div>
|
|
1268
|
+
</div>
|
|
1269
|
+
|
|
1270
|
+
<!-- Footer removed as requested -->
|
|
1271
|
+
</div>
|
|
1272
|
+
</div>
|
|
1273
|
+
|
|
1274
|
+
<script>
|
|
1275
|
+
const translations = ${JSON.stringify(o)};
|
|
1276
|
+
const toggleTheme = document.getElementById('toggleTheme');
|
|
1277
|
+
const toggleLang = document.getElementById('toggleLang');
|
|
1278
|
+
|
|
1279
|
+
// Simple debounce function to prevent too many updates
|
|
1280
|
+
function debounce(func, wait) {
|
|
1281
|
+
let timeout;
|
|
1282
|
+
return function(...args) {
|
|
1283
|
+
clearTimeout(timeout);
|
|
1284
|
+
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// Get stored preferences or use defaults
|
|
1289
|
+
let currentLang = localStorage.getItem('salla_demo_lang') || 'ar';
|
|
1290
|
+
let currentTheme = localStorage.getItem('salla_demo_theme') || 'light';
|
|
1291
|
+
|
|
1292
|
+
function __demoTrans(key){
|
|
1293
|
+
return translations[currentLang][key];
|
|
1294
|
+
}
|
|
1295
|
+
// Function to update language
|
|
1296
|
+
function updateLanguage(lang) {
|
|
1297
|
+
currentLang = lang;
|
|
1298
|
+
const dir = currentLang === 'ar' ? 'rtl' : 'ltr';
|
|
1299
|
+
document.documentElement.setAttribute('lang', currentLang);
|
|
1300
|
+
document.documentElement.setAttribute('dir', dir);
|
|
1301
|
+
localStorage.setItem('salla_demo_lang', currentLang);
|
|
1302
|
+
|
|
1303
|
+
// Update language code and title
|
|
1304
|
+
const langCode = toggleLang.querySelector('.lang-code');
|
|
1305
|
+
const pageTitle = document.getElementById('pageTitle');
|
|
1306
|
+
langCode.textContent = currentLang === 'ar' ? 'EN' : 'AR';
|
|
1307
|
+
pageTitle.textContent = __demoTrans('title');
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// Function to update theme
|
|
1311
|
+
function updateTheme(theme) {
|
|
1312
|
+
currentTheme = theme;
|
|
1313
|
+
document.documentElement.setAttribute('data-theme', currentTheme);
|
|
1314
|
+
localStorage.setItem('salla_demo_theme', currentTheme);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
// Initialize with stored or default values
|
|
1318
|
+
updateLanguage(currentLang);
|
|
1319
|
+
updateTheme(currentTheme);
|
|
1320
|
+
|
|
1321
|
+
|
|
1322
|
+
function initSettings(){
|
|
1323
|
+
// Initialize grid settings from localStorage
|
|
1324
|
+
const savedGrid = getSavedGrid();
|
|
1325
|
+
|
|
1326
|
+
const grid = document.getElementById('componentsGrid');
|
|
1327
|
+
if (grid) {
|
|
1328
|
+
// Apply grid settings immediately
|
|
1329
|
+
if (savedGrid.columns === 'auto-fill') {
|
|
1330
|
+
// Apply special auto-fill behavior
|
|
1331
|
+
updateGridBasedOnItemCount();
|
|
1332
|
+
} else {
|
|
1333
|
+
// Apply normal grid columns
|
|
1334
|
+
grid.style.gridTemplateColumns = savedGrid.columns;
|
|
1335
|
+
}
|
|
1336
|
+
grid.style.gap = savedGrid.gap;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// Initialize grid gap inputs with saved values
|
|
1340
|
+
const gapMatch = savedGrid.gap.match(/([d.]+)([a-z%]+)/);
|
|
1341
|
+
if (gapMatch && document.getElementById('gridGapValue') && document.getElementById('gridGapUnit')) {
|
|
1342
|
+
const [_, gapValue, gapUnit] = gapMatch;
|
|
1343
|
+
document.getElementById('gridGapValue').value = gapValue;
|
|
1344
|
+
document.getElementById('gridGapUnit').value = gapUnit;
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// Initialize grid preset buttons based on saved columns
|
|
1348
|
+
const gridColumnsInput = document.getElementById('gridColumns');
|
|
1349
|
+
if (gridColumnsInput) {
|
|
1350
|
+
gridColumnsInput.value = savedGrid.columns;
|
|
1351
|
+
|
|
1352
|
+
// Set the active preset button
|
|
1353
|
+
document.querySelectorAll('.grid-preset-btn').forEach(btn => {
|
|
1354
|
+
const columns = btn.getAttribute('data-columns');
|
|
1355
|
+
if (columns === savedGrid.columns ||
|
|
1356
|
+
(columns === 'auto-fill' && savedGrid.columns === 'auto-fill') ||
|
|
1357
|
+
(columns === 'custom' && !['1', '2', '3', '4', 'auto-fill'].includes(savedGrid.columns))) {
|
|
1358
|
+
|
|
1359
|
+
// Remove active class from all buttons
|
|
1360
|
+
document.querySelectorAll('.grid-preset-btn').forEach(b => b.classList.remove('active'));
|
|
1361
|
+
// Add active class to this button
|
|
1362
|
+
btn.classList.add('active');
|
|
1363
|
+
|
|
1364
|
+
// Handle custom preset
|
|
1365
|
+
if (columns === 'custom') {
|
|
1366
|
+
gridColumnsInput.readOnly = false;
|
|
1367
|
+
gridColumnsInput.setAttribute('data-custom-value', savedGrid.columns);
|
|
1368
|
+
} else {
|
|
1369
|
+
gridColumnsInput.readOnly = true;
|
|
1370
|
+
}
|
|
1371
|
+
}
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// Apply custom CSS if saved
|
|
1376
|
+
const savedCSS = Salla.storage.get('salla_demo_custom_css', '');
|
|
1377
|
+
if (savedCSS) {
|
|
1378
|
+
const customCSSElement = document.createElement('style');
|
|
1379
|
+
customCSSElement.id = 'custom-css-element';
|
|
1380
|
+
customCSSElement.textContent = savedCSS;
|
|
1381
|
+
document.head.appendChild(customCSSElement);
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
// Apply custom JS if saved
|
|
1385
|
+
const savedJS = Salla.storage.get('salla_demo_custom_js', '');
|
|
1386
|
+
if (savedJS) {
|
|
1387
|
+
try {
|
|
1388
|
+
eval(savedJS);
|
|
1389
|
+
} catch (error) {
|
|
1390
|
+
console.error('Error executing custom JS:', error);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
// Event listeners for theme and language toggles
|
|
1395
|
+
toggleTheme.addEventListener('click', () => {
|
|
1396
|
+
updateTheme(currentTheme === 'light' ? 'dark' : 'light');
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
toggleLang.addEventListener('click', () => {
|
|
1400
|
+
updateLanguage(currentLang === 'ar' ? 'en' : 'ar');
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1403
|
+
// Settings tabs functionality
|
|
1404
|
+
document.querySelectorAll('.settings-tab-btn').forEach(tab => {
|
|
1405
|
+
tab.addEventListener('click', () => {
|
|
1406
|
+
const tabId = tab.getAttribute('data-tab');
|
|
1407
|
+
if (!tabId) return;
|
|
1408
|
+
|
|
1409
|
+
// Update active tab
|
|
1410
|
+
document.querySelectorAll('.settings-tab-btn').forEach(t => {
|
|
1411
|
+
t.classList.remove('active');
|
|
1412
|
+
});
|
|
1413
|
+
tab.classList.add('active');
|
|
1414
|
+
|
|
1415
|
+
// Update active content
|
|
1416
|
+
document.querySelectorAll('.settings-tab-content').forEach(content => {
|
|
1417
|
+
content.classList.remove('active');
|
|
1418
|
+
});
|
|
1419
|
+
document.getElementById(tabId + '-tab')?.classList.add('active');
|
|
1420
|
+
|
|
1421
|
+
// Apply settings immediately when switching tabs
|
|
1422
|
+
applySettings();
|
|
1423
|
+
});
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
// Grid preset buttons functionality
|
|
1427
|
+
document.querySelectorAll('.grid-preset-btn').forEach(btn => {
|
|
1428
|
+
btn.addEventListener('click', () => {
|
|
1429
|
+
// Remove active class from all buttons
|
|
1430
|
+
document.querySelectorAll('.grid-preset-btn').forEach(b => b.classList.remove('active'));
|
|
1431
|
+
// Add active class to clicked button
|
|
1432
|
+
btn.classList.add('active');
|
|
1433
|
+
|
|
1434
|
+
const columns = btn.getAttribute('data-columns');
|
|
1435
|
+
const gridColumns = document.getElementById('gridColumns');
|
|
1436
|
+
|
|
1437
|
+
if (gridColumns) {
|
|
1438
|
+
// If custom preset, enable input and set to custom value
|
|
1439
|
+
if (columns === 'custom') {
|
|
1440
|
+
gridColumns.readOnly = false;
|
|
1441
|
+
gridColumns.value = gridColumns.getAttribute('data-custom-value') || 'repeat(auto-fill, minmax(300px, 1fr))';
|
|
1442
|
+
}
|
|
1443
|
+
// If auto-fill preset, disable input and set special value
|
|
1444
|
+
else if (columns === 'auto-fill') {
|
|
1445
|
+
gridColumns.readOnly = true;
|
|
1446
|
+
gridColumns.value = 'auto-fill';
|
|
1447
|
+
}
|
|
1448
|
+
// For other presets, disable input and set preset value
|
|
1449
|
+
else {
|
|
1450
|
+
gridColumns.readOnly = true;
|
|
1451
|
+
gridColumns.value = columns;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
// Apply settings immediately
|
|
1456
|
+
applySettings();
|
|
1457
|
+
});
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
// Drawer functionality
|
|
1461
|
+
const componentDrawer = document.getElementById('componentDrawer');
|
|
1462
|
+
const settingsDrawer = document.getElementById('settingsDrawer');
|
|
1463
|
+
const drawerOverlay = document.getElementById('drawerOverlay');
|
|
1464
|
+
const drawerClose = componentDrawer?.querySelector('.drawer-close');
|
|
1465
|
+
const drawerReset = componentDrawer?.querySelector('.drawer-reset');
|
|
1466
|
+
const drawerTitle = componentDrawer?.querySelector('.drawer-title');
|
|
1467
|
+
const drawerContent = componentDrawer?.querySelector('.drawer-content');
|
|
1468
|
+
|
|
1469
|
+
// Function to open component drawer
|
|
1470
|
+
function openDrawer(componentName) {
|
|
1471
|
+
// Inject form builder script if it's not loaded yet
|
|
1472
|
+
if (!document.getElementById('form-builder-3-script')) {
|
|
1473
|
+
const script = document.createElement('script');
|
|
1474
|
+
script.id = 'form-builder-3-script';
|
|
1475
|
+
script.src = 'https://cdn.assets.salla.network/themes/default/temporary/form-builder-3.js';
|
|
1476
|
+
script.async = true;
|
|
1477
|
+
document.head.appendChild(script);
|
|
1478
|
+
}
|
|
1479
|
+
|
|
1480
|
+
if (drawerTitle) drawerTitle.textContent = componentName;
|
|
1481
|
+
componentDrawer?.classList.add('active');
|
|
1482
|
+
drawerOverlay?.classList.add('active');
|
|
1483
|
+
document.body.style.overflow = 'hidden';
|
|
1484
|
+
if(componentDrawer && componentDrawer.currentComponent === componentName){
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
if (componentDrawer) componentDrawer.currentComponent = componentName;
|
|
1488
|
+
const schema = schemaForComponent(componentName);
|
|
1489
|
+
|
|
1490
|
+
if(!schema){
|
|
1491
|
+
return drawerContent.innerHTML = \`
|
|
1492
|
+
<div style="padding: 2rem; text-align: center; color: #666;">
|
|
1493
|
+
<div style="margin-bottom: 1rem;">
|
|
1494
|
+
<i class="sicon-info" style="font-size: 3rem; color: #2377CD;"></i>
|
|
1495
|
+
</div>
|
|
1496
|
+
<h3 style="margin-bottom: 1rem; font-weight: 500;">\${__demoTrans('noSettings')}</h3>
|
|
1497
|
+
<p>\${__demoTrans('addSettings')}</p>
|
|
1498
|
+
<a href="/twilight-bundle.json" target="_blank">twilight-bundle.json</a>
|
|
1499
|
+
</div>
|
|
1500
|
+
\`;
|
|
1501
|
+
}
|
|
1502
|
+
const savedFormbuilder = getSavedLanguages();
|
|
1503
|
+
drawerContent.innerHTML = \`
|
|
1504
|
+
<form-builder-3
|
|
1505
|
+
form-key="form-builder-3"
|
|
1506
|
+
form-data='\${schema}'
|
|
1507
|
+
save-url="${i}"
|
|
1508
|
+
sources-url="${i}/sources"
|
|
1509
|
+
upload-url="${i}/uploader"
|
|
1510
|
+
direction="v"
|
|
1511
|
+
button="start"
|
|
1512
|
+
css-url="${r.join(",")}"
|
|
1513
|
+
language-list="\${savedFormbuilder.languages.join(',')}"
|
|
1514
|
+
default-language="\${savedFormbuilder.defaultLanguage}"
|
|
1515
|
+
submit-label="\${__demoTrans('saveSettings')}"></form-builder-3>
|
|
1516
|
+
\`;
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// Function to close drawer
|
|
1520
|
+
function closeDrawer() {
|
|
1521
|
+
document.querySelectorAll('.drawer.active').forEach(element => element.classList.remove('active'));
|
|
1522
|
+
drawerOverlay?.classList.remove('active');
|
|
1523
|
+
document.body.style.overflow = '';
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
function resetComponentSettings() {
|
|
1527
|
+
// Reset any component settings that need to be updated when form-builder settings change
|
|
1528
|
+
// Find all form-builder components and reset them
|
|
1529
|
+
const formComponents = document.querySelectorAll('[data-component-type="form-builder"]');
|
|
1530
|
+
formComponents.forEach(component => {
|
|
1531
|
+
// Trigger a reset or re-render for the component
|
|
1532
|
+
component.classList.add('settings-updated');
|
|
1533
|
+
setTimeout(() => {
|
|
1534
|
+
component.classList.remove('settings-updated');
|
|
1535
|
+
}, 1000);
|
|
1536
|
+
});
|
|
1537
|
+
|
|
1538
|
+
// Trigger custom event for components to listen to
|
|
1539
|
+
document.dispatchEvent(new CustomEvent('formbuilder-settings-changed', {
|
|
1540
|
+
detail: {
|
|
1541
|
+
timestamp: new Date().getTime()
|
|
1542
|
+
}
|
|
1543
|
+
}));
|
|
1544
|
+
|
|
1545
|
+
// Close the component drawer if it's open
|
|
1546
|
+
const componentDrawer = document.getElementById('componentDrawer');
|
|
1547
|
+
if (componentDrawer?.classList.contains('active')) {
|
|
1548
|
+
componentDrawer.classList.remove('active');
|
|
1549
|
+
document.getElementById('drawerOverlay')?.classList.remove('active');
|
|
1550
|
+
document.body.style.overflow = '';
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
// Function to reset settings and reload page
|
|
1555
|
+
function resetSettings() {
|
|
1556
|
+
if (componentDrawer && componentDrawer.currentComponent) {
|
|
1557
|
+
localStorage.removeItem('form-builder::' + componentDrawer.currentComponent);
|
|
1558
|
+
localStorage.removeItem('form-builder::data_' + componentDrawer.currentComponent);
|
|
1559
|
+
reRenderComponent(componentDrawer.currentComponent);
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
|
|
1564
|
+
// Add event listeners for drawer close and reset
|
|
1565
|
+
drawerClose.addEventListener('click', closeDrawer);
|
|
1566
|
+
drawerOverlay.addEventListener('click', closeDrawer);
|
|
1567
|
+
drawerReset.addEventListener('click', resetSettings);
|
|
1568
|
+
(async () => {
|
|
1569
|
+
async function waitForCondition(callback, timeout, interval) {
|
|
1570
|
+
const start = Date.now();
|
|
1571
|
+
|
|
1572
|
+
while (Date.now() - start < timeout) {
|
|
1573
|
+
if (callback()) {
|
|
1574
|
+
return true;
|
|
1575
|
+
}
|
|
1576
|
+
console.log('waiting for window.Salla.onReady...'+(Date.now() - start));
|
|
1577
|
+
await new Promise((resolve) => setTimeout(resolve, interval));
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
return false;
|
|
1581
|
+
}
|
|
1582
|
+
await waitForCondition(()=>window.Salla && window.Salla.onReady, 10000, 50);
|
|
1583
|
+
await window.Salla.onReady();
|
|
1584
|
+
Salla.lang.setLocale(currentLang);
|
|
1585
|
+
const hiddenComponents = Salla.storage.get('hidden-salla-components', []);
|
|
1586
|
+
Object.keys(window.customComponentsSchema || {}).forEach(name => renderComponent(name));
|
|
1587
|
+
initSettings();
|
|
1588
|
+
})();
|
|
1589
|
+
|
|
1590
|
+
<\/script>
|
|
1591
|
+
<style>${e.css}</style>
|
|
1592
|
+
<script>${e.js}<\/script>
|
|
1593
|
+
</body>
|
|
1594
|
+
</html>`;
|
|
1595
|
+
}
|
|
1596
|
+
function w(t) {
|
|
1597
|
+
t && a.existsSync(t) && a.unlinkSync(t);
|
|
1598
|
+
}
|
|
1599
|
+
function k(t) {
|
|
1600
|
+
try {
|
|
1601
|
+
const e = c.join(process.cwd(), "twilight-bundle.json"), r = JSON.parse(a.readFileSync(e, "utf-8")).components.find((s) => s.name === t);
|
|
1602
|
+
return r != null && r.fields ? (r.fields.push({
|
|
1603
|
+
type: "string",
|
|
1604
|
+
format: "hidden",
|
|
1605
|
+
id: "twilight-bundles-component-name",
|
|
1606
|
+
value: t
|
|
1607
|
+
}), JSON.stringify(r == null ? void 0 : r.fields)) : "";
|
|
1608
|
+
} catch (e) {
|
|
1609
|
+
return console.error("Error getting schema for component:", e), "";
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
function B(t = {}) {
|
|
1613
|
+
let e;
|
|
1614
|
+
return {
|
|
1615
|
+
name: "salla-component-demo",
|
|
1616
|
+
enforce: "pre",
|
|
1617
|
+
configResolved(o) {
|
|
1618
|
+
var g, p, b, f, v, h;
|
|
1619
|
+
if ((g = o.server) != null && g.open)
|
|
1620
|
+
return;
|
|
1621
|
+
const r = I();
|
|
1622
|
+
let s = t.components ? Object.fromEntries(
|
|
1623
|
+
Object.entries(r).filter(([d]) => t.components.includes(d))
|
|
1624
|
+
) : r;
|
|
1625
|
+
const l = ".salla-temp", n = c.resolve(process.cwd(), "node_modules", l), C = Object.entries(s).map(function([d, u]) {
|
|
1626
|
+
var y, S;
|
|
1627
|
+
const x = (y = o.server) != null && y.port ? u.replace(process.cwd(), `http://localhost:${(S = o.server) == null ? void 0 : S.port}`) : u, E = k(d);
|
|
1628
|
+
return { name: d, path: u, url: x, schema: E };
|
|
1629
|
+
});
|
|
1630
|
+
a.existsSync(n) || a.mkdirSync(n, { recursive: !0 }), e = c.resolve(n, "index.html"), a.writeFileSync(e, G(C, {
|
|
1631
|
+
grid: {
|
|
1632
|
+
columns: ((p = t.grid) == null ? void 0 : p.columns) || "repeat(auto-fill, minmax(300px, 1fr))",
|
|
1633
|
+
gap: ((b = t.grid) == null ? void 0 : b.gap) || "1rem",
|
|
1634
|
+
minWidth: ((f = t.grid) == null ? void 0 : f.minWidth) || "300px"
|
|
1635
|
+
},
|
|
1636
|
+
css: t.css || "",
|
|
1637
|
+
js: t.js || "",
|
|
1638
|
+
formbuilder: {
|
|
1639
|
+
languages: ((v = t.formbuilder) == null ? void 0 : v.languages) || ["ar", "en"],
|
|
1640
|
+
defaultLanguage: ((h = t.formbuilder) == null ? void 0 : h.defaultLanguage) || "ar"
|
|
1641
|
+
}
|
|
1642
|
+
}));
|
|
1643
|
+
const m = () => {
|
|
1644
|
+
w(e);
|
|
1645
|
+
try {
|
|
1646
|
+
a.rmdirSync(n);
|
|
1647
|
+
} catch {
|
|
1648
|
+
}
|
|
1649
|
+
};
|
|
1650
|
+
process.on("SIGINT", m), process.on("SIGTERM", m), process.on("exit", m), o.server.open = `/node_modules/${l}/index.html`;
|
|
1651
|
+
},
|
|
1652
|
+
configureServer(o) {
|
|
1653
|
+
},
|
|
1654
|
+
config(o) {
|
|
1655
|
+
return {
|
|
1656
|
+
...o,
|
|
1657
|
+
server: {
|
|
1658
|
+
...o.server,
|
|
1659
|
+
watch: {
|
|
1660
|
+
usePolling: !0,
|
|
1661
|
+
interval: 100
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
},
|
|
1666
|
+
closeBundle() {
|
|
1667
|
+
w(e);
|
|
1668
|
+
const o = c.resolve(process.cwd(), "node_modules/.salla-temp");
|
|
1669
|
+
try {
|
|
1670
|
+
a.rmdirSync(o);
|
|
1671
|
+
} catch {
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
};
|
|
1675
|
+
}
|
|
1676
|
+
export {
|
|
1677
|
+
B as sallaDemoPlugin
|
|
1678
|
+
};
|