feat: add discussions to docs

This commit is contained in:
Isaiah Hamilton committed 2022-06-09 01:54:32 -04:00
1 parent 2e12803500
commit a50c56e3cb
7 files changed
+1734 -44

No files matched your search

@@ -0,0 +1,35 @@
import Head from 'next/head'
import NavBar from '../nav/NavBar'
import Footer from '../Footer'
const Layout = ({
children,
meta,
currentPage,
}: {
meta: { title: string; description: string }
children: React.ReactNode
currentPage: string
}) => {
return (
<>
<Head>
<title>{meta?.title} | Supabase</title>
<meta name="description" content={meta?.description} />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<link rel="icon" href="/favicon.ico" />
<meta property="og:type" content="website" />
<meta property="og:site_name" content={meta?.title} />
<meta property="og:description" content={meta?.description} />
<meta property="og:title" content={meta?.title} />
</Head>
<main>
<NavBar currentPage={currentPage} />
<article className="text-scale-1200 mx-auto max-w-7xl">{children}</article>
<Footer />
</main>
</>
)
}
export default Layout
+1
View File
@@ -29,6 +29,7 @@ const NavBar = ({ currentPage }: { currentPage: string }) => {
active: currentPage == 'Reference',
link: '/reference/javascript/supabase-client',
},
{ text: 'Discussions', active: currentPage == 'Discussions', link: '/discussions' },
]
return (
+3
View File
@@ -2,4 +2,7 @@ const withTM = require('next-transpile-modules')(['common'])
module.exports = withTM({
reactStrictMode: true,
images: {
domains: ['avatars.githubusercontent.com'],
},
})
+3
View File
@@ -9,12 +9,14 @@
"lint": "next lint"
},
"dependencies": {
"@apollo/client": "^3.6.6",
"@mdx-js/loader": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@next/mdx": "^12.0.4",
"@supabase/ui": "v0.37.0-alpha.50",
"@tailwindcss/typography": "^0.4.1",
"common": "*",
"graphql": "^16.5.0",
"gray-matter": "^4.0.3",
"markdown-toc": "^1.2.0",
"next": "12.1.0",
@@ -23,6 +25,7 @@
"react": "17.0.2",
"react-copy-to-clipboard": "^5.0.2",
"react-dom": "17.0.2",
"react-markdown": "^8.0.3",
"react-syntax-highlighter": "^15.3.1",
"remark": "^14.0.2",
"remark-html": "^15.0.0",
+204
View File
@@ -0,0 +1,204 @@
import { ApolloClient, createHttpLink, InMemoryCache, gql } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
import Layout from '../../components/layouts/Layout'
import { IconArrowLeft } from '@supabase/ui'
import ReactMarkdown from 'react-markdown'
import Image from 'next/image'
import Link from 'next/link'
export async function getServerSideProps(context: any) {
const prams = context.params
const httpLink = createHttpLink({
uri: 'https://api.github.com/graphql',
})
const authLink = setContext((_, { Headers }) => {
return {
headers: {
Headers,
authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`,
},
}
})
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
})
const { data } = await client.query({
query: gql`
{
repository(owner: "supabase", name: "supabase") {
discussion(number: ${prams!.id}) {
id
number
title
bodyText
createdAt
author {
url
login
avatarUrl
}
category {
name
}
comments(first: 10) {
totalCount
nodes {
id
replies(first: 10) {
totalCount
}
author {
avatarUrl
login
url
}
body
createdAt
upvoteCount
}
}
}
}
}
`,
})
return {
props: {
data,
prams,
},
}
}
const discussion = ({ data }: any) => {
const meta_description = 'Discuss Supabase with other developers and users.'
const getTimeSinceCreated = (createdAt: string) => {
const date = new Date(createdAt)
const now = new Date()
const timeSinceCreated = now.getTime() - date.getTime()
const days = Math.floor(timeSinceCreated / (1000 * 60 * 60 * 24))
const hours = Math.floor((timeSinceCreated % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
const minutes = Math.floor((timeSinceCreated % (1000 * 60 * 60)) / (1000 * 60))
const seconds = Math.floor((timeSinceCreated % (1000 * 60)) / 1000)
if (days < 7) {
if (days > 1) {
return `${days} days ago`
} else {
if (hours > 1) {
return `${hours} hours ago`
} else {
if (minutes > 1) {
return `${minutes} minutes ago`
} else {
return `${seconds} seconds ago`
}
}
}
} else {
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})
}
}
return (
<Layout
meta={{
title: data.repository.discussion.title,
description: meta_description,
}}
currentPage={'Discussions'}
>
<div className="mt-8 space-y-8">
<div>
<Link href="/discussions">
<a className="text-scale-1100 group flex w-fit items-center">
<IconArrowLeft
className="stroke-2 transition group-hover:-translate-x-1"
height={15}
/>
Back
</a>
</Link>
<div className="mt-3 flex items-center text-3xl">
<span>{data.repository.discussion.title}</span>
<span className="text-scale-1000 ml-1">#{data.repository.discussion.number}</span>
</div>
<div className="text-scale-1100 mt-1">
{`${data.repository.discussion.author.login} started this conversation in ${data.repository.discussion.category.name}`}
</div>
</div>
<div className="bg-scale-400 border-scale-600 rounded-lg border px-6 py-4">
<div className="flex items-center">
<Link href={data.repository.discussion.author.url}>
<a className="flex items-center">
<Image
className="rounded-full"
src={data.repository.discussion.author.avatarUrl}
width={30}
height={30}
/>
<span className="ml-2">{data.repository.discussion.author.login}</span>
</a>
</Link>
<span className="text-scale-1100 ml-2">{`on ${getTimeSinceCreated(
data.repository.discussion.createdAt
)}`}</span>
</div>
<div className="mt-4">
<ReactMarkdown>{data.repository.discussion.body}</ReactMarkdown>
</div>
</div>
<div>
{`${data.repository.discussion.comments.totalCount} comments${
data.repository.discussion.comments?.nodes[0] === undefined
? ``
: ` • ${data.repository.discussion.comments.nodes[0].replies.totalCount} replies`
}`}
</div>
<div className="space-y-8">
{data.repository.discussion.comments.nodes.map((comment: any) => {
return (
<div
className="bg-scale-400 border-scale-600 rounded-lg border px-6 py-4"
key={comment.id}
>
<div className="flex items-center">
<Link href={comment.author.url}>
<a className="flex items-center">
<Image
className="rounded-full"
src={comment.author.avatarUrl}
width={30}
height={30}
/>
<span className="ml-2">{comment.author.login}</span>
</a>
</Link>
<span className="text-scale-1100 ml-2">{`on ${getTimeSinceCreated(
comment.createdAt
)}`}</span>
</div>
<div className="mt-4">
<ReactMarkdown>{comment.body}</ReactMarkdown>
</div>
</div>
)
})}
</div>
</div>
</Layout>
)
}
export default discussion
+275
View File
@@ -0,0 +1,275 @@
import { ApolloClient, createHttpLink, InMemoryCache, gql } from '@apollo/client'
import { setContext } from '@apollo/client/link/context'
import Layout from '../../components/layouts/Layout'
import { IconArrowUp, IconCheckCircle } from '@supabase/ui'
import Image from 'next/image'
import Link from 'next/link'
export async function getStaticProps() {
const httpLink = createHttpLink({
uri: 'https://api.github.com/graphql',
})
const authLink = setContext((_, { Headers }) => {
return {
headers: {
Headers,
authorization: `Bearer ${process.env.GITHUB_ACCESS_TOKEN}`,
},
}
})
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
})
const { data } = await client.query({
query: gql`
{
repository(owner: "supabase", name: "supabase") {
pinnedDiscussions(first: 3) {
edges {
node {
id
discussion {
id
number
title
author {
url
avatarUrl
login
}
category {
id
emoji
name
}
}
}
}
totalCount
}
discussions(first: 10) {
nodes {
id
number
createdAt
upvoteCount
title
body
comments(first: 3) {
totalCount
nodes {
id
author {
avatarUrl
login
}
}
}
category {
id
name
emoji
}
author {
login
url
avatarUrl
}
answer {
isAnswer
author {
avatarUrl
login
}
}
}
totalCount
}
}
}
`,
})
return {
props: {
data,
},
}
}
const discussions = ({ data }: any) => {
const meta_title = 'Discussions'
const meta_description = 'Discuss Supabase with other developers and users.'
// TODO: This was a quick hack to show emojis in discussions. could be replaced with a proper solution.
const emojiInput = [':zap:', ':ship:', ':bulb:', ':question:', ':raised_hands:']
const emojiOutput = ['⚡️', '🚢', '💡', '❓', '🙌']
const getEmoji = (category: string) => {
const index = emojiInput.indexOf(category)
return emojiOutput[index]
}
const getTimeSinceCreated = (createdAt: string) => {
const date = new Date(createdAt)
const now = new Date()
const timeSinceCreated = now.getTime() - date.getTime()
const days = Math.floor(timeSinceCreated / (1000 * 60 * 60 * 24))
const hours = Math.floor((timeSinceCreated % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60))
const minutes = Math.floor((timeSinceCreated % (1000 * 60 * 60)) / (1000 * 60))
const seconds = Math.floor((timeSinceCreated % (1000 * 60)) / 1000)
if (days < 7) {
if (days > 1) {
return `${days} days ago`
} else {
if (hours > 1) {
return `${hours} hours ago`
} else {
if (minutes > 1) {
return `${minutes} minutes ago`
} else {
return `${seconds} seconds ago`
}
}
}
} else {
return date.toLocaleDateString('en-US', {
month: 'short',
day: 'numeric',
year: 'numeric',
})
}
}
return (
<Layout meta={{ title: meta_title, description: meta_description }} currentPage={'Discussions'}>
<div className="mb-16 space-y-8">
<div className="flex items-center justify-between">
<h2 className="my-4 text-4xl">Supabase Discussions</h2>
<Link href="https://github.com/supabase/supabase/discussions/new">
<a
target="_blank"
className="rounded-lg bg-[#34b17b] px-4 py-2 text-sm text-white transition duration-150 hover:bg-[#40cf8e]"
>
New Discussion
</a>
</Link>
</div>
<div className="flex justify-around space-x-4">
{data.repository.pinnedDiscussions.edges.map((discussion: any) => {
const item = discussion.node
return (
<div
className="border-scale-600 bg-scale-400 w-1/3 rounded-xl border px-4 py-4"
key={item.id}
>
<Link href={`/discussions/${item.discussion.number}`}>
<a className="space-y-4">
<div className="flex justify-end text-2xl">
{getEmoji(item.discussion.category.emoji)}
</div>
<div>
<p className="text-sm font-normal">{item.discussion.category.name}</p>
<h2 className="max-w-[350px] truncate text-xl font-semibold">
{item.discussion.title}
</h2>
</div>
<Link href={item.discussion.author.url}>
<a className="flex w-fit items-center space-x-2">
<Image
className="rounded-full"
src={item.discussion.author.avatarUrl}
height={30}
width={30}
/>
<span className="text-sm">{item.discussion.author.login}</span>
</a>
</Link>
</a>
</Link>
</div>
)
})}
</div>
<div className="space-y-6">
{data.repository.discussions.nodes.map((discussion: any) => {
return (
<div className="border-scale-600 border-b" key={discussion.id}>
<Link href={`/discussions/${discussion.number}`}>
<a className="mx-6 mb-6 flex items-center justify-between">
<div className="flex items-center">
<div className="item-center flex items-center space-x-6">
<div className="item-center bg-scale-400 border-scale-600 flex h-fit items-center space-x-1 rounded-xl border py-1 pl-1 pr-2">
<IconArrowUp className="stroke-2" height={15} />
<span>{discussion.upvoteCount}</span>
</div>
<div className="rounded-lg bg-gray-400 py-4 px-5">
{getEmoji(discussion.category.emoji)}
</div>
</div>
<div className="ml-6">
<h2 className="text-lg font-semibold">{discussion.title}</h2>
<span className="text-scale-1000 text-sm">
<Link href={discussion.author.url}>
<a>{discussion.author.login}</a>
</Link>
<span>{` asked ${getTimeSinceCreated(discussion.createdAt)} • `}</span>
<span className={discussion.answer?.isAnswer ? 'text-brand-900' : ''}>
{discussion.answer?.isAnswer ? 'Answered' : 'Unanswered'}
</span>
</span>
</div>
</div>
<div className="flex items-center space-x-2">
<div className="flex items-center -space-x-2">
{/* TODO: this is a hack because I couldn't find a participant query for graphql. could be replaced with a proper solution. */}
{discussion.comments.totalCount === 0 ? (
<div>
<Image
className="rounded-full"
src={discussion.author.avatarUrl}
height={30}
width={30}
/>
</div>
) : (
discussion.comments.nodes.map((comment: any) => {
return (
<div>
<Image
className="rounded-full"
src={comment.author.avatarUrl}
height={30}
width={30}
/>
</div>
)
})
)}
</div>
<div
className={`item-center flex items-center space-x-1 ${
discussion.answer?.isAnswer ? 'text-brand-900' : ''
}`}
>
<IconCheckCircle className="stroke-2" height={15} />
<span>{discussion.comments.totalCount}</span>
</div>
</div>
</a>
</Link>
</div>
)
})}
</div>
</div>
</Layout>
)
}
export default discussions
+1213 -44
View File
File diff suppressed because it is too large. Load diff