From b81d2901fc09ccaeded5420af101b53ac5995c46 Mon Sep 17 00:00:00 2001 From: Shea Duma Date: Fri, 15 May 2026 08:07:00 +0300 Subject: [PATCH 1/8] added base setting needed to implement per space sidebar icons --- .../common-settings/appearance/Appearance.tsx | 147 ++++++++++++++++++ .../features/settings/cosmetics/Themes.tsx | 2 +- .../features/space-settings/SpaceSettings.tsx | 10 ++ src/app/pages/client/space/Space.tsx | 15 +- src/app/state/settings.ts | 7 + src/app/state/spaceSettings.ts | 1 + 6 files changed, 176 insertions(+), 6 deletions(-) create mode 100644 src/app/features/common-settings/appearance/Appearance.tsx diff --git a/src/app/features/common-settings/appearance/Appearance.tsx b/src/app/features/common-settings/appearance/Appearance.tsx new file mode 100644 index 000000000..4954dc988 --- /dev/null +++ b/src/app/features/common-settings/appearance/Appearance.tsx @@ -0,0 +1,147 @@ +import { useState, type MouseEventHandler } from 'react'; +import { + Box, + Text, + IconButton, + Icon, + Icons, + Scroll, + Button, + config, + Menu, + MenuItem, + PopOut, + type RectCords, +} from 'folds'; +import { Page, PageContent, PageHeader } from '$components/page'; +import { SequenceCard } from '$components/sequence-card'; +import { SettingTile } from '$components/setting-tile'; +import { useRoom } from '$hooks/useRoom'; + +import { SequenceCardStyle } from '$features/common-settings/styles.css'; +import { useShowRoomIcon } from '$hooks/useShowRoomIcon'; +import { useSetting } from '$state/hooks/settings'; +import type { ShowRoomIcon } from '$state/settings'; +import { settingsAtom } from '$state/settings'; +import { stopPropagation } from '$utils/keyboard'; +import FocusTrap from 'focus-trap-react'; + +function SelectShowRoomIcon({roomId}: {roomId: string}) { + const [menuCords, setMenuCords] = useState(); + const showRoomIconItems = useShowRoomIcon(); + const [showRoomIconArray, setShowRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); + const showRoomIcon = showRoomIconArray.find(item => item.roomId === roomId )?.display; + + const handleMenu: MouseEventHandler = (evt) => { + setMenuCords(evt.currentTarget.getBoundingClientRect()); + }; + + const handleSelect = (position: ShowRoomIcon) => { + const CleanedShowRoomIconArray = showRoomIconArray.filter(item => item.roomId !== roomId ); + const newShowRoomIconArray = [...CleanedShowRoomIconArray, {roomId, display: position}] + setShowRoomIconArray(newShowRoomIconArray); + setMenuCords(undefined); + }; + + return ( + <> + + setMenuCords(undefined), + clickOutsideDeactivates: true, + isKeyForward: (evt: KeyboardEvent) => + evt.key === 'ArrowDown' || evt.key === 'ArrowRight', + isKeyBackward: (evt: KeyboardEvent) => + evt.key === 'ArrowUp' || evt.key === 'ArrowLeft', + escapeDeactivates: stopPropagation, + }} + > + + + {showRoomIconItems.map((item) => ( + handleSelect(item.layout)} + > + {item.name} + + ))} + + + + } + /> + + ); +} + +type AppearanceProps = { + requestClose: () => void; +}; +export function Appearance({ requestClose }: AppearanceProps) { + const room = useRoom(); + + return ( + + + + + + Appearance + + + + + + + + + + + + + + + Visual Tweaks + + } + /> + + + + + + + + ); +} diff --git a/src/app/features/settings/cosmetics/Themes.tsx b/src/app/features/settings/cosmetics/Themes.tsx index e00e5f425..6081accdc 100644 --- a/src/app/features/settings/cosmetics/Themes.tsx +++ b/src/app/features/settings/cosmetics/Themes.tsx @@ -868,7 +868,7 @@ export function Appearance({ } diff --git a/src/app/features/space-settings/SpaceSettings.tsx b/src/app/features/space-settings/SpaceSettings.tsx index d773e5ff8..6479d6de6 100644 --- a/src/app/features/space-settings/SpaceSettings.tsx +++ b/src/app/features/space-settings/SpaceSettings.tsx @@ -17,6 +17,7 @@ import { EmojisStickers } from '$features/common-settings/emojis-stickers'; import { Members } from '$features/common-settings/members'; import { DeveloperTools } from '$features/common-settings/developer-tools'; import { Cosmetics } from '$features/common-settings/cosmetics/Cosmetics'; +import { Appearance } from '$features/common-settings/appearance/Appearance'; import { RoomAbbreviations } from '$features/room-settings/abbreviations/RoomAbbreviations'; import { General } from './general'; import { Permissions } from './permissions'; @@ -67,6 +68,12 @@ const useSpaceSettingsMenuItems = (): SpaceSettingsMenuItem[] => name: 'Developer Tools', icon: Icons.Terminal, }, + { + page: SpaceSettingsPage.AppearancePage, + name: 'Appearance', + icon: Icons.Alphabet, + activeIcon: Icons.AlphabetUnderline, + }, ], [] ); @@ -197,6 +204,9 @@ export function SpaceSettings({ initialPage, requestClose }: SpaceSettingsProps) {activePage === SpaceSettingsPage.AbbreviationsPage && ( )} + {activePage === SpaceSettingsPage.AppearancePage && ( + + )} ); } diff --git a/src/app/pages/client/space/Space.tsx b/src/app/pages/client/space/Space.tsx index e4599c463..0c2e09c7f 100644 --- a/src/app/pages/client/space/Space.tsx +++ b/src/app/pages/client/space/Space.tsx @@ -372,7 +372,7 @@ function SpaceHeader({ hideText, mx }: { hideText?: boolean; mx: MatrixClient }) {hasBanner && ( <> -
+ -
+ )} {hasBanner && bannerViewerOpen && ( @@ -521,10 +521,15 @@ export function Space() { const [roomSidebarWidth, setRoomSidebarWidth] = useSetting(settingsAtom, 'roomSidebarWidth'); const [curWidth, setCurWidth] = useState(roomSidebarWidth); - const [showRoomIcon] = useSetting(settingsAtom, 'showRoomIcon'); + const [showRoomIconGeneral] = useSetting(settingsAtom, 'showRoomIcon'); + + const [showRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); + // oxlint-disable-next-line no-console + console.log(showRoomIconArray, space.roomId); + const showIcons = () => { - if (showRoomIcon === ShowRoomIcon.Always) return true; - if (showRoomIcon === ShowRoomIcon.Never) return false; + if (showRoomIconGeneral === ShowRoomIcon.Always) return true; + if (showRoomIconGeneral === ShowRoomIcon.Never) return false; return curWidth < 144; }; useEffect(() => { diff --git a/src/app/state/settings.ts b/src/app/state/settings.ts index b1b744c1f..aab58f600 100644 --- a/src/app/state/settings.ts +++ b/src/app/state/settings.ts @@ -28,6 +28,11 @@ export enum ShowRoomIcon { Smart = 'smart', Never = 'never', } +export type PerRoomShowRoomIcon = { + roomId: string; + display: ShowRoomIcon; +}; + export type JumboEmojiSize = 'none' | 'extraSmall' | 'small' | 'normal' | 'large' | 'extraLarge'; export type ThemeRemoteFavorite = { @@ -160,6 +165,7 @@ export interface Settings { mentionInReplies: boolean; showPersonaSetting: boolean; closeFoldersByDefault: boolean; + perRoomShowRoomIcon: PerRoomShowRoomIcon[]; showRoomIcon: ShowRoomIcon; showRoomBanners: boolean; roomSidebarWidth: number; @@ -292,6 +298,7 @@ export const defaultSettings: Settings = { mentionInReplies: true, showPersonaSetting: false, closeFoldersByDefault: false, + perRoomShowRoomIcon: [], showRoomIcon: ShowRoomIcon.Smart, showRoomBanners: true, roomSidebarWidth: 256, diff --git a/src/app/state/spaceSettings.ts b/src/app/state/spaceSettings.ts index c33b5e957..de91d6f3a 100644 --- a/src/app/state/spaceSettings.ts +++ b/src/app/state/spaceSettings.ts @@ -9,6 +9,7 @@ export enum SpaceSettingsPage { // Sable pages CosmeticsPage, AbbreviationsPage, + AppearancePage, } export type SpaceSettingsState = { From ac922e1ee4b479e9e8810fdff0bbb375b1c4854e Mon Sep 17 00:00:00 2001 From: Shea Duma Date: Fri, 15 May 2026 09:03:46 +0300 Subject: [PATCH 2/8] added resetting space room status and setting for home --- .../common-settings/appearance/Appearance.tsx | 17 +++++++------ .../features/settings/cosmetics/Themes.tsx | 14 ++++++++++- src/app/hooks/useShowRoomIcon.ts | 25 ++++++++++++++++++- src/app/pages/client/space/Space.tsx | 15 +++++------ 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/app/features/common-settings/appearance/Appearance.tsx b/src/app/features/common-settings/appearance/Appearance.tsx index 4954dc988..3d1266952 100644 --- a/src/app/features/common-settings/appearance/Appearance.tsx +++ b/src/app/features/common-settings/appearance/Appearance.tsx @@ -19,26 +19,27 @@ import { SettingTile } from '$components/setting-tile'; import { useRoom } from '$hooks/useRoom'; import { SequenceCardStyle } from '$features/common-settings/styles.css'; -import { useShowRoomIcon } from '$hooks/useShowRoomIcon'; +import { useShowPerRoomRoomIcon } from '$hooks/useShowRoomIcon'; import { useSetting } from '$state/hooks/settings'; import type { ShowRoomIcon } from '$state/settings'; import { settingsAtom } from '$state/settings'; import { stopPropagation } from '$utils/keyboard'; import FocusTrap from 'focus-trap-react'; -function SelectShowRoomIcon({roomId}: {roomId: string}) { +export function SelectShowPerRoomRoomIcon({roomId}: {roomId: string}) { const [menuCords, setMenuCords] = useState(); - const showRoomIconItems = useShowRoomIcon(); + const showRoomIconItems = useShowPerRoomRoomIcon(); const [showRoomIconArray, setShowRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); const showRoomIcon = showRoomIconArray.find(item => item.roomId === roomId )?.display; - + const handleMenu: MouseEventHandler = (evt) => { setMenuCords(evt.currentTarget.getBoundingClientRect()); }; - const handleSelect = (position: ShowRoomIcon) => { - const CleanedShowRoomIconArray = showRoomIconArray.filter(item => item.roomId !== roomId ); - const newShowRoomIconArray = [...CleanedShowRoomIconArray, {roomId, display: position}] + const handleSelect = (position?: ShowRoomIcon) => { + let newShowRoomIconArray = showRoomIconArray.filter(item => item.roomId !== roomId ); + if(position) + newShowRoomIconArray = [...newShowRoomIconArray, {roomId, display: position}] setShowRoomIconArray(newShowRoomIconArray); setMenuCords(undefined); }; @@ -134,7 +135,7 @@ export function Appearance({ requestClose }: AppearanceProps) { } + after={} />
diff --git a/src/app/features/settings/cosmetics/Themes.tsx b/src/app/features/settings/cosmetics/Themes.tsx index 6081accdc..8bea290e7 100644 --- a/src/app/features/settings/cosmetics/Themes.tsx +++ b/src/app/features/settings/cosmetics/Themes.tsx @@ -38,6 +38,7 @@ import FocusTrap from 'focus-trap-react'; import { useShowRoomIcon } from '$hooks/useShowRoomIcon'; import type { PanelSizetItem } from '$hooks/usePanelSizes'; import { usePanelSizeItems } from '$hooks/usePanelSizes'; +import { SelectShowPerRoomRoomIcon } from '$features/common-settings/appearance/Appearance'; const clampIncomingInlineImageHeight = (n: number) => Math.max(1, Math.min(4096, n)); @@ -717,7 +718,8 @@ function SelectShowRoomIcon() { setMenuCords(evt.currentTarget.getBoundingClientRect()); }; - const handleSelect = (position: ShowRoomIcon) => { + const handleSelect = (position?: ShowRoomIcon) => { + if(!position) return; setShowRoomIcon(position); setMenuCords(undefined); }; @@ -874,6 +876,16 @@ export function Appearance({ after={} /> + {/*THIS SHOULD BE MOVED TO A NEW SETTINGS MENU INSIDE OF THE HOME SETTINGS AS SOON AS THERE IS A REASON TO CREATE A HOME MENU SETTINGS PANEL + it is currently here because it would be eerie to have an entire home settings menu for just one single setting*/} + + } + /> + @@ -24,3 +24,26 @@ export const useShowRoomIcon = (): MessageLayoutItem[] => ], [] ); + +export const useShowPerRoomRoomIcon = (): MessageLayoutItem[] => + useMemo( + () => [ + { + layout: undefined, + name: 'Default', + }, + { + layout: ShowRoomIcon.Always, + name: 'Always', + }, + { + layout: ShowRoomIcon.Smart, + name: 'Smart', + }, + { + layout: ShowRoomIcon.Never, + name: 'Never', + }, + ], + [] + ); diff --git a/src/app/pages/client/space/Space.tsx b/src/app/pages/client/space/Space.tsx index 0c2e09c7f..ce3f3f935 100644 --- a/src/app/pages/client/space/Space.tsx +++ b/src/app/pages/client/space/Space.tsx @@ -520,21 +520,18 @@ export function Space() { const [roomSidebarWidth, setRoomSidebarWidth] = useSetting(settingsAtom, 'roomSidebarWidth'); const [curWidth, setCurWidth] = useState(roomSidebarWidth); + useEffect(() => { + setCurWidth(roomSidebarWidth); + }, [roomSidebarWidth]); const [showRoomIconGeneral] = useSetting(settingsAtom, 'showRoomIcon'); - const [showRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); - // oxlint-disable-next-line no-console - console.log(showRoomIconArray, space.roomId); - + const showRoomIcon = showRoomIconArray.find(item => item.roomId === space.roomId )?.display ?? showRoomIconGeneral; const showIcons = () => { - if (showRoomIconGeneral === ShowRoomIcon.Always) return true; - if (showRoomIconGeneral === ShowRoomIcon.Never) return false; + if (showRoomIcon === ShowRoomIcon.Always) return true; + if (showRoomIcon === ShowRoomIcon.Never) return false; return curWidth < 144; }; - useEffect(() => { - setCurWidth(roomSidebarWidth); - }, [roomSidebarWidth]); const [joinCallOnSingleClick] = useSetting(settingsAtom, 'joinCallOnSingleClick'); const tombstoneEvent = useStateEvent(space, EventType.RoomTombstone); From f0e175d4bcd0831f8566f8a6f716bd3255334c1d Mon Sep 17 00:00:00 2001 From: Shea Duma Date: Fri, 15 May 2026 10:05:54 +0300 Subject: [PATCH 3/8] fixed some banner issues --- .../common-settings/appearance/Appearance.tsx | 11 ++++--- .../features/settings/cosmetics/Themes.tsx | 2 +- src/app/pages/client/home/Home.tsx | 14 +++++---- .../client/sidebar/SidebarResizer.css.ts | 29 +++++++++++++++---- .../pages/client/sidebar/SidebarResizer.tsx | 9 ++---- src/app/pages/client/space/Space.tsx | 2 ++ 6 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/app/features/common-settings/appearance/Appearance.tsx b/src/app/features/common-settings/appearance/Appearance.tsx index 3d1266952..06e9090fb 100644 --- a/src/app/features/common-settings/appearance/Appearance.tsx +++ b/src/app/features/common-settings/appearance/Appearance.tsx @@ -26,20 +26,19 @@ import { settingsAtom } from '$state/settings'; import { stopPropagation } from '$utils/keyboard'; import FocusTrap from 'focus-trap-react'; -export function SelectShowPerRoomRoomIcon({roomId}: {roomId: string}) { +export function SelectShowPerRoomRoomIcon({ roomId }: { roomId: string }) { const [menuCords, setMenuCords] = useState(); const showRoomIconItems = useShowPerRoomRoomIcon(); const [showRoomIconArray, setShowRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); - const showRoomIcon = showRoomIconArray.find(item => item.roomId === roomId )?.display; + const showRoomIcon = showRoomIconArray.find((item) => item.roomId === roomId)?.display; const handleMenu: MouseEventHandler = (evt) => { setMenuCords(evt.currentTarget.getBoundingClientRect()); }; const handleSelect = (position?: ShowRoomIcon) => { - let newShowRoomIconArray = showRoomIconArray.filter(item => item.roomId !== roomId ); - if(position) - newShowRoomIconArray = [...newShowRoomIconArray, {roomId, display: position}] + let newShowRoomIconArray = showRoomIconArray.filter((item) => item.roomId !== roomId); + if (position) newShowRoomIconArray = [...newShowRoomIconArray, { roomId, display: position }]; setShowRoomIconArray(newShowRoomIconArray); setMenuCords(undefined); }; @@ -135,7 +134,7 @@ export function Appearance({ requestClose }: AppearanceProps) { } + after={} /> diff --git a/src/app/features/settings/cosmetics/Themes.tsx b/src/app/features/settings/cosmetics/Themes.tsx index 8bea290e7..fa93a3890 100644 --- a/src/app/features/settings/cosmetics/Themes.tsx +++ b/src/app/features/settings/cosmetics/Themes.tsx @@ -719,7 +719,7 @@ function SelectShowRoomIcon() { }; const handleSelect = (position?: ShowRoomIcon) => { - if(!position) return; + if (!position) return; setShowRoomIcon(position); setMenuCords(undefined); }; diff --git a/src/app/pages/client/home/Home.tsx b/src/app/pages/client/home/Home.tsx index 38022a2e6..8b520e5c2 100644 --- a/src/app/pages/client/home/Home.tsx +++ b/src/app/pages/client/home/Home.tsx @@ -213,16 +213,20 @@ export function Home() { const [roomSidebarWidth, setRoomSidebarWidth] = useSetting(settingsAtom, 'roomSidebarWidth'); const [curWidth, setCurWidth] = useState(roomSidebarWidth); + useEffect(() => { + setCurWidth(roomSidebarWidth); + }, [roomSidebarWidth]); - const [showRoomIcon] = useSetting(settingsAtom, 'showRoomIcon'); + const [showRoomIconGeneral] = useSetting(settingsAtom, 'showRoomIcon'); + const [showRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); + const showRoomIcon = + showRoomIconArray.find((item) => item.roomId === 'Home')?.display ?? showRoomIconGeneral; const showIcons = () => { if (showRoomIcon === ShowRoomIcon.Always) return true; if (showRoomIcon === ShowRoomIcon.Never) return false; - return curWidth < 96; + return curWidth < 144; }; - useEffect(() => { - setCurWidth(roomSidebarWidth); - }, [roomSidebarWidth]); + const [joinCallOnSingleClick] = useSetting(settingsAtom, 'joinCallOnSingleClick'); const selectedRoomId = useSelectedRoom(); diff --git a/src/app/pages/client/sidebar/SidebarResizer.css.ts b/src/app/pages/client/sidebar/SidebarResizer.css.ts index b37504b98..5acd9d4b9 100644 --- a/src/app/pages/client/sidebar/SidebarResizer.css.ts +++ b/src/app/pages/client/sidebar/SidebarResizer.css.ts @@ -1,5 +1,6 @@ import { style } from '@vanilla-extract/css'; -import { color } from 'folds'; +import { recipe } from '@vanilla-extract/recipes'; +import { color, toRem } from 'folds'; /** Out-of-flow so flex siblings (e.g. PageRoot vertical Line) stay flush with the panel edge. */ export const SidebarResizerDockRight = style({ @@ -29,17 +30,33 @@ export const SidebarResizerDockTop = style({ cursor: 'ns-resize', }); -export const SidebarResizer = style({ - backgroundColor: 'inherit', - transition: '0.2s', - ':hover': {}, +export const SidebarResizer = recipe({ + base: { + backgroundColor: 'inherit', + transition: '0.2s', + ':hover': {}, + touchAction: 'none', + }, + variants: { + topSided: { + true: { + width: '100%', + height: toRem(8), + }, + false: { + width: toRem(4), + height: '100%', + }, + }, + }, }); export const SidebarResizerHover = style({ - zIndex: 100, + zIndex: 110, }); export const SideBarResizerAnimation = style({ width: '100%', height: '100%', backgroundColor: color.Surface.ContainerLine, transition: '0.5s', + touchAction: 'none', }); diff --git a/src/app/pages/client/sidebar/SidebarResizer.tsx b/src/app/pages/client/sidebar/SidebarResizer.tsx index 6b7d0144c..b54d258f0 100644 --- a/src/app/pages/client/sidebar/SidebarResizer.tsx +++ b/src/app/pages/client/sidebar/SidebarResizer.tsx @@ -1,6 +1,6 @@ // The disable is because the position should only update whenever the new one is updated // oxlint-disable eslint-plugin-react-hooks/exhaustive-deps -import { Box, toRem } from 'folds'; +import { Box } from 'folds'; import * as css from '$pages/client/sidebar/SidebarResizer.css'; import type { Dispatch, SetStateAction } from 'react'; import React, { useCallback, useEffect, useState } from 'react'; @@ -64,6 +64,7 @@ export function SidebarResizer({ const onPointerDown = useCallback( (e: React.PointerEvent) => { e.preventDefault(); + e.currentTarget.setPointerCapture(e.pointerId); setOldPos(topSided ? e.clientY : e.clientX); setIsPointerDown(true); window.addEventListener('pointerup', onPointerUp); @@ -80,14 +81,10 @@ export function SidebarResizer({ return ( setIsPointerOver(true)} onPointerLeave={() => setIsPointerOver(false)} onPointerDown={onPointerDown} - style={{ - width: topSided ? '100%' : toRem(4), - height: topSided ? toRem(4) : '100%', - }} shrink="No" > item.roomId === space.roomId )?.display ?? showRoomIconGeneral; + // oxlint-disable-next-line no-console + console.log(showRoomIconArray, space.roomId); const showIcons = () => { if (showRoomIcon === ShowRoomIcon.Always) return true; if (showRoomIcon === ShowRoomIcon.Never) return false; From 30940f24091eff9fcb52ce097ad9decc7e94d6cf Mon Sep 17 00:00:00 2001 From: Shea Duma Date: Fri, 15 May 2026 19:15:03 +0300 Subject: [PATCH 4/8] add banner to roomCard --- src/app/components/room-card/RoomCard.tsx | 234 ++++++++++++---------- src/app/components/room-card/style.css.ts | 33 ++- src/app/features/room/MembersDrawer.tsx | 2 - src/app/pages/client/space/Space.tsx | 5 +- 4 files changed, 164 insertions(+), 110 deletions(-) diff --git a/src/app/components/room-card/RoomCard.tsx b/src/app/components/room-card/RoomCard.tsx index ed905872e..b7afb0111 100644 --- a/src/app/components/room-card/RoomCard.tsx +++ b/src/app/components/room-card/RoomCard.tsx @@ -18,6 +18,7 @@ import { as, color, config, + toRem, } from 'folds'; import classNames from 'classnames'; import FocusTrap from 'focus-trap-react'; @@ -36,6 +37,9 @@ import { KnockRoomPrompt } from '$components/knock-room-prompt'; import { RoomAvatar } from '$components/room-avatar'; import { formatCompactNumber } from '$utils/formatCompactNumber'; import * as css from './style.css'; +import type { RoomBannerContent } from '$types/matrix-sdk-events'; +import { CustomStateEvent } from '$types/matrix/room'; +import colorMXID from '$utils/colorMXID'; type GridColumnCount = '1' | '2' | '3'; const getGridColumnCount = (gridWidth: number): GridColumnCount => { @@ -66,7 +70,6 @@ export function RoomCardGrid({ children }: { children: ReactNode }) { export const RoomCardBase = as<'div'>(({ className, ...props }, ref) => ( ( ? getRoomAvatarUrl(mx, joinedRoom, 96, useAuthentication) : avatarUrl && mxcUrlToHttp(mx, avatarUrl, useAuthentication, 96, 96, 'crop'); + const bannerState = joinedRoom + ? getStateEvent(joinedRoom, CustomStateEvent.RoomBanner) + : undefined; + const bannerMXC = bannerState?.getContent()?.url; + const bannerURI = mxcUrlToHttp(mx, bannerMXC ?? '', true); const roomName = joinedRoom?.name || name || fallbackName; const roomTopic = (topicEvent?.getContent().topic as string) || undefined || topic || fallbackTopic; @@ -215,11 +223,28 @@ export const RoomCard = as<'div', RoomCardProps>( const [viewTopic, setViewTopic] = useState(false); const closeTopic = () => setViewTopic(false); const openTopic = () => setViewTopic(true); - + if (!bannerURI && !avatar) + // oxlint-disable-next-line no-console + console.log(bannerURI, avatar, roomIdOrAlias); return ( - - + + {!bannerURI && !avatar ? ( + + ) : ( + {`${name} + )} + ( )} /> - {(roomType === RoomType.Space || joinedRoom?.isSpaceRoom()) && ( - - Space - - )} - - {roomName} - - {roomTopic} - - - }> - - - {renderTopicViewer(roomName, roomTopic, closeTopic)} - - - - - {typeof joinedMemberCount === 'number' && ( - - - {`${formatCompactNumber(joinedMemberCount)} Members`} + + + + {roomName} + + {roomTopic} + + + }> + + + {renderTopicViewer(roomName, roomTopic, closeTopic)} + + + + {(roomType === RoomType.Space || joinedRoom?.isSpaceRoom()) && ( + + Space + + )} - )} - {typeof joinedRoomId === 'string' && ( - - )} - {typeof joinedRoomId !== 'string' && - joinState.status !== AsyncStatus.Error && - (joinRule === JoinRule.Knock ? ( - <> - - - {knocking && ( - setKnocking(false)} - onCancel={() => setKnocking(false)} - /> - )} - - ) : ( + {typeof joinedMemberCount === 'number' && ( + + + {`${formatCompactNumber(joinedMemberCount)} Members`} + + )} + {typeof joinedRoomId === 'string' && ( - ))} - {typeof joinedRoomId !== 'string' && joinState.status === AsyncStatus.Error && ( - - - - {(openError) => ( - - )} - - - )} + + {knocking && ( + setKnocking(false)} + onCancel={() => setKnocking(false)} + /> + )} + + ) : ( + + ))} + {typeof joinedRoomId !== 'string' && joinState.status === AsyncStatus.Error && ( + + + + {(openError) => ( + + )} + + + )} + ); } diff --git a/src/app/components/room-card/style.css.ts b/src/app/components/room-card/style.css.ts index 8afe6704b..98f8fe042 100644 --- a/src/app/components/room-card/style.css.ts +++ b/src/app/components/room-card/style.css.ts @@ -1,6 +1,7 @@ import { style } from '@vanilla-extract/css'; -import { DefaultReset, config } from 'folds'; +import { DefaultReset, color, config, toRem } from 'folds'; import { ContainerColor } from '$styles/ContainerColor.css'; +import { recipe } from '@vanilla-extract/recipes'; export const CardGrid = style({ display: 'grid', @@ -12,11 +13,15 @@ export const RoomCardBase = style([ DefaultReset, ContainerColor({ variant: 'SurfaceVariant' }), { - padding: config.space.S500, borderRadius: config.radii.R500, + overflow: 'hidden', }, ]); +export const RoomCardItems = style({ + padding: config.space.S500, + backgroundColor: color.SurfaceVariant.Container, +}); export const RoomCardTopic = style({ minHeight: `calc(3 * ${config.lineHeight.T200})`, display: '-webkit-box', @@ -34,3 +39,27 @@ export const ActionButton = style({ flex: '1 1 0', minWidth: 1, }); + +export const RoomCardBanner = recipe({ + base: { + height: toRem(96), + minHeight: toRem(96), + width: '100%', + objectFit: 'cover', + objectPosition: 'center center', + }, + variants: { + trueBanner: { + true: {}, + false: { + filter: 'blur(40px)', + }, + }, + }, +}); +export const RoomCardAvatar = style({ + position: 'sticky', + transform: 'translateY(-50%)', + marginLeft: config.space.S500, + outline: `${config.borderWidth.B600} solid ${color.Surface.Container}`, +}); diff --git a/src/app/features/room/MembersDrawer.tsx b/src/app/features/room/MembersDrawer.tsx index 2641899d4..3aeb18c15 100644 --- a/src/app/features/room/MembersDrawer.tsx +++ b/src/app/features/room/MembersDrawer.tsx @@ -296,8 +296,6 @@ export function MembersDrawer({ room, members }: MembersDrawerProps) { ); const handleMemberClick: MouseEventHandler = (evt) => { - // oxlint-disable-next-line no-console - console.log(evt); const btn = evt.currentTarget as HTMLButtonElement; const userId = btn.getAttribute('data-user-id'); if (!userId) return; diff --git a/src/app/pages/client/space/Space.tsx b/src/app/pages/client/space/Space.tsx index e82d5b921..8dbcfc417 100644 --- a/src/app/pages/client/space/Space.tsx +++ b/src/app/pages/client/space/Space.tsx @@ -526,9 +526,8 @@ export function Space() { const [showRoomIconGeneral] = useSetting(settingsAtom, 'showRoomIcon'); const [showRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); - const showRoomIcon = showRoomIconArray.find(item => item.roomId === space.roomId )?.display ?? showRoomIconGeneral; - // oxlint-disable-next-line no-console - console.log(showRoomIconArray, space.roomId); + const showRoomIcon = + showRoomIconArray.find((item) => item.roomId === space.roomId)?.display ?? showRoomIconGeneral; const showIcons = () => { if (showRoomIcon === ShowRoomIcon.Always) return true; if (showRoomIcon === ShowRoomIcon.Never) return false; From 027f6d22ae9850f0464dce53e990f02ddd015d1c Mon Sep 17 00:00:00 2001 From: Shea Duma Date: Fri, 15 May 2026 20:16:39 +0300 Subject: [PATCH 5/8] add changeset --- .changeset/add_per_room_icon_display.md | 5 +++++ .changeset/fix-various-banner-fixes.md | 5 +++++ src/app/components/room-card/RoomCard.tsx | 9 +++------ src/app/components/room-card/style.css.ts | 2 +- .../common-settings/general/RoomProfile.tsx | 16 ++++++++++++---- src/app/features/settings/settingsLink.ts | 1 + 6 files changed, 27 insertions(+), 11 deletions(-) create mode 100644 .changeset/add_per_room_icon_display.md create mode 100644 .changeset/fix-various-banner-fixes.md diff --git a/.changeset/add_per_room_icon_display.md b/.changeset/add_per_room_icon_display.md new file mode 100644 index 000000000..6e20d1371 --- /dev/null +++ b/.changeset/add_per_room_icon_display.md @@ -0,0 +1,5 @@ +--- +default: minor +--- + +Add per Space setting for when to show room icons in sidebar diff --git a/.changeset/fix-various-banner-fixes.md b/.changeset/fix-various-banner-fixes.md new file mode 100644 index 000000000..0c012d451 --- /dev/null +++ b/.changeset/fix-various-banner-fixes.md @@ -0,0 +1,5 @@ +--- +default: fix +--- + +Various small banner changes diff --git a/src/app/components/room-card/RoomCard.tsx b/src/app/components/room-card/RoomCard.tsx index b7afb0111..f7bcb09cd 100644 --- a/src/app/components/room-card/RoomCard.tsx +++ b/src/app/components/room-card/RoomCard.tsx @@ -223,22 +223,19 @@ export const RoomCard = as<'div', RoomCardProps>( const [viewTopic, setViewTopic] = useState(false); const closeTopic = () => setViewTopic(false); const openTopic = () => setViewTopic(true); - if (!bannerURI && !avatar) - // oxlint-disable-next-line no-console - console.log(bannerURI, avatar, roomIdOrAlias); return ( - + {!bannerURI && !avatar ? ( ) : ( {`${name}) { +function RoomBannerEdit({ bannerURI, permissions }: Readonly) { const mx = useMatrixClient(); const [alertRemove, setAlertRemove] = useState(false); const space = useRoom(); + + const userId = mx.getUserId() ?? ''; + const canEdit = permissions.stateEvent(CustomStateEvent.RoomAbbreviations, userId); + const [stagedUrl, setStagedUrl] = useState(); const [isRemoving, setIsRemoving] = useState(false); @@ -420,6 +425,7 @@ function RoomBannerEdit({ bannerURI }: Readonly) { fill="Soft" outlined radii="300" + disabled={!canEdit} > {bannerUrl ? 'Change Banner' : 'Upload Banner'} @@ -430,6 +436,7 @@ function RoomBannerEdit({ bannerURI }: Readonly) { fill="None" radii="300" onClick={() => setAlertRemove(true)} + disabled={!canEdit} > Remove @@ -466,7 +473,7 @@ function RoomBannerEdit({ bannerURI }: Readonly) { Are you sure you want to remove profile banner? - @@ -585,8 +592,9 @@ export function RoomProfile({ permissions }: RoomProfileProps) { variant="SurfaceVariant" direction="Column" gap="400" + disabled={!canEdit} > - + )} diff --git a/src/app/features/settings/settingsLink.ts b/src/app/features/settings/settingsLink.ts index 03cfac011..6104186ed 100644 --- a/src/app/features/settings/settingsLink.ts +++ b/src/app/features/settings/settingsLink.ts @@ -123,6 +123,7 @@ const settingsLinkFocusIdsBySection: Record Date: Fri, 15 May 2026 20:23:43 +0300 Subject: [PATCH 6/8] i call the failures skill issues because it behaves correctly wo the incertitude --- src/app/features/common-settings/appearance/Appearance.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/features/common-settings/appearance/Appearance.tsx b/src/app/features/common-settings/appearance/Appearance.tsx index 06e9090fb..b7bc803e0 100644 --- a/src/app/features/common-settings/appearance/Appearance.tsx +++ b/src/app/features/common-settings/appearance/Appearance.tsx @@ -30,7 +30,7 @@ export function SelectShowPerRoomRoomIcon({ roomId }: { roomId: string }) { const [menuCords, setMenuCords] = useState(); const showRoomIconItems = useShowPerRoomRoomIcon(); const [showRoomIconArray, setShowRoomIconArray] = useSetting(settingsAtom, 'perRoomShowRoomIcon'); - const showRoomIcon = showRoomIconArray.find((item) => item.roomId === roomId)?.display; + const showRoomIcon = showRoomIconArray?.find((item) => item.roomId === roomId)?.display; const handleMenu: MouseEventHandler = (evt) => { setMenuCords(evt.currentTarget.getBoundingClientRect()); From 4a2521c233e1ce3a16736b23573b700d2d415bb6 Mon Sep 17 00:00:00 2001 From: Shea Duma Date: Sat, 16 May 2026 00:20:25 +0300 Subject: [PATCH 7/8] fix user icon positionings in VCs in collapsed sidebar view --- src/app/pages/client/direct/Direct.tsx | 1 + src/app/pages/client/home/Home.tsx | 1 + src/app/pages/client/space/Space.tsx | 1 + 3 files changed, 3 insertions(+) diff --git a/src/app/pages/client/direct/Direct.tsx b/src/app/pages/client/direct/Direct.tsx index dce68f104..81dc6181d 100644 --- a/src/app/pages/client/direct/Direct.tsx +++ b/src/app/pages/client/direct/Direct.tsx @@ -338,6 +338,7 @@ export function Direct() { width: '100%', aspectRatio: 1, display: 'flex', + flexDirection: 'column', } : {} } diff --git a/src/app/pages/client/home/Home.tsx b/src/app/pages/client/home/Home.tsx index 8b520e5c2..cddcefbb0 100644 --- a/src/app/pages/client/home/Home.tsx +++ b/src/app/pages/client/home/Home.tsx @@ -427,6 +427,7 @@ export function Home() { width: '100%', aspectRatio: 1, display: 'flex', + flexDirection: 'column', } : {} } diff --git a/src/app/pages/client/space/Space.tsx b/src/app/pages/client/space/Space.tsx index 8dbcfc417..e30634310 100644 --- a/src/app/pages/client/space/Space.tsx +++ b/src/app/pages/client/space/Space.tsx @@ -1020,6 +1020,7 @@ export function Space() { width: '100%', aspectRatio: 1, display: 'flex', + flexDirection: 'column', } : { paddingLeft } } From 6c832a8a8d5898013173ba8f5a8dc89e7a4a5951 Mon Sep 17 00:00:00 2001 From: Shea Duma Date: Sat, 16 May 2026 13:30:01 +0300 Subject: [PATCH 8/8] fix permission check --- src/app/components/room-card/RoomCard.tsx | 2 +- src/app/features/common-settings/general/RoomProfile.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/components/room-card/RoomCard.tsx b/src/app/components/room-card/RoomCard.tsx index f7bcb09cd..9c35f0186 100644 --- a/src/app/components/room-card/RoomCard.tsx +++ b/src/app/components/room-card/RoomCard.tsx @@ -236,7 +236,7 @@ export const RoomCard = as<'div', RoomCardProps>( ) : ( {`${name} diff --git a/src/app/features/common-settings/general/RoomProfile.tsx b/src/app/features/common-settings/general/RoomProfile.tsx index 975a6b9a2..a65d7ef1a 100644 --- a/src/app/features/common-settings/general/RoomProfile.tsx +++ b/src/app/features/common-settings/general/RoomProfile.tsx @@ -320,7 +320,7 @@ function RoomBannerEdit({ bannerURI, permissions }: Readonly) { const space = useRoom(); const userId = mx.getUserId() ?? ''; - const canEdit = permissions.stateEvent(CustomStateEvent.RoomAbbreviations, userId); + const canEdit = permissions.stateEvent(CustomStateEvent.RoomBanner, userId); const [stagedUrl, setStagedUrl] = useState(); const [isRemoving, setIsRemoving] = useState(false);