@owdproject/core 3.0.0-alpha.5 → 3.0.0-alpha.7

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 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 essential modules.
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,62 @@ You can simply install a new application and define it this way.
46
46
 
47
47
  ```typescript
48
48
  // owd.config.ts
49
- import AppTodo from 'owd-app-todo/owd.config'
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
- './node_modules/owd-app-todo',
57
- ],
58
-
59
- loader: async () => {
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.
67
59
 
68
60
  ### Install a new theme
69
- Install a new theme by defining its location in the `theme` property of your configuration file.
70
- Themes can be loaded from local paths or directly from GitHub repositories.
61
+ You can install a new theme by defining it as a Nuxt.js layer in `nuxt.config.ts`.
62
+ Themes can be loaded from a local path or directly from a GitHub repository.
71
63
 
72
64
  **1. Using a local theme:**
73
65
 
74
- To use a theme from a local folder, specify the path like this:
66
+ Clone it first in a folder of your project like `./desktop/theme/theme-win95`.
67
+
68
+ ```bash
69
+ git clone git@github.com:owdproject/theme-win95.git ./desktop/theme/theme-win95
70
+ ```
71
+
72
+ Then specify the path theme in the `nuxt.config.ts` configuration:
75
73
 
76
74
  ```typescript
77
- // owd.config.ts
78
- export const owdConfig = {
79
- theme: './desktop/themes/owd-theme-win95',
80
- }
75
+ // nuxt.config.ts
76
+ export default defineNuxtConfig({
77
+ modules: [
78
+ "@owdproject/core",
79
+ ],
80
+
81
+ extends: [
82
+ "./desktop/theme/theme-win95"
83
+ ],
84
+
85
+ ...
81
86
  ```
82
87
 
83
88
  **2. Using a theme from GitHub:**
84
89
 
85
- To use a theme directly from a GitHub repository, specify it in this format: `github:<username>/<repository>`:
90
+ To use a theme directly specifying a GitHub repository, use this format: `github:<username>/<repository>`:
86
91
 
87
92
  ```typescript
88
- // owd.config.ts
89
- export const owdConfig = {
90
- theme: ['github:owdproject/theme-win95', { install: true }],
91
- }
93
+ // nuxt.config.ts
94
+ export default defineNuxtConfig({
95
+ modules: [
96
+ "@owdproject/core",
97
+ ],
98
+
99
+ extends: [
100
+ "github:owdproject/theme-gnome",
101
+ { install: true }
102
+ ],
103
+
104
+ ...
92
105
  ```
93
106
 
94
107
  ## Contributing
@@ -111,10 +124,10 @@ Then, clone your fork using HTTPS or SSH:
111
124
 
112
125
  ```bash
113
126
  # Clone using HTTPS
114
- git clone https://github.com/<your-username>/owd-client.git
127
+ git clone https://github.com/<your-username>/client.git
115
128
 
116
129
  # Clone using SSH
117
- git clone git@github.com:<your-username>/owd-client.git
130
+ git clone git@github.com:<your-username>/client.git
118
131
  ```
119
132
 
120
133
  Once you have cloned the repository, navigate to the project folder.
package/index.ts CHANGED
@@ -5,6 +5,7 @@ import pkg from './package.json'
5
5
  export default defineNuxtModule({
6
6
  meta: {
7
7
  name: 'owd-core',
8
+ priority: 9999,
8
9
  },
9
10
  async setup(options, nuxt) {
10
11
  const {resolve} = createResolver(import.meta.url)
@@ -16,12 +17,6 @@ export default defineNuxtModule({
16
17
 
17
18
  nuxt.options.runtimeConfig.public.coreVersion = pkg.version
18
19
 
19
- // configure nuxt plugins
20
-
21
- nuxt.options.primevue = nuxt.options.primevue || {};
22
- nuxt.options.primevue.options = nuxt.options.primevue.options || {};
23
- nuxt.options.primevue.options.theme = nuxt.options.primevue.options.theme || {};
24
-
25
20
  {
26
21
 
27
22
  // install open web desktop apps
@@ -36,20 +31,31 @@ export default defineNuxtModule({
36
31
 
37
32
  {
38
33
 
39
- // install tailwind
34
+ // install primevue
40
35
 
41
- await installModule("@nuxtjs/tailwindcss", {
42
- viewer: false,
43
- })
36
+ nuxt.options.primevue = nuxt.options.primevue || {};
37
+ nuxt.options.primevue.options = nuxt.options.primevue.options || {};
38
+ nuxt.options.primevue.options.theme = nuxt.options.primevue.options.theme || {};
39
+
40
+ await installModule("@primevue/nuxt-module")
44
41
 
45
42
  }
46
43
 
47
44
  {
48
45
 
49
- // install primevue
46
+ // install tailwind
50
47
 
51
- nuxt.options.modules.push('@primevue/nuxt-module')
52
- await installModule("@primevue/nuxt-module")
48
+ const tailwindPaths = nuxt.options.runtimeConfig?.owd?.tailwindPaths || []
49
+ tailwindPaths.push('./runtime/components/**/*.{vue,mjs,ts}') // Aggiungi sempre questo al core
50
+
51
+ nuxt.options.tailwindcss = nuxt.options.tailwindcss || {}
52
+ nuxt.options.tailwindcss.config = nuxt.options.tailwindcss.config || {}
53
+ // @ts-ignore
54
+ nuxt.options.tailwindcss.config.content = tailwindPaths
55
+
56
+ await installModule('@nuxtjs/tailwindcss', {
57
+ viewer: false,
58
+ })
53
59
 
54
60
  }
55
61
 
@@ -57,7 +63,6 @@ export default defineNuxtModule({
57
63
 
58
64
  // install pinia
59
65
 
60
- nuxt.options.modules.push('@pinia/nuxt')
61
66
  await installModule("@pinia/nuxt")
62
67
 
63
68
  }
@@ -66,7 +71,6 @@ export default defineNuxtModule({
66
71
 
67
72
  // install @nuxt/fonts
68
73
 
69
- nuxt.options.modules.push('@nuxt/fonts')
70
74
  await installModule("@nuxt/fonts")
71
75
 
72
76
  }
@@ -75,7 +79,6 @@ export default defineNuxtModule({
75
79
 
76
80
  // install @nuxt/icon
77
81
 
78
- nuxt.options.modules.push('@nuxt/icon')
79
82
  await installModule("@nuxt/icon", {
80
83
  clientBundle: {
81
84
  scan: true,
@@ -89,7 +92,6 @@ export default defineNuxtModule({
89
92
 
90
93
  // install @vueuse/nuxt
91
94
 
92
- nuxt.options.modules.push('@vueuse/nuxt')
93
95
  await installModule("@vueuse/nuxt")
94
96
 
95
97
  }
@@ -98,7 +100,6 @@ export default defineNuxtModule({
98
100
 
99
101
  // install @nuxtjs/i18n
100
102
 
101
- nuxt.options.modules.push('@nuxtjs/i18n')
102
103
  await installModule("@nuxtjs/i18n")
103
104
 
104
105
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@owdproject/core",
3
- "version": "3.0.0-alpha.5",
3
+ "version": "3.0.0-alpha.7",
4
4
  "description": "Open Web Desktop core",
5
5
  "keywords": [
6
6
  "web",
@@ -114,13 +114,13 @@ const classes = computed(() => {
114
114
  <vue-resizable
115
115
  ref="windowResizableController"
116
116
  :class="classes"
117
- :width="windowController?.state.size?.width"
118
- :height="windowController?.state.size?.height"
119
- :min-height="windowController?.state.size?.minHeight"
120
- :max-width="windowController?.state.size?.maxWidth"
121
- :max-height="windowController?.state.size?.maxHeight"
122
- :left="windowController?.state.position?.x"
123
- :top="windowController?.state.position?.y"
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?.state.position?.z}"
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
  >
@@ -1,3 +1,7 @@
1
+ import {TerminalManager} from "../core/managers/TerminalManager";
2
+
3
+ const terminalManager = new TerminalManager()
4
+
1
5
  export function useTerminalManager() {
2
- // todo reimplement index of applications cmds
6
+ return terminalManager
3
7
  }
@@ -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 ?? undefined
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
- await this.applicationManager.execAppCommand(this.id, command)
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
- if (!this.state.pinned) this.state.pinned = this.config.pinned
132
- if (!this.state.position) this.state.position = deepClone(this.config.position)
152
+ const overridable = this.config.overridable || {}
133
153
 
134
- if (!this.state.minimizable) this.state.minimizable = this.config.minimizable
135
- if (!this.state.maximized) this.state.maximized = this.config.maximized
136
- if (!this.state.destroyable) this.state.destroyable = this.config.destroyable
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
- if (!this.state.size) {
141
- this.state.size = deepClone(this.config.size)
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
- // sizes
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 height() {
240
- if (typeof this.state.size?.height === 'undefined') {
241
- return this.config.size.height
239
+ get position() {
240
+ if (typeof this.state.position === 'undefined') {
241
+ return this.config.position
242
242
  }
243
243
 
244
- return this.state.size.height
244
+ return this.state.position
245
245
  }
246
246
 
247
- get maxHeight() {
248
- if (typeof this.state.size?.maxHeight === 'undefined') {
249
- return this.config.size.maxHeight ?? 600
250
- }
247
+ // sizes
251
248
 
252
- return this.state.size.maxHeight
253
- }
249
+ get size() {
250
+ const stateSize = this.state.size || {}
251
+ const configSize = this.config.size || {}
254
252
 
255
- get minHeight() {
256
- if (typeof this.state.size?.minHeight === 'undefined') {
257
- return this.config.size.minHeight
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 (typeof this.state.minimizable === 'undefined') {
276
- return !!this.config.minimizable
275
+ if (this.config.overridable?.minimizable) {
276
+ return !!this.state.minimizable
277
277
  }
278
278
 
279
- return this.state.minimizable
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 (typeof this.state.maximized === 'undefined') {
308
- return !!this.config.maximized
307
+ if (this.config.overridable?.maximized) {
308
+ return !!this.state.maximized
309
309
  }
310
310
 
311
- return this.state.maximized
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
- return !!this.state.destroyable
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
- return !!this.state.draggable
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
- return !!this.state.resizable
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 applicationController;
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
  }
@@ -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
 
@@ -19,3 +21,13 @@ export function normalizeApplicationConfig(config: ApplicationConfig): Applicati
19
21
  entries: normalizedEntries,
20
22
  }
21
23
  }
24
+
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 || []
29
+
30
+ if (!nuxt.options.runtimeConfig.owd.tailwindPaths.includes(path)) {
31
+ nuxt.options.runtimeConfig.owd.tailwindPaths.push(path)
32
+ }
33
+ }
@@ -1,7 +1,30 @@
1
- export function deepClone(obj: any) {
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 (
@@ -7,6 +7,7 @@ export function handleWindowControllerProps(windowController: any) {
7
7
 
8
8
  return {
9
9
  ...windowController,
10
+ ...windowController.config,
10
11
  state: {
11
12
  ...windowController.config,
12
13
  },
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(appId: string, config: ApplicationConfig): Promise<IApplicationController>
14
+ defineApp(id: string, config: ApplicationConfig): Promise<IApplicationController>
15
15
 
16
16
  closeApp(id: string): void
17
17
 
18
- launchAppEntry(appId: string, entry: string): Promise<IApplicationController | undefined>
19
- execAppCommand(appId: string, command: string): Promise<IApplicationController | undefined>
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 sIApplicationController {
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 width(): WindowSizeValue
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
@@ -312,9 +302,9 @@ interface DesktopSystemBarConfig {
312
302
 
313
303
  // TERMINAL
314
304
 
315
- interface CommandFn {
316
- fn: (app: IApplicationController, args: string[]) => string | CommandOutput | void
317
- app: IApplicationController
305
+ type TerminalCommand = {
306
+ name: string
307
+ applicationId: string
318
308
  }
319
309
 
320
310
  interface CommandOutput {