maud_ui/primitives/
separator.rs1use maud::{html, Markup};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum Orientation {
8 Horizontal,
9 Vertical,
10}
11
12impl Orientation {
13 fn class(&self) -> &'static str {
14 match self {
15 Self::Horizontal => "mui-separator--horizontal",
16 Self::Vertical => "mui-separator--vertical",
17 }
18 }
19
20 fn aria_orientation(&self) -> &'static str {
21 match self {
22 Self::Horizontal => "horizontal",
23 Self::Vertical => "vertical",
24 }
25 }
26}
27
28#[derive(Debug, Clone, Copy)]
30pub struct Props {
31 pub orientation: Orientation,
33 pub decorative: bool,
35}
36
37impl Default for Props {
38 fn default() -> Self {
39 Self {
40 orientation: Orientation::Horizontal,
41 decorative: false,
42 }
43 }
44}
45
46pub fn render(props: Props) -> Markup {
48 let class = format!("mui-separator {}", props.orientation.class());
49 html! {
50 @if props.decorative {
51 div class=(class) aria-hidden="true" {}
52 } @else {
53 div class=(class)
54 role="separator"
55 aria-orientation=(props.orientation.aria_orientation()) {}
56 }
57 }
58}
59
60pub fn showcase() -> Markup {
62 html! {
63 div.mui-showcase__grid {
64 section {
66 h2 { "Profile card sections" }
67 p.mui-showcase__caption { "Separator divides the Bio block from account Settings in a user profile." }
68 div style="border: 1px solid var(--mui-border); border-radius: 0.5rem; padding: 1.25rem; max-width: 24rem; background: var(--mui-card-bg, var(--mui-bg, transparent));" {
69 div {
70 div style="font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--mui-text-muted); margin-bottom: 0.25rem;" { "Bio" }
71 div style="font-weight: 600; font-size: 1rem;" { "Henry Geldenhuys" }
72 div style="font-size: 0.8125rem; color: var(--mui-text-muted); margin-top: 0.25rem;" {
73 "Staff engineer at Kapable. Building Claude Conductor. Cape Town \u{2192} Remote."
74 }
75 }
76 div style="margin: 1rem 0;" {
77 (render(Props { orientation: Orientation::Horizontal, decorative: true }))
78 }
79 div {
80 div style="font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--mui-text-muted); margin-bottom: 0.25rem;" { "Settings" }
81 div style="display: flex; justify-content: space-between; font-size: 0.875rem; padding: 0.25rem 0;" {
82 span { "Email" }
83 span style="color: var(--mui-text-muted);" { "invoice@geldentech.ca" }
84 }
85 div style="display: flex; justify-content: space-between; font-size: 0.875rem; padding: 0.25rem 0;" {
86 span { "Two-factor" }
87 span style="color: var(--mui-text-muted);" { "Enabled" }
88 }
89 }
90 }
91 }
92
93 section {
95 h2 { "Auth methods" }
96 p.mui-showcase__caption { "\u{201c}OR\u{201d} label separates social sign-in from email + password." }
97 div style="display: flex; flex-direction: column; gap: 0.75rem; max-width: 22rem;" {
98 button class="mui-btn mui-btn--outline mui-btn--md" style="width: 100%;" {
99 span aria-hidden="true" style="margin-right: 0.5rem;" { "G" }
100 "Sign in with Google"
101 }
102 div style="display: flex; align-items: center; gap: 0.75rem; margin: 0.25rem 0;" {
103 div style="flex: 1;" {
104 (render(Props { orientation: Orientation::Horizontal, decorative: true }))
105 }
106 span style="font-size: 0.75rem; font-weight: 500; text-transform: uppercase; color: var(--mui-text-muted); letter-spacing: 0.08em;" { "OR" }
107 div style="flex: 1;" {
108 (render(Props { orientation: Orientation::Horizontal, decorative: true }))
109 }
110 }
111 div class="mui-field" {
112 input type="email" placeholder="you@company.com" class="mui-input" style="width: 100%;";
113 }
114 div class="mui-field" {
115 input type="password" placeholder="Password" class="mui-input" style="width: 100%;";
116 }
117 button class="mui-btn mui-btn--primary mui-btn--md" type="submit" { "Sign in" }
118 }
119 }
120
121 section {
123 h2 { "Navigation" }
124 p.mui-showcase__caption { "Vertical separator between primary nav and user menu." }
125 nav style="display: flex; align-items: center; gap: 1rem; padding: 0.5rem 0.75rem; border: 1px solid var(--mui-border); border-radius: 0.5rem; height: 2.75rem;" {
126 a href="#" style="font-weight: 500; text-decoration: none; color: inherit;" { "Dashboard" }
127 a href="#" style="color: var(--mui-text-muted); text-decoration: none;" { "Projects" }
128 a href="#" style="color: var(--mui-text-muted); text-decoration: none;" { "Billing" }
129 a href="#" style="color: var(--mui-text-muted); text-decoration: none;" { "Settings" }
130 div style="flex: 1;" {}
131 (render(Props {
132 orientation: Orientation::Vertical,
133 ..Default::default()
134 }))
135 a href="#" style="color: var(--mui-text-muted); text-decoration: none; font-size: 0.875rem;" { "Docs" }
136 a href="#" style="font-weight: 500; text-decoration: none; color: inherit;" { "HG" }
137 }
138 }
139 }
140 }
141}