refactor to pages

This commit is contained in:
Janis
2023-01-29 20:01:56 +01:00
parent 976a11a78f
commit 0997e8fdb8
26 changed files with 2050 additions and 1252 deletions

View File

@@ -1,3 +1,3 @@
export default async function Layout({ children }) { export default async function AdminArticleEditorLayout({ children }) {
return <div>{children}</div>; return <div>{children}</div>;
} }

View File

@@ -18,7 +18,7 @@ import Markdown from "../../../../../components/Markdown";
type ArticleWithCategory = Prisma.ArticleGetPayload<{ include: { category: true } }>; type ArticleWithCategory = Prisma.ArticleGetPayload<{ include: { category: true } }>;
export default function ArticleEditor({ params }: { params: { articleId: string } }) { export default function AdminArticlesEditorPage({ params }: { params: { articleId: string } }) {
const router = useRouter(); const router = useRouter();
const [title, setTitle] = useState<string>(""); const [title, setTitle] = useState<string>("");
const [selectCategoriesOptions, setSelectCategoriesOptions] = useState<any>([]); const [selectCategoriesOptions, setSelectCategoriesOptions] = useState<any>([]);

View File

@@ -2,7 +2,7 @@
import React from "react"; import React from "react";
function AdminArticlesPage() { export default function AdminArticlesPage() {
return ( return (
<div> <div>
<h1>Page to manage articles</h1> <h1>Page to manage articles</h1>
@@ -11,5 +11,3 @@ function AdminArticlesPage() {
</div> </div>
); );
} }
export default AdminArticlesPage;

View File

@@ -1,3 +1,3 @@
export default async function Layout({ children }) { export default async function AdminCategoriesEditorLayout({ children }) {
return <div>{children}</div>; return <div>{children}</div>;
} }

View File

@@ -14,7 +14,7 @@ import { apiUrl } from "../../../../../global";
type CategoryWithSvg = Prisma.CategoryGetPayload<{ include: { svg: true } }>; type CategoryWithSvg = Prisma.CategoryGetPayload<{ include: { svg: true } }>;
export default function CategoryEditor({ params }: { params: { categoryId: string } }) { export default function AdminCategoriesEditor({ params }: { params: { categoryId: string } }) {
const router = useRouter(); const router = useRouter();
const [title, setTitle] = useState<string>(""); const [title, setTitle] = useState<string>("");
const [color, setColor] = useState<string>(""); const [color, setColor] = useState<string>("");

View File

@@ -19,6 +19,6 @@ async function getImages(): Promise<GalleryImage[]> {
})); }));
} }
export default async function page() { export default async function AdminImagesPage() {
return <Gallery images={await getImages()} />; return <Gallery images={await getImages()} />;
} }

View File

@@ -1,28 +0,0 @@
import React from "react";
import styles from "../../../../styles/modules/Sidebar.module.scss";
export default function Sidebar() {
return (
<div className={styles.sidebar}>
<div className={styles.stickyContainer}>
<div className={styles.sidebarContainer}>
<h3>Popular</h3>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
</div>
<div className={styles.sidebarContainer}>
<h3>Related</h3>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
</div>
<div className={styles.adContainer}>Future advertisement</div>
</div>
</div>
);
}

View File

@@ -1,17 +1,13 @@
import { Article } from "@prisma/client"; import { Article } from "@prisma/client";
import { GetArticle } from "./page"; import { FetchManager } from "../../../../manager/fetchManager";
export default async function Head({ export default async function ArticleHead({ params }: { params: { articleName: string; categoryName: string } }) {
params, const articleName: string = params.articleName;
}: { const article: Article = await FetchManager.Article.getByName(articleName);
params: { articleName: string; categoryName: string }; return (
}) { <>
const articleName: string = params.articleName; <title>{article?.title}</title>
const article: Article = await GetArticle(articleName); <meta name="viewport" content="width=device-width, initial-scale=1" />
return ( </>
<> );
<title>{article?.title}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</>
);
} }

View File

@@ -1,3 +1,3 @@
export default function Layout({ children }) { export default function ArticleLayout({ children }) {
return <div>{children}</div>; return <div>{children}</div>;
} }

View File

@@ -1,31 +1,15 @@
import { marked } from "marked"; import ContentTable from "../../../../components/ContentTable";
import ContentTable from "./ContentTable"; import Sidebar from "../../../../components/Sidebar";
import Sidebar from "./Sidebar";
import styles from "../../../../styles/modules/Article.module.scss"; import styles from "../../../../styles/modules/Article.module.scss";
import Image from "next/image"; import Image from "next/image";
import urlJoin from "url-join";
import { apiUrl } from "../../../../global";
import { Prisma } from "@prisma/client";
import Markdown from "../../../../components/Markdown"; import Markdown from "../../../../components/Markdown";
import { IContentTableEntry } from "../../../../types/contentTable"; import { ArticleWithIncludes, FetchManager } from "../../../../manager/fetchManager";
import { formatTextToUrlName } from "../../../../utils";
type ArticleWithIncludes = Prisma.ArticleGetPayload<{
include: { category: true; image: true };
}>;
export async function GetArticle(articleName: string): Promise<any> {
const result: Response = await fetch(urlJoin(apiUrl, `articles/name/${articleName ?? ""}`), {
cache: "force-cache",
next: { revalidate: 60 * 10 },
});
return result.json();
}
//* MAIN //* MAIN
export default async function ArticlePage({ params }: { params: { articleName: string; categoryName: string } }) { export default async function ArticlePage({ params }: { params: { articleName: string; categoryName: string } }) {
const articleName: string = params.articleName.toLowerCase().replaceAll("%20", " "); const articleName: string = formatTextToUrlName(params.articleName);
const article: ArticleWithIncludes = await GetArticle(articleName); const article: ArticleWithIncludes = await FetchManager.Article.getByName(articleName);
const dateUpdated: Date = new Date(article.dateUpdated); const dateUpdated: Date = new Date(article.dateUpdated);
const dateCreated: Date = new Date(article.dateCreated); const dateCreated: Date = new Date(article.dateCreated);
@@ -60,14 +44,6 @@ export default async function ArticlePage({ params }: { params: { articleName: s
<p>{article?.introduction}</p> <p>{article?.introduction}</p>
</div> </div>
<Markdown value={markdown} /> <Markdown value={markdown} />
{/* <div
className="markdown"
dangerouslySetInnerHTML={{
__html: ParseMarkdown(markdown),
}}
></div>
<LoadMarkdown /> */}
</div> </div>
<Sidebar /> <Sidebar />
</div> </div>
@@ -75,12 +51,8 @@ export default async function ArticlePage({ params }: { params: { articleName: s
} }
export async function generateStaticParams() { export async function generateStaticParams() {
const articles: ArticleWithIncludes[] = await ( // Fetchmanager does not work here
await fetch(urlJoin(apiUrl, `articles/`), { const articles: ArticleWithIncludes[] = await FetchManager.Article.list(false);
cache: "no-cache",
next: { revalidate: 60 * 10 },
})
).json();
return await Promise.all( return await Promise.all(
articles.map(async (article) => ({ articles.map(async (article) => ({

View File

@@ -1,22 +1,10 @@
import styles from "../../styles/modules/CategoryList.module.scss"; import styles from "../../styles/modules/CategoryList.module.scss";
import Link from "next/link"; import Link from "next/link";
import { Category, Svg, Prisma } from "@prisma/client";
import urlJoin from "url-join";
import { apiUrl } from "../../global";
type CategoryWithSvg = Prisma.CategoryGetPayload<{ include: { svg: true } }>; import { FetchManager } from "../../manager/fetchManager";
export async function GetCategories(): Promise<any> {
const result: Response = await fetch(urlJoin(apiUrl, `categories`), {
cache: "force-cache",
next: { revalidate: 3600 },
});
return result.json();
}
export default async function CategoryList() { export default async function CategoryList() {
const categories = await GetCategories(); const categories = await FetchManager.Category.list();
return ( return (
<div className={styles.categoryList}> <div className={styles.categoryList}>
<h1>Overview</h1> <h1>Overview</h1>

View File

@@ -1,7 +1,7 @@
export default async function Head() { export default async function RootHead() {
return ( return (
<> <>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
</> </>
); );
} }

View File

@@ -1,21 +1,10 @@
import "../styles/globals.scss"; import "../styles/globals.scss";
import "../styles/variables_colors.scss"; import "../styles/variables_colors.scss";
import "../styles/variables.scss"; import "../styles/variables.scss";
import { Category } from "@prisma/client";
import urlJoin from "url-join";
import { apiUrl } from "../global";
import Link from "next/link"; import Link from "next/link";
import Footer from "../components/Footer"; import Footer from "../components/Footer";
import Nav from "../components/Nav"; import Nav from "../components/Nav";
import { FetchManager } from "../manager/fetchManager";
async function getCategories(): Promise<Category[]> {
const result: Response = await fetch(urlJoin(apiUrl, `categories`), {
cache: "no-cache",
next: { revalidate: 3600 },
});
return await result.json();
}
export default async function RootLayout({ children }: { children: React.ReactNode }) { export default async function RootLayout({ children }: { children: React.ReactNode }) {
return ( return (
@@ -27,7 +16,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<Link href={"/admin"}> Admin</Link> <Link href={"/admin"}> Admin</Link>
</div> </div>
<header> <header>
<Nav categories={await getCategories()} /> <Nav categories={await FetchManager.Category.list()} />
</header> </header>
<main>{children}</main> <main>{children}</main>
<Footer /> <Footer />

View File

@@ -1,3 +1,3 @@
export default function Home() { export default function HomePage() {
return <h1>Home</h1>; return <h1>Home</h1>;
} }

View File

@@ -1,23 +1,21 @@
import React from "react"; import React from "react";
export default function Typograhy() { export default function TypograhyPage() {
return ( return (
<div> <div>
<h1>Testing this headline</h1> <h1>Testing this headline</h1>
<h2>Testing this headline</h2> <h2>Testing this headline</h2>
<h3>Testing this headline</h3> <h3>Testing this headline</h3>
<h4>Testing this headline</h4> <h4>Testing this headline</h4>
<h5>Testing this headline</h5> <h5>Testing this headline</h5>
<h6>Testing this headline</h6> <h6>Testing this headline</h6>
<br /> <br />
<p> <p>
This is a paragraph Lorem ipsum dolor sit, amet consectetur adipisicing This is a paragraph Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dolores enim unde obcaecati ea
elit. Dolores enim unde obcaecati ea harum voluptate, nisi quia. Quod, harum voluptate, nisi quia. Quod, et autem! Aperiam mollitia ullam ab eaque quidem facilis est ducimus delectus.
et autem! Aperiam mollitia ullam ab eaque quidem facilis est ducimus </p>
delectus. <br />
</p> <a href="#">This is a link</a>
<br /> </div>
<a href="#">This is a link</a> );
</div>
);
} }

View File

@@ -1,7 +1,5 @@
import React from "react"; import React from "react";
import styles from "../../../../styles/modules/ArticleContentTable.module.scss"; import styles from "../styles/modules/ArticleContentTable.module.scss";
import { Article } from "@prisma/client";
import { IContentTableEntry } from "../../../../types/contentTable";
export default function ContentTable({ contentTableData }: { contentTableData: any }) { export default function ContentTable({ contentTableData }: { contentTableData: any }) {
return ( return (

View File

@@ -8,10 +8,9 @@ import styles from "../styles/modules/markdown.module.scss";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
import remarkGemoji from "remark-gemoji"; import remarkGemoji from "remark-gemoji";
import remarkStringify from "remark-stringify"; import remarkStringify from "remark-stringify";
import { useState, useEffect } from "react";
import { useLocalStorage } from "usehooks-ts";
import React from "react"; import React from "react";
import Head from "../app/head";
import { formatTextToUrlName } from "../utils"; import { formatTextToUrlName } from "../utils";
function flatten(text, child) { function flatten(text, child) {
@@ -31,6 +30,7 @@ export default function Markdown({ value }: { value: any }) {
className={styles.markdown} className={styles.markdown}
//@ts-ignore //@ts-ignore
remarkPlugins={[remarkGfm, remarkGemoji, remarkStringify]} remarkPlugins={[remarkGfm, remarkGemoji, remarkStringify]}
//@ts-ignore
components={{ components={{
h1: HeadingRenderer, h1: HeadingRenderer,
h2: HeadingRenderer, h2: HeadingRenderer,

28
components/Sidebar.tsx Normal file
View File

@@ -0,0 +1,28 @@
import React from "react";
import styles from "../styles/modules/Sidebar.module.scss";
export default function Sidebar() {
return (
<div className={styles.sidebar}>
<div className={styles.stickyContainer}>
<div className={styles.sidebarContainer}>
<h3>Popular</h3>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
</div>
<div className={styles.sidebarContainer}>
<h3>Related</h3>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
<a href="#"> Set up Docker</a>
</div>
<div className={styles.adContainer}>Future advertisement</div>
</div>
</div>
);
}

77
manager/fetchManager.ts Normal file
View File

@@ -0,0 +1,77 @@
import { Article, Category } from '@prisma/client';
import { Prisma } from "@prisma/client";
import urlJoin from "url-join";
import { apiUrl } from "../global";
const GLOBAL_NO_CACHE: boolean = true;
export type ArticleWithIncludes = Prisma.ArticleGetPayload<{ include: { category: true, image: true } }>
export type CategoryWithIncludes = Prisma.CategoryGetPayload<{ include: { svg: true } }>
export interface FetchError {
code: number;
message?: string;
data?: any;
}
export class FetchManager {
static Article = class {
static async list(noCache: boolean = false): Promise<ArticleWithIncludes[]> {
const response = await fetch(urlJoin(apiUrl, `articles`), {
cache: GLOBAL_NO_CACHE || noCache ? "no-cache" : "force-cache",
next: { revalidate: 60 * 10 },
})
return await response.json()
}
static async get(id: string, noCache: boolean = false): Promise<ArticleWithIncludes> {
const response = await fetch(urlJoin(apiUrl, `articles/${id}`), {
cache: GLOBAL_NO_CACHE || noCache ? "no-cache" : "force-cache",
next: { revalidate: 60 * 10 },
})
return await response.json()
}
static async getByName(name: string, noCache: boolean = false): Promise<ArticleWithIncludes> {
const response = await fetch(urlJoin(apiUrl, `articles/name/${name}`), {
cache: GLOBAL_NO_CACHE || noCache ? "no-cache" : "force-cache",
next: { revalidate: 60 * 10 },
})
return await response.json()
}
}
static Category = class {
static async list(noCache: boolean = false): Promise<CategoryWithIncludes[]> {
const response = await fetch(urlJoin(apiUrl, `categories`), {
cache: GLOBAL_NO_CACHE || noCache ? "no-cache" : "force-cache",
next: { revalidate: 60 * 10 },
})
return await response.json()
}
static async get(id: string, noCache: boolean = false): Promise<CategoryWithIncludes> {
const response = await fetch(urlJoin(apiUrl, `categories/${id}`), {
cache: GLOBAL_NO_CACHE || noCache ? "no-cache" : "force-cache",
next: { revalidate: 60 * 10 },
})
return await response.json()
}
static async getByName(name: string, noCache: boolean = false): Promise<CategoryWithIncludes> {
const response = await fetch(urlJoin(apiUrl, `categories/name/${name}`), {
cache: GLOBAL_NO_CACHE || noCache ? "no-cache" : "force-cache",
next: { revalidate: 60 * 10 },
})
return await response.json()
}
}
}

View File

@@ -1,26 +1,8 @@
/** @type {import('next').NextConfig} */ /** @type {import('next').NextConfig} */
const nextConfig = { const nextConfig = {
reactStrictMode: true,
experimental: { experimental: {
appDir: true, appDir: true,
}, },
typescript: {
// !! WARN !!
// Dangerously allow production builds to successfully complete even if your project has type errors.
ignoreBuildErrors: true,
},
images: {
remotePatterns: [
{
protocol: "https",
hostname: "c2.staticflickr.com",
},
{
protocol: "https",
hostname: "c4.staticflickr.com",
},
],
},
}; };
module.exports = nextConfig; module.exports = nextConfig;

2962
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@
"scripts": { "scripts": {
"prisma": "prisma generate && prisma db push && prisma studio", "prisma": "prisma generate && prisma db push && prisma studio",
"dev": "next dev", "dev": "next dev",
"build": "prisma generate && prisma migrate deploy && next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"vercel-build": "prisma generate && prisma db push && next build", "vercel-build": "prisma generate && prisma db push && next build",
@@ -23,7 +23,6 @@
"eslint-config-next": "13.0.7", "eslint-config-next": "13.0.7",
"marked": "^4.2.4", "marked": "^4.2.4",
"next": "^13.1.6", "next": "^13.1.6",
"next-gallery": "^1.1.0",
"prismjs": "^1.29.0", "prismjs": "^1.29.0",
"react": "18.2.0", "react": "18.2.0",
"react-code-blocks": "^0.0.9-0", "react-code-blocks": "^0.0.9-0",
@@ -41,8 +40,7 @@
"remark-stringify": "^10.0.2", "remark-stringify": "^10.0.2",
"sass": "^1.57.0", "sass": "^1.57.0",
"typescript": "4.9.4", "typescript": "4.9.4",
"url-join": "^5.0.0", "url-join": "^5.0.0"
"usehooks-ts": "^2.9.1"
}, },
"devDependencies": { "devDependencies": {
"@fec/remark-a11y-emoji": "^3.1.0", "@fec/remark-a11y-emoji": "^3.1.0",

View File

@@ -1,6 +1,8 @@
import { Request, Response } from "express"; import { Request, Response } from "express";
import prisma from "../../../lib/prisma"; import prisma from "../../../lib/prisma";
//@ts-ignore
import { Prisma } from "@prisma/client"; import { Prisma } from "@prisma/client";
//@ts-ignore
import { Article, Category } from "@prisma/client"; import { Article, Category } from "@prisma/client";
import { ResponseError } from "../../../types/responseErrors"; import { ResponseError } from "../../../types/responseErrors";
import { formatTextToUrlName } from "../../../utils"; import { formatTextToUrlName } from "../../../utils";
@@ -111,9 +113,11 @@ export default async function handler(req: Request, res: Response) {
title: data.title, title: data.title,
name: formatTextToUrlName(data.title), name: formatTextToUrlName(data.title),
introduction: data.introduction, introduction: data.introduction,
//@ts-ignore
categoryId: data.categoryId, categoryId: data.categoryId,
contentTable: data.contentTable, contentTable: data.contentTable,
markdown: data.markdown, markdown: data.markdown,
//@ts-ignore
imageId: data.imageId, imageId: data.imageId,
} }

View File