Skip to content

Commit

Permalink
Add changelog to /about (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
Plsr authored Jan 20, 2023
1 parent ba0adde commit cf473f7
Show file tree
Hide file tree
Showing 7 changed files with 1,201 additions and 23 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GITHUB_ACCESS_TOKEN=
104 changes: 104 additions & 0 deletions components/changelog-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import {
CalendarIcon,
CodeBracketIcon,
UserCircleIcon,
} from '@heroicons/react/24/outline'
import clsx from 'clsx'
import { format } from 'date-fns'
import { motion, useAnimation, useInView } from 'framer-motion'
import Link from 'next/link'
import { useEffect, useRef } from 'react'
import { ReleasesResponseData } from '../lib/github'
import { Headline } from './headline'

type ChangelogListProps = {
changelogEntries: ReleasesResponseData[]
}

const variants = {
hidden: {
opacity: 0,
},
visible: {
opacity: 1,
transition: {
delayChildren: 0,
staggerChildren: 0.2,
},
},
}
export const ChangelogList = ({ changelogEntries }: ChangelogListProps) => {
const controls = useAnimation()
const ref = useRef(null)
const isInView = useInView(ref)

useEffect(() => {
if (isInView) {
controls.start('visible')
}
}, [controls, isInView])

return (
<>
<motion.ul
ref={ref}
variants={variants}
initial="hidden"
animate={controls}
>
{changelogEntries.map((entry, index) => (
<motion.li key={entry.id} variants={variants}>
<ChangelogEntry entry={entry} latest={index === 0} />
</motion.li>
))}
</motion.ul>
</>
)
}

type ChangelogEntryProps = {
entry: ReleasesResponseData
latest?: boolean
}

const ChangelogEntry = ({ entry, latest = false }: ChangelogEntryProps) => {
return (
<div className="bg-slate-100 p-4 rounded-xl mb-8">
<h3 className=" text-slate-800 flex items-center mb-2">
<div
className={clsx(
'font-semibold font-headline',
latest && 'text-lg',
!latest && 'text-sm'
)}
>
{entry.name}
</div>{' '}
{latest && (
<span className=" text-xs ml-2 px-2 py-1 pb-0.5 rounded-xl bg-blue-300 text-slate-50">
latest
</span>
)}
</h3>
<p className="text-sm text-slate-500">{entry.body}</p>
<div className="flex mt-4">
<p className="text-xs text-slate-500 mr-4 flex">
<UserCircleIcon className="inline h-3 w-3 mr-1" />
{entry.author.login}
</p>
<p className="text-xs text-slate-500 mr-4 flex">
<CalendarIcon className="inline h-3 w-3 mr-1" />
{format(new Date(entry.created_at.toString()), 'do MMMM, yyyy')}
</p>
<p className="text-xs text-blue-500 flex underline">
<Link
href={`https://github.com/Plsr/website-next/commit/${entry.target_commitish}`}
>
<CodeBracketIcon className="inline h-3 w-3 mr-1" />
{entry.target_commitish.slice(0, 8)}
</Link>
</p>
</div>
</div>
)
}
15 changes: 11 additions & 4 deletions components/headline.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import { ReactNode } from 'react'

export const Headline = ({ level, children }: props) => {
export const Headline = ({ level, children, id }: props) => {
if (level === 2)
return (
<h2 className="font-headline text-2xl font-bold mb-4 mt-8">{children}</h2>
<h2 id={id} className="font-headline text-2xl font-bold mb-4 mt-8">
{children}
</h2>
)
if (level === 3)
return (
<h3 className="font-headline text-xl font-bold mb-4 mt-8">{children}</h3>
<h3 id={id} className="font-headline text-xl font-bold mb-4 mt-8">
{children}
</h3>
)
if (level === 4)
return (
<h3 className="font-headline text-lg font-bold mb-4 mt-8">{children}</h3>
<h3 id={id} className="font-headline text-lg font-bold mb-4 mt-8">
{children}
</h3>
)
return null
}

type props = {
level: 2 | 3 | 4
children: ReactNode | ReactNode[]
id?: string
}
63 changes: 63 additions & 0 deletions lib/github.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { Octokit } from 'octokit'

const octokit = new Octokit({
auth: process.env.GITHUB_ACCESS_TOKEN,
})

export const getWebsiteReleases = async (): Promise<ReleasesResponseData[]> => {
const releases = await octokit.request(
'GET /repos/{owner}/{repo}/releases{?per_page,page}',
{
owner: 'Plsr',
repo: 'website-next',
}
)

const releaseData = releases.data.filter((release: ReleasesResponseData) => {
return release.draft === false && release.prerelease === false
})

return releaseData
}

export type ReleasesResponseData = {
url: string
assets_url: string
upload_url: string
html_url: string
id: number
author: Author
node_id: string
tag_name: string
target_commitish: string
name: string
draft: boolean
prerelease: boolean
created_at: Date
published_at: Date
assets: any[]
tarball_url: string
zipball_url: string
body: string
}

type Author = {
login: string
id: number
node_id: string
avatar_url: string
gravatar_id: string
url: string
html_url: string
followers_url: string
following_url: string
gists_url: string
starred_url: string
subscriptions_url: string
organizations_url: string
repos_url: string
events_url: string
received_events_url: string
type: string
site_admin: boolean
}
Loading

1 comment on commit cf473f7

@vercel
Copy link

@vercel vercel bot commented on cf473f7 Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.