all in one
This commit is contained in:
parent
31a126572b
commit
884b72a257
@ -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
|
||||
role: Design and implement the web app
|
||||
date: Jul 29, 2023 - Nov 5, 2023
|
||||
z: 1
|
||||
---
|
||||
|
||||
<details>
|
||||
|
8
_content/cases/wellsfargo.md
Normal file
8
_content/cases/wellsfargo.md
Normal 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
28
new.ts
Normal 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+"})
|
||||
|
@ -6,7 +6,8 @@
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"new": "bun new.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
||||
|
@ -23,38 +23,30 @@ export default function Content({ params }: Props) {
|
||||
const imgSize = 1024;
|
||||
const { data, content } = getContent(params.slug);
|
||||
|
||||
const title = () => {
|
||||
return (
|
||||
const title = () =>
|
||||
<span className="text-3xl">
|
||||
{data.title}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
const goal = () => {
|
||||
const g = data.goal
|
||||
return g ?
|
||||
const goal = () =>
|
||||
data.goal ?
|
||||
(
|
||||
<div>
|
||||
<h2>The goal</h2>
|
||||
{g}
|
||||
{data.goal}
|
||||
</div>
|
||||
) :
|
||||
""
|
||||
}
|
||||
const role = () => {
|
||||
const r = data.role
|
||||
return r ?
|
||||
const role = () =>
|
||||
data.role ?
|
||||
(
|
||||
<div>
|
||||
<h2>My role</h2>
|
||||
{r}
|
||||
{data.role}
|
||||
</div>
|
||||
) :
|
||||
""
|
||||
}
|
||||
|
||||
const ctnt = () => {
|
||||
return (
|
||||
const ctnt = () =>
|
||||
<Markdown
|
||||
className={styles.md}
|
||||
remarkPlugins={[remarkGfm, remarkFrontmatter]}
|
||||
@ -71,8 +63,7 @@ export default function Content({ params }: Props) {
|
||||
>
|
||||
{content}
|
||||
</Markdown>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full h-full p-20 overflow-x-hidden overflow-scroll">
|
||||
<div className="flex flex-col gap-4 text-center">
|
||||
|
@ -1,7 +1,5 @@
|
||||
import Cases from "$components/cases";
|
||||
|
||||
export default function CasesPage() {
|
||||
return (
|
||||
<Cases />
|
||||
)
|
||||
}
|
||||
const CasesPage = () => <Cases />
|
||||
|
||||
export default CasesPage
|
||||
|
@ -2,24 +2,16 @@ import { GrayMatterFile } from "gray-matter";
|
||||
import Link from "next/link";
|
||||
import { getCases } from "../lib/content";
|
||||
|
||||
export default function Cases() {
|
||||
const cases: GrayMatterFile<string>[] = getCases()
|
||||
return (
|
||||
<div className="p-20 w-3/4 mx-auto">
|
||||
{cases.map((c) => {
|
||||
const d = c.data;
|
||||
const date = d.date.split("-")
|
||||
const from = date[0]?.trim()
|
||||
const to = date[1]?.trim()
|
||||
return (
|
||||
const Cases = () =>
|
||||
<div className="p-20 w-3/4 mx-auto flex flex-col gap-4">
|
||||
{cases.filter(c => !c.data.draft).sort(c => c.data.z).map((c) => c.data).map((d) =>
|
||||
<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}>
|
||||
<span className="text-lg px-6">{d.title}</span>
|
||||
{from} {to ? `- ${to}` : ""}
|
||||
<span>{d.date}</span>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Cases;
|
||||
|
@ -2,9 +2,7 @@ import { faGithub, faGitlab } from "@fortawesome/free-brands-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function Links() {
|
||||
|
||||
return (
|
||||
const Links = () =>
|
||||
<div className="grid w-full h-full place-content-center">
|
||||
<div className={"grid grid-cols-2 gap-4 place-content-center"}>
|
||||
<Link aria-label="GitHub" href={process.env.NEXT_PUBLIC_GITHUB_URL!} target="_blank">
|
||||
@ -15,5 +13,5 @@ export default function Links() {
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Links
|
||||
|
@ -2,18 +2,15 @@
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
|
||||
export default function Navbar() {
|
||||
const path = usePathname()
|
||||
|
||||
const link = (text: string, href: string) => {
|
||||
const path = usePathname()
|
||||
return (
|
||||
<Link data-selected={path === href} className="btn" aria-label={text} href={href}>
|
||||
{text}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
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", "/")}
|
||||
@ -21,5 +18,5 @@ export default function Navbar() {
|
||||
{link("Contact", "/contact")}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Navbar
|
||||
|
@ -1,16 +1,13 @@
|
||||
import { faEnvelope } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
export default function Contact() {
|
||||
|
||||
const email = "ivan@idimitrov.dev";
|
||||
const mailto = `mailto:${email}`
|
||||
|
||||
return (
|
||||
const Contact = () =>
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
export default Contact
|
||||
|
@ -2,7 +2,7 @@ import fs from "fs";
|
||||
import matter, { GrayMatterFile } from "gray-matter";
|
||||
import path from "path";
|
||||
|
||||
const baseDir = "./_content/"
|
||||
export const baseDir = "./_content/"
|
||||
|
||||
export const getContent = (slug: string[]): GrayMatterFile<string> => {
|
||||
let p = path.join(baseDir)
|
||||
@ -17,13 +17,10 @@ export const getContent = (slug: string[]): GrayMatterFile<string> => {
|
||||
|
||||
const getAllPathsRecursive = (base = baseDir): string[] => {
|
||||
let results = [] as string[];
|
||||
|
||||
const files = fs.readdirSync(base);
|
||||
|
||||
for (const file of files) {
|
||||
const filePath = path.join(base, file);
|
||||
const stat = fs.statSync(filePath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
results = results.concat(getAllPathsRecursive(filePath));
|
||||
} else if (path.extname(filePath) === '.md') {
|
||||
@ -33,11 +30,9 @@ const getAllPathsRecursive = (base = baseDir): string[] => {
|
||||
return results;
|
||||
}
|
||||
|
||||
export const getAllPaths = (base = baseDir): string[] => {
|
||||
return 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>[] => {
|
||||
return getAllPaths(`${baseDir}cases/`).map(s => s.split("/")).map(getContent)
|
||||
}
|
||||
export const getCases = (): GrayMatterFile<string>[] => getAllPaths(`${baseDir}cases/`).map(s => s.split("/")).map(getContent)
|
||||
|
||||
export const getAllContent = (): GrayMatterFile<string>[] => getAllPaths().map(s => s.split("/")).map(getContent)
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
import Links from "$components/links";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<Links />
|
||||
)
|
||||
}
|
||||
const Home = () => <Links />
|
||||
|
||||
export default Home;
|
||||
|
Loading…
Reference in New Issue
Block a user