@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
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ <p align="center">
2
+ <img width="160" height="160" alt="Motion logo" src="https://avatars.githubusercontent.com/u/65117737?s=160&v=4" />
3
+ </p>
4
+ <h1 align="center">Open Web Desktop</h1>
5
+ <h3 align="center">
6
+ A framework for building web-based desktop experiences.
7
+ </h3>
8
+
9
+ ## Overview
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 and leverages the extensible architecture of Nuxt.js.
11
+
12
+ [Check out the demo](https://owdproject.github.io/docs) of the `client` base repository, decked with essential modules.
13
+
14
+ ## Features
15
+ - Open-source web desktop environment built with Nuxt.js
16
+ - Fully extendable through themes, apps, and modules
17
+ - Bundled with popular libraries like Pinia, VueUse, Mitt
18
+ - Designed to make the most of the Nuxt.js ecosystem
19
+ - Styled with PrimeVue and Tailwind for a consistent UI
20
+ - Fully localizable with i18n support
21
+
22
+ ## Getting started
23
+ Required software:
24
+
25
+ - [Git](https://git-scm.com)
26
+ - [Node](https://nodejs.org)
27
+
28
+ When you are ready, bootstrap a new project by running:
29
+ ```
30
+ npm create owd
31
+ ```
32
+ Once the process is complete, you can start to develop:
33
+ ```
34
+ # Run the dev server with hot-reload
35
+ npm run dev
36
+
37
+ # Build for production
38
+ npm run generate
39
+ ```
40
+
41
+ ## Modules
42
+ Open Web Desktop projects can be extended with themes, plugins, and desktop apps — whether contributed by the community or created custom for your needs. Explore available modules at [topics/owd-modules](https://github.com/topics/owd-modules).
43
+
44
+ ### Install a new app
45
+ You can simply install a new app with `npm install git+https://github.com/owdproject/app-todo.git` or by cloning it into `./desktop/apps/app-todo`. Then, define the application in your project configuration.
46
+
47
+ ```typescript
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
55
+ apps: [
56
+ './node_modules/owd-app-todo',
57
+ ],
58
+
59
+ loader: async () => {
60
+ await defineDesktopApp(AppTodo)
61
+ }
62
+ }
63
+ ```
64
+
65
+ ## Themes
66
+ Themes allow you to customize the look and feel of your Open Web Desktop instance.
67
+ You can explore available themes, ranging from popular OS designs to fully custom creations, at [topics/owd-themes](https://github.com/topics/owd-modules).
68
+
69
+ ### Install a new theme
70
+ You can install a new theme by defining its location in the `theme` property of your `owd.config.ts` file.
71
+ Themes can be loaded from local paths or directly from GitHub repositories.
72
+
73
+ **1. Using a local theme:**
74
+
75
+ To use a theme from a local folder, specify the path like this:
76
+
77
+ ```typescript
78
+ // owd.config.ts
79
+ export const owdConfig = {
80
+ theme: './desktop/themes/owd-theme-win95',
81
+ }
82
+ ```
83
+
84
+ **2. Using a theme from GitHub:**
85
+
86
+ To use a theme directly from a GitHub repository, specify it in this format: `github:<username>/<repository>`:
87
+
88
+ ```typescript
89
+ // owd.config.ts
90
+ export const owdConfig = {
91
+ theme: ['github:owdproject/theme-win95', { install: true }],
92
+ }
93
+ ```
94
+
95
+ ## Contributing
96
+
97
+ **Any contribution is welcome!** Open Web Desktop is built with Nuxt and follows a modular architecture, making it easy to contribute to the core codebase or create new modules, themes and desktop apps.
98
+
99
+ ### Local Development Setup
100
+
101
+ If you'd like to contribute, here's how to set up your local development environment:
102
+
103
+ **Prerequisites:**
104
+
105
+ - [Git](https://git-scm.com)
106
+ - [Node](https://nodejs.org)
107
+
108
+ **Cloning the Repository:**
109
+
110
+ To contribute, start by forking the Open Web Desktop client repository on GitHub.
111
+
112
+ Then, clone your fork using HTTPS or SSH:
113
+
114
+ ```bash
115
+ # Clone using HTTPS
116
+ git clone https://github.com/<your-username>/owd-client.git
117
+
118
+ # Clone using SSH
119
+ git clone git@github.com:<your-username>/owd-client.git
120
+ ```
121
+
122
+ Once you have cloned the repository, navigate to the project folder.
123
+ Install the dependencies, then start the development server:
124
+
125
+ ```bash
126
+ cd owd-client
127
+
128
+ npm install
129
+ npm run dev
130
+ ```
131
+
132
+ This will launch Open Web Desktop in development mode, allowing you to test your changes and see them reflected in real-time.
133
+ The dev server will be available at http://localhost:3000 by default.
134
+
135
+ ## Getting Involved
136
+
137
+ 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, add new features, and build a stronger community.
138
+
139
+ ### License
140
+
141
+ Open Web Desktop is licensed under the [GNU General Public License v3](LICENSE).
package/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './runtime/composables/useAppEntries'
2
+ export * from './runtime/composables/useApplicationManager'
3
+ export * from './runtime/composables/useApplicationState'
4
+ export * from './runtime/composables/useDesktopManager'
5
+ export * from './runtime/composables/useTerminalManager'
6
+ export * from './runtime/utils/utilsCommon'
7
+ export * from './runtime/utils/utilsDebug'
8
+ export * from './runtime/utils/utilsDesktop'
9
+ export * from './runtime/utils/utilsTerminal'
10
+ export * from './runtime/utils/utilsWindow'
@@ -0,0 +1,146 @@
1
+ import {defineNuxtModule, createResolver, addComponentsDir, addImportsDir, installModule} from '@nuxt/kit'
2
+ import pkg from '../package.json'
3
+ import path from "path";
4
+
5
+ export default defineNuxtModule({
6
+ meta: {
7
+ name: 'owd-core',
8
+ },
9
+ async setup(options, nuxt) {
10
+ const {resolve} = createResolver(import.meta.url);
11
+
12
+ // set core version to runtime variables
13
+
14
+ nuxt.options.runtimeConfig.public.coreVersion = pkg.version
15
+
16
+ // configure nuxt plugins
17
+
18
+ nuxt.options.primevue = nuxt.options.primevue || {};
19
+ nuxt.options.primevue.options = nuxt.options.primevue.options || {};
20
+ nuxt.options.primevue.options.theme = nuxt.options.primevue.options.theme || {};
21
+ nuxt.options.primevue.options.theme.options = {
22
+ cssLayer: false
23
+ };
24
+
25
+ {
26
+
27
+ // install tailwind
28
+
29
+ nuxt.options.modules.push('@nuxtjs/tailwindcss')
30
+ await installModule("@nuxtjs/tailwindcss", {
31
+ viewer: false,
32
+ //configPath: resolve(runtimeDir, "tailwind.config"),
33
+ })
34
+
35
+ }
36
+
37
+ {
38
+
39
+ // install primevue
40
+
41
+ nuxt.options.modules.push('@primevue/nuxt-module')
42
+ await installModule("@primevue/nuxt-module")
43
+
44
+ }
45
+
46
+ {
47
+
48
+ // install pinia
49
+
50
+ nuxt.options.modules.push('@pinia/nuxt')
51
+ await installModule("@pinia/nuxt")
52
+
53
+ }
54
+
55
+ {
56
+
57
+ // install @nuxt/fonts
58
+
59
+ nuxt.options.modules.push('@nuxt/fonts')
60
+ await installModule("@nuxt/fonts")
61
+
62
+ }
63
+
64
+ {
65
+
66
+ // install @nuxt/icon
67
+
68
+ nuxt.options.modules.push('@nuxt/icon')
69
+ await installModule("@nuxt/icon", {
70
+ clientBundle: {
71
+ scan: true,
72
+ sizeLimitKb: 256,
73
+ },
74
+ })
75
+
76
+ }
77
+
78
+ {
79
+
80
+ // install @vueuse/nuxt
81
+
82
+ nuxt.options.modules.push('@vueuse/nuxt')
83
+ await installModule("@vueuse/nuxt")
84
+
85
+ }
86
+
87
+ {
88
+
89
+ // install @nuxtjs/i18n
90
+
91
+ nuxt.options.modules.push('@nuxtjs/i18n')
92
+ await installModule("@nuxtjs/i18n")
93
+
94
+ }
95
+
96
+ {
97
+
98
+ // configure scss for vite
99
+
100
+ nuxt.hook('vite:extendConfig', (viteConfig) => {
101
+ viteConfig.css = viteConfig.css || {}
102
+ viteConfig.css.preprocessorOptions = viteConfig.css.preprocessorOptions || {}
103
+ viteConfig.css.preprocessorOptions.scss = {
104
+ api: 'modern-compiler',
105
+ }
106
+ })
107
+
108
+ }
109
+
110
+ {
111
+
112
+ // add css
113
+
114
+ nuxt.options.css.push('sanitize.css')
115
+
116
+ }
117
+
118
+ {
119
+
120
+ // add runtime components
121
+
122
+ addComponentsDir({
123
+ path: resolve("../runtime/components"),
124
+ prefix: "",
125
+ global: true,
126
+ })
127
+
128
+ }
129
+
130
+ {
131
+
132
+ nuxt.options.plugins.push(
133
+ resolve('../runtime/plugins/resize.client.ts'),
134
+ resolve('../runtime/plugins/slicksort.client.ts'),
135
+ resolve('../runtime/plugins/swiper.client.ts'),
136
+ )
137
+
138
+ addImportsDir(resolve('../runtime/composables'))
139
+ addImportsDir(resolve('../runtime/core'))
140
+ addImportsDir(resolve('../runtime/stores'))
141
+ addImportsDir(resolve('../runtime/utils'))
142
+
143
+ }
144
+
145
+ }
146
+ })
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@owdproject/core",
3
+ "version": "3.0.0-alpha.0",
4
+ "description": "Open Web Desktop core",
5
+ "keywords": [
6
+ "web",
7
+ "desktop",
8
+ "vue",
9
+ "web desktop"
10
+ ],
11
+ "homepage": "https://github.com/owdproject/client#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/owdproject/client/issues"
14
+ },
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/owdproject/client.git"
18
+ },
19
+ "license": "GPL-3.0-or-later",
20
+ "author": {
21
+ "name": "dxlliv",
22
+ "url": "https://github.com/dxlliv"
23
+ },
24
+ "dependencies": {
25
+ "@nuxt/fonts": "^0.11.0",
26
+ "@nuxt/icon": "^1.11.0",
27
+ "@nuxtjs/i18n": "^9.4.0",
28
+ "@nuxtjs/tailwindcss": "^6.13.2",
29
+ "@pinia/nuxt": "^0.10.1",
30
+ "@primeuix/themes": "^1.0.0",
31
+ "@primevue/forms": "^4.3.3",
32
+ "@primevue/nuxt-module": "^4.3.3",
33
+ "@vueuse/components": "^13.0.0",
34
+ "@vueuse/core": "^13.0.0",
35
+ "@vueuse/nuxt": "^13.0.0",
36
+ "memfs": "^4.17.0",
37
+ "mitt": "^3.0.1",
38
+ "nanoid": "^5.1.5",
39
+ "nuxt": "^3.16.1",
40
+ "pinia": "^3.0.1",
41
+ "sanitize.css": "^13.0.0",
42
+ "sass": "^1.86.0",
43
+ "vue-resizable": "^2.1.7"
44
+ }
45
+ }
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import {useApplicationManager} from "../../../composables/useApplicationManager"
3
+
4
+ defineProps<{
5
+ workspaceFilter?: string
6
+ }>()
7
+
8
+ const applicationManager = useApplicationManager()
9
+ </script>
10
+
11
+ <template>
12
+ <CoreApplicationWindowsRender
13
+ v-for="app of applicationManager.appsRunning"
14
+ :workspace-filter="workspaceFilter"
15
+ :windows="app.windowsOpened"
16
+ />
17
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ workspaceFilter?: string
4
+ windows: Map<string, IApplicationController['windows']>
5
+ }>()
6
+ </script>
7
+
8
+ <template>
9
+ <template
10
+ v-for="[windowId, window] in windows"
11
+ :key="windowId"
12
+ >
13
+ <component
14
+ v-if="!workspaceFilter || (workspaceFilter && window.state.workspace === workspaceFilter)"
15
+ :window="window"
16
+ :is="window.config.component"
17
+ />
18
+ </template>
19
+ </template>
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <div class="owd-background">
3
+ <slot />
4
+ </div>
5
+ </template>
6
+
7
+ <style scoped lang="scss">
8
+ .owd-background {
9
+ position: fixed;
10
+ top: 0;
11
+ left: 0;
12
+ right: 0;
13
+ bottom: 0;
14
+ background-color: var(--owd-background-color);
15
+ z-index: -1;
16
+ }
17
+ </style>
@@ -0,0 +1,77 @@
1
+ <script setup lang="ts">
2
+ import {onMounted, onUnmounted} from "vue"
3
+ import {computed, toRaw} from "@vue/reactivity"
4
+ import {useDesktopManager} from "../../../composables/useDesktopManager"
5
+ import {useApplicationManager} from "../../../composables/useApplicationManager"
6
+ import {useDesktopStore} from "../../../stores/storeDesktop"
7
+ import {useDesktopWorkspaceStore} from "../../../stores/storeDesktopWorkspace"
8
+
9
+ const props = withDefaults(defineProps<{
10
+ windows?: DesktopWindowsConfig
11
+ systemBar?: DesktopSystemBarConfig
12
+ dockBar?: DesktopDockBarConfig
13
+ }>(), {
14
+ windows: {
15
+ position: 'fixed',
16
+ },
17
+ systemBar: {},
18
+ dockBar: {},
19
+ })
20
+
21
+ const desktopManager = useDesktopManager()
22
+ const applicationManager = useApplicationManager()
23
+
24
+ // create firsts workspaces if not available
25
+ const desktopStore = useDesktopStore()
26
+ const desktopWorkspaceStore = useDesktopWorkspaceStore()
27
+
28
+ if (desktopStore.$persistedState) {
29
+ desktopStore.$persistedState.isReady().then(() => {
30
+ desktopWorkspaceStore.setupWorkspaces()
31
+ })
32
+ } else {
33
+ desktopWorkspaceStore.setupWorkspaces()
34
+ }
35
+
36
+ // override desktop configurations
37
+ desktopManager.overrideConfig({
38
+ windows: toRaw(props.windows),
39
+ systemBar: toRaw(props.systemBar),
40
+ dockBar: toRaw(props.dockBar),
41
+ })
42
+
43
+ // define apps and restore statuses
44
+ applicationManager.importApps()
45
+
46
+ // desktop resize
47
+ // todo move to composable
48
+
49
+ onMounted(() => window.addEventListener('resize', handleDesktopResize))
50
+ onUnmounted(() => window.removeEventListener('resize', handleDesktopResize))
51
+
52
+ function handleDesktopResize() {
53
+ //store.dispatch('core/window/windowsAdjustPosition')
54
+ }
55
+
56
+ const classes = computed(() => {
57
+ const list = ['owd-desktop']
58
+
59
+ list.push(`owd-desktop--${desktopManager.config.name}`)
60
+
61
+ return list
62
+ })
63
+ </script>
64
+
65
+ <template>
66
+ <div :class="classes">
67
+ <slot/>
68
+ </div>
69
+ </template>
70
+
71
+ <style scoped lang="scss">
72
+ .owd-desktop {
73
+ width: 100vw;
74
+ height: 100dvh;
75
+ user-select: none;
76
+ }
77
+ </style>
@@ -0,0 +1,67 @@
1
+ <template>
2
+ <li :class="['owd-explorer-file', { 'owd-explorer-file--inactive': props.inactive }]">
3
+ <a :href="props.url" :target="props.target" :title="props.title" @click="props.fn">
4
+ <img :src="props.icon" :alt="props.title" />
5
+ <div class="owd-explorer-file__name" v-html="props.name" />
6
+ </a>
7
+ </li>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ const props = defineProps<{
12
+ name: string
13
+ title: string
14
+ icon: string
15
+ url: string
16
+ target: string
17
+ inactive: boolean
18
+ }>()
19
+ </script>
20
+
21
+ <style scoped lang="scss">
22
+ li.file {
23
+ width: 100px;
24
+ margin: 0 5px 5px 0;
25
+ text-align: center;
26
+ float: left;
27
+ border-radius: 2px;
28
+ border: 1px solid rgba(0, 0, 0, 0);
29
+
30
+ @media(max-width: 480px) {
31
+ margin-right: 0;
32
+ }
33
+
34
+ @media(min-width: 480px) {
35
+ &:not(.inactive):hover {
36
+
37
+ }
38
+ }
39
+
40
+ &.inactive {
41
+ filter: grayscale(100%);
42
+ opacity: 0.2;
43
+ }
44
+
45
+ a {
46
+ display: block;
47
+ color: #CCC;
48
+ text-decoration: none;
49
+ transition: color 0.15s ease-in-out;
50
+ padding: 10px 0;
51
+
52
+ img {
53
+ vertical-align: middle;
54
+ height: 32px;
55
+ border-radius: 2px;
56
+ }
57
+
58
+ div.name {
59
+ font-size: 12px;
60
+ letter-spacing: -0.2px;
61
+ line-height: 10px;
62
+ margin-top: 10px;
63
+ cursor: pointer;
64
+ }
65
+ }
66
+ }
67
+ </style>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <CoreExplorerFile class="owd-explorer-folder">
3
+ <slot />
4
+ </CoreExplorerFile>
5
+ </template>
6
+
7
+ <style scoped lang="scss">
8
+ .owd-explorer-folder {
9
+
10
+ }
11
+ </style>
@@ -0,0 +1,53 @@
1
+ <script setup lang="ts">
2
+ import {ref, onMounted, onUnmounted} from 'vue'
3
+ import {computed} from "@vue/reactivity"
4
+ import {useI18n} from "vue-i18n"
5
+
6
+ const date: Ref<Date> = ref(new Date())
7
+ const {locale} = useI18n()
8
+
9
+ let minuteTimeout: any
10
+
11
+ onMounted(() => {
12
+ function scheduleNextMinute() {
13
+ const now = new Date()
14
+ const millisecondsToNextMinute = (60 - now.getSeconds()) * 1000 - now.getMilliseconds()
15
+ minuteTimeout = setTimeout(() => {
16
+ date.value = new Date()
17
+ scheduleNextMinute()
18
+ }, millisecondsToNextMinute)
19
+ }
20
+ scheduleNextMinute()
21
+ })
22
+
23
+ onUnmounted(() => {
24
+ clearTimeout(minuteTimeout)
25
+ })
26
+
27
+ const time = computed(() => {
28
+ if (!date.value) {
29
+ return ''
30
+ }
31
+
32
+ let hours = date.value.getHours()
33
+ let minutes: string = date.value.getMinutes().toString()
34
+ let period = 'AM'
35
+
36
+ if (locale.value !== 'it') {
37
+ if (hours >= 12) {
38
+ period = 'PM'
39
+ if (hours > 12) hours -= 12
40
+ } else if (hours === 0) {
41
+ hours = 12
42
+ }
43
+ }
44
+
45
+ if (minutes.length === 1) minutes = `0${minutes}`
46
+
47
+ return locale.value === 'it' ? `${hours}:${minutes}` : `${hours}:${minutes} ${period}`
48
+ })
49
+ </script>
50
+
51
+ <template>
52
+ <time class="owd-time" v-text="time" />
53
+ </template>