From 6b17f569bb66cc632ba73b69d4c3e5b370141521 Mon Sep 17 00:00:00 2001 From: Michael Peters Date: Sun, 5 Dec 2021 23:52:10 -0600 Subject: [PATCH] jsx is for professionals --- ...lay-add-guild.ts => overlay-add-guild.tsx} | 80 +++++++------- ...-channel.ts => overlay-create-channel.tsx} | 36 +++--- .../elements/overlay-create-invite-token.ts | 24 ---- .../elements/overlay-create-invite-token.tsx | 28 +++++ .../webapp/elements/overlay-error-message.ts | 10 -- .../webapp/elements/overlay-error-message.tsx | 11 ++ ...settings.ts => overlay-guild-settings.tsx} | 104 +++++++++--------- .../{overlay-image.ts => overlay-image.tsx} | 28 +++-- ...-channel.ts => overlay-modify-channel.tsx} | 45 +++++--- ...personalize.ts => overlay-personalize.tsx} | 63 +++++++---- ...lay-token-log.ts => overlay-token-log.tsx} | 12 +- ...rget.ts => overlay-upload-drop-target.tsx} | 13 ++- .../webapp/elements/require/base-elements.tsx | 53 ++++----- .../webapp/elements/require/elements-util.tsx | 17 +-- 14 files changed, 284 insertions(+), 240 deletions(-) rename src/client/webapp/elements/{overlay-add-guild.ts => overlay-add-guild.tsx} (78%) rename src/client/webapp/elements/{overlay-create-channel.ts => overlay-create-channel.tsx} (80%) delete mode 100644 src/client/webapp/elements/overlay-create-invite-token.ts create mode 100644 src/client/webapp/elements/overlay-create-invite-token.tsx delete mode 100644 src/client/webapp/elements/overlay-error-message.ts create mode 100644 src/client/webapp/elements/overlay-error-message.tsx rename src/client/webapp/elements/{overlay-guild-settings.ts => overlay-guild-settings.tsx} (72%) rename src/client/webapp/elements/{overlay-image.ts => overlay-image.tsx} (80%) rename src/client/webapp/elements/{overlay-modify-channel.ts => overlay-modify-channel.tsx} (77%) rename src/client/webapp/elements/{overlay-personalize.ts => overlay-personalize.tsx} (69%) rename src/client/webapp/elements/{overlay-token-log.ts => overlay-token-log.tsx} (92%) rename src/client/webapp/elements/{overlay-upload-drop-target.ts => overlay-upload-drop-target.tsx} (84%) diff --git a/src/client/webapp/elements/overlay-add-guild.ts b/src/client/webapp/elements/overlay-add-guild.tsx similarity index 78% rename from src/client/webapp/elements/overlay-add-guild.ts rename to src/client/webapp/elements/overlay-add-guild.tsx index 62354ad..ea37fa0 100644 --- a/src/client/webapp/elements/overlay-add-guild.ts +++ b/src/client/webapp/elements/overlay-add-guild.tsx @@ -19,6 +19,9 @@ import UI from '../ui'; import GuildsManager from '../guilds-manager'; import CombinedGuild from '../guild-combined'; +import React from 'react'; +import ReactHelper from './require/react-helper'; + export interface IAddGuildData { name: string, url: string, @@ -58,45 +61,44 @@ export default function createAddGuildOverlay(document: Document, q: Q, ui: UI, //LOG.debug('addguilddata:', { addGuildData }); - const element = BaseElements.createOverlay(document, { - class: 'content add-guild', content: [ - { class: 'preview', content: [ - { tag: 'img', class: 'icon', src: addGuildData.iconSrc, alt: 'icon' }, - { content: [ - { class: 'name', content: addGuildData.name }, - { class: 'url', content: addGuildData.url }, - { class: 'expires', - content: (expired ? 'Invite Expired ' : 'Invite Expires ') + moment(addGuildData.expires).fromNow() } - ] } - ] }, - { class: 'divider' }, - { class: 'message-preview message', content: [ - { class: 'member-avatar', content: { tag: 'img', src: './img/loading.svg', alt: 'avatar' } }, - { class: 'right', content: [ - { class: 'header', content: [ - { class: 'member-name', content: displayName }, - { class: 'timestamp', content: moment().calendar(ElementsUtil.calendarFormats) } - ] }, - { class: 'content text', content: 'Example Message' } - ] } - ] }, - { class: 'display-name-input', placeholder: 'Display Name', - spellcheck: 'false', contenteditable: 'plaintext-only', content: displayName }, - { class: 'avatar-input', content: [ - { tag: 'label', class: 'avatar-upload-label button', content: [ - 'Select Avatar', - { class: 'avatar-upload', tag: 'input', - type: 'file', accept: '.png,.jpg,.jpeg', style: 'display: none;' }, - ] } - ] }, - { class: 'lower', content: [ - { class: 'error' }, - { class: 'buttons', content: [ - { class: 'button submit', content: 'Add Guild' } - ] } - ] } - ] - }); + + const element = BaseElements.createOverlay(document, ( +
+
+ icon +
+
{addGuildData.name}
+
{addGuildData.url}
+
{(expired ? 'Invite Expired ' : 'Invite Expires ') + moment(addGuildData.expires).fromNow()}
+
+
+
+
+
avatar
+
+
+
{displayName}
+
{moment().calendar(ElementsUtil.calendarFormats)}
+
+
What's up, gamers?
+
+
+
+
+ +
+
+
+
+
Add Guild
+
+
+
+ )); let avatarBuff: Buffer | null; let defaultAvatarBuff: Buffer | null; diff --git a/src/client/webapp/elements/overlay-create-channel.ts b/src/client/webapp/elements/overlay-create-channel.tsx similarity index 80% rename from src/client/webapp/elements/overlay-create-channel.ts rename to src/client/webapp/elements/overlay-create-channel.tsx index a2a9d86..130cb20 100644 --- a/src/client/webapp/elements/overlay-create-channel.ts +++ b/src/client/webapp/elements/overlay-create-channel.tsx @@ -10,26 +10,30 @@ import BaseElements from "./require/base-elements"; import Q from '../q-module'; import CombinedGuild from '../guild-combined'; +import React from 'react'; + export default function createCreateChannelOverlay(document: Document, q: Q, guild: CombinedGuild): HTMLElement { // See also overlay-modify-channel - const element = BaseElements.createOverlay(document, { class: 'content submit-dialog modify-channel', content: [ - { class: 'preview channel-title', content: [ - { class: 'channel-icon', content: BaseElements.Q_TEXT_CHANNEL_ICON }, - { class: 'channel-name', content: 'channel-name' }, - { class: 'channel-flavor-divider' }, - { class: 'channel-flavor-text', content: '' } - ] }, - { class: 'text-input channel-name', 'data-placeholder': 'channel-name', content: '', contenteditable: 'plaintext-only' }, - { class: 'text-input channel-flavor-text', 'data-placeholder': 'Flavor Text (optional)', content: '' || '', contenteditable: 'plaintext-only' }, - { class: 'lower', content: [ - { class: 'error' }, - { class: 'buttons', content: [ - { class: 'button submit', content: 'Create Channel' } - ] } - ] } - ] }); + const element = BaseElements.createOverlay(document, ( +
+
+
{BaseElements.TEXT_CHANNEL_ICON}
+
channel-name
+
+
+
+
+
+
+
+
+
Create Channel
+
+
+
+ )); let newName = ''; let newFlavorText: string | null = ''; diff --git a/src/client/webapp/elements/overlay-create-invite-token.ts b/src/client/webapp/elements/overlay-create-invite-token.ts deleted file mode 100644 index cb55953..0000000 --- a/src/client/webapp/elements/overlay-create-invite-token.ts +++ /dev/null @@ -1,24 +0,0 @@ -import CombinedGuild from "../guild-combined"; -import BaseElements from "./require/base-elements"; - -export default function createCreateInviteTokenOverlay(document: Document, guild: CombinedGuild): HTMLElement { - const element = BaseElements.createOverlay(document, { class: 'content submit-dialog', content: [ - { class: 'role-select category-select', content: [ - { class: 'label', content: 'Select Starting Roles' }, - { class: 'categories', content: [ - { class: 'category suggestion-1', content: '+Gamer' }, - { class: 'category suggestion-2', content: '+Chodist' }, - { class: 'category suggestion-3', content: '+Gamer' }, - { class: 'category more', content: 'More...' }, - ] } - ] }, - { class: 'lower', content: [ - { class: 'error' }, - { class: 'buttons', content: [ - { class: 'button submit', content: 'Create Invite Token' } - ] } - ] } - ] }); - - return element; -} diff --git a/src/client/webapp/elements/overlay-create-invite-token.tsx b/src/client/webapp/elements/overlay-create-invite-token.tsx new file mode 100644 index 0000000..9f97f02 --- /dev/null +++ b/src/client/webapp/elements/overlay-create-invite-token.tsx @@ -0,0 +1,28 @@ +import CombinedGuild from "../guild-combined"; +import BaseElements, { HTMLElementWithRemoveSelf } from "./require/base-elements"; + +import React from "react"; + +export default function createCreateInviteTokenOverlay(document: Document, guild: CombinedGuild): HTMLElementWithRemoveSelf { + const element = BaseElements.createOverlay(document, ( +
+
+
Select Starting Roles
+
+
+Gamer
+
+Chodist
+
+Gamer
+
More...
+
+
+
+
+
+
Create Invite Token
+
+
+
+ )); + + return element; +} diff --git a/src/client/webapp/elements/overlay-error-message.ts b/src/client/webapp/elements/overlay-error-message.ts deleted file mode 100644 index 5297743..0000000 --- a/src/client/webapp/elements/overlay-error-message.ts +++ /dev/null @@ -1,10 +0,0 @@ -import BaseElements from './require/base-elements.js'; - -export default function createErrorMessageOverlay(document: Document, title: string, message: string): HTMLElement { - return BaseElements.createOverlay(document, { - class: 'content error-message', content: [ - { class: 'title', content: title }, - { class: 'message', content: message } - ] - }); -} diff --git a/src/client/webapp/elements/overlay-error-message.tsx b/src/client/webapp/elements/overlay-error-message.tsx new file mode 100644 index 0000000..32071a3 --- /dev/null +++ b/src/client/webapp/elements/overlay-error-message.tsx @@ -0,0 +1,11 @@ +import React from 'react'; +import BaseElements, { HTMLElementWithRemoveSelf } from './require/base-elements.js'; + +export default function createErrorMessageOverlay(document: Document, title: string, message: string): HTMLElementWithRemoveSelf { + return BaseElements.createOverlay(document, ( +
+
{title}
+
{message}
+
+ )); +} diff --git a/src/client/webapp/elements/overlay-guild-settings.ts b/src/client/webapp/elements/overlay-guild-settings.tsx similarity index 72% rename from src/client/webapp/elements/overlay-guild-settings.ts rename to src/client/webapp/elements/overlay-guild-settings.tsx index 9e6ac6a..0948f1c 100644 --- a/src/client/webapp/elements/overlay-guild-settings.ts +++ b/src/client/webapp/elements/overlay-guild-settings.tsx @@ -6,64 +6,61 @@ const LOG = Logger.create(__filename, electronConsole); import Globals from '../globals'; -import BaseElements from './require/base-elements'; +import BaseElements, { HTMLElementWithRemoveSelf } from './require/base-elements'; import ElementsUtil from './require/elements-util'; import { GuildMetadata } from '../data-types'; import Q from '../q-module'; import CombinedGuild from '../guild-combined'; -export default function createGuildSettingsOverlay(document: Document, q: Q, guild: CombinedGuild, guildMeta: GuildMetadata): HTMLElement { - const element = BaseElements.createOverlay(document, { - class: 'content display-swapper guild-settings', content: [ - { class: 'options', content: [ - { class: 'title', content: guildMeta.name }, // TODO: update on change - { class: 'choosable chosen', content: 'Overview' }, - { class: 'choosable', content: 'Channels' }, - { class: 'choosable', content: 'Roles' }, - { class: 'choosable', content: 'Invites' }, - ] }, - { class: 'display', content: [ - { class: 'scroll', content: [ - { class: 'metadata', content: [ - { tag: 'label', class: 'image-input-label', content: [ - { class: 'image-input', content: [ - { class: 'icon', content: [ - { tag: 'img', class: 'guild-icon', src: './img/loading.svg', alt: 'icon' }, - { class: 'modify', content: [ - { tag: 'img', src: './img/pencil-icon.png' } - ] } - ] }, - ] }, - { tag: 'input', class: 'image-input-upload', type: 'file', accept: '.png,.jpg,.jpeg', style: 'display: none' } - ] }, - { class: 'name', content: [ - { class: 'label', content: 'Guild Name' }, - { tag: 'input', type: 'text', class: 'guild-name', 'placeholder': guildMeta.name, - contenteditable: 'plaintext-only', content: guildMeta.name }, - ] }, - ] } - ] }, - { class: 'popup changes', content: [ - { class: 'content', content: [ - { class: 'tip', content: 'You have unsaved changes' }, - { class: 'actions', content: [ - { class: 'button perdu reset', content: 'Reset' }, - { class: 'button positive save-changes', content: 'Save Changes' } - ] } - ]} - ] }, - { class: 'popup error', content: [ - { class: 'content', content: [ - { class: 'tip' }, - { class: 'actions', content: [ - { class: 'button perdu close', content: 'X' }, - ] } - ] } - ] }, - ] } - ] - }); +import React from 'react'; + +export default function createGuildSettingsOverlay(document: Document, q: Q, guild: CombinedGuild, guildMeta: GuildMetadata): HTMLElementWithRemoveSelf { + const element = BaseElements.createOverlay(document, ( +
+
+
{guildMeta.name}
+
Overview
+
Channels
+
Roles
+
Invites
+
+
+
+
+ +
+
Guild Name
+ +
+
+
+
+
+
You have unsaved changes
+
+
Reset
+
Save Changes
+
+
+
+
+
+
+
+
X
+
+
+
+
+
+ )); let newIconBuff: Buffer | null = null; let oldName = guildMeta.name; @@ -87,8 +84,10 @@ export default function createGuildSettingsOverlay(document: Document, q: Q, gui } function reset() { + q.$$$(element, '.image-input-upload').value = ''; q.$$$(element, 'input.guild-name').value = oldName; (async () => { + LOG.debug('resetting icon'); q.$$$(element, '.icon img').src = await ElementsUtil.getImageBufferFromResourceFailSoftly(guild, guildMeta.iconResourceId); })(); @@ -114,6 +113,7 @@ export default function createGuildSettingsOverlay(document: Document, q: Q, gui onCleared: () => {}, onError: async (errMsg) => await updatePopups(errMsg), onLoaded: async (buff, src) => { + LOG.debug('image loaded'); newIconBuff = buff; (q.$$$(element, 'img.guild-icon') as HTMLImageElement).src = src; await updatePopups(); diff --git a/src/client/webapp/elements/overlay-image.ts b/src/client/webapp/elements/overlay-image.tsx similarity index 80% rename from src/client/webapp/elements/overlay-image.ts rename to src/client/webapp/elements/overlay-image.tsx index 6aa8f42..5870fd3 100644 --- a/src/client/webapp/elements/overlay-image.ts +++ b/src/client/webapp/elements/overlay-image.tsx @@ -5,24 +5,28 @@ const LOG = Logger.create(__filename, electronConsole); import * as FileType from 'file-type' -import BaseElements from './require/base-elements'; +import BaseElements, { HTMLElementWithRemoveSelf } from './require/base-elements'; import ElementsUtil from './require/elements-util'; import Q from '../q-module'; import createImageContextMenu from './context-menu-img'; import CombinedGuild from '../guild-combined'; -export default function createImageOverlay(document: Document, q: Q, guild: CombinedGuild, resourceId: string, resourceName: string): HTMLElement { - const element = BaseElements.createOverlay(document, { class: 'content popup-image', content: [ - { tag: 'img', src: './img/loading.svg', alt: resourceName, title: resourceName }, - { class: 'download', content: [ - { class: 'info', content: [ - { class: 'name', content: resourceName }, - { class: 'size', content: 'Loading Size...' } - ] }, - { class: 'button', content: 'Loading...' } - ] } - ] }); +import React from 'react'; + +export default function createImageOverlay(document: Document, q: Q, guild: CombinedGuild, resourceId: string, resourceName: string): HTMLElementWithRemoveSelf { + const element = BaseElements.createOverlay(document, ( +
+ {resourceName} +
+
+
{resourceName}
+
Loading Size...
+
+
Loading...
+
+
+ )); (async () => { try { diff --git a/src/client/webapp/elements/overlay-modify-channel.ts b/src/client/webapp/elements/overlay-modify-channel.tsx similarity index 77% rename from src/client/webapp/elements/overlay-modify-channel.ts rename to src/client/webapp/elements/overlay-modify-channel.tsx index 2a37fde..4fe0aee 100644 --- a/src/client/webapp/elements/overlay-modify-channel.ts +++ b/src/client/webapp/elements/overlay-modify-channel.tsx @@ -6,30 +6,39 @@ const LOG = Logger.create(__filename, electronConsole); import { Channel } from '../data-types'; import Globals from '../globals.js'; -import BaseElements from './require/base-elements.js'; +import BaseElements, { HTMLElementWithRemoveSelf } from './require/base-elements.js'; import ElementsUtil from './require/elements-util.js'; import Q from '../q-module'; import CombinedGuild from '../guild-combined'; -export default function createModifyChannelOverlay(document: Document, q: Q, guild: CombinedGuild, channel: Channel): HTMLElement { +import React from 'react'; + +export default function createModifyChannelOverlay(document: Document, q: Q, guild: CombinedGuild, channel: Channel): HTMLElementWithRemoveSelf { // See also overlay-create-channel - const element = BaseElements.createOverlay(document, { class: 'content submit-dialog modify-channel', content: [ - { class: 'preview channel-title', content: [ - { class: 'channel-icon', content: BaseElements.Q_TEXT_CHANNEL_ICON }, - { class: 'channel-name', content: channel.name }, - { class: 'channel-flavor-divider' }, - { class: 'channel-flavor-text', content: channel.flavorText || '' } - ] }, - { class: 'text-input channel-name', 'data-placeholder': 'channel-name', content: channel.name, contenteditable: 'plaintext-only' }, - { class: 'text-input channel-flavor-text', 'data-placeholder': 'Flavor Text (optional)', content: channel.flavorText || '', contenteditable: 'plaintext-only' }, - { class: 'lower', content: [ - { class: 'error' }, - { class: 'buttons', content: [ - { class: 'button submit', content: 'Save Changes' } - ] } - ] } - ] }); + const element = BaseElements.createOverlay(document, ( +
+
+
{BaseElements.TEXT_CHANNEL_ICON}
+
{channel.name}
+
+
{channel.flavorText || ''}
+
+
+
+
+
+
+
Save Changes
+
+
+
+ )); + + q.$$$(element, '.text-input.channel-name').innerText = channel.name; + q.$$$(element, '.text-input.channel-flavor-text').innerText = channel.flavorText || ''; let newName = channel.name; let newFlavorText = channel.flavorText; diff --git a/src/client/webapp/elements/overlay-personalize.ts b/src/client/webapp/elements/overlay-personalize.tsx similarity index 69% rename from src/client/webapp/elements/overlay-personalize.ts rename to src/client/webapp/elements/overlay-personalize.tsx index f8cb6ba..b199ab4 100644 --- a/src/client/webapp/elements/overlay-personalize.ts +++ b/src/client/webapp/elements/overlay-personalize.tsx @@ -4,7 +4,7 @@ const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); -import BaseElements from './require/base-elements'; +import BaseElements, { HTMLElementWithRemoveSelf } from './require/base-elements'; import ElementsUtil from './require/elements-util'; import Globals from '../globals'; @@ -14,27 +14,46 @@ import createTextMessage from './msg-txt'; import CombinedGuild from '../guild-combined'; import { ConnectionInfo } from '../data-types'; -export default function createPersonalizeOverlay(document: Document, q: Q, guild: CombinedGuild, connection: ConnectionInfo): HTMLElement { - const element = BaseElements.createOverlay(document, { - class: 'content submit-dialog personalize', content: [ - createTextMessage(q, guild, { id: 'test-message', member: connection, sent: new Date(), text: 'Example Message' }), - { class: 'text-input', placeholder: 'New Display Name', - spellcheck: 'false', contenteditable: 'plaintext-only', content: connection.displayName }, - { class: 'image-input avatar-input', content: [ - { tag: 'label', class: 'image-input-label avatar-input-label button', content: [ - 'Select New Avatar', - { class: 'image-input-upload avatar-upload', tag: 'input', - type: 'file', accept: '.png,.jpg,.jpeg', style: 'display: none;' }, - ] } - ] }, - { class: 'lower', content: [ - { class: 'error' }, - { class: 'buttons', content: [ - { class: 'button submit', content: 'Save Changes' } - ] } - ] } - ] - }); +import React from 'react'; +import moment from 'moment'; + +export default function createPersonalizeOverlay(document: Document, q: Q, guild: CombinedGuild, connection: ConnectionInfo): HTMLElementWithRemoveSelf { + const element = BaseElements.createOverlay(document, ( +
+
+
+ {connection.displayName} +
+
+
+
{connection.displayName}
+
{moment(new Date()).calendar(ElementsUtil.calendarFormats)}
+
+
Example Message
+
+
+
+
+ +
+
+
+
+
Save Changes
+
+
+
+ )); + + q.$$$(element, '.text-input.display-name-input').innerText = connection.displayName; + (async () => { + (q.$$$(element, '.member-avatar img') as HTMLImageElement).src = + await ElementsUtil.getImageBufferFromResourceFailSoftly(guild, connection.avatarResourceId); + })(); let newAvatarBuffer: Buffer | null = null; BaseElements.bindImageUploadEvents(q.$$$(element, '.avatar-upload') as HTMLInputElement, { diff --git a/src/client/webapp/elements/overlay-token-log.ts b/src/client/webapp/elements/overlay-token-log.tsx similarity index 92% rename from src/client/webapp/elements/overlay-token-log.ts rename to src/client/webapp/elements/overlay-token-log.tsx index 7bcdbaa..53b1936 100644 --- a/src/client/webapp/elements/overlay-token-log.ts +++ b/src/client/webapp/elements/overlay-token-log.tsx @@ -13,12 +13,14 @@ import { Member } from '../data-types'; import Q from '../q-module'; import CombinedGuild from '../guild-combined'; +import React from 'react'; + export default function createTokenLogOverlay(document: Document, q: Q, guild: CombinedGuild): HTMLElement { - const element = BaseElements.createOverlay(document, { - class: 'content token-log', content: [ - { class: 'tokens', content: { tag: 'img', src: './img/loading.svg', alt: 'loading...' } }, - ] - }); + const element = BaseElements.createOverlay(document, ( +
+
Loading...
+
+ )); (async () => { Util.withPotentialErrorWarnOnCancel(q, { diff --git a/src/client/webapp/elements/overlay-upload-drop-target.ts b/src/client/webapp/elements/overlay-upload-drop-target.tsx similarity index 84% rename from src/client/webapp/elements/overlay-upload-drop-target.ts rename to src/client/webapp/elements/overlay-upload-drop-target.tsx index 4230848..bc0f8ed 100644 --- a/src/client/webapp/elements/overlay-upload-drop-target.ts +++ b/src/client/webapp/elements/overlay-upload-drop-target.tsx @@ -9,11 +9,16 @@ import Q from '../q-module'; import createUploadOverlayFromDataTransferItem from './overlay-upload-datatransfer'; import CombinedGuild from '../guild-combined'; +import React from 'react'; + export default function createUploadDropTarget(document: Document, q: Q, guild: CombinedGuild, channel: Channel): HTMLElement { - const element = BaseElements.createOverlay(document, { class: 'content drop-target', content: [ - // TODO: icon? - { class: 'message', content: 'Upload to #' + channel.name } - ] }); + const element = BaseElements.createOverlay(document, ( +
+ {/* TODO: icon? */} +
Upload to #{channel.name}
+
+ )); + element.addEventListener('dragover', (e) => { e.preventDefault(); e.stopPropagation(); diff --git a/src/client/webapp/elements/require/base-elements.tsx b/src/client/webapp/elements/require/base-elements.tsx index a71e3e3..9cafca9 100644 --- a/src/client/webapp/elements/require/base-elements.tsx +++ b/src/client/webapp/elements/require/base-elements.tsx @@ -250,12 +250,18 @@ export default class BaseElements { } // eslint-disable-next-line @typescript-eslint/no-explicit-any - static createOverlay(document: Document, content: any): HTMLElementWithRemoveSelf { + static createOverlay(document: Document, content: JSX.Element): HTMLElementWithRemoveSelf { const q = new Q(document); let wasDownInternal = false; // because 'click' fires on the overlay element anyway // eslint-disable-next-line @typescript-eslint/no-explicit-any - const element = q.create({ class: 'overlay', content: content }) as any; + const element: HTMLElementWithRemoveSelf = ReactHelper.createElementFromJSX(
{content}
) as HTMLElementWithRemoveSelf; + element.removeSelf = () => { + if (element.parentElement) { + element.parentElement.removeChild(element); + } + window.removeEventListener('keydown', onKeyEscape); + } const onKeyEscape = (e: KeyboardEvent) => { if (e.key == 'Escape') { element.removeSelf(); @@ -269,12 +275,7 @@ export default class BaseElements { } element.removeSelf(); }); - element.removeSelf = () => { - if (element.parentElement) { - element.parentElement.removeChild(element); - } - window.removeEventListener('keydown', onKeyEscape); - } + q.$$$(element, '.content').addEventListener('click', (e) => { e.stopPropagation(); // prevent the element from closing if the content is clicked on }); @@ -290,23 +291,25 @@ export default class BaseElements { const { guild, channel, resourceName, resourceBuffFunc, resourceSizeFunc } = props; - const element = BaseElements.createOverlay(document, { class: 'content upload', content: [ - { class: 'title', content: [ - { tag: 'img', src: './img/loading.svg', alt: resourceName }, - { class: 'right', content: [ - { class: 'name', content: resourceName }, - { class: 'size', content: '? B' } - ] } - ] }, - { class: 'text-input', placeholder: 'Add a comment (optional)', contenteditable: 'plaintext-only' }, - { class: 'lower', content: [ - { class: 'error' }, - { class: 'buttons', content: [ - { class: 'button upload', content: 'Upload to #' + channel.name } - ] } - ] } - - ] }); + const element = BaseElements.createOverlay(document, ( +
+
+ {resourceName} +
+
{resourceName}
+
? B
+
+
+
+
+
+
+
Upload to #{channel.name}
+
+
+
+ )); + q.$$$(element, '.text-input').addEventListener('keydown', async (e) => { if (e.key == 'Enter' && !e.shiftKey) { e.preventDefault(); diff --git a/src/client/webapp/elements/require/elements-util.tsx b/src/client/webapp/elements/require/elements-util.tsx index 3b822d3..f8b3c9c 100644 --- a/src/client/webapp/elements/require/elements-util.tsx +++ b/src/client/webapp/elements/require/elements-util.tsx @@ -9,6 +9,7 @@ import Logger from '../../../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); import * as FileType from 'file-type'; +import * as uuid from 'uuid'; import Util from '../../util'; import Globals from '../../globals'; @@ -17,11 +18,6 @@ import { ShouldNeverHappenError } from '../../data-types'; import React from 'react'; -// TODO: pass-through Globals in init function -// alignment: { -// centerY: 'top' -// left: 'right + 20' -// } interface IAlignment { left?: string; centerX?: string; @@ -37,7 +33,6 @@ interface IHTMLElementWithRemovalType extends HTMLElement { interface SimpleQElement { tag: 'span', - // eslint-disable-next-line @typescript-eslint/no-explicit-any content: (SimpleQElement | string)[], class: string | null } @@ -124,11 +119,8 @@ export default class ElementsUtil { } // creates spans to format the text (all in q.js element markup that gets converted to jsx [aka hypergaming]) - // eslint-disable-next-line @typescript-eslint/no-explicit-any static parseMessageText(text: string): JSX.Element { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const obj: SimpleQElement = { tag: 'span', content: [] as (SimpleQElement | string)[], class: null }; - // eslint-disable-next-line @typescript-eslint/no-explicit-any + const obj: SimpleQElement = { tag: 'span', content: [], class: null }; const stack: SimpleQElement[] = [ obj ]; let idx = 0; function makeEscape(regex: RegExp, len: number, str: string): { matcher: RegExp, response: ((i: number) => void)} { // function for readability @@ -152,8 +144,7 @@ export default class ElementsUtil { // TODO: optimise out empty elements stack.pop(); } else { // italic begins - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const obj: SimpleQElement = { tag: 'span', class: cls, content: [] as any[] } + const obj: SimpleQElement = { tag: 'span', class: cls, content: [] } top.content.push(obj); stack.push(obj); } @@ -195,7 +186,7 @@ export default class ElementsUtil { return qjsObj } else { const content = qjsObj.content.map(qjsElement => createReactElement(qjsElement)); - return React.createElement(qjsObj.tag, { className: qjsObj.class }, content); + return React.createElement(qjsObj.tag, { key: uuid.v4(), className: qjsObj.class }, content); } }