diff --git a/public/css.css b/public/css.css
new file mode 100644
index 0000000..bb9fba4
--- /dev/null
+++ b/public/css.css
@@ -0,0 +1,100 @@
+@import url(https://fonts.bunny.net/css?family=chivo-mono:500);
+
+:root {
+ --background: #2e3440;
+ --background-text: #3b4252;
+ --border: #5e81ac;
+ --border2: #b48ead;
+ --text: #eceff4;
+ --link: #88c0d0;
+ --link-visited: #81a1c1;
+
+ --padding: 10px 20px;
+ --margin: 4px;
+ --gap: 10px;
+
+ --radius: 4px;
+}
+
+code {
+ background: var(--background-text);
+ color: var(--text);
+ padding: 2px 4px;
+ border-radius: var(--radius);
+}
+
+html {
+ color: var(--text);
+ background-color: var(--background);
+ font-family: 'Chivo Mono', monospace;
+}
+
+body {
+ background-color: initial !important;
+}
+
+a {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+body {
+ min-height: 100vh;
+ min-width: 100vw;
+ margin: 0px;
+ padding: 0px;
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ line-height: 1.5;
+}
+
+#content {
+ display: grid;
+ grid-template-areas:
+ "header1 header1 header1"
+ "content1 content2 content2"
+ "footer1 footer2 footer3"
+ ;
+ grid-template-columns: 1fr 1fr 1fr;
+ grid-gap: var(--gap);
+ padding: var(--padding);
+}
+
+#content>div {
+ background: var(--background);
+ border: 4px solid var(--border);
+ border-radius: var(--radius);
+ padding: var(--padding);
+ align-content: center;
+}
+
+#content>div:nth-child(3n+1) {
+ border: 4px solid var(--border2);
+}
+
+#background {
+ position: fixed;
+ z-index: -3;
+
+ left: 0;
+ right: 0;
+ top: 0;
+ bottom: 0;
+
+ color: var(--background-text);
+ opacity: 0.3;
+
+ aspect-ratio: 1/1;
+
+ transform-origin: top;
+ transform: scale(150%) rotate(-20deg) translateY(-25%);
+
+ align-content: center;
+ text-align: center;
+}
diff --git a/public/index.html b/public/index.html
index 6d85d95..5189848 100644
--- a/public/index.html
+++ b/public/index.html
@@ -2,131 +2,53 @@
-
+
-
+
-
content
-
content
-
content
+
+
Things I like
+
+ - Anime
+ - Programming
+ - Gaming
+ - Vim motions
+
+
+
+
Projects I've finished
+
+
+
-
-
+
diff --git a/public/main.js b/public/main.js
new file mode 100644
index 0000000..c6e759a
--- /dev/null
+++ b/public/main.js
@@ -0,0 +1,15 @@
+const generate_background = ((terms) => {
+ let str = "";
+ terms = terms == null ? "${i} :3 Nix Linux Test Portchain Programming Rust C++ Openbirch Godot".split(" ") : terms;
+ for (let i = 0; i < 5000; i++) {
+ let idx = Math.floor(Math.random() * terms.length);
+ str += terms[idx] + " ";
+ }
+
+
+ let idx = Math.floor(Math.random() * terms.length);
+ document.getElementById("background").innerText = str;
+ try {
+ document.querySelector(".footer>marquee").innerText = terms[idx] + " Footer";
+ } catch (e) {}
+})
diff --git a/public/md2html.js b/public/md2html.js
new file mode 100644
index 0000000..5d3e2a2
--- /dev/null
+++ b/public/md2html.js
@@ -0,0 +1,228 @@
+const md2tokens = (markdown, newline) => {
+ // Simple lexer and parser
+ let i = 0;
+ let current_string = "";
+ newline = newline == null ? true : newline;
+ let newline_count = newline ? 1 : 0;
+
+ let tokens = [];
+
+ let match = (c) => {
+ if (c == markdown[i]) {
+ i++;
+ return true;
+ }
+
+ return false;
+ }
+
+ let advance = () => {
+ i++;
+ if (i < markdown.length)
+ return true
+
+ return false
+ }
+
+ let capture_until = (c) => {
+ let capture = "";
+ while (markdown[i] != c && markdown.length > i) {
+ capture += markdown[i];
+ i++;
+ }
+ return capture;
+ }
+
+ let finish = (type) => {
+ if (current_string.trim().length == 0) {
+ current_string = "";
+ return;
+ }
+
+ tokens.push({ type: type == null ? "span" : type, content: current_string })
+ current_string = "";
+ }
+
+ let def = () => {
+ current_string += markdown[i];
+ newline = false;
+ newline_count = 0;
+ }
+
+ while (i < markdown.length) {
+ switch (markdown[i]) {
+ case '\\':
+ i++;
+ current_string += markdown[i];
+ break;
+
+ case '*':
+ finish();
+ advance();
+ let depth_em = 1;
+ let type = "em";
+ if (match("*")) {
+ type = "bold";
+ depth_em = 2;
+ }
+
+ let found_match = () => {
+ for (let j = 0; j < depth_em; j++) {
+ if (markdown[i + j] != "*")
+ return false
+ }
+ return true
+ }
+
+ while (!found_match()) {
+ current_string += markdown[i];
+ if (!advance())
+ break;
+ }
+
+ advance();
+
+ finish(type);
+ break;
+
+ case "#":
+ if (!newline) {
+ def();
+ break;
+ }
+
+ finish();
+ let depth_he = 0;
+ do {
+ depth_he++;
+
+ } while (match("#"));
+
+ while (markdown[i] != "\n" && markdown.length > i) {
+ current_string += markdown[i];
+ i++
+ }
+
+ tokens.push({ type: "header", level: depth_he, content: current_string });
+ current_string = "";
+ break;
+
+ case '!':
+ if (markdown[i + 1] != "[") {
+ def();
+ break;
+ }
+
+ finish();
+ advance();
+ advance();
+ let alt_text = capture_until("]");
+ advance();
+ if (!match("(")) {
+ current_string = `![${alt_text}]`;
+ def();
+ break;
+ }
+
+ let url = capture_until("\"");
+ advance();
+ let title = capture_until("\"");
+ advance();
+ if (!match(")")) {
+ current_string = `;
+ break;
+ }
+
+ tokens.push({type:"image", alt: alt_text, url: url, title: title})
+ break;
+
+ case '-':
+ if (!newline) {
+ def();
+ break;
+ }
+
+ let items = [];
+
+ advance();
+
+ do {
+ let text = capture_until("\n");
+ advance();
+ items.push(md2tokens(text, false));
+ } while (match("-"));
+
+ tokens.push({type:"ul", items: items});
+
+ break;
+
+ case '\n':
+ if (newline_count > 2)
+ break;
+
+ newline = true;
+ newline_count++;
+ finish();
+ tokens.push({ type: "newline" })
+ break;
+
+ case '`':
+ finish();
+ advance();
+ current_string = capture_until("`");
+ finish("inlinecode");
+ break;
+
+ default:
+ def()
+ }
+ i++;
+ }
+
+ finish();
+
+ console.log(tokens);
+
+ return tokens;
+};
+
+const tokens2html = (tokens) => {
+ let output = "";
+
+ for (let token of tokens) {
+ switch (token.type) {
+ case "span":
+ output += `
${token.content}`;
+ break
+ case "bold":
+ output += `
${token.content}`
+ break;
+ case "em":
+ output += `
${token.content}`
+ break;
+ case "header":
+ output += `
${token.content}`
+ break;
+ case "newline":
+ output += "
"
+ break;
+ case "image":
+ output += `

`;
+ break
+ case "ul":
+ console.log(token);
+ output += "
";
+ for (let item of token.items) {
+ output += `- ${tokens2html(item)}
`
+ }
+ output += "
";
+ break;
+ case "inlinecode":
+ output += `
${token.content}
`;
+ break;
+ }
+ }
+
+ return output;
+}
diff --git a/public/posts/index.html b/public/posts/index.html
new file mode 100644
index 0000000..a39f45e
--- /dev/null
+++ b/public/posts/index.html
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/posts/openbirch.md b/public/posts/openbirch.md
new file mode 100644
index 0000000..d8a898b
--- /dev/null
+++ b/public/posts/openbirch.md
@@ -0,0 +1,13 @@
+Functions Vectors Evaluate Isolate Solve Matrix Tensor Calculus Derivation Limit Procedures Scopes Statements Interpreter Parser Lexer
+# Openbirch
+Openbirch is a programming language that I made together with my friend from school.
+It was an attempt at making a CAS tool to use instead of Maple (the UX is terrible).
+
+The biggest challenge besides creating a programming language was creating a programming language
+where any variable could be undefined at runtime, but still used to define other variables.
+
+An example of this would be `x := 2*y`. Here `y` is not defined, but it is still used to define `x`.
+
+This was a unique challenge that was solved by representing everything as a *tree*
+
+
diff --git a/public/test.png b/public/test.png
new file mode 100644
index 0000000..d23ef05
Binary files /dev/null and b/public/test.png differ
diff --git a/src/main.rs b/src/main.rs
index c05caf5..7b02a35 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
use std::{
env::current_dir,
+ ffi::OsStr,
io::{BufRead, BufReader, Write},
net::{TcpListener, TcpStream},
path::PathBuf,
@@ -38,7 +39,16 @@ impl Request {
"POST" => RequestMethod::POST,
_ => panic!("Unknown method"),
},
- path: Some(parts.next().expect("Invalid request").to_string()),
+ path: Some(
+ parts
+ .next()
+ .expect("Invalid request")
+ .to_string()
+ .split("?")
+ .next()
+ .unwrap()
+ .to_string(),
+ ),
}
}
pub fn file(&self) -> Option
{
@@ -65,6 +75,22 @@ impl Request {
}
}
+fn get_mime_type<'a>(extension: Option<&'a OsStr>) -> String {
+ if extension.is_none() {
+ return "text/text".to_string();
+ }
+
+ let s = extension.unwrap().to_str();
+ match s {
+ Some("js") => "text/javascript".to_string(),
+ Some("md") => "text/markdown".to_string(),
+ Some("css") => "text/css".to_string(),
+ Some("html") => "text/html".to_string(),
+ Some("png") => "image/png".to_string(),
+ _ => "text/text".to_string(),
+ }
+}
+
fn handle_connection(mut stream: TcpStream) {
let buf_reader = BufReader::new(&stream);
let http_request: Vec<_> = buf_reader
@@ -83,13 +109,24 @@ fn handle_connection(mut stream: TcpStream) {
println!("Requested file: {:#?}", req.file());
+ let mut response_content = vec![];
+
let response = match req.file() {
- Some(path) => match std::fs::read_to_string(path) {
- Ok(content) => format!("HTTP/1.1 200 OK{0}Content-Length: {1}{0}{0}{content}", CLRF, content.len()),
- Err(e) => format!("HTTP/1.1 500{0}{0}{e}", CLRF),
- }
- None => format!("HTTP/1.1 500{0}{0}", CLRF),
+ Some(path) => match std::fs::read(&path) {
+ Ok(content) => {
+ let len = &content.len();
+ response_content = content;
+ format!(
+ "HTTP/1.1 200 OK{0}Content-Type: {2}{0}Content-Length: {1}{0}{0}",
+ CLRF,
+ len,
+ get_mime_type(path.extension())
+ )},
+ Err(e) => format!("HTTP/1.1 404{0}{0}{e}", CLRF),
+ },
+ None => format!("HTTP/1.1 404{0}{0}", CLRF),
};
stream.write_all(response.as_bytes()).unwrap();
+ stream.write_all(&response_content).unwrap();
}