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,98 @@
|
|
|
1
|
+
# Neobrutalism Theme
|
|
2
|
+
|
|
3
|
+
A bold, high-contrast UJM theme built on the neobrutalist design language:
|
|
4
|
+
**pure-ink borders, hard offset shadows (no blur), zero border-radius, chunky
|
|
5
|
+
grotesk display type, and flat saturated color blocks.** Buttons and cards
|
|
6
|
+
"press" into the page on interaction. Full light + dark mode support.
|
|
7
|
+
|
|
8
|
+
> See [`docs/themes.md`](../../../../docs/themes.md) for how the theme system
|
|
9
|
+
> works and how to author your own theme (inside UJM or in a consumer project).
|
|
10
|
+
|
|
11
|
+
## Use it
|
|
12
|
+
|
|
13
|
+
In your consuming project's `src/_config.yml`:
|
|
14
|
+
|
|
15
|
+
```yaml
|
|
16
|
+
theme:
|
|
17
|
+
id: "neobrutalism"
|
|
18
|
+
appearance: "light" # or "dark" / "system"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
That's it — every layout, nav, footer, and page is inherited from the shared
|
|
22
|
+
defaults (via the Classy layout fallback) and restyled in neobrutalist form.
|
|
23
|
+
|
|
24
|
+
## Customize it (without editing the theme)
|
|
25
|
+
|
|
26
|
+
All design tokens are `!default` variables. Override them **before** the theme
|
|
27
|
+
is imported — in your project's `src/assets/css/main.scss`, set the variables,
|
|
28
|
+
then `@use 'ultimate-jekyll-manager' as *;`:
|
|
29
|
+
|
|
30
|
+
```scss
|
|
31
|
+
// Change the accent + structure, then import the framework (which loads the theme)
|
|
32
|
+
$primary: #FF5C00; // your brand color
|
|
33
|
+
$nb-border-width: 4px; // chunkier borders
|
|
34
|
+
$nb-shadow-offset: 7px; // deeper hard shadow
|
|
35
|
+
$nb-accent-yellow: #D4FF00; // swap the signature highlight
|
|
36
|
+
|
|
37
|
+
@use 'ultimate-jekyll-manager' as *;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Key tokens (see `_config.scss` for the full list)
|
|
41
|
+
|
|
42
|
+
| Token | Purpose | Default |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `$primary` … `$danger` | Bootstrap semantic colors | electric blue, hot pink, etc. |
|
|
45
|
+
| `$nb-ink` / `$nb-paper` | Border/shadow color + page surface (light) | `#111` / `#FFFEF2` |
|
|
46
|
+
| `$nb-ink-dark` / `$nb-paper-dark` | Same, dark mode | `#F5F5F5` / `#16161A` |
|
|
47
|
+
| `$nb-border-width` | Standard border thickness | `3px` |
|
|
48
|
+
| `$nb-shadow-offset` | Hard shadow distance | `5px` |
|
|
49
|
+
| `$nb-accent-*` | Color-block palette | blue/pink/yellow/green/purple/orange |
|
|
50
|
+
| `$nb-font-display` | Heading font | `Archivo` |
|
|
51
|
+
| `$font-family-sans-serif` | Body font | `Space Grotesk` |
|
|
52
|
+
|
|
53
|
+
> Fonts are loaded via the theme's `head` block in the base layout. If you
|
|
54
|
+
> change the font tokens, update the Google Fonts `<link>` accordingly (in your
|
|
55
|
+
> page/layout `theme.head.content`, or by overriding the base layout).
|
|
56
|
+
|
|
57
|
+
## No theme-prefixed classes
|
|
58
|
+
|
|
59
|
+
This theme deliberately uses **NO `nb-` prefixed classes in markup** — so the same
|
|
60
|
+
HTML is swappable across themes (change `theme.id`, done). It styles:
|
|
61
|
+
|
|
62
|
+
- **Standard Bootstrap classes** wherever they fit: `.card` (the canonical container —
|
|
63
|
+
gets the ink frame + hard shadow), `.btn` / `.btn-primary` / `.btn-warning` (yellow
|
|
64
|
+
accent), `.text-bg-{primary,secondary,success,warning,…}` (the color-block fills),
|
|
65
|
+
`.border`, `.shadow`, `.accordion`, `.badge`.
|
|
66
|
+
- **Universal semantic layout classes** for structures with no Bootstrap equivalent:
|
|
67
|
+
`.section-hero`, `.hero-title`, `.action-block`, `.logo-strip`, `.showcase-row`,
|
|
68
|
+
`.step-card`, `.stat-block`, `.cta-panel`, `.pricing-plan`, `.billing-toggle`,
|
|
69
|
+
`.kicker`, `.highlight`. Any theme can style these same names. See
|
|
70
|
+
[docs/themes.md → Universal layout classes](../../../../docs/themes.md).
|
|
71
|
+
|
|
72
|
+
The `nb-` prefix survives ONLY on SCSS internals (the `$nb-*` config tokens, `--nb-*`
|
|
73
|
+
CSS variables, and `@mixin nb-border/nb-shadow/nb-press`) — these never appear in HTML.
|
|
74
|
+
|
|
75
|
+
## Structure
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
neobrutalism/
|
|
79
|
+
├── _config.scss ← all customizable tokens (!default) + Bootstrap forward
|
|
80
|
+
├── _theme.scss ← entry point (config → mixins → root → base → layout → components → bootstrap overrides)
|
|
81
|
+
├── _theme.js ← JS entry (Bootstrap UMD + behaviors on DOM ready)
|
|
82
|
+
├── css/
|
|
83
|
+
│ ├── base/
|
|
84
|
+
│ │ ├── _mixins.scss ← nb-border / nb-shadow / nb-press (the SSOT for the look)
|
|
85
|
+
│ │ ├── _root.scss ← SCSS → CSS-variable bridge (light/dark)
|
|
86
|
+
│ │ ├── _typography.scss
|
|
87
|
+
│ │ └── _utilities.scss
|
|
88
|
+
│ ├── layout/
|
|
89
|
+
│ │ ├── _general.scss ← sections, hero, footer, gradient/accent overrides
|
|
90
|
+
│ │ └── _navigation.scss
|
|
91
|
+
│ └── components/
|
|
92
|
+
│ ├── _buttons.scss
|
|
93
|
+
│ ├── _cards.scss
|
|
94
|
+
│ └── _forms.scss
|
|
95
|
+
└── js/
|
|
96
|
+
├── navbar-scroll.js
|
|
97
|
+
└── initialize-tooltips.js
|
|
98
|
+
```
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Neobrutalism Theme Configuration
|
|
2
|
+
// ALL customizable variables are defined here with !default.
|
|
3
|
+
// Consuming projects override any of these BEFORE the theme is imported.
|
|
4
|
+
//
|
|
5
|
+
// Design language: raw, high-contrast color blocks; pure-black hard borders;
|
|
6
|
+
// hard offset shadows (no blur); zero border-radius; chunky grotesk type.
|
|
7
|
+
// This is NOT a recolored Classy — the shadow/border/press system is the identity.
|
|
8
|
+
|
|
9
|
+
// ============================================
|
|
10
|
+
// Bootstrap Color Overrides
|
|
11
|
+
// ============================================
|
|
12
|
+
// Loud, saturated, high-contrast. These map onto Bootstrap's semantic colors.
|
|
13
|
+
$primary: #2563EB !default; // electric blue
|
|
14
|
+
$secondary: #EC4899 !default; // hot pink
|
|
15
|
+
$success: #16A34A !default; // grass green
|
|
16
|
+
$info: #06B6D4 !default; // cyan
|
|
17
|
+
$warning: #FACC15 !default; // acid yellow
|
|
18
|
+
$danger: #EF4444 !default; // red
|
|
19
|
+
$light: #FFFEF2 !default; // paper white (warm off-white)
|
|
20
|
+
$dark: #111111 !default; // near-black
|
|
21
|
+
|
|
22
|
+
// ============================================
|
|
23
|
+
// Ink & Paper (the structural neutrals)
|
|
24
|
+
// ============================================
|
|
25
|
+
// "Ink" = the universal border/shadow color. "Paper" = the page surface.
|
|
26
|
+
$nb-ink: #111111 !default; // borders + hard shadows (light mode)
|
|
27
|
+
$nb-paper: #FFFEF2 !default; // body background (light mode)
|
|
28
|
+
$nb-surface: #FFFFFF !default; // cards / elevated surfaces (light mode)
|
|
29
|
+
$nb-surface-alt: #F4F1E4 !default; // alt sections / wells (light mode)
|
|
30
|
+
|
|
31
|
+
// Dark mode counterparts
|
|
32
|
+
$nb-ink-dark: #F5F5F5 !default; // borders + shadows become near-white
|
|
33
|
+
$nb-paper-dark: #16161A !default; // body background (dark mode)
|
|
34
|
+
$nb-surface-dark: #1F1F25 !default; // cards (dark mode)
|
|
35
|
+
$nb-surface-alt-dark: #25252D !default; // alt sections (dark mode)
|
|
36
|
+
|
|
37
|
+
// ============================================
|
|
38
|
+
// Accent Palette (for color-block sections, tags, highlights)
|
|
39
|
+
// ============================================
|
|
40
|
+
// Used directly as section backgrounds and decorative blocks.
|
|
41
|
+
$nb-accent-blue: #2563EB !default;
|
|
42
|
+
$nb-accent-pink: #EC4899 !default;
|
|
43
|
+
$nb-accent-yellow: #FACC15 !default;
|
|
44
|
+
$nb-accent-green: #16A34A !default;
|
|
45
|
+
$nb-accent-purple: #8B5CF6 !default;
|
|
46
|
+
$nb-accent-orange: #FB923C !default;
|
|
47
|
+
|
|
48
|
+
// ============================================
|
|
49
|
+
// Borders — the defining structural element
|
|
50
|
+
// ============================================
|
|
51
|
+
$nb-border-width: 3px !default; // standard border thickness
|
|
52
|
+
$nb-border-width-lg: 4px !default; // emphasis (hero buttons, feature cards)
|
|
53
|
+
$nb-border-width-sm: 2px !default; // small controls (inputs, tags)
|
|
54
|
+
$nb-border-color: $nb-ink !default; // remapped to ink-dark in dark mode via _root
|
|
55
|
+
$nb-border: $nb-border-width solid $nb-border-color !default;
|
|
56
|
+
|
|
57
|
+
// Zero radius everywhere — this is the neobrutalist signature.
|
|
58
|
+
$border-radius: 0 !default;
|
|
59
|
+
$border-radius-sm: 0 !default;
|
|
60
|
+
$border-radius-lg: 0 !default;
|
|
61
|
+
$border-radius-xl: 0 !default;
|
|
62
|
+
$border-radius-2xl: 0 !default;
|
|
63
|
+
$border-radius-pill: 0 !default;
|
|
64
|
+
|
|
65
|
+
// ============================================
|
|
66
|
+
// Hard Offset Shadows — the second defining element
|
|
67
|
+
// ============================================
|
|
68
|
+
// No blur, no spread — a solid block offset down-right in ink color.
|
|
69
|
+
$nb-shadow-offset: 5px !default; // default offset distance
|
|
70
|
+
$nb-shadow-offset-sm: 3px !default;
|
|
71
|
+
$nb-shadow-offset-lg: 8px !default;
|
|
72
|
+
$nb-shadow-color: $nb-ink !default; // remapped in dark mode via _root
|
|
73
|
+
|
|
74
|
+
$nb-shadow-sm: $nb-shadow-offset-sm $nb-shadow-offset-sm 0 $nb-shadow-color !default;
|
|
75
|
+
$nb-shadow: $nb-shadow-offset $nb-shadow-offset 0 $nb-shadow-color !default;
|
|
76
|
+
$nb-shadow-lg: $nb-shadow-offset-lg $nb-shadow-offset-lg 0 $nb-shadow-color !default;
|
|
77
|
+
|
|
78
|
+
// ============================================
|
|
79
|
+
// Typography
|
|
80
|
+
// ============================================
|
|
81
|
+
// Chunky geometric grotesk for display; clean grotesk for body.
|
|
82
|
+
$font-family-sans-serif: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif !default;
|
|
83
|
+
$nb-font-display: 'Archivo', 'Space Grotesk', sans-serif !default;
|
|
84
|
+
$nb-font-mono: 'Space Mono', ui-monospace, SFMono-Regular, Menlo, monospace !default;
|
|
85
|
+
|
|
86
|
+
$headings-font-weight: 800 !default;
|
|
87
|
+
$nb-heading-letter-spacing: -0.02em !default;
|
|
88
|
+
$font-weight-bold: 700 !default;
|
|
89
|
+
|
|
90
|
+
// ============================================
|
|
91
|
+
// Motion — snappy, mechanical, no easing softness
|
|
92
|
+
// ============================================
|
|
93
|
+
// Neobrutalism favors instant/linear motion over smooth cubic-beziers.
|
|
94
|
+
$nb-transition-fast: all 0.08s ease-out !default;
|
|
95
|
+
$nb-transition: all 0.12s ease-out !default;
|
|
96
|
+
|
|
97
|
+
// ============================================
|
|
98
|
+
// Component Sizing
|
|
99
|
+
// ============================================
|
|
100
|
+
// Avatar sizes map (matches Classy so shared layouts/includes render correctly)
|
|
101
|
+
$avatar-sizes: (
|
|
102
|
+
null: 3rem,
|
|
103
|
+
2xs: 0.5rem,
|
|
104
|
+
xs: 1.5rem,
|
|
105
|
+
sm: 2rem,
|
|
106
|
+
md: 2.5rem,
|
|
107
|
+
lg: 3.5rem,
|
|
108
|
+
xl: 5rem,
|
|
109
|
+
2xl: 7.5rem,
|
|
110
|
+
3xl: 10rem,
|
|
111
|
+
4xl: 12.5rem,
|
|
112
|
+
5xl: 15rem
|
|
113
|
+
) !default;
|
|
114
|
+
|
|
115
|
+
// ============================================
|
|
116
|
+
// Forward Bootstrap with our configuration
|
|
117
|
+
// ============================================
|
|
118
|
+
@forward '../bootstrap/scss/bootstrap.scss' with (
|
|
119
|
+
$primary: $primary,
|
|
120
|
+
$secondary: $secondary,
|
|
121
|
+
$success: $success,
|
|
122
|
+
$info: $info,
|
|
123
|
+
$warning: $warning,
|
|
124
|
+
$danger: $danger,
|
|
125
|
+
$light: $light,
|
|
126
|
+
$dark: $dark,
|
|
127
|
+
$font-family-sans-serif: $font-family-sans-serif,
|
|
128
|
+
$headings-font-weight: $headings-font-weight,
|
|
129
|
+
$font-weight-bold: $font-weight-bold,
|
|
130
|
+
$border-radius: $border-radius,
|
|
131
|
+
$border-radius-sm: $border-radius-sm,
|
|
132
|
+
$border-radius-lg: $border-radius-lg,
|
|
133
|
+
// Neobrutalism uses solid borders everywhere, so Bootstrap's default
|
|
134
|
+
// border width is bumped and box-shadow softness is disabled.
|
|
135
|
+
$border-width: $nb-border-width,
|
|
136
|
+
$enable-rounded: false,
|
|
137
|
+
$enable-shadows: false,
|
|
138
|
+
$enable-negative-margins: true
|
|
139
|
+
);
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Neobrutalism Theme — JS entry point
|
|
2
|
+
// Loaded at runtime via webpack's __theme__ alias (import('__theme__/_theme.js')).
|
|
3
|
+
// Exposes Bootstrap globally and wires up theme behaviors on DOM ready.
|
|
4
|
+
import bootstrap from '__main_assets__/themes/bootstrap/js/index.umd.js';
|
|
5
|
+
import { ready as domReady } from 'web-manager/modules/dom.js';
|
|
6
|
+
|
|
7
|
+
// Make Bootstrap available globally (used by UJM utilities + components)
|
|
8
|
+
window.bootstrap = bootstrap;
|
|
9
|
+
|
|
10
|
+
/* @dev-only:start */
|
|
11
|
+
{
|
|
12
|
+
console.log('Neobrutalism theme loaded successfully (assets/themes/neobrutalism/_theme.js)');
|
|
13
|
+
}
|
|
14
|
+
/* @dev-only:end */
|
|
15
|
+
|
|
16
|
+
// Theme behaviors
|
|
17
|
+
import setupNavbarScroll from './js/navbar-scroll.js';
|
|
18
|
+
import initializeTooltips from './js/initialize-tooltips.js';
|
|
19
|
+
|
|
20
|
+
// Initialize when DOM is ready
|
|
21
|
+
domReady().then(() => {
|
|
22
|
+
// Neobrutalism behaviors
|
|
23
|
+
setupNavbarScroll();
|
|
24
|
+
|
|
25
|
+
// Generic Bootstrap initializations
|
|
26
|
+
initializeTooltips();
|
|
27
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// Neobrutalism Theme — SCSS entry point
|
|
2
|
+
// Forwards config (so consuming projects can override vars), loads Bootstrap via
|
|
3
|
+
// config, then layers the neobrutalist system on top. Import order matters:
|
|
4
|
+
// config → mixins → root vars → base → layout → components → bootstrap overrides.
|
|
5
|
+
|
|
6
|
+
// Forward theme configuration (allows consuming project to override)
|
|
7
|
+
@forward 'config';
|
|
8
|
+
@use 'config' as *;
|
|
9
|
+
|
|
10
|
+
// Mixins must be available to every partial below.
|
|
11
|
+
// @import (not @use) so the mixins land in the global scope the @imports share.
|
|
12
|
+
@import 'css/base/mixins';
|
|
13
|
+
|
|
14
|
+
// CSS custom properties (light/dark bridge)
|
|
15
|
+
@import 'css/base/root';
|
|
16
|
+
|
|
17
|
+
// Base styles
|
|
18
|
+
@import 'css/base/typography';
|
|
19
|
+
@import 'css/base/utilities';
|
|
20
|
+
|
|
21
|
+
// Layout styles
|
|
22
|
+
@import 'css/layout/general';
|
|
23
|
+
@import 'css/layout/navigation';
|
|
24
|
+
|
|
25
|
+
// Component styles
|
|
26
|
+
@import 'css/components/buttons';
|
|
27
|
+
@import 'css/components/cards';
|
|
28
|
+
@import 'css/components/forms';
|
|
29
|
+
@import 'css/components/infinite-scroll';
|
|
30
|
+
|
|
31
|
+
// Universal Bootstrap overrides (shared across all UJ themes).
|
|
32
|
+
// Must come AFTER Bootstrap is loaded via config to use @extend.
|
|
33
|
+
@import '../bootstrap/overrides';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// Neobrutalism Theme — Mixins
|
|
2
|
+
// The shared building blocks of the neobrutalist look. Components @include these
|
|
3
|
+
// so the border/shadow/press system lives in ONE place (SSOT) rather than being
|
|
4
|
+
// copy-pasted across buttons, cards, inputs, etc.
|
|
5
|
+
|
|
6
|
+
// Hard border in the current ink color.
|
|
7
|
+
@mixin nb-border($width: var(--nb-border-width)) {
|
|
8
|
+
border: $width solid var(--nb-border-color);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// Hard offset shadow (no blur). $size: sm | md | lg.
|
|
12
|
+
@mixin nb-shadow($size: md) {
|
|
13
|
+
@if $size == sm {
|
|
14
|
+
box-shadow: var(--nb-shadow-sm);
|
|
15
|
+
} @else if $size == lg {
|
|
16
|
+
box-shadow: var(--nb-shadow-lg);
|
|
17
|
+
} @else {
|
|
18
|
+
box-shadow: var(--nb-shadow);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// The signature interaction: the element sits on a hard offset shadow, then
|
|
23
|
+
// "presses" toward the page on hover/active. THE INVARIANT: the element's
|
|
24
|
+
// translate distance + the shrunk shadow offset must always equal the RESTING
|
|
25
|
+
// shadow offset, so the bottom-right edge stays perfectly pinned (the face and
|
|
26
|
+
// shadow line up exactly when the press completes — no drift).
|
|
27
|
+
//
|
|
28
|
+
// $rest = the element's resting shadow offset. Pass the SAME size you gave
|
|
29
|
+
// nb-shadow() (default 5px = md; pass $nb-shadow-offset-lg for lg-shadow elements).
|
|
30
|
+
@mixin nb-press($rest: $nb-shadow-offset) {
|
|
31
|
+
transition: $nb-transition;
|
|
32
|
+
|
|
33
|
+
// Hover: press ~40% of the way in. shadow = rest - translate (stays pinned).
|
|
34
|
+
&:hover {
|
|
35
|
+
$hover-move: round($rest * 0.4);
|
|
36
|
+
$hover-shadow: $rest - $hover-move;
|
|
37
|
+
transform: translate($hover-move, $hover-move);
|
|
38
|
+
box-shadow: #{$hover-shadow} #{$hover-shadow} 0 var(--nb-shadow-color);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Active: press fully in. translate == rest, shadow collapses to 0 → flush.
|
|
42
|
+
&:active {
|
|
43
|
+
transform: translate($rest, $rest);
|
|
44
|
+
box-shadow: 0 0 0 var(--nb-shadow-color);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Neobrutalism Theme — CSS Custom Properties
|
|
2
|
+
// Bridges SCSS config into runtime CSS variables so light/dark mode switching
|
|
3
|
+
// works without recompilation. Components read these var(--nb-*) tokens, never
|
|
4
|
+
// the raw SCSS values, so dark mode is a single block of overrides.
|
|
5
|
+
|
|
6
|
+
// ============================================
|
|
7
|
+
// Light Mode (default)
|
|
8
|
+
// ============================================
|
|
9
|
+
:root,
|
|
10
|
+
[data-bs-theme="light"] {
|
|
11
|
+
// Structural tokens
|
|
12
|
+
--nb-ink: #{$nb-ink};
|
|
13
|
+
--nb-paper: #{$nb-paper};
|
|
14
|
+
--nb-surface: #{$nb-surface};
|
|
15
|
+
--nb-surface-alt: #{$nb-surface-alt};
|
|
16
|
+
|
|
17
|
+
// Height of the fixed navbar — the first section adds this to its top padding
|
|
18
|
+
// so content clears the overlapping nav (see _general.scss "Section rhythm").
|
|
19
|
+
--nb-navbar-height: 4.5rem;
|
|
20
|
+
|
|
21
|
+
// Border + shadow color follow the ink
|
|
22
|
+
--nb-border-color: var(--nb-ink);
|
|
23
|
+
--nb-shadow-color: var(--nb-ink);
|
|
24
|
+
|
|
25
|
+
// Border + shadow recipes (used by components)
|
|
26
|
+
--nb-border-width: #{$nb-border-width};
|
|
27
|
+
--nb-border: #{$nb-border-width} solid var(--nb-border-color);
|
|
28
|
+
--nb-shadow-sm: #{$nb-shadow-offset-sm} #{$nb-shadow-offset-sm} 0 var(--nb-shadow-color);
|
|
29
|
+
--nb-shadow: #{$nb-shadow-offset} #{$nb-shadow-offset} 0 var(--nb-shadow-color);
|
|
30
|
+
--nb-shadow-lg: #{$nb-shadow-offset-lg} #{$nb-shadow-offset-lg} 0 var(--nb-shadow-color);
|
|
31
|
+
|
|
32
|
+
// Accent palette (for color-block sections)
|
|
33
|
+
--nb-accent-blue: #{$nb-accent-blue};
|
|
34
|
+
--nb-accent-pink: #{$nb-accent-pink};
|
|
35
|
+
--nb-accent-yellow: #{$nb-accent-yellow};
|
|
36
|
+
--nb-accent-green: #{$nb-accent-green};
|
|
37
|
+
--nb-accent-purple: #{$nb-accent-purple};
|
|
38
|
+
--nb-accent-orange: #{$nb-accent-orange};
|
|
39
|
+
|
|
40
|
+
// INTERACTIVE accent — the single token every hover/active fill points at
|
|
41
|
+
// (nav links, footer links, dropdown items, body links, mobile toggler). It
|
|
42
|
+
// tracks the rendered primary blue (--bs-primary), NOT the yellow signature
|
|
43
|
+
// accent. Retune all interactive states from this one line. Yellow stays
|
|
44
|
+
// reserved for static signature blocks (kicker, highlight, hero, badges).
|
|
45
|
+
--nb-accent-interactive: var(--bs-primary);
|
|
46
|
+
--nb-accent-interactive-ink: #ffffff; // readable text on the interactive fill
|
|
47
|
+
|
|
48
|
+
// Map onto Bootstrap surfaces
|
|
49
|
+
--bs-body-bg: #{$nb-paper};
|
|
50
|
+
--bs-body-bg-rgb: #{red($nb-paper)}, #{green($nb-paper)}, #{blue($nb-paper)};
|
|
51
|
+
--bs-body-color: #{$nb-ink};
|
|
52
|
+
--bs-secondary-bg: #{$nb-surface};
|
|
53
|
+
--bs-tertiary-bg: #{$nb-surface-alt};
|
|
54
|
+
--bs-border-color: var(--nb-ink);
|
|
55
|
+
--bs-card-bg: #{$nb-surface};
|
|
56
|
+
--bs-emphasis-color: #{$nb-ink};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ============================================
|
|
60
|
+
// Dark Mode
|
|
61
|
+
// ============================================
|
|
62
|
+
// Ink flips to near-white: borders and hard shadows become light on dark paper.
|
|
63
|
+
[data-bs-theme="dark"] {
|
|
64
|
+
--nb-ink: #{$nb-ink-dark};
|
|
65
|
+
--nb-paper: #{$nb-paper-dark};
|
|
66
|
+
--nb-surface: #{$nb-surface-dark};
|
|
67
|
+
--nb-surface-alt: #{$nb-surface-alt-dark};
|
|
68
|
+
|
|
69
|
+
--nb-border-color: var(--nb-ink);
|
|
70
|
+
--nb-shadow-color: var(--nb-ink);
|
|
71
|
+
|
|
72
|
+
--bs-body-bg: #{$nb-paper-dark};
|
|
73
|
+
--bs-body-bg-rgb: #{red($nb-paper-dark)}, #{green($nb-paper-dark)}, #{blue($nb-paper-dark)};
|
|
74
|
+
--bs-body-color: #{$nb-ink-dark};
|
|
75
|
+
--bs-secondary-bg: #{$nb-surface-dark};
|
|
76
|
+
--bs-tertiary-bg: #{$nb-surface-alt-dark};
|
|
77
|
+
--bs-border-color: var(--nb-ink);
|
|
78
|
+
--bs-card-bg: #{$nb-surface-dark};
|
|
79
|
+
--bs-emphasis-color: #{$nb-ink-dark};
|
|
80
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Neobrutalism Theme — Typography
|
|
2
|
+
// Chunky, confident, tightly-tracked headings; clean grotesk body.
|
|
3
|
+
// Fonts are loaded via the theme's `head` block in base.html (Google Fonts),
|
|
4
|
+
// NOT @import-ed here, to avoid render-blocking duplicate loads.
|
|
5
|
+
|
|
6
|
+
body {
|
|
7
|
+
font-family: $font-family-sans-serif;
|
|
8
|
+
font-weight: 400;
|
|
9
|
+
-webkit-font-smoothing: antialiased;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
h1, h2, h3, h4, h5, h6,
|
|
13
|
+
.h1, .h2, .h3, .h4, .h5, .h6 {
|
|
14
|
+
font-family: $nb-font-display;
|
|
15
|
+
font-weight: $headings-font-weight;
|
|
16
|
+
letter-spacing: $nb-heading-letter-spacing;
|
|
17
|
+
line-height: 1.05;
|
|
18
|
+
text-wrap: balance;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Display headings get extra weight + tighter tracking
|
|
22
|
+
.display-1, .display-2, .display-3, .display-4, .display-5, .display-6 {
|
|
23
|
+
font-family: $nb-font-display;
|
|
24
|
+
font-weight: 900;
|
|
25
|
+
letter-spacing: -0.03em;
|
|
26
|
+
line-height: 0.98;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Monospace accents (kickers, labels, code-ish tags)
|
|
30
|
+
.font-mono,
|
|
31
|
+
code, kbd, samp, pre {
|
|
32
|
+
font-family: $nb-font-mono;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Eyebrow / kicker label — universal "section kicker" above headlines.
|
|
36
|
+
.kicker {
|
|
37
|
+
display: inline-block;
|
|
38
|
+
font-family: $nb-font-mono;
|
|
39
|
+
font-weight: 700;
|
|
40
|
+
font-size: 0.8rem;
|
|
41
|
+
text-transform: uppercase;
|
|
42
|
+
letter-spacing: 0.08em;
|
|
43
|
+
padding: 0.35rem 0.65rem;
|
|
44
|
+
background: var(--nb-accent-yellow);
|
|
45
|
+
color: #111111;
|
|
46
|
+
@include nb-border($nb-border-width-sm);
|
|
47
|
+
|
|
48
|
+
// On a dark/ink panel (e.g. the CTA), keep the accent block readable.
|
|
49
|
+
&--invert { background: var(--nb-accent-yellow); color: #111111; }
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Highlighted inline text — marker-style background swipe.
|
|
53
|
+
.highlight {
|
|
54
|
+
background: var(--nb-accent-yellow);
|
|
55
|
+
color: #111111;
|
|
56
|
+
padding: 0 0.15em;
|
|
57
|
+
box-decoration-break: clone;
|
|
58
|
+
-webkit-box-decoration-break: clone;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Links: bold, underlined, no fade — they look clickable and stay readable in both
|
|
62
|
+
// modes. Hover shifts to the interactive accent (blue), matching every other hover
|
|
63
|
+
// in the theme. Buttons/nav/dropdown/footer links opt out of this generic rule via
|
|
64
|
+
// their own higher-specificity hover, so this only catches plain in-content links.
|
|
65
|
+
a {
|
|
66
|
+
font-weight: 600;
|
|
67
|
+
text-underline-offset: 0.15em;
|
|
68
|
+
text-decoration-thickness: 2px;
|
|
69
|
+
|
|
70
|
+
&:hover { color: var(--nb-accent-interactive); }
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Buttons are <a> too, but set their text via --bs-btn-color. A direct `color` on
|
|
74
|
+
// `a:hover` would beat that var and turn button labels blue — exclude them so the
|
|
75
|
+
// button keeps its own (frozen) text color. Nav/dropdown/footer links already win
|
|
76
|
+
// on specificity with their explicit white hover, so they need no guard here.
|
|
77
|
+
a.btn:hover { color: var(--bs-btn-color); }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// Neobrutalism Theme — Base
|
|
2
|
+
// Body surface + neobrutalist treatment of Bootstrap's accent-block utilities.
|
|
3
|
+
// No theme-prefixed classes: the look comes from restyling STANDARD classes
|
|
4
|
+
// (.text-bg-*, .border, .shadow, .card) so markup stays swappable across themes.
|
|
5
|
+
|
|
6
|
+
// Body surface
|
|
7
|
+
body {
|
|
8
|
+
background-color: var(--nb-paper);
|
|
9
|
+
color: var(--bs-body-color);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// ============================================
|
|
13
|
+
// Accent blocks: .text-bg-* (Bootstrap) get the hard neobrutalist edge when
|
|
14
|
+
// used as full-bleed section/decorative blocks. Bootstrap already sets the
|
|
15
|
+
// background + a readable contrast color; we just square the corners.
|
|
16
|
+
// (Borders/shadows are added per-component where needed, e.g. .showcase-num.)
|
|
17
|
+
// ============================================
|
|
18
|
+
.text-bg-primary,
|
|
19
|
+
.text-bg-secondary,
|
|
20
|
+
.text-bg-success,
|
|
21
|
+
.text-bg-info,
|
|
22
|
+
.text-bg-warning,
|
|
23
|
+
.text-bg-danger {
|
|
24
|
+
border-radius: 0;
|
|
25
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// Neobrutalism Theme — Buttons
|
|
2
|
+
// Every button is a hard-bordered block sitting on an offset shadow that
|
|
3
|
+
// "presses" into the page on interaction. This restyles Bootstrap's own
|
|
4
|
+
// .btn / .btn-* classes so all existing markup (nav CTAs, hero buttons,
|
|
5
|
+
// forms) inherits the look with zero HTML changes.
|
|
6
|
+
|
|
7
|
+
.btn {
|
|
8
|
+
font-family: $nb-font-display;
|
|
9
|
+
font-weight: 700;
|
|
10
|
+
letter-spacing: -0.01em;
|
|
11
|
+
border-radius: 0;
|
|
12
|
+
@include nb-border();
|
|
13
|
+
@include nb-shadow(md);
|
|
14
|
+
text-transform: none;
|
|
15
|
+
padding: 0.6rem 1.25rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Press EXACTLY like the stat cards. These use the DOUBLED `.btn.btn` selector
|
|
19
|
+
// (specificity 0,2,0) on purpose: every theme page bundle re-emits Bootstrap's own
|
|
20
|
+
// `.btn { transition: color … }` and `.btn:hover` (because page SCSS @forwards
|
|
21
|
+
// Bootstrap), and those load AFTER the main bundle. The doubled class beats them so
|
|
22
|
+
// the press is pure transform+shadow with the stat-card timing — no color flash, no
|
|
23
|
+
// focus-ring fighting the offset shadow.
|
|
24
|
+
.btn.btn {
|
|
25
|
+
// Same transition the stat cards use → identical feel.
|
|
26
|
+
@include nb-press();
|
|
27
|
+
|
|
28
|
+
// Focus shows an OUTLINE ring (outside the box, never conflicts with the offset
|
|
29
|
+
// shadow). No focus box-shadow — that was the "flash of border".
|
|
30
|
+
&:focus { outline: 0; }
|
|
31
|
+
&:focus-visible {
|
|
32
|
+
outline: 3px solid var(--nb-border-color);
|
|
33
|
+
outline-offset: 3px;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.btn {
|
|
38
|
+
|
|
39
|
+
// Bootstrap adds a subtle border-color per-variant; force ink so the
|
|
40
|
+
// signature black/white frame is consistent across every color.
|
|
41
|
+
// (btn-adaptive / -inverse are the mode-flipping solids used by the nav CTA,
|
|
42
|
+
// auth buttons, etc. — they MUST be in this list or they'd keep Bootstrap's
|
|
43
|
+
// default "darken on hover" and feel different from every other button.)
|
|
44
|
+
&.btn-primary,
|
|
45
|
+
&.btn-secondary,
|
|
46
|
+
&.btn-success,
|
|
47
|
+
&.btn-info,
|
|
48
|
+
&.btn-warning,
|
|
49
|
+
&.btn-danger,
|
|
50
|
+
&.btn-light,
|
|
51
|
+
&.btn-dark,
|
|
52
|
+
&.btn-adaptive,
|
|
53
|
+
&.btn-adaptive-inverse {
|
|
54
|
+
border-color: var(--nb-border-color);
|
|
55
|
+
--bs-btn-hover-border-color: var(--nb-border-color);
|
|
56
|
+
--bs-btn-active-border-color: var(--nb-border-color);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 3. SOLID buttons: freeze hover/active fill to the resting color so the press is
|
|
60
|
+
// pure transform+shadow (no color shift) — exactly the stat-card feel. Outline
|
|
61
|
+
// buttons are intentionally EXCLUDED so they keep their fill-on-hover.
|
|
62
|
+
// Freezing to `var(--bs-btn-bg)` works in BOTH modes automatically because the
|
|
63
|
+
// adaptive classes already set --bs-btn-bg per light/dark.
|
|
64
|
+
&.btn-primary, &.btn-secondary, &.btn-success,
|
|
65
|
+
&.btn-info, &.btn-warning, &.btn-danger,
|
|
66
|
+
&.btn-light, &.btn-dark,
|
|
67
|
+
&.btn-adaptive, &.btn-adaptive-inverse {
|
|
68
|
+
--bs-btn-hover-bg: var(--bs-btn-bg);
|
|
69
|
+
--bs-btn-hover-color: var(--bs-btn-color);
|
|
70
|
+
--bs-btn-active-bg: var(--bs-btn-bg);
|
|
71
|
+
--bs-btn-active-color: var(--bs-btn-color);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// btn-adaptive / -inverse RESTING fill. The global _buttons-adaptive.scss sets these
|
|
76
|
+
// via `.btn-adaptive` (0,1,0), but Bootstrap's own `.btn { --bs-btn-bg: transparent }`
|
|
77
|
+
// re-emission can tie/beat it on order, leaving the button transparent. Restate the
|
|
78
|
+
// resting fill here at `.btn.btn-adaptive` (0,2,0) so it always wins — same trick the
|
|
79
|
+
// press uses. Mode-flip handled by pairing with [data-bs-theme="dark"].
|
|
80
|
+
.btn.btn-adaptive {
|
|
81
|
+
--bs-btn-color: #fff;
|
|
82
|
+
--bs-btn-bg: var(--bs-dark);
|
|
83
|
+
--bs-btn-border-color: var(--nb-border-color);
|
|
84
|
+
}
|
|
85
|
+
[data-bs-theme="dark"] .btn.btn-adaptive {
|
|
86
|
+
--bs-btn-color: #000;
|
|
87
|
+
--bs-btn-bg: var(--bs-light);
|
|
88
|
+
}
|
|
89
|
+
.btn.btn-adaptive-inverse {
|
|
90
|
+
--bs-btn-color: #000;
|
|
91
|
+
--bs-btn-bg: var(--bs-light);
|
|
92
|
+
--bs-btn-border-color: var(--nb-border-color);
|
|
93
|
+
}
|
|
94
|
+
[data-bs-theme="dark"] .btn.btn-adaptive-inverse {
|
|
95
|
+
--bs-btn-color: #fff;
|
|
96
|
+
--bs-btn-bg: var(--bs-dark);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Size variants keep the chunky proportions
|
|
100
|
+
.btn-lg {
|
|
101
|
+
padding: 0.85rem 1.75rem;
|
|
102
|
+
font-size: 1.1rem;
|
|
103
|
+
@include nb-border($nb-border-width-lg);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.btn-sm {
|
|
107
|
+
padding: 0.35rem 0.8rem;
|
|
108
|
+
font-size: 0.85rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Outline buttons: transparent fill, ink frame, fill-on-hover (no fade)
|
|
112
|
+
[class*="btn-outline-"] {
|
|
113
|
+
background: transparent;
|
|
114
|
+
border-color: var(--nb-border-color);
|
|
115
|
+
color: var(--bs-body-color);
|
|
116
|
+
|
|
117
|
+
&:hover {
|
|
118
|
+
color: #111111;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
.btn-outline-primary:hover { background: $primary; }
|
|
122
|
+
.btn-outline-secondary:hover { background: $secondary; }
|
|
123
|
+
.btn-outline-success:hover { background: $success; }
|
|
124
|
+
.btn-outline-danger:hover { background: $danger; }
|
|
125
|
+
.btn-outline-warning:hover { background: $warning; }
|
|
126
|
+
.btn-outline-info:hover { background: $info; }
|
|
127
|
+
|
|
128
|
+
// Link-style button stays flat (no border/shadow) but bold + underlined
|
|
129
|
+
.btn-link {
|
|
130
|
+
border: 0;
|
|
131
|
+
box-shadow: none;
|
|
132
|
+
font-weight: 700;
|
|
133
|
+
text-decoration: underline;
|
|
134
|
+
text-underline-offset: 0.2em;
|
|
135
|
+
|
|
136
|
+
&:hover,
|
|
137
|
+
&:active {
|
|
138
|
+
transform: none;
|
|
139
|
+
box-shadow: none;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// NOTE: There are intentionally NO theme-specific accent button classes
|
|
144
|
+
// (e.g. .btn-nb-yellow). Themes must restyle the STANDARD Bootstrap button
|
|
145
|
+
// classes so the same markup works across themes (swap theme.id, done). Need a
|
|
146
|
+
// yellow CTA? Use `.btn-warning` ($warning is the acid-yellow accent). Need other
|
|
147
|
+
// accents? Use `.btn-primary` / `.btn-success` / etc. The base `.btn` rule above
|
|
148
|
+
// already gives every variant the neobrutalist border + offset shadow + press.
|