diff --git a/assets/brand/nova-brand.png b/assets/brand/nova-brand.png new file mode 100644 index 0000000..0e8a8de Binary files /dev/null and b/assets/brand/nova-brand.png differ diff --git a/assets/brand/nova-brand.svg b/assets/brand/nova-brand.svg new file mode 100644 index 0000000..43b5f05 --- /dev/null +++ b/assets/brand/nova-brand.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ui/app_state/nova.rs b/src/ui/app_state/nova.rs index 43a9f9b..f28ee3e 100644 --- a/src/ui/app_state/nova.rs +++ b/src/ui/app_state/nova.rs @@ -20,6 +20,7 @@ pub enum SettingsTab { StatusBar, Ai, Raw, + About, } #[derive(Debug, Clone)] diff --git a/src/ui/components/mod.rs b/src/ui/components/mod.rs index c894bf7..a7cbba9 100644 --- a/src/ui/components/mod.rs +++ b/src/ui/components/mod.rs @@ -7,6 +7,7 @@ mod search_bar; mod section_label; mod setting_row; mod settings; +mod settings_about; mod settings_ai; mod settings_general; mod settings_keybindings; diff --git a/src/ui/components/settings.rs b/src/ui/components/settings.rs index 6dd5878..bc0acab 100644 --- a/src/ui/components/settings.rs +++ b/src/ui/components/settings.rs @@ -15,7 +15,8 @@ use crate::ui::{ }; use super::{ - settings_ai, settings_general, settings_keybindings, settings_status_bar, settings_theme, + settings_about, settings_ai, settings_general, settings_keybindings, settings_status_bar, + settings_theme, }; const SIDEBAR_WIDTH: f32 = 160.0; @@ -133,68 +134,76 @@ fn modal_inner<'a>( let body = row![ sidebar_nav(active_tab), rule::vertical(1), - container( - scrollable(match active_tab { - SettingsTab::General => settings_general::general_tab(settings, shell_input), - SettingsTab::Theme => settings_theme::theme_tab(settings), - SettingsTab::Keybindings => - settings_keybindings::keybindings_tab(settings, recording_index), - SettingsTab::StatusBar => settings_status_bar::status_bar_tab(settings), - SettingsTab::Ai => settings_ai::ai_tab(settings), - SettingsTab::Raw => edit_raw_tab(raw_content), - }) - .height(Length::Fill) - .direction(scrollable::Direction::Vertical( - scrollable::Scrollbar::new() - .width(4) - .margin(4) - .scroller_width(4), - )) - .style(|_t, _status| scrollable::Style { - container: container::Style::default(), - vertical_rail: scrollable::Rail { - background: None, - border: Border::default(), - scroller: scrollable::Scroller { - background: Color { - r: 0.5, - g: 0.5, - b: 0.5, - a: 0.35, - } - .into(), - border: Border { - color: Color::TRANSPARENT, - radius: Radius::new(4.0), - width: 0.0, + if *active_tab == SettingsTab::About { + container(settings_about::about_tab()) + .width(Length::Fill) + .height(Length::Fill) + } else { + container( + scrollable(match active_tab { + SettingsTab::General => settings_general::general_tab(settings, shell_input), + SettingsTab::Theme => settings_theme::theme_tab(settings), + SettingsTab::Keybindings => { + settings_keybindings::keybindings_tab(settings, recording_index) + } + SettingsTab::StatusBar => settings_status_bar::status_bar_tab(settings), + SettingsTab::Ai => settings_ai::ai_tab(settings), + SettingsTab::Raw => edit_raw_tab(raw_content), + SettingsTab::About => unreachable!(), + }) + .height(Length::Fill) + .direction(scrollable::Direction::Vertical( + scrollable::Scrollbar::new() + .width(4) + .margin(4) + .scroller_width(4), + )) + .style(|_t, _status| scrollable::Style { + container: container::Style::default(), + vertical_rail: scrollable::Rail { + background: None, + border: Border::default(), + scroller: scrollable::Scroller { + background: Color { + r: 0.5, + g: 0.5, + b: 0.5, + a: 0.35, + } + .into(), + border: Border { + color: Color::TRANSPARENT, + radius: Radius::new(4.0), + width: 0.0, + }, + }, + }, + horizontal_rail: scrollable::Rail { + background: None, + border: Border::default(), + scroller: scrollable::Scroller { + background: Color::TRANSPARENT.into(), + border: Border::default(), }, }, - }, - horizontal_rail: scrollable::Rail { - background: None, - border: Border::default(), - scroller: scrollable::Scroller { + gap: None, + auto_scroll: scrollable::AutoScroll { background: Color::TRANSPARENT.into(), border: Border::default(), + shadow: Shadow::default(), + icon: Color::TRANSPARENT, }, - }, - gap: None, - auto_scroll: scrollable::AutoScroll { - background: Color::TRANSPARENT.into(), - border: Border::default(), - shadow: Shadow::default(), - icon: Color::TRANSPARENT, - }, - }), - ) - .padding(Padding { - top: 16.0, - bottom: 16.0, - left: 20.0, - right: 16.0, - }) - .width(Length::Fill) - .height(Length::Fill), + }), + ) + .padding(Padding { + top: 16.0, + bottom: 16.0, + left: 20.0, + right: 16.0, + }) + .width(Length::Fill) + .height(Length::Fill) + }, ] .height(Length::Fill); @@ -263,6 +272,7 @@ fn sidebar_nav<'a>(active_tab: &'a SettingsTab) -> Element<'a, Message> { (SettingsTab::StatusBar, "Status Bar"), (SettingsTab::Ai, "AI"), (SettingsTab::Raw, "Raw"), + (SettingsTab::About, "About"), ]; let mut nav = column![].spacing(2).padding(Padding::from([8, 6])); diff --git a/src/ui/components/settings_about.rs b/src/ui/components/settings_about.rs new file mode 100644 index 0000000..eafc450 --- /dev/null +++ b/src/ui/components/settings_about.rs @@ -0,0 +1,35 @@ +use iced::{ + ContentFit, Element, Length, + alignment::Horizontal, + widget::{column, container, svg, text}, +}; + +use crate::ui::{app_state::Message, theme}; + +const BRAND_SVG: &[u8] = include_bytes!("../../../assets/brand/nova-brand.svg"); + +static BRAND_HANDLE: std::sync::LazyLock = + std::sync::LazyLock::new(|| svg::Handle::from_memory(BRAND_SVG)); + +pub(super) fn about_tab<'a>() -> Element<'a, Message> { + let fg_muted = theme::color::runtime().foreground_muted; + + container( + column![ + svg(BRAND_HANDLE.clone()) + .width(260) + .content_fit(ContentFit::Contain), + text(format!("v{}", env!("CARGO_PKG_VERSION"))) + .font(theme::font::regular()) + .size(12) + .color(fg_muted), + ] + .spacing(12) + .align_x(Horizontal::Center), + ) + .width(Length::Fill) + .height(Length::Fill) + .align_x(Horizontal::Center) + .align_y(iced::alignment::Vertical::Center) + .into() +}