format all src

This commit is contained in:
Ivan Dimitrov 2023-11-19 10:33:42 +02:00
parent eff108c7d0
commit 4cb2cddcef
10 changed files with 134 additions and 137 deletions

View File

@ -1,59 +1,58 @@
.md * { .md * {
@apply py-2 @apply py-2;
} }
.md ol { .md ol {
@apply list-decimal list-inside @apply list-decimal list-inside;
} }
.md ul { .md ul {
@apply list-disc list-inside @apply list-disc list-inside;
} }
.md hr { .md hr {
@apply m-4 @apply m-4;
} }
.md blockquote { .md blockquote {
@apply border-l-neutral-500 border-l-4 p-2 @apply border-l-neutral-500 border-l-4 p-2;
} }
.md blockquote p { .md blockquote p {
@apply before:content-['"'] after:content-['"'] @apply before:content-['"'] after:content-['"'];
} }
.md details { .md details {
@apply p-20 @apply p-20;
} }
.md code { .md code {
@apply rounded-lg @apply rounded-lg;
} }
.md h1 { .md h1 {
@apply text-6xl @apply text-6xl;
} }
.md h2 { .md h2 {
@apply text-5xl @apply text-5xl;
} }
.md h3 { .md h3 {
@apply text-4xl @apply text-4xl;
} }
.md h4 { .md h4 {
@apply text-3xl @apply text-3xl;
} }
.md h5 { .md h5 {
@apply text-2xl @apply text-2xl;
} }
.md h6 { .md h6 {
@apply text-xl @apply text-xl;
} }
.md a { .md a {
@apply underline text-teal-200 hover:text-cyan-500 @apply underline text-teal-200 hover:text-cyan-500;
} }

View File

@ -1,4 +1,4 @@
import styles from "./content.module.css" import styles from "./content.module.css";
import { getAllPaths, getContent } from "$lib/content"; import { getAllPaths, getContent } from "$lib/content";
import Markdown from "react-markdown"; import Markdown from "react-markdown";
import remarkGfm from "remark-gfm"; import remarkGfm from "remark-gfm";
@ -9,19 +9,19 @@ import { notFound } from "next/navigation";
import Link from "next/link"; import Link from "next/link";
import CopyButton from "$components/copy-button"; import CopyButton from "$components/copy-button";
import { getText } from "$lib/react"; import { getText } from "$lib/react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter" import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import codeStyle from 'react-syntax-highlighter/dist/esm/styles/prism/coldark-dark' import codeStyle from "react-syntax-highlighter/dist/esm/styles/prism/coldark-dark";
type Params = { type Params = {
slug: string[] slug: string[];
} };
type Props = { type Props = {
params: Params params: Params;
} };
export async function generateStaticParams(): Promise<Params[]> { export async function generateStaticParams(): Promise<Params[]> {
return getAllPaths().map(p => ({ slug: p.split("/") })) return getAllPaths().map(p => ({ slug: p.split("/") }));
} }
export default function Content({ params }: Props) { export default function Content({ params }: Props) {
@ -29,34 +29,34 @@ export default function Content({ params }: Props) {
const { data, content } = getContent(params.slug); const { data, content } = getContent(params.slug);
if (data.draft) { if (data.draft) {
notFound() notFound();
} }
const title = () => <span className="text-3xl">{data.title}</span> const title = () => <span className="text-3xl">{data.title}</span>;
const goal = () => const goal = () =>
data.goal ? data.goal ? (
( <div>
<div> <h2>The goal</h2>
<h2>The goal</h2> {data.goal}
{data.goal} </div>
</div> ) : (
) : ""
""; );
const role = () => const role = () =>
data.role ? data.role ? (
( <div>
<div> <h2>My role</h2>
<h2>My role</h2> {data.role}
{data.role} </div>
</div> ) : (
) : ""
""; );
const date = () => data.date ? (<span>{data.date}</span>) : "" const date = () => (data.date ? <span>{data.date}</span> : "");
const ctnt = () => const ctnt = () => (
<Markdown <Markdown
className={styles.md} className={styles.md}
remarkPlugins={[remarkGfm, remarkFrontmatter]} remarkPlugins={[remarkGfm, remarkFrontmatter]}
@ -65,14 +65,21 @@ export default function Content({ params }: Props) {
img({ height, width, src, alt, className }) { img({ height, width, src, alt, className }) {
return ( return (
<span className="w-full h-max p-20"> <span className="w-full h-max p-20">
<Image className={`w-full h-full border-2 px-2 ${className || ""}`} alt={alt!} height={Number(height) || imgSize} width={Number(width) || imgSize} src={`${data.slug}${src}`}></Image> <Image
className={`w-full h-full border-2 px-2 ${className || ""}`}
alt={alt!}
height={Number(height) || imgSize}
width={Number(width) || imgSize}
src={`${data.slug}${src}`}></Image>
</span> </span>
) );
}, },
a({ href, children, className }) { a({ href, children, className }) {
return ( return (
<Link className={className || ""} aria-label={getText(children)} href={href!} target="_blank">{children}</Link> <Link className={className || ""} aria-label={getText(children)} href={href!} target="_blank">
) {children}
</Link>
);
}, },
pre({ children, className }) { pre({ children, className }) {
return ( return (
@ -80,26 +87,24 @@ export default function Content({ params }: Props) {
<CopyButton text={getText(children)} /> <CopyButton text={getText(children)} />
<pre className={`${className || ""}`}>{children}</pre> <pre className={`${className || ""}`}>{children}</pre>
</div> </div>
) );
}, },
code({ children, ref, className, node, ...rest }) { code({ children, ref, className, node, ...rest }) {
const match = /language-(\w+)/.exec(className || '') const match = /language-(\w+)/.exec(className || "");
return match ? ( return match ? (
<SyntaxHighlighter <SyntaxHighlighter {...rest} language={match[1]} style={codeStyle}>
{...rest} {getText(children)}
language={match[1]} </SyntaxHighlighter>
style={codeStyle}
>{getText(children)}</SyntaxHighlighter>
) : ( ) : (
<code {...rest} className={`${className} text-orange-400 font-black font-mono`}> <code {...rest} className={`${className} text-orange-400 font-black font-mono`}>
{children} {children}
</code> </code>
) );
} },
}} }}>
>
{content} {content}
</Markdown> </Markdown>
);
return ( return (
<div className="w-full h-full p-4 lg:p-20 overflow-x-hidden overflow-scroll"> <div className="w-full h-full p-4 lg:p-20 overflow-x-hidden overflow-scroll">
@ -109,9 +114,7 @@ export default function Content({ params }: Props) {
{role()} {role()}
{date()} {date()}
</div> </div>
<div className="w-full m-auto lg:w-3/4 mt-10"> <div className="w-full m-auto lg:w-3/4 mt-10">{ctnt()}</div>
{ctnt()}
</div>
</div> </div>
) );
} }

View File

@ -2,12 +2,15 @@ import { faEnvelope } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const email = "ivan@idimitrov.dev"; const email = "ivan@idimitrov.dev";
const mailto = `mailto:${email}` const mailto = `mailto:${email}`;
const Contact = () => const Contact = () => (
<div className="w-full h-full p-2 grid place-content-center"> <div className="w-full h-full p-2 grid place-content-center">
<div className="flex flex-row gap-4"> <div className="flex flex-row gap-4">
<a aria-label={mailto} href={mailto}><FontAwesomeIcon className="w-14 h-14" icon={faEnvelope} /></a> <a aria-label={mailto} href={mailto}>
<FontAwesomeIcon className="w-14 h-14" icon={faEnvelope} />
</a>
</div> </div>
</div> </div>
);
export default Contact export default Contact;

View File

@ -4,29 +4,28 @@
@layer components { @layer components {
.btn { .btn {
@apply bg-gray-900 transition ease-in duration-200 text-gray-300 hover:bg-gray-700/60 rounded-md px-3 py-2 text-sm @apply bg-gray-900 transition ease-in duration-200 text-gray-300 hover:bg-gray-700/60 rounded-md px-3 py-2 text-sm;
} }
} }
@layer utilities { @layer utilities {
.gradient { .gradient {
@apply bg-gradient-to-br from-slate-950 via-red-700 to-yellow-400 @apply bg-gradient-to-br from-slate-950 via-red-700 to-yellow-400;
} }
} }
html * { html * {
@apply scrollbar scrollbar-thin scrollbar-thumb-sky-400 @apply scrollbar scrollbar-thin scrollbar-thumb-sky-400;
} }
body { body {
@apply gradient text-slate-50 w-screen h-screen overflow-hidden @apply gradient text-slate-50 w-screen h-screen overflow-hidden;
} }
main { main {
@apply flex flex-col w-full h-full bg-slate-950/95 @apply flex flex-col w-full h-full bg-slate-950/95;
} }
svg { svg {
@apply hover:text-sky-400 transition duration-200 ease-in @apply hover:text-sky-400 transition duration-200 ease-in;
} }

View File

@ -1,17 +1,13 @@
import './globals.css' import "./globals.css";
import Navbar from '$components/navbar' import Navbar from "$components/navbar";
import type { Metadata } from 'next' import type { Metadata } from "next";
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Ivan Dimitrov", title: "Ivan Dimitrov",
description: "Freelance Software Developer", description: "Freelance Software Developer",
} };
export default function RootLayout({ export default function RootLayout({ children }: { children: React.ReactNode }) {
children,
}: {
children: React.ReactNode
}) {
return ( return (
<html lang="en"> <html lang="en">
<body> <body>
@ -21,5 +17,5 @@ export default function RootLayout({
</main> </main>
</body> </body>
</html> </html>
) );
} }

View File

@ -5,18 +5,10 @@ import Link from "next/link";
const Home = () => ( const Home = () => (
<div className="grid w-full h-full place-content-center"> <div className="grid w-full h-full place-content-center">
<div className={"grid grid-cols-2 gap-4 place-content-center"}> <div className={"grid grid-cols-2 gap-4 place-content-center"}>
<Link <Link aria-label="GitHub" href={process.env.NEXT_PUBLIC_GITHUB_URL!} target="_blank">
aria-label="GitHub"
href={process.env.NEXT_PUBLIC_GITHUB_URL!}
target="_blank"
>
<FontAwesomeIcon className="w-14 h-14" icon={faGithub} /> <FontAwesomeIcon className="w-14 h-14" icon={faGithub} />
</Link> </Link>
<Link <Link aria-label="GitLab" href={process.env.NEXT_PUBLIC_GITLAB_URL!} target="_blank">
aria-label="GitLab"
href={process.env.NEXT_PUBLIC_GITLAB_URL!}
target="_blank"
>
<FontAwesomeIcon className="w-14 h-14" icon={faGitlab} /> <FontAwesomeIcon className="w-14 h-14" icon={faGitlab} />
</Link> </Link>
</div> </div>

View File

@ -1,28 +1,29 @@
"use client" "use client";
import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons" import { faCheck, faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useState } from "react" import { useState } from "react";
type Props = { type Props = {
text: string text: string;
} };
const CopyButton = ({ text }: Props) => { const CopyButton = ({ text }: Props) => {
const [visible, setVisible] = useState("invisible") const [visible, setVisible] = useState("invisible");
return ( return (
<button <button
className="absolute top-5 right-5" className="absolute top-5 right-5"
aria-label="copy" aria-label="copy"
onClick={() => { onClick={() => {
navigator.clipboard.writeText(text) navigator.clipboard.writeText(text);
setVisible("visible") setVisible("visible");
setTimeout(() => setVisible("invisible"), 1000) setTimeout(() => setVisible("invisible"), 1000);
}} }}>
> <span className={`${visible} absolute bottom-5 left-5`}>
<span className={`${visible} absolute bottom-5 left-5`}><FontAwesomeIcon className="text-green-400" icon={faCheck} /></span> <FontAwesomeIcon className="text-green-400" icon={faCheck} />
</span>
<FontAwesomeIcon icon={faCopy} /> <FontAwesomeIcon icon={faCopy} />
</button> </button>
) );
} };
export default CopyButton; export default CopyButton;

View File

@ -1,9 +1,9 @@
"use client" "use client";
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
const Navbar = () => { const Navbar = () => {
const path = usePathname() const path = usePathname();
const link = (text: string, href: string) => { const link = (text: string, href: string) => {
return ( return (
<Link className="gradient w-full h-max rounded-md border-2" aria-label={text} href={href}> <Link className="gradient w-full h-max rounded-md border-2" aria-label={text} href={href}>
@ -11,8 +11,8 @@ const Navbar = () => {
{text} {text}
</div> </div>
</Link> </Link>
) );
} };
return ( return (
<div className="w-max h-max px-6 py-2 mx-auto rounded-full bg-slate-900 grid place-content-center"> <div className="w-max h-max px-6 py-2 mx-auto rounded-full bg-slate-900 grid place-content-center">
<div className="flex flex-row gap-6"> <div className="flex flex-row gap-6">
@ -21,8 +21,7 @@ const Navbar = () => {
{link("Contact", "/contact")} {link("Contact", "/contact")}
</div> </div>
</div> </div>
) );
} };
export default Navbar;
export default Navbar

View File

@ -2,18 +2,18 @@ import fs from "fs";
import matter, { GrayMatterFile } from "gray-matter"; import matter, { GrayMatterFile } from "gray-matter";
import path from "path"; import path from "path";
export const baseDir = "./_content/" export const baseDir = "./_content/";
export const getContent = (slug: string[]): GrayMatterFile<string> => { export const getContent = (slug: string[]): GrayMatterFile<string> => {
let p = path.join(baseDir) let p = path.join(baseDir);
slug.forEach(s => { slug.forEach(s => {
p = path.join(p, s) p = path.join(p, s);
}) });
const file = fs.readFileSync(p, "utf8") const file = fs.readFileSync(p, "utf8");
const m = matter(file); const m = matter(file);
m.data.slug = `/c/${slug.join("/")}` m.data.slug = `/c/${slug.join("/")}`;
return m return m;
} };
const getAllPathsRecursive = (base = baseDir): string[] => { const getAllPathsRecursive = (base = baseDir): string[] => {
let results = [] as string[]; let results = [] as string[];
@ -23,16 +23,21 @@ const getAllPathsRecursive = (base = baseDir): string[] => {
const stat = fs.statSync(filePath); const stat = fs.statSync(filePath);
if (stat.isDirectory()) { if (stat.isDirectory()) {
results = results.concat(getAllPathsRecursive(filePath)); results = results.concat(getAllPathsRecursive(filePath));
} else if (path.extname(filePath) === '.md') { } else if (path.extname(filePath) === ".md") {
results.push(filePath); results.push(filePath);
} }
} }
return results; return results;
} };
export const getAllPaths = (base = baseDir): string[] => getAllPathsRecursive(base).map(p => p.substring(9)) export const getAllPaths = (base = baseDir): string[] => getAllPathsRecursive(base).map(p => p.substring(9));
export const getCases = (): GrayMatterFile<string>[] => getAllPaths(`${baseDir}cases/`).map(s => s.split("/")).map(getContent) export const getCases = (): GrayMatterFile<string>[] =>
getAllPaths(`${baseDir}cases/`)
export const getAllContent = (): GrayMatterFile<string>[] => getAllPaths().map(s => s.split("/")).map(getContent) .map(s => s.split("/"))
.map(getContent);
export const getAllContent = (): GrayMatterFile<string>[] =>
getAllPaths()
.map(s => s.split("/"))
.map(getContent);

View File

@ -1,10 +1,10 @@
import { ReactNode } from "react" import { ReactNode } from "react";
export const getText = (node: ReactNode | any) => { export const getText = (node: ReactNode | any) => {
const props = node.props const props = node.props;
if (!props) { if (!props) {
return node return node;
} }
const c = props.children || "" const c = props.children || "";
return typeof c === "string" ? c : c.map(getText).join("") return typeof c === "string" ? c : c.map(getText).join("");
} };