@smartnet360/svelte-components 0.0.1-beta.2
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.
- package/dist/Desktop/Desktop.svelte +423 -0
- package/dist/Desktop/Desktop.svelte.d.ts +26 -0
- package/dist/Desktop/Grid/Half.svelte +50 -0
- package/dist/Desktop/Grid/Half.svelte.d.ts +29 -0
- package/dist/Desktop/Grid/Quarter.svelte +103 -0
- package/dist/Desktop/Grid/Quarter.svelte.d.ts +27 -0
- package/dist/Desktop/Grid/README.md +331 -0
- package/dist/Desktop/Grid/ResizeHandle.svelte +118 -0
- package/dist/Desktop/Grid/ResizeHandle.svelte.d.ts +23 -0
- package/dist/Desktop/Grid/index.d.ts +4 -0
- package/dist/Desktop/Grid/index.js +4 -0
- package/dist/Desktop/Grid/resizeStore.d.ts +16 -0
- package/dist/Desktop/Grid/resizeStore.js +39 -0
- package/dist/Desktop/GridRenderer.svelte +328 -0
- package/dist/Desktop/GridRenderer.svelte.d.ts +25 -0
- package/dist/Desktop/GridSelector/ComponentPalette.svelte +243 -0
- package/dist/Desktop/GridSelector/ComponentPalette.svelte.d.ts +27 -0
- package/dist/Desktop/GridSelector/ConfigurationPanel.svelte +242 -0
- package/dist/Desktop/GridSelector/ConfigurationPanel.svelte.d.ts +28 -0
- package/dist/Desktop/GridSelector/GridSelector.svelte +232 -0
- package/dist/Desktop/GridSelector/GridSelector.svelte.d.ts +43 -0
- package/dist/Desktop/GridSelector/LayoutPicker.svelte +241 -0
- package/dist/Desktop/GridSelector/LayoutPicker.svelte.d.ts +28 -0
- package/dist/Desktop/GridSelector/LayoutPreview.svelte +309 -0
- package/dist/Desktop/GridSelector/LayoutPreview.svelte.d.ts +32 -0
- package/dist/Desktop/GridSelector/index.d.ts +4 -0
- package/dist/Desktop/GridSelector/index.js +4 -0
- package/dist/Desktop/GridViewer.svelte +125 -0
- package/dist/Desktop/GridViewer.svelte.d.ts +21 -0
- package/dist/Desktop/README.md +279 -0
- package/dist/Desktop/gridLayouts.d.ts +76 -0
- package/dist/Desktop/gridLayouts.js +351 -0
- package/dist/Desktop/index.d.ts +7 -0
- package/dist/Desktop/index.js +7 -0
- package/dist/Desktop/launchHelpers.d.ts +25 -0
- package/dist/Desktop/launchHelpers.js +77 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +65 -0
@@ -0,0 +1,241 @@
|
|
1
|
+
|
2
|
+
<script lang="ts">
|
3
|
+
/**
|
4
|
+
* Layout Picker Component
|
5
|
+
*
|
6
|
+
* Displays available grid layouts organized by category with visual previews.
|
7
|
+
* Users can click to select a layout type.
|
8
|
+
*/
|
9
|
+
|
10
|
+
import { createEventDispatcher } from 'svelte';
|
11
|
+
import type { GridLayoutDefinition } from '../gridLayouts.js';
|
12
|
+
|
13
|
+
export let basicLayouts: GridLayoutDefinition[] = [];
|
14
|
+
export let asymmetricLayouts: GridLayoutDefinition[] = [];
|
15
|
+
export let symmetricLayouts: GridLayoutDefinition[] = [];
|
16
|
+
export let selectedLayoutId: string = '';
|
17
|
+
|
18
|
+
const dispatch = createEventDispatcher<{
|
19
|
+
layoutSelected: { layoutId: string };
|
20
|
+
}>();
|
21
|
+
|
22
|
+
function selectLayout(layoutId: string) {
|
23
|
+
dispatch('layoutSelected', { layoutId });
|
24
|
+
}
|
25
|
+
</script>
|
26
|
+
|
27
|
+
<div class="layout-picker p-3">
|
28
|
+
<div class="picker-header mb-3">
|
29
|
+
<h6 class="mb-1">
|
30
|
+
<span class="step-number badge bg-primary me-2">1</span>
|
31
|
+
Choose Layout
|
32
|
+
</h6>
|
33
|
+
</div>
|
34
|
+
|
35
|
+
<!-- Basic Layouts -->
|
36
|
+
{#if basicLayouts.length > 0}
|
37
|
+
<div class="layout-category mb-4">
|
38
|
+
<div class="category-header mb-2">
|
39
|
+
<span class="badge bg-primary">Basic</span>
|
40
|
+
<small class="text-muted ms-2">Simple half layouts (1x1)</small>
|
41
|
+
</div>
|
42
|
+
|
43
|
+
<div class="layout-grid">
|
44
|
+
{#each basicLayouts as layout}
|
45
|
+
<button
|
46
|
+
class="layout-option btn"
|
47
|
+
class:selected={selectedLayoutId === layout.id}
|
48
|
+
on:click={() => selectLayout(layout.id)}
|
49
|
+
title={layout.description}
|
50
|
+
>
|
51
|
+
<div class="layout-preview">
|
52
|
+
{@html layout.previewSvg}
|
53
|
+
</div>
|
54
|
+
<div class="layout-info">
|
55
|
+
<div class="layout-name">{layout.name}</div>
|
56
|
+
<div class="layout-icon">{layout.icon}</div>
|
57
|
+
</div>
|
58
|
+
</button>
|
59
|
+
{/each}
|
60
|
+
</div>
|
61
|
+
</div>
|
62
|
+
{/if}
|
63
|
+
|
64
|
+
<!-- Asymmetric Layouts -->
|
65
|
+
{#if asymmetricLayouts.length > 0}
|
66
|
+
<div class="layout-category mb-4">
|
67
|
+
<div class="category-header mb-2">
|
68
|
+
<span class="badge bg-primary">Asymmetric</span>
|
69
|
+
<small class="text-muted ms-2">Mixed half + quarters (1x2, 2x1)</small>
|
70
|
+
</div>
|
71
|
+
|
72
|
+
<div class="layout-grid">
|
73
|
+
{#each asymmetricLayouts as layout}
|
74
|
+
<button
|
75
|
+
class="layout-option btn"
|
76
|
+
class:selected={selectedLayoutId === layout.id}
|
77
|
+
on:click={() => selectLayout(layout.id)}
|
78
|
+
title={layout.description}
|
79
|
+
>
|
80
|
+
<div class="layout-preview">
|
81
|
+
{@html layout.previewSvg}
|
82
|
+
</div>
|
83
|
+
<div class="layout-info">
|
84
|
+
<div class="layout-name">{layout.name}</div>
|
85
|
+
<div class="layout-icon">{layout.icon}</div>
|
86
|
+
</div>
|
87
|
+
</button>
|
88
|
+
{/each}
|
89
|
+
</div>
|
90
|
+
</div>
|
91
|
+
{/if}
|
92
|
+
|
93
|
+
<!-- Symmetric Layouts -->
|
94
|
+
{#if symmetricLayouts.length > 0}
|
95
|
+
<div class="layout-category mb-4">
|
96
|
+
<div class="category-header mb-2">
|
97
|
+
<span class="badge bg-primary">Symmetric</span>
|
98
|
+
<small class="text-muted ms-2">Equal quarters (2x2)</small>
|
99
|
+
</div>
|
100
|
+
|
101
|
+
<div class="layout-grid">
|
102
|
+
{#each symmetricLayouts as layout}
|
103
|
+
<button
|
104
|
+
class="layout-option btn"
|
105
|
+
class:selected={selectedLayoutId === layout.id}
|
106
|
+
on:click={() => selectLayout(layout.id)}
|
107
|
+
title={layout.description}
|
108
|
+
>
|
109
|
+
<div class="layout-preview">
|
110
|
+
{@html layout.previewSvg}
|
111
|
+
</div>
|
112
|
+
<div class="layout-info">
|
113
|
+
<div class="layout-name">{layout.name}</div>
|
114
|
+
<div class="layout-icon">{layout.icon}</div>
|
115
|
+
</div>
|
116
|
+
</button>
|
117
|
+
{/each}
|
118
|
+
</div>
|
119
|
+
</div>
|
120
|
+
{/if}
|
121
|
+
</div>
|
122
|
+
|
123
|
+
<style>
|
124
|
+
.layout-picker {
|
125
|
+
border-bottom: 1px solid #dee2e6;
|
126
|
+
}
|
127
|
+
|
128
|
+
.category-header {
|
129
|
+
display: flex;
|
130
|
+
align-items: center;
|
131
|
+
}
|
132
|
+
|
133
|
+
.layout-grid {
|
134
|
+
display: grid;
|
135
|
+
grid-template-columns: 1fr 1fr;
|
136
|
+
gap: 8px;
|
137
|
+
}
|
138
|
+
|
139
|
+
.layout-option {
|
140
|
+
border: 2px solid #dee2e6;
|
141
|
+
border-radius: 8px;
|
142
|
+
padding: 8px;
|
143
|
+
background: #fff;
|
144
|
+
transition: all 0.2s ease;
|
145
|
+
cursor: pointer;
|
146
|
+
text-align: center;
|
147
|
+
min-height: 80px;
|
148
|
+
display: flex;
|
149
|
+
flex-direction: column;
|
150
|
+
justify-content: space-between;
|
151
|
+
}
|
152
|
+
|
153
|
+
.layout-option:hover {
|
154
|
+
border-color: #007bff;
|
155
|
+
transform: translateY(-1px);
|
156
|
+
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.15);
|
157
|
+
}
|
158
|
+
|
159
|
+
.layout-option.selected {
|
160
|
+
border-color: #007bff;
|
161
|
+
background: #e7f3ff;
|
162
|
+
box-shadow: 0 0 0 3px rgba(0, 123, 255, 0.1);
|
163
|
+
}
|
164
|
+
|
165
|
+
.layout-preview {
|
166
|
+
flex: 1;
|
167
|
+
display: flex;
|
168
|
+
align-items: center;
|
169
|
+
justify-content: center;
|
170
|
+
margin-bottom: 4px;
|
171
|
+
}
|
172
|
+
|
173
|
+
.layout-preview :global(svg) {
|
174
|
+
width: 100%;
|
175
|
+
max-width: 60px;
|
176
|
+
height: auto;
|
177
|
+
}
|
178
|
+
|
179
|
+
.layout-info {
|
180
|
+
flex-shrink: 0;
|
181
|
+
}
|
182
|
+
|
183
|
+
.layout-name {
|
184
|
+
font-size: 10px;
|
185
|
+
font-weight: 500;
|
186
|
+
color: #333;
|
187
|
+
line-height: 1.2;
|
188
|
+
margin-bottom: 2px;
|
189
|
+
}
|
190
|
+
|
191
|
+
.layout-icon {
|
192
|
+
font-size: 12px;
|
193
|
+
opacity: 0.7;
|
194
|
+
}
|
195
|
+
|
196
|
+
.layout-option.selected .layout-name {
|
197
|
+
color: #007bff;
|
198
|
+
font-weight: 600;
|
199
|
+
}
|
200
|
+
|
201
|
+
/* Dark theme support */
|
202
|
+
:global(.theme-dark) .layout-option {
|
203
|
+
background: #3d3d3d;
|
204
|
+
border-color: #555;
|
205
|
+
color: #fff;
|
206
|
+
}
|
207
|
+
|
208
|
+
:global(.theme-dark) .layout-option:hover {
|
209
|
+
border-color: #4dabf7;
|
210
|
+
}
|
211
|
+
|
212
|
+
:global(.theme-dark) .layout-option.selected {
|
213
|
+
border-color: #4dabf7;
|
214
|
+
background: #1a2a3a;
|
215
|
+
}
|
216
|
+
|
217
|
+
:global(.theme-dark) .layout-name {
|
218
|
+
color: #fff;
|
219
|
+
}
|
220
|
+
|
221
|
+
:global(.theme-dark) .layout-option.selected .layout-name {
|
222
|
+
color: #4dabf7;
|
223
|
+
}
|
224
|
+
|
225
|
+
/* Responsive adjustments */
|
226
|
+
@media (max-width: 768px) {
|
227
|
+
.layout-grid {
|
228
|
+
grid-template-columns: 1fr;
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
.step-number {
|
233
|
+
font-size: 12px;
|
234
|
+
width: 20px;
|
235
|
+
height: 20px;
|
236
|
+
display: inline-flex;
|
237
|
+
align-items: center;
|
238
|
+
justify-content: center;
|
239
|
+
border-radius: 50%;
|
240
|
+
}
|
241
|
+
</style>
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import type { GridLayoutDefinition } from '../gridLayouts.js';
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
4
|
+
$$bindings?: Bindings;
|
5
|
+
} & Exports;
|
6
|
+
(internal: unknown, props: Props & {
|
7
|
+
$$events?: Events;
|
8
|
+
$$slots?: Slots;
|
9
|
+
}): Exports & {
|
10
|
+
$set?: any;
|
11
|
+
$on?: any;
|
12
|
+
};
|
13
|
+
z_$$bindings?: Bindings;
|
14
|
+
}
|
15
|
+
declare const LayoutPicker: $$__sveltets_2_IsomorphicComponent<{
|
16
|
+
basicLayouts?: GridLayoutDefinition[];
|
17
|
+
asymmetricLayouts?: GridLayoutDefinition[];
|
18
|
+
symmetricLayouts?: GridLayoutDefinition[];
|
19
|
+
selectedLayoutId?: string;
|
20
|
+
}, {
|
21
|
+
layoutSelected: CustomEvent<{
|
22
|
+
layoutId: string;
|
23
|
+
}>;
|
24
|
+
} & {
|
25
|
+
[evt: string]: CustomEvent<any>;
|
26
|
+
}, {}, {}, string>;
|
27
|
+
type LayoutPicker = InstanceType<typeof LayoutPicker>;
|
28
|
+
export default LayoutPicker;
|
@@ -0,0 +1,309 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
<script lang="ts">
|
4
|
+
/**
|
5
|
+
* Layout Preview Component
|
6
|
+
*
|
7
|
+
* Shows a visual preview of the selected layout with dropdown selectors for components.
|
8
|
+
* Much simpler than drag & drop - users just select components from dropdowns.
|
9
|
+
*/
|
10
|
+
import { createEventDispatcher } from 'svelte';
|
11
|
+
import type { GridLayoutDefinition, ComponentAssignment } from '../gridLayouts.js';
|
12
|
+
import type { ComponentConfig } from './GridSelector.svelte';
|
13
|
+
|
14
|
+
export let selectedLayout: GridLayoutDefinition | null = null;
|
15
|
+
export let componentAssignments: ComponentAssignment[] = [];
|
16
|
+
export let availableComponents: ComponentConfig[] = [];
|
17
|
+
|
18
|
+
const dispatch = createEventDispatcher<{
|
19
|
+
componentAssigned: { slotId: string; componentId: string };
|
20
|
+
componentRemoved: { slotId: string };
|
21
|
+
}>();
|
22
|
+
|
23
|
+
// Get component assignment for a slot
|
24
|
+
function getAssignedComponent(slotId: string): ComponentConfig | null {
|
25
|
+
const assignment = componentAssignments.find(a => a.slotId === slotId);
|
26
|
+
if (!assignment) return null;
|
27
|
+
|
28
|
+
return availableComponents.find(c => c.id === assignment.componentId) || null;
|
29
|
+
}
|
30
|
+
|
31
|
+
// Handle component selection from dropdown
|
32
|
+
function handleComponentSelect(slotId: string, event: Event) {
|
33
|
+
const target = event.target as HTMLSelectElement;
|
34
|
+
const componentId = target.value;
|
35
|
+
|
36
|
+
if (componentId === '') {
|
37
|
+
// Empty selection - remove component
|
38
|
+
dispatch('componentRemoved', { slotId });
|
39
|
+
} else {
|
40
|
+
// Component selected - assign it
|
41
|
+
dispatch('componentAssigned', { slotId, componentId });
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
// Get selected value for dropdown
|
46
|
+
function getSelectedValue(slotId: string): string {
|
47
|
+
const assignment = componentAssignments.find(a => a.slotId === slotId);
|
48
|
+
return assignment?.componentId || '';
|
49
|
+
}
|
50
|
+
</script>
|
51
|
+
|
52
|
+
<div class="layout-preview">
|
53
|
+
{#if !selectedLayout}
|
54
|
+
<div class="empty-preview">
|
55
|
+
<div class="empty-content">
|
56
|
+
<div class="empty-icon">🎨</div>
|
57
|
+
<h5>Select a Layout</h5>
|
58
|
+
<p class="text-muted">Choose a layout from the left panel to see the preview</p>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
{:else}
|
62
|
+
<div class="preview-header mb-3">
|
63
|
+
<h5 class="mb-1">
|
64
|
+
<span class="step-number badge bg-primary me-2">2</span>
|
65
|
+
{selectedLayout.name}
|
66
|
+
</h5>
|
67
|
+
<p class="text-muted mb-0">{selectedLayout.description}</p>
|
68
|
+
</div>
|
69
|
+
|
70
|
+
<div class="preview-container">
|
71
|
+
<!-- Simple grid with dropdowns for each slot -->
|
72
|
+
<div class="grid-preview" style="display: grid; gap: 12px; height: 100%;">
|
73
|
+
{#each selectedLayout.slots as slot}
|
74
|
+
{@const assignedComponent = getAssignedComponent(slot.id)}
|
75
|
+
<div
|
76
|
+
class="slot-selector"
|
77
|
+
class:has-component={assignedComponent}
|
78
|
+
style="
|
79
|
+
grid-column: {Math.floor(slot.position.x / 50) + 1} / span 1;
|
80
|
+
grid-row: {Math.floor(slot.position.y / 50) + 1} / span 1;
|
81
|
+
{selectedLayout.id === 'half-horizontal' ? 'grid-template-columns: 1fr 1fr; grid-template-rows: 1fr;' : ''}
|
82
|
+
{selectedLayout.id === 'half-vertical' ? 'grid-template-columns: 1fr; grid-template-rows: 1fr 1fr;' : ''}
|
83
|
+
{selectedLayout.id.includes('quarters') || selectedLayout.id.includes('left-half') || selectedLayout.id.includes('right-half') || selectedLayout.id.includes('top-half') || selectedLayout.id.includes('bottom-half') ? 'grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr;' : ''}
|
84
|
+
"
|
85
|
+
>
|
86
|
+
<div class="slot-content">
|
87
|
+
<div class="slot-header">
|
88
|
+
<h6 class="slot-name mb-2">{slot.name}</h6>
|
89
|
+
</div>
|
90
|
+
|
91
|
+
<div class="component-selector">
|
92
|
+
<select
|
93
|
+
class="form-select"
|
94
|
+
value={getSelectedValue(slot.id)}
|
95
|
+
on:change={(e) => handleComponentSelect(slot.id, e)}
|
96
|
+
aria-label="Select component for {slot.name}"
|
97
|
+
>
|
98
|
+
<option value="">Choose a component...</option>
|
99
|
+
{#each availableComponents as component}
|
100
|
+
<option value={component.id}>
|
101
|
+
{component.icon || '📦'} {component.name}
|
102
|
+
</option>
|
103
|
+
{/each}
|
104
|
+
</select>
|
105
|
+
</div>
|
106
|
+
|
107
|
+
{#if assignedComponent}
|
108
|
+
<div class="selected-component mt-3">
|
109
|
+
<div class="component-preview">
|
110
|
+
<div class="component-icon">
|
111
|
+
{#if assignedComponent.icon}
|
112
|
+
{#if assignedComponent.icon.startsWith('http') || assignedComponent.icon.startsWith('/') || assignedComponent.icon.startsWith('.')}
|
113
|
+
<img src={assignedComponent.icon} alt={assignedComponent.name} />
|
114
|
+
{:else}
|
115
|
+
<span class="icon-emoji">{assignedComponent.icon}</span>
|
116
|
+
{/if}
|
117
|
+
{:else}
|
118
|
+
<span class="icon-default">📦</span>
|
119
|
+
{/if}
|
120
|
+
</div>
|
121
|
+
<div class="component-info">
|
122
|
+
<div class="component-name">{assignedComponent.name}</div>
|
123
|
+
{#if assignedComponent.description}
|
124
|
+
<small class="component-description text-muted">{assignedComponent.description}</small>
|
125
|
+
{/if}
|
126
|
+
</div>
|
127
|
+
</div>
|
128
|
+
</div>
|
129
|
+
{/if}
|
130
|
+
</div>
|
131
|
+
</div>
|
132
|
+
{/each}
|
133
|
+
</div>
|
134
|
+
</div>
|
135
|
+
{/if}
|
136
|
+
</div>
|
137
|
+
|
138
|
+
<style>
|
139
|
+
.layout-preview {
|
140
|
+
height: 100%;
|
141
|
+
display: flex;
|
142
|
+
flex-direction: column;
|
143
|
+
}
|
144
|
+
|
145
|
+
.empty-preview {
|
146
|
+
display: flex;
|
147
|
+
align-items: center;
|
148
|
+
justify-content: center;
|
149
|
+
height: 100%;
|
150
|
+
min-height: 400px;
|
151
|
+
}
|
152
|
+
|
153
|
+
.empty-content {
|
154
|
+
text-align: center;
|
155
|
+
max-width: 300px;
|
156
|
+
}
|
157
|
+
|
158
|
+
.empty-icon {
|
159
|
+
font-size: 4rem;
|
160
|
+
margin-bottom: 1rem;
|
161
|
+
opacity: 0.3;
|
162
|
+
}
|
163
|
+
|
164
|
+
.preview-container {
|
165
|
+
flex: 1;
|
166
|
+
padding: 20px;
|
167
|
+
min-height: 400px;
|
168
|
+
}
|
169
|
+
|
170
|
+
.grid-preview {
|
171
|
+
display: grid;
|
172
|
+
gap: 12px;
|
173
|
+
height: 100%;
|
174
|
+
border: 2px dashed #dee2e6;
|
175
|
+
border-radius: 12px;
|
176
|
+
padding: 12px;
|
177
|
+
background: #fafafa;
|
178
|
+
}
|
179
|
+
|
180
|
+
.slot-selector {
|
181
|
+
background: white;
|
182
|
+
border: 2px solid #dee2e6;
|
183
|
+
border-radius: 8px;
|
184
|
+
padding: 16px;
|
185
|
+
min-height: 120px;
|
186
|
+
display: flex;
|
187
|
+
flex-direction: column;
|
188
|
+
transition: all 0.2s ease;
|
189
|
+
}
|
190
|
+
|
191
|
+
.slot-selector:hover {
|
192
|
+
border-color: #007bff;
|
193
|
+
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.1);
|
194
|
+
}
|
195
|
+
|
196
|
+
.slot-selector.has-component {
|
197
|
+
border-color: #28a745;
|
198
|
+
background: #f8fff9;
|
199
|
+
}
|
200
|
+
|
201
|
+
.slot-content {
|
202
|
+
flex: 1;
|
203
|
+
display: flex;
|
204
|
+
flex-direction: column;
|
205
|
+
}
|
206
|
+
|
207
|
+
.slot-header {
|
208
|
+
text-align: center;
|
209
|
+
margin-bottom: 12px;
|
210
|
+
}
|
211
|
+
|
212
|
+
.slot-name {
|
213
|
+
font-weight: 600;
|
214
|
+
color: #495057;
|
215
|
+
margin-bottom: 0;
|
216
|
+
font-size: 14px;
|
217
|
+
}
|
218
|
+
|
219
|
+
.component-selector {
|
220
|
+
margin-bottom: 12px;
|
221
|
+
}
|
222
|
+
|
223
|
+
.selected-component {
|
224
|
+
flex: 1;
|
225
|
+
display: flex;
|
226
|
+
align-items: center;
|
227
|
+
justify-content: center;
|
228
|
+
}
|
229
|
+
|
230
|
+
.component-preview {
|
231
|
+
text-align: center;
|
232
|
+
width: 100%;
|
233
|
+
}
|
234
|
+
|
235
|
+
.component-icon {
|
236
|
+
width: 40px;
|
237
|
+
height: 40px;
|
238
|
+
display: flex;
|
239
|
+
align-items: center;
|
240
|
+
justify-content: center;
|
241
|
+
background: #f8f9fa;
|
242
|
+
border-radius: 6px;
|
243
|
+
border: 1px solid #dee2e6;
|
244
|
+
margin: 0 auto 8px;
|
245
|
+
}
|
246
|
+
|
247
|
+
.component-icon img {
|
248
|
+
width: 24px;
|
249
|
+
height: 24px;
|
250
|
+
object-fit: contain;
|
251
|
+
}
|
252
|
+
|
253
|
+
.icon-emoji,
|
254
|
+
.icon-default {
|
255
|
+
font-size: 20px;
|
256
|
+
line-height: 1;
|
257
|
+
}
|
258
|
+
|
259
|
+
.component-info {
|
260
|
+
text-align: center;
|
261
|
+
}
|
262
|
+
|
263
|
+
.component-name {
|
264
|
+
font-weight: 500;
|
265
|
+
font-size: 13px;
|
266
|
+
color: #333;
|
267
|
+
margin-bottom: 4px;
|
268
|
+
}
|
269
|
+
|
270
|
+
.component-description {
|
271
|
+
font-size: 11px;
|
272
|
+
line-height: 1.3;
|
273
|
+
color: #6c757d;
|
274
|
+
}
|
275
|
+
|
276
|
+
/* Dark theme support */
|
277
|
+
:global(.theme-dark) .grid-preview {
|
278
|
+
background: #2d2d2d;
|
279
|
+
border-color: #555;
|
280
|
+
}
|
281
|
+
|
282
|
+
:global(.theme-dark) .slot-selector {
|
283
|
+
background: #3d3d3d;
|
284
|
+
border-color: #555;
|
285
|
+
color: #fff;
|
286
|
+
}
|
287
|
+
|
288
|
+
:global(.theme-dark) .slot-selector:hover {
|
289
|
+
border-color: #4dabf7;
|
290
|
+
}
|
291
|
+
|
292
|
+
:global(.theme-dark) .slot-selector.has-component {
|
293
|
+
border-color: #51cf66;
|
294
|
+
background: #2d3d2d;
|
295
|
+
}
|
296
|
+
|
297
|
+
:global(.theme-dark) .component-icon {
|
298
|
+
background: #2d2d2d;
|
299
|
+
border-color: #555;
|
300
|
+
}
|
301
|
+
|
302
|
+
:global(.theme-dark) .component-name {
|
303
|
+
color: #fff;
|
304
|
+
}
|
305
|
+
|
306
|
+
:global(.theme-dark) .slot-name {
|
307
|
+
color: #ccc;
|
308
|
+
}
|
309
|
+
</style>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import type { GridLayoutDefinition, ComponentAssignment } from '../gridLayouts.js';
|
2
|
+
import type { ComponentConfig } from './GridSelector.svelte';
|
3
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
4
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
5
|
+
$$bindings?: Bindings;
|
6
|
+
} & Exports;
|
7
|
+
(internal: unknown, props: Props & {
|
8
|
+
$$events?: Events;
|
9
|
+
$$slots?: Slots;
|
10
|
+
}): Exports & {
|
11
|
+
$set?: any;
|
12
|
+
$on?: any;
|
13
|
+
};
|
14
|
+
z_$$bindings?: Bindings;
|
15
|
+
}
|
16
|
+
declare const LayoutPreview: $$__sveltets_2_IsomorphicComponent<{
|
17
|
+
selectedLayout?: GridLayoutDefinition | null;
|
18
|
+
componentAssignments?: ComponentAssignment[];
|
19
|
+
availableComponents?: ComponentConfig[];
|
20
|
+
}, {
|
21
|
+
componentAssigned: CustomEvent<{
|
22
|
+
slotId: string;
|
23
|
+
componentId: string;
|
24
|
+
}>;
|
25
|
+
componentRemoved: CustomEvent<{
|
26
|
+
slotId: string;
|
27
|
+
}>;
|
28
|
+
} & {
|
29
|
+
[evt: string]: CustomEvent<any>;
|
30
|
+
}, {}, {}, string>;
|
31
|
+
type LayoutPreview = InstanceType<typeof LayoutPreview>;
|
32
|
+
export default LayoutPreview;
|
@@ -0,0 +1,4 @@
|
|
1
|
+
export { default as GridSelector, type ComponentConfig } from './GridSelector.svelte';
|
2
|
+
export { default as LayoutPicker } from './LayoutPicker.svelte';
|
3
|
+
export { default as LayoutPreview } from './LayoutPreview.svelte';
|
4
|
+
export { default as ConfigurationPanel } from './ConfigurationPanel.svelte';
|
@@ -0,0 +1,4 @@
|
|
1
|
+
export { default as GridSelector } from './GridSelector.svelte';
|
2
|
+
export { default as LayoutPicker } from './LayoutPicker.svelte';
|
3
|
+
export { default as LayoutPreview } from './LayoutPreview.svelte';
|
4
|
+
export { default as ConfigurationPanel } from './ConfigurationPanel.svelte';
|