the proposal board: a Space's pinned playlist takes signed proposals, and an accept republishes it

This commit is contained in:
KeelrLeek committed 2026-09-02 16:33:38 -05:00
1 parent 8b511b20e7
commit bf81792c49
15 files changed
+3207 -10

No files matched your search

+41 -1
View File
@@ -80,6 +80,9 @@ export const community = $state({
/** The open Space (space_open), or null. */
space: null,
spaceError: "",
/** space_board: the proposal board beside the open Space's pinned playlist, or null. */
board: null,
boardError: "",
/** persona key → ProfileView | {none} | {error} | {pending}: other
* people's signed profiles, read once per session when surfaced. */
remoteProfiles: {},
@@ -574,11 +577,48 @@ export const leaveSpace = (owner, space) =>
run("space:leave", async () => {
await api.spaceLeave(owner, space);
community.space = null;
community.board = null;
await refreshSpaces();
});
// ---- the proposal board ---------------------------------------------------------
/** Read the board beside the Space's pinned playlist; the playlist's owner also
* brings its roster in line with the members here. */
export async function openBoard(owner, space) {
community.boardError = "";
community.busy["board:" + space] = true;
try {
community.board = await api.spaceBoard(owner, space);
} catch (e) {
community.board = null;
community.boardError = String(e?.message ?? e);
} finally {
delete community.busy["board:" + space];
}
}
async function boardRun(key, fn) {
community.busy[key] = true;
community.boardError = "";
try {
return await fn();
} catch (e) {
community.boardError = String(e?.message ?? e);
throw e;
} finally {
delete community.busy[key];
}
}
export const proposeToBoard = (owner, space, base, ops, note) =>
boardRun("board:propose", async () => {
community.board = await api.spacePropose(owner, space, base, ops, note);
});
export const decideProposal = (owner, space, proposal, accept, reason) =>
boardRun("board:decide", async () => {
community.board = await api.spaceDecide(owner, space, proposal, accept, reason);
});
// Dev handle beside `__soulstream` (state.svelte.js): probes reach the store
// through this, never through a bare import (which would be a second copy).
if (import.meta.env.DEV) globalThis.__community = community;
if (import.meta.env.DEV) globalThis.__communityActions = { friendRequest, friendRequestByKey, friendAccept, friendDecline, friendRemove, friendForget, checkLink, refreshFriends, sharedPublish, sharedWithdraw, shareSend, sharePreview, shareImport, refreshShares, refreshPublished, publishInbox, checkInbox, refreshInbox, refreshSpaces, openSpace, createSpace, postToSpace, inviteToSpace, removeFromSpace, pinToSpace, leaveSpace };
if (import.meta.env.DEV) globalThis.__communityActions = { friendRequest, friendRequestByKey, friendAccept, friendDecline, friendRemove, friendForget, checkLink, refreshFriends, sharedPublish, sharedWithdraw, shareSend, sharePreview, shareImport, refreshShares, refreshPublished, publishInbox, checkInbox, refreshInbox, refreshSpaces, openSpace, createSpace, postToSpace, inviteToSpace, removeFromSpace, pinToSpace, leaveSpace, openBoard, proposeToBoard, decideProposal };