vault backup: 2024-12-26 16:54:24

This commit is contained in:
2024-12-26 16:54:24 +08:00
parent 31571f0b31
commit 58edbcd957
14 changed files with 293 additions and 17 deletions

183
.obsidian/plugins/link-preview/main.js vendored Normal file
View File

@@ -0,0 +1,183 @@
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// main.ts
var main_exports = {};
__export(main_exports, {
default: () => LinkPreviewPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian = require("obsidian");
var DEFAULT_SETTINGS = {
previewDelay: 300,
maxPreviewHeight: 400,
maxPreviewWidth: 600
};
var LinkPreviewPlugin = class extends import_obsidian.Plugin {
constructor() {
super(...arguments);
// Track active preview elements by link URL
this.activeLinks = /* @__PURE__ */ new Map();
}
async onload() {
await this.loadSettings();
this.registerHoverHandler(document);
this.registerEvent(
this.app.workspace.on("window-open", ({ win }) => {
this.registerHoverHandler(win.document);
})
);
this.addSettingTab(new LinkPreviewSettingTab(this.app, this));
}
registerHoverHandler(doc) {
this.registerDomEvent(doc, "mouseover", (evt) => {
const target = evt.target;
const linkEl = target.closest("a");
if (!linkEl)
return;
if (linkEl.hasClass("external-link")) {
const rect = linkEl.getBoundingClientRect();
this.showPreview(linkEl, rect, doc);
}
});
}
/**
* Clean up any remaining previews when plugin is disabled
*/
onunload() {
this.activeLinks.forEach((previewEl, linkId) => {
previewEl.remove();
});
this.activeLinks.clear();
}
/**
* Creates and shows a preview window for a link element
* @param linkEl - The link element for which to create a preview
* @param rect - The bounding rectangle of the link element
*/
showPreview(linkEl, rect, doc) {
const url = linkEl.getAttribute("href");
if (!url)
return;
const linkId = `preview-${url}`;
if (this.activeLinks.has(linkId))
return;
let hideTimeout;
const win = doc.defaultView;
if (!win)
return;
const handleLinkLeave = () => {
hideTimeout = win.setTimeout(cleanupPreview, 300);
};
const handlePreviewEnter = () => {
if (hideTimeout) {
win.clearTimeout(hideTimeout);
}
};
const handlePreviewLeave = () => {
cleanupPreview();
};
const cleanupPreview = () => {
const previewEl = this.activeLinks.get(linkId);
if (previewEl) {
previewEl.remove();
this.activeLinks.delete(linkId);
}
linkEl.removeEventListener("mouseleave", handleLinkLeave);
};
setTimeout(() => {
if (this.activeLinks.has(linkId))
return;
const hoverEl = this.createPreviewElement(rect);
this.activeLinks.set(linkId, hoverEl);
const loadingEl = hoverEl.createDiv({ cls: "preview-loading" });
loadingEl.setText("Loading preview...");
const iframeWrapper = hoverEl.createDiv({ cls: "preview-iframe-wrapper" });
const iframe = iframeWrapper.createEl("iframe", {
attr: {
src: url
}
});
iframe.addEventListener("load", () => {
loadingEl.remove();
iframe.style.display = "block";
});
iframe.addEventListener("error", () => {
loadingEl.setText("Failed to load preview");
});
linkEl.addEventListener("mouseleave", handleLinkLeave);
hoverEl.addEventListener("mouseenter", handlePreviewEnter);
hoverEl.addEventListener("mouseleave", handlePreviewLeave);
doc.body.appendChild(hoverEl);
}, this.settings.previewDelay);
}
/**
* Creates the preview container element with proper positioning
* @param rect - The bounding rectangle used for positioning
* @returns HTMLElement configured as preview container
*/
createPreviewElement(rect) {
const el = createEl("div", {
cls: "hover-popup"
});
el.style.cssText = `
position: fixed;
left: ${rect.left}px;
top: ${rect.bottom + 5}px;
width: ${this.settings.maxPreviewWidth}px;
height: ${this.settings.maxPreviewHeight}px;
`;
return el;
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
};
var LinkPreviewSettingTab = class extends import_obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
const { containerEl } = this;
containerEl.empty();
new import_obsidian.Setting(containerEl).setName("Preview delay").setDesc("How long to wait before showing the preview (in milliseconds)").addText((text) => text.setPlaceholder("300").setValue(String(this.plugin.settings.previewDelay)).onChange(async (value) => {
this.plugin.settings.previewDelay = Number(value);
await this.plugin.saveSettings();
}));
new import_obsidian.Setting(containerEl).setName("Maximum preview height").setDesc("Maximum height of the preview window (in pixels)").addText((text) => text.setPlaceholder("300").setValue(String(this.plugin.settings.maxPreviewHeight)).onChange(async (value) => {
this.plugin.settings.maxPreviewHeight = Number(value);
await this.plugin.saveSettings();
}));
new import_obsidian.Setting(containerEl).setName("Maximum preview width").setDesc("Maximum width of the preview window (in pixels)").addText((text) => text.setPlaceholder("400").setValue(String(this.plugin.settings.maxPreviewWidth)).onChange(async (value) => {
this.plugin.settings.maxPreviewWidth = Number(value);
await this.plugin.saveSettings();
}));
}
};
/* nosourcemap */

View File

@@ -0,0 +1,10 @@
{
"id": "link-preview",
"name": "Link Preview",
"version": "0.1.3",
"minAppVersion": "1.7.6",
"description": "Show a preview of external links on hover",
"author": "Felipe Tappata",
"authorUrl": "https://github.com/felipetappata",
"isDesktopOnly": false
}

View File

@@ -0,0 +1,70 @@
/* Main preview container */
.hover-popup {
background-color: var(--background-primary);
border: 1px solid var(--background-modifier-border);
border-radius: var(--radius-m);
box-shadow: var(--shadow-s);
padding: var(--size-4-2);
display: flex;
flex-direction: column;
pointer-events: all;
position: fixed;
z-index: 1000;
min-height: 100px; /* Minimum height to prevent tiny windows */
}
/* Preview navigation controls */
.preview-nav-group {
display: flex;
gap: 4px;
}
.preview-nav-button-disabled {
opacity: 0.5;
cursor: default;
}
.preview-nav-button-disabled:hover {
background-color: transparent !important;
color: var(--text-muted) !important;
}
/* Only keep tooltip for external link button */
.preview-nav-button:not([data-tooltip]):hover::after {
display: none;
}
/* Preview content container */
.preview-iframe-wrapper {
flex: 1;
position: relative;
background-color: var(--background-secondary);
border-radius: var(--radius-s);
box-shadow: var(--shadow-xs);
overflow: hidden; /* Ensure content respects rounded corners */
height: 100%; /* Make sure wrapper takes full height */
min-height: 0; /* Allow wrapper to shrink */
width: 100%;
height: 100%;
}
/* Preview iframe */
.preview-iframe-wrapper iframe {
display: none;
width: 100%;
height: 100%;
border: none;
background-color: white;
pointer-events: all;
}
/* Loading state indicator */
.preview-loading {
padding: 20px;
text-align: center;
color: var(--text-muted);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}