Merge pull request #2808 from ClearlyClaire/glitch-soc/merge-upstream

Merge upstream changes up to 079d681ac6
This commit is contained in:
Claire 2024-08-08 21:00:19 +02:00 committed by GitHub
commit 42c9488032
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
98 changed files with 727 additions and 450 deletions

View file

@ -116,7 +116,7 @@ module ApplicationHelper
def material_symbol(icon, attributes = {}) def material_symbol(icon, attributes = {})
inline_svg_tag( inline_svg_tag(
"400-24px/#{icon}.svg", "400-24px/#{icon}.svg",
class: %w(icon).concat(attributes[:class].to_s.split), class: ['icon', "material-#{icon}"].concat(attributes[:class].to_s.split),
role: :img role: :img
) )
end end
@ -127,23 +127,23 @@ module ApplicationHelper
def visibility_icon(status) def visibility_icon(status)
if status.public_visibility? if status.public_visibility?
fa_icon('globe', title: I18n.t('statuses.visibilities.public')) material_symbol('globe', title: I18n.t('statuses.visibilities.public'))
elsif status.unlisted_visibility? elsif status.unlisted_visibility?
fa_icon('unlock', title: I18n.t('statuses.visibilities.unlisted')) material_symbol('lock_open', title: I18n.t('statuses.visibilities.unlisted'))
elsif status.private_visibility? || status.limited_visibility? elsif status.private_visibility? || status.limited_visibility?
fa_icon('lock', title: I18n.t('statuses.visibilities.private')) material_symbol('lock', title: I18n.t('statuses.visibilities.private'))
elsif status.direct_visibility? elsif status.direct_visibility?
fa_icon('at', title: I18n.t('statuses.visibilities.direct')) material_symbol('alternate_email', title: I18n.t('statuses.visibilities.direct'))
end end
end end
def interrelationships_icon(relationships, account_id) def interrelationships_icon(relationships, account_id)
if relationships.following[account_id] && relationships.followed_by[account_id] if relationships.following[account_id] && relationships.followed_by[account_id]
fa_icon('exchange', title: I18n.t('relationships.mutual'), class: 'fa-fw active passive') material_symbol('sync_alt', title: I18n.t('relationships.mutual'), class: 'active passive')
elsif relationships.following[account_id] elsif relationships.following[account_id]
fa_icon(locale_direction == 'ltr' ? 'arrow-right' : 'arrow-left', title: I18n.t('relationships.following'), class: 'fa-fw active') material_symbol(locale_direction == 'ltr' ? 'arrow_right_alt' : 'arrow_left_alt', title: I18n.t('relationships.following'), class: 'active')
elsif relationships.followed_by[account_id] elsif relationships.followed_by[account_id]
fa_icon(locale_direction == 'ltr' ? 'arrow-left' : 'arrow-right', title: I18n.t('relationships.followers'), class: 'fa-fw passive') material_symbol(locale_direction == 'ltr' ? 'arrow_left_alt' : 'arrow_right_alt', title: I18n.t('relationships.followers'), class: 'passive')
end end
end end

View file

@ -60,13 +60,13 @@ module StatusesHelper
def fa_visibility_icon(status) def fa_visibility_icon(status)
case status.visibility case status.visibility
when 'public' when 'public'
fa_icon 'globe fw' material_symbol 'globe'
when 'unlisted' when 'unlisted'
fa_icon 'unlock fw' material_symbol 'lock_open'
when 'private' when 'private'
fa_icon 'lock fw' material_symbol 'lock'
when 'direct' when 'direct'
fa_icon 'at fw' material_symbol 'alternate_email'
end end
end end

View file

@ -0,0 +1,185 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import { supportsPassiveEvents } from 'detect-passive-events';
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
import type { IconProp } from './icon';
import { Icon } from './icon';
const listenerOptions = supportsPassiveEvents
? { passive: true, capture: true }
: true;
interface SelectItem {
value: string;
icon?: string;
iconComponent?: IconProp;
text: string;
meta: string;
extra?: string;
}
interface Props {
value: string;
classNamePrefix: string;
style?: React.CSSProperties;
items: SelectItem[];
onChange: (value: string) => void;
onClose: () => void;
}
export const DropdownSelector: React.FC<Props> = ({
style,
items,
value,
classNamePrefix = 'privacy-dropdown',
onClose,
onChange,
}) => {
const nodeRef = useRef<HTMLUListElement>(null);
const focusedItemRef = useRef<HTMLLIElement>(null);
const [currentValue, setCurrentValue] = useState(value);
const handleDocumentClick = useCallback(
(e: MouseEvent | TouchEvent) => {
if (
nodeRef.current &&
e.target instanceof Node &&
!nodeRef.current.contains(e.target)
) {
onClose();
e.stopPropagation();
}
},
[nodeRef, onClose],
);
const handleClick = useCallback(
(
e: React.MouseEvent<HTMLLIElement> | React.KeyboardEvent<HTMLLIElement>,
) => {
const value = e.currentTarget.getAttribute('data-index');
e.preventDefault();
onClose();
if (value) onChange(value);
},
[onClose, onChange],
);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLLIElement>) => {
const value = e.currentTarget.getAttribute('data-index');
const index = items.findIndex((item) => item.value === value);
let element: Element | null | undefined = null;
switch (e.key) {
case 'Escape':
onClose();
break;
case ' ':
case 'Enter':
handleClick(e);
break;
case 'ArrowDown':
element =
nodeRef.current?.children[index + 1] ??
nodeRef.current?.firstElementChild;
break;
case 'ArrowUp':
element =
nodeRef.current?.children[index - 1] ??
nodeRef.current?.lastElementChild;
break;
case 'Tab':
if (e.shiftKey) {
element =
nodeRef.current?.children[index + 1] ??
nodeRef.current?.firstElementChild;
} else {
element =
nodeRef.current?.children[index - 1] ??
nodeRef.current?.lastElementChild;
}
break;
case 'Home':
element = nodeRef.current?.firstElementChild;
break;
case 'End':
element = nodeRef.current?.lastElementChild;
break;
}
if (element && element instanceof HTMLElement) {
const selectedValue = element.getAttribute('data-index');
element.focus();
if (selectedValue) setCurrentValue(selectedValue);
e.preventDefault();
e.stopPropagation();
}
},
[nodeRef, items, onClose, handleClick, setCurrentValue],
);
useEffect(() => {
document.addEventListener('click', handleDocumentClick, { capture: true });
document.addEventListener('touchend', handleDocumentClick, listenerOptions);
focusedItemRef.current?.focus({ preventScroll: true });
return () => {
document.removeEventListener('click', handleDocumentClick, {
capture: true,
});
document.removeEventListener(
'touchend',
handleDocumentClick,
listenerOptions,
);
};
}, [handleDocumentClick]);
return (
<ul style={style} role='listbox' ref={nodeRef}>
{items.map((item) => (
<li
role='option'
tabIndex={0}
key={item.value}
data-index={item.value}
onKeyDown={handleKeyDown}
onClick={handleClick}
className={classNames(`${classNamePrefix}__option`, {
active: item.value === currentValue,
})}
aria-selected={item.value === currentValue}
ref={item.value === currentValue ? focusedItemRef : null}
>
{item.icon && item.iconComponent && (
<div className={`${classNamePrefix}__option__icon`}>
<Icon id={item.icon} icon={item.iconComponent} />
</div>
)}
<div className={`${classNamePrefix}__option__content`}>
<strong>{item.text}</strong>
{item.meta}
</div>
{item.extra && (
<div
className={`${classNamePrefix}__option__additional`}
title={item.extra}
>
<Icon id='info-circle' icon={InfoIcon} />
</div>
)}
</li>
))}
</ul>
);
};

View file

@ -3,10 +3,9 @@ import { useCallback, useState, useRef } from 'react';
import Overlay from 'react-overlays/Overlay'; import Overlay from 'react-overlays/Overlay';
import { DropdownSelector } from 'flavours/glitch/components/dropdown_selector';
import { IconButton } from 'flavours/glitch/components/icon_button'; import { IconButton } from 'flavours/glitch/components/icon_button';
import { PrivacyDropdownMenu } from './privacy_dropdown_menu';
export const DropdownIconButton = ({ value, disabled, icon, onChange, iconComponent, title, options }) => { export const DropdownIconButton = ({ value, disabled, icon, onChange, iconComponent, title, options }) => {
const containerRef = useRef(null); const containerRef = useRef(null);
@ -53,7 +52,7 @@ export const DropdownIconButton = ({ value, disabled, icon, onChange, iconCompon
{({ props, placement }) => ( {({ props, placement }) => (
<div {...props}> <div {...props}>
<div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}> <div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>
<PrivacyDropdownMenu <DropdownSelector
items={options} items={options}
value={value} value={value}
onClose={handleClose} onClose={handleClose}

View file

@ -11,10 +11,9 @@ import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?re
import LockIcon from '@/material-icons/400-24px/lock.svg?react'; import LockIcon from '@/material-icons/400-24px/lock.svg?react';
import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import PublicIcon from '@/material-icons/400-24px/public.svg?react';
import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react'; import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
import { DropdownSelector } from 'flavours/glitch/components/dropdown_selector';
import { Icon } from 'flavours/glitch/components/icon'; import { Icon } from 'flavours/glitch/components/icon';
import { PrivacyDropdownMenu } from './privacy_dropdown_menu';
const messages = defineMessages({ const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' }, public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' },
@ -143,7 +142,7 @@ class PrivacyDropdown extends PureComponent {
{({ props, placement }) => ( {({ props, placement }) => (
<div {...props}> <div {...props}>
<div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}> <div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>
<PrivacyDropdownMenu <DropdownSelector
items={this.options} items={this.options}
value={value} value={value}
onClose={this.handleClose} onClose={this.handleClose}

View file

@ -1,128 +0,0 @@
import PropTypes from 'prop-types';
import { useCallback, useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import { supportsPassiveEvents } from 'detect-passive-events';
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
import { Icon } from 'flavours/glitch/components/icon';
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
export const PrivacyDropdownMenu = ({ style, items, value, onClose, onChange }) => {
const nodeRef = useRef(null);
const focusedItemRef = useRef(null);
const [currentValue, setCurrentValue] = useState(value);
const handleDocumentClick = useCallback((e) => {
if (nodeRef.current && !nodeRef.current.contains(e.target)) {
onClose();
e.stopPropagation();
}
}, [nodeRef, onClose]);
const handleClick = useCallback((e) => {
const value = e.currentTarget.getAttribute('data-index');
e.preventDefault();
onClose();
onChange(value);
}, [onClose, onChange]);
const handleKeyDown = useCallback((e) => {
const value = e.currentTarget.getAttribute('data-index');
const index = items.findIndex(item => (item.value === value));
let element = null;
switch (e.key) {
case 'Escape':
onClose();
break;
case ' ':
case 'Enter':
handleClick(e);
break;
case 'ArrowDown':
element = nodeRef.current.childNodes[index + 1] || nodeRef.current.firstChild;
break;
case 'ArrowUp':
element = nodeRef.current.childNodes[index - 1] || nodeRef.current.lastChild;
break;
case 'Tab':
if (e.shiftKey) {
element = nodeRef.current.childNodes[index + 1] || nodeRef.current.firstChild;
} else {
element = nodeRef.current.childNodes[index - 1] || nodeRef.current.lastChild;
}
break;
case 'Home':
element = nodeRef.current.firstChild;
break;
case 'End':
element = nodeRef.current.lastChild;
break;
}
if (element) {
element.focus();
setCurrentValue(element.getAttribute('data-index'));
e.preventDefault();
e.stopPropagation();
}
}, [nodeRef, items, onClose, handleClick, setCurrentValue]);
useEffect(() => {
document.addEventListener('click', handleDocumentClick, { capture: true });
document.addEventListener('touchend', handleDocumentClick, listenerOptions);
focusedItemRef.current?.focus({ preventScroll: true });
return () => {
document.removeEventListener('click', handleDocumentClick, { capture: true });
document.removeEventListener('touchend', handleDocumentClick, listenerOptions);
};
}, [handleDocumentClick]);
return (
<ul style={{ ...style }} role='listbox' ref={nodeRef}>
{items.map(item => (
<li
role='option'
tabIndex={0}
key={item.value}
data-index={item.value}
onKeyDown={handleKeyDown}
onClick={handleClick}
className={classNames('privacy-dropdown__option', { active: item.value === currentValue })}
aria-selected={item.value === currentValue}
ref={item.value === currentValue ? focusedItemRef : null}
>
<div className='privacy-dropdown__option__icon'>
<Icon id={item.icon} icon={item.iconComponent} />
</div>
<div className='privacy-dropdown__option__content'>
<strong>{item.text}</strong>
{item.meta}
</div>
{item.extra && (
<div className='privacy-dropdown__option__additional' title={item.extra}>
<Icon id='info-circle' icon={InfoIcon} />
</div>
)}
</li>
))}
</ul>
);
};
PrivacyDropdownMenu.propTypes = {
style: PropTypes.object,
items: PropTypes.array.isRequired,
value: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
};

View file

@ -7,6 +7,9 @@ import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
import { CheckboxWithLabel } from './checkbox_with_label'; import { CheckboxWithLabel } from './checkbox_with_label';
// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = () => {};
export const PolicyControls: React.FC = () => { export const PolicyControls: React.FC = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -135,6 +138,21 @@ export const PolicyControls: React.FC = () => {
/> />
</span> </span>
</CheckboxWithLabel> </CheckboxWithLabel>
<CheckboxWithLabel checked disabled onChange={noop}>
<strong>
<FormattedMessage
id='notifications.policy.filter_limited_accounts_title'
defaultMessage='Moderated accounts'
/>
</strong>
<span className='hint'>
<FormattedMessage
id='notifications.policy.filter_limited_accounts_hint'
defaultMessage='Limited by server moderators'
/>
</span>
</CheckboxWithLabel>
</div> </div>
</section> </section>
); );

View file

@ -1,7 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useRef, useCallback, useEffect } from 'react'; import { useRef, useCallback, useEffect } from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
@ -90,6 +90,23 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
const columnTitle = intl.formatMessage(messages.title, { name: account?.get('display_name') || account?.get('username') }); const columnTitle = intl.formatMessage(messages.title, { name: account?.get('display_name') || account?.get('username') });
let explainer = null;
if (account?.limited) {
const isLocal = account.acct.indexOf('@') === -1;
explainer = (
<div className='dismissable-banner'>
<div className='dismissable-banner__message'>
{isLocal ? (
<FormattedMessage id='notification_requests.explainer_for_limited_account' defaultMessage='Notifications from this account have been filtered because the account has been limited by a moderator.' />
) : (
<FormattedMessage id='notification_requests.explainer_for_limited_remote_account' defaultMessage='Notifications from this account have been filtered because the account or its server has been limited by a moderator.' />
)}
</div>
</div>
);
}
return ( return (
<Column bindToDocument={!multiColumn} ref={columnRef} label={columnTitle}> <Column bindToDocument={!multiColumn} ref={columnRef} label={columnTitle}>
<ColumnHeader <ColumnHeader
@ -109,6 +126,7 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
<SensitiveMediaContextProvider hideMediaByDefault> <SensitiveMediaContextProvider hideMediaByDefault>
<ScrollableList <ScrollableList
prepend={explainer}
scrollKey={`notification_requests/${id}`} scrollKey={`notification_requests/${id}`}
trackScroll={!multiColumn} trackScroll={!multiColumn}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}

View file

@ -474,8 +474,11 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>(
state.lastReadId, state.lastReadId,
action.payload.markers.notifications.last_read_id, action.payload.markers.notifications.last_read_id,
) < 0 ) < 0
) ) {
state.lastReadId = action.payload.markers.notifications.last_read_id; state.lastReadId = action.payload.markers.notifications.last_read_id;
state.readMarkerId =
action.payload.markers.notifications.last_read_id;
}
}) })
.addCase(mountNotifications, (state) => { .addCase(mountNotifications, (state) => {
state.mounted += 1; state.mounted += 1;

View file

@ -17,7 +17,7 @@
background: $ui-base-color; background: $ui-base-color;
color: $darker-text-color; color: $darker-text-color;
border-radius: 4px; border-radius: 4px;
border: 1px solid lighten($ui-base-color, 8%); border: 1px solid var(--background-border-color);
font-size: 17px; font-size: 17px;
line-height: normal; line-height: normal;
margin: 0; margin: 0;

View file

@ -10,6 +10,13 @@ $content-width: 840px;
width: 100%; width: 100%;
min-height: 100vh; min-height: 100vh;
.icon {
width: 16px;
height: 16px;
vertical-align: top;
margin: 0 2px;
}
.sidebar-wrapper { .sidebar-wrapper {
min-height: 100vh; min-height: 100vh;
overflow: hidden; overflow: hidden;

View file

@ -403,7 +403,7 @@ body > [data-popper-placement] {
&__suggestions { &__suggestions {
box-shadow: var(--dropdown-shadow); box-shadow: var(--dropdown-shadow);
background: $ui-base-color; background: $ui-base-color;
border: 1px solid lighten($ui-base-color, 14%); border: 1px solid var(--background-border-color);
border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px;
color: $secondary-text-color; color: $secondary-text-color;
font-size: 14px; font-size: 14px;
@ -3268,11 +3268,6 @@ $ui-header-logo-wordmark-width: 99px;
.explore__search-header { .explore__search-header {
display: flex; display: flex;
} }
.explore__search-results {
border: 0;
border-radius: 0;
}
} }
.icon-with-badge { .icon-with-badge {
@ -9346,10 +9341,13 @@ noscript {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@media screen and (min-width: $no-gap-breakpoint) {
border: 1px solid var(--background-border-color); border: 1px solid var(--background-border-color);
border-top: 0; border-top: 0;
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
}
} }
.story { .story {

View file

@ -442,11 +442,6 @@ code {
border-radius: 4px; border-radius: 4px;
padding: 10px 16px; padding: 10px 16px;
&::placeholder {
color: $dark-text-color;
opacity: 1;
}
&:invalid { &:invalid {
box-shadow: none; box-shadow: none;
} }
@ -608,8 +603,7 @@ code {
inset-inline-end: 3px; inset-inline-end: 3px;
top: 1px; top: 1px;
padding: 10px; padding: 10px;
padding-bottom: 9px; font-size: 14px;
font-size: 16px;
color: $dark-text-color; color: $dark-text-color;
font-family: inherit; font-family: inherit;
pointer-events: none; pointer-events: none;
@ -626,11 +620,6 @@ code {
inset-inline-end: 0; inset-inline-end: 0;
bottom: 1px; bottom: 1px;
width: 5px; width: 5px;
background-image: linear-gradient(
to right,
rgba(darken($ui-base-color, 10%), 0),
darken($ui-base-color, 10%)
);
} }
} }
} }

View file

@ -559,11 +559,11 @@ html {
.compose-form .autosuggest-textarea__textarea, .compose-form .autosuggest-textarea__textarea,
.compose-form__highlightable, .compose-form__highlightable,
.autosuggest-textarea__suggestions,
.search__input, .search__input,
.search__popout, .search__popout,
.emoji-mart-search input, .emoji-mart-search input,
.language-dropdown__dropdown .emoji-mart-search input, .language-dropdown__dropdown .emoji-mart-search input,
// .strike-card,
.poll__option input[type='text'] { .poll__option input[type='text'] {
background: darken($ui-base-color, 10%); background: darken($ui-base-color, 10%);
} }

View file

@ -90,16 +90,6 @@ body.rtl {
direction: rtl; direction: rtl;
} }
.simple_form .label_input__append {
&::after {
background-image: linear-gradient(
to left,
rgba(darken($ui-base-color, 10%), 0),
darken($ui-base-color, 10%)
);
}
}
.simple_form select { .simple_form select {
background: $ui-base-color background: $ui-base-color
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>") url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>")

View file

@ -273,8 +273,8 @@ a.table-action-link {
} }
} }
&:nth-child(even) { &:last-child {
background: var(--background-color); border-radius: 0 0 4px 4px;
} }
&__content { &__content {

View file

@ -211,7 +211,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
border: 1px solid lighten($ui-base-color, 8%); border: 1px solid var(--background-border-color);
border-radius: 4px; border-radius: 4px;
padding: 15px; padding: 15px;
text-decoration: none; text-decoration: none;

View file

@ -0,0 +1,185 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import { supportsPassiveEvents } from 'detect-passive-events';
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
import type { IconProp } from './icon';
import { Icon } from './icon';
const listenerOptions = supportsPassiveEvents
? { passive: true, capture: true }
: true;
interface SelectItem {
value: string;
icon?: string;
iconComponent?: IconProp;
text: string;
meta: string;
extra?: string;
}
interface Props {
value: string;
classNamePrefix: string;
style?: React.CSSProperties;
items: SelectItem[];
onChange: (value: string) => void;
onClose: () => void;
}
export const DropdownSelector: React.FC<Props> = ({
style,
items,
value,
classNamePrefix = 'privacy-dropdown',
onClose,
onChange,
}) => {
const nodeRef = useRef<HTMLUListElement>(null);
const focusedItemRef = useRef<HTMLLIElement>(null);
const [currentValue, setCurrentValue] = useState(value);
const handleDocumentClick = useCallback(
(e: MouseEvent | TouchEvent) => {
if (
nodeRef.current &&
e.target instanceof Node &&
!nodeRef.current.contains(e.target)
) {
onClose();
e.stopPropagation();
}
},
[nodeRef, onClose],
);
const handleClick = useCallback(
(
e: React.MouseEvent<HTMLLIElement> | React.KeyboardEvent<HTMLLIElement>,
) => {
const value = e.currentTarget.getAttribute('data-index');
e.preventDefault();
onClose();
if (value) onChange(value);
},
[onClose, onChange],
);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLLIElement>) => {
const value = e.currentTarget.getAttribute('data-index');
const index = items.findIndex((item) => item.value === value);
let element: Element | null | undefined = null;
switch (e.key) {
case 'Escape':
onClose();
break;
case ' ':
case 'Enter':
handleClick(e);
break;
case 'ArrowDown':
element =
nodeRef.current?.children[index + 1] ??
nodeRef.current?.firstElementChild;
break;
case 'ArrowUp':
element =
nodeRef.current?.children[index - 1] ??
nodeRef.current?.lastElementChild;
break;
case 'Tab':
if (e.shiftKey) {
element =
nodeRef.current?.children[index + 1] ??
nodeRef.current?.firstElementChild;
} else {
element =
nodeRef.current?.children[index - 1] ??
nodeRef.current?.lastElementChild;
}
break;
case 'Home':
element = nodeRef.current?.firstElementChild;
break;
case 'End':
element = nodeRef.current?.lastElementChild;
break;
}
if (element && element instanceof HTMLElement) {
const selectedValue = element.getAttribute('data-index');
element.focus();
if (selectedValue) setCurrentValue(selectedValue);
e.preventDefault();
e.stopPropagation();
}
},
[nodeRef, items, onClose, handleClick, setCurrentValue],
);
useEffect(() => {
document.addEventListener('click', handleDocumentClick, { capture: true });
document.addEventListener('touchend', handleDocumentClick, listenerOptions);
focusedItemRef.current?.focus({ preventScroll: true });
return () => {
document.removeEventListener('click', handleDocumentClick, {
capture: true,
});
document.removeEventListener(
'touchend',
handleDocumentClick,
listenerOptions,
);
};
}, [handleDocumentClick]);
return (
<ul style={style} role='listbox' ref={nodeRef}>
{items.map((item) => (
<li
role='option'
tabIndex={0}
key={item.value}
data-index={item.value}
onKeyDown={handleKeyDown}
onClick={handleClick}
className={classNames(`${classNamePrefix}__option`, {
active: item.value === currentValue,
})}
aria-selected={item.value === currentValue}
ref={item.value === currentValue ? focusedItemRef : null}
>
{item.icon && item.iconComponent && (
<div className={`${classNamePrefix}__option__icon`}>
<Icon id={item.icon} icon={item.iconComponent} />
</div>
)}
<div className={`${classNamePrefix}__option__content`}>
<strong>{item.text}</strong>
{item.meta}
</div>
{item.extra && (
<div
className={`${classNamePrefix}__option__additional`}
title={item.extra}
>
<Icon id='info-circle' icon={InfoIcon} />
</div>
)}
</li>
))}
</ul>
);
};

View file

@ -11,10 +11,9 @@ import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?re
import LockIcon from '@/material-icons/400-24px/lock.svg?react'; import LockIcon from '@/material-icons/400-24px/lock.svg?react';
import PublicIcon from '@/material-icons/400-24px/public.svg?react'; import PublicIcon from '@/material-icons/400-24px/public.svg?react';
import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react'; import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
import { DropdownSelector } from 'mastodon/components/dropdown_selector';
import { Icon } from 'mastodon/components/icon'; import { Icon } from 'mastodon/components/icon';
import { PrivacyDropdownMenu } from './privacy_dropdown_menu';
const messages = defineMessages({ const messages = defineMessages({
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' }, public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' },
@ -143,7 +142,7 @@ class PrivacyDropdown extends PureComponent {
{({ props, placement }) => ( {({ props, placement }) => (
<div {...props}> <div {...props}>
<div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}> <div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>
<PrivacyDropdownMenu <DropdownSelector
items={this.options} items={this.options}
value={value} value={value}
onClose={this.handleClose} onClose={this.handleClose}

View file

@ -1,128 +0,0 @@
import PropTypes from 'prop-types';
import { useCallback, useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import { supportsPassiveEvents } from 'detect-passive-events';
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
import { Icon } from 'mastodon/components/icon';
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
export const PrivacyDropdownMenu = ({ style, items, value, onClose, onChange }) => {
const nodeRef = useRef(null);
const focusedItemRef = useRef(null);
const [currentValue, setCurrentValue] = useState(value);
const handleDocumentClick = useCallback((e) => {
if (nodeRef.current && !nodeRef.current.contains(e.target)) {
onClose();
e.stopPropagation();
}
}, [nodeRef, onClose]);
const handleClick = useCallback((e) => {
const value = e.currentTarget.getAttribute('data-index');
e.preventDefault();
onClose();
onChange(value);
}, [onClose, onChange]);
const handleKeyDown = useCallback((e) => {
const value = e.currentTarget.getAttribute('data-index');
const index = items.findIndex(item => (item.value === value));
let element = null;
switch (e.key) {
case 'Escape':
onClose();
break;
case ' ':
case 'Enter':
handleClick(e);
break;
case 'ArrowDown':
element = nodeRef.current.childNodes[index + 1] || nodeRef.current.firstChild;
break;
case 'ArrowUp':
element = nodeRef.current.childNodes[index - 1] || nodeRef.current.lastChild;
break;
case 'Tab':
if (e.shiftKey) {
element = nodeRef.current.childNodes[index + 1] || nodeRef.current.firstChild;
} else {
element = nodeRef.current.childNodes[index - 1] || nodeRef.current.lastChild;
}
break;
case 'Home':
element = nodeRef.current.firstChild;
break;
case 'End':
element = nodeRef.current.lastChild;
break;
}
if (element) {
element.focus();
setCurrentValue(element.getAttribute('data-index'));
e.preventDefault();
e.stopPropagation();
}
}, [nodeRef, items, onClose, handleClick, setCurrentValue]);
useEffect(() => {
document.addEventListener('click', handleDocumentClick, { capture: true });
document.addEventListener('touchend', handleDocumentClick, listenerOptions);
focusedItemRef.current?.focus({ preventScroll: true });
return () => {
document.removeEventListener('click', handleDocumentClick, { capture: true });
document.removeEventListener('touchend', handleDocumentClick, listenerOptions);
};
}, [handleDocumentClick]);
return (
<ul style={{ ...style }} role='listbox' ref={nodeRef}>
{items.map(item => (
<li
role='option'
tabIndex={0}
key={item.value}
data-index={item.value}
onKeyDown={handleKeyDown}
onClick={handleClick}
className={classNames('privacy-dropdown__option', { active: item.value === currentValue })}
aria-selected={item.value === currentValue}
ref={item.value === currentValue ? focusedItemRef : null}
>
<div className='privacy-dropdown__option__icon'>
<Icon id={item.icon} icon={item.iconComponent} />
</div>
<div className='privacy-dropdown__option__content'>
<strong>{item.text}</strong>
{item.meta}
</div>
{item.extra && (
<div className='privacy-dropdown__option__additional' title={item.extra}>
<Icon id='info-circle' icon={InfoIcon} />
</div>
)}
</li>
))}
</ul>
);
};
PrivacyDropdownMenu.propTypes = {
style: PropTypes.object,
items: PropTypes.array.isRequired,
value: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
};

View file

@ -7,6 +7,9 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store';
import { CheckboxWithLabel } from './checkbox_with_label'; import { CheckboxWithLabel } from './checkbox_with_label';
// eslint-disable-next-line @typescript-eslint/no-empty-function
const noop = () => {};
export const PolicyControls: React.FC = () => { export const PolicyControls: React.FC = () => {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
@ -135,6 +138,21 @@ export const PolicyControls: React.FC = () => {
/> />
</span> </span>
</CheckboxWithLabel> </CheckboxWithLabel>
<CheckboxWithLabel checked disabled onChange={noop}>
<strong>
<FormattedMessage
id='notifications.policy.filter_limited_accounts_title'
defaultMessage='Moderated accounts'
/>
</strong>
<span className='hint'>
<FormattedMessage
id='notifications.policy.filter_limited_accounts_hint'
defaultMessage='Limited by server moderators'
/>
</span>
</CheckboxWithLabel>
</div> </div>
</section> </section>
); );

View file

@ -1,7 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useRef, useCallback, useEffect } from 'react'; import { useRef, useCallback, useEffect } from 'react';
import { defineMessages, useIntl } from 'react-intl'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
@ -90,6 +90,23 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
const columnTitle = intl.formatMessage(messages.title, { name: account?.get('display_name') || account?.get('username') }); const columnTitle = intl.formatMessage(messages.title, { name: account?.get('display_name') || account?.get('username') });
let explainer = null;
if (account?.limited) {
const isLocal = account.acct.indexOf('@') === -1;
explainer = (
<div className='dismissable-banner'>
<div className='dismissable-banner__message'>
{isLocal ? (
<FormattedMessage id='notification_requests.explainer_for_limited_account' defaultMessage='Notifications from this account have been filtered because the account has been limited by a moderator.' />
) : (
<FormattedMessage id='notification_requests.explainer_for_limited_remote_account' defaultMessage='Notifications from this account have been filtered because the account or its server has been limited by a moderator.' />
)}
</div>
</div>
);
}
return ( return (
<Column bindToDocument={!multiColumn} ref={columnRef} label={columnTitle}> <Column bindToDocument={!multiColumn} ref={columnRef} label={columnTitle}>
<ColumnHeader <ColumnHeader
@ -109,6 +126,7 @@ export const NotificationRequest = ({ multiColumn, params: { id } }) => {
<SensitiveMediaContextProvider hideMediaByDefault> <SensitiveMediaContextProvider hideMediaByDefault>
<ScrollableList <ScrollableList
prepend={explainer}
scrollKey={`notification_requests/${id}`} scrollKey={`notification_requests/${id}`}
trackScroll={!multiColumn} trackScroll={!multiColumn}
bindToDocument={!multiColumn} bindToDocument={!multiColumn}

View file

@ -545,6 +545,8 @@
"notifications.permission_denied": "Computernotifikationer er utilgængelige grundet tidligere afvist browsertilladelsesanmodning", "notifications.permission_denied": "Computernotifikationer er utilgængelige grundet tidligere afvist browsertilladelsesanmodning",
"notifications.permission_denied_alert": "Computernotifikationer kan ikke aktiveres, da browsertilladelse tidligere blev nægtet", "notifications.permission_denied_alert": "Computernotifikationer kan ikke aktiveres, da browsertilladelse tidligere blev nægtet",
"notifications.permission_required": "Computernotifikationer er utilgængelige, da den krævede tilladelse ikke er tildelt.", "notifications.permission_required": "Computernotifikationer er utilgængelige, da den krævede tilladelse ikke er tildelt.",
"notifications.policy.filter_limited_accounts_hint": "Begrænset af servermoderatorer",
"notifications.policy.filter_limited_accounts_title": "Modererede konti",
"notifications.policy.filter_new_accounts.hint": "Oprettet indenfor {days, plural, one {den seneste dag} other {de seneste # dage}}", "notifications.policy.filter_new_accounts.hint": "Oprettet indenfor {days, plural, one {den seneste dag} other {de seneste # dage}}",
"notifications.policy.filter_new_accounts_title": "Ny konti", "notifications.policy.filter_new_accounts_title": "Ny konti",
"notifications.policy.filter_not_followers_hint": "Inklusiv personer, som har fulgt dig {days, plural, one {mindre end én dag} other {færre end # dage}}", "notifications.policy.filter_not_followers_hint": "Inklusiv personer, som har fulgt dig {days, plural, one {mindre end én dag} other {færre end # dage}}",

View file

@ -11,6 +11,7 @@
"about.not_available": "Αυτές οι πληροφορίες δεν έχουν είναι διαθέσιμες σε αυτόν τον διακομιστή.", "about.not_available": "Αυτές οι πληροφορίες δεν έχουν είναι διαθέσιμες σε αυτόν τον διακομιστή.",
"about.powered_by": "Αποκεντρωμένα μέσα κοινωνικής δικτύωσης που βασίζονται στο {mastodon}", "about.powered_by": "Αποκεντρωμένα μέσα κοινωνικής δικτύωσης που βασίζονται στο {mastodon}",
"about.rules": "Κανόνες διακομιστή", "about.rules": "Κανόνες διακομιστή",
"account.account_note_header": "Προσωπική σημείωση",
"account.add_or_remove_from_list": "Προσθήκη ή Αφαίρεση από λίστες", "account.add_or_remove_from_list": "Προσθήκη ή Αφαίρεση από λίστες",
"account.badges.bot": "Αυτοματοποιημένος", "account.badges.bot": "Αυτοματοποιημένος",
"account.badges.group": "Ομάδα", "account.badges.group": "Ομάδα",
@ -170,21 +171,28 @@
"confirmations.block.confirm": "Αποκλεισμός", "confirmations.block.confirm": "Αποκλεισμός",
"confirmations.delete.confirm": "Διαγραφή", "confirmations.delete.confirm": "Διαγραφή",
"confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή τη δημοσίευση;", "confirmations.delete.message": "Σίγουρα θες να διαγράψεις αυτή τη δημοσίευση;",
"confirmations.delete.title": "Διαγραφή ανάρτησης;",
"confirmations.delete_list.confirm": "Διαγραφή", "confirmations.delete_list.confirm": "Διαγραφή",
"confirmations.delete_list.message": "Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;", "confirmations.delete_list.message": "Σίγουρα θες να διαγράψεις οριστικά αυτή τη λίστα;",
"confirmations.delete_list.title": "Διαγραφή λίστας;",
"confirmations.discard_edit_media.confirm": "Απόρριψη", "confirmations.discard_edit_media.confirm": "Απόρριψη",
"confirmations.discard_edit_media.message": "Έχεις μη αποθηκευμένες αλλαγές στην περιγραφή πολυμέσων ή στην προεπισκόπηση, απόρριψη ούτως ή άλλως;", "confirmations.discard_edit_media.message": "Έχεις μη αποθηκευμένες αλλαγές στην περιγραφή πολυμέσων ή στην προεπισκόπηση, απόρριψη ούτως ή άλλως;",
"confirmations.edit.confirm": "Επεξεργασία", "confirmations.edit.confirm": "Επεξεργασία",
"confirmations.edit.message": "Αν το επεξεργαστείς τώρα θα αντικατασταθεί το μήνυμα που συνθέτεις. Είσαι σίγουρος ότι θέλεις να συνεχίσεις;", "confirmations.edit.message": "Αν το επεξεργαστείς τώρα θα αντικατασταθεί το μήνυμα που συνθέτεις. Είσαι σίγουρος ότι θέλεις να συνεχίσεις;",
"confirmations.edit.title": "Αντικατάσταση ανάρτησης;",
"confirmations.logout.confirm": "Αποσύνδεση", "confirmations.logout.confirm": "Αποσύνδεση",
"confirmations.logout.message": "Σίγουρα θέλεις να αποσυνδεθείς;", "confirmations.logout.message": "Σίγουρα θέλεις να αποσυνδεθείς;",
"confirmations.logout.title": "Αποσύνδεση;",
"confirmations.mute.confirm": "Αποσιώπηση", "confirmations.mute.confirm": "Αποσιώπηση",
"confirmations.redraft.confirm": "Διαγραφή & ξαναγράψιμο", "confirmations.redraft.confirm": "Διαγραφή & ξαναγράψιμο",
"confirmations.redraft.message": "Σίγουρα θέλεις να σβήσεις αυτή την ανάρτηση και να την ξαναγράψεις; Οι προτιμήσεις και προωθήσεις θα χαθούν και οι απαντήσεις στην αρχική ανάρτηση θα μείνουν ορφανές.", "confirmations.redraft.message": "Σίγουρα θέλεις να σβήσεις αυτή την ανάρτηση και να την ξαναγράψεις; Οι προτιμήσεις και προωθήσεις θα χαθούν και οι απαντήσεις στην αρχική ανάρτηση θα μείνουν ορφανές.",
"confirmations.redraft.title": "Διαγραφή & επανασύνταξη;",
"confirmations.reply.confirm": "Απάντησε", "confirmations.reply.confirm": "Απάντησε",
"confirmations.reply.message": "Απαντώντας τώρα θα αντικαταστήσεις το κείμενο που ήδη γράφεις. Σίγουρα θέλεις να συνεχίσεις;", "confirmations.reply.message": "Απαντώντας τώρα θα αντικαταστήσεις το κείμενο που ήδη γράφεις. Σίγουρα θέλεις να συνεχίσεις;",
"confirmations.reply.title": "Αντικατάσταση ανάρτησης;",
"confirmations.unfollow.confirm": "Άρση ακολούθησης", "confirmations.unfollow.confirm": "Άρση ακολούθησης",
"confirmations.unfollow.message": "Σίγουρα θες να πάψεις να ακολουθείς τον/την {name};", "confirmations.unfollow.message": "Σίγουρα θες να πάψεις να ακολουθείς τον/την {name};",
"confirmations.unfollow.title": "Άρση ακολούθησης;",
"conversation.delete": "Διαγραφή συζήτησης", "conversation.delete": "Διαγραφή συζήτησης",
"conversation.mark_as_read": "Σήμανση ως αναγνωσμένο", "conversation.mark_as_read": "Σήμανση ως αναγνωσμένο",
"conversation.open": "Προβολή συνομιλίας", "conversation.open": "Προβολή συνομιλίας",
@ -292,6 +300,7 @@
"filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα", "filter_modal.select_filter.subtitle": "Χρησιμοποιήστε μια υπάρχουσα κατηγορία ή δημιουργήστε μια νέα",
"filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης", "filter_modal.select_filter.title": "Φιλτράρισμα αυτής της ανάρτησης",
"filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης", "filter_modal.title.status": "Φιλτράρισμα μιας ανάρτησης",
"filtered_notifications_banner.pending_requests": "Από {count, plural, =0 {κανένα} one {ένα άτομο} other {# άτομα}} που μπορεί να ξέρεις",
"filtered_notifications_banner.title": "Φιλτραρισμένες ειδοποιήσεις", "filtered_notifications_banner.title": "Φιλτραρισμένες ειδοποιήσεις",
"firehose.all": "Όλα", "firehose.all": "Όλα",
"firehose.local": "Αυτός ο διακομιστής", "firehose.local": "Αυτός ο διακομιστής",
@ -496,10 +505,13 @@
"notification.update": "ο/η {name} επεξεργάστηκε μια ανάρτηση", "notification.update": "ο/η {name} επεξεργάστηκε μια ανάρτηση",
"notification_requests.accept": "Αποδοχή", "notification_requests.accept": "Αποδοχή",
"notification_requests.dismiss": "Απόρριψη", "notification_requests.dismiss": "Απόρριψη",
"notification_requests.maximize": "Μεγιστοποίηση",
"notification_requests.minimize_banner": "Ελαχιστοποίηση μπάνερ φιλτραρισμένων ειδοποιήσεων",
"notification_requests.notifications_from": "Ειδοποιήσεις από {name}", "notification_requests.notifications_from": "Ειδοποιήσεις από {name}",
"notification_requests.title": "Φιλτραρισμένες ειδοποιήσεις", "notification_requests.title": "Φιλτραρισμένες ειδοποιήσεις",
"notifications.clear": "Καθαρισμός ειδοποιήσεων", "notifications.clear": "Καθαρισμός ειδοποιήσεων",
"notifications.clear_confirmation": "Σίγουρα θέλεις να καθαρίσεις μόνιμα όλες τις ειδοποιήσεις σου;", "notifications.clear_confirmation": "Σίγουρα θέλεις να καθαρίσεις μόνιμα όλες τις ειδοποιήσεις σου;",
"notifications.clear_title": "Εκκαθάριση ειδοποιήσεων;",
"notifications.column_settings.admin.report": "Νέες αναφορές:", "notifications.column_settings.admin.report": "Νέες αναφορές:",
"notifications.column_settings.admin.sign_up": "Νέες εγγραφές:", "notifications.column_settings.admin.sign_up": "Νέες εγγραφές:",
"notifications.column_settings.alert": "Ειδοποιήσεις επιφάνειας εργασίας", "notifications.column_settings.alert": "Ειδοποιήσεις επιφάνειας εργασίας",

View file

@ -505,6 +505,8 @@
"notification.update": "{name} edited a post", "notification.update": "{name} edited a post",
"notification_requests.accept": "Accept", "notification_requests.accept": "Accept",
"notification_requests.dismiss": "Dismiss", "notification_requests.dismiss": "Dismiss",
"notification_requests.explainer_for_limited_account": "Notifications from this account have been filtered because the account has been limited by a moderator.",
"notification_requests.explainer_for_limited_remote_account": "Notifications from this account have been filtered because the account or its server has been limited by a moderator.",
"notification_requests.maximize": "Maximize", "notification_requests.maximize": "Maximize",
"notification_requests.minimize_banner": "Minimize filtered notifications banner", "notification_requests.minimize_banner": "Minimize filtered notifications banner",
"notification_requests.notifications_from": "Notifications from {name}", "notification_requests.notifications_from": "Notifications from {name}",
@ -545,6 +547,8 @@
"notifications.permission_denied": "Desktop notifications are unavailable due to previously denied browser permissions request", "notifications.permission_denied": "Desktop notifications are unavailable due to previously denied browser permissions request",
"notifications.permission_denied_alert": "Desktop notifications can't be enabled, as browser permission has been denied before", "notifications.permission_denied_alert": "Desktop notifications can't be enabled, as browser permission has been denied before",
"notifications.permission_required": "Desktop notifications are unavailable because the required permission has not been granted.", "notifications.permission_required": "Desktop notifications are unavailable because the required permission has not been granted.",
"notifications.policy.filter_limited_accounts_hint": "Limited by server moderators",
"notifications.policy.filter_limited_accounts_title": "Moderated accounts",
"notifications.policy.filter_new_accounts.hint": "Created within the past {days, plural, one {one day} other {# days}}", "notifications.policy.filter_new_accounts.hint": "Created within the past {days, plural, one {one day} other {# days}}",
"notifications.policy.filter_new_accounts_title": "New accounts", "notifications.policy.filter_new_accounts_title": "New accounts",
"notifications.policy.filter_not_followers_hint": "Including people who have been following you fewer than {days, plural, one {one day} other {# days}}", "notifications.policy.filter_not_followers_hint": "Including people who have been following you fewer than {days, plural, one {one day} other {# days}}",

View file

@ -545,6 +545,8 @@
"notifications.permission_denied": "Las notificaciones de escritorio no están disponibles, debido a una solicitud de permiso del navegador web previamente denegada", "notifications.permission_denied": "Las notificaciones de escritorio no están disponibles, debido a una solicitud de permiso del navegador web previamente denegada",
"notifications.permission_denied_alert": "No se pueden habilitar las notificaciones de escritorio, ya que el permiso del navegador fue denegado antes", "notifications.permission_denied_alert": "No se pueden habilitar las notificaciones de escritorio, ya que el permiso del navegador fue denegado antes",
"notifications.permission_required": "Las notificaciones de escritorio no están disponibles porque no se concedió el permiso requerido.", "notifications.permission_required": "Las notificaciones de escritorio no están disponibles porque no se concedió el permiso requerido.",
"notifications.policy.filter_limited_accounts_hint": "Limitada por los moderadores del servidor",
"notifications.policy.filter_limited_accounts_title": "Cuentas moderadas",
"notifications.policy.filter_new_accounts.hint": "Creada hace {days, plural, one {un día} other {# días}}", "notifications.policy.filter_new_accounts.hint": "Creada hace {days, plural, one {un día} other {# días}}",
"notifications.policy.filter_new_accounts_title": "Nuevas cuentas", "notifications.policy.filter_new_accounts_title": "Nuevas cuentas",
"notifications.policy.filter_not_followers_hint": "Incluyendo cuentas que te han estado siguiendo menos de {days, plural, one {un día} other {# días}}", "notifications.policy.filter_not_followers_hint": "Incluyendo cuentas que te han estado siguiendo menos de {days, plural, one {un día} other {# días}}",

View file

@ -545,6 +545,8 @@
"notifications.permission_denied": "Työpöytäilmoitukset eivät ole käytettävissä, koska selaimen käyttöoikeuspyyntö on aiemmin evätty", "notifications.permission_denied": "Työpöytäilmoitukset eivät ole käytettävissä, koska selaimen käyttöoikeuspyyntö on aiemmin evätty",
"notifications.permission_denied_alert": "Työpöytäilmoituksia ei voi ottaa käyttöön, koska selaimen käyttöoikeus on aiemmin evätty", "notifications.permission_denied_alert": "Työpöytäilmoituksia ei voi ottaa käyttöön, koska selaimen käyttöoikeus on aiemmin evätty",
"notifications.permission_required": "Työpöytäilmoitukset eivät ole käytettävissä, koska siihen tarvittavaa käyttöoikeutta ei ole myönnetty.", "notifications.permission_required": "Työpöytäilmoitukset eivät ole käytettävissä, koska siihen tarvittavaa käyttöoikeutta ei ole myönnetty.",
"notifications.policy.filter_limited_accounts_hint": "Palvelimen moderaattorien rajoittamat",
"notifications.policy.filter_limited_accounts_title": "Moderoidut tilit",
"notifications.policy.filter_new_accounts.hint": "Luotu {days, plural, one {viime päivän} other {viimeisen # päivän}} aikana", "notifications.policy.filter_new_accounts.hint": "Luotu {days, plural, one {viime päivän} other {viimeisen # päivän}} aikana",
"notifications.policy.filter_new_accounts_title": "Uudet tilit", "notifications.policy.filter_new_accounts_title": "Uudet tilit",
"notifications.policy.filter_not_followers_hint": "Mukaan lukien alle {days, plural, one {päivän} other {# päivää}} sinua seuranneet", "notifications.policy.filter_not_followers_hint": "Mukaan lukien alle {days, plural, one {päivän} other {# päivää}} sinua seuranneet",

View file

@ -75,8 +75,9 @@
"block_modal.show_less": "Ssken-d drus", "block_modal.show_less": "Ssken-d drus",
"block_modal.show_more": "Ssken-d ugar", "block_modal.show_more": "Ssken-d ugar",
"block_modal.they_cant_mention": "Ur zmiren ad k·m-id-bedren, ur zmiren ad k·m-ḍefren.", "block_modal.they_cant_mention": "Ur zmiren ad k·m-id-bedren, ur zmiren ad k·m-ḍefren.",
"block_modal.they_cant_see_posts": "Ur zmiren ad walin tisufaɣ-nwen, ur tettwalim tid-nsen.", "block_modal.they_cant_see_posts": "Ur yezmir ad wali tisuffaɣ-ik·im, ur tettwaliḍ tidak-is.",
"block_modal.title": "Sewḥel aseqdac ?", "block_modal.title": "Sewḥel aseqdac ?",
"block_modal.you_wont_see_mentions": "Ur tezmireḍ ara ad twaliḍ tisuffaɣ anda d-yettwabdar.",
"boost_modal.combo": "Tzemreḍ ad tsiteḍ ɣef {combo} akken ad tzegleḍ aya tikelt i d-iteddun", "boost_modal.combo": "Tzemreḍ ad tsiteḍ ɣef {combo} akken ad tzegleḍ aya tikelt i d-iteddun",
"bundle_column_error.copy_stacktrace": "Nɣel tuccḍa n uneqqis", "bundle_column_error.copy_stacktrace": "Nɣel tuccḍa n uneqqis",
"bundle_column_error.error.title": "Uh, ala !", "bundle_column_error.error.title": "Uh, ala !",
@ -176,7 +177,9 @@
"dismissable_banner.explore_tags": "D wiyi i d ihacṭagen i d-yettawin tamyigawt deg web anmetti ass-a. Ihacṭagen i sseqdacen ugar n medden, εlayit d imezwura.", "dismissable_banner.explore_tags": "D wiyi i d ihacṭagen i d-yettawin tamyigawt deg web anmetti ass-a. Ihacṭagen i sseqdacen ugar n medden, εlayit d imezwura.",
"domain_block_modal.block": "Sewḥel aqeddac", "domain_block_modal.block": "Sewḥel aqeddac",
"domain_block_modal.they_cant_follow": "Yiwen ur yezmir ad k·m-id-yeḍfer seg uqeddac-a.", "domain_block_modal.they_cant_follow": "Yiwen ur yezmir ad k·m-id-yeḍfer seg uqeddac-a.",
"domain_block_modal.they_wont_know": "Ur-d yettawi ara s lexbaṛ belli yettuseḥbes.",
"domain_block_modal.title": "Sewḥel taɣult?", "domain_block_modal.title": "Sewḥel taɣult?",
"domain_block_modal.you_wont_see_posts": "Ur tettuɣaleḍ ara ttwaliḍ tisuffaɣ neɣ ulɣuten n iseqdacen n uqeddac-a.",
"domain_pill.activitypub_like_language": "ActivityPub am tutlayt yettmeslay Mastodon d izeḍwan inmettiyen nniḍen.", "domain_pill.activitypub_like_language": "ActivityPub am tutlayt yettmeslay Mastodon d izeḍwan inmettiyen nniḍen.",
"domain_pill.server": "Aqeddac", "domain_pill.server": "Aqeddac",
"domain_pill.username": "Isem n useqdac", "domain_pill.username": "Isem n useqdac",
@ -348,9 +351,15 @@
"load_pending": "{count, plural, one {# n uferdis amaynut} other {# n yiferdisen imaynuten}}", "load_pending": "{count, plural, one {# n uferdis amaynut} other {# n yiferdisen imaynuten}}",
"loading_indicator.label": "Yessalay-d …", "loading_indicator.label": "Yessalay-d …",
"media_gallery.toggle_visible": "{number, plural, one {Ffer tugna} other {Ffer tugniwin}}", "media_gallery.toggle_visible": "{number, plural, one {Ffer tugna} other {Ffer tugniwin}}",
"mute_modal.hide_from_notifications": "Ffer-it deg ulɣuten",
"mute_modal.hide_options": "Ffer tinefrunin", "mute_modal.hide_options": "Ffer tinefrunin",
"mute_modal.indefinite": "Alamma ssnesreɣ asgugem fell-as",
"mute_modal.show_options": "Sken-d tinefrunin", "mute_modal.show_options": "Sken-d tinefrunin",
"mute_modal.title": "Sgugem aseqdac?", "mute_modal.they_can_mention_and_follow": "Yezmer ad k·m-id-yebder, ad k·m-yeḍfer, maca ur t-tettwaliḍt ara.",
"mute_modal.they_wont_know": "Ur yezmir ara ad iẓer dakken tesgugmeṭ.",
"mute_modal.title": "Asgugem n useqdac?",
"mute_modal.you_wont_see_mentions": "Ur tezmireḍ ara ad twaliḍ tisuffaɣ anda d-yettwabdar.",
"mute_modal.you_wont_see_posts": "Yezmer ad yettwali tisuffaɣ-ik·im, maca ur tettwaliḍ ara tidak-is.",
"navigation_bar.about": "Ɣef", "navigation_bar.about": "Ɣef",
"navigation_bar.advanced_interface": "Ldi deg ugrudem n web leqqayen", "navigation_bar.advanced_interface": "Ldi deg ugrudem n web leqqayen",
"navigation_bar.blocks": "Iseqdacen yettusḥebsen", "navigation_bar.blocks": "Iseqdacen yettusḥebsen",

View file

@ -545,6 +545,8 @@
"notifications.permission_denied": "권한이 거부되었기 때문에 데스크탑 알림을 활성화할 수 없음", "notifications.permission_denied": "권한이 거부되었기 때문에 데스크탑 알림을 활성화할 수 없음",
"notifications.permission_denied_alert": "이전에 브라우저 권한이 거부되었기 때문에, 데스크탑 알림이 활성화 될 수 없습니다.", "notifications.permission_denied_alert": "이전에 브라우저 권한이 거부되었기 때문에, 데스크탑 알림이 활성화 될 수 없습니다.",
"notifications.permission_required": "필요한 권한이 승인되지 않아 데스크탑 알림을 사용할 수 없습니다.", "notifications.permission_required": "필요한 권한이 승인되지 않아 데스크탑 알림을 사용할 수 없습니다.",
"notifications.policy.filter_limited_accounts_hint": "서버 중재자에 의해 제한됨",
"notifications.policy.filter_limited_accounts_title": "중재된 계정",
"notifications.policy.filter_new_accounts.hint": "{days, plural, one {하루} other {#일}} 안에 만들어진", "notifications.policy.filter_new_accounts.hint": "{days, plural, one {하루} other {#일}} 안에 만들어진",
"notifications.policy.filter_new_accounts_title": "새 계정", "notifications.policy.filter_new_accounts_title": "새 계정",
"notifications.policy.filter_not_followers_hint": "나를 팔로우 한 지 {days, plural, other {# 일}}이 되지 않은 사람들을 포함", "notifications.policy.filter_not_followers_hint": "나를 팔로우 한 지 {days, plural, other {# 일}}이 되지 않은 사람들을 포함",

View file

@ -610,7 +610,7 @@
"poll_button.remove_poll": "移除投票", "poll_button.remove_poll": "移除投票",
"privacy.change": "设置嘟文的可见范围", "privacy.change": "设置嘟文的可见范围",
"privacy.direct.long": "帖子中提到的每个人", "privacy.direct.long": "帖子中提到的每个人",
"privacy.direct.short": "具体的人", "privacy.direct.short": "特定的人",
"privacy.private.long": "仅限您的关注者", "privacy.private.long": "仅限您的关注者",
"privacy.private.short": "关注者", "privacy.private.short": "关注者",
"privacy.public.long": "所有 Mastodon 内外的人", "privacy.public.long": "所有 Mastodon 内外的人",

View file

@ -474,8 +474,11 @@ export const notificationGroupsReducer = createReducer<NotificationGroupsState>(
state.lastReadId, state.lastReadId,
action.payload.markers.notifications.last_read_id, action.payload.markers.notifications.last_read_id,
) < 0 ) < 0
) ) {
state.lastReadId = action.payload.markers.notifications.last_read_id; state.lastReadId = action.payload.markers.notifications.last_read_id;
state.readMarkerId =
action.payload.markers.notifications.last_read_id;
}
}) })
.addCase(mountNotifications, (state) => { .addCase(mountNotifications, (state) => {
state.mounted += 1; state.mounted += 1;

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M400-240 160-480l240-240 56 58-142 142h486v80H314l142 142-56 58Z"/></svg>

After

Width:  |  Height:  |  Size: 189 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M280-280q17 0 28.5-11.5T320-320q0-17-11.5-28.5T280-360q-17 0-28.5 11.5T240-320q0 17 11.5 28.5T280-280Zm-40-160h80v-240h-80v240Zm200 160h280v-80H440v80Zm0-160h280v-80H440v80Zm0-160h280v-80H440v80ZM160-120q-33 0-56.5-23.5T80-200v-560q0-33 23.5-56.5T160-840h640q33 0 56.5 23.5T880-760v560q0 33-23.5 56.5T800-120H160Zm0-80h640v-560H160v560Zm0 0v-560 560Z"/></svg>

After

Width:  |  Height:  |  Size: 475 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M838-65 720-183v89h-80v-226h226v80h-90l118 118-56 57ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 20-2 40t-6 40h-82q5-20 7.5-40t2.5-40q0-20-2.5-40t-7.5-40H654q3 20 4.5 40t1.5 40q0 20-1.5 40t-4.5 40h-80q3-20 4.5-40t1.5-40q0-20-1.5-40t-4.5-40H386q-3 20-4.5 40t-1.5 40q0 20 1.5 40t4.5 40h134v80H404q12 43 31 82.5t45 75.5q20 0 40-2.5t40-4.5v82q-20 2-40 4.5T480-80ZM170-400h136q-3-20-4.5-40t-1.5-40q0-20 1.5-40t4.5-40H170q-5 20-7.5 40t-2.5 40q0 20 2.5 40t7.5 40Zm34-240h118q9-37 22.5-72.5T376-782q-55 18-99 54.5T204-640Zm172 462q-18-34-31.5-69.5T322-320H204q29 51 73 87.5t99 54.5Zm28-462h152q-12-43-31-82.5T480-798q-26 36-45 75.5T404-640Zm234 0h118q-29-51-73-87.5T584-782q18 34 31.5 69.5T638-640Z"/></svg>

After

Width:  |  Height:  |  Size: 917 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M80-80v-720q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v480q0 33-23.5 56.5T800-240H240L80-80Zm126-240h594v-480H160v525l46-45Zm-46 0v-480 480Z"/></svg>

After

Width:  |  Height:  |  Size: 272 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M260-160q-91 0-155.5-63T40-377q0-78 47-139t123-78q25-92 100-149t170-57q117 0 198.5 81.5T760-520q69 8 114.5 59.5T920-340q0 75-52.5 127.5T740-160H260Zm0-80h480q42 0 71-29t29-71q0-42-29-71t-71-29h-60v-80q0-83-58.5-141.5T480-720q-83 0-141.5 58.5T280-520h-20q-58 0-99 41t-41 99q0 58 41 99t99 41Zm220-240Z"/></svg>

After

Width:  |  Height:  |  Size: 424 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M260-160q-91 0-155.5-63T40-377q0-78 47-139t123-78q17-72 85-137t145-65q33 0 56.5 23.5T520-716v242l64-62 56 56-160 160-160-160 56-56 64 62v-242q-76 14-118 73.5T280-520h-20q-58 0-99 41t-41 99q0 58 41 99t99 41h480q42 0 71-29t29-71q0-42-29-71t-71-29h-60v-80q0-48-22-89.5T600-680v-93q74 35 117 103.5T760-520q69 8 114.5 59.5T920-340q0 75-52.5 127.5T740-160H260Zm220-358Z"/></svg>

After

Width:  |  Height:  |  Size: 488 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M160-160v-80h109q-51-44-80-106t-29-134q0-112 68-197.5T400-790v84q-70 25-115 86.5T240-480q0 54 21.5 99.5T320-302v-98h80v240H160Zm440 0q-50 0-85-35t-35-85q0-48 33-82.5t81-36.5q17-36 50.5-58.5T720-480q53 0 91.5 34.5T858-360q42 0 72 29t30 70q0 42-29 71.5T860-160H600Zm116-360q-7-41-27-76t-49-62v98h-80v-240h240v80H691q43 38 70.5 89T797-520h-81ZM600-240h260q8 0 14-6t6-14q0-8-6-14t-14-6h-70v-50q0-29-20.5-49.5T720-400q-29 0-49.5 20.5T650-330v10h-50q-17 0-28.5 11.5T560-280q0 17 11.5 28.5T600-240Zm120-80Z"/></svg>

After

Width:  |  Height:  |  Size: 624 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M260-160q-91 0-155.5-63T40-377q0-78 47-139t123-78q25-92 100-149t170-57q117 0 198.5 81.5T760-520q69 8 114.5 59.5T920-340q0 75-52.5 127.5T740-160H520q-33 0-56.5-23.5T440-240v-206l-64 62-56-56 160-160 160 160-56 56-64-62v206h220q42 0 71-29t29-71q0-42-29-71t-71-29h-60v-80q0-83-58.5-141.5T480-720q-83 0-141.5 58.5T280-520h-20q-58 0-99 41t-41 99q0 58 41 99t99 41h100v80H260Zm220-280Z"/></svg>

After

Width:  |  Height:  |  Size: 503 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M320-240 80-480l240-240 57 57-184 184 183 183-56 56Zm320 0-57-57 184-184-183-183 56-56 240 240-240 240Z"/></svg>

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 228 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M240-400h480v-80H240v80Zm0-120h480v-80H240v80Zm0-120h480v-80H240v80ZM880-80 720-240H160q-33 0-56.5-23.5T80-320v-480q0-33 23.5-56.5T160-880h640q33 0 56.5 23.5T880-800v720ZM160-320h594l46 45v-525H160v480Zm0 0v-480 480Z"/></svg>

After

Width:  |  Height:  |  Size: 341 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M40-120v-80h880v80H40Zm120-120q-33 0-56.5-23.5T80-320v-440q0-33 23.5-56.5T160-840h640q33 0 56.5 23.5T880-760v440q0 33-23.5 56.5T800-240H160Zm0-80h640v-440H160v440Zm0 0v-440 440Z"/></svg>

After

Width:  |  Height:  |  Size: 302 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M560-520h280v-200H560v200Zm140-50-100-70v-40l100 70 100-70v40l-100 70ZM80-120q-33 0-56.5-23.5T0-200v-560q0-33 23.5-56.5T80-840h800q33 0 56.5 23.5T960-760v560q0 33-23.5 56.5T880-120H80Zm556-80h244v-560H80v560h4q42-75 116-117.5T360-360q86 0 160 42.5T636-200ZM360-400q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35ZM182-200h356q-34-38-80.5-59T360-280q-51 0-97 21t-81 59Zm178-280q-17 0-28.5-11.5T320-520q0-17 11.5-28.5T360-560q17 0 28.5 11.5T400-520q0 17-11.5 28.5T360-480Zm120 0Z"/></svg>

After

Width:  |  Height:  |  Size: 625 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-120q-151 0-255.5-46.5T120-280v-400q0-66 105.5-113T480-840q149 0 254.5 47T840-680v400q0 67-104.5 113.5T480-120Zm0-479q89 0 179-25.5T760-679q-11-29-100.5-55T480-760q-91 0-178.5 25.5T200-679q14 30 101.5 55T480-599Zm0 199q42 0 81-4t74.5-11.5q35.5-7.5 67-18.5t57.5-25v-120q-26 14-57.5 25t-67 18.5Q600-528 561-524t-81 4q-42 0-82-4t-75.5-11.5Q287-543 256-554t-56-25v120q25 14 56 25t66.5 18.5Q358-408 398-404t82 4Zm0 200q46 0 93.5-7t87.5-18.5q40-11.5 67-26t32-29.5v-98q-26 14-57.5 25t-67 18.5Q600-328 561-324t-81 4q-42 0-82-4t-75.5-11.5Q287-343 256-354t-56-25v99q5 15 31.5 29t66.5 25.5q40 11.5 88 18.5t94 7Z"/></svg>

After

Width:  |  Height:  |  Size: 729 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-120 80-600l120-240h560l120 240-400 480Zm-95-520h190l-60-120h-70l-60 120Zm55 347v-267H218l222 267Zm80 0 222-267H520v267Zm144-347h106l-60-120H604l60 120Zm-474 0h106l60-120H250l-60 120Z"/></svg>

After

Width:  |  Height:  |  Size: 312 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M440-160q-17 0-28.5-11.5T400-200v-240L168-736q-15-20-4.5-42t36.5-22h560q26 0 36.5 22t-4.5 42L560-440v240q0 17-11.5 28.5T520-160h-80Zm40-308 198-252H282l198 252Zm0 0Z"/></svg>

After

Width:  |  Height:  |  Size: 290 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M0-240v-63q0-43 44-70t116-27q13 0 25 .5t23 2.5q-14 21-21 44t-7 48v65H0Zm240 0v-65q0-32 17.5-58.5T307-410q32-20 76.5-30t96.5-10q53 0 97.5 10t76.5 30q32 20 49 46.5t17 58.5v65H240Zm540 0v-65q0-26-6.5-49T754-397q11-2 22.5-2.5t23.5-.5q72 0 116 26.5t44 70.5v63H780Zm-455-80h311q-10-20-55.5-35T480-370q-55 0-100.5 15T325-320ZM160-440q-33 0-56.5-23.5T80-520q0-34 23.5-57t56.5-23q34 0 57 23t23 57q0 33-23 56.5T160-440Zm640 0q-33 0-56.5-23.5T720-520q0-34 23.5-57t56.5-23q34 0 57 23t23 57q0 33-23 56.5T800-440Zm-320-40q-50 0-85-35t-35-85q0-51 35-85.5t85-34.5q51 0 85.5 34.5T600-600q0 50-34.5 85T480-480Zm0-80q17 0 28.5-11.5T520-600q0-17-11.5-28.5T480-640q-17 0-28.5 11.5T440-600q0 17 11.5 28.5T480-560Zm1 240Zm-1-280Z"/></svg>

After

Width:  |  Height:  |  Size: 831 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="m791-55-91-91q-49 32-104.5 49T480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-60 17-115.5T146-700l-91-91 57-57 736 736-57 57ZM480-160q43 0 83.5-11t78.5-33L204-642q-22 38-33 78.5T160-480q0 133 93.5 226.5T480-160Zm334-100-58-58q22-38 33-78.5t11-83.5q0-133-93.5-226.5T480-800q-43 0-83.5 11T318-756l-58-58q49-32 104.5-49T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 60-17 115.5T814-260ZM537-537ZM423-423Z"/></svg>

After

Width:  |  Height:  |  Size: 542 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M320-160h320v-120q0-66-47-113t-113-47q-66 0-113 47t-47 113v120Zm160-360q66 0 113-47t47-113v-120H320v120q0 66 47 113t113 47ZM160-80v-80h80v-120q0-61 28.5-114.5T348-480q-51-32-79.5-85.5T240-680v-120h-80v-80h640v80h-80v120q0 61-28.5 114.5T612-480q51 32 79.5 85.5T720-280v120h80v80H160Zm320-80Zm0-640Z"/></svg>

After

Width:  |  Height:  |  Size: 422 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h560q33 0 56.5 23.5T840-760v560q0 33-23.5 56.5T760-120H200Zm0-80h560v-120H640q-30 38-71.5 59T480-240q-47 0-88.5-21T320-320H200v120Zm280-120q38 0 69-22t43-58h168v-360H200v360h168q12 36 43 58t69 22ZM200-200h560-560Z"/></svg>

After

Width:  |  Height:  |  Size: 398 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-200 240-440l56-56 184 183 184-183 56 56-240 240Zm0-240L240-680l56-56 184 183 184-183 56 56-240 240Z"/></svg>

After

Width:  |  Height:  |  Size: 229 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M280-600v-80h560v80H280Zm0 160v-80h560v80H280Zm0 160v-80h560v80H280ZM160-600q-17 0-28.5-11.5T120-640q0-17 11.5-28.5T160-680q17 0 28.5 11.5T200-640q0 17-11.5 28.5T160-600Zm0 160q-17 0-28.5-11.5T120-480q0-17 11.5-28.5T160-520q17 0 28.5 11.5T200-480q0 17-11.5 28.5T160-440Zm0 160q-17 0-28.5-11.5T120-320q0-17 11.5-28.5T160-360q17 0 28.5 11.5T200-320q0 17-11.5 28.5T160-280Z"/></svg>

After

Width:  |  Height:  |  Size: 495 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm320-280L160-640v400h640v-400L480-440Zm0-80 320-200H160l320 200ZM160-640v-80 480-400Z"/></svg>

Before

Width:  |  Height:  |  Size: 309 B

After

Width:  |  Height:  |  Size: 328 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m234-480-12-60q-12-5-22.5-10.5T178-564l-58 18-40-68 46-40q-2-13-2-26t2-26l-46-40 40-68 58 18q11-8 21.5-13.5T222-820l12-60h80l12 60q12 5 22.5 10.5T370-796l58-18 40 68-46 40q2 13 2 26t-2 26l46 40-40 68-58-18q-11 8-21.5 13.5T326-540l-12 60h-80Zm40-120q33 0 56.5-23.5T354-680q0-33-23.5-56.5T274-760q-33 0-56.5 23.5T194-680q0 33 23.5 56.5T274-600ZM592-40l-18-84q-17-6-31.5-14.5T514-158l-80 26-56-96 64-56q-2-18-2-36t2-36l-64-56 56-96 80 26q14-11 28.5-19.5T574-516l18-84h112l18 84q17 6 31.5 14.5T782-482l80-26 56 96-64 56q2 18 2 36t-2 36l64 56-56 96-80-26q-14 11-28.5 19.5T722-124l-18 84H592Zm56-160q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="m234-480-12-60q-12-5-22.5-10.5T178-564l-58 18-40-68 46-40q-2-13-2-26t2-26l-46-40 40-68 58 18q11-8 21.5-13.5T222-820l12-60h80l12 60q12 5 22.5 10.5T370-796l58-18 40 68-46 40q2 13 2 26t-2 26l46 40-40 68-58-18q-11 8-21.5 13.5T326-540l-12 60h-80Zm40-120q33 0 56.5-23.5T354-680q0-33-23.5-56.5T274-760q-33 0-56.5 23.5T194-680q0 33 23.5 56.5T274-600ZM592-40l-18-84q-17-6-31.5-14.5T514-158l-80 26-56-96 64-56q-2-18-2-36t2-36l-64-56 56-96 80 26q14-11 28.5-19.5T574-516l18-84h112l18 84q17 6 31.5 14.5T782-482l80-26 56 96-64 56q2 18 2 36t-2 36l64 56-56 96-80-26q-14 11-28.5 19.5T722-124l-18 84H592Zm56-160q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35Z"/></svg>

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 790 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M620-520q25 0 42.5-17.5T680-580q0-25-17.5-42.5T620-640q-25 0-42.5 17.5T560-580q0 25 17.5 42.5T620-520Zm-280 0q25 0 42.5-17.5T400-580q0-25-17.5-42.5T340-640q-25 0-42.5 17.5T280-580q0 25 17.5 42.5T340-520Zm140 260q68 0 123.5-38.5T684-400H276q25 63 80.5 101.5T480-260Zm0 180q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Z"/></svg>

After

Width:  |  Height:  |  Size: 675 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-260q75 0 127.5-52.5T660-440q0-75-52.5-127.5T480-620q-75 0-127.5 52.5T300-440q0 75 52.5 127.5T480-260Zm0-80q-42 0-71-29t-29-71q0-42 29-71t71-29q42 0 71 29t29 71q0 42-29 71t-71 29ZM160-120q-33 0-56.5-23.5T80-200v-480q0-33 23.5-56.5T160-760h126l74-80h240l74 80h126q33 0 56.5 23.5T880-680v480q0 33-23.5 56.5T800-120H160Zm0-80h640v-480H638l-73-80H395l-73 80H160v480Zm320-240Z"/></svg>

After

Width:  |  Height:  |  Size: 500 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M460-200h40v-74l140-140v-186H320v186l140 140v74Zm-80 80v-120L240-380v-220q0-33 23.5-56.5T320-680h40l-40 40v-200h80v160h160v-160h80v200l-40-40h40q33 0 56.5 23.5T720-600v220L580-240v120H380Zm100-280Z"/></svg>

After

Width:  |  Height:  |  Size: 322 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M380-120v-120L240-380v-220q0-24 11-45t32-32l77 77h-40v186l140 140v74h40v-74l37-37L56-792l56-56 736 736-56 56-198-198-14 14v120H380Zm306-268-46-46v-166H474L320-754v-86h80v160h160v-160h80v200l-40-40h40q33 0 56.5 23.5T720-600v178l-34 34ZM558-516Zm-130 97Z"/></svg>

After

Width:  |  Height:  |  Size: 377 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-280q83 0 141.5-58.5T680-480q0-83-58.5-141.5T480-680q-83 0-141.5 58.5T280-480q0 83 58.5 141.5T480-280Zm0 200q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>

After

Width:  |  Height:  |  Size: 515 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-80q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Zm0-320Z"/></svg>

After

Width:  |  Height:  |  Size: 410 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-280q17 0 28.5-11.5T520-320q0-17-11.5-28.5T480-360q-17 0-28.5 11.5T440-320q0 17 11.5 28.5T480-280Zm-40-160h80v-240h-80v240ZM330-120 120-330v-300l210-210h300l210 210v300L630-120H330Zm34-80h232l164-164v-232L596-760H364L200-596v232l164 164Zm116-280Z"/></svg>

After

Width:  |  Height:  |  Size: 375 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M480-280q83 0 141.5-58.5T680-480q0-83-58.5-141.5T480-680q-83 0-141.5 58.5T280-480q0 83 58.5 141.5T480-280Zm66-106-86-86v-128h40v112l74 74-28 28ZM480-80q-139-35-229.5-159.5T160-516v-244l320-120 320 120v244q0 152-90.5 276.5T480-80Zm0-84q104-33 172-132t68-220v-189l-240-90-240 90v189q0 121 68 220t172 132Zm0-316Z"/></svg>

After

Width:  |  Height:  |  Size: 434 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M840-680v480q0 33-23.5 56.5T760-120H200q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h480l160 160Zm-80 34L646-760H200v560h560v-446ZM480-240q50 0 85-35t35-85q0-50-35-85t-85-35q-50 0-85 35t-35 85q0 50 35 85t85 35ZM240-560h360v-160H240v160Zm-40-86v446-560 114Z"/></svg>

After

Width:  |  Height:  |  Size: 389 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M418-340q24 24 62 23.5t56-27.5l224-336-336 224q-27 18-28.5 55t22.5 61Zm62-460q59 0 113.5 16.5T696-734l-76 48q-33-17-68.5-25.5T480-720q-133 0-226.5 93.5T160-400q0 42 11.5 83t32.5 77h552q23-38 33.5-79t10.5-85q0-36-8.5-70T766-540l48-76q30 47 47.5 100T880-406q1 57-13 109t-41 99q-11 18-30 28t-40 10H204q-21 0-40-10t-30-28q-26-45-40-95.5T80-400q0-83 31.5-155.5t86-127Q252-737 325-768.5T480-800Zm7 313Z"/></svg>

After

Width:  |  Height:  |  Size: 521 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="M280-120 80-320l200-200 57 56-104 104h607v80H233l104 104-57 56Zm400-320-57-56 104-104H120v-80h607L623-784l57-56 200 200-200 200Z"/></svg>

After

Width:  |  Height:  |  Size: 253 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#5f6368"><path d="m136-240-56-56 296-298 160 160 208-206H640v-80h240v240h-80v-104L536-320 376-480 136-240Z"/></svg>

After

Width:  |  Height:  |  Size: 213 B

View file

@ -496,11 +496,11 @@ html {
.compose-form .autosuggest-textarea__textarea, .compose-form .autosuggest-textarea__textarea,
.compose-form__highlightable, .compose-form__highlightable,
.autosuggest-textarea__suggestions,
.search__input, .search__input,
.search__popout, .search__popout,
.emoji-mart-search input, .emoji-mart-search input,
.language-dropdown__dropdown .emoji-mart-search input, .language-dropdown__dropdown .emoji-mart-search input,
// .strike-card,
.poll__option input[type='text'] { .poll__option input[type='text'] {
background: darken($ui-base-color, 10%); background: darken($ui-base-color, 10%);
} }

View file

@ -7,7 +7,7 @@
background: $ui-base-color; background: $ui-base-color;
color: $darker-text-color; color: $darker-text-color;
border-radius: 4px; border-radius: 4px;
border: 1px solid lighten($ui-base-color, 8%); border: 1px solid var(--background-border-color);
font-size: 17px; font-size: 17px;
line-height: normal; line-height: normal;
margin: 0; margin: 0;

View file

@ -13,7 +13,7 @@ $content-width: 840px;
.icon { .icon {
width: 16px; width: 16px;
height: 16px; height: 16px;
vertical-align: middle; vertical-align: top;
margin: 0 2px; margin: 0 2px;
} }

View file

@ -403,7 +403,7 @@ body > [data-popper-placement] {
&__suggestions { &__suggestions {
box-shadow: var(--dropdown-shadow); box-shadow: var(--dropdown-shadow);
background: $ui-base-color; background: $ui-base-color;
border: 1px solid lighten($ui-base-color, 14%); border: 1px solid var(--background-border-color);
border-radius: 0 0 4px 4px; border-radius: 0 0 4px 4px;
color: $secondary-text-color; color: $secondary-text-color;
font-size: 14px; font-size: 14px;
@ -3086,11 +3086,6 @@ $ui-header-logo-wordmark-width: 99px;
.explore__search-header { .explore__search-header {
display: flex; display: flex;
} }
.explore__search-results {
border: 0;
border-radius: 0;
}
} }
.icon-with-badge { .icon-with-badge {
@ -8789,10 +8784,13 @@ noscript {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@media screen and (min-width: $no-gap-breakpoint) {
border: 1px solid var(--background-border-color); border: 1px solid var(--background-border-color);
border-top: 0; border-top: 0;
border-bottom-left-radius: 4px; border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
}
} }
.story { .story {

View file

@ -441,11 +441,6 @@ code {
border-radius: 4px; border-radius: 4px;
padding: 10px 16px; padding: 10px 16px;
&::placeholder {
color: $dark-text-color;
opacity: 1;
}
&:invalid { &:invalid {
box-shadow: none; box-shadow: none;
} }
@ -607,8 +602,7 @@ code {
inset-inline-end: 3px; inset-inline-end: 3px;
top: 1px; top: 1px;
padding: 10px; padding: 10px;
padding-bottom: 9px; font-size: 14px;
font-size: 16px;
color: $dark-text-color; color: $dark-text-color;
font-family: inherit; font-family: inherit;
pointer-events: none; pointer-events: none;
@ -626,11 +620,6 @@ code {
inset-inline-end: 0; inset-inline-end: 0;
bottom: 1px; bottom: 1px;
width: 5px; width: 5px;
background-image: linear-gradient(
to right,
rgba(darken($ui-base-color, 10%), 0),
darken($ui-base-color, 10%)
);
} }
} }
} }

View file

@ -35,16 +35,6 @@ body.rtl {
direction: rtl; direction: rtl;
} }
.simple_form .label_input__append {
&::after {
background-image: linear-gradient(
to left,
rgba(darken($ui-base-color, 10%), 0),
darken($ui-base-color, 10%)
);
}
}
.simple_form select { .simple_form select {
background: $ui-base-color background: $ui-base-color
url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>") url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 12%))}'/></svg>")

View file

@ -273,8 +273,8 @@ a.table-action-link {
} }
} }
&:nth-child(even) { &:last-child {
background: var(--background-color); border-radius: 0 0 4px 4px;
} }
&__content { &__content {

View file

@ -217,7 +217,7 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
border: 1px solid lighten($ui-base-color, 8%); border: 1px solid var(--background-border-color);
border-radius: 4px; border-radius: 4px;
padding: 15px; padding: 15px;
text-decoration: none; text-decoration: none;

View file

@ -49,15 +49,15 @@
= check_box_tag :batch_checkbox_all, nil, false = check_box_tag :batch_checkbox_all, nil, false
.batch-table__toolbar__actions .batch-table__toolbar__actions
- if params[:local] == '1' - if params[:local] == '1'
= f.button safe_join([fa_icon('save'), t('generic.save_changes')]), name: :update, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([material_symbol('save'), t('generic.save_changes')]), name: :update, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
= f.button safe_join([material_symbol('visibility'), t('admin.custom_emojis.list')]), name: :list, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([material_symbol('visibility'), t('admin.custom_emojis.list')]), name: :list, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
= f.button safe_join([material_symbol('visibility_off'), t('admin.custom_emojis.unlist')]), name: :unlist, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([material_symbol('visibility_off'), t('admin.custom_emojis.unlist')]), name: :unlist, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
= f.button safe_join([fa_icon('power-off'), t('admin.custom_emojis.enable')]), name: :enable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([material_symbol('radio_button_checked'), t('admin.custom_emojis.enable')]), name: :enable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
= f.button safe_join([fa_icon('power-off'), t('admin.custom_emojis.disable')]), name: :disable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([material_symbol('radio_button_unchecked'), t('admin.custom_emojis.disable')]), name: :disable, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }
- if can?(:destroy, :custom_emoji) - if can?(:destroy, :custom_emoji)
= f.button safe_join([material_symbol('close'), t('admin.custom_emojis.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') } = f.button safe_join([material_symbol('close'), t('admin.custom_emojis.delete')]), name: :delete, class: 'table-action-link', type: :submit, data: { confirm: t('admin.reports.are_you_sure') }

View file

@ -1,7 +1,7 @@
.directory__tag .directory__tag
= link_to admin_instance_path(instance) do = link_to admin_instance_path(instance) do
%h4 %h4
= fa_icon 'warning fw', title: t('admin.instances.availability.warning') if instance.failing? = material_symbol 'warning', title: t('admin.instances.availability.warning') if instance.failing?
= instance.domain = instance.domain
%small %small

View file

@ -8,7 +8,7 @@
&nbsp; &nbsp;
= t 'admin.relays.enabled' = t 'admin.relays.enabled'
- elsif relay.pending? - elsif relay.pending?
= fa_icon('hourglass') = material_symbol('hourglass')
&nbsp; &nbsp;
= t 'admin.relays.pending' = t 'admin.relays.pending'
- else - else

View file

@ -30,7 +30,7 @@
%span.negative-hint= t('admin.statuses.deleted') %span.negative-hint= t('admin.statuses.deleted')
· ·
- if status.reblog? - if status.reblog?
= fa_icon('retweet fw') = material_symbol('repeat_active')
= t('statuses.boosted_from_html', acct_link: admin_account_inline_link_to(status.proper.account)) = t('statuses.boosted_from_html', acct_link: admin_account_inline_link_to(status.proper.account))
- else - else
= fa_visibility_icon(status) = fa_visibility_icon(status)

View file

@ -61,11 +61,11 @@
.one-line= report.comment.presence || t('admin.reports.comment.none') .one-line= report.comment.presence || t('admin.reports.comment.none')
%span.report-card__summary__item__content__icon{ title: t('admin.accounts.statuses') } %span.report-card__summary__item__content__icon{ title: t('admin.accounts.statuses') }
= fa_icon('comment') = material_symbol('comment')
= report.status_ids.size = report.status_ids.size
%span.report-card__summary__item__content__icon{ title: t('admin.accounts.media_attachments') } %span.report-card__summary__item__content__icon{ title: t('admin.accounts.media_attachments') }
= fa_icon('camera') = material_symbol('photo_camera')
= report.media_attachments_count = report.media_attachments_count
- if report.forwarded? - if report.forwarded?

View file

@ -35,7 +35,7 @@
= t 'admin.reports.statuses' = t 'admin.reports.statuses'
%small.section-skip-link %small.section-skip-link
= link_to '#actions' do = link_to '#actions' do
= fa_icon 'angle-double-down' = material_symbol 'keyboard_double_arrow_down'
= t('admin.reports.skip_to_actions') = t('admin.reports.skip_to_actions')
%p %p

View file

@ -38,7 +38,7 @@
- if @admin_settings.mascot.persisted? - if @admin_settings.mascot.persisted?
= image_tag @admin_settings.mascot.file.url, class: 'fields-group__thumbnail' = image_tag @admin_settings.mascot.file.url, class: 'fields-group__thumbnail'
= link_to admin_site_upload_path(@admin_settings.mascot), data: { method: :delete }, class: 'link-button link-button--destructive' do = link_to admin_site_upload_path(@admin_settings.mascot), data: { method: :delete }, class: 'link-button link-button--destructive' do
= fa_icon 'trash fw' = material_symbol 'delete'
= t('admin.site_uploads.delete') = t('admin.site_uploads.delete')
.actions .actions

View file

@ -37,7 +37,7 @@
- if @admin_settings.thumbnail.persisted? - if @admin_settings.thumbnail.persisted?
= image_tag @admin_settings.thumbnail.file.url(:'@1x'), class: 'fields-group__thumbnail' = image_tag @admin_settings.thumbnail.file.url(:'@1x'), class: 'fields-group__thumbnail'
= link_to admin_site_upload_path(@admin_settings.thumbnail), data: { method: :delete }, class: 'link-button link-button--destructive' do = link_to admin_site_upload_path(@admin_settings.thumbnail), data: { method: :delete }, class: 'link-button link-button--destructive' do
= fa_icon 'trash fw' = material_symbol 'delete'
= t('admin.site_uploads.delete') = t('admin.site_uploads.delete')
.fields-row .fields-row
@ -51,7 +51,7 @@
- if @admin_settings.favicon.persisted? - if @admin_settings.favicon.persisted?
= image_tag @admin_settings.favicon.file.url('48'), class: 'fields-group__thumbnail' = image_tag @admin_settings.favicon.file.url('48'), class: 'fields-group__thumbnail'
= link_to admin_site_upload_path(@admin_settings.favicon), data: { method: :delete }, class: 'link-button link-button--destructive' do = link_to admin_site_upload_path(@admin_settings.favicon), data: { method: :delete }, class: 'link-button link-button--destructive' do
= fa_icon 'trash fw' = material_symbol 'delete'
= t('admin.site_uploads.delete') = t('admin.site_uploads.delete')
.fields-row .fields-row
@ -65,7 +65,7 @@
- if @admin_settings.app_icon.persisted? - if @admin_settings.app_icon.persisted?
= image_tag @admin_settings.app_icon.file.url('48'), class: 'fields-group__thumbnail' = image_tag @admin_settings.app_icon.file.url('48'), class: 'fields-group__thumbnail'
= link_to admin_site_upload_path(@admin_settings.app_icon), data: { method: :delete }, class: 'link-button link-button--destructive' do = link_to admin_site_upload_path(@admin_settings.app_icon), data: { method: :delete }, class: 'link-button link-button--destructive' do
= fa_icon 'trash fw' = material_symbol 'delete'
= t('admin.site_uploads.delete') = t('admin.site_uploads.delete')
.actions .actions

View file

@ -1,10 +1,10 @@
.content__heading__tabs .content__heading__tabs
= render_navigation renderer: :links do |primary| = render_navigation renderer: :links do |primary|
:ruby :ruby
primary.item :branding, safe_join([fa_icon('pencil fw'), t('admin.settings.branding.title')]), admin_settings_branding_path primary.item :branding, safe_join([material_symbol('edit'), t('admin.settings.branding.title')]), admin_settings_branding_path
primary.item :about, safe_join([fa_icon('file-text fw'), t('admin.settings.about.title')]), admin_settings_about_path primary.item :about, safe_join([material_symbol('description'), t('admin.settings.about.title')]), admin_settings_about_path
primary.item :registrations, safe_join([material_symbol('group'), t('admin.settings.registrations.title')]), admin_settings_registrations_path primary.item :registrations, safe_join([material_symbol('group'), t('admin.settings.registrations.title')]), admin_settings_registrations_path
primary.item :discovery, safe_join([fa_icon('search fw'), t('admin.settings.discovery.title')]), admin_settings_discovery_path primary.item :discovery, safe_join([material_symbol('search'), t('admin.settings.discovery.title')]), admin_settings_discovery_path
primary.item :content_retention, safe_join([fa_icon('history fw'), t('admin.settings.content_retention.title')]), admin_settings_content_retention_path primary.item :content_retention, safe_join([material_symbol('history'), t('admin.settings.content_retention.title')]), admin_settings_content_retention_path
primary.item :appearance, safe_join([fa_icon('desktop fw'), t('admin.settings.appearance.title')]), admin_settings_appearance_path primary.item :appearance, safe_join([material_symbol('computer'), t('admin.settings.appearance.title')]), admin_settings_appearance_path
primary.item :other, safe_join([fa_icon('ellipsis-h fw'), t('admin.settings.other.title')]), admin_settings_other_path primary.item :other, safe_join([material_symbol('more_horiz'), t('admin.settings.other.title')]), admin_settings_other_path

View file

@ -33,7 +33,7 @@
= check_box_tag :batch_checkbox_all, nil, false = check_box_tag :batch_checkbox_all, nil, false
.batch-table__toolbar__actions .batch-table__toolbar__actions
- unless @statuses.empty? - unless @statuses.empty?
= f.button safe_join([fa_icon('flag'), t('admin.statuses.batch.report')]), = f.button safe_join([material_symbol('flag'), t('admin.statuses.batch.report')]),
class: 'table-action-link', class: 'table-action-link',
data: { confirm: t('admin.reports.are_you_sure') }, data: { confirm: t('admin.reports.are_you_sure') },
name: :report, name: :report,

View file

@ -1,6 +1,6 @@
.applications-list__item .applications-list__item
= link_to admin_webhook_path(webhook), class: 'announcements-list__item__title' do = link_to admin_webhook_path(webhook), class: 'announcements-list__item__title' do
= fa_icon 'inbox' = material_symbol 'inbox'
= webhook.url = webhook.url
.announcements-list__item__action-bar .announcements-list__item__action-bar

View file

@ -5,7 +5,7 @@
.content__heading__row .content__heading__row
%h2 %h2
%small %small
= fa_icon 'inbox' = material_symbol 'inbox'
= t('admin.webhooks.webhook') = t('admin.webhooks.webhook')
= @webhook.url = @webhook.url
.content__heading__actions .content__heading__actions

View file

@ -24,7 +24,7 @@
.directory__tag .directory__tag
%div %div
%h4 %h4
= fa_icon 'hashtag' = material_symbol 'tag'
= featured_tag.display_name = featured_tag.display_name
%small %small
- if featured_tag.last_status_at.nil? - if featured_tag.last_status_at.nil?

View file

@ -2,7 +2,7 @@
.log-entry__header .log-entry__header
.log-entry__avatar .log-entry__avatar
.indicator-icon{ class: login_activity.success? ? 'success' : 'failure' } .indicator-icon{ class: login_activity.success? ? 'success' : 'failure' }
= fa_icon login_activity.success? ? 'check' : 'times' = material_symbol login_activity.success? ? 'check' : 'close'
.log-entry__content .log-entry__content
.log-entry__title .log-entry__title
= login_activity_title(login_activity) = login_activity_title(login_activity)

View file

@ -43,7 +43,7 @@
= image_tag @account.avatar.url, class: 'fields-group__thumbnail', id: 'account_avatar-preview' = image_tag @account.avatar.url, class: 'fields-group__thumbnail', id: 'account_avatar-preview'
- if @account.avatar.present? - if @account.avatar.present?
= link_to settings_profile_picture_path('avatar'), data: { method: :delete }, class: 'link-button link-button--destructive' do = link_to settings_profile_picture_path('avatar'), data: { method: :delete }, class: 'link-button link-button--destructive' do
= fa_icon 'trash fw' = material_symbol 'delete'
= t('generic.delete') = t('generic.delete')
.fields-row .fields-row
@ -59,7 +59,7 @@
= image_tag @account.header.url, class: 'fields-group__thumbnail', id: 'account_header-preview' = image_tag @account.header.url, class: 'fields-group__thumbnail', id: 'account_header-preview'
- if @account.header.present? - if @account.header.present?
= link_to settings_profile_picture_path('header'), data: { method: :delete }, class: 'link-button link-button--destructive' do = link_to settings_profile_picture_path('header'), data: { method: :delete }, class: 'link-button link-button--destructive' do
= fa_icon 'trash fw' = material_symbol 'delete'
= t('generic.delete') = t('generic.delete')
%h4= t('edit_profile.other') %h4= t('edit_profile.other')

View file

@ -1,7 +1,7 @@
.content__heading__tabs .content__heading__tabs
= render_navigation renderer: :links do |primary| = render_navigation renderer: :links do |primary|
:ruby :ruby
primary.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_path primary.item :profile, safe_join([material_symbol('person'), t('settings.edit_profile')]), settings_profile_path
primary.item :privacy, safe_join([fa_icon('lock fw'), t('privacy.title')]), settings_privacy_path primary.item :privacy, safe_join([material_symbol('lock'), t('privacy.title')]), settings_privacy_path
primary.item :verification, safe_join([fa_icon('check fw'), t('verification.verification')]), settings_verification_path primary.item :verification, safe_join([material_symbol('check'), t('verification.verification')]), settings_verification_path
primary.item :featured_tags, safe_join([fa_icon('hashtag fw'), t('settings.featured_tags')]), settings_featured_tags_path primary.item :featured_tags, safe_join([material_symbol('tag'), t('settings.featured_tags')]), settings_featured_tags_path

View file

@ -6,7 +6,7 @@
%p.hint %p.hint
%span.positive-hint %span.positive-hint
= fa_icon 'check' = material_symbol 'check'
&nbsp; &nbsp;
= t 'two_factor_authentication.enabled' = t 'two_factor_authentication.enabled'

View file

@ -26,5 +26,5 @@
- @verified_links.each do |field| - @verified_links.each do |field|
%li %li
%span.verified-badge %span.verified-badge
= fa_icon 'check', class: 'verified-badge__mark' = material_symbol 'check', class: 'verified-badge__mark'
%span= field.value %span= field.value

View file

@ -12,6 +12,7 @@ el:
last_attempt: Έχεις μια ακόμα προσπάθεια πριν κλειδωθεί ο λογαριασμός σου. last_attempt: Έχεις μια ακόμα προσπάθεια πριν κλειδωθεί ο λογαριασμός σου.
locked: Ο λογαριασμός σου κλειδώθηκε. locked: Ο λογαριασμός σου κλειδώθηκε.
not_found_in_database: Λάθος %{authentication_keys} ή συνθηματικό. not_found_in_database: Λάθος %{authentication_keys} ή συνθηματικό.
omniauth_user_creation_failure: Σφάλμα δημιουργίας λογαριασμού για αυτήν την ταυτότητα.
pending: Εκκρεμεί η έγκριση του λογαριασμού σου. pending: Εκκρεμεί η έγκριση του λογαριασμού σου.
timeout: Η τρέχουσα σύνδεσή σου έληξε. Παρακαλούμε συνδέσου ξανά για να συνεχίσεις. timeout: Η τρέχουσα σύνδεσή σου έληξε. Παρακαλούμε συνδέσου ξανά για να συνεχίσεις.
unauthenticated: Πρέπει να συνδεθείς ή να εγγραφείς για να συνεχίσεις. unauthenticated: Πρέπει να συνδεθείς ή να εγγραφείς για να συνεχίσεις.

View file

@ -83,6 +83,7 @@ el:
access_denied: Ο ιδιοκτήτης του πόρου ή του παρόχου έγκρισης απέρριψε το αίτημα. access_denied: Ο ιδιοκτήτης του πόρου ή του παρόχου έγκρισης απέρριψε το αίτημα.
credential_flow_not_configured: Η ροή Resource Owner Password Credentials απέτυχε επειδή το Doorkeeper.configure.resource_owner_from_credentials δεν έχει ρυθμιστεί. credential_flow_not_configured: Η ροή Resource Owner Password Credentials απέτυχε επειδή το Doorkeeper.configure.resource_owner_from_credentials δεν έχει ρυθμιστεί.
invalid_client: Η ταυτοποίηση του πελάτη απέτυχε είτε λόγω άγνωστου πελάτη, είτε λόγω έλλειψης ταυτοποιημένου πελάτη ή λόγω μη υποστηριζόμενης μεθόδου ταυτοποίησης. invalid_client: Η ταυτοποίηση του πελάτη απέτυχε είτε λόγω άγνωστου πελάτη, είτε λόγω έλλειψης ταυτοποιημένου πελάτη ή λόγω μη υποστηριζόμενης μεθόδου ταυτοποίησης.
invalid_code_challenge_method: Η μέθοδος πρόκλησης κώδικα πρέπει να είναι S256, το απλό δεν υποστηρίζεται.
invalid_grant: Η άδεια πιστοποίησης που δόθηκε είναι άκυρη, ληγμένη, έχει ανακληθεί, δεν συμφωνεί με το URI ανακατεύθυνσης που δόθηκε στο αίτημα πιστοποίησης ή εκδόθηκε προς άλλο πελάτη. invalid_grant: Η άδεια πιστοποίησης που δόθηκε είναι άκυρη, ληγμένη, έχει ανακληθεί, δεν συμφωνεί με το URI ανακατεύθυνσης που δόθηκε στο αίτημα πιστοποίησης ή εκδόθηκε προς άλλο πελάτη.
invalid_redirect_uri: Το uri ανακατεύθυνσης που δόθηκε δεν είναι έγκυρο. invalid_redirect_uri: Το uri ανακατεύθυνσης που δόθηκε δεν είναι έγκυρο.
invalid_request: invalid_request:

View file

@ -286,6 +286,7 @@ el:
update_custom_emoji_html: Ο/Η %{name} ενημέρωσε το emoji %{target} update_custom_emoji_html: Ο/Η %{name} ενημέρωσε το emoji %{target}
update_domain_block_html: Ο/Η %{name} ενημέρωσε τον αποκλεισμό τομέα για %{target} update_domain_block_html: Ο/Η %{name} ενημέρωσε τον αποκλεισμό τομέα για %{target}
update_ip_block_html: Ο/Η %{name} άλλαξε τον κανόνα για την IP %{target} update_ip_block_html: Ο/Η %{name} άλλαξε τον κανόνα για την IP %{target}
update_report_html: Ο χρήστης %{name} ενημέρωσε την αναφορά %{target}
update_status_html: Ο/Η %{name} ενημέρωσε την ανάρτηση του/της %{target} update_status_html: Ο/Η %{name} ενημέρωσε την ανάρτηση του/της %{target}
update_user_role_html: Ο/Η %{name} άλλαξε τον ρόλο %{target} update_user_role_html: Ο/Η %{name} άλλαξε τον ρόλο %{target}
deleted_account: διαγεγραμμένος λογαριασμός deleted_account: διαγεγραμμένος λογαριασμός
@ -293,6 +294,7 @@ el:
filter_by_action: Φιλτράρισμα ανά ενέργεια filter_by_action: Φιλτράρισμα ανά ενέργεια
filter_by_user: Φιλτράρισμα ανά χρήστη filter_by_user: Φιλτράρισμα ανά χρήστη
title: Αρχείο ελέγχου title: Αρχείο ελέγχου
unavailable_instance: "(μη διαθέσιμο όνομα τομέα)"
announcements: announcements:
destroyed_msg: Επιτυχής διαγραφή ανακοίνωσης! destroyed_msg: Επιτυχής διαγραφή ανακοίνωσης!
edit: edit:
@ -469,6 +471,9 @@ el:
title: Ακολούθησε τις προτάσεις title: Ακολούθησε τις προτάσεις
unsuppress: Επαναφορά των συστάσεων ακολούθησης unsuppress: Επαναφορά των συστάσεων ακολούθησης
instances: instances:
audit_log:
title: Πρόσφατα Αρχεία Ελέγχου
view_all: Δείτε πλήρη αρχεία καταγραφής ελέγχων
availability: availability:
description_html: description_html:
one: Εάν η παράδοση στον τομέα αποτύχει για <strong>%{count} ημέρα</strong>, δεν θα γίνουν περαιτέρω προσπάθειες παράδοσης εκτός αν μια παράδοση <em>από</em> τον τομέα ληφθεί. one: Εάν η παράδοση στον τομέα αποτύχει για <strong>%{count} ημέρα</strong>, δεν θα γίνουν περαιτέρω προσπάθειες παράδοσης εκτός αν μια παράδοση <em>από</em> τον τομέα ληφθεί.
@ -598,6 +603,9 @@ el:
actions_description_html: Αποφάσισε ποια μέτρα θα ληφθούν για την επίλυση αυτής της αναφοράς. Εάν προβείς σε τιμωρητική ενέργεια κατά του αναφερόμενου λογαριασμού, θα αποσταλεί ειδοποίηση μέσω ηλεκτρονικού ταχυδρομείου σε αυτόν, εκτός όταν η κατηγορία <strong>Σπαμ</strong> είναι επιλεγμένη. actions_description_html: Αποφάσισε ποια μέτρα θα ληφθούν για την επίλυση αυτής της αναφοράς. Εάν προβείς σε τιμωρητική ενέργεια κατά του αναφερόμενου λογαριασμού, θα αποσταλεί ειδοποίηση μέσω ηλεκτρονικού ταχυδρομείου σε αυτόν, εκτός όταν η κατηγορία <strong>Σπαμ</strong> είναι επιλεγμένη.
actions_description_remote_html: Αποφάσισε ποια μέτρα θα ληφθούν για την επίλυση αυτής της αναφοράς. Αυτό θα επηρεάσει μόνο το πώς <strong>ο δικός σας</strong> διακομιστής επικοινωνεί με αυτόν τον απομακρυσμένο λογαριασμό και χειρίζεται το περιεχόμενό του. actions_description_remote_html: Αποφάσισε ποια μέτρα θα ληφθούν για την επίλυση αυτής της αναφοράς. Αυτό θα επηρεάσει μόνο το πώς <strong>ο δικός σας</strong> διακομιστής επικοινωνεί με αυτόν τον απομακρυσμένο λογαριασμό και χειρίζεται το περιεχόμενό του.
add_to_report: Πρόσθεσε περισσότερα στην αναφορά add_to_report: Πρόσθεσε περισσότερα στην αναφορά
already_suspended_badges:
local: Ήδη σε αναστολή σε αυτόν τον διακομιστή
remote: Ήδη σε αναστολή στο διακομιστή του
are_you_sure: Σίγουρα; are_you_sure: Σίγουρα;
assign_to_self: Ανάθεση σε μένα assign_to_self: Ανάθεση σε μένα
assigned: Αρμόδιος συντονιστής assigned: Αρμόδιος συντονιστής
@ -634,6 +642,7 @@ el:
report: 'Αναφορά #%{id}' report: 'Αναφορά #%{id}'
reported_account: Αναφερόμενος λογαριασμός reported_account: Αναφερόμενος λογαριασμός
reported_by: Αναφέρθηκε από reported_by: Αναφέρθηκε από
reported_with_application: Αναφέρθηκε με την εφαρμογή
resolved: Επιλύθηκε resolved: Επιλύθηκε
resolved_msg: Η αναφορά επιλύθηκε επιτυχώς! resolved_msg: Η αναφορά επιλύθηκε επιτυχώς!
skip_to_actions: Μετάβαση στις ενέργειες skip_to_actions: Μετάβαση στις ενέργειες
@ -745,7 +754,11 @@ el:
branding: branding:
preamble: Η ταυτότητα του διακομιστή σου, τον διαφοροποιεί από άλλους διακομιστές του δικτύου. Αυτές οι πληροφορίες μπορεί να εμφανίζονται σε διάφορα περιβάλλοντα, όπως η ιστοσελίδα του Mastodon, εγγενείς εφαρμογές, σε προεπισκοπήσεις συνδέσμου σε άλλους ιστότοπους και εντός εφαρμογών μηνυμάτων και ούτω καθεξής. Γι' αυτό, είναι καλύτερο να διατηρούνται αυτές οι πληροφορίες σαφείς, σύντομες και συνοπτικές. preamble: Η ταυτότητα του διακομιστή σου, τον διαφοροποιεί από άλλους διακομιστές του δικτύου. Αυτές οι πληροφορίες μπορεί να εμφανίζονται σε διάφορα περιβάλλοντα, όπως η ιστοσελίδα του Mastodon, εγγενείς εφαρμογές, σε προεπισκοπήσεις συνδέσμου σε άλλους ιστότοπους και εντός εφαρμογών μηνυμάτων και ούτω καθεξής. Γι' αυτό, είναι καλύτερο να διατηρούνται αυτές οι πληροφορίες σαφείς, σύντομες και συνοπτικές.
title: Ταυτότητα title: Ταυτότητα
captcha_enabled:
desc_html: Αυτό βασίζεται σε εξωτερικά scripts από το hCaptcha, όπου υπάρχει ανησυχία πέρι ασφάλειας και ιδιωτηκότητας. Επιπρόσθετα, <strong> μπορεί να κάνει τη διαδικασία εγγραφής πολύ λιγότερο προσβάσιμη για κάποια άτομα (ειδικά αυτά με αναπηρίες)</strong>. Για αυτούς τους λόγους, παρακαλώ σκέψου άλλου τρόπους εγγραφής όπως με αποδοχή ή με πρόσκληση.
title: Απαιτείται από νέους χρήστες να λύσουν ένα CAPTCHA για να επιβεβαιώσουν τον λογαριασμό τους
content_retention: content_retention:
danger_zone: Επικίνδυνη Ζώνη
preamble: Έλεγξε πώς αποθηκεύεται το περιεχόμενο που δημιουργείται από τους χρήστες στο Mastodon. preamble: Έλεγξε πώς αποθηκεύεται το περιεχόμενο που δημιουργείται από τους χρήστες στο Mastodon.
title: Διατήρηση περιεχομένου title: Διατήρηση περιεχομένου
default_noindex: default_noindex:
@ -765,6 +778,7 @@ el:
disabled: Για κανέναν disabled: Για κανέναν
users: Προς συνδεδεμένους τοπικούς χρήστες users: Προς συνδεδεμένους τοπικούς χρήστες
registrations: registrations:
moderation_recommandation: Παρακαλώ βεβαιώσου ότι έχεις μια επαρκής και ενεργή ομάδα συντονισμού πριν ανοίξεις τις εγγραφές για όλους!
preamble: Έλεγξε ποιος μπορεί να δημιουργήσει ένα λογαριασμό στον διακομιστή σας. preamble: Έλεγξε ποιος μπορεί να δημιουργήσει ένα λογαριασμό στον διακομιστή σας.
title: Εγγραφές title: Εγγραφές
registrations_mode: registrations_mode:
@ -772,9 +786,28 @@ el:
approved: Απαιτείται έγκριση για εγγραφή approved: Απαιτείται έγκριση για εγγραφή
none: Δεν μπορεί να εγγραφεί κανείς none: Δεν μπορεί να εγγραφεί κανείς
open: Μπορεί να εγγραφεί ο οποιοσδήποτε open: Μπορεί να εγγραφεί ο οποιοσδήποτε
warning_hint: Προτείνουμε τη χρήση του "Απαιτείται έγκριση για εγγραφή" εκτός αν ξέρεις ότι η ομάδα συντονισμού σου μπορεί να διαχειριστεί τις κακόβουλες και σπαμ εγγραφές σε εύλογο χρονικό διάστημα.
security:
authorized_fetch: Απαίτηση ταυτόποιησης από διακομιστές σε ομοσπονδία
authorized_fetch_hint: Η απαίτηση ελέγχου ταυτότητας από ομοσπονδιακούς διακομιστές επιτρέπει την αυστηρότερη επιβολή αποκλεισμού τόσο σε επίπεδο χρήστη όσο και σε επίπεδο διακομιστή. Ωστόσο, αυτό έχει το κόστος στην απόδοσης μειώνει την εμβέλεια των απαντήσεών σας και μπορεί να δημιουργήσει προβλήματα συμβατότητας με ορισμένες ομοσπονδιακές υπηρεσίες. Επιπλέον, αυτό δεν θα εμποδίσει τους αφοσιωμένους ηθοποιούς να ανακτήσουν τις δημόσιες αναρτήσεις και τους λογαριασμούς σας.
authorized_fetch_overridden_hint: Προς το παρόν, δε μπορείς να αλλάξεις αυτή την ρύθμιση επειδή παρακάμπτεται από μια μεταβλητή περιβάλλοντος.
federation_authentication: Επιβολή ομοσπονδιακής ταυτοποίησης
title: Ρυθμίσεις διακομιστή
site_uploads: site_uploads:
delete: Διαγραφή μεταφορτωμένου αρχείου delete: Διαγραφή μεταφορτωμένου αρχείου
destroyed_msg: Η μεταφόρτωση ιστότοπου διαγράφηκε επιτυχώς! destroyed_msg: Η μεταφόρτωση ιστότοπου διαγράφηκε επιτυχώς!
software_updates:
critical_update: Κρίσιμο - παρακαλώ ενημέρωσε γρήγορα
description: Συνιστάται να διατηρείς την εγκατάσταση του Mastodon ενημερωμένη για να επωφεληθείς από τις πιο πρόσφατες διορθώσεις και δυνατότητες. Επιπλέον, μερικές φορές είναι κρίσιμο να ενημερώσεις το Mastodon εγκαίρως για να αποφύγεις προβλήματα ασφαλείας. Για αυτούς τους λόγους, το Mastodon ελέγχει για ενημερώσεις κάθε 30 λεπτά και θα σας ειδοποιεί σύμφωνα με τις προτιμήσεις ειδοποίησης μέσω email.
documentation_link: Μάθε περισσότερα
release_notes: Σημειώσεις έκδοσης
title: Διαθέσιμες ενημερώσεις
type: Τύπος
types:
major: Κύρια έκδοση
minor: Τυπική ενημέρωση
patch: Ενημέρωση επιδιόρθωσης - διορθώσεις σφαλμάτων και εύκολα εφαρμόσιμες αλλαγές
version: Έκδοση
statuses: statuses:
account: Συντάκτης account: Συντάκτης
application: Εφαρμογή application: Εφαρμογή
@ -815,6 +848,20 @@ el:
system_checks: system_checks:
database_schema_check: database_schema_check:
message_html: Υπάρχουν μετακινήσεις βάσεων δεδομένων που εκκρεμούν. Παρακαλώ εκτέλεσέ τες για να βεβαιωθείς ότι η εφαρμογή συμπεριφέρεται όπως αναμένεται message_html: Υπάρχουν μετακινήσεις βάσεων δεδομένων που εκκρεμούν. Παρακαλώ εκτέλεσέ τες για να βεβαιωθείς ότι η εφαρμογή συμπεριφέρεται όπως αναμένεται
elasticsearch_health_red:
message_html: Το σύμπλεγμα Elasticsearch δεν είναι υγιές (κόκκινη κατάσταση), μη διαθέσιμες δυνατότητες αναζήτησης
elasticsearch_health_yellow:
message_html: Το σύμπλεγμα Elasticsearch δεν είναι υγιές (κίτρινη κατάσταση), ίσως θες να διαπιστώσεις την αιτία
elasticsearch_index_mismatch:
message_html: Οι αντιστοιχές δείκτη του Elasticsearch δεν είναι ενημερωμένες. Παρακαλώ εκτέλεσε το <code>tootctl search deploy --only=%{value}</code>
elasticsearch_preset:
action: Δες το εγχειρίδιο
message_html: Το σύμπλεγμα Elasticsearch σου, έχει παραπάνω από ένα κόμβο, το Mastodon δεν είναι ρυθμισμένο για να τους χρησιμοποιεί.
elasticsearch_preset_single_node:
action: Δες το εγχειρίδιο
message_html: Το σύμπλεγμα Elasticsearch σου έχει μόνο ένα κόμβο, το <code>ES_PRESET</code> πρέπει να οριστεί ως <code>single_node_cluster</code>.
elasticsearch_reset_chewy:
message_html: Ο δείκτης του συστήματος Elasticsearch είναι ξεπερασμένος λόγω μιας αλλαγής ρύθμισης. Παρακαλώ εκτέλεσε <code>tootctl search deploy --reset-chewy</code> για να τον ενημερώσεις.
elasticsearch_running_check: elasticsearch_running_check:
message_html: Δεν ήταν δυνατή η σύνδεση στο Elasticsearch. Παρακαλώ έλεγξε ότι εκτελείται ή απενεργοποίησε την αναζήτηση πλήρους κειμένου message_html: Δεν ήταν δυνατή η σύνδεση στο Elasticsearch. Παρακαλώ έλεγξε ότι εκτελείται ή απενεργοποίησε την αναζήτηση πλήρους κειμένου
elasticsearch_version_check: elasticsearch_version_check:
@ -825,6 +872,12 @@ el:
message_html: Δεν έχεις ορίσει κανέναν κανόνα διακομιστή. message_html: Δεν έχεις ορίσει κανέναν κανόνα διακομιστή.
sidekiq_process_check: sidekiq_process_check:
message_html: Καμία διεργασία Sidekiq δεν εκτελείται για την ουρά %{value}. Παρακαλώ έλεγξε τη διαμόρφωση του Sidekiq message_html: Καμία διεργασία Sidekiq δεν εκτελείται για την ουρά %{value}. Παρακαλώ έλεγξε τη διαμόρφωση του Sidekiq
software_version_critical_check:
action: Δες τις διαθέσιμες ενημερώσεις
message_html: Μια κρίσιμη ενημέρωση του Mastodon είναι διαθέσιμη, παρακαλώ ενήμερωσε το συντομότερο δυνατόν.
software_version_patch_check:
action: Δες τις διαθέσιμες ενημερώσεις
message_html: Μια ενημέρωση διόρθωσης σφαλμάτων του Mastodon είναι διαθέσιμη.
upload_check_privacy_error: upload_check_privacy_error:
action: Δες εδώ για περισσότερες πληροφορίες action: Δες εδώ για περισσότερες πληροφορίες
message_html: "<strong>Ο διακομιστής σας δεν έχει ρυθμιστεί σωστά. Το απόρρητο των χρηστών σας κινδυνεύει.</strong>" message_html: "<strong>Ο διακομιστής σας δεν έχει ρυθμιστεί σωστά. Το απόρρητο των χρηστών σας κινδυνεύει.</strong>"
@ -832,6 +885,13 @@ el:
action: Δες εδώ για περισσότερες πληροφορίες action: Δες εδώ για περισσότερες πληροφορίες
message_html: "<strong>Ο χώρος αποθήκευσης αντικειμένων σου δεν έχει ρυθμιστεί σωστά. Το απόρρητο των χρηστών σου κινδυνεύει.</strong>" message_html: "<strong>Ο χώρος αποθήκευσης αντικειμένων σου δεν έχει ρυθμιστεί σωστά. Το απόρρητο των χρηστών σου κινδυνεύει.</strong>"
tags: tags:
moderation:
not_trendable: Δε δημιουργεί τάσεις
not_usable: Μη χρησιμοποιήσιμη
pending_review: Εκκρεμεί αξιολόγηση
review_requested: Αιτήθηκε αξιολόγηση
reviewed: Αξιολογήθηκε
title: Κατάσταση
review: Κατάσταση αξιολόγησης review: Κατάσταση αξιολόγησης
updated_msg: Οι ρυθμίσεις των ετικετών ενημερώθηκαν επιτυχώς updated_msg: Οι ρυθμίσεις των ετικετών ενημερώθηκαν επιτυχώς
title: Διαχείριση title: Διαχείριση

View file

@ -4,78 +4,78 @@ SimpleNavigation::Configuration.run do |navigation|
self_destruct = SelfDestructHelper.self_destruct? self_destruct = SelfDestructHelper.self_destruct?
navigation.items do |n| navigation.items do |n|
n.item :web, safe_join([fa_icon('chevron-left fw'), t('settings.back')]), root_path n.item :web, safe_join([material_symbol('chevron_left'), t('settings.back')]), root_path
n.item :software_updates, safe_join([fa_icon('exclamation-circle fw'), t('admin.critical_update_pending')]), admin_software_updates_path, if: -> { ENV['UPDATE_CHECK_URL'] != '' && current_user.can?(:view_devops) && SoftwareUpdate.urgent_pending? }, html: { class: 'warning' } n.item :software_updates, safe_join([material_symbol('report'), t('admin.critical_update_pending')]), admin_software_updates_path, if: -> { ENV['UPDATE_CHECK_URL'] != '' && current_user.can?(:view_devops) && SoftwareUpdate.urgent_pending? }, html: { class: 'warning' }
n.item :profile, safe_join([fa_icon('user fw'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? && !self_destruct }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy} n.item :profile, safe_join([material_symbol('person'), t('settings.profile')]), settings_profile_path, if: -> { current_user.functional? && !self_destruct }, highlights_on: %r{/settings/profile|/settings/featured_tags|/settings/verification|/settings/privacy}
n.item :preferences, safe_join([fa_icon('cog fw'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? && !self_destruct } do |s| n.item :preferences, safe_join([material_symbol('settings'), t('settings.preferences')]), settings_preferences_path, if: -> { current_user.functional? && !self_destruct } do |s|
s.item :appearance, safe_join([fa_icon('desktop fw'), t('settings.appearance')]), settings_preferences_appearance_path s.item :appearance, safe_join([material_symbol('computer'), t('settings.appearance')]), settings_preferences_appearance_path
s.item :notifications, safe_join([fa_icon('envelope fw'), t('settings.notifications')]), settings_preferences_notifications_path s.item :notifications, safe_join([material_symbol('mail'), t('settings.notifications')]), settings_preferences_notifications_path
s.item :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_path s.item :other, safe_join([material_symbol('settings'), t('preferences.other')]), settings_preferences_other_path
end end
n.item :flavours, safe_join([fa_icon('paint-brush fw'), t('settings.flavours')]), settings_flavours_path do |flavours| n.item :flavours, safe_join([material_symbol('brush'), t('settings.flavours')]), settings_flavours_path do |flavours|
Themes.instance.flavours.each do |flavour| Themes.instance.flavours.each do |flavour|
flavours.item flavour.to_sym, safe_join([fa_icon('star fw'), t("flavours.#{flavour}.name", default: flavour)]), settings_flavour_path(flavour) flavours.item flavour.to_sym, safe_join([material_symbol('star-fill'), t("flavours.#{flavour}.name", default: flavour)]), settings_flavour_path(flavour)
end end
end end
n.item :relationships, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? && !self_destruct } do |s| n.item :relationships, safe_join([material_symbol('groups'), t('settings.relationships')]), relationships_path, if: -> { current_user.functional? && !self_destruct } do |s|
s.item :current, safe_join([fa_icon('users fw'), t('settings.relationships')]), relationships_path s.item :current, safe_join([material_symbol('groups'), t('settings.relationships')]), relationships_path
s.item :severed_relationships, safe_join([fa_icon('unlink fw'), t('settings.severed_relationships')]), severed_relationships_path s.item :severed_relationships, safe_join([material_symbol('link_off'), t('settings.severed_relationships')]), severed_relationships_path
end end
n.item :filters, safe_join([fa_icon('filter fw'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? && !self_destruct } n.item :filters, safe_join([material_symbol('filter_alt'), t('filters.index.title')]), filters_path, highlights_on: %r{/filters}, if: -> { current_user.functional? && !self_destruct }
n.item :statuses_cleanup, safe_join([fa_icon('history fw'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? && !self_destruct } n.item :statuses_cleanup, safe_join([material_symbol('history'), t('settings.statuses_cleanup')]), statuses_cleanup_path, if: -> { current_user.functional_or_moved? && !self_destruct }
n.item :security, safe_join([fa_icon('lock fw'), t('settings.account')]), edit_user_registration_path do |s| n.item :security, safe_join([material_symbol('lock'), t('settings.account')]), edit_user_registration_path do |s|
s.item :password, safe_join([fa_icon('lock fw'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes} s.item :password, safe_join([material_symbol('lock'), t('settings.account_settings')]), edit_user_registration_path, highlights_on: %r{/auth/edit|/settings/delete|/settings/migration|/settings/aliases|/settings/login_activities|^/disputes}
s.item :two_factor_authentication, safe_join([fa_icon('mobile fw'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_path, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys} s.item :two_factor_authentication, safe_join([material_symbol('safety_check'), t('settings.two_factor_authentication')]), settings_two_factor_authentication_methods_path, highlights_on: %r{/settings/two_factor_authentication|/settings/otp_authentication|/settings/security_keys}
s.item :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path, if: -> { !self_destruct } s.item :authorized_apps, safe_join([material_symbol('list_alt'), t('settings.authorized_apps')]), oauth_authorized_applications_path, if: -> { !self_destruct }
end end
n.item :data, safe_join([fa_icon('cloud-download fw'), t('settings.import_and_export')]), settings_export_path do |s| n.item :data, safe_join([material_symbol('cloud_sync'), t('settings.import_and_export')]), settings_export_path do |s|
s.item :import, safe_join([fa_icon('cloud-upload fw'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? && !self_destruct } s.item :import, safe_join([material_symbol('cloud_upload'), t('settings.import')]), settings_imports_path, if: -> { current_user.functional? && !self_destruct }
s.item :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_path s.item :export, safe_join([material_symbol('cloud_download'), t('settings.export')]), settings_export_path
end end
n.item :invites, safe_join([fa_icon('user-plus fw'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? && !self_destruct } n.item :invites, safe_join([material_symbol('person_add'), t('invites.title')]), invites_path, if: -> { current_user.can?(:invite_users) && current_user.functional? && !self_destruct }
n.item :development, safe_join([fa_icon('code fw'), t('settings.development')]), settings_applications_path, highlights_on: %r{/settings/applications}, if: -> { current_user.functional? && !self_destruct } n.item :development, safe_join([material_symbol('code'), t('settings.development')]), settings_applications_path, highlights_on: %r{/settings/applications}, if: -> { current_user.functional? && !self_destruct }
n.item :trends, safe_join([fa_icon('fire fw'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) && !self_destruct } do |s| n.item :trends, safe_join([material_symbol('trending_up'), t('admin.trends.title')]), admin_trends_statuses_path, if: -> { current_user.can?(:manage_taxonomies) && !self_destruct } do |s|
s.item :statuses, safe_join([fa_icon('comments-o fw'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses} s.item :statuses, safe_join([material_symbol('chat_bubble'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses}
s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/trends/tags} s.item :tags, safe_join([material_symbol('tag'), t('admin.trends.tags.title')]), admin_trends_tags_path, highlights_on: %r{/admin/trends/tags}
s.item :links, safe_join([fa_icon('newspaper-o fw'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links} s.item :links, safe_join([material_symbol('breaking_news'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links}
end end
n.item :moderation, safe_join([fa_icon('gavel fw'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) && !self_destruct } do |s| n.item :moderation, safe_join([material_symbol('gavel'), t('moderation.title')]), nil, if: -> { current_user.can?(:manage_reports, :view_audit_log, :manage_users, :manage_invites, :manage_taxonomies, :manage_federation, :manage_blocks) && !self_destruct } do |s|
s.item :reports, safe_join([fa_icon('flag fw'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports|admin/report_notes}, if: -> { current_user.can?(:manage_reports) } s.item :reports, safe_join([material_symbol('flag'), t('admin.reports.title')]), admin_reports_path, highlights_on: %r{/admin/reports|admin/report_notes}, if: -> { current_user.can?(:manage_reports) }
s.item :accounts, safe_join([fa_icon('users fw'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|admin/account_moderation_notes|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) } s.item :accounts, safe_join([material_symbol('groups'), t('admin.accounts.title')]), admin_accounts_path(origin: 'local'), highlights_on: %r{/admin/accounts|admin/account_moderation_notes|/admin/pending_accounts|/admin/disputes|/admin/users}, if: -> { current_user.can?(:manage_users) }
s.item :tags, safe_join([fa_icon('hashtag fw'), t('admin.tags.title')]), admin_tags_path, highlights_on: %r{/admin/tags}, if: -> { current_user.can?(:manage_taxonomies) } s.item :tags, safe_join([material_symbol('tag'), t('admin.tags.title')]), admin_tags_path, highlights_on: %r{/admin/tags}, if: -> { current_user.can?(:manage_taxonomies) }
s.item :invites, safe_join([fa_icon('user-plus fw'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) } s.item :invites, safe_join([material_symbol('person_add'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) }
s.item :follow_recommendations, safe_join([fa_icon('user-plus fw'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) } s.item :follow_recommendations, safe_join([material_symbol('person_add'), t('admin.follow_recommendations.title')]), admin_follow_recommendations_path, highlights_on: %r{/admin/follow_recommendations}, if: -> { current_user.can?(:manage_taxonomies) }
s.item :instances, safe_join([fa_icon('cloud fw'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) } s.item :instances, safe_join([material_symbol('cloud'), t('admin.instances.title')]), admin_instances_path(limited: limited_federation_mode? ? nil : '1'), highlights_on: %r{/admin/instances|/admin/domain_blocks|/admin/domain_allows}, if: -> { current_user.can?(:manage_federation) }
s.item :email_domain_blocks, safe_join([fa_icon('envelope fw'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_path, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.can?(:manage_blocks) } s.item :email_domain_blocks, safe_join([material_symbol('mail'), t('admin.email_domain_blocks.title')]), admin_email_domain_blocks_path, highlights_on: %r{/admin/email_domain_blocks}, if: -> { current_user.can?(:manage_blocks) }
s.item :ip_blocks, safe_join([fa_icon('ban fw'), t('admin.ip_blocks.title')]), admin_ip_blocks_path, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.can?(:manage_blocks) } s.item :ip_blocks, safe_join([material_symbol('hide_source'), t('admin.ip_blocks.title')]), admin_ip_blocks_path, highlights_on: %r{/admin/ip_blocks}, if: -> { current_user.can?(:manage_blocks) }
s.item :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) } s.item :action_logs, safe_join([material_symbol('list'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) }
end end
n.item :admin, safe_join([fa_icon('cogs fw'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) && !self_destruct } do |s| n.item :admin, safe_join([material_symbol('manufacturing'), t('admin.title')]), nil, if: -> { current_user.can?(:view_dashboard, :manage_settings, :manage_rules, :manage_announcements, :manage_custom_emojis, :manage_webhooks, :manage_federation) && !self_destruct } do |s|
s.item :dashboard, safe_join([fa_icon('tachometer fw'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) } s.item :dashboard, safe_join([material_symbol('speed'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) }
s.item :settings, safe_join([fa_icon('cogs fw'), t('admin.settings.title')]), admin_settings_path, if: -> { current_user.can?(:manage_settings) }, highlights_on: %r{/admin/settings} s.item :settings, safe_join([material_symbol('manufacturing'), t('admin.settings.title')]), admin_settings_path, if: -> { current_user.can?(:manage_settings) }, highlights_on: %r{/admin/settings}
s.item :rules, safe_join([fa_icon('gavel fw'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}, if: -> { current_user.can?(:manage_rules) } s.item :rules, safe_join([material_symbol('gavel'), t('admin.rules.title')]), admin_rules_path, highlights_on: %r{/admin/rules}, if: -> { current_user.can?(:manage_rules) }
s.item :warning_presets, safe_join([fa_icon('warning fw'), t('admin.warning_presets.title')]), admin_warning_presets_path, highlights_on: %r{/admin/warning_presets}, if: -> { current_user.can?(:manage_settings) } s.item :warning_presets, safe_join([material_symbol('warning'), t('admin.warning_presets.title')]), admin_warning_presets_path, highlights_on: %r{/admin/warning_presets}, if: -> { current_user.can?(:manage_settings) }
s.item :roles, safe_join([fa_icon('vcard fw'), t('admin.roles.title')]), admin_roles_path, highlights_on: %r{/admin/roles}, if: -> { current_user.can?(:manage_roles) } s.item :roles, safe_join([material_symbol('contact_mail'), t('admin.roles.title')]), admin_roles_path, highlights_on: %r{/admin/roles}, if: -> { current_user.can?(:manage_roles) }
s.item :announcements, safe_join([fa_icon('bullhorn fw'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}, if: -> { current_user.can?(:manage_announcements) } s.item :announcements, safe_join([material_symbol('campaign'), t('admin.announcements.title')]), admin_announcements_path, highlights_on: %r{/admin/announcements}, if: -> { current_user.can?(:manage_announcements) }
s.item :custom_emojis, safe_join([fa_icon('smile-o fw'), t('admin.custom_emojis.title')]), admin_custom_emojis_path, highlights_on: %r{/admin/custom_emojis}, if: -> { current_user.can?(:manage_custom_emojis) } s.item :custom_emojis, safe_join([material_symbol('mood'), t('admin.custom_emojis.title')]), admin_custom_emojis_path, highlights_on: %r{/admin/custom_emojis}, if: -> { current_user.can?(:manage_custom_emojis) }
s.item :webhooks, safe_join([fa_icon('inbox fw'), t('admin.webhooks.title')]), admin_webhooks_path, highlights_on: %r{/admin/webhooks}, if: -> { current_user.can?(:manage_webhooks) } s.item :webhooks, safe_join([material_symbol('inbox'), t('admin.webhooks.title')]), admin_webhooks_path, highlights_on: %r{/admin/webhooks}, if: -> { current_user.can?(:manage_webhooks) }
s.item :relays, safe_join([fa_icon('exchange fw'), t('admin.relays.title')]), admin_relays_path, highlights_on: %r{/admin/relays}, if: -> { !limited_federation_mode? && current_user.can?(:manage_federation) } s.item :relays, safe_join([material_symbol('captive_portal'), t('admin.relays.title')]), admin_relays_path, highlights_on: %r{/admin/relays}, if: -> { !limited_federation_mode? && current_user.can?(:manage_federation) }
end end
n.item :sidekiq, safe_join([fa_icon('diamond fw'), 'Sidekiq']), sidekiq_path, link_html: { target: 'sidekiq' }, if: -> { current_user.can?(:view_devops) } n.item :sidekiq, safe_join([material_symbol('diamond'), 'Sidekiq']), sidekiq_path, link_html: { target: 'sidekiq' }, if: -> { current_user.can?(:view_devops) }
n.item :pghero, safe_join([fa_icon('database fw'), 'PgHero']), pghero_path, link_html: { target: 'pghero' }, if: -> { current_user.can?(:view_devops) } n.item :pghero, safe_join([material_symbol('database'), 'PgHero']), pghero_path, link_html: { target: 'pghero' }, if: -> { current_user.can?(:view_devops) }
n.item :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_path, link_html: { 'data-method' => 'delete' } n.item :logout, safe_join([material_symbol('logout'), t('auth.logout')]), destroy_user_session_path, link_html: { 'data-method' => 'delete' }
end end
end end

View file

@ -225,7 +225,7 @@ describe ApplicationHelper do
it 'returns an unlock icon for a unlisted visible status' do it 'returns an unlock icon for a unlisted visible status' do
result = helper.visibility_icon Status.new(visibility: 'unlisted') result = helper.visibility_icon Status.new(visibility: 'unlisted')
expect(result).to match(/unlock/) expect(result).to match(/lock_open/)
end end
it 'returns a lock icon for a private visible status' do it 'returns a lock icon for a private visible status' do
@ -235,7 +235,7 @@ describe ApplicationHelper do
it 'returns an at icon for a direct visible status' do it 'returns an at icon for a direct visible status' do
result = helper.visibility_icon Status.new(visibility: 'direct') result = helper.visibility_icon Status.new(visibility: 'direct')
expect(result).to match(/at/) expect(result).to match(/alternate_email/)
end end
end end

View file

@ -36,7 +36,7 @@ describe StatusesHelper do
it 'returns the correct fa icon' do it 'returns the correct fa icon' do
result = helper.fa_visibility_icon(status) result = helper.fa_visibility_icon(status)
expect(result).to match('fa-globe') expect(result).to match('material-globe')
end end
end end
@ -46,7 +46,7 @@ describe StatusesHelper do
it 'returns the correct fa icon' do it 'returns the correct fa icon' do
result = helper.fa_visibility_icon(status) result = helper.fa_visibility_icon(status)
expect(result).to match('fa-unlock') expect(result).to match('material-lock_open')
end end
end end
@ -56,7 +56,7 @@ describe StatusesHelper do
it 'returns the correct fa icon' do it 'returns the correct fa icon' do
result = helper.fa_visibility_icon(status) result = helper.fa_visibility_icon(status)
expect(result).to match('fa-lock') expect(result).to match('material-lock')
end end
end end
@ -66,7 +66,7 @@ describe StatusesHelper do
it 'returns the correct fa icon' do it 'returns the correct fa icon' do
result = helper.fa_visibility_icon(status) result = helper.fa_visibility_icon(status)
expect(result).to match('fa-at') expect(result).to match('material-alternate_email')
end end
end end
end end