mirror of
https://github.com/wavetermdev/docusaurus-og.git
synced 2026-08-05 13:46:35 -07:00
feat: add GithubChallenges component UI - using mock data for now
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
TimelineItem,
|
||||
ShowcaseCard,
|
||||
JobsPerDepartment,
|
||||
GithubChallenges,
|
||||
} from '../components/mdx'
|
||||
import * as jobData from '/generated/jobs.json'
|
||||
|
||||
@@ -355,3 +356,4 @@ import * as jobData from '/generated/jobs.json'
|
||||
</CallToActionButton>
|
||||
</Box>
|
||||
<JobsPerDepartment jobData={jobData} />
|
||||
<GithubChallenges org="codex" useDummyData />
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
@use '../../../css/utils';
|
||||
@use '../../../css/lsd';
|
||||
|
||||
.mdx-ghc__container {
|
||||
border-top: 1px solid rgb(var(--lsd-border-primary));
|
||||
padding-top: 24px;
|
||||
}
|
||||
|
||||
.mdx-ghc__issue-title {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mdx-ghc__issue-title-link {
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.mdx-ghc__header {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.mdx-ghc__challenge-labels {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.mdx-ghc__challenge-label {
|
||||
border: 1px solid rgb(var(--lsd-border-primary));
|
||||
padding: 4px 8px;
|
||||
border-radius: 20px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.mdx-ghc-subheader-text {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.mdx-ghc__view-on-github-link {
|
||||
display: block;
|
||||
width: fit-content;
|
||||
|
||||
margin-top: 40px;
|
||||
margin-bottom: 56px;
|
||||
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.mdx-ghc__participant-photo {
|
||||
border-radius: 100%;
|
||||
margin-left: -4px;
|
||||
border: 1px solid rgb(var(--lsd-border-secondary));
|
||||
}
|
||||
|
||||
.mdx-ghc__participant-photo-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
direction: rtl;
|
||||
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.mdx-ghc__comment-count {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.mdx-ghc__issue-content-grid {
|
||||
display: grid;
|
||||
/* Fixed widths for the 1st, 2nd and 3rd columns, while the 4th column takes up the remaining space */
|
||||
grid-template-columns: 82px 135px 82px 1fr;
|
||||
row-gap: 12px;
|
||||
margin-top: 24px;
|
||||
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.mdx-ghc__achievement {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 4px;
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import { Typography } from '@acid-info/lsd-react'
|
||||
import { SingleGithubChallenge } from './SingleGithubChallenge'
|
||||
import React from 'react'
|
||||
import useFetchGithubIssues, { GithubIssue } from './useFetchGithubIssues'
|
||||
|
||||
type GithubChallengesHeaderProps = {
|
||||
message?: string
|
||||
}
|
||||
|
||||
const GithubChallengesHeader: React.FC<GithubChallengesHeaderProps> = ({
|
||||
message,
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h1" className="mdx-ghc__header">
|
||||
Open challenges
|
||||
</Typography>
|
||||
|
||||
{!!message && <Typography variant="body1">{message}</Typography>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
const hasChallenges = (githubChallenges: GithubIssue[]): boolean => {
|
||||
return githubChallenges.length > 0
|
||||
}
|
||||
|
||||
type GithubChallengesProps = React.HTMLAttributes<HTMLDivElement> & {
|
||||
org: string
|
||||
useDummyData?: boolean
|
||||
}
|
||||
|
||||
export const GithubChallenges: React.FC<GithubChallengesProps> = ({
|
||||
org,
|
||||
useDummyData,
|
||||
...props
|
||||
}) => {
|
||||
const [data, error, loading] = useFetchGithubIssues(org, useDummyData)
|
||||
|
||||
if (loading) {
|
||||
return <GithubChallengesHeader />
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <GithubChallengesHeader message="Error fetching data" />
|
||||
}
|
||||
|
||||
if (!data || !hasChallenges(data)) {
|
||||
return <GithubChallengesHeader message="No challenges to show" />
|
||||
}
|
||||
|
||||
return (
|
||||
<div {...props}>
|
||||
<GithubChallengesHeader />
|
||||
<Typography
|
||||
variant="body1"
|
||||
className="mdx-ghc-subheader-text"
|
||||
component="div"
|
||||
>
|
||||
Lorem ipsum dolor sit amet consectetur. Enim magna urna fames mattis
|
||||
tincidunt nibh mi ornare. Sed amet morbi mauris pellentesque fusce ut.
|
||||
Bibendum vestibulum Lorem ipsum dolor sit amet consectetur. Enim magna
|
||||
urna fames mattis tincidunt nibh mi ornare. Sed amet morbi mauris
|
||||
pellentesque fusce ut. Bibendum vestibulum
|
||||
</Typography>
|
||||
{data.map((issue) => {
|
||||
return <SingleGithubChallenge key={issue.id} issue={issue} />
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
import { Button, Typography } from '@acid-info/lsd-react'
|
||||
import React from 'react'
|
||||
import { IconExternalLink } from '@logos-theme/components/Icon'
|
||||
import './GithubChallenges.scss'
|
||||
import Link from '@docusaurus/Link'
|
||||
import { GithubIssue } from './useFetchGithubIssues'
|
||||
|
||||
function addSizeToAvatarUrl(avatarUrl: string, size: number = 24): string {
|
||||
const url = new URL(avatarUrl)
|
||||
const params = new URLSearchParams(url.search)
|
||||
params.set('s', size.toString())
|
||||
|
||||
// Prepend the size parameter to the start of the query string
|
||||
url.search = Array.from(params.entries())
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join('&')
|
||||
|
||||
return url.toString()
|
||||
}
|
||||
|
||||
type SingleGithubChallengeProps = {
|
||||
issue: GithubIssue
|
||||
}
|
||||
|
||||
export const SingleGithubChallenge: React.FC<SingleGithubChallengeProps> = ({
|
||||
issue,
|
||||
}) => {
|
||||
return (
|
||||
<div className="mdx-ghc__container">
|
||||
<Link href={issue.url} className="mdx-ghc__issue-title-link">
|
||||
<Typography variant="h6" className="mdx-ghc__issue-title">
|
||||
{issue.title}
|
||||
</Typography>
|
||||
</Link>
|
||||
|
||||
<div className="mdx-ghc__challenge-labels">
|
||||
{issue.labels.map((label, index) => (
|
||||
<Typography
|
||||
variant="body3"
|
||||
key={index}
|
||||
className="mdx-ghc__challenge-label"
|
||||
>
|
||||
{label.name}
|
||||
</Typography>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mdx-ghc__issue-content-grid">
|
||||
{/* 1st row 1st item */}
|
||||
<Typography variant="body3" className="mdx-ghc__label">
|
||||
Participants
|
||||
</Typography>
|
||||
|
||||
{/* 1st row 2nd item */}
|
||||
<div className="mdx-ghc__participant-photo-container">
|
||||
<Typography
|
||||
variant="body3"
|
||||
className="mdx-ghc__comment-count"
|
||||
component="div"
|
||||
>
|
||||
{issue.comments.length}
|
||||
</Typography>
|
||||
{issue.participants.map((participant, index) => (
|
||||
<img
|
||||
key={index}
|
||||
className="mdx-ghc__participant-photo"
|
||||
src={addSizeToAvatarUrl(participant.avatarUrl)}
|
||||
alt={participant.login}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* 1st row 3rd item */}
|
||||
<Typography variant="body3" className="mdx-ghc__label">
|
||||
Project
|
||||
</Typography>
|
||||
|
||||
{/* 1st row 4th item */}
|
||||
<Typography variant="body3" className="mdx-ghc__project-name">
|
||||
{issue.project ? issue.project.name : ''}
|
||||
</Typography>
|
||||
|
||||
{/* 2nd row 1st item */}
|
||||
<Typography variant="body3" className="mdx-ghc__label">
|
||||
Achievement
|
||||
</Typography>
|
||||
|
||||
{/* 2nd row 2nd item */}
|
||||
<div className="mdx-ghc__achievement">
|
||||
<img
|
||||
className="mdx-ghc__participant-photo"
|
||||
src={addSizeToAvatarUrl(
|
||||
'https://avatars.githubusercontent.com/u/8811422?u=b4aec0f11a78abe3b71c42e4adfba3ebd61f34aa&v=4',
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 2nd row 3rd item */}
|
||||
<Typography variant="body3" className="mdx-ghc__label">
|
||||
Milestone
|
||||
</Typography>
|
||||
|
||||
{/* 2nd row 4th item */}
|
||||
<Typography variant="body3" className="mdx-ghc__milestone-text">
|
||||
{issue.milestone || ''}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<Link href={issue.url} className="mdx-ghc__view-on-github-link">
|
||||
<Button
|
||||
className="mdx-ghc__view-on-github-button"
|
||||
icon={<IconExternalLink />}
|
||||
>
|
||||
View on GitHub
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import { GithubIssue } from './useFetchGithubIssues'
|
||||
|
||||
// Only for dev purposes - prevents making multiple requests to the API while developing.
|
||||
export const dummyGithubIssue: GithubIssue = {
|
||||
id: '12345',
|
||||
title: 'Bug in pagination',
|
||||
body: 'When navigating to the second page, the first item repeats.',
|
||||
url: 'https://github.com/user/repo/issues/12345',
|
||||
labels: [
|
||||
{
|
||||
name: 'bug',
|
||||
},
|
||||
{
|
||||
name: 'frontend',
|
||||
},
|
||||
],
|
||||
comments: [
|
||||
{
|
||||
body: 'I have also noticed this issue. Working on a fix now.',
|
||||
},
|
||||
{
|
||||
body: 'Any updates on this?',
|
||||
},
|
||||
{
|
||||
body: 'I like turtles.',
|
||||
},
|
||||
],
|
||||
participants: [
|
||||
{
|
||||
login: 'alice123',
|
||||
avatarUrl:
|
||||
'https://avatars.githubusercontent.com/u/8811422?u=b4aec0f11a78abe3b71c42e4adfba3ebd61f34aa&v=4',
|
||||
},
|
||||
{
|
||||
login: 'bob456',
|
||||
avatarUrl:
|
||||
'https://avatars.githubusercontent.com/u/8811422?u=b4aec0f11a78abe3b71c42e4adfba3ebd61f34aa&v=4',
|
||||
},
|
||||
{
|
||||
login: 'jaquim',
|
||||
avatarUrl:
|
||||
'https://avatars.githubusercontent.com/u/8811422?u=b4aec0f11a78abe3b71c42e4adfba3ebd61f34aa&v=4',
|
||||
},
|
||||
],
|
||||
project: {
|
||||
name: 'Awesome Project',
|
||||
},
|
||||
achievement: 'Solved critical frontend bug',
|
||||
milestone: 'v1.0.0',
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from './GithubChallenges'
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { dummyGithubIssue } from './githubChallengesDummyData'
|
||||
|
||||
type GithubIssueParticipant = {
|
||||
login: string
|
||||
avatarUrl: string
|
||||
}
|
||||
|
||||
type GithubProject = {
|
||||
name: string
|
||||
}
|
||||
|
||||
type GithubMilestone = string
|
||||
|
||||
type GithubIssueComment = {
|
||||
body: string
|
||||
}
|
||||
|
||||
type GithubIssueLabel = {
|
||||
name: string
|
||||
}
|
||||
|
||||
export type GithubIssue = {
|
||||
id: string
|
||||
title: string
|
||||
body: string
|
||||
url: string
|
||||
labels: GithubIssueLabel[]
|
||||
comments: GithubIssueComment[]
|
||||
participants: GithubIssueParticipant[]
|
||||
project?: GithubProject
|
||||
milestone?: GithubMilestone
|
||||
achievement: string
|
||||
}
|
||||
|
||||
function useFetchGithubIssues(
|
||||
org: string,
|
||||
useDummyData: boolean = false,
|
||||
): [GithubIssue[] | null, string | null, boolean] {
|
||||
const [data, setData] = useState<GithubIssue[] | null>(null)
|
||||
const [errorMessage, setErrorMessage] = useState<string | null>(null)
|
||||
const [loading, setLoading] = useState<boolean>(true)
|
||||
|
||||
useEffect(() => {
|
||||
if (useDummyData) {
|
||||
// Mocking an API call with setTimeout
|
||||
setTimeout(() => {
|
||||
try {
|
||||
// Success scenario:
|
||||
setData([dummyGithubIssue, dummyGithubIssue, dummyGithubIssue])
|
||||
setLoading(false)
|
||||
|
||||
// Uncomment the below lines to simulate an error scenario:
|
||||
// throw new Error("Failed to fetch data");
|
||||
} catch (error) {
|
||||
let errorMessage = 'An error occurred'
|
||||
if (error instanceof Error) {
|
||||
errorMessage = error.message
|
||||
} else if (typeof error === 'string') {
|
||||
errorMessage = error
|
||||
}
|
||||
|
||||
console.error(errorMessage)
|
||||
setErrorMessage(errorMessage)
|
||||
setLoading(false)
|
||||
}
|
||||
}, 2000) // Mock delay of 2 seconds
|
||||
}
|
||||
}, [])
|
||||
|
||||
return [data, errorMessage, loading]
|
||||
}
|
||||
|
||||
export default useFetchGithubIssues
|
||||
@@ -25,3 +25,4 @@ export * from './ShowcaseCard'
|
||||
export * from './SocialCard'
|
||||
export * from './TimelineItem'
|
||||
export * from './JobsPerDepartment'
|
||||
export * from './GithubChallenges'
|
||||
|
||||
Reference in New Issue
Block a user