all in one

This commit is contained in:
Ivan Dimitrov 2023-11-11 19:54:06 +02:00
parent 31a126572b
commit 884b72a257
12 changed files with 126 additions and 122 deletions

View File

@ -3,6 +3,7 @@ title: Multi-tenant knowledge base website based on Google APIs
goal: Create a modern multi-tenant web app that lets users use their Google Drive as a knowledge base goal: Create a modern multi-tenant web app that lets users use their Google Drive as a knowledge base
role: Design and implement the web app role: Design and implement the web app
date: Jul 29, 2023 - Nov 5, 2023 date: Jul 29, 2023 - Nov 5, 2023
z: 1
--- ---
<details> <details>

View File

@ -0,0 +1,8 @@
---
title: Wells Fargo Open Banking APIs integration
goal:
role:
date: Feb, 2021 - Aug, 2021
z: 3
draft: true
---

28
new.ts Normal file
View File

@ -0,0 +1,28 @@
import { baseDir, getAllContent } from "@/app/lib/content";
import fs from "fs"
const args = process.argv.slice(2)
const path = args[0]
if (!path) {
throw new Error("Path is needed!")
}
const slug = path.split("/");
const t = slug[slug.length - 1]
const nextZ = Math.max.apply(Math, getAllContent().map(c => Number(c.data.z))) + 1
const meta = (title: string = t, goal: string = "", role: string = "", date: string = "", z: number = nextZ) => `---
title: ${title}
goal: ${goal}
role: ${role}
date: ${date}
z: ${z}
draft: true
---
`
fs.writeFileSync(`${baseDir}${path}.md`, meta(), {flag: "w+"})

View File

@ -6,7 +6,8 @@
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start",
"lint": "next lint" "lint": "next lint",
"new": "bun new.ts"
}, },
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/fontawesome-svg-core": "^6.4.2",

View File

@ -23,56 +23,47 @@ export default function Content({ params }: Props) {
const imgSize = 1024; const imgSize = 1024;
const { data, content } = getContent(params.slug); const { data, content } = getContent(params.slug);
const title = () => { const title = () =>
return ( <span className="text-3xl">
<span className="text-3xl"> {data.title}
{data.title} </span>
</span> const goal = () =>
) data.goal ?
}
const goal = () => {
const g = data.goal
return g ?
( (
<div> <div>
<h2>The goal</h2> <h2>The goal</h2>
{g} {data.goal}
</div> </div>
) : ) :
"" ""
} const role = () =>
const role = () => { data.role ?
const r = data.role
return r ?
( (
<div> <div>
<h2>My role</h2> <h2>My role</h2>
{r} {data.role}
</div> </div>
) : ) :
"" ""
}
const ctnt = () => { const ctnt = () =>
return ( <Markdown
<Markdown className={styles.md}
className={styles.md} remarkPlugins={[remarkGfm, remarkFrontmatter]}
remarkPlugins={[remarkGfm, remarkFrontmatter]} rehypePlugins={[rehypeRaw, rehypeHighlight]}
rehypePlugins={[rehypeRaw, rehypeHighlight]} components={{
components={{ img({ height, width, src, alt }) {
img({ height, width, src, alt }) { return (
return ( <span className="w-full h-max p-20">
<span className="w-full h-max p-20"> <Image className="w-full h-full" alt={alt!} height={Number(height) || imgSize} width={Number(width) || imgSize} src={`${data.slug}${src}`}></Image>
<Image className="w-full h-full" alt={alt!} height={Number(height) || imgSize} width={Number(width) || imgSize} src={`${data.slug}${src}`}></Image> </span>
</span> )
) }
} }}
}} >
> {content}
{content} </Markdown>
</Markdown>
)
}
return ( return (
<div className="w-full h-full p-20 overflow-x-hidden overflow-scroll"> <div className="w-full h-full p-20 overflow-x-hidden overflow-scroll">
<div className="flex flex-col gap-4 text-center"> <div className="flex flex-col gap-4 text-center">

View File

@ -1,7 +1,5 @@
import Cases from "$components/cases"; import Cases from "$components/cases";
export default function CasesPage() { const CasesPage = () => <Cases />
return (
<Cases /> export default CasesPage
)
}

View File

@ -2,24 +2,16 @@ import { GrayMatterFile } from "gray-matter";
import Link from "next/link"; import Link from "next/link";
import { getCases } from "../lib/content"; import { getCases } from "../lib/content";
export default function Cases() { const cases: GrayMatterFile<string>[] = getCases()
const cases: GrayMatterFile<string>[] = getCases() const Cases = () =>
return ( <div className="p-20 w-3/4 mx-auto flex flex-col gap-4">
<div className="p-20 w-3/4 mx-auto"> {cases.filter(c => !c.data.draft).sort(c => c.data.z).map((c) => c.data).map((d) =>
{cases.map((c) => { <div key={d.slug} className="w-full h-max flex justify-center">
const d = c.data; <Link className="btn flex flex-col w-full text-center" href={d.slug}>
const date = d.date.split("-") <span className="text-lg px-6">{d.title}</span>
const from = date[0]?.trim() <span>{d.date}</span>
const to = date[1]?.trim() </Link>
return ( </div>
<div key={d.slug} className="w-full h-max flex justify-center"> )}
<Link className="btn flex flex-col w-full text-center" href={d.slug}> </div>
<span className="text-lg px-6">{d.title}</span> export default Cases;
{from} {to ? `- ${to}` : ""}
</Link>
</div>
)
})}
</div>
)
}

View File

@ -2,18 +2,16 @@ import { faGithub, faGitlab } from "@fortawesome/free-brands-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import Link from "next/link"; import Link from "next/link";
export default function Links() { const Links = () =>
<div className="grid w-full h-full place-content-center">
return ( <div className={"grid grid-cols-2 gap-4 place-content-center"}>
<div className="grid w-full h-full place-content-center"> <Link aria-label="GitHub" href={process.env.NEXT_PUBLIC_GITHUB_URL!} target="_blank">
<div className={"grid grid-cols-2 gap-4 place-content-center"}> <FontAwesomeIcon icon={faGithub} />
<Link aria-label="GitHub" href={process.env.NEXT_PUBLIC_GITHUB_URL!} target="_blank"> </Link>
<FontAwesomeIcon icon={faGithub} /> <Link aria-label="GitLab" href={process.env.NEXT_PUBLIC_GITLAB_URL!} target="_blank">
</Link> <FontAwesomeIcon icon={faGitlab} />
<Link aria-label="GitLab" href={process.env.NEXT_PUBLIC_GITLAB_URL!} target="_blank"> </Link>
<FontAwesomeIcon icon={faGitlab} />
</Link>
</div>
</div> </div>
) </div>
}
export default Links

View File

@ -2,24 +2,21 @@
import Link from "next/link"; import Link from "next/link";
import { usePathname } from "next/navigation"; import { usePathname } from "next/navigation";
export default function Navbar() { const link = (text: string, href: string) => {
const path = usePathname() const path = usePathname()
const link = (text: string, href: string) => {
return (
<Link data-selected={path === href} className="btn" aria-label={text} href={href}>
{text}
</Link>
)
}
return ( return (
<div className="w-max h-max px-6 py-2 mx-auto rounded-full bg-slate-900 grid place-content-center"> <Link data-selected={path === href} className="btn" aria-label={text} href={href}>
<div className="flex flex-row gap-6"> {text}
{link("Home", "/")} </Link>
{link("Cases", "/cases")}
{link("Contact", "/contact")}
</div>
</div>
) )
} }
const Navbar = () =>
<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">
{link("Home", "/")}
{link("Cases", "/cases")}
{link("Contact", "/contact")}
</div>
</div>
export default Navbar

View File

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

View File

@ -2,7 +2,7 @@ import fs from "fs";
import matter, { GrayMatterFile } from "gray-matter"; import matter, { GrayMatterFile } from "gray-matter";
import path from "path"; import path from "path";
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)
@ -17,13 +17,10 @@ export const getContent = (slug: string[]): GrayMatterFile<string> => {
const getAllPathsRecursive = (base = baseDir): string[] => { const getAllPathsRecursive = (base = baseDir): string[] => {
let results = [] as string[]; let results = [] as string[];
const files = fs.readdirSync(base); const files = fs.readdirSync(base);
for (const file of files) { for (const file of files) {
const filePath = path.join(base, file); const filePath = path.join(base, file);
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') {
@ -33,11 +30,9 @@ const getAllPathsRecursive = (base = baseDir): string[] => {
return results; return results;
} }
export const getAllPaths = (base = baseDir): string[] => { export const getAllPaths = (base = baseDir): string[] => getAllPathsRecursive(base).map(p => p.substring(9))
return getAllPathsRecursive(base).map(p => p.substring(9))
}
export const getCases = (): GrayMatterFile<string>[] => { export const getCases = (): GrayMatterFile<string>[] => getAllPaths(`${baseDir}cases/`).map(s => s.split("/")).map(getContent)
return getAllPaths(`${baseDir}cases/`).map(s => s.split("/")).map(getContent)
} export const getAllContent = (): GrayMatterFile<string>[] => getAllPaths().map(s => s.split("/")).map(getContent)

View File

@ -1,7 +1,5 @@
import Links from "$components/links"; import Links from "$components/links";
export default function Home() { const Home = () => <Links />
return (
<Links /> export default Home;
)
}