mirror of
https://github.com/prdlk/website.git
synced 2026-08-02 17:31:41 +00:00
feat(about): add personal bio and details to about page
This commit is contained in:
+53
-19
@@ -2,35 +2,69 @@
|
||||
import PageLayout from "@/layouts/Base.astro";
|
||||
|
||||
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",
|
||||
};
|
||||
|
||||
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}>
|
||||
<h1 class="title mb-12">About</h1>
|
||||
<div class="prose prose-sm prose-cactus max-w-none">
|
||||
<p>
|
||||
Hi, I’m a starter Astro. I’m particularly great for getting you started with your own blogging
|
||||
website.
|
||||
I'm Prad Nukala — an engineer and founder building decentralized identity infrastructure. As
|
||||
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>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>
|
||||
Clone or fork my <a
|
||||
class="cactus-link inline-block"
|
||||
href="https://github.com/chrismwilliams/astro-cactus"
|
||||
rel="noreferrer"
|
||||
target="_blank">repo</a
|
||||
> if you like me!
|
||||
I help shape the open standards behind user-owned identity as a working-group member at the
|
||||
W3C (DIDs, WebAuthn, WebAssembly) and the Decentralized Identity Foundation (UCAN, DWN). I've
|
||||
been shipping software since age 12 — three apps with over 1M downloads, technical writing
|
||||
read 120k+ times, and bylines in Fast Company.
|
||||
</p>
|
||||
|
||||
<h2>Education</h2>
|
||||
<p>
|
||||
<strong>Virginia Commonwealth University</strong><br />
|
||||
B.S. in Applied Mathematics · 2017–2020
|
||||
</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 & Recognition</h2>
|
||||
<ul>
|
||||
<li>Guest Lecturer, <em>Crypto Finance (15.492)</em> — MIT Sloan School of Management</li>
|
||||
</ul>
|
||||
|
||||
<h2>Standards & Organizations</h2>
|
||||
<ul>
|
||||
{
|
||||
organizations.map((org) => (
|
||||
<li>
|
||||
<a href={org.url} rel="noreferrer" target="_blank">
|
||||
{org.name}
|
||||
</a>{" "}
|
||||
— {org.role}
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</PageLayout>
|
||||
|
||||
@@ -3,8 +3,10 @@ import { render } from "astro:content";
|
||||
import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
|
||||
import { Icon } from "astro-icon/components";
|
||||
import PostPreview from "@/components/blog/PostPreview.astro";
|
||||
import TagList from "@/components/TagList.astro";
|
||||
import { getAllExperience, getContentForExperience } from "@/data/experience";
|
||||
import PageLayout from "@/layouts/Base.astro";
|
||||
import { breadcrumbList } from "@/utils/seo";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const experiences = await getAllExperience();
|
||||
@@ -20,12 +22,18 @@ type Props = InferGetStaticPropsType<typeof getStaticPaths>;
|
||||
|
||||
const { exp, content } = Astro.props as Props;
|
||||
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 meta = {
|
||||
description: exp.data.description ?? `${role ?? ""} at ${organization}`.trim(),
|
||||
keywords: tags,
|
||||
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,
|
||||
};
|
||||
---
|
||||
@@ -108,4 +116,6 @@ const meta = {
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
<TagList tags={tags} class="border-global-text/10 mt-4 border-t pt-6" />
|
||||
</PageLayout>
|
||||
|
||||
@@ -1,11 +1,27 @@
|
||||
---
|
||||
import { getAllExperience } from "@/data/experience";
|
||||
import PageLayout from "@/layouts/Base.astro";
|
||||
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
|
||||
|
||||
const experiences = await getAllExperience();
|
||||
|
||||
const meta = {
|
||||
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",
|
||||
};
|
||||
|
||||
|
||||
+16
-27
@@ -5,8 +5,10 @@ import Project from "@/components/project/Project.astro";
|
||||
import { getAllPosts } from "@/data/post";
|
||||
import { getAllSpeaking } from "@/data/speaking";
|
||||
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 { personSchema, websiteSchema } from "@/utils/seo";
|
||||
|
||||
const MAX_POSTS = 4;
|
||||
const allPosts = await getAllPosts();
|
||||
@@ -15,36 +17,26 @@ const latestPosts = (allPosts.sort(collectionDateSort) as CollectionEntry<"writi
|
||||
MAX_POSTS,
|
||||
);
|
||||
|
||||
const MAX_PROJECTS = 2;
|
||||
const MAX_PROJECTS = 3;
|
||||
const allProjects = await getCollection("projects");
|
||||
const latestProjects = allProjects.sort(projectDateSort).slice(0, MAX_PROJECTS);
|
||||
|
||||
const MAX_TALKS = 3;
|
||||
const latestTalks = (await getAllSpeaking()).sort(collectionDateSort).slice(0, MAX_TALKS);
|
||||
const talks = (await getAllSpeaking()).sort(collectionDateSort);
|
||||
|
||||
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 = {
|
||||
title: "Engineer & Founder",
|
||||
description:
|
||||
"Prad Nukala — engineer and founder building decentralized identity infrastructure. Explore my projects, experience, writing, and talks.",
|
||||
};
|
||||
|
||||
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),
|
||||
schema: [websiteSchema(), personSchema(skills)],
|
||||
};
|
||||
---
|
||||
|
||||
<PageLayout meta={meta}>
|
||||
<script type="application/ld+json" set:html={JSON.stringify(personSchema)} is:inline />
|
||||
<section>
|
||||
<h1 class="title mb-6">Prad Nukala</h1>
|
||||
<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.
|
||||
</p>
|
||||
<p>
|
||||
Find me on <a class="cactus-link" href={social.GitHub} rel="noreferrer" target="_blank">Github</a>,
|
||||
<a class="cactus-link" href={social.X} rel="noreferrer" target="_blank">X</a>,
|
||||
<a class="cactus-link" href={social.LinkedIn} rel="noreferrer" target="_blank">LinkedIn</a>, or
|
||||
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="me noreferrer" target="_blank">X</a>,
|
||||
<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>.
|
||||
</p>
|
||||
</section>
|
||||
@@ -93,13 +85,13 @@ const personSchema = {
|
||||
</a>
|
||||
</section>
|
||||
{
|
||||
latestTalks.length > 0 && (
|
||||
talks.length > 0 && (
|
||||
<section class="mt-16">
|
||||
<h2 class="title text-accent mb-6 text-xl">
|
||||
<a href="/speaking/">Speaking</a>
|
||||
</h2>
|
||||
<ul class="space-y-4" role="list">
|
||||
{latestTalks.map((talk) => (
|
||||
{talks.map((talk) => (
|
||||
<li>
|
||||
<a class="cactus-link" href={`/speaking/${talk.id}/`}>
|
||||
{talk.data.title}
|
||||
@@ -108,9 +100,6 @@ const personSchema = {
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<a class="hover:text-link mt-6 inline-block" href="/speaking/">
|
||||
See all talks <span aria-hidden="true">→</span>
|
||||
</a>
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -60,9 +60,9 @@ export async function getStaticPaths() {
|
||||
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())
|
||||
.filter((p) => !p.data.ogImage)
|
||||
.filter((p) => !p.data.ogImage && !p.data.externalUrl)
|
||||
.map((p) => ({
|
||||
params: { slug: `writing/${p.id}` },
|
||||
props: {
|
||||
|
||||
@@ -6,6 +6,7 @@ import Pagination from "@/components/Paginator.astro";
|
||||
import Project from "@/components/project/Project.astro";
|
||||
import PageLayout from "@/layouts/Base.astro";
|
||||
import { projectDateSort } from "@/utils/date";
|
||||
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
|
||||
|
||||
export const getStaticPaths = (async ({ paginate }) => {
|
||||
const MAX_PROJECTS_PER_PAGE = 10;
|
||||
@@ -21,6 +22,18 @@ const { page } = Astro.props;
|
||||
|
||||
const meta = {
|
||||
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",
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import { getCollection } from "astro:content";
|
||||
import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
|
||||
import Project from "@/components/project/Project.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
|
||||
export const getStaticPaths = (async () => {
|
||||
@@ -16,11 +17,22 @@ export const getStaticPaths = (async () => {
|
||||
export type Props = InferGetStaticPropsType<typeof getStaticPaths>;
|
||||
|
||||
const { project } = Astro.props;
|
||||
const { title, description, link, repo, tags, startDate } = project.data;
|
||||
const path = `/projects/${project.id}/`;
|
||||
|
||||
const meta = {
|
||||
description: project.data.description || `Project: ${project.data.title}`,
|
||||
description: description || `Project: ${title}`,
|
||||
keywords: tags,
|
||||
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,
|
||||
};
|
||||
---
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ export const GET = async () => {
|
||||
title: post.data.title,
|
||||
description: post.data.description,
|
||||
pubDate: post.data.publishDate,
|
||||
link: `writing/${post.id}/`,
|
||||
link: post.data.externalUrl ?? `writing/${post.id}/`,
|
||||
})),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@ import Pagination from "@/components/Paginator.astro";
|
||||
import { getAllSpeaking } from "@/data/speaking";
|
||||
import PageLayout from "@/layouts/Base.astro";
|
||||
import { collectionDateSort } from "@/utils/date";
|
||||
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
|
||||
|
||||
export const getStaticPaths = (async ({ paginate }) => {
|
||||
const talks = await getAllSpeaking();
|
||||
@@ -20,6 +21,18 @@ const { page } = Astro.props;
|
||||
|
||||
const meta = {
|
||||
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",
|
||||
};
|
||||
|
||||
|
||||
@@ -3,8 +3,10 @@ import { getCollection, render } from "astro:content";
|
||||
import type { GetStaticPaths, InferGetStaticPropsType } from "astro";
|
||||
import ExperienceTags from "@/components/ExperienceTags.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 { breadcrumbList, videoSchema } from "@/utils/seo";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const talks = await getCollection("speaking");
|
||||
@@ -18,9 +20,28 @@ type Props = InferGetStaticPropsType<typeof getStaticPaths>;
|
||||
|
||||
const { talk } = Astro.props as Props;
|
||||
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}>
|
||||
@@ -29,19 +50,11 @@ const meta = { description, ogImage: `/og-image/speaking/${talk.id}.png`, title
|
||||
<p class="text-muted mb-6">
|
||||
<FormattedDate date={publishDate} />{event && ` · ${event}`}
|
||||
</p>
|
||||
<StreamPlayer videoId={videoId} 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>
|
||||
)
|
||||
}
|
||||
<YouTube id={youtubeId} title={title} />
|
||||
<div class="prose prose-sm prose-cactus mt-8 max-w-none">
|
||||
<Content />
|
||||
</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>
|
||||
</PageLayout>
|
||||
|
||||
@@ -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>
|
||||
@@ -8,6 +8,7 @@ import { getAllExperience } from "@/data/experience";
|
||||
import { getAllPosts, groupPostsByYear } from "@/data/post";
|
||||
import PageLayout from "@/layouts/Base.astro";
|
||||
import { collectionDateSort } from "@/utils/date";
|
||||
import { breadcrumbList, collectionPageSchema } from "@/utils/seo";
|
||||
|
||||
export const getStaticPaths = (async ({ paginate }) => {
|
||||
const MAX_POSTS_PER_PAGE = 10;
|
||||
@@ -36,6 +37,18 @@ const { page, experiences, pinnedPosts } = Astro.props;
|
||||
|
||||
const meta = {
|
||||
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",
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
export const getStaticPaths = (async () => {
|
||||
const blogEntries = await getAllPosts();
|
||||
return blogEntries.map((post) => ({
|
||||
params: { slug: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
// External (PESOS) articles link out to the publisher; no local detail page.
|
||||
return blogEntries
|
||||
.filter((post) => !post.data.externalUrl)
|
||||
.map((post) => ({
|
||||
params: { slug: post.id },
|
||||
props: { post },
|
||||
}));
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
type Props = InferGetStaticPropsType<typeof getStaticPaths>;
|
||||
|
||||
+11
-8
@@ -3,7 +3,7 @@ import type { SiteConfig } from "@/types";
|
||||
|
||||
export const siteConfig: SiteConfig = {
|
||||
// ! 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",
|
||||
author: "Prad Nukala",
|
||||
description: "Engineer & founder. Projects, experience, writing and talks.",
|
||||
@@ -33,25 +33,28 @@ export const socialLinks: {
|
||||
isWebmention?: boolean;
|
||||
}[] = [
|
||||
{ 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: "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" },
|
||||
];
|
||||
|
||||
// Used to generate links in both the Header & Footer.
|
||||
export const menuLinks: { path: string; title: string }[] = [
|
||||
{
|
||||
path: "/",
|
||||
title: "Home",
|
||||
path: "/experience/",
|
||||
title: "Experience",
|
||||
},
|
||||
{
|
||||
path: "/projects/",
|
||||
title: "Projects",
|
||||
},
|
||||
{
|
||||
path: "/experience/",
|
||||
title: "Experience",
|
||||
},
|
||||
{
|
||||
path: "/writing/",
|
||||
title: "Writing",
|
||||
|
||||
@@ -20,7 +20,10 @@ export interface PaginationLink {
|
||||
export interface SiteMeta {
|
||||
articleDate?: string | undefined;
|
||||
description?: string;
|
||||
keywords?: string[];
|
||||
ogImage?: string | undefined;
|
||||
/** One or more schema.org JSON-LD objects rendered into <head>. */
|
||||
schema?: Record<string, unknown> | Record<string, unknown>[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user