Cleanup AI slop and simplify db interface

This commit is contained in:
2026-01-12 18:51:09 -08:00
parent 88b6d1bade
commit 6664e6e3d1
16 changed files with 712 additions and 767 deletions

View File

@@ -1,24 +1,41 @@
import React from 'react';
import postArchiveScript from '../clientJS/post-archive' with { type: "text" };
import { getPostsByYearAndMonth } from '../../db';
import { minifyJS } from '../utils';
import { db } from '../../db';
// @ts-expect-error - Importing as text, not a module
import postArchiveScript from '../clientJS/post-archive' with { type: "text" };
// Interface for archive data structure
export interface ArchiveMonth {
name: string;
count: string;
posts: Array<{
title: string;
href: string;
}>;
}
export interface ArchiveYear {
year: string;
count: string;
months: ArchiveMonth[];
}
// Read posts from database once and store in a closure
const getArchiveData = (() => {
let cachedData: ReturnType<typeof getPostsByYearAndMonth> | null = null;
return () => {
if (!cachedData) {
cachedData = getPostsByYearAndMonth();
}
return cachedData;
return cachedData;
};
})();
export function PostArchive() {
const archiveData = getArchiveData();
return (
<div className="postList sheet-background">
<h3>Posts</h3>
@@ -59,3 +76,69 @@ export function PostArchive() {
</div>
)
}
// Function to get posts organized by year and month for the archive
export function getPostsByYearAndMonth(): ArchiveYear[] {
const query = db.query(`
SELECT * FROM posts
WHERE path NOT LIKE '%.md'
ORDER BY date DESC
`);
const posts = query.all() as any[];
// Group posts by year and month
const yearMap = new Map<string, ArchiveYear>();
const monthNames = [
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
];
// Process each post
posts.forEach(post => {
const date = new Date(post.date);
const year = String(date.getFullYear());
const monthName = monthNames[date.getMonth()];
// Create clean post href from path
const href = post.path.replace(/^.*\/content\//, '/').replace(/\.md$/, '');
// Initialize year if it doesn't exist
if (!yearMap.has(year)) {
yearMap.set(year, {
year,
count: "(0)",
months: []
});
}
const yearData = yearMap.get(year)!;
// Find or create month data
let monthData = yearData.months.find(m => m.name === monthName);
if (!monthData) {
monthData = {
name: monthName,
count: "(0)",
posts: []
};
yearData.months.push(monthData);
}
// Add post to the month
monthData.posts.push({
title: post.title,
href
});
// Update counts
monthData.count = `(${monthData.posts.length})`;
yearData.count = `(${yearData.months.reduce((total, m) => total + m.posts.length, 0)})`;
});
// Convert map to array and sort
return Array.from(yearMap.values()).sort((a, b) =>
parseInt(b.year) - parseInt(a.year)
);
}

View File

@@ -1,38 +1,49 @@
import React from 'react';
import tagPickerScript from '../clientJS/tag-picker.js' with { type: "text" };
import { minifyJS } from '../utils';
import { dbConnection } from '../../db/index.js';
import { getAllTags } from '../../db/tags';
// @ts-expect-error - Importing as text, not a module
import tagPickerScript from '../clientJS/tag-picker.js' with { type: "text" };
const tags = getAllTags();
const tags = dbConnection.getAllTags().map(tag => ({
name: tag.name,
post_count: tag.post_count,
urlNormalized: tag.urlNormalized
}));
export function TagPicker({ searchParams }: { searchParams?: URLSearchParams }) {
const selectedTags = typeof searchParams === 'object' ? searchParams.getAll('tag') : [];
export function TagPicker() {
return (
<div className="tags sheet-background">
<h3>Tags</h3>
{tags.length > 0 ? (
<ul className="tag-pills">
{tags.map(tag => (
<li key={tag.name}>
<a
data-tag
href={`?tag=${tag.name.toLowerCase().replace(/\s+/g, '-')}`}
className="tag-pill"
title={`${tag.post_count} post${tag.post_count !== 1 ? 's' : ''} (click to view)`}
>
{tag.name}
</a>
</li>
))}
</ul>
) : (
<p className="no-tags-available">No tags available</p>
<ul className="tag-pills">
{tags.map(tag => {
const active = selectedTags.includes(tag.urlNormalized)
return (
< li key={tag.name} >
<a
title={`${tag.post_count} post${tag.post_count !== 1 ? 's' : ''} (click to view)`}
data-tag
className={`tag-pill ${active ? 'active' : ''}`}
href={`?tag=${tag.urlNormalized}`}
>
{tag.name}
</a>
</li>
)
})}
</ul>
{/* Show clear tags button if there are selected tags */}
{selectedTags.length > 0 && (
<div className="tag-actions">
<a href="/" className="clear-tags-btn">
Clear all filters
</a>
</div>
)}
<div className="tag-actions" style={{ display: 'none' }}>
<a href="/" className="clear-tags-btn">
Clear all filters
</a>
</div>
<script dangerouslySetInnerHTML={{ __html: minifyJS(tagPickerScript) }} />
</div>
)

View File

@@ -1,7 +1,9 @@
import React from 'react';
import themePickerScript from '../clientJS/theme-picker' with { type: "text" };
import { minifyJS } from '../utils';
// @ts-expect-error - Importing as text, not a module
import themePickerScript from '../clientJS/theme-picker' with { type: "text" };
const LIGHT_THEMES = ['latte', 'solarized-light', 'gruvbox-light'];
const DARK_THEMES = ['frappe', 'macchiato', 'mocha', 'solarized-dark', 'gruvbox-dark', 'nord', 'dracula', 'one-dark', 'tokyo-night'];
@@ -26,15 +28,15 @@ export function ThemePicker() {
<label htmlFor="theme" className="hidden">Theme</label>
<div className="theme-controls">
<div className="theme-mode-toggle">
<button
className="mode-btn active"
<button
className="mode-btn active"
data-mode="light"
id="lightModeBtn"
>
Light
</button>
<button
className="mode-btn"
<button
className="mode-btn"
data-mode="dark"
id="darkModeBtn"
>
@@ -42,8 +44,8 @@ export function ThemePicker() {
</button>
</div>
<div className="theme-dropdown-wrapper">
<button
className="theme-dropdown-trigger"
<button
className="theme-dropdown-trigger"
id="themeDropdownTrigger"
>
<span id="currentThemeDisplay">Catppuccin Latte</span>
@@ -62,4 +64,4 @@ export function ThemePicker() {
<script dangerouslySetInnerHTML={{ __html: minifyJS(themePickerScript) }} />
</div>
)
}
}