Skip to content

Commit ddc6bca

Browse files
committed
WIP... regression
1 parent c1442bc commit ddc6bca

File tree

10 files changed

+573
-548
lines changed

10 files changed

+573
-548
lines changed

webclient_fresh/src/components/layout/LayoutGrid.component.svelte

Lines changed: 195 additions & 388 deletions
Large diffs are not rendered by default.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<script lang="ts">
2+
import type { Snippet } from 'svelte'
3+
import type { PaneStateInterface } from '@/store/layout/models'
4+
5+
let {
6+
pane,
7+
children,
8+
onclose
9+
}: {
10+
pane: PaneStateInterface
11+
children?: Snippet
12+
onclose?: () => void
13+
} = $props()
14+
15+
function handleClose() {
16+
onclose?.()
17+
}
18+
</script>
19+
20+
<div class="pane border border-base-300 overflow-hidden flex flex-col">
21+
{#if children}
22+
{@render children()}
23+
{:else}
24+
<div class="p-4 text-center text-base-content/50">
25+
No content for {pane.title}
26+
</div>
27+
{/if}
28+
</div>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<script lang="ts">
2+
import type { Snippet } from 'svelte'
3+
import type { PaneTabStateInterface } from '@/store/layout/models'
4+
5+
let {
6+
tab,
7+
onclick,
8+
onclose
9+
}: {
10+
tab: PaneTabStateInterface
11+
onclick?: () => void
12+
onclose?: () => void
13+
} = $props()
14+
15+
function handleClick() {
16+
onclick?.()
17+
}
18+
19+
function handleClose(e: MouseEvent) {
20+
e.stopPropagation()
21+
onclose?.()
22+
}
23+
</script>
24+
25+
<span
26+
role="button"
27+
tabindex="0"
28+
class="btn btn-primary btn-sm"
29+
class:btn-primary={tab.isActive}
30+
onclick={handleClick}
31+
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { handleClick() } }}
32+
>
33+
{tab.title}
34+
{#if tab.isCloseable}
35+
<span
36+
role="button"
37+
tabindex="0"
38+
class="ml-2 w-4 h-4 rounded-full hover:bg-base-300 flex items-center justify-center text-xs"
39+
onclick={handleClose}
40+
onkeydown={(e) => { if (e.key === 'Enter' || e.key === ' ') { handleClose(e) } }}
41+
>×</span>
42+
{/if}
43+
</span>
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
# Layout Store Implementation
2+
3+
import { writable, derived, type Writable, type Readable } from 'svelte/store'
4+
import type {
5+
LayoutStateInterface,
6+
PaneStateInterface,
7+
LayoutStoreInterface,
8+
LayoutStoreActionsInterface,
9+
LayoutStoreGettersInterface
10+
} from './models'
11+
12+
// Private writable store
13+
const writableLayoutStore = writable<LayoutStateInterface>({
14+
panes: {
15+
'left-top': {
16+
id: 'left-top',
17+
position: 'left-top',
18+
title: 'Left Top',
19+
isVisible: false,
20+
isResizable: true,
21+
dimensions: { width: 300, minWidth: 200, height: 300, minHeight: 200 },
22+
tabs: [{
23+
id: 'left-top-tab-1',
24+
paneId: 'left-top',
25+
title: 'Notes',
26+
componentType: 'TextArea',
27+
isActive: true,
28+
isCloseable: true
29+
}],
30+
activeTabId: 'left-top-tab-1'
31+
},
32+
'left-bottom': {
33+
id: 'left-bottom',
34+
position: 'left-bottom',
35+
title: 'Left Bottom',
36+
isVisible: false,
37+
isResizable: true,
38+
dimensions: { width: 300, minWidth: 200, height: 200, minHeight: 150 },
39+
tabs: [{
40+
id: 'left-bottom-tab-1',
41+
paneId: 'left-bottom',
42+
title: 'Scratch',
43+
componentType: 'TextArea',
44+
isActive: true,
45+
isCloseable: true
46+
}],
47+
activeTabId: 'left-bottom-tab-1'
48+
},
49+
'right-top': {
50+
id: 'right-top',
51+
position: 'right-top',
52+
title: 'Right Top',
53+
isVisible: false,
54+
isResizable: true,
55+
dimensions: { width: 300, minWidth: 200, height: 300, minHeight: 200 },
56+
tabs: [{
57+
id: 'right-top-tab-1',
58+
paneId: 'right-top',
59+
title: 'Workspace',
60+
componentType: 'TextArea',
61+
isActive: true,
62+
isCloseable: true
63+
}],
64+
activeTabId: 'right-top-tab-1'
65+
},
66+
'right-bottom': {
67+
id: 'right-bottom',
68+
position: 'right-bottom',
69+
title: 'Right Bottom',
70+
isVisible: false,
71+
isResizable: true,
72+
dimensions: { width: 300, minWidth: 200, height: 200, minHeight: 150 },
73+
tabs: [{
74+
id: 'right-bottom-tab-1',
75+
paneId: 'right-bottom',
76+
title: 'Debug',
77+
componentType: 'TextArea',
78+
isActive: true,
79+
isCloseable: true
80+
}],
81+
activeTabId: 'right-bottom-tab-1'
82+
},
83+
'bottom-left': {
84+
id: 'bottom-left',
85+
position: 'bottom-left',
86+
title: 'Bottom Left',
87+
isVisible: false,
88+
isResizable: true,
89+
dimensions: { width: 400, minWidth: 300, height: 200, minHeight: 150 },
90+
tabs: [{
91+
id: 'bottom-left-tab-1',
92+
paneId: 'bottom-left',
93+
title: 'Output',
94+
componentType: 'TextArea',
95+
isActive: true,
96+
isCloseable: true
97+
}],
98+
activeTabId: 'bottom-left-tab-1'
99+
},
100+
'bottom-right': {
101+
id: 'bottom-right',
102+
position: 'bottom-right',
103+
title: 'Bottom Right',
104+
isVisible: false,
105+
isResizable: true,
106+
dimensions: { width: 400, minWidth: 300, height: 200, minHeight: 150 },
107+
tabs: [{
108+
id: 'bottom-right-tab-1',
109+
paneId: 'bottom-right',
110+
title: 'Console',
111+
componentType: 'TextArea',
112+
isActive: true,
113+
isCloseable: true
114+
}],
115+
activeTabId: 'bottom-right-tab-1'
116+
},
117+
'center': {
118+
id: 'center',
119+
position: 'center',
120+
title: 'Code Editor',
121+
isVisible: true,
122+
isResizable: true,
123+
dimensions: { width: 400, minWidth: 300, height: 400, minHeight: 300 },
124+
tabs: [],
125+
activeTabId: null
126+
}
127+
},
128+
isResizing: false,
129+
globalSettings: {
130+
theme: 'dark',
131+
showPaneTitles: true,
132+
enableAnimations: true
133+
}
134+
})
135+
136+
// Public hook
137+
export function useLayoutStore(): LayoutStoreInterface {
138+
// Actions: modify state
139+
const actions: LayoutStoreActionsInterface = {
140+
togglePaneVisibility: (position: string) => {
141+
const positions = {
142+
left: ['left-top', 'left-bottom'],
143+
right: ['right-top', 'right-bottom'],
144+
bottom: ['bottom-left', 'bottom-right']
145+
}
146+
147+
const positionsToToggle = positions[position as keyof typeof positions] || [position]
148+
const anyVisible = positionsToToggle.some(pos =>
149+
writableLayoutStore.get().panes[pos]?.isVisible
150+
)
151+
152+
writableLayoutStore.update(state => {
153+
const newPanes = { ...state.panes }
154+
positionsToToggle.forEach(pos => {
155+
if (newPanes[pos]) {
156+
newPanes[pos] = { ...newPanes[pos], isVisible: !anyVisible }
157+
}
158+
})
159+
return { ...state, panes: newPanes }
160+
})
161+
},
162+
163+
setPaneVisibility: (position: string, visible: boolean) => {
164+
writableLayoutStore.update(state => ({
165+
...state,
166+
panes: {
167+
...state.panes,
168+
[position]: {
169+
...state.panes[position],
170+
isVisible: visible
171+
}
172+
}
173+
}))
174+
},
175+
176+
updatePaneDimensions: (position: string, dimensions: Partial<LayoutDimensionsInterface>) => {
177+
writableLayoutStore.update(state => ({
178+
...state,
179+
panes: {
180+
...state.panes,
181+
[position]: {
182+
...state.panes[position],
183+
dimensions: {
184+
...state.panes[position].dimensions,
185+
...dimensions
186+
}
187+
}
188+
}
189+
}))
190+
},
191+
192+
resetLayout: () => {
193+
// Reset to default state
194+
const defaultState = writableLayoutStore.get()
195+
writableLayoutStore.update(state => ({
196+
...state,
197+
panes: Object.fromEntries(
198+
Object.entries(state.panes).map(([key, pane]) => [
199+
key,
200+
{ ...pane, isVisible: key === 'center' }
201+
])
202+
)
203+
}))
204+
}
205+
}
206+
207+
// Getters: read-only derived stores
208+
const panes = derived(writableLayoutStore, $state => $state.panes)
209+
const visiblePanes = derived(writableLayoutStore, $state =>
210+
Object.fromEntries(
211+
Object.entries($state.panes).filter(([_, pane]) => pane.isVisible)
212+
)
213+
)
214+
const isResizing = derived(writableLayoutStore, $state => $state.isResizing)
215+
const globalSettings = derived(writableLayoutStore, $state => $state.globalSettings)
216+
217+
const getters: LayoutStoreGettersInterface = {
218+
panes,
219+
visiblePanes,
220+
isResizing,
221+
globalSettings
222+
}
223+
224+
return { actions, getters }
225+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { useLayoutStore } from './Layout.store'
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Layout State Interface
2+
3+
import type { LayoutDimensionsInterface, PanePosition } from '@/models/layout'
4+
5+
export interface PaneStateInterface {
6+
id: string
7+
position: PanePosition
8+
title: string
9+
isVisible: boolean
10+
isResizable: boolean
11+
dimensions: LayoutDimensionsInterface
12+
tabs: PaneTabStateInterface[]
13+
activeTabId: string | null
14+
}
15+
16+
export interface PaneTabStateInterface {
17+
id: string
18+
paneId: string
19+
title: string
20+
componentType: string
21+
componentProps?: Record<string, any>
22+
isActive: boolean
23+
isCloseable: boolean
24+
}
25+
26+
export interface LayoutStateInterface {
27+
panes: Record<string, PaneStateInterface>
28+
isResizing: boolean
29+
globalSettings: {
30+
theme: string
31+
showPaneTitles: boolean
32+
enableAnimations: boolean
33+
}
34+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Layout Store Interfaces
2+
3+
import type { Writable, Readable } from 'svelte/store'
4+
import type { LayoutStateInterface, LayoutDimensionsInterface } from '@/models/layout'
5+
6+
export interface LayoutStoreActionsInterface {
7+
togglePaneVisibility: (position: string) => void
8+
setPaneVisibility: (position: string, visible: boolean) => void
9+
updatePaneDimensions: (position: string, dimensions: Partial<LayoutDimensionsInterface>) => void
10+
resetLayout: () => void
11+
}
12+
13+
export interface LayoutStoreGettersInterface {
14+
panes: Readable<LayoutStateInterface['panes']>
15+
visiblePanes: Readable<LayoutStateInterface['panes']>
16+
isResizing: Readable<LayoutStateInterface['isResizing']>
17+
globalSettings: Readable<LayoutStateInterface['globalSettings']>
18+
}
19+
20+
export interface LayoutStoreInterface {
21+
actions: LayoutStoreActionsInterface
22+
getters: LayoutStoreGettersInterface
23+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './LayoutState.interface'
2+
export * from './LayoutStore.interface'
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,18 @@
1+
import { writable } from 'svelte/store'
2+
import { useEditorStore } from '../editor/Editor.store'
3+
import { useLayoutStore } from '../layout/Layout.store'
4+
5+
export function useAppStore() {
6+
const editorStore = useEditorStore()
7+
const layoutStore = useLayoutStore()
8+
9+
return {
10+
editorStore,
11+
layoutStore
12+
}
13+
}
14+
15+
export const currentPage = writable<'editor' | 'settings'>('editor')
16+
117
export * from './Root.store'
218
export * from './models'

0 commit comments

Comments
 (0)