@stonecrop/desktop 0.30.0 → 0.32.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/README.md +1 -1
- package/dist/assets/index.css +394 -0
- package/dist/desktop.js +933 -833
- package/dist/desktop.js.map +1 -1
- package/dist/src/components/ActionSet.vue.d.ts +12 -0
- package/dist/src/components/ActionSet.vue.d.ts.map +1 -0
- package/dist/src/components/CommandPalette.vue.d.ts +35 -0
- package/dist/src/components/CommandPalette.vue.d.ts.map +1 -0
- package/dist/src/components/Desktop.vue.d.ts +26 -0
- package/dist/src/components/Desktop.vue.d.ts.map +1 -0
- package/dist/src/components/SheetNav.vue.d.ts +10 -0
- package/dist/src/components/SheetNav.vue.d.ts.map +1 -0
- package/dist/{tsdoc-metadata.json → src/tsdoc-metadata.json} +1 -1
- package/package.json +37 -31
- package/dist/desktop.css +0 -1
- package/dist/desktop.d.ts +0 -119
- package/dist/desktop.tsbuildinfo +0 -1
- package/dist/src/index.js +0 -6
- package/dist/src/plugins/index.js +0 -17
- package/dist/src/types/index.js +0 -0
- package/src/components/ActionSet.vue +0 -211
- package/src/components/CommandPalette.vue +0 -235
- package/src/components/Desktop.vue +0 -982
- package/src/components/SheetNav.vue +0 -297
- package/src/index.ts +0 -9
- package/src/plugins/index.ts +0 -21
- package/src/shims-vue.d.ts +0 -5
- package/src/types/index.ts +0 -107
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<footer>
|
|
3
|
-
<ul class="tabs">
|
|
4
|
-
<li class="hidebreadcrumbs" @click="toggleBreadcrumbs" @keydown.enter="toggleBreadcrumbs">
|
|
5
|
-
<a tabindex="0"><div :class="rotateHideTabIcon">×</div></a>
|
|
6
|
-
</li>
|
|
7
|
-
<li
|
|
8
|
-
class="hometab"
|
|
9
|
-
:style="{ display: breadcrumbsVisibile ? 'block' : 'none' }"
|
|
10
|
-
@click="navigateHome"
|
|
11
|
-
@keydown.enter="navigateHome">
|
|
12
|
-
<router-link to="/" tabindex="0">
|
|
13
|
-
<svg class="icon" aria-label="Home" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
14
|
-
<path d="M3 12l9-9 9 9" />
|
|
15
|
-
<path d="M9 21V12h6v9" />
|
|
16
|
-
</svg>
|
|
17
|
-
</router-link>
|
|
18
|
-
</li>
|
|
19
|
-
<li
|
|
20
|
-
:class="['searchtab', { 'search-active': searchVisible }]"
|
|
21
|
-
:style="{ display: breadcrumbsVisibile ? 'block' : 'none' }">
|
|
22
|
-
<a tabindex="0">
|
|
23
|
-
<svg
|
|
24
|
-
v-show="!searchVisible"
|
|
25
|
-
class="icon search-icon"
|
|
26
|
-
role="button"
|
|
27
|
-
aria-label="Search"
|
|
28
|
-
viewBox="0 0 24 24"
|
|
29
|
-
fill="none"
|
|
30
|
-
stroke="currentColor"
|
|
31
|
-
stroke-width="2"
|
|
32
|
-
@click="toggleSearch"
|
|
33
|
-
@keydown.enter="toggleSearch">
|
|
34
|
-
<circle cx="11" cy="11" r="7" />
|
|
35
|
-
<path d="M21 21l-4.35-4.35" />
|
|
36
|
-
</svg>
|
|
37
|
-
<input
|
|
38
|
-
v-show="searchVisible"
|
|
39
|
-
ref="searchinput"
|
|
40
|
-
v-model="searchText"
|
|
41
|
-
type="text"
|
|
42
|
-
placeholder="Search..."
|
|
43
|
-
@click.stop
|
|
44
|
-
@input="handleSearchInput($event)"
|
|
45
|
-
@blur="handleSearch($event)"
|
|
46
|
-
@keydown.enter="handleSearch($event)"
|
|
47
|
-
@keydown.escape="toggleSearch" />
|
|
48
|
-
</a>
|
|
49
|
-
</li>
|
|
50
|
-
<li
|
|
51
|
-
v-for="breadcrumb in breadcrumbs"
|
|
52
|
-
:key="breadcrumb.title"
|
|
53
|
-
:style="{ display: breadcrumbsVisibile ? 'block' : 'none' }">
|
|
54
|
-
<router-link tabindex="0" :to="breadcrumb.to"> {{ breadcrumb.title }} </router-link>
|
|
55
|
-
</li>
|
|
56
|
-
</ul>
|
|
57
|
-
</footer>
|
|
58
|
-
</template>
|
|
59
|
-
|
|
60
|
-
<script setup lang="ts">
|
|
61
|
-
import { computed, nextTick, ref, useTemplateRef } from 'vue'
|
|
62
|
-
|
|
63
|
-
const { breadcrumbs = [] } = defineProps<{ breadcrumbs?: { title: string; to: string }[] }>()
|
|
64
|
-
|
|
65
|
-
const breadcrumbsVisibile = ref(true)
|
|
66
|
-
const searchVisible = ref(false)
|
|
67
|
-
const searchText = ref('')
|
|
68
|
-
const inputRef = useTemplateRef<HTMLInputElement>('searchinput')
|
|
69
|
-
|
|
70
|
-
const rotateHideTabIcon = computed(() => {
|
|
71
|
-
return breadcrumbsVisibile.value ? 'unrotated' : 'rotated'
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
const toggleBreadcrumbs = () => {
|
|
75
|
-
breadcrumbsVisibile.value = !breadcrumbsVisibile.value
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const toggleSearch = async () => {
|
|
79
|
-
searchVisible.value = !searchVisible.value
|
|
80
|
-
await nextTick(() => {
|
|
81
|
-
inputRef.value?.focus()
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const handleSearchInput = (event: Event | MouseEvent) => {
|
|
86
|
-
event.preventDefault()
|
|
87
|
-
event.stopPropagation()
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const handleSearch = async (event: FocusEvent | KeyboardEvent) => {
|
|
91
|
-
event.preventDefault()
|
|
92
|
-
event.stopPropagation()
|
|
93
|
-
await toggleSearch()
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const navigateHome = (/* event: MouseEvent | KeyboardEvent */) => {
|
|
97
|
-
// navigate home
|
|
98
|
-
}
|
|
99
|
-
</script>
|
|
100
|
-
|
|
101
|
-
<style scoped>
|
|
102
|
-
footer {
|
|
103
|
-
position: fixed;
|
|
104
|
-
bottom: 0px;
|
|
105
|
-
width: 100%;
|
|
106
|
-
background-color: transparent;
|
|
107
|
-
height: auto;
|
|
108
|
-
min-height: 2.4rem;
|
|
109
|
-
z-index: 100;
|
|
110
|
-
text-align: left;
|
|
111
|
-
font-size: 100%;
|
|
112
|
-
display: flex;
|
|
113
|
-
justify-content: right;
|
|
114
|
-
padding: 0 0.75rem 0 0;
|
|
115
|
-
box-sizing: border-box;
|
|
116
|
-
}
|
|
117
|
-
ul {
|
|
118
|
-
display: flex;
|
|
119
|
-
flex-direction: row-reverse;
|
|
120
|
-
margin: 0;
|
|
121
|
-
padding: 0;
|
|
122
|
-
list-style: none;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.tabs li {
|
|
126
|
-
float: left;
|
|
127
|
-
list-style-type: none;
|
|
128
|
-
position: relative;
|
|
129
|
-
margin-left: -1px;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/* Base tab styling */
|
|
133
|
-
.tabs a {
|
|
134
|
-
float: left;
|
|
135
|
-
padding: 0.5rem 1rem;
|
|
136
|
-
height: 2.4rem;
|
|
137
|
-
box-sizing: border-box;
|
|
138
|
-
display: flex;
|
|
139
|
-
align-items: center;
|
|
140
|
-
justify-content: center;
|
|
141
|
-
text-decoration: none;
|
|
142
|
-
color: var(--sc-gray-60);
|
|
143
|
-
background: var(--sc-btn-color);
|
|
144
|
-
border: 1px solid var(--sc-btn-border);
|
|
145
|
-
font-size: 0.85rem;
|
|
146
|
-
font-family: var(--sc-font-family);
|
|
147
|
-
transition: all 0.15s ease;
|
|
148
|
-
|
|
149
|
-
/* Minimal ornamentation - subtle top radius only */
|
|
150
|
-
border-top-left-radius: 2px;
|
|
151
|
-
border-top-right-radius: 2px;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
.tabs a:hover {
|
|
155
|
-
background: var(--sc-btn-hover);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.tabs .router-link-active {
|
|
159
|
-
z-index: 3;
|
|
160
|
-
background: var(--sc-primary-color) !important;
|
|
161
|
-
border-color: var(--sc-primary-color) !important;
|
|
162
|
-
color: var(--sc-primary-text-color) !important;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/* Pseudo-elements removed - minimal ornamentation style */
|
|
166
|
-
|
|
167
|
-
/* Hide breadcrumbs tab */
|
|
168
|
-
.hidebreadcrumbs a {
|
|
169
|
-
min-width: 2.4rem;
|
|
170
|
-
width: 2.4rem;
|
|
171
|
-
height: 2.4rem;
|
|
172
|
-
padding: 0.5rem;
|
|
173
|
-
background: var(--sc-btn-color);
|
|
174
|
-
border: 1px solid var(--sc-btn-border);
|
|
175
|
-
color: var(--sc-gray-60);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
.hidebreadcrumbs a div {
|
|
179
|
-
font-size: 1.2rem;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
.rotated {
|
|
183
|
-
transform: rotate(45deg);
|
|
184
|
-
-webkit-transform: rotate(45deg);
|
|
185
|
-
-moz-transform: rotate(45deg);
|
|
186
|
-
-ms-transform: rotate(45deg);
|
|
187
|
-
-o-transform: rotate(45deg);
|
|
188
|
-
transition: transform 250ms ease;
|
|
189
|
-
}
|
|
190
|
-
.unrotated {
|
|
191
|
-
transform: rotate(0deg);
|
|
192
|
-
-webkit-transform: rotate(0deg);
|
|
193
|
-
-moz-transform: rotate(0deg);
|
|
194
|
-
-ms-transform: rotate(0deg);
|
|
195
|
-
-o-transform: rotate(0deg);
|
|
196
|
-
transition: transform 250ms ease;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
li:active,
|
|
200
|
-
li:hover,
|
|
201
|
-
li:focus,
|
|
202
|
-
li > a:active,
|
|
203
|
-
li > a:hover,
|
|
204
|
-
li > a:focus {
|
|
205
|
-
z-index: 3;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
a:active,
|
|
209
|
-
a:hover,
|
|
210
|
-
a:focus {
|
|
211
|
-
outline: 2px solid var(--sc-input-active-border-color);
|
|
212
|
-
z-index: 3;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/* Home tab */
|
|
216
|
-
.hometab a {
|
|
217
|
-
min-width: 2.4rem;
|
|
218
|
-
width: 2.4rem;
|
|
219
|
-
height: 2.4rem;
|
|
220
|
-
padding: 0.5rem;
|
|
221
|
-
background: var(--sc-btn-color);
|
|
222
|
-
border: 1px solid var(--sc-btn-border);
|
|
223
|
-
color: var(--sc-gray-60);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/* SVG icon styling */
|
|
227
|
-
.icon {
|
|
228
|
-
width: 1rem;
|
|
229
|
-
height: 1rem;
|
|
230
|
-
stroke: currentColor;
|
|
231
|
-
flex-shrink: 0;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/* Search tab with animation */
|
|
235
|
-
.searchtab {
|
|
236
|
-
overflow: hidden;
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
.searchtab a {
|
|
240
|
-
min-width: 2.4rem;
|
|
241
|
-
height: 2.4rem;
|
|
242
|
-
padding: 0.5rem;
|
|
243
|
-
background: var(--sc-btn-color);
|
|
244
|
-
border: 1px solid var(--sc-btn-border);
|
|
245
|
-
color: var(--sc-gray-60);
|
|
246
|
-
overflow: hidden;
|
|
247
|
-
/* Animation for smooth expand/collapse */
|
|
248
|
-
max-width: 2.4rem;
|
|
249
|
-
transition:
|
|
250
|
-
max-width 0.35s ease-in-out,
|
|
251
|
-
padding 0.35s ease-in-out,
|
|
252
|
-
background 0.2s ease;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
.searchtab .search-icon {
|
|
256
|
-
cursor: pointer;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.searchtab input {
|
|
260
|
-
outline: none;
|
|
261
|
-
border: 1px solid var(--sc-input-border-color);
|
|
262
|
-
border-radius: 0.25rem;
|
|
263
|
-
background-color: var(--sc-form-background);
|
|
264
|
-
color: var(--sc-gray-80);
|
|
265
|
-
text-align: left;
|
|
266
|
-
font-size: 0.875rem;
|
|
267
|
-
padding: 0.25rem 0.5rem;
|
|
268
|
-
width: 180px;
|
|
269
|
-
height: 1.5rem;
|
|
270
|
-
flex-shrink: 0;
|
|
271
|
-
opacity: 0;
|
|
272
|
-
transition: opacity 0.2s ease-in-out;
|
|
273
|
-
transition-delay: 0s;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
.searchtab input:focus {
|
|
277
|
-
border-color: var(--sc-input-active-border-color);
|
|
278
|
-
outline: none;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
.searchtab input::placeholder {
|
|
282
|
-
color: var(--sc-input-label-color);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
/* Search active state - expanded with animation */
|
|
286
|
-
.searchtab.search-active a {
|
|
287
|
-
max-width: 200px;
|
|
288
|
-
min-width: auto;
|
|
289
|
-
width: auto;
|
|
290
|
-
padding: 0.5rem 0.75rem;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
.searchtab.search-active input {
|
|
294
|
-
opacity: 1;
|
|
295
|
-
transition-delay: 0.15s;
|
|
296
|
-
}
|
|
297
|
-
</style>
|
package/src/index.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import ActionSet from './components/ActionSet.vue'
|
|
2
|
-
import CommandPalette from './components/CommandPalette.vue'
|
|
3
|
-
import Desktop from './components/Desktop.vue'
|
|
4
|
-
import SheetNav from './components/SheetNav.vue'
|
|
5
|
-
import StonecropDesktop from './plugins'
|
|
6
|
-
export type * from './types'
|
|
7
|
-
export type { RouteAdapter, NavigationTarget, ActionEventPayload, RecordOpenEventPayload } from './types'
|
|
8
|
-
|
|
9
|
-
export { ActionSet, CommandPalette, Desktop, SheetNav, StonecropDesktop }
|
package/src/plugins/index.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { App, type Plugin } from 'vue'
|
|
2
|
-
|
|
3
|
-
import ActionSet from '../components/ActionSet.vue'
|
|
4
|
-
import CommandPalette from '../components/CommandPalette.vue'
|
|
5
|
-
import Desktop from '../components/Desktop.vue'
|
|
6
|
-
import SheetNav from '../components/SheetNav.vue'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* This is the main plugin that will be used to register all the desktop components.
|
|
10
|
-
* @public
|
|
11
|
-
*/
|
|
12
|
-
const plugin: Plugin = {
|
|
13
|
-
install: (app: App) => {
|
|
14
|
-
app.component('ActionSet', ActionSet)
|
|
15
|
-
app.component('CommandPalette', CommandPalette)
|
|
16
|
-
app.component('Desktop', Desktop)
|
|
17
|
-
app.component('SheetNav', SheetNav)
|
|
18
|
-
},
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export default plugin
|
package/src/shims-vue.d.ts
DELETED
package/src/types/index.ts
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Base type for elements in the Action Set
|
|
3
|
-
* @public
|
|
4
|
-
*/
|
|
5
|
-
export type BaseElement = {
|
|
6
|
-
label: string
|
|
7
|
-
show?: boolean
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Element actions
|
|
12
|
-
* @public
|
|
13
|
-
*/
|
|
14
|
-
export type ElementAction = BaseElement & {
|
|
15
|
-
link?: string
|
|
16
|
-
action?: () => void
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Button elements
|
|
21
|
-
* @public
|
|
22
|
-
*/
|
|
23
|
-
export type ButtonElement = BaseElement &
|
|
24
|
-
ElementAction & {
|
|
25
|
-
type: 'button'
|
|
26
|
-
disabled?: boolean
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Dropdown elements
|
|
31
|
-
* @public
|
|
32
|
-
*/
|
|
33
|
-
export type DropdownElement = BaseElement & {
|
|
34
|
-
type: 'dropdown'
|
|
35
|
-
actions: ElementAction[]
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Superset of all element types in the Action Set
|
|
40
|
-
* @public
|
|
41
|
-
*/
|
|
42
|
-
export type ActionElements = ButtonElement | DropdownElement
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Navigation target passed to RouteAdapter.navigate and emitted with the 'navigate' event
|
|
46
|
-
* @public
|
|
47
|
-
*/
|
|
48
|
-
export type NavigationTarget = {
|
|
49
|
-
view: 'doctypes' | 'records' | 'record'
|
|
50
|
-
doctype?: string
|
|
51
|
-
recordId?: string
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Adapter that lets host applications (Nuxt, etc.) supply their own routing layer.
|
|
56
|
-
* When provided as a prop, Desktop uses these functions instead of reaching into
|
|
57
|
-
* the Vue Router instance baked into the Stonecrop registry.
|
|
58
|
-
* @public
|
|
59
|
-
*/
|
|
60
|
-
export type RouteAdapter = {
|
|
61
|
-
/** Returns the active doctype key (e.g. 'plan', 'recipe'). Called inside computed — should read reactive state. */
|
|
62
|
-
getCurrentDoctype: () => string
|
|
63
|
-
/** Returns the active record ID, or '' when viewing a list. Called inside computed. */
|
|
64
|
-
getCurrentRecordId: () => string
|
|
65
|
-
/** Returns which of the three views is currently active. Called inside computed. */
|
|
66
|
-
getCurrentView: () => 'doctypes' | 'records' | 'record'
|
|
67
|
-
/** Perform the navigation. Called after the host app has handled any side effects. */
|
|
68
|
-
navigate: (target: NavigationTarget) => void | Promise<void>
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Payload emitted with the 'action' event when the user triggers a declared action.
|
|
73
|
-
*
|
|
74
|
-
* Re-exported, not defined here: the shell emits it and `useClientAction` consumes it, and those
|
|
75
|
-
* now live in different packages. It is declared in `@stonecrop/stonecrop` — which this package
|
|
76
|
-
* already depends on — so the two cannot drift. Importing it from `@stonecrop/desktop` still
|
|
77
|
-
* works and is still the natural place for a host to reach for it.
|
|
78
|
-
*
|
|
79
|
-
* @public
|
|
80
|
-
*/
|
|
81
|
-
export type { ActionEventPayload } from '@stonecrop/stonecrop'
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Payload emitted with the 'record:open' event
|
|
85
|
-
* @public
|
|
86
|
-
*/
|
|
87
|
-
export type RecordOpenEventPayload = {
|
|
88
|
-
doctype: string
|
|
89
|
-
recordId: string
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Payload emitted with the 'load-records' event when Desktop needs records for a list view
|
|
94
|
-
* @public
|
|
95
|
-
*/
|
|
96
|
-
export type LoadRecordsEventPayload = {
|
|
97
|
-
doctype: string
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Payload emitted with the 'load-record' event when Desktop needs a single record
|
|
102
|
-
* @public
|
|
103
|
-
*/
|
|
104
|
-
export type LoadRecordEventPayload = {
|
|
105
|
-
doctype: string
|
|
106
|
-
recordId: string
|
|
107
|
-
}
|