\n",[16,2321,2322,2326,2331,2335,2339],{"__ignoreMap":100},[104,2323,2324],{"class":106,"line":107},[104,2325,2092],{},[104,2327,2328],{"class":106,"line":156},[104,2329,2330],{},"const { Content, headings } = await entry.render();\n",[104,2332,2333],{"class":106,"line":163},[104,2334,2092],{},[104,2336,2337],{"class":106,"line":181},[104,2338,160],{"emptyLinePlaceholder":159},[104,2340,2341],{"class":106,"line":186},[104,2342,2343],{},"\u003CContent />\n",[12,2345,2346,2347,2350],{},"That should take care of displaying the content you wrote in your markdown file; you want to get the frontmatter data (like a title, cover image and such), you can do so using ",[16,2348,2349],{},"entry.data.title"," and so on.",[40,2352,2354],{"id":2353},"adding-functionalities","Adding Functionalities",[77,2356,2358],{"id":2357},"table-of-contents","Table of Contents",[12,2360,2361],{},"But what if I wanted to add a summary ?",[12,2363,2364],{},"You could obviously write by hand each time, but you could also leverage the data Astro gives us; you may have noticed that I destructured 2 properties from the renderer entry: we have already used content, so let's look at the headings.",[12,2366,2367,2368,2371,2372,2375,2376,2378,2379,2382,2383,2388],{},"The headings variable is an array of all the headings in a file (think ",[16,2369,2370],{},"#",", ",[16,2373,2374],{},"##"," etc) as well as their level (",[16,2377,2374],{}," is 2, ",[16,2380,2381],{},"###"," is 3 etc). With these informations, we can build a structure displaying each section and subsection and display it accordingly (more info on this article from ",[25,2384,2387],{"href":2385,"rel":2386},"https://kld.dev/building-table-of-contents/",[29],"Kevin Drum"," and add it our page.",[77,2390,2392],{"id":2391},"embeds-and-markdown-customization","Embeds and markdown customization",[12,2394,2395,2396,2401,2402,2405,2406,2409,2410,2414],{},"You may also notice I have some embeds on my articles even though Markdown natively does not support embedding content. This is done by using a Remark plugin. Remark is a tool that can be used to parse and transform Markdown. In this case, I used a plugin called ",[25,2397,2400],{"href":2398,"rel":2399},"https://github.com/remark-embedder/core",[29],"remark-embedder"," to add custom logic to replace links from specific websites (in this case, Youtube and CodeSandbox) with ",[16,2403,2404],{},"\u003Ciframe>","s containing the actual page; without the plugin, those would simply be text links and would make for a much less pleasing lecture, wouldn't you agree ?\nYou can obviously do more with remark than just that, so take a look at the plugins they offer. But how do you use with Astro? You simply add the plugins in your ",[16,2407,2408],{},"astro.config.mjs"," file (documentation on how to do that is ",[25,2411,1107],{"href":2412,"rel":2413},"https://docs.astro.build/en/reference/configuration-reference/#markdownremarkplugins",[29],").",[12,2416,2417],{},"This post was a bit chaotic, but I hope I was able to share a bit of what I did on my blog section (where you are hopefully reading this right now).",[1024,2419,2420],{},"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 pre.shiki code .s_ZFR, html code.shiki .s_ZFR{--shiki-default:#F5BDE6}html pre.shiki code .s57MT, html code.shiki .s57MT{--shiki-default:#8AADF4}html pre.shiki code .sXptk, html code.shiki .sXptk{--shiki-default:#8BD5CA}html pre.shiki code .sSZ1V, html code.shiki .sSZ1V{--shiki-default:#A6DA95}html pre.shiki code .sFaBz, html code.shiki .sFaBz{--shiki-default:#CAD3F5}html pre.shiki code .slVFb, html code.shiki .slVFb{--shiki-default:#939AB7}html pre.shiki code .sIF4r, html code.shiki .sIF4r{--shiki-default:#C6A0F6}html pre.shiki code .sPUSY, html code.shiki .sPUSY{--shiki-default:#C6A0F6;--shiki-default-font-weight:bold}html pre.shiki code .siK8c, html code.shiki .siK8c{--shiki-default:#8AADF4;--shiki-default-font-style:italic}html pre.shiki code .sfEIy, html code.shiki .sfEIy{--shiki-default:#939AB7;--shiki-default-font-style:italic}",{"title":100,"searchDepth":156,"depth":156,"links":2422},[2423,2427],{"id":2030,"depth":156,"text":2031,"children":2424},[2425,2426],{"id":2034,"depth":163,"text":2035},{"id":2154,"depth":163,"text":2155},{"id":2353,"depth":156,"text":2354,"children":2428},[2429,2430],{"id":2357,"depth":163,"text":2358},{"id":2391,"depth":163,"text":2392},"I've recently decided to recentralize all my articles on my own blog instead of publishing them to Hashnode (nothing wrong with Hashnode, just something that I had wanted to do for a while) and since I have a wondeful brand new personal site built with astro I decided to take advantage of their collection system and the new experimental (at least at the time of writing this article) view transitions api to build something a bit more tailored to what I like. Here's how it went.",{"cover_image":1038},"/articles/astro-blog-md","2023-08-24T00:00:00.000Z","---\ntitle: \"Building an Astro Blog with View Transitions\"\nsummary: \"a tale of sweat, content collections, pages and storage\"\npublishDate: 2023-08-24\nslug: astro-blog-md\ntags:\n- astro\n- markdown\ncover_image: ./images/og.png\n---\n\nI've recently decided to recentralize all my articles on my own blog instead of publishing them to [Hashnode](https://hashnode.com) (nothing wrong with Hashnode, just something that I had wanted to do for a while) and since I have a wondeful brand new [personal site](https://matteogassend.com) built with [astro](https://astro.build) I decided to take advantage of their collection system and the new **experimental** (at least at the time of writing this article) view transitions api to build something a bit more tailored to what I like. Here's how it went.\n\n## Astro Collections\n\n### Introduction\n\nAstro content collection are as simple as a folder containing a bunch of Markdown (or Markdoc or MDX) files if that's the only thing you need, but they can also do relationship matching between different collections, frontmatter validation using [zod](https://zod.dev) and you can also customize how the markdown is parsed and translated to html using [rehype](https://github.com/rehypejs/rehype) and [remark](https://github.com/remarkjs/remark) and their plugin ecosystem.\n\nLet's look at an example, shall we? (btw, documentation for what I'm about to talk about is [here](https://docs.astro.build/en/guides/content-collections/))\n\nTaking my blog as an example, we can see that (for now) the \"articles\" content collection has a bit of frontmatter validation; I am requiring that each article have a **title**, a **cover** image, a **publish date** and a list of tags. (Maybe I'll add something like article series in a future update? who knows?)\n\nWith this \"schema\" defined then, all my articles will need to have a frontmatter section looking kind of like this:\n\n```yaml\n---\ntitle: Some title here\npublishDate: 2023-06-10\ncover: https://example.com/image.webp\ntags:\n - tag1\n - tag2\n---\n```\n\nThen you can do a bunch of operations, like retrieving all the collection's \"entries\" (in this case, each article) and they can be handled like any other array in javascript or typescript (map over them, sort them by publication date etc).\n\n### Displaying articles and more\n\nWhen you nativate to a blog post on my website, I have a route that catches the article's slug (a human readable name that can be used in a url, basically), fetches the corresponding article and displays it along with its frontmatter data.\n\nThe code for it would look a bit like this:\n\n```js\nconst { slug } = Astro.params;\nif (slug === undefined) {\n throw new Error(\"Slug is required\");\n}\n// 2. Query for the entry directly using the request slug\nconst entry = await getEntry(\"articles\", slug);\n// 3. Redirect if the entry does not exist\nif (entry === undefined) {\n return Astro.redirect(\"/404\");\n}\n```\n\nand you would store in a file called `[...slug].astro`.\n\nThen to display the markdown content, you can call the render method and then display the content on the page:\n\n```javascript\n---\nconst { Content, headings } = await entry.render();\n---\n\n\u003CContent />\n```\n\nThat should take care of displaying the content you wrote in your markdown file; you want to get the frontmatter data (like a title, cover image and such), you can do so using `entry.data.title` and so on.\n\n## Adding Functionalities\n\n### Table of Contents\n\nBut what if I wanted to add a summary ?\n\nYou could obviously write by hand each time, but you could also leverage the data Astro gives us; you may have noticed that I destructured 2 properties from the renderer entry: we have already used content, so let's look at the headings.\n\nThe headings variable is an array of all the headings in a file (think `#`, `##` etc) as well as their level (`##` is 2, `###` is 3 etc). With these informations, we can build a structure displaying each section and subsection and display it accordingly (more info on this article from [Kevin Drum](https://kld.dev/building-table-of-contents/) and add it our page.\n\n### Embeds and markdown customization\n\nYou may also notice I have some embeds on my articles even though Markdown natively does not support embedding content. This is done by using a Remark plugin. Remark is a tool that can be used to parse and transform Markdown. In this case, I used a plugin called [remark-embedder](https://github.com/remark-embedder/core) to add custom logic to replace links from specific websites (in this case, Youtube and CodeSandbox) with `\u003Ciframe>`s containing the actual page; without the plugin, those would simply be text links and would make for a much less pleasing lecture, wouldn't you agree ?\nYou can obviously do more with remark than just that, so take a look at the plugins they offer. But how do you use with Astro? You simply add the plugins in your `astro.config.mjs` file (documentation on how to do that is [here](https://docs.astro.build/en/reference/configuration-reference/#markdownremarkplugins)).\n\nThis post was a bit chaotic, but I hope I was able to share a bit of what I did on my blog section (where you are hopefully reading this right now).\n",{"title":2002,"description":2431},"astro-blog-md","articles/astro-blog-md","a tale of sweat, content collections, pages and storage",[2022,2441],"markdown","0eup2bIlhmUpzAGnqBpsBKmofsmMu4ykCwV1JmbRRuc",[2444,2468,2498,2527],{"id":2445,"title":2446,"body":2447,"companyName":2446,"date":2451,"des":2452,"description":100,"end":2456,"extension":1036,"meta":2457,"navigation":159,"path":2458,"role":2459,"seo":2460,"skills":2461,"stem":2465,"type":2466,"__hash__":2467},"experiences/experiences/lokki.md","Lokki",{"type":9,"value":2448,"toc":2449},[],{"title":100,"searchDepth":156,"depth":156,"links":2450},[],"2024-10-01T00:00:00.000Z",[2453,2454,2455],"Added features to existing web application","Integrated new designs to the applications","Built a proof of concept AI helper","2025-03-09T00:00:00.000Z",{},"/experiences/lokki","Fullstack developer",{"title":2446,"description":100},[1048,2462,2463,2464],"react","mongodb","nestjs","experiences/lokki","permanent contracts","rh5bLgFgfLZkQvDHwrv2u5qkZIRUk9B6WBYLIWaPsWs",{"id":2469,"title":2470,"body":2471,"companyName":2470,"date":2483,"des":2484,"description":100,"end":2485,"extension":1036,"meta":2486,"navigation":159,"path":2487,"role":2488,"seo":2489,"skills":2490,"stem":2495,"type":2496,"__hash__":2497},"experiences/experiences/agiltech.md","Agiltech",{"type":9,"value":2472,"toc":2481},[2473],[484,2474,2475,2478],{},[487,2476,2477],{},"Built native bluetooth module for Android",[487,2479,2480],{},"Worked on industry-specific transportation software",{"title":100,"searchDepth":156,"depth":156,"links":2482},[],"2023-07-01T00:00:00.000Z",[2477,2480],"2024-10-15T00:00:00.000Z",{},"/experiences/agiltech","RnD Engineer",{"title":2470,"description":100},[2491,1048,2492,2493,2494],"php","html","css","java","experiences/agiltech","permanent contract","9eTT4WBhcfMPx-xsPrIQKMyPJoHYwnZXFJgY5SBCMBw",{"id":2499,"title":2500,"body":2501,"companyName":2513,"date":2514,"des":2515,"description":100,"end":2518,"extension":1036,"meta":2519,"navigation":159,"path":2520,"role":2521,"seo":2522,"skills":2523,"stem":2525,"type":2496,"__hash__":2526},"experiences/experiences/aer.md","Aer",{"type":9,"value":2502,"toc":2511},[2503],[484,2504,2505,2508],{},[487,2506,2507],{},"accompanied students",[487,2509,2510],{},"updated subjects",{"title":100,"searchDepth":156,"depth":156,"links":2512},[],"Epitech","2021-09-01T00:00:00.000Z",[2516,2517],"Accompanied students.","Updated subjects.","2023-05-12T00:00:00.000Z",{},"/experiences/aer","Pedagogical Assistant",{"title":2500,"description":100},[2491,1048,2492,2493,2524],"python","experiences/aer","t5aYwRboCf3vLmU91cc_HzWHFoAFI_jC2MbCYSnV2Yc",{"id":2528,"title":2529,"body":2530,"companyName":2513,"date":2545,"des":2546,"description":100,"end":2550,"extension":1036,"meta":2551,"navigation":159,"path":2552,"role":2553,"seo":2554,"skills":2555,"stem":2557,"type":2558,"__hash__":2559},"experiences/experiences/cc.md","Cc",{"type":9,"value":2531,"toc":2543},[2532],[484,2533,2534,2537,2540],{},[487,2535,2536],{},"co-managed the Lyon's coding club activities",[487,2538,2539],{},"coordinated with the national direction",[487,2541,2542],{},"participated in rewriting (and creating) new activities proposals",{"title":100,"searchDepth":156,"depth":156,"links":2544},[],"2019-10-01T00:00:00.000Z",[2547,2548,2549],"Co-managed the Lyon's coding club activities.","Coordinated with the national.","Participated in rewriting (and creating) new activities proposals.","2020-07-03T00:00:00.000Z",{},"/experiences/cc","Coding Club Regional Manager",{"title":2529,"description":100},[2556,1048,2492,2493,2463,2524],"mysql","experiences/cc","internship","v5mArZPYHgloVKBFE3ogESvpfky6-RQDcL6o1JRqB_8",["Reactive",2561],{"$scolor-mode":2562,"$snuxt-seo-utils:routeRules":2565,"$ssite-config":2566},{"preference":2563,"value":2563,"unknown":159,"forced":2564},"system",false,{"head":-1,"seoMeta":-1},{"_priority":2567,"env":2571,"name":2572,"url":2573},{"name":2568,"env":2569,"url":2570},-5,-15,-4,"production","matteogassend.com","https://www.matteogassend.com/",["Set"],["ShallowReactive",2576],{"home-articles":-1,"home-experiences":-1}]