Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions src/components/papers/PaperHero.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
import { Image } from 'astro:assets'
import type { InferEntrySchema } from 'astro:content'

import { FormattedDate } from 'astro-pure/user'
import { cn } from 'astro-pure/utils'

interface Props {
data: InferEntrySchema<'papers'>
remarkPluginFrontmatter: Record<string, unknown>
}

const {
data: {
title,
description,
draft,
heroImage,
publishDate,
updatedDate,
status,
tags,
language,
comment: enableComment
},
remarkPluginFrontmatter
} = Astro.props

const dateTimeOptions: Intl.DateTimeFormatOptions = {
month: 'short'
}

const statusText =
status === 'reading' ? 'Reading' : status === 'revisit' ? 'Need Revisit' : 'Completed'

const statusClass =
status === 'reading'
? 'border-amber-300/70 bg-amber-100/60 text-amber-700 dark:border-amber-700/60 dark:bg-amber-900/30 dark:text-amber-300'
: status === 'revisit'
? 'border-sky-300/70 bg-sky-100/60 text-sky-700 dark:border-sky-700/60 dark:bg-sky-900/30 dark:text-sky-300'
: 'border-emerald-300/70 bg-emerald-100/60 text-emerald-700 dark:border-emerald-700/60 dark:bg-emerald-900/30 dark:text-emerald-300'
---

{
heroImage && (
<div class='mb-6'>
<Image
alt={heroImage.alt || title}
class='h-auto w-full max-w-[65ch] rounded-2xl object-contain'
fetchpriority='high'
loading='eager'
{...heroImage}
/>
</div>
)
}

{draft && <span class='text-red-500'>(Draft)</span>}

<div class='max-lg:mx-auto'>
<div class='flex flex-wrap items-center gap-2 text-xs leading-6 text-muted-foreground'>
<span class='inline-flex items-center gap-1'>
<FormattedDate class='font-sans' date={publishDate} dateTimeOptions={dateTimeOptions} />
{
updatedDate && (
<>
<span>/</span>
<span>
Update
<FormattedDate
class='font-sans'
date={updatedDate}
dateTimeOptions={dateTimeOptions}
/>
</span>
</>
)
}
</span>
<span class='hidden sm:inline'>•</span>
<span>{remarkPluginFrontmatter.minutesRead}</span>
{
language && (
<>
<span class='hidden sm:inline'>•</span>
<span>{language}</span>
</>
)
}
<span class='hidden sm:inline'>•</span>
<span class={cn('rounded-full border px-2 py-0.5 font-medium', statusClass)}>{statusText}</span>
</div>

<h1 class='mt-4 text-2xl font-medium sm:mb-2 sm:mt-6 sm:text-3xl'>{title}</h1>

<blockquote class='mt-3 text-sm italic text-muted-foreground'>
<q>{description}</q>
</blockquote>

{!!tags.length && (
<div class='mt-3 flex flex-wrap gap-2 text-xs'>
{tags.map((tag) => (
<a
aria-label={`View more papers with the tag ${tag}`}
class='rounded-full border bg-muted px-2 py-0.5 text-muted-foreground transition-colors hover:text-primary'
href={`/papers/tags/${tag}`}
>
#{tag}
</a>
))}
</div>
)}

{!draft && enableComment && (
<p class='mt-3 text-xs text-muted-foreground'>
阅读后欢迎在评论区讨论你对这篇论文的理解和分歧。
</p>
)}
</div>

<div class='mt-4 w-1/2 border-t max-lg:mx-auto sm:mt-6 sm:w-1/3'></div>
66 changes: 66 additions & 0 deletions src/components/papers/PaperMeta.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
import type { InferEntrySchema } from 'astro:content'
import { cn } from 'astro-pure/utils'

interface Props {
data: InferEntrySchema<'papers'>
class?: string
}

const {
data: { paperLink, pdfLink, codeLink, authors, venue, year },
class: className
} = Astro.props
---

<div class={cn('rounded-xl border bg-muted/20 p-4', className)}>
<h2 class='text-sm font-semibold uppercase tracking-wide text-muted-foreground'>Paper Reference</h2>

<div class='mt-2 flex flex-wrap items-center gap-2 text-sm'>
<a
href={paperLink}
target='_blank'
rel='noopener noreferrer'
class='rounded-full border bg-background px-3 py-1 transition-colors hover:text-primary'
>
Original Link ↗
</a>
{
pdfLink && (
<a
href={pdfLink}
target='_blank'
rel='noopener noreferrer'
class='rounded-full border bg-background px-3 py-1 transition-colors hover:text-primary'
>
PDF ↗
</a>
)
}
{
codeLink && (
<a
href={codeLink}
target='_blank'
rel='noopener noreferrer'
class='rounded-full border bg-background px-3 py-1 transition-colors hover:text-primary'
>
Code ↗
</a>
)
}
</div>

<div class='mt-3 space-y-1 text-sm text-muted-foreground'>
<p>
<span class='font-medium text-foreground'>Authors:</span>
{authors.join(', ')}
</p>
<p>
<span class='font-medium text-foreground'>Venue:</span>
{venue || 'N/A'}
{' · '}
{year}
</p>
</div>
</div>
108 changes: 108 additions & 0 deletions src/components/papers/PaperPreview.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
---
import type { CollectionEntry } from 'astro:content'
import { FormattedDate } from 'astro-pure/user'
import { cn } from 'astro-pure/utils'

interface Props {
paper: CollectionEntry<'papers'>
detailed?: boolean
class?: string
}

const { paper, detailed = false, class: className } = Astro.props

const {
id,
data: { title, description, publishDate, updatedDate, status, tags, venue, year, paperLink, draft }
} = paper

const postDate = updatedDate ?? publishDate

const statusText =
status === 'reading' ? 'Reading' : status === 'revisit' ? 'Need Revisit' : 'Completed'

const statusClass =
status === 'reading'
? 'border-amber-300/70 bg-amber-100/60 text-amber-700 dark:border-amber-700/60 dark:bg-amber-900/30 dark:text-amber-300'
: status === 'revisit'
? 'border-sky-300/70 bg-sky-100/60 text-sky-700 dark:border-sky-700/60 dark:bg-sky-900/30 dark:text-sky-300'
: 'border-emerald-300/70 bg-emerald-100/60 text-emerald-700 dark:border-emerald-700/60 dark:bg-emerald-900/30 dark:text-emerald-300'
---

<li
class={cn(
'group rounded-2xl border bg-background px-5 py-3 transition-colors duration-200 hover:bg-muted max-sm:px-4',
detailed ? 'sm:py-4' : 'py-2.5',
className
)}
>
<a href={`/papers/${id}`} class='block no-underline'>
<div class='flex flex-wrap items-center gap-2 text-xs text-muted-foreground'>
<FormattedDate class='font-sans' date={postDate} />
<span class='hidden sm:inline'>•</span>
<span>{year}</span>
{venue && (
<>
<span class='hidden sm:inline'>•</span>
<span>{venue}</span>
</>
)}
<span class='hidden sm:inline'>•</span>
<span
class={cn(
'rounded-full border px-2 py-0.5 font-medium',
statusClass
)}
>
{statusText}
</span>
</div>

<div class='mt-1.5 flex items-start justify-between gap-3'>
<h3 class={cn('font-medium leading-6 group-hover:text-primary', detailed ? 'text-lg' : 'text-base')}>
{draft && <span class='text-red-500'>(Draft) </span>}
{title}
</h3>
<svg
xmlns='http://www.w3.org/2000/svg'
width='16'
height='16'
viewBox='0 0 24 24'
fill='none'
stroke-width='2.5'
stroke-linecap='round'
stroke-linejoin='round'
class='mt-1 shrink-0 stroke-muted-foreground transition-colors group-hover:stroke-primary'
>
<line x1='5' y1='12' x2='19' y2='12'></line>
<polyline points='12 5 19 12 12 19'></polyline>
</svg>
</div>

<p class={cn('mt-1 line-clamp-2 text-sm text-muted-foreground', detailed && 'line-clamp-3')}>
{description}
</p>
</a>

<div class='mt-2.5 flex flex-wrap items-center gap-2 text-xs'>
<a
href={paperLink}
target='_blank'
rel='noopener noreferrer'
class='rounded-full border px-2 py-0.5 text-muted-foreground transition-colors hover:text-primary'
>
Original Paper ↗
</a>
{
tags.map((tag) => (
<a
href={`/papers/tags/${tag}`}
class='rounded-full border bg-muted px-2 py-0.5 text-muted-foreground transition-colors hover:text-primary'
data-astro-prefetch
>
#{tag}
</a>
))
}
</div>
</li>
38 changes: 37 additions & 1 deletion src/content.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,40 @@ const blog = defineCollection({
})
})

export const collections = { blog }
const papers = defineCollection({
// Load Markdown and MDX files in the `src/content/papers/` directory.
loader: glob({ base: './src/content/papers', pattern: '**/*.{md,mdx}' }),
schema: ({ image }) =>
z.object({
// Required
title: z.string().max(120),
description: z.string().max(280),
publishDate: z.coerce.date(),
paperLink: z.string().url(),
authors: z.array(z.string()).min(1),
year: z.number().int(),
// Optional
updatedDate: z.coerce.date().optional(),
venue: z.string().optional(),
pdfLink: z.string().url().optional(),
codeLink: z.string().url().optional(),
heroImage: z
.object({
src: image(),
alt: z.string().optional(),
inferSize: z.boolean().optional(),
width: z.number().optional(),
height: z.number().optional(),
color: z.string().optional()
})
.optional(),
tags: z.array(z.string()).default([]).transform(removeDupsAndLowerCase),
status: z.enum(['reading', 'completed', 'revisit']).default('completed'),
language: z.string().optional(),
draft: z.boolean().default(false),
comment: z.boolean().default(true),
featured: z.boolean().default(false)
})
})

export const collections = { blog, papers }
Loading