diff --git a/content/index.md b/content/index.md index 74c811258..573f9eff0 100644 --- a/content/index.md +++ b/content/index.md @@ -16,4 +16,4 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started. https://quartz.jzhao.xyz ☝️ Link Card View! -``` \ No newline at end of file +``` diff --git a/quartz/components/LinkCardHandler.tsx b/quartz/components/LinkCardHandler.tsx index a41a10381..494aa5cf9 100644 --- a/quartz/components/LinkCardHandler.tsx +++ b/quartz/components/LinkCardHandler.tsx @@ -2,10 +2,13 @@ import linkCardScript from "./scripts/linkcard.inline" import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -const LinkCardHandler: QuartzComponent = ({ displayClass: _displayClass, cfg:_cfg }: QuartzComponentProps) => { +const LinkCardHandler: QuartzComponent = ({ + displayClass: _displayClass, + cfg: _cfg, +}: QuartzComponentProps) => { return <> } LinkCardHandler.beforeDOMLoaded = linkCardScript -export default (() => LinkCardHandler) satisfies QuartzComponentConstructor \ No newline at end of file +export default (() => LinkCardHandler) satisfies QuartzComponentConstructor diff --git a/quartz/components/scripts/linkcard.inline.ts b/quartz/components/scripts/linkcard.inline.ts index c5ff8024b..ee8811605 100644 --- a/quartz/components/scripts/linkcard.inline.ts +++ b/quartz/components/scripts/linkcard.inline.ts @@ -1,29 +1,29 @@ // Handle link card image failures function handleLinkCardImages() { - const linkCardImages = document.querySelectorAll('.rlc-image') - + const linkCardImages = document.querySelectorAll(".rlc-image") + linkCardImages.forEach((img: Element) => { const imgElement = img as HTMLImageElement - const container = imgElement.closest('.rlc-image-container') - + 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') + container.classList.add("image-failed") return } - + // Event listener for image load errors const handleError = () => { - container.classList.add('image-failed') + container.classList.add("image-failed") } - - imgElement.addEventListener('error', handleError) - window.addCleanup(() => imgElement.removeEventListener('error', handleError)) + + imgElement.addEventListener("error", handleError) + window.addCleanup(() => imgElement.removeEventListener("error", handleError)) }) } // Execute on page load and navigation events -document.addEventListener('nav', handleLinkCardImages) -document.addEventListener('DOMContentLoaded', handleLinkCardImages) \ No newline at end of file +document.addEventListener("nav", handleLinkCardImages) +document.addEventListener("DOMContentLoaded", handleLinkCardImages) diff --git a/quartz/components/styles/linkcard.scss b/quartz/components/styles/linkcard.scss index aaa4bfdb3..de08e3a8d 100644 --- a/quartz/components/styles/linkcard.scss +++ b/quartz/components/styles/linkcard.scss @@ -1,148 +1,147 @@ .rlc-container { - display: flex; + 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; - border: 1px solid var(--lightgray); - border-radius: 12px; - margin: 16px 0; - background: var(--light); - transition: all 0.2s ease; 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; - - &: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 { + 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-url-container { - display: flex; - align-items: center; - gap: 6px; - font-size: 0.75rem; - color: var(--gray); - margin: 0; + } + + .rlc-image { + width: auto; + height: 100%; + object-fit: cover; + object-position: center; + min-width: 100%; // コンテナの幅は最低限埋める + } +} + +@media (max-width: 768px) { + .rlc-container { + flex-direction: column; + min-height: auto; + margin: 12px 0; + + .rlc-info { + padding: 16px; } - - .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 - + width: 100%; + height: 160px; + order: -1; + max-width: none; // remove max-width restriction on mobile + &.image-failed { display: none; } } - - .rlc-image { - width: auto; - height: 100%; - object-fit: cover; - object-position: center; - min-width: 100%; // コンテナの幅は最低限埋める + + .rlc-title { + font-size: 0.95rem; } } - - @media (max-width: 768px) { - .rlc-container { - flex-direction: column; - min-height: auto; - margin: 12px 0; - - .rlc-info { - padding: 16px; +} + +@media (max-width: 480px) { + .rlc-container { + .rlc-info { + padding: 12px; + } + + .rlc-image-container { + height: 140px; + + &.image-failed { + display: none; } - - .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; - } - + } + + .rlc-title { + font-size: 0.9rem; + } + + .rlc-url-container { + font-size: 0.7rem; } } - - @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; - } - } - } \ No newline at end of file +} diff --git a/quartz/plugins/transformers/index.ts b/quartz/plugins/transformers/index.ts index 9afb24f52..84c398fda 100644 --- a/quartz/plugins/transformers/index.ts +++ b/quartz/plugins/transformers/index.ts @@ -11,4 +11,4 @@ export { SyntaxHighlighting } from "./syntax" export { TableOfContents } from "./toc" export { HardLineBreaks } from "./linebreaks" export { RoamFlavoredMarkdown } from "./roam" -export { LinkCard } from "./linkcard" \ No newline at end of file +export { LinkCard } from "./linkcard" diff --git a/quartz/plugins/transformers/linkcard.ts b/quartz/plugins/transformers/linkcard.ts index 9cc40045b..85f1384b7 100644 --- a/quartz/plugins/transformers/linkcard.ts +++ b/quartz/plugins/transformers/linkcard.ts @@ -31,4 +31,4 @@ export const LinkCard: QuartzTransformerPlugin> = (userOpts) => ] }, } -} \ No newline at end of file +} diff --git a/quartz/styles/linkcard.scss b/quartz/styles/linkcard.scss index 62f2ca391..c2fd08a91 100644 --- a/quartz/styles/linkcard.scss +++ b/quartz/styles/linkcard.scss @@ -1,148 +1,147 @@ .rlc-container { - display: flex; + 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; - border: 1px solid var(--lightgray); - border-radius: 12px; - margin: 16px 0; - background: var(--light); - transition: all 0.2s ease; 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; - - &: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 { + 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-url-container { - display: flex; - align-items: center; - gap: 6px; - font-size: 0.75rem; - color: var(--gray); - margin: 0; + } + + .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-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 - + width: 100%; + height: 160px; + order: -1; + max-width: none; // remove max-width restriction on mobile + &.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 + + .rlc-title { + font-size: 0.95rem; } } - - @media (max-width: 768px) { - .rlc-container { - flex-direction: column; - min-height: auto; - margin: 12px 0; - - .rlc-info { - padding: 16px; +} + +@media (max-width: 480px) { + .rlc-container { + .rlc-info { + padding: 12px; + } + + .rlc-image-container { + height: 140px; + + &.image-failed { + display: none; } - - .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; - } - + } + + .rlc-title { + font-size: 0.9rem; + } + + .rlc-url-container { + font-size: 0.7rem; } } - - @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; - } - } - } \ No newline at end of file +}