mirror of
https://github.com/DerTyp7/explainegy-nextjs.git
synced 2026-07-31 07:39:04 +02:00
add prisma
This commit is contained in:
@@ -1,18 +1,19 @@
|
||||
import React from "react";
|
||||
import { TutorialMeta } from "./page";
|
||||
import prisma from "../../../lib/prisma";
|
||||
import styles from "../../../styles/TutorialContentTable.module.scss";
|
||||
import { Article, ContentTableEntry } from "@prisma/client";
|
||||
|
||||
export default function ContentTable({
|
||||
tutorialMeta,
|
||||
contentTableEntries,
|
||||
}: {
|
||||
tutorialMeta: TutorialMeta;
|
||||
contentTableEntries: ContentTableEntry[];
|
||||
}) {
|
||||
return (
|
||||
<div className={styles.tutorialContentTable}>
|
||||
<div className={styles.stickyContainer}>
|
||||
<div className={styles.list}>
|
||||
<h2>Contents</h2>
|
||||
{tutorialMeta?.contentTable?.map((e, i) => {
|
||||
{contentTableEntries?.map((e, i) => {
|
||||
return (
|
||||
<a key={i} href={"#" + e.anchor}>
|
||||
{e.title}
|
||||
@@ -20,7 +21,7 @@ export default function ContentTable({
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{tutorialMeta?.contentTable?.length < 15 ? (
|
||||
{contentTableEntries?.length < 15 ? (
|
||||
<div className={styles.adContainer}>Future advertisement</div>
|
||||
) : (
|
||||
""
|
||||
17
app/tutorials/[articleName]/head.tsx
Normal file
17
app/tutorials/[articleName]/head.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Article } from "@prisma/client";
|
||||
import { GetArticle } from "./page";
|
||||
|
||||
export default async function Head({
|
||||
params,
|
||||
}: {
|
||||
params: { articleName: 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" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
73
app/tutorials/[articleName]/page.tsx
Normal file
73
app/tutorials/[articleName]/page.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import { marked } from "marked";
|
||||
import ContentTable from "./ContentTable";
|
||||
import Sidebar from "./Sidebar";
|
||||
import styles from "../../../styles/Tutorial.module.scss";
|
||||
import LoadMarkdown from "./LoadMarkdown";
|
||||
import prisma from "../../../lib/prisma";
|
||||
import { Article, ContentTableEntry } from "@prisma/client";
|
||||
|
||||
export async function GetContentTableEntries(
|
||||
article: Article
|
||||
): Promise<ContentTableEntry[]> {
|
||||
const entries = await prisma.contentTableEntry.findMany({
|
||||
where: { article: article },
|
||||
orderBy: { orderIndex: "asc" },
|
||||
});
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
export async function GetArticle(articleName: string) {
|
||||
const article = await prisma.article.findUnique({
|
||||
where: { name: articleName.toLowerCase() },
|
||||
});
|
||||
|
||||
return article;
|
||||
}
|
||||
|
||||
function ParseMarkdown(markdown: string): string {
|
||||
let result = marked.parse(markdown);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//* MAIN
|
||||
export default async function Tutorial({
|
||||
params,
|
||||
}: {
|
||||
params: { articleName: string };
|
||||
}) {
|
||||
const articleName: string = params.articleName;
|
||||
const article: Article = await GetArticle(articleName);
|
||||
const markdown: string = article.markdown;
|
||||
const contentTableEntries: ContentTableEntry[] = await GetContentTableEntries(
|
||||
article
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.tutorial}>
|
||||
<ContentTable contentTableEntries={contentTableEntries} />
|
||||
<div className={styles.tutorialContent}>
|
||||
<div className={styles.head}>
|
||||
<h1>{article.title}</h1>
|
||||
</div>
|
||||
<div
|
||||
className="markdown"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: ParseMarkdown(markdown),
|
||||
}}
|
||||
></div>
|
||||
<LoadMarkdown />
|
||||
</div>
|
||||
<Sidebar />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const articles = await prisma.article.findMany();
|
||||
|
||||
return articles.map((article) => ({
|
||||
articleName: article.name ?? "",
|
||||
}));
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import { GetTutorialMeta, TutorialMeta } from "./page";
|
||||
export default async function Head({
|
||||
params,
|
||||
}: {
|
||||
params: { tutorialId: string };
|
||||
}) {
|
||||
const tutorialId: string = params.tutorialId;
|
||||
const tutorialMeta: TutorialMeta = await GetTutorialMeta(tutorialId);
|
||||
return (
|
||||
<>
|
||||
<title>{tutorialMeta.title}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
import { marked } from "marked";
|
||||
import { db, storage } from "../../../firebase-config";
|
||||
import { collection, doc, getDoc, getDocs } from "firebase/firestore";
|
||||
import { getDownloadURL, ref } from "firebase/storage";
|
||||
import ContentTable from "./ContentTable";
|
||||
import Sidebar from "./Sidebar";
|
||||
import styles from "../../../styles/Tutorial.module.scss";
|
||||
import LoadMarkdown from "./LoadMarkdown";
|
||||
import Head from "next/head";
|
||||
|
||||
export type ContentTable = {
|
||||
anchor: string;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type TutorialMeta = {
|
||||
id: string;
|
||||
title: string;
|
||||
contentTable: ContentTable[];
|
||||
};
|
||||
|
||||
export async function GetTutorialMeta(
|
||||
tutorialId: string
|
||||
): Promise<TutorialMeta> {
|
||||
const firebaseData = await getDoc(doc(db, "tutorials", tutorialId));
|
||||
const firebaseJsonData = firebaseData.data();
|
||||
|
||||
const tutorial: TutorialMeta = {
|
||||
id: tutorialId,
|
||||
title: firebaseJsonData?.title ?? "Tutorial not found!",
|
||||
contentTable: firebaseJsonData?.contentTable ?? [],
|
||||
};
|
||||
return tutorial;
|
||||
}
|
||||
|
||||
async function FetchTutorialMarkdown(tutorialId: string) {
|
||||
try {
|
||||
const url = await getDownloadURL(
|
||||
ref(storage, `markdowns/${tutorialId}.md`)
|
||||
);
|
||||
const data = await fetch(url, {
|
||||
next: { revalidate: 30 * 60 },
|
||||
});
|
||||
return await data.text();
|
||||
} catch {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function ParseMarkdown(markdown: string): string {
|
||||
let result = marked.parse(markdown);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//* MAIN
|
||||
export default async function Tutorial({
|
||||
params,
|
||||
}: {
|
||||
params: { tutorialId: string };
|
||||
}) {
|
||||
const tutorialId: string = params.tutorialId;
|
||||
const tutorialMeta: TutorialMeta = await GetTutorialMeta(tutorialId);
|
||||
const markdown: string = await FetchTutorialMarkdown(tutorialId);
|
||||
|
||||
return (
|
||||
<div className={styles.tutorial}>
|
||||
<ContentTable tutorialMeta={tutorialMeta} />
|
||||
<div className={styles.tutorialContent}>
|
||||
<div className={styles.head}>
|
||||
<h1>{tutorialMeta.title}</h1>
|
||||
</div>
|
||||
<div
|
||||
className="markdown"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: ParseMarkdown(markdown),
|
||||
}}
|
||||
></div>
|
||||
<LoadMarkdown />
|
||||
</div>
|
||||
<Sidebar />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
const data = await getDocs(collection(db, "tutorials"));
|
||||
|
||||
return data.docs.map((doc) => ({
|
||||
tutorialId: doc.id,
|
||||
}));
|
||||
}
|
||||
Reference in New Issue
Block a user