diff --git a/icons/cog.svg b/icons/cog.svg new file mode 100644 index 0000000..493377c --- /dev/null +++ b/icons/cog.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/logos/external_link.svg b/icons/external_link.svg similarity index 100% rename from logos/external_link.svg rename to icons/external_link.svg diff --git a/logos/globe.svg b/icons/globe.svg similarity index 100% rename from logos/globe.svg rename to icons/globe.svg diff --git a/icons/moon.svg b/icons/moon.svg new file mode 100644 index 0000000..af08447 --- /dev/null +++ b/icons/moon.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/icons/sun.svg b/icons/sun.svg new file mode 100644 index 0000000..0809dad --- /dev/null +++ b/icons/sun.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 1fe84a1..cc0483d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -63,10 +63,6 @@ fn init() -> State { println!("Settings clicked"); }); - main_window.on_feedback_clicked(move || { - println!("Feedback clicked"); - }); - main_window.on_open_clicked(move || { println!("Open clicked"); }); diff --git a/ui/button.slint b/ui/button.slint new file mode 100644 index 0000000..472b10c --- /dev/null +++ b/ui/button.slint @@ -0,0 +1,35 @@ +import { Theme } from "theme.slint"; + +export component GradientButton inherits Rectangle { + callback clicked <=> touch.clicked; + in property text; + + background: Theme.gradient-main; + border-radius: Theme.radius; + drop-shadow-offset-x: Theme.shadow-primary-x; + drop-shadow-offset-y: Theme.shadow-primary-y; + drop-shadow-blur: Theme.shadow-primary-blur; + drop-shadow-color: touch.has-hover ? Theme.shadow-color : transparent; + horizontal-stretch: 0; + + animate drop-shadow-color { duration: 300ms; } + + touch := TouchArea { + mouse-cursor: pointer; + } + + HorizontalLayout { + padding: Theme.spacing-sm; + padding-left: Theme.spacing-xl; + padding-right: Theme.spacing-xl; + + Text { + text: text; + font-family: "Segoe UI"; + font-size: 14px; + font-weight: 600; + min-width: self.preferred-width; + min-height: self.preferred-height; + } + } +} diff --git a/ui/footer.slint b/ui/footer.slint index 8c23b50..d2e61a3 100644 --- a/ui/footer.slint +++ b/ui/footer.slint @@ -1,37 +1,66 @@ -import { - Button, - HorizontalBox, - VerticalBox, -} from "std-widgets.slint"; +import { IconButton } from "icon_button.slint"; +import { Theme } from "theme.slint"; +import { GradientButton } from "button.slint"; export component Footer inherits Rectangle { callback settings-clicked(); - callback feedback-clicked(); callback open-clicked(); - HorizontalBox { - spacing: 16px; - padding-top: 16px; + property cog_icon: @image-url("../icons/cog.svg"); + property sun_icon: @image-url("../icons/sun.svg"); + property moon_icon: @image-url("../icons/moon.svg"); - HorizontalBox { + width: 448px; + + Rectangle { + height: 1px; + width: 100%; + y: 0px; + background: Theme.border-main; + } + + HorizontalLayout { + alignment: space-between; + spacing: Theme.spacing-lg; + padding: Theme.spacing-md; + padding-left: Theme.spacing-lg; + + HorizontalLayout { spacing: 16px; - Button { - text: "⚙️ Настроить"; - clicked => { - root.settings-clicked(); + VerticalLayout { + alignment: center; + IconButton { + icon: sun_icon; + clicked => { + Theme.toggle(); + } } } - Button { - text: "💬 Обратная связь"; - clicked => { - root.feedback-clicked(); + VerticalLayout { + alignment: center; + IconButton { + icon: cog_icon; + clicked => { + root.settings-clicked(); + } } } } - Button { + HorizontalLayout { + alignment: center; + VerticalLayout { + alignment: center; + Text { + text: "Escape - закрыть"; + color: Theme.text-hint; + } + } + } + + GradientButton { text: "Открыть"; clicked => { root.open-clicked(); diff --git a/ui/header.slint b/ui/header.slint index 9aed392..1eb5641 100644 --- a/ui/header.slint +++ b/ui/header.slint @@ -1,40 +1,38 @@ import { BrowserConfig } from "./types.slint"; - +import { Theme } from "theme.slint"; export component Header inherits Rectangle { in property url; - property icon-gradient: @linear-gradient(135deg, rgb(59, 130, 246), rgb(6, 182, 212)); VerticalLayout { - // width: 100%; - width: 448px; - padding: 12px; - padding-top: 20px; - spacing: 12px; + width: 100%; + padding: Theme.spacing-md; + padding-top: Theme.spacing-xl; + spacing: Theme.spacing-md; HorizontalLayout { - spacing: 12px; + spacing: Theme.spacing-md; Rectangle { width: 48px; height: 48px; - border-radius: 12px; - background: icon-gradient; + border-radius: Theme.radius; + background: Theme.gradient-main; Image { - source: @image-url("../logos/globe.svg"); + source: @image-url("../icons/globe.svg"); colorize: white; } } VerticalLayout { alignment: center; - spacing: 4px; + spacing: Theme.spacing-xs; Text { font-family: "Segpoe UI"; text: "Выберите браузер"; - color: #ffffff; + color: Theme.text-main; font-size: 18px; font-weight: 600; } @@ -42,7 +40,7 @@ export component Header inherits Rectangle { Text { font-family: "Segpoe UI"; text: "Для открытия ссылки"; - color: #94a3b8; + color: Theme.text-muted; font-size: 14px; } } @@ -50,22 +48,22 @@ export component Header inherits Rectangle { Rectangle { height: 44px; - border-radius: 12px; - background: #1e293b; + border-radius: Theme.radius; + background: Theme.surface-elevated; border-width: 1px; - border-color: #334155; + border-color: Theme.border-main; HorizontalLayout { - padding: 12px; - padding-left: 16px; - padding-right: 16px; - spacing: 8px; + padding: Theme.spacing-md; + padding-left: Theme.spacing-lg; + padding-right: Theme.spacing-lg; + spacing: Theme.spacing-sm; alignment: start; Image { - source: @image-url("../logos/external_link.svg"); + source: @image-url("../icons/external_link.svg"); width: 16px; - colorize: #64748b; + colorize: Theme.text-control-muted; height: 16px; } @@ -74,7 +72,7 @@ export component Header inherits Rectangle { Text { text: "ku6epxboctuk.github.io"; - color: #cbd5e1; + color: Theme.text-control; font-size: 14px; font-family: "Consolas"; } @@ -87,6 +85,6 @@ export component Header inherits Rectangle { height: 1px; width: 100%; y: parent.height - self.height; - background: #334155; + background: Theme.border-main; } } diff --git a/ui/icon_button.slint b/ui/icon_button.slint new file mode 100644 index 0000000..461c300 --- /dev/null +++ b/ui/icon_button.slint @@ -0,0 +1,19 @@ +export component IconButton inherits Rectangle { + callback clicked <=> touch.clicked; + + in property icon; + property icon_color: touch.has-hover ? #ffffff : #94a3b8; + height: 24px; + width: 24px; + background: transparent; + touch := TouchArea { + mouse-cursor: pointer; + } + + Image { + source: icon; + colorize: icon_color; + width: 24px; + height: 24px; + } +} diff --git a/ui/main.slint b/ui/main.slint index 1d1e34c..a93bc11 100644 --- a/ui/main.slint +++ b/ui/main.slint @@ -3,6 +3,7 @@ import { BrowserItem } from "./browser_item.slint"; import { Header } from "./header.slint"; import { Footer } from "./footer.slint"; import { BrowserConfig } from "./types.slint"; +import { Theme } from "theme.slint"; export component MainWindow inherits Window { in property <[BrowserConfig]> browser-model: []; @@ -15,7 +16,6 @@ export component MainWindow inherits Window { callback toggle-remember(bool); callback toggle-always-ask(bool); callback settings-clicked(); - callback feedback-clicked(); callback open-clicked(); callback request-drag(); @@ -30,20 +30,19 @@ export component MainWindow inherits Window { width: 488px; height: 800px; - padding: 20px; + padding: Theme.spacing-xl; Rectangle { max-width: 448px; width: 100%; height: 760px; - border-radius: 16px; + border-radius: Theme.radius-lg; clip: true; - background: #0f172a; + background: Theme.surface-main; border-width: 1px; - border-color: #334155; + border-color: Theme.border-main; VerticalLayout { - padding: 12px; Header { url: current-url; @@ -83,9 +82,8 @@ export component MainWindow inherits Window { } Footer { - settings-clicked => settings-clicked(); - feedback-clicked => feedback-clicked(); - open-clicked => open-clicked(); + settings-clicked => root.settings-clicked(); + open-clicked => root.open-clicked(); } } } diff --git a/ui/theme.slint b/ui/theme.slint new file mode 100644 index 0000000..51efa4b --- /dev/null +++ b/ui/theme.slint @@ -0,0 +1,42 @@ +export global Theme { + in-out property is-dark: true; + + out property width: 448px; + + out property surface-main: is-dark ? #0f172a : #ffffff; + out property surface-control: is-dark ? #1e293b4d : #ffffff; + out property surface-elevated: is-dark ? #1e293b80 : #ffffff; + out property surface-hover: is-dark ? #1e293b : #ffffff; + + out property border-main: is-dark ? #334155 : #ffffff; + + out property gradient-main: @linear-gradient(135deg, rgb(59, 130, 246), rgb(6, 182, 212)); + + out property text-main: is-dark ? #ffffff : #000000; + out property text-muted: is-dark ? #94a3b8 : #000000; + + out property text-control: is-dark ? #cbd5e1 : #000000; + out property text-control-muted: is-dark ? #64748b : #000000; + + out property text-hint: is-dark ? #475569 : #000000; + + out property shadow-color: is-dark ? #3b82f640 : #000000; + + out property shadow-primary-x: 0px; + out property shadow-primary-y: 10px; + out property shadow-primary-blur: 15px; + + out property radius: 12px; + out property radius-lg: 16px; + + out property spacing-xl: 20px; + out property spacing-lg: 16px; + out property spacing-md: 12px; + out property spacing-sm: 8px; + out property spacing-xs: 4px; + + callback toggle(); + toggle => { + is-dark = !is-dark; + } +}