diff --git a/quartz/components/LinkCardHandler.tsx b/quartz/components/LinkCardHandler.tsx index 494aa5cf9..08d9f9797 100644 --- a/quartz/components/LinkCardHandler.tsx +++ b/quartz/components/LinkCardHandler.tsx @@ -1,13 +1,8 @@ // @ts-ignore import linkCardScript from "./scripts/linkcard.inline" -import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor } from "./types" -const LinkCardHandler: QuartzComponent = ({ - displayClass: _displayClass, - cfg: _cfg, -}: QuartzComponentProps) => { - return <> -} +const LinkCardHandler: QuartzComponent = () => null LinkCardHandler.beforeDOMLoaded = linkCardScript diff --git a/quartz/components/scripts/linkcard.inline.ts b/quartz/components/scripts/linkcard.inline.ts index ee8811605..3101c9c09 100644 --- a/quartz/components/scripts/linkcard.inline.ts +++ b/quartz/components/scripts/linkcard.inline.ts @@ -1,29 +1,21 @@ -// Handle link card image failures function handleLinkCardImages() { - const linkCardImages = document.querySelectorAll(".rlc-image") + const linkCardImages = document.querySelectorAll(".rlc-image") as NodeListOf - linkCardImages.forEach((img: Element) => { - const imgElement = img as HTMLImageElement + linkCardImages.forEach((imgElement) => { const container = imgElement.closest(".rlc-image-container") - if (!container) return - // If the image has already failed to load (complete=true and naturalWidth=0) if (imgElement.complete && imgElement.naturalWidth === 0) { container.classList.add("image-failed") return } - // Event listener for image load errors - const handleError = () => { - container.classList.add("image-failed") - } + const handleError = () => container.classList.add("image-failed") - imgElement.addEventListener("error", handleError) + imgElement.addEventListener("error", handleError, { once: true }) window.addCleanup(() => imgElement.removeEventListener("error", handleError)) }) } -// Execute on page load and navigation events document.addEventListener("nav", handleLinkCardImages) document.addEventListener("DOMContentLoaded", handleLinkCardImages) diff --git a/quartz/components/styles/linkcard.scss b/quartz/components/styles/linkcard.scss index de08e3a8d..90235ac57 100644 --- a/quartz/components/styles/linkcard.scss +++ b/quartz/components/styles/linkcard.scss @@ -91,7 +91,7 @@ height: 100%; object-fit: cover; object-position: center; - min-width: 100%; // コンテナの幅は最低限埋める + min-width: 100%; // ensure container width is minimally filled } } diff --git a/quartz/plugins/transformers/linkcard.ts b/quartz/plugins/transformers/linkcard.ts index 85f1384b7..05aa4d379 100644 --- a/quartz/plugins/transformers/linkcard.ts +++ b/quartz/plugins/transformers/linkcard.ts @@ -14,6 +14,9 @@ const defaultOptions: Options = { showDescription: false, } +/** + * LinkCard transformer plugin that processes link metadata at build time. + */ export const LinkCard: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { diff --git a/quartz/styles/linkcard.scss b/quartz/styles/linkcard.scss deleted file mode 100644 index c2fd08a91..000000000 --- a/quartz/styles/linkcard.scss +++ /dev/null @@ -1,147 +0,0 @@ -.rlc-container { - display: flex; - text-decoration: none; - border: 1px solid var(--lightgray); - border-radius: 12px; - margin: 16px 0; - background: var(--light); - transition: all 0.2s ease; - color: var(--darkgray); - overflow: hidden; - - &:hover { - border-color: var(--secondary); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08); - text-decoration: none; - color: var(--darkgray); - transform: translateY(-2px); - } - - .rlc-info { - display: flex; - flex-direction: column; - justify-content: center; - flex: 1; - padding: 12px 16px; - min-width: 0; - gap: 4px; - } - - .rlc-content { - flex: 1; - } - - .rlc-title { - font-weight: 600; - font-size: 1rem; - line-height: 1.3; - margin: 0 0 4px 0; - color: var(--dark); - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .rlc-description { - display: none; - } - - .rlc-url-container { - display: flex; - align-items: center; - gap: 6px; - font-size: 0.75rem; - color: var(--gray); - margin: 0; - } - - .rlc-favicon { - width: 16px; - height: 16px; - border-radius: 3px; - flex-shrink: 0; - } - - .rlc-url { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - } - - .rlc-image-container { - flex-shrink: 0; - display: flex; - align-items: center; - justify-content: center; - background: var(--lightgray); - position: relative; - overflow: hidden; - min-width: 120px; // set minimum width - max-width: 300px; // set maximum width - height: 120px; // fixed height - width: auto; // width adjusts automatically to image - - &.image-failed { - display: none; - } - } - - .rlc-image { - width: auto; - height: 100%; - object-fit: cover; - object-position: center; - min-width: 100%; // ensure container is at least filled - } -} - -@media (max-width: 768px) { - .rlc-container { - flex-direction: column; - min-height: auto; - margin: 12px 0; - - .rlc-info { - padding: 16px; - } - - .rlc-image-container { - width: 100%; - height: 160px; - order: -1; - max-width: none; // remove max-width restriction on mobile - - &.image-failed { - display: none; - } - } - - .rlc-title { - font-size: 0.95rem; - } - } -} - -@media (max-width: 480px) { - .rlc-container { - .rlc-info { - padding: 12px; - } - - .rlc-image-container { - height: 140px; - - &.image-failed { - display: none; - } - } - - .rlc-title { - font-size: 0.9rem; - } - - .rlc-url-container { - font-size: 0.7rem; - } - } -}