From 398806a2b0aa00d304dfb606d7f1e22558f13e8f Mon Sep 17 00:00:00 2001 From: Echo Date: Fri, 27 Feb 2026 14:36:19 +0100 Subject: [PATCH] [Glitch] Profile editing: Tab display controls Port d69d7c0507f4e0453e032c897cb3343065798381 to glitch-soc Signed-off-by: Claire --- .../components/profile_display_modal.tsx | 122 ++++++++++++++++++ .../glitch/features/account_edit/index.tsx | 19 ++- .../features/account_edit/styles.module.scss | 10 ++ .../features/ui/components/dialog_modal.tsx | 94 ++++++++++++++ .../features/ui/components/modal_root.jsx | 1 + 5 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 app/javascript/flavours/glitch/features/account_edit/components/profile_display_modal.tsx create mode 100644 app/javascript/flavours/glitch/features/ui/components/dialog_modal.tsx diff --git a/app/javascript/flavours/glitch/features/account_edit/components/profile_display_modal.tsx b/app/javascript/flavours/glitch/features/account_edit/components/profile_display_modal.tsx new file mode 100644 index 0000000000..3b866d2ba3 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account_edit/components/profile_display_modal.tsx @@ -0,0 +1,122 @@ +import type { ChangeEventHandler, FC } from 'react'; +import { useCallback } from 'react'; + +import { FormattedMessage, useIntl } from 'react-intl'; + +import { Callout } from '@/flavours/glitch/components/callout'; +import { ToggleField } from '@/flavours/glitch/components/form_fields'; +import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator'; +import { patchProfile } from '@/flavours/glitch/reducers/slices/profile_edit'; +import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store'; + +import type { DialogModalProps } from '../../ui/components/dialog_modal'; +import { DialogModal } from '../../ui/components/dialog_modal'; +import { messages } from '../index'; +import classes from '../styles.module.scss'; + +export const ProfileDisplayModal: FC = ({ onClose }) => { + const intl = useIntl(); + + const { profile, isPending } = useAppSelector((state) => state.profileEdit); + const serverName = useAppSelector( + (state) => state.meta.get('domain') as string, + ); + + const dispatch = useAppDispatch(); + const handleToggleChange: ChangeEventHandler = useCallback( + (event) => { + const { name, checked } = event.target; + void dispatch(patchProfile({ [name]: checked })); + }, + [dispatch], + ); + + if (!profile) { + return ; + } + + return ( + +
+ + } + hint={ + + } + /> + + + } + hint={ + + } + /> + + + } + hint={ + + } + /> +
+ + + } + icon={false} + > + + +
+ ); +}; diff --git a/app/javascript/flavours/glitch/features/account_edit/index.tsx b/app/javascript/flavours/glitch/features/account_edit/index.tsx index e9b7df708f..6d3809c481 100644 --- a/app/javascript/flavours/glitch/features/account_edit/index.tsx +++ b/app/javascript/flavours/glitch/features/account_edit/index.tsx @@ -1,13 +1,14 @@ import { useCallback, useEffect } from 'react'; import type { FC } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { useHistory } from 'react-router-dom'; import type { ModalType } from '@/flavours/glitch/actions/modal'; import { openModal } from '@/flavours/glitch/actions/modal'; import { Avatar } from '@/flavours/glitch/components/avatar'; +import { Button } from '@/flavours/glitch/components/button'; import { CustomEmojiProvider } from '@/flavours/glitch/components/emoji/context'; import { EmojiHTML } from '@/flavours/glitch/components/emoji/html'; import { useElementHandledLink } from '@/flavours/glitch/components/status/handled_link'; @@ -25,7 +26,7 @@ import { EditButton } from './components/edit_button'; import { AccountEditSection } from './components/section'; import classes from './styles.module.scss'; -const messages = defineMessages({ +export const messages = defineMessages({ columnTitle: { id: 'account_edit.column_title', defaultMessage: 'Edit Profile', @@ -104,6 +105,9 @@ export const AccountEdit: FC = () => { const handleBioEdit = useCallback(() => { handleOpenModal('ACCOUNT_EDIT_BIO'); }, [handleOpenModal]); + const handleProfileDisplayEdit = useCallback(() => { + handleOpenModal('ACCOUNT_EDIT_PROFILE_DISPLAY'); + }, [handleOpenModal]); const history = useHistory(); const handleFeaturedTagsEdit = useCallback(() => { @@ -193,6 +197,17 @@ export const AccountEdit: FC = () => { title={messages.profileTabTitle} description={messages.profileTabSubtitle} showDescription + buttons={ + + } /> diff --git a/app/javascript/flavours/glitch/features/account_edit/styles.module.scss b/app/javascript/flavours/glitch/features/account_edit/styles.module.scss index ee8603cc4f..29daddbe3f 100644 --- a/app/javascript/flavours/glitch/features/account_edit/styles.module.scss +++ b/app/javascript/flavours/glitch/features/account_edit/styles.module.scss @@ -90,6 +90,16 @@ textarea.inputText { } } +.toggleInputWrapper { + > div { + padding: 12px 0; + + &:not(:first-child) { + border-top: 1px solid var(--color-border-primary); + } + } +} + // Column component .column { diff --git a/app/javascript/flavours/glitch/features/ui/components/dialog_modal.tsx b/app/javascript/flavours/glitch/features/ui/components/dialog_modal.tsx new file mode 100644 index 0000000000..462fe369cc --- /dev/null +++ b/app/javascript/flavours/glitch/features/ui/components/dialog_modal.tsx @@ -0,0 +1,94 @@ +import type { FC, ReactNode } from 'react'; + +import { FormattedMessage, useIntl } from 'react-intl'; + +import classNames from 'classnames'; + +import { Button } from '@/flavours/glitch/components/button'; +import { IconButton } from '@/flavours/glitch/components/icon_button'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; + +export type { BaseConfirmationModalProps as DialogModalProps } from './confirmation_modals/confirmation_modal'; + +interface DialogModalProps { + className?: string; + title: ReactNode; + onClose: () => void; + description?: ReactNode; + formClassName?: string; + children?: ReactNode; + noCancelButton?: boolean; + onSave?: () => void; + saveLabel?: ReactNode; +} + +export const DialogModal: FC = ({ + className, + title, + onClose, + description, + formClassName, + children, + noCancelButton = false, + onSave, + saveLabel, +}) => { + const intl = useIntl(); + + const showButtons = !noCancelButton || onSave; + + return ( +
+
+ + +

{title}

+
+ +
+ {description && ( +
+ {description} +
+ )} +
+ {children} +
+
+ + {showButtons && ( +
+ {!noCancelButton && ( + + )} + {onSave && ( + + )} +
+ )} +
+ ); +}; diff --git a/app/javascript/flavours/glitch/features/ui/components/modal_root.jsx b/app/javascript/flavours/glitch/features/ui/components/modal_root.jsx index 9067f415ef..b5f58b98c7 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.jsx @@ -105,6 +105,7 @@ export const MODAL_COMPONENTS = { 'ACCOUNT_FIELD_OVERFLOW': () => import('@/flavours/glitch/features/account_timeline/modals/field_modal').then(module => ({ default: module.AccountFieldModal })), 'ACCOUNT_EDIT_NAME': () => import('@/flavours/glitch/features/account_edit/components/name_modal').then(module => ({ default: module.NameModal })), 'ACCOUNT_EDIT_BIO': () => import('@/flavours/glitch/features/account_edit/components/bio_modal').then(module => ({ default: module.BioModal })), + 'ACCOUNT_EDIT_PROFILE_DISPLAY': () => import('@/flavours/glitch/features/account_edit/components/profile_display_modal').then(module => ({ default: module.ProfileDisplayModal })), }; export default class ModalRoot extends PureComponent {