mirror of
https://github.com/lbr77/blog-astro.git
synced 2026-04-08 16:11:56 +00:00
format
This commit is contained in:
@@ -1,17 +1,16 @@
|
||||
|
||||
<p class="text-xs uppercase text-muted-foreground">comment</p>
|
||||
<h3 class="text-xl font-semibold mb-3">留言 / 评论</h3>
|
||||
<p class="text-muted-foreground text-xs uppercase">comment</p>
|
||||
<h3 class="mb-3 text-xl font-semibold">留言 / 评论</h3>
|
||||
<div id="tcomment" class="space-y-2">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
如果暂时没有看到评论,请点击下方按钮重新加载。
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="inline-flex items-center justify-center rounded-md border border-input bg-background px-3 py-1.5 text-sm font-medium shadow-sm transition-colors hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||
onclick="window.runTwikooComments && window.runTwikooComments()"
|
||||
>
|
||||
重新加载评论
|
||||
</button>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
如果暂时没有看到评论,请点击下方按钮重新加载。
|
||||
</p>
|
||||
<button
|
||||
type="button"
|
||||
class="border-input bg-background hover:bg-accent hover:text-accent-foreground focus-visible:ring-ring inline-flex items-center justify-center rounded-md border px-3 py-1.5 text-sm font-medium shadow-sm transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none"
|
||||
onclick="window.runTwikooComments && window.runTwikooComments()"
|
||||
>
|
||||
重新加载评论
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script src="/js/twikoo-loader.js" defer></script>
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
---
|
||||
import type * as interfaces from '../lib/interfaces.ts'
|
||||
import Bookmark from './notion/Bookmark.astro'
|
||||
import BulletedListItems from './notion/BulletedListItems.astro'
|
||||
import Callout from './notion/Callout.astro'
|
||||
import Code from './notion/Code.astro'
|
||||
import ColumnList from './notion/ColumnList.astro'
|
||||
import Divider from './notion/Divider.astro'
|
||||
import Bookmark from './notion/Bookmark.astro'
|
||||
import Embed from './notion/Embed.astro'
|
||||
import Equation from './notion/Equation.astro'
|
||||
import File from './notion/File.astro'
|
||||
import Heading1 from './notion/Heading1.astro'
|
||||
import Heading2 from './notion/Heading2.astro'
|
||||
import Heading3 from './notion/Heading3.astro'
|
||||
import Image from './notion/Image.astro'
|
||||
import LinkToPage from './notion/LinkToPage.astro'
|
||||
import Equation from './notion/Equation.astro'
|
||||
import NumberedListItems from './notion/NumberedListItems.astro'
|
||||
import Paragraph from './notion/Paragraph.astro'
|
||||
import Quote from './notion/Quote.astro'
|
||||
@@ -22,7 +23,6 @@ import TableOfContents from './notion/TableOfContents.astro'
|
||||
import ToDo from './notion/ToDo.astro'
|
||||
import Toggle from './notion/Toggle.astro'
|
||||
import Video from './notion/Video.astro'
|
||||
import type * as interfaces from '../lib/interfaces.ts'
|
||||
|
||||
export interface Props {
|
||||
blocks: interfaces.Block[]
|
||||
@@ -52,19 +52,11 @@ const {
|
||||
return <Heading3 block={block} headings={headings} />
|
||||
case 'bulleted_list':
|
||||
return (
|
||||
<BulletedListItems
|
||||
block={block}
|
||||
level={level}
|
||||
headings={headings}
|
||||
/>
|
||||
<BulletedListItems block={block} level={level} headings={headings} />
|
||||
)
|
||||
case 'numbered_list':
|
||||
return (
|
||||
<NumberedListItems
|
||||
block={block}
|
||||
level={level}
|
||||
headings={headings}
|
||||
/>
|
||||
<NumberedListItems block={block} level={level} headings={headings} />
|
||||
)
|
||||
case 'to_do':
|
||||
return <ToDo block={block} headings={headings} />
|
||||
|
||||
@@ -32,12 +32,16 @@ const canonicalUrl = Astro.url
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={ogImageUrl} />
|
||||
<meta property="og:image:alt" content={title} />
|
||||
{ogImageWidth && (
|
||||
<meta property="og:image:width" content={String(ogImageWidth)} />
|
||||
)}
|
||||
{ogImageHeight && (
|
||||
<meta property="og:image:height" content={String(ogImageHeight)} />
|
||||
)}
|
||||
{
|
||||
ogImageWidth && (
|
||||
<meta property="og:image:width" content={String(ogImageWidth)} />
|
||||
)
|
||||
}
|
||||
{
|
||||
ogImageHeight && (
|
||||
<meta property="og:image:height" content={String(ogImageHeight)} />
|
||||
)
|
||||
}
|
||||
{ogImageType && <meta property="og:image:type" content={ogImageType} />}
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:locale" content={SITE.locale} />
|
||||
|
||||
@@ -36,19 +36,26 @@ const canonicalUrl = Astro.url
|
||||
<meta property="og:description" content={description} />
|
||||
<meta property="og:image" content={ogImage.url} />
|
||||
<meta property="og:image:alt" content={title} />
|
||||
{ogImage.width && (
|
||||
<meta property="og:image:width" content={String(ogImage.width)} />
|
||||
)}
|
||||
{ogImage.height && (
|
||||
<meta property="og:image:height" content={String(ogImage.height)} />
|
||||
)}
|
||||
{
|
||||
ogImage.width && (
|
||||
<meta property="og:image:width" content={String(ogImage.width)} />
|
||||
)
|
||||
}
|
||||
{
|
||||
ogImage.height && (
|
||||
<meta property="og:image:height" content={String(ogImage.height)} />
|
||||
)
|
||||
}
|
||||
{ogImage.type && <meta property="og:image:type" content={ogImage.type} />}
|
||||
<meta property="og:type" content="article" />
|
||||
<meta property="og:locale" content={SITE.locale} />
|
||||
<meta property="og:site_name" content={SITE.title} />
|
||||
<meta property="og:url" content={canonicalUrl} />
|
||||
<meta property="og:author" content={author} />
|
||||
<meta property="article:published_time" content={post.data.date.toISOString()} />
|
||||
<meta
|
||||
property="article:published_time"
|
||||
content={post.data.date.toISOString()}
|
||||
/>
|
||||
|
||||
<meta name="twitter:title" content={title} />
|
||||
<meta name="twitter:description" content={description} />
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import {
|
||||
getCombinedReadingTime,
|
||||
getParentId,
|
||||
getParentPost,
|
||||
getPostById,
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import Link from '@/components/Link.astro'
|
||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||
import {
|
||||
getCombinedReadingTime,
|
||||
getParentId,
|
||||
getParentPost,
|
||||
getPostById,
|
||||
|
||||
@@ -78,8 +78,9 @@ const { headings } = Astro.props
|
||||
>
|
||||
<a
|
||||
href={`#${heading.slug}`}
|
||||
class="mobile-toc-item underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
class="mobile-toc-item truncate underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
data-heading-id={heading.slug}
|
||||
title={heading.text}
|
||||
>
|
||||
{heading.text}
|
||||
</a>
|
||||
|
||||
@@ -63,8 +63,9 @@ const parentId = isCurrentSubpost ? getParentId(currentPostId) : currentPostId
|
||||
? `/blog/${parentId}#${heading.slug}`
|
||||
: `#${heading.slug}`
|
||||
}
|
||||
class="marker:text-foreground/30 list-none underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
class="marker:text-foreground/30 list-none truncate underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
data-heading-link={heading.slug}
|
||||
title={heading.text}
|
||||
>
|
||||
{heading.text}
|
||||
</a>
|
||||
@@ -93,12 +94,13 @@ const parentId = isCurrentSubpost ? getParentId(currentPostId) : currentPostId
|
||||
? '#'
|
||||
: `/blog/${section.subpostId}`
|
||||
}
|
||||
class="marker:text-foreground/30 list-none underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
class="marker:text-foreground/30 list-none truncate underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
data-heading-link={
|
||||
section.subpostId === currentPostId
|
||||
? 'top'
|
||||
: `${section.subpostId}-top`
|
||||
}
|
||||
title={section.title}
|
||||
>
|
||||
{section.title}
|
||||
</a>
|
||||
@@ -119,12 +121,13 @@ const parentId = isCurrentSubpost ? getParentId(currentPostId) : currentPostId
|
||||
? `#${heading.slug}`
|
||||
: `/blog/${section.subpostId}#${heading.slug}`
|
||||
}
|
||||
class="marker:text-foreground/30 hover:text-foreground/60 list-none underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
class="marker:text-foreground/30 hover:text-foreground/60 list-none truncate underline decoration-transparent underline-offset-[3px] transition-colors duration-200 hover:decoration-inherit"
|
||||
data-heading-link={
|
||||
section.subpostId === currentPostId
|
||||
? heading.slug
|
||||
: `${section.subpostId}-${heading.slug}`
|
||||
}
|
||||
title={heading.text}
|
||||
>
|
||||
{heading.text}
|
||||
</a>
|
||||
|
||||
@@ -16,7 +16,7 @@ import { Icon } from 'astro-icon/components'
|
||||
</Button>
|
||||
|
||||
<script is:inline data-astro-rerun>
|
||||
(() => {
|
||||
;(() => {
|
||||
const theme = (() => {
|
||||
const stored = localStorage?.getItem('theme') ?? ''
|
||||
if (['dark', 'light'].includes(stored)) return stored
|
||||
@@ -83,9 +83,8 @@ import { Icon } from 'astro-icon/components'
|
||||
|
||||
const handleToggleClick = (event) => {
|
||||
const element = document.documentElement
|
||||
const currentTheme = element.getAttribute('data-theme') === 'dark'
|
||||
? 'dark'
|
||||
: 'light'
|
||||
const currentTheme =
|
||||
element.getAttribute('data-theme') === 'dark' ? 'dark' : 'light'
|
||||
const newTheme = currentTheme === 'dark' ? 'light' : 'dark'
|
||||
|
||||
const prefersReducedMotion = window.matchMedia(
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import type * as interfaces from '../../lib/interfaces.ts'
|
||||
import { isAmazonURL, isGitHubURL } from '../../lib/blog-helpers.ts'
|
||||
import GithubLinkPreview from './GitHubLinkPreview.astro'
|
||||
import type * as interfaces from '../../lib/interfaces.ts'
|
||||
import Caption from './Caption.astro'
|
||||
import GithubLinkPreview from './GitHubLinkPreview.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
@@ -50,7 +50,6 @@ try {
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
@@ -80,7 +79,9 @@ try {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
transition: background-color 160ms ease, border-color 160ms ease;
|
||||
transition:
|
||||
background-color 160ms ease,
|
||||
border-color 160ms ease;
|
||||
}
|
||||
.bookmark > a:hover {
|
||||
background: var(--notion-surface-strong);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import '../../styles/notion-color.css'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
@@ -21,7 +21,8 @@ const listTypes = ['disc', 'circle', 'square']
|
||||
{
|
||||
items
|
||||
.filter(
|
||||
(b: interfaces.Block) => b.Type === 'bulleted_list_item' && b.BulletedListItem,
|
||||
(b: interfaces.Block) =>
|
||||
b.Type === 'bulleted_list_item' && b.BulletedListItem,
|
||||
)
|
||||
.map((b: interfaces.Block) => {
|
||||
const item = b.BulletedListItem
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import '../../styles/notion-color.css'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
---
|
||||
export interface Props {
|
||||
url: URL
|
||||
}
|
||||
const { url } = Astro.props
|
||||
const param = url.searchParams.get('ctz')
|
||||
---
|
||||
|
||||
<div class="circuit-simulator-applet-wrapper">
|
||||
<iframe
|
||||
src={`https://www.falstad.com/circuit/circuitjs.html?ctz=${param}`}
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.circuit-simulator-applet-wrapper {
|
||||
margin: 0.4rem auto;
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
}
|
||||
.circuit-simulator-applet-wrapper iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid var(--fg);
|
||||
}
|
||||
</style>
|
||||
---
|
||||
export interface Props {
|
||||
url: URL
|
||||
}
|
||||
const { url } = Astro.props
|
||||
const param = url.searchParams.get('ctz')
|
||||
---
|
||||
|
||||
<div class="circuit-simulator-applet-wrapper">
|
||||
<iframe
|
||||
src={`https://www.falstad.com/circuit/circuitjs.html?ctz=${param}`}
|
||||
allowfullscreen></iframe>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.circuit-simulator-applet-wrapper {
|
||||
margin: 0.4rem auto;
|
||||
width: 100%;
|
||||
aspect-ratio: 4 / 3;
|
||||
}
|
||||
.circuit-simulator-applet-wrapper iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid var(--fg);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -40,9 +40,9 @@ const displayLanguage =
|
||||
<figure class="code mac">
|
||||
<div class="chrome">
|
||||
<div class="dots">
|
||||
<span class="dot dot-red" />
|
||||
<span class="dot dot-amber" />
|
||||
<span class="dot dot-green" />
|
||||
<span class="dot dot-red"></span>
|
||||
<span class="dot dot-amber"></span>
|
||||
<span class="dot dot-green"></span>
|
||||
</div>
|
||||
<div class="meta">
|
||||
<span class="lang">{displayLanguage}</span>
|
||||
@@ -76,7 +76,8 @@ const displayLanguage =
|
||||
.then(() => {
|
||||
const originalText = target.innerText
|
||||
|
||||
target.innerText = target.getAttribute('data-done-text') || target.innerText
|
||||
target.innerText =
|
||||
target.getAttribute('data-done-text') || target.innerText
|
||||
|
||||
setTimeout(() => {
|
||||
target.innerText = originalText
|
||||
@@ -100,7 +101,8 @@ const displayLanguage =
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
border: 1px solid color-mix(in oklab, var(--border) 70%, transparent);
|
||||
background: linear-gradient(
|
||||
background:
|
||||
linear-gradient(
|
||||
180deg,
|
||||
color-mix(in oklab, var(--muted) 12%, transparent),
|
||||
transparent 30%
|
||||
@@ -171,7 +173,9 @@ const displayLanguage =
|
||||
line-height: 1.2rem;
|
||||
cursor: pointer;
|
||||
font-size: 0.75rem;
|
||||
transition: background-color 120ms ease, transform 120ms ease;
|
||||
transition:
|
||||
background-color 120ms ease,
|
||||
transform 120ms ease;
|
||||
}
|
||||
|
||||
.code button.copy:hover {
|
||||
@@ -199,7 +203,11 @@ const displayLanguage =
|
||||
background: transparent;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: color-mix(in oklab, var(--muted-foreground) 60%, transparent)
|
||||
scrollbar-color: color-mix(
|
||||
in oklab,
|
||||
var(--muted-foreground) 60%,
|
||||
transparent
|
||||
)
|
||||
transparent;
|
||||
}
|
||||
|
||||
@@ -240,6 +248,15 @@ const displayLanguage =
|
||||
}
|
||||
|
||||
.lang {
|
||||
font-family: var(--font-mono, 'SFMono-Regular', Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace);
|
||||
font-family: var(
|
||||
--font-mono,
|
||||
'SFMono-Regular',
|
||||
Menlo,
|
||||
Monaco,
|
||||
Consolas,
|
||||
'Liberation Mono',
|
||||
'Courier New',
|
||||
monospace
|
||||
);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -31,7 +31,7 @@ if (!block.ColumnList) {
|
||||
box-sizing: border-box;
|
||||
margin: 1rem auto;
|
||||
gap: 0 1rem;
|
||||
}
|
||||
}
|
||||
.column-list > div {
|
||||
flex: 1 1 180px;
|
||||
min-width: 0;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
<hr class="divider" />
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import {
|
||||
isTweetURL,
|
||||
isTikTokURL,
|
||||
isCircuitSimulatorAppletURL,
|
||||
isCodePenURL,
|
||||
isInstagramURL,
|
||||
isPinterestURL,
|
||||
isCodePenURL,
|
||||
isCircuitSimulatorAppletURL,
|
||||
isTikTokURL,
|
||||
isTweetURL,
|
||||
} from '../../lib/blog-helpers.ts'
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import Bookmark from './Bookmark.astro'
|
||||
import TweetEmbed from './TweetEmbed.astro'
|
||||
import TikTokEmbed from './TikTokEmbed.astro'
|
||||
import CircuitSimulatorAppletEmbed from './CircuitSimulatorAppletEmbed.astro'
|
||||
import CodePenEmbed from './CodePenEmbed.astro'
|
||||
import InstagramEmbed from './InstagramEmbed.astro'
|
||||
import PinterestEmbed from './PinterestEmbed.astro'
|
||||
import CodePenEmbed from './CodePenEmbed.astro'
|
||||
import CircuitSimulatorAppletEmbed from './CircuitSimulatorAppletEmbed.astro'
|
||||
import TikTokEmbed from './TikTokEmbed.astro'
|
||||
import TweetEmbed from './TweetEmbed.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces'
|
||||
import { filePath } from '../../lib/blog-helpers'
|
||||
import * as interfaces from '../../lib/interfaces'
|
||||
import Caption from './Caption.astro'
|
||||
|
||||
export interface Props {
|
||||
@@ -26,8 +26,7 @@ try {
|
||||
}
|
||||
|
||||
const filename =
|
||||
url &&
|
||||
decodeURIComponent(url.pathname.split('/').slice(-1)[0] || '')
|
||||
url && decodeURIComponent(url.pathname.split('/').slice(-1)[0] || '')
|
||||
---
|
||||
|
||||
<div class="file">
|
||||
|
||||
@@ -1,315 +1,315 @@
|
||||
---
|
||||
export interface Props {
|
||||
url: URL
|
||||
}
|
||||
|
||||
type EmbedStyle =
|
||||
| 'default'
|
||||
| 'a11y-dark'
|
||||
| 'a11y-light'
|
||||
| 'agate'
|
||||
| 'an-old-hope'
|
||||
| 'androidstudio'
|
||||
| 'arduino-light'
|
||||
| 'arta'
|
||||
| 'ascetic'
|
||||
| 'atom-one-dark'
|
||||
| 'atom-one-dark-reasonable'
|
||||
| 'atom-one-light'
|
||||
| 'brown-paper'
|
||||
| 'codepen-embed'
|
||||
| 'color-brewer'
|
||||
| 'dark'
|
||||
| 'devibeans'
|
||||
| 'docco'
|
||||
| 'far'
|
||||
| 'felipec'
|
||||
| 'foundation'
|
||||
| 'github'
|
||||
| 'github-dark'
|
||||
| 'github-dark-dimmed'
|
||||
| 'gml'
|
||||
| 'googlecode'
|
||||
| 'gradient-dark'
|
||||
| 'gradient-light'
|
||||
| 'grayscale'
|
||||
| 'hybrid'
|
||||
| 'idea'
|
||||
| 'intellij-light'
|
||||
| 'ir-black'
|
||||
| 'isbl-editor-dark'
|
||||
| 'isbl-editor-light'
|
||||
| 'kimbie-dark'
|
||||
| 'kimbie-light'
|
||||
| 'lightfair'
|
||||
| 'lioshi'
|
||||
| 'magula'
|
||||
| 'mono-blue'
|
||||
| 'monokai'
|
||||
| 'monokai-sublime'
|
||||
| 'night-owl'
|
||||
| 'nnfx-dark'
|
||||
| 'nnfx-light'
|
||||
| 'nord'
|
||||
| 'obsidian'
|
||||
| 'panda-syntax-dark'
|
||||
| 'panda-syntax-light'
|
||||
| 'paraiso-dark'
|
||||
| 'paraiso-light'
|
||||
| 'pojoaque'
|
||||
| 'purebasic'
|
||||
| 'qtcreator-dark'
|
||||
| 'qtcreator-light'
|
||||
| 'rainbow'
|
||||
| 'routeros'
|
||||
| 'school-book'
|
||||
| 'shades-of-purple'
|
||||
| 'srcery'
|
||||
| 'stackoverflow-dark'
|
||||
| 'stackoverflow-light'
|
||||
| 'sunburst'
|
||||
| 'tokyo-night-dark'
|
||||
| 'tokyo-night-light'
|
||||
| 'tomorrow-night-blue'
|
||||
| 'tomorrow-night-bright'
|
||||
| 'vs'
|
||||
| 'vs2015'
|
||||
| 'xcode'
|
||||
| 'xt256'
|
||||
| 'base16/3024'
|
||||
| 'base16/apathy'
|
||||
| 'base16/apprentice'
|
||||
| 'base16/ashes'
|
||||
| 'base16/atelier-cave'
|
||||
| 'base16/atelier-cave-light'
|
||||
| 'base16/atelier-dune'
|
||||
| 'base16/atelier-dune-light'
|
||||
| 'base16/atelier-estuary'
|
||||
| 'base16/atelier-estuary-light'
|
||||
| 'base16/atelier-forest'
|
||||
| 'base16/atelier-forest-light'
|
||||
| 'base16/atelier-heath'
|
||||
| 'base16/atelier-heath-light'
|
||||
| 'base16/atelier-lakeside'
|
||||
| 'base16/atelier-lakeside-light'
|
||||
| 'base16/atelier-plateau'
|
||||
| 'base16/atelier-plateau-light'
|
||||
| 'base16/atelier-savanna'
|
||||
| 'base16/atelier-savanna-light'
|
||||
| 'base16/atelier-seaside'
|
||||
| 'base16/atelier-seaside-light'
|
||||
| 'base16/atelier-sulphurpool'
|
||||
| 'base16/atelier-sulphurpool-light'
|
||||
| 'base16/atlas'
|
||||
| 'base16/bespin'
|
||||
| 'base16/black-metal'
|
||||
| 'base16/black-metal-bathory'
|
||||
| 'base16/black-metal-burzum'
|
||||
| 'base16/black-metal-dark-funeral'
|
||||
| 'base16/black-metal-gorgoroth'
|
||||
| 'base16/black-metal-immortal'
|
||||
| 'base16/black-metal-khold'
|
||||
| 'base16/black-metal-marduk'
|
||||
| 'base16/black-metal-mayhem'
|
||||
| 'base16/black-metal-nile'
|
||||
| 'base16/black-metal-venom'
|
||||
| 'base16/brewer'
|
||||
| 'base16/bright'
|
||||
| 'base16/brogrammer'
|
||||
| 'base16/brush-trees'
|
||||
| 'base16/brush-trees-dark'
|
||||
| 'base16/chalk'
|
||||
| 'base16/circus'
|
||||
| 'base16/classic-dark'
|
||||
| 'base16/classic-light'
|
||||
| 'base16/codeschool'
|
||||
| 'base16/colors'
|
||||
| 'base16/cupcake'
|
||||
| 'base16/cupertino'
|
||||
| 'base16/danqing'
|
||||
| 'base16/darcula'
|
||||
| 'base16/dark-violet'
|
||||
| 'base16/darkmoss'
|
||||
| 'base16/darktooth'
|
||||
| 'base16/decaf'
|
||||
| 'base16/default-dark'
|
||||
| 'base16/default-light'
|
||||
| 'base16/dirtysea'
|
||||
| 'base16/dracula'
|
||||
| 'base16/edge-dark'
|
||||
| 'base16/edge-light'
|
||||
| 'base16/eighties'
|
||||
| 'base16/embers'
|
||||
| 'base16/equilibrium-dark'
|
||||
| 'base16/equilibrium-gray-dark'
|
||||
| 'base16/equilibrium-gray-light'
|
||||
| 'base16/equilibrium-light'
|
||||
| 'base16/espresso'
|
||||
| 'base16/eva'
|
||||
| 'base16/eva-dim'
|
||||
| 'base16/flat'
|
||||
| 'base16/framer'
|
||||
| 'base16/fruit-soda'
|
||||
| 'base16/gigavolt'
|
||||
| 'base16/github'
|
||||
| 'base16/google-dark'
|
||||
| 'base16/google-light'
|
||||
| 'base16/grayscale-dark'
|
||||
| 'base16/grayscale-light'
|
||||
| 'base16/green-screen'
|
||||
| 'base16/gruvbox-dark-hard'
|
||||
| 'base16/gruvbox-dark-medium'
|
||||
| 'base16/gruvbox-dark-pale'
|
||||
| 'base16/gruvbox-dark-soft'
|
||||
| 'base16/gruvbox-light-hard'
|
||||
| 'base16/gruvbox-light-medium'
|
||||
| 'base16/gruvbox-light-soft'
|
||||
| 'base16/hardcore'
|
||||
| 'base16/harmonic16-dark'
|
||||
| 'base16/harmonic16-light'
|
||||
| 'base16/heetch-dark'
|
||||
| 'base16/heetch-light'
|
||||
| 'base16/helios'
|
||||
| 'base16/hopscotch'
|
||||
| 'base16/horizon-dark'
|
||||
| 'base16/horizon-light'
|
||||
| 'base16/humanoid-dark'
|
||||
| 'base16/humanoid-light'
|
||||
| 'base16/ia-dark'
|
||||
| 'base16/ia-light'
|
||||
| 'base16/icy-dark'
|
||||
| 'base16/ir-black'
|
||||
| 'base16/isotope'
|
||||
| 'base16/kimber'
|
||||
| 'base16/london-tube'
|
||||
| 'base16/macintosh'
|
||||
| 'base16/marrakesh'
|
||||
| 'base16/materia'
|
||||
| 'base16/material'
|
||||
| 'base16/material-darker'
|
||||
| 'base16/material-lighter'
|
||||
| 'base16/material-palenight'
|
||||
| 'base16/material-vivid'
|
||||
| 'base16/mellow-purple'
|
||||
| 'base16/mexico-light'
|
||||
| 'base16/mocha'
|
||||
| 'base16/monokai'
|
||||
| 'base16/nebula'
|
||||
| 'base16/nord'
|
||||
| 'base16/nova'
|
||||
| 'base16/ocean'
|
||||
| 'base16/oceanicnext'
|
||||
| 'base16/one-light'
|
||||
| 'base16/onedark'
|
||||
| 'base16/outrun-dark'
|
||||
| 'base16/papercolor-dark'
|
||||
| 'base16/papercolor-light'
|
||||
| 'base16/paraiso'
|
||||
| 'base16/pasque'
|
||||
| 'base16/phd'
|
||||
| 'base16/pico'
|
||||
| 'base16/pop'
|
||||
| 'base16/porple'
|
||||
| 'base16/qualia'
|
||||
| 'base16/railscasts'
|
||||
| 'base16/rebecca'
|
||||
| 'base16/ros-pine'
|
||||
| 'base16/ros-pine-dawn'
|
||||
| 'base16/ros-pine-moon'
|
||||
| 'base16/sagelight'
|
||||
| 'base16/sandcastle'
|
||||
| 'base16/seti-ui'
|
||||
| 'base16/shapeshifter'
|
||||
| 'base16/silk-dark'
|
||||
| 'base16/silk-light'
|
||||
| 'base16/snazzy'
|
||||
| 'base16/solar-flare'
|
||||
| 'base16/solar-flare-light'
|
||||
| 'base16/solarized-dark'
|
||||
| 'base16/solarized-light'
|
||||
| 'base16/spacemacs'
|
||||
| 'base16/summercamp'
|
||||
| 'base16/summerfruit-dark'
|
||||
| 'base16/summerfruit-light'
|
||||
| 'base16/synth-midnight-terminal-dark'
|
||||
| 'base16/synth-midnight-terminal-light'
|
||||
| 'base16/tango'
|
||||
| 'base16/tender'
|
||||
| 'base16/tomorrow'
|
||||
| 'base16/tomorrow-night'
|
||||
| 'base16/twilight'
|
||||
| 'base16/unikitty-dark'
|
||||
| 'base16/unikitty-light'
|
||||
| 'base16/vulcan'
|
||||
| 'base16/windows-10'
|
||||
| 'base16/windows-10-light'
|
||||
| 'base16/windows-95'
|
||||
| 'base16/windows-95-light'
|
||||
| 'base16/windows-high-contrast'
|
||||
| 'base16/windows-high-contrast-light'
|
||||
| 'base16/windows-nt'
|
||||
| 'base16/windows-nt-light'
|
||||
| 'base16/woodland'
|
||||
| 'base16/xcode-dusk'
|
||||
| 'base16/zenburn'
|
||||
|
||||
type EmbedParams = {
|
||||
style: EmbedStyle
|
||||
type: 'code' | 'markdown' | 'ipynb'
|
||||
showBorder?: 'on'
|
||||
showLineNumbers?: 'on'
|
||||
showFileMeta?: 'on'
|
||||
showFullPath?: 'on'
|
||||
showCopy?: 'on'
|
||||
fetchFromJsDelivr?: 'on'
|
||||
maxHeight?: number
|
||||
}
|
||||
|
||||
function buildEmbedQuery(params: EmbedParams) {
|
||||
return Object.entries(params)
|
||||
.filter(([, v]) => v !== undefined)
|
||||
.map(
|
||||
([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`
|
||||
)
|
||||
.join('&')
|
||||
}
|
||||
|
||||
/* Edit Params */
|
||||
const EMBED_PARAMS: EmbedParams = {
|
||||
style: 'github',
|
||||
type: 'code',
|
||||
showBorder: 'on',
|
||||
showLineNumbers: 'on',
|
||||
showFileMeta: 'on',
|
||||
showFullPath: 'on',
|
||||
showCopy: 'on',
|
||||
}
|
||||
|
||||
const { url } = Astro.props
|
||||
const PreviewURL = encodeURIComponent(url.toString())
|
||||
const embedQuery = buildEmbedQuery(EMBED_PARAMS)
|
||||
const embedScriptSrc = `https://emgithub.com/embed-v2.js?target=${PreviewURL}&${embedQuery}`
|
||||
---
|
||||
|
||||
<div class="github-link-preview-wrapper">
|
||||
<div class="github-link-preview">
|
||||
<script is:inline src={embedScriptSrc}></script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.github-link-preview-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
.github-link-preview {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
table {
|
||||
white-space: unset;
|
||||
}
|
||||
td::after {
|
||||
display: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
---
|
||||
export interface Props {
|
||||
url: URL
|
||||
}
|
||||
|
||||
type EmbedStyle =
|
||||
| 'default'
|
||||
| 'a11y-dark'
|
||||
| 'a11y-light'
|
||||
| 'agate'
|
||||
| 'an-old-hope'
|
||||
| 'androidstudio'
|
||||
| 'arduino-light'
|
||||
| 'arta'
|
||||
| 'ascetic'
|
||||
| 'atom-one-dark'
|
||||
| 'atom-one-dark-reasonable'
|
||||
| 'atom-one-light'
|
||||
| 'brown-paper'
|
||||
| 'codepen-embed'
|
||||
| 'color-brewer'
|
||||
| 'dark'
|
||||
| 'devibeans'
|
||||
| 'docco'
|
||||
| 'far'
|
||||
| 'felipec'
|
||||
| 'foundation'
|
||||
| 'github'
|
||||
| 'github-dark'
|
||||
| 'github-dark-dimmed'
|
||||
| 'gml'
|
||||
| 'googlecode'
|
||||
| 'gradient-dark'
|
||||
| 'gradient-light'
|
||||
| 'grayscale'
|
||||
| 'hybrid'
|
||||
| 'idea'
|
||||
| 'intellij-light'
|
||||
| 'ir-black'
|
||||
| 'isbl-editor-dark'
|
||||
| 'isbl-editor-light'
|
||||
| 'kimbie-dark'
|
||||
| 'kimbie-light'
|
||||
| 'lightfair'
|
||||
| 'lioshi'
|
||||
| 'magula'
|
||||
| 'mono-blue'
|
||||
| 'monokai'
|
||||
| 'monokai-sublime'
|
||||
| 'night-owl'
|
||||
| 'nnfx-dark'
|
||||
| 'nnfx-light'
|
||||
| 'nord'
|
||||
| 'obsidian'
|
||||
| 'panda-syntax-dark'
|
||||
| 'panda-syntax-light'
|
||||
| 'paraiso-dark'
|
||||
| 'paraiso-light'
|
||||
| 'pojoaque'
|
||||
| 'purebasic'
|
||||
| 'qtcreator-dark'
|
||||
| 'qtcreator-light'
|
||||
| 'rainbow'
|
||||
| 'routeros'
|
||||
| 'school-book'
|
||||
| 'shades-of-purple'
|
||||
| 'srcery'
|
||||
| 'stackoverflow-dark'
|
||||
| 'stackoverflow-light'
|
||||
| 'sunburst'
|
||||
| 'tokyo-night-dark'
|
||||
| 'tokyo-night-light'
|
||||
| 'tomorrow-night-blue'
|
||||
| 'tomorrow-night-bright'
|
||||
| 'vs'
|
||||
| 'vs2015'
|
||||
| 'xcode'
|
||||
| 'xt256'
|
||||
| 'base16/3024'
|
||||
| 'base16/apathy'
|
||||
| 'base16/apprentice'
|
||||
| 'base16/ashes'
|
||||
| 'base16/atelier-cave'
|
||||
| 'base16/atelier-cave-light'
|
||||
| 'base16/atelier-dune'
|
||||
| 'base16/atelier-dune-light'
|
||||
| 'base16/atelier-estuary'
|
||||
| 'base16/atelier-estuary-light'
|
||||
| 'base16/atelier-forest'
|
||||
| 'base16/atelier-forest-light'
|
||||
| 'base16/atelier-heath'
|
||||
| 'base16/atelier-heath-light'
|
||||
| 'base16/atelier-lakeside'
|
||||
| 'base16/atelier-lakeside-light'
|
||||
| 'base16/atelier-plateau'
|
||||
| 'base16/atelier-plateau-light'
|
||||
| 'base16/atelier-savanna'
|
||||
| 'base16/atelier-savanna-light'
|
||||
| 'base16/atelier-seaside'
|
||||
| 'base16/atelier-seaside-light'
|
||||
| 'base16/atelier-sulphurpool'
|
||||
| 'base16/atelier-sulphurpool-light'
|
||||
| 'base16/atlas'
|
||||
| 'base16/bespin'
|
||||
| 'base16/black-metal'
|
||||
| 'base16/black-metal-bathory'
|
||||
| 'base16/black-metal-burzum'
|
||||
| 'base16/black-metal-dark-funeral'
|
||||
| 'base16/black-metal-gorgoroth'
|
||||
| 'base16/black-metal-immortal'
|
||||
| 'base16/black-metal-khold'
|
||||
| 'base16/black-metal-marduk'
|
||||
| 'base16/black-metal-mayhem'
|
||||
| 'base16/black-metal-nile'
|
||||
| 'base16/black-metal-venom'
|
||||
| 'base16/brewer'
|
||||
| 'base16/bright'
|
||||
| 'base16/brogrammer'
|
||||
| 'base16/brush-trees'
|
||||
| 'base16/brush-trees-dark'
|
||||
| 'base16/chalk'
|
||||
| 'base16/circus'
|
||||
| 'base16/classic-dark'
|
||||
| 'base16/classic-light'
|
||||
| 'base16/codeschool'
|
||||
| 'base16/colors'
|
||||
| 'base16/cupcake'
|
||||
| 'base16/cupertino'
|
||||
| 'base16/danqing'
|
||||
| 'base16/darcula'
|
||||
| 'base16/dark-violet'
|
||||
| 'base16/darkmoss'
|
||||
| 'base16/darktooth'
|
||||
| 'base16/decaf'
|
||||
| 'base16/default-dark'
|
||||
| 'base16/default-light'
|
||||
| 'base16/dirtysea'
|
||||
| 'base16/dracula'
|
||||
| 'base16/edge-dark'
|
||||
| 'base16/edge-light'
|
||||
| 'base16/eighties'
|
||||
| 'base16/embers'
|
||||
| 'base16/equilibrium-dark'
|
||||
| 'base16/equilibrium-gray-dark'
|
||||
| 'base16/equilibrium-gray-light'
|
||||
| 'base16/equilibrium-light'
|
||||
| 'base16/espresso'
|
||||
| 'base16/eva'
|
||||
| 'base16/eva-dim'
|
||||
| 'base16/flat'
|
||||
| 'base16/framer'
|
||||
| 'base16/fruit-soda'
|
||||
| 'base16/gigavolt'
|
||||
| 'base16/github'
|
||||
| 'base16/google-dark'
|
||||
| 'base16/google-light'
|
||||
| 'base16/grayscale-dark'
|
||||
| 'base16/grayscale-light'
|
||||
| 'base16/green-screen'
|
||||
| 'base16/gruvbox-dark-hard'
|
||||
| 'base16/gruvbox-dark-medium'
|
||||
| 'base16/gruvbox-dark-pale'
|
||||
| 'base16/gruvbox-dark-soft'
|
||||
| 'base16/gruvbox-light-hard'
|
||||
| 'base16/gruvbox-light-medium'
|
||||
| 'base16/gruvbox-light-soft'
|
||||
| 'base16/hardcore'
|
||||
| 'base16/harmonic16-dark'
|
||||
| 'base16/harmonic16-light'
|
||||
| 'base16/heetch-dark'
|
||||
| 'base16/heetch-light'
|
||||
| 'base16/helios'
|
||||
| 'base16/hopscotch'
|
||||
| 'base16/horizon-dark'
|
||||
| 'base16/horizon-light'
|
||||
| 'base16/humanoid-dark'
|
||||
| 'base16/humanoid-light'
|
||||
| 'base16/ia-dark'
|
||||
| 'base16/ia-light'
|
||||
| 'base16/icy-dark'
|
||||
| 'base16/ir-black'
|
||||
| 'base16/isotope'
|
||||
| 'base16/kimber'
|
||||
| 'base16/london-tube'
|
||||
| 'base16/macintosh'
|
||||
| 'base16/marrakesh'
|
||||
| 'base16/materia'
|
||||
| 'base16/material'
|
||||
| 'base16/material-darker'
|
||||
| 'base16/material-lighter'
|
||||
| 'base16/material-palenight'
|
||||
| 'base16/material-vivid'
|
||||
| 'base16/mellow-purple'
|
||||
| 'base16/mexico-light'
|
||||
| 'base16/mocha'
|
||||
| 'base16/monokai'
|
||||
| 'base16/nebula'
|
||||
| 'base16/nord'
|
||||
| 'base16/nova'
|
||||
| 'base16/ocean'
|
||||
| 'base16/oceanicnext'
|
||||
| 'base16/one-light'
|
||||
| 'base16/onedark'
|
||||
| 'base16/outrun-dark'
|
||||
| 'base16/papercolor-dark'
|
||||
| 'base16/papercolor-light'
|
||||
| 'base16/paraiso'
|
||||
| 'base16/pasque'
|
||||
| 'base16/phd'
|
||||
| 'base16/pico'
|
||||
| 'base16/pop'
|
||||
| 'base16/porple'
|
||||
| 'base16/qualia'
|
||||
| 'base16/railscasts'
|
||||
| 'base16/rebecca'
|
||||
| 'base16/ros-pine'
|
||||
| 'base16/ros-pine-dawn'
|
||||
| 'base16/ros-pine-moon'
|
||||
| 'base16/sagelight'
|
||||
| 'base16/sandcastle'
|
||||
| 'base16/seti-ui'
|
||||
| 'base16/shapeshifter'
|
||||
| 'base16/silk-dark'
|
||||
| 'base16/silk-light'
|
||||
| 'base16/snazzy'
|
||||
| 'base16/solar-flare'
|
||||
| 'base16/solar-flare-light'
|
||||
| 'base16/solarized-dark'
|
||||
| 'base16/solarized-light'
|
||||
| 'base16/spacemacs'
|
||||
| 'base16/summercamp'
|
||||
| 'base16/summerfruit-dark'
|
||||
| 'base16/summerfruit-light'
|
||||
| 'base16/synth-midnight-terminal-dark'
|
||||
| 'base16/synth-midnight-terminal-light'
|
||||
| 'base16/tango'
|
||||
| 'base16/tender'
|
||||
| 'base16/tomorrow'
|
||||
| 'base16/tomorrow-night'
|
||||
| 'base16/twilight'
|
||||
| 'base16/unikitty-dark'
|
||||
| 'base16/unikitty-light'
|
||||
| 'base16/vulcan'
|
||||
| 'base16/windows-10'
|
||||
| 'base16/windows-10-light'
|
||||
| 'base16/windows-95'
|
||||
| 'base16/windows-95-light'
|
||||
| 'base16/windows-high-contrast'
|
||||
| 'base16/windows-high-contrast-light'
|
||||
| 'base16/windows-nt'
|
||||
| 'base16/windows-nt-light'
|
||||
| 'base16/woodland'
|
||||
| 'base16/xcode-dusk'
|
||||
| 'base16/zenburn'
|
||||
|
||||
type EmbedParams = {
|
||||
style: EmbedStyle
|
||||
type: 'code' | 'markdown' | 'ipynb'
|
||||
showBorder?: 'on'
|
||||
showLineNumbers?: 'on'
|
||||
showFileMeta?: 'on'
|
||||
showFullPath?: 'on'
|
||||
showCopy?: 'on'
|
||||
fetchFromJsDelivr?: 'on'
|
||||
maxHeight?: number
|
||||
}
|
||||
|
||||
function buildEmbedQuery(params: EmbedParams) {
|
||||
return Object.entries(params)
|
||||
.filter(([, v]) => v !== undefined)
|
||||
.map(
|
||||
([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`,
|
||||
)
|
||||
.join('&')
|
||||
}
|
||||
|
||||
/* Edit Params */
|
||||
const EMBED_PARAMS: EmbedParams = {
|
||||
style: 'github',
|
||||
type: 'code',
|
||||
showBorder: 'on',
|
||||
showLineNumbers: 'on',
|
||||
showFileMeta: 'on',
|
||||
showFullPath: 'on',
|
||||
showCopy: 'on',
|
||||
}
|
||||
|
||||
const { url } = Astro.props
|
||||
const PreviewURL = encodeURIComponent(url.toString())
|
||||
const embedQuery = buildEmbedQuery(EMBED_PARAMS)
|
||||
const embedScriptSrc = `https://emgithub.com/embed-v2.js?target=${PreviewURL}&${embedQuery}`
|
||||
---
|
||||
|
||||
<div class="github-link-preview-wrapper">
|
||||
<div class="github-link-preview">
|
||||
<script is:inline src={embedScriptSrc}></script>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.github-link-preview-wrapper {
|
||||
display: flex;
|
||||
}
|
||||
.github-link-preview {
|
||||
flex: 1;
|
||||
width: 0;
|
||||
|
||||
table {
|
||||
white-space: unset;
|
||||
}
|
||||
td::after {
|
||||
display: unset;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { buildHeadingId } from '../../lib/blog-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { buildHeadingId } from '../../lib/blog-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { buildHeadingId } from '../../lib/blog-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
---
|
||||
import { ENABLE_LIGHTBOX } from '@/consts'
|
||||
import * as interfaces from '../../lib/interfaces'
|
||||
import { filePath } from '../../lib/blog-helpers'
|
||||
import * as interfaces from '../../lib/interfaces'
|
||||
import Caption from './Caption.astro'
|
||||
import fslightbox from 'fslightbox'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
@@ -22,7 +21,8 @@ if (block.Image.External) {
|
||||
image = filePath(new URL(block.Image.File.Url))
|
||||
}
|
||||
|
||||
const altText = block.Image.Caption?.map(c => c.Text.Content).join('') || 'Image'
|
||||
const altText =
|
||||
block.Image.Caption?.map((c) => c.Text.Content).join('') || 'Image'
|
||||
---
|
||||
|
||||
<figure class="image">
|
||||
@@ -31,20 +31,25 @@ const altText = block.Image.Caption?.map(c => c.Text.Content).join('') || 'Image
|
||||
<div class="image-wrapper">
|
||||
<div class="image-container">
|
||||
{ENABLE_LIGHTBOX ? (
|
||||
<a data-fslightbox href={image} data-type="image" class="lightbox-link">
|
||||
<img
|
||||
src={image}
|
||||
<a
|
||||
data-fslightbox
|
||||
href={image}
|
||||
data-type="image"
|
||||
class="lightbox-link"
|
||||
>
|
||||
<img
|
||||
src={image}
|
||||
alt={altText}
|
||||
loading="lazy"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="image-content"
|
||||
/>
|
||||
</a>
|
||||
) : (
|
||||
<img
|
||||
src={image}
|
||||
<img
|
||||
src={image}
|
||||
alt={altText}
|
||||
loading="lazy"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
class="image-content"
|
||||
/>
|
||||
@@ -62,29 +67,31 @@ const altText = block.Image.Caption?.map(c => c.Text.Content).join('') || 'Image
|
||||
margin: 1rem auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.image-wrapper {
|
||||
margin: 0 auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
|
||||
.image-container {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-radius: 0.5rem;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
transition:
|
||||
transform 0.2s ease,
|
||||
box-shadow 0.2s ease;
|
||||
}
|
||||
|
||||
|
||||
.image-container:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
|
||||
.lightbox-link {
|
||||
display: block;
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
|
||||
.image-content {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
@@ -93,17 +100,18 @@ const altText = block.Image.Caption?.map(c => c.Text.Content).join('') || 'Image
|
||||
object-fit: cover;
|
||||
transition: opacity 0.3s ease;
|
||||
}
|
||||
|
||||
.image-content[loading="lazy"] {
|
||||
background: linear-gradient(90deg,
|
||||
hsl(var(--muted)) 0%,
|
||||
hsl(var(--muted) / 0.8) 50%,
|
||||
|
||||
.image-content[loading='lazy'] {
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
hsl(var(--muted)) 0%,
|
||||
hsl(var(--muted) / 0.8) 50%,
|
||||
hsl(var(--muted)) 100%
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
}
|
||||
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -200% 0;
|
||||
@@ -112,12 +120,12 @@ const altText = block.Image.Caption?.map(c => c.Text.Content).join('') || 'Image
|
||||
background-position: 200% 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.image {
|
||||
margin: 0.75rem auto;
|
||||
}
|
||||
|
||||
|
||||
.image-container:hover {
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import arrow from '../../images/icon-arrow-link.svg'
|
||||
import { getPostLink } from '../../lib/blog-helpers.ts'
|
||||
import type { Post } from '../../lib/interfaces.ts'
|
||||
import { getPostByPageId } from '../../lib/notion/client'
|
||||
import { getPostLink } from '../../lib/blog-helpers.ts'
|
||||
import '../../styles/notion-color.css'
|
||||
import arrow from '../../images/icon-arrow-link.svg'
|
||||
|
||||
export interface Props {
|
||||
pageId: string
|
||||
@@ -22,18 +22,22 @@ if (pageId) {
|
||||
<a href={getPostLink(post.Slug)} class="link">
|
||||
<>
|
||||
<span class="icon">
|
||||
{post.Icon && post.Icon.Type === 'emoji'
|
||||
? post.Icon.Emoji
|
||||
: post.Icon && post.Icon.Type === 'external'
|
||||
? (
|
||||
<img
|
||||
src={post.Icon.Url}
|
||||
class="notion-icon"
|
||||
alt="Post title icon in a page link"
|
||||
/>
|
||||
)
|
||||
: '📄'}
|
||||
<img src={arrow.src} class="icon-link" alt="Arrow icon of a page link" />
|
||||
{post.Icon && post.Icon.Type === 'emoji' ? (
|
||||
post.Icon.Emoji
|
||||
) : post.Icon && post.Icon.Type === 'external' ? (
|
||||
<img
|
||||
src={post.Icon.Url}
|
||||
class="notion-icon"
|
||||
alt="Post title icon in a page link"
|
||||
/>
|
||||
) : (
|
||||
'📄'
|
||||
)}
|
||||
<img
|
||||
src={arrow.src}
|
||||
class="icon-link"
|
||||
alt="Arrow icon of a page link"
|
||||
/>
|
||||
</span>
|
||||
<span class="text">{post.Title}</span>
|
||||
</>
|
||||
@@ -42,7 +46,11 @@ if (pageId) {
|
||||
<a class="link">
|
||||
<span class="icon">
|
||||
🚫
|
||||
<img src={arrow.src} class="icon-link" alt="Arrow icon of a page link" />
|
||||
<img
|
||||
src={arrow.src}
|
||||
class="icon-link"
|
||||
alt="Arrow icon of a page link"
|
||||
/>
|
||||
</span>
|
||||
<span class="text not-found">Post not found</span>
|
||||
</a>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import '../../styles/notion-color.css'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
@@ -21,7 +21,8 @@ const items = block.ListItems ?? []
|
||||
{
|
||||
items
|
||||
.filter(
|
||||
(b: interfaces.Block) => b.Type === 'numbered_list_item' && b.NumberedListItem,
|
||||
(b: interfaces.Block) =>
|
||||
b.Type === 'numbered_list_item' && b.NumberedListItem,
|
||||
)
|
||||
.map((b: interfaces.Block) => {
|
||||
const item = b.NumberedListItem
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import '../../styles/notion-color.css'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -11,5 +11,4 @@ const { url } = Astro.props
|
||||
type="text/javascript"
|
||||
async
|
||||
defer
|
||||
src="//assets.pinterest.com/js/pinit.js"
|
||||
></script>
|
||||
src="//assets.pinterest.com/js/pinit.js"></script>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import '../../styles/notion-color.css'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
---
|
||||
import katex from 'katex'
|
||||
import type { RichText } from '../../lib/interfaces.ts'
|
||||
import Anchor from './annotations/Anchor.astro'
|
||||
import Bold from './annotations/Bold.astro'
|
||||
import Code from './annotations/Code.astro'
|
||||
import Color from './annotations/Color.astro'
|
||||
import Italic from './annotations/Italic.astro'
|
||||
import Strikethrough from './annotations/Strikethrough.astro'
|
||||
import Underline from './annotations/Underline.astro'
|
||||
import Color from './annotations/Color.astro'
|
||||
import Code from './annotations/Code.astro'
|
||||
import Anchor from './annotations/Anchor.astro'
|
||||
import Mention from './Mention.astro'
|
||||
|
||||
export interface Props {
|
||||
@@ -43,13 +43,13 @@ const { richText } = Astro.props
|
||||
{content}
|
||||
</>
|
||||
)
|
||||
}
|
||||
},
|
||||
)}
|
||||
{richText.Equation && (
|
||||
<span
|
||||
set:html={katex.renderToString(
|
||||
richText.Equation.Expression,
|
||||
{ throwOnError: false }
|
||||
{ throwOnError: false },
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import type * as interfaces from '../../lib/interfaces'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { buildHeadingId } from '../../lib/blog-helpers.ts'
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import '../../styles/notion-color.css'
|
||||
|
||||
@@ -39,7 +39,7 @@ if (!block.TableOfContents) {
|
||||
)} ${indentClass}`}
|
||||
>
|
||||
{heading.RichTexts.map(
|
||||
(richText: interfaces.RichText) => richText.PlainText
|
||||
(richText: interfaces.RichText) => richText.PlainText,
|
||||
).join('')}
|
||||
</a>
|
||||
)
|
||||
@@ -52,6 +52,9 @@ if (!block.TableOfContents) {
|
||||
}
|
||||
.table-of-contents > a {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
line-height: 1.8rem;
|
||||
font-size: 0.9rem;
|
||||
font-weight: 500;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import '../../styles/notion-color.css'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { snakeToKebab } from '../../lib/style-helpers.ts'
|
||||
import RichText from './RichText.astro'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import '../../styles/notion-color.css'
|
||||
import NotionBlocks from '../NotionBlocks.astro'
|
||||
import RichText from './RichText.astro'
|
||||
|
||||
export interface Props {
|
||||
block: interfaces.Block
|
||||
|
||||
@@ -17,7 +17,8 @@ const postURL =
|
||||
</blockquote>
|
||||
</div>
|
||||
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"
|
||||
></script>
|
||||
|
||||
<style>
|
||||
.tweet-embed {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import { isYouTubeURL, parseYouTubeVideoId } from '../../lib/blog-helpers.ts'
|
||||
import * as interfaces from '../../lib/interfaces.ts'
|
||||
import Caption from './Caption.astro'
|
||||
|
||||
export interface Props {
|
||||
|
||||
@@ -14,10 +14,8 @@ const buttonVariants = cva(
|
||||
'bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
|
||||
outline:
|
||||
'border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
|
||||
muted:
|
||||
'bg-muted text-foreground hover:bg-muted/80',
|
||||
ghost:
|
||||
'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50',
|
||||
muted: 'bg-muted text-foreground hover:bg-muted/80',
|
||||
ghost: 'hover:bg-muted hover:text-foreground dark:hover:bg-muted/50',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
|
||||
@@ -130,7 +130,8 @@ const PaginationComponent: React.FC<PaginationProps> = ({
|
||||
baseUrl,
|
||||
}) => {
|
||||
const buildPages = () => {
|
||||
if (totalPages <= 7) return Array.from({ length: totalPages }, (_, i) => i + 1)
|
||||
if (totalPages <= 7)
|
||||
return Array.from({ length: totalPages }, (_, i) => i + 1)
|
||||
|
||||
const pageSet = new Set<number>([
|
||||
1,
|
||||
|
||||
@@ -4,8 +4,7 @@ export const ENABLE_LIGHTBOX = true
|
||||
|
||||
export const SITE: Site = {
|
||||
title: '溴化锂的笔记本',
|
||||
description:
|
||||
'Security, Programming, Life',
|
||||
description: 'Security, Programming, Life',
|
||||
href: 'https://nvme0n1p.dev',
|
||||
author: 'libr',
|
||||
locale: 'zh-CN',
|
||||
|
||||
@@ -6,8 +6,8 @@ import Footer from '@/components/Footer.astro'
|
||||
import Head from '@/components/Head.astro'
|
||||
import Header from '@/components/Header.astro'
|
||||
import { ENABLE_LIGHTBOX, SITE } from '@/consts'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { getStaticFilePath } from '@/lib/blog-helpers'
|
||||
import { cn } from '@/lib/utils'
|
||||
interface Props {
|
||||
class?: string
|
||||
}
|
||||
@@ -38,11 +38,6 @@ const { class: className } = Astro.props
|
||||
</main>
|
||||
<Footer />
|
||||
|
||||
|
||||
{
|
||||
ENABLE_LIGHTBOX && (
|
||||
<script src={getStaticFilePath('/js/fslightbox.js')} />
|
||||
)
|
||||
}
|
||||
{ENABLE_LIGHTBOX && <script src={getStaticFilePath('/js/fslightbox.js')} />}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -11,18 +11,19 @@ import { cn } from '@/lib/utils'
|
||||
<PageHead slot="head" title="500" />
|
||||
<Breadcrumbs items={[{ label: 'Error', icon: 'lucide:server-off' }]} />
|
||||
|
||||
<section class="flex flex-col items-center justify-center gap-y-4 text-center">
|
||||
<section
|
||||
class="flex flex-col items-center justify-center gap-y-4 text-center"
|
||||
>
|
||||
<div class="max-w-md">
|
||||
<h1 class="mb-4 text-3xl font-medium">500: Something went wrong</h1>
|
||||
<p class="prose">
|
||||
服务器爆炸了!如果你能联系到博主的话提醒他一声吧!
|
||||
</p>
|
||||
<p class="prose">服务器爆炸了!如果你能联系到博主的话提醒他一声吧!</p>
|
||||
</div>
|
||||
<Link
|
||||
href="/"
|
||||
class={cn(buttonVariants({ variant: 'outline' }), 'flex gap-x-1.5 group')}
|
||||
>
|
||||
<span class="transition-transform group-hover:-translate-x-1">←</span>
|
||||
<span class="transition-transform group-hover:-translate-x-1">←</span
|
||||
>
|
||||
Go to home page
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
import Breadcrumbs from '@/components/Breadcrumbs.astro'
|
||||
import Comment from '@/components/Comment.astro'
|
||||
import Link from '@/components/Link.astro'
|
||||
import PageHead from '@/components/PageHead.astro'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import Comment from '@/components/Comment.astro'
|
||||
---
|
||||
|
||||
<Layout class="max-w-3xl">
|
||||
@@ -13,11 +13,11 @@ import Comment from '@/components/Comment.astro'
|
||||
<section class="grid gap-6">
|
||||
<div class="relative rounded-lg border p-6">
|
||||
<div class="relative flex flex-col gap-4">
|
||||
<p class="text-xs uppercase tracking-[0.35em] text-muted-foreground">
|
||||
<p class="text-muted-foreground text-xs tracking-[0.35em] uppercase">
|
||||
profile
|
||||
</p>
|
||||
<h1 class="text-3xl font-semibold">关于我</h1>
|
||||
<p class="max-w-3xl text-muted-foreground">
|
||||
<p class="text-muted-foreground max-w-3xl">
|
||||
啥都写一点,但是啥都不精通。前端后端客户端,运维网安都会那么一点点,尝试写出点什么项目但总是失败。
|
||||
</p>
|
||||
</div>
|
||||
@@ -26,19 +26,19 @@ import Comment from '@/components/Comment.astro'
|
||||
<div class="grid gap-4 md:grid-cols-3">
|
||||
<div class="rounded-lg border p-5">
|
||||
<h3 class="text-lg font-semibold">安全</h3>
|
||||
<p class="text-sm leading-relaxed text-muted-foreground">
|
||||
<p class="text-muted-foreground text-sm leading-relaxed">
|
||||
非典型 Misc,啥都做点,(感觉更像是全栈?)
|
||||
</p>
|
||||
</div>
|
||||
<div class="rounded-lg border p-5">
|
||||
<h3 class="text-lg font-semibold">代码</h3>
|
||||
<p class="text-sm leading-relaxed text-muted-foreground">
|
||||
<p class="text-muted-foreground text-sm leading-relaxed">
|
||||
近期在写 C 和 Swift,之前写过 Golang、Python、JavaScript
|
||||
</p>
|
||||
</div>
|
||||
<div class="rounded-lg border p-5">
|
||||
<h3 class="text-lg font-semibold">生活</h3>
|
||||
<p class="text-sm leading-relaxed text-muted-foreground">
|
||||
<p class="text-muted-foreground text-sm leading-relaxed">
|
||||
二次元、骑车、游泳、羽毛球、CS、摄影
|
||||
</p>
|
||||
</div>
|
||||
@@ -47,41 +47,45 @@ import Comment from '@/components/Comment.astro'
|
||||
<div class="rounded-lg border p-6">
|
||||
<div class="flex items-center justify-between gap-4">
|
||||
<div>
|
||||
<p class="text-xs uppercase text-muted-foreground">setup</p>
|
||||
<p class="text-muted-foreground text-xs uppercase">setup</p>
|
||||
<h3 class="text-xl font-semibold">常用设备</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-4 grid gap-3 md:grid-cols-2">
|
||||
<div class="rounded-lg border p-4">
|
||||
<p class="text-sm font-semibold">PC</p>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
<p class="text-muted-foreground text-sm">
|
||||
M2 Macbook Air · MSI Stealth 14 · iPad Air 5
|
||||
</p>
|
||||
</div>
|
||||
<div class="rounded-lg border p-4">
|
||||
<p class="text-sm font-semibold">手机</p>
|
||||
<p class="text-sm text-muted-foreground">iPhone 17 · vivo x100 · iPhone 13 mini</p>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
iPhone 17 · vivo x100 · iPhone 13 mini
|
||||
</p>
|
||||
</div>
|
||||
<div class="rounded-lg border p-4 md:col-span-2">
|
||||
<p class="text-sm font-semibold">影音与记录</p>
|
||||
<p class="text-sm text-muted-foreground">Sony XM5 · Nikon Zfc</p>
|
||||
<p class="text-muted-foreground text-sm">Sony XM5 · Nikon Zfc</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="rounded-lg border p-6">
|
||||
<p class="text-xs uppercase text-muted-foreground">site</p>
|
||||
<p class="text-muted-foreground text-xs uppercase">site</p>
|
||||
<h3 class="text-xl font-semibold">关于本站</h3>
|
||||
<p class="mt-2 text-sm leading-relaxed text-muted-foreground">
|
||||
<p class="text-muted-foreground mt-2 text-sm leading-relaxed">
|
||||
栈在 <Link href="https://astro.build" external underline>Astro</Link>,
|
||||
<Link href="https://tailwindcss.com" external underline>Tailwind</Link>,
|
||||
<Link href="https://ui.shadcn.com" external underline>shadcn/ui</Link> 之上,开源在
|
||||
<Link href="https://github.com/jktrn/astro-erudite" external underline>GitHub</Link>。
|
||||
<Link href="https://github.com/jktrn/astro-erudite" external underline
|
||||
>GitHub</Link
|
||||
>。
|
||||
</p>
|
||||
<h4 class="text-l font-semibold mt-2">大事记</h4>
|
||||
<h4 class="text-l mt-2 font-semibold">大事记</h4>
|
||||
<div class="mt-3 overflow-x-auto rounded-lg border">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-muted/60 text-left text-muted-foreground">
|
||||
<thead class="bg-muted/60 text-muted-foreground text-left">
|
||||
<tr>
|
||||
<th class="px-4 py-2 font-semibold">时间</th>
|
||||
<th class="px-4 py-2 font-semibold">事件</th>
|
||||
@@ -91,26 +95,30 @@ import Comment from '@/components/Comment.astro'
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2018</td>
|
||||
<td class="px-4 py-2">
|
||||
第一次建站,域名 <code>stevelbr.ga</code>,使用 hexo 和不知道有几种主题
|
||||
第一次建站,域名 <code>stevelbr.ga</code>,使用 hexo
|
||||
和不知道有几种主题
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2020</td>
|
||||
<td class="px-4 py-2">
|
||||
购入腾讯云轻量服务器,购入域名 <code>stevelbr.top</code> ,使用 typecho 和
|
||||
typecho-theme-handsome 建站,接入备案。
|
||||
购入腾讯云轻量服务器,购入域名 <code>stevelbr.top</code> ,使用 typecho
|
||||
和 typecho-theme-handsome 建站,接入备案。
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2023</td>
|
||||
<td class="px-4 py-2">
|
||||
停止续费腾讯云轻量,购入域名 <code>nvme0n1p.dev</code>,使用 hugo+serverless service 建站。
|
||||
停止续费腾讯云轻量,购入域名 <code>nvme0n1p.dev</code>,使用
|
||||
hugo+serverless service 建站。
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2024.1</td>
|
||||
<td class="px-4 py-2">
|
||||
使用 <Link href="http://cali.so" external underline>cali.so</Link> nextjs自建服务,运行于 vercel。
|
||||
使用 <Link href="http://cali.so" external underline
|
||||
>cali.so</Link
|
||||
> nextjs自建服务,运行于 vercel。
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -128,18 +136,24 @@ import Comment from '@/components/Comment.astro'
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2024.10</td>
|
||||
<td class="px-4 py-2">
|
||||
优化 nuxtjs 代码,现在全站支持无刷新页面切换。<del>同时增加 algolia docsearch 魔改版作为站内搜索。</del>好像没开 Server Side Rendering ,炸了
|
||||
优化 nuxtjs 代码,现在全站支持无刷新页面切换。<del
|
||||
>同时增加 algolia docsearch 魔改版作为站内搜索。</del
|
||||
>好像没开 Server Side Rendering ,炸了
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2024.11</td>
|
||||
<td class="px-4 py-2">
|
||||
感谢<Link href="https://www.dkdun.cn/" external underline>林枫云</Link>对 ctfer 的支持,切换到了他家的香港服务器。
|
||||
感谢<Link href="https://www.dkdun.cn/" external underline
|
||||
>林枫云</Link
|
||||
>对 ctfer 的支持,切换到了他家的香港服务器。
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2025.2</td>
|
||||
<td class="px-4 py-2">用nextjs重写了。优化了访问速度,减少了了图片。</td>
|
||||
<td class="px-4 py-2"
|
||||
>用nextjs重写了。优化了访问速度,减少了了图片。</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="px-4 py-2 whitespace-nowrap">2025.7</td>
|
||||
|
||||
@@ -1,35 +1,34 @@
|
||||
---
|
||||
import Breadcrumbs from '@/components/Breadcrumbs.astro'
|
||||
import Comment from '@/components/Comment.astro'
|
||||
import Link from '@/components/Link.astro'
|
||||
import NotionBlocks from '@/components/NotionBlocks.astro'
|
||||
import PostHead from '@/components/PostHead.astro'
|
||||
import PostNavigation from '@/components/PostNavigation.astro'
|
||||
import SubpostsHeader from '@/components/SubpostsHeader.astro'
|
||||
import SubpostsSidebar from '@/components/SubpostsSidebar.astro'
|
||||
import TOCHeader from '@/components/TOCHeader.astro'
|
||||
import TOCSidebar from '@/components/TOCSidebar.astro'
|
||||
import NotionBlocks from '@/components/NotionBlocks.astro'
|
||||
import { badgeVariants } from '@/components/ui/badge'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import type { TOCSection } from '@/lib/data-utils'
|
||||
import {
|
||||
fetchRemotePostContent,
|
||||
getAdjacentPosts,
|
||||
getAllPostsAndSubposts,
|
||||
getParentId,
|
||||
getParentPost,
|
||||
getSubpostCount,
|
||||
getTOCSections,
|
||||
fetchRemotePostContent,
|
||||
renderRemoteBlockMap,
|
||||
hasSubposts,
|
||||
isSubpost,
|
||||
parseAuthors,
|
||||
renderRemoteBlockMap,
|
||||
} from '@/lib/data-utils'
|
||||
import type { TOCSection } from '@/lib/data-utils'
|
||||
import Comment from '@/components/Comment.astro'
|
||||
import { formatDate } from '@/lib/utils'
|
||||
import { Icon } from 'astro-icon/components'
|
||||
import { Image } from 'astro:assets'
|
||||
import { render } from 'astro:content'
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const posts = await getAllPostsAndSubposts()
|
||||
@@ -71,9 +70,7 @@ try {
|
||||
parentPost = isCurrentSubpost ? await getParentPost(currentPostId) : null
|
||||
|
||||
hasChildPosts = await hasSubposts(currentPostId)
|
||||
subpostCount = !isCurrentSubpost
|
||||
? await getSubpostCount(currentPostId)
|
||||
: 0
|
||||
subpostCount = !isCurrentSubpost ? await getSubpostCount(currentPostId) : 0
|
||||
|
||||
tocSections = remoteContent
|
||||
? remoteContent.headings.length > 0
|
||||
@@ -91,7 +88,7 @@ try {
|
||||
console.error('blog page render failed:', error)
|
||||
return Astro.rewrite('/500')
|
||||
}
|
||||
export const prerender = false;
|
||||
export const prerender = false
|
||||
---
|
||||
|
||||
<Layout>
|
||||
|
||||
@@ -5,8 +5,7 @@ import PageHead from '@/components/PageHead.astro'
|
||||
import PaginationComponent from '@/components/ui/pagination'
|
||||
import { SITE } from '@/consts'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import { getAllPosts, groupPostsByYear, normalizePost } from '@/lib/data-utils'
|
||||
import type { PaginateFunction } from 'astro'
|
||||
import { groupPostsByYear, normalizePost } from '@/lib/data-utils'
|
||||
|
||||
// export async function getStaticPaths({
|
||||
// paginate,
|
||||
@@ -16,33 +15,37 @@ import type { PaginateFunction } from 'astro'
|
||||
// const allPosts = await getAllPosts()
|
||||
// return paginate(allPosts, { pageSize: SITE.postsPerPage })
|
||||
// }
|
||||
const nowPage = parseInt(new URL(Astro.request.url).searchParams.get("p") || "1");
|
||||
const nowPage = parseInt(
|
||||
new URL(Astro.request.url).searchParams.get('p') || '1',
|
||||
)
|
||||
|
||||
// use url param
|
||||
// use url param
|
||||
// const { page } = Astro.para
|
||||
|
||||
const page = await fetch(`https://notion-api.nvme0n1p.dev/v2/posts/?page=${nowPage}&length=${SITE.postsPerPage}`)
|
||||
const page = await fetch(
|
||||
`https://notion-api.nvme0n1p.dev/v2/posts/?page=${nowPage}&length=${SITE.postsPerPage}`,
|
||||
)
|
||||
.then((res) => {
|
||||
if (!res.ok) throw new Error(`Failed to fetch posts: ${res.status}`);
|
||||
return res.json();
|
||||
if (!res.ok) throw new Error(`Failed to fetch posts: ${res.status}`)
|
||||
return res.json()
|
||||
})
|
||||
.then((allPosts) => {
|
||||
const totalPages = allPosts.length;
|
||||
const currentPage = nowPage;
|
||||
return {
|
||||
data: allPosts.posts.map((post) => normalizePost(post)),
|
||||
currentPage,
|
||||
lastPage: totalPages,
|
||||
};
|
||||
});
|
||||
const totalPages = allPosts.length
|
||||
const currentPage = nowPage
|
||||
return {
|
||||
data: allPosts.posts.map((post) => normalizePost(post)),
|
||||
currentPage,
|
||||
lastPage: totalPages,
|
||||
}
|
||||
})
|
||||
// fetch page
|
||||
if(page.lastPage < page.currentPage) {
|
||||
console.log("redirect to 404")
|
||||
return Astro.rewrite("/404")
|
||||
if (page.lastPage < page.currentPage) {
|
||||
console.log('redirect to 404')
|
||||
return Astro.rewrite('/404')
|
||||
}
|
||||
const postsByYear = groupPostsByYear(page.data)
|
||||
const years = Object.keys(postsByYear).sort((a, b) => parseInt(b) - parseInt(a))
|
||||
export const prerender = false;
|
||||
export const prerender = false
|
||||
---
|
||||
|
||||
<Layout class="max-w-3xl">
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
---
|
||||
import Breadcrumbs from '@/components/Breadcrumbs.astro'
|
||||
import Comment from '@/components/Comment.astro'
|
||||
import Link from '@/components/Link.astro'
|
||||
import PageHead from '@/components/PageHead.astro'
|
||||
import Layout from '@/layouts/Layout.astro'
|
||||
import {
|
||||
getFriendLinks,
|
||||
type LinkEntry,
|
||||
} from '@/lib/data-utils'
|
||||
import Comment from '@/components/Comment.astro'
|
||||
import { getFriendLinks } from '@/lib/data-utils'
|
||||
const placeholderAvatar = '/avatar-placeholder.svg'
|
||||
const visibleLinks = await getFriendLinks()
|
||||
---
|
||||
@@ -19,48 +16,44 @@ const visibleLinks = await getFriendLinks()
|
||||
<section class="rounded-lg border p-6">
|
||||
<div class="flex flex-col gap-2">
|
||||
<h1 class="text-2xl font-semibold">友链 / Friends</h1>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
这里收集一些朋友和有趣的网站
|
||||
</p>
|
||||
<p class="text-muted-foreground text-sm">这里收集一些朋友和有趣的网站</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="grid gap-4">
|
||||
{
|
||||
visibleLinks.map((friend) => (
|
||||
<article class="rounded-lg border p-4 transition hover:border-primary/60">
|
||||
<article class="hover:border-primary/60 rounded-lg border p-4 transition">
|
||||
<div class="flex items-start gap-3">
|
||||
{
|
||||
friend.picLink ? (
|
||||
<img
|
||||
src={friend.picLink}
|
||||
alt={friend.name}
|
||||
loading="lazy"
|
||||
class="h-12 w-12 rounded-full border object-cover"
|
||||
width="48"
|
||||
height="48"
|
||||
onerror={`this.onerror=null;this.src='${placeholderAvatar}';`}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={placeholderAvatar}
|
||||
alt="avatar placeholder"
|
||||
loading="lazy"
|
||||
class="h-12 w-12 rounded-full border object-cover"
|
||||
width="48"
|
||||
height="48"
|
||||
/>
|
||||
)
|
||||
}
|
||||
{friend.picLink ? (
|
||||
<img
|
||||
src={friend.picLink}
|
||||
alt={friend.name}
|
||||
loading="lazy"
|
||||
class="h-12 w-12 rounded-full border object-cover"
|
||||
width="48"
|
||||
height="48"
|
||||
onerror={`this.onerror=null;this.src='${placeholderAvatar}';`}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={placeholderAvatar}
|
||||
alt="avatar placeholder"
|
||||
loading="lazy"
|
||||
class="h-12 w-12 rounded-full border object-cover"
|
||||
width="48"
|
||||
height="48"
|
||||
/>
|
||||
)}
|
||||
<div class="flex-1 space-y-1">
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
<h2 class="text-lg font-semibold leading-tight">
|
||||
<h2 class="text-lg leading-tight font-semibold">
|
||||
<Link href={friend.links} external underline>
|
||||
{friend.name}
|
||||
</Link>
|
||||
</h2>
|
||||
</div>
|
||||
<p class="text-sm text-muted-foreground">
|
||||
<p class="text-muted-foreground text-sm">
|
||||
{friend.Description || '你来到了知识的荒原'}
|
||||
</p>
|
||||
</div>
|
||||
@@ -72,10 +65,11 @@ const visibleLinks = await getFriendLinks()
|
||||
|
||||
<section class="rounded-lg border p-6">
|
||||
<h3 class="text-lg font-semibold">申请方式</h3>
|
||||
<p class="text-sm text-muted-foreground mt-2">
|
||||
<p class="text-muted-foreground mt-2 text-sm">
|
||||
请提供站点名称、链接、一句话介绍。
|
||||
</p>
|
||||
<pre class="mt-3 whitespace-pre-wrap break-words rounded-md bg-muted/50 p-3 text-xs text-muted-foreground">
|
||||
<pre
|
||||
class="bg-muted/50 text-muted-foreground mt-3 rounded-md p-3 text-xs break-words whitespace-pre-wrap">
|
||||
name: 溴化锂的笔记本
|
||||
link: https://nvme0n1p.dev
|
||||
avatar: https://gravatar.com/avatar/29d64df3ca2a9dac5a7fffa5372fb80fb3270ceb223de2af0c33cdc4b2cbe954?v=1687917579000&size=256&d=initials
|
||||
|
||||
@@ -15,9 +15,7 @@ const blog = await getRecentPosts(SITE.featuredPostCount)
|
||||
<section class="rounded-lg border">
|
||||
<div class="flex flex-col space-y-1.5 p-6">
|
||||
<h3 class="text-3xl leading-none font-medium">溴化锂</h3>
|
||||
<p class="text-muted-foreground text-sm">
|
||||
LiBr
|
||||
</p>
|
||||
<p class="text-muted-foreground text-sm">LiBr</p>
|
||||
</div>
|
||||
<div class="p-6 pt-0">
|
||||
<p class="text-muted-foreground mb-2 text-sm">
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function getStaticPaths() {
|
||||
}
|
||||
|
||||
const { tag, posts } = Astro.props
|
||||
export const prerender = false;
|
||||
export const prerender = false
|
||||
---
|
||||
|
||||
<Layout class="max-w-3xl">
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getSortedTags } from '@/lib/data-utils'
|
||||
import { Icon } from 'astro-icon/components'
|
||||
|
||||
const sortedTags = await getSortedTags()
|
||||
export const prerender = false;
|
||||
export const prerender = false
|
||||
---
|
||||
|
||||
<Layout class="max-w-3xl">
|
||||
|
||||
@@ -44,13 +44,37 @@
|
||||
--notion-red: color-mix(in oklab, var(--foreground) 82%, #d44c47);
|
||||
|
||||
--notion-gray-background: color-mix(in oklab, var(--background) 82%, #f1f1ef);
|
||||
--notion-brown-background: color-mix(in oklab, var(--background) 82%, #f4eeee);
|
||||
--notion-orange-background: color-mix(in oklab, var(--background) 82%, #fbecdd);
|
||||
--notion-yellow-background: color-mix(in oklab, var(--background) 82%, #fbf3db);
|
||||
--notion-green-background: color-mix(in oklab, var(--background) 82%, #edf3ec);
|
||||
--notion-brown-background: color-mix(
|
||||
in oklab,
|
||||
var(--background) 82%,
|
||||
#f4eeee
|
||||
);
|
||||
--notion-orange-background: color-mix(
|
||||
in oklab,
|
||||
var(--background) 82%,
|
||||
#fbecdd
|
||||
);
|
||||
--notion-yellow-background: color-mix(
|
||||
in oklab,
|
||||
var(--background) 82%,
|
||||
#fbf3db
|
||||
);
|
||||
--notion-green-background: color-mix(
|
||||
in oklab,
|
||||
var(--background) 82%,
|
||||
#edf3ec
|
||||
);
|
||||
--notion-blue-background: color-mix(in oklab, var(--background) 82%, #e7f3f8);
|
||||
--notion-purple-background: color-mix(in oklab, var(--background) 82%, rgba(244, 240, 247, 0.8));
|
||||
--notion-pink-background: color-mix(in oklab, var(--background) 82%, rgba(249, 238, 243, 0.8));
|
||||
--notion-purple-background: color-mix(
|
||||
in oklab,
|
||||
var(--background) 82%,
|
||||
rgba(244, 240, 247, 0.8)
|
||||
);
|
||||
--notion-pink-background: color-mix(
|
||||
in oklab,
|
||||
var(--background) 82%,
|
||||
rgba(249, 238, 243, 0.8)
|
||||
);
|
||||
--notion-red-background: color-mix(in oklab, var(--background) 82%, #fdebec);
|
||||
|
||||
--notion-tag-foreground: var(--foreground);
|
||||
|
||||
Reference in New Issue
Block a user