mirror of
				https://github.com/DerTyp7/explainegy-nextjs.git
				synced 2025-10-31 05:37:12 +01: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
	 Janis
					Janis