feat(start): three-part start page (Recent · Welcome · Supporters) that tabs when narrow
Rebuild the Start page as three parts — Recent Files (left), Welcome (center) and Supporters (right) — that sit side by side while they fit. When the page is too narrow for all three it falls back to a tab bar (Recent Files / Welcome / Supporters) showing one section at a time, with Welcome open by default (new StartSection state + StartSectionSelect). The Recent Documents list moves off the left properties slot and into the page itself. The Welcome column's button rows now flex-wrap, and the two intro-video cards sit side by side, wrap to a stacked column when the width gets tight, then shrink to fit the remaining height so they never spill over the status bar. Trimmed the headline to just "Open CAD Studio" (dropped "Welcome to" + the subtitle) and the "Release Notes" button, and tightened the page's side padding. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
6a5402ccae
commit
e2a56033d4
3 changed files with 198 additions and 73 deletions
|
|
@ -208,6 +208,15 @@ struct AddSelectedRestore {
|
||||||
ribbon_lineweight: LineWeight,
|
ribbon_lineweight: LineWeight,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Which Start-page section a narrow (tabbed) Start page is showing.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Eq, Default, Debug)]
|
||||||
|
pub enum StartSection {
|
||||||
|
Recent,
|
||||||
|
#[default]
|
||||||
|
Welcome,
|
||||||
|
Supporters,
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) struct OpenCADStudio {
|
pub(super) struct OpenCADStudio {
|
||||||
start: Instant,
|
start: Instant,
|
||||||
tabs: Vec<DocumentTab>,
|
tabs: Vec<DocumentTab>,
|
||||||
|
|
@ -220,6 +229,9 @@ pub(super) struct OpenCADStudio {
|
||||||
/// Paying Patreon supporters shown on the Start page (name, pledge cents),
|
/// Paying Patreon supporters shown on the Start page (name, pledge cents),
|
||||||
/// fetched once at boot, highest pledge first.
|
/// fetched once at boot, highest pledge first.
|
||||||
patrons: Vec<(String, i64)>,
|
patrons: Vec<(String, i64)>,
|
||||||
|
/// Which Start-page section is shown when the page is too narrow for all
|
||||||
|
/// three side by side and falls back to a tab bar.
|
||||||
|
start_section: StartSection,
|
||||||
/// Read-only editor buffer backing the command-line history dropdown, so
|
/// Read-only editor buffer backing the command-line history dropdown, so
|
||||||
/// the log can be drag-selected across lines and copied (issue #232).
|
/// the log can be drag-selected across lines and copied (issue #232).
|
||||||
/// Rebuilt from the history each time the dropdown is opened.
|
/// Rebuilt from the history each time the dropdown is opened.
|
||||||
|
|
@ -1115,6 +1127,8 @@ pub enum Message {
|
||||||
OpenRecent(PathBuf),
|
OpenRecent(PathBuf),
|
||||||
/// Open a URL in the system browser (start-page intro video, links).
|
/// Open a URL in the system browser (start-page intro video, links).
|
||||||
OpenUrl(String),
|
OpenUrl(String),
|
||||||
|
/// Select which section a narrow (tabbed) Start page shows.
|
||||||
|
StartSectionSelect(StartSection),
|
||||||
/// Scroll the status-bar layout-tab strip horizontally by `delta` px
|
/// Scroll the status-bar layout-tab strip horizontally by `delta` px
|
||||||
/// (negative = left). Driven by the ‹ › arrows next to the tabs.
|
/// (negative = left). Driven by the ‹ › arrows next to the tabs.
|
||||||
ScrollLayoutTabs(f32),
|
ScrollLayoutTabs(f32),
|
||||||
|
|
@ -1960,6 +1974,7 @@ impl OpenCADStudio {
|
||||||
recent_files: recent::load_recent_files(),
|
recent_files: recent::load_recent_files(),
|
||||||
command_line: CommandLine::new(),
|
command_line: CommandLine::new(),
|
||||||
patrons: Vec::new(),
|
patrons: Vec::new(),
|
||||||
|
start_section: StartSection::default(),
|
||||||
history_content: iced::widget::text_editor::Content::new(),
|
history_content: iced::widget::text_editor::Content::new(),
|
||||||
status_bar: StatusBar::new(),
|
status_bar: StatusBar::new(),
|
||||||
cursor_pos: Point::ORIGIN,
|
cursor_pos: Point::ORIGIN,
|
||||||
|
|
|
||||||
|
|
@ -221,6 +221,11 @@ impl OpenCADStudio {
|
||||||
Task::none()
|
Task::none()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Message::StartSectionSelect(section) => {
|
||||||
|
self.start_section = section;
|
||||||
|
Task::none()
|
||||||
|
}
|
||||||
|
|
||||||
Message::ScrollLayoutTabs(dx) => iced::widget::operation::scroll_by(
|
Message::ScrollLayoutTabs(dx) => iced::widget::operation::scroll_by(
|
||||||
iced::advanced::widget::Id::new(crate::ui::statusbar::LAYOUT_TABS_SCROLL_ID),
|
iced::advanced::widget::Id::new(crate::ui::statusbar::LAYOUT_TABS_SCROLL_ID),
|
||||||
iced::widget::scrollable::AbsoluteOffset { x: dx, y: 0.0 },
|
iced::widget::scrollable::AbsoluteOffset { x: dx, y: 0.0 },
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,12 @@ impl OpenCADStudio {
|
||||||
// viewport draws the layout's own geometry (white sheet + entities +
|
// viewport draws the layout's own geometry (white sheet + entities +
|
||||||
// borders) and the floating content viewports blit on top.
|
// borders) and the floating content viewports blit on top.
|
||||||
let viewport_3d: Element<'_, Message> = if tab.is_start {
|
let viewport_3d: Element<'_, Message> = if tab.is_start {
|
||||||
start_page_view(&self.patrons)
|
start_page_view(
|
||||||
|
&self.patrons,
|
||||||
|
&self.recent_files,
|
||||||
|
self.win_size.0,
|
||||||
|
self.start_section,
|
||||||
|
)
|
||||||
} else if is_paper {
|
} else if is_paper {
|
||||||
shader(ViewportPane::model(
|
shader(ViewportPane::model(
|
||||||
&tab.scene,
|
&tab.scene,
|
||||||
|
|
@ -1132,10 +1137,11 @@ impl OpenCADStudio {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Properties / layers panels carry no useful state on the Start tab.
|
// The Start tab shows its own three-panel page (Recent · Welcome ·
|
||||||
// Replace the properties panel with a Recent Documents list there.
|
// Supporters) in place of the viewport, so the left properties slot is
|
||||||
|
// empty there.
|
||||||
let properties_el: Element<'_, Message> = if tab.is_start {
|
let properties_el: Element<'_, Message> = if tab.is_start {
|
||||||
recent_files_panel(&self.recent_files)
|
Space::new().into()
|
||||||
} else if self.show_properties && !self.clean_screen {
|
} else if self.show_properties && !self.clean_screen {
|
||||||
tab.properties.view()
|
tab.properties.view()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1981,19 +1987,18 @@ fn pane_mouse_area<'a>(idx: usize) -> Element<'a, Message> {
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, Message> {
|
pub(super) fn start_page_view<'a>(
|
||||||
|
patrons: &'a [(String, i64)],
|
||||||
|
recents: &'a [std::path::PathBuf],
|
||||||
|
avail_w: f32,
|
||||||
|
active: super::StartSection,
|
||||||
|
) -> Element<'a, Message> {
|
||||||
const TEXT: Color = Color {
|
const TEXT: Color = Color {
|
||||||
r: 0.94,
|
r: 0.94,
|
||||||
g: 0.93,
|
g: 0.93,
|
||||||
b: 0.92,
|
b: 0.92,
|
||||||
a: 1.0,
|
a: 1.0,
|
||||||
};
|
};
|
||||||
const MUTED: Color = Color {
|
|
||||||
r: 0.62,
|
|
||||||
g: 0.62,
|
|
||||||
b: 0.62,
|
|
||||||
a: 1.0,
|
|
||||||
};
|
|
||||||
const CARD_BG: Color = Color {
|
const CARD_BG: Color = Color {
|
||||||
r: 0.12,
|
r: 0.12,
|
||||||
g: 0.12,
|
g: 0.12,
|
||||||
|
|
@ -2007,20 +2012,7 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
a: 1.0,
|
a: 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Brand-tinted "Welcome to" — the "OpenCADStudio" word takes the accent colour
|
let headline = text("Open CAD Studio").size(40).color(BRAND);
|
||||||
// (Thunderbird-style coloured headline split).
|
|
||||||
let headline = row![
|
|
||||||
text("Welcome to ").size(40).color(TEXT),
|
|
||||||
text("Open CAD Studio").size(40).color(BRAND),
|
|
||||||
]
|
|
||||||
.align_y(iced::Center);
|
|
||||||
|
|
||||||
let subtitle = text(
|
|
||||||
"Open CAD Studio is an open-source CAD viewer and editor — a gift from contributors like you. \
|
|
||||||
Open a DWG/DXF file, start a new drawing, or help shape what comes next.",
|
|
||||||
)
|
|
||||||
.size(13)
|
|
||||||
.color(MUTED);
|
|
||||||
|
|
||||||
// Plain outlined button (Open / New / Help / Contribute).
|
// Plain outlined button (Open / New / Help / Contribute).
|
||||||
let outline_btn = |label: &'static str, msg: Message| {
|
let outline_btn = |label: &'static str, msg: Message| {
|
||||||
|
|
@ -2097,38 +2089,32 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
let primary_row = row![
|
let primary_row = WrapFlow::new(vec![
|
||||||
outline_btn("New Drawing", Message::TabNew),
|
outline_btn("New Drawing", Message::TabNew).into(),
|
||||||
outline_btn("Open File…", Message::OpenFile),
|
outline_btn("Open File…", Message::OpenFile).into(),
|
||||||
donate_btn,
|
donate_btn.into(),
|
||||||
]
|
])
|
||||||
.spacing(12)
|
.spacing_x(12.0)
|
||||||
.align_y(iced::Center);
|
.row_h(48.0);
|
||||||
|
|
||||||
#[cfg_attr(target_arch = "wasm32", allow(unused_mut))]
|
#[cfg_attr(target_arch = "wasm32", allow(unused_mut))]
|
||||||
let mut secondary_row = row![
|
let mut secondary_items: Vec<Element<'a, Message>> = vec![
|
||||||
outline_btn(
|
outline_btn(
|
||||||
"Send Feedback",
|
"Send Feedback",
|
||||||
Message::RibbonToolClick {
|
Message::RibbonToolClick {
|
||||||
tool_id: "REPORT".to_string(),
|
tool_id: "REPORT".to_string(),
|
||||||
event: crate::modules::ModuleEvent::Command("REPORT".to_string()),
|
event: crate::modules::ModuleEvent::Command("REPORT".to_string()),
|
||||||
},
|
},
|
||||||
),
|
)
|
||||||
outline_btn(
|
.into(),
|
||||||
"Release Notes",
|
outline_btn("Plugins", Message::PluginManagerOpen).into(),
|
||||||
Message::RibbonToolClick {
|
|
||||||
tool_id: "CHANGELOG".to_string(),
|
|
||||||
event: crate::modules::ModuleEvent::Command("CHANGELOG".to_string()),
|
|
||||||
},
|
|
||||||
),
|
|
||||||
outline_btn("Plugins", Message::PluginManagerOpen),
|
|
||||||
];
|
];
|
||||||
// The web build is already in the browser, so only the desktop offers a
|
// The web build is already in the browser, so only the desktop offers a
|
||||||
// link to the web version.
|
// link to the web version.
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
{
|
{
|
||||||
// Bright ribbon blue (matches the active-tool accent), filled.
|
// Bright ribbon blue (matches the active-tool accent), filled.
|
||||||
secondary_row = secondary_row.push(
|
secondary_items.push(
|
||||||
button(text("OCS Web").size(14).color(Color::WHITE))
|
button(text("OCS Web").size(14).color(Color::WHITE))
|
||||||
.on_press(Message::RibbonToolClick {
|
.on_press(Message::RibbonToolClick {
|
||||||
tool_id: "WEBVERSION".to_string(),
|
tool_id: "WEBVERSION".to_string(),
|
||||||
|
|
@ -2162,10 +2148,13 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
radius: 6.0.into(),
|
radius: 6.0.into(),
|
||||||
},
|
},
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}),
|
})
|
||||||
|
.into(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let secondary_row = secondary_row.spacing(12).align_y(iced::Center);
|
let secondary_row = WrapFlow::new(secondary_items)
|
||||||
|
.spacing_x(12.0)
|
||||||
|
.row_h(44.0);
|
||||||
|
|
||||||
// Intro videos: clickable thumbnails with a play badge, side by side.
|
// Intro videos: clickable thumbnails with a play badge, side by side.
|
||||||
// Native iced has no embedded web player, so a click opens the video in the
|
// Native iced has no embedded web player, so a click opens the video in the
|
||||||
|
|
@ -2198,7 +2187,7 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
}
|
}
|
||||||
// One clickable video card: cover-fitted thumbnail with a white play triangle
|
// One clickable video card: cover-fitted thumbnail with a white play triangle
|
||||||
// on a translucent disc, opening `url` in the browser on click.
|
// on a translucent disc, opening `url` in the browser on click.
|
||||||
let video_card = |handle: iced::widget::image::Handle, url: &str| {
|
let video_card = |handle: iced::widget::image::Handle, url: &str, card_w: f32, card_h: f32| {
|
||||||
let thumb = iced::widget::image(handle)
|
let thumb = iced::widget::image(handle)
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
|
|
@ -2233,8 +2222,8 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
.center_y(Fill);
|
.center_y(Fill);
|
||||||
mouse_area(
|
mouse_area(
|
||||||
container(iced::widget::stack![thumb, play_badge])
|
container(iced::widget::stack![thumb, play_badge])
|
||||||
.width(iced::Length::Fixed(352.0))
|
.width(iced::Length::Fixed(card_w))
|
||||||
.height(iced::Length::Fixed(198.0))
|
.height(iced::Length::Fixed(card_h))
|
||||||
.style(|_: &Theme| container::Style {
|
.style(|_: &Theme| container::Style {
|
||||||
background: Some(Background::Color(CARD_BG)),
|
background: Some(Background::Color(CARD_BG)),
|
||||||
border: Border {
|
border: Border {
|
||||||
|
|
@ -2249,14 +2238,50 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
.interaction(iced::mouse::Interaction::Pointer)
|
.interaction(iced::mouse::Interaction::Pointer)
|
||||||
.on_press(Message::OpenUrl(url.to_string()))
|
.on_press(Message::OpenUrl(url.to_string()))
|
||||||
};
|
};
|
||||||
let cards = container(
|
// The two video cards keep their 16:9-ish aspect. They sit side by side
|
||||||
iced::widget::row![
|
// while there's room; when the width gets tight they WRAP to a stacked
|
||||||
video_card(intro_thumb_1(), INTRO_VIDEO_URL),
|
// column; and when even the stack won't fit the remaining height they
|
||||||
video_card(intro_thumb_2(), INTRO_VIDEO_URL_2),
|
// SHRINK to fit — never overflowing onto the status bar.
|
||||||
]
|
let cards = container(responsive(move |size| {
|
||||||
.spacing(12),
|
const GAP: f32 = 12.0;
|
||||||
)
|
const MAX_W: f32 = 352.0;
|
||||||
.center_x(Fill);
|
let aspect = 352.0f32 / 198.0; // width / height
|
||||||
|
|
||||||
|
// Wrap to a stacked column once side-by-side cards would get too small.
|
||||||
|
let side_w = ((size.width - GAP) / 2.0).min(MAX_W);
|
||||||
|
let stacked = side_w < 220.0;
|
||||||
|
|
||||||
|
let (mut cw, mut ch, rows) = if stacked {
|
||||||
|
let w = size.width.min(MAX_W);
|
||||||
|
(w, w / aspect, 2.0f32)
|
||||||
|
} else {
|
||||||
|
(side_w, side_w / aspect, 1.0f32)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Shrink to fit the height the page can give the cards.
|
||||||
|
let needed_h = ch * rows + if rows > 1.0 { GAP } else { 0.0 };
|
||||||
|
if needed_h > size.height && needed_h > 1.0 {
|
||||||
|
let scale = (size.height / needed_h).max(0.0);
|
||||||
|
cw *= scale;
|
||||||
|
ch *= scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
let c1 = video_card(intro_thumb_1(), INTRO_VIDEO_URL, cw, ch);
|
||||||
|
let c2 = video_card(intro_thumb_2(), INTRO_VIDEO_URL_2, cw, ch);
|
||||||
|
let inner: Element<'_, Message> = if stacked {
|
||||||
|
column![c1, c2].spacing(GAP).into()
|
||||||
|
} else {
|
||||||
|
iced::widget::row![c1, c2].spacing(GAP).into()
|
||||||
|
};
|
||||||
|
container(inner)
|
||||||
|
.center_x(Fill)
|
||||||
|
.center_y(Fill)
|
||||||
|
.width(Fill)
|
||||||
|
.height(Fill)
|
||||||
|
.into()
|
||||||
|
}))
|
||||||
|
.width(Fill)
|
||||||
|
.height(Fill);
|
||||||
|
|
||||||
// Buttons sit on a transparent container with a large, brand-tinted
|
// Buttons sit on a transparent container with a large, brand-tinted
|
||||||
// ambient shadow (offset = 0, big blur) — produces a soft halo behind
|
// ambient shadow (offset = 0, big blur) — produces a soft halo behind
|
||||||
|
|
@ -2287,14 +2312,12 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
let content = column![
|
let content = column![
|
||||||
Space::new().height(iced::Length::Fixed(28.0)),
|
Space::new().height(iced::Length::Fixed(28.0)),
|
||||||
container(headline).center_x(Fill),
|
container(headline).center_x(Fill),
|
||||||
container(subtitle).center_x(Fill).padding([10, 60]),
|
|
||||||
Space::new().height(iced::Length::Fixed(22.0)),
|
Space::new().height(iced::Length::Fixed(22.0)),
|
||||||
container(primary_glow).center_x(Fill),
|
container(primary_glow).center_x(Fill),
|
||||||
Space::new().height(iced::Length::Fixed(10.0)),
|
Space::new().height(iced::Length::Fixed(10.0)),
|
||||||
container(secondary_row).center_x(Fill),
|
container(secondary_row).center_x(Fill),
|
||||||
Space::new().height(iced::Length::Fixed(40.0)),
|
Space::new().height(iced::Length::Fixed(24.0)),
|
||||||
cards,
|
cards,
|
||||||
Space::new().height(Fill),
|
|
||||||
]
|
]
|
||||||
.spacing(0)
|
.spacing(0)
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
|
|
@ -2309,6 +2332,18 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
b: 0.085,
|
b: 0.085,
|
||||||
a: 1.0,
|
a: 1.0,
|
||||||
};
|
};
|
||||||
|
// Three parts — Recent Files · Welcome · Supporters. They sit side by side
|
||||||
|
// while they fit; when the page is too narrow it becomes a tab bar with the
|
||||||
|
// Welcome tab open by default.
|
||||||
|
let recent_w = 280.0f32;
|
||||||
|
let sup_w = 240.0f32;
|
||||||
|
let welcome_min = 480.0f32;
|
||||||
|
let avail = (avail_w - 16.0).max(0.0); // minus the page's l/r padding
|
||||||
|
let fits_all = avail >= recent_w + welcome_min + sup_w;
|
||||||
|
|
||||||
|
let recent = recent_files_panel(recents);
|
||||||
|
let welcome = container(content).width(Fill).height(Fill);
|
||||||
|
|
||||||
// Right rail: Patreon supporters, fetched at boot. When the list is empty
|
// Right rail: Patreon supporters, fetched at boot. When the list is empty
|
||||||
// (no token configured / offline) only the "Support on Patreon" button
|
// (no token configured / offline) only the "Support on Patreon" button
|
||||||
// shows, so the rail always invites support.
|
// shows, so the rail always invites support.
|
||||||
|
|
@ -2385,19 +2420,89 @@ pub(super) fn start_page_view<'a>(patrons: &'a [(String, i64)]) -> Element<'a, M
|
||||||
.into()
|
.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
container(iced::widget::row![
|
let body: Element<'a, Message> = if fits_all {
|
||||||
container(content).width(Fill).height(Fill),
|
iced::widget::row![recent, welcome, supporters]
|
||||||
supporters,
|
.spacing(16)
|
||||||
])
|
.into()
|
||||||
|
} else {
|
||||||
|
let tab_btn = |label: &'static str, section: super::StartSection| {
|
||||||
|
let is_active = active == section;
|
||||||
|
button(text(label).size(14))
|
||||||
|
.on_press(Message::StartSectionSelect(section))
|
||||||
|
.padding([8, 18])
|
||||||
|
.style(move |_: &Theme, status| button::Style {
|
||||||
|
background: Some(Background::Color(match (is_active, status) {
|
||||||
|
(true, _) => Color {
|
||||||
|
r: 0.18,
|
||||||
|
g: 0.18,
|
||||||
|
b: 0.20,
|
||||||
|
a: 1.0,
|
||||||
|
},
|
||||||
|
(false, button::Status::Hovered) => Color {
|
||||||
|
r: 0.14,
|
||||||
|
g: 0.14,
|
||||||
|
b: 0.16,
|
||||||
|
a: 1.0,
|
||||||
|
},
|
||||||
|
_ => Color::TRANSPARENT,
|
||||||
|
})),
|
||||||
|
text_color: if is_active {
|
||||||
|
TEXT
|
||||||
|
} else {
|
||||||
|
Color {
|
||||||
|
r: 0.62,
|
||||||
|
g: 0.62,
|
||||||
|
b: 0.62,
|
||||||
|
a: 1.0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
border: Border {
|
||||||
|
color: if is_active { BRAND } else { Color::TRANSPARENT },
|
||||||
|
width: if is_active { 1.0 } else { 0.0 },
|
||||||
|
radius: 6.0.into(),
|
||||||
|
},
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
let tab_bar = iced::widget::row![
|
||||||
|
tab_btn("Recent Files", super::StartSection::Recent),
|
||||||
|
tab_btn("Welcome", super::StartSection::Welcome),
|
||||||
|
tab_btn("Supporters", super::StartSection::Supporters),
|
||||||
|
]
|
||||||
|
.spacing(6);
|
||||||
|
let section_body: Element<'a, Message> = match active {
|
||||||
|
super::StartSection::Recent => container(recent)
|
||||||
|
.width(Fill)
|
||||||
|
.height(Fill)
|
||||||
|
.center_x(Fill)
|
||||||
|
.into(),
|
||||||
|
super::StartSection::Welcome => welcome.into(),
|
||||||
|
super::StartSection::Supporters => container(supporters)
|
||||||
|
.width(Fill)
|
||||||
|
.height(Fill)
|
||||||
|
.center_x(Fill)
|
||||||
|
.into(),
|
||||||
|
};
|
||||||
|
column![
|
||||||
|
container(tab_bar).center_x(Fill),
|
||||||
|
Space::new().height(iced::Length::Fixed(12.0)),
|
||||||
|
section_body,
|
||||||
|
]
|
||||||
|
.width(Fill)
|
||||||
|
.height(Fill)
|
||||||
|
.into()
|
||||||
|
};
|
||||||
|
|
||||||
|
container(body)
|
||||||
.style(|_: &Theme| container::Style {
|
.style(|_: &Theme| container::Style {
|
||||||
background: Some(Background::Color(PAGE_BG)),
|
background: Some(Background::Color(PAGE_BG)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
.padding(iced::Padding {
|
.padding(iced::Padding {
|
||||||
top: 40.0,
|
top: 16.0,
|
||||||
right: 60.0,
|
right: 8.0,
|
||||||
bottom: 40.0,
|
bottom: 16.0,
|
||||||
left: 60.0,
|
left: 8.0,
|
||||||
})
|
})
|
||||||
.width(Fill)
|
.width(Fill)
|
||||||
.height(Fill)
|
.height(Fill)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue