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.
- package/package.json +8 -8
- package/public/themes/README.md +29 -0
- package/public/themes/catppuccin/theme.css +195 -0
- package/public/themes/dracula/theme.css +181 -0
- package/public/themes/index.json +7 -0
- package/public/themes/waffles/theme.css +143 -0
- package/router.js +20 -0
- package/styles/dark-theme.css +15 -1
- package/styles.css +18 -2
- package/vite.config.js +57 -0
- package/vue/components/CheckGroup.vue +156 -0
- package/vue/components/FormField.vue +14 -2
- package/vue/components/Header.vue +164 -35
- package/vue/components/QuickSearch.vue +325 -348
- package/vue/components/RadioGroup.vue +191 -0
- package/vue/components/Sidebar.vue +226 -262
- package/vue/components/SidebarNavLink.vue +161 -0
- package/vue/composables/useCustomTheme.js +162 -0
- package/vue/composables/useTheme.js +43 -10
- package/vue/data/examplePeople.js +45 -0
- package/vue/views/App.vue +85 -15
- package/vue/views/FormExample.vue +64 -29
- package/vue/views/PageStructure.vue +168 -95
- package/vue/views/TableExample.vue +2 -76
- package/vue/views/ThemePreview.vue +172 -0
- package/vue/views/UserDetails.vue +39 -0
- package/vue/views/Welcome.vue +9 -6
|
@@ -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/<name>/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/<name>/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>
|
package/vue/views/Welcome.vue
CHANGED
|
@@ -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
|
})
|