@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.
- package/CHANGELOG.md +6 -0
- package/LICENSE.md +8 -0
- package/README.md +20 -0
- package/dist/bases-plugin.d.ts +10 -0
- package/dist/bases-plugin.js +118 -0
- package/dist/bases-view/app-database-query-source.d.ts +30 -0
- package/dist/bases-view/app-database-query-source.js +248 -0
- package/dist/bases-view/bases.svelte.d.ts +569 -0
- package/dist/bases-view/bases.svelte.js +910 -0
- package/dist/bases-view/card-view/components/card-placeholder.svelte +68 -0
- package/dist/bases-view/card-view/components/card-placeholder.svelte.d.ts +7 -0
- package/dist/bases-view/card-view/components/card.svelte +289 -0
- package/dist/bases-view/card-view/components/card.svelte.d.ts +7 -0
- package/dist/bases-view/card-view/index.d.ts +11 -0
- package/dist/bases-view/card-view/index.js +55 -0
- package/dist/bases-view/cell-editor-options.d.ts +2 -0
- package/dist/bases-view/cell-editor-options.js +26 -0
- package/dist/bases-view/cell-editor.svelte +206 -0
- package/dist/bases-view/cell-editor.svelte.d.ts +12 -0
- package/dist/bases-view/cell.svelte +132 -0
- package/dist/bases-view/cell.svelte.d.ts +16 -0
- package/dist/bases-view/column-definition.d.ts +22 -0
- package/dist/bases-view/column-definition.js +149 -0
- package/dist/bases-view/columns.d.ts +15 -0
- package/dist/bases-view/columns.js +103 -0
- package/dist/bases-view/components/Tag.svelte +14 -0
- package/dist/bases-view/components/Tag.svelte.d.ts +8 -0
- package/dist/bases-view/components/autocomplete.svelte +45 -0
- package/dist/bases-view/components/autocomplete.svelte.d.ts +17 -0
- package/dist/bases-view/components/card-image.svelte +121 -0
- package/dist/bases-view/components/card-image.svelte.d.ts +11 -0
- package/dist/bases-view/components/column-visibility.svelte +388 -0
- package/dist/bases-view/components/column-visibility.svelte.d.ts +13 -0
- package/dist/bases-view/components/datetime.svelte +35 -0
- package/dist/bases-view/components/datetime.svelte.d.ts +7 -0
- package/dist/bases-view/components/file.svelte +31 -0
- package/dist/bases-view/components/file.svelte.d.ts +8 -0
- package/dist/bases-view/components/filters/filter-editor.svelte +102 -0
- package/dist/bases-view/components/filters/filter-editor.svelte.d.ts +10 -0
- package/dist/bases-view/components/filters/filter-group.svelte +142 -0
- package/dist/bases-view/components/filters/filter-group.svelte.d.ts +11 -0
- package/dist/bases-view/components/filters/filter-properties.svelte +77 -0
- package/dist/bases-view/components/filters/filter-properties.svelte.d.ts +8 -0
- package/dist/bases-view/components/filters/filter-root.svelte +112 -0
- package/dist/bases-view/components/filters/filter-root.svelte.d.ts +12 -0
- package/dist/bases-view/components/filters/filter-row.svelte +351 -0
- package/dist/bases-view/components/filters/filter-row.svelte.d.ts +11 -0
- package/dist/bases-view/components/group/group-root.svelte +120 -0
- package/dist/bases-view/components/group/group-root.svelte.d.ts +8 -0
- package/dist/bases-view/components/limit.svelte +100 -0
- package/dist/bases-view/components/limit.svelte.d.ts +12 -0
- package/dist/bases-view/components/query-editor.svelte +230 -0
- package/dist/bases-view/components/query-editor.svelte.d.ts +15 -0
- package/dist/bases-view/components/sort/sort-direction-labels.d.ts +9 -0
- package/dist/bases-view/components/sort/sort-direction-labels.js +25 -0
- package/dist/bases-view/components/sort/sort-root.svelte +239 -0
- package/dist/bases-view/components/sort/sort-root.svelte.d.ts +11 -0
- package/dist/bases-view/components/sort/sort-row.svelte +190 -0
- package/dist/bases-view/components/sort/sort-row.svelte.d.ts +15 -0
- package/dist/bases-view/components/summary-strip.svelte +56 -0
- package/dist/bases-view/components/summary-strip.svelte.d.ts +8 -0
- package/dist/bases-view/components/tag-chip.svelte +47 -0
- package/dist/bases-view/components/tag-chip.svelte.d.ts +12 -0
- package/dist/bases-view/components/views.svelte +178 -0
- package/dist/bases-view/components/views.svelte.d.ts +12 -0
- package/dist/bases-view/data-table-adapter/data-table.svelte.d.ts +45 -0
- package/dist/bases-view/data-table-adapter/data-table.svelte.js +112 -0
- package/dist/bases-view/data-table-adapter/flex-render.svelte +43 -0
- package/dist/bases-view/data-table-adapter/flex-render.svelte.d.ts +30 -0
- package/dist/bases-view/data-table-adapter/index.d.ts +3 -0
- package/dist/bases-view/data-table-adapter/index.js +3 -0
- package/dist/bases-view/data-table-adapter/render-helpers.d.ts +101 -0
- package/dist/bases-view/data-table-adapter/render-helpers.js +110 -0
- package/dist/bases-view/db.d.ts +31 -0
- package/dist/bases-view/db.js +174 -0
- package/dist/bases-view/document-core.d.ts +2 -0
- package/dist/bases-view/document-core.js +166 -0
- package/dist/bases-view/export-core.d.ts +4 -0
- package/dist/bases-view/export-core.js +31 -0
- package/dist/bases-view/file-fields-core.d.ts +31 -0
- package/dist/bases-view/file-fields-core.js +114 -0
- package/dist/bases-view/filter-parser.d.ts +27 -0
- package/dist/bases-view/filter-parser.js +315 -0
- package/dist/bases-view/functions-core.d.ts +66 -0
- package/dist/bases-view/functions-core.js +265 -0
- package/dist/bases-view/functions.d.ts +5 -0
- package/dist/bases-view/functions.js +107 -0
- package/dist/bases-view/fuzzy-search.d.ts +6 -0
- package/dist/bases-view/fuzzy-search.js +15 -0
- package/dist/bases-view/hooks/useResizeObserver.svelte.d.ts +7 -0
- package/dist/bases-view/hooks/useResizeObserver.svelte.js +26 -0
- package/dist/bases-view/index.d.ts +66 -0
- package/dist/bases-view/index.js +231 -0
- package/dist/bases-view/list-view/index.d.ts +10 -0
- package/dist/bases-view/list-view/index.js +17 -0
- package/dist/bases-view/list-view/list.svelte +156 -0
- package/dist/bases-view/list-view/list.svelte.d.ts +7 -0
- package/dist/bases-view/map-view/index.d.ts +10 -0
- package/dist/bases-view/map-view/index.js +17 -0
- package/dist/bases-view/map-view/view.svelte +28 -0
- package/dist/bases-view/map-view/view.svelte.d.ts +7 -0
- package/dist/bases-view/metadata-invalidation-core.d.ts +34 -0
- package/dist/bases-view/metadata-invalidation-core.js +162 -0
- package/dist/bases-view/metadata-type-info.d.ts +7 -0
- package/dist/bases-view/metadata-type-info.js +10 -0
- package/dist/bases-view/models.d.ts +90 -0
- package/dist/bases-view/models.js +133 -0
- package/dist/bases-view/query-result-core.d.ts +8 -0
- package/dist/bases-view/query-result-core.js +16 -0
- package/dist/bases-view/resource-url.d.ts +2 -0
- package/dist/bases-view/resource-url.js +21 -0
- package/dist/bases-view/search-core.d.ts +9 -0
- package/dist/bases-view/search-core.js +20 -0
- package/dist/bases-view/summary-core.d.ts +7 -0
- package/dist/bases-view/summary-core.js +17 -0
- package/dist/bases-view/table-view/components/div-table.svelte +464 -0
- package/dist/bases-view/table-view/components/div-table.svelte.d.ts +32 -0
- package/dist/bases-view/table-view/components/dnd-style.d.ts +3 -0
- package/dist/bases-view/table-view/components/dnd-style.js +6 -0
- package/dist/bases-view/table-view/components/sort-header.svelte +48 -0
- package/dist/bases-view/table-view/components/sort-header.svelte.d.ts +11 -0
- package/dist/bases-view/table-view/components/table-column-tracks.d.ts +14 -0
- package/dist/bases-view/table-view/components/table-column-tracks.js +27 -0
- package/dist/bases-view/table-view/components/table-header.svelte +146 -0
- package/dist/bases-view/table-view/components/table-header.svelte.d.ts +10 -0
- package/dist/bases-view/table-view/components/table-placeholder.svelte +46 -0
- package/dist/bases-view/table-view/components/table-placeholder.svelte.d.ts +30 -0
- package/dist/bases-view/table-view/components/table-virtualizer-core.d.ts +13 -0
- package/dist/bases-view/table-view/components/table-virtualizer-core.js +12 -0
- package/dist/bases-view/table-view/components/table.svelte +997 -0
- package/dist/bases-view/table-view/components/table.svelte.d.ts +32 -0
- package/dist/bases-view/table-view/index.svelte.d.ts +10 -0
- package/dist/bases-view/table-view/index.svelte.js +30 -0
- package/dist/bases-view/unknown-view/index.d.ts +10 -0
- package/dist/bases-view/unknown-view/index.js +19 -0
- package/dist/bases-view/unknown-view/view.svelte +11 -0
- package/dist/bases-view/unknown-view/view.svelte.d.ts +6 -0
- package/dist/bases-view/view-header.svelte +142 -0
- package/dist/bases-view/view-header.svelte.d.ts +28 -0
- package/dist/bases-view/view-registration-inventory.d.ts +22 -0
- package/dist/bases-view/view-registration-inventory.js +7 -0
- package/dist/bases-view/view-settings.svelte +350 -0
- package/dist/bases-view/view-settings.svelte.d.ts +9 -0
- package/dist/bases-view/view.svelte +192 -0
- package/dist/bases-view/view.svelte.d.ts +15 -0
- package/dist/bases-view-surface.svelte +31 -0
- package/dist/bases-view-surface.svelte.d.ts +14 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +8 -0
- package/dist/serialized-write-queue.d.ts +10 -0
- package/dist/serialized-write-queue.js +36 -0
- package/dist/styles.css +2164 -0
- package/manifest.json +33 -0
- package/package.json +90 -0
- package/styles.css +1 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import { FileView, MarkdownView, TFile, useLocale, View, WorkspaceLeaf, } from "@lapis-notes/api";
|
|
2
|
+
import { mount, unmount } from "svelte";
|
|
3
|
+
import {} from "./models";
|
|
4
|
+
import NoteEditor from "@lapis-notes/api/editor";
|
|
5
|
+
import * as yaml from "js-yaml";
|
|
6
|
+
import { TableView } from "./table-view/index.svelte";
|
|
7
|
+
import { UnknownView } from "./unknown-view";
|
|
8
|
+
import { CardView } from "./card-view";
|
|
9
|
+
import { ListView } from "./list-view";
|
|
10
|
+
import { MapView } from "./map-view";
|
|
11
|
+
import { normalizeBasesDocument } from "./document-core";
|
|
12
|
+
import { SerializedWriteQueue } from "../serialized-write-queue";
|
|
13
|
+
import { BUILT_IN_BASES_VIEW_ITEMS, } from "./view-registration-inventory";
|
|
14
|
+
export * from "./models";
|
|
15
|
+
export const BasesViewType = "bases";
|
|
16
|
+
const { t } = useLocale("bases");
|
|
17
|
+
export const vaultKey = Symbol("vaultKey");
|
|
18
|
+
export function normalizeName(name) {
|
|
19
|
+
return name.replaceAll(/[^a-zA-Z0-9 ]/g, " ").trim();
|
|
20
|
+
}
|
|
21
|
+
export function columnName(column) {
|
|
22
|
+
if (!column)
|
|
23
|
+
return "";
|
|
24
|
+
return column.columnDef.meta?.displayName ?? normalizeName(column.id);
|
|
25
|
+
}
|
|
26
|
+
export function serializeBasesDocument(content) {
|
|
27
|
+
const data = yaml
|
|
28
|
+
.dump(content, {
|
|
29
|
+
noCompatMode: true,
|
|
30
|
+
schema: yaml.JSON_SCHEMA,
|
|
31
|
+
})
|
|
32
|
+
.trim();
|
|
33
|
+
return data;
|
|
34
|
+
}
|
|
35
|
+
/** @deprecated Use serializeBasesDocument. */
|
|
36
|
+
export const dumpDocument = serializeBasesDocument;
|
|
37
|
+
export function registerBuiltInBasesViews(views) {
|
|
38
|
+
const implementations = {
|
|
39
|
+
table: {
|
|
40
|
+
factory: (controller, containerEl) => new TableView(controller, containerEl),
|
|
41
|
+
options: TableView.getViewOptions,
|
|
42
|
+
},
|
|
43
|
+
unknown: {
|
|
44
|
+
factory: (controller, containerEl) => new UnknownView(controller, containerEl),
|
|
45
|
+
options: UnknownView.getViewOptions,
|
|
46
|
+
},
|
|
47
|
+
cards: {
|
|
48
|
+
factory: (controller, containerEl) => new CardView(controller, containerEl),
|
|
49
|
+
options: CardView.getViewOptions,
|
|
50
|
+
},
|
|
51
|
+
list: {
|
|
52
|
+
factory: (controller, containerEl) => new ListView(controller, containerEl),
|
|
53
|
+
options: ListView.getViewOptions,
|
|
54
|
+
},
|
|
55
|
+
map: {
|
|
56
|
+
factory: (controller, containerEl) => new MapView(controller, containerEl),
|
|
57
|
+
options: MapView.getViewOptions,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
for (const item of BUILT_IN_BASES_VIEW_ITEMS) {
|
|
61
|
+
views.set(item.id, { ...item, ...implementations[item.id] });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function createBasesViewRegistrations(app, registrations) {
|
|
65
|
+
const views = new Map();
|
|
66
|
+
registerBuiltInBasesViews(views);
|
|
67
|
+
for (const [viewId, registration,] of app.plugins.getBasesViewRegistrations()) {
|
|
68
|
+
views.set(viewId, registration);
|
|
69
|
+
}
|
|
70
|
+
for (const [viewId, registration] of registrations ?? []) {
|
|
71
|
+
views.set(viewId, registration);
|
|
72
|
+
}
|
|
73
|
+
return views;
|
|
74
|
+
}
|
|
75
|
+
export function parseBasesDocument(content) {
|
|
76
|
+
return normalizeBasesDocument(yaml.load(content));
|
|
77
|
+
}
|
|
78
|
+
export class BasesView extends MarkdownView {
|
|
79
|
+
views;
|
|
80
|
+
writeQueue;
|
|
81
|
+
constructor(leaf) {
|
|
82
|
+
super(leaf);
|
|
83
|
+
this.state["mode"] ||= "preview";
|
|
84
|
+
this.views = createBasesViewRegistrations(this.app);
|
|
85
|
+
this.writeQueue = new SerializedWriteQueue(({ file, content }) => this.app.vault.modify(file, content));
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Register a Base view handler that can be used to render data from property
|
|
89
|
+
* queries.
|
|
90
|
+
*
|
|
91
|
+
* @since 1.10.0
|
|
92
|
+
* @returns False if bases are not enabled in this vault.
|
|
93
|
+
* @public
|
|
94
|
+
*/
|
|
95
|
+
registerBasesView(viewId, registration) {
|
|
96
|
+
this.views.set(viewId, registration);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
getMode() {
|
|
100
|
+
return this.getState()["mode"] || "preview";
|
|
101
|
+
}
|
|
102
|
+
setState(state, result) {
|
|
103
|
+
const previous = { ...this.getState() };
|
|
104
|
+
return super.setState(state, result).then(() => {
|
|
105
|
+
if (state.mode !== previous.mode) {
|
|
106
|
+
this.load();
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
getViewData() {
|
|
111
|
+
return this.editor.getValue();
|
|
112
|
+
}
|
|
113
|
+
setViewData(data, clear) {
|
|
114
|
+
this.editor.setValue(data);
|
|
115
|
+
}
|
|
116
|
+
clear() {
|
|
117
|
+
this.editor.setValue("");
|
|
118
|
+
}
|
|
119
|
+
canAcceptExtension(extension) {
|
|
120
|
+
return ["bases", "base"].includes(extension);
|
|
121
|
+
}
|
|
122
|
+
component;
|
|
123
|
+
previewLoadVersion = 0;
|
|
124
|
+
onOpen() {
|
|
125
|
+
return Promise.resolve();
|
|
126
|
+
}
|
|
127
|
+
async onClose() {
|
|
128
|
+
await this.writeQueue.flush();
|
|
129
|
+
}
|
|
130
|
+
load() {
|
|
131
|
+
if (this.containerEl) {
|
|
132
|
+
const loadVersion = ++this.previewLoadVersion;
|
|
133
|
+
this.unload();
|
|
134
|
+
this.containerEl.empty();
|
|
135
|
+
this.actions = [];
|
|
136
|
+
const mode = this.getMode();
|
|
137
|
+
if (mode === "preview") {
|
|
138
|
+
this.containerEl.addClass("mod-loader");
|
|
139
|
+
this.addAction("pencil", `${t("Current view: preview")}\n${t("Click to edit")}\n${t("⌘+Click to open to the right")}`, (evt) => {
|
|
140
|
+
if (evt.metaKey || evt.ctrlKey) {
|
|
141
|
+
const leaf = this.app.workspace.getLeaf("split", "horizontal");
|
|
142
|
+
const state = { ...this.leaf.state };
|
|
143
|
+
state.state ||= {};
|
|
144
|
+
state.state["mode"] = "source";
|
|
145
|
+
leaf.setViewState(state);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
this.setState({ ...this.getState(), mode: "source" });
|
|
149
|
+
}
|
|
150
|
+
this.app.workspace.requestSaveLayout();
|
|
151
|
+
});
|
|
152
|
+
const doc = parseBasesDocument(this.editor.getValue());
|
|
153
|
+
void import("./view.svelte").then(({ default: BasesComponent }) => {
|
|
154
|
+
if (loadVersion !== this.previewLoadVersion ||
|
|
155
|
+
this.getMode() !== "preview" ||
|
|
156
|
+
!this.containerEl) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
this.component = mount(BasesComponent, {
|
|
160
|
+
target: this.containerEl,
|
|
161
|
+
props: {
|
|
162
|
+
app: this.app,
|
|
163
|
+
host: this,
|
|
164
|
+
registrations: this.views,
|
|
165
|
+
onChange: (doc) => {
|
|
166
|
+
const content = serializeBasesDocument(doc);
|
|
167
|
+
this.editor.setValue(content);
|
|
168
|
+
if (this.file) {
|
|
169
|
+
this.writeQueue.enqueue({
|
|
170
|
+
file: this.file,
|
|
171
|
+
content,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
readOnly: false,
|
|
176
|
+
showHeader: true,
|
|
177
|
+
document: doc,
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
this.containerEl.removeClass("mod-loader");
|
|
184
|
+
this.editor.updateExtensions(this.app.editorExtensions(BasesViewType, {
|
|
185
|
+
file: this.file?.path,
|
|
186
|
+
mode: "source",
|
|
187
|
+
}));
|
|
188
|
+
this.addAction("book-open", `${t("Current view: editing")}\n${t("Click to read")}\n${t("⌘+Click to open to the right")}`, (evt) => {
|
|
189
|
+
if (evt.metaKey || evt.ctrlKey) {
|
|
190
|
+
const leaf = this.app.workspace.getLeaf("split", "horizontal");
|
|
191
|
+
const state = { ...this.leaf.state };
|
|
192
|
+
state.state ||= {};
|
|
193
|
+
state.state["mode"] = "preview";
|
|
194
|
+
leaf.setViewState(state);
|
|
195
|
+
}
|
|
196
|
+
else {
|
|
197
|
+
this.setState({ ...this.getState(), mode: "preview" });
|
|
198
|
+
}
|
|
199
|
+
this.app.workspace.requestSaveLayout();
|
|
200
|
+
});
|
|
201
|
+
this.component = mount(NoteEditor, {
|
|
202
|
+
target: this.containerEl,
|
|
203
|
+
props: {
|
|
204
|
+
app: this.app,
|
|
205
|
+
leaf: this.leaf,
|
|
206
|
+
editor: this.editor,
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
refresh() {
|
|
213
|
+
this.load();
|
|
214
|
+
}
|
|
215
|
+
onunload() {
|
|
216
|
+
void this.writeQueue.flush();
|
|
217
|
+
if (this.component) {
|
|
218
|
+
unmount(this.component);
|
|
219
|
+
this.component = null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
getViewType() {
|
|
223
|
+
return BasesViewType;
|
|
224
|
+
}
|
|
225
|
+
getIcon() {
|
|
226
|
+
return "lucide-database";
|
|
227
|
+
}
|
|
228
|
+
getDisplayText() {
|
|
229
|
+
return this.file?.baseName ?? t("Bases");
|
|
230
|
+
}
|
|
231
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BasesOptions } from "@lapis-notes/api";
|
|
2
|
+
import { BasesView, QueryController } from "../bases.svelte";
|
|
3
|
+
export declare class ListView extends BasesView {
|
|
4
|
+
readonly controller: QueryController;
|
|
5
|
+
readonly scrollEl: HTMLElement;
|
|
6
|
+
type: string;
|
|
7
|
+
constructor(controller: QueryController, scrollEl: HTMLElement);
|
|
8
|
+
onDataUpdated(): void;
|
|
9
|
+
static getViewOptions(): BasesOptions[];
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BasesView, QueryController } from "../bases.svelte";
|
|
2
|
+
import ListViewComponent from "./list.svelte";
|
|
3
|
+
export class ListView extends BasesView {
|
|
4
|
+
controller;
|
|
5
|
+
scrollEl;
|
|
6
|
+
type = "list";
|
|
7
|
+
constructor(controller, scrollEl) {
|
|
8
|
+
super(controller);
|
|
9
|
+
this.controller = controller;
|
|
10
|
+
this.scrollEl = scrollEl;
|
|
11
|
+
this.mountViewComponent(ListViewComponent, { view: this }, scrollEl);
|
|
12
|
+
}
|
|
13
|
+
onDataUpdated() { }
|
|
14
|
+
static getViewOptions() {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { MetadataType } from "@lapis-notes/api";
|
|
3
|
+
import ChevronDown from "@lucide/svelte/icons/chevron-down";
|
|
4
|
+
import ChevronRight from "@lucide/svelte/icons/chevron-right";
|
|
5
|
+
import Cell from "../cell.svelte";
|
|
6
|
+
import type { BasesView } from "../bases.svelte";
|
|
7
|
+
import SummaryStrip from "../components/summary-strip.svelte";
|
|
8
|
+
import { getMetadataTypeInfo } from "../metadata-type-info";
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
view,
|
|
12
|
+
}: {
|
|
13
|
+
view: BasesView;
|
|
14
|
+
} = $props();
|
|
15
|
+
|
|
16
|
+
let groups = $derived(view.data.groupedData);
|
|
17
|
+
let groupBy = $derived(view.data.groupBy);
|
|
18
|
+
let groupLabel = $derived.by(() => {
|
|
19
|
+
if (!groupBy) return "";
|
|
20
|
+
return view.config.getDisplayName(groupBy) || groupBy;
|
|
21
|
+
});
|
|
22
|
+
let types = $derived.by(() => {
|
|
23
|
+
return view.allProperties.reduce<Record<string, { type: MetadataType }>>(
|
|
24
|
+
(acc, id) => {
|
|
25
|
+
if (id.startsWith("note.")) {
|
|
26
|
+
const key = id.substring(5);
|
|
27
|
+
acc[id] = {
|
|
28
|
+
type: getMetadataTypeInfo(
|
|
29
|
+
key,
|
|
30
|
+
"text",
|
|
31
|
+
view.controller.app,
|
|
32
|
+
).type,
|
|
33
|
+
};
|
|
34
|
+
} else {
|
|
35
|
+
acc[id] = { type: "text" };
|
|
36
|
+
}
|
|
37
|
+
return acc;
|
|
38
|
+
},
|
|
39
|
+
{},
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
let visibleProperties = $derived(view.config.getOrder());
|
|
43
|
+
let showsFileIdentity = $derived.by(() => {
|
|
44
|
+
return visibleProperties.some((id) =>
|
|
45
|
+
[
|
|
46
|
+
"file",
|
|
47
|
+
"file.name",
|
|
48
|
+
"file.basename",
|
|
49
|
+
"file.file",
|
|
50
|
+
"file.fullname",
|
|
51
|
+
].includes(id),
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
let collapsedGroups = $state<Record<string, boolean>>({});
|
|
55
|
+
|
|
56
|
+
function groupId(
|
|
57
|
+
group: { key?: { toString(): string } | null },
|
|
58
|
+
index: number,
|
|
59
|
+
) {
|
|
60
|
+
return `${groupBy || "ungrouped"}:${group.key?.toString() ?? `ungrouped_${index}`}`;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function isCollapsed(
|
|
64
|
+
group: { key?: { toString(): string } | null },
|
|
65
|
+
index: number,
|
|
66
|
+
) {
|
|
67
|
+
return !!collapsedGroups[groupId(group, index)];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function toggleGroup(
|
|
71
|
+
group: { key?: { toString(): string } | null },
|
|
72
|
+
index: number,
|
|
73
|
+
) {
|
|
74
|
+
const key = groupId(group, index);
|
|
75
|
+
collapsedGroups = {
|
|
76
|
+
...collapsedGroups,
|
|
77
|
+
[key]: !collapsedGroups[key],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
</script>
|
|
81
|
+
|
|
82
|
+
<div
|
|
83
|
+
class="bases-card-grid bases-style-h-full-668b21 bases-style-overflow-auto-73fc3f bases-style-px-4-f0faeb bases-style-pb-10-cbd82b"
|
|
84
|
+
data-layout="list"
|
|
85
|
+
data-ui-component="bases-list-view"
|
|
86
|
+
data-ui-part="viewport"
|
|
87
|
+
>
|
|
88
|
+
<SummaryStrip
|
|
89
|
+
{view}
|
|
90
|
+
class="bases-card-grid__summary sticky bases-style-top-0-216740 bases-style-z-20-145745 bases-style-border-b-65fdba bases-style-px-1-d8e0e3 bases-style-py-3-1b2d54 backdrop-blur"
|
|
91
|
+
/>
|
|
92
|
+
{#each groups as group, index (index)}
|
|
93
|
+
{#if groupBy}
|
|
94
|
+
<div
|
|
95
|
+
class="bases-card-grid__group-header sticky bases-style-top-0-216740 bases-style-z-10-236812 bases-style-border-b-65fdba bases-style-px-1-d8e0e3 bases-style-py-3-1b2d54 bases-style-text-xs-359090 bases-style-font-semibold-e83a70 bases-style-tracking-0-18em-a82f6f uppercase backdrop-blur"
|
|
96
|
+
>
|
|
97
|
+
<button
|
|
98
|
+
type="button"
|
|
99
|
+
data-ui-part="group-toggle"
|
|
100
|
+
class="bases-style-flex-60fbb7 bases-style-w-full-6da6a3 bases-style-items-center-3960ff bases-style-gap-2-77a2a2 bases-style-text-left-2eba0d"
|
|
101
|
+
aria-expanded={!isCollapsed(group, index)}
|
|
102
|
+
onclick={() => toggleGroup(group, index)}
|
|
103
|
+
>
|
|
104
|
+
{#if isCollapsed(group, index)}
|
|
105
|
+
<ChevronRight class="bases-style-size-4-f7b5fa bases-style-shrink-0-012fbd" />
|
|
106
|
+
{:else}
|
|
107
|
+
<ChevronDown class="bases-style-size-4-f7b5fa bases-style-shrink-0-012fbd" />
|
|
108
|
+
{/if}
|
|
109
|
+
<span>{groupLabel}</span>
|
|
110
|
+
<span class="bases-card-grid__group-value">
|
|
111
|
+
{#if group.hasKey()}
|
|
112
|
+
{group.key?.toString()}
|
|
113
|
+
{:else}
|
|
114
|
+
Ungrouped
|
|
115
|
+
{/if}
|
|
116
|
+
</span>
|
|
117
|
+
</button>
|
|
118
|
+
</div>
|
|
119
|
+
{/if}
|
|
120
|
+
|
|
121
|
+
{#if !isCollapsed(group, index)}
|
|
122
|
+
<ul class="bases-style-marker-text-muted-foreground-ff5bf1 bases-style-list-disc-1f33b4 bases-style-space-y-2-6f7e01 bases-style-py-3-1b2d54 bases-style-pl-6-9079b6">
|
|
123
|
+
{#each group.entries as row (row.id)}
|
|
124
|
+
<li
|
|
125
|
+
class="bases-style-text-card-foreground-0474d7 bases-style-text-sm-fc7473 bases-style-leading-6-18550d"
|
|
126
|
+
data-ui-part="row"
|
|
127
|
+
>
|
|
128
|
+
{#if !showsFileIdentity}
|
|
129
|
+
<span class="bases-style-font-medium-2689f3">{row.file.basename}</span>
|
|
130
|
+
{#if visibleProperties.length > 0}
|
|
131
|
+
<span class="bases-style-text-muted-foreground-bfa603">, </span>
|
|
132
|
+
{/if}
|
|
133
|
+
{/if}
|
|
134
|
+
|
|
135
|
+
{#each visibleProperties as id, index (id)}
|
|
136
|
+
<span class="bases-style-inline-block-bb0c4b bases-style-align-baseline-8d378d">
|
|
137
|
+
<Cell
|
|
138
|
+
app={view.controller.app}
|
|
139
|
+
name={id}
|
|
140
|
+
file={row.file}
|
|
141
|
+
readOnly={view.controller.readOnly}
|
|
142
|
+
type={types[id]?.type}
|
|
143
|
+
value={row.getValue(id)}
|
|
144
|
+
class="bases-style-inline-block-bb0c4b bases-style-h-auto-b8f0a0 bases-style-w-auto-23e1f6 bases-style-align-baseline-8d378d"
|
|
145
|
+
/>
|
|
146
|
+
</span>
|
|
147
|
+
{#if index < visibleProperties.length - 1}
|
|
148
|
+
<span class="bases-style-text-muted-foreground-bfa603">, </span>
|
|
149
|
+
{/if}
|
|
150
|
+
{/each}
|
|
151
|
+
</li>
|
|
152
|
+
{/each}
|
|
153
|
+
</ul>
|
|
154
|
+
{/if}
|
|
155
|
+
{/each}
|
|
156
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { BasesOptions } from "@lapis-notes/api";
|
|
2
|
+
import { BasesView, QueryController } from "../bases.svelte";
|
|
3
|
+
export declare class MapView extends BasesView {
|
|
4
|
+
readonly controller: QueryController;
|
|
5
|
+
readonly scrollEl: HTMLElement;
|
|
6
|
+
type: string;
|
|
7
|
+
constructor(controller: QueryController, scrollEl: HTMLElement);
|
|
8
|
+
onDataUpdated(): void;
|
|
9
|
+
static getViewOptions(): BasesOptions[];
|
|
10
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { BasesView, QueryController } from "../bases.svelte";
|
|
2
|
+
import MapViewComponent from "./view.svelte";
|
|
3
|
+
export class MapView extends BasesView {
|
|
4
|
+
controller;
|
|
5
|
+
scrollEl;
|
|
6
|
+
type = "map";
|
|
7
|
+
constructor(controller, scrollEl) {
|
|
8
|
+
super(controller);
|
|
9
|
+
this.controller = controller;
|
|
10
|
+
this.scrollEl = scrollEl;
|
|
11
|
+
this.mountViewComponent(MapViewComponent, { view: this }, scrollEl);
|
|
12
|
+
}
|
|
13
|
+
onDataUpdated() { }
|
|
14
|
+
static getViewOptions() {
|
|
15
|
+
return [];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { BasesView } from "../bases.svelte";
|
|
3
|
+
import SummaryStrip from "../components/summary-strip.svelte";
|
|
4
|
+
|
|
5
|
+
let {
|
|
6
|
+
view,
|
|
7
|
+
}: {
|
|
8
|
+
view: BasesView;
|
|
9
|
+
} = $props();
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<div
|
|
13
|
+
class="bases-style-flex-60fbb7 bases-style-h-full-668b21 bases-style-flex-col-8dddea bases-style-gap-3-1004c0 bases-style-border-t-b950dd bases-style-px-4-f0faeb bases-style-py-5-c9b99c bases-style-text-sm-fc7473"
|
|
14
|
+
data-layout="map"
|
|
15
|
+
data-ui-component="bases-map-view"
|
|
16
|
+
data-ui-part="unavailable"
|
|
17
|
+
>
|
|
18
|
+
<SummaryStrip {view} />
|
|
19
|
+
<div class="bases-style-font-medium-2689f3">Map view is not available in this runtime yet.</div>
|
|
20
|
+
<p class="bases-style-text-muted-foreground-bfa603">
|
|
21
|
+
This Base can keep a `map` layout in its config, but the current runtime
|
|
22
|
+
only provides an explicit fallback state until map capability is
|
|
23
|
+
implemented.
|
|
24
|
+
</p>
|
|
25
|
+
<p class="bases-style-text-muted-foreground-bfa603">
|
|
26
|
+
Current result count: {view.data.data.length}
|
|
27
|
+
</p>
|
|
28
|
+
</div>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { BasesPropertyId, CachedMetadata } from "@lapis-notes/api";
|
|
2
|
+
import { type Filters, type SortColumn } from "./models";
|
|
3
|
+
export type MetadataDependencySet = {
|
|
4
|
+
custom: boolean;
|
|
5
|
+
tags: boolean;
|
|
6
|
+
links: boolean;
|
|
7
|
+
backlinks: boolean;
|
|
8
|
+
properties: Set<string>;
|
|
9
|
+
propertyPresence: boolean;
|
|
10
|
+
staticFileFields: Set<string>;
|
|
11
|
+
dynamicFileFields: Set<string>;
|
|
12
|
+
};
|
|
13
|
+
type MetadataDependencyInput = {
|
|
14
|
+
documentFilter: Filters;
|
|
15
|
+
viewFilter: Filters | undefined;
|
|
16
|
+
order: BasesPropertyId[];
|
|
17
|
+
sort: SortColumn[];
|
|
18
|
+
groupByProperty?: BasesPropertyId | null;
|
|
19
|
+
imageProperty?: BasesPropertyId | null;
|
|
20
|
+
formulas: Record<string, string>;
|
|
21
|
+
};
|
|
22
|
+
type MetadataInvalidationInput = {
|
|
23
|
+
changedPath: string;
|
|
24
|
+
currentResultPaths: string[];
|
|
25
|
+
cache: CachedMetadata | null;
|
|
26
|
+
prevCache: CachedMetadata | null;
|
|
27
|
+
dependencies: MetadataDependencySet;
|
|
28
|
+
isDirectlyAffectedByPathChange: (watchedPath: string, changedPath: string) => boolean;
|
|
29
|
+
};
|
|
30
|
+
export declare function createMetadataDependencySet(): MetadataDependencySet;
|
|
31
|
+
export declare function collectMetadataDependencies(input: MetadataDependencyInput): MetadataDependencySet;
|
|
32
|
+
export declare function cacheMatchesDependencies(cache: CachedMetadata | null | undefined, dependencies: MetadataDependencySet): boolean;
|
|
33
|
+
export declare function shouldReloadForMetadataChange(input: MetadataInvalidationInput): boolean;
|
|
34
|
+
export {};
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { isFilterGroup, isFilterLine, } from "./models";
|
|
2
|
+
const DYNAMIC_FILE_FIELDS = new Set(["file.mtime", "file.size"]);
|
|
3
|
+
export function createMetadataDependencySet() {
|
|
4
|
+
return {
|
|
5
|
+
custom: false,
|
|
6
|
+
tags: false,
|
|
7
|
+
links: false,
|
|
8
|
+
backlinks: false,
|
|
9
|
+
properties: new Set(),
|
|
10
|
+
propertyPresence: false,
|
|
11
|
+
staticFileFields: new Set(),
|
|
12
|
+
dynamicFileFields: new Set(),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function trackPropertyDependency(dependencies, propertyId) {
|
|
16
|
+
if (!propertyId) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
if (propertyId === "file") {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (propertyId.startsWith("formula.")) {
|
|
23
|
+
dependencies.custom = true;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (propertyId === "file.tags") {
|
|
27
|
+
dependencies.tags = true;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (propertyId === "file.links" ||
|
|
31
|
+
propertyId === "file.embeds") {
|
|
32
|
+
dependencies.links = true;
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (propertyId === "file.backlinks") {
|
|
36
|
+
dependencies.links = true;
|
|
37
|
+
dependencies.backlinks = true;
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (propertyId === "file.properties") {
|
|
41
|
+
dependencies.propertyPresence = true;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
if (propertyId.startsWith("file.")) {
|
|
45
|
+
if (DYNAMIC_FILE_FIELDS.has(propertyId)) {
|
|
46
|
+
dependencies.dynamicFileFields.add(propertyId);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
dependencies.staticFileFields.add(propertyId);
|
|
50
|
+
}
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const normalized = propertyId.startsWith("note.")
|
|
54
|
+
? propertyId.slice("note.".length)
|
|
55
|
+
: propertyId;
|
|
56
|
+
if (normalized.length > 0) {
|
|
57
|
+
dependencies.properties.add(normalized);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function trackFilterLineDependencies(dependencies, filter) {
|
|
61
|
+
if (filter.custom || filter.column.startsWith("formula.")) {
|
|
62
|
+
dependencies.custom = true;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
trackPropertyDependency(dependencies, filter.column);
|
|
66
|
+
if (filter.op === "hasTag" || filter.op === "!hasTag") {
|
|
67
|
+
dependencies.tags = true;
|
|
68
|
+
}
|
|
69
|
+
if (filter.op === "hasLink" || filter.op === "!hasLink") {
|
|
70
|
+
dependencies.links = true;
|
|
71
|
+
}
|
|
72
|
+
if (filter.op === "hasProperty" || filter.op === "!hasProperty") {
|
|
73
|
+
dependencies.propertyPresence = true;
|
|
74
|
+
const values = Array.isArray(filter.value) ? filter.value : [filter.value];
|
|
75
|
+
for (const value of values) {
|
|
76
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
77
|
+
dependencies.properties.add(value.trim());
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (filter.op === "inFolder" || filter.op === "!inFolder") {
|
|
82
|
+
dependencies.staticFileFields.add("file.folder");
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function collectFilterDependencies(dependencies, filter) {
|
|
86
|
+
if (!filter) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (typeof filter === "string") {
|
|
90
|
+
if (filter.trim().length > 0) {
|
|
91
|
+
dependencies.custom = true;
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (isFilterLine(filter)) {
|
|
96
|
+
trackFilterLineDependencies(dependencies, filter);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (isFilterGroup(filter)) {
|
|
100
|
+
const values = "and" in filter ? filter.and : "or" in filter ? filter.or : filter.not;
|
|
101
|
+
for (const entry of values) {
|
|
102
|
+
collectFilterDependencies(dependencies, entry);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function collectMetadataDependencies(input) {
|
|
107
|
+
const dependencies = createMetadataDependencySet();
|
|
108
|
+
collectFilterDependencies(dependencies, input.documentFilter);
|
|
109
|
+
collectFilterDependencies(dependencies, input.viewFilter);
|
|
110
|
+
for (const propertyId of input.order) {
|
|
111
|
+
trackPropertyDependency(dependencies, propertyId);
|
|
112
|
+
}
|
|
113
|
+
for (const sort of input.sort) {
|
|
114
|
+
trackPropertyDependency(dependencies, sort.property);
|
|
115
|
+
}
|
|
116
|
+
trackPropertyDependency(dependencies, input.groupByProperty ?? null);
|
|
117
|
+
trackPropertyDependency(dependencies, input.imageProperty ?? null);
|
|
118
|
+
if (Object.keys(input.formulas).length > 0) {
|
|
119
|
+
dependencies.custom = true;
|
|
120
|
+
}
|
|
121
|
+
return dependencies;
|
|
122
|
+
}
|
|
123
|
+
export function cacheMatchesDependencies(cache, dependencies) {
|
|
124
|
+
if (!cache) {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
if (dependencies.tags && (cache.tags?.length ?? 0) > 0) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
if (dependencies.links &&
|
|
131
|
+
((cache.links?.length ?? 0) > 0 || (cache.embeds?.length ?? 0) > 0)) {
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
const frontmatter = cache.frontmatter ?? {};
|
|
135
|
+
if (dependencies.propertyPresence && Object.keys(frontmatter).length > 0) {
|
|
136
|
+
return true;
|
|
137
|
+
}
|
|
138
|
+
for (const property of dependencies.properties) {
|
|
139
|
+
if (property in frontmatter) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
export function shouldReloadForMetadataChange(input) {
|
|
146
|
+
if (input.currentResultPaths.includes(input.changedPath)) {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
if (input.dependencies.links) {
|
|
150
|
+
for (const path of input.currentResultPaths) {
|
|
151
|
+
if (input.isDirectlyAffectedByPathChange(path, input.changedPath)) {
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (input.dependencies.custom ||
|
|
157
|
+
input.dependencies.dynamicFileFields.size > 0) {
|
|
158
|
+
return true;
|
|
159
|
+
}
|
|
160
|
+
return (cacheMatchesDependencies(input.cache, input.dependencies) ||
|
|
161
|
+
cacheMatchesDependencies(input.prevCache, input.dependencies));
|
|
162
|
+
}
|