Compare commits
No commits in common. "a2d594b393982b2506f292e314c3451441b82b06" and "27201e2be8fb7c58ce159a12f25e4b3a3deffcd7" have entirely different histories.
a2d594b393
...
27201e2be8
4 changed files with 1 additions and 293 deletions
|
@ -34,10 +34,6 @@ There are other easy ways to support the project and show your appreciation, whi
|
|||
- Environment details (browser, OS, etc.)
|
||||
- For feature requests, describe the feature and why you think it would be useful
|
||||
|
||||
For the language of the issue, please use English or Chinese. Both are OK, but using English is preferred as it allows more people to understand the issue and help with it.
|
||||
|
||||
If you are not comfortable with either, you can still use your native language (or use a translator), but I may not be able to fully understand it.
|
||||
|
||||
## Development
|
||||
### Development Environment
|
||||
This project is built using Astro, requiring a Node.js (v22.15.1 (lts) is recommended) environment.
|
||||
|
@ -92,11 +88,6 @@ Now you already made changes to the code and want to commit it. please:
|
|||
- Link any related issues in the PR description (if any)
|
||||
- Provide a clear description of the changes
|
||||
|
||||
For the language of the pull request message, please use English or Chinese. Both are OK, but using English is preferred as it allows more people to understand the issue and help with it.
|
||||
|
||||
If you are not comfortable with either, you can still use your native language (or use a translator), but I may not be able to fully understand it.
|
||||
|
||||
|
||||
## Code of Conduct
|
||||
Please be respectful and considerate of others when contributing. I want to maintain a welcoming and inclusive environment for everyone.
|
||||
|
||||
|
|
|
@ -1,239 +0,0 @@
|
|||
---
|
||||
interface Props {
|
||||
url: string;
|
||||
showArchive?: boolean;
|
||||
title?: string;
|
||||
description?: string;
|
||||
siteName?: string;
|
||||
}
|
||||
|
||||
const { url, showArchive = true} = Astro.props;
|
||||
|
||||
const siteMetadata = {
|
||||
title: Astro.props.title || '',
|
||||
description: Astro.props.description || '',
|
||||
siteName: Astro.props.siteName || '',
|
||||
image: '',
|
||||
domain: new URL(url).hostname || ''
|
||||
};
|
||||
|
||||
// Get metadata from the URL
|
||||
async function fetchMetadata(url: string) {
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'User-Agent': 'Mozilla/5.0 (compatible; LinkCard/1.0)'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}`);
|
||||
}
|
||||
|
||||
const html = await response.text();
|
||||
|
||||
// 提取元数据
|
||||
const titleMatch = html.match(/<title[^>]*>([^<]+)<\/title>/i);
|
||||
const descriptionMatch = html.match(/<meta[^>]+name=["']description["'][^>]+content=["']([^"']+)["']/i) ||
|
||||
html.match(/<meta[^>]+property=["']og:description["'][^>]+content=["']([^"']+)["']/i);
|
||||
const imageMatch = html.match(/<meta[^>]+property=["']og:image["'][^>]+content=["']([^"']+)["']/i) ||
|
||||
html.match(/<meta[^>]+name=["']twitter:image["'][^>]+content=["']([^"']+)["']/i);
|
||||
const siteNameMatch = html.match(/<meta[^>]+property=["']og:site_name["'][^>]+content=["']([^"']+)["']/i);
|
||||
|
||||
return {
|
||||
title: titleMatch?.[1]?.trim() || new URL(url).hostname,
|
||||
description: descriptionMatch?.[1]?.trim() || '',
|
||||
image: imageMatch?.[1]?.trim() || '',
|
||||
siteName: siteNameMatch?.[1]?.trim() || new URL(url).hostname,
|
||||
domain: new URL(url).hostname
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(`Failed to fetch metadata for ${url}:`, error);
|
||||
const domain = new URL(url).hostname;
|
||||
return {
|
||||
title: domain,
|
||||
description: '',
|
||||
image: '',
|
||||
siteName: domain,
|
||||
domain
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the URL is archived on the Wayback Machine at the build time
|
||||
async function checkArchive(url: string) {
|
||||
try {
|
||||
const archiveUrl = `https://archive.org/wayback/available?url=${encodeURIComponent(url)}`;
|
||||
const response = await fetch(archiveUrl);
|
||||
const data = await response.json();
|
||||
|
||||
if (data.archived_snapshots?.closest?.available) {
|
||||
return data.archived_snapshots.closest.url;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn(`Failed to check archive for ${url}:`, error);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// extract metadata and archive URL
|
||||
const metadata = Astro.props.title ? siteMetadata : await fetchMetadata(url);
|
||||
const archiveUrl = showArchive ? await checkArchive(url) : null;
|
||||
---
|
||||
|
||||
<div class="link-card">
|
||||
<a href={url} target="_blank" rel="noopener noreferrer" class="link-card__main">
|
||||
{metadata.image && (
|
||||
<div class="link-card__image">
|
||||
<img src={metadata.image} alt={metadata.title} loading="lazy" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="link-card__content">
|
||||
<div class="link-card__header">
|
||||
<h3 class="link-card__title">{metadata.title}</h3>
|
||||
<span class="link-card__domain">{metadata.domain}</span>
|
||||
</div>
|
||||
|
||||
{metadata.description && (
|
||||
<p class="link-card__description">{metadata.description}</p>
|
||||
)}
|
||||
|
||||
{metadata.siteName && <div class="link-card__footer">
|
||||
<span class="link-card__site-name">{metadata.siteName}</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</a>
|
||||
|
||||
{showArchive && archiveUrl && (
|
||||
<div class="link-card__archive">
|
||||
<a href={archiveUrl} target="_blank" rel="noopener noreferrer" title="View archived version">
|
||||
View archived version
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.link-card {
|
||||
border: 1px solid var(--border-color, #e1e5e9);
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.link-card__main {
|
||||
display: flex;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.link-card__image {
|
||||
flex-shrink: 0;
|
||||
width: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.link-card__image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.link-card__content {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.link-card__header {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.link-card__title {
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 4px 0;
|
||||
line-height: 1.3;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
color: var(--header-color);
|
||||
}
|
||||
|
||||
.link-card__domain {
|
||||
font-size: 0.85rem;
|
||||
color: var(--secondary-text-color);
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
.link-card__description {
|
||||
font-size: 0.9rem;
|
||||
color: var(--text-color);
|
||||
line-height: 1.4;
|
||||
margin: 8px 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.link-card__footer {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.link-card__site-name {
|
||||
font-size: 0.8rem;
|
||||
color: #888;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.link-card__archive {
|
||||
border-top: 1px solid var(--border-color, #e1e5e9);
|
||||
padding: 8px 16px;
|
||||
}
|
||||
|
||||
.link-card__archive a {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
font-size: 0.8rem;
|
||||
color: var(--secondary-text-color);
|
||||
text-decoration: none;
|
||||
transition: color 0.2s ease;
|
||||
}
|
||||
|
||||
/* mobile devices */
|
||||
@media (max-width: 768px) {
|
||||
.link-card__main {
|
||||
flex-direction: column;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.link-card__image {
|
||||
width: 100%;
|
||||
height: 160px;
|
||||
}
|
||||
|
||||
.link-card__content {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.link-card__title {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Image not exist*/
|
||||
.link-card__main:not(:has(.link-card__image)) .link-card__content {
|
||||
padding: 20px;
|
||||
}
|
||||
</style>
|
|
@ -5,16 +5,8 @@ description: "Sample article showcasing basic Markdown syntax and formatting for
|
|||
tags: ["markdown", "css", "html", "sample"]
|
||||
---
|
||||
import Callout from '/src/components/shortcodes/Callout.astro';
|
||||
import LinkCard from '/src/components/shortcodes/LinkCard.astro';
|
||||
import Spoiler from '/src/components/shortcodes/Spoiler.astro';
|
||||
|
||||
This article offers a sample of basic and extended Markdown formatting that can be used, also it shows how some basic HTML elements are decorated.
|
||||
## Markdown in Astro
|
||||
> [Markdown](https://daringfireball.net/projects/markdown/) is commonly used to author text-heavy content like blog posts and documentation. Astro includes built-in support for Markdown files that can also include [frontmatter YAML](https://dev.to/paulasantamaria/introduction-to-yaml-125f) (or [TOML](https://toml.io)) to define custom properties such as a title, description, and tags.
|
||||
>
|
||||
> In Astro, you can author content in [GitHub Flavored Markdown](https://github.github.com/gfm/), then render it in `.astro` components. This combines a familiar writing format designed for content with the flexibility of Astro’s component syntax and architecture.
|
||||
|
||||
source: [Markdown in Astro | Docs](https://docs.astro.build/en/guides/markdown-content/)
|
||||
|
||||
## Theme Specifics
|
||||
This theme came with a set of shortcodes that can be used to enhance the Markdown experience. These shortcodes are located in the `/src/components/shortcodes` directory and can be used to add custom functionality or styling to your Markdown content.
|
||||
|
@ -28,30 +20,6 @@ your content here...
|
|||
</ExampleShortcode>
|
||||
```
|
||||
|
||||
### Spoiler
|
||||
Inspired by the spoiler in [Moegirl wiki](https://zh.moegirl.org.cn/Mainpage), you can use the `Spoiler` component to hide content that you want to reveal later. This is useful for spoilers in game plots , movies plots, or any other content where you want to keep certain information hidden until the user chooses to reveal it.
|
||||
|
||||
To reveal the content, readers can hover over the text to reveal it.
|
||||
<Spoiler>
|
||||
A hot take: the theme is done through what is called 'vibe coding'.
|
||||
</Spoiler>
|
||||
|
||||
```mdx
|
||||
<Spoiler>
|
||||
A hot take: the theme is done through what is called 'vibe coding'.
|
||||
</Spoiler>
|
||||
```
|
||||
You can also display a 'tip' for the reader when hovered:
|
||||
<Spoiler tip='attention is all you need'>
|
||||
A hot take: the theme is done through what is called 'vibe coding'.
|
||||
</Spoiler>
|
||||
|
||||
```mdx
|
||||
<Spoiler tip='attention is all you need'>
|
||||
A hot take: the theme is done through what is called 'vibe coding'.
|
||||
</Spoiler>
|
||||
```
|
||||
|
||||
### Callouts
|
||||
You can use callouts to highlight important information or warnings in your content. Callouts are styled boxes that draw attention to specific parts of the text.
|
||||
<Callout icon='💁' type="info">
|
||||
|
@ -75,18 +43,7 @@ You can use callouts to highlight important information or warnings in your cont
|
|||
This is an error callout. It should be used to indicate critical issues that need immediate attention.
|
||||
</Callout>
|
||||
```
|
||||
### LinkCard
|
||||
You can use the `LinkCard` component to create cards that link to external resources or pages. This is useful for showcasing projects, documentation, or any other relevant links.
|
||||
|
||||
<LinkCard url="https://astro.build"/>
|
||||
```mdx
|
||||
<LinkCard url="https://astro.build"/>
|
||||
```
|
||||
<Callout type="warning">
|
||||
On a machine with bad network, this will significantly increase build time when no other params are passed to the component.
|
||||
</Callout>
|
||||
Or to customize the card further with a title and description:
|
||||
<LinkCard url="https://www.bilibili.com/video/BV1PC4y1L7mq/" title="Don't check the description" description="Don't click on the link" />
|
||||
|
||||
## Headings
|
||||
|
||||
|
@ -128,7 +85,7 @@ The blockquote element represents content that is quoted from another source, op
|
|||
|
||||
## Tables
|
||||
|
||||
Tables aren't part of the core Markdown spec, but Astro supports supports them out-of-the-box.
|
||||
Tables aren't part of the core Markdown spec, but Hugo supports supports them out-of-the-box.
|
||||
|
||||
| Name | Age |
|
||||
| ----- | --- |
|
||||
|
|
|
@ -223,7 +223,6 @@ div.content {
|
|||
|
||||
pre {
|
||||
padding: 1rem;
|
||||
margin: 1rem auto;
|
||||
}
|
||||
/* Highlighted Code Blocks */
|
||||
pre.astro-code,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue