+
+
+
"Building the Future of Trusted System Software Together"
-
+
"Leading technology partners creating secure, reusable, and reliable firmware for modern client devices."
-
-
+
-
- {/* Video Section */}
- {/* Top row: icon/text + main iframe */}
-
-
-
-
-
-
+
+
+
"Welcome"
-
+
"Learn how ODP projects help build secure, modern devices"
-
+
+ allowfullscreen
+ >
diff --git a/src/components/mod.rs b/src/components/mod.rs
index 3718f1a..74b44e5 100644
--- a/src/components/mod.rs
+++ b/src/components/mod.rs
@@ -6,9 +6,11 @@ pub mod header;
pub mod image_button;
pub mod landing_page;
pub mod main;
+pub mod page_layout;
pub mod partner;
pub mod partners_grid;
pub mod project_introduction;
pub mod projects_component;
pub mod repo_view;
pub mod team_grid;
+pub mod themed_icon;
diff --git a/src/components/page_layout.rs b/src/components/page_layout.rs
new file mode 100644
index 0000000..1180c3b
--- /dev/null
+++ b/src/components/page_layout.rs
@@ -0,0 +1,57 @@
+//! Shared page chrome.
+//!
+//! Wraps every standard page in:
+//!
+//! * an `ErrorBoundary` that renders a generic fallback list,
+//! * the outer `w-full min-h-screen` container,
+//! * the site ` `,
+//! * the page `children`,
+//! * and the site ` `.
+//!
+//! Pages that need horizontal scrolling on overflow (typically those that
+//! embed the repository graph SVG, the project introduction overlay, or
+//! other wide content) opt in via `scrollable_x=true`. The default is
+//! `overflow-x-hidden` to match the home / community / team pages.
+
+use crate::components::footer::Footer;
+use crate::components::header::Header;
+use leptos::prelude::*;
+
+#[component]
+pub fn PageLayout(
+ /// If `true`, the outer container allows horizontal scrolling
+ /// (`overflow-x: auto`). Default is `overflow-x-hidden`.
+ #[prop(optional)]
+ scrollable_x: bool,
+ children: Children,
+) -> impl IntoView {
+ let outer_class = if scrollable_x {
+ "w-full min-h-screen overflow-x-auto"
+ } else {
+ "w-full min-h-screen overflow-x-hidden"
+ };
+
+ view! {
+ "Uh oh! Something went wrong!"
+ "Errors: "
+
+ {move || {
+ errors
+ .get()
+ .into_iter()
+ .map(|(_, e)| view! { - {e.to_string()}
})
+ .collect_view()
+ }}
+
+ }
+ }>
+
+
+ {children()}
+
+
+
+ }
+}
diff --git a/src/components/partner.rs b/src/components/partner.rs
index ad1bea1..9a140ec 100644
--- a/src/components/partner.rs
+++ b/src/components/partner.rs
@@ -1,16 +1,16 @@
-use leptos::prelude::*;
-
-#[component]
-pub fn Partner(name: &'static str, url: &'static str, logo: &'static str) -> impl IntoView {
- view! {
-
-
-
-
-
- }
-}
+use leptos::prelude::*;
+
+#[component]
+pub fn Partner(name: &'static str, url: &'static str, logo: &'static str) -> impl IntoView {
+ view! {
+
+
+
+
+
+ }
+}
diff --git a/src/components/partners_grid.rs b/src/components/partners_grid.rs
index 809c9ba..e0eaa6e 100644
--- a/src/components/partners_grid.rs
+++ b/src/components/partners_grid.rs
@@ -34,16 +34,11 @@ const PARTNERS: &[PartnerInfo] = &[
#[component]
pub fn PartnersGrid() -> impl IntoView {
view! {
-
-
-
- {"Our Partners"}
-
+
+
+ {"Our Partners"}
-
+
impl IntoView {
view! {
-
- {/* Left Column: Big Picture with Overlayed Text and Small Image */}
+
+
- {/* Big Picture */}
+
- {/* Overlayed Text and Small Picture */}
+
- {/* Small Picture aligned with project title and 60px above */}
+
{project_title}
{project_summary}
- {/* Right Column */}
- {/* WHAT label */}
-
- {"WHAT"}
-
- {/* WHAT description */}
-
-
- {/* WHY label */}
-
- {"WHY"}
-
- {/* WHY description */}
-
- {project_why}
-
- {/* WHO label */}
-
- {"WHO"}
-
- {/* WHO description */}
+ {"WHAT"}
+
+ {"WHY"}
+ {project_why}
+ {"WHO"}
-
- {/* Left Column */}
+
+
-
- {"System Firmware Domains"}
-
-
+ {"System Firmware Domains"}
+
{"Reusable foundations for secure, high-quality device platforms"}
- {/* Right Column */}
- {/* WHAT label */}
-
- {"WHAT"}
-
- {/* WHAT description */}
-
+ {"WHAT"}
+
{"ODP supports development across three core areas of system firmware. Each domain is designed for modularity, security, and long-term reuse across hardware platforms."}
- {/* WHY label */}
-
- {"WHY"}
-
- {/* WHY description */}
-
+ {"WHY"}
+
{"Modern computing devices need modern solutions that prioritize memory safety and security from the language on up."}
@@ -76,43 +26,28 @@ pub fn ProjectsComponent() -> impl IntoView {
// Projects Details Section
-
-
- {/* Row 1 */}
-
- {/* Image Button */}
+
+
+
+
-
+
- {/* Text Content */}
-
-
- {"Patina (Boot Firmware)"}
-
-
- {"Rethink your boot firmware"}
-
-
+
+ {"Patina (Boot Firmware)"}
+ {"Rethink your boot firmware"}
+
{"Patina provides a UEFI compatible firmware interface written in the Rust language with a focus on memory safety and composition. Compatible with current UEFI device drivers and loaders but with a focus on the future."}
@@ -122,7 +57,9 @@ pub fn ProjectsComponent() -> impl IntoView {
style="text-decoration: none;"
>
{"→ "}
- {"Read the Patina Documentation"}
+
+ {"Read the Patina Documentation"}
+
impl IntoView {
style="text-decoration: none;"
>
{"→ "}
- {"View Patina Source Code on GitHub"}
+
+ {"View Patina Source Code on GitHub"}
+
- {/* Row 2 */}
-
+
-
+
-
-
- {"Secure Embedded Controller"}
-
-
+
+ {"Secure Embedded Controller"}
+
{"A Secure end-to-end Rust-based EC implementation"}
-
+
{"ODP EC provides a modern embedded controller firmware written in Rust. Designed for safety and composability, it serves as a foundational layer for secure device management."}
@@ -175,7 +104,9 @@ pub fn ProjectsComponent() -> impl IntoView {
style="text-decoration: none;"
>
{"→ "}
- {"Read the Secure EC Documentation"}
+
+ {"Read the Secure EC Documentation"}
+
impl IntoView {
style="text-decoration: none;"
>
{"→ "}
- {"View Secure EC Source Code on GitHub"}
+
+ {"View Secure EC Source Code on GitHub"}
+
- {/* Row 3 */}
-
+
-
+
-
-
+
+
{"Unified Embedded Controller Services"}
-
+
{"A standard and secure cross-architecture EC services implementation"}
-
+
{"ODP EC Services provides a modern EC services firmware written in Rust. Designed for safety and composability, it serves as a foundational layer for secure EC services on Windows platforms."}
@@ -228,7 +153,9 @@ pub fn ProjectsComponent() -> impl IntoView {
style="text-decoration: none;"
>
{"→ "}
- {"Read the EC Services Documentation"}
+
+ {"Read the EC Services Documentation"}
+
impl IntoView {
style="text-decoration: none;"
>
{"→ "}
- {"View EC Services Source Code on GitHub"}
+
+ {"View EC Services Source Code on GitHub"}
+
diff --git a/src/components/team_grid.rs b/src/components/team_grid.rs
index a779e0b..c1f71ea 100644
--- a/src/components/team_grid.rs
+++ b/src/components/team_grid.rs
@@ -15,20 +15,31 @@ pub struct TeamMember {
pub fn TeamGrid(#[prop(into)] members: Vec) -> impl IntoView {
view! {
-
- {members.into_iter().map(|member| {
- view! {
-
-
- {format!("{} {}", member.first_name, member.last_name)}
- {member.role}
-
- {"GitHub: "}
- {member.github_username}
+
+ {members
+ .into_iter()
+ .map(|member| {
+ view! {
+
+
+
+ {format!("{} {}", member.first_name, member.last_name)}
+
+ {member.role}
+
+ {"GitHub: "}
+
+ {member.github_username}
+
+
-
- }
- }).collect_view()}
+ }
+ })
+ .collect_view()}
}
diff --git a/src/components/themed_icon.rs b/src/components/themed_icon.rs
new file mode 100644
index 0000000..33add36
--- /dev/null
+++ b/src/components/themed_icon.rs
@@ -0,0 +1,36 @@
+use leptos::prelude::*;
+
+/// A `` that swaps between `/images/light/{name}.svg` and
+/// `/images/dark/{name}.svg` based on `prefers-color-scheme`.
+///
+/// Replaces the dozen-plus hand-rolled `![]()
`
+/// blocks scattered through the components and pages. The light asset is the
+/// fallback that is rendered when no `` matches.
+///
+/// `class` and `style` are forwarded to the `
` element so callers can
+/// keep the exact sizing they had before.
+#[component]
+pub fn ThemedIcon(
+ /// Asset basename (without extension or directory). The component looks up
+ /// `/images/light/{name}.svg` and `/images/dark/{name}.svg`.
+ #[prop(into)]
+ name: String,
+ /// `alt` text for the `
`.
+ #[prop(into)]
+ alt: String,
+ /// Optional Tailwind / utility classes for the `
`.
+ #[prop(into, optional)]
+ class: String,
+ /// Optional inline style string for the `
`.
+ #[prop(into, optional)]
+ style: String,
+) -> impl IntoView {
+ let dark_src = format!("/images/dark/{}.svg", name);
+ let light_src = format!("/images/light/{}.svg", name);
+ view! {
+
+
+
+
+ }
+}
diff --git a/src/pages/announcements.rs b/src/pages/announcements.rs
index 7cdc05a..016b5bf 100644
--- a/src/pages/announcements.rs
+++ b/src/pages/announcements.rs
@@ -9,19 +9,35 @@ fn patina_press_release() -> impl IntoView {
view! {
- "October 7, 2025 – Redmond, WA" " – The " "Open Device Partnership (ODP)" " is announcing " "Patina"", a new open-source firmware project is public, and details will be shared at the upcoming "
-
+ "October 7, 2025 – Redmond, WA"
+ " – The "
+ "Open Device Partnership (ODP)"
+ " is announcing "
+ "Patina"
+ ", a new open-source firmware project is public, and details will be shared at the upcoming "
+
"UEFI 2025 Developer Conference & Plugfest"
", October 7–10 in Sunnyvale, California. Patina is a Rust-based, UEFI-compatible firmware designed for memory safety and to address long standing challenges in the PC firmware ecosystem. It reimagines system firmware development to meet the evolving needs of modern hardware, software development lifecycles, supply chains, and industry collaboration. Patina joins a growing portfolio of ODP projects aimed at building a secure, modern foundation for device enablement. To learn more about Patina, please visit the project page and documentation here: "
-
+
"Patina Documentation"
"."
- "ODP is an industry-wide, open-source initiative focused on advancing " "security, fundamentals, and standardization" " in device software. The partnership's work addresses long-standing challenges in firmware and system design by leveraging " "memory-safe programming languages like Rust" " and " "hardware-rooted security features" " and doing so based on standards that will work across a partner's entire device product line. This approach reduces exposure to common vulnerabilities while providing manufacturers with a sustainable, consistent foundation that lowers engineering costs across product lines."
+ "ODP is an industry-wide, open-source initiative focused on advancing "
+ "security, fundamentals, and standardization"
+ " in device software. The partnership's work addresses long-standing challenges in firmware and system design by leveraging "
+ "memory-safe programming languages like Rust" " and "
+ "hardware-rooted security features"
+ " and doing so based on standards that will work across a partner's entire device product line. This approach reduces exposure to common vulnerabilities while providing manufacturers with a sustainable, consistent foundation that lowers engineering costs across product lines."
@@ -29,13 +45,16 @@ fn patina_press_release() -> impl IntoView {
-
- "Secure EC firmware"", providing a modern, security-focused embedded controller implementation designed to eliminate classes of bugs prevalent in legacy EC codebases."
+ "Secure EC firmware"
+ ", providing a modern, security-focused embedded controller implementation designed to eliminate classes of bugs prevalent in legacy EC codebases."
-
- "Unified OS-EC service interface"", ensuring that operating systems can interact with embedded controllers in a consistent, well-defined way across devices."
+ "Unified OS-EC service interface"
+ ", ensuring that operating systems can interact with embedded controllers in a consistent, well-defined way across devices."
-
- "MPTF"", extending recent advancements in the Windows power-thermal framework to meet partner needs."
+ "MPTF"
+ ", extending recent advancements in the Windows power-thermal framework to meet partner needs."
@@ -52,7 +71,10 @@ fn patina_press_release() -> impl IntoView {
"👉 Learn more and get involved at "
-
+
"opendevicepartnership.org"
"."
@@ -103,46 +125,56 @@ pub fn AnnouncementsPage() -> impl IntoView {
view! {
- Announcements
+ Announcements
- {announcements.iter().enumerate().map(|(i, (link, _, slug))| {
- let navigate = navigate.clone();
- let slug = *slug;
- view! {
- -
-
-
- }
- }).collect::>()}
+ {announcements
+ .iter()
+ .enumerate()
+ .map(|(i, (link, _, slug))| {
+ let navigate = navigate.clone();
+ let slug = *slug;
+ view! {
+ -
+
+
+ }
+ })
+ .collect::>()}
{move || {
- let (title, content): (String, AnyView) = if let Some((_, title, slug)) = announcements.get(selected.get()) {
+ let (title, content): (String, AnyView) = if let Some((_, title, slug)) = announcements
+ .get(selected.get())
+ {
let content = match *slug {
"welcome-patina-announcement" => patina_press_release().into_any(),
_ => view! { "Content not found"
}.into_any(),
};
(title.to_string(), content)
} else {
- ("No announcement selected".to_string(), view! { {""}
}.into_any())
+ (
+ "No announcement selected".to_string(),
+ view! { {""}
}.into_any(),
+ )
};
view! {
- {title}
-
- {content}
-
+ {title}
+ {content}
}
}}
diff --git a/src/pages/boot_firmware.rs b/src/pages/boot_firmware.rs
index fab308d..d7c9a04 100644
--- a/src/pages/boot_firmware.rs
+++ b/src/pages/boot_firmware.rs
@@ -1,6 +1,5 @@
-use crate::components::documentation_training::{DocLink, DocumentationTraining};
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::documentation_training::DocumentationTraining;
+use crate::components::page_layout::PageLayout;
use crate::components::project_introduction::ProjectIntroduction;
use crate::components::repo_view::RepositoryGraph;
@@ -9,34 +8,6 @@ use leptos::prelude::*;
/// Default Home Page
#[component]
pub fn BootFirmware() -> impl IntoView {
- let links = vec![
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/why/why.html",
- title: "Why ODP?",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/getting_started.html",
- title: "Getting Started with ODP",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/welcome.html",
- title: "Tutorials",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/specs/specifications.html",
- title: "Specifications",
- external: true,
- },
- DocLink {
- href: "/community",
- title: "Contributing to ODP",
- external: false,
- },
- ];
-
let project_title = "Patina";
let project_summary = "Modern Boot Firmware";
@@ -46,38 +17,18 @@ pub fn BootFirmware() -> impl IntoView {
let links_data = r#"[{"source": 0, "target": 5}, {"source": 0, "target": 7}, {"source": 3, "target": 4}, {"source": 3, "target": 5}, {"source": 3, "target": 6}, {"source": 3, "target": 7}, {"source": 4, "target": 5}, {"source": 4, "target": 6}, {"source": 4, "target": 7}, {"source": 4, "target": 8}, {"source": 4, "target": 9}, {"source": 5, "target": 6}, {"source": 5, "target": 7}, {"source": 5, "target": 9}, {"source": 6, "target": 7}]"#;
view! {
- "Uh oh! Something went wrong!"
-
- "Errors: "
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
- }
- }>
-
-
-
-
-
-
-
-
-
+
+
+
+
+
}
}
diff --git a/src/pages/community.rs b/src/pages/community.rs
index 6e49089..50d81c2 100644
--- a/src/pages/community.rs
+++ b/src/pages/community.rs
@@ -1,6 +1,5 @@
use crate::components::community_teams::CommunityTeams;
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::page_layout::PageLayout;
use leptos::prelude::*;
@@ -8,31 +7,8 @@ use leptos::prelude::*;
#[component]
pub fn Community() -> impl IntoView {
view! {
- "Uh oh! Something went wrong!"
-
- "Errors: "
- // Render a list of errors as strings - good for development purposes
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
-
- }
- }>
-
-
-
-
-
-
-
-
+
+
+
}
}
diff --git a/src/pages/embedded_controller.rs b/src/pages/embedded_controller.rs
index 85cc455..90531dc 100644
--- a/src/pages/embedded_controller.rs
+++ b/src/pages/embedded_controller.rs
@@ -1,6 +1,5 @@
-use crate::components::documentation_training::{DocLink, DocumentationTraining};
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::documentation_training::DocumentationTraining;
+use crate::components::page_layout::PageLayout;
use crate::components::project_introduction::ProjectIntroduction;
use crate::components::repo_view::RepositoryGraph;
@@ -9,34 +8,6 @@ use leptos::prelude::*;
/// Default Home Page
#[component]
pub fn EmbeddedController() -> impl IntoView {
- let links = vec![
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/why/why.html",
- title: "Why ODP?",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/getting_started.html",
- title: "Getting Started with ODP",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/welcome.html",
- title: "Tutorials",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/specs/specifications.html",
- title: "Specifications",
- external: true,
- },
- DocLink {
- href: "/community",
- title: "Contributing to ODP",
- external: false,
- },
- ];
-
let project_title = "Secure Embedded Controller";
let project_summary = "A hardened firmware platform for modern embedded controllers";
let project_what = r#"The ODP Secure EC stack is a Rust-based firmware platform for modern embedded controllers, supporting both discrete and integrated ECs.
@@ -53,35 +24,18 @@ It’s a modern foundation for building reliable, adaptable EC firmware — not
let links_data = r#"[{"source": 0, "target": 2}, {"source": 0, "target": 4}, {"source": 0, "target": 5}, {"source": 0, "target": 6}, {"source": 0, "target": 11}, {"source": 0, "target": 12}, {"source": 0, "target": 13}, {"source": 0, "target": 19}, {"source": 0, "target": 20}, {"source": 0, "target": 23}, {"source": 1, "target": 4}, {"source": 2, "target": 43}, {"source": 3, "target": 17}, {"source": 3, "target": 18}, {"source": 4, "target": 3}, {"source": 4, "target": 26}, {"source": 4, "target": 36}, {"source": 5, "target": 3}, {"source": 5, "target": 26}, {"source": 5, "target": 36}, {"source": 6, "target": 4}, {"source": 7, "target": 4}, {"source": 8, "target": 4}, {"source": 9, "target": 4}, {"source": 11, "target": 8}, {"source": 11, "target": 39}, {"source": 12, "target": 4}, {"source": 12, "target": 19}, {"source": 13, "target": 14}, {"source": 13, "target": 15}, {"source": 13, "target": 21}, {"source": 13, "target": 28}, {"source": 13, "target": 29}, {"source": 13, "target": 40}, {"source": 13, "target": 42}, {"source": 14, "target": 4}, {"source": 15, "target": 4}, {"source": 16, "target": 22}, {"source": 20, "target": 4}, {"source": 21, "target": 4}, {"source": 23, "target": 9}, {"source": 25, "target": 0}, {"source": 26, "target": 10}, {"source": 28, "target": 4}, {"source": 29, "target": 4}, {"source": 30, "target": 5}, {"source": 31, "target": 5}, {"source": 33, "target": 4}, {"source": 36, "target": 32}, {"source": 36, "target": 37}, {"source": 39, "target": 4}, {"source": 40, "target": 4}, {"source": 41, "target": 4}, {"source": 42, "target": 4}, {"source": 43, "target": 30}, {"source": 43, "target": 31}]"#;
view! {
- "Uh oh! Something went wrong!"
-
- "Errors: "
- // Render a list of errors as strings - good for development purposes
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
-
- }
- }>
-
-
-
-
-
-
-
-
-
+
+
+
+
+
}
}
diff --git a/src/pages/getting_started.rs b/src/pages/getting_started.rs
index 3cef9eb..7033885 100644
--- a/src/pages/getting_started.rs
+++ b/src/pages/getting_started.rs
@@ -1,6 +1,5 @@
-use crate::components::footer::Footer;
-use crate::components::header::Header;
use crate::components::landing_page::LandingPage;
+use crate::components::page_layout::PageLayout;
use leptos::prelude::*;
@@ -8,30 +7,8 @@ use leptos::prelude::*;
#[component]
pub fn GettingStarted() -> impl IntoView {
view! {
- "Uh oh! Something went wrong!"
-
- "Errors: "
- // Render a list of errors as strings - good for development purposes
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
-
- }
- }>
-
-
-
-
-
-
-
+
+
+
}
}
diff --git a/src/pages/home.rs b/src/pages/home.rs
index 84c3514..0efc46c 100644
--- a/src/pages/home.rs
+++ b/src/pages/home.rs
@@ -1,7 +1,6 @@
-use crate::components::documentation_training::{DocLink, DocumentationTraining};
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::documentation_training::DocumentationTraining;
use crate::components::main::Main;
+use crate::components::page_layout::PageLayout;
use crate::components::partners_grid::PartnersGrid;
use leptos::prelude::*;
@@ -9,58 +8,11 @@ use leptos::prelude::*;
/// Default Home Page
#[component]
pub fn Home() -> impl IntoView {
- // Documentation links for the DocumentationTraining section
- let links = vec![
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/why/why.html",
- title: "Why ODP?",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/getting_started.html",
- title: "Getting Started with ODP",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/welcome.html",
- title: "Tutorials",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/specs/specifications.html",
- title: "Specifications",
- external: true,
- },
- DocLink {
- href: "/community",
- title: "Contributing to ODP",
- external: false,
- },
- ];
-
view! {
- "Uh oh! Something went wrong!"
- "Errors: "
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
- }
- }>
-
-
-
-
-
-
-
-
+
+
+
+
+
}
}
diff --git a/src/pages/projects.rs b/src/pages/projects.rs
index 4ec5f01..645e24a 100644
--- a/src/pages/projects.rs
+++ b/src/pages/projects.rs
@@ -1,6 +1,5 @@
-use crate::components::documentation_training::{DocLink, DocumentationTraining};
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::documentation_training::DocumentationTraining;
+use crate::components::page_layout::PageLayout;
use crate::components::projects_component::ProjectsComponent;
use leptos::prelude::*;
@@ -8,60 +7,10 @@ use leptos::prelude::*;
/// Default Home Page
#[component]
pub fn Projects() -> impl IntoView {
- let links = vec![
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/why/why.html",
- title: "Why ODP?",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/getting_started.html",
- title: "Getting Started with ODP",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/welcome.html",
- title: "Tutorials",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/specs/specifications.html",
- title: "Specifications",
- external: true,
- },
- DocLink {
- href: "/community",
- title: "Contributing to ODP",
- external: false,
- },
- ];
-
view! {
- "Uh oh! Something went wrong!"
-
- "Errors: "
- // Render a list of errors as strings - good for development purposes
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
-
- }
- }>
-
-
-
-
-
-
-
-
+
+
+
+
}
}
diff --git a/src/pages/team_ec.rs b/src/pages/team_ec.rs
index 609ba36..ef8c318 100644
--- a/src/pages/team_ec.rs
+++ b/src/pages/team_ec.rs
@@ -1,6 +1,6 @@
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::page_layout::PageLayout;
use crate::components::team_grid::{TeamGrid, TeamMember};
+use crate::components::themed_icon::ThemedIcon;
use leptos::prelude::*;
@@ -78,102 +78,40 @@ pub fn TeamEC() -> impl IntoView {
let team = create_team();
view! {
- "Uh oh! Something went wrong!"
+
+
- "Errors: "
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
- }
- }>
-
-
-
-
- {/* Back Button: above content on mobile, absolutely positioned on desktop */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {"Meet the team"}
-
- {/* Left Column */}
-
-
- {"Meet the team"}
-
-
- {/* Right Column */}
-
- {/* Team Introduction */}
-
- {"Secure EC team"}
-
-
- {"Developing and managing secure EC internals"}
-
-
+
+ {"Secure EC team"}
+
+ {"Developing and managing secure EC internals"}
+
-
-
-
+
+
}
}
diff --git a/src/pages/team_ec_services.rs b/src/pages/team_ec_services.rs
index cb21c84..1178210 100644
--- a/src/pages/team_ec_services.rs
+++ b/src/pages/team_ec_services.rs
@@ -1,6 +1,6 @@
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::page_layout::PageLayout;
use crate::components::team_grid::{TeamGrid, TeamMember};
+use crate::components::themed_icon::ThemedIcon;
use leptos::prelude::*;
@@ -30,102 +30,40 @@ pub fn TeamECServices() -> impl IntoView {
let team = create_team();
view! {
- "Uh oh! Something went wrong!"
+
+
- "Errors: "
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
- }
- }>
-
-
-
-
- {/* Back Button: above content on mobile, absolutely positioned on desktop */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {"Meet the team"}
-
- {/* Left Column */}
-
-
- {"Meet the team"}
-
-
- {/* Right Column */}
-
-
- {"Unified EC services team"}
-
-
- {"Designing and managing implementation of a unified EC Services interface"}
-
-
+
+ {"Unified EC services team"}
+
+ {"Designing and managing implementation of a unified EC Services interface"}
+
-
-
-
-
+
+
}
}
diff --git a/src/pages/team_patina.rs b/src/pages/team_patina.rs
index a1c2d13..7d2b14a 100644
--- a/src/pages/team_patina.rs
+++ b/src/pages/team_patina.rs
@@ -1,6 +1,6 @@
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::page_layout::PageLayout;
use crate::components::team_grid::{TeamGrid, TeamMember};
+use crate::components::themed_icon::ThemedIcon;
use leptos::prelude::*;
@@ -86,105 +86,40 @@ pub fn TeamPatina() -> impl IntoView {
let team = create_team();
view! {
- "Uh oh! Something went wrong!"
+
+
- "Errors: "
- // Render a list of errors as strings - good for development purposes
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
-
- }
- }>
-
-
-
-
- {/* Back Button: above content on mobile, absolutely positioned on desktop */}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+ {"Meet the team"}
-
- {/* Left Column */}
-
-
- {"Meet the team"}
-
-
- {/* Right Column */}
-
- {/* Team Introduction */}
-
- {"Patina team"}
-
-
- {"Developing and managing development of a new modern UEFI"}
-
-
+
+ {"Patina team"}
+
+ {"Developing and managing development of a new modern UEFI"}
+
-
-
-
-
+
+
}
}
diff --git a/src/pages/unified_ec_services.rs b/src/pages/unified_ec_services.rs
index 15e0801..57f3960 100644
--- a/src/pages/unified_ec_services.rs
+++ b/src/pages/unified_ec_services.rs
@@ -1,6 +1,5 @@
-use crate::components::documentation_training::{DocLink, DocumentationTraining};
-use crate::components::footer::Footer;
-use crate::components::header::Header;
+use crate::components::documentation_training::DocumentationTraining;
+use crate::components::page_layout::PageLayout;
use crate::components::project_introduction::ProjectIntroduction;
use crate::components::repo_view::RepositoryGraph;
@@ -9,34 +8,6 @@ use leptos::prelude::*;
/// Default Home Page
#[component]
pub fn WindowsEcServices() -> impl IntoView {
- let links = vec![
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/why/why.html",
- title: "Why ODP?",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/getting_started.html",
- title: "Getting Started with ODP",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/intro/welcome.html",
- title: "Tutorials",
- external: true,
- },
- DocLink {
- href: "https://opendevicepartnership.github.io/documentation/guide/specs/specifications.html",
- title: "Specifications",
- external: true,
- },
- DocLink {
- href: "/community",
- title: "Contributing to ODP",
- external: false,
- },
- ];
-
let project_title = "Unified Embedded Controller Interface";
let project_summary = "";
let project_what = r#"The Unified Windows EC Service interface defines runtime coordination between firmware components using async message-passing.
@@ -52,35 +23,18 @@ pub fn WindowsEcServices() -> impl IntoView {
let links_data = r#"[{"source": 0, "target": 1}, {"source": 1, "target": 2}]"#;
view! {
- "Uh oh! Something went wrong!"
-
- "Errors: "
- // Render a list of errors as strings - good for development purposes
-
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! { - {e.to_string()}
})
- .collect_view()
- }}
-
-
- }
- }>
-
-
-
-
-
-
-
-
-
+
+
+
+
+
}
}
diff --git a/style/tailwind.css b/style/tailwind.css
index 31b1fe5..cc4df96 100644
--- a/style/tailwind.css
+++ b/style/tailwind.css
@@ -20,45 +20,67 @@
}
@layer utilities {
+ /*
+ * Typography & surface utility classes.
+ *
+ * Naming convention
+ * .hN - desktop / large-screen size of heading level N
+ * .hN_mobile - small-screen size of the same heading; the call site
+ * pairs them as `class="h2_mobile md:h2"` so the mobile
+ * variant is the default and the desktop variant kicks
+ * in at the `md` (>= 768 px) breakpoint.
+ * .pN - paragraph / body sizes (.p is the base, .p1 / .p2
+ * are larger emphasised body sizes, .p_mono is the
+ * display monospaced lockup, .mono is the small caps
+ * monospaced label).
+ * .link* - underlined inline links.
+ * .background_*- surface tokens (primary/secondary/tertiary/quaternary).
+ *
+ * Known issues to address in a follow-up (visual changes required):
+ * - Several classes have no mobile twin (.p_mono, .mono, .link_large,
+ * .icon, .odp-btn-text, .odp-header-btn-text).
+ */
+
+ /* Surfaces ---------------------------------------------------------- */
+
.header_background {
- @apply bg-[#FFFFFF] dark:bg-[#171717];
+ @apply bg-surface-primary dark:bg-surface-primary-dark;
}
.background_primary {
- @apply bg-[#FFFFFF] dark:bg-[#171717];
+ @apply bg-surface-primary dark:bg-surface-primary-dark;
}
.background_secondary {
- @apply bg-[#F1F1F1] dark:bg-[#3B3B3B];
+ @apply bg-surface-secondary dark:bg-surface-secondary-dark;
}
.background_tertiary {
- @apply bg-[#E2E2E2] dark:bg-[#595959];
+ @apply bg-surface-tertiary dark:bg-surface-tertiary-dark;
}
.background_quaternary {
- @apply bg-[#CACACA] dark:bg-[#797979];
+ @apply bg-surface-quaternary dark:bg-surface-quaternary-dark;
}
.background_announcement {
- @apply bg-[#FEEED6] dark:bg-[#FEEED6];
- }
-
- .h1 {
- @apply text-black dark:text-white;
- font-family: Geist, sans-serif;
- font-size: 100px;
- font-style: normal;
- font-weight: 400;
- line-height: 95%;
- letter-spacing: -2.8px;
- margin-bottom: 12px;
+ @apply bg-surface-announcement dark:bg-surface-announcement-dark;
}
- .h1_mobile {
+ /* Headings ---------------------------------------------------------- */
+
+ /* Display headline used as the page-level h1.
+ *
+ * Fluidly scales between 36 px (at <=320 px viewport) and 80 px (at
+ * >=1280 px viewport). The middle term is a linear interpolation:
+ * size = 1.33rem + 4.58vw, anchored so both endpoints land exactly on
+ * the desired bounds. This obsoletes .h1_mobile -- a single class now
+ * works at every viewport.
+ */
+ .h1 {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
- font-size: 60px;
+ font-size: clamp(2.25rem, 1.33rem + 4.58vw, 5rem);
font-style: normal;
font-weight: 400;
line-height: 100%;
@@ -66,50 +88,33 @@
margin-bottom: 12px;
}
+ /* Section heading. Fluidly scales 28 px (mobile) -> 30 px (desktop). */
.h2 {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
- font-size: 30px;
- font-style: normal;
- font-weight: 500;
- line-height: 110%; /* 66px */
- letter-spacing: -1.2px;
- margin-bottom: 12px;
- }
-
- .h2_mobile {
- @apply text-black dark:text-white;
- font-family: Geist, sans-serif;
- font-size: 50px;
+ font-size: clamp(1.75rem, 1.71rem + 0.21vw, 1.875rem);
font-style: normal;
font-weight: 500;
- line-height: 110%; /* 66px */
+ line-height: 110%;
letter-spacing: -1.2px;
margin-bottom: 12px;
}
+ /* Sub-section heading (e.g. card titles). Fluidly scales 20 px -> 25 px. */
.h3 {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
- font-size: 25px;
+ font-size: clamp(1.25rem, 1.15rem + 0.52vw, 1.5625rem);
font-style: normal;
font-weight: 600;
- line-height: 120%; /* 42px */
+ line-height: 120%;
letter-spacing: -0.7px;
margin-bottom: 12px;
}
- .h3_mobile {
- @apply text-black dark:text-white;
- font-family: Geist, sans-serif;
- font-size: 25px;
- font-style: normal;
- font-weight: 600;
- line-height: 120%; /* 42px */
- letter-spacing: -0.7px;
- margin-bottom: 12px;
- }
+ /* Body / paragraph text. ----------------------------------------- */
+ /* Default body text. */
.p {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
@@ -119,52 +124,34 @@
line-height: 130%; /* 26px */
}
+ /* Mobile twin of .p (16 < 20, OK). Retained because the footer
+ * intentionally renders smaller copy on mobile via `p_mobile md:p`. */
.p_mobile {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
- font-size: 10px;
+ font-size: 16px;
font-style: normal;
font-weight: 400;
- line-height: 110%; /* 26px */
+ line-height: 130%;
}
+ /* Lead / intro paragraph. Fluidly scales 22 px -> 30 px. */
.p1 {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
- font-size: 30px;
- font-style: normal;
- font-weight: 500;
- line-height: 140%; /* 49px */
- letter-spacing: -0.7px;
- margin-bottom: 12px;
- }
-
- .p1_mobile {
- @apply text-black dark:text-white;
- font-family: Geist, sans-serif;
- font-size: 30px;
+ font-size: clamp(1.375rem, 1.21rem + 0.83vw, 1.875rem);
font-style: normal;
font-weight: 500;
- line-height: 130%; /* 49px */
+ line-height: 140%;
letter-spacing: -0.7px;
margin-bottom: 12px;
}
+ /* Secondary paragraph (smaller than .p1). Fluidly scales 18 px -> 25 px. */
.p2 {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
- font-size: 25px;
- font-style: normal;
- font-weight: 500;
- line-height: 130%;
- letter-spacing: -0.25px;
- margin-bottom: 12px;
- }
-
- .p2_mobile {
- @apply text-black dark:text-white;
- font-family: Geist, sans-serif;
- font-size: 18px;
+ font-size: clamp(1.125rem, 0.98rem + 0.73vw, 1.5625rem);
font-style: normal;
font-weight: 500;
line-height: 130%;
@@ -172,6 +159,7 @@
margin-bottom: 12px;
}
+ /* Display monospaced lockup; no mobile twin defined. */
.p_mono {
@apply text-black dark:text-white;
font-family: "Geist Mono", monospace;
@@ -183,6 +171,7 @@
text-transform: uppercase;
}
+ /* Small uppercase monospace label (WHAT / WHY / WHO). No mobile twin. */
.mono {
@apply text-black dark:text-white;
font-family: "Geist Mono", monospace;
@@ -195,6 +184,9 @@
margin-bottom: 12px;
}
+ /* Inline links. -------------------------------------------------- */
+
+ /* Underlined link, default desktop size. */
.link {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
@@ -211,6 +203,8 @@
text-underline-position: from-font;
}
+ /* Mobile twin of .link (20 < 25, OK). Also used as a fallback for the
+ * undefined .link_large_mobile in src/components/documentation_training.rs. */
.link_mobile {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
@@ -227,6 +221,8 @@
text-underline-position: from-font;
}
+ /* Larger underlined link (used in the Documentation list). No mobile
+ * twin; pages pair it with .link_mobile on small screens. */
.link_large {
@apply text-black dark:text-white;
font-family: Geist, sans-serif;
@@ -242,6 +238,9 @@
text-underline-position: from-font;
}
+ /* Misc lockups & buttons. ---------------------------------------- */
+
+ /* Square icon container (150x150). Same size on every breakpoint. */
.icon {
display: flex;
width: 150px;
@@ -306,7 +305,7 @@
/* Header buttons on quaternary background (announcements page) */
.background_quaternary .odp-header-btn {
- @apply bg-[#CACACA] dark:bg-[#797979] border-black dark:border-white;
+ @apply bg-surface-quaternary dark:bg-surface-quaternary-dark border-black dark:border-white;
}
.background_quaternary .odp-header-btn-active {
diff --git a/tailwind.config.js b/tailwind.config.js
index a72e415..973633e 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -12,6 +12,26 @@ module.exports = {
fontFamily: {
Geist: ['Geist', 'sans-serif', 'mono'],
},
+ // Brand surface colors. Each surface has a light + dark token so the
+ // .background_* / .header_background utilities can express the dark-mode
+ // pair as `bg-surface-N dark:bg-surface-N-dark`. Keeping the literal
+ // pairs in style/tailwind.css would force every future palette tweak
+ // to chase nine hex codes through CSS; centralizing here makes the
+ // palette one edit and exposes the tokens to devtools.
+ colors: {
+ surface: {
+ primary: '#FFFFFF',
+ 'primary-dark': '#171717',
+ secondary: '#F1F1F1',
+ 'secondary-dark': '#3B3B3B',
+ tertiary: '#E2E2E2',
+ 'tertiary-dark': '#595959',
+ quaternary: '#CACACA',
+ 'quaternary-dark': '#797979',
+ announcement: '#FEEED6',
+ 'announcement-dark': '#FEEED6',
+ },
+ },
},
},
plugins: [],
"Building the Future of Trusted System Software Together"
-+
"Leading technology partners creating secure, reusable, and reliable firmware for modern client devices."
"Errors: "
+-
+ {move || {
+ errors
+ .get()
+ .into_iter()
+ .map(|(_, e)| view! {
- {e.to_string()} }) + .collect_view() + }} +
- "October 7, 2025 – Redmond, WA" " – The " "Open Device Partnership (ODP)" " is announcing " "Patina"", a new open-source firmware project is public, and details will be shared at the upcoming " - + "October 7, 2025 – Redmond, WA" + " – The " + "Open Device Partnership (ODP)" + " is announcing " + "Patina" + ", a new open-source firmware project is public, and details will be shared at the upcoming " + "UEFI 2025 Developer Conference & Plugfest" ", October 7–10 in Sunnyvale, California. Patina is a Rust-based, UEFI-compatible firmware designed for memory safety and to address long standing challenges in the PC firmware ecosystem. It reimagines system firmware development to meet the evolving needs of modern hardware, software development lifecycles, supply chains, and industry collaboration. Patina joins a growing portfolio of ODP projects aimed at building a secure, modern foundation for device enablement. To learn more about Patina, please visit the project page and documentation here: " - + "Patina Documentation" "."
- "ODP is an industry-wide, open-source initiative focused on advancing " "security, fundamentals, and standardization" " in device software. The partnership's work addresses long-standing challenges in firmware and system design by leveraging " "memory-safe programming languages like Rust" " and " "hardware-rooted security features" " and doing so based on standards that will work across a partner's entire device product line. This approach reduces exposure to common vulnerabilities while providing manufacturers with a sustainable, consistent foundation that lowers engineering costs across product lines." + "ODP is an industry-wide, open-source initiative focused on advancing " + "security, fundamentals, and standardization" + " in device software. The partnership's work addresses long-standing challenges in firmware and system design by leveraging " + "memory-safe programming languages like Rust" " and " + "hardware-rooted security features" + " and doing so based on standards that will work across a partner's entire device product line. This approach reduces exposure to common vulnerabilities while providing manufacturers with a sustainable, consistent foundation that lowers engineering costs across product lines."
@@ -29,13 +45,16 @@ fn patina_press_release() -> impl IntoView {
- - "Secure EC firmware"", providing a modern, security-focused embedded controller implementation designed to eliminate classes of bugs prevalent in legacy EC codebases." + "Secure EC firmware" + ", providing a modern, security-focused embedded controller implementation designed to eliminate classes of bugs prevalent in legacy EC codebases."
- - "Unified OS-EC service interface"", ensuring that operating systems can interact with embedded controllers in a consistent, well-defined way across devices." + "Unified OS-EC service interface" + ", ensuring that operating systems can interact with embedded controllers in a consistent, well-defined way across devices."
- - "MPTF"", extending recent advancements in the Windows power-thermal framework to meet partner needs." + "MPTF" + ", extending recent advancements in the Windows power-thermal framework to meet partner needs."
@@ -52,7 +71,10 @@ fn patina_press_release() -> impl IntoView {
"👉 Learn more and get involved at " - + "opendevicepartnership.org" "."
@@ -103,46 +125,56 @@ pub fn AnnouncementsPage() -> impl IntoView { view! {-
- {announcements.iter().enumerate().map(|(i, (link, _, slug))| {
- let navigate = navigate.clone();
- let slug = *slug;
- view! {
-
- - - - } - }).collect::
- + + + } + }) + .collect::
"Content not found"
}.into_any(), }; (title.to_string(), content) } else { - ("No announcement selected".to_string(), view! {{""}
}.into_any()) + ( + "No announcement selected".to_string(), + view! {{""}
}.into_any(), + ) }; view! {"Errors: "
--
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} -
"Errors: "
- // Render a list of errors as strings - good for development purposes --
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} - -
"Errors: "
- // Render a list of errors as strings - good for development purposes --
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} - -
"Errors: "
- // Render a list of errors as strings - good for development purposes --
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} - -
"Errors: "
--
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} -
"Errors: "
- // Render a list of errors as strings - good for development purposes --
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} - -
"Errors: "
--
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} -
"Errors: "
--
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} -
"Errors: "
- // Render a list of errors as strings - good for development purposes --
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} - -
"Errors: "
- // Render a list of errors as strings - good for development purposes --
- {move || {
- errors
- .get()
- .into_iter()
- .map(|(_, e)| view! {
- {e.to_string()} }) - .collect_view() - }} - -