Merge commit 'c4eec632b92c800ae38dba111c4c76e63bb1c0de' into glitch-soc/merge-upstream

This commit is contained in:
Claire 2026-04-22 20:24:21 +02:00
commit b6abf7a69f
30 changed files with 242 additions and 110 deletions

View File

@ -76,6 +76,26 @@
} }
.emptyMessage { .emptyMessage {
padding: 8px 16px; display: flex;
flex-direction: column;
align-items: center;
text-align: center;
gap: 8px;
padding: 16px;
font-size: 13px; font-size: 13px;
} }
.loadingIndicator {
--spinner-size: 20px;
position: relative;
display: block;
width: var(--spinner-size);
height: var(--spinner-size);
overflow: hidden;
& :global(.circular-progress) {
width: var(--spinner-size);
height: var(--spinner-size);
}
}

View File

@ -22,6 +22,8 @@ import { matchWidth } from 'mastodon/components/dropdown/utils';
import { IconButton } from 'mastodon/components/icon_button'; import { IconButton } from 'mastodon/components/icon_button';
import { useOnClickOutside } from 'mastodon/hooks/useOnClickOutside'; import { useOnClickOutside } from 'mastodon/hooks/useOnClickOutside';
import { LoadingIndicator } from '../loading_indicator';
import classes from './combobox.module.scss'; import classes from './combobox.module.scss';
import { FormFieldWrapper } from './form_field_wrapper'; import { FormFieldWrapper } from './form_field_wrapper';
import type { CommonFieldWrapperProps } from './form_field_wrapper'; import type { CommonFieldWrapperProps } from './form_field_wrapper';
@ -531,6 +533,7 @@ const ComboboxWithRef = <Item extends ComboboxItem, GroupKey extends string>(
<div {...props} className={classNames(classes.popover, placement)}> <div {...props} className={classNames(classes.popover, placement)}>
<StatusMessageWrapper <StatusMessageWrapper
showStatus={showStatusMessageInMenu} showStatus={showStatusMessageInMenu}
isLoading={isLoading}
status={statusMessage} status={statusMessage}
> >
{hasGroups ? ( {hasGroups ? (
@ -592,10 +595,20 @@ Combobox.displayName = 'Combobox';
const StatusMessageWrapper: React.FC<{ const StatusMessageWrapper: React.FC<{
showStatus: boolean; showStatus: boolean;
status: string; status: string;
isLoading: boolean;
children: React.ReactNode; children: React.ReactNode;
}> = ({ showStatus, status, children }) => { }> = ({ showStatus, status, isLoading, children }) => {
if (showStatus) { if (showStatus) {
return <span className={classes.emptyMessage}>{status}</span>; return (
<span className={classes.emptyMessage}>
{isLoading && (
<span className={classes.loadingIndicator}>
<LoadingIndicator role='none' />
</span>
)}
{status}
</span>
);
} }
return children; return children;

View File

@ -1,3 +1,13 @@
.wrapper {
--diameter: 20px;
--padding: 2px;
--transition: 0.2s ease-in-out;
display: inline-block;
position: relative;
height: calc(var(--diameter) + var(--padding) * 2);
}
.input { .input {
position: absolute; position: absolute;
opacity: 0; opacity: 0;
@ -9,10 +19,6 @@
} }
.toggle { .toggle {
--diameter: 20px;
--padding: 2px;
--transition: 0.2s ease-in-out;
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
border-radius: 9999px; border-radius: 9999px;
@ -68,8 +74,3 @@
:global([dir='rtl']) .input:checked + .toggle::before { :global([dir='rtl']) .input:checked + .toggle::before {
transform: translateX(calc(-1 * (var(--diameter) - (var(--padding) * 2)))); transform: translateX(calc(-1 * (var(--diameter) - (var(--padding) * 2))));
} }
.wrapper {
display: inline-block;
position: relative;
}

View File

@ -31,20 +31,17 @@ ToggleField.displayName = 'ToggleField';
export const Toggle = forwardRef<HTMLInputElement, Props>( export const Toggle = forwardRef<HTMLInputElement, Props>(
({ className, size, ...otherProps }, ref) => ( ({ className, size, ...otherProps }, ref) => (
<span className={classes.wrapper}> <span
className={classes.wrapper}
style={{ '--diameter': size ? `${size}px` : undefined } as CSSProperties}
>
<input <input
{...otherProps} {...otherProps}
type='checkbox' type='checkbox'
className={classes.input} className={classes.input}
ref={ref} ref={ref}
/> />
<span <span className={classNames(classes.toggle, className)} hidden />
className={classNames(classes.toggle, className)}
style={
{ '--diameter': size ? `${size}px` : undefined } as CSSProperties
}
hidden
/>
</span> </span>
), ),
); );

View File

@ -331,6 +331,10 @@ const TopicField: React.FC = () => {
[topic], [topic],
); );
const isCurrentTopicOnlySuggestion =
tags.length === 1 && tags[0]?.id === 'new';
const hideTagSuggestions = !tags.length || isCurrentTopicOnlySuggestion;
return ( return (
<ComboboxField <ComboboxField
required={false} required={false}
@ -369,7 +373,7 @@ const TopicField: React.FC = () => {
} }
: undefined : undefined
} }
suppressMenu={!tags.length} suppressMenu={hideTagSuggestions}
/> />
); );
}; };

View File

@ -7,8 +7,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
import { NonceProvider } from 'react-select'; import { NonceProvider } from 'react-select';
import AsyncSelect from 'react-select/async'; import AsyncSelect from 'react-select/async';
import Toggle from 'react-toggle';
import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
import { injectIntl } from '@/mastodon/components/intl'; import { injectIntl } from '@/mastodon/components/intl';
import SettingToggle from '../../notifications/components/setting_toggle'; import SettingToggle from '../../notifications/components/setting_toggle';

View File

@ -7,8 +7,6 @@ import { useParams, useHistory, Link } from 'react-router-dom';
import { isFulfilled } from '@reduxjs/toolkit'; import { isFulfilled } from '@reduxjs/toolkit';
import Toggle from 'react-toggle';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react'; import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react'; import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
import { fetchList } from 'mastodon/actions/lists'; import { fetchList } from 'mastodon/actions/lists';
@ -20,7 +18,11 @@ import { Avatar } from 'mastodon/components/avatar';
import { AvatarGroup } from 'mastodon/components/avatar_group'; import { AvatarGroup } from 'mastodon/components/avatar_group';
import { Column } from 'mastodon/components/column'; import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header'; import { ColumnHeader } from 'mastodon/components/column_header';
import { SelectField, TextInputField } from 'mastodon/components/form_fields'; import {
SelectField,
TextInputField,
Toggle,
} from 'mastodon/components/form_fields';
import { Icon } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon';
import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import type { List } from 'mastodon/models/list'; import type { List } from 'mastodon/models/list';

View File

@ -1,7 +1,7 @@
import type { PropsWithChildren } from 'react'; import type { PropsWithChildren } from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import Toggle from 'react-toggle'; import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
interface Props { interface Props {
checked: boolean; checked: boolean;

View File

@ -3,7 +3,7 @@ import { PureComponent } from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import Toggle from 'react-toggle'; import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
export default class SettingToggle extends PureComponent { export default class SettingToggle extends PureComponent {
@ -27,7 +27,7 @@ export default class SettingToggle extends PureComponent {
return ( return (
<div className='setting-toggle'> <div className='setting-toggle'>
<Toggle disabled={disabled} id={id} checked={settings.getIn(settingPath, defaultValue)} onChange={this.onChange} onKeyDown={this.onKeyDown} /> <Toggle disabled={disabled} id={id} checked={settings.getIn(settingPath, defaultValue)} onChange={this.onChange} onKeyDown={this.onKeyDown} size={16} />
<label htmlFor={id} className='setting-toggle__label'>{label}</label> <label htmlFor={id} className='setting-toggle__label'>{label}</label>
</div> </div>
); );

View File

@ -6,8 +6,6 @@ import classNames from 'classnames';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
import { useHistory } from 'react-router-dom'; import { useHistory } from 'react-router-dom';
import Toggle from 'react-toggle';
import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react'; import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react';
import EditIcon from '@/material-icons/400-24px/edit.svg?react'; import EditIcon from '@/material-icons/400-24px/edit.svg?react';
import PersonIcon from '@/material-icons/400-24px/person.svg?react'; import PersonIcon from '@/material-icons/400-24px/person.svg?react';
@ -16,7 +14,11 @@ import { closeOnboarding } from 'mastodon/actions/onboarding';
import { Button } from 'mastodon/components/button'; import { Button } from 'mastodon/components/button';
import { Column } from 'mastodon/components/column'; import { Column } from 'mastodon/components/column';
import { ColumnHeader } from 'mastodon/components/column_header'; import { ColumnHeader } from 'mastodon/components/column_header';
import { TextAreaField, TextInputField } from 'mastodon/components/form_fields'; import {
TextAreaField,
TextInputField,
Toggle,
} from 'mastodon/components/form_fields';
import { Icon } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon';
import { LoadingIndicator } from 'mastodon/components/loading_indicator'; import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { me } from 'mastodon/initial_state'; import { me } from 'mastodon/initial_state';

View File

@ -6,8 +6,7 @@ import type { Map } from 'immutable';
import { OrderedSet } from 'immutable'; import { OrderedSet } from 'immutable';
import { shallowEqual } from 'react-redux'; import { shallowEqual } from 'react-redux';
import Toggle from 'react-toggle'; import { Toggle } from '@/mastodon/components/form_fields/toggle_field';
import { fetchAccount } from 'mastodon/actions/accounts'; import { fetchAccount } from 'mastodon/actions/accounts';
import { Button } from 'mastodon/components/button'; import { Button } from 'mastodon/components/button';
import type { Status } from 'mastodon/models/status'; import type { Status } from 'mastodon/models/status';

View File

@ -13,12 +13,12 @@
"about.not_available": "Þessar upplýsingar hafa ekki verið gerðar aðgengilegar á þessum netþjóni.", "about.not_available": "Þessar upplýsingar hafa ekki verið gerðar aðgengilegar á þessum netþjóni.",
"about.powered_by": "Dreifhýstur samskiptamiðill keyrður með {mastodon}", "about.powered_by": "Dreifhýstur samskiptamiðill keyrður með {mastodon}",
"about.rules": "Reglur netþjónsins", "about.rules": "Reglur netþjónsins",
"account.account_note_header": "Einkaminnispunktur", "account.account_note_header": "Mínir minnispunktar",
"account.activity": "Virkni", "account.activity": "Virkni",
"account.add_note": "Bæta við einkaminnispunkti", "account.add_note": "Bæta við persónulegum minnispunkti",
"account.add_or_remove_from_list": "Bæta við eða fjarlægja af listum", "account.add_or_remove_from_list": "Bæta við eða fjarlægja af listum",
"account.badges.admin": "Stjóri", "account.badges.admin": "Stjóri",
"account.badges.blocked": "Lokað á", "account.badges.blocked": "Útilokað",
"account.badges.bot": "Yrki", "account.badges.bot": "Yrki",
"account.badges.domain_blocked": "Útilokað lén", "account.badges.domain_blocked": "Útilokað lén",
"account.badges.group": "Hópur", "account.badges.group": "Hópur",
@ -28,13 +28,13 @@
"account.block_domain": "Útiloka lénið {domain}", "account.block_domain": "Útiloka lénið {domain}",
"account.block_short": "Útiloka", "account.block_short": "Útiloka",
"account.blocked": "Útilokaður", "account.blocked": "Útilokaður",
"account.blocking": "Útilokun", "account.blocking": "Útilok",
"account.cancel_follow_request": "Taka fylgjendabeiðni til baka", "account.cancel_follow_request": "Taka fylgjendabeiðni til baka",
"account.copy": "Afrita tengil í notandasnið", "account.copy": "Afrita tengil í notandasnið",
"account.direct": "Einkaspjall við @{name}", "account.direct": "Einkaspjall við @{name}",
"account.disable_notifications": "Hætta að láta mig vita þegar @{name} sendir inn", "account.disable_notifications": "Hætta að láta mig vita þegar @{name} sendir inn",
"account.domain_blocking": "Útiloka lén", "account.domain_blocking": "Útilokað lén",
"account.edit_note": "Breyta einkaminnispunkti", "account.edit_note": "Breyta persónulegum minnispunkti",
"account.edit_profile": "Breyta notandasniði", "account.edit_profile": "Breyta notandasniði",
"account.edit_profile_short": "Breyta", "account.edit_profile_short": "Breyta",
"account.enable_notifications": "Láta mig vita þegar @{name} sendir inn", "account.enable_notifications": "Láta mig vita þegar @{name} sendir inn",
@ -55,8 +55,8 @@
"account.filters.replies_toggle": "Birta svör", "account.filters.replies_toggle": "Birta svör",
"account.follow": "Fylgjast með", "account.follow": "Fylgjast með",
"account.follow_back": "Fylgjast með til baka", "account.follow_back": "Fylgjast með til baka",
"account.follow_back_short": "Fylgjast með til baka", "account.follow_back_short": "Fylgjaka",
"account.follow_request": "Beiðni um að fylgjast með", "account.follow_request": "Beiðni um að fylgja",
"account.follow_request_cancel": "Hætta við beiðni", "account.follow_request_cancel": "Hætta við beiðni",
"account.follow_request_cancel_short": "Hætta við", "account.follow_request_cancel_short": "Hætta við",
"account.follow_request_short": "Beiðni", "account.follow_request_short": "Beiðni",
@ -90,7 +90,7 @@
"account.menu.note.description": "Einungis sýnilegt þér", "account.menu.note.description": "Einungis sýnilegt þér",
"account.menu.open_original_page": "Skoða á {domain}", "account.menu.open_original_page": "Skoða á {domain}",
"account.menu.remove_follower": "Fjarlægja fylgjanda", "account.menu.remove_follower": "Fjarlægja fylgjanda",
"account.menu.report": "Kæra aðgang", "account.menu.report": "Tilkynna aðgang",
"account.menu.share": "Deila…", "account.menu.share": "Deila…",
"account.menu.show_reblogs": "Sýna endurbirtingar í tímalínu", "account.menu.show_reblogs": "Sýna endurbirtingar í tímalínu",
"account.menu.unblock": "Aflétta útilokun aðgangs", "account.menu.unblock": "Aflétta útilokun aðgangs",
@ -102,7 +102,7 @@
"account.mute_short": "Þagga niður", "account.mute_short": "Þagga niður",
"account.muted": "Þaggaður", "account.muted": "Þaggaður",
"account.muting": "Þöggun", "account.muting": "Þöggun",
"account.mutual": "Þið fylgist með hvor öðrum", "account.mutual": "Þið fylgið hvor öðrum",
"account.name.copy": "Afrita kennislóð", "account.name.copy": "Afrita kennislóð",
"account.name.help.domain": "{domain} er netþjónninn sem hýsir upplýsingasnið um notandann og færslurnar hans.", "account.name.help.domain": "{domain} er netþjónninn sem hýsir upplýsingasnið um notandann og færslurnar hans.",
"account.name.help.domain_self": "{domain} er netþjónninn þinn sem hýsir upplýsingasniðið þitt og færslurnar þínar.", "account.name.help.domain_self": "{domain} er netþjónninn þinn sem hýsir upplýsingasniðið þitt og færslurnar þínar.",
@ -125,7 +125,7 @@
"account.remove_from_followers": "Fjarlægja {name} úr fylgjendum", "account.remove_from_followers": "Fjarlægja {name} úr fylgjendum",
"account.report": "Kæra @{name}", "account.report": "Kæra @{name}",
"account.requested_follow": "{name} hefur beðið um að fylgjast með þér", "account.requested_follow": "{name} hefur beðið um að fylgjast með þér",
"account.requests_to_follow_you": "Bað um að fylgjast með þér", "account.requests_to_follow_you": "Bað um að fylgja þér",
"account.share": "Deila notandasniði fyrir @{name}", "account.share": "Deila notandasniði fyrir @{name}",
"account.show_reblogs": "Sýna endurbirtingar frá @{name}", "account.show_reblogs": "Sýna endurbirtingar frá @{name}",
"account.statuses_counter": "{count, plural, one {{counter} færsla} other {{counter} færslur}}", "account.statuses_counter": "{count, plural, one {{counter} færsla} other {{counter} færslur}}",
@ -402,7 +402,7 @@
"collections.new_collection": "Nýtt safn", "collections.new_collection": "Nýtt safn",
"collections.no_collections_yet": "Engin söfn ennþá.", "collections.no_collections_yet": "Engin söfn ennþá.",
"collections.remove_account": "Fjarlægja", "collections.remove_account": "Fjarlægja",
"collections.report_collection": "Kæra þetta safn", "collections.report_collection": "Tilkynna þetta safn",
"collections.revoke_collection_inclusion": "Fjarlægja mig úr þessu safni", "collections.revoke_collection_inclusion": "Fjarlægja mig úr þessu safni",
"collections.revoke_inclusion.confirmation": "Þú varst fjarlægð/ur úr \"{collection}\"", "collections.revoke_inclusion.confirmation": "Þú varst fjarlægð/ur úr \"{collection}\"",
"collections.revoke_inclusion.error": "Upp kom villa, reyndu aftur síðar.", "collections.revoke_inclusion.error": "Upp kom villa, reyndu aftur síðar.",
@ -412,8 +412,8 @@
"collections.share_short": "Deila", "collections.share_short": "Deila",
"collections.suggestions.can_not_add": "Er ekki hægt að bæta við", "collections.suggestions.can_not_add": "Er ekki hægt að bæta við",
"collections.suggestions.can_not_add_desc": "Þessir aðgangar gætu hafa skráð sig úr almennri birtingu eða gætu verið á netþjónum sem ekki styðja söfn.", "collections.suggestions.can_not_add_desc": "Þessir aðgangar gætu hafa skráð sig úr almennri birtingu eða gætu verið á netþjónum sem ekki styðja söfn.",
"collections.suggestions.must_follow": "Verður fyrst að fylgjast með", "collections.suggestions.must_follow": "Verður fyrst að fylgja",
"collections.suggestions.must_follow_desc": "Þessir aðgangar yfirfara allar beiðnir um að fylgjast m. Fylgjendur geta bætt þeim í söfn.", "collections.suggestions.must_follow_desc": "Þessir aðgangar yfirfara allar beiðnir um að fylgja þeim. Fylgjendur geta bætt þeim í söfn.",
"collections.topic_hint": "Bættu við myllumerki sem hjálpar öðrum að skilja aðalefni þessa safns.", "collections.topic_hint": "Bættu við myllumerki sem hjálpar öðrum að skilja aðalefni þessa safns.",
"collections.topic_special_chars_hint": "Sérstafir verða fjarlægðir við vistun", "collections.topic_special_chars_hint": "Sérstafir verða fjarlægðir við vistun",
"collections.unlisted_collections_description": "Þessi birtast ekki öðrum á notandasíðunni þinni. Þeir sem eru með tengil á þau geta séð þau.", "collections.unlisted_collections_description": "Þessi birtast ekki öðrum á notandasíðunni þinni. Þeir sem eru með tengil á þau geta séð þau.",
@ -508,9 +508,9 @@
"confirmations.discard_draft.post.title": "Henda drögum að færslunni þinni?", "confirmations.discard_draft.post.title": "Henda drögum að færslunni þinni?",
"confirmations.discard_edit_media.confirm": "Henda", "confirmations.discard_edit_media.confirm": "Henda",
"confirmations.discard_edit_media.message": "Þú ert með óvistaðar breytingar á lýsingu myndefnis eða forskoðunar, henda þeim samt?", "confirmations.discard_edit_media.message": "Þú ert með óvistaðar breytingar á lýsingu myndefnis eða forskoðunar, henda þeim samt?",
"confirmations.follow_to_list.confirm": "Fylgjast með og bæta á lista", "confirmations.follow_to_list.confirm": "Fylgja og bæta á lista",
"confirmations.follow_to_list.message": "Þú þarft að fylgjast með {name} til að bæta viðkomandi á lista.", "confirmations.follow_to_list.message": "Þú þarft að fylgja {name} til að bæta viðkomandi á lista.",
"confirmations.follow_to_list.title": "Fylgjast með notanda?", "confirmations.follow_to_list.title": "Fylgja notanda?",
"confirmations.hide_featured_tab.confirm": "Fela flipa", "confirmations.hide_featured_tab.confirm": "Fela flipa",
"confirmations.hide_featured_tab.intro": "Þú getur breytt þessu hvenær sem er í <i>Breyta notandasniði > Stillingar notandasniðsflipa</i>.", "confirmations.hide_featured_tab.intro": "Þú getur breytt þessu hvenær sem er í <i>Breyta notandasniði > Stillingar notandasniðsflipa</i>.",
"confirmations.hide_featured_tab.message": "Þetta mun fela flipann fyrir notendum á {serverName} og öðrum netþjónum sem nota nýjustu útgáfuna af Mastodon. Birting í öðrum viðmótum gæti verið á ýmsan máta.", "confirmations.hide_featured_tab.message": "Þetta mun fela flipann fyrir notendum á {serverName} og öðrum netþjónum sem nota nýjustu útgáfuna af Mastodon. Birting í öðrum viðmótum gæti verið á ýmsan máta.",
@ -536,7 +536,7 @@
"confirmations.redraft.message": "Ertu viss um að þú viljir eyða þessari færslu og enduvinna drögin? Eftirlæti og endurbirtingar munu glatast og svör við upprunalegu færslunni munu verða munaðarlaus.", "confirmations.redraft.message": "Ertu viss um að þú viljir eyða þessari færslu og enduvinna drögin? Eftirlæti og endurbirtingar munu glatast og svör við upprunalegu færslunni munu verða munaðarlaus.",
"confirmations.redraft.title": "Eyða og byrja ný drög að færslu?", "confirmations.redraft.title": "Eyða og byrja ný drög að færslu?",
"confirmations.remove_from_followers.confirm": "Fjarlægja fylgjanda", "confirmations.remove_from_followers.confirm": "Fjarlægja fylgjanda",
"confirmations.remove_from_followers.message": "{name} mun hætta að fylgjast með þér. Ertu viss um að þú viljir halda áfram?", "confirmations.remove_from_followers.message": "{name} mun hætta að fylgja þér. Ertu viss um að þú viljir halda áfram?",
"confirmations.remove_from_followers.title": "Fjarlægja fylgjanda?", "confirmations.remove_from_followers.title": "Fjarlægja fylgjanda?",
"confirmations.revoke_collection_inclusion.confirm": "Fjarlægja mig", "confirmations.revoke_collection_inclusion.confirm": "Fjarlægja mig",
"confirmations.revoke_collection_inclusion.message": "Þessi aðgerð er varanleg og umsjónaraðili safnsins mun ekki geta bætt þér aftur við síðar.", "confirmations.revoke_collection_inclusion.message": "Þessi aðgerð er varanleg og umsjónaraðili safnsins mun ekki geta bætt þér aftur við síðar.",
@ -547,9 +547,9 @@
"confirmations.unblock.confirm": "Aflétta útilokun", "confirmations.unblock.confirm": "Aflétta útilokun",
"confirmations.unblock.title": "Aflétta útilokun á {name}?", "confirmations.unblock.title": "Aflétta útilokun á {name}?",
"confirmations.unfollow.confirm": "Hætta að fylgja", "confirmations.unfollow.confirm": "Hætta að fylgja",
"confirmations.unfollow.title": "Hætta að fylgjast með {name}?", "confirmations.unfollow.title": "Hætta að fylgja {name}?",
"confirmations.withdraw_request.confirm": "Taka beiðni til baka", "confirmations.withdraw_request.confirm": "Taka beiðni til baka",
"confirmations.withdraw_request.title": "Taka aftur beiðni um að fylgjast með {name}?", "confirmations.withdraw_request.title": "Taka aftur beiðni um að fylgja {name}?",
"content_warning.hide": "Fela færslu", "content_warning.hide": "Fela færslu",
"content_warning.show": "Birta samt", "content_warning.show": "Birta samt",
"content_warning.show_more": "Sýna meira", "content_warning.show_more": "Sýna meira",
@ -1113,7 +1113,7 @@
"report.category.title_account": "notandasnið", "report.category.title_account": "notandasnið",
"report.category.title_status": "færsla", "report.category.title_status": "færsla",
"report.close": "Lokið", "report.close": "Lokið",
"report.collection_comment": "Hvers vegna viltu kæra þetta safn?", "report.collection_comment": "Afhverju viltu tilkynna þetta safn?",
"report.comment.title": "Er eitthvað annað sem þú heldur að við ættum að vita?", "report.comment.title": "Er eitthvað annað sem þú heldur að við ættum að vita?",
"report.forward": "Áframsenda til {target}", "report.forward": "Áframsenda til {target}",
"report.forward_hint": "Notandaaðgangurinn er af öðrum vefþjóni. Á einnig að senda nafnlaust afrit af kærunni þangað?", "report.forward_hint": "Notandaaðgangurinn er af öðrum vefþjóni. Á einnig að senda nafnlaust afrit af kærunni þangað?",

View File

@ -410,6 +410,10 @@
"collections.search_accounts_max_reached": "Du har lagt till maximalt antal konton", "collections.search_accounts_max_reached": "Du har lagt till maximalt antal konton",
"collections.sensitive": "Känsligt", "collections.sensitive": "Känsligt",
"collections.share_short": "Dela", "collections.share_short": "Dela",
"collections.suggestions.can_not_add": "Kan inte läggas till",
"collections.suggestions.can_not_add_desc": "Dessa konton kan ha valt bort upptäckt, eller kan de vara på en server som inte stöder samlingar.",
"collections.suggestions.must_follow": "Måste följa först",
"collections.suggestions.must_follow_desc": "Dessa konton granskar alla följa förfrågningar. Följare kan lägga till dem i samlingar.",
"collections.topic_hint": "Lägg till en hashtagg som hjälper andra att förstå huvudämnet i denna samling.", "collections.topic_hint": "Lägg till en hashtagg som hjälper andra att förstå huvudämnet i denna samling.",
"collections.topic_special_chars_hint": "Specialtecken kommer att tas bort när du sparar", "collections.topic_special_chars_hint": "Specialtecken kommer att tas bort när du sparar",
"collections.unlisted_collections_description": "Dessa visas inte på din profil till andra. Vem som helst med länken kan upptäcka dem.", "collections.unlisted_collections_description": "Dessa visas inte på din profil till andra. Vem som helst med länken kan upptäcka dem.",

View File

@ -1122,7 +1122,7 @@ a.name-tag,
text-decoration: none; text-decoration: none;
margin-bottom: 10px; margin-bottom: 10px;
&:hover { &:where(a):where(:hover, :focus, :active) {
color: var(--color-text-brand); color: var(--color-text-brand);
} }
} }
@ -1131,14 +1131,6 @@ a.name-tag,
vertical-align: middle; vertical-align: middle;
} }
a.announcements-list__item__title {
&:hover,
&:focus,
&:active {
color: var(--color-text-primary);
}
}
&__action-bar { &__action-bar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;

View File

@ -53,6 +53,7 @@ class Collection < ApplicationRecord
validates :language, language: { if: :local?, allow_nil: true } validates :language, language: { if: :local?, allow_nil: true }
validate :tag_is_usable validate :tag_is_usable
validate :items_do_not_exceed_limit validate :items_do_not_exceed_limit
validate :user_does_not_exceed_limit, on: :create
scope :with_items, -> { includes(:collection_items).merge(CollectionItem.with_accounts) } scope :with_items, -> { includes(:collection_items).merge(CollectionItem.with_accounts) }
scope :with_tag, -> { includes(:tag) } scope :with_tag, -> { includes(:tag) }
@ -105,4 +106,11 @@ class Collection < ApplicationRecord
def items_do_not_exceed_limit def items_do_not_exceed_limit
errors.add(:collection_items, :too_many, count: MAX_ITEMS) if pending_or_accepted_items.size > MAX_ITEMS errors.add(:collection_items, :too_many, count: MAX_ITEMS) if pending_or_accepted_items.size > MAX_ITEMS
end end
def user_does_not_exceed_limit
return unless local?
limit = account.user.role.collection_limit
errors.add(:base, :too_many, count: limit) if account.collections.count >= limit
end
end end

View File

@ -4,15 +4,16 @@
# #
# Table name: user_roles # Table name: user_roles
# #
# id :bigint(8) not null, primary key # id :bigint(8) not null, primary key
# color :string default(""), not null # collection_limit :integer default(10), not null
# highlighted :boolean default(FALSE), not null # color :string default(""), not null
# name :string default(""), not null # highlighted :boolean default(FALSE), not null
# permissions :bigint(8) default(0), not null # name :string default(""), not null
# position :integer default(0), not null # permissions :bigint(8) default(0), not null
# require_2fa :boolean default(FALSE), not null # position :integer default(0), not null
# created_at :datetime not null # require_2fa :boolean default(FALSE), not null
# updated_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null
# #
class UserRole < ApplicationRecord class UserRole < ApplicationRecord
@ -104,6 +105,7 @@ class UserRole < ApplicationRecord
validates :name, presence: true, unless: :everyone? validates :name, presence: true, unless: :everyone?
validates :color, format: { with: CSS_COLORS }, if: :color? validates :color, format: { with: CSS_COLORS }, if: :color?
validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) } validates :position, numericality: { in: (-POSITION_LIMIT..POSITION_LIMIT) }
validates :collection_limit, numericality: { only_integer: true, greater_than_or_equal_to: 0 }
validate :validate_permissions_elevation validate :validate_permissions_elevation
validate :validate_position_elevation validate :validate_position_elevation

View File

@ -3,6 +3,8 @@
class REST::RoleSerializer < ActiveModel::Serializer class REST::RoleSerializer < ActiveModel::Serializer
attributes :id, :name, :permissions, :color, :highlighted attributes :id, :name, :permissions, :color, :highlighted
attribute :collection_limit, if: -> { Mastodon::Feature.collections_enabled? }
def id def id
object.id.to_s object.id.to_s
end end

View File

@ -32,6 +32,14 @@
%hr.spacer/ %hr.spacer/
- if Mastodon::Feature.collections_enabled?
.fields-group
= form.input :collection_limit,
wrapper: :with_label
%hr.spacer/
- unless current_user.role == form.object - unless current_user.role == form.object
.field-group .field-group

View File

@ -679,7 +679,7 @@ is:
suspend_description_html: Notandaaðgangurinn og allt efni á honum mun verða óaðgengilegt og á endanum eytt út og samskipti við aðganginn verða ekki möguleg. Hægt að afturkalla innan 30 daga. Lokar öllum kærum gagnvart þessum aðgangi. suspend_description_html: Notandaaðgangurinn og allt efni á honum mun verða óaðgengilegt og á endanum eytt út og samskipti við aðganginn verða ekki möguleg. Hægt að afturkalla innan 30 daga. Lokar öllum kærum gagnvart þessum aðgangi.
actions_description_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Ef þú ákveður að refsa kærða notandaaðgangnum, verður viðkomandi send tilkynning í tölvupósti, nema ef flokkurinn <strong>Ruslpóstur</strong> sé valinn. actions_description_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Ef þú ákveður að refsa kærða notandaaðgangnum, verður viðkomandi send tilkynning í tölvupósti, nema ef flokkurinn <strong>Ruslpóstur</strong> sé valinn.
actions_description_remote_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Þetta mun aðeins hafa áhrif á hvernig <strong>netþjónninn þinn</strong> meðhöndlar þennan fjartengda aðgang og efnið á honum. actions_description_remote_html: Ákveddu til hvaða aðgerða eigi að taka til að leysa þessa kæru. Þetta mun aðeins hafa áhrif á hvernig <strong>netþjónninn þinn</strong> meðhöndlar þennan fjartengda aðgang og efnið á honum.
actions_no_posts: Þessi kæra er ekki með neinar tengdar færslur til að eyða actions_no_posts: Þessi tilkynning er ekki með neinar tengdar færslur til að eyða
add_to_report: Bæta fleiru í kæru add_to_report: Bæta fleiru í kæru
already_suspended_badges: already_suspended_badges:
local: Þegar frystur á þessum netþjóni local: Þegar frystur á þessum netþjóni
@ -884,7 +884,7 @@ is:
public: Allir public: Allir
landing_page: landing_page:
values: values:
about: Um hugbúnaðinn about: Um
local_feed: Staðbundið streymi local_feed: Staðbundið streymi
trends: Vinsælt trends: Vinsælt
registrations: registrations:

View File

@ -160,6 +160,7 @@ en:
other: We have to make sure you're at least %{count} to use %{domain}. We won't store this. other: We have to make sure you're at least %{count} to use %{domain}. We won't store this.
role: The role controls which permissions the user has. role: The role controls which permissions the user has.
user_role: user_role:
collection_limit: Limits the number of Collections that a single user with this role can create. Please note that when you decrease this number, users who are already at this limit will not lose any Collections. But they will not be able to create additional ones.
color: Color to be used for the role throughout the UI, as RGB in hex format color: Color to be used for the role throughout the UI, as RGB in hex format
highlighted: This makes the role publicly visible highlighted: This makes the role publicly visible
name: Public name of the role, if role is set to be displayed as a badge name: Public name of the role, if role is set to be displayed as a badge
@ -386,6 +387,7 @@ en:
role: Role role: Role
time_zone: Time zone time_zone: Time zone
user_role: user_role:
collection_limit: Maximum number of Collections per user
color: Badge color color: Badge color
highlighted: Display role as badge on user profiles highlighted: Display role as badge on user profiles
name: Name name: Name

View File

@ -61,6 +61,9 @@ sv:
setting_default_quote_policy_private: Inlägg som endast är för följare och som författats på Mastodon kan inte citeras av andra. setting_default_quote_policy_private: Inlägg som endast är för följare och som författats på Mastodon kan inte citeras av andra.
setting_default_quote_policy_unlisted: När folk citerar dig, kommer deras inlägg också att döljas från trendande tidslinjer. setting_default_quote_policy_unlisted: När folk citerar dig, kommer deras inlägg också att döljas från trendande tidslinjer.
setting_default_sensitive: Känslig media döljs som standard och kan visas med ett klick setting_default_sensitive: Känslig media döljs som standard och kan visas med ett klick
setting_display_media_default: Varna innan du visar media markerad som känslig
setting_display_media_hide_all: Varna innan du visar alla medier
setting_display_media_show_all: Visa alla medier utan varning, inklusive media markerad som känslig
setting_emoji_style: Hur emojier visas. "Automatiskt" kommer att försöka använda webbläsarens emojier, men faller tillbaka till Twemoji för äldre webbläsare. setting_emoji_style: Hur emojier visas. "Automatiskt" kommer att försöka använda webbläsarens emojier, men faller tillbaka till Twemoji för äldre webbläsare.
setting_quick_boosting_html: När aktiverad, klicka på %{boost_icon} Boost-ikonen för att omedelbart boosta istället för att öppna boost/citera-rullgardinsmenyn. Flyttar citering till %{options_icon} (Alternativ)-menyn. setting_quick_boosting_html: När aktiverad, klicka på %{boost_icon} Boost-ikonen för att omedelbart boosta istället för att öppna boost/citera-rullgardinsmenyn. Flyttar citering till %{options_icon} (Alternativ)-menyn.
setting_system_scrollbars_ui: Gäller endast för webbläsare som är baserade på Safari och Chrome setting_system_scrollbars_ui: Gäller endast för webbläsare som är baserade på Safari och Chrome

View File

@ -0,0 +1,7 @@
# frozen_string_literal: true
class AddCollectionLimitToUserRoles < ActiveRecord::Migration[8.1]
def change
add_column :user_roles, :collection_limit, :integer, null: false, default: 10
end
end

View File

@ -7,7 +7,7 @@ class MigrateRoles < ActiveRecord::Migration[5.2]
class User < ApplicationRecord; end class User < ApplicationRecord; end
def up def up
load Rails.root.join('db', 'seeds', '03_roles.rb') create_user_roles
owner_role = UserRole.find_by(name: 'Owner') owner_role = UserRole.find_by(name: 'Owner')
moderator_role = UserRole.find_by(name: 'Moderator') moderator_role = UserRole.find_by(name: 'Moderator')
@ -24,4 +24,30 @@ class MigrateRoles < ActiveRecord::Migration[5.2]
User.where(role_id: [admin_role.id, owner_role.id]).in_batches.update_all(admin: true) if admin_role User.where(role_id: [admin_role.id, owner_role.id]).in_batches.update_all(admin: true) if admin_role
User.where(role_id: moderator_role.id).in_batches.update_all(moderator: true) if moderator_role User.where(role_id: moderator_role.id).in_batches.update_all(moderator: true) if moderator_role
end end
private
def create_user_roles
now = Time.zone.now.to_fs(:db)
safety_assured do
execute <<~SQL.squish
INSERT INTO user_roles ( id, permissions, created_at, updated_at )
VALUES ( -99, 65536, '#{now}', '#{now}' )
ON CONFLICT DO NOTHING
SQL
[
['Moderator', 10, 1308],
['Admin', 100, 983_036],
['Owner', 1000, 1],
].each do |name, position, permissions|
execute <<~SQL.squish
INSERT INTO user_roles ( name, position, highlighted, permissions, created_at, updated_at )
SELECT '#{name}', #{position}, true, #{permissions}, '#{now}', '#{now}'
WHERE NOT EXISTS ( SELECT 1 FROM user_roles WHERE name = '#{name}' )
SQL
end
end
end
end end

View File

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.1].define(version: 2026_04_15_133505) do ActiveRecord::Schema[8.1].define(version: 2026_04_20_124030) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql" enable_extension "pg_catalog.plpgsql"
@ -1340,6 +1340,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_04_15_133505) do
end end
create_table "user_roles", force: :cascade do |t| create_table "user_roles", force: :cascade do |t|
t.integer "collection_limit", default: 10, null: false
t.string "color", default: "", null: false t.string "color", default: "", null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.boolean "highlighted", default: false, null: false t.boolean "highlighted", default: false, null: false

View File

@ -107,7 +107,6 @@
"react-select": "^5.7.3", "react-select": "^5.7.3",
"react-sparklines": "^1.7.0", "react-sparklines": "^1.7.0",
"react-textarea-autosize": "^8.4.1", "react-textarea-autosize": "^8.4.1",
"react-toggle": "^4.1.3",
"redux-immutable": "^4.0.0", "redux-immutable": "^4.0.0",
"regenerator-runtime": "^0.14.0", "regenerator-runtime": "^0.14.0",
"requestidlecallback": "^0.3.0", "requestidlecallback": "^0.3.0",
@ -160,7 +159,6 @@
"@types/react-router-dom": "^5.3.3", "@types/react-router-dom": "^5.3.3",
"@types/react-sparklines": "^1.7.2", "@types/react-sparklines": "^1.7.2",
"@types/react-test-renderer": "^18.0.0", "@types/react-test-renderer": "^18.0.0",
"@types/react-toggle": "^4.0.3",
"@types/redux-immutable": "^4.0.3", "@types/redux-immutable": "^4.0.3",
"@types/requestidlecallback": "^0.3.5", "@types/requestidlecallback": "^0.3.5",
"@vitest/browser": "^4.1.0", "@vitest/browser": "^4.1.0",

View File

@ -71,6 +71,20 @@ RSpec.describe Collection do
it { is_expected.to be_valid } it { is_expected.to be_valid }
end end
end end
context 'when the user is already at the per-user limit of collections' do
subject { Fabricate.build(:collection, account:) }
let(:role) { Fabricate(:user_role, collection_limit: 2) }
let(:user) { Fabricate(:user, role:) }
let(:account) { user.account }
before do
Fabricate.times(2, :collection, account:)
end
it { is_expected.to_not be_valid }
end
end end
describe '#item_for' do describe '#item_for' do

View File

@ -31,6 +31,12 @@ RSpec.describe UserRole do
it { is_expected.to_not allow_values('x', '112233445566', '#xxyyzz').for(:color) } it { is_expected.to_not allow_values('x', '112233445566', '#xxyyzz').for(:color) }
end end
describe 'collection_limit' do
subject { Fabricate.build :user_role }
it { is_expected.to validate_numericality_of(:collection_limit).only_integer.is_greater_than_or_equal_to(0) }
end
context 'when current_account is set' do context 'when current_account is set' do
subject { Fabricate :user_role } subject { Fabricate :user_role }

View File

@ -0,0 +1,43 @@
# frozen_string_literal: true
require 'rails_helper'
RSpec.describe REST::RoleSerializer do
subject { serialized_record_json(role, described_class) }
let(:everyone) do
Fabricate.build(:user_role, permissions: 0)
end
let(:role) do
Fabricate.build(:user_role, id: 2342, name: 'test role', color: '#ABC', highlighted: true, permissions: 2300, collection_limit: 11)
end
before do
allow(UserRole).to receive(:everyone).and_return(everyone)
end
it 'includes the relevant attributes' do
expect(subject)
.to include({
'id' => '2342',
'name' => 'test role',
'color' => '#ABC',
'highlighted' => true,
'permissions' => '2300',
})
end
context 'when collections are enabled', feature: :collections do
it 'includes the relevant attributes' do
expect(subject)
.to include({
'id' => '2342',
'name' => 'test role',
'color' => '#ABC',
'highlighted' => true,
'permissions' => '2300',
'collection_limit' => 11,
})
end
end
end

View File

@ -6,6 +6,7 @@ import { optimizeLodashImports } from '@optimize-lodash/rollup-plugin';
import babel from '@rolldown/plugin-babel'; import babel from '@rolldown/plugin-babel';
import legacy from '@vitejs/plugin-legacy'; import legacy from '@vitejs/plugin-legacy';
import react from '@vitejs/plugin-react'; import react from '@vitejs/plugin-react';
import browserslist from 'browserslist';
import postcssPresetEnv from 'postcss-preset-env'; import postcssPresetEnv from 'postcss-preset-env';
import Compress from 'rollup-plugin-gzip'; import Compress from 'rollup-plugin-gzip';
import { visualizer } from 'rollup-plugin-visualizer'; import { visualizer } from 'rollup-plugin-visualizer';
@ -182,6 +183,7 @@ export const config: UserConfigFnPromise = async ({ mode, command }) => {
legacy({ legacy({
renderLegacyChunks: false, renderLegacyChunks: false,
modernPolyfills: true, modernPolyfills: true,
modernTargets: browserslist.loadConfig({ path: process.cwd() }),
}), }),
isProdBuild && (Compress() as PluginOption), isProdBuild && (Compress() as PluginOption),
command === 'build' && command === 'build' &&

View File

@ -2885,7 +2885,6 @@ __metadata:
"@types/react-router-dom": "npm:^5.3.3" "@types/react-router-dom": "npm:^5.3.3"
"@types/react-sparklines": "npm:^1.7.2" "@types/react-sparklines": "npm:^1.7.2"
"@types/react-test-renderer": "npm:^18.0.0" "@types/react-test-renderer": "npm:^18.0.0"
"@types/react-toggle": "npm:^4.0.3"
"@types/redux-immutable": "npm:^4.0.3" "@types/redux-immutable": "npm:^4.0.3"
"@types/requestidlecallback": "npm:^0.3.5" "@types/requestidlecallback": "npm:^0.3.5"
"@use-gesture/react": "npm:^10.3.1" "@use-gesture/react": "npm:^10.3.1"
@ -2966,7 +2965,6 @@ __metadata:
react-sparklines: "npm:^1.7.0" react-sparklines: "npm:^1.7.0"
react-test-renderer: "npm:^18.2.0" react-test-renderer: "npm:^18.2.0"
react-textarea-autosize: "npm:^8.4.1" react-textarea-autosize: "npm:^8.4.1"
react-toggle: "npm:^4.1.3"
redux-immutable: "npm:^4.0.0" redux-immutable: "npm:^4.0.0"
regenerator-runtime: "npm:^0.14.0" regenerator-runtime: "npm:^0.14.0"
requestidlecallback: "npm:^0.3.0" requestidlecallback: "npm:^0.3.0"
@ -4791,15 +4789,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@types/react-toggle@npm:^4.0.3":
version: 4.0.5
resolution: "@types/react-toggle@npm:4.0.5"
dependencies:
"@types/react": "npm:*"
checksum: 10c0/f557b85c96715b145bcc3beb2903f88ee3a6045ef85da0f80561c7cc2ecdc531e2d4ae121ed8ec3a1761264de25b8410653744093f37abf042201587add7ffa6
languageName: node
linkType: hard
"@types/react-transition-group@npm:^4.4.0": "@types/react-transition-group@npm:^4.4.0":
version: 4.4.8 version: 4.4.8
resolution: "@types/react-transition-group@npm:4.4.8" resolution: "@types/react-transition-group@npm:4.4.8"
@ -5927,11 +5916,11 @@ __metadata:
linkType: hard linkType: hard
"baseline-browser-mapping@npm:^2.9.0": "baseline-browser-mapping@npm:^2.9.0":
version: 2.9.2 version: 2.10.20
resolution: "baseline-browser-mapping@npm:2.9.2" resolution: "baseline-browser-mapping@npm:2.10.20"
bin: bin:
baseline-browser-mapping: dist/cli.js baseline-browser-mapping: dist/cli.cjs
checksum: 10c0/4f9be09e20261ed26f19e9b95454dcb8d8371b87983c57cd9f70b9572e9b3053577f0d8d6d91297bdb605337747680686e22f62522a6e57ae2488fcacf641188 checksum: 10c0/3d60c9656c4c4673593aa8d0ae9aa6b69b4e018c2f585874a0e8a40cb28d0559f57ee1b2e7e44cb1e7f6aac66f658a4a3c1285901b8836d8ae31e189e30aa816
languageName: node languageName: node
linkType: hard linkType: hard
@ -6160,9 +6149,9 @@ __metadata:
linkType: hard linkType: hard
"caniuse-lite@npm:^1.0.30001759, caniuse-lite@npm:^1.0.30001766": "caniuse-lite@npm:^1.0.30001759, caniuse-lite@npm:^1.0.30001766":
version: 1.0.30001770 version: 1.0.30001790
resolution: "caniuse-lite@npm:1.0.30001770" resolution: "caniuse-lite@npm:1.0.30001790"
checksum: 10c0/02d15a8b723af65318cb4d888a52bb090076898da7b0de99e8676d537f8d1d2ae4797e81518e1e30cbfe84c33b048c322e8bfafc5b23cfee8defb0d2bf271149 checksum: 10c0/eec0adc1dcb35d51e57bcfa0657493cb57ef43f0ceb03c1edcfee34d43e7a938e6beed2781118c7a5ee99d4f71d443977f08ca5a549005cf89260733af9ad3f8
languageName: node languageName: node
linkType: hard linkType: hard
@ -6245,7 +6234,7 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"classnames@npm:^2.2.5, classnames@npm:^2.3.2": "classnames@npm:^2.3.2":
version: 2.5.1 version: 2.5.1
resolution: "classnames@npm:2.5.1" resolution: "classnames@npm:2.5.1"
checksum: 10c0/afff4f77e62cea2d79c39962980bf316bacb0d7c49e13a21adaadb9221e1c6b9d3cdb829d8bb1b23c406f4e740507f37e1dcf506f7e3b7113d17c5bab787aa69 checksum: 10c0/afff4f77e62cea2d79c39962980bf316bacb0d7c49e13a21adaadb9221e1c6b9d3cdb829d8bb1b23c406f4e740507f37e1dcf506f7e3b7113d17c5bab787aa69
@ -12290,19 +12279,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"react-toggle@npm:^4.1.3":
version: 4.1.3
resolution: "react-toggle@npm:4.1.3"
dependencies:
classnames: "npm:^2.2.5"
peerDependencies:
prop-types: ">= 15.3.0 < 19"
react: ">= 15.3.0 < 19"
react-dom: ">= 15.3.0 < 19"
checksum: 10c0/afae643981d6fb922d66830ec0e9c793e729d7a55e3974edf212965acc8dc51f0d098ae6e409461d3ff2f87fe027dc3556a1a746f8472ed3a79c8878bf338fee
languageName: node
linkType: hard
"react-transition-group@npm:^4.3.0": "react-transition-group@npm:^4.3.0":
version: 4.4.5 version: 4.4.5
resolution: "react-transition-group@npm:4.4.5" resolution: "react-transition-group@npm:4.4.5"