Compare commits

..

2 Commits

Author SHA1 Message Date
57cc41b2cf capture Mac command key
* remove tooltip
2025-05-16 11:58:55 -07:00
9ec688f679 commenteditor-emoji-picker 2025-04-30 19:41:04 +02:00
11 changed files with 45 additions and 9 deletions

View File

@ -15,7 +15,7 @@ export default function EnforceSso() {
<Text size="md">{t("Enforce SSO")}</Text> <Text size="md">{t("Enforce SSO")}</Text>
<Text size="sm" c="dimmed"> <Text size="sm" c="dimmed">
{t( {t(
"Once enforced, members will not be able to login with email and password.", "Once enforced, members will not able to login with email and password.",
)} )}
</Text> </Text>
</div> </div>

View File

@ -1,4 +1,4 @@
import { Button, Group } from "@mantine/core"; import { Button, Group, Tooltip } from "@mantine/core";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
type CommentActionsProps = { type CommentActionsProps = {

View File

@ -109,6 +109,7 @@ function CommentDialog({ editor, pageId }: CommentDialogProps) {
<CommentEditor <CommentEditor
onUpdate={handleCommentEditorChange} onUpdate={handleCommentEditorChange}
onSave={handleAddComment}
placeholder={t("Write a comment")} placeholder={t("Write a comment")}
editable={true} editable={true}
autofocus={true} autofocus={true}

View File

@ -8,10 +8,12 @@ import { useFocusWithin } from "@mantine/hooks";
import clsx from "clsx"; import clsx from "clsx";
import { forwardRef, useEffect, useImperativeHandle } from "react"; import { forwardRef, useEffect, useImperativeHandle } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import EmojiCommand from "@/features/editor/extensions/emoji-command";
interface CommentEditorProps { interface CommentEditorProps {
defaultContent?: any; defaultContent?: any;
onUpdate?: any; onUpdate?: any;
onSave?: any;
editable: boolean; editable: boolean;
placeholder?: string; placeholder?: string;
autofocus?: boolean; autofocus?: boolean;
@ -22,6 +24,7 @@ const CommentEditor = forwardRef(
{ {
defaultContent, defaultContent,
onUpdate, onUpdate,
onSave,
editable, editable,
placeholder, placeholder,
autofocus, autofocus,
@ -42,7 +45,35 @@ const CommentEditor = forwardRef(
}), }),
Underline, Underline,
Link, Link,
EmojiCommand,
], ],
editorProps: {
handleDOMEvents: {
keydown: (_view, event) => {
if (
[
"ArrowUp",
"ArrowDown",
"ArrowLeft",
"ArrowRight",
"Enter",
].includes(event.key)
) {
const emojiCommand = document.querySelector("#emoji-command");
if (emojiCommand) {
return true;
}
}
if ((event.ctrlKey || event.metaKey) && event.key === "Enter") {
event.preventDefault();
if (onSave) onSave();
return true;
}
},
},
},
onUpdate({ editor }) { onUpdate({ editor }) {
if (onUpdate) onUpdate(editor.getJSON()); if (onUpdate) onUpdate(editor.getJSON());
}, },

View File

@ -112,6 +112,7 @@ function CommentListItem({ comment }: CommentListItemProps) {
defaultContent={content} defaultContent={content}
editable={true} editable={true}
onUpdate={(newContent: any) => setContent(newContent)} onUpdate={(newContent: any) => setContent(newContent)}
onSave={handleUpdateComment}
autofocus={true} autofocus={true}
/> />

View File

@ -142,6 +142,7 @@ const CommentEditorWithActions = ({ commentId, onSave, isLoading }) => {
<CommentEditor <CommentEditor
ref={commentEditorRef} ref={commentEditorRef}
onUpdate={setContent} onUpdate={setContent}
onSave={handleSave}
editable={true} editable={true}
/> />
{focused && <CommentActions onSave={handleSave} isLoading={isLoading} />} {focused && <CommentActions onSave={handleSave} isLoading={isLoading} />}

View File

@ -16,17 +16,19 @@
.commentEditor { .commentEditor {
.focused { .focused {
border-radius: var(--mantine-radius-sm);
box-shadow: 0 0 0 2px var(--mantine-color-blue-3); box-shadow: 0 0 0 2px var(--mantine-color-blue-3);
} }
.ProseMirror :global(.ProseMirror){ .ProseMirror :global(.ProseMirror){
border-radius: var(--mantine-radius-sm);
max-width: 100%; max-width: 100%;
white-space: pre-wrap; white-space: pre-wrap;
word-break: break-word; word-break: break-word;
max-height: 20vh; max-height: 20vh;
padding-left: 6px; padding-left: 6px;
padding-right: 6px; padding-right: 6px;
margin-top: 2px; margin-top: 10px;
margin-bottom: 2px; margin-bottom: 2px;
overflow: hidden auto; overflow: hidden auto;
} }

View File

@ -33,7 +33,7 @@ const renderEmojiItems = () => {
showOnCreate: true, showOnCreate: true,
interactive: true, interactive: true,
trigger: "manual", trigger: "manual",
placement: "bottom-start", placement: "bottom",
}); });
}, },
onStart: (props: { onStart: (props: {

View File

@ -387,14 +387,14 @@ export class WorkspaceService {
.replace(/[^a-z0-9]/g, '') .replace(/[^a-z0-9]/g, '')
.substring(0, 20); .substring(0, 20);
// Ensure we leave room for a random suffix. // Ensure we leave room for a random suffix.
const maxSuffixLength = 6; const maxSuffixLength = 3;
if (subdomain.length < 4) { if (subdomain.length < 4) {
subdomain = `${subdomain}-${generateRandomSuffix(maxSuffixLength)}`; subdomain = `${subdomain}-${generateRandomSuffix(maxSuffixLength)}`;
} }
if (DISALLOWED_HOSTNAMES.includes(subdomain)) { if (DISALLOWED_HOSTNAMES.includes(subdomain)) {
subdomain = `workspace-${generateRandomSuffix(maxSuffixLength)}`; subdomain = `myworkspace-${generateRandomSuffix(maxSuffixLength)}`;
} }
let uniqueHostname = subdomain; let uniqueHostname = subdomain;

View File

@ -70,7 +70,7 @@ export class UserTokenRepo {
.where('userId', '=', userId) .where('userId', '=', userId)
.where('workspaceId', '=', workspaceId) .where('workspaceId', '=', workspaceId)
.where('type', '=', tokenType) .where('type', '=', tokenType)
.orderBy('expiresAt', 'desc') .orderBy('expiresAt desc')
.execute(); .execute();
} }

View File

@ -70,7 +70,7 @@ export class WorkspaceRepo {
return await this.db return await this.db
.selectFrom('workspaces') .selectFrom('workspaces')
.selectAll() .selectAll()
.orderBy('createdAt', 'asc') .orderBy('createdAt asc')
.limit(1) .limit(1)
.executeTakeFirst(); .executeTakeFirst();
} }