Skip to main content

logicaffeine_web/ui/pages/
terms.rs

1//! Terms of service page.
2//!
3//! Renders the terms of service from an embedded HTML file with consistent
4//! legal page styling and navigation.
5//!
6//! # Route
7//!
8//! Accessed via `Route::Terms`.
9
10use dioxus::prelude::*;
11use crate::ui::components::main_nav::{MainNav, ActivePage};
12use crate::ui::components::footer::Footer;
13use crate::ui::seo::{JsonLdMultiple, PageHead, organization_schema, webpage_schema, breadcrumb_schema, BreadcrumbItem, pages as seo_pages};
14
15// Compiled in natively (tests, SSG prerender); wasm fetches the staged /data copy
16// so the ~135 KB of legal prose never rides inside the shipped binary.
17#[cfg(not(target_arch = "wasm32"))]
18const TERMS_HTML: &str = include_str!("../../../terms.html");
19
20const LEGAL_STYLE: &str = r#"
21.legal-container {
22    min-height: 100vh;
23    display: flex;
24    flex-direction: column;
25    background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
26}
27
28.legal-content {
29    flex: 1;
30    max-width: 900px;
31    margin: 0 auto;
32    padding: 40px 20px 60px;
33    width: 100%;
34}
35
36.legal-content-inner {
37    background: rgba(255, 255, 255, 0.98);
38    border-radius: 16px;
39    padding: 40px;
40    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
41}
42
43.legal-footer {
44    border-top: 1px solid rgba(255,255,255,0.06);
45    padding: 24px 20px;
46    text-align: center;
47    color: rgba(229,231,235,0.56);
48    font-size: 13px;
49}
50
51.legal-footer a {
52    color: rgba(229,231,235,0.72);
53    text-decoration: none;
54    margin: 0 8px;
55}
56
57.legal-footer a:hover {
58    color: #a78bfa;
59}
60
61.github-link {
62    display: inline-flex;
63    align-items: center;
64    gap: 6px;
65}
66"#;
67
68#[component]
69pub fn Terms() -> Element {
70    let breadcrumbs = vec![
71        BreadcrumbItem { name: "Home", path: "/" },
72        BreadcrumbItem { name: "Terms of Service", path: "/terms" },
73    ];
74    let schemas = vec![
75        organization_schema(),
76        webpage_schema("Terms of Service", "Terms and conditions for using LOGICAFFEINE. Business Source License details and usage policies.", "/terms"),
77        breadcrumb_schema(&breadcrumbs),
78    ];
79
80    rsx! {
81        PageHead {
82            title: seo_pages::TERMS.title,
83            description: seo_pages::TERMS.description,
84            canonical_path: seo_pages::TERMS.canonical_path,
85        }
86        style { "{LEGAL_STYLE}" }
87        JsonLdMultiple { schemas }
88
89        div { class: "legal-container",
90            MainNav { active: ActivePage::Other, subtitle: Some("Terms of Use") }
91
92            main { class: "legal-content",
93                TermsBody {}
94            }
95
96            Footer {}
97        }
98    }
99}
100
101#[cfg(not(target_arch = "wasm32"))]
102#[component]
103fn TermsBody() -> Element {
104    rsx! {
105        div { class: "legal-content-inner", dangerous_inner_html: "{TERMS_HTML}" }
106    }
107}
108
109#[cfg(target_arch = "wasm32")]
110#[component]
111fn TermsBody() -> Element {
112    let mut body = use_resource(|| crate::ui::data_fetch::fetch_static_text("/data/terms.html"));
113    let state = body.read_unchecked();
114    match &*state {
115        Some(Ok(html)) => rsx! {
116            div { class: "legal-content-inner", dangerous_inner_html: "{html}" }
117        },
118        Some(Err(e)) => rsx! {
119            div { class: "legal-content-inner",
120                p { "The terms of service failed to load: {e}" }
121                button { onclick: move |_| body.restart(), "Retry" }
122            }
123        },
124        None => rsx! {
125            div { class: "legal-content-inner", p { "Loading\u{2026}" } }
126        },
127    }
128}