diff --git a/main.js b/main.js index 28c7e88..72118ab 100644 --- a/main.js +++ b/main.js @@ -76,7 +76,7 @@ function resolveColorVarToHex(colorVar, settings) { return null; } function applyCardColorToElement(cardEl, colorVar, settings) { - var _a, _b, _c, _d, _e; + var _a, _b, _c, _d; const style = Number((_a = settings.cardStyle) != null ? _a : 2); const opacity = Number((_b = settings.cardBgOpacity) != null ? _b : 0.08); const borderThickness = Number((_c = settings.borderThickness) != null ? _c : 2); @@ -90,7 +90,6 @@ function applyCardColorToElement(cardEl, colorVar, settings) { const hex = resolveColorVarToHex(colorVar, settings) || colorVar; const rgba = hexToRgba(hex, opacity); const borderColor = borderShadowOpacity >= 1 ? colorVar : hexToRgba(hex, borderShadowOpacity); - const borderRadius = (_e = settings.borderRadius) != null ? _e : 6; if (style === 1) { cardEl.setCssProps({ "border": `${borderThickness}px solid ${borderColor}`, @@ -111,7 +110,6 @@ function applyCardColorToElement(cardEl, colorVar, settings) { "box-shadow": `2px 2px 0 0 ${borderColor}` }); } - cardEl.setCssProps({ "border-radius": `${borderRadius}px` }); } function resolveAutoColor(content, tags, settings) { const rules = settings.autoColorRules; @@ -265,7 +263,7 @@ var DateTimeModal = class extends import_obsidian.Modal { }); }); const exactPanel = contentEl.createDiv("sc-dt-panel sc-dt-panel-exact"); - exactPanel.setCssProps({ "display": "none" }); + exactPanel.addClass("sc-hidden"); const exactInput = exactPanel.createEl("input", { type: "datetime-local", cls: "sc-dt-exact-input" }); if (this.card.expiresAt) { const d = new Date(this.card.expiresAt); @@ -281,15 +279,15 @@ var DateTimeModal = class extends import_obsidian.Modal { relRadio.addEventListener("change", () => { if (relRadio.checked) { this.mode = "relative"; - relPanel.setCssProps({ "display": "" }); - exactPanel.setCssProps({ "display": "none" }); + relPanel.removeClass("sc-hidden"); + exactPanel.addClass("sc-hidden"); } }); exactRadio.addEventListener("change", () => { if (exactRadio.checked) { this.mode = "exact"; - relPanel.setCssProps({ "display": "none" }); - exactPanel.setCssProps({ "display": "" }); + relPanel.addClass("sc-hidden"); + exactPanel.removeClass("sc-hidden"); } }); const actionsRow = contentEl.createDiv("sc-dt-actions-row"); @@ -352,7 +350,7 @@ var DateTimeModal = class extends import_obsidian.Modal { }; // src/utils/editor-utils.ts -function handleKeyWrap(event, editorEl, editor, enabled = true) { +function handleKeyWrap(event, editorEl, _editor, enabled = true) { if (!enabled) return false; if (event.ctrlKey || event.metaKey || event.altKey) @@ -1090,22 +1088,18 @@ var _CardComponent = class extends import_obsidian3.Component { const pill = container.createDiv("sc-expiry-pill"); pill.textContent = this.formatExpiryTimeLeft(this.card.expiresAt); if (this.card.status) - pill.setCssProps({ "margin-bottom": "4px" }); + pill.addClass("sc-status-pill--with-margin"); } if (this.card.status) { const pill = container.createDiv("sc-status-pill"); pill.textContent = this.card.status.name; const statusDef = (this.store.settings.cardStatuses || []).find((s) => s.name === this.card.status.name); if (statusDef == null ? void 0 : statusDef.colorIndex) { - pill.setCssProps({ - "background-color": `var(--card-color-${statusDef.colorIndex})`, - "color": statusDef.textColor || "#000" - }); + pill.style.backgroundColor = `var(--card-color-${statusDef.colorIndex})`; + pill.style.color = statusDef.textColor || "#000"; } else { - pill.setCssProps({ - "background-color": this.card.status.color || "transparent", - "color": this.card.status.textColor || "#000" - }); + pill.style.backgroundColor = this.card.status.color || "transparent"; + pill.style.color = this.card.status.textColor || "#000"; } } } @@ -1428,7 +1422,7 @@ var _CardComponent = class extends import_obsidian3.Component { if (todayVisible) { menu.addItem((item) => { var _a, _b; - item.setTitle("Add to today").setIcon((_b = (_a = s.builtinCategoryIcons) == null ? void 0 : _a["today"]) != null ? _b : "calendar-check").onClick(async () => { + item.setTitle("Add to Today").setIcon((_b = (_a = s.builtinCategoryIcons) == null ? void 0 : _a["today"]) != null ? _b : "calendar-check").onClick(async () => { await this.store.setCategory(this.card.id, "today"); }); }); @@ -1436,7 +1430,7 @@ var _CardComponent = class extends import_obsidian3.Component { if (tomorrowVisible) { menu.addItem((item) => { var _a, _b; - item.setTitle("Add to tomorrow").setIcon((_b = (_a = s.builtinCategoryIcons) == null ? void 0 : _a["tomorrow"]) != null ? _b : "calendar-plus").onClick(async () => { + item.setTitle("Add to Tomorrow").setIcon((_b = (_a = s.builtinCategoryIcons) == null ? void 0 : _a["tomorrow"]) != null ? _b : "calendar-plus").onClick(async () => { await this.store.setCategory(this.card.id, "tomorrow"); }); }); @@ -1458,13 +1452,13 @@ var _CardComponent = class extends import_obsidian3.Component { } menu.addSeparator(); menu.addItem((item) => { - item.setTitle(this.card.pinned ? "Unpin" : "Pin card").setIcon("pin").onClick(async () => { + item.setTitle(this.card.pinned ? "Unpin" : "Pin Card").setIcon("pin").onClick(async () => { await this.store.togglePin(this.card.id, !this.card.pinned); }); }); if (s.enableCardStatus && Array.isArray(s.cardStatuses) && s.cardStatuses.length > 0) { menu.addItem((item) => { - item.setTitle("Set status").setIcon("flag").onClick(() => { + item.setTitle("Set Status").setIcon("flag").onClick(() => { var _a; const menu2 = new import_obsidian3.Menu(); (_a = s.cardStatuses) == null ? void 0 : _a.forEach((st) => { @@ -1480,7 +1474,7 @@ var _CardComponent = class extends import_obsidian3.Component { }); }); menu2.addItem((i) => { - i.setTitle("Clear status").onClick(async () => { + i.setTitle("Clear Status").onClick(async () => { await this.store.setStatus(this.card.id, null); }); }); @@ -1489,7 +1483,7 @@ var _CardComponent = class extends import_obsidian3.Component { }); } menu.addItem((item) => { - item.setTitle("Set expiry").setIcon("alarm-clock").onClick(() => { + item.setTitle("Set Expiry").setIcon("alarm-clock").onClick(() => { new DateTimeModal(this.app, this.card, this.store).open(); }); }); @@ -1500,7 +1494,7 @@ var _CardComponent = class extends import_obsidian3.Component { }); }); menu.addItem((item) => { - item.setTitle(this.card.notePath ? "View note" : "Create note").setIcon(this.card.notePath ? "link" : "file-plus").onClick(async () => { + item.setTitle(this.card.notePath ? "View Note" : "Create Note").setIcon(this.card.notePath ? "link" : "file-plus").onClick(async () => { if (this.card.notePath) { const file = this.app.vault.getAbstractFileByPath(this.card.notePath); if (file instanceof import_obsidian3.TFile) { @@ -2319,7 +2313,7 @@ var CardSidebarView = class extends import_obsidian4.ItemView { if (!baseRange.collapsed) return baseRange; const node = baseRange.startContainer; - if (!(node instanceof Text)) + if (!(node == null ? void 0 : node.data)) return null; const text = node.data; if (!text) @@ -2552,7 +2546,7 @@ var CardSidebarView = class extends import_obsidian4.ItemView { box.createDiv({ text: "Loading cards...", cls: "sc-sidebar-loading-text" }); this._loadingTimeout = window.setTimeout(() => this.hideLoadingOverlay(), maxMs); } - hideLoadingOverlay(fadeMs = 0) { + hideLoadingOverlay(_fadeMs = 0) { if (this._loadingTimeout) { window.clearTimeout(this._loadingTimeout); this._loadingTimeout = null; @@ -2907,7 +2901,7 @@ var CardSidebarView = class extends import_obsidian4.ItemView { const menu = new import_obsidian4.Menu(); menu.addItem((item) => { var _a; - item.setTitle("Show tags").setChecked((_a = this.plugin.settings.sidebarShowTags) != null ? _a : true).onClick(async () => { + item.setTitle("Show Tags").setChecked((_a = this.plugin.settings.sidebarShowTags) != null ? _a : true).onClick(async () => { var _a2; const current = (_a2 = this.plugin.settings.sidebarShowTags) != null ? _a2 : true; this.plugin.settings.sidebarShowTags = !current; @@ -2917,7 +2911,7 @@ var CardSidebarView = class extends import_obsidian4.ItemView { }); menu.addItem((item) => { var _a; - item.setTitle("Show timestamps").setChecked((_a = this.plugin.settings.sidebarShowTimestamps) != null ? _a : this.plugin.settings.showTimestamps).onClick(async () => { + item.setTitle("Show Timestamps").setChecked((_a = this.plugin.settings.sidebarShowTimestamps) != null ? _a : this.plugin.settings.showTimestamps).onClick(async () => { var _a2; const current = (_a2 = this.plugin.settings.sidebarShowTimestamps) != null ? _a2 : this.plugin.settings.showTimestamps; this.plugin.settings.sidebarShowTimestamps = !current; @@ -3000,7 +2994,7 @@ var CardSidebarView = class extends import_obsidian4.ItemView { void this.renderCards(); }, 300); } - async renderCards(isManualReload = false) { + async renderCards(_isManualReload = false) { var _a, _b; const settings = { ...this.store.settings }; const scrollTop = ((_a = this.cardsContainer) == null ? void 0 : _a.scrollTop) || 0; @@ -4157,8 +4151,8 @@ var QuickCardWithFilterModal = class extends import_obsidian7.Modal { const { contentEl } = this; contentEl.empty(); contentEl.addClass("sc-quick-card-modal"); - contentEl.createEl("h2", { text: "Quick card add", cls: "sc-modal-title" }); - contentEl.createEl("h3", { text: "Card content", cls: "sc-modal-section-title" }); + contentEl.createDiv({ text: "Quick card add", cls: "sc-modal-title" }); + contentEl.createDiv({ text: "Card content", cls: "sc-modal-section-title" }); const editorEl = contentEl.createDiv({ cls: "sc-modal-textarea" }); @@ -4182,7 +4176,7 @@ var QuickCardWithFilterModal = class extends import_obsidian7.Modal { this.app.workspace.activeEditor = null; } }); - contentEl.createEl("h3", { text: "Color", cls: "sc-modal-section-title" }); + contentEl.createDiv({ text: "Color", cls: "sc-modal-section-title" }); const colorContainer = contentEl.createDiv("sc-modal-color-container"); let selectedColor = "var(--card-color-1)"; const colors = [ @@ -4199,8 +4193,7 @@ var QuickCardWithFilterModal = class extends import_obsidian7.Modal { ]; colors.forEach((color, idx) => { const swatch = colorContainer.createDiv("sc-modal-color-swatch"); - const hex = this.resolveColor(color.var); - swatch.setCssProps({ "background-color": hex }); + swatch.style.backgroundColor = this.resolveColor(color.var); swatch.title = this.store.settings.colorNames[idx] || color.name; if (selectedColor === color.var) swatch.addClass("is-selected"); @@ -4210,7 +4203,7 @@ var QuickCardWithFilterModal = class extends import_obsidian7.Modal { selectedColor = color.var; }); }); - contentEl.createEl("h3", { text: "Tags", cls: "sc-modal-section-title" }); + contentEl.createDiv({ text: "Tags", cls: "sc-modal-section-title" }); const tagsWrapper = contentEl.createDiv("sc-modal-tags-wrapper"); const tagsInput = tagsWrapper.createEl("input", { placeholder: "Tags (comma separated)...", @@ -4265,7 +4258,7 @@ var QuickCardWithFilterModal = class extends import_obsidian7.Modal { items[selectedTagIdx].click(); } }); - contentEl.createEl("h3", { text: "Apply category", cls: "sc-modal-section-title" }); + contentEl.createDiv({ text: "Apply category", cls: "sc-modal-section-title" }); const select = contentEl.createEl("select", { cls: "sc-modal-select" }); this.getAvailableFilters().forEach((f) => { const opt = select.createEl("option", { value: f.value, text: f.label }); @@ -4365,10 +4358,6 @@ var SearchModal = class extends import_obsidian8.Modal { cls: "sc-search-input" }); this.resultsContainer = contentEl.createDiv("sc-search-results"); - this.resultsContainer.setCssProps({ - "max-height": "400px", - "overflow": "auto" - }); this.searchInput.focus(); this.searchInput.addEventListener("input", () => this.renderResults()); this.searchInput.addEventListener("keydown", (e) => this.handleKeydown(e)); @@ -4383,11 +4372,7 @@ var SearchModal = class extends import_obsidian8.Modal { this.searchResults.forEach((card, idx) => { const result = this.resultsContainer.createDiv("sc-search-result"); result.textContent = card.content.substring(0, 100) + (card.content.length > 100 ? "..." : ""); - result.setCssProps({ - "padding": "8px", - "cursor": "pointer", - "border-left": `4px solid ${card.color}` - }); + result.style.borderLeft = `4px solid ${card.color}`; result.dataset.index = String(idx); result.addEventListener("click", () => this.selectResult(card)); result.addEventListener("mouseenter", () => { @@ -4401,10 +4386,10 @@ var SearchModal = class extends import_obsidian8.Modal { els.forEach((el, idx) => { if (idx === this.selectedIndex) { el.addClass("selected"); - el.setCssProps({ "background-color": "var(--background-modifier-hover)" }); + el.addClass("sc-search-result--selected"); } else { el.removeClass("selected"); - el.setCssProps({ "background-color": "" }); + el.removeClass("sc-search-result--selected"); } }); } @@ -4504,7 +4489,7 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { if (!baseRange.collapsed) return baseRange; const node = baseRange.startContainer; - if (!(node instanceof Text)) + if (!(node == null ? void 0 : node.data)) return null; const text = node.data; if (!text) @@ -4702,7 +4687,7 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { return "home"; } async onOpen() { - var _a, _b; + var _a; const container = this.containerEl; container.empty(); container.addClass("sc-home-container"); @@ -4711,10 +4696,8 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { const main = container.createDiv({ cls: "sc-home-main" }); const maxW = (_a = this.plugin.settings.homepageMaxWidth) != null ? _a : 1e3; container.setCssProps({ "--sc-home-max-width": `${maxW}px` }); - const topMargin = (_b = this.plugin.settings.homepageTopMargin) != null ? _b : 70; - container.setCssProps({ "--sc-home-top-margin": `${topMargin}px` }); const topSection = main.createDiv({ cls: "sc-home-top" }); - topSection.createEl("h2", { text: this.plugin.settings.homepageName || "SideCards", cls: "sc-home-title" }); + topSection.createDiv({ text: this.plugin.settings.homepageName || "SideCards", cls: "sc-home-title" }); const paletteRow = topSection.createDiv({ cls: "sc-home-palette-row" }); if (this.plugin.settings.hideCategoryDropdown && this.plugin.settings.hideColorSwatches) { paletteRow.addClass("sc-hidden"); @@ -4884,7 +4867,7 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { item.addEventListener("contextmenu", (e) => { e.preventDefault(); const menu = new import_obsidian9.Menu(); - menu.addItem((i) => i.setTitle("Unpin from homepage").setIcon("pin-off").onClick(async () => { + menu.addItem((i) => i.setTitle("Unpin from Homepage").setIcon("pin-off").onClick(async () => { this.plugin.settings.pinnedNotes = (this.plugin.settings.pinnedNotes || []).filter((p) => p !== file.path); await this.plugin.saveSettings(); await this.renderFileList(container, "pinned"); @@ -5124,7 +5107,7 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { await this.renderFileList(recentList, "recent"); this.renderCards(cardList); } - renderToolbar(container, editorEl, cardList, pinnedList, recentList) { + renderToolbar(container, _editorEl, cardList, pinnedList, recentList) { container.empty(); const leftActions = container.createDiv({ cls: "sc-home-toolbar-left" }); const searchWrap = container.createDiv({ cls: "sc-home-search-wrap" }); @@ -5190,7 +5173,7 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { const menu = new import_obsidian9.Menu(); menu.addItem((item) => { var _a; - item.setTitle("Show tags").setChecked((_a = this.plugin.settings.homeShowTags) != null ? _a : true).onClick(async () => { + item.setTitle("Show Tags").setChecked((_a = this.plugin.settings.homeShowTags) != null ? _a : true).onClick(async () => { var _a2; const current = (_a2 = this.plugin.settings.homeShowTags) != null ? _a2 : true; this.plugin.settings.homeShowTags = !current; @@ -5200,7 +5183,7 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { }); menu.addItem((item) => { var _a; - item.setTitle("Show timestamps").setChecked((_a = this.plugin.settings.homeShowTimestamps) != null ? _a : this.plugin.settings.showTimestamps).onClick(async () => { + item.setTitle("Show Timestamps").setChecked((_a = this.plugin.settings.homeShowTimestamps) != null ? _a : this.plugin.settings.showTimestamps).onClick(async () => { var _a2; const current = (_a2 = this.plugin.settings.homeShowTimestamps) != null ? _a2 : this.plugin.settings.showTimestamps; this.plugin.settings.homeShowTimestamps = !current; @@ -5377,7 +5360,7 @@ var SideCardsHomeView = class extends import_obsidian9.ItemView { return []; } } - async createCardFromHomeInput(editorEl, cardList) { + async createCardFromHomeInput(editorEl, _cardList) { var _a; const content = (_a = editorEl.textContent) == null ? void 0 : _a.trim(); if (!content) @@ -5563,9 +5546,9 @@ var SideCardsPlugin = class extends import_obsidian10.Plugin { return false; } }); - this.addRibbonIcon("home", "Open homepage", () => void this.activateHomeView()); - this.addRibbonIcon("rows-3", "Open sidebar", () => void this.activateView()); - this.addRibbonIcon("rectangle-horizontal", "Add card", () => new QuickCardWithFilterModal(this.app, this, this.store).open()); + this.addRibbonIcon("home", "Open Homepage", () => void this.activateHomeView()); + this.addRibbonIcon("rows-3", "Open Sidebar", () => void this.activateView()); + this.addRibbonIcon("rectangle-horizontal", "Add Card", () => new QuickCardWithFilterModal(this.app, this, this.store).open()); this.addSettingTab(new SideCardsSettingTab(this.app, this)); this.registerEvent( this.app.vault.on("rename", (file, oldPath) => { @@ -5626,6 +5609,7 @@ var SideCardsPlugin = class extends import_obsidian10.Plugin { this.injectStatusColors(); this.applyButtonPadding(); this.applyMaxCardHeight(); + this.applyHomepageTopMargin(); this.registerDomEvent(document, "dragover", (ev) => { if (!ev.dataTransfer) return; @@ -5728,6 +5712,11 @@ var SideCardsPlugin = class extends import_obsidian10.Plugin { document.body.removeClass("sc-max-card-height-active"); } } + applyHomepageTopMargin() { + var _a; + const topMargin = (_a = this.settings.homepageTopMargin) != null ? _a : 70; + document.documentElement.style.setProperty("--sc-home-top-margin", `${topMargin}px`); + } injectStatusColors() { } async activateView() { @@ -5783,7 +5772,7 @@ var SideCardsPlugin = class extends import_obsidian10.Plugin { if (!baseRange.collapsed) return baseRange; const node = baseRange.startContainer; - if (!(node instanceof Text)) + if (!(node == null ? void 0 : node.data)) return null; const text = node.data; if (!text) @@ -6165,27 +6154,31 @@ var SideCardsSettingTab = class extends import_obsidian10.PluginSettingTab { } }; new import_obsidian10.Setting(containerEl).setName("Latest release notes").setDesc("View the most recent plugin release notes.").addButton((b) => { - b.setButtonText("Open changelog").onClick(() => { + b.setButtonText("Open Changelog").onClick(() => { new ChangelogModal(this.app, this.plugin).open(); }); }); - new import_obsidian10.Setting(containerEl).setName("Storage folder").setDesc("Choose where to save notes created from cards.").addSearch((cb) => { - cb.setPlaceholder("Choose a folder").setValue(this.plugin.settings.storageFolder || "").onChange(async (value) => { - const newFolder = value.trim(); - const oldFolder = this.plugin.settings.storageFolder; - this.plugin.settings.storageFolder = newFolder; - this.plugin.settings.tutorialShown = true; - await this.plugin.saveSettings(); - if (newFolder !== oldFolder) { - await this.plugin.store.switchStorageFolder(newFolder); - } + new import_obsidian10.Setting(containerEl).setName("Storage folder").setDesc("Choose where to save notes created from cards.").addButton((b) => { + var _a; + b.setButtonText(((_a = this.plugin.settings.storageFolder) == null ? void 0 : _a.trim()) ? this.plugin.settings.storageFolder : "Unset").onClick(() => { + const folders = this.app.vault.getAllLoadedFiles().filter((f) => f instanceof import_obsidian10.TFolder).map((f) => f.path).sort(); + const suggest = new FolderSuggestModal(this.app, folders, async (folder) => { + var _a2; + const newFolder = folder || ""; + const oldFolder = this.plugin.settings.storageFolder; + this.plugin.settings.storageFolder = newFolder; + this.plugin.settings.tutorialShown = true; + await this.plugin.saveSettings(); + if (newFolder !== oldFolder) { + await this.plugin.store.switchStorageFolder(newFolder); + } + b.setButtonText(((_a2 = this.plugin.settings.storageFolder) == null ? void 0 : _a2.trim()) ? this.plugin.settings.storageFolder : "Unset"); + refreshSidebarCards(); + refreshHomepage(); + }); + suggest.setPlaceholder("Select storage folder..."); + suggest.open(); }); - const folders = /* @__PURE__ */ new Set(["/"]); - this.app.vault.getAllLoadedFiles().forEach((file) => { - if (file.parent) - folders.add(file.parent.path); - }); - new FolderSuggest(this.app, cb.inputEl, folders); }); new import_obsidian10.Setting(containerEl).setName("Behaviour").setDesc("").setHeading(); new import_obsidian10.Setting(containerEl).setName("Note title format").setDesc("Format used when creating a note from a card.").addDropdown((dd) => dd.addOption("words3_hhmm", "First 3 words + hhmm").addOption("words5_hhmm", "First 5 words + hhmm").addOption("datetime", "Date and time").setValue(this.plugin.settings.noteTitleFormat || "words3_hhmm").onChange(async (value) => { @@ -6307,9 +6300,7 @@ var SideCardsSettingTab = class extends import_obsidian10.PluginSettingTab { this.plugin.settings.homepageTopMargin = value; label.textContent = `${value}px`; await this.plugin.saveSettings(); - document.querySelectorAll(".sc-home-container").forEach((el) => { - el.setCssProps({ "--sc-home-top-margin": `${value}px` }); - }); + document.documentElement.style.setProperty("--sc-home-top-margin", `${value}px`); }); slider.sliderEl.insertAdjacentElement("afterend", label); }); @@ -7282,13 +7273,13 @@ var SideCardsSettingTab = class extends import_obsidian10.PluginSettingTab { ); }; renderStatusConfig(); - new import_obsidian10.Setting(containerEl).setName("Data management").setHeading(); - new import_obsidian10.Setting(containerEl).setName("Export data").setDesc("Download all cards as a JSON file.").addButton((btn) => btn.setButtonText("Export data").onClick(() => { + new import_obsidian10.Setting(containerEl).setName("Data Management").setHeading(); + new import_obsidian10.Setting(containerEl).setName("Export Data").setDesc("Download all cards as a JSON file.").addButton((btn) => btn.setButtonText("Export Data").onClick(() => { const cards = this.plugin.store.getAll().map((c) => c.toJSON()); const payload = JSON.stringify({ version: 1, exportedAt: new Date().toISOString(), cards }, null, 2); const blob = new Blob([payload], { type: "application/json" }); const url = URL.createObjectURL(blob); - const a = document.createElement("a"); + const a = containerEl.createEl("a"); a.href = url; a.download = `sidecards-export-${new Date().toISOString().slice(0, 10)}.json`; document.body.appendChild(a); @@ -7297,8 +7288,8 @@ var SideCardsSettingTab = class extends import_obsidian10.PluginSettingTab { URL.revokeObjectURL(url); new import_obsidian10.Notice("Cards exported."); })); - new import_obsidian10.Setting(containerEl).setName("Import data").setDesc("Import cards from a previously exported JSON file. Existing cards with the same ID will be skipped.").addButton((btn) => btn.setButtonText("Import data").onClick(() => { - const input = document.createElement("input"); + new import_obsidian10.Setting(containerEl).setName("Import Data").setDesc("Import cards from a previously exported JSON file.").addButton((btn) => btn.setButtonText("Import Data").onClick(() => { + const input = containerEl.createEl("input"); input.type = "file"; input.accept = ".json,application/json"; input.addEventListener("change", () => { @@ -7469,74 +7460,20 @@ var ChangelogModal = class extends import_obsidian10.Modal { this.contentEl.empty(); } }; -var FolderSuggest = class { - constructor(app, inputEl, folders) { - this.app = app; - this.inputEl = inputEl; - var _a; - this.folders = Array.from(folders).sort(); - this.suggestEl = document.createElement("div"); - this.suggestEl.className = "suggestion-container sc-folder-suggest"; - (_a = this.inputEl.parentElement) == null ? void 0 : _a.appendChild(this.suggestEl); - this.inputEl.addEventListener("click", () => this.onFocus()); - this.inputEl.addEventListener("input", () => this.onInput()); - document.addEventListener("click", (event) => this.onClick(event)); +var FolderSuggestModal = class extends import_obsidian10.FuzzySuggestModal { + constructor(app, folders, onChoose) { + super(app); + this.folders = folders; + this.onChoose = onChoose; } - onFocus() { - var _a; - const foldersSet = /* @__PURE__ */ new Set(["/"]); - const vaultWithRoot = this.app.vault; - const root = (_a = vaultWithRoot.getRoot) == null ? void 0 : _a.call(vaultWithRoot); - const walk = (node) => { - if (!node) - return; - const children = node.children || []; - for (const c of children) { - if (c && c.path && c.children) { - foldersSet.add(c.path || "/"); - walk(c); - } - } - }; - if (root) - walk(root); - try { - this.app.vault.getAllLoadedFiles().forEach((file) => { - if (file && file.parent) - foldersSet.add(file.parent.path); - }); - } catch (e) { - } - this.folders = Array.from(foldersSet).sort(); - this.updateSuggestions(); - this.suggestEl.addClass("is-visible"); + getItems() { + return this.folders; } - onInput() { - this.updateSuggestions(); + getItemText(item) { + return item; } - onClick(event) { - const target = event.target; - if (!target) - return; - if (!this.inputEl.contains(target) && !this.suggestEl.contains(target)) { - this.suggestEl.removeClass("is-visible"); - } - } - updateSuggestions() { - const inputValue = this.inputEl.value.toLowerCase(); - this.suggestEl.empty(); - const filtered = this.folders.filter((folder) => folder.toLowerCase().includes(inputValue)).slice(0, 100); - filtered.forEach((folder) => { - const item = document.createElement("div"); - item.className = "suggestion-item sc-folder-suggest-item"; - item.textContent = folder; - item.addEventListener("click", () => { - this.inputEl.value = folder; - this.inputEl.dispatchEvent(new Event("input")); - this.suggestEl.removeClass("is-visible"); - }); - this.suggestEl.appendChild(item); - }); + onChooseItem(item, evt) { + void Promise.resolve(this.onChoose(item)); } }; var SidecardsIconPickerModal = class extends import_obsidian10.Modal { diff --git a/src/core/Plugin.ts b/src/core/Plugin.ts index 2e8ea20..842393c 100644 --- a/src/core/Plugin.ts +++ b/src/core/Plugin.ts @@ -1,5 +1,5 @@ -import { Plugin, PluginSettingTab, App, Setting, WorkspaceLeaf, setIcon, Notice, TFile, Platform, requestUrl, Component, MarkdownRenderer, Modal, getIconIds, MarkdownView, activeDocument, activeWindow, Text } from "obsidian"; +import { Plugin, PluginSettingTab, App, Setting, WorkspaceLeaf, setIcon, Notice, TFile, Platform, requestUrl, Component, MarkdownRenderer, Modal, getIconIds, MarkdownView, FuzzySuggestModal, TFolder } from "obsidian"; import { CardSidebarView } from "../views/CardSidebarView"; import { CardStore } from "../services/CardStore"; import { FilterService } from "../services/FilterService"; @@ -20,7 +20,7 @@ export default class SideCardsPlugin extends Plugin { async onload() { await this.loadSettings(); - (activeDocument.documentElement).setCssProps({ + (document.documentElement).setCssProps({ '--card-color-1': this.settings.color1 || '#8392a4', '--card-color-2': this.settings.color2 || '#eb3b5a', '--card-color-3': this.settings.color3 || '#fa8231', @@ -117,7 +117,7 @@ export default class SideCardsPlugin extends Plugin { id: 'custom-wrap-comment', name: 'Wrap with comment %% (any focused editable)', checkCallback: (checking: boolean) => { - const activeEl = activeDocument.activeElement; + const activeEl = document.activeElement; if (activeEl instanceof HTMLElement && activeEl.isContentEditable) { if (!checking) { this.wrapWith('%%', '%%'); @@ -132,7 +132,7 @@ export default class SideCardsPlugin extends Plugin { id: 'custom-wrap-bold', name: 'Wrap with **bold**', checkCallback: (checking: boolean) => { - const activeEl = activeDocument.activeElement; + const activeEl = document.activeElement; if (activeEl instanceof HTMLElement && activeEl.isContentEditable) { if (!checking) { this.wrapWith('**', '**'); @@ -147,7 +147,7 @@ export default class SideCardsPlugin extends Plugin { id: 'custom-wrap-italic', name: 'Wrap with *italic*', checkCallback: (checking: boolean) => { - const activeEl = activeDocument.activeElement; + const activeEl = document.activeElement; if (activeEl instanceof HTMLElement && activeEl.isContentEditable) { if (!checking) { this.wrapWith('*', '*'); @@ -162,7 +162,7 @@ export default class SideCardsPlugin extends Plugin { id: 'custom-wrap-highlight', name: 'Wrap with ==highlight==', checkCallback: (checking: boolean) => { - const activeEl = activeDocument.activeElement; + const activeEl = document.activeElement; if (activeEl instanceof HTMLElement && activeEl.isContentEditable) { if (!checking) { this.wrapWith('==', '=='); @@ -240,9 +240,10 @@ export default class SideCardsPlugin extends Plugin { this.injectStatusColors(); this.applyButtonPadding(); this.applyMaxCardHeight(); + this.applyHomepageTopMargin(); // Allow drop on any element — needed so the browser accepts the drop - this.registerDomEvent(activeDocument, 'dragover', (ev: DragEvent) => { + this.registerDomEvent(document, 'dragover', (ev: DragEvent) => { if (!ev.dataTransfer) return; const types = Array.from(ev.dataTransfer.types || []); if (!types.includes('text/x-card-sidebar')) return; @@ -301,8 +302,8 @@ export default class SideCardsPlugin extends Plugin { mdView.editor.replaceSelection(content); mdView.editor.focus(); }; - activeDocument.addEventListener('drop', cardDropHandler, true /* capture */); - (this as unknown as { _cardDropCleanup?: () => void })._cardDropCleanup = () => activeDocument.removeEventListener('drop', cardDropHandler, true); + document.addEventListener('drop', cardDropHandler, true /* capture */); + (this as unknown as { _cardDropCleanup?: () => void })._cardDropCleanup = () => document.removeEventListener('drop', cardDropHandler, true); // Auto-open sidebar on startup; show setup modal if no storage folder set this.app.workspace.onLayoutReady(() => { @@ -325,7 +326,7 @@ export default class SideCardsPlugin extends Plugin { applyButtonPadding(): void { const paddingPx = this.settings.buttonPaddingBottom ?? 26; - (activeDocument.documentElement).setCssProps({ + (document.documentElement).setCssProps({ '--sc-button-padding-bottom': `${paddingPx}px` }); } @@ -333,14 +334,19 @@ export default class SideCardsPlugin extends Plugin { applyMaxCardHeight(): void { const h = this.settings.maxCardHeight; if (h && h > 0) { - activeDocument.documentElement.setCssProps({ '--sc-max-card-height': `${h}px` }); - activeDocument.body.addClass('sc-max-card-height-active'); + document.documentElement.setCssProps({ '--sc-max-card-height': `${h}px` }); + document.body.addClass('sc-max-card-height-active'); } else { - activeDocument.documentElement.style.removeProperty('--sc-max-card-height'); - activeDocument.body.removeClass('sc-max-card-height-active'); + document.documentElement.style.removeProperty('--sc-max-card-height'); + document.body.removeClass('sc-max-card-height-active'); } } + applyHomepageTopMargin(): void { + const topMargin = this.settings.homepageTopMargin ?? 70; + document.documentElement.style.setProperty('--sc-home-top-margin', `${topMargin}px`); + } + injectStatusColors(): void { // We now apply status colors directly to elements in CardComponent } @@ -366,7 +372,7 @@ export default class SideCardsPlugin extends Plugin { } private wrapWith(start: string, end: string) { - const activeEl = activeDocument.activeElement; + const activeEl = document.activeElement; if (!(activeEl instanceof HTMLElement) || activeEl.isContentEditable !== true) { new Notice('No editable field focused'); return; @@ -390,10 +396,10 @@ export default class SideCardsPlugin extends Plugin { const wrapped = start + text + end; range.deleteContents(); - range.insertNode(activeDocument.createTextNode(wrapped)); + range.insertNode(document.createTextNode(wrapped)); // Optional: place caret inside the wrapped text - const newRange = activeDocument.createRange(); + const newRange = document.createRange(); newRange.setStart(range.startContainer, range.startOffset + start.length); newRange.collapse(true); sel.removeAllRanges(); @@ -408,8 +414,8 @@ export default class SideCardsPlugin extends Plugin { if (!selection.rangeCount) return null; const baseRange = selection.getRangeAt(0); if (!baseRange.collapsed) return baseRange; - const node = baseRange.startContainer; - if (!node.instanceOf(Text)) return null; + const node = baseRange.startContainer as Text; + if (!node?.data) return null; const text = node.data; if (!text) return null; const offset = baseRange.startOffset; @@ -420,7 +426,7 @@ export default class SideCardsPlugin extends Plugin { let end = offset; while (start > 0 && this.isWordChar(text[start - 1])) start--; while (end < text.length && this.isWordChar(text[end])) end++; - const wordRange = activeDocument.createRange(); + const wordRange = document.createRange(); wordRange.setStart(node, start); wordRange.setEnd(node, end); return wordRange; @@ -511,7 +517,7 @@ export default class SideCardsPlugin extends Plugin { folderInput.addEventListener('focus', () => renderSuggestions(folderInput.value)); folderInput.addEventListener('input', () => renderSuggestions(folderInput.value)); - folderInput.addEventListener('blur', () => activeWindow.setTimeout(() => suggestEl.removeClass('is-visible'), 150)); + folderInput.addEventListener('blur', () => window.setTimeout(() => suggestEl.removeClass('is-visible'), 150)); const btnRow = content.createDiv({ cls: 'sc-setup-btn-row' }); @@ -537,7 +543,7 @@ export default class SideCardsPlugin extends Plugin { }); modal.open(); - activeWindow.setTimeout(() => folderInput.focus(), 50); + window.setTimeout(() => folderInput.focus(), 50); } async fetchAllReleases(): Promise> { @@ -579,7 +585,7 @@ class SideCardsSettingTab extends PluginSettingTab { } private updateCSSVariables(): void { - const root = activeDocument.documentElement; + const root = document.documentElement; root.setCssProps({ '--card-color-1': this.plugin.settings.color1 || '#8392a4', '--card-color-2': this.plugin.settings.color2 || '#eb3b5a', @@ -613,7 +619,7 @@ class SideCardsSettingTab extends PluginSettingTab { if (hex && hex.startsWith('var')) { const varName = hex.match(/--[a-zA-Z0-9-]+/)?.[0]; if (varName) { - hex = getComputedStyle(activeDocument.documentElement).getPropertyValue(varName).trim(); + hex = getComputedStyle(document.documentElement).getPropertyValue(varName).trim(); } } @@ -691,8 +697,8 @@ class SideCardsSettingTab extends PluginSettingTab { const rect = row.getBoundingClientRect(); offsetY = e.clientY - rect.top; - activeDocument.addEventListener('pointermove', onPointerMove, { passive: false }); - activeDocument.addEventListener('pointerup', onPointerUp); + document.addEventListener('pointermove', onPointerMove, { passive: false }); + document.addEventListener('pointerup', onPointerUp); // Don't preventDefault yet — let clicks through until threshold }; @@ -725,7 +731,7 @@ class SideCardsSettingTab extends PluginSettingTab { boxShadow: '0 4px 16px rgba(0,0,0,0.25)', opacity: '0.9', }); - activeDocument.body.appendChild(ghost); + document.body.appendChild(ghost); draggedEl!.setCssProps({ 'opacity': '0.3' }); } @@ -754,8 +760,8 @@ class SideCardsSettingTab extends PluginSettingTab { }; const onPointerUp = (e: PointerEvent) => { - activeDocument.removeEventListener('pointermove', onPointerMove); - activeDocument.removeEventListener('pointerup', onPointerUp); + document.removeEventListener('pointermove', onPointerMove); + document.removeEventListener('pointerup', onPointerUp); getRows().forEach(row => row.removeClass('sc-drag-over-top', 'sc-drag-over-bottom')); @@ -779,8 +785,8 @@ class SideCardsSettingTab extends PluginSettingTab { container.addEventListener('pointerdown', onPointerDown); return () => { container.removeEventListener('pointerdown', onPointerDown); - activeDocument.removeEventListener('pointermove', onPointerMove); - activeDocument.removeEventListener('pointerup', onPointerUp); + document.removeEventListener('pointermove', onPointerMove); + document.removeEventListener('pointerup', onPointerUp); ghost?.remove(); if (draggedEl) draggedEl.setCssProps({ 'opacity': '' }); }; @@ -841,22 +847,29 @@ class SideCardsSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Storage folder') .setDesc('Choose where to save notes created from cards.') - .addSearch(cb => { - cb.setPlaceholder('Choose a folder') - .setValue(this.plugin.settings.storageFolder || '') - .onChange(async (value) => { - const newFolder = value.trim(); - const oldFolder = this.plugin.settings.storageFolder; - this.plugin.settings.storageFolder = newFolder; - this.plugin.settings.tutorialShown = true; - await this.plugin.saveSettings(); - if (newFolder !== oldFolder) { - await this.plugin.store.switchStorageFolder(newFolder); - } + .addButton(b => { + b.setButtonText(this.plugin.settings.storageFolder?.trim() ? this.plugin.settings.storageFolder : 'Unset') + .onClick(() => { + const folders = this.app.vault.getAllLoadedFiles() + .filter((f): f is TFolder => f instanceof TFolder) + .map(f => f.path) + .sort(); + const suggest = new FolderSuggestModal(this.app, folders, async (folder) => { + const newFolder = folder || ''; + const oldFolder = this.plugin.settings.storageFolder; + this.plugin.settings.storageFolder = newFolder; + this.plugin.settings.tutorialShown = true; + await this.plugin.saveSettings(); + if (newFolder !== oldFolder) { + await this.plugin.store.switchStorageFolder(newFolder); + } + b.setButtonText(this.plugin.settings.storageFolder?.trim() ? this.plugin.settings.storageFolder : 'Unset'); + refreshSidebarCards(); + refreshHomepage(); + }); + suggest.setPlaceholder('Select storage folder...'); + suggest.open(); }); - const folders = new Set(['/']); - this.app.vault.getAllLoadedFiles().forEach((file) => { if (file.parent) folders.add(file.parent.path); }); - new FolderSuggest(this.app, cb.inputEl, folders); }); // ── Behaviour ───────────────────────────────────────────────────────────── @@ -1038,7 +1051,7 @@ class SideCardsSettingTab extends PluginSettingTab { label.textContent = `${value}px`; await this.plugin.saveSettings(); // Apply live to open homepage views - activeDocument.querySelectorAll('.sc-home-container').forEach((el) => { + document.querySelectorAll('.sc-home-container').forEach((el) => { (el as HTMLElement).setCssProps({ '--sc-home-max-width': `${value}px` }); }); }); @@ -1059,9 +1072,7 @@ class SideCardsSettingTab extends PluginSettingTab { this.plugin.settings.homepageTopMargin = value; label.textContent = `${value}px`; await this.plugin.saveSettings(); - activeDocument.querySelectorAll('.sc-home-container').forEach((el) => { - (el as HTMLElement).setCssProps({ '--sc-home-top-margin': `${value}px` }); - }); + document.documentElement.style.setProperty('--sc-home-top-margin', `${value}px`); }); slider.sliderEl.insertAdjacentElement('afterend', label); }); @@ -1079,7 +1090,7 @@ class SideCardsSettingTab extends PluginSettingTab { previewCard.className = 'sc-card'; previewCard.addClass(`sc-style-${settings.cardStyle || 2}`); const color1 = settings.color1 || '#8392a4'; - const root = activeDocument.documentElement; + const root = document.documentElement; root.setCssProps({ '--card-color-1': color1 }); previewCard.setCssProps({ 'border-radius': `${settings.borderRadius || 0}px`, @@ -1142,7 +1153,7 @@ class SideCardsSettingTab extends PluginSettingTab { new Setting(containerEl).setName('Card border radius').setDesc('Set the corner rounding of the card').addSlider(slider => slider.setLimits(0, 30, 1).setValue(this.plugin.settings.borderRadius || 0).setDynamicTooltip().onChange(async (value) => { this.plugin.settings.borderRadius = value; await this.plugin.saveSettings(); - activeDocument.documentElement.setCssProps({ '--card-border-radius': `${value}px` }); + document.documentElement.setCssProps({ '--card-border-radius': `${value}px` }); updatePreview(); refreshSidebarCards(); })); @@ -1369,7 +1380,7 @@ class SideCardsSettingTab extends PluginSettingTab { if (e.dataTransfer) { e.dataTransfer.effectAllowed = 'move'; } - activeWindow.setTimeout(() => { + window.setTimeout(() => { setting.settingEl.addClass('sc-dragging'); }, 0); }); @@ -1824,7 +1835,7 @@ class SideCardsSettingTab extends PluginSettingTab { ruleDragSrcId = `rule-${idx}`; e.dataTransfer?.setData('text/plain', ruleDragSrcId); if (e.dataTransfer) e.dataTransfer.effectAllowed = 'move'; - activeWindow.setTimeout(() => setting.settingEl.addClass('sc-dragging'), 0); + window.setTimeout(() => setting.settingEl.addClass('sc-dragging'), 0); }); setting.settingEl.addEventListener('dragend', () => { rulesContainer.querySelectorAll('.sc-dragging').forEach(el => el.removeClass('sc-dragging')); @@ -2047,7 +2058,7 @@ class SideCardsSettingTab extends PluginSettingTab { statusDragSrcId = `status-${idx}`; e.dataTransfer?.setData('text/plain', statusDragSrcId); if (e.dataTransfer) e.dataTransfer.effectAllowed = 'move'; - activeWindow.setTimeout(() => setting.settingEl.addClass('sc-dragging'), 0); + window.setTimeout(() => setting.settingEl.addClass('sc-dragging'), 0); }); setting.settingEl.addEventListener('dragend', () => { statusConfigContainer.querySelectorAll('.sc-dragging').forEach(el => el.removeClass('sc-dragging')); @@ -2128,16 +2139,16 @@ class SideCardsSettingTab extends PluginSettingTab { const a = containerEl.createEl('a'); a.href = url; a.download = `sidecards-export-${new Date().toISOString().slice(0, 10)}.json`; - activeDocument.body.appendChild(a); + document.body.appendChild(a); a.click(); - activeDocument.body.removeChild(a); + document.body.removeChild(a); URL.revokeObjectURL(url); new Notice('Cards exported.'); })); new Setting(containerEl) .setName('Import Data') - .setDesc('Import cards from a previously exported JSON file. Existing cards with the same ID will be skipped.') + .setDesc('Import cards from a previously exported JSON file.') .addButton(btn => btn .setButtonText('Import Data') .onClick(() => { @@ -2306,73 +2317,26 @@ class ChangelogModal extends Modal { } } -class FolderSuggest { - private suggestEl: HTMLElement; - private folders: string[]; +class FolderSuggestModal extends FuzzySuggestModal { + folders: string[]; + onChoose: (folder: string) => void | Promise; - constructor(private app: App, private inputEl: HTMLInputElement, folders: Set) { - this.folders = Array.from(folders).sort(); - this.suggestEl = this.inputEl.parentElement?.createDiv() || activeDocument.createElement('div'); - this.suggestEl.className = 'suggestion-container sc-folder-suggest'; - this.inputEl.parentElement?.appendChild(this.suggestEl); - this.inputEl.addEventListener('click', () => this.onFocus()); - this.inputEl.addEventListener('input', () => this.onInput()); - activeDocument.addEventListener('click', (event) => this.onClick(event)); + constructor(app: App, folders: string[], onChoose: (folder: string) => void | Promise) { + super(app); + this.folders = folders; + this.onChoose = onChoose; } - private onFocus(): void { - const foldersSet = new Set(['/']); - type VaultNode = { path?: string; children?: VaultNode[] }; - const vaultWithRoot = this.app.vault as unknown as { getRoot?: () => VaultNode }; - const root: VaultNode | undefined = vaultWithRoot.getRoot?.(); - const walk = (node: VaultNode) => { - if (!node) return; - const children = node.children || []; - for (const c of children) { - if (c && c.path && c.children) { - foldersSet.add(c.path || '/'); - walk(c); - } - } - }; - if (root) walk(root); - try { - this.app.vault.getAllLoadedFiles().forEach((file) => { - if (file && file.parent) foldersSet.add(file.parent.path); - }); - } catch { /* ignore */ } - this.folders = Array.from(foldersSet).sort(); - this.updateSuggestions(); - this.suggestEl.addClass('is-visible'); + getItems(): string[] { + return this.folders; } - private onInput(): void { - this.updateSuggestions(); + getItemText(item: string): string { + return item; } - private onClick(event: MouseEvent): void { - const target = event.target as Node | null; - if (!target) return; - if (!this.inputEl.contains(target) && !this.suggestEl.contains(target)) { - this.suggestEl.removeClass('is-visible'); - } - } - - private updateSuggestions(): void { - const inputValue = this.inputEl.value.toLowerCase(); - this.suggestEl.empty(); - const filtered = this.folders.filter(folder => folder.toLowerCase().includes(inputValue)).slice(0, 100); - filtered.forEach(folder => { - const item = this.suggestEl.createDiv(); - item.className = 'suggestion-item sc-folder-suggest-item'; - item.textContent = folder; - item.addEventListener('click', () => { - this.inputEl.value = folder; - this.inputEl.dispatchEvent(new Event('input')); - this.suggestEl.removeClass('is-visible'); - }); - this.suggestEl.appendChild(item); - }); + onChooseItem(item: string, evt: MouseEvent | KeyboardEvent): void { + void Promise.resolve(this.onChoose(item)); } } diff --git a/src/utils/dom.ts b/src/utils/dom.ts index e81c366..51882d2 100644 --- a/src/utils/dom.ts +++ b/src/utils/dom.ts @@ -67,8 +67,6 @@ export function applyCardColorToElement(cardEl: HTMLElement, colorVar: string, s const hex = resolveColorVarToHex(colorVar, settings) || colorVar; const rgba = hexToRgba(hex, opacity); const borderColor = borderShadowOpacity >= 1 ? colorVar : hexToRgba(hex, borderShadowOpacity); - const borderRadius = settings.borderRadius ?? 6; - if (style === 1) { cardEl.setCssProps({ 'border': `${borderThickness}px solid ${borderColor}`, @@ -90,8 +88,6 @@ export function applyCardColorToElement(cardEl: HTMLElement, colorVar: string, s 'box-shadow': `2px 2px 0 0 ${borderColor}` }); } - - cardEl.setCssProps({ 'border-radius': `${borderRadius}px` }); } export function resolveAutoColor( diff --git a/src/utils/drag-drop.ts b/src/utils/drag-drop.ts index 44b7f1b..661e04f 100644 --- a/src/utils/drag-drop.ts +++ b/src/utils/drag-drop.ts @@ -1,4 +1,3 @@ -import { activeDocument } from "obsidian"; import SideCardsPlugin from "../core/Plugin"; /** @@ -175,8 +174,8 @@ export function attachDragToReorder( offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; - activeDocument.addEventListener('pointermove', onPointerMove); - activeDocument.addEventListener('pointerup', onPointerUp); + document.addEventListener('pointermove', onPointerMove); + document.addEventListener('pointerup', onPointerUp); // Don't preventDefault here for mouse — let clicks through until threshold crossed // For touch, we need to prevent scroll once drag is active (done in onPointerMove) }; @@ -436,8 +435,8 @@ export function attachPinnedListDragToReorder( dropIndex = computeDropIndex(e.clientY); positionIndicator(dropIndex); - activeDocument.addEventListener('pointermove', onPointerMove); - activeDocument.addEventListener('pointerup', onPointerUp); + document.addEventListener('pointermove', onPointerMove); + document.addEventListener('pointerup', onPointerUp); e.preventDefault(); }; diff --git a/src/views/CardSidebarView.ts b/src/views/CardSidebarView.ts index 22258e1..b4add42 100644 --- a/src/views/CardSidebarView.ts +++ b/src/views/CardSidebarView.ts @@ -1,5 +1,5 @@ -import { ItemView, WorkspaceLeaf, Notice, Menu, TFile, setIcon, Scope, Editor, App, MarkdownFileInfo, Text } from "obsidian"; +import { ItemView, WorkspaceLeaf, Notice, Menu, TFile, setIcon, Scope, Editor, App, MarkdownFileInfo } from "obsidian"; import { CardStore } from "../services/CardStore"; import { FilterService, FilterOptions } from "../services/FilterService"; import { SortService, SortMode } from "../services/SortService"; @@ -86,8 +86,8 @@ export class CardSidebarView extends ItemView { if (!selection.rangeCount) return null; const baseRange = selection.getRangeAt(0); if (!baseRange.collapsed) return baseRange; - const node = baseRange.startContainer; - if (!node.instanceOf(Text)) return null; + const node = baseRange.startContainer as Text; + if (!node?.data) return null; const text = node.data; if (!text) return null; const offset = baseRange.startOffset; diff --git a/src/views/HomeView.ts b/src/views/HomeView.ts index a28a5be..464ef4a 100644 --- a/src/views/HomeView.ts +++ b/src/views/HomeView.ts @@ -1,4 +1,4 @@ -import { ItemView, WorkspaceLeaf, Menu, Notice, setIcon, Scope, Editor, TFile, Platform, App, MarkdownFileInfo, Text } from "obsidian"; +import { ItemView, WorkspaceLeaf, Menu, Notice, setIcon, Scope, Editor, TFile, Platform, App, MarkdownFileInfo } from "obsidian"; import type SideCardsPlugin from "../core/Plugin"; import { CardStore } from "../services/CardStore"; import { Card } from "../models/Card"; @@ -91,8 +91,8 @@ export class SideCardsHomeView extends ItemView { if (!selection.rangeCount) return null; const baseRange = selection.getRangeAt(0); if (!baseRange.collapsed) return baseRange; - const node = baseRange.startContainer; - if (!node.instanceOf(Text)) return null; + const node = baseRange.startContainer as Text; + if (!node?.data) return null; const text = node.data; if (!text) return null; const offset = baseRange.startOffset; @@ -306,8 +306,6 @@ export class SideCardsHomeView extends ItemView { // Apply user-configured max width via CSS variable so it overrides correctly const maxW = this.plugin.settings.homepageMaxWidth ?? 1000; container.setCssProps({ '--sc-home-max-width': `${maxW}px` }); - const topMargin = this.plugin.settings.homepageTopMargin ?? 70; - container.setCssProps({ '--sc-home-top-margin': `${topMargin}px` }); // Top Section const topSection = main.createDiv({ cls: 'sc-home-top' }); @@ -762,7 +760,7 @@ export class SideCardsHomeView extends ItemView { this.renderCards(cardList); } - private renderToolbar(container: HTMLElement, _editorEl: HTMLElement, _cardList: HTMLElement, pinnedList: HTMLElement, recentList: HTMLElement) { + private renderToolbar(container: HTMLElement, _editorEl: HTMLElement, cardList: HTMLElement, pinnedList: HTMLElement, recentList: HTMLElement) { container.empty(); const leftActions = container.createDiv({ cls: 'sc-home-toolbar-left' }); diff --git a/styles.css b/styles.css index 57a5afe..8a49640 100644 --- a/styles.css +++ b/styles.css @@ -8,16 +8,32 @@ .sc-home-category-bar { margin: 0; gap: 10px; + display: flex; + flex-wrap: nowrap; + overflow-x: auto; + padding-bottom: 0; + margin-bottom: 16px; + scrollbar-width: none; } .sc-color-dots.two-row { gap: 8px; margin-bottom: 6px; + display: grid; + grid-template-columns: repeat(5, 18px); + grid-auto-rows: 18px; + column-gap: 8px; + row-gap: 8px; + width: fit-content; } .sc-home-main { - margin-top: var(--sc-home-top-margin, 70px); + margin: var(--sc-home-top-margin, 70px) auto 0; transition: all 0.2s ease; + width: 100%; + max-width: var(--sc-home-max-width, 1000px); + padding: 40px 20px; + box-sizing: border-box; } .sc-home-right, @@ -30,6 +46,10 @@ .sc-sidebar-button-container { padding-bottom: var(--sc-button-padding-bottom, 26px); + display: flex; + gap: 8px; + justify-content: flex-end; + margin-top: 8px; } .sc-content p { @@ -162,14 +182,6 @@ background-color: var(--background-primary); } -.sc-home-main { - width: 100%; - max-width: var(--sc-home-max-width, 1000px); - margin: 0 auto; - padding: 40px 20px; - box-sizing: border-box; -} - .sc-home-top { margin-bottom: 40px; } @@ -348,27 +360,14 @@ padding: 6px 8px; font-size: 13px; width: 100%; + font-family: var(--font-interface); } .sc-home-search-input::placeholder { color: var(--text-muted); } -.sc-home-category-bar { - display: flex; - gap: 4px; - flex-wrap: nowrap; - overflow-x: auto; - padding-bottom: 16px; - margin-bottom: 16px; - scrollbar-width: none; -} - -.sc-home-category-bar::-webkit-scrollbar { - display: none; -} - -.sc-home-card-list { +.sc-home-card-list { display: flex; flex-direction: column; gap: 8px; @@ -447,6 +446,7 @@ padding: 8px; scrollbar-width: auto; -ms-overflow-style: auto; + position: relative; } .sc-sidebar-cards-container.hide-scrollbar { @@ -623,7 +623,7 @@ flex-shrink: 0; transition: transform 0.1s ease; } -de + .sc-home-color-dot { border-radius: 10px; border: 1px solid var(--background-primary); @@ -807,11 +807,6 @@ de height: 100%; } -/* sc-sidebar-cards-container positional */ -.sc-sidebar-cards-container { - position: relative; -} - /* sc-sidebar-input-container: sticky bottom input area */ .sc-sidebar-input-container { padding: 8px; @@ -821,14 +816,6 @@ de bottom: 0; } -/* sc-sidebar-button-container: action buttons row */ -.sc-sidebar-button-container { - display: flex; - gap: 8px; - justify-content: flex-end; - margin-top: 8px; -} - /* sc-sidebar-loading: full-cover loading overlay */ .sc-sidebar-loading { position: absolute; @@ -863,6 +850,7 @@ de overflow-x: auto; flex-wrap: nowrap; white-space: nowrap; + border-bottom: 1px solid var(--background-modifier-border); } /* sc-search-wrap visibility helpers */ @@ -897,21 +885,6 @@ de order: 1; } -/* Home search input font */ -.sc-home-search-input { - font-family: var(--font-interface); -} - -/* Color swatch grid (two-row context menu) */ -.sc-color-dots.two-row { - display: grid; - grid-template-columns: repeat(5, 18px); - grid-auto-rows: 18px; - column-gap: 8px; - row-gap: 8px; - width: fit-content; -} - /* Individual color swatch in context menu */ .sc-color-dot-swatch { width: 18px;