I'm a professional software developer currently working as a project manager and team lead. On my personal website, I share thoughts on tech, leadership, and digital life.
Welcome, and feel free to explore!
diff --git a/src/layouts/BaseLayout.astro b/src/layouts/BaseLayout.astro
index f33ca69..216287e 100644
--- a/src/layouts/BaseLayout.astro
+++ b/src/layouts/BaseLayout.astro
@@ -1,4 +1,5 @@
---
+import type { WithContext, Thing } from "schema-dts";
import Analytics from "../components/Analytics.astro";
import Head from "../components/Head.astro";
import Header from "../components/Header.astro";
@@ -8,13 +9,14 @@ type Props = {
readonly description: string;
readonly title: string;
readonly lang: string;
+ readonly schema: WithContext;
};
-const { title, description, lang } = Astro.props;
+const { title, description, lang, schema } = Astro.props;
---
-
+
diff --git a/src/pages/404.astro b/src/pages/404.astro
index 8bbd18a..4215a60 100644
--- a/src/pages/404.astro
+++ b/src/pages/404.astro
@@ -1,13 +1,19 @@
---
import Layout from "../layouts/BaseLayout.astro";
+import websiteSchema from "../utils/schemas/websiteSchema";
const title = "404 — Page Not Found | Valentin Popov";
const description = "The page you're looking for doesn't exist!";
const lang = "en";
+
+const schema = websiteSchema({
+ siteUrl: new URL("/", Astro.site).toString(),
+ title,
+});
---
-
-
+
+
404
Page not found
diff --git a/src/pages/blog/[...slug].astro b/src/pages/blog/[...slug].astro
index c625057..8d5169a 100644
--- a/src/pages/blog/[...slug].astro
+++ b/src/pages/blog/[...slug].astro
@@ -2,6 +2,7 @@
import { type CollectionEntry, getCollection } from "astro:content";
import Comments from "../../components/Comments.astro";
import Layout from "../../layouts/BaseLayout.astro";
+import blogPostSchema from "../../utils/schemas/blogPostSchema";
import dayjs from "dayjs";
type Props = CollectionEntry<"blog">;
@@ -21,10 +22,21 @@ const post = Astro.props;
const { Content, remarkPluginFrontmatter } = await post.render();
-const date = dayjs(post.data.pubDate.toString()).format("MMMM DD, YYYY");
-const title = `${post.data.title} | Valentin Popov`;
+const title = post.data.title;
const description = post.data.description;
+const author = post.data.author;
const lang = post.data.lang;
+
+const formattedData = dayjs(post.data.pubDate.toString()).format("MMMM DD, YYYY");
+const data = post.data.pubDate.toISOString();
+
+const schema = blogPostSchema({
+ siteUrl: new URL("/", Astro.site).toString(),
+ title,
+ slug: post.slug,
+ datePublished: data,
+ author,
+});
---
-
+
-
{post.data.title}
+
{title}
Posted
-
- by {post.data.author}
+
+ by {author}
• {remarkPluginFrontmatter.minutesRead}
diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro
index f800268..611d0fc 100644
--- a/src/pages/blog/index.astro
+++ b/src/pages/blog/index.astro
@@ -3,10 +3,8 @@ import type { CollectionEntry } from "astro:content";
import { getCollection } from "astro:content";
import Layout from "../../layouts/BaseLayout.astro";
import PostElement from "../../components/PostElement.astro";
-
-const title = "Valentin Popov's Blog | Software Development, Leadership & Open-Source";
-const description = "Explore Valentin Popov's blog on software development, tech leadership, and open-source experiments. Stay updated with in-depth tutorials and expert insights.";
-const lang = "en";
+import blogSchema from "../../utils/schemas/blogSchema";
+import RSSIcon from "../../components/Icons/RSS.astro";
const posts = await getCollection("blog", ({ data }) => {
return data.draft !== true;
@@ -24,14 +22,26 @@ const postsByYear = posts.reduce[]>>((acc
}, {});
const years = Object.keys(postsByYear).sort((a, b) => Number(b) - Number(a));
+
+const title = "Valentin Popov's Blog | Software Development, Leadership & Open-Source";
+const description = "Explore Valentin Popov's blog on software development, tech leadership, and open-source experiments. Stay updated with in-depth tutorials and expert insights.";
+const lang = "en";
+
+const schema = blogSchema({
+ siteUrl: new URL("/", Astro.site).toString(),
+ title,
+});
---
-
+
-
Blog posts
+
+ Blog posts
+
+
-
+
{
years.map((year) => (
diff --git a/src/pages/index.astro b/src/pages/index.astro
index f595b94..fb52e79 100644
--- a/src/pages/index.astro
+++ b/src/pages/index.astro
@@ -3,13 +3,19 @@ import Layout from "../layouts/BaseLayout.astro";
import LatestPostsSection from "../components/Sections/LatestPosts.astro";
import SocialLinksSection from "../components/Sections/SocialLinks.astro";
import WelcomeSection from "../components/Sections/Welcome.astro";
+import websiteSchema from "../utils/schemas/websiteSchema";
const title = "Valentin Popov – Software Developer & Team Lead | Tech Insights";
-const description = "Valentin Popov is an experienced project manager and team lead sharing expert insights on software development, leadership, and digital innovation.";
+const description = "Blog by Valentin Popov — software developer and team lead writing about code, side projects, digital tools, and fun experiments.";
const lang = "en";
+
+const schema = websiteSchema({
+ siteUrl: new URL("/", Astro.site).toString(),
+ title,
+});
---
-
+
diff --git a/src/utils/schemas/blogPostSchema.ts b/src/utils/schemas/blogPostSchema.ts
new file mode 100644
index 0000000..b20f248
--- /dev/null
+++ b/src/utils/schemas/blogPostSchema.ts
@@ -0,0 +1,21 @@
+import type { WithContext, BlogPosting } from "schema-dts";
+
+export type BlogPostSchemaParams = {
+ readonly siteUrl: string;
+ readonly title: string;
+ readonly slug: string;
+ readonly datePublished: string;
+ readonly author: string;
+};
+
+export default ({ siteUrl, title, slug, datePublished, author }: BlogPostSchemaParams): WithContext => ({
+ "@context": "https://schema.org",
+ "@type": "BlogPosting",
+ "url": new URL(`/blog/${slug}`, siteUrl).toString(),
+ "headline": title,
+ "datePublished": datePublished,
+ "author": {
+ "@type": "Person",
+ "name": author,
+ },
+});
diff --git a/src/utils/schemas/blogSchema.ts b/src/utils/schemas/blogSchema.ts
new file mode 100644
index 0000000..7ff84d8
--- /dev/null
+++ b/src/utils/schemas/blogSchema.ts
@@ -0,0 +1,13 @@
+import type { WithContext, Blog } from "schema-dts";
+
+export type BlogSchemaParams = {
+ readonly siteUrl: string;
+ readonly title: string;
+};
+
+export default ({ siteUrl, title }: BlogSchemaParams): WithContext => ({
+ "@context": "https://schema.org",
+ "@type": "Blog",
+ "url": new URL("/blog/", siteUrl).toString(),
+ "name": title,
+});
diff --git a/src/utils/schemas/websiteSchema.ts b/src/utils/schemas/websiteSchema.ts
new file mode 100644
index 0000000..bebb963
--- /dev/null
+++ b/src/utils/schemas/websiteSchema.ts
@@ -0,0 +1,13 @@
+import type { WithContext, WebSite } from "schema-dts";
+
+export type WebsiteSchemaParams = {
+ readonly siteUrl: string;
+ readonly title: string;
+};
+
+export default ({ siteUrl, title }: WebsiteSchemaParams): WithContext => ({
+ "@context": "https://schema.org",
+ "@type": "WebSite",
+ "url": new URL("/", siteUrl).toString(),
+ "name": title,
+});