The darfk.net website

This website is static HTML generated using a single Rust source file and the maud crate. I chose this method because it allows me to quickly create content, learn rust and have a good time. I also do not really like writing XML. While I see the value in learning a static HTML framework, they're a bit overkill for what I need. At some point I might integrate markdown into this. Some pages are read from markdown files and rendered using this application.

the source?

here it is:

use std::fs;
use std::path::Path;

use chrono::Datelike;
use maud::{html, Markup, DOCTYPE};

fn projects_index(pages: &Vec<Page>) -> Markup {
    struct PageLink {
        title: String,
        path: String,
        description: String,
    }

    let project_links = pages
        .iter()
        .filter(|page| page.typ == PageType::Project)
        .map(|page| PageLink {
            title: page.title.to_owned(),
            path: page.path.to_owned(),
            description: page.description.to_owned(),
        })
        .collect::<Vec<_>>();

    html!(
        h2 {"Projects"}
        p {"A list of completed works or works in progress."}
        @for project in project_links {
            hr;
            h3 {
                a href=(project.path) { (project.title) }
            }
            p { (project.description) }
        }
    )
}

fn this_source_file() -> Markup {
    html!((fs::read_to_string("src/main.rs").unwrap()))
}

fn projects_website() -> Markup {
    html!(
        h2 {("The darfk.net website")}
        p {
            ("This website is static HTML generated using a single Rust source file and the ")
            a href="https://maud.lambda.xyz/" {("maud crate")} (".")
            (" I chose this method because it allows me to quickly create content, learn rust and have a good time.")
            (" I also do not really like writing XML.")
            (" While I see the value in learning a static HTML framework, they're a bit overkill for what I need. ")
            s {"At some point I might integrate markdown into this."} (" Some pages are read from markdown files and rendered using this application.")
        }
        h3 {
            ("the source?")
        }
        p {
            ("here it is:")
        }
        pre {
            (this_source_file())
        }

    )
}

// this is the original content for my site
// I see no reason to change it
fn index() -> Markup {
    html!(
        h1 { ("Greetings!") }
        p { ("
            I'm Thomas, a ") a href="https://en.wikipedia.org/wiki/Wollongong" { "Wollongong" } (" based software engineer with experience in interactive entertainment and embedded systems.
            I enjoy programming, electronics, video games and spending time with my friends and family.
            ")
        };
        p { ("I've operated a ") a href="ts3server:teamspeak.darfk.net" {("teamspeak server")} (" since 2007, it's a place in which my friends and I hang out.")}
        p { ("If you would like to contact me:") }
        ul {
            li { ("email ") a href="mailto:tom@darfk.net" {("tom@darfk.net") } }
            li { ("telephone ") a href="tel:+61 4 0321 4411" {("+61 4 0321 4411") } }
        }
        p { em { ("Thank you for visiting!" )}}
    )
}

fn resume() -> Markup {
    let role = |role: &str, from: &str, to: &str| html!((role) (" ") span class="lowlight" {("from ")} (from) (" ") span class="lowlight" {("to ")} (to));

    html!(
        h1 {"Thomas Payne"}
        h2 { "Software and Electrical Engineer"}
        h4 id="resume-contact" {
            span { "mail: " a href="mailto:tom@darfk.net" { "tom@darfk.net" } };
            span { "phone: " a href="tel:+61403214411" { "+61 4 0321 4411" } };
            span class="hide-on-web" { "web: " a href="https://darfk.net" { "darfk.net" } };
        }
        h2 { "About" }
        p { "I am a technical, logical and reasonable individual with a passion for computer science, interactive
            entertainment and emerging technologies. I have a strong appreciation for solid, concise software;
            taking inspiration from the likes of Carmack and Torvalds."}
        h2 { "Work Experience" }

        h3 {a href="https://bigtincan.com" {"Bigtincan"}}
        h4 {(role("Senior Developer", "Feb 2020", "present"))}
        ul {
            li { "Technical lead for microservice projects used to augment " a href="https://www.bigtincan.com/content/" {"BTC's core platforms"}; br;
                "written in ";
                a href="https://golang.org/" {"Go"} " and "
                a href="https://dotnet.microsoft.com" {".NET"}
            }
            li { "Develop and maintain software platform for integrating 3rd party Digital Asset Management systems into core platform; written in ";
                a href="https://www.java.com" {"Java"} ", " a href="https://dotnet.microsoft.com" {"C#/.NET"} " and " a href="https://www.typescriptlang.org/" {"Typescript"}
            }
            li {
                "Build in-house GUI tools for automation and monitoring using "
                a href="https://react.dev/" {"React.JS"} ", "
                a href="https://golang.org/" {"Go"} " and "
                a href="https://htmx.org/" {"HTMX"}
            }
            li {"Develop and maintain front end user applications written using " a href="https://react.dev/" {"React.JS"}}
            li {
                "Developed a lean CI/CD pipeline, optimised for responsiveness and zero downtime"; br;
                "leveraging ";
                a href="https://www.docker.com/" {"Docker"}
                ", "
                a href="https://kubernetes.io/" {"Kubernetes"}
                " and "
                a href="https://jenkins.io/" {"Jenkins"}
            }
        }

        h3 {a href="https://silabs.com" {"Silicon Labs (Sydney)"}}
        h4 {(role("Embedded Systems Developer", "2018", "closure, 2019"))}
        ul {
            li { "Extend functionality of cloud based IoT fleet management system"; br; "written in "
                a href="https://nodejs.org/" {"Node.js"} " and "
                a href="https://golang.org/" {"Go"}
            }
            li { "Development of sample 'apps' on Silabs' in-house embedded RTOS (" a href="https://docs.silabs.com/gecko-os/4/standard/latest/" { "Gecko OS 4"} "). Deployed for various platforms based on ARM Cortex-M4" }
            li { "Completed a rewrite of previous OTA firmware bundling software."; br; "Ported from Python 2 and C to Go"}
            li { "Development and maintenance of an automated regression testing system for embedded platforms, written using Python/Shell/C"}
            li { "Conducted employee training seminars on topics including: git, bash, unix philosophy"}
        }

        div class="page-break-after" {}

        h3 { "As a private contractor" }
        h4 { (role("", "Jan 2009", "Aug 2011")) ", " (role(" ", "Jan 2016", "Aug 2017")) }
        ul {
            li { "Develop a social network platform for a retirement village; using the Laravel framework" }
            li { "Designed and developed small websites for local businesses" }
            li { "Computer diagnosis and repair, NAS and backup systems installation for local businesses with DSS Digital" }
        }

        h3 { "Modus Corporation" }
        h4 {(role("Developer", "Aug 2011", "Dec 2014"))}
        ul {
            li { "Extend functionality of cloud based IoT fleet management system"; br; "written in "
                a href="https://nodejs.org/" {"Node.js"} " and "
                a href="https://golang.org/" {"Go"}
            }
            li { "Maintain and develop in-house CMS and email/SMS broadcast system built in PHP" }
            li { "Responsive, mobile first website template builds using React"}
            li { "Develop tools to maintain full Linux server stack including continuous integration and deployment"}
        }

        h3 { "redzWeb digital marketing" }
        h4 {(role("Developer", "Jan  2008", "Feb 2009"))}
        ul {
            li { "Developed components for the " a href="https://www.joomla.org" { "Joomla!" } " CMS"; }
            li { "Managed media streaming services for live online broadcasts" }
        }
        hr class="page-break-after";

        h2 {("Education")}
        h3 {("Bachelor of Engineering (Honors) - Electrical Engineering")}
        h4 {("2023 - University of Wollongong")}
        p {("Electives: Wireless Communication Systems, Network Engineering, Embedded Systems.")}
        p {("Extra curricula activities: Participated in and organised events within the UOW maker space. Designed and developed software platform for robotics experiments. Placed in several annual innovation fair showcases.")}

        h3 {("Advanced Diploma of Professional Game Development (Programming)")}
        h4 {("2010 - Academy of Interactive Entertainment Canberra")}
        hr;

        h2 {("Technical Skills")}
        ul {
            li { "Server side scripting and applications with a variety of tools and languages; Go, Rust, NodeJS, C#, PHP, Python, and more" }
            li { "Thorough knowledge of Linux server environment and web hosting environment configuration, skills relating to sysops/devops" }
            li { "Cloud service provision, management and deployment of applications to cloud platforms, CI/CD, Cloud orchestration using Kubernetes/Docker"}
            li { "Creating technical documentation"}
            li { "Relational database design"}
            li { "Modern game development practices; shader languages, engine design, optimisation for real-time rendering pipelines"}
            li { "Archaic game development practices; interfacing with systems on a hardware level, efficiency and optimisation for limited capacity"}
            li { "Digital electronics, microcontroller software, digital and analog circuit design and analysis" }
            li { "PCB design and fabrication"}
        }

        hr;
        h2 { "Referees" }
        p { "Referees can be provided upon inquiry."}

        div class="hide-on-print" {
            hr;
            p { "This document has been designed to be viewable in print and on the web."}
        }
        div class="hide-on-web" {
            hr;
            p { "This is a living document." br; "The latest version can be viewed on the web at " a href="https://darfk.net/resume/" { "https://darfk.net/resume/"} " ." }
        }


    )
}

fn banner_links() -> Markup {
    html!(ul {
        // nothing here yet
        // li { a href="/about" {("about")} }
        li { a href="/" {("home")} }
        li { a href="/projects" {("projects")} }
        // li { a href="/notes" {("notes")} }
        li { a href="/resume" {("résumé")} }
        li { a href="/links" {("links")} }
        li { a href="ts3server:teamspeak.darfk.net" {("teamspeak")}}
        li { a href="https://mastodon.social/@daafuku" {("mastodon")}}
    })
}

fn layout(title: Option<&str>, content: Markup) -> Markup {
    let year = chrono::Utc::now().year().to_string();

    html!(
        (DOCTYPE) html {
            head {
                meta charset="utf-8";
                meta name="viewport" content="width=device-width, initial-scale=1";
                link rel="stylesheet" href="/main.css";
                title { ("darfk.net - Thomas Payne")
                    @if let Some(title) = title {
                        (" - ") (title)
                    }
                }
            }
            body {
                div id="container" class="center" {
                    header {
                        div id="banner" { h1 {
                            ("Thomas Payne")
                            @if let Some(title) = title {
                                (" - ") (title)
                            }
                        }}
                        (banner_links())
                    }
                    div id="content" {
                        (content)
                    }
                    footer {
                        ("© ") (year) (" - Thomas Payne")
                    }
                }
            }
        }
    )
}

#[derive(PartialEq, Eq)]
enum PageType {
    Project,
    Other,
}

struct Page {
    path: String,
    title: String,
    description: String,
    markup: Markup,
    typ: PageType,
}

impl Page {
    fn new(path: &str, title: &str, description: &str, markup: Markup, typ: PageType) -> Self {
        Page {
            path: path.to_string(),
            title: title.to_string(),
            description: description.to_string(),
            markup: markup,
            typ: typ,
        }
    }
}

fn markup_from_markdown_file(path: &str) -> Markup {
    maud::PreEscaped(markdown::to_html(&fs::read_to_string(path).unwrap()))
}

fn main() {
    let mut static_resources = Vec::<&str>::new();
    static_resources.push("main.css");

    let mut pages = Vec::<Page>::new();

    pages.push(Page::new(
        "index",
        "Home Page",
        "",
        layout(None, index()),
        PageType::Other,
    ));

    pages.push(Page::new(
        "/resume",
        "résumé",
        "résumé of Thomas Payne",
        layout(Some("résumé"), resume()),
        PageType::Other,
    ));

    pages.push(Page::new(
        "/projects/website",
        "This website",
        "How this website is made",
        layout(Some("This website"), projects_website()),
        PageType::Project,
    ));

    pages.push(Page::new(
        "/links",
        "Links",
        "Links which I recommend taking a look at",
        layout(Some("Links"), markup_from_markdown_file("pages/links.md")),
        PageType::Other,
    ));

    pages.push(Page::new(
        "/projects/coles",
        "Coles Barcode Generator",
        "Getting free parking at my local mall",
        layout(
            Some("Coles Barcode Generator"),
            markup_from_markdown_file("projects/coles-barcode.md"),
        ),
        PageType::Project,
    ));

    pages.push(Page::new(
        "/projects",
        "Projects",
        "list of projects",
        layout(Some("Projects"), projects_index(&pages)),
        PageType::Other,
    ));

    pages.drain(..).for_each(|page| {
        let page_file_path_string = match page.path.as_str() {
            "index" => format!("output/index.html"),
            _ => format!("output/{}/index.html", page.path),
        };
        let page_file_path = Path::new(page_file_path_string.as_str());

        fs::create_dir_all(page_file_path.parent().unwrap()).unwrap();
        fs::write(page_file_path, page.markup.into_string()).unwrap();
    });

    static_resources.drain(..).for_each(|static_resource| {
        fs::copy(
            format!("static/{}", static_resource),
            format!("output/{}", static_resource),
        )
        .unwrap();
    })
}