mirror of
https://github.com/DerTyp7/explainegy-nextjs.git
synced 2025-10-29 21:02:13 +01:00
refactor to pages
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
export default async function Layout({ children }) {
|
||||
export default async function AdminArticleEditorLayout({ children }) {
|
||||
return <div>{children}</div>;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import Markdown from "../../../../../components/Markdown";
|
||||
|
||||
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 [title, setTitle] = useState<string>("");
|
||||
const [selectCategoriesOptions, setSelectCategoriesOptions] = useState<any>([]);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import React from "react";
|
||||
|
||||
function AdminArticlesPage() {
|
||||
export default function AdminArticlesPage() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Page to manage articles</h1>
|
||||
@@ -11,5 +11,3 @@ function AdminArticlesPage() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminArticlesPage;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export default async function Layout({ children }) {
|
||||
export default async function AdminCategoriesEditorLayout({ children }) {
|
||||
return <div>{children}</div>;
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { apiUrl } from "../../../../../global";
|
||||
|
||||
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 [title, setTitle] = useState<string>("");
|
||||
const [color, setColor] = useState<string>("");
|
||||
|
||||
@@ -19,6 +19,6 @@ async function getImages(): Promise<GalleryImage[]> {
|
||||
}));
|
||||
}
|
||||
|
||||
export default async function page() {
|
||||
export default async function AdminImagesPage() {
|
||||
return <Gallery images={await getImages()} />;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -1,17 +1,13 @@
|
||||
import { Article } from "@prisma/client";
|
||||
import { GetArticle } from "./page";
|
||||
import { FetchManager } from "../../../../manager/fetchManager";
|
||||
|
||||
export default async function Head({
|
||||
params,
|
||||
}: {
|
||||
params: { articleName: string; categoryName: string };
|
||||
}) {
|
||||
const articleName: string = params.articleName;
|
||||
const article: Article = await GetArticle(articleName);
|
||||
return (
|
||||
<>
|
||||
<title>{article?.title}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</>
|
||||
);
|
||||
export default async function ArticleHead({ params }: { params: { articleName: string; categoryName: string } }) {
|
||||
const articleName: string = params.articleName;
|
||||
const article: Article = await FetchManager.Article.getByName(articleName);
|
||||
return (
|
||||
<>
|
||||
<title>{article?.title}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function Layout({ children }) {
|
||||
export default function ArticleLayout({ children }) {
|
||||
return <div>{children}</div>;
|
||||
}
|
||||
|
||||
@@ -1,31 +1,15 @@
|
||||
import { marked } from "marked";
|
||||
import ContentTable from "./ContentTable";
|
||||
import Sidebar from "./Sidebar";
|
||||
import ContentTable from "../../../../components/ContentTable";
|
||||
import Sidebar from "../../../../components/Sidebar";
|
||||
import styles from "../../../../styles/modules/Article.module.scss";
|
||||
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 { IContentTableEntry } from "../../../../types/contentTable";
|
||||
|
||||
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();
|
||||
}
|
||||
import { ArticleWithIncludes, FetchManager } from "../../../../manager/fetchManager";
|
||||
import { formatTextToUrlName } from "../../../../utils";
|
||||
|
||||
//* MAIN
|
||||
export default async function ArticlePage({ params }: { params: { articleName: string; categoryName: string } }) {
|
||||
const articleName: string = params.articleName.toLowerCase().replaceAll("%20", " ");
|
||||
const article: ArticleWithIncludes = await GetArticle(articleName);
|
||||
const articleName: string = formatTextToUrlName(params.articleName);
|
||||
const article: ArticleWithIncludes = await FetchManager.Article.getByName(articleName);
|
||||
|
||||
const dateUpdated: Date = new Date(article.dateUpdated);
|
||||
const dateCreated: Date = new Date(article.dateCreated);
|
||||
@@ -60,14 +44,6 @@ export default async function ArticlePage({ params }: { params: { articleName: s
|
||||
<p>{article?.introduction}</p>
|
||||
</div>
|
||||
<Markdown value={markdown} />
|
||||
|
||||
{/* <div
|
||||
className="markdown"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: ParseMarkdown(markdown),
|
||||
}}
|
||||
></div>
|
||||
<LoadMarkdown /> */}
|
||||
</div>
|
||||
<Sidebar />
|
||||
</div>
|
||||
@@ -75,12 +51,8 @@ export default async function ArticlePage({ params }: { params: { articleName: s
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const articles: ArticleWithIncludes[] = await (
|
||||
await fetch(urlJoin(apiUrl, `articles/`), {
|
||||
cache: "no-cache",
|
||||
next: { revalidate: 60 * 10 },
|
||||
})
|
||||
).json();
|
||||
// Fetchmanager does not work here
|
||||
const articles: ArticleWithIncludes[] = await FetchManager.Article.list(false);
|
||||
|
||||
return await Promise.all(
|
||||
articles.map(async (article) => ({
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
import styles from "../../styles/modules/CategoryList.module.scss";
|
||||
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 } }>;
|
||||
|
||||
export async function GetCategories(): Promise<any> {
|
||||
const result: Response = await fetch(urlJoin(apiUrl, `categories`), {
|
||||
cache: "force-cache",
|
||||
next: { revalidate: 3600 },
|
||||
});
|
||||
|
||||
return result.json();
|
||||
}
|
||||
import { FetchManager } from "../../manager/fetchManager";
|
||||
|
||||
export default async function CategoryList() {
|
||||
const categories = await GetCategories();
|
||||
const categories = await FetchManager.Category.list();
|
||||
return (
|
||||
<div className={styles.categoryList}>
|
||||
<h1>Overview</h1>
|
||||
|
||||
12
app/head.tsx
12
app/head.tsx
@@ -1,7 +1,7 @@
|
||||
export default async function Head() {
|
||||
return (
|
||||
<>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</>
|
||||
);
|
||||
export default async function RootHead() {
|
||||
return (
|
||||
<>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,10 @@
|
||||
import "../styles/globals.scss";
|
||||
import "../styles/variables_colors.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 Footer from "../components/Footer";
|
||||
import Nav from "../components/Nav";
|
||||
|
||||
async function getCategories(): Promise<Category[]> {
|
||||
const result: Response = await fetch(urlJoin(apiUrl, `categories`), {
|
||||
cache: "no-cache",
|
||||
next: { revalidate: 3600 },
|
||||
});
|
||||
|
||||
return await result.json();
|
||||
}
|
||||
import { FetchManager } from "../manager/fetchManager";
|
||||
|
||||
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
@@ -27,7 +16,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
<Link href={"/admin"}> Admin</Link>
|
||||
</div>
|
||||
<header>
|
||||
<Nav categories={await getCategories()} />
|
||||
<Nav categories={await FetchManager.Category.list()} />
|
||||
</header>
|
||||
<main>{children}</main>
|
||||
<Footer />
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export default function Home() {
|
||||
return <h1>Home</h1>;
|
||||
export default function HomePage() {
|
||||
return <h1>Home</h1>;
|
||||
}
|
||||
|
||||
@@ -1,23 +1,21 @@
|
||||
import React from "react";
|
||||
|
||||
export default function Typograhy() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Testing this headline</h1>
|
||||
<h2>Testing this headline</h2>
|
||||
<h3>Testing this headline</h3>
|
||||
<h4>Testing this headline</h4>
|
||||
<h5>Testing this headline</h5>
|
||||
<h6>Testing this headline</h6>
|
||||
<br />
|
||||
<p>
|
||||
This is a paragraph Lorem ipsum dolor sit, amet consectetur adipisicing
|
||||
elit. Dolores enim unde obcaecati ea harum voluptate, nisi quia. Quod,
|
||||
et autem! Aperiam mollitia ullam ab eaque quidem facilis est ducimus
|
||||
delectus.
|
||||
</p>
|
||||
<br />
|
||||
<a href="#">This is a link</a>
|
||||
</div>
|
||||
);
|
||||
export default function TypograhyPage() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Testing this headline</h1>
|
||||
<h2>Testing this headline</h2>
|
||||
<h3>Testing this headline</h3>
|
||||
<h4>Testing this headline</h4>
|
||||
<h5>Testing this headline</h5>
|
||||
<h6>Testing this headline</h6>
|
||||
<br />
|
||||
<p>
|
||||
This is a paragraph Lorem ipsum dolor sit, amet consectetur adipisicing elit. Dolores enim unde obcaecati ea
|
||||
harum voluptate, nisi quia. Quod, et autem! Aperiam mollitia ullam ab eaque quidem facilis est ducimus delectus.
|
||||
</p>
|
||||
<br />
|
||||
<a href="#">This is a link</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import React from "react";
|
||||
import styles from "../../../../styles/modules/ArticleContentTable.module.scss";
|
||||
import { Article } from "@prisma/client";
|
||||
import { IContentTableEntry } from "../../../../types/contentTable";
|
||||
import styles from "../styles/modules/ArticleContentTable.module.scss";
|
||||
|
||||
export default function ContentTable({ contentTableData }: { contentTableData: any }) {
|
||||
return (
|
||||
@@ -8,10 +8,9 @@ import styles from "../styles/modules/markdown.module.scss";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import remarkGemoji from "remark-gemoji";
|
||||
import remarkStringify from "remark-stringify";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useLocalStorage } from "usehooks-ts";
|
||||
|
||||
import React from "react";
|
||||
import Head from "../app/head";
|
||||
|
||||
import { formatTextToUrlName } from "../utils";
|
||||
|
||||
function flatten(text, child) {
|
||||
@@ -31,6 +30,7 @@ export default function Markdown({ value }: { value: any }) {
|
||||
className={styles.markdown}
|
||||
//@ts-ignore
|
||||
remarkPlugins={[remarkGfm, remarkGemoji, remarkStringify]}
|
||||
//@ts-ignore
|
||||
components={{
|
||||
h1: HeadingRenderer,
|
||||
h2: HeadingRenderer,
|
||||
|
||||
28
components/Sidebar.tsx
Normal file
28
components/Sidebar.tsx
Normal 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
77
manager/fetchManager.ts
Normal 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()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,26 +1,8 @@
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
experimental: {
|
||||
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;
|
||||
|
||||
2962
package-lock.json
generated
2962
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,7 +5,7 @@
|
||||
"scripts": {
|
||||
"prisma": "prisma generate && prisma db push && prisma studio",
|
||||
"dev": "next dev",
|
||||
"build": "prisma generate && prisma migrate deploy && next build",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint",
|
||||
"vercel-build": "prisma generate && prisma db push && next build",
|
||||
@@ -23,7 +23,6 @@
|
||||
"eslint-config-next": "13.0.7",
|
||||
"marked": "^4.2.4",
|
||||
"next": "^13.1.6",
|
||||
"next-gallery": "^1.1.0",
|
||||
"prismjs": "^1.29.0",
|
||||
"react": "18.2.0",
|
||||
"react-code-blocks": "^0.0.9-0",
|
||||
@@ -41,8 +40,7 @@
|
||||
"remark-stringify": "^10.0.2",
|
||||
"sass": "^1.57.0",
|
||||
"typescript": "4.9.4",
|
||||
"url-join": "^5.0.0",
|
||||
"usehooks-ts": "^2.9.1"
|
||||
"url-join": "^5.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@fec/remark-a11y-emoji": "^3.1.0",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Request, Response } from "express";
|
||||
import prisma from "../../../lib/prisma";
|
||||
//@ts-ignore
|
||||
import { Prisma } from "@prisma/client";
|
||||
//@ts-ignore
|
||||
import { Article, Category } from "@prisma/client";
|
||||
import { ResponseError } from "../../../types/responseErrors";
|
||||
import { formatTextToUrlName } from "../../../utils";
|
||||
@@ -111,9 +113,11 @@ export default async function handler(req: Request, res: Response) {
|
||||
title: data.title,
|
||||
name: formatTextToUrlName(data.title),
|
||||
introduction: data.introduction,
|
||||
//@ts-ignore
|
||||
categoryId: data.categoryId,
|
||||
contentTable: data.contentTable,
|
||||
markdown: data.markdown,
|
||||
//@ts-ignore
|
||||
imageId: data.imageId,
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user