mirror of
https://github.com/DerTyp7/explainegy-nextjs.git
synced 2025-10-29 21:02:13 +01:00
ads
This commit is contained in:
14
app/Nav.tsx
14
app/Nav.tsx
@@ -4,9 +4,6 @@ import Image from "next/image";
|
|||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import { Category } from "@prisma/client";
|
import { Category } from "@prisma/client";
|
||||||
import urlJoin from "url-join";
|
|
||||||
import { apiUrl } from "./global";
|
|
||||||
import { GetStaticProps } from "next";
|
|
||||||
|
|
||||||
function switchTheme(theme) {
|
function switchTheme(theme) {
|
||||||
const bodyElement = document.getElementsByTagName("body")[0];
|
const bodyElement = document.getElementsByTagName("body")[0];
|
||||||
@@ -71,7 +68,16 @@ export default function Nav({ categories }: { categories: Category[] }) {
|
|||||||
return (
|
return (
|
||||||
<nav className={styles.nav}>
|
<nav className={styles.nav}>
|
||||||
<div className={styles.containerLeft}>
|
<div className={styles.containerLeft}>
|
||||||
<Image src={"/images/logo.svg"} height={40} width={160} alt="Nav bar logo" />
|
<Image
|
||||||
|
src={"/images/logo.svg"}
|
||||||
|
height={40}
|
||||||
|
width={160}
|
||||||
|
alt="Nav bar logo"
|
||||||
|
onClick={() => {
|
||||||
|
window.open("/", "_self");
|
||||||
|
}}
|
||||||
|
className={styles.logo}
|
||||||
|
/>
|
||||||
<div className={styles.links}>
|
<div className={styles.links}>
|
||||||
<div className={styles.dropDown}>
|
<div className={styles.dropDown}>
|
||||||
<Link href="/articles">Categories</Link>
|
<Link href="/articles">Categories</Link>
|
||||||
|
|||||||
@@ -9,17 +9,9 @@ import urlJoin from "url-join";
|
|||||||
import { apiUrl } from "../../../global";
|
import { apiUrl } from "../../../global";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
|
|
||||||
type ArticleWithContentTableEntries = Prisma.ArticleGetPayload<{ include: { contentTableEntries: true } }>;
|
type ArticleWithIncludes = Prisma.ArticleGetPayload<{
|
||||||
type ArticleWithCategory = Prisma.ArticleGetPayload<{ include: { category: true } }>;
|
include: { contentTableEntries: true; category: true; image: true };
|
||||||
|
}>;
|
||||||
// export async function GetContentTableEntries(article: Article): Promise<ContentTableEntry[]> {
|
|
||||||
// const entries = await prisma.contentTableEntry.findMany({
|
|
||||||
// where: { articleId: article?.id ?? 1 },
|
|
||||||
// orderBy: { orderIndex: "asc" },
|
|
||||||
// });
|
|
||||||
|
|
||||||
// return entries;
|
|
||||||
// }
|
|
||||||
|
|
||||||
export async function GetArticle(articleName: string): Promise<any> {
|
export async function GetArticle(articleName: string): Promise<any> {
|
||||||
const result: Response = await fetch(urlJoin(apiUrl, `articles/${articleName ?? ""}`), {
|
const result: Response = await fetch(urlJoin(apiUrl, `articles/${articleName ?? ""}`), {
|
||||||
@@ -38,7 +30,10 @@ function ParseMarkdown(markdown: string): string {
|
|||||||
//* 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 = params.articleName.toLowerCase().replaceAll("%20", " ");
|
||||||
const article: ArticleWithContentTableEntries = await GetArticle(articleName);
|
const article: ArticleWithIncludes = await GetArticle(articleName);
|
||||||
|
const dateUpdated: Date = new Date(article.dateUpdated);
|
||||||
|
const dateCreated: Date = new Date(article.dateCreated);
|
||||||
|
const dateOptions: Intl.DateTimeFormatOptions = { month: "long", day: "numeric", year: "numeric" };
|
||||||
const markdown: string = article?.markdown ?? "";
|
const markdown: string = article?.markdown ?? "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -46,22 +41,27 @@ export default async function ArticlePage({ params }: { params: { articleName: s
|
|||||||
<ContentTable contentTableEntries={article.contentTableEntries} />
|
<ContentTable contentTableEntries={article.contentTableEntries} />
|
||||||
<div className={styles.tutorialContent}>
|
<div className={styles.tutorialContent}>
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<p className="text-muted">Published on January 13, 2022</p>
|
<p className={`${styles.dates} text-muted`}>
|
||||||
|
{`Published on ${dateCreated.toLocaleDateString("en-US", dateOptions)}`}
|
||||||
|
<br />
|
||||||
|
{dateUpdated > dateCreated ? `Updated on ${dateUpdated.toLocaleDateString("en-US", dateOptions)}` : ""}
|
||||||
|
</p>
|
||||||
|
|
||||||
<h1>{article?.title}</h1>
|
<h1>{article?.title}</h1>
|
||||||
<div className={styles.tags}>
|
<div className={styles.tags}>
|
||||||
<a href="#">Docker</a> <a href="#">Setup</a> <a href="#">Ubuntu</a>
|
<a href="#">Docker</a> <a href="#">Setup</a> <a href="#">Ubuntu</a>
|
||||||
</div>
|
</div>
|
||||||
<Image
|
<Image
|
||||||
src={"/images/test.jpg"}
|
src={article?.image?.url ?? ""}
|
||||||
height={350}
|
height={350}
|
||||||
width={750}
|
width={750}
|
||||||
alt="Image"
|
alt={article?.image?.alt ?? ""}
|
||||||
quality={100}
|
quality={100}
|
||||||
placeholder="blur"
|
placeholder="blur"
|
||||||
blurDataURL="/images/blur.png"
|
blurDataURL="/images/blur.png"
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
|
<p>{article?.introduction}</p>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="markdown"
|
className="markdown"
|
||||||
@@ -77,7 +77,7 @@ export default async function ArticlePage({ params }: { params: { articleName: s
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function generateStaticParams() {
|
export async function generateStaticParams() {
|
||||||
const articles: ArticleWithCategory[] = await (
|
const articles: ArticleWithIncludes[] = await (
|
||||||
await fetch(urlJoin(apiUrl, `articles/`), {
|
await fetch(urlJoin(apiUrl, `articles/`), {
|
||||||
cache: "force-cache",
|
cache: "force-cache",
|
||||||
next: { revalidate: 60 * 10 },
|
next: { revalidate: 60 * 10 },
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export default async function CategoryPage({ params }: { params: { categoryName:
|
|||||||
const allArticles: Article[] = await GetAllArticles(categoryName);
|
const allArticles: Article[] = await GetAllArticles(categoryName);
|
||||||
const popularArticles: Article[] = await GetPopularArticles(categoryName);
|
const popularArticles: Article[] = await GetPopularArticles(categoryName);
|
||||||
const recentArticles: Article[] = await GetRecentArticles(categoryName);
|
const recentArticles: Article[] = await GetRecentArticles(categoryName);
|
||||||
console.log(popularArticles);
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.category}>
|
<div className={styles.category}>
|
||||||
<h1>{category?.title}</h1>
|
<h1>{category?.title}</h1>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import prisma from "../../../lib/prisma";
|
|||||||
import { Article, Prisma, ContentTableEntry } from '@prisma/client';
|
import { Article, Prisma, ContentTableEntry } from '@prisma/client';
|
||||||
import { ResponseError } from "../../../types/responseErrors";
|
import { ResponseError } from "../../../types/responseErrors";
|
||||||
|
|
||||||
type ArticleWithIncludes = Prisma.ArticleGetPayload<{ include: { contentTableEntries: true, category: true } }>
|
type ArticleWithIncludes = Prisma.ArticleGetPayload<{ include: { contentTableEntries: true, category: true, image: true } }>
|
||||||
|
|
||||||
function sortContentTableEntries(entries: ContentTableEntry[]): ContentTableEntry[] {
|
function sortContentTableEntries(entries: ContentTableEntry[]): ContentTableEntry[] {
|
||||||
return entries.sort((a, b) => a.orderIndex - b.orderIndex);
|
return entries.sort((a, b) => a.orderIndex - b.orderIndex);
|
||||||
@@ -16,7 +16,7 @@ export default async function handler(req: Request, res: Response) {
|
|||||||
const articleName: string = req.query.articleName.toString();
|
const articleName: string = req.query.articleName.toString();
|
||||||
|
|
||||||
await prisma.article
|
await prisma.article
|
||||||
.findUnique({ where: { name: articleName }, include: { category: true, contentTableEntries: true } })
|
.findUnique({ where: { name: articleName }, include: { category: true, contentTableEntries: true, image: true } })
|
||||||
.then((result: ArticleWithIncludes) => {
|
.then((result: ArticleWithIncludes) => {
|
||||||
if (result !== null) {
|
if (result !== null) {
|
||||||
result.contentTableEntries = sortContentTableEntries(result.contentTableEntries);
|
result.contentTableEntries = sortContentTableEntries(result.contentTableEntries);
|
||||||
|
|||||||
@@ -11,12 +11,13 @@ model Article {
|
|||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String @unique
|
name String @unique
|
||||||
title String @unique
|
title String @unique
|
||||||
|
introduction String @default("")
|
||||||
|
imageId Int?
|
||||||
|
image Image? @relation(fields: [imageId], references: [id])
|
||||||
markdown String
|
markdown String
|
||||||
contentTableEntries ContentTableEntry[]
|
contentTableEntries ContentTableEntry[]
|
||||||
categoryId Int?
|
categoryId Int?
|
||||||
category Category? @relation(fields: [categoryId], references: [id])
|
category Category? @relation(fields: [categoryId], references: [id])
|
||||||
typeId Int?
|
|
||||||
type ArticleType? @relation(fields: [typeId], references: [id])
|
|
||||||
dateCreated DateTime @default(now())
|
dateCreated DateTime @default(now())
|
||||||
dateUpdated DateTime @default(now())
|
dateUpdated DateTime @default(now())
|
||||||
}
|
}
|
||||||
@@ -44,20 +45,13 @@ model Category {
|
|||||||
dateUpdated DateTime @default(now())
|
dateUpdated DateTime @default(now())
|
||||||
}
|
}
|
||||||
|
|
||||||
model ArticleType {
|
|
||||||
id Int @id @default(autoincrement())
|
|
||||||
name String @unique
|
|
||||||
title String @unique
|
|
||||||
Article Article[]
|
|
||||||
dateCreated DateTime @default(now())
|
|
||||||
dateUpdated DateTime @default(now())
|
|
||||||
}
|
|
||||||
|
|
||||||
model Image {
|
model Image {
|
||||||
id Int @id @default(autoincrement())
|
id Int @id @default(autoincrement())
|
||||||
name String @unique
|
name String @unique
|
||||||
|
alt String @default("")
|
||||||
url String @default("")
|
url String @default("")
|
||||||
dateCreated DateTime @default(now())
|
dateCreated DateTime @default(now())
|
||||||
|
Article Article[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model Svg {
|
model Svg {
|
||||||
|
|||||||
@@ -22,12 +22,35 @@
|
|||||||
padding: 10px 0px 10px 0px;
|
padding: 10px 0px 10px 0px;
|
||||||
gap: 10px 0px;
|
gap: 10px 0px;
|
||||||
|
|
||||||
h1 {
|
.dates {
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
width: min(100%, 750px);
|
width: min(100%, 750px);
|
||||||
height: auto;
|
height: auto;
|
||||||
aspect-ratio: 15/7;
|
aspect-ratio: 15/7;
|
||||||
|
border-radius: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tags {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 5px 10px;
|
||||||
|
a {
|
||||||
|
font-size: 0.8em;
|
||||||
|
background-color: var(--color-background-article-tag);
|
||||||
|
opacity: 0.9;
|
||||||
|
color: var(--color-font-article-tag);
|
||||||
|
padding: 5px 10px 5px 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-decoration: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--color-font-article-tag) !important;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,9 @@
|
|||||||
column-gap: 20px;
|
column-gap: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.links {
|
.links {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|||||||
@@ -18,7 +18,8 @@
|
|||||||
--color-background-dropdown: var(--color-background-body);
|
--color-background-dropdown: var(--color-background-body);
|
||||||
--color-accent: #2294ff;
|
--color-accent: #2294ff;
|
||||||
--color-font-link: var(--color-accent);
|
--color-font-link: var(--color-accent);
|
||||||
|
--color-font-article-tag: #fff;
|
||||||
|
--color-background-article-tag: #007aec;
|
||||||
--color-font-link-hover: #5caffc;
|
--color-font-link-hover: #5caffc;
|
||||||
|
|
||||||
/* Colors: Markdown */
|
/* Colors: Markdown */
|
||||||
|
|||||||
Reference in New Issue
Block a user