Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion otty/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ impl App {
let initial_settings = settings.settings_data().clone();
theme_manager.set_custom_palette(initial_settings.to_color_palette());
let current_theme = theme_manager.current();
let fonts = FontsConfig::default();
let mut fonts = FontsConfig::default();
// 从 settings.json 的 font.size 读取终端字号
fonts.terminal.size = initial_settings.font_size();
let terminal_settings = terminal_settings(current_theme, &fonts);
let shell_path = initial_settings.terminal_shell().to_string();
let shell_session = match setup_shell_session_with_shell(&shell_path) {
Expand Down
4 changes: 2 additions & 2 deletions otty/src/components/primitive/icon_button.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use iced::widget::{button, container, svg};
use iced::{Element, Length, alignment};

use crate::layout::BUTTON_RADIUS_ROUNDED;
use crate::layout::RADIUS_CONTROL;
use crate::theme::{StyleOverrides, ThemeProps};

/// UI events emitted by an icon button.
Expand Down Expand Up @@ -76,7 +76,7 @@ pub(crate) fn view<'a>(
.height(Length::Fixed(props.size))
.style(|_, _| iced::widget::button::Style {
border: iced::Border {
radius: iced::border::Radius::from(BUTTON_RADIUS_ROUNDED),
radius: iced::border::Radius::from(RADIUS_CONTROL),
..Default::default()
},
..Default::default()
Expand Down
8 changes: 7 additions & 1 deletion otty/src/components/primitive/sidebar_workspace_panel.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use iced::widget::{Space, container};
use iced::{Element, Length, Theme};

use crate::layout::RADIUS_INNER;
use crate::theme::ThemeProps;

/// Props for rendering sidebar workspace panel container.
Expand All @@ -27,8 +28,13 @@ pub(crate) fn view<'a, Message: 'a>(
.height(Length::Fill)
.clip(true)
.style(move |_| iced::widget::container::Style {
background: Some(palette.dim_black.into()),
// 侧边栏表面色(VS Code sideBar.background)
background: Some(palette.sidebar.into()),
text_color: Some(palette.foreground),
border: iced::Border {
radius: iced::border::Radius::from(RADIUS_INNER),
..Default::default()
},
..Default::default()
})
.into()
Expand Down
18 changes: 11 additions & 7 deletions otty/src/layout.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use iced::Size;

use crate::app::view::HEADER_SEPARATOR_HEIGHT;
use crate::widgets::chrome::view::action_bar::ACTION_BAR_HEIGHT;
use crate::widgets::tabs::view::tab_bar::TAB_BAR_HEIGHT;

/// Shared compact control size used by dense toolbars and menus.
Expand All @@ -13,12 +11,18 @@ pub(crate) const BUTTON_SIZE_RAIL: f32 = 44.0;
/// Shared rounded corner radius for standard buttons.
pub(crate) const BUTTON_RADIUS_ROUNDED: f32 = 6.0;

pub(crate) fn screen_size_from_window(window_size: Size) -> Size {
let height =
(window_size.height - ACTION_BAR_HEIGHT - HEADER_SEPARATOR_HEIGHT)
.max(0.0);
// ============================================================
// Modern UI 分级圆角 token(精确对齐 VS Code styleOverrides 范式):
// CONTROL(4px) = 可交互控件:按钮/输入/列表行/标签页
// INNER(6px) = 内嵌容器:侧边栏/面板
// OUTER(8px) = 悬浮层 + 编辑器主角卡片
// ============================================================
pub(crate) const RADIUS_CONTROL: f32 = 4.0;
pub(crate) const RADIUS_INNER: f32 = 6.0;
pub(crate) const RADIUS_OUTER: f32 = 8.0;

Size::new(window_size.width, height)
pub(crate) fn screen_size_from_window(window_size: Size) -> Size {
Size::new(window_size.width, window_size.height)
}

pub(crate) fn pane_grid_size(
Expand Down
2 changes: 1 addition & 1 deletion otty/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn main() -> iced::Result {
.theme(App::theme)
.antialiasing(true)
.window(window::Settings {
decorations: false,
decorations: true,
min_size: Some(Size {
width: MIN_WINDOW_WIDTH,
height: MIN_WINDOW_HEIGHT,
Expand Down
18 changes: 9 additions & 9 deletions otty/src/style.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
use iced::Background;
use iced::widget::{container, scrollable};

use super::theme::{IcedColorPalette, ThemeProps};
use super::theme::{IcedColorPalette, ThemeProps, mix_color};
use crate::layout::{RADIUS_CONTROL, RADIUS_OUTER};

pub(crate) fn thin_scroll_style(
palette: IcedColorPalette,
) -> impl Fn(&iced::Theme, scrollable::Status) -> scrollable::Style + 'static {
move |theme, status| {
let mut style = scrollable::default(theme, status);
let radius = iced::border::Radius::from(0.0);
// 滚动条滑块:控件级圆角(VS Code 范式 control=4px)
let radius = iced::border::Radius::from(RADIUS_CONTROL);

style.vertical_rail.border.radius = radius;
style.vertical_rail.scroller.border.radius = radius;
Expand All @@ -34,14 +36,11 @@ pub(crate) fn tree_row_style(
is_selected: bool,
is_hovered: bool,
) -> container::Style {
// 自适应混合(color-mix 等价):选中=玫瑰红~35%(对应 VS Code list.activeSelectionBackground),hover=前景 8%
let background = if is_selected {
let mut color = palette.dim_blue;
color.a = 0.7;
Some(color.into())
Some(mix_color(palette.accent, palette.background, 0.35).into())
} else if is_hovered {
let mut color = palette.overlay;
color.a = 0.6;
Some(color.into())
Some(mix_color(palette.foreground, palette.background, 0.08).into())
} else {
None
};
Expand All @@ -63,7 +62,8 @@ pub(crate) fn menu_panel_style(
border: iced::Border {
width: 0.25,
color: palette.overlay,
radius: iced::border::Radius::new(4.0),
// 菜单属于悬浮层:外层圆角 8px(VS Code 范式 outer=8px)
radius: iced::border::Radius::new(RADIUS_OUTER),
},
..Default::default()
}
Expand Down
30 changes: 28 additions & 2 deletions otty/src/theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,17 @@ use iced::theme::Palette;
use iced::{Color, Theme};
use otty_ui_term::{ColorPalette as TerminalColorPalette, parse_hex_color};

/// 自适应混合色:等价 CSS `color-mix(in srgb, fg P%, bg)`。
/// 用前景色按百分比混合背景色,生成跟随主题的半透明态(hover/选中/高亮)。
pub(crate) fn mix_color(foreground: Color, background: Color, percent: f32) -> Color {
Color::from_rgba(
foreground.r * percent + background.r * (1.0 - percent),
foreground.g * percent + background.g * (1.0 - percent),
foreground.b * percent + background.b * (1.0 - percent),
background.a,
)
}

/// Raw string-based color palette used for serialization and settings.
#[derive(Debug, Clone)]
pub struct ColorPalette {
Expand Down Expand Up @@ -34,6 +45,12 @@ pub struct ColorPalette {
pub dim_white: String,
pub dim_foreground: String,
pub overlay: String,
/// 侧边栏表面色(对应 VS Code sideBar.background)
pub sidebar: String,
/// 活动栏表面色(对应 VS Code activityBar.background)
pub activity_bar: String,
/// UI 强调色(对应 VS Code statusBar.background / 主色)
pub accent: String,
}

impl Default for ColorPalette {
Expand Down Expand Up @@ -68,6 +85,9 @@ impl Default for ColorPalette {
dim_cyan: String::from("#326B73"),
dim_white: String::from("#6C7385"),
overlay: String::from("#232530"),
sidebar: String::from("#232530"),
activity_bar: String::from("#1B1D23"),
accent: String::from("#C45A6D"),
}
}
}
Expand Down Expand Up @@ -140,6 +160,9 @@ pub struct IcedColorPalette {
pub dim_white: Color,
pub dim_foreground: Color,
pub overlay: Color,
pub sidebar: Color,
pub activity_bar: Color,
pub accent: Color,
}

impl From<&ColorPalette> for IcedColorPalette {
Expand Down Expand Up @@ -174,6 +197,9 @@ impl From<&ColorPalette> for IcedColorPalette {
dim_white: parse_hex_color(&p.dim_white),
dim_foreground: parse_hex_color(&p.dim_foreground),
overlay: parse_hex_color(&p.overlay),
sidebar: parse_hex_color(&p.sidebar),
activity_bar: parse_hex_color(&p.activity_bar),
accent: parse_hex_color(&p.accent),
}
}
}
Expand Down Expand Up @@ -213,7 +239,7 @@ impl From<&AppTheme> for Theme {
let palette = Palette {
background: palette.background,
text: palette.foreground,
primary: palette.blue,
primary: palette.accent,
success: palette.green,
danger: palette.red,
warning: palette.yellow,
Expand Down Expand Up @@ -312,6 +338,6 @@ mod tests {

let theme = Theme::from(&app_theme);

assert_eq!(theme.palette().primary, app_theme.iced_palette().blue);
assert_eq!(theme.palette().primary, app_theme.iced_palette().accent);
}
}
31 changes: 22 additions & 9 deletions otty/src/view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ use crate::components::primitive::{
menu_item, resize_grips, sidebar_workspace_panel,
};
use crate::geometry::{anchor_position, menu_height_for_items};
use crate::layout::BUTTON_SIZE_COMPACT;
use crate::layout::{BUTTON_SIZE_COMPACT, RADIUS_OUTER};
use crate::style::menu_panel_style;
use crate::theme::ThemeProps;
use crate::theme::{ThemeProps, mix_color};
use crate::widgets::chrome::ChromeEvent;
use crate::widgets::chrome::view::action_bar;
use crate::widgets::explorer::ExplorerEvent;
Expand Down Expand Up @@ -124,13 +124,8 @@ pub(super) fn view(app: &App) -> Element<'_, AppEvent, Theme, iced::Renderer> {
})
};

let header = view_header(app, theme_props);

let root_layers: Vec<Element<'_, AppEvent, Theme, iced::Renderer>> = vec![
column![header, content_stack]
.width(Length::Fill)
.height(Length::Fill)
.into(),
content_stack.into(),
resize_grips_layer,
];

Expand Down Expand Up @@ -301,9 +296,27 @@ fn view_tab_area<'a>(

let content = view_tab_content(app, theme_props);

column![tab_bar, content]
// VS Code "Editor Border" 范式:编辑器区域 = 主角卡片
// 1px 边框(前景 12% 混合)+ 8px 圆角 + overflow hidden,
// 把编辑器从周围 chrome(侧边栏/活动栏/面板)中独立出来。
container(column![tab_bar, content])
.width(Length::Fill)
.height(Length::Fill)
.clip(true)
.style(move |_| {
let palette = theme_props.theme.iced_palette();
let border_color =
mix_color(palette.foreground, palette.background, 0.12);
iced::widget::container::Style {
border: iced::Border {
width: 1.0,
color: border_color,
radius: iced::border::Radius::from(RADIUS_OUTER),
..Default::default()
},
..Default::default()
}
})
.into()
}

Expand Down
2 changes: 1 addition & 1 deletion otty/src/widgets/quick_launch/view/sidebar_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub(crate) fn view(
) -> Element<'_, QuickLaunchIntent, Theme, iced::Renderer> {
let palette = props.theme.theme.iced_palette().clone();
let icon_color = palette.foreground;
let highlight_icon_color = palette.blue;
let highlight_icon_color = palette.accent;
let error_color = palette.red;
let overlay = palette.overlay;
let row_palette = palette.clone();
Expand Down
4 changes: 2 additions & 2 deletions otty/src/widgets/quick_launch/view/wizard_form.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use iced::{Element, Length, Theme, alignment};
use super::super::event::QuickLaunchIntent;
use super::super::state::WizardEditorState;
use super::super::types::QuickLaunchType;
use crate::layout::{BUTTON_RADIUS_ROUNDED, BUTTON_SIZE_REGULAR};
use crate::layout::{BUTTON_SIZE_REGULAR, RADIUS_CONTROL};
use crate::theme::{IcedColorPalette, ThemeProps};

const SECTION_SPACING: f32 = 16.0;
Expand Down Expand Up @@ -441,7 +441,7 @@ fn button_style(
background,
text_color,
border: iced::Border {
radius: iced::border::Radius::from(BUTTON_RADIUS_ROUNDED),
radius: iced::border::Radius::from(RADIUS_CONTROL),
..Default::default()
},
..Default::default()
Expand Down
Loading
Loading