feat: Implement sub-room functionality

- Added support for sub-rooms in the SpaceHierarchy component, allowing rooms to have nested child rooms.
- Introduced UnjoinedSubRoomItem component to display unjoined sub-rooms with a join button.
- Created SubRooms settings page for managing sub-rooms, including adding and removing sub-rooms.
- Updated RoomNavItem to include options for creating sub-rooms.
- Enhanced room fetching logic to filter out sub-rooms from the main room list.
- Added hooks for managing sub-rooms state and permissions.
- Updated relevant state management to handle sub-room creation and association with parent rooms.
This commit is contained in:
2026-03-15 16:25:53 +11:00
parent a0c0068997
commit c7bd376292
21 changed files with 917 additions and 111 deletions

View File

@@ -36,27 +36,34 @@ import { validBlurHash } from '../../../utils/blurHash';
* Fetches media with authentication headers and returns a blob URL.
* This is needed because service workers don't work reliably in Tauri/WebKit.
* Falls back to unauthenticated request if authenticated request fails with 401.
* If all attempts fail, returns the original URL to let the browser try directly.
*/
const fetchAuthenticatedMedia = async (
url: string,
accessToken: string | null
): Promise<string> => {
let response = await fetch(url, {
method: 'GET',
headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,
});
// If we got a 401 and we tried with auth, fallback to unauthenticated request
if (!response.ok && response.status === 401 && accessToken) {
console.warn('[ImageContent] Auth failed (401), attempting unauthenticated fallback for:', url);
response = await fetch(url, { method: 'GET' });
try {
let response = await fetch(url, {
method: 'GET',
headers: accessToken ? { Authorization: `Bearer ${accessToken}` } : undefined,
});
// If we got a 401 and we tried with auth, fallback to unauthenticated request
if (!response.ok && response.status === 401 && accessToken) {
console.warn('[ImageContent] Auth failed (401), attempting unauthenticated fallback for:', url);
response = await fetch(url, { method: 'GET' });
}
if (!response.ok) {
console.warn(`[ImageContent] Failed to fetch authenticated media (${response.status}), falling back to original URL`);
return url;
}
const blob = await response.blob();
return URL.createObjectURL(blob);
} catch (error) {
console.warn('[ImageContent] Error fetching authenticated media, falling back to original URL:', error);
return url;
}
if (!response.ok) {
throw new Error(`Failed to fetch media: ${response.status}`);
}
const blob = await response.blob();
return URL.createObjectURL(blob);
};
/**