@keenmate/pure-css 1.1.0 → 1.2.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 +85 -0
- package/COMPONENTS.md +149 -0
- package/README.md +20 -8
- package/components.json +2692 -0
- package/dist/css/base.css +1 -0
- package/dist/css/pure-css.css +316 -15
- package/dist/css/utilities.css +237 -0
- package/package.json +6 -3
- package/src/scss/_base-css-variables.scss +16 -5
- package/src/scss/_icon-hover.scss +64 -64
- package/src/scss/_layout-responsive.scss +123 -92
- package/src/scss/_sidebar.scss +447 -447
- package/src/scss/pure-css.scss +48 -48
- package/src/scss/utilities.scss +59 -10
- package/src/scss/variables/_base.scss +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keenmate/pure-css",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "The Keenmate CSS foundation — --base-* theming contract, PureCSS grid and utility classes. Extracted from pure-admin-core so docs sites, standalone pages and every web/svelte component share one theming layer.",
|
|
5
5
|
"style": "dist/css/pure-css.css",
|
|
6
6
|
"exports": {
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"src/js/",
|
|
25
25
|
"README.md",
|
|
26
26
|
"CHANGELOG.md",
|
|
27
|
-
"LICENSE"
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"components.json",
|
|
29
|
+
"COMPONENTS.md"
|
|
28
30
|
],
|
|
29
31
|
"scripts": {
|
|
30
32
|
"build:bundle": "sass src/scss/pure-css.scss dist/css/pure-css.css --no-source-map --silence-deprecation=import",
|
|
@@ -42,7 +44,8 @@
|
|
|
42
44
|
"test:e2e:ui": "playwright test --ui",
|
|
43
45
|
"test:e2e:headed": "playwright test --headed",
|
|
44
46
|
"test:e2e:install": "playwright install chromium",
|
|
45
|
-
"prepublishOnly": "npm run build"
|
|
47
|
+
"prepublishOnly": "npm run build && npm run catalog",
|
|
48
|
+
"catalog": "node scripts/build-catalog.mjs"
|
|
46
49
|
},
|
|
47
50
|
"keywords": [
|
|
48
51
|
"css",
|
|
@@ -14,11 +14,18 @@
|
|
|
14
14
|
// --ms-accent-color: var(--base-accent-color, #3b82f6);
|
|
15
15
|
// ============================================================================
|
|
16
16
|
|
|
17
|
-
// Make
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
//
|
|
21
|
-
|
|
17
|
+
// Make the $-vocabulary resolvable here.
|
|
18
|
+
//
|
|
19
|
+
// MUST be @import, not `@use 'variables/index' as *`. A theme's whole job is to set
|
|
20
|
+
// $base-* BEFORE pulling this file in (the !default flags then keep those values) --
|
|
21
|
+
// but `@use ... as *` REFUSES to expose a member whose name already exists in the
|
|
22
|
+
// importing global scope, so every theme died on
|
|
23
|
+
// "This module and the new module both define a variable named $base-accent-color".
|
|
24
|
+
// That made the usage documented at the top of this file impossible: it worked only
|
|
25
|
+
// for a theme that overrode nothing. @import shares one global scope and is what the
|
|
26
|
+
// !default mechanism needs. pure-css's own `@use 'base-css-variables' as bcv` entries
|
|
27
|
+
// are unaffected -- a module that @imports still exports its members normally.
|
|
28
|
+
@import 'variables/index';
|
|
22
29
|
|
|
23
30
|
@mixin output-base-css-variables {
|
|
24
31
|
// === Accent Colors ===
|
|
@@ -181,6 +188,10 @@
|
|
|
181
188
|
--base-border-radius-sm: #{$base-border-radius-sm};
|
|
182
189
|
--base-border-radius-md: #{$base-border-radius-md};
|
|
183
190
|
--base-border-radius-lg: #{$base-border-radius-lg};
|
|
191
|
+
// Checkbox BOX scale — multiplies the box's own size (NOT a transform, which
|
|
192
|
+
// would pixel-snap the mask glyph off-centre). One knob every component with a
|
|
193
|
+
// checkbox reads; pairs with --base-icon-check-size.
|
|
194
|
+
--base-checkbox-scale: #{$base-checkbox-scale};
|
|
184
195
|
|
|
185
196
|
// === Rem base for web components ===
|
|
186
197
|
--base-rem: #{$base-rem};
|
|
@@ -1,64 +1,64 @@
|
|
|
1
|
-
// ── Icon hover affordance (foundation) ────────────────────────────────────────
|
|
2
|
-
// See pure-admin/docs/icon-hover-fill-design.md.
|
|
3
|
-
//
|
|
4
|
-
// Inside an ENABLED interactive control on :hover, icons react — no JS, no SVG
|
|
5
|
-
// computation, driven by convention + marker classes the wrapper stamps:
|
|
6
|
-
//
|
|
7
|
-
// • Masked `.pa-icon` glyphs that declared a filled source on
|
|
8
|
-
// `--pa-icon-src-hover` swap their mask to it. NO-OP for outline-only glyphs
|
|
9
|
-
// (e.g. Lucide ships no solid), and no marker needed — it's automatic.
|
|
10
|
-
// • Font Awesome `<i>` marked `.pc-icon-hover-fill` flips regular → solid via the
|
|
11
|
-
// font-weight axis (same codepoint). Needs the `far` regular face present
|
|
12
|
-
// (largely FA Pro), else there's nothing lighter to flip from.
|
|
13
|
-
// • Outline icons marked `.pc-icon-hover-highlight` recolour to
|
|
14
|
-
// `--pc-icon-hover-color` (default: the accent). This is the answer for sets
|
|
15
|
-
// with no solid form (Lucide): a real hover cue without a fill.
|
|
16
|
-
//
|
|
17
|
-
// The behaviour lives here (foundation) so every consumer — pure-admin core,
|
|
18
|
-
// keen, svelte, the web components — shares ONE definition. Wrappers only stamp
|
|
19
|
-
// the marker classes. `pc-icon-hover-effects` is a mixin so component layers can
|
|
20
|
-
// apply the same effects to their own enabled-control selectors (e.g. core on
|
|
21
|
-
// `.pa-btn` / `.pa-tabs__item`) without redefining them.
|
|
22
|
-
//
|
|
23
|
-
// Deliberately NOT here yet: the two-asset outline↔solid toggle for Heroicons /
|
|
24
|
-
// Fluent (render both layers, swap visibility) — that needs a wrapper markup
|
|
25
|
-
// contract, so it's wired when a wrapper renders both layers.
|
|
26
|
-
|
|
27
|
-
@mixin pc-icon-hover-effects {
|
|
28
|
-
// Masked icons: swap to the filled mask source if one was declared. Set the
|
|
29
|
-
// longhand directly (not --pa-icon-src) so the var(--pa-icon-src) fallback
|
|
30
|
-
// stays non-cyclic — reassigning --pa-icon-src to reference itself would
|
|
31
|
-
// compute to invalid and wipe the mask to a solid box.
|
|
32
|
-
.pa-icon {
|
|
33
|
-
-webkit-mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
34
|
-
mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Font Awesome regular → solid (weight axis). No transition — a font-weight
|
|
38
|
-
// swap is instant, matching the mask swap.
|
|
39
|
-
.pc-icon-hover-fill {
|
|
40
|
-
font-weight: 900;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Outline-only sets (Lucide): recolour the stroke instead of filling. Works
|
|
44
|
-
// because Lucide SVGs are stroke="currentColor".
|
|
45
|
-
.pc-icon-hover-highlight {
|
|
46
|
-
color: var(--pc-icon-hover-color, var(--pc-accent));
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Shell contexts owned by the foundation: sidebar nav links AND submenu toggles,
|
|
51
|
-
// so a submenu parent's icon reacts identically to a plain/child link (not just
|
|
52
|
-
// to the toggle's own hover colour).
|
|
53
|
-
.pc-sidebar__link:not([aria-disabled='true']):not(.is-disabled):hover,
|
|
54
|
-
.pc-sidebar__toggle:not([aria-disabled='true']):not(.is-disabled):hover {
|
|
55
|
-
@include pc-icon-hover-effects;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Generic opt-in: put `.pc-icon-hover` on any enabled control/element to get the
|
|
59
|
-
// behaviour without depending on a component class (a bare link, a custom
|
|
60
|
-
// button, a list row, …). Disabled opt-outs are excluded so only actionable
|
|
61
|
-
// controls react.
|
|
62
|
-
.pc-icon-hover:not([disabled]):not([aria-disabled='true']):not(.is-disabled):hover {
|
|
63
|
-
@include pc-icon-hover-effects;
|
|
64
|
-
}
|
|
1
|
+
// ── Icon hover affordance (foundation) ────────────────────────────────────────
|
|
2
|
+
// See pure-admin/docs/icon-hover-fill-design.md.
|
|
3
|
+
//
|
|
4
|
+
// Inside an ENABLED interactive control on :hover, icons react — no JS, no SVG
|
|
5
|
+
// computation, driven by convention + marker classes the wrapper stamps:
|
|
6
|
+
//
|
|
7
|
+
// • Masked `.pa-icon` glyphs that declared a filled source on
|
|
8
|
+
// `--pa-icon-src-hover` swap their mask to it. NO-OP for outline-only glyphs
|
|
9
|
+
// (e.g. Lucide ships no solid), and no marker needed — it's automatic.
|
|
10
|
+
// • Font Awesome `<i>` marked `.pc-icon-hover-fill` flips regular → solid via the
|
|
11
|
+
// font-weight axis (same codepoint). Needs the `far` regular face present
|
|
12
|
+
// (largely FA Pro), else there's nothing lighter to flip from.
|
|
13
|
+
// • Outline icons marked `.pc-icon-hover-highlight` recolour to
|
|
14
|
+
// `--pc-icon-hover-color` (default: the accent). This is the answer for sets
|
|
15
|
+
// with no solid form (Lucide): a real hover cue without a fill.
|
|
16
|
+
//
|
|
17
|
+
// The behaviour lives here (foundation) so every consumer — pure-admin core,
|
|
18
|
+
// keen, svelte, the web components — shares ONE definition. Wrappers only stamp
|
|
19
|
+
// the marker classes. `pc-icon-hover-effects` is a mixin so component layers can
|
|
20
|
+
// apply the same effects to their own enabled-control selectors (e.g. core on
|
|
21
|
+
// `.pa-btn` / `.pa-tabs__item`) without redefining them.
|
|
22
|
+
//
|
|
23
|
+
// Deliberately NOT here yet: the two-asset outline↔solid toggle for Heroicons /
|
|
24
|
+
// Fluent (render both layers, swap visibility) — that needs a wrapper markup
|
|
25
|
+
// contract, so it's wired when a wrapper renders both layers.
|
|
26
|
+
|
|
27
|
+
@mixin pc-icon-hover-effects {
|
|
28
|
+
// Masked icons: swap to the filled mask source if one was declared. Set the
|
|
29
|
+
// longhand directly (not --pa-icon-src) so the var(--pa-icon-src) fallback
|
|
30
|
+
// stays non-cyclic — reassigning --pa-icon-src to reference itself would
|
|
31
|
+
// compute to invalid and wipe the mask to a solid box.
|
|
32
|
+
.pa-icon {
|
|
33
|
+
-webkit-mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
34
|
+
mask-image: var(--pa-icon-src-hover, var(--pa-icon-src));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Font Awesome regular → solid (weight axis). No transition — a font-weight
|
|
38
|
+
// swap is instant, matching the mask swap.
|
|
39
|
+
.pc-icon-hover-fill {
|
|
40
|
+
font-weight: 900;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Outline-only sets (Lucide): recolour the stroke instead of filling. Works
|
|
44
|
+
// because Lucide SVGs are stroke="currentColor".
|
|
45
|
+
.pc-icon-hover-highlight {
|
|
46
|
+
color: var(--pc-icon-hover-color, var(--pc-accent));
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Shell contexts owned by the foundation: sidebar nav links AND submenu toggles,
|
|
51
|
+
// so a submenu parent's icon reacts identically to a plain/child link (not just
|
|
52
|
+
// to the toggle's own hover colour).
|
|
53
|
+
.pc-sidebar__link:not([aria-disabled='true']):not(.is-disabled):hover,
|
|
54
|
+
.pc-sidebar__toggle:not([aria-disabled='true']):not(.is-disabled):hover {
|
|
55
|
+
@include pc-icon-hover-effects;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Generic opt-in: put `.pc-icon-hover` on any enabled control/element to get the
|
|
59
|
+
// behaviour without depending on a component class (a bare link, a custom
|
|
60
|
+
// button, a list row, …). Disabled opt-outs are excluded so only actionable
|
|
61
|
+
// controls react.
|
|
62
|
+
.pc-icon-hover:not([disabled]):not([aria-disabled='true']):not(.is-disabled):hover {
|
|
63
|
+
@include pc-icon-hover-effects;
|
|
64
|
+
}
|
|
@@ -21,110 +21,130 @@
|
|
|
21
21
|
--pc-easing-snappy: #{$easing-snappy};
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
24
|
+
// Off-canvas drawer overlay — the sidebar SLIDES in/out as a fixed sheet in sync
|
|
25
|
+
// with the profile panel (same $transition-medium / $easing-snappy), translated
|
|
26
|
+
// off-canvas at the inline-start edge; `.sidebar-visible` slides it to
|
|
27
|
+
// translateX(0). Content takes full width in both states because the drawer is
|
|
28
|
+
// out of flow (fixed), so the flex sibling `.pc-layout__content {flex:1}` grows.
|
|
29
|
+
//
|
|
30
|
+
// Shared by two callers via $bodyQualifier:
|
|
31
|
+
// • '' → every sidebar below $mobile-breakpoint (media query).
|
|
32
|
+
// • '.sidebar-overlay' → the opt-in desktop "overlay" sidebar behaviour, at any
|
|
33
|
+
// width (burger opens a temporary floating drawer).
|
|
34
|
+
// The qualifier composes onto `body` so the body.loaded transition gate and the
|
|
35
|
+
// .sidebar-visible open state resolve as SAME-ELEMENT compounds (body.loaded,
|
|
36
|
+
// body.sidebar-visible) — not broken descendant selectors.
|
|
37
|
+
//
|
|
38
|
+
// $drawerWidth differs per caller: mobile uses a near-full-width 90vw sheet;
|
|
39
|
+
// desktop overlay uses the normal $sidebar-width (288px) so the content stays
|
|
40
|
+
// usable behind it and the dismiss zone isn't a sliver.
|
|
41
|
+
@mixin sidebar-drawer-overlay($bodyQualifier: '', $drawerWidth: $mobile-sidebar-width) {
|
|
42
|
+
body#{$bodyQualifier} {
|
|
43
|
+
.pc-layout__sidebar,
|
|
44
|
+
.pc-layout__sidebar--icon-collapse {
|
|
45
|
+
position: fixed;
|
|
46
|
+
top: $navbar-height;
|
|
47
|
+
inset-inline-start: 0; // RTL: flips to right
|
|
48
|
+
bottom: 0;
|
|
49
|
+
width: $drawerWidth;
|
|
50
|
+
z-index: 1050;
|
|
51
|
+
background-color: var(--pc-sidebar-bg, var(--base-page-bg));
|
|
52
|
+
opacity: 1;
|
|
53
|
+
overflow-y: auto;
|
|
54
|
+
overscroll-behavior: contain; // drawer's own scroll doesn't chain to the page
|
|
55
|
+
border-inline-end: none; // RTL: flips to left
|
|
56
|
+
transform: translateX(-100%); // off-canvas (slid out past the inline-start edge)
|
|
57
|
+
visibility: hidden; // inert + unfocusable while closed; flips visible on open
|
|
54
58
|
}
|
|
55
|
-
}
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
// RTL: the drawer sits at the inline-start (right) edge, so it slides off to
|
|
61
|
+
// the right when closed.
|
|
62
|
+
[dir="rtl"] & {
|
|
63
|
+
.pc-layout__sidebar,
|
|
64
|
+
.pc-layout__sidebar--icon-collapse {
|
|
65
|
+
transform: translateX(100%);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
// icon-collapse mode is a full labelled drawer here — force labels visible.
|
|
70
|
+
.pc-layout__sidebar--icon-collapse .pc-sidebar__label {
|
|
71
|
+
opacity: 1 !important;
|
|
72
|
+
width: auto !important;
|
|
73
|
+
overflow: visible !important;
|
|
74
|
+
position: static !important;
|
|
75
|
+
}
|
|
71
76
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
pointer-events: none;
|
|
88
|
-
|
|
89
|
-
body.loaded & {
|
|
90
|
-
transition: opacity $transition-medium $easing-snappy,
|
|
91
|
-
visibility $transition-medium $easing-snappy;
|
|
77
|
+
// Backdrop scrim: an always-present fixed pseudo that FADES its opacity, so it
|
|
78
|
+
// eases in/out with the drawer (a pseudo that only existed while open couldn't
|
|
79
|
+
// fade out). Inert + invisible when closed. On the body pseudo so it's
|
|
80
|
+
// positioned against the viewport — the toggle class lives on body too.
|
|
81
|
+
&::before {
|
|
82
|
+
content: "";
|
|
83
|
+
position: fixed;
|
|
84
|
+
top: $navbar-height;
|
|
85
|
+
inset-inline: 0; // RTL: covers full width
|
|
86
|
+
bottom: 0;
|
|
87
|
+
background-color: $mobile-backdrop-bg;
|
|
88
|
+
z-index: 1040;
|
|
89
|
+
opacity: 0;
|
|
90
|
+
visibility: hidden;
|
|
91
|
+
pointer-events: none;
|
|
92
92
|
}
|
|
93
|
-
}
|
|
94
93
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
94
|
+
// Gate the drawer + scrim transitions on body.loaded so neither animates from
|
|
95
|
+
// its closed position on first paint.
|
|
96
|
+
&.loaded {
|
|
97
|
+
.pc-layout__sidebar,
|
|
98
|
+
.pc-layout__sidebar--icon-collapse {
|
|
99
|
+
transition: transform $transition-medium $easing-snappy,
|
|
100
|
+
visibility $transition-medium $easing-snappy;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
&::before {
|
|
104
|
+
transition: opacity $transition-medium $easing-snappy,
|
|
105
|
+
visibility $transition-medium $easing-snappy;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
105
108
|
|
|
106
|
-
.
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
// Open — slide the drawer in, reveal the scrim, lock background scroll.
|
|
110
|
+
// Listed LAST so translateX(0) beats both the default and the RTL closed
|
|
111
|
+
// transform at equal specificity (source order wins).
|
|
112
|
+
&.sidebar-visible {
|
|
113
|
+
// Standard modal-drawer scroll-lock: while the drawer + scrim are open the
|
|
114
|
+
// page behind must not scroll (otherwise dragging the scrim strip scrolls
|
|
115
|
+
// the content under the fixed drawer, exposing that the drawer is only
|
|
116
|
+
// viewport-high). This covers desktop browsers + Android; iOS Safari ignores
|
|
117
|
+
// body{overflow:hidden} for touch scroll, so the toggle also applies a
|
|
118
|
+
// position:fixed body lock in JS (demo layout.mustache). See
|
|
119
|
+
// docs/mobile-sidebar-overlay.md.
|
|
120
|
+
overflow: hidden;
|
|
121
|
+
|
|
122
|
+
.pc-layout__sidebar,
|
|
123
|
+
.pc-layout__sidebar--icon-collapse {
|
|
124
|
+
transform: translateX(0);
|
|
125
|
+
visibility: visible;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&::before {
|
|
129
|
+
opacity: 1;
|
|
130
|
+
visibility: visible;
|
|
131
|
+
pointer-events: auto; // tap the scrim to dismiss
|
|
132
|
+
}
|
|
110
133
|
}
|
|
111
134
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
135
|
+
// Resize handle is meaningless on a fixed overlay drawer (and would ride the
|
|
136
|
+
// overlay edge straddling the backdrop-dismiss tap zone). Touch resize still
|
|
137
|
+
// works in the tablet band above $mobile-breakpoint.
|
|
138
|
+
.pc-sidebar-resize {
|
|
139
|
+
display: none;
|
|
116
140
|
}
|
|
117
141
|
}
|
|
142
|
+
}
|
|
118
143
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
// backdrop-dismiss tap zone). Touch resize still works in the tablet band
|
|
124
|
-
// above this breakpoint, where the coarse-pointer affordance is kept.
|
|
125
|
-
.pc-sidebar-resize {
|
|
126
|
-
display: none;
|
|
127
|
-
}
|
|
144
|
+
// Responsive Design - Mobile and Tablet
|
|
145
|
+
@media (max-width: $mobile-breakpoint) {
|
|
146
|
+
// Below the mobile breakpoint EVERY sidebar is an off-canvas drawer.
|
|
147
|
+
@include sidebar-drawer-overlay;
|
|
128
148
|
|
|
129
149
|
// Adjust navbar for mobile
|
|
130
150
|
.pc-navbar__inner {
|
|
@@ -146,6 +166,17 @@
|
|
|
146
166
|
}
|
|
147
167
|
}
|
|
148
168
|
|
|
169
|
+
// Desktop opt-in: `body.sidebar-overlay` turns the sidebar into a temporary
|
|
170
|
+
// floating drawer — the "overlay" sidebar behaviour. The burger toggles
|
|
171
|
+
// `.sidebar-visible`; a tap on the scrim/outside closes it (demo JS). Gated
|
|
172
|
+
// ABOVE the mobile breakpoint: at/below it the media query already renders the
|
|
173
|
+
// sidebar as a 90vw drawer, so the desktop rules would only fight it (and widen
|
|
174
|
+
// a phone drawer to 288px). Uses the normal $sidebar-width so the drawer floats
|
|
175
|
+
// over content rather than swallowing the viewport.
|
|
176
|
+
@media (min-width: ($mobile-breakpoint + 1)) {
|
|
177
|
+
@include sidebar-drawer-overlay('.sidebar-overlay', $sidebar-width);
|
|
178
|
+
}
|
|
179
|
+
|
|
149
180
|
@media (max-width: $tablet-breakpoint) and (min-width: $tablet-breakpoint-min) {
|
|
150
181
|
// Tablet: reduce the sidebar by default, but honour an explicit resize.
|
|
151
182
|
// The default (un-resized) width caps at $sidebar-width-tablet via min() so
|