@keenmate/pure-admin-core 2.4.0 → 2.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/README.md +11 -6
- package/dist/css/main.css +47 -130
- package/package.json +1 -1
- package/snippets/AUDIT.md +94 -0
- package/snippets/alerts.html +264 -89
- package/snippets/badges.html +193 -61
- package/snippets/buttons.html +178 -0
- package/snippets/callouts.html +210 -129
- package/snippets/cards.html +383 -200
- package/snippets/checkbox-lists.html +199 -65
- package/snippets/code.html +55 -11
- package/snippets/command-palette.html +401 -111
- package/snippets/comparison.html +144 -93
- package/snippets/customization.html +311 -104
- package/snippets/data-display.html +584 -0
- package/snippets/detail-panel.html +470 -138
- package/snippets/filter-card.html +246 -0
- package/snippets/forms.html +408 -308
- package/snippets/grid.html +253 -141
- package/snippets/layout.html +379 -480
- package/snippets/lists.html +144 -47
- package/snippets/loaders.html +64 -39
- package/snippets/manifest.json +330 -280
- package/snippets/modal-dialogs.html +137 -64
- package/snippets/modals.html +221 -151
- package/snippets/notifications.html +285 -0
- package/snippets/popconfirm.html +213 -19
- package/snippets/profile.html +290 -330
- package/snippets/statistics.html +247 -0
- package/snippets/tables.html +359 -150
- package/snippets/tabs.html +129 -45
- package/snippets/timeline.html +123 -56
- package/snippets/toasts.html +179 -31
- package/snippets/tooltips.html +199 -81
- package/snippets/typography.html +183 -58
- package/snippets/utilities.html +511 -415
- package/snippets/virtual-scroll.html +201 -75
- package/snippets/web-daterangepicker.html +369 -189
- package/snippets/web-multiselect.html +360 -124
- package/src/scss/core-components/_alerts.scss +51 -12
- package/src/scss/core-components/_pagers.scss +1 -1
- package/src/scss/core-components/_popconfirm.scss +35 -13
- package/src/scss/core-components/_tables.scss +2 -134
- package/src/scss/variables/_components.scss +17 -2
package/snippets/layout.html
CHANGED
|
@@ -1,122 +1,207 @@
|
|
|
1
1
|
<!-- ================================
|
|
2
2
|
LAYOUT & SIDEBAR SNIPPETS
|
|
3
3
|
Pure Admin Visual Framework
|
|
4
|
+
|
|
5
|
+
SCSS lives in core-components/layout/ as a subfolder:
|
|
6
|
+
_layout-container.scss .pa-layout, container widths, footer
|
|
7
|
+
_navbar.scss .pa-navbar + header sections
|
|
8
|
+
_navbar-elements.scss burger, brand, nav, dropdowns, title, profile
|
|
9
|
+
_sidebar.scss .pa-layout__sidebar + .pa-sidebar BEM block
|
|
10
|
+
_sidebar-states.scss hidden, icon-collapse, flyouts
|
|
11
|
+
_layout-responsive.scss mobile / tablet media queries
|
|
4
12
|
================================ -->
|
|
5
13
|
|
|
14
|
+
|
|
6
15
|
<!-- ================================
|
|
7
16
|
BASIC LAYOUT STRUCTURE
|
|
17
|
+
The framework expects this outer shell — navbar fixed at top,
|
|
18
|
+
layout below it hosting sidebar + content + footer.
|
|
8
19
|
================================ -->
|
|
9
20
|
|
|
10
|
-
<!-- Navbar (
|
|
21
|
+
<!-- Navbar (position: fixed, full width by default) -->
|
|
11
22
|
<nav class="pa-navbar">
|
|
12
23
|
<div class="pa-navbar__inner">
|
|
13
|
-
<!--
|
|
14
|
-
<!-- Burger menu, brand, navigation, page title, profile -->
|
|
15
|
-
<!-- See HEADER/NAVBAR section below for complete example -->
|
|
24
|
+
<!-- Header sections go here — see NAVBAR section below for a full example -->
|
|
16
25
|
</div>
|
|
17
26
|
</nav>
|
|
18
27
|
|
|
19
|
-
<!-- Layout
|
|
28
|
+
<!-- Layout wrapper (sits below navbar thanks to margin-top: $header-height) -->
|
|
20
29
|
<div class="pa-layout">
|
|
21
|
-
<!--
|
|
30
|
+
<!-- Inner: sidebar + content (flex row) -->
|
|
22
31
|
<div class="pa-layout__inner">
|
|
23
|
-
<!-- Sidebar -->
|
|
24
32
|
<aside class="pa-layout__sidebar">
|
|
25
33
|
<nav class="pa-sidebar__nav">
|
|
26
34
|
<ul>
|
|
27
|
-
<!-- Sidebar
|
|
28
|
-
<!-- See SIDEBAR sections below for complete examples -->
|
|
35
|
+
<!-- Sidebar items go here — see SIDEBAR sections below -->
|
|
29
36
|
</ul>
|
|
30
37
|
</nav>
|
|
31
38
|
</aside>
|
|
32
39
|
|
|
33
|
-
<!--
|
|
40
|
+
<!-- Content wrapper (scrolls in sticky mode) -->
|
|
34
41
|
<div class="pa-layout__content">
|
|
35
|
-
<!-- Main
|
|
42
|
+
<!-- Main content — sets container-type: inline-size, so
|
|
43
|
+
pa-col-sm-* / -md-* / -lg-* / -xl-* grid responsiveness
|
|
44
|
+
works automatically for any pa-row nested inside. -->
|
|
36
45
|
<main class="pa-layout__main">
|
|
37
|
-
|
|
38
|
-
<!-- Your page content here -->
|
|
39
|
-
</div>
|
|
46
|
+
<!-- Your page content here -->
|
|
40
47
|
</main>
|
|
41
48
|
</div>
|
|
42
49
|
</div>
|
|
43
50
|
|
|
44
|
-
<!-- Footer
|
|
45
|
-
<!-- Three-section layout: Left / Center / Right -->
|
|
51
|
+
<!-- Footer — sibling of __inner, inside .pa-layout -->
|
|
46
52
|
<footer class="pa-layout__footer">
|
|
47
|
-
<!-- Left Section (stays anchored left) -->
|
|
48
53
|
<div class="pa-footer__start">
|
|
49
54
|
<p>© 2024 Pure Admin Framework</p>
|
|
50
55
|
</div>
|
|
51
|
-
|
|
52
|
-
<!-- Center Section (flexible, fills space) -->
|
|
53
56
|
<div class="pa-footer__center">
|
|
54
|
-
<!-- Optional
|
|
57
|
+
<!-- Optional centre content; hidden on mobile by default -->
|
|
55
58
|
</div>
|
|
56
|
-
|
|
57
|
-
<!-- Right Section (stays anchored right) -->
|
|
58
59
|
<div class="pa-footer__end">
|
|
59
60
|
<span>App version: 1.2.1</span>
|
|
60
|
-
<span>Database version: 2.3.1</span>
|
|
61
61
|
<a href="#">Open Source Licenses</a>
|
|
62
62
|
</div>
|
|
63
63
|
</footer>
|
|
64
64
|
</div>
|
|
65
65
|
|
|
66
|
+
<!-- Footer end with vertical stack (for many small items) -->
|
|
67
|
+
<div class="pa-footer__end pa-footer__end--vertical">
|
|
68
|
+
<span>Version 1.2.1</span>
|
|
69
|
+
<span>Build 2341</span>
|
|
70
|
+
<a href="#">Licenses</a>
|
|
71
|
+
</div>
|
|
72
|
+
|
|
66
73
|
|
|
67
74
|
<!-- ================================
|
|
68
|
-
LAYOUT
|
|
69
|
-
|
|
75
|
+
LAYOUT MODES (body-level flags)
|
|
76
|
+
Two orthogonal mode flags applied to <body>:
|
|
77
|
+
pa-layout--sticky — body overflow: hidden; .pa-layout is
|
|
78
|
+
100vh, content wrapper scrolls internally.
|
|
79
|
+
Good for "app" feel with fixed sidebar.
|
|
80
|
+
(none) — default; body scrolls naturally, footer
|
|
81
|
+
reaches viewport bottom via min-height.
|
|
82
|
+
|
|
83
|
+
Container widths (also body classes — constrain both .pa-navbar
|
|
84
|
+
and .pa-layout max-width):
|
|
85
|
+
pa-container-sm 768px
|
|
86
|
+
pa-container-md 1024px
|
|
87
|
+
pa-container-lg 1280px
|
|
88
|
+
pa-container-xl 1600px
|
|
89
|
+
pa-container-2xl 1920px
|
|
90
|
+
(none) fluid / full width
|
|
70
91
|
================================ -->
|
|
71
92
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
<div class="pa-layout">
|
|
75
|
-
<!-- Content -->
|
|
76
|
-
</div>
|
|
93
|
+
<body class="pa-layout--sticky pa-container-lg">
|
|
94
|
+
<!-- Sticky mode, constrained to 1280px -->
|
|
77
95
|
</body>
|
|
78
96
|
|
|
79
|
-
<!-- Small Container (768px) -->
|
|
80
|
-
<body class="pa-container-sm">
|
|
81
|
-
<div class="pa-layout">
|
|
82
|
-
<!-- Content -->
|
|
83
|
-
</div>
|
|
84
|
-
</body>
|
|
85
97
|
|
|
86
|
-
<!--
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
</div>
|
|
91
|
-
</body>
|
|
98
|
+
<!-- ================================
|
|
99
|
+
NAVBAR / HEADER
|
|
100
|
+
Three-section layout (start / center / end) inside .pa-navbar__inner.
|
|
101
|
+
================================ -->
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
103
|
+
<nav class="pa-navbar">
|
|
104
|
+
<div class="pa-navbar__inner">
|
|
105
|
+
<!-- START: burger, brand, left nav -->
|
|
106
|
+
<div class="pa-header__start">
|
|
107
|
+
<button class="pa-header__burger burger-menu" onclick="toggleSidebar()" aria-label="Toggle sidebar">
|
|
108
|
+
<span></span><span></span><span></span>
|
|
109
|
+
</button>
|
|
99
110
|
|
|
100
|
-
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
111
|
+
<div class="pa-header__brand">
|
|
112
|
+
<h1>Pure Admin</h1>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<!-- Nav: pa-header__nav auto-styles its direct child <ul> > <li> > <a>.
|
|
116
|
+
No additional classes needed on list items or anchors. -->
|
|
117
|
+
<nav class="pa-header__nav pa-header__nav--start">
|
|
118
|
+
<ul>
|
|
119
|
+
<li><a href="/">Dashboard</a></li>
|
|
120
|
+
<li><a href="/components">Components</a></li>
|
|
121
|
+
|
|
122
|
+
<!-- Hover-triggered dropdown -->
|
|
123
|
+
<li class="pa-header__nav-item pa-header__nav-item--has-dropdown">
|
|
124
|
+
<a href="#" class="pa-header__nav-link">More</a>
|
|
125
|
+
<ul class="pa-header__dropdown">
|
|
126
|
+
<li><a href="/forms">Forms</a></li>
|
|
127
|
+
<li><a href="/tables">Tables</a></li>
|
|
128
|
+
|
|
129
|
+
<!-- Nested dropdown (level 2) -->
|
|
130
|
+
<li class="pa-header__nav-item--has-dropdown">
|
|
131
|
+
<a href="#">Reports ›</a>
|
|
132
|
+
<ul class="pa-header__dropdown pa-header__dropdown--level2">
|
|
133
|
+
<li><a href="/reports/daily">Daily</a></li>
|
|
134
|
+
<li><a href="/reports/weekly">Weekly</a></li>
|
|
135
|
+
</ul>
|
|
136
|
+
</li>
|
|
137
|
+
</ul>
|
|
138
|
+
</li>
|
|
139
|
+
</ul>
|
|
140
|
+
</nav>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<!-- CENTER: page title (flexes + truncates) -->
|
|
144
|
+
<div class="pa-header__center">
|
|
145
|
+
<div class="pa-header__title">
|
|
146
|
+
<h2>Dashboard</h2>
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
|
|
150
|
+
<!-- END: right nav, notifications, profile -->
|
|
151
|
+
<div class="pa-header__end">
|
|
152
|
+
<nav class="pa-header__nav pa-header__nav--end">
|
|
153
|
+
<ul>
|
|
154
|
+
<li><a href="/alerts">Alerts</a></li>
|
|
155
|
+
</ul>
|
|
156
|
+
</nav>
|
|
157
|
+
|
|
158
|
+
<!-- pa-notifications is defined in _notifications.scss, not
|
|
159
|
+
layout — see the (pending) notifications snippet for
|
|
160
|
+
the full variant set. -->
|
|
161
|
+
<div class="pa-notifications">
|
|
162
|
+
<button class="pa-notifications__btn" onclick="toggleNotifications()" aria-label="Notifications">
|
|
163
|
+
<span class="pa-notifications__icon">🔔</span>
|
|
164
|
+
<span class="pa-notifications__badge">3</span>
|
|
165
|
+
</button>
|
|
166
|
+
</div>
|
|
106
167
|
|
|
107
|
-
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
168
|
+
<button class="pa-header__profile-btn" onclick="toggleProfilePanel()" aria-label="User Profile">
|
|
169
|
+
<span class="pa-btn__icon">👤</span>
|
|
170
|
+
<span class="pa-header__profile-name">John Doe</span>
|
|
171
|
+
</button>
|
|
172
|
+
</div>
|
|
111
173
|
</div>
|
|
112
|
-
</
|
|
174
|
+
</nav>
|
|
175
|
+
|
|
176
|
+
<!--
|
|
177
|
+
Notes on the navbar:
|
|
178
|
+
- .pa-header__nav--start / --end are organisational placeholders
|
|
179
|
+
(empty SCSS blocks). They let you group nav links by side without
|
|
180
|
+
adding display rules. If you add your own styling, remember these
|
|
181
|
+
classes carry none of their own.
|
|
182
|
+
- .pa-header__nav-item--has-dropdown uses position: static so the
|
|
183
|
+
dropdown positions relative to the navbar, not this specific item.
|
|
184
|
+
- On mobile (max-width: $mobile-breakpoint), .pa-header__nav is hidden
|
|
185
|
+
entirely. Put dropdown-only items in a sidebar nav if they must stay
|
|
186
|
+
reachable below 768px.
|
|
187
|
+
-->
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
<!-- THEME SWITCHER (helper block in the header) -->
|
|
191
|
+
|
|
192
|
+
<div class="theme-switcher">
|
|
193
|
+
<label for="theme">Theme:</label>
|
|
194
|
+
<select id="theme" onchange="switchTheme(this.value)">
|
|
195
|
+
<option value="corporate">Corporate</option>
|
|
196
|
+
<option value="dark">Dark</option>
|
|
197
|
+
</select>
|
|
198
|
+
</div>
|
|
113
199
|
|
|
114
200
|
|
|
115
201
|
<!-- ================================
|
|
116
|
-
SIDEBAR
|
|
202
|
+
SIDEBAR — BASIC MENU
|
|
117
203
|
================================ -->
|
|
118
204
|
|
|
119
|
-
<!-- Sidebar with Simple Links -->
|
|
120
205
|
<aside class="pa-layout__sidebar">
|
|
121
206
|
<nav class="pa-sidebar__nav">
|
|
122
207
|
<ul>
|
|
@@ -126,74 +211,33 @@
|
|
|
126
211
|
<span class="pa-sidebar__label">Dashboard</span>
|
|
127
212
|
</a>
|
|
128
213
|
</li>
|
|
129
|
-
|
|
130
214
|
<li class="pa-sidebar__item">
|
|
131
215
|
<a href="/components" class="pa-sidebar__link">
|
|
132
216
|
<span class="pa-sidebar__icon">🧩</span>
|
|
133
217
|
<span class="pa-sidebar__label">Components</span>
|
|
134
218
|
</a>
|
|
135
219
|
</li>
|
|
136
|
-
|
|
137
220
|
<li class="pa-sidebar__item">
|
|
138
221
|
<a href="/forms" class="pa-sidebar__link">
|
|
139
222
|
<span class="pa-sidebar__icon">📝</span>
|
|
140
223
|
<span class="pa-sidebar__label">Forms</span>
|
|
141
224
|
</a>
|
|
142
225
|
</li>
|
|
143
|
-
|
|
144
|
-
<li class="pa-sidebar__item">
|
|
145
|
-
<a href="/tables" class="pa-sidebar__link">
|
|
146
|
-
<span class="pa-sidebar__icon">📋</span>
|
|
147
|
-
<span class="pa-sidebar__label">Tables</span>
|
|
148
|
-
</a>
|
|
149
|
-
</li>
|
|
150
|
-
</ul>
|
|
151
|
-
</nav>
|
|
152
|
-
</aside>
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
<!-- ================================
|
|
156
|
-
SIDEBAR - WITH FONT AWESOME ICONS
|
|
157
|
-
================================ -->
|
|
158
|
-
|
|
159
|
-
<!-- Sidebar with Font Awesome Icons -->
|
|
160
|
-
<aside class="pa-layout__sidebar">
|
|
161
|
-
<nav class="pa-sidebar__nav">
|
|
162
|
-
<ul>
|
|
163
|
-
<li class="pa-sidebar__item">
|
|
164
|
-
<a href="/" class="pa-sidebar__link pa-sidebar__link--active">
|
|
165
|
-
<span class="pa-sidebar__icon"><i class="fa-solid fa-chart-line"></i></span>
|
|
166
|
-
<span class="pa-sidebar__label">Dashboard</span>
|
|
167
|
-
</a>
|
|
168
|
-
</li>
|
|
169
|
-
|
|
170
|
-
<li class="pa-sidebar__item">
|
|
171
|
-
<a href="/users" class="pa-sidebar__link">
|
|
172
|
-
<span class="pa-sidebar__icon"><i class="fa-solid fa-users"></i></span>
|
|
173
|
-
<span class="pa-sidebar__label">Users</span>
|
|
174
|
-
</a>
|
|
175
|
-
</li>
|
|
176
|
-
|
|
177
|
-
<li class="pa-sidebar__item">
|
|
178
|
-
<a href="/settings" class="pa-sidebar__link">
|
|
179
|
-
<span class="pa-sidebar__icon"><i class="fa-solid fa-gear"></i></span>
|
|
180
|
-
<span class="pa-sidebar__label">Settings</span>
|
|
181
|
-
</a>
|
|
182
|
-
</li>
|
|
183
226
|
</ul>
|
|
184
227
|
</nav>
|
|
185
228
|
</aside>
|
|
186
229
|
|
|
187
230
|
|
|
188
231
|
<!-- ================================
|
|
189
|
-
SIDEBAR
|
|
232
|
+
SIDEBAR — WITH COLLAPSIBLE SUBMENU
|
|
233
|
+
Use <button class="pa-sidebar__toggle"> for collapsible parents and
|
|
234
|
+
<a class="pa-sidebar__link"> for leaves. Submenu opens when the
|
|
235
|
+
parent <li> gets --open and the <ul> gets --open.
|
|
190
236
|
================================ -->
|
|
191
237
|
|
|
192
|
-
<!-- Sidebar with Submenu (Two Levels) -->
|
|
193
238
|
<aside class="pa-layout__sidebar">
|
|
194
239
|
<nav class="pa-sidebar__nav">
|
|
195
240
|
<ul>
|
|
196
|
-
<!-- Regular link -->
|
|
197
241
|
<li class="pa-sidebar__item">
|
|
198
242
|
<a href="/" class="pa-sidebar__link">
|
|
199
243
|
<span class="pa-sidebar__icon">📊</span>
|
|
@@ -201,7 +245,7 @@
|
|
|
201
245
|
</a>
|
|
202
246
|
</li>
|
|
203
247
|
|
|
204
|
-
<!-- Collapsible
|
|
248
|
+
<!-- Collapsible (parent is a button, not a link) -->
|
|
205
249
|
<li class="pa-sidebar__item">
|
|
206
250
|
<button class="pa-sidebar__toggle" onclick="toggleSubmenu(this)">
|
|
207
251
|
<span class="pa-sidebar__icon">📋</span>
|
|
@@ -211,13 +255,13 @@
|
|
|
211
255
|
<ul class="pa-sidebar__submenu">
|
|
212
256
|
<li class="pa-sidebar__item">
|
|
213
257
|
<a href="/tables" class="pa-sidebar__link">
|
|
214
|
-
<span class="pa-sidebar__icon"
|
|
215
|
-
<span class="pa-sidebar__label">Standard
|
|
258
|
+
<span class="pa-sidebar__icon">•</span>
|
|
259
|
+
<span class="pa-sidebar__label">Standard</span>
|
|
216
260
|
</a>
|
|
217
261
|
</li>
|
|
218
262
|
<li class="pa-sidebar__item">
|
|
219
263
|
<a href="/tables-lazy" class="pa-sidebar__link">
|
|
220
|
-
<span class="pa-sidebar__icon"
|
|
264
|
+
<span class="pa-sidebar__icon">•</span>
|
|
221
265
|
<span class="pa-sidebar__label">Lazy Loading</span>
|
|
222
266
|
</a>
|
|
223
267
|
</li>
|
|
@@ -229,10 +273,12 @@
|
|
|
229
273
|
|
|
230
274
|
|
|
231
275
|
<!-- ================================
|
|
232
|
-
SIDEBAR
|
|
276
|
+
SIDEBAR — THREE-LEVEL NESTING
|
|
277
|
+
Level 2 and level 3 items get progressively indented via
|
|
278
|
+
padding-inline-start so the hierarchy reads at a glance. All
|
|
279
|
+
indentation is RTL-aware.
|
|
233
280
|
================================ -->
|
|
234
281
|
|
|
235
|
-
<!-- Sidebar with Three-Level Nesting -->
|
|
236
282
|
<aside class="pa-layout__sidebar">
|
|
237
283
|
<nav class="pa-sidebar__nav">
|
|
238
284
|
<ul>
|
|
@@ -259,12 +305,6 @@
|
|
|
259
305
|
<span class="pa-sidebar__label">Security</span>
|
|
260
306
|
</a>
|
|
261
307
|
</li>
|
|
262
|
-
<li class="pa-sidebar__item">
|
|
263
|
-
<a href="/settings/advanced/performance" class="pa-sidebar__link">
|
|
264
|
-
<span class="pa-sidebar__icon">•</span>
|
|
265
|
-
<span class="pa-sidebar__label">Performance</span>
|
|
266
|
-
</a>
|
|
267
|
-
</li>
|
|
268
308
|
</ul>
|
|
269
309
|
</li>
|
|
270
310
|
</ul>
|
|
@@ -275,272 +315,126 @@
|
|
|
275
315
|
|
|
276
316
|
|
|
277
317
|
<!-- ================================
|
|
278
|
-
SIDEBAR
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
<!-- Full Sidebar with Mixed Links and Submenus -->
|
|
282
|
-
<aside class="pa-layout__sidebar">
|
|
283
|
-
<nav class="pa-sidebar__nav">
|
|
284
|
-
<ul>
|
|
285
|
-
<li class="pa-sidebar__item">
|
|
286
|
-
<a href="/" class="pa-sidebar__link pa-sidebar__link--active">
|
|
287
|
-
<span class="pa-sidebar__icon">📊</span>
|
|
288
|
-
<span class="pa-sidebar__label">Dashboard</span>
|
|
289
|
-
</a>
|
|
290
|
-
</li>
|
|
291
|
-
|
|
292
|
-
<li class="pa-sidebar__item">
|
|
293
|
-
<a href="/components" class="pa-sidebar__link">
|
|
294
|
-
<span class="pa-sidebar__icon">🧩</span>
|
|
295
|
-
<span class="pa-sidebar__label">Components</span>
|
|
296
|
-
</a>
|
|
297
|
-
</li>
|
|
298
|
-
|
|
299
|
-
<li class="pa-sidebar__item">
|
|
300
|
-
<a href="/forms" class="pa-sidebar__link">
|
|
301
|
-
<span class="pa-sidebar__icon">📝</span>
|
|
302
|
-
<span class="pa-sidebar__label">Forms</span>
|
|
303
|
-
</a>
|
|
304
|
-
</li>
|
|
305
|
-
|
|
306
|
-
<li class="pa-sidebar__item">
|
|
307
|
-
<a href="/buttons" class="pa-sidebar__link">
|
|
308
|
-
<span class="pa-sidebar__icon">🔘</span>
|
|
309
|
-
<span class="pa-sidebar__label">Buttons</span>
|
|
310
|
-
</a>
|
|
311
|
-
</li>
|
|
312
|
-
|
|
313
|
-
<li class="pa-sidebar__item">
|
|
314
|
-
<a href="/cards" class="pa-sidebar__link">
|
|
315
|
-
<span class="pa-sidebar__icon">🃏</span>
|
|
316
|
-
<span class="pa-sidebar__label">Cards</span>
|
|
317
|
-
</a>
|
|
318
|
-
</li>
|
|
319
|
-
|
|
320
|
-
<li class="pa-sidebar__item">
|
|
321
|
-
<a href="/badges" class="pa-sidebar__link">
|
|
322
|
-
<span class="pa-sidebar__icon">🏷️</span>
|
|
323
|
-
<span class="pa-sidebar__label">Badges</span>
|
|
324
|
-
</a>
|
|
325
|
-
</li>
|
|
318
|
+
SIDEBAR MODES
|
|
319
|
+
Only one real modifier class exists on the sidebar element:
|
|
320
|
+
--icon-collapse (for the icon-only collapsed state).
|
|
326
321
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
</a>
|
|
332
|
-
</li>
|
|
322
|
+
Hidden vs visible is controlled by body classes:
|
|
323
|
+
.sidebar-hidden — desktop: sidebar collapses (or hides)
|
|
324
|
+
.sidebar-visible — mobile: sidebar overlays the content
|
|
325
|
+
================================ -->
|
|
333
326
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
327
|
+
<!-- Icon-collapse sidebar: hidden state shows a narrow icon bar with
|
|
328
|
+
hover flyouts for labels and submenus. When not hidden, renders
|
|
329
|
+
at normal width with labels visible. -->
|
|
330
|
+
<aside class="pa-layout__sidebar pa-layout__sidebar--icon-collapse">
|
|
331
|
+
<!-- Same pa-sidebar__nav markup as above. No content changes needed —
|
|
332
|
+
the CSS handles the collapse/flyout behaviour automatically. -->
|
|
333
|
+
</aside>
|
|
340
334
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
<span class="pa-sidebar__label">Tables</span>
|
|
346
|
-
<span class="pa-sidebar__chevron">›</span>
|
|
347
|
-
</button>
|
|
348
|
-
<ul class="pa-sidebar__submenu">
|
|
349
|
-
<li class="pa-sidebar__item">
|
|
350
|
-
<a href="/tables" class="pa-sidebar__link">
|
|
351
|
-
<span class="pa-sidebar__icon">📊</span>
|
|
352
|
-
<span class="pa-sidebar__label">Standard Tables</span>
|
|
353
|
-
</a>
|
|
354
|
-
</li>
|
|
355
|
-
<li class="pa-sidebar__item">
|
|
356
|
-
<a href="/tables-lazy" class="pa-sidebar__link">
|
|
357
|
-
<span class="pa-sidebar__icon">⚡</span>
|
|
358
|
-
<span class="pa-sidebar__label">Lazy Loading</span>
|
|
359
|
-
</a>
|
|
360
|
-
</li>
|
|
361
|
-
</ul>
|
|
362
|
-
</li>
|
|
363
|
-
</ul>
|
|
364
|
-
</nav>
|
|
335
|
+
<!-- Default sidebar with no modifier: hides entirely under .sidebar-hidden,
|
|
336
|
+
shows fully otherwise. -->
|
|
337
|
+
<aside class="pa-layout__sidebar">
|
|
338
|
+
<!-- nav -->
|
|
365
339
|
</aside>
|
|
366
340
|
|
|
367
341
|
|
|
368
342
|
<!-- ================================
|
|
369
|
-
SIDEBAR
|
|
370
|
-
|
|
343
|
+
SIDEBAR WIDTH / RESIZING
|
|
344
|
+
The sidebar reads its width from a CSS custom property:
|
|
371
345
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
<!-- Nav content -->
|
|
375
|
-
</aside>
|
|
346
|
+
:root { --pa-local-sidebar-width: 28.8rem; } /* default */
|
|
347
|
+
:where(.pa-layout__sidebar) { width: var(--pa-local-sidebar-width); }
|
|
376
348
|
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
<!-- Nav content -->
|
|
380
|
-
</aside>
|
|
349
|
+
:where() gives the rule zero specificity, so any utility class
|
|
350
|
+
(.wr-*, .minwr-*, .maxwr-*) on the same element wins.
|
|
381
351
|
|
|
352
|
+
To make the sidebar drag-resizable, include a .pa-sidebar-resize
|
|
353
|
+
handle inside it and wire up JS that:
|
|
354
|
+
1. On mousedown: add body.pa-sidebar-resizing (locks selection)
|
|
355
|
+
+ .pa-sidebar-resize--active (visual feedback)
|
|
356
|
+
2. On mousemove: update --pa-local-sidebar-width on :root or html
|
|
357
|
+
3. On mouseup: remove both classes; optionally persist width to
|
|
358
|
+
localStorage.
|
|
382
359
|
|
|
383
|
-
|
|
384
|
-
|
|
360
|
+
There is NO pa-layout__sidebar--resizable or --sticky modifier.
|
|
361
|
+
Earlier docs claimed these; they never existed in SCSS.
|
|
385
362
|
================================ -->
|
|
386
363
|
|
|
387
|
-
<!--
|
|
388
|
-
<aside class="pa-layout__sidebar">
|
|
389
|
-
<!-- Nav content -->
|
|
390
|
-
</aside>
|
|
391
|
-
|
|
392
|
-
<!-- Resizable sidebar (opt-in, drag right edge to resize) -->
|
|
393
|
-
<aside class="pa-layout__sidebar pa-layout__sidebar--resizable">
|
|
394
|
-
<!-- Nav content -->
|
|
395
|
-
<!-- Drag handle appears on right edge -->
|
|
396
|
-
<!-- Width saved to localStorage -->
|
|
397
|
-
<!-- Double-click handle to reset to default -->
|
|
398
|
-
</aside>
|
|
399
|
-
|
|
400
|
-
<!-- Custom fixed width using utility class (overrides default and resize) -->
|
|
364
|
+
<!-- Fixed width via rem utility — overrides the CSS variable default -->
|
|
401
365
|
<aside class="pa-layout__sidebar wr-25">
|
|
402
|
-
<!--
|
|
403
|
-
<!-- wr-* sets exact width, blocks resize -->
|
|
366
|
+
<!-- 25rem (250px) — utility class wins because :where() has 0 specificity -->
|
|
404
367
|
</aside>
|
|
405
368
|
|
|
406
|
-
<!--
|
|
407
|
-
<aside class="pa-layout__sidebar
|
|
408
|
-
|
|
409
|
-
|
|
369
|
+
<!-- Resizable sidebar — user-drag-to-resize via handle + JS -->
|
|
370
|
+
<aside class="pa-layout__sidebar">
|
|
371
|
+
<nav class="pa-sidebar__nav">
|
|
372
|
+
<!-- nav items -->
|
|
373
|
+
</nav>
|
|
374
|
+
<!-- Handle element; styled absolute on inline-end edge -->
|
|
375
|
+
<div class="pa-sidebar-resize"></div>
|
|
410
376
|
</aside>
|
|
411
377
|
|
|
378
|
+
<!-- Width bounds set by the CSS variables below — JS should respect these: -->
|
|
412
379
|
<!--
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
WIDTH UTILITY CLASSES (rem-based, 10px = 1rem):
|
|
420
|
-
- .wr-15 to .wr-25 - Fixed width (15rem to 25rem)
|
|
421
|
-
- .minwr-15 to .minwr-25 - Minimum width (allows resize above)
|
|
422
|
-
- .maxwr-15 to .maxwr-25 - Maximum width (limits resize)
|
|
423
|
-
|
|
424
|
-
NOTE: Fixed width (.wr-*) overrides both default and resizable width.
|
|
425
|
-
Use .minwr-* with --resizable to set a floor while allowing resize.
|
|
380
|
+
:root {
|
|
381
|
+
--pa-local-sidebar-width: 28.8rem; /* default */
|
|
382
|
+
--pa-local-sidebar-min-width: 18rem; /* floor */
|
|
383
|
+
--pa-local-sidebar-max-width: 50rem; /* ceiling */
|
|
384
|
+
}
|
|
426
385
|
-->
|
|
427
386
|
|
|
428
387
|
|
|
429
388
|
<!-- ================================
|
|
430
|
-
|
|
431
|
-
Three
|
|
389
|
+
BURGER MENU
|
|
390
|
+
Three <span>s stacked vertically; add .active to animate into an X.
|
|
391
|
+
RTL-aware — the translation direction flips under [dir="rtl"].
|
|
432
392
|
================================ -->
|
|
433
393
|
|
|
434
|
-
|
|
435
|
-
<
|
|
436
|
-
<
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
<!-- Hamburger Menu (burger) -->
|
|
440
|
-
<button class="pa-header__burger burger-menu" onclick="toggleSidebar()" aria-label="Toggle sidebar">
|
|
441
|
-
<span></span>
|
|
442
|
-
<span></span>
|
|
443
|
-
<span></span>
|
|
444
|
-
</button>
|
|
445
|
-
|
|
446
|
-
<!-- Brand -->
|
|
447
|
-
<div class="pa-header__brand">
|
|
448
|
-
<h1>Pure Admin</h1>
|
|
449
|
-
</div>
|
|
450
|
-
|
|
451
|
-
<!-- Left Navigation Links -->
|
|
452
|
-
<nav class="pa-header__nav pa-header__nav--start">
|
|
453
|
-
<ul>
|
|
454
|
-
<li><a href="/">Dashboard</a></li>
|
|
455
|
-
<li><a href="/components">Components</a></li>
|
|
456
|
-
<li><a href="/forms">Forms</a></li>
|
|
457
|
-
</ul>
|
|
458
|
-
</nav>
|
|
459
|
-
</div>
|
|
394
|
+
<button class="burger-menu" onclick="toggleSidebar()" aria-label="Toggle sidebar">
|
|
395
|
+
<span></span>
|
|
396
|
+
<span></span>
|
|
397
|
+
<span></span>
|
|
398
|
+
</button>
|
|
460
399
|
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
<!-- Right Section: Right Nav, Notifications, Profile (stays anchored right) -->
|
|
469
|
-
<div class="pa-header__end">
|
|
470
|
-
<!-- Right Navigation Links -->
|
|
471
|
-
<nav class="pa-header__nav pa-header__nav--end">
|
|
472
|
-
<ul>
|
|
473
|
-
<li><a href="/alerts">Alerts</a></li>
|
|
474
|
-
<li><a href="/tables">Tables</a></li>
|
|
475
|
-
</ul>
|
|
476
|
-
</nav>
|
|
477
|
-
|
|
478
|
-
<!-- Notification Bell -->
|
|
479
|
-
<div class="pa-notifications">
|
|
480
|
-
<button class="pa-notifications__btn" onclick="toggleNotifications()" aria-label="Notifications">
|
|
481
|
-
<span class="pa-notifications__icon">🔔</span>
|
|
482
|
-
<span class="pa-notifications__badge">3</span>
|
|
483
|
-
</button>
|
|
484
|
-
</div>
|
|
485
|
-
|
|
486
|
-
<!-- Profile Button -->
|
|
487
|
-
<button class="pa-header__profile-btn" onclick="toggleProfilePanel()" aria-label="User Profile">
|
|
488
|
-
<span class="pa-btn__icon">👤</span>
|
|
489
|
-
<span class="pa-header__profile-name">John Doe</span>
|
|
490
|
-
</button>
|
|
491
|
-
</div>
|
|
492
|
-
</div>
|
|
493
|
-
</nav>
|
|
400
|
+
<!--
|
|
401
|
+
- burger-menu (no .active) → three bars (☰) — sidebar visible / shown
|
|
402
|
+
- burger-menu.active → X shape — sidebar hidden / closed
|
|
403
|
+
Animation: ~150ms ease-out. Top/bottom bars rotate; middle bar fades.
|
|
404
|
+
The class .pa-header__burger is just a layout-position helper; the
|
|
405
|
+
visual animation lives on .burger-menu.
|
|
406
|
+
-->
|
|
494
407
|
|
|
495
408
|
|
|
496
409
|
<!-- ================================
|
|
497
|
-
JAVASCRIPT
|
|
410
|
+
JAVASCRIPT — SIDEBAR TOGGLE + SUBMENU
|
|
498
411
|
================================ -->
|
|
499
412
|
|
|
500
413
|
<script>
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
*/
|
|
414
|
+
// Toggle sidebar: mobile uses .sidebar-visible (overlay); desktop uses
|
|
415
|
+
// .sidebar-hidden (collapse / hide depending on --icon-collapse).
|
|
504
416
|
function toggleSidebar() {
|
|
505
417
|
const body = document.body;
|
|
506
|
-
const
|
|
418
|
+
const burger = document.querySelector('.burger-menu');
|
|
507
419
|
const isMobile = window.innerWidth <= 768;
|
|
508
420
|
|
|
509
421
|
if (isMobile) {
|
|
510
|
-
// Mobile: Toggle sidebar visibility
|
|
511
422
|
body.classList.toggle('sidebar-visible');
|
|
512
|
-
|
|
423
|
+
burger.classList.toggle('active');
|
|
513
424
|
} else {
|
|
514
|
-
// Desktop: Toggle sidebar hidden state
|
|
515
425
|
body.classList.toggle('sidebar-hidden');
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
localStorage.setItem('sidebar-hidden', isHidden);
|
|
426
|
+
burger.classList.toggle('active');
|
|
427
|
+
localStorage.setItem('sidebar-hidden', body.classList.contains('sidebar-hidden'));
|
|
519
428
|
}
|
|
520
429
|
}
|
|
521
|
-
</script>
|
|
522
430
|
|
|
523
|
-
|
|
524
|
-
<!-- ================================
|
|
525
|
-
JAVASCRIPT - SUBMENU TOGGLE
|
|
526
|
-
================================ -->
|
|
527
|
-
|
|
528
|
-
<script>
|
|
529
|
-
/**
|
|
530
|
-
* Toggle sidebar submenu open/closed
|
|
531
|
-
* Saves state to localStorage for persistence
|
|
532
|
-
*
|
|
533
|
-
* @param {HTMLElement} button - The .pa-sidebar__toggle button element
|
|
534
|
-
*/
|
|
431
|
+
// Toggle collapsible submenu — flips --open on the parent item + the <ul>.
|
|
535
432
|
function toggleSubmenu(button) {
|
|
536
433
|
const parentItem = button.closest('.pa-sidebar__item');
|
|
537
434
|
const submenu = parentItem.querySelector('.pa-sidebar__submenu');
|
|
538
|
-
|
|
539
435
|
if (!submenu) return;
|
|
540
436
|
|
|
541
437
|
const isOpen = parentItem.classList.contains('pa-sidebar__item--open');
|
|
542
|
-
|
|
543
|
-
// Toggle current submenu
|
|
544
438
|
if (isOpen) {
|
|
545
439
|
parentItem.classList.remove('pa-sidebar__item--open');
|
|
546
440
|
submenu.classList.remove('pa-sidebar__submenu--open');
|
|
@@ -549,157 +443,162 @@ function toggleSubmenu(button) {
|
|
|
549
443
|
submenu.classList.add('pa-sidebar__submenu--open');
|
|
550
444
|
}
|
|
551
445
|
|
|
552
|
-
//
|
|
553
|
-
const
|
|
554
|
-
localStorage.setItem(`submenu-${
|
|
446
|
+
// Optional: persist per-menu open state
|
|
447
|
+
const id = button.querySelector('.pa-sidebar__label').textContent.toLowerCase().replace(/\s+/g, '-');
|
|
448
|
+
localStorage.setItem(`submenu-${id}`, !isOpen ? 'open' : 'closed');
|
|
555
449
|
}
|
|
556
|
-
|
|
557
|
-
/**
|
|
558
|
-
* Restore submenu states from localStorage on page load (optional)
|
|
559
|
-
*/
|
|
560
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
561
|
-
document.querySelectorAll('.pa-sidebar__toggle').forEach(button => {
|
|
562
|
-
const label = button.querySelector('.pa-sidebar__label');
|
|
563
|
-
if (!label) return;
|
|
564
|
-
|
|
565
|
-
const submenuId = label.textContent.toLowerCase().replace(/\s+/g, '-');
|
|
566
|
-
const savedState = localStorage.getItem(`submenu-${submenuId}`);
|
|
567
|
-
|
|
568
|
-
if (savedState === 'open') {
|
|
569
|
-
const parentItem = button.closest('.pa-sidebar__item');
|
|
570
|
-
const submenu = parentItem.querySelector('.pa-sidebar__submenu');
|
|
571
|
-
if (submenu) {
|
|
572
|
-
parentItem.classList.add('pa-sidebar__item--open');
|
|
573
|
-
submenu.classList.add('pa-sidebar__submenu--open');
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
});
|
|
577
|
-
});
|
|
578
450
|
</script>
|
|
579
451
|
|
|
580
452
|
|
|
581
453
|
<!-- ================================
|
|
582
|
-
|
|
454
|
+
COMPONENT REFERENCE
|
|
583
455
|
================================ -->
|
|
584
456
|
|
|
585
457
|
<!--
|
|
586
|
-
LAYOUT
|
|
587
|
-
|
|
588
|
-
-
|
|
589
|
-
-
|
|
590
|
-
|
|
591
|
-
-
|
|
592
|
-
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
- .pa-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
- .pa-
|
|
605
|
-
- .
|
|
606
|
-
- .pa-
|
|
607
|
-
|
|
608
|
-
-
|
|
609
|
-
- .pa-
|
|
610
|
-
|
|
611
|
-
- .pa-
|
|
612
|
-
- .pa-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
-
|
|
616
|
-
- .
|
|
617
|
-
- .
|
|
618
|
-
- .pa-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
- .pa-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
-
|
|
630
|
-
- .pa-
|
|
631
|
-
- .pa-container
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
- .pa-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
- .pa-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
- .pa-
|
|
642
|
-
- .pa-
|
|
643
|
-
-
|
|
644
|
-
- .pa-
|
|
645
|
-
- .pa-
|
|
646
|
-
- .pa-
|
|
647
|
-
- .
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
-
|
|
652
|
-
|
|
653
|
-
- .pa-layout__sidebar--icon-collapse
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
-
|
|
660
|
-
-
|
|
661
|
-
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
- .
|
|
665
|
-
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
-
|
|
670
|
-
-
|
|
671
|
-
-
|
|
672
|
-
-
|
|
673
|
-
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
-
|
|
691
|
-
-
|
|
692
|
-
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
-
|
|
696
|
-
-
|
|
697
|
-
-
|
|
698
|
-
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
-
|
|
704
|
-
|
|
458
|
+
LAYOUT SHELL:
|
|
459
|
+
- .pa-navbar Fixed top bar (position: fixed, z-index $z-index-header).
|
|
460
|
+
- .pa-navbar__inner Inner flex container (padding, gap).
|
|
461
|
+
- .pa-layout Below navbar (margin-top: $header-height);
|
|
462
|
+
flex column, max-width 100%.
|
|
463
|
+
- .pa-layout__inner Flex row hosting sidebar + content.
|
|
464
|
+
- .pa-layout__content Wraps <main>; overflow-y: auto so the
|
|
465
|
+
content area is always scrollable.
|
|
466
|
+
- .pa-layout__main Main content region. Sets
|
|
467
|
+
container-type: inline-size — this is
|
|
468
|
+
WHY responsive grid classes
|
|
469
|
+
(pa-col-sm-*, -md-*, etc.) work inside
|
|
470
|
+
the layout automatically.
|
|
471
|
+
- .pa-layout__footer Page footer; flex row with start/center/end
|
|
472
|
+
sections (responsive — center hidden on mobile).
|
|
473
|
+
|
|
474
|
+
FOOTER SECTIONS:
|
|
475
|
+
- .pa-footer__start Anchored to inline-start (copyright, etc.)
|
|
476
|
+
- .pa-footer__center Flexible middle
|
|
477
|
+
- .pa-footer__end Anchored to inline-end (version info, links)
|
|
478
|
+
- .pa-footer__end--vertical Stack end items vertically (flex-column)
|
|
479
|
+
|
|
480
|
+
BODY-LEVEL FLAGS (orthogonal — any combination is valid):
|
|
481
|
+
- .pa-layout--sticky Fixed-viewport mode: body overflow: hidden;
|
|
482
|
+
.pa-layout is 100vh; content wrapper scrolls.
|
|
483
|
+
- .pa-container-sm / -md / -lg / -xl / -2xl
|
|
484
|
+
Constrains .pa-navbar AND .pa-layout max-width
|
|
485
|
+
to 768 / 1024 / 1280 / 1600 / 1920 px
|
|
486
|
+
respectively. Navbar and layout both get
|
|
487
|
+
margin-inline: auto to stay centred.
|
|
488
|
+
- .sidebar-hidden Desktop sidebar collapse / hide state.
|
|
489
|
+
- .sidebar-visible Mobile sidebar overlay visible.
|
|
490
|
+
- .pa-sidebar-resizing Set by the resize JS during drag (locks
|
|
491
|
+
text selection, forces ew-resize cursor).
|
|
492
|
+
|
|
493
|
+
NAVBAR HEADER SECTIONS (inside .pa-navbar__inner):
|
|
494
|
+
- .pa-header__start Start-anchored section; flex, gap.
|
|
495
|
+
- .pa-header__center Flexible middle (flex: 1; min-width: 0).
|
|
496
|
+
- .pa-header__end End-anchored section; margin-inline-start: auto.
|
|
497
|
+
|
|
498
|
+
NAVBAR ELEMENTS (inside header sections):
|
|
499
|
+
- .pa-header__burger Wrapper for the burger-menu button.
|
|
500
|
+
- .burger-menu The animated three-bar button itself.
|
|
501
|
+
- .burger-menu.active X-shape state (bars rotate + middle fades).
|
|
502
|
+
- .pa-header__brand Logo / brand area; h1 styled automatically.
|
|
503
|
+
- .pa-header__nav Nav container; auto-styles direct
|
|
504
|
+
ul > li > a descendants (no classes needed
|
|
505
|
+
on list items / anchors).
|
|
506
|
+
- .pa-header__nav--start Organisational placeholder (empty SCSS block).
|
|
507
|
+
- .pa-header__nav--end Organisational placeholder (empty SCSS block).
|
|
508
|
+
- .pa-header__nav-item Explicit li class (same behaviour as bare <li>).
|
|
509
|
+
- .pa-header__nav-item--has-dropdown
|
|
510
|
+
Parent li that reveals a child .pa-header__dropdown
|
|
511
|
+
on hover. Uses position: static so the
|
|
512
|
+
dropdown positions relative to the navbar.
|
|
513
|
+
- .pa-header__nav-link Optional anchor class (flex + gap for icon+text).
|
|
514
|
+
- .pa-header__dropdown Hover-dropdown <ul> (absolute; card-bg;
|
|
515
|
+
box-shadow; z-index 1100).
|
|
516
|
+
- .pa-header__dropdown--level2 Nested dropdown shifted to the side.
|
|
517
|
+
- .pa-header__title Centre-section page title with ellipsis h2.
|
|
518
|
+
- .pa-header__profile-btn Right-side profile button (flex-shrink: 0).
|
|
519
|
+
- .theme-switcher Inline label + select styled for the header.
|
|
520
|
+
|
|
521
|
+
SIDEBAR:
|
|
522
|
+
- .pa-layout__sidebar Sidebar column; width comes from
|
|
523
|
+
--pa-local-sidebar-width via :where()
|
|
524
|
+
so utility classes override it.
|
|
525
|
+
- .pa-layout__sidebar--icon-collapse Collapses to a narrow icon bar under
|
|
526
|
+
.sidebar-hidden; hover reveals labels
|
|
527
|
+
+ submenus as flyouts.
|
|
528
|
+
(Expanded when NOT .sidebar-hidden.)
|
|
529
|
+
|
|
530
|
+
SIDEBAR BEM BLOCK:
|
|
531
|
+
- .pa-sidebar__nav <nav> wrapper for the menu ul.
|
|
532
|
+
- .pa-sidebar__item <li> menu item.
|
|
533
|
+
- .pa-sidebar__item--open Submenu-open state — set by JS when
|
|
534
|
+
toggling a .pa-sidebar__toggle parent.
|
|
535
|
+
Rotates the chevron 90° (−90° in RTL).
|
|
536
|
+
- .pa-sidebar__link Leaf link (flex: icon + label, optional hover).
|
|
537
|
+
- .pa-sidebar__link--active Active leaf state — accent colour +
|
|
538
|
+
accent border-inline-end accent bar.
|
|
539
|
+
- .pa-sidebar__toggle Collapsible parent (<button>, not <a>).
|
|
540
|
+
- .pa-sidebar__toggle--active Active collapsible state (kept open manually).
|
|
541
|
+
- .pa-sidebar__icon Fixed-width icon slot ($sidebar-icon-size).
|
|
542
|
+
- .pa-sidebar__label Text label (flex: 1; ellipsis on overflow).
|
|
543
|
+
- .pa-sidebar__chevron Right-pointing indicator; rotates on --open.
|
|
544
|
+
- .pa-sidebar__submenu Nested <ul>; hidden by default.
|
|
545
|
+
- .pa-sidebar__submenu--open Visible state.
|
|
546
|
+
|
|
547
|
+
RESIZE MECHANISM:
|
|
548
|
+
- .pa-sidebar-resize Handle element inside the sidebar
|
|
549
|
+
(absolute-positioned on the inline-end edge).
|
|
550
|
+
- .pa-sidebar-resize--active Active state (highlighted during drag).
|
|
551
|
+
- --pa-local-sidebar-width runtime width; JS rewrites this on drag.
|
|
552
|
+
- --pa-local-sidebar-min-width floor (default 18rem).
|
|
553
|
+
- --pa-local-sidebar-max-width ceiling (default 50rem).
|
|
554
|
+
- body.pa-sidebar-resizing set by JS during drag to disable text
|
|
555
|
+
selection + force ew-resize cursor.
|
|
556
|
+
(NO .pa-layout__sidebar--resizable or --sticky — these were never in
|
|
557
|
+
SCSS. The older snippet advertised them; the real knobs are the CSS
|
|
558
|
+
variable + handle element above.)
|
|
559
|
+
|
|
560
|
+
RESPONSIVE BEHAVIOUR (built in):
|
|
561
|
+
- Below $mobile-breakpoint (768px):
|
|
562
|
+
- .pa-header__nav hides entirely.
|
|
563
|
+
- Theme-switcher label hides.
|
|
564
|
+
- body:not(.sidebar-visible) hides the sidebar (width: 0).
|
|
565
|
+
- .sidebar-visible renders sidebar as a fixed-position overlay
|
|
566
|
+
($mobile-sidebar-width) with a backdrop::before.
|
|
567
|
+
- Footer wraps, centre section hidden.
|
|
568
|
+
- Between $tablet-breakpoint-min and $tablet-breakpoint:
|
|
569
|
+
- Sidebar width shrinks to $sidebar-width-tablet.
|
|
570
|
+
- Sidebar link padding tightens.
|
|
571
|
+
|
|
572
|
+
STRUCTURE PATTERNS:
|
|
573
|
+
|
|
574
|
+
Minimal app shell:
|
|
575
|
+
<body class="pa-layout--sticky">
|
|
576
|
+
<nav class="pa-navbar"><div class="pa-navbar__inner">
|
|
577
|
+
<div class="pa-header__start">…</div>
|
|
578
|
+
<div class="pa-header__center"><div class="pa-header__title"><h2>Page</h2></div></div>
|
|
579
|
+
<div class="pa-header__end">…</div>
|
|
580
|
+
</div></nav>
|
|
581
|
+
|
|
582
|
+
<div class="pa-layout">
|
|
583
|
+
<div class="pa-layout__inner">
|
|
584
|
+
<aside class="pa-layout__sidebar">…</aside>
|
|
585
|
+
<div class="pa-layout__content">
|
|
586
|
+
<main class="pa-layout__main">…</main>
|
|
587
|
+
</div>
|
|
588
|
+
</div>
|
|
589
|
+
<footer class="pa-layout__footer">…</footer>
|
|
590
|
+
</div>
|
|
591
|
+
</body>
|
|
592
|
+
|
|
593
|
+
Constrained-width layout:
|
|
594
|
+
<body class="pa-container-lg">
|
|
595
|
+
…navbar + layout… (both limited to 1280px, centred)
|
|
596
|
+
</body>
|
|
597
|
+
|
|
598
|
+
Resizable sidebar:
|
|
599
|
+
<aside class="pa-layout__sidebar">
|
|
600
|
+
<nav class="pa-sidebar__nav">…</nav>
|
|
601
|
+
<div class="pa-sidebar-resize"></div>
|
|
602
|
+
</aside>
|
|
603
|
+
<!-- + JS that updates --pa-local-sidebar-width on drag -->
|
|
705
604
|
-->
|