picocrank 1.21.5 → 1.22.1

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.
@@ -10,103 +10,132 @@
10
10
  </Section>
11
11
 
12
12
  <Section title="Header" subtitle="Branding, search, and top navigation">
13
- <dl>
14
- <dt>Logo and title</dt>
15
- <dd>
16
- <label class="page-structure-control">
17
- <input
18
- type="checkbox"
19
- :checked="brandingEnabled"
20
- @change="toggleBrandingEnabled"
21
- />
22
- <span>Show logo and title in the header</span>
23
- </label>
24
- </dd>
25
-
26
- <dt>QuickSearch</dt>
27
- <dd>
28
- <label class="page-structure-control">
29
- <input
30
- type="checkbox"
31
- :checked="quickSearchEnabled"
32
- @change="toggleQuickSearchEnabled"
33
- />
34
- <span>Show QuickSearch in the header toolbar</span>
35
- </label>
36
- <p class="subtle">
37
- On narrow screens it collapses to a search button that opens search in an overlay.
38
- </p>
39
- </dd>
40
-
41
- <dt>Top bar</dt>
42
- <dd>
43
- <label class="page-structure-control">
44
- <input
45
- type="checkbox"
46
- :checked="topBarEnabled"
47
- @change="toggleTopBarEnabled"
13
+ <FormLayout @submit.prevent>
14
+ <FormField label="Logo and title" fake>
15
+ <RadioGroup
16
+ name="ps-branding"
17
+ variant="boolean"
18
+ aria-label="Logo and title"
19
+ :model-value="brandingEnabled"
20
+ :options="showHideOptions"
21
+ @update:model-value="setBrandingEnabled"
22
+ />
23
+ </FormField>
24
+
25
+ <FormField label="QuickSearch" fake>
26
+ <RadioGroup
27
+ name="ps-quicksearch"
28
+ variant="boolean"
29
+ aria-label="QuickSearch"
30
+ :model-value="quickSearchEnabled"
31
+ :options="showHideOptions"
32
+ @update:model-value="setQuickSearchEnabled"
33
+ />
34
+ </FormField>
35
+
36
+ <FormField label="Dummy background search" fake :disabled="!quickSearchEnabled">
37
+ <div>
38
+ <RadioGroup
39
+ name="ps-dummy-search"
40
+ variant="boolean"
41
+ aria-label="Dummy background search"
42
+ :model-value="dummySearchFetchEnabled"
43
+ :options="onOffOptions"
44
+ :disabled="!quickSearchEnabled"
45
+ @update:model-value="setDummySearchFetchEnabled"
48
46
  />
49
- <span>Show horizontal navigation links below the header</span>
50
- </label>
51
- <p class="subtle">
52
- On narrow screens: if both are on, the sidebar takes precedence and the top bar is hidden.
53
- If only the top bar is on, Header collapses it into a mobile sidebar automatically.
54
- </p>
55
- </dd>
56
-
57
- <dt>Breadcrumbs</dt>
58
- <dd>
59
- <label class="page-structure-control">
60
- <input
61
- type="checkbox"
62
- :checked="breadcrumbsEnabled"
63
- @change="toggleBreadcrumbsEnabled"
47
+ <p class="subtle">
48
+ Turns on QuickSearch’s background-fetch loading UI. Local matches still
49
+ appear immediately while the dummy request runs.
50
+ </p>
51
+ </div>
52
+ </FormField>
53
+
54
+ <FormField label="Dark/Light mode button" fake>
55
+ <RadioGroup
56
+ name="ps-theme-toggle"
57
+ variant="boolean"
58
+ aria-label="Dark/Light mode button"
59
+ :model-value="themeToggleEnabled"
60
+ :options="showHideOptions"
61
+ @update:model-value="setThemeToggleEnabled"
62
+ />
63
+ </FormField>
64
+
65
+ <FormField label="Top bar" fake>
66
+ <div>
67
+ <RadioGroup
68
+ name="ps-topbar"
69
+ variant="boolean"
70
+ aria-label="Top bar"
71
+ :model-value="topBarEnabled"
72
+ :options="showHideOptions"
73
+ @update:model-value="setTopBarEnabled"
64
74
  />
65
- <span>Show route breadcrumbs in the header</span>
66
- </label>
67
- </dd>
68
- </dl>
75
+ <p class="subtle">
76
+ On narrow screens: if both are on, the sidebar takes precedence and the top bar is hidden.
77
+ If only the top bar is on, Header collapses it into a mobile sidebar automatically.
78
+ </p>
79
+ </div>
80
+ </FormField>
81
+
82
+ <FormField label="Breadcrumbs" fake>
83
+ <RadioGroup
84
+ name="ps-breadcrumbs"
85
+ variant="boolean"
86
+ aria-label="Breadcrumbs"
87
+ :model-value="breadcrumbsEnabled"
88
+ :options="showHideOptions"
89
+ @update:model-value="setBreadcrumbsEnabled"
90
+ />
91
+ </FormField>
92
+ </FormLayout>
69
93
  </Section>
70
94
 
71
95
  <Section title="Sidebar" subtitle="Primary navigation panel">
72
- <dl>
73
- <dt>Sidebar navigation</dt>
74
- <dd>
75
- <label class="page-structure-control">
76
- <input
77
- type="checkbox"
78
- :checked="sidebarEnabled"
79
- @change="toggleSidebarEnabled"
96
+ <FormLayout @submit.prevent>
97
+ <FormField label="Sidebar navigation" fake>
98
+ <div>
99
+ <RadioGroup
100
+ name="ps-sidebar"
101
+ variant="boolean"
102
+ aria-label="Sidebar navigation"
103
+ :model-value="sidebarEnabled"
104
+ :options="showHideOptions"
105
+ @update:model-value="setSidebarEnabled"
80
106
  />
81
- <span>Show the sidebar navigation panel</span>
82
- </label>
83
- <p class="subtle">
84
- When enabled, use the menu button in the header to open and pin the sidebar.
85
- </p>
86
- </dd>
87
-
88
- <dt>Example link states</dt>
89
- <dd>
90
- <label class="page-structure-control">
91
- <input
92
- type="checkbox"
93
- :checked="exampleLinksEnabled"
94
- @change="toggleExampleLinks"
107
+ <p class="subtle">
108
+ When enabled, use the menu button in the header to open and pin the sidebar.
109
+ </p>
110
+ </div>
111
+ </FormField>
112
+
113
+ <FormField label="Example link states" fake>
114
+ <div>
115
+ <RadioGroup
116
+ name="ps-example-links"
117
+ variant="boolean"
118
+ aria-label="Example link states"
119
+ :model-value="exampleLinksEnabled"
120
+ :options="onOffOptions"
121
+ @update:model-value="setExampleLinks"
95
122
  />
96
- <span>Add example links that demonstrate indicator, count, and disabled states</span>
97
- </label>
98
- <p class="subtle">
99
- Adds a “Link states” section to the sidebar with an attention indicator,
100
- a notification count badge, and a disabled item.
101
- </p>
102
- </dd>
103
- </dl>
123
+ <p class="subtle">
124
+ Adds a “Link states” section to the sidebar with an attention indicator,
125
+ a notification count badge, and a disabled item.
126
+ </p>
127
+ </div>
128
+ </FormField>
129
+ </FormLayout>
104
130
  </Section>
105
131
  </template>
106
132
 
107
133
  <script setup>
108
134
  import { inject, ref, onBeforeUnmount } from 'vue'
109
135
  import Section from '../components/Section.vue'
136
+ import FormLayout from '../components/FormLayout.vue'
137
+ import FormField from '../components/FormField.vue'
138
+ import RadioGroup from '../components/RadioGroup.vue'
110
139
  import {
111
140
  Notification01Icon,
112
141
  Alert02Icon,
@@ -121,12 +150,26 @@ const EXAMPLE_LINK_NAMES = [
121
150
  'example-disabled',
122
151
  ]
123
152
 
153
+ const showHideOptions = [
154
+ { label: 'Shown', value: true },
155
+ { label: 'Hidden', value: false },
156
+ ]
157
+
158
+ const onOffOptions = [
159
+ { label: 'On', value: true },
160
+ { label: 'Off', value: false },
161
+ ]
162
+
124
163
  const sidebarEnabled = inject('sidebarEnabled')
125
164
  const toggleSidebarEnabled = inject('toggleSidebarEnabled')
126
165
  const brandingEnabled = inject('brandingEnabled')
127
166
  const toggleBrandingEnabled = inject('toggleBrandingEnabled')
128
167
  const quickSearchEnabled = inject('quickSearchEnabled')
129
168
  const toggleQuickSearchEnabled = inject('toggleQuickSearchEnabled')
169
+ const dummySearchFetchEnabled = inject('dummySearchFetchEnabled')
170
+ const toggleDummySearchFetchEnabled = inject('toggleDummySearchFetchEnabled')
171
+ const themeToggleEnabled = inject('themeToggleEnabled')
172
+ const toggleThemeToggleEnabled = inject('toggleThemeToggleEnabled')
130
173
  const topBarEnabled = inject('topBarEnabled')
131
174
  const toggleTopBarEnabled = inject('toggleTopBarEnabled')
132
175
  const breadcrumbsEnabled = inject('breadcrumbsEnabled')
@@ -135,6 +178,40 @@ const navigation = inject('navigation', null)
135
178
 
136
179
  const exampleLinksEnabled = ref(false)
137
180
 
181
+ function setFlag(flag, toggle, want) {
182
+ if (flag.value !== want) {
183
+ toggle()
184
+ }
185
+ }
186
+
187
+ function setBrandingEnabled(want) {
188
+ setFlag(brandingEnabled, toggleBrandingEnabled, want)
189
+ }
190
+
191
+ function setQuickSearchEnabled(want) {
192
+ setFlag(quickSearchEnabled, toggleQuickSearchEnabled, want)
193
+ }
194
+
195
+ function setDummySearchFetchEnabled(want) {
196
+ setFlag(dummySearchFetchEnabled, toggleDummySearchFetchEnabled, want)
197
+ }
198
+
199
+ function setThemeToggleEnabled(want) {
200
+ setFlag(themeToggleEnabled, toggleThemeToggleEnabled, want)
201
+ }
202
+
203
+ function setTopBarEnabled(want) {
204
+ setFlag(topBarEnabled, toggleTopBarEnabled, want)
205
+ }
206
+
207
+ function setBreadcrumbsEnabled(want) {
208
+ setFlag(breadcrumbsEnabled, toggleBreadcrumbsEnabled, want)
209
+ }
210
+
211
+ function setSidebarEnabled(want) {
212
+ setFlag(sidebarEnabled, toggleSidebarEnabled, want)
213
+ }
214
+
138
215
  function removeExampleLinks() {
139
216
  if (!navigation) {
140
217
  return
@@ -178,9 +255,12 @@ function addExampleLinks() {
178
255
  })
179
256
  }
180
257
 
181
- function toggleExampleLinks() {
182
- exampleLinksEnabled.value = !exampleLinksEnabled.value
183
- if (exampleLinksEnabled.value) {
258
+ function setExampleLinks(want) {
259
+ if (exampleLinksEnabled.value === want) {
260
+ return
261
+ }
262
+ exampleLinksEnabled.value = want
263
+ if (want) {
184
264
  if (!sidebarEnabled.value) {
185
265
  toggleSidebarEnabled()
186
266
  }
@@ -198,14 +278,7 @@ onBeforeUnmount(() => {
198
278
  </script>
199
279
 
200
280
  <style scoped>
201
- .page-structure-control {
202
- display: flex;
203
- align-items: center;
204
- gap: 0.5rem;
205
- cursor: pointer;
206
- }
207
-
208
- .page-structure-control + .subtle {
281
+ .subtle {
209
282
  margin-top: 0.5rem;
210
283
  }
211
284
  </style>
@@ -30,6 +30,7 @@
30
30
 
31
31
  <script setup>
32
32
  import { ref, onMounted } from 'vue'
33
+ import { getExampleTableRows } from '../data/examplePeople.js'
33
34
 
34
35
  const headers = ref([
35
36
  { key: "name", label: "Name", sortable: true, hidden: false, width: "20%" },
@@ -40,81 +41,6 @@
40
41
  const data = ref([])
41
42
 
42
43
  onMounted(() => {
43
- data.value = [
44
- { name: "Alice", age: 30, city: "New York", foo: "bar" },
45
- { name: "Bob", age: 25, city: "Los Angeles" },
46
- { name: "Charlie", age: 35, city: "Chicago" },
47
- { name: "David", age: 28, city: "Houston" },
48
- { name: "Eve", age: 22, city: "Phoenix" },
49
- { name: "Frank", age: 40, city: "Philadelphia" },
50
- { name: "Grace", age: 29, city: "San Antonio" },
51
- { name: "Hannah", age: 32, city: "San Diego" },
52
- { name: "Ian", age: 27, city: "Dallas" },
53
- { name: "Jack", age: 31, city: "San Jose" },
54
- { name: "Kathy", age: 26, city: "Austin" },
55
- { name: "Leo", age: 33, city: "Jacksonville" },
56
- { name: "Mia", age: 24, city: "Fort Worth" },
57
- { name: "Nina", age: 38, city: "Columbus" },
58
- { name: "Oscar", age: 36, city: "Charlotte" },
59
- { name: "Paul", age: 34, city: "San Francisco" },
60
- { name: "Quinn", age: 23, city: "Indianapolis" },
61
- { name: "Rita", age: 37, city: "Seattle" },
62
- { name: "Sam", age: 39, city: "Denver" },
63
- { name: "Tina", age: 21, city: "Washington D.C." },
64
- { name: "Uma", age: 28, city: "Miami" },
65
- { name: "Victor", age: 30, city: "Portland" },
66
- { name: "Wendy", age: 29, city: "Nashville" },
67
- { name: "Xavier", age: 31, city: "Oklahoma City" },
68
- { name: "Yara", age: 27, city: "Tampa" },
69
- { name: "Zane", age: 32, city: "Albuquerque" },
70
- { name: "Ava", age: 26, city: "Las Vegas" },
71
- { name: "Ben", age: 33, city: "New Orleans" },
72
- { name: "Cara", age: 25, city: "San Francisco" },
73
- { name: "Drew", age: 34, city: "Seattle" },
74
- { name: "Ethan", age: 28, city: "Denver" },
75
- { name: "Fiona", age: 30, city: "Washington D.C." },
76
- { name: "George", age: 29, city: "Miami" },
77
- { name: "Hannah", age: 32, city: "San Diego" },
78
- { name: "Ian", age: 27, city: "Dallas" },
79
- { name: "Jack", age: 31, city: "San Jose" },
80
- { name: "Kathy", age: 26, city: "Austin" },
81
- { name: "Leo", age: 33, city: "Jacksonville" },
82
- { name: "Mia", age: 24, city: "Fort Worth" },
83
- { name: "Nina", age: 38, city: "Columbus" },
84
- { name: "Oscar", age: 36, city: "Charlotte" },
85
- { name: "Paul", age: 34, city: "San Francisco" },
86
- { name: "Quinn", age: 23, city: "Indianapolis" },
87
- { name: "Rita", age: 37, city: "Seattle" },
88
- { name: "Sam", age: 39, city: "Denver" },
89
- { name: "Tina", age: 21, city: "Washington D.C." },
90
- { name: "Uma", age: 28, city: "Miami" },
91
- { name: "Victor", age: 30, city: "Portland" },
92
- { name: "Wendy", age: 29, city: "Nashville" },
93
- { name: "Xavier", age: 31, city: "Oklahoma City" },
94
- { name: "Yara", age: 27, city: "Tampa" },
95
- { name: "Zane", age: 32, city: "Albuquerque" },
96
- { name: "Ava", age: 26, city: "Las Vegas" },
97
- { name: "Ben", age: 33, city: "New Orleans" },
98
- { name: "Cara", age: 25, city: "San Francisco" },
99
- { name: "Drew", age: 34, city: "Seattle" },
100
- { name: "Ethan", age: 28, city: "Denver" },
101
- { name: "Fiona", age: 30, city: "Washington D.C." },
102
- { name: "George", age: 29, city: "Miami" },
103
- { name: "Hannah", age: 32, city: "San Diego" },
104
- { name: "Ian", age: 27, city: "Dallas" },
105
- { name: "Jack", age: 31, city: "San Jose" },
106
- { name: "Kathy", age: 26, city: "Austin" },
107
- { name: "Leo", age: 33, city: "Jacksonville" },
108
- { name: "Mia", age: 24, city: "Fort Worth" },
109
- { name: "Nina", age: 38, city: "Columbus" },
110
- { name: "Oscar", age: 36, city: "Charlotte" },
111
- { name: "Paul", age: 34, city: "San Francisco" },
112
- { name: "Quinn", age: 23, city: "Indianapolis" },
113
- { name: "Rita", age: 37, city: "Seattle" },
114
- { name: "Sam", age: 39, city: "Denver" },
115
- { name: "Tina", age: 21, city: "Washington D.C." },
116
- { name: "Uma", age: 28, city: "Miami" },
117
- { name: "Victor", age: 30, city: "Portland" },
118
- ]
44
+ data.value = getExampleTableRows()
119
45
  })
120
46
  </script>
@@ -0,0 +1,172 @@
1
+ <template>
2
+ <Section
3
+ title="Theme Switcher"
4
+ subtitle="Drop-in themes layered on Femtocrank — not part of the Vite CSS/JS bundle"
5
+ >
6
+ <p>
7
+ Themes live under <code>public/themes/&lt;name&gt;/theme.css</code>. Drop a folder
8
+ in and restart the dev server (or rebuild); PicoCrank discovers themes from
9
+ <code>index.json</code> and applies them with <code>useCustomTheme()</code>.
10
+ </p>
11
+
12
+ <label class="theme-picker">
13
+ <span>Active theme</span>
14
+ <select :value="themePreference" @change="onThemeChange">
15
+ <option value="">Default (Femtocrank)</option>
16
+ <option
17
+ v-for="name in availableThemes"
18
+ :key="name"
19
+ :value="name"
20
+ >
21
+ {{ name }}
22
+ </option>
23
+ </select>
24
+ </label>
25
+
26
+ <p v-if="availableThemes.length === 0" class="subtle">
27
+ No drop-in themes found. Add <code>public/themes/&lt;name&gt;/theme.css</code>
28
+ and restart Vite.
29
+ </p>
30
+ <p v-else class="subtle">
31
+ Preference is stored in localStorage and applies across the whole examples site.
32
+ Light/dark mode (header sun/moon) is separate from drop-in themes.
33
+ </p>
34
+ </Section>
35
+
36
+ <Section title="Buttons" subtitle="Default and karma variants">
37
+ <div role="toolbar" class="preview-row">
38
+ <button type="button">Default</button>
39
+ <button type="button" class="neutral">Neutral</button>
40
+ <button type="button" class="good">Good</button>
41
+ <button type="button" class="bad">Bad</button>
42
+ <button type="button" class="warning">Warning</button>
43
+ <button type="button" disabled>Disabled</button>
44
+ </div>
45
+ </Section>
46
+
47
+ <Section title="Notifications" subtitle="Block-level karma status">
48
+ <div class="notification show good" role="status">
49
+ <strong>GOOD:</strong> Theme tokens are applying to karma backgrounds.
50
+ </div>
51
+ <div class="notification show bad" role="status">
52
+ <strong>BAD:</strong> Check contrast on error surfaces.
53
+ </div>
54
+ <div class="notification show warning" role="status">
55
+ <strong>WARNING:</strong> Accent and border colors should stay readable.
56
+ </div>
57
+ <p class="fg-success show inline-notification">
58
+ <strong>SUCCESS:</strong> Inline notification with foreground karma.
59
+ </p>
60
+ <p class="fg-warning show inline-notification">
61
+ <strong>WARNING:</strong> Another inline status line.
62
+ </p>
63
+ </Section>
64
+
65
+ <Section title="Form controls" subtitle="Inputs inherit theme variables">
66
+ <FormLayout @submit.prevent>
67
+ <FormField label="Name" for="theme-preview-name">
68
+ <input id="theme-preview-name" type="text" value="PicoCrank" />
69
+ </FormField>
70
+ <FormField label="Status" for="theme-preview-status">
71
+ <select id="theme-preview-status">
72
+ <option>Ready</option>
73
+ <option>Busy</option>
74
+ </select>
75
+ </FormField>
76
+ <FormField label="Notes" for="theme-preview-notes">
77
+ <textarea id="theme-preview-notes" rows="3">Override Femtocrank tokens in theme.css</textarea>
78
+ </FormField>
79
+ <template #actions>
80
+ <button type="submit" class="good">Save</button>
81
+ <button type="button" class="neutral">Cancel</button>
82
+ </template>
83
+ </FormLayout>
84
+ </Section>
85
+
86
+ <Section title="Content chrome" subtitle="Sections, links, and muted text">
87
+ <p>
88
+ Body copy should pick up <code>--text-color</code>.
89
+ <a href="#">Sample link</a> uses the theme link color.
90
+ </p>
91
+ <p class="subtle">
92
+ Muted / subtle text uses secondary contrast — useful for captions and hints.
93
+ </p>
94
+ <table class="preview-table">
95
+ <thead>
96
+ <tr>
97
+ <th>Token</th>
98
+ <th>Role</th>
99
+ </tr>
100
+ </thead>
101
+ <tbody>
102
+ <tr>
103
+ <td><code>--border-color</code></td>
104
+ <td>Borders and rules</td>
105
+ </tr>
106
+ <tr>
107
+ <td><code>--standout-bg-color</code></td>
108
+ <td>Raised / standout surfaces</td>
109
+ </tr>
110
+ <tr>
111
+ <td><code>--karma-*</code></td>
112
+ <td>Status backgrounds and accents</td>
113
+ </tr>
114
+ </tbody>
115
+ </table>
116
+ </Section>
117
+ </template>
118
+
119
+ <script setup>
120
+ import Section from '../components/Section.vue'
121
+ import FormLayout from '../components/FormLayout.vue'
122
+ import FormField from '../components/FormField.vue'
123
+ import { useCustomTheme } from '../composables/useCustomTheme.js'
124
+
125
+ const { availableThemes, themePreference, setTheme, discoverThemes } = useCustomTheme()
126
+
127
+ discoverThemes()
128
+
129
+ function onThemeChange(event) {
130
+ setTheme(event.target.value)
131
+ }
132
+ </script>
133
+
134
+ <style scoped>
135
+ .theme-picker {
136
+ display: flex;
137
+ flex-wrap: wrap;
138
+ align-items: center;
139
+ gap: 0.75rem;
140
+ margin: 1rem 0;
141
+ }
142
+
143
+ .theme-picker select {
144
+ min-width: 14rem;
145
+ }
146
+
147
+ .preview-row {
148
+ display: flex;
149
+ flex-wrap: wrap;
150
+ gap: 0.5rem;
151
+ }
152
+
153
+ .preview-table {
154
+ width: 100%;
155
+ border-collapse: collapse;
156
+ }
157
+
158
+ .preview-table th,
159
+ .preview-table td {
160
+ text-align: left;
161
+ padding: 0.5rem 0.75rem;
162
+ border-bottom: 1px solid var(--border-color, #d7d7d7);
163
+ }
164
+
165
+ .notification {
166
+ margin-bottom: 0.5rem;
167
+ }
168
+
169
+ .inline-notification {
170
+ margin: 0.5rem 0;
171
+ }
172
+ </style>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <Section
3
+ title="User details"
4
+ subtitle="Signed-in account for this example app"
5
+ >
6
+ <p class="subtle">
7
+ This is a minimal profile page used by the header username control.
8
+ </p>
9
+
10
+ <dl>
11
+ <dt>Display name</dt>
12
+ <dd>{{ user.displayName }}</dd>
13
+
14
+ <dt>Username</dt>
15
+ <dd>{{ user.username }}</dd>
16
+
17
+ <dt>Email</dt>
18
+ <dd><a :href="`mailto:${user.email}`">{{ user.email }}</a></dd>
19
+
20
+ <dt>Role</dt>
21
+ <dd>{{ user.role }}</dd>
22
+
23
+ <dt>Status</dt>
24
+ <dd><span class="tag good">{{ user.status }}</span></dd>
25
+ </dl>
26
+ </Section>
27
+ </template>
28
+
29
+ <script setup>
30
+ import Section from '../components/Section.vue'
31
+
32
+ const user = {
33
+ displayName: 'Guest User',
34
+ username: 'guest',
35
+ email: 'guest@example.com',
36
+ role: 'Viewer',
37
+ status: 'Active',
38
+ }
39
+ </script>
@@ -110,6 +110,12 @@ const { show: showPopup } = useNotificationPopups()
110
110
  const welcomeNavigation = ref(null)
111
111
 
112
112
  const popularExamples = [
113
+ {
114
+ name: 'ThemePreview',
115
+ category: 'Layouts',
116
+ label: 'Theme Switcher',
117
+ description: 'Switch drop-in themes live',
118
+ },
113
119
  {
114
120
  name: 'TableExample',
115
121
  category: 'Data display',
@@ -128,12 +134,6 @@ const popularExamples = [
128
134
  label: 'Buttons',
129
135
  description: 'Variants, toolbars, and form actions',
130
136
  },
131
- {
132
- name: 'StatusExample',
133
- category: 'Feedback',
134
- label: 'Status',
135
- description: 'Inline messages and notification popups',
136
- },
137
137
  ]
138
138
 
139
139
  function showWelcomeToast() {
@@ -156,6 +156,9 @@ onMounted(() => {
156
156
  nav.addRouterLink('PageStructure', 'Page structure', {
157
157
  description: 'Sidebar, header, QuickSearch, and breadcrumbs',
158
158
  })
159
+ nav.addRouterLink('ThemePreview', 'Theme Switcher', {
160
+ description: 'Drop-in themes on Femtocrank',
161
+ })
159
162
  nav.addRouterLink('TableExample', 'Table', {
160
163
  description: 'Lists with sorting and pagination',
161
164
  })