picocrank 1.25.1 → 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.
Files changed (44) hide show
  1. package/eslint.config.js +68 -0
  2. package/package.json +13 -3
  3. package/router.js +74 -0
  4. package/styles/dark-theme.css +21 -9
  5. package/styles/picocrank-extensions.css +131 -2
  6. package/supplemental-themes/catppuccin-latte-frappe/theme.css +12 -22
  7. package/supplemental-themes/dracula-alucard/theme.css +12 -22
  8. package/supplemental-themes/gruvbox-dark-light/theme.css +12 -22
  9. package/supplemental-themes/waffles/theme.css +2 -12
  10. package/vue/components/Breadcrumbs.vue +192 -45
  11. package/vue/components/Calendar.vue +93 -180
  12. package/vue/components/DangerZone.vue +186 -0
  13. package/vue/components/Header.vue +22 -6
  14. package/vue/components/Login.vue +6 -7
  15. package/vue/components/NavigationGrid.vue +26 -204
  16. package/vue/components/NotificationBlock.vue +120 -0
  17. package/vue/components/NotificationPopup.vue +44 -41
  18. package/vue/components/QuickSearch.vue +21 -47
  19. package/vue/components/RadioGroup.vue +4 -4
  20. package/vue/components/ReadOnlyTextArea.vue +1 -1
  21. package/vue/components/SidebarNavLink.vue +3 -3
  22. package/vue/components/Table.vue +109 -81
  23. package/vue/components/TableColumnFilterPopover.vue +7 -17
  24. package/vue/components/TableColumnOptionsPopover.vue +22 -27
  25. package/vue/components/Tabs.vue +366 -82
  26. package/vue/components/TopBar.vue +2 -2
  27. package/vue/composables/tableColumnPriorities.js +33 -0
  28. package/vue/composables/tableFilters.js +1 -1
  29. package/vue/data/navSectionHubs.js +196 -0
  30. package/vue/data/routeBreadcrumbs.js +90 -0
  31. package/vue/examples/Admin.vue +12 -12
  32. package/vue/examples/App.vue +27 -36
  33. package/vue/examples/CalendarExample.vue +32 -22
  34. package/vue/examples/ExampleHeaderThemeSwitcher.vue +1 -1
  35. package/vue/examples/Login.vue +0 -3
  36. package/vue/examples/LoginExample.vue +2 -14
  37. package/vue/examples/NavSectionHub.vue +36 -0
  38. package/vue/examples/PageStructure.vue +6 -3
  39. package/vue/examples/StatusExample.vue +248 -129
  40. package/vue/examples/TableExample.vue +68 -67
  41. package/vue/examples/TabsExample.vue +200 -255
  42. package/vue/examples/ThemePreview.vue +21 -23
  43. package/vue/examples/ViewItem.vue +32 -5
  44. package/vue/examples/Welcome.vue +3 -112
@@ -35,7 +35,7 @@ html[data-theme="dark"] {
35
35
  --gb-good-fg: var(--gb-bg0-hard);
36
36
 
37
37
  --body-bg-color: var(--gb-bg0);
38
- --surface-bg-color: var(--gb-bg1);
38
+ --section-bg-color: var(--gb-bg1);
39
39
  --standout-bg-color: var(--gb-bg1);
40
40
  --section-header-bg-color: var(--gb-bg1);
41
41
  --shadow-color: var(--gb-shadow-strong);
@@ -65,7 +65,10 @@ html[data-theme="dark"] {
65
65
  --input-bg-color: var(--gb-bg0);
66
66
  --input-fg-color: var(--gb-fg0);
67
67
  --control-option-bg-color: var(--gb-bg2);
68
- --control-hover-bg-color: var(--gb-bg2);
68
+ --control-hover-bg-color: var(--gb-bg3);
69
+ --control-checked-bg: color-mix(in srgb, var(--gb-green) 35%, var(--standout-bg-color));
70
+ --control-checked-hover-bg: color-mix(in srgb, var(--gb-green) 45%, var(--standout-bg-color));
71
+ --control-checked-fg: var(--gb-fg0);
69
72
  --menu-hover-bg-color: var(--gb-bg2);
70
73
 
71
74
  --table-row-hover-bg: var(--gb-bg2);
@@ -88,19 +91,11 @@ html[data-theme="dark"] {
88
91
  --karma-bad: var(--gb-red);
89
92
  --karma-warning: var(--gb-yellow);
90
93
  --karma-severe: var(--gb-orange);
91
- --karma-important: var(--gb-purple);
92
94
  --karma-note: var(--gb-aqua);
93
95
  --karma-info: var(--gb-bg2);
94
96
  --karma-old: var(--gb-gray);
95
97
 
96
- --karma-good-fg: var(--gb-green);
97
- --karma-bad-fg: var(--gb-red);
98
- --karma-warning-fg: var(--gb-yellow);
99
- --karma-severe-fg: var(--gb-orange);
100
- --karma-important-fg: var(--gb-purple);
101
- --karma-note-fg: var(--gb-aqua);
102
- --karma-info-fg: var(--gb-fg3);
103
- --karma-old-fg: var(--gb-fg4);
98
+ --karma-on-bg-fg: var(--gb-good-fg);
104
99
  }
105
100
 
106
101
  html[data-theme="light"] {
@@ -130,7 +125,7 @@ html[data-theme="light"] {
130
125
  --gb-good-fg: var(--gb-bg0);
131
126
 
132
127
  --body-bg-color: var(--gb-bg0);
133
- --surface-bg-color: var(--gb-bg1);
128
+ --section-bg-color: var(--gb-bg1);
134
129
  --standout-bg-color: var(--gb-bg1);
135
130
  --section-header-bg-color: var(--gb-bg1);
136
131
  --shadow-color: var(--gb-shadow-strong);
@@ -160,7 +155,10 @@ html[data-theme="light"] {
160
155
  --input-bg-color: var(--gb-bg0);
161
156
  --input-fg-color: var(--gb-fg0);
162
157
  --control-option-bg-color: var(--gb-bg2);
163
- --control-hover-bg-color: var(--gb-bg2);
158
+ --control-hover-bg-color: var(--gb-bg3);
159
+ --control-checked-bg: color-mix(in srgb, var(--gb-green) 20%, var(--standout-bg-color));
160
+ --control-checked-hover-bg: color-mix(in srgb, var(--gb-green) 28%, var(--standout-bg-color));
161
+ --control-checked-fg: var(--gb-fg0);
164
162
  --menu-hover-bg-color: var(--gb-bg2);
165
163
 
166
164
  --table-row-hover-bg: var(--gb-bg2);
@@ -183,17 +181,9 @@ html[data-theme="light"] {
183
181
  --karma-bad: var(--gb-red);
184
182
  --karma-warning: var(--gb-yellow);
185
183
  --karma-severe: var(--gb-orange);
186
- --karma-important: var(--gb-purple);
187
184
  --karma-note: var(--gb-aqua);
188
185
  --karma-info: var(--gb-bg2);
189
186
  --karma-old: var(--gb-gray);
190
187
 
191
- --karma-good-fg: var(--gb-green);
192
- --karma-bad-fg: var(--gb-red);
193
- --karma-warning-fg: var(--gb-yellow);
194
- --karma-severe-fg: var(--gb-orange);
195
- --karma-important-fg: var(--gb-purple);
196
- --karma-note-fg: var(--gb-aqua);
197
- --karma-info-fg: var(--gb-fg3);
198
- --karma-old-fg: var(--gb-fg4);
188
+ --karma-on-bg-fg: var(--gb-good-fg);
199
189
  }
@@ -18,7 +18,7 @@ html {
18
18
  --waffle-accent: #a05020;
19
19
 
20
20
  --body-bg-color: var(--waffle-cream);
21
- --surface-bg-color: #fffdf6;
21
+ --section-bg-color: #fffdf6;
22
22
  --standout-bg-color: var(--waffle-batter);
23
23
  --section-header-bg-color: var(--waffle-batter);
24
24
  --shadow-color: rgba(139, 69, 19, 0.12);
@@ -59,19 +59,9 @@ html {
59
59
  --karma-bad: #f0a0a8;
60
60
  --karma-warning: var(--waffle-butter);
61
61
  --karma-severe: #e08a6a;
62
- --karma-important: #ffe8a3;
63
62
  --karma-note: #a8d4e8;
64
63
  --karma-info: var(--waffle-batter);
65
64
  --karma-old: #d4c4a0;
66
-
67
- --karma-good-fg: #4a7a28;
68
- --karma-bad-fg: var(--waffle-berry);
69
- --karma-warning-fg: #9a6b00;
70
- --karma-severe-fg: #a04020;
71
- --karma-important-fg: #8a6800;
72
- --karma-note-fg: #2a6a88;
73
- --karma-info-fg: #7a6540;
74
- --karma-old-fg: #6a5840;
75
65
  }
76
66
 
77
67
  body {
@@ -145,7 +135,7 @@ html[data-theme="dark"] {
145
135
  --disabled-text-color: #7a6548;
146
136
 
147
137
  --body-bg-color: var(--waffle-cream);
148
- --surface-bg-color: var(--waffle-batter);
138
+ --section-bg-color: var(--waffle-batter);
149
139
  --section-header-bg-color: var(--waffle-section);
150
140
  --sidebar-bg-color: var(--waffle-sidebar);
151
141
  --sidebar-link-color: var(--waffle-foreground);
@@ -1,58 +1,205 @@
1
1
  <template>
2
- <div id = "breadcrumbs">
3
- <template v-for="(link, index) in links" :key="link.name">
4
- <router-link :to="link.href">{{ link.name }}</router-link>
5
- <span v-if="index < links.length - 1" class="separator">
6
- &raquo;
7
- </span>
8
- </template>
9
- </div>
2
+ <nav id="breadcrumbs" class="breadcrumbs" aria-label="Breadcrumb">
3
+ <div class="breadcrumbs-links flex-row">
4
+ <template v-for="(link, index) in links" :key="`${link.name}-${index}`">
5
+ <HugeiconsIcon
6
+ v-if="index > 0"
7
+ :icon="ArrowRight01Icon"
8
+ class="separator"
9
+ width="0.85em"
10
+ height="0.85em"
11
+ aria-hidden="true"
12
+ />
13
+
14
+ <nav
15
+ v-if="hasMenu(link)"
16
+ class="menu breadcrumb-menu"
17
+ :aria-label="`${link.name} sections`"
18
+ >
19
+ <ul>
20
+ <li>
21
+ <span class="submenu">
22
+ <router-link
23
+ v-if="link.to"
24
+ :to="link.to"
25
+ class="button breadcrumb-link"
26
+ :aria-current="isLast(index) ? 'page' : undefined"
27
+ >
28
+ <span>{{ link.name }}</span>
29
+ </router-link>
30
+ <span
31
+ v-else
32
+ class="button breadcrumb-link"
33
+ :aria-current="isLast(index) ? 'page' : undefined"
34
+ >
35
+ {{ link.name }}
36
+ </span>
37
+ </span>
38
+ <div>
39
+ <ul>
40
+ <li v-for="menuItem in link.menu" :key="menuItem.name">
41
+ <router-link
42
+ :to="menuItem.to"
43
+ :class="{ active: isMenuItemActive(link, menuItem) }"
44
+ >
45
+ {{ menuItem.name }}
46
+ </router-link>
47
+ </li>
48
+ </ul>
49
+ </div>
50
+ </li>
51
+ </ul>
52
+ </nav>
53
+
54
+ <router-link
55
+ v-else-if="!isLast(index)"
56
+ :to="link.to ?? link.href"
57
+ class="button breadcrumb-link"
58
+ >
59
+ <span>{{ link.name }}</span>
60
+ </router-link>
61
+
62
+ <span
63
+ v-else
64
+ class="button breadcrumb-link active"
65
+ aria-current="page"
66
+ >
67
+ <span>{{ link.name }}</span>
68
+ </span>
69
+ </template>
70
+ </div>
71
+ </nav>
10
72
  </template>
11
73
 
74
+ <script setup>
75
+ import { ref, watch } from 'vue'
76
+ import { useRoute } from 'vue-router'
77
+ import { HugeiconsIcon } from '@hugeicons/vue'
78
+ import { ArrowRight01Icon } from '@hugeicons/core-free-icons'
79
+
80
+ const route = useRoute()
81
+ const links = ref([])
82
+
83
+ function hasMenu(link) {
84
+ return Array.isArray(link.menu) && link.menu.length > 0
85
+ }
86
+
87
+ function isLast(index) {
88
+ return index === links.value.length - 1
89
+ }
90
+
91
+ function isMenuItemActive(link, menuItem) {
92
+ const activeRoute = link.to?.name
93
+ const itemRoute = menuItem.to?.name
94
+ return activeRoute != null && activeRoute === itemRoute
95
+ }
96
+
97
+ watch(() => route.matched, (matched) => {
98
+ links.value = []
99
+ matched.forEach((record) => {
100
+ if (record.meta && record.meta.breadcrumbs) {
101
+ record.meta.breadcrumbs(route).forEach((item) => {
102
+ links.value.push({
103
+ name: item.name,
104
+ to: item.to,
105
+ href: item.href || record.path || '/',
106
+ menu: item.menu,
107
+ })
108
+ })
109
+ } else if (record.name) {
110
+ links.value.push({
111
+ name: record.meta?.title || record.name,
112
+ to: { name: record.name, params: route.params, query: route.query },
113
+ href: route.fullPath || record.path || '/',
114
+ })
115
+ }
116
+ })
117
+ }, { immediate: true })
118
+ </script>
119
+
12
120
  <style scoped>
13
- span {
14
- color: #bbb;
121
+ .breadcrumbs {
122
+ flex: 1 1 auto;
123
+ min-width: 0;
124
+ }
125
+
126
+ .breadcrumbs-links {
127
+ display: flex;
128
+ align-items: center;
129
+ gap: 0.0625rem;
130
+ flex-wrap: wrap;
131
+ }
132
+
133
+ .breadcrumb-menu {
134
+ display: inline-flex;
135
+ flex-shrink: 0;
136
+ }
137
+
138
+ .breadcrumb-menu > ul {
139
+ list-style: none;
140
+ padding: 0;
141
+ margin: 0;
142
+ }
143
+
144
+ .breadcrumb-link {
145
+ display: inline-flex;
146
+ align-items: center;
147
+ gap: 0.375rem;
148
+ padding: 0.5em 0.375em;
149
+ border-radius: 0.25em;
150
+ text-decoration: none;
151
+ color: var(--header-fg-color);
152
+ transition: background-color 0.15s ease, color 0.15s ease;
153
+ white-space: nowrap;
154
+ border: 0;
155
+ font-weight: normal;
156
+ background-color: transparent;
157
+ cursor: default;
15
158
  }
16
159
 
17
- a {
18
- text-decoration: none;
19
- padding: 0.4em;
20
- border-radius: 0.2em;
160
+ a.breadcrumb-link {
161
+ cursor: pointer;
21
162
  }
22
163
 
23
- a:hover {
24
- text-decoration: underline;
25
- background-color: #000;
164
+ .breadcrumb-link.active {
165
+ text-decoration: underline;
166
+ font-weight: 500;
26
167
  }
27
168
 
169
+ .separator {
170
+ flex-shrink: 0;
171
+ color: var(--header-fg-color);
172
+ opacity: 0.4;
173
+ }
28
174
  </style>
29
175
 
176
+ <style>
177
+ header .breadcrumbs a.breadcrumb-link:hover,
178
+ header .breadcrumbs a.breadcrumb-link:focus-visible,
179
+ header .breadcrumbs .breadcrumb-menu.menu > ul > li:hover,
180
+ header .breadcrumbs .breadcrumb-menu.menu > ul > li:focus-within,
181
+ header .breadcrumbs .breadcrumb-menu.menu > ul > li:hover > span > a,
182
+ header .breadcrumbs .breadcrumb-menu.menu > ul > li:focus-within > span > a,
183
+ header .breadcrumbs .breadcrumb-menu.menu > ul div ul a:hover,
184
+ header .breadcrumbs .breadcrumb-menu.menu > ul div ul a:focus-visible {
185
+ background-color: var(--header-hover-background-color);
186
+ color: var(--header-hover-text-color);
187
+ }
30
188
 
31
- <script setup>
32
- import { ref } from 'vue';
33
- import { watch } from 'vue';
34
- import { useRoute } from 'vue-router';
35
-
36
- const route = useRoute();
37
- const links = ref([]);
38
-
39
- watch(() => route.matched, (matched) => {
40
-
41
- links.value = [];
42
- matched.forEach((record) => {
43
- if (record.meta && record.meta.breadcrumbs) {
44
- record.meta.breadcrumbs(route).forEach((item) => {
45
- links.value.push({
46
- name: item.name,
47
- href: item.href || record.path || '/'
48
- });
49
- });
50
- } else if (record.name) {
51
- links.value.push({
52
- name: record.name,
53
- href: record.path || '/'
54
- });
55
- }
56
- });
57
- }, { immediate: true });
58
- </script>
189
+ header .breadcrumbs a.breadcrumb-link:focus-visible {
190
+ outline-color: var(--header-focus-outline-color);
191
+ }
192
+
193
+ header .breadcrumb-menu.menu > ul > li {
194
+ border-radius: 0.25em;
195
+ }
196
+
197
+ header .breadcrumb-menu.menu > ul li span.submenu .breadcrumb-link {
198
+ text-decoration: inherit;
199
+ }
200
+
201
+ header .breadcrumb-menu.menu > ul li span.submenu .breadcrumb-link[aria-current="page"] {
202
+ text-decoration: underline;
203
+ font-weight: 500;
204
+ }
205
+ </style>