From 2659726c4a0181548264490cba2c96748767f5ed Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 20 Oct 2021 12:40:33 -0600 Subject: [PATCH 01/11] PSFD-423: Permission check for polls dialog --- .../views/rooms/MessageComposer.tsx | 31 ++++++++++++------- src/i18n/strings/en_EN.json | 1 + src/stores/polls/consts.ts | 19 ++++++++++++ 3 files changed, 40 insertions(+), 11 deletions(-) create mode 100644 src/stores/polls/consts.ts diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 79f613b9965..91b4e91d52b 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -56,6 +56,8 @@ import Modal from "../../../Modal"; import InfoDialog from "../dialogs/InfoDialog"; import { RelationType } from 'matrix-js-sdk/src/@types/event'; import RoomContext from '../../../contexts/RoomContext'; +import { POLL_START_EVENT_TYPE } from "../../../stores/polls/consts"; +import ErrorDialog from "../dialogs/ErrorDialog"; let instanceCount = 0; const NARROW_MODE_BREAKPOINT = 500; @@ -197,18 +199,25 @@ class UploadButton extends React.Component { } } +interface IPollButtonProps { + room: Room; +} + // TODO: [polls] Make this component actually do something -class PollButton extends React.PureComponent { +class PollButton extends React.PureComponent { private onCreateClick = () => { - Modal.createTrackedDialog('Polls', 'Not Yet Implemented', InfoDialog, { - // XXX: Deliberately not translated given this dialog is meant to be replaced and we don't - // want to clutter the language files with short-lived strings. - title: "Polls are currently in development", - description: "" + - "Thanks for testing polls! We haven't quite gotten a chance to write the feature yet " + - "though. Check back later for updates.", - hasCloseButton: true, - }); + const canSend = this.props.room.currentState.maySendEvent( + POLL_START_EVENT_TYPE.name, + MatrixClientPeg.get().getUserId(), + ); + if (!canSend) { + Modal.createTrackedDialog('Polls', 'permissions error: cannot start', ErrorDialog, { + title: _t("Permission Required"), + description: _t("You do not have permission to start polls in this room."), + }); + } else { + // start + } }; render() { @@ -463,7 +472,7 @@ export default class MessageComposer extends React.Component { if (!this.state.haveRecording) { if (SettingsStore.getValue("feature_polls")) { buttons.push( - , + , ); } buttons.push( diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 68f4fca1835..c389ce21a1f 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1585,6 +1585,7 @@ "Emoji picker": "Emoji picker", "Add emoji": "Add emoji", "Upload file": "Upload file", + "You do not have permission to start polls in this room.": "You do not have permission to start polls in this room.", "Create poll": "Create poll", "Reply to encrypted thread…": "Reply to encrypted thread…", "Reply to thread…": "Reply to thread…", diff --git a/src/stores/polls/consts.ts b/src/stores/polls/consts.ts new file mode 100644 index 00000000000..0c8b5df0d80 --- /dev/null +++ b/src/stores/polls/consts.ts @@ -0,0 +1,19 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { UnstableValue } from "matrix-js-sdk/src/NamespacedValue"; + +export const POLL_START_EVENT_TYPE = new UnstableValue("m.poll.start", "org.matrix.msc3381.poll.start"); From 14b01d1610a0059721b3790aec73649d7eaf1968 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 20 Oct 2021 13:43:24 -0600 Subject: [PATCH 02/11] PSFD-423: Implement compound scrollable dialog and skeleton create poll --- res/css/_components.scss | 3 +- res/css/views/dialogs/_CompoundDialog.scss | 87 +++++++++++++++ .../views/dialogs/ScrollableBaseModal.tsx | 105 ++++++++++++++++++ .../views/elements/PollCreateDialog.tsx | 53 +++++++++ .../views/rooms/MessageComposer.tsx | 6 +- src/i18n/strings/en_EN.json | 1 + 6 files changed, 252 insertions(+), 3 deletions(-) create mode 100644 res/css/views/dialogs/_CompoundDialog.scss create mode 100644 src/components/views/dialogs/ScrollableBaseModal.tsx create mode 100644 src/components/views/elements/PollCreateDialog.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index 26e36b8cddb..c3851433b9b 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -74,6 +74,7 @@ @import "./views/dialogs/_ChangelogDialog.scss"; @import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss"; @import "./views/dialogs/_CommunityPrototypeInviteDialog.scss"; +@import "./views/dialogs/_CompoundDialog.scss"; @import "./views/dialogs/_ConfirmSpaceUserActionDialog.scss"; @import "./views/dialogs/_ConfirmUserActionDialog.scss"; @import "./views/dialogs/_CreateCommunityPrototypeDialog.scss"; @@ -200,10 +201,10 @@ @import "./views/right_panel/_EncryptionInfo.scss"; @import "./views/right_panel/_PinnedMessagesCard.scss"; @import "./views/right_panel/_RoomSummaryCard.scss"; +@import "./views/right_panel/_ThreadPanel.scss"; @import "./views/right_panel/_UserInfo.scss"; @import "./views/right_panel/_VerificationPanel.scss"; @import "./views/right_panel/_WidgetCard.scss"; -@import "./views/right_panel/_ThreadPanel.scss"; @import "./views/room_settings/_AliasSettings.scss"; @import "./views/rooms/_AppsDrawer.scss"; @import "./views/rooms/_Autocomplete.scss"; diff --git a/res/css/views/dialogs/_CompoundDialog.scss b/res/css/views/dialogs/_CompoundDialog.scss new file mode 100644 index 00000000000..d90c7e0f8e6 --- /dev/null +++ b/res/css/views/dialogs/_CompoundDialog.scss @@ -0,0 +1,87 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// -------------------------------------------------------------------------------- +// DEV NOTE: This stylesheet covers dialogs listed by the compound, including +// over multiple React components. The actual inner contents of the dialog should +// be in their respective stylesheets. +// -------------------------------------------------------------------------------- + +// Override legacy/default styles for dialogs +.mx_Dialog_wrapper.mx_CompoundDialog > .mx_Dialog { + padding: 0; // we'll manage it ourselves + color: $primary-content; +} + +.mx_CompoundDialog { + .mx_CompoundDialog_header { + padding: 32px 32px 16px 32px; + + h1 { + display: inline-block; + font-weight: 600; + font-size: $font-24px; + margin: 0; // managed by header class + } + + .mx_CompoundDialog_cancelButton { + mask: url('$(res)/img/feather-customised/cancel.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: cover; + width: 20px; + height: 20px; + background-color: $dialog-close-fg-color; + cursor: pointer; + + // Align with middle of title, 34px from right edge + position: absolute; + top: 34px; + right: 34px; + } + } + + .mx_CompoundDialog_content { + overflow: auto; + padding: 8px 32px; + } + + .mx_CompoundDialog_footer { + padding: 20px 32px; + text-align: right; + position: absolute; + bottom: 0; + left: 0; + right: 0; + + .mx_AccessibleButton { + margin-left: 24px; + } + } +} + +.mx_ScrollableBaseDialog { + width: 544px; // fixed + height: 516px; // fixed + + .mx_CompoundDialog_content { + height: 349px; // dialogHeight - header - footer + } + + .mx_CompoundDialog_footer { + box-shadow: 0px -4px 4px rgba(0, 0, 0, 0.05); // hardcoded colour for both themes + } +} diff --git a/src/components/views/dialogs/ScrollableBaseModal.tsx b/src/components/views/dialogs/ScrollableBaseModal.tsx new file mode 100644 index 00000000000..c1a56682877 --- /dev/null +++ b/src/components/views/dialogs/ScrollableBaseModal.tsx @@ -0,0 +1,105 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { MatrixClient } from "matrix-js-sdk/src/client"; +import { MatrixClientPeg } from "../../../MatrixClientPeg"; +import { Key } from "../../../Keyboard"; +import { IDialogProps } from "./IDialogProps"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import FocusLock from "react-focus-lock"; +import { _t } from "../../../languageHandler"; +import AccessibleButton from "../elements/AccessibleButton"; + +export interface IScrollableBaseState { + canSubmit: boolean; + title: string; + actionLabel: string; +} + +/** + * Scrollable dialog base from Compound (Web Components). + */ +export abstract class ScrollableBaseModal + extends React.PureComponent { + + protected constructor(props: TProps) { + super(props); + } + + protected get matrixClient(): MatrixClient { + return MatrixClientPeg.get(); + } + + private onKeyDown = (e: KeyboardEvent | React.KeyboardEvent): void => { + if (e.key === Key.ESCAPE) { + e.stopPropagation(); + e.preventDefault(); + this.cancel(); + } + }; + + private onCancel = () => { + this.cancel(); + }; + + private onSubmit = () => { + this.submit(); + }; + + protected abstract cancel(): void; + protected abstract submit(): void; + protected abstract renderContent(): React.ReactNode; + + public render(): JSX.Element { + return ( + + +
+

{ this.state.title }

+ +
+
+ { this.renderContent() } +
+
+ + { _t("Cancel") } + + + { this.state.actionLabel } + +
+
+
+ ); + } +} diff --git a/src/components/views/elements/PollCreateDialog.tsx b/src/components/views/elements/PollCreateDialog.tsx new file mode 100644 index 00000000000..120f148036b --- /dev/null +++ b/src/components/views/elements/PollCreateDialog.tsx @@ -0,0 +1,53 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { IScrollableBaseState, ScrollableBaseModal } from "../dialogs/ScrollableBaseModal"; +import { IDialogProps } from "../dialogs/IDialogProps"; +import React from "react"; +import { _t } from "../../../languageHandler"; +import { Room } from "matrix-js-sdk/src/models/room"; + +interface IProps extends IDialogProps { + room: Room; +} + +interface IState extends IScrollableBaseState { +} + +export default class PollCreateDialog extends ScrollableBaseModal { + public constructor(props: IProps) { + super(props); + + this.state = { + title: _t("Create poll"), + actionLabel: _t("Create Poll"), + canSubmit: false, // need to add a question and at least one option first + }; + } + + protected submit(): void { + console.log("@@ TODO"); + this.props.onFinished(true); + } + + protected cancel(): void { + this.props.onFinished(false); + } + + protected renderContent(): React.ReactNode { + return "TODO"; + } +} diff --git a/src/components/views/rooms/MessageComposer.tsx b/src/components/views/rooms/MessageComposer.tsx index 91b4e91d52b..b935f037322 100644 --- a/src/components/views/rooms/MessageComposer.tsx +++ b/src/components/views/rooms/MessageComposer.tsx @@ -58,6 +58,7 @@ import { RelationType } from 'matrix-js-sdk/src/@types/event'; import RoomContext from '../../../contexts/RoomContext'; import { POLL_START_EVENT_TYPE } from "../../../stores/polls/consts"; import ErrorDialog from "../dialogs/ErrorDialog"; +import PollCreateDialog from "../elements/PollCreateDialog"; let instanceCount = 0; const NARROW_MODE_BREAKPOINT = 500; @@ -203,7 +204,6 @@ interface IPollButtonProps { room: Room; } -// TODO: [polls] Make this component actually do something class PollButton extends React.PureComponent { private onCreateClick = () => { const canSend = this.props.room.currentState.maySendEvent( @@ -216,7 +216,9 @@ class PollButton extends React.PureComponent { description: _t("You do not have permission to start polls in this room."), }); } else { - // start + Modal.createTrackedDialog('Polls', 'create', PollCreateDialog, { + room: this.props.room, + }, 'mx_CompoundDialog'); } }; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index c389ce21a1f..7c298d7e6f1 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2158,6 +2158,7 @@ "%(oneUser)schanged the server ACLs %(count)s times|one": "%(oneUser)schanged the server ACLs", "%(severalUsers)schanged the pinned messages for the room %(count)s times.|other": "%(severalUsers)schanged the pinned messages for the room %(count)s times.", "%(oneUser)schanged the pinned messages for the room %(count)s times.|other": "%(oneUser)schanged the pinned messages for the room %(count)s times.", + "Create Poll": "Create Poll", "Power level": "Power level", "Custom level": "Custom level", "QR Code": "QR Code", From 01c9495e01860b31a5f580c759c9a90ad1a2da2f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 20 Oct 2021 14:39:47 -0600 Subject: [PATCH 03/11] PSFD-325: Ask the question --- res/css/_components.scss | 1 + res/css/views/dialogs/_PollCreateDialog.scss | 25 +++++++++++++++++ .../views/elements/PollCreateDialog.tsx | 28 +++++++++++++++++-- src/i18n/strings/en_EN.json | 3 ++ 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 res/css/views/dialogs/_PollCreateDialog.scss diff --git a/res/css/_components.scss b/res/css/_components.scss index c3851433b9b..116189d64cc 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -100,6 +100,7 @@ @import "./views/dialogs/_MessageEditHistoryDialog.scss"; @import "./views/dialogs/_ModalWidgetDialog.scss"; @import "./views/dialogs/_NewSessionReviewDialog.scss"; +@import "./views/dialogs/_PollCreateDialog.scss"; @import "./views/dialogs/_RegistrationEmailPromptDialog.scss"; @import "./views/dialogs/_RoomSettingsDialog.scss"; @import "./views/dialogs/_RoomSettingsDialogBridges.scss"; diff --git a/res/css/views/dialogs/_PollCreateDialog.scss b/res/css/views/dialogs/_PollCreateDialog.scss new file mode 100644 index 00000000000..74dd55f43ce --- /dev/null +++ b/res/css/views/dialogs/_PollCreateDialog.scss @@ -0,0 +1,25 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +.mx_PollCreateDialog { + h2 { + font-weight: 600; + font-size: $font-15px; + line-height: $font-24px; + margin-top: 0; + margin-bottom: 8px; + } +} diff --git a/src/components/views/elements/PollCreateDialog.tsx b/src/components/views/elements/PollCreateDialog.tsx index 120f148036b..1beecd0bd24 100644 --- a/src/components/views/elements/PollCreateDialog.tsx +++ b/src/components/views/elements/PollCreateDialog.tsx @@ -16,15 +16,18 @@ limitations under the License. import { IScrollableBaseState, ScrollableBaseModal } from "../dialogs/ScrollableBaseModal"; import { IDialogProps } from "../dialogs/IDialogProps"; -import React from "react"; +import React, { ChangeEvent } from "react"; import { _t } from "../../../languageHandler"; import { Room } from "matrix-js-sdk/src/models/room"; +import Field from "./Field"; +import AccessibleButton from "./AccessibleButton"; interface IProps extends IDialogProps { room: Room; } interface IState extends IScrollableBaseState { + question: string; } export default class PollCreateDialog extends ScrollableBaseModal { @@ -35,9 +38,22 @@ export default class PollCreateDialog extends ScrollableBaseModal 0, + }); + } + + private onQuestionChange = (e: ChangeEvent) => { + this.setState({ question: e.target.value }, () => this.checkCanSubmit()); + }; + protected submit(): void { console.log("@@ TODO"); this.props.onFinished(true); @@ -48,6 +64,14 @@ export default class PollCreateDialog extends ScrollableBaseModal +

{ _t("What is your poll question or topic?") }

+ + ; } } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 7c298d7e6f1..934f3869133 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2159,6 +2159,9 @@ "%(severalUsers)schanged the pinned messages for the room %(count)s times.|other": "%(severalUsers)schanged the pinned messages for the room %(count)s times.", "%(oneUser)schanged the pinned messages for the room %(count)s times.|other": "%(oneUser)schanged the pinned messages for the room %(count)s times.", "Create Poll": "Create Poll", + "What is your poll question or topic?": "What is your poll question or topic?", + "Question or topic": "Question or topic", + "Write something...": "Write something...", "Power level": "Power level", "Custom level": "Custom level", "QR Code": "QR Code", From d28d011f5b7e87860b6f2429272a62aeb4fc46a7 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 20 Oct 2021 14:40:13 -0600 Subject: [PATCH 04/11] PSFD-328: Ask for options --- res/css/views/dialogs/_PollCreateDialog.scss | 45 +++++++++++++++++ res/img/element-icons/x-8px.svg | 4 ++ .../views/elements/PollCreateDialog.tsx | 50 ++++++++++++++++++- src/i18n/strings/en_EN.json | 4 ++ 4 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 res/img/element-icons/x-8px.svg diff --git a/res/css/views/dialogs/_PollCreateDialog.scss b/res/css/views/dialogs/_PollCreateDialog.scss index 74dd55f43ce..240ed73eeb0 100644 --- a/res/css/views/dialogs/_PollCreateDialog.scss +++ b/res/css/views/dialogs/_PollCreateDialog.scss @@ -21,5 +21,50 @@ limitations under the License. line-height: $font-24px; margin-top: 0; margin-bottom: 8px; + + &:nth-child(n + 2) { + margin-top: 20px; + } + } + + .mx_PollCreateDialog_option { + display: flex; + align-items: center; + margin-top: 11px; + margin-bottom: 22px; // 11px from the top will collapse, so this creates a 22px gap between options + + .mx_Field { + flex: 1; + margin: 0; + } + + .mx_PollCreateDialog_removeOption { + margin-left: 12px; + width: 20px; + height: 20px; + border-radius: 50%; + background-color: $quinary-content; + cursor: pointer; + position: relative; + + &::before { + content: ""; + mask: url('$(res)/img/element-icons/x-8px.svg'); + mask-repeat: no-repeat; + mask-position: center; + mask-size: cover; + width: 8px; + height: 8px; + position: absolute; + top: 6px; + left: 6px; + background-color: $secondary-content; + } + } + } + + .mx_PollCreateDialog_addOption { + padding: 0; + margin-bottom: 40px; // arbitrary to create scrollable area under the poll } } diff --git a/res/img/element-icons/x-8px.svg b/res/img/element-icons/x-8px.svg new file mode 100644 index 00000000000..c9730ed6192 --- /dev/null +++ b/res/img/element-icons/x-8px.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/views/elements/PollCreateDialog.tsx b/src/components/views/elements/PollCreateDialog.tsx index 1beecd0bd24..abc3551061d 100644 --- a/src/components/views/elements/PollCreateDialog.tsx +++ b/src/components/views/elements/PollCreateDialog.tsx @@ -19,6 +19,7 @@ import { IDialogProps } from "../dialogs/IDialogProps"; import React, { ChangeEvent } from "react"; import { _t } from "../../../languageHandler"; import { Room } from "matrix-js-sdk/src/models/room"; +import { arrayFastClone, arraySeed } from "../../../utils/arrays"; import Field from "./Field"; import AccessibleButton from "./AccessibleButton"; @@ -28,8 +29,13 @@ interface IProps extends IDialogProps { interface IState extends IScrollableBaseState { question: string; + options: string[]; } +const MIN_OPTIONS = 1; +const MAX_OPTIONS = 20; +const DEFAULT_NUM_OPTIONS = 2; + export default class PollCreateDialog extends ScrollableBaseModal { public constructor(props: IProps) { super(props); @@ -40,13 +46,15 @@ export default class PollCreateDialog extends ScrollableBaseModal 0, + this.state.question.trim().length > 0 && + this.state.options.filter(op => op.trim().length > 0).length >= MIN_OPTIONS, }); } @@ -54,6 +62,24 @@ export default class PollCreateDialog extends ScrollableBaseModal this.checkCanSubmit()); }; + private onOptionChange = (i: number, e: ChangeEvent) => { + const newOptions = arrayFastClone(this.state.options); + newOptions[i] = e.target.value; + this.setState({ options: newOptions }, () => this.checkCanSubmit()); + }; + + private onOptionRemove = (i: number) => { + const newOptions = arrayFastClone(this.state.options); + newOptions.splice(i, 1); + this.setState({ options: newOptions }, () => this.checkCanSubmit()); + }; + + private onOptionAdd = () => { + const newOptions = arrayFastClone(this.state.options); + newOptions.push(""); + this.setState({ options: newOptions }); + }; + protected submit(): void { console.log("@@ TODO"); this.props.onFinished(true); @@ -72,6 +98,28 @@ export default class PollCreateDialog extends ScrollableBaseModal +

{ _t("Create options") }

+ { + this.state.options.map((op, i) =>
+ this.onOptionChange(i, e)} + /> + this.onOptionRemove(i)} + disabled={this.state.options.length <= MIN_OPTIONS} + className="mx_PollCreateDialog_removeOption" + /> +
) + } + = MAX_OPTIONS} + kind="secondary" + className="mx_PollCreateDialog_addOption" + >{ _t("Add option") } ; } } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 934f3869133..81d8b6e9ff7 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2162,6 +2162,10 @@ "What is your poll question or topic?": "What is your poll question or topic?", "Question or topic": "Question or topic", "Write something...": "Write something...", + "Create options": "Create options", + "Option %(number)s": "Option %(number)s", + "Write an option": "Write an option", + "Add option": "Add option", "Power level": "Power level", "Custom level": "Custom level", "QR Code": "QR Code", From a1453601cc58e8713293d4fafc1fd34dd1d7cfd8 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 20 Oct 2021 16:59:50 -0600 Subject: [PATCH 05/11] PSFD-423: Ensure form submission semantics work for dialogs --- res/css/_common.scss | 35 +++++++++++++---- res/css/views/elements/_AccessibleButton.scss | 2 + .../views/dialogs/ScrollableBaseModal.tsx | 38 ++++++++++++------- 3 files changed, 54 insertions(+), 21 deletions(-) diff --git a/res/css/_common.scss b/res/css/_common.scss index 1284a5c499b..3663b087c80 100644 --- a/res/css/_common.scss +++ b/res/css/_common.scss @@ -404,7 +404,10 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { * We should go through and have one consistent set of styles for buttons throughout the app. * For now, I am duplicating the selectors here for mx_Dialog and mx_DialogButtons. */ -.mx_Dialog button, .mx_Dialog input[type="submit"], .mx_Dialog_buttons button, .mx_Dialog_buttons input[type="submit"] { +.mx_Dialog button:not(.mx_Dialog_nonDialogButton), +.mx_Dialog input[type="submit"], +.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton), +.mx_Dialog_buttons input[type="submit"] { @mixin mx_DialogButton; margin-left: 0px; margin-right: 8px; @@ -417,36 +420,52 @@ input[type=text]:focus, input[type=password]:focus, textarea:focus { font-family: inherit; } -.mx_Dialog button:last-child { +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):last-child { margin-right: 0px; } -.mx_Dialog button:hover, .mx_Dialog input[type="submit"]:hover, .mx_Dialog_buttons button:hover, .mx_Dialog_buttons input[type="submit"]:hover { +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):hover, +.mx_Dialog input[type="submit"]:hover, +.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):hover, +.mx_Dialog_buttons input[type="submit"]:hover { @mixin mx_DialogButton_hover; } -.mx_Dialog button:focus, .mx_Dialog input[type="submit"]:focus, .mx_Dialog_buttons button:focus, .mx_Dialog_buttons input[type="submit"]:focus { +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):focus, +.mx_Dialog input[type="submit"]:focus, +.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):focus, +.mx_Dialog_buttons input[type="submit"]:focus { filter: brightness($focus-brightness); } -.mx_Dialog button.mx_Dialog_primary, .mx_Dialog input[type="submit"].mx_Dialog_primary, .mx_Dialog_buttons button.mx_Dialog_primary, .mx_Dialog_buttons input[type="submit"].mx_Dialog_primary { +.mx_Dialog button.mx_Dialog_primary, +.mx_Dialog input[type="submit"].mx_Dialog_primary, +.mx_Dialog_buttons button.mx_Dialog_primary, +.mx_Dialog_buttons input[type="submit"].mx_Dialog_primary { color: $accent-fg-color; background-color: $accent-color; min-width: 156px; } -.mx_Dialog button.danger, .mx_Dialog input[type="submit"].danger, .mx_Dialog_buttons button.danger, .mx_Dialog_buttons input[type="submit"].danger { +.mx_Dialog button.danger, +.mx_Dialog input[type="submit"].danger, +.mx_Dialog_buttons button.danger, +.mx_Dialog_buttons input[type="submit"].danger { background-color: $warning-color; border: solid 1px $warning-color; color: $accent-fg-color; } -.mx_Dialog button.warning, .mx_Dialog input[type="submit"].warning { +.mx_Dialog button.warning, +.mx_Dialog input[type="submit"].warning { border: solid 1px $warning-color; color: $warning-color; } -.mx_Dialog button:disabled, .mx_Dialog input[type="submit"]:disabled, .mx_Dialog_buttons button:disabled, .mx_Dialog_buttons input[type="submit"]:disabled { +.mx_Dialog button:not(.mx_Dialog_nonDialogButton):disabled, +.mx_Dialog input[type="submit"]:disabled, +.mx_Dialog_buttons button:not(.mx_Dialog_nonDialogButton):disabled, +.mx_Dialog_buttons input[type="submit"]:disabled { background-color: $light-fg-color; border: solid 1px $light-fg-color; opacity: 0.7; diff --git a/res/css/views/elements/_AccessibleButton.scss b/res/css/views/elements/_AccessibleButton.scss index 7bc47a3c98e..8cf870fb7c9 100644 --- a/res/css/views/elements/_AccessibleButton.scss +++ b/res/css/views/elements/_AccessibleButton.scss @@ -30,11 +30,13 @@ limitations under the License. align-items: center; justify-content: center; font-size: $font-14px; + border: none; // override default