ultimate-jekyll-manager 1.7.1 → 1.8.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/.claude/scheduled_tasks.lock +1 -0
- package/CHANGELOG.md +68 -1
- package/CLAUDE.md +36 -15
- package/README.md +4 -2
- package/TODO-AUTH-TESTING.md +1 -1
- package/dist/assets/js/libs/form-manager.js +4 -1
- package/dist/assets/js/pages/payment/confirmation/index.js +9 -0
- package/dist/assets/themes/newsflash/README.md +58 -0
- package/dist/assets/themes/newsflash/_config.scss +138 -0
- package/dist/assets/themes/newsflash/_theme.js +27 -0
- package/dist/assets/themes/newsflash/_theme.scss +37 -0
- package/dist/assets/themes/newsflash/css/base/_mixins.scss +50 -0
- package/dist/assets/themes/newsflash/css/base/_root.scss +134 -0
- package/dist/assets/themes/newsflash/css/base/_typography.scss +49 -0
- package/dist/assets/themes/newsflash/css/base/_utilities.scss +58 -0
- package/dist/assets/themes/newsflash/css/components/_badges.scss +65 -0
- package/dist/assets/themes/newsflash/css/components/_buttons.scss +139 -0
- package/dist/assets/themes/newsflash/css/components/_cards.scss +52 -0
- package/dist/assets/themes/newsflash/css/components/_editorial.scss +182 -0
- package/dist/assets/themes/newsflash/css/components/_forms.scss +75 -0
- package/dist/assets/themes/newsflash/css/components/_infinite-scroll.scss +102 -0
- package/dist/assets/themes/newsflash/css/components/_panels.scss +91 -0
- package/dist/assets/themes/newsflash/css/components/_ticker.scss +70 -0
- package/dist/assets/themes/newsflash/css/layout/_general.scss +264 -0
- package/dist/assets/themes/newsflash/css/layout/_navigation.scss +164 -0
- package/dist/assets/themes/newsflash/js/initialize-tooltips.js +20 -0
- package/dist/assets/themes/newsflash/js/masthead-scroll.js +29 -0
- package/dist/assets/themes/newsflash/pages/404/index.scss +27 -0
- package/dist/assets/themes/newsflash/pages/about/index.scss +70 -0
- package/dist/assets/themes/newsflash/pages/blog/index.scss +17 -0
- package/dist/assets/themes/newsflash/pages/blog/post.js +29 -0
- package/dist/assets/themes/newsflash/pages/blog/post.scss +164 -0
- package/dist/assets/themes/newsflash/pages/index.scss +159 -0
- package/dist/assets/themes/newsflash/pages/pricing/index.scss +194 -0
- package/dist/assets/themes/newsflash/pages/test/libraries/layers/index.js +9 -0
- package/dist/assets/themes/newsflash/pages/test/libraries/layers/index.scss +7 -0
- package/dist/commands/blogify.js +6 -3
- package/dist/commands/test.js +34 -5
- package/dist/defaults/CLAUDE.md +17 -4
- package/dist/defaults/dist/_includes/core/pricing/resolve-plan.html +59 -0
- package/dist/defaults/dist/_includes/themes/classy/frontend/sections/footer.html +20 -3
- package/dist/defaults/dist/_layouts/themes/classy/admin/core/minimal-viewport-locked.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/admin/core/minimal.html +1 -1
- package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +5 -40
- package/dist/defaults/dist/_layouts/themes/neobrutalism/frontend/pages/pricing.html +33 -34
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/core/base.html +61 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/404.html +86 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/about.html +353 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/categories/category.html +105 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/categories/index.html +93 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/index.html +373 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/post.html +289 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/tags/index.html +90 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/blog/tags/tag.html +107 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/contact.html +340 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/index.html +522 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/pricing.html +485 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/team/index.html +207 -0
- package/dist/defaults/dist/_layouts/themes/newsflash/frontend/pages/team/member.html +134 -0
- package/dist/defaults/test/README.md +4 -0
- package/dist/gulp/tasks/jekyll.js +4 -2
- package/dist/test/runner.js +50 -3
- package/dist/test/suites/build/attach-log-file.test.js +102 -0
- package/dist/test/suites/build/theme-contract.test.js +173 -0
- package/dist/test/utils/extended-mode-warning.js +13 -0
- package/dist/utils/attach-log-file.js +70 -43
- package/docs/appearance.md +1 -0
- package/docs/assets.md +9 -0
- package/docs/audit.md +27 -7
- package/docs/build-system.md +57 -0
- package/docs/common-mistakes.md +15 -0
- package/docs/{project-structure.md → directory-structure.md} +1 -1
- package/docs/environment-detection.md +1 -1
- package/docs/javascript-libraries.md +38 -1
- package/docs/layouts-and-pages.md +146 -0
- package/docs/local-development.md +1 -8
- package/docs/logging.md +30 -0
- package/docs/migration.md +131 -0
- package/docs/no-inline-scripts.md +304 -0
- package/docs/purgecss.md +164 -0
- package/docs/seo.md +131 -4
- package/docs/templating.md +23 -0
- package/docs/test-boot-layer.md +1 -1
- package/docs/test-framework.md +56 -8
- package/docs/themes.md +254 -13
- package/logs/test.log +111 -0
- package/package.json +1 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
// Newsflash Theme — Blog post page-specific CSS
|
|
2
|
+
// The editorial article treatment for
|
|
3
|
+
// (_layouts/themes/newsflash/frontend/pages/blog/post.html): reading-progress
|
|
4
|
+
// bar, drop cap, serif crossheads with the vermilion dash, framed in-content
|
|
5
|
+
// images, and the centered pullquote. NOTE: flat file shape — the post layout
|
|
6
|
+
// sets `asset_path: blog/post`, so this compiles to pages/blog/post.<id>.bundle.css.
|
|
7
|
+
// Compiles standalone, so it pulls in the theme tokens + mixins via loadPaths.
|
|
8
|
+
@use 'config' as *;
|
|
9
|
+
@import 'css/base/mixins';
|
|
10
|
+
|
|
11
|
+
// ============================================
|
|
12
|
+
// Reading progress — fixed vermilion rule across the very top
|
|
13
|
+
// ============================================
|
|
14
|
+
// Sits above the sticky masthead (z-index 1030); driven by pages/blog/post.js.
|
|
15
|
+
.reading-progress {
|
|
16
|
+
position: fixed;
|
|
17
|
+
top: 0;
|
|
18
|
+
left: 0;
|
|
19
|
+
right: 0;
|
|
20
|
+
height: 4px;
|
|
21
|
+
z-index: 1040;
|
|
22
|
+
pointer-events: none;
|
|
23
|
+
background: transparent;
|
|
24
|
+
|
|
25
|
+
span {
|
|
26
|
+
display: block;
|
|
27
|
+
height: 100%;
|
|
28
|
+
background: var(--bs-primary);
|
|
29
|
+
transform: scaleX(0);
|
|
30
|
+
transform-origin: left;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ============================================
|
|
35
|
+
// Article hero — wide cinematic frame
|
|
36
|
+
// ============================================
|
|
37
|
+
.article-hero {
|
|
38
|
+
aspect-ratio: 21 / 10;
|
|
39
|
+
|
|
40
|
+
img {
|
|
41
|
+
height: 100%;
|
|
42
|
+
// Lift the framework's generic .blog-post-image cap (max-height: 480px in
|
|
43
|
+
// the main bundle) — the 21/10 frame is the size authority here, and the
|
|
44
|
+
// cap leaves a blank strip inside the frame on wide viewports.
|
|
45
|
+
max-height: none;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ============================================
|
|
50
|
+
// Article body — the editorial reading column
|
|
51
|
+
// ============================================
|
|
52
|
+
.blog-post-content {
|
|
53
|
+
font-size: 1.13rem;
|
|
54
|
+
line-height: 1.78;
|
|
55
|
+
|
|
56
|
+
p {
|
|
57
|
+
margin-bottom: 1.5em;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Drop cap on the opening paragraph
|
|
61
|
+
> p:first-of-type::first-letter {
|
|
62
|
+
font-family: $nf-font-display;
|
|
63
|
+
font-weight: 600;
|
|
64
|
+
font-size: 4.2rem;
|
|
65
|
+
line-height: 0.82;
|
|
66
|
+
color: var(--bs-primary);
|
|
67
|
+
float: left;
|
|
68
|
+
padding: 8px 12px 0 0;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Serif crossheads with the vermilion dash
|
|
72
|
+
h2, h3 {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
gap: 0.5em;
|
|
76
|
+
font-size: 1.7rem;
|
|
77
|
+
letter-spacing: -0.014em;
|
|
78
|
+
line-height: 1.25;
|
|
79
|
+
margin: 2em 0 0.8em;
|
|
80
|
+
|
|
81
|
+
&::before {
|
|
82
|
+
content: "";
|
|
83
|
+
width: 0.55em;
|
|
84
|
+
height: 0.18em;
|
|
85
|
+
background: var(--bs-primary);
|
|
86
|
+
border-radius: 50rem;
|
|
87
|
+
flex: none;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
h3 {
|
|
92
|
+
font-size: 1.35rem;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// In-content images get the editorial frame
|
|
96
|
+
img {
|
|
97
|
+
border: var(--nf-border);
|
|
98
|
+
border-radius: $nf-radius;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
figcaption {
|
|
102
|
+
font-size: 0.78rem;
|
|
103
|
+
color: var(--bs-secondary-color);
|
|
104
|
+
padding-top: 10px;
|
|
105
|
+
text-align: right;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Pullquote — centered italic serif with the oversized quote mark
|
|
109
|
+
blockquote {
|
|
110
|
+
margin: 2.4em 0;
|
|
111
|
+
padding: 0 1em;
|
|
112
|
+
text-align: center;
|
|
113
|
+
border: 0;
|
|
114
|
+
|
|
115
|
+
&::before {
|
|
116
|
+
content: "\201C";
|
|
117
|
+
display: block;
|
|
118
|
+
font-family: $nf-font-display;
|
|
119
|
+
font-weight: 900;
|
|
120
|
+
font-size: 4rem;
|
|
121
|
+
line-height: 0.6;
|
|
122
|
+
color: var(--bs-primary);
|
|
123
|
+
margin-bottom: 0.25em;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
p {
|
|
127
|
+
font-family: $nf-font-display;
|
|
128
|
+
font-style: italic;
|
|
129
|
+
font-weight: 550;
|
|
130
|
+
font-size: clamp(1.4rem, 2.6vw, 1.9rem);
|
|
131
|
+
letter-spacing: -0.01em;
|
|
132
|
+
line-height: 1.3;
|
|
133
|
+
margin: 0;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
cite {
|
|
137
|
+
display: block;
|
|
138
|
+
margin-top: 1.1em;
|
|
139
|
+
font-family: $font-family-sans-serif;
|
|
140
|
+
font-style: normal;
|
|
141
|
+
font-weight: 700;
|
|
142
|
+
font-size: 0.78rem;
|
|
143
|
+
letter-spacing: 0.12em;
|
|
144
|
+
text-transform: uppercase;
|
|
145
|
+
color: var(--bs-secondary-color);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// List markers pick up the accent
|
|
150
|
+
li::marker {
|
|
151
|
+
color: var(--bs-primary);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Tag row sits on a hairline rule
|
|
156
|
+
.tag-row {
|
|
157
|
+
border-top: var(--nf-border);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
@media (max-width: 767.98px) {
|
|
161
|
+
.blog-post-content {
|
|
162
|
+
font-size: 1.05rem;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Newsflash Theme — Homepage page-specific CSS
|
|
2
|
+
// Styles the editorial front-page override
|
|
3
|
+
// (_layouts/themes/newsflash/frontend/pages/index.html).
|
|
4
|
+
//
|
|
5
|
+
// Class names are UNIVERSAL (section-hero, hero-title, feed-num, rail-title,
|
|
6
|
+
// mostread, stat-num, cta-panel, Bootstrap .card/.badge …) — no theme prefix —
|
|
7
|
+
// so the same markup is swappable across themes. This file gives those classes
|
|
8
|
+
// the newsflash look. Compiles standalone, so it pulls in the theme tokens +
|
|
9
|
+
// mixins via loadPaths.
|
|
10
|
+
@use 'config' as *;
|
|
11
|
+
@import 'css/base/mixins';
|
|
12
|
+
|
|
13
|
+
// ============================================
|
|
14
|
+
// Hero — the front-page lead
|
|
15
|
+
// ============================================
|
|
16
|
+
.section-hero {
|
|
17
|
+
padding-top: clamp(2.5rem, 5vw, 4rem);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.hero-title {
|
|
21
|
+
font-size: clamp(2.6rem, 5.4vw, 4.4rem);
|
|
22
|
+
font-weight: 550;
|
|
23
|
+
letter-spacing: -0.022em;
|
|
24
|
+
line-height: 1.04;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.hero-art {
|
|
28
|
+
.art-frame {
|
|
29
|
+
aspect-ratio: 4 / 3;
|
|
30
|
+
@include nf-shadow-pop();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.hero-art-chip {
|
|
34
|
+
position: absolute;
|
|
35
|
+
top: 18px;
|
|
36
|
+
left: -14px;
|
|
37
|
+
transform: rotate(-4deg);
|
|
38
|
+
z-index: 2;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Decorative cover art (pre-content fallback when the site has no posts yet):
|
|
43
|
+
// vermilion-to-orange wash with a blue corner glow — pure CSS, no asset.
|
|
44
|
+
.cover-art {
|
|
45
|
+
background:
|
|
46
|
+
radial-gradient(110% 90% at 88% 8%, #FFB36B 0%, rgba(255, 179, 107, 0) 52%),
|
|
47
|
+
radial-gradient(120% 110% at 8% 95%, var(--nf-blue) 0%, rgba(39, 66, 245, 0) 56%),
|
|
48
|
+
linear-gradient(155deg, var(--nf-vermilion) 10%, #FF7A3D 90%);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ============================================
|
|
52
|
+
// The rundown — stroked step numerals on dashed rows
|
|
53
|
+
// ============================================
|
|
54
|
+
// (The latest feed uses .feed-item's BASE layout from _editorial.scss —
|
|
55
|
+
// square art thumb + text. Only the rundown swaps the thumb for a numeral.)
|
|
56
|
+
.feed-num {
|
|
57
|
+
font-family: $nf-font-display;
|
|
58
|
+
font-style: italic;
|
|
59
|
+
font-weight: 800;
|
|
60
|
+
font-size: 3.2rem;
|
|
61
|
+
line-height: 1;
|
|
62
|
+
color: transparent;
|
|
63
|
+
-webkit-text-stroke: 1.5px var(--nf-ink);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// On rundown rows the numeral replaces the thumbnail — shrink its column
|
|
67
|
+
.feed-item .feed-num {
|
|
68
|
+
width: 5rem;
|
|
69
|
+
}
|
|
70
|
+
.section-rundown .feed-item {
|
|
71
|
+
grid-template-columns: 5rem 1fr;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// ============================================
|
|
75
|
+
// The rail (sticky sidebar)
|
|
76
|
+
// ============================================
|
|
77
|
+
.rail-stack {
|
|
78
|
+
position: sticky;
|
|
79
|
+
top: 5.75rem; // clears the sticky masthead
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.rail-title {
|
|
83
|
+
display: flex;
|
|
84
|
+
align-items: center;
|
|
85
|
+
gap: 0.6em;
|
|
86
|
+
font-weight: 800;
|
|
87
|
+
font-size: 0.8rem;
|
|
88
|
+
letter-spacing: 0.14em;
|
|
89
|
+
text-transform: uppercase;
|
|
90
|
+
margin-bottom: 1rem;
|
|
91
|
+
|
|
92
|
+
&::after {
|
|
93
|
+
content: "";
|
|
94
|
+
flex: 1;
|
|
95
|
+
height: var(--nf-border-width);
|
|
96
|
+
background: var(--nf-border-color);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Most-read list — stroked counter numerals that ink in on hover
|
|
101
|
+
.mostread {
|
|
102
|
+
counter-reset: mostread;
|
|
103
|
+
|
|
104
|
+
li {
|
|
105
|
+
counter-increment: mostread;
|
|
106
|
+
display: flex;
|
|
107
|
+
gap: 1rem;
|
|
108
|
+
align-items: flex-start;
|
|
109
|
+
padding: 0.8rem 0;
|
|
110
|
+
border-bottom: 1px solid var(--nf-line);
|
|
111
|
+
|
|
112
|
+
&:first-child { padding-top: 0; }
|
|
113
|
+
&:last-child { border-bottom: 0; padding-bottom: 0; }
|
|
114
|
+
|
|
115
|
+
&::before {
|
|
116
|
+
content: counter(mostread);
|
|
117
|
+
font-family: $nf-font-display;
|
|
118
|
+
font-style: italic;
|
|
119
|
+
font-weight: 900;
|
|
120
|
+
font-size: 2rem;
|
|
121
|
+
line-height: 1;
|
|
122
|
+
color: transparent;
|
|
123
|
+
-webkit-text-stroke: 1.3px var(--nf-ink);
|
|
124
|
+
flex: none;
|
|
125
|
+
width: 1.2em;
|
|
126
|
+
transition: $nf-transition;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
&:hover::before {
|
|
130
|
+
color: var(--bs-primary);
|
|
131
|
+
-webkit-text-stroke-color: var(--bs-primary);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
a {
|
|
136
|
+
font-weight: 700;
|
|
137
|
+
font-size: 0.95rem;
|
|
138
|
+
line-height: 1.35;
|
|
139
|
+
color: inherit;
|
|
140
|
+
text-decoration: none;
|
|
141
|
+
|
|
142
|
+
&:hover {
|
|
143
|
+
color: var(--bs-primary);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Newsletter rail — the vermilion slab gets the hard offset shadow
|
|
149
|
+
.rail-stack .card.bg-primary {
|
|
150
|
+
box-shadow: var(--nf-shadow-hard-hover) !important;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// (Feature icon chips, stats numerals + the CTA band live in the main bundle — _panels.scss —
|
|
154
|
+
// because pricing/about reuse them. Reader quote-cards live in pages/about/index.scss —
|
|
155
|
+
// the testimonials section moved to the about page.)
|
|
156
|
+
|
|
157
|
+
@media (max-width: 991.98px) {
|
|
158
|
+
.rail-stack { position: static; }
|
|
159
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
// Newsflash Theme — Pricing page-specific CSS
|
|
2
|
+
// The "subscription desk" treatment for
|
|
3
|
+
// (_layouts/themes/newsflash/frontend/pages/pricing.html): pill billing
|
|
4
|
+
// toggle, framed plan cards with the vermilion "Editor's pick", and the
|
|
5
|
+
// enterprise strip. Compiles standalone — theme tokens + mixins via loadPaths.
|
|
6
|
+
@use 'config' as *;
|
|
7
|
+
@import 'css/base/mixins';
|
|
8
|
+
|
|
9
|
+
// ============================================
|
|
10
|
+
// Billing toggle — pill segmented control
|
|
11
|
+
// ============================================
|
|
12
|
+
.billing-toggle {
|
|
13
|
+
display: flex;
|
|
14
|
+
justify-content: center;
|
|
15
|
+
gap: 0.35rem;
|
|
16
|
+
width: fit-content;
|
|
17
|
+
margin: 0 auto 1.25rem;
|
|
18
|
+
padding: 0.35rem;
|
|
19
|
+
border: var(--nf-border);
|
|
20
|
+
border-radius: 50rem;
|
|
21
|
+
background: var(--bs-card-bg);
|
|
22
|
+
|
|
23
|
+
.billing-option {
|
|
24
|
+
display: inline-flex;
|
|
25
|
+
align-items: center;
|
|
26
|
+
gap: 0.5em;
|
|
27
|
+
padding: 0.5rem 1.25rem;
|
|
28
|
+
border-radius: 50rem;
|
|
29
|
+
font-weight: 700;
|
|
30
|
+
font-size: 0.9rem;
|
|
31
|
+
cursor: pointer;
|
|
32
|
+
transition: $nf-transition;
|
|
33
|
+
|
|
34
|
+
&:hover {
|
|
35
|
+
background: var(--nf-paper-2);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.btn-check:checked + .billing-option {
|
|
40
|
+
background: var(--nf-ink);
|
|
41
|
+
color: var(--nf-paper);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.billing-save {
|
|
45
|
+
font-size: 0.68rem;
|
|
46
|
+
font-weight: 800;
|
|
47
|
+
letter-spacing: 0.06em;
|
|
48
|
+
text-transform: uppercase;
|
|
49
|
+
padding: 0.3em 0.7em;
|
|
50
|
+
border-radius: 50rem;
|
|
51
|
+
background: var(--nf-volt);
|
|
52
|
+
color: var(--nf-volt-ink);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// ============================================
|
|
57
|
+
// Plan grid + cards
|
|
58
|
+
// ============================================
|
|
59
|
+
.pricing-plan-grid {
|
|
60
|
+
display: grid;
|
|
61
|
+
grid-template-columns: repeat(4, 1fr);
|
|
62
|
+
gap: 1.5rem;
|
|
63
|
+
align-items: start;
|
|
64
|
+
margin-bottom: 2rem;
|
|
65
|
+
|
|
66
|
+
@media (max-width: 1199.98px) {
|
|
67
|
+
grid-template-columns: repeat(2, 1fr);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@media (max-width: 767.98px) {
|
|
71
|
+
grid-template-columns: 1fr;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.pricing-plan {
|
|
76
|
+
position: relative;
|
|
77
|
+
padding: 1.75rem;
|
|
78
|
+
|
|
79
|
+
&--popular {
|
|
80
|
+
border-color: var(--bs-primary);
|
|
81
|
+
border-width: 2.5px;
|
|
82
|
+
box-shadow: var(--nf-shadow-hard-hover);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.pricing-plan-flag {
|
|
87
|
+
position: absolute;
|
|
88
|
+
top: -0.85rem;
|
|
89
|
+
left: 50%;
|
|
90
|
+
transform: translateX(-50%) rotate(-2deg);
|
|
91
|
+
white-space: nowrap;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.pricing-plan-name {
|
|
95
|
+
font-size: 1.4rem;
|
|
96
|
+
margin-bottom: 0.1rem;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.pricing-plan-tagline {
|
|
100
|
+
margin-bottom: 1.25rem;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.pricing-plan-price {
|
|
104
|
+
font-family: $nf-font-display;
|
|
105
|
+
margin-bottom: 0.25rem;
|
|
106
|
+
|
|
107
|
+
.pricing-plan-currency {
|
|
108
|
+
font-size: 1.4rem;
|
|
109
|
+
font-weight: 600;
|
|
110
|
+
vertical-align: super;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.pricing-plan-amount {
|
|
114
|
+
font-size: 3rem;
|
|
115
|
+
font-weight: 600;
|
|
116
|
+
letter-spacing: -0.02em;
|
|
117
|
+
line-height: 1;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.pricing-plan-per {
|
|
121
|
+
font-family: $font-family-sans-serif;
|
|
122
|
+
font-size: 0.95rem;
|
|
123
|
+
color: var(--bs-secondary-color);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.pricing-plan-ppu {
|
|
128
|
+
font-size: 0.85rem;
|
|
129
|
+
color: var(--bs-secondary-color);
|
|
130
|
+
min-height: 1.3em;
|
|
131
|
+
margin-bottom: 1.25rem;
|
|
132
|
+
|
|
133
|
+
.price-per-unit {
|
|
134
|
+
font-weight: 700;
|
|
135
|
+
color: var(--bs-primary);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.pricing-plan-billing,
|
|
140
|
+
.pricing-plan-guarantee {
|
|
141
|
+
font-size: 0.8rem;
|
|
142
|
+
color: var(--bs-secondary-color);
|
|
143
|
+
text-align: center;
|
|
144
|
+
margin-bottom: 0.35rem;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.pricing-plan-rule {
|
|
148
|
+
margin: 1.25rem 0;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.pricing-plan-inherit {
|
|
152
|
+
font-size: 0.8rem;
|
|
153
|
+
font-weight: 800;
|
|
154
|
+
letter-spacing: 0.08em;
|
|
155
|
+
text-transform: uppercase;
|
|
156
|
+
color: var(--bs-secondary-color);
|
|
157
|
+
margin-bottom: 0.75rem;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.pricing-plan-features {
|
|
161
|
+
list-style: none;
|
|
162
|
+
padding: 0;
|
|
163
|
+
margin: 0 0 1rem;
|
|
164
|
+
|
|
165
|
+
li {
|
|
166
|
+
display: flex;
|
|
167
|
+
gap: 0.6em;
|
|
168
|
+
align-items: baseline;
|
|
169
|
+
padding: 0.3rem 0;
|
|
170
|
+
font-size: 0.92rem;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.pricing-plan-feature-icon {
|
|
174
|
+
color: var(--bs-primary);
|
|
175
|
+
flex: none;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ============================================
|
|
180
|
+
// Enterprise strip
|
|
181
|
+
// ============================================
|
|
182
|
+
.enterprise-panel {
|
|
183
|
+
display: flex;
|
|
184
|
+
flex-direction: row;
|
|
185
|
+
align-items: center;
|
|
186
|
+
justify-content: space-between;
|
|
187
|
+
gap: 1.5rem;
|
|
188
|
+
padding: 1.75rem;
|
|
189
|
+
|
|
190
|
+
@media (max-width: 767.98px) {
|
|
191
|
+
flex-direction: column;
|
|
192
|
+
align-items: flex-start;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// /test — Theme (newsflash) 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 (newsflash) 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/commands/blogify.js
CHANGED
|
@@ -276,11 +276,14 @@ module.exports = async function (options) {
|
|
|
276
276
|
});
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
// Generate 12
|
|
279
|
+
// Generate posts (--count=<n>, default 12)
|
|
280
|
+
const count = parseInt(options.count, 10) || 12;
|
|
280
281
|
const now = Math.floor(Date.now() / 1000);
|
|
281
282
|
const dayInSeconds = 86400;
|
|
282
283
|
|
|
283
|
-
|
|
284
|
+
logger.log(`Generating ${count} test posts...`);
|
|
285
|
+
|
|
286
|
+
for (let i = 0; i < count; i++) {
|
|
284
287
|
// Calculate timestamp for each post (spread over last 12 days)
|
|
285
288
|
const postTimestamp = now - (i * dayInSeconds);
|
|
286
289
|
const postId = `test-${postTimestamp}`; // Add test- prefix to ID
|
|
@@ -335,5 +338,5 @@ ${generateBlogContent(postImages)}`;
|
|
|
335
338
|
logger.log(`Created post: ${filename}`);
|
|
336
339
|
}
|
|
337
340
|
|
|
338
|
-
logger.log(`Successfully created
|
|
341
|
+
logger.log(`Successfully created ${count} blog posts in ${postsDir}`);
|
|
339
342
|
};
|
package/dist/commands/test.js
CHANGED
|
@@ -5,15 +5,34 @@ const Manager = require('../build.js');
|
|
|
5
5
|
const mgr = new Manager();
|
|
6
6
|
const logger = mgr.logger('test');
|
|
7
7
|
const { run } = require('../test/runner.js');
|
|
8
|
+
const attachLogFile = require('../utils/attach-log-file.js');
|
|
9
|
+
const { EXTENDED_MODE_WARNING } = require('../test/utils/extended-mode-warning.js');
|
|
8
10
|
|
|
9
11
|
module.exports = async function (options) {
|
|
12
|
+
// Tee all test output to <projectRoot>/logs/test.log (ANSI-stripped) — mirrors
|
|
13
|
+
// the dev/build log pattern and EM/BEM's test.log. Skipped on CI via isServer().
|
|
14
|
+
attachLogFile('test');
|
|
15
|
+
|
|
10
16
|
const layer = options.layer || 'all';
|
|
17
|
+
// Positional target: `npx mgr test <target>` where target supports source
|
|
18
|
+
// prefixes — `project:`, `project:<path>`, `mgr:`, `ujm:`, or a bare `<path>`.
|
|
19
|
+
const target = (options._ && options._[1]) || null;
|
|
20
|
+
// `--filter` flag: substring match on test NAMES/descriptions (orthogonal to target).
|
|
11
21
|
const filter = options.filter || null;
|
|
12
22
|
const reporter = options.reporter || 'pretty';
|
|
13
|
-
|
|
23
|
+
// Extended mode — opt into tests that hit REAL external services (network fetches, Firebase
|
|
24
|
+
// via web-manager, live APIs) instead of skipping them. Off by default so `npx mgr test`
|
|
25
|
+
// stays fast and offline-safe. The canonical signal is the unprefixed `TEST_EXTENDED_MODE`
|
|
26
|
+
// env var — the SAME name across BEM/BXM/UJM/EM (cross-framework parity); `--extended` is the
|
|
27
|
+
// CLI shorthand. Once set on process.env it propagates to every spawned child (the Jekyll
|
|
28
|
+
// build, the boot HTTP server / Puppeteer browsers) automatically via inherited `process.env`.
|
|
29
|
+
const extended = options.extended === true
|
|
30
|
+
|| options.extended === 'true'
|
|
31
|
+
|| process.env.TEST_EXTENDED_MODE === 'true'
|
|
32
|
+
|| process.env.TEST_EXTENDED_MODE === '1';
|
|
14
33
|
|
|
15
|
-
if (
|
|
16
|
-
process.env.
|
|
34
|
+
if (extended) {
|
|
35
|
+
process.env.TEST_EXTENDED_MODE = 'true';
|
|
17
36
|
}
|
|
18
37
|
|
|
19
38
|
// Canonical signal — every Manager picks this up via isTesting().
|
|
@@ -33,10 +52,15 @@ module.exports = async function (options) {
|
|
|
33
52
|
}
|
|
34
53
|
|
|
35
54
|
if (reporter !== 'json') {
|
|
36
|
-
logger.log(`Running tests (layer=${layer}${filter ? ` filter="${filter}"` : ''}${
|
|
55
|
+
logger.log(`Running tests (layer=${layer}${target ? ` target="${target}"` : ''}${filter ? ` filter="${filter}"` : ''}${extended ? ' +extended' : ''})`);
|
|
56
|
+
logger.log(`Test mode: ${extended ? 'extended (real external APIs)' : 'normal (external APIs skipped)'}`);
|
|
57
|
+
if (extended) {
|
|
58
|
+
logger.warn(EXTENDED_MODE_WARNING[0]);
|
|
59
|
+
EXTENDED_MODE_WARNING.slice(1).forEach((line) => logger.warn(line));
|
|
60
|
+
}
|
|
37
61
|
}
|
|
38
62
|
|
|
39
|
-
const result = await run({ layer, filter, reporter });
|
|
63
|
+
const result = await run({ layer, target, filter, reporter });
|
|
40
64
|
|
|
41
65
|
if (reporter === 'json') {
|
|
42
66
|
// Final machine-readable summary.
|
|
@@ -51,6 +75,11 @@ module.exports = async function (options) {
|
|
|
51
75
|
|
|
52
76
|
if (result.failed > 0) {
|
|
53
77
|
process.exitCode = 1;
|
|
78
|
+
attachLogFile.detach();
|
|
54
79
|
throw new Error(`${result.failed} test(s) failed`);
|
|
55
80
|
}
|
|
81
|
+
|
|
82
|
+
// Restore stdout/stderr and close the log file. UJM's util writes synchronously,
|
|
83
|
+
// so the tail is already on disk — this just cleans up the handle.
|
|
84
|
+
attachLogFile.detach();
|
|
56
85
|
};
|
package/dist/defaults/CLAUDE.md
CHANGED
|
@@ -28,9 +28,12 @@ npm start # dev: clean → setup → bundle exec gulp serve (Jekyll +
|
|
|
28
28
|
npm run build # production build (UJ_BUILD_MODE=true): clean → setup → full gulp pipeline → _site/
|
|
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
|
-
npx mgr test pages/home # run a specific test by path (relative to test
|
|
32
|
-
npx mgr test
|
|
33
|
-
npx mgr test
|
|
31
|
+
npx mgr test pages/home # run a specific test by path (relative to test/, both sources)
|
|
32
|
+
npx mgr test project: # run ONLY your project tests (project:custom-test for one path)
|
|
33
|
+
npx mgr test mgr: # run ONLY framework tests (ujm: / framework: are equivalent)
|
|
34
|
+
npx mgr test --filter=foo # match test NAMES within the selected files (composes with target)
|
|
35
|
+
npx mgr test --extended # also run tests that hit real external services (or TEST_EXTENDED_MODE=true; off by default)
|
|
36
|
+
# (output is teed to logs/ — dev.log on `npm start`, build.log on `npm run build`, test.log on `npx mgr test`; cat instead of scrolling scrollback)
|
|
34
37
|
npx mgr audit # HTML validation + spellcheck + optional Lighthouse
|
|
35
38
|
npx mgr install dev # use LOCAL ultimate-jekyll-manager source (to test framework edits)
|
|
36
39
|
npx mgr install live # restore the published ultimate-jekyll-manager from npm
|
|
@@ -51,7 +54,7 @@ See `node_modules/ultimate-jekyll-manager/docs/themes.md` for the full "Bootstra
|
|
|
51
54
|
|
|
52
55
|
## 🚨 Development workflow — MUST follow
|
|
53
56
|
|
|
54
|
-
- **🚫 NEVER run `npm start
|
|
57
|
+
- **🚫 NEVER run `npm start`** — the user runs the dev server; running it again kills theirs. Assume it's already running; if it isn't, instruct the user to run it rather than running it yourself. Running `npx mgr test` is fine.
|
|
55
58
|
- **✅ ALWAYS check `logs/dev.log`** after editing source files (SCSS, JS, HTML, config) to confirm the build succeeded. The dev server's gulp watcher recompiles on file change — check the log for errors.
|
|
56
59
|
- Success: `Reloading Browsers...`
|
|
57
60
|
- Failure: `'sass' errored`, `'webpack' errored`, `'build-error'`, `'jekyll' errored`
|
|
@@ -114,6 +117,16 @@ At build time, `require('ultimate-jekyll-manager/build')` exposes:
|
|
|
114
117
|
- `Manager.logger(name)` — timestamped logger instance
|
|
115
118
|
- `Manager.require(path)` — escape hatch for UJM transitive deps (use sparingly)
|
|
116
119
|
|
|
120
|
+
## Dependency resolution
|
|
121
|
+
|
|
122
|
+
- **Do NOT install framework dependencies directly** (`firebase`, `web-manager`, etc.). UJM's webpack config resolves them through the framework's own `node_modules/`. If something doesn't resolve, the issue is in UJM's webpack config — not your `package.json`.
|
|
123
|
+
- **web-manager owns Firebase.** Never `import firebase from 'firebase/app'`. Use `import webManager from 'web-manager'` → `webManager.auth()`, `webManager.firestore()`.
|
|
124
|
+
- **`Manager.require(name)`** resolves from UJM's module context at runtime for unbundled code (gulp tasks, test fixtures).
|
|
125
|
+
|
|
126
|
+
## Testing
|
|
127
|
+
|
|
128
|
+
Every feature ships with tests at every layer it has a surface in: **logic** (`test/build/`, or `test/page/` for frontend module logic), **UI** (`test/page/` — real events on the real DOM), and **end-to-end** (`test/boot/`). Skip a layer only when the feature genuinely has no surface there — "the logic test covers it" does not excuse the UI test. See `test/README.md` and `node_modules/ultimate-jekyll-manager/docs/test-framework.md`.
|
|
129
|
+
|
|
117
130
|
<!-- Everything above this marker is owned by the framework and rewritten on every `npx mgr setup`. Add your project-specific notes below — they are preserved across setups. -->
|
|
118
131
|
|
|
119
132
|
# ========== Custom Values ==========
|