diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2369cff7e6..ed89d81563 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -116,7 +116,7 @@ module ApplicationHelper def material_symbol(icon, attributes = {}) inline_svg_tag( "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 ) end @@ -127,23 +127,23 @@ module ApplicationHelper def visibility_icon(status) 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? - 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? - fa_icon('lock', title: I18n.t('statuses.visibilities.private')) + material_symbol('lock', title: I18n.t('statuses.visibilities.private')) 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 def interrelationships_icon(relationships, 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] - 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] - 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 diff --git a/app/helpers/statuses_helper.rb b/app/helpers/statuses_helper.rb index ca693a8a78..d956e4fcd8 100644 --- a/app/helpers/statuses_helper.rb +++ b/app/helpers/statuses_helper.rb @@ -60,13 +60,13 @@ module StatusesHelper def fa_visibility_icon(status) case status.visibility when 'public' - fa_icon 'globe fw' + material_symbol 'globe' when 'unlisted' - fa_icon 'unlock fw' + material_symbol 'lock_open' when 'private' - fa_icon 'lock fw' + material_symbol 'lock' when 'direct' - fa_icon 'at fw' + material_symbol 'alternate_email' end end diff --git a/app/javascript/flavours/glitch/components/dropdown_selector.tsx b/app/javascript/flavours/glitch/components/dropdown_selector.tsx new file mode 100644 index 0000000000..f8bf96c634 --- /dev/null +++ b/app/javascript/flavours/glitch/components/dropdown_selector.tsx @@ -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 = ({ + style, + items, + value, + classNamePrefix = 'privacy-dropdown', + onClose, + onChange, +}) => { + const nodeRef = useRef(null); + const focusedItemRef = useRef(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 | React.KeyboardEvent, + ) => { + const value = e.currentTarget.getAttribute('data-index'); + + e.preventDefault(); + + onClose(); + if (value) onChange(value); + }, + [onClose, onChange], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + 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 ( +
    + {items.map((item) => ( +
  • + {item.icon && item.iconComponent && ( +
    + +
    + )} + +
    + {item.text} + {item.meta} +
    + + {item.extra && ( +
    + +
    + )} +
  • + ))} +
+ ); +}; diff --git a/app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx b/app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx index 9774d4260e..55830f0a92 100644 --- a/app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx +++ b/app/javascript/flavours/glitch/features/compose/components/dropdown_icon_button.jsx @@ -3,10 +3,9 @@ import { useCallback, useState, useRef } from 'react'; import Overlay from 'react-overlays/Overlay'; +import { DropdownSelector } from 'flavours/glitch/components/dropdown_selector'; import { IconButton } from 'flavours/glitch/components/icon_button'; -import { PrivacyDropdownMenu } from './privacy_dropdown_menu'; - export const DropdownIconButton = ({ value, disabled, icon, onChange, iconComponent, title, options }) => { const containerRef = useRef(null); @@ -53,7 +52,7 @@ export const DropdownIconButton = ({ value, disabled, icon, onChange, iconCompon {({ props, placement }) => (
- (
- { - 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 ( -
    - {items.map(item => ( -
  • -
    - -
    - -
    - {item.text} - {item.meta} -
    - - {item.extra && ( -
    - -
    - )} -
  • - ))} -
- ); -}; - -PrivacyDropdownMenu.propTypes = { - style: PropTypes.object, - items: PropTypes.array.isRequired, - value: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, -}; diff --git a/app/javascript/flavours/glitch/features/notifications/components/policy_controls.tsx b/app/javascript/flavours/glitch/features/notifications/components/policy_controls.tsx index 58eff3fbcf..5982db2923 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/policy_controls.tsx +++ b/app/javascript/flavours/glitch/features/notifications/components/policy_controls.tsx @@ -7,6 +7,9 @@ import { useAppSelector, useAppDispatch } from 'flavours/glitch/store'; import { CheckboxWithLabel } from './checkbox_with_label'; +// eslint-disable-next-line @typescript-eslint/no-empty-function +const noop = () => {}; + export const PolicyControls: React.FC = () => { const dispatch = useAppDispatch(); @@ -135,6 +138,21 @@ export const PolicyControls: React.FC = () => { /> + + + + + + + + +
); diff --git a/app/javascript/flavours/glitch/features/notifications/request.jsx b/app/javascript/flavours/glitch/features/notifications/request.jsx index b95533aa36..3dd186f2bf 100644 --- a/app/javascript/flavours/glitch/features/notifications/request.jsx +++ b/app/javascript/flavours/glitch/features/notifications/request.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import { useRef, useCallback, useEffect } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; 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') }); + let explainer = null; + + if (account?.limited) { + const isLocal = account.acct.indexOf('@') === -1; + explainer = ( +
+
+ {isLocal ? ( + + ) : ( + + )} +
+
+ ); + } + return ( { ( state.lastReadId, action.payload.markers.notifications.last_read_id, ) < 0 - ) + ) { state.lastReadId = action.payload.markers.notifications.last_read_id; + state.readMarkerId = + action.payload.markers.notifications.last_read_id; + } }) .addCase(mountNotifications, (state) => { state.mounted += 1; diff --git a/app/javascript/flavours/glitch/styles/_mixins.scss b/app/javascript/flavours/glitch/styles/_mixins.scss index 444d2e0160..f139bef21b 100644 --- a/app/javascript/flavours/glitch/styles/_mixins.scss +++ b/app/javascript/flavours/glitch/styles/_mixins.scss @@ -17,7 +17,7 @@ background: $ui-base-color; color: $darker-text-color; border-radius: 4px; - border: 1px solid lighten($ui-base-color, 8%); + border: 1px solid var(--background-border-color); font-size: 17px; line-height: normal; margin: 0; diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss index 110d5f249d..08c0a08be3 100644 --- a/app/javascript/flavours/glitch/styles/admin.scss +++ b/app/javascript/flavours/glitch/styles/admin.scss @@ -10,6 +10,13 @@ $content-width: 840px; width: 100%; min-height: 100vh; + .icon { + width: 16px; + height: 16px; + vertical-align: top; + margin: 0 2px; + } + .sidebar-wrapper { min-height: 100vh; overflow: hidden; diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss index b8647cd559..cd1b04d284 100644 --- a/app/javascript/flavours/glitch/styles/components.scss +++ b/app/javascript/flavours/glitch/styles/components.scss @@ -403,7 +403,7 @@ body > [data-popper-placement] { &__suggestions { box-shadow: var(--dropdown-shadow); 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; color: $secondary-text-color; font-size: 14px; @@ -3268,11 +3268,6 @@ $ui-header-logo-wordmark-width: 99px; .explore__search-header { display: flex; } - - .explore__search-results { - border: 0; - border-radius: 0; - } } .icon-with-badge { @@ -9346,10 +9341,13 @@ noscript { flex: 1 1 auto; display: flex; flex-direction: column; - border: 1px solid var(--background-border-color); - border-top: 0; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; + + @media screen and (min-width: $no-gap-breakpoint) { + border: 1px solid var(--background-border-color); + border-top: 0; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + } } .story { diff --git a/app/javascript/flavours/glitch/styles/forms.scss b/app/javascript/flavours/glitch/styles/forms.scss index 4877170275..d206af1f18 100644 --- a/app/javascript/flavours/glitch/styles/forms.scss +++ b/app/javascript/flavours/glitch/styles/forms.scss @@ -442,11 +442,6 @@ code { border-radius: 4px; padding: 10px 16px; - &::placeholder { - color: $dark-text-color; - opacity: 1; - } - &:invalid { box-shadow: none; } @@ -608,8 +603,7 @@ code { inset-inline-end: 3px; top: 1px; padding: 10px; - padding-bottom: 9px; - font-size: 16px; + font-size: 14px; color: $dark-text-color; font-family: inherit; pointer-events: none; @@ -626,11 +620,6 @@ code { inset-inline-end: 0; bottom: 1px; width: 5px; - background-image: linear-gradient( - to right, - rgba(darken($ui-base-color, 10%), 0), - darken($ui-base-color, 10%) - ); } } } diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss index e97b40d3f7..73ec36c1b6 100644 --- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss +++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss @@ -559,11 +559,11 @@ html { .compose-form .autosuggest-textarea__textarea, .compose-form__highlightable, +.autosuggest-textarea__suggestions, .search__input, .search__popout, .emoji-mart-search input, .language-dropdown__dropdown .emoji-mart-search input, -// .strike-card, .poll__option input[type='text'] { background: darken($ui-base-color, 10%); } diff --git a/app/javascript/flavours/glitch/styles/rtl.scss b/app/javascript/flavours/glitch/styles/rtl.scss index 1091a13238..3f03051ce1 100644 --- a/app/javascript/flavours/glitch/styles/rtl.scss +++ b/app/javascript/flavours/glitch/styles/rtl.scss @@ -90,16 +90,6 @@ body.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 { background: $ui-base-color url("data:image/svg+xml;utf8,") diff --git a/app/javascript/flavours/glitch/styles/tables.scss b/app/javascript/flavours/glitch/styles/tables.scss index dd73f6e205..992ad0cbe4 100644 --- a/app/javascript/flavours/glitch/styles/tables.scss +++ b/app/javascript/flavours/glitch/styles/tables.scss @@ -273,8 +273,8 @@ a.table-action-link { } } - &:nth-child(even) { - background: var(--background-color); + &:last-child { + border-radius: 0 0 4px 4px; } &__content { diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss index dd349526ad..ac419b4570 100644 --- a/app/javascript/flavours/glitch/styles/widgets.scss +++ b/app/javascript/flavours/glitch/styles/widgets.scss @@ -211,7 +211,7 @@ display: flex; align-items: center; justify-content: space-between; - border: 1px solid lighten($ui-base-color, 8%); + border: 1px solid var(--background-border-color); border-radius: 4px; padding: 15px; text-decoration: none; diff --git a/app/javascript/mastodon/components/dropdown_selector.tsx b/app/javascript/mastodon/components/dropdown_selector.tsx new file mode 100644 index 0000000000..f8bf96c634 --- /dev/null +++ b/app/javascript/mastodon/components/dropdown_selector.tsx @@ -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 = ({ + style, + items, + value, + classNamePrefix = 'privacy-dropdown', + onClose, + onChange, +}) => { + const nodeRef = useRef(null); + const focusedItemRef = useRef(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 | React.KeyboardEvent, + ) => { + const value = e.currentTarget.getAttribute('data-index'); + + e.preventDefault(); + + onClose(); + if (value) onChange(value); + }, + [onClose, onChange], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + 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 ( +
    + {items.map((item) => ( +
  • + {item.icon && item.iconComponent && ( +
    + +
    + )} + +
    + {item.text} + {item.meta} +
    + + {item.extra && ( +
    + +
    + )} +
  • + ))} +
+ ); +}; diff --git a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx index 071f0a6fab..f474aecf28 100644 --- a/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx +++ b/app/javascript/mastodon/features/compose/components/privacy_dropdown.jsx @@ -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 PublicIcon from '@/material-icons/400-24px/public.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 { PrivacyDropdownMenu } from './privacy_dropdown_menu'; - const messages = defineMessages({ public_short: { id: 'privacy.public.short', defaultMessage: 'Public' }, public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' }, @@ -143,7 +142,7 @@ class PrivacyDropdown extends PureComponent { {({ props, placement }) => (
- { - 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 ( -
    - {items.map(item => ( -
  • -
    - -
    - -
    - {item.text} - {item.meta} -
    - - {item.extra && ( -
    - -
    - )} -
  • - ))} -
- ); -}; - -PrivacyDropdownMenu.propTypes = { - style: PropTypes.object, - items: PropTypes.array.isRequired, - value: PropTypes.string.isRequired, - onClose: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, -}; diff --git a/app/javascript/mastodon/features/notifications/components/policy_controls.tsx b/app/javascript/mastodon/features/notifications/components/policy_controls.tsx index 1647bf6b45..d6bc412994 100644 --- a/app/javascript/mastodon/features/notifications/components/policy_controls.tsx +++ b/app/javascript/mastodon/features/notifications/components/policy_controls.tsx @@ -7,6 +7,9 @@ import { useAppSelector, useAppDispatch } from 'mastodon/store'; import { CheckboxWithLabel } from './checkbox_with_label'; +// eslint-disable-next-line @typescript-eslint/no-empty-function +const noop = () => {}; + export const PolicyControls: React.FC = () => { const dispatch = useAppDispatch(); @@ -135,6 +138,21 @@ export const PolicyControls: React.FC = () => { /> + + + + + + + + +
); diff --git a/app/javascript/mastodon/features/notifications/request.jsx b/app/javascript/mastodon/features/notifications/request.jsx index 7cba946165..30ec004e70 100644 --- a/app/javascript/mastodon/features/notifications/request.jsx +++ b/app/javascript/mastodon/features/notifications/request.jsx @@ -1,7 +1,7 @@ import PropTypes from 'prop-types'; import { useRef, useCallback, useEffect } from 'react'; -import { defineMessages, useIntl } from 'react-intl'; +import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; 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') }); + let explainer = null; + + if (account?.limited) { + const isLocal = account.acct.indexOf('@') === -1; + explainer = ( +
+
+ {isLocal ? ( + + ) : ( + + )} +
+
+ ); + } + return ( { ( state.lastReadId, action.payload.markers.notifications.last_read_id, ) < 0 - ) + ) { state.lastReadId = action.payload.markers.notifications.last_read_id; + state.readMarkerId = + action.payload.markers.notifications.last_read_id; + } }) .addCase(mountNotifications, (state) => { state.mounted += 1; diff --git a/app/javascript/material-icons/400-24px/arrow_left_alt.svg b/app/javascript/material-icons/400-24px/arrow_left_alt.svg new file mode 100644 index 0000000000..a2b57a7f3c --- /dev/null +++ b/app/javascript/material-icons/400-24px/arrow_left_alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/breaking_news.svg b/app/javascript/material-icons/400-24px/breaking_news.svg new file mode 100644 index 0000000000..d7dd0c12f4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/breaking_news.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/captive_portal.svg b/app/javascript/material-icons/400-24px/captive_portal.svg new file mode 100644 index 0000000000..1f0f09c773 --- /dev/null +++ b/app/javascript/material-icons/400-24px/captive_portal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/chat_bubble.svg b/app/javascript/material-icons/400-24px/chat_bubble.svg new file mode 100644 index 0000000000..7d210b4608 --- /dev/null +++ b/app/javascript/material-icons/400-24px/chat_bubble.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud.svg b/app/javascript/material-icons/400-24px/cloud.svg new file mode 100644 index 0000000000..75b4e957fc --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_download.svg b/app/javascript/material-icons/400-24px/cloud_download.svg new file mode 100644 index 0000000000..2fc3717ff9 --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud_download.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_sync.svg b/app/javascript/material-icons/400-24px/cloud_sync.svg new file mode 100644 index 0000000000..dbf6adc000 --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud_sync.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/cloud_upload.svg b/app/javascript/material-icons/400-24px/cloud_upload.svg new file mode 100644 index 0000000000..5e1a4b9aef --- /dev/null +++ b/app/javascript/material-icons/400-24px/cloud_upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/code.svg b/app/javascript/material-icons/400-24px/code.svg index 8ef5c55cd4..5bdc338f7f 100644 --- a/app/javascript/material-icons/400-24px/code.svg +++ b/app/javascript/material-icons/400-24px/code.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/comment.svg b/app/javascript/material-icons/400-24px/comment.svg new file mode 100644 index 0000000000..da1ae0392e --- /dev/null +++ b/app/javascript/material-icons/400-24px/comment.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/computer.svg b/app/javascript/material-icons/400-24px/computer.svg new file mode 100644 index 0000000000..8c5bd9110e --- /dev/null +++ b/app/javascript/material-icons/400-24px/computer.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/contact_mail.svg b/app/javascript/material-icons/400-24px/contact_mail.svg new file mode 100644 index 0000000000..1ae26cc4d1 --- /dev/null +++ b/app/javascript/material-icons/400-24px/contact_mail.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/database.svg b/app/javascript/material-icons/400-24px/database.svg new file mode 100644 index 0000000000..54ca2f4e56 --- /dev/null +++ b/app/javascript/material-icons/400-24px/database.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/diamond.svg b/app/javascript/material-icons/400-24px/diamond.svg new file mode 100644 index 0000000000..26f4814b44 --- /dev/null +++ b/app/javascript/material-icons/400-24px/diamond.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/filter_alt.svg b/app/javascript/material-icons/400-24px/filter_alt.svg new file mode 100644 index 0000000000..0294cf1da5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/filter_alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/groups.svg b/app/javascript/material-icons/400-24px/groups.svg new file mode 100644 index 0000000000..0e795eb301 --- /dev/null +++ b/app/javascript/material-icons/400-24px/groups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/hide_source.svg b/app/javascript/material-icons/400-24px/hide_source.svg new file mode 100644 index 0000000000..d103ed770a --- /dev/null +++ b/app/javascript/material-icons/400-24px/hide_source.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/hourglass.svg b/app/javascript/material-icons/400-24px/hourglass.svg new file mode 100644 index 0000000000..07667a06e4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/hourglass.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/inbox.svg b/app/javascript/material-icons/400-24px/inbox.svg new file mode 100644 index 0000000000..427817958c --- /dev/null +++ b/app/javascript/material-icons/400-24px/inbox.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/keyboard_double_arrow_down.svg b/app/javascript/material-icons/400-24px/keyboard_double_arrow_down.svg new file mode 100644 index 0000000000..45b6e420f4 --- /dev/null +++ b/app/javascript/material-icons/400-24px/keyboard_double_arrow_down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/list.svg b/app/javascript/material-icons/400-24px/list.svg new file mode 100644 index 0000000000..457a820ab1 --- /dev/null +++ b/app/javascript/material-icons/400-24px/list.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/mail.svg b/app/javascript/material-icons/400-24px/mail.svg index 15e1d12d4e..a92ea7b198 100644 --- a/app/javascript/material-icons/400-24px/mail.svg +++ b/app/javascript/material-icons/400-24px/mail.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/manufacturing.svg b/app/javascript/material-icons/400-24px/manufacturing.svg index f19180759c..e0946f5ba5 100644 --- a/app/javascript/material-icons/400-24px/manufacturing.svg +++ b/app/javascript/material-icons/400-24px/manufacturing.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/mood.svg b/app/javascript/material-icons/400-24px/mood.svg new file mode 100644 index 0000000000..27b3534244 --- /dev/null +++ b/app/javascript/material-icons/400-24px/mood.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/photo_camera.svg b/app/javascript/material-icons/400-24px/photo_camera.svg new file mode 100644 index 0000000000..4621435ce0 --- /dev/null +++ b/app/javascript/material-icons/400-24px/photo_camera.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/power.svg b/app/javascript/material-icons/400-24px/power.svg new file mode 100644 index 0000000000..023a3a31da --- /dev/null +++ b/app/javascript/material-icons/400-24px/power.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/power_off.svg b/app/javascript/material-icons/400-24px/power_off.svg new file mode 100644 index 0000000000..25edd4de10 --- /dev/null +++ b/app/javascript/material-icons/400-24px/power_off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/radio_button_checked.svg b/app/javascript/material-icons/400-24px/radio_button_checked.svg new file mode 100644 index 0000000000..a8ab2c9b9c --- /dev/null +++ b/app/javascript/material-icons/400-24px/radio_button_checked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/radio_button_unchecked.svg b/app/javascript/material-icons/400-24px/radio_button_unchecked.svg new file mode 100644 index 0000000000..37665285d5 --- /dev/null +++ b/app/javascript/material-icons/400-24px/radio_button_unchecked.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/report.svg b/app/javascript/material-icons/400-24px/report.svg new file mode 100644 index 0000000000..f281f0e1fa --- /dev/null +++ b/app/javascript/material-icons/400-24px/report.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/safety_check.svg b/app/javascript/material-icons/400-24px/safety_check.svg new file mode 100644 index 0000000000..f4eab46fb7 --- /dev/null +++ b/app/javascript/material-icons/400-24px/safety_check.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/save.svg b/app/javascript/material-icons/400-24px/save.svg new file mode 100644 index 0000000000..a86028d995 --- /dev/null +++ b/app/javascript/material-icons/400-24px/save.svg @@ -0,0 +1 @@ + diff --git a/app/javascript/material-icons/400-24px/speed.svg b/app/javascript/material-icons/400-24px/speed.svg new file mode 100644 index 0000000000..ceb855c684 --- /dev/null +++ b/app/javascript/material-icons/400-24px/speed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/sync_alt.svg b/app/javascript/material-icons/400-24px/sync_alt.svg new file mode 100644 index 0000000000..a3bbb26a7a --- /dev/null +++ b/app/javascript/material-icons/400-24px/sync_alt.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/material-icons/400-24px/trending_up.svg b/app/javascript/material-icons/400-24px/trending_up.svg new file mode 100644 index 0000000000..06f9ba2063 --- /dev/null +++ b/app/javascript/material-icons/400-24px/trending_up.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss index 0ad8e1028e..5684a99e51 100644 --- a/app/javascript/styles/mastodon-light/diff.scss +++ b/app/javascript/styles/mastodon-light/diff.scss @@ -496,11 +496,11 @@ html { .compose-form .autosuggest-textarea__textarea, .compose-form__highlightable, +.autosuggest-textarea__suggestions, .search__input, .search__popout, .emoji-mart-search input, .language-dropdown__dropdown .emoji-mart-search input, -// .strike-card, .poll__option input[type='text'] { background: darken($ui-base-color, 10%); } diff --git a/app/javascript/styles/mastodon/_mixins.scss b/app/javascript/styles/mastodon/_mixins.scss index 899b494e54..c2e4acba4d 100644 --- a/app/javascript/styles/mastodon/_mixins.scss +++ b/app/javascript/styles/mastodon/_mixins.scss @@ -7,7 +7,7 @@ background: $ui-base-color; color: $darker-text-color; border-radius: 4px; - border: 1px solid lighten($ui-base-color, 8%); + border: 1px solid var(--background-border-color); font-size: 17px; line-height: normal; margin: 0; diff --git a/app/javascript/styles/mastodon/admin.scss b/app/javascript/styles/mastodon/admin.scss index 4c8e647c54..a22d6522d5 100644 --- a/app/javascript/styles/mastodon/admin.scss +++ b/app/javascript/styles/mastodon/admin.scss @@ -13,7 +13,7 @@ $content-width: 840px; .icon { width: 16px; height: 16px; - vertical-align: middle; + vertical-align: top; margin: 0 2px; } diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 8d83fd8526..92690053d6 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -403,7 +403,7 @@ body > [data-popper-placement] { &__suggestions { box-shadow: var(--dropdown-shadow); 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; color: $secondary-text-color; font-size: 14px; @@ -3086,11 +3086,6 @@ $ui-header-logo-wordmark-width: 99px; .explore__search-header { display: flex; } - - .explore__search-results { - border: 0; - border-radius: 0; - } } .icon-with-badge { @@ -8789,10 +8784,13 @@ noscript { flex: 1 1 auto; display: flex; flex-direction: column; - border: 1px solid var(--background-border-color); - border-top: 0; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; + + @media screen and (min-width: $no-gap-breakpoint) { + border: 1px solid var(--background-border-color); + border-top: 0; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + } } .story { diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index 13a731f7f6..971e78f76f 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -441,11 +441,6 @@ code { border-radius: 4px; padding: 10px 16px; - &::placeholder { - color: $dark-text-color; - opacity: 1; - } - &:invalid { box-shadow: none; } @@ -607,8 +602,7 @@ code { inset-inline-end: 3px; top: 1px; padding: 10px; - padding-bottom: 9px; - font-size: 16px; + font-size: 14px; color: $dark-text-color; font-family: inherit; pointer-events: none; @@ -626,11 +620,6 @@ code { inset-inline-end: 0; bottom: 1px; width: 5px; - background-image: linear-gradient( - to right, - rgba(darken($ui-base-color, 10%), 0), - darken($ui-base-color, 10%) - ); } } } diff --git a/app/javascript/styles/mastodon/rtl.scss b/app/javascript/styles/mastodon/rtl.scss index 8d3efcb572..07fe96fc3a 100644 --- a/app/javascript/styles/mastodon/rtl.scss +++ b/app/javascript/styles/mastodon/rtl.scss @@ -35,16 +35,6 @@ body.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 { background: $ui-base-color url("data:image/svg+xml;utf8,") diff --git a/app/javascript/styles/mastodon/tables.scss b/app/javascript/styles/mastodon/tables.scss index 65f42d0467..4997ed9b84 100644 --- a/app/javascript/styles/mastodon/tables.scss +++ b/app/javascript/styles/mastodon/tables.scss @@ -273,8 +273,8 @@ a.table-action-link { } } - &:nth-child(even) { - background: var(--background-color); + &:last-child { + border-radius: 0 0 4px 4px; } &__content { diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss index 0d56bd9c48..da7d68ce8d 100644 --- a/app/javascript/styles/mastodon/widgets.scss +++ b/app/javascript/styles/mastodon/widgets.scss @@ -217,7 +217,7 @@ display: flex; align-items: center; justify-content: space-between; - border: 1px solid lighten($ui-base-color, 8%); + border: 1px solid var(--background-border-color); border-radius: 4px; padding: 15px; text-decoration: none; diff --git a/app/views/admin/custom_emojis/index.html.haml b/app/views/admin/custom_emojis/index.html.haml index 82fec554b0..6db97e2e8e 100644 --- a/app/views/admin/custom_emojis/index.html.haml +++ b/app/views/admin/custom_emojis/index.html.haml @@ -49,15 +49,15 @@ = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - 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_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) = 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') } diff --git a/app/views/admin/instances/_instance.html.haml b/app/views/admin/instances/_instance.html.haml index 522a2444bb..4cae3caf52 100644 --- a/app/views/admin/instances/_instance.html.haml +++ b/app/views/admin/instances/_instance.html.haml @@ -1,7 +1,7 @@ .directory__tag = link_to admin_instance_path(instance) do %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 %small diff --git a/app/views/admin/relays/_relay.html.haml b/app/views/admin/relays/_relay.html.haml index 0960124ccf..2e76f54308 100644 --- a/app/views/admin/relays/_relay.html.haml +++ b/app/views/admin/relays/_relay.html.haml @@ -8,7 +8,7 @@   = t 'admin.relays.enabled' - elsif relay.pending? - = fa_icon('hourglass') + = material_symbol('hourglass')   = t 'admin.relays.pending' - else diff --git a/app/views/admin/reports/_status.html.haml b/app/views/admin/reports/_status.html.haml index 66820f0a6e..11be38ef84 100644 --- a/app/views/admin/reports/_status.html.haml +++ b/app/views/admin/reports/_status.html.haml @@ -30,7 +30,7 @@ %span.negative-hint= t('admin.statuses.deleted') · - 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)) - else = fa_visibility_icon(status) diff --git a/app/views/admin/reports/index.html.haml b/app/views/admin/reports/index.html.haml index dae2c1aa5b..b476c6ccfa 100644 --- a/app/views/admin/reports/index.html.haml +++ b/app/views/admin/reports/index.html.haml @@ -61,11 +61,11 @@ .one-line= report.comment.presence || t('admin.reports.comment.none') %span.report-card__summary__item__content__icon{ title: t('admin.accounts.statuses') } - = fa_icon('comment') + = material_symbol('comment') = report.status_ids.size %span.report-card__summary__item__content__icon{ title: t('admin.accounts.media_attachments') } - = fa_icon('camera') + = material_symbol('photo_camera') = report.media_attachments_count - if report.forwarded? diff --git a/app/views/admin/reports/show.html.haml b/app/views/admin/reports/show.html.haml index ca1edea0fe..69e9c02921 100644 --- a/app/views/admin/reports/show.html.haml +++ b/app/views/admin/reports/show.html.haml @@ -35,7 +35,7 @@ = t 'admin.reports.statuses' %small.section-skip-link = link_to '#actions' do - = fa_icon 'angle-double-down' + = material_symbol 'keyboard_double_arrow_down' = t('admin.reports.skip_to_actions') %p diff --git a/app/views/admin/settings/appearance/show.html.haml b/app/views/admin/settings/appearance/show.html.haml index d5e6c13bc9..f350956c87 100644 --- a/app/views/admin/settings/appearance/show.html.haml +++ b/app/views/admin/settings/appearance/show.html.haml @@ -38,7 +38,7 @@ - if @admin_settings.mascot.persisted? = 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 - = fa_icon 'trash fw' + = material_symbol 'delete' = t('admin.site_uploads.delete') .actions diff --git a/app/views/admin/settings/branding/show.html.haml b/app/views/admin/settings/branding/show.html.haml index 71aac5ead1..e03c16a25a 100644 --- a/app/views/admin/settings/branding/show.html.haml +++ b/app/views/admin/settings/branding/show.html.haml @@ -37,7 +37,7 @@ - if @admin_settings.thumbnail.persisted? = 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 - = fa_icon 'trash fw' + = material_symbol 'delete' = t('admin.site_uploads.delete') .fields-row @@ -51,7 +51,7 @@ - if @admin_settings.favicon.persisted? = 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 - = fa_icon 'trash fw' + = material_symbol 'delete' = t('admin.site_uploads.delete') .fields-row @@ -65,7 +65,7 @@ - if @admin_settings.app_icon.persisted? = 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 - = fa_icon 'trash fw' + = material_symbol 'delete' = t('admin.site_uploads.delete') .actions diff --git a/app/views/admin/settings/shared/_links.html.haml b/app/views/admin/settings/shared/_links.html.haml index f9b41b5814..7e45dfa60c 100644 --- a/app/views/admin/settings/shared/_links.html.haml +++ b/app/views/admin/settings/shared/_links.html.haml @@ -1,10 +1,10 @@ .content__heading__tabs = render_navigation renderer: :links do |primary| :ruby - primary.item :branding, safe_join([fa_icon('pencil fw'), 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 :branding, safe_join([material_symbol('edit'), t('admin.settings.branding.title')]), admin_settings_branding_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 :discovery, safe_join([fa_icon('search fw'), 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 :appearance, safe_join([fa_icon('desktop fw'), 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 :discovery, safe_join([material_symbol('search'), t('admin.settings.discovery.title')]), admin_settings_discovery_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([material_symbol('computer'), t('admin.settings.appearance.title')]), admin_settings_appearance_path + primary.item :other, safe_join([material_symbol('more_horiz'), t('admin.settings.other.title')]), admin_settings_other_path diff --git a/app/views/admin/statuses/index.html.haml b/app/views/admin/statuses/index.html.haml index b03b8ac51b..4d5d037060 100644 --- a/app/views/admin/statuses/index.html.haml +++ b/app/views/admin/statuses/index.html.haml @@ -33,7 +33,7 @@ = check_box_tag :batch_checkbox_all, nil, false .batch-table__toolbar__actions - 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', data: { confirm: t('admin.reports.are_you_sure') }, name: :report, diff --git a/app/views/admin/webhooks/_webhook.html.haml b/app/views/admin/webhooks/_webhook.html.haml index 6b3e49eba0..39abb7dd2c 100644 --- a/app/views/admin/webhooks/_webhook.html.haml +++ b/app/views/admin/webhooks/_webhook.html.haml @@ -1,6 +1,6 @@ .applications-list__item = link_to admin_webhook_path(webhook), class: 'announcements-list__item__title' do - = fa_icon 'inbox' + = material_symbol 'inbox' = webhook.url .announcements-list__item__action-bar diff --git a/app/views/admin/webhooks/show.html.haml b/app/views/admin/webhooks/show.html.haml index 5ac809efc5..c2c4f55788 100644 --- a/app/views/admin/webhooks/show.html.haml +++ b/app/views/admin/webhooks/show.html.haml @@ -5,7 +5,7 @@ .content__heading__row %h2 %small - = fa_icon 'inbox' + = material_symbol 'inbox' = t('admin.webhooks.webhook') = @webhook.url .content__heading__actions diff --git a/app/views/settings/featured_tags/index.html.haml b/app/views/settings/featured_tags/index.html.haml index c8c9ec4069..4b6c019e69 100644 --- a/app/views/settings/featured_tags/index.html.haml +++ b/app/views/settings/featured_tags/index.html.haml @@ -24,7 +24,7 @@ .directory__tag %div %h4 - = fa_icon 'hashtag' + = material_symbol 'tag' = featured_tag.display_name %small - if featured_tag.last_status_at.nil? diff --git a/app/views/settings/login_activities/_login_activity.html.haml b/app/views/settings/login_activities/_login_activity.html.haml index 36314926a3..d003058aea 100644 --- a/app/views/settings/login_activities/_login_activity.html.haml +++ b/app/views/settings/login_activities/_login_activity.html.haml @@ -2,7 +2,7 @@ .log-entry__header .log-entry__avatar .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__title = login_activity_title(login_activity) diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index 34ce85ab15..61ba79c449 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -43,7 +43,7 @@ = image_tag @account.avatar.url, class: 'fields-group__thumbnail', id: 'account_avatar-preview' - if @account.avatar.present? = 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') .fields-row @@ -59,7 +59,7 @@ = image_tag @account.header.url, class: 'fields-group__thumbnail', id: 'account_header-preview' - if @account.header.present? = 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') %h4= t('edit_profile.other') diff --git a/app/views/settings/shared/_profile_navigation.html.haml b/app/views/settings/shared/_profile_navigation.html.haml index 3a657c5bde..d490bd7566 100644 --- a/app/views/settings/shared/_profile_navigation.html.haml +++ b/app/views/settings/shared/_profile_navigation.html.haml @@ -1,7 +1,7 @@ .content__heading__tabs = render_navigation renderer: :links do |primary| :ruby - primary.item :profile, safe_join([fa_icon('user fw'), t('settings.edit_profile')]), settings_profile_path - primary.item :privacy, safe_join([fa_icon('lock fw'), t('privacy.title')]), settings_privacy_path - primary.item :verification, safe_join([fa_icon('check fw'), 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 :profile, safe_join([material_symbol('person'), t('settings.edit_profile')]), settings_profile_path + primary.item :privacy, safe_join([material_symbol('lock'), t('privacy.title')]), settings_privacy_path + primary.item :verification, safe_join([material_symbol('check'), t('verification.verification')]), settings_verification_path + primary.item :featured_tags, safe_join([material_symbol('tag'), t('settings.featured_tags')]), settings_featured_tags_path diff --git a/app/views/settings/two_factor_authentication_methods/index.html.haml b/app/views/settings/two_factor_authentication_methods/index.html.haml index 51141fab4f..2e4ff4091c 100644 --- a/app/views/settings/two_factor_authentication_methods/index.html.haml +++ b/app/views/settings/two_factor_authentication_methods/index.html.haml @@ -6,7 +6,7 @@ %p.hint %span.positive-hint - = fa_icon 'check' + = material_symbol 'check'   = t 'two_factor_authentication.enabled' diff --git a/app/views/settings/verifications/show.html.haml b/app/views/settings/verifications/show.html.haml index 94283d2050..4fb2918018 100644 --- a/app/views/settings/verifications/show.html.haml +++ b/app/views/settings/verifications/show.html.haml @@ -26,5 +26,5 @@ - @verified_links.each do |field| %li %span.verified-badge - = fa_icon 'check', class: 'verified-badge__mark' + = material_symbol 'check', class: 'verified-badge__mark' %span= field.value diff --git a/config/locales/devise.el.yml b/config/locales/devise.el.yml index 52674dc849..209dfe5bdf 100644 --- a/config/locales/devise.el.yml +++ b/config/locales/devise.el.yml @@ -12,6 +12,7 @@ el: last_attempt: Έχεις μια ακόμα προσπάθεια πριν κλειδωθεί ο λογαριασμός σου. locked: Ο λογαριασμός σου κλειδώθηκε. not_found_in_database: Λάθος %{authentication_keys} ή συνθηματικό. + omniauth_user_creation_failure: Σφάλμα δημιουργίας λογαριασμού για αυτήν την ταυτότητα. pending: Εκκρεμεί η έγκριση του λογαριασμού σου. timeout: Η τρέχουσα σύνδεσή σου έληξε. Παρακαλούμε συνδέσου ξανά για να συνεχίσεις. unauthenticated: Πρέπει να συνδεθείς ή να εγγραφείς για να συνεχίσεις. diff --git a/config/locales/doorkeeper.el.yml b/config/locales/doorkeeper.el.yml index 167cc6bd44..7fcd69c238 100644 --- a/config/locales/doorkeeper.el.yml +++ b/config/locales/doorkeeper.el.yml @@ -83,6 +83,7 @@ el: access_denied: Ο ιδιοκτήτης του πόρου ή του παρόχου έγκρισης απέρριψε το αίτημα. credential_flow_not_configured: Η ροή Resource Owner Password Credentials απέτυχε επειδή το Doorkeeper.configure.resource_owner_from_credentials δεν έχει ρυθμιστεί. invalid_client: Η ταυτοποίηση του πελάτη απέτυχε είτε λόγω άγνωστου πελάτη, είτε λόγω έλλειψης ταυτοποιημένου πελάτη ή λόγω μη υποστηριζόμενης μεθόδου ταυτοποίησης. + invalid_code_challenge_method: Η μέθοδος πρόκλησης κώδικα πρέπει να είναι S256, το απλό δεν υποστηρίζεται. invalid_grant: Η άδεια πιστοποίησης που δόθηκε είναι άκυρη, ληγμένη, έχει ανακληθεί, δεν συμφωνεί με το URI ανακατεύθυνσης που δόθηκε στο αίτημα πιστοποίησης ή εκδόθηκε προς άλλο πελάτη. invalid_redirect_uri: Το uri ανακατεύθυνσης που δόθηκε δεν είναι έγκυρο. invalid_request: diff --git a/config/locales/el.yml b/config/locales/el.yml index e177bf342a..009e1f82ed 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -286,6 +286,7 @@ el: update_custom_emoji_html: Ο/Η %{name} ενημέρωσε το emoji %{target} update_domain_block_html: Ο/Η %{name} ενημέρωσε τον αποκλεισμό τομέα για %{target} update_ip_block_html: Ο/Η %{name} άλλαξε τον κανόνα για την IP %{target} + update_report_html: Ο χρήστης %{name} ενημέρωσε την αναφορά %{target} update_status_html: Ο/Η %{name} ενημέρωσε την ανάρτηση του/της %{target} update_user_role_html: Ο/Η %{name} άλλαξε τον ρόλο %{target} deleted_account: διαγεγραμμένος λογαριασμός @@ -293,6 +294,7 @@ el: filter_by_action: Φιλτράρισμα ανά ενέργεια filter_by_user: Φιλτράρισμα ανά χρήστη title: Αρχείο ελέγχου + unavailable_instance: "(μη διαθέσιμο όνομα τομέα)" announcements: destroyed_msg: Επιτυχής διαγραφή ανακοίνωσης! edit: @@ -469,6 +471,9 @@ el: title: Ακολούθησε τις προτάσεις unsuppress: Επαναφορά των συστάσεων ακολούθησης instances: + audit_log: + title: Πρόσφατα Αρχεία Ελέγχου + view_all: Δείτε πλήρη αρχεία καταγραφής ελέγχων availability: description_html: one: Εάν η παράδοση στον τομέα αποτύχει για %{count} ημέρα, δεν θα γίνουν περαιτέρω προσπάθειες παράδοσης εκτός αν μια παράδοση από τον τομέα ληφθεί. @@ -598,6 +603,9 @@ el: actions_description_html: Αποφάσισε ποια μέτρα θα ληφθούν για την επίλυση αυτής της αναφοράς. Εάν προβείς σε τιμωρητική ενέργεια κατά του αναφερόμενου λογαριασμού, θα αποσταλεί ειδοποίηση μέσω ηλεκτρονικού ταχυδρομείου σε αυτόν, εκτός όταν η κατηγορία Σπαμ είναι επιλεγμένη. actions_description_remote_html: Αποφάσισε ποια μέτρα θα ληφθούν για την επίλυση αυτής της αναφοράς. Αυτό θα επηρεάσει μόνο το πώς ο δικός σας διακομιστής επικοινωνεί με αυτόν τον απομακρυσμένο λογαριασμό και χειρίζεται το περιεχόμενό του. add_to_report: Πρόσθεσε περισσότερα στην αναφορά + already_suspended_badges: + local: Ήδη σε αναστολή σε αυτόν τον διακομιστή + remote: Ήδη σε αναστολή στο διακομιστή του are_you_sure: Σίγουρα; assign_to_self: Ανάθεση σε μένα assigned: Αρμόδιος συντονιστής @@ -634,6 +642,7 @@ el: report: 'Αναφορά #%{id}' reported_account: Αναφερόμενος λογαριασμός reported_by: Αναφέρθηκε από + reported_with_application: Αναφέρθηκε με την εφαρμογή resolved: Επιλύθηκε resolved_msg: Η αναφορά επιλύθηκε επιτυχώς! skip_to_actions: Μετάβαση στις ενέργειες @@ -745,7 +754,11 @@ el: branding: preamble: Η ταυτότητα του διακομιστή σου, τον διαφοροποιεί από άλλους διακομιστές του δικτύου. Αυτές οι πληροφορίες μπορεί να εμφανίζονται σε διάφορα περιβάλλοντα, όπως η ιστοσελίδα του Mastodon, εγγενείς εφαρμογές, σε προεπισκοπήσεις συνδέσμου σε άλλους ιστότοπους και εντός εφαρμογών μηνυμάτων και ούτω καθεξής. Γι' αυτό, είναι καλύτερο να διατηρούνται αυτές οι πληροφορίες σαφείς, σύντομες και συνοπτικές. title: Ταυτότητα + captcha_enabled: + desc_html: Αυτό βασίζεται σε εξωτερικά scripts από το hCaptcha, όπου υπάρχει ανησυχία πέρι ασφάλειας και ιδιωτηκότητας. Επιπρόσθετα, μπορεί να κάνει τη διαδικασία εγγραφής πολύ λιγότερο προσβάσιμη για κάποια άτομα (ειδικά αυτά με αναπηρίες). Για αυτούς τους λόγους, παρακαλώ σκέψου άλλου τρόπους εγγραφής όπως με αποδοχή ή με πρόσκληση. + title: Απαιτείται από νέους χρήστες να λύσουν ένα CAPTCHA για να επιβεβαιώσουν τον λογαριασμό τους content_retention: + danger_zone: Επικίνδυνη Ζώνη preamble: Έλεγξε πώς αποθηκεύεται το περιεχόμενο που δημιουργείται από τους χρήστες στο Mastodon. title: Διατήρηση περιεχομένου default_noindex: @@ -765,6 +778,7 @@ el: disabled: Για κανέναν users: Προς συνδεδεμένους τοπικούς χρήστες registrations: + moderation_recommandation: Παρακαλώ βεβαιώσου ότι έχεις μια επαρκής και ενεργή ομάδα συντονισμού πριν ανοίξεις τις εγγραφές για όλους! preamble: Έλεγξε ποιος μπορεί να δημιουργήσει ένα λογαριασμό στον διακομιστή σας. title: Εγγραφές registrations_mode: @@ -772,9 +786,28 @@ el: approved: Απαιτείται έγκριση για εγγραφή none: Δεν μπορεί να εγγραφεί κανείς open: Μπορεί να εγγραφεί ο οποιοσδήποτε + warning_hint: Προτείνουμε τη χρήση του "Απαιτείται έγκριση για εγγραφή" εκτός αν ξέρεις ότι η ομάδα συντονισμού σου μπορεί να διαχειριστεί τις κακόβουλες και σπαμ εγγραφές σε εύλογο χρονικό διάστημα. + security: + authorized_fetch: Απαίτηση ταυτόποιησης από διακομιστές σε ομοσπονδία + authorized_fetch_hint: Η απαίτηση ελέγχου ταυτότητας από ομοσπονδιακούς διακομιστές επιτρέπει την αυστηρότερη επιβολή αποκλεισμού τόσο σε επίπεδο χρήστη όσο και σε επίπεδο διακομιστή. Ωστόσο, αυτό έχει το κόστος στην απόδοσης μειώνει την εμβέλεια των απαντήσεών σας και μπορεί να δημιουργήσει προβλήματα συμβατότητας με ορισμένες ομοσπονδιακές υπηρεσίες. Επιπλέον, αυτό δεν θα εμποδίσει τους αφοσιωμένους ηθοποιούς να ανακτήσουν τις δημόσιες αναρτήσεις και τους λογαριασμούς σας. + authorized_fetch_overridden_hint: Προς το παρόν, δε μπορείς να αλλάξεις αυτή την ρύθμιση επειδή παρακάμπτεται από μια μεταβλητή περιβάλλοντος. + federation_authentication: Επιβολή ομοσπονδιακής ταυτοποίησης + title: Ρυθμίσεις διακομιστή site_uploads: delete: Διαγραφή μεταφορτωμένου αρχείου destroyed_msg: Η μεταφόρτωση ιστότοπου διαγράφηκε επιτυχώς! + software_updates: + critical_update: Κρίσιμο - παρακαλώ ενημέρωσε γρήγορα + description: Συνιστάται να διατηρείς την εγκατάσταση του Mastodon ενημερωμένη για να επωφεληθείς από τις πιο πρόσφατες διορθώσεις και δυνατότητες. Επιπλέον, μερικές φορές είναι κρίσιμο να ενημερώσεις το Mastodon εγκαίρως για να αποφύγεις προβλήματα ασφαλείας. Για αυτούς τους λόγους, το Mastodon ελέγχει για ενημερώσεις κάθε 30 λεπτά και θα σας ειδοποιεί σύμφωνα με τις προτιμήσεις ειδοποίησης μέσω email. + documentation_link: Μάθε περισσότερα + release_notes: Σημειώσεις έκδοσης + title: Διαθέσιμες ενημερώσεις + type: Τύπος + types: + major: Κύρια έκδοση + minor: Τυπική ενημέρωση + patch: Ενημέρωση επιδιόρθωσης - διορθώσεις σφαλμάτων και εύκολα εφαρμόσιμες αλλαγές + version: Έκδοση statuses: account: Συντάκτης application: Εφαρμογή @@ -815,6 +848,20 @@ el: system_checks: database_schema_check: message_html: Υπάρχουν μετακινήσεις βάσεων δεδομένων που εκκρεμούν. Παρακαλώ εκτέλεσέ τες για να βεβαιωθείς ότι η εφαρμογή συμπεριφέρεται όπως αναμένεται + elasticsearch_health_red: + message_html: Το σύμπλεγμα Elasticsearch δεν είναι υγιές (κόκκινη κατάσταση), μη διαθέσιμες δυνατότητες αναζήτησης + elasticsearch_health_yellow: + message_html: Το σύμπλεγμα Elasticsearch δεν είναι υγιές (κίτρινη κατάσταση), ίσως θες να διαπιστώσεις την αιτία + elasticsearch_index_mismatch: + message_html: Οι αντιστοιχές δείκτη του Elasticsearch δεν είναι ενημερωμένες. Παρακαλώ εκτέλεσε το tootctl search deploy --only=%{value} + elasticsearch_preset: + action: Δες το εγχειρίδιο + message_html: Το σύμπλεγμα Elasticsearch σου, έχει παραπάνω από ένα κόμβο, το Mastodon δεν είναι ρυθμισμένο για να τους χρησιμοποιεί. + elasticsearch_preset_single_node: + action: Δες το εγχειρίδιο + message_html: Το σύμπλεγμα Elasticsearch σου έχει μόνο ένα κόμβο, το ES_PRESET πρέπει να οριστεί ως single_node_cluster. + elasticsearch_reset_chewy: + message_html: Ο δείκτης του συστήματος Elasticsearch είναι ξεπερασμένος λόγω μιας αλλαγής ρύθμισης. Παρακαλώ εκτέλεσε tootctl search deploy --reset-chewy για να τον ενημερώσεις. elasticsearch_running_check: message_html: Δεν ήταν δυνατή η σύνδεση στο Elasticsearch. Παρακαλώ έλεγξε ότι εκτελείται ή απενεργοποίησε την αναζήτηση πλήρους κειμένου elasticsearch_version_check: @@ -825,6 +872,12 @@ el: message_html: Δεν έχεις ορίσει κανέναν κανόνα διακομιστή. sidekiq_process_check: 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: action: Δες εδώ για περισσότερες πληροφορίες message_html: "Ο διακομιστής σας δεν έχει ρυθμιστεί σωστά. Το απόρρητο των χρηστών σας κινδυνεύει." @@ -832,6 +885,13 @@ el: action: Δες εδώ για περισσότερες πληροφορίες message_html: "Ο χώρος αποθήκευσης αντικειμένων σου δεν έχει ρυθμιστεί σωστά. Το απόρρητο των χρηστών σου κινδυνεύει." tags: + moderation: + not_trendable: Δε δημιουργεί τάσεις + not_usable: Μη χρησιμοποιήσιμη + pending_review: Εκκρεμεί αξιολόγηση + review_requested: Αιτήθηκε αξιολόγηση + reviewed: Αξιολογήθηκε + title: Κατάσταση review: Κατάσταση αξιολόγησης updated_msg: Οι ρυθμίσεις των ετικετών ενημερώθηκαν επιτυχώς title: Διαχείριση diff --git a/config/navigation.rb b/config/navigation.rb index 3a3f5c9783..7673e8b624 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -4,78 +4,78 @@ SimpleNavigation::Configuration.run do |navigation| self_destruct = SelfDestructHelper.self_destruct? 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| - s.item :appearance, safe_join([fa_icon('desktop fw'), 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 :other, safe_join([fa_icon('cog fw'), t('preferences.other')]), settings_preferences_other_path + 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([material_symbol('computer'), t('settings.appearance')]), settings_preferences_appearance_path + s.item :notifications, safe_join([material_symbol('mail'), t('settings.notifications')]), settings_preferences_notifications_path + s.item :other, safe_join([material_symbol('settings'), t('preferences.other')]), settings_preferences_other_path 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| - 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 - n.item :relationships, safe_join([fa_icon('users fw'), 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 :severed_relationships, safe_join([fa_icon('unlink fw'), t('settings.severed_relationships')]), severed_relationships_path + 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([material_symbol('groups'), t('settings.relationships')]), relationships_path + s.item :severed_relationships, safe_join([material_symbol('link_off'), t('settings.severed_relationships')]), severed_relationships_path 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 :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 :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([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| - 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 :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 :authorized_apps, safe_join([fa_icon('list fw'), t('settings.authorized_apps')]), oauth_authorized_applications_path, if: -> { !self_destruct } + n.item :security, safe_join([material_symbol('lock'), t('settings.account')]), edit_user_registration_path do |s| + 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([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([material_symbol('list_alt'), t('settings.authorized_apps')]), oauth_authorized_applications_path, if: -> { !self_destruct } end - n.item :data, safe_join([fa_icon('cloud-download fw'), 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 :export, safe_join([fa_icon('cloud-download fw'), t('settings.export')]), settings_export_path + n.item :data, safe_join([material_symbol('cloud_sync'), t('settings.import_and_export')]), settings_export_path do |s| + 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([material_symbol('cloud_download'), t('settings.export')]), settings_export_path 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 :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 :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([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| - 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 :tags, safe_join([fa_icon('hashtag fw'), 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} + 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([material_symbol('chat_bubble'), t('admin.trends.statuses.title')]), admin_trends_statuses_path, highlights_on: %r{/admin/trends/statuses} + 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([material_symbol('breaking_news'), t('admin.trends.links.title')]), admin_trends_links_path, highlights_on: %r{/admin/trends/links} 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| - 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 :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 :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 :invites, safe_join([fa_icon('user-plus fw'), 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 :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 :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 :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 :action_logs, safe_join([fa_icon('bars fw'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) } + 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([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([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([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([material_symbol('person_add'), t('admin.invites.title')]), admin_invites_path, if: -> { current_user.can?(:manage_invites) } + 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([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([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([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([material_symbol('list'), t('admin.action_logs.title')]), admin_action_logs_path, if: -> { current_user.can?(:view_audit_log) } 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| - s.item :dashboard, safe_join([fa_icon('tachometer fw'), 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 :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 :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 :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 :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 :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 :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 :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) } + 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([material_symbol('speed'), t('admin.dashboard.title')]), admin_dashboard_path, if: -> { current_user.can?(:view_dashboard) } + 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([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([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([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([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([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([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([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 - n.item :sidekiq, safe_join([fa_icon('diamond fw'), '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 :logout, safe_join([fa_icon('sign-out fw'), t('auth.logout')]), destroy_user_session_path, link_html: { 'data-method' => 'delete' } + 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([material_symbol('database'), 'PgHero']), pghero_path, link_html: { target: 'pghero' }, if: -> { current_user.can?(:view_devops) } + n.item :logout, safe_join([material_symbol('logout'), t('auth.logout')]), destroy_user_session_path, link_html: { 'data-method' => 'delete' } end end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index 2a472d75a6..12202539d8 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -225,7 +225,7 @@ describe ApplicationHelper do it 'returns an unlock icon for a unlisted visible status' do result = helper.visibility_icon Status.new(visibility: 'unlisted') - expect(result).to match(/unlock/) + expect(result).to match(/lock_open/) end 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 result = helper.visibility_icon Status.new(visibility: 'direct') - expect(result).to match(/at/) + expect(result).to match(/alternate_email/) end end diff --git a/spec/helpers/statuses_helper_spec.rb b/spec/helpers/statuses_helper_spec.rb index 73d7d80e46..ba6fe361d9 100644 --- a/spec/helpers/statuses_helper_spec.rb +++ b/spec/helpers/statuses_helper_spec.rb @@ -36,7 +36,7 @@ describe StatusesHelper do it 'returns the correct fa icon' do result = helper.fa_visibility_icon(status) - expect(result).to match('fa-globe') + expect(result).to match('material-globe') end end @@ -46,7 +46,7 @@ describe StatusesHelper do it 'returns the correct fa icon' do result = helper.fa_visibility_icon(status) - expect(result).to match('fa-unlock') + expect(result).to match('material-lock_open') end end @@ -56,7 +56,7 @@ describe StatusesHelper do it 'returns the correct fa icon' do result = helper.fa_visibility_icon(status) - expect(result).to match('fa-lock') + expect(result).to match('material-lock') end end @@ -66,7 +66,7 @@ describe StatusesHelper do it 'returns the correct fa icon' do result = helper.fa_visibility_icon(status) - expect(result).to match('fa-at') + expect(result).to match('material-alternate_email') end end end