diff --git a/src/package.json b/src/package.json
index 9d16e8b..ba22f1d 100644
--- a/src/package.json
+++ b/src/package.json
@@ -22,6 +22,7 @@
"@astrojs/sitemap": "^3.2.1",
"@react-hook/intersection-observer": "^3.1.2",
"lucide-react": "^0.468.0",
+ "marked": "^15.0.6",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-responsive": "^10.0.0",
diff --git a/src/pnpm-lock.yaml b/src/pnpm-lock.yaml
index 12976b4..58ac0bb 100644
--- a/src/pnpm-lock.yaml
+++ b/src/pnpm-lock.yaml
@@ -23,6 +23,9 @@ importers:
lucide-react:
specifier: ^0.468.0
version: 0.468.0(react@18.3.1)
+ marked:
+ specifier: ^15.0.6
+ version: 15.0.6
react:
specifier: ^18.3.1
version: 18.3.1
@@ -1353,6 +1356,11 @@ packages:
markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
+ marked@15.0.6:
+ resolution: {integrity: sha512-Y07CUOE+HQXbVDCGl3LXggqJDbXDP2pArc2C1N1RRMN0ONiShoSsIInMd5Gsxupe7fKLpgimTV+HOJ9r7bA+pg==}
+ engines: {node: '>= 18'}
+ hasBin: true
+
matchmediaquery@0.4.2:
resolution: {integrity: sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA==}
@@ -3717,6 +3725,8 @@ snapshots:
markdown-table@3.0.4: {}
+ marked@15.0.6: {}
+
matchmediaquery@0.4.2:
dependencies:
css-mediaquery: 0.1.2
diff --git a/src/src/components/404/glitched-text.tsx b/src/src/components/404/glitched-text.tsx
new file mode 100644
index 0000000..bd0ef07
--- /dev/null
+++ b/src/src/components/404/glitched-text.tsx
@@ -0,0 +1,56 @@
+import React, { useState, useEffect } from "react";
+
+const GlitchText = () => {
+ const originalText = 'Error 404';
+ const [characters, setCharacters] = useState(
+ originalText.split("").map(char => ({ char, isGlitched: false }))
+ );
+ const glitchChars = "!<>-_\\/[]{}—=+*^?#________";
+
+ useEffect(() => {
+ const glitchInterval = setInterval(() => {
+ if (Math.random() < 0.2) { // 20% chance to trigger glitch
+ setCharacters(prev => {
+ return originalText.split('').map((originalChar, index) => {
+ if (Math.random() < 0.3) { // 30% chance to glitch each character
+ return {
+ char: glitchChars[Math.floor(Math.random() * glitchChars.length)],
+ isGlitched: true
+ };
+ }
+ return { char: originalChar, isGlitched: false };
+ });
+ });
+
+ // Reset after short delay
+ setTimeout(() => {
+ setCharacters(originalText.split('').map(char => ({
+ char,
+ isGlitched: false
+ })));
+ }, 100);
+ }
+ }, 50);
+
+ return () => clearInterval(glitchInterval);
+ }, []);
+
+ return (
+
+
+
+ {characters.map((charObj, index) => (
+
+ {charObj.char}
+
+ ))}
+
+
+
+ );
+};
+
+export default GlitchText;
diff --git a/src/src/components/blog/header.tsx b/src/src/components/blog/header.tsx
new file mode 100644
index 0000000..4e25020
--- /dev/null
+++ b/src/src/components/blog/header.tsx
@@ -0,0 +1,38 @@
+import React from "react";
+import { RssIcon, TagIcon, TrendingUpIcon } from "lucide-react";
+
+export const BlogHeader = () => {
+ return (
+
+
+ Latest Thoughts
+ & Writings
+
+
+
+ );
+};
diff --git a/src/src/components/blog/post-list.tsx b/src/src/components/blog/post-list.tsx
index 6215fc0..c024d2b 100644
--- a/src/src/components/blog/post-list.tsx
+++ b/src/src/components/blog/post-list.tsx
@@ -27,12 +27,7 @@ const formatDate = (dateString: string) => {
export const BlogPostList = ({ posts }: BlogPostListProps) => {
return (
-
-
- Latest Thoughts
- & Writings
-
-
+
{posts.map((post) => (
-
diff --git a/src/src/pages/404.astro b/src/src/pages/404.astro
index 48a7b53..dde8857 100644
--- a/src/src/pages/404.astro
+++ b/src/src/pages/404.astro
@@ -1,16 +1,16 @@
---
import IndexLayout from "@/layouts/index.astro";
-
+import GlitchText from "@/components/404/glitched-text";
const title = "404 Not Found";
---
-
404
- Whoops! This page doesn't exist.
+
+ Whoops! This page doesn't exist :(
diff --git a/src/src/pages/blog/index.astro b/src/src/pages/blog/index.astro
index bd16b94..29d3e41 100644
--- a/src/src/pages/blog/index.astro
+++ b/src/src/pages/blog/index.astro
@@ -1,7 +1,9 @@
---
import { getCollection } from "astro:content";
import ContentLayout from "@/layouts/content.astro";
+import { BlogHeader } from "@/components/blog/header";
import { BlogPostList } from "@/components/blog/post-list";
+
const posts = (await getCollection("blog", ({ data }) => {
return data.isDraft !== true;
})).sort((a, b) => {
@@ -22,5 +24,6 @@ const posts = (await getCollection("blog", ({ data }) => {
title="Blog | Timothy Pidashev"
description="My experiences and technical insights into software development and the ever-evolving world of programming."
>
+
diff --git a/src/src/pages/rss.ts b/src/src/pages/rss.ts
index 019c2d9..2f9bdd1 100644
--- a/src/src/pages/rss.ts
+++ b/src/src/pages/rss.ts
@@ -5,16 +5,25 @@ import type { APIContext } from "astro";
export async function GET(context: APIContext) {
const blog = await getCollection("blog");
+ const sortedPosts = blog
+ .sort((a, b) => b.data.date.valueOf() - a.data.date.valueOf());
+
return rss({
title: "Timothy Pidashev",
description: "My experiences and technical insights into software development and the ever-evolving world of programming.",
site: context.site!,
- items: blog.map((post) => ({
+ items: sortedPosts.map((post) => ({
title: post.data.title,
pubDate: post.data.date,
description: post.data.description,
link: `/blog/${post.slug}/`,
+ author: post.data.author,
+ categories: post.data.tags,
+ enclosure: post.data.image ? {
+ url: new URL(`blog/${post.slug}/thumbnail.png`, context.site).toString(),
+ type: 'image/jpeg',
+ length: 0
+ } : undefined
})),
- customData: `en-us`,
});
}