<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>gongju.dev Changelog</title>
        <link>https://gongju.dev/blog</link>
        <description>Release notes and updates for gongju.dev</description>
        <lastBuildDate>Mon, 20 Jul 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-Hans</language>
        <copyright>Copyright © 2026 gongju.dev</copyright>
        <item>
            <title><![CDATA[i18n parity, 12 new tool tests, smarter search, homepage tag filter]]></title>
            <link>https://gongju.dev/blog/2026-07-20-i18n-tests-search-discoverability</link>
            <guid>https://gongju.dev/blog/2026-07-20-i18n-tests-search-discoverability</guid>
            <pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[This batch fills the missing en/ja/vi docs so every locale ships all 77 tools, adds unit tests for 12 more tools, makes the search box understand pinyin and aliases, and adds a purpose-tag filter plus collapsible categories to the homepage.]]></description>
            <content:encoded><![CDATA[<p>This update is about three things: non-Chinese user experience, test coverage, and finding tools on the homepage.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="i18n">i18n<a href="https://gongju.dev/blog/2026-07-20-i18n-tests-search-discoverability#i18n" class="hash-link" aria-label="i18n的直接链接" title="i18n的直接链接" translate="no">​</a></h2>
<ul>
<li class="">en/ja/vi were missing 8 tool docs in total, so non-Chinese users saw a shorter tool list than the Chinese locale.</li>
<li class="">We backfilled the missing chmod-calculator, dot-renderer, image-to-ico, cidr-calculator, csv-editor, password-generator, pdf-to-html, and random-username docs.</li>
<li class="">All four locales now ship the same 77 tools. Clicking through the navbar on any locale shows an identical list.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="test-coverage">Test coverage<a href="https://gongju.dev/blog/2026-07-20-i18n-tests-search-discoverability#test-coverage" class="hash-link" aria-label="Test coverage的直接链接" title="Test coverage的直接链接" translate="no">​</a></h2>
<ul>
<li class="">Previously we only had 47 test files / 135 assertions, with 32 tools untested.</li>
<li class="">Added unit tests for 12 tools (7 ciphers, 2 network, 3 image/analysis):<!-- -->
<ul>
<li class="">Atbash / Rot13 involution round-trips</li>
<li class="">Caesar / Bacon / RailFence / Vigenere encode↔decode round-trips</li>
<li class="">Morse encode/decode plus space-to-slash handling</li>
<li class="">DnsLookup / SslCheck with mocked fetch covering empty-URL prompts and API success/failure paths</li>
<li class="">Pigpen / WordCloud with mocked canvas checking placeholder copy and disabled-state coupling</li>
<li class="">TextEncrypt covering empty-text and short-password warnings plus mocked encrypt success showing the shareable link</li>
</ul>
</li>
<li class="">Total: 47 → 59 test files, 135 → 177 assertions (with more to come).</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="search-experience">Search experience<a href="https://gongju.dev/blog/2026-07-20-i18n-tests-search-discoverability#search-experience" class="hash-link" aria-label="Search experience的直接链接" title="Search experience的直接链接" translate="no">​</a></h2>
<ul>
<li class="">The old search only did a naive substring match against title and description, so queries like "json 美化", "erweima", or "validator" returned nothing.</li>
<li class="">A new <code>src/utils/search.js</code> scores matches across multiple fields and ranks by weight: title substring &gt; title full pinyin &gt; title pinyin initials &gt; aliases &gt; alias pinyin &gt; description.</li>
<li class="">We added an <code>aliases</code> frontmatter field to 23 popular tools (json-formatter, qrcode, timestamp, regex-tester, …), so queries like "二维码", "validator", or "时间戳" now hit.</li>
<li class="">Matched title fragments are highlighted in yellow inside the result cards, so you can see exactly what matched.</li>
<li class="">Fixed a P2 bug where the homepage "Search" button had no onClick handler — clicking it now focuses the input.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="homepage-discoverability">Homepage discoverability<a href="https://gongju.dev/blog/2026-07-20-i18n-tests-search-discoverability#homepage-discoverability" class="hash-link" aria-label="Homepage discoverability的直接链接" title="Homepage discoverability的直接链接" translate="no">​</a></h2>
<ul>
<li class="">70+ tools on one long scroll was painful for newcomers.</li>
<li class="">A new "purpose" tag bar sits at the top of the tools section (Converter, Generator, Encoder, Decoder, Formatter, Validator, Calculator, Lookup, Cipher, Editor, Security, Compressor). Click it to filter across categories, with counts next to each tag.</li>
<li class="">Category headers are now collapsible — click to fold/unfold, with an up/down chevron and a count badge.</li>
<li class="">When a purpose tag is selected, "Favorites" and "Recently used" automatically step aside and only tools matching the selected purpose remain.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bug-fix">Bug fix<a href="https://gongju.dev/blog/2026-07-20-i18n-tests-search-discoverability#bug-fix" class="hash-link" aria-label="Bug fix的直接链接" title="Bug fix的直接链接" translate="no">​</a></h2>
<ul>
<li class="">The timestamp tool test was flaky around the 0:00 boundary when the current year showed up in multiple description values; switched to <code>getAllByText</code> to make it deterministic.</li>
</ul>
<p>Let us know in the comments below if the new search feels right for you.</p>]]></content:encoded>
            <category>Release</category>
        </item>
        <item>
            <title><![CDATA[Tool recommendations, PWA install prompt, per-tool OG images, and a global stash palette]]></title>
            <link>https://gongju.dev/blog/2026-07-20-recommendations-pwa-og-stash</link>
            <guid>https://gongju.dev/blog/2026-07-20-recommendations-pwa-og-stash</guid>
            <pubDate>Mon, 20 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Four UX upgrades today: a 'similar tools' section at the bottom of every tool page, an install-to-home-screen prompt, 77 static OG images generated at build time, and a global stash palette summoned with Alt+S for cross-tool data flow.]]></description>
            <content:encoded><![CDATA[<p>Four small UX upgrades today, all about helping you find tools, install the site, share it, and move data between tools faster.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="tool-recommendations-at-the-bottom-of-every-tool-page">Tool recommendations at the bottom of every tool page<a href="https://gongju.dev/blog/2026-07-20-recommendations-pwa-og-stash#tool-recommendations-at-the-bottom-of-every-tool-page" class="hash-link" aria-label="Tool recommendations at the bottom of every tool page的直接链接" title="Tool recommendations at the bottom of every tool page的直接链接" translate="no">​</a></h2>
<ul>
<li class="">A new "Similar tools" section now sits above the share/embed widget on every tool page.</li>
<li class="">Recommendations are computed from frontmatter tags (overlap * 3) plus same-category bonus (+1), capped at 4 results.</li>
<li class="">Cards reuse the homepage tool card styling - icon, title, two-line description, up to two tag chips, and an arrow link.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="pwa-install-prompt">PWA install prompt<a href="https://gongju.dev/blog/2026-07-20-recommendations-pwa-og-stash#pwa-install-prompt" class="hash-link" aria-label="PWA install prompt的直接链接" title="PWA install prompt的直接链接" translate="no">​</a></h2>
<ul>
<li class="">A dismissible install banner now appears at the bottom of the screen on Chrome/Edge (listening to <code>beforeinstallprompt</code>), and shows a manual "share button -&gt; add to home screen" instruction on iOS Safari.</li>
<li class="">Dismissing persists for 7 days in <code>localStorage</code>. The banner is hidden in <code>standalone</code> mode so installed users never see it.</li>
<li class="">The web manifest now ships 7 app shortcuts (JSON, Base64, timestamp, UUID, QR code, image compressor, regex). Long-pressing the installed icon on mobile surfaces them.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="per-tool-og-images-static-generated-at-build-time">Per-tool OG images (static, generated at build time)<a href="https://gongju.dev/blog/2026-07-20-recommendations-pwa-og-stash#per-tool-og-images-static-generated-at-build-time" class="hash-link" aria-label="Per-tool OG images (static, generated at build time)的直接链接" title="Per-tool OG images (static, generated at build time)的直接链接" translate="no">​</a></h2>
<ul>
<li class="">A new <code>scripts/generate-og-images.js</code> scans every <code>docs/*.mdx</code> and emits a 1200x630 SVG into <code>static/og/&lt;tool-id&gt;.svg</code> (about 1-2 KB each, 77 files total).</li>
<li class="">Template: accent bar, brand logo, GONGJU.DEV label, category name, the tool title (wrapped to up to 3 lines), a two-line description, and a footer line "Free - Local - Privacy-first - gongju.dev".</li>
<li class="">The build pipeline now runs <code>npm run gen-og</code> before <code>docusaurus build</code>.</li>
<li class="">Each tool page injects <code>og:image</code> and <code>twitter:image</code> meta tags pointing to its own SVG. Twitter will fall back to the default social card since it doesn't accept SVG; Facebook, Slack, LinkedIn, Telegram and others render it natively.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="global-stash-palette-cross-tool-data-flow-no-per-tool-changes">Global stash palette (cross-tool data flow, no per-tool changes)<a href="https://gongju.dev/blog/2026-07-20-recommendations-pwa-og-stash#global-stash-palette-cross-tool-data-flow-no-per-tool-changes" class="hash-link" aria-label="Global stash palette (cross-tool data flow, no per-tool changes)的直接链接" title="Global stash palette (cross-tool data flow, no per-tool changes)的直接链接" translate="no">​</a></h2>
<ul>
<li class="">Press <code>Alt+S</code> (or <code>Ctrl/Cmd+Shift+V</code>) anywhere on the site to summon a modal that lists your stashed items.</li>
<li class="">Search at the top filters by content. Up/Down arrows move the highlight, Enter inserts the selected item into whichever input was focused before you opened the palette, Esc closes.</li>
<li class="">Each item shows its type tag (text/json), relative timestamp ("just now", "5 minutes ago", "3 hours ago"), the content (clamped to 2 lines), and a copy-to-clipboard button.</li>
<li class="">The insertion uses React's native value setter plus <code>input</code>/<code>change</code> events, so it works with any controlled component without each tool having to expose a ref.</li>
<li class="">The first-visit toast now advertises all three global shortcuts: <code>Ctrl+B</code> for the workspace drawer, <code>Ctrl+K</code> for the command palette, and <code>Alt+S</code> for the stash palette.</li>
</ul>
<p>Feedback welcome in the comments below - especially if the Alt+S shortcut collides with anything you rely on.</p>]]></content:encoded>
            <category>Release</category>
        </item>
        <item>
            <title><![CDATA[Changelog launched + July 17 batch of fixes]]></title>
            <link>https://gongju.dev/blog/2026-07-17-changelog-launch</link>
            <guid>https://gongju.dev/blog/2026-07-17-changelog-launch</guid>
            <pubDate>Fri, 17 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[The Changelog section is live. From now on every bug fix and new feature will be logged here. This entry covers the July 17 changes: clipboard safety rewrite, i18n dead-link fixes, command palette accessibility, and more.]]></description>
            <content:encoded><![CDATA[<p>The <strong>Changelog</strong> section is live today. From now on, every bug fix and new feature will be logged here — feel free to drop feedback in the comments below.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="new-changelog-section">New: Changelog section<a href="https://gongju.dev/blog/2026-07-17-changelog-launch#new-changelog-section" class="hash-link" aria-label="New: Changelog section的直接链接" title="New: Changelog section的直接链接" translate="no">​</a></h2>
<ul>
<li class="">A <code>/blog</code> route is now live, with a <strong>Changelog</strong> entry in the navbar.</li>
<li class="">Release notes are written in English by default; the four locales automatically fall back to the default language content.</li>
<li class="">Every post ships with a Giscus comment thread, shared with the tool pages.</li>
<li class="">RSS and Atom feeds are available at <code>/blog/rss.xml</code> and <code>/blog/atom.xml</code>.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="security--reliability">Security &amp; reliability<a href="https://gongju.dev/blog/2026-07-17-changelog-launch#security--reliability" class="hash-link" aria-label="Security &amp; reliability的直接链接" title="Security &amp; reliability的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>Clipboard rewrite</strong>: 47 tools now go through a unified clipboard helper. HTTPS-only origins, private mode, and permission denial no longer fail silently — failures surface a toast.</li>
<li class="">localStorage writes are now wrapped in try/catch, so private mode or quota exceeded no longer crash the site.</li>
<li class=""><strong>Regex Tester self-XSS fix</strong>: user-supplied match strings are escaped before being wrapped in <code>&lt;mark&gt;</code>, so payloads like <code>&lt;img onerror=...&gt;</code> can no longer be injected.</li>
<li class="">Several tools' image-to-clipboard operations now <code>await</code> and degrade gracefully, falling back to a PNG download when not supported.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="i18n">i18n<a href="https://gongju.dev/blog/2026-07-17-changelog-launch#i18n" class="hash-link" aria-label="i18n的直接链接" title="i18n的直接链接" translate="no">​</a></h2>
<ul>
<li class="">Fixed a P0 issue where clicking tool cards, favorites, or recently-used entries returned 404 dead links on non-Chinese locales.</li>
<li class="">Hard-coded Chinese strings in the workspace drawer, command palette, breadcrumbs, and other spots now go through the translation system.</li>
<li class="">The Giscus comment UI language now follows the current locale (zh-CN / en / ja / vi).</li>
<li class="">The homepage now shows the pdf / fun / mcp categories — 19+ tools that were previously only reachable via search are now visible.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="accessibility">Accessibility<a href="https://gongju.dev/blog/2026-07-17-changelog-launch#accessibility" class="hash-link" aria-label="Accessibility的直接链接" title="Accessibility的直接链接" translate="no">​</a></h2>
<ul>
<li class="">The command palette (Ctrl/Cmd+K) is now a proper dialog: semantic roles, a focus trap, and Caps Lock no longer breaks the trigger.</li>
<li class="">The workspace drawer on mobile (&lt; 768px) now fills 100% width instead of overflowing the screen.</li>
</ul>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="bug-fixes">Bug fixes<a href="https://gongju.dev/blog/2026-07-17-changelog-launch#bug-fixes" class="hash-link" aria-label="Bug fixes的直接链接" title="Bug fixes的直接链接" translate="no">​</a></h2>
<ul>
<li class=""><strong>Dot Renderer</strong> button clicks now show clear toast feedback for empty input / success / failure, while auto-render stays silent.</li>
<li class=""><strong>Markdown Preview</strong> switched to a standard GFM renderer, so tables, task lists, and strikethrough now render correctly.</li>
<li class=""><strong>YAML highlight</strong> fixed a regex ordering bug that broke HTML rendering.</li>
</ul>
<p>Feedback and bug reports are welcome in the comments below.</p>]]></content:encoded>
            <category>Release</category>
        </item>
    </channel>
</rss>