<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/modules/content/">
  <channel>
    <title><![CDATA[Amytis]]></title>
    <link>https://amytis.vercel.app</link>
    <description><![CDATA[Amytis — an elegant open-source framework for building your personal digital garden.]]></description>
    <language>en</language>
    <lastBuildDate>Mon, 25 May 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://amytis.vercel.app/feed.xml" rel="self" type="application/rss+xml" />
    <image>
      <url>https://amytis.vercel.app/og-image.png</url>
      <title>Amytis</title>
      <link>https://amytis.vercel.app</link>
    </image>
    
        <item>
          <title><![CDATA[Code Block Features Showcase]]></title>
          <link>https://amytis.vercel.app/posts/code-block-features-showcase/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/code-block-features-showcase/</guid>
          <pubDate>Mon, 25 May 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Walk through the advanced code-block features: line numbers, line highlighting, title bars, diff colors, word-wrap toggle, and plaintext fallback.]]></description>
          <content:encoded><![CDATA[<p>The default Shiki pipeline applies build-time syntax highlighting with a
dual <code>github-light</code> / <code>github-dark</code> theme. The features below are opt-in
via fence metadata.</p>
<h2>Title bar</h2>
<pre><code class="language-ts">export const greet = (name: string) => `Hello, ${name}!`;
</code></pre>
<h2>Line numbers</h2>
<pre><code class="language-python">def fib(n):
    if n &#x3C; 2:
        return n
    return fib(n - 1) + fib(n - 2)
</code></pre>
<h2>Highlighted lines</h2>
<pre><code class="language-rust">fn main() {
    let x = compute();
    println!("{x}");
    if x > 10 {
        warn();
        recover();
    }
}
</code></pre>
<h2>Title + line numbers + highlights combined</h2>
<pre><code class="language-tsx">import { highlightToHast } from '@/lib/shiki';
import { toHtml } from 'hast-util-to-html';
import CodeBlockToolbar from './CodeBlockToolbar';

export default async function CodeBlock({ language, children, title }) {
  const hast = await highlightToHast(children, language, { title });
  const html = toHtml(hast);
  return (
    &#x3C;div className="cb-root">
      {title &#x26;&#x26; &#x3C;span className="cb-title">{title}&#x3C;/span>}
      &#x3C;CodeBlockToolbar code={children} />
      &#x3C;div dangerouslySetInnerHTML={{ __html: html }} />
    &#x3C;/div>
  );
}
</code></pre>
<h2>Diff with red/green backgrounds</h2>
<pre><code class="language-diff">-export const VERSION = "1.0";
+export const VERSION = "2.0";
 export const NAME = "amytis";
-export const STAGE = "alpha";
+export const STAGE = "beta";
</code></pre>
<h2>Word-wrap toggle</h2>
<p>Long lines in code blocks overflow horizontally by default — the block grows
a scrollbar at the bottom. Click the <strong>Wrap</strong> button in any block's header
to soft-wrap long lines onto multiple visual lines instead; click again to
restore horizontal scrolling.</p>
<pre><code class="language-bash">curl -X POST "https://api.example.com/v1/items?fields=id,name,description,createdAt,updatedAt&#x26;sort=createdAt:desc&#x26;limit=100&#x26;offset=0&#x26;filter[status]=active&#x26;filter[category]=blog&#x26;include=author,tags" -H "Authorization: Bearer YOUR_API_TOKEN_HERE" -H "Content-Type: application/json" -d '{"name":"example","description":"a sufficiently long single line to demonstrate the wrap toggle"}'
</code></pre>
<p>Try the <strong>Wrap</strong> button in the header above ↑ to see the long line collapse
into multiple soft-wrapped lines.</p>
<h2>Mermaid still works (regression check)</h2>
<pre><code class="language-mermaid">graph LR
  A[Markdown] --> B[remark]
  B --> C[rehype + Shiki]
  C --> D[Static HTML]
</code></pre>
<h2>Tabbed code groups</h2>
<p>Group adjacent fences into a single tabbed widget by wrapping them in a
<code>:::code-group</code> container directive. Tab names come from the <code>[label]</code>
token after the language. The mechanism is pure CSS (radio inputs + sibling
selectors) — zero JavaScript, zero hydration cost.</p>
<p>When a tab label matches a known package manager, language, or common
config filename, an icon appears automatically before the label. Resolution
is handled by <code>resolveCodeGroupIcon</code> in <code>src/lib/code-group-icons.ts</code>.</p>
<p>:::code-group</p>
<pre><code class="language-bash">npm install amytis
</code></pre>
<pre><code class="language-bash">yarn add amytis
</code></pre>
<pre><code class="language-bash">pnpm add amytis
</code></pre>
<pre><code class="language-bash">bun add amytis
</code></pre>
<p>:::</p>
<p>Filename labels also resolve — e.g. <code>tsconfig.json</code>, <code>vite.config.ts</code>, or
<code>Dockerfile</code>:</p>
<p>:::code-group</p>
<pre><code class="language-json">{ "compilerOptions": { "target": "es2022", "module": "esnext" } }
</code></pre>
<pre><code class="language-ts">import { defineConfig } from 'vite';
export default defineConfig({ server: { port: 5173 } });
</code></pre>
<pre><code class="language-dockerfile">FROM node:20-alpine
WORKDIR /app
COPY . .
RUN npm ci &#x26;&#x26; npm run build
</code></pre>
<p>:::</p>
<p>Tabs work across languages too — handy for showing the same algorithm in
multiple implementations:</p>
<p>:::code-group</p>
<pre><code class="language-ts">export function greet(name: string): string {
  return `Hello, ${name}!`;
}
</code></pre>
<pre><code class="language-python">def greet(name: str) -> str:
    return f"Hello, {name}!"
</code></pre>
<pre><code class="language-rust">fn greet(name: &#x26;str) -> String {
    format!("Hello, {name}!")
}
</code></pre>
<p>:::</p>
<h2>Notation comments</h2>
<p>Annotate individual lines with <code>// [!code …]</code> comments. Six markers are
supported — focus, diff, highlight, error, warning — using the language's
native comment style (<code>//</code> in C-family, <code>#</code> in Python, <code>--</code> in SQL, etc.):</p>
<pre><code class="language-ts">function login(user: string) {            // [!code focus]
  const token = oldApi.auth(user)         // [!code --]
  const token = newApi.auth({ user })     // [!code ++]
  validate(token)                         // [!code highlight]
  throwIfExpired(token)                   // [!code error]
  if (!token.refreshable) warn()          // [!code warning]
  return token
}
</code></pre>
<p><code>// [!code focus]</code> dims the rest of the block so the focused subset stands
out; hover the block to reveal the dimmed lines. <code>// [!code error]</code> /
<code>[!code warning]</code> tint the line with a colored left-border (red / amber).
<code>[!code ++]</code> / <code>[!code --]</code> color individual lines without needing a
<code>diff</code>-language fence.</p>
<p>Notation comments work in <strong>any</strong> language — Python:</p>
<pre><code class="language-python">def fib(n):
    if n &#x3C; 2: return n          # [!code focus]
    return fib(n-1) + fib(n-2)
</code></pre>
<h2>GitHub-flavored alerts</h2>
<p>Add a <code>[!TYPE]</code> marker on the first line of a blockquote to render it as a
GitHub-style callout. Five types are supported, each with its own color,
icon, and label:</p>
<blockquote>
<p>[!NOTE]
Highlights information that users should take into account, even when skimming.</p>
</blockquote>
<blockquote>
<p>[!TIP]
Optional information to help a user be more successful.</p>
</blockquote>
<blockquote>
<p>[!IMPORTANT]
Crucial information necessary for users to succeed.</p>
</blockquote>
<blockquote>
<p>[!WARNING]
Critical content demanding immediate user attention due to potential risks.</p>
</blockquote>
<blockquote>
<p>[!CAUTION]
Negative potential consequences of an action.</p>
</blockquote>
<p>rST equivalents (<code>.. note::</code> / <code>.. tip::</code> / <code>.. important::</code> / <code>.. warning::</code>
/ <code>.. caution::</code>) render with matching colors via docutils' admonition
directives — same visual treatment across both pipelines.</p>
<h2>Explicit plaintext</h2>
<pre><code class="language-plaintext">This block opts out of syntax highlighting entirely. Use `plaintext` (or its
aliases `text`, `txt`, `plain`) for prose-like blocks where token coloring
would be noisy or misleading. Unknown language names will fail the build.
</code></pre>]]></content:encoded>
          <dc:creator><![CDATA[Amytis Team]]></dc:creator>
          <category><![CDATA[test]]></category><category><![CDATA[code]]></category><category><![CDATA[shiki]]></category>
        </item>
        <item>
          <title><![CDATA[i18n in a Static Next.js Blog: Client-Side Toggle vs URL-Based Routing]]></title>
          <link>https://amytis.vercel.app/posts/i18n-routing-considerations/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/i18n-routing-considerations/</guid>
          <pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[A deep dive into the trade-offs between client-side language switching and proper URL-based locale routing for a statically exported Next.js digital garden.]]></description>
          <content:encoded><![CDATA[<p>When building a multilingual static blog with Next.js, there are two fundamentally different approaches to internationalisation. Choosing between them involves trade-offs across SEO, developer experience, content strategy, and hosting complexity.</p>
<h2>The Client-Side Toggle Approach</h2>
<p>The simplest approach stores language preference in client state and resolves translations after hydration:</p>
<pre><code class="language-tsx">// Language stored in context, resolved on the client
const { t, language } = useLanguage();
const label = t('about'); // "About" or "关于"
</code></pre>
<p>For page content that has locale variants, all versions are server-rendered into the HTML and a thin client wrapper toggles visibility:</p>
<pre><code class="language-tsx">// LocaleSwitch: shows/hides [data-locale] divs via useEffect
&#x3C;LocaleSwitch>
  &#x3C;div data-locale="en">&#x3C;MarkdownRenderer content={enContent} />&#x3C;/div>
  &#x3C;div data-locale="zh" style={{ display: 'none' }}>&#x3C;MarkdownRenderer content={zhContent} />&#x3C;/div>
&#x3C;/LocaleSwitch>
</code></pre>
<p>This works and is zero-config — no routing changes needed. But it has real limitations.</p>
<h3>SEO Problems</h3>
<ul>
<li><strong>Crawlers always see the default language.</strong> Googlebot doesn't execute <code>localStorage</code> reads, so it always indexes the default locale's content.</li>
<li><strong><code>display:none</code> content is risky.</strong> Google may partially index hidden locale variants, or ignore them entirely.</li>
<li><strong>No <code>hreflang</code> signals.</strong> Search engines can't discover alternate language versions of a page.</li>
<li><strong><code>&#x3C;html lang></code> not updated.</strong> Accessibility and search engine tooling rely on this attribute.</li>
</ul>
<hr>
<h2>URL-Based Locale Routing</h2>
<p>The proper solution gives each language variant its own URL:</p>
<pre><code>/about        → English (default, no prefix)
/zh/about     → Chinese
</code></pre>
<p>With Next.js App Router, this means moving all routes under an <code>app/[locale]/</code> segment and using <code>generateStaticParams</code> to pre-render each route for each locale at build time.</p>
<p>Since Amytis uses <code>output: "export"</code>, this is pure <strong>Static Site Generation</strong> — the HTML is fully pre-built per locale. Crawlers get complete HTML with no JavaScript required, and each locale is independently indexable.</p>
<h3>The Default Locale Prefix Problem</h3>
<p>Most sites want the default locale to have a clean URL (<code>/about</code>, not <code>/en/about</code>). With a runtime server, middleware handles this transparently. With static export, you need your <strong>hosting layer</strong> to do the rewrite.</p>
<h4>Netlify / Cloudflare Pages</h4>
<p>Drop a <code>_redirects</code> file in <code>public/</code>:</p>
<pre><code>/en              /            301
/en/*            /:splat      301
/*               /en/:splat   200
</code></pre>
<p>The <code>200</code> status is a <strong>silent rewrite</strong> — the user sees <code>/about</code> in the URL bar, but the server serves <code>out/en/about/index.html</code>.</p>
<h4>Vercel</h4>
<pre><code class="language-json">{
  "redirects": [
    { "source": "/en/:path*", "destination": "/:path*", "permanent": true }
  ],
  "rewrites": [
    { "source": "/((?!zh/).*)", "destination": "/en/$1" }
  ]
}
</code></pre>
<h4>Nginx</h4>
<pre><code class="language-nginx">location ~ ^/en(/.*)?$ { return 301 ${1:-/}; }
location /zh/ { try_files $uri $uri/index.html =404; }
location / { try_files /en$uri /en$uri/index.html =404; }
</code></pre>
<h4>GitHub Pages</h4>
<p>GitHub Pages has no native rewrite support. The simplest workaround is a root <code>index.html</code> with a JS language detector:</p>
<pre><code class="language-html">&#x3C;script>
  const lang = navigator.language.startsWith('zh') ? 'zh' : 'en';
  window.location.replace('/' + lang + '/');
&#x3C;/script>
</code></pre>
<p>Or just accept the <code>/en/</code> prefix for all locales.</p>
<hr>
<h2>Content Strategy</h2>
<p>URL-based routing changes more than just URLs — it changes how you think about content.</p>
<p>For a personal digital garden, most content is written in one language and won't be fully translated. The realistic scope is:</p>



































<table><thead><tr><th>Content Type</th><th>Translated?</th><th>Approach</th></tr></thead><tbody><tr><td>Static pages (about, privacy)</td><td>Yes</td><td>Optional <code>.zh.mdx</code> variant files</td></tr><tr><td>Posts</td><td>Rarely</td><td>Fallback to original + notice</td></tr><tr><td>Series descriptions</td><td>Maybe</td><td>Optional <code>index.zh.mdx</code></td></tr><tr><td>Books</td><td>Unlikely</td><td>Fallback</td></tr><tr><td>Flows (daily notes)</td><td>No</td><td>UI-only i18n, no locale in URL</td></tr></tbody></table>
<p>The <code>.{locale}.mdx</code> convention — already used for static pages in Amytis — extends naturally to posts and series:</p>
<pre><code>content/posts/my-post.mdx           # default locale
content/posts/my-post.zh.mdx        # optional Chinese translation
content/series/my-series/index.zh.mdx
</code></pre>
<p>At build time, <code>generateStaticParams</code> generates <code>/en/my-post</code> and <code>/zh/my-post</code>. If the <code>.zh.mdx</code> file doesn't exist, the Chinese URL falls back to the English content with a small "not available in this language" banner.</p>
<hr>
<h2>Trade-offs at a Glance</h2>



































<table><thead><tr><th>Aspect</th><th>Client-Side Toggle</th><th>URL-Based Routing</th></tr></thead><tbody><tr><td>SEO</td><td>Crawlers see default lang only</td><td>Each locale fully indexed</td></tr><tr><td>Default locale prefix</td><td>No prefix</td><td>CDN rewrite needed</td></tr><tr><td>Build size</td><td>Same</td><td>~2×</td></tr><tr><td>Refactor scope</td><td>None</td><td>Large</td></tr><tr><td>Content strategy</td><td><code>.zh.mdx</code> for pages only</td><td><code>.zh.mdx</code> for all content types</td></tr></tbody></table>
<hr>
<h2>Conclusion</h2>
<p>For a personal blog where SEO in a second language isn't critical, the client-side toggle approach is pragmatic and gets the job done. UI strings translate, page content can optionally have locale variants, and there's no hosting complexity.</p>
<p>For a project where bilingual SEO matters — where you genuinely want Chinese content indexed under Chinese URLs — URL-based routing is the right architecture. The CDN configuration is a one-time setup, and the <code>.{locale}.mdx</code> convention for content is already half-implemented.</p>
<p>The good news: both approaches share the same content file convention. Migrating from client-side toggle to URL-based routing is a routing and build change, not a content restructure.</p>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          <category><![CDATA[nextjs]]></category><category><![CDATA[i18n]]></category><category><![CDATA[seo]]></category><category><![CDATA[static-site]]></category>
        </item>
        <item>
          <title><![CDATA[Multimedia Showcase: Video, Podcasts & Embeds]]></title>
          <link>https://amytis.vercel.app/posts/multimedia-showcase/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/multimedia-showcase/</guid>
          <pubDate>Fri, 20 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[A comprehensive test of multimedia embedding support — YouTube, Vimeo, podcasts, livestreams, HTML5 native media, and audio platforms.]]></description>
          <content:encoded><![CDATA[<p>This post tests how Amytis renders multimedia content embedded via raw HTML iframes and native HTML5 media elements. Since <code>rehype-raw</code> is enabled, standard HTML embed codes work directly inside Markdown.</p>
<hr>
<h2>YouTube Video</h2>
<p>Responsive 16:9 YouTube embed using a padded wrapper:</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 12px; margin: 1.5rem 0;">
  <iframe src="https://www.youtube.com/embed/jNQXAC9IVRw?rel=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture; web-share" title="Me at the zoo — first YouTube video ever uploaded (2005)"></iframe>
</div>
<p><em>"Me at the zoo" — the very first video uploaded to YouTube (April 23, 2005).</em></p>
<hr>
<h2>Vimeo Video</h2>
<p>Vimeo also supports responsive 16:9 embedding:</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 12px; margin: 1.5rem 0;">
  <iframe src="https://player.vimeo.com/video/76979871?color=ff9933&#x26;title=0&#x26;byline=0&#x26;portrait=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;" allow="autoplay; fullscreen; picture-in-picture" title="Big Buck Bunny — Blender Foundation (Vimeo)"></iframe>
</div>
<p><em>Big Buck Bunny (2008) — open-source animated short by the Blender Foundation.</em></p>
<hr>
<h2>Podcast Embeds</h2>
<h3>Spotify Podcast</h3>
<p>Spotify provides a fixed-height iframe embed for individual episodes:</p>
<iframe src="https://open.spotify.com/embed/episode/0b8q6Q7fKqZLlSc0Lh1WQe?utm_source=generator&#x26;theme=0" style="border-radius: 12px; margin: 1rem 0;" width="100%" height="152" frameborder="0" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" title="Spotify Podcast Episode"></iframe>
<p>You can also embed the full show player at a taller height (352px) to show the episode list:</p>
<iframe src="https://open.spotify.com/embed/show/5as3aKmN2k11yfDDDSrvaZ?utm_source=generator" style="border-radius: 12px; margin: 1rem 0;" width="100%" height="352" frameborder="0" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy" title="Spotify Show Player"></iframe>
<h3>Apple Podcasts</h3>
<p>Apple Podcasts uses a similar iframe embed pattern:</p>
<iframe src="https://embed.podcasts.apple.com/us/podcast/syntax-tasty-web-development-treats/id1253186678?itsct=podcast_box_player&#x26;itscg=30200&#x26;ls=1&#x26;theme=auto" height="175px" frameborder="0" sandbox="allow-forms allow-popups allow-same-origin allow-scripts allow-top-navigation-by-user-activation" allow="autoplay *; encrypted-media *; clipboard-write" style="width: 100%; max-width: 660px; overflow: hidden; border-radius: 10px; margin: 1rem 0; display: block;" title="Apple Podcasts — Syntax.fm"></iframe>
<hr>
<h2>Livestream Embeds</h2>
<h3>YouTube Live</h3>
<p>A YouTube Live channel or active live video can be embedded exactly like a regular video. Use the channel's live URL (<code>/live</code>) or a live event ID:</p>
<pre><code class="language-html">&#x3C;!-- Replace CHANNEL_ID with the YouTube channel ID -->
&#x3C;iframe
  src="https://www.youtube.com/embed/live_stream?channel=CHANNEL_ID"
  ...
>&#x3C;/iframe>
</code></pre>
<p>Below is NASA's public live stream:</p>
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; border-radius: 12px; margin: 1.5rem 0;">
  <iframe src="https://www.youtube.com/embed/xAieE-QtOeM?autoplay=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; fullscreen; gyroscope; picture-in-picture" title="NASA TV Live"></iframe>
</div>
<h3>Twitch Stream</h3>
<p>Twitch requires your site's hostname in the <code>parent</code> query parameter (so the embed works in production):</p>
<pre><code class="language-html">&#x3C;!-- Replace CHANNEL_NAME with a Twitch channel, and your-domain.com with your domain -->
&#x3C;iframe
  src="https://player.twitch.tv/?channel=CHANNEL_NAME&#x26;parent=your-domain.com"
  height="378"
  width="100%"
  allow="fullscreen"
  title="Twitch Stream"
>&#x3C;/iframe>
</code></pre>
<p>Twitch also supports embedding past broadcasts (VODs) and clips:</p>
<pre><code class="language-html">&#x3C;!-- VOD -->
&#x3C;iframe src="https://player.twitch.tv/?video=VOD_ID&#x26;parent=your-domain.com" ...>&#x3C;/iframe>
&#x3C;!-- Clip -->
&#x3C;iframe src="https://clips.twitch.tv/embed?clip=CLIP_SLUG&#x26;parent=your-domain.com" ...>&#x3C;/iframe>
</code></pre>
<hr>
<h2>HTML5 Native Media</h2>
<p>Native <code>&#x3C;video></code> and <code>&#x3C;audio></code> elements work without any third-party embeds.</p>
<h3>HTML5 Video</h3>
<p>&#x3C;video
controls
style="width: 100%; border-radius: 12px; margin: 1rem 0; background: #000;"
poster="<a href="https://peach.blender.org/wp-content/uploads/title_anouncement.jpg">https://peach.blender.org/wp-content/uploads/title_anouncement.jpg</a>"</p>
<blockquote>
</blockquote>
  <source src="https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4" type="video/mp4">
  Your browser does not support the HTML5 video element.

<p><em>Elephants Dream (2006) — first open-source animated film by the Blender Foundation.</em></p>
<p>Attributes you can use:</p>

































<table><thead><tr><th align="left">Attribute</th><th align="left">Description</th></tr></thead><tbody><tr><td align="left"><code>controls</code></td><td align="left">Show playback controls</td></tr><tr><td align="left"><code>autoplay</code></td><td align="left">Start playing automatically (use with <code>muted</code>)</td></tr><tr><td align="left"><code>muted</code></td><td align="left">Mute by default (required for autoplay)</td></tr><tr><td align="left"><code>loop</code></td><td align="left">Loop the video</td></tr><tr><td align="left"><code>poster</code></td><td align="left">Preview image shown before play</td></tr><tr><td align="left"><code>preload</code></td><td align="left"><code>auto</code> | <code>metadata</code> | <code>none</code></td></tr></tbody></table>
<h3>HTML5 Audio</h3>
<p>&#x3C;audio
controls
style="width: 100%; margin: 1rem 0;"</p>
<blockquote>
</blockquote>
  <source src="https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3" type="audio/mpeg">
  Your browser does not support the HTML5 audio element.

<p><em>SoundHelix royalty-free sample track.</em></p>
<p>Multiple formats improve cross-browser support:</p>
<pre><code class="language-html">&#x3C;audio controls>
  &#x3C;source src="https://amytis.vercel.app/posts/multimedia-showcase/audio.ogg" type="audio/ogg" />
  &#x3C;source src="https://amytis.vercel.app/posts/multimedia-showcase/audio.mp3" type="audio/mpeg" />
  Your browser does not support the HTML5 audio element.
&#x3C;/audio>
</code></pre>
<hr>
<h2>Audio Platforms</h2>
<h3>SoundCloud</h3>
<p>SoundCloud exposes an iframe embed from any track's "Share → Embed" menu:</p>
<iframe width="100%" height="166" scrolling="no" frameborder="no" allow="autoplay" style="border-radius: 8px; margin: 1rem 0;" src="https://w.soundcloud.com/player/?url=https%3A//api.soundcloud.com/tracks/1&#x26;color=%23ff5500&#x26;auto_play=false&#x26;hide_related=false&#x26;show_comments=true&#x26;show_user=true&#x26;show_reposts=false&#x26;show_teaser=true" title="SoundCloud track"></iframe>
<p>The full visual player (300px height) shows the waveform:</p>
<pre><code class="language-html">&#x3C;iframe
  width="100%"
  height="300"
  src="https://w.soundcloud.com/player/?url=TRACK_URL&#x26;visual=true"
  ...
>&#x3C;/iframe>
</code></pre>
<h3>Bandcamp</h3>
<p>Bandcamp provides both album and track embed codes:</p>
<pre><code class="language-html">&#x3C;!-- Album embed -->
&#x3C;iframe
  style="border: 0; width: 100%; height: 120px;"
  src="https://bandcamp.com/EmbeddedPlayer/album=ALBUM_ID/size=large/bgcol=ffffff/linkcol=0687f5/"
  seamless
>&#x3C;/iframe>
</code></pre>
<hr>
<h2>Embed Best Practices</h2>
<p>When embedding third-party media, keep these in mind:</p>
<ul>
<li><strong>Responsive sizing</strong>: Wrap iframes in a <code>padding-bottom: 56.25%; position: relative</code> container to maintain 16:9 ratio.</li>
<li><strong><code>loading="lazy"</code></strong>: Add this to below-the-fold embeds to defer loading and improve page speed.</li>
<li><strong><code>title</code> attribute</strong>: Always provide a descriptive <code>title</code> for screen reader accessibility.</li>
<li><strong>Privacy-enhanced mode</strong>: YouTube supports <code>youtube-nocookie.com</code> to reduce tracking when embeds don't auto-play.</li>
<li><strong><code>allow</code> over <code>allowfullscreen</code></strong>: Use <code>allow="fullscreen"</code> instead of the deprecated <code>allowfullscreen</code> boolean attribute. Note that bare <code>allow="fullscreen"</code> restricts fullscreen to the iframe's own origin (more secure), whereas the legacy <code>allowfullscreen</code> was equivalent to <code>allow="fullscreen *"</code> (any origin). For third-party embeds like YouTube or Vimeo, <code>allow="fullscreen"</code> is the correct and preferred form. When both attributes are present the browser warns that <code>allow</code> takes precedence.</li>
<li><strong><code>sandbox</code> attribute</strong>: Use for untrusted embeds to restrict what the iframe can do.</li>
<li><strong>Twitch <code>parent</code> parameter</strong>: Twitch requires your site's hostname in <code>parent</code> for embeds to work outside localhost.</li>
</ul>
<pre><code class="language-html">&#x3C;!-- YouTube privacy-enhanced embed -->
&#x3C;iframe
  src="https://www.youtube-nocookie.com/embed/VIDEO_ID?rel=0"
  ...
>&#x3C;/iframe>
</code></pre>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          <category><![CDATA[multimedia]]></category><category><![CDATA[video]]></category><category><![CDATA[audio]]></category><category><![CDATA[podcast]]></category><category><![CDATA[embed]]></category><category><![CDATA[test]]></category>
        </item>
        <item>
          <title><![CDATA[Syntax Highlighting]]></title>
          <link>https://amytis.vercel.app/markdown-showcase/syntax-highlighting/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/markdown-showcase/syntax-highlighting/</guid>
          <pubDate>Sun, 15 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Amytis provides beautiful syntax highlighting for dozens of programming languages. Here are a few examples within the series context. For a comprehensive showca...]]></description>
          <content:encoded><![CDATA[<p>Amytis provides beautiful syntax highlighting for dozens of programming languages. Here are a few examples within the series context.</p>
<blockquote>
<p>For a comprehensive showcase covering 11+ languages, see the standalone <a href="https://amytis.vercel.app/posts/syntax-highlighting-showcase">Syntax Highlighting Showcase</a> post.</p>
</blockquote>
<h2>TypeScript</h2>
<pre><code class="language-typescript">interface Post {
  title: string;
  date: string;
  featured: boolean;
}

function getFeatured(posts: Post[]): Post[] {
  return posts.filter(p => p.featured);
}
</code></pre>
<h2>Python</h2>
<pre><code class="language-python">from pathlib import Path
from dataclasses import dataclass

@dataclass
class Post:
    title: str
    slug: str
    featured: bool = False

    @property
    def url(self) -> str:
        return f"/posts/{self.slug}"

def load_posts(directory: Path) -> list[Post]:
    return [
        Post(title=f.stem.replace("-", " ").title(), slug=f.stem)
        for f in directory.glob("*.md")
    ]
</code></pre>
<h2>Rust</h2>
<pre><code class="language-rust">use std::fs;

struct Post {
    title: String,
    slug: String,
    featured: bool,
}

fn load_posts(dir: &#x26;str) -> Vec&#x3C;Post> {
    fs::read_dir(dir)
        .expect("Failed to read directory")
        .filter_map(|entry| {
            let path = entry.ok()?.path();
            let slug = path.file_stem()?.to_str()?.to_string();
            Some(Post {
                title: slug.replace('-', " "),
                slug,
                featured: false,
            })
        })
        .collect()
}
</code></pre>
<h2>Go</h2>
<pre><code class="language-go">package blog

import (
	"os"
	"path/filepath"
	"strings"
)

type Post struct {
	Title    string
	Slug     string
	Featured bool
}

func LoadPosts(dir string) ([]Post, error) {
	entries, err := os.ReadDir(dir)
	if err != nil {
		return nil, err
	}

	var posts []Post
	for _, e := range entries {
		if filepath.Ext(e.Name()) == ".md" {
			slug := strings.TrimSuffix(e.Name(), ".md")
			posts = append(posts, Post{
				Title: strings.ReplaceAll(slug, "-", " "),
				Slug:  slug,
			})
		}
	}
	return posts, nil
}
</code></pre>
<h2>CSS / Tailwind</h2>
<pre><code class="language-css">.card-base {
  @apply relative overflow-hidden rounded-2xl border border-muted/20 bg-muted/5 p-8 transition-all hover:border-accent/30;
}
</code></pre>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          <category><![CDATA[code]]></category><category><![CDATA[typescript]]></category>
        </item>
        <item>
          <title><![CDATA[Mathematical Notation]]></title>
          <link>https://amytis.vercel.app/markdown-showcase/mathematical-notation/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/markdown-showcase/mathematical-notation/</guid>
          <pubDate>Sat, 14 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Amytis uses rehype-katex to render beautiful mathematical formulas. Inline Math The Pythagorean theorem is $a^2 + b^2 = c^2$. We can also express complex number...]]></description>
          <content:encoded><![CDATA[<p>Amytis uses <code>rehype-katex</code> to render beautiful mathematical formulas.</p>
<h2>Inline Math</h2>
<p>The Pythagorean theorem is $a^2 + b^2 = c^2$. We can also express complex numbers like $e^{i\pi} + 1 = 0$.</p>
<h2>Block Math</h2>
<p>For more complex equations, use block math:</p>
<p>$$
I = \int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
$$</p>
<p>Or Maxwell's equations:</p>
<p>$$
\begin{aligned}
\nabla \cdot \mathbf{E} &#x26;= \frac{\rho}{\varepsilon_0} \
\nabla \cdot \mathbf{B} &#x26;= 0 \
\nabla \times \mathbf{E} &#x26;= -\frac{\partial \mathbf{B}}{\partial t} \
\nabla \times \mathbf{B} &#x26;= \mu_0\left(\mathbf{J} + \varepsilon_0 \frac{\partial \mathbf{E}}{\partial t}\right)
\end{aligned}
$$</p>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          <category><![CDATA[math]]></category><category><![CDATA[latex]]></category>
        </item>
        <item>
          <title><![CDATA[Visuals and Diagrams]]></title>
          <link>https://amytis.vercel.app/markdown-showcase/visuals-and-diagrams/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/markdown-showcase/visuals-and-diagrams/</guid>
          <pubDate>Fri, 13 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Visualizing information is key to understanding. Amytis integrates Mermaid.js for diagrams and handles images with ease. Mermaid Diagrams You can write diagrams...]]></description>
          <content:encoded><![CDATA[<p>Visualizing information is key to understanding. Amytis integrates Mermaid.js for diagrams and handles images with ease.</p>
<h2>Mermaid Diagrams</h2>
<p>You can write diagrams directly in your markdown:</p>
<pre><code class="language-mermaid">graph TD
    A[Idea] --> B{Is it good?}
    B -- Yes --> C[Plant it]
    B -- No --> D[Discard]
    C --> E[Grow]
    E --> F[Evergreen]
</code></pre>
<h2>Images</h2>
<p>Standard markdown images are supported, including relative paths:</p>
<p><img src="https://images.unsplash.com/photo-1466692476868-aef1dfb1e735?auto=format&#x26;fit=crop&#x26;w=1200&#x26;q=80" alt="Digital Garden"></p>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          <category><![CDATA[visuals]]></category><category><![CDATA[mermaid]]></category>
        </item>
        <item>
          <title><![CDATA[System Architecture 101]]></title>
          <link>https://amytis.vercel.app/digital-garden/02-architecture/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/digital-garden/02-architecture/</guid>
          <pubDate>Thu, 12 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Building a robust digital garden requires a flexible architecture. Amytis uses a blend of static generation and dynamic client-side enhancements. The Stack - Ne...]]></description>
          <content:encoded><![CDATA[<p>Building a robust digital garden requires a flexible architecture. Amytis uses a blend of static generation and dynamic client-side enhancements.</p>
<h2>The Stack</h2>
<ul>
<li><strong>Next.js 16</strong>: The backbone of our routing and static generation.</li>
<li><strong>Tailwind CSS v4</strong>: For austere, elegant styling.</li>
<li><strong>Unified/Remark/Rehype</strong>: The engine that transforms MDX into interactive content.</li>
</ul>
<h3>Asset Pipeline</h3>
<p>Our custom <code>copy-assets.ts</code> script ensures that images located next to your markdown files are correctly mapped to the public directory during the build process. This allows for a clean developer experience where images and text live together.</p>]]></content:encoded>
          <dc:creator><![CDATA[Amytis Team]]></dc:creator>
          <category><![CDATA[architecture]]></category><category><![CDATA[nextjs]]></category>
        </item>
        <item>
          <title><![CDATA[Syntax Highlighting Showcase]]></title>
          <link>https://amytis.vercel.app/posts/syntax-highlighting-showcase/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/syntax-highlighting-showcase/</guid>
          <pubDate>Wed, 11 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[A comprehensive test of syntax highlighting across various programming languages.]]></description>
          <content:encoded><![CDATA[<h2>JavaScript</h2>
<pre><code class="language-javascript">async function fetchUserData(userId) {
  const response = await fetch(`/api/users/${userId}`);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }
  const data = await response.json();
  return { ...data, fetchedAt: Date.now() };
}

// Destructuring, template literals, arrow functions
const formatUser = ({ name, email, roles = [] }) =>
  `${name} &#x3C;${email}> [${roles.join(', ')}]`;

class EventEmitter {
  #listeners = new Map();

  on(event, callback) {
    if (!this.#listeners.has(event)) {
      this.#listeners.set(event, []);
    }
    this.#listeners.get(event).push(callback);
    return this;
  }

  emit(event, ...args) {
    for (const cb of this.#listeners.get(event) ?? []) {
      cb(...args);
    }
  }
}
</code></pre>
<h2>TypeScript</h2>
<pre><code class="language-typescript">interface Repository&#x3C;T extends { id: string }> {
  findById(id: string): Promise&#x3C;T | null>;
  findAll(filter?: Partial&#x3C;T>): Promise&#x3C;T[]>;
  create(data: Omit&#x3C;T, 'id'>): Promise&#x3C;T>;
  update(id: string, data: Partial&#x3C;T>): Promise&#x3C;T>;
  delete(id: string): Promise&#x3C;void>;
}

type Result&#x3C;T, E = Error> =
  | { ok: true; value: T }
  | { ok: false; error: E };

async function tryCatch&#x3C;T>(fn: () => Promise&#x3C;T>): Promise&#x3C;Result&#x3C;T>> {
  try {
    return { ok: true, value: await fn() };
  } catch (error) {
    return { ok: false, error: error as Error };
  }
}

// Mapped type with conditional
type ReadonlyDeep&#x3C;T> = {
  readonly [K in keyof T]: T[K] extends object ? ReadonlyDeep&#x3C;T[K]> : T[K];
};
</code></pre>
<h2>Python</h2>
<pre><code class="language-python">from dataclasses import dataclass, field
from typing import Generator
import asyncio

@dataclass
class TreeNode:
    value: int
    left: "TreeNode | None" = None
    right: "TreeNode | None" = None

    def inorder(self) -> Generator[int, None, None]:
        if self.left:
            yield from self.left.inorder()
        yield self.value
        if self.right:
            yield from self.right.inorder()

async def fetch_all(urls: list[str]) -> list[dict]:
    async with aiohttp.ClientSession() as session:
        tasks = [session.get(url) for url in urls]
        responses = await asyncio.gather(*tasks)
        return [await r.json() for r in responses]

# List comprehension with walrus operator
results = [
    cleaned
    for raw in data
    if (cleaned := raw.strip().lower()) and len(cleaned) > 3
]
</code></pre>
<h2>Rust</h2>
<pre><code class="language-rust">use std::collections::HashMap;

#[derive(Debug, Clone)]
struct LRUCache&#x3C;K: Eq + std::hash::Hash + Clone, V: Clone> {
    capacity: usize,
    map: HashMap&#x3C;K, (V, usize)>,
    counter: usize,
}

impl&#x3C;K: Eq + std::hash::Hash + Clone, V: Clone> LRUCache&#x3C;K, V> {
    fn new(capacity: usize) -> Self {
        Self {
            capacity,
            map: HashMap::with_capacity(capacity),
            counter: 0,
        }
    }

    fn get(&#x26;mut self, key: &#x26;K) -> Option&#x3C;&#x26;V> {
        self.counter += 1;
        if let Some(entry) = self.map.get_mut(key) {
            entry.1 = self.counter;
            Some(&#x26;entry.0)
        } else {
            None
        }
    }

    fn put(&#x26;mut self, key: K, value: V) {
        if self.map.len() >= self.capacity &#x26;&#x26; !self.map.contains_key(&#x26;key) {
            let oldest = self.map.iter()
                .min_by_key(|(_, (_, ts))| ts)
                .map(|(k, _)| k.clone());
            if let Some(k) = oldest {
                self.map.remove(&#x26;k);
            }
        }
        self.counter += 1;
        self.map.insert(key, (value, self.counter));
    }
}
</code></pre>
<h2>Go</h2>
<pre><code class="language-go">package main

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type WorkerPool struct {
	workers int
	jobs    chan func() error
	wg      sync.WaitGroup
}

func NewWorkerPool(workers int) *WorkerPool {
	return &#x26;WorkerPool{
		workers: workers,
		jobs:    make(chan func() error, workers*2),
	}
}

func (p *WorkerPool) Start(ctx context.Context) &#x3C;-chan error {
	errs := make(chan error, p.workers)

	for i := 0; i &#x3C; p.workers; i++ {
		p.wg.Add(1)
		go func(id int) {
			defer p.wg.Done()
			for {
				select {
				case &#x3C;-ctx.Done():
					return
				case job, ok := &#x3C;-p.jobs:
					if !ok {
						return
					}
					if err := job(); err != nil {
						errs &#x3C;- fmt.Errorf("worker %d: %w", id, err)
					}
				}
			}
		}(i)
	}

	go func() {
		p.wg.Wait()
		close(errs)
	}()

	return errs
}
</code></pre>
<h2>Java</h2>
<pre><code class="language-java">import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

public sealed interface Either&#x3C;L, R> permits Either.Left, Either.Right {

    record Left&#x3C;L, R>(L value) implements Either&#x3C;L, R> {}
    record Right&#x3C;L, R>(R value) implements Either&#x3C;L, R> {}

    static &#x3C;L, R> Either&#x3C;L, R> left(L value) {
        return new Left&#x3C;>(value);
    }

    static &#x3C;L, R> Either&#x3C;L, R> right(R value) {
        return new Right&#x3C;>(value);
    }

    default &#x3C;T> T fold(Function&#x3C;L, T> onLeft, Function&#x3C;R, T> onRight) {
        return switch (this) {
            case Left&#x3C;L, R> l -> onLeft.apply(l.value());
            case Right&#x3C;L, R> r -> onRight.apply(r.value());
        };
    }

    default &#x3C;T> Either&#x3C;L, T> map(Function&#x3C;R, T> f) {
        return switch (this) {
            case Left&#x3C;L, R> l -> Either.left(l.value());
            case Right&#x3C;L, R> r -> Either.right(f.apply(r.value()));
        };
    }
}
</code></pre>
<h2>C / C++</h2>
<pre><code class="language-c">#include &#x3C;stdio.h>
#include &#x3C;stdlib.h>
#include &#x3C;string.h>

typedef struct Node {
    void *data;
    struct Node *next;
} Node;

typedef struct {
    Node *head;
    size_t size;
    size_t elem_size;
} LinkedList;

LinkedList *list_create(size_t elem_size) {
    LinkedList *list = malloc(sizeof(LinkedList));
    list->head = NULL;
    list->size = 0;
    list->elem_size = elem_size;
    return list;
}

void list_push(LinkedList *list, const void *data) {
    Node *node = malloc(sizeof(Node));
    node->data = malloc(list->elem_size);
    memcpy(node->data, data, list->elem_size);
    node->next = list->head;
    list->head = node;
    list->size++;
}
</code></pre>
<h2>Ruby</h2>
<pre><code class="language-ruby">module Enumerable
  def lazy_map(&#x26;block)
    Enumerator::Lazy.new(self) do |yielder, value|
      yielder &#x3C;&#x3C; block.call(value)
    end
  end
end

class Router
  attr_reader :routes

  def initialize(&#x26;block)
    @routes = []
    instance_eval(&#x26;block) if block_given?
  end

  %i[get post put patch delete].each do |method|
    define_method(method) do |path, **opts, &#x26;handler|
      @routes &#x3C;&#x3C; {
        method: method.upcase,
        pattern: compile_pattern(path),
        handler: handler,
        **opts
      }
    end
  end

  private

  def compile_pattern(path)
    regex = path.gsub(/:(\w+)/) { "(?&#x3C;#{$1}>[^/]+)" }
    Regexp.new("\\A#{regex}\\z")
  end
end
</code></pre>
<h2>SQL</h2>
<pre><code class="language-sql">WITH monthly_revenue AS (
    SELECT
        date_trunc('month', o.created_at) AS month,
        p.category,
        SUM(oi.quantity * oi.unit_price) AS revenue,
        COUNT(DISTINCT o.customer_id) AS unique_customers
    FROM orders o
    JOIN order_items oi ON o.id = oi.order_id
    JOIN products p ON oi.product_id = p.id
    WHERE o.status = 'completed'
        AND o.created_at >= NOW() - INTERVAL '12 months'
    GROUP BY 1, 2
),
ranked AS (
    SELECT *,
        ROW_NUMBER() OVER (
            PARTITION BY month ORDER BY revenue DESC
        ) AS rank,
        LAG(revenue) OVER (
            PARTITION BY category ORDER BY month
        ) AS prev_month_revenue
    FROM monthly_revenue
)
SELECT
    month,
    category,
    revenue,
    unique_customers,
    ROUND(
        (revenue - prev_month_revenue) / NULLIF(prev_month_revenue, 0) * 100,
        2
    ) AS growth_pct
FROM ranked
WHERE rank &#x3C;= 5
ORDER BY month DESC, revenue DESC;
</code></pre>
<h2>Shell / Bash</h2>
<pre><code class="language-bash">#!/usr/bin/env bash
set -euo pipefail

readonly LOG_FILE="/var/log/deploy.log"
readonly LOCK_FILE="/tmp/deploy.lock"

log() {
  local level="$1"; shift
  printf "[%s] [%s] %s\n" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$level" "$*" \
    | tee -a "$LOG_FILE"
}

cleanup() {
  rm -f "$LOCK_FILE"
  log INFO "Lock released"
}
trap cleanup EXIT

deploy() {
  local env="${1:?Environment required}"
  local version="${2:-latest}"

  if [[ -f "$LOCK_FILE" ]]; then
    log ERROR "Deployment already in progress"
    return 1
  fi
  echo $$ > "$LOCK_FILE"

  log INFO "Deploying version=$version to env=$env"

  docker pull "app:${version}" \
    &#x26;&#x26; docker compose -f "docker-compose.${env}.yml" up -d \
    &#x26;&#x26; log INFO "Deployment successful" \
    || { log ERROR "Deployment failed"; return 1; }
}

deploy "$@"
</code></pre>
<h2>HTML / CSS</h2>
<pre><code class="language-html">&#x3C;dialog id="modal" class="backdrop:bg-black/50">
  &#x3C;form method="dialog">
    &#x3C;header>
      &#x3C;h2>Confirm Action&#x3C;/h2>
      &#x3C;button type="submit" value="cancel" aria-label="Close">
        &#x26;times;
      &#x3C;/button>
    &#x3C;/header>
    &#x3C;p>Are you sure you want to proceed?&#x3C;/p>
    &#x3C;footer>
      &#x3C;button type="submit" value="cancel">Cancel&#x3C;/button>
      &#x3C;button type="submit" value="confirm" autofocus>Confirm&#x3C;/button>
    &#x3C;/footer>
  &#x3C;/form>
&#x3C;/dialog>
</code></pre>
<pre><code class="language-css">@layer components {
  .card {
    --card-padding: clamp(1rem, 3vw, 2rem);

    display: grid;
    grid-template-rows: auto 1fr auto;
    padding: var(--card-padding);
    border-radius: 0.75rem;
    background: light-dark(white, oklch(0.25 0.01 260));
    box-shadow: 0 1px 3px oklch(0 0 0 / 0.12);
    transition: box-shadow 0.2s ease;

    &#x26;:hover {
      box-shadow: 0 8px 24px oklch(0 0 0 / 0.15);
    }

    &#x26; > img {
      aspect-ratio: 16 / 9;
      object-fit: cover;
      border-radius: 0.5rem;
    }
  }
}
</code></pre>
<h2>JSON / YAML</h2>
<pre><code class="language-json">{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "strict": true,
    "paths": {
      "@/*": ["./src/*"],
      "@components/*": ["./src/components/*"]
    },
    "plugins": [{ "name": "next" }]
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "exclude": ["node_modules"]
}
</code></pre>
<pre><code class="language-yaml">services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        NODE_ENV: production
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/app
    depends_on:
      db:
        condition: service_healthy
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 30s
      retries: 3

  db:
    image: postgres:16-alpine
    volumes:
      - pgdata:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass

volumes:
  pgdata:
</code></pre>
<h2>Diff</h2>
<pre><code class="language-diff">--- a/src/config.ts
+++ b/src/config.ts
@@ -12,8 +12,10 @@ export const config = {
   pagination: {
     posts: 10,
-    series: 5,
+    series: 12,
   },
+  features: {
+    darkMode: true,
+    search: true,
+  },
 };
</code></pre>
<h2>Inline Code</h2>
<p>Inline code also renders with highlighting: <code>const x: number = 42</code>, a CSS property like <code>background-color: oklch(0.5 0.2 240)</code>, or a shell command <code>git rebase -i HEAD~3</code>.</p>]]></content:encoded>
          <dc:creator><![CDATA[Amytis Team]]></dc:creator>
          <category><![CDATA[test]]></category><category><![CDATA[code]]></category><category><![CDATA[syntax-highlighting]]></category>
        </item>
        <item>
          <title><![CDATA[中文测试文章]]></title>
          <link>https://amytis.vercel.app/markdown-showcase/中文测试文章/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/markdown-showcase/中文测试文章/</guid>
          <pubDate>Mon, 09 Feb 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[这是一篇用于测试中文文件名和内容支持的文章。]]></description>
          <content:encoded><![CDATA[<p>这篇文章用于验证 Amytis 博客系统对中文文件名和内容的支持。</p>
<h2>功能测试</h2>
<h3>中文标签与分类</h3>
<p>本文使用了中文标签（<code>中文</code>、<code>测试</code>、<code>i18n</code>）和中文分类（<code>测试</code>），确保它们在标签页和归档页中正确显示。</p>
<h3>中文内容渲染</h3>
<p>Markdown 渲染引擎应当正确处理中文段落、<strong>粗体</strong>、<em>斜体</em>、以及<code>行内代码</code>等格式。</p>
<blockquote>
<p>这是一段中文引用，用于测试引用块的渲染效果。</p>
</blockquote>
<h3>代码块</h3>
<pre><code class="language-python"># 中文注释测试
def 问候(名字: str) -> str:
    return f"你好，{名字}！欢迎来到 Amytis。"

print(问候("世界"))
</code></pre>
<h3>列表</h3>
<ol>
<li>第一项：验证中文文件名在 URL 中的正确编码</li>
<li>第二项：验证中文标签页的链接跳转</li>
<li>第三项：验证搜索功能对中文内容的支持</li>
</ol>
<ul>
<li>无序列表项一</li>
<li>无序列表项二</li>
<li>无序列表项三</li>
</ul>
<h3>表格</h3>






























<table><thead><tr><th>功能</th><th>状态</th><th>备注</th></tr></thead><tbody><tr><td>中文文件名</td><td>已支持</td><td>URL 自动编码</td></tr><tr><td>中文标签</td><td>已支持</td><td>标签页正常跳转</td></tr><tr><td>中文搜索</td><td>已支持</td><td>Fuse.js 支持</td></tr><tr><td>中文分类</td><td>已支持</td><td>归档页正常显示</td></tr></tbody></table>]]></content:encoded>
          <dc:creator><![CDATA[Amytis]]></dc:creator>
          <category><![CDATA[中文]]></category><category><![CDATA[测试]]></category><category><![CDATA[i18n]]></category>
        </item>
        <item>
          <title><![CDATA[Part 2: Routing Mastery]]></title>
          <link>https://amytis.vercel.app/nextjs-deep-dive/02-routing-mastery/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/nextjs-deep-dive/02-routing-mastery/</guid>
          <pubDate>Sat, 31 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Mastering dynamic routes, parallel routes, and intercepted routes.]]></description>
          <content:encoded><![CDATA[<p>In Next.js 15, <strong>folders are routes</strong> and <strong>files are pages</strong>. This convention-based approach eliminates the need for a separate routing configuration — your project structure <em>is</em> your route map.</p>
<p><img src="https://amytis.vercel.app/nextjs-deep-dive/02-routing-mastery/assets/diagram.svg" alt="Routing Diagram"></p>
<h2>File-Based Routing</h2>
<p>Every folder inside <code>app/</code> becomes a URL segment. A <code>page.tsx</code> file inside that folder makes it publicly accessible:</p>
<pre><code>app/
├── page.tsx            → /
├── about/
│   └── page.tsx        → /about
├── posts/
│   ├── page.tsx        → /posts
│   └── [slug]/
│       └── page.tsx    → /posts/my-first-post
└── series/
    └── [slug]/
        └── page/
            └── [page]/
                └── page.tsx  → /series/my-series/page/2
</code></pre>
<h2>Dynamic Routes</h2>
<p>Square brackets denote dynamic segments. The parameter value is passed to your component:</p>
<pre><code class="language-typescript">// app/posts/[slug]/page.tsx
interface Props {
  params: Promise&#x3C;{ slug: string }>;
}

export default async function PostPage({ params }: Props) {
  const { slug } = await params;
  const post = await getPostBySlug(slug);

  return &#x3C;article>{post.title}&#x3C;/article>;
}

export async function generateStaticParams() {
  const posts = await getAllPosts();
  return posts.map((post) => ({ slug: post.slug }));
}
</code></pre>
<p>The <code>generateStaticParams</code> function tells Next.js which pages to pre-render at build time, enabling fully static output.</p>
<h2>Layouts</h2>
<p>Layouts wrap pages and persist across navigation. They're defined with <code>layout.tsx</code> and receive <code>children</code> as a prop:</p>
<pre><code class="language-typescript">// app/layout.tsx — Root layout (required)
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    &#x3C;html lang="en">
      &#x3C;body>{children}&#x3C;/body>
    &#x3C;/html>
  );
}
</code></pre>
<p>Nested layouts compose naturally. A <code>posts/layout.tsx</code> wraps all post pages without affecting the rest of the site.</p>
<h2>Parallel Routes</h2>
<p>Parallel routes let you render multiple pages in the same layout simultaneously, using named slots:</p>
<pre><code>app/
└── dashboard/
    ├── layout.tsx
    ├── page.tsx
    ├── @analytics/
    │   └── page.tsx
    └── @activity/
        └── page.tsx
</code></pre>
<p>The layout receives each slot as a prop:</p>
<pre><code class="language-typescript">export default function DashboardLayout({
  children,
  analytics,
  activity,
}: {
  children: React.ReactNode;
  analytics: React.ReactNode;
  activity: React.ReactNode;
}) {
  return (
    &#x3C;div className="grid grid-cols-2 gap-4">
      &#x3C;main>{children}&#x3C;/main>
      &#x3C;aside>{analytics}&#x3C;/aside>
      &#x3C;aside>{activity}&#x3C;/aside>
    &#x3C;/div>
  );
}
</code></pre>
<h2>Intercepted Routes</h2>
<p>Intercepted routes display a route within the context of another route — perfect for modals. The <code>(.)</code> convention intercepts a sibling route:</p>
<pre><code>app/
└── posts/
    ├── page.tsx
    ├── [slug]/
    │   └── page.tsx        → Full post page
    └── (.)  [slug]/
        └── page.tsx        → Modal overlay when navigating from /posts
</code></pre>
<p>When a user clicks a post link from the listing page, the intercepted route renders as a modal. If they navigate directly to the URL or refresh, they see the full page.</p>
<p><img src="https://amytis.vercel.app/nextjs-deep-dive/02-routing-mastery/assets/m-p-model.png" alt="m-p-model">
<em>M-P-Model</em></p>
<h2>Summary</h2>
<p>Next.js routing is built on a few simple conventions that scale from a single-page site to a complex application. The file system does the heavy lifting — no router configuration, no route registration, just folders and files.</p>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          
        </item>
        <item>
          <title><![CDATA[Part 1: Getting Started with Next.js 15]]></title>
          <link>https://amytis.vercel.app/nextjs-deep-dive/01-getting-started/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/nextjs-deep-dive/01-getting-started/</guid>
          <pubDate>Fri, 30 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Setting up the environment and understanding the core philosophy.]]></description>
          <content:encoded><![CDATA[<p>Next.js 15 brings powerful new features to the table. In this part, we explore the foundation: the App Router, Bun as a package manager, and static export for deployment.</p>
<h2>Setting Up with Bun</h2>
<p>Bun is a fast JavaScript runtime and package manager that pairs well with Next.js 15. Creating a new project takes a single command:</p>
<pre><code class="language-bash">bunx create-next-app@latest my-app
cd my-app
bun dev
</code></pre>
<p>Bun's install speed is noticeably faster than npm or yarn, and its built-in bundler means fewer dependencies in your toolchain.</p>
<h2>The App Router</h2>
<p>Next.js 15 uses the App Router by default, replacing the legacy Pages Router. The key difference is that <strong>every component is a Server Component</strong> unless you explicitly opt in to client-side rendering with <code>"use client"</code>.</p>
<pre><code class="language-typescript">// app/page.tsx — This is a Server Component by default
export default function HomePage() {
  return (
    &#x3C;main>
      &#x3C;h1>Welcome to Next.js 15&#x3C;/h1>
      &#x3C;p>This component renders on the server.&#x3C;/p>
    &#x3C;/main>
  );
}
</code></pre>
<p>Server Components unlock several benefits:</p>
<ul>
<li><strong>Smaller client bundles</strong> — Server-only code never ships to the browser</li>
<li><strong>Direct data access</strong> — Query databases or read files without an API layer</li>
<li><strong>Streaming</strong> — The server can send HTML progressively as components render</li>
</ul>
<h2>Static Export</h2>
<p>For sites that don't need a running server (blogs, documentation, landing pages), Next.js supports full static export:</p>
<pre><code class="language-typescript">// next.config.ts
const nextConfig = {
  output: 'export',
  images: {
    unoptimized: true,
  },
};

export default nextConfig;
</code></pre>
<p>Running <code>bun run build</code> with this configuration generates a <code>out/</code> directory containing plain HTML, CSS, and JavaScript files. You can deploy this to any static hosting service — GitHub Pages, Netlify, Cloudflare Pages, or an S3 bucket.</p>
<h2>What's Next</h2>
<p>In <a href="https://amytis.vercel.app/series/nextjs-deep-dive">Part 2</a>, we'll explore the file-based routing system in depth: dynamic routes, route groups, layouts, and how Next.js turns your folder structure into a fully-featured application.</p>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          
        </item>
        <item>
          <title><![CDATA[多语言测试并且要测试以下超长的标题看如何处理，如果太长的话要考虑方案: Amytis Digital Garden]]></title>
          <link>https://amytis.vercel.app/posts/multilingual-test-中文长标题/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/multilingual-test-中文长标题/</guid>
          <pubDate>Mon, 26 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[这是一个用于测试多语言支持的文档，包含了中文、英文以及代码块。通过增加更多标题和内容，测试目录的滚动和链接功能。]]></description>
          <content:encoded><![CDATA[<p>这是一个结合了 <strong>中文</strong> 和 <em>English</em> 的测试页面。我们致力于提供最优质的阅读体验。</p>
<h2>核心特性 (Core Features)</h2>
<h3>1. 自动生成目录 (TOC)</h3>
<p>该部分用于测试中文标题是否能正确生成 ID 并在侧边栏中点击跳转。</p>
<h3>2. 代码高亮 (Syntax Highlighting)</h3>
<p>支持多种编程语言的高亮显示。</p>
<pre><code class="language-typescript">// 这是一个 TypeScript 示例
function greet(name: string): string {
  return `你好, ${name}! Welcome to Amytis.`;
}
</code></pre>
<pre><code class="language-rust">// 这是一个 Rust 示例
fn main() {
    println!("你好，世界！");
}
</code></pre>
<h2>深入探讨 (Deep Dive)</h2>
<h3>3. 排版展示 (Typography)</h3>
<p>中文排版需要考虑字符间距和行高。在 Tailwind v4 中，我们通过 <code>prose-emerald</code> 插件来优化视觉效果。</p>
<p>这是一段较长的中文测试文本：
数字花园不仅仅是一个博客，它是一个不断生长的知识库。在这里，每一个节点都可能触发新的思考。我们支持 <strong>加粗</strong>、<em>斜体</em>、<del>删除线</del> 以及 <code>行内代码</code>。</p>
<h3>4. 国际化支持 (I18n)</h3>
<p>Amytis 旨在支持多种语言的无缝切换（虽然目前主要展示中文支持）。对于 CJK 字符，由于没有空格作为天然的分隔符，目录生成逻辑（slugify）需要特别处理。我们现在使用 <code>github-slugger</code> 来确保 ID 生成的一致性。</p>
<h2>复杂图表 (Mermaid)</h2>
<p>测试 Mermaid 图表中的中文标签是否正常显示。</p>
<pre><code class="language-mermaid">flowchart LR
    A[开始] --> B{是否成功?}
    B -- 是 --> C[庆祝]
    B -- 否 --> D[调试代码]
    D --> B
</code></pre>
<h2>技术实现 (Technical Implementation)</h2>
<h3>5. Next.js App Router</h3>
<p>我们利用 Next.js 15 的强力特性，如静态生成 (SSG) 和 服务器组件 (Server Components)。</p>
<h3>6. Tailwind CSS v4</h3>
<p>采用最新的 Tailwind CSS v4，利用其高性能的引擎和更简洁的配置。</p>
<h3>7. 静态站点导出 (Static Export)</h3>
<p>由于我们需要将站点部署在 GitHub Pages 或类似的静态托管服务上，我们使用了 <code>output: 'export'</code>。</p>
<h2>数学公式 (LaTeX)</h2>
<p>支持行内公式 $E=mc^2$ 以及块级公式：</p>
<p>$$
\frac{-b \pm \sqrt{b^2 - 4ac}}{2a}
$$</p>
<h2>更多测试章节 (Extended Sections)</h2>
<h3>8. 列表测试 (Lists)</h3>
<ul>
<li>无序列表项一 (Unordered Item 1)</li>
<li>无序列表项二 (Unordered Item 2)
<ul>
<li>嵌套项 (Nested Item)</li>
<li>嵌套项二 (Nested Item 2)</li>
</ul>
</li>
</ul>
<ol>
<li>有序列表项一 (Ordered Item 1)</li>
<li>有序列表项二 (Ordered Item 2)</li>
</ol>
<h3>9. 引用块 (Blockquotes)</h3>
<blockquote>
<p>这是一个带有作者信息的引用块。数字花园的概念最早由 Mike Caulfield 提出，强调知识的非线性和持续演进。</p>
</blockquote>
<h3>10. 脚注测试</h3>
<p>我们可以为某些词汇添加脚注<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup>。</p>
<h2>未来展望 (Future Roadmap)</h2>
<h3>11. 搜索功能增强</h3>
<p>我们将集成模糊搜索，支持中文分词，提升搜索体验。</p>
<h3>12. 更多主题色</h3>
<p>除了现在的翡翠色 (Emerald)，我们还计划支持琥珀色 (Amber) 和 玫瑰色 (Rose)。</p>
<h2>总结</h2>
<p>多语言支持对于数字花园至关重要。</p>
<blockquote>
<p>"语言的边界就是世界的边界。" — 维特根斯坦</p>
</blockquote>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p>这是一个中文脚注的示例。 <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
          <dc:creator><![CDATA[Amytis Team]]></dc:creator>
          <category><![CDATA[chinese]]></category><category><![CDATA[multilingual]]></category><category><![CDATA[test]]></category>
        </item>
        <item>
          <title><![CDATA[The Kitchen Sink: Comprehensive Feature Test]]></title>
          <link>https://amytis.vercel.app/posts/kitchen-sink/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/kitchen-sink/</guid>
          <pubDate>Wed, 21 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[A complete showcase of all markdown features, code highlighting, diagrams, math, and layout capabilities supported by Amytis.]]></description>
          <content:encoded><![CDATA[<p>This is a paragraph under H1. <strong>Bold text</strong>, <em>italic text</em>, and <del>strikethrough</del>.</p>
<h2>Heading Level 2</h2>
<p>Here is a blockquote:</p>
<blockquote>
<p>"The digital garden is not just a collection of posts, but a web of interconnected thoughts."</p>
<p>— Unknown Gardener</p>
</blockquote>
<h3>Heading Level 3</h3>
<h4>Heading Level 4</h4>
<h5>Heading Level 5</h5>
<h6>Heading Level 6</h6>
<hr>
<h2>Lists</h2>
<h3>Unordered</h3>
<ul>
<li>Item 1</li>
<li>Item 2
<ul>
<li>Nested Item 2.1</li>
<li>Nested Item 2.2</li>
</ul>
</li>
<li>Item 3</li>
</ul>
<h3>Ordered</h3>
<ol>
<li>Step One</li>
<li>Step Two</li>
<li>Step Three</li>
</ol>
<h3>Task List</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" checked disabled> Implement Markdown</li>
<li class="task-list-item"><input type="checkbox" checked disabled> Add Syntax Highlighting</li>
<li class="task-list-item"><input type="checkbox" disabled> Write Documentation</li>
</ul>
<hr>
<h2>Code</h2>
<h3>Inline</h3>
<p>The <code>useState</code> hook is essential. You can install via <code>bun install</code>.</p>
<h3>Code Blocks</h3>
<p><strong>TypeScript:</strong></p>
<pre><code class="language-typescript">interface User {
  id: number;
  name: string;
}

function getUser(id: number): User {
  return { id, name: "Alice" };
}
</code></pre>
<p><strong>Bash:</strong></p>
<pre><code class="language-bash">echo "Hello World" > hello.txt
ls -la
</code></pre>
<p><strong>JSON:</strong></p>
<pre><code class="language-json">{
  "project": "Amytis",
  "version": "1.4.0"
}
</code></pre>
<hr>
<h2>Math (LaTeX)</h2>
<p>Inline math: $E = mc^2$ and $e^{iπ} + 1 = 0$.</p>
<p>Block math:</p>
<p>$$
\frac{1}{\sigma\sqrt{2\pi}} \exp\left( -\frac{1}{2} \left( \frac{x-\mu}{\sigma} \right)^2 \right)
$$</p>
<hr>
<h2>Diagrams (Mermaid)</h2>
<h3>Flowchart</h3>
<pre><code class="language-mermaid">flowchart LR
    A[Start] --> B{Is it working?}
    B -- Yes --> C[Great!]
    B -- No --> D[Debug]
    D --> B
</code></pre>
<h3>Sequence Diagram</h3>
<pre><code class="language-mermaid">sequenceDiagram
    Alice->>John: Hello John, how are you?
    John-->>Alice: Great!
</code></pre>
<hr>
<h2>Images</h2>
<h3>Standard Markdown</h3>
<p><img src="https://amytis.vercel.app/posts/kitchen-sink/assets/test.svg" alt="Test SVG"></p>
<h3>Raw HTML (Quoted)</h3>
<img src="https://amytis.vercel.app/posts/kitchen-sink/assets/test.svg" width="100" alt="Small HTML Image" style="border: 2px solid #ccc; border-radius: 8px;">
<h3>Photos from Public Directory</h3>
<p><img src="https://amytis.vercel.app/images/antelope-canyon.jpg" alt="Antelope Canyon"></p>
<p><img src="https://amytis.vercel.app/images/mountains.jpg" alt="Mountain Landscape"></p>
<p><img src="https://amytis.vercel.app/images/lake.jpg" alt="Lake View"></p>
<p><img src="https://amytis.vercel.app/images/flowers.jpg" alt="Flowers"></p>
<p><img src="https://amytis.vercel.app/images/cappadocia.jpg" alt="Cappadocia"></p>
<p><img src="https://amytis.vercel.app/images/galaxy.jpg" alt="Galaxy"></p>
<h3>Vibrant Waves (JPG format)</h3>
<p><img src="https://amytis.vercel.app/images/vibrant-waves.jpg" alt="Vibrant Waves"></p>
<h3>Side by Side (Raw HTML)</h3>
<div style="display: flex; gap: 1rem; flex-wrap: wrap;">
  <img src="https://amytis.vercel.app/images/antelope-canyon.jpg" alt="Antelope Canyon" style="width: 48%; border-radius: 8px;">
  <img src="https://amytis.vercel.app/images/cappadocia.jpg" alt="Cappadocia" style="width: 48%; border-radius: 8px;">
</div>
<hr>
<h2>Tables</h2>

























<table><thead><tr><th align="left">Feature</th><th align="center">Status</th><th align="left">Notes</th></tr></thead><tbody><tr><td align="left"><strong>GFM</strong></td><td align="center">✅</td><td align="left">Tables supported</td></tr><tr><td align="left"><strong>Math</strong></td><td align="center">✅</td><td align="left">KaTeX integration</td></tr><tr><td align="left"><strong>Mermaid</strong></td><td align="center">✅</td><td align="left">Native rendering</td></tr></tbody></table>
<hr>
<h2>Links</h2>
<ul>
<li><a href="https://amytis.vercel.app/">Internal Link to Home</a></li>
<li><a href="https://google.com">External Link (Google)</a></li>
<li><a href="https://github.com/vercel/next.js">Reference Link</a></li>
</ul>
<hr>
<h2>HTML Components</h2>
<details>
  <summary>Click to expand secret info</summary>
  <div style="padding: 1rem; background: #f0fdf4; border-radius: 0.5rem; color: #166534;">
    This content is inside a raw HTML <code>details</code> tag with inline styles.
  </div>
</details>
<hr>
<h2>Footnotes</h2>
<p>Here is a footnote reference<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup>. And another one<sup><a href="#user-content-fn-note2" id="user-content-fnref-note2" data-footnote-ref="" aria-describedby="footnote-label">2</a></sup>.</p>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p>This is the first footnote text. <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-note2">
<p>This is a second footnote with <strong>bold</strong> text. <a href="#user-content-fnref-note2" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
          <dc:creator><![CDATA[Amytis Team]]></dc:creator>
          <dc:creator><![CDATA[Tester]]></dc:creator>
          <category><![CDATA[features]]></category><category><![CDATA[test]]></category><category><![CDATA[demo]]></category>
        </item>
        <item>
          <title><![CDATA[Markdown Features Test]]></title>
          <link>https://amytis.vercel.app/posts/markdown-features/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/markdown-features/</guid>
          <pubDate>Fri, 16 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Testing tables, task lists, and other GFM features.]]></description>
          <content:encoded><![CDATA[<p>This post tests GitHub Flavored Markdown (GFM) support.</p>
<h2>Tables</h2>

























<table><thead><tr><th align="left">Feature</th><th align="center">Supported</th><th align="left">Notes</th></tr></thead><tbody><tr><td align="left">Tables</td><td align="center">Yes</td><td align="left">Requires remark-gfm</td></tr><tr><td align="left">Task Lists</td><td align="center">Yes</td><td align="left">Checkboxes</td></tr><tr><td align="left">Strikethrough</td><td align="center">Yes</td><td align="left"><del>Deleted</del></td></tr></tbody></table>
<h2>Footnotes</h2>
<p>Here is a simple footnote<sup><a href="#user-content-fn-1" id="user-content-fnref-1" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup>.</p>
<h2>Wide Table Test</h2>
<p>Testing horizontal scrolling for very wide tables with extensive content.</p>
























































<table><thead><tr><th align="left">ID</th><th align="left">Data Column 1</th><th align="left">Data Column 2</th><th align="left">Data Column 3</th><th align="left">Data Column 4</th><th align="left">Data Column 5</th><th align="left">Data Column 6</th><th align="left">Data Column 7</th><th align="left">Data Column 8</th><th align="left">Data Column 9</th><th align="left">Data Column 10</th><th align="left">Data Column 11</th><th align="left">Data Column 12</th><th align="left">Data Column 13</th><th align="left">Data Column 14</th></tr></thead><tbody><tr><td align="left">001</td><td align="left">Extremely long description for testing purposes</td><td align="left">Validating responsive behavior</td><td align="left">Content overflow check</td><td align="left">Column four data</td><td align="left">Column five data</td><td align="left">Column six data</td><td align="left">Column seven data</td><td align="left">Column eight data</td><td align="left">Column nine data</td><td align="left">Column ten data</td><td align="left">Column eleven data</td><td align="left">Column twelve data</td><td align="left">Column thirteen data</td><td align="left">Column fourteen data</td></tr><tr><td align="left">002</td><td align="left">Another long entry to see how it wraps or scrolls</td><td align="left">Consistency verification</td><td align="left">More test data here</td><td align="left">Row two col four</td><td align="left">Row two col five</td><td align="left">Row two col six</td><td align="left">Row two col seven</td><td align="left">Row two col eight</td><td align="left">Row two col nine</td><td align="left">Row two col ten</td><td align="left">Row two col eleven</td><td align="left">Row two col twelve</td><td align="left">Row two col thirteen</td><td align="left">Row two col fourteen</td></tr></tbody></table>
<h2>Links</h2>
<p>Standard inline link: <a href="https://nextjs.org">Next.js Website</a></p>
<p>Reference-style link: <a href="https://github.com/vercel/next.js">Amytis GitHub</a></p>
<p>Autolinks (GFM): <a href="https://google.com">https://google.com</a> and <a href="http://www.github.com">www.github.com</a></p>
<h2>More Reference Links</h2>
<p>Here are some search engines: <a href="https://google.com" title="Google Search">Google</a>, <a href="https://yahoo.com">Yahoo</a>, and <a href="https://bing.com">Bing</a>.</p>
<h2>Footnotes(big)</h2>
<p>And here is a longer one<sup><a href="#user-content-fn-bignote" id="user-content-fnref-bignote" data-footnote-ref="" aria-describedby="footnote-label">2</a></sup>.</p>
<h2>Task List</h2>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" checked disabled> Install remark-gfm</li>
<li class="task-list-item"><input type="checkbox" checked disabled> Configure ReactMarkdown</li>
<li class="task-list-item"><input type="checkbox" disabled> Verify rendering</li>
</ul>
<h2>Strikethrough</h2>
<p>This text is <del>struck through</del>.</p>
<h2>Autolink literals</h2>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-1">
<p>This is the first footnote. <a href="#user-content-fnref-1" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
<li id="user-content-fn-bignote">
<p>Here's one with multiple paragraphs and code.</p>
<p>Indent paragraphs to include them in the footnote.</p>
<p><code>{ code }</code></p>
<p>Add as many paragraphs as you like. <a href="#user-content-fnref-bignote" data-footnote-backref="" aria-label="Back to reference 2" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
          <dc:creator><![CDATA[Tester]]></dc:creator>
          <category><![CDATA[markdown]]></category><category><![CDATA[gfm]]></category>
        </item>
        <item>
          <title><![CDATA[Nested Image Test]]></title>
          <link>https://amytis.vercel.app/posts/nested-image-test/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/nested-image-test/</guid>
          <pubDate>Thu, 15 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Testing nested images in a dedicated 'images' subdirectory.]]></description>
          <content:encoded><![CDATA[<p>This post demonstrates loading an image from an <code>./images/</code> subdirectory.</p>
<p><img src="https://amytis.vercel.app/posts/nested-image-test/images/test.svg" alt="Test Image"></p>
<h2>inline html pic</h2>
<p><strong>测试一下 (Quoted - Recommended):</strong>
<img src="https://amytis.vercel.app/posts/nested-image-test/images/test.svg" width="100" style="display: inline-block;" alt="Quoted Image"></p>
<p><strong>测试一下 (Unquoted - Testing):</strong>
&#x3C;img src=./images/test.svg width="100" style="display: inline-block;" alt="Unquoted Image" /></p>
<p><strong>Simple Unquoted:</strong>
&#x3C;img src=./images/test.svg /></p>
<h3>Note on HTML Attributes</h3>
<p>HTML5 allows omitting quotes for simple values. This should work.</p>]]></content:encoded>
          <dc:creator><![CDATA[Tester]]></dc:creator>
          <category><![CDATA[images]]></category><category><![CDATA[nested]]></category>
        </item>
        <item>
          <title><![CDATA[Legacy Markdown Support]]></title>
          <link>https://amytis.vercel.app/posts/legacy-markdown/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/legacy-markdown/</guid>
          <pubDate>Thu, 15 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Demonstrating support for standard .md files.]]></description>
          <content:encoded><![CDATA[<p>This post is written in a standard <code>.md</code> file, not <code>.mdx</code>.</p>
<h2>Why support both?</h2>
<p>Migration from other systems (Jekyll, Hugo) often involves thousands of <code>.md</code> files. Supporting them natively makes migration easier.</p>
<h2>Footnotes</h2>
<p>Footnote test<sup><a href="#user-content-fn-test" id="user-content-fnref-test" data-footnote-ref="" aria-describedby="footnote-label">1</a></sup>.</p>
<p>One of the main benefits of <code>.md</code> support is seamless migration. If you're moving from Jekyll, Hugo, or another static site generator, your existing posts can be dropped into the <code>content/posts/</code> directory without any changes. Frontmatter fields like <code>title</code>, <code>date</code>, and <code>tags</code> are parsed identically for both formats.</p>
<p>The key difference is that <code>.mdx</code> files allow embedding React components directly in your content, while <code>.md</code> files stick to standard Markdown. For most blog posts, standard Markdown is more than sufficient — and keeping your content in <code>.md</code> means it stays portable across any Markdown-compatible system.</p>
<h3>Code Block Test</h3>
<pre><code class="language-javascript">console.log("Hello from .md file!");
</code></pre>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
<h2>References</h2>
<p>This is a [link to markdown guide][md-guide].</p>
<p>Internal links: <a href="https://amytis.vercel.app/">Home</a> and <a href="https://amytis.vercel.app/archive">Archives</a>.</p>
<h2>More Reference Links</h2>
<p>Reference links test: <a href="https://www.markdownguide.org">Markdown Guide</a>, <a href="https://commonmark.org">CommonMark</a>.</p>
<h3>markdown table</h3>

























<table><thead><tr><th align="left">Feature</th><th align="center">Sum</th><th align="left">Notes</th></tr></thead><tbody><tr><td align="left">Tables</td><td align="center"><code>></code> 10</td><td align="left">Requires remark-gfm</td></tr><tr><td align="left">Task Lists</td><td align="center">5</td><td align="left">Checkboxes</td></tr><tr><td align="left">Strikethrough</td><td align="center">1</td><td align="left"><del>Deleted</del></td></tr></tbody></table>
<section data-footnotes="" class="footnotes"><h2 class="sr-only" id="footnote-label">Footnotes</h2>
<ol>
<li id="user-content-fn-test">
<p>A simple footnote. <a href="#user-content-fnref-test" data-footnote-backref="" aria-label="Back to reference 1" class="data-footnote-backref">↩</a></p>
</li>
</ol>
</section>]]></content:encoded>
          <dc:creator><![CDATA[Old Timer]]></dc:creator>
          <category><![CDATA[markdown]]></category><category><![CDATA[legacy]]></category>
        </item>
        <item>
          <title><![CDATA[Asynchronous JavaScript]]></title>
          <link>https://amytis.vercel.app/posts/asynchronous-javascript/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/asynchronous-javascript/</guid>
          <pubDate>Wed, 14 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Handling asynchronous operations is critical in JavaScript. The Evolution 1. Callbacks (Callback Hell) 2. Promises 3. Async/Await Code Comparison Using Promises...]]></description>
          <content:encoded><![CDATA[<p>Handling asynchronous operations is critical in JavaScript.</p>
<h2>The Evolution</h2>
<ol>
<li>Callbacks (Callback Hell)</li>
<li>Promises</li>
<li>Async/Await</li>
</ol>
<h2>Code Comparison</h2>
<p><strong>Using Promises:</strong></p>
<pre><code class="language-javascript">fetchData()
  .then(data => process(data))
  .catch(err => console.error(err));
</code></pre>
<p><strong>Using Async/Await:</strong></p>
<pre><code class="language-javascript">async function getData() {
  try {
    const data = await fetchData();
    return process(data);
  } catch (err) {
    console.error(err);
  }
}
</code></pre>
<h2>Promise State Machine</h2>
<pre><code class="language-mermaid">stateDiagram-v2
    [*] --> Pending
    Pending --> Fulfilled : resolve()
    Pending --> Rejected : reject()
    Fulfilled --> [*]
    Rejected --> [*]
</code></pre>]]></content:encoded>
          <dc:creator><![CDATA[JS Ninja]]></dc:creator>
          <category><![CDATA[javascript]]></category><category><![CDATA[async]]></category><category><![CDATA[programming]]></category>
        </item>
        <item>
          <title><![CDATA[QuickSort: An Algorithmic Deep Dive]]></title>
          <link>https://amytis.vercel.app/posts/the-art-of-algorithms/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/posts/the-art-of-algorithms/</guid>
          <pubDate>Mon, 12 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Implementing and visualizing the QuickSort algorithm.]]></description>
          <content:encoded><![CDATA[<p>Sorting is a fundamental concept in computer science. Let's look at <strong>QuickSort</strong>.</p>
<h2>Implementation</h2>
<pre><code class="language-typescript">function quickSort(arr: number[]): number[] {
  if (arr.length &#x3C;= 1) {
    return arr;
  }

  const pivot = arr[arr.length - 1];
  const left = [];
  const right = [];

  for (let i = 0; i &#x3C; arr.length - 1; i++) {
    if (arr[i] &#x3C; pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }

  return [...quickSort(left), pivot, ...quickSort(right)];
}
</code></pre>
<h2>Logic Flow</h2>
<pre><code class="language-mermaid">graph TD
    Start([Start]) --> Check{"Length &#x3C;= 1?"}
    Check -- Yes --> Return["Return Array"]
    Check -- No --> Pivot["Choose Pivot"]
    Pivot --> Partition["Partition Array"]
    Partition --> RecurseL["Recurse Left"]
    Partition --> RecurseR["Recurse Right"]
    RecurseL --> Combine["Combine Results"]
    RecurseR --> Combine
    Combine --> End([End])
</code></pre>]]></content:encoded>
          <dc:creator><![CDATA[Algo Master]]></dc:creator>
          <dc:creator><![CDATA[Math Wizard]]></dc:creator>
          <category><![CDATA[algorithms]]></category><category><![CDATA[sorting]]></category><category><![CDATA[typescript]]></category>
        </item>
        <item>
          <title><![CDATA[README Index Post]]></title>
          <link>https://amytis.vercel.app/rst-readme/readme-index-post/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/rst-readme/readme-index-post/</guid>
          <pubDate>Fri, 09 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[Post inside a series whose metadata is loaded from README.rst.]]></description>
          <content:encoded><![CDATA[<p>Content for the README-indexed series.</p>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          <category><![CDATA[rst]]></category><category><![CDATA[readme]]></category>
        </item>
        <item>
          <title><![CDATA[Deeper Notes]]></title>
          <link>https://amytis.vercel.app/rst-legacy/deeper-notes/</link>
          <guid isPermaLink="true">https://amytis.vercel.app/rst-legacy/deeper-notes/</guid>
          <pubDate>Mon, 05 Jan 2026 00:00:00 GMT</pubDate>
          <description><![CDATA[]]></description>
          <content:encoded><![CDATA[<p>This post uses a folder layout.</p>
<h2>Images</h2>
<p>.. image:: ./images/test.svg
:alt: Test image</p>]]></content:encoded>
          <dc:creator><![CDATA[John Hu]]></dc:creator>
          <category><![CDATA[rst]]></category><category><![CDATA[notes]]></category>
        </item>
  </channel>
</rss>