feat(about): add personal bio and details to about page

This commit is contained in:
Prad Nukala
2026-06-30 14:28:50 -04:00
parent 2f40cf3bce
commit 0e45270d93
15 changed files with 200 additions and 109 deletions
+53 -19
View File
@@ -2,35 +2,69 @@
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
const meta = { const meta = {
description: "I'm a starter theme for Astro.build", description:
"About Prad Nukala — engineer and founder building decentralized identity infrastructure, W3C and DIF working-group member, and lifelong app developer.",
title: "About", title: "About",
}; };
const organizations = [
{
name: "World Wide Web Consortium (W3C)",
role: "Working Group — DIDs, WebAuthn, WASM",
url: "https://www.w3.org/",
},
{
name: "Decentralized Identity Foundation (DIF)",
role: "Working Group — UCAN, DWN",
url: "https://identity.foundation/",
},
];
--- ---
<PageLayout meta={meta}> <PageLayout meta={meta}>
<h1 class="title mb-12">About</h1> <h1 class="title mb-12">About</h1>
<div class="prose prose-sm prose-cactus max-w-none"> <div class="prose prose-sm prose-cactus max-w-none">
<p> <p>
Hi, Im a starter Astro. Im particularly great for getting you started with your own blogging I'm Prad Nukala — an engineer and founder building decentralized identity infrastructure. As
website. co-founder and CEO of <a href="https://sonr.io" rel="noreferrer" target="_blank">Sonr</a>, I'm
building a peer-to-peer identity and data network powered by decentralized identifiers (DIDs),
WebAuthn, and IPFS.
</p> </p>
<p>Here are my some of my awesome built in features:</p>
<ul class="list-inside list-disc" role="list">
<li>I'm ultra fast as I'm a static site</li>
<li>I'm fully responsive</li>
<li>I come with a light and dark mode</li>
<li>I'm easy to customise and add additional content</li>
<li>I have Tailwind CSS styling</li>
<li>Shiki code syntax highlighting</li>
<li>Satori for auto generating OG images for blog posts</li>
</ul>
<p> <p>
Clone or fork my <a I help shape the open standards behind user-owned identity as a working-group member at the
class="cactus-link inline-block" W3C (DIDs, WebAuthn, WebAssembly) and the Decentralized Identity Foundation (UCAN, DWN). I've
href="https://github.com/chrismwilliams/astro-cactus" been shipping software since age 12 — three apps with over 1M downloads, technical writing
rel="noreferrer" read 120k+ times, and bylines in Fast Company.
target="_blank">repo</a
> if you like me!
</p> </p>
<h2>Education</h2>
<p>
<strong>Virginia Commonwealth University</strong><br />
B.S. in Applied Mathematics · 20172020
</p>
<p>
Attended 5 MLH hackathons, published 3 apps in 3 years with over 1M downloads, and wrote 3
articles with over 120k reads. Coursework spanned linear algebra, number theory, topological
data analysis, and vector calculus.
</p>
<h2>Honors &amp; Recognition</h2>
<ul>
<li>Guest Lecturer, <em>Crypto Finance (15.492)</em> — MIT Sloan School of Management</li>
</ul>
<h2>Standards &amp; Organizations</h2>
<ul>
{
organizations.map((org) => (
<li>
<a href={org.url} rel="noreferrer" target="_blank">
{org.name}
</a>{" "}
— {org.role}
</li>
))
}
</ul>
</div> </div>
</PageLayout> </PageLayout>
+11 -1
View File
@@ -3,8 +3,10 @@ import { render } from "astro:content";
import type { GetStaticPaths, InferGetStaticPropsType } from "astro"; import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
import { Icon } from "astro-icon/components"; import { Icon } from "astro-icon/components";
import PostPreview from "@/components/blog/PostPreview.astro"; import PostPreview from "@/components/blog/PostPreview.astro";
import TagList from "@/components/TagList.astro";
import { getAllExperience, getContentForExperience } from "@/data/experience"; import { getAllExperience, getContentForExperience } from "@/data/experience";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { breadcrumbList } from "@/utils/seo";
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const experiences = await getAllExperience(); const experiences = await getAllExperience();
@@ -20,12 +22,18 @@ type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const { exp, content } = Astro.props as Props; const { exp, content } = Astro.props as Props;
const { Content } = await render(exp); const { Content } = await render(exp);
const { startDate, endDate, organization, role, location, url } = exp.data; const { startDate, endDate, organization, role, location, url, tags } = exp.data;
const range = `${startDate.getFullYear()} ${endDate ? endDate.getFullYear() : "Present"}`; const range = `${startDate.getFullYear()} ${endDate ? endDate.getFullYear() : "Present"}`;
const meta = { const meta = {
description: exp.data.description ?? `${role ?? ""} at ${organization}`.trim(), description: exp.data.description ?? `${role ?? ""} at ${organization}`.trim(),
keywords: tags,
ogImage: `/og-image/experience/${exp.id}.png`, ogImage: `/og-image/experience/${exp.id}.png`,
schema: breadcrumbList([
{ name: "Home", path: "/" },
{ name: "Experience", path: "/experience/" },
{ name: exp.data.title, path: `/experience/${exp.id}/` },
]),
title: exp.data.title, title: exp.data.title,
}; };
--- ---
@@ -108,4 +116,6 @@ const meta = {
</section> </section>
) )
} }
<TagList tags={tags} class="border-global-text/10 mt-4 border-t pt-6" />
</PageLayout> </PageLayout>
+16
View File
@@ -1,11 +1,27 @@
--- ---
import { getAllExperience } from "@/data/experience"; import { getAllExperience } from "@/data/experience";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
const experiences = await getAllExperience(); const experiences = await getAllExperience();
const meta = { const meta = {
description: "Roles and organizations I've worked with", description: "Roles and organizations I've worked with",
schema: [
breadcrumbList([
{ name: "Home", path: "/" },
{ name: "Experience", path: "/experience/" },
]),
collectionPageSchema({
name: "Experience",
description: "Roles and organizations I've worked with",
path: "/experience/",
items: experiences.map((e) => ({
name: e.data.role ? `${e.data.role}, ${e.data.organization}` : e.data.organization,
path: `/experience/${e.id}/`,
})),
}),
],
title: "Experience", title: "Experience",
}; };
+16 -27
View File
@@ -5,8 +5,10 @@ import Project from "@/components/project/Project.astro";
import { getAllPosts } from "@/data/post"; import { getAllPosts } from "@/data/post";
import { getAllSpeaking } from "@/data/speaking"; import { getAllSpeaking } from "@/data/speaking";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { siteConfig, socialLinks } from "@/site.config"; import { socialLinks } from "@/site.config";
import { getTagIndex, getTaggedCollections } from "@/data/tags";
import { collectionDateSort, projectDateSort } from "@/utils/date"; import { collectionDateSort, projectDateSort } from "@/utils/date";
import { personSchema, websiteSchema } from "@/utils/seo";
const MAX_POSTS = 4; const MAX_POSTS = 4;
const allPosts = await getAllPosts(); const allPosts = await getAllPosts();
@@ -15,36 +17,26 @@ const latestPosts = (allPosts.sort(collectionDateSort) as CollectionEntry<"writi
MAX_POSTS, MAX_POSTS,
); );
const MAX_PROJECTS = 2; const MAX_PROJECTS = 3;
const allProjects = await getCollection("projects"); const allProjects = await getCollection("projects");
const latestProjects = allProjects.sort(projectDateSort).slice(0, MAX_PROJECTS); const latestProjects = allProjects.sort(projectDateSort).slice(0, MAX_PROJECTS);
const MAX_TALKS = 3; const talks = (await getAllSpeaking()).sort(collectionDateSort);
const latestTalks = (await getAllSpeaking()).sort(collectionDateSort).slice(0, MAX_TALKS);
const social = Object.fromEntries(socialLinks.map((s) => [s.friendlyName, s.link]));
// Skills (from all tagged content) feed the Person `knowsAbout` signal.
const skills = [...getTagIndex(await getTaggedCollections()).values()].map((t) => t.label);
const meta = { const meta = {
title: "Engineer & Founder", title: "Engineer & Founder",
description: description:
"Prad Nukala — engineer and founder building decentralized identity infrastructure. Explore my projects, experience, writing, and talks.", "Prad Nukala — engineer and founder building decentralized identity infrastructure. Explore my projects, experience, writing, and talks.",
}; schema: [websiteSchema(), personSchema(skills)],
const social = Object.fromEntries(socialLinks.map((s) => [s.friendlyName, s.link]));
// Person structured data for richer search results.
const personSchema = {
"@context": "https://schema.org",
"@type": "Person",
name: siteConfig.author,
url: siteConfig.url,
jobTitle: "Engineer & Founder",
description: meta.description,
image: new URL("/avatar.png", siteConfig.url).href,
sameAs: socialLinks.filter((s) => !s.link.startsWith("mailto:")).map((s) => s.link),
}; };
--- ---
<PageLayout meta={meta}> <PageLayout meta={meta}>
<script type="application/ld+json" set:html={JSON.stringify(personSchema)} is:inline />
<section> <section>
<h1 class="title mb-6">Prad Nukala</h1> <h1 class="title mb-6">Prad Nukala</h1>
<p class="mb-4"> <p class="mb-4">
@@ -52,9 +44,9 @@ const personSchema = {
Here you'll find what I've built, where I've worked, what I write, and the talks I've given. Here you'll find what I've built, where I've worked, what I write, and the talks I've given.
</p> </p>
<p> <p>
Find me on <a class="cactus-link" href={social.GitHub} rel="noreferrer" target="_blank">Github</a>, Find me on <a class="cactus-link" href={social.GitHub} rel="me noreferrer" target="_blank">Github</a>,
<a class="cactus-link" href={social.X} rel="noreferrer" target="_blank">X</a>, <a class="cactus-link" href={social.X} rel="me noreferrer" target="_blank">X</a>,
<a class="cactus-link" href={social.LinkedIn} rel="noreferrer" target="_blank">LinkedIn</a>, or <a class="cactus-link" href={social.LinkedIn} rel="me noreferrer" target="_blank">LinkedIn</a>, or
<a class="cactus-link" href={social.Email}>contact me directly</a>. <a class="cactus-link" href={social.Email}>contact me directly</a>.
</p> </p>
</section> </section>
@@ -93,13 +85,13 @@ const personSchema = {
</a> </a>
</section> </section>
{ {
latestTalks.length > 0 && ( talks.length > 0 && (
<section class="mt-16"> <section class="mt-16">
<h2 class="title text-accent mb-6 text-xl"> <h2 class="title text-accent mb-6 text-xl">
<a href="/speaking/">Speaking</a> <a href="/speaking/">Speaking</a>
</h2> </h2>
<ul class="space-y-4" role="list"> <ul class="space-y-4" role="list">
{latestTalks.map((talk) => ( {talks.map((talk) => (
<li> <li>
<a class="cactus-link" href={`/speaking/${talk.id}/`}> <a class="cactus-link" href={`/speaking/${talk.id}/`}>
{talk.data.title} {talk.data.title}
@@ -108,9 +100,6 @@ const personSchema = {
</li> </li>
))} ))}
</ul> </ul>
<a class="hover:text-link mt-6 inline-block" href="/speaking/">
See all talks <span aria-hidden="true">→</span>
</a>
</section> </section>
) )
} }
+2 -2
View File
@@ -60,9 +60,9 @@ export async function getStaticPaths() {
getAllSpeaking(), getAllSpeaking(),
]); ]);
// Writing keeps its existing behaviour: skip posts with a custom ogImage. // Writing: skip posts with a custom ogImage, and external (link-out) articles.
const writing = (await getAllPosts()) const writing = (await getAllPosts())
.filter((p) => !p.data.ogImage) .filter((p) => !p.data.ogImage && !p.data.externalUrl)
.map((p) => ({ .map((p) => ({
params: { slug: `writing/${p.id}` }, params: { slug: `writing/${p.id}` },
props: { props: {
+13
View File
@@ -6,6 +6,7 @@ import Pagination from "@/components/Paginator.astro";
import Project from "@/components/project/Project.astro"; import Project from "@/components/project/Project.astro";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { projectDateSort } from "@/utils/date"; import { projectDateSort } from "@/utils/date";
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
export const getStaticPaths = (async ({ paginate }) => { export const getStaticPaths = (async ({ paginate }) => {
const MAX_PROJECTS_PER_PAGE = 10; const MAX_PROJECTS_PER_PAGE = 10;
@@ -21,6 +22,18 @@ const { page } = Astro.props;
const meta = { const meta = {
description: "Things I've built", description: "Things I've built",
schema: [
breadcrumbList([
{ name: "Home", path: "/" },
{ name: "Projects", path: "/projects/" },
]),
collectionPageSchema({
name: "Projects",
description: "Things I've built",
path: page.url.current,
items: page.data.map((p) => ({ name: p.data.title, path: `/projects/${p.id}/` })),
}),
],
title: "Projects", title: "Projects",
}; };
+14 -2
View File
@@ -3,6 +3,7 @@ import { getCollection } from "astro:content";
import type { GetStaticPaths, InferGetStaticPropsType } from "astro"; import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
import Project from "@/components/project/Project.astro"; import Project from "@/components/project/Project.astro";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { breadcrumbList, creativeWorkSchema } from "@/utils/seo";
// if you're using an adaptor in SSR mode, getStaticPaths wont work -> https://docs.astro.build/en/guides/routing/#modifying-the-slug-example-for-ssr // if you're using an adaptor in SSR mode, getStaticPaths wont work -> https://docs.astro.build/en/guides/routing/#modifying-the-slug-example-for-ssr
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
@@ -16,11 +17,22 @@ export const getStaticPaths = (async () => {
export type Props = InferGetStaticPropsType<typeof getStaticPaths>; export type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const { project } = Astro.props; const { project } = Astro.props;
const { title, description, link, repo, tags, startDate } = project.data;
const path = `/projects/${project.id}/`;
const meta = { const meta = {
description: project.data.description || `Project: ${project.data.title}`, description: description || `Project: ${title}`,
keywords: tags,
ogImage: `/og-image/projects/${project.id}.png`, ogImage: `/og-image/projects/${project.id}.png`,
title: project.data.title, schema: [
breadcrumbList([
{ name: "Home", path: "/" },
{ name: "Projects", path: "/projects/" },
{ name: title, path },
]),
creativeWorkSchema({ title, description, path, url: link, repo, dateCreated: startDate, keywords: tags }),
],
title,
}; };
--- ---
+1 -1
View File
@@ -13,7 +13,7 @@ export const GET = async () => {
title: post.data.title, title: post.data.title,
description: post.data.description, description: post.data.description,
pubDate: post.data.publishDate, pubDate: post.data.publishDate,
link: `writing/${post.id}/`, link: post.data.externalUrl ?? `writing/${post.id}/`,
})), })),
}); });
}; };
+13
View File
@@ -6,6 +6,7 @@ import Pagination from "@/components/Paginator.astro";
import { getAllSpeaking } from "@/data/speaking"; import { getAllSpeaking } from "@/data/speaking";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { collectionDateSort } from "@/utils/date"; import { collectionDateSort } from "@/utils/date";
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
export const getStaticPaths = (async ({ paginate }) => { export const getStaticPaths = (async ({ paginate }) => {
const talks = await getAllSpeaking(); const talks = await getAllSpeaking();
@@ -20,6 +21,18 @@ const { page } = Astro.props;
const meta = { const meta = {
description: "Talks and presentations I've given", description: "Talks and presentations I've given",
schema: [
breadcrumbList([
{ name: "Home", path: "/" },
{ name: "Speaking", path: "/speaking/" },
]),
collectionPageSchema({
name: "Speaking",
description: "Talks and presentations I've given",
path: page.url.current,
items: page.data.map((t) => ({ name: t.data.title, path: `/speaking/${t.id}/` })),
}),
],
title: "Speaking", title: "Speaking",
}; };
+27 -14
View File
@@ -3,8 +3,10 @@ import { getCollection, render } from "astro:content";
import type { GetStaticPaths, InferGetStaticPropsType } from "astro"; import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
import ExperienceTags from "@/components/ExperienceTags.astro"; import ExperienceTags from "@/components/ExperienceTags.astro";
import FormattedDate from "@/components/FormattedDate.astro"; import FormattedDate from "@/components/FormattedDate.astro";
import StreamPlayer from "@/components/StreamPlayer.astro"; import TagList from "@/components/TagList.astro";
import YouTube from "@/components/YouTube.astro";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { breadcrumbList, videoSchema } from "@/utils/seo";
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const talks = await getCollection("speaking"); const talks = await getCollection("speaking");
@@ -18,9 +20,28 @@ type Props = InferGetStaticPropsType<typeof getStaticPaths>;
const { talk } = Astro.props as Props; const { talk } = Astro.props as Props;
const { Content } = await render(talk); const { Content } = await render(talk);
const { title, description, videoId, originalSource, event, publishDate, experiences } = talk.data; const { title, description, youtubeId, event, publishDate, experiences, tags } = talk.data;
const meta = { description, ogImage: `/og-image/speaking/${talk.id}.png`, title }; const path = `/speaking/${talk.id}/`;
const ogImage = `/og-image/speaking/${talk.id}.png`;
const schema = [
breadcrumbList([
{ name: "Home", path: "/" },
{ name: "Speaking", path: "/speaking/" },
{ name: title, path },
]),
videoSchema({
title,
description,
path,
thumbnail: `https://i.ytimg.com/vi/${youtubeId}/hqdefault.jpg`,
uploadDate: publishDate,
embedUrl: `https://www.youtube.com/embed/${youtubeId}`,
contentUrl: `https://www.youtube.com/watch?v=${youtubeId}`,
}),
];
const meta = { description, keywords: tags, ogImage, schema, title };
--- ---
<PageLayout meta={meta}> <PageLayout meta={meta}>
@@ -29,19 +50,11 @@ const meta = { description, ogImage: `/og-image/speaking/${talk.id}.png`, title
<p class="text-muted mb-6"> <p class="text-muted mb-6">
<FormattedDate date={publishDate} />{event && ` · ${event}`} <FormattedDate date={publishDate} />{event && ` · ${event}`}
</p> </p>
<StreamPlayer videoId={videoId} title={title} /> <YouTube id={youtubeId} title={title} />
{
originalSource && (
<p class="text-muted mt-3 text-sm">
<a class="cactus-link" href={originalSource} rel="noopener noreferrer" target="_blank">
Watch original on YouTube →
</a>
</p>
)
}
<div class="prose prose-sm prose-cactus mt-8 max-w-none"> <div class="prose prose-sm prose-cactus mt-8 max-w-none">
<Content /> <Content />
</div> </div>
{experiences.length > 0 && <div class="mt-8"><ExperienceTags experiences={experiences} /></div>} <TagList tags={tags} class="mt-8" />
{experiences.length > 0 && <div class="mt-6"><ExperienceTags experiences={experiences} /></div>}
</article> </article>
</PageLayout> </PageLayout>
-31
View File
@@ -1,31 +0,0 @@
---
import { getTagIndex, getTaggedCollections } from "@/data/tags";
import PageLayout from "@/layouts/Base.astro";
const cols = await getTaggedCollections();
const tags = [...getTagIndex(cols).entries()]
.map(([slug, { label, count }]) => ({ slug, label, count }))
.sort((a, b) => b.count - a.count || a.label.localeCompare(b.label));
const meta = {
description: "Browse projects, experience, writing, and talks by skill and topic.",
title: "Tags",
};
---
<PageLayout meta={meta}>
<h1 class="title mb-6">Tags</h1>
<p class="text-muted mb-8">Skills and topics spanning my projects, experience, writing, and talks.</p>
<ul class="flex flex-wrap gap-x-4 gap-y-2">
{
tags.map(({ slug, label, count }) => (
<li>
<a class="cactus-link before:content-['#']" href={`/tags/${slug}/`}>
{label}
</a>
<span class="text-muted text-sm"> {count}</span>
</li>
))
}
</ul>
</PageLayout>
+13
View File
@@ -8,6 +8,7 @@ import { getAllExperience } from "@/data/experience";
import { getAllPosts, groupPostsByYear } from "@/data/post"; import { getAllPosts, groupPostsByYear } from "@/data/post";
import PageLayout from "@/layouts/Base.astro"; import PageLayout from "@/layouts/Base.astro";
import { collectionDateSort } from "@/utils/date"; import { collectionDateSort } from "@/utils/date";
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
export const getStaticPaths = (async ({ paginate }) => { export const getStaticPaths = (async ({ paginate }) => {
const MAX_POSTS_PER_PAGE = 10; const MAX_POSTS_PER_PAGE = 10;
@@ -36,6 +37,18 @@ const { page, experiences, pinnedPosts } = Astro.props;
const meta = { const meta = {
description: "Essays, notes and articles I've written", description: "Essays, notes and articles I've written",
schema: [
breadcrumbList([
{ name: "Home", path: "/" },
{ name: "Writing", path: "/writing/" },
]),
collectionPageSchema({
name: "Writing",
description: "Essays, notes and articles I've written",
path: page.url.current,
items: page.data.map((p) => ({ name: p.data.title, path: `/writing/${p.id}/` })),
}),
],
title: "Writing", title: "Writing",
}; };
+7 -4
View File
@@ -7,10 +7,13 @@ import PostLayout from "@/layouts/BlogPost.astro";
// if you're using an adaptor in SSR mode, getStaticPaths wont work -> https://docs.astro.build/en/guides/routing/#modifying-the-slug-example-for-ssr // if you're using an adaptor in SSR mode, getStaticPaths wont work -> https://docs.astro.build/en/guides/routing/#modifying-the-slug-example-for-ssr
export const getStaticPaths = (async () => { export const getStaticPaths = (async () => {
const blogEntries = await getAllPosts(); const blogEntries = await getAllPosts();
return blogEntries.map((post) => ({ // External (PESOS) articles link out to the publisher; no local detail page.
params: { slug: post.id }, return blogEntries
props: { post }, .filter((post) => !post.data.externalUrl)
})); .map((post) => ({
params: { slug: post.id },
props: { post },
}));
}) satisfies GetStaticPaths; }) satisfies GetStaticPaths;
type Props = InferGetStaticPropsType<typeof getStaticPaths>; type Props = InferGetStaticPropsType<typeof getStaticPaths>;
+11 -8
View File
@@ -3,7 +3,7 @@ import type { SiteConfig } from "@/types";
export const siteConfig: SiteConfig = { export const siteConfig: SiteConfig = {
// ! Please remember to replace the following site property with your own domain, used in astro.config.ts // ! Please remember to replace the following site property with your own domain, used in astro.config.ts
url: "https://prad.nu/", url: "https://www.pradnukala.com/",
title: "Prad Nukala", title: "Prad Nukala",
author: "Prad Nukala", author: "Prad Nukala",
description: "Engineer & founder. Projects, experience, writing and talks.", description: "Engineer & founder. Projects, experience, writing and talks.",
@@ -33,25 +33,28 @@ export const socialLinks: {
isWebmention?: boolean; isWebmention?: boolean;
}[] = [ }[] = [
{ friendlyName: "GitHub", link: "https://github.com/prdlk", name: "mdi:github" }, { friendlyName: "GitHub", link: "https://github.com/prdlk", name: "mdi:github" },
{ friendlyName: "X", link: "https://x.com/basedprad", name: "mdi:twitter" }, { friendlyName: "X", link: "https://x.com/basedprad", name: "x" },
{ friendlyName: "LinkedIn", link: "https://linkedin.com/in/pradn", name: "mdi:linkedin" }, { friendlyName: "LinkedIn", link: "https://linkedin.com/in/pradn", name: "mdi:linkedin" },
{ friendlyName: "Medium", link: "https://medium.com/@prnk28", name: "mdi:medium" },
{
friendlyName: "Discord",
link: "https://discord.com/users/788422222930640936",
name: "mdi:discord",
},
{ friendlyName: "Telegram", link: "https://t.me/prdnk", name: "mdi:telegram" },
{ friendlyName: "Email", link: "mailto:prnk28@gmail.com", name: "mdi:email-outline" }, { friendlyName: "Email", link: "mailto:prnk28@gmail.com", name: "mdi:email-outline" },
]; ];
// Used to generate links in both the Header & Footer. // Used to generate links in both the Header & Footer.
export const menuLinks: { path: string; title: string }[] = [ export const menuLinks: { path: string; title: string }[] = [
{ {
path: "/", path: "/experience/",
title: "Home", title: "Experience",
}, },
{ {
path: "/projects/", path: "/projects/",
title: "Projects", title: "Projects",
}, },
{
path: "/experience/",
title: "Experience",
},
{ {
path: "/writing/", path: "/writing/",
title: "Writing", title: "Writing",
+3
View File
@@ -20,7 +20,10 @@ export interface PaginationLink {
export interface SiteMeta { export interface SiteMeta {
articleDate?: string | undefined; articleDate?: string | undefined;
description?: string; description?: string;
keywords?: string[];
ogImage?: string | undefined; ogImage?: string | undefined;
/** One or more schema.org JSON-LD objects rendered into <head>. */
schema?: Record<string, unknown> | Record<string, unknown>[];
title: string; title: string;
} }