Skip to content

Commit

Permalink
Merge pull request #6 from stifskere/dev
Browse files Browse the repository at this point in the history
feat: github gists
  • Loading branch information
stifskere authored May 12, 2024
2 parents 33ab744 + 9d2f8d8 commit eade627
Show file tree
Hide file tree
Showing 14 changed files with 653 additions and 157 deletions.
376 changes: 318 additions & 58 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@
"lint": "next lint"
},
"dependencies": {
"@types/react-syntax-highlighter": "^15.5.13",
"date-fns": "^3.3.1",
"next": "14.1.0",
"next": "^14.2.3",
"react": "^18",
"react-dom": "^18",
"react-icons": "^5.0.1",
"react-syntax-highlighter": "^15.5.0",
"sharp": "^0.33.2"
},
"devDependencies": {
Expand Down
Binary file modified public/background.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
44 changes: 44 additions & 0 deletions src/app/github/gists/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import {NextResponse} from "next/server";
import {githubRequestInit} from "@/app/github/github-constants";
import {GithubCompiledGist, GithubGist} from "@/app/github/github-types";

export const revalidate = 3600;

const pinnedGists: string[] = ["PortfolioIntroduction.md", "C# Tutorial.cs"];

export async function GET(): Promise<NextResponse<GithubCompiledGist[] | null>> {
const gistsResponse: Response
= await fetch("https://api.github.com/gists", githubRequestInit);

if (!gistsResponse.ok)
return NextResponse.json(null, { status: 500 });

const gistsObject: GithubCompiledGist[]
= (await gistsResponse.json() satisfies Promise<GithubGist[]>)
.filter((gist: GithubGist) => gist.public)
.flatMap((gist: GithubGist) => Object.keys(gist.files)
.map(async (file: string) => {
let content: string =
(await (await fetch(gist.files[file].raw_url)).text());

if (content.length > 500)
content = content.slice(0, 500) + " // ...";

const filename: string = gist.files[file].filename;
const order: number = pinnedGists.findIndex(f => f == filename);

return {
filename: filename,
language: gist.files[file].language,
cut_string: content,
public_url: gist.html_url,
description: gist.description,
order: order !== -1 ? order : pinnedGists.length
} satisfies GithubCompiledGist;
})
);

return NextResponse.json<GithubCompiledGist[]>(
await Promise.all(gistsObject)
);
}
8 changes: 8 additions & 0 deletions src/app/github/github-constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

export const githubRequestInit: RequestInit = {
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${process.env["API_GITHUB_TOKEN"]}`,
"Cache-Control": "no-cache"
}
}
25 changes: 23 additions & 2 deletions src/app/github/github-types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,32 @@ export interface GithubRepositoryFromSource {
commit_count: number;
}


export type GithubRepository = Omit<
GithubRepositoryFromSource,
"commits_url" |
"forks_url" |
"fork_repo" |
"fork"
>;
>;

export interface GithubGist {
html_url: string;
files: { [key: string]: GithubGistFile }
public: boolean
description?: string;
}

interface GithubGistFile {
filename: string;
language: string;
raw_url: string;
}

export interface GithubCompiledGist {
filename: string;
language: string;
cut_string: string;
public_url: string;
description?: string;
order: number;
}
17 changes: 5 additions & 12 deletions src/app/github/route.ts → src/app/github/repos/route.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,9 @@
import {NextResponse} from "next/server";
import {GithubRepository, GithubRepositoryFromSource} from "@/app/github/github-types";
import {githubRequestInit} from "@/app/github/github-constants";

export const revalidate = 3600;

const githubRequestInit: RequestInit = {
headers: {
Accept: "application/vnd.github+json",
Authorization: `Bearer ${process.env["API_GITHUB_TOKEN"]}`,
"Cache-Control": "no-cache"
}
}

export async function GET(): Promise<NextResponse<GithubRepository[] | null>> {
const repositoryResponse: Response
= await fetch("https://api.github.com/users/stifskere/repos?per_page=100&cache_bust=0", githubRequestInit);
Expand All @@ -21,11 +14,11 @@ export async function GET(): Promise<NextResponse<GithubRepository[] | null>> {
const repos: GithubRepositoryFromSource[] = await repositoryResponse.json();

for (const repository of repos) {
const commitsResponse: Response
const repoCommitsResponse: Response
= await fetch(repository.commits_url.replace("{/sha}", ""), githubRequestInit);

repository.commit_count = commitsResponse.ok
? ((await commitsResponse.json()) as unknown[]).length
repository.commit_count = repoCommitsResponse.ok
? ((await repoCommitsResponse.json()) as unknown[]).length
: 0;

if (!repository.fork)
Expand All @@ -36,7 +29,7 @@ export async function GET(): Promise<NextResponse<GithubRepository[] | null>> {

if (forkResponse.ok) {
const currentRespository: GithubRepositoryFromSource
= (await forkResponse.json() satisfies GithubRepositoryFromSource);
= await forkResponse.json() satisfies GithubRepositoryFromSource;

if (currentRespository.parent !== undefined)
repository.parent = currentRespository.parent;
Expand Down
76 changes: 16 additions & 60 deletions src/app/page.css
Original file line number Diff line number Diff line change
Expand Up @@ -151,37 +151,6 @@ body {
height: 100vh;
}

.projects[data-loading="true"],
.projects[data-did-error="true"] {
height: 70vh;
}

.projects[data-did-error="true"] .no-repositories-info {
box-shadow: 0 0 20px red;

border: 1px solid red;

animation: error-border linear infinite 2s;

@media (orientation: portrait) {
width: 80vw;
}
}

@keyframes error-border {
0% {
box-shadow: 0 0 20px red;
}

50% {
box-shadow: 0 0 30px red;
}

100% {
box-shadow: 0 0 20px red;
}
}

.projects > div {
position: absolute;

Expand All @@ -200,35 +169,6 @@ body {
align-items: center;
}

.no-repositories-info {
width: 850px;
height: 175px;

color: white;

display: flex;

flex-direction: column;

justify-content: center;
align-items: center;

gap: 15px;

text-align: center;

padding: 0 30px;
}

.no-repositories-info > h1,
.no-repositories-info > svg {
font-size: 2.3em;
}

.no-repositories-info > p {
font-size: 1.3em;
}

.repositories {
display: flex;

Expand Down Expand Up @@ -257,6 +197,22 @@ body {
min-height: 50px;
}

/*gists*/
.gists {
min-height: 50vh;

padding: 20vh 0;

display: flex;

justify-content: center;
align-items: center;

flex-direction: column;

gap: 30px;
}

/*footer section*/
footer {
height: 400px;
Expand Down
53 changes: 29 additions & 24 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {formatDistanceToNowStrict} from "date-fns";
import {FaGithub, FaInstagram, FaLinkedin} from "react-icons/fa6";
import {CgSpinner} from "react-icons/cg";

import {GithubRepository} from "@/app/github/github-types";
import {GithubCompiledGist, GithubRepository} from "@/app/github/github-types";

import Social from "@/components/social";
import Box from "@/components/box";
Expand All @@ -20,21 +20,31 @@ import FooterContact from "@/components/footer-contact";
import logo from "../../public/logo.png";

import "./page.css";
import Gist from "@/components/gist";
import Loader from "@/components/content-loader";


export default function Home(): ReactElement {
const [repos, setRepos]: StateTuple<GithubRepository[] | undefined | null> = useState();
const [page, setPage]: StateTuple<number> = useState(0);
const [gists, setGists]: StateTuple<GithubCompiledGist[] | undefined | null> = useState();

useEffect((): void => {
fetch("/github")
fetch("/github/repos")
.then(async (r: Response): Promise<void> => setRepos(
r.ok
? (await r.json()).sort((a: GithubRepository, b: GithubRepository): number =>
new Date(b.pushed_at).getTime() - new Date(a.pushed_at).getTime()
)
: null
));

fetch("/github/gists")
.then(async (r: Response): Promise<void> => setGists(
r.ok
? (await r.json())
: null
));
}, []);

function setCurrentPage(page: number): void {
Expand Down Expand Up @@ -78,40 +88,35 @@ export default function Home(): ReactElement {
</>
</Box>
</section>
<section className="projects" data-did-error={repos === null} data-loading={repos === undefined}>
<section className="projects">
<div>
<Choose>
<When condition={repos === null}>
<Box className="no-repositories-info">
<h1>Whoops!</h1>
<p>
Looks like there was an error while loading the repositories,
try reloading or wait for this bug to be fixed.
</p>
</Box>
</When>
<When condition={repos === undefined}>
<Box className="no-repositories-info">
<CgSpinner className="spin" />
<p>Loading, please wait...</p>
</Box>
</When>
<Otherwise>
<Loader error={repos === null} waiting={repos === undefined} what="github repositories">
<>
<div className="repositories">
{repos!.slice(page * 3, Math.min((page + 1) * 3, repos!.length))
{repos?.slice(page * 3, Math.min((page + 1) * 3, repos!.length))
.map((repo: GithubRepository, index: number): ReactElement =>
<Repository repository={repo} key={index}/>
)}
</div>
<PageSelector
pageSelected={setCurrentPage}
className="repository-page-selector"
pages={Math.ceil(repos!.length / 3)}
pages={Math.ceil(repos?.length ?? 0 / 3)}
/>
</Otherwise>
</Choose>
</>
</Loader>
</div>
</section>
<section className="gists">
<Loader error={gists === null} waiting={gists === undefined} what="github gists">
<>
{gists
?.toSorted((gistA: GithubCompiledGist, gistB: GithubCompiledGist) => gistA.order - gistB.order)
.map((gist: GithubCompiledGist, index: number) => <Gist key={index} gist={gist}/>)
}
</>
</Loader>
</section>
<footer>
<div className="footer-content">
<Image unoptimized src={logo} alt="logo"/>
Expand Down
20 changes: 20 additions & 0 deletions src/components/box/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,24 @@

border: white 1px solid;
border-radius: 8px;
}

.error-box {
border: red 1px solid;

animation: error-border infinite 2s;
}

@keyframes error-border {
0% {
box-shadow: 0 0 20px red;
}

50% {
box-shadow: 0 0 30px red;
}

100% {
box-shadow: 0 0 20px red;
}
}
Loading

0 comments on commit eade627

Please sign in to comment.