mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 03:00:33 +02:00
Merge commit 'cc3c7ba532f75617505bb41297651a5c14f71bdd' into glitch-soc/merge-upstream
Conflicts: - `app/helpers/theme_helper.rb`: Upstream simplified `theme_style_tags`. Our version is different because of the different theming system. Adapted upstream's changes. - `app/views/layouts/error.html.haml`: Theming system.
This commit is contained in:
@@ -19,14 +19,11 @@ module ThemeHelper
|
||||
|
||||
def theme_style_tags(flavour_and_skin)
|
||||
flavour, theme = flavour_and_skin
|
||||
if theme == 'system'
|
||||
''.html_safe.tap do |tags|
|
||||
tags << vite_stylesheet_tag("skins/#{flavour}/mastodon-light", type: :virtual, media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
|
||||
tags << vite_stylesheet_tag("skins/#{flavour}/default", type: :virtual, media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
|
||||
end
|
||||
else
|
||||
vite_stylesheet_tag "skins/#{flavour}/#{theme}", type: :virtual, media: 'all', crossorigin: 'anonymous'
|
||||
end
|
||||
|
||||
# TODO: get rid of that when we retire the themes and perform the settings migration
|
||||
theme = 'default' if %w(mastodon-light contrast system).include?(theme)
|
||||
|
||||
vite_stylesheet_tag "skins/#{flavour}/#{theme}", type: :virtual, media: 'all', crossorigin: 'anonymous'
|
||||
end
|
||||
|
||||
def theme_color_tags(color_scheme)
|
||||
|
||||
1
app/javascript/entrypoints/theme-selection.ts
Normal file
1
app/javascript/entrypoints/theme-selection.ts
Normal file
@@ -0,0 +1 @@
|
||||
import '../inline/theme-selection';
|
||||
@@ -11,11 +11,13 @@ import classes from './styles.module.css';
|
||||
|
||||
interface MiniCardListProps {
|
||||
cards?: (Pick<MiniCardProps, 'label' | 'value'> & { key?: Key })[];
|
||||
className?: string;
|
||||
onOverflowClick?: MouseEventHandler;
|
||||
}
|
||||
|
||||
export const MiniCardList: FC<MiniCardListProps> = ({
|
||||
cards = [],
|
||||
className,
|
||||
onOverflowClick,
|
||||
}) => {
|
||||
const {
|
||||
@@ -27,29 +29,37 @@ export const MiniCardList: FC<MiniCardListProps> = ({
|
||||
maxWidth,
|
||||
} = useOverflow();
|
||||
|
||||
if (!cards.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.wrapper} ref={wrapperRef}>
|
||||
<div className={classNames(classes.wrapper, className)} ref={wrapperRef}>
|
||||
<dl className={classes.list} ref={listRef} style={{ maxWidth }}>
|
||||
{cards.map((card, index) => (
|
||||
<MiniCard
|
||||
key={card.key ?? index}
|
||||
label={card.label}
|
||||
value={card.value}
|
||||
hidden={index >= hiddenIndex}
|
||||
hidden={hasOverflow && index >= hiddenIndex}
|
||||
/>
|
||||
))}
|
||||
</dl>
|
||||
<button
|
||||
type='button'
|
||||
className={classNames(classes.more, !hasOverflow && classes.hidden)}
|
||||
onClick={onOverflowClick}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='minicard.more_items'
|
||||
defaultMessage='+ {count} more'
|
||||
values={{ count: hiddenCount }}
|
||||
/>
|
||||
</button>
|
||||
{cards.length > 1 && (
|
||||
<div>
|
||||
<button
|
||||
type='button'
|
||||
className={classNames(classes.more, !hasOverflow && classes.hidden)}
|
||||
onClick={onOverflowClick}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='minicard.more_items'
|
||||
defaultMessage='+{count}'
|
||||
values={{ count: hiddenCount }}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -7,18 +7,6 @@ const meta = {
|
||||
title: 'Components/MiniCard',
|
||||
component: MiniCardList,
|
||||
args: {
|
||||
cards: [
|
||||
{ label: 'Pronouns', value: 'they/them' },
|
||||
{
|
||||
label: 'Website',
|
||||
value: <a href='https://example.com'>bowie-the-db.meow</a>,
|
||||
},
|
||||
{
|
||||
label: 'Free playlists',
|
||||
value: <a href='https://soundcloud.com/bowie-the-dj'>soundcloud.com</a>,
|
||||
},
|
||||
{ label: 'Location', value: 'Purris, France' },
|
||||
],
|
||||
onOverflowClick: action('Overflow clicked'),
|
||||
},
|
||||
render(args) {
|
||||
@@ -43,7 +31,22 @@ export default meta;
|
||||
|
||||
type Story = StoryObj<typeof meta>;
|
||||
|
||||
export const Default: Story = {};
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
cards: [
|
||||
{ label: 'Pronouns', value: 'they/them' },
|
||||
{
|
||||
label: 'Website',
|
||||
value: <a href='https://example.com'>bowie-the-db.meow</a>,
|
||||
},
|
||||
{
|
||||
label: 'Free playlists',
|
||||
value: <a href='https://soundcloud.com/bowie-the-dj'>soundcloud.com</a>,
|
||||
},
|
||||
{ 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' }],
|
||||
},
|
||||
};
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { isClientFeatureEnabled } from '@/mastodon/utils/environment';
|
||||
|
||||
export function isRedesignEnabled() {
|
||||
return isClientFeatureEnabled('profile_redesign');
|
||||
}
|
||||
@@ -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 '@/mastodon/components/account_bio';
|
||||
import { AccountFields } from '@/mastodon/components/account_fields';
|
||||
import { DisplayName } from '@/mastodon/components/display_name';
|
||||
import { AnimateEmojiProvider } from '@/mastodon/components/emoji/context';
|
||||
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { FormattedDateWrapper } from 'mastodon/components/formatted_date';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { AccountNote } from 'mastodon/features/account/components/account_note';
|
||||
import { DomainPill } from 'mastodon/features/account/components/domain_pill';
|
||||
@@ -25,10 +23,11 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
import { AccountBadges } from './badges';
|
||||
import { AccountButtons } from './buttons';
|
||||
import { FamiliarFollowers } from './familiar_followers';
|
||||
import { AccountHeaderFields } from './fields';
|
||||
import { AccountInfo } from './info';
|
||||
import { AccountLinks } from './links';
|
||||
import { MemorialNote } from './memorial_note';
|
||||
import { MovedNote } from './moved_note';
|
||||
import { AccountNumberFields } from './number_fields';
|
||||
import { AccountTabs } from './tabs';
|
||||
|
||||
const titleFromAccount = (account: Account) => {
|
||||
@@ -192,32 +191,10 @@ export const AccountHeader: React.FC<{
|
||||
className='account__header__content'
|
||||
/>
|
||||
|
||||
<div className='account__header__fields'>
|
||||
<dl>
|
||||
<dt>
|
||||
<FormattedMessage
|
||||
id='account.joined_short'
|
||||
defaultMessage='Joined'
|
||||
/>
|
||||
</dt>
|
||||
<dd>
|
||||
<FormattedDateWrapper
|
||||
value={account.created_at}
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<AccountFields
|
||||
fields={account.fields}
|
||||
emojis={account.emojis}
|
||||
/>
|
||||
</div>
|
||||
<AccountHeaderFields accountId={accountId} />
|
||||
</div>
|
||||
|
||||
<AccountLinks accountId={accountId} />
|
||||
<AccountNumberFields accountId={accountId} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { openModal } from '@/mastodon/actions/modal';
|
||||
import { AccountFields } from '@/mastodon/components/account_fields';
|
||||
import { EmojiHTML } from '@/mastodon/components/emoji/html';
|
||||
import { FormattedDateWrapper } from '@/mastodon/components/formatted_date';
|
||||
import { MiniCardList } from '@/mastodon/components/mini_card/list';
|
||||
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
|
||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
import type { Account } from '@/mastodon/models/account';
|
||||
import { useAppDispatch } from '@/mastodon/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 <RedesignAccountHeaderFields account={account} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account__header__fields'>
|
||||
<dl>
|
||||
<dt>
|
||||
<FormattedMessage id='account.joined_short' defaultMessage='Joined' />
|
||||
</dt>
|
||||
<dd>
|
||||
<FormattedDateWrapper
|
||||
value={account.created_at}
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
/>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<AccountFields fields={account.fields} emojis={account.emojis} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const RedesignAccountHeaderFields: FC<{ account: Account }> = ({ account }) => {
|
||||
const htmlHandlers = useElementHandledLink();
|
||||
const cards = useMemo(
|
||||
() =>
|
||||
account.fields.toArray().map(({ value_emojified, name_emojified }) => ({
|
||||
label: (
|
||||
<EmojiHTML
|
||||
htmlString={name_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
className='translate'
|
||||
as='span'
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
),
|
||||
value: (
|
||||
<EmojiHTML
|
||||
as='span'
|
||||
htmlString={value_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
),
|
||||
})),
|
||||
[account.emojis, account.fields, htmlHandlers],
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const handleOverflowClick = useCallback(() => {
|
||||
dispatch(
|
||||
openModal({
|
||||
modalType: 'ACCOUNT_FIELDS',
|
||||
modalProps: { accountId: account.id },
|
||||
}),
|
||||
);
|
||||
}, [account.id, dispatch]);
|
||||
|
||||
return (
|
||||
<MiniCardList
|
||||
cards={cards}
|
||||
className={classes.fieldList}
|
||||
onOverflowClick={handleOverflowClick}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { DisplayName } from '@/mastodon/components/display_name';
|
||||
import { AnimateEmojiProvider } from '@/mastodon/components/emoji/context';
|
||||
import { EmojiHTML } from '@/mastodon/components/emoji/html';
|
||||
import { IconButton } from '@/mastodon/components/icon_button';
|
||||
import { LoadingIndicator } from '@/mastodon/components/loading_indicator';
|
||||
import { useElementHandledLink } from '@/mastodon/components/status/handled_link';
|
||||
import { useAccount } from '@/mastodon/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 (
|
||||
<div className='modal-root__modal dialog-modal'>
|
||||
<LoadingIndicator />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='modal-root__modal dialog-modal'>
|
||||
<div className='dialog-modal__header'>
|
||||
<IconButton
|
||||
icon='close'
|
||||
className={classes.modalCloseButton}
|
||||
onClick={onClose}
|
||||
iconComponent={CloseIcon}
|
||||
title={intl.formatMessage({
|
||||
id: 'account_fields_modal.close',
|
||||
defaultMessage: 'Close',
|
||||
})}
|
||||
/>
|
||||
<span className={`${classes.modalTitle} dialog-modal__header__title`}>
|
||||
<FormattedMessage
|
||||
id='account_fields_modal.title'
|
||||
defaultMessage="{name}'s info"
|
||||
values={{
|
||||
name: <DisplayName account={account} variant='simple' />,
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div className='dialog-modal__content'>
|
||||
<AnimateEmojiProvider>
|
||||
<dl className={classes.modalFieldsList}>
|
||||
{account.fields.map((field, index) => (
|
||||
<div key={index} className={classes.modalFieldItem}>
|
||||
<EmojiHTML
|
||||
as='dt'
|
||||
htmlString={field.name_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
className='translate'
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
<EmojiHTML
|
||||
as='dd'
|
||||
htmlString={field.value_emojified}
|
||||
extraEmojis={account.emojis}
|
||||
{...htmlHandlers}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</AnimateEmojiProvider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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 '@/mastodon/components/counters';
|
||||
import { ShortNumber } from '@/mastodon/components/short_number';
|
||||
import { useAccount } from '@/mastodon/hooks/useAccount';
|
||||
|
||||
export const AccountLinks: FC<{ accountId: string }> = ({ accountId }) => {
|
||||
const intl = useIntl();
|
||||
const account = useAccount(accountId);
|
||||
|
||||
if (!account) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className='account__header__extra__links'>
|
||||
<NavLink
|
||||
to={`/@${account.acct}`}
|
||||
title={intl.formatNumber(account.statuses_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.statuses_count}
|
||||
renderer={StatusesCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/following`}
|
||||
title={intl.formatNumber(account.following_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.following_count}
|
||||
renderer={FollowingCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/followers`}
|
||||
title={intl.formatNumber(account.followers_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.followers_count}
|
||||
renderer={FollowersCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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 '@/mastodon/components/counters';
|
||||
import { FormattedDateWrapper } from '@/mastodon/components/formatted_date';
|
||||
import { ShortNumber } from '@/mastodon/components/short_number';
|
||||
import { useAccount } from '@/mastodon/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 (
|
||||
<div
|
||||
className={classNames(
|
||||
'account__header__extra__links',
|
||||
isRedesignEnabled() && classes.fieldNumbersWrapper,
|
||||
)}
|
||||
>
|
||||
{!isRedesignEnabled() && (
|
||||
<NavLink
|
||||
to={`/@${account.acct}`}
|
||||
title={intl.formatNumber(account.statuses_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.statuses_count}
|
||||
renderer={StatusesCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/following`}
|
||||
title={intl.formatNumber(account.following_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.following_count}
|
||||
renderer={FollowingCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
<NavLink
|
||||
exact
|
||||
to={`/@${account.acct}/followers`}
|
||||
title={intl.formatNumber(account.followers_count)}
|
||||
>
|
||||
<ShortNumber
|
||||
value={account.followers_count}
|
||||
renderer={FollowersCounter}
|
||||
/>
|
||||
</NavLink>
|
||||
|
||||
{isRedesignEnabled() && (
|
||||
<NavLink exact to={`/@${account.acct}`}>
|
||||
<FormattedMessage
|
||||
id='account.joined_long'
|
||||
defaultMessage='Joined on {date}'
|
||||
values={{
|
||||
date: (
|
||||
<strong>
|
||||
<FormattedDateWrapper
|
||||
value={account.created_at}
|
||||
year='numeric'
|
||||
month='short'
|
||||
day='2-digit'
|
||||
/>
|
||||
</strong>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</NavLink>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -85,6 +85,7 @@ export const MODAL_COMPONENTS = {
|
||||
'IGNORE_NOTIFICATIONS': IgnoreNotificationsModal,
|
||||
'ANNUAL_REPORT': AnnualReportModal,
|
||||
'COMPOSE_PRIVACY': () => Promise.resolve({ default: VisibilityModal }),
|
||||
'ACCOUNT_FIELDS': () => import('mastodon/features/account_timeline/components/fields_modal.tsx').then(module => ({ default: module.AccountFieldsModal })),
|
||||
};
|
||||
|
||||
export default class ModalRoot extends PureComponent {
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"account.go_to_profile": "Go to profile",
|
||||
"account.hide_reblogs": "Hide boosts from @{name}",
|
||||
"account.in_memoriam": "In Memoriam.",
|
||||
"account.joined_long": "Joined on {date}",
|
||||
"account.joined_short": "Joined",
|
||||
"account.languages": "Change subscribed languages",
|
||||
"account.link_verified_on": "Ownership of this link was checked on {date}",
|
||||
@@ -90,6 +91,8 @@
|
||||
"account.unmute": "Unmute @{name}",
|
||||
"account.unmute_notifications_short": "Unmute notifications",
|
||||
"account.unmute_short": "Unmute",
|
||||
"account_fields_modal.close": "Close",
|
||||
"account_fields_modal.title": "{name}'s info",
|
||||
"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",
|
||||
@@ -589,7 +592,7 @@
|
||||
"load_pending": "{count, plural, one {# new item} other {# new items}}",
|
||||
"loading_indicator.label": "Loading…",
|
||||
"media_gallery.hide": "Hide",
|
||||
"minicard.more_items": "+ {count} more",
|
||||
"minicard.more_items": "+{count}",
|
||||
"moved_to_account_banner.text": "Your account {disabledAccount} is currently disabled because you moved to {movedToAccount}.",
|
||||
"mute_modal.hide_from_notifications": "Hide from notifications",
|
||||
"mute_modal.hide_options": "Hide options",
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
@use 'common';
|
||||
@use 'mastodon/high-contrast';
|
||||
|
||||
@@ -39,8 +39,8 @@
|
||||
color: var(--color-text-error);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
&:not(:disabled):hover,
|
||||
&:not(:disabled):active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@@ -1081,20 +1081,36 @@ body > [data-popper-placement] {
|
||||
}
|
||||
|
||||
a {
|
||||
--text-decoration-default: none;
|
||||
--text-decoration-hover: underline;
|
||||
|
||||
[data-contrast='high'] & {
|
||||
--text-decoration-default: underline;
|
||||
--text-decoration-hover: none;
|
||||
}
|
||||
|
||||
color: var(--color-text-status-links);
|
||||
text-decoration: none;
|
||||
text-decoration: var(--text-decoration-default);
|
||||
unicode-bidi: isolate;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
text-decoration: var(--text-decoration-hover);
|
||||
}
|
||||
|
||||
&.mention {
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
text-decoration: none;
|
||||
|
||||
span {
|
||||
text-decoration: var(--text-decoration-default);
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
span {
|
||||
text-decoration: underline;
|
||||
text-decoration: var(--text-decoration-hover);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1356,6 +1372,15 @@ body > [data-popper-placement] {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
[data-contrast='high'] & {
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover,
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.icon {
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
.status__content a,
|
||||
.reply-indicator__content a,
|
||||
.edit-indicator__content a,
|
||||
.link-footer a,
|
||||
.status__content__read-more-button,
|
||||
.status__content__translate-button {
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.mention {
|
||||
text-decoration: none;
|
||||
|
||||
span {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
span {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.link-button:disabled {
|
||||
cursor: not-allowed;
|
||||
|
||||
&:hover,
|
||||
&:focus,
|
||||
&:active {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
!!!
|
||||
%html{ lang: I18n.locale }
|
||||
%html{ lang: I18n.locale, 'data-contrast': 'auto', 'data-color-scheme': 'auto' }
|
||||
%head
|
||||
%meta{ 'content' => 'text/html; charset=UTF-8', 'http-equiv' => 'Content-Type' }/
|
||||
%meta{ charset: 'utf-8' }/
|
||||
@@ -8,6 +8,7 @@
|
||||
= vite_client_tag
|
||||
= vite_react_refresh_tag
|
||||
= vite_polyfills_tag
|
||||
= flavoured_vite_typescript_tag 'theme-selection.ts', crossorigin: 'anonymous', blocking: 'render'
|
||||
= theme_style_tags current_theme
|
||||
= flavoured_vite_typescript_tag 'error.ts', crossorigin: 'anonymous'
|
||||
%body.error
|
||||
|
||||
@@ -9,17 +9,10 @@ RSpec.describe ThemeHelper do
|
||||
context 'when using "system" theme' do
|
||||
let(:theme) { ['glitch', 'system'] }
|
||||
|
||||
it 'returns the mastodon-light and application stylesheets with correct color schemes' do
|
||||
it 'returns the default theme' do
|
||||
expect(html_links.first.attributes.symbolize_keys)
|
||||
.to include(
|
||||
# This is now identical to the default theme & will be unified very soon
|
||||
href: have_attributes(value: match(/default/)),
|
||||
media: have_attributes(value: 'not all and (prefers-color-scheme: dark)')
|
||||
)
|
||||
expect(html_links.last.attributes.symbolize_keys)
|
||||
.to include(
|
||||
href: have_attributes(value: match(/default/)),
|
||||
media: have_attributes(value: '(prefers-color-scheme: dark)')
|
||||
href: have_attributes(value: match(/default/))
|
||||
)
|
||||
end
|
||||
end
|
||||
@@ -41,8 +34,7 @@ RSpec.describe ThemeHelper do
|
||||
it 'returns the theme stylesheet without color scheme information' do
|
||||
expect(html_links.first.attributes.symbolize_keys)
|
||||
.to include(
|
||||
href: have_attributes(value: match(/contrast/)),
|
||||
media: have_attributes(value: 'all')
|
||||
href: have_attributes(value: match(/default/))
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
52
yarn.lock
52
yarn.lock
@@ -10515,17 +10515,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pg-cloudflare@npm:^1.2.7":
|
||||
version: 1.2.7
|
||||
resolution: "pg-cloudflare@npm:1.2.7"
|
||||
checksum: 10c0/8a52713dbdecc9d389dc4e65e3b7ede2e199ec3715f7491ee80a15db171f2d75677a102e9c2cef0cb91a2f310e91f976eaec0dd6ef5d8bf357de0b948f9d9431
|
||||
"pg-cloudflare@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "pg-cloudflare@npm:1.3.0"
|
||||
checksum: 10c0/b0866c88af8e54c7b3ed510719d92df37714b3af5e3a3a10d9f761fcec99483e222f5b78a1f2de590368127648087c45c01aaf66fadbe46edb25673eedc4f8fc
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pg-connection-string@npm:^2.6.0, pg-connection-string@npm:^2.9.1":
|
||||
version: 2.9.1
|
||||
resolution: "pg-connection-string@npm:2.9.1"
|
||||
checksum: 10c0/9a646529bbc0843806fc5de98ce93735a4612b571f11867178a85665d11989a827e6fd157388ca0e34ec948098564fce836c178cfd499b9f0e8cd9972b8e2e5c
|
||||
"pg-connection-string@npm:^2.10.0, pg-connection-string@npm:^2.6.0":
|
||||
version: 2.10.0
|
||||
resolution: "pg-connection-string@npm:2.10.0"
|
||||
checksum: 10c0/6639d3e12f66bc3cc5fa1e5794b4b22a4212e30424cbf001422e041c77c598ee0cd19395a9d79cb99a962da612b03c021e8148c3437cf01a29a18437bad193eb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10536,19 +10536,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pg-pool@npm:^3.10.1":
|
||||
version: 3.10.1
|
||||
resolution: "pg-pool@npm:3.10.1"
|
||||
"pg-pool@npm:^3.11.0":
|
||||
version: 3.11.0
|
||||
resolution: "pg-pool@npm:3.11.0"
|
||||
peerDependencies:
|
||||
pg: ">=8.0"
|
||||
checksum: 10c0/a00916b7df64226cc597fe769e3a757ff9b11562dc87ce5b0a54101a18c1fe282daaa2accaf27221e81e1e4cdf4da6a33dab09614734d32904d6c4e11c44a079
|
||||
checksum: 10c0/4b104b48a47257a0edad0c62e5ea1908b72cb79386270264b452e69895e9e4c589d00cdbf6e46d4e9c05bc7e7d191656b66814b5282d65f33b12648a21df3c7f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pg-protocol@npm:*, pg-protocol@npm:^1.10.3":
|
||||
version: 1.10.3
|
||||
resolution: "pg-protocol@npm:1.10.3"
|
||||
checksum: 10c0/f7ef54708c93ee6d271e37678296fc5097e4337fca91a88a3d99359b78633dbdbf6e983f0adb34b7cdd261b7ec7266deb20c3233bf3dfdb498b3e1098e8750b9
|
||||
"pg-protocol@npm:*, pg-protocol@npm:^1.11.0":
|
||||
version: 1.11.0
|
||||
resolution: "pg-protocol@npm:1.11.0"
|
||||
checksum: 10c0/93e83581781418c9173eba4e4545f73392cfe66b78dd1d3624d7339fbd37e7f4abebaf2615e68e0701a9bf0edf5b81a4ad533836f388f775fe25fa24a691c464
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10566,13 +10566,13 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"pg@npm:^8.5.0":
|
||||
version: 8.16.3
|
||||
resolution: "pg@npm:8.16.3"
|
||||
version: 8.17.1
|
||||
resolution: "pg@npm:8.17.1"
|
||||
dependencies:
|
||||
pg-cloudflare: "npm:^1.2.7"
|
||||
pg-connection-string: "npm:^2.9.1"
|
||||
pg-pool: "npm:^3.10.1"
|
||||
pg-protocol: "npm:^1.10.3"
|
||||
pg-cloudflare: "npm:^1.3.0"
|
||||
pg-connection-string: "npm:^2.10.0"
|
||||
pg-pool: "npm:^3.11.0"
|
||||
pg-protocol: "npm:^1.11.0"
|
||||
pg-types: "npm:2.2.0"
|
||||
pgpass: "npm:1.0.5"
|
||||
peerDependencies:
|
||||
@@ -10583,7 +10583,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
pg-native:
|
||||
optional: true
|
||||
checksum: 10c0/a6a407ff0efb7599760d72ffdcda47a74c34c0fd71d896623caac45cf2cfb0f49a10973cce23110f182b9810639a1e9f6904454d7358c7001574ee0ffdcbce2a
|
||||
checksum: 10c0/39a92391adfc73f793d195b4062bc2d21aa3537073e3973f3979d72901d92a59e129f31f42577ff916038a6c3f9fe423b6024717529609ae8548fda21248cfe7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -10685,8 +10685,8 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"pino@npm:^10.0.0":
|
||||
version: 10.1.1
|
||||
resolution: "pino@npm:10.1.1"
|
||||
version: 10.2.0
|
||||
resolution: "pino@npm:10.2.0"
|
||||
dependencies:
|
||||
"@pinojs/redact": "npm:^0.4.0"
|
||||
atomic-sleep: "npm:^1.0.0"
|
||||
@@ -10701,7 +10701,7 @@ __metadata:
|
||||
thread-stream: "npm:^4.0.0"
|
||||
bin:
|
||||
pino: bin.js
|
||||
checksum: 10c0/c0a78ae4209b81879e3b2c72abd523c6045412066d214b7577f4073b23369751bbb7a1c6abb691bdf347ac81fab5e9cad9d8db0612fe2e5a9607ef895651a1bb
|
||||
checksum: 10c0/8f88a2e205508d47ef04d2a6ec26ec450abb4b344d2d998d2e24b9e624e1a1ef7184f260ca5be06bc3733aa1ad76704657e373b359c7b71489a11709227e26da
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user