mirror of
https://github.com/DerTyp7/explainegy-nextjs.git
synced 2025-10-29 21:02:13 +01:00
Now starting with real commit messages
This commit is contained in:
18
app/Nav.tsx
18
app/Nav.tsx
@@ -1,10 +1,13 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { time } from "console";
|
|
||||||
import styles from "../styles/Nav.module.scss";
|
import styles from "../styles/Nav.module.scss";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import Category from "./articles/[categoryName]/page";
|
|
||||||
|
export type NavCategory = {
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
};
|
||||||
|
|
||||||
function switchTheme(theme) {
|
function switchTheme(theme) {
|
||||||
const bodyElement = document.getElementsByTagName("body")[0];
|
const bodyElement = document.getElementsByTagName("body")[0];
|
||||||
@@ -39,7 +42,7 @@ function toggleTheme() {
|
|||||||
}, 150);
|
}, 150);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Nav({ categories }) {
|
export default function Nav({ categories }: { categories: NavCategory[] }) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (localStorage.getItem("theme") == "dark") {
|
if (localStorage.getItem("theme") == "dark") {
|
||||||
switchTheme("dark");
|
switchTheme("dark");
|
||||||
@@ -58,15 +61,18 @@ export default function Nav({ categories }) {
|
|||||||
/>
|
/>
|
||||||
<div className={styles.links}>
|
<div className={styles.links}>
|
||||||
<div className={styles.dropDown}>
|
<div className={styles.dropDown}>
|
||||||
Categories
|
<Link href="/articles">Categories</Link>
|
||||||
<div className={styles.dropDownContainer}>
|
<div className={styles.dropDownContainer}>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<Link href={"/articles"}>All</Link>
|
<Link href={"/articles"}>All</Link>
|
||||||
{categories?.map((cat, i) => {
|
{categories?.map((cat, i) => {
|
||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<Link href={`/articles/${cat.name.toLowerCase()}`}>
|
<Link
|
||||||
{cat?.name}
|
key={i}
|
||||||
|
href={`/articles/${cat.name.toLowerCase()}`}
|
||||||
|
>
|
||||||
|
{cat.title}
|
||||||
</Link>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,12 +32,14 @@ function ParseMarkdown(markdown: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//* MAIN
|
//* MAIN
|
||||||
export default async function Tutorial({
|
export default async function ArticlePage({
|
||||||
params,
|
params,
|
||||||
}: {
|
}: {
|
||||||
params: { articleName: string; categoryName: string };
|
params: { articleName: string; categoryName: string };
|
||||||
}) {
|
}) {
|
||||||
const articleName: string = params.articleName;
|
const articleName: string = params.articleName
|
||||||
|
.toLowerCase()
|
||||||
|
.replaceAll("%20", " ");
|
||||||
const article: Article = await GetArticle(articleName);
|
const article: Article = await GetArticle(articleName);
|
||||||
const markdown: string = article?.markdown ?? "";
|
const markdown: string = article?.markdown ?? "";
|
||||||
const contentTableEntries: ContentTableEntry[] = await GetContentTableEntries(
|
const contentTableEntries: ContentTableEntry[] = await GetContentTableEntries(
|
||||||
|
|||||||
@@ -1,3 +1,88 @@
|
|||||||
export default function Category() {
|
import styles from "../../../styles/Category.module.scss";
|
||||||
return <h1>List all articles in a category</h1>;
|
import Link from "next/link";
|
||||||
|
import prisma from "../../../lib/prisma";
|
||||||
|
import { Article, Category } from "@prisma/client";
|
||||||
|
|
||||||
|
export async function GetAllArticles(category: Category): Promise<Article[]> {
|
||||||
|
return await prisma.article.findMany({ where: { category: category } });
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GetPopularArticles(
|
||||||
|
category: Category
|
||||||
|
): Promise<Article[]> {
|
||||||
|
return await prisma.article.findMany({
|
||||||
|
where: { category: category },
|
||||||
|
take: 6,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GetRecentArticles(
|
||||||
|
category: Category
|
||||||
|
): Promise<Article[]> {
|
||||||
|
return await prisma.article.findMany({
|
||||||
|
where: { category: category },
|
||||||
|
take: 6,
|
||||||
|
orderBy: { dateCreated: "desc" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function GetCategory(categoryName: string): Promise<Category> {
|
||||||
|
return await prisma.category.findUnique({ where: { name: categoryName } });
|
||||||
|
}
|
||||||
|
export default async function CategoryPage({
|
||||||
|
params,
|
||||||
|
}: {
|
||||||
|
params: { categoryName: string };
|
||||||
|
}) {
|
||||||
|
const categoryName = params.categoryName.toLowerCase().replaceAll("%20", " ");
|
||||||
|
const category: Category = await GetCategory(categoryName);
|
||||||
|
const allArticles: Article[] = await GetAllArticles(category);
|
||||||
|
const popularArticles: Article[] = await GetPopularArticles(category);
|
||||||
|
const recentArticles: Article[] = await GetRecentArticles(category);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.category}>
|
||||||
|
<h1>{category?.title}</h1>
|
||||||
|
<div className={styles.content}>
|
||||||
|
<div className={`${styles.showcase} ${styles.smallShowcase}`}>
|
||||||
|
<h2>Most popular articles</h2>
|
||||||
|
{popularArticles?.map((a, i) => {
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<Link key={i} href={`/articles/${category.name}/${a.name}`}>
|
||||||
|
{a.name}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* <div className={`${styles.showcase} ${styles.smallShowcase}`}>
|
||||||
|
<h2>Most recent articles</h2>
|
||||||
|
{recentArticles?.map((a, i) => {
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<Link key={i} href={`/articles/${category.name}/${a.name}`}>
|
||||||
|
{a.name}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div> */}
|
||||||
|
|
||||||
|
<div className={styles.showcase}>
|
||||||
|
<h2>All articles</h2>
|
||||||
|
{allArticles?.map((a, i) => {
|
||||||
|
{
|
||||||
|
return (
|
||||||
|
<Link key={i} href={`/articles/${category.name}/${a.name}`}>
|
||||||
|
{a.name}
|
||||||
|
</Link>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,45 @@
|
|||||||
import styles from "../../styles/CategoryList.module.scss";
|
import styles from "../../styles/CategoryList.module.scss";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import prisma from "../../lib/prisma";
|
import prisma from "../../lib/prisma";
|
||||||
import { Category } from "@prisma/client";
|
import { Category, Svg, Prisma } from "@prisma/client";
|
||||||
import { Suspense } from "react";
|
import { Suspense } from "react";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
|
|
||||||
export async function GetCategories(): Promise<Category[]> {
|
type CategoryWithSvg = Prisma.CategoryGetPayload<{ include: { svg: true } }>;
|
||||||
return await prisma.category.findMany();
|
|
||||||
|
export async function GetCategories(): Promise<CategoryWithSvg[]> {
|
||||||
|
return await prisma.category.findMany({ include: { svg: true } });
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function CategoryList() {
|
export default async function CategoryList() {
|
||||||
const categories = await GetCategories();
|
const categories = await GetCategories();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.categoryList}>
|
<div className={styles.categoryList}>
|
||||||
<h1>Overview</h1>
|
<h1>Overview</h1>
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
<div className={styles.grid}>
|
<div className={styles.grid}>
|
||||||
{categories.map((cat, i) => {
|
{categories?.length > 0
|
||||||
return (
|
? categories.map((cat, i) => {
|
||||||
<div key={i} className={styles.linkContainer}>
|
return (
|
||||||
<Link
|
<div key={i} className={styles.linkContainer}>
|
||||||
href={`/articles/${cat.name.toLowerCase()}`}
|
<Link
|
||||||
style={{ backgroundColor: cat.color }}
|
href={`/articles/${cat.name.toLowerCase()}`}
|
||||||
>
|
style={{ backgroundColor: cat.color }}
|
||||||
<div className={styles.svgContainer}>
|
|
||||||
<svg
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
viewBox="0 0 640 512"
|
|
||||||
>
|
>
|
||||||
<path d={cat.svg} />
|
<div className={styles.svgContainer}>
|
||||||
</svg>
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
viewBox={cat?.svg?.viewbox}
|
||||||
|
>
|
||||||
|
<path d={cat?.svg?.path} />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{cat.title}
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{cat.name}
|
);
|
||||||
</Link>
|
})
|
||||||
</div>
|
: "We did not find any categories"}
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,9 +5,13 @@ import Nav from "./Nav";
|
|||||||
import Footer from "./Footer";
|
import Footer from "./Footer";
|
||||||
import { Category } from "@prisma/client";
|
import { Category } from "@prisma/client";
|
||||||
import prisma from "../lib/prisma";
|
import prisma from "../lib/prisma";
|
||||||
|
import { NavCategory } from "./Nav";
|
||||||
|
|
||||||
export async function GetCategories(): Promise<Category[]> {
|
export async function GetNavCategories(): Promise<NavCategory[]> {
|
||||||
return await prisma.category.findMany();
|
const result: NavCategory[] = await prisma.category.findMany({
|
||||||
|
select: { name: true, title: true },
|
||||||
|
});
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function RootLayout({
|
export default async function RootLayout({
|
||||||
@@ -21,7 +25,7 @@ export default async function RootLayout({
|
|||||||
|
|
||||||
<body className="body">
|
<body className="body">
|
||||||
<header>
|
<header>
|
||||||
<Nav categories={await GetCategories()} />
|
<Nav categories={await GetNavCategories()} />
|
||||||
</header>
|
</header>
|
||||||
<main>{children}</main>
|
<main>{children}</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"prisma": "prisma generate && prisma db push && prisma studio",
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "prisma generate && prisma migrate deploy && next build",
|
"build": "prisma generate && prisma migrate deploy && prisma db push && next build",
|
||||||
"start": "next start",
|
"start": "next start",
|
||||||
"lint": "next lint"
|
"lint": "next lint"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -35,8 +35,10 @@ model ContentTableEntry {
|
|||||||
model Category {
|
model Category {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String @unique
|
name String @unique
|
||||||
|
title String @unique
|
||||||
color String @unique
|
color String @unique
|
||||||
svg String @default("")
|
svgId Int
|
||||||
|
svg Svg @relation(fields: [svgId], references: [id])
|
||||||
Article Article[]
|
Article Article[]
|
||||||
dateCreated DateTime @default(now())
|
dateCreated DateTime @default(now())
|
||||||
dateUpdated DateTime @default(now())
|
dateUpdated DateTime @default(now())
|
||||||
@@ -45,7 +47,16 @@ model Category {
|
|||||||
model ArticleType {
|
model ArticleType {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String @unique
|
name String @unique
|
||||||
|
title String @unique
|
||||||
Article Article[]
|
Article Article[]
|
||||||
dateCreated DateTime @default(now())
|
dateCreated DateTime @default(now())
|
||||||
dateUpdated DateTime @default(now())
|
dateUpdated DateTime @default(now())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Svg {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
name String @unique
|
||||||
|
path String @default("")
|
||||||
|
viewbox String @default("0 0 512 512")
|
||||||
|
Category Category[]
|
||||||
|
}
|
||||||
|
|||||||
55
styles/Category.module.scss
Normal file
55
styles/Category.module.scss
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
@import "variables.scss";
|
||||||
|
.category {
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 50px;
|
||||||
|
row-gap: 50px;
|
||||||
|
padding: 0px 20px 0 20px;
|
||||||
|
.showcase {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr 1fr;
|
||||||
|
gap: 10px 10px;
|
||||||
|
|
||||||
|
@media (max-width: $category-breakpoint-1) {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: $category-breakpoint-2) {
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
font-size: 1em;
|
||||||
|
grid-column: 1 / -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: rgba(126, 126, 126, 0.1);
|
||||||
|
box-shadow: 0px 0px 15px 5px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 20px;
|
||||||
|
transition: all 50ms linear;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
max-width: 300px;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(126, 126, 126, 0.2);
|
||||||
|
box-shadow: 0px 0px 15px 5px rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.smallShowcase {
|
||||||
|
@media (max-width: $category-breakpoint-2) {
|
||||||
|
& > a:nth-child(n + 5) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -48,7 +48,7 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
row-gap: 20px;
|
row-gap: 20px;
|
||||||
background-color: #384d54;
|
background-color: #383d54;
|
||||||
color: white;
|
color: white;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
transition: all 100ms linear;
|
transition: all 100ms linear;
|
||||||
|
|||||||
@@ -26,3 +26,8 @@ $nav-breakpoint-4: 400px;
|
|||||||
/* CategoryList */
|
/* CategoryList */
|
||||||
$categoryList-breakpoint-1: 850px;
|
$categoryList-breakpoint-1: 850px;
|
||||||
$categoryList-breakpoint-2: 600px;
|
$categoryList-breakpoint-2: 600px;
|
||||||
|
|
||||||
|
/* Category */
|
||||||
|
|
||||||
|
$category-breakpoint-1: 800px;
|
||||||
|
$category-breakpoint-2: 550px;
|
||||||
|
|||||||
Reference in New Issue
Block a user