diff --git a/packages/presentation/src/communication.ts b/packages/presentation/src/communication.ts index 6be9e0a896..83c405094d 100644 --- a/packages/presentation/src/communication.ts +++ b/packages/presentation/src/communication.ts @@ -47,6 +47,7 @@ import { type RequestEvent, type ResponseEvent, type UpdateNotificationContextEvent, + type AddCollaboratorsEvent, MessageRequestEventType, NotificationRequestEventType } from '@hcengineering/communication-sdk-types' @@ -181,6 +182,16 @@ class Client { await this.sendEvent(event) } + async addCollaborators (card: CardID, cardType: CardType, collaborators: AccountID[]): Promise { + const event: AddCollaboratorsEvent = { + type: NotificationRequestEventType.AddCollaborators, + card, + cardType, + collaborators + } + await this.sendEvent(event) + } + async createFile ( card: CardID, message: MessageID, diff --git a/packages/theme/styles/_next-colors.scss b/packages/theme/styles/_next-colors.scss index 2bd400e260..06579874e2 100644 --- a/packages/theme/styles/_next-colors.scss +++ b/packages/theme/styles/_next-colors.scss @@ -107,6 +107,9 @@ //MessageInput --next-message-input-color-background: var(--color-global-dark-gray); --next-message-input-color-stroke: var(--color-global-charcoal-black); + + //Message + --next-message-hover-color-background: var(--color-huly-off-white-5) } @@ -165,4 +168,8 @@ //MessageInput --next-message-input-color-background: var(--color-global-light-gray); --next-message-input-color-stroke: var(--color-global-white-100); + + + //Message + --next-message-hover-color-background: var(--color-huly-dark-grey-5) } diff --git a/packages/ui-next/lang/cs.json b/packages/ui-next/lang/cs.json index accb0b306e..51e181ad53 100644 --- a/packages/ui-next/lang/cs.json +++ b/packages/ui-next/lang/cs.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} v {time}", "YearAt": "{year} v {time}", "Yesterday": "Včera", - "YesterdayAt": "Včera v {time}" + "YesterdayAt": "Včera v {time}", + "AndMore": "a {count} dalších", + "IsTyping": "{count, plural, =1 {píše} other {píší}}" } } diff --git a/packages/ui-next/lang/de.json b/packages/ui-next/lang/de.json index dbcdec1df1..f552195f9e 100644 --- a/packages/ui-next/lang/de.json +++ b/packages/ui-next/lang/de.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} um {time}", "YearAt": "{year} um {time}", "Yesterday": "Gestern", - "YesterdayAt": "Gestern um {time}" + "YesterdayAt": "Gestern um {time}", + "AndMore": "und {count} weitere", + "IsTyping": "{count, plural, =1 {schreibt} other {schreiben}}" } } diff --git a/packages/ui-next/lang/en.json b/packages/ui-next/lang/en.json index 912a73febc..eb3db8a90b 100644 --- a/packages/ui-next/lang/en.json +++ b/packages/ui-next/lang/en.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} at {time}", "YearAt": "{year} at {time}", "Yesterday": "Yesterday", - "YesterdayAt": "Yesterday at {time}" + "YesterdayAt": "Yesterday at {time}", + "AndMore": "and {count} more", + "IsTyping": "{count, plural, =1 {is typing} other {are typing}}..." } } diff --git a/packages/ui-next/lang/es.json b/packages/ui-next/lang/es.json index e56675a57e..99738881b0 100644 --- a/packages/ui-next/lang/es.json +++ b/packages/ui-next/lang/es.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} a las {time}", "YearAt": "{year} a las {time}", "Yesterday": "Ayer", - "YesterdayAt": "Ayer a las {time}" + "YesterdayAt": "Ayer a las {time}", + "AndMore": "y {count} más", + "IsTyping": "{count, plural, =1 {está escribiendo} other {están escribiendo}}" } } diff --git a/packages/ui-next/lang/fr.json b/packages/ui-next/lang/fr.json index 3beb1d5e81..936ad7e78c 100644 --- a/packages/ui-next/lang/fr.json +++ b/packages/ui-next/lang/fr.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} à {time}", "YearAt": "{year} à {time}", "Yesterday": "Hier", - "YesterdayAt": "Hier à {time}" + "YesterdayAt": "Hier à {time}", + "AndMore": "et {count} autres", + "IsTyping": "{count, plural, =1 {est en train d'écrire} other {écrivent}}" } } diff --git a/packages/ui-next/lang/it.json b/packages/ui-next/lang/it.json index ae5dc9a98d..bffabdf786 100644 --- a/packages/ui-next/lang/it.json +++ b/packages/ui-next/lang/it.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} alle {time}", "YearAt": "{year} alle {time}", "Yesterday": "Ieri", - "YesterdayAt": "Ieri alle {time}" + "YesterdayAt": "Ieri alle {time}", + "AndMore": "e {count} altri", + "IsTyping": "{count, plural, =1 {sta scrivendo} other {stanno scrivendo}}" } } diff --git a/packages/ui-next/lang/ja.json b/packages/ui-next/lang/ja.json index ef692ffa03..fca7af07df 100644 --- a/packages/ui-next/lang/ja.json +++ b/packages/ui-next/lang/ja.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday}・{time}", "YearAt": "{year}・{time}", "Yesterday": "昨日", - "YesterdayAt": "昨日・{time}" + "YesterdayAt": "昨日・{time}", + "AndMore": "および{count}件の他", + "IsTyping": "{count, plural, =1 {入力中} other {入力中}}" } } diff --git a/packages/ui-next/lang/pt.json b/packages/ui-next/lang/pt.json index 8cb43053d6..58e4571478 100644 --- a/packages/ui-next/lang/pt.json +++ b/packages/ui-next/lang/pt.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} às {time}", "YearAt": "{year} às {time}", "Yesterday": "Ontem", - "YesterdayAt": "Ontem às {time}" + "YesterdayAt": "Ontem às {time}", + "AndMore": "e mais {count}", + "IsTyping": "{count, plural, =1 {está digitando} other {estão digitando}}" } } diff --git a/packages/ui-next/lang/ru.json b/packages/ui-next/lang/ru.json index c985eb2eb3..93a93cad64 100644 --- a/packages/ui-next/lang/ru.json +++ b/packages/ui-next/lang/ru.json @@ -25,6 +25,8 @@ "WeekdayAt": "{weekday} в {time}", "YearAt": "{year} в {time}", "Yesterday": "Вчера", - "YesterdayAt": "Вчера в {time}" + "YesterdayAt": "Вчера в {time}", + "AndMore": "и еще {count}", + "IsTyping": "{count, plural, =1 {печатает} other {печатают}}..." } } diff --git a/packages/ui-next/lang/zh.json b/packages/ui-next/lang/zh.json index a1d7831753..2e228537d7 100644 --- a/packages/ui-next/lang/zh.json +++ b/packages/ui-next/lang/zh.json @@ -26,6 +26,8 @@ "WeekdayAt": "{weekday} 于 {time}", "YearAt": "{year} 于 {time}", "Yesterday": "昨天", - "YesterdayAt": "昨天 于 {time}" + "YesterdayAt": "昨天 于 {time}", + "AndMore": "和其他 {count} 条", + "IsTyping": "{count, plural, =1 {正在输入} other {正在输入}}" } } \ No newline at end of file diff --git a/packages/ui-next/package.json b/packages/ui-next/package.json index 486c8ed9eb..1a44ab6ce2 100644 --- a/packages/ui-next/package.json +++ b/packages/ui-next/package.json @@ -56,6 +56,8 @@ "@hcengineering/ui": "^0.6.15", "@hcengineering/view": "^0.6.13", "@hcengineering/view-resources": "^0.6.0", + "@hcengineering/presence": "^0.6.0", + "@hcengineering/presence-resources": "^0.6.0", "@tiptap/core": "^2.11.7", "@tiptap/pm": "^2.11.7", "fast-equals": "^5.2.2", diff --git a/packages/ui-next/src/components/DateSeparator.svelte b/packages/ui-next/src/components/DateSeparator.svelte index 9aa4da833d..2e25c8c4fc 100644 --- a/packages/ui-next/src/components/DateSeparator.svelte +++ b/packages/ui-next/src/components/DateSeparator.svelte @@ -44,10 +44,12 @@
-
- {#await formatDate(date, $themeStore.language) then date} - {date} - {/await} +
+
+ {#await formatDate(date, $themeStore.language) then date} + {date} + {/await} +
@@ -55,10 +57,7 @@ .date-separator { display: flex; width: 100%; - padding: 0.375rem 0; - align-items: center; - gap: 0.375rem; - border-bottom: 1px solid var(--next-divider-color); + padding: 0 2rem; background: var(--next-panel-color-background); &.sticky { @@ -68,10 +67,19 @@ } } + .date-separator__content { + display: flex; + width: 100%; + align-items: center; + border-bottom: 1px solid var(--next-divider-color); + gap: 0.375rem; + padding: 0.375rem 0; + } + .date-separator__date { color: var(--next-text-color-secondary); font-size: 0.813rem; - font-weight: 500; + font-weight: 400; padding: 0 1rem; } diff --git a/packages/ui-next/src/components/ReactionPresenter.svelte b/packages/ui-next/src/components/ReactionPresenter.svelte index 70ba369501..cf92629336 100644 --- a/packages/ui-next/src/components/ReactionPresenter.svelte +++ b/packages/ui-next/src/components/ReactionPresenter.svelte @@ -14,6 +14,10 @@ --> - - -
+
{#if icon} diff --git a/packages/ui-next/src/components/ReactionsList.svelte b/packages/ui-next/src/components/ReactionsList.svelte index ecc22d4852..ea4ade7df8 100644 --- a/packages/ui-next/src/components/ReactionsList.svelte +++ b/packages/ui-next/src/components/ReactionsList.svelte @@ -58,6 +58,7 @@ me.socialIds.includes(it.creator))} + socialIds={reactions.map((it) => it.creator)} count={reactions.length} on:click={() => dispatch('click', emoji)} /> diff --git a/packages/ui-next/src/components/ReactionsTooltip.svelte b/packages/ui-next/src/components/ReactionsTooltip.svelte new file mode 100644 index 0000000000..ffd4ab5082 --- /dev/null +++ b/packages/ui-next/src/components/ReactionsTooltip.svelte @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + +
+ {#each persons as person (person)} + + {/each} +
diff --git a/packages/ui-next/src/components/TextInput.svelte b/packages/ui-next/src/components/TextInput.svelte index bdf06de8af..9777075985 100644 --- a/packages/ui-next/src/components/TextInput.svelte +++ b/packages/ui-next/src/components/TextInput.svelte @@ -20,6 +20,7 @@ import { handler, registerFocus } from '@hcengineering/ui' import { FocusPosition } from '@tiptap/core' import { createEventDispatcher } from 'svelte' + import { EditorView } from '@tiptap/pm/view' import { EmojiExtension, IsEmptyContentExtension, @@ -45,6 +46,7 @@ export let boundary: HTMLElement | undefined = undefined export let autofocus: FocusPosition = false export let onCancel: (() => void) | undefined = undefined + export let onPaste: ((view: EditorView, event: ClipboardEvent) => boolean) | undefined = undefined const dispatch = createEventDispatcher() @@ -148,9 +150,11 @@ {boundary} canEmbedFiles={false} canEmbedImages={false} + dropcursor={false} editorAttributes={{ class: 'next-text-editor-view' }} {placeholder} {placeholderParams} + {onPaste} on:content={(ev) => { if (canSubmit(loading, content, hasNonTextContent)) { dispatch('submit', ev.detail) diff --git a/packages/ui-next/src/components/TypingPresenter.svelte b/packages/ui-next/src/components/TypingPresenter.svelte new file mode 100644 index 0000000000..493bc4afc3 --- /dev/null +++ b/packages/ui-next/src/components/TypingPresenter.svelte @@ -0,0 +1,88 @@ + + + + + {#if typingPersonsLabel !== ''} + + {typingPersonsLabel} + + {#if moreCount > 0} + + {/if} + + {/if} + + + diff --git a/packages/ui-next/src/components/icons/IconMessageMultiple.svelte b/packages/ui-next/src/components/icons/IconMessageMultiple.svelte new file mode 100644 index 0000000000..aa7cf3882b --- /dev/null +++ b/packages/ui-next/src/components/icons/IconMessageMultiple.svelte @@ -0,0 +1,31 @@ + + + + + + + + diff --git a/packages/ui-next/src/components/message/MessageActionsPanel.svelte b/packages/ui-next/src/components/message/MessageActionsPanel.svelte new file mode 100644 index 0000000000..2abb6dcc6d --- /dev/null +++ b/packages/ui-next/src/components/message/MessageActionsPanel.svelte @@ -0,0 +1,108 @@ + + + + +
+ {#each actions as action (action.id)} +
+ + diff --git a/packages/ui-next/src/components/message/MessageInput.svelte b/packages/ui-next/src/components/message/MessageInput.svelte index 9987041e6e..82f09d8d60 100644 --- a/packages/ui-next/src/components/message/MessageInput.svelte +++ b/packages/ui-next/src/components/message/MessageInput.svelte @@ -20,12 +20,17 @@ import { uploadFile, deleteFile, getCommunicationClient } from '@hcengineering/presentation' import { CardID, CardType, Message } from '@hcengineering/communication-types' import { AttachmentPresenter } from '@hcengineering/attachment-resources' + import { isEmptyMarkup } from '@hcengineering/text' + import { updateMyPresence } from '@hcengineering/presence-resources' + import { ThrottledCaller } from '@hcengineering/ui' + import { getCurrentEmployee } from '@hcengineering/contact' import TextInput from '../TextInput.svelte' import { defaultMessageInputActions, toMarkdown } from '../../utils' import uiNext from '../../plugin' import IconPlus from '../icons/IconPlus.svelte' - import { type TextInputAction, UploadedFile } from '../../types' + import { type TextInputAction, UploadedFile, type PresenceTyping } from '../../types' + import TypingPresenter from '../TypingPresenter.svelte' export let cardId: CardID | undefined = undefined export let cardType: CardType | undefined = undefined @@ -36,14 +41,16 @@ export let onCancel: (() => void) | undefined = undefined export let onSubmit: ((markdown: string, files: UploadedFile[]) => Promise) | undefined = undefined + const throttle = new ThrottledCaller(500) + const dispatch = createEventDispatcher() + const communicationClient = getCommunicationClient() + const me = getCurrentEmployee() + let files: UploadedFile[] = [] let inputElement: HTMLInputElement let progress = false - const dispatch = createEventDispatcher() - const communicationClient = getCommunicationClient() - async function handleSubmit (event: CustomEvent): Promise { event.preventDefault() event.stopPropagation() @@ -57,6 +64,7 @@ if (onSubmit !== undefined) { await onSubmit(markdown, filesToLoad) + return } if (message === undefined) { @@ -145,53 +153,129 @@ } files = [] } + + async function loadFiles (evt: ClipboardEvent): Promise { + progress = true + const files = (evt.clipboardData?.files ?? []) as File[] + + for (const file of files) { + await addFile(file) + } + + progress = false + } + + function pasteAction (_: any, evt: ClipboardEvent): boolean { + let target: HTMLElement | null = evt.target as HTMLElement + let allowed = false + while (target != null) { + target = target.parentElement + if (target === inputElement) { + allowed = true + } + } + if (!allowed) { + return false + } + const hasFiles = Array.from(evt.clipboardData?.items ?? []).some((i) => i.kind === 'file') + + if (hasFiles) { + void loadFiles(evt) + return true + } + + return allowed + } + + async function fileDrop (e: DragEvent): Promise { + const list = e.dataTransfer?.files + const limiter = new RateLimiter(10) + + if (list === undefined || list.length === 0) return + progress = true + for (let index = 0; index < list.length; index++) { + const file = list.item(index) + if (file !== null) { + await limiter.add(() => addFile(file)) + } + } + await limiter.waitProcessing() + progress = false + } + + async function onUpdate (event: CustomEvent): Promise { + if (cardId === undefined || cardType === undefined) return + if (message !== undefined) return + const markup = event.detail + if (!isEmptyMarkup(markup)) { + throttle.call(() => { + const room = { objectId: cardId, objectClass: cardType } + const typing: PresenceTyping = { person: me, lastTyping: Date.now() } + updateMyPresence(room, { typing }) + }) + } + } - - 0} - actions={[...defaultMessageInputActions, attachAction]} - on:submit={handleSubmit} - onCancel={onCancel ? handleCancel : undefined} +
{}} + on:dragleave={() => {}} + on:drop|preventDefault|stopPropagation={fileDrop} > -
- {#if files.length > 0} -
- {#each files as file (file.blobId)} -
- { - if (result !== undefined) { - files = files.filter((it) => it.blobId !== file.blobId) - void deleteFile(file.blobId) - } - }} - /> -
- {/each} -
- {/if} -
- + + 0} + actions={[...defaultMessageInputActions, attachAction]} + on:submit={handleSubmit} + on:update={onUpdate} + onCancel={onCancel ? handleCancel : undefined} + onPaste={pasteAction} + > +
+ {#if files.length > 0} +
+ {#each files as file (file.blobId)} +
+ { + if (result !== undefined) { + files = files.filter((it) => it.blobId !== file.blobId) + void deleteFile(file.blobId) + } + }} + /> +
+ {/each} +
+ {/if} +
+
+
+ +{#if cardId && message === undefined} + +{/if} diff --git a/packages/ui-next/src/components/message/MessageReplies.svelte b/packages/ui-next/src/components/message/MessageReplies.svelte index 1246206b7f..7964b79b6d 100644 --- a/packages/ui-next/src/components/message/MessageReplies.svelte +++ b/packages/ui-next/src/components/message/MessageReplies.svelte @@ -125,40 +125,49 @@
-
-
+ + + -
-
+ + +
diff --git a/packages/ui-next/src/components/message/MessagesGroup.svelte b/packages/ui-next/src/components/message/MessagesGroup.svelte index 9426a99e08..e1b405742a 100644 --- a/packages/ui-next/src/components/message/MessagesGroup.svelte +++ b/packages/ui-next/src/components/message/MessagesGroup.svelte @@ -60,7 +60,6 @@ align-items: flex-start; gap: 0.75rem; width: 100%; - padding: 0 2rem; } .messages-group__messages { @@ -69,7 +68,5 @@ align-items: flex-start; flex: 1 0 0; width: 100%; - gap: 1rem; - padding: 1rem 0; } diff --git a/packages/ui-next/src/components/message/activity/ActivityObjectValue.svelte b/packages/ui-next/src/components/message/activity/ActivityObjectValue.svelte index 3e258c45fa..68a2be77e6 100644 --- a/packages/ui-next/src/components/message/activity/ActivityObjectValue.svelte +++ b/packages/ui-next/src/components/message/activity/ActivityObjectValue.svelte @@ -34,7 +34,7 @@ $: action = message.data.action - + {#if clazz.icon} @@ -54,7 +54,7 @@ disabled={action === 'remove'} accent={true} component={objectPanel?.component ?? view.component.EditDoc} - shrink={0} + shrink={1} > {card.title} diff --git a/packages/ui-next/src/plugin.ts b/packages/ui-next/src/plugin.ts index 0abb117d95..abe8b1a020 100644 --- a/packages/ui-next/src/plugin.ts +++ b/packages/ui-next/src/plugin.ts @@ -45,7 +45,9 @@ export const uiNext = plugin(uiNextId, { WeekdayAt: '' as IntlString, YearAt: '' as IntlString, Yesterday: '' as IntlString, - YesterdayAt: '' as IntlString + YesterdayAt: '' as IntlString, + AndMore: '' as IntlString, + IsTyping: '' as IntlString } }) diff --git a/packages/ui-next/src/types.ts b/packages/ui-next/src/types.ts index fa8e654739..169367d3d9 100644 --- a/packages/ui-next/src/types.ts +++ b/packages/ui-next/src/types.ts @@ -17,6 +17,8 @@ import { type Asset, type IntlString } from '@hcengineering/platform' import { type ComponentType } from 'svelte' import { type TextEditorHandler } from '@hcengineering/text-editor' import { type BlobID } from '@hcengineering/communication-types' +import type { Ref, Timestamp } from '@hcengineering/core' +import type { Person } from '@hcengineering/contact' export interface NavigationSection { id: string @@ -85,3 +87,17 @@ export interface UploadedFile { filename: string size: number } + +export interface Action { + id: string + label: IntlString + icon: IconComponent + action: (event: MouseEvent) => void + order: number + disabled?: boolean +} + +export interface PresenceTyping { + person: Ref + lastTyping: Timestamp +} diff --git a/packages/ui/src/components/internal/Root.svelte b/packages/ui/src/components/internal/Root.svelte index 0bbe190195..a97d2470fa 100644 --- a/packages/ui/src/components/internal/Root.svelte +++ b/packages/ui/src/components/internal/Root.svelte @@ -153,7 +153,12 @@ weekInfoFirstDay - +
diff --git a/plugins/chat-resources/src/components/ChatApplication.svelte b/plugins/chat-resources/src/components/ChatApplication.svelte index 2be6961986..7037ba537b 100644 --- a/plugins/chat-resources/src/components/ChatApplication.svelte +++ b/plugins/chat-resources/src/components/ChatApplication.svelte @@ -177,7 +177,6 @@ .chat { background: var(--next-background-color); border-color: var(--next-border-color); - font-family: 'Inter Display', sans-serif; } .chat__navigator { diff --git a/plugins/chat-resources/src/components/ChatFooter.svelte b/plugins/chat-resources/src/components/ChatFooter.svelte index e28c5a3dfe..5f139c1fc9 100644 --- a/plugins/chat-resources/src/components/ChatFooter.svelte +++ b/plugins/chat-resources/src/components/ChatFooter.svelte @@ -15,11 +15,13 @@ diff --git a/plugins/contact-resources/src/utils.ts b/plugins/contact-resources/src/utils.ts index 4627c1eb1a..68dc0ea085 100644 --- a/plugins/contact-resources/src/utils.ts +++ b/plugins/contact-resources/src/utils.ts @@ -401,6 +401,23 @@ export const personByPersonIdStore: Readable> = derived( return new Map(mapped) } ) + +/** + * [PersonId (social ID) => Employee] mapping + */ +export const employeeByPersonIdStore: Readable> = derived( + [personByPersonIdStore, employeeByIdStore], + ([personByPersonId, employeeById]) => { + const mapped = Array.from(personByPersonId.entries()) + .map(([personId, person]) => { + const employee = employeeById.get(person._id as Ref) + if (employee === undefined) return undefined + return [personId, employee] as const + }) + .filter(notEmpty) + return new Map(mapped) + } +) /** * [string (social key) => Employee] mapping */ diff --git a/plugins/contact/src/utils.ts b/plugins/contact/src/utils.ts index cf6f5c71a8..abf9471560 100644 --- a/plugins/contact/src/utils.ts +++ b/plugins/contact/src/utils.ts @@ -302,6 +302,14 @@ export async function getPersonBySocialId (client: Client, socialIdString: Perso return await client.findOne(contact.class.Person, { _id: socialId?.attachedTo, _class: socialId?.attachedToClass }) } +export async function getEmployeeBySocialId (client: Client, socialIdString: PersonId): Promise { + const socialId = await client.findOne(contact.class.SocialIdentity, { _id: socialIdString as SocialIdentityRef }) + + if (socialId === undefined) return undefined + + return await client.findOne(contact.mixin.Employee, { _id: socialId.attachedTo as Ref }) +} + export async function getPersonRefBySocialId ( client: Client, socialIdString: PersonId diff --git a/plugins/text-editor-resources/src/components/ReferenceInput.svelte b/plugins/text-editor-resources/src/components/ReferenceInput.svelte index 1467ad9db9..2ee2729f2f 100644 --- a/plugins/text-editor-resources/src/components/ReferenceInput.svelte +++ b/plugins/text-editor-resources/src/components/ReferenceInput.svelte @@ -162,6 +162,7 @@ {boundary} {canEmbedFiles} {canEmbedImages} + dropcursor={false} on:content={(ev) => { if (canSubmit) { dispatch('message', ev.detail) diff --git a/plugins/text-editor-resources/src/components/TextEditor.svelte b/plugins/text-editor-resources/src/components/TextEditor.svelte index 6beb9511de..a0dc4d2917 100644 --- a/plugins/text-editor-resources/src/components/TextEditor.svelte +++ b/plugins/text-editor-resources/src/components/TextEditor.svelte @@ -41,6 +41,7 @@ export let autofocus: FocusPosition = false export let canEmbedFiles = true export let canEmbedImages = true + export let dropcursor: false | undefined = undefined export let onPaste: ((view: EditorView, event: ClipboardEvent) => boolean) | undefined = undefined let element: HTMLElement @@ -167,6 +168,7 @@ (await getEditorKit()).configure({ mode: 'compact', file: canEmbedFiles ? {} : false, + dropcursor, image: canEmbedImages ? { toolbar: { diff --git a/plugins/text-editor-resources/src/kits/default-kit.ts b/plugins/text-editor-resources/src/kits/default-kit.ts index cd8c311996..cd85ed9657 100644 --- a/plugins/text-editor-resources/src/kits/default-kit.ts +++ b/plugins/text-editor-resources/src/kits/default-kit.ts @@ -40,6 +40,7 @@ export interface DefaultKitOptions { levels?: Level[] } history?: false + dropcursor?: false } export const DefaultKit = Extension.create({ @@ -59,7 +60,8 @@ export const DefaultKit = Extension.create({ heading: this.options.heading, history: this.options.history, bulletList: false, - orderedList: false + orderedList: false, + dropcursor: this.options.dropcursor }), ListItem.extend({ group: 'listItems' }), BulletList.extend({ content: 'listItems+' }), diff --git a/plugins/workbench-resources/src/components/sidebar/Sidebar.svelte b/plugins/workbench-resources/src/components/sidebar/Sidebar.svelte index 41ef14c127..66496b83ab 100644 --- a/plugins/workbench-resources/src/components/sidebar/Sidebar.svelte +++ b/plugins/workbench-resources/src/components/sidebar/Sidebar.svelte @@ -50,6 +50,7 @@ flex-direction: row; min-width: 25rem; border-radius: 0 var(--medium-BorderRadius) var(--medium-BorderRadius) 0; + border-bottom: 1px solid transparent; // adjust the side panel body height to match the main panel &.mini { justify-content: flex-end;