<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Tinkering — mizore / notes</title>
    <link>https://mizore.blog/en/categories/tinkering/</link>
    <link xmlns="http://www.w3.org/2005/Atom" href="https://mizore.blog/en/categories/tinkering/feed.xml" rel="self" type="application/rss+xml"></link>
    <description>3 posts</description>
    <language>en</language>
    <lastBuildDate>Mon, 22 Jun 2026 00:00:00 +0000</lastBuildDate>
    <item>
      <title>New Blog Features: Language Icons, Source Quotes, Tickers, and Charts</title>
      <link>https://mizore.blog/en/posts/blog-git-metadata-and-icons/</link>
      <description>&lt;blockquote&gt;&#xA;&lt;p&gt;This post was written during the old blog (Next.js + MDX) era. After migrating to the current static site, all of these features happen at build time: TradingView widgets became ticker cards that only load the live chart when you click &amp;quot;Live chart&amp;quot;; ECharts blocks became static SVG charts with hover values; source embeds are pinned commit snippets with line numbers; and language icons became corner language labels on code blocks.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;This update pushes the blog&#39;s writing experience another step forward: code blocks are easier to scan, code references link straight to GitHub, and financial posts can embed TradingView charts with a tiny shortcode.&lt;/p&gt;&#xA;&lt;h2 id=&#34;whats-new&#34;&gt;What&#39;s New&lt;/h2&gt;&#xA;&lt;h3 id=&#34;language-icons-on-code-blocks&#34;&gt;Language Icons on Code Blocks&lt;/h3&gt;&#xA;&lt;p&gt;A language logo and copy button float in the top-right corner of every code block—no title bar, no badge border, and no extra vertical space. When a block has a &lt;code&gt;title&lt;/code&gt; or comes from GitHub, a small path line appears above the code and the GitHub link sits tucked into a small icon in the top-right corner.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;feature&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;language icons&amp;#39;&lt;/span&gt;&#xA;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;theme&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;catppuccin&amp;#39;&lt;/span&gt;&#xA;&lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;feature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;theme&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;ts&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;restyled-inline-code&#34;&gt;Restyled Inline Code&lt;/h3&gt;&#xA;&lt;p&gt;Inline code in prose like &lt;code&gt;git log --follow&lt;/code&gt;, &lt;code&gt;$AAPL&lt;/code&gt;, and &lt;code&gt;::tv AAPL&lt;/code&gt; no longer sticks out like a bright patch. In light mode it blends closer to Catppuccin Latte&#39;s paper tone, and in dark mode it settles into a low-luminance Mocha surface.&lt;/p&gt;&#xA;&lt;h3 id=&#34;quoting-github-code-directly&#34;&gt;Quoting GitHub Code Directly&lt;/h3&gt;&#xA;&lt;p&gt;When writing a post, enter:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;::github-code repo=&amp;#34;mizorewww/blog&amp;#34; ref=&amp;#34;c067042276d4b4b384c66c0c61fcd4f6716eb599&amp;#34; path=&amp;#34;contentlayer.config.ts&amp;#34; lines=&amp;#34;251-253&amp;#34; lang=&amp;#34;ts&amp;#34; title=&amp;#34;contentlayer.config.ts&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;md&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;It renders as a code block with Shiki syntax highlighting, a language icon, and a direct link to GitHub:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L251-L253&#34;&gt;L251–253 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;251&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;githubEmbedPattern&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/^::github-(code|diff)\s+(.+)$/&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;252&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tradingViewMiniPattern&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/^\$([A-Za-z0-9._:-]+)$/&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;253&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tradingViewAdvancedPattern&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/^::(?:tv|tv-advanced|tradingview)\s+(.+)$/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;line-by-line-diff-highlighting-like-github&#34;&gt;Line-by-Line Diff Highlighting Like GitHub&lt;/h3&gt;&#xA;&lt;p&gt;When writing a post, enter:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;::github-diff repo=&amp;#34;mizorewww/blog&amp;#34; ref=&amp;#34;c067042276d4b4b384c66c0c61fcd4f6716eb599&amp;#34; path=&amp;#34;css/prism.css&amp;#34; lines=&amp;#34;1-15&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;md&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Rendered output:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/commit/c067042276d4b4b384c66c0c61fcd4f6716eb599&#34;&gt;Changes to &lt;code&gt;css/prism.css&lt;/code&gt; in c067042&lt;/a&gt;&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;gu&#34;&gt;@@ -8,6 +8,44 @@ figure[data-rehype-pretty-code-figure] [data-rehype-pretty-code-title] {&lt;/span&gt;&#xA;   @apply flex items-center justify-between gap-3 border-b border-slate-200 bg-white/70 px-4 py-2 text-xs text-slate-600 dark:border-[#405064] dark:bg-white/[0.035] dark:text-white/65;&#xA; }&#xA; &#xA;&lt;span class=&#34;gi&#34;&gt;+figure[data-rehype-pretty-code-figure] .code-title-main {&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+  @apply inline-flex min-w-0 items-center gap-2;&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+}&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+figure[data-rehype-pretty-code-figure] .code-language-icon {&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+  @apply inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-[5px] border border-slate-300 bg-slate-100 px-1 font-sans text-[0.62rem] leading-none font-semibold text-slate-600 dark:border-white/15 dark:bg-white/10 dark:text-white/70;&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+}&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+figure[data-rehype-pretty-code-figure] .code-language-icon[data-code-language=&amp;#39;ts&amp;#39;],&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+figure[data-rehype-pretty-code-figure] .code-language-icon[data-code-language=&amp;#39;tsx&amp;#39;] {&lt;/span&gt;&#xA;&lt;span class=&#34;gi&#34;&gt;+  @apply border-sky-200 bg-sky-50 text-sky-700 dark:border-sky-400/25 dark:bg-sky-400/10 dark:text-sky-200;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;diff&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;single-line-tickers-become-mini-charts&#34;&gt;Single-Line Tickers Become Mini Charts&lt;/h3&gt;&#xA;&lt;p&gt;Put a ticker on its own line:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;$AAPL&#xA;$BINANCE:BTCUSDT.P&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;md&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;On the old site, each of these lines turned into a Mini Chart. The current static site doesn&#39;t load TradingView scripts upfront—instead, it renders a ticker card linking to TradingView:&lt;/p&gt;&#xA;&lt;div class=&#34;ticker&#34; data-symbol=&#34;NASDAQ:AAPL&#34; data-interval=&#34;&#34; data-height=&#34;&#34;&gt;&lt;span&gt;&lt;b&gt;NASDAQ:AAPL&lt;/b&gt;&lt;span class=&#34;ticker-label&#34;&gt;Apple Inc.&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;ticker-go&#34;&gt;&lt;button type=&#34;button&#34;&gt;Live chart&lt;/button&gt;&lt;a href=&#34;https://www.tradingview.com/symbols/NASDAQ-AAPL/&#34;&gt;TradingView ↗&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&#xA;&lt;div class=&#34;ticker&#34; data-symbol=&#34;BINANCE:BTCUSDT.P&#34; data-interval=&#34;&#34; data-height=&#34;&#34;&gt;&lt;span&gt;&lt;b&gt;BINANCE:BTCUSDT.P&lt;/b&gt;&lt;span class=&#34;ticker-label&#34;&gt;Bitcoin / USDT Perpetual&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;ticker-go&#34;&gt;&lt;button type=&#34;button&#34;&gt;Live chart&lt;/button&gt;&lt;a href=&#34;https://www.tradingview.com/symbols/BINANCE-BTCUSDT.P/&#34;&gt;TradingView ↗&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&#xA;&lt;h3 id=&#34;shortcode-for-advanced-charts&#34;&gt;Shortcode for Advanced Charts&lt;/h3&gt;&#xA;&lt;p&gt;When writing a post, enter:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;::tv AAPL interval=60 height=460&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;md&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;On the old site this rendered an interactive Advanced Chart; here it is likewise a ticker card.&lt;/p&gt;&#xA;&lt;h3 id=&#34;rendering-echarts-directly-from-code-blocks&#34;&gt;Rendering ECharts Directly from Code Blocks&lt;/h3&gt;&#xA;&lt;p&gt;Use an &lt;code&gt;```echarts&lt;/code&gt; code block whose body is the chart&#39;s option JSON, with &lt;code&gt;title&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; supported in the meta string:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;``&lt;span class=&#34;sb&#34;&gt;`echarts title=&amp;#34;Weekly Visits&amp;#34; height=320&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;  &amp;#34;tooltip&amp;#34;: { &amp;#34;trigger&amp;#34;: &amp;#34;axis&amp;#34; },&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;  &amp;#34;xAxis&amp;#34;: {&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;    &amp;#34;type&amp;#34;: &amp;#34;category&amp;#34;,&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;    &amp;#34;data&amp;#34;: [&amp;#34;Mon&amp;#34;, &amp;#34;Tue&amp;#34;, &amp;#34;Wed&amp;#34;, &amp;#34;Thu&amp;#34;, &amp;#34;Fri&amp;#34;, &amp;#34;Sat&amp;#34;, &amp;#34;Sun&amp;#34;]&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;  },&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;  &amp;#34;yAxis&amp;#34;: { &amp;#34;type&amp;#34;: &amp;#34;value&amp;#34; },&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;  &amp;#34;series&amp;#34;: [&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;    {&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;      &amp;#34;name&amp;#34;: &amp;#34;Visits&amp;#34;,&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;      &amp;#34;type&amp;#34;: &amp;#34;line&amp;#34;,&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;      &amp;#34;smooth&amp;#34;: true,&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;      &amp;#34;areaStyle&amp;#34;: {},&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;      &amp;#34;data&amp;#34;: [120, 200, 150, 80, 70, 110, 130]&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;    }&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;  ]&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;``&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;md&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;On the old site these were two ECharts instances. The current site draws the same data as static SVG at build time; since there is no pie chart type, the second example is represented as a &lt;code&gt;data&lt;/code&gt; table:&lt;/p&gt;&#xA;&lt;figure class=&#34;chart&#34;&gt;&lt;figcaption&gt;&lt;span&gt;Weekly Visits&lt;/span&gt;&lt;/figcaption&gt;&lt;div class=&#34;plot&#34; data-tip=&#34;{&amp;#34;x&amp;#34;:[7.83,22.79,37.75,52.71,67.67,82.63,97.59],&amp;#34;l&amp;#34;:[&amp;#34;Mon&amp;#34;,&amp;#34;Tue&amp;#34;,&amp;#34;Wed&amp;#34;,&amp;#34;Thu&amp;#34;,&amp;#34;Fri&amp;#34;,&amp;#34;Sat&amp;#34;,&amp;#34;Sun&amp;#34;],&amp;#34;s&amp;#34;:[{&amp;#34;n&amp;#34;:&amp;#34;Visits&amp;#34;,&amp;#34;c&amp;#34;:&amp;#34;var(--green)&amp;#34;,&amp;#34;v&amp;#34;:[&amp;#34;120&amp;#34;,&amp;#34;200&amp;#34;,&amp;#34;150&amp;#34;,&amp;#34;80&amp;#34;,&amp;#34;70&amp;#34;,&amp;#34;110&amp;#34;,&amp;#34;130&amp;#34;]}]}&#34; style=&#34;--h:274&#34;&gt;&lt;svg viewBox=&#34;0 0 664 274&#34; preserveAspectRatio=&#34;none&#34; role=&#34;img&#34; aria-label=&#34;Weekly Visits&#34;&gt;&lt;path d=&#34;M52 190H648M52 130H648M52 70H648M52 10H648&#34; fill=&#34;none&#34; style=&#34;stroke:var(--grid)&#34; vector-effect=&#34;non-scaling-stroke&#34;/&gt;&lt;path d=&#34;M52 106L151.3 10L250.7 70L350 154L449.3 166L548.7 118L648 94L648 250L52 250Z&#34; fill-opacity=&#34;0.16&#34; style=&#34;fill:var(--green)&#34; vector-effect=&#34;non-scaling-stroke&#34;/&gt;&lt;path d=&#34;M52 106L151.3 10L250.7 70L350 154L449.3 166L548.7 118L648 94&#34; stroke-width=&#34;1.25&#34; fill=&#34;none&#34; stroke-linejoin=&#34;round&#34; style=&#34;stroke:var(--green)&#34; vector-effect=&#34;non-scaling-stroke&#34;/&gt;&lt;path d=&#34;M52 250H648&#34; fill=&#34;none&#34; style=&#34;stroke:var(--faint)&#34; vector-effect=&#34;non-scaling-stroke&#34;/&gt;&lt;/svg&gt;&lt;span class=&#34;yl&#34; style=&#34;left:0.000%;top:91.241%;width:6.627%&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;yl&#34; style=&#34;left:0.000%;top:69.343%;width:6.627%&#34;&gt;50&lt;/span&gt;&lt;span class=&#34;yl&#34; style=&#34;left:0.000%;top:47.445%;width:6.627%&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;yl&#34; style=&#34;left:0.000%;top:25.547%;width:6.627%&#34;&gt;150&lt;/span&gt;&lt;span class=&#34;yl&#34; style=&#34;left:0.000%;top:3.650%;width:6.627%&#34;&gt;200&lt;/span&gt;&lt;span class=&#34;xl&#34; style=&#34;left:22.791%;top:96.350%&#34;&gt;Tue&lt;/span&gt;&lt;span class=&#34;xl&#34; style=&#34;left:52.711%;top:96.350%&#34;&gt;Thu&lt;/span&gt;&lt;span class=&#34;xl&#34; style=&#34;left:82.631%;top:96.350%&#34;&gt;Sat&lt;/span&gt;&lt;span class=&#34;dl&#34; style=&#34;left:22.791%;top:3.650%;transform:translate(6px,-50%);color:var(--ink)&#34;&gt;200 · Tue&lt;/span&gt;&lt;/div&gt;&lt;/figure&gt;&#xA;&lt;figure class=&#34;data&#34;&gt;&lt;figcaption&gt;Posts by Category&lt;/figcaption&gt;&lt;div class=&#34;data-scroll&#34; tabindex=&#34;0&#34;&gt;&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th class=&#34;num&#34;&gt;Posts&lt;/th&gt;&lt;th class=&#34;num&#34;&gt;Share&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Tinkering&lt;/td&gt;&lt;td class=&#34;num&#34;&gt;40&lt;/td&gt;&lt;td class=&#34;num bar&#34; style=&#34;--a:0.0%;--b:100.0%&#34;&gt;40%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Dev&lt;/td&gt;&lt;td class=&#34;num&#34;&gt;32&lt;/td&gt;&lt;td class=&#34;num bar&#34; style=&#34;--a:0.0%;--b:80.0%&#34;&gt;32%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Notes&lt;/td&gt;&lt;td class=&#34;num&#34;&gt;18&lt;/td&gt;&lt;td class=&#34;num bar&#34; style=&#34;--a:0.0%;--b:45.0%&#34;&gt;18%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Other&lt;/td&gt;&lt;td class=&#34;num&#34;&gt;10&lt;/td&gt;&lt;td class=&#34;num bar&#34; style=&#34;--a:0.0%;--b:25.0%&#34;&gt;10%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/figure&gt;&#xA;&lt;p&gt;If the JSON is invalid, it gracefully falls back to a regular code block instead of breaking the build. When you need functions or other options that plain JSON cannot express, you can also pass a JS object directly to the &lt;code&gt;&amp;lt;ECharts&amp;gt;&lt;/code&gt; component. Charts follow the site&#39;s light/dark theme, and the &lt;code&gt;echarts&lt;/code&gt; library is lazy-loaded on demand so it stays out of the initial bundle.&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-it-works-under-the-hood&#34;&gt;How It Works Under the Hood&lt;/h2&gt;&#xA;&lt;h3 id=&#34;turning-shortcodes-into-components-in-remark&#34;&gt;Turning Shortcodes into Components in Remark&lt;/h3&gt;&#xA;&lt;p&gt;These regular expressions match the ticker chart syntax. &lt;code&gt;$AAPL&lt;/code&gt; becomes a Mini Chart and &lt;code&gt;::tv AAPL&lt;/code&gt; becomes an Advanced Chart.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L251-L253&#34;&gt;L251–253 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;251&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;githubEmbedPattern&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/^::github-(code|diff)\s+(.+)$/&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;252&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tradingViewMiniPattern&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/^\$([A-Za-z0-9._:-]+)$/&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;253&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tradingViewAdvancedPattern&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;/^::(?:tv|tv-advanced|tradingview)\s+(.+)$/&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;The Mini Chart transform is intentionally conservative: it only triggers when an entire paragraph consists of a single ticker, so mentioning &lt;code&gt;$AAPL&lt;/code&gt; in the middle of a sentence won&#39;t drop a giant chart into the paragraph.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L288-L295&#34;&gt;L288–295 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;288&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createTradingViewMiniNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;MdastNode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;289&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isTradingViewTicker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;290&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;291&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;292&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;293&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createMdxFlowNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;TradingViewMiniChart&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;294&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;normalizeTradingViewSymbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;295&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Advanced Chart adds parameter parsing so attributes like &lt;code&gt;height=460&lt;/code&gt; and &lt;code&gt;interval=60&lt;/code&gt; are forwarded as JSX props.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L298-L313&#34;&gt;L298–313 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;298&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createTradingViewAdvancedNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;MdastNode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;299&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rawSymbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrParts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;/\s+/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;300&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;301&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rawSymbol&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isTradingViewTicker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rawSymbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;302&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;null&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;303&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;304&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;305&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;parseEmbedAttributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrParts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;join&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;TradingViewAttrs&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;306&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;307&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createMdxFlowNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;TradingViewAdvancedChart&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;308&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;height&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;attrs.height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;309&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;interval&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;attrs.interval&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;310&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;locale&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;attrs.locale&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;311&lt;/span&gt;    &lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;normalizeTradingViewSymbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;rawSymbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;312&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;timezone&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;attrs.timezone&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;313&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Finally, the plugins are wired into Contentlayer&#39;s remark pipeline. Because shortcodes are transformed before MDX compilation, no string scanning happens in the browser.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L1063-L1069&#34;&gt;L1063–1069 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;1063&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;makeSource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;1064&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;contentDirPath&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;1065&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;documentTypes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Blog&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Authors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;1066&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;mdx&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;1067&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;cwd&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;process.cwd&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;1068&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;remarkPlugins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;remarkGfm&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;remarkTradingViewWidgets&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;remarkIconShortcodes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;remarkGitHubEmbeds&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;1069&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;rehypePlugins&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;loading-tradingview-only-on-the-client&#34;&gt;Loading TradingView Only on the Client&lt;/h3&gt;&#xA;&lt;p&gt;The official TradingView widget requires injecting an external &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt;, so the component stays a client component. On render, it clears the container and inserts the widget mount node and config script; whenever the theme or props change, it rebuilds the widget.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;components/TradingViewWidgets.tsx&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/components/TradingViewWidgets.tsx#L83-L101&#34;&gt;L83–101 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;83&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;useEffect&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;84&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;container&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;containerRef&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;current&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;85&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;86&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;87&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;88&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;89&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;90&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;innerHTML&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;lt;div class=&amp;#34;tradingview-widget-container__widget&amp;#34;&amp;gt;&amp;lt;/div&amp;gt;&amp;#39;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;91&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;92&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;script&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;document&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createElement&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;script&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;93&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;94&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;src&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;scriptSrc&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;95&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stringify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;96&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;appendChild&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;script&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;97&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;98&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;99&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;container&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;innerHTML&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;100&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;101&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;scriptSrc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Ticker symbols are normalized first. Bare &lt;code&gt;AAPL&lt;/code&gt; defaults to &lt;code&gt;NASDAQ:AAPL&lt;/code&gt;, while an explicit symbol like &lt;code&gt;NYSE:IBM&lt;/code&gt; is left untouched.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;lib/tradingview.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/lib/tradingview.ts#L4-L20&#34;&gt;L4–20 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;normalizeTradingViewSymbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;defaultExchange&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;NASDAQ&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;5&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;trim&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;/^\$/&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;toUpperCase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;6&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;7&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;8&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;9&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;10&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;11&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;explicitTradingViewSymbolPattern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;12&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;13&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;14&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;15&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;plainTickerPattern&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;16&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;defaultExchange&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;17&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;18&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;19&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;symbol&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;enhancing-code-block-title-bars-in-rehype&#34;&gt;Enhancing Code Block Title Bars in Rehype&lt;/h3&gt;&#xA;&lt;p&gt;Language icons aren&#39;t written by hand in each post; they&#39;re injected across the board during the rehype pass. It locates the &lt;code&gt;figure&lt;/code&gt; generated by Shiki and ensures a title bar exists.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L850-L868&#34;&gt;L850–868 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;850&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;enhanceCodeTitle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;node&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;HastNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;851&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;852&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tagName&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;figure&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;853&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;data-rehype-pretty-code-figure&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;undefined&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;854&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;855&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;856&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;857&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;858&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ensureCodeTitle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;859&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;code&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;findDescendantElement&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;node&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;860&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;sourceUrl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;typeof&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;githubSourceUrl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;string&amp;#39;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;githubSourceUrl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;861&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getCodeLanguage&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;862&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;titleText&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getNodeText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getLanguageName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;863&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;864&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;children&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createCodeTitleNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;titleText&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;865&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;866&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sourceUrl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;867&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;children&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;push&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createCodeSourceLinkNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sourceUrl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;868&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;The left side of the title bar pairs the language icon with the title text. When no explicit title is provided, it falls back to the language display name—such as &lt;code&gt;TypeScript&lt;/code&gt;, &lt;code&gt;Diff&lt;/code&gt;, or &lt;code&gt;Markdown&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L787-L799&#34;&gt;L787–799 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;787&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createCodeTitleNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;titleText&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HastNode&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;788&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;789&lt;/span&gt;    &lt;span class=&#34;kr&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;element&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;790&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;tagName&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;span&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;791&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;className&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;code-title-main&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;792&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;children&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;793&lt;/span&gt;      &lt;span class=&#34;nx&#34;&gt;createCodeLanguageIconNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;794&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;795&lt;/span&gt;        &lt;span class=&#34;kr&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;element&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;796&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;tagName&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;span&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;797&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;properties&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;className&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;code-title-text&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;798&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;children&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;titleText&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getLanguageName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;language&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}],&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;799&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Visually, the logos come straight from &lt;code&gt;simple-icons&lt;/code&gt; brand icons, tree-shaken on demand so they don&#39;t bloat first-load JavaScript; languages without a brand icon fall back to a short text badge.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;css/prism.css&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/css/prism.css#L11-L17&#34;&gt;L11–17 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;11&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;figure&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;data-rehype-pretty-code-figure&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;code-title-main&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;12&lt;/span&gt;  @apply inline-flex min-w-0 items-center gap-2&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;13&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;14&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;15&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;figure&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;data-rehype-pretty-code-figure&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nc&#34;&gt;code-language-icon&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;16&lt;/span&gt;  @apply inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-[5px] border border-slate-300 bg-slate-100 px-1 font-sans text-[0.62rem] leading-none font-semibold text-slate-600 &lt;span class=&#34;n&#34;&gt;dark&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;border&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;white&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dark&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;bg-white&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dark&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;white&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;70&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;keeping-inline-code-from-stealing-attention&#34;&gt;Keeping Inline Code from Stealing Attention&lt;/h3&gt;&#xA;&lt;p&gt;Inline code now uses a low-contrast, subtly bordered token style. It&#39;s still unmistakably code, without popping out of the paragraph like a button.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;css/tailwind.css&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/css/tailwind.css#L110-L124&#34;&gt;L110–124 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;110&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;where&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;not&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;pre&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;code&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;111&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;border&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;solid&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;color-mix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oklab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slate&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;-300&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;72&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;transparent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;112&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;border-radius&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;113&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;background&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;linear-gradient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;114&lt;/span&gt;    &lt;span class=&#34;kc&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;bottom&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;115&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;color-mix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oklab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;white&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;92&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slate&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;-100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;116&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;color-mix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oklab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slate&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;-100&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;88&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;white&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;117&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;118&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;box-shadow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;inset&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;-1&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;px&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;color-mix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;oklab&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;var&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;slate&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;-300&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;45&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;transparent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;119&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;color&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mh&#34;&gt;#4c4f69&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;120&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;padding&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.08&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;rem&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.34&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;rem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;121&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;font-size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;0.86&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;em&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;122&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;font-weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;500&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;123&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;line-height&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;1.75&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;124&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;word-break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;break-word&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;h3 id=&#34;github-code-and-diffs-still-go-through-shiki&#34;&gt;GitHub Code and Diffs Still Go Through Shiki&lt;/h3&gt;&#xA;&lt;p&gt;At build time, &lt;code&gt;::github-code&lt;/code&gt; and &lt;code&gt;::github-diff&lt;/code&gt; fetch the real source file or diff and emit a standard code AST node. That means they don&#39;t need a custom renderer—Shiki highlights them just like any other code block.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L543-L552&#34;&gt;L543–552 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;543&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;kind&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;code&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;544&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;selectCodeLines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getGitHubFile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;545&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;546&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;547&lt;/span&gt;    &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;normalizeGitHubRepo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lines&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;sb&#34;&gt;`#L&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lines&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;548&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;549&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createCodeNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lang&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;text&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;550&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;showLineNumbers&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;551&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;sourceUrl&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;getGitHubCodeUrl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;552&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Diffs follow the exact same path, except the data source is a patch and the language defaults to &lt;code&gt;diff&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;figcaption&gt;&lt;span class=&#34;code-path&#34;&gt;&lt;b&gt;contentlayer.config.ts&lt;/b&gt;&lt;/span&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;a href=&#34;https://github.com/mizorewww/blog/blob/c067042276d4b4b384c66c0c61fcd4f6716eb599/contentlayer.config.ts#L555-L563&#34;&gt;L555–563 · c067042 ↗&lt;/a&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figcaption&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;ln&#34;&gt;555&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;selectCodeLines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getGitHubDiff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lines&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;556&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;557&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;558&lt;/span&gt;  &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;normalizeGitHubRepo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;repo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;path&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;base&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;head&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;559&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;560&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createCodeNode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;No diff matched this query.&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;lang&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;diff&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;561&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;showLineNumbers&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;562&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;sourceUrl&lt;/span&gt;: &lt;span class=&#34;kt&#34;&gt;getGitHubDiffUrl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attrs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt;&#xA;&lt;span class=&#34;ln&#34;&gt;563&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&#xA;&lt;p&gt;That&#39;s why GitHub embeds get the Shiki color theme, language icon, copy button, GitHub link, and diff line backgrounds all at once.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-mental-model-for-writing-posts&#34;&gt;The Mental Model for Writing Posts&lt;/h2&gt;&#xA;&lt;p&gt;For normal posts, you just write Markdown. When you want an icon, write &lt;code&gt;:icon-code:&lt;/code&gt;; for a market ticker, write &lt;code&gt;$AAPL&lt;/code&gt; or &lt;code&gt;::tv AAPL&lt;/code&gt;; for a data chart, write an &lt;code&gt;```echarts&lt;/code&gt; block; to quote source code, write &lt;code&gt;::github-code&lt;/code&gt;; and to quote a commit diff, write &lt;code&gt;::github-diff&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The build step turns these shortcodes into stable MDX components or Shiki code blocks, while the runtime only handles interactivity and external widgets. The authoring syntax stays brief, and the rendered page stays predictable.&lt;/p&gt;&#xA;</description>
      <category>Tinkering</category>
      <pubDate>Mon, 22 Jun 2026 00:00:00 +0000</pubDate>
      <guid>https://mizore.blog/en/posts/blog-git-metadata-and-icons/</guid>
    </item>
    <item>
      <title>Fixing Obsidian Web Clipper Not Working on KDE Plasma Wayland</title>
      <link>https://mizore.blog/en/posts/kde-plasma-obsidian-web-clipper/</link>
      <description>&lt;p&gt;While using Obsidian on Plasma Wayland, I noticed that whenever Obsidian was already open, clicking &lt;strong&gt;Add to Obsidian&lt;/strong&gt; in Chrome&#39;s &lt;strong&gt;Obsidian Web Clipper&lt;/strong&gt; extension created a completely blank note.&lt;/p&gt;&#xA;&lt;p&gt;The content would only show up properly if I closed Obsidian completely before clipping from Web Clipper.&lt;/p&gt;&#xA;&lt;h2 id=&#34;cause&#34;&gt;Cause&lt;/h2&gt;&#xA;&lt;p&gt;This isn&#39;t because Web Clipper failed to capture the page—it&#39;s because KDE prevented the already-running Obsidian instance from properly receiving focus.&lt;/p&gt;&#xA;&lt;p&gt;When Web Clipper hands page content over to Obsidian, Obsidian needs to be raised and focused properly to read the incoming data. Under KDE&#39;s default window management rules, an Obsidian instance running in the background can be blocked from stealing focus, so the clipped content is never written and you end up with an empty note.&lt;/p&gt;&#xA;&lt;h2 id=&#34;analysis&#34;&gt;Analysis&lt;/h2&gt;&#xA;&lt;p&gt;The key symptoms are:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Clipping works normally when Obsidian is closed;&lt;/li&gt;&#xA;&lt;li&gt;Clipping produces an empty note when Obsidian is already open;&lt;/li&gt;&#xA;&lt;li&gt;This means the browser extension itself is working fine;&lt;/li&gt;&#xA;&lt;li&gt;The failure happens when Obsidian is already running and KDE prevents it from responding properly to Web Clipper&#39;s activation request.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;So this is a window focus and activation permission issue in KDE, not a misconfiguration in your Obsidian vault, templates, or Chrome extension.&lt;/p&gt;&#xA;&lt;h2 id=&#34;solution&#34;&gt;Solution&lt;/h2&gt;&#xA;&lt;p&gt;Add a window rule for Obsidian in KDE: open &lt;code&gt;System Settings → Window Management → Window Rules&lt;/code&gt; and configure it as shown below.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://mizore.blog/images/639f87fb1000edf73702913b297ee8295880b29d636cd55533af044ea6b0d2c5.webp&#34; alt=&#34;Obsidian window rule configuration in KDE System Settings&#34; decoding=&#34;async&#34; fetchpriority=&#34;high&#34; width=&#34;1600&#34; height=&#34;1167&#34; srcset=&#34;https://mizore.blog/images/605a9074e4b97eb9a9e494b9842199c8879802dcf3e731bd960c1ecd3a66dc58.webp 720w, https://mizore.blog/images/639f87fb1000edf73702913b297ee8295880b29d636cd55533af044ea6b0d2c5.webp 1600w&#34; sizes=&#34;(max-width: 760px) calc(100vw - 64px), 704px&#34;&gt;&lt;/p&gt;&#xA;</description>
      <category>Tinkering</category>
      <pubDate>Sun, 10 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mizore.blog/en/posts/kde-plasma-obsidian-web-clipper/</guid>
    </item>
    <item>
      <title>Xiaomi Book Pro 14 on Linux</title>
      <link>https://mizore.blog/en/posts/xiaomi-book-pro-14/</link>
      <description>&lt;p&gt;The reason I picked up this Xiaomi Book Pro 14 is quite simple: I already have a MacBook Pro that works great for my daily needs, but there are always things that a Mac either can&#39;t do or does awkwardly. I needed an x86 thin-and-light to handle the tasks that are &amp;quot;best done on x86.&amp;quot;&lt;/p&gt;&#xA;&lt;p&gt;As someone who can&#39;t stand leaving things stock, the first order of business with a new machine was, naturally, installing Arch Linux. I ran into a few pitfalls along the way and thoroughly dug into the fingerprint feature—something I’d never used before. I’m documenting it all here as a record for myself and a reference for anyone who encounters similar issues.&lt;/p&gt;&#xA;&lt;p&gt;First, here are the specs of my unit:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;SoC:&lt;/strong&gt; Intel Ultra X7 358H&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;RAM:&lt;/strong&gt; 32GB LPDDR5x 9600MT/s (Soldered)&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;GPU:&lt;/strong&gt; Intel Arc B390&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://mizore.blog/images/b5d09a616b4aa066b319f1f0025d0b697b73dd46c282c049256b89395a24afb6.webp&#34; alt=&#34;Xiaomi Book Pro 14 running Arch Linux, with fastfetch system information in the terminal&#34; decoding=&#34;async&#34; fetchpriority=&#34;high&#34; width=&#34;1600&#34; height=&#34;1200&#34; srcset=&#34;https://mizore.blog/images/7ca7c73067278d7a82fe9e0e1a8ae3a98b66a535ce28bf1b4b2af3bd29ab5c10.webp 720w, https://mizore.blog/images/b5d09a616b4aa066b319f1f0025d0b697b73dd46c282c049256b89395a24afb6.webp 1600w&#34; sizes=&#34;(max-width: 760px) calc(100vw - 64px), 704px&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;problem-1-screen-artifacts&#34;&gt;Problem 1: Screen Artifacts&lt;/h2&gt;&#xA;&lt;p&gt;Right after the installation, the screen was glitching out. After some digging, the culprit turned out to be Intel&#39;s Panel Self Refresh technology.&lt;/p&gt;&#xA;&lt;p&gt;The fix is straightforward—just add this line to your kernel parameters:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;xe.enable_psr=0&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;h2 id=&#34;problem-2-keyboard-not-recognized&#34;&gt;Problem 2: Keyboard Not Recognized&lt;/h2&gt;&#xA;&lt;p&gt;This one was even weirder: the keyboard worked perfectly in the BIOS and GRUB, but became completely unresponsive as soon as the system booted. Getting stuck here during the installation process is incredibly frustrating.&lt;/p&gt;&#xA;&lt;p&gt;The solution, again, is to add kernel parameters:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;i8042.nopnp=1 i8042.dumbkbd=1&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Once the screen and keyboard were sorted out, the system was basically usable. What follows is the part I spent the most time on—the fingerprint reader.&lt;/p&gt;&#xA;&lt;h2 id=&#34;fingerprint-the-main-event&#34;&gt;Fingerprint: The Main Event&lt;/h2&gt;&#xA;&lt;p&gt;Honestly, I&#39;d never used a device with a fingerprint reader before, so I explored this area quite meticulously and hit many snags. It deserves its own write-up.&lt;/p&gt;&#xA;&lt;h3 id=&#34;why-doesnt-sudo-pop-up-a-fingerprint-gui-like-macos&#34;&gt;Why doesn&#39;t &lt;code&gt;sudo&lt;/code&gt; pop up a fingerprint GUI like macOS?&lt;/h3&gt;&#xA;&lt;p&gt;This was the most irritating part of the whole ordeal. On macOS, &lt;code&gt;sudo&lt;/code&gt; can use Touch ID. Why not on Linux?&lt;/p&gt;&#xA;&lt;p&gt;It&#39;s not that &amp;quot;no one thought of it&amp;quot;; it&#39;s that the architectures are fundamentally different.&lt;/p&gt;&#xA;&lt;p&gt;The authentication chain for &lt;code&gt;sudo&lt;/code&gt; looks like this:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;sudo → PAM → Terminal session or askpass&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;The beautiful KDE fingerprint authentication dialog, on the other hand, follows a different path:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;App → Polkit → KDE Polkit Agent → PAM → fprintd&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;That GUI is provided by the Polkit agent. It doesn&#39;t spring forth from PAM itself, nor is it part of &lt;code&gt;sudo&lt;/code&gt;. The PAM module can only participate in the authentication flow; it can&#39;t magically transform a terminal-based &lt;code&gt;sudo&lt;/code&gt; prompt into a KDE-style identity verification pop-up.&lt;/p&gt;&#xA;&lt;p&gt;Using &lt;code&gt;sudo -A&lt;/code&gt; with &lt;code&gt;SUDO_ASKPASS&lt;/code&gt; can indeed pop up a graphical password box, but that&#39;s still on &lt;code&gt;sudo&lt;/code&gt;&#39;s own askpass track, which is separate from the KDE Polkit agent. So, at best, it makes the &amp;quot;enter password&amp;quot; step a GUI, but it can&#39;t bring over the fingerprint experience.&lt;/p&gt;&#xA;&lt;p&gt;macOS can do it because Apple integrated &lt;code&gt;sudo&lt;/code&gt;, PAM, Touch ID, the Secure Enclave, and LocalAuthentication at the system level right from the start. On Linux, these components belong to different projects and thus have no natural path to a unified experience.&lt;/p&gt;&#xA;&lt;h3 id=&#34;a-key-limitation-of-pam_fprintd-the-pam-stack-is-serial&#34;&gt;A Key Limitation of &lt;code&gt;pam_fprintd&lt;/code&gt;: The PAM Stack is Serial&lt;/h3&gt;&#xA;&lt;p&gt;There&#39;s another fundamental limitation with &lt;code&gt;pam_fprintd&lt;/code&gt;: in a standard PAM stack, it and password authentication execute in series.&lt;/p&gt;&#xA;&lt;p&gt;My initial ideal experience was something like this:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;For a single sudo prompt, it would simultaneously wait for my password and my fingerprint, using whichever was provided first.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;But in reality, this isn&#39;t possible. A login manager can use more complex methods to fire up multiple PAM sessions to simulate concurrency, but a regular &lt;code&gt;sudo&lt;/code&gt; won&#39;t do that.&lt;/p&gt;&#xA;&lt;p&gt;So, the real-world choices are limited to the following experiences:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Option A:&lt;/strong&gt; Fingerprint first, fallback to password on failure.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Option B:&lt;/strong&gt; Password first, fallback to fingerprint if you press Enter with an empty field.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Option C:&lt;/strong&gt; Only use the Polkit GUI, don&#39;t force fingerprint on sudo.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Option D:&lt;/strong&gt; Use a third-party hack module (not recommended—don&#39;t mess around with root authentication).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I eventually settled on Option B, but I tried Option A first. Let me explain why it flopped.&lt;/p&gt;&#xA;&lt;h3 id=&#34;option-a-fingerprint-first-fallback-to-password-post-mortem&#34;&gt;Option A: Fingerprint First, Fallback to Password (Post-Mortem)&lt;/h3&gt;&#xA;&lt;p&gt;My initial, intuitive configuration was this, in &lt;code&gt;/etc/pam.d/sudo&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;#%PAM-1.0&#xA;&#xA;auth        sufficient  pam_fprintd.so max-tries=3 timeout=8&#xA;auth        include     system-auth&#xA;account     include     system-auth&#xA;session     include     system-auth&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Logically, this looks fine: try the fingerprint first. If it succeeds, great; if not, it&#39;ll ask for a password.&lt;/p&gt;&#xA;&lt;p&gt;But in practice, it broke. I deliberately let the fingerprint recognition fail, then typed the correct password, but &lt;code&gt;sudo&lt;/code&gt; still would not let me through. The logs showed entries like this:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;pam_unix(sudo:auth): conversation failed&#xA;pam_unix(sudo:auth): auth could not identify password for [...]&#xA;pam_faillock(sudo:auth): Consecutive login failures ... account temporarily locked&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Meanwhile, &lt;code&gt;fprintd&lt;/code&gt; was also complaining:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;Device was already claimed&#xA;Verification was in progress, stopping it&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;It seems the interaction between &lt;code&gt;sudo&lt;/code&gt;, the terminal PAM conversation, &lt;code&gt;pam_fprintd&lt;/code&gt;, and the subsequent password stack gets into a messy state. After the fingerprint failed, the password fallback didn&#39;t take over cleanly, and it also increased the &lt;code&gt;faillock&lt;/code&gt; failure count, temporarily locking my account.&lt;/p&gt;&#xA;&lt;p&gt;The biggest danger with this kind of problem is that you&#39;re modifying the root privilege escalation entry point. If you bork &lt;code&gt;/etc/pam.d/sudo&lt;/code&gt; and don&#39;t have another root channel, it&#39;s easy to lock yourself out.&lt;/p&gt;&#xA;&lt;p&gt;My recovery method at that time was using a still-functional Polkit:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;pkexec sh -c &lt;span class=&#34;s1&#34;&gt;&amp;#39;cat &amp;gt; /etc/pam.d/sudo &amp;lt;&amp;lt;EOF&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;#%PAM-1.0&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;auth        include     system-auth&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;account     include     system-auth&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;session     include     system-auth&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;EOF&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;faillock --user username --reset&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;systemctl restart fprintd&lt;/span&gt;&#xA;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;bash&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;I suggest keeping this rollback method in mind: first, revert sudo to Arch&#39;s default password-only path, then clear &lt;code&gt;faillock&lt;/code&gt;, and finally restart &lt;code&gt;fprintd&lt;/code&gt; to release any lingering device claims. It&#39;s a lifesaver in critical moments.&lt;/p&gt;&#xA;&lt;h3 id=&#34;option-b-password-first-empty-enter-for-fingerprint-my-current-setup&#34;&gt;Option B: Password First, Empty Enter for Fingerprint (My Current Setup)&lt;/h3&gt;&#xA;&lt;p&gt;I later switched to a different approach: the system presents a normal sudo password prompt, but if you just press Enter (submitting an empty password), it falls back to fingerprint verification.&lt;/p&gt;&#xA;&lt;p&gt;My current configuration in &lt;code&gt;/etc/pam.d/sudo&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;#%PAM-1.0&#xA;&#xA;# Prompt for password first; an empty password triggers a fingerprint attempt&#xA;auth        sufficient  pam_unix.so try_first_pass likeauth nullok&#xA;&#xA;# Prevent fingerprint prompts in non-tty background sudo processes&#xA;auth        [success=1 default=ignore] pam_succeed_if.so service in sudo:su:su-l tty in :unknown&#xA;-auth       sufficient  pam_fprintd.so max-tries=3 timeout=8&#xA;&#xA;# Arch&amp;#39;s default fallback&#xA;auth        include     system-auth&#xA;account     include     system-auth&#xA;session     include     system-auth&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;The interactive flow goes like this:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;[sudo] password for user:&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;If you want to enter a password, just type it. If you want to use your fingerprint, press Enter on an empty field, and it will switch to:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;Place your right index finger on the fingerprint reader&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;This approach feels more intuitive in the terminal than &amp;quot;fingerprint first,&amp;quot; but it has its own little quirks.&lt;/p&gt;&#xA;&lt;h3 id=&#34;the-catch-with-option-b-empty-enter-can-leave-a-failure-record&#34;&gt;The Catch with Option B: Empty Enter Can Leave a Failure Record&lt;/h3&gt;&#xA;&lt;p&gt;That &amp;quot;empty Enter&amp;quot; step inherently goes through &lt;code&gt;pam_unix.so&lt;/code&gt; first. From &lt;code&gt;pam_unix&lt;/code&gt;&#39;s perspective, an empty string is not a correct password, so it registers an authentication failure before the PAM flow moves on to &lt;code&gt;pam_fprintd&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;When you check &lt;code&gt;faillock&lt;/code&gt;, you might see a record like this:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;user:&#xA;When                Type  Source       Valid&#xA;2026-05-08 ...      TTY   /dev/pts/1   V&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;This means that even if the subsequent fingerprint authentication is successful, that initial empty Enter step might still be logged as a failed attempt.&lt;/p&gt;&#xA;&lt;p&gt;So, if you go with this option, keep a few things in mind:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Don&#39;t set &lt;code&gt;faillock&lt;/code&gt;&#39;s failure threshold too low.&lt;/li&gt;&#xA;&lt;li&gt;Always leave a working root backdoor while debugging PAM, like a currently functional &lt;code&gt;pkexec&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;After consecutive failures, remember to check:&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;faillock --user &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$USER&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;bash&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;And manually reset it if necessary:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;faillock --user &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$USER&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; --reset&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;bash&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;Also, a side note: if you want the most stable graphical privilege escalation experience, it&#39;s best to just prefer Polkit for daily use and not force everything through &lt;code&gt;sudo&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h3 id=&#34;kwallet-why-you-cant-unlock-it-with-a-fingerprint&#34;&gt;KWallet: Why You Can&#39;t Unlock It with a Fingerprint&lt;/h3&gt;&#xA;&lt;p&gt;This is another common point of confusion.&lt;/p&gt;&#xA;&lt;p&gt;The role of &lt;code&gt;kwallet-pam&lt;/code&gt; is, when you log in with your password, to pass that login password to KWallet, allowing the wallet to be automatically unlocked with the same credentials.&lt;/p&gt;&#xA;&lt;p&gt;There&#39;s a line in the logs that says it all:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;pam_kwallet5(plasmalogin-autologin:auth): Empty or missing password, doing nothing&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;This line makes the problem crystal clear: an automatic or fingerprint-based login does not provide the plaintext &amp;quot;user password,&amp;quot; so KWallet doesn&#39;t get the key it needs.&lt;/p&gt;&#xA;&lt;p&gt;A fingerprint authentication only answers one question:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;Is this person who they claim to be?&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;KWallet&#39;s decryption requires an answer to a different question:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;What is the key or password used to open the wallet?&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;p&gt;The fingerprint device won&#39;t spit out your login password; it only tells the system if the authentication was successful. Therefore, KWallet has no way to decrypt using a fingerprint alone.&lt;/p&gt;&#xA;&lt;p&gt;There are a few ways to handle this:&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Disable automatic login, log in with your password, and keep your KWallet password synchronized with your login password.&lt;/li&gt;&#xA;&lt;li&gt;Accept reality and manually enter your KWallet password once after reaching the desktop.&lt;/li&gt;&#xA;&lt;li&gt;Reduce wallet security, for instance, by using a wallet with an empty password—but this is absolutely not recommended, especially if you&#39;re storing important keys.&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;So, this isn&#39;t a case of KDE failing to connect things; it&#39;s that &amp;quot;authentication&amp;quot; and &amp;quot;decryption&amp;quot; are fundamentally two different things.&lt;/p&gt;&#xA;&lt;h3 id=&#34;fprintd-device-contention-issues&#34;&gt;&lt;code&gt;fprintd&lt;/code&gt; Device Contention Issues&lt;/h3&gt;&#xA;&lt;p&gt;During my tinkering, I also encountered this error:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;Device was already claimed&#xA;Verification was in progress, stopping it&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;This usually means a previous verification didn&#39;t terminate cleanly, or several authentication requests are simultaneously trying to claim the same fingerprint device.&lt;/p&gt;&#xA;&lt;p&gt;The fix is simple:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;systemctl restart fprintd&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;bash&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;If you lack sufficient user permissions, use your confirmed-working Polkit backdoor:&lt;/p&gt;&#xA;&lt;figure class=&#34;code&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;pkexec systemctl restart fprintd&lt;/code&gt;&lt;/pre&gt;&lt;span class=&#34;code-tools&#34;&gt;&lt;span class=&#34;lang&#34;&gt;bash&lt;/span&gt;&lt;button class=&#34;copy&#34; type=&#34;button&#34;&gt;copy&lt;/button&gt;&lt;/span&gt;&lt;/figure&gt;&#xA;&lt;p&gt;This is also why I don&#39;t recommend configuring too many authentication entry points to automatically grab the fingerprint reader. The device can serve only one verification request at a time. When multiple PAM or Polkit requests compete for it, the resulting experience becomes incredibly erratic.&lt;/p&gt;&#xA;&lt;h2 id=&#34;final-state-summary&#34;&gt;Final State Summary&lt;/h2&gt;&#xA;&lt;p&gt;After all that tinkering, here&#39;s the current fingerprint and authentication configuration for this machine:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;fprintd:&lt;/strong&gt; Correctly identifies the Goodix device. I have enrolled my right index finger.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;KDE User Settings:&lt;/strong&gt; Fingerprint can be managed through &lt;code&gt;kcm_users&lt;/code&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Polkit:&lt;/strong&gt; Prioritizes fingerprint, falls back to password on failure.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;kio-admin:&lt;/strong&gt; Installed, allowing graphical root file operations via the &lt;code&gt;admin://&lt;/code&gt; protocol.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;sudo:&lt;/strong&gt; Asks for password first; pressing Enter on empty triggers a fingerprint attempt (max 3 tries).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Plasma Login Manager:&lt;/strong&gt; PAM is configured for fingerprint, but auto-login bypasses it.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;KWallet:&lt;/strong&gt; Cannot be unlocked with a fingerprint alone.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;&#xA;&lt;p&gt;The Linux compatibility of this Xiaomi Book Pro 14 is far better than I imagined. The few issues I faced all had clear causes and solutions, and in general, it&#39;s been a very smooth experience.&lt;/p&gt;&#xA;&lt;p&gt;Another feeling I have is that tinkering with systems is much faster than it used to be. In the past, I&#39;d have to dig through piles of ArchWiki entries and man pages for a problem. Now, you can just ask ChatGPT &amp;quot;how to fix xxx,&amp;quot; and the efficiency is on a whole different level. This time, I even used OpenAI Codex, making the overall debugging process smoother by orders of magnitude.&lt;/p&gt;&#xA;</description>
      <category>Tinkering</category>
      <pubDate>Sun, 10 May 2026 00:00:00 +0000</pubDate>
      <guid>https://mizore.blog/en/%E6%8A%98%E8%85%BE/xiaomi-book-pro-14/</guid>
    </item>
  </channel>
</rss>