mirror of
https://github.com/miro0o/miniWorldMap.git
synced 2026-07-22 07:46:00 +00:00
Release 0.2.2
This commit is contained in:
parent
53cc944d25
commit
f6cdeb16c6
14 changed files with 372 additions and 353 deletions
|
|
@ -1,5 +1,12 @@
|
|||
# Changelog
|
||||
|
||||
## 0.2.2
|
||||
|
||||
- Address Obsidian community plugin review findings around settings APIs, command names, deprecated slider tooltips, direct static styles, and config folder handling.
|
||||
- Raise the minimum supported Obsidian version to 1.13.0 for the current settings definitions API.
|
||||
- Remove reveal CSS that relied on partially supported browser features in older Obsidian builds.
|
||||
- Tighten 2D neighbor list typing and add regression coverage for configured vault folders.
|
||||
|
||||
## 0.2.1
|
||||
|
||||
- Add default day/night map background fallbacks when the active Obsidian theme cannot provide a matching background color.
|
||||
|
|
|
|||
348
main.js
348
main.js
File diff suppressed because one or more lines are too long
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"id": "mini-world-map",
|
||||
"name": "Mini World Map",
|
||||
"version": "0.2.1",
|
||||
"minAppVersion": "1.5.0",
|
||||
"version": "0.2.2",
|
||||
"minAppVersion": "1.13.0",
|
||||
"description": "Visualize your vault as a hierarchy-first world map with internal links layered on top.",
|
||||
"author": "Miro0o and Codex",
|
||||
"authorUrl": "https://github.com/Miro0o",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
}
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "mini-world-map",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mini-world-map",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"3d-force-graph": "1.80.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "mini-world-map",
|
||||
"version": "0.2.1",
|
||||
"version": "0.2.2",
|
||||
"description": "Hierarchy-first 2D radial rings and 3D map views for your Obsidian vault",
|
||||
"main": "main.js",
|
||||
"type": "module",
|
||||
|
|
|
|||
298
src/main.ts
298
src/main.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { Notice, Plugin, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { Notice, Plugin, PluginSettingTab, Setting, type App, type SettingDefinitionItem, type SettingDefinitionRender } from 'obsidian';
|
||||
import { VIEW_TYPE_MINI_WORLD_MAP } from './constants';
|
||||
import type { Language, MiniWorldMapSettings, ViewMode } from './settings';
|
||||
import {
|
||||
|
|
@ -10,6 +10,7 @@ import {
|
|||
MAX_LINK_LIMIT,
|
||||
MAX_RENDER_NODE_LIMIT,
|
||||
MAX_SWIRL_STRENGTH,
|
||||
applyVaultConfigDirDefault,
|
||||
clampNumber,
|
||||
mergeSettings,
|
||||
normalizeHoverHighlightMode,
|
||||
|
|
@ -26,7 +27,8 @@ export default class MiniWorldMapPlugin extends Plugin {
|
|||
|
||||
async onload(): Promise<void> {
|
||||
console.info('[Mini World Map] loading');
|
||||
this.settings = mergeSettings(await this.loadData());
|
||||
const saved = await this.loadData();
|
||||
this.settings = applyVaultConfigDirDefault(mergeSettings(saved), saved, this.app.vault.configDir);
|
||||
this.registerView(VIEW_TYPE_MINI_WORLD_MAP, (leaf) => new MiniWorldMapView(leaf, this));
|
||||
|
||||
this.addRibbonIcon('network', 'Open Mini World Map', () => {
|
||||
|
|
@ -35,13 +37,13 @@ export default class MiniWorldMapPlugin extends Plugin {
|
|||
|
||||
this.addCommand({
|
||||
id: 'open-map',
|
||||
name: 'Open Mini World Map',
|
||||
name: 'Open map',
|
||||
callback: () => void this.activateView(),
|
||||
});
|
||||
|
||||
this.addCommand({
|
||||
id: 'toggle-render-mode',
|
||||
name: 'Toggle Mini World Map render mode',
|
||||
name: 'Toggle render mode',
|
||||
callback: () => {
|
||||
this.setViewMode(this.settings.viewMode === 'radial2d' ? 'map3d' : 'radial2d');
|
||||
void this.activateView();
|
||||
|
|
@ -50,7 +52,7 @@ export default class MiniWorldMapPlugin extends Plugin {
|
|||
|
||||
this.addCommand({
|
||||
id: 'rebuild-index',
|
||||
name: 'Rebuild Mini World Map index',
|
||||
name: 'Rebuild index',
|
||||
callback: () => {
|
||||
let rebuilt = false;
|
||||
for (const leaf of this.app.workspace.getLeavesOfType(VIEW_TYPE_MINI_WORLD_MAP)) {
|
||||
|
|
@ -66,7 +68,7 @@ export default class MiniWorldMapPlugin extends Plugin {
|
|||
|
||||
this.addCommand({
|
||||
id: 'search-3d',
|
||||
name: 'Search Mini World Map',
|
||||
name: 'Search map',
|
||||
callback: () => {
|
||||
void this.activateView().then((view) => {
|
||||
const controller = view?.controller;
|
||||
|
|
@ -119,167 +121,155 @@ export default class MiniWorldMapPlugin extends Plugin {
|
|||
|
||||
class MiniWorldMapSettingTab extends PluginSettingTab {
|
||||
constructor(
|
||||
app: import('obsidian').App,
|
||||
app: App,
|
||||
private plugin: MiniWorldMapPlugin,
|
||||
) {
|
||||
super(app, plugin);
|
||||
}
|
||||
|
||||
display(): void {
|
||||
const { containerEl } = this;
|
||||
getSettingDefinitions(): SettingDefinitionItem[] {
|
||||
const radial = this.plugin.settings.radial;
|
||||
const language = this.plugin.settings.language;
|
||||
containerEl.empty();
|
||||
containerEl.createEl('h2', { text: t(language, 'settings.title') });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'language'))
|
||||
.setDesc(t(language, 'settings.languageDesc'))
|
||||
.addDropdown((dropdown) => {
|
||||
for (const [value, label] of languageOptions(language)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(this.plugin.settings.language).onChange(async (value) => {
|
||||
this.plugin.settings.language = normalizeLanguage(value);
|
||||
await this.plugin.saveSettings();
|
||||
this.display();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'settings.defaultMode'))
|
||||
.setDesc(t(language, 'settings.defaultModeDesc'))
|
||||
.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOption('radial2d', viewModeLabel(language, 'radial2d'))
|
||||
.addOption('map3d', viewModeLabel(language, 'map3d'))
|
||||
.setValue(this.plugin.settings.viewMode)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.viewMode = normalizeViewMode(value);
|
||||
await this.plugin.saveSettings();
|
||||
return [
|
||||
{
|
||||
type: 'group',
|
||||
heading: t(language, 'settings.title'),
|
||||
items: [
|
||||
this.renderSetting(t(language, 'language'), t(language, 'settings.languageDesc'), (setting) => {
|
||||
setting.addDropdown((dropdown) => {
|
||||
for (const [value, label] of languageOptions(language)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(this.plugin.settings.language).onChange(async (value) => {
|
||||
this.plugin.settings.language = normalizeLanguage(value);
|
||||
await this.plugin.saveSettings();
|
||||
this.update();
|
||||
});
|
||||
});
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.defaultDepth'))
|
||||
.setDesc(t(language, 'settings.depthDesc'))
|
||||
.addSlider((slider) =>
|
||||
slider
|
||||
.setLimits(1, 20, 1)
|
||||
.setValue(radial.atlasDepth)
|
||||
.setDynamicTooltip()
|
||||
.onChange(async (value) => {
|
||||
radial.atlasDepth = clampNumber(value, 1, MAX_ATLAS_DEPTH, DEFAULT_RADIAL_SETTINGS.atlasDepth);
|
||||
await this.plugin.saveSettings();
|
||||
this.renderSetting(t(language, 'settings.defaultMode'), t(language, 'settings.defaultModeDesc'), (setting) => {
|
||||
setting.addDropdown((dropdown) =>
|
||||
dropdown
|
||||
.addOption('radial2d', viewModeLabel(language, 'radial2d'))
|
||||
.addOption('map3d', viewModeLabel(language, 'map3d'))
|
||||
.setValue(this.plugin.settings.viewMode)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.viewMode = normalizeViewMode(value);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.defaultNodes'))
|
||||
.setDesc(t(language, 'settings.nodeLimitDesc'))
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(String(DEFAULT_RADIAL_SETTINGS.renderNodeLimit))
|
||||
.setValue(String(radial.renderNodeLimit))
|
||||
.onChange(async (value) => {
|
||||
radial.renderNodeLimit = clampNumber(value, 200, MAX_RENDER_NODE_LIMIT, DEFAULT_RADIAL_SETTINGS.renderNodeLimit);
|
||||
await this.plugin.saveSettings();
|
||||
this.renderSetting(t(language, 'control.defaultDepth'), t(language, 'settings.depthDesc'), (setting) => {
|
||||
setting.addSlider((slider) =>
|
||||
slider
|
||||
.setLimits(1, 20, 1)
|
||||
.setValue(radial.atlasDepth)
|
||||
.onChange(async (value) => {
|
||||
radial.atlasDepth = clampNumber(value, 1, MAX_ATLAS_DEPTH, DEFAULT_RADIAL_SETTINGS.atlasDepth);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.defaultNoteLinks'))
|
||||
.setDesc(t(language, 'settings.linkLimitDesc'))
|
||||
.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(String(DEFAULT_RADIAL_SETTINGS.linkLimit))
|
||||
.setValue(String(radial.linkLimit))
|
||||
.onChange(async (value) => {
|
||||
radial.linkLimit = clampNumber(value, 0, MAX_LINK_LIMIT, DEFAULT_RADIAL_SETTINGS.linkLimit);
|
||||
await this.plugin.saveSettings();
|
||||
this.renderSetting(t(language, 'control.defaultNodes'), t(language, 'settings.nodeLimitDesc'), (setting) => {
|
||||
setting.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(String(DEFAULT_RADIAL_SETTINGS.renderNodeLimit))
|
||||
.setValue(String(radial.renderNodeLimit))
|
||||
.onChange(async (value) => {
|
||||
radial.renderNodeLimit = clampNumber(value, 200, MAX_RENDER_NODE_LIMIT, DEFAULT_RADIAL_SETTINGS.renderNodeLimit);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.showNoteLinks'))
|
||||
.setDesc(t(language, 'settings.showLinksDesc'))
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(radial.showLinkOverlay && !radial.hiddenLegendItems.includes('link')).onChange(async (value) => {
|
||||
radial.showLinkOverlay = value;
|
||||
const hidden = new Set(radial.hiddenLegendItems);
|
||||
if (value) hidden.delete('link');
|
||||
else hidden.add('link');
|
||||
radial.hiddenLegendItems = [...hidden];
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.hover'))
|
||||
.setDesc(t(language, 'settings.hoverDesc'))
|
||||
.addDropdown((dropdown) => {
|
||||
for (const [value, label] of hoverModeOptions(language, HOVER_HIGHLIGHT_MODE_OPTIONS)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(radial.hoverHighlightMode).onChange(async (value) => {
|
||||
radial.hoverHighlightMode = normalizeHoverHighlightMode(value);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.hoverTargets'))
|
||||
.setDesc(t(language, 'settings.hoverTargetsDesc'))
|
||||
.addDropdown((dropdown) => {
|
||||
for (const [value, label] of hoverTargetOptions(language, HOVER_TARGET_MODE_OPTIONS)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(radial.hoverTargetMode).onChange(async (value) => {
|
||||
radial.hoverTargetMode = normalizeHoverTargetMode(value);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.labels'))
|
||||
.setDesc(t(language, 'settings.labelsDesc'))
|
||||
.addDropdown((dropdown) => {
|
||||
for (const [value, label] of labelVisibilityOptions(language, LABEL_VISIBILITY_OPTIONS)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(radial.labelVisibility).onChange(async (value) => {
|
||||
radial.labelVisibility = normalizeLabelVisibility(value);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.spin'))
|
||||
.setDesc(t(language, 'settings.spinDesc'))
|
||||
.addSlider((slider) =>
|
||||
slider
|
||||
.setLimits(0, MAX_SWIRL_STRENGTH, 1)
|
||||
.setValue(radial.swirlStrength)
|
||||
.setDynamicTooltip()
|
||||
.onChange(async (value) => {
|
||||
radial.swirlStrength = clampNumber(value, 0, MAX_SWIRL_STRENGTH, DEFAULT_RADIAL_SETTINGS.swirlStrength);
|
||||
await this.plugin.saveSettings();
|
||||
this.renderSetting(t(language, 'control.defaultNoteLinks'), t(language, 'settings.linkLimitDesc'), (setting) => {
|
||||
setting.addText((text) =>
|
||||
text
|
||||
.setPlaceholder(String(DEFAULT_RADIAL_SETTINGS.linkLimit))
|
||||
.setValue(String(radial.linkLimit))
|
||||
.onChange(async (value) => {
|
||||
radial.linkLimit = clampNumber(value, 0, MAX_LINK_LIMIT, DEFAULT_RADIAL_SETTINGS.linkLimit);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
);
|
||||
this.renderSetting(t(language, 'control.showNoteLinks'), t(language, 'settings.showLinksDesc'), (setting) => {
|
||||
setting.addToggle((toggle) =>
|
||||
toggle.setValue(radial.showLinkOverlay && !radial.hiddenLegendItems.includes('link')).onChange(async (value) => {
|
||||
radial.showLinkOverlay = value;
|
||||
const hidden = new Set(radial.hiddenLegendItems);
|
||||
if (value) hidden.delete('link');
|
||||
else hidden.add('link');
|
||||
radial.hiddenLegendItems = [...hidden];
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
this.renderSetting(t(language, 'control.hover'), t(language, 'settings.hoverDesc'), (setting) => {
|
||||
setting.addDropdown((dropdown) => {
|
||||
for (const [value, label] of hoverModeOptions(language, HOVER_HIGHLIGHT_MODE_OPTIONS)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(radial.hoverHighlightMode).onChange(async (value) => {
|
||||
radial.hoverHighlightMode = normalizeHoverHighlightMode(value);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
}),
|
||||
this.renderSetting(t(language, 'control.hoverTargets'), t(language, 'settings.hoverTargetsDesc'), (setting) => {
|
||||
setting.addDropdown((dropdown) => {
|
||||
for (const [value, label] of hoverTargetOptions(language, HOVER_TARGET_MODE_OPTIONS)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(radial.hoverTargetMode).onChange(async (value) => {
|
||||
radial.hoverTargetMode = normalizeHoverTargetMode(value);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
}),
|
||||
this.renderSetting(t(language, 'control.labels'), t(language, 'settings.labelsDesc'), (setting) => {
|
||||
setting.addDropdown((dropdown) => {
|
||||
for (const [value, label] of labelVisibilityOptions(language, LABEL_VISIBILITY_OPTIONS)) dropdown.addOption(value, label);
|
||||
dropdown.setValue(radial.labelVisibility).onChange(async (value) => {
|
||||
radial.labelVisibility = normalizeLabelVisibility(value);
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
}),
|
||||
this.renderSetting(t(language, 'control.spin'), t(language, 'settings.spinDesc'), (setting) => {
|
||||
setting.addSlider((slider) =>
|
||||
slider
|
||||
.setLimits(0, MAX_SWIRL_STRENGTH, 1)
|
||||
.setValue(radial.swirlStrength)
|
||||
.onChange(async (value) => {
|
||||
radial.swirlStrength = clampNumber(value, 0, MAX_SWIRL_STRENGTH, DEFAULT_RADIAL_SETTINGS.swirlStrength);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
this.renderSetting(t(language, 'control.unresolvedLinks'), t(language, 'settings.unresolvedDesc'), (setting) => {
|
||||
setting.addToggle((toggle) =>
|
||||
toggle.setValue(radial.includeUnresolvedLinks).onChange(async (value) => {
|
||||
radial.includeUnresolvedLinks = value;
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
this.renderSetting(t(language, 'control.ignoredFolders'), t(language, 'settings.ignoredDesc'), (setting) => {
|
||||
setting.addTextArea((text) =>
|
||||
text.setValue(radial.ignoreFolders.join('\n')).onChange(async (value) => {
|
||||
radial.ignoreFolders = value
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
}),
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.unresolvedLinks'))
|
||||
.setDesc(t(language, 'settings.unresolvedDesc'))
|
||||
.addToggle((toggle) =>
|
||||
toggle.setValue(radial.includeUnresolvedLinks).onChange(async (value) => {
|
||||
radial.includeUnresolvedLinks = value;
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName(t(language, 'control.ignoredFolders'))
|
||||
.setDesc(t(language, 'settings.ignoredDesc'))
|
||||
.addTextArea((text) =>
|
||||
text.setValue(radial.ignoreFolders.join('\n')).onChange(async (value) => {
|
||||
radial.ignoreFolders = value
|
||||
.split('\n')
|
||||
.map((line) => line.trim())
|
||||
.filter(Boolean);
|
||||
await this.plugin.saveSettings();
|
||||
}),
|
||||
);
|
||||
private renderSetting(name: string, desc: string, render: (setting: Setting) => void): SettingDefinitionRender {
|
||||
return {
|
||||
name,
|
||||
desc,
|
||||
render,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,9 +236,6 @@ export class RadialRenderer {
|
|||
showLoadingMask(text: string): void {
|
||||
cancelAnimationFrame(this.revealFrame);
|
||||
this.revealDepthLimit = Number.POSITIVE_INFINITY;
|
||||
this.container.style.setProperty('--mwm-reveal-x', '50%');
|
||||
this.container.style.setProperty('--mwm-reveal-y', '50%');
|
||||
this.container.style.setProperty('--mwm-reveal-radius', '0px');
|
||||
this.container.removeClass('is-radial-revealing');
|
||||
this.container.removeClass('is-radial-depth-revealing');
|
||||
this.container.addClass('is-radial-preparing');
|
||||
|
|
|
|||
|
|
@ -35,9 +35,8 @@ function normalizeCssColor(value: string): string | null {
|
|||
const doc = activeDocument;
|
||||
const body = doc.body;
|
||||
const probe = doc.createElement('span');
|
||||
probe.style.color = value;
|
||||
probe.setCssStyles({ color: value, display: 'none' });
|
||||
if (!probe.style.color) return null;
|
||||
probe.style.display = 'none';
|
||||
body.appendChild(probe);
|
||||
try {
|
||||
const computed = doc.defaultView?.getComputedStyle(probe).color ?? getComputedStyle(probe).color;
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ export const DEFAULT_RADIAL_SETTINGS: RadialSettings = {
|
|||
swirlStrength: 0,
|
||||
showRingGuides: false,
|
||||
hiddenLegendItems: [],
|
||||
ignoreFolders: ['.git', '.obsidian'],
|
||||
ignoreFolders: ['.git'],
|
||||
};
|
||||
|
||||
export const DEFAULT_GALAXY_SETTINGS: GalaxySettings = {
|
||||
|
|
@ -181,6 +181,15 @@ export function mergeSettings(saved: unknown): MiniWorldMapSettings {
|
|||
};
|
||||
}
|
||||
|
||||
export function applyVaultConfigDirDefault(settings: MiniWorldMapSettings, saved: unknown, configDir: string): MiniWorldMapSettings {
|
||||
if (hasSavedIgnoreFolders(saved)) return settings;
|
||||
const normalized = normalizeIgnoredFolder(configDir);
|
||||
if (normalized && !settings.radial.ignoreFolders.includes(normalized)) {
|
||||
settings.radial.ignoreFolders = [...settings.radial.ignoreFolders, normalized];
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
export function mergeRadialSettings(saved: unknown): RadialSettings {
|
||||
const s = isRecord(saved) ? saved : {};
|
||||
const d = DEFAULT_RADIAL_SETTINGS;
|
||||
|
|
@ -348,6 +357,19 @@ function finiteNumber(value: unknown, fallback: number): number {
|
|||
return typeof value === 'number' && Number.isFinite(value) ? value : Number.parseFloat(String(value)) || fallback;
|
||||
}
|
||||
|
||||
function hasSavedIgnoreFolders(saved: unknown): boolean {
|
||||
const raw = isRecord(saved) ? saved : {};
|
||||
const radial = isRecord(raw['radial']) ? raw['radial'] : raw;
|
||||
return Array.isArray(radial['ignoreFolders']);
|
||||
}
|
||||
|
||||
function normalizeIgnoredFolder(path: string): string {
|
||||
return path
|
||||
.trim()
|
||||
.replace(/\\/g, '/')
|
||||
.replace(/^\/+|\/+$/g, '');
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { App } from 'obsidian';
|
|||
import { TFile, TFolder } from 'obsidian';
|
||||
import type { RadialSettings } from '../settings';
|
||||
import { buildWorldMap, normalizeVaultPath } from './buildWorldMap';
|
||||
import type { LinkTable, VisibleGraphState, VisibleWorldGraph, WorldFileRecord, WorldModel, WorldNode } from './types';
|
||||
import type { LinkTable, VisibleGraphState, VisibleWorldGraph, WorldEdge, WorldFileRecord, WorldModel, WorldNode } from './types';
|
||||
import { ROOT_ID } from './types';
|
||||
import { buildVisibleWorldGraph, visualNodeId } from './visibleGraph';
|
||||
|
||||
|
|
@ -35,12 +35,12 @@ export class WorldMapIndex {
|
|||
};
|
||||
}
|
||||
|
||||
get linkEdgesBySource() {
|
||||
return this.model?.linkEdgesBySource ?? new Map();
|
||||
get linkEdgesBySource(): Map<string, WorldEdge[]> {
|
||||
return this.model?.linkEdgesBySource ?? new Map<string, WorldEdge[]>();
|
||||
}
|
||||
|
||||
get linkEdgesByTarget() {
|
||||
return this.model?.linkEdgesByTarget ?? new Map();
|
||||
get linkEdgesByTarget(): Map<string, WorldEdge[]> {
|
||||
return this.model?.linkEdgesByTarget ?? new Map<string, WorldEdge[]>();
|
||||
}
|
||||
|
||||
rebuild(settings: RadialSettings = this.settings): void {
|
||||
|
|
|
|||
|
|
@ -1147,11 +1147,6 @@
|
|||
height: 16px;
|
||||
}
|
||||
|
||||
.mwm-radial-host.is-radial-revealing .mwm-radial-canvas,
|
||||
.mwm-radial-host.is-radial-revealing .mwm-radial-labels {
|
||||
clip-path: circle(var(--mwm-reveal-radius, 0px) at var(--mwm-reveal-x, 50%) var(--mwm-reveal-y, 50%));
|
||||
}
|
||||
|
||||
.mwm-radial-host.is-radial-preparing .mwm-radial-canvas,
|
||||
.mwm-radial-host.is-radial-preparing .mwm-radial-labels {
|
||||
opacity: 0;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { mergeSettings } from '../src/settings';
|
||||
import { applyVaultConfigDirDefault, mergeSettings } from '../src/settings';
|
||||
|
||||
describe('Mini World Map settings migration', () => {
|
||||
it('defaults to 2D radial mode and preserves legacy radial keys', () => {
|
||||
|
|
@ -33,6 +33,14 @@ describe('Mini World Map settings migration', () => {
|
|||
expect(mergeSettings({ radial: { hoverTargetMode: 'anything' } }).radial.hoverTargetMode).toBe('nodes');
|
||||
});
|
||||
|
||||
it('adds the current vault config folder to default ignored folders', () => {
|
||||
const settings = applyVaultConfigDirDefault(mergeSettings({}), {}, '.custom-config');
|
||||
expect(settings.radial.ignoreFolders).toContain('.custom-config');
|
||||
|
||||
const explicit = applyVaultConfigDirDefault(mergeSettings({ radial: { ignoreFolders: ['Archive'] } }), { radial: { ignoreFolders: ['Archive'] } }, '.custom-config');
|
||||
expect(explicit.radial.ignoreFolders).toEqual(['Archive']);
|
||||
});
|
||||
|
||||
it('preserves intentional nested 2D note-link visibility', () => {
|
||||
expect(mergeSettings({ radial: { showLinkOverlay: false } }).radial.showLinkOverlay).toBe(false);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const records = [
|
|||
];
|
||||
|
||||
function model(overrides: Partial<typeof DEFAULT_RADIAL_SETTINGS> = {}) {
|
||||
const settings = { ...DEFAULT_RADIAL_SETTINGS, ...overrides };
|
||||
const settings = { ...DEFAULT_RADIAL_SETTINGS, ignoreFolders: [...DEFAULT_RADIAL_SETTINGS.ignoreFolders, '.obsidian'], ...overrides };
|
||||
return buildWorldMap(
|
||||
records,
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,5 +4,6 @@
|
|||
"0.1.2": "1.5.0",
|
||||
"0.1.3": "1.5.0",
|
||||
"0.2.0": "1.5.0",
|
||||
"0.2.1": "1.5.0"
|
||||
"0.2.1": "1.5.0",
|
||||
"0.2.2": "1.13.0"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue