diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2369cff7e65140..ed89d815634945 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -116,7 +116,7 @@ def fa_icon(icon, attributes = {}) 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 @@ def check_icon 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 ca693a8a78a9af..d956e4fcd8fb29 100644 --- a/app/helpers/statuses_helper.rb +++ b/app/helpers/statuses_helper.rb @@ -60,13 +60,13 @@ def stream_link_target 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 00000000000000..f8bf96c634294a --- /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 9774d4260eb462..55830f0a92723e 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 58eff3fbcf2d5c..5982db29239ba4 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 b95533aa3638f5..3dd186f2bfa753 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 444d2e01609641..f139bef21b5ef1 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 110d5f249d7f94..08c0a08be368d5 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 b8647cd559fe1b..cd1b04d2848053 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 4877170275f470..d206af1f189e3a 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 e97b40d3f744f4..73ec36c1b68bf8 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 1091a13238a73b..3f03051ce19776 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 dd73f6e2055f1b..992ad0cbe4e548 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 dd349526ade2ec..ac419b4570dda7 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 00000000000000..f8bf96c634294a --- /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 071f0a6fabf399..f474aecf284932 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 1647bf6b45682a..d6bc412994161b 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 7cba9461659ab1..30ec004e707bc2 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 00000000000000..a2b57a7f3c1c44 --- /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 00000000000000..d7dd0c12f47fec --- /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 00000000000000..1f0f09c7734912 --- /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 00000000000000..7d210b460865ee --- /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 00000000000000..75b4e957fc416a --- /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 00000000000000..2fc3717ff9e35e --- /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 00000000000000..dbf6adc0001ada --- /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 00000000000000..5e1a4b9aef684f --- /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 8ef5c55cd48598..5bdc338f7f5bc6 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 00000000000000..da1ae0392e7329 --- /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 00000000000000..8c5bd9110e1d23 --- /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 00000000000000..1ae26cc4d157ed --- /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 00000000000000..54ca2f4e560b2e --- /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 00000000000000..26f4814b443b95 --- /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 00000000000000..0294cf1da53ac0 --- /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 00000000000000..0e795eb301d89d --- /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 00000000000000..d103ed770a5d6b --- /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 00000000000000..07667a06e4995d --- /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 00000000000000..427817958c169a --- /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 00000000000000..45b6e420f46692 --- /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 00000000000000..457a820ab1781b --- /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 15e1d12d4e1a21..a92ea7b198a82f 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 f19180759c0df3..e0946f5ba52434 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 00000000000000..27b3534244888c --- /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 00000000000000..4621435ce097ac --- /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 00000000000000..023a3a31daf5d8 --- /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 00000000000000..25edd4de108108 --- /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 00000000000000..a8ab2c9b9c3dcd --- /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 00000000000000..37665285d5eda6 --- /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 00000000000000..f281f0e1fa8f01 --- /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 00000000000000..f4eab46fb75b82 --- /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 00000000000000..a86028d9955c73 --- /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 00000000000000..ceb855c684f8c3 --- /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 00000000000000..a3bbb26a7a364f --- /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 00000000000000..06f9ba20639860 --- /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 0ad8e1028ea231..5684a99e519727 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 899b494e549312..c2e4acba4d649f 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 4c8e647c54fdc5..a22d6522d50175 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 8d83fd85268518..92690053d68ad6 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 13a731f7f6392e..971e78f76f57c4 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 8d3efcb5726197..07fe96fc3ad1f1 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 65f42d0467b747..4997ed9b847611 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 0d56bd9c48bc71..da7d68ce8db39d 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 82fec554b03345..6db97e2e8e973c 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 522a2444bb9d6b..4cae3caf5251f2 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 0960124ccfae4e..2e76f5430838be 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 66820f0a6e7fb2..11be38ef845106 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 dae2c1aa5bb7e3..b476c6ccfa0342 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 ca1edea0fe3148..69e9c02921ea51 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 d5e6c13bc944f9..f350956c87a829 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 71aac5ead1c1f0..e03c16a25a88f8 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 f9b41b5814aadc..7e45dfa60c1d3e 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 b03b8ac51b9002..4d5d03706084d1 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 6b3e49eba0a44a..39abb7dd2c7608 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 5ac809efc55907..c2c4f55788e38a 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 c8c9ec4069fb7b..4b6c019e69b250 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 36314926a3dbdd..d003058aea61ec 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 34ce85ab15101c..61ba79c4491f02 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 3a657c5bded7ad..d490bd75661704 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 51141fab4fd2eb..2e4ff4091c7b51 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 94283d2050eb41..4fb2918018413f 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 52674dc8493994..209dfe5bdf8ae2 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 167cc6bd44e99b..7fcd69c2384b53 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 e177bf342afc75..009e1f82edffc9 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 3a3f5c97830cb5..7673e8b62450ec 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -4,78 +4,78 @@ 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 2a472d75a60f72..12202539d85335 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -225,7 +225,7 @@ def current_skin = 'default' 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 @@ def current_skin = 'default' 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 73d7d80e46043f..ba6fe361d96685 100644 --- a/spec/helpers/statuses_helper_spec.rb +++ b/spec/helpers/statuses_helper_spec.rb @@ -36,7 +36,7 @@ def status_text_summary(status) 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 @@ def status_text_summary(status) 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 @@ def status_text_summary(status) 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 @@ def status_text_summary(status) 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