@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,157 @@
1
+ <script setup lang="ts">
2
+ import {ref,provide} from 'vue'
3
+ import {computed} from "@vue/reactivity"
4
+ import {useDesktopManager} from "../../../composables/useDesktopManager"
5
+ import {handleWindowControllerProps} from "../../../utils/utilsWindow"
6
+
7
+ const props = defineProps<{
8
+ window?: IWindowController
9
+ content?: WindowContent
10
+ }>()
11
+
12
+ const emit = defineEmits([
13
+ 'resize:start',
14
+ 'resize:move',
15
+ 'resize:end',
16
+ 'drag:start',
17
+ 'drag:move',
18
+ 'drag:end',
19
+ 'close',
20
+ 'open',
21
+ 'blur',
22
+ 'focus',
23
+ 'minimize',
24
+ 'restore',
25
+ 'maximize',
26
+ 'unmaximize',
27
+ 'toggle-maximize'
28
+ ])
29
+
30
+ const desktopManager = useDesktopManager() // used in <style v-bind>
31
+ const windowController: IWindowController = handleWindowControllerProps(props.window)
32
+
33
+ provide<IWindowController>('windowController', windowController)
34
+ provide<WindowContent>('windowContent', props.content ?? {})
35
+
36
+ const isDragging = ref(false)
37
+ const isResizing = ref(false)
38
+
39
+ function onWindowPointerDown() {
40
+ windowController?.actions?.setActive(true)
41
+ windowController?.actions?.bringToFront()
42
+ }
43
+
44
+ function onWindowDragStart(data: any) {
45
+ isDragging.value = true
46
+
47
+ emit('drag:start', data)
48
+ }
49
+
50
+ function onWindowDragMove(data: any) {
51
+ emit('drag:move', data)
52
+ }
53
+
54
+ function onWindowDragEnd(data: { left: number; top: number }) {
55
+ windowController?.actions?.setPosition({
56
+ x: data.left,
57
+ y: data.top
58
+ })
59
+
60
+ isDragging.value = false
61
+
62
+ emit('drag:end', data)
63
+ }
64
+
65
+ function onWindowResizeStart(data: any) {
66
+ isResizing.value = true
67
+
68
+ emit('resize:start', data)
69
+ }
70
+
71
+ function onWindowResizeMove(data: any) {
72
+ emit('resize:move', data)
73
+ }
74
+
75
+ /**
76
+ * Window end resize event
77
+ */
78
+ function onWindowResizeEnd(data: { left: number; top: number, width: number, height: number }) {
79
+ isResizing.value = false
80
+
81
+ windowController?.actions?.setPosition({
82
+ x: data.left,
83
+ y: data.top
84
+ })
85
+
86
+ windowController?.actions?.setSize({
87
+ width: data.width,
88
+ height: data.height
89
+ })
90
+
91
+ emit('resize:end', data)
92
+ }
93
+
94
+ const classes = computed(() => {
95
+ const list = ['owd-window']
96
+
97
+ if (windowController?.state.focused) {
98
+ list.push('owd-window--focused')
99
+ }
100
+
101
+ if (isDragging.value) {
102
+ list.push('owd-window--dragging')
103
+ }
104
+
105
+ if (isResizing.value) {
106
+ list.push('owd-window--resizing')
107
+ }
108
+
109
+ return list
110
+ })
111
+ </script>
112
+
113
+ <template>
114
+ <vue-resizable
115
+ ref="windowResizableController"
116
+ :class="classes"
117
+ :width="windowController?.state.size?.width"
118
+ :height="windowController?.state.size?.height"
119
+ :min-width="windowController?.state.size?.minWidth"
120
+ :min-height="windowController?.state.size?.minHeight"
121
+ :max-width="windowController?.state.size?.maxWidth"
122
+ :max-height="windowController?.state.size?.maxHeight"
123
+ :left="windowController?.state.position?.x"
124
+ :top="windowController?.state.position?.y"
125
+ :active="windowController?.isResizable ? undefined : []"
126
+ @drag:start="onWindowDragStart"
127
+ @drag:move="onWindowDragMove"
128
+ @drag:end="onWindowDragEnd"
129
+ @resize:start="onWindowResizeStart"
130
+ @resize:move="onWindowResizeMove"
131
+ @resize:end="onWindowResizeEnd"
132
+ :style="{zIndex: windowController?.state.position?.z}"
133
+ :drag-selector="windowController?.isDraggable ? '.owd-window-nav__draggable' : '.owd-window-nav__draggable-none'"
134
+ @pointerdown="onWindowPointerDown"
135
+ >
136
+
137
+ <slot/>
138
+
139
+ </vue-resizable>
140
+ </template>
141
+
142
+ <style scoped lang="scss">
143
+ .owd-window {
144
+ position: v-bind('desktopManager.config.windows.position');
145
+
146
+ &--dragging, &--resizing {
147
+ :deep(.owd-window__content) {
148
+ pointer-events: none;
149
+ }
150
+ }
151
+
152
+ :deep(.owd-window__content) {
153
+ overflow-y: auto;
154
+ height: 100%;
155
+ }
156
+ }
157
+ </style>
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import {inject} from "vue"
3
+ import {computed} from "@vue/reactivity"
4
+
5
+ const windowContent = inject<WindowContent>('windowContent')
6
+
7
+ const classes = computed(() => {
8
+ const list = ['owd-window__content']
9
+
10
+ if (windowContent?.centered) {
11
+ list.push('owd-window__content--centered')
12
+ }
13
+
14
+ if (windowContent?.padded) {
15
+ list.push('p-2')
16
+ }
17
+
18
+ return list
19
+ })
20
+ </script>
21
+
22
+ <template>
23
+ <div :class="classes">
24
+ <slot />
25
+ </div>
26
+ </template>
27
+
28
+ <style scoped lang="scss">
29
+
30
+ </style>
@@ -0,0 +1,43 @@
1
+ <script setup lang="ts">
2
+ import {inject} from "vue"
3
+ import {computed} from "@vue/reactivity"
4
+
5
+ const windowController = inject<IWindowController>('windowController')
6
+
7
+ const classes = computed(() => {
8
+ const list = ['owd-window-nav']
9
+
10
+ if (typeof windowController?.state.active === 'undefined' || !!windowController?.state.active) {
11
+ list.push('owd-window-nav--active')
12
+ }
13
+
14
+ if (typeof windowController?.state.focused === 'undefined' || !!windowController?.state.focused) {
15
+ list.push('owd-window-nav--focused')
16
+ }
17
+
18
+ return list
19
+ })
20
+ </script>
21
+
22
+ <template>
23
+ <div :class="classes">
24
+ <div class="owd-window-nav__draggable"/>
25
+
26
+ <slot/>
27
+
28
+ </div>
29
+ </template>
30
+
31
+ <style lang="scss">
32
+ .owd-window-nav {
33
+ position: relative;
34
+
35
+ &__draggable {
36
+ position: absolute;
37
+ top: 0;
38
+ left: 0;
39
+ right: 0;
40
+ height: 100%;
41
+ }
42
+ }
43
+ </style>
@@ -0,0 +1,21 @@
1
+ import {useApplicationManager} from './useApplicationManager'
2
+ import {computed} from "@vue/reactivity"
3
+
4
+ export function useAppEntries() {
5
+ const applicationManager = useApplicationManager()
6
+
7
+ const sortedAppEntries = function(sortBy: 'title'): Ref<ApplicationEntryWithInherited[]> {
8
+ return computed(() => {
9
+ const currentEntries = [...applicationManager.appsEntries]
10
+
11
+ if (sortBy === 'title') {
12
+ currentEntries.sort((a, b) => (a.title || '').localeCompare(b.title || ''))
13
+ } else if (sortBy === 'category') {
14
+ currentEntries.sort((a, b) => (a.category || '').localeCompare(b.category || ''))
15
+ }
16
+ return currentEntries
17
+ })
18
+ }
19
+
20
+ return { sortedAppEntries }
21
+ }
@@ -0,0 +1,7 @@
1
+ import {ApplicationManager} from "../core/managers/ApplicationManager";
2
+
3
+ const applicationManager = new ApplicationManager()
4
+
5
+ export function useApplicationManager(): IApplicationManager {
6
+ return applicationManager
7
+ }
@@ -0,0 +1,19 @@
1
+ import {defineStore} from "pinia"
2
+ import {ref} from "@vue/reactivity"
3
+
4
+ export const useApplicationState = (appId: string) => {
5
+ return defineStore(`owd/application/${appId}`, () => {
6
+ const meta: Ref<any> = ref({})
7
+
8
+ const windows: Ref<{[windowId: string]: WindowStoredState}> = ref({})
9
+
10
+ return {
11
+ windows,
12
+ meta,
13
+ }
14
+ }, {
15
+ persistedState: {
16
+ persist: true
17
+ },
18
+ })()
19
+ }
@@ -0,0 +1,7 @@
1
+ import {DesktopManager} from "../core/managers/DesktopManager";
2
+
3
+ const desktopManager = new DesktopManager()
4
+
5
+ export function useDesktopManager() {
6
+ return desktopManager
7
+ }
@@ -0,0 +1,3 @@
1
+ export function useTerminalManager() {
2
+ // todo reimplement index of applications cmds
3
+ }
@@ -0,0 +1,209 @@
1
+ import {nanoid} from "nanoid";
2
+ import {WindowController} from "./WindowController";
3
+ import {useApplicationManager} from "../../composables/useApplicationManager"
4
+ import {useApplicationState} from "../../composables/useApplicationState"
5
+ import {useDesktopManager} from "../../composables/useDesktopManager"
6
+ import {debugLog, debugError} from "../../utils/utilsDebug"
7
+ import {useDesktopWorkspaceStore} from "../../stores/storeDesktopWorkspace"
8
+ import {reactive} from '@vue/reactivity'
9
+
10
+ export class ApplicationController implements IApplicationController {
11
+ private readonly applicationManager: IApplicationManager
12
+ private readonly desktopManager: IDesktopManager
13
+
14
+ public readonly id
15
+ public readonly config
16
+ public readonly store
17
+
18
+ public windows = reactive(new Map<string, IWindowController>())
19
+
20
+ public isRunning: boolean = false
21
+
22
+ constructor(
23
+ id: string,
24
+ config: ApplicationConfig
25
+ ) {
26
+ this.applicationManager = useApplicationManager()
27
+ this.desktopManager = useDesktopManager()
28
+
29
+ this.id = id
30
+ this.config = config
31
+ this.store = useApplicationState(id)
32
+ }
33
+
34
+ public async initApplication(): Promise<void> {
35
+ // set as default app for specific purposes
36
+ // todo improve this and move it in a store
37
+ if (this.config.provides) {
38
+ const existingDefault = this.desktopManager.getDefaultApp(this.config.provides.name)
39
+
40
+ if (!existingDefault) {
41
+ this.desktopManager.setDefaultApp(
42
+ this.config.provides.name,
43
+ this,
44
+ this.config.entries[this.config.provides.entry] as ApplicationEntry
45
+ )
46
+
47
+ debugLog(`${this.config.title} has been set as predefined app for "${this.config.provides}"`)
48
+ }
49
+ }
50
+
51
+ if (this.store.$persistedState) {
52
+ await this.store.$persistedState.isReady()
53
+ }
54
+
55
+ // set default meta values
56
+ this.store.meta = this.config.meta ?? undefined
57
+
58
+ // once app is defined, always run "onReady"
59
+ if (typeof this.config.onReady === 'function') {
60
+ this.config.onReady(this)
61
+ }
62
+
63
+ // restore application state
64
+ await this.restoreApplication()
65
+ }
66
+
67
+ /**
68
+ * App always tries to restore previous windows
69
+ * and returns a boolean if it succeeded
70
+ */
71
+ public async restoreApplication() {
72
+ if (typeof this.config.onRestore === 'function') {
73
+ await this.config.onRestore(this)
74
+ }
75
+
76
+ if (!this.store.windows || Object.keys(this.store.windows).length === 0) {
77
+ return false
78
+ }
79
+
80
+ this.restoreWindows()
81
+
82
+ this.setRunning(true)
83
+
84
+ return true
85
+ }
86
+
87
+ private restoreWindows() {
88
+ Object.keys(this.store.windows).map(windowId => {
89
+ const windowStore: WindowStoredState | undefined = this.store.windows[windowId]
90
+
91
+ if (windowStore) {
92
+ this.openWindow(windowStore.model, windowStore, {isRestoring: true})
93
+ }
94
+ })
95
+
96
+ debugLog('Windows have been restored', this.windows)
97
+ }
98
+
99
+ public openWindow(model: string, windowStoredState: WindowStoredState | undefined, meta?: any) {
100
+ const desktopWorkspaceStore = useDesktopWorkspaceStore()
101
+
102
+ if (!this.config.windows || !this.config.windows.hasOwnProperty(model)) {
103
+ debugError(`Window model "${model}" not found`)
104
+ return
105
+ }
106
+
107
+ let windowId: string
108
+
109
+ if (!windowStoredState) {
110
+
111
+ windowId = `${model}-${nanoid(6)}`
112
+
113
+ const windowConfig: WindowConfig = this.config.windows[model] as WindowConfig
114
+ const screenHeight = window.innerHeight
115
+ const centerY = (screenHeight - Number(windowConfig.size.height)) / 2
116
+ const positionY = windowConfig.position?.y !== undefined
117
+ ? window.scrollY + windowConfig.position.y
118
+ : window.scrollY + centerY
119
+
120
+ this.store.windows[windowId] = {
121
+ model,
122
+ state: {
123
+ id: windowId,
124
+ active: true,
125
+ focused: false,
126
+ position: {
127
+ x: windowConfig.position?.x,
128
+ y: positionY,
129
+ },
130
+ createdAt: +new Date(),
131
+ workspace: desktopWorkspaceStore.active
132
+ }
133
+ }
134
+
135
+ windowStoredState = this.store.windows[windowId]
136
+
137
+ } else {
138
+
139
+ // restore previous id if state is defined
140
+ windowId = windowStoredState.state.id
141
+
142
+ }
143
+
144
+ const windowConfig = this.config.windows[model] as WindowConfig
145
+
146
+ const windowController = new WindowController(
147
+ this,
148
+ model,
149
+ windowConfig,
150
+ windowStoredState!
151
+ )
152
+
153
+ if (!meta?.isRestoring) {
154
+ windowController.actions.bringToFront()
155
+ }
156
+
157
+ this.windows.set(
158
+ windowId,
159
+ windowController,
160
+ )
161
+
162
+ this.setRunning(true)
163
+
164
+ return windowController
165
+ }
166
+
167
+ public closeWindow(windowId: string) {
168
+ delete this.store.windows[windowId];
169
+ this.windows.delete(windowId);
170
+
171
+ if (this.windows.size === 0) {
172
+ this.applicationManager.closeApp(this.id)
173
+ }
174
+ }
175
+
176
+ public closeAllWindows() {
177
+ this.store.windows = {}
178
+ this.windows.clear()
179
+ }
180
+
181
+ get windowsOpened() {
182
+ return this.windows;
183
+ }
184
+
185
+ public setRunning(value: boolean): void {
186
+ this.isRunning = value
187
+ }
188
+
189
+ // meta
190
+
191
+ get meta() {
192
+ console.log('META', this.id, this.store.meta)
193
+ return this.store.meta
194
+ }
195
+
196
+ getMeta(key: string) {
197
+ return this.meta[key]
198
+ }
199
+
200
+ setMeta(key: string, value: any) {
201
+ this.meta[key] = value
202
+ }
203
+
204
+ // commands
205
+
206
+ async execCommand(input: string): Promise<CommandOutput | void> {
207
+ await this.applicationManager.execAppCommand(this.id, input)
208
+ }
209
+ }