Skip to content

Commit

Permalink
update styles and finish blog templates
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrkulpinski committed Jul 10, 2024
1 parent e747e72 commit 5d18be2
Show file tree
Hide file tree
Showing 10 changed files with 172 additions and 53 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<a href="https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/piotrkulpinski/openalternative">
<img alt="open in devcontainer" src="https://img.shields.io/static/v1?label=Dev%20Containers&message=Enabled&color=blue&logo=visualstudiocode" />
</a>
<a href="https://news.ycombinator.com/item?id=39639386"><img src="https://img.shields.io/badge/Hacker%20News-156-%23FF6600" alt="Hacker News"></a>
</p>

<p align="center">
Expand Down
5 changes: 4 additions & 1 deletion app/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import { Series } from "./Series"

export const Footer = ({ children, className, ...props }: HTMLAttributes<HTMLElement>) => {
return (
<footer className={cx("flex flex-col justify-between gap-4", className)} {...props}>
<footer
className={cx("relative z-20 flex flex-col justify-between gap-4", className)}
{...props}
>
<Series className="text-sm/normal md:gap-x-4">
<H6 as="strong">Explore:</H6>

Expand Down
24 changes: 21 additions & 3 deletions app/components/Grid.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,24 @@
import type { HTMLAttributes } from "react"
import { cx } from "~/utils/cva"
import { cva, cx, VariantProps } from "~/utils/cva"

export const Grid = ({ className, ...props }: HTMLAttributes<HTMLElement>) => {
return <div className={cx("grid-auto-fill-md grid gap-5", className)} {...props} />
const gridVariants = cva({
base: "grid gap-5",

variants: {
size: {
sm: "grid-auto-fill-sm",
md: "grid-auto-fill-md",
lg: "grid-auto-fill-lg",
},
},

defaultVariants: {
size: "md",
},
})

type GridProps = Omit<HTMLAttributes<HTMLElement>, "size"> & VariantProps<typeof gridVariants>

export const Grid = ({ className, size, ...props }: GridProps) => {
return <div className={cx(gridVariants({ size, className }))} {...props} />
}
8 changes: 5 additions & 3 deletions app/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,15 @@ export const Header = ({ className, ...props }: HTMLAttributes<HTMLElement>) =>
return (
<Container
className={cx(
"group/menu fixed top-[var(--header-top)] inset-x-0 z-40 backdrop-blur-xl bg-background/95",
"max-lg:data-[state=open]:bg-background/75",
"group/menu fixed top-[var(--header-top)] inset-x-0 z-40 duration-300",
"max-lg:data-[state=open]:bg-background/90 max-lg:data-[state=open]:backdrop-blur-sm",
className,
)}
data-state={isNavOpen ? "open" : "close"}
{...props}
>
<div className="fixed inset-x-0 h-[calc(var(--header-top)+var(--header-height)+2rem)] pointer-events-none bg-gradient-to-b from-background via-background to-transparent lg:h-[calc(var(--header-top)+var(--header-height)+3rem)]" />

<div
className={cx(
"flex flex-wrap items-center py-3.5 gap-x-3 text-sm h-[var(--header-height)] isolate overflow-clip duration-300 lg:gap-4",
Expand Down Expand Up @@ -82,7 +84,7 @@ export const Header = ({ className, ...props }: HTMLAttributes<HTMLElement>) =>
</svg>
</button>

<Breadcrumbs className="mr-auto" />
<Breadcrumbs className="mr-auto flex-1" />

<nav className="contents max-lg:hidden">
<DropdownMenu modal={false}>
Expand Down
57 changes: 25 additions & 32 deletions app/components/Intro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import type { HTMLAttributes, ReactNode } from "react"
import { VariantProps, cva, cx } from "~/utils/cva"
import { Heading, type HeadingProps } from "./Heading"
import { Prose } from "./Prose"
import { Series } from "./Series"

const introVariants = cva({
base: "flex w-full flex-col gap-y-2",
Expand All @@ -22,43 +21,37 @@ const introVariants = cva({

type IntroProps = Omit<HTMLAttributes<HTMLElement>, "title" | "prefix"> &
VariantProps<typeof introVariants> & {
title: ReactNode
title?: ReactNode
description?: ReactNode
prefix?: ReactNode
suffix?: ReactNode
headingProps?: HeadingProps
}

export const Intro = ({
children,
className,
alignment,
title,
description,
prefix,
suffix,
headingProps = { size: "h1" },
...props
}: IntroProps) => {
const Intro = ({ children, className, alignment, title, description, ...props }: IntroProps) => {
return (
<div className={cx(introVariants({ alignment, className }))} {...props}>
<Series size="lg" className="relative w-full">
{prefix}
{title && <Heading {...headingProps}>{title}</Heading>}
{suffix}

<div className="absolute -bottom-2 inset-x-0 h-8 bg-gradient-to-t from-background/40 to-transparent pointer-events-none select-none" />
</Series>

{description && (
<Prose className="max-w-2xl">
<h2 className="!text-base !font-normal !tracking-normal !text-secondary md:!text-lg">
{description}
</h2>
</Prose>
)}

{title && <IntroTitle>{title}</IntroTitle>}
{description && <IntroDescription>{description}</IntroDescription>}
{children}
</div>
)
}

const IntroTitle = ({ size = "h1", ...props }: HTMLAttributes<HTMLElement> & HeadingProps) => {
return (
<div className="relative">
<Heading size={size} {...props} />
<div className="absolute -bottom-2 inset-x-0 h-8 bg-gradient-to-t from-background/40 to-transparent pointer-events-none select-none" />
</div>
)
}

const IntroDescription = ({ children, className, ...props }: HTMLAttributes<HTMLElement>) => {
return (
<Prose className={cx("max-w-2xl", className)} {...props}>
<h2 className="!text-base !font-normal !tracking-normal !text-foreground/70 md:!text-lg">
{children}
</h2>
</Prose>
)
}

export { Intro, IntroTitle, IntroDescription }
56 changes: 56 additions & 0 deletions app/components/records/PostRecord.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { Link, unstable_useViewTransitionState } from "@remix-run/react"
import type { HTMLAttributes } from "react"
import { Card } from "../Card"
import { H4 } from "../Heading"
import { Post } from "content-collections"
import { formatDate } from "@curiousleaf/utils"

type PostRecordProps = HTMLAttributes<HTMLElement> & {
post: Post
}

export const PostRecord = ({ className, post, ...props }: PostRecordProps) => {
const to = `/blog/${post._meta.path}`
const vt = unstable_useViewTransitionState(to)

return (
<Card style={{ viewTransitionName: vt ? `post-${post._meta.path}` : undefined }} asChild>
<Link to={to} prefetch="intent" unstable_viewTransition {...props}>
<Card.Header>
<H4
as="h3"
className="!leading-snug"
style={{ viewTransitionName: vt ? `post-${post._meta.path}-title` : undefined }}
>
{post.title}
</H4>
</Card.Header>

{post.description && (
<Card.Description
style={{ viewTransitionName: vt ? `post-${post._meta.path}-description` : undefined }}
>
{post.description}
</Card.Description>
)}

{post.datePublished && (
<Card.Footer
style={{ viewTransitionName: vt ? `post-${post._meta.path}-date` : undefined }}
>
<time dateTime={post.datePublished}>{formatDate(new Date(post.datePublished))}</time>
</Card.Footer>
)}

{post.image && (
<img
src={post.image}
alt=""
className="-m-5 mt-0 w-[calc(100%+2.5rem)] max-w-none"
style={{ viewTransitionName: vt ? `post-${post._meta.path}-image` : undefined }}
/>
)}
</Link>
</Card>
)
}
56 changes: 50 additions & 6 deletions app/routes/blog.$slug.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { formatDate } from "@curiousleaf/utils"
import { LoaderFunctionArgs } from "@remix-run/node"
import { json, MetaFunction, useLoaderData } from "@remix-run/react"
import {
json,
MetaFunction,
unstable_useViewTransitionState,
useLoaderData,
} from "@remix-run/react"
import { allPosts, Post } from "content-collections"
import { BackButton } from "~/components/BackButton"
import { BreadcrumbsLink } from "~/components/Breadcrumbs"
import { Intro } from "~/components/Intro"
import { Intro, IntroDescription, IntroTitle } from "~/components/Intro"
import { Markdown } from "~/components/Markdown"
import { getMetaTags } from "~/utils/meta"

export const handle = {
Expand Down Expand Up @@ -45,11 +52,48 @@ export const loader = async ({ params: { slug } }: LoaderFunctionArgs) => {
}

export default function BlogPostPage() {
const { meta } = useLoaderData<typeof loader>()
const { post } = useLoaderData<typeof loader>()

const vt = unstable_useViewTransitionState(`/blog/${post._meta.path}`)

return (
<>
<Intro {...meta} />
</>
<div
className="flex flex-col gap-12 max-w-prose"
style={{ viewTransitionName: vt ? `post-${post._meta.path}` : undefined }}
>
<Intro>
<IntroTitle
style={{ viewTransitionName: vt ? `post-${post._meta.path}-title` : undefined }}
>
{post.title}
</IntroTitle>

<IntroDescription
style={{ viewTransitionName: vt ? `post-${post._meta.path}-description` : undefined }}
>
{post.description}
</IntroDescription>

{post.datePublished && (
<p
style={{ viewTransitionName: vt ? `post-${post._meta.path}-date` : undefined }}
className="mt-2 text-muted"
>
<time dateTime={post.datePublished}>{formatDate(new Date(post.datePublished))}</time>
</p>
)}
</Intro>

{post.image && (
<img
src={post.image}
alt={post.title}
className="w-full h-auto object-cover rounded-lg"
style={{ viewTransitionName: vt ? `post-${post._meta.path}-image` : undefined }}
/>
)}

<Markdown>{post.content}</Markdown>
</div>
)
}
12 changes: 4 additions & 8 deletions app/routes/blog._index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { json, Link, MetaFunction, useLoaderData } from "@remix-run/react"
import { json, MetaFunction, useLoaderData } from "@remix-run/react"
import { allPosts } from "content-collections"
import { Grid } from "~/components/Grid"
import { Intro } from "~/components/Intro"
import { PostRecord } from "~/components/records/PostRecord"
import { getMetaTags } from "~/utils/meta"

export const meta: MetaFunction<typeof loader> = ({ matches, data, location }) => {
Expand Down Expand Up @@ -32,14 +33,9 @@ export default function BlogPage() {
<Intro {...meta} />

{!!allPosts.length ? (
<Grid>
<Grid size="lg">
{allPosts.map(post => (
<li key={post._meta.path}>
<Link to={`/blog/${post._meta.path}`} unstable_viewTransition>
<h3>{post.title}</h3>
<p>{post.description}</p>
</Link>
</li>
<PostRecord key={post._meta.path} post={post} />
))}
</Grid>
) : (
Expand Down
3 changes: 3 additions & 0 deletions content-collections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ const posts = defineCollection({
schema: z => ({
title: z.string(),
description: z.string(),
image: z.string().optional(),
datePublished: z.string(),
dateModified: z.string().optional(),
}),
})

Expand Down
3 changes: 3 additions & 0 deletions tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export default {
fontFamily: {
sans: ["Uncut Sans", ...defaultTheme.fontFamily.sans],
},
scale: {
flip: "-1",
},
gridColumns: {
DEFAULT: "16rem",
xxs: "10rem",
Expand Down

0 comments on commit 5d18be2

Please sign in to comment.