Compare commits

...
2 Commits
Author SHA1 Message Date
amadou 6773adc470 Merge remote-tracking branch 'origin/main' 2026-08-21 14:10:09 +02:00
amadou cf6f8229e3 vault backup: 2026-08-21 14:10:09 2026-08-21 14:10:09 +02:00
8 changed files with 299 additions and 717 deletions
-1
View File
@@ -1,7 +1,6 @@
[ [
"iconic", "iconic",
"folder-links", "folder-links",
"settings-search",
"omnisearch", "omnisearch",
"editing-toolbar", "editing-toolbar",
"obsidian-local-rest-api", "obsidian-local-rest-api",
+4 -3
View File
@@ -195,8 +195,7 @@
"folderSortOrder": "alpha-asc", "folderSortOrder": "alpha-asc",
"enableFolderNotes": true, "enableFolderNotes": true,
"folderNoteType": "markdown", "folderNoteType": "markdown",
"folderNoteName": "", "folderNoteNamePattern": "{{folder}}",
"folderNoteNamePattern": "",
"folderNoteTemplate": null, "folderNoteTemplate": null,
"enableFolderNoteLinks": true, "enableFolderNoteLinks": true,
"hideFolderNoteInList": true, "hideFolderNoteInList": true,
@@ -262,6 +261,7 @@
"unfinishedTaskBackgroundColor": "#ef000050", "unfinishedTaskBackgroundColor": "#ef000050",
"unfinishedTaskBackgroundColorDark": "#ef000050", "unfinishedTaskBackgroundColorDark": "#ef000050",
"showFileIcons": true, "showFileIcons": true,
"unfinishedTaskIcon": "compact",
"useFolderIconForFiles": false, "useFolderIconForFiles": false,
"showFilenameMatchIcons": false, "showFilenameMatchIcons": false,
"fileNameIconMap": {}, "fileNameIconMap": {},
@@ -323,6 +323,7 @@
"calendarMonthHighlights": {}, "calendarMonthHighlights": {},
"calendarShowWeekNumber": false, "calendarShowWeekNumber": false,
"calendarShowQuarter": false, "calendarShowQuarter": false,
"calendarShowOutsideMonthDays": true,
"calendarShowYearCalendar": true, "calendarShowYearCalendar": true,
"calendarLeftPlacement": "navigation", "calendarLeftPlacement": "navigation",
"calendarWeeksToShow": 1, "calendarWeeksToShow": 1,
@@ -560,7 +561,7 @@
"#404040", "#404040",
"#404040" "#404040"
], ],
"lastShownVersion": "3.3.2", "lastShownVersion": "3.3.4",
"rootFolderOrder": [], "rootFolderOrder": [],
"rootTagOrder": [], "rootTagOrder": [],
"rootPropertyOrder": [] "rootPropertyOrder": []
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "notebook-navigator", "id": "notebook-navigator",
"name": "Notebook Navigator", "name": "Notebook Navigator",
"version": "3.3.2", "version": "3.3.4",
"minAppVersion": "1.11.0", "minAppVersion": "1.11.0",
"description": "Replace the default file explorer with a clean two-pane interface featuring folder tree, tag browsing, file previews, keyboard navigation, drag-and-drop, pinned notes, and customizable display options.", "description": "Replace the default file explorer with a clean two-pane interface featuring folder tree, tag browsing, file previews, keyboard navigation, drag-and-drop, pinned notes, and customizable display options.",
"author": "Johan Sanneblad", "author": "Johan Sanneblad",
+130 -5
View File
@@ -247,8 +247,8 @@ body {
--nn-theme-file-preview-color: var(--nn-theme-foreground-muted); --nn-theme-file-preview-color: var(--nn-theme-foreground-muted);
--nn-theme-file-preview-font-weight: 400; --nn-theme-file-preview-font-weight: 400;
/* --nn-theme-file-task-color and --nn-theme-file-task-complete-color are /* --nn-theme-file-task-color and --nn-theme-file-task-complete-color are
intentionally not declared here: task progress rules use var() fallbacks to detect whether intentionally not declared here: task progress and replacement icon rules use var() fallbacks
a theme or Style Settings set them, so customized colors can persist on selected rows. */ to detect whether a theme or Style Settings set them, so customized colors can persist on selected rows. */
--nn-theme-file-task-font-weight: 400; --nn-theme-file-task-font-weight: 400;
--nn-theme-file-task-complete-font-weight: 400; --nn-theme-file-task-complete-font-weight: 400;
--nn-theme-file-date-color: var(--nn-theme-foreground-faded); --nn-theme-file-date-color: var(--nn-theme-foreground-faded);
@@ -2975,6 +2975,8 @@ button.nn-navigation-calendar-year-month {
z-index: 1; z-index: 1;
display: block; display: block;
max-width: 100%; max-width: 100%;
/* Keeps Windows interface-font descenders inside the clipped label used for horizontal ellipsis. */
line-height: 1.2;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
@@ -4023,7 +4025,7 @@ button.nn-navigation-calendar-day {
color: var(--nn-file-name-custom-color); color: var(--nn-file-name-custom-color);
} }
.nn-file-word-count-suffix { .nn-file-name-suffix {
color: var(--nn-theme-file-word-count-color); color: var(--nn-theme-file-word-count-color);
font-weight: var(--nn-theme-file-word-count-font-weight); font-weight: var(--nn-theme-file-word-count-font-weight);
} }
@@ -4112,6 +4114,16 @@ button.nn-navigation-calendar-day {
color: var(--nn-theme-navitem-selected-icon-color); color: var(--nn-theme-navitem-selected-icon-color);
} }
/* A configured task color remains stable across selection states. Without one, the replacement
follows the same normal and selected colors as the file icon it replaces. */
.nn-file-icon.nn-file-icon-unfinished-task[data-has-color='false'] {
color: var(--nn-theme-file-task-color, var(--nn-theme-navitem-icon-color));
}
.nn-file.nn-selected .nn-file-icon.nn-file-icon-unfinished-task[data-has-color='false'] {
color: var(--nn-theme-file-task-color, var(--nn-theme-navitem-selected-icon-color));
}
/* Quick actions panel - horizontal container for action icons */ /* Quick actions panel - horizontal container for action icons */
.nn-quick-actions-panel { .nn-quick-actions-panel {
position: absolute; position: absolute;
@@ -4224,6 +4236,14 @@ button.nn-navigation-calendar-day {
flex-shrink: 0; flex-shrink: 0;
} }
/* Emoji and icon-font providers render the glyph on the container instead of adding an SVG,
so they need an explicit font size to match the task indicator box. */
.nn-file-task-progress-icon.nn-emoji-icon,
.nn-file-task-progress-icon.nn-iconfont {
font-size: calc(var(--icon-size) * 0.8);
line-height: calc(var(--icon-size) * 0.8);
}
/* The icon has no font weight, so its stroke width tracks the state weight variable instead: /* The icon has no font weight, so its stroke width tracks the state weight variable instead:
weight 400 maps to the lucide default stroke of 2, weight 600 to 2.5, keeping the icon's weight 400 maps to the lucide default stroke of 2, weight 600 to 2.5, keeping the icon's
visual boldness in sync with the count text. */ visual boldness in sync with the count text. */
@@ -4554,7 +4574,7 @@ button.nn-navigation-calendar-day {
); );
} }
.nn-file.nn-selected .nn-file-word-count-suffix { .nn-file.nn-selected .nn-file-name-suffix {
color: var(--nn-selected-file-word-count-color); color: var(--nn-selected-file-word-count-color);
} }
@@ -5495,6 +5515,11 @@ body.nn-resizing {
.nn-file.nn-compact.nn-context-menu-active:not(.nn-selected) .nn-file-content::after { .nn-file.nn-compact.nn-context-menu-active:not(.nn-selected) .nn-file-content::after {
border-radius: min(14px, var(--nn-theme-navitem-border-radius)); border-radius: min(14px, var(--nn-theme-navitem-border-radius));
} }
/* Appearance menu entries holding a per-selection custom value are marked in bold */
.nn-menu-title-custom {
font-weight: 600;
}
/* Source: src/styles/sections/state-hidden-items.css */ /* Source: src/styles/sections/state-hidden-items.css */
/* ======================================================================== /* ========================================================================
@@ -7428,6 +7453,99 @@ button.nn-youtube-button svg {
text-align: right; text-align: right;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
} }
/* Cards linking to the author's other plugins on the settings start page */
.setting-item.nn-plugin-cards {
display: block;
}
/* One column when the settings pane is narrow, because the description needs the width */
.nn-plugin-card-list {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(16em, 1fr));
gap: var(--size-4-2);
margin-top: var(--size-4-2);
}
/* A button so the whole card can be reached from the keyboard. The declarations before the
layout undo the button styling a theme applies. */
.nn-plugin-card {
height: auto;
padding: var(--size-4-3);
background-color: var(--background-secondary);
box-shadow: none;
text-align: start;
white-space: normal;
display: flex;
align-items: flex-start;
gap: var(--size-4-3);
width: 100%;
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-m);
cursor: pointer;
}
.nn-plugin-card:hover {
border-color: var(--background-modifier-border-hover);
background-color: var(--background-modifier-hover);
}
.nn-plugin-card-icon {
display: flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
width: var(--size-4-8);
height: var(--size-4-8);
border-radius: var(--radius-m);
background-color: var(--background-primary);
color: var(--text-accent);
}
/* min-width lets a long word wrap instead of stretching the card past its column */
.nn-plugin-card-details {
display: flex;
flex-direction: column;
gap: var(--size-2-1);
min-width: 0;
}
.nn-plugin-card-name {
color: var(--text-normal);
font-size: var(--font-ui-small);
font-weight: var(--font-semibold);
line-height: 1.3;
}
/* One line whatever the language, cut with an ellipsis, so every card is the same height */
.nn-plugin-card-description {
color: var(--text-muted);
font-size: var(--font-ui-smaller);
line-height: 1.4;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Sits at the far edge, the way Obsidian marks a row that opens somewhere else. It keeps to
the middle of the card while the icon and the name line up at the top. */
.nn-plugin-card-arrow {
display: flex;
align-items: center;
align-self: center;
flex: 0 0 auto;
margin-inline-start: auto;
color: var(--text-faint);
}
.nn-plugin-card-arrow .svg-icon {
width: var(--icon-s);
height: var(--icon-s);
}
.nn-plugin-card:hover .nn-plugin-card-arrow {
color: var(--text-muted);
}
/* Source: src/styles/sections/settings-sponsor-button.css */ /* Source: src/styles/sections/settings-sponsor-button.css */
/* ======================================================================== /* ========================================================================
@@ -8906,6 +9024,13 @@ body.is-phone .notebook-navigator-android .nn-split-container {
font-size: calc(var(--nn-file-icon-size-mobile, var(--nn-file-icon-size)) * var(--nn-android-font-scale-reciprocal, 1)); font-size: calc(var(--nn-file-icon-size-mobile, var(--nn-file-icon-size)) * var(--nn-android-font-scale-reciprocal, 1));
} }
/* Task indicators are smaller than file icons, so preserve their 80% size while compensating
for Android textZoom. Without this override, the general icon rule above enlarges them. */
.notebook-navigator-android .nn-mobile .nn-file-task-progress-icon.nn-emoji-icon,
.notebook-navigator-android .nn-mobile .nn-file-task-progress-icon.nn-iconfont {
font-size: calc(var(--icon-size) * 0.8 * var(--nn-android-font-scale-reciprocal, 1));
}
/* Clamp height compensation - Android doesn't scale max-height, so match the compensated line-height after textZoom applies. */ /* Clamp height compensation - Android doesn't scale max-height, so match the compensated line-height after textZoom applies. */
.notebook-navigator-android .nn-file-name { .notebook-navigator-android .nn-file-name {
max-height: calc(var(--nn-file-title-line-height) * var(--filename-rows, 1) * var(--nn-android-font-scale, 1)); max-height: calc(var(--nn-file-title-line-height) * var(--filename-rows, 1) * var(--nn-android-font-scale, 1));
@@ -9713,7 +9838,7 @@ settings:
- -
id: nn-theme-file-task-color id: nn-theme-file-task-color
title: File task color title: File task color
description: Icon, bar, and count color for notes with unfinished tasks. description: Color for the task display and replacement file icon in notes with unfinished tasks.
type: variable-themed-color type: variable-themed-color
format: hex format: hex
default-light: '#' default-light: '#'
-512
View File
@@ -1,512 +0,0 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __export = (target, all) => {
__markAsModule(target);
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __reExport = (target, module2, desc) => {
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
for (let key of __getOwnPropNames(module2))
if (!__hasOwnProp.call(target, key) && key !== "default")
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
}
return target;
};
var __toModule = (module2) => {
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
};
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
// src/main.ts
__export(exports, {
default: () => SettingsSearch
});
var import_obsidian = __toModule(require("obsidian"));
// node_modules/monkey-around/mjs/index.js
function around(obj, factories) {
const removers = Object.keys(factories).map((key) => around1(obj, key, factories[key]));
return removers.length === 1 ? removers[0] : function() {
removers.forEach((r) => r());
};
}
function around1(obj, method, createWrapper) {
const original = obj[method], hadOwn = obj.hasOwnProperty(method);
let current = createWrapper(original);
if (original)
Object.setPrototypeOf(current, original);
Object.setPrototypeOf(wrapper, current);
obj[method] = wrapper;
return remove;
function wrapper(...args) {
if (current === original && obj[method] === wrapper)
remove();
return current.apply(this, args);
}
function remove() {
if (obj[method] === wrapper) {
if (hadOwn)
obj[method] = original;
else
delete obj[method];
}
if (current === original)
return;
current = original;
Object.setPrototypeOf(wrapper, original || Function);
}
}
// src/main.ts
var SettingsSearch = class extends import_obsidian.Plugin {
constructor() {
super(...arguments);
__publicField(this, "settingsSearchEl", createDiv("settings-search-container vertical-tab-header-group"));
__publicField(this, "settingsResultsContainerEl", createDiv("settings-search-results-container vertical-tab-content"));
__publicField(this, "settingsNavItemContainer", this.settingsSearchEl.createDiv("vertical-tab-header-group-items").createDiv("vertical-tab-nav-item settings-search-input"));
__publicField(this, "settingsResultsEl");
__publicField(this, "search");
__publicField(this, "locale");
__publicField(this, "resources", []);
__publicField(this, "results", []);
__publicField(this, "loaded", false);
__publicField(this, "tabIndex", 0);
__publicField(this, "pluginTabIndex", 0);
__publicField(this, "seen", []);
__publicField(this, "settingCache", new Map());
__publicField(this, "searchAppended", false);
__publicField(this, "activeIndex", -1);
__publicField(this, "activeSetting");
__publicField(this, "scope", new import_obsidian.Scope(this.app.scope));
__publicField(this, "mobileContainers", []);
}
async onload() {
(window["SettingsSearch"] = {
addResources: this.addResources.bind(this),
removeResources: this.removeResources.bind(this),
removeTabResources: this.removeTabResources.bind(this)
}) && this.register(() => delete window["SettingsSearch"]);
this.app.workspace.onLayoutReady(async () => {
this.settingsResultsContainerEl.createEl("h3", {
text: "Settings Search Results"
});
this.settingsResultsEl = this.settingsResultsContainerEl.createDiv("settings-search-results");
this.buildScope();
this.buildSearch();
this.buildResources();
this.buildPluginResources();
this.patchSettings();
this.loaded = true;
this.app.workspace.trigger("settings-search-loaded");
});
}
buildResources() {
const tab = this.app.setting.settingTabs[this.tabIndex];
if (tab && tab.id !== void 0 && !this.seen.includes(tab.id)) {
this.getTabResources(tab);
this.tabIndex++;
setTimeout(() => this.buildResources());
}
}
buildPluginResources() {
const tab = this.app.setting.pluginTabs[this.pluginTabIndex];
if (tab) {
this.getTabResources(tab);
this.pluginTabIndex++;
setTimeout(() => this.buildPluginResources());
}
}
get manifests() {
return Object.values(this.app.plugins.manifests);
}
addResourceToCache(resource) {
if (!resource || !resource.text || !resource.name || !resource.tab) {
return new Error("A valid resource must be provided.");
}
let name;
if (resource.external) {
name = createFragment((el) => {
(0, import_obsidian.setIcon)(el.createSpan({
attr: {
"aria-label": "This setting was added by another plugin."
}
}), "info");
el.createSpan({ text: resource.text });
});
} else {
name = resource.text;
}
const setting = new import_obsidian.Setting(createDiv()).setName(name).setDesc(createFragment((e) => e.createDiv().innerHTML = resource.desc ?? ""));
if (resource.external) {
setting.settingEl.addClass("set-externally");
}
if (resource.tab == "community-plugins") {
let plugin = this.manifests.find((p) => p.name == resource.text);
if (plugin && this.app.plugins.getPlugin(plugin.id)?._loaded && this.app.setting.pluginTabs.find((t) => t.id == plugin.id)) {
setting.addExtraButton((b) => {
b.setTooltip(`Open ${resource.text} Settings`).onClick(() => {
this.app.setting.openTabById(plugin.id);
});
});
}
}
if (resource.tab == "plugins") {
const plugins = Object.values(this.app.internalPlugins.plugins);
const plugin = plugins.find((p) => p._loaded && p.instance.name == resource.text);
if (plugin && this.app.setting.pluginTabs.find((t) => t.id == plugin.instance.id)) {
setting.addExtraButton((b) => {
b.setTooltip(`Open ${resource.text} Settings`).onClick(() => {
this.app.setting.openTabById(plugin.instance.id);
});
});
}
}
setting.addExtraButton((b) => {
b.setIcon("forward-arrow").onClick(() => {
this.showResult(resource);
});
});
this.settingCache.set(resource, setting);
}
getResourceFromCache(resource) {
if (!this.settingCache.has(resource)) {
this.addResourceToCache(resource);
}
return this.settingCache.get(resource);
}
removeResourcesFromCache(resources) {
for (const resource of resources) {
this.settingCache.delete(resource);
}
}
addResources(...resources) {
for (const resource of resources) {
resource.external = true;
if (this.resources.find((k) => this.equivalent(resource, k)))
continue;
this.resources.push(resource);
this.addResourceToCache(resource);
}
return () => this.removeResources(...resources);
}
equivalent(resource1, resource2) {
return resource1.name == resource2.name && resource1.tab == resource2.tab && resource1.text == resource2.text && resource1.desc == resource2.desc && resource1.external == resource2.external;
}
removeResources(...resources) {
const removing = [];
const keys = [...this.settingCache.keys()];
for (const resource of resources) {
if (!resource || !resource.text || !resource.name || !resource.tab) {
continue;
}
resource.external = true;
this.resources = this.resources.filter((r) => !this.equivalent(resource, r));
removing.push(...keys.filter((k) => k == resource || this.equivalent(resource, k)));
}
this.removeResourcesFromCache(removing);
}
removeTabResources(tab) {
const removing = this.resources.filter((t) => t.tab == tab);
this.resources = this.resources.filter((t) => t.tab != tab);
this.removeResourcesFromCache(removing);
}
async getTabResources(tab) {
await tab.display();
const settings = tab.containerEl.querySelectorAll(".setting-item:not(.setting-item-header)");
for (const el of Array.from(settings)) {
const text = el.querySelector(".setting-item-name")?.textContent;
if (!text)
continue;
const desc = el.querySelector(".setting-item-description")?.innerHTML ?? "";
const resource = {
tab: tab.id,
name: tab.name,
text,
desc
};
this.resources.push(resource);
this.addResourceToCache(resource);
}
if (this.app.setting.activeTab?.id == tab.id)
return;
this.seen.push(tab.id);
tab.containerEl.detach();
tab.hide();
}
patchSettings() {
const self = this;
this.register(around(this.app.setting, {
onOpen: function(next) {
return function() {
next.apply(this);
if (!import_obsidian.Platform.isMobile)
self.search.inputEl.focus();
return next;
};
}
}));
this.register(around(this.app.setting, {
addSettingTab: function(next) {
return function(tab) {
if (tab && tab.id !== void 0 && !self.seen.includes(tab.id)) {
self.getTabResources(tab);
}
return next.call(this, tab);
};
}
}));
this.register(around(this.app.setting, {
removeSettingTab: function(next) {
return function(tab) {
if (this.isPluginSettingTab(tab)) {
self.removeTabResources(tab.id);
}
return next.call(this, tab);
};
}
}));
this.register(around(this.app.setting, {
openTab: function(next) {
return function(tab) {
self.searchAppended = false;
self.app.keymap.popScope(self.scope);
return next.call(this, tab);
};
},
openTabById: function(next) {
return function(tab) {
self.searchAppended = false;
self.app.keymap.popScope(self.scope);
return next.call(this, tab);
};
},
onClose: function(next) {
return function() {
if (import_obsidian.Platform.isMobile) {
self.detach();
}
return next.call(this);
};
}
}));
}
buildSearch() {
const tempSetting = new import_obsidian.Setting(createDiv()).addSearch((s) => {
this.search = s;
});
this.settingsNavItemContainer.append(tempSetting.controlEl);
tempSetting.settingEl.detach();
this.search.onChange((v) => {
this.onChange(v);
});
this.search.setPlaceholder("Search settings...");
this.app.setting.tabHeadersEl.prepend(this.settingsSearchEl);
}
buildScope() {
this.scope.register(["Ctrl"], "N", () => {
if (this.activeSetting) {
this.activeSetting.settingEl.removeClass("active");
}
this.activeIndex = ((this.activeIndex + 1) % this.results.length + this.results.length) % this.results.length;
this.centerActiveSetting();
});
this.scope.register([], "ArrowDown", () => {
if (this.activeSetting) {
this.activeSetting.settingEl.removeClass("active");
}
this.activeIndex = ((this.activeIndex + 1) % this.results.length + this.results.length) % this.results.length;
this.centerActiveSetting();
});
this.scope.register(["Ctrl"], "P", () => {
if (this.activeSetting) {
this.activeSetting.settingEl.removeClass("active");
}
this.activeIndex = ((this.activeIndex - 1) % this.results.length + this.results.length) % this.results.length;
this.centerActiveSetting();
});
this.scope.register([], "ArrowUp", () => {
if (this.activeSetting) {
this.activeSetting.settingEl.removeClass("active");
}
this.activeIndex = ((this.activeIndex - 1) % this.results.length + this.results.length) % this.results.length;
this.centerActiveSetting();
});
this.scope.register([], "Enter", () => {
if (this.activeSetting) {
this.showResult(this.results[this.activeIndex]);
}
});
}
centerActiveSetting() {
const result = this.results[this.activeIndex];
this.activeSetting = this.getResourceFromCache(result);
this.activeSetting.settingEl.addClass("active");
this.activeSetting.settingEl.scrollIntoView({
behavior: "auto",
block: "nearest"
});
}
detachFromMobile() {
if (import_obsidian.Platform.isMobile) {
this.settingsResultsContainerEl.detach();
for (const header of this.mobileContainers) {
this.app.setting.tabHeadersEl.append(header);
}
this.search.setValue("");
}
}
detachFromDesktop() {
if (import_obsidian.Platform.isDesktop) {
this.app.setting.openTabById(this.app.setting.lastTabId);
}
}
detach() {
this.detachFromDesktop();
this.detachFromMobile();
this.searchAppended = false;
}
onChange(v) {
if (!v) {
this.detach();
this.app.keymap.popScope(this.scope);
return;
}
if (!this.searchAppended) {
this.activeIndex = -1;
this.app.keymap.popScope(this.scope);
this.app.keymap.pushScope(this.scope);
if (this.activeSetting) {
this.activeSetting.settingEl.removeClass("active");
this.activeSetting = null;
}
if (!import_obsidian.Platform.isMobile) {
this.app.setting.activeTab.navEl.removeClass("is-active");
this.app.setting.tabContentContainer.empty();
this.app.setting.tabContentContainer.append(this.settingsResultsContainerEl);
} else {
const headers = this.app.setting.tabHeadersEl.querySelectorAll(".vertical-tab-header-group:not(.settings-search-container)");
for (const header of Array.from(headers)) {
this.mobileContainers.push(header);
header.detach();
}
this.app.setting.tabHeadersEl.append(this.settingsResultsContainerEl);
}
this.searchAppended = true;
}
this.appendResults(this.performFuzzySearch(v));
}
getMatchText(text, result) {
const matchElements = {};
return createFragment((content) => {
for (let i = 0; i < text.length; i++) {
let match = result.matches.find((m) => m[0] === i);
if (match) {
const index = result.matches.indexOf(match);
if (!matchElements[index]) {
matchElements[index] = createSpan("suggestion-highlight");
}
let element = matchElements[index];
content.appendChild(element);
element.appendText(text.substring(match[0], match[1]));
i += match[1] - match[0] - 1;
continue;
}
content.appendText(text[i]);
}
});
}
appendResults(results) {
this.settingsResultsEl.empty();
if (results.length) {
const headers = {};
for (const resource of results) {
if (!(resource.tab in headers)) {
headers[resource.tab] = this.settingsResultsEl.createDiv();
new import_obsidian.Setting(headers[resource.tab]).setHeading().setName(resource.name);
}
const setting = this.getResourceFromCache(resource);
headers[resource.tab].append(setting.settingEl);
}
} else {
this.settingsResultsEl.setText("No results found :(");
}
}
showResult(result) {
this.search.setValue("");
const tab = this.app.setting.settingTabs.find((t) => t.id == result.tab) ?? this.app.setting.pluginTabs.find((t) => t.id == result.tab);
if (!tab) {
new import_obsidian.Notice("There was an issue opening the setting tab.");
return;
}
this.app.setting.openTabById(tab.id);
this.app.keymap.popScope(this.scope);
this.detach();
try {
const names = tab.containerEl.querySelectorAll(".setting-item-name");
const el = Array.from(names).find((n) => n.textContent == result.text);
if (!el)
return;
const setting = el.closest(".setting-item");
if (!setting)
return;
if (tab.id == "obsidian-style-settings") {
let collapsed = setting.closest(".style-settings-container");
let previous = collapsed?.previousElementSibling;
while (previous != null && previous.hasClass("is-collapsed") && previous.hasClass("style-settings-heading")) {
previous.removeClass("is-collapsed");
collapsed = collapsed.parentElement?.closest(".style-settings-container");
previous = collapsed?.previousElementSibling;
}
}
let details = setting.closest("details");
while (details) {
details.setAttr("open", "open");
details = details.parentElement?.closest("details");
}
setting.scrollIntoView(true);
setting.addClass("is-flashing");
window.setTimeout(() => setting.removeClass("is-flashing"), 3e3);
} catch (e) {
console.error(e);
}
}
performFuzzySearch(input) {
const results = [], hotkeys = [];
for (const resource of this.resources) {
let result = (0, import_obsidian.prepareSimpleSearch)(input)(resource.text) ?? (0, import_obsidian.prepareSimpleSearch)(input)(resource.desc);
if (result) {
if (resource.tab == "hotkeys") {
hotkeys.push(resource);
} else {
results.push(resource);
}
}
}
this.results = [...results, ...hotkeys];
return this.results;
}
onunload() {
this.settingsSearchEl.detach();
this.settingsResultsEl.detach();
this.detach();
if (this.searchAppended && import_obsidian.Platform.isDesktop)
this.app.setting.openTabById(this.app.setting.lastTabId);
}
};
/* nosourcemap */
-10
View File
@@ -1,10 +0,0 @@
{
"id": "settings-search",
"name": "Settings Search",
"version": "1.3.10",
"minAppVersion": "0.12.17",
"author": "Jeremy Valentine",
"description": "Globally search settings in Obsidian.md",
"authorUrl": "https://github.com/valentine195",
"isDesktopOnly": false
}
-25
View File
@@ -1,25 +0,0 @@
/* src/assets/main.css */
.settings-search-container.vertical-tab-header-group {
padding-bottom: 0;
}
.settings-search-input {
padding-left: 6px;
}
.vertical-tab-nav-item.settings-search-input {
background-color: inherit !important;
}
.settings-search-input .setting-item-control {
display: block;
}
.settings-search-input .search-input-container {
margin: 0;
}
.settings-search-results .setting-item.active {
background-color: var(--background-secondary);
}
.settings-search-results .set-externally .setting-item-name {
display: flex;
gap: 0.5rem;
}
/* src/styles.css */