feat: revamped author card

This commit is contained in:
enscribe 2024-09-12 18:08:19 -07:00
parent c410c499e1
commit 2211c4bbf3
No known key found for this signature in database
GPG key ID: 9BBD5C4114E25322
46 changed files with 566 additions and 426 deletions

View file

@ -1,30 +1,110 @@
---
import type { CollectionEntry } from 'astro:content'
import Link from '@components/Link.astro'
import AvatarComponent from '@/components/ui/avatar'
import { buttonVariants } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import Link from '@components/Link.astro'
import type { CollectionEntry } from 'astro:content'
import { Github, Globe, Linkedin, Twitter } from 'lucide-react'
type Props = {
author: CollectionEntry<'authors'>
linkDisabled?: boolean
}
const { author } = Astro.props
const { name, avatar, bio } = author.data
const { author, linkDisabled = false } = Astro.props
const { name, avatar, bio, pronouns, github, twitter, linkedin, website } =
author.data
---
<div
class="rounded-xl border p-4 transition-colors duration-300 ease-in-out hover:bg-secondary/50"
class="rounded-xl border p-4 transition-colors duration-300 ease-in-out has-[a:hover]:bg-secondary/50"
>
<Link href={`/authors/${author.slug}`} class="flex flex-wrap gap-4">
<AvatarComponent
client:load
src={avatar}
alt={`Avatar of ${name}`}
fallback={name[0]}
className="size-32 rounded-md"
/>
<div class="flex-grow">
<h3 class="mb-1 text-lg font-semibold">{name}</h3>
<p class="text-sm text-muted-foreground">{bio}</p>
<div class="flex flex-wrap gap-4">
<Link
href={`/authors/${author.slug}`}
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 &&
'transition-shadow duration-300 hover:cursor-pointer hover:ring-2 hover:ring-primary',
)}
/>
</Link>
<div class="flex flex-grow flex-col justify-between">
<div>
<div class="flex items-center gap-2">
<h3 class="text-lg font-semibold">{name}</h3>
{
pronouns && (
<span class="text-sm text-muted-foreground">({pronouns})</span>
)
}
</div>
<p class="text-sm text-muted-foreground">{bio}</p>
</div>
<ul class="flex gap-2">
{
github && (
<li>
<Link
href={`https://github.com/${github}`}
aria-label="GitHub"
title="GitHub"
class={buttonVariants({ variant: 'outline', size: 'icon' })}
>
<Github className="size-4" />
</Link>
</li>
)
}
{
twitter && (
<li>
<Link
href={`https://twitter.com/${twitter}`}
aria-label="Twitter"
title="Twitter"
class={buttonVariants({ variant: 'outline', size: 'icon' })}
>
<Twitter className="size-4" />
</Link>
</li>
)
}
{
linkedin && (
<li>
<Link
href={`https://linkedin.com/in/${linkedin}`}
aria-label="LinkedIn"
title="LinkedIn"
class={buttonVariants({ variant: 'outline', size: 'icon' })}
>
<Linkedin className="size-4" />
</Link>
</li>
)
}
{
website && (
<li>
<Link
href={website}
aria-label="Website"
title="Website"
class={buttonVariants({ variant: 'outline', size: 'icon' })}
>
<Globe className="size-4" />
</Link>
</li>
)
}
</ul>
</div>
</Link>
</div>
</div>

View file

@ -1,10 +1,10 @@
---
import type { CollectionEntry } from 'astro:content'
import { formatDate, readingTime, parseAuthors } from '@lib/utils'
import { Image } from 'astro:assets'
import AvatarComponent from '@/components/ui/avatar'
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
import AvatarComponent from '@/components/ui/avatar'
import { formatDate, parseAuthors, readingTime } from '@lib/utils'
import { Image } from 'astro:assets'
import type { CollectionEntry } from 'astro:content'
import Link from './Link.astro'
type Props = {

View file

@ -0,0 +1,53 @@
---
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from '@/components/ui/breadcrumb'
import { HomeIcon } from 'lucide-react'
export interface BreadcrumbItem {
href?: string
label: string
icon?: any
}
interface Props {
items: BreadcrumbItem[]
}
const { items } = Astro.props
---
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="/">
<HomeIcon className="size-4" />
</BreadcrumbLink>
</BreadcrumbItem>
{
items.map((item, index) => (
<>
<BreadcrumbSeparator />
<BreadcrumbItem>
{index === items.length - 1 ? (
<BreadcrumbPage>
{item.icon && <item.icon className="size-4 mr-1" />}
{item.label}
</BreadcrumbPage>
) : (
<BreadcrumbLink href={item.href}>
{item.icon && <item.icon className="size-4 mr-1" />}
{item.label}
</BreadcrumbLink>
)}
</BreadcrumbItem>
</>
))
}
</BreadcrumbList>
</Breadcrumb>

View file

@ -2,8 +2,8 @@
import '../styles/global.css'
import '../styles/katex.css'
import '@fontsource/geist-sans'
import '@fontsource/geist-mono'
import '@fontsource/geist-sans'
import { ViewTransitions } from 'astro:transitions'
@ -28,28 +28,14 @@ const { title, description, image = '/static/twitter-card.png' } = Astro.props
<meta name="title" content={title} />
<meta name="description" content={description} />
<link
rel="apple-touch-icon"
sizes="180x180"
href="/favicons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/favicons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/favicons/favicon-16x16.png"
/>
<link rel="manifest" href="/favicons/site.webmanifest" />
<link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="shortcut icon" href="/favicons/favicon.ico" />
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
<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" />
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#5bbad5" />
<link rel="shortcut icon" href="/favicon.ico" />
<meta name="msapplication-TileColor" content="#da532c" />
<meta name="msapplication-config" content="/favicons/browserconfig.xml" />
<meta name="msapplication-config" content="/browserconfig.xml" />
<meta name="theme-color" content="#121212" />
<meta property="og:type" content="website" />

View file

@ -1,16 +1,10 @@
---
import { ModeToggle } from '@/components/ui/mode-toggle'
import Container from '@components/Container.astro'
import Link from '@components/Link.astro'
import { SITE } from '@consts'
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'
const items = [
{ href: '/blog', label: 'blog' },
{ href: '/authors', label: 'authors' },
{ href: '/about', label: 'about' },
]
---
<header
@ -29,7 +23,7 @@ const items = [
<div class="flex items-center gap-4">
<nav class="flex items-center gap-4 text-sm sm:gap-6">
{
items.map((item) => (
NAV_LINKS.map((item) => (
<Link
href={item.href}
class="capitalize text-foreground/60 transition-colors hover:text-foreground/80"

View file

@ -1,13 +1,13 @@
---
import Link from '@components/Link.astro'
import { ArrowLeft, ArrowRight } from 'lucide-react'
import { buttonVariants } from '@/components/ui/button'
import { cn } from '@/lib/utils'
import Link from '@components/Link.astro'
import { ArrowLeft, ArrowRight } from 'lucide-react'
const { prevPost, nextPost } = Astro.props
---
<div class="mt-8 flex justify-between gap-4">
<div class="flex justify-between gap-4">
<Link
href={prevPost ? `/blog/${prevPost.slug}` : '#'}
class={cn(

View file

@ -1,8 +1,8 @@
---
import { Twitter, Github, Linkedin, Mail, Rss } from 'lucide-react'
import { SITE } from '@consts'
import { buttonVariants } from '@/components/ui/button'
import Link from '@components/Link.astro'
import { SITE } from '@consts'
import { Github, Linkedin, Mail, Rss, Twitter } from 'lucide-react'
---
<ul class="not-prose flex flex-wrap gap-2" role="list">

View file

@ -27,7 +27,7 @@ function buildToc(headings: Heading[]) {
}
---
<details open class="group mb-8 block rounded-xl border p-4 xl:hidden">
<details open class="group block rounded-xl border p-4 xl:hidden">
<summary
class="flex cursor-pointer items-center justify-between text-xl font-semibold"
>

View file

@ -1,6 +1,6 @@
---
import type { Heading } from './TableOfContents.astro'
import Link from './Link.astro'
import type { Heading } from './TableOfContents.astro'
const { heading } = Astro.props
---

View file

@ -1,8 +1,7 @@
import { cn } from '@/lib/utils'
import * as AvatarPrimitive from '@radix-ui/react-avatar'
import * as React from 'react'
import { cn } from '@/lib/utils'
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>

View file

@ -1,9 +1,8 @@
import { cva, type VariantProps } from 'class-variance-authority'
import { cn } from '@/lib/utils'
import { type VariantProps, cva } from 'class-variance-authority'
import { Hash } from 'lucide-react'
import * as React from 'react'
import { cn } from '@/lib/utils'
const badgeVariants = cva(
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs transition-colors focus:outline-none focus:ring focus:ring-ring',
{

View file

@ -1,9 +1,8 @@
import { cn } from '@/lib/utils'
import { ChevronRightIcon, DotsHorizontalIcon } from '@radix-ui/react-icons'
import { Slot } from '@radix-ui/react-slot'
import * as React from 'react'
import { cn } from '@/lib/utils'
const Breadcrumb = React.forwardRef<
HTMLElement,
React.ComponentPropsWithoutRef<'nav'> & {

View file

@ -1,8 +1,7 @@
import { Slot } from '@radix-ui/react-slot'
import { cva, type VariantProps } from 'class-variance-authority'
import * as React from 'react'
import { cn } from '@/lib/utils'
import { Slot } from '@radix-ui/react-slot'
import { type VariantProps, cva } from 'class-variance-authority'
import * as React from 'react'
const buttonVariants = cva(
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',

View file

@ -1,6 +1,5 @@
import * as React from 'react'
import { cn } from '@/lib/utils'
import * as React from 'react'
const Card = React.forwardRef<
HTMLDivElement,

View file

@ -1,3 +1,4 @@
import { cn } from '@/lib/utils'
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
import {
CheckIcon,
@ -6,8 +7,6 @@ import {
} from '@radix-ui/react-icons'
import * as React from 'react'
import { cn } from '@/lib/utils'
const DropdownMenu = DropdownMenuPrimitive.Root
const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
@ -49,7 +48,7 @@ const DropdownMenuSubContent = React.forwardRef<
<DropdownMenuPrimitive.SubContent
ref={ref}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
'bg-popover text-popover-foreground z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className,
)}
{...props}
@ -67,7 +66,7 @@ const DropdownMenuContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md',
'bg-popover text-popover-foreground z-50 min-w-[8rem] overflow-hidden rounded-md border p-1 shadow-md',
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
className,
)}

View file

@ -1,6 +1,3 @@
import { Laptop, Moon, Sun } from 'lucide-react'
import * as React from 'react'
import { Button } from '@/components/ui/button'
import {
DropdownMenu,
@ -8,6 +5,8 @@ import {
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Laptop, Moon, Sun } from 'lucide-react'
import * as React from 'react'
export function ModeToggle() {
const [theme, setThemeState] = React.useState<

View file

@ -1,8 +1,7 @@
import { cn } from '@/lib/utils'
import * as SeparatorPrimitive from '@radix-ui/react-separator'
import * as React from 'react'
import { cn } from '@/lib/utils'
const Separator = React.forwardRef<
React.ElementRef<typeof SeparatorPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>