Fixed Card Border Radius & Homepage Top Spacing bug

This commit is contained in:
Kazi Aidah Haque 2026-05-17 02:03:05 +06:00
parent f6276b019f
commit 217a4fd4da
7 changed files with 208 additions and 341 deletions

241
main.js
View file

@ -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 {

View file

@ -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<Array<{ name?: string; tag_name?: string; published_at?: string; created_at?: string; body?: string }>> {
@ -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<string>(['/']);
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<string> {
folders: string[];
onChoose: (folder: string) => void | Promise<void>;
constructor(private app: App, private inputEl: HTMLInputElement, folders: Set<string>) {
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<void>) {
super(app);
this.folders = folders;
this.onChoose = onChoose;
}
private onFocus(): void {
const foldersSet = new Set<string>(['/']);
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));
}
}

View file

@ -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(

View file

@ -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();
};

View file

@ -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;

View file

@ -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' });

View file

@ -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;