@lapis-notes/bases 0.1.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.
Files changed (155) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE.md +8 -0
  3. package/README.md +20 -0
  4. package/dist/bases-plugin.d.ts +10 -0
  5. package/dist/bases-plugin.js +118 -0
  6. package/dist/bases-view/app-database-query-source.d.ts +30 -0
  7. package/dist/bases-view/app-database-query-source.js +248 -0
  8. package/dist/bases-view/bases.svelte.d.ts +569 -0
  9. package/dist/bases-view/bases.svelte.js +910 -0
  10. package/dist/bases-view/card-view/components/card-placeholder.svelte +68 -0
  11. package/dist/bases-view/card-view/components/card-placeholder.svelte.d.ts +7 -0
  12. package/dist/bases-view/card-view/components/card.svelte +289 -0
  13. package/dist/bases-view/card-view/components/card.svelte.d.ts +7 -0
  14. package/dist/bases-view/card-view/index.d.ts +11 -0
  15. package/dist/bases-view/card-view/index.js +55 -0
  16. package/dist/bases-view/cell-editor-options.d.ts +2 -0
  17. package/dist/bases-view/cell-editor-options.js +26 -0
  18. package/dist/bases-view/cell-editor.svelte +206 -0
  19. package/dist/bases-view/cell-editor.svelte.d.ts +12 -0
  20. package/dist/bases-view/cell.svelte +132 -0
  21. package/dist/bases-view/cell.svelte.d.ts +16 -0
  22. package/dist/bases-view/column-definition.d.ts +22 -0
  23. package/dist/bases-view/column-definition.js +149 -0
  24. package/dist/bases-view/columns.d.ts +15 -0
  25. package/dist/bases-view/columns.js +103 -0
  26. package/dist/bases-view/components/Tag.svelte +14 -0
  27. package/dist/bases-view/components/Tag.svelte.d.ts +8 -0
  28. package/dist/bases-view/components/autocomplete.svelte +45 -0
  29. package/dist/bases-view/components/autocomplete.svelte.d.ts +17 -0
  30. package/dist/bases-view/components/card-image.svelte +121 -0
  31. package/dist/bases-view/components/card-image.svelte.d.ts +11 -0
  32. package/dist/bases-view/components/column-visibility.svelte +388 -0
  33. package/dist/bases-view/components/column-visibility.svelte.d.ts +13 -0
  34. package/dist/bases-view/components/datetime.svelte +35 -0
  35. package/dist/bases-view/components/datetime.svelte.d.ts +7 -0
  36. package/dist/bases-view/components/file.svelte +31 -0
  37. package/dist/bases-view/components/file.svelte.d.ts +8 -0
  38. package/dist/bases-view/components/filters/filter-editor.svelte +102 -0
  39. package/dist/bases-view/components/filters/filter-editor.svelte.d.ts +10 -0
  40. package/dist/bases-view/components/filters/filter-group.svelte +142 -0
  41. package/dist/bases-view/components/filters/filter-group.svelte.d.ts +11 -0
  42. package/dist/bases-view/components/filters/filter-properties.svelte +77 -0
  43. package/dist/bases-view/components/filters/filter-properties.svelte.d.ts +8 -0
  44. package/dist/bases-view/components/filters/filter-root.svelte +112 -0
  45. package/dist/bases-view/components/filters/filter-root.svelte.d.ts +12 -0
  46. package/dist/bases-view/components/filters/filter-row.svelte +351 -0
  47. package/dist/bases-view/components/filters/filter-row.svelte.d.ts +11 -0
  48. package/dist/bases-view/components/group/group-root.svelte +120 -0
  49. package/dist/bases-view/components/group/group-root.svelte.d.ts +8 -0
  50. package/dist/bases-view/components/limit.svelte +100 -0
  51. package/dist/bases-view/components/limit.svelte.d.ts +12 -0
  52. package/dist/bases-view/components/query-editor.svelte +230 -0
  53. package/dist/bases-view/components/query-editor.svelte.d.ts +15 -0
  54. package/dist/bases-view/components/sort/sort-direction-labels.d.ts +9 -0
  55. package/dist/bases-view/components/sort/sort-direction-labels.js +25 -0
  56. package/dist/bases-view/components/sort/sort-root.svelte +239 -0
  57. package/dist/bases-view/components/sort/sort-root.svelte.d.ts +11 -0
  58. package/dist/bases-view/components/sort/sort-row.svelte +190 -0
  59. package/dist/bases-view/components/sort/sort-row.svelte.d.ts +15 -0
  60. package/dist/bases-view/components/summary-strip.svelte +56 -0
  61. package/dist/bases-view/components/summary-strip.svelte.d.ts +8 -0
  62. package/dist/bases-view/components/tag-chip.svelte +47 -0
  63. package/dist/bases-view/components/tag-chip.svelte.d.ts +12 -0
  64. package/dist/bases-view/components/views.svelte +178 -0
  65. package/dist/bases-view/components/views.svelte.d.ts +12 -0
  66. package/dist/bases-view/data-table-adapter/data-table.svelte.d.ts +45 -0
  67. package/dist/bases-view/data-table-adapter/data-table.svelte.js +112 -0
  68. package/dist/bases-view/data-table-adapter/flex-render.svelte +43 -0
  69. package/dist/bases-view/data-table-adapter/flex-render.svelte.d.ts +30 -0
  70. package/dist/bases-view/data-table-adapter/index.d.ts +3 -0
  71. package/dist/bases-view/data-table-adapter/index.js +3 -0
  72. package/dist/bases-view/data-table-adapter/render-helpers.d.ts +101 -0
  73. package/dist/bases-view/data-table-adapter/render-helpers.js +110 -0
  74. package/dist/bases-view/db.d.ts +31 -0
  75. package/dist/bases-view/db.js +174 -0
  76. package/dist/bases-view/document-core.d.ts +2 -0
  77. package/dist/bases-view/document-core.js +166 -0
  78. package/dist/bases-view/export-core.d.ts +4 -0
  79. package/dist/bases-view/export-core.js +31 -0
  80. package/dist/bases-view/file-fields-core.d.ts +31 -0
  81. package/dist/bases-view/file-fields-core.js +114 -0
  82. package/dist/bases-view/filter-parser.d.ts +27 -0
  83. package/dist/bases-view/filter-parser.js +315 -0
  84. package/dist/bases-view/functions-core.d.ts +66 -0
  85. package/dist/bases-view/functions-core.js +265 -0
  86. package/dist/bases-view/functions.d.ts +5 -0
  87. package/dist/bases-view/functions.js +107 -0
  88. package/dist/bases-view/fuzzy-search.d.ts +6 -0
  89. package/dist/bases-view/fuzzy-search.js +15 -0
  90. package/dist/bases-view/hooks/useResizeObserver.svelte.d.ts +7 -0
  91. package/dist/bases-view/hooks/useResizeObserver.svelte.js +26 -0
  92. package/dist/bases-view/index.d.ts +66 -0
  93. package/dist/bases-view/index.js +231 -0
  94. package/dist/bases-view/list-view/index.d.ts +10 -0
  95. package/dist/bases-view/list-view/index.js +17 -0
  96. package/dist/bases-view/list-view/list.svelte +156 -0
  97. package/dist/bases-view/list-view/list.svelte.d.ts +7 -0
  98. package/dist/bases-view/map-view/index.d.ts +10 -0
  99. package/dist/bases-view/map-view/index.js +17 -0
  100. package/dist/bases-view/map-view/view.svelte +28 -0
  101. package/dist/bases-view/map-view/view.svelte.d.ts +7 -0
  102. package/dist/bases-view/metadata-invalidation-core.d.ts +34 -0
  103. package/dist/bases-view/metadata-invalidation-core.js +162 -0
  104. package/dist/bases-view/metadata-type-info.d.ts +7 -0
  105. package/dist/bases-view/metadata-type-info.js +10 -0
  106. package/dist/bases-view/models.d.ts +90 -0
  107. package/dist/bases-view/models.js +133 -0
  108. package/dist/bases-view/query-result-core.d.ts +8 -0
  109. package/dist/bases-view/query-result-core.js +16 -0
  110. package/dist/bases-view/resource-url.d.ts +2 -0
  111. package/dist/bases-view/resource-url.js +21 -0
  112. package/dist/bases-view/search-core.d.ts +9 -0
  113. package/dist/bases-view/search-core.js +20 -0
  114. package/dist/bases-view/summary-core.d.ts +7 -0
  115. package/dist/bases-view/summary-core.js +17 -0
  116. package/dist/bases-view/table-view/components/div-table.svelte +464 -0
  117. package/dist/bases-view/table-view/components/div-table.svelte.d.ts +32 -0
  118. package/dist/bases-view/table-view/components/dnd-style.d.ts +3 -0
  119. package/dist/bases-view/table-view/components/dnd-style.js +6 -0
  120. package/dist/bases-view/table-view/components/sort-header.svelte +48 -0
  121. package/dist/bases-view/table-view/components/sort-header.svelte.d.ts +11 -0
  122. package/dist/bases-view/table-view/components/table-column-tracks.d.ts +14 -0
  123. package/dist/bases-view/table-view/components/table-column-tracks.js +27 -0
  124. package/dist/bases-view/table-view/components/table-header.svelte +146 -0
  125. package/dist/bases-view/table-view/components/table-header.svelte.d.ts +10 -0
  126. package/dist/bases-view/table-view/components/table-placeholder.svelte +46 -0
  127. package/dist/bases-view/table-view/components/table-placeholder.svelte.d.ts +30 -0
  128. package/dist/bases-view/table-view/components/table-virtualizer-core.d.ts +13 -0
  129. package/dist/bases-view/table-view/components/table-virtualizer-core.js +12 -0
  130. package/dist/bases-view/table-view/components/table.svelte +997 -0
  131. package/dist/bases-view/table-view/components/table.svelte.d.ts +32 -0
  132. package/dist/bases-view/table-view/index.svelte.d.ts +10 -0
  133. package/dist/bases-view/table-view/index.svelte.js +30 -0
  134. package/dist/bases-view/unknown-view/index.d.ts +10 -0
  135. package/dist/bases-view/unknown-view/index.js +19 -0
  136. package/dist/bases-view/unknown-view/view.svelte +11 -0
  137. package/dist/bases-view/unknown-view/view.svelte.d.ts +6 -0
  138. package/dist/bases-view/view-header.svelte +142 -0
  139. package/dist/bases-view/view-header.svelte.d.ts +28 -0
  140. package/dist/bases-view/view-registration-inventory.d.ts +22 -0
  141. package/dist/bases-view/view-registration-inventory.js +7 -0
  142. package/dist/bases-view/view-settings.svelte +350 -0
  143. package/dist/bases-view/view-settings.svelte.d.ts +9 -0
  144. package/dist/bases-view/view.svelte +192 -0
  145. package/dist/bases-view/view.svelte.d.ts +15 -0
  146. package/dist/bases-view-surface.svelte +31 -0
  147. package/dist/bases-view-surface.svelte.d.ts +14 -0
  148. package/dist/index.d.ts +10 -0
  149. package/dist/index.js +8 -0
  150. package/dist/serialized-write-queue.d.ts +10 -0
  151. package/dist/serialized-write-queue.js +36 -0
  152. package/dist/styles.css +2164 -0
  153. package/manifest.json +33 -0
  154. package/package.json +90 -0
  155. package/styles.css +1 -0
@@ -0,0 +1,351 @@
1
+ <script module lang="ts">
2
+ let filterErrorSequence = 0;
3
+ </script>
4
+
5
+ <script lang="ts">
6
+ import type { Table } from "@tanstack/table-core";
7
+ import * as Popover from "@lapismd/design-core/shadcn/popover";
8
+ import * as Command from "@lapismd/design-core/shadcn/command";
9
+ import { columnName, filterTypeFor, isFilterLine } from "../..";
10
+ import { Icon } from "@lapis-notes/api/icon";
11
+ import CheckIcon from "@lucide/svelte/icons/check";
12
+ import CodeXML from "@lucide/svelte/icons/code-xml";
13
+ import FilterIcon from "@lucide/svelte/icons/mouse-pointer-click";
14
+
15
+ import Trash from "@lucide/svelte/icons/trash-2";
16
+ import ArrowUpDown from "@lucide/svelte/icons/chevrons-up-down";
17
+ import * as Select from "@lapismd/design-core/shadcn/select";
18
+
19
+ import { Button } from "@lapismd/design-core/shadcn/button";
20
+ import type { FilterLine } from "../..";
21
+ import { onMount, untrack } from "svelte";
22
+ import FilterEditor from "./filter-editor.svelte";
23
+ import { cn } from "@lapis-notes/api";
24
+ import {
25
+ resolveFilterDraft,
26
+ toSQL,
27
+ validateFilterPredicate,
28
+ } from "../../filter-parser";
29
+ import { Notice } from "@lapis-notes/api";
30
+ import QueryEditor from "../query-editor.svelte";
31
+ import type { BasesPropertyId, QueryController } from "../../bases.svelte";
32
+
33
+ let {
34
+ label,
35
+ controller,
36
+ value = $bindable(),
37
+ deleteFilter,
38
+ }: {
39
+ label: string;
40
+ controller: QueryController;
41
+ value: string | FilterLine;
42
+ deleteFilter?: () => void;
43
+ } = $props();
44
+
45
+ let filter: FilterLine = $state({
46
+ column: "",
47
+ op: "",
48
+ value: "",
49
+ });
50
+ const filterErrorId = `bases-filter-error-${++filterErrorSequence}`;
51
+ let customDraft = $state("");
52
+ let customError = $state<string | null>(null);
53
+
54
+ let column = $derived(
55
+ filter.column
56
+ ? controller.getColumn(filter.column as BasesPropertyId)
57
+ : undefined,
58
+ );
59
+ let type = $derived(column?.type ?? "unknown");
60
+ let filterTypes = $derived(filterTypeFor(column));
61
+ let simple = $derived(typeof filter.custom !== "string");
62
+ let filterValue = $derived(filterTypes.find((f) => f.value === filter.op));
63
+ let isValid = $derived(
64
+ filter.op.length > 0 &&
65
+ filter.column.length > 0 &&
66
+ filterValue &&
67
+ (filterValue.type === "none" || String(filter.value).length > 0),
68
+ );
69
+
70
+ function equalFilterLines(
71
+ left: FilterLine | null | undefined,
72
+ right: FilterLine | null | undefined,
73
+ ): boolean {
74
+ if (!left || !right) {
75
+ return left === right;
76
+ }
77
+
78
+ const equalValue =
79
+ Array.isArray(left.value) || Array.isArray(right.value)
80
+ ? Array.isArray(left.value) &&
81
+ Array.isArray(right.value) &&
82
+ left.value.length === right.value.length &&
83
+ left.value.every((value, index) => value === right.value[index])
84
+ : left.value === right.value;
85
+
86
+ return (
87
+ left.column === right.column &&
88
+ left.op === right.op &&
89
+ left.custom === right.custom &&
90
+ equalValue
91
+ );
92
+ }
93
+
94
+ function syncCustomDraft(source: string, error: string | null = null) {
95
+ if (untrack(() => customDraft) !== source) {
96
+ customDraft = source;
97
+ }
98
+ customError = error;
99
+ }
100
+
101
+ function updateCustomDraft(source: string) {
102
+ customDraft = source;
103
+ const result = resolveFilterDraft(filter.custom ?? "", source);
104
+ customError = result.error;
105
+ if (result.valid) {
106
+ filter.custom = result.applied;
107
+ }
108
+ }
109
+
110
+ $effect(() => {
111
+ if (isFilterLine(value)) {
112
+ if (!equalFilterLines(filter, value)) {
113
+ filter = { ...value };
114
+ }
115
+ if (typeof value.custom === "string") {
116
+ syncCustomDraft(value.custom);
117
+ }
118
+ return;
119
+ }
120
+
121
+ if (typeof filter.custom === "string" && filter.custom === value) {
122
+ syncCustomDraft(value);
123
+ return;
124
+ }
125
+
126
+ const validation = validateFilterPredicate(value);
127
+ if (!validation.valid) {
128
+ filter = { ...filter, custom: value };
129
+ syncCustomDraft(value, validation.error);
130
+ return;
131
+ }
132
+
133
+ const predicate = validation.predicate;
134
+ if (isFilterLine(predicate)) {
135
+ if (!equalFilterLines(filter, predicate)) {
136
+ filter = predicate;
137
+ }
138
+ if (typeof predicate.custom === "string") {
139
+ syncCustomDraft(predicate.custom);
140
+ } else {
141
+ syncCustomDraft(value);
142
+ }
143
+ } else {
144
+ filter.op = filterTypes[0].value;
145
+ }
146
+ });
147
+
148
+ $effect(() => {
149
+ if (filterValue && filterValue.type === "none" && filterValue.value) {
150
+ filterValue.value = "";
151
+ }
152
+ });
153
+
154
+ onMount(() => {
155
+ if (!filter.column) {
156
+ filter.column = controller.getAllColumns()[0]?.id;
157
+ }
158
+ if (!filter.value) {
159
+ filter.value = "";
160
+ }
161
+ });
162
+
163
+ function toggleSimple() {
164
+ if (simple) {
165
+ const source = toSQL(filter);
166
+ filter.custom = source;
167
+ syncCustomDraft(source);
168
+ } else {
169
+ const validation = validateFilterPredicate(customDraft);
170
+ customError = validation.error;
171
+ if (!validation.valid) {
172
+ return;
173
+ }
174
+ const predicate = validation.predicate;
175
+ if (isFilterLine(predicate) && !predicate.custom) {
176
+ filter.column = predicate.column;
177
+ filter.op = predicate.op;
178
+ filter.value = predicate.value;
179
+ filter.custom = null;
180
+ } else {
181
+ new Notice(
182
+ `This filter cannot be represented by the simple filter builder`,
183
+ );
184
+ }
185
+ }
186
+ }
187
+
188
+ $effect(() => {
189
+ const nextValue = isValid
190
+ ? simple
191
+ ? { ...filter, custom: null }
192
+ : (filter.custom ?? "")
193
+ : "";
194
+
195
+ if (typeof nextValue === "string") {
196
+ if (value !== nextValue) {
197
+ value = nextValue;
198
+ }
199
+ return;
200
+ }
201
+
202
+ if (!isFilterLine(value) || !equalFilterLines(value, nextValue)) {
203
+ value = nextValue;
204
+ }
205
+ });
206
+ let columnsIsOpen: boolean = $state(false);
207
+ </script>
208
+
209
+ <div class="filter-row bases-style-flex-60fbb7 bases-style-items-center-3960ff bases-style-gap-0-63a285">
210
+ <span class="filter-row__label bases-style-min-w-4-5rem-00331a bases-style-pr-1-eda955 bases-style-text-right-308fc0"
211
+ >{label}</span
212
+ >
213
+ <div class="filter-row__field">
214
+ <div
215
+ class={cn(
216
+ "filter-row__controls bases-style-bg-background-e6f9e3 bases-style-flex-60fbb7 bases-style-min-h-9-968a1e bases-style-items-center-3960ff bases-style-rounded-md-421ac2 bases-style-border-2-65935d",
217
+ )}
218
+ data-invalid={customError !== null}
219
+ >
220
+ {#if simple}
221
+ <Popover.Root bind:open={columnsIsOpen}>
222
+ <Popover.Trigger>
223
+ {#snippet child({ props }: { props: Record<string, any> })}
224
+ <Button
225
+ {...props}
226
+ variant="outline"
227
+ size="sm"
228
+ class="bases-style-min-h-inherit-05c993 bases-style-h-auto-b8f0a0 bases-style-self-stretch-18069a bases-style-rounded-none-0c5e91 bases-style-rounded-l-md-9b2e91 bases-style-border-none-4a5f0e bases-style-shadow-none-ad47d1 bases-style-outline-none-df37b1"
229
+ >
230
+ <Icon name={[column?.icon ?? "lucide-file"]} />
231
+ {column?.displayName}
232
+ <ArrowUpDown />
233
+ </Button>
234
+ {/snippet}
235
+ </Popover.Trigger>
236
+ <Popover.Content class="bases-style-w-max-2f935d bases-style-p-0-8a539c" align="start">
237
+ <Command.Root>
238
+ <Command.Input placeholder="Find or create" />
239
+ <Command.List class="bases-style-p-1-eb6a3c">
240
+ <Command.Empty>No results found.</Command.Empty>
241
+ {#each controller.getAllColumns() as column (column.id)}
242
+ <Command.Item
243
+ onSelect={() => {
244
+ filter.column = column.id;
245
+ columnsIsOpen = false;
246
+ }}
247
+ >
248
+ <div
249
+ class={cn(
250
+ "bases-style-mr-2-d2347e bases-style-flex-60fbb7 bases-style-size-4-f7b5fa bases-style-items-center-3960ff bases-style-justify-center-86843c",
251
+ filter.column === column.id
252
+ ? ""
253
+ : "bases-style-opacity-50-0b8c50 [&_svg]:invisible",
254
+ )}
255
+ >
256
+ <CheckIcon class="bases-style-size-4-f7b5fa" />
257
+ </div>
258
+ <Icon name={[column?.icon ?? "lucide-info"]} />
259
+ <span>{column?.displayName}</span>
260
+ {#if !column?.id?.startsWith("note.")}
261
+ <Command.Shortcut class="bases-style-font-mono-0e6570 bases-style-text-0-75em-c425cc"
262
+ >{column?.id}</Command.Shortcut
263
+ >
264
+ {/if}
265
+ </Command.Item>
266
+ {/each}
267
+ </Command.List>
268
+ </Command.Root>
269
+ </Popover.Content>
270
+ </Popover.Root>
271
+ <Select.Root type="single" bind:value={filter.op}>
272
+ <Select.Trigger
273
+ size="sm"
274
+ data-bases-filter-control="operator-trigger"
275
+ class="bases-style-bg-background-e6f9e3 bases-style-min-h-inherit-05c993 bases-style-h-auto-b8f0a0 bases-style-self-stretch-18069a bases-style-rounded-none-0c5e91 bases-style-border-none-4a5f0e bases-style-shadow-none-ad47d1 bases-style-outline-none-df37b1"
276
+ >
277
+ {filterValue?.label || filter.op}
278
+ </Select.Trigger>
279
+ <Select.Content
280
+ align="start"
281
+ data-bases-filter-control="operator-content"
282
+ >
283
+ <Select.Group>
284
+ {#each filterTypes as filterType (filterType.value)}
285
+ <Select.Item value={filterType.value} label={filterType.label}
286
+ >{filterType.label}</Select.Item
287
+ >
288
+ {/each}
289
+ </Select.Group>
290
+ </Select.Content>
291
+ </Select.Root>
292
+ <FilterEditor
293
+ type={filterValue?.type ?? type}
294
+ {controller}
295
+ bind:value={filter.value}
296
+ />
297
+ <Button
298
+ onclick={() => toggleSimple()}
299
+ data-tooltip="Simple filter"
300
+ aria-label="Use custom filter"
301
+ variant="ghost"
302
+ size="sm"
303
+ class="bases-style-bg-background-e6f9e3 bases-style-min-h-inherit-05c993 bases-style-h-auto-b8f0a0 bases-style-self-stretch-18069a bases-style-rounded-none-0c5e91 bases-style-border-none-4a5f0e bases-style-shadow-none-ad47d1 bases-style-outline-none-df37b1"
304
+ >
305
+ <CodeXML />
306
+ </Button>
307
+ {:else}
308
+ <QueryEditor
309
+ {controller}
310
+ onBlur={updateCustomDraft}
311
+ onDocChange={updateCustomDraft}
312
+ bind:content={customDraft}
313
+ invalid={customError !== null}
314
+ describedBy={customError ? filterErrorId : undefined}
315
+ class="bases-style-bg-background-e6f9e3 bases-style-h-full-668b21 grow bases-style-rounded-l-md-9b2e91 bases-style-border-none-4a5f0e bases-style-pl-1-6ad214 bases-style-outline-none-df37b1"
316
+ />
317
+ <Button
318
+ onclick={() => toggleSimple()}
319
+ data-tooltip="Simple filter"
320
+ aria-label="Use simple filter"
321
+ variant="ghost"
322
+ size="sm"
323
+ class="bases-style-min-h-inherit-05c993 bases-style-bg-background-e6f9e3 bases-style-h-auto-b8f0a0 bases-style-self-stretch-18069a bases-style-rounded-none-0c5e91 bases-style-border-none-4a5f0e bases-style-shadow-none-ad47d1 bases-style-outline-none-df37b1"
324
+ >
325
+ <FilterIcon />
326
+ </Button>
327
+ {/if}
328
+ {#if deleteFilter}
329
+ <Button
330
+ variant="ghost"
331
+ size="sm"
332
+ aria-label="Delete filter"
333
+ class="bases-style-bg-background-e6f9e3 bases-style-min-h-inherit-05c993 bases-style-h-auto-b8f0a0 bases-style-self-stretch-18069a bases-style-rounded-none-0c5e91 bases-style-rounded-r-md-d4eb07 bases-style-border-none-4a5f0e bases-style-shadow-none-ad47d1 bases-style-outline-none-df37b1"
334
+ onclick={() => deleteFilter()}
335
+ >
336
+ <Trash />
337
+ </Button>
338
+ {/if}
339
+ </div>
340
+ {#if customError}
341
+ <p
342
+ id={filterErrorId}
343
+ class="filter-row__error"
344
+ data-ui-part="filter-error"
345
+ role="alert"
346
+ >
347
+ {customError}
348
+ </p>
349
+ {/if}
350
+ </div>
351
+ </div>
@@ -0,0 +1,11 @@
1
+ import type { FilterLine } from "../..";
2
+ import type { QueryController } from "../../bases.svelte";
3
+ type $$ComponentProps = {
4
+ label: string;
5
+ controller: QueryController;
6
+ value: string | FilterLine;
7
+ deleteFilter?: () => void;
8
+ };
9
+ declare const FilterRow: import("svelte").Component<$$ComponentProps, {}, "value">;
10
+ type FilterRow = ReturnType<typeof FilterRow>;
11
+ export default FilterRow;
@@ -0,0 +1,120 @@
1
+ <script lang="ts">
2
+ import * as Command from "@lapismd/design-core/shadcn/command";
3
+ import * as Popover from "@lapismd/design-core/shadcn/popover";
4
+ import * as Select from "@lapismd/design-core/shadcn/select";
5
+ import { Button } from "@lapismd/design-core/shadcn/button";
6
+ import { cn } from "@lapis-notes/api";
7
+ import CheckIcon from "@lucide/svelte/icons/check";
8
+ import type { QueryController } from "../../bases.svelte";
9
+ import { Icon } from "@lapis-notes/api/icon";
10
+
11
+ let {
12
+ controller,
13
+ class: className,
14
+ }: {
15
+ controller: QueryController;
16
+ class?: string;
17
+ } = $props();
18
+
19
+ const directions = [
20
+ { label: "Ascending", value: "ASC" },
21
+ { label: "Descending", value: "DESC" },
22
+ ] as const;
23
+
24
+ let groupBy = $derived(controller.selectedView.groupBy);
25
+ let selectedColumn = $derived.by(() => {
26
+ return groupBy?.property
27
+ ? controller.getColumn(groupBy.property)
28
+ : undefined;
29
+ });
30
+
31
+ function setGroupBy(property: string) {
32
+ controller.selectedView.groupBy = {
33
+ property,
34
+ direction: controller.selectedView.groupBy?.direction ?? "ASC",
35
+ };
36
+ }
37
+
38
+ function getDirection() {
39
+ return controller.selectedView.groupBy?.direction ?? "ASC";
40
+ }
41
+
42
+ function setDirection(direction: string) {
43
+ if (!controller.selectedView.groupBy) return;
44
+ controller.selectedView.groupBy = {
45
+ ...controller.selectedView.groupBy,
46
+ direction: direction === "DESC" ? "DESC" : "ASC",
47
+ };
48
+ }
49
+ </script>
50
+
51
+ <Popover.Root>
52
+ <Popover.Trigger>
53
+ {#snippet child({ props }: { props: Record<string, unknown> })}
54
+ <Button
55
+ {...props}
56
+ variant="outline"
57
+ size="sm"
58
+ class={cn("bases-style-h-8-ed8a5d bases-style-border-dashed-a29b7a", className, {
59
+ "bases-style-text-var-text-accent-69c994 bases-style-hover-bg-color-mix-in-srgb-var-interactive-4e3e8a bases-style-hover-text-var-text-accent-5b2cb5":
60
+ !!groupBy?.property,
61
+ })}
62
+ >
63
+ Group
64
+ </Button>
65
+ {/snippet}
66
+ </Popover.Trigger>
67
+ <Popover.Content class="bases-style-w-320px-57f3af bases-style-p-0-8a539c" align="start">
68
+ <Command.Root>
69
+ <Command.Input placeholder="Group by property" />
70
+ <Command.List class="bases-style-p-1-eb6a3c">
71
+ <Command.Empty>No properties found.</Command.Empty>
72
+ {#each controller.getAllColumns() as column (column.id)}
73
+ <Command.Item onSelect={() => setGroupBy(column.id)}>
74
+ <div
75
+ data-ui-part="bases-option-indicator"
76
+ data-selected={groupBy?.property === column.id}
77
+ class={cn(
78
+ "bases-style-mr-2-d2347e bases-style-flex-60fbb7 bases-style-size-4-f7b5fa bases-style-items-center-3960ff bases-style-justify-center-86843c bases-style-rounded-sm-36d446 border bases-style-border-var-interactive-accent-f46c93",
79
+ groupBy?.property === column.id
80
+ ? "bases-style-ring-ring-3e1868 bases-style-border-none-4a5f0e bases-style-bg-var-interactive-accent-c58cc0 bases-style-text-var-text-on-accent-22b2b1 hover:ring"
81
+ : "bases-style-opacity-50-0b8c50 [&_svg]:invisible",
82
+ )}
83
+ >
84
+ <CheckIcon class="bases-style-size-4-f7b5fa" />
85
+ </div>
86
+ <Icon name={[column.icon ?? "lucide-file"]} />
87
+ <span class="truncate">{column.displayName}</span>
88
+ </Command.Item>
89
+ {/each}
90
+ </Command.List>
91
+ <div class="bases-style-border-t-b950dd bases-style-p-2-7660b4">
92
+ <div class="bases-style-grid-f3c543 bases-style-grid-cols-1-d7c833 bases-style-gap-2-77a2a2">
93
+ <Select.Root type="single" bind:value={getDirection, setDirection}>
94
+ <Select.Trigger size="sm" class="bases-style-bg-background-e6f9e3 bases-style-h-8-ed8a5d bases-style-justify-between-8ef226">
95
+ {directions.find(
96
+ (direction) => direction.value === getDirection(),
97
+ )?.label}
98
+ </Select.Trigger>
99
+ <Select.Content>
100
+ {#each directions as direction (direction.value)}
101
+ <Select.Item value={direction.value} label={direction.label}
102
+ >{direction.label}</Select.Item
103
+ >
104
+ {/each}
105
+ </Select.Content>
106
+ </Select.Root>
107
+ <Button
108
+ variant="ghost"
109
+ size="sm"
110
+ class="bases-style-justify-start-4b5cc1"
111
+ disabled={!selectedColumn}
112
+ onclick={() => (controller.selectedView.groupBy = undefined)}
113
+ >
114
+ Clear grouping
115
+ </Button>
116
+ </div>
117
+ </div>
118
+ </Command.Root>
119
+ </Popover.Content>
120
+ </Popover.Root>
@@ -0,0 +1,8 @@
1
+ import type { QueryController } from "../../bases.svelte";
2
+ type $$ComponentProps = {
3
+ controller: QueryController;
4
+ class?: string;
5
+ };
6
+ declare const GroupRoot: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type GroupRoot = ReturnType<typeof GroupRoot>;
8
+ export default GroupRoot;
@@ -0,0 +1,100 @@
1
+ <script lang="ts">
2
+ import * as Popover from "@lapismd/design-core/shadcn/popover";
3
+ import * as Command from "@lapismd/design-core/shadcn/command";
4
+ import { Button } from "@lapismd/design-core/shadcn/button";
5
+ import { Label } from "@lapismd/design-core/shadcn/label";
6
+ import { Input } from "@lapismd/design-core/shadcn/input";
7
+ import type { BasesViewBase } from "../models";
8
+ import { cn } from "@lapis-notes/api";
9
+ import Copy from "@lucide/svelte/icons/copy";
10
+ import Download from "@lucide/svelte/icons/download";
11
+ import ShowAll from "@lucide/svelte/icons/rotate-ccw";
12
+ let {
13
+ count,
14
+ view = $bindable(),
15
+ onCopyCsv,
16
+ onExportCsv,
17
+ table,
18
+ class: className,
19
+ }: {
20
+ count: number;
21
+ view: BasesViewBase;
22
+ onCopyCsv?: () => void | Promise<void>;
23
+ onExportCsv?: () => void;
24
+ table?: any;
25
+ class?: string;
26
+ } = $props();
27
+
28
+ let showAll = $derived.by(() => {
29
+ return !view.limit || view.limit <= 0;
30
+ });
31
+
32
+ function changeLimit(event: FocusEvent) {
33
+ const target = event.target as HTMLInputElement;
34
+ const value = +target.value;
35
+ if (value !== view.limit) {
36
+ view.limit = value;
37
+ }
38
+ }
39
+ </script>
40
+
41
+ <Popover.Root>
42
+ <Popover.Trigger>
43
+ {#snippet child({ props }: { props: Record<string, unknown> })}
44
+ <Button
45
+ {...props}
46
+ variant="outline"
47
+ size="sm"
48
+ class={cn("bases-style-h-8-ed8a5d bases-style-border-dashed-a29b7a", className)}
49
+ >
50
+ {count} results
51
+ </Button>
52
+ {/snippet}
53
+ </Popover.Trigger>
54
+ <Popover.Content class="bases-style-w-270px-448793 bases-style-min-w-220px-cbc208 bases-style-p-0-8a539c" align="start">
55
+ <Command.Root>
56
+ <div class="bases-style-p-2-7660b4">
57
+ <div class="bases-style-grid-f3c543 bases-style-grid-cols-1-d7c833 bases-style-items-center-3960ff bases-style-gap-2-77a2a2 bases-style-px-2-d5eab2 bases-style-pt-1-6b7d6e">
58
+ <Label for="column_name" class="bases-style-text-sm-fc7473 bases-style-opacity-50-0b8c50"
59
+ >Limit number of results</Label
60
+ >
61
+ <Input
62
+ type="number"
63
+ placeholder="e.g 10"
64
+ id="column_name"
65
+ onblur={(evt) => changeLimit(evt)}
66
+ value={showAll ? "" : view.limit}
67
+ class="bases-style-col-span-2-40efc0 bases-style-h-8-ed8a5d"
68
+ />
69
+ </div>
70
+ <div class="bases-style-mt-2-50d0d2 bases-style-grid-f3c543 bases-style-grid-cols-1-d7c833 bases-style-items-center-3960ff bases-style-gap-2-77a2a2 bases-style-px-2-d5eab2 bases-style-pt-1-6b7d6e">
71
+ <Button
72
+ disabled={showAll}
73
+ size="sm"
74
+ onclick={() => (view.limit = 0)}
75
+ class={cn("bases-style-w-full-6da6a3 bases-style-justify-start-4b5cc1")}
76
+ variant="ghost"
77
+ >
78
+ <ShowAll /> Show all
79
+ </Button>
80
+ <Button
81
+ size="sm"
82
+ onclick={() => onCopyCsv?.()}
83
+ class={cn("bases-style-w-full-6da6a3 bases-style-justify-start-4b5cc1")}
84
+ variant="ghost"
85
+ >
86
+ <Copy /> Copy to clipboard
87
+ </Button>
88
+ <Button
89
+ size="sm"
90
+ onclick={() => onExportCsv?.()}
91
+ class={cn("bases-style-w-full-6da6a3 bases-style-justify-start-4b5cc1")}
92
+ variant="ghost"
93
+ >
94
+ <Download /> Export CSV...
95
+ </Button>
96
+ </div>
97
+ </div>
98
+ </Command.Root>
99
+ </Popover.Content>
100
+ </Popover.Root>
@@ -0,0 +1,12 @@
1
+ import type { BasesViewBase } from "../models";
2
+ type $$ComponentProps = {
3
+ count: number;
4
+ view: BasesViewBase;
5
+ onCopyCsv?: () => void | Promise<void>;
6
+ onExportCsv?: () => void;
7
+ table?: any;
8
+ class?: string;
9
+ };
10
+ declare const Limit: import("svelte").Component<$$ComponentProps, {}, "view">;
11
+ type Limit = ReturnType<typeof Limit>;
12
+ export default Limit;