picocrank 1.21.4 → 1.22.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.
@@ -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
  })