started on revamping landing page
continuous-integration/drone/push Build encountered an error
Details
continuous-integration/drone/push Build encountered an error
Details
parent
3dc83ace74
commit
7c6a4ae9cf
@ -1,3 +1,2 @@
|
||||
NEXT_PUBLIC_GITEA_USERNAME=Guusvanmeerveld
|
||||
NEXT_PUBLIC_GITEA_SERVER=git.guusvanmeerveld.dev
|
||||
DATABASE_URL=postgresql://portfolio:portfolio@localhost:5432/portfolio?schema=public
|
||||
LANDING_JSON_LOCATION=./landing.json
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"owner": {
|
||||
"fullName": "Guus van Meerveld",
|
||||
"name": "guus",
|
||||
"description": "AI student at Radboud University. Creating software as a hobby.",
|
||||
"contact": {
|
||||
"email": "contact@guusvanmeerveld.dev",
|
||||
"git": "https://github.com/Guusvanmeerveld",
|
||||
"linkedin": "https://linkedin.com/in/guus-van-meerveld-038357210"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import { format as formatTimeAgo } from "timeago.js";
|
||||
import z from "zod";
|
||||
|
||||
import { FC } from "react";
|
||||
|
||||
import { RepositoryResponse } from "@models/git/responses";
|
||||
|
||||
const BestRepository: FC<{ repository: z.infer<typeof RepositoryResponse> }> =
|
||||
({ repository }) => {
|
||||
return (
|
||||
<div className="hero bg-primary">
|
||||
<div className="container">
|
||||
<div className="columns">
|
||||
<div className="column col-8 col-md-12 col-mx-auto">
|
||||
<h3 className="text-secondary">My most popular project:</h3>
|
||||
<h1>{repository.full_name}</h1>
|
||||
|
||||
<h5>{repository.description}</h5>
|
||||
<p className="text-secondary">
|
||||
Written in {repository.language}, has{" "}
|
||||
{repository.open_issues_count} issue(s) and{" "}
|
||||
{repository.forks_count} fork(s).
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<Link href={repository.html_url}>
|
||||
<a className="btn mr-2">Github</a>
|
||||
</Link>
|
||||
{repository.website && (
|
||||
<Link href={repository.website}>
|
||||
<a className="btn">Website</a>
|
||||
</Link>
|
||||
)}
|
||||
</p>
|
||||
|
||||
<h5 className="text-secondary">
|
||||
Last updated {formatTimeAgo(repository.updated_at, "en_US")}
|
||||
</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BestRepository;
|
@ -1,71 +0,0 @@
|
||||
import Link from "next/link";
|
||||
import { format as formatTimeAgo } from "timeago.js";
|
||||
import z from "zod";
|
||||
|
||||
import styles from "./repositories.module.scss";
|
||||
|
||||
import { FC } from "react";
|
||||
|
||||
import { RepositoryResponse } from "@models/git/responses";
|
||||
|
||||
import multipleClassNames from "@utils/multipleClassNames";
|
||||
|
||||
const FeaturedRepositories: FC<{
|
||||
repositories: z.infer<typeof RepositoryResponse>[];
|
||||
}> = ({ repositories }) => {
|
||||
return (
|
||||
<div className={multipleClassNames("container", styles.main)}>
|
||||
<div className="columns">
|
||||
<div className="column col-6 col-mx-auto text-center">
|
||||
<h3>Some of my featured projects:</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div className="columns">
|
||||
<div className="column col-9 col-mx-auto">
|
||||
<div className="columns">
|
||||
{repositories.map((repository) => {
|
||||
return (
|
||||
<div
|
||||
key={repository.full_name}
|
||||
className="column col-3 col-md-12 col-mx-auto mb-2"
|
||||
>
|
||||
<div
|
||||
className={multipleClassNames(
|
||||
"card",
|
||||
"text-center",
|
||||
styles.card
|
||||
)}
|
||||
>
|
||||
<div className="card-header text-primary">
|
||||
<div className="card-title h5">
|
||||
{repository.full_name}
|
||||
</div>
|
||||
<div className="card-subtitle text-gray">
|
||||
{(repository.size / 1024).toPrecision(2)} MB - Last
|
||||
updated {formatTimeAgo(repository.updated_at, "en_US")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body">{repository.description}</div>
|
||||
<div className="card-footer">
|
||||
<Link href={repository.html_url}>
|
||||
<a className="btn btn-primary">Git</a>
|
||||
</Link>
|
||||
|
||||
{repository.website && (
|
||||
<Link href={repository.website}>
|
||||
<a className="btn btn-primary ml-2">Website</a>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeaturedRepositories;
|
@ -1,29 +0,0 @@
|
||||
import z from "zod";
|
||||
|
||||
export const RepositoryResponse = z.object({
|
||||
full_name: z.string(),
|
||||
html_url: z.string(),
|
||||
language: z.string(),
|
||||
website: z.string(),
|
||||
created_at: z.string(),
|
||||
updated_at: z.string(),
|
||||
forks_count: z.number(),
|
||||
open_issues_count: z.number(),
|
||||
stars_count: z.number(),
|
||||
description: z.string(),
|
||||
size: z.number()
|
||||
});
|
||||
|
||||
export const SearchResultsResponse = z.object({
|
||||
ok: z.boolean(),
|
||||
data: RepositoryResponse.array()
|
||||
});
|
||||
|
||||
export const UserResponse = z.object({
|
||||
id: z.number(),
|
||||
login: z.string(),
|
||||
email: z.string(),
|
||||
avatar_url: z.string(),
|
||||
full_name: z.string(),
|
||||
description: z.string()
|
||||
});
|
@ -0,0 +1,11 @@
|
||||
import z from "zod";
|
||||
|
||||
import { OwnerModel } from "./owner";
|
||||
|
||||
export const LandingModel = z.object({
|
||||
owner: OwnerModel
|
||||
});
|
||||
|
||||
export type Landing = z.infer<typeof LandingModel>;
|
||||
|
||||
export default Landing;
|
@ -0,0 +1,17 @@
|
||||
import z from "zod";
|
||||
|
||||
export const OwnerModel = z.object({
|
||||
fullName: z.string(),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
avatar: z.string().optional(),
|
||||
contact: z.object({
|
||||
email: z.string().email(),
|
||||
linkedin: z.string().url(),
|
||||
git: z.string().url()
|
||||
})
|
||||
});
|
||||
|
||||
export type Owner = z.infer<typeof OwnerModel>;
|
||||
|
||||
export default Owner;
|
@ -1,8 +1,8 @@
|
||||
import z from "zod";
|
||||
|
||||
export const Post = z.object({
|
||||
title: z.string(),
|
||||
content: z.string().min(100),
|
||||
tags: z.string(),
|
||||
title: z.string().trim(),
|
||||
content: z.string().min(100).trim(),
|
||||
tags: z.string().trim(),
|
||||
publish: z.boolean()
|
||||
});
|
||||
|
@ -0,0 +1,58 @@
|
||||
import { NextApiHandler } from "next";
|
||||
import z from "zod";
|
||||
|
||||
import { LinkIdFromString } from "@models/link";
|
||||
import { Response } from "@models/response";
|
||||
|
||||
import { methodNotAllowed, unauthorized } from "@utils/errors";
|
||||
import prisma from "@utils/prisma";
|
||||
import { withIronSession } from "@utils/session";
|
||||
|
||||
const handler: NextApiHandler<Response> = async (req, res) => {
|
||||
if (req.method?.toUpperCase() !== "DELETE") {
|
||||
res.status(405).json(methodNotAllowed);
|
||||
return;
|
||||
}
|
||||
|
||||
const user = req.session.user;
|
||||
|
||||
if (user === undefined) {
|
||||
res.status(401).json(unauthorized);
|
||||
return;
|
||||
}
|
||||
|
||||
const parsePostDataResult = z
|
||||
.object({
|
||||
id: LinkIdFromString
|
||||
})
|
||||
.safeParse(req.query);
|
||||
|
||||
if (!parsePostDataResult.success) {
|
||||
res
|
||||
.status(400)
|
||||
.json({ ok: false, error: parsePostDataResult.error.message });
|
||||
return;
|
||||
}
|
||||
|
||||
const link = await prisma.link.findUnique({
|
||||
where: { id: parsePostDataResult.data.id },
|
||||
include: { author: true }
|
||||
});
|
||||
|
||||
if (link === null) {
|
||||
res.status(400).json({ ok: false, error: "Link does not exist" });
|
||||
return;
|
||||
}
|
||||
|
||||
if (link.authorId !== user.id) {
|
||||
res.status(401).json(unauthorized);
|
||||
return;
|
||||
}
|
||||
|
||||
await prisma.link
|
||||
.delete({ where: { id: link.id } })
|
||||
.then(() => res.json({ ok: true, data: "Successfully deleted link" }))
|
||||
.catch((error) => res.status(500).json({ ok: false, error }));
|
||||
};
|
||||
|
||||
export default withIronSession(handler);
|
@ -0,0 +1,26 @@
|
||||
import { GetServerSideProps, NextPage } from "next";
|
||||
import z from "zod";
|
||||
|
||||
import { LinkIdFromString } from "@models/link";
|
||||
|
||||
import { withSessionSsr } from "@utils/session";
|
||||
|
||||
const EditLinkPage: NextPage = () => {
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = withSessionSsr(
|
||||
async ({ req, params }) => {
|
||||
const user = req.session.user;
|
||||
|
||||
if (user === undefined) return { notFound: true };
|
||||
|
||||
const parseParamsResult = z
|
||||
.object({ id: LinkIdFromString })
|
||||
.safeParse(params);
|
||||
|
||||
if (!parseParamsResult.success) return { notFound: true };
|
||||
}
|
||||
);
|
||||
|
||||
export default EditLinkPage;
|
@ -1,21 +0,0 @@
|
||||
import * as configcat from "configcat-node";
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||
const createConfigCatClient = () => {
|
||||
if (!process.env.CONFIG_CAT_SDK_KEY) return;
|
||||
|
||||
const logger = configcat.createConsoleLogger(
|
||||
process.env.NODE_ENV == "production" ? 0 : 3
|
||||
);
|
||||
|
||||
const configCatClient = configcat.createClient(
|
||||
process.env.CONFIG_CAT_SDK_KEY,
|
||||
{
|
||||
logger
|
||||
}
|
||||
);
|
||||
|
||||
return configCatClient;
|
||||
};
|
||||
|
||||
export default createConfigCatClient;
|
@ -0,0 +1,7 @@
|
||||
import { stat } from "fs-extra";
|
||||
|
||||
export const exists = async (fileName: string): Promise<boolean> => {
|
||||
return await stat(fileName)
|
||||
.then(() => true)
|
||||
.catch(() => false);
|
||||
};
|
@ -0,0 +1,30 @@
|
||||
import { readJson } from "fs-extra";
|
||||
|
||||
import Landing, { LandingModel } from "@models/landing";
|
||||
|
||||
import { landingJsonLocation } from "@utils/config";
|
||||
import { exists } from "@utils/exists";
|
||||
|
||||
export const readLandingJson = async (): Promise<Landing | null> => {
|
||||
const location = landingJsonLocation;
|
||||
|
||||
const fileExists = await exists(location);
|
||||
|
||||
if (!fileExists) {
|
||||
console.log(`Could not find landing json file at: ${location}`);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
const rawJson: unknown = await readJson(location);
|
||||
|
||||
const landingResult = LandingModel.safeParse(rawJson);
|
||||
|
||||
if (!landingResult.success) {
|
||||
console.log(`Failed to parse landing json: ${landingResult.error}`);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return landingResult.data;
|
||||
};
|
Loading…
Reference in new issue