ultimate-jekyll-manager 1.4.3 → 1.5.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/CHANGELOG.md +14 -0
- package/CLAUDE-ATTRIBUTION.md +215 -0
- package/CLAUDE.md +7 -6
- package/README.md +1 -0
- package/dist/assets/css/pages/test/libraries/layers/index.scss +28 -0
- package/dist/assets/js/modules/redirect.js +5 -4
- package/dist/assets/js/pages/download/index.js +1 -1
- package/dist/assets/js/pages/feedback/index.js +7 -1
- package/dist/assets/js/pages/test/libraries/layers/index.js +11 -0
- package/dist/assets/themes/_template/README.md +50 -0
- package/dist/assets/themes/_template/_config.scss +60 -0
- package/dist/assets/themes/_template/_theme.js +13 -4
- package/dist/assets/themes/_template/_theme.scss +16 -4
- package/dist/assets/themes/_template/css/base/_root.scss +19 -0
- package/dist/assets/themes/_template/css/components/_components.scss +23 -0
- package/dist/assets/themes/classy/README.md +18 -6
- package/dist/assets/themes/neobrutalism/README.md +98 -0
- package/dist/assets/themes/neobrutalism/_config.scss +139 -0
- package/dist/assets/themes/neobrutalism/_theme.js +27 -0
- package/dist/assets/themes/neobrutalism/_theme.scss +33 -0
- package/dist/assets/themes/neobrutalism/css/base/_mixins.scss +46 -0
- package/dist/assets/themes/neobrutalism/css/base/_root.scss +80 -0
- package/dist/assets/themes/neobrutalism/css/base/_typography.scss +77 -0
- package/dist/assets/themes/neobrutalism/css/base/_utilities.scss +25 -0
- package/dist/assets/themes/neobrutalism/css/components/_buttons.scss +148 -0
- package/dist/assets/themes/neobrutalism/css/components/_cards.scss +69 -0
- package/dist/assets/themes/neobrutalism/css/components/_forms.scss +88 -0
- package/dist/assets/themes/neobrutalism/css/components/_infinite-scroll.scss +94 -0
- package/dist/assets/themes/neobrutalism/css/layout/_general.scss +200 -0
- package/dist/assets/themes/neobrutalism/css/layout/_navigation.scss +153 -0
- package/dist/assets/themes/neobrutalism/js/initialize-tooltips.js +20 -0
- package/dist/assets/themes/neobrutalism/js/navbar-scroll.js +29 -0
- package/dist/assets/themes/neobrutalism/pages/index.scss +227 -0
- package/dist/assets/themes/neobrutalism/pages/pricing/index.scss +267 -0
- package/dist/assets/themes/neobrutalism/pages/test/libraries/layers/index.js +9 -0
- package/dist/assets/themes/neobrutalism/pages/test/libraries/layers/index.scss +7 -0
- package/dist/build.js +2 -5
- package/dist/commands/install.js +1 -1
- package/dist/commands/setup.js +41 -0
- package/dist/defaults/CLAUDE.md +5 -1
- package/dist/defaults/dist/_includes/core/head.html +17 -0
- package/dist/defaults/dist/_includes/themes/classy/frontend/sections/footer.html +4 -4
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +2 -0
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/feedback.html +7 -3
- package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/core/base.html +31 -0
- package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/pages/index.html +345 -0
- package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/pages/pricing.html +483 -0
- package/dist/defaults/dist/pages/test/libraries/layers.html +57 -0
- package/dist/defaults/src/_config.yml +2 -0
- package/dist/defaults/test/_init.js +10 -0
- package/dist/gulp/tasks/defaults.js +8 -0
- package/dist/gulp/tasks/sass.js +43 -2
- package/dist/gulp/tasks/translation.js +11 -0
- package/dist/gulp/tasks/utils/manage-test-layers.js +97 -0
- package/dist/index.js +30 -4
- package/dist/test/runner.js +62 -0
- package/dist/test/suites/build/manager.test.js +11 -4
- package/dist/test/suites/build/mode-helpers.test.js +54 -2
- package/dist/utils/mode-helpers.js +65 -40
- package/docs/assets.md +6 -1
- package/docs/environment-detection.md +85 -0
- package/docs/test-framework.md +48 -3
- package/docs/themes.md +451 -0
- package/package.json +2 -1
- package/docs/cross-context-helpers.md +0 -75
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
// Neobrutalism Theme — Homepage page-specific CSS
|
|
2
|
+
// Styles the neobrutalist homepage override
|
|
3
|
+
// (_layouts/themes/neobrutalism/frontend/pages/index.html).
|
|
4
|
+
//
|
|
5
|
+
// Class names are UNIVERSAL (section-hero, showcase-row, stat-block, cta-panel,
|
|
6
|
+
// .card, Bootstrap .text-bg-* …) — no theme prefix — so the same markup is
|
|
7
|
+
// swappable across themes. This file gives those classes the neobrutalist look.
|
|
8
|
+
// Compiles standalone, so it pulls in the theme tokens + mixins via loadPaths.
|
|
9
|
+
@use 'config' as *;
|
|
10
|
+
@import 'css/base/mixins';
|
|
11
|
+
|
|
12
|
+
// Shared section heading block
|
|
13
|
+
.section-head { max-width: 60ch; }
|
|
14
|
+
.section-title {
|
|
15
|
+
font-family: $nb-font-display;
|
|
16
|
+
font-weight: 900;
|
|
17
|
+
font-size: clamp(2rem, 5vw, 3.5rem);
|
|
18
|
+
letter-spacing: -0.03em;
|
|
19
|
+
line-height: 1;
|
|
20
|
+
margin: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// ============================================
|
|
24
|
+
// Hero — asymmetric split (.text-bg-warning gives the yellow block + ink text)
|
|
25
|
+
// ============================================
|
|
26
|
+
.section-hero {
|
|
27
|
+
padding-top: clamp(3rem, 8vw, 7rem);
|
|
28
|
+
padding-bottom: clamp(3rem, 8vw, 7rem);
|
|
29
|
+
border-bottom: $nb-border-width-lg solid var(--nb-border-color);
|
|
30
|
+
|
|
31
|
+
.text-uppercase {
|
|
32
|
+
display: inline-block;
|
|
33
|
+
font-family: $nb-font-mono;
|
|
34
|
+
font-weight: 700;
|
|
35
|
+
letter-spacing: 0.08em;
|
|
36
|
+
background: #111111;
|
|
37
|
+
color: var(--nb-accent-yellow);
|
|
38
|
+
padding: 0.4rem 0.8rem;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.hero-title {
|
|
43
|
+
font-family: $nb-font-display;
|
|
44
|
+
font-weight: 900;
|
|
45
|
+
font-size: clamp(2.75rem, 8vw, 6rem);
|
|
46
|
+
line-height: 0.92;
|
|
47
|
+
letter-spacing: -0.04em;
|
|
48
|
+
margin: 0;
|
|
49
|
+
|
|
50
|
+
.text-accent {
|
|
51
|
+
background: #111111;
|
|
52
|
+
color: var(--nb-accent-yellow);
|
|
53
|
+
padding: 0 0.1em;
|
|
54
|
+
box-decoration-break: clone;
|
|
55
|
+
-webkit-box-decoration-break: clone;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Hero CTAs use Bootstrap `.d-grid.gap-3` (full-width stacked buttons) in the
|
|
60
|
+
// markup. The only theme-specific bit is the slight rightward offset on large
|
|
61
|
+
// screens that gives the split hero its asymmetry.
|
|
62
|
+
.hero-actions {
|
|
63
|
+
@media (min-width: 992px) { margin-left: 1.5rem; }
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ============================================
|
|
67
|
+
// Trusted-by — framed marquee strip
|
|
68
|
+
// ============================================
|
|
69
|
+
.logo-strip { padding: clamp(2.5rem, 6vw, 4rem) 0; }
|
|
70
|
+
.logo-strip-box {
|
|
71
|
+
position: relative;
|
|
72
|
+
padding: 2rem 0 1.75rem;
|
|
73
|
+
background: var(--nb-surface);
|
|
74
|
+
@include nb-border();
|
|
75
|
+
@include nb-shadow(md);
|
|
76
|
+
overflow: hidden;
|
|
77
|
+
}
|
|
78
|
+
.logo-strip-label {
|
|
79
|
+
position: absolute;
|
|
80
|
+
top: 0;
|
|
81
|
+
left: 0;
|
|
82
|
+
font-family: $nb-font-mono;
|
|
83
|
+
font-weight: 700;
|
|
84
|
+
font-size: 0.75rem;
|
|
85
|
+
letter-spacing: 0.08em;
|
|
86
|
+
text-transform: uppercase;
|
|
87
|
+
background: #111111;
|
|
88
|
+
color: var(--nb-accent-yellow);
|
|
89
|
+
padding: 0.3rem 0.7rem;
|
|
90
|
+
z-index: 5;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// ============================================
|
|
94
|
+
// Showcase — alternating offset rows
|
|
95
|
+
// ============================================
|
|
96
|
+
.showcase { padding: clamp(3rem, 8vw, 6rem) 0; }
|
|
97
|
+
.showcase-list { display: flex; flex-direction: column; gap: 2rem; }
|
|
98
|
+
.showcase-row {
|
|
99
|
+
display: grid;
|
|
100
|
+
// Number column fixed; text column sized to content so it sits next to the
|
|
101
|
+
// number instead of stretching across the row (which left an awkward gap).
|
|
102
|
+
grid-template-columns: minmax(120px, 180px) minmax(auto, 60ch);
|
|
103
|
+
gap: 2.5rem;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: start;
|
|
106
|
+
|
|
107
|
+
@media (max-width: 767.98px) { grid-template-columns: 1fr; gap: 1rem; }
|
|
108
|
+
|
|
109
|
+
// Flipped rows: number moves to the right, the whole pair sits to the right edge.
|
|
110
|
+
&--flip {
|
|
111
|
+
@media (min-width: 768px) {
|
|
112
|
+
grid-template-columns: minmax(auto, 60ch) minmax(120px, 180px);
|
|
113
|
+
justify-content: end;
|
|
114
|
+
.showcase-num { order: 2; }
|
|
115
|
+
.showcase-body { order: 1; }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
.showcase-num {
|
|
120
|
+
font-family: $nb-font-display;
|
|
121
|
+
font-weight: 900;
|
|
122
|
+
font-size: clamp(3rem, 9vw, 6rem);
|
|
123
|
+
line-height: 1;
|
|
124
|
+
display: flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
justify-content: center;
|
|
127
|
+
aspect-ratio: 1;
|
|
128
|
+
@include nb-border($nb-border-width-lg);
|
|
129
|
+
@include nb-shadow(lg);
|
|
130
|
+
// Color comes from the Bootstrap .text-bg-* utility on the element.
|
|
131
|
+
}
|
|
132
|
+
.showcase-body { max-width: 60ch; }
|
|
133
|
+
.showcase-title {
|
|
134
|
+
font-family: $nb-font-display;
|
|
135
|
+
font-weight: 800;
|
|
136
|
+
font-size: clamp(1.5rem, 3.5vw, 2.25rem);
|
|
137
|
+
letter-spacing: -0.02em;
|
|
138
|
+
margin-bottom: 0.75rem;
|
|
139
|
+
}
|
|
140
|
+
.showcase-desc { font-size: 1.1rem; margin: 0; color: var(--bs-body-color); }
|
|
141
|
+
|
|
142
|
+
// ============================================
|
|
143
|
+
// Steps (features) — numbered .card blocks
|
|
144
|
+
// ============================================
|
|
145
|
+
.steps {
|
|
146
|
+
padding: clamp(3rem, 8vw, 6rem) 0;
|
|
147
|
+
border-top: $nb-border-width-lg solid var(--nb-border-color);
|
|
148
|
+
border-bottom: $nb-border-width-lg solid var(--nb-border-color);
|
|
149
|
+
}
|
|
150
|
+
.step-card { // sits on .card (gets the neobrutalist frame from the card component)
|
|
151
|
+
.card-body { padding: 1.75rem; }
|
|
152
|
+
}
|
|
153
|
+
.step-card-top {
|
|
154
|
+
display: flex;
|
|
155
|
+
align-items: center;
|
|
156
|
+
justify-content: space-between;
|
|
157
|
+
margin-bottom: 1.25rem;
|
|
158
|
+
}
|
|
159
|
+
.step-card-num { font-family: $nb-font-display; font-weight: 900; font-size: 2.5rem; line-height: 1; }
|
|
160
|
+
.step-card-icon {
|
|
161
|
+
font-size: 1.75rem;
|
|
162
|
+
width: 3.25rem;
|
|
163
|
+
height: 3.25rem;
|
|
164
|
+
display: inline-flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
justify-content: center;
|
|
167
|
+
background: var(--nb-accent-yellow);
|
|
168
|
+
color: #111111;
|
|
169
|
+
@include nb-border($nb-border-width-sm);
|
|
170
|
+
}
|
|
171
|
+
.step-card-title { font-family: $nb-font-display; font-weight: 800; font-size: 1.5rem; margin-bottom: 0.5rem; }
|
|
172
|
+
.step-card-desc { margin: 0; color: var(--bs-body-color); }
|
|
173
|
+
|
|
174
|
+
// ============================================
|
|
175
|
+
// Stats — oversized color-block cells (.text-bg-* gives the fill)
|
|
176
|
+
// ============================================
|
|
177
|
+
.stats { padding: clamp(3rem, 8vw, 6rem) 0; }
|
|
178
|
+
.stats-grid {
|
|
179
|
+
display: grid;
|
|
180
|
+
grid-template-columns: repeat(4, 1fr);
|
|
181
|
+
gap: 1.5rem;
|
|
182
|
+
|
|
183
|
+
@media (max-width: 991.98px) { grid-template-columns: repeat(2, 1fr); }
|
|
184
|
+
@media (max-width: 479.98px) { grid-template-columns: 1fr; }
|
|
185
|
+
}
|
|
186
|
+
.stat-block {
|
|
187
|
+
display: flex;
|
|
188
|
+
flex-direction: column;
|
|
189
|
+
padding: 1.75rem;
|
|
190
|
+
@include nb-border($nb-border-width-lg);
|
|
191
|
+
@include nb-shadow(lg);
|
|
192
|
+
@include nb-press($nb-shadow-offset-lg); // press matched to the lg resting shadow
|
|
193
|
+
}
|
|
194
|
+
.stat-block-num { font-family: $nb-font-display; font-weight: 900; font-size: clamp(2.5rem, 6vw, 3.5rem); line-height: 1; }
|
|
195
|
+
.stat-block-label { font-weight: 800; font-size: 1.1rem; margin-top: 0.5rem; }
|
|
196
|
+
.stat-block-sub { font-family: $nb-font-mono; font-size: 0.8rem; margin-top: 0.25rem; }
|
|
197
|
+
|
|
198
|
+
// ============================================
|
|
199
|
+
// CTA — full-bleed ink panel
|
|
200
|
+
// ============================================
|
|
201
|
+
.cta { padding: clamp(3rem, 8vw, 6rem) 0; }
|
|
202
|
+
.cta-panel {
|
|
203
|
+
background: #111111;
|
|
204
|
+
color: #FFFEF2;
|
|
205
|
+
padding: clamp(2.5rem, 6vw, 4.5rem);
|
|
206
|
+
text-align: center;
|
|
207
|
+
// Frame + offset shadow in the accent (not ink) so both read against the dark panel.
|
|
208
|
+
border: $nb-border-width-lg solid var(--nb-accent-yellow);
|
|
209
|
+
box-shadow: #{$nb-shadow-offset-lg} #{$nb-shadow-offset-lg} 0 var(--nb-accent-yellow);
|
|
210
|
+
}
|
|
211
|
+
.cta-title {
|
|
212
|
+
font-family: $nb-font-display;
|
|
213
|
+
font-weight: 900;
|
|
214
|
+
font-size: clamp(2rem, 6vw, 4rem);
|
|
215
|
+
line-height: 1;
|
|
216
|
+
letter-spacing: -0.03em;
|
|
217
|
+
margin-bottom: 1.25rem;
|
|
218
|
+
|
|
219
|
+
.text-accent {
|
|
220
|
+
background: var(--nb-accent-yellow);
|
|
221
|
+
color: #111111;
|
|
222
|
+
padding: 0 0.1em;
|
|
223
|
+
box-decoration-break: clone;
|
|
224
|
+
-webkit-box-decoration-break: clone;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
.cta-desc { font-size: 1.25rem; max-width: 50ch; margin: 0 auto 2rem; opacity: 0.85; }
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
// Neobrutalism Theme — Pricing page-specific CSS
|
|
2
|
+
// Styles the neobrutalist pricing override. Class names are UNIVERSAL (no theme
|
|
3
|
+
// prefix) so the markup is swappable across themes. Compiles to its own bundle
|
|
4
|
+
// (pages/pricing/index.neobrutalism.bundle.css). See docs/themes.md.
|
|
5
|
+
@use 'config' as *;
|
|
6
|
+
@import 'css/base/mixins';
|
|
7
|
+
|
|
8
|
+
// Section heading (also defined in homepage bundle; page bundles are independent)
|
|
9
|
+
.section-head { max-width: 60ch; }
|
|
10
|
+
.section-title {
|
|
11
|
+
font-family: $nb-font-display;
|
|
12
|
+
font-weight: 900;
|
|
13
|
+
font-size: clamp(2rem, 5vw, 3.5rem);
|
|
14
|
+
letter-spacing: -0.03em;
|
|
15
|
+
line-height: 1;
|
|
16
|
+
margin: 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ============================================
|
|
20
|
+
// Hero
|
|
21
|
+
// ============================================
|
|
22
|
+
.pricing-hero {
|
|
23
|
+
text-align: center;
|
|
24
|
+
padding: clamp(3rem, 7vw, 5rem) 0 clamp(2rem, 4vw, 3rem);
|
|
25
|
+
}
|
|
26
|
+
.pricing-title {
|
|
27
|
+
font-family: $nb-font-display;
|
|
28
|
+
font-weight: 900;
|
|
29
|
+
font-size: clamp(2.5rem, 7vw, 5rem);
|
|
30
|
+
line-height: 0.95;
|
|
31
|
+
letter-spacing: -0.03em;
|
|
32
|
+
margin-bottom: 1rem;
|
|
33
|
+
|
|
34
|
+
.text-accent {
|
|
35
|
+
background: var(--nb-accent-yellow);
|
|
36
|
+
color: #111111;
|
|
37
|
+
padding: 0 0.1em;
|
|
38
|
+
box-decoration-break: clone;
|
|
39
|
+
-webkit-box-decoration-break: clone;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ============================================
|
|
44
|
+
// Billing toggle — hard square segmented control
|
|
45
|
+
// ============================================
|
|
46
|
+
.billing-toggle {
|
|
47
|
+
display: flex;
|
|
48
|
+
justify-content: center;
|
|
49
|
+
margin: 0 auto 1.5rem;
|
|
50
|
+
width: 100%;
|
|
51
|
+
max-width: 420px;
|
|
52
|
+
@include nb-border();
|
|
53
|
+
@include nb-shadow(md);
|
|
54
|
+
}
|
|
55
|
+
.billing-option {
|
|
56
|
+
flex: 1;
|
|
57
|
+
text-align: center;
|
|
58
|
+
padding: 0.85rem 1rem;
|
|
59
|
+
font-family: $nb-font-display;
|
|
60
|
+
font-weight: 700;
|
|
61
|
+
cursor: pointer;
|
|
62
|
+
background: var(--nb-surface);
|
|
63
|
+
color: var(--bs-body-color);
|
|
64
|
+
transition: $nb-transition;
|
|
65
|
+
margin: 0;
|
|
66
|
+
|
|
67
|
+
& + .billing-option { border-left: $nb-border-width solid var(--nb-border-color); }
|
|
68
|
+
|
|
69
|
+
.btn-check:checked + & {
|
|
70
|
+
background: #111111;
|
|
71
|
+
color: var(--nb-accent-yellow);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
.billing-save {
|
|
75
|
+
display: inline-block;
|
|
76
|
+
font-family: $nb-font-mono;
|
|
77
|
+
font-size: 0.65rem;
|
|
78
|
+
font-weight: 700;
|
|
79
|
+
text-transform: uppercase;
|
|
80
|
+
background: var(--nb-accent-yellow);
|
|
81
|
+
color: #111111;
|
|
82
|
+
padding: 0.1rem 0.35rem;
|
|
83
|
+
margin-left: 0.35rem;
|
|
84
|
+
vertical-align: middle;
|
|
85
|
+
}
|
|
86
|
+
.btn-check:checked + .billing-option .billing-save { background: var(--nb-accent-yellow); }
|
|
87
|
+
|
|
88
|
+
// ============================================
|
|
89
|
+
// Plan grid — popular plan emphasized (equal height, same baseline)
|
|
90
|
+
// ============================================
|
|
91
|
+
.pricing-plan-grid {
|
|
92
|
+
display: grid;
|
|
93
|
+
grid-template-columns: repeat(4, 1fr);
|
|
94
|
+
gap: 1.5rem;
|
|
95
|
+
align-items: stretch; // all cards fill the row's full height → equal height
|
|
96
|
+
margin-bottom: 2rem;
|
|
97
|
+
|
|
98
|
+
@media (max-width: 1199.98px) { grid-template-columns: repeat(2, 1fr); }
|
|
99
|
+
@media (max-width: 575.98px) { grid-template-columns: 1fr; }
|
|
100
|
+
}
|
|
101
|
+
.pricing-plan { // sits on .card (frame/shadow come from the card component)
|
|
102
|
+
position: relative;
|
|
103
|
+
display: flex;
|
|
104
|
+
flex-direction: column; // lets the features list grow so footers align
|
|
105
|
+
padding: 1.75rem 1.5rem;
|
|
106
|
+
// No press interaction on the card itself — it's not clickable. Only the CTA
|
|
107
|
+
// button inside reacts to the pointer.
|
|
108
|
+
|
|
109
|
+
// Features sit directly under the divider (top of the lower half), not pushed
|
|
110
|
+
// to the bottom. Cards stay equal height via the grid's align-items: stretch.
|
|
111
|
+
|
|
112
|
+
// Popular plan: accent fill + thicker frame. Same height + same press as the others.
|
|
113
|
+
&--popular {
|
|
114
|
+
background: var(--nb-accent-yellow);
|
|
115
|
+
color: #111111;
|
|
116
|
+
@include nb-border($nb-border-width-lg);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
.pricing-plan-flag {
|
|
120
|
+
position: absolute;
|
|
121
|
+
top: 0;
|
|
122
|
+
right: 0;
|
|
123
|
+
transform: translateY(-50%);
|
|
124
|
+
font-family: $nb-font-mono;
|
|
125
|
+
font-weight: 700;
|
|
126
|
+
font-size: 0.7rem;
|
|
127
|
+
text-transform: uppercase;
|
|
128
|
+
letter-spacing: 0.05em;
|
|
129
|
+
background: #111111;
|
|
130
|
+
color: var(--nb-accent-yellow);
|
|
131
|
+
padding: 0.3rem 0.6rem;
|
|
132
|
+
}
|
|
133
|
+
.pricing-plan-name {
|
|
134
|
+
font-family: $nb-font-display;
|
|
135
|
+
font-weight: 900;
|
|
136
|
+
font-size: 1.75rem;
|
|
137
|
+
margin-bottom: 0.15rem;
|
|
138
|
+
}
|
|
139
|
+
.pricing-plan-tagline {
|
|
140
|
+
font-family: $nb-font-mono;
|
|
141
|
+
font-size: 0.8rem;
|
|
142
|
+
opacity: 0.7;
|
|
143
|
+
margin-bottom: 1rem;
|
|
144
|
+
}
|
|
145
|
+
.pricing-plan-price {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: baseline;
|
|
148
|
+
gap: 0.1rem;
|
|
149
|
+
margin-bottom: 0.25rem;
|
|
150
|
+
}
|
|
151
|
+
.pricing-plan-currency { font-family: $nb-font-display; font-weight: 900; font-size: 1.5rem; }
|
|
152
|
+
.pricing-plan-amount { font-family: $nb-font-display; font-weight: 900; font-size: 3rem; line-height: 1; }
|
|
153
|
+
.pricing-plan-per { font-family: $nb-font-mono; font-size: 0.85rem; opacity: 0.7; }
|
|
154
|
+
.pricing-plan-ppu { font-family: $nb-font-mono; font-size: 0.75rem; opacity: 0.7; margin-bottom: 1.25rem; min-height: 1.2em; }
|
|
155
|
+
.pricing-plan-billing { font-size: 0.8rem; text-align: center; opacity: 0.75; margin-bottom: 0.4rem; }
|
|
156
|
+
.pricing-plan-guarantee { font-size: 0.8rem; text-align: center; opacity: 0.8; margin-bottom: 1rem; }
|
|
157
|
+
.pricing-plan-rule {
|
|
158
|
+
border: 0;
|
|
159
|
+
border-top: $nb-border-width-sm solid currentColor;
|
|
160
|
+
opacity: 0.25;
|
|
161
|
+
margin: 0 0 1.25rem;
|
|
162
|
+
}
|
|
163
|
+
.pricing-plan-features {
|
|
164
|
+
list-style: none;
|
|
165
|
+
padding: 0;
|
|
166
|
+
margin: 0;
|
|
167
|
+
display: flex;
|
|
168
|
+
flex-direction: column;
|
|
169
|
+
gap: 0.6rem;
|
|
170
|
+
|
|
171
|
+
li { display: flex; align-items: flex-start; gap: 0.6rem; font-size: 0.95rem; font-weight: 500; }
|
|
172
|
+
|
|
173
|
+
// Spacing when a second (additional-features) list follows the inherit label
|
|
174
|
+
& + .pricing-plan-inherit { margin-top: 1rem; }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// "Everything in <plan>, and more:" / "What you get:" tier-inheritance label
|
|
178
|
+
.pricing-plan-inherit {
|
|
179
|
+
font-family: $nb-font-mono;
|
|
180
|
+
font-size: 0.8rem;
|
|
181
|
+
opacity: 0.7;
|
|
182
|
+
margin: 0 0 0.6rem;
|
|
183
|
+
|
|
184
|
+
strong { font-weight: 700; opacity: 1; }
|
|
185
|
+
}
|
|
186
|
+
.pricing-plan-feature-icon {
|
|
187
|
+
flex-shrink: 0;
|
|
188
|
+
width: 1.5rem;
|
|
189
|
+
height: 1.5rem;
|
|
190
|
+
display: inline-flex;
|
|
191
|
+
align-items: center;
|
|
192
|
+
justify-content: center;
|
|
193
|
+
background: var(--nb-accent-green);
|
|
194
|
+
color: #111111;
|
|
195
|
+
@include nb-border($nb-border-width-sm);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Enterprise strip (sits on .card)
|
|
199
|
+
.enterprise-panel {
|
|
200
|
+
display: flex;
|
|
201
|
+
flex-direction: row;
|
|
202
|
+
align-items: center;
|
|
203
|
+
justify-content: space-between;
|
|
204
|
+
gap: 1.5rem;
|
|
205
|
+
padding: 1.75rem 2rem;
|
|
206
|
+
flex-wrap: wrap;
|
|
207
|
+
}
|
|
208
|
+
.enterprise-panel-title { font-family: $nb-font-display; font-weight: 900; font-size: 1.75rem; margin-bottom: 0.25rem; }
|
|
209
|
+
|
|
210
|
+
// ============================================
|
|
211
|
+
// Stats / social proof (.text-bg-* gives the fill)
|
|
212
|
+
// ============================================
|
|
213
|
+
.stats { padding: clamp(3rem, 8vw, 6rem) 0; }
|
|
214
|
+
.stats-grid {
|
|
215
|
+
display: grid;
|
|
216
|
+
grid-template-columns: repeat(4, 1fr);
|
|
217
|
+
gap: 1.5rem;
|
|
218
|
+
|
|
219
|
+
@media (max-width: 991.98px) { grid-template-columns: repeat(2, 1fr); }
|
|
220
|
+
@media (max-width: 479.98px) { grid-template-columns: 1fr; }
|
|
221
|
+
}
|
|
222
|
+
.stat-block {
|
|
223
|
+
display: flex;
|
|
224
|
+
flex-direction: column;
|
|
225
|
+
padding: 1.75rem;
|
|
226
|
+
@include nb-border($nb-border-width-lg);
|
|
227
|
+
@include nb-shadow(lg);
|
|
228
|
+
@include nb-press($nb-shadow-offset-lg); // press matched to the lg resting shadow
|
|
229
|
+
}
|
|
230
|
+
.stat-block-num { font-family: $nb-font-display; font-weight: 900; font-size: clamp(2.5rem, 6vw, 3.5rem); line-height: 1; }
|
|
231
|
+
.stat-block-label { font-weight: 800; font-size: 1.1rem; margin-top: 0.5rem; }
|
|
232
|
+
|
|
233
|
+
// ============================================
|
|
234
|
+
// FAQ
|
|
235
|
+
// ============================================
|
|
236
|
+
.faq { padding: clamp(3rem, 8vw, 6rem) 0; }
|
|
237
|
+
|
|
238
|
+
// ============================================
|
|
239
|
+
// CTA — full-bleed ink panel
|
|
240
|
+
// ============================================
|
|
241
|
+
.cta { padding: clamp(3rem, 8vw, 6rem) 0; }
|
|
242
|
+
.cta-panel {
|
|
243
|
+
background: #111111;
|
|
244
|
+
color: #FFFEF2;
|
|
245
|
+
padding: clamp(2.5rem, 6vw, 4.5rem);
|
|
246
|
+
text-align: center;
|
|
247
|
+
// Frame + offset shadow in the accent (not ink) so both read against the dark panel.
|
|
248
|
+
border: $nb-border-width-lg solid var(--nb-accent-yellow);
|
|
249
|
+
box-shadow: #{$nb-shadow-offset-lg} #{$nb-shadow-offset-lg} 0 var(--nb-accent-yellow);
|
|
250
|
+
}
|
|
251
|
+
.cta-title {
|
|
252
|
+
font-family: $nb-font-display;
|
|
253
|
+
font-weight: 900;
|
|
254
|
+
font-size: clamp(2rem, 6vw, 4rem);
|
|
255
|
+
line-height: 1;
|
|
256
|
+
letter-spacing: -0.03em;
|
|
257
|
+
margin-bottom: 1.25rem;
|
|
258
|
+
|
|
259
|
+
.text-accent {
|
|
260
|
+
background: var(--nb-accent-yellow);
|
|
261
|
+
color: #111111;
|
|
262
|
+
padding: 0 0.1em;
|
|
263
|
+
box-decoration-break: clone;
|
|
264
|
+
-webkit-box-decoration-break: clone;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
.cta-desc { font-size: 1.25rem; max-width: 50ch; margin: 0 auto 2rem; opacity: 0.85; }
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// /test — Theme (neobrutalism) page JS — the #theme layer.
|
|
2
|
+
// Runs AFTER #main, BEFORE #project. Turns the "js-theme" dot green.
|
|
3
|
+
export default ({ manager, options }) => {
|
|
4
|
+
const dot = document.querySelector('.layer-dot[data-layer="js-theme"]');
|
|
5
|
+
if (dot) {
|
|
6
|
+
dot.style.background = '#30a46c'; // green
|
|
7
|
+
}
|
|
8
|
+
console.log('[test-layer] #theme JS ran → js-theme dot green');
|
|
9
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// /test — Theme (neobrutalism) page CSS — the #theme layer.
|
|
2
|
+
// Loads AFTER the universal layer and turns the "css-theme" dot green.
|
|
3
|
+
// Compiles standalone, so no theme tokens are needed here — just the proof.
|
|
4
|
+
|
|
5
|
+
.layer-dot[data-layer="css-theme"] {
|
|
6
|
+
background: #30a46c; // green
|
|
7
|
+
}
|
package/dist/build.js
CHANGED
|
@@ -110,11 +110,8 @@ Manager.actLikeProduction = function () {
|
|
|
110
110
|
}
|
|
111
111
|
Manager.prototype.actLikeProduction = Manager.actLikeProduction;
|
|
112
112
|
|
|
113
|
-
// getEnvironment
|
|
114
|
-
|
|
115
|
-
return Manager.isServer() ? 'production' : 'development';
|
|
116
|
-
}
|
|
117
|
-
Manager.prototype.getEnvironment = Manager.getEnvironment;
|
|
113
|
+
// getEnvironment() is the SSOT and lives in src/utils/mode-helpers.js (alongside the is*()
|
|
114
|
+
// family). It's mixed onto the Manager via the attachTo() call below, same as in EM/BXM.
|
|
118
115
|
|
|
119
116
|
// getConfig: requires and parses config.yml
|
|
120
117
|
Manager.getConfig = function (type) {
|
package/dist/commands/install.js
CHANGED
package/dist/commands/setup.js
CHANGED
|
@@ -39,6 +39,7 @@ module.exports = async function (options) {
|
|
|
39
39
|
options.checkLocality = options.checkLocality !== 'false';
|
|
40
40
|
options.publishGitHubToken = options.publishGitHubToken !== 'false';
|
|
41
41
|
options.deduplicatePosts = options.deduplicatePosts !== 'false';
|
|
42
|
+
options.removeLegacyTeamMembers = options.removeLegacyTeamMembers !== 'false';
|
|
42
43
|
options.migrate = options.migrate !== 'false';
|
|
43
44
|
|
|
44
45
|
// Quick mode: skip slow/network operations
|
|
@@ -137,6 +138,11 @@ module.exports = async function (options) {
|
|
|
137
138
|
if (options.deduplicatePosts) {
|
|
138
139
|
await deduplicatePosts();
|
|
139
140
|
}
|
|
141
|
+
|
|
142
|
+
// Remove legacy default team members (first-name-only format, e.g. team/alex)
|
|
143
|
+
if (options.removeLegacyTeamMembers) {
|
|
144
|
+
await removeLegacyTeamMembers();
|
|
145
|
+
}
|
|
140
146
|
};
|
|
141
147
|
|
|
142
148
|
// --- Version check functions ---
|
|
@@ -527,6 +533,41 @@ async function deduplicatePosts() {
|
|
|
527
533
|
}
|
|
528
534
|
}
|
|
529
535
|
|
|
536
|
+
async function removeLegacyTeamMembers() {
|
|
537
|
+
// Legacy default team members that used the first-name-only format.
|
|
538
|
+
// These shipped before team members were renamed to first-last (e.g. team/alex -> team/alex-raeburn).
|
|
539
|
+
const legacyTeamMembers = ['alex'];
|
|
540
|
+
|
|
541
|
+
logger.log('Checking for legacy default team members to remove...');
|
|
542
|
+
|
|
543
|
+
let removedCount = 0;
|
|
544
|
+
|
|
545
|
+
legacyTeamMembers.forEach((slug) => {
|
|
546
|
+
// The _team collection file (any markdown/html extension)
|
|
547
|
+
const memberFiles = glob(`src/_team/${slug}.{md,markdown,html}`, { nodir: true });
|
|
548
|
+
|
|
549
|
+
memberFiles.forEach((filePath) => {
|
|
550
|
+
jetpack.remove(filePath);
|
|
551
|
+
logger.log(` ✓ Removed legacy team member: ${filePath}`);
|
|
552
|
+
removedCount++;
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// The associated image directory (src/assets/images/team/<slug>)
|
|
556
|
+
const imageDir = path.join(process.cwd(), 'src', 'assets', 'images', 'team', slug);
|
|
557
|
+
|
|
558
|
+
if (jetpack.exists(imageDir)) {
|
|
559
|
+
jetpack.remove(imageDir);
|
|
560
|
+
logger.log(` ✓ Removed legacy team member image directory: team/${slug}`);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
if (removedCount > 0) {
|
|
565
|
+
logger.log(logger.format.green(`✓ Removed ${removedCount} legacy team member(s)`));
|
|
566
|
+
} else {
|
|
567
|
+
logger.log('No legacy team members found');
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
|
|
530
571
|
// --- Migration functions ---
|
|
531
572
|
|
|
532
573
|
async function migrate() {
|
package/dist/defaults/CLAUDE.md
CHANGED
|
@@ -29,8 +29,12 @@ npm run build # production build (UJ_BUILD_MODE=true): clean → setup →
|
|
|
29
29
|
npm run deploy # build → `npu sync --message='Deploy'` (publishes _site/)
|
|
30
30
|
npx mgr test # run framework + project test suites (build / page / boot layers)
|
|
31
31
|
npx mgr audit # HTML validation + spellcheck + optional Lighthouse
|
|
32
|
+
npx mgr install dev # use LOCAL ultimate-jekyll-manager source (to test framework edits)
|
|
33
|
+
npx mgr install live # restore the published ultimate-jekyll-manager from npm
|
|
32
34
|
```
|
|
33
35
|
|
|
36
|
+
> Editing the UJM framework source while working here? Run `npx mgr install dev` so this project picks up your uncommitted framework changes (it otherwise uses its installed `node_modules/ultimate-jekyll-manager`). Run `npx mgr install live` to switch back.
|
|
37
|
+
|
|
34
38
|
## Where things live
|
|
35
39
|
|
|
36
40
|
- `src/_config.yml` — Jekyll config: brand, theme, meta, web_manager (Firebase). `Manager.getConfig('project')` reads this. **`brand.id` + `theme.id` are required.**
|
|
@@ -72,7 +76,7 @@ At build time, `require('ultimate-jekyll-manager/build')` exposes:
|
|
|
72
76
|
- `Manager.getConfig(type)` — read `_config.yml` (`'project'` or `'main'`)
|
|
73
77
|
- `Manager.getPackage(type)` — read `package.json` (`'project'` or `'main'`)
|
|
74
78
|
- `Manager.getUJMConfig()` — read `config/ultimate-jekyll-manager.json`
|
|
75
|
-
- `Manager.getEnvironment()` — `'development'
|
|
79
|
+
- `Manager.getEnvironment()` — `'development' | 'testing' | 'production'` (mutually exclusive; testing wins). Gate side effects on the intentional check (`isProduction()` for prod-only; `isDevelopment() || isTesting()` for local-or-test) — never `!isDevelopment()`.
|
|
76
80
|
- `Manager.isBuildMode()` / `isQuickMode()` / `isServer()` / `actLikeProduction()` — env-gated flags
|
|
77
81
|
- `Manager.logger(name)` — timestamped logger instance
|
|
78
82
|
- `Manager.require(path)` — escape hatch for UJM transitive deps (use sparingly)
|
|
@@ -26,12 +26,15 @@
|
|
|
26
26
|
|
|
27
27
|
{% iftruthy page.resolved.asset_path %}
|
|
28
28
|
{% capture page-css-path %}/assets/css/pages/{{ page.resolved.asset_path }}.bundle.css{% endcapture %}
|
|
29
|
+
{% capture page-css-theme-path %}/assets/css/pages/{{ page.resolved.asset_path }}.{{ page.resolved.theme.id }}.bundle.css{% endcapture %}
|
|
29
30
|
{% endiftruthy %}
|
|
30
31
|
{% iffalsy page.resolved.asset_path %}
|
|
31
32
|
{% if page.canonical.path == "/" %}
|
|
32
33
|
{% capture page-css-path %}/assets/css/pages/index.bundle.css{% endcapture %}
|
|
34
|
+
{% capture page-css-theme-path %}/assets/css/pages/index.{{ page.resolved.theme.id }}.bundle.css{% endcapture %}
|
|
33
35
|
{% else %}
|
|
34
36
|
{% capture page-css-path %}/assets/css/pages{{ page.canonical.path }}/index.bundle.css{% endcapture %}
|
|
37
|
+
{% capture page-css-theme-path %}/assets/css/pages{{ page.canonical.path }}/index.{{ page.resolved.theme.id }}.bundle.css{% endcapture %}
|
|
35
38
|
{% endif %}
|
|
36
39
|
{% endiffalsy %}
|
|
37
40
|
|
|
@@ -210,6 +213,20 @@
|
|
|
210
213
|
{% endif %}
|
|
211
214
|
{% endiffile %}
|
|
212
215
|
|
|
216
|
+
<!-- Then, the active theme's page-specific bundle (loaded AFTER base so it can override).
|
|
217
|
+
Only present when the theme ships page CSS for this path — otherwise nothing loads
|
|
218
|
+
and the theme's component/general styles handle the page. No fallback needed. -->
|
|
219
|
+
{% iffile page-css-theme-path %}
|
|
220
|
+
<link rel="stylesheet" type="text/css" href="{{ site.url }}{{ page-css-theme-path }}?cb={{ site.uj.cache_breaker }}"/>
|
|
221
|
+
|
|
222
|
+
<!-- Dev log -->
|
|
223
|
+
{% if jekyll.environment == "development" %}
|
|
224
|
+
<script>
|
|
225
|
+
console.info("Theme page-specific css loading: #main{{ page-css-theme-path }}");
|
|
226
|
+
</script>
|
|
227
|
+
{% endif %}
|
|
228
|
+
{% endiffile %}
|
|
229
|
+
|
|
213
230
|
<!-- Style - Scripts are Disabled -->
|
|
214
231
|
<noscript>
|
|
215
232
|
{{ page-ie-script }}
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
</div>
|
|
71
71
|
|
|
72
72
|
<!-- Bottom Section -->
|
|
73
|
-
<div class="row mt-4 pt-3 border-top">
|
|
73
|
+
<div class="row mt-4 pt-3 border-top align-items-center">
|
|
74
74
|
<div class="col-md-6 d-flex align-items-center">
|
|
75
75
|
<!-- Language Dropdown -->
|
|
76
|
-
<div class="d-
|
|
76
|
+
<div class="d-flex align-items-center me-3">
|
|
77
77
|
<div class="dropup uj-language-dropdown">
|
|
78
78
|
<button class="btn btn-sm btn-outline-adaptive dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false">
|
|
79
79
|
<i class="fa fa-sm me-1">
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
</button>
|
|
86
86
|
<ul class="dropdown-menu">
|
|
87
87
|
{% assign default_language = site.translation.default | default: "en" %}
|
|
88
|
-
{% if site.translation.languages.size > 0 %}
|
|
88
|
+
{% if site.translation.enabled and site.translation.languages.size > 0 %}
|
|
89
89
|
{% assign all_languages = site.translation.languages | push: default_language %}
|
|
90
90
|
{% else %}
|
|
91
91
|
{% assign all_languages = "" | split: "" | push: default_language %}
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
|
|
106
106
|
<!-- Social Links -->
|
|
107
107
|
{% if data.socials.enabled %}
|
|
108
|
-
<div class="d-
|
|
108
|
+
<div class="d-flex align-items-center">
|
|
109
109
|
{% if data.socials.list and data.socials.list.size > 0 %}
|
|
110
110
|
{% assign social_list = data.socials.list %}
|
|
111
111
|
{% else %}
|