Skip to content

Commit

Permalink
外部链接样式css优化
Browse files Browse the repository at this point in the history
  • Loading branch information
hulinjiang committed Dec 2, 2024
1 parent 743918e commit 81e0989
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 159 deletions.
2 changes: 1 addition & 1 deletion quartz/components/Banner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default (() => {
href={`https://github.com/CatCodeMe/blog_from_obsidian/commits/main/${fileRelativePath}`}
target="_blank"
rel="noreferrer noopener nofollow"
className="meta-item history-link"
className="meta-item history-link external"
title="View history on GitHub"
>
Git-Blame
Expand Down
159 changes: 66 additions & 93 deletions quartz/plugins/transformers/links.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,104 +53,77 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
if (node.tagName === "a") {
const props = node.properties
const href = props?.href as string
if (typeof href === "string") {
// Handle short domain names
const isShortDomain = /^[^/]+\.[^/]+$/.test(href)
if (isShortDomain) {
props.href = `https://${href}`
}

// rewrite all links
let dest = props.href as RelativeURL
const classes = (props.className ?? []) as string[]
const isExternal = isAbsoluteUrl(dest) || isShortDomain
classes.push(isExternal ? "external" : "internal")

// Add external-icon class for specific domains
const domainMatch = dest.match(/(?:https?:\/\/)?(?:www\.)?([^\/]+)/)
const domain = domainMatch ? domainMatch[1] : dest

// Check if it's an RSS feed
const isRSSFeed = dest.includes("index.xml")
if (isRSSFeed) {
classes.push("external-icon")
}

const hasSpecialIcon = isExternal && (
domain.includes("github.com") ||
domain.includes("twitter.com") ||
domain.includes("x.com") ||
domain.includes("google.com") ||
domain.includes("youtube.com") ||
domain.includes("stackoverflow.com") ||
domain.includes("reddit.com") ||
domain.includes("hackernews.com") ||
domain.includes("obsidian.md") ||
domain.includes("wikipedia.org") ||
domain.includes("quartz") ||
domain.includes("mermaid")
)

if (hasSpecialIcon) {
classes.push("external-icon")
} else if (isExternal && !isRSSFeed && opts.externalLinkIcon) {
// Only add arrow for external links without special icons and not RSS feeds
node.children.push({
type: "text",
value: " ↗",
})
}
// Handle short domain names
const isShortDomain = /^[^/]+\.[^/]+$/.test(href)
if (isShortDomain) {
props.href = `https://${href}`
}

// Check if the link has alias text
if (
node.children.length === 1 &&
node.children[0].type === "text" &&
node.children[0].value !== dest
) {
classes.push("alias")
}
props.className = classes
// rewrite all links
let dest = props.href as RelativeURL
const classes = (props.className ?? []) as string[]
const isExternal = isAbsoluteUrl(dest) || isShortDomain
classes.push(isExternal ? "external" : "internal")

if (isExternal && opts.openLinksInNewTab) {
props.target = "_blank"
props.rel = "noopener noreferrer"
}
// Add external-icon class for specific domains
const domainMatch = dest.match(/(?:https?:\/\/)?(?:www\.)?([^\/]+)/)
const domain = domainMatch ? domainMatch[1] : dest

// don't process external links or intra-document anchors
const isInternal = !(isAbsoluteUrl(dest) || dest.startsWith("#"))
if (isInternal) {
dest = node.properties.href = transformLink(
file.data.slug!,
dest,
transformOptions,
)

// url.resolve is considered legacy
// WHATWG equivalent https://nodejs.dev/en/api/v18/url/#urlresolvefrom-to
const url = new URL(dest, "https://base.com/" + stripSlashes(curSlug, true))
const canonicalDest = url.pathname
let [destCanonical, _destAnchor] = splitAnchor(canonicalDest)
if (destCanonical.endsWith("/")) {
destCanonical += "index"
}

// need to decodeURIComponent here as WHATWG URL percent-encodes everything
const full = decodeURIComponent(stripSlashes(destCanonical, true)) as FullSlug
const simple = simplifySlug(full)
outgoing.add(simple)
node.properties["data-slug"] = full
}
// Check if it's an RSS feed
const isRSSFeed = dest.includes("index.xml")
if (isRSSFeed) {
classes.push("external")
}
// Check if the link has alias text
if (
node.children.length === 1 &&
node.children[0].type === "text" &&
node.children[0].value !== dest
) {
// Add the 'alias' class if the text content is not the same as the href
classes.push("alias")
}
node.properties.className = classes

// rewrite link internals if prettylinks is on
if (
opts.prettyLinks &&
isInternal &&
node.children.length === 1 &&
node.children[0].type === "text" &&
!node.children[0].value.startsWith("#")
) {
node.children[0].value = path.basename(node.children[0].value)
if (isExternal && opts.openLinksInNewTab) {
node.properties.target = "_blank"
node.properties.rel = "noopener noreferrer"
}

// don't process external links or intra-document anchors
const isInternal = !(isAbsoluteUrl(dest) || dest.startsWith("#"))
if (isInternal) {
dest = node.properties.href = transformLink(
file.data.slug!,
dest,
transformOptions,
)

// url.resolve is considered legacy
// WHATWG equivalent https://nodejs.dev/en/api/v18/url/#urlresolvefrom-to
const url = new URL(dest, "https://base.com/" + stripSlashes(curSlug, true))
const canonicalDest = url.pathname
let [destCanonical, _destAnchor] = splitAnchor(canonicalDest)
if (destCanonical.endsWith("/")) {
destCanonical += "index"
}

// need to decodeURIComponent here as WHATWG URL percent-encodes everything
const full = decodeURIComponent(stripSlashes(destCanonical, true)) as FullSlug
const simple = simplifySlug(full)
outgoing.add(simple)
node.properties["data-slug"] = full
}

// rewrite link internals if prettylinks is on
if (
opts.prettyLinks &&
isInternal &&
node.children.length === 1 &&
node.children[0].type === "text" &&
!node.children[0].value.startsWith("#")
) {
node.children[0].value = path.basename(node.children[0].value)
}
}

Expand Down
Loading

0 comments on commit 81e0989

Please sign in to comment.