//! ProjectGrid: flex-wrap grid of ProjectBox cards. //! //! Lays out projects in a responsive grid that wraps when the window is wide //! enough for multiple columns. use gpui::*; use crate::components::project_box::ProjectBox; use crate::state::AppState; use crate::theme; // ── ProjectGrid View ──────────────────────────────────────────────── pub struct ProjectGrid { app_state: Entity, /// One ProjectBox entity per project. project_boxes: Vec>, } impl ProjectGrid { pub fn new(app_state: Entity, cx: &mut Context) -> Self { // Clone projects out of state to avoid borrowing cx through app_state let projects: Vec<_> = { let state = app_state.read(cx); state.projects.clone() }; let project_boxes: Vec> = projects .into_iter() .map(|proj| { cx.new(|cx| { let mut pb = ProjectBox::new(proj); pb.init_subviews(cx); pb }) }) .collect(); Self { app_state, project_boxes, } } } impl Render for ProjectGrid { fn render(&mut self, _window: &mut Window, _cx: &mut Context) -> impl IntoElement { let mut grid = div() .id("project-grid") .flex_1() .w_full() .h_full() .flex() .flex_row() .flex_wrap() .gap(px(8.0)) .p(px(8.0)) .bg(theme::CRUST) .overflow_y_scroll(); for pb in &self.project_boxes { grid = grid.child(pb.clone()); } if self.project_boxes.is_empty() { grid = grid.child( div() .flex_1() .flex() .items_center() .justify_center() .text_size(px(16.0)) .text_color(theme::OVERLAY0) .child("No projects. Press Ctrl+N to add one."), ); } grid } }