mirror of
https://github.com/decaf-dev/obsidian-vault-explorer.git
synced 2026-07-22 10:10:31 +00:00
Add file icons (#155)
* feat: add file icons setting * feat: render file icons
This commit is contained in:
parent
61f7989309
commit
ebfd815630
29 changed files with 1009 additions and 300 deletions
|
|
@ -51,6 +51,8 @@ Features are what the software should do.
|
|||
| Left/right buttons to allow a user to scroll between groups | #accessibility |
|
||||
| Duplicate a filter rule | #filter |
|
||||
| Random sort | #filter |
|
||||
| Add file icons | #filter |
|
||||
| Add file icon setting | #setting |
|
||||
|
||||
## Event callbacks
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "vault-explorer",
|
||||
"name": "Vault Explorer",
|
||||
"version": "1.20.0",
|
||||
"version": "1.21.0",
|
||||
"minAppVersion": "1.4.13",
|
||||
"description": "Explore your vault in visual format",
|
||||
"author": "DecafDev",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-vault-explorer",
|
||||
"version": "1.20.0",
|
||||
"version": "1.21.0",
|
||||
"description": "Explore your vault in visual format",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -19,15 +19,15 @@ export const DEFAULT_SETTINGS: VaultExplorerPluginSettings = {
|
|||
filters: {
|
||||
search: {
|
||||
isEnabled: true,
|
||||
value: ""
|
||||
value: "",
|
||||
},
|
||||
favorites: {
|
||||
isEnabled: true,
|
||||
value: false
|
||||
value: false,
|
||||
},
|
||||
timestamp: {
|
||||
isEnabled: true,
|
||||
value: "all"
|
||||
value: "all",
|
||||
},
|
||||
sort: {
|
||||
isEnabled: true,
|
||||
|
|
@ -36,8 +36,8 @@ export const DEFAULT_SETTINGS: VaultExplorerPluginSettings = {
|
|||
custom: {
|
||||
isEnabled: true,
|
||||
selectedGroupId: "",
|
||||
groups: []
|
||||
}
|
||||
groups: [],
|
||||
},
|
||||
},
|
||||
views: {
|
||||
dashboard: {
|
||||
|
|
@ -60,13 +60,14 @@ export const DEFAULT_SETTINGS: VaultExplorerPluginSettings = {
|
|||
},
|
||||
related: {
|
||||
isEnabled: false,
|
||||
}
|
||||
},
|
||||
},
|
||||
currentView: TExplorerView.GRID,
|
||||
titleWrapping: "normal",
|
||||
enableClockUpdates: true,
|
||||
enableFileIcons: false,
|
||||
enableScrollButtons: true,
|
||||
pageSize: 50,
|
||||
viewOrder: [TExplorerView.GRID, TExplorerView.LIST, TExplorerView.FEED],
|
||||
pluginVersion: null
|
||||
}
|
||||
pluginVersion: null,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,21 @@
|
|||
export type PluginEvent = "file-rename" | "file-create" | "file-delete" | "file-modify" | "metadata-change" | "properties-filter-update" | "folder-rename" | "folder-delete" | "folder-create" | "page-size-setting-change" | "title-wrapping-setting-change" | "property-setting-change" | "device-registration-change" | "clock-updates-setting-change" | "filter-toggle-setting-change" | "scroll-buttons-setting-change" | "view-toggle-setting-change";
|
||||
export type PluginEvent =
|
||||
| "file-rename"
|
||||
| "file-create"
|
||||
| "file-delete"
|
||||
| "file-modify"
|
||||
| "metadata-change"
|
||||
| "properties-filter-update"
|
||||
| "folder-rename"
|
||||
| "folder-delete"
|
||||
| "folder-create"
|
||||
| "page-size-setting-change"
|
||||
| "title-wrapping-setting-change"
|
||||
| "property-setting-change"
|
||||
| "device-registration-change"
|
||||
| "clock-updates-setting-change"
|
||||
| "filter-toggle-setting-change"
|
||||
| "scroll-buttons-setting-change"
|
||||
| "view-toggle-setting-change"
|
||||
| "file-icons-setting-change";
|
||||
|
||||
export type EventCallback = (...data: unknown[]) => void;
|
||||
|
|
|
|||
148
src/main.ts
148
src/main.ts
|
|
@ -1,18 +1,22 @@
|
|||
import { Plugin, TAbstractFile, TFile, TFolder } from 'obsidian';
|
||||
import { Plugin, TAbstractFile, TFile, TFolder } from "obsidian";
|
||||
|
||||
import VaultExplorerView from './obsidian/vault-explorer-view';
|
||||
import VaultExplorerSettingsTab from './obsidian/vault-explorer-settings-tab';
|
||||
import VaultExplorerView from "./obsidian/vault-explorer-view";
|
||||
import VaultExplorerSettingsTab from "./obsidian/vault-explorer-settings-tab";
|
||||
|
||||
import { VaultExplorerPluginSettings } from './types';
|
||||
import { DEFAULT_SETTINGS, HOVER_LINK_SOURCE_ID, VAULT_EXPLORER_VIEW } from './constants';
|
||||
import _ from 'lodash';
|
||||
import EventManager from './event/event-manager';
|
||||
import { preformMigrations } from './migrations';
|
||||
import Logger from 'js-logger';
|
||||
import { formatMessageForLogger, stringToLogLevel } from './logger';
|
||||
import { moveFocus } from './focus-utils';
|
||||
import { loadDeviceId } from './svelte/shared/services/device-id-utils';
|
||||
import License from './svelte/shared/services/license';
|
||||
import { VaultExplorerPluginSettings } from "./types";
|
||||
import {
|
||||
DEFAULT_SETTINGS,
|
||||
HOVER_LINK_SOURCE_ID,
|
||||
VAULT_EXPLORER_VIEW,
|
||||
} from "./constants";
|
||||
import _ from "lodash";
|
||||
import EventManager from "./event/event-manager";
|
||||
import { preformMigrations } from "./migrations";
|
||||
import Logger from "js-logger";
|
||||
import { formatMessageForLogger, stringToLogLevel } from "./logger";
|
||||
import { moveFocus } from "./focus-utils";
|
||||
import { loadDeviceId } from "./svelte/shared/services/device-id-utils";
|
||||
import License from "./svelte/shared/services/license";
|
||||
|
||||
export default class VaultExplorerPlugin extends Plugin {
|
||||
settings: VaultExplorerPluginSettings = DEFAULT_SETTINGS;
|
||||
|
|
@ -40,7 +44,10 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
});
|
||||
|
||||
this.registerEvents();
|
||||
this.registerHoverLinkSource(HOVER_LINK_SOURCE_ID, { display: this.manifest.name, defaultMod: true });
|
||||
this.registerHoverLinkSource(HOVER_LINK_SOURCE_ID, {
|
||||
display: this.manifest.name,
|
||||
defaultMod: true,
|
||||
});
|
||||
this.addSettingTab(new VaultExplorerSettingsTab(this.app, this));
|
||||
|
||||
this.app.workspace.onLayoutReady(() => {
|
||||
|
|
@ -49,60 +56,79 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
|
||||
await loadDeviceId();
|
||||
await License.getInstance().verifyLicense();
|
||||
|
||||
}
|
||||
|
||||
private registerEvents() {
|
||||
//Callback if the file is renamed or moved
|
||||
//This callback is already debounced by Obsidian
|
||||
this.registerEvent(this.app.vault.on("rename", (file: TAbstractFile, oldPath: string) => {
|
||||
if (file instanceof TFolder) {
|
||||
EventManager.getInstance().emit("folder-rename", oldPath, file);
|
||||
} else if (file instanceof TFile) {
|
||||
EventManager.getInstance().emit("file-rename", oldPath, file);
|
||||
}
|
||||
}));
|
||||
this.registerEvent(
|
||||
this.app.vault.on(
|
||||
"rename",
|
||||
(file: TAbstractFile, oldPath: string) => {
|
||||
if (file instanceof TFolder) {
|
||||
EventManager.getInstance().emit(
|
||||
"folder-rename",
|
||||
oldPath,
|
||||
file
|
||||
);
|
||||
} else if (file instanceof TFile) {
|
||||
EventManager.getInstance().emit(
|
||||
"file-rename",
|
||||
oldPath,
|
||||
file
|
||||
);
|
||||
}
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
//Callback if a file is deleted
|
||||
//This callback is already debounced by Obsidian
|
||||
this.registerEvent(this.app.vault.on("delete", (file: TAbstractFile) => {
|
||||
if (file instanceof TFolder) {
|
||||
EventManager.getInstance().emit("folder-delete", file.path);
|
||||
} else
|
||||
if (file instanceof TFile) {
|
||||
this.registerEvent(
|
||||
this.app.vault.on("delete", (file: TAbstractFile) => {
|
||||
if (file instanceof TFolder) {
|
||||
EventManager.getInstance().emit("folder-delete", file.path);
|
||||
} else if (file instanceof TFile) {
|
||||
EventManager.getInstance().emit("file-delete", file.path);
|
||||
}
|
||||
}));
|
||||
})
|
||||
);
|
||||
|
||||
//Callback if a file is created
|
||||
//This callback is already debounced by Obsidian
|
||||
this.registerEvent(this.app.vault.on("create", (file: TAbstractFile) => {
|
||||
//For some reason Obsidian will call this event for every file in the vault when the plugin is loaded
|
||||
//We need to ignore these events
|
||||
if (!this.layoutReady) return;
|
||||
this.registerEvent(
|
||||
this.app.vault.on("create", (file: TAbstractFile) => {
|
||||
//For some reason Obsidian will call this event for every file in the vault when the plugin is loaded
|
||||
//We need to ignore these events
|
||||
if (!this.layoutReady) return;
|
||||
|
||||
if (file instanceof TFolder) {
|
||||
EventManager.getInstance().emit("folder-create", file);
|
||||
} else if (file instanceof TFile) {
|
||||
EventManager.getInstance().emit("file-create", file);
|
||||
}
|
||||
}));
|
||||
if (file instanceof TFolder) {
|
||||
EventManager.getInstance().emit("folder-create", file);
|
||||
} else if (file instanceof TFile) {
|
||||
EventManager.getInstance().emit("file-create", file);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
//Callback if a file is modified
|
||||
//This callback is already debounced by Obsidian
|
||||
this.registerEvent(this.app.vault.on("modify", (file: TAbstractFile) => {
|
||||
if (file instanceof TFile) {
|
||||
if (file.extension !== "md") return;
|
||||
EventManager.getInstance().emit("file-modify", file);
|
||||
}
|
||||
}));
|
||||
this.registerEvent(
|
||||
this.app.vault.on("modify", (file: TAbstractFile) => {
|
||||
if (file instanceof TFile) {
|
||||
if (file.extension !== "md") return;
|
||||
EventManager.getInstance().emit("file-modify", file);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
//Callback if the frontmatter is changed
|
||||
//This callback is already debounced by Obsidian
|
||||
this.registerEvent(this.app.metadataCache.on("changed", (file) => {
|
||||
if (file.extension !== "md") return;
|
||||
EventManager.getInstance().emit("metadata-change", file);
|
||||
}));
|
||||
this.registerEvent(
|
||||
this.app.metadataCache.on("changed", (file) => {
|
||||
if (file.extension !== "md") return;
|
||||
EventManager.getInstance().emit("metadata-change", file);
|
||||
})
|
||||
);
|
||||
|
||||
this.registerDomEvent(document, "keydown", (event) => {
|
||||
if (event.key === "ArrowLeft") {
|
||||
|
|
@ -111,21 +137,20 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
moveFocus("next");
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
onunload() {
|
||||
|
||||
}
|
||||
onunload() {}
|
||||
|
||||
async loadSettings() {
|
||||
const loadedData: Record<string, unknown> | null = await this.loadData();
|
||||
const loadedData: Record<string, unknown> | null =
|
||||
await this.loadData();
|
||||
|
||||
let currentData: Record<string, unknown> = {};
|
||||
|
||||
if (loadedData !== null) {
|
||||
//This will be undefined if the settings are from a version before 0.3.0
|
||||
const loadedVersion = loadedData["pluginVersion"] as string ?? null;
|
||||
const loadedVersion =
|
||||
(loadedData["pluginVersion"] as string) ?? null;
|
||||
if (loadedVersion !== null) {
|
||||
const newData = preformMigrations(loadedVersion, loadedData);
|
||||
currentData = newData;
|
||||
|
|
@ -140,8 +165,19 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
}
|
||||
|
||||
async saveSettings() {
|
||||
Logger.trace({ fileName: "main.ts", functionName: "saveSettings", message: "called" });
|
||||
Logger.debug({ fileName: "main.ts", functionName: "saveSettings", message: "saving settings" }, this.settings);
|
||||
Logger.trace({
|
||||
fileName: "main.ts",
|
||||
functionName: "saveSettings",
|
||||
message: "called",
|
||||
});
|
||||
Logger.debug(
|
||||
{
|
||||
fileName: "main.ts",
|
||||
functionName: "saveSettings",
|
||||
message: "saving settings",
|
||||
},
|
||||
this.settings
|
||||
);
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import Migrate_1_17_0 from "./migrate_1_17_0";
|
|||
import Migrate_1_13_0 from "./migrate_1_13_0";
|
||||
import Migrate_1_10_0 from "./migrate_1_10_0";
|
||||
import { isVersionLessThan } from "src/utils";
|
||||
import Migrate_1_21_0 from "./migrate_1_21_0";
|
||||
|
||||
const migrations: TMigration[] = [
|
||||
{
|
||||
|
|
@ -80,9 +81,17 @@ const migrations: TMigration[] = [
|
|||
to: "1.17.0",
|
||||
migrate: Migrate_1_17_0,
|
||||
},
|
||||
{
|
||||
from: "1.20.0",
|
||||
to: "1.21.0",
|
||||
migrate: Migrate_1_21_0,
|
||||
},
|
||||
];
|
||||
|
||||
export const preformMigrations = (settingsVersion: string, data: Record<string, unknown>) => {
|
||||
export const preformMigrations = (
|
||||
settingsVersion: string,
|
||||
data: Record<string, unknown>
|
||||
) => {
|
||||
let updatedData = structuredClone(data);
|
||||
|
||||
for (const migration of migrations) {
|
||||
|
|
@ -96,4 +105,4 @@ export const preformMigrations = (settingsVersion: string, data: Record<string,
|
|||
}
|
||||
|
||||
return updatedData;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,40 +1,42 @@
|
|||
import { TExplorerView, VaultExplorerPluginSettings } from "src/types";
|
||||
import { TExplorerView } from "src/types";
|
||||
import MigrationInterface from "./migration_interface";
|
||||
import { VaultExplorerPluginSettings_1_16_0 } from "src/types/types-1.16.0";
|
||||
import { VaultExplorerPluginSettings_1_20_0 } from "src/types/types-1.20.0";
|
||||
|
||||
export default class Migrate_1_17_0 implements MigrationInterface {
|
||||
migrate(data: Record<string, unknown>) {
|
||||
const typedData = (data as unknown) as VaultExplorerPluginSettings_1_16_0;
|
||||
const newData: VaultExplorerPluginSettings = {
|
||||
const typedData = data as unknown as VaultExplorerPluginSettings_1_16_0;
|
||||
const newData: VaultExplorerPluginSettings_1_20_0 = {
|
||||
...typedData,
|
||||
views: {
|
||||
dashboard: {
|
||||
isEnabled: false
|
||||
isEnabled: false,
|
||||
},
|
||||
grid: {
|
||||
isEnabled: true
|
||||
isEnabled: true,
|
||||
},
|
||||
list: {
|
||||
isEnabled: true
|
||||
isEnabled: true,
|
||||
},
|
||||
table: {
|
||||
isEnabled: false
|
||||
isEnabled: false,
|
||||
},
|
||||
feed: {
|
||||
isEnabled: true
|
||||
isEnabled: true,
|
||||
},
|
||||
recommended: {
|
||||
isEnabled: false
|
||||
isEnabled: false,
|
||||
},
|
||||
related: {
|
||||
isEnabled: false
|
||||
}
|
||||
isEnabled: false,
|
||||
},
|
||||
},
|
||||
viewOrder: typedData.views.order as unknown as TExplorerView[],
|
||||
enableClockUpdates: typedData.views.enableClockUpdates,
|
||||
currentView: typedData.views.currentView as unknown as TExplorerView,
|
||||
titleWrapping: typedData.views.titleWrapping
|
||||
}
|
||||
currentView: typedData.views
|
||||
.currentView as unknown as TExplorerView,
|
||||
titleWrapping: typedData.views.titleWrapping,
|
||||
};
|
||||
delete (newData as any).views.order;
|
||||
delete (newData as any).views.currentView;
|
||||
delete (newData as any).views.enableClockUpdates;
|
||||
|
|
|
|||
14
src/migrations/migrate_1_21_0.ts
Normal file
14
src/migrations/migrate_1_21_0.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
import { VaultExplorerPluginSettings } from "src/types";
|
||||
import MigrationInterface from "./migration_interface";
|
||||
import { VaultExplorerPluginSettings_1_20_0 } from "src/types/types-1.20.0";
|
||||
|
||||
export default class Migrate_1_21_0 implements MigrationInterface {
|
||||
migrate(data: Record<string, unknown>) {
|
||||
const typedData = data as unknown as VaultExplorerPluginSettings_1_20_0;
|
||||
const newData: VaultExplorerPluginSettings = {
|
||||
...typedData,
|
||||
enableFileIcons: true,
|
||||
};
|
||||
return newData as unknown as Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,17 @@
|
|||
import { App, PluginSettingTab, Setting } from "obsidian";
|
||||
import VaultExplorerPlugin from "src/main";
|
||||
import { getDropdownOptionsForProperties, getObsidianPropertiesByType } from "./utils";
|
||||
import { LOG_LEVEL_DEBUG, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, LOG_LEVEL_OFF, LOG_LEVEL_TRACE, LOG_LEVEL_WARN } from "src/logger/constants";
|
||||
import {
|
||||
getDropdownOptionsForProperties,
|
||||
getObsidianPropertiesByType,
|
||||
} from "./utils";
|
||||
import {
|
||||
LOG_LEVEL_DEBUG,
|
||||
LOG_LEVEL_ERROR,
|
||||
LOG_LEVEL_INFO,
|
||||
LOG_LEVEL_OFF,
|
||||
LOG_LEVEL_TRACE,
|
||||
LOG_LEVEL_WARN,
|
||||
} from "src/logger/constants";
|
||||
import Logger from "js-logger";
|
||||
import { stringToLogLevel } from "src/logger";
|
||||
import { TExplorerView, WordBreak } from "src/types";
|
||||
|
|
@ -25,160 +35,214 @@ export default class VaultExplorerSettingsTab extends PluginSettingTab {
|
|||
|
||||
const textProperties = getObsidianPropertiesByType(this.app, "text");
|
||||
const dateProperties = getObsidianPropertiesByType(this.app, "date");
|
||||
const dateTimeProperties = getObsidianPropertiesByType(this.app, "datetime");
|
||||
const checkboxProperties = getObsidianPropertiesByType(this.app, "checkbox");
|
||||
const dateTimeProperties = getObsidianPropertiesByType(
|
||||
this.app,
|
||||
"datetime"
|
||||
);
|
||||
const checkboxProperties = getObsidianPropertiesByType(
|
||||
this.app,
|
||||
"checkbox"
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("General").setHeading();
|
||||
|
||||
new Setting(containerEl).setName("Page size").setDesc("The number of items to display per page.").addDropdown(dropdown => dropdown
|
||||
.addOptions({
|
||||
"10": "10",
|
||||
"25": "25",
|
||||
"50": "50",
|
||||
"100": "100",
|
||||
"250": "250",
|
||||
"500": "500",
|
||||
})
|
||||
.setValue(this.plugin.settings.pageSize.toString())
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.pageSize = parseInt(value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("page-size-setting-change");
|
||||
}));
|
||||
new Setting(containerEl)
|
||||
.setName("Title wrapping")
|
||||
.setDesc(
|
||||
"Sets the wrapping style for the title."
|
||||
)
|
||||
.setDesc("Set the wrapping style for the title.")
|
||||
.addDropdown((cb) => {
|
||||
cb.addOptions({
|
||||
"normal": "Normal",
|
||||
normal: "Normal",
|
||||
"break-word": "Break Word",
|
||||
})
|
||||
});
|
||||
cb.setValue(this.plugin.settings.titleWrapping).onChange(
|
||||
async (value) => {
|
||||
this.plugin.settings.titleWrapping = value as WordBreak;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("title-wrapping-setting-change");
|
||||
EventManager.getInstance().emit(
|
||||
"title-wrapping-setting-change"
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Enable scroll buttons")
|
||||
.setDesc("When enabled, scroll buttons will be displayed for scrollable content.")
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enableScrollButtons)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableScrollButtons = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("scroll-buttons-setting-change");
|
||||
}));
|
||||
.setName("File icons")
|
||||
.setDesc("Display an icon next to the file name.")
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.enableFileIcons)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableFileIcons = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"file-icons-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Scroll buttons")
|
||||
.setDesc("Display scroll buttons for scrollable content.")
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.enableScrollButtons)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableScrollButtons = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"scroll-buttons-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Page size")
|
||||
.setDesc("Number of items to display per page.")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions({
|
||||
"10": "10",
|
||||
"25": "25",
|
||||
"50": "50",
|
||||
"100": "100",
|
||||
"250": "250",
|
||||
"500": "500",
|
||||
})
|
||||
.setValue(this.plugin.settings.pageSize.toString())
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.pageSize = parseInt(value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"page-size-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("Filters").setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Search filter")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Search filter").addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.filters.search.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.filters.search.isEnabled = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("filter-toggle-setting-change");
|
||||
}));
|
||||
EventManager.getInstance().emit(
|
||||
"filter-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Favorites filter")
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.filters.favorites.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.filters.favorites.isEnabled = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("filter-toggle-setting-change");
|
||||
}));
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.filters.favorites.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.filters.favorites.isEnabled =
|
||||
value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"filter-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Timestamp filter")
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.filters.timestamp.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.filters.timestamp.isEnabled = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("filter-toggle-setting-change");
|
||||
}));
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.filters.timestamp.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.filters.timestamp.isEnabled =
|
||||
value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"filter-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Sort filter")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Sort filter").addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.filters.sort.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.filters.sort.isEnabled = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("filter-toggle-setting-change");
|
||||
}));
|
||||
EventManager.getInstance().emit(
|
||||
"filter-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Custom filter")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Custom filter").addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.filters.custom.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.filters.custom.isEnabled = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("filter-toggle-setting-change");
|
||||
}));
|
||||
|
||||
EventManager.getInstance().emit(
|
||||
"filter-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("Views").setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Dashboard view")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Dashboard view").addToggle((toggle) =>
|
||||
toggle
|
||||
.setDisabled(true) //TODO - Implement dashboard view
|
||||
.setValue(this.plugin.settings.views.dashboard.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.views.dashboard.isEnabled = value;
|
||||
this.updateViewOrder(TExplorerView.DASHBOARD, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("view-toggle-setting-change");
|
||||
}));
|
||||
EventManager.getInstance().emit(
|
||||
"view-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Grid view")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Grid view").addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.views.grid.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.views.grid.isEnabled = value;
|
||||
this.updateViewOrder(TExplorerView.GRID, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("view-toggle-setting-change");
|
||||
}));
|
||||
EventManager.getInstance().emit(
|
||||
"view-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("List view")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("List view").addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.views.list.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.views.list.isEnabled = value;
|
||||
this.updateViewOrder(TExplorerView.LIST, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("view-toggle-setting-change");
|
||||
}));
|
||||
EventManager.getInstance().emit(
|
||||
"view-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Feed view")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Feed view").addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.views.feed.isEnabled)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.views.feed.isEnabled = value;
|
||||
this.updateViewOrder(TExplorerView.FEED, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("view-toggle-setting-change");
|
||||
}));
|
||||
EventManager.getInstance().emit(
|
||||
"view-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Table view")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Table view").addToggle((toggle) =>
|
||||
toggle
|
||||
.setDisabled(true) //TODO implement
|
||||
.setTooltip("This view is not yet implemented.")
|
||||
.setValue(this.plugin.settings.views.table.isEnabled)
|
||||
|
|
@ -186,26 +250,32 @@ export default class VaultExplorerSettingsTab extends PluginSettingTab {
|
|||
this.plugin.settings.views.table.isEnabled = value;
|
||||
this.updateViewOrder(TExplorerView.TABLE, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("view-toggle-setting-change");
|
||||
}));
|
||||
|
||||
EventManager.getInstance().emit(
|
||||
"view-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Recommended view")
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.views.recommended.isEnabled)
|
||||
.setDisabled(true) //TODO implement
|
||||
.setTooltip("This view is not yet implemented.")
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.views.recommended.isEnabled = value;
|
||||
this.updateViewOrder(TExplorerView.RECOMMENDED, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("view-toggle-setting-change");
|
||||
}));
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.views.recommended.isEnabled)
|
||||
.setDisabled(true) //TODO implement
|
||||
.setTooltip("This view is not yet implemented.")
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.views.recommended.isEnabled =
|
||||
value;
|
||||
this.updateViewOrder(TExplorerView.RECOMMENDED, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"view-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Related view")
|
||||
.addToggle(toggle => toggle
|
||||
new Setting(containerEl).setName("Related view").addToggle((toggle) =>
|
||||
toggle
|
||||
.setDisabled(true) //TODO implement
|
||||
.setTooltip("This view is not yet implemented.")
|
||||
.setValue(this.plugin.settings.views.related.isEnabled)
|
||||
|
|
@ -213,119 +283,178 @@ export default class VaultExplorerSettingsTab extends PluginSettingTab {
|
|||
this.plugin.settings.views.related.isEnabled = value;
|
||||
this.updateViewOrder(TExplorerView.RELATED, value);
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("view-toggle-setting-change");
|
||||
}));
|
||||
EventManager.getInstance().emit(
|
||||
"view-toggle-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("Built-in properties").setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Favorite property')
|
||||
.setDesc('The property used to mark a note as a favorite. This must be a checkbox property.')
|
||||
.addDropdown(dropdown => dropdown.addOptions(getDropdownOptionsForProperties(checkboxProperties))
|
||||
.setValue(this.plugin.settings.properties.favorite)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.favorite = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("property-setting-change");
|
||||
}));
|
||||
.setName("Favorite property")
|
||||
.setDesc(
|
||||
"Property used to mark a note as a favorite. This must be a checkbox property."
|
||||
)
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(
|
||||
getDropdownOptionsForProperties(checkboxProperties)
|
||||
)
|
||||
.setValue(this.plugin.settings.properties.favorite)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.favorite = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"property-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('URL property')
|
||||
.setDesc('The property used to store the URL of the content. This must be a text property.')
|
||||
.addDropdown(dropdown => dropdown.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.url)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.url = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("property-setting-change");
|
||||
}));
|
||||
.setName("URL property")
|
||||
.setDesc(
|
||||
"Property used to store the URL of the content. This must be a text property."
|
||||
)
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.url)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.url = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"property-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
const creationDateDesc = new DocumentFragment();
|
||||
creationDateDesc.createDiv({
|
||||
text: "The property containing the creation date. This must be a date or datetime property.",
|
||||
text: "Property containing the creation date. This must be a date or datetime property.",
|
||||
});
|
||||
creationDateDesc.createDiv({
|
||||
text: "If set to 'Select a property', the file's created at date will be used.",
|
||||
});
|
||||
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Creation date property")
|
||||
.setDesc(creationDateDesc)
|
||||
.addDropdown(dropdown => dropdown.addOptions(getDropdownOptionsForProperties([...dateProperties, ...dateTimeProperties]))
|
||||
.setValue(this.plugin.settings.properties.createdDate)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.createdDate = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("property-setting-change");
|
||||
}));
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(
|
||||
getDropdownOptionsForProperties([
|
||||
...dateProperties,
|
||||
...dateTimeProperties,
|
||||
])
|
||||
)
|
||||
.setValue(this.plugin.settings.properties.createdDate)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.createdDate = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"property-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
const modificationDateDesc = new DocumentFragment();
|
||||
modificationDateDesc.createDiv({
|
||||
text: "The property containing the modification date. This must be a date or datetime property.",
|
||||
text: "Property containing the modification date. This must be a date or datetime property.",
|
||||
});
|
||||
modificationDateDesc.createDiv({
|
||||
text: "If set to 'Select a property', the file's modified at date will be used.",
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Modification date property')
|
||||
.setName("Modification date property")
|
||||
.setDesc(modificationDateDesc)
|
||||
.addDropdown(dropdown => dropdown.addOptions(getDropdownOptionsForProperties([...dateProperties, ...dateTimeProperties]))
|
||||
.setValue(this.plugin.settings.properties.modifiedDate)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.modifiedDate = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("property-setting-change");
|
||||
}));
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(
|
||||
getDropdownOptionsForProperties([
|
||||
...dateProperties,
|
||||
...dateTimeProperties,
|
||||
])
|
||||
)
|
||||
.setValue(this.plugin.settings.properties.modifiedDate)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.modifiedDate = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"property-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("Custom properties").setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Custom property 1')
|
||||
.setDesc('The first custom property. This must be a text property.')
|
||||
.addDropdown(dropdown => dropdown.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.custom1)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.custom1 = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("property-setting-change");
|
||||
}));
|
||||
.setName("Custom property 1")
|
||||
.setDesc("First custom property. This must be a text property.")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.custom1)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.custom1 = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"property-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Custom property 2')
|
||||
.setDesc('The second custom property. This must be a text property.')
|
||||
.addDropdown(dropdown => dropdown.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.custom2)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.custom2 = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("property-setting-change");
|
||||
}));
|
||||
.setName("Custom property 2")
|
||||
.setDesc("Second custom property. This must be a text property.")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.custom2)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.custom2 = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"property-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Custom property 3')
|
||||
.setDesc('The third custom property. This must be a text property.')
|
||||
.addDropdown(dropdown => dropdown.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.custom3)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.custom3 = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("property-setting-change");
|
||||
}));
|
||||
.setName("Custom property 3")
|
||||
.setDesc("Third custom property. This must be a text property.")
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOptions(getDropdownOptionsForProperties(textProperties))
|
||||
.setValue(this.plugin.settings.properties.custom3)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.properties.custom3 = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"property-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("Updates").setHeading();
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Enable clock updates")
|
||||
.setDesc("When enabled, time values will update every minute, refreshing the Vault Explorer view. When disabled, time values will only update when the view is first opened.")
|
||||
.addToggle(toggle => toggle
|
||||
.setValue(this.plugin.settings.enableClockUpdates)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableClockUpdates = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit("clock-updates-setting-change");
|
||||
}));
|
||||
.setDesc(
|
||||
"When enabled, time values will update every minute, refreshing the Vault Explorer view. When disabled, time values will only update when the view is first opened."
|
||||
)
|
||||
.addToggle((toggle) =>
|
||||
toggle
|
||||
.setValue(this.plugin.settings.enableClockUpdates)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.enableClockUpdates = value;
|
||||
await this.plugin.saveSettings();
|
||||
EventManager.getInstance().emit(
|
||||
"clock-updates-setting-change"
|
||||
);
|
||||
})
|
||||
);
|
||||
|
||||
new Setting(containerEl).setName("Premium").setHeading();
|
||||
|
||||
|
|
@ -337,7 +466,7 @@ export default class VaultExplorerSettingsTab extends PluginSettingTab {
|
|||
new Setting(containerEl)
|
||||
.setName("Log level")
|
||||
.setDesc(
|
||||
"Sets the log level. Please use trace to see all log messages."
|
||||
"Set the log level. Please use trace to see all log messages."
|
||||
)
|
||||
.addDropdown((cb) => {
|
||||
cb.addOptions({
|
||||
|
|
@ -346,8 +475,8 @@ export default class VaultExplorerSettingsTab extends PluginSettingTab {
|
|||
[LOG_LEVEL_WARN]: "Warn",
|
||||
[LOG_LEVEL_INFO]: "Info",
|
||||
[LOG_LEVEL_DEBUG]: "Debug",
|
||||
[LOG_LEVEL_TRACE]: "Trace"
|
||||
})
|
||||
[LOG_LEVEL_TRACE]: "Trace",
|
||||
});
|
||||
cb.setValue(this.plugin.settings.logLevel).onChange(
|
||||
async (value) => {
|
||||
this.plugin.settings.logLevel = value;
|
||||
|
|
@ -370,7 +499,9 @@ export default class VaultExplorerSettingsTab extends PluginSettingTab {
|
|||
if (this.plugin.settings.currentView == null)
|
||||
this.plugin.settings.currentView = view;
|
||||
} else {
|
||||
const filtered = this.plugin.settings.viewOrder.filter(v => v !== view);
|
||||
const filtered = this.plugin.settings.viewOrder.filter(
|
||||
(v) => v !== view
|
||||
);
|
||||
this.plugin.settings.viewOrder = filtered;
|
||||
|
||||
//If the user turned off the current view, set the current view to the first view
|
||||
|
|
|
|||
|
|
@ -10,19 +10,42 @@
|
|||
import Stack from "src/svelte/shared/components/stack.svelte";
|
||||
import Tag from "src/svelte/shared/components/tag.svelte";
|
||||
import { removeFrontmatterBlock } from "../services/utils/frontmatter-utils";
|
||||
import Icon from "src/svelte/shared/components/icon.svelte";
|
||||
import { getIconIdForFile } from "../services/utils/file-icon-utils";
|
||||
|
||||
export let name: string;
|
||||
export let displayName: string;
|
||||
export let baseName: string;
|
||||
export let extension: string;
|
||||
export let path: string;
|
||||
export let tags: string[] | null;
|
||||
export let createdMillis: number;
|
||||
export let content: string | null;
|
||||
|
||||
let wordBreak: WordBreak = "normal";
|
||||
let enableFileIcons = false;
|
||||
|
||||
let plugin: VaultExplorerPlugin;
|
||||
store.plugin.subscribe((value) => {
|
||||
plugin = value;
|
||||
wordBreak = plugin.settings.titleWrapping;
|
||||
enableFileIcons = plugin.settings.enableFileIcons;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
function handleFileIconsChange() {
|
||||
enableFileIcons = plugin.settings.enableFileIcons;
|
||||
}
|
||||
|
||||
EventManager.getInstance().on(
|
||||
"file-icons-setting-change",
|
||||
handleFileIconsChange,
|
||||
);
|
||||
return () => {
|
||||
EventManager.getInstance().off(
|
||||
"file-icons-setting-change",
|
||||
handleFileIconsChange,
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
|
|
@ -93,7 +116,12 @@
|
|||
});
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
<Stack spacing="xs">
|
||||
{#if enableFileIcons}
|
||||
<Icon iconId={getIconIdForFile(baseName, extension)} />
|
||||
{/if}
|
||||
<span>{displayName}</span>
|
||||
</Stack>
|
||||
</div>
|
||||
{#if displayContent != null && displayContent.length > 0}
|
||||
<div class="vault-explorer-feed-card__content">
|
||||
|
|
|
|||
|
|
@ -4,12 +4,17 @@
|
|||
import { FileRenderData } from "../types";
|
||||
import License from "src/svelte/shared/services/license";
|
||||
import FeedCard from "./feed-card.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import EventManager from "src/event/event-manager";
|
||||
import VaultExplorerPlugin from "src/main";
|
||||
import store from "src/svelte/shared/services/store";
|
||||
|
||||
export let enablePremiumFeatures = false;
|
||||
export let data: FileRenderData[] = [];
|
||||
export let startIndex;
|
||||
export let pageLength;
|
||||
|
||||
let enableFileIcons = false;
|
||||
let displayedItems: FileRenderData[] = [];
|
||||
|
||||
License.getInstance()
|
||||
|
|
@ -42,7 +47,9 @@
|
|||
{#if enablePremiumFeatures}
|
||||
{#each displayedItems as fileData (fileData.path)}
|
||||
<FeedCard
|
||||
name={fileData.name}
|
||||
displayName={fileData.displayName}
|
||||
extension={fileData.extension}
|
||||
baseName={fileData.baseName}
|
||||
path={fileData.path}
|
||||
tags={fileData.tags}
|
||||
content={fileData.content}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@
|
|||
import { HOVER_LINK_SOURCE_ID } from "src/constants";
|
||||
import EventManager from "src/event/event-manager";
|
||||
import ScrollButton from "src/svelte/shared/components/scroll-button.svelte";
|
||||
import Icon from "src/svelte/shared/components/icon.svelte";
|
||||
import { getIconIdForFile } from "../services/utils/file-icon-utils";
|
||||
|
||||
export let name: string;
|
||||
export let displayName: string;
|
||||
export let path: string;
|
||||
export let baseName: string;
|
||||
export let extension: string;
|
||||
export let url: string | null;
|
||||
export let tags: string[] | null;
|
||||
export let custom1: string | null;
|
||||
|
|
@ -26,6 +30,7 @@
|
|||
let tagContainerRef: HTMLDivElement | null;
|
||||
let wordBreak: WordBreak = "normal";
|
||||
|
||||
let enableFileIcons: boolean = false;
|
||||
let enableScrollButtons: boolean = false;
|
||||
let renderScrollLeftButton = false;
|
||||
let renderScrollRightButton = false;
|
||||
|
|
@ -35,6 +40,24 @@
|
|||
plugin = p;
|
||||
wordBreak = plugin.settings.titleWrapping;
|
||||
enableScrollButtons = plugin.settings.enableScrollButtons;
|
||||
enableFileIcons = plugin.settings.enableFileIcons;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
function handleFileIconsChange() {
|
||||
enableFileIcons = plugin.settings.enableFileIcons;
|
||||
}
|
||||
|
||||
EventManager.getInstance().on(
|
||||
"file-icons-setting-change",
|
||||
handleFileIconsChange,
|
||||
);
|
||||
return () => {
|
||||
EventManager.getInstance().off(
|
||||
"file-icons-setting-change",
|
||||
handleFileIconsChange,
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
|
|
@ -185,7 +208,12 @@
|
|||
});
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
<Stack spacing="xs">
|
||||
{#if enableFileIcons}
|
||||
<Icon iconId={getIconIdForFile(baseName, extension)} />
|
||||
{/if}
|
||||
<span>{displayName}</span>
|
||||
</Stack>
|
||||
</div>
|
||||
{#if url !== null}
|
||||
<IconButton iconId="external-link" on:click={handleUrlClick} />
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@
|
|||
<div class="vault-explorer-grid-view__container">
|
||||
{#each displayedItems as file (file.path)}
|
||||
<GridCard
|
||||
name={file.name}
|
||||
displayName={file.displayName}
|
||||
path={file.path}
|
||||
baseName={file.baseName}
|
||||
extension={file.extension}
|
||||
url={file.url}
|
||||
tags={file.tags}
|
||||
custom1={file.custom1}
|
||||
|
|
|
|||
|
|
@ -5,14 +5,40 @@
|
|||
import { HOVER_LINK_SOURCE_ID } from "src/constants";
|
||||
import Tag from "src/svelte/shared/components/tag.svelte";
|
||||
import Wrap from "src/svelte/shared/components/wrap.svelte";
|
||||
import Icon from "src/svelte/shared/components/icon.svelte";
|
||||
import Stack from "src/svelte/shared/components/stack.svelte";
|
||||
import { getIconIdForFile } from "../services/utils/file-icon-utils";
|
||||
import { onMount } from "svelte";
|
||||
import EventManager from "src/event/event-manager";
|
||||
|
||||
export let name: string;
|
||||
export let displayName: string;
|
||||
export let baseName: string;
|
||||
export let extension: string;
|
||||
export let path: string;
|
||||
export let tags: string[] | null;
|
||||
|
||||
let enableFileIcons: boolean = false;
|
||||
let plugin: VaultExplorerPlugin;
|
||||
store.plugin.subscribe((p) => {
|
||||
plugin = p;
|
||||
enableFileIcons = plugin.settings.enableFileIcons;
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
function handleFileIconsChange() {
|
||||
enableFileIcons = plugin.settings.enableFileIcons;
|
||||
}
|
||||
|
||||
EventManager.getInstance().on(
|
||||
"file-icons-setting-change",
|
||||
handleFileIconsChange,
|
||||
);
|
||||
return () => {
|
||||
EventManager.getInstance().off(
|
||||
"file-icons-setting-change",
|
||||
handleFileIconsChange,
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
function handleTitleClick() {
|
||||
|
|
@ -49,7 +75,12 @@
|
|||
});
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
<Stack spacing="xs">
|
||||
{#if enableFileIcons}
|
||||
<Icon iconId={getIconIdForFile(baseName, extension)} />
|
||||
{/if}
|
||||
<span>{displayName}</span>
|
||||
</Stack>
|
||||
</div>
|
||||
{#if tags != null}
|
||||
<div class="vault-explorer-list-item__tags">
|
||||
|
|
|
|||
|
|
@ -24,6 +24,12 @@
|
|||
|
||||
<div class="vault-explorer-list-view">
|
||||
{#each displayedItems as file (file.path)}
|
||||
<ListItem name={file.name} path={file.path} tags={file.tags} />
|
||||
<ListItem
|
||||
displayName={file.displayName}
|
||||
extension={file.extension}
|
||||
baseName={file.baseName}
|
||||
path={file.path}
|
||||
tags={file.tags}
|
||||
/>
|
||||
{/each}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -710,9 +710,13 @@
|
|||
$: renderData = [...filteredTimestamp].sort((a, b) => {
|
||||
const { value } = sortFilter;
|
||||
if (value === "file-name-asc") {
|
||||
return a.name.toLowerCase().localeCompare(b.name.toLowerCase());
|
||||
return a.displayName
|
||||
.toLowerCase()
|
||||
.localeCompare(b.displayName.toLowerCase());
|
||||
} else if (value === "file-name-desc") {
|
||||
return b.name.toLowerCase().localeCompare(a.name.toLowerCase());
|
||||
return b.displayName
|
||||
.toLowerCase()
|
||||
.localeCompare(a.displayName.toLowerCase());
|
||||
} else if (value === "modified-asc") {
|
||||
return a.modifiedMillis - b.modifiedMillis;
|
||||
} else if (value === "modified-desc") {
|
||||
|
|
|
|||
|
|
@ -18,8 +18,11 @@ function createFileContentStore() {
|
|||
for (let file of files) {
|
||||
promises.push(
|
||||
(async () => {
|
||||
const { extension } = file;
|
||||
if (extension === "md") {
|
||||
const { basename, extension } = file;
|
||||
if (
|
||||
extension === "md" &&
|
||||
!basename.endsWith(".excalidraw")
|
||||
) {
|
||||
const content = await app.vault.cachedRead(file);
|
||||
return {
|
||||
path: file.path,
|
||||
|
|
|
|||
|
|
@ -8,9 +8,9 @@ export const filterBySearch = (file: FileRenderData, value: string) => {
|
|||
|
||||
const compare = value.toLowerCase().trim();
|
||||
|
||||
const { name, path, content, } = file;
|
||||
const { displayName, path, content } = file;
|
||||
|
||||
if (name.toLowerCase().includes(compare)) {
|
||||
if (displayName.toLowerCase().includes(compare)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -23,4 +23,4 @@ export const filterBySearch = (file: FileRenderData, value: string) => {
|
|||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
63
src/svelte/app/services/utils/file-icon-utils.ts
Normal file
63
src/svelte/app/services/utils/file-icon-utils.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import Logger from "js-logger";
|
||||
|
||||
export const getIconIdForFile = (baseName: string, extension: string) => {
|
||||
if (baseName.endsWith(".excalidraw")) {
|
||||
return "excalidraw-icon";
|
||||
}
|
||||
|
||||
switch (extension) {
|
||||
case "md":
|
||||
return "file";
|
||||
case "canvas":
|
||||
return "layout-dashboard";
|
||||
case "zip":
|
||||
return "file-archive";
|
||||
case "png":
|
||||
case "jpg":
|
||||
case "jpeg":
|
||||
case "gif":
|
||||
case "webp":
|
||||
case "svg":
|
||||
case "avif":
|
||||
case "bmp":
|
||||
return "file-image";
|
||||
case "mp3":
|
||||
case "wav":
|
||||
case "aac":
|
||||
case "flac":
|
||||
case "ogg":
|
||||
case "wma":
|
||||
case "alac":
|
||||
case "aiff":
|
||||
return "file-audio";
|
||||
case "mp4":
|
||||
case "avi":
|
||||
case "mkv":
|
||||
case "mov":
|
||||
case "wmv":
|
||||
case "flv":
|
||||
case "webm":
|
||||
case "mpeg":
|
||||
case "m4v":
|
||||
case "3gp":
|
||||
return "file-video";
|
||||
case "xls":
|
||||
case "xlsx":
|
||||
return "file-spreadsheet";
|
||||
case "xml":
|
||||
case "json":
|
||||
return "file-code";
|
||||
case "ppt":
|
||||
case "pptx":
|
||||
return "images";
|
||||
case "doc":
|
||||
case "docx":
|
||||
return "file-type";
|
||||
case "pdf":
|
||||
case "txt":
|
||||
return "file-text";
|
||||
default:
|
||||
Logger.warn(`No icon found for file extension: ${extension}`);
|
||||
return "file";
|
||||
}
|
||||
};
|
||||
|
|
@ -95,8 +95,10 @@ export const formatFileDataForRender = (
|
|||
const displayName = extension === "md" ? basename : name;
|
||||
|
||||
return {
|
||||
name: displayName,
|
||||
displayName,
|
||||
baseName: basename,
|
||||
path,
|
||||
extension,
|
||||
url,
|
||||
content,
|
||||
tags,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
export interface FileRenderData {
|
||||
name: string;
|
||||
displayName: string;
|
||||
path: string;
|
||||
extension: string;
|
||||
baseName: string;
|
||||
content: string | null;
|
||||
url: string | null;
|
||||
tags: string[] | null;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { setIcon } from "obsidian";
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import { getSvgData } from "../services/get-svg-data";
|
||||
|
||||
export let ariaLabel = "";
|
||||
export let iconId = "";
|
||||
|
|
@ -8,21 +9,13 @@
|
|||
export let noPadding = false;
|
||||
export let isTabbable = true;
|
||||
|
||||
$: svgData = getSvgData(iconId);
|
||||
|
||||
function getSvgData(id: string) {
|
||||
if (id === "ellipsis-vertical") {
|
||||
return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-ellipsis-vertical"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
let ref: HTMLElement;
|
||||
|
||||
// Use onMount to ensure the element is available in the DOM
|
||||
onMount(() => {
|
||||
if (iconId === "ellipsis-vertical") return;
|
||||
if (iconId === "file-pdf") return;
|
||||
setIcon(ref, iconId);
|
||||
});
|
||||
|
||||
|
|
@ -33,6 +26,8 @@
|
|||
$: className =
|
||||
"clickable-icon" +
|
||||
(noPadding == true ? " vault-explorer-icon--no-padding" : "");
|
||||
|
||||
$: svgData = getSvgData(iconId);
|
||||
</script>
|
||||
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -1,30 +1,37 @@
|
|||
<script lang="ts">
|
||||
import { setIcon } from "obsidian";
|
||||
import { onMount } from "svelte";
|
||||
import { getSvgData } from "../services/get-svg-data";
|
||||
|
||||
export let ariaLabel = "";
|
||||
export let iconId = "";
|
||||
export let xs = false;
|
||||
|
||||
let ref: HTMLElement;
|
||||
let ref: HTMLElement | null = null;
|
||||
|
||||
// Use onMount to ensure the element is available in the DOM
|
||||
onMount(() => {
|
||||
if (!ref) return;
|
||||
if (iconId === "ellipsis-vertical") return;
|
||||
if (iconId === "file-pdf") return;
|
||||
setIcon(ref, iconId);
|
||||
|
||||
const icon = ref.querySelector("svg");
|
||||
// const icon = ref.querySelector("svg");
|
||||
|
||||
if (xs && icon) {
|
||||
icon.style.setProperty("width", "var(--icon-xs)");
|
||||
icon.style.setProperty("height", "var(--icon-xs)");
|
||||
}
|
||||
// if (xs && icon) {
|
||||
// icon.style.setProperty("width", "var(--icon-xs)");
|
||||
// icon.style.setProperty("height", "var(--icon-xs)");
|
||||
// }
|
||||
});
|
||||
|
||||
$: className = `vault-explorer-icon ${xs ? "vault-explorer-icon--xs" : ""}`;
|
||||
$: svgData = getSvgData(iconId);
|
||||
|
||||
$: className = `vault-explorer-icon ${xs ? "vault-explorer-icon--xs" : "vault-explorer-icon--md"}`;
|
||||
</script>
|
||||
|
||||
<div class={className} aria-label={ariaLabel} bind:this={ref}></div>
|
||||
<div class={className} aria-label={ariaLabel} bind:this={ref}>
|
||||
{@html svgData}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.vault-explorer-icon {
|
||||
|
|
@ -33,7 +40,13 @@
|
|||
opacity: var(--icon-opacity);
|
||||
}
|
||||
|
||||
.vault-explorer-icon--md {
|
||||
width: var(--icon-m);
|
||||
height: var(--icon-m);
|
||||
}
|
||||
|
||||
.vault-explorer-icon--xs {
|
||||
width: var(--icon-xs);
|
||||
height: var(--icon-xs);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
10
src/svelte/shared/services/get-svg-data.ts
Normal file
10
src/svelte/shared/services/get-svg-data.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
const LUCIDE_ELLIPSIS_VERTICAL = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="svg-icon lucide-ellipsis-vertical"><circle cx="12" cy="12" r="1"/><circle cx="12" cy="5" r="1"/><circle cx="12" cy="19" r="1"/></svg>`;
|
||||
|
||||
export const getSvgData = (iconId: string) => {
|
||||
switch (iconId) {
|
||||
case "ellipsis-vertical":
|
||||
return LUCIDE_ELLIPSIS_VERTICAL;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
|
@ -40,7 +40,8 @@ export function isVaultExplorerPluginSettings(obj: unknown): obj is VaultExplore
|
|||
(typedObj["filters"]["sort"]["value"] === "file-name-asc" ||
|
||||
typedObj["filters"]["sort"]["value"] === "file-name-desc" ||
|
||||
typedObj["filters"]["sort"]["value"] === "modified-asc" ||
|
||||
typedObj["filters"]["sort"]["value"] === "modified-desc") &&
|
||||
typedObj["filters"]["sort"]["value"] === "modified-desc" ||
|
||||
typedObj["filters"]["sort"]["value"] === "random") &&
|
||||
(typedObj["filters"]["timestamp"] !== null &&
|
||||
typeof typedObj["filters"]["timestamp"] === "object" ||
|
||||
typeof typedObj["filters"]["timestamp"] === "function") &&
|
||||
|
|
@ -616,6 +617,7 @@ export function isVaultExplorerPluginSettings(obj: unknown): obj is VaultExplore
|
|||
(typedObj["titleWrapping"] === "normal" ||
|
||||
typedObj["titleWrapping"] === "break-word") &&
|
||||
typeof typedObj["enableClockUpdates"] === "boolean" &&
|
||||
typeof typedObj["enableFileIcons"] === "boolean" &&
|
||||
(typedObj["currentView"] === null ||
|
||||
typedObj["currentView"] === TExplorerView.DASHBOARD ||
|
||||
typedObj["currentView"] === TExplorerView.GRID ||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export interface VaultExplorerPluginSettings {
|
|||
};
|
||||
titleWrapping: WordBreak;
|
||||
enableClockUpdates: boolean;
|
||||
enableFileIcons: boolean;
|
||||
currentView: TExplorerView | null;
|
||||
enableScrollButtons: boolean;
|
||||
pageSize: number;
|
||||
|
|
|
|||
298
src/types/types-1.20.0.ts
Normal file
298
src/types/types-1.20.0.ts
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
export interface VaultExplorerPluginSettings_1_20_0 {
|
||||
properties: {
|
||||
favorite: string;
|
||||
url: string;
|
||||
createdDate: string;
|
||||
modifiedDate: string;
|
||||
custom1: string;
|
||||
custom2: string;
|
||||
custom3: string;
|
||||
};
|
||||
filters: {
|
||||
search: TSearchFilter;
|
||||
favorites: TFavoritesFilter;
|
||||
sort: TSortFilter;
|
||||
timestamp: TTimestampFilter;
|
||||
custom: TCustomFilter;
|
||||
};
|
||||
views: {
|
||||
dashboard: TDashboardView;
|
||||
grid: TGridView;
|
||||
list: TListView;
|
||||
table: TTableView;
|
||||
feed: TFeedView;
|
||||
recommended: TRecommendedView;
|
||||
related: TRelatedView;
|
||||
};
|
||||
titleWrapping: WordBreak;
|
||||
enableClockUpdates: boolean;
|
||||
currentView: TExplorerView | null;
|
||||
enableScrollButtons: boolean;
|
||||
pageSize: number;
|
||||
pluginVersion: string | null;
|
||||
viewOrder: TExplorerView[];
|
||||
logLevel: string;
|
||||
}
|
||||
|
||||
interface BaseView {
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
interface TTableView extends BaseView {}
|
||||
|
||||
interface TListView extends BaseView {}
|
||||
|
||||
interface TGridView extends BaseView {}
|
||||
|
||||
interface TDashboardView extends BaseView {}
|
||||
|
||||
interface TFeedView extends BaseView {}
|
||||
|
||||
interface TRecommendedView extends BaseView {}
|
||||
|
||||
interface TRelatedView extends BaseView {}
|
||||
|
||||
interface BaseFilter {
|
||||
isEnabled: boolean;
|
||||
}
|
||||
|
||||
interface TSearchFilter extends BaseFilter {
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface TFavoritesFilter extends BaseFilter {
|
||||
value: boolean;
|
||||
}
|
||||
|
||||
interface TSortFilter extends BaseFilter {
|
||||
value: SortFilterOption;
|
||||
}
|
||||
|
||||
interface TTimestampFilter extends BaseFilter {
|
||||
value: TimestampFilterOption;
|
||||
}
|
||||
|
||||
interface TCustomFilter extends BaseFilter {
|
||||
selectedGroupId: string;
|
||||
groups: TFilterGroup[];
|
||||
}
|
||||
|
||||
type TimestampFilterOption =
|
||||
| "created-today"
|
||||
| "modified-today"
|
||||
| "created-this-week"
|
||||
| "modified-this-week"
|
||||
| "created-2-weeks"
|
||||
| "modified-2-weeks"
|
||||
| "all";
|
||||
|
||||
type SortFilterOption =
|
||||
| "file-name-asc"
|
||||
| "file-name-desc"
|
||||
| "modified-asc"
|
||||
| "modified-desc"
|
||||
| "random";
|
||||
|
||||
type WordBreak = "normal" | "break-word";
|
||||
|
||||
enum TExplorerView {
|
||||
DASHBOARD = "dashboard",
|
||||
GRID = "grid",
|
||||
LIST = "list",
|
||||
FEED = "feed",
|
||||
TABLE = "table",
|
||||
RECOMMENDED = "recommended",
|
||||
RELATED = "related",
|
||||
}
|
||||
|
||||
type FilterOperator = "and" | "or";
|
||||
|
||||
enum TextFilterCondition {
|
||||
IS = "is",
|
||||
IS_NOT = "is-not",
|
||||
CONTAINS = "contains",
|
||||
DOES_NOT_CONTAIN = "does-not-contain",
|
||||
STARTS_WITH = "starts-with",
|
||||
ENDS_WITH = "ends-with",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
enum ListFilterCondition {
|
||||
CONTAINS = "contains",
|
||||
DOES_NOT_CONTAIN = "does-not-contain",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
enum NumberFilterCondition {
|
||||
IS_EQUAL = "is-equal",
|
||||
IS_NOT_EQUAL = "is-not-equal",
|
||||
IS_GREATER = "is-greater",
|
||||
IS_LESS = "is-less",
|
||||
IS_GREATER_OR_EQUAL = "is-greater-or-equal",
|
||||
IS_LESS_OR_EQUAL = "is-less-or-equal",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
enum CheckboxFilterCondition {
|
||||
IS = "is",
|
||||
IS_NOT = "is-not",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
//TODO: add is between
|
||||
enum DateFilterCondition {
|
||||
IS = "is",
|
||||
IS_BEFORE = "is-before",
|
||||
IS_AFTER = "is-after",
|
||||
IS_ON_OR_BEFORE = "is-on-or-before",
|
||||
IS_ON_OR_AFTER = "is-on-or-after",
|
||||
EXISTS = "exists",
|
||||
DOES_NOT_EXIST = "does-not-exist",
|
||||
}
|
||||
|
||||
enum ContentFilterCondition {
|
||||
CONTAINS = "contains",
|
||||
DOES_NOT_CONTAIN = "does-not-contain",
|
||||
IS_EMPTY = "is-empty",
|
||||
IS_NOT_EMPTY = "is-not-empty",
|
||||
}
|
||||
|
||||
//TODO add is child of and is parent of?
|
||||
enum FolderFilterCondition {
|
||||
IS = "is",
|
||||
IS_NOT = "is-not",
|
||||
}
|
||||
|
||||
enum FileNameFilterCondition {
|
||||
IS = "is",
|
||||
IS_NOT = "is-not",
|
||||
CONTAINS = "contains",
|
||||
DOES_NOT_CONTAIN = "does-not-contain",
|
||||
STARTS_WITH = "starts-with",
|
||||
ENDS_WITH = "ends-with",
|
||||
}
|
||||
|
||||
type FilterCondition =
|
||||
| TextFilterCondition
|
||||
| NumberFilterCondition
|
||||
| DateFilterCondition
|
||||
| CheckboxFilterCondition
|
||||
| ListFilterCondition
|
||||
| ContentFilterCondition
|
||||
| FolderFilterCondition
|
||||
| FileNameFilterCondition;
|
||||
|
||||
//This matches the Obsidian property types
|
||||
enum PropertyType {
|
||||
TEXT = "text",
|
||||
NUMBER = "number",
|
||||
LIST = "list",
|
||||
CHECKBOX = "checkbox",
|
||||
DATE = "date",
|
||||
DATETIME = "datetime",
|
||||
}
|
||||
|
||||
enum FilterRuleType {
|
||||
PROPERTY = "property",
|
||||
FOLDER = "folder",
|
||||
FILE_NAME = "file-name",
|
||||
CONTENT = "content",
|
||||
}
|
||||
|
||||
enum DatePropertyFilterValue {
|
||||
TODAY = "today",
|
||||
TOMORROW = "tomorrow",
|
||||
YESTERDAY = "yesterday",
|
||||
ONE_WEEK_FROM_NOW = "one-week-from-now",
|
||||
ONE_WEEK_AGO = "one-week-ago",
|
||||
ONE_MONTH_FROM_NOW = "one-month-from-now",
|
||||
ONE_MONTH_AGO = "one-month-ago",
|
||||
CUSTOM = "custom",
|
||||
}
|
||||
|
||||
interface BaseFilterRule {
|
||||
id: string;
|
||||
operator: FilterOperator;
|
||||
type: FilterRuleType;
|
||||
condition: FilterCondition;
|
||||
isEnabled: boolean;
|
||||
value: string;
|
||||
matchWhenPropertyDNE: boolean;
|
||||
}
|
||||
|
||||
interface TextPropertyFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.PROPERTY;
|
||||
propertyType: PropertyType.TEXT;
|
||||
propertyName: string;
|
||||
condition: TextFilterCondition;
|
||||
}
|
||||
|
||||
interface NumberPropertyFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.PROPERTY;
|
||||
propertyType: PropertyType.NUMBER;
|
||||
propertyName: string;
|
||||
condition: NumberFilterCondition;
|
||||
}
|
||||
|
||||
interface ListPropertyFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.PROPERTY;
|
||||
propertyType: PropertyType.LIST;
|
||||
propertyName: string;
|
||||
condition: ListFilterCondition;
|
||||
}
|
||||
|
||||
interface CheckboxPropertyFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.PROPERTY;
|
||||
propertyType: PropertyType.CHECKBOX;
|
||||
propertyName: string;
|
||||
condition: CheckboxFilterCondition;
|
||||
}
|
||||
|
||||
interface DatePropertyFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.PROPERTY;
|
||||
propertyType: PropertyType.DATE | PropertyType.DATETIME;
|
||||
propertyName: string;
|
||||
condition: DateFilterCondition;
|
||||
valueData: string;
|
||||
}
|
||||
|
||||
interface FolderFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.FOLDER;
|
||||
condition: FolderFilterCondition;
|
||||
includeSubfolders: boolean;
|
||||
}
|
||||
|
||||
interface FileNameFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.FILE_NAME;
|
||||
condition: FileNameFilterCondition;
|
||||
}
|
||||
|
||||
interface ContentFilterRule extends BaseFilterRule {
|
||||
type: FilterRuleType.CONTENT;
|
||||
condition: ContentFilterCondition;
|
||||
}
|
||||
|
||||
type TFilterRule =
|
||||
| PropertyFilterRule
|
||||
| FolderFilterRule
|
||||
| FileNameFilterRule
|
||||
| ContentFilterRule;
|
||||
|
||||
type PropertyFilterRule =
|
||||
| TextPropertyFilterRule
|
||||
| NumberPropertyFilterRule
|
||||
| ListPropertyFilterRule
|
||||
| CheckboxPropertyFilterRule
|
||||
| DatePropertyFilterRule;
|
||||
|
||||
interface TFilterGroup {
|
||||
id: string;
|
||||
name: string;
|
||||
rules: TFilterRule[];
|
||||
isEnabled: boolean;
|
||||
isSticky: boolean;
|
||||
}
|
||||
|
|
@ -81,5 +81,6 @@
|
|||
"1.18.2": "1.4.13",
|
||||
"1.19.0": "1.4.13",
|
||||
"1.19.1": "1.4.13",
|
||||
"1.20.0": "1.4.13"
|
||||
"1.20.0": "1.4.13",
|
||||
"1.21.0": "1.4.13"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue