From 7042020ca092c6d691d49983545bf9c82469ab22 Mon Sep 17 00:00:00 2001 From: Stachu Korick Date: Tue, 4 Nov 2025 18:16:54 -0500 Subject: [PATCH] add sm64net canvas and package support --- backend/src/LocalExec/Canvas.fs | 1 + backend/src/LocalExec/LocalExec.fs | 21 +- canvases/dark-sm64net/config.yml | 2 + canvases/dark-sm64net/main.dark | 309 +++++++++++++++++++++ packages/stachu/sm64/core.dark | 16 ++ packages/stachu/sm64/courses.dark | 284 +++++++++++++++++++ packages/stachu/sm64/layout.dark | 249 +++++++++++++++++ packages/stachu/sm64/stars.dark | 234 ++++++++++++++++ packages/stachu/sm64/views/contribute.dark | 14 + packages/stachu/sm64/views/game.dark | 10 + packages/stachu/sm64/views/home.dark | 186 +++++++++++++ packages/stachu/sm64/views/stages.dark | 36 +++ 12 files changed, 1361 insertions(+), 1 deletion(-) create mode 100644 canvases/dark-sm64net/config.yml create mode 100644 canvases/dark-sm64net/main.dark create mode 100644 packages/stachu/sm64/core.dark create mode 100644 packages/stachu/sm64/courses.dark create mode 100644 packages/stachu/sm64/layout.dark create mode 100644 packages/stachu/sm64/stars.dark create mode 100644 packages/stachu/sm64/views/contribute.dark create mode 100644 packages/stachu/sm64/views/game.dark create mode 100644 packages/stachu/sm64/views/home.dark create mode 100644 packages/stachu/sm64/views/stages.dark diff --git a/backend/src/LocalExec/Canvas.fs b/backend/src/LocalExec/Canvas.fs index e965b4e3c0..51940c4a45 100644 --- a/backend/src/LocalExec/Canvas.fs +++ b/backend/src/LocalExec/Canvas.fs @@ -80,6 +80,7 @@ let loadFromDisk } // i.e. dark-packages -> ("Darklang", "Packages") + // dark-sm64net -> ("Darklang", "Sm64net") let (ownerName, canvasName) = if String.startsWith "dark-" canvasName then let canvasName = canvasName |> String.dropLeft 5 diff --git a/backend/src/LocalExec/LocalExec.fs b/backend/src/LocalExec/LocalExec.fs index 02b36fd2c6..6f8e008790 100644 --- a/backend/src/LocalExec/LocalExec.fs +++ b/backend/src/LocalExec/LocalExec.fs @@ -24,6 +24,16 @@ module HandleCommand = return Ok() } + let reloadSm64NetCanvas () : Ply> = + uply { + let! (canvasId, toplevels) = + Canvas.loadFromDisk LibPackageManager.PackageManager.pt "dark-sm64net" + + print $"Loaded canvas {canvasId} with {List.length toplevels} toplevels" + + return Ok() + } + let reloadPackages () : Ply> = uply { // first, load the packages from disk, ensuring all parse well @@ -65,10 +75,13 @@ module HandleCommand = //do! PM.flushCheckpoint () - // Reload dark-packages canvas after package reload + // Reload canvases after package reload print "Reloading dark-packages canvas..." let! _ = reloadDarkPackagesCanvas () + print "Reloading dark-sm64net canvas..." + let! _ = reloadSm64NetCanvas () + return Ok() } @@ -163,11 +176,17 @@ let main (args : string[]) : int = "loading dark-packages canvas from disk" (HandleCommand.reloadDarkPackagesCanvas ()) + | [ "reload-sm64net-canvas" ] -> + handleCommand + "loading dark-sm64net canvas from disk" + (HandleCommand.reloadSm64NetCanvas ()) + | _ -> print "Invalid arguments" print "Available commands:" print " reload-packages" print " reload-dark-packages-canvas" + print " reload-sm64net-canvas" print " migrations run" print " migrations list" NonBlockingConsole.wait () diff --git a/canvases/dark-sm64net/config.yml b/canvases/dark-sm64net/config.yml new file mode 100644 index 0000000000..c6fec492d6 --- /dev/null +++ b/canvases/dark-sm64net/config.yml @@ -0,0 +1,2 @@ +id: 22222222-2222-2222-2222-222222222222 +main: main diff --git a/canvases/dark-sm64net/main.dark b/canvases/dark-sm64net/main.dark new file mode 100644 index 0000000000..02cb37eef2 --- /dev/null +++ b/canvases/dark-sm64net/main.dark @@ -0,0 +1,309 @@ +// SM64.net website canvas + +[] +let _handler _req = Stdlib.Http.response (Stdlib.String.toBytes "pong") 200L + + +[] +let _handler _req = + let html = + Stachu.SM64.Views.Home.view |> Stachu.SM64.Layout.layoutWithoutNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + Stachu.SM64.Views.Contribute.view |> Stachu.SM64.Layout.layoutWithoutNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + Stachu.SM64.Views.Game.view |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + Stachu.SM64.Views.Stages.view |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Plot" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "Princess Peach invites Mario to her castle..." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Mechanics" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "SM64 features various movement mechanics including jumping, diving, and wall kicks." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Castle" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "Peach's Castle is the central hub of Super Mario 64." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Characters" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "Mario, Princess Peach, Bowser, and many others..." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Standard Courses" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "There are 15 standard courses in Super Mario 64." ] + Stdlib.Html.ul + [] + [ Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "Bob-omb Battlefield (BoB)" ] + Stdlib.Html.li [] [ Stdlib.Html.stringNode "Whomp's Fortress (WF)" ] + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "Jolly Roger Bay (JRB)" ] + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "Cool, Cool Mountain (CCM)" ] + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "Big Boo's Haunt (BBH)" ] ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Secret Stages" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Secret stages with single stars." ] ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Bowser Stages" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "The three Bowser stages and their red coins." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "All Stars" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "There are 120 stars total in Super Mario 64." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Speedrunning" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "SM64 speedrunning has various categories including 0 star, 1 star, 16 star, 70 star, and 120 star." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Records" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "World records for SM64." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Rankings" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Rankings of speedrunners." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Categories" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Speedrunning categories." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Routes" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Speedrun routes." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Speedrunners" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Notable SM64 speedrunners." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Strategies" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Speedrunning strategies." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Competitions" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "SM64 competitions." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Challenges" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "SM64 challenges." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Tools" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Tools for SM64 speedrunning." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Usamune" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "Usamune tool." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L + + +[] +let _handler _req = + let html = + (Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Twitch Bot" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "A Twitch bot for SM64 information." ] ]) + |> Stachu.SM64.Layout.layoutWithNav + + Stdlib.Http.responseWithHtml html 200L diff --git a/packages/stachu/sm64/core.dark b/packages/stachu/sm64/core.dark new file mode 100644 index 0000000000..293a6e22a6 --- /dev/null +++ b/packages/stachu/sm64/core.dark @@ -0,0 +1,16 @@ +/// Core SM64 types and helpers +module Stachu.SM64.Core + +type SupportedGameRelease = + | NA + + +type EntryRequirement = + /// At least "n" stars are required to open the door normally + | MinimumStarCount of Int64 + /// Entry to the star is in the basement + | IsInBasement + /// Entry to the star is upstairs + | IsUpstairs + /// Entry to the star is in the "tippy" top of the castle + | IsInTippy diff --git a/packages/stachu/sm64/courses.dark b/packages/stachu/sm64/courses.dark new file mode 100644 index 0000000000..5e7b1aa3f8 --- /dev/null +++ b/packages/stachu/sm64/courses.dark @@ -0,0 +1,284 @@ +/// SM64 Course definitions +module Stachu.SM64.Courses + +type StandardCourse = + | BobOmbBattlefield + | WhompsFortress + | JollyRogerBay + | CoolCoolMountain + | BigBoosHaunt + | HazyMazyCave + | LethalLavaLand + | ShiftingSandLand + | DireDireDocks + | SnowmanLand + | WetDryWorld + | TallTallMountain + | TinyHugeIsland + | TickTockClock + | RainbowRide + + +type StandardCourseInfo = + { name: String + courseNumber: Int64 + abbreviation: String + entryRequirements: List } + + +let getInfoForStandardCourse + (gameRelease: Stachu.SM64.Core.SupportedGameRelease) + (standardCourse: StandardCourse) + : StandardCourseInfo = + match standardCourse with + | BobOmbBattlefield -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Bob-omb Battlefield") + courseNumber = 1L + abbreviation = "BoB" + entryRequirements = [] } + + | WhompsFortress -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Whomp's Fortress") + courseNumber = 2L + abbreviation = "WF" + entryRequirements = + [ Stachu.SM64.Core.EntryRequirement.MinimumStarCount 1L ] } + + | JollyRogerBay -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Jolly Roger Bay") + courseNumber = 3L + abbreviation = "JRB" + entryRequirements = + [ Stachu.SM64.Core.EntryRequirement.MinimumStarCount 3L ] } + + | CoolCoolMountain -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Cool, Cool Mountain") + courseNumber = 4L + abbreviation = "CCM" + entryRequirements = + [ Stachu.SM64.Core.EntryRequirement.MinimumStarCount 3L ] } + + | BigBoosHaunt -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Big Boo's Haunt") + courseNumber = 5L + abbreviation = "BBH" + entryRequirements = [] } + + | HazyMazyCave -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Hazy Mazy Cave") + courseNumber = 6L + abbreviation = "HMC" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInBasement ] } + + | LethalLavaLand -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Lethal Lava Land") + courseNumber = 7L + abbreviation = "LLL" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInBasement ] } + + | ShiftingSandLand -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Shifting Sand Land") + courseNumber = 8L + abbreviation = "SSL" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInBasement ] } + + | DireDireDocks -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Dire, Dire Docks") + courseNumber = 9L + abbreviation = "DDD" + entryRequirements = + [ Stachu.SM64.Core.EntryRequirement.IsInBasement + Stachu.SM64.Core.EntryRequirement.MinimumStarCount 30L ] } + + | SnowmanLand -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Snowman's Land") + courseNumber = 10L + abbreviation = "SL" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsUpstairs ] } + + | WetDryWorld -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Wet-Dry World") + courseNumber = 11L + abbreviation = "WDW" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsUpstairs ] } + + | TallTallMountain -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Tall, Tall Mountain") + courseNumber = 12L + abbreviation = "TTM" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsUpstairs ] } + + | TinyHugeIsland -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Tiny-Huge Island") + courseNumber = 13L + abbreviation = "THI" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsUpstairs ] } + + | TickTockClock -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Tick Tock Clock") + courseNumber = 14L + abbreviation = "TTC" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInTippy ] } + + | RainbowRide -> + StandardCourseInfo + { name = + (match gameRelease with + | NA -> "Rainbow Ride") + courseNumber = 15L + abbreviation = "RR" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInTippy ] } + + +type SecretStage = + | PrincessSecretSlide + | TowerOfTheWingCap + | VanishCapUnderTheMoat + | CavernOfTheMetalCave + | SecretAquarium + | Cloud + + +type SecretStageInfo = + { name: String + abbreviation: String + entryRequirements: List } + + +let getSecretStageInfo + (gameRelease: Stachu.SM64.Core.SupportedGameRelease) + (secretStage: SecretStage) + : SecretStageInfo = + match secretStage with + | PrincessSecretSlide -> + SecretStageInfo + { name = + (match gameRelease with + | NA -> "Princess Secret Slide") + abbreviation = "PSS" + entryRequirements = [] } + + | TowerOfTheWingCap -> + SecretStageInfo + { name = + (match gameRelease with + | NA -> "Tower of the Wing Cap") + abbreviation = "ToTWC" + entryRequirements = + [ Stachu.SM64.Core.EntryRequirement.MinimumStarCount 10L ] } + + | VanishCapUnderTheMoat -> + SecretStageInfo + { name = + (match gameRelease with + | NA -> "Vanish Cap Under the Moat") + abbreviation = "CotMC" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInBasement ] } + + | CavernOfTheMetalCave -> + SecretStageInfo + { name = + (match gameRelease with + | NA -> "Cavern of the Metal Cap") + abbreviation = "VCutM" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInBasement ] } + + | SecretAquarium -> + SecretStageInfo + { name = + (match gameRelease with + | NA -> "The Secret Aquarium") + abbreviation = "SA" + entryRequirements = [] } + + | Cloud -> + SecretStageInfo + { name = + (match gameRelease with + | NA -> "The Secret Aquarium") + abbreviation = "SA" + entryRequirements = [ Stachu.SM64.Core.EntryRequirement.IsInBasement ] } + + +type BowserStage = + | BitDW + | BitFS + | BitS + + +type BowserStageInfo = + { name: String + abbreviation: String + entryRequirements: List } + + +let getBowserStageInfo + (gameRelease: Stachu.SM64.Core.SupportedGameRelease) + (bowserStage: BowserStage) + : BowserStageInfo = + match bowserStage with + | BitDW -> + BowserStageInfo + { name = + (match gameRelease with + | NA -> "Bowser in the Dark World") + abbreviation = "BitDW" + entryRequirements = [] } + + | BitFS -> + BowserStageInfo + { name = + (match gameRelease with + | NA -> "Bowser in the Fire Sea") + abbreviation = "BitFS" + entryRequirements = [] } + + | BitS -> + BowserStageInfo + { name = + (match gameRelease with + | NA -> "Bowser in the Sky") + abbreviation = "BitS" + entryRequirements = [] } diff --git a/packages/stachu/sm64/layout.dark b/packages/stachu/sm64/layout.dark new file mode 100644 index 0000000000..f733f719d1 --- /dev/null +++ b/packages/stachu/sm64/layout.dark @@ -0,0 +1,249 @@ +/// SM64.net Layout and HTML helpers +module Stachu.SM64.Layout + +type SiteRoute = + | Home + | Contribute + // Core + | Game + | Plot + | Mechanics + | Castle + | Characters + | Stages + | StandardCourses + | StandardCourse of Stachu.SM64.Courses.StandardCourse + | StandardCourseStar of Stachu.SM64.Stars.StandardCourseStar + | SecretStages + | SecretStage of Stachu.SM64.Courses.SecretStage + | SecretStageStar of Stachu.SM64.Courses.SecretStage + | BowserStages + | BowserStage of Stachu.SM64.Courses.BowserStage + | BowserStageReds of Stachu.SM64.Courses.BowserStage + | AllStars + // Speedrunning + | Speedrunning + | Records + | Rankings + | Categories + | Speedrunners + | Speedrunner of String + | Strategies + | Routes + | Competitions + | Challenges + // Tools + | Tools + | Usamune + | TwitchBot + + +let routePath (route: SiteRoute) : String = + match route with + | Home -> "/" + | Contribute -> "/contribute" + // Core + | Game -> "/game" + | Plot -> "/plot" + | Mechanics -> "/mechanics" + | Characters -> "/characters" + | Castle -> "/castle" + | Stages -> "/stages" + | StandardCourses -> "/stages/courses" + | StandardCourse stage -> + let stageInfo = + Stachu.SM64.Courses.getInfoForStandardCourse + Stachu.SM64.Core.SupportedGameRelease.NA + stage + + "/stages/courses/" ++ stageInfo.abbreviation + + | StandardCourseStar star -> + let starInfo = Stachu.SM64.Stars.getStandardCourseStarInfo star + let (course, placement) = starInfo.courseConnection + + let courseInfo = + Stachu.SM64.Courses.getInfoForStandardCourse + Stachu.SM64.Core.SupportedGameRelease.NA + course + + let placementInt = Stachu.SM64.Stars.starNumberToInt placement + "/stars/" ++ courseInfo.abbreviation ++ "/" ++ (Stdlib.Int64.toString placementInt) + + | SecretStages -> "/stages/secret" + | SecretStage stage -> + let stageInfo = + Stachu.SM64.Courses.getSecretStageInfo + Stachu.SM64.Core.SupportedGameRelease.NA + stage + + "/stages/secret/" ++ stageInfo.abbreviation + + | SecretStageStar stage -> + let stageInfo = + Stachu.SM64.Courses.getSecretStageInfo + Stachu.SM64.Core.SupportedGameRelease.NA + stage + + "/stages/secret/" ++ stageInfo.abbreviation ++ "/star" + + | BowserStages -> "/stages/bowser" + | BowserStage stage -> + let stageInfo = + Stachu.SM64.Courses.getBowserStageInfo + Stachu.SM64.Core.SupportedGameRelease.NA + stage + + "/stages/bowser/" ++ stageInfo.abbreviation + + | BowserStageReds stage -> + let stageInfo = + Stachu.SM64.Courses.getBowserStageInfo + Stachu.SM64.Core.SupportedGameRelease.NA + stage + + "/stages/bowser/" ++ stageInfo.abbreviation ++ "/reds" + + | AllStars -> "/stars" + // Speedrunning + | Speedrunning -> "/speedrunning" + | Records -> "/speedrunning/records" + | Rankings -> "/speedrunning/rankings" + | Categories -> "/speedrunning/categories" + | Routes -> "/speedrunning/routes" + | Speedrunners -> "/speedrunning/speedrunners" + | Speedrunner handle -> "/speedrunning/speedrunners/" ++ handle + | Strategies -> "/speedrunning/strategies" + | Competitions -> "/speedrunning/competitions" + | Challenges -> "/speedrunning/challenges" + // Tools + | Tools -> "/tools" + | Usamune -> "/tools/usamune" + | TwitchBot -> "/tools/twitch-bot" + + +let bracketLink (path: String) (text: String) : Stdlib.Html.Node = + Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some path) ] + [ Stdlib.Html.stringNode ("[" ++ text ++ "]") ] + + +let navLink (text: String) (path: String) : Stdlib.Html.Node = + Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some path) + ("class", Stdlib.Option.Option.Some "navbar-item") ] + [ Stdlib.Html.stringNode text ] + + +let nav : Stdlib.Html.Node = + Stdlib.Html.nav + [ ("role", Stdlib.Option.Option.Some "navigation") + ("aria-label", Stdlib.Option.Option.Some "main navigation") + ("class", Stdlib.Option.Option.Some "navbar") ] + [ Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "navbar-brand") ] + [ Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some (routePath SiteRoute.Home)) + ("class", Stdlib.Option.Option.Some "navbar-item") ] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "sm64.net" ] ] ] + + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "navbar-menu") ] + [ Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "navbar-end") ] + [ Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some (routePath SiteRoute.Home)) + ("class", Stdlib.Option.Option.Some "navbar-item") ] + [ Stdlib.Html.stringNode "?" ] + + // The Game dropdown + Stdlib.Html.div + [ ("class", + Stdlib.Option.Option.Some "navbar-item has-dropdown is-hoverable") ] + [ Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some (routePath SiteRoute.Game)) + ("class", Stdlib.Option.Option.Some "navbar-link") ] + [ Stdlib.Html.stringNode "The Game" ] + + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "navbar-dropdown") ] + [ navLink "The Game" (routePath SiteRoute.Game) + Stdlib.Html.htmlTagNode "hr" [ ("class", Stdlib.Option.Option.Some "navbar-divider") ] [] + navLink "Plot" (routePath SiteRoute.Plot) + navLink "Mechanics" (routePath SiteRoute.Mechanics) + navLink "Castle" (routePath SiteRoute.Castle) + navLink "Characters" (routePath SiteRoute.Characters) + navLink "Stages" (routePath SiteRoute.Stages) + navLink "Stars" (routePath SiteRoute.AllStars) ] ] + + // Speedrunning dropdown + Stdlib.Html.div + [ ("class", + Stdlib.Option.Option.Some "navbar-item has-dropdown is-hoverable") ] + [ Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some (routePath SiteRoute.Speedrunning)) + ("class", Stdlib.Option.Option.Some "navbar-link") ] + [ Stdlib.Html.stringNode "Speedrunning" ] + + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "navbar-dropdown") ] + [ navLink "Speedrunning" (routePath SiteRoute.Speedrunning) + Stdlib.Html.htmlTagNode "hr" [ ("class", Stdlib.Option.Option.Some "navbar-divider") ] [] + navLink "Records" (routePath SiteRoute.Records) + navLink "Rankings" (routePath SiteRoute.Rankings) + navLink "Categories" (routePath SiteRoute.Categories) + navLink "Routes" (routePath SiteRoute.Routes) + navLink "Speedrunners" (routePath SiteRoute.Speedrunners) + navLink "Strategies" (routePath SiteRoute.Strategies) + navLink "Competitions" (routePath SiteRoute.Competitions) + navLink "Challenges" (routePath SiteRoute.Challenges) ] ] + + // Tools dropdown + Stdlib.Html.div + [ ("class", + Stdlib.Option.Option.Some "navbar-item has-dropdown is-hoverable") ] + [ Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some (routePath SiteRoute.Tools)) + ("class", Stdlib.Option.Option.Some "navbar-link") ] + [ Stdlib.Html.stringNode "Tools" ] + + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "navbar-dropdown") ] + [ navLink "Tools" (routePath SiteRoute.Tools) + Stdlib.Html.htmlTagNode "hr" [ ("class", Stdlib.Option.Option.Some "navbar-divider") ] [] + navLink "Usamune" (routePath SiteRoute.Usamune) + navLink "Twitch Bot" (routePath SiteRoute.TwitchBot) ] ] ] ] ] + + +let layout (shouldDisplayNav: Bool) (content: Stdlib.Html.Node) : String = + let nodes = + [ Stdlib.Html.html + [] + [ Stdlib.Html.head + [] + [ Stdlib.Html.link + [ ("href", + Stdlib.Option.Option.Some + "https://cdn.jsdelivr.net/npm/bulma@0.9.0/css/bulma.css") + ("rel", Stdlib.Option.Option.Some "stylesheet") ] ] + + Stdlib.Html.body + [] + [ Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "container") ] + (if shouldDisplayNav then + [ nav + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "content") ] + [ content ] ] + else + [ content ]) ] ] ] + + Stdlib.Html.document nodes + + +let layoutWithoutNav (content: Stdlib.Html.Node) : String = + layout false content + + +let layoutWithNav (content: Stdlib.Html.Node) : String = layout true content diff --git a/packages/stachu/sm64/stars.dark b/packages/stachu/sm64/stars.dark new file mode 100644 index 0000000000..5a3e9b6418 --- /dev/null +++ b/packages/stachu/sm64/stars.dark @@ -0,0 +1,234 @@ +/// SM64 Star definitions +module Stachu.SM64.Stars + +// This type represents each of the 6 "regular" stars within the 15 standard courses +type StandardCourseStar = + // BoB - Standard Course #1 + | BigBobOmbOnTheSummit // 1 + | FootraceWithKoopaTheQuick // 2 + | ShootIntoTheWildSky // 3 + | FindThe8RedCoins // 4 + | MarioWingsToTheSky // 5 + | BehindChainChompsGate // 6 + // Whomp's - Standard Course #2 + | ChipOffWhompsBlock // 1 + | ToTheTopOfTheFortress // 2 + | ShootIntoTheWildBlue // 3 + | RedCoinsOnTheFloatingIsle // 4 + | FallOntoTheCagedIsland // 5 + | BlastAwayTheWall // 6 + // JRB - Standard Course #3 + | PlunderInTheSunkenShip // 1 + | CanTheEelComeOutAndPlay // 2 + | TreasureOfTheOceanCave // 3 + | RedCoinsOnTheShipAfloat // 4 + | BlastToTheStonePillar // 5 + | ThroughTheJetStream // 6 + // CCM - Standard Course #4 + | SlipSlidinAway // 1 + | LilPenguinLost // 2 + | BigPenguinRace // 3 + | FrostySlideFor8RedCoins // 4 + | SnowmanLostHisHead // 5 + | WallKicksWillWork // 6 + // BBH - Standard Course #5 + | GoOnAGhostHunt // 1 + | SeekThe8RedCoins // 2 + | EyeToEyeInTheSecretRoom // 3 + | RideBigBoosMerryGoRound // 4 + | BigBoosBalcony // 5 + | SecretOfTheHauntedBooks // 6 + // HMC - Standard Course #6 + | SwimmingBeastInTheCavern // 1 + | ElevateFor8RedCoins // 2 + | MetalHeadMarioCanMove // 3 + | NavigatingTheToxicMaze // 4 + | AMazeingEmergencyExit // 5 + | WatchForRollingRocks // 6 + // LLL - Standard Course #7 + | BoilTheBigBully // 1 + | BullyTheBullies // 2 + | EightCoinPuzzleWith15Pieces // 3 + | RedHotLogRolling // 4 + | HotFootItIntoTheVolcano // 5 + | ElevatorTourInTheVolcano // 6 + // SSL - Standard Course #8 + | InTheTalonsOfTheBigBird // 1 + | ShiningAtopThePyramid // 2 + | InsideTheAncientPyramid // 3 + | StandTallOnTheFourPillars // 4 + | FreeFlyingFor8RedCoins // 5 + | PyramidPuzzle // 6 + // DDD - Standard Course #9 + | BoardBowsersSub // 1 + | ChestsInTheCurrent // 2 + | PoleJumpingForRedCoins // 3 + | ThroughTheJetStreams // 4 + | TheMantaRaysReward // 5 + | CollectTheCaps // 6 + // SL/SML - Standard Course #10 + | SnowmansBigHead // 1 + | ChillWithTheBully // 2 + | InTheDeepFreeze // 3 + | WhirlFromTheFreezingPond // 4 + | ShellShreddinForRedCoins // 5 + | IntoTheIgloo // 6 + // WDW - Standard Course #11 + | ShockingArrowLifts // 1 + | TopOfTheTown // 2 + | SecretsInTheShallowsAndSky // 3 + | ExpressElevatorHurryUp // 4 + | GoToTownForRedCoins // 5 + | QuickRaceThroughDowntown // 6 + // TTM - Standard Course #12 + | ScaleTheMountain // 1 + | MysteryOfTheMonkeyCage // 2 + | ScaryShroomsRedCoins // 3 + | MysteriousMountainside // 4 + | BreathtakingViewFromTheBridge // 5 + | BlastToTheLonelyMushroom // 6 + // THI - Standard Course #13 + | PluckThePiranhaFlower // 1 + | TheTipTopOfTheHugeIsland // 2 + | RematchWithKoopaTheQuick // 3 + | FiveIttyBittySecrets // 4 + | WigglersRedCoins // 5 + | MakeWigglerSquirm // 6 + // TTC - Standard Course #14 + | RollIntoTheCage // 1 + | ThePitAndThePendulums // 2 + | GetAHand // 3 + | StompOnTheThwomp // 4 + | TimedJumpsOnMovingBars // 5 + | StopTimeForRedCoins // 6 + // RR - Standard Course #15 + | CruiserCrossingTheRainbow // 1 + | TheBigHouseInTheSky // 2 + | CoinsAmassedInAMaze // 3 + | SwinginInTheBreeze // 4 + | TrickyTriangles // 5 + | SomewhereOverTheRainbow // 6 + + +type StarNumber = + | One + | Two + | Three + | Four + | Five + | Six + + +let starNumberToInt (sn: StarNumber) : Int64 = + match sn with + | One -> 1L + | Two -> 2L + | Three -> 3L + | Four -> 4L + | Five -> 5L + | Six -> 6L + + +type StandardCourseStarInfo = + { name: String + courseConnection: Stachu.SM64.Courses.StandardCourse * StarNumber } + + +let getStandardCourseStarInfo (star: StandardCourseStar) : StandardCourseStarInfo = + match star with + | BigBobOmbOnTheSummit -> + StandardCourseStarInfo + { name = "Big Bob-omb on the Summit" + courseConnection = (Stachu.SM64.Courses.StandardCourse.BobOmbBattlefield, StarNumber.One) } + + | FootraceWithKoopaTheQuick -> + StandardCourseStarInfo + { name = "Footrace with Koopa the Quick" + courseConnection = (Stachu.SM64.Courses.StandardCourse.BobOmbBattlefield, StarNumber.Two) } + + | ShootIntoTheWildSky -> + StandardCourseStarInfo + { name = "Shoot into the Wild Sky" + courseConnection = (Stachu.SM64.Courses.StandardCourse.BobOmbBattlefield, StarNumber.Three) } + + | FindThe8RedCoins -> + StandardCourseStarInfo + { name = "Find the 8 Red Coins" + courseConnection = (Stachu.SM64.Courses.StandardCourse.BobOmbBattlefield, StarNumber.Four) } + + | MarioWingsToTheSky -> + StandardCourseStarInfo + { name = "Mario Wings to the Sky" + courseConnection = (Stachu.SM64.Courses.StandardCourse.BobOmbBattlefield, StarNumber.Five) } + + | BehindChainChompsGate -> + StandardCourseStarInfo + { name = "Behind Chain Chomp's Gate" + courseConnection = (Stachu.SM64.Courses.StandardCourse.BobOmbBattlefield, StarNumber.Six) } + + | ChipOffWhompsBlock -> + StandardCourseStarInfo + { name = "Chip Off Whomp's Block" + courseConnection = (Stachu.SM64.Courses.StandardCourse.WhompsFortress, StarNumber.One) } + + | ToTheTopOfTheFortress -> + StandardCourseStarInfo + { name = "To the Top of the Fortress" + courseConnection = (Stachu.SM64.Courses.StandardCourse.WhompsFortress, StarNumber.Two) } + + | ShootIntoTheWildBlue -> + StandardCourseStarInfo + { name = "Shoot Into the Wild Blue" + courseConnection = (Stachu.SM64.Courses.StandardCourse.WhompsFortress, StarNumber.Three) } + + | RedCoinsOnTheFloatingIsle -> + StandardCourseStarInfo + { name = "Red Coins on the Floating Isle" + courseConnection = (Stachu.SM64.Courses.StandardCourse.WhompsFortress, StarNumber.Four) } + + | FallOntoTheCagedIsland -> + StandardCourseStarInfo + { name = "Fall Onto the Caged Island" + courseConnection = (Stachu.SM64.Courses.StandardCourse.WhompsFortress, StarNumber.Five) } + + | BlastAwayTheWall -> + StandardCourseStarInfo + { name = "Blast Away the Wall" + courseConnection = (Stachu.SM64.Courses.StandardCourse.WhompsFortress, StarNumber.Six) } + + // JRB + | PlunderInTheSunkenShip -> + StandardCourseStarInfo + { name = "Plunder in the Sunken Ship" + courseConnection = (Stachu.SM64.Courses.StandardCourse.JollyRogerBay, StarNumber.One) } + + | CanTheEelComeOutAndPlay -> + StandardCourseStarInfo + { name = "Can the Eel Come Out and Play?" + courseConnection = (Stachu.SM64.Courses.StandardCourse.JollyRogerBay, StarNumber.Two) } + + | TreasureOfTheOceanCave -> + StandardCourseStarInfo + { name = "Treasure of the Ocean Cave" + courseConnection = (Stachu.SM64.Courses.StandardCourse.JollyRogerBay, StarNumber.Three) } + + | RedCoinsOnTheShipAfloat -> + StandardCourseStarInfo + { name = "Red Coins on the Ship Afloat" + courseConnection = (Stachu.SM64.Courses.StandardCourse.JollyRogerBay, StarNumber.Four) } + + | BlastToTheStonePillar -> + StandardCourseStarInfo + { name = "Blast to the Stone Pillar" + courseConnection = (Stachu.SM64.Courses.StandardCourse.JollyRogerBay, StarNumber.Five) } + + | ThroughTheJetStream -> + StandardCourseStarInfo + { name = "Through the Jet Stream" + courseConnection = (Stachu.SM64.Courses.StandardCourse.JollyRogerBay, StarNumber.Six) } + + // I'll add stub entries for the rest to keep this manageable + | _ -> + StandardCourseStarInfo + { name = "TODO" + courseConnection = (Stachu.SM64.Courses.StandardCourse.BobOmbBattlefield, StarNumber.One) } diff --git a/packages/stachu/sm64/views/contribute.dark b/packages/stachu/sm64/views/contribute.dark new file mode 100644 index 0000000000..0b9536c4aa --- /dev/null +++ b/packages/stachu/sm64/views/contribute.dark @@ -0,0 +1,14 @@ +/// Contribute page view +module Stachu.SM64.Views.Contribute + +let view : Stdlib.Html.Node = + Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Contribute" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "Contributions are welcome! Find the source code on " + Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some "https://github.com/stachudotnet/sm64.net") ] + [ Stdlib.Html.stringNode "GitHub" ] + Stdlib.Html.stringNode "." ] ] diff --git a/packages/stachu/sm64/views/game.dark b/packages/stachu/sm64/views/game.dark new file mode 100644 index 0000000000..376596095d --- /dev/null +++ b/packages/stachu/sm64/views/game.dark @@ -0,0 +1,10 @@ +/// Game page view +module Stachu.SM64.Views.Game + +let view : Stdlib.Html.Node = + Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Super Mario 64" ] + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "Super Mario 64 is a 1996 platform game for the Nintendo 64." ] ] diff --git a/packages/stachu/sm64/views/home.dark b/packages/stachu/sm64/views/home.dark new file mode 100644 index 0000000000..a350da2ac4 --- /dev/null +++ b/packages/stachu/sm64/views/home.dark @@ -0,0 +1,186 @@ +/// Home page view +module Stachu.SM64.Views.Home + +let view : Stdlib.Html.Node = + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "columns is-desktop is-centered") ] + [ Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "column is-two-thirds-desktop") ] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "sm64.net" ] + + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "content is-medium") ] + [ Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "box") ] + [ Stdlib.Html.stringNode "This is a website centered around:" + + Stdlib.Html.ul + [] + [ Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "Super Mario 64, the core game itself" + + Stdlib.Html.ul + [] + [ Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "the " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Plot) + "plot" ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "core " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Mechanics) + "mechanics" ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "varied " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Characters) + "characters" ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "the " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Castle) + "castle" + Stdlib.Html.stringNode ", its " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Stages) + "stages" + Stdlib.Html.stringNode ", and their " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.AllStars) + "stars" ] ] ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "the " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Speedrunning) + "speedrunning" + Stdlib.Html.stringNode " of SM64" + + Stdlib.Html.ul + [] + [ Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "world " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Records) + "records" + Stdlib.Html.stringNode " and " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Rankings) + "rankings" + Stdlib.Html.stringNode " of major and minor " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Categories) + "categories" ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "speedrunner " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Speedrunners) + "profiles" ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "a directory of " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Strategies) + "strategies" + Stdlib.Html.stringNode " and " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Routes) + "routes" + Stdlib.Html.stringNode " used in speedrunning" ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "speedrunning " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Competitions) + "competitions" + Stdlib.Html.stringNode " and " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Challenges) + "challenges" ] ] ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "the world of [ROM Hacks], variants of the original Super Mario 64 game" ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "a directory of software " + Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Tools) + "tools" + Stdlib.Html.stringNode " to assist with speedrunning" + + Stdlib.Html.ul + [] + [ Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "[a trainer] to help you improve your speedrunning" ] + + Stdlib.Html.li + [] + [ Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.TwitchBot) + "a Twitch bot" + Stdlib.Html.stringNode " you can use to provide helpful '!sm64 ___' commands" ] ] ] + + Stdlib.Html.li + [] + [ Stdlib.Html.stringNode "a software development-focused [log] of how this site is being built" ] ] ] ] + + Stdlib.Html.div + [ ("class", Stdlib.Option.Option.Some "content is-small") ] + [ Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "This website is currently proof-of-concept / work-in-progress." ] + + Stdlib.Html.p + [] + [ Stdlib.Html.stringNode "Development is often streamed " + Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some "https://twitch.tv/stachudotnet") ] + [ Stdlib.Html.stringNode "on Twitch" ] + Stdlib.Html.stringNode " and source code available " + Stdlib.Html.a + [ ("href", Stdlib.Option.Option.Some "https://github.com/stachudotnet/sm64.net") ] + [ Stdlib.Html.stringNode "on GitHub" ] + Stdlib.Html.stringNode "." ] + + Stdlib.Html.p + [] + [ Stachu.SM64.Layout.bracketLink + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.Contribute) + "Contributions" + Stdlib.Html.stringNode " are welcome." ] ] ] ] diff --git a/packages/stachu/sm64/views/stages.dark b/packages/stachu/sm64/views/stages.dark new file mode 100644 index 0000000000..77931c5917 --- /dev/null +++ b/packages/stachu/sm64/views/stages.dark @@ -0,0 +1,36 @@ +/// Stages overview page view +module Stachu.SM64.Views.Stages + +let view : Stdlib.Html.Node = + Stdlib.Html.div + [] + [ Stdlib.Html.h1 [] [ Stdlib.Html.stringNode "Stages" ] + Stdlib.Html.p [] [ Stdlib.Html.stringNode "SM64 has multiple types of stages:" ] + Stdlib.Html.ul + [] + [ Stdlib.Html.li + [] + [ Stdlib.Html.a + [ ("href", + Stdlib.Option.Option.Some + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.StandardCourses)) ] + [ Stdlib.Html.stringNode "Standard Courses" ] ] + + Stdlib.Html.li + [] + [ Stdlib.Html.a + [ ("href", + Stdlib.Option.Option.Some + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.SecretStages)) ] + [ Stdlib.Html.stringNode "Secret Stages" ] ] + + Stdlib.Html.li + [] + [ Stdlib.Html.a + [ ("href", + Stdlib.Option.Option.Some + (Stachu.SM64.Layout.routePath + Stachu.SM64.Layout.SiteRoute.BowserStages)) ] + [ Stdlib.Html.stringNode "Bowser Stages" ] ] ] ]