Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,17 @@ jobs:
- name: Run ESLint
run: pnpm run lint

- name: Audit content frontmatter
run: pnpm run audit-frontmatter

- name: Check structured-data module
run: pnpm run validate-structured-data

- name: Check Remark42 rewrite
run: pnpm run check-remark42-rewrite

- name: Build project
run: pnpm run build

- name: Validate generated feeds
run: pnpm run validate-feeds
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,22 @@ When bumping `package.json` version, run `pnpm changelog:since` (or follow the p

[6.13.2] through [6.21.0] is one ChatGPT Codex and Astra batch at full power, Max setting. Months of site work, shipped in days.

## [6.22.2] — 2026-09-10

### Changed

- Search data is emitted once per page, reducing initial HTML while keeping desktop and mobile search behavior.
- CI now checks frontmatter, structured-data exports, the Remark42 rewrite, and generated feeds around the production build.
- Writing Insights caches use content-aware hashes, so title and same-length body edits refresh analytics without discarding valid cached work.
- Optional Threads and IndexNow requests share explicit build-time deadlines.
- Article images open in a keyboard-accessible dialog, and scrolling respects reduced-motion preferences.

### Fixed

- Clearing search cannot reopen stale debounced results.
- Social-image metadata drops entries when source AVIF files are removed.
- Vite development file serving uses its strict filesystem boundary.

## [6.22.1] — 2026-09-09

### Changed
Expand Down
5 changes: 0 additions & 5 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,6 @@ export default defineConfig({
usePolling: false,
},
hmr: true,
// Optimize dev server performance
fs: {
// Limit file system access for faster startup
strict: false,
},
},
build: {
cssMinify: true,
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "notes blog",
"type": "module",
"version": "6.22.1",
"version": "6.22.2",
"repository": {
"type": "git",
"url": "https://github.com/antoniwan/notes.git"
Expand Down
Binary file added public/images/2026/empathy-sword-edges.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/notes-og-v2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/notes-og-v3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/images/notes-og-v4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 15 additions & 19 deletions scripts/generate-social-images.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,8 +251,11 @@ async function generateSocialForFile(filePath, previousEntry) {
};
}

async function writeManifest(mappings) {
const manifestPath = path.join(__dirname, '../src/data/socialImageManifest.ts');
export async function writeManifest(
mappings,
manifestPath = path.join(__dirname, '../src/data/socialImageManifest.ts'),
) {
const projectPrettierConfig = (await prettier.resolveConfig(manifestPath)) || {};

const lines = [
'// Auto-generated by scripts/generate-social-images.js. DO NOT EDIT BY HAND.',
Expand All @@ -265,8 +268,8 @@ async function writeManifest(mappings) {
];

const formatted = await prettier.format(lines.join('\n'), {
...projectPrettierConfig,
parser: 'typescript',
singleQuote: true,
});

let existing = '';
Expand Down Expand Up @@ -330,24 +333,17 @@ async function main() {

await writeFingerprintPayloadIfNeeded(nextSources, existingFingerprintsRaw);

const manifestPath = path.join(__dirname, '../src/data/socialImageManifest.ts');
let hasManifest = true;
try {
await fs.stat(manifestPath);
} catch {
hasManifest = false;
}

// Avoid rewriting manifest on no-op builds; update only when needed.
if (!hasManifest || generatedCount > 0) {
await writeManifest(mappings);
}
// writeManifest compares content before writing, so this also reconciles
// removed AVIF sources without touching the file on no-op builds.
await writeManifest(mappings);
console.log(
`✅ Social image step done: ${generatedCount} generated, ${skippedCount} reused, ${mappings.length} total.`,
);
}

main().catch((err) => {
console.error('❌ Error generating social images:', err);
process.exit(1);
});
if (process.argv[1] && path.resolve(process.argv[1]) === __filename) {
main().catch((err) => {
console.error('❌ Error generating social images:', err);
process.exit(1);
});
}
7 changes: 6 additions & 1 deletion src/components/BackToTop.astro
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,11 @@ const { class: className = '' } = Astro.props;
}

function scrollToTop() {
const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if ('scrollBehavior' in document.documentElement.style) {
window.scrollTo({
top: 0,
behavior: 'smooth',
behavior: prefersReducedMotion ? 'auto' : 'smooth',
});
} else {
window.scrollTo(0, 0);
Expand Down Expand Up @@ -109,6 +110,10 @@ const { class: className = '' } = Astro.props;
}

@media (prefers-reduced-motion: reduce) {
:global(html) {
scroll-behavior: auto !important;
}

#back-to-top {
animation: none !important;
transition: none !important;
Expand Down
15 changes: 2 additions & 13 deletions src/components/Header.astro
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,6 @@ import ThemeToggle from './ThemeToggle.astro';
import MobileNav from './MobileNav.astro';
import SearchBar from './SearchBar.astro';
import Container from './Container.astro';

interface Props {
searchData: unknown[];
}

const { searchData } = Astro.props;
---

<header class="site-header" role="banner">
Expand All @@ -22,7 +16,7 @@ const { searchData } = Astro.props;
</div>
<div class="site-header__actions">
<div class="site-header__desktop-search">
<SearchBar searchData={searchData} placeholder="Search notes…" />
<SearchBar placeholder="Search notes…" />
</div>
<button
type="button"
Expand Down Expand Up @@ -54,12 +48,7 @@ const { searchData } = Astro.props;
</div>
</Container>
<div id="mobile-search-container" class="site-header__search-panel" hidden>
<Container
><SearchBar
searchData={searchData}
placeholder="Search notes, topics, and pages…"
/></Container
>
<Container><SearchBar placeholder="Search notes, topics, and pages…" /></Container>
</div>
</header>

Expand Down
27 changes: 13 additions & 14 deletions src/components/SearchBar.astro
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
---
interface Props {
searchData: unknown[];
class?: string;
placeholder?: string;
}

const {
searchData,
class: className = '',
placeholder = 'Search writings, pages...',
} = Astro.props;
const { class: className = '', placeholder = 'Search writings, pages...' } = Astro.props;

// Generate unique ID for this search instance
const searchId = `search-${Math.random().toString(36).slice(2, 11)}`;

// Serialize search data for client-side use
const searchDataJson = JSON.stringify(searchData);
---

<div class={`search-container relative ${className}`}>
Expand Down Expand Up @@ -100,11 +92,6 @@ const searchDataJson = JSON.stringify(searchData);
</div>
</div>

<script define:vars={{ searchDataJson }} is:inline>
// Make search data globally available
window.searchData = JSON.parse(searchDataJson);
</script>

<script>
// Search functionality
class SearchBar {
Expand All @@ -116,6 +103,7 @@ const searchDataJson = JSON.stringify(searchData);
private clearBtn: HTMLButtonElement | null;
private debounceTimer: ReturnType<typeof setTimeout> | null = null;
private isSearching = false;
private searchRequestId = 0;

constructor(searchId: string) {
this.input = document.getElementById(searchId) as HTMLInputElement;
Expand Down Expand Up @@ -193,6 +181,7 @@ const searchDataJson = JSON.stringify(searchData);

handleInput() {
const query = this.input?.value.trim() || '';
this.searchRequestId += 1;

// Show/hide clear button
if (this.clearBtn) {
Expand All @@ -202,10 +191,12 @@ const searchDataJson = JSON.stringify(searchData);
// Clear previous timer
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = null;
}

// Debounce search
this.debounceTimer = setTimeout(() => {
this.debounceTimer = null;
if (query.length >= 2) {
this.performSearch(query);
} else {
Expand All @@ -217,14 +208,17 @@ const searchDataJson = JSON.stringify(searchData);
async performSearch(query: string) {
if (this.isSearching) return;

const requestId = this.searchRequestId;
this.isSearching = true;
this.showLoading();

try {
// Simulate search - replace with actual search implementation
const results = await this.searchPosts(query);
if (requestId !== this.searchRequestId || this.input?.value.trim() !== query) return;
this.displayResults(results);
} catch (error) {
if (requestId !== this.searchRequestId || this.input?.value.trim() !== query) return;
this.showNoResults();
} finally {
this.isSearching = false;
Expand Down Expand Up @@ -533,6 +527,11 @@ const searchDataJson = JSON.stringify(searchData);
}

clearSearch() {
this.searchRequestId += 1;
if (this.debounceTimer) {
clearTimeout(this.debounceTimer);
this.debounceTimer = null;
}
if (this.input) {
this.input.value = '';
this.input.focus();
Expand Down
2 changes: 2 additions & 0 deletions src/content/p/briefly-on-empathy-as-a-double-edged-sword.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ description: >-
lead to overwhelm. Explores the tension between compassion and
self-preservation.
pubDate: '2024-07-29T17:12:19.944Z'
updatedDate: '2026-09-10T10:56:46-04:00'
language:
- en
heroImage: /images/2026/empathy-sword-edges.png
category:
- metaspace
- integration-growth
Expand Down
6 changes: 3 additions & 3 deletions src/content/p/life-statement-transformation.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: Why Creating a Life Statement Has Helped Me So Much
description: >-
A personal journey of self-discovery through creating a life statement,
exploring the gap between values and actions, and finding clarity in personal
identity.
After my daughter was born, I noticed a gap between the "family first" man
I thought I was and where my time actually went. Writing a personal
mission statement is how I closed it.
pubDate: '2024-04-27T08:50:00.000Z'
language:
- en
Expand Down
6 changes: 3 additions & 3 deletions src/content/p/mercy-through-the-blade.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: 'Mercy Through the Blade: The Silent Law of Leadership'
description: >-
A deep exploration of authentic leadership, the warrior's dilemma between
truth and comfort, and the sacred responsibility of wielding power with grace
and ferocity.
On leadership as choosing hard truths over comfortable ones — why softening
reality to spare feelings can do more harm than telling people what they
need to hear.
pubDate: '2025-04-26T00:00:00.000Z'
updatedDate: '2026-09-08T16:15:00-04:00'
language:
Expand Down
4 changes: 2 additions & 2 deletions src/content/p/notes-on-respect.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
---
title: Notes on Respect
description: >-
A personal reflection on the transformative power of respect, self-worth, and
healthy boundaries in personal growth and relationships.
How getting healthy changed the way people treat me, and what I've learned
about respect, self-worth, and boundaries along the way.
pubDate: '2024-05-07'
language:
- en
Expand Down
6 changes: 3 additions & 3 deletions src/content/p/power-intentional-living.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: On Self-Discovery, Self-Awareness, Value-Based Living
description: >-
A journey through self-awareness, challenging negative self-talk, and
discovering the transformative power of value-based decision making in
everyday life.
Catching an intrusive negative thought, reviewing a month of memories to
counter it, and a night alone at a concert that made me question why I
was really there.
pubDate: '2024-03-25T14:15:00.000Z'
language:
- en
Expand Down
5 changes: 3 additions & 2 deletions src/content/p/reflections-from-a-tough-weekend.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
---
title: Reflections From a Tough Weekend
description: >-
A raw and honest reflection on processing emotional pain, self-healing, and
the journey towards emotional wellbeing.
A raw journal entry written to get through a painful weekend: notes to
myself on loneliness, an emotionally abusive relationship, and staying
kind while I heal.
pubDate: '2024-05-14'
language:
- en
Expand Down
9 changes: 4 additions & 5 deletions src/content/p/who-really-raised-me.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
---
title: Who, really, raised me?
description: >-
A deep dive into the fictional characters that shaped my values, from
childhood cartoons to adult anime. Discover how Samurai X, Dragon Ball Z,
Berserk, and especially One Punch Man's Saitama became my true mentors,
teaching me about discipline, brotherhood, pain as power, and the loneliness
of mastery.
Which fictional characters shaped my values, from childhood cartoons to
adult anime — and what Samurai X, Dragon Ball Z, Berserk, and especially
One Punch Man's Saitama taught me about discipline, brotherhood, and the
loneliness of mastery.
pubDate: '2025-04-17T13:56:47.953Z'
updatedDate: '2026-08-27T16:54:00.000Z'
language:
Expand Down
Loading
Loading