add community creation flow

This commit is contained in:
2026-09-19 08:14:03 +07:00
parent 907347d002
commit 0328d35945
8 changed files with 126 additions and 33 deletions
+1
View File
@@ -12,6 +12,7 @@ state = { path = "../state" }
device = { path = "../device" }
chat = { path = "../chat" }
chat_ui = { path = "../chat_ui" }
community = { path = "../community" }
settings = { path = "../settings" }
person = { path = "../person" }
auto_update = { path = "../auto_update" }
+74 -10
View File
@@ -5,9 +5,10 @@ use std::rc::Rc;
use auto_update::AutoUpdater;
use chat::{ChatEvent, ChatRegistry, Room, RoomKind};
use common::TimestampExt;
use community::{CommunityEvent, CommunityMetadata, CommunityRegistry};
use gpui::prelude::FluentBuilder;
use gpui::{
AnyElement, App, Context, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
AnyElement, App, AppContext, Context, ElementId, Entity, EventEmitter, FocusHandle, Focusable,
InteractiveElement, IntoElement, ParentElement, Render, SharedString, Styled, Subscription,
UniformListScrollHandle, Window, div, px, retain_all, uniform_list,
};
@@ -20,12 +21,13 @@ use ui::avatar::Avatar;
use ui::button::{Button, ButtonVariants};
use ui::dock::{Panel, PanelEvent};
use ui::indicator::Indicator;
use ui::input::{Input, InputState};
use ui::menu::{ContextMenu, DropdownMenu, PopupMenuItem};
use ui::nav_item::NavItem;
use ui::scroll::Scrollbar;
use ui::{
Icon, IconName, Sizable, StyledExt, TRAFFIC_LIGHT_PADDING, h_flex, title_bar_drag_handlers,
v_flex,
Icon, IconName, Sizable, StyledExt, TRAFFIC_LIGHT_PADDING, WindowExtension, h_flex,
title_bar_drag_handlers, v_flex,
};
use crate::Command;
@@ -34,7 +36,7 @@ mod entry;
mod tree;
pub(crate) use entry::RoomEntry;
use tree::{SidebarRow, TreeRow, TreeRowKind, TreeSection, dummy_communities};
use tree::{SidebarRow, TreeRow, TreeRowKind, TreeSection};
/// Sidebar.
pub struct Sidebar {
@@ -58,6 +60,7 @@ impl Sidebar {
pub fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let settings = AppSettings::global(cx).read(cx).entity().clone();
let chat = ChatRegistry::global(cx);
let communities = CommunityRegistry::global(cx);
let mut subscriptions = smallvec![];
@@ -74,6 +77,14 @@ impl Sidebar {
this.restore_state(cx);
}));
subscriptions.push(
cx.subscribe(&communities, |_this, _communities, event, _cx| {
if let CommunityEvent::Error(error) = event {
log::error!("community: {error}");
}
}),
);
Self {
focus_handle: cx.focus_handle(),
scroll_handle: UniformListScrollHandle::new(),
@@ -145,6 +156,36 @@ impl Sidebar {
self.pinned_rooms.contains(&room_id)
}
fn new_community(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let name_input = cx.new(|cx| InputState::new(window, cx).placeholder("Community name"));
window.open_modal(cx, move |this, _window, _cx| {
let name_input = name_input.clone();
this.width(px(380.))
.confirm()
.title("New community")
.child(Input::new(&name_input))
.on_ok(move |_event, _window, cx| {
let name = name_input.read(cx).value().trim().to_owned();
if name.is_empty() {
return false;
}
let metadata = CommunityMetadata {
name,
..CommunityMetadata::default()
};
CommunityRegistry::global(cx)
.update(cx, |registry, cx| registry.create(metadata, cx));
true
})
});
}
fn tree_rows(&self, cx: &App) -> Vec<SidebarRow> {
let chat = ChatRegistry::global(cx);
let chat = chat.read(cx);
@@ -197,7 +238,9 @@ impl Sidebar {
}
}
let communities = dummy_communities();
let registry = CommunityRegistry::global(cx);
let communities = registry.read(cx).communities();
rows.push(SidebarRow::Section {
section: TreeSection::Community,
count: communities.len(),
@@ -213,9 +256,15 @@ impl Sidebar {
rows.extend(
communities
.iter()
.map(|entry| SidebarRow::Community { entry, depth: 1 }),
.cloned()
.map(|community| SidebarRow::Community {
community,
depth: 1,
}),
);
}
rows.push(SidebarRow::NewCommunity { depth: 1 });
}
let messages = chat.rooms(&RoomKind::Ongoing, cx);
@@ -345,13 +394,28 @@ impl Sidebar {
)
.into_any_element()
}
SidebarRow::Community { entry, depth } => TreeRow::new(
SidebarRow::Community { community, depth } => {
let community = community.read(cx);
TreeRow::new(
ElementId::NamedInteger("tree-row".into(), index as u64),
TreeRowKind::Community,
community.name(),
)
.depth(*depth)
.avatar(community.id().to_hex())
.into_any_element()
}
SidebarRow::NewCommunity { depth } => TreeRow::new(
ElementId::NamedInteger("tree-row".into(), index as u64),
TreeRowKind::Community,
entry.name,
TreeRowKind::Hint,
"New community",
)
.depth(*depth)
.avatar(entry.name)
.icon(IconName::Plus)
.on_click(cx.listener(|this, _event, window, cx| {
this.new_community(window, cx);
}))
.into_any_element(),
SidebarRow::Hint { text, depth } => TreeRow::new(
ElementId::NamedInteger("tree-row".into(), index as u64),
+5 -17
View File
@@ -1,6 +1,7 @@
use std::rc::Rc;
use chat::Room;
use community::Community;
use gpui::prelude::FluentBuilder;
use gpui::{
App, ClickEvent, ElementId, Entity, InteractiveElement, IntoElement, ParentElement, RenderOnce,
@@ -66,7 +67,10 @@ pub enum SidebarRow {
pinned: bool,
},
Community {
entry: &'static CommunityEntry,
community: Entity<Community>,
depth: u8,
},
NewCommunity {
depth: u8,
},
Hint {
@@ -75,22 +79,6 @@ pub enum SidebarRow {
},
}
pub struct CommunityEntry {
pub name: &'static str,
}
pub fn dummy_communities() -> &'static [CommunityEntry] {
// TODO(concord): replace with CommunityRegistry communities, see docs/concord-usage.md.
&[
CommunityEntry {
name: "Coop Contributors",
},
CommunityEntry {
name: "Nostr Design",
},
]
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TreeRowKind {
Section,