@owdproject/core 3.2.0 → 3.3.1
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 +110 -61
- package/module.ts +64 -65
- package/package.json +6 -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,10 +63,82 @@ 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.1";
|
|
86
122
|
const pkg = {
|
|
87
123
|
version: version};
|
|
88
124
|
|
|
125
|
+
function primevueModuleDependency(nuxt) {
|
|
126
|
+
const existing = nuxt.options.primevue ?? {};
|
|
127
|
+
const components = { ...existing.components ?? {} };
|
|
128
|
+
const include = components.include;
|
|
129
|
+
if (include && include !== "*" && Array.isArray(include) && !include.includes("ConfirmDialog")) {
|
|
130
|
+
components.include = [...include, "ConfirmDialog"];
|
|
131
|
+
}
|
|
132
|
+
return {
|
|
133
|
+
defaults: defu(
|
|
134
|
+
{
|
|
135
|
+
options: { theme: {} },
|
|
136
|
+
components
|
|
137
|
+
},
|
|
138
|
+
existing
|
|
139
|
+
)
|
|
140
|
+
};
|
|
141
|
+
}
|
|
89
142
|
const module$1 = defineNuxtModule({
|
|
90
143
|
meta: {
|
|
91
144
|
name: "desktop",
|
|
@@ -96,6 +149,21 @@ const module$1 = defineNuxtModule({
|
|
|
96
149
|
apps: [],
|
|
97
150
|
modules: []
|
|
98
151
|
},
|
|
152
|
+
moduleDependencies: (nuxt) => ({
|
|
153
|
+
"@pinia/nuxt": {},
|
|
154
|
+
"@primevue/nuxt-module": primevueModuleDependency(nuxt),
|
|
155
|
+
"@nuxt/fonts": {},
|
|
156
|
+
"@nuxt/icon": {
|
|
157
|
+
defaults: {
|
|
158
|
+
clientBundle: {
|
|
159
|
+
scan: true,
|
|
160
|
+
sizeLimitKb: 256
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
"@vueuse/nuxt": {},
|
|
165
|
+
"@nuxtjs/i18n": {}
|
|
166
|
+
}),
|
|
99
167
|
async setup(_options, _nuxt) {
|
|
100
168
|
const { resolve } = createResolver(import.meta.url);
|
|
101
169
|
_nuxt.options.experimental = {
|
|
@@ -119,20 +187,25 @@ const module$1 = defineNuxtModule({
|
|
|
119
187
|
{ cause: e }
|
|
120
188
|
);
|
|
121
189
|
}
|
|
122
|
-
|
|
190
|
+
assertValidDesktopUserConfig(clientConfig, resolvedConfig.file);
|
|
123
191
|
if (!clientConfig.theme) {
|
|
124
192
|
clientConfig.theme = "@owdproject/theme-nova";
|
|
125
193
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
194
|
+
const {
|
|
195
|
+
theme: configTheme,
|
|
196
|
+
apps: configApps,
|
|
197
|
+
modules: configModules,
|
|
198
|
+
desktopRuntime
|
|
199
|
+
} = splitDesktopUserConfig(
|
|
200
|
+
clientConfig,
|
|
201
|
+
resolvedConfig.file
|
|
202
|
+
);
|
|
203
|
+
clientConfig.theme = configTheme ?? clientConfig.theme;
|
|
204
|
+
if (configApps) clientConfig.apps = configApps;
|
|
205
|
+
if (configModules) clientConfig.modules = configModules;
|
|
206
|
+
_nuxt.options.runtimeConfig.public.desktop = defu(
|
|
207
|
+
desktopRuntime,
|
|
208
|
+
{ coreVersion: pkg.version }
|
|
136
209
|
);
|
|
137
210
|
{
|
|
138
211
|
if (clientConfig.theme) {
|
|
@@ -150,12 +223,6 @@ const module$1 = defineNuxtModule({
|
|
|
150
223
|
}
|
|
151
224
|
}
|
|
152
225
|
_nuxt.options.appConfig.desktop = _nuxt.options.runtimeConfig.public.desktop;
|
|
153
|
-
{
|
|
154
|
-
_nuxt.options.primevue = _nuxt.options.primevue || {};
|
|
155
|
-
_nuxt.options.primevue.options = _nuxt.options.primevue.options || {};
|
|
156
|
-
_nuxt.options.primevue.options.theme = _nuxt.options.primevue.options.theme || {};
|
|
157
|
-
await installModule("@primevue/nuxt-module");
|
|
158
|
-
}
|
|
159
226
|
{
|
|
160
227
|
const tailwindPaths = _nuxt.options.runtimeConfig.app.owd?.tailwindPaths || [];
|
|
161
228
|
tailwindPaths.push("./runtime/components/**/*.{vue,mjs,ts}");
|
|
@@ -166,26 +233,6 @@ const module$1 = defineNuxtModule({
|
|
|
166
233
|
viewer: false
|
|
167
234
|
});
|
|
168
235
|
}
|
|
169
|
-
{
|
|
170
|
-
await installModule("@pinia/nuxt");
|
|
171
|
-
}
|
|
172
|
-
{
|
|
173
|
-
await installModule("@nuxt/fonts");
|
|
174
|
-
}
|
|
175
|
-
{
|
|
176
|
-
await installModule("@nuxt/icon", {
|
|
177
|
-
clientBundle: {
|
|
178
|
-
scan: true,
|
|
179
|
-
sizeLimitKb: 256
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
{
|
|
184
|
-
await installModule("@vueuse/nuxt");
|
|
185
|
-
}
|
|
186
|
-
{
|
|
187
|
-
await installModule("@nuxtjs/i18n");
|
|
188
|
-
}
|
|
189
236
|
{
|
|
190
237
|
_nuxt.hook("vite:extendConfig", (viteConfig) => {
|
|
191
238
|
viteConfig.css = viteConfig.css || {};
|
|
@@ -202,14 +249,16 @@ const module$1 = defineNuxtModule({
|
|
|
202
249
|
addComponentsDir({
|
|
203
250
|
path: resolve("./runtime/components"),
|
|
204
251
|
prefix: "",
|
|
252
|
+
pathPrefix: false,
|
|
205
253
|
global: true
|
|
206
254
|
});
|
|
207
255
|
}
|
|
208
256
|
{
|
|
209
257
|
addPlugin(resolve("./runtime/plugins/resize.client.ts"));
|
|
210
|
-
addPlugin(
|
|
258
|
+
addPlugin(
|
|
259
|
+
resolve("./runtime/plugins/02.desktop-register-desktop-apps.client.ts")
|
|
260
|
+
);
|
|
211
261
|
addImportsDir(resolve("./runtime/composables"));
|
|
212
|
-
addImportsDir(resolve("./runtime/core"));
|
|
213
262
|
addImportsDir(resolve("./runtime/stores"));
|
|
214
263
|
addImportsDir(resolve("./runtime/utils"));
|
|
215
264
|
}
|
package/module.ts
CHANGED
|
@@ -6,14 +6,40 @@ import {
|
|
|
6
6
|
installModule,
|
|
7
7
|
addPlugin
|
|
8
8
|
} from '@nuxt/kit'
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
9
|
+
import { defu } from 'defu'
|
|
10
|
+
import type { Nuxt } from '@nuxt/schema'
|
|
11
|
+
import { assertValidDesktopUserConfig } from './runtime/utils/validateDesktopUserConfig'
|
|
11
12
|
import {
|
|
12
13
|
resolveDesktopConfigPath,
|
|
13
14
|
warnLegacyDesktopConfig,
|
|
14
15
|
} from './runtime/utils/resolveDesktopConfigPath'
|
|
16
|
+
import { splitDesktopUserConfig } from './runtime/utils/splitDesktopUserConfig'
|
|
15
17
|
import pkg from './package.json'
|
|
16
18
|
|
|
19
|
+
function primevueModuleDependency(nuxt: Nuxt) {
|
|
20
|
+
const existing = nuxt.options.primevue ?? {}
|
|
21
|
+
const components = { ...(existing.components ?? {}) }
|
|
22
|
+
const include = components.include
|
|
23
|
+
if (
|
|
24
|
+
include &&
|
|
25
|
+
include !== '*' &&
|
|
26
|
+
Array.isArray(include) &&
|
|
27
|
+
!include.includes('ConfirmDialog')
|
|
28
|
+
) {
|
|
29
|
+
components.include = [...include, 'ConfirmDialog']
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {
|
|
33
|
+
defaults: defu(
|
|
34
|
+
{
|
|
35
|
+
options: { theme: {} },
|
|
36
|
+
components,
|
|
37
|
+
},
|
|
38
|
+
existing,
|
|
39
|
+
),
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
17
43
|
export default defineNuxtModule({
|
|
18
44
|
meta: {
|
|
19
45
|
name: 'desktop',
|
|
@@ -24,6 +50,21 @@ export default defineNuxtModule({
|
|
|
24
50
|
apps: [],
|
|
25
51
|
modules: [],
|
|
26
52
|
},
|
|
53
|
+
moduleDependencies: (nuxt) => ({
|
|
54
|
+
'@pinia/nuxt': {},
|
|
55
|
+
'@primevue/nuxt-module': primevueModuleDependency(nuxt),
|
|
56
|
+
'@nuxt/fonts': {},
|
|
57
|
+
'@nuxt/icon': {
|
|
58
|
+
defaults: {
|
|
59
|
+
clientBundle: {
|
|
60
|
+
scan: true,
|
|
61
|
+
sizeLimitKb: 256,
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
'@vueuse/nuxt': {},
|
|
66
|
+
'@nuxtjs/i18n': {},
|
|
67
|
+
}),
|
|
27
68
|
async setup(_options, _nuxt) {
|
|
28
69
|
const { resolve } = createResolver(import.meta.url)
|
|
29
70
|
|
|
@@ -62,29 +103,31 @@ export default defineNuxtModule({
|
|
|
62
103
|
)
|
|
63
104
|
}
|
|
64
105
|
|
|
65
|
-
|
|
106
|
+
assertValidDesktopUserConfig(clientConfig, resolvedConfig.file)
|
|
66
107
|
|
|
67
108
|
if (!clientConfig.theme) {
|
|
68
109
|
clientConfig.theme = '@owdproject/theme-nova'
|
|
69
110
|
}
|
|
70
111
|
|
|
71
|
-
|
|
112
|
+
const {
|
|
113
|
+
theme: configTheme,
|
|
114
|
+
apps: configApps,
|
|
115
|
+
modules: configModules,
|
|
116
|
+
desktopRuntime,
|
|
117
|
+
} = splitDesktopUserConfig(
|
|
118
|
+
clientConfig as Record<string, unknown>,
|
|
119
|
+
resolvedConfig.file,
|
|
120
|
+
)
|
|
72
121
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
122
|
+
clientConfig.theme = configTheme ?? clientConfig.theme
|
|
123
|
+
if (configApps) clientConfig.apps = configApps
|
|
124
|
+
if (configModules) clientConfig.modules = configModules
|
|
77
125
|
|
|
78
126
|
// init desktop runtime config and define core version
|
|
79
127
|
|
|
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
|
|
128
|
+
_nuxt.options.runtimeConfig.public.desktop = defu(
|
|
129
|
+
desktopRuntime,
|
|
130
|
+
{ coreVersion: pkg.version },
|
|
88
131
|
)
|
|
89
132
|
|
|
90
133
|
{
|
|
@@ -118,18 +161,7 @@ export default defineNuxtModule({
|
|
|
118
161
|
_nuxt.options.appConfig.desktop = _nuxt.options.runtimeConfig.public.desktop
|
|
119
162
|
|
|
120
163
|
{
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
_nuxt.options.primevue = _nuxt.options.primevue || {}
|
|
124
|
-
_nuxt.options.primevue.options = _nuxt.options.primevue.options || {}
|
|
125
|
-
_nuxt.options.primevue.options.theme =
|
|
126
|
-
_nuxt.options.primevue.options.theme || {}
|
|
127
|
-
|
|
128
|
-
await installModule('@primevue/nuxt-module')
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
{
|
|
132
|
-
// install tailwind
|
|
164
|
+
// Tailwind after theme/apps so registerTailwindPath paths are collected first.
|
|
133
165
|
|
|
134
166
|
const tailwindPaths =
|
|
135
167
|
_nuxt.options.runtimeConfig.app.owd?.tailwindPaths || []
|
|
@@ -145,41 +177,6 @@ export default defineNuxtModule({
|
|
|
145
177
|
})
|
|
146
178
|
}
|
|
147
179
|
|
|
148
|
-
{
|
|
149
|
-
// install pinia
|
|
150
|
-
|
|
151
|
-
await installModule('@pinia/nuxt')
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
{
|
|
155
|
-
// install @nuxt/fonts
|
|
156
|
-
|
|
157
|
-
await installModule('@nuxt/fonts')
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
{
|
|
161
|
-
// install @nuxt/icon
|
|
162
|
-
|
|
163
|
-
await installModule('@nuxt/icon', {
|
|
164
|
-
clientBundle: {
|
|
165
|
-
scan: true,
|
|
166
|
-
sizeLimitKb: 256
|
|
167
|
-
}
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
{
|
|
172
|
-
// install @vueuse/nuxt
|
|
173
|
-
|
|
174
|
-
await installModule('@vueuse/nuxt')
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
{
|
|
178
|
-
// install @nuxtjs/i18n
|
|
179
|
-
|
|
180
|
-
await installModule('@nuxtjs/i18n')
|
|
181
|
-
}
|
|
182
|
-
|
|
183
180
|
{
|
|
184
181
|
// configure scss for vite
|
|
185
182
|
|
|
@@ -205,18 +202,20 @@ export default defineNuxtModule({
|
|
|
205
202
|
addComponentsDir({
|
|
206
203
|
path: resolve('./runtime/components'),
|
|
207
204
|
prefix: '',
|
|
205
|
+
pathPrefix: false,
|
|
208
206
|
global: true
|
|
209
207
|
})
|
|
210
208
|
}
|
|
211
209
|
|
|
212
210
|
{
|
|
213
211
|
addPlugin(resolve('./runtime/plugins/resize.client.ts'))
|
|
214
|
-
addPlugin(
|
|
212
|
+
addPlugin(
|
|
213
|
+
resolve('./runtime/plugins/02.desktop-register-desktop-apps.client.ts'),
|
|
214
|
+
)
|
|
215
215
|
|
|
216
216
|
// add other files
|
|
217
217
|
|
|
218
218
|
addImportsDir(resolve('./runtime/composables'))
|
|
219
|
-
addImportsDir(resolve('./runtime/core'))
|
|
220
219
|
addImportsDir(resolve('./runtime/stores'))
|
|
221
220
|
addImportsDir(resolve('./runtime/utils'))
|
|
222
221
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owdproject/core",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
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
|
".": {
|
|
@@ -82,6 +84,7 @@
|
|
|
82
84
|
"@primeuix/themes": "^2.0.3",
|
|
83
85
|
"@primevue/forms": "^4.5.5",
|
|
84
86
|
"@primevue/nuxt-module": "^4.5.5",
|
|
87
|
+
"primevue": "^4.5.5",
|
|
85
88
|
"@vueuse/components": "^14.3.0",
|
|
86
89
|
"@vueuse/core": "^14.3.0",
|
|
87
90
|
"@vueuse/nuxt": "^14.3.0",
|
|
@@ -94,6 +97,7 @@
|
|
|
94
97
|
"shellwords": "^1.1.1",
|
|
95
98
|
"vue-resizable": "^2.1.7",
|
|
96
99
|
"getopts": "^2.3.0",
|
|
100
|
+
"defu": "^6.1.4",
|
|
97
101
|
"neo-blessed": "^0.2.0"
|
|
98
102
|
},
|
|
99
103
|
"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
|