This commit is contained in:
Janis
2023-01-29 20:01:56 +01:00
parent d3e5295832
commit bc29de3255
119 changed files with 26881 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
import React from "react";
import styles from "../styles/modules/ArticleContentTable.module.scss";
export default function ContentTable({ contentTableData }: { contentTableData: any }) {
return (
<div className={styles.articleContentTable}>
<div className={styles.stickyContainer}>
<div className={styles.list}>
<h2>Contents</h2>
{contentTableData?.map((e, i) => {
return (
<a key={i} href={"#" + e.anchor}>
{e.title}
</a>
);
})}
</div>
{contentTableData?.length < 15 ? <div className={styles.adContainer}>Future advertisement</div> : ""}
</div>
</div>
);
}

40
components/Footer.tsx Normal file
View File

@@ -0,0 +1,40 @@
import React from "react";
import styles from "../styles/modules/Footer.module.scss";
import Image from "next/image";
export default function Footer() {
return (
<footer className={styles.footer}>
<div className={styles.adContainer}>Future advertisement</div>
<div className={styles.content}>
<div className={styles.company}>
<Image
src={"/images/logo.svg"}
width={190}
height={52}
alt={"Logo"}
/>
<h1>Simple tutorials for everyone!</h1>
</div>
<div className={styles.links}>
<div className={styles.grid}>
<a href="#">Tutorials</a>
<a href="#">Contact</a>
<a href="#">About</a>
<a></a>
<a href="#">Report Bug</a>
<a href="#">Legal</a>
<a></a>
<a href="#">Feedback</a>
<a href="#">Privacy</a>
<a></a>
<a></a>
<a href="#">Cookies</a>
</div>
</div>
</div>
</footer>
);
}

76
components/Markdown.tsx Normal file
View File

@@ -0,0 +1,76 @@
"use client";
import PropTypes from "prop-types";
import ReactMarkdown from "react-markdown";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import oneDark from "react-syntax-highlighter/dist/esm/styles/prism/one-dark";
import oneLight from "react-syntax-highlighter/dist/esm/styles/prism/one-light";
import styles from "../styles/modules/markdown.module.scss";
import remarkGfm from "remark-gfm";
import remarkGemoji from "remark-gemoji";
import remarkStringify from "remark-stringify";
import React from "react";
import { formatTextToUrlName } from "../utils";
function flatten(text, child) {
return typeof child === "string" ? text + child : React.Children.toArray(child.props.children).reduce(flatten, text);
}
function HeadingRenderer({ children, level }) {
children = React.Children.toArray(children);
const text = children.reduce(flatten, "");
return React.createElement("h" + level, { id: formatTextToUrlName(text) }, children);
}
export default function Markdown({ value }: { value: any }) {
return (
<div>
<ReactMarkdown
className={styles.markdown}
//@ts-ignore
remarkPlugins={[remarkGfm, remarkGemoji, remarkStringify]}
//@ts-ignore
components={{
h1: HeadingRenderer,
h2: HeadingRenderer,
h3: HeadingRenderer,
h4: HeadingRenderer,
h5: HeadingRenderer,
h6: HeadingRenderer,
code({ node, inline, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || "");
return !inline ? (
<>
<div className={styles.toolbar}>
<div
onClick={() => {
navigator.clipboard.writeText(String(children).replace(/\n$/, ""));
}}
className={styles.copyBtn}
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M502.6 70.63l-61.25-61.25C435.4 3.371 427.2 0 418.7 0H255.1c-35.35 0-64 28.66-64 64l.0195 256C192 355.4 220.7 384 256 384h192c35.2 0 64-28.8 64-64V93.25C512 84.77 508.6 76.63 502.6 70.63zM464 320c0 8.836-7.164 16-16 16H255.1c-8.838 0-16-7.164-16-16L239.1 64.13c0-8.836 7.164-16 16-16h128L384 96c0 17.67 14.33 32 32 32h47.1V320zM272 448c0 8.836-7.164 16-16 16H63.1c-8.838 0-16-7.164-16-16L47.98 192.1c0-8.836 7.164-16 16-16H160V128H63.99c-35.35 0-64 28.65-64 64l.0098 256C.002 483.3 28.66 512 64 512h192c35.2 0 64-28.8 64-64v-32h-47.1L272 448z" />
</svg>
</div>
</div>
<SyntaxHighlighter style={oneDark} language={match ? match[1] : ""} PreTag="div" {...props}>
{String(children).replace(/\n$/, "")}
</SyntaxHighlighter>
</>
) : (
<code>{children}</code>
);
},
}}
>
{value}
</ReactMarkdown>
</div>
);
}
Markdown.propTypes = {
value: PropTypes.string.isRequired,
};

135
components/Nav.tsx Normal file
View File

@@ -0,0 +1,135 @@
"use client";
import styles from "../styles/modules/Nav.module.scss";
import Image from "next/image";
import Link from "next/link";
import { useEffect, useState } from "react";
import { Category } from "@prisma/client";
function switchTheme(theme) {
const bodyElement = document.getElementsByTagName("body")[0];
if (theme == "dark") {
bodyElement.classList.remove("theme-light");
} else {
bodyElement.classList.add("theme-light");
}
}
function toggleTheme() {
const svgElement = document.getElementById("themeSwitchSvg");
if (localStorage.getItem("theme") == "light") {
svgElement.style.animationDirection = "normal";
svgElement.style.animationName = styles.spinThemeSwitch;
} else {
svgElement.style.animationDirection = "reverse";
svgElement.style.animationName = styles.spinThemeSwitch;
}
setTimeout(() => {
if (localStorage.getItem("theme") == "light") {
localStorage.setItem("theme", "dark");
switchTheme("dark");
} else {
localStorage.setItem("theme", "light");
switchTheme("light");
}
svgElement.style.animationName = "";
}, 150);
}
export default function Nav({ categories }: { categories: Category[] }) {
const [searchResults, setSearchResults] = useState([]);
async function handleSearchInput(event) {
const query = event.target.value;
let result = await fetch(`/api/search?q=${query}`);
let json = await result.json();
if (json.length == 0 && query.length > 0) {
setSearchResults([{ name: "", title: "No article found..." }]);
} else {
setSearchResults(json);
}
}
useEffect(() => {
if (localStorage.getItem("theme") == "dark") {
switchTheme("dark");
} else {
switchTheme("light");
}
}, []);
useEffect(() => {
console.log(searchResults);
}, [searchResults]);
return (
<nav className={styles.nav}>
<div className={styles.containerLeft}>
<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.dropDown}>
<Link href="/articles">Categories</Link>
<div className={styles.dropDownContainer}>
<div className={styles.content}>
<Link href={"/articles"}>All</Link>
{categories?.map((cat, i) => {
{
return (
<Link key={i} href={`/articles/${cat.name.toLowerCase()}`}>
{cat.title}
</Link>
);
}
})}
</div>
</div>
</div>
</div>
</div>
<div className={styles.containerCenter}>
<div className={styles.searchBar}>
<div className={styles.icon}>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M416 208c0 45.9-14.9 88.3-40 122.7L502.6 457.4c12.5 12.5 12.5 32.8 0 45.3s-32.8 12.5-45.3 0L330.7 376c-34.4 25.2-76.8 40-122.7 40C93.1 416 0 322.9 0 208S93.1 0 208 0S416 93.1 416 208zM208 352c79.5 0 144-64.5 144-144s-64.5-144-144-144S64 128.5 64 208s64.5 144 144 144z" />
</svg>
</div>
<input onInput={handleSearchInput} type="text" name="" id="" />
</div>
<div className={styles.searchResults}>
<div className={styles.content}>
{searchResults.map((s) => {
{
return <Link href={`/articles/${s.name.toLowerCase()}`}>{s.title}</Link>;
}
})}
</div>
</div>
</div>
<div className={styles.containerRight}>
<div
className={styles.themeSwitch}
onClick={() => {
toggleTheme();
}}
>
<svg id="themeSwitchSvg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M448 256c0-106-86-192-192-192V448c106 0 192-86 192-192zm64 0c0 141.4-114.6 256-256 256S0 397.4 0 256S114.6 0 256 0S512 114.6 512 256z" />
</svg>
</div>
</div>
</nav>
);
}

28
components/Sidebar.tsx Normal file
View 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>
);
}