commit 485e657296c38b1801505b649871f51e0ad237c8 Author: Winter Hille Date: Mon Jan 27 00:00:47 2025 -0800 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eb5a316 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +target diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..3946387 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,142 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "bunbun_dev" +version = "0.1.0" +dependencies = [ + "fluffle", + "markdown", +] + +[[package]] +name = "fluffle" +version = "0.1.0" +source = "git+https://codeberg.org/bunbun/fluffle#7e7a9a9a9a5a1a2137e3635d182a1b920f21a91c" +dependencies = [ + "lazy-regex", +] + +[[package]] +name = "lazy-regex" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d8e41c97e6bc7ecb552016274b99fbb5d035e8de288c582d9b933af6677bfda" +dependencies = [ + "lazy-regex-proc_macros", + "once_cell", + "regex", +] + +[[package]] +name = "lazy-regex-proc_macros" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76e1d8b05d672c53cb9c7b920bbba8783845ae4f0b076e02a3db1d02c81b4163" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "markdown" +version = "1.0.0-alpha.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6491e6c702bf7e3b24e769d800746d5f2c06a6c6a2db7992612e0f429029e81" +dependencies = [ + "unicode-id", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "proc-macro2" +version = "1.0.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "syn" +version = "2.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-id" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10103c57044730945224467c09f71a4db0071c123a0648cc3e818913bde6b561" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..694c483 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "bunbun_dev" +version = "0.1.0" +edition = "2021" + +[dependencies] +fluffle = { git = "https://codeberg.org/bunbun/fluffle", features = [] } +markdown = "1.0.0-alpha.21" diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..bce9093 --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1730785428, + "narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..a7ad271 --- /dev/null +++ b/flake.nix @@ -0,0 +1,27 @@ +{ + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let pkgs = nixpkgs.legacyPackages.${system}; + in with pkgs; { + packages.default = rustPlatform.buildRustPackage { + inherit ((lib.importTOML ./Cargo.toml).package) name; + + src = ./.; + + cargoLock.lockFile = ./Cargo.lock; + + nativeBuildInputs = [ pkg-config ]; + }; + + devShells.default = mkShell { + nativeBuildInputs = [ pkg-config ]; + + buildInputs = [ rustc cargo wasm-bindgen-cli lld ]; + }; + }); +} diff --git a/site/assets/favicon.svg b/site/assets/favicon.svg new file mode 100644 index 0000000..a3cfe80 --- /dev/null +++ b/site/assets/favicon.svg @@ -0,0 +1,3 @@ + + + diff --git a/site/pages/about.md b/site/pages/about.md new file mode 100644 index 0000000..ba89cd1 --- /dev/null +++ b/site/pages/about.md @@ -0,0 +1,7 @@ +### About Me + +... + +### About the Website + +... diff --git a/site/pages/main.md b/site/pages/main.md new file mode 100644 index 0000000..93bf3ad --- /dev/null +++ b/site/pages/main.md @@ -0,0 +1,3 @@ +## Welcome to my Website + +Hello! I'm Winter and this is my website... _Why are you here?_ diff --git a/site/styles/style.css b/site/styles/style.css new file mode 100644 index 0000000..2ebd029 --- /dev/null +++ b/site/styles/style.css @@ -0,0 +1,271 @@ +@import url("https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:ital,wght@0,100..900;1,100..900&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,wght@8..144,100..1000&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,100..700;1,100..700&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Roboto+Serif:ital,opsz,wght@0,8..144,100..900;1,8..144,100..900&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Roboto+Slab:wght@100..900&display=swap"); + +:root { + --serif-font: "Roboto Serif", serif; + --sans-serif-font: "Roboto", sans-serif; + --monospace-font: "Roboto Mono", monospace; + + --white-10: #ffffff; + --white-20: #ebebeb; + --white-30: #d6d6d6; + --white-40: #c2c2c2; + --white-50: #adadad; + + --black-10: #525252; + --black-20: #3d3d3d; + --black-30: #292929; + --black-40: #141414; + --black-50: #000000; +} + +:root { + --foreground: var(--white-10); + --background: var(--black-50); + + --accent-10: var(--black-10); + --accent-20: var(--black-20); + --accent-30: var(--black-30); + --accent-40: var(--black-40); + --accent-50: var(--white-50); +} + +@media (prefers-color-scheme: light) { + :root { + --foreground: var(--black-50); + --background: var(--white-10); + + --accent-10: var(--white-50); + --accent-20: var(--white-40); + --accent-30: var(--white-30); + --accent-40: var(--white-20); + --accent-50: var(--black-10); + } +} + +* { + cursor: none; +} + +body { + display: flex; + flex-direction: column; + box-sizing: border-box; + margin: 0; + background: var(--background); + padding: 2em; + min-height: 100vh; + color: var(--foreground); + font-family: var(--sans-serif-font); +} + +body>header { + display: flex; + position: sticky; + top: 0; + justify-content: space-between; + margin-top: -1em; + border-bottom: 0.1em solid var(--accent-50); + background: var(--background); + padding: 0.5em; +} + +body>header>a { + color: var(--foreground); + font-weight: 500; + font-size: 2em; + text-decoration: none; + + &::after { + content: "_"; + } + + &:hover::after { + animation: blink 0.5s alternate infinite; + } +} + +@keyframes blink { + to { + opacity: 0; + } + + from { + opacity: 1; + } +} + +body>header>nav { + display: flex; + align-items: center; +} + +body>header>nav>a { + color: var(--foreground); + text-decoration: none; + + &:hover { + text-decoration: underline; + } +} + +body>.content { + flex: 1; + padding: 1em; + overflow-y: hidden; +} + +body>.content>main { + min-width: auto; +} + +body>.content>main { + min-width: 60ch; + + /* paragraphs */ + p { + margin: 0; + color: var(--accent-50); + } + + >p { + margin-block-start: 1em; + margin-block-end: 1em; + } + + /* headings */ + h1, + h2, + h3, + h4, + h5, + h6 { + margin: 0; + } + + > :is(h1, h2, h3, h4, h5, h6) { + margin-block-start: 1em; + margin-block-end: 1em; + } + + /* links */ + a { + color: var(--foreground); + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + /* images */ + img { + border-radius: 0.26em; + } + + /* block qutoes */ + blockquote { + display: block; + margin: 0; + margin-left: 1em; + margin-block-start: 1em; + border-left: 0.2em solid var(--accent-40); + padding-left: 0.5em; + } + + /* lists */ + ul, + ol { + margin: 0; + padding-left: 2em; + color: var(--accent-50); + + li { + margin: 0; + } + + li::marker { + color: var(--foreground); + } + } + + > :is(ul, ol) { + margin-block-start: 1em; + margin-block-end: 1em; + } + + /* horizontal rule */ + hr { + margin: 1em 0; + border: none; + border-bottom: 0.1em solid var(--accent-50); + } + + /* inline code */ + p>code { + display: inline-block; + border-radius: 0.23em; + background: var(--accent-40); + padding: 0.2em; + color: var(--foreground); + font-size: 0.8em; + line-height: 1; + font-family: var(--monospace-font); + } + + /* code blocks */ + pre { + display: block; + margin: 1em 0; + border-radius: 0.26em; + background: var(--accent-40); + padding: 0.8em; + width: fit-content; + overflow: hidden; + } + + pre>code { + font-size: 0.8em; + font-family: var(--monospace-font); + } +} + +body>footer { + padding: 0.5em; + color: var(--accent-10); + white-space: nowrap; +} + +body>footer>a { + display: inline-block; + margin: -0.2em 0; + border-radius: 0.23em; + background: #42a5f54d; + padding: 0.2em; + color: #42a5f5; + line-height: 1; + text-decoration: none; + + &:hover { + text-decoration: underline; + } +} + +.cursor { + position: fixed; + transform: translate(-50%, -50%); + visibility: visible; + z-index: 999; + backdrop-filter: invert(100%); + transition: + width 200ms, + height 200ms; + border-radius: 50%; + width: 12px; + height: 12px; + pointer-events: none; +} diff --git a/site/templates/error.html b/site/templates/error.html new file mode 100644 index 0000000..b9d94ba --- /dev/null +++ b/site/templates/error.html @@ -0,0 +1,54 @@ + + + + + + {{code}} {{message}} + + + + +

{{code}}

+

{{message}}

+ + diff --git a/site/templates/main.html b/site/templates/main.html new file mode 100644 index 0000000..b4db63a --- /dev/null +++ b/site/templates/main.html @@ -0,0 +1,34 @@ + + + + + + + + bunbun.dev + + + +
+ bunbun.dev + +
+
+
{{content}}
+
+ + + + + diff --git a/site/wasm/cursor/.cargo/config.toml b/site/wasm/cursor/.cargo/config.toml new file mode 100644 index 0000000..f4e8c00 --- /dev/null +++ b/site/wasm/cursor/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" diff --git a/site/wasm/cursor/Cargo.lock b/site/wasm/cursor/Cargo.lock new file mode 100644 index 0000000..2b8a4c9 --- /dev/null +++ b/site/wasm/cursor/Cargo.lock @@ -0,0 +1,144 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "js-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "wasm-bindgen" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" + +[[package]] +name = "wasm_cursor" +version = "0.0.0" +dependencies = [ + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +dependencies = [ + "js-sys", + "wasm-bindgen", +] diff --git a/site/wasm/cursor/Cargo.toml b/site/wasm/cursor/Cargo.toml new file mode 100644 index 0000000..3da642f --- /dev/null +++ b/site/wasm/cursor/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "wasm_cursor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +wasm-bindgen = "=0.2.95" +web-sys = { version = "0.3.72", features = ["CssStyleDeclaration", "Document", "HtmlElement", "MouseEvent", "NodeList", "Window"] } diff --git a/site/wasm/cursor/build.rs b/site/wasm/cursor/build.rs new file mode 100644 index 0000000..70b3a8b --- /dev/null +++ b/site/wasm/cursor/build.rs @@ -0,0 +1,22 @@ +use std::{path::Path, process::Command}; + +fn main() { + /* + println!("cargo::rerun-if-changed=target/wasm32-unknown-unknown/debug/wasm_cursor.wasm"); + + let out = Command::new("wasm-bindgen") + .args(&[ + "./target/wasm32-unknown-unknown/debug/wasm_cursor.wasm", + "--out-dir", + "pkg", + "--target", + "web", + ]) + .output() + .unwrap(); + + if !out.status.success() { + panic!("{}", String::from_utf8_lossy(&out.stderr)); + } + */ +} diff --git a/site/wasm/cursor/pkg/wasm_cursor.d.ts b/site/wasm/cursor/pkg/wasm_cursor.d.ts new file mode 100644 index 0000000..6e9cf7c --- /dev/null +++ b/site/wasm/cursor/pkg/wasm_cursor.d.ts @@ -0,0 +1,37 @@ +/* tslint:disable */ +/* eslint-disable */ +export function main(): void; + +export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; + +export interface InitOutput { + readonly memory: WebAssembly.Memory; + readonly main: () => void; + readonly __wbindgen_malloc: (a: number, b: number) => number; + readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number; + readonly __wbindgen_export_2: WebAssembly.Table; + readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h00af0edcf808575b: (a: number, b: number, c: number) => void; + readonly __wbindgen_exn_store: (a: number) => void; + readonly __wbindgen_start: () => void; +} + +export type SyncInitInput = BufferSource | WebAssembly.Module; +/** +* Instantiates the given `module`, which can either be bytes or +* a precompiled `WebAssembly.Module`. +* +* @param {{ module: SyncInitInput }} module - Passing `SyncInitInput` directly is deprecated. +* +* @returns {InitOutput} +*/ +export function initSync(module: { module: SyncInitInput } | SyncInitInput): InitOutput; + +/** +* If `module_or_path` is {RequestInfo} or {URL}, makes a request and +* for everything else, calls `WebAssembly.instantiate` directly. +* +* @param {{ module_or_path: InitInput | Promise }} module_or_path - Passing `InitInput` directly is deprecated. +* +* @returns {Promise} +*/ +export default function __wbg_init (module_or_path?: { module_or_path: InitInput | Promise } | InitInput | Promise): Promise; diff --git a/site/wasm/cursor/pkg/wasm_cursor.js b/site/wasm/cursor/pkg/wasm_cursor.js new file mode 100644 index 0000000..437d54b --- /dev/null +++ b/site/wasm/cursor/pkg/wasm_cursor.js @@ -0,0 +1,474 @@ +let wasm; + +const heap = new Array(128).fill(undefined); + +heap.push(undefined, null, true, false); + +function getObject(idx) { return heap[idx]; } + +let heap_next = heap.length; + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} + +function addHeapObject(obj) { + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; + + heap[idx] = obj; + return idx; +} + +function debugString(val) { + // primitive types + const type = typeof val; + if (type == 'number' || type == 'boolean' || val == null) { + return `${val}`; + } + if (type == 'string') { + return `"${val}"`; + } + if (type == 'symbol') { + const description = val.description; + if (description == null) { + return 'Symbol'; + } else { + return `Symbol(${description})`; + } + } + if (type == 'function') { + const name = val.name; + if (typeof name == 'string' && name.length > 0) { + return `Function(${name})`; + } else { + return 'Function'; + } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = '['; + if (length > 0) { + debug += debugString(val[0]); + } + for(let i = 1; i < length; i++) { + debug += ', ' + debugString(val[i]); + } + debug += ']'; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == 'Object') { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return 'Object(' + JSON.stringify(val) + ')'; + } catch (_) { + return 'Object'; + } + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; +} + +let WASM_VECTOR_LEN = 0; + +let cachedUint8ArrayMemory0 = null; + +function getUint8ArrayMemory0() { + if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) { + cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8ArrayMemory0; +} + +const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); + +const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); +} + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; +}); + +function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8ArrayMemory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + ptr = realloc(ptr, len, offset, 1) >>> 0; + } + + WASM_VECTOR_LEN = offset; + return ptr; +} + +let cachedDataViewMemory0 = null; + +function getDataViewMemory0() { + if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) { + cachedDataViewMemory0 = new DataView(wasm.memory.buffer); + } + return cachedDataViewMemory0; +} + +const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); + +if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; + +function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len)); +} + +const CLOSURE_DTORS = (typeof FinalizationRegistry === 'undefined') + ? { register: () => {}, unregister: () => {} } + : new FinalizationRegistry(state => { + wasm.__wbindgen_export_2.get(state.dtor)(state.a, state.b) +}); + +function makeMutClosure(arg0, arg1, dtor, f) { + const state = { a: arg0, b: arg1, cnt: 1, dtor }; + const real = (...args) => { + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + if (--state.cnt === 0) { + wasm.__wbindgen_export_2.get(state.dtor)(a, state.b); + CLOSURE_DTORS.unregister(state); + } else { + state.a = a; + } + } + }; + real.original = state; + CLOSURE_DTORS.register(real, state, state); + return real; +} +function __wbg_adapter_16(arg0, arg1, arg2) { + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h00af0edcf808575b(arg0, arg1, addHeapObject(arg2)); +} + +export function main() { + wasm.main(); +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +function handleError(f, args) { + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } +} + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + + } catch (e) { + if (module.headers.get('Content-Type') != 'application/wasm') { + console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); + + } else { + throw e; + } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + + } else { + return instance; + } + } +} + +function __wbg_get_imports() { + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbindgen_cb_drop = function(arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + const ret = false; + return ret; + }; + imports.wbg.__wbindgen_object_clone_ref = function(arg0) { + const ret = getObject(arg0); + return addHeapObject(ret); + }; + imports.wbg.__wbg_instanceof_Window_6575cd7f1322f82f = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof Window; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }; + imports.wbg.__wbg_document_d7fa2c739c2b191a = function(arg0) { + const ret = getObject(arg0).document; + return isLikeNone(ret) ? 0 : addHeapObject(ret); + }; + imports.wbg.__wbg_body_8e909b791b1745d3 = function(arg0) { + const ret = getObject(arg0).body; + return isLikeNone(ret) ? 0 : addHeapObject(ret); + }; + imports.wbg.__wbg_createElement_e4523490bd0ae51d = function() { return handleError(function (arg0, arg1, arg2) { + const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2)); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_querySelectorAll_28e417f74795a70f = function() { return handleError(function (arg0, arg1, arg2) { + const ret = getObject(arg0).querySelectorAll(getStringFromWasm0(arg1, arg2)); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_setclassName_4b7637091f940659 = function(arg0, arg1, arg2) { + getObject(arg0).className = getStringFromWasm0(arg1, arg2); + }; + imports.wbg.__wbg_instanceof_HtmlElement_aab18e065dc9207d = function(arg0) { + let result; + try { + result = getObject(arg0) instanceof HTMLElement; + } catch (_) { + result = false; + } + const ret = result; + return ret; + }; + imports.wbg.__wbg_style_04eb1488bc2ceffc = function(arg0) { + const ret = getObject(arg0).style; + return addHeapObject(ret); + }; + imports.wbg.__wbg_setProperty_b9a2384cbfb499fb = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { + getObject(arg0).setProperty(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); + }, arguments) }; + imports.wbg.__wbg_type_739ef24b64f58229 = function(arg0, arg1) { + const ret = getObject(arg1).type; + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }; + imports.wbg.__wbg_addEventListener_4357f9b7b3826784 = function() { return handleError(function (arg0, arg1, arg2, arg3) { + getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3)); + }, arguments) }; + imports.wbg.__wbg_clientX_a8eebf094c107e43 = function(arg0) { + const ret = getObject(arg0).clientX; + return ret; + }; + imports.wbg.__wbg_clientY_ffe0a79af8089cd4 = function(arg0) { + const ret = getObject(arg0).clientY; + return ret; + }; + imports.wbg.__wbg_appendChild_bc4a0deae90a5164 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg0).appendChild(getObject(arg1)); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_length_9a6b70327f5f86e1 = function(arg0) { + const ret = getObject(arg0).length; + return ret; + }; + imports.wbg.__wbg_get_602f2a39a831c929 = function(arg0, arg1) { + const ret = getObject(arg0)[arg1 >>> 0]; + return isLikeNone(ret) ? 0 : addHeapObject(ret); + }; + imports.wbg.__wbg_newnoargs_1ede4bf2ebbaaf43 = function(arg0, arg1) { + const ret = new Function(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_call_a9ef466721e824f2 = function() { return handleError(function (arg0, arg1) { + const ret = getObject(arg0).call(getObject(arg1)); + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_globalThis_05c129bf37fcf1be = function() { return handleError(function () { + const ret = globalThis.globalThis; + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_self_bf91bf94d9e04084 = function() { return handleError(function () { + const ret = self.self; + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_window_52dd9f07d03fd5f8 = function() { return handleError(function () { + const ret = window.window; + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbg_global_3eca19bb09e9c484 = function() { return handleError(function () { + const ret = global.global; + return addHeapObject(ret); + }, arguments) }; + imports.wbg.__wbindgen_is_undefined = function(arg0) { + const ret = getObject(arg0) === undefined; + return ret; + }; + imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { + const ret = debugString(getObject(arg1)); + const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const len1 = WASM_VECTOR_LEN; + getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true); + getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true); + }; + imports.wbg.__wbindgen_object_drop_ref = function(arg0) { + takeObject(arg0); + }; + imports.wbg.__wbindgen_throw = function(arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }; + imports.wbg.__wbindgen_rethrow = function(arg0) { + throw takeObject(arg0); + }; + imports.wbg.__wbindgen_closure_wrapper66 = function(arg0, arg1, arg2) { + const ret = makeMutClosure(arg0, arg1, 13, __wbg_adapter_16); + return addHeapObject(ret); + }; + + return imports; +} + +function __wbg_init_memory(imports, memory) { + +} + +function __wbg_finalize_init(instance, module) { + wasm = instance.exports; + __wbg_init.__wbindgen_wasm_module = module; + cachedDataViewMemory0 = null; + cachedUint8ArrayMemory0 = null; + + + wasm.__wbindgen_start(); + return wasm; +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + + if (typeof module !== 'undefined') { + if (Object.getPrototypeOf(module) === Object.prototype) { + ({module} = module) + } else { + console.warn('using deprecated parameters for `initSync()`; pass a single object instead') + } + } + + const imports = __wbg_get_imports(); + + __wbg_init_memory(imports); + + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + + const instance = new WebAssembly.Instance(module, imports); + + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(module_or_path) { + if (wasm !== undefined) return wasm; + + + if (typeof module_or_path !== 'undefined') { + if (Object.getPrototypeOf(module_or_path) === Object.prototype) { + ({module_or_path} = module_or_path) + } else { + console.warn('using deprecated parameters for the initialization function; pass a single object instead') + } + } + + if (typeof module_or_path === 'undefined') { + module_or_path = new URL('wasm_cursor_bg.wasm', import.meta.url); + } + const imports = __wbg_get_imports(); + + if (typeof module_or_path === 'string' || (typeof Request === 'function' && module_or_path instanceof Request) || (typeof URL === 'function' && module_or_path instanceof URL)) { + module_or_path = fetch(module_or_path); + } + + __wbg_init_memory(imports); + + const { instance, module } = await __wbg_load(await module_or_path, imports); + + return __wbg_finalize_init(instance, module); +} + +export { initSync }; +export default __wbg_init; diff --git a/site/wasm/cursor/pkg/wasm_cursor_bg.wasm b/site/wasm/cursor/pkg/wasm_cursor_bg.wasm new file mode 100644 index 0000000..501b37e Binary files /dev/null and b/site/wasm/cursor/pkg/wasm_cursor_bg.wasm differ diff --git a/site/wasm/cursor/pkg/wasm_cursor_bg.wasm.d.ts b/site/wasm/cursor/pkg/wasm_cursor_bg.wasm.d.ts new file mode 100644 index 0000000..9213665 --- /dev/null +++ b/site/wasm/cursor/pkg/wasm_cursor_bg.wasm.d.ts @@ -0,0 +1,10 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export function main(): void; +export function __wbindgen_malloc(a: number, b: number): number; +export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number; +export const __wbindgen_export_2: WebAssembly.Table; +export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h00af0edcf808575b(a: number, b: number, c: number): void; +export function __wbindgen_exn_store(a: number): void; +export function __wbindgen_start(): void; diff --git a/site/wasm/cursor/src/lib.rs b/site/wasm/cursor/src/lib.rs new file mode 100644 index 0000000..f4deb17 --- /dev/null +++ b/site/wasm/cursor/src/lib.rs @@ -0,0 +1,99 @@ +use wasm_bindgen::prelude::*; +use web_sys::{window, HtmlElement, MouseEvent}; + +#[wasm_bindgen(start)] +fn main() -> Result<(), JsValue> { + let document = window().unwrap().document().unwrap(); + let body = document.body().unwrap(); + + let cursor = document.create_element("div")?.dyn_into::()?; + cursor.set_class_name("cursor"); + cursor.style().set_property("visibility", "hidden")?; + + body.append_child(&cursor)?; + + let mut first_move = true; + + let cursor_clone = cursor.clone(); + let event_handler = + Closure::wrap( + Box::new(move |event: MouseEvent| match event.type_().as_str() { + "mousemove" => { + if first_move { + cursor_clone + .style() + .set_property("visibility", "visible") + .unwrap(); + first_move = false; + } + + set_cursor_position(&cursor_clone, event.client_x(), event.client_y()) + } + "mousedown" => set_cursor_size(&cursor_clone, 18), + "mouseup" => set_cursor_size(&cursor_clone, 12), + "mouseout" => cursor_clone + .style() + .set_property("visibility", "hidden") + .unwrap(), + "mouseover" => cursor_clone + .style() + .set_property("visibility", "visible") + .unwrap(), + _ => unreachable!(), + }) as Box, + ); + + for event in ["mousemove", "mousedown", "mouseup", "mouseout", "mouseover"] { + document.add_event_listener_with_callback(event, event_handler.as_ref().unchecked_ref())?; + } + + event_handler.forget(); + + let elements = document.query_selector_all("a")?; + for i in 0..elements.length() { + let element = elements.get(i).unwrap(); + + let cursor_clone = cursor.clone(); + let event_handler = + Closure::wrap( + Box::new(move |event: MouseEvent| match event.type_().as_str() { + "mouseenter" => set_cursor_size(&cursor_clone, 24), + "mouseleave" => set_cursor_size(&cursor_clone, 12), + "mousedown" => set_cursor_size(&cursor_clone, 18), + "mouseup" => set_cursor_size(&cursor_clone, 24), + _ => unreachable!(), + }) as Box, + ); + + for event in ["mouseenter", "mouseleave", "mousedown", "mouseup"] { + element + .add_event_listener_with_callback(event, event_handler.as_ref().unchecked_ref())?; + } + + event_handler.forget(); + } + + Ok(()) +} + +fn set_cursor_position(cursor: &HtmlElement, x: i32, y: i32) { + cursor + .style() + .set_property("left", &format!("{}px", x)) + .unwrap(); + cursor + .style() + .set_property("top", &format!("{}px", y)) + .unwrap(); +} + +fn set_cursor_size(cursor: &HtmlElement, size: i32) { + cursor + .style() + .set_property("width", &format!("{}px", size)) + .unwrap(); + cursor + .style() + .set_property("height", &format!("{}px", size)) + .unwrap(); +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..74755ef --- /dev/null +++ b/src/main.rs @@ -0,0 +1,139 @@ +use std::{ + collections::HashMap, + fs::{self, File}, + io::{self, Read}, + path::{Path, PathBuf}, +}; + +use fluffle::{ + http::{ + response::{ResponseLine, Status}, + Request, Response, + }, + HttpVersion, Server, +}; + +const PAGES_DIR: &str = "site/pages"; +const TEMPLATES_DIR: &str = "site/templates"; + +fn walk_dir>(dir: P, depth: i32) -> io::Result> { + let mut entries = Vec::new(); + + if depth == 0 { + return Ok(entries); + } + + for entry in fs::read_dir(dir)? { + let entry = entry?; + let path = entry.path(); + + entries.push(path.clone()); + + if path.is_dir() { + let sub_entries = if depth < 0 { + walk_dir(&path, -1)? + } else { + walk_dir(&path, depth - 1)? + }; + entries.extend(sub_entries); + } + } + + Ok(entries) +} + +fn main() { + let mut server = Server::new("127.0.0.1", 8080); + + server.on_request(|request: Request| -> Response { + println!("{:#?}", request); + + let uri = request.request_line.target; + let uri = uri.trim_start_matches("/"); + + let uri = if uri.is_empty() { "main" } else { uri }; + + for entry in walk_dir(PAGES_DIR, -1).unwrap() { + let file_name = entry.file_name().and_then(|name| name.to_str()).unwrap(); + let file_stem = entry.file_stem().and_then(|stem| stem.to_str()).unwrap(); + let file_ext = entry.extension().and_then(|ext| ext.to_str()).unwrap(); + + if file_name == uri || file_stem == uri { + let mut file = File::open(&entry).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + + let mut template_file = File::open(format!("{}/main.html", TEMPLATES_DIR)).unwrap(); + let mut template_content = String::new(); + template_file.read_to_string(&mut template_content).unwrap(); + + if file_ext == "md" { + content = markdown::to_html(&content); + } + + content = template_content.replace("{{content}}", &content); + + let response_line = ResponseLine::new(HttpVersion::default(), Status::OK); + let content = Some(Vec::from(content)); + + return Response { + response_line, + headers: None, + content, + }; + } + } + + let path = format!("site/{}", uri); + let path = Path::new(&path); + + if path.exists() { + let mut file = File::open(path).unwrap(); + let mut content = Vec::new(); + file.read_to_end(&mut content).unwrap(); + + let file_ext = path.extension().and_then(|ext| ext.to_str()).unwrap(); + + let response_line = ResponseLine::new(HttpVersion::default(), Status::OK); + let headers = match file_ext { + "js" => Some(HashMap::from([("Content-Type", "text/javascript")])), + "wasm" => Some(HashMap::from([("Content-Type", "application/wasm")])), + _ => None, + }; + let content = Some(Vec::from(content)); + + return Response { + response_line, + headers, + content, + }; + } + + if request.headers.get("Accept").unwrap().contains("text/html") { + let mut file = File::open(format!("{}/error.html", TEMPLATES_DIR)).unwrap(); + let mut content = String::new(); + file.read_to_string(&mut content).unwrap(); + + content = content.replace("{{code}}", "404"); + content = content.replace("{{message}}", "Not Found"); + + let response_line = ResponseLine::new(HttpVersion::default(), Status::NotFound); + let content = Some(Vec::from(content)); + + return Response { + response_line, + headers: None, + content, + }; + } + + let response_line = ResponseLine::new(HttpVersion::default(), Status::NotFound); + Response { + response_line, + headers: None, + content: None, + } + }); + + server.run(); +}