From ccb67d9a952db94b76b4c44cfccffa1cb38126ff Mon Sep 17 00:00:00 2001 From: Maze Winther Date: Fri, 24 Jul 2026 14:15:21 +0200 Subject: [PATCH] feat(desktop): scaffold shell with browser/preview/inspector/timeline panels --- apps/desktop/src/main.rs | 39 ++++------------------ apps/desktop/src/panels/browser.rs | 23 +++++++++++++ apps/desktop/src/panels/inspector.rs | 23 +++++++++++++ apps/desktop/src/panels/mod.rs | 9 +++++ apps/desktop/src/panels/preview.rs | 20 ++++++++++++ apps/desktop/src/panels/timeline.rs | 20 ++++++++++++ apps/desktop/src/shell.rs | 49 ++++++++++++++++++++++++++++ 7 files changed, 150 insertions(+), 33 deletions(-) create mode 100644 apps/desktop/src/panels/browser.rs create mode 100644 apps/desktop/src/panels/inspector.rs create mode 100644 apps/desktop/src/panels/mod.rs create mode 100644 apps/desktop/src/panels/preview.rs create mode 100644 apps/desktop/src/panels/timeline.rs create mode 100644 apps/desktop/src/shell.rs diff --git a/apps/desktop/src/main.rs b/apps/desktop/src/main.rs index d4e1c7e5..37d40468 100644 --- a/apps/desktop/src/main.rs +++ b/apps/desktop/src/main.rs @@ -1,38 +1,13 @@ use gpui::{ - App, Application, Bounds, Context, SharedString, TitlebarOptions, Window, WindowBounds, - WindowOptions, div, prelude::*, px, size, + px, size, App, AppContext, Application, Bounds, SharedString, TitlebarOptions, WindowBounds, + WindowOptions, }; +mod panels; +mod shell; mod theme; -use theme::ActiveTheme; - -struct Root { - status: SharedString, -} - -impl Render for Root { - fn render(&mut self, window: &mut Window, _cx: &mut Context) -> impl IntoElement { - let colors = window.theme().colors; - - div() - .flex() - .flex_col() - .gap_2() - .size_full() - .justify_center() - .items_center() - .bg(colors.background) - .text_color(colors.foreground) - .child(div().text_xl().child("OpenCut")) - .child( - div() - .text_sm() - .text_color(colors.muted_foreground) - .child(self.status.clone()), - ) - } -} +use shell::Shell; fn main() { #[cfg(target_os = "linux")] @@ -73,9 +48,7 @@ fn main() { }) .detach(); - Root { - status: "desktop shell scaffold".into(), - } + Shell::new(cx) }) }, ) diff --git a/apps/desktop/src/panels/browser.rs b/apps/desktop/src/panels/browser.rs new file mode 100644 index 00000000..16df7989 --- /dev/null +++ b/apps/desktop/src/panels/browser.rs @@ -0,0 +1,23 @@ +use gpui::{div, prelude::*, Context, Window}; + +use crate::theme::ActiveTheme; + +pub(crate) struct Browser; + +impl Render for Browser { + fn render(&mut self, window: &mut Window, _cx: &mut Context) -> impl IntoElement { + let colors = window.theme().colors; + + div() + .flex() + .w_1_4() + .h_full() + .items_center() + .justify_center() + .border_r_1() + .border_color(colors.sidebar_border) + .bg(colors.sidebar) + .text_color(colors.sidebar_foreground) + .child("Browser") + } +} diff --git a/apps/desktop/src/panels/inspector.rs b/apps/desktop/src/panels/inspector.rs new file mode 100644 index 00000000..aa9134aa --- /dev/null +++ b/apps/desktop/src/panels/inspector.rs @@ -0,0 +1,23 @@ +use gpui::{div, prelude::*, Context, Window}; + +use crate::theme::ActiveTheme; + +pub(crate) struct Inspector; + +impl Render for Inspector { + fn render(&mut self, window: &mut Window, _cx: &mut Context) -> impl IntoElement { + let colors = window.theme().colors; + + div() + .flex() + .w_1_4() + .h_full() + .items_center() + .justify_center() + .border_l_1() + .border_color(colors.border) + .bg(colors.card) + .text_color(colors.card_foreground) + .child("Inspector") + } +} diff --git a/apps/desktop/src/panels/mod.rs b/apps/desktop/src/panels/mod.rs new file mode 100644 index 00000000..de594e35 --- /dev/null +++ b/apps/desktop/src/panels/mod.rs @@ -0,0 +1,9 @@ +mod browser; +mod inspector; +mod preview; +mod timeline; + +pub(crate) use browser::Browser; +pub(crate) use inspector::Inspector; +pub(crate) use preview::Preview; +pub(crate) use timeline::Timeline; diff --git a/apps/desktop/src/panels/preview.rs b/apps/desktop/src/panels/preview.rs new file mode 100644 index 00000000..e8a8069a --- /dev/null +++ b/apps/desktop/src/panels/preview.rs @@ -0,0 +1,20 @@ +use gpui::{div, prelude::*, Context, Window}; + +use crate::theme::ActiveTheme; + +pub(crate) struct Preview; + +impl Render for Preview { + fn render(&mut self, window: &mut Window, _cx: &mut Context) -> impl IntoElement { + let colors = window.theme().colors; + + div() + .flex() + .w_1_2() + .h_full() + .items_center() + .justify_center() + .bg(colors.background) + .child("Preview") + } +} diff --git a/apps/desktop/src/panels/timeline.rs b/apps/desktop/src/panels/timeline.rs new file mode 100644 index 00000000..db33b8bc --- /dev/null +++ b/apps/desktop/src/panels/timeline.rs @@ -0,0 +1,20 @@ +use gpui::{div, prelude::*, Context, Window}; + +use crate::theme::ActiveTheme; + +pub(crate) struct Timeline; + +impl Render for Timeline { + fn render(&mut self, window: &mut Window, _cx: &mut Context) -> impl IntoElement { + let colors = window.theme().colors; + + div() + .flex() + .h_1_3() + .items_center() + .justify_center() + .bg(colors.card) + .text_color(colors.card_foreground) + .child("Timeline") + } +} diff --git a/apps/desktop/src/shell.rs b/apps/desktop/src/shell.rs new file mode 100644 index 00000000..375f3715 --- /dev/null +++ b/apps/desktop/src/shell.rs @@ -0,0 +1,49 @@ +use gpui::{div, prelude::*, App, Context, Entity, Window}; + +use crate::panels::{Browser, Inspector, Preview, Timeline}; +use crate::theme::ActiveTheme; + +// Panels are entities created once in `new`, not via `cx.new` inline in +// `render`, so each keeps its own state across renders instead of being +// torn down and rebuilt on every frame. +pub(crate) struct Shell { + browser: Entity, + preview: Entity, + inspector: Entity, + timeline: Entity, +} + +impl Shell { + pub(crate) fn new(cx: &mut App) -> Self { + Self { + browser: cx.new(|_| Browser), + preview: cx.new(|_| Preview), + inspector: cx.new(|_| Inspector), + timeline: cx.new(|_| Timeline), + } + } +} + +impl Render for Shell { + fn render(&mut self, window: &mut Window, _cx: &mut Context) -> impl IntoElement { + let colors = window.theme().colors; + + div() + .flex() + .flex_col() + .size_full() + .bg(colors.background) + .text_color(colors.foreground) + .child( + div() + .flex() + .h_2_3() + .border_b_1() + .border_color(colors.border) + .child(self.browser.clone()) + .child(self.preview.clone()) + .child(self.inspector.clone()), + ) + .child(self.timeline.clone()) + } +}