[{"data":1,"prerenderedAt":1142},["ShallowReactive",2],{"post-\u002Fposts\u002Fhow-i-ported-astropaper-to-nuxt-content-with-fable-5":3,"all-posts":1132},{"id":4,"title":5,"author":6,"body":7,"canonicalURL":1117,"description":1118,"draft":1119,"extension":1120,"featured":866,"hideEditPost":1119,"meta":1121,"modDatetime":1117,"navigation":866,"ogImage":1117,"path":1122,"pubDatetime":1123,"seo":1124,"stem":1125,"tags":1126,"timezone":1117,"__hash__":1131},"posts\u002Fposts\u002Fhow-i-ported-astropaper-to-nuxt-content-with-fable-5.md","How I Ported AstroPaper to Nuxt Content with Fable 5","Alexander Opalic",{"type":8,"value":9,"toc":1102},"minimark",[10,35,40,119,122,130,157,176,179,296,314,479,482,485,527,545,548,555,595,598,601,648,652,667,722,728,731,770,927,930,953,1037,1047,1050,1053,1070,1073,1093,1096,1099],[11,12,13,14,21,22,26,27,30,31,34],"p",{},"This entire blog is a port of ",[15,16,20],"a",{"href":17,"rel":18},"https:\u002F\u002Fgithub.com\u002Fsatnaing\u002Fastro-paper",[19],"nofollow","AstroPaper"," — Sat Naing's minimal, accessible Astro blog theme — rebuilt on ",[23,24,25],"strong",{},"Nuxt 4"," and ",[23,28,29],{},"Nuxt Content v3",". The port was done in a single session by Claude Code running ",[23,32,33],{},"Fable 5",", and this post documents exactly how it went: the plan, the architecture mapping, and the gotchas that only showed up once a real browser looked at the result.",[36,37,39],"h2",{"id":38},"table-of-contents","Table of contents",[41,42,43,47],"details",{},[44,45,46],"summary",{},"Open Table of contents",[48,49,50,57,63,69,75,101,107,113],"ul",{},[51,52,53],"li",{},[15,54,56],{"href":55},"#the-starting-point","The starting point",[51,58,59],{},[15,60,62],{"href":61},"#mapping-astro-concepts-to-nuxt","Mapping Astro concepts to Nuxt",[51,64,65],{},[15,66,68],{"href":67},"#porting-the-design","Porting the design",[51,70,71],{},[15,72,74],{"href":73},"#migrating-the-content","Migrating the content",[51,76,77,81],{},[15,78,80],{"href":79},"#the-gotchas","The gotchas",[48,82,83,89,95],{},[51,84,85],{},[15,86,88],{"href":87},"#1-pnpm-blocks-native-build-scripts","1. pnpm blocks native build scripts",[51,90,91],{},[15,92,94],{"href":93},"#2-shiki-tokens-are-class-based-not-inline","2. Shiki tokens are class-based, not inline",[51,96,97],{},[15,98,100],{"href":99},"#3-mdc-eats-callout-markers","3. MDC eats callout markers",[51,102,103],{},[15,104,106],{"href":105},"#verification","Verification",[51,108,109],{},[15,110,112],{"href":111},"#what-was-deliberately-left-out","What was deliberately left out",[51,114,115],{},[15,116,118],{"href":117},"#takeaway","Takeaway",[36,120,56],{"id":121},"the-starting-point",[11,123,124,125,129],{},"The prompt was simple: ",[126,127,128],"em",{},"\"create a port of astro-paper, clone this to tmp, but use Nuxt 4 and Nuxt Content.\""," The agent's first moves:",[131,132,133,143,150],"ol",{},[51,134,135,139,140],{},[136,137,138],"code",{},"git clone --depth 1"," AstroPaper into ",[136,141,142],{},"\u002Ftmp\u002Fastro-paper",[51,144,145,146,149],{},"Read the Nuxt and Nuxt Content ",[136,147,148],{},"llms.txt"," docs to confirm current APIs",[51,151,152,153,156],{},"Read ",[23,154,155],{},"every"," source file of the theme — config, layouts, components, pages, utils, and all three CSS files — before writing a single line",[11,158,159,160,163,164,167,168,171,172,175],{},"That last step mattered. AstroPaper v6 has subtle behavior baked in: frontmatter ",[136,161,162],{},"slug"," overrides file names, underscore-prefixed directories are stripped from URLs (the release posts live in ",[136,165,166],{},"_releases\u002F"," but appear at ",[136,169,170],{},"\u002Fposts\u002Fastro-paper-v6","), and scheduled posts get a 15-minute publish margin. Skipping the reading phase would have produced a port that ",[126,173,174],{},"looked"," right and behaved wrong.",[36,177,62],{"id":178},"mapping-astro-concepts-to-nuxt",[180,181,182,195],"table",{},[183,184,185],"thead",{},[186,187,188,192],"tr",{},[189,190,191],"th",{},"AstroPaper (Astro 6)",[189,193,194],{},"NuxtPaper (Nuxt 4)",[196,197,198,213,229,240,251,262,281],"tbody",{},[186,199,200,204],{},[201,202,203],"td",{},"Content collections + glob loader",[201,205,206,209,210],{},[136,207,208],{},"@nuxt\u002Fcontent"," collections in ",[136,211,212],{},"content.config.ts",[186,214,215,220],{},[201,216,217],{},[136,218,219],{},"getCollection(\"posts\")",[201,221,222,225,226],{},[136,223,224],{},"queryCollection(\"posts\")"," + ",[136,227,228],{},"useAsyncData",[186,230,231,237],{},[201,232,233,236],{},[136,234,235],{},".astro"," components",[201,238,239],{},"Vue SFCs with auto-import",[186,241,242,248],{},[201,243,244,247],{},[136,245,246],{},"getStaticPaths"," pagination",[201,249,250],{},"One catch-all route deciding list vs. detail",[186,252,253,256],{},[201,254,255],{},"Pagefind search",[201,257,258,259],{},"MiniSearch + ",[136,260,261],{},"queryCollectionSearchSections",[186,263,264,270],{},[201,265,266,269],{},[136,267,268],{},"@astrojs\u002Frss"," \u002F sitemap",[201,271,272,273,276,277,280],{},"Nitro server routes (",[136,274,275],{},"\u002Frss.xml",", ",[136,278,279],{},"\u002Fsitemap.xml",")",[186,282,283,286],{},[201,284,285],{},"Inline theme script in Layout",[201,287,288,291,292,295],{},[136,289,290],{},"app.head.script"," + a ",[136,293,294],{},"useTheme"," composable",[11,297,298,299,302,303,306,307,309,310,313],{},"The trickiest routing decision: Astro disambiguates ",[136,300,301],{},"\u002Fposts\u002F2"," (pagination) from ",[136,304,305],{},"\u002Fposts\u002Fmy-post"," (detail) at build time via ",[136,308,246],{},". Nuxt routes dynamically, so the port uses a single ",[136,311,312],{},"pages\u002Fposts\u002F[...slug].vue"," catch-all — an empty or numeric segment renders the paginated list, anything else renders the post.",[315,316,321],"pre",{"className":317,"code":318,"language":319,"meta":320,"style":320},"language-ts shiki shiki-themes min-light night-owl","\u002F\u002F pages\u002Fposts\u002F[...slug].vue\nconst isList = computed(\n  () =>\n    segments.value.length === 0 ||\n    (segments.value.length === 1 && \u002F^\\d+$\u002F.test(segments.value[0]!))\n);\n","ts","",[136,322,323,332,354,364,395,473],{"__ignoreMap":320},[324,325,328],"span",{"class":326,"line":327},"line",1,[324,329,331],{"class":330},"sEmqk","\u002F\u002F pages\u002Fposts\u002F[...slug].vue\n",[324,333,335,339,343,346,350],{"class":326,"line":334},2,[324,336,338],{"class":337},"sj-IK","const",[324,340,342],{"class":341},"sVwY6"," isList",[324,344,345],{"class":337}," =",[324,347,349],{"class":348},"sCRLn"," computed",[324,351,353],{"class":352},"styZ9","(\n",[324,355,357,361],{"class":326,"line":356},3,[324,358,360],{"class":359},"swRlg","  ()",[324,362,363],{"class":337}," =>\n",[324,365,367,371,375,379,381,385,388,392],{"class":326,"line":366},4,[324,368,370],{"class":369},"s120W","    segments",[324,372,374],{"class":373},"sdI2O",".",[324,376,378],{"class":377},"sWAzl","value",[324,380,374],{"class":373},[324,382,384],{"class":383},"s_WS7","length",[324,386,387],{"class":337}," ===",[324,389,391],{"class":390},"sC5Uh"," 0",[324,393,394],{"class":337}," ||\n",[324,396,398,401,404,406,408,410,412,414,417,420,424,428,432,436,439,442,445,448,451,453,455,458,461,464,467,470],{"class":326,"line":397},5,[324,399,400],{"class":352},"    (",[324,402,403],{"class":369},"segments",[324,405,374],{"class":373},[324,407,378],{"class":377},[324,409,374],{"class":373},[324,411,384],{"class":383},[324,413,387],{"class":337},[324,415,416],{"class":390}," 1",[324,418,419],{"class":337}," &&",[324,421,423],{"class":422},"sIKrn"," \u002F",[324,425,427],{"class":426},"sysy8","^",[324,429,431],{"class":430},"sfnFC","\\d",[324,433,435],{"class":434},"seDH9","+",[324,437,438],{"class":426},"$",[324,440,441],{"class":422},"\u002F",[324,443,374],{"class":444},"sGYWJ",[324,446,447],{"class":348},"test",[324,449,450],{"class":352},"(",[324,452,403],{"class":369},[324,454,374],{"class":373},[324,456,378],{"class":457},"sJOc3",[324,459,460],{"class":352},"[",[324,462,463],{"class":390},"0",[324,465,466],{"class":352},"]",[324,468,469],{"class":337},"!",[324,471,472],{"class":352},"))\n",[324,474,476],{"class":326,"line":475},6,[324,477,478],{"class":352},");\n",[36,480,68],{"id":481},"porting-the-design",[11,483,484],{},"AstroPaper's look survives almost verbatim because both projects use Tailwind CSS v4:",[48,486,487,507,524],{},[51,488,489,492,493,276,496,499,500,503,504],{},[136,490,491],{},"theme.css"," — the design tokens (",[136,494,495],{},"--background",[136,497,498],{},"--accent",", …) copied as-is, including the ",[136,501,502],{},"@custom-variant dark"," that keys off ",[136,505,506],{},"data-theme=\"dark\"",[51,508,509,512,513,516,517,520,521],{},[136,510,511],{},"typography.css"," — the ",[136,514,515],{},"app-prose"," overrides ported with one change: Astro's ",[136,518,519],{},".astro-code"," selectors became Nuxt Content's ",[136,522,523],{},".shiki",[51,525,526],{},"The Tabler icons were code-generated: a small script read every SVG from the cloned repo and wrapped each one in a Vue SFC",[11,528,529,530,533,534,537,538,540,541,544],{},"The FOUC-free dark mode works the same way as the original — an inline script in ",[136,531,532],{},"\u003Chead>"," sets ",[136,535,536],{},"data-theme"," before first paint, and a ",[136,539,294],{}," composable handles toggling, ",[136,542,543],{},"localStorage",", and OS-preference sync.",[36,546,74],{"id":547},"migrating-the-content",[11,549,550,551,554],{},"A migration script (",[136,552,553],{},"scripts\u002Fmigrate-content.mjs",") converted the original posts:",[48,556,557,563,571,585],{},[51,558,559,560,562],{},"Files renamed to their frontmatter ",[136,561,162],{},", so every URL matches the original site",[51,564,565,26,567,570],{},[136,566,166],{},[136,568,569],{},"_color-schemes\u002F"," flattened into the posts root, mirroring Astro's underscore-stripping",[51,572,573,574,577,578,581,582],{},"MDX converted to MDC: imports stripped, ",[136,575,576],{},"\u003CResponsiveTable>"," JSX rewritten to ",[136,579,580],{},"::responsive-table"," blocks backed by a Vue component in ",[136,583,584],{},"components\u002Fcontent\u002F",[51,586,587,588,591,592],{},"Image references rewritten to ",[136,589,590],{},"\u002Fimages\u002F"," in ",[136,593,594],{},"public\u002F",[36,596,80],{"id":597},"the-gotchas",[11,599,600],{},"This is the part worth reading. Three issues only surfaced when the agent drove a real browser against the dev server.",[602,603,608,641],"div",{"className":604,"data-callout":606,"data-collapsible":607},[605],"callout","note","false",[602,609,612,636],{"className":610},[611],"callout-title",[602,613,617],{"className":614,"ariaHidden":616},[615],"callout-title-icon","true",[618,619,627,632],"svg",{"xmlns":620,"width":621,"height":621,"viewBox":622,"fill":623,"stroke":624,"strokeWidth":625,"strokeLineCap":626,"strokeLineJoin":626},"http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","1em","0 0 24 24","none","currentColor","2","round",[326,628],{"x1":629,"y1":625,"x2":630,"y2":631},"18","22","6",[633,634],"path",{"d":635},"M7.5 20.5 19 9l-4-4L3.5 16.5 2 22z",[602,637,640],{"className":638},[639],"callout-title-text","Note",[602,642,645],{"className":643},[644],"callout-content",[11,646,647],{},"Everything below was found by taking screenshots with a browser-automation CLI and actually looking at them — not by tests or type checks.",[649,650,88],"h3",{"id":651},"_1-pnpm-blocks-native-build-scripts",[11,653,654,655,658,659,662,663,666],{},"Nuxt Content v3 stores content in SQLite via ",[136,656,657],{},"better-sqlite3",". The first ",[136,660,661],{},"pnpm dev"," crashed with ",[126,664,665],{},"\"Could not locate the bindings file\""," because pnpm refuses to run install scripts by default. Fix:",[315,668,672],{"className":669,"code":670,"language":671,"meta":320,"style":320},"language-json shiki shiki-themes min-light night-owl","{\n  \"pnpm\": {\n    \"onlyBuiltDependencies\": [\"better-sqlite3\"]\n  }\n}\n","json",[136,673,674,679,691,712,717],{"__ignoreMap":320},[324,675,676],{"class":326,"line":327},[324,677,678],{"class":352},"{\n",[324,680,681,684,688],{"class":326,"line":334},[324,682,683],{"class":434},"  \"pnpm\"",[324,685,687],{"class":686},"s0XAg",":",[324,689,690],{"class":352}," {\n",[324,692,693,696,698,701,704,707,709],{"class":326,"line":356},[324,694,695],{"class":434},"    \"onlyBuiltDependencies\"",[324,697,687],{"class":686},[324,699,700],{"class":352}," [",[324,702,703],{"class":422},"\"",[324,705,657],{"class":706},"stZ2A",[324,708,703],{"class":422},[324,710,711],{"class":352},"]\n",[324,713,714],{"class":326,"line":366},[324,715,716],{"class":352},"  }\n",[324,718,719],{"class":326,"line":397},[324,720,721],{"class":352},"}\n",[11,723,724,725,374],{},"…followed by ",[136,726,727],{},"pnpm rebuild better-sqlite3",[649,729,94],{"id":730},"_2-shiki-tokens-are-class-based-not-inline",[11,732,733,734,737,738,741,742,745,746,749,750,753,754,757,758,761,762,765,766,769],{},"Astro emits Shiki tokens with inline styles. Nuxt Content emits ",[126,735,736],{},"classes"," (",[136,739,740],{},"\u003Cspan class=\"sCRLn\">",") plus a generated stylesheet of ",[136,743,744],{},"--shiki-default"," \u002F ",[136,747,748],{},"--shiki-dark"," variables, and switches them via the ",[136,751,752],{},"dark"," class on ",[136,755,756],{},"\u003Chtml>",". Token colors worked out of the box — but the ",[136,759,760],{},"\u003Cpre>"," element ships with an ",[23,763,764],{},"empty"," ",[136,767,768],{},"style"," attribute, so Tailwind Typography's default dark-gray code background showed through in both themes. The fix was defining the block backgrounds explicitly:",[315,771,775],{"className":772,"code":773,"language":774,"meta":320,"style":320},"language-css shiki shiki-themes min-light night-owl",".app-prose pre.shiki {\n  --shiki-default-bg: #ffffff; \u002F* min-light *\u002F\n  --shiki-dark-bg: #011627; \u002F* night-owl *\u002F\n  background-color: var(--shiki-default-bg);\n}\n\nhtml[data-theme=\"dark\"] .app-prose pre.shiki {\n  background-color: var(--shiki-dark-bg);\n}\n","css",[136,776,777,796,818,835,858,862,868,904,922],{"__ignoreMap":320},[324,778,779,782,785,789,791,794],{"class":326,"line":327},[324,780,374],{"class":781},"sKmXy",[324,783,515],{"class":784},"sNE3-",[324,786,788],{"class":787},"sGkQF"," pre",[324,790,374],{"class":781},[324,792,793],{"class":784},"shiki",[324,795,690],{"class":352},[324,797,798,802,805,808,812,815],{"class":326,"line":334},[324,799,801],{"class":800},"sF-nr","  --shiki-default-bg",[324,803,687],{"class":804},"sVzfZ",[324,806,807],{"class":390}," #",[324,809,811],{"class":810},"s5thU","ffffff",[324,813,814],{"class":352},"; ",[324,816,817],{"class":330},"\u002F* min-light *\u002F\n",[324,819,820,823,825,827,830,832],{"class":326,"line":356},[324,821,822],{"class":800},"  --shiki-dark-bg",[324,824,687],{"class":804},[324,826,807],{"class":390},[324,828,829],{"class":810},"011627",[324,831,814],{"class":352},[324,833,834],{"class":330},"\u002F* night-owl *\u002F\n",[324,836,837,841,843,846,849,853,855],{"class":326,"line":366},[324,838,840],{"class":839},"syytd","  background-color",[324,842,687],{"class":804},[324,844,845],{"class":781}," var",[324,847,450],{"class":848},"s6Vda",[324,850,852],{"class":851},"sMBZI","--shiki-default-bg",[324,854,280],{"class":848},[324,856,857],{"class":352},";\n",[324,859,860],{"class":326,"line":397},[324,861,721],{"class":352},[324,863,864],{"class":326,"line":475},[324,865,867],{"emptyLinePlaceholder":866},true,"\n",[324,869,871,874,877,879,882,884,887,889,891,894,896,898,900,902],{"class":326,"line":870},7,[324,872,873],{"class":787},"html",[324,875,460],{"class":876},"sXOhJ",[324,878,536],{"class":784},[324,880,881],{"class":434},"=",[324,883,703],{"class":422},[324,885,752],{"class":886},"sS6ib",[324,888,703],{"class":422},[324,890,466],{"class":876},[324,892,893],{"class":781}," .",[324,895,515],{"class":784},[324,897,788],{"class":787},[324,899,374],{"class":781},[324,901,793],{"class":784},[324,903,690],{"class":352},[324,905,907,909,911,913,915,918,920],{"class":326,"line":906},8,[324,908,840],{"class":839},[324,910,687],{"class":804},[324,912,845],{"class":781},[324,914,450],{"class":848},[324,916,917],{"class":851},"--shiki-dark-bg",[324,919,280],{"class":848},[324,921,857],{"class":352},[324,923,925],{"class":326,"line":924},9,[324,926,721],{"class":352},[649,928,100],{"id":929},"_3-mdc-eats-callout-markers",[11,931,932,933,936,937,940,941,944,945,948,949,952],{},"AstroPaper uses ",[136,934,935],{},"rehype-callouts"," for GitHub-style ",[136,938,939],{},"> [!TIP]"," callouts. In Nuxt Content they rendered as plain blockquotes containing a mysterious ",[136,942,943],{},"\u003Cspan>!TIP\u003C\u002Fspan>"," — because MDC's inline span syntax (",[136,946,947],{},"[text]",") consumed the brackets ",[23,950,951],{},"before"," the rehype plugin ever ran. The migration script now escapes them:",[315,954,958],{"className":955,"code":956,"language":957,"meta":320,"style":320},"language-js shiki shiki-themes min-light night-owl","out = out.replace(\u002F^(>\\s*)\\[!(\\w+)\\]\u002Fgm, \"$1\\\\[!$2]\");\n","js",[136,959,960],{"__ignoreMap":320},[324,961,962,966,968,971,973,976,978,980,982,986,990,993,995,999,1002,1005,1007,1009,1012,1014,1018,1021,1024,1027,1030,1033,1035],{"class":326,"line":327},[324,963,965],{"class":964},"sw9md","out",[324,967,345],{"class":337},[324,969,970],{"class":383}," out",[324,972,374],{"class":444},[324,974,975],{"class":348},"replace",[324,977,450],{"class":352},[324,979,441],{"class":422},[324,981,427],{"class":426},[324,983,985],{"class":984},"s3BZK","(>",[324,987,989],{"class":988},"swXwZ","\\s",[324,991,992],{"class":434},"*",[324,994,280],{"class":984},[324,996,998],{"class":997},"scFj9","\\[",[324,1000,1001],{"class":984},"!(",[324,1003,1004],{"class":988},"\\w",[324,1006,435],{"class":434},[324,1008,280],{"class":984},[324,1010,1011],{"class":997},"\\]",[324,1013,441],{"class":422},[324,1015,1017],{"class":1016},"scjHm","gm",[324,1019,1020],{"class":686},",",[324,1022,1023],{"class":422}," \"",[324,1025,1026],{"class":886},"$1",[324,1028,1029],{"class":997},"\\\\",[324,1031,1032],{"class":886},"[!$2]",[324,1034,703],{"class":422},[324,1036,478],{"class":352},[11,1038,1039,1040,1042,1043,1046],{},"With the escape in place, ",[136,1041,935],{}," sees the literal ",[136,1044,1045],{},"[!TIP]"," and renders proper callouts — like the one above.",[36,1048,106],{"id":1049},"verification",[11,1051,1052],{},"The port wasn't declared done until:",[48,1054,1055,1061,1064],{},[51,1056,1057,1058,1060],{},"Every route returned the right status code (",[136,1059,441],{},", pagination, nested post URLs, tags, archives, search, RSS, sitemap, and a 404 for garbage paths)",[51,1062,1063],{},"Screenshots confirmed both themes, code highlighting, callouts, tables, the mobile hamburger menu, and search results",[51,1065,1066,1069],{},[136,1067,1068],{},"nuxt generate"," produced a fully static build — 96 prerendered routes, with draft posts correctly excluded from the output, the RSS feed, and the sitemap",[36,1071,112],{"id":1072},"what-was-deliberately-left-out",[48,1074,1075,1081,1087],{},[51,1076,1077,1080],{},[23,1078,1079],{},"Dynamic OG images"," — AstroPaper renders per-post OG images with satori; the port falls back to a static default image",[51,1082,1083,1086],{},[23,1084,1085],{},"remark-collapse"," — the table of contents renders expanded",[51,1088,1089,1092],{},[23,1090,1091],{},"Per-element view transitions"," — document-level transitions are enabled, but the title\u002Ftag morph animations were skipped",[36,1094,118],{"id":1095},"takeaway",[11,1097,1098],{},"The port took one session: read everything first, map the concepts honestly, migrate content with a script instead of by hand, and verify in a real browser — because the only three real bugs were ones no compiler would ever catch.",[768,1100,1101],{},"html pre.shiki code .sEmqk, html code.shiki .sEmqk{--shiki-default:#C2C3C5;--shiki-default-font-style:inherit;--shiki-dark:#637777;--shiki-dark-font-style:italic}html pre.shiki code .sj-IK, html code.shiki .sj-IK{--shiki-default:#D32F2F;--shiki-dark:#C792EA}html pre.shiki code .sVwY6, html code.shiki .sVwY6{--shiki-default:#1976D2;--shiki-default-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .sCRLn, html code.shiki .sCRLn{--shiki-default:#6F42C1;--shiki-default-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .styZ9, html code.shiki .styZ9{--shiki-default:#24292EFF;--shiki-dark:#D6DEEB}html pre.shiki code .swRlg, html code.shiki .swRlg{--shiki-default:#24292EFF;--shiki-dark:#D9F5DD}html pre.shiki code .s120W, html code.shiki .s120W{--shiki-default:#1976D2;--shiki-default-font-style:inherit;--shiki-dark:#D6DEEB;--shiki-dark-font-style:italic}html pre.shiki code .sdI2O, html code.shiki .sdI2O{--shiki-default:#24292EFF;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sWAzl, html code.shiki .sWAzl{--shiki-default:#1976D2;--shiki-default-font-style:inherit;--shiki-dark:#FAF39F;--shiki-dark-font-style:italic}html pre.shiki code .s_WS7, html code.shiki .s_WS7{--shiki-default:#1976D2;--shiki-default-font-style:inherit;--shiki-dark:#7FDBCA;--shiki-dark-font-style:italic}html pre.shiki code .sC5Uh, html code.shiki .sC5Uh{--shiki-default:#1976D2;--shiki-dark:#F78C6C}html pre.shiki code .sIKrn, html code.shiki .sIKrn{--shiki-default:#22863A;--shiki-dark:#D9F5DD}html pre.shiki code .sysy8, html code.shiki .sysy8{--shiki-default:#D32F2F;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sfnFC, html code.shiki .sfnFC{--shiki-default:#22863A;--shiki-default-font-style:inherit;--shiki-dark:#82AAFF;--shiki-dark-font-style:italic}html pre.shiki code .seDH9, html code.shiki .seDH9{--shiki-default:#D32F2F;--shiki-dark:#7FDBCA}html pre.shiki code .sGYWJ, html code.shiki .sGYWJ{--shiki-default:#6F42C1;--shiki-default-font-style:inherit;--shiki-dark:#C792EA;--shiki-dark-font-style:italic}html pre.shiki code .sJOc3, html code.shiki .sJOc3{--shiki-default:#24292EFF;--shiki-default-font-style:inherit;--shiki-dark:#BAEBE2;--shiki-dark-font-style:italic}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s0XAg, html code.shiki .s0XAg{--shiki-default:#212121;--shiki-dark:#D6DEEB}html pre.shiki code .stZ2A, html code.shiki .stZ2A{--shiki-default:#22863A;--shiki-dark:#C789D6}html pre.shiki code .sKmXy, html code.shiki .sKmXy{--shiki-default:#6F42C1;--shiki-dark:#C5E478}html pre.shiki code .sNE3-, html code.shiki .sNE3-{--shiki-default:#6F42C1;--shiki-default-font-style:inherit;--shiki-dark:#C5E478;--shiki-dark-font-style:italic}html pre.shiki code .sGkQF, html code.shiki .sGkQF{--shiki-default:#22863A;--shiki-dark:#FF6363}html pre.shiki code .sF-nr, html code.shiki .sF-nr{--shiki-default:#24292EFF;--shiki-dark:#C5E478}html pre.shiki code .sVzfZ, html code.shiki .sVzfZ{--shiki-default:#D32F2F;--shiki-dark:#D6DEEB}html pre.shiki code .s5thU, html code.shiki .s5thU{--shiki-default:#1976D2;--shiki-dark:#FFEB95}html pre.shiki code .syytd, html code.shiki .syytd{--shiki-default:#1976D2;--shiki-dark:#80CBC4}html pre.shiki code .s6Vda, html code.shiki .s6Vda{--shiki-default:#1976D2;--shiki-dark:#D6DEEB}html pre.shiki code .sMBZI, html code.shiki .sMBZI{--shiki-default:#1976D2;--shiki-dark:#C5E478}html pre.shiki code .sXOhJ, html code.shiki .sXOhJ{--shiki-default:#24292EFF;--shiki-dark:#C792EA}html pre.shiki code .sS6ib, html code.shiki .sS6ib{--shiki-default:#22863A;--shiki-dark:#ECC48D}html pre.shiki code .sw9md, html code.shiki .sw9md{--shiki-default:#24292EFF;--shiki-dark:#D7DBE0}html pre.shiki code .s3BZK, html code.shiki .s3BZK{--shiki-default:#22863A;--shiki-dark:#5CA7E4}html pre.shiki code .swXwZ, html code.shiki .swXwZ{--shiki-default:#22863A;--shiki-dark:#82AAFF}html pre.shiki code .scFj9, html code.shiki .scFj9{--shiki-default:#22863A;--shiki-dark:#F78C6C}html pre.shiki code .scjHm, html code.shiki .scjHm{--shiki-default:#D32F2F;--shiki-dark:#5CA7E4}",{"title":320,"searchDepth":334,"depth":334,"links":1103},[1104,1105,1106,1107,1108,1109,1114,1115,1116],{"id":38,"depth":334,"text":39},{"id":121,"depth":334,"text":56},{"id":178,"depth":334,"text":62},{"id":481,"depth":334,"text":68},{"id":547,"depth":334,"text":74},{"id":597,"depth":334,"text":80,"children":1110},[1111,1112,1113],{"id":651,"depth":356,"text":88},{"id":730,"depth":356,"text":94},{"id":929,"depth":356,"text":100},{"id":1049,"depth":334,"text":106},{"id":1072,"depth":334,"text":112},{"id":1095,"depth":334,"text":118},null,"A full walkthrough of porting the AstroPaper blog theme from Astro 6 to Nuxt 4 and Nuxt Content v3 — done in one session with Claude Code running Fable 5.",false,"md",{},"\u002Fposts\u002Fhow-i-ported-astropaper-to-nuxt-content-with-fable-5","2026-06-10",{"title":5,"description":1118},"posts\u002Fhow-i-ported-astropaper-to-nuxt-content-with-fable-5",[1127,1128,1129,1130],"nuxt","nuxt-content","ai","port","wypmUfQC5oFemLdFU6PVFT4Y3Sa1Eot-d3wy6HevYmE",[1133,1135],{"path":1122,"title":5,"description":1118,"pubDatetime":1123,"modDatetime":1117,"timezone":1117,"featured":866,"draft":1119,"tags":1134},[1127,1128,1129,1130],{"path":1136,"title":1137,"description":1138,"pubDatetime":1139,"modDatetime":1117,"timezone":1117,"featured":1119,"draft":1119,"tags":1140},"\u002Fposts\u002Fpredefined-color-schemes","Predefined color schemes","Some well-crafted, predefined light and dark color schemes for NuxtPaper, ready to drop into theme.css.","2024-01-01",[1141],"color-schemes",1781461333076]