AkurAI Build
Menu

BifrOSt-Web

public

Latest change 7c2cb56e0351160e3b6c17af94380b79b538c130 - Publish 0.2.2 changelog and refresh release facts by Ólafur Búi Ólafsson

use dioxus::prelude::*;
use serde::{Deserialize, Serialize};

const CSS: Asset = asset!("/public/assets/main.css");

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct HomepageContent {
    locale: String,
    design_contract: String,
    meta: MetaContent,
    brand: BrandContent,
    ui: UiContent,
    languages: Vec<LanguageOption>,
    navigation: Vec<NavigationItem>,
    hero: HeroContent,
    release_facts: Vec<Fact>,
    experience: ExperienceContent,
    build: BuildContent,
    safety: SafetyContent,
    download: DownloadContent,
    footer: FooterContent,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct MetaContent {
    title: String,
    description: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct BrandContent {
    name: String,
    home_aria: String,
    mark_path: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct UiContent {
    primary_navigation_aria: String,
    mobile_navigation_aria: String,
    open_navigation: String,
    language_control: String,
    screenshots_aria: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct LanguageOption {
    code: String,
    short_label: String,
    label: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct NavigationItem {
    label: String,
    href: String,
    kind: String,
    external: bool,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct HeroContent {
    origin: String,
    headline_line_1: String,
    headline_line_2: String,
    lede: String,
    primary_label: String,
    primary_href: String,
    secondary_label: String,
    secondary_href: String,
    image_path: String,
    image_alt: String,
    marker_top: String,
    marker_bottom: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Fact {
    label: String,
    value: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct ExperienceContent {
    heading: String,
    intro: String,
    image_coordinate: String,
    scenes: Vec<SceneContent>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct SceneContent {
    label: String,
    title: String,
    note: String,
    image_path: String,
    image_alt: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct BuildContent {
    heading: String,
    intro: String,
    layers: Vec<LayerContent>,
    profiles_intro: String,
    profiles: Vec<String>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct LayerContent {
    tone: String,
    label: String,
    value: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct SafetyContent {
    heading: String,
    intro: String,
    steps: Vec<SafetyStep>,
    links: Vec<LinkContent>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct SafetyStep {
    label: String,
    detail: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct LinkContent {
    label: String,
    href: String,
    external: bool,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct DownloadContent {
    heading: String,
    intro: String,
    cta_label: String,
    cta_href: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct FooterContent {
    summary: String,
    links: Vec<LinkContent>,
    disclaimer: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct ChangelogContent {
    locale: String,
    design_contract: String,
    meta: MetaContent,
    brand: BrandContent,
    ui: UiContent,
    languages: Vec<LanguageOption>,
    navigation: Vec<NavigationItem>,
    hero: ChangelogHero,
    os: OsHighlights,
    repository_eyebrow: String,
    repository_heading: String,
    repository_intro: String,
    changes_label: String,
    repositories: Vec<RepositoryUpdate>,
    footer: FooterContent,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct ChangelogHero {
    eyebrow: String,
    heading: String,
    intro: String,
    status_label: String,
    status_value: String,
    development_label: String,
    development_value: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct OsHighlights {
    eyebrow: String,
    heading: String,
    intro: String,
    items: Vec<Highlight>,
    links: Vec<LinkContent>,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct Highlight {
    title: String,
    detail: String,
}

#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
struct RepositoryUpdate {
    id: String,
    index: String,
    kicker: String,
    name: String,
    status: String,
    summary: String,
    changes: Vec<String>,
    links: Vec<LinkContent>,
}

#[cfg(feature = "server")]
thread_local! {
    static CONTENT_DB: rusqlite::Connection = {
        let path = std::env::var("BIFROST_CONTENT_DB")
            .unwrap_or_else(|_| "data/content.db".to_string());
        rusqlite::Connection::open(path).expect("failed to open the BifrOSt content database")
    };
}

#[get("/api/content/{locale}")]
async fn get_homepage_content(locale: String) -> Result<HomepageContent> {
    let payload = CONTENT_DB.with(|database| {
        database.query_row(
            "SELECT payload FROM page_content WHERE page = ?1 AND locale = ?2",
            rusqlite::params!["home", locale],
            |row| row.get::<_, String>(0),
        )
    })?;

    Ok(serde_json::from_str(&payload)?)
}

#[get("/api/changelog/{locale}")]
async fn get_changelog_content(locale: String) -> Result<ChangelogContent> {
    let payload = CONTENT_DB.with(|database| {
        database.query_row(
            "SELECT payload FROM changelog_content WHERE locale = ?1",
            rusqlite::params![locale],
            |row| row.get::<_, String>(0),
        )
    })?;

    Ok(serde_json::from_str(&payload)?)
}

#[derive(Routable, Clone, PartialEq)]
enum Route {
    #[route("/")]
    HomePage {},
    #[route("/changelog")]
    ChangelogPage {},
}

fn main() {
    dioxus::launch(App);
}

#[component]
fn App() -> Element {
    let locale = use_signal(|| "is".to_string());
    use_context_provider(|| locale);
    let stored_locale = locale;
    use_effect(move || {
        let mut locale_from_storage = stored_locale;
        spawn(async move {
            if let Ok(value) =
                document::eval(r#"return localStorage.getItem("bifrost-locale");"#).await
                && let Some(code) = value.as_str()
                && matches!(code, "is" | "en")
                && locale_from_storage() != code
            {
                locale_from_storage.set(code.to_string());
            }
        });

        document::eval(
            r#"
            if (!window.__bifrostLanguageObserver) {
                const syncLanguage = () => {
                    const shell = document.querySelector(".site-shell[lang]");
                    if (shell) document.documentElement.lang = shell.lang;
                };
                const observer = new MutationObserver(syncLanguage);
                observer.observe(document.body, {
                    attributes: true,
                    attributeFilter: ["lang"],
                    childList: true,
                    subtree: true
                });
                window.__bifrostLanguageObserver = observer;
                syncLanguage();
            }
            "#,
        );
    });

    rsx! {
        document::Stylesheet { href: CSS }
        document::Meta { name: "theme-color", content: "#07111f" }
        Router::<Route> {}
    }
}

fn loading_view() -> Element {
    rsx! {
        div {
            class: "content-loading",
            aria_busy: "true",
            span {}
            span {}
            span {}
        }
    }
}

fn select_locale(mut locale: Signal<String>, requested: String) {
    let code = if requested == "en" { "en" } else { "is" };
    locale.set(code.to_string());
    let script = format!(r#"localStorage.setItem("bifrost-locale", {code:?});"#);
    document::eval(&script);
}

#[component]
fn SiteHeader(
    brand: BrandContent,
    ui: UiContent,
    languages: Vec<LanguageOption>,
    navigation: Vec<NavigationItem>,
    current_locale: String,
    locale: Signal<String>,
    brand_href: String,
) -> Element {
    rsx! {
        header {
            class: "site-header",
            a {
                class: "brand",
                href: "{brand_href}",
                aria_label: "{brand.home_aria}",
                img { src: "{brand.mark_path}", alt: "", width: "40", height: "40" }
                span { "{brand.name}" }
            }

            div {
                class: "header-actions",
                nav {
                    class: "desktop-nav",
                    aria_label: "{ui.primary_navigation_aria}",
                    for item in navigation.iter() {
                        a {
                            key: "{item.href}",
                            class: if item.kind == "source" { "nav-source" } else { "" },
                            href: "{item.href}",
                            target: if item.external { "_blank" } else { "_self" },
                            rel: if item.external { "noreferrer" } else { "" },
                            "{item.label}"
                            if item.kind == "source" {
                                span { class: "link-arrow", aria_hidden: "true" }
                            }
                        }
                    }
                }

                div {
                    class: "language-switch",
                    role: "group",
                    aria_label: "{ui.language_control}",
                    for option in languages.iter() {
                        {
                            let code = option.code.clone();
                            rsx! {
                                button {
                                    key: "{option.code}",
                                    class: if option.code == current_locale { "is-active" } else { "" },
                                    aria_pressed: option.code == current_locale,
                                    title: "{option.label}",
                                    onclick: move |_| select_locale(locale, code.clone()),
                                    "{option.short_label}"
                                }
                            }
                        }
                    }
                }

                details {
                    class: "mobile-nav",
                    summary {
                        aria_label: "{ui.open_navigation}",
                        span { class: "menu-line" }
                        span { class: "menu-line" }
                    }
                    nav {
                        aria_label: "{ui.mobile_navigation_aria}",
                        for item in navigation.iter() {
                            a {
                                key: "mobile-{item.href}",
                                href: "{item.href}",
                                target: if item.external { "_blank" } else { "_self" },
                                rel: if item.external { "noreferrer" } else { "" },
                                "{item.label}"
                            }
                        }
                    }
                }
            }
        }
    }
}

#[component]
fn SiteFooter(brand: BrandContent, footer: FooterContent) -> Element {
    rsx! {
        footer {
            div {
                class: "footer-brand",
                img { src: "{brand.mark_path}", alt: "", width: "34", height: "34" }
                span { "{brand.name}" }
            }
            p { "{footer.summary}" }
            div {
                class: "footer-links",
                for link in footer.links.iter() {
                    a {
                        key: "{link.href}",
                        href: "{link.href}",
                        target: if link.external { "_blank" } else { "_self" },
                        rel: if link.external { "noreferrer" } else { "" },
                        "{link.label}"
                    }
                }
            }
            p { class: "footer-note", "{footer.disclaimer}" }
        }
    }
}

#[component]
fn HomePage() -> Element {
    let locale = use_context::<Signal<String>>();

    rsx! {
        SuspenseBoundary {
            fallback: |_| loading_view(),
            ContentLoader { locale }
        }
    }
}

#[component]
fn ContentLoader(mut locale: Signal<String>) -> Element {
    let content_resource = use_server_future(move || {
        let requested_locale = locale();
        async move {
            get_homepage_content(requested_locale)
                .await
                .map_err(|error| error.to_string())
        }
    })?;

    let loaded = content_resource.read();
    let Some(result) = loaded.as_ref() else {
        return rsx! {};
    };

    match result {
        Ok(content) => rsx! { Homepage { content: content.clone(), locale } },
        Err(error) => rsx! {
            main { class: "content-error", role: "alert", code { "{error}" } }
        },
    }
}

#[component]
fn Homepage(content: HomepageContent, mut locale: Signal<String>) -> Element {
    let mut active_scene = use_signal(|| 0usize);
    let scene_index = active_scene().min(content.experience.scenes.len().saturating_sub(1));
    let scene = &content.experience.scenes[scene_index];

    rsx! {
        document::Title { "{content.meta.title}" }
        document::Meta { name: "description", content: "{content.meta.description}" }

        div {
            class: "site-shell",
            lang: "{content.locale}",

            div {
                class: "direction-contract",
                hidden: true,
                dangerous_inner_html: "{content.design_contract}",
            }

            SiteHeader {
                brand: content.brand.clone(),
                ui: content.ui.clone(),
                languages: content.languages.clone(),
                navigation: content.navigation.clone(),
                current_locale: content.locale.clone(),
                locale,
                brand_href: "#top".to_string(),
            }

            main {
                id: "top",
                section {
                    class: "hero",
                    div {
                        class: "hero-copy",
                        p { class: "hero-origin", "{content.hero.origin}" }
                        h1 {
                            span { "{content.hero.headline_line_1}" }
                            " "
                            span { class: "title-accent", "{content.hero.headline_line_2}" }
                        }
                        p { class: "hero-lede", "{content.hero.lede}" }
                        div {
                            class: "hero-actions",
                            a {
                                class: "button button-primary",
                                href: "{content.hero.primary_href}",
                                target: "_blank",
                                rel: "noreferrer",
                                "{content.hero.primary_label}"
                                span { class: "link-arrow", aria_hidden: "true" }
                            }
                            a {
                                class: "text-link",
                                href: "{content.hero.secondary_href}",
                                "{content.hero.secondary_label}"
                            }
                        }
                    }

                    div {
                        class: "hero-visual",
                        div {
                            class: "hero-image-wrap",
                            img {
                                src: "{content.hero.image_path}",
                                alt: "{content.hero.image_alt}",
                                fetchpriority: "high",
                            }
                        }
                        div { class: "hero-marker hero-marker-top", aria_hidden: "true", "{content.hero.marker_top}" }
                        div { class: "hero-marker hero-marker-bottom", aria_hidden: "true", "{content.hero.marker_bottom}" }
                    }

                    div {
                        class: "aurora-path",
                        aria_hidden: "true",
                        span { class: "aurora-line aurora-line-one" }
                        span { class: "aurora-line aurora-line-two" }
                        span { class: "aurora-line aurora-line-three" }
                    }
                }

                section {
                    class: "release-ribbon",
                    for fact in &content.release_facts {
                        div {
                            key: "{fact.label}",
                            span { "{fact.label}" }
                            strong { "{fact.value}" }
                        }
                    }
                }

                section {
                    class: "experience-section",
                    id: "experience",
                    div {
                        class: "section-intro",
                        h2 { "{content.experience.heading}" }
                        p { "{content.experience.intro}" }
                    }

                    div {
                        class: "scene-stage",
                        div {
                            class: "scene-image",
                            img { src: "{scene.image_path}", alt: "{scene.image_alt}" }
                            div { class: "image-coordinate", aria_hidden: "true", "{content.experience.image_coordinate}" }
                        }
                        div {
                            class: "scene-notes",
                            div {
                                class: "scene-tabs",
                                role: "tablist",
                                aria_label: "{content.ui.screenshots_aria}",
                                for (index, item) in content.experience.scenes.iter().enumerate() {
                                    button {
                                        key: "{item.label}",
                                        class: if scene_index == index { "scene-tab is-active" } else { "scene-tab" },
                                        role: "tab",
                                        aria_selected: scene_index == index,
                                        onclick: move |_| active_scene.set(index),
                                        span { class: "tab-index", "{index + 1}" }
                                        "{item.label}"
                                    }
                                }
                            }
                            div {
                                class: "scene-caption",
                                aria_live: "polite",
                                p { class: "scene-count", "{scene_index + 1:02} / {content.experience.scenes.len():02}" }
                                h3 { "{scene.title}" }
                                p { "{scene.note}" }
                            }
                        }
                    }
                }

                section {
                    class: "build-section",
                    id: "built",
                    div {
                        class: "build-heading",
                        h2 { "{content.build.heading}" }
                        p { "{content.build.intro}" }
                    }
                    div {
                        class: "stack-diagram",
                        for layer in &content.build.layers {
                            div {
                                key: "{layer.label}",
                                class: "stack-layer stack-{layer.tone}",
                                span { "{layer.label}" }
                                strong { "{layer.value}" }
                            }
                        }
                    }
                    div {
                        class: "profile-line",
                        p { "{content.build.profiles_intro}" }
                        ul {
                            for profile in &content.build.profiles {
                                li { key: "{profile}", "{profile}" }
                            }
                        }
                    }
                }

                section {
                    class: "safety-section",
                    id: "install",
                    div {
                        class: "safety-heading",
                        svg {
                            class: "safety-icon",
                            view_box: "0 0 48 48",
                            role: "presentation",
                            path { d: "M24 4 44 40H4L24 4Z", fill: "none", stroke: "currentColor", stroke_width: "2" }
                            path { d: "M24 17v11", stroke: "currentColor", stroke_width: "3", stroke_linecap: "round" }
                            circle { cx: "24", cy: "34", r: "1.8", fill: "currentColor" }
                        }
                        h2 { "{content.safety.heading}" }
                    }
                    div {
                        class: "safety-copy",
                        p { "{content.safety.intro}" }
                        ol {
                            for step in &content.safety.steps {
                                li {
                                    key: "{step.label}",
                                    span { "{step.label}" }
                                    strong { "{step.detail}" }
                                }
                            }
                        }
                        div {
                            class: "safety-links",
                            for link in &content.safety.links {
                                a {
                                    key: "{link.href}",
                                    href: "{link.href}",
                                    target: if link.external { "_blank" } else { "_self" },
                                    rel: if link.external { "noreferrer" } else { "" },
                                    "{link.label}"
                                    span { class: "link-arrow", aria_hidden: "true" }
                                }
                            }
                        }
                    }
                }

                section {
                    class: "download-section",
                    div {
                        class: "download-mark",
                        img { src: "{content.brand.mark_path}", alt: "", loading: "lazy" }
                    }
                    div {
                        h2 { "{content.download.heading}" }
                        p { "{content.download.intro}" }
                    }
                    a {
                        class: "button button-light",
                        href: "{content.download.cta_href}",
                        target: "_blank",
                        rel: "noreferrer",
                        "{content.download.cta_label}"
                        span { class: "link-arrow", aria_hidden: "true" }
                    }
                }
            }

            SiteFooter { brand: content.brand.clone(), footer: content.footer.clone() }
        }
    }
}

#[component]
fn ChangelogPage() -> Element {
    let locale = use_context::<Signal<String>>();

    rsx! {
        SuspenseBoundary {
            fallback: |_| loading_view(),
            ChangelogLoader { locale }
        }
    }
}

#[component]
fn ChangelogLoader(mut locale: Signal<String>) -> Element {
    let content_resource = use_server_future(move || {
        let requested_locale = locale();
        async move {
            get_changelog_content(requested_locale)
                .await
                .map_err(|error| error.to_string())
        }
    })?;

    let loaded = content_resource.read();
    let Some(result) = loaded.as_ref() else {
        return rsx! {};
    };

    match result {
        Ok(content) => rsx! { Changelog { content: content.clone(), locale } },
        Err(error) => rsx! {
            main { class: "content-error", role: "alert", code { "{error}" } }
        },
    }
}

#[component]
fn Changelog(content: ChangelogContent, mut locale: Signal<String>) -> Element {
    rsx! {
        document::Title { "{content.meta.title}" }
        document::Meta { name: "description", content: "{content.meta.description}" }

        div {
            class: "site-shell",
            lang: "{content.locale}",

            div {
                class: "direction-contract",
                hidden: true,
                dangerous_inner_html: "{content.design_contract}",
            }

            SiteHeader {
                brand: content.brand.clone(),
                ui: content.ui.clone(),
                languages: content.languages.clone(),
                navigation: content.navigation.clone(),
                current_locale: content.locale.clone(),
                locale,
                brand_href: "/".to_string(),
            }

            main {
                id: "top",
                class: "changelog-main",

                section {
                    class: "changelog-hero",
                    div {
                        class: "changelog-hero-copy",
                        p { class: "changelog-eyebrow", "{content.hero.eyebrow}" }
                        h1 { "{content.hero.heading}" }
                        p { class: "changelog-intro", "{content.hero.intro}" }
                    }
                    div {
                        class: "changelog-status",
                        div {
                            span { "{content.hero.status_label}" }
                            strong { "{content.hero.status_value}" }
                        }
                        div {
                            span { "{content.hero.development_label}" }
                            strong { "{content.hero.development_value}" }
                        }
                    }
                    div {
                        class: "changelog-route",
                        aria_hidden: "true",
                        span {}
                        span {}
                        span {}
                    }
                    div {
                        class: "changelog-trails",
                        aria_hidden: "true",
                        span {}
                        span {}
                        span {}
                    }
                }

                section {
                    class: "changelog-os",
                    id: "bifrost",
                    div {
                        class: "changelog-section-heading",
                        p { class: "changelog-eyebrow", "{content.os.eyebrow}" }
                        h2 { "{content.os.heading}" }
                        p { "{content.os.intro}" }
                    }
                    ol {
                        class: "highlight-ledger",
                        for (index, item) in content.os.items.iter().enumerate() {
                            {
                                let number = format!("{:02}", index + 1);
                                rsx! {
                                    li {
                                        key: "{item.title}",
                                        span { class: "highlight-index", "{number}" }
                                        div {
                                            h3 { "{item.title}" }
                                            p { "{item.detail}" }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    div {
                        class: "changelog-links",
                        for link in &content.os.links {
                            a {
                                key: "{link.href}",
                                href: "{link.href}",
                                target: if link.external { "_blank" } else { "_self" },
                                rel: if link.external { "noreferrer" } else { "" },
                                "{link.label}"
                                span { class: "link-arrow", aria_hidden: "true" }
                            }
                        }
                    }
                }

                section {
                    class: "repository-section",
                    div {
                        class: "repository-intro",
                        p { class: "changelog-eyebrow", "{content.repository_eyebrow}" }
                        h2 { "{content.repository_heading}" }
                        p { "{content.repository_intro}" }
                    }
                    div {
                        class: "repository-timeline",
                        for repository in &content.repositories {
                            article {
                                class: "repository-update",
                                id: "{repository.id}",
                                div {
                                    class: "repository-rail",
                                    span { "{repository.index}" }
                                    small { "{repository.kicker}" }
                                }
                                div {
                                    class: "repository-copy",
                                    div {
                                        class: "repository-title",
                                        h3 { "{repository.name}" }
                                        span { "{repository.status}" }
                                    }
                                    p { class: "repository-summary", "{repository.summary}" }
                                    h4 { "{content.changes_label}" }
                                    ul {
                                        for change in &repository.changes {
                                            li { key: "{change}", "{change}" }
                                        }
                                    }
                                    div {
                                        class: "repository-links",
                                        for link in &repository.links {
                                            a {
                                                key: "{link.href}",
                                                href: "{link.href}",
                                                target: if link.external { "_blank" } else { "_self" },
                                                rel: if link.external { "noreferrer" } else { "" },
                                                "{link.label}"
                                                span { class: "link-arrow", aria_hidden: "true" }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            SiteFooter { brand: content.brand.clone(), footer: content.footer.clone() }
        }
    }
}