commit 89faac0c833ef155d213342643f5f0091aaae221
parent ebe9feb8f811ebb6f4b4f8efc1e2649f7f7aae05
Author: MTRNord <mtrnord1@gmail.com>
Date: Sat, 6 May 2023 15:36:14 +0200
Improve font sizes, fix stories for input, render non encrypted images, fix avatar sizes
Diffstat:
8 files changed, 84 insertions(+), 30 deletions(-)
diff --git a/src/app/sdk/api/apiTypes.ts b/src/app/sdk/api/apiTypes.ts
@@ -311,6 +311,12 @@ export interface IRoomMessageTextContent extends IRoomMessageContent<"m.text"> {
formatted_body?: string;
}
+export interface IRoomMessageImageContent extends IRoomMessageContent<"m.image"> {
+ info?: IImageInfo;
+ url?: string;
+ file?: IEncryptedFile;
+}
+
export interface IRoomMessageEvent<Content = any> extends IRoomEvent<Content> { }
export interface IRoomMessageTextEvent extends IRoomMessageEvent<IRoomMessageTextContent> { }
@@ -319,6 +325,10 @@ export function isRoomMessageTextEvent(event: IRoomEvent): event is IRoomMessage
return event.type === "m.room.message" && event.content.msgtype === "m.text";
}
+export function isRoomMessageImageEvent(event: IRoomEvent): event is IRoomMessageEvent<IRoomMessageImageContent> {
+ return event.type === "m.room.message" && event.content.msgtype === "m.image";
+}
+
export function isRoomMessageEvent(event: IRoomEvent): event is IRoomMessageEvent {
return event.type === "m.room.message";
}
@@ -368,12 +378,29 @@ export interface IThumbnailInfo {
w: number;
}
+export interface IEncryptedFile {
+ v: string;
+ key: {
+ alg: string;
+ ext: boolean;
+ k: string;
+ key_ops: string[];
+ kty: string;
+ };
+ iv: string;
+ hashes: {
+ [key: string]: string;
+ };
+ url: string;
+}
+
export interface IImageInfo {
h: number;
mimetype: string;
size: number;
thumbnail_info?: IThumbnailInfo;
thumbnail_url?: string;
+ thumbnail_file?: IEncryptedFile;
w: number;
}
diff --git a/src/app/sdk/client.ts b/src/app/sdk/client.ts
@@ -134,6 +134,10 @@ export class MatrixClient extends EventEmitter {
return this.access_token !== undefined;
}
+ public convertMXC(url: string): string {
+ return `${this.hostname}/_matrix/media/r0/download/${url.substring(6)}`;
+ }
+
public setCurrentRoom(roomID?: string) {
if (roomID !== this.currentRoom) {
this.currentRoom = roomID;
diff --git a/src/app/sdk/room.ts b/src/app/sdk/room.ts
@@ -71,7 +71,7 @@ export class Room extends EventEmitter {
if (isRoomAvatarEvent(event)) {
const rawAvatarURL = event.content.url;
if (rawAvatarURL?.startsWith("mxc://")) {
- avatarURL = `${this.hostname}/_matrix/media/r0/download/${rawAvatarURL.substring(6)}`;
+ avatarURL = this.client.convertMXC(rawAvatarURL);
}
}
});
@@ -197,7 +197,7 @@ export class Room extends EventEmitter {
if (event.state_key === userID && event.content.membership == "join") {
const rawAvatarURL = event.content.avatar_url;
if (rawAvatarURL?.startsWith("mxc://")) {
- avatarURL = `${this.hostname}/_matrix/media/r0/download/${rawAvatarURL.substring(6)}`;
+ avatarURL = this.client.convertMXC(rawAvatarURL);
}
}
}
diff --git a/src/components/avatar/avatar.tsx b/src/components/avatar/avatar.tsx
@@ -23,7 +23,7 @@ const Avatar: FC<AvatarProps> = memo(({ avatarUrl, displayname, dm = false, onli
if (avatarUrl) {
return (
<div className="flex relative min-w-[2rem] min-h-[2rem] justify-center items-center m-0 mr-3 text-xl rounded-full text-white">
- <img className="rounded-full w-8 h-8" alt={displayname} src={avatarUrl} />
+ <img className="rounded-full w-8 h-8 object-cover" alt={displayname} src={avatarUrl} />
{
dm ?
(
diff --git a/src/components/events/messageEvent.tsx b/src/components/events/messageEvent.tsx
@@ -1,8 +1,8 @@
-import { memo } from "react";
-import { IRoomEvent, isRoomMessageTextEvent } from "../../app/sdk/api/apiTypes";
+import { memo, useContext, useEffect, useState } from "react";
+import { IRoomEvent, isRoomMessageImageEvent, isRoomMessageTextEvent } from "../../app/sdk/api/apiTypes";
import { FC } from "react";
import Avatar from "../avatar/avatar";
-import { useRoom } from "../../app/sdk/client";
+import { MatrixContext, useRoom } from "../../app/sdk/client";
import Linkify from "linkify-react";
import DOMPurify from "dompurify";
@@ -34,6 +34,7 @@ const linkifyOptions = {
const MessageEvent: FC<MessageEventProps> = memo(({ event, roomID, hasPreviousEvent }) => {
const room = useRoom(roomID);
+ const client = useContext(MatrixContext);
const renderCorrectMessage = (event: IRoomEvent) => {
if (isRoomMessageTextEvent(event)) {
@@ -113,6 +114,38 @@ const MessageEvent: FC<MessageEventProps> = memo(({ event, roomID, hasPreviousEv
</div>
)
}
+ } else if (isRoomMessageImageEvent(event)) {
+ const [url, setUrl] = useState<string | undefined>(undefined);
+
+ useEffect(() => {
+ if (event.content.url) {
+ setUrl(client.convertMXC(event.content.url));
+ } else {
+ // Image is encrypted and we need to download and decrypt it
+
+ }
+ }, [event.content.url])
+
+ return (
+ <div className={!hasPreviousEvent ? "flex flex-row gap-4 p-2 pb-1 hover:bg-gray-200 rounded-md duration-200 ease-in-out items-start" : "flex flex-row p-2 pb-1 pt-0 hover:bg-gray-200 rounded-md duration-200 ease-in-out"}>
+ {!hasPreviousEvent && <Avatar
+ displayname={room?.getMemberName(event.sender) || ""}
+ avatarUrl={room?.getMemberAvatar(event.sender)}
+ online={room?.isOnline() || false}
+ dm={room?.isDM() || false}
+ />}
+ <div className={!hasPreviousEvent ? "flex flex-col gap-1" : "ml-[3.7rem]"}>
+ {!hasPreviousEvent && <h2 className="text-sm font-medium text-red-500 whitespace-normal">{room?.getMemberName(event.sender)}</h2>}
+ {/* TODO: Loading circle while image is loading */}
+ <img
+ src={url}
+ alt={event.content.body}
+ title={event.content.body}
+ className="rounded-md object-cover border-slate-400 border-2 max-h-[512px] max-w-[512px] h-[unset]"
+ />
+ </div>
+ </div>
+ )
} else {
return (
<div className={!hasPreviousEvent ? "flex flex-row gap-4 p-2 pb-1 hover:bg-gray-200 rounded-md duration-200 ease-in-out items-start" : "flex flex-row p-2 pb-1 pt-0 hover:bg-gray-200 rounded-md duration-200 ease-in-out"}>
diff --git a/src/components/input/chat/input.stories.tsx b/src/components/input/chat/input.stories.tsx
@@ -1,9 +1,6 @@
import { Meta, StoryObj } from '@storybook/react';
import ChatInput from './input';
import { BADGE } from '@geometricpanda/storybook-addon-badges';
-import { $getRoot, EditorState, LexicalEditor } from 'lexical';
-import { TRANSFORMERS, $convertToMarkdownString } from "@lexical/markdown";
-import { $generateHtmlFromNodes } from "@lexical/html";
const meta: Meta<typeof ChatInput> = {
title: 'Chat/Input',
@@ -18,14 +15,6 @@ const meta: Meta<typeof ChatInput> = {
name: "Namespace",
description: "The Namespace of the editor.",
},
- onChange: {
- description: "The onChange handler of the editor.",
- required: true,
- },
- onError: {
- description: "The error handler of the editor.",
- required: true,
- },
}
};
@@ -34,19 +23,6 @@ type Story = StoryObj<typeof ChatInput>;
export const Default: Story = {
args: {
- onChange: (editorState: EditorState, editor: LexicalEditor) => {
- editorState.read(() => {
- // Read the contents of the EditorState here.
- const root = $getRoot();
- // make it markdown
- const markdown = $convertToMarkdownString(TRANSFORMERS, root);
- const html = $generateHtmlFromNodes(editor, null);
-
- console.log(markdown);
- console.log(html);
- });
- },
- onError: (error) => { console.error(error); },
namespace: "Editor"
}
};
\ No newline at end of file
diff --git a/src/index.scss b/src/index.scss
@@ -4,6 +4,10 @@ html {
height: 100%;
}
+:root {
+ font-size: 15px;
+}
+
code {
@apply rounded font-normal text-red-500 bg-slate-100 p-0.5;
}
diff --git a/tailwind.config.js b/tailwind.config.js
@@ -12,6 +12,16 @@ export default {
sans: ['Inter var', ...defaultTheme.fontFamily.sans],
},
},
+ fontSize: {
+ xs: '0.694rem',
+ sm: '0.833rem',
+ base: '1rem',
+ xl: '1.2rem',
+ '2xl': '1.44rem',
+ '3xl': '1.728rem',
+ '4xl': '2.074rem',
+ '5xl': '2.488rem',
+ }
},
plugins: [
require('@tailwindcss/forms'),