···11+# webbed site
22+33+```sh
44+gleam run
55+gleam run -m serve
66+```
77+88+# Credits
99+1010+- The [Myna](https://github.com/sayyadirfanali/Myna) monospace font
1111+- [Inclusive Sans](https://github.com/LivKing/Inclusive-Sans)
···11+import gleam/bytes_tree
22+import gleam/erlang/process
33+import gleam/http/request.{type Request}
44+import gleam/http/response.{type Response}
55+import gleam/list
66+import gleam/string
77+import mist.{type Connection, type ResponseData}
88+import simplifile
99+1010+pub fn main() {
1111+ let assert Ok(_) =
1212+ mist.new(handler)
1313+ // Listen on all interfaces so I can check the site on my phone
1414+ // Careful if you're in a public wifi!
1515+ |> mist.bind("0.0.0.0")
1616+ |> mist.port(8080)
1717+ |> mist.start
1818+1919+ process.sleep_forever()
2020+}
2121+2222+fn handler(req: Request(Connection)) -> Response(ResponseData) {
2323+ let path = case req.path {
2424+ // I tinker with the css a lot so I like the direct updates
2525+ "/style.css" -> "/../assets/style.css"
2626+ "/" -> "/index.html"
2727+ p ->
2828+ case string.ends_with(p, "/") {
2929+ True -> p <> "index.html"
3030+ False ->
3131+ case string.contains(p, ".") {
3232+ True -> p
3333+ False -> p <> ".html"
3434+ }
3535+ }
3636+ }
3737+3838+ let file_path = "./dist" <> path
3939+4040+ case simplifile.read_bits(file_path) {
4141+ Ok(bits) ->
4242+ response.new(200)
4343+ |> response.set_header("content-type", get_content_type(path))
4444+ |> response.set_body(mist.Bytes(bytes_tree.from_bit_array(bits)))
4545+ Error(simplifile.Enoent) ->
4646+ response.new(404)
4747+ |> response.set_body(mist.Bytes(bytes_tree.from_string("Not Found")))
4848+ Error(_) ->
4949+ response.new(500)
5050+ |> response.set_body(
5151+ mist.Bytes(bytes_tree.from_string("Internal server error")),
5252+ )
5353+ }
5454+}
5555+5656+fn get_content_type(path: String) -> String {
5757+ case string.split(path, ".") |> list.last {
5858+ Ok("html") -> "text/html; charset=utf-8"
5959+ Ok("css") -> "text/css; charset=utf-8"
6060+ Ok("js") -> "application/javascript"
6161+ Ok("png") -> "image/png"
6262+ Ok("jpg") | Ok("jpeg") -> "image/jpeg"
6363+ Ok("svg") -> "image/svg+xml"
6464+ _ -> "application/octet-stream"
6565+ }
6666+}
+22
gleam.toml
···11+name = "webbed_site"
22+version = "1.0.0"
33+44+# Fill out these fields if you intend to generate HTML documentation or publish
55+# your project to the Hex package manager.
66+#
77+# description = ""
88+# licences = ["Apache-2.0"]
99+# repository = { type = "github", user = "", repo = "" }
1010+# links = [{ title = "Website", href = "" }]
1111+#
1212+# For a full reference of all the available options, you can have a look at
1313+# https://gleam.run/writing-gleam/gleam-toml/.
1414+1515+[dependencies]
1616+gleam_stdlib = ">= 0.44.0 and < 2.0.0"
1717+lustre_ssg = { git = "https://github.com/fruno-bulax/lustre_ssg", ref = "6c132bd34ab75a1144d31c0f896cab0e3cbf80fc" }
1818+lustre = ">= 5.4.0 and < 6.0.0"
1919+gleam_time = ">= 1.6.0 and < 2.0.0"
2020+simplifile = ">= 2.3.2 and < 3.0.0"
2121+tom = ">= 2.0.0 and < 3.0.0"
2222+shellout = ">= 1.7.0 and < 2.0.0"
+33
manifest.toml
···11+# This file was generated by Gleam
22+# You typically do not need to edit this file
33+44+packages = [
55+ { name = "envoy", version = "1.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "envoy", source = "hex", outer_checksum = "850DA9D29D2E5987735872A2B5C81035146D7FE19EFC486129E44440D03FD832" },
66+ { name = "exception", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "exception", source = "hex", outer_checksum = "329D269D5C2A314F7364BD2711372B6F2C58FA6F39981572E5CA68624D291F8C" },
77+ { name = "filepath", version = "1.1.2", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "filepath", source = "hex", outer_checksum = "B06A9AF0BF10E51401D64B98E4B627F1D2E48C154967DA7AF4D0914780A6D40A" },
88+ { name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" },
99+ { name = "gleam_erlang", version = "1.3.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_erlang", source = "hex", outer_checksum = "1124AD3AA21143E5AF0FC5CF3D9529F6DB8CA03E43A55711B60B6B7B3874375C" },
1010+ { name = "gleam_json", version = "3.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "44FDAA8847BE8FC48CA7A1C089706BD54BADCC4C45B237A992EDDF9F2CDB2836" },
1111+ { name = "gleam_otp", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_stdlib"], otp_app = "gleam_otp", source = "hex", outer_checksum = "BA6A294E295E428EC1562DC1C11EA7530DCB981E8359134BEABC8493B7B2258E" },
1212+ { name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
1313+ { name = "gleam_stdlib", version = "0.67.1", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "6CE3E4189A8B8EC2F73AB61A2FBDE49F159D6C9C61C49E3B3082E439F260D3D0" },
1414+ { name = "gleam_time", version = "1.6.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "0DF3834D20193F0A38D0EB21F0A78D48F2EC276C285969131B86DF8D4EF9E762" },
1515+ { name = "houdini", version = "1.2.0", build_tools = ["gleam"], requirements = [], otp_app = "houdini", source = "hex", outer_checksum = "5DB1053F1AF828049C2B206D4403C18970ABEF5C18671CA3C2D2ED0DD64F6385" },
1616+ { name = "jot", version = "8.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "houdini", "splitter"], otp_app = "jot", source = "hex", outer_checksum = "CCE11C8904B129CC9DA3A293B645884B91C96D252183F6DBCAEFA8F2587CAEFD" },
1717+ { name = "lustre", version = "5.4.0", build_tools = ["gleam"], requirements = ["gleam_erlang", "gleam_json", "gleam_otp", "gleam_stdlib", "houdini"], otp_app = "lustre", source = "hex", outer_checksum = "40E097BABCE65FB7C460C073078611F7F5802EB07E1A9BFB5C229F71B60F8E50" },
1818+ { name = "lustre_ssg", version = "0.12.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_regexp", "gleam_stdlib", "jot", "lustre", "simplifile", "temporary", "tom"], source = "git", repo = "https://github.com/fruno-bulax/lustre_ssg", commit = "6c132bd34ab75a1144d31c0f896cab0e3cbf80fc" },
1919+ { name = "shellout", version = "1.7.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "shellout", source = "hex", outer_checksum = "1BDC03438FEB97A6AF3E396F4ABEB32BECF20DF2452EC9A8C0ACEB7BDDF70B14" },
2020+ { name = "simplifile", version = "2.3.2", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "E049B4DACD4D206D87843BCF4C775A50AE0F50A52031A2FFB40C9ED07D6EC70A" },
2121+ { name = "splitter", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "splitter", source = "hex", outer_checksum = "3DFD6B6C49E61EDAF6F7B27A42054A17CFF6CA2135FF553D0CB61C234D281DD0" },
2222+ { 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" },
2323+ { name = "tom", version = "2.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_time"], otp_app = "tom", source = "hex", outer_checksum = "74D0C5A3761F7A7D06994755D4D5AD854122EF8E9F9F76A3E7547606D8C77091" },
2424+]
2525+2626+[requirements]
2727+gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
2828+gleam_time = { version = ">= 1.6.0 and < 2.0.0" }
2929+lustre = { version = ">= 5.4.0 and < 6.0.0" }
3030+lustre_ssg = { git = "https://github.com/fruno-bulax/lustre_ssg", ref = "6c132bd34ab75a1144d31c0f896cab0e3cbf80fc" }
3131+shellout = { version = ">= 1.7.0 and < 2.0.0" }
3232+simplifile = { version = ">= 2.3.2 and < 3.0.0" }
3333+tom = { version = ">= 2.0.0 and < 3.0.0" }
···11+#!/usr/bin/env python3
22+33+import http.server
44+import socketserver
55+import sys
66+import os.path
77+88+PORT = 8080
99+# Be careful in public networks!
1010+# I just wanna check the site on my phone
1111+HOST = "0.0.0.0"
1212+ROOT = "./dist"
1313+1414+class CleanUrlHandler(http.server.SimpleHTTPRequestHandler):
1515+ def __init__(self, *args, **kwargs):
1616+ super().__init__(*args, directory=ROOT, **kwargs)
1717+1818+ def do_GET(self):
1919+ # This is a very shitty check, but it's good enough
2020+ if not '.' in self.path and not os.path.isdir(self.translate_path(self.path)):
2121+ self.path += '.html'
2222+2323+ super().do_GET()
2424+2525+with socketserver.TCPServer((HOST, PORT), CleanUrlHandler) as http:
2626+ print(f"Serving 💅 at {HOST}:{PORT}")
2727+ try:
2828+ http.serve_forever()
2929+ except KeyboardInterrupt:
3030+ sys.exit(0)