Files
certifai/src/app.rs
T
Sharang Parnerkar ca5da3c232
CI / Format (push) Successful in 22s
CI / Clippy (push) Successful in 2m29s
CI / Security Audit (push) Successful in 1m32s
CI / Tests (push) Successful in 3m32s
CI / Deploy (push) Successful in 2s
CI / E2E Tests (push) Failing after 31s
feat(ui): redesign landing page and update styling
Overhaul landing page design with updated CSS, Tailwind config, and
i18n translations across all supported languages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:34:58 +01:00

136 lines
4.7 KiB
Rust

use crate::i18n::Locale;
use crate::{components::*, pages::*};
use dioxus::prelude::*;
/// Application routes.
///
/// Public pages (`LandingPage`, `ImpressumPage`, `PrivacyPage`) live
/// outside the `AppShell` layout. Authenticated pages are wrapped in
/// `AppShell` which renders the sidebar. `DeveloperShell` and `OrgShell`
/// provide nested tab navigation within the app shell.
#[derive(Debug, Clone, Routable, PartialEq)]
#[rustfmt::skip]
pub enum Route {
#[route("/")]
LandingPage {},
#[route("/impressum")]
ImpressumPage {},
#[route("/privacy")]
PrivacyPage {},
#[layout(AppShell)]
#[route("/dashboard")]
DashboardPage {},
#[route("/providers")]
ProvidersPage {},
#[layout(DeveloperShell)]
#[route("/developer/agents")]
AgentsPage {},
#[route("/developer/flow")]
FlowPage {},
#[route("/developer/analytics")]
AnalyticsPage {},
#[end_layout]
#[layout(OrgShell)]
#[route("/organization/pricing")]
OrgPricingPage {},
#[route("/organization/dashboard")]
OrgDashboardPage {},
#[end_layout]
#[end_layout]
#[route("/login?:redirect_url")]
Login { redirect_url: String },
}
const FAVICON: Asset = asset!("/assets/favicon.svg");
const MAIN_CSS: Asset = asset!("/assets/main.css");
const TAILWIND_CSS: Asset = asset!("/assets/tailwind.css");
const MANIFEST: Asset = asset!("/assets/manifest.json");
/// Google Fonts URL for Literata (body) and Sora (headings).
const GOOGLE_FONTS: &str = "https://fonts.googleapis.com/css2?\
family=Sora:wght@300;400;500;600;700;800&\
family=Literata:ital,opsz,wght@0,7..72,400;0,7..72,500;0,7..72,600;0,7..72,700;1,7..72,400&\
display=swap";
/// Root application component. Loads global assets and mounts the router.
///
/// Provides a `Signal<Locale>` context that all child components can read
/// via `use_context::<Signal<Locale>>()` to access the current locale.
/// The locale is persisted in `localStorage` under `"certifai_locale"`.
#[component]
pub fn App() -> Element {
// Read persisted locale from localStorage on first render.
let initial_locale = {
#[cfg(feature = "web")]
{
web_sys::window()
.and_then(|w| w.local_storage().ok().flatten())
.and_then(|s| s.get_item("certifai_locale").ok().flatten())
.map(|code| Locale::from_code(&code))
.unwrap_or_default()
}
#[cfg(not(feature = "web"))]
{
Locale::default()
}
};
use_context_provider(|| Signal::new(initial_locale));
rsx! {
// Seggwat feedback widget
document::Script {
src: "https://seggwat.com/static/widgets/v1/seggwat-feedback.js",
r#defer: true,
"data-project-key": "a04b8cf1-9177-42ce-8a7b-084f38b99799",
"data-button-color": "#8b5cf6",
"data-button-position": "right-side",
"data-enable-screenshots": "true",
}
document::Link { rel: "icon", href: FAVICON }
document::Link { rel: "manifest", href: MANIFEST }
document::Meta { name: "theme-color", content: "#0c0a1d" }
document::Meta { name: "apple-mobile-web-app-capable", content: "yes" }
document::Meta {
name: "apple-mobile-web-app-status-bar-style",
content: "black-translucent",
}
document::Link { rel: "apple-touch-icon", href: FAVICON }
document::Link { rel: "preconnect", href: "https://fonts.googleapis.com" }
document::Link {
rel: "preconnect",
href: "https://fonts.gstatic.com",
crossorigin: "anonymous",
}
document::Link { rel: "stylesheet", href: GOOGLE_FONTS }
document::Link { rel: "stylesheet", href: TAILWIND_CSS }
document::Link { rel: "stylesheet", href: MAIN_CSS }
// Register PWA service worker
document::Script {
r#"
if ('serviceWorker' in navigator) {{
navigator.serviceWorker.register('/assets/sw.js')
.catch(function(e) {{ console.warn('SW registration failed:', e); }});
}}
"#
}
// Apply persisted theme to <html> before first paint to avoid flash.
// Default to certifai-dark when no preference is stored.
document::Script {
r#"
(function() {{
var t = localStorage.getItem('theme') || 'certifai-dark';
document.documentElement.setAttribute('data-theme', t);
}})();
"#
}
Router::<Route> {}
}
}