@squeditor/squeditor-framework 1.0.0
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/LICENSE +21 -0
- package/README.md +106 -0
- package/package.json +36 -0
- package/php/functions.php +92 -0
- package/project-template/package.json +29 -0
- package/project-template/postcss.config.js +6 -0
- package/project-template/squeditor.config.js +81 -0
- package/project-template/src/404.php +21 -0
- package/project-template/src/assets/css/squeditor-icons.css +4719 -0
- package/project-template/src/assets/css/tailwind.css +3 -0
- package/project-template/src/assets/css/uikit-components.css +14586 -0
- package/project-template/src/assets/js/gsap-advanced.js +26 -0
- package/project-template/src/assets/js/gsap-init.js +672 -0
- package/project-template/src/assets/js/gsap-modules/cursor-preview.js +132 -0
- package/project-template/src/assets/js/gsap-modules/cursor.js +456 -0
- package/project-template/src/assets/js/gsap-modules/loop-panels.js +78 -0
- package/project-template/src/assets/js/gsap-modules/marquee.js +106 -0
- package/project-template/src/assets/js/gsap-modules/pinned-panels.js +105 -0
- package/project-template/src/assets/js/gsap-modules/scroll-to.js +54 -0
- package/project-template/src/assets/js/gsap-modules/swipe-slider.js +121 -0
- package/project-template/src/assets/js/gsap-modules/text-mask.js +93 -0
- package/project-template/src/assets/js/gsap-modules/tilt.js +70 -0
- package/project-template/src/assets/js/main.js +302 -0
- package/project-template/src/assets/js/uikit-components.js +18171 -0
- package/project-template/src/assets/scss/_base.scss +140 -0
- package/project-template/src/assets/scss/_components.scss +165 -0
- package/project-template/src/assets/scss/_config.scss +13 -0
- package/project-template/src/assets/scss/_functions.scss +81 -0
- package/project-template/src/assets/scss/_tokens.scss +229 -0
- package/project-template/src/assets/scss/_transitions.scss +36 -0
- package/project-template/src/assets/scss/_uikit-overrides.scss +187 -0
- package/project-template/src/assets/scss/_uikit_dynamic.scss +43 -0
- package/project-template/src/assets/scss/_utilities.scss +31 -0
- package/project-template/src/assets/scss/custom.scss +10 -0
- package/project-template/src/assets/scss/main.scss +11 -0
- package/project-template/src/assets/static/fonts/squeditor-icons/squeditor-icons.eot +0 -0
- package/project-template/src/assets/static/fonts/squeditor-icons/squeditor-icons.svg +1183 -0
- package/project-template/src/assets/static/fonts/squeditor-icons/squeditor-icons.ttf +0 -0
- package/project-template/src/assets/static/fonts/squeditor-icons/squeditor-icons.woff +0 -0
- package/project-template/src/config/site-config.php +34 -0
- package/project-template/src/data/blog.php +21 -0
- package/project-template/src/data/portfolio.php +23 -0
- package/project-template/src/data/team.php +23 -0
- package/project-template/src/index.php +57 -0
- package/project-template/src/init.php +19 -0
- package/project-template/src/page-templates/base.php +39 -0
- package/project-template/src/page-templates/body-scripts.php +26 -0
- package/project-template/src/page-templates/head.php +47 -0
- package/project-template/src/page-templates/transition.php +45 -0
- package/project-template/src/sections/cards/cards-grid.php +34 -0
- package/project-template/src/sections/cards/cards-horizontal.php +28 -0
- package/project-template/src/sections/cta/cta-banner.php +34 -0
- package/project-template/src/sections/cta/cta-newsletter.php +19 -0
- package/project-template/src/sections/footer/layout-01.php +35 -0
- package/project-template/src/sections/header/layout-01.php +36 -0
- package/project-template/src/sections/hero/hero-centered.php +44 -0
- package/project-template/src/sections/hero/hero-split.php +132 -0
- package/project-template/src/sections/hero/hero-video.php +22 -0
- package/project-template/src/sections/sidebar/sidebar-right.php +11 -0
- package/project-template/src/template-parts/breadcrumbs.php +17 -0
- package/project-template/src/template-parts/footer.php +74 -0
- package/project-template/src/template-parts/header.php +120 -0
- package/project-template/src/template-parts/mega-menu.php +7 -0
- package/project-template/src/template-parts/nav.php +16 -0
- package/project-template/src/template-parts/page-title-bar.php +14 -0
- package/project-template/tailwind.config.js +26 -0
- package/project-template/vite.config.js +67 -0
- package/scripts/build-components.js +109 -0
- package/scripts/copy-static.js +150 -0
- package/scripts/dev-router.php +23 -0
- package/scripts/dev.js +55 -0
- package/scripts/get-port.js +27 -0
- package/scripts/package-customer.js +278 -0
- package/scripts/package-dist.js +54 -0
- package/scripts/scaffold.js +72 -0
- package/scripts/snapshot.js +74 -0
- package/uikit-manifest.json +248 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/sections/hero/hero-split.php
|
|
3
|
+
|
|
4
|
+
$defaults = [
|
|
5
|
+
'badge_icon' => 'sq-icon-stars-02',
|
|
6
|
+
'badge_label' => 'True 24/7',
|
|
7
|
+
'badge_sub' => 'Care When It Counts',
|
|
8
|
+
'heading' => 'A calmer dental visit starts here.',
|
|
9
|
+
'heading_highlight' => 'here.',
|
|
10
|
+
'subheading' => 'Modern dentistry designed around your comfort. From routine checkups to advanced care, we make dental visits simple, clear, and stress-free.',
|
|
11
|
+
'cta_label' => 'Contact Us',
|
|
12
|
+
'cta_url' => '/contact.html',
|
|
13
|
+
'avatars' => [
|
|
14
|
+
'assets/static/images/common/avatars/01.png',
|
|
15
|
+
'assets/static/images/common/avatars/02.png',
|
|
16
|
+
'assets/static/images/common/avatars/03.png'
|
|
17
|
+
],
|
|
18
|
+
'avatar_count' => '15+',
|
|
19
|
+
'avatar_label' => 'Expert Dentists for you',
|
|
20
|
+
'image_src' => 'assets/static/images/showcase/hero-dental.png', // Will generate real image later
|
|
21
|
+
'image_alt' => 'Dental care procedure',
|
|
22
|
+
'services' => [
|
|
23
|
+
['label' => 'Teeth Cleaning', 'status' => 'active'],
|
|
24
|
+
['label' => 'Whitening', 'status' => 'active'],
|
|
25
|
+
['label' => 'Lost Filling', 'status' => 'pending'],
|
|
26
|
+
],
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
// Merge provided args with defaults
|
|
30
|
+
$args = array_merge($defaults, $args ?? []);
|
|
31
|
+
|
|
32
|
+
// Process heading highlight
|
|
33
|
+
$highlight_html = '<span class="text-sq-secondary">' . htmlspecialchars($args['heading_highlight']) . '</span>';
|
|
34
|
+
$processed_heading = str_replace(
|
|
35
|
+
htmlspecialchars($args['heading_highlight']),
|
|
36
|
+
$highlight_html,
|
|
37
|
+
htmlspecialchars($args['heading'])
|
|
38
|
+
);
|
|
39
|
+
?>
|
|
40
|
+
|
|
41
|
+
<div class="sq-hero--split min-h-screen w-full relative overflow-hidden flex flex-col pt-8 pb-8 px-4 md:px-8">
|
|
42
|
+
<div class="sq-hero--inner max-w-7xl mx-auto lg:px-6 flex items-center justify-between">
|
|
43
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 md:gap-12 lg:gap-24 flex-1 relative z-10">
|
|
44
|
+
|
|
45
|
+
<!-- Left Column: Content -->
|
|
46
|
+
<div class="flex flex-col justify-center max-w-xl py-8 md:py-12">
|
|
47
|
+
|
|
48
|
+
<!-- Badge -->
|
|
49
|
+
<div class="inline-flex items-center self-start bg-white dark:bg-opacity-5 rounded-full p-1 pr-4 shadow-sm border mb-8" data-gsap="from: {opacity: 0, y: -20}; duration: 0.8">
|
|
50
|
+
<span class="flex items-center justify-center w-8 h-8 rounded-full sq-bg-secondary font-bold mr-3">
|
|
51
|
+
<i class="sq-icon <?= htmlspecialchars($args['badge_icon']) ?>"></i>
|
|
52
|
+
</span>
|
|
53
|
+
<span class="text-sm font-semibold"><?= htmlspecialchars($args['badge_label']) ?></span>
|
|
54
|
+
<span class="w-px h-4 bg-zinc-200 mx-4"></span>
|
|
55
|
+
<span class="text-sm text-muted"><?= htmlspecialchars($args['badge_sub']) ?></span>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Heading -->
|
|
59
|
+
<h2 class="text-5xl md:text-6xl lg:text-7xl font-bold tracking-tight mb-6 leading-[1.1]"
|
|
60
|
+
data-gsap="from: {opacity: 0, y: 60}; duration: 0.8; delay: 0.2">
|
|
61
|
+
<?= $processed_heading ?>
|
|
62
|
+
</h2>
|
|
63
|
+
|
|
64
|
+
<!-- Subheading -->
|
|
65
|
+
<p class="text-lg md:text-xl text-muted mb-10 max-w-md leading-relaxed"
|
|
66
|
+
data-gsap="from: {opacity: 0, y: 20}; duration: 0.8; delay: 0.4">
|
|
67
|
+
<?= htmlspecialchars($args['subheading']) ?>
|
|
68
|
+
</p>
|
|
69
|
+
|
|
70
|
+
<!-- CTA Button -->
|
|
71
|
+
<div data-gsap="from: {opacity: 0, y: 16}; duration: 0.6; delay: 0.7" class="self-start mb-16">
|
|
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
|
+
<?= htmlspecialchars($args['cta_label']) ?>
|
|
74
|
+
<i class="sq-icon sq-icon-arrow-up-right text-lg leading-none mt-0.5"></i>
|
|
75
|
+
</a>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<!-- Social Proof -->
|
|
79
|
+
<div class="flex items-center mt-auto" data-gsap="from: {opacity: 0, y: 16}; duration: 0.6; delay: 0.9">
|
|
80
|
+
<div class="flex -space-x-3 mr-4">
|
|
81
|
+
<?php foreach($args['avatars'] as $avatar): ?>
|
|
82
|
+
<div class="w-10 h-10 rounded-full border-[3px] overflow-hidden bg-zinc-100 border-white dark:border-zinc-900 shadow-sm">
|
|
83
|
+
<img class="w-full h-full object-cover" src="<?= htmlspecialchars($avatar) ?>" alt="Dentist Avatar">
|
|
84
|
+
</div>
|
|
85
|
+
<?php endforeach; ?>
|
|
86
|
+
<div class="w-10 h-10 rounded-full border-[3px] border-white dark:border-zinc-900 bg-zinc-100 dark:bg-zinc-700 flex items-center justify-center text-xs font-bold text-zinc-700 dark:text-zinc-200">
|
|
87
|
+
<?= htmlspecialchars($args['avatar_count']) ?>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
<span class="text-sm text-muted font-medium"><?= htmlspecialchars($args['avatar_label']) ?></span>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<!-- Right Column: Image & Floating Cards -->
|
|
96
|
+
<div class="relative h-[400px] md:h-[700px]">
|
|
97
|
+
|
|
98
|
+
<!-- Image Wrapper -->
|
|
99
|
+
<div class="h-full rounded-[2rem] 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 rounded-[2rem]">
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<!-- Floating Services Container -->
|
|
104
|
+
<div class="absolute bottom-4 md:bottom-12 right-4 md:right-12 flex flex-col gap-3 z-10 w-64" data-gsap="from: {opacity: 0, x: 30}; stagger: 0.15; delay: 1.3">
|
|
105
|
+
<?php foreach($args['services'] as $index => $service): ?>
|
|
106
|
+
<div class="bg-white/90 backdrop-blur-md rounded-full py-3 px-5 shadow-lg flex items-center justify-between border border-white/40">
|
|
107
|
+
|
|
108
|
+
<div class="flex items-center gap-3">
|
|
109
|
+
<!-- Service Icon -->
|
|
110
|
+
<i class="sq-icon sq-icon-medical-cross text-xl text-zinc-400"></i>
|
|
111
|
+
|
|
112
|
+
<span class="text-sm font-medium text-zinc-800"><?= htmlspecialchars($service['label']) ?></span>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<!-- Status Icon -->
|
|
116
|
+
<?php if($service['status'] === 'active'): ?>
|
|
117
|
+
<div class="w-5 h-5 rounded-full bg-emerald-500 flex items-center justify-center">
|
|
118
|
+
<i class="sq-icon sq-icon-check text-white text-[10px] font-bold"></i>
|
|
119
|
+
</div>
|
|
120
|
+
<?php else: ?>
|
|
121
|
+
<div class="w-5 h-5 rounded-full border-2 border-zinc-200"></div>
|
|
122
|
+
<?php endif; ?>
|
|
123
|
+
|
|
124
|
+
</div>
|
|
125
|
+
<?php endforeach; ?>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/sections/hero/hero-video.php
|
|
3
|
+
$heading = $heading ?? 'Watch Our Story';
|
|
4
|
+
$video_url = $video_url ?? 'https://www.w3schools.com/html/mov_bbb.mp4';
|
|
5
|
+
?>
|
|
6
|
+
<section class="relative h-screen flex items-center justify-center overflow-hidden">
|
|
7
|
+
<video autoplay loop muted class="absolute z-0 w-full h-full object-cover">
|
|
8
|
+
<source src="<?= htmlspecialchars($video_url) ?>" type="video/mp4">
|
|
9
|
+
</video>
|
|
10
|
+
<div class="z-10 relative text-center text-white p-8 md:p-16 sq-hero-overlay max-w-4xl mx-6">
|
|
11
|
+
<h1 class="text-5xl lg:text-8xl font-black mb-8 tracking-tighter leading-tight">
|
|
12
|
+
Elevate Your <span class="text-accent">SaaS Presence</span>
|
|
13
|
+
</h1>
|
|
14
|
+
<p class="text-lg md:text-xl text-teal-50/80 mb-10 max-w-2xl mx-auto leading-relaxed">
|
|
15
|
+
A premium frontend framework built for modern developers who demand speed, flexibility, and stunning aesthetics out of the box.
|
|
16
|
+
</p>
|
|
17
|
+
<div class="flex flex-col sm:flex-row items-center justify-center gap-4">
|
|
18
|
+
<a href="#explore" class="btn btn-secondary btn-lg w-full sm:w-auto rounded-2xl hover:shadow-2xl transition-all hover:-translate-y-1">Start Designing</a>
|
|
19
|
+
<a href="#" class="btn btn-ghost btn-lg w-full sm:w-auto rounded-2xl bg-white/10 backdrop-blur-md border border-white/20 text-white hover:bg-white/20 transition-all">View Demo</a>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</section>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/sections/sidebar/sidebar-right.php
|
|
3
|
+
?>
|
|
4
|
+
<div class="sq-sidebar bg-body text-body p-6 rounded-lg shadow-sm border border-zinc-100">
|
|
5
|
+
<h3 class="text-lg font-bold mb-4 border-b border-zinc-100 pb-2">Categories</h3>
|
|
6
|
+
<ul class="space-y-2">
|
|
7
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Design</a></li>
|
|
8
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Development</a></li>
|
|
9
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Business</a></li>
|
|
10
|
+
</ul>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/template-parts/breadcrumbs.php
|
|
3
|
+
$crumbs = $crumbs ?? [];
|
|
4
|
+
?>
|
|
5
|
+
<nav aria-label="Breadcrumb">
|
|
6
|
+
<ol class="flex items-center space-x-2 text-sm">
|
|
7
|
+
<li><a href="/" class="hover:text-primary">Home</a></li>
|
|
8
|
+
<?php foreach ($crumbs as $crumb): ?>
|
|
9
|
+
<li><span class="mx-2">/</span></li>
|
|
10
|
+
<?php if (!empty($crumb['url'])): ?>
|
|
11
|
+
<li><a href="<?= htmlspecialchars($crumb['url']) ?>" class="hover:text-primary"><?= htmlspecialchars($crumb['label']) ?></a></li>
|
|
12
|
+
<?php else: ?>
|
|
13
|
+
<li class="text-zinc-900 font-medium" aria-current="page"><?= htmlspecialchars($crumb['label']) ?></li>
|
|
14
|
+
<?php endif; ?>
|
|
15
|
+
<?php endforeach; ?>
|
|
16
|
+
</ol>
|
|
17
|
+
</nav>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/template-parts/footer.php
|
|
3
|
+
$layout = $layout ?? 'default';
|
|
4
|
+
$isDark = $isDark ?? false;
|
|
5
|
+
|
|
6
|
+
if ($layout !== 'default') {
|
|
7
|
+
get_section('footer/' . $layout, get_defined_vars());
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
?>
|
|
11
|
+
<!-- Site Footer -->
|
|
12
|
+
<footer id="sq_footer" class="sq--footer 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-12 text-body">
|
|
14
|
+
<div class="sq--footer--brand md:col-span-2">
|
|
15
|
+
<div class="flex items-center gap-2 mb-6">
|
|
16
|
+
<a href="index.html" class="sq--logo flex items-center gap-2 group">
|
|
17
|
+
<div class="w-8 h-8 sq-bg-secondary rounded-lg flex items-center justify-center transition-transform group-hover:scale-110">
|
|
18
|
+
<i class="sq-icon-zap"></i>
|
|
19
|
+
</div>
|
|
20
|
+
<h1 class="font-bold text-xl m-0 tracking-tight"><?= htmlspecialchars($site['name']) ?></h1>
|
|
21
|
+
</a>
|
|
22
|
+
</div>
|
|
23
|
+
<p class="text-sm max-w-xs leading-relaxed mb-8">
|
|
24
|
+
<?= htmlspecialchars($site['description']) ?>
|
|
25
|
+
</p>
|
|
26
|
+
<div class="flex gap-4">
|
|
27
|
+
<?php foreach ($site['socials'] as $platform => $url): ?>
|
|
28
|
+
<a href="<?= htmlspecialchars($url) ?>" class="hover:text-secondary transition-colors">
|
|
29
|
+
<span data-uk-icon="icon: <?= htmlspecialchars($platform) ?>; ratio: 0.8"></span>
|
|
30
|
+
</a>
|
|
31
|
+
<?php endforeach; ?>
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<div class="sq--footer--links">
|
|
36
|
+
<h3 class="font-bold text-sm mb-6">Product</h3>
|
|
37
|
+
<ul class="space-y-4 text-sm">
|
|
38
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Editor</a></li>
|
|
39
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Framework</a></li>
|
|
40
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Templates</a></li>
|
|
41
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Pricing</a></li>
|
|
42
|
+
</ul>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="sq--footer--links">
|
|
46
|
+
<h3 class="font-bold text-sm mb-6">Support</h3>
|
|
47
|
+
<ul class="space-y-4 text-sm">
|
|
48
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Help Center</a></li>
|
|
49
|
+
<li><a href="#" class="hover:text-secondary transition-colors">API Documentation</a></li>
|
|
50
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Community</a></li>
|
|
51
|
+
<li><a href="#" class="hover:text-secondary transition-colors">FAQ</a></li>
|
|
52
|
+
</ul>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="sq--footer--links">
|
|
56
|
+
<h3 class="font-bold text-sm mb-6">Resources</h3>
|
|
57
|
+
<ul class="space-y-4 text-sm">
|
|
58
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Blog</a></li>
|
|
59
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Changelog</a></li>
|
|
60
|
+
<li><a href="#" class="hover:text-secondary transition-colors">Freebies</a></li>
|
|
61
|
+
</ul>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="sq--footer--divider max-w-7xl mx-auto px-6 mt-20 mb-8">
|
|
65
|
+
<hr>
|
|
66
|
+
</div>
|
|
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-xs">
|
|
68
|
+
<p>© <?= date('Y') ?> <?= htmlspecialchars($site['name']) ?>. Built locally by Developers.</p>
|
|
69
|
+
<div class="flex gap-8">
|
|
70
|
+
<a href="#" class="hover:text-secondary transition-colors">Terms of Service</a>
|
|
71
|
+
<a href="#" class="hover:text-secondary transition-colors">Privacy Policy</a>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
</footer>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/template-parts/header.php
|
|
3
|
+
// $site is available from site-config.php (already included by base.php)
|
|
4
|
+
$layout = $layout ?? 'default';
|
|
5
|
+
$isDark = $isDark ?? false;
|
|
6
|
+
$isFloat = $isFloat ?? false;
|
|
7
|
+
|
|
8
|
+
if ($layout !== 'default') {
|
|
9
|
+
get_section('header/' . $layout, get_defined_vars());
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
?>
|
|
13
|
+
<!-- Site Header -->
|
|
14
|
+
<header id="sq_header" class="sq--header absolute w-full top-0 z-[1000]" data-uk-sticky="top: 80; cls-active: sq-header--sticky; animation: uk-animation-slide-top">
|
|
15
|
+
<div class="sq--header--inner max-w-7xl mx-auto px-6 h-20 flex items-center justify-between">
|
|
16
|
+
|
|
17
|
+
<!-- Logo -->
|
|
18
|
+
<a href="index.html" class="sq--logo flex items-center gap-2 group">
|
|
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-zap"></i>
|
|
21
|
+
</div>
|
|
22
|
+
<h1 class="font-bold text-xl m-0 tracking-tight hidden md:inline-flex"><?= htmlspecialchars($site['name']) ?></h1>
|
|
23
|
+
</a>
|
|
24
|
+
|
|
25
|
+
<!-- Desktop Nav (Centered) -->
|
|
26
|
+
<div class="sq--header--nav hidden md:flex items-center absolute left-1/2 -translate-x-1/2">
|
|
27
|
+
<?php get_template_part('nav'); ?>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<!-- Right Side / CTA -->
|
|
31
|
+
<div class="sq--header--cta flex items-center gap-6">
|
|
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>
|
|
34
|
+
|
|
35
|
+
<!-- Mobile Toggle -->
|
|
36
|
+
<button class="sq--header--mobile--toggle md:hidden" data-uk-toggle="target: #sq_mobile_offcanvas" type="button" aria-label="Menu">
|
|
37
|
+
<span data-uk-icon="icon: menu; ratio: 1"></span>
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</header>
|
|
42
|
+
|
|
43
|
+
<!-- Mobile Offcanvas Nav -->
|
|
44
|
+
<div id="sq_mobile_offcanvas" data-uk-offcanvas="flip: true; overlay: true">
|
|
45
|
+
<div class="uk-offcanvas-bar">
|
|
46
|
+
<?php get_template_part('nav', ['mobile' => true]); ?>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<!-- Creative Offcanvas -->
|
|
51
|
+
<div id="sq-offcanvas-creative" class="sq-offcanvas-creative fixed inset-0 z-[9999] pointer-events-none text-zinc-600 shadow-2xl" data-gsap-timeline="{paused: true}">
|
|
52
|
+
|
|
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="#sq-offcanvas-creative" data-gsap="position: '<'; from: {autoAlpha: 0, duration: 0.25, ease: 'power3.out'}"></div>
|
|
55
|
+
|
|
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">
|
|
58
|
+
|
|
59
|
+
<!-- Header -->
|
|
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
|
+
<a href="#" class="sq-logo text-xl font-bold text-zinc-900" data-sq-cursor-stick>Squeditor</a>
|
|
62
|
+
<button data-gsap-reverse="#sq-offcanvas-creative" class="opacity-50 hover:opacity-100 transition-opacity" data-sq-cursor-stick>
|
|
63
|
+
<span data-uk-icon="icon: close; ratio: 1.5"></span>
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
<ul class="flex flex-col items-start justify-start gap-6 w-full p-6 lg:p-12">
|
|
69
|
+
<li class="overflow-hidden">
|
|
70
|
+
<div data-gsap="position: '>-0.2'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
71
|
+
<a class="text-4xl font-bold text-zinc-900 hover:text-zinc-900 transition-colors duration-300" href="index.html">Home</a>
|
|
72
|
+
</div>
|
|
73
|
+
</li>
|
|
74
|
+
<li class="overflow-hidden">
|
|
75
|
+
<div data-gsap="position: '<0.1'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
76
|
+
<a class="text-4xl font-bold text-zinc-900 hover:text-zinc-900 transition-colors duration-300" href="work.html">Work</a>
|
|
77
|
+
</div>
|
|
78
|
+
</li>
|
|
79
|
+
<li class="overflow-hidden">
|
|
80
|
+
<div data-gsap="position: '<0.1'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
81
|
+
<a class="text-4xl font-bold text-zinc-900 hover:text-zinc-900 transition-colors duration-300" href="services.html">Services</a>
|
|
82
|
+
</div>
|
|
83
|
+
</li>
|
|
84
|
+
<li class="overflow-hidden">
|
|
85
|
+
<div data-gsap="position: '<0.1'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
86
|
+
<a class="text-4xl font-bold text-zinc-900 hover:text-zinc-900 transition-colors duration-300" href="about.html">About</a>
|
|
87
|
+
</div>
|
|
88
|
+
</li>
|
|
89
|
+
<li class="overflow-hidden">
|
|
90
|
+
<div data-gsap="position: '<0.1'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
91
|
+
<a class="text-4xl font-bold text-zinc-900 hover:text-zinc-900 transition-colors duration-300" href="contact.html">Get in touch</a>
|
|
92
|
+
</div>
|
|
93
|
+
</li>
|
|
94
|
+
<li class="overflow-hidden mt-4">
|
|
95
|
+
<div data-gsap="position: '<0.1'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
96
|
+
<a class="text-xl font-bold text-zinc-400 hover:text-zinc-900 transition-colors duration-300" href="blog.html">Blog</a>
|
|
97
|
+
</div>
|
|
98
|
+
</li>
|
|
99
|
+
<li class="overflow-hidden">
|
|
100
|
+
<div data-gsap="position: '<0.1'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
101
|
+
<a class="text-xl font-bold text-zinc-400 hover:text-zinc-900 transition-colors duration-300" href="style-guide.html">Style Guide</a>
|
|
102
|
+
</div>
|
|
103
|
+
</li>
|
|
104
|
+
<li class="overflow-hidden">
|
|
105
|
+
<div data-gsap="position: '<0.1'; from: {yPercent: 100, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
106
|
+
<a class="text-xl font-bold text-zinc-400 hover:text-zinc-900 transition-colors duration-300" href="gsap-demo.html">Demos</a>
|
|
107
|
+
</div>
|
|
108
|
+
</li>
|
|
109
|
+
</ul>
|
|
110
|
+
|
|
111
|
+
<div class="flex items-center gap-4 w-full p-6 lg:p-12" data-gsap="position: '<0.1'; from: {yPercent: 10, opacity: 0, duration: 0.4, ease: 'power3.out'}">
|
|
112
|
+
<a href="#" class="w-12 h-12 flex items-center justify-center rounded-full bg-zinc-100 hover:bg-zinc-200 transition-colors duration-300" data-sq-cursor-stick>
|
|
113
|
+
<span data-uk-icon="icon: facebook; ratio: 1"></span>
|
|
114
|
+
</a>
|
|
115
|
+
<a href="#" class="w-12 h-12 flex items-center justify-center rounded-full bg-zinc-100 hover:bg-zinc-200 transition-colors duration-300" data-sq-cursor-stick>
|
|
116
|
+
<span data-uk-icon="icon: github; ratio: 1"></span>
|
|
117
|
+
</a>
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/template-parts/nav.php
|
|
3
|
+
$is_mobile = $mobile ?? false;
|
|
4
|
+
$nav_class = $is_mobile ? 'flex flex-col space-y-4' : 'flex space-x-2 items-center m-0 p-0';
|
|
5
|
+
?>
|
|
6
|
+
<nav>
|
|
7
|
+
<ul class="<?= $nav_class ?>">
|
|
8
|
+
<?php foreach ($site['nav'] as $item): ?>
|
|
9
|
+
<li>
|
|
10
|
+
<a href="<?= htmlspecialchars($item['url']) ?>" 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 py-2 px-3">
|
|
11
|
+
<?= htmlspecialchars($item['label']) ?>
|
|
12
|
+
</a>
|
|
13
|
+
</li>
|
|
14
|
+
<?php endforeach; ?>
|
|
15
|
+
</ul>
|
|
16
|
+
</nav>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<?php
|
|
2
|
+
// src/template-parts/page-title-bar.php
|
|
3
|
+
$title = $title ?? 'Page Title';
|
|
4
|
+
$subtitle = $subtitle ?? '';
|
|
5
|
+
$class = $class ?? 'py-20 text-center bg-zinc-50 dark:bg-zinc-800 dark:bg-opacity-40';
|
|
6
|
+
?>
|
|
7
|
+
<div class="<?= htmlspecialchars($class) ?>">
|
|
8
|
+
<div class="max-w-7xl mx-auto px-6">
|
|
9
|
+
<h1 class="text-4xl font-bold m-0"><?= htmlspecialchars($title) ?></h1>
|
|
10
|
+
<?php if ($subtitle): ?>
|
|
11
|
+
<p class="mt-4 text-base opacity-60"><?= htmlspecialchars($subtitle) ?></p>
|
|
12
|
+
<?php endif; ?>
|
|
13
|
+
</div>
|
|
14
|
+
</div>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** @type {import('tailwindcss').Config} */
|
|
2
|
+
module.exports = {
|
|
3
|
+
darkMode: ['selector', '.sq-theme-dark'],
|
|
4
|
+
content: [
|
|
5
|
+
'./src/**/*.php',
|
|
6
|
+
'./src/**/*.html',
|
|
7
|
+
],
|
|
8
|
+
theme: {
|
|
9
|
+
extend: {
|
|
10
|
+
colors: {
|
|
11
|
+
primary: 'var(--sq-color-primary)',
|
|
12
|
+
secondary: 'var(--sq-color-secondary)',
|
|
13
|
+
accent: 'var(--sq-color-accent)',
|
|
14
|
+
'transition-from': 'var(--sq-page-transition-from)',
|
|
15
|
+
'transition-via': 'var(--sq-page-transition-via)',
|
|
16
|
+
'transition-to': 'var(--sq-page-transition-to)',
|
|
17
|
+
},
|
|
18
|
+
fontFamily: {
|
|
19
|
+
sans: ['var(--sq-font-sans)'],
|
|
20
|
+
serif: ['var(--sq-font-serif)'],
|
|
21
|
+
mono: ['var(--sq-font-mono)'],
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
plugins: [],
|
|
26
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
root: 'src',
|
|
6
|
+
base: './',
|
|
7
|
+
publicDir: false, // Handle static assets via dedicated script to maintain structure
|
|
8
|
+
server: {
|
|
9
|
+
host: '127.0.0.1',
|
|
10
|
+
port: 5173,
|
|
11
|
+
strictPort: true,
|
|
12
|
+
},
|
|
13
|
+
build: {
|
|
14
|
+
outDir: path.resolve(__dirname, 'dist'),
|
|
15
|
+
emptyOutDir: true, // Wipe dist/ to clean up the assets/assets mess
|
|
16
|
+
rollupOptions: {
|
|
17
|
+
input: {
|
|
18
|
+
main: path.resolve(__dirname, 'src/assets/js/main.js'),
|
|
19
|
+
main_css: path.resolve(__dirname, 'src/assets/scss/main.scss'),
|
|
20
|
+
tailwind: path.resolve(__dirname, 'src/assets/css/tailwind.css'),
|
|
21
|
+
'squeditor-icons': path.resolve(__dirname, 'src/assets/css/squeditor-icons.css'),
|
|
22
|
+
},
|
|
23
|
+
output: {
|
|
24
|
+
entryFileNames: 'assets/js/[name].js',
|
|
25
|
+
assetFileNames: (assetInfo) => {
|
|
26
|
+
const name = assetInfo.names ? assetInfo.names[0] : assetInfo.name;
|
|
27
|
+
if (name.endsWith('.css')) return 'assets/css/[name][extname]';
|
|
28
|
+
|
|
29
|
+
// Route fonts and other compiled assets
|
|
30
|
+
const isFont = name.match(/\.(woff2?|eot|ttf|otf)$/) || name.includes('squeditor-icons.svg');
|
|
31
|
+
const isImage = !isFont && name.match(/\.(png|jpe?g|gif|svg|webp)$/);
|
|
32
|
+
|
|
33
|
+
if (isFont) {
|
|
34
|
+
if (name.startsWith('squeditor-icons')) {
|
|
35
|
+
return 'assets/static/fonts/squeditor-icons/[name][extname]';
|
|
36
|
+
}
|
|
37
|
+
return 'assets/static/fonts/[name][extname]';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (isImage) {
|
|
41
|
+
return 'assets/static/images/[name][extname]';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return 'assets/[name][extname]';
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
css: {
|
|
50
|
+
preprocessorOptions: {
|
|
51
|
+
scss: {
|
|
52
|
+
api: 'modern-compiler',
|
|
53
|
+
silenceDeprecations: ['import', 'legacy-js-api'],
|
|
54
|
+
// Global SCSS import for all files
|
|
55
|
+
additionalData: `@import "/assets/scss/_config.scss"; @import "/assets/scss/_functions.scss"; @import "/assets/scss/_tokens.scss";`,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
plugins: [{
|
|
60
|
+
name: 'php-watch',
|
|
61
|
+
handleHotUpdate({ file, server }) {
|
|
62
|
+
if (file.endsWith('.php')) {
|
|
63
|
+
server.ws.send({ type: 'full-reload' });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}],
|
|
67
|
+
});
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
// Resolve project root (cwd when running npm scripts)
|
|
5
|
+
const projectRoot = process.cwd();
|
|
6
|
+
const config = require(path.join(projectRoot, 'squeditor.config.js'));
|
|
7
|
+
const fwRoot = path.resolve(projectRoot, config.framework); // resolves ..
|
|
8
|
+
const manifest = require(path.join(fwRoot, 'uikit-manifest.json'));
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
const selectedComponents = config.components || [];
|
|
12
|
+
|
|
13
|
+
// JS output still relies on concatenation
|
|
14
|
+
const outputJsDir = path.join(projectRoot, config.output.js);
|
|
15
|
+
fs.mkdirSync(outputJsDir, { recursive: true });
|
|
16
|
+
// CSS output changes to dynamic SCSS generation
|
|
17
|
+
const outputScssDir = path.join(projectRoot, 'src/assets/scss');
|
|
18
|
+
fs.mkdirSync(outputScssDir, { recursive: true });
|
|
19
|
+
// JS and SCSS collectors
|
|
20
|
+
const jsPaths = new Set();
|
|
21
|
+
const scssPaths = new Set();
|
|
22
|
+
|
|
23
|
+
// 1. Core JS and SCSS
|
|
24
|
+
const core = manifest['_core'];
|
|
25
|
+
core.js.forEach(f => jsPaths.add(f));
|
|
26
|
+
core.css.forEach(f => scssPaths.add(f));
|
|
27
|
+
|
|
28
|
+
// 2. Component JS and SCSS
|
|
29
|
+
selectedComponents.forEach(componentName => {
|
|
30
|
+
const entry = manifest[componentName];
|
|
31
|
+
if (!entry) {
|
|
32
|
+
console.warn(`[Squeditor] Unknown component in config: "${componentName}" — skipping.`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
entry.js.forEach(f => jsPaths.add(f));
|
|
36
|
+
entry.css.forEach(f => scssPaths.add(f));
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// 3. Generate Bundles
|
|
40
|
+
let jsBundle = '';
|
|
41
|
+
jsPaths.forEach(f => {
|
|
42
|
+
const filePath = path.join(projectRoot, f.replace('node_modules/uikit/', 'node_modules/uikit/'));
|
|
43
|
+
// Special case for icon which points to dist/ specifically in manifest
|
|
44
|
+
const iconPath = path.join(projectRoot, f);
|
|
45
|
+
const finalPath = fs.existsSync(iconPath) ? iconPath : path.join(projectRoot, 'node_modules/uikit', f.replace('node_modules/uikit/', ''));
|
|
46
|
+
|
|
47
|
+
if (fs.existsSync(finalPath)) {
|
|
48
|
+
jsBundle += fs.readFileSync(finalPath, 'utf8') + '\n';
|
|
49
|
+
} else {
|
|
50
|
+
console.warn(`[Squeditor] file not found: ${finalPath}`);
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
let scssImports = '// Auto-generated by build-components.js — DO NOT EDIT\n';
|
|
55
|
+
scssImports += '// These imports point to the UIKit SCSS source files to enable tree-shaking natively via Vite\n\n';
|
|
56
|
+
scssImports += '// Core UIkit Dependencies\n';
|
|
57
|
+
|
|
58
|
+
scssPaths.forEach(f => {
|
|
59
|
+
const absolutePath = path.join(projectRoot, f);
|
|
60
|
+
const relativePath = path.relative(outputScssDir, absolutePath).replace(/\\/g, '/');
|
|
61
|
+
if (f.includes('variables.scss') || f.includes('mixins.scss')) {
|
|
62
|
+
scssImports += `@import "${relativePath}";\n`;
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
scssImports += '\n// Active UIkit Components\n';
|
|
67
|
+
scssPaths.forEach(f => {
|
|
68
|
+
if (!f.includes('variables.scss') && !f.includes('mixins.scss')) {
|
|
69
|
+
const absolutePath = path.join(projectRoot, f);
|
|
70
|
+
const relativePath = path.relative(outputScssDir, absolutePath).replace(/\\/g, '/');
|
|
71
|
+
scssImports += `@import "${relativePath}";\n`;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Finalize writes
|
|
76
|
+
fs.writeFileSync(path.join(outputJsDir, 'uikit-components.js'), jsBundle);
|
|
77
|
+
fs.writeFileSync(path.join(outputScssDir, '_uikit_dynamic.scss'), scssImports);
|
|
78
|
+
|
|
79
|
+
console.log('[Squeditor] ✅ uikit-components.js and _uikit_dynamic.scss built successfully.');
|
|
80
|
+
console.log(` Components included: _core, ${selectedComponents.join(', ')}`);
|
|
81
|
+
|
|
82
|
+
// Generate src/config/active-components.php for the style-guide page
|
|
83
|
+
const phpConfigDir = path.join(projectRoot, 'src/config');
|
|
84
|
+
fs.mkdirSync(phpConfigDir, { recursive: true });
|
|
85
|
+
const phpConfig = `<?php\n// Auto-generated by build-components.js — DO NOT EDIT\n$active_components = ${JSON.stringify(selectedComponents)};\n`;
|
|
86
|
+
fs.writeFileSync(
|
|
87
|
+
path.join(phpConfigDir, 'active-components.php'),
|
|
88
|
+
phpConfig
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Inject all themes into main.scss so live-switching works in the Style Guide
|
|
92
|
+
const mainScssPath = path.join(projectRoot, 'src/assets/scss/main.scss');
|
|
93
|
+
if (fs.existsSync(mainScssPath) && config.themes) {
|
|
94
|
+
let mainScss = fs.readFileSync(mainScssPath, 'utf8');
|
|
95
|
+
|
|
96
|
+
// Strip out any existing theme imports
|
|
97
|
+
mainScss = mainScss.replace(/@import\s+['"]themes\/[^'"]+['"];\n?/g, '');
|
|
98
|
+
|
|
99
|
+
// Append all configured themes
|
|
100
|
+
let themeImports = '';
|
|
101
|
+
Object.keys(config.themes).forEach(themeKey => {
|
|
102
|
+
themeImports += `@import 'themes/${themeKey}';\n`;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Ensure exactly one trailing newline
|
|
106
|
+
mainScss = mainScss.trim() + '\n' + themeImports;
|
|
107
|
+
fs.writeFileSync(mainScssPath, mainScss);
|
|
108
|
+
console.log(`[Squeditor] 🎨 Injected themes: ${Object.keys(config.themes).join(', ')}`);
|
|
109
|
+
}
|