picocrank 1.25.2 → 1.26.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/eslint.config.js +68 -0
- package/package.json +13 -3
- package/router.js +74 -0
- package/styles/dark-theme.css +20 -11
- package/styles/picocrank-extensions.css +77 -30
- package/supplemental-themes/catppuccin-latte-frappe/theme.css +10 -24
- package/supplemental-themes/dracula-alucard/theme.css +10 -24
- package/supplemental-themes/gruvbox-dark-light/theme.css +10 -24
- package/supplemental-themes/waffles/theme.css +2 -16
- package/vue/components/Breadcrumbs.vue +192 -45
- package/vue/components/Calendar.vue +45 -25
- package/vue/components/DangerZone.vue +186 -0
- package/vue/components/Header.vue +22 -6
- package/vue/components/NavigationGrid.vue +26 -180
- package/vue/components/NotificationBlock.vue +120 -0
- package/vue/components/NotificationPopup.vue +44 -41
- package/vue/components/ReadOnlyTextArea.vue +1 -1
- package/vue/components/SidebarNavLink.vue +3 -3
- package/vue/components/Table.vue +107 -79
- package/vue/components/TableColumnOptionsPopover.vue +9 -0
- package/vue/components/Tabs.vue +363 -79
- package/vue/components/TopBar.vue +2 -2
- package/vue/composables/tableColumnPriorities.js +33 -0
- package/vue/composables/tableFilters.js +1 -1
- package/vue/data/navSectionHubs.js +196 -0
- package/vue/data/routeBreadcrumbs.js +90 -0
- package/vue/examples/Admin.vue +12 -12
- package/vue/examples/App.vue +27 -36
- package/vue/examples/CalendarExample.vue +32 -22
- package/vue/examples/ExampleHeaderThemeSwitcher.vue +1 -1
- package/vue/examples/Login.vue +0 -3
- package/vue/examples/LoginExample.vue +2 -14
- package/vue/examples/NavSectionHub.vue +36 -0
- package/vue/examples/PageStructure.vue +6 -3
- package/vue/examples/StatusExample.vue +248 -129
- package/vue/examples/TableExample.vue +68 -67
- package/vue/examples/TabsExample.vue +200 -255
- package/vue/examples/ThemePreview.vue +21 -23
- package/vue/examples/ViewItem.vue +32 -5
- package/vue/examples/Welcome.vue +3 -40
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<Section
|
|
3
|
-
title="
|
|
3
|
+
:title="tableSectionTitle"
|
|
4
4
|
:icon="TableIcon"
|
|
5
5
|
subtitle="Sortable columns, pagination, and column filters. Right-click or long-press a column header to filter."
|
|
6
6
|
:padding="false"
|
|
@@ -15,8 +15,10 @@
|
|
|
15
15
|
:column-options="enabledFeatures.includes('columnOptions')"
|
|
16
16
|
:loading="enabledFeatures.includes('loading')"
|
|
17
17
|
:horizontal-scroll="layout === 'scroll'"
|
|
18
|
+
:responsive-columns="layout === 'priorities'"
|
|
18
19
|
:sticky-cols="stickyCols"
|
|
19
20
|
v-model:column-visibility="columnVisibility"
|
|
21
|
+
v-model:layout-label="tableLayoutLabel"
|
|
20
22
|
:default-column-visibility="defaultColumnVisibility"
|
|
21
23
|
v-bind="tableListeners"
|
|
22
24
|
>
|
|
@@ -26,14 +28,14 @@
|
|
|
26
28
|
</router-link>
|
|
27
29
|
</template>
|
|
28
30
|
|
|
29
|
-
<template #cell-city="{
|
|
31
|
+
<template #cell-city="{ value }">
|
|
30
32
|
<span class="subtle">
|
|
31
33
|
{{ value }}
|
|
32
34
|
</span>
|
|
33
35
|
</template>
|
|
34
36
|
|
|
35
37
|
<template #cell-status="{ value }">
|
|
36
|
-
<span class="tag
|
|
38
|
+
<span class="tag" :class="statusTagClass(value)">{{ value }}</span>
|
|
37
39
|
</template>
|
|
38
40
|
</Table>
|
|
39
41
|
</Section>
|
|
@@ -49,14 +51,23 @@
|
|
|
49
51
|
|
|
50
52
|
<FormLayout>
|
|
51
53
|
<FormField label="Data" fake description="Connect or disconnect row data for the table above. Saved column layouts persist in localStorage for this table.">
|
|
52
|
-
<
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
<RadioGroup
|
|
55
|
+
v-model="dataConnected"
|
|
56
|
+
name="table-data-connection"
|
|
57
|
+
variant="boolean"
|
|
58
|
+
:options="dataConnectionOptions"
|
|
59
|
+
/>
|
|
60
|
+
</FormField>
|
|
61
|
+
|
|
62
|
+
<FormField
|
|
63
|
+
label="Wide table"
|
|
64
|
+
fake
|
|
65
|
+
description="Adds extra columns (email, department, role, status) to the table."
|
|
66
|
+
>
|
|
67
|
+
<label>
|
|
68
|
+
<input v-model="wideTable" type="checkbox" />
|
|
69
|
+
Show extended columns
|
|
70
|
+
</label>
|
|
60
71
|
</FormField>
|
|
61
72
|
|
|
62
73
|
<FormField label="Features" fake description="Toggle core table behaviour.">
|
|
@@ -70,7 +81,7 @@
|
|
|
70
81
|
<FormField
|
|
71
82
|
label="Responsive layout"
|
|
72
83
|
fake
|
|
73
|
-
description="Column priorities hide lower-priority columns as the table narrows. Horizontal scroll keeps every column visible with optional sticky leading columns."
|
|
84
|
+
description="Column priorities hide lower-priority columns as the table narrows. Horizontal scroll keeps every column visible with optional sticky leading columns. Browser layout leaves column sizing to the viewport."
|
|
74
85
|
>
|
|
75
86
|
<RadioGroup
|
|
76
87
|
v-model="layout"
|
|
@@ -91,18 +102,6 @@
|
|
|
91
102
|
:options="stickyColOptions"
|
|
92
103
|
/>
|
|
93
104
|
</FormField>
|
|
94
|
-
|
|
95
|
-
<FormField
|
|
96
|
-
v-if="layout === 'scroll'"
|
|
97
|
-
label="Wide table"
|
|
98
|
-
fake
|
|
99
|
-
description="Adds extra columns so horizontal scroll is easier to see."
|
|
100
|
-
>
|
|
101
|
-
<label>
|
|
102
|
-
<input v-model="wideTable" type="checkbox" />
|
|
103
|
-
Show extended columns
|
|
104
|
-
</label>
|
|
105
|
-
</FormField>
|
|
106
105
|
</FormLayout>
|
|
107
106
|
|
|
108
107
|
<div class="table-events">
|
|
@@ -120,6 +119,14 @@
|
|
|
120
119
|
{{ activeFilterCount }} active filter(s)
|
|
121
120
|
</p>
|
|
122
121
|
<p v-else class="event-line subtle">Query: waiting for the first table update…</p>
|
|
122
|
+
|
|
123
|
+
<p v-if="tableLayoutLabel" class="event-line">
|
|
124
|
+
<strong>Layout:</strong>
|
|
125
|
+
{{ tableLayoutLabel }}
|
|
126
|
+
</p>
|
|
127
|
+
<p v-else-if="enabledFeatures.includes('columnOptions')" class="event-line subtle">
|
|
128
|
+
Layout: using developer defaults (change columns, order, or filters to see a preset or “Custom” label).
|
|
129
|
+
</p>
|
|
123
130
|
</div>
|
|
124
131
|
</Section>
|
|
125
132
|
|
|
@@ -139,7 +146,7 @@
|
|
|
139
146
|
<template v-for="header in headers" :key="header.key">
|
|
140
147
|
<dt>{{ header.label || header.key }}</dt>
|
|
141
148
|
<dd>
|
|
142
|
-
<span v-if="header.key === 'status'" class="tag
|
|
149
|
+
<span v-if="header.key === 'status'" class="tag" :class="statusTagClass(lastRowClick.row[header.key])">
|
|
143
150
|
{{ lastRowClick.row[header.key] }}
|
|
144
151
|
</span>
|
|
145
152
|
<template v-else>
|
|
@@ -170,15 +177,28 @@ const defaultColumnVisibility = {
|
|
|
170
177
|
|
|
171
178
|
const enabledFeatures = ref([...defaultFeatures])
|
|
172
179
|
const columnVisibility = ref({ ...defaultColumnVisibility })
|
|
173
|
-
const layout = ref('
|
|
180
|
+
const layout = ref('priorities')
|
|
174
181
|
const stickyColsOption = ref('2')
|
|
175
182
|
const wideTable = ref(true)
|
|
176
183
|
const dataConnected = ref(true)
|
|
177
184
|
const data = ref([])
|
|
178
185
|
const lastRowClick = ref(null)
|
|
179
186
|
const lastQuery = ref(null)
|
|
187
|
+
const tableLayoutLabel = ref('')
|
|
180
188
|
const rowDialogRef = ref(null)
|
|
181
189
|
|
|
190
|
+
const tableSectionTitle = computed(() => {
|
|
191
|
+
if (tableLayoutLabel.value) {
|
|
192
|
+
return `Table Example (${tableLayoutLabel.value})`
|
|
193
|
+
}
|
|
194
|
+
return 'Table Example'
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
const dataConnectionOptions = [
|
|
198
|
+
{ label: 'Connect data', value: true },
|
|
199
|
+
{ label: 'Disconnect data', value: false },
|
|
200
|
+
]
|
|
201
|
+
|
|
182
202
|
const featureOptions = [
|
|
183
203
|
{ value: 'pagination', label: 'Pagination' },
|
|
184
204
|
{ value: 'filters', label: 'Column filters' },
|
|
@@ -188,9 +208,9 @@ const featureOptions = [
|
|
|
188
208
|
]
|
|
189
209
|
|
|
190
210
|
const layoutOptions = [
|
|
191
|
-
{ value: 'default', label: 'Default' },
|
|
192
211
|
{ value: 'priorities', label: 'Column priorities' },
|
|
193
212
|
{ value: 'scroll', label: 'Horizontal scroll' },
|
|
213
|
+
{ value: 'browser', label: 'Browser' },
|
|
194
214
|
]
|
|
195
215
|
|
|
196
216
|
const stickyColOptions = [
|
|
@@ -202,27 +222,18 @@ const stickyColOptions = [
|
|
|
202
222
|
|
|
203
223
|
const baseHeaders = [
|
|
204
224
|
{ key: 'name', label: 'Name', sortable: true, filterable: true, filterType: 'text', width: '20%' },
|
|
205
|
-
{ key: 'age', label: 'Age', sortable: true, filterable: true, filterType: 'number' },
|
|
206
|
-
{ key: 'birthYear', label: 'Birth year', sortable: true, filterable: true, filterType: 'number' },
|
|
207
|
-
{ key: 'city', label: 'City', sortable: true, filterable: true, filterType: 'select', width: '200px' },
|
|
225
|
+
{ key: 'age', label: 'Age', sortable: true, filterable: true, filterType: 'number', colPriority: 2 },
|
|
226
|
+
{ key: 'birthYear', label: 'Birth year', sortable: true, filterable: true, filterType: 'number', colPriority: 3 },
|
|
227
|
+
{ key: 'city', label: 'City', sortable: true, filterable: true, filterType: 'select', width: '200px', colPriority: 1 },
|
|
208
228
|
]
|
|
209
229
|
|
|
210
230
|
const extendedHeaders = [
|
|
211
231
|
{ key: 'email', label: 'Email', sortable: true, filterable: true, filterType: 'text' },
|
|
212
|
-
{ key: 'department', label: 'Department', sortable: true, filterable: true, filterType: 'select' },
|
|
213
|
-
{ key: 'role', label: 'Role', sortable: true, filterable: true, filterType: 'text' },
|
|
214
|
-
{ key: 'status', label: 'Status', sortable: true, filterable: true, filterType: 'select' },
|
|
232
|
+
{ key: 'department', label: 'Department', sortable: true, filterable: true, filterType: 'select', colPriority: 2 },
|
|
233
|
+
{ key: 'role', label: 'Role', sortable: true, filterable: true, filterType: 'text', colPriority: 1 },
|
|
234
|
+
{ key: 'status', label: 'Status', sortable: true, filterable: true, filterType: 'select', colPriority: 1 },
|
|
215
235
|
]
|
|
216
236
|
|
|
217
|
-
const priorityByKey = {
|
|
218
|
-
age: 2,
|
|
219
|
-
birthYear: 3,
|
|
220
|
-
city: 1,
|
|
221
|
-
department: 2,
|
|
222
|
-
role: 1,
|
|
223
|
-
status: 1,
|
|
224
|
-
}
|
|
225
|
-
|
|
226
237
|
const stickyCols = computed(() => {
|
|
227
238
|
if (layout.value !== 'scroll' || stickyColsOption.value === 'none') {
|
|
228
239
|
return null
|
|
@@ -230,25 +241,11 @@ const stickyCols = computed(() => {
|
|
|
230
241
|
return Number(stickyColsOption.value)
|
|
231
242
|
})
|
|
232
243
|
|
|
233
|
-
const useExtendedColumns = computed(() =>
|
|
234
|
-
|
|
235
|
-
const headers = computed(() => {
|
|
236
|
-
const columns = useExtendedColumns.value
|
|
237
|
-
? [...baseHeaders, ...extendedHeaders]
|
|
238
|
-
: [...baseHeaders]
|
|
244
|
+
const useExtendedColumns = computed(() => wideTable.value)
|
|
239
245
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
return columns.map((header) => {
|
|
245
|
-
const colPriority = priorityByKey[header.key]
|
|
246
|
-
if (!colPriority) {
|
|
247
|
-
return { ...header }
|
|
248
|
-
}
|
|
249
|
-
return { ...header, colPriority }
|
|
250
|
-
})
|
|
251
|
-
})
|
|
246
|
+
const headers = computed(() => (
|
|
247
|
+
useExtendedColumns.value ? [...baseHeaders, ...extendedHeaders] : [...baseHeaders]
|
|
248
|
+
))
|
|
252
249
|
|
|
253
250
|
const tableData = computed(() => {
|
|
254
251
|
if (!dataConnected.value) {
|
|
@@ -309,10 +306,20 @@ function handleQueryChange(query) {
|
|
|
309
306
|
lastQuery.value = query
|
|
310
307
|
}
|
|
311
308
|
|
|
309
|
+
function statusTagClass(value) {
|
|
310
|
+
if (value === 'Active') {
|
|
311
|
+
return 'good'
|
|
312
|
+
}
|
|
313
|
+
if (value === 'Pending') {
|
|
314
|
+
return 'warning'
|
|
315
|
+
}
|
|
316
|
+
return null
|
|
317
|
+
}
|
|
318
|
+
|
|
312
319
|
function resetControls() {
|
|
313
320
|
enabledFeatures.value = [...defaultFeatures]
|
|
314
321
|
columnVisibility.value = { ...defaultColumnVisibility }
|
|
315
|
-
layout.value = '
|
|
322
|
+
layout.value = 'priorities'
|
|
316
323
|
stickyColsOption.value = '2'
|
|
317
324
|
wideTable.value = true
|
|
318
325
|
dataConnected.value = true
|
|
@@ -332,12 +339,6 @@ onMounted(() => {
|
|
|
332
339
|
margin-top: 1.5rem;
|
|
333
340
|
}
|
|
334
341
|
|
|
335
|
-
.table-data-actions {
|
|
336
|
-
display: flex;
|
|
337
|
-
flex-wrap: wrap;
|
|
338
|
-
gap: 0.5rem;
|
|
339
|
-
}
|
|
340
|
-
|
|
341
342
|
.table-events h4 {
|
|
342
343
|
margin-top: 0;
|
|
343
344
|
}
|