From 4b1f66418b0173dd5edcfe9153e00dfe2e4ab948 Mon Sep 17 00:00:00 2001 From: Echo Date: Tue, 17 Feb 2026 16:45:24 +0100 Subject: [PATCH] Profile editing: Add initial route (#37885) --- app/javascript/mastodon/components/column.tsx | 12 ++++- .../mastodon/components/column_header.tsx | 9 ++-- .../mastodon/components/follow_button.tsx | 18 +++++-- .../mastodon/features/account_edit/index.tsx | 53 +++++++++++++++++++ .../features/account_edit/styles.module.scss | 26 +++++++++ app/javascript/mastodon/features/ui/index.jsx | 5 +- .../features/ui/util/async-components.js | 5 ++ app/javascript/mastodon/hooks/useAccountId.ts | 4 ++ app/javascript/mastodon/locales/en.json | 2 + app/javascript/mastodon/utils/environment.ts | 2 +- config/routes/web_app.rb | 1 + 11 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 app/javascript/mastodon/features/account_edit/index.tsx create mode 100644 app/javascript/mastodon/features/account_edit/styles.module.scss diff --git a/app/javascript/mastodon/components/column.tsx b/app/javascript/mastodon/components/column.tsx index 01c75d85c0..2abe3425e4 100644 --- a/app/javascript/mastodon/components/column.tsx +++ b/app/javascript/mastodon/components/column.tsx @@ -1,6 +1,8 @@ import { forwardRef, useRef, useImperativeHandle } from 'react'; import type { Ref } from 'react'; +import classNames from 'classnames'; + import { scrollTop } from 'mastodon/scroll'; export interface ColumnRef { @@ -12,10 +14,11 @@ interface ColumnProps { children?: React.ReactNode; label?: string; bindToDocument?: boolean; + className?: string; } export const Column = forwardRef( - ({ children, label, bindToDocument }, ref: Ref) => { + ({ children, label, bindToDocument, className }, ref: Ref) => { const nodeRef = useRef(null); useImperativeHandle(ref, () => ({ @@ -39,7 +42,12 @@ export const Column = forwardRef( })); return ( -
+
{children}
); diff --git a/app/javascript/mastodon/components/column_header.tsx b/app/javascript/mastodon/components/column_header.tsx index 06ba29cd26..64273ab214 100644 --- a/app/javascript/mastodon/components/column_header.tsx +++ b/app/javascript/mastodon/components/column_header.tsx @@ -73,6 +73,7 @@ export interface Props { iconComponent?: IconProp; active?: boolean; children?: React.ReactNode; + className?: string; pinned?: boolean; multiColumn?: boolean; extraButton?: React.ReactNode; @@ -91,6 +92,7 @@ export const ColumnHeader: React.FC = ({ iconComponent, active, children, + className, pinned, multiColumn, extraButton, @@ -141,7 +143,7 @@ export const ColumnHeader: React.FC = ({ onPin?.(); }, [history, pinned, onPin]); - const wrapperClassName = classNames('column-header__wrapper', { + const wrapperClassName = classNames('column-header__wrapper', className, { active, }); @@ -256,7 +258,8 @@ export const ColumnHeader: React.FC = ({ } const hasIcon = icon && iconComponent; - const hasTitle = hasIcon && title; + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + const hasTitle = (hasIcon || backButton) && title; const component = (
@@ -270,7 +273,7 @@ export const ColumnHeader: React.FC = ({ className='column-header__title' type='button' > - {!backButton && ( + {!backButton && hasIcon && ( + {label} + + ); + } + return ( {label} diff --git a/app/javascript/mastodon/features/account_edit/index.tsx b/app/javascript/mastodon/features/account_edit/index.tsx new file mode 100644 index 0000000000..838a07f131 --- /dev/null +++ b/app/javascript/mastodon/features/account_edit/index.tsx @@ -0,0 +1,53 @@ +import type { FC } from 'react'; + +import { FormattedMessage, useIntl } from 'react-intl'; + +import { Link } from 'react-router-dom'; + +import { Column } from '@/mastodon/components/column'; +import { ColumnHeader } from '@/mastodon/components/column_header'; +import { LoadingIndicator } from '@/mastodon/components/loading_indicator'; +import BundleColumnError from '@/mastodon/features/ui/components/bundle_column_error'; +import { useAccount } from '@/mastodon/hooks/useAccount'; +import { useCurrentAccountId } from '@/mastodon/hooks/useAccountId'; + +import classes from './styles.module.scss'; + +export const AccountEdit: FC<{ multiColumn: boolean }> = ({ multiColumn }) => { + const accountId = useCurrentAccountId(); + const account = useAccount(accountId); + const intl = useIntl(); + + if (!accountId) { + return ; + } + + if (!account) { + return ( + + + + ); + } + + return ( + + + + + } + /> + + ); +}; diff --git a/app/javascript/mastodon/features/account_edit/styles.module.scss b/app/javascript/mastodon/features/account_edit/styles.module.scss new file mode 100644 index 0000000000..3662b51443 --- /dev/null +++ b/app/javascript/mastodon/features/account_edit/styles.module.scss @@ -0,0 +1,26 @@ +.column { + border: 1px solid var(--color-border-primary); + border-top-width: 0; +} + +.header { + :global(.column-header__buttons) { + align-items: center; + padding-inline-end: 16px; + height: auto; + } +} + +.nav { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + padding: 24px 24px 12px; + + > h1 { + flex-grow: 1; + font-weight: 600; + font-size: 15px; + } +} diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx index c2fcd2d02f..089e5764bc 100644 --- a/app/javascript/mastodon/features/ui/index.jsx +++ b/app/javascript/mastodon/features/ui/index.jsx @@ -22,7 +22,7 @@ import { identityContextPropShape, withIdentity } from 'mastodon/identity_contex import { layoutFromWindow } from 'mastodon/is_mobile'; import { WithRouterPropTypes } from 'mastodon/utils/react_router'; import { checkAnnualReport } from '@/mastodon/reducers/slices/annual_report'; -import { isServerFeatureEnabled } from '@/mastodon/utils/environment'; +import { isClientFeatureEnabled, isServerFeatureEnabled } from '@/mastodon/utils/environment'; import { uploadCompose, resetCompose, changeComposeSpoilerness } from '../../actions/compose'; import { clearHeight } from '../../actions/height_cache'; @@ -80,6 +80,7 @@ import { TermsOfService, AccountFeatured, AccountAbout, + AccountEdit, Quotes, } from './util/async-components'; import { ColumnsContextProvider } from './util/columns_context'; @@ -232,6 +233,8 @@ class SwitchingColumnsArea extends PureComponent { + {isClientFeatureEnabled('profile_editing') && } + diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 55fcc29fa4..6b0188f9b6 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -92,6 +92,11 @@ export function AccountAbout() { .then((module) => ({ default: module.AccountAbout })); } +export function AccountEdit() { + return import('../../account_edit') + .then((module) => ({ default: module.AccountEdit })); +} + export function Followers () { return import('../../followers'); } diff --git a/app/javascript/mastodon/hooks/useAccountId.ts b/app/javascript/mastodon/hooks/useAccountId.ts index cab8f48934..028d882445 100644 --- a/app/javascript/mastodon/hooks/useAccountId.ts +++ b/app/javascript/mastodon/hooks/useAccountId.ts @@ -55,3 +55,7 @@ export function useAccountId() { return accountId satisfies AccountId; } + +export function useCurrentAccountId() { + return useAppSelector((state) => state.meta.get('me', null) as string | null); +} diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 6070aecbe8..91e0fb79b2 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -141,6 +141,8 @@ "account.unmute": "Unmute @{name}", "account.unmute_notifications_short": "Unmute notifications", "account.unmute_short": "Unmute", + "account_edit.column_button": "Done", + "account_edit.column_title": "Edit Profile", "account_note.placeholder": "Click to add note", "admin.dashboard.daily_retention": "User retention rate by day after sign-up", "admin.dashboard.monthly_retention": "User retention rate by month after sign-up", diff --git a/app/javascript/mastodon/utils/environment.ts b/app/javascript/mastodon/utils/environment.ts index 5f736fa80c..58421817ad 100644 --- a/app/javascript/mastodon/utils/environment.ts +++ b/app/javascript/mastodon/utils/environment.ts @@ -18,7 +18,7 @@ export function isServerFeatureEnabled(feature: ServerFeatures) { return initialState?.features.includes(feature) ?? false; } -type ClientFeatures = 'collections'; +type ClientFeatures = 'collections' | 'profile_editing'; export function isClientFeatureEnabled(feature: ClientFeatures) { try { diff --git a/config/routes/web_app.rb b/config/routes/web_app.rb index 2901e22715..cb85dc8753 100644 --- a/config/routes/web_app.rb +++ b/config/routes/web_app.rb @@ -25,6 +25,7 @@ /notifications_v2/(*any) /notifications/(*any) /pinned + /profile/(*any) /public /public/local /public/remote