@squeditor/squeditor-framework 1.0.1 → 1.0.3
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 +7 -15
- package/package.json +1 -1
- 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/_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/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 +18 -5
- package/scripts/snapshot.js +134 -33
- package/scripts/utils/resolve-pages.js +47 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* Swiper framework overrides */
|
|
2
|
+
.swiper {
|
|
3
|
+
--swiper-theme-color: var(--sq-color-primary, #000);
|
|
4
|
+
--swiper-navigation-size: 20px;
|
|
5
|
+
|
|
6
|
+
&-pagination-bullet {
|
|
7
|
+
background: var(--sq-color-primary, #000);
|
|
8
|
+
opacity: 0.3;
|
|
9
|
+
transition: all 0.3s ease;
|
|
10
|
+
|
|
11
|
+
&-active {
|
|
12
|
+
opacity: 1;
|
|
13
|
+
width: 24px;
|
|
14
|
+
border-radius: 4px;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
&-button-next,
|
|
19
|
+
&-button-prev {
|
|
20
|
+
transition: all 0.3s ease;
|
|
21
|
+
&:hover {
|
|
22
|
+
transform: translateY(-50%) scale(1.05);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
&.swiper-button-disabled {
|
|
26
|
+
opacity: 0;
|
|
27
|
+
pointer-events: none;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// two.scss
|
|
2
|
+
$sq-color-primary: #21169a;
|
|
3
|
+
$sq-color-secondary: #f5590b;
|
|
4
|
+
$sq-color-accent: #f59e0b;
|
|
5
|
+
$sq-color-muted-text: #272164;
|
|
6
|
+
$sq-color-muted-bg: #e4e2de;
|
|
7
|
+
$sq-color-light: #e4e2de;
|
|
8
|
+
$sq-color-body-bg: #f4f1eb;
|
|
9
|
+
$sq-color-body-text: #201a63;
|
|
10
|
+
$sq-color-heading-text: #272164;
|
|
11
|
+
|
|
12
|
+
.theme-two {
|
|
13
|
+
--sq-color-primary: #{$sq-color-primary};
|
|
14
|
+
--sq-color-primary-contrast: #{sq-color-contrast($sq-color-primary, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
15
|
+
--sq-color-secondary: #{$sq-color-secondary};
|
|
16
|
+
--sq-color-secondary-contrast: #{sq-color-contrast($sq-color-secondary, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
17
|
+
--sq-color-accent: #{$sq-color-accent};
|
|
18
|
+
--sq-color-accent-contrast: #{sq-color-contrast($sq-color-accent, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
19
|
+
--sq-color-muted-text: #{$sq-color-muted-text};
|
|
20
|
+
--sq-color-muted-bg: #{$sq-color-muted-bg};
|
|
21
|
+
--sq-color-light: #{$sq-color-light};
|
|
22
|
+
--sq-color-body-bg: #{$sq-color-body-bg};
|
|
23
|
+
--sq-color-body-text: #{$sq-color-body-text};
|
|
24
|
+
--sq-color-heading-text: #{$sq-color-heading-text};
|
|
25
|
+
--sq-font-sans: 'TASA Orbiter', sans-serif;
|
|
26
|
+
--sq-font-heading: 'TASA Orbiter', sans-serif;
|
|
27
|
+
--sq-radius-lg: 32px;
|
|
28
|
+
|
|
29
|
+
// Page Transitions
|
|
30
|
+
--sq-page-transition-from: var(--sq-color-secondary);
|
|
31
|
+
--sq-page-transition-via: var(--sq-color-accent);
|
|
32
|
+
--sq-page-transition-to: var(--sq-color-accent);
|
|
33
|
+
|
|
34
|
+
// Explicit overrides
|
|
35
|
+
--sq-btn-primary-bg: var(--sq-color-primary);
|
|
36
|
+
--sq-btn-primary-text: var(--sq-color-primary-contrast);
|
|
37
|
+
--sq-btn-secondary-bg: var(--sq-color-secondary);
|
|
38
|
+
--sq-btn-secondary-text: var(--sq-color-secondary-contrast);
|
|
39
|
+
--sq-btn-accent-bg: var(--sq-color-accent);
|
|
40
|
+
--sq-btn-accent-text: var(--sq-color-accent-contrast);
|
|
41
|
+
--sq-form-focus-border: var(--sq-color-secondary);
|
|
42
|
+
|
|
43
|
+
h1,
|
|
44
|
+
h2,
|
|
45
|
+
h3,
|
|
46
|
+
h4,
|
|
47
|
+
h5,
|
|
48
|
+
h6 {
|
|
49
|
+
font-family: var(--sq-font-heading);
|
|
50
|
+
letter-spacing: -0.04em;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.btn {
|
|
54
|
+
--sq-btn-radius: 50rem;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
@apply selection:bg-secondary selection:text-black;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.theme-two.sq-theme-dark {
|
|
61
|
+
$sq-color-primary-dark: #16239a;
|
|
62
|
+
$sq-color-secondary-dark: #ffc156;
|
|
63
|
+
$sq-color-accent-dark: #f59e0b;
|
|
64
|
+
$sq-color-muted-text: #c4d3d3;
|
|
65
|
+
$sq-color-muted-bg: #202052;
|
|
66
|
+
$sq-color-body-bg: #181843;
|
|
67
|
+
$sq-color-body-text: #c4d3d3;
|
|
68
|
+
$sq-color-heading-text: #ffffff;
|
|
69
|
+
|
|
70
|
+
--sq-color-primary: #{$sq-color-primary-dark};
|
|
71
|
+
--sq-color-primary-contrast: #{sq-color-contrast($sq-color-primary-dark, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
72
|
+
--sq-color-secondary: #{$sq-color-secondary-dark};
|
|
73
|
+
--sq-color-secondary-contrast: #{sq-color-contrast($sq-color-secondary-dark, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
74
|
+
--sq-color-accent: #{$sq-color-accent-dark};
|
|
75
|
+
--sq-color-accent-contrast: #{sq-color-contrast($sq-color-accent-dark, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
76
|
+
|
|
77
|
+
--sq-color-primary: #{$sq-color-primary-dark};
|
|
78
|
+
--sq-color-primary-contrast: #{sq-color-contrast($sq-color-primary-dark, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
79
|
+
--sq-color-secondary: #{$sq-color-secondary-dark};
|
|
80
|
+
--sq-color-secondary-contrast: #{sq-color-contrast($sq-color-secondary-dark, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
81
|
+
--sq-color-accent: #{$sq-color-accent-dark};
|
|
82
|
+
--sq-color-accent-contrast: #{sq-color-contrast($sq-color-accent-dark, $sq-contrast-light-text, $sq-contrast-dark-text, $sq-min-contrast-ratio)};
|
|
83
|
+
|
|
84
|
+
--sq-color-muted-text: #{$sq-color-muted-text};
|
|
85
|
+
--sq-color-muted-bg: #{$sq-color-muted-bg};
|
|
86
|
+
|
|
87
|
+
--sq-color-body-bg: #{$sq-color-body-bg};
|
|
88
|
+
--sq-color-body-text: #{$sq-color-body-text};
|
|
89
|
+
--sq-color-heading-text: #{$sq-color-heading-text};
|
|
90
|
+
|
|
91
|
+
--sq-sticky-bg: #{$sq-color-muted-bg};
|
|
92
|
+
--sq-sticky-text: #{$sq-color-body-text};
|
|
93
|
+
|
|
94
|
+
--sq-card-bg: #{$sq-color-body-bg};
|
|
95
|
+
}
|
|
Binary file
|
|
Binary file
|
|
@@ -30,17 +30,17 @@ ob_start();
|
|
|
30
30
|
?>
|
|
31
31
|
|
|
32
32
|
<section class="py-32 md:py-48 flex items-center justify-center bg-gradient-to-b from-zinc-100 to-transparent" data-uk-height-viewport="offset-top: true">
|
|
33
|
-
<div class="max-w-4xl mx-auto px-6 text-center">
|
|
33
|
+
<div class="max-w-4xl mx-auto px-6 text-center" data-gsap-timeline="{defaults: {duration: 1.2, ease: 'power4.out', delay: 0.8}}">
|
|
34
34
|
|
|
35
|
-
<h2 class="text-6xl font-bold tracking-tight mb-8 lg:px-8">
|
|
36
|
-
Start building<span class="
|
|
35
|
+
<h2 class="text-6xl font-bold tracking-tight mb-8 lg:px-8" data-gsap="from: {y: 60, opacity: 0, filter: 'blur(20px)'}">
|
|
36
|
+
Start building <span class="bg-gradient-to-r from-zinc-500 via-zinc-400 to-zinc-200 text-transparent bg-clip-text">creative websites</span> with Squeditor
|
|
37
37
|
</h2>
|
|
38
38
|
|
|
39
|
-
<p class="text-xl text-muted max-w-2xl mx-auto font-light leading-relaxed mb-12">
|
|
39
|
+
<p class="text-xl text-muted max-w-2xl mx-auto font-light leading-relaxed mb-12" data-gsap="position: '<-0.5'; from: {y: 40, opacity: 0, filter: 'blur(10px)'}">
|
|
40
40
|
You can now begin creating interactive GSAP experiences, modifying the UIKit configuration, and adding content to your template files.
|
|
41
41
|
</p>
|
|
42
42
|
|
|
43
|
-
<div class="flex items-center justify-center gap-4">
|
|
43
|
+
<div class="flex items-center justify-center gap-4" data-gsap="position: '<-0.5'; from: {y: 20, opacity: 0, filter: 'blur(5px)'}">
|
|
44
44
|
<a href="https://squeditor.com/" class="btn btn-lg btn-secondary !px-8 !py-3 !rounded-full text-white font-medium hover:scale-105 transition-transform">
|
|
45
45
|
Try Squeditor
|
|
46
46
|
</a>
|
|
@@ -11,9 +11,45 @@ require_once __DIR__ . '/config/site-config.php';
|
|
|
11
11
|
define('SRC_PATH', __DIR__);
|
|
12
12
|
|
|
13
13
|
// Global Theme & Schema Detection
|
|
14
|
-
$active_theme = $_GET['theme'] ??
|
|
14
|
+
$active_theme = $_GET['theme'] ?? null;
|
|
15
15
|
$active_schema = $_GET['schema'] ?? 'light';
|
|
16
16
|
|
|
17
|
+
if (!$active_theme) {
|
|
18
|
+
if (file_exists(__DIR__ . '/config/active-themes.php')) {
|
|
19
|
+
require_once __DIR__ . '/config/active-themes.php';
|
|
20
|
+
|
|
21
|
+
$current_uri = $_SERVER['REQUEST_URI'] ?? '/';
|
|
22
|
+
$path_only = parse_url($current_uri, PHP_URL_PATH);
|
|
23
|
+
|
|
24
|
+
// Strip trailing slash except for root
|
|
25
|
+
if ($path_only !== '/' && substr($path_only, -1) === '/') {
|
|
26
|
+
$path_only = rtrim($path_only, '/');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Normalize .html requests to .php for config matching
|
|
30
|
+
if (substr($path_only, -5) === '.html') {
|
|
31
|
+
$path_only = substr($path_only, 0, -5) . '.php';
|
|
32
|
+
}
|
|
33
|
+
// Normalize extensionless requests to .php for config matching
|
|
34
|
+
elseif ($path_only !== '/' && !pathinfo($path_only, PATHINFO_EXTENSION)) {
|
|
35
|
+
$path_only .= '.php';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check exact match, also check matching without leading slash
|
|
39
|
+
$path_no_slash = ltrim($path_only, '/');
|
|
40
|
+
|
|
41
|
+
if (isset($active_themes[$path_only])) {
|
|
42
|
+
$active_theme = $active_themes[$path_only];
|
|
43
|
+
} elseif (isset($active_themes[$path_no_slash])) {
|
|
44
|
+
$active_theme = $active_themes[$path_no_slash];
|
|
45
|
+
} else {
|
|
46
|
+
$active_theme = 'default';
|
|
47
|
+
}
|
|
48
|
+
} else {
|
|
49
|
+
$active_theme = 'default';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
17
53
|
// Add to site config for template access
|
|
18
54
|
$site['theme'] = $active_theme;
|
|
19
|
-
$site['schema'] = $active_schema;
|
|
55
|
+
$site['schema'] = $active_schema;
|
|
@@ -13,6 +13,12 @@ if (!$is_snapshot) {
|
|
|
13
13
|
fclose($fp);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
+
|
|
17
|
+
// Load slider config for conditional CSS loading
|
|
18
|
+
$active_slider = false;
|
|
19
|
+
if (file_exists(__DIR__ . '/../config/active-slider.php')) {
|
|
20
|
+
require_once __DIR__ . '/../config/active-slider.php';
|
|
21
|
+
}
|
|
16
22
|
?>
|
|
17
23
|
<meta charset="UTF-8">
|
|
18
24
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
@@ -36,6 +42,7 @@ if (!$is_snapshot) {
|
|
|
36
42
|
<script type="module" src="<?= $vite_server ?>/@vite/client"></script>
|
|
37
43
|
<link rel="stylesheet" href="<?= $vite_server ?>/assets/css/tailwind.css">
|
|
38
44
|
<link rel="stylesheet" href="<?= $vite_server ?>/assets/css/squeditor-icons.css">
|
|
45
|
+
<?php if ($active_slider): ?><link rel="stylesheet" href="<?= $vite_server ?>/assets/css/slider.min.css"><?php endif; ?>
|
|
39
46
|
<script type="module" src="<?= $vite_server ?>/assets/scss/main.scss"></script>
|
|
40
47
|
<style>html.js-fouc { opacity: 0; transition: opacity 0.15s ease-out; }</style>
|
|
41
48
|
<script>document.documentElement.classList.add('js-fouc');</script>
|
|
@@ -43,5 +50,6 @@ if (!$is_snapshot) {
|
|
|
43
50
|
<!-- Production Static Assets -->
|
|
44
51
|
<link rel="stylesheet" href="assets/css/squeditor-icons.css">
|
|
45
52
|
<link rel="stylesheet" href="assets/css/tailwind.css">
|
|
46
|
-
|
|
53
|
+
<?php if ($active_slider): ?><link rel="stylesheet" href="assets/css/slider.min.css"><?php endif; ?>
|
|
54
|
+
<link rel="stylesheet" href="assets/css/main.min.css">
|
|
47
55
|
<?php endif; ?>
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/pages/swiper-test.php
|
|
3
|
+
require_once __DIR__ . '/init.php';
|
|
4
|
+
|
|
5
|
+
// Content
|
|
6
|
+
ob_start();
|
|
7
|
+
?>
|
|
8
|
+
|
|
9
|
+
<main id="main-content">
|
|
10
|
+
<section class="py-24">
|
|
11
|
+
<div class="max-w-7xl mx-auto px-6">
|
|
12
|
+
<h1 class="text-4xl md:text-5xl font-bold mb-4 text-center">Multi-Slider Architecture</h1>
|
|
13
|
+
<p class="text-lg text-muted text-center max-w-2xl mx-auto mb-16">
|
|
14
|
+
Test the dynamic library injection framework. Switch between <code>swiper</code> and <code>splide</code> in your <code>squeditor.config.js</code> to see Vite dynamically bundle the correct dependencies or set <code>false</code> to disable it!
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
<!-- Splide Test -->
|
|
18
|
+
<div class="mb-16 border-t pt-16">
|
|
19
|
+
<div class="flex items-center justify-between">
|
|
20
|
+
<h2 class="text-2xl font-bold mb-6">Splide Slider</h2>
|
|
21
|
+
<p class="text-xs font-mono uppercase tracking-widest text-muted mb-4">Requires <code class="text-xs">slider: { library: 'splide' }</code> -> squeditor.config.js</p>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="splide" data-splide='{
|
|
24
|
+
"type" : "blurfade",
|
|
25
|
+
"perMove" : 1,
|
|
26
|
+
"gap" : 16,
|
|
27
|
+
"autoplay" : true,
|
|
28
|
+
"interval" : 3000,
|
|
29
|
+
"pagination" : true,
|
|
30
|
+
"breakpoints": {
|
|
31
|
+
"1024": { "perPage": 1, "gap": "1rem" },
|
|
32
|
+
"768" : { "perPage": 1, "gap": "0.75rem" },
|
|
33
|
+
"480" : { "perPage": 1, "arrows": false }
|
|
34
|
+
}
|
|
35
|
+
}'>
|
|
36
|
+
<div class="splide__track">
|
|
37
|
+
<ul class="splide__list">
|
|
38
|
+
<?php for($i=1; $i<=6; $i++): ?>
|
|
39
|
+
<li class="splide__slide">
|
|
40
|
+
<div class="bg-muted text-dark h-full min-h-[24rem] rounded-2xl flex items-center justify-center text-2xl font-bold">Slide <?= $i ?></div>
|
|
41
|
+
</li>
|
|
42
|
+
<?php endfor; ?>
|
|
43
|
+
</ul>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<style>
|
|
49
|
+
.splide__pagination__page.is-active {
|
|
50
|
+
background: var(--sq-color-primary);
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
53
|
+
|
|
54
|
+
<!-- Demo 1: Basic Responsive Grid -->
|
|
55
|
+
<div class="mb-8 border-t pt-16 mt-16">
|
|
56
|
+
<div class="flex items-center justify-between">
|
|
57
|
+
<h2 class="text-2xl font-bold mb-6">Swiper Slider</h2>
|
|
58
|
+
<p class="text-xs font-mono uppercase tracking-widest text-muted mb-4">Requires <code class="text-xs">slider: { library: 'swiper' }</code> -> squeditor.config.js</p>
|
|
59
|
+
</div>
|
|
60
|
+
<div class="swiper rounded-2xl overflow-hidden shadow-sm"
|
|
61
|
+
data-sq-swiper="
|
|
62
|
+
slidesPerView: 1;
|
|
63
|
+
spaceBetween: 20;
|
|
64
|
+
breakpoints: {
|
|
65
|
+
sm: { slidesPerView: 2 },
|
|
66
|
+
md: { slidesPerView: 3 },
|
|
67
|
+
lg: { slidesPerView: 4 }
|
|
68
|
+
}"
|
|
69
|
+
>
|
|
70
|
+
<div class="swiper-wrapper">
|
|
71
|
+
<?php for($i=1; $i<=6; $i++): ?>
|
|
72
|
+
<div class="swiper-slide">
|
|
73
|
+
<div class="bg-muted text-dark aspect-square rounded-2xl flex items-center justify-center text-2xl font-bold">Slide <?= $i ?></div>
|
|
74
|
+
</div>
|
|
75
|
+
<?php endfor; ?>
|
|
76
|
+
</div>
|
|
77
|
+
<div class="swiper-pagination mt-6 relative !bottom-0 pb-4"></div>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
</div>
|
|
82
|
+
</section>
|
|
83
|
+
</main>
|
|
84
|
+
|
|
85
|
+
<?php
|
|
86
|
+
$content = ob_get_clean();
|
|
87
|
+
require SRC_PATH . '/page-templates/base.php';
|
|
@@ -11,15 +11,15 @@ if ($layout !== 'default') {
|
|
|
11
11
|
}
|
|
12
12
|
?>
|
|
13
13
|
<!-- Site Header -->
|
|
14
|
-
<header id="sq_header" class="sq--header absolute w-full top-0 z-[1000]" data-
|
|
14
|
+
<header id="sq_header" class="sq--header absolute w-full top-0 z-[1000] bg-white dark:bg-zinc-900" data-gsap="from: {y: -80, opacity: 0}; to: {y: 0, opacity: 1}; duration: 1.2; ease: expo.inOut;">
|
|
15
15
|
<div class="sq--header--inner max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
|
16
16
|
|
|
17
17
|
<!-- Logo -->
|
|
18
18
|
<a href="index.html" class="sq--logo flex items-center gap-2 group">
|
|
19
19
|
<div class="w-8 h-8 sq-bg-secondary rounded-lg flex items-center justify-center transition-transform group-hover:scale-110">
|
|
20
|
-
<i class="sq-icon-
|
|
20
|
+
<i class="sq-icon-waves"></i>
|
|
21
21
|
</div>
|
|
22
|
-
<h1 class="font-bold text-xl m-0 tracking-tight
|
|
22
|
+
<h1 class="font-bold text-xl m-0 tracking-tight"><?= htmlspecialchars($site['name']) ?></h1>
|
|
23
23
|
</a>
|
|
24
24
|
|
|
25
25
|
<!-- Desktop Nav (Centered) -->
|
|
@@ -30,11 +30,11 @@ if ($layout !== 'default') {
|
|
|
30
30
|
<!-- Right Side / CTA -->
|
|
31
31
|
<div class="sq--header--cta flex items-center gap-6">
|
|
32
32
|
<a href="#" class="sq-nav-link text-base font-medium text-zinc-900 dark:text-white !text-opacity-70 hover:text-secondary hover:!text-opacity-100 transition-colors hidden md:inline-block">Log in</a>
|
|
33
|
-
<a href="https://squeditor.com/" class="btn btn-secondary">Try Squeditor</a>
|
|
33
|
+
<a href="https://squeditor.com/" class="btn btn-secondary !hidden md:!inline-flex">Try Squeditor</a>
|
|
34
34
|
|
|
35
35
|
<!-- Mobile Toggle -->
|
|
36
|
-
<button class="sq--header--mobile--toggle md:hidden" data-
|
|
37
|
-
<span data-uk-icon="icon: menu; ratio: 1"></span>
|
|
36
|
+
<button class="sq--header--mobile--toggle md:hidden" data-gsap-toggle="#sq_offcanvas_creative" type="button" aria-label="Menu">
|
|
37
|
+
<span data-uk-icon="icon: menu; ratio: 1.5"></span>
|
|
38
38
|
</button>
|
|
39
39
|
</div>
|
|
40
40
|
</div>
|
|
@@ -48,18 +48,18 @@ if ($layout !== 'default') {
|
|
|
48
48
|
</div>
|
|
49
49
|
|
|
50
50
|
<!-- Creative Offcanvas -->
|
|
51
|
-
<div id="
|
|
51
|
+
<div id="sq_offcanvas_creative" class="sq-offcanvas-creative fixed inset-0 z-[9999] pointer-events-none text-zinc-600 shadow-2xl" style="visibility: hidden" data-gsap-timeline="{paused: true}">
|
|
52
52
|
|
|
53
53
|
<!-- Backdrop Overlay -->
|
|
54
|
-
<div class="sq-offcanvas-creative--close fixed inset-0 z-10 pointer-events-auto bg-black/50 backdrop-blur-md" data-gsap-reverse="#
|
|
54
|
+
<div class="sq-offcanvas-creative--close fixed inset-0 z-10 pointer-events-auto bg-black/50 backdrop-blur-md" data-gsap-reverse="#sq_offcanvas_creative" data-gsap="position: '<'; from: {autoAlpha: 0, duration: 0.25, ease: 'power3.out'}"></div>
|
|
55
55
|
|
|
56
56
|
<!-- Offcanvas Background Panel -->
|
|
57
|
-
<div class="absolute top-0 left-0 w-full md:w-1/3 h-full bg-white shadow-2xl flex flex-col items-start justify-start z-20 pointer-events-auto" data-gsap="from: {xPercent: -100, duration: 0.6, ease: 'power4.inOut'}" data-sq-cursor-color="#4f46e5">
|
|
57
|
+
<div class="absolute top-0 left-0 w-full md:w-1/3 h-full bg-white shadow-2xl flex flex-col items-start justify-start z-20 pointer-events-auto" data-gsap="position: '-=0.3'; from: {xPercent: -100, duration: 0.6, ease: 'power4.inOut'}" data-sq-cursor-color="#4f46e5">
|
|
58
58
|
|
|
59
59
|
<!-- Header -->
|
|
60
60
|
<div class="flex items-center justify-between w-full p-6 lg:p-12" data-gsap="from: {yPercent: -20, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
61
61
|
<a href="#" class="sq-logo text-xl font-bold text-zinc-900" data-sq-cursor-stick>Squeditor</a>
|
|
62
|
-
<button data-gsap-reverse="#
|
|
62
|
+
<button data-gsap-reverse="#sq_offcanvas_creative" class="opacity-50 hover:opacity-100 transition-opacity" data-sq-cursor-stick>
|
|
63
63
|
<span data-uk-icon="icon: close; ratio: 1.5"></span>
|
|
64
64
|
</button>
|
|
65
65
|
</div>
|
|
@@ -117,4 +117,4 @@ if ($layout !== 'default') {
|
|
|
117
117
|
</a>
|
|
118
118
|
</div>
|
|
119
119
|
</div>
|
|
120
|
-
</div>
|
|
120
|
+
</div>
|
|
@@ -6,6 +6,7 @@ const projectRoot = process.cwd();
|
|
|
6
6
|
const config = require(path.join(projectRoot, 'squeditor.config.js'));
|
|
7
7
|
const fwRoot = path.resolve(projectRoot, config.framework); // resolves ..
|
|
8
8
|
const manifest = require(path.join(fwRoot, 'uikit-manifest.json'));
|
|
9
|
+
const resolvePages = require('./utils/resolve-pages');
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
const selectedComponents = config.components || [];
|
|
@@ -82,12 +83,34 @@ console.log(` Components included: _core, ${selectedComponents.join(', ')}`);
|
|
|
82
83
|
// Generate src/config/active-components.php for the style-guide page
|
|
83
84
|
const phpConfigDir = path.join(projectRoot, 'src/config');
|
|
84
85
|
fs.mkdirSync(phpConfigDir, { recursive: true });
|
|
85
|
-
const
|
|
86
|
+
const phpComponentsArray = `[${selectedComponents.map(c => `'${c}'`).join(', ')}]`;
|
|
87
|
+
const phpConfig = `<?php\n// Auto-generated by build-components.js — DO NOT EDIT\n$active_components = ${phpComponentsArray};\n`;
|
|
86
88
|
fs.writeFileSync(
|
|
87
89
|
path.join(phpConfigDir, 'active-components.php'),
|
|
88
90
|
phpConfig
|
|
89
91
|
);
|
|
90
92
|
|
|
93
|
+
// Generate src/config/active-themes.php for automatic PHP dev server theme detection
|
|
94
|
+
// Map each page to its corresponding theme identifier
|
|
95
|
+
const themePageMapping = {};
|
|
96
|
+
if (config.themes) {
|
|
97
|
+
Object.keys(config.themes).forEach(themeKey => {
|
|
98
|
+
const rawPages = config.themes[themeKey].pages || [];
|
|
99
|
+
const absolutePages = resolvePages(rawPages, projectRoot);
|
|
100
|
+
absolutePages.forEach(page => {
|
|
101
|
+
// Clean leading slashes for normalization if desired, but here we just map exact values
|
|
102
|
+
themePageMapping[page] = themeKey;
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const phpThemesArrayParts = Object.entries(themePageMapping).map(([page, theme]) => `'${page}' => '${theme}'`);
|
|
107
|
+
const phpThemesConfig = `<?php\n// Auto-generated by build-components.js — DO NOT EDIT\n$active_themes = [${phpThemesArrayParts.join(', ')}];\n`;
|
|
108
|
+
fs.writeFileSync(
|
|
109
|
+
path.join(phpConfigDir, 'active-themes.php'),
|
|
110
|
+
phpThemesConfig
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
|
|
91
114
|
// Inject all themes into main.scss so live-switching works in the Style Guide
|
|
92
115
|
const mainScssPath = path.join(projectRoot, 'src/assets/scss/main.scss');
|
|
93
116
|
if (fs.existsSync(mainScssPath) && config.themes) {
|
|
@@ -107,3 +130,57 @@ if (fs.existsSync(mainScssPath) && config.themes) {
|
|
|
107
130
|
fs.writeFileSync(mainScssPath, mainScss);
|
|
108
131
|
console.log(`[Squeditor] 🎨 Injected themes: ${Object.keys(config.themes).join(', ')}`);
|
|
109
132
|
}
|
|
133
|
+
|
|
134
|
+
// Generate Dynamic Slider Config Import
|
|
135
|
+
const sliderConfig = config.slider || { library: false };
|
|
136
|
+
const dynamicSliderPath = path.join(outputJsDir, '_slider_dynamic.js');
|
|
137
|
+
let sliderImportCode = '// Auto-generated by build-components.js — DO NOT EDIT\n';
|
|
138
|
+
if (sliderConfig.library === 'swiper') {
|
|
139
|
+
sliderImportCode += 'import \'./modules/swiper-init.js\';\n';
|
|
140
|
+
} else if (sliderConfig.library === 'splide') {
|
|
141
|
+
sliderImportCode += 'import \'./modules/splide-init.js\';\n';
|
|
142
|
+
}
|
|
143
|
+
fs.writeFileSync(dynamicSliderPath, sliderImportCode);
|
|
144
|
+
console.log(`[Squeditor] 🎠 Injected slider library: ${sliderConfig.library || 'none'}`);
|
|
145
|
+
|
|
146
|
+
// Copy slider library CSS to src/assets/css/slider.min.css
|
|
147
|
+
// This keeps the CSS separate from main.js and gives it a clear, descriptive filename
|
|
148
|
+
const sliderCssDest = path.join(projectRoot, 'src/assets/css/slider.min.css');
|
|
149
|
+
if (sliderConfig.library === 'splide') {
|
|
150
|
+
const splideCssPath = path.join(projectRoot, 'node_modules/@splidejs/splide/dist/css/splide.min.css');
|
|
151
|
+
if (fs.existsSync(splideCssPath)) {
|
|
152
|
+
fs.copyFileSync(splideCssPath, sliderCssDest);
|
|
153
|
+
console.log('[Squeditor] 📎 Copied Splide CSS → src/assets/css/slider.min.css');
|
|
154
|
+
} else {
|
|
155
|
+
console.warn('[Squeditor] ⚠️ Splide CSS not found at expected path.');
|
|
156
|
+
fs.writeFileSync(sliderCssDest, '/* Splide CSS not found */\n');
|
|
157
|
+
}
|
|
158
|
+
} else if (sliderConfig.library === 'swiper') {
|
|
159
|
+
// Concatenate all Swiper CSS modules into a single file
|
|
160
|
+
const swiperCssParts = [
|
|
161
|
+
'node_modules/swiper/swiper.min.css',
|
|
162
|
+
'node_modules/swiper/modules/navigation.min.css',
|
|
163
|
+
'node_modules/swiper/modules/pagination.min.css',
|
|
164
|
+
'node_modules/swiper/modules/effect-fade.min.css',
|
|
165
|
+
'node_modules/swiper/modules/free-mode.min.css',
|
|
166
|
+
];
|
|
167
|
+
let combinedCss = '/* Swiper CSS - auto-generated by build-components.js */\n';
|
|
168
|
+
for (const part of swiperCssParts) {
|
|
169
|
+
const fullPath = path.join(projectRoot, part);
|
|
170
|
+
if (fs.existsSync(fullPath)) {
|
|
171
|
+
combinedCss += fs.readFileSync(fullPath, 'utf8') + '\n';
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
fs.writeFileSync(sliderCssDest, combinedCss);
|
|
175
|
+
console.log('[Squeditor] 📎 Copied Swiper CSS → src/assets/css/slider.min.css');
|
|
176
|
+
} else {
|
|
177
|
+
// No slider configured — write an empty placeholder so head.php link doesn't 404
|
|
178
|
+
fs.writeFileSync(sliderCssDest, '/* No slider library configured */\n');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Generate src/config/active-slider.php for conditional CSS loading in head.php
|
|
182
|
+
const phpSliderConfig = `<?php\n// Auto-generated by build-components.js — DO NOT EDIT\n$active_slider = ${sliderConfig.library ? `'${sliderConfig.library}'` : 'false'};\n`;
|
|
183
|
+
fs.writeFileSync(
|
|
184
|
+
path.join(phpConfigDir, 'active-slider.php'),
|
|
185
|
+
phpSliderConfig
|
|
186
|
+
);
|
package/scripts/copy-static.js
CHANGED
|
@@ -145,6 +145,32 @@ async function run() {
|
|
|
145
145
|
} else {
|
|
146
146
|
console.warn(`[Squeditor] ⚠️ Source directory for static assets not found: ${srcDir}`);
|
|
147
147
|
}
|
|
148
|
+
|
|
149
|
+
// Post-Vite-build CSS renaming for clearer dist output
|
|
150
|
+
const distCssDir = path.join(projectRoot, config.snapshot.outputDir, 'assets/css');
|
|
151
|
+
|
|
152
|
+
// Rename main_css.css → main.min.css (SCSS entry output)
|
|
153
|
+
const mainCssSrc = path.join(distCssDir, 'main_css.css');
|
|
154
|
+
const mainCssDest = path.join(distCssDir, 'main.min.css');
|
|
155
|
+
if (fs.existsSync(mainCssSrc)) {
|
|
156
|
+
fs.renameSync(mainCssSrc, mainCssDest);
|
|
157
|
+
console.log('[Squeditor] 📎 Renamed main_css.css → main.min.css');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Remove stale main.css (previously contained CSS-in-JS extracted by Vite, now handled separately)
|
|
161
|
+
const staleMainCss = path.join(distCssDir, 'main.css');
|
|
162
|
+
if (fs.existsSync(staleMainCss)) {
|
|
163
|
+
fs.unlinkSync(staleMainCss);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Copy slider.min.css to dist (generated by build-components.js)
|
|
167
|
+
const sliderCssSrc = path.join(projectRoot, 'src/assets/css/slider.min.css');
|
|
168
|
+
const sliderCssDest = path.join(distCssDir, 'slider.min.css');
|
|
169
|
+
if (fs.existsSync(sliderCssSrc)) {
|
|
170
|
+
fs.mkdirSync(distCssDir, { recursive: true });
|
|
171
|
+
fs.copyFileSync(sliderCssSrc, sliderCssDest);
|
|
172
|
+
console.log('[Squeditor] 📎 Copied slider.min.css → dist/assets/css/');
|
|
173
|
+
}
|
|
148
174
|
}
|
|
149
175
|
|
|
150
176
|
run();
|
package/scripts/dev-router.php
CHANGED
|
@@ -19,5 +19,14 @@ if (preg_match('/\.html$/', $uri)) {
|
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
// 3.
|
|
22
|
+
// 3. If it is an extensionless request, route it to the equivalent PHP file
|
|
23
|
+
if ($uri !== '/' && !pathinfo($uri, PATHINFO_EXTENSION)) {
|
|
24
|
+
$php_file = $uri . '.php';
|
|
25
|
+
if (file_exists($doc_root . $php_file)) {
|
|
26
|
+
require $doc_root . $php_file;
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 4. Let PHP's core handle index.php fallback for directories or 404s
|
|
23
32
|
return false;
|
package/scripts/dev.js
CHANGED
|
@@ -23,6 +23,18 @@ async function startDev() {
|
|
|
23
23
|
fwRoot = config.framework;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
|
|
27
|
+
// Run build-components.js BEFORE starting servers to ensure
|
|
28
|
+
// active-themes.php, _uikit_dynamic.scss, _slider_dynamic.js etc. exist on first request
|
|
29
|
+
const buildComponentsPath = path.join(fwRoot, 'scripts/build-components.js');
|
|
30
|
+
console.log('[Squeditor] 🔧 Building dynamic components...');
|
|
31
|
+
const { execSync } = require('child_process');
|
|
32
|
+
try {
|
|
33
|
+
execSync(`node "${buildComponentsPath}"`, { stdio: 'inherit', cwd: projectRoot });
|
|
34
|
+
} catch (e) {
|
|
35
|
+
console.error('[Squeditor] ❌ Failed to build dynamic components:', e.message);
|
|
36
|
+
}
|
|
37
|
+
|
|
26
38
|
const devRouterPath = path.join(fwRoot, 'scripts/dev-router.php');
|
|
27
39
|
|
|
28
40
|
// Start PHP Server
|
|
@@ -35,7 +47,6 @@ async function startDev() {
|
|
|
35
47
|
env: { ...process.env, SQUEDITOR_PHP_PORT: phpPort, SQUEDITOR_VITE_PORT: vitePort }
|
|
36
48
|
});
|
|
37
49
|
|
|
38
|
-
// Start Vite
|
|
39
50
|
const vite = spawn('npx', [
|
|
40
51
|
'vite',
|
|
41
52
|
'--port', vitePort.toString(),
|
|
@@ -45,6 +56,24 @@ async function startDev() {
|
|
|
45
56
|
env: { ...process.env, SQUEDITOR_PHP_PORT: phpPort, SQUEDITOR_VITE_PORT: vitePort }
|
|
46
57
|
});
|
|
47
58
|
|
|
59
|
+
// Watch squeditor.config.js for changes and rebuild dynamic components
|
|
60
|
+
if (fs.existsSync(configPath)) {
|
|
61
|
+
let rebuildTimeout;
|
|
62
|
+
fs.watch(configPath, (eventType) => {
|
|
63
|
+
if (eventType === 'change') {
|
|
64
|
+
// Debounce to prevent multiple triggers from IDE saves
|
|
65
|
+
clearTimeout(rebuildTimeout);
|
|
66
|
+
rebuildTimeout = setTimeout(() => {
|
|
67
|
+
console.log(`\n[Squeditor] 🔄 Config changed. Rebuilding dynamic components...`);
|
|
68
|
+
const buildScript = spawn('node', [path.join(fwRoot, 'scripts/build-components.js')], { stdio: 'inherit' });
|
|
69
|
+
buildScript.on('close', (code) => {
|
|
70
|
+
if (code === 0) console.log(`[Squeditor] ✨ Rebuild complete! (Vite will hot-reload automatically)`);
|
|
71
|
+
});
|
|
72
|
+
}, 300);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
48
77
|
process.on('SIGINT', () => {
|
|
49
78
|
php.kill();
|
|
50
79
|
vite.kill();
|