@squeditor/squeditor-framework 1.0.2 → 1.0.4
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 +22 -31
- package/package.json +1 -1
- package/php/functions.php +45 -0
- package/project-template/package.json +3 -1
- package/project-template/squeditor.config.js +21 -9
- package/project-template/src/assets/js/_slider_dynamic.js +2 -0
- package/project-template/src/assets/js/gsap-init.js +28 -1
- package/project-template/src/assets/js/main.js +1 -0
- package/project-template/src/assets/js/modules/splide-init.js +207 -0
- package/project-template/src/assets/js/modules/swiper-init.js +216 -0
- package/project-template/src/assets/js/uikit-components.js +27 -21
- package/project-template/src/assets/scss/_base.scss +0 -9
- package/project-template/src/assets/scss/_components.scss +107 -2
- package/project-template/src/assets/scss/_swiper.scss +30 -0
- package/project-template/src/assets/scss/main.scss +2 -1
- package/project-template/src/assets/scss/themes/_two.scss +95 -0
- package/project-template/src/assets/static/images/og-default.png +0 -0
- package/project-template/src/assets/static/images/placeholder.png +0 -0
- package/project-template/src/index.php +5 -5
- package/project-template/src/init.php +38 -2
- package/project-template/src/page-templates/head.php +9 -1
- package/project-template/src/slider-test.php +87 -0
- package/project-template/src/template-parts/header.php +11 -11
- package/project-template/tailwind.config.js +29 -1
- package/scripts/build-components.js +78 -1
- package/scripts/copy-static.js +26 -0
- package/scripts/dev-router.php +10 -1
- package/scripts/dev.js +30 -1
- package/scripts/package-customer.js +52 -21
- package/scripts/package-dist.js +1 -1
- package/scripts/scaffold.js +4 -3
- package/scripts/snapshot.js +134 -33
- package/scripts/utils/resolve-pages.js +47 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import Swiper from 'swiper';
|
|
2
|
+
import { Navigation, Pagination, Autoplay, Parallax, Thumbs, EffectFade, FreeMode } from 'swiper/modules';
|
|
3
|
+
|
|
4
|
+
// Swiper CSS is handled separately by build-components.js → slider.min.css
|
|
5
|
+
|
|
6
|
+
function splitTopLevel(str, delimiters = [';', ',']) {
|
|
7
|
+
const result = [];
|
|
8
|
+
let current = '';
|
|
9
|
+
let braceDepth = 0;
|
|
10
|
+
|
|
11
|
+
for (let i = 0; i < str.length; i++) {
|
|
12
|
+
const char = str[i];
|
|
13
|
+
if (char === '{') braceDepth++;
|
|
14
|
+
if (char === '}') braceDepth--;
|
|
15
|
+
|
|
16
|
+
if (braceDepth === 0 && delimiters.includes(char)) {
|
|
17
|
+
result.push(current);
|
|
18
|
+
current = '';
|
|
19
|
+
} else {
|
|
20
|
+
current += char;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (current) result.push(current);
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Parses a string like "slidesPerView: 1; md: {slidesPerView: 3}; loop: true"
|
|
29
|
+
* into a valid JavaScript object.
|
|
30
|
+
*/
|
|
31
|
+
function parseSwiperOptions(optionString) {
|
|
32
|
+
if (!optionString) return {};
|
|
33
|
+
|
|
34
|
+
const options = {};
|
|
35
|
+
const statements = splitTopLevel(optionString, [';', ',']);
|
|
36
|
+
|
|
37
|
+
statements.forEach(statement => {
|
|
38
|
+
statement = statement.trim();
|
|
39
|
+
if (!statement) return;
|
|
40
|
+
|
|
41
|
+
const firstColon = statement.indexOf(':');
|
|
42
|
+
if (firstColon > -1) {
|
|
43
|
+
const key = statement.slice(0, firstColon).trim();
|
|
44
|
+
let rawValue = statement.slice(firstColon + 1).trim();
|
|
45
|
+
|
|
46
|
+
// Handle nested objects
|
|
47
|
+
if (rawValue.startsWith('{') && rawValue.endsWith('}')) {
|
|
48
|
+
const innerString = rawValue.slice(1, -1);
|
|
49
|
+
options[key] = parseSwiperOptions(innerString);
|
|
50
|
+
} else {
|
|
51
|
+
options[key] = parsePrimitive(rawValue);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return options;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function parsePrimitive(val) {
|
|
60
|
+
if (val === 'true') return true;
|
|
61
|
+
if (val === 'false') return false;
|
|
62
|
+
if (val === 'null') return null;
|
|
63
|
+
|
|
64
|
+
// Check if it's a number
|
|
65
|
+
if (!isNaN(vanillaParseFloat(val))) {
|
|
66
|
+
return vanillaParseFloat(val);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Remove wrapping quotes if they exist
|
|
70
|
+
if ((val.startsWith("'") && val.endsWith("'")) || (val.startsWith('"') && val.endsWith('"'))) {
|
|
71
|
+
return val.slice(1, -1);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return val;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function vanillaParseFloat(val) {
|
|
78
|
+
if(typeof val === 'string' && val.trim() === '') return NaN;
|
|
79
|
+
return Number(val);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Maps Tailwind breakpoints to Swiper breakpoints
|
|
84
|
+
*/
|
|
85
|
+
function mapBreakpoints(options) {
|
|
86
|
+
const swiperBreakpoints = {};
|
|
87
|
+
const tailwindScreens = {
|
|
88
|
+
'sm': 640,
|
|
89
|
+
'md': 768,
|
|
90
|
+
'lg': 1024,
|
|
91
|
+
'xl': 1280,
|
|
92
|
+
'2xl': 1536
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
let hasBreakpoints = false;
|
|
96
|
+
|
|
97
|
+
// 1. Move root-level 'sm', 'md' directly into swiperBreakpoints
|
|
98
|
+
Object.keys(tailwindScreens).forEach(screen => {
|
|
99
|
+
if (options[screen]) {
|
|
100
|
+
hasBreakpoints = true;
|
|
101
|
+
swiperBreakpoints[tailwindScreens[screen]] = options[screen];
|
|
102
|
+
delete options[screen]; // Remove from root options
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
// 2. Process nested options.breakpoints if it exists
|
|
107
|
+
if (options.breakpoints) {
|
|
108
|
+
hasBreakpoints = true;
|
|
109
|
+
Object.keys(options.breakpoints).forEach(key => {
|
|
110
|
+
if (tailwindScreens[key]) {
|
|
111
|
+
swiperBreakpoints[tailwindScreens[key]] = options.breakpoints[key];
|
|
112
|
+
} else {
|
|
113
|
+
swiperBreakpoints[key] = options.breakpoints[key];
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (hasBreakpoints && Object.keys(swiperBreakpoints).length > 0) {
|
|
119
|
+
options.breakpoints = swiperBreakpoints;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return options;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Initializes Swiper instance for a single element
|
|
127
|
+
*/
|
|
128
|
+
function initSwiperElement(el) {
|
|
129
|
+
// Prevent double initialization
|
|
130
|
+
if (el.swiper) return;
|
|
131
|
+
|
|
132
|
+
const rawOptions = el.getAttribute('data-sq-swiper') || '';
|
|
133
|
+
let parsedOptions = parseSwiperOptions(rawOptions);
|
|
134
|
+
parsedOptions = mapBreakpoints(parsedOptions);
|
|
135
|
+
|
|
136
|
+
// Default Configuration
|
|
137
|
+
const config = {
|
|
138
|
+
modules: [Navigation, Pagination, Autoplay, Parallax, Thumbs, EffectFade, FreeMode],
|
|
139
|
+
speed: 600,
|
|
140
|
+
// Optional navigation
|
|
141
|
+
navigation: {},
|
|
142
|
+
// Optional pagination
|
|
143
|
+
pagination: {
|
|
144
|
+
clickable: true
|
|
145
|
+
},
|
|
146
|
+
...parsedOptions
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Apply custom detached navigation if specified
|
|
150
|
+
if (parsedOptions.navNext || parsedOptions.navPrev) {
|
|
151
|
+
config.navigation = {
|
|
152
|
+
nextEl: parsedOptions.navNext || null,
|
|
153
|
+
prevEl: parsedOptions.navPrev || null
|
|
154
|
+
};
|
|
155
|
+
// Clean up root
|
|
156
|
+
delete config.navNext;
|
|
157
|
+
delete config.navPrev;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Apply custom detached pagination if specified
|
|
161
|
+
if (parsedOptions.paginationEl) {
|
|
162
|
+
config.pagination = {
|
|
163
|
+
el: parsedOptions.paginationEl,
|
|
164
|
+
clickable: true,
|
|
165
|
+
type: parsedOptions.paginationType || 'bullets'
|
|
166
|
+
};
|
|
167
|
+
delete config.paginationEl;
|
|
168
|
+
delete config.paginationType;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Handle Thumbs Gallery synchronization
|
|
172
|
+
if (parsedOptions.thumbs) {
|
|
173
|
+
const thumbTarget = document.querySelector(parsedOptions.thumbs);
|
|
174
|
+
if (thumbTarget) {
|
|
175
|
+
// First, ensure the thumb target is initialized
|
|
176
|
+
if (!thumbTarget.swiper) {
|
|
177
|
+
initSwiperElement(thumbTarget);
|
|
178
|
+
}
|
|
179
|
+
config.thumbs = {
|
|
180
|
+
swiper: thumbTarget.swiper
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Ensure slider has basic class structure required by CSS
|
|
186
|
+
if (!el.classList.contains('swiper')) {
|
|
187
|
+
el.classList.add('swiper');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const wrapper = el.querySelector(':scope > div');
|
|
191
|
+
if (wrapper && !wrapper.classList.contains('swiper-wrapper')) {
|
|
192
|
+
wrapper.classList.add('swiper-wrapper');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const slides = wrapper ? wrapper.children : el.children;
|
|
196
|
+
Array.from(slides).forEach(slide => {
|
|
197
|
+
if (!slide.classList.contains('swiper-slide')) {
|
|
198
|
+
slide.classList.add('swiper-slide');
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Initialize!
|
|
203
|
+
new Swiper(el, config);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Global Initialization
|
|
208
|
+
*/
|
|
209
|
+
export function initSwiper() {
|
|
210
|
+
const swipers = document.querySelectorAll('[data-sq-swiper]');
|
|
211
|
+
swipers.forEach(initSwiperElement);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
215
|
+
initSwiper();
|
|
216
|
+
});
|