From cd43a0978176b16330130fe2bbdb069b161d13d0 Mon Sep 17 00:00:00 2001 From: heaven Date: Sat, 22 Nov 2025 18:13:21 +0100 Subject: [PATCH] Added tag filtering and dropdown --- astro.config.ts | 4 +- src/components/widgets/PostList.astro | 295 ++++++++++++++---- src/config.ts | 14 +- src/content.config.ts | 6 +- .../posts/_relearning-programming-part1.md | 58 ++++ .../relearning-programming-introduction.md | 2 +- .../posts/{_test-blog.md => test-blog.md} | 2 +- src/styles/global.css | 2 +- src/types/config.types.ts | 10 + 9 files changed, 331 insertions(+), 62 deletions(-) create mode 100644 src/content/posts/_relearning-programming-part1.md rename src/content/posts/{_test-blog.md => test-blog.md} (81%) diff --git a/astro.config.ts b/astro.config.ts index 1764691..7f63977 100644 --- a/astro.config.ts +++ b/astro.config.ts @@ -18,8 +18,8 @@ import nodeAdapter from '@astrojs/node' export default defineConfig({ adapter: nodeAdapter({ - mode: 'standalone', - }),// Set adapter for deployment + mode: 'standalone' + }), // Set adapter for deployment site: themeConfig.site.website, image: { service: { diff --git a/src/components/widgets/PostList.astro b/src/components/widgets/PostList.astro index 3022f19..f7d9456 100644 --- a/src/components/widgets/PostList.astro +++ b/src/components/widgets/PostList.astro @@ -4,72 +4,236 @@ import type { PostListProps } from '@/types' import { themeConfig } from '@/config' const { posts } = Astro.props as PostListProps + +// Read predefined tags and fallback from config +const predefinedTags: string[] = themeConfig.tags?.predefined ?? ['General'] +const fallbackTag: string = themeConfig.tags?.default ?? themeConfig.tags?.fallback ?? 'General' + +/** + * Normalize and pick a canonical tag for a post. + * - Supports `tags`, `tag`, `topic` frontmatter shapes. + * - Accepts arrays, CSV strings, and nested/plugin-provided locations. + * - Matches case-insensitively against predefined tags; falls back to `fallbackTag`. + */ +function canonicalTag(post: any): string { + const fm = post?.data ?? {} + const candidates: string[] = [] + + const addCandidate = (v: unknown) => { + if (v == null) return + if (Array.isArray(v)) { + for (const x of v) addCandidate(x) + return + } + if (typeof v === 'string') { + for (const part of v + .split(',') + .map((s) => s.trim()) + .filter(Boolean)) { + candidates.push(part) + } + return + } + if (typeof v === 'object') { + try { + for (const val of Object.values(v as Record)) addCandidate(val) + } catch { + // ignore + } + return + } + // fallback: stringify anything else + candidates.push(String(v)) + } + + // Common frontmatter keys + addCandidate(fm.tags) + addCandidate(fm.tag) + addCandidate(fm.topic) + + // Some plugins may attach frontmatter into nested fields + addCandidate(fm.remarkPluginFrontmatter?.tags ?? fm.remarkPluginFrontmatter?.tag) + addCandidate(fm.frontmatter?.tags ?? fm.frontmatter?.tag) + + // Also accept top-level collection shapes such as post.tags + addCandidate(post?.tags) + addCandidate(post?.tag) + addCandidate(post?.topic) + + const normalized = candidates.map((s) => String(s).trim()).filter(Boolean) + if (normalized.length === 0) return fallbackTag + + // Exact case-insensitive match + for (const c of normalized) { + const match = predefinedTags.find((p) => p.toLowerCase() === c.toLowerCase()) + if (match) return match + } + + // Loose substring match (helpful for hyphenated or compound tags) + for (const c of normalized) { + const match = predefinedTags.find( + (p) => c.toLowerCase().includes(p.toLowerCase()) || p.toLowerCase().includes(c.toLowerCase()) + ) + if (match) return match + } + + // If nothing matches, return fallback + return fallbackTag +} + +// Build posts with canonical tags and compute counts +const postsWithTag = posts.map((post) => ({ ...post, canonicalTag: canonicalTag(post) })) + +const counts: Record = {} +for (const t of predefinedTags) counts[t] = 0 +// Ensure fallback counted even if not in predefined tags +if (!(fallbackTag in counts)) counts[fallbackTag] = 0 + +for (const p of postsWithTag) { + counts[p.canonicalTag] = (counts[p.canonicalTag] || 0) + 1 +} --- - -
+
+
+ + +
+ + +
+ + diff --git a/src/config.ts b/src/config.ts index f625b1b..ce677da 100644 --- a/src/config.ts +++ b/src/config.ts @@ -12,10 +12,10 @@ export const themeConfig: ThemeConfig = { // GENERAL SETTINGS //////////////////////////////////////////////////////////////////////////////////// general: { - contentWidth: '40rem', // Content area width + contentWidth: '42rem', // Content area width centeredLayout: true, // Use centered layout (false for left-aligned) themeToggle: false, // Show theme toggle button (uses system theme by default) - postListDottedDivider: true, // Show dotted divider in post list + postListDottedDivider: false, // Show dotted divider in post list footer: true, // Show footer fadeAnimation: true // Enable fade animations }, @@ -33,5 +33,15 @@ export const themeConfig: ThemeConfig = { toc: true, // Show the table of contents (when there is enough page width) imageViewer: true, // Enable image viewer copyCode: true // Enable copy button in code blocks + }, + + // TAG SETTINGS ////////////////////////////////////////////////////////////////////////////////////// + // Predefined canonical tags for the site. This list is used by components + // (e.g., PostList) to render a consistent dropdown and to compute counts. + // Add or remove tags here to control what appears in the UI. + tags: { + predefined: ['General', 'Game Dev', 'Reverse Engineering', 'Study'], + // Fallback/default tag to use when a post does not have a recognized tag + default: 'General' } } diff --git a/src/content.config.ts b/src/content.config.ts index a8be435..4413f9d 100644 --- a/src/content.config.ts +++ b/src/content.config.ts @@ -10,7 +10,11 @@ const posts = defineCollection({ title: z.string(), // Transform string to Date object pubDate: z.coerce.date(), - image: z.string().optional() + image: z.string().optional(), + // Preserve tag fields so components can read them. Support string or array formats. + tags: z.union([z.string(), z.array(z.string())]).optional(), + tag: z.union([z.string(), z.array(z.string())]).optional(), + topic: z.string().optional() }) }) diff --git a/src/content/posts/_relearning-programming-part1.md b/src/content/posts/_relearning-programming-part1.md new file mode 100644 index 0000000..39fdf5b --- /dev/null +++ b/src/content/posts/_relearning-programming-part1.md @@ -0,0 +1,58 @@ +--- +title: 'Relearning Programming - Variables and Initialization' +pubDate: '2025-11-22' +tags: 'Study' +--- + +![](./_assets/relearn-programming.png) + +# Foreword +Hey, +I suck at coding - and that's why I decided to relearn programming. My language of choice is C++. I've been working with this language for a long time now, and it just grew on me like no other language did. + + +# What Led Me Here +I've been struggling with my problem solving + the core concepts of C++ itself. Even though I am aware of the fact that it's totally common to make mistakes, I've had the overwhelming feeling of frustration and "imposter syndrome". Every piece of information was +floating around in my head with no structure. Toss in ADHD and boom. That's how you replicate the feeling. + +I tolerated it for too long. + + +# My Plan And Goals +My goals with relearning programming and C++ is to start with the bare basics and thoroughly study and apply my knowledge with a modern approach to C++. During this journey I will make sure to deep dive into every concept where my skills are lacking. I will make sure to +fully understand each assignment, each function call, each class and each line of code. + +I will make sure to create plenty of small exercises & projects. The exercises give me the freedom to experiment with certain features and +to puzzle together solutions, which then can be finally implemented into the projects. These projects can be small games, utility tools or +simply just code snippets. Old C++ code repels me, so I’m sticking to C++20 for now and moving to C++23 soon. + +Nearly everything I learn and code will be talked about in this series of blog posts. This will make sure that I summarize and explain +the material in my own words. The length of the posts might vary. Sometimes I will talk about more than one concept in one post. Some +concepts are too short to write a 500 word post about. + + +# What This Series Will Look Like +- Notes from studying C++ / programming concepts in my own words +- Small exercises to experiment +- Projects to apply what I've learned (Games, utilities, code snippets) +- Mistakes I make along the way + solutions to them +- Occasional rants, schizophrenia and dog pictures + +# Starting Point +Right now, I know a lot, but at the same time, I don't know anything. I struggle with the understanding of how everything is running +under the hood. This is a crucial point to be aware of, because each decision you take has influence on the logic and performance of +your program. Not to mention the cruciality of the architecture. + +# Closing Thoughts +I feel motivated and nervous at the same time. This will be a long, but quick journey. Beside me mentioning that I suck at programming +and that "I don't know anything", I'm pretty sure that I'll profit of my past experience and knowledge. + +I'm so hyped to show off my future projects and I'll try my best to entertain you via some text and images. It's quite hard to pull +off, if I am being honest. + +To my future me ever reading this: Do not fucking skip anything. + +--- + +*"Using no way as a way, having no limitation as limitation"
+~ Bruce Lee* diff --git a/src/content/posts/relearning-programming-introduction.md b/src/content/posts/relearning-programming-introduction.md index 4edd6eb..1e3e375 100644 --- a/src/content/posts/relearning-programming-introduction.md +++ b/src/content/posts/relearning-programming-introduction.md @@ -1,7 +1,7 @@ --- title: 'Relearning Programming - Introduction' pubDate: '2025-11-21' -tag: 'study' +tag: 'Study' --- ![](./_assets/relearn-programming.png) diff --git a/src/content/posts/_test-blog.md b/src/content/posts/test-blog.md similarity index 81% rename from src/content/posts/_test-blog.md rename to src/content/posts/test-blog.md index 831ed3c..5d65925 100644 --- a/src/content/posts/_test-blog.md +++ b/src/content/posts/test-blog.md @@ -1,5 +1,5 @@ --- -title: 'IT WORKED' +title: 'Welcome!!!' pubDate: '2025-07-18' topic: 'general' --- diff --git a/src/styles/global.css b/src/styles/global.css index 40c62eb..73c3986 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -74,7 +74,7 @@ html.light { /* Dark Mode (Explicit) */ html.dark { - --bg: #151414; + --bg: #0a0a0a; --text-primary: rgba(197, 201, 197, 1); --text-secondary: rgba(197, 201, 197, 0.4); --text-tertiary: rgba(197, 201, 197, 0.24); diff --git a/src/types/config.types.ts b/src/types/config.types.ts index 8f3d4bf..0d0dc0f 100644 --- a/src/types/config.types.ts +++ b/src/types/config.types.ts @@ -40,10 +40,20 @@ export interface PostSettings { copyCode: boolean } +// Tag settings for predefined tags +export interface TagSettings { + predefined: string[] + // optional default/fallback keys allow flexibility in config naming + default?: string + fallback?: string +} + // Theme configuration type export interface ThemeConfig { site: SiteInfo general: GeneralSettings date: DateSettings post: PostSettings + // optional tag settings + tags?: TagSettings }