mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-20 05:41:36 +00:00
Merge commit '0d650780e26735621f08bbdd545b162871e4562c' into glitch-soc/merge-upstream
Conflicts: - `.prettierignore`: Upstream added a file, glitch-soc had extra files. Took upstream's changes and moved glitch-soc's additions at the end.
This commit is contained in:
@@ -18,7 +18,7 @@ import { useIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import { useAppHistory } from './router';
|
||||
|
||||
const messages = defineMessages({
|
||||
export const messages = defineMessages({
|
||||
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
|
||||
hide: { id: 'column_header.hide_settings', defaultMessage: 'Hide settings' },
|
||||
moveLeft: {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import SettingsIcon from '@/material-icons/400-20px/settings.svg?react';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
import { requestBrowserPermission } from 'mastodon/actions/notifications';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
});
|
||||
|
||||
class NotificationsPermissionBanner extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
handleClick = () => {
|
||||
this.props.dispatch(requestBrowserPermission());
|
||||
};
|
||||
|
||||
handleClose = () => {
|
||||
this.props.dispatch(changeSetting(['notifications', 'dismissPermissionBanner'], true));
|
||||
};
|
||||
|
||||
render () {
|
||||
const { intl } = this.props;
|
||||
|
||||
return (
|
||||
<div className='notifications-permission-banner'>
|
||||
<div className='notifications-permission-banner__close'>
|
||||
<IconButton icon='times' iconComponent={CloseIcon} onClick={this.handleClose} title={intl.formatMessage(messages.close)} />
|
||||
</div>
|
||||
|
||||
<h2><FormattedMessage id='notifications_permission_banner.title' defaultMessage='Never miss a thing' /></h2>
|
||||
<p><FormattedMessage id='notifications_permission_banner.how_to_control' defaultMessage="To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled." values={{ icon: <Icon id='sliders' icon={SettingsIcon} /> }} /></p>
|
||||
<Button onClick={this.handleClick}><FormattedMessage id='notifications_permission_banner.enable' defaultMessage='Enable desktop notifications' /></Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect()(injectIntl(NotificationsPermissionBanner));
|
||||
@@ -0,0 +1,74 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { useAppDispatch } from '@/mastodon/store';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
import UnfoldMoreIcon from '@/material-icons/400-24px/unfold_more.svg?react';
|
||||
import { requestBrowserPermission } from 'mastodon/actions/notifications';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { Button } from 'mastodon/components/button';
|
||||
import { messages as columnHeaderMessages } from 'mastodon/components/column_header';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
|
||||
const messages = defineMessages({
|
||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
||||
});
|
||||
|
||||
const NotificationsPermissionBanner: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
dispatch(requestBrowserPermission());
|
||||
}, [dispatch]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
dispatch(changeSetting(['notifications', 'dismissPermissionBanner'], true));
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<div className='notifications-permission-banner'>
|
||||
<div className='notifications-permission-banner__close'>
|
||||
<IconButton
|
||||
icon='times'
|
||||
iconComponent={CloseIcon}
|
||||
onClick={handleClose}
|
||||
title={intl.formatMessage(messages.close)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2>
|
||||
<FormattedMessage
|
||||
id='notifications_permission_banner.title'
|
||||
defaultMessage='Never miss a thing'
|
||||
/>
|
||||
</h2>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id='notifications_permission_banner.how_to_control'
|
||||
defaultMessage="To receive notifications when Mastodon isn't open, enable desktop notifications. You can control precisely which types of interactions generate desktop notifications through the {icon} button above once they're enabled."
|
||||
values={{
|
||||
icon: (
|
||||
<Icon
|
||||
id='sliders'
|
||||
icon={UnfoldMoreIcon}
|
||||
aria-label={intl.formatMessage(columnHeaderMessages.show)}
|
||||
/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</p>
|
||||
<Button onClick={handleClick}>
|
||||
<FormattedMessage
|
||||
id='notifications_permission_banner.enable'
|
||||
defaultMessage='Enable desktop notifications'
|
||||
/>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default NotificationsPermissionBanner;
|
||||
@@ -1,71 +1,30 @@
|
||||
import { useLayoutEffect, useEffect, useState } from 'react';
|
||||
import { useLayoutEffect } from 'react';
|
||||
|
||||
import { createAppSelector, useAppSelector } from 'mastodon/store';
|
||||
import { getScrollbarWidth } from 'mastodon/utils/scrollbar';
|
||||
|
||||
const getShouldLockBodyScroll = createAppSelector(
|
||||
[
|
||||
(state) => state.navigation.open,
|
||||
(state) => state.modal.get('stack').size > 0,
|
||||
],
|
||||
(isMobileMenuOpen: boolean, isModalOpen: boolean) => {
|
||||
return isMobileMenuOpen || isModalOpen;
|
||||
},
|
||||
(isMobileMenuOpen: boolean, isModalOpen: boolean) =>
|
||||
isMobileMenuOpen || isModalOpen,
|
||||
);
|
||||
|
||||
/**
|
||||
* This component locks scrolling on the `body` element when
|
||||
* This component locks scrolling on the body when
|
||||
* `getShouldLockBodyScroll` returns true.
|
||||
*
|
||||
* The scrollbar width is taken into account and written to
|
||||
* a CSS custom property `--root-scrollbar-width`
|
||||
*/
|
||||
|
||||
export const BodyScrollLock: React.FC = () => {
|
||||
const shouldLockBodyScroll = useAppSelector(getShouldLockBodyScroll);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
document.body.classList.toggle('with-modals--active', shouldLockBodyScroll);
|
||||
document.documentElement.classList.toggle(
|
||||
'has-modal',
|
||||
shouldLockBodyScroll,
|
||||
);
|
||||
}, [shouldLockBodyScroll]);
|
||||
|
||||
const [scrollbarWidth, setScrollbarWidth] = useState(() =>
|
||||
getScrollbarWidth(),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleResize = () => {
|
||||
setScrollbarWidth(getScrollbarWidth());
|
||||
};
|
||||
window.addEventListener('resize', handleResize, { passive: true });
|
||||
return () => {
|
||||
window.removeEventListener('resize', handleResize);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Inject style element to make scrollbar width available
|
||||
// as CSS custom property
|
||||
useLayoutEffect(() => {
|
||||
const nonce = document
|
||||
.querySelector('meta[name=style-nonce]')
|
||||
?.getAttribute('content');
|
||||
|
||||
if (nonce) {
|
||||
const styleEl = document.createElement('style');
|
||||
styleEl.nonce = nonce;
|
||||
styleEl.innerHTML = `
|
||||
:root {
|
||||
--root-scrollbar-width: ${scrollbarWidth}px;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(styleEl);
|
||||
|
||||
return () => {
|
||||
document.head.removeChild(styleEl);
|
||||
};
|
||||
}
|
||||
|
||||
return () => '';
|
||||
}, [scrollbarWidth]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
@@ -13,6 +13,7 @@ export const ConfirmationModal: React.FC<
|
||||
title: React.ReactNode;
|
||||
message: React.ReactNode;
|
||||
confirm: React.ReactNode;
|
||||
cancel?: React.ReactNode;
|
||||
secondary?: React.ReactNode;
|
||||
onSecondary?: () => void;
|
||||
onConfirm: () => void;
|
||||
@@ -22,6 +23,7 @@ export const ConfirmationModal: React.FC<
|
||||
title,
|
||||
message,
|
||||
confirm,
|
||||
cancel,
|
||||
onClose,
|
||||
onConfirm,
|
||||
secondary,
|
||||
@@ -57,10 +59,12 @@ export const ConfirmationModal: React.FC<
|
||||
<div className='safety-action-modal__bottom'>
|
||||
<div className='safety-action-modal__actions'>
|
||||
<button onClick={handleCancel} className='link-button'>
|
||||
<FormattedMessage
|
||||
id='confirmation_modal.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
{cancel ?? (
|
||||
<FormattedMessage
|
||||
id='confirmation_modal.cancel'
|
||||
defaultMessage='Cancel'
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
|
||||
{secondary && (
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { replyCompose } from 'mastodon/actions/compose';
|
||||
import { editStatus } from 'mastodon/actions/statuses';
|
||||
import type { Status } from 'mastodon/models/status';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const editMessages = defineMessages({
|
||||
title: {
|
||||
id: 'confirmations.discard_draft.edit.title',
|
||||
defaultMessage: 'Discard changes to your post?',
|
||||
},
|
||||
message: {
|
||||
id: 'confirmations.discard_draft.edit.message',
|
||||
defaultMessage:
|
||||
'Continuing will discard any changes you have made to the post you are currently editing.',
|
||||
},
|
||||
cancel: {
|
||||
id: 'confirmations.discard_draft.edit.cancel',
|
||||
defaultMessage: 'Resume editing',
|
||||
},
|
||||
});
|
||||
|
||||
const postMessages = defineMessages({
|
||||
title: {
|
||||
id: 'confirmations.discard_draft.post.title',
|
||||
defaultMessage: 'Discard your draft post?',
|
||||
},
|
||||
message: {
|
||||
id: 'confirmations.discard_draft.post.message',
|
||||
defaultMessage:
|
||||
'Continuing will discard the post you are currently composing.',
|
||||
},
|
||||
cancel: {
|
||||
id: 'confirmations.discard_draft.post.cancel',
|
||||
defaultMessage: 'Resume draft',
|
||||
},
|
||||
});
|
||||
|
||||
const messages = defineMessages({
|
||||
confirm: {
|
||||
id: 'confirmations.discard_draft.confirm',
|
||||
defaultMessage: 'Discard and continue',
|
||||
},
|
||||
});
|
||||
|
||||
const DiscardDraftConfirmationModal: React.FC<
|
||||
{
|
||||
onConfirm: () => void;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ onConfirm, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const isEditing = useAppSelector((state) => !!state.compose.get('id'));
|
||||
|
||||
const contextualMessages = isEditing ? editMessages : postMessages;
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={intl.formatMessage(contextualMessages.title)}
|
||||
message={intl.formatMessage(contextualMessages.message)}
|
||||
cancel={intl.formatMessage(contextualMessages.cancel)}
|
||||
confirm={intl.formatMessage(messages.confirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export const ConfirmReplyModal: React.FC<
|
||||
{
|
||||
status: Status;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ status, onClose }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(replyCompose(status));
|
||||
}, [dispatch, status]);
|
||||
|
||||
return (
|
||||
<DiscardDraftConfirmationModal onConfirm={onConfirm} onClose={onClose} />
|
||||
);
|
||||
};
|
||||
|
||||
export const ConfirmEditStatusModal: React.FC<
|
||||
{
|
||||
statusId: string;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ statusId, onClose }) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(editStatus(statusId));
|
||||
}, [dispatch, statusId]);
|
||||
|
||||
return (
|
||||
<DiscardDraftConfirmationModal onConfirm={onConfirm} onClose={onClose} />
|
||||
);
|
||||
};
|
||||
@@ -1,45 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { editStatus } from 'mastodon/actions/statuses';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
editTitle: {
|
||||
id: 'confirmations.edit.title',
|
||||
defaultMessage: 'Overwrite post?',
|
||||
},
|
||||
editConfirm: { id: 'confirmations.edit.confirm', defaultMessage: 'Edit' },
|
||||
editMessage: {
|
||||
id: 'confirmations.edit.message',
|
||||
defaultMessage:
|
||||
'Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?',
|
||||
},
|
||||
});
|
||||
|
||||
export const ConfirmEditStatusModal: React.FC<
|
||||
{
|
||||
statusId: string;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ statusId, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(editStatus(statusId));
|
||||
}, [dispatch, statusId]);
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={intl.formatMessage(messages.editTitle)}
|
||||
message={intl.formatMessage(messages.editMessage)}
|
||||
confirm={intl.formatMessage(messages.editConfirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
export { ConfirmationModal } from './confirmation_modal';
|
||||
export { ConfirmDeleteStatusModal } from './delete_status';
|
||||
export { ConfirmDeleteListModal } from './delete_list';
|
||||
export { ConfirmReplyModal } from './reply';
|
||||
export { ConfirmEditStatusModal } from './edit_status';
|
||||
export {
|
||||
ConfirmReplyModal,
|
||||
ConfirmEditStatusModal,
|
||||
} from './discard_draft_confirmation';
|
||||
export { ConfirmUnfollowModal } from './unfollow';
|
||||
export { ConfirmClearNotificationsModal } from './clear_notifications';
|
||||
export { ConfirmLogOutModal } from './log_out';
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { replyCompose } from 'mastodon/actions/compose';
|
||||
import type { Status } from 'mastodon/models/status';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import type { BaseConfirmationModalProps } from './confirmation_modal';
|
||||
import { ConfirmationModal } from './confirmation_modal';
|
||||
|
||||
const messages = defineMessages({
|
||||
replyTitle: {
|
||||
id: 'confirmations.reply.title',
|
||||
defaultMessage: 'Overwrite post?',
|
||||
},
|
||||
replyConfirm: { id: 'confirmations.reply.confirm', defaultMessage: 'Reply' },
|
||||
replyMessage: {
|
||||
id: 'confirmations.reply.message',
|
||||
defaultMessage:
|
||||
'Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?',
|
||||
},
|
||||
});
|
||||
|
||||
export const ConfirmReplyModal: React.FC<
|
||||
{
|
||||
status: Status;
|
||||
} & BaseConfirmationModalProps
|
||||
> = ({ status, onClose }) => {
|
||||
const intl = useIntl();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const onConfirm = useCallback(() => {
|
||||
dispatch(replyCompose(status));
|
||||
}, [dispatch, status]);
|
||||
|
||||
return (
|
||||
<ConfirmationModal
|
||||
title={intl.formatMessage(messages.replyTitle)}
|
||||
message={intl.formatMessage(messages.replyMessage)}
|
||||
confirm={intl.formatMessage(messages.replyConfirm)}
|
||||
onConfirm={onConfirm}
|
||||
onClose={onClose}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -24,7 +24,7 @@
|
||||
"account.blocking": "Blokering",
|
||||
"account.cancel_follow_request": "Annullér anmodning om at følge",
|
||||
"account.copy": "Kopiér link til profil",
|
||||
"account.direct": "Privat omtale @{name}",
|
||||
"account.direct": "Nævn @{name} privat",
|
||||
"account.disable_notifications": "Advisér mig ikke længere, når @{name} poster",
|
||||
"account.domain_blocking": "Blokerer domæne",
|
||||
"account.edit_profile": "Redigér profil",
|
||||
@@ -121,7 +121,7 @@
|
||||
"annual_report.summary.highlighted_post.by_replies": "mest besvarede indlæg",
|
||||
"annual_report.summary.highlighted_post.possessive": "{name}s",
|
||||
"annual_report.summary.most_used_app.most_used_app": "mest benyttede app",
|
||||
"annual_report.summary.most_used_hashtag.most_used_hashtag": "mest benyttede etiket",
|
||||
"annual_report.summary.most_used_hashtag.most_used_hashtag": "mest benyttede hashtag",
|
||||
"annual_report.summary.most_used_hashtag.none": "Intet",
|
||||
"annual_report.summary.new_posts.new_posts": "nye indlæg",
|
||||
"annual_report.summary.percentile.text": "<topLabel>Det betyder, at man er i top</topLabel><percentage></percentage><bottomLabel>af {domain}-brugere.</bottomLabel>",
|
||||
@@ -194,10 +194,10 @@
|
||||
"compose.saved.body": "Indlæg gemt.",
|
||||
"compose_form.direct_message_warning_learn_more": "Få mere at vide",
|
||||
"compose_form.encryption_warning": "Indlæg på Mastodon er ikke ende-til-ende-krypteret. Del derfor ikke sensitiv information via Mastodon.",
|
||||
"compose_form.hashtag_warning": "Da indlægget ikke er offentligt, vises det ikke under nogen etiket, da kun offentlige indlæg er søgbare via etiketter.",
|
||||
"compose_form.hashtag_warning": "Da indlægget ikke er offentligt, vises det ikke under noget hashtag, da kun offentlige indlæg er søgbare via hashtags.",
|
||||
"compose_form.lock_disclaimer": "Din konto er ikke {locked}. Enhver kan følge dig og se indlæg kun beregnet for følgere.",
|
||||
"compose_form.lock_disclaimer.lock": "låst",
|
||||
"compose_form.placeholder": "Hvad tænker du på?",
|
||||
"compose_form.placeholder": "Hvad har du på hjertet?",
|
||||
"compose_form.poll.duration": "Afstemningens varighed",
|
||||
"compose_form.poll.multiple": "Multivalg",
|
||||
"compose_form.poll.option_placeholder": "Valgmulighed {number}",
|
||||
@@ -205,7 +205,7 @@
|
||||
"compose_form.poll.switch_to_multiple": "Ændr afstemning til flervalgstype",
|
||||
"compose_form.poll.switch_to_single": "Ændr afstemning til enkeltvalgstype",
|
||||
"compose_form.poll.type": "Stil",
|
||||
"compose_form.publish": "Indsend",
|
||||
"compose_form.publish": "Slå op",
|
||||
"compose_form.reply": "Svar",
|
||||
"compose_form.save_changes": "Opdatér",
|
||||
"compose_form.spoiler.marked": "Fjern emnefelt",
|
||||
@@ -305,8 +305,8 @@
|
||||
"emoji_button.search_results": "Søgeresultater",
|
||||
"emoji_button.symbols": "Symboler",
|
||||
"emoji_button.travel": "Rejser og steder",
|
||||
"empty_column.account_featured.me": "Intet fremhævet endnu. Vidste du, at man kan fremhæve sine mest brugte hashtags og endda en vens konti på sin profil?",
|
||||
"empty_column.account_featured.other": "{acct} har ikke fremhævet noget endnu. Vidste du, at man kan fremhæve sine mest brugte hashtags og endda en vens konti på sin profil?",
|
||||
"empty_column.account_featured.me": "Intet fremhævet endnu. Vidste du, at man kan fremhæve sine mest brugte hashtags og endda din vens konti på din profil?",
|
||||
"empty_column.account_featured.other": "{acct} har ikke fremhævet noget endnu. Vidste du, at du kan fremhæve dine mest brugte hashtags og endda din vens konti på din profil?",
|
||||
"empty_column.account_featured_other.unknown": "Denne konto har ikke fremhævet noget endnu.",
|
||||
"empty_column.account_hides_collections": "Brugeren har valgt ikke at gøre denne information tilgængelig",
|
||||
"empty_column.account_suspended": "Konto suspenderet",
|
||||
@@ -321,8 +321,8 @@
|
||||
"empty_column.favourited_statuses": "Du har endnu ingen favoritindlæg. Når du føjer et opslag til favoritter, vil det dukke op her.",
|
||||
"empty_column.favourites": "Ingen har endnu føjet dette indlæg til favoritter. Når nogen gør det, vil det dukke op her.",
|
||||
"empty_column.follow_requests": "Du har endnu ingen følgeanmodninger. Når du modtager én, vil den dukke op her.",
|
||||
"empty_column.followed_tags": "Ingen etiketter følges endnu. Når det sker, vil de fremgå her.",
|
||||
"empty_column.hashtag": "Der er intet med denne etiket endnu.",
|
||||
"empty_column.followed_tags": "Ingen hashtags følges endnu. Når det sker, vil de fremgå her.",
|
||||
"empty_column.hashtag": "Der er intet med dette hashtag endnu.",
|
||||
"empty_column.home": "Din hjemmetidslinje er tom! Følg nogle personer, for at fylde den op.",
|
||||
"empty_column.list": "Der er ikke noget på denne liste endnu. Når medlemmer af listen udgiver nye indlæg vil de fremgå her.",
|
||||
"empty_column.mutes": "Du har endnu ikke skjult nogle brugere.",
|
||||
@@ -336,9 +336,10 @@
|
||||
"errors.unexpected_crash.copy_stacktrace": "Kopiér stacktrace til udklipsholderen",
|
||||
"errors.unexpected_crash.report_issue": "Anmeld problem",
|
||||
"explore.suggested_follows": "Personer",
|
||||
"explore.title": "Trender",
|
||||
"explore.trending_links": "Nyheder",
|
||||
"explore.trending_statuses": "Indlæg",
|
||||
"explore.trending_tags": "Etiketter",
|
||||
"explore.trending_tags": "Hashtags",
|
||||
"featured_carousel.header": "{count, plural, one {Fastgjort indlæg} other {Fastgjorte indlæg}}",
|
||||
"featured_carousel.next": "Næste",
|
||||
"featured_carousel.post": "Indlæg",
|
||||
@@ -384,7 +385,7 @@
|
||||
"follow_suggestions.similar_to_recently_followed_longer": "Svarende til profiler, som for nylig er fulgt",
|
||||
"follow_suggestions.view_all": "Vis alle",
|
||||
"follow_suggestions.who_to_follow": "Hvem, som skal følges",
|
||||
"followed_tags": "Etiketter, som følges",
|
||||
"followed_tags": "Hashtag, som følges",
|
||||
"footer.about": "Om",
|
||||
"footer.directory": "Profiloversigt",
|
||||
"footer.get_app": "Hent appen",
|
||||
@@ -402,7 +403,7 @@
|
||||
"hashtag.column_header.tag_mode.any": "eller {additional}",
|
||||
"hashtag.column_header.tag_mode.none": "uden {additional}",
|
||||
"hashtag.column_settings.select.no_options_message": "Ingen forslag fundet",
|
||||
"hashtag.column_settings.select.placeholder": "Angiv etiketter…",
|
||||
"hashtag.column_settings.select.placeholder": "Angiv hashtags…",
|
||||
"hashtag.column_settings.tag_mode.all": "Alle disse",
|
||||
"hashtag.column_settings.tag_mode.any": "Nogle af disse",
|
||||
"hashtag.column_settings.tag_mode.none": "Ingen af disse",
|
||||
@@ -411,10 +412,10 @@
|
||||
"hashtag.counter_by_uses": "{count, plural, one {{counter} indlæg} other {{counter} indlæg}}",
|
||||
"hashtag.counter_by_uses_today": "{count, plural, one {{counter} indlæg} other {{counter} indlæg}} i dag",
|
||||
"hashtag.feature": "Fremhæv på profil",
|
||||
"hashtag.follow": "Følg etiket",
|
||||
"hashtag.follow": "Følg hashtag",
|
||||
"hashtag.mute": "Tavsgør #{hashtag}",
|
||||
"hashtag.unfeature": "Fremhæv ikke på profil",
|
||||
"hashtag.unfollow": "Stop med at følge etiket",
|
||||
"hashtag.unfollow": "Følg ikke længere hashtag",
|
||||
"hashtags.and_other": "…og {count, plural, one {}other {# flere}}",
|
||||
"hints.profiles.followers_may_be_missing": "Der kan mangle følgere for denne profil.",
|
||||
"hints.profiles.follows_may_be_missing": "Fulgte kan mangle for denne profil.",
|
||||
@@ -442,7 +443,7 @@
|
||||
"ignore_notifications_modal.new_accounts_title": "Ignorér notifikationer fra nye konti?",
|
||||
"ignore_notifications_modal.not_followers_title": "Ignorér notifikationer fra folk, som ikke er følgere?",
|
||||
"ignore_notifications_modal.not_following_title": "Ignorér notifikationer fra folk, man ikke følger?",
|
||||
"ignore_notifications_modal.private_mentions_title": "Ignorér notifikationer fra uopfordrede Private omtaler?",
|
||||
"ignore_notifications_modal.private_mentions_title": "Ignorér notifikationer fra uopfordrede private omtaler?",
|
||||
"info_button.label": "Hjælp",
|
||||
"info_button.what_is_alt_text": "<h1>Hvad er alt-tekst?</h1> <p>Alt-tekst leverer billedbeskrivelser til folk med synsnedsættelser, lav båndbredde-forbindelser eller med ønske om ekstra kontekst.</p> <p>Tilgængelighed og forståelse kan forbedres for alle ved at skrive klar, kortfattet og objektiv alt-tekst.</p> <ul> <li>Fang vigtige elementer</li> <li>Opsummér tekst i billeder</li> <li>Brug almindelig sætningsstruktur</li> <li>Undgå overflødig information</li> <li>Fokusér på tendenser og centrale resultater i kompleks grafik (såsom diagrammer eller kort)</li> </ul>",
|
||||
"interaction_modal.action.favourite": "For at fortsætte, skal du føje til favoritter fra din konto.",
|
||||
@@ -558,7 +559,7 @@
|
||||
"navigation_bar.favourites": "Favoritter",
|
||||
"navigation_bar.filters": "Skjulte ord",
|
||||
"navigation_bar.follow_requests": "Følgeanmodninger",
|
||||
"navigation_bar.followed_tags": "Etiketter, som følges",
|
||||
"navigation_bar.followed_tags": "Hashtag, som følges",
|
||||
"navigation_bar.follows_and_followers": "Følges og følgere",
|
||||
"navigation_bar.import_export": "Import og eksport",
|
||||
"navigation_bar.lists": "Lister",
|
||||
@@ -574,7 +575,9 @@
|
||||
"navigation_bar.search": "Søg",
|
||||
"navigation_bar.search_trends": "Søg/Populære",
|
||||
"navigation_panel.collapse_followed_tags": "Sammenfold menuen Fulgte hashtags",
|
||||
"navigation_panel.collapse_lists": "Luk listemenu",
|
||||
"navigation_panel.expand_followed_tags": "Udfold menuen Fulgte hashtags",
|
||||
"navigation_panel.expand_lists": "Udvid listemenu",
|
||||
"not_signed_in_indicator.not_signed_in": "Log ind for at tilgå denne ressource.",
|
||||
"notification.admin.report": "{name} anmeldte {target}",
|
||||
"notification.admin.report_account": "{name} anmeldte {count, plural, one {et indlæg} other {# indlæg}} fra {target} angående {category}",
|
||||
@@ -703,7 +706,7 @@
|
||||
"onboarding.profile.display_name": "Vist navn",
|
||||
"onboarding.profile.display_name_hint": "Dit fulde navn eller dit sjove navn…",
|
||||
"onboarding.profile.note": "Bio",
|
||||
"onboarding.profile.note_hint": "Man kan @omtale andre personer eller #etiketter…",
|
||||
"onboarding.profile.note_hint": "Du kan @omtale andre personer eller #hashtags…",
|
||||
"onboarding.profile.save_and_continue": "Gem og fortsæt",
|
||||
"onboarding.profile.title": "Profilopsætning",
|
||||
"onboarding.profile.upload_avatar": "Upload profilbillede",
|
||||
@@ -728,9 +731,9 @@
|
||||
"privacy.private.short": "Følgere",
|
||||
"privacy.public.long": "Alle på og udenfor Mastodon",
|
||||
"privacy.public.short": "Offentlig",
|
||||
"privacy.unlisted.additional": "Dette er præcis som offentlig adfærd, dog vises indlægget ikke i tidslinjer, under etiketter, udforsk eller Mastodon-søgning, selv hvis du ellers har sagt at dine opslag godt må være søgbare.",
|
||||
"privacy.unlisted.additional": "Dette er præcis som offentlig adfærd, dog vises indlægget ikke i live feeds/hashtags, udforsk eller Mastodon-søgning, selv hvis valget gælder hele kontoen.",
|
||||
"privacy.unlisted.long": "Færre algoritmiske fanfarer",
|
||||
"privacy.unlisted.short": "Stille offentligt",
|
||||
"privacy.unlisted.short": "Offentlig (stille)",
|
||||
"privacy_policy.last_updated": "Senest opdateret {date}",
|
||||
"privacy_policy.title": "Privatlivspolitik",
|
||||
"recommended": "Anbefalet",
|
||||
@@ -801,14 +804,15 @@
|
||||
"report_notification.categories.violation": "Regelovertrædelse",
|
||||
"report_notification.categories.violation_sentence": "regelovertrædelse",
|
||||
"report_notification.open": "Åbn anmeldelse",
|
||||
"search.clear": "Ryd søgning",
|
||||
"search.no_recent_searches": "Ingen seneste søgninger",
|
||||
"search.placeholder": "Søg",
|
||||
"search.quick_action.account_search": "Profiler matchende {x}",
|
||||
"search.quick_action.go_to_account": "Gå til profilen {x}",
|
||||
"search.quick_action.go_to_hashtag": "Gå til etiketten {x}",
|
||||
"search.quick_action.go_to_hashtag": "Gå til hashtagget {x}",
|
||||
"search.quick_action.open_url": "Åbn URL i Mastodon",
|
||||
"search.quick_action.status_search": "Indlæg matchende {x}",
|
||||
"search.search_or_paste": "Søg efter eller angiv URL",
|
||||
"search.search_or_paste": "Søg eller indsæt URL",
|
||||
"search_popout.full_text_search_disabled_message": "Utilgængelig på {domain}.",
|
||||
"search_popout.full_text_search_logged_out_message": "Kun tilgængelig, når logget ind.",
|
||||
"search_popout.language_code": "ISO-sprogkode",
|
||||
@@ -819,9 +823,9 @@
|
||||
"search_popout.user": "bruger",
|
||||
"search_results.accounts": "Profiler",
|
||||
"search_results.all": "Alle",
|
||||
"search_results.hashtags": "Etiketter",
|
||||
"search_results.hashtags": "Hashtags",
|
||||
"search_results.no_results": "Ingen resultater.",
|
||||
"search_results.no_search_yet": "Prøv at søge efter indlæg, profiler eller etiketter.",
|
||||
"search_results.no_search_yet": "Prøv at søge efter indlæg, profiler eller hashtags.",
|
||||
"search_results.see_all": "Vis alle",
|
||||
"search_results.statuses": "Indlæg",
|
||||
"search_results.title": "Søg efter \"{q}\"",
|
||||
@@ -846,7 +850,7 @@
|
||||
"status.copy": "Kopiér link til indlæg",
|
||||
"status.delete": "Slet",
|
||||
"status.detailed_status": "Detaljeret samtalevisning",
|
||||
"status.direct": "Privat omtale @{name}",
|
||||
"status.direct": "Nævn @{name} privat",
|
||||
"status.direct_indicator": "Privat omtale",
|
||||
"status.edit": "Redigér",
|
||||
"status.edited": "Senest redigeret {date}",
|
||||
@@ -903,7 +907,10 @@
|
||||
"subscribed_languages.save": "Gem ændringer",
|
||||
"subscribed_languages.target": "Skift abonnementssprog for {target}",
|
||||
"tabs_bar.home": "Hjem",
|
||||
"tabs_bar.menu": "Menu",
|
||||
"tabs_bar.notifications": "Notifikationer",
|
||||
"tabs_bar.publish": "Nyt indlæg",
|
||||
"tabs_bar.search": "Søg",
|
||||
"terms_of_service.effective_as_of": "Gældende pr. {date}",
|
||||
"terms_of_service.title": "Tjenestevilkår",
|
||||
"terms_of_service.upcoming_changes_on": "Kommende ændringer pr. {date}",
|
||||
|
||||
@@ -219,11 +219,15 @@
|
||||
"confirmations.delete_list.confirm": "Delete",
|
||||
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
|
||||
"confirmations.delete_list.title": "Delete list?",
|
||||
"confirmations.discard_draft.confirm": "Discard and continue",
|
||||
"confirmations.discard_draft.edit.cancel": "Resume editing",
|
||||
"confirmations.discard_draft.edit.message": "Continuing will discard any changes you have made to the post you are currently editing.",
|
||||
"confirmations.discard_draft.edit.title": "Discard changes to your post?",
|
||||
"confirmations.discard_draft.post.cancel": "Resume draft",
|
||||
"confirmations.discard_draft.post.message": "Continuing will discard the post you are currently composing.",
|
||||
"confirmations.discard_draft.post.title": "Discard your draft post?",
|
||||
"confirmations.discard_edit_media.confirm": "Discard",
|
||||
"confirmations.discard_edit_media.message": "You have unsaved changes to the media description or preview, discard them anyway?",
|
||||
"confirmations.edit.confirm": "Edit",
|
||||
"confirmations.edit.message": "Editing now will overwrite the message you are currently composing. Are you sure you want to proceed?",
|
||||
"confirmations.edit.title": "Overwrite post?",
|
||||
"confirmations.follow_to_list.confirm": "Follow and add to list",
|
||||
"confirmations.follow_to_list.message": "You need to be following {name} to add them to a list.",
|
||||
"confirmations.follow_to_list.title": "Follow user?",
|
||||
@@ -241,9 +245,6 @@
|
||||
"confirmations.remove_from_followers.confirm": "Remove follower",
|
||||
"confirmations.remove_from_followers.message": "{name} will stop following you. Are you sure you want to proceed?",
|
||||
"confirmations.remove_from_followers.title": "Remove follower?",
|
||||
"confirmations.reply.confirm": "Reply",
|
||||
"confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
|
||||
"confirmations.reply.title": "Overwrite post?",
|
||||
"confirmations.unfollow.confirm": "Unfollow",
|
||||
"confirmations.unfollow.message": "Are you sure you want to unfollow {name}?",
|
||||
"confirmations.unfollow.title": "Unfollow user?",
|
||||
|
||||
@@ -569,6 +569,7 @@
|
||||
"navigation_bar.mutes": "کاربران خموشانده",
|
||||
"navigation_bar.opened_in_classic_interface": "فرستهها، حسابها و دیگر صفحههای خاص به طور پیشگزیده در میانای وب کلاسیک گشوده میشوند.",
|
||||
"navigation_bar.preferences": "ترجیحات",
|
||||
"navigation_bar.privacy_and_reach": "محرمانگی و دسترسی",
|
||||
"navigation_bar.search": "جستوجو",
|
||||
"navigation_bar.search_trends": "جستجو \\ پرطرفدار",
|
||||
"not_signed_in_indicator.not_signed_in": "برای دسترسی به این منبع باید وارد شوید.",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Sääntörikkomus",
|
||||
"report_notification.categories.violation_sentence": "sääntörikkomus",
|
||||
"report_notification.open": "Avaa raportti",
|
||||
"search.clear": "Tyhjennä haku",
|
||||
"search.no_recent_searches": "Ei viimeaikaisia hakuja",
|
||||
"search.placeholder": "Hae",
|
||||
"search.quick_action.account_search": "Profiilit haulla {x}",
|
||||
|
||||
@@ -563,6 +563,8 @@
|
||||
"navigation_bar.follows_and_followers": "Ag leanúint agus do do leanúint",
|
||||
"navigation_bar.import_export": "Allmhairiú agus onnmhairiú",
|
||||
"navigation_bar.lists": "Liostaí",
|
||||
"navigation_bar.live_feed_local": "Fotha beo (áitiúil)",
|
||||
"navigation_bar.live_feed_public": "Fotha beo (poiblí)",
|
||||
"navigation_bar.logout": "Logáil Amach",
|
||||
"navigation_bar.moderation": "Measarthacht",
|
||||
"navigation_bar.more": "Tuilleadh",
|
||||
@@ -802,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Sárú rialach",
|
||||
"report_notification.categories.violation_sentence": "sárú riail",
|
||||
"report_notification.open": "Oscail tuairisc",
|
||||
"search.clear": "Glan an cuardach",
|
||||
"search.no_recent_searches": "Níl aon chuardach le déanaí",
|
||||
"search.placeholder": "Cuardaigh",
|
||||
"search.quick_action.account_search": "Próifílí a mheaitseálann {x}",
|
||||
|
||||
@@ -573,7 +573,10 @@
|
||||
"navigation_bar.preferences": "Preferências",
|
||||
"navigation_bar.privacy_and_reach": "Privacidade e alcance",
|
||||
"navigation_bar.search": "Pesquisar",
|
||||
"navigation_bar.search_trends": "Pesquisar / Em destaque",
|
||||
"navigation_panel.collapse_followed_tags": "Recolher o menu de etiquetas seguidas",
|
||||
"navigation_panel.collapse_lists": "Recolher lista de menu",
|
||||
"navigation_panel.expand_followed_tags": "Expandir o menu de etiquetas seguidas",
|
||||
"navigation_panel.expand_lists": "Expandir lista de menu",
|
||||
"not_signed_in_indicator.not_signed_in": "Tens de iniciar a sessão para utilizares esta funcionalidade.",
|
||||
"notification.admin.report": "{name} denunciou {target}",
|
||||
|
||||
@@ -804,6 +804,7 @@
|
||||
"report_notification.categories.violation": "Kural ihlali",
|
||||
"report_notification.categories.violation_sentence": "kural ihlali",
|
||||
"report_notification.open": "Bildirim aç",
|
||||
"search.clear": "Aramayı temizle",
|
||||
"search.no_recent_searches": "Son arama yok",
|
||||
"search.placeholder": "Ara",
|
||||
"search.quick_action.account_search": "Eşleşen profiller {x}",
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
import { isMobile } from '../is_mobile';
|
||||
|
||||
export const getScrollbarWidth = () => {
|
||||
if (isMobile(window.innerWidth)) {
|
||||
return 0;
|
||||
}
|
||||
const outer = document.createElement('div');
|
||||
outer.style.visibility = 'hidden';
|
||||
outer.style.overflow = 'scroll';
|
||||
document.body.appendChild(outer);
|
||||
|
||||
const inner = document.createElement('div');
|
||||
outer.appendChild(inner);
|
||||
|
||||
const scrollbarWidth = outer.offsetWidth - inner.offsetWidth;
|
||||
outer.remove();
|
||||
|
||||
return scrollbarWidth;
|
||||
};
|
||||
@@ -1,6 +1,20 @@
|
||||
@use 'variables' as *;
|
||||
@use 'functions' as *;
|
||||
|
||||
html.has-modal {
|
||||
&,
|
||||
body {
|
||||
touch-action: none;
|
||||
overscroll-behavior: none;
|
||||
-webkit-overflow-scrolling: auto;
|
||||
scrollbar-gutter: stable;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: $font-sans-serif, sans-serif;
|
||||
background: var(--background-color);
|
||||
@@ -64,21 +78,6 @@ body {
|
||||
height: 100%;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
&.with-modals--active {
|
||||
overflow-y: hidden;
|
||||
overscroll-behavior: none;
|
||||
margin-right: var(--root-scrollbar-width, 0);
|
||||
}
|
||||
}
|
||||
|
||||
&.with-modals {
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
|
||||
&--active {
|
||||
overflow-y: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
&.player {
|
||||
|
||||
@@ -2896,10 +2896,6 @@ a.account__display-name {
|
||||
border-top: 1px solid var(--background-border-color);
|
||||
box-sizing: border-box;
|
||||
|
||||
.with-modals--active & {
|
||||
padding-right: var(--root-scrollbar-width);
|
||||
}
|
||||
|
||||
.layout-multiple-columns & {
|
||||
display: none;
|
||||
}
|
||||
@@ -3170,7 +3166,7 @@ a.account__display-name {
|
||||
.navigation-panel {
|
||||
margin: 0;
|
||||
border-inline-start: 1px solid var(--background-border-color);
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
}
|
||||
|
||||
.navigation-panel__banner,
|
||||
@@ -3228,6 +3224,7 @@ a.account__display-name {
|
||||
.navigation-panel {
|
||||
width: 284px;
|
||||
overflow-y: auto;
|
||||
scrollbar-width: thin;
|
||||
|
||||
&__menu {
|
||||
flex-shrink: 0;
|
||||
|
||||
Reference in New Issue
Block a user