-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 from EmilEinarsen/feat/blog
feat: ✨ blog like news pages
- Loading branch information
Showing
58 changed files
with
995 additions
and
426 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { HomeIcon } from '@heroicons/react/24/solid' | ||
import { Link } from '@remix-run/react' | ||
import React from 'react' | ||
import { useRouteData } from '~/hooks/useRouteData' | ||
import { clsx } from '~/utils/utils' | ||
|
||
interface BreadcrumbProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> {} | ||
|
||
export const Breadcrumb = (props: BreadcrumbProps) => { | ||
const { post } = useRouteData() | ||
|
||
return ( | ||
<nav | ||
{...props} | ||
className={clsx( | ||
'w-min', | ||
props.className | ||
)} | ||
aria-label="Breadcrumb" | ||
> | ||
<ol role="list" className="flex items-center space-x-4"> | ||
<li> | ||
<div> | ||
<Link to='/' className="text-gray-400 hover:text-gray-500 whitespace-nowrap"> | ||
<HomeIcon className="flex-shrink-0 w-5 h-5" aria-hidden="true" /> | ||
<span className="sr-only">Home</span> | ||
</Link> | ||
</div> | ||
</li> | ||
{post?.breadcrumbs.map((page, i, pages) => ( | ||
<li key={page.name}> | ||
<div className="flex items-center"> | ||
<svg | ||
className="flex-shrink-0 w-5 h-5 text-gray-300" | ||
fill="currentColor" | ||
viewBox="0 0 20 20" | ||
aria-hidden="true" | ||
> | ||
<path d="M5.555 17.776l8-16 .894.448-8 16-.894-.448z" /> | ||
</svg> | ||
<Link | ||
to={page.href} | ||
className="ml-4 text-sm font-medium text-gray-500 hover:text-gray-700 whitespace-nowrap aria-[current='page']:" | ||
aria-current={i === pages.length-1 ? 'page' : undefined} | ||
> | ||
{page.name} | ||
</Link> | ||
</div> | ||
</li> | ||
))} | ||
</ol> | ||
</nav> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import { ArrowLongLeftIcon, ArrowLongRightIcon } from '@heroicons/react/24/solid' | ||
import { Link, useLocation } from '@remix-run/react' | ||
import { useMemo } from 'react' | ||
import { clsx } from '~/utils/utils' | ||
|
||
interface PaginationProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> { | ||
currentPage: number | ||
maxPage: number | ||
} | ||
|
||
export const Pagination = ({ currentPage, maxPage, ...props }: PaginationProps) => { | ||
const { pathname } = useLocation() | ||
|
||
const pagination = useMemo(() => { | ||
const previousPage = Math.max(currentPage - 1, 1); | ||
const nextPage = Math.min(currentPage + 1, maxPage); | ||
|
||
return { | ||
previous: { | ||
disabled: previousPage <= 1, | ||
link: `${pathname}?page=${previousPage}` | ||
}, | ||
pages: [...Array(maxPage+1).keys()].slice(1).map(i => ({ label: i, value: i, href: `${pathname}?page=${i}` })), | ||
next: { | ||
disabled: currentPage === maxPage, // or some empty state indicator | ||
link: `${pathname}?page=${nextPage}` | ||
} | ||
} | ||
}, [currentPage, maxPage]); | ||
|
||
return ( | ||
<nav className={clsx( | ||
'flex items-center justify-between px-4 border-t border-gray-200 sm:px-0', | ||
props.className | ||
)}> | ||
<div className="flex flex-1 w-0 -mt-px"> | ||
<Link | ||
to={pagination.previous.link} | ||
className="inline-flex items-center pt-4 pr-1 text-sm font-medium text-gray-500 border-transparent hover:border-gray-300 hover:text-gray-700" | ||
aria-disabled={pagination.previous.disabled} | ||
> | ||
<ArrowLongLeftIcon className="w-5 h-5 mr-3 text-gray-400" aria-hidden="true" /> | ||
Previous | ||
</Link> | ||
</div> | ||
<div className="hidden md:-mt-px md:flex"> | ||
{pagination.pages.map(page => | ||
<Link | ||
to={page.href} | ||
className={clsx( | ||
"inline-flex items-center border-t-2 px-4 pt-4 text-sm font-medium", | ||
currentPage === page.value && 'border-indigo-500 text-indigo-600', | ||
currentPage !== page.value && 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300' | ||
)} | ||
> | ||
{page.label} | ||
</Link> | ||
)} | ||
</div> | ||
<div className="flex justify-end flex-1 w-0 -mt-px"> | ||
<Link | ||
to={pagination.next.link} | ||
className="inline-flex items-center pt-4 pr-1 text-sm font-medium text-gray-500 border-t-2 border-transparent hover:border-gray-300 hover:text-gray-700" | ||
aria-disabled={pagination.next.disabled} | ||
> | ||
Next | ||
<ArrowLongRightIcon className="w-5 h-5 ml-3 text-gray-400" aria-hidden="true" /> | ||
</Link> | ||
</div> | ||
</nav> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import { Link } from '@remix-run/react' | ||
import { clsx, dateFormat } from '~/utils/utils' | ||
import { Image } from '../core/image' | ||
|
||
import type { Post } from '~/loaders/groq-fragments/documents/blog-post' | ||
|
||
interface BlogPostProps extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement> { | ||
post: Post | ||
withoutImage?: boolean | ||
} | ||
|
||
export const BlogPost = ({ post, withoutImage, ...props }: BlogPostProps) => { | ||
return ( | ||
<article | ||
key={post.id} | ||
{...props} | ||
className={clsx( | ||
'relative flex flex-col gap-8 isolate lg:flex-row', | ||
props.className | ||
)} | ||
> | ||
<div className="relative aspect-[16/9] sm:aspect-[2/1] lg:aspect-square lg:w-48 lg:shrink-0"> | ||
<Image | ||
image={post.image!} | ||
alt="" | ||
background | ||
className="object-cover rounded-2xl bg-gray-50" | ||
/> | ||
<div className="absolute inset-0 rounded-2xl ring-1 ring-inset ring-gray-900/10" /> | ||
</div> | ||
<div> | ||
<div className="flex items-center text-xs gap-x-4"> | ||
<time dateTime={post.publishedAt} className="text-gray-500"> | ||
{dateFormat(post.publishedAt)} | ||
</time> | ||
<p | ||
/* href={post.category.href} */ | ||
className="relative z-10 rounded-full bg-gray-50 px-3 py-1.5 font-medium text-gray-600"/* hover:bg-gray-100 */ | ||
> | ||
{post.category.title} | ||
</p> | ||
</div> | ||
<div className="relative max-w-xl group"> | ||
<h3 className="mt-3 text-lg font-semibold leading-6 text-gray-900 group-hover:text-gray-600"> | ||
<Link to={post.href.slug}> | ||
<span className="absolute inset-0" /> | ||
{post.title} | ||
</Link> | ||
</h3> | ||
<p className="mt-5 text-sm leading-6 text-gray-600">{post.description}</p> | ||
</div> | ||
<div className="flex pt-6 mt-6 border-t border-gray-900/5"> | ||
<div className="relative flex items-center gap-x-4"> | ||
<Image image={post.author.image} className="w-10 h-10 rounded-full bg-gray-50" /> | ||
<div className="text-sm leading-6"> | ||
<p className="font-semibold text-gray-900"> | ||
<span /* href={post.author.slug} */> | ||
{post.author.name} | ||
</span> | ||
</p> | ||
<p className="text-gray-600">{post.author.role}</p> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</article> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { ModuleProps } from '.' | ||
import { BlogPost } from '../app/Post' | ||
|
||
const BlogPosts = (props: ModuleProps<'blog-posts'>) => { | ||
return ( | ||
<section> | ||
<div className='max-w-6xl py-16 mx-auto sm:py-24 sm:px-6'> | ||
<div className='mx-auto mb-16 prose prose-xl text-center sm:mb-24 prose-gray'> | ||
<h2>{props.data.title}</h2> | ||
{props.data.subtitle && <p>{props.data.subtitle}</p>} | ||
</div> | ||
<div className='grid gap-10 sm:grid-cols-2'> | ||
{props.data.posts.map(post => | ||
<BlogPost | ||
key={post.id} | ||
post={post} | ||
className='col-span-1' | ||
/> | ||
)} | ||
</div> | ||
</div> | ||
</section> | ||
) | ||
} | ||
|
||
export default BlogPosts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
e8c33c1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Successfully deployed to the following URLs:
hagatun – ./
hagatun.vercel.app
hagatun-hagatun.vercel.app
hagatun-git-main-hagatun.vercel.app
hagatun.se