@owdproject/nuxt-theme-ui 0.0.0-stage → 4.0.0-alpha.3

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 (85) hide show
  1. package/dist/i18n/locales/en.d.ts +2 -0
  2. package/dist/i18n/locales/en.js +1 -0
  3. package/dist/module.d.mts +7 -0
  4. package/dist/module.json +9 -0
  5. package/dist/module.mjs +50 -0
  6. package/dist/runtime/apps/calculator/app.config.d.ts +34 -0
  7. package/dist/runtime/apps/calculator/app.config.js +35 -0
  8. package/dist/runtime/apps/calculator/components/Window/WindowCalculator.d.vue.ts +6 -0
  9. package/dist/runtime/apps/calculator/components/Window/WindowCalculator.vue +85 -0
  10. package/dist/runtime/apps/calculator/components/Window/WindowCalculator.vue.d.ts +6 -0
  11. package/dist/runtime/apps/calculator/plugin.d.ts +2 -0
  12. package/dist/runtime/apps/calculator/plugin.js +11 -0
  13. package/dist/runtime/apps/explorer/app.config.d.ts +36 -0
  14. package/dist/runtime/apps/explorer/app.config.js +39 -0
  15. package/dist/runtime/apps/explorer/components/Window/WindowExplorer.d.vue.ts +6 -0
  16. package/dist/runtime/apps/explorer/components/Window/WindowExplorer.vue +30 -0
  17. package/dist/runtime/apps/explorer/components/Window/WindowExplorer.vue.d.ts +6 -0
  18. package/dist/runtime/apps/explorer/plugin.d.ts +2 -0
  19. package/dist/runtime/apps/explorer/plugin.js +11 -0
  20. package/dist/runtime/apps/installBuiltInApps.d.ts +3 -0
  21. package/dist/runtime/apps/installBuiltInApps.js +28 -0
  22. package/dist/runtime/apps/notepad/app.config.d.ts +34 -0
  23. package/dist/runtime/apps/notepad/app.config.js +35 -0
  24. package/dist/runtime/apps/notepad/components/Window/WindowNotepad.d.vue.ts +6 -0
  25. package/dist/runtime/apps/notepad/components/Window/WindowNotepad.vue +43 -0
  26. package/dist/runtime/apps/notepad/components/Window/WindowNotepad.vue.d.ts +6 -0
  27. package/dist/runtime/apps/notepad/plugin.d.ts +2 -0
  28. package/dist/runtime/apps/notepad/plugin.js +11 -0
  29. package/dist/runtime/apps/registry.d.ts +8 -0
  30. package/dist/runtime/apps/registry.js +10 -0
  31. package/dist/runtime/components/Background/DesktopBackground.d.vue.ts +3 -0
  32. package/dist/runtime/components/Background/DesktopBackground.vue +3 -0
  33. package/dist/runtime/components/Background/DesktopBackground.vue.d.ts +3 -0
  34. package/dist/runtime/components/Desktop/DesktopContent.d.vue.ts +13 -0
  35. package/dist/runtime/components/Desktop/DesktopContent.vue +23 -0
  36. package/dist/runtime/components/Desktop/DesktopContent.vue.d.ts +13 -0
  37. package/dist/runtime/components/Desktop.client.d.vue.ts +23 -0
  38. package/dist/runtime/components/Desktop.client.vue +47 -0
  39. package/dist/runtime/components/Desktop.client.vue.d.ts +23 -0
  40. package/dist/runtime/components/NuxtLauncherOverlay.d.vue.ts +3 -0
  41. package/dist/runtime/components/NuxtLauncherOverlay.vue +69 -0
  42. package/dist/runtime/components/NuxtLauncherOverlay.vue.d.ts +3 -0
  43. package/dist/runtime/components/NuxtTopBar.d.vue.ts +3 -0
  44. package/dist/runtime/components/NuxtTopBar.vue +63 -0
  45. package/dist/runtime/components/NuxtTopBar.vue.d.ts +3 -0
  46. package/dist/runtime/components/Window/DesktopWindow.d.vue.ts +43 -0
  47. package/dist/runtime/components/Window/DesktopWindow.vue +40 -0
  48. package/dist/runtime/components/Window/DesktopWindow.vue.d.ts +43 -0
  49. package/dist/runtime/components/Window/DesktopWindowContent.d.vue.ts +13 -0
  50. package/dist/runtime/components/Window/DesktopWindowContent.vue +9 -0
  51. package/dist/runtime/components/Window/DesktopWindowContent.vue.d.ts +13 -0
  52. package/dist/runtime/components/Window/DesktopWindowIframe.d.vue.ts +29 -0
  53. package/dist/runtime/components/Window/DesktopWindowIframe.vue +13 -0
  54. package/dist/runtime/components/Window/DesktopWindowIframe.vue.d.ts +29 -0
  55. package/dist/runtime/components/Window/DesktopWindowNav.d.vue.ts +3 -0
  56. package/dist/runtime/components/Window/DesktopWindowNav.vue +105 -0
  57. package/dist/runtime/components/Window/DesktopWindowNav.vue.d.ts +3 -0
  58. package/dist/runtime/composables/useNuxtStartMenu.d.ts +9 -0
  59. package/dist/runtime/composables/useNuxtStartMenu.js +57 -0
  60. package/dist/types.d.mts +7 -0
  61. package/package.json +70 -4
  62. package/src/i18n/locales/en.ts +1 -0
  63. package/src/module.ts +69 -0
  64. package/src/runtime/apps/calculator/app.config.ts +35 -0
  65. package/src/runtime/apps/calculator/components/Window/WindowCalculator.vue +95 -0
  66. package/src/runtime/apps/calculator/plugin.ts +12 -0
  67. package/src/runtime/apps/explorer/app.config.ts +39 -0
  68. package/src/runtime/apps/explorer/components/Window/WindowExplorer.vue +34 -0
  69. package/src/runtime/apps/explorer/plugin.ts +12 -0
  70. package/src/runtime/apps/installBuiltInApps.ts +36 -0
  71. package/src/runtime/apps/notepad/app.config.ts +35 -0
  72. package/src/runtime/apps/notepad/components/Window/WindowNotepad.vue +46 -0
  73. package/src/runtime/apps/notepad/plugin.ts +12 -0
  74. package/src/runtime/apps/registry.ts +21 -0
  75. package/src/runtime/components/Background/DesktopBackground.vue +3 -0
  76. package/src/runtime/components/Desktop/DesktopContent.vue +37 -0
  77. package/src/runtime/components/Desktop.client.vue +55 -0
  78. package/src/runtime/components/NuxtLauncherOverlay.vue +71 -0
  79. package/src/runtime/components/NuxtTopBar.vue +68 -0
  80. package/src/runtime/components/Window/DesktopWindow.vue +44 -0
  81. package/src/runtime/components/Window/DesktopWindowContent.vue +17 -0
  82. package/src/runtime/components/Window/DesktopWindowIframe.vue +13 -0
  83. package/src/runtime/components/Window/DesktopWindowNav.vue +110 -0
  84. package/src/runtime/composables/useNuxtStartMenu.ts +72 -0
  85. package/README.md +0 -3
@@ -0,0 +1,55 @@
1
+ <script setup lang="ts">
2
+ import { ref, onMounted, onUnmounted } from "vue";
3
+ import { useDesktopWorkArea } from "@owdproject/nuxt/runtime/composables/useDesktopWorkArea";
4
+ import Background from "./Background/DesktopBackground.vue";
5
+ import DesktopContent from "./Desktop/DesktopContent.vue";
6
+ import NuxtTopBar from "./NuxtTopBar.vue";
7
+ import NuxtLauncherOverlay from "./NuxtLauncherOverlay.vue";
8
+
9
+ defineProps({
10
+ systemBar: { type: null, required: false },
11
+ });
12
+
13
+ const shellStageRef = ref(null);
14
+ useDesktopWorkArea(shellStageRef);
15
+
16
+ const BODY_SHELL_CLASS = "owd-has-nuxt-shell";
17
+
18
+ onMounted(() => {
19
+ document.body.classList.add(BODY_SHELL_CLASS);
20
+ });
21
+
22
+ onUnmounted(() => {
23
+ document.body.classList.remove(BODY_SHELL_CLASS);
24
+ });
25
+ </script>
26
+
27
+ <template>
28
+ <DesktopCore
29
+ v-bind="$props"
30
+ class="owd-desktop--nuxt flex flex-col h-screen overflow-hidden select-none bg-gray-50 dark:bg-gray-950"
31
+ >
32
+ <NuxtTopBar />
33
+
34
+ <div ref="shellStageRef" class="flex-1 min-h-0 relative flex flex-col">
35
+ <Background />
36
+
37
+ <DesktopContent>
38
+ <slot />
39
+ </DesktopContent>
40
+ <DesktopCoreApplicationRender />
41
+ </div>
42
+
43
+ <NuxtLauncherOverlay />
44
+
45
+ <!-- Supports programmatically opened Nuxt UI modals -->
46
+ <UModals />
47
+ </DesktopCore>
48
+ </template>
49
+
50
+ <style>
51
+ /* Custom style rules for desktop shell */
52
+ .owd-desktop--nuxt {
53
+ --owd-system-bar-height: 48px;
54
+ }
55
+ </style>
@@ -0,0 +1,71 @@
1
+ <script setup lang="ts">
2
+ import { useNuxtStartMenu } from '../composables/useNuxtStartMenu'
3
+ import { watch, ref } from 'vue'
4
+
5
+ const { open, searchQuery, filteredEntries, close, launchEntry } = useNuxtStartMenu()
6
+ const searchInput = ref<any>(null)
7
+
8
+ watch(open, (isOpen) => {
9
+ if (isOpen) {
10
+ setTimeout(() => {
11
+ searchInput.value?.$el?.querySelector('input')?.focus()
12
+ }, 100)
13
+ }
14
+ })
15
+ </script>
16
+
17
+ <template>
18
+ <div v-if="open" class="fixed inset-0 z-40 flex items-start justify-center pt-24" @click="close">
19
+ <!-- Overlay/Command Palette -->
20
+ <div
21
+ class="w-full max-w-xl mx-4 flex flex-col bg-white/75 dark:bg-gray-900/75 backdrop-blur-xl border border-gray-200 dark:border-gray-800 rounded-xl shadow-2xl overflow-hidden ring-1 ring-gray-200 dark:ring-gray-800"
22
+ @click.stop
23
+ >
24
+ <div class="p-4 border-b border-gray-200 dark:border-gray-800">
25
+ <UInput
26
+ ref="searchInput"
27
+ v-model="searchQuery"
28
+ icon="i-heroicons-magnifying-glass"
29
+ size="lg"
30
+ color="gray"
31
+ variant="none"
32
+ placeholder="Search apps..."
33
+ class="w-full text-lg"
34
+ :ui="{ wrapper: 'shadow-none', icon: { base: 'text-gray-400 dark:text-gray-500' } }"
35
+ />
36
+ </div>
37
+
38
+ <div class="flex-1 overflow-y-auto max-h-[50vh] p-2">
39
+ <div v-if="filteredEntries.length === 0" class="text-center py-12 text-gray-500 dark:text-gray-400 text-sm">
40
+ No apps found.
41
+ </div>
42
+
43
+ <div class="grid grid-cols-1 gap-1">
44
+ <button
45
+ v-for="entry in filteredEntries"
46
+ :key="entry.application.id"
47
+ class="flex items-center gap-3 p-3 rounded-lg hover:bg-gray-100/50 dark:hover:bg-gray-800/50 focus:bg-gray-100/50 dark:focus:bg-gray-800/50 transition-colors text-left outline-none"
48
+ @click="launchEntry(entry)"
49
+ >
50
+ <div class="flex-shrink-0 p-2 bg-gray-100 dark:bg-gray-800 rounded-md">
51
+ <UIcon
52
+ v-if="entry.icon"
53
+ :name="entry.icon"
54
+ class="w-5 h-5 text-gray-700 dark:text-gray-300"
55
+ />
56
+ <UIcon
57
+ v-else
58
+ name="i-heroicons-window"
59
+ class="w-5 h-5 text-gray-700 dark:text-gray-300"
60
+ />
61
+ </div>
62
+ <div class="flex flex-col min-w-0">
63
+ <span class="text-sm font-medium text-gray-900 dark:text-gray-100">{{ entry.title }}</span>
64
+ <span class="text-xs text-gray-500 dark:text-gray-400 truncate" v-if="entry.description">{{ entry.description }}</span>
65
+ </div>
66
+ </button>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </template>
@@ -0,0 +1,68 @@
1
+ <script setup lang="ts">
2
+ import { ref, onMounted, onUnmounted, computed } from 'vue'
3
+ import { useColorMode } from '#imports'
4
+ import { useNuxtStartMenu } from '../composables/useNuxtStartMenu'
5
+
6
+ const { toggle: toggleStart, open: startOpen } = useNuxtStartMenu()
7
+
8
+ const time = ref('')
9
+ const dateLabel = ref('')
10
+ let timer: any
11
+
12
+ onMounted(() => {
13
+ const update = () => {
14
+ const d = new Date()
15
+ time.value = d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })
16
+ dateLabel.value = d.toLocaleDateString([], { weekday: 'short', month: 'short', day: 'numeric' })
17
+ }
18
+ update()
19
+ timer = setInterval(update, 1000)
20
+ })
21
+
22
+ onUnmounted(() => {
23
+ clearInterval(timer)
24
+ })
25
+
26
+ const colorMode = useColorMode()
27
+ const isDark = computed({
28
+ get () {
29
+ return colorMode.value === 'dark'
30
+ },
31
+ set () {
32
+ colorMode.preference = colorMode.value === 'dark' ? 'light' : 'dark'
33
+ }
34
+ })
35
+ </script>
36
+
37
+ <template>
38
+ <header class="h-[60px] w-full flex items-center justify-between px-4 sm:px-6 lg:px-8 bg-white/75 dark:bg-gray-900/75 backdrop-blur border-b border-gray-200 dark:border-gray-800 flex-shrink-0 select-none z-50">
39
+ <!-- Left Section: Logo/Start Button -->
40
+ <div class="flex items-center gap-4">
41
+ <button
42
+ @click="toggleStart"
43
+ class="flex items-center gap-2 hover:opacity-80 transition-opacity"
44
+ aria-label="Toggle Start Menu"
45
+ >
46
+ <UIcon name="i-heroicons-cube-transparent" class="w-6 h-6 text-green-500" />
47
+ <span class="font-bold text-gray-900 dark:text-white text-lg tracking-tight hidden sm:block">Nuxt OS</span>
48
+ </button>
49
+ </div>
50
+
51
+ <!-- Center Section: Title/Clock -->
52
+ <div class="flex flex-col items-center justify-center">
53
+ <span class="text-sm font-medium text-gray-700 dark:text-gray-300">{{ time }}</span>
54
+ <span class="text-xs text-gray-500 dark:text-gray-400">{{ dateLabel }}</span>
55
+ </div>
56
+
57
+ <!-- Right Section: Quick controls -->
58
+ <div class="flex items-center gap-3">
59
+ <UButton
60
+ :icon="isDark ? 'i-heroicons-moon' : 'i-heroicons-sun'"
61
+ color="gray"
62
+ variant="ghost"
63
+ class="text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200"
64
+ @click="isDark = !isDark"
65
+ />
66
+ </div>
67
+ </header>
68
+ </template>
@@ -0,0 +1,44 @@
1
+ <script setup lang="ts">
2
+ import { useWindowDragHandlers } from "@owdproject/nuxt/runtime/composables/useWindowDragHandlers"
3
+ const props = defineProps({
4
+ config: { type: null, required: false },
5
+ window: { type: null, required: false },
6
+ content: { type: null, required: false }
7
+ })
8
+ const { onDragStart, onDragEnd } = useWindowDragHandlers(
9
+ () => props.window
10
+ )
11
+ </script>
12
+
13
+ <template>
14
+ <DesktopCoreWindow
15
+ v-bind="$props"
16
+ v-show="window?.state?.active !== false"
17
+ @drag:start="onDragStart"
18
+ @drag:end="onDragEnd"
19
+ >
20
+ <div class="flex flex-col h-full bg-white dark:bg-gray-950 border border-gray-200 dark:border-gray-800 rounded-lg shadow-xl overflow-hidden">
21
+ <DesktopWindowNav>
22
+ <template #prepend>
23
+ <slot name="nav-prepend" />
24
+ </template>
25
+ <template #append>
26
+ <slot name="nav-append" />
27
+ </template>
28
+ </DesktopWindowNav>
29
+ <div class="flex-1 min-h-0 relative">
30
+ <DesktopWindowContent>
31
+ <slot />
32
+ </DesktopWindowContent>
33
+ </div>
34
+ </div>
35
+ </DesktopCoreWindow>
36
+ </template>
37
+
38
+ <style scoped>
39
+ .owd-window {
40
+ box-sizing: border-box;
41
+ min-width: 160px;
42
+ min-height: 160px;
43
+ }
44
+ </style>
@@ -0,0 +1,17 @@
1
+ <template>
2
+ <DesktopCoreWindowContent>
3
+ <slot />
4
+ </DesktopCoreWindowContent>
5
+ </template>
6
+
7
+ <style scoped>
8
+ .owd-window__content--centered {
9
+ display: flex;
10
+ flex-direction: column;
11
+ justify-content: center;
12
+ align-items: center;
13
+ }
14
+ .owd-window__content--padded {
15
+ padding: 12px;
16
+ }
17
+ </style>
@@ -0,0 +1,13 @@
1
+ <script setup lang="ts">
2
+ defineProps({
3
+ config: { type: null, required: false },
4
+ window: { type: null, required: false },
5
+ src: { type: String, required: true }
6
+ });
7
+ </script>
8
+
9
+ <template>
10
+ <DesktopWindow v-bind="$props">
11
+ <iframe :src="src" class="w-full h-full border-0" />
12
+ </DesktopWindow>
13
+ </template>
@@ -0,0 +1,110 @@
1
+ <script setup lang="ts">
2
+ import { inject, computed } from "vue"
3
+ import { useToggleWindowMaximize } from "@owdproject/nuxt/runtime/composables/useToggleWindowMaximize"
4
+
5
+ const windowController = inject<any>("windowController")
6
+ const toggleWindowMaximize = useToggleWindowMaximize()
7
+
8
+ function onWindowMinimize() {
9
+ if (!windowController?.instanced) return
10
+ windowController.actions.minimize()
11
+ }
12
+
13
+ function onWindowMaximize() {
14
+ toggleWindowMaximize(windowController)
15
+ }
16
+
17
+ function onWindowNavDestroy() {
18
+ if (!windowController?.instanced) return
19
+ windowController.actions.destroy()
20
+ }
21
+
22
+ const dropdownItems = computed(() => [
23
+ [
24
+ {
25
+ label: 'Minimize',
26
+ icon: 'i-heroicons-minus',
27
+ click: onWindowMinimize
28
+ },
29
+ {
30
+ label: windowController?.state?.maximized ? 'Restore' : 'Maximize',
31
+ icon: 'i-heroicons-squares-2x2',
32
+ click: onWindowMaximize
33
+ }
34
+ ],
35
+ [
36
+ {
37
+ label: 'Close',
38
+ icon: 'i-heroicons-x-mark',
39
+ click: onWindowNavDestroy
40
+ }
41
+ ]
42
+ ])
43
+ </script>
44
+
45
+ <template>
46
+ <DesktopCoreWindowNav
47
+ class="flex items-center justify-between px-3 py-1.5 bg-gray-50 dark:bg-gray-900 border-b border-gray-200 dark:border-gray-800 select-none cursor-default"
48
+ @dblclick="onWindowMaximize"
49
+ >
50
+ <div class="flex items-center space-x-2 min-w-0">
51
+ <UDropdown :items="dropdownItems" :popper="{ placement: 'bottom-start' }">
52
+ <UButton
53
+ v-if="windowController?.icon"
54
+ :icon="windowController.icon"
55
+ color="gray"
56
+ variant="ghost"
57
+ size="2xs"
58
+ class="h-5 w-5 p-0 flex items-center justify-center rounded"
59
+ />
60
+ <UButton
61
+ v-else
62
+ icon="i-heroicons-cog-6-tooth"
63
+ color="gray"
64
+ variant="ghost"
65
+ size="2xs"
66
+ class="h-5 w-5 p-0 flex items-center justify-center rounded"
67
+ />
68
+ </UDropdown>
69
+
70
+ <div
71
+ v-if="windowController?.title"
72
+ class="text-xs font-semibold text-gray-700 dark:text-gray-300 truncate"
73
+ v-text="windowController?.title"
74
+ />
75
+ </div>
76
+
77
+ <div class="flex items-center space-x-1 flex-shrink-0">
78
+ <UButton
79
+ v-if="!windowController?.instanced || windowController?.isMinimizable"
80
+ icon="i-heroicons-minus"
81
+ size="2xs"
82
+ color="gray"
83
+ variant="ghost"
84
+ class="h-5 w-5 p-0 flex items-center justify-center rounded"
85
+ @mousedown.stop
86
+ @click.stop="onWindowMinimize"
87
+ />
88
+ <UButton
89
+ v-if="windowController?.isMaximizable"
90
+ icon="i-heroicons-squares-2x2"
91
+ size="2xs"
92
+ color="gray"
93
+ variant="ghost"
94
+ class="h-5 w-5 p-0 flex items-center justify-center rounded"
95
+ @mousedown.stop
96
+ @click.stop="onWindowMaximize"
97
+ />
98
+ <UButton
99
+ v-if="!windowController?.instanced || windowController?.isDestroyable"
100
+ icon="i-heroicons-x-mark"
101
+ size="2xs"
102
+ color="red"
103
+ variant="ghost"
104
+ class="h-5 w-5 p-0 flex items-center justify-center rounded hover:bg-red-500 hover:text-white"
105
+ @mousedown.stop
106
+ @click.stop="onWindowNavDestroy"
107
+ />
108
+ </div>
109
+ </DesktopCoreWindowNav>
110
+ </template>
@@ -0,0 +1,72 @@
1
+ import { ref, computed } from 'vue'
2
+ import { useScrollLock } from '@vueuse/core'
3
+ import { useApplicationManager } from '@owdproject/nuxt/runtime/composables/useApplicationManager'
4
+ import { useApplicationEntries } from '@owdproject/nuxt/runtime/composables/useApplicationEntries'
5
+
6
+ const open = ref(false)
7
+ const searchQuery = ref('')
8
+
9
+ function isValidEntry(
10
+ entry: any
11
+ ): entry is any {
12
+ return Boolean(entry?.application?.id && entry.command)
13
+ }
14
+
15
+ export function useNuxtStartMenu() {
16
+ const applicationManager = useApplicationManager()
17
+ const applicationEntries = useApplicationEntries()
18
+
19
+ const bodyScrollLock = useScrollLock(
20
+ typeof document !== 'undefined' ? document.body : null,
21
+ )
22
+
23
+ const allEntries = computed(() => {
24
+ return (applicationEntries as any)
25
+ .sortedAppEntries('title', 'primary')
26
+ .value.filter(isValidEntry)
27
+ })
28
+
29
+ const filteredEntries = computed(() => {
30
+ const q = searchQuery.value.trim().toLowerCase()
31
+ const entries = allEntries.value
32
+ if (!q) return entries
33
+ return entries.filter((entry: any) =>
34
+ (entry.title ?? '').toLowerCase().includes(q),
35
+ )
36
+ })
37
+
38
+ function syncScrollLock() {
39
+ bodyScrollLock.value = open.value
40
+ }
41
+
42
+ function toggle() {
43
+ open.value = !open.value
44
+ searchQuery.value = ''
45
+ syncScrollLock()
46
+ }
47
+
48
+ function close() {
49
+ open.value = false
50
+ searchQuery.value = ''
51
+ bodyScrollLock.value = false
52
+ }
53
+
54
+ async function launchEntry(entry: any) {
55
+ if (!isValidEntry(entry)) return
56
+ await applicationManager.execAppCommand(
57
+ entry.application.id,
58
+ entry.command,
59
+ )
60
+ close()
61
+ }
62
+
63
+ return {
64
+ open,
65
+ searchQuery,
66
+ allEntries,
67
+ filteredEntries,
68
+ toggle,
69
+ close,
70
+ launchEntry,
71
+ }
72
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.