@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,80 @@
1
+ <script lang="ts">
2
+ import Input from "./ui/input/input.svelte";
3
+ import SelectRecord from "./selectRecord.svelte";
4
+ import UpdateDetailViewButton from "./detailView/update/updateDetailViewButton.svelte";
5
+ import { ExternalLink } from "lucide-svelte";
6
+
7
+ interface LocalProps {
8
+ parentCollectionName: string;
9
+ collectionName: string;
10
+ fieldName: string;
11
+ value?: any;
12
+ destructive?: boolean;
13
+ entry: Record<string, any>;
14
+ }
15
+
16
+ let {
17
+ parentCollectionName,
18
+ collectionName,
19
+ fieldName,
20
+ value = $bindable(),
21
+ destructive,
22
+ entry,
23
+ }: LocalProps = $props();
24
+
25
+ const idIsZero = $derived(value?.id === 0);
26
+ const refrenceId = $derived(value ? value.id : null);
27
+ const primaryField = $derived(value ? Object.values(value)[1] : null);
28
+ </script>
29
+
30
+ <!-- THE SELECT BUTTON -->
31
+ {#if !idIsZero}
32
+ <div class="relative">
33
+ <div
34
+ class="flex gap-2 absolute right-0 top-0 mr-9 h-full items-center text-xs"
35
+ >
36
+ {#if value !== null}
37
+ <UpdateDetailViewButton
38
+ collectionName={collectionName}
39
+ recordId={value.id}
40
+ variant="ghost"
41
+ class="h-5 w-5 px-0 py-0 text-muted-foreground hover:bg-transparent"
42
+ Icon={ExternalLink}
43
+ ></UpdateDetailViewButton>
44
+ {/if}
45
+ {#if primaryField}
46
+ <div
47
+ class="flex items-center bg-background rounded-full border h-6 px-3 shadow-sm"
48
+ >
49
+ {primaryField}
50
+ </div>
51
+ {/if}
52
+ <SelectRecord
53
+ class="h-6 px-2 font-normal text-xs"
54
+ variant="outline"
55
+ {parentCollectionName}
56
+ {collectionName}
57
+ {fieldName}
58
+ bind:value
59
+ {entry}
60
+ />
61
+ </div>
62
+ <Input
63
+ placeholder={"NULL"}
64
+ type="number"
65
+ class="
66
+ bg-soft text-xs
67
+ {destructive ? 'border-destructive bg-destructive/10' : ''}
68
+ "
69
+ bind:value={() => refrenceId, (v) => (value.id = v)}
70
+ />
71
+ </div>
72
+ {:else}
73
+ <div class="relative z-10">
74
+ <Input
75
+ placeholder={"PARENT ID"}
76
+ class="bg-soft text-xs"
77
+ disabled={true}
78
+ />
79
+ </div>
80
+ {/if}
@@ -0,0 +1,45 @@
1
+ <script>
2
+ import * as Tooltip from "./ui/tooltip";
3
+ import Button from "./ui/button/button.svelte";
4
+ import { Menu, Moon, Sun } from "lucide-svelte";
5
+ import BreadCrumbs from "./breadCrumbs.svelte";
6
+ import { toggleMode, mode } from "mode-watcher";
7
+ import { mediaQueries } from "$lib/utils";
8
+ import { expandMiniSideBar } from "./miniSidebar.svelte";
9
+
10
+ let isSmallScreen = $derived(!mediaQueries.sm.current);
11
+ </script>
12
+
13
+ <div
14
+ class="flex items-center justify-between border-b border-input bg-background px-3"
15
+ >
16
+ <div class="flex items-center gap-4">
17
+ {#if isSmallScreen}
18
+ <Menu
19
+ class="h-10 text-muted-foreground hover:bg-transparent cursor-pointer hover:text-foreground"
20
+ style="left: 0.6rem; top: 0rem;"
21
+ size="18"
22
+ onclick={() => expandMiniSideBar()}
23
+ />
24
+ {/if}
25
+ <BreadCrumbs />
26
+ </div>
27
+ <div class="flex h-full items-center gap-3">
28
+ <Tooltip.Root>
29
+ <Tooltip.Trigger>
30
+ <Button
31
+ class="h-6 w-6 text-muted-foreground hover:bg-transparent"
32
+ variant="ghost"
33
+ size="icon"
34
+ onclick={toggleMode}
35
+ Icon={$mode === "light" ? Moon : Sun}
36
+ ></Button>
37
+ </Tooltip.Trigger>
38
+ <Tooltip.Content side="bottom" sideOffset={7.5}
39
+ >{$mode === "light"
40
+ ? "Night Mode"
41
+ : "Light Mode"}</Tooltip.Content
42
+ >
43
+ </Tooltip.Root>
44
+ </div>
45
+ </div>
@@ -0,0 +1,36 @@
1
+ /**
2
+ * TODO
3
+ *
4
+ * this file shows an example of downloading the types files of a library from npm to use them in adding type support of that library in the vscode editor
5
+ * so the whole point is that for users to be able to paste a url from npm or jsr of a library and have all ts support from its types
6
+ */
7
+
8
+ import { gunzipSync } from "fflate";
9
+ import { untar } from "@andrewbranch/untar.js";
10
+
11
+ async function extractTgz(buffer: ArrayBuffer) {
12
+ const tarBuffer = gunzipSync(new Uint8Array(buffer));
13
+
14
+ const cleanBuffer = tarBuffer.buffer.slice(
15
+ tarBuffer.byteOffset,
16
+ tarBuffer.byteOffset + tarBuffer.byteLength,
17
+ );
18
+ const files = await untar(cleanBuffer as ArrayBuffer);
19
+
20
+ const dtsFiles = [];
21
+
22
+ for (const file of files) {
23
+ if (file.filename.endsWith(".d.ts")) {
24
+ const content = new TextDecoder().decode(file.fileData);
25
+ dtsFiles.push({ name: file.filename, content });
26
+ }
27
+ }
28
+
29
+ return dtsFiles;
30
+ }
31
+
32
+ const tgzURL = "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz";
33
+ const response = await fetch(tgzURL);
34
+ const arrayBuffer = await response.arrayBuffer();
35
+
36
+ const files = await extractTgz(arrayBuffer);
@@ -0,0 +1,238 @@
1
+ <script lang="ts" module>
2
+ let isSmallScreen = $derived(!mediaQueries.sm.current);
3
+ let isCollapsed = $derived(isSmallScreen);
4
+
5
+ export let collapseMiniSideBar = () => {
6
+ isCollapsed = true;
7
+ };
8
+ export let expandMiniSideBar = () => {
9
+ isCollapsed = false;
10
+ };
11
+ </script>
12
+
13
+ <script lang="ts">
14
+ import { House, Layers, Library, LogOut, Workflow, X } from "lucide-svelte";
15
+ import Button from "$lib/components/ui/button/button.svelte";
16
+ import Separator from "$lib/components/ui/separator/separator.svelte";
17
+ import * as Tooltip from "$lib/components/ui/tooltip";
18
+ import * as Accordion from "$lib/components/ui/accordion/index.js";
19
+
20
+ import { ctx } from "$lib/store.svelte";
21
+ import { getDashboardNavs } from "../../extensions/extensionUtils";
22
+ import { mediaQueries } from "$lib/utils";
23
+ import * as Popover from "./ui/popover";
24
+ import { location } from "@wjfe/n-savant";
25
+
26
+ const sections: any = [
27
+ [
28
+ {
29
+ label: "Home",
30
+ href: "/",
31
+ icon: House,
32
+ },
33
+ {
34
+ label: "Collections",
35
+ href: "/collections",
36
+ icon: Library,
37
+ },
38
+ {
39
+ label: "Data Model",
40
+ href: "/datamodel/graph",
41
+ icon: Layers,
42
+ },
43
+ {
44
+ label: "Workflows",
45
+ href: "/workflows",
46
+ icon: Workflow,
47
+ },
48
+ ],
49
+ [],
50
+ [],
51
+ ];
52
+
53
+ const navs = getDashboardNavs();
54
+
55
+ if (navs.top) {
56
+ sections[0] = [...sections[0], ...navs.top];
57
+ }
58
+ if (navs.middle) {
59
+ sections[1] = [...sections[1], ...navs.middle];
60
+ }
61
+ if (navs.bottom) {
62
+ sections[2] = [...sections[2], ...navs.bottom];
63
+ }
64
+
65
+ // adding the logout server button
66
+ if (!window.APP_ENV.LOBB_URL) {
67
+ sections[2] = [
68
+ ...sections[2],
69
+ {
70
+ label: "Log out of the server",
71
+ onclick: () => {
72
+ localStorage.removeItem("lobb_url");
73
+ ctx.lobbUrl = null;
74
+ },
75
+ icon: LogOut,
76
+ },
77
+ ];
78
+ }
79
+ </script>
80
+
81
+ {#snippet section(section: any)}
82
+ <div class="flex flex-col {isSmallScreen ? 'gap-0' : 'gap-2'}">
83
+ {#each section as item}
84
+ {#if isSmallScreen}
85
+ {#if !item.navs}
86
+ <Button
87
+ onclick={() => {
88
+ if (item.onclick) {
89
+ item.onclick();
90
+ } else {
91
+ location.navigate(item.href);
92
+ }
93
+ isCollapsed = true;
94
+ }}
95
+ class="flex items-center justify-start flex-nowrap text-muted-foreground text-nowrap h-10 w-full"
96
+ variant="ghost"
97
+ size="icon"
98
+ Icon={item.icon}
99
+ >
100
+ {item.label}
101
+ </Button>
102
+ {:else}
103
+ <Accordion.Root type="single">
104
+ <Accordion.Item class="border-b-0">
105
+ <Accordion.Trigger class="justify-between p-0 h-10">
106
+ <div
107
+ class="flex items-center gap-2 text-muted-foreground"
108
+ >
109
+ <item.icon size="18" />
110
+ <div class="text-nowrap">{item.label}</div>
111
+ </div>
112
+ </Accordion.Trigger>
113
+ <Accordion.Content class="pl-2 border-l">
114
+ {#each item.navs as childItem}
115
+ <Button
116
+ onclick={() => {
117
+ if (childItem.onclick) {
118
+ childItem.onclick();
119
+ } else {
120
+ location.navigate(item.href);
121
+ }
122
+ isCollapsed = true;
123
+ }}
124
+ class="flex items-center justify-start flex-nowrap text-muted-foreground text-nowrap h-8 w-full"
125
+ variant="ghost"
126
+ size="icon"
127
+ Icon={childItem.icon}
128
+ >
129
+ {childItem.label}
130
+ </Button>
131
+ {/each}
132
+ </Accordion.Content>
133
+ </Accordion.Item>
134
+ </Accordion.Root>
135
+ {/if}
136
+ {:else}
137
+ <Tooltip.Root>
138
+ <Tooltip.Trigger>
139
+ {#if !item.navs}
140
+ <Button
141
+ onclick={() => {
142
+ if (item.onclick) {
143
+ item.onclick();
144
+ }
145
+ isCollapsed = true;
146
+ }}
147
+ href={item.href}
148
+ class="text-muted-foreground"
149
+ variant="ghost"
150
+ size="icon"
151
+ Icon={item.icon}
152
+ ></Button>
153
+ {:else}
154
+ <Popover.Root>
155
+ <Popover.Trigger>
156
+ <Button
157
+ class="text-muted-foreground"
158
+ variant="ghost"
159
+ size="icon"
160
+ Icon={item.icon}
161
+ ></Button>
162
+ </Popover.Trigger>
163
+ <Popover.Content
164
+ sideOffset={17.5}
165
+ side="right"
166
+ class="popover_content w-60 mb-4 p-0"
167
+ >
168
+ <div class="py-1">
169
+ {#each item.navs as childItem}
170
+ <div
171
+ class="px-1 text-xs text-muted-foreground"
172
+ >
173
+ <Button
174
+ variant="ghost"
175
+ class="flex h-7 w-full justify-start p-2 text-xs font-normal text-muted-foreground"
176
+ Icon={childItem.icon}
177
+ onclick={() => {
178
+ if (childItem.onclick) {
179
+ childItem.onclick();
180
+ }
181
+ }}
182
+ href={childItem.href}
183
+ >
184
+ {childItem.label}
185
+ </Button>
186
+ </div>
187
+ {/each}
188
+ </div>
189
+ </Popover.Content>
190
+ </Popover.Root>
191
+ {/if}
192
+ </Tooltip.Trigger>
193
+ <Tooltip.Content side="right" sideOffset={15}>
194
+ {item.label}
195
+ </Tooltip.Content>
196
+ </Tooltip.Root>
197
+ {/if}
198
+ {/each}
199
+ </div>
200
+ {/snippet}
201
+
202
+ <div
203
+ class="
204
+ {isSmallScreen ? 'fixed top-0 left-0 h-full z-50' : 'relative'}
205
+ border-r bg-background w-screen
206
+ {isCollapsed
207
+ ? 'max-w-0 p-0'
208
+ : `max-w-14 ${isSmallScreen ? 'px-3 pb-3' : 'p-2'}`}"
209
+ style="transition: max-width 150ms, padding 150ms; {isSmallScreen &&
210
+ !isCollapsed
211
+ ? 'max-width: 100vw'
212
+ : ''}"
213
+ >
214
+ {#if isSmallScreen}
215
+ {#if !isCollapsed}
216
+ <X
217
+ class="absolute h-10 text-muted-foreground hover:bg-transparent cursor-pointer hover:text-foreground"
218
+ style="left: 0.6rem; top: 0rem;"
219
+ size="18"
220
+ onclick={() => (isCollapsed = !isCollapsed)}
221
+ />
222
+ {/if}
223
+ {/if}
224
+ <div
225
+ class="flex h-full flex-col justify-between gap-2 w-full overflow-hidden"
226
+ >
227
+ <!-- upper part -->
228
+ <div class="flex flex-col gap-2 {isSmallScreen ? 'pt-8' : ''}">
229
+ {@render section(sections[0])}
230
+ <Separator />
231
+ {@render section(sections[1])}
232
+ </div>
233
+ <div class="flex flex-col gap-2">
234
+ <Separator />
235
+ {@render section(sections[2])}
236
+ </div>
237
+ </div>
238
+ </div>
@@ -0,0 +1,181 @@
1
+ <script lang="ts">
2
+ import { onMount, onDestroy } from "svelte";
3
+ import * as monaco from "monaco-editor";
4
+ import editorWorker from "monaco-editor/esm/vs/editor/editor.worker?worker";
5
+ import jsonWorker from "monaco-editor/esm/vs/language/json/json.worker?worker";
6
+ import cssWorker from "monaco-editor/esm/vs/language/css/css.worker?worker";
7
+ import htmlWorker from "monaco-editor/esm/vs/language/html/html.worker?worker";
8
+ import tsWorker from "monaco-editor/esm/vs/language/typescript/ts.worker?worker";
9
+ import { cn } from "$lib/utils";
10
+
11
+ interface Props {
12
+ type: "javascript" | "typescript" | "json" | "sql";
13
+ name: string;
14
+ value?: string;
15
+ default?: string;
16
+ types?: string;
17
+ class?: string;
18
+ handleCtrlSave?: () => void;
19
+ onChange?: (value: string) => void;
20
+ }
21
+
22
+ let {
23
+ type,
24
+ name,
25
+ value = $bindable(""),
26
+ class: className,
27
+ types,
28
+ handleCtrlSave,
29
+ onChange,
30
+ ...props
31
+ }: Props = $props();
32
+
33
+ let editorContainer: HTMLDivElement;
34
+ let editor: monaco.editor.IStandaloneCodeEditor;
35
+ let model: monaco.editor.ITextModel;
36
+
37
+ if (props.default) {
38
+ value = props.default;
39
+ }
40
+
41
+ $effect(() => {
42
+ if (value !== undefined && editor && value !== editor.getValue()) {
43
+ editor.setValue(value);
44
+ }
45
+ });
46
+
47
+ self.MonacoEnvironment = {
48
+ getWorker(_, label) {
49
+ if (label === "json") {
50
+ return new jsonWorker();
51
+ }
52
+ if (label === "css" || label === "scss" || label === "less") {
53
+ return new cssWorker();
54
+ }
55
+ if (
56
+ label === "html" ||
57
+ label === "handlebars" ||
58
+ label === "razor"
59
+ ) {
60
+ return new htmlWorker();
61
+ }
62
+ if (label === "typescript" || label === "javascript") {
63
+ return new tsWorker();
64
+ }
65
+ return new editorWorker();
66
+ },
67
+ };
68
+
69
+ onMount(async () => {
70
+ monaco.editor.defineTheme("transparentTheme", {
71
+ base: "vs",
72
+ inherit: true,
73
+ rules: [],
74
+ colors: {
75
+ "editor.background": "#EFEFEF00",
76
+ focusBorder: "#00000000",
77
+ },
78
+ });
79
+
80
+ if (type === "typescript") {
81
+ monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
82
+ target: monaco.languages.typescript.ScriptTarget.ESNext,
83
+ moduleResolution:
84
+ monaco.languages.typescript.ModuleResolutionKind.NodeJs,
85
+ esModuleInterop: true,
86
+ });
87
+ monaco.languages.typescript.typescriptDefaults.addExtraLib(
88
+ types ?? "",
89
+ "file:///global.d.ts",
90
+ );
91
+
92
+ // this is an example of importing the picocolors library types
93
+ // with this you can easily use the picolo types in the web editor like this
94
+ // import type Pico from "picocolors"
95
+ // function work(pc: typeof Pico) {
96
+ // pc.bold(`How are ${pc.italic(`you`)} doing?`)
97
+ // }
98
+
99
+ monaco.languages.typescript.typescriptDefaults.addExtraLib(
100
+ `export type Formatter = (input: string | number | null | undefined) => string
101
+ export interface Colors {
102
+ isColorSupported: boolean
103
+
104
+ reset: Formatter
105
+ bold: Formatter
106
+ dim: Formatter
107
+ italic: Formatter
108
+ underline: Formatter
109
+ inverse: Formatter
110
+ hidden: Formatter
111
+ strikethrough: Formatter
112
+ }`,
113
+ "file:///node_modules/picocolors/types.d.ts",
114
+ );
115
+ monaco.languages.typescript.typescriptDefaults.addExtraLib(
116
+ `import { Colors } from "./types.d.ts"
117
+ declare const picocolors: Colors & { createColors: (enabled?: boolean) => Colors }
118
+ export = picocolors`,
119
+ "file:///node_modules/picocolors/index.d.ts",
120
+ );
121
+ }
122
+
123
+ model = monaco.editor.createModel(
124
+ value,
125
+ type,
126
+ monaco.Uri.parse(`file:///${name}.ts`),
127
+ );
128
+
129
+ editor = monaco.editor.create(editorContainer, {
130
+ model: model,
131
+ value: value,
132
+ language: type,
133
+ automaticLayout: true,
134
+ theme: "transparentTheme",
135
+ minimap: { enabled: false },
136
+ glyphMargin: false,
137
+ overviewRulerLanes: 0,
138
+ hideCursorInOverviewRuler: true,
139
+ stickyScroll: { enabled: false },
140
+ lineNumbersMinChars: 2,
141
+ scrollBeyondLastLine: false,
142
+ padding: { top: 10, bottom: 1 },
143
+ });
144
+
145
+ editor.onDidChangeModelContent(() => {
146
+ value = editor.getValue();
147
+ if (onChange) {
148
+ onChange(value);
149
+ }
150
+ });
151
+
152
+ // adding duplicate line shortcut
153
+ editor.addCommand(
154
+ monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.DownArrow,
155
+ () => editor.trigger("", "editor.action.copyLinesDownAction", null),
156
+ );
157
+ editor.addCommand(
158
+ monaco.KeyMod.Shift | monaco.KeyMod.Alt | monaco.KeyCode.UpArrow,
159
+ () => editor.trigger("", "editor.action.copyLinesUpAction", null),
160
+ );
161
+
162
+ editor.addCommand(monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS, () => {
163
+ if (handleCtrlSave) {
164
+ handleCtrlSave();
165
+ }
166
+ });
167
+ });
168
+
169
+ onDestroy(() => {
170
+ editor?.dispose();
171
+ model.dispose();
172
+ });
173
+ </script>
174
+
175
+ <div class={cn("resize-y rounded-md border bg-soft shadow-sm h-60", className)}>
176
+ <div
177
+ bind:this={editorContainer}
178
+ class="editor pl-2"
179
+ style="height: 100%; width: 100%;"
180
+ ></div>
181
+ </div>