[{"data":1,"prerenderedAt":469},["ShallowReactive",2],{"home-projects-en":3,"home-posts-en":61},[4,29,45],{"id":5,"title":6,"description":7,"extension":8,"featured":9,"github":10,"image":11,"live":11,"meta":12,"order":21,"stack":22,"stem":27,"__hash__":28},"projects_en\u002Fen\u002Fprojects\u002Fportfolio-site.md","This website","Bilingual portfolio, blog and vlog built with Nuxt 4, Nuxt Content and Tailwind CSS v4. Fully static, no server required.","md",true,"https:\u002F\u002Fgithub.com\u002Fusername\u002Fportfolio",null,{"body":13},{"type":14,"value":15,"toc":16},"minimark",[],{"title":17,"searchDepth":18,"depth":19,"links":20},"",2,3,[],1,[23,24,25,26],"Nuxt","Vue","Tailwind CSS","TypeScript","en\u002Fprojects\u002Fportfolio-site","2V3pPGX1HHYsEbTTHFtHy4Efp-dO3eucCkv8rP_gBqU",{"id":30,"title":31,"description":32,"extension":8,"featured":9,"github":33,"image":11,"live":11,"meta":34,"order":18,"stack":39,"stem":43,"__hash__":44},"projects_en\u002Fen\u002Fprojects\u002Ftask-api.md","Task API","A sample REST API for task management with JWT auth, rate limiting and OpenAPI docs. Placeholder project — replace with your real work.","https:\u002F\u002Fgithub.com\u002Fusername\u002Ftask-api",{"body":35},{"type":14,"value":36,"toc":37},[],{"title":17,"searchDepth":18,"depth":19,"links":38},[],[40,41,42],"Node.js","PostgreSQL","Docker","en\u002Fprojects\u002Ftask-api","nqPY9gm3twN0vb7-4OwYNhKlMDg4fVYqX6iu0bVQpys",{"id":46,"title":47,"description":48,"extension":8,"featured":9,"github":49,"image":11,"live":50,"meta":51,"order":19,"stack":56,"stem":59,"__hash__":60},"projects_en\u002Fen\u002Fprojects\u002Fcli-tool.md","devkit CLI","A command-line toolkit that scaffolds projects and automates routine dev chores. Placeholder project — replace with your real work.","https:\u002F\u002Fgithub.com\u002Fusername\u002Fdevkit","https:\u002F\u002Fexample.com",{"body":52},{"type":14,"value":53,"toc":54},[],{"title":17,"searchDepth":18,"depth":19,"links":55},[],[57,58],"Go","Cobra","en\u002Fprojects\u002Fcli-tool","cm4OL5mFx3_TAJxQnSzqmf__WjLrAu2XFZ03nbe887k",[62,317],{"id":63,"title":64,"body":65,"date":306,"description":307,"extension":8,"image":11,"meta":308,"navigation":9,"path":309,"seo":310,"stem":311,"tags":312,"__hash__":316},"blog_en\u002Fblog\u002Fnuxt-content-static-blog.md","Building a static blog with Nuxt Content v3",{"type":14,"value":66,"toc":300},[67,76,81,89,182,189,193,196,271,275,278,286,289,293,296],[68,69,70,71,75],"p",{},"This site is a fully static Nuxt app. Every post is a Markdown file in the repo, and ",[72,73,74],"code",{},"nuxt generate"," turns the whole thing into plain HTML. Here's the interesting part of the setup.",[77,78,80],"h2",{"id":79},"collections-are-typed","Collections are typed",[68,82,83,84,88],{},"Nuxt Content v3 replaced the old file-based querying with ",[85,86,87],"strong",{},"collections"," — you declare a schema, and frontmatter gets validated at build time:",[90,91,95],"pre",{"className":92,"code":93,"language":94,"meta":17,"style":17},"language-ts shiki shiki-themes github-light github-dark","const blogSchema = z.object({\n  title: z.string(),\n  description: z.string(),\n  date: z.string(),\n  tags: z.array(z.string()).default([]),\n})\n","ts",[72,96,97,123,134,143,153,176],{"__ignoreMap":17},[98,99,101,105,109,112,116,120],"span",{"class":100,"line":21},"line",[98,102,104],{"class":103},"szBVR","const",[98,106,108],{"class":107},"sj4cs"," blogSchema",[98,110,111],{"class":103}," =",[98,113,115],{"class":114},"sVt8B"," z.",[98,117,119],{"class":118},"sScJk","object",[98,121,122],{"class":114},"({\n",[98,124,125,128,131],{"class":100,"line":18},[98,126,127],{"class":114},"  title: z.",[98,129,130],{"class":118},"string",[98,132,133],{"class":114},"(),\n",[98,135,136,139,141],{"class":100,"line":19},[98,137,138],{"class":114},"  description: z.",[98,140,130],{"class":118},[98,142,133],{"class":114},[98,144,146,149,151],{"class":100,"line":145},4,[98,147,148],{"class":114},"  date: z.",[98,150,130],{"class":118},[98,152,133],{"class":114},[98,154,156,159,162,165,167,170,173],{"class":100,"line":155},5,[98,157,158],{"class":114},"  tags: z.",[98,160,161],{"class":118},"array",[98,163,164],{"class":114},"(z.",[98,166,130],{"class":118},[98,168,169],{"class":114},"()).",[98,171,172],{"class":118},"default",[98,174,175],{"class":114},"([]),\n",[98,177,179],{"class":100,"line":178},6,[98,180,181],{"class":114},"})\n",[68,183,184,185,188],{},"Typos in frontmatter now fail the build instead of silently rendering ",[72,186,187],{},"undefined",". This is the single biggest quality-of-life win over v2.",[77,190,192],{"id":191},"queries-look-like-sql-because-they-are","Queries look like SQL because they are",[68,194,195],{},"Under the hood, content lives in SQLite. The query API compiles to SQL:",[90,197,199],{"className":92,"code":198,"language":94,"meta":17,"style":17},"const posts = await queryCollection('blog_en')\n  .order('date', 'DESC')\n  .limit(3)\n  .all()\n",[72,200,201,226,247,261],{"__ignoreMap":17},[98,202,203,205,208,210,213,216,219,223],{"class":100,"line":21},[98,204,104],{"class":103},[98,206,207],{"class":107}," posts",[98,209,111],{"class":103},[98,211,212],{"class":103}," await",[98,214,215],{"class":118}," queryCollection",[98,217,218],{"class":114},"(",[98,220,222],{"class":221},"sZZnC","'blog_en'",[98,224,225],{"class":114},")\n",[98,227,228,231,234,236,239,242,245],{"class":100,"line":18},[98,229,230],{"class":114},"  .",[98,232,233],{"class":118},"order",[98,235,218],{"class":114},[98,237,238],{"class":221},"'date'",[98,240,241],{"class":114},", ",[98,243,244],{"class":221},"'DESC'",[98,246,225],{"class":114},[98,248,249,251,254,256,259],{"class":100,"line":19},[98,250,230],{"class":114},[98,252,253],{"class":118},"limit",[98,255,218],{"class":114},[98,257,258],{"class":107},"3",[98,260,225],{"class":114},[98,262,263,265,268],{"class":100,"line":145},[98,264,230],{"class":114},[98,266,267],{"class":118},"all",[98,269,270],{"class":114},"()\n",[77,272,274],{"id":273},"two-languages-two-collections","Two languages, two collections",[68,276,277],{},"For a bilingual site, one collection per locale keeps things simple:",[90,279,284],{"className":280,"code":282,"language":283},[281],"language-text","content\u002F\n  en\u002Fblog\u002F    → collection blog_en, served at \u002Fblog\n  uz\u002Fblog\u002F    → collection blog_uz, served at \u002Fuz\u002Fblog\n","text",[72,285,282],{"__ignoreMap":17},[68,287,288],{},"A tiny composable picks the right collection from the active locale, and the rest of the code never thinks about i18n.",[77,290,292],{"id":291},"the-result","The result",[68,294,295],{},"No server, no database in production, no CMS subscription. Just Markdown files, a git history, and static HTML that any CDN can serve.",[297,298,299],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}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 .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}",{"title":17,"searchDepth":18,"depth":19,"links":301},[302,303,304,305],{"id":79,"depth":18,"text":80},{"id":191,"depth":18,"text":192},{"id":273,"depth":18,"text":274},{"id":291,"depth":18,"text":292},"2026-07-14","How this site works under the hood: Markdown collections, SQLite-backed queries, and full static generation with Nuxt.",{},"\u002Fblog\u002Fnuxt-content-static-blog",{"title":64,"description":307},"blog\u002Fnuxt-content-static-blog",[313,314,315],"nuxt","vue","tooling","Vjjtutnkn2zGY1coUA-L_dr9pk_zjeJYAjL0ciEyAk8",{"id":318,"title":319,"body":320,"date":459,"description":460,"extension":8,"image":11,"meta":461,"navigation":9,"path":462,"seo":463,"stem":464,"tags":465,"__hash__":468},"blog_en\u002Fblog\u002Fhello-world.md","Hello, world — why I'm starting this blog",{"type":14,"value":321,"toc":454},[322,330,334,337,359,363,366,441,445,448,451],[68,323,324,325,329],{},"Every engineer eventually hears the same advice: ",[326,327,328],"em",{},"write in public",". This is me finally taking it.",[77,331,333],{"id":332},"what-to-expect-here","What to expect here",[68,335,336],{},"I plan to write about three things:",[338,339,340,347,353],"ol",{},[341,342,343,346],"li",{},[85,344,345],{},"Engineering notes"," — problems I hit at work and how I solved them",[341,348,349,352],{},[85,350,351],{},"Tooling"," — editors, CLIs, and workflows that actually save time",[341,354,355,358],{},[85,356,357],{},"Career"," — what I learn about growing as a software engineer",[77,360,362],{"id":361},"why-write-at-all","Why write at all?",[68,364,365],{},"Writing forces clarity. If I can't explain a solution in a few paragraphs, I probably don't understand it yet. A blog is also a public notebook — six months from now, the person most likely to need these notes is me.",[90,367,369],{"className":92,"code":368,"language":94,"meta":17,"style":17},"\u002F\u002F The whole plan, as code:\nconst blog = {\n  cadence: 'when I have something worth saying',\n  language: ['en', 'uz'],\n  topics: ['engineering', 'tooling', 'career'],\n}\n",[72,370,371,377,389,400,416,436],{"__ignoreMap":17},[98,372,373],{"class":100,"line":21},[98,374,376],{"class":375},"sJ8bj","\u002F\u002F The whole plan, as code:\n",[98,378,379,381,384,386],{"class":100,"line":18},[98,380,104],{"class":103},[98,382,383],{"class":107}," blog",[98,385,111],{"class":103},[98,387,388],{"class":114}," {\n",[98,390,391,394,397],{"class":100,"line":19},[98,392,393],{"class":114},"  cadence: ",[98,395,396],{"class":221},"'when I have something worth saying'",[98,398,399],{"class":114},",\n",[98,401,402,405,408,410,413],{"class":100,"line":145},[98,403,404],{"class":114},"  language: [",[98,406,407],{"class":221},"'en'",[98,409,241],{"class":114},[98,411,412],{"class":221},"'uz'",[98,414,415],{"class":114},"],\n",[98,417,418,421,424,426,429,431,434],{"class":100,"line":155},[98,419,420],{"class":114},"  topics: [",[98,422,423],{"class":221},"'engineering'",[98,425,241],{"class":114},[98,427,428],{"class":221},"'tooling'",[98,430,241],{"class":114},[98,432,433],{"class":221},"'career'",[98,435,415],{"class":114},[98,437,438],{"class":100,"line":178},[98,439,440],{"class":114},"}\n",[77,442,444],{"id":443},"a-note-on-the-two-languages","A note on the two languages",[68,446,447],{},"I write in English and Uzbek. Not every post will be translated — each language gets the posts that make sense for its audience.",[68,449,450],{},"See you in the next post.",[297,452,453],{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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);}",{"title":17,"searchDepth":18,"depth":19,"links":455},[456,457,458],{"id":332,"depth":18,"text":333},{"id":361,"depth":18,"text":362},{"id":443,"depth":18,"text":444},"2026-07-10","The obligatory first post: what this blog is for, what I'll write about, and why writing in public matters for engineers.",{},"\u002Fblog\u002Fhello-world",{"title":319,"description":460},"blog\u002Fhello-world",[466,467],"meta","career","8gQyRdZxZAg6lljmYYzjiFlDvuVFTHEQ0j4LdjNcYyU",1784073506107]