Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/Content/Embed/EmbedVideo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ interface EmbedVideoProps
extends Required<Pick<APIEmbedVideo, "width" | "height">> {
thumbnail?: APIEmbedThumbnail["url"];
url: APIEmbedVideo["url"] | undefined;
proxyUrl: APIEmbedVideo["proxy_url"] | undefined;
proxyUrl: APIEmbedVideo["proxy_url"] | undefined | null;
}

function EmbedVideo(props: EmbedVideoProps) {
if (props.proxyUrl !== undefined)
if (props.proxyUrl)
return (
<ThumbnailWrapper
thumbnail={props.thumbnail}
Expand Down
2 changes: 1 addition & 1 deletion src/Message/Reactions/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const Reaction = styled.withConfig({
display: "flex",
flexDirection: "row",
alignItems: "center",
padding: `${theme.space.small} ${theme.space.medium}`,
padding: `${theme.space.xs} ${theme.space.medium}`,
borderRadius: 8,
cursor: "not-allowed",
backgroundColor: theme.colors.backgroundSecondary,
Expand Down
21 changes: 20 additions & 1 deletion src/Message/style/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import {
styled,
theme,
} from "../../Stitches/stitches.config";
import { Link } from "../../markdown/render/elements";
import SvgFromUrl from "../../SvgFromUrl";
import { Link } from "../../markdown/render/elements";

export const SmallTimestamp = styled.withConfig({
displayName: "small-timestamp",
Expand Down Expand Up @@ -96,6 +96,25 @@ export const MessageHeaderBase = styled.withConfig({
flexWrap: "wrap",
});

export const MessageEditor = styled.withConfig({
displayName: "message-editor",
componentId: commonComponentId,
})("input", {
paddingTop: theme.space.xl,
paddingBottom: theme.space.xl,
paddingLeft: theme.space.xxl,
paddingRight: theme.space.large,
backgroundColor: theme.colors.primaryOpacity10,
// backgroundColor: theme.colors.primaryOpacity10,
outline: "none",
borderRadius: 8,
border: "none",
color: theme.colors.primaryOpacity80,
fontWeight: 400,
lineHeight: "1.375rem",
width: "100%",
});

export const AutomodHeaderText = styled.withConfig({
displayName: "automod-header-text",
componentId: commonComponentId,
Expand Down
50 changes: 50 additions & 0 deletions src/Message/variants/EditMessageInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from "react";
import { useConfig } from "../../core/ConfigContext";
import type { ChatMessage } from "../../types";

import * as Styles from "../style/message";

interface EditMessageInputProps {
// isFirstMessage?: boolean;
message: ChatMessage;
// isHovered?: boolean;
// noThreadButton?: boolean;
// isEditing?:boolean;
// isContextMenuInteraction?: boolean;
// hideTimestamp?: boolean;
// overrides?: {
// userMentioned?: boolean;
// };
}

function EditMessageInput(props: EditMessageInputProps) {
const { handleMessageEditSubmit } = useConfig();

function submitMessageCallback(content: string) {
if (!handleMessageEditSubmit || !content) return;

handleMessageEditSubmit({
...props.message,
content: content,
edited_timestamp: new Date().getMilliseconds().toString(),
});
}

function onKeyDown(e: React.KeyboardEvent<HTMLInputElement>) {
const target = e.target as HTMLInputElement;

if (e.key === "Enter") {
submitMessageCallback(target.value);
}
}

return (
<Styles.MessageEditor
autoCorrect={"false"}
onKeyDown={onKeyDown}
defaultValue={props.message.content}
/>
);
}

export default EditMessageInput;
46 changes: 28 additions & 18 deletions src/Message/variants/NormalMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import React, { memo, useMemo } from "react";
import MessageAuthor from "../MessageAuthor";
import Content from "../../Content";
import Moment from "moment";
import Tooltip from "../../Tooltip";
import type { GetAvatarOptions } from "../../utils/getAvatar";
import getAvatar from "../../utils/getAvatar";
import LargeTimestamp from "../LargeTimestamp";
import ChatTag from "../../ChatTag";
import * as Styles from "../style/message";
import type {
APIMessageInteraction,
APIRole,
APIUser,
Snowflake,
} from "discord-api-types/v10";
import { MessageType } from "discord-api-types/v10";
import Moment from "moment";
import React, { memo, useMemo } from "react";
import ChatTag from "../../ChatTag";
import Content from "../../Content";
import Tooltip from "../../Tooltip";
import { useConfig } from "../../core/ConfigContext";
import getDisplayName from "../../utils/getDisplayName";
import type { ChatMessage } from "../../types";
import type { GetAvatarOptions } from "../../utils/getAvatar";
import getAvatar from "../../utils/getAvatar";
import getDisplayName from "../../utils/getDisplayName";
import LargeTimestamp from "../LargeTimestamp";
import MessageAuthor from "../MessageAuthor";
import * as Styles from "../style/message";

interface ReplyInfoProps {
channelId: Snowflake;
Expand Down Expand Up @@ -163,8 +163,6 @@ const ReplyInfo = memo((props: ReplyInfoProps) => {

ReplyInfo.displayName = "ReplyInfo";

// type Message = Omit<MessageData, "referencedMessage"> & Partial<MessageData>;

interface MessageProps {
isFirstMessage?: boolean;
message: ChatMessage;
Expand All @@ -181,7 +179,14 @@ function NormalMessage(props: MessageProps) {
const shouldShowReply =
props.message.type === MessageType.Reply ||
Boolean(props.message.interaction);
const { currentUser, resolveChannel } = useConfig();

const {
currentUser,
resolveChannel,
editingMessageId,
EditMessageComponent,
} = useConfig();

const channel = resolveChannel(props.message.channel_id);
const guildId =
channel !== null && "guild_id" in channel ? channel.guild_id : null;
Expand Down Expand Up @@ -220,6 +225,7 @@ function NormalMessage(props: MessageProps) {
isContextMenuInteraction={props.isContextMenuInteraction}
/>
)}

<Styles.MessageHeaderBase>
<MessageAuthor
guildId={guildId}
Expand All @@ -231,10 +237,14 @@ function NormalMessage(props: MessageProps) {
<LargeTimestamp timestamp={props.message.timestamp} />
)}
</Styles.MessageHeaderBase>
<Content
message={props.message}
noThreadButton={props.noThreadButton}
/>
{editingMessageId === props.message.id && EditMessageComponent ? (
<EditMessageComponent message={props.message} />
) : (
<Content
message={props.message}
noThreadButton={props.noThreadButton}
/>
)}
</Styles.Message>
);

Expand Down
19 changes: 11 additions & 8 deletions src/core/ConfigContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import type { ReactElement } from "react";
import { createContext, useContext } from "react";
import type {
APIChannel,
APIEmbedImage,
Expand All @@ -9,11 +7,13 @@ import type {
APIUser,
Snowflake,
} from "discord-api-types/v10";
import type { SvgConfig } from "./svgs";
import type { Tag } from "../ChatTag/style";
import type { APIAttachment } from "discord-api-types/v10";
import type { UserAvatar } from "../utils/getAvatar";
import type { ReactElement } from "react";
import { createContext, useContext } from "react";
import type { Tag } from "../ChatTag/style";
import type { ChatMessage } from "../types";
import type { UserAvatar } from "../utils/getAvatar";
import type { SvgConfig } from "./svgs";

export type PartialSvgConfig = Partial<SvgConfig>;

Expand All @@ -29,9 +29,9 @@ export interface ChatBadgeProps {
}

export enum MessageTypeResponse {
InAppError,
ConsoleError,
None,
InAppError = 0,
ConsoleError = 1,
None = 2,
}

export type Config<SvgConfig extends PartialSvgConfig> = {
Expand All @@ -50,6 +50,7 @@ export type Config<SvgConfig extends PartialSvgConfig> = {
avatarUrlOverride?(user: APIUser): UserAvatar | null;
themeOverrideClassName?: string;
unknownMessageTypeResponse?: MessageTypeResponse;
editingMessageId?: string;

// Click handlers
currentUser(): APIUser | null;
Expand All @@ -62,6 +63,8 @@ export type Config<SvgConfig extends PartialSvgConfig> = {
attachmentImageOnClick?(image: APIAttachment): void;
embedImageOnClick?(image: APIEmbedImage): void;
externalLinkOpenRequested?(url: string): void;
handleMessageEditSubmit?(message: ChatMessage): void;
EditMessageComponent?: (props: { message: ChatMessage }) => JSX.Element;
};

export const ConfigContext = createContext<Config<PartialSvgConfig>>({
Expand Down
56 changes: 56 additions & 0 deletions src/stories/Normal.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,62 @@ VideoAttachment.args = {
],
};

export const Editing: StoryFn<typeof MessageGroup> = Template.bind({});
Editing.args = {
showButtons: true,
messages: [
{
id: "1101275906716213331",
type: 0,
content:
"Small update: We needed to roll this back ~~for 24 hours~~ to patch some security issues. It'll be back real soon. Update: we don't want to re-roll it out on a friday afternoon, so thisll be back next week.",
channel_id: "697138785317814292",
author: {
id: "132819036282159104",
username: "mrquine",
global_name: "Mr. Quine",
avatar: "3a30ffeeeb354950804d77ded94162d3",
discriminator: "0001",
public_flags: 4457220,
},
attachments: [],
embeds: [],
mentions: [],
mention_roles: [],
pinned: false,
mention_everyone: false,
tts: false,
timestamp: "2023-04-27T22:37:16.878000+00:00",
edited_timestamp: "2023-04-28T21:00:43.827000+00:00",
flags: 0,
components: [],
message_reference: {
channel_id: "697138785317814292",
guild_id: "613425648685547541",
message_id: "1101188115344920607",
},
reactions: [
{
emoji: {
id: null,
name: "👍",
},
count: 234,
me: false,
},
{
emoji: {
id: "1085363933579329656",
name: "App_Broom",
},
count: 185,
me: false,
},
],
},
],
};

export const Reply: StoryFn<typeof MessageGroup> = Template.bind({});
Reply.args = {
messages: [
Expand Down
Loading