\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",{"id":2444,"title":2445,"body":2446,"description":2600,"extension":1036,"meta":2601,"navigation":159,"path":2602,"publishDate":2603,"rawbody":2604,"seo":2605,"series":1043,"slug":2606,"stem":2607,"summary":2608,"tags":2609,"__hash__":2614},"articles/articles/appwrite-hackaton-movieplay.md","Appwrite Hackaton: MoviePlay",{"type":9,"value":2447,"toc":2588},[2448,2465,2469,2472,2478,2482,2487,2491,2496,2535,2539,2551,2555,2559,2563,2566,2569,2572,2575,2578,2581],[12,2449,2450,2451,1070,2454,2459,2460,2464],{},"Well, I recently quit my job so I got free time and this hackathon between ",[25,2452,1069],{"href":1067,"rel":2453},[29],[25,2455,2458],{"href":2456,"rel":2457},"https://appwrite.io",[29],"Appwrite"," is announced. This is clearly a sign. So I decided to build ",[25,2461,2463],{"href":2456,"rel":2462},[29],"MoviePlay",". Before we get into the trials and tribulations of this project, let's get all the technical stuff out of the way.",[40,2466,2468],{"id":2467},"the-idea","The Idea",[12,2470,2471],{},"Have you ever had a debate with someone as to what is the correct order to watch Star Wars? There's the chronological order, the release order, the machete order",[12,2473,2474],{},[35,2475],{"alt":2476,"src":2477},"enough already","https://media.giphy.com/media/SRka2MLKzpzE6K24al/giphy.gif",[40,2479,2481],{"id":2480},"team","Team",[484,2483,2484],{},[487,2485,2486],{},"Me",[40,2488,2490],{"id":2489},"tech-stack","Tech Stack",[484,2492,2493],{},[487,2494,2495],{},"ReactJS & Typescript (ViteJS)",[484,2497,2498,2501,2524,2527],{},[487,2499,2500],{},"TailwindCSS & DaisyUI",[487,2502,2503,2508],{},[25,2504,2507],{"href":2505,"rel":2506},"https://cloud.appwrite.io",[29],"Appwrite Cloud",[484,2509,2510,2513,2516],{},[487,2511,2512],{},"Database",[487,2514,2515],{},"Account",[487,2517,2518,2519],{},"Functions",[484,2520,2521],{},[487,2522,2523],{},"NodeJS",[487,2525,2526],{},"Vercel",[487,2528,2529,2534],{},[25,2530,2533],{"href":2531,"rel":2532},"https://www.npmjs.com/package/@matfire/the_movie_wrapper",[29],"The-Movie-Wrapper"," (I made this one, but still...)",[40,2536,2538],{"id":2537},"look-at-the-code","Look at the code",[12,2540,2541,2542,2546,2547],{},"You can see the code ",[25,2543,1107],{"href":2544,"rel":2545},"https://github.com/matfire/movieplay",[29]," and see it live ",[25,2548,1107],{"href":2549,"rel":2550},"https://movieplay.nirah.tech",[29],[40,2552,2554],{"id":2553},"demo","Demo",[2556,2557],"youtube",{"id":2558},"8GJyqRNkZrA",[40,2560,2562],{"id":2561},"on-the-using-of-appwrite","On the using of Appwrite",[12,2564,2565],{},"I had already used a self-hosted version of Appwrite and have been tinkering with the closed cloud beta for a bit, so I was already familiar with the tool and will not really talk about onboarding.",[77,2567,2512],{"id":2568},"database",[12,2570,2571],{},"I was a bit disappointed relationships (as of 06/04/2023) are not yet supported on Cloud, so you still need to do all the foreign key constraints by hand, which makes fetching client-side a bit of a hassle.",[77,2573,2515],{"id":2574},"account",[12,2576,2577],{},"I really like how accounts are handled, especially oauth2 stuff; the fact that you can connect multiple providers for the same account seamlessly is pretty cool",[77,2579,2518],{"id":2580},"functions",[12,2582,2583,2584,2587],{},"I needed to use functions to store the number of views a playlist could get. I would have loved a trigger on ",[268,2585,2586],{},"database read operations",", but I can see it would probably be too much performance overhead; the way I solved this is when navigating to a page, the page loader function triggers the function to increment the views number.",{"title":100,"searchDepth":156,"depth":156,"links":2589},[2590,2591,2592,2593,2594,2595],{"id":2467,"depth":156,"text":2468},{"id":2480,"depth":156,"text":2481},{"id":2489,"depth":156,"text":2490},{"id":2537,"depth":156,"text":2538},{"id":2553,"depth":156,"text":2554},{"id":2561,"depth":156,"text":2562,"children":2596},[2597,2598,2599],{"id":2568,"depth":163,"text":2512},{"id":2574,"depth":163,"text":2515},{"id":2580,"depth":163,"text":2518},"Well, I recently quit my job so I got free time and this hackathon between Hashnode and Appwrite is announced. This is clearly a sign. So I decided to build MoviePlay. Before we get into the trials and tribulations of this project, let's get all the technical stuff out of the way.",{"cover_image":1038},"/articles/appwrite-hackaton-movieplay","2023-06-10T00:00:00.000Z","---\ntitle: \"Appwrite Hackaton: MoviePlay\"\npublishDate: 2023-06-10\nsummary: \"A postmortem of an Appwrite Hackaton to celebrate the launch of their cloud beta\"\nslug: appwrite-hackaton-movieplay\ntags:\n- reactjs\n- typescript\n- tailwind-css\n- appwrite\ncover_image: ./images/og.png\n---\n\nWell, I recently quit my job so I got free time and this hackathon between [Hashnode](https://hashnode.com) and [Appwrite](https://appwrite.io) is announced. This is clearly a sign. So I decided to build [MoviePlay](https://appwrite.io). Before we get into the trials and tribulations of this project, let's get all the technical stuff out of the way.\n\n## The Idea\n\nHave you ever had a debate with someone as to what is the correct order to watch Star Wars? There's the chronological order, the release order, the machete order\n\n\n\n## Team\n\n- Me\n\n## Tech Stack\n\n- ReactJS & Typescript (ViteJS)\n\n* TailwindCSS & DaisyUI\n\n* [Appwrite Cloud](https://cloud.appwrite.io)\n - Database\n\n - Account\n\n - Functions\n - NodeJS\n\n* Vercel\n\n* [The-Movie-Wrapper](https://www.npmjs.com/package/@matfire/the_movie_wrapper) (I made this one, but still...)\n\n## Look at the code\n\nYou can see the code [here](https://github.com/matfire/movieplay) and see it live [here](https://movieplay.nirah.tech)\n\n## Demo\n\n::youtube{#8GJyqRNkZrA}\n::\n\n## On the using of Appwrite\n\nI had already used a self-hosted version of Appwrite and have been tinkering with the closed cloud beta for a bit, so I was already familiar with the tool and will not really talk about onboarding.\n\n### Database\n\nI was a bit disappointed relationships (as of 06/04/2023) are not yet supported on Cloud, so you still need to do all the foreign key constraints by hand, which makes fetching client-side a bit of a hassle.\n\n### Account\n\nI really like how accounts are handled, especially oauth2 stuff; the fact that you can connect multiple providers for the same account seamlessly is pretty cool\n\n### Functions\n\nI needed to use functions to store the number of views a playlist could get. I would have loved a trigger on **database read operations**, but I can see it would probably be too much performance overhead; the way I solved this is when navigating to a page, the page loader function triggers the function to increment the views number.\n",{"title":2445,"description":2600},"appwrite-hackaton-movieplay","articles/appwrite-hackaton-movieplay","A postmortem of an Appwrite Hackaton to celebrate the launch of their cloud beta",[2610,2611,2612,2613],"reactjs","typescript","tailwind-css","appwrite","EpBeP4Pmmr4anj0uu7vqC7C9JGBmfI2bUYFlxClSq4A",["Reactive",2616],{"$scolor-mode":2617,"$snuxt-seo-utils:routeRules":2620,"$ssite-config":2621},{"preference":2618,"value":2618,"unknown":159,"forced":2619},"system",false,{"head":-1,"seoMeta":-1},{"_priority":2622,"env":2626,"name":2627,"url":2628},{"name":2623,"env":2624,"url":2625},-5,-15,-4,"production","matteogassend.com","https://www.matteogassend.com/",["Set"],["ShallowReactive",2631],{"articles-index":-1},"/articles"]