@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,132 @@
1
+ <script lang="ts">
2
+ import { DateTime } from "luxon";
3
+ import { type DType } from "peaql";
4
+ import type { HTMLAttributes } from "svelte/elements";
5
+ import DatetimeWidget from "./components/datetime.svelte";
6
+ import { cn, TFile, type App, type MetadataType } from "@lapis-notes/api";
7
+ import { normalizeMetadataValue } from "@lapis-notes/api/metadata-value";
8
+ import CellEditor from "./cell-editor.svelte";
9
+ import { set, unset } from "lodash-es";
10
+ import { untrack } from "svelte";
11
+ import { Icon } from "./functions";
12
+ import { Icon as IconComponent } from "@lapis-notes/api/icon";
13
+ import File from "./components/file.svelte";
14
+ import Tag from "./components/tag-chip.svelte";
15
+ import type { Value } from "@lapis-notes/api";
16
+ let {
17
+ app,
18
+ file,
19
+ type,
20
+ name,
21
+ value: cellValue,
22
+ readOnly = false,
23
+ class: className,
24
+ meta,
25
+ ...rest
26
+ }: HTMLAttributes<HTMLDivElement> & {
27
+ name: string;
28
+ app: App;
29
+ type: string | DType;
30
+ value: Value | null | unknown;
31
+ file: TFile;
32
+ readOnly?: boolean;
33
+ meta?: unknown;
34
+ } = $props();
35
+
36
+ let displayType = $derived(String(type ?? ""));
37
+ let value = $derived(
38
+ cellValue instanceof Object && "value" in cellValue
39
+ ? (cellValue as Value).value
40
+ : (cellValue ?? ""),
41
+ );
42
+
43
+ function focusElement(evt: Event) {
44
+ const target = evt.target;
45
+ if (!(target instanceof HTMLElement) || target.closest("button")) return;
46
+ const cell = evt.currentTarget;
47
+ if (!(cell instanceof HTMLElement)) return;
48
+ cell.querySelector("input")?.focus();
49
+ }
50
+
51
+ function metadataTypeFromDisplayType(displayType: string): MetadataType {
52
+ switch (displayType.toLowerCase()) {
53
+ case "boolean":
54
+ case "checkbox":
55
+ return "checkbox";
56
+ case "number":
57
+ return "number";
58
+ case "date":
59
+ return "date";
60
+ case "datetime":
61
+ case "timestamp":
62
+ return "datetime";
63
+ case "multitext":
64
+ return "multitext";
65
+ case "tags":
66
+ return "tags";
67
+ case "aliases":
68
+ return "aliases";
69
+ case "array":
70
+ return "array";
71
+ case "object":
72
+ return "object";
73
+ default:
74
+ return "text";
75
+ }
76
+ }
77
+
78
+ function onValueChange(name: string, value: any) {
79
+ if (name.startsWith("file.") || name.startsWith("formula.")) return;
80
+ untrack(() => {
81
+ if (file) {
82
+ const id = name.startsWith("note.") ? name.substring(5) : name;
83
+ const declaredType =
84
+ app.metadataTypeManager.types[id]?.type ??
85
+ metadataTypeFromDisplayType(displayType);
86
+ const normalized = normalizeMetadataValue(declaredType, value);
87
+ const existing =
88
+ cellValue instanceof Object && "value" in cellValue
89
+ ? (cellValue as Value).value
90
+ : "";
91
+ if (existing === normalized) return;
92
+ app.fileManager.processFrontMatter(file, (data) => {
93
+ if (normalized === null || normalized === undefined) {
94
+ unset(data, id);
95
+ } else {
96
+ set(data, id, normalized);
97
+ }
98
+ });
99
+ }
100
+ });
101
+ }
102
+ </script>
103
+
104
+ <div
105
+ {...rest}
106
+ class={cn("bases-style-h-full-668b21 bases-style-w-full-6da6a3", className)}
107
+ onclick={(evt) => focusElement(evt)}
108
+ data-ui-component="bases-cell"
109
+ data-ui-part="root"
110
+ data-type={displayType}
111
+ data-property={name}
112
+ >
113
+ {#if !readOnly && !(name.startsWith("file.") || name.startsWith("formula.") || name === "file")}
114
+ <CellEditor {app} {onValueChange} {value} {name} type={displayType} />
115
+ {:else if file && name === "file.name"}
116
+ <File {app} {file} />
117
+ {:else if name === "file.tags"}
118
+ <div class="markdown-rendered bases-style-flex-60fbb7 bases-style-h-full-668b21 bases-style-w-full-6da6a3 bases-style-gap-2-77a2a2">
119
+ {#each Array.isArray(value) ? value : [] as tag}
120
+ <Tag name={tag} />
121
+ {/each}
122
+ </div>
123
+ {:else if value instanceof TFile}
124
+ <File {app} file={value} />
125
+ {:else if value instanceof DateTime}
126
+ <DatetimeWidget {value} />
127
+ {:else if value instanceof Icon}
128
+ <IconComponent name={[value.name, "circle-question-mark"]} />
129
+ {:else}
130
+ <div class="bases-style-h-full-668b21 bases-style-w-full-6da6a3">{value}</div>
131
+ {/if}
132
+ </div>
@@ -0,0 +1,16 @@
1
+ import { type DType } from "peaql";
2
+ import type { HTMLAttributes } from "svelte/elements";
3
+ import { TFile, type App } from "@lapis-notes/api";
4
+ import type { Value } from "@lapis-notes/api";
5
+ type $$ComponentProps = HTMLAttributes<HTMLDivElement> & {
6
+ name: string;
7
+ app: App;
8
+ type: string | DType;
9
+ value: Value | null | unknown;
10
+ file: TFile;
11
+ readOnly?: boolean;
12
+ meta?: unknown;
13
+ };
14
+ declare const Cell: import("svelte").Component<$$ComponentProps, {}, "">;
15
+ type Cell = ReturnType<typeof Cell>;
16
+ export default Cell;
@@ -0,0 +1,22 @@
1
+ import type { App, MetadataType } from "@lapis-notes/api";
2
+ import { type DType } from "peaql";
3
+ import type { VaultRecord } from ".";
4
+ export type SortDirection = "ASC" | "DESC";
5
+ export type ColumnMeta = {
6
+ displayName: string;
7
+ icon: string;
8
+ type: MetadataType;
9
+ frontmatter?: boolean;
10
+ };
11
+ export type ColumnDef = {
12
+ id: string;
13
+ meta: ColumnMeta;
14
+ colSpan?: number | null | undefined;
15
+ size?: number;
16
+ };
17
+ export declare function columnsFor(rows: VaultRecord[], properties: Record<string, {
18
+ displayName: string;
19
+ }> | undefined, formulas: Record<string, string>, app?: Pick<App, "metadataTypeManager">): {
20
+ columns: ColumnDef[];
21
+ frontmatter: Record<string, DType>;
22
+ };
@@ -0,0 +1,149 @@
1
+ import { TimeStamp } from "peaql";
2
+ import { getMetadataTypeInfo } from "./metadata-type-info";
3
+ export function columnsFor(rows, properties = {}, formulas, app) {
4
+ const columns = [
5
+ {
6
+ id: "file",
7
+ meta: {
8
+ displayName: properties["file"]?.displayName || "file",
9
+ icon: "lucide-file",
10
+ type: "file",
11
+ },
12
+ },
13
+ {
14
+ id: "file.name",
15
+ meta: {
16
+ displayName: properties["file.name"]?.displayName || "file name",
17
+ icon: "lucide-text",
18
+ type: "text",
19
+ },
20
+ },
21
+ {
22
+ id: "file.basename",
23
+ meta: {
24
+ displayName: properties["file.basename"]?.displayName || "file base name",
25
+ icon: "lucide-text",
26
+ type: "text",
27
+ },
28
+ },
29
+ {
30
+ id: "file.folder",
31
+ meta: {
32
+ displayName: properties["file.folder"]?.displayName || "folder",
33
+ icon: "lucide-text",
34
+ type: "text",
35
+ },
36
+ },
37
+ {
38
+ id: "file.fullname",
39
+ meta: {
40
+ displayName: properties["file.fullname"]?.displayName || "file full name",
41
+ icon: "lucide-text",
42
+ type: "text",
43
+ },
44
+ },
45
+ {
46
+ id: "file.path",
47
+ meta: {
48
+ displayName: properties["file.path"]?.displayName || "file path",
49
+ icon: "lucide-text",
50
+ type: "text",
51
+ },
52
+ },
53
+ {
54
+ id: "file.ext",
55
+ meta: {
56
+ displayName: properties["file.ext"]?.displayName || "file extension",
57
+ icon: "lucide-text",
58
+ type: "text",
59
+ },
60
+ },
61
+ {
62
+ id: "file.ctime",
63
+ meta: {
64
+ displayName: properties["file.ctime"]?.displayName || "created time",
65
+ icon: "lucide-clock",
66
+ type: "datetime",
67
+ },
68
+ },
69
+ {
70
+ id: "file.mtime",
71
+ meta: {
72
+ displayName: properties["file.mtime"]?.displayName || "modified time",
73
+ icon: "lucide-clock",
74
+ type: "datetime",
75
+ },
76
+ },
77
+ {
78
+ id: "file.size",
79
+ meta: {
80
+ displayName: properties["file.size"]?.displayName || "file size",
81
+ icon: "lucide-binary",
82
+ type: "number",
83
+ },
84
+ },
85
+ ];
86
+ const metadata = {};
87
+ rows.forEach((row) => {
88
+ if (row.cache && row.cache.frontmatter) {
89
+ Object.keys(row.cache.frontmatter).forEach((key) => {
90
+ metadata[key] ||= 0;
91
+ metadata[key] += 1;
92
+ });
93
+ }
94
+ });
95
+ for (const key of Object.keys(formulas)) {
96
+ const id = key.match(/^[a-zA-Z0-9_]+$/)
97
+ ? "formula." + key
98
+ : `formula["${key.replaceAll('"', '"')}"]`;
99
+ columns.push({
100
+ id,
101
+ meta: {
102
+ displayName: properties[id]?.displayName || key,
103
+ icon: "lucide-square-function",
104
+ type: "text",
105
+ },
106
+ });
107
+ }
108
+ const frontmatter = {};
109
+ Object.keys(metadata)
110
+ .sort((a, b) => metadata[b] - metadata[a])
111
+ .forEach((key) => {
112
+ const name = key.replaceAll(/[^a-zA-Z0-9]/g, " ");
113
+ const { type, icon } = getMetadataTypeInfo(key, "unknown", app);
114
+ frontmatter[key] = metadataType(type);
115
+ columns.push({
116
+ id: key,
117
+ meta: {
118
+ frontmatter: true,
119
+ displayName: properties[key]?.displayName || name,
120
+ icon,
121
+ type,
122
+ },
123
+ });
124
+ });
125
+ return { columns, frontmatter };
126
+ }
127
+ function metadataType(type) {
128
+ switch (type) {
129
+ case "text":
130
+ return String;
131
+ case "checkbox":
132
+ return Boolean;
133
+ case "number":
134
+ return Number;
135
+ case "date":
136
+ case "datetime":
137
+ return TimeStamp;
138
+ case "tags":
139
+ case "multitext":
140
+ case "aliases":
141
+ return [String];
142
+ case "array":
143
+ return [Object];
144
+ case "object":
145
+ return Object;
146
+ default:
147
+ return Object;
148
+ }
149
+ }
@@ -0,0 +1,15 @@
1
+ import type { App, MetadataType } from "@lapis-notes/api";
2
+ import { type DType } from "peaql";
3
+ import type { BasesPropertyId } from "@lapis-notes/api";
4
+ import type { VaultRecord } from ".";
5
+ export type ColumnDefinition = {
6
+ id: BasesPropertyId;
7
+ displayName: string;
8
+ type: MetadataType;
9
+ icon: string;
10
+ };
11
+ export declare function columnsFor(rows: VaultRecord[], properties: Record<string, {
12
+ displayName: string;
13
+ }> | undefined, formulas: Record<string, string>, app?: Pick<App, "metadataTypeManager">): Record<string, ColumnDefinition>;
14
+ export declare function frontMatterTypesForColumns(columns: Record<string, ColumnDefinition>): Record<string, DType>;
15
+ export declare function metadataType(type: MetadataType): DType;
@@ -0,0 +1,103 @@
1
+ import { inferMetadataPropertyType } from "@lapis-notes/api/metadata-value";
2
+ import { TimeStamp } from "peaql";
3
+ import { buildFileColumns } from "./file-fields-core";
4
+ import { getMetadataTypeInfo } from "./metadata-type-info";
5
+ export function columnsFor(rows, properties = {}, formulas, app) {
6
+ const columns = buildFileColumns(properties).map((column) => ({
7
+ id: column.id,
8
+ displayName: column.displayName,
9
+ icon: column.icon,
10
+ type: column.type,
11
+ }));
12
+ const metadata = {};
13
+ const observedMetadataTypes = {};
14
+ rows.forEach((row) => {
15
+ if (row.cache && row.cache.frontmatter) {
16
+ Object.entries(row.cache.frontmatter).forEach(([key, value]) => {
17
+ metadata[key] ||= 0;
18
+ metadata[key] += 1;
19
+ observedMetadataTypes[key] ??= inferMetadataTypeFromValue(key, value, app);
20
+ });
21
+ }
22
+ });
23
+ for (const key of Object.keys(formulas)) {
24
+ const id = ("formula." + key);
25
+ columns.push({
26
+ id,
27
+ displayName: properties[id]?.displayName || key,
28
+ icon: "lucide-square-function",
29
+ type: "text",
30
+ });
31
+ }
32
+ Object.entries(properties).forEach(([id, property]) => {
33
+ if (!id.startsWith("note.")) {
34
+ return;
35
+ }
36
+ if (columns.some((column) => column.id === id)) {
37
+ return;
38
+ }
39
+ const key = id.slice("note.".length);
40
+ const name = key.replaceAll(/[^a-zA-Z0-9-_]/g, " ");
41
+ const { type, icon } = getMetadataTypeInfo(key, "unknown", app);
42
+ columns.push({
43
+ id: id,
44
+ displayName: property.displayName || name,
45
+ icon,
46
+ type,
47
+ });
48
+ });
49
+ Object.keys(metadata)
50
+ .sort((a, b) => metadata[b] - metadata[a])
51
+ .forEach((key) => {
52
+ const name = key.replaceAll(/[^a-zA-Z0-9-_]/g, " ");
53
+ const { type, icon } = getMetadataTypeInfo(key, observedMetadataTypes[key] ?? "unknown", app);
54
+ columns.push({
55
+ id: key,
56
+ displayName: properties[key]?.displayName || name,
57
+ icon,
58
+ type,
59
+ });
60
+ });
61
+ return columns.reduce((acc, value) => {
62
+ acc[value.id] = value;
63
+ return acc;
64
+ }, {});
65
+ }
66
+ export function frontMatterTypesForColumns(columns) {
67
+ const types = {};
68
+ for (const [id, column] of Object.entries(columns)) {
69
+ if (id === "file" || id.startsWith("file.") || id.startsWith("formula.")) {
70
+ continue;
71
+ }
72
+ const noteId = id.startsWith("note.") ? id : `note.${id}`;
73
+ types[noteId] ??= metadataType(column.type);
74
+ }
75
+ return types;
76
+ }
77
+ export function metadataType(type) {
78
+ switch (type) {
79
+ case "text":
80
+ return String;
81
+ case "checkbox":
82
+ return Boolean;
83
+ case "number":
84
+ return Number;
85
+ case "date":
86
+ case "datetime":
87
+ return TimeStamp;
88
+ case "tags":
89
+ case "multitext":
90
+ case "aliases":
91
+ return [String];
92
+ case "array":
93
+ return [Object];
94
+ case "object":
95
+ return Object;
96
+ default:
97
+ return Object;
98
+ }
99
+ }
100
+ function inferMetadataTypeFromValue(key, value, app) {
101
+ return (app?.metadataTypeManager?.determinePropertyType?.(key, value) ??
102
+ inferMetadataPropertyType(key, value));
103
+ }
@@ -0,0 +1,14 @@
1
+ <script lang="ts">
2
+ import Tag from "./tag-chip.svelte";
3
+
4
+ let {
5
+ class: className,
6
+ name,
7
+ ...props
8
+ }: {
9
+ class?: string;
10
+ name: string;
11
+ } = $props();
12
+ </script>
13
+
14
+ <Tag class={className} {name} {...props} />
@@ -0,0 +1,8 @@
1
+ import Tag from "./tag-chip.svelte";
2
+ type $$ComponentProps = {
3
+ class?: string;
4
+ name: string;
5
+ };
6
+ declare const Tag: import("svelte").Component<$$ComponentProps, {}, "">;
7
+ type Tag = ReturnType<typeof Tag>;
8
+ export default Tag;
@@ -0,0 +1,45 @@
1
+ <script lang="ts">
2
+ import { cn } from "@lapis-notes/api";
3
+ import AutocompleteInput from "@lapismd/design-core/forms/AutocompleteInput.svelte";
4
+
5
+ type Options = { label: string; value: string; icon?: string };
6
+
7
+ let {
8
+ value = $bindable(""),
9
+ options,
10
+ placeholder = "Find or create",
11
+ class: className,
12
+ onSelect,
13
+ id,
14
+ "aria-label": ariaLabel,
15
+ }: {
16
+ value: string;
17
+ options: Array<Options> | (() => Array<Options>);
18
+ placeholder?: string;
19
+ class?: string;
20
+ onSelect?: (value: string) => void;
21
+ id?: string;
22
+ "aria-label"?: string;
23
+ } = $props();
24
+
25
+ let suggestions = $derived.by(() => {
26
+ const opts = Array.isArray(options) ? options : options();
27
+ return [...new Set(opts.map((option) => option.value).filter(Boolean))];
28
+ });
29
+ </script>
30
+
31
+ <div
32
+ class={cn("bases-autocomplete", className)}
33
+ data-ui-component="bases-autocomplete"
34
+ data-ui-part="root"
35
+ >
36
+ <AutocompleteInput
37
+ {id}
38
+ bind:value
39
+ {suggestions}
40
+ {placeholder}
41
+ ariaLabel={ariaLabel ?? placeholder ?? "Autocomplete"}
42
+ commitOnBlur
43
+ onCommit={(committedValue) => onSelect?.(committedValue)}
44
+ />
45
+ </div>
@@ -0,0 +1,17 @@
1
+ type Options = {
2
+ label: string;
3
+ value: string;
4
+ icon?: string;
5
+ };
6
+ type $$ComponentProps = {
7
+ value: string;
8
+ options: Array<Options> | (() => Array<Options>);
9
+ placeholder?: string;
10
+ class?: string;
11
+ onSelect?: (value: string) => void;
12
+ id?: string;
13
+ "aria-label"?: string;
14
+ };
15
+ declare const Autocomplete: import("svelte").Component<$$ComponentProps, {}, "value">;
16
+ type Autocomplete = ReturnType<typeof Autocomplete>;
17
+ export default Autocomplete;
@@ -0,0 +1,121 @@
1
+ <script lang="ts">
2
+ import { TFile, type App } from "@lapis-notes/api";
3
+ import { loadBasesResourceUrl } from "../resource-url";
4
+
5
+ const IMAGE_EXTENSIONS = new Set([
6
+ "apng",
7
+ "avif",
8
+ "bmp",
9
+ "gif",
10
+ "ico",
11
+ "jpeg",
12
+ "jpg",
13
+ "png",
14
+ "svg",
15
+ "tif",
16
+ "tiff",
17
+ "webp",
18
+ ]);
19
+
20
+ let {
21
+ app,
22
+ value,
23
+ sourceFile = null,
24
+ height,
25
+ fit = "contain",
26
+ }: {
27
+ app: App;
28
+ value: unknown;
29
+ sourceFile?: TFile | null;
30
+ height: number;
31
+ fit?: string;
32
+ } = $props();
33
+
34
+ let resourceUrl = $state("");
35
+ let imageFile = $derived(resolveImageFile(value, sourceFile));
36
+
37
+ function unwrapValue(value: unknown): unknown {
38
+ if (value instanceof TFile) {
39
+ return value;
40
+ }
41
+
42
+ if (value && typeof value === "object") {
43
+ const candidate = value as { file?: unknown; value?: unknown };
44
+ if (candidate.file instanceof TFile) {
45
+ return candidate.file;
46
+ }
47
+
48
+ if ("value" in candidate) {
49
+ return candidate.value;
50
+ }
51
+ }
52
+
53
+ return value;
54
+ }
55
+
56
+ function imagePathFromText(value: string): string {
57
+ const trimmed = value.trim();
58
+ const embedMatch = /^!?\[\[([^\]|]+)(?:\|[^\]]*)?\]\]$/u.exec(trimmed);
59
+ if (embedMatch) {
60
+ return embedMatch[1].trim();
61
+ }
62
+
63
+ const markdownImageMatch = /^!\[[^\]]*\]\(([^)]+)\)$/u.exec(trimmed);
64
+ if (markdownImageMatch) {
65
+ return markdownImageMatch[1].trim();
66
+ }
67
+
68
+ return trimmed;
69
+ }
70
+
71
+ function isImagePath(path: string): boolean {
72
+ const extensionIndex = path.lastIndexOf(".");
73
+ if (extensionIndex === -1) {
74
+ return false;
75
+ }
76
+ return IMAGE_EXTENSIONS.has(path.slice(extensionIndex + 1).toLowerCase());
77
+ }
78
+
79
+ function resolveImageFile(
80
+ value: unknown,
81
+ sourceFile: TFile | null,
82
+ ): TFile | null {
83
+ const unwrapped = unwrapValue(value);
84
+ if (unwrapped instanceof TFile) {
85
+ return isImagePath(unwrapped.path) ? unwrapped : null;
86
+ }
87
+
88
+ if (typeof unwrapped !== "string") {
89
+ return null;
90
+ }
91
+
92
+ const imagePath = imagePathFromText(unwrapped);
93
+ if (!isImagePath(imagePath)) {
94
+ return null;
95
+ }
96
+
97
+ return (
98
+ app.metadataCache.getFirstLinkpathDest(
99
+ imagePath,
100
+ sourceFile?.path ?? "",
101
+ ) ?? app.vault.getFileByPath(imagePath)
102
+ );
103
+ }
104
+
105
+ $effect(() => {
106
+ resourceUrl = "";
107
+
108
+ if (!imageFile) {
109
+ return;
110
+ }
111
+
112
+ return loadBasesResourceUrl(app, imageFile, (url) => {
113
+ resourceUrl = url;
114
+ });
115
+ });
116
+ </script>
117
+
118
+ <div
119
+ class="bases-card__image bases-style-rounded-t-lg-bc0d7f"
120
+ style={`height: ${height}px; background-size: ${fit}; background-image: ${resourceUrl ? `url("${resourceUrl}")` : "none"}; background-position: center; background-repeat: no-repeat;`}
121
+ ></div>
@@ -0,0 +1,11 @@
1
+ import { TFile, type App } from "@lapis-notes/api";
2
+ type $$ComponentProps = {
3
+ app: App;
4
+ value: unknown;
5
+ sourceFile?: TFile | null;
6
+ height: number;
7
+ fit?: string;
8
+ };
9
+ declare const CardImage: import("svelte").Component<$$ComponentProps, {}, "">;
10
+ type CardImage = ReturnType<typeof CardImage>;
11
+ export default CardImage;