Merge branch 'cinnyapp:dev' into ts

This commit is contained in:
Array in a Matrix 2023-06-14 09:17:52 -04:00 committed by GitHub
commit c072b1281c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 81 additions and 34 deletions

View file

@ -12,7 +12,7 @@ jobs:
PR_NUMBER: ${{github.event.number}} PR_NUMBER: ${{github.event.number}}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.5.3
- name: Setup node - name: Setup node
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0
with: with:

View file

@ -45,7 +45,7 @@ jobs:
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_PR_CINNY }} NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID_PR_CINNY }}
timeout-minutes: 1 timeout-minutes: 1
- name: Comment preview on PR - name: Comment preview on PR
uses: thollander/actions-comment-pull-request@632cf9ce90574d125be56b5f3405cda41a84e2fd uses: thollander/actions-comment-pull-request@dadb7667129e23f12ca3925c90dc5cd7121ab57e
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with: with:

View file

@ -11,9 +11,9 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.5.3
- name: Build Docker image - name: Build Docker image
uses: docker/build-push-action@v3.2.0 uses: docker/build-push-action@v4.1.0
with: with:
context: . context: .
push: false push: false

View file

@ -14,7 +14,7 @@ jobs:
pull-requests: write pull-requests: write
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.5.3
- name: NPM Lockfile Changes - name: NPM Lockfile Changes
uses: codepunkt/npm-lockfile-changes@b40543471c36394409466fdb277a73a0856d7891 uses: codepunkt/npm-lockfile-changes@b40543471c36394409466fdb277a73a0856d7891
with: with:

View file

@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.5.3
- name: Setup node - name: Setup node
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0
with: with:

View file

@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.5.3
- name: Setup node - name: Setup node
uses: actions/setup-node@v3.6.0 uses: actions/setup-node@v3.6.0
with: with:
@ -66,11 +66,11 @@ jobs:
packages: write packages: write
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3.2.0 uses: actions/checkout@v3.5.3
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v2.1.0 uses: docker/setup-qemu-action@v2.1.0
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2.2.1 uses: docker/setup-buildx-action@v2.6.0
- name: Login to Docker Hub - name: Login to Docker Hub
uses: docker/login-action@v2.1.0 uses: docker/login-action@v2.1.0
with: with:
@ -84,13 +84,13 @@ jobs:
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker - name: Extract metadata (tags, labels) for Docker
id: meta id: meta
uses: docker/metadata-action@v4.1.1 uses: docker/metadata-action@v4.5.0
with: with:
images: | images: |
${{ secrets.DOCKER_USERNAME }}/cinny ${{ secrets.DOCKER_USERNAME }}/cinny
ghcr.io/${{ github.repository }} ghcr.io/${{ github.repository }}
- name: Build and push Docker image - name: Build and push Docker image
uses: docker/build-push-action@v3.2.0 uses: docker/build-push-action@v4.1.0
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64 platforms: linux/amd64,linux/arm64

View file

@ -11,7 +11,7 @@ RUN npm run build
## App ## App
FROM nginx:1.23.3-alpine FROM nginx:1.25.0-alpine
COPY --from=builder /src/dist /app COPY --from=builder /src/dist /app

View file

@ -93,7 +93,8 @@ export const CustomEditor = forwardRef<HTMLDivElement, CustomEditorProps>(
const handleKeydown: KeyboardEventHandler = useCallback( const handleKeydown: KeyboardEventHandler = useCallback(
(evt) => { (evt) => {
onKeyDown?.(evt); onKeyDown?.(evt);
toggleKeyboardShortcut(editor, evt); const shortcutToggled = toggleKeyboardShortcut(editor, evt);
if (shortcutToggled) evt.preventDefault();
}, },
[editor, onKeyDown] [editor, onKeyDown]
); );

View file

@ -104,7 +104,7 @@ export function EmoticonAutocomplete({
as="img" as="img"
src={mx.mxcUrlToHttp(key) || key} src={mx.mxcUrlToHttp(key) || key}
alt={emoticon.shortcode} alt={emoticon.shortcode}
style={{ width: toRem(24), height: toRem(24) }} style={{ width: toRem(24), height: toRem(24), objectFit: 'contain' }}
/> />
) : ( ) : (
<Box <Box

View file

@ -23,13 +23,14 @@ export const getAutocompletePrefix = <TPrefix extends string>(
validPrefixes: readonly TPrefix[] validPrefixes: readonly TPrefix[]
): TPrefix | undefined => { ): TPrefix | undefined => {
const world = Editor.string(editor, queryRange); const world = Editor.string(editor, queryRange);
const prefix = world[0] as TPrefix | undefined; return validPrefixes.find((p) => world.startsWith(p));
if (!prefix) return undefined;
return validPrefixes.includes(prefix) ? prefix : undefined;
}; };
export const getAutocompleteQueryText = (editor: Editor, queryRange: BaseRange): string => export const getAutocompleteQueryText = (
Editor.string(editor, queryRange).slice(1); editor: Editor,
queryRange: BaseRange,
prefix: string
): string => Editor.string(editor, queryRange).slice(prefix.length);
export const getAutocompleteQuery = <TPrefix extends string>( export const getAutocompleteQuery = <TPrefix extends string>(
editor: Editor, editor: Editor,
@ -41,6 +42,6 @@ export const getAutocompleteQuery = <TPrefix extends string>(
return { return {
range: queryRange, range: queryRange,
prefix, prefix,
text: getAutocompleteQueryText(editor, queryRange), text: getAutocompleteQueryText(editor, queryRange, prefix),
}; };
}; };

View file

@ -2,11 +2,25 @@ import { BasePoint, BaseRange, Editor, Element, Point, Range, Transforms } from
import { BlockType, MarkType } from './Elements'; import { BlockType, MarkType } from './Elements';
import { EmoticonElement, FormattedText, HeadingLevel, LinkElement, MentionElement } from './slate'; import { EmoticonElement, FormattedText, HeadingLevel, LinkElement, MentionElement } from './slate';
const ALL_MARK_TYPE: MarkType[] = [
MarkType.Bold,
MarkType.Code,
MarkType.Italic,
MarkType.Spoiler,
MarkType.StrikeThrough,
MarkType.Underline,
];
export const isMarkActive = (editor: Editor, format: MarkType) => { export const isMarkActive = (editor: Editor, format: MarkType) => {
const marks = Editor.marks(editor); const marks = Editor.marks(editor);
return marks ? marks[format] === true : false; return marks ? marks[format] === true : false;
}; };
export const isAnyMarkActive = (editor: Editor) => {
const marks = Editor.marks(editor);
return marks && !!ALL_MARK_TYPE.find((type) => marks[type] === true);
};
export const toggleMark = (editor: Editor, format: MarkType) => { export const toggleMark = (editor: Editor, format: MarkType) => {
const isActive = isMarkActive(editor, format); const isActive = isMarkActive(editor, format);
@ -17,6 +31,10 @@ export const toggleMark = (editor: Editor, format: MarkType) => {
} }
}; };
export const removeAllMark = (editor: Editor) => {
ALL_MARK_TYPE.forEach((mark) => Editor.removeMark(editor, mark));
};
export const isBlockActive = (editor: Editor, format: BlockType) => { export const isBlockActive = (editor: Editor, format: BlockType) => {
const [match] = Editor.nodes(editor, { const [match] = Editor.nodes(editor, {
match: (node) => Element.isElement(node) && node.type === format, match: (node) => Element.isElement(node) && node.type === format,
@ -140,11 +158,11 @@ export const replaceWithElement = (editor: Editor, selectRange: BaseRange, eleme
}; };
export const moveCursor = (editor: Editor, withSpace?: boolean) => { export const moveCursor = (editor: Editor, withSpace?: boolean) => {
// without timeout it works properly when we select autocomplete with Tab or Space // without timeout move cursor doesn't works properly.
setTimeout(() => { setTimeout(() => {
Transforms.move(editor); Transforms.move(editor);
if (withSpace) editor.insertText(' '); if (withSpace) editor.insertText(' ');
}, 1); }, 100);
}; };
interface PointUntilCharOptions { interface PointUntilCharOptions {

View file

@ -1,7 +1,7 @@
import { isHotkey } from 'is-hotkey'; import { isHotkey } from 'is-hotkey';
import { KeyboardEvent } from 'react'; import { KeyboardEvent } from 'react';
import { Editor } from 'slate'; import { Editor } from 'slate';
import { isBlockActive, toggleBlock, toggleMark } from './common'; import { isAnyMarkActive, isBlockActive, removeAllMark, toggleBlock, toggleMark } from './common';
import { BlockType, MarkType } from './Elements'; import { BlockType, MarkType } from './Elements';
export const INLINE_HOTKEYS: Record<string, MarkType> = { export const INLINE_HOTKEYS: Record<string, MarkType> = {
@ -22,19 +22,42 @@ export const BLOCK_HOTKEYS: Record<string, BlockType> = {
}; };
const BLOCK_KEYS = Object.keys(BLOCK_HOTKEYS); const BLOCK_KEYS = Object.keys(BLOCK_HOTKEYS);
export const toggleKeyboardShortcut = (editor: Editor, event: KeyboardEvent<Element>) => { /**
BLOCK_KEYS.forEach((hotkey) => { * @return boolean true if shortcut is toggled.
*/
export const toggleKeyboardShortcut = (editor: Editor, event: KeyboardEvent<Element>): boolean => {
if (isHotkey('escape', event)) {
if (isAnyMarkActive(editor)) {
removeAllMark(editor);
return true;
}
console.log(isBlockActive(editor, BlockType.Paragraph));
if (!isBlockActive(editor, BlockType.Paragraph)) {
toggleBlock(editor, BlockType.Paragraph);
return true;
}
return false;
}
const blockToggled = BLOCK_KEYS.find((hotkey) => {
if (isHotkey(hotkey, event)) { if (isHotkey(hotkey, event)) {
event.preventDefault(); event.preventDefault();
toggleBlock(editor, BLOCK_HOTKEYS[hotkey]); toggleBlock(editor, BLOCK_HOTKEYS[hotkey]);
return true;
} }
return false;
}); });
if (blockToggled) return true;
if (!isBlockActive(editor, BlockType.CodeBlock)) const inlineToggled = isBlockActive(editor, BlockType.CodeBlock)
INLINE_KEYS.forEach((hotkey) => { ? false
if (isHotkey(hotkey, event)) { : INLINE_KEYS.find((hotkey) => {
event.preventDefault(); if (isHotkey(hotkey, event)) {
toggleMark(editor, INLINE_HOTKEYS[hotkey]); event.preventDefault();
} toggleMark(editor, INLINE_HOTKEYS[hotkey]);
}); return true;
}
return false;
});
return !!inlineToggled;
}; };

View file

@ -88,7 +88,7 @@ const elementToPlainText = (node: CustomElement, children: string): string => {
export const toPlainText = (node: Descendant | Descendant[]): string => { export const toPlainText = (node: Descendant | Descendant[]): string => {
if (Array.isArray(node)) return node.map((n) => toPlainText(n)).join(''); if (Array.isArray(node)) return node.map((n) => toPlainText(n)).join('');
if (Text.isText(node)) return sanitizeText(node.text); if (Text.isText(node)) return node.text;
const children = node.children.map((n) => toPlainText(n)).join(''); const children = node.children.map((n) => toPlainText(n)).join('');
return elementToPlainText(node, children); return elementToPlainText(node, children);

View file

@ -122,6 +122,7 @@ export const CustomEmojiImg = style([
{ {
width: toRem(32), width: toRem(32),
height: toRem(32), height: toRem(32),
objectFit: 'contain',
}, },
]); ]);
@ -130,5 +131,6 @@ export const StickerImg = style([
{ {
width: toRem(96), width: toRem(96),
height: toRem(96), height: toRem(96),
objectFit: 'contain',
}, },
]); ]);

View file

@ -373,6 +373,7 @@ function ImagePackSidebarStack({
style={{ style={{
width: toRem(24), width: toRem(24),
height: toRem(24), height: toRem(24),
objectFit: 'contain',
}} }}
src={mx.mxcUrlToHttp(pack.getPackAvatarUrl(usage) ?? '') || pack.avatarUrl} src={mx.mxcUrlToHttp(pack.getPackAvatarUrl(usage) ?? '') || pack.avatarUrl}
alt={label || 'Unknown Pack'} alt={label || 'Unknown Pack'}

View file

@ -184,12 +184,13 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
body, body,
formattedBody, formattedBody,
}); });
ReactEditor.focus(editor);
}; };
navigation.on(cons.events.navigation.REPLY_TO_CLICKED, handleReplyTo); navigation.on(cons.events.navigation.REPLY_TO_CLICKED, handleReplyTo);
return () => { return () => {
navigation.removeListener(cons.events.navigation.REPLY_TO_CLICKED, handleReplyTo); navigation.removeListener(cons.events.navigation.REPLY_TO_CLICKED, handleReplyTo);
}; };
}, [setReplyDraft]); }, [setReplyDraft, editor]);
const handleRemoveUpload = useCallback( const handleRemoveUpload = useCallback(
(upload: TUploadContent | TUploadContent[]) => { (upload: TUploadContent | TUploadContent[]) => {