From 9f66cbb0602d7547644570c9e3282aa7cf43dc43 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 4 Jun 2025 12:25:31 -0500 Subject: [PATCH 01/28] style accordion --- preview/assets/main.css | 4 +- preview/src/components/accordion/mod.rs | 20 ++++-- preview/src/components/accordion/style.css | 79 ++++++++++++++++------ primitives/src/accordion.rs | 13 +++- 4 files changed, 90 insertions(+), 26 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index d71f258..d0147b9 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -38,10 +38,10 @@ --hover-background-color: #292929; --focused-background-color: #2c2b2b; --contrast-background-color: #e6e6e6; - --text-color: #fff; + --text-color: #D4D4D4; --dim-text-color: rgb(220, 220, 220); --border-color: #fff; - --dim-border-color: rgb(43, 43, 43); + --dim-border-color: #232323; --muted-text-color: #b0b0b0; --focused-border-color: #2b7fff; --success-background-color: #02271c; diff --git a/preview/src/components/accordion/mod.rs b/preview/src/components/accordion/mod.rs index 4a71f31..9cda9d6 100644 --- a/preview/src/components/accordion/mod.rs +++ b/preview/src/components/accordion/mod.rs @@ -11,6 +11,7 @@ pub(super) fn Demo() -> Element { } Accordion { class: "accordion", + width: "15rem", allow_multiple_open: false, horizontal: false, for i in 0..4 { @@ -23,10 +24,21 @@ pub(super) fn Demo() -> Element { on_trigger_click: move || { tracing::info!("trigger"); }, - AccordionTrigger { class: "accordion-trigger", "the quick brown fox" } - AccordionContent { class: "accordion-content", - div { class: "accordion-content-inner", - p { "lorem ipsum lorem ipsum" } + AccordionTrigger { class: "accordion-trigger", + "the quick brown fox" + svg { + class: "accordion-expand-icon", + view_box: "0 0 24 24", + xmlns: "http://www.w3.org/2000/svg", + polyline { points: "6 9 12 15 18 9" } + } + } + AccordionContent { class: "accordion-content", style: "--collapsible-content-width: 140px", + div { padding_bottom: "1rem", + p { + padding: "0", + "lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum lorem ipsum" + } } } } diff --git a/preview/src/components/accordion/style.css b/preview/src/components/accordion/style.css index 3ad21bc..89be4b8 100644 --- a/preview/src/components/accordion/style.css +++ b/preview/src/components/accordion/style.css @@ -1,42 +1,83 @@ -.accordion { - background-color: var(--brighter-background-color); -} - .accordion-trigger { + display: flex; + align-items: center; + justify-content: space-between; + flex-direction: row; border: none; outline: none; - border-bottom: 1px solid var(--dim-border-color); width: 100%; color: var(--text-color); - background-color: var(--brighter-background-color); - padding: 10px; + background-color: transparent; + padding: 0; + padding-top: 1rem; + padding-bottom: 1rem; text-align: left; - font-weight: bold; + box-sizing: border-box; } -.accordion-trigger:focus { - border: 1px solid maroon; +.accordion-trigger:focus-visible { + box-shadow: 0 0 0 3px var(--focused-border-color); } .accordion-trigger:hover { cursor: pointer; + text-decoration-line: underline; } .accordion-content { display: grid; - grid-template-rows: 0fr; - transition: grid-template-rows 0.3s ease-out; } -.accordion-item[data-open="true"] .accordion-content { - grid-template-rows: 1fr; +.accordion-content[data-open="false"] { + animation: slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1); +} +.accordion-content[data-open="true"] { + animation: slideUp 300ms cubic-bezier(0.87, 0, 0.13, 1); +} + +@keyframes slideDown { + from { + height: var(--collapsible-content-width); + } + to { + height: 0px; + } +} + +@keyframes slideUp { + from { + height: 0px; + } + to { + height: var(--collapsible-content-width); + } } -.accordion-content-inner { +.accordion-item { + margin-top: 1px; + border-bottom: 1px solid var(--dim-border-color); overflow: hidden; } -.accordion-content-inner p { - margin: 0; - padding: 10px; -} \ No newline at end of file +.accordion-item:first-child { + margin-top: 0px; +} + +.accordion-item:last-child { + border-bottom: none; +} + +.accordion-expand-icon { + fill: none; + stroke: var(--text-color); + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 2; + width: 20px; + height: 20px; + transition: all 150ms cubic-bezier(0.4, 0, 0.2, 1); +} + +.accordion-item[data-open="true"] .accordion-expand-icon { + rotate: 180deg; +} diff --git a/primitives/src/accordion.rs b/primitives/src/accordion.rs index 96e2cd6..362faf7 100644 --- a/primitives/src/accordion.rs +++ b/primitives/src/accordion.rs @@ -186,6 +186,10 @@ pub struct AccordionProps { /// Settings this to true will use left/right keybinds for navigation instead of up/down. Defaults to false. #[props(default)] horizontal: ReadOnlySignal, + + /// Attributes to extend the root element. + #[props(extends = GlobalAttributes)] + attributes: Vec, } #[component] @@ -210,6 +214,8 @@ pub fn Accordion(props: AccordionProps) -> Element { ctx.set_focus(None); }, + ..props.attributes, + {props.children} } } @@ -297,14 +303,19 @@ pub struct AccordionContentProps { pub fn AccordionContent(props: AccordionContentProps) -> Element { let item: Item = use_context(); let id = use_id_or(item.aria_id, props.id); + let ctx: AccordionContext = use_context(); + let open = ctx.is_open(item.id); rsx! { div { id: id, class: props.class, style: props.style, + "data-open": open, - {props.children} + if open { + {props.children} + } } } } From 849dc4e6c2939743d47614fdcd2eb7c929790f02 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 4 Jun 2025 15:48:56 -0500 Subject: [PATCH 02/28] alert styles --- preview/assets/main.css | 95 ++++++++++++++++--- preview/src/components/accordion/style.css | 8 +- preview/src/components/alert_dialog/mod.rs | 45 ++++----- preview/src/components/alert_dialog/style.css | 72 ++++++++------ primitives/src/alert_dialog.rs | 22 ++--- 5 files changed, 160 insertions(+), 82 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index d0147b9..c2720a8 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -9,22 +9,25 @@ :root { --background-color: #fff; --brighter-background-color: #fbfbfb; - --dim-background-color: oklch(0.967 0.003 264.542); + --dim-background-color: #F3F4F6; + --muted-background-color: #fff; --hover-background-color: #dadada; --focused-background-color: #d7d7d7; --contrast-background-color: #0d0d0d; --text-color: #000; --dim-text-color: rgb(43, 43, 43); --border-color: #000; - --dim-border-color: rgb(43, 43, 43); + --dim-border-color: #E5E5E5; --muted-text-color: #b0b0b0; --focused-border-color: #2b7fff; --success-background-color: #ecfdf5; --success-text-color: #10b981; --warning-background-color: #fffbeb; --warning-text-color: #f59e0b; - --error-background-color: #fef2f2; - --error-text-color: #ef4444; + --error-background-color: #ef4444; + --error-background-color-focused: #dc2626; + --error-border-color: var(--error-background-color); + --error-text-color: var(--dim-text-color); --info-background-color: #e0f2fe; --info-text-color: #0284c7; } @@ -35,21 +38,24 @@ --background-color: #000; --brighter-background-color: #0e0e0e; --dim-background-color: #141313; - --hover-background-color: #292929; + --muted-background-color: #0A0A0A; + --hover-background-color: #1a1a1a; --focused-background-color: #2c2b2b; --contrast-background-color: #e6e6e6; --text-color: #D4D4D4; --dim-text-color: rgb(220, 220, 220); --border-color: #fff; - --dim-border-color: #232323; + --dim-border-color: #383839; --muted-text-color: #b0b0b0; --focused-border-color: #2b7fff; --success-background-color: #02271c; --success-text-color: #b6fae3; --warning-background-color: #342203; --warning-text-color: #feeac7; - --error-background-color: #360e0e; - --error-text-color: #e0baba; + --error-background-color: #a22e2e; + --error-background-color-focused: #9b1c1c; + --error-border-color: var(--error-background-color); + --error-text-color: var(--dim-text-color); --info-background-color: #0c1f2b; --info-text-color: #b3d7e6; } @@ -186,7 +192,6 @@ body { flex-direction: column; align-items: center; justify-content: center; - background-color: var(--dim-background-color); border: 1px solid var(--dim-border-color); border-radius: 8px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); @@ -205,7 +210,6 @@ body { max-height: 100%; border-top-right-radius: 0.5em; border-top-left-radius: 0.5em; - background-color: var(--dim-background-color); padding: 20px; box-sizing: border-box; } @@ -245,7 +249,6 @@ body { padding: 3rem; flex: 1 0 auto; border-radius: 0.5rem; - background-color: var(--dim-background-color); border: 1px solid var(--dim-border-color); box-sizing: border-box; } @@ -258,3 +261,73 @@ body { height: 100%; width: 100%; } + + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.269 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.371 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.439 0 0); +} \ No newline at end of file diff --git a/preview/src/components/accordion/style.css b/preview/src/components/accordion/style.css index 89be4b8..59dd204 100644 --- a/preview/src/components/accordion/style.css +++ b/preview/src/components/accordion/style.css @@ -29,13 +29,13 @@ } .accordion-content[data-open="false"] { - animation: slideDown 300ms cubic-bezier(0.87, 0, 0.13, 1); + animation: accordionSlideDown 300ms cubic-bezier(0.87, 0, 0.13, 1); } .accordion-content[data-open="true"] { - animation: slideUp 300ms cubic-bezier(0.87, 0, 0.13, 1); + animation: accordionSlideUp 300ms cubic-bezier(0.87, 0, 0.13, 1); } -@keyframes slideDown { +@keyframes accordionSlideDown { from { height: var(--collapsible-content-width); } @@ -44,7 +44,7 @@ } } -@keyframes slideUp { +@keyframes accordionSlideUp { from { height: 0px; } diff --git a/preview/src/components/alert_dialog/mod.rs b/preview/src/components/alert_dialog/mod.rs index 24136d4..8993c63 100644 --- a/preview/src/components/alert_dialog/mod.rs +++ b/preview/src/components/alert_dialog/mod.rs @@ -11,33 +11,30 @@ pub(super) fn Demo() -> Element { rel: "stylesheet", href: asset!("/src/components/alert_dialog/style.css"), } - div { - class: "alert-dialog-example", - style: "padding: 20px; max-width: 420px; margin: 0 auto; background: var(--dim-background-color); border-radius: 8px; border: 1px solid var(--dim-border-color); box-shadow: 0 2px 8px rgba(0,0,0,0.08);", - button { - class: "alert-dialog-trigger", - style: "margin-bottom: 1.5rem;", - onclick: move |_| open.set(true), - "Show Alert Dialog (Primitive)" - } - AlertDialogRoot { open: Some(open), on_open_change: move |v| open.set(v), - AlertDialogContent { class: "alert-dialog", - AlertDialogTitle { "Delete item" } - AlertDialogDescription { "Are you sure you want to delete this item? This action cannot be undone." } - AlertDialogActions { - AlertDialogCancel { class: "alert-dialog-cancel", "Cancel" } - AlertDialogAction { - class: "alert-dialog-action", - on_click: move |_| confirmed.set(true), - "Delete" - } + button { + class: "alert-dialog-trigger", + style: "margin-bottom: 1.5rem;", + onclick: move |_| open.set(true), + "Show Alert Dialog (Primitive)" + } + AlertDialogRoot { open: Some(open), on_open_change: move |v| open.set(v), + AlertDialogContent { class: "alert-dialog", + AlertDialogTitle { "Delete item" } + AlertDialogDescription { "Are you sure you want to delete this item? This action cannot be undone." } + AlertDialogActions { + class: "alert-dialog-actions", + AlertDialogCancel { class: "alert-dialog-cancel", "Cancel" } + AlertDialogAction { + class: "alert-dialog-action", + on_click: move |_| confirmed.set(true), + "Delete" } } } - if confirmed() { - p { style: "color: var(--error-text-color); margin-top: 16px; font-weight: 600;", - "Item deleted!" - } + } + if confirmed() { + p { style: "color: var(--error-text-color); margin-top: 16px; font-weight: 600;", + "Item deleted!" } } } diff --git a/preview/src/components/alert_dialog/style.css b/preview/src/components/alert_dialog/style.css index f55f65c..7383761 100644 --- a/preview/src/components/alert_dialog/style.css +++ b/preview/src/components/alert_dialog/style.css @@ -9,14 +9,16 @@ /* Alert Dialog Container - improved for theme consistency */ .alert-dialog { + display: flex; + flex-direction: column; + text-align: center; position: fixed; top: 50%; left: 50%; - width: 400px; - max-width: 90vw; - min-width: 320px; + width: 100%; + max-width: calc(100% - 2rem); margin: 0; - background: var(--dim-background-color); + background: var(--muted-background-color); color: var(--text-color); border: 1px solid var(--dim-border-color); border-radius: 8px; @@ -29,29 +31,42 @@ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; transform: translate(-50%, -50%); animation: none; + box-sizing: border-box; } .alert-dialog-title { font-size: 1.25rem; font-weight: 700; color: var(--text-color); - margin-bottom: 8px; + margin: 0; } .alert-dialog-description { font-size: 1rem; color: var(--muted-text-color); - margin-bottom: 16px; + margin: 0; } .alert-dialog-actions { display: flex; - justify-content: flex-end; + flex-direction: column-reverse; gap: 12px; } +@media (width >= 40rem) { + .alert-dialog-actions { + flex-direction: row; + justify-content: flex-end; + } + + .alert-dialog { + text-align: left; + max-width: 32rem; + } +} + .alert-dialog-cancel { - background-color: var(--background-color); + background-color: var(--dim-background-color); color: var(--text-color); border: 1px solid var(--dim-border-color); border-radius: 4px; @@ -61,53 +76,50 @@ transition: all 0.2s ease; } -.alert-dialog-cancel:hover, -.alert-dialog-cancel:focus { +.alert-dialog-cancel:hover { background-color: var(--hover-background-color); - color: var(--text-color); - outline: none; +} + +.alert-dialog-cancel:focus { box-shadow: 0 0 0 2px var(--focused-border-color); } .alert-dialog-action { background-color: var(--error-background-color); color: var(--error-text-color); - border: 1px solid var(--error-text-color); + border: 1px solid var(--error-border-color); border-radius: 4px; padding: 8px 18px; font-size: 1rem; cursor: pointer; - font-weight: 600; transition: all 0.2s ease; } -.alert-dialog-action:hover, +.alert-dialog-action:hover { + background-color: var(--error-background-color-focused); +} + .alert-dialog-action:focus { - background-color: var(--error-text-color); - color: var(--background-color); - outline: none; box-shadow: 0 0 0 2px var(--focused-border-color); } .alert-dialog-trigger { - background: var(--focused-border-color); - color: var(--background-color); - border: none; + background-color: var(--dim-background-color); + color: var(--text-color); + border: 1px solid var(--dim-border-color); border-radius: 4px; - padding: 10px 22px; + padding: 8px 18px; font-size: 1rem; - font-weight: 600; cursor: pointer; - transition: background 0.15s, color 0.15s; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transition: all 0.2s ease; +} + +.alert-dialog-trigger:hover { + background-color: var(--hover-background-color); } -.alert-dialog-trigger:hover, .alert-dialog-trigger:focus { - background: var(--highlight-color-main); - color: var(--background-color); - outline: 2px solid var(--focused-border-color); - outline-offset: 2px; + box-shadow: 0 0 0 2px var(--focused-border-color); } @keyframes fadeIn { diff --git a/primitives/src/alert_dialog.rs b/primitives/src/alert_dialog.rs index c981ed0..b234edc 100644 --- a/primitives/src/alert_dialog.rs +++ b/primitives/src/alert_dialog.rs @@ -147,13 +147,15 @@ pub fn AlertDialogDescription(props: AlertDialogDescriptionProps) -> Element { #[derive(Props, Clone, PartialEq)] pub struct AlertDialogActionsProps { + #[props(extends = GlobalAttributes)] + attributes: Vec, children: Element, } #[component] pub fn AlertDialogActions(props: AlertDialogActionsProps) -> Element { rsx! { - div { class: "alert-dialog-actions", {props.children} } + div { ..props.attributes, {props.children} } } } @@ -161,13 +163,11 @@ pub fn AlertDialogActions(props: AlertDialogActionsProps) -> Element { pub struct AlertDialogActionProps { #[props(default)] on_click: Option>, - #[props(default)] - class: Option, - #[props(default)] - style: Option, #[props(default = "button".to_string())] r#type: String, children: Element, + #[props(extends = GlobalAttributes)] + attributes: Vec, } #[component] @@ -184,9 +184,8 @@ pub fn AlertDialogAction(props: AlertDialogActionProps) -> Element { rsx! { button { r#type: props.r#type.clone(), - class: props.class.clone().unwrap_or_else(|| "alert-dialog-action".to_string()), - style: props.style.clone().unwrap_or_default(), onclick: on_click, + ..props.attributes, {props.children} } } @@ -196,12 +195,10 @@ pub fn AlertDialogAction(props: AlertDialogActionProps) -> Element { pub struct AlertDialogCancelProps { #[props(default)] on_click: Option>, - #[props(default)] - class: Option, - #[props(default)] - style: Option, #[props(default = "button".to_string())] r#type: String, + #[props(extends = GlobalAttributes)] + attributes: Vec, children: Element, } @@ -219,10 +216,9 @@ pub fn AlertDialogCancel(props: AlertDialogCancelProps) -> Element { rsx! { button { r#type: props.r#type.clone(), - class: props.class.clone().unwrap_or_else(|| "alert-dialog-cancel".to_string()), - style: props.style.clone().unwrap_or_default(), onclick: on_click, autofocus: true, + ..props.attributes, {props.children} } } From b401323fd510fe4e327b76bdf1102f4aea6df166 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Wed, 4 Jun 2025 16:24:00 -0500 Subject: [PATCH 03/28] style avatar --- preview/assets/main.css | 70 -------------- preview/src/components/aspect_ratio/style.css | 2 +- preview/src/components/avatar/mod.rs | 91 ++++++++----------- preview/src/components/avatar/style.css | 59 ++++-------- primitives/src/avatar.rs | 9 +- 5 files changed, 65 insertions(+), 166 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index c2720a8..51f3eae 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -261,73 +261,3 @@ body { height: 100%; width: 100%; } - - -:root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); -} - -.dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.269 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.371 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.439 0 0); -} \ No newline at end of file diff --git a/preview/src/components/aspect_ratio/style.css b/preview/src/components/aspect_ratio/style.css index 006e1e7..1866f58 100644 --- a/preview/src/components/aspect_ratio/style.css +++ b/preview/src/components/aspect_ratio/style.css @@ -11,4 +11,4 @@ object-fit: cover; width: 100%; height: 100%; -} \ No newline at end of file +} diff --git a/preview/src/components/avatar/mod.rs b/preview/src/components/avatar/mod.rs index a718c9a..adf3cd0 100644 --- a/preview/src/components/avatar/mod.rs +++ b/preview/src/components/avatar/mod.rs @@ -8,63 +8,50 @@ pub(super) fn Demo() -> Element { rel: "stylesheet", href: asset!("/src/components/avatar/style.css"), } - div { class: "avatar-example-section", - div { class: "avatar-example", - div { class: "avatar-item", - p { class: "avatar-label", "Basic Usage" } - Avatar { - class: "avatar", - on_state_change: move |state| { - avatar_state.set(format!("Avatar 1: {state:?}")); - }, - AvatarImage { - src: asset!("/assets/dioxus-logo.png", ImageAssetOptions::new().with_avif()), - alt: "User avatar", - } - AvatarFallback { class: "avatar-fallback", "UA" } + div { display: "flex", flex_direction: "row", align_items: "center", justify_content: "between", gap: "1rem", + div { class: "avatar-item", + p { class: "avatar-label", "Basic Usage" } + Avatar { + class: "avatar avatar-sm", + on_state_change: move |state| { + avatar_state.set(format!("Avatar 1: {state:?}")); + }, + AvatarImage { + class: "avatar-image", + src: "https://avatars.githubusercontent.com/u/66571940?s=96&v=4", + alt: "User avatar", } + AvatarFallback { class: "avatar-fallback", "EA" } } - div { class: "avatar-item", - p { class: "avatar-label", "Error State" } - Avatar { - class: "avatar", - on_state_change: move |state| { - avatar_state.set(format!("Avatar 2: {state:?}")); - }, - AvatarImage { - src: "https://invalid-url.example/image.jpg", - alt: "Invalid image", - } - AvatarFallback { class: "avatar-fallback", "JD" } - } - } - div { class: "avatar-item", - p { class: "avatar-label", "Emoji Fallback" } - Avatar { - class: "avatar", - on_state_change: move |state| { - avatar_state.set(format!("Avatar 3: {state:?}")); - }, - AvatarImage { - src: "https://invalid-url.example/image.jpg", - alt: "Invalid image", - } - AvatarFallback { class: "avatar-fallback", "👤" } + } + div { class: "avatar-item", + p { class: "avatar-label", "Error State" } + Avatar { + class: "avatar avatar-md", + on_state_change: move |state| { + avatar_state.set(format!("Avatar 2: {state:?}")); + }, + AvatarImage { + class: "avatar-image", + src: "https://invalid-url.example/image.jpg", + alt: "Invalid image", } + AvatarFallback { class: "avatar-fallback", "JK" } } - div { class: "avatar-item", - p { class: "avatar-label", "Large Size" } - Avatar { - class: "avatar avatar-lg", - on_state_change: move |state| { - avatar_state.set(format!("Avatar 4: {state:?}")); - }, - AvatarImage { - src: asset!("/assets/dioxus-logo.png", ImageAssetOptions::new().with_avif()), - alt: "Large avatar", - } - AvatarFallback { class: "avatar-fallback", "LG" } + } + div { class: "avatar-item", + p { class: "avatar-label", "Large Size" } + Avatar { + class: "avatar avatar-lg", + on_state_change: move |state| { + avatar_state.set(format!("Avatar 4: {state:?}")); + }, + AvatarImage { + class: "avatar-image", + src: asset!("/assets/dioxus-logo.png", ImageAssetOptions::new().with_avif()), + alt: "Large avatar", } + AvatarFallback { class: "avatar-fallback", "DX" } } } } diff --git a/preview/src/components/avatar/style.css b/preview/src/components/avatar/style.css index 541d6aa..5c7ee3f 100644 --- a/preview/src/components/avatar/style.css +++ b/preview/src/components/avatar/style.css @@ -1,13 +1,3 @@ -/* Avatar Example Layout */ -.avatar-example { - display: flex; - flex-wrap: wrap; - gap: 1.5rem; - padding: 1rem; - background: var(--brighter-background-color); - border-radius: 8px; -} - .avatar-item { display: flex; flex-direction: column; @@ -25,9 +15,10 @@ .avatar { width: 64px; height: 64px; - border-radius: 50%; + display: flex; + flex-shrink: 0; + border-radius: 3.40282e+38px; overflow: hidden; - background: var(--brighter-background-color); color: var(--text-color); font-weight: 500; display: inline-flex; @@ -38,27 +29,28 @@ transition: transform 0.2s, box-shadow 0.2s; } -.avatar:hover { - transform: scale(1.05); - box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); +.avatar-image { + aspect-ratio: 1; + width: 100%; + height: 100%; } /* Avatar sizes */ .avatar-sm { - width: 40px; - height: 40px; + width: 2rem; + height: 2rem; font-size: 0.875rem; } .avatar-md { - width: 80px; - height: 80px; + width: 3rem; + height: 3rem; font-size: 1.25rem; } .avatar-lg { - width: 120px; - height: 120px; + width: 4rem; + height: 4rem; font-size: 1.75rem; } @@ -67,12 +59,8 @@ animation: pulse 1.5s infinite ease-in-out; } -.avatar[data-state="error"] { - border: 2px solid #ef4444; -} - .avatar[data-state="empty"] { - background: #cbd5e1; + background: var(--muted-background-color); } @keyframes pulse { @@ -95,23 +83,12 @@ display: flex; align-items: center; justify-content: center; - background: #e2e8f0; - color: #64748b; + background: var(--background-color); + color: var(--text-color); font-size: 1.5rem; } .avatar[data-state="error"] .avatar-fallback { - background: #fee2e2; - color: #b91c1c; + background: var(--dim-background-color); + color: var(--text-color); } - -/* State display */ -.avatar-state-display { - width: 100%; - margin-top: 1rem; - padding: 0.75rem; - background: #f0f0f0; - border-radius: 4px; - font-family: monospace; - color: var(--dim-text-color); -} \ No newline at end of file diff --git a/primitives/src/avatar.rs b/primitives/src/avatar.rs index 522249d..e472fa9 100644 --- a/primitives/src/avatar.rs +++ b/primitives/src/avatar.rs @@ -61,7 +61,7 @@ pub fn Avatar(props: AvatarProps) -> Element { }); // Create context for child components - let _ctx = use_context_provider(|| AvatarCtx { + use_context_provider(|| AvatarCtx { state, has_fallback_child, has_image_child, @@ -123,7 +123,7 @@ pub fn AvatarFallback(props: AvatarFallbackProps) -> Element { } rsx! { - span { ..props.attributes,{props.children} } + span { ..props.attributes, {props.children} } } } @@ -170,6 +170,11 @@ pub fn AvatarImage(props: AvatarImageProps) -> Element { } }; + let show_image = (ctx.state)() != AvatarState::Error; + if !show_image { + return rsx!({}); + } + rsx! { img { src: props.src.clone(), From faee2387d1be37dd7aac376553c8e52b3e1fec63 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 10:24:15 -0500 Subject: [PATCH 04/28] calendar styling --- preview/assets/main.css | 14 +- preview/src/components/calendar/docs.md | 9 +- preview/src/components/calendar/mod.rs | 34 ++- preview/src/components/calendar/style.css | 134 ++++------ primitives/src/calendar.rs | 312 +++++++++++++++------- 5 files changed, 318 insertions(+), 185 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index 51f3eae..e60daa8 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -1,3 +1,5 @@ +@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); + /* Theme style variables */ :root { --highlight-color-main: #dd7230; @@ -12,6 +14,7 @@ --dim-background-color: #F3F4F6; --muted-background-color: #fff; --hover-background-color: #dadada; + --hover-border-color: #b0b0b0; --focused-background-color: #d7d7d7; --contrast-background-color: #0d0d0d; --text-color: #000; @@ -40,13 +43,14 @@ --dim-background-color: #141313; --muted-background-color: #0A0A0A; --hover-background-color: #1a1a1a; + --hover-border-color: #3E3E3E; --focused-background-color: #2c2b2b; --contrast-background-color: #e6e6e6; --text-color: #D4D4D4; --dim-text-color: rgb(220, 220, 220); --border-color: #fff; - --dim-border-color: #383839; - --muted-text-color: #b0b0b0; + --dim-border-color: #232323; + --muted-text-color: #A1A1A1; --focused-border-color: #2b7fff; --success-background-color: #02271c; --success-text-color: #b6fae3; @@ -78,6 +82,10 @@ body { padding: 0; color: var(--text-color); background-color: var(--background-color); + font-family: "Inter", sans-serif; + font-optical-sizing: auto; + font-weight: 400; + font-style: normal; } .navbar { @@ -179,6 +187,7 @@ body { align-items: center; justify-content: center; width: 100vw; + background-color: var(--muted-background-color); } .component-preview-separator { @@ -250,6 +259,7 @@ body { flex: 1 0 auto; border-radius: 0.5rem; border: 1px solid var(--dim-border-color); + background-color: var(--muted-background-color); box-sizing: border-box; } diff --git a/preview/src/components/calendar/docs.md b/preview/src/components/calendar/docs.md index 20a1043..01cdf8a 100644 --- a/preview/src/components/calendar/docs.md +++ b/preview/src/components/calendar/docs.md @@ -19,7 +19,14 @@ Calendar { // The calendar header should contain the navigation controls and the title for the calendar. CalendarHeader { // The calendar navigation handles switching between months and years within the calendar view. - CalendarNavigation {} + CalendarNavigation { + // The previous month button allows users to navigate to the previous month. + PreviousMonthButton {} + // The title displays the current month and year of the calendar view. + CalendarTitle {} + // The next month button allows users to navigate to the next month. + NextMonthButton {} + } } // The calendar grid displays the days of the month in a grid layout. CalendarGrid {} diff --git a/preview/src/components/calendar/mod.rs b/preview/src/components/calendar/mod.rs index 9a0984f..692fea3 100644 --- a/preview/src/components/calendar/mod.rs +++ b/preview/src/components/calendar/mod.rs @@ -1,11 +1,11 @@ use dioxus::prelude::*; use dioxus_primitives::calendar::{ - Calendar, CalendarDate, CalendarGrid, CalendarHeader, CalendarNavigation, + Calendar, CalendarDate, CalendarGrid, CalendarHeader, CalendarMonthTitle, CalendarNavigation, CalendarNextMonthButton, CalendarPreviousMonthButton }; #[component] pub(super) fn Demo() -> Element { let mut selected_date = use_signal(|| None::); - let mut view_date = use_signal(|| CalendarDate::new(2024, 5, 15)); + let mut view_date = use_signal(|| CalendarDate::new(2025, 6, 5)); rsx! { document::Link { rel: "stylesheet", @@ -24,17 +24,31 @@ pub(super) fn Demo() -> Element { tracing::info!("View changed to: {}-{}", new_view.year, new_view.month); view_date.set(new_view); }, - CalendarHeader { CalendarNavigation {} } + CalendarHeader { + CalendarNavigation { + CalendarPreviousMonthButton { + svg { + class: "calendar-previous-month-icon", + view_box: "0 0 24 24", + xmlns: "http://www.w3.org/2000/svg", + polyline { points: "15 6 9 12 15 18" } + } + } + CalendarMonthTitle {} + CalendarNextMonthButton { + svg { + class: "calendar-next-month-icon", + view_box: "0 0 24 24", + xmlns: "http://www.w3.org/2000/svg", + polyline { points: "9 18 15 12 9 6" } + } + } + + } + } CalendarGrid {} } } - div { class: "selected-date", style: "margin-top: 20px;", - if let Some(date) = selected_date() { - p { style: "font-weight: bold;", "Selected date: {date}" } - } else { - p { "No date selected" } - } - } } } } diff --git a/preview/src/components/calendar/style.css b/preview/src/components/calendar/style.css index c3b2847..29b1ae4 100644 --- a/preview/src/components/calendar/style.css +++ b/preview/src/components/calendar/style.css @@ -1,9 +1,8 @@ /* Calendar Container */ .calendar { - width: 100%; border: 1px solid var(--dim-border-color); border-radius: 8px; - background-color: var(--background-color); + background-color: var(--muted-background-color); box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } @@ -13,8 +12,7 @@ display: flex; align-items: center; justify-content: space-between; - padding: 12px; - border-bottom: 1px solid var(--dim-border-color); + padding: .75rem .75rem .25rem .75rem; } .calendar-nav-title { @@ -25,129 +23,111 @@ .calendar-nav-prev, .calendar-nav-next { - background: none; - border: none; - font-size: 18px; - color: var(--dim-text-color); - cursor: pointer; - width: 30px; - height: 30px; display: flex; align-items: center; justify-content: center; - border-radius: 4px; + width: 1.75rem; + height: 1.75rem; + background-color: var(--dim-background-color); + color: var(--muted-text-color); + border: 1px solid var(--dim-border-color); + border-radius: .5rem; + font-size: 1rem; + cursor: pointer; } .calendar-nav-prev:hover, .calendar-nav-next:hover { background-color: var(--hover-background-color); color: var(--text-color); + border-color: var(--hover-border-color); } -.calendar-nav-prev:focus, -.calendar-nav-next:focus { - outline: 2px solid var(--focused-border-color); - outline-offset: 2px; -} - -.calendar-nav-prev:disabled, -.calendar-nav-next:disabled { - color: #ccc; - cursor: not-allowed; +.calendar-nav-prev:focus-visible, +.calendar-nav-next:focus-visible { + box-shadow: 0 0 0 2px var(--focused-border-color); } /* Calendar Grid */ .calendar-grid { - padding: 8px; + padding: .5rem; + width: 100%; } .calendar-grid-header { - display: grid; - grid-template-columns: repeat(7, 1fr); + display: flex; + flex-direction: row; margin-bottom: 8px; } .calendar-grid-day-header { text-align: center; font-size: 12px; - font-weight: 600; + font-weight: 300; color: var(--muted-text-color); - padding: 4px; + width: 2rem; } .calendar-grid-body { + width: 100%; display: flex; flex-direction: column; - gap: 2px; -} - -.calendar-grid-week { - display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 2px; -} - -.calendar-grid-days { - display: grid; - grid-template-columns: repeat(7, 1fr); - gap: 4px; + width: 100%; + gap: .25rem } .calendar-grid-cell { + width: 2rem; aspect-ratio: 1; - display: flex; - align-items: center; - justify-content: center; font-size: 14px; border: none; background: none; - border-radius: 4px; + border-radius: .5rem; cursor: pointer; - color: var(--dim-text-color); + color: var(--text-color); } -.calendar-grid-cell:hover:not([data-disabled="true"]) { +.calendar-grid-cell[data-month="current"]:hover:not([data-disabled="true"]) { background-color: var(--hover-background-color); } -.calendar-grid-cell:focus { +.calendar-grid-cell[data-month="current"]:focus-visible { outline: 2px solid var(--focused-border-color); outline-offset: 2px; } +.calendar-grid-cell[data-month="last"], +.calendar-grid-cell[data-month="next"], .calendar-grid-cell[data-disabled="true"] { - color: var(--dim-text-color); + color: var(--muted-text-color); cursor: not-allowed; } -.calendar-grid-cell[data-selected="true"] { - background-color: var(--focused-border-color); - color: var(--text-color); +.calendar-grid-cell[data-month="current"][data-selected="true"] { + background-color: var(--contrast-background-color); + color: var(--background-color); } - -.calendar-grid-cell[data-today="true"]:not([data-selected="true"]) { - border: 2px solid var(--focused-border-color); - font-weight: bold; +.calendar-grid-cell[data-month="current"][data-selected="true"]:hover { + background-color: var(--focused-background-color); + color: var(--muted-background-color); } -.calendar-grid-cell-empty { - aspect-ratio: 1; +.calendar-grid-cell[data-month="current"][data-today="true"]:not([data-selected="true"]) { + background-color: var(--focused-background-color); } .calendar-grid-weeknum { - display: flex; - align-items: center; - justify-content: center; font-size: 12px; - color: var(--dim-text-color); + color: var(--muted-text-color); background-color: var(--background-color); - border-radius: 4px; + border-radius: .5rem; } /* Calendar with week numbers */ -.calendar-grid.show-week-numbers .calendar-grid-header, -.calendar-grid.show-week-numbers .calendar-grid-week { - grid-template-columns: auto repeat(7, 1fr); +.calendar-grid-week { + display: flex; + flex-direction: row; + width: 100%; } /* Calendar states */ @@ -156,19 +136,13 @@ pointer-events: none; } -/* Animation for month transitions */ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(10px); - } - - to { - opacity: 1; - transform: translateY(0); - } +.calendar-next-month-icon, +.calendar-previous-month-icon { + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 2; + width: 20px; + height: 20px; } - -.calendar-grid-body { - animation: fadeIn 0.2s ease-out; -} \ No newline at end of file diff --git a/primitives/src/calendar.rs b/primitives/src/calendar.rs index f33bfc1..da22fa2 100644 --- a/primitives/src/calendar.rs +++ b/primitives/src/calendar.rs @@ -1,9 +1,9 @@ use crate::use_unique_id; use dioxus_lib::prelude::*; -use std::fmt; +use std::fmt::{self, Display}; // Calendar date representation -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct CalendarDate { pub year: i32, pub month: u32, // 1-12 @@ -39,19 +39,7 @@ impl CalendarDate { // Get the number of days in the month pub fn days_in_month(&self) -> u32 { - match self.month { - 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, - 4 | 6 | 9 | 11 => 30, - 2 => { - // Leap year check (simplified) - if self.year % 4 == 0 && (self.year % 100 != 0 || self.year % 400 == 0) { - 29 - } else { - 28 - } - } - _ => 30, // Default for invalid months - } + days_in_month(self.year, self.month) } // Get the previous month @@ -99,6 +87,29 @@ impl CalendarDate { } } +fn days_in_month(year: i32, month: u32) -> u32 { + match month { + 1 | 3 | 5 | 7 | 8 | 10 | 12 => 31, + 4 | 6 | 9 | 11 => 30, + 2 => { + // Leap year check (simplified) + if year % 4 == 0 && (year % 100 != 0 || year % 400 == 0) { + 29 + } else { + 28 + } + } + _ => unreachable!(), // Invalid month + } +} + +// Zeller's Congruence +fn month_start_day_of_week(year: i32, month: u32) -> u32 { + let month_offsets = [0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]; + let year = if month < 3 { year - 1 } else { year }; + ((year + year / 4 - year / 100 + year / 400 + month_offsets[month as usize - 1] + 1) % 7) as _ +} + impl fmt::Display for CalendarDate { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}-{:02}-{:02}", self.year, self.month, self.day) @@ -281,8 +292,28 @@ pub struct CalendarNavigationProps { // Calendar Navigation component #[component] pub fn CalendarNavigation(props: CalendarNavigationProps) -> Element { - let ctx: CalendarContext = use_context(); + rsx! { + div { class: "calendar-navigation", ..props.attributes, + {props.children} + } + } +} + + +/// Next month navigation button component props +#[derive(Props, Clone, PartialEq)] +pub struct CalendarPreviousMonthButtonProps { + #[props(extends = GlobalAttributes)] + attributes: Vec, + + children: Element, +} + +/// Next month navigation button component +#[component] +pub fn CalendarPreviousMonthButton(props: CalendarPreviousMonthButtonProps) -> Element { + let ctx: CalendarContext = use_context(); // Handle navigation to previous month let handle_prev_month = move |e: Event| { e.prevent_default(); @@ -290,6 +321,33 @@ pub fn CalendarNavigation(props: CalendarNavigationProps) -> Element { ctx.set_view_date.call(current_view.prev_month()); }; + rsx! { + button { + class: "calendar-nav-prev", + aria_label: "Previous month", + r#type: "button", + onclick: handle_prev_month, + disabled: (ctx.disabled)(), + ..props.attributes, + + {props.children} + } + } +} + +/// Next month navigation button component props +#[derive(Props, Clone, PartialEq)] +pub struct CalendarNextMonthButtonProps { + #[props(extends = GlobalAttributes)] + attributes: Vec, + + children: Element, +} + +/// Next month navigation button component +#[component] +pub fn CalendarNextMonthButton(props: CalendarNextMonthButtonProps) -> Element { + let ctx: CalendarContext = use_context(); // Handle navigation to next month let handle_next_month = move |e: Event| { e.prevent_default(); @@ -297,6 +355,31 @@ pub fn CalendarNavigation(props: CalendarNavigationProps) -> Element { ctx.set_view_date.call(current_view.next_month()); }; + rsx! { + button { + class: "calendar-nav-next", + aria_label: "Next month", + r#type: "button", + onclick: handle_next_month, + disabled: (ctx.disabled)(), + ..props.attributes, + + {props.children} + } + } +} + +/// Calendar Month Title component props +#[derive(Props, Clone, PartialEq)] +pub struct CalendarMonthTitleProps { + #[props(extends = GlobalAttributes)] + attributes: Vec, +} + +/// Calendar Month Title component +#[component] +pub fn CalendarMonthTitle(props: CalendarMonthTitleProps) -> Element { + let ctx: CalendarContext = use_context(); // Format the current month and year let month_year = use_memo(move || { let view_date = (ctx.view_date)(); @@ -319,28 +402,11 @@ pub fn CalendarNavigation(props: CalendarNavigationProps) -> Element { }); rsx! { - div { class: "calendar-navigation", ..props.attributes, - - // Default navigation UI - button { - class: "calendar-nav-prev", - aria_label: "Previous month", - r#type: "button", - onclick: handle_prev_month, - disabled: (ctx.disabled)(), - "⬅" - } - - div { class: "calendar-nav-title", {month_year} } + div { + class: "calendar-month-title", + ..props.attributes, - button { - class: "calendar-nav-next", - aria_label: "Next month", - r#type: "button", - onclick: handle_next_month, - disabled: (ctx.disabled)(), - "⮕" - } + {month_year} } } } @@ -356,8 +422,8 @@ pub struct CalendarGridProps { #[props(default)] show_week_numbers: bool, - /// Day labels (Mon, Tue, etc.) - #[props(default = vec!["Mo".to_string(), "Tu".to_string(), "We".to_string(), "Th".to_string(), "Fr".to_string(), "Sa".to_string(), "Su".to_string()])] + /// Day labels (Sun, Mon, etc.) + #[props(default = vec!["Su".to_string(), "Mo".to_string(), "Tu".to_string(), "We".to_string(), "Th".to_string(), "Fr".to_string(), "Sa".to_string()])] day_labels: Vec, #[props(extends = GlobalAttributes)] @@ -378,91 +444,90 @@ pub fn CalendarGrid(props: CalendarGridProps) -> Element { let view_date = (ctx.view_date)(); let days_in_month = view_date.days_in_month(); - // For a proper calendar grid, we need to determine the day of week for the first day - // For simplicity, we'll use a fixed offset (assuming first day is Monday) - // In a real implementation, we would calculate this properly - let first_day_offset = 2; // Adjust this based on testing + let first_day_offset = month_start_day_of_week(view_date.year, view_date.month); // Create a grid with empty cells for padding and actual days let mut grid = Vec::new(); // Add empty cells for days before the first day of the month - for _ in 0..first_day_offset { - grid.push(None); + for i in 0..first_day_offset { + grid.push(CalendarDayProps { + month: RelativeMonth::Last, + day: (view_date.prev_month().days_in_month() + i + 1 - first_day_offset) as u32, + is_selected: false, + is_today: false, + }); } // Add days of the month for day in 1..=days_in_month { - grid.push(Some(day)); + grid.push(CalendarDayProps { + month: RelativeMonth::Current, + day, + is_selected: (ctx.selected_date)().is_some_and(|d| { + d.day == day + && d.month == (ctx.view_date)().month + && d.year == (ctx.view_date)().year + }), + is_today: day == (ctx.view_date)().day, + }); } // Add empty cells to complete the grid (for a clean layout) let remainder = grid.len() % 7; if remainder > 0 { - for _ in 0..(7 - remainder) { - grid.push(None); + for day in 1..=(7 - remainder) { + grid.push(CalendarDayProps { + month: RelativeMonth::Next, + day: day as u32, + is_selected: false, + is_today: false, + }); } } - grid + // Turn the flat grid into a 2D grid (7 columns) + grid.chunks(7) + .map(|chunk| chunk.to_vec()) + .collect::>() }); - // Handle day selection - let handle_day_select = move |day: u32| { - if !(ctx.disabled)() { - let view_date = (ctx.view_date)(); - let date = CalendarDate::new(view_date.year, view_date.month, day); - ctx.set_selected_date.call(Some(date)); - } - }; - rsx! { - div { + table { role: "grid", id: props.id, class: "calendar-grid", ..props.attributes, // Day headers - div { role: "row", class: "calendar-grid-header", - - // Day name headers - for day_label in &props.day_labels { - div { - role: "columnheader", - class: "calendar-grid-day-header", - {day_label.clone()} + thead { role: "row", + tr { + class: "calendar-grid-header", + // Day name headers + for day_label in &props.day_labels { + th { + class: "calendar-grid-day-header", + {day_label.clone()} + } } } } // Calendar days grid - div { class: "calendar-grid-body", - - // Create a simple grid layout - div { class: "calendar-grid-days", - - // Display all days in a grid - for day_opt in days_grid() { - if let Some(day) = day_opt { - button { - class: "calendar-grid-cell", - onclick: move |e| { - e.prevent_default(); - handle_day_select(day); - }, - r#type: "button", - "data-today": day == (ctx.view_date)().day, - "data-selected": (ctx.selected_date)() - .is_some_and(|d| { - d.day == day && d.month == (ctx.view_date)().month - && d.year == (ctx.view_date)().year - }), - {day.to_string()} + tbody { class: "calendar-grid-body", + // Display all days in a grid + for row in &*days_grid.read() { + tr { + class: "calendar-grid-week", + for props in row.iter().copied() { + td { + CalendarDay { + day: props.day, + is_today: props.is_today, + is_selected: props.is_selected, + month: props.month + } } - } else { - // Empty cell for padding - div { class: "calendar-grid-cell calendar-grid-cell-empty" } } } } @@ -471,6 +536,69 @@ pub fn CalendarGrid(props: CalendarGridProps) -> Element { } } +#[derive(Copy, Clone, Debug, PartialEq)] +enum RelativeMonth { + Last, + Current, + Next, +} + +impl Display for RelativeMonth { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + RelativeMonth::Last => write!(f, "last"), + RelativeMonth::Current => write!(f, "current"), + RelativeMonth::Next => write!(f, "next"), + } + } +} + +#[derive(Props, Copy, Clone, Debug, PartialEq)] +struct CalendarDayProps { + day: u32, + is_selected: bool, + is_today: bool, + month: RelativeMonth, +} + +#[component] +fn CalendarDay(props: CalendarDayProps) -> Element { + let CalendarDayProps { + day, + is_selected, + is_today, + month, + } = props; + let ctx: CalendarContext = use_context(); + + // Handle day selection + let handle_day_select = move |day: u32| { + if !(ctx.disabled)() { + let view_date = (ctx.view_date)(); + let date = CalendarDate::new(view_date.year, view_date.month, day); + ctx.set_selected_date.call(Some(date)); + } + }; + + rsx! { + button { + class: "calendar-grid-cell", + onclick: move |e| { + e.prevent_default(); + if month == RelativeMonth::Current { + handle_day_select(day); + } + }, + r#type: "button", + tabindex: (month != RelativeMonth::Current).then_some("-1"), + "data-today": is_today, + "data-selected": is_selected, + "data-month": "{month}", + {day.to_string()} + } + } +} + // Calendar Cell component props #[derive(Props, Clone, PartialEq)] pub struct CalendarCellProps { From c760d5344960bddc01c72513cdd28586ca39bdae Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 10:45:47 -0500 Subject: [PATCH 05/28] checkbox styling --- preview/assets/main.css | 4 +- preview/src/components/calendar/mod.rs | 1 - preview/src/components/checkbox/mod.rs | 14 +++++-- preview/src/components/checkbox/style.css | 45 +++++++++++++++-------- 4 files changed, 43 insertions(+), 21 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index e60daa8..c32d6d6 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -11,8 +11,8 @@ :root { --background-color: #fff; --brighter-background-color: #fbfbfb; - --dim-background-color: #F3F4F6; --muted-background-color: #fff; + --dim-background-color: #F3F4F6; --hover-background-color: #dadada; --hover-border-color: #b0b0b0; --focused-background-color: #d7d7d7; @@ -40,8 +40,8 @@ :root { --background-color: #000; --brighter-background-color: #0e0e0e; - --dim-background-color: #141313; --muted-background-color: #0A0A0A; + --dim-background-color: #141313; --hover-background-color: #1a1a1a; --hover-border-color: #3E3E3E; --focused-background-color: #2c2b2b; diff --git a/preview/src/components/calendar/mod.rs b/preview/src/components/calendar/mod.rs index 692fea3..0cb261a 100644 --- a/preview/src/components/calendar/mod.rs +++ b/preview/src/components/calendar/mod.rs @@ -43,7 +43,6 @@ pub(super) fn Demo() -> Element { polyline { points: "9 18 15 12 9 6" } } } - } } CalendarGrid {} diff --git a/preview/src/components/checkbox/mod.rs b/preview/src/components/checkbox/mod.rs index a86b396..a6a2f76 100644 --- a/preview/src/components/checkbox/mod.rs +++ b/preview/src/components/checkbox/mod.rs @@ -7,8 +7,16 @@ pub(super) fn Demo() -> Element { rel: "stylesheet", href: asset!("/src/components/checkbox/style.css"), } - Checkbox { id: "tos-check", name: "tos-check", - CheckboxIndicator { "✓" } + Checkbox { class: "checkbox", name: "tos-check", + CheckboxIndicator { + class: "checkbox-indicator", + svg { + class: "checkbox-check-icon", + view_box: "0 0 24 24", + xmlns: "http://www.w3.org/2000/svg", + path { d: "M5 13l4 4L19 7" } + } + } } } -} +} \ No newline at end of file diff --git a/preview/src/components/checkbox/style.css b/preview/src/components/checkbox/style.css index d1cff52..28ce91b 100644 --- a/preview/src/components/checkbox/style.css +++ b/preview/src/components/checkbox/style.css @@ -1,23 +1,38 @@ -#tos-check { - width: 25px; - height: 25px; - margin: 8px 16px; +.checkbox { + width: 1rem; + height: 1rem; color: var(--text-color); - background-color: var(--background-color); - border: 1px solid var(--dim-border-color); + background-color: var(--dim-background-color); + border: 1px solid var(--hover-border-color); border-radius: 4px; cursor: pointer; - font-size: 14px; + box-sizing: border-box; + padding: 0; + margin: 0; } -#tos-check:hover { - color: var(--text-color); - background-color: var(--hover-background-color); - transition: background-color 0.2s ease; +.checkbox-indicator { + display: flex; + align-items: center; + justify-content: center; } -#tos-check:focus { - color: var(--text-color); - background-color: var(--focused-background-color); - transition: background-color 0.2s ease; +.checkbox[data-state="checked"] { + background-color: var(--contrast-background-color); + color: var(--background-color); + border: none; +} + +.checkbox:focus-visible { + box-shadow: 0 0 0 2px var(--focused-border-color); +} + +.checkbox-check-icon { + fill: none; + stroke: currentColor; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 2; + width: 1rem; + height: 1rem; } From 2d87ecb14a4e438a16a1f427a9a692d82c79a483 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 11:07:27 -0500 Subject: [PATCH 06/28] style context menu --- preview/assets/main.css | 4 +- preview/src/components/context_menu/mod.rs | 73 +++++++++---------- preview/src/components/context_menu/style.css | 28 ++----- primitives/src/context_menu.rs | 13 +++- 4 files changed, 55 insertions(+), 63 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index c32d6d6..9f2eb38 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -30,7 +30,7 @@ --error-background-color: #ef4444; --error-background-color-focused: #dc2626; --error-border-color: var(--error-background-color); - --error-text-color: var(--dim-text-color); + --error-text-color: var(--text-color); --info-background-color: #e0f2fe; --info-text-color: #0284c7; } @@ -44,7 +44,7 @@ --dim-background-color: #141313; --hover-background-color: #1a1a1a; --hover-border-color: #3E3E3E; - --focused-background-color: #2c2b2b; + --focused-background-color: #262626; --contrast-background-color: #e6e6e6; --text-color: #D4D4D4; --dim-text-color: rgb(220, 220, 220); diff --git a/preview/src/components/context_menu/mod.rs b/preview/src/components/context_menu/mod.rs index 657c766..350b9fd 100644 --- a/preview/src/components/context_menu/mod.rs +++ b/preview/src/components/context_menu/mod.rs @@ -4,50 +4,47 @@ use dioxus_primitives::context_menu::{ }; #[component] pub(super) fn Demo() -> Element { - let mut selected_value = use_signal(String::new); rsx! { document::Link { rel: "stylesheet", href: asset!("/src/components/context_menu/style.css"), } - div { class: "context-menu-example", - ContextMenu { - ContextMenuTrigger { class: "context-menu-trigger", "Right click here to open context menu" } - ContextMenuContent { class: "context-menu-content", - ContextMenuItem { - class: "context-menu-item", - value: "edit".to_string(), - index: 0usize, - on_select: move |value| { - selected_value.set(value); - }, - "Edit" - } - ContextMenuItem { - class: "context-menu-item", - value: "duplicate".to_string(), - index: 1usize, - on_select: move |value| { - selected_value.set(value); - }, - "Duplicate" - } - ContextMenuItem { - class: "context-menu-item", - value: "delete".to_string(), - index: 2usize, - on_select: move |value| { - selected_value.set(value); - }, - "Delete" - } - } + ContextMenu { + ContextMenuTrigger { + padding: "20px", + background: "var(--background-color)", + border: "1px dashed var(--dim-border-color)", + border_radius: ".5rem", + cursor: "context-menu", + user_select: "none", + text_align: "center", + "right click here" } - div { class: "selected-value", - if selected_value().is_empty() { - "No action selected" - } else { - "Selected action: {selected_value()}" + ContextMenuContent { class: "context-menu-content", + ContextMenuItem { + class: "context-menu-item", + value: "edit".to_string(), + index: 0usize, + "Edit" + } + ContextMenuItem { + class: "context-menu-item", + value: "undo".to_string(), + index: 1usize, + disabled: true, + "Undo" + } + ContextMenuItem { + class: "context-menu-item", + value: "duplicate".to_string(), + index: 1usize, + "Duplicate" + } + ContextMenuItem { + class: "context-menu-item", + value: "delete".to_string(), + index: 2usize, + "Delete" } } } diff --git a/preview/src/components/context_menu/style.css b/preview/src/components/context_menu/style.css index db57e10..0a4fdf1 100644 --- a/preview/src/components/context_menu/style.css +++ b/preview/src/components/context_menu/style.css @@ -1,23 +1,9 @@ -.context-menu-example { - padding: 20px; -} - -.context-menu-trigger { - padding: 20px; - background: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - cursor: context-menu; - user-select: none; -} - .context-menu-content { min-width: 220px; - background: var(--brighter-background-color); + background: var(--focused-background-color); border-radius: 6px; padding: 5px; - box-shadow: 0 10px 20px rgba(0, 0, 0, 0.1); - border: 1px solid var(--dim-border-color); + box-shadow: 0 0 0 1px var(--hover-border-color); animation: slideIn 0.1s ease-out; } @@ -37,12 +23,14 @@ align-items: center; } -.context-menu-item:hover { - background: var(--hover-background-color); +.context-menu-item[data-disabled="true"] { + color: var(--muted-text-color); + cursor: not-allowed; } -.context-menu-item:focus { - background: var(--focused-background-color); +.context-menu-item:hover:not([data-disabled="true"]), +.context-menu-item:focus-visible { + background: var(--hover-border-color); } @keyframes slideIn { diff --git a/primitives/src/context_menu.rs b/primitives/src/context_menu.rs index 032c354..dcb3968 100644 --- a/primitives/src/context_menu.rs +++ b/primitives/src/context_menu.rs @@ -251,6 +251,10 @@ pub fn ContextMenuContent(props: ContextMenuContentProps) -> Element { #[derive(Props, Clone, PartialEq)] pub struct ContextMenuItemProps { + /// Whether the item is disabled + #[props(default = ReadOnlySignal::new(Signal::new(false)))] + disabled: ReadOnlySignal, + /// The value of the menu item value: ReadOnlySignal, @@ -270,6 +274,8 @@ pub struct ContextMenuItemProps { pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element { let mut ctx: ContextMenuCtx = use_context(); + let disabled = use_memo(move || (props.disabled)() || (ctx.disabled)()); + // Register this item with the menu use_effect(move || { ctx.item_count += 1; @@ -295,7 +301,7 @@ pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element { let handle_click = { let value = (props.value)().clone(); move |_| { - if !(ctx.disabled)() { + if !disabled() { props.on_select.call(value.clone()); ctx.set_open.call(false); ctx.restore_trigger_focus(); @@ -309,7 +315,7 @@ pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element { // Check for Enter or Space key if event.key() == Key::Enter || event.key().to_string() == " " { event.prevent_default(); - if !(ctx.disabled)() { + if !disabled() { props.on_select.call(value.clone()); ctx.set_open.call(false); ctx.restore_trigger_focus(); @@ -325,7 +331,8 @@ pub fn ContextMenuItem(props: ContextMenuItemProps) -> Element { onclick: handle_click, onkeydown: handle_keydown, onfocus: move |_| ctx.set_focus(Some((props.index)())), - aria_disabled: (ctx.disabled)(), + aria_disabled: disabled(), + "data-disabled": disabled(), ..props.attributes, {props.children} From 6356f709680fa305f7ab43a89fe53ccd63979ab6 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 11:19:36 -0500 Subject: [PATCH 07/28] style dropdown menu --- preview/assets/hero.css | 2 +- preview/assets/main.css | 4 +- preview/src/components/alert_dialog/style.css | 6 +- preview/src/components/aspect_ratio/style.css | 2 +- preview/src/components/context_menu/style.css | 4 +- .../src/components/dropdown_menu/style.css | 62 ++++++++++--------- preview/src/components/hover_card/style.css | 2 +- preview/src/components/radio_group/style.css | 2 +- preview/src/components/toast/style.css | 2 +- 9 files changed, 45 insertions(+), 41 deletions(-) diff --git a/preview/assets/hero.css b/preview/assets/hero.css index 45d17cc..48d05eb 100644 --- a/preview/assets/hero.css +++ b/preview/assets/hero.css @@ -46,7 +46,7 @@ padding: 10px; color: var(--text-color); border: 1px solid var(--border-color); - border-radius: 4px; + border-radius: .5rem; background-color: var(--brighter-background-color); box-sizing: border-box; margin: 2em auto; diff --git a/preview/assets/main.css b/preview/assets/main.css index 9f2eb38..0dc10f6 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -129,7 +129,7 @@ body { /* Code block styles */ .code-block { font-family: "Courier New", Courier, monospace; - border-radius: 4px; + border-radius: .5rem; overflow: scroll; width: 100%; height: 100%; @@ -162,7 +162,7 @@ body { background: none; color: var(--text-color); border: none; - border-radius: 4px; + border-radius: .5rem; cursor: pointer; } diff --git a/preview/src/components/alert_dialog/style.css b/preview/src/components/alert_dialog/style.css index 7383761..25baa2d 100644 --- a/preview/src/components/alert_dialog/style.css +++ b/preview/src/components/alert_dialog/style.css @@ -69,7 +69,7 @@ background-color: var(--dim-background-color); color: var(--text-color); border: 1px solid var(--dim-border-color); - border-radius: 4px; + border-radius: .5rem; padding: 8px 18px; font-size: 1rem; cursor: pointer; @@ -88,7 +88,7 @@ background-color: var(--error-background-color); color: var(--error-text-color); border: 1px solid var(--error-border-color); - border-radius: 4px; + border-radius: .5rem; padding: 8px 18px; font-size: 1rem; cursor: pointer; @@ -107,7 +107,7 @@ background-color: var(--dim-background-color); color: var(--text-color); border: 1px solid var(--dim-border-color); - border-radius: 4px; + border-radius: .5rem; padding: 8px 18px; font-size: 1rem; cursor: pointer; diff --git a/preview/src/components/aspect_ratio/style.css b/preview/src/components/aspect_ratio/style.css index 1866f58..a4505b8 100644 --- a/preview/src/components/aspect_ratio/style.css +++ b/preview/src/components/aspect_ratio/style.css @@ -1,5 +1,5 @@ .aspect-ratio-container { - border-radius: 6px; + border-radius: .5rem; overflow: hidden; box-shadow: 0 2px 10px #000000; background-color: var(--dim-background-color); diff --git a/preview/src/components/context_menu/style.css b/preview/src/components/context_menu/style.css index 0a4fdf1..f200cba 100644 --- a/preview/src/components/context_menu/style.css +++ b/preview/src/components/context_menu/style.css @@ -1,7 +1,7 @@ .context-menu-content { min-width: 220px; background: var(--focused-background-color); - border-radius: 6px; + border-radius: .5rem; padding: 5px; box-shadow: 0 0 0 1px var(--hover-border-color); animation: slideIn 0.1s ease-out; @@ -13,7 +13,7 @@ .context-menu-item { padding: 8px 12px; - border-radius: 4px; + border-radius: .5rem; cursor: pointer; user-select: none; outline: none; diff --git a/preview/src/components/dropdown_menu/style.css b/preview/src/components/dropdown_menu/style.css index dd102d2..dd38fd1 100644 --- a/preview/src/components/dropdown_menu/style.css +++ b/preview/src/components/dropdown_menu/style.css @@ -5,23 +5,22 @@ } .dropdown-menu-trigger { - padding: 8px 16px; + background-color: var(--dim-background-color); color: var(--text-color); - background-color: var(--brighter-background-color); border: 1px solid var(--dim-border-color); - border-radius: 4px; + border-radius: .5rem; + padding: 8px 18px; + font-size: 1rem; cursor: pointer; - font-size: 14px; transition: all 0.2s ease; } .dropdown-menu-trigger:hover { - background-color: var(--dim-background-color); + background-color: var(--hover-background-color); } .dropdown-menu-trigger:focus { - outline: none; - box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25); + box-shadow: 0 0 0 2px var(--focused-border-color); } .dropdown-menu-content { @@ -30,12 +29,11 @@ left: 0; margin-top: 4px; min-width: 200px; - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); - z-index: 1000; - padding: 4px 0; + background: var(--focused-background-color); + border-radius: .5rem; + padding: 5px; + box-shadow: 0 0 0 1px var(--hover-border-color); + animation: slideIn 0.1s ease-out; } .dropdown-menu-content[hidden] { @@ -43,29 +41,35 @@ } .dropdown-menu-item { - padding: 8px 16px; + padding: 8px 12px; + border-radius: .5rem; cursor: pointer; - font-size: 14px; - transition: all 0.2s ease; user-select: none; + outline: none; + font-size: 14px; + color: var(--text-color); + display: flex; + align-items: center; } -.dropdown-menu-item:hover { - background-color: var(--hover-background-color); +.dropdown-menu-item[data-disabled="true"] { + color: var(--muted-text-color); + cursor: not-allowed; } -.dropdown-menu-item:focus { - outline: none; - background-color: var(--focused-background-color); +.dropdown-menu-item:hover:not([data-disabled="true"]), +.dropdown-menu-item:focus-visible { + background: var(--hover-border-color); } -/* State styles */ -.dropdown-menu[data-disabled="true"] .dropdown-menu-trigger { - opacity: 0.5; - cursor: not-allowed; -} +@keyframes slideIn { + from { + opacity: 0; + transform: scale(0.95); + } -.dropdown-menu-item[data-disabled="true"] { - opacity: 0.5; - cursor: not-allowed; + to { + opacity: 1; + transform: scale(1); + } } \ No newline at end of file diff --git a/preview/src/components/hover_card/style.css b/preview/src/components/hover_card/style.css index 2ec8f75..0bb0007 100644 --- a/preview/src/components/hover_card/style.css +++ b/preview/src/components/hover_card/style.css @@ -14,7 +14,7 @@ z-index: 1000; min-width: 200px; padding: 12px 16px; - border-radius: 6px; + border-radius: .5rem; background-color: var(--brighter-background-color); color: var(--text-color); font-size: 14px; diff --git a/preview/src/components/radio_group/style.css b/preview/src/components/radio_group/style.css index 4d1d05c..483d081 100644 --- a/preview/src/components/radio_group/style.css +++ b/preview/src/components/radio_group/style.css @@ -9,7 +9,7 @@ display: flex; align-items: center; padding: 8px 16px; - border-radius: 6px; + border-radius: .5rem; border: 1px solid var(--dim-border-color); background: var(--brighter-background-color); cursor: pointer; diff --git a/preview/src/components/toast/style.css b/preview/src/components/toast/style.css index d7285fb..1d7ef60 100644 --- a/preview/src/components/toast/style.css +++ b/preview/src/components/toast/style.css @@ -11,7 +11,7 @@ .toast { background-color: var(--dim-background-color); - border-radius: 6px; + border-radius: .5rem; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); padding: 12px 16px; display: flex; From 3e8a37a0fa433257aa5f17560dda971549138fa4 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 11:33:07 -0500 Subject: [PATCH 08/28] hover card styling --- preview/src/components/hover_card/mod.rs | 74 +---------- preview/src/components/hover_card/style.css | 137 +------------------- 2 files changed, 14 insertions(+), 197 deletions(-) diff --git a/preview/src/components/hover_card/mod.rs b/preview/src/components/hover_card/mod.rs index 6cf9c4b..f38ccd5 100644 --- a/preview/src/components/hover_card/mod.rs +++ b/preview/src/components/hover_card/mod.rs @@ -1,6 +1,6 @@ use dioxus::prelude::*; use dioxus_primitives::hover_card::{ - HoverCard, HoverCardAlign, HoverCardContent, HoverCardSide, HoverCardTrigger, + HoverCard, HoverCardContent, HoverCardSide, HoverCardTrigger, }; #[component] pub(super) fn Demo() -> Element { @@ -13,74 +13,14 @@ pub(super) fn Demo() -> Element { style: "padding: 50px; display: flex; flex-direction: row; flex-wrap: wrap; gap: 40px; justify-content: center; align-items: center;", HoverCard { class: "hover-card", HoverCardTrigger { class: "hover-card-trigger", - button { class: "user-trigger", "@johndoe" } + "@johndoe" } HoverCardContent { class: "hover-card-content", side: HoverCardSide::Bottom, - div { class: "user-card", - div { class: "user-card-header", - img { - class: "user-card-avatar", - src: "https://github.com/DioxusLabs.png", - alt: "User avatar", - } - div { - h4 { class: "user-card-name", "John Doe" } - p { class: "user-card-username", "@johndoe" } - } - } - p { class: "user-card-bio", - "Software developer passionate about Rust and web technologies. Building awesome UI components with Dioxus." - } - div { class: "user-card-stats", - div { class: "user-card-stat", - span { class: "user-card-stat-value", "142" } - span { class: "user-card-stat-label", "Posts" } - } - div { class: "user-card-stat", - span { class: "user-card-stat-value", "2.5k" } - span { class: "user-card-stat-label", "Followers" } - } - div { class: "user-card-stat", - span { class: "user-card-stat-value", "350" } - span { class: "user-card-stat-label", "Following" } - } - } - } - } - } - HoverCard { class: "hover-card", - HoverCardTrigger { class: "hover-card-trigger", - button { class: "product-trigger", "View Product" } - } - HoverCardContent { - class: "hover-card-content", - side: HoverCardSide::Right, - align: HoverCardAlign::Start, - div { class: "product-card", - img { - class: "product-card-image", - src: "https://images.unsplash.com/photo-1505740420928-5e560c06d30e", - alt: "Product image", - } - h4 { class: "product-card-title", "Wireless Headphones" } - p { class: "product-card-price", "$129.99" } - p { class: "product-card-description", - "High-quality wireless headphones with noise cancellation and 30-hour battery life." - } - div { class: "product-card-rating", "★★★★☆ (4.5)" } - } - } - } - HoverCard { class: "hover-card", - HoverCardTrigger { class: "hover-card-trigger", - a { href: "#", "Hover over this link" } - } - HoverCardContent { - class: "hover-card-content", - side: HoverCardSide::Top, - align: HoverCardAlign::Center, - div { style: "padding: 8px;", - p { style: "margin: 0;", "This link will take you to an external website." } + div { + padding: "1rem", + "Dioxus is" + i { " the " } + "Rust framework for building fullstack web, desktop, and mobile apps. Iterate with live hotreloading, add server functions, and deploy in record time." } } } diff --git a/preview/src/components/hover_card/style.css b/preview/src/components/hover_card/style.css index 0bb0007..7119a57 100644 --- a/preview/src/components/hover_card/style.css +++ b/preview/src/components/hover_card/style.css @@ -6,22 +6,19 @@ .hover-card-trigger { display: inline-block; - cursor: pointer; } .hover-card-content { position: absolute; z-index: 1000; min-width: 200px; - padding: 12px 16px; border-radius: .5rem; - background-color: var(--brighter-background-color); - color: var(--text-color); - font-size: 14px; - line-height: 1.5; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - border: 1px solid #eaeaea; - animation: hoverCardFadeIn 0.2s ease-in-out; + min-width: 200px; + background: var(--focused-background-color); + border-radius: .5rem; + padding: 5px; + box-shadow: 0 0 0 1px var(--hover-border-color); + animation: hoverCardFadeIn 0.1s ease-out; } /* Positioning based on side */ @@ -112,129 +109,9 @@ /* State styles */ .hover-card[data-disabled="true"] .hover-card-trigger { - cursor: default; + color: var(--muted-text-color); } .hover-card-content[data-state="closed"] { display: none; } - -/* Example specific styles */ -.user-card { - display: flex; - flex-direction: column; - gap: 8px; -} - -.user-card-header { - display: flex; - align-items: center; - gap: 12px; -} - -.user-card-avatar { - width: 48px; - height: 48px; - border-radius: 50%; - object-fit: cover; -} - -.user-card-name { - margin: 0; - font-size: 16px; - font-weight: 600; -} - -.user-card-username { - margin: 0; - font-size: 14px; - color: var(--dim-text-color); -} - -.user-card-bio { - margin: 8px 0; - font-size: 14px; - color: var(--text-color); -} - -.user-card-stats { - display: flex; - gap: 16px; - margin-top: 8px; -} - -.user-card-stat { - display: flex; - flex-direction: column; -} - -.user-card-stat-value { - font-weight: 600; - font-size: 14px; -} - -.user-card-stat-label { - font-size: 12px; - color: var(--dim-text-color); -} - -.user-trigger { - cursor: pointer; - padding: 8px 16px; - color: var(--text-color); - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - cursor: pointer; - font-size: 14px; -} - -.product-card { - display: flex; - flex-direction: column; - gap: 8px; -} - -.product-card-image { - width: 100%; - height: 120px; - object-fit: cover; - border-radius: 4px; -} - -.product-card-title { - margin: 0; - font-size: 16px; - font-weight: 600; -} - -.product-card-price { - font-size: 14px; - font-weight: 600; - color: #0070f3; -} - -.product-card-description { - margin: 8px 0; - font-size: 14px; - color: var(--text-color); -} - -.product-card-rating { - display: flex; - align-items: center; - gap: 4px; - font-size: 14px; - color: #f5a623; -} - -.product-trigger { - cursor: pointer; - padding: 8px 16px; - color: var(--text-color); - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - cursor: pointer; - font-size: 14px; -} From 26c70fc3a672b2da2375ec92e3840fa13b1a27f3 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 11:40:01 -0500 Subject: [PATCH 09/28] fix nested padding border radius --- preview/src/components/context_menu/style.css | 4 ++-- preview/src/components/dropdown_menu/style.css | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/preview/src/components/context_menu/style.css b/preview/src/components/context_menu/style.css index f200cba..e8cc67d 100644 --- a/preview/src/components/context_menu/style.css +++ b/preview/src/components/context_menu/style.css @@ -2,7 +2,7 @@ min-width: 220px; background: var(--focused-background-color); border-radius: .5rem; - padding: 5px; + padding: .25em; box-shadow: 0 0 0 1px var(--hover-border-color); animation: slideIn 0.1s ease-out; } @@ -13,7 +13,7 @@ .context-menu-item { padding: 8px 12px; - border-radius: .5rem; + border-radius: calc(.5rem - .25em); cursor: pointer; user-select: none; outline: none; diff --git a/preview/src/components/dropdown_menu/style.css b/preview/src/components/dropdown_menu/style.css index dd38fd1..2be0270 100644 --- a/preview/src/components/dropdown_menu/style.css +++ b/preview/src/components/dropdown_menu/style.css @@ -31,7 +31,7 @@ min-width: 200px; background: var(--focused-background-color); border-radius: .5rem; - padding: 5px; + padding: .25em; box-shadow: 0 0 0 1px var(--hover-border-color); animation: slideIn 0.1s ease-out; } @@ -42,7 +42,7 @@ .dropdown-menu-item { padding: 8px 12px; - border-radius: .5rem; + border-radius: calc(.5rem - .25em); cursor: pointer; user-select: none; outline: none; From d2f0fb1f9220233157b7538a4745907bd9f839f1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 11:42:49 -0500 Subject: [PATCH 10/28] better demo for the dropdown menu --- preview/src/components/dropdown_menu/mod.rs | 22 +++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/preview/src/components/dropdown_menu/mod.rs b/preview/src/components/dropdown_menu/mod.rs index 0183178..f63338a 100644 --- a/preview/src/components/dropdown_menu/mod.rs +++ b/preview/src/components/dropdown_menu/mod.rs @@ -14,30 +14,40 @@ pub(super) fn Demo() -> Element { DropdownMenuContent { class: "dropdown-menu-content", DropdownMenuItem { class: "dropdown-menu-item", - value: "item1".to_string(), + value: "edit".to_string(), index: 0usize, on_select: move |value| { tracing::info!("Selected: {}", value); }, - "Item 1" + "Edit" } DropdownMenuItem { class: "dropdown-menu-item", - value: "item2".to_string(), + value: "undo".to_string(), index: 1usize, + disabled: true, on_select: move |value| { tracing::info!("Selected: {}", value); }, - "Item 2" + "Undo" } DropdownMenuItem { class: "dropdown-menu-item", - value: "item3".to_string(), + value: "duplicate".to_string(), index: 2usize, on_select: move |value| { tracing::info!("Selected: {}", value); }, - "Item 3" + "Duplicate" + } + DropdownMenuItem { + class: "dropdown-menu-item", + value: "delete".to_string(), + index: 3usize, + on_select: move |value| { + tracing::info!("Selected: {}", value); + }, + "Delete" } } } From 2cb928c43c0b2ab31e7546c2c269fcd7d1e23c48 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 13:11:57 -0500 Subject: [PATCH 11/28] style menubar --- preview/assets/main.css | 4 +- preview/src/components/checkbox/style.css | 5 +- preview/src/components/context_menu/style.css | 5 +- .../src/components/dropdown_menu/style.css | 17 +++-- preview/src/components/menubar/style.css | 67 ++++++++++++++----- 5 files changed, 70 insertions(+), 28 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index 0dc10f6..5881e0e 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -17,7 +17,8 @@ --hover-border-color: #b0b0b0; --focused-background-color: #d7d7d7; --contrast-background-color: #0d0d0d; - --text-color: #000; + --bright-text-color: #000; + --text-color: #111; --dim-text-color: rgb(43, 43, 43); --border-color: #000; --dim-border-color: #E5E5E5; @@ -46,6 +47,7 @@ --hover-border-color: #3E3E3E; --focused-background-color: #262626; --contrast-background-color: #e6e6e6; + --bright-text-color: #fAfAfA; --text-color: #D4D4D4; --dim-text-color: rgb(220, 220, 220); --border-color: #fff; diff --git a/preview/src/components/checkbox/style.css b/preview/src/components/checkbox/style.css index 28ce91b..d651540 100644 --- a/preview/src/components/checkbox/style.css +++ b/preview/src/components/checkbox/style.css @@ -3,7 +3,8 @@ height: 1rem; color: var(--text-color); background-color: var(--dim-background-color); - border: 1px solid var(--hover-border-color); + border: none; + box-shadow: inset 0 0 0 1px var(--hover-border-color); border-radius: 4px; cursor: pointer; box-sizing: border-box; @@ -20,7 +21,7 @@ .checkbox[data-state="checked"] { background-color: var(--contrast-background-color); color: var(--background-color); - border: none; + box-shadow: none; } .checkbox:focus-visible { diff --git a/preview/src/components/context_menu/style.css b/preview/src/components/context_menu/style.css index e8cc67d..3ee9198 100644 --- a/preview/src/components/context_menu/style.css +++ b/preview/src/components/context_menu/style.css @@ -2,7 +2,7 @@ min-width: 220px; background: var(--focused-background-color); border-radius: .5rem; - padding: .25em; + padding: .25rem; box-shadow: 0 0 0 1px var(--hover-border-color); animation: slideIn 0.1s ease-out; } @@ -13,7 +13,7 @@ .context-menu-item { padding: 8px 12px; - border-radius: calc(.5rem - .25em); + border-radius: calc(.5rem - .25rem); cursor: pointer; user-select: none; outline: none; @@ -30,6 +30,7 @@ .context-menu-item:hover:not([data-disabled="true"]), .context-menu-item:focus-visible { + color: var(--bright-text-color); background: var(--hover-border-color); } diff --git a/preview/src/components/dropdown_menu/style.css b/preview/src/components/dropdown_menu/style.css index 2be0270..8351c23 100644 --- a/preview/src/components/dropdown_menu/style.css +++ b/preview/src/components/dropdown_menu/style.css @@ -7,7 +7,8 @@ .dropdown-menu-trigger { background-color: var(--dim-background-color); color: var(--text-color); - border: 1px solid var(--dim-border-color); + box-shadow: inset 0 0 0 1px var(--dim-border-color); + border: none; border-radius: .5rem; padding: 8px 18px; font-size: 1rem; @@ -16,10 +17,11 @@ } .dropdown-menu-trigger:hover { - background-color: var(--hover-background-color); + color: var(--bright-text-color); + background: var(--hover-border-color); } -.dropdown-menu-trigger:focus { +.dropdown-menu-trigger:focus-visible { box-shadow: 0 0 0 2px var(--focused-border-color); } @@ -31,8 +33,8 @@ min-width: 200px; background: var(--focused-background-color); border-radius: .5rem; - padding: .25em; - box-shadow: 0 0 0 1px var(--hover-border-color); + padding: .25rem; + box-shadow: inset 0 0 0 1px var(--hover-border-color); animation: slideIn 0.1s ease-out; } @@ -42,7 +44,7 @@ .dropdown-menu-item { padding: 8px 12px; - border-radius: calc(.5rem - .25em); + border-radius: calc(.5rem - .25rem); cursor: pointer; user-select: none; outline: none; @@ -59,6 +61,7 @@ .dropdown-menu-item:hover:not([data-disabled="true"]), .dropdown-menu-item:focus-visible { + color: var(--bright-text-color); background: var(--hover-border-color); } @@ -72,4 +75,4 @@ opacity: 1; transform: scale(1); } -} \ No newline at end of file +} diff --git a/preview/src/components/menubar/style.css b/preview/src/components/menubar/style.css index e45ee7c..c49fce1 100644 --- a/preview/src/components/menubar/style.css +++ b/preview/src/components/menubar/style.css @@ -1,10 +1,12 @@ .menubar { display: flex; - gap: 4px; - padding: 4px; - border: 1px solid var(--dim-border-color); - border-radius: 4px; + gap: .25rem; + padding: .25rem; + border: none; + box-shadow: inset 0 0 0 1px var(--dim-border-color); + border-radius: .5rem; background: var(--background-color); + box-sizing: border-box; } .menubar-menu { @@ -17,11 +19,23 @@ background: none; cursor: pointer; color: var(--text-color); + border-radius: calc(.5rem - .25rem); +} + +.menubar-menu[data-state="open"] .menubar-trigger { + color: var(--bright-text-color); + background-color: var(--hover-border-color); } -.menubar-trigger:hover { - background: var(--hover-background-color); - border-radius: 4px; +.menubar-trigger[data-disabled="true"] { + color: var(--muted-text-color); + cursor: not-allowed; +} + +.menubar-trigger:hover:not([data-disabled="true"]), +.menubar-trigger:focus-visible { + color: var(--bright-text-color); + background: var(--hover-border-color); } .menubar-content { @@ -30,11 +44,13 @@ top: 100%; left: 0; min-width: 200px; - background: var(--background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - padding: 4px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + margin-left: -.25rem; + margin-top: .5rem; + background: var(--focused-background-color); + border-radius: .5rem; + padding: .25rem; + box-shadow: inset 0 0 0 1px var(--hover-border-color); + animation: menubarSlideIn 0.1s ease-out; } .menubar-menu[data-state="open"] .menubar-content { @@ -45,14 +61,33 @@ display: block; padding: 8px 12px; cursor: pointer; - border-radius: 4px; + border-radius: calc(.5rem - .25rem); } -.menubar-item:hover { - background: var(--hover-background-color); +.menubar-item[data-disabled="true"] { + color: var(--muted-text-color); + cursor: not-allowed; +} + +.menubar-item:hover:not([data-disabled="true"]), +.menubar-item:focus-visible { + color: var(--bright-text-color); + background: var(--hover-border-color); } [data-disabled="true"] { opacity: 0.5; cursor: not-allowed; -} \ No newline at end of file +} + +@keyframes menubarSlideIn { + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } +} From 8a071e4d265f55870521e0d28631ff537ceb5892 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 13:23:25 -0500 Subject: [PATCH 12/28] progress styling --- preview/assets/main.css | 1 - preview/src/components/progress/mod.rs | 39 +++++++++++------------ preview/src/components/progress/style.css | 28 ++-------------- 3 files changed, 21 insertions(+), 47 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index 5881e0e..42ab6b4 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -205,7 +205,6 @@ body { justify-content: center; border: 1px solid var(--dim-border-color); border-radius: 8px; - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); box-sizing: border-box; margin: 20px 0; width: 75vw; diff --git a/preview/src/components/progress/mod.rs b/preview/src/components/progress/mod.rs index d00987f..a019757 100644 --- a/preview/src/components/progress/mod.rs +++ b/preview/src/components/progress/mod.rs @@ -2,32 +2,29 @@ use dioxus::prelude::*; use dioxus_primitives::progress::{Progress, ProgressIndicator}; #[component] pub(super) fn Demo() -> Element { - let mut progress = use_signal(|| 80.0); + let mut progress = use_signal(|| 0); + + use_effect(move || { + let mut timer = document::eval( + "setInterval(() => { + dioxus.send(Math.floor(Math.random() * 30)); + }, 1000);", + ); + spawn(async move { + while let Ok(new_progress) = timer.recv::().await { + let mut progress = progress.write(); + *progress = (*progress + new_progress) % 101; + } + }); + }); + rsx! { document::Link { rel: "stylesheet", href: asset!("/src/components/progress/style.css"), } - div { style: "display: flex; flex-direction: column; align-items: center; gap: 4px;", - Progress { class: "progress", value: progress(), - ProgressIndicator { class: "progress-indicator" } - } - button { - class: "progress-button", - onclick: move |_| progress.set(progress() + 10.0), - "Increment" - } - button { - class: "progress-button", - onclick: move |_| progress.set(progress() - 10.0), - "Decrement" - } - button { class: "progress-button", onclick: move |_| progress.set(0.0), "Reset" } - button { - class: "progress-button", - onclick: move |_| progress.set(100.0), - "Complete" - } + Progress { class: "progress", value: progress() as f64, + ProgressIndicator { class: "progress-indicator" } } } } diff --git a/preview/src/components/progress/style.css b/preview/src/components/progress/style.css index 35369f2..8c6a9e1 100644 --- a/preview/src/components/progress/style.css +++ b/preview/src/components/progress/style.css @@ -1,11 +1,10 @@ .progress { position: relative; overflow: hidden; - background: var(--brighter-background-color); + background: var(--hover-border-color); border-radius: 9999px; width: 200px; - height: 20px; - border: 2px solid var(--dim-border-color); + height: .5rem; box-sizing: border-box; } @@ -16,10 +15,9 @@ .progress-indicator { height: 100%; - background-color: var(--contrast-background-color); + background-color: var(--bright-text-color); transition: width 250ms ease; width: var(--progress-value, 0%); - /* Use CSS variable for width */ } @keyframes indeterminate { @@ -31,23 +29,3 @@ transform: translateX(200%); } } - -.progress-button { - padding: 8px 12px; - border-radius: 4px; - cursor: pointer; - user-select: none; - outline: none; - font-size: 14px; - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - color: var(--text-color); -} - -.progress-button:hover { - background: var(--hover-background-color); -} - -.progress-button:focus { - background: var(--focused-background-color); -} From 0659723b3dd45475c06960cede629e9e6f502168 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 14:03:23 -0500 Subject: [PATCH 13/28] fix light mode --- preview/assets/main.css | 8 +- preview/src/components/accordion/style.css | 2 +- preview/src/components/alert_dialog/style.css | 179 ++++++++++-------- preview/src/components/aspect_ratio/mod.rs | 7 +- preview/src/components/aspect_ratio/style.css | 2 - preview/src/components/calendar/style.css | 156 ++++++++------- preview/src/components/context_menu/style.css | 68 ++++--- .../src/components/dropdown_menu/style.css | 105 ++++++---- preview/src/components/hover_card/style.css | 14 +- preview/src/components/menubar/style.css | 35 +++- 10 files changed, 338 insertions(+), 238 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index 42ab6b4..bb340fc 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -12,17 +12,17 @@ --background-color: #fff; --brighter-background-color: #fbfbfb; --muted-background-color: #fff; - --dim-background-color: #F3F4F6; - --hover-background-color: #dadada; + --dim-background-color: #F8F8F8; + --hover-background-color: #f5f5f5; --hover-border-color: #b0b0b0; - --focused-background-color: #d7d7d7; + --focused-background-color: #f5f5f5; --contrast-background-color: #0d0d0d; --bright-text-color: #000; --text-color: #111; --dim-text-color: rgb(43, 43, 43); --border-color: #000; --dim-border-color: #E5E5E5; - --muted-text-color: #b0b0b0; + --muted-text-color: #848484; --focused-border-color: #2b7fff; --success-background-color: #ecfdf5; --success-text-color: #10b981; diff --git a/preview/src/components/accordion/style.css b/preview/src/components/accordion/style.css index 59dd204..6b41630 100644 --- a/preview/src/components/accordion/style.css +++ b/preview/src/components/accordion/style.css @@ -16,7 +16,7 @@ } .accordion-trigger:focus-visible { - box-shadow: 0 0 0 3px var(--focused-border-color); + box-shadow: 0 0 0 2px var(--focused-border-color); } .accordion-trigger:hover { diff --git a/preview/src/components/alert_dialog/style.css b/preview/src/components/alert_dialog/style.css index 25baa2d..55e7584 100644 --- a/preview/src/components/alert_dialog/style.css +++ b/preview/src/components/alert_dialog/style.css @@ -1,133 +1,146 @@ /* Alert Dialog Backdrop */ .alert-dialog-backdrop { - position: fixed; - inset: 0; - background: rgba(0, 0, 0, 0.3); - z-index: 1000; - animation: fadeIn 0.2s ease; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.3); + z-index: 1000; + animation: fadeIn 0.2s ease; } /* Alert Dialog Container - improved for theme consistency */ .alert-dialog { - display: flex; - flex-direction: column; - text-align: center; - position: fixed; - top: 50%; - left: 50%; - width: 100%; - max-width: calc(100% - 2rem); - margin: 0; - background: var(--muted-background-color); - color: var(--text-color); - border: 1px solid var(--dim-border-color); - border-radius: 8px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18); - z-index: 1001; - padding: 32px 24px 24px 24px; - display: flex; - flex-direction: column; - gap: 16px; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; - transform: translate(-50%, -50%); - animation: none; - box-sizing: border-box; + display: flex; + flex-direction: column; + text-align: center; + position: fixed; + top: 50%; + left: 50%; + width: 100%; + max-width: calc(100% - 2rem); + margin: 0; + background: var(--muted-background-color); + color: var(--text-color); + border: 1px solid var(--dim-border-color); + border-radius: 8px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18); + z-index: 1001; + padding: 32px 24px 24px 24px; + display: flex; + flex-direction: column; + gap: 16px; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, + Arial, sans-serif; + transform: translate(-50%, -50%); + animation: none; + box-sizing: border-box; } .alert-dialog-title { - font-size: 1.25rem; - font-weight: 700; - color: var(--text-color); - margin: 0; + font-size: 1.25rem; + font-weight: 700; + color: var(--text-color); + margin: 0; } .alert-dialog-description { - font-size: 1rem; - color: var(--muted-text-color); - margin: 0; + font-size: 1rem; + color: var(--muted-text-color); + margin: 0; } .alert-dialog-actions { - display: flex; - flex-direction: column-reverse; - gap: 12px; + display: flex; + flex-direction: column-reverse; + gap: 12px; } @media (width >= 40rem) { - .alert-dialog-actions { - flex-direction: row; - justify-content: flex-end; - } - - .alert-dialog { - text-align: left; - max-width: 32rem; - } + .alert-dialog-actions { + flex-direction: row; + justify-content: flex-end; + } + + .alert-dialog { + text-align: left; + max-width: 32rem; + } } .alert-dialog-cancel { + background-color: var(--background-color); + color: var(--text-color); + border: 1px solid var(--dim-border-color); + border-radius: 0.5rem; + padding: 8px 18px; + font-size: 1rem; + cursor: pointer; + transition: all 0.2s ease; +} + +@media (prefers-color-scheme: dark) { + .alert-dialog-cancel { background-color: var(--dim-background-color); - color: var(--text-color); - border: 1px solid var(--dim-border-color); - border-radius: .5rem; - padding: 8px 18px; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; + } } .alert-dialog-cancel:hover { - background-color: var(--hover-background-color); + background-color: var(--hover-background-color); } .alert-dialog-cancel:focus { - box-shadow: 0 0 0 2px var(--focused-border-color); + box-shadow: 0 0 0 2px var(--focused-border-color); } .alert-dialog-action { - background-color: var(--error-background-color); - color: var(--error-text-color); - border: 1px solid var(--error-border-color); - border-radius: .5rem; - padding: 8px 18px; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; + background-color: var(--error-background-color); + color: var(--error-text-color); + border: 1px solid var(--error-border-color); + border-radius: 0.5rem; + padding: 8px 18px; + font-size: 1rem; + cursor: pointer; + transition: all 0.2s ease; } .alert-dialog-action:hover { - background-color: var(--error-background-color-focused); + background-color: var(--error-background-color-focused); } .alert-dialog-action:focus { - box-shadow: 0 0 0 2px var(--focused-border-color); + box-shadow: 0 0 0 2px var(--focused-border-color); } .alert-dialog-trigger { + background-color: var(--background-color); + color: var(--text-color); + border: 1px solid var(--dim-border-color); + border-radius: 0.5rem; + padding: 8px 18px; + font-size: 1rem; + cursor: pointer; + transition: all 0.2s ease; +} + +@media (prefers-color-scheme: dark) { + .alert-dialog-trigger { background-color: var(--dim-background-color); - color: var(--text-color); - border: 1px solid var(--dim-border-color); - border-radius: .5rem; - padding: 8px 18px; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; + } } .alert-dialog-trigger:hover { - background-color: var(--hover-background-color); + background-color: var(--hover-background-color); } .alert-dialog-trigger:focus { - box-shadow: 0 0 0 2px var(--focused-border-color); + box-shadow: 0 0 0 2px var(--focused-border-color); } @keyframes fadeIn { - from { - opacity: 0; - } - - to { - opacity: 1; - } -} \ No newline at end of file + from { + opacity: 0; + } + + to { + opacity: 1; + } +} diff --git a/preview/src/components/aspect_ratio/mod.rs b/preview/src/components/aspect_ratio/mod.rs index bd53c77..1f0dd23 100644 --- a/preview/src/components/aspect_ratio/mod.rs +++ b/preview/src/components/aspect_ratio/mod.rs @@ -12,9 +12,10 @@ pub(super) fn Demo() -> Element { width: "10em", min_width: "30vw", AspectRatio { ratio: 4.0 / 3.0, - img { - class: "aspect-ratio-image", - src: asset!("/assets/dioxus-logo.png", ImageAssetOptions::new().with_avif()), + div { + background: "linear-gradient(to bottom right, var(--hover-background-color), var(--dim-background-color))", + width: "100%", + height: "100%", } } } diff --git a/preview/src/components/aspect_ratio/style.css b/preview/src/components/aspect_ratio/style.css index a4505b8..e3085db 100644 --- a/preview/src/components/aspect_ratio/style.css +++ b/preview/src/components/aspect_ratio/style.css @@ -1,8 +1,6 @@ .aspect-ratio-container { border-radius: .5rem; overflow: hidden; - box-shadow: 0 2px 10px #000000; - background-color: var(--dim-background-color); padding: 1rem; box-sizing: border-box; } diff --git a/preview/src/components/calendar/style.css b/preview/src/components/calendar/style.css index 29b1ae4..54ebe9b 100644 --- a/preview/src/components/calendar/style.css +++ b/preview/src/components/calendar/style.css @@ -1,139 +1,157 @@ /* Calendar Container */ .calendar { - border: 1px solid var(--dim-border-color); - border-radius: 8px; - background-color: var(--muted-background-color); - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + border: 1px solid var(--dim-border-color); + border-radius: 8px; + background-color: var(--muted-background-color); + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, + Arial, sans-serif; } /* Calendar Navigation */ .calendar-navigation { - display: flex; - align-items: center; - justify-content: space-between; - padding: .75rem .75rem .25rem .75rem; + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.75rem 0.75rem 0.25rem 0.75rem; } .calendar-nav-title { - font-weight: 600; - font-size: 16px; - color: var(--text-color); + font-weight: 600; + font-size: 16px; + color: var(--text-color); } .calendar-nav-prev, .calendar-nav-next { - display: flex; - align-items: center; - justify-content: center; - width: 1.75rem; - height: 1.75rem; + display: flex; + align-items: center; + justify-content: center; + width: 1.75rem; + height: 1.75rem; + background-color: transparent; + color: var(--muted-text-color); + border: 1px solid var(--dim-border-color); + border-radius: 0.5rem; + font-size: 1rem; + cursor: pointer; +} + +@media (prefers-color-scheme: dark) { + .calendar-nav-prev, + .calendar-nav-next { background-color: var(--dim-background-color); - color: var(--muted-text-color); - border: 1px solid var(--dim-border-color); - border-radius: .5rem; - font-size: 1rem; - cursor: pointer; + } } .calendar-nav-prev:hover, .calendar-nav-next:hover { - background-color: var(--hover-background-color); - color: var(--text-color); - border-color: var(--hover-border-color); + background-color: var(--hover-background-color); + color: var(--text-color); + border-color: var(--hover-border-color); } .calendar-nav-prev:focus-visible, .calendar-nav-next:focus-visible { - box-shadow: 0 0 0 2px var(--focused-border-color); + box-shadow: 0 0 0 2px var(--focused-border-color); } /* Calendar Grid */ .calendar-grid { - padding: .5rem; - width: 100%; + padding: 0.5rem; + width: 100%; } .calendar-grid-header { - display: flex; - flex-direction: row; - margin-bottom: 8px; + display: flex; + flex-direction: row; + margin-bottom: 8px; } .calendar-grid-day-header { - text-align: center; - font-size: 12px; - font-weight: 300; - color: var(--muted-text-color); - width: 2rem; + text-align: center; + font-size: 12px; + font-weight: 300; + color: var(--muted-text-color); + width: 2rem; } .calendar-grid-body { - width: 100%; - display: flex; - flex-direction: column; - width: 100%; - gap: .25rem + width: 100%; + display: flex; + flex-direction: column; + width: 100%; + gap: 0.25rem; } .calendar-grid-cell { - width: 2rem; - aspect-ratio: 1; - font-size: 14px; - border: none; - background: none; - border-radius: .5rem; - cursor: pointer; - color: var(--text-color); + width: 2rem; + aspect-ratio: 1; + font-size: 14px; + border: none; + background: none; + border-radius: 0.5rem; + cursor: pointer; + color: var(--text-color); } -.calendar-grid-cell[data-month="current"]:hover:not([data-disabled="true"]) { - background-color: var(--hover-background-color); +.calendar-grid-cell[data-month="current"]:not([data-disabled="true"]):hover { + background-color: var(--hover-background-color); } .calendar-grid-cell[data-month="current"]:focus-visible { - outline: 2px solid var(--focused-border-color); - outline-offset: 2px; + outline: 2px solid var(--focused-border-color); + outline-offset: 2px; } .calendar-grid-cell[data-month="last"], .calendar-grid-cell[data-month="next"], .calendar-grid-cell[data-disabled="true"] { - color: var(--muted-text-color); - cursor: not-allowed; + color: var(--muted-text-color); + cursor: not-allowed; } .calendar-grid-cell[data-month="current"][data-selected="true"] { - background-color: var(--contrast-background-color); - color: var(--background-color); + background-color: var(--contrast-background-color); + color: var(--background-color); } -.calendar-grid-cell[data-month="current"][data-selected="true"]:hover { +@media (prefers-color-scheme: dark) { + .calendar-grid-cell[data-month="current"][data-selected="true"]:hover { background-color: var(--focused-background-color); color: var(--muted-background-color); + } +} +@media (prefers-color-scheme: light) { + .calendar-grid-cell[data-month="current"][data-selected="true"]:hover { + background-color: var(--contrast-background-color); + font-weight: 520; + } } -.calendar-grid-cell[data-month="current"][data-today="true"]:not([data-selected="true"]) { - background-color: var(--focused-background-color); +.calendar-grid-cell[data-month="current"][data-today="true"]:not( + [data-selected="true"] + ) { + background-color: var(--focused-background-color); } .calendar-grid-weeknum { - font-size: 12px; - color: var(--muted-text-color); - background-color: var(--background-color); - border-radius: .5rem; + font-size: 12px; + color: var(--muted-text-color); + background-color: var(--background-color); + border-radius: 0.5rem; } /* Calendar with week numbers */ .calendar-grid-week { - display: flex; - flex-direction: row; - width: 100%; + display: flex; + flex-direction: row; + width: 100%; } /* Calendar states */ .calendar[data-disabled="true"] { - opacity: 0.6; - pointer-events: none; + opacity: 0.6; + pointer-events: none; } .calendar-next-month-icon, diff --git a/preview/src/components/context_menu/style.css b/preview/src/components/context_menu/style.css index 3ee9198..add57a5 100644 --- a/preview/src/components/context_menu/style.css +++ b/preview/src/components/context_menu/style.css @@ -1,47 +1,61 @@ .context-menu-content { - min-width: 220px; + min-width: 220px; + background: var(--background-color); + border-radius: 0.5rem; + padding: 0.25rem; + box-shadow: 0 0 0 1px var(--dim-border-color); + animation: slideIn 0.1s ease-out; +} + +@media (prefers-color-scheme: dark) { + .context-menu-content { background: var(--focused-background-color); - border-radius: .5rem; - padding: .25rem; box-shadow: 0 0 0 1px var(--hover-border-color); - animation: slideIn 0.1s ease-out; + } } .context-menu-content[hidden] { - display: none; + display: none; } .context-menu-item { - padding: 8px 12px; - border-radius: calc(.5rem - .25rem); - cursor: pointer; - user-select: none; - outline: none; - font-size: 14px; - color: var(--text-color); - display: flex; - align-items: center; + padding: 8px 12px; + border-radius: calc(0.5rem - 0.25rem); + cursor: pointer; + user-select: none; + outline: none; + font-size: 14px; + color: var(--text-color); + display: flex; + align-items: center; } .context-menu-item[data-disabled="true"] { - color: var(--muted-text-color); - cursor: not-allowed; + color: var(--muted-text-color); + cursor: not-allowed; } .context-menu-item:hover:not([data-disabled="true"]), .context-menu-item:focus-visible { - color: var(--bright-text-color); + color: var(--bright-text-color); + background: var(--hover-background-color); +} + +@media (prefers-color-scheme: dark) { + .context-menu-item:hover:not([data-disabled="true"]), + .context-menu-item:focus-visible { background: var(--hover-border-color); + } } @keyframes slideIn { - from { - opacity: 0; - transform: scale(0.95); - } - - to { - opacity: 1; - transform: scale(1); - } -} \ No newline at end of file + from { + opacity: 0; + transform: scale(0.95); + } + + to { + opacity: 1; + transform: scale(1); + } +} diff --git a/preview/src/components/dropdown_menu/style.css b/preview/src/components/dropdown_menu/style.css index 8351c23..2e1255a 100644 --- a/preview/src/components/dropdown_menu/style.css +++ b/preview/src/components/dropdown_menu/style.css @@ -1,78 +1,99 @@ /* Dropdown Menu Styles */ .dropdown-menu { - position: relative; - display: inline-block; + position: relative; + display: inline-block; } .dropdown-menu-trigger { + background-color: var(--background-color); + color: var(--text-color); + box-shadow: inset 0 0 0 1px var(--dim-border-color); + border: none; + border-radius: 0.5rem; + padding: 8px 18px; + font-size: 1rem; + cursor: pointer; + transition: all 0.2s ease; +} + +@media (prefers-color-scheme: dark) { + .dropdown-menu-trigger { background-color: var(--dim-background-color); - color: var(--text-color); - box-shadow: inset 0 0 0 1px var(--dim-border-color); - border: none; - border-radius: .5rem; - padding: 8px 18px; - font-size: 1rem; - cursor: pointer; - transition: all 0.2s ease; + } } .dropdown-menu-trigger:hover { - color: var(--bright-text-color); - background: var(--hover-border-color); + color: var(--bright-text-color); + background: var(--hover-background-color); } .dropdown-menu-trigger:focus-visible { - box-shadow: 0 0 0 2px var(--focused-border-color); + box-shadow: 0 0 0 2px var(--focused-border-color); } .dropdown-menu-content { - position: absolute; - top: 100%; - left: 0; - margin-top: 4px; - min-width: 200px; + position: absolute; + top: 100%; + left: 0; + margin-top: 4px; + min-width: 200px; + background: var(--background-color); + border-radius: 0.5rem; + padding: 0.25rem; + box-shadow: inset 0 0 0 1px var(--dim-border-color); + animation: slideIn 0.1s ease-out; +} + +@media (prefers-color-scheme: dark) { + .dropdown-menu-content { background: var(--focused-background-color); - border-radius: .5rem; - padding: .25rem; box-shadow: inset 0 0 0 1px var(--hover-border-color); - animation: slideIn 0.1s ease-out; + } } + .dropdown-menu-content[hidden] { - display: none; + display: none; } .dropdown-menu-item { - padding: 8px 12px; - border-radius: calc(.5rem - .25rem); - cursor: pointer; - user-select: none; - outline: none; - font-size: 14px; - color: var(--text-color); - display: flex; - align-items: center; + padding: 8px 12px; + border-radius: calc(0.5rem - 0.25rem); + cursor: pointer; + user-select: none; + outline: none; + font-size: 14px; + color: var(--text-color); + display: flex; + align-items: center; } .dropdown-menu-item[data-disabled="true"] { - color: var(--muted-text-color); - cursor: not-allowed; + color: var(--muted-text-color); + cursor: not-allowed; } .dropdown-menu-item:hover:not([data-disabled="true"]), .dropdown-menu-item:focus-visible { - color: var(--bright-text-color); + color: var(--bright-text-color); + background: var(--hover-background-color); +} + +@media (prefers-color-scheme: dark) { + .dropdown-menu-item:hover:not([data-disabled="true"]), +.dropdown-menu-item:focus-visible { background: var(--hover-border-color); + } } @keyframes slideIn { - from { - opacity: 0; - transform: scale(0.95); - } + from { + opacity: 0; + transform: scale(0.95); + } - to { - opacity: 1; - transform: scale(1); - } + to { + opacity: 1; + transform: scale(1); + } } diff --git a/preview/src/components/hover_card/style.css b/preview/src/components/hover_card/style.css index 7119a57..3c54afe 100644 --- a/preview/src/components/hover_card/style.css +++ b/preview/src/components/hover_card/style.css @@ -14,13 +14,23 @@ min-width: 200px; border-radius: .5rem; min-width: 200px; - background: var(--focused-background-color); border-radius: .5rem; padding: 5px; - box-shadow: 0 0 0 1px var(--hover-border-color); + background: var(--background-color); + /* Semi transparent shadow effect in light mode */ + box-shadow: 0 2px 10px #0000001a; + border: 1px solid var(--dim-border-color); animation: hoverCardFadeIn 0.1s ease-out; } +@media (prefers-color-scheme: dark) { + .hover-card-content { + background: var(--focused-background-color); + box-shadow: 0 0 0 1px var(--hover-border-color); + border: none; + } +} + /* Positioning based on side */ .hover-card-content[data-side="top"] { position: absolute; diff --git a/preview/src/components/menubar/style.css b/preview/src/components/menubar/style.css index c49fce1..d0204ff 100644 --- a/preview/src/components/menubar/style.css +++ b/preview/src/components/menubar/style.css @@ -24,7 +24,12 @@ .menubar-menu[data-state="open"] .menubar-trigger { color: var(--bright-text-color); - background-color: var(--hover-border-color); + background-color: var(--hover-background-color); +} +@media (prefers-color-scheme: dark) { + .menubar-menu[data-state="open"] .menubar-trigger { + background-color: var(--hover-border-color); + } } .menubar-trigger[data-disabled="true"] { @@ -35,7 +40,13 @@ .menubar-trigger:hover:not([data-disabled="true"]), .menubar-trigger:focus-visible { color: var(--bright-text-color); - background: var(--hover-border-color); + background: var(--hover-background-color); +} +@media (prefers-color-scheme: dark) { + .menubar-trigger:hover:not([data-disabled="true"]), + .menubar-trigger:focus-visible { + background: var(--hover-border-color); + } } .menubar-content { @@ -46,13 +57,20 @@ min-width: 200px; margin-left: -.25rem; margin-top: .5rem; - background: var(--focused-background-color); + background: var(--background-color); border-radius: .5rem; padding: .25rem; - box-shadow: inset 0 0 0 1px var(--hover-border-color); + box-shadow: inset 0 0 0 1px var(--dim-border-color); animation: menubarSlideIn 0.1s ease-out; } +@media (prefers-color-scheme: dark) { + .menubar-content { + background: var(--focused-background-color); + box-shadow: inset 0 0 0 1px var(--hover-border-color); + } +} + .menubar-menu[data-state="open"] .menubar-content { display: block; } @@ -61,6 +79,7 @@ display: block; padding: 8px 12px; cursor: pointer; + font-size: 14px; border-radius: calc(.5rem - .25rem); } @@ -72,7 +91,13 @@ .menubar-item:hover:not([data-disabled="true"]), .menubar-item:focus-visible { color: var(--bright-text-color); - background: var(--hover-border-color); + background: var(--hover-background-color); +} +@media (prefers-color-scheme: dark) { + .menubar-item:hover:not([data-disabled="true"]), + .menubar-item:focus-visible { + background: var(--hover-border-color); + } } [data-disabled="true"] { From 35261f2c3f9e62f0167eb90145c1ffb5311b2214 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 14:33:14 -0500 Subject: [PATCH 14/28] style radio group --- preview/src/components/radio_group/mod.rs | 7 ++- preview/src/components/radio_group/style.css | 64 +++++++++++--------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/preview/src/components/radio_group/mod.rs b/preview/src/components/radio_group/mod.rs index 0dd8923..6b28b3b 100644 --- a/preview/src/components/radio_group/mod.rs +++ b/preview/src/components/radio_group/mod.rs @@ -18,19 +18,20 @@ pub(super) fn Demo() -> Element { class: "radio-item", value: "option1".to_string(), index: 0usize, - "Option 1" + "Blue" } RadioItem { class: "radio-item", value: "option2".to_string(), index: 1usize, - "Option 2" + "Red" } RadioItem { class: "radio-item", value: "option3".to_string(), index: 2usize, - "Option 3" + disabled: true, + "Green" } } div { style: "margin-top: 1rem;", "Selected value: {value()}" } diff --git a/preview/src/components/radio_group/style.css b/preview/src/components/radio_group/style.css index 483d081..aa7239a 100644 --- a/preview/src/components/radio_group/style.css +++ b/preview/src/components/radio_group/style.css @@ -1,38 +1,48 @@ .radio-group { - display: flex; - flex-direction: column; - gap: 10px; - padding: 15px; + display: flex; + flex-direction: column; + gap: 1.5rem; } .radio-item { - display: flex; - align-items: center; - padding: 8px 16px; - border-radius: .5rem; - border: 1px solid var(--dim-border-color); - background: var(--brighter-background-color); - cursor: pointer; - font-size: 14px; - transition: all 0.2s; - color: var(--text-color); -} + display: flex; + align-items: center; + gap: 1.5rem; + border: none; + padding: 0; + font-size: 14px; + color: var(--text-color); + background-color: transparent; -.radio-item:hover { - background: var(--hover-background-color); -} + &:before { + content: ""; + display: block; + width: 1rem; + height: 1rem; + box-sizing: border-box; + border: 0.25rem solid var(--dim-background-color); + box-shadow: 0 0 0 1px var(--hover-border-color); + background: var(--dim-background-color); + border-radius: 1.5rem; + cursor: pointer; + } -.radio-item:focus { + &:focus-visible { outline: none; - box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1); -} + } -.radio-item[data-state="checked"] { - background: var(--focused-background-color); - border-color: var(--dim-border-color); -} + &:focus-visible:before { + box-shadow: 0 0 0 2px var(--focused-border-color); + } -.radio-item[data-disabled="true"] { + &[data-state="checked"]:before { + border: 0.25rem solid var(--dim-background-color); + box-shadow: 0 0 0 1px var(--hover-border-color); + background: var(--text-color); + } + + &[data-disabled="true"]:before { opacity: 0.5; cursor: not-allowed; -} \ No newline at end of file + } +} From 2994174110fbb1c4f61987b0fb7c6e54ebbdba2c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 14:37:00 -0500 Subject: [PATCH 15/28] light theme radio group --- preview/src/components/radio_group/style.css | 25 ++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/preview/src/components/radio_group/style.css b/preview/src/components/radio_group/style.css index aa7239a..08b0715 100644 --- a/preview/src/components/radio_group/style.css +++ b/preview/src/components/radio_group/style.css @@ -1,13 +1,14 @@ .radio-group { display: flex; flex-direction: column; - gap: 1.5rem; + gap: .75rem; } .radio-item { display: flex; + flex-direction: row; align-items: center; - gap: 1.5rem; + gap: .75rem; border: none; padding: 0; font-size: 14px; @@ -20,9 +21,8 @@ width: 1rem; height: 1rem; box-sizing: border-box; - border: 0.25rem solid var(--dim-background-color); - box-shadow: 0 0 0 1px var(--hover-border-color); - background: var(--dim-background-color); + box-shadow: 0 0 0 1px var(--dim-border-color); + background: var(--background-color); border-radius: 1.5rem; cursor: pointer; } @@ -36,8 +36,7 @@ } &[data-state="checked"]:before { - border: 0.25rem solid var(--dim-background-color); - box-shadow: 0 0 0 1px var(--hover-border-color); + border: 0.25rem solid var(--background-color); background: var(--text-color); } @@ -46,3 +45,15 @@ cursor: not-allowed; } } + +@media (prefers-color-scheme: dark) { + .radio-item { + &:before { + background: var(--dim-background-color); + box-shadow: 0 0 0 1px var(--hover-border-color); + } + &[data-state="checked"]:before { + border: 0.25rem solid var(--dim-background-color); + } + } +} From 8c83ba58d680267a94bf2fabd5ada74bd56034dc Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 14:48:13 -0500 Subject: [PATCH 16/28] scroll area styling --- preview/src/components/radio_group/mod.rs | 6 - preview/src/components/scroll_area/mod.rs | 49 ++----- preview/src/components/scroll_area/style.css | 135 ------------------- 3 files changed, 11 insertions(+), 179 deletions(-) diff --git a/preview/src/components/radio_group/mod.rs b/preview/src/components/radio_group/mod.rs index 6b28b3b..d8e44d9 100644 --- a/preview/src/components/radio_group/mod.rs +++ b/preview/src/components/radio_group/mod.rs @@ -2,7 +2,6 @@ use dioxus::prelude::*; use dioxus_primitives::radio_group::{RadioGroup, RadioItem}; #[component] pub(super) fn Demo() -> Element { - let mut value = use_signal(|| String::from("option1")); rsx! { document::Link { rel: "stylesheet", @@ -10,10 +9,6 @@ pub(super) fn Demo() -> Element { } RadioGroup { class: "radio-group", - value, - on_value_change: move |new_value| { - value.set(new_value); - }, RadioItem { class: "radio-item", value: "option1".to_string(), @@ -34,6 +29,5 @@ pub(super) fn Demo() -> Element { "Green" } } - div { style: "margin-top: 1rem;", "Selected value: {value()}" } } } diff --git a/preview/src/components/scroll_area/mod.rs b/preview/src/components/scroll_area/mod.rs index 5294066..07eeb87 100644 --- a/preview/src/components/scroll_area/mod.rs +++ b/preview/src/components/scroll_area/mod.rs @@ -7,44 +7,17 @@ pub(super) fn Demo() -> Element { rel: "stylesheet", href: asset!("/src/components/scroll_area/style.css"), } - div { class: "scroll-area-demo", - div { class: "scroll-demo-section", - h3 { "Vertical Scroll" } - ScrollArea { - class: "demo-scroll-area", - direction: ScrollDirection::Vertical, - div { class: "scroll-content", - for i in 1..=20 { - p { "Scrollable content item {i}" } - } - } - } - } - div { class: "scroll-demo-section", - h3 { "Horizontal Scroll" } - ScrollArea { - class: "demo-scroll-area", - direction: ScrollDirection::Horizontal, - div { class: "scroll-content-horizontal", - for i in 1..=20 { - span { "Column {i} " } - } - } - } - } - div { class: "scroll-demo-section", - h3 { "Both Directions" } - ScrollArea { - class: "demo-scroll-area", - direction: ScrollDirection::Both, - div { class: "scroll-content-both", - for i in 1..=20 { - div { - for j in 1..=20 { - span { "Cell {i},{j} " } - } - } - } + ScrollArea { + width: "10em", + height: "10em", + border: "1px solid var(--dim-border-color)", + border_radius: "0.5em", + padding: "0 1em 1em 1em", + direction: ScrollDirection::Vertical, + div { class: "scroll-content", + for i in 1..=20 { + p { + "Scrollable content item {i}" } } } diff --git a/preview/src/components/scroll_area/style.css b/preview/src/components/scroll_area/style.css index e243f48..e69de29 100644 --- a/preview/src/components/scroll_area/style.css +++ b/preview/src/components/scroll_area/style.css @@ -1,135 +0,0 @@ -.scroll-area-demo { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - padding: 2em; - width: 35rem; - max-width: 100%; -} - -.scroll-demo-section { - max-width: 30rem; - max-height: 30rem; - margin-bottom: 30px; -} - -.scroll-demo-section h3 { - margin-bottom: 10px; - color: var(--text-color); -} - -.demo-scroll-area { - border: 1px solid var(--dim-border-color); - border-radius: 4px; - background: var(--background-color); -} - -/* Vertical scroll example */ -.demo-scroll-area[data-scroll-direction="vertical"] { - height: 20rem; - width: auto; -} - -.scroll-content { - padding: 10px; -} - -.scroll-content p { - margin: 8px 0; - padding: 8px; - background: var(--brighter-background-color); - border-radius: 4px; -} - -/* Horizontal scroll example */ -.demo-scroll-area[data-scroll-direction="horizontal"] { - height: auto; - width: 20rem; -} - -.scroll-content-horizontal { - padding: 10px; - white-space: nowrap; -} - -.scroll-content-horizontal span { - display: inline-block; - margin: 0 4px; - padding: 8px 16px; - background: var(--brighter-background-color); - border-radius: 4px; -} - -/* Both directions example */ -.demo-scroll-area[data-scroll-direction="both"] { - height: 20rem; - width: 20rem; -} - -.scroll-content-both { - padding: 10px; - white-space: nowrap; -} - -.scroll-content-both div { - margin: 4px 0; -} - -.scroll-content-both span { - display: inline-block; - margin: 0 4px; - padding: 8px; - background: var(--brighter-background-color); - border-radius: 4px; - min-width: 80px; - text-align: center; -} - -/* Scrollbar styles */ -.scroll-area-auto-hide { - scrollbar-width: thin; - scrollbar-color: rgba(0, 0, 0, 0.3) transparent; -} - -.scroll-area-auto-hide::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -.scroll-area-auto-hide::-webkit-scrollbar-track { - background: transparent; -} - -.scroll-area-auto-hide::-webkit-scrollbar-thumb { - background-color: rgba(0, 0, 0, 0.3); - border-radius: 4px; -} - -.scroll-area-auto-hide::-webkit-scrollbar-corner { - background: transparent; -} - -.scroll-area-always-show { - scrollbar-width: thin; - scrollbar-color: rgba(0, 0, 0, 0.3) rgba(0, 0, 0, 0.1); -} - -.scroll-area-always-show::-webkit-scrollbar { - width: 8px; - height: 8px; -} - -.scroll-area-always-show::-webkit-scrollbar-track { - background: rgba(0, 0, 0, 0.1); -} - -.scroll-area-always-show::-webkit-scrollbar-thumb { - background-color: rgba(0, 0, 0, 0.3); - border-radius: 4px; -} - -.scroll-area-always-show::-webkit-scrollbar-corner { - background: rgba(0, 0, 0, 0.1); -} \ No newline at end of file From ab9807181eba8d4980f23110b67b18ef05003c28 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 16:26:41 -0500 Subject: [PATCH 17/28] partially styled select --- .../src/components/dropdown_menu/style.css | 3 +- preview/src/components/radio_group/mod.rs | 1 + preview/src/components/select/mod.rs | 42 ++-- preview/src/components/select/style.css | 185 ++---------------- 4 files changed, 24 insertions(+), 207 deletions(-) diff --git a/preview/src/components/dropdown_menu/style.css b/preview/src/components/dropdown_menu/style.css index 2e1255a..3fa8a24 100644 --- a/preview/src/components/dropdown_menu/style.css +++ b/preview/src/components/dropdown_menu/style.css @@ -51,7 +51,6 @@ } } - .dropdown-menu-content[hidden] { display: none; } @@ -81,7 +80,7 @@ @media (prefers-color-scheme: dark) { .dropdown-menu-item:hover:not([data-disabled="true"]), -.dropdown-menu-item:focus-visible { + .dropdown-menu-item:focus-visible { background: var(--hover-border-color); } } diff --git a/preview/src/components/radio_group/mod.rs b/preview/src/components/radio_group/mod.rs index d8e44d9..d474a82 100644 --- a/preview/src/components/radio_group/mod.rs +++ b/preview/src/components/radio_group/mod.rs @@ -1,5 +1,6 @@ use dioxus::prelude::*; use dioxus_primitives::radio_group::{RadioGroup, RadioItem}; + #[component] pub(super) fn Demo() -> Element { rsx! { diff --git a/preview/src/components/select/mod.rs b/preview/src/components/select/mod.rs index 90f9cb5..c1fb889 100644 --- a/preview/src/components/select/mod.rs +++ b/preview/src/components/select/mod.rs @@ -2,43 +2,23 @@ use dioxus::prelude::*; use dioxus_primitives::select::{Select, SelectGroup, SelectOption}; #[component] pub(super) fn Demo() -> Element { - let mut selected = use_signal(|| None::); - use_effect(move || { - if let Some(value) = selected() { - tracing::info!("Selected value: {value}"); - } - }); rsx! { document::Link { rel: "stylesheet", href: asset!("/src/components/select/style.css"), } - div { class: "select-example", - div { class: "select-container", - label { class: "select-label", "Choose a fruit:" } - Select { - class: "select", - value: selected, - on_value_change: move |value| selected.set(value), - placeholder: "Select a fruit...", - SelectGroup { label: "Fruits".to_string(), - SelectOption { value: "apple".to_string(), "Apple" } - SelectOption { value: "banana".to_string(), "Banana" } - SelectOption { value: "orange".to_string(), "Orange" } - SelectOption { value: "strawberry".to_string(), "Strawberry" } - SelectOption { value: "watermelon".to_string(), "Watermelon" } - } - SelectGroup { label: "Other".to_string(), - SelectOption { value: "other".to_string(), "Other" } - } - } + Select { + class: "select", + placeholder: "Select a fruit...", + SelectGroup { label: "Fruits".to_string(), + SelectOption { value: "apple".to_string(), "Apple" } + SelectOption { value: "banana".to_string(), "Banana" } + SelectOption { value: "orange".to_string(), "Orange" } + SelectOption { value: "strawberry".to_string(), "Strawberry" } + SelectOption { value: "watermelon".to_string(), "Watermelon" } } - div { class: "selected-value", - if let Some(value) = selected() { - "Selected: {value}" - } else { - "No selection" - } + SelectGroup { label: "Other".to_string(), + SelectOption { value: "other".to_string(), "Other" } } } } diff --git a/preview/src/components/select/style.css b/preview/src/components/select/style.css index 2e4b4ba..79edb62 100644 --- a/preview/src/components/select/style.css +++ b/preview/src/components/select/style.css @@ -5,188 +5,25 @@ max-width: 300px; padding: 8px 16px; color: var(--text-color); - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; + box-shadow: inset 0 0 0 1px var(--dim-border-color); + border: none; + border-radius: 0.5rem; + border-radius: 0.5rem; cursor: pointer; font-size: 14px; transition: all 0.2s ease; appearance: none; -} - -.select-label { - display: block; - margin-bottom: 8px; - font-size: 14px; - font-weight: 500; - color: var(--dim-text-color); -} - -.select-trigger { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - padding: 10px 12px; - background-color: var(--background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - font-size: 14px; - text-align: left; - cursor: pointer; - transition: border-color 0.2s, box-shadow 0.2s; -} - -.select-trigger:hover { - border-color: var(--hover-border-color); -} - -.select-trigger:focus { - outline: none; - border-color: #0066cc; - box-shadow: 0 0 0 2px rgba(0, 102, 204, 0.2); -} - -.select-trigger[data-state="open"] { - border-color: #0066cc; -} - -.select-trigger[data-disabled="true"] { - opacity: 0.5; - cursor: not-allowed; -} - -.select-placeholder { - color: var(--text-color); -} - -.select-value { - color: var(--text-color); -} - -.select-icon { - margin-left: 8px; - color: var(--text-color); - transition: transform 0.2s; -} - -.select-trigger[data-state="open"] .select-icon { - transform: rotate(180deg); -} - -.select-content { position: absolute; - left: 0; - width: 100%; - max-height: 200px; - overflow-y: auto; - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); - z-index: 100; - margin-top: 4px; -} - -.select-content[data-position="top"] { - bottom: 100%; - margin-bottom: 4px; - margin-top: 0; -} - -.select-group { - padding: 5px 0; -} - -.select-item { - display: flex; align-items: center; - justify-content: space-between; - padding: 8px 12px; - font-size: 14px; - cursor: pointer; - transition: background-color 0.2s; -} - -.select-item:hover { - background-color: var(--hover-background-color); -} - -.select-item:focus { - outline: none; - background-color: var(--focused-background-color); -} - -.select-item[data-highlighted="true"] { - background-color: var(--focused-background-color); -} - -.select-item[data-state="selected"] { - font-weight: 500; -} - -.select-item[data-disabled="true"] { - opacity: 0.5; - cursor: not-allowed; -} - -.select-item-indicator { - color: #0066cc; - margin-left: 8px; -} - -.select-separator { - height: 1px; - background-color: var(--dim-border-color); - margin: 5px 0; -} - -/* Animation */ -@keyframes slideDown { - from { - opacity: 0; - transform: translateY(-10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -@keyframes slideUp { - from { - opacity: 0; - transform: translateY(10px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - -.select-content[data-state="open"][data-position="bottom"] { - animation: slideDown 0.2s ease-out; -} - -.select-content[data-state="open"][data-position="top"] { - animation: slideUp 0.2s ease-out; -} - -/* Example specific styles */ -.select-example { - padding: 20px; - max-width: 500px; - margin: 0 auto; } -.select-container { - margin-bottom: 20px; +.select:not([aria-activedescendant]) { + color: var(--muted-text-color); } -.selected-value { - margin-top: 20px; - padding: 10px; - background-color: var(--brighter-background-color); - border-radius: 4px; - font-size: 14px; +@media (prefers-color-scheme: dark) { + .select { + background-color: var(--dim-background-color); + background-color: var(--dim-background-color); + } } From 5b1d76a39087f2c653213086abb1c709f3f1bac6 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 16:42:53 -0500 Subject: [PATCH 18/28] style slider --- preview/src/components/progress/style.css | 3 +- preview/src/components/slider/mod.rs | 33 ++++--------------- preview/src/components/slider/style.css | 40 +++++------------------ 3 files changed, 15 insertions(+), 61 deletions(-) diff --git a/preview/src/components/progress/style.css b/preview/src/components/progress/style.css index 8c6a9e1..46cd8dc 100644 --- a/preview/src/components/progress/style.css +++ b/preview/src/components/progress/style.css @@ -1,7 +1,7 @@ .progress { position: relative; overflow: hidden; - background: var(--hover-border-color); + background: var(--focused-background-color); border-radius: 9999px; width: 200px; height: .5rem; @@ -24,7 +24,6 @@ 0% { transform: translateX(-100%); } - 100% { transform: translateX(200%); } diff --git a/preview/src/components/slider/mod.rs b/preview/src/components/slider/mod.rs index 140215c..491ab47 100644 --- a/preview/src/components/slider/mod.rs +++ b/preview/src/components/slider/mod.rs @@ -4,38 +4,17 @@ use dioxus_primitives::slider::{ }; #[component] pub(super) fn Demo() -> Element { - let mut value = use_signal(|| SliderValue::Single(50.0)); rsx! { document::Link { rel: "stylesheet", href: asset!("/src/components/slider/style.css"), } - div { class: "slider-example", - div { - label { "Single Value Slider" } - div { style: "display: flex; flex-wrap: wrap; align-items: center; gap: 1rem;", - Slider { - class: "slider", - value, - horizontal: true, - on_value_change: move |v| { - value.set(v); - }, - SliderTrack { class: "slider-track", - SliderRange { class: "slider-range" } - SliderThumb { class: "slider-thumb" } - } - } - input { - class: "slider-value", - r#type: "text", - readonly: true, - value: match value() { - SliderValue::Single(v) => format!("{v:.1}"), - _ => String::new(), - }, - } - } + Slider { + class: "slider", + horizontal: true, + SliderTrack { class: "slider-track", + SliderRange { class: "slider-range" } + SliderThumb { class: "slider-thumb" } } } } diff --git a/preview/src/components/slider/style.css b/preview/src/components/slider/style.css index 552c1ec..c06e9a7 100644 --- a/preview/src/components/slider/style.css +++ b/preview/src/components/slider/style.css @@ -1,16 +1,3 @@ -.slider-example { - display: flex; - flex-direction: column; - gap: 2rem; - padding: 2rem; -} - -.slider-example>div { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - .slider { position: relative; display: flex; @@ -29,9 +16,10 @@ .slider-track { position: relative; flex-grow: 1; - background-color: rgba(100, 116, 139, 0.1); + background: var(--focused-background-color); border-radius: 9999px; - height: 4px; + height: .5rem; + box-sizing: border-box; } .slider[data-orientation="vertical"] .slider-track { @@ -56,9 +44,8 @@ width: 16px; height: 16px; background-color: var(--brighter-background-color); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); border-radius: 50%; - border: 2px solid var(--contrast-background-color); + border: 1px solid var(--contrast-background-color); position: absolute; top: 50%; transform: translate(-50%, -50%); @@ -71,13 +58,11 @@ transform: translate(-50%, 50%); } +.slider-thumb:focus-visible[data-dragging="true"], +.slider-thumb:focus-visible, .slider-thumb:hover { - border-color: var(--hover-border-color); -} - -.slider-thumb:focus-visible { - outline: 2px solid var(--focused-border-color); - outline-offset: 2px; + box-shadow: 0 0 0 4px color-mix(in oklab, var(--hover-border-color) 50%,transparent); + transition: box-shadow 150ms; } .slider[data-disabled="true"] { @@ -88,12 +73,3 @@ .slider[data-disabled="true"] .slider-thumb { cursor: not-allowed; } - -.slider-value { - font-size: 14px; - color: var(--text-color); - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - padding: 0.25rem 0.5rem; -} From b1472e3e8424b87f6ae8c4d01e670cdf2a5c287c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 16:52:04 -0500 Subject: [PATCH 19/28] style switch --- preview/src/components/switch/style.css | 30 ++++++++++++++++--------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/preview/src/components/switch/style.css b/preview/src/components/switch/style.css index 488559b..2630a2f 100644 --- a/preview/src/components/switch/style.css +++ b/preview/src/components/switch/style.css @@ -7,9 +7,9 @@ .switch { all: unset; - width: 42px; - height: 25px; - background-color: var(--background-color); + width: 2rem; + height: 1.15rem; + background-color: var(--dim-border-color); border-radius: 9999px; position: relative; transition: background-color 150ms; @@ -22,19 +22,29 @@ .switch-thumb { display: block; - width: 21px; - height: 21px; - background-color: var(--contrast-background-color); + width: calc(1.15rem - 2px); + height: calc(1.15rem - 2px); + background-color: var(--background-color); border-radius: 9999px; - box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1); transition: transform 150ms; - transform: translateX(2px); + transform: translateX(1px); will-change: transform; } +@media (prefers-color-scheme: dark) { + .switch-thumb { + background-color: var(--contrast-background-color); + } +} + .switch[data-state="checked"] .switch-thumb { - transform: translateX(19px); - background-color: var(--background-color); + transform: translateX(calc(2rem - 1px - (1.15rem - 2px))); +} + +@media (prefers-color-scheme: dark) { + .switch[data-state="checked"] .switch-thumb { + background-color: var(--dim-background-color); + } } /* Only apply disabled styles when data-disabled is "true" */ From 58217a0cbbcce942c48ca7f4b534149f4cf7450c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Thu, 5 Jun 2025 16:54:29 -0500 Subject: [PATCH 20/28] clean up formatting --- preview/src/components/select/style.css | 31 ++++++------- preview/src/components/slider/mod.rs | 5 +- preview/src/components/switch/style.css | 62 ++++++++++++------------- 3 files changed, 48 insertions(+), 50 deletions(-) diff --git a/preview/src/components/select/style.css b/preview/src/components/select/style.css index 79edb62..f27640d 100644 --- a/preview/src/components/select/style.css +++ b/preview/src/components/select/style.css @@ -1,24 +1,23 @@ /* Select Styles */ .select { - position: relative; - width: 100%; - max-width: 300px; - padding: 8px 16px; - color: var(--text-color); - box-shadow: inset 0 0 0 1px var(--dim-border-color); - border: none; - border-radius: 0.5rem; - border-radius: 0.5rem; - cursor: pointer; - font-size: 14px; - transition: all 0.2s ease; - appearance: none; - position: absolute; - align-items: center; + position: relative; + max-width: 300px; + padding: 8px 16px; + color: var(--text-color); + box-shadow: inset 0 0 0 1px var(--dim-border-color); + border: none; + border-radius: 0.5rem; + border-radius: 0.5rem; + cursor: pointer; + font-size: 14px; + transition: all 0.2s ease; + appearance: none; + position: absolute; + align-items: center; } .select:not([aria-activedescendant]) { - color: var(--muted-text-color); + color: var(--muted-text-color); } @media (prefers-color-scheme: dark) { diff --git a/preview/src/components/slider/mod.rs b/preview/src/components/slider/mod.rs index 491ab47..3196747 100644 --- a/preview/src/components/slider/mod.rs +++ b/preview/src/components/slider/mod.rs @@ -1,7 +1,6 @@ use dioxus::prelude::*; -use dioxus_primitives::slider::{ - Slider, SliderRange, SliderThumb, SliderTrack, SliderValue, -}; +use dioxus_primitives::slider::{Slider, SliderRange, SliderThumb, SliderTrack}; + #[component] pub(super) fn Demo() -> Element { rsx! { diff --git a/preview/src/components/switch/style.css b/preview/src/components/switch/style.css index 2630a2f..e06b0fa 100644 --- a/preview/src/components/switch/style.css +++ b/preview/src/components/switch/style.css @@ -1,54 +1,54 @@ .switch-example { - display: flex; - align-items: center; - gap: 15px; - padding: 20px; + display: flex; + align-items: center; + gap: 15px; + padding: 20px; } .switch { - all: unset; - width: 2rem; - height: 1.15rem; - background-color: var(--dim-border-color); - border-radius: 9999px; - position: relative; - transition: background-color 150ms; - cursor: pointer; + all: unset; + width: 2rem; + height: 1.15rem; + background-color: var(--dim-border-color); + border-radius: 9999px; + position: relative; + transition: background-color 150ms; + cursor: pointer; } .switch[data-state="checked"] { - background-color: var(--contrast-background-color); + background-color: var(--contrast-background-color); } .switch-thumb { - display: block; - width: calc(1.15rem - 2px); - height: calc(1.15rem - 2px); - background-color: var(--background-color); - border-radius: 9999px; - transition: transform 150ms; - transform: translateX(1px); - will-change: transform; + display: block; + width: calc(1.15rem - 2px); + height: calc(1.15rem - 2px); + background-color: var(--background-color); + border-radius: 9999px; + transition: transform 150ms; + transform: translateX(1px); + will-change: transform; } @media (prefers-color-scheme: dark) { - .switch-thumb { - background-color: var(--contrast-background-color); - } + .switch-thumb { + background-color: var(--contrast-background-color); + } } .switch[data-state="checked"] .switch-thumb { - transform: translateX(calc(2rem - 1px - (1.15rem - 2px))); + transform: translateX(calc(2rem - 1px - (1.15rem - 2px))); } @media (prefers-color-scheme: dark) { - .switch[data-state="checked"] .switch-thumb { - background-color: var(--dim-background-color); - } + .switch[data-state="checked"] .switch-thumb { + background-color: var(--dim-background-color); + } } /* Only apply disabled styles when data-disabled is "true" */ .switch[data-disabled="true"] { - opacity: 0.5; - cursor: not-allowed; -} \ No newline at end of file + opacity: 0.5; + cursor: not-allowed; +} From db6d5c44e610b7954c9d5edb5476bf5d2f2ab8e7 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 6 Jun 2025 12:50:58 -0500 Subject: [PATCH 21/28] tab styling --- preview/src/components/tabs/mod.rs | 34 +++++++++++- preview/src/components/tabs/style.css | 80 ++++++++++++++++----------- preview/src/main.rs | 62 +++++++++++++++------ 3 files changed, 124 insertions(+), 52 deletions(-) diff --git a/preview/src/components/tabs/mod.rs b/preview/src/components/tabs/mod.rs index 53ea055..aef304c 100644 --- a/preview/src/components/tabs/mod.rs +++ b/preview/src/components/tabs/mod.rs @@ -8,6 +8,7 @@ pub(super) fn Demo() -> Element { class: "tabs", default_value: "tab1".to_string(), horizontal: true, + max_width: "16rem", div { class: "tabs-list", TabTrigger { class: "tabs-trigger", @@ -28,9 +29,36 @@ pub(super) fn Demo() -> Element { "Tab 3" } } - TabContent { class: "tabs-content", value: "tab1".to_string(), "Tab 1 Content" } - TabContent { class: "tabs-content", value: "tab2".to_string(), "Tab 2 Content" } - TabContent { class: "tabs-content", value: "tab3".to_string(), "Tab 3 Content" } + TabContent { class: "tabs-content", value: "tab1".to_string(), + div { + width: "100%", + height: "5rem", + display: "flex", + align_items: "center", + justify_content: "center", + "Tab 1 Content" + } + } + TabContent { class: "tabs-content", value: "tab2".to_string(), + div { + width: "100%", + height: "5rem", + display: "flex", + align_items: "center", + justify_content: "center", + "Tab 2 Content" + } + } + TabContent { class: "tabs-content", value: "tab3".to_string(), + div { + width: "100%", + height: "5rem", + display: "flex", + align_items: "center", + justify_content: "center", + "Tab 3 Content" + } + } } } } diff --git a/preview/src/components/tabs/style.css b/preview/src/components/tabs/style.css index 3532451..3d8a5fb 100644 --- a/preview/src/components/tabs/style.css +++ b/preview/src/components/tabs/style.css @@ -2,62 +2,78 @@ width: 100%; display: flex; flex-direction: column; - background: var(--background-color); + gap: .5rem; } .tabs-list { display: flex; - /* border-style: solid; - border-color: var(--dim-border-color); - border-width: 1px 0px 1px 1px; */ -} - -.tabs-trigger { - all: unset; - width: 100%; - display: flex; - align-items: center; - justify-content: center; - padding: 8px 16px; - font-size: 14px; - color: var(--text-color); - cursor: pointer; - border-left: 1px solid var(--dim-border-color); - border-bottom: 1px solid var(--dim-border-color); - transition: background-color 0.2s; + flex-direction: row; + flex: 1; + gap: .25rem; + width: fit-content; + padding: .25rem; + border: none; + border-radius: .5rem; + background: var(--dim-background-color); box-sizing: border-box; } -.tabs-trigger:first-child { - border-left: none; +@media (prefers-color-scheme: dark) { + .tabs-list { + background: var(--focused-background-color); + } } -.tabs-trigger:hover { - color: var(--hover-text-color); - background: var(--hover-background-color); +.tabs-trigger { + padding: 4px 8px; + border: none; + background: none; + cursor: pointer; + color: var(--muted-text-color); + border-radius: calc(.5rem - .25rem); } .tabs-trigger[data-state="active"] { - color: var(--text-color); - border-bottom: none; + color: var(--bright-text-color); + background-color: var(--background-color); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18); } -.tabs-trigger:focus-visible { - outline: 2px solid #3b82f6; - outline-offset: -2px; +@media (prefers-color-scheme: dark) { + .tabs-trigger[data-state="active"] { + box-shadow: inset 0 0 0 1px var(--hover-border-color); + background-color: var(--dim-border-color); + } } .tabs-trigger[data-disabled="true"] { - opacity: 0.5; + color: var(--muted-text-color); cursor: not-allowed; } +.tabs-trigger:hover:not([data-disabled="true"]), +.tabs-trigger:focus-visible { + color: var(--dim-text-color); +} + .tabs-content { - padding: 16px; - font-size: 14px; + width: 100%; + background: var(--background-color); + border-radius: .5rem; + padding: .25rem; + border: 1px solid var(--dim-border-color); + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18); box-sizing: border-box; } +@media (prefers-color-scheme: dark) { + .tabs-content { + border: none; + background: var(--dim-background-color); + box-shadow: inset 0 0 0 1px var(--hover-border-color); + } +} + .tabs-content[data-state="inactive"] { display: none; } diff --git a/preview/src/main.rs b/preview/src/main.rs index 73c2242..5abef96 100644 --- a/preview/src/main.rs +++ b/preview/src/main.rs @@ -119,6 +119,48 @@ fn CopyIcon() -> Element { fn ComponentCode(rs_highlighted: HighlightedCode, css_highlighted: HighlightedCode) -> Element { let mut collapsed = use_signal(|| true); + let expand = rsx!{ + button { + width: "100%", + height: "2rem", + color: "var(--text-color)", + background_color: "rgba(0, 0, 0, 0)", + border_radius: "0 0 0.5rem 0.5rem", + border: "none", + text_align: "center", + onclick: move |_| { + collapsed.toggle(); + }, + if collapsed() { + svg { + fill: "none", + xmlns: "http://www.w3.org/2000/svg", + stroke: "var(--text-color)", + stroke_linecap: "round", + stroke_linejoin: "round", + stroke_width: "2", + width: "20px", + height: "20px", + view_box: "0 0 24 24", + polyline { points: "6 9 12 15 18 9" } + } + } else { + svg { + fill: "none", + xmlns: "http://www.w3.org/2000/svg", + stroke: "var(--text-color)", + stroke_linecap: "round", + stroke_linejoin: "round", + stroke_width: "2", + width: "20px", + height: "20px", + view_box: "0 0 24 24", + polyline { points: "6 15 12 9 18 15" } + } + } + } + }; + rsx! { Tabs { class: "tabs", @@ -126,6 +168,7 @@ fn ComponentCode(rs_highlighted: HighlightedCode, css_highlighted: HighlightedCo border_bottom_left_radius: "0.5rem", border_bottom_right_radius: "0.5rem", horizontal: true, + width: "100%", div { class: "tabs-list", TabTrigger { class: "tabs-trigger", value: "main.rs", index: 0usize, "main.rs" } TabTrigger { @@ -148,6 +191,7 @@ fn ComponentCode(rs_highlighted: HighlightedCode, css_highlighted: HighlightedCo width: "100%", position: "relative", CodeBlock { source: rs_highlighted, collapsed: collapsed() } + {expand.clone()} } TabContent { class: "tabs-content", @@ -155,23 +199,7 @@ fn ComponentCode(rs_highlighted: HighlightedCode, css_highlighted: HighlightedCo width: "100%", position: "relative", CodeBlock { source: css_highlighted, collapsed: collapsed() } - } - button { - width: "100%", - height: "2rem", - color: "var(--text-color)", - background_color: "rgba(0, 0, 0, 0)", - border_radius: "0 0 0.5rem 0.5rem", - border: "none", - text_align: "center", - onclick: move |_| { - collapsed.toggle(); - }, - if collapsed() { - "↓" - } else { - "↑" - } + {expand} } } } From e9f6374a5abbe65912fa305bcde629a124d9e797 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 6 Jun 2025 13:10:27 -0500 Subject: [PATCH 22/28] style toggle group --- preview/assets/main.css | 2 ++ preview/src/components/toggle_group/mod.rs | 8 ++++---- preview/src/components/toggle_group/style.css | 14 +++++++++++--- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index bb340fc..f7e6add 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -15,6 +15,7 @@ --dim-background-color: #F8F8F8; --hover-background-color: #f5f5f5; --hover-border-color: #b0b0b0; + --hover-border-color-more: #d0d0d0; --focused-background-color: #f5f5f5; --contrast-background-color: #0d0d0d; --bright-text-color: #000; @@ -45,6 +46,7 @@ --dim-background-color: #141313; --hover-background-color: #1a1a1a; --hover-border-color: #3E3E3E; + --hover-border-color-more: #5D5D5D; --focused-background-color: #262626; --contrast-background-color: #e6e6e6; --bright-text-color: #fAfAfA; diff --git a/preview/src/components/toggle_group/mod.rs b/preview/src/components/toggle_group/mod.rs index a86442c..a2a30b3 100644 --- a/preview/src/components/toggle_group/mod.rs +++ b/preview/src/components/toggle_group/mod.rs @@ -7,10 +7,10 @@ pub(super) fn Demo() -> Element { rel: "stylesheet", href: asset!("/src/components/toggle_group/style.css"), } - ToggleGroup { class: "toggle-group", horizontal: true, - ToggleItem { class: "toggle-item", index: 0usize, "Align Left" } - ToggleItem { class: "toggle-item", index: 1usize, "Align Middle" } - ToggleItem { class: "toggle-item", index: 2usize, "Align Right" } + ToggleGroup { class: "toggle-group", horizontal: true, allow_multiple_pressed: true, + ToggleItem { class: "toggle-item", index: 0usize, em { "B" } } + ToggleItem { class: "toggle-item", index: 1usize, i { "I" } } + ToggleItem { class: "toggle-item", index: 2usize, u { "U" } } } } } diff --git a/preview/src/components/toggle_group/style.css b/preview/src/components/toggle_group/style.css index 0861855..3d106d9 100644 --- a/preview/src/components/toggle_group/style.css +++ b/preview/src/components/toggle_group/style.css @@ -11,11 +11,12 @@ padding: 10px; min-width: 35px; color: var(--text-color); - background-color: var(--brighter-background-color); + background-color: var(--background-color); transition: background-color 200ms ease, border 200ms ease; border-top: 1px solid var(--dim-border-color); + border-right: 1px solid var(--dim-border-color); border-bottom: 1px solid var(--dim-border-color); } @@ -25,7 +26,14 @@ } .toggle-item[data-state="on"] { - background-color: var(--focused-background-color); + color: var(--bright-text-color); + background-color: var(--hover-border-color); + border-top: 1px solid var(--hover-border-color-more); + border-right: 1px solid var(--hover-border-color-more); + border-bottom: 1px solid var(--hover-border-color-more); +} +.toggle-item:first-child[data-state="on"] { + border: 1px solid var(--hover-border-color-more); } .toggle-item:first-child { @@ -38,6 +46,6 @@ border-bottom-right-radius: 10px; } -.toggle-item:first-child, .toggle-item:last-child { +.toggle-item:first-child { border: 1px solid var(--dim-border-color); } \ No newline at end of file From d49263a3123be4488917daae73b077a55c5df036 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 6 Jun 2025 13:36:20 -0500 Subject: [PATCH 23/28] style toolbar --- preview/src/components/toolbar/mod.rs | 100 +++++++++++------------ preview/src/components/toolbar/style.css | 69 ++++++---------- 2 files changed, 72 insertions(+), 97 deletions(-) diff --git a/preview/src/components/toolbar/mod.rs b/preview/src/components/toolbar/mod.rs index 13ee119..73f689f 100644 --- a/preview/src/components/toolbar/mod.rs +++ b/preview/src/components/toolbar/mod.rs @@ -16,78 +16,70 @@ pub(super) fn Demo() -> Element { let mut set_align = move |align: &str| { text_align.set(align.to_string()); }; - let text_classes = use_memo(move || { + let text_styles = use_memo(move || { let mut classes = Vec::new(); for style in text_style() { match style.as_str() { - "bold" => classes.push("toolbar-bold"), - "italic" => classes.push("toolbar-italic"), - "underline" => classes.push("toolbar-underline"), + "bold" => classes.push("font-weight: bold;"), + "italic" => classes.push("font-style: italic;"), + "underline" => classes.push("text-decoration: underline;"), _ => {} } } classes.join(" ") }); - let text_align_style = use_memo(move || format!("text-align: {};", text_align())); + let text_align_style = + use_memo(move || format!("text-align: {}; {}", text_align(), text_styles())); rsx! { document::Link { rel: "stylesheet", href: asset!("/src/components/toolbar/style.css"), } - div { class: "toolbar-example", - h3 { - width: "100%", - text_align: "center", - "Text Formatting Toolbar" - } - Toolbar { class: "toolbar", aria_label: "Text formatting", - div { class: "toolbar-group", - ToolbarButton { - class: "toolbar-button", - index: 0usize, - on_click: move |_| toggle_style("bold"), - "Bold" - } - ToolbarButton { - class: "toolbar-button", - index: 1usize, - on_click: move |_| toggle_style("italic"), - "Italic" - } - ToolbarButton { - class: "toolbar-button", - index: 2usize, - on_click: move |_| toggle_style("underline"), - "Underline" - } + Toolbar { class: "toolbar", aria_label: "Text formatting", + div { class: "toolbar-group", + ToolbarButton { + class: "toolbar-button", + index: 0usize, + on_click: move |_| toggle_style("bold"), + "Bold" + } + ToolbarButton { + class: "toolbar-button", + index: 1usize, + on_click: move |_| toggle_style("italic"), + "Italic" } - ToolbarSeparator { class: "toolbar-separator" } - div { class: "toolbar-group", - ToolbarButton { - class: "toolbar-button", - index: 3usize, - on_click: move |_| set_align("left"), - "Align Left" - } - ToolbarButton { - class: "toolbar-button", - index: 4usize, - on_click: move |_| set_align("center"), - "Align Center" - } - ToolbarButton { - class: "toolbar-button", - index: 5usize, - on_click: move |_| set_align("right"), - "Align Right" - } + ToolbarButton { + class: "toolbar-button", + index: 2usize, + on_click: move |_| toggle_style("underline"), + "Underline" } } - div { class: "toolbar-content", - p { class: text_classes, style: text_align_style, - "This is a sample text that will be formatted according to the toolbar buttons you click. Try clicking the buttons above to see how the text formatting changes." + ToolbarSeparator { class: "toolbar-separator" } + div { class: "toolbar-group", + ToolbarButton { + class: "toolbar-button", + index: 3usize, + on_click: move |_| set_align("left"), + "Align Left" + } + ToolbarButton { + class: "toolbar-button", + index: 4usize, + on_click: move |_| set_align("center"), + "Align Center" + } + ToolbarButton { + class: "toolbar-button", + index: 5usize, + on_click: move |_| set_align("right"), + "Align Right" } } } + p { style: text_align_style, max_width: "30rem", + "This is a sample text that will be formatted according to the toolbar buttons you click. Try clicking the buttons above to see how the text formatting changes." + } } } diff --git a/preview/src/components/toolbar/style.css b/preview/src/components/toolbar/style.css index 37209cc..e841086 100644 --- a/preview/src/components/toolbar/style.css +++ b/preview/src/components/toolbar/style.css @@ -1,26 +1,17 @@ -.toolbar-example { - width: 35rem; - max-width: 100%; - margin: 20px; - padding: 10px; - border: 1px solid var(--dim-border-color); - border-radius: .5em; - background-color: var(--background-color); -} - .toolbar { display: flex; flex-wrap: wrap; flex-direction: row; align-items: center; justify-content: space-between; - gap: 5px; - padding: 5px; - background-color: var(--brighter-background-color); - border-radius: 4px; + border: none; + box-shadow: inset 0 0 0 1px var(--dim-border-color); + gap: .25rem; + padding: .25rem; + border-radius: .5rem; } -.toolbar button { +/* .toolbar button { padding: 8px 12px; border: 1px solid var(--dim-border-color); border-radius: 4px; @@ -28,19 +19,32 @@ background-color: var(--background-color); cursor: pointer; font-size: 14px; -} +} */ -.toolbar button:hover { - background-color: var(--hover-background-color); +.toolbar button { + padding: 8px 12px; + border: none; + background: none; + cursor: pointer; + color: var(--text-color); + border-radius: calc(.5rem - .25rem); } -.toolbar button:focus { - outline: 2px solid #0066cc; - outline-offset: 2px; +.toolbar button:hover:not([disabled]), +.toolbar button:focus-visible { + color: var(--bright-text-color); + background: var(--hover-background-color); +} +@media (prefers-color-scheme: dark) { + .toolbar button:hover:not([disabled]), + .toolbar button:focus-visible { + background: var(--hover-border-color); + } } + .toolbar button:disabled { - opacity: 0.5; + color: var(--muted-text-color); cursor: not-allowed; } @@ -57,28 +61,7 @@ margin: 0 5px; } -.toolbar-content { - margin-top: 20px; - padding: 20px; - border: 1px solid var(--dim-border-color); - border-radius: 4px; - background-color: var(--background-color); -} - .toolbar-content p { margin: 0; padding: 0; } - -/* For text formatting buttons */ -.toolbar-bold { - font-weight: bold; -} - -.toolbar-italic { - font-style: italic; -} - -.toolbar-underline { - text-decoration: underline; -} From 1044e304fe6404966f150a922684701827afb8bb Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 6 Jun 2025 13:38:13 -0500 Subject: [PATCH 24/28] clean up toolbar example code --- preview/src/components/toolbar/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/preview/src/components/toolbar/mod.rs b/preview/src/components/toolbar/mod.rs index 73f689f..ec41723 100644 --- a/preview/src/components/toolbar/mod.rs +++ b/preview/src/components/toolbar/mod.rs @@ -5,13 +5,9 @@ pub(super) fn Demo() -> Element { let mut text_style = use_signal(Vec::new); let mut text_align = use_signal(|| String::from("left")); let mut toggle_style = move |style: &str| { - let mut current_styles = text_style(); - if current_styles.contains(&style.to_string()) { - current_styles.retain(|s| s != style); - } else { - current_styles.push(style.to_string()); - } - text_style.set(current_styles); + let mut current_styles = text_style.write(); + current_styles.retain(|s| s != style); + current_styles.push(style.to_string()); }; let mut set_align = move |align: &str| { text_align.set(align.to_string()); From 86bb2fc9448148f2a2fc175f2136aa1db83bf9ae Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 6 Jun 2025 14:08:14 -0500 Subject: [PATCH 25/28] style tooltip --- preview/src/components/tooltip/mod.rs | 35 ++--- preview/src/components/tooltip/style.css | 166 ++++++++++++++--------- 2 files changed, 110 insertions(+), 91 deletions(-) diff --git a/preview/src/components/tooltip/mod.rs b/preview/src/components/tooltip/mod.rs index 5b80429..a04d46f 100644 --- a/preview/src/components/tooltip/mod.rs +++ b/preview/src/components/tooltip/mod.rs @@ -1,5 +1,5 @@ use dioxus::prelude::*; -use dioxus_primitives::tooltip::{Tooltip, TooltipContent, TooltipSide, TooltipTrigger}; +use dioxus_primitives::tooltip::{Tooltip, TooltipContent, TooltipTrigger}; #[component] pub(super) fn Demo() -> Element { rsx! { @@ -7,31 +7,16 @@ pub(super) fn Demo() -> Element { rel: "stylesheet", href: asset!("/src/components/tooltip/style.css"), } - div { - class: "tooltip-example", - style: "padding: 50px; display: flex; gap: 20px;", - Tooltip { class: "tooltip", - TooltipTrigger { class: "tooltip-trigger", - button { "Hover me" } - } - TooltipContent { class: "tooltip-content", "This is a basic tooltip" } + Tooltip { class: "tooltip", + TooltipTrigger { class: "tooltip-trigger", + button { "Rich content" } } - Tooltip { class: "tooltip", - TooltipTrigger { class: "tooltip-trigger", - button { "Right tooltip" } - } - TooltipContent { class: "tooltip-content", side: TooltipSide::Right, - "This tooltip appears on the right" - } - } - Tooltip { class: "tooltip", - TooltipTrigger { class: "tooltip-trigger", - button { "Rich content" } - } - TooltipContent { class: "tooltip-content", style: "width: 200px;", - h4 { style: "margin-top: 0; margin-bottom: 8px;", "Tooltip title" } - p { style: "margin: 0;", "This tooltip contains rich HTML content with styling." } - } + TooltipContent { + side: dioxus_primitives::tooltip::TooltipSide::Left, + class: "tooltip-content", + style: "width: 200px;", + h4 { style: "margin-top: 0; margin-bottom: 8px;", "Tooltip title" } + p { style: "margin: 0;", "This tooltip contains rich HTML content with styling." } } } } diff --git a/preview/src/components/tooltip/style.css b/preview/src/components/tooltip/style.css index ef95657..ef7d452 100644 --- a/preview/src/components/tooltip/style.css +++ b/preview/src/components/tooltip/style.css @@ -1,134 +1,168 @@ /* Tooltip Styles */ .tooltip { - position: relative; - display: inline-block; + position: relative; + display: inline-block; } .tooltip-trigger { - display: inline-block; + display: inline-block; } .tooltip-content { - position: absolute; - z-index: 1000; - max-width: 250px; - padding: 8px 12px; - border-radius: 4px; - background-color: var(--brighter-background-color); - color: var(--text-color); - font-size: 14px; - line-height: 1.4; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); - animation: tooltipFadeIn 0.2s ease-in-out; + position: absolute; + z-index: 1000; + max-width: 250px; + padding: 8px 12px; + border-radius: 0.5rem; + background-color: var(--text-color); + color: var(--background-color); + font-size: 14px; + line-height: 1.4; + animation: tooltipFadeIn 0.2s ease-in-out; +} + +.tooltip-content::after { + content: " "; + position: absolute; + rotate: 45deg; + margin-left: -0.25rem; + border-width: 0.25rem; + border-style: solid; } /* Positioning based on side */ .tooltip-content[data-side="top"] { - position: absolute; - bottom: 100%; - margin-bottom: 8px; - left: 50%; - transform: translateX(-50%); + position: absolute; + bottom: 100%; + margin-bottom: 8px; + left: 50%; + transform: translateX(-50%); +} +.tooltip-content[data-side="top"]::after { + top: calc(100% - 0.25rem); + left: 50%; + border-radius: 0 0 0.1rem 0; + border-color: var(--text-color); } .tooltip-content[data-side="right"] { - position: absolute; - left: 100%; - top: 50%; - transform: translateY(-50%); - margin-left: 8px; + position: absolute; + left: 100%; + top: 50%; + transform: translateY(-50%); + margin-left: 8px; +} +.tooltip-content[data-side="right"]::after { + top: calc(50% - 0.25rem); + left: 0; + border-radius: 0 0 0 0.1rem; + border-color: var(--text-color); } .tooltip-content[data-side="bottom"] { - position: absolute; - top: 100%; - margin-top: 8px; - left: 50%; - transform: translateX(-50%); + position: absolute; + top: 100%; + margin-top: 8px; + left: 50%; + transform: translateX(-50%); +} +.tooltip-content[data-side="bottom"]::after { + bottom: calc(100% - 0.25rem); + left: 50%; + border-radius: 0.1rem 0 0 0; + border-color: var(--text-color); } .tooltip-content[data-side="left"] { - position: absolute; - right: 100%; - top: 50%; - transform: translateY(-50%); - margin-right: 8px; + position: absolute; + right: 100%; + top: 50%; + transform: translateY(-50%); + margin-right: 8px; +} +.tooltip-content[data-side="left"]::after { + top: calc(50% - 0.25rem); + right: -0.25rem; + border-radius: 0 0.1rem 0 0; + border-color: var(--text-color); } /* Alignment styles for top and bottom */ .tooltip-content[data-side="top"][data-align="start"], .tooltip-content[data-side="bottom"][data-align="start"] { - left: 0; - transform: none; + left: 0; + transform: none; } .tooltip-content[data-side="top"][data-align="end"], .tooltip-content[data-side="bottom"][data-align="end"] { - left: auto; - right: 0; - transform: none; + left: auto; + right: 0; + transform: none; } /* Alignment styles for left and right */ .tooltip-content[data-side="left"][data-align="start"], .tooltip-content[data-side="right"][data-align="start"] { - top: 0; - transform: none; + top: 0; + transform: none; } .tooltip-content[data-side="left"][data-align="center"], .tooltip-content[data-side="right"][data-align="center"] { - top: 50%; - transform: translateY(-50%); + top: 50%; + transform: translateY(-50%); } .tooltip-content[data-side="left"][data-align="end"], .tooltip-content[data-side="right"][data-align="end"] { - top: auto; - bottom: 0; - transform: none; + top: auto; + bottom: 0; + transform: none; } /* Animation */ @keyframes tooltipFadeIn { - from { - opacity: 0; - } + from { + opacity: 0; + transform: scale(0.95); + } - to { - opacity: 1; - } + to { + opacity: 1; + transform: scale(1); + } } /* State styles */ .tooltip[data-disabled="true"] .tooltip-trigger { - cursor: default; + cursor: default; } .tooltip-content[data-state="closed"] { - display: none; + display: none; } .tooltip-content[data-state="open"] { - display: block; + display: block; } .tooltip button { - padding: 8px 12px; - border-radius: 4px; - cursor: pointer; - user-select: none; - outline: none; - font-size: 14px; - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - color: var(--text-color); + padding: 8px 12px; + border-radius: 4px; + cursor: pointer; + user-select: none; + outline: none; + font-size: 14px; + background-color: var(--brighter-background-color); + border: 1px solid var(--dim-border-color); + color: var(--text-color); } .tooltip button:hover { - background: var(--hover-background-color); + background: var(--hover-background-color); } .tooltip button:focus { - background: var(--focused-background-color); + background: var(--focused-background-color); } From 276e25d3d17a50f4259b704ed7ca25f0b27af370 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 9 Jun 2025 11:07:40 -0500 Subject: [PATCH 26/28] basic toast styling --- preview/src/components/toast/style.css | 113 ++++++++++++++++++------- preview/src/main.rs | 2 +- primitives/src/calendar.rs | 1 - primitives/src/toast.rs | 12 ++- 4 files changed, 95 insertions(+), 33 deletions(-) diff --git a/preview/src/components/toast/style.css b/preview/src/components/toast/style.css index 1d7ef60..cdc9854 100644 --- a/preview/src/components/toast/style.css +++ b/preview/src/components/toast/style.css @@ -3,50 +3,117 @@ bottom: 20px; right: 20px; display: flex; - flex-direction: column; - gap: 10px; + flex-direction: column-reverse; + gap: 0.75rem; z-index: 9999; max-width: 350px; } .toast { - background-color: var(--dim-background-color); - border-radius: .5rem; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - padding: 12px 16px; + width: 18rem; + height: 4rem; + margin-top: -4rem; + overflow: hidden; + transition: transform 0.2s ease, margin-top 0.2s ease, opacity 0.2s ease; + transform: scale(calc(100% - var(--toast-index) * 2%)); + box-sizing: border-box; + z-index: calc(var(--toast-count) - var(--toast-index)); + opacity: calc(1 - var(--toast-hidden)); display: flex; - align-items: flex-start; justify-content: space-between; - animation: toast-slide-in 0.2s ease-out; - overflow: hidden; - border-left: 4px solid var(--dim-border-color); + align-items: center; + padding: 12px 16px; + background-color: var(--focused-background-color); + border-radius: 0.5rem; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); + border: 1px solid var(--hover-border-color); + box-sizing: border-box; + --toast-hidden: calc(min(max(0, var(--toast-index) - 2), 1)); +} + +.toast-container:not(:hover) .toast[data-toast-even]:not([data-top]) { + animation: slide-up-even 0.2s ease-out; +} +.toast-container:not(:hover) .toast[data-toast-odd]:not([data-top]) { + animation: slide-up-odd 0.2s ease-out; } -.toast[data-type="success"] { +@keyframes slide-up-even { + from { + transform: translateY(0.5rem) scale(calc(100% - var(--toast-index) * 2%)); + } + to { + transform: translateY(calc(var(--toast-hidden) * -0.5rem)) + scale(calc(100% - var(--toast-index) * 2%)); + } +} + +@keyframes slide-up-odd { + from { + transform: translateY(0.5rem) scale(calc(100% - var(--toast-index) * 2%)); + } + to { + transform: translateY(calc(var(--toast-hidden) * -0.5rem)) + scale(calc(100% - var(--toast-index) * 2%)); + } +} + +.toast[data-top] { + animation: slide-in 0.2s ease-out; +} + +.toast-container:hover .toast[data-top] { + animation: slide-in 0 ease-out; +} + +@keyframes slide-in { + from { + transform: translateY(100%) scale(calc(110% - var(--toast-index) * 2%)); + opacity: 0; + } + to { + transform: translateY(0) scale(calc(100% - var(--toast-index) * 2%)); + opacity: 1; + } +} + +.toast-container:hover .toast { + /* transform: translate(-100%, calc(var(--toast-index) * -1 * 100%)) scale(calc(100%)); */ + margin-top: var(--toast-padding); + transform: scale(calc(100%)); + opacity: 1; +} + +.toast-container:hover .toast-content { + filter: blur(0); +} + +/* .toast[data-type="success"] .toast-body { border-left-color: var(--success-background-color); } -.toast[data-type="error"] { +.toast[data-type="error"] .toast-body { border-left-color: var(--error-background-color); } -.toast[data-type="warning"] { +.toast[data-type="warning"] .toast-body { border-left-color: var(--warning-background-color); } -.toast[data-type="info"] { +.toast[data-type="info"] .toast-body { border-left-color: var(--info-background-color); } -/* Permanent toast styling */ -.toast[data-permanent="true"] { +.toast[data-permanent="true"] .toast-body { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); border-width: 4px; -} +} */ .toast-content { flex: 1; margin-right: 8px; + transition: filter 0.2s ease; + filter: blur(calc(10rem * ((var(--toast-index) - 1) / 4))); } .toast-title { @@ -76,18 +143,6 @@ color: var(--text-color); } -@keyframes toast-slide-in { - from { - transform: translateX(100%); - opacity: 0; - } - - to { - transform: translateX(0); - opacity: 1; - } -} - .toast-example { padding: 20px; display: flex; diff --git a/preview/src/main.rs b/preview/src/main.rs index 5abef96..524309e 100644 --- a/preview/src/main.rs +++ b/preview/src/main.rs @@ -119,7 +119,7 @@ fn CopyIcon() -> Element { fn ComponentCode(rs_highlighted: HighlightedCode, css_highlighted: HighlightedCode) -> Element { let mut collapsed = use_signal(|| true); - let expand = rsx!{ + let expand = rsx! { button { width: "100%", height: "2rem", diff --git a/primitives/src/calendar.rs b/primitives/src/calendar.rs index da22fa2..f16b13d 100644 --- a/primitives/src/calendar.rs +++ b/primitives/src/calendar.rs @@ -300,7 +300,6 @@ pub fn CalendarNavigation(props: CalendarNavigationProps) -> Element { } } - /// Next month navigation button component props #[derive(Props, Clone, PartialEq)] pub struct CalendarPreviousMonthButtonProps { diff --git a/primitives/src/toast.rs b/primitives/src/toast.rs index 4104d24..f462c04 100644 --- a/primitives/src/toast.rs +++ b/primitives/src/toast.rs @@ -152,6 +152,7 @@ pub fn ToastProvider(props: ToastProviderProps) -> Element { let toasts_vec = toasts.read(); toasts_vec.iter().cloned().collect::>() }); + let length = toast_list.len(); rsx! { // Render children @@ -164,12 +165,14 @@ pub fn ToastProvider(props: ToastProviderProps) -> Element { aria_live: "polite", aria_label: "Notifications", class: "toast-container", + style: "--toast-count: {length}", // Render all toasts - for toast in toast_list().iter() { + for (index, toast) in toast_list.read().iter().rev().enumerate() { Toast { key: "{toast.id}", id: toast.id, + index, title: toast.title.clone(), description: toast.description.clone(), toast_type: toast.toast_type, @@ -198,6 +201,7 @@ pub fn ToastProvider(props: ToastProviderProps) -> Element { #[derive(Props, Clone, PartialEq)] pub struct ToastProps { id: usize, + index: usize, title: String, description: Option, toast_type: ToastType, @@ -245,7 +249,11 @@ pub fn Toast(props: ToastProps) -> Element { role: "alert", class: "toast", "data-type": props.toast_type.as_str(), - "data-permanent": props.permanent.to_string(), + "data-permanent": props.permanent, + "data-toast-even": (props.index % 2 == 0).then_some("true"), + "data-toast-odd": (props.index % 2 == 1).then_some("true"), + "data-top": (props.index == 0).then_some("true"), + style: "--toast-index: {props.index}", ..props.attributes, div { class: "toast-content", From 9927914dd5a496e7c317d8f853d4d23125ef31af Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 9 Jun 2025 11:38:27 -0500 Subject: [PATCH 27/28] Finish toast styling --- preview/assets/main.css | 8 +- preview/src/components/toast/mod.rs | 141 +++++-------------------- preview/src/components/toast/style.css | 131 ++++++----------------- 3 files changed, 59 insertions(+), 221 deletions(-) diff --git a/preview/assets/main.css b/preview/assets/main.css index f7e6add..e9df89c 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -33,8 +33,8 @@ --error-background-color-focused: #dc2626; --error-border-color: var(--error-background-color); --error-text-color: var(--text-color); - --info-background-color: #e0f2fe; - --info-text-color: #0284c7; + --info-background-color: var(--background-color); + --info-text-color: var(--dim-text-color); } } @@ -64,8 +64,8 @@ --error-background-color-focused: #9b1c1c; --error-border-color: var(--error-background-color); --error-text-color: var(--dim-text-color); - --info-background-color: #0c1f2b; - --info-text-color: #b3d7e6; + --info-background-color: var(--focused-background-color); + --info-text-color: var(--hover-border-color); } } diff --git a/preview/src/components/toast/mod.rs b/preview/src/components/toast/mod.rs index ef91200..5f6bf39 100644 --- a/preview/src/components/toast/mod.rs +++ b/preview/src/components/toast/mod.rs @@ -18,123 +18,30 @@ fn ToastButton() -> Element { rel: "stylesheet", href: asset!("/src/components/toast/style.css"), } - div { class: "toast-example", - h4 { "Timed Toasts (auto-dismiss)" } - div { class: "toast-buttons", - button { - onclick: move |_| { - toast_api - .success( - "Success".to_string(), - Some(ToastOptions { - duration: Some(Duration::from_secs(3)), - ..Default::default() - }), - ); - }, - "Success (3s)" - } - button { - onclick: move |_| { - toast_api - .error( - "Error".to_string(), - Some(ToastOptions { - duration: Some(Duration::from_secs(5)), - ..Default::default() - }), - ); - }, - "Error (5s)" - } - button { - onclick: move |_| { - toast_api - .warning( - "Warning".to_string(), - Some(ToastOptions { - description: Some("This action might cause issues".to_string()), - duration: Some(Duration::from_secs(3)), - ..Default::default() - }), - ); - }, - "Warning (3s)" - } - button { - onclick: move |_| { - toast_api - .info( - "Custom Toast".to_string(), - Some(ToastOptions { - description: Some( - "This is a custom toast with specific settings".to_string(), - ), - duration: Some(Duration::from_secs(10)), - permanent: false, - }), - ); - }, - "Custom Info (10s)" - } - } - h4 { "Permanent Toasts (manual close)" } - div { class: "toast-buttons", - button { - onclick: move |_| { - toast_api - .success( - "Important".to_string(), - Some(ToastOptions { - permanent: true, - ..Default::default() - }), - ); - }, - "Permanent Success" - } - button { - onclick: move |_| { - toast_api - .error( - "Critical Error".to_string(), - Some(ToastOptions { - permanent: true, - ..Default::default() - }), - ); - }, - "Permanent Error" - } - button { - onclick: move |_| { - toast_api - .warning( - "Attention Needed".to_string(), - Some(ToastOptions { - description: Some("This requires your attention".to_string()), - permanent: true, - ..Default::default() - }), - ); - }, - "Permanent Warning" - } - button { - onclick: move |_| { - toast_api - .info( - "Info Toast".to_string(), - Some(ToastOptions { - description: Some("This is an informational message".to_string()), - permanent: true, - ..Default::default() - }), - ); - }, - "Permanent Info" - } - } + // Additional styles just for the trigger button + document::Link { + rel: "stylesheet", + href: asset!("/src/components/alert_dialog/style.css"), + } + button { + class: "alert-dialog-trigger", + onclick: move |_| { + toast_api + .info( + "Custom Toast".to_string(), + Some(ToastOptions { + description: Some( + "Some info you need".to_string(), + ), + duration: Some(Duration::from_secs(10)), + permanent: false, + }), + ); + }, + "Info (10s)" + } + style { + "" } } } diff --git a/preview/src/components/toast/style.css b/preview/src/components/toast/style.css index cdc9854..25b3518 100644 --- a/preview/src/components/toast/style.css +++ b/preview/src/components/toast/style.css @@ -15,7 +15,7 @@ margin-top: -4rem; overflow: hidden; transition: transform 0.2s ease, margin-top 0.2s ease, opacity 0.2s ease; - transform: scale(calc(100% - var(--toast-index) * 2%)); + transform: scale(calc(100% - var(--toast-index) * 5%), calc(100% - var(--toast-index) * 2%)); box-sizing: border-box; z-index: calc(var(--toast-count) - var(--toast-index)); opacity: calc(1 - var(--toast-hidden)); @@ -23,14 +23,20 @@ justify-content: space-between; align-items: center; padding: 12px 16px; - background-color: var(--focused-background-color); border-radius: 0.5rem; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); - border: 1px solid var(--hover-border-color); + border: 1px solid var(--dim-border-color); box-sizing: border-box; --toast-hidden: calc(min(max(0, var(--toast-index) - 2), 1)); } +@media (prefers-color-scheme: dark) { + .toast { + border: 1px solid var(--hover-border-color); + filter: brightness(calc(0.5 + 0.5 * (1 - ((var(--toast-index) + 1) / 4)))); + } +} + .toast-container:not(:hover) .toast[data-toast-even]:not([data-top]) { animation: slide-up-even 0.2s ease-out; } @@ -40,21 +46,21 @@ @keyframes slide-up-even { from { - transform: translateY(0.5rem) scale(calc(100% - var(--toast-index) * 2%)); + transform: translateY(0.5rem) scale(calc(100% - var(--toast-index) * 5%), calc(100% - var(--toast-index) * 2%)); } to { - transform: translateY(calc(var(--toast-hidden) * -0.5rem)) - scale(calc(100% - var(--toast-index) * 2%)); + transform: translateY(0) + scale(calc(100% - var(--toast-index) * 5%), calc(100% - var(--toast-index) * 2%)); } } @keyframes slide-up-odd { from { - transform: translateY(0.5rem) scale(calc(100% - var(--toast-index) * 2%)); + transform: translateY(0.5rem) scale(calc(100% - var(--toast-index) * 5%), calc(100% - var(--toast-index) * 2%)); } to { - transform: translateY(calc(var(--toast-hidden) * -0.5rem)) - scale(calc(100% - var(--toast-index) * 2%)); + transform: translateY(0) + scale(calc(100% - var(--toast-index) * 5%), calc(100% - var(--toast-index) * 2%)); } } @@ -68,52 +74,46 @@ @keyframes slide-in { from { - transform: translateY(100%) scale(calc(110% - var(--toast-index) * 2%)); + transform: translateY(100%) scale(calc(110% - var(--toast-index) * 5%), calc(110% - var(--toast-index) * 2%)); opacity: 0; } to { - transform: translateY(0) scale(calc(100% - var(--toast-index) * 2%)); + transform: translateY(0) scale(calc(100% - var(--toast-index) * 5%), calc(100% - var(--toast-index) * 2%)); opacity: 1; } } .toast-container:hover .toast { - /* transform: translate(-100%, calc(var(--toast-index) * -1 * 100%)) scale(calc(100%)); */ margin-top: var(--toast-padding); transform: scale(calc(100%)); opacity: 1; + filter: brightness(1); } -.toast-container:hover .toast-content { - filter: blur(0); -} - -/* .toast[data-type="success"] .toast-body { - border-left-color: var(--success-background-color); +.toast[data-type="success"] { + background-color: var(--success-background-color); + color: var(--success-text-color); } -.toast[data-type="error"] .toast-body { - border-left-color: var(--error-background-color); +.toast[data-type="error"] { + background-color: var(--error-background-color); + color: var(--error-text-color); } -.toast[data-type="warning"] .toast-body { - border-left-color: var(--warning-background-color); +.toast[data-type="warning"] { + background-color: var(--warning-background-color); + color: var(--warning-text-color); } -.toast[data-type="info"] .toast-body { - border-left-color: var(--info-background-color); +.toast[data-type="info"] { + background-color: var(--info-background-color); + color: var(--info-text-color); } -.toast[data-permanent="true"] .toast-body { - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25); - border-width: 4px; -} */ - .toast-content { flex: 1; margin-right: 8px; transition: filter 0.2s ease; - filter: blur(calc(10rem * ((var(--toast-index) - 1) / 4))); } .toast-title { @@ -140,74 +140,5 @@ } .toast-close:hover { - color: var(--text-color); -} - -.toast-example { - padding: 20px; - display: flex; - flex-direction: column; - align-items: center; -} - -.toast-example h3 { - margin-top: 0; - margin-bottom: 10px; -} - -.toast-example h4 { - margin-top: 20px; - margin-bottom: 10px; - font-size: 1rem; -} - -.toast-buttons { - display: flex; - flex-wrap: wrap; - gap: 10px; - margin-top: 15px; -} - -.toast-buttons button { - padding: 8px 16px; - color: var(--text-color); - background-color: var(--brighter-background-color); - border: 1px solid var(--dim-border-color); - border-radius: 4px; - cursor: pointer; - font-size: 14px; - transition: all 0.2s ease; -} - -.toast-buttons button:hover { - background-color: var(--dim-background-color); -} - -.toast-buttons button:focus { - outline: none; - box-shadow: 0 0 0 2px rgba(13, 110, 253, 0.25); -} - -.toast-buttons button:nth-child(1) { - background-color: var(--success-background-color); - color: var(--success-text-color); -} - -.toast-buttons button:nth-child(2) { - background-color: var(--error-background-color); - color: var(--error-text-color); -} - -.toast-buttons button:nth-child(3) { - background-color: var(--warning-background-color); - color: var(--warning-text-color); -} - -.toast-buttons button:nth-child(4) { - background-color: var(--info-background-color); - color: var(--info-text-color); -} - -.toast-buttons button:hover { - filter: brightness(0.95); + color: var(--bright-text-color); } From 03b9febe2ed723606803d6eeab13d3472dd7029d Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Mon, 9 Jun 2025 12:12:56 -0500 Subject: [PATCH 28/28] add github link and fix codeblock styling --- preview/.DS_Store | Bin 0 -> 6148 bytes preview/assets/.DS_Store | Bin 0 -> 6148 bytes preview/assets/github-mark/.DS_Store | Bin 0 -> 6148 bytes .../assets/github-mark/github-mark-white.svg | 1 + preview/assets/github-mark/github-mark.svg | 1 + preview/assets/hero.css | 6 ++- preview/assets/main.css | 40 ++++++++++-------- preview/src/components/alert_dialog/style.css | 6 +-- preview/src/components/tooltip/style.css | 2 +- preview/src/main.rs | 36 ++++++++++------ 10 files changed, 57 insertions(+), 35 deletions(-) create mode 100644 preview/.DS_Store create mode 100644 preview/assets/.DS_Store create mode 100644 preview/assets/github-mark/.DS_Store create mode 100644 preview/assets/github-mark/github-mark-white.svg create mode 100644 preview/assets/github-mark/github-mark.svg diff --git a/preview/.DS_Store b/preview/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ec4745f15463c817e200da7e148a31e41a0f4fab GIT binary patch literal 6148 zcmeHK%}T>S5Z-NTyQK&@D0&QdtyrNd;w8lT0!H+pQWFw17_+5G&7l->)fe(jd>&_Z zH-}*GC}L;I?l(I>yO|HVKa4T%F2X~`EXJ6ChR9KA5HvTsS|%8gt2uI(1w}Rs5*aj1 z^cPL|?Oo=x41N)-fB#1?OX4gajXrs+-P!2&L{ALFz4s&wFZc6B=KAwn99>D71eNXw z*Kt%#t*vvJ=6;+;bCnQ>5ro{`#AzrCS1!^pQ@NgYh`#7gt)1oaw_qRiR)tvozyZD)DvkL)U^_S>jKoMW)mh_j$w Rr32DMKoLS6G4Klvd;uYiOeFvS literal 0 HcmV?d00001 diff --git a/preview/assets/.DS_Store b/preview/assets/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..dd4793521258c1ecb5763a6e3a57858694e94c08 GIT binary patch literal 6148 zcmeHKK~BRk5Zo;lDyjrMa`Xo{RD2**;lQ~cXp>4UB9SYgcYlQ6@C^O}v))zJDg=oO zLa-z4jYV}k%Rg4WLL|@0vdOELTyF~_Yy@cx- zLL1A{hJYEE-p*fMZ@$W2eIt9jIUL0T-8x(WSHKncFAB&K4UERh?p*;_z!lglAnQYb z2^YpmIWHY>`3L|WBAkJ?{47dMFfNRfGVTDZrC=>(J7TbwBOWZTFiy%^PHcw{wkNZl zP&hvw{fC@RTqwJD1zdq+1y1yGBK!Ys|M~y8$gf-hSKv=6z{7H0&hSdMw{~7m_Syhj pzyy+)l=mfQH1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 \ No newline at end of file diff --git a/preview/assets/github-mark/github-mark.svg b/preview/assets/github-mark/github-mark.svg new file mode 100644 index 0000000..37fa923 --- /dev/null +++ b/preview/assets/github-mark/github-mark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/preview/assets/hero.css b/preview/assets/hero.css index 48d05eb..590fd1b 100644 --- a/preview/assets/hero.css +++ b/preview/assets/hero.css @@ -45,10 +45,14 @@ margin: 20px 0; padding: 10px; color: var(--text-color); - border: 1px solid var(--border-color); + border: 1px solid var(--dim-border-color); border-radius: .5rem; background-color: var(--brighter-background-color); box-sizing: border-box; margin: 2em auto; padding: 10px 20px; } + +#hero-search-input:focus-visible { + box-shadow: 0 0 0 2px var(--focused-border-color); +} diff --git a/preview/assets/main.css b/preview/assets/main.css index e9df89c..cba0559 100644 --- a/preview/assets/main.css +++ b/preview/assets/main.css @@ -70,13 +70,13 @@ } @media (prefers-color-scheme: light) { - .code-block-dark { + .dark-mode-only { display: none; } } @media (prefers-color-scheme: dark) { - .code-block-light { + .light-mode-only { display: none; } } @@ -97,11 +97,11 @@ body { align-items: center; justify-content: space-between; position: sticky; - padding: 1rem; + padding: .5rem 1rem; top: 0; z-index: 1000; - background-color: var(--brighter-background-color); - border-bottom: 1px solid var(--border-color); + background-color: var(--background-color); + border-bottom: 1px solid var(--dim-border-color); } .navbar-link { @@ -139,6 +139,8 @@ body { height: 100%; max-height: 80vh; box-sizing: border-box; + padding: .5rem; + margin: 0; } .code-block[data-collapsed="true"] { @@ -146,9 +148,8 @@ body { backdrop-filter: blur(1px); mask: linear-gradient( to bottom, - rgba(0, 0, 0, 1) 12.5%, - rgba(0, 0, 0, 1) 25%, - rgba(0, 0, 0, 1) 37.5%, + rgba(0, 0, 0, 1) 0%, + rgba(0, 0, 0, 1) 60%, rgba(0, 0, 0, 0) 100% ); overflow: hidden; @@ -191,13 +192,6 @@ body { align-items: center; justify-content: center; width: 100vw; - background-color: var(--muted-background-color); -} - -.component-preview-separator { - width: 100%; - height: 1px; - background-color: var(--dim-border-color); } .component-preview-contents { @@ -205,9 +199,6 @@ body { flex-direction: column; align-items: center; justify-content: center; - border: 1px solid var(--dim-border-color); - border-radius: 8px; - box-sizing: border-box; margin: 20px 0; width: 75vw; } @@ -224,6 +215,9 @@ body { border-top-left-radius: 0.5em; padding: 20px; box-sizing: border-box; + border: 1px solid var(--dim-border-color); + background-color: var(--muted-background-color); + border-radius: 8px; } /* component info styles */ @@ -242,7 +236,17 @@ body { } .component-code { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; width: 100%; + min-height: 25vh; + max-height: 100%; + border-top-right-radius: 0.5em; + border-top-left-radius: 0.5em; + padding-top: 2rem; + box-sizing: border-box; } /* Masonry styles */ diff --git a/preview/src/components/alert_dialog/style.css b/preview/src/components/alert_dialog/style.css index 55e7584..ab93a6c 100644 --- a/preview/src/components/alert_dialog/style.css +++ b/preview/src/components/alert_dialog/style.css @@ -87,7 +87,7 @@ background-color: var(--hover-background-color); } -.alert-dialog-cancel:focus { +.alert-dialog-cancel:focus-visible { box-shadow: 0 0 0 2px var(--focused-border-color); } @@ -106,7 +106,7 @@ background-color: var(--error-background-color-focused); } -.alert-dialog-action:focus { +.alert-dialog-action:focus-visible { box-shadow: 0 0 0 2px var(--focused-border-color); } @@ -131,7 +131,7 @@ background-color: var(--hover-background-color); } -.alert-dialog-trigger:focus { +.alert-dialog-trigger:focus-visible { box-shadow: 0 0 0 2px var(--focused-border-color); } diff --git a/preview/src/components/tooltip/style.css b/preview/src/components/tooltip/style.css index ef7d452..7da05ff 100644 --- a/preview/src/components/tooltip/style.css +++ b/preview/src/components/tooltip/style.css @@ -163,6 +163,6 @@ background: var(--hover-background-color); } -.tooltip button:focus { +.tooltip button:focus-visible { background: var(--focused-background-color); } diff --git a/preview/src/main.rs b/preview/src/main.rs index 524309e..c67dd65 100644 --- a/preview/src/main.rs +++ b/preview/src/main.rs @@ -1,9 +1,8 @@ use dioxus::prelude::*; -use dioxus_primitives::{ - separator::Separator, - tabs::{TabContent, TabTrigger, Tabs}, -}; +use dioxus_primitives::tabs::{TabContent, TabTrigger, Tabs}; + mod components; + #[derive(Clone, PartialEq)] struct ComponentDemoData { name: &'static str, @@ -57,11 +56,28 @@ fn Navbar() -> Element { } } div { class: "navbar-links", - Link { to: Route::Home, class: "navbar-link", "Home" } Link { to: "https://docs.rs/crate/dioxus-components/latest", class: "navbar-link", - "docs.rs" + "Docs.rs" + } + Link { + to: "https://github.com/DioxusLabs/components", + class: "navbar-link", + img { + class: "light-mode-only", + src: asset!("/assets/github-mark/github-mark.svg"), + alt: "GitHub", + width: "24", + height: "24", + } + img { + class: "dark-mode-only", + src: asset!("/assets/github-mark/github-mark-white.svg"), + alt: "GitHub", + width: "24", + height: "24", + } } } } @@ -79,12 +95,12 @@ fn CodeBlock(source: HighlightedCode, collapsed: bool) -> Element { let mut copied = use_signal(|| false); rsx! { pre { - class: "code-block code-block-dark", + class: "code-block dark-mode-only", "data-collapsed": "{collapsed}", dangerous_inner_html: source.dark, } pre { - class: "code-block code-block-light", + class: "code-block light-mode-only", "data-collapsed": "{collapsed}", dangerous_inner_html: source.light, } @@ -243,10 +259,6 @@ fn ComponentHighlight(demo: ComponentDemoData) -> Element { div { class: "component-preview", div { class: "component-preview-contents", div { class: "component-preview-frame", Comp {} } - Separator { - class: "component-preview-separator", - horizontal: true, - } div { class: "component-code", ComponentCode { rs_highlighted, css_highlighted } }