@owdproject/core 3.1.4 → 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/README.md +6 -6
- package/bin/cli.js +395 -0
- package/bin/desktop.js +5 -0
- package/bin/lib/catalog.js +293 -0
- package/bin/lib/config.js +109 -0
- package/bin/lib/desktopConfig.js +56 -0
- package/bin/lib/generateTemplate.js +389 -0
- package/bin/lib/install.js +408 -0
- package/bin/lib/migrateModulePlayground.config.mjs +164 -0
- package/bin/lib/migrateModulePlayground.mjs +313 -0
- package/bin/lib/npmVersions.js +124 -0
- package/bin/lib/playgroundContext.js +188 -0
- package/bin/lib/scaffold.js +197 -0
- package/bin/lib/status.js +289 -0
- package/bin/lib/validateModule.js +697 -0
- package/bin/lib/workspace.js +182 -0
- package/bin/owd.js +2 -25
- package/bin/tui.js +1379 -0
- package/dist/module.d.mts +13 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +267 -0
- package/dist/types.d.mts +7 -0
- package/module.ts +69 -32
- package/package.json +81 -22
- package/runtime/components/{Core/Application/CoreApplicationRender.vue → Desktop/Application/DesktopApplicationRender.vue} +4 -2
- package/runtime/components/Desktop/Application/DesktopApplicationWindowsRender.vue +38 -0
- package/runtime/components/{Core/Window/CoreWindow.vue → Desktop/Window/DesktopWindow.vue} +42 -8
- package/runtime/components/{Core/Window/CoreWindowNav.vue → Desktop/Window/DesktopWindowNav.vue} +26 -8
- package/runtime/composables/useApplicationManager.ts +19 -14
- package/runtime/composables/useDesktopManager.ts +33 -9
- package/runtime/composables/useWorkspaceManager.ts +41 -0
- package/runtime/{core → internal}/controllers/ApplicationController.ts +114 -24
- package/runtime/{core → internal}/controllers/WindowController.ts +4 -9
- package/runtime/plugins/02.desktop-register-desktop-apps.client.ts +17 -0
- package/runtime/stores/storeApplicationMeta.ts +56 -12
- package/runtime/stores/storeDesktop.ts +68 -2
- package/runtime/stores/storeDesktopDefaultApps.ts +2 -2
- package/runtime/stores/storeDesktopWorkspace.ts +14 -2
- package/runtime/utils/captureElementToCanvas.ts +21 -0
- package/runtime/utils/explorerEntryPath.ts +10 -0
- package/runtime/utils/resolveDesktopConfigPath.ts +52 -0
- package/runtime/utils/splitDesktopUserConfig.ts +85 -0
- package/runtime/utils/utilCommon.ts +0 -32
- package/runtime/utils/utilDesktop.ts +27 -2
- package/runtime/utils/validateDesktopUserConfig.ts +44 -0
- package/types/index.d.ts +45 -12
- package/CHANGELOG.md +0 -25
- package/project.json +0 -4
- package/runtime/components/Core/Application/CoreApplicationWindowsRender.vue +0 -19
- package/runtime/components/Core/Explorer/CoreExplorerFile.vue +0 -76
- package/runtime/components/Core/Explorer/CoreExplorerFolder.vue +0 -10
- package/runtime/stores/storeApplication.ts +0 -236
- package/test/basic.test.ts +0 -15
- package/test/fixtures/basic/app.vue +0 -5
- package/test/fixtures/basic/nuxt.config.ts +0 -5
- package/test/fixtures/basic/package.json +0 -5
- package/tsconfig.app.json +0 -31
- package/tsconfig.json +0 -12
- package/tsconfig.spec.json +0 -37
- package/vitest.config.ts +0 -24
- /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/CoreWindowContent.vue → Desktop/Window/DesktopWindowContent.vue} +0 -0
|
@@ -1,6 +1,41 @@
|
|
|
1
1
|
import { defineStore } from 'pinia'
|
|
2
2
|
import { ref } from 'vue'
|
|
3
3
|
|
|
4
|
+
export type DesktopWindowSurface = 'acrylic' | 'solid'
|
|
5
|
+
|
|
6
|
+
export type DesktopAppearance = 'dark' | 'light'
|
|
7
|
+
|
|
8
|
+
export type DesktopPersonalization = {
|
|
9
|
+
windowSurface: DesktopWindowSurface
|
|
10
|
+
/** Used when windowSurface is solid (CSS color string). */
|
|
11
|
+
windowTint: string
|
|
12
|
+
appearance: DesktopAppearance
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const defaultDesktopPersonalization: DesktopPersonalization = {
|
|
16
|
+
windowSurface: 'acrylic',
|
|
17
|
+
windowTint: '#2d2d30',
|
|
18
|
+
appearance: 'dark',
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function mergePersonalization(
|
|
22
|
+
raw: Partial<DesktopPersonalization> | undefined | null,
|
|
23
|
+
): DesktopPersonalization {
|
|
24
|
+
const windowSurface =
|
|
25
|
+
raw?.windowSurface === 'solid' || raw?.windowSurface === 'acrylic'
|
|
26
|
+
? raw.windowSurface
|
|
27
|
+
: defaultDesktopPersonalization.windowSurface
|
|
28
|
+
const appearance =
|
|
29
|
+
raw?.appearance === 'light' || raw?.appearance === 'dark'
|
|
30
|
+
? raw.appearance
|
|
31
|
+
: defaultDesktopPersonalization.appearance
|
|
32
|
+
const tint =
|
|
33
|
+
typeof raw?.windowTint === 'string' && raw.windowTint.trim()
|
|
34
|
+
? raw.windowTint.trim()
|
|
35
|
+
: defaultDesktopPersonalization.windowTint
|
|
36
|
+
return { windowSurface, windowTint: tint, appearance }
|
|
37
|
+
}
|
|
38
|
+
|
|
4
39
|
export const useDesktopStore = defineStore(
|
|
5
40
|
'owd/desktop',
|
|
6
41
|
() => {
|
|
@@ -16,7 +51,8 @@ export const useDesktopStore = defineStore(
|
|
|
16
51
|
window: {
|
|
17
52
|
positionZ: number
|
|
18
53
|
}
|
|
19
|
-
defaultApps: {
|
|
54
|
+
defaultApps: Record<string, { applicationId: string; entry: string }>
|
|
55
|
+
personalization: DesktopPersonalization
|
|
20
56
|
}>({
|
|
21
57
|
workspace: {
|
|
22
58
|
overview: false,
|
|
@@ -29,11 +65,41 @@ export const useDesktopStore = defineStore(
|
|
|
29
65
|
window: {
|
|
30
66
|
positionZ: 0,
|
|
31
67
|
},
|
|
32
|
-
defaultApps: {}
|
|
68
|
+
defaultApps: {},
|
|
69
|
+
personalization: { ...defaultDesktopPersonalization },
|
|
33
70
|
})
|
|
34
71
|
|
|
72
|
+
function setWindowSurface(value: DesktopWindowSurface) {
|
|
73
|
+
const base = mergePersonalization(state.value.personalization)
|
|
74
|
+
state.value.personalization = mergePersonalization({
|
|
75
|
+
...base,
|
|
76
|
+
windowSurface: value,
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function setWindowTint(value: string) {
|
|
81
|
+
const v = value.trim()
|
|
82
|
+
if (!v) return
|
|
83
|
+
const base = mergePersonalization(state.value.personalization)
|
|
84
|
+
state.value.personalization = mergePersonalization({
|
|
85
|
+
...base,
|
|
86
|
+
windowTint: v,
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function setAppearance(value: DesktopAppearance) {
|
|
91
|
+
const base = mergePersonalization(state.value.personalization)
|
|
92
|
+
state.value.personalization = mergePersonalization({
|
|
93
|
+
...base,
|
|
94
|
+
appearance: value,
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
35
98
|
return {
|
|
36
99
|
state,
|
|
100
|
+
setWindowSurface,
|
|
101
|
+
setWindowTint,
|
|
102
|
+
setAppearance,
|
|
37
103
|
}
|
|
38
104
|
},
|
|
39
105
|
{
|
|
@@ -27,12 +27,12 @@ export const useDesktopDefaultAppsStore = defineStore(
|
|
|
27
27
|
/**
|
|
28
28
|
* Gets the default app config for a given feature
|
|
29
29
|
*/
|
|
30
|
-
function getDefaultApp(feature: string): DefaultAppConfig {
|
|
30
|
+
function getDefaultApp(feature: string): DefaultAppConfig | undefined {
|
|
31
31
|
if (!desktopStore.state.hasOwnProperty('defaultApps')) {
|
|
32
32
|
desktopStore.state.defaultApps = {}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
return desktopStore.state.defaultApps[feature]
|
|
35
|
+
return desktopStore.state.defaultApps[feature]
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -23,13 +23,23 @@ export const useDesktopWorkspaceStore = defineStore(
|
|
|
23
23
|
function setupWorkspaces() {
|
|
24
24
|
if (desktopStore.state.workspace.list.length === 0) {
|
|
25
25
|
createWorkspace()
|
|
26
|
-
desktopStore.state.workspace.active = desktopStore.state.workspace
|
|
27
|
-
.list[0] as string
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
if (desktopStore.state.workspace.list.length === 1) {
|
|
31
29
|
createWorkspace()
|
|
32
30
|
}
|
|
31
|
+
|
|
32
|
+
const list = desktopStore.state.workspace.list
|
|
33
|
+
const active = desktopStore.state.workspace.active
|
|
34
|
+
if (!active || !list.includes(active)) {
|
|
35
|
+
desktopStore.state.workspace.active = list[0] ?? ''
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Id of the workspace new windows should use (after setupWorkspaces). */
|
|
40
|
+
function resolveActiveWorkspaceId(): string {
|
|
41
|
+
setupWorkspaces()
|
|
42
|
+
return desktopStore.state.workspace.active || desktopStore.state.workspace.list[0] || ''
|
|
33
43
|
}
|
|
34
44
|
|
|
35
45
|
function setOverview(value: boolean) {
|
|
@@ -56,8 +66,10 @@ export const useDesktopWorkspaceStore = defineStore(
|
|
|
56
66
|
list,
|
|
57
67
|
workspaceActiveIndex,
|
|
58
68
|
setupWorkspaces,
|
|
69
|
+
resolveActiveWorkspaceId,
|
|
59
70
|
setOverview,
|
|
60
71
|
setWorkspace,
|
|
72
|
+
createWorkspace,
|
|
61
73
|
}
|
|
62
74
|
},
|
|
63
75
|
)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders a DOM subtree to a canvas via html2canvas (optional dependency).
|
|
3
|
+
* Used for workspace thumbnails / previews; returns null if capture fails or html2canvas is missing.
|
|
4
|
+
*/
|
|
5
|
+
export async function captureElementToCanvas(
|
|
6
|
+
element: HTMLElement | null | undefined,
|
|
7
|
+
options?: Record<string, unknown>,
|
|
8
|
+
): Promise<HTMLCanvasElement | null> {
|
|
9
|
+
if (!element || typeof window === 'undefined') {
|
|
10
|
+
return null
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
const { default: html2canvas } = await import('html2canvas')
|
|
14
|
+
return await html2canvas(element, {
|
|
15
|
+
allowTaint: true,
|
|
16
|
+
...(options as object),
|
|
17
|
+
})
|
|
18
|
+
} catch {
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Absolute path for a listing entry under `basePath` (virtual FS paths).
|
|
3
|
+
* Avoids `//fileName` when `basePath` is `/` or has trailing slashes.
|
|
4
|
+
*/
|
|
5
|
+
export function explorerEntryAbsolutePath(basePath: string, fileName: string): string {
|
|
6
|
+
const normalizedBase = (basePath ?? '/').replace(/\/+$/, '') || '/'
|
|
7
|
+
const tail = fileName.replace(/^\/+/, '')
|
|
8
|
+
if (normalizedBase === '/') return `/${tail}`
|
|
9
|
+
return `${normalizedBase}/${tail}`
|
|
10
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs'
|
|
2
|
+
import { join } from 'node:path'
|
|
3
|
+
|
|
4
|
+
export const DESKTOP_CONFIG_FILENAME = 'desktop.config.ts'
|
|
5
|
+
export const LEGACY_DESKTOP_CONFIG_FILENAME = 'owd.config.ts'
|
|
6
|
+
|
|
7
|
+
export const LEGACY_CONFIG_DEPRECATION =
|
|
8
|
+
'[@owdproject/core] owd.config.ts is deprecated and kept only for backward compatibility; rename to desktop.config.ts (required from @owdproject/core 3.2).'
|
|
9
|
+
|
|
10
|
+
export type ResolvedDesktopConfigPath = {
|
|
11
|
+
path: string
|
|
12
|
+
file: string
|
|
13
|
+
legacy: boolean
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function resolveDesktopConfigPath(
|
|
17
|
+
rootDir: string,
|
|
18
|
+
): ResolvedDesktopConfigPath | null {
|
|
19
|
+
const desktopPath = join(rootDir, DESKTOP_CONFIG_FILENAME)
|
|
20
|
+
const legacyPath = join(rootDir, LEGACY_DESKTOP_CONFIG_FILENAME)
|
|
21
|
+
const hasDesktop = existsSync(desktopPath)
|
|
22
|
+
const hasLegacy = existsSync(legacyPath)
|
|
23
|
+
|
|
24
|
+
if (hasDesktop && hasLegacy) {
|
|
25
|
+
console.warn(
|
|
26
|
+
'[@owdproject/core] Both desktop.config.ts and owd.config.ts exist; using desktop.config.ts. Remove owd.config.ts.',
|
|
27
|
+
)
|
|
28
|
+
return { path: desktopPath, file: DESKTOP_CONFIG_FILENAME, legacy: false }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (hasDesktop) {
|
|
32
|
+
return { path: desktopPath, file: DESKTOP_CONFIG_FILENAME, legacy: false }
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (hasLegacy) {
|
|
36
|
+
return {
|
|
37
|
+
path: legacyPath,
|
|
38
|
+
file: LEGACY_DESKTOP_CONFIG_FILENAME,
|
|
39
|
+
legacy: true,
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return null
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function warnLegacyDesktopConfig(
|
|
47
|
+
resolved: ResolvedDesktopConfigPath | null | undefined,
|
|
48
|
+
): void {
|
|
49
|
+
if (resolved?.legacy) {
|
|
50
|
+
console.warn(LEGACY_CONFIG_DEPRECATION)
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -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) {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime validation for the object exported from `desktop.config.ts`
|
|
3
|
+
* (or legacy `owd.config.ts`).
|
|
4
|
+
*/
|
|
5
|
+
export function assertValidDesktopUserConfig(
|
|
6
|
+
config: unknown,
|
|
7
|
+
configFile = 'desktop.config.ts',
|
|
8
|
+
): void {
|
|
9
|
+
if (!config || typeof config !== 'object' || Array.isArray(config)) {
|
|
10
|
+
throw new Error(
|
|
11
|
+
`[@owdproject/core] ${configFile} must default-export a non-array object from defineDesktopConfig({ ... }).`,
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const c = config as Record<string, unknown>
|
|
16
|
+
|
|
17
|
+
if (c.theme != null && typeof c.theme !== 'string') {
|
|
18
|
+
throw new Error(
|
|
19
|
+
`[@owdproject/core] ${configFile}: \`theme\` must be a string (npm package name of the theme module).`,
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (c.apps !== undefined) {
|
|
24
|
+
if (
|
|
25
|
+
!Array.isArray(c.apps) ||
|
|
26
|
+
!(c.apps as unknown[]).every((item) => typeof item === 'string')
|
|
27
|
+
) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`[@owdproject/core] ${configFile}: \`apps\` must be an array of strings (Nuxt module package names).`,
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (c.modules !== undefined) {
|
|
35
|
+
if (
|
|
36
|
+
!Array.isArray(c.modules) ||
|
|
37
|
+
!(c.modules as unknown[]).every((item) => typeof item === 'string')
|
|
38
|
+
) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`[@owdproject/core] ${configFile}: \`modules\` must be an array of strings (Nuxt module package names).`,
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
package/types/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Nuxt } from '@nuxt/schema'
|
|
2
|
+
import type { ShallowRef } from 'vue'
|
|
2
3
|
import { useApplicationManager } from '../runtime/composables/useApplicationManager'
|
|
3
4
|
|
|
4
5
|
declare module 'nuxt/schema' {
|
|
@@ -16,7 +17,7 @@ interface IApplicationManager {
|
|
|
16
17
|
|
|
17
18
|
get appsRunning(): Reactive<IApplicationController[]>
|
|
18
19
|
|
|
19
|
-
get windowsOpened(): Reactive<IWindowController
|
|
20
|
+
get windowsOpened(): Reactive<Map<string, IWindowController>>
|
|
20
21
|
|
|
21
22
|
get appCategories(): string[]
|
|
22
23
|
|
|
@@ -84,7 +85,8 @@ interface IApplicationController {
|
|
|
84
85
|
get meta(): { [key: string]: any }
|
|
85
86
|
|
|
86
87
|
store: Pinia
|
|
87
|
-
windows:
|
|
88
|
+
windows: Map<string, IWindowController>
|
|
89
|
+
openWindowCount: ShallowRef<number>
|
|
88
90
|
|
|
89
91
|
isRunning: boolean
|
|
90
92
|
|
|
@@ -116,7 +118,7 @@ interface IApplicationController {
|
|
|
116
118
|
get windowsOpened(): Reactive<Map<string, IWindowController>>
|
|
117
119
|
}
|
|
118
120
|
|
|
119
|
-
interface IWindowController {
|
|
121
|
+
export interface IWindowController {
|
|
120
122
|
application: IApplicationController
|
|
121
123
|
instanced: boolean
|
|
122
124
|
model: string
|
|
@@ -134,6 +136,8 @@ interface IWindowController {
|
|
|
134
136
|
// sizes
|
|
135
137
|
get size(): WindowSize
|
|
136
138
|
|
|
139
|
+
get position(): WindowPosition | undefined
|
|
140
|
+
|
|
137
141
|
// minimize
|
|
138
142
|
get isMinimizable(): boolean
|
|
139
143
|
|
|
@@ -179,14 +183,27 @@ interface IWindowController {
|
|
|
179
183
|
setTitleOverride(title: string | undefined): void
|
|
180
184
|
resetTitleOverride(): void
|
|
181
185
|
}
|
|
186
|
+
|
|
187
|
+
/** Payload restored with window state (e.g. explorer cwd in `path`). */
|
|
188
|
+
get meta(): { path?: string } & Record<string, unknown>
|
|
189
|
+
|
|
190
|
+
/** Chrome menu model (e.g. PrimeVue Menubar). */
|
|
191
|
+
menu: unknown[]
|
|
192
|
+
|
|
193
|
+
setMenu(menu: unknown[]): void
|
|
194
|
+
|
|
195
|
+
destroy(): boolean
|
|
196
|
+
|
|
197
|
+
/** Set by module-fs when an explorer surface mounts on this window. */
|
|
198
|
+
fsExplorer?: any
|
|
182
199
|
}
|
|
183
200
|
|
|
184
|
-
interface WindowContent {
|
|
201
|
+
export interface WindowContent {
|
|
185
202
|
padded?: boolean
|
|
186
203
|
centered?: boolean
|
|
187
204
|
}
|
|
188
205
|
|
|
189
|
-
interface WindowConfig {
|
|
206
|
+
export interface WindowConfig {
|
|
190
207
|
title?: string
|
|
191
208
|
category?: string
|
|
192
209
|
icon?: string
|
|
@@ -309,15 +326,28 @@ type ApplicationEntryVisibility = 'primary' | 'secondary' | 'hidden'
|
|
|
309
326
|
// DESKTOP
|
|
310
327
|
|
|
311
328
|
interface IDesktopManager {
|
|
312
|
-
defaultApps:
|
|
329
|
+
defaultApps: import('vue').ComputedRef<Record<string, DefaultAppConfig>>
|
|
313
330
|
|
|
314
|
-
getDefaultApp(feature: string)
|
|
331
|
+
getDefaultApp(feature: string): DefaultAppConfig | undefined
|
|
315
332
|
|
|
316
333
|
setDefaultApp(
|
|
317
334
|
feature: string,
|
|
318
335
|
application: IApplicationController,
|
|
319
|
-
|
|
320
|
-
)
|
|
336
|
+
entry: string,
|
|
337
|
+
): void
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
interface DocsModuleUserSourceConfig {
|
|
341
|
+
cwd: string
|
|
342
|
+
prefix?: string
|
|
343
|
+
include?: string
|
|
344
|
+
exclude?: string[]
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
interface DocsModuleConfig {
|
|
348
|
+
basePath?: string
|
|
349
|
+
title?: string
|
|
350
|
+
sources?: DocsModuleUserSourceConfig[]
|
|
321
351
|
}
|
|
322
352
|
|
|
323
353
|
interface DesktopConfig {
|
|
@@ -325,7 +355,9 @@ interface DesktopConfig {
|
|
|
325
355
|
modules?: string[]
|
|
326
356
|
apps?: string[]
|
|
327
357
|
|
|
328
|
-
|
|
358
|
+
docs?: DocsModuleConfig
|
|
359
|
+
|
|
360
|
+
name?: string
|
|
329
361
|
defaultApps?: DefaultAppsConfig
|
|
330
362
|
features?: string[]
|
|
331
363
|
|
|
@@ -375,9 +407,10 @@ interface DefaultAppsConfig {
|
|
|
375
407
|
[key: string]: DefaultAppConfig
|
|
376
408
|
}
|
|
377
409
|
|
|
410
|
+
/** Stored default for a feature: which app and which entry key to use. */
|
|
378
411
|
interface DefaultAppConfig {
|
|
379
|
-
|
|
380
|
-
entry:
|
|
412
|
+
applicationId: string
|
|
413
|
+
entry: string
|
|
381
414
|
}
|
|
382
415
|
|
|
383
416
|
export function defineDesktopApp(config: ApplicationConfig)
|
package/CHANGELOG.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
## 3.1.4 (2025-05-22)
|
|
2
|
-
|
|
3
|
-
### 🚀 Features
|
|
4
|
-
|
|
5
|
-
- Allow apps to have a menu ([4bfea74](https://github.com/owdproject/client/commit/4bfea74))
|
|
6
|
-
- Add methods to better handle window changes ([54d1346](https://github.com/owdproject/client/commit/54d1346))
|
|
7
|
-
- Check if owd.config.ts is available and valid ([4920302](https://github.com/owdproject/client/commit/4920302))
|
|
8
|
-
- Add fit-parent to CoreWindow.vue ([59e068c](https://github.com/owdproject/client/commit/59e068c))
|
|
9
|
-
- Add focus() to WindowController and set methods as public (deprecate actions) ([710f7be](https://github.com/owdproject/client/commit/710f7be))
|
|
10
|
-
- Add owd global command ([f98c74c](https://github.com/owdproject/client/commit/f98c74c))
|
|
11
|
-
- Add useClipboardFs.ts composable ([cf934f4](https://github.com/owdproject/client/commit/cf934f4))
|
|
12
|
-
- Add window utils in ApplicationController.ts ([ffc97d0](https://github.com/owdproject/client/commit/ffc97d0))
|
|
13
|
-
- Export most used functions from core ([6635af7](https://github.com/owdproject/client/commit/6635af7))
|
|
14
|
-
- Merge owd.config.ts with nuxt.config.ts in module.ts ([069243c](https://github.com/owdproject/client/commit/069243c))
|
|
15
|
-
- Implement basic owd.config.ts ([d052552](https://github.com/owdproject/client/commit/d052552))
|
|
16
|
-
- Rewrite project ([cbbd45d](https://github.com/owdproject/client/commit/cbbd45d))
|
|
17
|
-
|
|
18
|
-
### 🩹 Fixes
|
|
19
|
-
|
|
20
|
-
- Add key on CoreApplicationWindowsRender v-for ([d2e8e3c](https://github.com/owdproject/client/commit/d2e8e3c))
|
|
21
|
-
- Check if entries property is set before normalizing in utilApp.ts ([6092c33](https://github.com/owdproject/client/commit/6092c33))
|
|
22
|
-
- Add missing min-width ([aa0c1b5](https://github.com/owdproject/client/commit/aa0c1b5))
|
|
23
|
-
- Minor improvements ([7f79208](https://github.com/owdproject/client/commit/7f79208))
|
|
24
|
-
- Fix imports ([44740cd](https://github.com/owdproject/client/commit/44740cd))
|
|
25
|
-
- Set window starting positionZ to 0 ([b99352e](https://github.com/owdproject/client/commit/b99352e))
|
package/project.json
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
<script setup lang="ts">
|
|
2
|
-
defineProps<{
|
|
3
|
-
workspaceFilter?: string
|
|
4
|
-
windows: Map<string, IApplicationController['windows']>
|
|
5
|
-
}>()
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<template>
|
|
9
|
-
<template v-for="[windowId, window] in windows" :key="windowId">
|
|
10
|
-
<component
|
|
11
|
-
v-if="
|
|
12
|
-
!workspaceFilter ||
|
|
13
|
-
(workspaceFilter && window.state.workspace === workspaceFilter)
|
|
14
|
-
"
|
|
15
|
-
:window="window"
|
|
16
|
-
:is="window.config.component"
|
|
17
|
-
/>
|
|
18
|
-
</template>
|
|
19
|
-
</template>
|
|
@@ -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>
|