refactor: rebase from hard fork into soft fork that follows upstream

This commit is contained in:
z0x 2025-03-23 19:17:50 -04:00
parent 021accda4e
commit 8560239425
59 changed files with 2419 additions and 11935 deletions

View file

@ -1,70 +0,0 @@
---
import Link from '@/components/Link.astro'
import AvatarComponent from '@/components/ui/avatar'
import { cn } from '@/lib/utils'
import type { SocialLink } from '@/types'
import type { CollectionEntry } from 'astro:content'
import SocialIcons from './SocialIcons.astro'
type Props = {
author: CollectionEntry<'authors'>
linkDisabled?: boolean
}
const { author, linkDisabled = false } = Astro.props
const {
name,
avatar,
bio,
pronouns,
github,
twitter,
linkedin,
website,
mail,
} = author.data
const socialLinks: SocialLink[] = [
website && { href: website, label: 'Website' },
github && { href: github, label: 'GitHub' },
twitter && { href: twitter, label: 'Twitter' },
linkedin && { href: linkedin, label: 'LinkedIn' },
mail && { href: `mailto:${mail}`, label: 'Email' },
].filter(Boolean) as SocialLink[]
---
<div
class="has-[a:hover]:bg-secondary/50 overflow-hidden rounded-xl border p-4 transition-colors duration-300 ease-in-out"
>
<div class="flex flex-wrap gap-4">
<Link
href={`/authors/${author.id}`}
class={cn('block', linkDisabled && 'pointer-events-none')}
>
<AvatarComponent
client:load
src={avatar}
alt={`Avatar of ${name}`}
fallback={name[0]}
className={cn(
'size-32 rounded-md',
!linkDisabled &&
'hover:ring-primary transition-shadow duration-300 hover:cursor-pointer hover:ring-2',
)}
/>
</Link>
<div class="flex grow flex-col justify-between gap-y-4">
<div>
<div class="flex flex-wrap items-center gap-x-2">
<h3 class="text-lg font-medium">{name}</h3>
{
pronouns && (
<span class="text-muted-foreground text-sm">({pronouns})</span>
)
}
</div>
<p class="text-muted-foreground text-sm">{bio}</p>
</div>
<SocialIcons links={socialLinks} />
</div>
</div>
</div>

View file

@ -1,10 +1,6 @@
---
import AvatarComponent from '@/components/ui/avatar'
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
import { parseAuthors } from '@/lib/server-utils'
import { formatDate, readingTime } from '@/lib/utils'
import { Icon } from 'astro-icon/components'
import { Image } from 'astro:assets'
import type { CollectionEntry } from 'astro:content'
import Link from './Link.astro'
@ -19,19 +15,15 @@ const { entry } = Astro.props as {
const formattedDate = formatDate(entry.data.date)
const readTime = readingTime(entry.body!)
const authors = await parseAuthors(entry.data.authors ?? [])
---
<div
class="hover:bg-secondary/50 rounded-xl border p-4 transition-colors duration-300 ease-in-out"
class="not-prose hover:bg-secondary/50 rounded-xl border p-4 transition-colors duration-300 ease-in-out"
>
<Link
href={`/${entry.collection}/${entry.id}`}
class="flex flex-col gap-4 sm:flex-row"
>
<Link href={`/blog/${entry.id}`} class="flex flex-col gap-4 sm:flex-row">
{
entry.data.image && (
<div class="max-w-[200px] sm:shrink-0">
<div class="max-w-[200px] sm:flex-shrink-0">
<Image
src={entry.data.image}
alt={entry.data.title}
@ -42,8 +34,8 @@ const authors = await parseAuthors(entry.data.authors ?? [])
</div>
)
}
<div class="grow">
<h3 class="mb-1 text-lg font-medium">
<div class="flex-grow">
<h3 class="mb-1 text-lg font-semibold">
{entry.data.title}
</h3>
<p class="text-muted-foreground mb-2 text-sm">
@ -52,41 +44,10 @@ const authors = await parseAuthors(entry.data.authors ?? [])
<div
class="text-muted-foreground mb-2 flex flex-wrap items-center gap-x-2 text-xs"
>
{
authors.length > 0 && (
<>
{authors.map((author) => (
<div class="flex items-center gap-x-1.5">
<AvatarComponent
client:load
src={author.avatar}
alt={author.name}
fallback={author.name[0]}
className="size-5 rounded-full"
/>
<span>{author.name}</span>
</div>
))}
<Separator orientation="vertical" className="h-4!" />
</>
)
}
<span>{formattedDate}</span>
<Separator orientation="vertical" className="h-4!" />
<Separator orientation="vertical" className="h-4" />
<span>{readTime}</span>
</div>
{
entry.data.tags && (
<div class="flex flex-wrap gap-2">
{entry.data.tags.map((tag) => (
<Badge variant="secondary" className="flex items-center gap-x-1">
<Icon name="lucide:hash" class="size-3" />
{tag}
</Badge>
))}
</div>
)
}
</div>
</Link>
</div>

View file

@ -2,7 +2,6 @@
import Container from '@/components/Container.astro'
import { Separator } from '@/components/ui/separator'
import { SOCIAL_LINKS } from '@/consts'
import Link from './Link.astro'
import SocialIcons from './SocialIcons.astro'
---
@ -13,16 +12,11 @@ import SocialIcons from './SocialIcons.astro'
>
<div class="flex items-center gap-x-2">
<span class="text-muted-foreground text-center text-sm">
&copy; {new Date().getFullYear()} All rights reserved.
&copy; {new Date().getFullYear()} • z0x
</span>
<Separator orientation="vertical" className="h-4!" />
<p class="text-muted-foreground text-center text-sm">
Made with 🤍 by <Link
href="https://github.com/jktrn"
class="text-foreground"
external
underline>enscribe</Link
>!
All rights reserved.
</p>
</div>
<SocialIcons links={SOCIAL_LINKS} />

View file

@ -1,4 +1,6 @@
---
import '@fontsource-variable/geist'
import '@fontsource-variable/geist-mono'
import '../styles/global.css'
import '../styles/typography.css'
@ -22,38 +24,48 @@ const { title, description, image = '/static/twitter-card.png' } = Astro.props
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no" />
<meta
name="format-detection"
content="telephone=no,date=no,address=no,email=no,url=no"
/>
<link rel="canonical" href={canonicalURL} />
<link rel="sitemap" href="/sitemap-index.xml" />
<title>{title}</title>
<meta name="title" content={title} />
<meta name="apple-mobile-web-app-title" content={title} />
<meta name="description" content={description} />
<meta name="author" content={SITE.title} />
<link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<meta name="apple-mobile-web-app-title" content="astro-erudite" />
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="manifest" href="/site.webmanifest" />
<meta name="theme-color" content="#121212" media="(prefers-color-scheme: dark)" />
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
<meta
name="theme-color"
content="#121212"
media="(prefers-color-scheme: dark)"
/>
<meta
name="theme-color"
content="#ffffff"
media="(prefers-color-scheme: light)"
/>
<meta property="og:type" content="website" />
<meta property="og:url" content={Astro.url} />
<meta property="og:site_name" content={SITE.title} />
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={new URL(image, Astro.url)} />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={Astro.url} />
<meta property="twitter:title" content={title} />
<meta property="twitter:description" content={description} />
<meta property="twitter:image" content={new URL(image, Astro.url)} />
<ClientRouter />

View file

@ -1,11 +1,8 @@
---
import Container from '@/components/Container.astro'
import Link from '@/components/Link.astro'
import MobileMenu from '@/components/ui/mobile-menu'
import { ModeToggle } from '@/components/ui/mode-toggle'
import { NAV_LINKS, SITE } from '@/consts'
import { Image } from 'astro:assets'
import logo from '../../public/static/logo.svg'
import { SITE } from '@/consts'
---
<header
@ -15,26 +12,12 @@ import logo from '../../public/static/logo.svg'
<Container>
<div class="flex flex-wrap items-center justify-between gap-4 py-4">
<Link
href="/"
href="https://z0x.ca"
class="hover:text-primary flex shrink-0 items-center gap-2 text-xl font-medium transition-colors duration-300"
>
<Image src={logo} alt="Logo" class="size-8" />
{SITE.title}
</Link>
<div class="flex items-center gap-2 md:gap-4">
<nav class="hidden items-center gap-4 text-sm sm:gap-6 md:flex">
{
NAV_LINKS.map((item) => (
<Link
href={item.href}
class="text-foreground/60 hover:text-foreground/80 capitalize transition-colors"
>
{item.label}
</Link>
))
}
</nav>
<MobileMenu client:load transition:persist />
<ModeToggle client:load transition:persist />
</div>
</div>

View file

@ -1,53 +0,0 @@
---
import Link from '@/components/Link.astro'
import { Badge } from '@/components/ui/badge'
import { Image } from 'astro:assets'
import type { CollectionEntry } from 'astro:content'
type Props = {
project: CollectionEntry<'projects'>
}
const { project } = Astro.props
---
<div
class="hover:bg-secondary/50 rounded-xl border p-4 transition-colors duration-300 ease-in-out"
>
<Link
href={project.data.link}
class="flex flex-col gap-4 sm:flex-row"
external
>
{
project.data.image && (
<div class="max-w-[200px] sm:shrink-0">
<Image
src={project.data.image}
alt={project.data.name}
width={1200}
height={630}
class="object-cover"
/>
</div>
)
}
<div class="grow">
<h3 class="mb-1 text-lg font-medium">
{project.data.name}
</h3>
<p class="text-muted-foreground mb-2 text-sm">
{project.data.description}
</p>
{
project.data.tags && (
<div class="flex flex-wrap gap-2">
{project.data.tags.map((tag: string) => (
<Badge variant="secondary">{tag}</Badge>
))}
</div>
)
}
</div>
</Link>
</div>

View file

@ -17,6 +17,7 @@ function buildToc(headings: Heading[]): Heading[] {
const toc: Heading[] = []
const stack: Heading[] = []
// biome-ignore lint/complexity/noForEach: <explanation>
headings.forEach((h) => {
const heading = { ...h, subheadings: [] }

View file

@ -1,60 +0,0 @@
import { useState, useEffect } from 'react'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { NAV_LINKS } from '@/consts'
import { Menu } from 'lucide-react'
const MobileMenu = () => {
const [isOpen, setIsOpen] = useState(false)
useEffect(() => {
const handleViewTransitionStart = () => {
setIsOpen(false)
}
document.addEventListener('astro:before-swap', handleViewTransitionStart)
return () => {
document.removeEventListener(
'astro:before-swap',
handleViewTransitionStart,
)
}
}, [])
return (
<DropdownMenu open={isOpen} onOpenChange={setIsOpen} modal={false}>
<DropdownMenuTrigger asChild>
<Button
variant="outline"
size="icon"
className="md:hidden"
title="Menu"
>
<Menu className="h-5 w-5" />
<span className="sr-only">Toggle menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="bg-background">
{NAV_LINKS.map((item) => (
<DropdownMenuItem key={item.href} asChild>
<a
href={item.href}
className="w-full text-lg font-medium capitalize"
onClick={() => setIsOpen(false)}
>
{item.label}
</a>
</DropdownMenuItem>
))}
</DropdownMenuContent>
</DropdownMenu>
)
}
export default MobileMenu