diff --git a/app/javascript/flavours/glitch/components/mini_card/list.tsx b/app/javascript/flavours/glitch/components/mini_card/list.tsx index b5b8fbc2c8..f775e70aac 100644 --- a/app/javascript/flavours/glitch/components/mini_card/list.tsx +++ b/app/javascript/flavours/glitch/components/mini_card/list.tsx @@ -11,11 +11,13 @@ import classes from './styles.module.css'; interface MiniCardListProps { cards?: (Pick & { key?: Key })[]; + className?: string; onOverflowClick?: MouseEventHandler; } export const MiniCardList: FC = ({ cards = [], + className, onOverflowClick, }) => { const { @@ -27,29 +29,37 @@ export const MiniCardList: FC = ({ maxWidth, } = useOverflow(); + if (!cards.length) { + return null; + } + return ( -
+
{cards.map((card, index) => (
- + {cards.length > 1 && ( +
+ +
+ )}
); }; diff --git a/app/javascript/flavours/glitch/components/mini_card/mini_card.stories.tsx b/app/javascript/flavours/glitch/components/mini_card/mini_card.stories.tsx index ada76011b2..60534f05f6 100644 --- a/app/javascript/flavours/glitch/components/mini_card/mini_card.stories.tsx +++ b/app/javascript/flavours/glitch/components/mini_card/mini_card.stories.tsx @@ -7,18 +7,6 @@ const meta = { title: 'Components/MiniCard', component: MiniCardList, args: { - cards: [ - { label: 'Pronouns', value: 'they/them' }, - { - label: 'Website', - value: bowie-the-db.meow, - }, - { - label: 'Free playlists', - value: soundcloud.com, - }, - { label: 'Location', value: 'Purris, France' }, - ], onOverflowClick: action('Overflow clicked'), }, render(args) { @@ -43,7 +31,22 @@ export default meta; type Story = StoryObj; -export const Default: Story = {}; +export const Default: Story = { + args: { + cards: [ + { label: 'Pronouns', value: 'they/them' }, + { + label: 'Website', + value: bowie-the-db.meow, + }, + { + label: 'Free playlists', + value: soundcloud.com, + }, + { label: 'Location', value: 'Purris, France' }, + ], + }, +}; export const LongValue: Story = { args: { @@ -60,3 +63,9 @@ export const LongValue: Story = { ], }, }; + +export const OneCard: Story = { + args: { + cards: [{ label: 'Pronouns', value: 'they/them' }], + }, +}; diff --git a/app/javascript/flavours/glitch/components/mini_card/styles.module.css b/app/javascript/flavours/glitch/components/mini_card/styles.module.css index d912f1e5cf..642c08c5fa 100644 --- a/app/javascript/flavours/glitch/components/mini_card/styles.module.css +++ b/app/javascript/flavours/glitch/components/mini_card/styles.module.css @@ -6,7 +6,6 @@ } .list { - min-width: 0; display: flex; gap: 4px; overflow: hidden; @@ -21,16 +20,19 @@ flex-shrink: 0; } -.card { - max-width: 20vw; - overflow: hidden; -} - .more { color: var(--color-text-secondary); font-weight: 600; appearance: none; background: none; + aspect-ratio: 1; + height: 100%; + transition: all 300ms linear; +} + +.more:hover { + background-color: var(--color-bg-brand-softer); + color: var(--color-text-primary); } .hidden { diff --git a/app/javascript/flavours/glitch/features/account_timeline/common.ts b/app/javascript/flavours/glitch/features/account_timeline/common.ts new file mode 100644 index 0000000000..33d1ee210d --- /dev/null +++ b/app/javascript/flavours/glitch/features/account_timeline/common.ts @@ -0,0 +1,5 @@ +import { isClientFeatureEnabled } from '@/flavours/glitch/utils/environment'; + +export function isRedesignEnabled() { + return isClientFeatureEnabled('profile_redesign'); +} diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx b/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx index c73110db89..8bb39b456c 100644 --- a/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx +++ b/app/javascript/flavours/glitch/features/account_timeline/components/account_header.tsx @@ -1,18 +1,16 @@ import { useCallback } from 'react'; -import { useIntl, FormattedMessage } from 'react-intl'; +import { useIntl } from 'react-intl'; import classNames from 'classnames'; import { Helmet } from 'react-helmet'; import { AccountBio } from '@/flavours/glitch/components/account_bio'; -import { AccountFields } from '@/flavours/glitch/components/account_fields'; import { DisplayName } from '@/flavours/glitch/components/display_name'; import { AnimateEmojiProvider } from '@/flavours/glitch/components/emoji/context'; import LockIcon from '@/material-icons/400-24px/lock.svg?react'; import { openModal } from 'flavours/glitch/actions/modal'; import { Avatar } from 'flavours/glitch/components/avatar'; -import { FormattedDateWrapper } from 'flavours/glitch/components/formatted_date'; import { Icon } from 'flavours/glitch/components/icon'; import { AccountNote } from 'flavours/glitch/features/account/components/account_note'; import { DomainPill } from 'flavours/glitch/features/account/components/domain_pill'; @@ -31,6 +29,7 @@ import { ActionBar } from '../../account/components/action_bar'; import { AccountBadges } from './badges'; import { AccountButtons } from './buttons'; import { FamiliarFollowers } from './familiar_followers'; +import { AccountHeaderFields } from './fields'; import { AccountInfo } from './info'; import { MemorialNote } from './memorial_note'; import { MovedNote } from './moved_note'; @@ -197,29 +196,7 @@ export const AccountHeader: React.FC<{ className='account__header__content' /> -
-
-
- -
-
- -
-
- - -
+
)} diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/fields.tsx b/app/javascript/flavours/glitch/features/account_timeline/components/fields.tsx new file mode 100644 index 0000000000..cd8f7d593f --- /dev/null +++ b/app/javascript/flavours/glitch/features/account_timeline/components/fields.tsx @@ -0,0 +1,97 @@ +import { useCallback, useMemo } from 'react'; +import type { FC } from 'react'; + +import { FormattedMessage } from 'react-intl'; + +import { openModal } from '@/flavours/glitch/actions/modal'; +import { AccountFields } from '@/flavours/glitch/components/account_fields'; +import { EmojiHTML } from '@/flavours/glitch/components/emoji/html'; +import { FormattedDateWrapper } from '@/flavours/glitch/components/formatted_date'; +import { MiniCardList } from '@/flavours/glitch/components/mini_card/list'; +import { useElementHandledLink } from '@/flavours/glitch/components/status/handled_link'; +import { useAccount } from '@/flavours/glitch/hooks/useAccount'; +import type { Account } from '@/flavours/glitch/models/account'; +import { useAppDispatch } from '@/flavours/glitch/store'; + +import { isRedesignEnabled } from '../common'; + +import classes from './redesign.module.scss'; + +export const AccountHeaderFields: FC<{ accountId: string }> = ({ + accountId, +}) => { + const account = useAccount(accountId); + + if (!account) { + return null; + } + + if (isRedesignEnabled()) { + return ; + } + + return ( +
+
+
+ +
+
+ +
+
+ + +
+ ); +}; + +const RedesignAccountHeaderFields: FC<{ account: Account }> = ({ account }) => { + const htmlHandlers = useElementHandledLink(); + const cards = useMemo( + () => + account.fields.toArray().map(({ value_emojified, name_emojified }) => ({ + label: ( + + ), + value: ( + + ), + })), + [account.emojis, account.fields, htmlHandlers], + ); + + const dispatch = useAppDispatch(); + const handleOverflowClick = useCallback(() => { + dispatch( + openModal({ + modalType: 'ACCOUNT_FIELDS', + modalProps: { accountId: account.id }, + }), + ); + }, [account.id, dispatch]); + + return ( + + ); +}; diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/fields_modal.tsx b/app/javascript/flavours/glitch/features/account_timeline/components/fields_modal.tsx new file mode 100644 index 0000000000..d103349273 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account_timeline/components/fields_modal.tsx @@ -0,0 +1,80 @@ +import type { FC } from 'react'; + +import { FormattedMessage, useIntl } from 'react-intl'; + +import { DisplayName } from '@/flavours/glitch/components/display_name'; +import { AnimateEmojiProvider } from '@/flavours/glitch/components/emoji/context'; +import { EmojiHTML } from '@/flavours/glitch/components/emoji/html'; +import { IconButton } from '@/flavours/glitch/components/icon_button'; +import { LoadingIndicator } from '@/flavours/glitch/components/loading_indicator'; +import { useElementHandledLink } from '@/flavours/glitch/components/status/handled_link'; +import { useAccount } from '@/flavours/glitch/hooks/useAccount'; +import CloseIcon from '@/material-icons/400-24px/close.svg?react'; + +import classes from './redesign.module.scss'; + +export const AccountFieldsModal: FC<{ + accountId: string; + onClose: () => void; +}> = ({ accountId, onClose }) => { + const intl = useIntl(); + const account = useAccount(accountId); + const htmlHandlers = useElementHandledLink(); + + if (!account) { + return ( +
+ +
+ ); + } + + return ( +
+
+ + + , + }} + /> + +
+
+ +
+ {account.fields.map((field, index) => ( +
+ + +
+ ))} +
+
+
+
+ ); +}; diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/links.tsx b/app/javascript/flavours/glitch/features/account_timeline/components/links.tsx deleted file mode 100644 index 0b055f4a0a..0000000000 --- a/app/javascript/flavours/glitch/features/account_timeline/components/links.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import type { FC } from 'react'; - -import { useIntl } from 'react-intl'; - -import { NavLink } from 'react-router-dom'; - -import { - FollowersCounter, - FollowingCounter, - StatusesCounter, -} from '@/flavours/glitch/components/counters'; -import { ShortNumber } from '@/flavours/glitch/components/short_number'; -import { useAccount } from '@/flavours/glitch/hooks/useAccount'; - -export const AccountLinks: FC<{ accountId: string }> = ({ accountId }) => { - const intl = useIntl(); - const account = useAccount(accountId); - - if (!account) { - return null; - } - - return ( -
- - - - - - - - - - - -
- ); -}; diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/number_fields.tsx b/app/javascript/flavours/glitch/features/account_timeline/components/number_fields.tsx new file mode 100644 index 0000000000..a5ef239e48 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account_timeline/components/number_fields.tsx @@ -0,0 +1,94 @@ +import type { FC } from 'react'; + +import { FormattedMessage, useIntl } from 'react-intl'; + +import classNames from 'classnames'; +import { NavLink } from 'react-router-dom'; + +import { + FollowersCounter, + FollowingCounter, + StatusesCounter, +} from '@/flavours/glitch/components/counters'; +import { FormattedDateWrapper } from '@/flavours/glitch/components/formatted_date'; +import { ShortNumber } from '@/flavours/glitch/components/short_number'; +import { useAccount } from '@/flavours/glitch/hooks/useAccount'; + +import { isRedesignEnabled } from '../common'; + +import classes from './redesign.module.scss'; + +export const AccountNumberFields: FC<{ accountId: string }> = ({ + accountId, +}) => { + const intl = useIntl(); + const account = useAccount(accountId); + + if (!account) { + return null; + } + + return ( +
+ {!isRedesignEnabled() && ( + + + + )} + + + + + + + + + + {isRedesignEnabled() && ( + + + + + ), + }} + /> + + )} +
+ ); +}; diff --git a/app/javascript/flavours/glitch/features/account_timeline/components/redesign.module.scss b/app/javascript/flavours/glitch/features/account_timeline/components/redesign.module.scss new file mode 100644 index 0000000000..dd09f199e5 --- /dev/null +++ b/app/javascript/flavours/glitch/features/account_timeline/components/redesign.module.scss @@ -0,0 +1,47 @@ +.fieldList { + margin-top: 16px; +} + +.fieldNumbersWrapper { + a { + font-weight: unset; + } +} + +.modalCloseButton { + padding: 8px; + border-radius: 50%; + border: 1px solid var(--color-border-primary); +} + +.modalTitle { + flex-grow: 1; + text-align: center; +} + +.modalFieldsList { + padding: 24px; +} + +.modalFieldItem { + &:not(:first-child) { + padding-top: 12px; + } + + &:not(:last-child)::after { + content: ''; + display: block; + border-bottom: 1px solid var(--color-border-primary); + margin-top: 12px; + } + + dt { + color: var(--color-text-secondary); + font-size: 13px; + } + + dd { + font-weight: 600; + font-size: 15px; + } +} 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 cfbde0fb3e..3c9d640334 100644 --- a/app/javascript/flavours/glitch/features/ui/components/modal_root.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/modal_root.jsx @@ -93,6 +93,7 @@ export const MODAL_COMPONENTS = { 'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal, 'ANNUAL_REPORT': AnnualReportModal, 'COMPOSE_PRIVACY': () => Promise.resolve({ default: VisibilityModal }), + 'ACCOUNT_FIELDS': () => import('flavours/glitch/features/account_timeline/components/fields_modal.tsx').then(module => ({ default: module.AccountFieldsModal })), }; export default class ModalRoot extends PureComponent {