@lobb-js/studio 0.1.31

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 (208) hide show
  1. package/.env.example +1 -0
  2. package/.storybook/main.ts +31 -0
  3. package/.storybook/preview.ts +21 -0
  4. package/.storybook/vitest.setup.ts +7 -0
  5. package/README.md +47 -0
  6. package/components.json +16 -0
  7. package/docker-entrypoint.sh +7 -0
  8. package/dockerfile +27 -0
  9. package/index.html +13 -0
  10. package/package.json +77 -0
  11. package/public/lobb.svg +15 -0
  12. package/src/Studio.svelte +150 -0
  13. package/src/app.css +121 -0
  14. package/src/components-export.ts +21 -0
  15. package/src/extensions/extension.types.ts +93 -0
  16. package/src/extensions/extensionUtils.ts +192 -0
  17. package/src/lib/Lobb.ts +241 -0
  18. package/src/lib/components/LlmButton.svelte +136 -0
  19. package/src/lib/components/alertView.svelte +20 -0
  20. package/src/lib/components/breadCrumbs.svelte +60 -0
  21. package/src/lib/components/combobox.svelte +92 -0
  22. package/src/lib/components/confirmationDialog/confirmationDialog.svelte +33 -0
  23. package/src/lib/components/confirmationDialog/store.svelte.ts +28 -0
  24. package/src/lib/components/createManyButton.svelte +107 -0
  25. package/src/lib/components/dataTable/childRecords.svelte +140 -0
  26. package/src/lib/components/dataTable/dataTable.svelte +223 -0
  27. package/src/lib/components/dataTable/fieldCell.svelte +74 -0
  28. package/src/lib/components/dataTable/filter.svelte +282 -0
  29. package/src/lib/components/dataTable/filterButton.svelte +39 -0
  30. package/src/lib/components/dataTable/footer.svelte +84 -0
  31. package/src/lib/components/dataTable/header.svelte +154 -0
  32. package/src/lib/components/dataTable/sort.svelte +171 -0
  33. package/src/lib/components/dataTable/sortButton.svelte +36 -0
  34. package/src/lib/components/dataTable/table.svelte +337 -0
  35. package/src/lib/components/dataTable/utils.ts +127 -0
  36. package/src/lib/components/detailView/create/children.svelte +68 -0
  37. package/src/lib/components/detailView/create/createDetailView.svelte +226 -0
  38. package/src/lib/components/detailView/create/createDetailViewButton.svelte +32 -0
  39. package/src/lib/components/detailView/create/createManyView.svelte +250 -0
  40. package/src/lib/components/detailView/create/subRecords.svelte +48 -0
  41. package/src/lib/components/detailView/detailViewForm.svelte +104 -0
  42. package/src/lib/components/detailView/fieldCustomInput.svelte +23 -0
  43. package/src/lib/components/detailView/fieldInput.svelte +287 -0
  44. package/src/lib/components/detailView/fieldInputReplacement.svelte +199 -0
  45. package/src/lib/components/detailView/store.svelte.ts +61 -0
  46. package/src/lib/components/detailView/update/children.svelte +94 -0
  47. package/src/lib/components/detailView/update/updateDetailView.svelte +175 -0
  48. package/src/lib/components/detailView/update/updateDetailViewButton.svelte +32 -0
  49. package/src/lib/components/detailView/utils.ts +177 -0
  50. package/src/lib/components/diffViewer.svelte +102 -0
  51. package/src/lib/components/drawer.svelte +28 -0
  52. package/src/lib/components/extensionsComponents.svelte +31 -0
  53. package/src/lib/components/foreingKeyInput.svelte +80 -0
  54. package/src/lib/components/header.svelte +45 -0
  55. package/src/lib/components/loadingTypesForMonacoEditor.ts +36 -0
  56. package/src/lib/components/miniSidebar.svelte +238 -0
  57. package/src/lib/components/monacoEditor.svelte +181 -0
  58. package/src/lib/components/rangeCalendarButton.svelte +257 -0
  59. package/src/lib/components/selectRecord.svelte +126 -0
  60. package/src/lib/components/setServerPage.svelte +48 -0
  61. package/src/lib/components/sidebar/index.ts +4 -0
  62. package/src/lib/components/sidebar/sidebar.svelte +149 -0
  63. package/src/lib/components/sidebar/sidebarElements.svelte +144 -0
  64. package/src/lib/components/sidebar/sidebarTrigger.svelte +33 -0
  65. package/src/lib/components/singletone.svelte +69 -0
  66. package/src/lib/components/ui/accordion/accordion-content.svelte +22 -0
  67. package/src/lib/components/ui/accordion/accordion-item.svelte +12 -0
  68. package/src/lib/components/ui/accordion/accordion-trigger.svelte +31 -0
  69. package/src/lib/components/ui/accordion/index.ts +17 -0
  70. package/src/lib/components/ui/alert/alert-description.svelte +16 -0
  71. package/src/lib/components/ui/alert/alert-title.svelte +24 -0
  72. package/src/lib/components/ui/alert/alert.svelte +39 -0
  73. package/src/lib/components/ui/alert/index.ts +14 -0
  74. package/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +13 -0
  75. package/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +17 -0
  76. package/src/lib/components/ui/alert-dialog/alert-dialog-content.svelte +26 -0
  77. package/src/lib/components/ui/alert-dialog/alert-dialog-description.svelte +16 -0
  78. package/src/lib/components/ui/alert-dialog/alert-dialog-footer.svelte +20 -0
  79. package/src/lib/components/ui/alert-dialog/alert-dialog-header.svelte +20 -0
  80. package/src/lib/components/ui/alert-dialog/alert-dialog-overlay.svelte +19 -0
  81. package/src/lib/components/ui/alert-dialog/alert-dialog-title.svelte +18 -0
  82. package/src/lib/components/ui/alert-dialog/index.ts +40 -0
  83. package/src/lib/components/ui/breadcrumb/breadcrumb-ellipsis.svelte +23 -0
  84. package/src/lib/components/ui/breadcrumb/breadcrumb-item.svelte +16 -0
  85. package/src/lib/components/ui/breadcrumb/breadcrumb-link.svelte +31 -0
  86. package/src/lib/components/ui/breadcrumb/breadcrumb-list.svelte +23 -0
  87. package/src/lib/components/ui/breadcrumb/breadcrumb-page.svelte +23 -0
  88. package/src/lib/components/ui/breadcrumb/breadcrumb-separator.svelte +27 -0
  89. package/src/lib/components/ui/breadcrumb/breadcrumb.svelte +15 -0
  90. package/src/lib/components/ui/breadcrumb/index.ts +25 -0
  91. package/src/lib/components/ui/button/button.svelte +110 -0
  92. package/src/lib/components/ui/button/index.ts +17 -0
  93. package/src/lib/components/ui/checkbox/checkbox.svelte +35 -0
  94. package/src/lib/components/ui/checkbox/index.ts +6 -0
  95. package/src/lib/components/ui/command/command-dialog.svelte +35 -0
  96. package/src/lib/components/ui/command/command-empty.svelte +12 -0
  97. package/src/lib/components/ui/command/command-group.svelte +31 -0
  98. package/src/lib/components/ui/command/command-input.svelte +25 -0
  99. package/src/lib/components/ui/command/command-item.svelte +19 -0
  100. package/src/lib/components/ui/command/command-link-item.svelte +19 -0
  101. package/src/lib/components/ui/command/command-list.svelte +16 -0
  102. package/src/lib/components/ui/command/command-separator.svelte +12 -0
  103. package/src/lib/components/ui/command/command-shortcut.svelte +20 -0
  104. package/src/lib/components/ui/command/command.svelte +21 -0
  105. package/src/lib/components/ui/command/index.ts +40 -0
  106. package/src/lib/components/ui/dialog/dialog-content.svelte +38 -0
  107. package/src/lib/components/ui/dialog/dialog-description.svelte +16 -0
  108. package/src/lib/components/ui/dialog/dialog-footer.svelte +20 -0
  109. package/src/lib/components/ui/dialog/dialog-header.svelte +20 -0
  110. package/src/lib/components/ui/dialog/dialog-overlay.svelte +19 -0
  111. package/src/lib/components/ui/dialog/dialog-title.svelte +16 -0
  112. package/src/lib/components/ui/dialog/index.ts +37 -0
  113. package/src/lib/components/ui/input/index.ts +7 -0
  114. package/src/lib/components/ui/input/input.svelte +46 -0
  115. package/src/lib/components/ui/label/index.ts +7 -0
  116. package/src/lib/components/ui/label/label.svelte +19 -0
  117. package/src/lib/components/ui/popover/index.ts +17 -0
  118. package/src/lib/components/ui/popover/popover-content.svelte +28 -0
  119. package/src/lib/components/ui/range-calendar/index.ts +30 -0
  120. package/src/lib/components/ui/range-calendar/range-calendar-cell.svelte +19 -0
  121. package/src/lib/components/ui/range-calendar/range-calendar-day.svelte +35 -0
  122. package/src/lib/components/ui/range-calendar/range-calendar-grid-body.svelte +12 -0
  123. package/src/lib/components/ui/range-calendar/range-calendar-grid-head.svelte +12 -0
  124. package/src/lib/components/ui/range-calendar/range-calendar-grid-row.svelte +12 -0
  125. package/src/lib/components/ui/range-calendar/range-calendar-grid.svelte +16 -0
  126. package/src/lib/components/ui/range-calendar/range-calendar-head-cell.svelte +16 -0
  127. package/src/lib/components/ui/range-calendar/range-calendar-header.svelte +16 -0
  128. package/src/lib/components/ui/range-calendar/range-calendar-heading.svelte +16 -0
  129. package/src/lib/components/ui/range-calendar/range-calendar-months.svelte +20 -0
  130. package/src/lib/components/ui/range-calendar/range-calendar-next-button.svelte +27 -0
  131. package/src/lib/components/ui/range-calendar/range-calendar-prev-button.svelte +27 -0
  132. package/src/lib/components/ui/range-calendar/range-calendar.svelte +57 -0
  133. package/src/lib/components/ui/select/index.ts +34 -0
  134. package/src/lib/components/ui/select/select-content.svelte +38 -0
  135. package/src/lib/components/ui/select/select-group-heading.svelte +16 -0
  136. package/src/lib/components/ui/select/select-item.svelte +37 -0
  137. package/src/lib/components/ui/select/select-scroll-down-button.svelte +19 -0
  138. package/src/lib/components/ui/select/select-scroll-up-button.svelte +19 -0
  139. package/src/lib/components/ui/select/select-separator.svelte +13 -0
  140. package/src/lib/components/ui/select/select-trigger.svelte +24 -0
  141. package/src/lib/components/ui/separator/index.ts +7 -0
  142. package/src/lib/components/ui/separator/separator.svelte +22 -0
  143. package/src/lib/components/ui/skeleton/index.ts +7 -0
  144. package/src/lib/components/ui/skeleton/skeleton.svelte +22 -0
  145. package/src/lib/components/ui/sonner/index.ts +1 -0
  146. package/src/lib/components/ui/sonner/sonner.svelte +20 -0
  147. package/src/lib/components/ui/switch/index.ts +7 -0
  148. package/src/lib/components/ui/switch/switch.svelte +27 -0
  149. package/src/lib/components/ui/textarea/index.ts +7 -0
  150. package/src/lib/components/ui/textarea/textarea.svelte +22 -0
  151. package/src/lib/components/ui/tooltip/index.ts +18 -0
  152. package/src/lib/components/ui/tooltip/tooltip-content.svelte +21 -0
  153. package/src/lib/components/workflowEditor.svelte +187 -0
  154. package/src/lib/eventSystem.ts +38 -0
  155. package/src/lib/index.ts +40 -0
  156. package/src/lib/store.svelte.ts +21 -0
  157. package/src/lib/store.types.ts +28 -0
  158. package/src/lib/utils.ts +84 -0
  159. package/src/main.ts +18 -0
  160. package/src/routes/collections/collection.svelte +46 -0
  161. package/src/routes/collections/collections.svelte +43 -0
  162. package/src/routes/data_model/dataModel.svelte +40 -0
  163. package/src/routes/data_model/flow.css +22 -0
  164. package/src/routes/data_model/flow.svelte +82 -0
  165. package/src/routes/data_model/syncManager.svelte +93 -0
  166. package/src/routes/data_model/utils.ts +35 -0
  167. package/src/routes/extensions/extension.svelte +16 -0
  168. package/src/routes/home.svelte +36 -0
  169. package/src/routes/workflows/workflows.svelte +135 -0
  170. package/src/stories/Configure.mdx +364 -0
  171. package/src/stories/assets/accessibility.png +0 -0
  172. package/src/stories/assets/accessibility.svg +1 -0
  173. package/src/stories/assets/addon-library.png +0 -0
  174. package/src/stories/assets/assets.png +0 -0
  175. package/src/stories/assets/avif-test-image.avif +0 -0
  176. package/src/stories/assets/context.png +0 -0
  177. package/src/stories/assets/discord.svg +1 -0
  178. package/src/stories/assets/docs.png +0 -0
  179. package/src/stories/assets/figma-plugin.png +0 -0
  180. package/src/stories/assets/github.svg +1 -0
  181. package/src/stories/assets/share.png +0 -0
  182. package/src/stories/assets/styling.png +0 -0
  183. package/src/stories/assets/testing.png +0 -0
  184. package/src/stories/assets/theming.png +0 -0
  185. package/src/stories/assets/tutorials.svg +1 -0
  186. package/src/stories/assets/youtube.svg +1 -0
  187. package/src/stories/detailView/detailViewForm.stories.svelte +79 -0
  188. package/src/stories/examples/Button.stories.svelte +31 -0
  189. package/src/stories/examples/Button.svelte +30 -0
  190. package/src/stories/examples/Header.stories.svelte +26 -0
  191. package/src/stories/examples/Header.svelte +45 -0
  192. package/src/stories/examples/Page.stories.svelte +29 -0
  193. package/src/stories/examples/Page.svelte +70 -0
  194. package/src/stories/examples/button.css +30 -0
  195. package/src/stories/examples/header.css +32 -0
  196. package/src/stories/examples/page.css +68 -0
  197. package/src/vite-env.d.ts +2 -0
  198. package/svelte.config.js +7 -0
  199. package/todo.md +24 -0
  200. package/tsconfig.app.json +25 -0
  201. package/tsconfig.json +14 -0
  202. package/tsconfig.node.json +24 -0
  203. package/vite-plugin-contextual-lib.js +66 -0
  204. package/vite.build.svelte.config.ts +18 -0
  205. package/vite.config.ts +84 -0
  206. package/vite.extension.config.ts +81 -0
  207. package/vite_utils.ts +28 -0
  208. package/vitest.shims.d.ts +1 -0
@@ -0,0 +1,257 @@
1
+ <script lang="ts">
2
+ import CalendarIcon from "@lucide/svelte/icons/calendar";
3
+ import type { DateRange } from "bits-ui";
4
+ import {
5
+ CalendarDate,
6
+ DateFormatter,
7
+ type DateValue,
8
+ getLocalTimeZone,
9
+ parseDate,
10
+ startOfWeek,
11
+ today,
12
+ } from "@internationalized/date";
13
+ import { cn } from "$lib/utils.js";
14
+ import { buttonVariants } from "$lib/components/ui/button/index.js";
15
+ import { RangeCalendar } from "$lib/components/ui/range-calendar/index.js";
16
+ import * as Popover from "$lib/components/ui/popover/index.js";
17
+ import Input from "./ui/input/input.svelte";
18
+
19
+ interface Props {
20
+ value: DateRange;
21
+ }
22
+
23
+ let { value = $bindable() }: Props = $props();
24
+
25
+ const df = new DateFormatter(navigator.language, {
26
+ dateStyle: "medium",
27
+ });
28
+
29
+ let startValue: DateValue | undefined = $state(undefined);
30
+ </script>
31
+
32
+ <div class="grid gap-2">
33
+ <Popover.Root>
34
+ <Popover.Trigger
35
+ class={cn(
36
+ buttonVariants({ variant: "outline" }),
37
+ !value && "text-muted-foreground",
38
+ "h-7 px-3 text-xs font-normal",
39
+ )}
40
+ >
41
+ <CalendarIcon class="mr-2 size-4" />
42
+ {#if value && value.start}
43
+ {#if value.end}
44
+ {df.format(value.start.toDate(getLocalTimeZone()))} - {df.format(
45
+ value.end.toDate(getLocalTimeZone()),
46
+ )}
47
+ {:else}
48
+ {df.format(value.start.toDate(getLocalTimeZone()))}
49
+ {/if}
50
+ {:else if startValue}
51
+ {df.format(startValue.toDate(getLocalTimeZone()))}
52
+ {:else}
53
+ Pick a date
54
+ {/if}
55
+ </Popover.Trigger>
56
+ <Popover.Content class="flex w-auto p-0" align="start">
57
+ <div class="flex flex-col border-r">
58
+ <div
59
+ class="flex flex-col overflow-hidden text-muted-foreground"
60
+ >
61
+ <button
62
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
63
+ onclick={() => {
64
+ const currentDate = today(getLocalTimeZone());
65
+ value = {
66
+ start: currentDate,
67
+ end: currentDate,
68
+ };
69
+ }}
70
+ >
71
+ Today
72
+ </button>
73
+ <button
74
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
75
+ onclick={() => {
76
+ const currentDate = today(getLocalTimeZone());
77
+ value = {
78
+ start: currentDate.subtract({ days: 1 }),
79
+ end: currentDate.subtract({ days: 1 }),
80
+ };
81
+ }}
82
+ >
83
+ Yesterday
84
+ </button>
85
+ <button
86
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
87
+ onclick={() => {
88
+ const currentDate = today(getLocalTimeZone());
89
+ const weekStart = startOfWeek(currentDate, "en-US");
90
+ value = {
91
+ start: weekStart,
92
+ end: currentDate,
93
+ };
94
+ }}
95
+ >
96
+ This week (Sun - Today)
97
+ </button>
98
+ <button
99
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
100
+ onclick={() => {
101
+ const currentDate = today(getLocalTimeZone());
102
+ const thisWeekStart = startOfWeek(
103
+ currentDate,
104
+ "en-US",
105
+ );
106
+ const lastWeekEnd = thisWeekStart.subtract({
107
+ days: 1,
108
+ });
109
+ const lastWeekStart = startOfWeek(
110
+ lastWeekEnd,
111
+ "en-US",
112
+ );
113
+ value = {
114
+ start: lastWeekStart,
115
+ end: lastWeekEnd,
116
+ };
117
+ }}
118
+ >
119
+ Last week (Sun - Sat)
120
+ </button>
121
+ <button
122
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
123
+ onclick={() => {
124
+ const currentDate = today(getLocalTimeZone());
125
+ value = {
126
+ start: currentDate.subtract({ days: 6 }),
127
+ end: currentDate,
128
+ };
129
+ }}
130
+ >
131
+ Last 7 days
132
+ </button>
133
+ <button
134
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
135
+ onclick={() => {
136
+ const currentDate = today(getLocalTimeZone());
137
+ value = {
138
+ start: currentDate.subtract({ days: 29 }),
139
+ end: currentDate,
140
+ };
141
+ }}
142
+ >
143
+ Last 30 days
144
+ </button>
145
+ <button
146
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
147
+ onclick={() => {
148
+ const currentDate = today(getLocalTimeZone());
149
+ value = {
150
+ start: currentDate.subtract({ days: 89 }),
151
+ end: currentDate,
152
+ };
153
+ }}
154
+ >
155
+ Last 90 days
156
+ </button>
157
+ <button
158
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
159
+ onclick={() => {
160
+ const currentDate = today(getLocalTimeZone());
161
+ value = {
162
+ start: currentDate.subtract({ months: 12 }),
163
+ end: currentDate,
164
+ };
165
+ }}
166
+ >
167
+ Last 12 months
168
+ </button>
169
+ <button
170
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
171
+ onclick={() => {
172
+ const currentDate = today(getLocalTimeZone());
173
+ const lastYearStart = currentDate
174
+ .subtract({ years: 1 })
175
+ .set({ month: 1, day: 1 });
176
+ const lastYearEnd = currentDate
177
+ .subtract({ years: 1 })
178
+ .set({ month: 12, day: 31 });
179
+ value = {
180
+ start: lastYearStart,
181
+ end: lastYearEnd,
182
+ };
183
+ }}
184
+ >
185
+ Last Calendar year
186
+ </button>
187
+ <button
188
+ class="text-start text-sm py-2 px-2 hover:bg-soft hover:text-primary"
189
+ onclick={() => {
190
+ const currentDate = today(getLocalTimeZone());
191
+ const yearStart = currentDate.set({
192
+ month: 1,
193
+ day: 1,
194
+ });
195
+ value = {
196
+ start: yearStart,
197
+ end: currentDate,
198
+ };
199
+ }}
200
+ >
201
+ This Year (Jan - Today)
202
+ </button>
203
+ </div>
204
+ </div>
205
+ <div>
206
+ <div class="flex gap-2 p-2 justify-end border-b">
207
+ <!-- Start Date -->
208
+ <Input
209
+ type="date"
210
+ class="w-fit"
211
+ bind:value={
212
+ () => {
213
+ if (!value?.start) return "";
214
+ // Convert CalendarDate → YYYY-MM-DD string
215
+ const jsDate = value.start.toDate("UTC");
216
+ return jsDate.toISOString().split("T")[0];
217
+ },
218
+ (v) => {
219
+ // Convert YYYY-MM-DD string → CalendarDate
220
+ value = {
221
+ ...value,
222
+ start: parseDate(v),
223
+ };
224
+ }
225
+ }
226
+ />
227
+
228
+ <!-- End Date -->
229
+ <Input
230
+ type="date"
231
+ class="w-fit"
232
+ bind:value={
233
+ () => {
234
+ if (!value?.end) return "";
235
+ const jsDate = value.end.toDate("UTC");
236
+ return jsDate.toISOString().split("T")[0];
237
+ },
238
+ (v) => {
239
+ value = {
240
+ ...value,
241
+ end: parseDate(v),
242
+ };
243
+ }
244
+ }
245
+ />
246
+ </div>
247
+ <RangeCalendar
248
+ bind:value
249
+ onStartValueChange={(v) => {
250
+ startValue = v;
251
+ }}
252
+ numberOfMonths={2}
253
+ />
254
+ </div>
255
+ </Popover.Content>
256
+ </Popover.Root>
257
+ </div>
@@ -0,0 +1,126 @@
1
+ <script lang="ts">
2
+ import { ArrowLeft, Link } from "lucide-svelte";
3
+ import Button, { type ButtonProps } from "./ui/button/button.svelte";
4
+ import DataTable from "./dataTable/dataTable.svelte";
5
+ import { getCollectionPrimaryField } from "./dataTable/utils";
6
+ import { emitEvent } from "$lib/eventSystem";
7
+ import Drawer from "./drawer.svelte";
8
+
9
+ interface LocalProps extends ButtonProps {
10
+ collectionName: string;
11
+ parentCollectionName?: string;
12
+ fieldName?: string;
13
+ value?: any;
14
+ onSelect?: (entry: any) => void;
15
+ filter?: Record<string, any>;
16
+ additionalFilter?: Record<string, any>;
17
+ text?: string;
18
+ entry?: Record<string, any>;
19
+ }
20
+
21
+ let {
22
+ parentCollectionName,
23
+ collectionName,
24
+ fieldName,
25
+ value = $bindable(),
26
+ onSelect,
27
+ filter = {},
28
+ additionalFilter = {},
29
+ text,
30
+ entry,
31
+ ...restProps
32
+ }: LocalProps = $props();
33
+
34
+ let openDrawer = $state(false);
35
+
36
+ async function handleButtonClick() {
37
+ try {
38
+ const eventResult = await emitEvent(
39
+ "studio.collections.preForeignKeySelect",
40
+ {
41
+ parentCollectionName,
42
+ collectionName,
43
+ fieldName,
44
+ entry,
45
+ },
46
+ );
47
+ if (eventResult.filter) {
48
+ additionalFilter = eventResult.filter;
49
+ }
50
+
51
+ openDrawer = true;
52
+ } catch (error) {
53
+ console.error(error);
54
+ }
55
+ }
56
+
57
+ async function onSelectHandler(entry: any) {
58
+ const primaryFieldName = getCollectionPrimaryField(collectionName);
59
+ const localValue: any = {
60
+ id: entry.id,
61
+ };
62
+ if (primaryFieldName) {
63
+ const primaryFieldValue = entry[primaryFieldName];
64
+ localValue[primaryFieldName] = primaryFieldValue;
65
+ }
66
+ value = localValue;
67
+
68
+ // calling the onSelect callback function
69
+ if (onSelect) {
70
+ onSelect(entry);
71
+ }
72
+
73
+ // closing the drawer
74
+ openDrawer = false;
75
+ }
76
+ </script>
77
+
78
+ <!-- THE SELECT BUTTON -->
79
+ <Button onclick={handleButtonClick} {...restProps}>
80
+ {#if restProps.children}
81
+ {@render restProps.children()}
82
+ {:else}
83
+ <Link size="13" />
84
+ {#if text}
85
+ {text}
86
+ {:else}
87
+ Select record
88
+ {/if}
89
+ {/if}
90
+ </Button>
91
+
92
+ <!-- THE SELECT DRAWER -->
93
+ {#if openDrawer}
94
+ <Drawer onHide={async () => { openDrawer = false }}>
95
+ <div class="flex h-12 items-center gap-4 border-b px-4">
96
+ <Button
97
+ variant="outline"
98
+ onclick={() => (openDrawer = false)}
99
+ class=" h-8 w-8 rounded-full text-xs font-normal"
100
+ Icon={ArrowLeft}
101
+ ></Button>
102
+ <div class="flex items-center gap-2">
103
+ <div class="text-sm">Select record from</div>
104
+ <span
105
+ class="rounded-md border bg-muted px-2 py-0.5 text-sm"
106
+ >
107
+ {collectionName}
108
+ </span>
109
+ </div>
110
+ </div>
111
+ <div class="flex-1 overflow-y-auto bg-muted">
112
+ <DataTable
113
+ {collectionName}
114
+ tableProps={{
115
+ showCheckboxes: false,
116
+ select: {
117
+ onSelect: onSelectHandler,
118
+ },
119
+ }}
120
+ filter={{
121
+ $and: [filter, additionalFilter],
122
+ }}
123
+ />
124
+ </div>
125
+ </Drawer>
126
+ {/if}
@@ -0,0 +1,48 @@
1
+ <script lang="ts">
2
+ import { toast } from "svelte-sonner";
3
+ import Button from "./ui/button/button.svelte";
4
+ import { ctx } from "$lib/store.svelte";
5
+ import { Input } from "$lib/components/ui/input";
6
+
7
+ let formData = {
8
+ server: "",
9
+ };
10
+
11
+ async function handleClick(e: Event) {
12
+ if (!formData.server) {
13
+ toast.error("Please fill the server url");
14
+ return;
15
+ }
16
+ try {
17
+ await fetch(formData.server);
18
+ } catch (error) {
19
+ toast.error(`Couldn't connect to the (${formData.server}) server`);
20
+ return;
21
+ }
22
+ localStorage.setItem("lobb_url", formData.server);
23
+ ctx.lobbUrl = formData.server;
24
+ }
25
+ </script>
26
+
27
+ <div
28
+ class="fixed left-0 top-0 flex h-screen w-screen items-center justify-center bg-muted"
29
+ >
30
+ <div class="flex w-full max-w-100 flex-col gap-6 p-6">
31
+ <div>
32
+ <div class="text-4xl">Welcome back</div>
33
+ <div>Sign in to your account</div>
34
+ </div>
35
+ <div class="flex flex-col gap-6 rounded-md border bg-white p-6">
36
+ <div class="flex flex-col gap-2">
37
+ <div>
38
+ <div class="mb-1 text-sm font-medium">Server</div>
39
+ <Input
40
+ bind:value={formData.server}
41
+ placeholder="http://example.lobb.com"
42
+ />
43
+ </div>
44
+ </div>
45
+ <Button onclick={handleClick}>Save & Connect</Button>
46
+ </div>
47
+ </div>
48
+ </div>
@@ -0,0 +1,4 @@
1
+ import Sidebar from "./sidebar.svelte";
2
+ import SidebarTrigger from "./sidebarTrigger.svelte";
3
+
4
+ export { Sidebar, SidebarTrigger }
@@ -0,0 +1,149 @@
1
+ <script lang="ts" module>
2
+ export interface SidebarProperties {
3
+ collapsed: boolean;
4
+ }
5
+ </script>
6
+
7
+ <script lang="ts">
8
+ import { setContext, type Snippet } from "svelte";
9
+
10
+ import { mediaQueries } from "$lib/utils";
11
+ import Skeleton from "../ui/skeleton/skeleton.svelte";
12
+ import { Search } from "lucide-svelte";
13
+ import SidebarElements, {
14
+ type SideBarData,
15
+ type SideBarElement,
16
+ type SidebarElementsProps,
17
+ } from "./sidebarElements.svelte";
18
+
19
+ interface Props {
20
+ title: string;
21
+ data: SideBarData | null;
22
+ sidebarElementsProps?: Partial<SidebarElementsProps>;
23
+ showSearch?: boolean;
24
+ children: Snippet<[]>;
25
+ belowSearch?: Snippet;
26
+ elementRightSide?: Snippet<[SideBarElement]>;
27
+ }
28
+
29
+ let {
30
+ title,
31
+ data,
32
+ sidebarElementsProps,
33
+ showSearch = true,
34
+ children,
35
+ belowSearch,
36
+ elementRightSide,
37
+ }: Props = $props();
38
+
39
+ let visibleData = $derived(data ? [...data] : null);
40
+ const sidebarProperties: SidebarProperties = $state({
41
+ collapsed: false,
42
+ });
43
+ setContext("sidebarProperties", sidebarProperties);
44
+
45
+ $effect(() => {
46
+ if (mediaQueries.lg.current) {
47
+ sidebarProperties.collapsed = false;
48
+ } else {
49
+ sidebarProperties.collapsed = true;
50
+ }
51
+ });
52
+
53
+ let searchTerm = $state("");
54
+
55
+ const sidebarWidth = 275;
56
+ let sidebarContainerHeight = $state(0);
57
+ let sidebarContainerWidth = $state(0);
58
+ let sidebarHeaderHeight = $state(0);
59
+ let sidebarBodyHeight = $derived(
60
+ sidebarContainerHeight - sidebarHeaderHeight,
61
+ );
62
+
63
+ function handleSearch() {
64
+ if (data) {
65
+ visibleData = filterSidebarData(data, searchTerm.toLowerCase());
66
+ }
67
+ }
68
+
69
+ function filterSidebarData(items: SideBarData, term: string): SideBarData {
70
+ return items.filter((item) => item.name.includes(term));
71
+ }
72
+ </script>
73
+
74
+ <div
75
+ class="flex h-full transition-[grid-template-columns]"
76
+ style="
77
+ display: grid;
78
+ grid-template-columns: {sidebarProperties.collapsed ? 0 : sidebarWidth}px 1fr;
79
+ "
80
+ bind:clientHeight={sidebarContainerHeight}
81
+ bind:clientWidth={sidebarContainerWidth}
82
+ >
83
+ <div
84
+ class="
85
+ bg-background border-r overflow-hidden
86
+ "
87
+ style="
88
+ {sidebarProperties.collapsed ? 'border-right-width: 0px; padding: 0px;' : ''}
89
+ height: {sidebarContainerHeight}px;
90
+ "
91
+ >
92
+ {#if visibleData !== null}
93
+ <div bind:clientHeight={sidebarHeaderHeight} class="p-2 pb-0!">
94
+ <div
95
+ class="relative flex justify-between items-center p-2 font-medium"
96
+ >
97
+ {title}
98
+ </div>
99
+ {#if showSearch}
100
+ <div class="p-2">
101
+ <div
102
+ class="flex items-center px-4 py-1 text-muted-foreground bg-soft border rounded-md"
103
+ >
104
+ <input
105
+ type="text"
106
+ class="w-full bg-transparent text-sm focus:outline-none"
107
+ oninput={handleSearch}
108
+ bind:value={searchTerm}
109
+ placeholder="Search"
110
+ />
111
+ <Search size="20" />
112
+ </div>
113
+ </div>
114
+ {/if}
115
+ </div>
116
+ <div
117
+ class="
118
+ text-primary p-2 overflow-y-auto overflow-x-clip
119
+ "
120
+ style="max-height: {sidebarBodyHeight}px;"
121
+ >
122
+ {@render belowSearch?.()}
123
+ {#key visibleData}
124
+ <SidebarElements
125
+ bind:data={visibleData}
126
+ {elementRightSide}
127
+ {...sidebarElementsProps}
128
+ />
129
+ {/key}
130
+ </div>
131
+ {:else}
132
+ <div class="flex flex-col gap-2 p-2">
133
+ <Skeleton class="h-6 w-full" />
134
+ <Skeleton class="h-6 w-full" />
135
+ <Skeleton class="h-6 w-full" />
136
+ <Skeleton class="h-6 w-full" />
137
+ <Skeleton class="h-6 w-full" />
138
+ </div>
139
+ {/if}
140
+ </div>
141
+ <div
142
+ class="overflow-auto h-full"
143
+ style="
144
+ max-height: {sidebarContainerHeight}px;
145
+ "
146
+ >
147
+ {@render children()}
148
+ </div>
149
+ </div>