feat(desktop): scaffold shell with browser/preview/inspector/timeline panels

This commit is contained in:
Maze Winther 2026-07-24 14:15:21 +02:00
parent cef8766acb
commit ccb67d9a95
7 changed files with 150 additions and 33 deletions

View File

@ -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<Self>) -> 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)
})
},
)

View File

@ -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<Self>) -> 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")
}
}

View File

@ -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<Self>) -> 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")
}
}

View File

@ -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;

View File

@ -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<Self>) -> impl IntoElement {
let colors = window.theme().colors;
div()
.flex()
.w_1_2()
.h_full()
.items_center()
.justify_center()
.bg(colors.background)
.child("Preview")
}
}

View File

@ -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<Self>) -> 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")
}
}

49
apps/desktop/src/shell.rs Normal file
View File

@ -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<Browser>,
preview: Entity<Preview>,
inspector: Entity<Inspector>,
timeline: Entity<Timeline>,
}
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<Self>) -> 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())
}
}