[feat] Anime review page

Changed files
+202 -31
src
+5 -4
gleam.toml
··· 2 2 version = "1.0.0" 3 3 4 4 [dependencies] 5 - gleam_stdlib = ">= 0.34.0 and < 2.0.0" 5 + gleam_stdlib = ">= 0.34.0 and < 0.50.0" 6 6 lustre = ">= 4.2.0 and < 5.0.0" 7 - tom = ">= 0.3.0 and < 1.0.0" 8 - simplifile = ">= 1.7.0 and < 2.0.0" 7 + tom = ">= 1.0.0 and < 2.0.0" 8 + simplifile = ">= 2.0.0 and < 3.0.0" 9 9 commonmark = ">= 0.1.8 and < 1.0.0" 10 10 glailglind = ">= 1.1.2 and < 2.0.0" 11 - lustre_ssg = ">= 0.8.0 and < 1.0.0" 11 + lustre_ssg = ">= 0.8.3 and < 1.0.0" 12 + gsv = ">= 3.0.1 and < 4.0.0" 12 13 13 14 [dev-dependencies] 14 15 gleeunit = ">= 1.0.0 and < 2.0.0"
+25 -19
manifest.toml
··· 3 3 4 4 packages = [ 5 5 { name = "commonmark", version = "0.1.8", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "commonmark", source = "hex", outer_checksum = "D20FD8F1B147C3F9288FDB84CC790B5136FFD9D4BD04E121BE851B7EB02A6566" }, 6 - { name = "filepath", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "EFB6FF65C98B2A16378ABC3EE2B14124168C0CE5201553DE652E2644DCFDB594" }, 7 - { name = "glailglind", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_httpc", "gleam_stdlib", "shellout", "simplifile", "tom"], otp_app = "glailglind", source = "hex", outer_checksum = "DD037D129592B871E943EAB9C137CE3B017C784D3DEB8180A2954D113D4EE479" }, 8 - { name = "gleam_erlang", version = "0.25.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "054D571A7092D2A9727B3E5D183B7507DAB0DA41556EC9133606F09C15497373" }, 9 - { name = "gleam_http", version = "3.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8C07DF9DF8CC7F054C650839A51C30A7D3C26482AC241C899C1CEA86B22DBE51" }, 10 - { name = "gleam_httpc", version = "2.2.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "CF76C71002DEECF6DC5D9CA83D962728FAE166B57926BE442D827004D3C7DF1B" }, 11 - { name = "gleam_json", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "thoas"], otp_app = "gleam_json", source = "hex", outer_checksum = "9063D14D25406326C0255BDA0021541E797D8A7A12573D849462CAFED459F6EB" }, 12 - { name = "gleam_otp", version = "0.10.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "0B04FE915ACECE539B317F9652CAADBBC0F000184D586AAAF2D94C100945D72B" }, 13 - { name = "gleam_stdlib", version = "0.37.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "5398BD6C2ABA17338F676F42F404B9B7BABE1C8DC7380031ACB05BBE1BCF3742" }, 14 - { name = "gleeunit", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "72CDC3D3F719478F26C4E2C5FED3E657AC81EC14A47D2D2DEBB8693CA3220C3B" }, 15 - { name = "jot", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "A929403A34DC43422BA50D9BE0B61447DE4F0AD62215BB8C640445370C02EC8B" }, 16 - { name = "lustre", version = "4.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "258F876CD7AB12C2C773F1A30F76DFC0A0ED989B720070DF32FC0717A6A0E60C" }, 17 - { name = "lustre_ssg", version = "0.8.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "jot", "lustre", "simplifile", "tom"], otp_app = "lustre_ssg", source = "hex", outer_checksum = "46BC70203D7730314E2CB78A3F7237F1753D86B05F4B7B26722F7FAB7345047C" }, 6 + { name = "envoy", version = "1.0.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "95FD059345AA982E89A0B6E2A3BF1CF43E17A7048DCD85B5B65D3B9E4E39D359" }, 7 + { name = "exception", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "F5580D584F16A20B7FCDCABF9E9BE9A2C1F6AC4F9176FA6DD0B63E3B20D450AA" }, 8 + { name = "filepath", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "67A6D15FB39EEB69DD31F8C145BB5A421790581BD6AA14B33D64D5A55DBD6587" }, 9 + { name = "glailglind", version = "1.1.3", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_http", "gleam_httpc", "gleam_stdlib", "shellout", "simplifile", "tom"], otp_app = "glailglind", source = "hex", outer_checksum = "4617C93C84172CF99EC05B4706720098A0BF299539DD58DD3D90DB2BF2B472F8" }, 10 + { name = "gleam_crypto", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "8AE56026B3E05EBB1F076778478A762E9EB62B31AEEB4285755452F397029D22" }, 11 + { name = "gleam_erlang", version = "0.33.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "A1D26B80F01901B59AABEE3475DD4C18D27D58FA5C897D922FCB9B099749C064" }, 12 + { name = "gleam_http", version = "3.7.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_http", source = "hex", outer_checksum = "8A70D2F70BB7CFEB5DF048A2183FFBA91AF6D4CF5798504841744A16999E33D2" }, 13 + { name = "gleam_httpc", version = "2.3.0", build_tools = ["gleam"], requirements = ["gleam_http", "gleam_stdlib"], otp_app = "gleam_httpc", source = "hex", outer_checksum = "CF6CDD88830CC9853F7638ECC0BE7D7CD9522640DA5FAB4C08CFAC8DEBD08028" }, 14 + { name = "gleam_json", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "0A57FB5666E695FD2BEE74C0428A98B0FC11A395D2C7B4CDF5E22C5DD32C74C6" }, 15 + { name = "gleam_otp", version = "0.16.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "FA0EB761339749B4E82D63016C6A18C4E6662DA05BAB6F1346F9AF2E679E301A" }, 16 + { name = "gleam_stdlib", version = "0.49.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "A7DB09F15738198A87255425FBCE049B4B84C77CC522786DC923DABA73911F13" }, 17 + { name = "glearray", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "glearray", source = "hex", outer_checksum = "B99767A9BC63EF9CC8809F66C7276042E5EFEACAA5B25188B552D3691B91AC6D" }, 18 + { name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" }, 19 + { name = "gsv", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib", "glearray"], otp_app = "gsv", source = "hex", outer_checksum = "31D3C88CECA73DE800FCE66A8F77354FDDA8EB627E2040AA4A27577AD43A68D4" }, 20 + { name = "jot", version = "1.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "jot", source = "hex", outer_checksum = "A0A52BD8D079AB0ABF80BE11DC63B85CF5791125991A029FAD7D17820D9419D8" }, 21 + { name = "lustre", version = "4.6.3", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib"], otp_app = "lustre", source = "hex", outer_checksum = "BDF833368F6C8F152F948D5B6A79866E9881CB80CB66C0685B3327E7DCBFB12F" }, 22 + { name = "lustre_ssg", version = "0.8.3", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib", "jot", "lustre", "simplifile", "temporary", "tom"], otp_app = "lustre_ssg", source = "hex", outer_checksum = "5F1DF752AE6AAD0BD332CCB52E1CF2086997CF55EB59894080F4E3ADF691B95C" }, 18 23 { name = "shellout", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "E2FCD18957F0E9F67E1F497FC9FF57393392F8A9BAEAEA4779541DE7A68DD7E0" }, 19 - { name = "simplifile", version = "1.7.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "1D5DFA3A2F9319EC85825F6ED88B8E449F381B0D55A62F5E61424E748E7DDEB0" }, 20 - { name = "thoas", version = "1.2.0", build_tools = ["rebar3"], requirements = [], otp_app = "thoas", source = "hex", outer_checksum = "540C8CB7D9257F2AD0A14145DC23560F91ACDCA995F0CCBA779EB33AF5D859D1" }, 21 - { name = "tom", version = "0.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "0831C73E45405A2153091226BF98FB485ED16376988602CC01A5FD086B82D577" }, 24 + { name = "simplifile", version = "2.2.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0DFABEF7DC7A9E2FF4BB27B108034E60C81BEBFCB7AB816B9E7E18ED4503ACD8" }, 25 + { name = "temporary", version = "1.0.0", build_tools = ["gleam"], requirements = ["envoy", "exception", "filepath", "gleam_crypto", "gleam_stdlib", "simplifile"], otp_app = "temporary", source = "hex", outer_checksum = "51C0FEF4D72CE7CA507BD188B21C1F00695B3D5B09D7DFE38240BFD3A8E1E9B3" }, 26 + { name = "tom", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "tom", source = "hex", outer_checksum = "228E667239504B57AD05EC3C332C930391592F6C974D0EFECF32FFD0F3629A27" }, 22 27 ] 23 28 24 29 [requirements] 25 30 commonmark = { version = ">= 0.1.8 and < 1.0.0" } 26 31 glailglind = { version = ">= 1.1.2 and < 2.0.0" } 27 - gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" } 32 + gleam_stdlib = { version = ">= 0.34.0 and < 0.50.0" } 28 33 gleeunit = { version = ">= 1.0.0 and < 2.0.0" } 34 + gsv = { version = ">= 3.0.1 and < 4.0.0" } 29 35 lustre = { version = ">= 4.2.0 and < 5.0.0" } 30 - lustre_ssg = { version = ">= 0.8.0 and < 1.0.0" } 31 - simplifile = { version = ">= 1.7.0 and < 2.0.0" } 32 - tom = { version = ">= 0.3.0 and < 1.0.0" } 36 + lustre_ssg = { version = ">= 0.8.3 and < 1.0.0" } 37 + simplifile = { version = ">= 2.0.0 and < 3.0.0" } 38 + tom = { version = ">= 1.0.0 and < 2.0.0" }
+26 -6
src/build.gleam
··· 1 1 import gleam/dict 2 2 import gleam/io 3 3 import gleam/list 4 + import gleam/option 4 5 import gleam/result 5 6 import gleam/string 7 + import gsv 6 8 import lustre/ssg 9 + import simplifile 7 10 import tailwind 8 11 import website/common 9 - 12 + import website/data/posts 13 + import website/data/projects 14 + import website/page/anime 10 15 import website/page/index 11 16 import website/page/post 12 17 import website/page/project 13 18 14 - import website/data/posts 15 - import website/data/projects 16 - 17 19 pub fn main() { 18 20 let projects = 19 21 dict.from_list( ··· 25 27 posts.all() 26 28 |> list.map(fn(post) { #(post.id, post) }), 27 29 ) 30 + let assert Ok(anime_csv) = simplifile.read("./src/website/data/anime.csv") 31 + let assert Ok(anime_rows) = gsv.to_lists(anime_csv) 32 + let anime = 33 + anime_rows 34 + |> list.map(fn(row) { 35 + case row { 36 + [title] -> Ok(common.Anime(title, option.None, option.None)) 37 + [title, link] -> Ok(common.Anime(title, option.Some(link), option.None)) 38 + [title, link, thoughts] -> 39 + Ok(common.Anime(title, option.Some(link), option.Some(thoughts))) 40 + _ -> Error(Nil) 41 + } 42 + }) 43 + |> result.values() 28 44 29 45 let build = 30 46 ssg.new("./priv") ··· 43 59 |> ssg.add_dynamic_route("/posts", posts, fn(p) { 44 60 post.view(p) |> common.wrapper(p.title, _) 45 61 }) 46 - |> ssg.use_index_routes 62 + |> ssg.add_static_route( 63 + "/anime", 64 + anime.view(anime) |> common.wrapper("Anime", _), 65 + ) 66 + |> ssg.use_index_routes() 47 67 |> ssg.add_static_dir("./src/static/") 48 - |> ssg.build 68 + |> ssg.build() 49 69 |> result.map_error(string.inspect) 50 70 |> result.try(fn(_) { 51 71 [
+8 -2
src/website/common.gleam
··· 1 1 import gleam/int 2 + import gleam/option.{type Option} 2 3 import lustre/attribute as attr 3 4 import lustre/element 4 5 import lustre/element/html ··· 31 32 summary: element.Element(a), 32 33 content: element.Element(a), 33 34 ) 35 + } 36 + 37 + pub type Anime { 38 + Anime(title: String, link: Option(String), thoughts: Option(String)) 34 39 } 35 40 36 41 pub fn wrapper( ··· 79 84 80 85 If you wish to get in contact, please send an email to [mia@naomieow.xyz](mailto:mia@naomieow.xyz), or contact me on [Discord](https://chat.lesbian.skin). 81 86 " 82 - |> md.render, 87 + |> md.render(), 83 88 ), 84 89 ]) 85 90 } ··· 98 103 navitem(name: "Home", href: ""), 99 104 navitem(name: "Projects", href: "projects"), 100 105 navitem(name: "Posts", href: "posts"), 106 + navitem(name: "Anime", href: "anime"), 101 107 darkmode(), 102 108 ], 103 109 ) ··· 128 134 ) 129 135 } 130 136 131 - pub fn link(text: String, link: String) -> element.Element(a) { 137 + pub fn link(text text: String, link link: String) -> element.Element(a) { 132 138 html.a([attr.href(link), attr.class("text-pink-400 underline")], [ 133 139 element.text(text), 134 140 ])
+52
src/website/data/anime.csv
··· 1 + Frieren: Beyond Journey’s End,https://anilist.co/anime/154587/Frieren-Beyond-Journeys-End/ 2 + DAN DA DAN,https://anilist.co/anime/171018/DAN-DA-DAN/ 3 + Kaiju No.8,https://anilist.co/anime/153288/Kaiju-No8/,"I'm a huge kaiju fan, so this one is quite biased!" 4 + Fullmetal Alchemist: Brotherhood,https://anilist.co/anime/5114/Fullmetal-Alchemist-Brotherhood/ 5 + Gundam: TWFM,https://anilist.co/anime/139274/Mobile-Suit-Gundam-The-Witch-from-Mercury/ 6 + Jujutsu Kaisen S2,https://anilist.co/anime/145064/JUJUTSU-KAISEN-Season-2/ 7 + Chainsaw Man,https://anilist.co/anime/127230/Chainsaw-Man/ 8 + Love is War S3,https://anilist.co/anime/125367/Kaguyasama-Love-is-War-Ultra-Romantic/ 9 + Love is War,https://anilist.co/anime/101921/Kaguyasama-Love-is-War/ 10 + Love is War S4,https://anilist.co/anime/151384/Kaguyasama-Love-is-War-The-First-Kiss-That-Never-Ends/ 11 + Love is War S2,https://anilist.co/anime/112641/Kaguyasama-Love-is-War/ 12 + Evangelion 1.0,https://anilist.co/anime/2759/Evangelion-10-You-Are-Not-Alone/,All the Eva movies are basically the same tier 13 + Evangelion 2.0,https://anilist.co/anime/3784/Evangelion-20-You-Can-Not-Advance/ 14 + Evangelion 3.0,https://anilist.co/anime/3785/Evangelion-30-You-Can-Not-Redo/ 15 + Evangelion 3.0+1.0,https://anilist.co/anime/3786/Evangelion-3010-Thrice-Upon-a-Time/ 16 + JoJo's P3,https://anilist.co/anime/20474/JoJos-Bizarre-Adventure-Stardust-Crusaders/ 17 + JoJo's P3P2,https://anilist.co/anime/20799/JoJos-Bizarre-Adventure-Stardust-Crusaders--Battle-in-Egypt/ 18 + JoJo's P4,https://anilist.co/anime/21450/JoJos-Bizarre-Adventure-Diamond-is-Unbreakable/ 19 + Attack on Titan,https://anilist.co/anime/16498/Attack-on-Titan/ 20 + Attack on Titan S4,https://anilist.co/anime/110277/Attack-on-Titan-Final-Season/ 21 + Attack on Titan S4P2,https://anilist.co/anime/131681/Attack-on-Titan-Final-Season-Part-2/ 22 + Attack on Titan S3,https://anilist.co/anime/99147/Attack-on-Titan-Season-3/ 23 + Attack on Titan S2,https://anilist.co/anime/20958/Attack-on-Titan-Season-2/ 24 + Attack on Titan S3P2,https://anilist.co/anime/104578/Attack-on-Titan-Season-3-Part-2/ 25 + Hell's Paradise,https://anilist.co/anime/128893/Hells-Paradise/ 26 + Death Note,https://anilist.co/anime/1535/Death-Note/ 27 + Attack on Titan S4P3S1,https://anilist.co/anime/146984/Attack-on-Titan-Final-Season-THE-FINAL-CHAPTERS-Special-1/ 28 + Attack on Titan S4P3S2,https://anilist.co/anime/162314/Attack-on-Titan-Final-Season-THE-FINAL-CHAPTERS-Special-2/ 29 + Cyberpunk: Edgerunners,https://anilist.co/anime/120377/Cyberpunk-Edgerunners/ 30 + My Hero Academia S7,https://anilist.co/anime/163139/My-Hero-Academia-Season-7/ 31 + Mushoku Tensei S2P2,https://anilist.co/anime/166873/Mushoku-Tensei-Jobless-Reincarnation-Season-2-Part-2/ 32 + Demon Slayer S4,https://anilist.co/anime/166240/Demon-Slayer-Kimetsu-no-Yaiba-Hashira-Training-Arc/ 33 + Demon Slayer S2,https://anilist.co/anime/142329/Demon-Slayer-Kimetsu-no-Yaiba-Entertainment-District-Arc/ 34 + Fate/Zero,https://anilist.co/anime/10087/FateZero/ 35 + Bocchi the Rock,https://anilist.co/anime/130003/BOCCHI-THE-ROCK/ 36 + Demon Slayer S3,https://anilist.co/anime/145139/Demon-Slayer-Kimetsu-no-Yaiba-Swordsmith-Village-Arc/ 37 + Demon Slayer: Mugen Train,https://anilist.co/anime/112151/Demon-Slayer-Kimetsu-no-Yaiba-The-Movie-Mugen-Train/ 38 + Demon Slayer,https://anilist.co/anime/101922/Demon-Slayer-Kimetsu-no-Yaiba/ 39 + Blue Exorcist S3,https://anilist.co/anime/158931/Blue-Exorcist-Shimane-Illuminati-Saga/ 40 + Blue Exorcist S4,https://anilist.co/anime/176311/Blue-Exorcist-Beyond-the-Snow-Saga/ 41 + Jujutsu Kaisen 0,https://anilist.co/anime/131573/JUJUTSU-KAISEN-0/ 42 + Attack on Titan: No Regrets,https://anilist.co/anime/20811/Attack-on-Titan-No-Regrets/ 43 + Blue Exorcist S2,https://anilist.co/anime/21861/Blue-Exorcist-Kyoto-Saga/ 44 + Blue Exorcist,https://anilist.co/anime/9919/Blue-Exorcist/,If episodes 17-25 didn't exist this would be higher than Season 2 45 + 7th Time Loop,https://anilist.co/anime/168374/7th-Time-Loop-The-Villainess-Enjoys-a-Carefree-Life-Married-to-Her-Worst-Enemy/ 46 + Campfire Cooking,https://anilist.co/anime/156067/Campfire-Cooking-in-Another-World-with-my-Absurd-Skill/ 47 + Mashle,https://anilist.co/anime/151801/MASHLE-MAGIC-AND-MUSCLES/ 48 + Mashle S2,https://anilist.co/anime/166610/MASHLE-MAGIC-AND-MUSCLES-Season-2/ 49 + 86,https://anilist.co/anime/116589/86-EIGHTYSIX/ 50 + 86 S2,https://anilist.co/anime/131586/86-EIGHTYSIX-Part-2/ 51 + AMAIM,https://anilist.co/anime/143203/AMAIM-Warrior-at-the-Borderline-Part-2/ 52 + Aldnoah.Zero,https://anilist.co/anime/20632/ALDNOAHZERO/
+86
src/website/page/anime.gleam
··· 1 + import gleam/float 2 + import gleam/int 3 + import gleam/list 4 + import gleam/option.{None, Some} 5 + import lustre/attribute as attr 6 + import lustre/element.{type Element} 7 + import lustre/element/html 8 + import lustre/ssg/djot 9 + import website/common.{type Anime} 10 + import website/md 11 + 12 + fn score(index: Int, length: Int) -> Int { 13 + float.truncate(int.to_float(length - index) /. int.to_float(length) *. 100.0) 14 + } 15 + 16 + pub fn view(anime: List(Anime)) -> List(Element(a)) { 17 + let length = list.length(anime) 18 + [ 19 + html.div( 20 + [ 21 + attr.class( 22 + "drop-shadow-md text-xl p-4 mb-4 rounded-xl bg-gray-200 dark:bg-neutral-800 dark:text-neutral-200", 23 + ), 24 + ], 25 + { 26 + "This is a non-comprehensive list of anime I have watched, sorted by whether or not I liked an anime more than the one below it. The \"score\" displayed on the left of each anime isn't technically decided by me and is actually dynamically created using the very basic formula: 27 + `(list_length - anime_index) / list_length * 100` 28 + where `anime_index` starts at `0` for the top-most anime. The (scoreless) list is [stored as a CSV](https://codeberg.org/naomi/website/src/branch/main/src/website/data/anime.csv) in the source code for the website, and is updated whenever I feel like it. 29 + I've also included some notes on some of the animes where I feel that I have something to comment on. 30 + Currently `" 31 + <> int.to_string(length) 32 + <> "` out of my (educated guess) `300+` watched anime are listed." 33 + } 34 + |> djot.content() 35 + |> md.render(), 36 + ), 37 + html.div( 38 + [attr.class("grid grid-cols-[min-content_33%_auto] gap-x-4")], 39 + list.index_map(anime, fn(a, i) { anime_entry(a, i, length) }) 40 + |> list.flatten(), 41 + ), 42 + ] 43 + } 44 + 45 + fn anime_entry( 46 + anime a: common.Anime, 47 + index i: Int, 48 + length length: Int, 49 + ) -> List(Element(a)) { 50 + [ 51 + html.p( 52 + [ 53 + attr.class( 54 + "drop-shadow-md text-xl p-4 mb-4 rounded-xl bg-gray-200 dark:bg-neutral-800 dark:text-neutral-200", 55 + ), 56 + ], 57 + [element.text(int.to_string(score(i, length)) <> "/100")], 58 + ), 59 + html.p( 60 + [ 61 + attr.class( 62 + "drop-shadow-md text-xl p-4 mb-4 rounded-xl bg-gray-200 dark:bg-neutral-800 dark:text-neutral-200", 63 + ), 64 + ], 65 + [ 66 + case a.link { 67 + None -> element.text(a.title) 68 + Some(link) -> common.link(a.title, link) 69 + }, 70 + ], 71 + ), 72 + html.p( 73 + [ 74 + attr.class( 75 + "drop-shadow-md text-xl p-4 mb-4 rounded-xl bg-gray-200 dark:bg-neutral-800 dark:text-neutral-200", 76 + ), 77 + ], 78 + [ 79 + case a.thoughts { 80 + None -> element.text("Nothing to add") 81 + Some(thoughts) -> element.text(thoughts) 82 + }, 83 + ], 84 + ), 85 + ] 86 + }