@lobb-js/studio 0.33.0 → 0.35.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.
- package/dist/applyUITheme.d.ts +2 -0
- package/dist/{applyStudioTheme.js → applyUITheme.js} +4 -4
- package/dist/components/LlmButton.svelte +4 -2
- package/dist/components/LlmButton.svelte.d.ts +1 -0
- package/dist/components/Studio.svelte +15 -7
- package/dist/components/codeEditor.svelte +1 -1
- package/dist/components/createManyButton.svelte +2 -2
- package/dist/components/dataTable/dataTable.svelte +1 -1
- package/dist/components/dataTable/dataTableTabs.svelte +1 -1
- package/dist/components/dataTable/filter.svelte +3 -2
- package/dist/components/dataTable/filterButton.svelte +1 -1
- package/dist/components/dataTable/footer.svelte +1 -1
- package/dist/components/dataTable/header.svelte +14 -21
- package/dist/components/dataTable/listViewChildren.svelte +1 -1
- package/dist/components/dataTable/sort.svelte +1 -1
- package/dist/components/dataTable/sortButton.svelte +1 -1
- package/dist/components/dataTable/table.svelte +8 -8
- package/dist/components/dataTable/utils.js +2 -1
- package/dist/components/dataTablePopup/dataTablePopup.svelte +1 -1
- package/dist/components/detailView/create/children.svelte +1 -1
- package/dist/components/detailView/create/createDetailView.svelte +2 -2
- package/dist/components/detailView/create/createDetailViewButton.svelte +2 -0
- package/dist/components/detailView/create/createDetailViewButton.svelte.d.ts +1 -0
- package/dist/components/detailView/create/createDetailViewChildren.svelte +4 -4
- package/dist/components/detailView/create/createManyView.svelte +4 -4
- package/dist/components/detailView/detailView.svelte +2 -1
- package/dist/components/detailView/fieldInput.svelte +10 -10
- package/dist/components/detailView/fieldInputReplacement.svelte +7 -7
- package/dist/components/detailView/passwordInput.svelte +1 -1
- package/dist/components/detailView/update/updateDetailView.svelte +2 -2
- package/dist/components/detailView/update/updateDetailViewButton.svelte +2 -0
- package/dist/components/detailView/update/updateDetailViewButton.svelte.d.ts +1 -0
- package/dist/components/detailView/update/updateDetailViewChildren.svelte +4 -4
- package/dist/components/diffViewer.svelte +1 -1
- package/dist/components/drawer.svelte +2 -2
- package/dist/components/foreingKeyInput.svelte +2 -2
- package/dist/components/horizontalNav.svelte +85 -0
- package/dist/components/horizontalNav.svelte.d.ts +3 -0
- package/dist/components/importButton.svelte +7 -7
- package/dist/components/mainNav.svelte +15 -0
- package/dist/components/mainNav.svelte.d.ts +6 -0
- package/dist/components/mainNavShared.d.ts +10 -0
- package/dist/components/mainNavShared.js +62 -0
- package/dist/components/polymorphicInput.svelte +1 -1
- package/dist/components/rangeCalendarButton.svelte +11 -12
- package/dist/components/richTextEditor.svelte +1 -1
- package/dist/components/routes/extensions/publicExtension.svelte +1 -1
- package/dist/components/routes/home.svelte +1 -1
- package/dist/components/routes/workflows/workflows.svelte +1 -1
- package/dist/components/setServerPage.svelte +1 -1
- package/dist/components/sidebar/sidebar.svelte +3 -3
- package/dist/components/sidebar/sidebarElements.svelte +4 -4
- package/dist/components/singletone.svelte +2 -2
- package/dist/components/ui/skeleton/skeleton.svelte +1 -1
- package/dist/components/ui/tooltip/tooltip-content.svelte +1 -1
- package/dist/components/verticalNav.svelte +174 -0
- package/dist/components/verticalNav.svelte.d.ts +3 -0
- package/dist/components/workflowEditor.svelte +2 -2
- package/dist/store.types.d.ts +4 -3
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +12 -0
- package/package.json +2 -2
- package/src/app.css +50 -76
- package/src/lib/{applyStudioTheme.ts → applyUITheme.ts} +5 -5
- package/src/lib/components/LlmButton.svelte +4 -2
- package/src/lib/components/Studio.svelte +15 -7
- package/src/lib/components/codeEditor.svelte +1 -1
- package/src/lib/components/createManyButton.svelte +2 -2
- package/src/lib/components/dataTable/dataTable.svelte +1 -1
- package/src/lib/components/dataTable/dataTableTabs.svelte +1 -1
- package/src/lib/components/dataTable/filter.svelte +3 -2
- package/src/lib/components/dataTable/filterButton.svelte +1 -1
- package/src/lib/components/dataTable/footer.svelte +1 -1
- package/src/lib/components/dataTable/header.svelte +14 -21
- package/src/lib/components/dataTable/listViewChildren.svelte +1 -1
- package/src/lib/components/dataTable/sort.svelte +1 -1
- package/src/lib/components/dataTable/sortButton.svelte +1 -1
- package/src/lib/components/dataTable/table.svelte +8 -8
- package/src/lib/components/dataTable/utils.ts +2 -1
- package/src/lib/components/dataTablePopup/dataTablePopup.svelte +1 -1
- package/src/lib/components/detailView/create/children.svelte +1 -1
- package/src/lib/components/detailView/create/createDetailView.svelte +2 -2
- package/src/lib/components/detailView/create/createDetailViewButton.svelte +2 -0
- package/src/lib/components/detailView/create/createDetailViewChildren.svelte +4 -4
- package/src/lib/components/detailView/create/createManyView.svelte +4 -4
- package/src/lib/components/detailView/detailView.svelte +2 -1
- package/src/lib/components/detailView/fieldInput.svelte +10 -10
- package/src/lib/components/detailView/fieldInputReplacement.svelte +7 -7
- package/src/lib/components/detailView/passwordInput.svelte +1 -1
- package/src/lib/components/detailView/update/updateDetailView.svelte +2 -2
- package/src/lib/components/detailView/update/updateDetailViewButton.svelte +2 -0
- package/src/lib/components/detailView/update/updateDetailViewChildren.svelte +4 -4
- package/src/lib/components/diffViewer.svelte +1 -1
- package/src/lib/components/drawer.svelte +2 -2
- package/src/lib/components/foreingKeyInput.svelte +2 -2
- package/src/lib/components/horizontalNav.svelte +85 -0
- package/src/lib/components/importButton.svelte +7 -7
- package/src/lib/components/mainNav.svelte +15 -0
- package/src/lib/components/mainNavShared.ts +67 -0
- package/src/lib/components/polymorphicInput.svelte +1 -1
- package/src/lib/components/rangeCalendarButton.svelte +11 -12
- package/src/lib/components/richTextEditor.svelte +1 -1
- package/src/lib/components/routes/extensions/publicExtension.svelte +1 -1
- package/src/lib/components/routes/home.svelte +1 -1
- package/src/lib/components/routes/workflows/workflows.svelte +1 -1
- package/src/lib/components/setServerPage.svelte +1 -1
- package/src/lib/components/sidebar/sidebar.svelte +3 -3
- package/src/lib/components/sidebar/sidebarElements.svelte +4 -4
- package/src/lib/components/singletone.svelte +2 -2
- package/src/lib/components/ui/skeleton/skeleton.svelte +1 -1
- package/src/lib/components/ui/tooltip/tooltip-content.svelte +1 -1
- package/src/lib/components/verticalNav.svelte +174 -0
- package/src/lib/components/workflowEditor.svelte +2 -2
- package/src/lib/store.types.ts +2 -2
- package/src/lib/utils.ts +12 -0
- package/dist/applyStudioTheme.d.ts +0 -2
- package/dist/components/miniSidebar.svelte +0 -300
- package/dist/components/miniSidebar.svelte.d.ts +0 -5
- package/src/lib/components/miniSidebar.svelte +0 -300
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
</script>
|
|
40
40
|
|
|
41
41
|
<div class="flex flex-col h-full bg-background">
|
|
42
|
-
<div class="flex justify-between items-center gap-2 p-2 border-b h-
|
|
42
|
+
<div class="flex justify-between items-center gap-2 p-2 border-b h-12 shrink-0">
|
|
43
43
|
<div class="flex items-center gap-1">
|
|
44
44
|
<SidebarTrigger />
|
|
45
45
|
</div>
|
|
46
46
|
<div>
|
|
47
|
-
<Button
|
|
47
|
+
<Button size="sm" Icon={Save} onclick={handleSave}>
|
|
48
48
|
Save
|
|
49
49
|
</Button>
|
|
50
50
|
</div>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
bind:ref
|
|
15
15
|
{sideOffset}
|
|
16
16
|
class={cn(
|
|
17
|
-
"bg-
|
|
17
|
+
"bg-popover text-popover-foreground border shadow-sm animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 overflow-hidden rounded-md px-3 py-1.5 text-xs",
|
|
18
18
|
className
|
|
19
19
|
)}
|
|
20
20
|
{...restProps}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { X } from "lucide-svelte";
|
|
3
|
+
import { onMount } from "svelte";
|
|
4
|
+
import { page } from "$app/state";
|
|
5
|
+
import { goto } from "$app/navigation";
|
|
6
|
+
import Button from "./ui/button/button.svelte";
|
|
7
|
+
import Separator from "./ui/separator/separator.svelte";
|
|
8
|
+
import * as Tooltip from "./ui/tooltip";
|
|
9
|
+
import * as Accordion from "./ui/accordion/index.js";
|
|
10
|
+
import * as Popover from "./ui/popover";
|
|
11
|
+
import { getStudioContext } from "../context";
|
|
12
|
+
import { mediaQueries } from "../utils";
|
|
13
|
+
import { buildNavSections, isItemActive, type NavItem } from "./mainNavShared";
|
|
14
|
+
|
|
15
|
+
const { lobb, ctx } = getStudioContext();
|
|
16
|
+
|
|
17
|
+
let isSmallScreen = $derived(!mediaQueries.sm.current);
|
|
18
|
+
let isCollapsed = $state(true);
|
|
19
|
+
$effect(() => {
|
|
20
|
+
isCollapsed = isSmallScreen;
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
let sections: NavItem[][] = $state([[], [], []]);
|
|
24
|
+
onMount(async () => {
|
|
25
|
+
sections = await buildNavSections(lobb, ctx);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const currentPath = $derived(page.url.pathname.replace(/\/$/, "") || "/");
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
{#snippet section(section: NavItem[])}
|
|
32
|
+
<div class="flex flex-col {isSmallScreen ? 'gap-0' : 'gap-2'}">
|
|
33
|
+
{#each section as item}
|
|
34
|
+
{@const active = isItemActive(currentPath, item)}
|
|
35
|
+
{#if isSmallScreen}
|
|
36
|
+
{#if !item.navs}
|
|
37
|
+
<Button
|
|
38
|
+
onclick={() => {
|
|
39
|
+
if (item.onclick) item.onclick();
|
|
40
|
+
else if (item.href) goto(item.href);
|
|
41
|
+
isCollapsed = true;
|
|
42
|
+
}}
|
|
43
|
+
class="flex items-center justify-start flex-nowrap text-nowrap h-10 w-full {active
|
|
44
|
+
? 'bg-accent text-foreground'
|
|
45
|
+
: 'text-foreground/70 hover:bg-accent/50 hover:text-foreground'}"
|
|
46
|
+
variant="ghost"
|
|
47
|
+
size="icon"
|
|
48
|
+
Icon={item.icon}
|
|
49
|
+
>
|
|
50
|
+
{item.label}
|
|
51
|
+
</Button>
|
|
52
|
+
{:else}
|
|
53
|
+
<Accordion.Root type="single">
|
|
54
|
+
<Accordion.Item class="border-b-0">
|
|
55
|
+
<Accordion.Trigger class="justify-between p-0 h-10">
|
|
56
|
+
<div
|
|
57
|
+
class="flex items-center gap-2 {active
|
|
58
|
+
? 'text-accent-foreground'
|
|
59
|
+
: 'text-foreground/70'}"
|
|
60
|
+
>
|
|
61
|
+
<item.icon size="18" />
|
|
62
|
+
<div class="text-nowrap">{item.label}</div>
|
|
63
|
+
</div>
|
|
64
|
+
</Accordion.Trigger>
|
|
65
|
+
<Accordion.Content class="pl-2 border-l border-border">
|
|
66
|
+
{#each item.navs as childItem}
|
|
67
|
+
{@const childActive = isItemActive(currentPath, childItem)}
|
|
68
|
+
<Button
|
|
69
|
+
onclick={() => {
|
|
70
|
+
if (childItem.onclick) childItem.onclick();
|
|
71
|
+
else if (childItem.href) goto(childItem.href);
|
|
72
|
+
isCollapsed = true;
|
|
73
|
+
}}
|
|
74
|
+
class="flex items-center justify-start flex-nowrap text-nowrap h-8 w-full {childActive
|
|
75
|
+
? 'bg-accent text-foreground'
|
|
76
|
+
: 'text-foreground/70 hover:bg-accent/50 hover:text-foreground'}"
|
|
77
|
+
variant="ghost"
|
|
78
|
+
size="icon"
|
|
79
|
+
Icon={childItem.icon}
|
|
80
|
+
>
|
|
81
|
+
{childItem.label}
|
|
82
|
+
</Button>
|
|
83
|
+
{/each}
|
|
84
|
+
</Accordion.Content>
|
|
85
|
+
</Accordion.Item>
|
|
86
|
+
</Accordion.Root>
|
|
87
|
+
{/if}
|
|
88
|
+
{:else}
|
|
89
|
+
<Tooltip.Root>
|
|
90
|
+
<Tooltip.Trigger>
|
|
91
|
+
{#if !item.navs}
|
|
92
|
+
<Button
|
|
93
|
+
onclick={() => { if (item.onclick) item.onclick(); }}
|
|
94
|
+
href={item.href}
|
|
95
|
+
class={active
|
|
96
|
+
? 'bg-accent text-foreground'
|
|
97
|
+
: 'text-foreground/70 hover:bg-accent/50 hover:text-foreground'}
|
|
98
|
+
variant="ghost"
|
|
99
|
+
size="icon"
|
|
100
|
+
Icon={item.icon}
|
|
101
|
+
></Button>
|
|
102
|
+
{:else}
|
|
103
|
+
<Popover.Root>
|
|
104
|
+
<Popover.Trigger>
|
|
105
|
+
<Button
|
|
106
|
+
class={active
|
|
107
|
+
? 'bg-accent text-foreground'
|
|
108
|
+
: 'text-foreground/70 hover:bg-accent/50 hover:text-foreground'}
|
|
109
|
+
variant="ghost"
|
|
110
|
+
size="icon"
|
|
111
|
+
Icon={item.icon}
|
|
112
|
+
></Button>
|
|
113
|
+
</Popover.Trigger>
|
|
114
|
+
<Popover.Content sideOffset={17.5} side="right" class="popover_content w-60 mb-4 p-0">
|
|
115
|
+
<div class="py-1">
|
|
116
|
+
{#each item.navs as childItem}
|
|
117
|
+
{@const childActive = isItemActive(currentPath, childItem)}
|
|
118
|
+
<div class="px-1 text-xs text-muted-foreground">
|
|
119
|
+
<Button
|
|
120
|
+
variant="ghost"
|
|
121
|
+
class="flex h-7 w-full justify-start p-2 text-xs font-normal {childActive
|
|
122
|
+
? 'bg-accent text-accent-foreground'
|
|
123
|
+
: 'text-muted-foreground'}"
|
|
124
|
+
Icon={childItem.icon}
|
|
125
|
+
onclick={() => { if (childItem.onclick) childItem.onclick(); }}
|
|
126
|
+
href={childItem.href}
|
|
127
|
+
>
|
|
128
|
+
{childItem.label}
|
|
129
|
+
</Button>
|
|
130
|
+
</div>
|
|
131
|
+
{/each}
|
|
132
|
+
</div>
|
|
133
|
+
</Popover.Content>
|
|
134
|
+
</Popover.Root>
|
|
135
|
+
{/if}
|
|
136
|
+
</Tooltip.Trigger>
|
|
137
|
+
<Tooltip.Content side="right" sideOffset={15}>
|
|
138
|
+
{item.label}
|
|
139
|
+
</Tooltip.Content>
|
|
140
|
+
</Tooltip.Root>
|
|
141
|
+
{/if}
|
|
142
|
+
{/each}
|
|
143
|
+
</div>
|
|
144
|
+
{/snippet}
|
|
145
|
+
|
|
146
|
+
<div
|
|
147
|
+
class="
|
|
148
|
+
{isSmallScreen ? 'fixed top-0 left-0 h-full z-50' : 'relative'}
|
|
149
|
+
border-r border-border bg-card text-foreground w-screen
|
|
150
|
+
{isCollapsed
|
|
151
|
+
? 'max-w-0 p-0'
|
|
152
|
+
: `max-w-14 ${isSmallScreen ? 'px-3 pb-3' : 'p-2'}`}"
|
|
153
|
+
style="transition: max-width 150ms, padding 150ms; {isSmallScreen && !isCollapsed ? 'max-width: 100vw' : ''}"
|
|
154
|
+
>
|
|
155
|
+
{#if isSmallScreen && !isCollapsed}
|
|
156
|
+
<X
|
|
157
|
+
class="absolute h-10 text-foreground/70 hover:bg-transparent cursor-pointer hover:text-foreground"
|
|
158
|
+
style="left: 0.6rem; top: 0rem;"
|
|
159
|
+
size="18"
|
|
160
|
+
onclick={() => (isCollapsed = !isCollapsed)}
|
|
161
|
+
/>
|
|
162
|
+
{/if}
|
|
163
|
+
<div class="flex h-full flex-col justify-between gap-2 w-full overflow-hidden">
|
|
164
|
+
<div class="flex flex-col gap-2 {isSmallScreen ? 'pt-8' : ''}">
|
|
165
|
+
{@render section(sections[0])}
|
|
166
|
+
<Separator class="bg-border" />
|
|
167
|
+
{@render section(sections[1])}
|
|
168
|
+
</div>
|
|
169
|
+
<div class="flex flex-col gap-2">
|
|
170
|
+
<Separator class="bg-border" />
|
|
171
|
+
{@render section(sections[2])}
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
@@ -157,7 +157,7 @@
|
|
|
157
157
|
<div>
|
|
158
158
|
{#if workflow.id}
|
|
159
159
|
<Button
|
|
160
|
-
class="
|
|
160
|
+
size="sm" class="w-full"
|
|
161
161
|
variant="default"
|
|
162
162
|
onclick={handleUpdateWorkflow}
|
|
163
163
|
Icon={Edit}
|
|
@@ -167,7 +167,7 @@
|
|
|
167
167
|
</Button>
|
|
168
168
|
{:else}
|
|
169
169
|
<Button
|
|
170
|
-
class="
|
|
170
|
+
size="sm" class="w-full"
|
|
171
171
|
variant="default"
|
|
172
172
|
onclick={handleCreateWorkflow}
|
|
173
173
|
Icon={Plus}
|
package/dist/store.types.d.ts
CHANGED
|
@@ -30,14 +30,15 @@ interface Collection {
|
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
32
|
type Collections = Record<string, Collection>;
|
|
33
|
-
export interface
|
|
33
|
+
export interface UITheme {
|
|
34
34
|
light?: Record<string, string>;
|
|
35
35
|
dark?: Record<string, string>;
|
|
36
36
|
}
|
|
37
37
|
interface Meta {
|
|
38
38
|
version: string;
|
|
39
|
-
|
|
40
|
-
theme?:
|
|
39
|
+
ui?: {
|
|
40
|
+
theme?: UITheme;
|
|
41
|
+
horizontalNav?: boolean;
|
|
41
42
|
};
|
|
42
43
|
relations: Array<any>;
|
|
43
44
|
collections: Collections;
|
package/dist/utils.d.ts
CHANGED
|
@@ -18,6 +18,7 @@ export declare const mediaQueries: {
|
|
|
18
18
|
xl: MediaQuery;
|
|
19
19
|
'2xl': MediaQuery;
|
|
20
20
|
};
|
|
21
|
+
export declare function getFieldTypeLabel(type: string | undefined | null): string;
|
|
21
22
|
export declare function calculateDrawerWidth(): number;
|
|
22
23
|
export declare function getChangedProperties(oldObj: Record<string, any>, newObj: Record<string, any>): Record<string, any>;
|
|
23
24
|
export declare function parseFunction(functionString: string): any;
|
package/dist/utils.js
CHANGED
|
@@ -12,6 +12,18 @@ export const mediaQueries = {
|
|
|
12
12
|
xl: new MediaQuery('min-width: 1280px'),
|
|
13
13
|
'2xl': new MediaQuery('min-width: 1536px'),
|
|
14
14
|
};
|
|
15
|
+
// User-facing label for a field type. "string"/"text" are jargon to
|
|
16
|
+
// non-technical users, so we surface "Text"/"Long text" instead. Types
|
|
17
|
+
// not in the map fall through to the raw identifier — extend as needed.
|
|
18
|
+
const FIELD_TYPE_LABELS = {
|
|
19
|
+
string: "Text",
|
|
20
|
+
text: "Long text",
|
|
21
|
+
};
|
|
22
|
+
export function getFieldTypeLabel(type) {
|
|
23
|
+
if (!type)
|
|
24
|
+
return "";
|
|
25
|
+
return FIELD_TYPE_LABELS[type] ?? type;
|
|
26
|
+
}
|
|
15
27
|
export function calculateDrawerWidth() {
|
|
16
28
|
const backgroundDrawerButtons = document.querySelectorAll(".backgroundDrawerButton");
|
|
17
29
|
const drawersCount = Array.from(backgroundDrawerButtons).length;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobb-js/studio",
|
|
3
3
|
"license": "UNLICENSED",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.35.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"postpublish": "./scripts/postpublish.sh"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@lobb-js/core": "^0.
|
|
45
|
+
"@lobb-js/core": "^0.35.0",
|
|
46
46
|
"@chromatic-com/storybook": "^4.1.2",
|
|
47
47
|
"@storybook/addon-a11y": "^10.0.1",
|
|
48
48
|
"@storybook/addon-docs": "^10.0.1",
|
package/src/app.css
CHANGED
|
@@ -7,74 +7,62 @@
|
|
|
7
7
|
@custom-variant dark (&:is(.dark *));
|
|
8
8
|
|
|
9
9
|
:root {
|
|
10
|
-
--radius: 0.
|
|
10
|
+
--radius: 0.5rem;
|
|
11
|
+
|
|
11
12
|
--background: oklch(1 0 0);
|
|
12
|
-
--foreground: oklch(0.
|
|
13
|
+
--foreground: oklch(0.20 0.012 138);
|
|
14
|
+
|
|
13
15
|
--card: oklch(1 0 0);
|
|
14
|
-
--card-foreground: oklch(0.
|
|
16
|
+
--card-foreground: oklch(0.20 0.012 138);
|
|
15
17
|
--popover: oklch(1 0 0);
|
|
16
|
-
--popover-foreground: oklch(0.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
--
|
|
20
|
-
--
|
|
21
|
-
|
|
22
|
-
--
|
|
23
|
-
--
|
|
24
|
-
|
|
25
|
-
--
|
|
26
|
-
--
|
|
27
|
-
|
|
28
|
-
--
|
|
29
|
-
--
|
|
30
|
-
|
|
31
|
-
--
|
|
32
|
-
|
|
33
|
-
--
|
|
34
|
-
--
|
|
35
|
-
--
|
|
36
|
-
--sidebar-foreground: oklch(0.129 0.042 264.695);
|
|
37
|
-
--sidebar-primary: oklch(0.208 0.042 265.755);
|
|
38
|
-
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
|
39
|
-
--sidebar-accent: oklch(0.968 0.007 247.896);
|
|
40
|
-
--sidebar-accent-foreground: oklch(0.208 0.042 265.755);
|
|
41
|
-
--sidebar-border: oklch(0.929 0.013 255.508);
|
|
42
|
-
--sidebar-ring: oklch(0.704 0.04 256.788);
|
|
18
|
+
--popover-foreground: oklch(0.20 0.012 138);
|
|
19
|
+
|
|
20
|
+
/* Brand green — used for primary buttons, focus rings, active accents. */
|
|
21
|
+
--primary: oklch(0.62 0.18 138);
|
|
22
|
+
--primary-foreground: oklch(1 0 0);
|
|
23
|
+
|
|
24
|
+
--secondary: oklch(0.97 0.001 138);
|
|
25
|
+
--secondary-foreground: oklch(0.20 0.012 138);
|
|
26
|
+
|
|
27
|
+
--muted: oklch(0.97 0.001 138);
|
|
28
|
+
--muted-foreground: oklch(0.55 0.012 138);
|
|
29
|
+
|
|
30
|
+
--accent: oklch(0.95 0.001 138);
|
|
31
|
+
--accent-foreground: oklch(0.20 0.012 138);
|
|
32
|
+
|
|
33
|
+
--destructive: oklch(0.62 0.24 27);
|
|
34
|
+
|
|
35
|
+
--border: oklch(0.91 0.001 138);
|
|
36
|
+
--input: oklch(0.91 0.001 138);
|
|
37
|
+
--ring: oklch(0.62 0.18 138);
|
|
43
38
|
}
|
|
44
39
|
|
|
45
40
|
.dark {
|
|
46
|
-
--background: oklch(0.
|
|
47
|
-
--foreground: oklch(0.
|
|
48
|
-
|
|
49
|
-
--card
|
|
50
|
-
--
|
|
51
|
-
--popover
|
|
52
|
-
--
|
|
53
|
-
|
|
54
|
-
--
|
|
55
|
-
--
|
|
56
|
-
|
|
57
|
-
--
|
|
58
|
-
--
|
|
59
|
-
|
|
60
|
-
--
|
|
61
|
-
--
|
|
62
|
-
|
|
63
|
-
--
|
|
64
|
-
--
|
|
65
|
-
|
|
66
|
-
--
|
|
67
|
-
|
|
68
|
-
--
|
|
69
|
-
--
|
|
70
|
-
--
|
|
71
|
-
--sidebar-foreground: oklch(0.984 0.003 247.858);
|
|
72
|
-
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
73
|
-
--sidebar-primary-foreground: oklch(0.984 0.003 247.858);
|
|
74
|
-
--sidebar-accent: oklch(0.279 0.041 260.031);
|
|
75
|
-
--sidebar-accent-foreground: oklch(0.984 0.003 247.858);
|
|
76
|
-
--sidebar-border: oklch(1 0 0 / 10%);
|
|
77
|
-
--sidebar-ring: oklch(0.551 0.027 264.364);
|
|
41
|
+
--background: oklch(0.16 0.012 138);
|
|
42
|
+
--foreground: oklch(0.94 0.012 138);
|
|
43
|
+
|
|
44
|
+
--card: oklch(0.18 0.012 138);
|
|
45
|
+
--card-foreground: oklch(0.94 0.012 138);
|
|
46
|
+
--popover: oklch(0.18 0.012 138);
|
|
47
|
+
--popover-foreground: oklch(0.94 0.012 138);
|
|
48
|
+
|
|
49
|
+
--primary: oklch(0.72 0.20 138);
|
|
50
|
+
--primary-foreground: oklch(0.16 0.012 138);
|
|
51
|
+
|
|
52
|
+
--secondary: oklch(0.24 0.012 138);
|
|
53
|
+
--secondary-foreground: oklch(0.94 0.012 138);
|
|
54
|
+
|
|
55
|
+
--muted: oklch(0.24 0.012 138);
|
|
56
|
+
--muted-foreground: oklch(0.65 0.012 138);
|
|
57
|
+
|
|
58
|
+
--accent: oklch(0.27 0.012 138);
|
|
59
|
+
--accent-foreground: oklch(0.94 0.012 138);
|
|
60
|
+
|
|
61
|
+
--destructive: oklch(0.70 0.22 27);
|
|
62
|
+
|
|
63
|
+
--border: oklch(1 0 0 / 8%);
|
|
64
|
+
--input: oklch(1 0 0 / 12%);
|
|
65
|
+
--ring: oklch(0.72 0.20 138);
|
|
78
66
|
}
|
|
79
67
|
|
|
80
68
|
@theme inline {
|
|
@@ -94,26 +82,12 @@
|
|
|
94
82
|
--color-secondary-foreground: var(--secondary-foreground);
|
|
95
83
|
--color-muted: var(--muted);
|
|
96
84
|
--color-muted-foreground: var(--muted-foreground);
|
|
97
|
-
--color-muted-soft: var(--muted-soft);
|
|
98
85
|
--color-accent: var(--accent);
|
|
99
86
|
--color-accent-foreground: var(--accent-foreground);
|
|
100
87
|
--color-destructive: var(--destructive);
|
|
101
88
|
--color-border: var(--border);
|
|
102
89
|
--color-input: var(--input);
|
|
103
90
|
--color-ring: var(--ring);
|
|
104
|
-
--color-chart-1: var(--chart-1);
|
|
105
|
-
--color-chart-2: var(--chart-2);
|
|
106
|
-
--color-chart-3: var(--chart-3);
|
|
107
|
-
--color-chart-4: var(--chart-4);
|
|
108
|
-
--color-chart-5: var(--chart-5);
|
|
109
|
-
--color-sidebar: var(--sidebar);
|
|
110
|
-
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
111
|
-
--color-sidebar-primary: var(--sidebar-primary);
|
|
112
|
-
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
113
|
-
--color-sidebar-accent: var(--sidebar-accent);
|
|
114
|
-
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
115
|
-
--color-sidebar-border: var(--sidebar-border);
|
|
116
|
-
--color-sidebar-ring: var(--sidebar-ring);
|
|
117
91
|
}
|
|
118
92
|
|
|
119
93
|
@layer base {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UITheme } from "./store.types";
|
|
2
2
|
|
|
3
|
-
//
|
|
4
|
-
//
|
|
3
|
+
// UI theme injection. Writes the configured CSS-variable overrides into
|
|
4
|
+
// a single <style> tag — light overrides under `:root`, dark under
|
|
5
5
|
// `.dark` — so each mode picks up its own variant. Idempotent: re-runs
|
|
6
6
|
// replace the previous block.
|
|
7
7
|
|
|
8
|
-
const STYLE_ID = "lobb-
|
|
8
|
+
const STYLE_ID = "lobb-ui-theme";
|
|
9
9
|
|
|
10
10
|
function buildDeclarations(vars: Record<string, string> | undefined): string {
|
|
11
11
|
if (!vars) return "";
|
|
@@ -17,7 +17,7 @@ function buildDeclarations(vars: Record<string, string> | undefined): string {
|
|
|
17
17
|
return out.join(" ");
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
export function
|
|
20
|
+
export function applyUITheme(theme: UITheme | undefined): void {
|
|
21
21
|
if (typeof document === "undefined") return;
|
|
22
22
|
|
|
23
23
|
document.getElementById(STYLE_ID)?.remove();
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
format?: any;
|
|
17
17
|
messages?: any[];
|
|
18
18
|
variant?: ButtonProps["variant"];
|
|
19
|
+
size?: ButtonProps["size"];
|
|
19
20
|
class?: ButtonProps["class"];
|
|
20
21
|
Icon?: ButtonProps["Icon"];
|
|
21
22
|
children?: ButtonProps["children"];
|
|
@@ -28,6 +29,7 @@
|
|
|
28
29
|
description,
|
|
29
30
|
placeholder = "write prompt description",
|
|
30
31
|
variant = "default",
|
|
32
|
+
size,
|
|
31
33
|
Icon = Brain,
|
|
32
34
|
onApiResponseComplete,
|
|
33
35
|
messages,
|
|
@@ -98,7 +100,7 @@
|
|
|
98
100
|
{#if ctx.meta.extensions.llm && ctx.meta.collections.llm_chat}
|
|
99
101
|
<Popover.Root bind:open={popoverOpen}>
|
|
100
102
|
<Popover.Trigger>
|
|
101
|
-
<Button {variant} class={props.class}>
|
|
103
|
+
<Button {variant} {size} class={props.class}>
|
|
102
104
|
{#if loading}
|
|
103
105
|
<LoaderIcon class="animate-spin" />
|
|
104
106
|
{:else}
|
|
@@ -129,7 +131,7 @@
|
|
|
129
131
|
<Button
|
|
130
132
|
type="submit"
|
|
131
133
|
Icon={Send}
|
|
132
|
-
|
|
134
|
+
size="sm">Submit</Button
|
|
133
135
|
>
|
|
134
136
|
</form>
|
|
135
137
|
</Popover.Content>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
import { createLobb } from "../store.svelte";
|
|
6
6
|
import { setStudioContext } from "../context";
|
|
7
7
|
import { LoaderCircle, ServerOff } from "lucide-svelte";
|
|
8
|
-
import
|
|
8
|
+
import MainNav from "./mainNav.svelte";
|
|
9
9
|
import * as Tooltip from "./ui/tooltip";
|
|
10
10
|
import { page } from "$app/state";
|
|
11
11
|
import { afterNavigate } from "$app/navigation";
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
} from "../extensions/extensionUtils";
|
|
18
18
|
import extensionMap from 'virtual:lobb-studio-extensions';
|
|
19
19
|
import { mediaQueries } from "../utils";
|
|
20
|
-
import {
|
|
20
|
+
import { applyUITheme } from "../applyUITheme";
|
|
21
21
|
import Home from "./routes/home.svelte";
|
|
22
22
|
import DataModel from "./routes/data_model/dataModel.svelte";
|
|
23
23
|
import Collections from "./routes/collections/collections.svelte";
|
|
@@ -44,6 +44,12 @@
|
|
|
44
44
|
|
|
45
45
|
let status: "loading" | "error" | "ready" = $state("loading");
|
|
46
46
|
let isSmallScreen = $derived(!mediaQueries.sm.current);
|
|
47
|
+
// Horizontal nav forces the layout to row mode (top bar instead of
|
|
48
|
+
// left rail). Falls back to vertical when small-screen mode is on,
|
|
49
|
+
// since there's no useful horizontal layout below 640px.
|
|
50
|
+
const horizontalNav = $derived(
|
|
51
|
+
(ctx.meta as any)?.ui?.horizontalNav === true && !isSmallScreen,
|
|
52
|
+
);
|
|
47
53
|
|
|
48
54
|
onMount(async () => {
|
|
49
55
|
// Remove the static loading screen defined in app.html — it shows instantly
|
|
@@ -51,7 +57,7 @@
|
|
|
51
57
|
document.getElementById("app-loading")?.remove();
|
|
52
58
|
try {
|
|
53
59
|
ctx.meta = await lobb.getMeta();
|
|
54
|
-
|
|
60
|
+
applyUITheme(ctx.meta.ui?.theme);
|
|
55
61
|
ctx.extensions = await loadExtensions(lobb, ctx, extensionMap);
|
|
56
62
|
await executeExtensionsOnStartup(lobb, ctx);
|
|
57
63
|
loadExtensionWorkflows(ctx as any);
|
|
@@ -104,11 +110,13 @@
|
|
|
104
110
|
{:else}
|
|
105
111
|
<Tooltip.Provider delayDuration={0} disableHoverableContent={true}>
|
|
106
112
|
<main
|
|
107
|
-
class="bg-muted h-screen w-screen"
|
|
108
|
-
style=
|
|
113
|
+
class="bg-muted h-screen w-screen overflow-hidden"
|
|
114
|
+
style={horizontalNav
|
|
115
|
+
? "display: grid; grid-template-rows: 3rem 1fr;"
|
|
116
|
+
: `display: grid; grid-template-columns: ${isSmallScreen ? '1fr' : '3.5rem 1fr'};`}
|
|
109
117
|
>
|
|
110
|
-
<
|
|
111
|
-
<div class="min-h-0 h-
|
|
118
|
+
<MainNav orientation={horizontalNav ? "horizontal" : "vertical"} />
|
|
119
|
+
<div class="min-h-0 h-full overflow-hidden">
|
|
112
120
|
{#if page.url.pathname.replace(/\/$/, "") === "/studio"}
|
|
113
121
|
<Home />
|
|
114
122
|
{:else if page.url.pathname.startsWith("/studio/collections")}
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
});
|
|
133
133
|
</script>
|
|
134
134
|
|
|
135
|
-
<div class={cn('resize-y rounded-md border bg-muted
|
|
135
|
+
<div class={cn('resize-y rounded-md border bg-muted h-60', className)}>
|
|
136
136
|
<div bind:this={editorContainer} class="h-full w-full pl-2" />
|
|
137
137
|
</div>
|
|
138
138
|
|
|
@@ -90,14 +90,14 @@
|
|
|
90
90
|
<Button
|
|
91
91
|
variant="outline"
|
|
92
92
|
onclick={() => hideDrawer()}
|
|
93
|
-
|
|
93
|
+
size="sm"
|
|
94
94
|
Icon={X}
|
|
95
95
|
>
|
|
96
96
|
Cancel
|
|
97
97
|
</Button>
|
|
98
98
|
<Button
|
|
99
99
|
variant="default"
|
|
100
|
-
|
|
100
|
+
size="sm"
|
|
101
101
|
Icon={Plus}
|
|
102
102
|
onclick={handleCreateMany}
|
|
103
103
|
>
|
|
@@ -279,7 +279,7 @@
|
|
|
279
279
|
|
|
280
280
|
<div
|
|
281
281
|
bind:clientWidth={dataTableContainerWidth}
|
|
282
|
-
class="flex flex-col overflow-auto h-full w-full"
|
|
282
|
+
class="flex flex-col overflow-auto h-full w-full bg-card"
|
|
283
283
|
>
|
|
284
284
|
{#snippet rowActionsSnippet(entry: Record<string, any>)}
|
|
285
285
|
<ExtensionsComponents
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
</script>
|
|
45
45
|
|
|
46
46
|
{#if tabs}
|
|
47
|
-
<div class="flex items-center gap-1 px-3 py-1.5 border-b shrink-0 bg-
|
|
47
|
+
<div class="flex items-center gap-1 px-3 py-1.5 border-b shrink-0 bg-card">
|
|
48
48
|
{#each tabs as tab}
|
|
49
49
|
{@const key = tab.id ?? tab.label}
|
|
50
50
|
{@const isActive = activeTab ? activeTab === key : (tab.default ?? tabs[0] === tab)}
|
|
@@ -71,7 +71,8 @@
|
|
|
71
71
|
<Popover.Trigger
|
|
72
72
|
class={buttonVariants({
|
|
73
73
|
variant: "ghost",
|
|
74
|
-
|
|
74
|
+
size: "sm",
|
|
75
|
+
class: "text-muted-foreground",
|
|
75
76
|
})}
|
|
76
77
|
>
|
|
77
78
|
<Plus />
|
|
@@ -184,7 +185,7 @@
|
|
|
184
185
|
<Popover.Trigger
|
|
185
186
|
class={buttonVariants({
|
|
186
187
|
variant: "ghost",
|
|
187
|
-
|
|
188
|
+
size: "sm",
|
|
188
189
|
})}
|
|
189
190
|
>
|
|
190
191
|
<Plus />
|