Support app.relay.emoji_confetti on jumbo emoji clicks with canvas physics, per-emoji particle profiles, and a fixed overlay that does not affect scroll. Also add a Vite playground for live component previews and theme hover preview.
124 lines
3.1 KiB
TypeScript
124 lines
3.1 KiB
TypeScript
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
import type { MatrixClient, Room } from 'matrix-js-sdk';
|
|
import {
|
|
connectLiveMatrixClient,
|
|
listJoinedRooms,
|
|
loadManualSession,
|
|
peekPaarrotSession,
|
|
pickDefaultRoom,
|
|
saveManualSession,
|
|
stopLiveMatrixClient,
|
|
type LiveConnectMode,
|
|
type ManualSessionInput,
|
|
} from './liveClient';
|
|
|
|
type LiveState = {
|
|
mode: LiveConnectMode;
|
|
status: 'idle' | 'connecting' | 'ready' | 'error';
|
|
error: string | null;
|
|
client: MatrixClient | null;
|
|
room: Room | null;
|
|
rooms: Room[];
|
|
sessionLabel: string | null;
|
|
};
|
|
|
|
const initial: LiveState = {
|
|
mode: 'mock',
|
|
status: 'idle',
|
|
error: null,
|
|
client: null,
|
|
room: null,
|
|
rooms: [],
|
|
sessionLabel: null,
|
|
};
|
|
|
|
export function usePlaygroundMatrix() {
|
|
const [state, setState] = useState<LiveState>(initial);
|
|
const clientRef = useRef<MatrixClient | null>(null);
|
|
const roomIdRef = useRef<string | undefined>(undefined);
|
|
const paarrotSession = peekPaarrotSession();
|
|
const hasPaarrotSession = Boolean(paarrotSession);
|
|
const hasManualSession = Boolean(loadManualSession());
|
|
|
|
const teardown = useCallback(() => {
|
|
stopLiveMatrixClient(clientRef.current);
|
|
clientRef.current = null;
|
|
}, []);
|
|
|
|
useEffect(() => () => teardown(), [teardown]);
|
|
|
|
const selectRoom = useCallback((roomId: string) => {
|
|
roomIdRef.current = roomId;
|
|
setState((prev) => {
|
|
if (!prev.client) return prev;
|
|
const room = pickDefaultRoom(prev.client, roomId) ?? null;
|
|
return { ...prev, room };
|
|
});
|
|
}, []);
|
|
|
|
const connectLive = useCallback(
|
|
async (manual?: ManualSessionInput) => {
|
|
teardown();
|
|
setState((prev) => ({
|
|
...prev,
|
|
mode: 'live',
|
|
status: 'connecting',
|
|
error: null,
|
|
client: null,
|
|
room: null,
|
|
rooms: [],
|
|
sessionLabel: null,
|
|
}));
|
|
|
|
try {
|
|
if (manual) saveManualSession(manual);
|
|
const mx = await connectLiveMatrixClient(manual);
|
|
clientRef.current = mx;
|
|
const rooms = listJoinedRooms(mx);
|
|
const room = pickDefaultRoom(mx, roomIdRef.current) ?? null;
|
|
if (room) roomIdRef.current = room.roomId;
|
|
|
|
const hs =
|
|
peekPaarrotSession()?.baseUrl ??
|
|
loadManualSession()?.baseUrl ??
|
|
'';
|
|
setState({
|
|
mode: 'live',
|
|
status: 'ready',
|
|
error: null,
|
|
client: mx,
|
|
room,
|
|
rooms,
|
|
sessionLabel: `${mx.getUserId() ?? '?'} · ${hs}`,
|
|
});
|
|
} catch (err) {
|
|
clientRef.current = null;
|
|
setState({
|
|
...initial,
|
|
mode: 'live',
|
|
status: 'error',
|
|
error: err instanceof Error ? err.message : String(err),
|
|
});
|
|
}
|
|
},
|
|
[teardown]
|
|
);
|
|
|
|
const useMocks = useCallback(() => {
|
|
teardown();
|
|
roomIdRef.current = undefined;
|
|
setState(initial);
|
|
}, [teardown]);
|
|
|
|
return {
|
|
...state,
|
|
hasPaarrotSession,
|
|
hasManualSession,
|
|
paarrotUserId: paarrotSession?.userId ?? null,
|
|
paarrotBaseUrl: paarrotSession?.baseUrl ?? null,
|
|
connectLive,
|
|
useMocks,
|
|
selectRoom,
|
|
};
|
|
}
|