@owdproject/core 3.2.0 → 3.3.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/bin/lib/migrateModulePlayground.config.mjs +4 -4
- package/bin/lib/validateModule.js +14 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +86 -38
- package/module.ts +35 -24
- package/package.json +5 -2
- package/runtime/components/{Core/Application/CoreApplicationRender.vue → Desktop/Application/DesktopApplicationRender.vue} +1 -1
- package/runtime/components/{Core/Application/CoreApplicationWindowsRender.vue → Desktop/Application/DesktopApplicationWindowsRender.vue} +3 -5
- package/runtime/composables/useApplicationManager.ts +1 -1
- package/runtime/composables/useDesktopManager.ts +3 -3
- package/runtime/composables/{useWorkspaceOverview.ts → useWorkspaceManager.ts} +2 -2
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +17 -0
- package/runtime/stores/storeDesktop.ts +0 -11
- package/runtime/utils/splitDesktopUserConfig.ts +85 -0
- package/runtime/utils/utilCommon.ts +0 -32
- package/runtime/utils/utilDesktop.ts +27 -2
- package/runtime/utils/{validateOwdUserConfig.ts → validateDesktopUserConfig.ts} +1 -1
- package/types/index.d.ts +0 -19
- package/runtime/components/Core/Explorer/CoreExplorerFile.vue +0 -76
- package/runtime/components/Core/Explorer/CoreExplorerFolder.vue +0 -10
- package/runtime/composables/useOwdDialogs.ts +0 -13
- package/runtime/dialogs/owdDialogProvider.ts +0 -81
- package/runtime/plugins/01.owd-dialogs-fallback.ts +0 -15
- package/runtime/stores/storeDesktopExplorer.ts +0 -74
- /package/runtime/components/{Core/Background/CoreBackground.vue → Desktop/Background/DesktopBackground.vue} +0 -0
- /package/runtime/components/{Core/Desktop/CoreDesktop.vue → Desktop/Core/DesktopCore.vue} +0 -0
- /package/runtime/components/{Core/Time/CoreTime.vue → Desktop/Time/DesktopTime.vue} +0 -0
- /package/runtime/components/{Core/Window/CoreWindow.vue → Desktop/Window/DesktopWindow.vue} +0 -0
- /package/runtime/components/{Core/Window/CoreWindowContent.vue → Desktop/Window/DesktopWindowContent.vue} +0 -0
- /package/runtime/components/{Core/Window/CoreWindowNav.vue → Desktop/Window/DesktopWindowNav.vue} +0 -0
- /package/runtime/{core → internal}/controllers/ApplicationController.ts +0 -0
- /package/runtime/{core → internal}/controllers/WindowController.ts +0 -0
|
@@ -104,8 +104,8 @@ export const configs = [
|
|
|
104
104
|
fsMounts: { '/mnt/test': '/test.zip' },
|
|
105
105
|
copyTestZip: true,
|
|
106
106
|
playgroundExtraDevDeps: {
|
|
107
|
-
'@owdproject/module-fs': '
|
|
108
|
-
'@owdproject/module-persistence': '
|
|
107
|
+
'@owdproject/module-fs': '^0.0.4',
|
|
108
|
+
'@owdproject/module-persistence': '^0.0.2',
|
|
109
109
|
},
|
|
110
110
|
launch: {
|
|
111
111
|
file: 'launch-audioplayer.client.ts',
|
|
@@ -143,8 +143,8 @@ export const configs = [
|
|
|
143
143
|
fsMounts: { '/mnt/test': '/test.zip' },
|
|
144
144
|
copyTestZip: true,
|
|
145
145
|
playgroundExtraDevDeps: {
|
|
146
|
-
'@owdproject/module-fs': '
|
|
147
|
-
'@owdproject/module-persistence': '
|
|
146
|
+
'@owdproject/module-fs': '^0.0.4',
|
|
147
|
+
'@owdproject/module-persistence': '^0.0.2',
|
|
148
148
|
'@owdproject/kit-fs': 'workspace:*',
|
|
149
149
|
'@owdproject/kit-explorer': 'workspace:*',
|
|
150
150
|
},
|
|
@@ -295,6 +295,20 @@ export function validateOwdModule(packageDir, options = {}) {
|
|
|
295
295
|
if (scripts['prepack'] && !scripts['prepack'].includes('nuxt-module-build')) {
|
|
296
296
|
issue('error', 'prepack-builder', 'prepack must run nuxt-module-build build')
|
|
297
297
|
}
|
|
298
|
+
if (scripts.prepare) {
|
|
299
|
+
issue(
|
|
300
|
+
'error',
|
|
301
|
+
'no-prepare-script',
|
|
302
|
+
'Do not add a "prepare" script on publishable packages — it runs on npm publish/install and breaks release. Use "prepack" (full build) and "dev:prepare" (local stub + playground) only.',
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
if (!rootExport?.development?.includes('src/module')) {
|
|
306
|
+
issue(
|
|
307
|
+
'warning',
|
|
308
|
+
'exports-development',
|
|
309
|
+
'exports["."].development should point to ./src/module.ts (monorepo dev without manual stub after every edit)',
|
|
310
|
+
)
|
|
311
|
+
}
|
|
298
312
|
if (!scripts['dev:generate']?.includes('NUXT_APP_BASE_URL')) {
|
|
299
313
|
issue(
|
|
300
314
|
'warning',
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,28 +1,9 @@
|
|
|
1
1
|
import { defineNuxtModule, createResolver, installModule, addComponentsDir, addPlugin, addImportsDir } from '@nuxt/kit';
|
|
2
|
+
import { defu } from 'defu';
|
|
2
3
|
import { existsSync } from 'node:fs';
|
|
3
4
|
import { join } from 'node:path';
|
|
4
5
|
|
|
5
|
-
function
|
|
6
|
-
function isObject(value) {
|
|
7
|
-
return value !== null && typeof value === "object" && !Array.isArray(value) && !(value instanceof Date) && !(value instanceof RegExp);
|
|
8
|
-
}
|
|
9
|
-
if (isObject(target) && isObject(source)) {
|
|
10
|
-
const result = { ...target };
|
|
11
|
-
for (const key in source) {
|
|
12
|
-
const targetValue = target[key];
|
|
13
|
-
const sourceValue = source[key];
|
|
14
|
-
if (isObject(sourceValue) && isObject(targetValue)) {
|
|
15
|
-
result[key] = deepMerge(targetValue, sourceValue);
|
|
16
|
-
} else {
|
|
17
|
-
result[key] = sourceValue;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return result;
|
|
21
|
-
}
|
|
22
|
-
return source;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function assertValidOwdUserConfig(config, configFile = "desktop.config.ts") {
|
|
6
|
+
function assertValidDesktopUserConfig(config, configFile = "desktop.config.ts") {
|
|
26
7
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
27
8
|
throw new Error(
|
|
28
9
|
`[@owdproject/core] ${configFile} must default-export a non-array object from defineDesktopConfig({ ... }).`
|
|
@@ -82,7 +63,62 @@ function warnLegacyDesktopConfig(resolved) {
|
|
|
82
63
|
}
|
|
83
64
|
}
|
|
84
65
|
|
|
85
|
-
const
|
|
66
|
+
const DESKTOP_MODULE_KEYS = ["theme", "apps", "modules"];
|
|
67
|
+
const DESKTOP_RUNTIME_KEYS = /* @__PURE__ */ new Set([
|
|
68
|
+
...DESKTOP_MODULE_KEYS,
|
|
69
|
+
"docs",
|
|
70
|
+
"name",
|
|
71
|
+
"defaultApps",
|
|
72
|
+
"features",
|
|
73
|
+
"explorer",
|
|
74
|
+
"systemBar",
|
|
75
|
+
"dockBar",
|
|
76
|
+
"workspaces"
|
|
77
|
+
]);
|
|
78
|
+
const NUXT_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
79
|
+
"ssr",
|
|
80
|
+
"modules",
|
|
81
|
+
"devtools",
|
|
82
|
+
"vite",
|
|
83
|
+
"nitro",
|
|
84
|
+
"runtimeConfig",
|
|
85
|
+
"app",
|
|
86
|
+
"appConfig",
|
|
87
|
+
"css",
|
|
88
|
+
"plugins",
|
|
89
|
+
"hooks",
|
|
90
|
+
"extends",
|
|
91
|
+
"compatibilityDate",
|
|
92
|
+
"experimental",
|
|
93
|
+
"future",
|
|
94
|
+
"i18n",
|
|
95
|
+
"tailwindcss",
|
|
96
|
+
"primevue"
|
|
97
|
+
]);
|
|
98
|
+
function splitDesktopUserConfig(config, configFile = "desktop.config.ts") {
|
|
99
|
+
const theme = typeof config.theme === "string" ? config.theme : void 0;
|
|
100
|
+
const apps = Array.isArray(config.apps) ? config.apps : void 0;
|
|
101
|
+
const modules = Array.isArray(config.modules) ? config.modules : void 0;
|
|
102
|
+
const desktopRuntime = {};
|
|
103
|
+
for (const [key, value] of Object.entries(config)) {
|
|
104
|
+
if (DESKTOP_MODULE_KEYS.includes(key)) {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
desktopRuntime[key] = value;
|
|
108
|
+
if (NUXT_OPTION_KEYS.has(key)) {
|
|
109
|
+
console.warn(
|
|
110
|
+
`[@owdproject/core] ${configFile}: key "${key}" looks like a Nuxt option and is ignored for _nuxt.options. Move it to nuxt.config.ts; shell values belong under defineDesktopConfig({ systemBar, workspaces, ... }).`
|
|
111
|
+
);
|
|
112
|
+
} else if (!DESKTOP_RUNTIME_KEYS.has(key)) {
|
|
113
|
+
console.warn(
|
|
114
|
+
`[@owdproject/core] ${configFile}: unknown desktop key "${key}" \u2014 merged into runtimeConfig.public.desktop only.`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return { theme, apps, modules, desktopRuntime };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const version = "3.3.0";
|
|
86
122
|
const pkg = {
|
|
87
123
|
version: version};
|
|
88
124
|
|
|
@@ -119,21 +155,27 @@ const module$1 = defineNuxtModule({
|
|
|
119
155
|
{ cause: e }
|
|
120
156
|
);
|
|
121
157
|
}
|
|
122
|
-
|
|
158
|
+
assertValidDesktopUserConfig(clientConfig, resolvedConfig.file);
|
|
123
159
|
if (!clientConfig.theme) {
|
|
124
160
|
clientConfig.theme = "@owdproject/theme-nova";
|
|
125
161
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
162
|
+
const {
|
|
163
|
+
theme: configTheme,
|
|
164
|
+
apps: configApps,
|
|
165
|
+
modules: configModules,
|
|
166
|
+
desktopRuntime
|
|
167
|
+
} = splitDesktopUserConfig(
|
|
168
|
+
clientConfig,
|
|
169
|
+
resolvedConfig.file
|
|
170
|
+
);
|
|
171
|
+
clientConfig.theme = configTheme ?? clientConfig.theme;
|
|
172
|
+
if (configApps) clientConfig.apps = configApps;
|
|
173
|
+
if (configModules) clientConfig.modules = configModules;
|
|
174
|
+
_nuxt.options.runtimeConfig.public.desktop = defu(
|
|
175
|
+
desktopRuntime,
|
|
176
|
+
{ coreVersion: pkg.version }
|
|
136
177
|
);
|
|
178
|
+
await installModule("@pinia/nuxt");
|
|
137
179
|
{
|
|
138
180
|
if (clientConfig.theme) {
|
|
139
181
|
await installModule(clientConfig.theme);
|
|
@@ -154,6 +196,13 @@ const module$1 = defineNuxtModule({
|
|
|
154
196
|
_nuxt.options.primevue = _nuxt.options.primevue || {};
|
|
155
197
|
_nuxt.options.primevue.options = _nuxt.options.primevue.options || {};
|
|
156
198
|
_nuxt.options.primevue.options.theme = _nuxt.options.primevue.options.theme || {};
|
|
199
|
+
_nuxt.options.primevue.components = _nuxt.options.primevue.components || {};
|
|
200
|
+
const include = _nuxt.options.primevue.components.include;
|
|
201
|
+
if (include && include !== "*" && Array.isArray(include)) {
|
|
202
|
+
if (!include.includes("ConfirmDialog")) {
|
|
203
|
+
include.push("ConfirmDialog");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
157
206
|
await installModule("@primevue/nuxt-module");
|
|
158
207
|
}
|
|
159
208
|
{
|
|
@@ -166,9 +215,6 @@ const module$1 = defineNuxtModule({
|
|
|
166
215
|
viewer: false
|
|
167
216
|
});
|
|
168
217
|
}
|
|
169
|
-
{
|
|
170
|
-
await installModule("@pinia/nuxt");
|
|
171
|
-
}
|
|
172
218
|
{
|
|
173
219
|
await installModule("@nuxt/fonts");
|
|
174
220
|
}
|
|
@@ -202,14 +248,16 @@ const module$1 = defineNuxtModule({
|
|
|
202
248
|
addComponentsDir({
|
|
203
249
|
path: resolve("./runtime/components"),
|
|
204
250
|
prefix: "",
|
|
251
|
+
pathPrefix: false,
|
|
205
252
|
global: true
|
|
206
253
|
});
|
|
207
254
|
}
|
|
208
255
|
{
|
|
209
256
|
addPlugin(resolve("./runtime/plugins/resize.client.ts"));
|
|
210
|
-
addPlugin(
|
|
257
|
+
addPlugin(
|
|
258
|
+
resolve("./runtime/plugins/02.desktop-register-desktop-apps.client.ts")
|
|
259
|
+
);
|
|
211
260
|
addImportsDir(resolve("./runtime/composables"));
|
|
212
|
-
addImportsDir(resolve("./runtime/core"));
|
|
213
261
|
addImportsDir(resolve("./runtime/stores"));
|
|
214
262
|
addImportsDir(resolve("./runtime/utils"));
|
|
215
263
|
}
|
package/module.ts
CHANGED
|
@@ -6,12 +6,13 @@ import {
|
|
|
6
6
|
installModule,
|
|
7
7
|
addPlugin
|
|
8
8
|
} from '@nuxt/kit'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { defu } from 'defu'
|
|
10
|
+
import { assertValidDesktopUserConfig } from './runtime/utils/validateDesktopUserConfig'
|
|
11
11
|
import {
|
|
12
12
|
resolveDesktopConfigPath,
|
|
13
13
|
warnLegacyDesktopConfig,
|
|
14
14
|
} from './runtime/utils/resolveDesktopConfigPath'
|
|
15
|
+
import { splitDesktopUserConfig } from './runtime/utils/splitDesktopUserConfig'
|
|
15
16
|
import pkg from './package.json'
|
|
16
17
|
|
|
17
18
|
export default defineNuxtModule({
|
|
@@ -62,31 +63,37 @@ export default defineNuxtModule({
|
|
|
62
63
|
)
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
assertValidDesktopUserConfig(clientConfig, resolvedConfig.file)
|
|
66
67
|
|
|
67
68
|
if (!clientConfig.theme) {
|
|
68
69
|
clientConfig.theme = '@owdproject/theme-nova'
|
|
69
70
|
}
|
|
70
71
|
|
|
71
|
-
|
|
72
|
+
const {
|
|
73
|
+
theme: configTheme,
|
|
74
|
+
apps: configApps,
|
|
75
|
+
modules: configModules,
|
|
76
|
+
desktopRuntime,
|
|
77
|
+
} = splitDesktopUserConfig(
|
|
78
|
+
clientConfig as Record<string, unknown>,
|
|
79
|
+
resolvedConfig.file,
|
|
80
|
+
)
|
|
72
81
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
82
|
+
clientConfig.theme = configTheme ?? clientConfig.theme
|
|
83
|
+
if (configApps) clientConfig.apps = configApps
|
|
84
|
+
if (configModules) clientConfig.modules = configModules
|
|
77
85
|
|
|
78
86
|
// init desktop runtime config and define core version
|
|
79
87
|
|
|
80
|
-
_nuxt.options.runtimeConfig.public.desktop =
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
// assign open web desktop config to runtime config
|
|
85
|
-
_nuxt.options.runtimeConfig.public.desktop = deepMerge(
|
|
86
|
-
_nuxt.options.runtimeConfig.public.desktop,
|
|
87
|
-
clientConfig
|
|
88
|
+
_nuxt.options.runtimeConfig.public.desktop = defu(
|
|
89
|
+
desktopRuntime,
|
|
90
|
+
{ coreVersion: pkg.version },
|
|
88
91
|
)
|
|
89
92
|
|
|
93
|
+
// Pinia before theme/modules/apps so defineDesktopApp can use stores when
|
|
94
|
+
// published app plugins register on app:created.
|
|
95
|
+
await installModule('@pinia/nuxt')
|
|
96
|
+
|
|
90
97
|
{
|
|
91
98
|
// install open web desktop theme
|
|
92
99
|
|
|
@@ -124,6 +131,14 @@ export default defineNuxtModule({
|
|
|
124
131
|
_nuxt.options.primevue.options = _nuxt.options.primevue.options || {}
|
|
125
132
|
_nuxt.options.primevue.options.theme =
|
|
126
133
|
_nuxt.options.primevue.options.theme || {}
|
|
134
|
+
_nuxt.options.primevue.components =
|
|
135
|
+
_nuxt.options.primevue.components || {}
|
|
136
|
+
const include = _nuxt.options.primevue.components.include
|
|
137
|
+
if (include && include !== '*' && Array.isArray(include)) {
|
|
138
|
+
if (!include.includes('ConfirmDialog')) {
|
|
139
|
+
include.push('ConfirmDialog')
|
|
140
|
+
}
|
|
141
|
+
}
|
|
127
142
|
|
|
128
143
|
await installModule('@primevue/nuxt-module')
|
|
129
144
|
}
|
|
@@ -145,12 +160,6 @@ export default defineNuxtModule({
|
|
|
145
160
|
})
|
|
146
161
|
}
|
|
147
162
|
|
|
148
|
-
{
|
|
149
|
-
// install pinia
|
|
150
|
-
|
|
151
|
-
await installModule('@pinia/nuxt')
|
|
152
|
-
}
|
|
153
|
-
|
|
154
163
|
{
|
|
155
164
|
// install @nuxt/fonts
|
|
156
165
|
|
|
@@ -205,18 +214,20 @@ export default defineNuxtModule({
|
|
|
205
214
|
addComponentsDir({
|
|
206
215
|
path: resolve('./runtime/components'),
|
|
207
216
|
prefix: '',
|
|
217
|
+
pathPrefix: false,
|
|
208
218
|
global: true
|
|
209
219
|
})
|
|
210
220
|
}
|
|
211
221
|
|
|
212
222
|
{
|
|
213
223
|
addPlugin(resolve('./runtime/plugins/resize.client.ts'))
|
|
214
|
-
addPlugin(
|
|
224
|
+
addPlugin(
|
|
225
|
+
resolve('./runtime/plugins/02.desktop-register-desktop-apps.client.ts'),
|
|
226
|
+
)
|
|
215
227
|
|
|
216
228
|
// add other files
|
|
217
229
|
|
|
218
230
|
addImportsDir(resolve('./runtime/composables'))
|
|
219
|
-
addImportsDir(resolve('./runtime/core'))
|
|
220
231
|
addImportsDir(resolve('./runtime/stores'))
|
|
221
232
|
addImportsDir(resolve('./runtime/utils'))
|
|
222
233
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owdproject/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Nuxt Desktop module for browser desktop experiences (windows, shell, apps)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nuxt",
|
|
@@ -41,7 +41,9 @@
|
|
|
41
41
|
"dev": "pnpm run dev:prepare",
|
|
42
42
|
"dev:prepare": "nuxt-module-build build --stub",
|
|
43
43
|
"build:module": "nuxt-module-build build",
|
|
44
|
-
"prepack": "nuxt-module-build build"
|
|
44
|
+
"prepack": "nuxt-module-build build",
|
|
45
|
+
"test": "vitest run",
|
|
46
|
+
"test:watch": "vitest"
|
|
45
47
|
},
|
|
46
48
|
"exports": {
|
|
47
49
|
".": {
|
|
@@ -94,6 +96,7 @@
|
|
|
94
96
|
"shellwords": "^1.1.1",
|
|
95
97
|
"vue-resizable": "^2.1.7",
|
|
96
98
|
"getopts": "^2.3.0",
|
|
99
|
+
"defu": "^6.1.4",
|
|
97
100
|
"neo-blessed": "^0.2.0"
|
|
98
101
|
},
|
|
99
102
|
"optionalDependencies": {
|
|
@@ -31,10 +31,8 @@ function matchesWorkspace(window: IWindowController): boolean {
|
|
|
31
31
|
|
|
32
32
|
<template>
|
|
33
33
|
<template v-for="[windowId, window] in windowEntries" :key="windowId">
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
:is="window.config.component"
|
|
38
|
-
/>
|
|
34
|
+
<Suspense v-if="matchesWorkspace(window)">
|
|
35
|
+
<component :window="window" :is="window.config.component" />
|
|
36
|
+
</Suspense>
|
|
39
37
|
</template>
|
|
40
38
|
</template>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { reactive, markRaw, computed } from 'vue'
|
|
2
|
-
import { ApplicationController } from '../
|
|
2
|
+
import { ApplicationController } from '../internal/controllers/ApplicationController'
|
|
3
3
|
import { normalizeApplicationConfig } from '../utils/utilApp'
|
|
4
4
|
import { debugLog } from '../utils/utilDebug'
|
|
5
5
|
import * as shellwords from 'shellwords'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { computed } from 'vue'
|
|
2
2
|
import { useAppConfig } from 'nuxt/app'
|
|
3
|
-
import {
|
|
3
|
+
import { defu } from 'defu'
|
|
4
4
|
import { useDesktopStore } from '../stores/storeDesktop'
|
|
5
5
|
import { useDesktopDefaultAppsStore } from '../stores/storeDesktopDefaultApps'
|
|
6
6
|
|
|
@@ -17,9 +17,9 @@ export function useDesktopManager() {
|
|
|
17
17
|
* Merges and sets the desktop config at runtime (shell geometry, feature flags, etc.).
|
|
18
18
|
*/
|
|
19
19
|
function setConfig(newConfig: DesktopConfig) {
|
|
20
|
-
appConfig.desktop =
|
|
21
|
-
appConfig.desktop,
|
|
20
|
+
appConfig.desktop = defu(
|
|
22
21
|
newConfig,
|
|
22
|
+
(appConfig.desktop ?? {}) as DesktopConfig,
|
|
23
23
|
) as DesktopConfig
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -3,9 +3,9 @@ import { useApplicationManager } from './useApplicationManager'
|
|
|
3
3
|
import { useDesktopWorkspaceStore } from '../stores/storeDesktopWorkspace'
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* Keyboard + HTML5 drop handlers for workspace
|
|
6
|
+
* Keyboard + HTML5 drop handlers for workspace management (move windows between desktops).
|
|
7
7
|
*/
|
|
8
|
-
export function
|
|
8
|
+
export function useWorkspaceManager() {
|
|
9
9
|
const applicationManager = useApplicationManager()
|
|
10
10
|
const desktopWorkspaceStore = useDesktopWorkspaceStore()
|
|
11
11
|
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { setActivePinia } from 'pinia'
|
|
2
|
+
import { defineNuxtPlugin } from 'nuxt/app'
|
|
3
|
+
import { flushPendingDesktopApps } from '../utils/utilDesktop'
|
|
4
|
+
|
|
5
|
+
export default defineNuxtPlugin({
|
|
6
|
+
name: 'desktop-register-desktop-apps',
|
|
7
|
+
dependsOn: ['pinia'],
|
|
8
|
+
enforce: 'post',
|
|
9
|
+
setup(nuxtApp) {
|
|
10
|
+
nuxtApp.hook('app:created', async () => {
|
|
11
|
+
if (nuxtApp.$pinia) {
|
|
12
|
+
setActivePinia(nuxtApp.$pinia)
|
|
13
|
+
}
|
|
14
|
+
await flushPendingDesktopApps()
|
|
15
|
+
})
|
|
16
|
+
},
|
|
17
|
+
})
|
|
@@ -51,10 +51,6 @@ export const useDesktopStore = defineStore(
|
|
|
51
51
|
window: {
|
|
52
52
|
positionZ: number
|
|
53
53
|
}
|
|
54
|
-
explorer: {
|
|
55
|
-
navExpandedKeys: string[]
|
|
56
|
-
quickAccessPins: { id: string; label: string; path: string; icon?: string }[]
|
|
57
|
-
}
|
|
58
54
|
defaultApps: Record<string, { applicationId: string; entry: string }>
|
|
59
55
|
personalization: DesktopPersonalization
|
|
60
56
|
}>({
|
|
@@ -69,13 +65,6 @@ export const useDesktopStore = defineStore(
|
|
|
69
65
|
window: {
|
|
70
66
|
positionZ: 0,
|
|
71
67
|
},
|
|
72
|
-
explorer: {
|
|
73
|
-
navExpandedKeys: [
|
|
74
|
-
'quickAccess',
|
|
75
|
-
'thisPc',
|
|
76
|
-
],
|
|
77
|
-
quickAccessPins: [],
|
|
78
|
-
},
|
|
79
68
|
defaultApps: {},
|
|
80
69
|
personalization: { ...defaultDesktopPersonalization },
|
|
81
70
|
})
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keys consumed by {@link @owdproject/core} module setup (install order).
|
|
3
|
+
* Must not be spread onto `_nuxt.options`.
|
|
4
|
+
*/
|
|
5
|
+
export const DESKTOP_MODULE_KEYS = ['theme', 'apps', 'modules'] as const
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Known desktop shell keys merged into `runtimeConfig.public.desktop` / `appConfig.desktop`.
|
|
9
|
+
* Additional keys are merged with a dev warning (extensions, theme overrides).
|
|
10
|
+
*/
|
|
11
|
+
export const DESKTOP_RUNTIME_KEYS = new Set([
|
|
12
|
+
...DESKTOP_MODULE_KEYS,
|
|
13
|
+
'docs',
|
|
14
|
+
'name',
|
|
15
|
+
'defaultApps',
|
|
16
|
+
'features',
|
|
17
|
+
'explorer',
|
|
18
|
+
'systemBar',
|
|
19
|
+
'dockBar',
|
|
20
|
+
'workspaces',
|
|
21
|
+
])
|
|
22
|
+
|
|
23
|
+
/** Nuxt top-level option names — warn if present in desktop.config (likely misconfiguration). */
|
|
24
|
+
const NUXT_OPTION_KEYS = new Set([
|
|
25
|
+
'ssr',
|
|
26
|
+
'modules',
|
|
27
|
+
'devtools',
|
|
28
|
+
'vite',
|
|
29
|
+
'nitro',
|
|
30
|
+
'runtimeConfig',
|
|
31
|
+
'app',
|
|
32
|
+
'appConfig',
|
|
33
|
+
'css',
|
|
34
|
+
'plugins',
|
|
35
|
+
'hooks',
|
|
36
|
+
'extends',
|
|
37
|
+
'compatibilityDate',
|
|
38
|
+
'experimental',
|
|
39
|
+
'future',
|
|
40
|
+
'i18n',
|
|
41
|
+
'tailwindcss',
|
|
42
|
+
'primevue',
|
|
43
|
+
])
|
|
44
|
+
|
|
45
|
+
export type SplitDesktopUserConfigResult = {
|
|
46
|
+
theme?: string
|
|
47
|
+
apps?: string[]
|
|
48
|
+
modules?: string[]
|
|
49
|
+
desktopRuntime: Record<string, unknown>
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function splitDesktopUserConfig(
|
|
53
|
+
config: Record<string, unknown>,
|
|
54
|
+
configFile = 'desktop.config.ts',
|
|
55
|
+
): SplitDesktopUserConfigResult {
|
|
56
|
+
const theme =
|
|
57
|
+
typeof config.theme === 'string' ? config.theme : undefined
|
|
58
|
+
const apps = Array.isArray(config.apps)
|
|
59
|
+
? (config.apps as string[])
|
|
60
|
+
: undefined
|
|
61
|
+
const modules = Array.isArray(config.modules)
|
|
62
|
+
? (config.modules as string[])
|
|
63
|
+
: undefined
|
|
64
|
+
|
|
65
|
+
const desktopRuntime: Record<string, unknown> = {}
|
|
66
|
+
|
|
67
|
+
for (const [key, value] of Object.entries(config)) {
|
|
68
|
+
if (DESKTOP_MODULE_KEYS.includes(key as (typeof DESKTOP_MODULE_KEYS)[number])) {
|
|
69
|
+
continue
|
|
70
|
+
}
|
|
71
|
+
desktopRuntime[key] = value
|
|
72
|
+
|
|
73
|
+
if (NUXT_OPTION_KEYS.has(key)) {
|
|
74
|
+
console.warn(
|
|
75
|
+
`[@owdproject/core] ${configFile}: key "${key}" looks like a Nuxt option and is ignored for _nuxt.options. Move it to nuxt.config.ts; shell values belong under defineDesktopConfig({ systemBar, workspaces, ... }).`,
|
|
76
|
+
)
|
|
77
|
+
} else if (!DESKTOP_RUNTIME_KEYS.has(key)) {
|
|
78
|
+
console.warn(
|
|
79
|
+
`[@owdproject/core] ${configFile}: unknown desktop key "${key}" — merged into runtimeConfig.public.desktop only.`,
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { theme, apps, modules, desktopRuntime }
|
|
85
|
+
}
|
|
@@ -24,35 +24,3 @@ export function deepEqual(obj1: any, obj2: any) {
|
|
|
24
24
|
}
|
|
25
25
|
return true
|
|
26
26
|
}
|
|
27
|
-
|
|
28
|
-
export function deepMerge<T>(target: T, source: Partial<T>): T {
|
|
29
|
-
function isObject(value: any): value is Record<string, any> {
|
|
30
|
-
return (
|
|
31
|
-
value !== null &&
|
|
32
|
-
typeof value === 'object' &&
|
|
33
|
-
!Array.isArray(value) &&
|
|
34
|
-
!(value instanceof Date) &&
|
|
35
|
-
!(value instanceof RegExp)
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (isObject(target) && isObject(source)) {
|
|
40
|
-
const result = { ...target }
|
|
41
|
-
|
|
42
|
-
for (const key in source) {
|
|
43
|
-
const targetValue = (target as any)[key]
|
|
44
|
-
const sourceValue = (source as any)[key]
|
|
45
|
-
|
|
46
|
-
if (isObject(sourceValue) && isObject(targetValue)) {
|
|
47
|
-
// @ts-ignore
|
|
48
|
-
result[key] = deepMerge(targetValue, sourceValue)
|
|
49
|
-
} else {
|
|
50
|
-
result[key] = sourceValue
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return result
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return source as T
|
|
58
|
-
}
|
|
@@ -1,8 +1,33 @@
|
|
|
1
|
+
import { getActivePinia } from 'pinia'
|
|
1
2
|
import { useApplicationManager } from '../composables/useApplicationManager'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const pendingDesktopApps: ApplicationConfig[] = []
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Register a desktop app. Queues until Pinia is active when theme/app plugins
|
|
8
|
+
* run before @pinia/nuxt (e.g. published apps using `app:created`).
|
|
9
|
+
*/
|
|
10
|
+
export async function defineDesktopApp(config: ApplicationConfig) {
|
|
11
|
+
if (import.meta.server) return undefined
|
|
12
|
+
|
|
13
|
+
if (getActivePinia()) {
|
|
14
|
+
const applicationManager = useApplicationManager()
|
|
15
|
+
return applicationManager.defineApp(config.id, config)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pendingDesktopApps.push(config)
|
|
19
|
+
return undefined
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export async function flushPendingDesktopApps() {
|
|
23
|
+
if (pendingDesktopApps.length === 0 || !getActivePinia()) return
|
|
24
|
+
|
|
25
|
+
const queue = pendingDesktopApps.splice(0, pendingDesktopApps.length)
|
|
4
26
|
const applicationManager = useApplicationManager()
|
|
5
|
-
|
|
27
|
+
|
|
28
|
+
for (const config of queue) {
|
|
29
|
+
await applicationManager.defineApp(config.id, config)
|
|
30
|
+
}
|
|
6
31
|
}
|
|
7
32
|
|
|
8
33
|
export function defineDesktopConfig(config: DesktopConfig) {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Runtime validation for the object exported from `desktop.config.ts`
|
|
3
3
|
* (or legacy `owd.config.ts`).
|
|
4
4
|
*/
|
|
5
|
-
export function
|
|
5
|
+
export function assertValidDesktopUserConfig(
|
|
6
6
|
config: unknown,
|
|
7
7
|
configFile = 'desktop.config.ts',
|
|
8
8
|
): void {
|
package/types/index.d.ts
CHANGED
|
@@ -360,31 +360,12 @@ interface DesktopConfig {
|
|
|
360
360
|
name?: string
|
|
361
361
|
defaultApps?: DefaultAppsConfig
|
|
362
362
|
features?: string[]
|
|
363
|
-
explorer?: DesktopExplorerConfig
|
|
364
363
|
|
|
365
364
|
systemBar?: DesktopSystemBarConfig
|
|
366
365
|
dockBar?: DesktopDockBarConfig
|
|
367
366
|
workspaces?: DesktopWorkspacesConfig
|
|
368
367
|
}
|
|
369
368
|
|
|
370
|
-
interface DesktopExplorerFolderConfig {
|
|
371
|
-
id: string
|
|
372
|
-
label: string
|
|
373
|
-
path: string
|
|
374
|
-
icon?: string
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
interface DesktopExplorerConfig {
|
|
378
|
-
quickAccess?: DesktopExplorerFolderConfig[]
|
|
379
|
-
quickAccessExtra?: DesktopExplorerFolderConfig[]
|
|
380
|
-
quickAccessOverride?: DesktopExplorerFolderConfig[]
|
|
381
|
-
specialFolders?: DesktopExplorerFolderConfig[]
|
|
382
|
-
specialFoldersExtra?: DesktopExplorerFolderConfig[]
|
|
383
|
-
specialFoldersOverride?: DesktopExplorerFolderConfig[]
|
|
384
|
-
/** Friendly labels for ZenFS mount points shown under “This PC” (paths → label). */
|
|
385
|
-
mountLabels?: Record<string, string>
|
|
386
|
-
}
|
|
387
|
-
|
|
388
369
|
interface DesktopWindowsConfig {
|
|
389
370
|
position: 'relative' | 'absolute' | 'fixed'
|
|
390
371
|
}
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<li
|
|
3
|
-
:class="[
|
|
4
|
-
'owd-explorer-file',
|
|
5
|
-
{ 'owd-explorer-file--inactive': props.inactive },
|
|
6
|
-
]"
|
|
7
|
-
>
|
|
8
|
-
<a
|
|
9
|
-
:href="props.url"
|
|
10
|
-
:target="props.target"
|
|
11
|
-
:title="props.title"
|
|
12
|
-
@click="props.fn"
|
|
13
|
-
>
|
|
14
|
-
<img :src="props.icon" :alt="props.title" />
|
|
15
|
-
<div class="owd-explorer-file__name" v-html="props.name" />
|
|
16
|
-
</a>
|
|
17
|
-
</li>
|
|
18
|
-
</template>
|
|
19
|
-
|
|
20
|
-
<script setup lang="ts">
|
|
21
|
-
const props = defineProps<{
|
|
22
|
-
name: string
|
|
23
|
-
title: string
|
|
24
|
-
icon: string
|
|
25
|
-
url: string
|
|
26
|
-
target: string
|
|
27
|
-
inactive: boolean
|
|
28
|
-
}>()
|
|
29
|
-
</script>
|
|
30
|
-
|
|
31
|
-
<style scoped lang="scss">
|
|
32
|
-
li.file {
|
|
33
|
-
width: 100px;
|
|
34
|
-
margin: 0 5px 5px 0;
|
|
35
|
-
text-align: center;
|
|
36
|
-
float: left;
|
|
37
|
-
border-radius: 2px;
|
|
38
|
-
border: 1px solid rgba(0, 0, 0, 0);
|
|
39
|
-
|
|
40
|
-
@media (max-width: 480px) {
|
|
41
|
-
margin-right: 0;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
@media (min-width: 480px) {
|
|
45
|
-
&:not(.inactive):hover {
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
&.inactive {
|
|
50
|
-
filter: grayscale(100%);
|
|
51
|
-
opacity: 0.2;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
a {
|
|
55
|
-
display: block;
|
|
56
|
-
color: #ccc;
|
|
57
|
-
text-decoration: none;
|
|
58
|
-
transition: color 0.15s ease-in-out;
|
|
59
|
-
padding: 10px 0;
|
|
60
|
-
|
|
61
|
-
img {
|
|
62
|
-
vertical-align: middle;
|
|
63
|
-
height: 32px;
|
|
64
|
-
border-radius: 2px;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
div.name {
|
|
68
|
-
font-size: 12px;
|
|
69
|
-
letter-spacing: -0.2px;
|
|
70
|
-
line-height: 10px;
|
|
71
|
-
margin-top: 10px;
|
|
72
|
-
cursor: pointer;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
</style>
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { inject } from 'vue'
|
|
2
|
-
import {
|
|
3
|
-
OWD_DIALOG_PROVIDER_KEY,
|
|
4
|
-
createBrowserFallbackDialogProvider,
|
|
5
|
-
type OwdDialogProvider,
|
|
6
|
-
} from '../dialogs/owdDialogProvider'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Returns the active desktop dialog provider (theme) or a documented browser fallback.
|
|
10
|
-
*/
|
|
11
|
-
export function useOwdDialogs(): OwdDialogProvider {
|
|
12
|
-
return inject(OWD_DIALOG_PROVIDER_KEY, null) ?? createBrowserFallbackDialogProvider()
|
|
13
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import type { InjectionKey } from 'vue'
|
|
2
|
-
|
|
3
|
-
/** Options for a yes/no confirmation (theme renders labels and chrome). */
|
|
4
|
-
export interface OwdConfirmDialogOptions {
|
|
5
|
-
title?: string
|
|
6
|
-
message: string
|
|
7
|
-
danger?: boolean
|
|
8
|
-
acceptLabel?: string
|
|
9
|
-
rejectLabel?: string
|
|
10
|
-
/**
|
|
11
|
-
* Theme-specific payload (e.g. Win95 delete dialog passes `toTrash` for slot templates).
|
|
12
|
-
*/
|
|
13
|
-
extras?: Record<string, unknown>
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Cross-theme dialog API. Themes implement with PrimeVue, GNOME dialogs, etc.
|
|
18
|
-
* Callers pass user-facing strings (usually from i18n); implementations only render.
|
|
19
|
-
*/
|
|
20
|
-
export interface OwdDialogProvider {
|
|
21
|
-
confirm(options: OwdConfirmDialogOptions): Promise<boolean>
|
|
22
|
-
alert(message: string, options?: { title?: string }): Promise<void>
|
|
23
|
-
prompt(
|
|
24
|
-
message: string,
|
|
25
|
-
defaultValue?: string,
|
|
26
|
-
): Promise<string | null>
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export const OWD_DIALOG_PROVIDER_KEY: InjectionKey<OwdDialogProvider> =
|
|
30
|
-
Symbol('owd-dialog-provider')
|
|
31
|
-
|
|
32
|
-
function browserGlobals(): {
|
|
33
|
-
confirm: (message?: string) => boolean
|
|
34
|
-
alert: (message?: string) => void
|
|
35
|
-
prompt: (message?: string, defaultText?: string) => string | null
|
|
36
|
-
} | null {
|
|
37
|
-
const g = globalThis as typeof globalThis & {
|
|
38
|
-
confirm?: (message?: string) => boolean
|
|
39
|
-
alert?: (message?: string) => void
|
|
40
|
-
prompt?: (message?: string, defaultText?: string) => string | null
|
|
41
|
-
}
|
|
42
|
-
if (typeof g.confirm !== 'function') return null
|
|
43
|
-
return {
|
|
44
|
-
confirm: g.confirm.bind(g),
|
|
45
|
-
alert:
|
|
46
|
-
typeof g.alert === 'function'
|
|
47
|
-
? g.alert.bind(g)
|
|
48
|
-
: (m?: string) => {
|
|
49
|
-
void m
|
|
50
|
-
},
|
|
51
|
-
prompt:
|
|
52
|
-
typeof g.prompt === 'function'
|
|
53
|
-
? g.prompt.bind(g)
|
|
54
|
-
: () => null,
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export function createBrowserFallbackDialogProvider(): OwdDialogProvider {
|
|
59
|
-
return {
|
|
60
|
-
async confirm(opts) {
|
|
61
|
-
if (import.meta.server) return false
|
|
62
|
-
const w = browserGlobals()
|
|
63
|
-
if (!w) return false
|
|
64
|
-
const text = [opts.title, opts.message].filter(Boolean).join('\n\n')
|
|
65
|
-
return w.confirm(text)
|
|
66
|
-
},
|
|
67
|
-
async alert(message, opts) {
|
|
68
|
-
if (import.meta.server) return
|
|
69
|
-
const w = browserGlobals()
|
|
70
|
-
if (!w) return
|
|
71
|
-
w.alert([opts?.title, message].filter(Boolean).join('\n\n'))
|
|
72
|
-
},
|
|
73
|
-
async prompt(message, defaultValue = '') {
|
|
74
|
-
if (import.meta.server) return null
|
|
75
|
-
const w = browserGlobals()
|
|
76
|
-
if (!w) return null
|
|
77
|
-
const v = w.prompt(message, defaultValue)
|
|
78
|
-
return v === null ? null : v
|
|
79
|
-
},
|
|
80
|
-
}
|
|
81
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { defineNuxtPlugin } from 'nuxt/app'
|
|
2
|
-
import {
|
|
3
|
-
OWD_DIALOG_PROVIDER_KEY,
|
|
4
|
-
createBrowserFallbackDialogProvider,
|
|
5
|
-
} from '../dialogs/owdDialogProvider'
|
|
6
|
-
|
|
7
|
-
export default defineNuxtPlugin({
|
|
8
|
-
name: 'owd-dialogs-fallback',
|
|
9
|
-
setup(nuxtApp) {
|
|
10
|
-
nuxtApp.vueApp.provide(
|
|
11
|
-
OWD_DIALOG_PROVIDER_KEY,
|
|
12
|
-
createBrowserFallbackDialogProvider(),
|
|
13
|
-
)
|
|
14
|
-
},
|
|
15
|
-
})
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
import { defineStore } from 'pinia'
|
|
2
|
-
import { computed } from 'vue'
|
|
3
|
-
import { useDesktopStore } from './storeDesktop'
|
|
4
|
-
|
|
5
|
-
type ExplorerQuickAccessPin = {
|
|
6
|
-
id: string
|
|
7
|
-
label: string
|
|
8
|
-
path: string
|
|
9
|
-
icon?: string
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export const useDesktopExplorerStore = defineStore(
|
|
13
|
-
'owd/desktop/explorer',
|
|
14
|
-
() => {
|
|
15
|
-
const desktopStore = useDesktopStore()
|
|
16
|
-
|
|
17
|
-
const navExpandedKeys = computed(
|
|
18
|
-
() => desktopStore.state.explorer.navExpandedKeys,
|
|
19
|
-
)
|
|
20
|
-
const quickAccessPins = computed(
|
|
21
|
-
() => desktopStore.state.explorer.quickAccessPins,
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
function setNavExpandedKeys(keys: string[]) {
|
|
25
|
-
desktopStore.state.explorer.navExpandedKeys = [...new Set(keys)]
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function setQuickAccessPins(pins: ExplorerQuickAccessPin[]) {
|
|
29
|
-
desktopStore.state.explorer.quickAccessPins = pins
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function pinQuickAccess(entry: ExplorerQuickAccessPin) {
|
|
33
|
-
const exists = desktopStore.state.explorer.quickAccessPins.some(
|
|
34
|
-
(pin) => pin.path === entry.path,
|
|
35
|
-
)
|
|
36
|
-
if (exists) return
|
|
37
|
-
desktopStore.state.explorer.quickAccessPins.push(entry)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function unpinQuickAccess(path: string) {
|
|
41
|
-
desktopStore.state.explorer.quickAccessPins =
|
|
42
|
-
desktopStore.state.explorer.quickAccessPins.filter(
|
|
43
|
-
(pin) => pin.path !== path,
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function reorderQuickAccess(startIndex: number, endIndex: number) {
|
|
48
|
-
const list = [...desktopStore.state.explorer.quickAccessPins]
|
|
49
|
-
if (
|
|
50
|
-
startIndex < 0 ||
|
|
51
|
-
endIndex < 0 ||
|
|
52
|
-
startIndex >= list.length ||
|
|
53
|
-
endIndex >= list.length ||
|
|
54
|
-
startIndex === endIndex
|
|
55
|
-
) {
|
|
56
|
-
return
|
|
57
|
-
}
|
|
58
|
-
const [item] = list.splice(startIndex, 1)
|
|
59
|
-
if (!item) return
|
|
60
|
-
list.splice(endIndex, 0, item)
|
|
61
|
-
desktopStore.state.explorer.quickAccessPins = list
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
navExpandedKeys,
|
|
66
|
-
quickAccessPins,
|
|
67
|
-
setNavExpandedKeys,
|
|
68
|
-
setQuickAccessPins,
|
|
69
|
-
pinQuickAccess,
|
|
70
|
-
unpinQuickAccess,
|
|
71
|
-
reorderQuickAccess,
|
|
72
|
-
}
|
|
73
|
-
},
|
|
74
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/runtime/components/{Core/Window/CoreWindowNav.vue → Desktop/Window/DesktopWindowNav.vue}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|