feat: P1 features — quick switcher, media gallery, DM previews, knock-to-join, syntax highlighting
P1-1: Quick room switcher (Ctrl+K/Cmd+K) — QuickSwitcher.tsx + ClientNonUIFeatures hotkey
P1-2: Media gallery drawer (images/videos/files) — MediaGallery.tsx + RoomViewHeader toggle
P1-4: DM last message preview + relative timestamp in RoomNavItem when direct=true
P1-7: Code syntax highlighting — TDS tokenizer (syntaxHighlight.ts), custom CSS theme
(.prism-tds-dark/.prism-tds-light), applied in react-custom-html-parser.tsx
P1-11: Knock-to-join — "Request to Join" in RoomIntro + Pending Requests in MembersDrawer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -10,8 +10,9 @@ import {
|
||||
Spinner,
|
||||
Text,
|
||||
as,
|
||||
color,
|
||||
} from 'folds';
|
||||
import { Room } from 'matrix-js-sdk';
|
||||
import { JoinRule, Room } from 'matrix-js-sdk';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import { IRoomCreateContent, Membership, StateEvent } from '../../../types/matrix/room';
|
||||
import { getMemberDisplayName, getStateEvent } from '../../utils/room';
|
||||
@@ -42,6 +43,8 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
|
||||
const mDirects = useAtomValue(mDirectAtom);
|
||||
const [invitePrompt, setInvitePrompt] = useState(false);
|
||||
const [viewTopic, setViewTopic] = useState(false);
|
||||
const [knocked, setKnocked] = useState(false);
|
||||
const [knockError, setKnockError] = useState<string | undefined>();
|
||||
|
||||
const createEvent = getStateEvent(room, StateEvent.RoomCreate);
|
||||
const avatarMxc = useRoomAvatar(room, mDirects.has(room.roomId));
|
||||
@@ -168,6 +171,36 @@ export const RoomIntro = as<'div', RoomIntroProps>(({ room, ...props }, ref) =>
|
||||
<Text size="B300">Join Old Room</Text>
|
||||
</Button>
|
||||
))}
|
||||
{room.getJoinRule() === JoinRule.Knock &&
|
||||
room.getMyMembership() !== Membership.Join &&
|
||||
(knocked ? (
|
||||
<Text size="T300" priority="300">
|
||||
Request sent — waiting for room admin approval
|
||||
</Text>
|
||||
) : (
|
||||
<>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setKnockError(undefined);
|
||||
mx.knockRoom(room.roomId)
|
||||
.then(() => setKnocked(true))
|
||||
.catch((err: Error) =>
|
||||
setKnockError(err.message ?? 'Failed to send request'),
|
||||
);
|
||||
}}
|
||||
variant="Primary"
|
||||
size="300"
|
||||
radii="300"
|
||||
>
|
||||
<Text size="B300">Request to Join</Text>
|
||||
</Button>
|
||||
{knockError && (
|
||||
<Text size="T300" style={{ color: color.Critical.Main }}>
|
||||
{knockError}
|
||||
</Text>
|
||||
)}
|
||||
</>
|
||||
))}
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
Reference in New Issue
Block a user