@owdproject/core 3.0.0-alpha.6 → 3.0.0-alpha.8
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 +42 -33
- package/index.ts +27 -7
- package/package.json +4 -1
- package/runtime/components/Core/Desktop/CoreDesktop.vue +10 -1
- package/runtime/components/Core/Window/CoreWindow.vue +8 -8
- package/runtime/composables/useTerminalManager.ts +5 -1
- package/runtime/core/controllers/ApplicationController.ts +26 -5
- package/runtime/core/controllers/WindowController.ts +70 -58
- package/runtime/core/managers/ApplicationManager.ts +5 -6
- package/runtime/core/managers/DesktopManager.ts +2 -1
- package/runtime/core/managers/TerminalManager.ts +42 -0
- package/runtime/utils/utilsApp.ts +8 -6
- package/runtime/utils/utilsCommon.ts +24 -1
- package/runtime/utils/utilsDesktop.ts +1 -3
- package/runtime/utils/utilsWindow.ts +1 -0
- package/types/owd.d.ts +21 -23
- package/types/index.d.ts +0 -9
package/README.md
CHANGED
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
</p>
|
|
4
4
|
<h1 align="center">Open Web Desktop</h1>
|
|
5
5
|
<h3 align="center">
|
|
6
|
-
A framework for building web-based desktop experiences
|
|
6
|
+
A framework for building web-based desktop experiences.
|
|
7
7
|
</h3>
|
|
8
8
|
|
|
9
9
|
## Overview
|
|
10
10
|
Open Web Desktop (OWD) is a framework designed to provide a simple environment for building web-based desktop experiences. It's built with TypeScript on top of the Nuxt.js framework.
|
|
11
11
|
|
|
12
|
-
[Check out the demo](https://owdproject.github.io/docs) of the `client` base repository, decked with
|
|
12
|
+
[Check out the demo](https://owdproject.github.io/docs) of the `client` base repository, decked with a couple of modules.
|
|
13
13
|
|
|
14
14
|
## Features
|
|
15
15
|
- Open-source web desktop environment built with Nuxt.js
|
|
@@ -26,11 +26,11 @@ Required software:
|
|
|
26
26
|
- [Node](https://nodejs.org)
|
|
27
27
|
|
|
28
28
|
When you are ready, bootstrap a new project by running:
|
|
29
|
-
```
|
|
29
|
+
```bash
|
|
30
30
|
npm create owd
|
|
31
31
|
```
|
|
32
32
|
Once the process is complete, you can start to develop:
|
|
33
|
-
```
|
|
33
|
+
```bash
|
|
34
34
|
# Run the dev server with hot-reload
|
|
35
35
|
npm run dev
|
|
36
36
|
|
|
@@ -46,49 +46,58 @@ You can simply install a new application and define it this way.
|
|
|
46
46
|
|
|
47
47
|
```typescript
|
|
48
48
|
// owd.config.ts
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
export const owdConfig = {
|
|
52
|
-
theme: ['github:owdproject/theme-win95', { install: true }],
|
|
53
|
-
|
|
54
|
-
// apps to import
|
|
49
|
+
export default defineDesktopConfig({
|
|
55
50
|
apps: [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
await defineDesktopApp(AppTodo)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
51
|
+
"@owdproject/app-about",
|
|
52
|
+
"@owdproject/app-todo",
|
|
53
|
+
]
|
|
54
|
+
})
|
|
63
55
|
```
|
|
64
56
|
|
|
65
57
|
## Themes
|
|
66
58
|
Themes allow you to customize the look and feel of your Open Web Desktop instance.
|
|
59
|
+
You can explore available themes, ranging from popular OS designs to fully custom creations, at [topics/owd-themes](https://github.com/topics/owd-themes).
|
|
67
60
|
|
|
68
61
|
### Install a new theme
|
|
69
|
-
|
|
70
|
-
Themes can be loaded from local
|
|
62
|
+
You can install a new theme by defining it in the `owd.config.ts` configuration.
|
|
63
|
+
Themes can be loaded from a local path or directly from a GitHub repository.
|
|
64
|
+
|
|
65
|
+
#### Using a local theme
|
|
66
|
+
|
|
67
|
+
Clone it first in a folder of your project like `./desktop/theme/theme-gnome`.
|
|
71
68
|
|
|
72
|
-
|
|
69
|
+
```bash
|
|
70
|
+
git clone git@github.com:owdproject/theme-gnome.git ./desktop/theme/theme-gnome
|
|
71
|
+
```
|
|
73
72
|
|
|
74
|
-
|
|
73
|
+
Then specify the path theme in `owd.config.ts`:
|
|
75
74
|
|
|
76
75
|
```typescript
|
|
77
76
|
// owd.config.ts
|
|
78
|
-
export
|
|
79
|
-
theme: './
|
|
80
|
-
|
|
77
|
+
export default defineDesktopConfig({
|
|
78
|
+
theme: './dev/themes/theme-gnome', // define here the theme you just cloned
|
|
79
|
+
apps: [
|
|
80
|
+
...
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
#### Using a theme package
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
Use npm to install the theme package as a dependency of your Open Web Desktop client:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npm install @owdproject/theme-gnome
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Then specify the path theme in `owd.config.ts`:
|
|
86
92
|
|
|
87
93
|
```typescript
|
|
88
94
|
// owd.config.ts
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
import {defineDesktopConfig} from "@owdproject/core/runtime/utils/utilsDesktop"
|
|
96
|
+
|
|
97
|
+
export default defineDesktopConfig({
|
|
98
|
+
theme: '@owdproject/theme-gnome', // define here the theme you just installed
|
|
99
|
+
apps: [
|
|
100
|
+
...
|
|
92
101
|
```
|
|
93
102
|
|
|
94
103
|
## Contributing
|
|
@@ -111,10 +120,10 @@ Then, clone your fork using HTTPS or SSH:
|
|
|
111
120
|
|
|
112
121
|
```bash
|
|
113
122
|
# Clone using HTTPS
|
|
114
|
-
git clone https://github.com/<your-username>/
|
|
123
|
+
git clone https://github.com/<your-username>/client.git
|
|
115
124
|
|
|
116
125
|
# Clone using SSH
|
|
117
|
-
git clone git@github.com:<your-username>/
|
|
126
|
+
git clone git@github.com:<your-username>/client.git
|
|
118
127
|
```
|
|
119
128
|
|
|
120
129
|
Once you have cloned the repository, navigate to the project folder.
|
|
@@ -130,10 +139,10 @@ npm run dev
|
|
|
130
139
|
This will launch Open Web Desktop in development mode, allowing you to test your changes and see them reflected in real-time.
|
|
131
140
|
The dev server will be available at http://localhost:3000.
|
|
132
141
|
|
|
133
|
-
##
|
|
142
|
+
## Sponsoring
|
|
134
143
|
|
|
135
144
|
Open Web Desktop is a vast project. The code has been totally rewritten and is now actively being developed, but your support is what makes it all possible. If you're enjoying it and want to see more, consider donating. Your contribution helps keep the project alive and awesome.
|
|
136
145
|
|
|
137
|
-
|
|
146
|
+
## License
|
|
138
147
|
|
|
139
148
|
Open Web Desktop is released under the [GNU General Public License v3](LICENSE).
|
package/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {defineNuxtModule, createResolver, addComponentsDir, addImportsDir, installModule, addPlugin} from '@nuxt/kit'
|
|
2
|
-
import {
|
|
2
|
+
import {deepMerge} from '@owdproject/core/runtime/utils/utilsCommon'
|
|
3
3
|
import pkg from './package.json'
|
|
4
4
|
|
|
5
5
|
export default defineNuxtModule({
|
|
@@ -9,24 +9,43 @@ export default defineNuxtModule({
|
|
|
9
9
|
},
|
|
10
10
|
async setup(options, nuxt) {
|
|
11
11
|
const {resolve} = createResolver(import.meta.url)
|
|
12
|
-
const desktopManager = useDesktopManager()
|
|
13
12
|
|
|
14
|
-
await import(nuxt.options.rootDir + '/owd.config.ts')
|
|
13
|
+
const desktopConfig = (await import(nuxt.options.rootDir + '/owd.config.ts')).default
|
|
15
14
|
|
|
16
|
-
// set core version to runtime
|
|
15
|
+
// set core version to runtime config
|
|
17
16
|
|
|
18
17
|
nuxt.options.runtimeConfig.public.coreVersion = pkg.version
|
|
19
18
|
|
|
20
19
|
{
|
|
21
20
|
|
|
21
|
+
// install open web desktop theme
|
|
22
|
+
|
|
23
|
+
if (desktopConfig.theme) {
|
|
24
|
+
await installModule(desktopConfig.theme)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// install open web desktop modules
|
|
28
|
+
|
|
29
|
+
if (desktopConfig.modules) {
|
|
30
|
+
for (const modulePath of desktopConfig.modules) {
|
|
31
|
+
await installModule(modulePath)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
// install open web desktop apps
|
|
23
36
|
|
|
24
|
-
if (
|
|
25
|
-
for (const appPath of
|
|
37
|
+
if (desktopConfig.apps) {
|
|
38
|
+
for (const appPath of desktopConfig.apps) {
|
|
26
39
|
await installModule(appPath)
|
|
27
40
|
}
|
|
28
41
|
}
|
|
29
42
|
|
|
43
|
+
// assign open web desktop config to runtime config
|
|
44
|
+
nuxt.options.runtimeConfig.public.desktop = deepMerge(
|
|
45
|
+
nuxt.options.runtimeConfig.public.desktop,
|
|
46
|
+
desktopConfig
|
|
47
|
+
)
|
|
48
|
+
|
|
30
49
|
}
|
|
31
50
|
|
|
32
51
|
{
|
|
@@ -45,11 +64,12 @@ export default defineNuxtModule({
|
|
|
45
64
|
|
|
46
65
|
// install tailwind
|
|
47
66
|
|
|
48
|
-
const tailwindPaths = nuxt.options.
|
|
67
|
+
const tailwindPaths = nuxt.options.runtimeConfig?.owd?.tailwindPaths || []
|
|
49
68
|
tailwindPaths.push('./runtime/components/**/*.{vue,mjs,ts}') // Aggiungi sempre questo al core
|
|
50
69
|
|
|
51
70
|
nuxt.options.tailwindcss = nuxt.options.tailwindcss || {}
|
|
52
71
|
nuxt.options.tailwindcss.config = nuxt.options.tailwindcss.config || {}
|
|
72
|
+
// @ts-ignore
|
|
53
73
|
nuxt.options.tailwindcss.config.content = tailwindPaths
|
|
54
74
|
|
|
55
75
|
await installModule('@nuxtjs/tailwindcss', {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owdproject/core",
|
|
3
|
-
"version": "3.0.0-alpha.
|
|
3
|
+
"version": "3.0.0-alpha.8",
|
|
4
4
|
"description": "Open Web Desktop core",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"web",
|
|
@@ -43,5 +43,8 @@
|
|
|
43
43
|
"sanitize.css": "^13.0.0",
|
|
44
44
|
"sass": "^1.86.0",
|
|
45
45
|
"vue-resizable": "^2.1.7"
|
|
46
|
+
},
|
|
47
|
+
"resolutions": {
|
|
48
|
+
"vite": "^6.3.2"
|
|
46
49
|
}
|
|
47
50
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import {onMounted, onUnmounted} from "vue"
|
|
3
|
+
import {useRuntimeConfig} from "nuxt/app"
|
|
3
4
|
import {computed, toRaw} from "@vue/reactivity"
|
|
4
5
|
import {useDesktopManager} from "../../../composables/useDesktopManager"
|
|
5
6
|
import {useApplicationManager} from "../../../composables/useApplicationManager"
|
|
@@ -10,16 +11,21 @@ const props = withDefaults(defineProps<{
|
|
|
10
11
|
windows?: DesktopWindowsConfig
|
|
11
12
|
systemBar?: DesktopSystemBarConfig
|
|
12
13
|
dockBar?: DesktopDockBarConfig
|
|
14
|
+
workspaces?: DesktopWorkspacesConfig
|
|
13
15
|
}>(), {
|
|
14
16
|
windows: {
|
|
15
17
|
position: 'fixed',
|
|
16
18
|
},
|
|
17
19
|
systemBar: {},
|
|
18
20
|
dockBar: {},
|
|
21
|
+
workspaces: {},
|
|
19
22
|
})
|
|
20
23
|
|
|
24
|
+
// todo move to owd initialization
|
|
25
|
+
|
|
21
26
|
const desktopManager = useDesktopManager()
|
|
22
27
|
const applicationManager = useApplicationManager()
|
|
28
|
+
const runtimeConfig = useRuntimeConfig()
|
|
23
29
|
|
|
24
30
|
// create firsts workspaces if not available
|
|
25
31
|
const desktopStore = useDesktopStore()
|
|
@@ -33,11 +39,14 @@ if (desktopStore.$persistedState) {
|
|
|
33
39
|
desktopWorkspaceStore.setupWorkspaces()
|
|
34
40
|
}
|
|
35
41
|
|
|
42
|
+
desktopManager.setConfig(runtimeConfig.public.desktop)
|
|
43
|
+
|
|
36
44
|
// override desktop configurations
|
|
37
45
|
desktopManager.setConfig({
|
|
38
46
|
windows: toRaw(props.windows),
|
|
39
|
-
systemBar: toRaw(
|
|
47
|
+
systemBar: toRaw(props.systemBar),
|
|
40
48
|
dockBar: toRaw(props.dockBar),
|
|
49
|
+
workspaces: toRaw(props.workspaces),
|
|
41
50
|
})
|
|
42
51
|
|
|
43
52
|
// desktop resize
|
|
@@ -114,13 +114,13 @@ const classes = computed(() => {
|
|
|
114
114
|
<vue-resizable
|
|
115
115
|
ref="windowResizableController"
|
|
116
116
|
:class="classes"
|
|
117
|
-
:width="windowController?.
|
|
118
|
-
:height="windowController?.
|
|
119
|
-
:min-height="windowController?.
|
|
120
|
-
:max-width="windowController?.
|
|
121
|
-
:max-height="windowController?.
|
|
122
|
-
:left="windowController?.
|
|
123
|
-
:top="windowController?.
|
|
117
|
+
:width="windowController?.size.width"
|
|
118
|
+
:height="windowController?.size.height"
|
|
119
|
+
:min-height="windowController?.size.minHeight"
|
|
120
|
+
:max-width="windowController?.size.maxWidth"
|
|
121
|
+
:max-height="windowController?.size.maxHeight"
|
|
122
|
+
:left="windowController?.position?.x"
|
|
123
|
+
:top="windowController?.position?.y"
|
|
124
124
|
:active="windowController?.isResizable ? undefined : []"
|
|
125
125
|
@drag:start="onWindowDragStart"
|
|
126
126
|
@drag:move="onWindowDragMove"
|
|
@@ -128,7 +128,7 @@ const classes = computed(() => {
|
|
|
128
128
|
@resize:start="onWindowResizeStart"
|
|
129
129
|
@resize:move="onWindowResizeMove"
|
|
130
130
|
@resize:end="onWindowResizeEnd"
|
|
131
|
-
:style="{zIndex: windowController?.
|
|
131
|
+
:style="{zIndex: windowController?.position?.z}"
|
|
132
132
|
:drag-selector="windowController?.isDraggable ? '.owd-window-nav__draggable' : '.owd-window-nav__draggable-none'"
|
|
133
133
|
@pointerdown="onWindowPointerDown"
|
|
134
134
|
>
|
|
@@ -2,6 +2,7 @@ import {nanoid} from "nanoid";
|
|
|
2
2
|
import {WindowController} from "./WindowController";
|
|
3
3
|
import {useApplicationManager} from "../../composables/useApplicationManager"
|
|
4
4
|
import {useApplicationState} from "../../composables/useApplicationState"
|
|
5
|
+
import {useTerminalManager} from "../../composables/useTerminalManager"
|
|
5
6
|
import {useDesktopManager} from "../../composables/useDesktopManager"
|
|
6
7
|
import {debugLog, debugError} from "../../utils/utilsDebug"
|
|
7
8
|
import {useDesktopWorkspaceStore} from "../../stores/storeDesktopWorkspace"
|
|
@@ -10,6 +11,7 @@ import {reactive} from '@vue/reactivity'
|
|
|
10
11
|
export class ApplicationController implements IApplicationController {
|
|
11
12
|
private readonly applicationManager: IApplicationManager
|
|
12
13
|
private readonly desktopManager: IDesktopManager
|
|
14
|
+
private readonly terminalManager: ITerminalManager
|
|
13
15
|
|
|
14
16
|
public readonly id
|
|
15
17
|
public readonly config
|
|
@@ -24,6 +26,7 @@ export class ApplicationController implements IApplicationController {
|
|
|
24
26
|
config: ApplicationConfig
|
|
25
27
|
) {
|
|
26
28
|
this.applicationManager = useApplicationManager()
|
|
29
|
+
this.terminalManager = useTerminalManager()
|
|
27
30
|
this.desktopManager = useDesktopManager()
|
|
28
31
|
|
|
29
32
|
this.id = id
|
|
@@ -32,6 +35,9 @@ export class ApplicationController implements IApplicationController {
|
|
|
32
35
|
}
|
|
33
36
|
|
|
34
37
|
public async initApplication(): Promise<void> {
|
|
38
|
+
|
|
39
|
+
// provides
|
|
40
|
+
|
|
35
41
|
// set as default app for specific purposes
|
|
36
42
|
// todo improve this and move it in a store
|
|
37
43
|
if (this.config.provides) {
|
|
@@ -48,20 +54,34 @@ export class ApplicationController implements IApplicationController {
|
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
56
|
|
|
57
|
+
// terminal
|
|
58
|
+
|
|
59
|
+
if (this.config.commands) {
|
|
60
|
+
for (const commandKey of Object.keys(this.config.commands)) {
|
|
61
|
+
this.terminalManager.addCommand({
|
|
62
|
+
applicationId: this.id,
|
|
63
|
+
name: commandKey
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// store
|
|
69
|
+
|
|
51
70
|
if (this.store.$persistedState) {
|
|
52
71
|
await this.store.$persistedState.isReady()
|
|
53
72
|
}
|
|
54
73
|
|
|
55
74
|
// set default meta values
|
|
56
|
-
this.store.meta = this.config.meta ??
|
|
75
|
+
this.store.meta = this.config.meta ?? {}
|
|
76
|
+
|
|
77
|
+
// restore application state
|
|
78
|
+
await this.restoreApplication()
|
|
57
79
|
|
|
58
80
|
// once app is defined, always run "onReady"
|
|
59
81
|
if (typeof this.config.onReady === 'function') {
|
|
82
|
+
// todo transform in hook
|
|
60
83
|
this.config.onReady(this)
|
|
61
84
|
}
|
|
62
|
-
|
|
63
|
-
// restore application state
|
|
64
|
-
await this.restoreApplication()
|
|
65
85
|
}
|
|
66
86
|
|
|
67
87
|
/**
|
|
@@ -70,6 +90,7 @@ export class ApplicationController implements IApplicationController {
|
|
|
70
90
|
*/
|
|
71
91
|
public async restoreApplication() {
|
|
72
92
|
if (typeof this.config.onRestore === 'function') {
|
|
93
|
+
// todo transform in hook
|
|
73
94
|
await this.config.onRestore(this)
|
|
74
95
|
}
|
|
75
96
|
|
|
@@ -203,6 +224,6 @@ export class ApplicationController implements IApplicationController {
|
|
|
203
224
|
// commands
|
|
204
225
|
|
|
205
226
|
async execCommand(command: string): Promise<CommandOutput | void> {
|
|
206
|
-
|
|
227
|
+
return this.applicationManager.execAppCommand(this.id, command)
|
|
207
228
|
}
|
|
208
229
|
}
|
|
@@ -59,6 +59,7 @@ export class WindowController implements IWindowController {
|
|
|
59
59
|
) {
|
|
60
60
|
this.application = application
|
|
61
61
|
this.model = model
|
|
62
|
+
|
|
62
63
|
this.storedState = windowStoredState
|
|
63
64
|
|
|
64
65
|
this.setConfig(windowConfig)
|
|
@@ -119,6 +120,26 @@ export class WindowController implements IWindowController {
|
|
|
119
120
|
if (typeof config.destroyable !== 'undefined') {
|
|
120
121
|
this.config.destroyable = config.destroyable
|
|
121
122
|
}
|
|
123
|
+
|
|
124
|
+
const DEFAULT_OVERRIDABLE = {
|
|
125
|
+
draggable: true,
|
|
126
|
+
resizable: false,
|
|
127
|
+
position: false,
|
|
128
|
+
size: false,
|
|
129
|
+
maximized: false,
|
|
130
|
+
destroyable: false,
|
|
131
|
+
minimizable: false,
|
|
132
|
+
maximizable: false,
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
DEFAULT_OVERRIDABLE.position = DEFAULT_OVERRIDABLE.draggable
|
|
136
|
+
DEFAULT_OVERRIDABLE.size = DEFAULT_OVERRIDABLE.resizable
|
|
137
|
+
DEFAULT_OVERRIDABLE.maximized = DEFAULT_OVERRIDABLE.maximizable
|
|
138
|
+
|
|
139
|
+
this.config.overridable = {
|
|
140
|
+
...DEFAULT_OVERRIDABLE,
|
|
141
|
+
...(config.overridable || {})
|
|
142
|
+
}
|
|
122
143
|
}
|
|
123
144
|
|
|
124
145
|
// state
|
|
@@ -128,17 +149,20 @@ export class WindowController implements IWindowController {
|
|
|
128
149
|
}
|
|
129
150
|
|
|
130
151
|
private restoreState() {
|
|
131
|
-
|
|
132
|
-
if (!this.state.position) this.state.position = deepClone(this.config.position)
|
|
152
|
+
const overridable = this.config.overridable || {}
|
|
133
153
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (!this.state.draggable) this.state.draggable = this.config.draggable
|
|
138
|
-
if (!this.state.resizable) this.state.resizable = this.config.resizable
|
|
154
|
+
for (const key in overridable) {
|
|
155
|
+
if (overridable[key as keyof typeof overridable]) {
|
|
156
|
+
const stateKey = key as keyof WindowState
|
|
139
157
|
|
|
140
|
-
|
|
141
|
-
|
|
158
|
+
if (typeof this.state[stateKey] === 'undefined') {
|
|
159
|
+
if (typeof this.config[stateKey] === 'object') {
|
|
160
|
+
this.state[stateKey] = deepClone(this.config[stateKey])
|
|
161
|
+
} else {
|
|
162
|
+
this.state[stateKey] = !!this.config[stateKey]
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
142
166
|
}
|
|
143
167
|
}
|
|
144
168
|
|
|
@@ -210,54 +234,30 @@ export class WindowController implements IWindowController {
|
|
|
210
234
|
return this.application.config.icon
|
|
211
235
|
}
|
|
212
236
|
|
|
213
|
-
//
|
|
214
|
-
|
|
215
|
-
get width() {
|
|
216
|
-
if (typeof this.state.size?.width === 'undefined') {
|
|
217
|
-
return this.config.size.width
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return this.state.size.width
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
get maxWidth() {
|
|
224
|
-
if (typeof this.state.size?.maxWidth === 'undefined') {
|
|
225
|
-
return this.config.size.maxWidth
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return this.state.size.maxWidth
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
get minWidth() {
|
|
232
|
-
if (typeof this.state.size?.minWidth === 'undefined') {
|
|
233
|
-
return this.config.size.minWidth
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return this.state.size.minWidth
|
|
237
|
-
}
|
|
237
|
+
// position
|
|
238
238
|
|
|
239
|
-
get
|
|
240
|
-
if (typeof this.state.
|
|
241
|
-
return this.config.
|
|
239
|
+
get position() {
|
|
240
|
+
if (typeof this.state.position === 'undefined') {
|
|
241
|
+
return this.config.position
|
|
242
242
|
}
|
|
243
243
|
|
|
244
|
-
return this.state.
|
|
244
|
+
return this.state.position
|
|
245
245
|
}
|
|
246
246
|
|
|
247
|
-
|
|
248
|
-
if (typeof this.state.size?.maxHeight === 'undefined') {
|
|
249
|
-
return this.config.size.maxHeight ?? 600
|
|
250
|
-
}
|
|
247
|
+
// sizes
|
|
251
248
|
|
|
252
|
-
|
|
253
|
-
|
|
249
|
+
get size() {
|
|
250
|
+
const stateSize = this.state.size || {}
|
|
251
|
+
const configSize = this.config.size || {}
|
|
254
252
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
253
|
+
return {
|
|
254
|
+
width: typeof stateSize.width !== 'undefined' ? stateSize.width : configSize.width,
|
|
255
|
+
height: typeof stateSize.height !== 'undefined' ? stateSize.height : configSize.height,
|
|
256
|
+
minWidth: typeof stateSize.minWidth !== 'undefined' ? stateSize.minWidth : configSize.minWidth,
|
|
257
|
+
maxWidth: typeof stateSize.maxWidth !== 'undefined' ? stateSize.maxWidth : configSize.maxWidth,
|
|
258
|
+
minHeight: typeof stateSize.minHeight !== 'undefined' ? stateSize.minHeight : configSize.minHeight,
|
|
259
|
+
maxHeight: typeof stateSize.maxHeight !== 'undefined' ? stateSize.maxHeight : (configSize.maxHeight ?? 600),
|
|
258
260
|
}
|
|
259
|
-
|
|
260
|
-
return this.state.size.minHeight
|
|
261
261
|
}
|
|
262
262
|
|
|
263
263
|
private setSize(data: { width: number, height: number}) {
|
|
@@ -272,11 +272,11 @@ export class WindowController implements IWindowController {
|
|
|
272
272
|
// minimize
|
|
273
273
|
|
|
274
274
|
get isMinimizable() {
|
|
275
|
-
if (
|
|
276
|
-
return !!this.
|
|
275
|
+
if (this.config.overridable?.minimizable) {
|
|
276
|
+
return !!this.state.minimizable
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
return this.
|
|
279
|
+
return !!this.config.minimizable
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
private minimize() {
|
|
@@ -304,11 +304,11 @@ export class WindowController implements IWindowController {
|
|
|
304
304
|
}
|
|
305
305
|
|
|
306
306
|
get isMaximized() {
|
|
307
|
-
if (
|
|
308
|
-
return !!this.
|
|
307
|
+
if (this.config.overridable?.maximized) {
|
|
308
|
+
return !!this.state.maximized
|
|
309
309
|
}
|
|
310
310
|
|
|
311
|
-
return this.
|
|
311
|
+
return !!this.config.maximized
|
|
312
312
|
}
|
|
313
313
|
|
|
314
314
|
private toggleMaximize() {
|
|
@@ -341,7 +341,11 @@ export class WindowController implements IWindowController {
|
|
|
341
341
|
// destroy
|
|
342
342
|
|
|
343
343
|
get isDestroyable() {
|
|
344
|
-
|
|
344
|
+
if (this.config.overridable?.destroyable) {
|
|
345
|
+
return !!this.state.destroyable
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return !!this.config.destroyable
|
|
345
349
|
}
|
|
346
350
|
|
|
347
351
|
private destroy() {
|
|
@@ -356,12 +360,20 @@ export class WindowController implements IWindowController {
|
|
|
356
360
|
|
|
357
361
|
// draggable
|
|
358
362
|
get isDraggable() {
|
|
359
|
-
|
|
363
|
+
if (this.config.overridable?.draggable) {
|
|
364
|
+
return !!this.state.draggable
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
return !!this.config.draggable
|
|
360
368
|
}
|
|
361
369
|
|
|
362
370
|
// resizable
|
|
363
371
|
get isResizable() {
|
|
364
|
-
|
|
372
|
+
if (this.config.overridable?.resizable) {
|
|
373
|
+
return !!this.state.resizable
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return !!this.config.resizable
|
|
365
377
|
}
|
|
366
378
|
|
|
367
379
|
// workspace
|
|
@@ -69,7 +69,7 @@ export class ApplicationManager implements IApplicationManager {
|
|
|
69
69
|
* @param id
|
|
70
70
|
* @param entryKey
|
|
71
71
|
*/
|
|
72
|
-
public async launchAppEntry(id: string, entryKey: string) {
|
|
72
|
+
public async launchAppEntry(id: string, entryKey: string): Promise<IApplicationController | undefined | void> {
|
|
73
73
|
if (!this.isAppDefined(id)) {
|
|
74
74
|
throw Error(`App "${id}" is not defined`);
|
|
75
75
|
}
|
|
@@ -91,7 +91,7 @@ export class ApplicationManager implements IApplicationManager {
|
|
|
91
91
|
* @param id
|
|
92
92
|
* @param command
|
|
93
93
|
*/
|
|
94
|
-
public async execAppCommand(id: string, command: string) {
|
|
94
|
+
public async execAppCommand(id: string, command: string): Promise<CommandOutput> {
|
|
95
95
|
if (!this.isAppDefined(id)) {
|
|
96
96
|
throw Error(`App "${id}" is not defined`);
|
|
97
97
|
}
|
|
@@ -106,12 +106,11 @@ export class ApplicationManager implements IApplicationManager {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
const commandFn: any = applicationController.config.commands![baseCommand]
|
|
109
|
-
|
|
110
|
-
commandFn(applicationController, commandSplit.slice(1))
|
|
109
|
+
const commandOutput = await commandFn(applicationController, commandSplit.slice(1))
|
|
111
110
|
|
|
112
111
|
applicationController.setRunning(true)
|
|
113
112
|
|
|
114
|
-
return
|
|
113
|
+
return commandOutput;
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
/**
|
|
@@ -149,7 +148,7 @@ export class ApplicationManager implements IApplicationManager {
|
|
|
149
148
|
title: entry.title !== undefined ? entry.title : applicationController.config.title,
|
|
150
149
|
icon: entry.icon !== undefined ? entry.icon : applicationController.config.icon,
|
|
151
150
|
category: entry.category !== undefined ? entry.category : applicationController.config.category,
|
|
152
|
-
visibility: entry.visibility,
|
|
151
|
+
visibility: entry.visibility ?? 'primary',
|
|
153
152
|
command: entry.command
|
|
154
153
|
})
|
|
155
154
|
}
|
|
@@ -2,6 +2,7 @@ import {deepMerge} from "../../utils/utilsCommon"
|
|
|
2
2
|
|
|
3
3
|
export class DesktopManager {
|
|
4
4
|
public config: DesktopConfig = {} as DesktopConfig
|
|
5
|
+
|
|
5
6
|
private defaultApps: DefaultAppsConfig = {}
|
|
6
7
|
|
|
7
8
|
constructor() {
|
|
@@ -30,7 +31,7 @@ export class DesktopManager {
|
|
|
30
31
|
|
|
31
32
|
private loadDefaultAppsFromConfig() {
|
|
32
33
|
if (this.config.defaultApps) {
|
|
33
|
-
this.defaultApps = {
|
|
34
|
+
this.defaultApps = {...this.config.defaultApps}
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {useApplicationManager} from "../../composables/useApplicationManager"
|
|
2
|
+
import {debugLog} from "../../utils/utilsDebug"
|
|
3
|
+
|
|
4
|
+
export class TerminalManager {
|
|
5
|
+
private commands: Map<string, TerminalCommand> = new Map()
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
public addCommand(command: TerminalCommand) {
|
|
11
|
+
for (const existingCommand of this.commands.keys()) {
|
|
12
|
+
if (existingCommand.startsWith(command.name) || command.name.startsWith(existingCommand)) {
|
|
13
|
+
throw new Error(`Command prefix conflict with "${existingCommand}"`)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
this.commands.set(command.name, command)
|
|
18
|
+
debugLog(`Registered terminal command: ${command.name} → ${command.applicationId}`)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
public listCommands(): string[] {
|
|
22
|
+
return Array.from(this.commands.keys())
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
public async execCommand(input: string): Promise<CommandOutput | void> {
|
|
26
|
+
const applicationManager = useApplicationManager()
|
|
27
|
+
|
|
28
|
+
const [name, ...args] = input.trim().split(/\s+/)
|
|
29
|
+
|
|
30
|
+
if (!name) {
|
|
31
|
+
return
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!this.commands.has(name)) {
|
|
35
|
+
throw new Error(`Command "${name}" not found`)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const cmd = this.commands.get(name)!
|
|
39
|
+
|
|
40
|
+
return applicationManager.execAppCommand(cmd.applicationId, input)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type {Nuxt} from "@nuxt/schema";
|
|
2
|
+
|
|
1
3
|
export function normalizeApplicationConfig(config: ApplicationConfig): ApplicationConfig {
|
|
2
4
|
const normalizedEntries: Record<string, ApplicationEntry> = {}
|
|
3
5
|
|
|
@@ -20,12 +22,12 @@ export function normalizeApplicationConfig(config: ApplicationConfig): Applicati
|
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
export function registerTailwindPath(nuxt, path: string) {
|
|
24
|
-
nuxt.options.
|
|
25
|
-
nuxt.options.
|
|
26
|
-
nuxt.options.
|
|
25
|
+
export function registerTailwindPath(nuxt: Nuxt, path: string) {
|
|
26
|
+
nuxt.options.runtimeConfig = nuxt.options.runtimeConfig || {}
|
|
27
|
+
nuxt.options.runtimeConfig.owd = nuxt.options.runtimeConfig.owd || {}
|
|
28
|
+
nuxt.options.runtimeConfig.owd.tailwindPaths = nuxt.options.runtimeConfig.owd.tailwindPaths || []
|
|
27
29
|
|
|
28
|
-
if (!nuxt.options.
|
|
29
|
-
nuxt.options.
|
|
30
|
+
if (!nuxt.options.runtimeConfig.owd.tailwindPaths.includes(path)) {
|
|
31
|
+
nuxt.options.runtimeConfig.owd.tailwindPaths.push(path)
|
|
30
32
|
}
|
|
31
33
|
}
|
|
@@ -1,7 +1,30 @@
|
|
|
1
|
-
export function deepClone(obj:
|
|
1
|
+
export function deepClone<T>(obj: T): T {
|
|
2
2
|
return JSON.parse(JSON.stringify(obj))
|
|
3
3
|
}
|
|
4
4
|
|
|
5
|
+
export function deepEqual(obj1, obj2) {
|
|
6
|
+
const keys1 = Object.keys(obj1);
|
|
7
|
+
const keys2 = Object.keys(obj2);
|
|
8
|
+
if (keys1.length !== keys2.length) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
for (const key of keys1) {
|
|
12
|
+
if (!obj2.hasOwnProperty(key)) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
|
|
16
|
+
if (!deepEqual(obj1[key], obj2[key])) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
} else {
|
|
20
|
+
if (obj1[key] !== obj2[key]) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
5
28
|
export function deepMerge<T>(target: T, source: Partial<T>): T {
|
|
6
29
|
function isObject(value: any): value is Record<string, any> {
|
|
7
30
|
return (
|
package/types/owd.d.ts
CHANGED
|
@@ -11,12 +11,12 @@ interface IApplicationManager {
|
|
|
11
11
|
|
|
12
12
|
get appsByCategory(): { [category: string]: IApplicationController[] }
|
|
13
13
|
|
|
14
|
-
defineApp(
|
|
14
|
+
defineApp(id: string, config: ApplicationConfig): Promise<IApplicationController>
|
|
15
15
|
|
|
16
16
|
closeApp(id: string): void
|
|
17
17
|
|
|
18
|
-
launchAppEntry(
|
|
19
|
-
execAppCommand(
|
|
18
|
+
launchAppEntry(id: string, entry: string): Promise<IApplicationController | undefined | void>
|
|
19
|
+
execAppCommand(id: string, command: string): Promise<CommandOutput | void>
|
|
20
20
|
|
|
21
21
|
isAppDefined(id: string): boolean
|
|
22
22
|
|
|
@@ -56,7 +56,7 @@ interface ApplicationConfigProvide {
|
|
|
56
56
|
|
|
57
57
|
type IApplicationMeta = { [key: string]: any }
|
|
58
58
|
|
|
59
|
-
interface
|
|
59
|
+
interface IApplicationController {
|
|
60
60
|
id: string
|
|
61
61
|
config: ApplicationConfig
|
|
62
62
|
|
|
@@ -81,7 +81,7 @@ interface sIApplicationController {
|
|
|
81
81
|
|
|
82
82
|
closeAllWindows(): void
|
|
83
83
|
|
|
84
|
-
execCommand(command: string)
|
|
84
|
+
execCommand(command: string): Promise<CommandOutput | void>
|
|
85
85
|
|
|
86
86
|
get windowsOpened(): Reactive<Map<string, IWindowController>>
|
|
87
87
|
}
|
|
@@ -102,17 +102,7 @@ interface IWindowController {
|
|
|
102
102
|
get icon(): string | undefined
|
|
103
103
|
|
|
104
104
|
// sizes
|
|
105
|
-
get
|
|
106
|
-
|
|
107
|
-
get maxWidth(): WindowSizeValue
|
|
108
|
-
|
|
109
|
-
get minWidth(): WindowSizeValue
|
|
110
|
-
|
|
111
|
-
get height(): WindowSizeValue
|
|
112
|
-
|
|
113
|
-
get maxHeight(): WindowSizeValue
|
|
114
|
-
|
|
115
|
-
get minHeight(): WindowSizeValue
|
|
105
|
+
get size(): WindowSize
|
|
116
106
|
|
|
117
107
|
// minimize
|
|
118
108
|
get isMinimizable(): boolean
|
|
@@ -170,7 +160,6 @@ interface WindowConfig {
|
|
|
170
160
|
title?: string
|
|
171
161
|
category?: string
|
|
172
162
|
icon?: string
|
|
173
|
-
pinned?: boolean
|
|
174
163
|
|
|
175
164
|
component?: Raw<Component>
|
|
176
165
|
|
|
@@ -195,6 +184,8 @@ interface WindowConfig {
|
|
|
195
184
|
|
|
196
185
|
// draggable
|
|
197
186
|
resizable?: boolean
|
|
187
|
+
|
|
188
|
+
overridable?: Partial<Record<'position' | 'size' | 'maximized' | 'draggable' | 'resizable' | 'destroyable' | 'minimizable', boolean>>
|
|
198
189
|
}
|
|
199
190
|
|
|
200
191
|
interface WindowStoredState {
|
|
@@ -212,7 +203,6 @@ interface WindowState {
|
|
|
212
203
|
createdAt: number
|
|
213
204
|
|
|
214
205
|
category?: string
|
|
215
|
-
pinned?: boolean
|
|
216
206
|
workspace: string
|
|
217
207
|
|
|
218
208
|
// position
|
|
@@ -286,13 +276,17 @@ interface IDesktopManager {
|
|
|
286
276
|
}
|
|
287
277
|
|
|
288
278
|
interface DesktopConfig {
|
|
289
|
-
|
|
290
|
-
|
|
279
|
+
theme?: string
|
|
280
|
+
modules?: string[]
|
|
291
281
|
apps?: string[]
|
|
282
|
+
|
|
283
|
+
name?: string
|
|
292
284
|
defaultApps?: DefaultAppsConfig
|
|
293
285
|
features?: string[]
|
|
286
|
+
|
|
294
287
|
systemBar?: DesktopSystemBarConfig
|
|
295
288
|
dockBar?: DesktopDockBarConfig
|
|
289
|
+
workspaces?: DesktopWorkspacesConfig
|
|
296
290
|
}
|
|
297
291
|
|
|
298
292
|
interface DesktopWindowsConfig {
|
|
@@ -310,11 +304,15 @@ interface DesktopSystemBarConfig {
|
|
|
310
304
|
startButton?: boolean
|
|
311
305
|
}
|
|
312
306
|
|
|
307
|
+
interface DesktopWorkspacesConfig {
|
|
308
|
+
enabled?: boolean
|
|
309
|
+
}
|
|
310
|
+
|
|
313
311
|
// TERMINAL
|
|
314
312
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
313
|
+
type TerminalCommand = {
|
|
314
|
+
name: string
|
|
315
|
+
applicationId: string
|
|
318
316
|
}
|
|
319
317
|
|
|
320
318
|
interface CommandOutput {
|