pl-fe: style migrations

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2025-11-11 12:53:54 +01:00
parent 517e88d422
commit a0e967cb54
8 changed files with 93 additions and 55 deletions

View File

@ -203,8 +203,8 @@ const SidebarNavigation: React.FC<ISidebarNavigation> = React.memo(({ shrink })
<SiteLogo /> <SiteLogo />
{account && ( {account && (
<Stack space={4}> <div className='⁂-sidebar-navigation__header'>
<div className='relative flex items-center'> <div className='⁂-sidebar-navigation__header__account'>
<ProfileDropdown account={account}> <ProfileDropdown account={account}>
{shrink ? ( {shrink ? (
<Avatar <Avatar
@ -214,11 +214,10 @@ const SidebarNavigation: React.FC<ISidebarNavigation> = React.memo(({ shrink })
username={account.username} username={account.username}
size={40} size={40}
/> />
// className='size-10 bg-gray-50 ring-2 ring-white'
) : ( ) : (
<Account <Account
account={account} account={account}
action={<Icon src={require('@phosphor-icons/core/regular/caret-down.svg')} className='text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500' />} action={<Icon src={require('@phosphor-icons/core/regular/caret-down.svg')} className='⁂-sidebar-navigation__header__account__expand' />}
disabled disabled
withLinkToProfile={false} withLinkToProfile={false}
/> />
@ -226,11 +225,9 @@ const SidebarNavigation: React.FC<ISidebarNavigation> = React.memo(({ shrink })
</ProfileDropdown> </ProfileDropdown>
</div> </div>
{!shrink && ( {!shrink && (
<div className='block w-full max-w-xs'> <SearchInput />
<SearchInput />
</div>
)} )}
</Stack> </div>
)} )}
<div className='⁂-sidebar-navigation__links'> <div className='⁂-sidebar-navigation__links'>

View File

@ -1,3 +1,4 @@
import clsx from 'clsx';
import React from 'react'; import React from 'react';
import IconButton from 'pl-fe/components/ui/icon-button'; import IconButton from 'pl-fe/components/ui/icon-button';
@ -13,6 +14,7 @@ interface IWidget {
actionTitle?: string; actionTitle?: string;
action?: JSX.Element; action?: JSX.Element;
children?: React.ReactNode; children?: React.ReactNode;
className?: string;
} }
/** Sidebar widget. */ /** Sidebar widget. */
@ -23,8 +25,9 @@ const Widget: React.FC<IWidget> = ({
actionIcon = require('@phosphor-icons/core/regular/arrow-right.svg'), actionIcon = require('@phosphor-icons/core/regular/arrow-right.svg'),
actionTitle, actionTitle,
action, action,
className,
}): JSX.Element => ( }): JSX.Element => (
<div className='⁂-widget'> <div className={clsx('⁂-widget', className)}>
{(title || action || onActionClick) && ( {(title || action || onActionClick) && (
<div className='⁂-widget__header'> <div className='⁂-widget__header'>
{title && <h1>{title}</h1>} {title && <h1>{title}</h1>}

View File

@ -2,7 +2,6 @@ import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import Spinner from 'pl-fe/components/ui/spinner'; import Spinner from 'pl-fe/components/ui/spinner';
import Text from 'pl-fe/components/ui/text';
import Widget from 'pl-fe/components/ui/widget'; import Widget from 'pl-fe/components/ui/widget';
import { type AccountGalleryAttachment, useGroupGallery } from 'pl-fe/hooks/use-account-gallery'; import { type AccountGalleryAttachment, useGroupGallery } from 'pl-fe/hooks/use-account-gallery';
import { MediaItem } from 'pl-fe/pages/accounts/account-gallery'; import { MediaItem } from 'pl-fe/pages/accounts/account-gallery';
@ -28,7 +27,7 @@ const GroupMediaPanel: React.FC<IGroupMediaPanel> = ({ group }) => {
if (nineAttachments.length) { if (nineAttachments.length) {
return ( return (
<div className='grid grid-cols-3 gap-0.5 overflow-hidden rounded-md'> <div className='⁂-media-panel__attachments'>
{nineAttachments.map((attachment, index) => ( {nineAttachments.map((attachment, index) => (
<MediaItem <MediaItem
key={`${attachment.status_id}+${attachment.id}`} key={`${attachment.status_id}+${attachment.id}`}
@ -41,23 +40,19 @@ const GroupMediaPanel: React.FC<IGroupMediaPanel> = ({ group }) => {
); );
} else { } else {
return ( return (
<Text size='sm' theme='muted'> <p className='⁂-media-panel__empty'>
<FormattedMessage id='media_panel.empty_message' defaultMessage='No media found.' /> <FormattedMessage id='media_panel.empty_message' defaultMessage='No media found.' />
</Text> </p>
); );
} }
}; };
return ( return (
<Widget title={<FormattedMessage id='media_panel.title' defaultMessage='Media' />}> <Widget className='⁂-media-panel' title={<FormattedMessage id='media_panel.title' defaultMessage='Media' />}>
{group && ( {isLoading ? (
<div className='w-full'> <Spinner />
{isLoading ? ( ) : (
<Spinner /> renderAttachments()
) : (
renderAttachments()
)}
</div>
)} )}
</Widget> </Widget>
); );

View File

@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import Stack from 'pl-fe/components/ui/stack';
import Widget from 'pl-fe/components/ui/widget'; import Widget from 'pl-fe/components/ui/widget';
import { ProfileField } from '../../util/async-components'; import { ProfileField } from '../../util/async-components';
@ -13,12 +12,10 @@ interface IProfileFieldsPanel {
/** Custom profile fields for sidebar. */ /** Custom profile fields for sidebar. */
const ProfileFieldsPanel: React.FC<IProfileFieldsPanel> = ({ account }) => ( const ProfileFieldsPanel: React.FC<IProfileFieldsPanel> = ({ account }) => (
<Widget> <Widget className='⁂-profile-fields-panel'>
<Stack space={4}> {account.fields.map((field, i) => (
{account.fields.map((field, i) => ( <ProfileField field={field} key={i} emojis={account.emojis} accountId={account.id} />
<ProfileField field={field} key={i} emojis={account.emojis} accountId={account.id} /> ))}
))}
</Stack>
</Widget> </Widget>
); );

View File

@ -2,7 +2,6 @@ import React from 'react';
import { FormattedMessage } from 'react-intl'; import { FormattedMessage } from 'react-intl';
import Spinner from 'pl-fe/components/ui/spinner'; import Spinner from 'pl-fe/components/ui/spinner';
import Text from 'pl-fe/components/ui/text';
import Widget from 'pl-fe/components/ui/widget'; import Widget from 'pl-fe/components/ui/widget';
import { type AccountGalleryAttachment, useAccountGallery } from 'pl-fe/hooks/use-account-gallery'; import { type AccountGalleryAttachment, useAccountGallery } from 'pl-fe/hooks/use-account-gallery';
import { MediaItem } from 'pl-fe/pages/accounts/account-gallery'; import { MediaItem } from 'pl-fe/pages/accounts/account-gallery';
@ -29,7 +28,7 @@ const ProfileMediaPanel: React.FC<IProfileMediaPanel> = ({ account }) => {
if (nineAttachments.length) { if (nineAttachments.length) {
return ( return (
<div className='grid grid-cols-3 gap-0.5 overflow-hidden rounded-md'> <div className='⁂-media-panel__attachments'>
{nineAttachments.map((attachment, index) => ( {nineAttachments.map((attachment, index) => (
<MediaItem <MediaItem
key={`${attachment.status_id}+${attachment.id}`} key={`${attachment.status_id}+${attachment.id}`}
@ -42,22 +41,20 @@ const ProfileMediaPanel: React.FC<IProfileMediaPanel> = ({ account }) => {
); );
} else { } else {
return ( return (
<Text size='sm' theme='muted'> <p className='⁂-media-panel__empty'>
<FormattedMessage id='media_panel.empty_message' defaultMessage='No media found.' /> <FormattedMessage id='media_panel.empty_message' defaultMessage='No media found.' />
</Text> </p>
); );
} }
}; };
return ( return (
<Widget title={<FormattedMessage id='media_panel.title' defaultMessage='Media' />}> <Widget className='⁂-media-panel' title={<FormattedMessage id='media_panel.title' defaultMessage='Media' />}>
<div className='w-full'> {isLoading || !account ? (
{isLoading || !account ? ( <Spinner />
<Spinner /> ) : (
) : ( renderAttachments()
renderAttachments() )}
)}
</div>
</Widget> </Widget>
); );
}; };

View File

@ -3,9 +3,7 @@ import React from 'react';
import { defineMessages, useIntl, type FormatDateOptions } from 'react-intl'; import { defineMessages, useIntl, type FormatDateOptions } from 'react-intl';
import AccountLocalTime from 'pl-fe/components/account-local-time'; import AccountLocalTime from 'pl-fe/components/account-local-time';
import Markup from 'pl-fe/components/markup';
import { ParsedContent } from 'pl-fe/components/parsed-content'; import { ParsedContent } from 'pl-fe/components/parsed-content';
import HStack from 'pl-fe/components/ui/hstack';
import Icon from 'pl-fe/components/ui/icon'; import Icon from 'pl-fe/components/ui/icon';
import CryptoAddress from 'pl-fe/features/crypto-donate/components/crypto-address'; import CryptoAddress from 'pl-fe/features/crypto-donate/components/crypto-address';
import LightningAddress from 'pl-fe/features/crypto-donate/components/lightning-address'; import LightningAddress from 'pl-fe/features/crypto-donate/components/lightning-address';
@ -59,28 +57,26 @@ const ProfileField: React.FC<IProfileField> = ({ accountId, field, emojis }) =>
} }
return ( return (
<dl> <dl className={clsx('⁂-profile-field', { '⁂-profile-field--verified': field.verified_at })}>
<dt title={field.name}> <dt title={field.name}>
<Markup weight='bold' tag='span'> <span data-markup>
<Emojify text={field.name} emojis={emojis} /> <Emojify text={field.name} emojis={emojis} />
</Markup> </span>
</dt> </dt>
<dd <dd title={unescapeHTML(field.value)}>
className={clsx({ 'text-success-500': field.verified_at })} <div className='⁂-profile-field__content'>
title={unescapeHTML(field.value)}
>
<HStack space={2} alignItems='center'>
{field.verified_at && ( {field.verified_at && (
<span className='flex-none' title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(field.verified_at, dateFormatOptions) })}> <span className='flex-none' title={intl.formatMessage(messages.linkVerifiedOn, { date: intl.formatDate(field.verified_at, dateFormatOptions) })}>
<Icon src={require('@phosphor-icons/core/regular/check.svg')} /> <Icon src={require('@phosphor-icons/core/regular/check.svg')} />
</span> </span>
)} )}
<Markup className='overflow-hidden break-words' tag='span'> <span data-markup>
<ParsedContent html={field.value} emojis={emojis} /> <ParsedContent html={field.value} emojis={emojis} />
</Markup> </span>
</HStack> </div>
{isTimezoneLabel(field.name) && ( {isTimezoneLabel(field.name) && (
<AccountLocalTime accountId={accountId} field={field} /> <AccountLocalTime accountId={accountId} field={field} />
)} )}

View File

@ -1,3 +1,5 @@
@use 'mixins';
.-account-card { .-account-card {
@apply block w-full shrink-0; @apply block w-full shrink-0;
@ -77,4 +79,43 @@
55% { transform: rotate(-20deg) skew(-30deg); } 55% { transform: rotate(-20deg) skew(-30deg); }
75% { transform: rotate(0deg) skew(-30deg); } 75% { transform: rotate(0deg) skew(-30deg); }
100% { transform: rotate(-37.6deg) skew(-30deg); } 100% { transform: rotate(-37.6deg) skew(-30deg); }
} }
.-media-panel {
.-widget__body {
width: 100%;
}
&__attachments {
@apply grid grid-cols-3 gap-0.5 overflow-hidden rounded-md;
}
&__empty {
@include mixins.text($size: sm, $theme: muted);
}
}
.-profile-field {
dt span {
@include mixins.text($weight: bold);
}
&--verified dd {
@apply text-success-500;
}
&__content {
@apply flex items-center gap-2;
}
}
.-profile-fields-panel {
.-widget__body {
@apply flex flex-col gap-4;
}
span[data-markup] {
@include mixins.text();
@apply overflow-hidden break-words;
}
}

View File

@ -143,6 +143,18 @@ body {
flex-direction: column; flex-direction: column;
gap: 1rem; gap: 1rem;
&__header {
@apply flex flex-col gap-y-4;
&__account {
@apply relative flex items-center;
&__expand {
@apply text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-500;
}
}
}
.-site-logo { .-site-logo {
height: 3rem; height: 3rem;
width: auto; width: auto;