Files
shadcn-slint/ui/components/toast.slint
2026-01-26 09:05:48 +08:00

149 lines
4.3 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Toast Component
// Notification toast with auto-dismiss and animations
import { Theme, Typography, SpacingSystem } from "../theme/theme.slint";
import { Animations } from "../utils/animations.slint";
// Toast message structure
export struct ToastMessage {
message: string,
variant: string, // default | success | error | warning
show: bool,
}
// Single toast item
export component Toast {
// Public properties
in property <string> message: "";
in property <string> variant: "default"; // default | success | error | warning
in-out property <bool> show: false;
// Callbacks
callback dismissed();
// Calculate colors based on variant
private property <color> bg-color: {
if variant == "success" { #10b981 }
else if variant == "error" { Theme.colors.destructive }
else if variant == "warning" { #f59e0b }
else { Theme.colors.card }
};
private property <color> text-color: {
if variant == "success" { #ffffff }
else if variant == "error" { Theme.colors.destructive-foreground }
else if variant == "warning" { #ffffff }
else { Theme.colors.card-foreground }
};
private property <string> icon: {
if variant == "success" { "✓" }
else if variant == "error" { "✕" }
else if variant == "warning" { "⚠" }
else { "" }
};
// Animation properties
property <length> translate-y: show ? 0px : -20px;
property <float> opacity-val: show ? 1.0 : 0.0;
animate translate-y, opacity-val {
duration: Animations.durations.normal;
easing: Animations.ease-out;
}
width: 350px;
height: show ? 60px : 0px;
if show: Rectangle {
y: translate-y;
opacity: opacity-val;
background: bg-color;
border-radius: SpacingSystem.radius.lg;
border-width: 1px;
border-color: Theme.colors.border;
drop-shadow-blur: 10px;
drop-shadow-color: #00000020;
drop-shadow-offset-y: 4px;
HorizontalLayout {
padding: SpacingSystem.spacing.s4;
spacing: SpacingSystem.spacing.s3;
alignment: space-between;
HorizontalLayout {
spacing: SpacingSystem.spacing.s3;
// Icon
Text {
text: icon;
font-size: Typography.sizes.xl;
color: text-color;
vertical-alignment: center;
}
// Message
Text {
text: message;
font-size: Typography.sizes.base;
color: text-color;
vertical-alignment: center;
wrap: word-wrap;
}
}
// Close button
Rectangle {
width: 24px;
height: 24px;
border-radius: SpacingSystem.radius.sm;
background: close-touch.has-hover ? #00000020 : Colors.transparent;
animate background {
duration: Animations.durations.fast;
easing: Animations.ease-in-out;
}
Text {
text: "✕";
font-size: Typography.sizes.sm;
color: text-color;
horizontal-alignment: center;
vertical-alignment: center;
}
close-touch := TouchArea {
clicked => {
root.dismissed();
}
}
}
}
}
}
// Toast container (manages multiple toasts)
export component ToastContainer {
in property <[ToastMessage]> toasts: [];
callback toast-dismissed(int);
// Position at top-right corner
width: 370px;
VerticalLayout {
spacing: SpacingSystem.spacing.s2;
alignment: start;
for toast[index] in toasts: Toast {
message: toast.message;
variant: toast.variant;
show: toast.show;
dismissed => {
root.toast-dismissed(index);
}
}
}
}