update community sidebar
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
# Community sidebar
|
||||
|
||||
When a community is opened from the sidebar, the sidebar's content becomes the
|
||||
community's own channel/member browser. Going back restores the normal tabs.
|
||||
|
||||
```
|
||||
+------------------+--------------------------------+
|
||||
| [<-] community | |
|
||||
| banner | |
|
||||
| v Channels 3 | messages |
|
||||
| # general | |
|
||||
| # random | |
|
||||
| v Admins 1 | |
|
||||
| @owner | |
|
||||
| v Members 2 +--------------------------------+
|
||||
| @alice | [ composer ] |
|
||||
| @bob | |
|
||||
+------------------+--------------------------------+
|
||||
```
|
||||
|
||||
## Current state
|
||||
|
||||
* `community_ui::CommunityPanel` renders its own 220px left column (channels +
|
||||
members) next to the timeline.
|
||||
* `Sidebar` renders the Recents/Chats/Communities tabs, and `Sidebar::open_community`
|
||||
records the community as recent and asks `CommunityRegistry` to emit
|
||||
`CommunityEvent::Open`, which `Workspace` turns into a center dock panel.
|
||||
* `Community` already folds channels (`state().channels`), members, the control
|
||||
roster (`control().roles`), the community icon, and the banner (`metadata.banner`).
|
||||
|
||||
## Plan
|
||||
|
||||
### 1. Backend: community crate
|
||||
|
||||
`crates/community/src/community.rs`
|
||||
|
||||
* Add `CommunityEvent::Close(CommunityId)` and `CommunityEvent::Channel(CommunityId, ChannelId)`.
|
||||
* Add `active: Option<ChannelId>` to `Community`, with:
|
||||
* `pub fn active_channel(&self) -> Option<ChannelId>` — the selected channel,
|
||||
defaulting to the first one.
|
||||
* `pub fn set_active_channel(&mut self, ChannelId, &mut Context<Self>)` — stores
|
||||
it and emits `Channel`.
|
||||
* Add `banner: Option<PathBuf>` resolved from `metadata.banner` the same way the
|
||||
icon already is, exposed as `pub fn banner(&self) -> Option<PathBuf>`.
|
||||
|
||||
`crates/community/src/lib.rs`
|
||||
|
||||
* Add `CommunityRegistry::emit_close(&mut self, CommunityId, &mut Window, &mut Context<Self>)`,
|
||||
mirroring `emit_community`, emitting `Close`.
|
||||
|
||||
`crates/community/src/sync.rs`
|
||||
|
||||
* Rename `resolve_icon` to `resolve_image` (it takes any `ImageRef`).
|
||||
|
||||
### 2. `community_ui`: panel becomes timeline-only
|
||||
|
||||
* Drop the internal channel/member column and its helpers.
|
||||
* Resolve the shown channel from `Community::active_channel` on every load and
|
||||
reload, and subscribe to `CommunityEvent::Channel` to follow sidebar clicks
|
||||
(deferred, because the community is being updated when it emits).
|
||||
|
||||
### 3. `workspace`: sidebar renders the community
|
||||
|
||||
`crates/workspace/src/sidebar/mod.rs`
|
||||
|
||||
* New state: `community: Option<WeakEntity<Community>>` and three section flags.
|
||||
* `open_community` also sets `self.community`; new `close_community` clears it and
|
||||
asks the registry to emit `Close`.
|
||||
* `render` picks between the existing tabs and `render_community`.
|
||||
* `render_user` keeps the account button as usual and adds a back button on the
|
||||
right when a community is open.
|
||||
* `render_community` pins the optional banner image and scrolls everything below
|
||||
it: collapsible Channels, Admins (members where `control().roles.is_staff`), and
|
||||
Members sections. Every row is a `TreeRow` — the component the sidebar's own
|
||||
lists use — so height, padding, typography, hover, and selection match, and each
|
||||
row is wrapped `flex_shrink_0` so the list scrolls instead of squashing.
|
||||
* Observe the registry so member/roster changes re-render the lists.
|
||||
|
||||
`crates/workspace/src/lib.rs`
|
||||
|
||||
* Remember the opened `CommunityPanel` so `CommunityEvent::Close` can close it:
|
||||
activate it, focus the group, then dispatch `ClosePanel`.
|
||||
|
||||
### 4. `community`: a list refresh keeps entities
|
||||
|
||||
`CommunityRegistry::track` used to rebuild every community, so an open panel and a
|
||||
browsing sidebar went stale on any list signal — and `sync::load` merges join
|
||||
material into a loaded `CommunityState`, so the state really can change. `track`
|
||||
now keeps the entity for an id it still tracks and hands it the new state through
|
||||
`Community::adopt`, which also cancels a fold in flight that would otherwise write
|
||||
the pre-adoption state back. Observers move to a
|
||||
`HashMap<CommunityId, Subscription>` so the survivors keep theirs, and the ids the
|
||||
list dropped lose their observer and their synced key.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Moderation, invites, community management, channel icons, unread badges, member
|
||||
search, and persisting the selected channel across restarts.
|
||||
Reference in New Issue
Block a user