@squeditor/squeditor-framework 1.0.3 → 1.0.5
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 -28
- package/package.json +2 -1
- package/php/functions.php +45 -0
- package/project-template/src/assets/css/fonts.css +2 -0
- package/project-template/src/assets/scss/_base.scss +4 -11
- package/project-template/src/assets/scss/_components.scss +101 -3
- package/project-template/src/assets/scss/_tokens.scss +18 -13
- package/project-template/src/config/site-config.php +1 -0
- package/project-template/src/index.php +2 -2
- package/project-template/src/page-templates/head.php +3 -1
- package/project-template/src/sections/cards/cards-horizontal.php +1 -1
- package/project-template/src/sections/cta/cta-banner.php +1 -1
- package/project-template/src/sections/cta/cta-newsletter.php +1 -1
- package/project-template/src/sections/header/layout-01.php +1 -1
- package/project-template/src/sections/hero/hero-split.php +4 -4
- package/project-template/src/template-parts/footer.php +6 -6
- package/project-template/src/template-parts/header.php +5 -5
- package/project-template/src/template-parts/nav.php +2 -2
- package/project-template/src/template-parts/page-title-bar.php +1 -1
- package/project-template/tailwind.config.js +29 -1
- package/project-template/vite.config.js +8 -0
- package/scripts/build-components.js +3 -6
- package/scripts/scaffold.js +30 -9
package/README.md
CHANGED
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
**Squeditor Framework** is a high-performance, developer-first framework for building lightning-fast, static websites. It combines the power of **PHP-style templating** with the modern performance of **Tailwind CSS**, the interactivity of **UIKit 3**, and the speed of **Vite**.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
We implement AI Agents skills to help you build your website easily in minutes. You can use AI Agents to generate well organized and clean code, components, sections, and pages and ship landing pages and saas and agency websites 10x faster.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
### Showcase and Demo
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
[Main Demo](https://squeditor.com/showcase/main-demo/) |
|
|
8
|
+
[All Components](https://squeditor.com/showcase/all-components/) |
|
|
9
|
+
[Style Guide](https://squeditor.com/showcase/style-guide/) |
|
|
10
|
+
[GSAP Animations](https://squeditor.com/showcase/gsap-animations/)
|
|
9
11
|
|
|
10
|
-
|
|
11
|
-
Stop loading massive component libraries. Squeditor Framework uses a **Component Manifest System** (via `uikit-manifest.json`) to tree-shake UIKit. Use only what you need (like a Slider or Modal) and Squeditor Framework will automatically bundle just the necessary SCSS and JS.
|
|
12
|
+
[Full Documentation](https://docs.squeditor.com/framework/getting-started/introduction)
|
|
12
13
|
|
|
13
|
-
###
|
|
14
|
-
Fully themeable via a centralized Design Token system (`_tokens.scss`). Every component and layout utility consumes CSS Custom Properties (`--sq-*`), allowing you to swap entire visual identities or color schemas (Light/Dark) instantly across the site.
|
|
14
|
+
### Key Features
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
-
|
|
22
|
-
- **Cards**: Grids, Horizontal, Feature lists
|
|
23
|
-
- **CTA**: Split, Banner, In-line
|
|
24
|
-
- **Global**: Responsive Header, Deep-linked Footer
|
|
25
|
-
|
|
26
|
-
### 📖 Automatic Style Guide
|
|
27
|
-
Every project includes an automatically generated `style-guide.php` page that renders every active component and its variants, serving as your project's living documentation.
|
|
16
|
+
- Zero-Runtime PHP Templating
|
|
17
|
+
- Selective UIKit 3 Integration
|
|
18
|
+
- Token-Based Styling Architecture
|
|
19
|
+
- Built-in Light/Dark Mode
|
|
20
|
+
- Section-Based Workflow
|
|
21
|
+
- Automatic Style Guide
|
|
28
22
|
|
|
29
23
|
---
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
### Project Architecture
|
|
32
26
|
|
|
33
27
|
```bash
|
|
34
28
|
[workspace-root]/
|
|
@@ -40,9 +34,9 @@ Every project includes an automatically generated `style-guide.php` page that re
|
|
|
40
34
|
|
|
41
35
|
---
|
|
42
36
|
|
|
43
|
-
|
|
37
|
+
### Getting Started
|
|
44
38
|
|
|
45
|
-
|
|
39
|
+
#### 1. Scaffold a New Project
|
|
46
40
|
Squeditor includes a robust CLI scaffolding tool. It generates a completely clean, minimalist project instance fully pre-configured to utilize the advanced GSAP and UIKit engines without demo bloat.
|
|
47
41
|
|
|
48
42
|
To scaffold your new project, simply run the following command in your terminal:
|
|
@@ -51,7 +45,7 @@ npx @squeditor/squeditor-framework your-project-name
|
|
|
51
45
|
```
|
|
52
46
|
*(Replace `your-project-name` with your desired folder name).*
|
|
53
47
|
|
|
54
|
-
|
|
48
|
+
#### 2. Development
|
|
55
49
|
Navigate into your newly generated project folder, install its dependencies, and start the development server:
|
|
56
50
|
```bash
|
|
57
51
|
cd your-project-name
|
|
@@ -64,7 +58,7 @@ npm run dev
|
|
|
64
58
|
> Vite will show a link to `http://127.0.0.1:5173/` in your terminal. **Do not use that link.**
|
|
65
59
|
> Instead, always visit the PHP Server address: **`http://127.0.0.1:3001`**. This is because Squeditor Framework uses PHP for template rendering, and Vite only serves the static assets.
|
|
66
60
|
|
|
67
|
-
|
|
61
|
+
#### 3. Build for Production
|
|
68
62
|
Generate the static `dist/` folder and a distributable ZIP archive:
|
|
69
63
|
```bash
|
|
70
64
|
npm run build
|
|
@@ -72,7 +66,7 @@ npm run build
|
|
|
72
66
|
|
|
73
67
|
---
|
|
74
68
|
|
|
75
|
-
|
|
69
|
+
### Technology Stack
|
|
76
70
|
|
|
77
71
|
- **Dev Engine**: PHP 8.2+ (as a templating pre-processor)
|
|
78
72
|
- **CSS Architecture**: Tailwind CSS + SCSS (Layered Overrides)
|
|
@@ -83,13 +77,13 @@ npm run build
|
|
|
83
77
|
|
|
84
78
|
---
|
|
85
79
|
|
|
86
|
-
|
|
80
|
+
### Contributing
|
|
87
81
|
|
|
88
82
|
We welcome contributions! Whether it's adding new section variants, improving the build pipeline, or refining the token system, feel free to open a PR.
|
|
89
83
|
|
|
90
84
|
---
|
|
91
85
|
|
|
92
|
-
|
|
86
|
+
### License
|
|
93
87
|
|
|
94
88
|
Squeditor Framework is released under the [MIT License](LICENSE).
|
|
95
89
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squeditor/squeditor-framework",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Squeditor Framework is a high-performance, developer-first framework for building lightning-fast, static websites. It combines the power of PHP-style templating with the modern performance of Tailwind CSS, the interactivity of UIKit 3, and the speed of Vite.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
|
+
"scaffold": "node scripts/scaffold.js",
|
|
10
11
|
"test": "echo \"Error: no test specified\" && exit 1"
|
|
11
12
|
},
|
|
12
13
|
"repository": {
|
package/php/functions.php
CHANGED
|
@@ -90,3 +90,48 @@ function parse_frontmatter(string $file): array {
|
|
|
90
90
|
}
|
|
91
91
|
return [];
|
|
92
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Load an asset file's contents directly (e.g., for inline SVG).
|
|
96
|
+
*
|
|
97
|
+
* @param string $path Path relative to src/assets/, e.g., 'static/icons/vite.svg'
|
|
98
|
+
* @return string File contents or empty string if not found
|
|
99
|
+
*/
|
|
100
|
+
function get_asset(string $path): string {
|
|
101
|
+
$full_path = SRC_PATH . '/assets/' . ltrim($path, '/');
|
|
102
|
+
if (!file_exists($full_path)) {
|
|
103
|
+
trigger_error("Asset not found: {$full_path}", E_USER_WARNING);
|
|
104
|
+
return '';
|
|
105
|
+
}
|
|
106
|
+
return file_get_contents($full_path);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Load an image file's contents directly (e.g., for inline SVG images) or return an <img> tag.
|
|
111
|
+
*
|
|
112
|
+
* @param string $filename Filename inside src/assets/static/images/, e.g., 'logo.svg'
|
|
113
|
+
* @param string $alt Alt text for the image (if returning an <img> tag)
|
|
114
|
+
* @param string $class Custom CSS class(es) to add to the <img> tag
|
|
115
|
+
* @param bool $inline Whether to return raw file contents (e.g. inline SVG). Default false.
|
|
116
|
+
* @return string Image tag or file contents, or empty string if not found
|
|
117
|
+
*/
|
|
118
|
+
function get_image(string $filename, string $alt = '', string $class = '', bool $inline = false): string {
|
|
119
|
+
$full_path = SRC_PATH . '/assets/static/images/' . ltrim($filename, '/');
|
|
120
|
+
if (!file_exists($full_path)) {
|
|
121
|
+
trigger_error("Image not found: {$full_path}", E_USER_WARNING);
|
|
122
|
+
return '';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if ($inline) {
|
|
126
|
+
return file_get_contents($full_path);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// We assume images are served from /assets/static/images/ relative to document root
|
|
130
|
+
// This path might need to be adjusted based on the server setup, but for now
|
|
131
|
+
// it returns a relative web path.
|
|
132
|
+
$web_path = '/assets/static/images/' . ltrim($filename, '/');
|
|
133
|
+
|
|
134
|
+
$class_attr = $class !== '' ? sprintf(' class="%s"', htmlspecialchars($class)) : '';
|
|
135
|
+
|
|
136
|
+
return sprintf('<img src="%s" alt="%s"%s>', htmlspecialchars($web_path), htmlspecialchars($alt), $class_attr);
|
|
137
|
+
}
|
|
@@ -24,16 +24,8 @@ h6,
|
|
|
24
24
|
font-family: var(--sq-font-heading);
|
|
25
25
|
color: var(--sq-color-heading-text);
|
|
26
26
|
font-weight: 600;
|
|
27
|
-
line-height: 1.2;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
h1,
|
|
31
|
-
h2,
|
|
32
|
-
h3,
|
|
33
|
-
h4,
|
|
34
|
-
h5,
|
|
35
|
-
h6 {
|
|
36
|
-
margin-bottom: 0.75em;
|
|
27
|
+
line-height: var(--sq-heading-line-height, 1.2);
|
|
28
|
+
letter-spacing: var(--sq-heading-letter-spacing, normal);
|
|
37
29
|
}
|
|
38
30
|
|
|
39
31
|
h1 {
|
|
@@ -84,7 +76,8 @@ h6 {
|
|
|
84
76
|
// Only apply paragraph and list styles if the author didn't supply their own layout classes
|
|
85
77
|
p:not([class]) {
|
|
86
78
|
margin-bottom: 1rem;
|
|
87
|
-
line-height: 1.6;
|
|
79
|
+
line-height: var(--sq-body-line-height, 1.6);
|
|
80
|
+
letter-spacing: var(--sq-body-letter-spacing, normal);
|
|
88
81
|
}
|
|
89
82
|
|
|
90
83
|
ul:not([class]),
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
font-size: var(--sq-btn-font-size);
|
|
11
11
|
font-weight: var(--sq-btn-font-weight);
|
|
12
12
|
|
|
13
|
-
@apply inline-flex items-center justify-center gap-2 py-0 px-4 transition-
|
|
13
|
+
@apply inline-flex items-center justify-center gap-2 py-0 px-4 transition-all duration-200 cursor-pointer outline-none no-underline;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
.btn-sm {
|
|
@@ -18,8 +18,13 @@
|
|
|
18
18
|
height: 2rem;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
.btn-md {
|
|
22
|
+
@apply text-base px-4;
|
|
23
|
+
height: 2.5rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
21
26
|
.btn-lg {
|
|
22
|
-
@apply text-
|
|
27
|
+
@apply text-base px-6;
|
|
23
28
|
height: 3rem;
|
|
24
29
|
}
|
|
25
30
|
|
|
@@ -110,7 +115,7 @@
|
|
|
110
115
|
}
|
|
111
116
|
}
|
|
112
117
|
|
|
113
|
-
.sq
|
|
118
|
+
.sq-header {
|
|
114
119
|
z-index: var(--sq-z-sticky);
|
|
115
120
|
|
|
116
121
|
&--sticky {
|
|
@@ -125,6 +130,99 @@
|
|
|
125
130
|
}
|
|
126
131
|
}
|
|
127
132
|
|
|
133
|
+
// ---------------------------------------------------------
|
|
134
|
+
// Container + Expand Container
|
|
135
|
+
// ---------------------------------------------------------
|
|
136
|
+
.container {
|
|
137
|
+
width: 100%;
|
|
138
|
+
|
|
139
|
+
@screen sm { max-width: 540px; }
|
|
140
|
+
@screen md { max-width: 720px; }
|
|
141
|
+
@screen lg { max-width: 960px; }
|
|
142
|
+
@screen xl { max-width: 1140px; }
|
|
143
|
+
@screen 2xl { max-width: 1280px; }
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* Base breakout — expands equally both sides */
|
|
147
|
+
.expand-container {
|
|
148
|
+
--scroll-width: var(--body-scroll-width, 17px);
|
|
149
|
+
--expand-size: calc((100vw - var(--scroll-width) - 100%) / -2);
|
|
150
|
+
margin-right: var(--expand-size);
|
|
151
|
+
margin-left: var(--expand-size);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.expand-container-end {
|
|
155
|
+
--scroll-width: var(--body-scroll-width, 17px);
|
|
156
|
+
/* Use width increase instead of negative margin */
|
|
157
|
+
--expand-size: calc((100vw - var(--scroll-width) - 100%) / 2);
|
|
158
|
+
width: calc(100% + var(--expand-size));
|
|
159
|
+
overflow: visible; /* let image overflow naturally */
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.expand-container-start {
|
|
163
|
+
--scroll-width: var(--body-scroll-width, 17px);
|
|
164
|
+
--expand-size: calc((100vw - var(--scroll-width) - 100%) / 2);
|
|
165
|
+
width: calc(100% + var(--expand-size));
|
|
166
|
+
margin-left: calc(var(--expand-size) * -1);
|
|
167
|
+
overflow: visible;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ---------------------------------------------------------
|
|
171
|
+
// Form icon group
|
|
172
|
+
// ---------------------------------------------------------
|
|
173
|
+
/* Base */
|
|
174
|
+
.form-icon-group {
|
|
175
|
+
position: relative;
|
|
176
|
+
display: flex;
|
|
177
|
+
flex-wrap: wrap;
|
|
178
|
+
align-items: stretch;
|
|
179
|
+
width: 100%;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.form-icon-group .form-icon {
|
|
183
|
+
display: inline-flex;
|
|
184
|
+
align-items: center;
|
|
185
|
+
justify-content: center;
|
|
186
|
+
position: absolute;
|
|
187
|
+
height: 100%;
|
|
188
|
+
background: transparent;
|
|
189
|
+
border: 0;
|
|
190
|
+
outline: 0;
|
|
191
|
+
text-decoration: none;
|
|
192
|
+
user-select: none;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/* Icon widths based on input size */
|
|
196
|
+
.form-icon-group .form-control + .form-icon { width: 3rem !important; }
|
|
197
|
+
.form-icon-group .form-control.form-control-lg + .form-icon { width: 3.5rem !important; }
|
|
198
|
+
.form-icon-group .form-control.form-control-sm + .form-icon { width: 2.5rem !important; }
|
|
199
|
+
.form-icon-group .form-control.form-control-xs + .form-icon { width: 2rem !important; }
|
|
200
|
+
|
|
201
|
+
/* Icon on the LEFT (default) */
|
|
202
|
+
.form-icon-group:not(.form-icon-flip) .form-control { padding-left: 2.75rem !important; }
|
|
203
|
+
.form-icon-group:not(.form-icon-flip) .form-control.form-control-lg { padding-left: 3.25rem !important; }
|
|
204
|
+
.form-icon-group:not(.form-icon-flip) .form-control.form-control-sm { padding-left: 2.25rem !important; }
|
|
205
|
+
.form-icon-group:not(.form-icon-flip) .form-control.form-control-xs { padding-left: 1.75rem !important; }
|
|
206
|
+
|
|
207
|
+
/* RTL — icon on the LEFT */
|
|
208
|
+
[dir="rtl"] .form-icon-group:not(.form-icon-flip) .form-control { padding-left: 1rem !important; padding-right: 2.75rem !important; }
|
|
209
|
+
[dir="rtl"] .form-icon-group:not(.form-icon-flip) .form-control.form-control-lg { padding-left: 1rem !important; padding-right: 3.25rem !important; }
|
|
210
|
+
[dir="rtl"] .form-icon-group:not(.form-icon-flip) .form-control.form-control-sm { padding-left: 1rem !important; padding-right: 2.25rem !important; }
|
|
211
|
+
[dir="rtl"] .form-icon-group:not(.form-icon-flip) .form-control.form-control-xs { padding-left: 1rem !important; padding-right: 1.75rem !important; }
|
|
212
|
+
|
|
213
|
+
/* Icon on the RIGHT (flip) */
|
|
214
|
+
.form-icon-group.form-icon-flip .form-icon { right: 0; }
|
|
215
|
+
.form-icon-group.form-icon-flip .form-control { padding-right: 2.75rem !important; }
|
|
216
|
+
.form-icon-group.form-icon-flip .form-control.form-control-lg { padding-right: 3.25rem !important; }
|
|
217
|
+
.form-icon-group.form-icon-flip .form-control.form-control-sm { padding-right: 2.25rem !important; }
|
|
218
|
+
.form-icon-group.form-icon-flip .form-control.form-control-xs { padding-right: 1.75rem !important; }
|
|
219
|
+
|
|
220
|
+
/* RTL — icon on the RIGHT (flip) */
|
|
221
|
+
[dir="rtl"] .form-icon-group.form-icon-flip .form-control { padding-right: 1rem !important; padding-left: 2.75rem !important; }
|
|
222
|
+
[dir="rtl"] .form-icon-group.form-icon-flip .form-control.form-control-lg { padding-right: 1rem !important; padding-left: 3.25rem !important; }
|
|
223
|
+
[dir="rtl"] .form-icon-group.form-icon-flip .form-control.form-control-sm { padding-right: 1rem !important; padding-left: 2.25rem !important; }
|
|
224
|
+
[dir="rtl"] .form-icon-group.form-icon-flip .form-control.form-control-xs { padding-right: 1rem !important; padding-left: 1.75rem !important; }
|
|
225
|
+
|
|
128
226
|
// ---------------------------------------------------------
|
|
129
227
|
// Page Transitions
|
|
130
228
|
// ---------------------------------------------------------
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
// _tokens.scss — Design tokens as CSS custom properties
|
|
2
2
|
|
|
3
3
|
// 1. Define SASS Variables for calculations
|
|
4
|
-
$color-primary: #
|
|
5
|
-
$color-primary-dark: #
|
|
6
|
-
$color-secondary: #
|
|
7
|
-
$color-secondary-dark: #
|
|
8
|
-
$color-accent: #
|
|
9
|
-
$color-accent-dark: #
|
|
4
|
+
$color-primary: #107466 !default;
|
|
5
|
+
$color-primary-dark: #F0FF44 !default;
|
|
6
|
+
$color-secondary: #1c2020 !default;
|
|
7
|
+
$color-secondary-dark: #fef1e7 !default;
|
|
8
|
+
$color-accent: #e5fdc5 !default;
|
|
9
|
+
$color-accent-dark: #e5fdc5 !default;
|
|
10
10
|
$color-white: #FFFFFF !default;
|
|
11
|
-
$color-muted-text: #
|
|
12
|
-
$color-muted-bg: #
|
|
11
|
+
$color-muted-text: #707070 !default;
|
|
12
|
+
$color-muted-bg: #fef1e7 !default;
|
|
13
13
|
$color-light: #f8f8f8 !default;
|
|
14
|
+
$color-dark: #19191b !default;
|
|
14
15
|
$color-body-bg: #FFFFFF !default;
|
|
15
16
|
$color-body-text: #19191b !default;
|
|
16
17
|
$color-heading-text: #19191b !default;
|
|
@@ -28,6 +29,7 @@ $color-border: rgba(138, 138, 138, 0.196) !default;
|
|
|
28
29
|
--sq-color-muted-text: #{$color-muted-text};
|
|
29
30
|
--sq-color-muted-bg: #{$color-muted-bg};
|
|
30
31
|
--sq-color-light: #{$color-light};
|
|
32
|
+
--sq-color-dark: #{$color-dark};
|
|
31
33
|
--sq-color-body-bg: #{$color-body-bg};
|
|
32
34
|
--sq-color-body-text: #{$color-body-text};
|
|
33
35
|
--sq-color-heading-text: #{$color-heading-text};
|
|
@@ -76,12 +78,12 @@ $color-border: rgba(138, 138, 138, 0.196) !default;
|
|
|
76
78
|
// --- Component Tokens ---
|
|
77
79
|
|
|
78
80
|
// Buttons
|
|
79
|
-
--sq-btn-height: 2.
|
|
81
|
+
--sq-btn-height: 2.75rem;
|
|
80
82
|
--sq-btn-bg: transparent;
|
|
81
83
|
--sq-btn-text: var(--sq-color-body-text);
|
|
82
|
-
--sq-btn-radius: var(--sq-radius-
|
|
83
|
-
--sq-btn-font-size: 1rem;
|
|
84
|
-
--sq-btn-font-weight:
|
|
84
|
+
--sq-btn-radius: var(--sq-radius-md);
|
|
85
|
+
--sq-btn-font-size: 1rem;
|
|
86
|
+
--sq-btn-font-weight: 600;
|
|
85
87
|
|
|
86
88
|
--sq-btn-default-bg: var(--sq-color-light);
|
|
87
89
|
--sq-btn-default-text: var(--sq-color-muted-text);
|
|
@@ -113,7 +115,7 @@ $color-border: rgba(138, 138, 138, 0.196) !default;
|
|
|
113
115
|
// Dropdown
|
|
114
116
|
--sq-dropdown-width: 300px;
|
|
115
117
|
--sq-dropdown-padding: 2rem;
|
|
116
|
-
--sq-dropdown-bg: var(--sq-color-
|
|
118
|
+
--sq-dropdown-bg: var(--sq-color-muted-bg);
|
|
117
119
|
--sq-dropdown-text: var(--sq-color-body-text);
|
|
118
120
|
|
|
119
121
|
// Accordion
|
|
@@ -226,4 +228,7 @@ $color-border: rgba(138, 138, 138, 0.196) !default;
|
|
|
226
228
|
--sq-card-bg: #19191b;
|
|
227
229
|
--sq-card-shadow: none;
|
|
228
230
|
--sq-card-shadow-hover: none;
|
|
231
|
+
|
|
232
|
+
// Dropdown
|
|
233
|
+
--sq-dropdown-bg: var(--sq-color-muted-bg);
|
|
229
234
|
}
|
|
@@ -41,10 +41,10 @@ ob_start();
|
|
|
41
41
|
</p>
|
|
42
42
|
|
|
43
43
|
<div class="flex items-center justify-center gap-4" data-gsap="position: '<-0.5'; from: {y: 20, opacity: 0, filter: 'blur(5px)'}">
|
|
44
|
-
<a href="https://squeditor.com/" class="btn btn-lg btn-secondary
|
|
44
|
+
<a href="https://squeditor.com/" class="btn btn-lg btn-secondary hover:scale-105 transition-transform">
|
|
45
45
|
Try Squeditor
|
|
46
46
|
</a>
|
|
47
|
-
<a href="https://docs.squeditor.com/" class="btn btn-lg !
|
|
47
|
+
<a href="https://docs.squeditor.com/" class="btn btn-lg !border !border-1 !border-solid !border-zinc-200 hover:scale-105 transition-transform">
|
|
48
48
|
View Docs
|
|
49
49
|
</a>
|
|
50
50
|
</div>
|
|
@@ -40,14 +40,16 @@ if (file_exists(__DIR__ . '/../config/active-slider.php')) {
|
|
|
40
40
|
<?php if ($is_vite): ?>
|
|
41
41
|
<!-- Vite Development Environment -->
|
|
42
42
|
<script type="module" src="<?= $vite_server ?>/@vite/client"></script>
|
|
43
|
-
<link rel="stylesheet" href="<?= $vite_server ?>/assets/css/
|
|
43
|
+
<link rel="stylesheet" href="<?= $vite_server ?>/assets/css/fonts.css">
|
|
44
44
|
<link rel="stylesheet" href="<?= $vite_server ?>/assets/css/squeditor-icons.css">
|
|
45
|
+
<link rel="stylesheet" href="<?= $vite_server ?>/assets/css/tailwind.css">
|
|
45
46
|
<?php if ($active_slider): ?><link rel="stylesheet" href="<?= $vite_server ?>/assets/css/slider.min.css"><?php endif; ?>
|
|
46
47
|
<script type="module" src="<?= $vite_server ?>/assets/scss/main.scss"></script>
|
|
47
48
|
<style>html.js-fouc { opacity: 0; transition: opacity 0.15s ease-out; }</style>
|
|
48
49
|
<script>document.documentElement.classList.add('js-fouc');</script>
|
|
49
50
|
<?php else: ?>
|
|
50
51
|
<!-- Production Static Assets -->
|
|
52
|
+
<link rel="stylesheet" href="assets/css/fonts.css">
|
|
51
53
|
<link rel="stylesheet" href="assets/css/squeditor-icons.css">
|
|
52
54
|
<link rel="stylesheet" href="assets/css/tailwind.css">
|
|
53
55
|
<?php if ($active_slider): ?><link rel="stylesheet" href="assets/css/slider.min.css"><?php endif; ?>
|
|
@@ -17,7 +17,7 @@ $items = $items ?? [];
|
|
|
17
17
|
<li class="flex items-center gap-2"><i class="sq-icon-chevron-right opacity-30"></i> <?= htmlspecialchars($feature) ?></li>
|
|
18
18
|
<?php endforeach; ?>
|
|
19
19
|
</ul>
|
|
20
|
-
<span class="absolute top-6 end-6 w-10 h-10 p-0 rounded-full flex items-center justify-center
|
|
20
|
+
<span class="absolute top-6 end-6 w-10 h-10 p-0 rounded-full flex items-center justify-center bg-white group-hover:-rotate-45 transition-transform duration-300">
|
|
21
21
|
<i class="sq-icon-arrow-right"></i>
|
|
22
22
|
</span>
|
|
23
23
|
</div>
|
|
@@ -7,7 +7,7 @@ $button_url = $button_url ?? '#';
|
|
|
7
7
|
$secondary_button_text = $secondary_button_text ?? '';
|
|
8
8
|
$hint_text = $hint_text ?? '';
|
|
9
9
|
?>
|
|
10
|
-
<section class="py-32 text-center border-t border-zinc-300 border-opacity-30 dark:border-opacity-5">
|
|
10
|
+
<section class="sq-cta-banner py-16 md:py-24 lg:py-32 text-center border-t border-zinc-300 border-opacity-30 dark:border-opacity-5">
|
|
11
11
|
<div class="max-w-4xl mx-auto px-6">
|
|
12
12
|
<h2 class="text-4xl md:text-5xl font-bold mb-4 tracking-tighter">
|
|
13
13
|
<?= $heading ?>
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
$heading = $heading ?? 'Subscribe to our newsletter';
|
|
4
4
|
$subheading = $subheading ?? 'Get the latest updates and news from our team.';
|
|
5
5
|
?>
|
|
6
|
-
<section class="py-20 bg-
|
|
6
|
+
<section class="py-20 bg-muted dark:bg-opacity-40">
|
|
7
7
|
<div class="max-w-7xl mx-auto px-6 flex flex-col items-center justify-between gap-8">
|
|
8
8
|
<div class="mb-8 md:mb-0 md:w-1/2">
|
|
9
9
|
<h2 class="text-4xl font-bold text-center m-0"><?= htmlspecialchars($heading) ?></h2>
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
$isDark = $isDark ?? false;
|
|
5
5
|
$isFloat = $isFloat ?? false;
|
|
6
6
|
|
|
7
|
-
$headerClasses = 'sq
|
|
7
|
+
$headerClasses = 'sq-header w-full z-[1000]';
|
|
8
8
|
if ($isFloat) $headerClasses .= ' absolute top-0';
|
|
9
9
|
if ($isDark) $headerClasses .= ' dark-mode text-white bg-zinc-900';
|
|
10
10
|
else $headerClasses .= ' bg-white border-b';
|
|
@@ -62,13 +62,13 @@ $processed_heading = str_replace(
|
|
|
62
62
|
</h2>
|
|
63
63
|
|
|
64
64
|
<!-- Subheading -->
|
|
65
|
-
<p class="text-lg md:text-xl text-muted mb-10 max-w-md
|
|
65
|
+
<p class="text-lg md:text-xl text-muted mb-10 max-w-md"
|
|
66
66
|
data-gsap="from: {opacity: 0, y: 20}; duration: 0.8; delay: 0.4">
|
|
67
67
|
<?= htmlspecialchars($args['subheading']) ?>
|
|
68
68
|
</p>
|
|
69
69
|
|
|
70
70
|
<!-- CTA Button -->
|
|
71
|
-
<div data-gsap="from: {opacity: 0, y: 16}; duration: 0.6; delay: 0.7" class="self-start mb-16">
|
|
71
|
+
<div data-gsap="from: {opacity: 0, y: 16}; duration: 0.6; delay: 0.7" class="self-start mb-8 lg:mb-16">
|
|
72
72
|
<a href="<?= htmlspecialchars($args['cta_url']) ?>" class="btn btn-secondary min-h-[48px] !px-8 !py-4 !text-base !shadow-lg !shadow-sq-primary/30 flex items-center gap-2 transition-transform hover:scale-105">
|
|
73
73
|
<?= htmlspecialchars($args['cta_label']) ?>
|
|
74
74
|
<i class="sq-icon sq-icon-arrow-up-right text-lg leading-none mt-0.5"></i>
|
|
@@ -96,8 +96,8 @@ $processed_heading = str_replace(
|
|
|
96
96
|
<div class="relative h-[400px] md:h-[700px]">
|
|
97
97
|
|
|
98
98
|
<!-- Image Wrapper -->
|
|
99
|
-
<div class="h-full rounded-
|
|
100
|
-
<img src="<?= htmlspecialchars($args['image_src']) ?>" alt="<?= htmlspecialchars($args['image_alt']) ?>" class="w-full h-full object-cover
|
|
99
|
+
<div class="h-full rounded-3xl overflow-hidden" data-gsap="from: {clipPath: 'inset(0 0 100% 0)'}; duration: 2; ease: expo.inOut;">
|
|
100
|
+
<img src="<?= htmlspecialchars($args['image_src']) ?>" alt="<?= htmlspecialchars($args['image_alt']) ?>" class="w-full h-full object-cover">
|
|
101
101
|
</div>
|
|
102
102
|
|
|
103
103
|
<!-- Floating Services Container -->
|
|
@@ -9,8 +9,8 @@ if ($layout !== 'default') {
|
|
|
9
9
|
}
|
|
10
10
|
?>
|
|
11
11
|
<!-- Site Footer -->
|
|
12
|
-
<footer id="sq_footer" class="sq
|
|
13
|
-
<div class="sq
|
|
12
|
+
<footer id="sq_footer" class="sq-footer py-12 md:py-18 lg:py-24 border-t dark:border-transparent dark:bg-black/40">
|
|
13
|
+
<div class="sq-footer-inner max-w-7xl mx-auto px-6 grid grid-cols-1 md:grid-cols-5 gap-6 md:gap-8 lg:gap-12">
|
|
14
14
|
<div class="sq--footer--brand md:col-span-2">
|
|
15
15
|
<div class="flex items-center gap-2 mb-6">
|
|
16
16
|
<a href="index.html" class="sq--logo flex items-center gap-2 group">
|
|
@@ -20,7 +20,7 @@ if ($layout !== 'default') {
|
|
|
20
20
|
<h1 class="font-bold text-xl m-0 tracking-tight"><?= htmlspecialchars($site['name']) ?></h1>
|
|
21
21
|
</a>
|
|
22
22
|
</div>
|
|
23
|
-
<p class="text-sm max-w-xs leading-relaxed mb-
|
|
23
|
+
<p class="text-sm max-w-xs leading-relaxed mb-6">
|
|
24
24
|
<?= htmlspecialchars($site['description']) ?>
|
|
25
25
|
</p>
|
|
26
26
|
<div class="flex gap-4">
|
|
@@ -61,11 +61,11 @@ if ($layout !== 'default') {
|
|
|
61
61
|
</ul>
|
|
62
62
|
</div>
|
|
63
63
|
</div>
|
|
64
|
-
<div class="sq
|
|
64
|
+
<div class="sq-footer-divider max-w-7xl mx-auto px-6 mt-8 md:mt-12 lg:mt-16 mb-8">
|
|
65
65
|
<hr>
|
|
66
66
|
</div>
|
|
67
|
-
<div class="sq
|
|
68
|
-
<p>© <?= date('Y') ?> <?= htmlspecialchars($site['name']) ?>. Built
|
|
67
|
+
<div class="sq-footer-bottom max-w-7xl mx-auto px-6 flex flex-col md:flex-row justify-between items-center gap-4 text-sm text-muted">
|
|
68
|
+
<p>© <?= date('Y') ?> <?= htmlspecialchars($site['name']) ?>. Built with ❤️ by Expert Developers.</p>
|
|
69
69
|
<div class="flex gap-8">
|
|
70
70
|
<a href="#" class="hover:text-secondary transition-colors">Terms of Service</a>
|
|
71
71
|
<a href="#" class="hover:text-secondary transition-colors">Privacy Policy</a>
|
|
@@ -11,8 +11,8 @@ if ($layout !== 'default') {
|
|
|
11
11
|
}
|
|
12
12
|
?>
|
|
13
13
|
<!-- Site Header -->
|
|
14
|
-
<header id="sq_header" class="sq
|
|
15
|
-
<div class="sq
|
|
14
|
+
<header id="sq_header" class="sq-header absolute w-full top-0 z-[1000]" data-gsap="from: {y: -80, opacity: 0}; to: {y: 0, opacity: 1}; duration: 1.2; ease: expo.inOut;">
|
|
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">
|
|
@@ -23,17 +23,17 @@ if ($layout !== 'default') {
|
|
|
23
23
|
</a>
|
|
24
24
|
|
|
25
25
|
<!-- Desktop Nav (Centered) -->
|
|
26
|
-
<div class="sq
|
|
26
|
+
<div class="sq-header-nav items-center absolute left-1/2 -translate-x-1/2 hidden lg:flex">
|
|
27
27
|
<?php get_template_part('nav'); ?>
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
30
|
<!-- Right Side / CTA -->
|
|
31
|
-
<div class="sq
|
|
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
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
|
|
36
|
+
<button class="sq-header-mobile-toggle md:hidden" data-gsap-toggle="#sq_offcanvas_creative" type="button" aria-label="Menu">
|
|
37
37
|
<span data-uk-icon="icon: menu; ratio: 1.5"></span>
|
|
38
38
|
</button>
|
|
39
39
|
</div>
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<?php
|
|
2
2
|
// src/template-parts/nav.php
|
|
3
3
|
$is_mobile = $mobile ?? false;
|
|
4
|
-
$nav_class = $is_mobile ? 'flex flex-col space-y-4' : 'flex space-x-
|
|
4
|
+
$nav_class = $is_mobile ? 'flex flex-col space-y-4' : 'flex space-x-8 items-center m-0 p-0';
|
|
5
5
|
?>
|
|
6
6
|
<nav>
|
|
7
7
|
<ul class="<?= $nav_class ?>">
|
|
8
8
|
<?php foreach ($site['nav'] as $item): ?>
|
|
9
9
|
<li>
|
|
10
|
-
<a href="<?= htmlspecialchars($item['url']) ?>" class="sq-nav-link
|
|
10
|
+
<a href="<?= htmlspecialchars($item['url']) ?>" class="sq-nav-link">
|
|
11
11
|
<?= htmlspecialchars($item['label']) ?>
|
|
12
12
|
</a>
|
|
13
13
|
</li>
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// src/template-parts/page-title-bar.php
|
|
3
3
|
$title = $title ?? 'Page Title';
|
|
4
4
|
$subtitle = $subtitle ?? '';
|
|
5
|
-
$class = $class ?? 'py-20 text-center bg-
|
|
5
|
+
$class = $class ?? 'py-20 text-center bg-muted dark:bg-opacity-40';
|
|
6
6
|
?>
|
|
7
7
|
<div class="<?= htmlspecialchars($class) ?>">
|
|
8
8
|
<div class="max-w-7xl mx-auto px-6">
|
|
@@ -7,6 +7,17 @@ module.exports = {
|
|
|
7
7
|
],
|
|
8
8
|
theme: {
|
|
9
9
|
extend: {
|
|
10
|
+
screens: {
|
|
11
|
+
'sm': '459px',
|
|
12
|
+
'md': '768px',
|
|
13
|
+
'lg': '992px',
|
|
14
|
+
'xl': '1200px',
|
|
15
|
+
'2xl': '1400px',
|
|
16
|
+
},
|
|
17
|
+
container: {
|
|
18
|
+
center: true,
|
|
19
|
+
padding: '1rem', // 16px each side = 32px gutter (--bs-gutter-x)
|
|
20
|
+
},
|
|
10
21
|
colors: {
|
|
11
22
|
primary: 'var(--sq-color-primary)',
|
|
12
23
|
secondary: 'var(--sq-color-secondary)',
|
|
@@ -20,7 +31,24 @@ module.exports = {
|
|
|
20
31
|
serif: ['var(--sq-font-serif)'],
|
|
21
32
|
mono: ['var(--sq-font-mono)'],
|
|
22
33
|
},
|
|
34
|
+
fontSize: {
|
|
35
|
+
// Display sizes
|
|
36
|
+
'display-1': ['8rem', { lineHeight: '1', letterSpacing: '-0.32rem' }],
|
|
37
|
+
'display-2': ['6rem', { lineHeight: '1', letterSpacing: '-0.24rem' }],
|
|
38
|
+
'display-3': ['5rem', { lineHeight: '1', letterSpacing: '-0.2rem' }],
|
|
39
|
+
'display-4': ['4.5rem', { lineHeight: '1', letterSpacing: '-0.18rem' }],
|
|
40
|
+
'display-5': ['4rem', { lineHeight: '1', letterSpacing: '-0.16rem' }],
|
|
41
|
+
'display-6': ['3.5rem', { lineHeight: '1', letterSpacing: '-0.14rem' }],
|
|
42
|
+
|
|
43
|
+
// Heading sizes
|
|
44
|
+
'h1': ['3rem', { lineHeight: '1.1', letterSpacing: '-0.12rem' }],
|
|
45
|
+
'h2': ['2.5rem', { lineHeight: '1.1', letterSpacing: '-0.08rem' }],
|
|
46
|
+
'h3': ['2rem', { lineHeight: '1.1', letterSpacing: '-0.07rem' }],
|
|
47
|
+
'h4': ['1.5rem', { lineHeight: '1.2', letterSpacing: '-0.06rem' }],
|
|
48
|
+
'h5': ['1.25rem', { lineHeight: '1.2', letterSpacing: '-0.05rem' }],
|
|
49
|
+
'h6': ['1rem', { lineHeight: '1.2', letterSpacing: '-0.004rem' }],
|
|
50
|
+
},
|
|
23
51
|
},
|
|
24
52
|
},
|
|
25
53
|
plugins: [],
|
|
26
|
-
}
|
|
54
|
+
}
|
|
@@ -19,6 +19,7 @@ export default defineConfig({
|
|
|
19
19
|
main_css: path.resolve(__dirname, 'src/assets/scss/main.scss'),
|
|
20
20
|
tailwind: path.resolve(__dirname, 'src/assets/css/tailwind.css'),
|
|
21
21
|
'squeditor-icons': path.resolve(__dirname, 'src/assets/css/squeditor-icons.css'),
|
|
22
|
+
'fonts': path.resolve(__dirname, 'src/assets/css/fonts.css'),
|
|
22
23
|
},
|
|
23
24
|
output: {
|
|
24
25
|
entryFileNames: 'assets/js/[name].js',
|
|
@@ -60,6 +61,13 @@ export default defineConfig({
|
|
|
60
61
|
name: 'php-watch',
|
|
61
62
|
handleHotUpdate({ file, server }) {
|
|
62
63
|
if (file.endsWith('.php')) {
|
|
64
|
+
// Force Vite to invalidate CSS modules so Tailwind generates new classes
|
|
65
|
+
const tailwindModule = server.moduleGraph.getModuleById(path.resolve(__dirname, 'src/assets/css/tailwind.css'));
|
|
66
|
+
if (tailwindModule) server.moduleGraph.invalidateModule(tailwindModule);
|
|
67
|
+
|
|
68
|
+
const scssModule = server.moduleGraph.getModuleById(path.resolve(__dirname, 'src/assets/scss/main.scss'));
|
|
69
|
+
if (scssModule) server.moduleGraph.invalidateModule(scssModule);
|
|
70
|
+
|
|
63
71
|
server.ws.send({ type: 'full-reload' });
|
|
64
72
|
}
|
|
65
73
|
}
|
|
@@ -77,8 +77,7 @@ scssPaths.forEach(f => {
|
|
|
77
77
|
fs.writeFileSync(path.join(outputJsDir, 'uikit-components.js'), jsBundle);
|
|
78
78
|
fs.writeFileSync(path.join(outputScssDir, '_uikit_dynamic.scss'), scssImports);
|
|
79
79
|
|
|
80
|
-
console.log('[Squeditor] ✅
|
|
81
|
-
console.log(` Components included: _core, ${selectedComponents.join(', ')}`);
|
|
80
|
+
console.log('[Squeditor] ✅ UIkit3 components built successfully.');
|
|
82
81
|
|
|
83
82
|
// Generate src/config/active-components.php for the style-guide page
|
|
84
83
|
const phpConfigDir = path.join(projectRoot, 'src/config');
|
|
@@ -128,7 +127,7 @@ if (fs.existsSync(mainScssPath) && config.themes) {
|
|
|
128
127
|
// Ensure exactly one trailing newline
|
|
129
128
|
mainScss = mainScss.trim() + '\n' + themeImports;
|
|
130
129
|
fs.writeFileSync(mainScssPath, mainScss);
|
|
131
|
-
console.log(`[Squeditor] 🎨
|
|
130
|
+
console.log(`[Squeditor] 🎨 Ready themes: ${Object.keys(config.themes).join(', ')}`);
|
|
132
131
|
}
|
|
133
132
|
|
|
134
133
|
// Generate Dynamic Slider Config Import
|
|
@@ -141,7 +140,7 @@ if (sliderConfig.library === 'swiper') {
|
|
|
141
140
|
sliderImportCode += 'import \'./modules/splide-init.js\';\n';
|
|
142
141
|
}
|
|
143
142
|
fs.writeFileSync(dynamicSliderPath, sliderImportCode);
|
|
144
|
-
console.log(`[Squeditor] 🎠
|
|
143
|
+
console.log(`[Squeditor] 🎠 Selected slider library: ${sliderConfig.library || 'none'}`);
|
|
145
144
|
|
|
146
145
|
// Copy slider library CSS to src/assets/css/slider.min.css
|
|
147
146
|
// This keeps the CSS separate from main.js and gives it a clear, descriptive filename
|
|
@@ -150,7 +149,6 @@ if (sliderConfig.library === 'splide') {
|
|
|
150
149
|
const splideCssPath = path.join(projectRoot, 'node_modules/@splidejs/splide/dist/css/splide.min.css');
|
|
151
150
|
if (fs.existsSync(splideCssPath)) {
|
|
152
151
|
fs.copyFileSync(splideCssPath, sliderCssDest);
|
|
153
|
-
console.log('[Squeditor] 📎 Copied Splide CSS → src/assets/css/slider.min.css');
|
|
154
152
|
} else {
|
|
155
153
|
console.warn('[Squeditor] ⚠️ Splide CSS not found at expected path.');
|
|
156
154
|
fs.writeFileSync(sliderCssDest, '/* Splide CSS not found */\n');
|
|
@@ -172,7 +170,6 @@ if (sliderConfig.library === 'splide') {
|
|
|
172
170
|
}
|
|
173
171
|
}
|
|
174
172
|
fs.writeFileSync(sliderCssDest, combinedCss);
|
|
175
|
-
console.log('[Squeditor] 📎 Copied Swiper CSS → src/assets/css/slider.min.css');
|
|
176
173
|
} else {
|
|
177
174
|
// No slider configured — write an empty placeholder so head.php link doesn't 404
|
|
178
175
|
fs.writeFileSync(sliderCssDest, '/* No slider library configured */\n');
|
package/scripts/scaffold.js
CHANGED
|
@@ -14,7 +14,24 @@ if (!projectName) {
|
|
|
14
14
|
let destIndex = args.indexOf('--dest');
|
|
15
15
|
let destPath = destIndex !== -1 ? args[destIndex + 1] : projectName;
|
|
16
16
|
const sourceDir = path.join(__dirname, '..', 'project-template');
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
// Check if running directly inside the cloned framework repository
|
|
19
|
+
let isInsideRepo = false;
|
|
20
|
+
try {
|
|
21
|
+
const pkgPath = path.join(process.cwd(), 'package.json');
|
|
22
|
+
if (fs.existsSync(pkgPath)) {
|
|
23
|
+
const pkg = require(pkgPath);
|
|
24
|
+
if (pkg.name === '@squeditor/squeditor-framework') {
|
|
25
|
+
isInsideRepo = true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
} catch (e) {}
|
|
29
|
+
|
|
30
|
+
// If running inside the repo, scaffold as a sibling (../destPath).
|
|
31
|
+
// Otherwise scaffold in the current directory.
|
|
32
|
+
const targetDir = isInsideRepo
|
|
33
|
+
? path.resolve(process.cwd(), '..', destPath)
|
|
34
|
+
: path.resolve(process.cwd(), destPath);
|
|
18
35
|
|
|
19
36
|
if (!fs.existsSync(sourceDir)) {
|
|
20
37
|
console.error(`Source template directory does not exist: ${sourceDir}`);
|
|
@@ -47,14 +64,18 @@ function copyDirectory(src, dest, ignoreList = []) {
|
|
|
47
64
|
console.log(`[Squeditor] Scaffolding new project: ${projectName}...`);
|
|
48
65
|
|
|
49
66
|
// 1. Copy the framework core
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
67
|
+
if (!isInsideRepo) {
|
|
68
|
+
const frameworkSourceDir = path.join(__dirname, '..');
|
|
69
|
+
const frameworkTargetDir = path.resolve(process.cwd(), 'squeditor-framework');
|
|
70
|
+
|
|
71
|
+
if (!fs.existsSync(frameworkTargetDir)) {
|
|
72
|
+
console.log(`[Squeditor] Installing local framework core at ./squeditor-framework...`);
|
|
73
|
+
// Pass the name of the target directory to the ignore list to prevent infinite loop
|
|
74
|
+
const ignoreCoreList = ['project-template', 'showcase', 'node_modules', '.git', '.github', 'squeditor-framework'];
|
|
75
|
+
copyDirectory(frameworkSourceDir, frameworkTargetDir, ignoreCoreList);
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
console.log(`[Squeditor] Running inside framework repo. Skipping core installation (using repo).`);
|
|
58
79
|
}
|
|
59
80
|
|
|
60
81
|
// 2. Copy the project template
|