@owdproject/core 3.0.0-alpha.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.
Files changed (37) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +141 -0
  3. package/index.ts +10 -0
  4. package/module/index.ts +146 -0
  5. package/package.json +45 -0
  6. package/runtime/components/Core/Application/CoreApplicationRender.vue +17 -0
  7. package/runtime/components/Core/Application/CoreApplicationWindowsRender.vue +19 -0
  8. package/runtime/components/Core/Background/CoreBackground.vue +17 -0
  9. package/runtime/components/Core/Desktop/CoreDesktop.vue +77 -0
  10. package/runtime/components/Core/Explorer/CoreExplorerFile.vue +67 -0
  11. package/runtime/components/Core/Explorer/CoreExplorerFolder.vue +11 -0
  12. package/runtime/components/Core/Time/CoreTime.vue +53 -0
  13. package/runtime/components/Core/Window/CoreWindow.vue +157 -0
  14. package/runtime/components/Core/Window/CoreWindowContent.vue +30 -0
  15. package/runtime/components/Core/Window/CoreWindowNav.vue +43 -0
  16. package/runtime/composables/useAppEntries.ts +21 -0
  17. package/runtime/composables/useApplicationManager.ts +7 -0
  18. package/runtime/composables/useApplicationState.ts +19 -0
  19. package/runtime/composables/useDesktopManager.ts +7 -0
  20. package/runtime/composables/useTerminalManager.ts +3 -0
  21. package/runtime/core/controllers/ApplicationController.ts +209 -0
  22. package/runtime/core/controllers/WindowController.ts +413 -0
  23. package/runtime/core/managers/ApplicationManager.ts +256 -0
  24. package/runtime/core/managers/DesktopManager.ts +41 -0
  25. package/runtime/plugins/resize.client.ts +6 -0
  26. package/runtime/stores/storeDesktop.ts +39 -0
  27. package/runtime/stores/storeDesktopVolume.ts +17 -0
  28. package/runtime/stores/storeDesktopWindow.ts +20 -0
  29. package/runtime/stores/storeDesktopWorkspace.ts +59 -0
  30. package/runtime/utils/utilsCommon.ts +35 -0
  31. package/runtime/utils/utilsDebug.ts +30 -0
  32. package/runtime/utils/utilsDesktop.ts +12 -0
  33. package/runtime/utils/utilsTerminal.ts +5 -0
  34. package/runtime/utils/utilsWindow.ts +14 -0
  35. package/tsconfig.json +3 -0
  36. package/types/index.d.ts +9 -0
  37. package/types/owd.d.ts +313 -0
@@ -0,0 +1,413 @@
1
+ import {useApplicationManager} from '../../composables/useApplicationManager'
2
+ import {useDesktopWindowStore} from '../../stores/storeDesktopWindow'
3
+ import {deepClone} from '../../utils/utilsCommon'
4
+ import {markRaw} from '@vue/reactivity'
5
+ import {defineAsyncComponent} from "vue"
6
+
7
+ export class WindowController implements IWindowController {
8
+ public readonly application: IApplicationController
9
+
10
+ public readonly instanced: boolean = true
11
+ public readonly model: string
12
+
13
+ public config: WindowConfig = {
14
+ title: '',
15
+ category: '',
16
+
17
+ component: undefined,
18
+
19
+ // position
20
+ position: {
21
+ x: 0,
22
+ y: 0,
23
+ z: 0,
24
+ },
25
+
26
+ // sizes
27
+ size: {
28
+ width: undefined,
29
+ height: undefined,
30
+ },
31
+
32
+ // minimize
33
+ minimizable: true,
34
+
35
+ // maximize
36
+ maximized: false,
37
+ maximizable: false,
38
+
39
+ // destroy
40
+ destroyable: true,
41
+
42
+ // draggable
43
+ draggable: true,
44
+
45
+ // resizable
46
+ resizable: true,
47
+ }
48
+
49
+ public override: WindowOverride = {}
50
+
51
+ public meta: any = {}
52
+ private storedState: WindowStoredState
53
+
54
+ constructor(
55
+ application: IApplicationController,
56
+ model: string,
57
+ windowConfig: WindowConfig,
58
+ windowStoredState: WindowStoredState,
59
+ ) {
60
+ this.application = application
61
+ this.model = model
62
+ this.storedState = windowStoredState
63
+
64
+ this.setConfig(windowConfig)
65
+
66
+ this.restoreState()
67
+ }
68
+
69
+ private setConfig(config: WindowConfig) {
70
+ // component
71
+ if (config.component) {
72
+ this.config.component = markRaw(
73
+ defineAsyncComponent(config.component)
74
+ )
75
+ }
76
+
77
+ // title
78
+ if (config.title) this.config.title = config.title
79
+ if (config.icon) this.config.icon = config.icon
80
+
81
+ // position
82
+ if (!this.config.position) this.config.position = { x: 0, y: 0, z: 0 }
83
+ if (config.position?.x) this.config.position.x = config.position.x
84
+ if (config.position?.y) this.config.position.y = config.position.y
85
+ if (config.position?.z) this.config.position.z = config.position.z
86
+
87
+ // sizes
88
+ if (config.size?.width) this.config.size.width = config.size.width
89
+ if (config.size?.height) this.config.size.height = config.size.height
90
+ if (config.size?.minWidth) this.config.size.minWidth = config.size.minWidth
91
+ if (config.size?.minHeight) this.config.size.minHeight = config.size.minHeight
92
+ if (config.size?.maxWidth) this.config.size.maxWidth = config.size.maxWidth
93
+ if (config.size?.maxHeight) this.config.size.maxHeight = config.size.maxHeight
94
+
95
+ // minimize
96
+ if (typeof config.minimizable !== 'undefined') {
97
+ this.config.minimizable = config.minimizable
98
+ }
99
+ if (typeof config.maximizable !== 'undefined') {
100
+ this.config.maximizable = config.maximizable
101
+ }
102
+
103
+ // maximize
104
+ if (typeof config.maximized !== 'undefined') {
105
+ this.config.maximized = config.maximized
106
+ }
107
+
108
+ // draggable
109
+ if (typeof config.draggable !== 'undefined') {
110
+ this.config.draggable = config.draggable
111
+ }
112
+
113
+ // resizable
114
+ if (typeof config.resizable !== 'undefined') {
115
+ this.config.resizable = config.resizable
116
+ }
117
+
118
+ // destroy
119
+ if (typeof config.destroyable !== 'undefined') {
120
+ this.config.destroyable = config.destroyable
121
+ }
122
+ }
123
+
124
+ // state
125
+
126
+ get state() {
127
+ return this.storedState.state
128
+ }
129
+
130
+ 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)
133
+
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
139
+
140
+ if (!this.state.size) {
141
+ this.state.size = deepClone(this.config.size)
142
+ }
143
+ }
144
+
145
+ // position
146
+
147
+ private setPosition(data: { x: number, y: number}) {
148
+ if (!this.state.position) {
149
+ this.state.position = { x: 0, y: 0}
150
+ }
151
+
152
+ this.state.position.x = data.x
153
+ this.state.position.y = data.y
154
+ }
155
+
156
+ private setActive(value: boolean) {
157
+ this.state.active = value
158
+ }
159
+
160
+ private setFocus(value: boolean) {
161
+ this.state.focused = value
162
+ }
163
+
164
+ private bringToFront() {
165
+ const applicationManager = useApplicationManager()
166
+ const desktopWindowStore = useDesktopWindowStore()
167
+
168
+ if (!this.state.position) {
169
+ this.state.position = { x: 0, y: 0, z: 0 }
170
+ }
171
+
172
+ // already focused
173
+ if (this.state.focused) {
174
+ return
175
+ }
176
+
177
+ // set focus false on all other windows
178
+ for (const [windowId, window] of applicationManager.windowsOpened) {
179
+ window.actions.setFocus(false)
180
+ }
181
+
182
+ this.setFocus(true)
183
+
184
+ this.state.position.z = desktopWindowStore.incrementPositionZ()
185
+ }
186
+
187
+ // common
188
+
189
+ get title(): string {
190
+ if (typeof this.override.title !== 'undefined') {
191
+ return this.override.title
192
+ }
193
+
194
+ if (this.config.title) {
195
+ return this.config.title
196
+ }
197
+
198
+ return this.application.config.title
199
+ }
200
+
201
+ get icon() {
202
+ if (typeof this.override.icon !== 'undefined') {
203
+ return this.override.icon
204
+ }
205
+
206
+ if (this.config.icon) {
207
+ return this.config.icon
208
+ }
209
+
210
+ return this.application.config.icon
211
+ }
212
+
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
+ }
238
+
239
+ get height() {
240
+ if (typeof this.state.size?.height === 'undefined') {
241
+ return this.config.size.height
242
+ }
243
+
244
+ return this.state.size.height
245
+ }
246
+
247
+ get maxHeight() {
248
+ if (typeof this.state.size?.maxHeight === 'undefined') {
249
+ return this.config.size.maxHeight ?? 600
250
+ }
251
+
252
+ return this.state.size.maxHeight
253
+ }
254
+
255
+ get minHeight() {
256
+ if (typeof this.state.size?.minHeight === 'undefined') {
257
+ return this.config.size.minHeight
258
+ }
259
+
260
+ return this.state.size.minHeight
261
+ }
262
+
263
+ private setSize(data: { width: number, height: number}) {
264
+ if (!this.state.size) {
265
+ this.state.size = { width: undefined, height: undefined }
266
+ }
267
+
268
+ this.state.size.width = data.width
269
+ this.state.size.height = data.height
270
+ }
271
+
272
+ // minimize
273
+
274
+ get isMinimizable() {
275
+ if (typeof this.state.minimizable === 'undefined') {
276
+ return !!this.config.minimizable
277
+ }
278
+
279
+ return this.state.minimizable
280
+ }
281
+
282
+ private minimize() {
283
+ if (!this.isMinimizable) {
284
+ return false
285
+ }
286
+
287
+ this.state.active = false
288
+ return true
289
+ }
290
+
291
+ private toggleMinimize() {
292
+ this.state.active = !this.state.active
293
+ this.bringToFront()
294
+ }
295
+
296
+ // maximize
297
+
298
+ get isMaximizable() {
299
+ if (typeof this.state.maximizable === 'undefined') {
300
+ return !!this.config.maximizable
301
+ }
302
+
303
+ return this.state.maximizable
304
+ }
305
+
306
+ get isMaximized() {
307
+ if (typeof this.state.maximized === 'undefined') {
308
+ return !!this.config.maximized
309
+ }
310
+
311
+ return this.state.maximized
312
+ }
313
+
314
+ private toggleMaximize() {
315
+ if (!this.isMaximizable) {
316
+ return false
317
+ }
318
+
319
+ this.state.maximized = !this.state.maximized
320
+ return true
321
+ }
322
+
323
+ private maximize() {
324
+ if (!this.isMaximizable) {
325
+ return false
326
+ }
327
+
328
+ this.state.maximized = true
329
+ return true
330
+ }
331
+
332
+ private unmaximize() {
333
+ if (!this.isMaximizable) {
334
+ return false
335
+ }
336
+
337
+ this.state.maximized = false
338
+ return true
339
+ }
340
+
341
+ // destroy
342
+
343
+ get isDestroyable() {
344
+ return !!this.state.destroyable
345
+ }
346
+
347
+ private destroy() {
348
+ if (!this.isDestroyable) {
349
+ return false
350
+ }
351
+
352
+ this.application.closeWindow(this.state.id)
353
+
354
+ return true
355
+ }
356
+
357
+ // draggable
358
+ get isDraggable() {
359
+ return !!this.state.draggable
360
+ }
361
+
362
+ // resizable
363
+ get isResizable() {
364
+ return !!this.state.resizable
365
+ }
366
+
367
+ // workspace
368
+ private setWorkspace(workspaceId: string) {
369
+ this.state.workspace = workspaceId
370
+ }
371
+
372
+ // override
373
+
374
+ setTitleOverride(value: undefined|string) {
375
+ this.override.title = value
376
+ }
377
+
378
+ resetTitleOverride() {
379
+ this.override.title = undefined
380
+ }
381
+
382
+ get actions() {
383
+ return {
384
+ // position
385
+ setActive: this.setActive.bind(this),
386
+ setFocus: this.setFocus.bind(this),
387
+ bringToFront: this.bringToFront.bind(this),
388
+ setPosition: this.setPosition.bind(this),
389
+
390
+ // size
391
+ setSize: this.setSize.bind(this),
392
+
393
+ // minimize
394
+ minimize: this.minimize.bind(this),
395
+ toggleMinimize: this.toggleMinimize.bind(this),
396
+
397
+ // maximize
398
+ toggleMaximize: this.toggleMaximize.bind(this),
399
+ maximize: this.maximize.bind(this),
400
+ unmaximize: this.unmaximize.bind(this),
401
+
402
+ // destroy
403
+ destroy: this.destroy.bind(this),
404
+
405
+ // workspace
406
+ setWorkspace: this.setWorkspace.bind(this),
407
+
408
+ // override
409
+ setTitleOverride: this.setTitleOverride.bind(this),
410
+ resetTitleOverride: this.resetTitleOverride.bind(this),
411
+ }
412
+ }
413
+ }
@@ -0,0 +1,256 @@
1
+ import type {Reactive} from "@vue/reactivity"
2
+ import {reactive, markRaw} from "@vue/reactivity"
3
+ import {ApplicationController} from "../controllers/ApplicationController";
4
+ import {debugLog} from "../../utils/utilsDebug"
5
+
6
+ export class ApplicationManager implements IApplicationManager {
7
+ public apps = reactive(
8
+ new Map<string, IApplicationController>()
9
+ )
10
+
11
+ constructor() {
12
+ }
13
+
14
+ /**
15
+ * Import applications on nuxt start
16
+ */
17
+ public async importApps() {
18
+ const {owdConfig} = await import(`~~/owd.config`)
19
+
20
+ if (owdConfig && typeof owdConfig.loader === 'function') {
21
+ await owdConfig.loader()
22
+ }
23
+ }
24
+
25
+ /**
26
+ * Define new application
27
+ *
28
+ * @param id
29
+ * @param config
30
+ */
31
+ public async defineApp(id: string, config: ApplicationConfig) {
32
+ if (this.isAppDefined(id)) {
33
+ debugLog(`App "${id}" is already defined`);
34
+ return this.apps.get(id)!;
35
+ }
36
+
37
+ if (!config.version) config.version = 'unknown'
38
+ if (!config.description) config.description = ''
39
+ if (!config.category) config.category = 'other'
40
+
41
+ const applicationConfig = markRaw(config)
42
+
43
+ const applicationController: IApplicationController = new ApplicationController(id, applicationConfig)
44
+
45
+ // finalize application setup doing other async operations
46
+ await applicationController.initApplication()
47
+
48
+ // define application
49
+ this.apps.set(id, applicationController)
50
+
51
+ return applicationController
52
+ }
53
+
54
+ /**
55
+ * Check if app has been defned
56
+ *
57
+ * @param id
58
+ */
59
+ public isAppDefined(id: string) {
60
+ return this.apps.has(id)
61
+ }
62
+
63
+ /**
64
+ * Check if app is running
65
+ *
66
+ * @param id
67
+ */
68
+ public isAppRunning(id: string) {
69
+ if (!this.isAppDefined(id)) {
70
+ throw Error(`App "${id}" is not defined`);
71
+ }
72
+
73
+ const applicationController: IApplicationController = this.apps.get(id)!
74
+
75
+ if (!applicationController.isRunning) {
76
+ return false
77
+ }
78
+
79
+ return true
80
+ }
81
+
82
+ /**
83
+ * Launch app rntry
84
+ *
85
+ * @param id
86
+ * @param entryKey
87
+ */
88
+ public async launchAppEntry(id: string, entryKey: string) {
89
+ if (!this.isAppDefined(id)) {
90
+ throw Error(`App "${id}" is not defined`);
91
+ }
92
+
93
+ const applicationController: IApplicationController = this.apps.get(id)!
94
+
95
+ if (applicationController.config.entries && !applicationController.config.entries.hasOwnProperty(entryKey)) {
96
+ throw Error(`App entry "${entryKey}" is not defined in ${id} application`);
97
+ }
98
+
99
+ const entry: ApplicationEntry = applicationController.config.entries[entryKey]!
100
+
101
+ console.log('dio cane', entry)
102
+
103
+ await this.execAppCommand(applicationController.id, entry.command)
104
+ }
105
+
106
+ /**
107
+ * Run app command
108
+ *
109
+ * @param id
110
+ * @param command
111
+ */
112
+ public async execAppCommand(id: string, command: string) {
113
+ if (!this.isAppDefined(id)) {
114
+ throw Error(`App "${id}" is not defined`);
115
+ }
116
+
117
+ const applicationController: IApplicationController = this.apps.get(id)!
118
+
119
+ if (applicationController.config.commands && !applicationController.config.commands.hasOwnProperty(command)) {
120
+ throw Error(`App command "${command}" is not defined in ${id} application`);
121
+ }
122
+
123
+ const commandSplit: string[] = command.split(" ")
124
+
125
+ const commandFn: any = applicationController.config.commands![
126
+ commandSplit[0] as keyof typeof applicationController.config.commands
127
+ ]
128
+
129
+ commandFn(applicationController, commandSplit.shift())
130
+
131
+ applicationController.setRunning(true)
132
+
133
+ return applicationController;
134
+ }
135
+
136
+ /**
137
+ * Close application
138
+ *
139
+ * @param id
140
+ */
141
+ public closeApp(id: string) {
142
+ if (!this.isAppDefined(id)) {
143
+ throw Error(`App "${id}" is not defined`);
144
+ }
145
+
146
+ const applicationController: IApplicationController = this.apps.get(id)!
147
+
148
+ applicationController.closeAllWindows()
149
+ applicationController.setRunning(false)
150
+ }
151
+
152
+ /**
153
+ * Array of available menu entries for system bars, docks
154
+ */
155
+ public get appsEntries() {
156
+ const entries: Reactive<ApplicationEntryWithInherited[]> = reactive([])
157
+
158
+ for (const applicationController of this.apps.values()) {
159
+ if (!applicationController.config.entries) {
160
+ continue
161
+ }
162
+
163
+ for (const entryKey of Object.keys(applicationController.config.entries)) {
164
+ const entry: ApplicationEntry = applicationController.config.entries[entryKey]!
165
+
166
+ entries.push({
167
+ application: applicationController,
168
+ title: entry.title !== undefined ? entry.title : applicationController.config.title,
169
+ icon: entry.icon !== undefined ? entry.icon : applicationController.config.icon,
170
+ category: entry.category !== undefined ? entry.category : applicationController.config.category,
171
+ command: entry.command
172
+ })
173
+ }
174
+ }
175
+
176
+ return entries
177
+ }
178
+
179
+ /**
180
+ * Array of opened windows for system bars, docks
181
+ */
182
+ public get windowsOpened() {
183
+ const windows: Reactive<Map<string, IWindowController>[]> = reactive([])
184
+
185
+ for (const applicationController of this.apps.values()) {
186
+ if (applicationController.isRunning) {
187
+ windows.push(...applicationController.windows)
188
+ }
189
+ }
190
+
191
+ return windows
192
+ }
193
+
194
+ /**
195
+ * Array of opened windows for system bars, docks
196
+ */
197
+ public get appsRunning() {
198
+ const applications: Reactive<IApplicationController[]> = reactive([])
199
+
200
+ for (const applicationController of this.apps.values()) {
201
+ if (applicationController.isRunning) {
202
+ applications.push(applicationController)
203
+ }
204
+ }
205
+
206
+ return applications
207
+ }
208
+
209
+ public getWindowOpenedId(windowId: string) {
210
+ const mapWindowFound: Map<string, IWindowController> | undefined = this.windowsOpened.find((window: any) => {
211
+ return window[1].state.id === windowId
212
+ })
213
+
214
+ if (mapWindowFound) {
215
+ // @ts-ignore
216
+ return mapWindowFound[1] as IWindowController
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Gets all unique categories from the installed apps
222
+ */
223
+ public get appCategories(): string[] {
224
+ const categories = new Set<string>()
225
+
226
+ for (const applicationController of this.apps.values()) {
227
+ if (applicationController.config.category) {
228
+ categories.add(applicationController.config.category)
229
+ }
230
+ }
231
+ return Array.from(categories).sort()
232
+ }
233
+
234
+ /**
235
+ * Gets the apps ordered by category
236
+ */
237
+ public get appsByCategory(): { [category: string]: IApplicationController[] } {
238
+ const categorizedApps: { [category: string]: IApplicationController[] } = {}
239
+
240
+ for (const applicationController of this.apps.values()) {
241
+ const category = applicationController.config.category || 'other'
242
+ if (!categorizedApps[category]) {
243
+ categorizedApps[category] = []
244
+ }
245
+ categorizedApps[category].push(applicationController)
246
+ }
247
+
248
+ for (const category in categorizedApps) {
249
+ categorizedApps[category]!.sort(
250
+ (a, b) => a.config.title.localeCompare(b.config.title)
251
+ )
252
+ }
253
+
254
+ return categorizedApps
255
+ }
256
+ }
@@ -0,0 +1,41 @@
1
+ import {deepMerge} from "../../utils/utilsCommon"
2
+
3
+ export class DesktopManager {
4
+ public config: DesktopConfig = {} as DesktopConfig
5
+ private defaultApps: DefaultAppsConfig = {}
6
+
7
+ constructor() {
8
+
9
+ }
10
+
11
+ public hasFeature(featureName: string) {
12
+ return this.config.features?.indexOf(featureName) !== -1
13
+ }
14
+
15
+ public setConfig(config: DesktopConfig) {
16
+ this.config = config
17
+ this.loadDefaultAppsFromConfig()
18
+ }
19
+
20
+ public overrideConfig(config: Partial<DesktopConfig>) {
21
+ this.config = deepMerge(this.config, config) as DesktopConfig
22
+ this.loadDefaultAppsFromConfig()
23
+ }
24
+
25
+ public setDefaultApp(feature: string, application: IApplicationController, entry: ApplicationEntry) {
26
+ this.defaultApps[feature] = {
27
+ application,
28
+ entry
29
+ }
30
+ }
31
+
32
+ public getDefaultApp(feature: string): DefaultAppConfig {
33
+ return this.defaultApps[feature] as DefaultAppConfig
34
+ }
35
+
36
+ private loadDefaultAppsFromConfig() {
37
+ if (this.config.defaultApps) {
38
+ this.defaultApps = { ...this.config.defaultApps }
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,6 @@
1
+ import VueResizable from 'vue-resizable/src/components/vue-resizable.vue'
2
+ import {defineNuxtPlugin} from "nuxt/app"
3
+
4
+ export default defineNuxtPlugin(nuxtApp => {
5
+ nuxtApp.vueApp.component('vue-resizable', VueResizable)
6
+ })