resolve conflichts

This commit is contained in:
Absturztaube 2020-12-04 20:45:10 +01:00
commit ad728d9046
83 changed files with 7208 additions and 1534 deletions

View File

@ -5,15 +5,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [Unreleased]
### Added
- Mouseover titles for emojis in reaction picker
- Support to input emoji into the search box in reaction picker
- Added some missing unicode emoji
### Fixed
- Fixed the occasional bug where screen would scroll 1px when typing into a reply form
- Fixed timeline errors locking timelines
- Fixed missing highlighted border in expanded conversations
- Fixed custom emoji not working in profile field names
- Fixed pinned statuses not appearing in user profiles
- Fixed some elements not being keyboard navigation friendly
- Fixed your latest chat messages disappearing when closing chat view and opening it again during the same session
### Changed
- Errors when fetching are now shown with popup errors instead of "Error fetching updates" in panel headers
- Fixed custom emoji not working in profile field names
- Fixed pinned statuses not appearing in user profiles
- Made reply/fav/repeat etc buttons easier to hit
## [2.2.1] - 2020-11-11

View File

@ -33,6 +33,7 @@ h4 {
max-width: 980px;
align-content: flex-start;
}
.underlay {
background-color: rgba(0,0,0,0.15);
background-color: var(--underlay, rgba(0,0,0,0.15));
@ -69,7 +70,7 @@ a {
color: var(--link, $fallback--link);
}
button {
.button-default {
user-select: none;
color: $fallback--text;
color: var(--btnText, $fallback--text);
@ -85,7 +86,8 @@ button {
font-family: sans-serif;
font-family: var(--interfaceFont, sans-serif);
i[class*=icon-], .svg-inline--fa {
i[class*=icon-],
.svg-inline--fa {
color: $fallback--text;
color: var(--btnText, $fallback--text);
}
@ -107,7 +109,8 @@ button {
background-color: $fallback--fg;
background-color: var(--btnPressed, $fallback--fg);
svg, i {
svg,
i {
color: $fallback--text;
color: var(--btnPressedText, $fallback--text);
}
@ -120,7 +123,8 @@ button {
background-color: $fallback--fg;
background-color: var(--btnDisabled, $fallback--fg);
svg, i {
svg,
i {
color: $fallback--text;
color: var(--btnDisabledText, $fallback--text);
}
@ -134,7 +138,8 @@ button {
box-shadow: 0px 0px 4px 0px rgba(255, 255, 255, 0.3), 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
box-shadow: var(--buttonPressedShadow);
svg, i {
svg,
i {
color: $fallback--text;
color: var(--btnToggledText, $fallback--text);
}
@ -149,6 +154,30 @@ button {
}
}
.button-unstyled {
background: none;
border: none;
outline: none;
display: inline;
text-align: initial;
font-size: 100%;
font-family: inherit;
padding: 0;
line-height: unset;
cursor: pointer;
box-sizing: content-box;
color: inherit;
&.-link {
color: $fallback--link;
color: var(--link, $fallback--link);
}
&.-fullwidth {
width: 100%;
}
}
input, textarea, .select, .input {
&.unstyled {
@ -442,6 +471,7 @@ main-router {
color: $fallback--faint;
color: var(--panelFaint, $fallback--faint);
}
.faint-link {
color: $fallback--faint;
color: var(--faintLink, $fallback--faint);
@ -453,11 +483,8 @@ main-router {
overflow-x: hidden;
}
button {
flex-shrink: 0;
}
button, .alert {
.button-default,
.alert {
// height: 100%;
line-height: 21px;
min-height: 0;
@ -468,8 +495,11 @@ main-router {
align-self: stretch;
}
button {
&, i[class*=icon-] {
.button-default {
flex-shrink: 0;
&,
i[class*=icon-] {
color: $fallback--text;
color: var(--btnPanelText, $fallback--text);
}
@ -492,7 +522,8 @@ main-router {
}
}
a {
a,
.-link {
color: $fallback--link;
color: var(--panelLink, $fallback--link)
}
@ -507,15 +538,15 @@ main-router {
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
.faint {
color: $fallback--faint;
color: var(--panelFaint, $fallback--faint);
}
a {
a,
.-link {
color: $fallback--link;
color: var(--panelLink, $fallback--link)
color: var(--panelLink, $fallback--link);
}
}
@ -797,7 +828,7 @@ nav {
}
}
.btn.btn-default {
.btn.button-default {
min-height: 28px;
}

View File

@ -4,6 +4,7 @@
trigger="click"
placement="bottom"
:bound-to="{ x: 'container' }"
remove-padding
>
<div
slot="content"
@ -13,14 +14,14 @@
<template v-if="relationship.following">
<button
v-if="relationship.showing_reblogs"
class="btn btn-default dropdown-item"
class="btn button-default dropdown-item"
@click="hideRepeats"
>
{{ $t('user_card.hide_repeats') }}
</button>
<button
v-if="!relationship.showing_reblogs"
class="btn btn-default dropdown-item"
class="btn button-default dropdown-item"
@click="showRepeats"
>
{{ $t('user_card.show_repeats') }}
@ -32,27 +33,27 @@
</template>
<button
v-if="relationship.blocking"
class="btn btn-default btn-block dropdown-item"
class="btn button-default btn-block dropdown-item"
@click="unblockUser"
>
{{ $t('user_card.unblock') }}
</button>
<button
v-else
class="btn btn-default btn-block dropdown-item"
class="btn button-default btn-block dropdown-item"
@click="blockUser"
>
{{ $t('user_card.block') }}
</button>
<button
class="btn btn-default btn-block dropdown-item"
class="btn button-default btn-block dropdown-item"
@click="reportUser"
>
{{ $t('user_card.report') }}
</button>
<button
v-if="pleromaChatMessagesAvailable"
class="btn btn-default btn-block dropdown-item"
class="btn button-default btn-block dropdown-item"
@click="openChat"
>
{{ $t('user_card.message') }}
@ -61,7 +62,7 @@
</div>
<div
slot="trigger"
class="btn btn-default ellipsis-button"
class="ellipsis-button"
>
<FAIcon
class="icon"

View File

@ -8,7 +8,7 @@
{{ $t('general.error_retry') }}
</p>
<button
class="btn"
class="btn button-default"
@click="retry"
>
{{ $t('general.retry') }}

View File

@ -9,7 +9,8 @@ import {
faMusic,
faImage,
faVideo,
faPlayCircle
faPlayCircle,
faTimes
} from '@fortawesome/free-solid-svg-icons'
library.add(
@ -17,7 +18,8 @@ library.add(
faMusic,
faImage,
faVideo,
faPlayCircle
faPlayCircle,
faTimes
)
const Attachment = {

View File

@ -42,15 +42,13 @@
icon="play-circle"
/>
</a>
<div
<button
v-if="nsfw && hideNsfwLocal && !hidden"
class="hider"
class="button-unstyled hider"
@click.prevent="toggleHidden"
>
<a
href="#"
@click.prevent="toggleHidden"
>Hide</a>
</div>
<FAIcon icon="times" />
</button>
<a
v-if="type === 'image' && (!hidden || preloadImage)"
@ -234,15 +232,23 @@
.hider {
position: absolute;
right: 0;
white-space: nowrap;
margin: 10px;
padding: 5px;
background: rgba(230,230,230,0.6);
font-weight: bold;
padding: 0;
z-index: 4;
line-height: 1;
border-radius: $fallback--tooltipRadius;
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
text-align: center;
width: 2em;
height: 2em;
font-size: 1.25em;
// TODO: theming? hard to theme with unknown background image color
background: rgba(230, 230, 230, 0.7);
.svg-inline--fa {
color: rgba(0, 0, 0, 0.6);
}
&:hover .svg-inline--fa {
color: rgba(0, 0, 0, 0.9);
}
}
video {

View File

@ -3,7 +3,7 @@
<div class="block-card-content-container">
<button
v-if="blocked"
class="btn btn-default"
class="btn button-default"
:disabled="progress"
@click="unblockUser"
>
@ -16,7 +16,7 @@
</button>
<button
v-else
class="btn btn-default"
class="btn button-default"
:disabled="progress"
@click="blockUser"
>

View File

@ -10,7 +10,10 @@
<span class="title">
{{ $t("chats.chats") }}
</span>
<button @click="newChat">
<button
class="button-default"
@click="newChat"
>
{{ $t("chats.new") }}
</button>
</div>

View File

@ -31,9 +31,6 @@
color: $fallback--text;
color: var(--text, $fallback--text);
}
border-radius: $fallback--chatMessageRadius;
border-radius: var(--chatMessageRadius, $fallback--chatMessageRadius);
}
.popover {

View File

@ -53,7 +53,7 @@
<div slot="content">
<div class="dropdown-menu">
<button
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click="deleteMessage"
>
<FAIcon icon="times" /> {{ $t("chats.delete") }}
@ -62,7 +62,7 @@
</div>
<button
slot="trigger"
class="menu-icon"
class="button-default menu-icon"
:title="$t('chats.more')"
>
<FAIcon icon="ellipsis-h" />

View File

@ -10,12 +10,13 @@
class="panel-heading conversation-heading"
>
<span class="title"> {{ $t('timeline.conversation') }} </span>
<span v-if="collapsable">
<a
href="#"
@click.prevent="toggleExpanded"
>{{ $t('timeline.collapse') }}</a>
</span>
<button
v-if="collapsable"
class="button-unstyled -link"
@click.prevent="toggleExpanded"
>
{{ $t('timeline.collapse') }}
</button>
</div>
<status
v-for="status in conversation"

View File

@ -21,7 +21,7 @@
grid-template-areas: "logo sitename actions";
}
button {
.button-default {
&, svg {
color: $fallback--text;
color: var(--btnTopBarText, $fallback--text);
@ -80,12 +80,13 @@
.nav-icon {
margin-left: 0.2em;
width: 2em;
height: 100%;
text-align: center;
}
a, a svg {
color: $fallback--link;
color: var(--topBarLink, $fallback--link);
.svg-inline--fa {
color: $fallback--link;
color: var(--topBarLink, $fallback--link);
}
}
.sitename {

View File

@ -36,9 +36,8 @@
@toggled="onSearchBarToggled"
@click.stop.native
/>
<a
href="#"
class="nav-icon"
<button
class="button-unstyled nav-icon"
@click.stop="openSettingsModal"
>
<FAIcon
@ -47,29 +46,32 @@
icon="cog"
:title="$t('nav.preferences')"
/>
</a>
</button>
<a
v-if="currentUser && currentUser.role === 'admin'"
href="/pleroma/admin/#/login-pleroma"
class="nav-icon"
target="_blank"
><FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="tachometer-alt"
:title="$t('nav.administration')"
/></a>
<a
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="tachometer-alt"
:title="$t('nav.administration')"
/>
</a>
<button
v-if="currentUser"
href="#"
class="nav-icon"
class="button-unstyled nav-icon"
@click.prevent="logout"
><FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="sign-out-alt"
:title="$t('login.logout')"
/></a>
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="sign-out-alt"
:title="$t('login.logout')"
/>
</button>
</div>
</div>
</nav>

View File

@ -6,7 +6,7 @@
<ProgressButton
v-if="muted"
:click="unmuteDomain"
class="btn btn-default"
class="btn button-default"
>
{{ $t('domain_mute_card.unmute') }}
<template slot="progress">
@ -16,7 +16,7 @@
<ProgressButton
v-else
:click="muteDomain"
class="btn btn-default"
class="btn button-default"
>
{{ $t('domain_mute_card.mute') }}
<template slot="progress">

View File

@ -114,7 +114,8 @@ const EmojiInput = {
showPicker: false,
temporarilyHideSuggestions: false,
keepOpen: false,
disableClickOutside: false
disableClickOutside: false,
suggestions: []
}
},
components: {
@ -124,21 +125,6 @@ const EmojiInput = {
padEmoji () {
return this.$store.getters.mergedConfig.padEmoji
},
suggestions () {
const firstchar = this.textAtCaret.charAt(0)
if (this.textAtCaret === firstchar) { return [] }
const matchedSuggestions = this.suggest(this.textAtCaret)
if (matchedSuggestions.length <= 0) {
return []
}
return take(matchedSuggestions, 5)
.map(({ imageUrl, ...rest }, index) => ({
...rest,
// eslint-disable-next-line camelcase
img: imageUrl || '',
highlighted: index === this.highlighted
}))
},
showSuggestions () {
return this.focused &&
this.suggestions &&
@ -188,6 +174,23 @@ const EmojiInput = {
watch: {
showSuggestions: function (newValue) {
this.$emit('shown', newValue)
},
textAtCaret: async function (newWord) {
const firstchar = newWord.charAt(0)
this.suggestions = []
if (newWord === firstchar) return
const matchedSuggestions = await this.suggest(newWord)
// Async: cancel if textAtCaret has changed during wait
if (this.textAtCaret !== newWord) return
if (matchedSuggestions.length <= 0) return
this.suggestions = take(matchedSuggestions, 5)
.map(({ imageUrl, ...rest }) => ({
...rest,
img: imageUrl || ''
}))
},
suggestions (newValue) {
this.$nextTick(this.resize)
}
},
methods: {

View File

@ -6,13 +6,13 @@
>
<slot />
<template v-if="enableEmojiPicker">
<div
<button
v-if="!hideEmojiButton"
class="emoji-picker-icon"
class="button-unstyled emoji-picker-icon"
@click.prevent="togglePicker"
>
<FAIcon :icon="['far', 'smile-beam']" />
</div>
</button>
<EmojiPicker
v-if="enableEmojiPicker"
ref="picker"
@ -37,7 +37,7 @@
v-for="(suggestion, index) in suggestions"
:key="index"
class="autocomplete-item"
:class="{ highlighted: suggestion.highlighted }"
:class="{ highlighted: index === highlighted }"
@click.stop.prevent="onClick($event, suggestion)"
>
<span class="image">

View File

@ -1,4 +1,3 @@
import { debounce } from 'lodash'
/**
* suggest - generates a suggestor function to be used by emoji-input
* data: object providing source information for specific types of suggestions:
@ -11,19 +10,19 @@ import { debounce } from 'lodash'
* doesn't support user linking you can just provide only emoji.
*/
const debounceUserSearch = debounce((data, input) => {
data.updateUsersList(input)
}, 500)
export default data => input => {
const firstChar = input[0]
if (firstChar === ':' && data.emoji) {
return suggestEmoji(data.emoji)(input)
export default data => {
const emojiCurry = suggestEmoji(data.emoji)
const usersCurry = data.store && suggestUsers(data.store)
return input => {
const firstChar = input[0]
if (firstChar === ':' && data.emoji) {
return emojiCurry(input)
}
if (firstChar === '@' && usersCurry) {
return usersCurry(input)
}
return []
}
if (firstChar === '@' && data.users) {
return suggestUsers(data)(input)
}
return []
}
export const suggestEmoji = emojis => input => {
@ -57,50 +56,75 @@ export const suggestEmoji = emojis => input => {
})
}
export const suggestUsers = data => input => {
const noPrefix = input.toLowerCase().substr(1)
const users = data.users
export const suggestUsers = ({ dispatch, state }) => {
// Keep some persistent values in closure, most importantly for the
// custom debounce to work. Lodash debounce does not return a promise.
let suggestions = []
let previousQuery = ''
let timeout = null
let cancelUserSearch = null
const newUsers = users.filter(
user =>
user.screen_name.toLowerCase().startsWith(noPrefix) ||
user.name.toLowerCase().startsWith(noPrefix)
/* taking only 20 results so that sorting is a bit cheaper, we display
* only 5 anyway. could be inaccurate, but we ideally we should query
* backend anyway
*/
).slice(0, 20).sort((a, b) => {
let aScore = 0
let bScore = 0
// Matches on screen name (i.e. user@instance) makes a priority
aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
// Matches on name takes second priority
aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
const diff = (bScore - aScore) * 10
// Then sort alphabetically
const nameAlphabetically = a.name > b.name ? 1 : -1
const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
return diff + nameAlphabetically + screenNameAlphabetically
/* eslint-disable camelcase */
}).map(({ screen_name, name, profile_image_url_original }) => ({
displayText: screen_name,
detailText: name,
imageUrl: profile_image_url_original,
replacement: '@' + screen_name + ' '
}))
// BE search users to get more comprehensive results
if (data.updateUsersList) {
debounceUserSearch(data, noPrefix)
const userSearch = (query) => dispatch('searchUsers', { query })
const debounceUserSearch = (query) => {
cancelUserSearch && cancelUserSearch()
return new Promise((resolve, reject) => {
timeout = setTimeout(() => {
userSearch(query).then(resolve).catch(reject)
}, 300)
cancelUserSearch = () => {
clearTimeout(timeout)
resolve([])
}
})
}
return async input => {
const noPrefix = input.toLowerCase().substr(1)
if (previousQuery === noPrefix) return suggestions
suggestions = []
previousQuery = noPrefix
// Fetch more and wait, don't fetch if there's the 2nd @ because
// the backend user search can't deal with it.
// Reference semantics make it so that we get the updated data after
// the await.
if (!noPrefix.includes('@')) {
await debounceUserSearch(noPrefix)
}
const newSuggestions = state.users.users.filter(
user =>
user.screen_name.toLowerCase().startsWith(noPrefix) ||
user.name.toLowerCase().startsWith(noPrefix)
).slice(0, 20).sort((a, b) => {
let aScore = 0
let bScore = 0
// Matches on screen name (i.e. user@instance) makes a priority
aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
// Matches on name takes second priority
aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
const diff = (bScore - aScore) * 10
// Then sort alphabetically
const nameAlphabetically = a.name > b.name ? 1 : -1
const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
return diff + nameAlphabetically + screenNameAlphabetically
/* eslint-disable camelcase */
}).map(({ screen_name, name, profile_image_url_original }) => ({
displayText: screen_name,
detailText: name,
imageUrl: profile_image_url_original,
replacement: '@' + screen_name + ' '
}))
/* eslint-enable camelcase */
suggestions = newSuggestions || []
return suggestions
}
return newUsers
/* eslint-enable camelcase */
}

View File

@ -6,7 +6,7 @@
:users="accountsForEmoji[reaction.name]"
>
<button
class="emoji-reaction btn btn-default"
class="emoji-reaction btn button-default"
:class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
@click="emojiOnClick(reaction.name, $event)"
@mouseenter="fetchEmojiReactionsByIfMissing()"

View File

@ -2,13 +2,13 @@
<div class="import-export-container">
<slot name="before" />
<button
class="btn"
class="btn button-default"
@click="exportData"
>
{{ exportLabel }}
</button>
<button
class="btn"
class="btn button-default"
@click="importData"
>
{{ importLabel }}

View File

@ -11,7 +11,7 @@
</div>
<button
v-else
class="btn btn-default"
class="btn button-default"
@click="process"
>
{{ exportButtonLabel }}

View File

@ -2,8 +2,9 @@
<Popover
trigger="click"
placement="top"
class="extra-button-popover"
:offset="{ y: 5 }"
:bound-to="{ x: 'container' }"
remove-padding
>
<div
slot="content"
@ -12,7 +13,7 @@
<div class="dropdown-menu">
<button
v-if="canMute && !status.thread_muted"
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="muteConversation"
>
<FAIcon
@ -22,7 +23,7 @@
</button>
<button
v-if="canMute && status.thread_muted"
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="unmuteConversation"
>
<FAIcon
@ -32,7 +33,7 @@
</button>
<button
v-if="!status.pinned && canPin"
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="pinStatus"
@click="close"
>
@ -43,7 +44,7 @@
</button>
<button
v-if="status.pinned && canPin"
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="unpinStatus"
@click="close"
>
@ -54,7 +55,7 @@
</button>
<button
v-if="!status.bookmarked"
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="bookmarkStatus"
@click="close"
>
@ -65,7 +66,7 @@
</button>
<button
v-if="status.bookmarked"
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="unbookmarkStatus"
@click="close"
>
@ -76,7 +77,7 @@
</button>
<button
v-if="canDelete"
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="deleteStatus"
@click="close"
>
@ -86,7 +87,7 @@
/><span>{{ $t("status.delete") }}</span>
</button>
<button
class="dropdown-item dropdown-item-icon"
class="button-default dropdown-item dropdown-item-icon"
@click.prevent="copyLink"
@click="close"
>
@ -97,9 +98,12 @@
</button>
</div>
</div>
<span slot="trigger">
<span
slot="trigger"
class="ExtraButtons"
>
<FAIcon
class="ExtraButtons fa-scale-110 fa-old-padding"
class="fa-scale-110 fa-old-padding"
icon="ellipsis-h"
/>
</span>
@ -112,11 +116,11 @@
@import '../../_variables.scss';
.ExtraButtons {
cursor: pointer;
position: static;
padding: 10px;
margin: -10px;
&:hover,
.extra-button-popover.open & {
&:hover .svg-inline--fa {
color: $fallback--text;
color: var(--text, $fallback--text);
}

View File

@ -31,11 +31,6 @@ const FavoriteButton = {
}
},
computed: {
classes () {
return {
'-favorited': this.status.favorited
}
},
...mapGetters(['mergedConfig'])
}
}

View File

@ -1,23 +1,31 @@
<template>
<div v-if="loggedIn">
<FAIcon
:class="classes"
class="FavoriteButton fa-scale-110 fa-old-padding -interactive"
<div class="FavoriteButton">
<button
v-if="loggedIn"
class="button-unstyled interactive"
:class="status.favorited && '-favorited'"
:title="$t('tool_tip.favorite')"
:icon="[status.favorited ? 'fas' : 'far', 'star']"
:spin="animated"
@click.prevent="favorite()"
/>
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
</div>
<div v-else>
<FAIcon
:class="classes"
class="FavoriteButton fa-scale-110 fa-old-padding"
:title="$t('tool_tip.favorite')"
:icon="['far', 'star']"
/>
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
>
<FAIcon
class="fa-scale-110 fa-old-padding"
:icon="[status.favorited ? 'fas' : 'far', 'star']"
:spin="animated"
/>
</button>
<span v-else>
<FAIcon
class="fa-scale-110 fa-old-padding"
:title="$t('tool_tip.favorite')"
:icon="['far', 'star']"
/>
</span>
<span
v-if="!mergedConfig.hidePostStats && status.fave_num > 0"
class="action-counter"
>
{{ status.fave_num }}
</span>
</div>
</template>
@ -27,19 +35,28 @@
@import '../../_variables.scss';
.FavoriteButton {
&.-interactive {
cursor: pointer;
animation-duration: 0.6s;
display: flex;
&:hover {
> :first-child {
padding: 10px;
margin: -10px -8px -10px -10px;
}
.action-counter {
pointer-events: none;
user-select: none;
}
.interactive {
.svg-inline--fa {
animation-duration: 0.6s;
}
&:hover .svg-inline--fa,
&.-favorited .svg-inline--fa {
color: $fallback--cOrange;
color: var(--cOrange, $fallback--cOrange);
}
}
&.-favorited {
color: $fallback--cOrange;
color: var(--cOrange, $fallback--cOrange);
}
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<button
class="btn btn-default follow-button"
class="btn button-default follow-button"
:class="{ toggled: isPressed }"
:disabled="inProgress"
:title="title"

View File

@ -2,13 +2,13 @@
<basic-user-card :user="user">
<div class="follow-request-card-content-container">
<button
class="btn btn-default"
class="btn button-default"
@click="approveUser"
>
{{ $t('user_card.approve') }}
</button>
<button
class="btn btn-default"
class="btn button-default"
@click="denyUser"
>
{{ $t('user_card.deny') }}

View File

@ -11,21 +11,21 @@
</div>
<div class="image-cropper-buttons-wrapper">
<button
class="btn"
class="button-default btn"
type="button"
:disabled="submitting"
@click="submit()"
v-text="saveText"
/>
<button
class="btn"
class="button-default btn"
type="button"
:disabled="submitting"
@click="destroy"
v-text="cancelText"
/>
<button
class="btn"
class="button-default btn"
type="button"
:disabled="submitting"
@click="submit(false)"

View File

@ -15,7 +15,7 @@
/>
<button
v-else
class="btn btn-default"
class="btn button-default"
@click="submit"
>
{{ submitButtonLabel }}

View File

@ -61,7 +61,7 @@
<button
:disabled="loggingIn"
type="submit"
class="btn btn-default"
class="btn button-default"
>
{{ $t('login.login') }}
</button>

View File

@ -1,33 +1,29 @@
<template>
<div
<label
class="media-upload"
:class="{ disabled: disabled }"
:title="$t('tool_tip.media_upload')"
>
<label
class="label"
:title="$t('tool_tip.media_upload')"
<FAIcon
v-if="uploading"
class="progress-icon"
icon="circle-notch"
spin
/>
<FAIcon
v-if="!uploading"
class="new-icon"
icon="upload"
/>
<input
v-if="uploadReady"
:disabled="disabled"
type="file"
style="position: fixed; top: -100em"
multiple="true"
@change="change"
>
<FAIcon
v-if="uploading"
class="progress-icon"
icon="circle-notch"
spin
/>
<FAIcon
v-if="!uploading"
class="new-icon"
icon="upload"
/>
<input
v-if="uploadReady"
:disabled="disabled"
type="file"
style="position: fixed; top: -100em"
multiple="true"
@change="change"
>
</label>
</div>
</label>
</template>
<script src="./media_upload.js" ></script>

View File

@ -23,23 +23,23 @@
<div class="form-group">
<div class="login-bottom">
<div>
<a
href="#"
<button
class="button-unstyled -link"
@click.prevent="requireTOTP"
>
{{ $t('login.enter_two_factor_code') }}
</a>
</button>
<br>
<a
href="#"
<button
class="button-unstyled -link"
@click.prevent="abortMFA"
>
{{ $t('general.cancel') }}
</a>
</button>
</div>
<button
type="submit"
class="btn btn-default"
class="btn button-default"
>
{{ $t('general.verify') }}
</button>

View File

@ -25,23 +25,23 @@
<div class="form-group">
<div class="login-bottom">
<div>
<a
href="#"
<button
class="button-unstyled -link"
@click.prevent="requireRecovery"
>
{{ $t('login.enter_recovery_code') }}
</a>
</button>
<br>
<a
href="#"
<button
class="button-unstyled -link"
@click.prevent="abortMFA"
>
{{ $t('general.cancel') }}
</a>
</button>
</div>
<button
type="submit"
class="btn btn-default"
class="btn button-default"
>
{{ $t('general.verify') }}
</button>

View File

@ -9,9 +9,8 @@
@click="scrollToTop()"
>
<div class="item">
<a
href="#"
class="mobile-nav-button"
<button
class="button-unstyled mobile-nav-button"
@click.stop.prevent="toggleMobileSidebar()"
>
<FAIcon
@ -22,7 +21,7 @@
v-if="unreadChatCount"
class="alert-dot"
/>
</a>
</button>
<router-link
v-if="!hideSitename"
class="site-name"
@ -33,10 +32,9 @@
</router-link>
</div>
<div class="item right">
<a
<button
v-if="currentUser"
class="mobile-nav-button"
href="#"
class="button-unstyled mobile-nav-button"
@click.stop.prevent="openMobileNotifications()"
>
<FAIcon
@ -47,7 +45,7 @@
v-if="unseenNotificationsCount"
class="alert-dot"
/>
</a>
</button>
</div>
</nav>
<div

View File

@ -1,7 +1,7 @@
<template>
<div v-if="isLoggedIn">
<button
class="new-status-button"
class="button-default new-status-button"
:class="{ 'hidden': isHidden }"
@click="openPostForm"
>

View File

@ -12,13 +12,13 @@
<div class="dropdown-menu">
<span v-if="user.is_local">
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleRight(&quot;admin&quot;)"
>
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
</button>
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleRight(&quot;moderator&quot;)"
>
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
@ -29,13 +29,13 @@
/>
</span>
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleActivationStatus()"
>
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
</button>
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="deleteUserDialog(true)"
>
{{ $t('user_card.admin_menu.delete_account') }}
@ -47,7 +47,7 @@
/>
<span v-if="hasTagPolicy">
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleTag(tags.FORCE_NSFW)"
>
{{ $t('user_card.admin_menu.force_nsfw') }}
@ -57,7 +57,7 @@
/>
</button>
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleTag(tags.STRIP_MEDIA)"
>
{{ $t('user_card.admin_menu.strip_media') }}
@ -67,7 +67,7 @@
/>
</button>
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleTag(tags.FORCE_UNLISTED)"
>
{{ $t('user_card.admin_menu.force_unlisted') }}
@ -77,7 +77,7 @@
/>
</button>
<button
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleTag(tags.SANDBOX)"
>
{{ $t('user_card.admin_menu.sandbox') }}
@ -88,7 +88,7 @@
</button>
<button
v-if="user.is_local"
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
>
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
@ -99,7 +99,7 @@
</button>
<button
v-if="user.is_local"
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
>
{{ $t('user_card.admin_menu.disable_any_subscription') }}
@ -110,7 +110,7 @@
</button>
<button
v-if="user.is_local"
class="dropdown-item"
class="button-default dropdown-item"
@click="toggleTag(tags.QUARANTINE)"
>
{{ $t('user_card.admin_menu.quarantine') }}
@ -124,7 +124,7 @@
</div>
<button
slot="trigger"
class="btn btn-default btn-block"
class="btn button-default btn-block"
:class="{ toggled }"
>
{{ $t('user_card.admin_menu.moderation') }}
@ -141,13 +141,13 @@
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
<template slot="footer">
<button
class="btn btn-default"
class="btn button-default"
@click="deleteUserDialog(false)"
>
{{ $t('general.cancel') }}
</button>
<button
class="btn btn-default danger"
class="btn button-default danger"
@click="deleteUser()"
>
{{ $t('user_card.admin_menu.delete_user') }}

View File

@ -3,7 +3,7 @@
<div class="mute-card-content-container">
<button
v-if="muted"
class="btn btn-default"
class="btn button-default"
:disabled="progress"
@click="unmuteUser"
>
@ -16,7 +16,7 @@
</button>
<button
v-else
class="btn btn-default"
class="btn button-default"
:disabled="progress"
@click="muteUser"
>

View File

@ -14,14 +14,15 @@
{{ notification.from_profile.screen_name }}
</router-link>
</small>
<a
href="#"
class="unmute"
<button
class="button-unstyled unmute"
@click.prevent="toggleMute"
><FAIcon
class="fa-scale-110 fa-old-padding"
icon="eye-slash"
/></a>
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="eye-slash"
/>
</button>
</div>
<div
v-else
@ -135,14 +136,16 @@
/>
</span>
</div>
<a
<button
v-if="needMute"
href="#"
class="button-unstyled"
@click.prevent="toggleMute"
><FAIcon
class="fa-scale-110 fa-old-padding"
icon="eye-slash"
/></a>
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="eye-slash"
/>
</button>
</span>
<div
v-if="notification.type === 'follow' || notification.type === 'follow_request'"

View File

@ -17,7 +17,7 @@
</div>
<button
v-if="unseenCount"
class="read-button"
class="button-default read-button"
@click.prevent="markAsSeen"
>
{{ $t('notifications.read') }}
@ -41,15 +41,15 @@
>
{{ $t('notifications.no_more_notifications') }}
</div>
<a
<button
v-else-if="!loading"
href="#"
class="button-unstyled -link -fullwidth"
@click.prevent="fetchOlderNotifications()"
>
<div class="new-status-notification text-center panel-footer">
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
</div>
</a>
</button>
<div
v-else
class="new-status-notification text-center panel-footer"

View File

@ -51,7 +51,7 @@
<button
:disabled="isPending"
type="submit"
class="btn btn-default btn-block"
class="btn button-default btn-block"
>
{{ $t('general.submit') }}
</button>

View File

@ -49,7 +49,7 @@
<div class="footer faint">
<button
v-if="!showResults"
class="btn btn-default poll-vote-button"
class="btn button-default poll-vote-button"
type="button"
:disabled="isDisabled"
@click="vote"

View File

@ -21,7 +21,10 @@ const Popover = {
// Replaces the classes you may want for the popover container.
// Use 'popover-default' in addition to get the default popover
// styles with your custom class.
popoverClass: String
popoverClass: String,
// If true, subtract padding when calculating position for the popover,
// use it when popover offset looks to be different on top vs bottom.
removePadding: Boolean
},
data () {
return {
@ -96,9 +99,15 @@ const Popover = {
if (origin.y + content.offsetHeight > yBounds.max) usingTop = true
if (origin.y - content.offsetHeight < yBounds.min) usingTop = false
let vPadding = 0
if (this.removePadding && usingTop) {
const anchorStyle = getComputedStyle(anchorEl)
vPadding = parseFloat(anchorStyle.paddingTop) + parseFloat(anchorStyle.paddingBottom)
}
const yOffset = (this.offset && this.offset.y) || 0
const translateY = usingTop
? -anchorEl.offsetHeight - yOffset - content.offsetHeight
? -anchorEl.offsetHeight + vPadding - yOffset - content.offsetHeight
: yOffset
const xOffset = (this.offset && this.offset.x) || 0

View File

@ -3,12 +3,13 @@
@mouseenter="onMouseenter"
@mouseleave="onMouseleave"
>
<div
<button
ref="trigger"
class="button-unstyled -fullwidth popover-trigger-button"
@click="onClick"
>
<slot name="trigger" />
</div>
</button>
<div
v-if="!hidden"
ref="content"
@ -30,6 +31,10 @@
<style lang="scss">
@import '../../_variables.scss';
.popover-trigger-button {
display: block;
}
.popover {
z-index: 8;
position: absolute;

View File

@ -159,8 +159,7 @@ const PostStatusForm = {
...this.$store.state.instance.emoji,
...this.$store.state.instance.customEmoji
],
users: this.$store.state.users.users,
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
store: this.$store
})
},
emojiSuggestor () {

View File

@ -24,12 +24,12 @@
tag="p"
class="visibility-notice"
>
<a
href="#"
<button
class="button-unstyled -link"
@click="openProfileTab"
>
{{ $t('post_status.account_not_locked_warning_link') }}
</a>
</button>
</i18n>
<p
v-if="!hideScopeNotice && newStatus.visibility === 'public'"
@ -243,38 +243,34 @@
@upload-failed="uploadFailed"
@all-uploaded="finishedUploadingFiles"
/>
<div
class="emoji-icon"
<button
class="emoji-icon button-unstyled"
:title="$t('emoji.add_emoji')"
@click="showEmojiPicker"
>
<div
:title="$t('emoji.add_emoji')"
class="btn btn-default"
@click="showEmojiPicker"
>
<FAIcon icon="smile-beam" />
</div>
</div>
<div
<FAIcon icon="smile-beam" />
</button>
<button
v-if="pollsAvailable"
class="poll-icon"
class="poll-icon button-unstyled"
:class="{ selected: pollFormVisible }"
:title="$t('polls.add_poll')"
@click="togglePollForm"
>
<FAIcon icon="poll-h" />
</div>
</button>
</div>
<button
v-if="posting"
disabled
class="btn btn-default"
class="btn button-default"
>
{{ $t('post_status.posting') }}
</button>
<button
v-else-if="isOverLengthLimit"
disabled
class="btn btn-default"
class="btn button-default"
>
{{ $t('general.submit') }}
</button>
@ -282,7 +278,7 @@
<button
v-else
:disabled="uploadingFiles || disableSubmit"
class="btn btn-default"
class="btn button-default"
@touchstart.stop.prevent="postStatus($event, newStatus)"
@click.stop.prevent="postStatus($event, newStatus)"
>

View File

@ -27,13 +27,21 @@ const ReactButton = {
},
computed: {
commonEmojis () {
return ['👍', '😠', '👀', '😂', '🔥']
return [
{ displayText: 'thumbsup', replacement: '👍' },
{ displayText: 'angry', replacement: '😠' },
{ displayText: 'eyes', replacement: '👀' },
{ displayText: 'joy', replacement: '😂' },
{ displayText: 'fire', replacement: '🔥' }
]
},
emojis () {
if (this.filterWord !== '') {
const filterWordLowercase = this.filterWord.toLowerCase()
let orderedEmojiList = []
for (const emoji of this.$store.state.instance.emoji) {
if (emoji.replacement === this.filterWord) return [emoji]
const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase)
if (indexOfFilterWord > -1) {
if (!Array.isArray(orderedEmojiList[indexOfFilterWord])) {

View File

@ -3,8 +3,8 @@
trigger="click"
placement="top"
:offset="{ y: 5 }"
class="react-button-popover"
:bound-to="{ x: 'container' }"
remove-padding
>
<div
slot="content"
@ -22,15 +22,17 @@
v-for="emoji in commonEmojis"
:key="emoji"
class="emoji-button"
:title="emoji.displayText"
@click="addReaction($event, emoji, close)"
>
{{ emoji }}
{{ emoji.replacement }}
</span>
<div class="reaction-picker-divider" />
<span
v-for="(emoji, key) in emojis"
:key="key"
class="emoji-button"
:title="emoji.displayText"
@click="addReaction($event, emoji.replacement, close)"
>
{{ emoji.replacement }}
@ -38,11 +40,14 @@
<div class="reaction-bottom-fader" />
</div>
</div>
<span slot="trigger">
<span
slot="trigger"
class="ReactButton"
:title="$t('tool_tip.add_reaction')"
>
<FAIcon
class="fa-scale-110 fa-old-padding add-reaction-button"
class="fa-scale-110 fa-old-padding"
:icon="['far', 'smile-beam']"
:title="$t('tool_tip.add_reaction')"
/>
</span>
</Popover>
@ -102,10 +107,11 @@
}
}
.add-reaction-button {
cursor: pointer;
.ReactButton {
padding: 10px;
margin: -10px;
&:hover {
&:hover .svg-inline--fa {
color: $fallback--text;
color: var(--text, $fallback--text);
}

View File

@ -211,7 +211,7 @@
<button
:disabled="isPending"
type="submit"
class="btn btn-default"
class="btn button-default"
>
{{ $t('general.submit') }}
</button>

View File

@ -1,20 +1,28 @@
<template>
<div>
<FAIcon
<div class="ReplyButton">
<button
v-if="loggedIn"
class="ReplyButton fa-scale-110 fa-old-padding -interactive"
icon="reply"
:title="$t('tool_tip.reply')"
class="button-unstyled interactive"
:class="{'-active': replying}"
@click.prevent="$emit('toggle')"
/>
<FAIcon
v-else
icon="reply"
class="ReplyButton fa-scale-110 fa-old-padding"
:title="$t('tool_tip.reply')"
/>
<span v-if="status.replies_count > 0">
@click.prevent="$emit('toggle')"
>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="reply"
/>
</button>
<span v-else>
<FAIcon
icon="reply"
class="fa-scale-110 fa-old-padding"
:title="$t('tool_tip.reply')"
/>
</span>
<span
v-if="status.replies_count > 0"
class="action-counter"
>
{{ status.replies_count }}
</span>
</div>
@ -26,14 +34,25 @@
@import '../../_variables.scss';
.ReplyButton {
&.-interactive {
cursor: pointer;
display: flex;
&:hover,
&.-active {
> :first-child {
padding: 10px;
margin: -10px -8px -10px -10px;
}
.action-counter {
pointer-events: none;
user-select: none;
}
.interactive {
&:hover .svg-inline--fa,
&.-active .svg-inline--fa {
color: $fallback--cBlue;
color: var(--cBlue, $fallback--cBlue);
}
}
}
</style>

View File

@ -24,11 +24,6 @@ const RetweetButton = {
}
},
computed: {
classes () {
return {
'-repeated': this.status.repeated
}
},
mergedConfig () {
return this.$store.getters.mergedConfig
}

View File

@ -1,33 +1,38 @@
<template>
<div v-if="loggedIn">
<template v-if="visibility !== 'private' && visibility !== 'direct'">
<div class="RetweetButton">
<button
v-if="visibility !== 'private' && visibility !== 'direct' && loggedIn"
class="button-unstyled interactive"
:class="status.repeated && '-repeated'"
:title="$t('tool_tip.repeat')"
@click.prevent="retweet()"
>
<FAIcon
:class="classes"
class="RetweetButton fa-scale-110 fa-old-padding -interactive"
class="fa-scale-110 fa-old-padding"
icon="retweet"
:spin="animated"
:title="$t('tool_tip.repeat')"
@click.prevent="retweet()"
/>
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
</template>
<template v-else>
</button>
<span v-else-if="loggedIn">
<FAIcon
:class="classes"
class="RetweetButton fa-scale-110 fa-old-padding"
class="fa-scale-110 fa-old-padding"
icon="lock"
:title="$t('timeline.no_retweet_hint')"
/>
</template>
</div>
<div v-else-if="!loggedIn">
<FAIcon
:class="classes"
class="fa-scale-110 fa-old-padding"
icon="retweet"
:title="$t('tool_tip.repeat')"
/>
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
</span>
<span v-else>
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="retweet"
:title="$t('tool_tip.repeat')"
/>
</span>
<span
v-if="!mergedConfig.hidePostStats && status.repeat_num > 0"
class="no-event"
>
{{ status.repeat_num }}
</span>
</div>
</template>
@ -37,19 +42,28 @@
@import '../../_variables.scss';
.RetweetButton {
&.-interactive {
cursor: pointer;
animation-duration: 0.6s;
display: flex;
&:hover {
> :first-child {
padding: 10px;
margin: -10px -8px -10px -10px;
}
.action-counter {
pointer-events: none;
user-select: none;
}
.interactive {
.svg-inline--fa {
animation-duration: 0.6s;
}
&:hover .svg-inline--fa,
&.-repeated .svg-inline--fa {
color: $fallback--cGreen;
color: var(--cGreen, $fallback--cGreen);
}
}
&.-repeated {
color: $fallback--cGreen;
color: var(--cGreen, $fallback--cGreen);
}
}
</style>

View File

@ -3,9 +3,9 @@
v-if="!showNothing"
class="ScopeSelector"
>
<span
<button
v-if="showDirect"
class="scope"
class="button-unstyled scope"
:class="css.direct"
:title="$t('post_status.scope.direct')"
@click="changeVis('direct')"
@ -14,10 +14,10 @@
icon="envelope"
class="fa-scale-110 fa-old-padding"
/>
</span>
<span
</button>
<button
v-if="showPrivate"
class="scope"
class="button-unstyled scope"
:class="css.private"
:title="$t('post_status.scope.private')"
@click="changeVis('private')"
@ -26,10 +26,10 @@
icon="lock"
class="fa-scale-110 fa-old-padding"
/>
</span>
<span
</button>
<button
v-if="showUnlisted"
class="scope"
class="button-unstyled scope"
:class="css.unlisted"
:title="$t('post_status.scope.unlisted')"
@click="changeVis('unlisted')"
@ -38,10 +38,10 @@
icon="lock-open"
class="fa-scale-110 fa-old-padding"
/>
</span>
<span
</button>
<button
v-if="showPublic"
class="scope"
class="button-unstyled scope"
:class="css.public"
:title="$t('post_status.scope.public')"
@click="changeVis('public')"
@ -50,7 +50,7 @@
icon="globe"
class="fa-scale-110 fa-old-padding"
/>
</span>
</button>
</div>
</template>

View File

@ -14,7 +14,7 @@
@keyup.enter="newQuery(searchTerm)"
>
<button
class="btn search-button"
class="btn button-default search-button"
@click="newQuery(searchTerm)"
>
<FAIcon icon="search" />

View File

@ -3,17 +3,18 @@
class="SearchBar"
:class="{ '-expanded': !hidden }"
>
<a
<button
v-if="hidden"
href="#"
class="nav-icon"
class="button-unstyled nav-icon"
:title="$t('nav.search')"
><FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="search"
@click.prevent.stop="toggleHidden"
/></a>
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="search"
/>
</button>
<template v-else>
<input
id="search-bar-input"
@ -25,7 +26,7 @@
@keyup.enter="find(searchTerm)"
>
<button
class="btn search-button"
class="button-default search-button"
@click="find(searchTerm)"
>
<FAIcon
@ -33,14 +34,16 @@
icon="search"
/>
</button>
<span>
<button
class="button-unstyled cancel-search"
@click.prevent.stop="toggleHidden"
>
<FAIcon
fixed-width
icon="times"
class="cancel-icon fa-scale-110 fa-old-padding"
@click.prevent.stop="toggleHidden"
/>
</span>
</button>
</template>
</div>
</template>
@ -69,8 +72,11 @@
flex: 1 0 auto;
}
.cancel-search {
height: 50px;
}
.cancel-icon {
cursor: pointer;
color: $fallback--text;
color: var(--btnTopBarText, $fallback--text);
}

View File

@ -30,13 +30,13 @@
</template>
</transition>
<button
class="btn"
class="btn button-default"
@click="peekModal"
>
{{ $t('general.peek') }}
</button>
<button
class="btn"
class="btn button-default"
@click="closeModal"
>
{{ $t('general.close') }}

View File

@ -27,7 +27,7 @@
<div class="bulk-actions">
<ProgressButton
v-if="selected.length > 0"
class="btn btn-default bulk-action-button"
class="btn button-default bulk-action-button"
:click="() => blockUsers(selected)"
>
{{ $t('user_card.block') }}
@ -37,7 +37,7 @@
</ProgressButton>
<ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
class="btn button-default"
:click="() => unblockUsers(selected)"
>
{{ $t('user_card.unblock') }}
@ -85,7 +85,7 @@
<div class="bulk-actions">
<ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
class="btn button-default"
:click="() => muteUsers(selected)"
>
{{ $t('user_card.mute') }}
@ -95,7 +95,7 @@
</ProgressButton>
<ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
class="btn button-default"
:click="() => unmuteUsers(selected)"
>
{{ $t('user_card.unmute') }}
@ -141,7 +141,7 @@
<div class="bulk-actions">
<ProgressButton
v-if="selected.length > 0"
class="btn btn-default"
class="btn button-default"
:click="() => unmuteDomains(selected)"
>
{{ $t('domain_mute_card.unmute') }}

View File

@ -21,7 +21,7 @@
<p>{{ $t('settings.notification_mutes') }}</p>
<p>{{ $t('settings.notification_blocks') }}</p>
<button
class="btn btn-default"
class="btn button-default"
@click="updateNotificationSettings"
>
{{ $t('general.submit') }}

View File

@ -68,8 +68,7 @@ const ProfileTab = {
...this.$store.state.instance.emoji,
...this.$store.state.instance.customEmoji
],
users: this.$store.state.users.users,
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
store: this.$store
})
},
emojiSuggestor () {
@ -79,10 +78,7 @@ const ProfileTab = {
] })
},
userSuggestor () {
return suggestor({
users: this.$store.state.users.users,
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
})
return suggestor({ store: this.$store })
},
fieldsLimits () {
return this.$store.state.instance.fieldsLimits

View File

@ -150,7 +150,7 @@
</p>
<button
:disabled="newName && newName.length === 0"
class="btn btn-default"
class="btn button-default"
@click="updateProfile"
>
{{ $t('general.submit') }}
@ -179,7 +179,7 @@
<button
v-show="pickAvatarBtnVisible"
id="pick-avatar"
class="btn"
class="button-default btn"
type="button"
>
{{ $t('settings.upload_a_photo') }}
@ -224,7 +224,7 @@
/>
<button
v-else-if="bannerPreview"
class="btn btn-default"
class="btn button-default"
@click="submitBanner(banner)"
>
{{ $t('general.submit') }}
@ -274,7 +274,7 @@
/>
<button
v-else-if="backgroundPreview"
class="btn btn-default"
class="btn button-default"
@click="submitBackground(background)"
>
{{ $t('general.submit') }}

View File

@ -2,14 +2,14 @@
<div>
<slot />
<button
class="btn btn-default"
class="btn button-default"
:disabled="disabled"
@click="confirm"
>
{{ $t('general.confirm') }}
</button>
<button
class="btn btn-default"
class="btn button-default"
:disabled="disabled"
@click="cancel"
>

View File

@ -29,7 +29,7 @@
/>
<button
v-if="!confirmNewBackupCodes"
class="btn btn-default"
class="btn button-default"
@click="getBackupCodes"
>
{{ $t('settings.mfa.generate_new_recovery_codes') }}
@ -61,7 +61,7 @@
<button
v-if="canSetupOTP"
class="btn btn-default"
class="btn button-default"
@click="cancelSetup"
>
{{ $t('general.cancel') }}
@ -69,7 +69,7 @@
<button
v-if="canSetupOTP"
class="btn btn-default"
class="btn button-default"
@click="setupOTP"
>
{{ $t('settings.mfa.setup_otp') }}
@ -108,13 +108,13 @@
>
<div class="confirm-otp-actions">
<button
class="btn btn-default"
class="btn button-default"
@click="doConfirmOTP"
>
{{ $t('settings.mfa.confirm_and_enable') }}
</button>
<button
class="btn btn-default"
class="btn button-default"
@click="cancelSetup"
>
{{ $t('general.cancel') }}

View File

@ -4,7 +4,7 @@
<strong>{{ $t('settings.mfa.otp') }}</strong>
<button
v-if="!isActivated"
class="btn btn-default"
class="btn button-default"
@click="doActivate"
>
{{ $t('general.enable') }}
@ -12,7 +12,7 @@
<button
v-if="isActivated"
class="btn btn-default"
class="btn button-default"
:disabled="deactivate"
@click="doDeactivate"
>

View File

@ -19,7 +19,7 @@
>
</div>
<button
class="btn btn-default"
class="btn button-default"
@click="changeEmail"
>
{{ $t('general.submit') }}
@ -57,7 +57,7 @@
>
</div>
<button
class="btn btn-default"
class="btn button-default"
@click="changePassword"
>
{{ $t('general.submit') }}
@ -92,7 +92,7 @@
<td>{{ oauthToken.validUntil }}</td>
<td class="actions">
<button
class="btn btn-default"
class="btn button-default"
@click="revokeToken(oauthToken.id)"
>
{{ $t('settings.revoke_token') }}
@ -116,7 +116,7 @@
type="password"
>
<button
class="btn btn-default"
class="btn button-default"
@click="deleteAccount"
>
{{ $t('settings.delete_account') }}
@ -130,7 +130,7 @@
</p>
<button
v-if="!deletingAccount"
class="btn btn-default"
class="btn button-default"
@click="confirmDelete"
>
{{ $t('general.submit') }}

View File

@ -15,7 +15,7 @@
<span class="alert error">
{{ $t('settings.style.preview.error') }}
</span>
<button class="btn">
<button class="btn button-default">
{{ $t('settings.style.preview.button') }}
</button>
</div>
@ -102,7 +102,7 @@
>
<label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
</span>
<button class="btn">
<button class="btn button-default">
{{ $t('settings.style.preview.button') }}
</button>
</div>

View File

@ -12,13 +12,13 @@
<div class="buttons">
<template v-if="themeWarning.type === 'snapshot_source_mismatch'">
<button
class="btn"
class="btn button-default"
@click="forceLoad"
>
{{ $t('settings.style.switcher.use_source') }}
</button>
<button
class="btn"
class="btn button-default"
@click="forceSnapshot"
>
{{ $t('settings.style.switcher.use_snapshot') }}
@ -26,7 +26,7 @@
</template>
<template v-else-if="themeWarning.noActionsPossible">
<button
class="btn"
class="btn button-default"
@click="dismissWarning"
>
{{ $t('general.dismiss') }}
@ -34,13 +34,13 @@
</template>
<template v-else>
<button
class="btn"
class="btn button-default"
@click="forceLoad"
>
{{ $t('settings.style.switcher.load_theme') }}
</button>
<button
class="btn"
class="btn button-default"
@click="dismissWarning"
>
{{ $t('settings.style.switcher.keep_as_is') }}
@ -131,13 +131,13 @@
<p>{{ $t('settings.theme_help') }}</p>
<div class="tab-header-buttons">
<button
class="btn"
class="btn button-default"
@click="clearOpacity"
>
{{ $t('settings.style.switcher.clear_opacity') }}
</button>
<button
class="btn"
class="btn button-default"
@click="clearV1"
>
{{ $t('settings.style.switcher.clear_all') }}
@ -238,13 +238,13 @@
<div class="tab-header">
<p>{{ $t('settings.theme_help') }}</p>
<button
class="btn"
class="btn button-default"
@click="clearOpacity"
>
{{ $t('settings.style.switcher.clear_opacity') }}
</button>
<button
class="btn"
class="btn button-default"
@click="clearV1"
>
{{ $t('settings.style.switcher.clear_all') }}
@ -806,7 +806,7 @@
<div class="tab-header">
<p>{{ $t('settings.radii_help') }}</p>
<button
class="btn"
class="btn button-default"
@click="clearRoundness"
>
{{ $t('settings.style.switcher.clear_all') }}
@ -936,7 +936,7 @@
/>
</div>
<button
class="btn"
class="btn button-default"
@click="clearShadows"
>
{{ $t('settings.style.switcher.clear_all') }}
@ -980,7 +980,7 @@
<div class="tab-header">
<p>{{ $t('settings.style.fonts.help') }}</p>
<button
class="btn"
class="btn button-default"
@click="clearFonts"
>
{{ $t('settings.style.switcher.clear_all') }}
@ -1017,14 +1017,14 @@
<div class="apply-container">
<button
class="btn submit"
class="btn button-default submit"
:disabled="!themeValid"
@click="setCustomTheme"
>
{{ $t('general.apply') }}
</button>
<button
class="btn"
class="btn button-default"
@click="clearAll"
>
{{ $t('settings.style.switcher.reset') }}

View File

@ -84,7 +84,7 @@
/>
</label>
<button
class="btn btn-default"
class="btn button-default"
:disabled="!ready || !present"
@click="del"
>
@ -94,7 +94,7 @@
/>
</button>
<button
class="btn btn-default"
class="btn button-default"
:disabled="!moveUpValid"
@click="moveUp"
>
@ -104,7 +104,7 @@
/>
</button>
<button
class="btn btn-default"
class="btn button-default"
:disabled="!moveDnValid"
@click="moveDn"
>
@ -114,7 +114,7 @@
/>
</button>
<button
class="btn btn-default"
class="btn button-default"
:disabled="usingFallback"
@click="add"
>

View File

@ -144,8 +144,8 @@
</router-link>
</li>
<li @click="toggleDrawer">
<a
href="#"
<button
class="button-unstyled -link -fullwidth"
@click="openSettingsModal"
>
<FAIcon
@ -153,7 +153,7 @@
class="fa-scale-110 fa-old-padding"
icon="cog"
/> {{ $t("settings.settings") }}
</a>
</button>
</li>
<li @click="toggleDrawer">
<router-link :to="{ name: 'about'}">
@ -183,8 +183,8 @@
v-if="currentUser"
@click="toggleDrawer"
>
<a
href="#"
<button
class="button-unstyled -link -fullwidth"
@click="doLogout"
>
<FAIcon
@ -192,7 +192,7 @@
class="fa-scale-110 fa-old-padding"
icon="sign-out-alt"
/> {{ $t("login.logout") }}
</a>
</button>
</li>
</ul>
</div>
@ -331,7 +331,7 @@
.side-drawer li {
padding: 0;
a {
a, button {
box-sizing: border-box;
display: block;
height: 3em;

View File

@ -47,16 +47,15 @@
>
{{ muteWordHits.join(', ') }}
</small>
<a
href="#"
class="unmute fa-scale-110 fa-old-padding"
<button
class="unmute button-unstyled"
@click.prevent="toggleMute"
>
<FAIcon
icon="eye-slash"
class="fa-scale-110 fa-old-padding"
/>
</a>
</button>
</div>
</template>
<template v-else>
@ -201,9 +200,9 @@
icon="external-link-square-alt"
/>
</a>
<a
<button
v-if="expandable && !isPreview"
href="#"
class="button-unstyled"
title="Expand"
@click.prevent="toggleExpanded"
>
@ -211,17 +210,17 @@
class="fa-scale-110 fa-old-padding"
icon="plus-square"
/>
</a>
<a
</button>
<button
v-if="unmuted"
href="#"
class="button-unstyled"
@click.prevent="toggleMute"
>
<FAIcon
icon="eye-slash"
class="fa-scale-110 fa-old-padding"
/>
</a>
</button>
</span>
</div>
@ -237,9 +236,8 @@
style="min-width: 0"
:class="{ '-strikethrough': !status.parent_visible }"
>
<a
class="reply-to"
href="#"
<button
class="button-unstyled reply-to"
:aria-label="$t('tool_tip.reply')"
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
>
@ -253,7 +251,7 @@
>
{{ $t('status.reply_to') }}
</span>
</a>
</button>
</StatusPopover>
<span
@ -286,11 +284,12 @@
:key="reply.id"
:status-id="reply.id"
>
<a
href="#"
class="reply-link"
<button
class="button-unstyled -link reply-link"
@click.prevent="gotoOriginal(reply.id)"
>{{ reply.name }}</a>
>
{{ reply.name }}
</button>
</StatusPopover>
</div>
</div>

View File

@ -12,35 +12,34 @@
@click.prevent="linkClicked"
v-html="status.summary_html"
/>
<a
<button
v-if="longSubject && showingLongSubject"
href="#"
class="tall-subject-hider"
class="button-unstyled -link tall-subject-hider"
@click.prevent="showingLongSubject=false"
>{{ $t("status.hide_full_subject") }}</a>
<a
>
{{ $t("status.hide_full_subject") }}
</button>
<button
v-else-if="longSubject"
class="tall-subject-hider"
class="button-unstyled -link tall-subject-hider"
:class="{ 'tall-subject-hider_focused': focused }"
href="#"
@click.prevent="showingLongSubject=true"
>
{{ $t("status.show_full_subject") }}
</a>
</button>
</div>
<div
:class="{'tall-status': hideTallStatus}"
class="status-content-wrapper"
>
<a
<button
v-if="hideTallStatus"
class="tall-status-hider"
class="button-unstyled -link tall-status-hider"
:class="{ 'tall-status-hider_focused': focused }"
href="#"
@click.prevent="toggleShowMore"
>
{{ $t("general.show_more") }}
</a>
</button>
<div
v-if="!hideSubjectStatus"
:class="{ 'single-line': singleLine }"
@ -48,10 +47,9 @@
@click.prevent="linkClicked"
v-html="postBodyHtml"
/>
<a
<button
v-if="hideSubjectStatus"
href="#"
class="cw-status-hider"
class="button-unstyled -link cw-status-hider"
@click.prevent="toggleShowMore"
>
{{ $t("status.show_content") }}
@ -79,15 +77,14 @@
v-if="status.card"
icon="link"
/>
</a>
<a
</button>
<button
v-if="showingMore && !fullContent"
href="#"
class="status-unhider"
class="button-unstyled -link status-unhider"
@click.prevent="toggleShowMore"
>
{{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
</a>
</button>
</div>
<div v-if="status.poll && status.poll.options && !hideSubjectStatus">

View File

@ -81,7 +81,7 @@ export default Vue.component('tab-switcher', {
const tabs = this.$slots.default
.map((slot, index) => {
if (!slot.tag) return
const classesTab = ['tab']
const classesTab = ['tab', 'button-default']
const classesWrapper = ['tab-wrapper']
if (this.activeIndex === index) {
classesTab.push('active')

View File

@ -4,7 +4,7 @@
<TimelineMenu v-if="!embedded" />
<button
v-if="showLoadButton"
class="loadmore-button"
class="button-default loadmore-button"
@click.prevent="showNewStatuses"
>
{{ loadButtonString }}
@ -61,13 +61,15 @@
>
{{ $t('timeline.no_more_statuses') }}
</div>
<a
<button
v-else-if="!timeline.loading"
href="#"
class="button-unstyled -link -fullwidth"
@click.prevent="fetchOlderStatuses()"
>
<div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div>
</a>
<div class="new-status-notification text-center panel-footer">
{{ $t('timeline.load_older') }}
</div>
</button>
<div
v-else
class="new-status-notification text-center panel-footer"

View File

@ -162,7 +162,7 @@
<template v-if="relationship.following">
<ProgressButton
v-if="!relationship.subscribing"
class="btn btn-default"
class="btn button-default"
:click="subscribeUser"
:title="$t('user_card.subscribe')"
>
@ -170,7 +170,7 @@
</ProgressButton>
<ProgressButton
v-else
class="btn btn-default toggled"
class="btn button-default toggled"
:click="unsubscribeUser"
:title="$t('user_card.unsubscribe')"
>
@ -192,14 +192,14 @@
<div>
<button
v-if="relationship.muting"
class="btn btn-default btn-block toggled"
class="btn button-default btn-block toggled"
@click="unmuteUser"
>
{{ $t('user_card.muted') }}
</button>
<button
v-else
class="btn btn-default btn-block"
class="btn button-default btn-block"
@click="muteUser"
>
{{ $t('user_card.mute') }}
@ -207,7 +207,7 @@
</div>
<div>
<button
class="btn btn-default btn-block"
class="btn button-default btn-block"
@click="mentionUser"
>
{{ $t('user_card.mention') }}

View File

@ -29,7 +29,7 @@
</div>
<div>
<button
class="btn btn-default"
class="btn button-default"
:disabled="processing"
@click="reportUser"
>

View File

@ -91,7 +91,11 @@ const withLoadMore = ({
{children}
</WrappedComponent>
<div class="with-load-more-footer">
{this.error && <a onClick={this.fetchEntries} class="alert error">{this.$t('general.generic_error')}</a>}
{this.error &&
<button onClick={this.fetchEntries} class="button-unstyled -link -fullwidth alert error">
{this.$t('general.generic_error')}
</button>
}
{!this.error && this.loading && <FAIcon spin icon="circle-notch"/>}
{!this.error && !this.loading && !this.bottomedOut && <a onClick={this.fetchEntries}>{this.$t('general.more')}</a>}
</div>

View File

@ -134,14 +134,14 @@
"registration": {
"bio": "Priskribo",
"email": "Retpoŝtadreso",
"fullname": "Vidiga nomo",
"fullname": "Prezenta nomo",
"password_confirm": "Konfirmo de pasvorto",
"registration": "Registriĝo",
"token": "Invita ĵetono",
"captcha": "TESTO DE HOMECO",
"new_captcha": "Klaku la bildon por akiri novan teston",
"username_placeholder": "ekz. lain",
"fullname_placeholder": "ekz. Lain Iwakura",
"fullname_placeholder": "ekz. Lain Ivakura",
"bio_placeholder": "ekz.\nSaluton, mi estas Lain.\nMi estas animea knabino vivanta en Japanujo. Eble vi konas min pro la retejo «Wired».",
"validations": {
"username_required": "ne povas resti malplena",
@ -164,7 +164,7 @@
"blocks_tab": "Blokitoj",
"btnRadius": "Butonoj",
"cBlue": "Blua (respondi, aboni)",
"cGreen": "Verda (kunhavigi)",
"cGreen": "Verda (diskonigi)",
"cOrange": "Oranĝa (ŝati)",
"cRed": "Ruĝa (nuligi)",
"change_password": "Ŝanĝi pasvorton",
@ -207,8 +207,8 @@
"import_theme": "Enlegi antaŭagordojn",
"inputRadius": "Enigaj kampoj",
"checkboxRadius": "Markbutonoj",
"instance_default": "(implicita: {value})",
"instance_default_simple": "(implicita)",
"instance_default": "(originale: {value})",
"instance_default_simple": "(originale)",
"interface": "Fasado",
"interfaceLanguage": "Lingvo de fasado",
"invalid_theme_imported": "La elektita dosiero ne estas subtenata haŭto de Pleromo. Neniuj ŝanĝoj al via haŭto okazis.",
@ -219,7 +219,7 @@
"loop_video_silent_only": "Ripetadi nur filmojn sen sono (ekz. la «GIF-ojn» de Mastodon)",
"mutes_tab": "Silentigoj",
"play_videos_in_modal": "Ludi filmojn en ŝpruca kadro",
"use_contain_fit": "Ne tondi la kunsendaĵon en bildetoj",
"use_contain_fit": "Ne pritondi bildetojn de kunsendaĵoj",
"name": "Nomo",
"name_bio": "Nomo kaj priskribo",
"new_password": "Nova pasvorto",
@ -265,7 +265,7 @@
"subject_line_email": "Kiel retpoŝto: «re: temo»",
"subject_line_mastodon": "Kiel Mastodon: kopii senŝanĝe",
"subject_line_noop": "Ne kopii",
"post_status_content_type": "Afiŝi specon de la enhavo de la stato",
"post_status_content_type": "Speco de enhavo de afiŝo",
"stop_gifs": "Movi GIF-bildojn dum ŝvebo de muso",
"streaming": "Ŝalti memagan fluigon de novaj afiŝoj kiam vi vidas la supron de la paĝo",
"text": "Teksto",
@ -379,7 +379,7 @@
"hint": "Por ombroj vi ankaŭ povas uzi --variable kiel koloran valoron, por uzi variantojn de CSS3. Bonvolu rimarki, ke tiuokaze agordoj de maltravidebleco ne funkcios.",
"filter_hint": {
"always_drop_shadow": "Averto: ĉi tiu ombro ĉiam uzas {0} kiam la foliumilo tion subtenas.",
"drop_shadow_syntax": "{0} ne subtenas parametron {1} kaj ŝlosilvorton {2}.",
"drop_shadow_syntax": "{0} ne subtenas parametron {1} kaj ĉefvorton {2}.",
"avatar_inset": "Bonvolu rimarki, ke agordi ambaŭ internajn kaj eksterajn ombrojn por profilbildoj povas redoni neatenditajn rezultojn ĉe profilbildoj travideblaj.",
"spread_zero": "Ombroj kun vastigo > 0 aperos kvazaŭ ĝi estus fakte nulo",
"inset_classic": "Internaj ombroj uzos {0}"
@ -394,7 +394,7 @@
"button": "Butono",
"buttonHover": "Butono (je ŝvebo)",
"buttonPressed": "Butono (premita)",
"buttonPressedHover": "Butono (premita kaj je ŝvebo)",
"buttonPressedHover": "Butono (je premo kaj ŝvebo)",
"input": "Eniga kampo"
},
"hintV3": "Kolorojn de ombroj vi ankaŭ povas skribi per la sistemo {0}."
@ -683,7 +683,7 @@
"replace": "Anstataŭigi",
"reject": "Rifuzi",
"ftl_removal": "Forigo el la historio de «La tuta konata reto»",
"keyword_policies": "Politiko pri ŝlosilvortoj"
"keyword_policies": "Politiko pri ĉefvortoj"
},
"federation": "Federado",
"mrf_policies_desc": "Politikoj de Mesaĝa ŝanĝilaro (MRF) efikas sur federa konduto de la nodo. La sekvaj politikoj estas ŝaltitaj:"
@ -739,8 +739,8 @@
"week_short": "{0}s",
"weeks": "{0} semajnoj",
"week": "{0} semajno",
"seconds_short": "{0}s",
"second_short": "{0}s",
"seconds_short": "{0}sek",
"second_short": "{0}sek",
"seconds": "{0} sekundoj",
"second": "{0} sekundo",
"now_short": "nun",
@ -749,14 +749,14 @@
"month_short": "{0}m",
"months": "{0} monatoj",
"month": "{0} monato",
"minutes_short": "{0}m",
"minute_short": "{0}m",
"minutes_short": "{0}min",
"minute_short": "{0}min",
"minutes": "{0} minutoj",
"minute": "{0} minuto",
"in_past": "antaŭ {0}",
"in_future": "post {0}",
"hours_short": "{0}h",
"hour_short": "{0}h",
"hours_short": "{0}hor",
"hour_short": "{0}hor",
"hours": "{0} horoj",
"hour": "{0} horo",
"days_short": "{0}t",

View File

@ -104,7 +104,8 @@
"no_more_notifications": "No hay más notificaciones",
"reacted_with": "reaccionó con {0}",
"migrated_to": "migrado a",
"follow_request": "quiere seguirte"
"follow_request": "quiere seguirte",
"error": "Error obteniendo notificaciones:{0}"
},
"polls": {
"add_poll": "Añadir encuesta",
@ -313,7 +314,7 @@
"hide_followers_count_description": "No mostrar el número de cuentas que me siguen",
"show_admin_badge": "Mostrar la insignia de Administrador en mi perfil",
"show_moderator_badge": "Mostrar la insignia de Moderador en mi perfil",
"nsfw_clickthrough": "Activar el clic para ocultar los adjuntos NSFW",
"nsfw_clickthrough": "Habilitar la ocultación de la imagen de vista previa del enlace y el adjunto para los estados NSFW por defecto",
"oauth_tokens": "Tokens de OAuth",
"token": "Token",
"refresh_token": "Actualizar el token",
@ -605,7 +606,8 @@
"up_to_date": "Actualizado",
"no_more_statuses": "No hay más estados",
"no_statuses": "Sin estados",
"reload": "Recargar"
"reload": "Recargar",
"error": "Error obteniendo la linea de tiempo:{0}"
},
"status": {
"favorites": "Favoritos",
@ -628,7 +630,9 @@
"copy_link": "Copiar el enlace al estado",
"status_unavailable": "Estado no disponible",
"bookmark": "Marcar",
"unbookmark": "Desmarcar"
"unbookmark": "Desmarcar",
"status_deleted": "Esta entrada ha sido eliminada",
"nsfw": "NSFW (No apropiado para el trabajo)"
},
"user_card": {
"approve": "Aprobar",

View File

@ -390,5 +390,13 @@
"GiB": "GiB",
"TiB": "TiB"
}
},
"about": {
"mrf": {
"keyword": {
"keyword_policies": "פוליסת מילות מפתח"
},
"federation": "פדרציה"
}
}
}

View File

@ -50,7 +50,8 @@
"follow_request": "vuole seguirti",
"no_more_notifications": "Fine delle notifiche",
"migrated_to": "è migrato verso",
"reacted_with": "ha reagito con {0}"
"reacted_with": "ha reagito con {0}",
"error": "Errore nel caricare le notifiche: {0}"
},
"settings": {
"attachments": "Allegati",
@ -427,7 +428,8 @@
"repeated": "condiviso",
"no_statuses": "Nessun messaggio",
"no_more_statuses": "Fine dei messaggi",
"reload": "Ricarica"
"reload": "Ricarica",
"error": "Errore nel caricare la sequenza: {0}"
},
"user_card": {
"follow": "Segui",
@ -703,7 +705,8 @@
"delete_confirm": "Vuoi veramente eliminare questo messaggio?",
"unbookmark": "Rimuovi segnalibro",
"bookmark": "Aggiungi segnalibro",
"status_deleted": "Questo messagio è stato cancellato"
"status_deleted": "Questo messagio è stato cancellato",
"nsfw": "Pruriginoso"
},
"time": {
"years_short": "{0}a",

View File

@ -18,7 +18,13 @@
"generic_error": "Произошла ошибка",
"optional": "не обязательно",
"show_less": "Показать меньше",
"show_more": "Показать больше"
"show_more": "Показать больше",
"peek": "Свернуть",
"dismiss": "Закрыть",
"retry": "Попробуйте еще раз",
"error_retry": "Пожалуйста попробуйте еще раз",
"close": "Закрыть",
"loading": "Загрузка…"
},
"login": {
"login": "Войти",
@ -33,8 +39,11 @@
"recovery_code": "Код восстановления",
"heading": {
"TotpForm": "Двухфакторная аутентификация",
"RecoveryForm": "Two-factor recovery"
}
"RecoveryForm": "Two-factor recovery",
"totp": "Двухфакторная аутентификация"
},
"hint": "Войдите чтобы присоединиться к дискуссии",
"description": "Войти с помощью OAuth"
},
"nav": {
"back": "Назад",
@ -46,7 +55,14 @@
"twkn": "Федеративная лента",
"search": "Поиск",
"friend_requests": "Запросы на чтение",
"bookmarks": "Закладки"
"bookmarks": "Закладки",
"chats": "Беседы",
"timelines": "Ленты",
"preferences": "Настройки",
"who_to_follow": "Кого читать",
"dms": "Личные Сообщения",
"administration": "Панель администратора",
"about": "О сервере"
},
"notifications": {
"broken_favorite": "Неизвестный статус, ищем...",
@ -56,12 +72,17 @@
"notifications": "Уведомления",
"read": "Прочесть",
"repeated_you": "повторил(а) ваш статус",
"follow_request": "хочет читать вас"
"follow_request": "хочет читать вас",
"reacted_with": "добавил реакцию: {0}",
"migrated_to": "мигрировал на",
"no_more_notifications": "Нет дальнейших уведомлений",
"error": "Ошибка при обновлении уведомлений: {0}"
},
"interactions": {
"favs_repeats": "Повторы и фавориты",
"follows": "Новые подписки",
"load_older": "Загрузить старые взаимодействия"
"follows": "Новые читатели",
"load_older": "Загрузить старые взаимодействия",
"moves": "Миграции пользователей"
},
"post_status": {
"account_not_locked_warning": "Ваш аккаунт не {0}. Кто угодно может начать читать вас чтобы видеть посты только для подписчиков.",
@ -81,7 +102,21 @@
"private": "Для подписчиков - этот пост видят только подписчики",
"public": "Публичный - этот пост виден всем",
"unlisted": "Непубличный - этот пост не виден на публичных лентах"
}
},
"preview_empty": "Пустой предпросмотр",
"media_description_error": "Не удалось обновить вложение, попробуйте еще раз",
"empty_status_error": "Нельзя отправить пустой статус без вложений",
"preview": "Предпросмотр",
"direct_warning_to_first_only": "Это сообщение увидят только пользователи упомянутые в его начале.",
"direct_warning_to_all": "Это сообщение увидят все упомянутые пользователи.",
"content_type": {
"text/bbcode": "BBCode",
"text/html": "HTML",
"text/markdown": "Markdown",
"text/plain": "Простой текст"
},
"media_description": "Описание вложения",
"new_status": "Написать новый статус"
},
"registration": {
"bio": "Описание",
@ -97,7 +132,12 @@
"password_required": "не должен быть пустым",
"password_confirmation_required": "не должно быть пустым",
"password_confirmation_match": "должно совпадать с паролем"
}
},
"bio_placeholder": "например:\nПривет, я Игорь Печкин.\nРаботаю почтальоном в деревне Простоквашино. С недавних пор велосипедист.",
"fullname_placeholder": "например: Почтальон Печкин",
"username_placeholder": "например: pechkin",
"captcha": "Код подтверждения",
"new_captcha": "Нажмите на изображение чтобы получить новый код"
},
"settings": {
"enter_current_password_to_confirm": "Введите свой текущий пароль",
@ -196,7 +236,7 @@
"hide_followers_count_description": "Не показывать число моих подписчиков",
"show_admin_badge": "Показывать значок администратора в моем профиле",
"show_moderator_badge": "Показывать значок модератора в моем профиле",
"nsfw_clickthrough": "Включить скрытие NSFW вложений",
"nsfw_clickthrough": "Включить скрытие NSFW вложений и не показывать изображения в предпросмотре ссылок для NSFW статусов",
"oauth_tokens": "OAuth токены",
"token": "Токен",
"refresh_token": "Рефреш токен",
@ -349,7 +389,60 @@
}
},
"allow_following_move": "Разрешить автоматически читать новый аккаунт при перемещении на другой сервер",
"hide_user_stats": "Не показывать статистику пользователей (например количество читателей)"
"hide_user_stats": "Не показывать статистику пользователей (например количество читателей)",
"discoverable": "Разрешить показ аккаунта в поисковиках и других сервисах",
"default_vis": "Видимость постов по умолчанию",
"mutes_and_blocks": "Блокировки и игнорируемые",
"composing": "Составление постов",
"chatMessageRadius": "Сообщения в беседе",
"blocks_tab": "Блокировки",
"import_mutes_from_a_csv_file": "Импортировать игнорируемых из CSV файла",
"mutes_imported": "Игнорируемые импортированы! Обработка может занять некоторое время.",
"mute_import_error": "Произошла ошибка при импорте игнорируемых",
"mute_import": "Импорт игнорируемых",
"block_export_button": "Экспортирует блокировки в CSV файл",
"mute_export_button": "Экспортирует игнорируемых пользователей в CSV файл",
"mute_export": "Экспорт игнорируемых",
"blocks_imported": "Блокировки импортированы! Обработка может занять некоторое время.",
"block_import_error": "Произошла ошибка при импорте блокировок",
"block_import": "Импорт блокировок",
"block_export": "Экспортировать блокировки",
"security": "Безопасность",
"app_name": "Приложение",
"user_mutes": "Пользователи",
"post_status_content_type": "Формат составляемых статусов по умолчанию",
"subject_line_noop": "Не копировать",
"subject_line_mastodon": "Как в Mastodon: скопировать как есть",
"subject_line_email": "Как в e-mail: \"re: тема\"",
"subject_line_behavior": "Копировать тему в ответах",
"no_mutes": "Нет игнорируемых",
"no_blocks": "Нет блокировок",
"notification_visibility_emoji_reactions": "Реакции",
"notification_visibility_moves": "Миграции пользователей",
"use_contain_fit": "Не обрезать вложения в миниатюрах",
"profile_fields": {
"value": "Значение",
"name": "Пункт",
"add_field": "Добавить поле",
"label": "Таблица метаданных профиля"
},
"play_videos_in_modal": "Проигрывать видео во всплывающей рамке",
"mutes_tab": "Игнорируемые",
"invalid_theme_imported": "Выбраный файл не является темой Pleroma. Изменений в тему не было внесено.",
"import_blocks_from_a_csv_file": "Импортировать блокировки из CSV файла",
"hide_filtered_statuses": "Не показывать отфильтрованные статусы",
"hide_muted_posts": "Не показывать статусы игнорируемых пользователей",
"hide_post_stats": "Не показывать статистику статусов (например количество отметок «Нравится»)",
"use_one_click_nsfw": "Открывать NSFW вложения одним кликом",
"preload_images": "Предварительно загружать изображения",
"max_thumbnails": "Максимальное число миниатюр показываемых в статусе",
"emoji_reactions_on_timeline": "Показывать эмодзи реакции в ленте",
"domain_mutes": "Узлы",
"notification_setting_privacy": "Приватность",
"notification_setting_block_from_strangers": "Не показывать уведомления от пользователей которых вы не читаете",
"notification_setting_filters": "Фильтрация",
"notifications": "Уведомления",
"virtual_scrolling": "Оптимизировать рендеринг ленты"
},
"timeline": {
"collapse": "Свернуть",
@ -363,7 +456,11 @@
},
"status": {
"bookmark": "В закладки",
"unbookmark": "Удалить из закладок"
"unbookmark": "Удалить из закладок",
"status_deleted": "Пост удален",
"reply_to": "Ответ",
"repeats": "Повторы",
"favorites": "Понравилось"
},
"user_card": {
"block": "Заблокировать",
@ -401,7 +498,11 @@
"quarantine": "Не федерировать посты пользователя",
"delete_user": "Удалить пользователя",
"delete_user_confirmation": "Вы уверены? Это действие нельзя отменить."
}
},
"media": "С вложениями",
"mention": "Упомянуть",
"show_repeats": "Показывать повторы",
"hide_repeats": "Скрыть повторы"
},
"user_profile": {
"timeline_title": "Лента пользователя"
@ -468,15 +569,84 @@
"media_proxy": "Прокси для внешних вложений",
"text_limit": "Лимит символов",
"title": "Особенности",
"gopher": "Gopher"
"gopher": "Gopher",
"who_to_follow": "Предложения кого читать",
"pleroma_chat_messages": "Pleroma Чат"
},
"tool_tip": {
"accept_follow_request": "Принять запрос на чтение",
"reject_follow_request": "Отклонить запрос на чтение"
"reject_follow_request": "Отклонить запрос на чтение",
"media_upload": "Прикрепить вложение"
},
"image_cropper": {
"save_without_cropping": "Сохранить не обрезая",
"save": "Сохранить",
"crop_picture": "Обрезать картинку"
"crop_picture": "Обрезать картинку",
"cancel": "Отменить"
},
"errors": {
"storage_unavailable": "Pleroma не смогла получить доступ к хранилищу браузера. Ваша сессия и настройки не будут сохранены, и вы можете столкнуться с непредвиденными проблемами. Попробуйте включить файлы cookie."
},
"polls": {
"not_enough_options": "Недостаточно уникальных вариантов в опросе",
"expired": "Опрос закончился {0} назад",
"expires_in": "Опрос заканчивается через {0}",
"expiry": "Срок опроса",
"multiple_choices": "Несколько вариантов",
"single_choice": "Один вариант",
"type": "Тип опроса",
"vote": "Проголосовать",
"votes": "голосов",
"option": "Вариант",
"add_option": "Добавить вариант",
"add_poll": "Прикрепить опрос"
},
"media_modal": {
"next": "Следующая",
"previous": "Предыдущая"
},
"importer": {
"error": "Произошла ошибка при импорте файла.",
"success": "Импорт прошел успешно.",
"submit": "Отправить"
},
"selectable_list": {
"select_all": "Выбрать все"
},
"emoji": {
"load_all": "Все {emojiAmount} эмодзи загружаются",
"load_all_hint": "Загружены первые {saneAmount} эмодзи, загрузка всех эмодзи может привести к проблемам с производительностью.",
"unicode": "Стандартные эмодзи",
"custom": "Пользовательские эмодзи",
"add_emoji": "Добавить эмодзи",
"search_emoji": "Поиск эмодзи",
"keep_open": "Оставить окно выбора открытым",
"emoji": "Эмодзи",
"stickers": "Стикеры"
},
"shoutbox": {
"title": "Болтовня"
},
"time": {
"days_short": "{0}дн",
"years_short": "{0}г",
"year_short": "{0}г",
"weeks_short": "{0}нед",
"week_short": "{0}нед",
"seconds_short": "{0}сек",
"second_short": "{0}с",
"now_short": "только что",
"now": "только что",
"months_short": "{0}мес",
"month_short": "{0}мес",
"minutes_short": "{0}мин",
"minute_short": "{0}мин",
"in_past": "{0} назад",
"in_future": "через {0}",
"hours_short": "{0}ч",
"hour_short": "{0}ч",
"hour": "{0} час",
"day_short": "{0}д",
"days": "{0} дней"
}
}

777
src/i18n/uk.json Normal file
View File

@ -0,0 +1,777 @@
{
"general": {
"dismiss": "Закрити",
"close": "Закрити",
"verify": "Перевірити",
"confirm": "Підтвердити",
"enable": "Увімкнути",
"disable": "Вимкнути",
"cancel": "Скасувати",
"show_less": "Показати менше",
"show_more": "Показати більше",
"optional": "необов'язково",
"retry": "Спробуйте ще раз",
"error_retry": "Будь ласка, спробуйте ще раз",
"generic_error": "Виникла помилка",
"loading": "Завантаження…",
"more": "Більше",
"submit": "Відправити",
"apply": "Застосувати",
"peek": "Глянути"
},
"finder": {
"error_fetching_user": "Користувача не знайдено",
"find_user": "Знайти користувача"
},
"features_panel": {
"gopher": "Gopher",
"pleroma_chat_messages": "Чат Pleroma",
"chat": "Чат",
"who_to_follow": "Кого відстежувати",
"title": "Особливості",
"scope_options": "Параметри осягу",
"media_proxy": "Посередник медіа-даних",
"text_limit": "Ліміт символів"
},
"exporter": {
"processing": "Опрацьовую, скоро ви зможете завантажити файл",
"export": "Експорт"
},
"domain_mute_card": {
"unmute_progress": "Вимикаю…",
"unmute": "Вимкнути ігнорування",
"mute_progress": "Вмикаю…",
"mute": "Ігнорувати"
},
"shoutbox": {
"title": "Міні-чат"
},
"about": {
"staff": "Адміністрація",
"mrf": {
"simple": {
"media_nsfw_desc": "Даний інстанс примусово позначає медіа в наступних інстансах як NSFW:",
"media_nsfw": "Примусове визначення медіа як дратівливого",
"media_removal_desc": "Поточний інстанс видаляє медіа з дописів на перелічених інстансах:",
"media_removal": "Видалення медіа",
"ftl_removal_desc": "Цей інстанс видаляє перелічені інстанси з \"Усієї відомої мережі\":",
"ftl_removal": "Видалення з \"Усієї відомої мережі\"",
"quarantine_desc": "Поточний інстанс буде надсилати тільки публічні дописи наступним інстансам:",
"quarantine": "Карантин",
"reject_desc": "Поточний інстанс не прийматиме повідомлення з перелічених інстансів:",
"accept": "Прийняти",
"reject": "Відхилити",
"accept_desc": "Поточний інстанс приймає повідомлення тільки з перелічених інстансів:",
"simple_policies": "Правила поточного інстансу"
},
"mrf_policies_desc": "Правила MRF розповсюджуються на даний інстанс. Наступні правила активні:",
"mrf_policies": "Активні правила MRF (модуль переписування повідомлень)",
"keyword": {
"is_replaced_by": "→",
"replace": "Замінити",
"reject": "Відхилити",
"ftl_removal": "Прибрати з федеративної стрічки",
"keyword_policies": "Політика щодо ключових слів"
},
"federation": "Федерація"
}
},
"login": {
"hint": "Увійдіть, щоб доєднатися до дискусії",
"username": "Ім'я користувача",
"register": "Зареєструватись",
"password": "Пароль",
"logout": "Вийти",
"description": "Увійти за допомогою OAuth",
"login": "Увійти",
"recovery_code": "Код відновлення",
"enter_recovery_code": "Введіть код відновлення",
"authentication_code": "Код автентифікації",
"heading": {
"recovery": "Двофакторне відновлення",
"totp": "Двофакторна автентифікація"
},
"enter_two_factor_code": "Введіть двофакторний код автентифікації",
"placeholder": "напр. stepan"
},
"importer": {
"error": "Під час імпортування файлу сталася помилка.",
"success": "Імпортовано успішно.",
"submit": "Відправити"
},
"image_cropper": {
"cancel": "Відмінити",
"save_without_cropping": "Зберегти не обрізаючи",
"crop_picture": "Обрізати малюнок",
"save": "Зберегти"
},
"polls": {
"expired": "Опитування закінчилось {0} тому",
"expires_in": "Опитування закінчується через {0}",
"expiry": "Термін опитування",
"multiple_choices": "Декілька варіантів",
"single_choice": "Один варіант",
"add_option": "Додати опцію",
"type": "Тип опитування",
"vote": "Проголосувати",
"votes": "голосів",
"option": "Відповідь",
"add_poll": "Додати опитування",
"not_enough_options": "Замало унікальних варіантів в опитуванні"
},
"notifications": {
"reacted_with": "додав реакцію: {0}",
"migrated_to": "мігрував на",
"no_more_notifications": "Немає більше сповіщень",
"repeated_you": "поширив(-ла) ваш допис",
"read": "Прочитано!",
"notifications": "Сповіщення",
"load_older": "Завантажити давніші сповіщення",
"follow_request": "хоче підписатись на вас",
"followed_you": "підписався(-лась) на вас",
"favorited_you": "вподобав(-ла) ваш допис",
"broken_favorite": "Невідомий допис, шукаю його…",
"error": "Помилка при оновленні сповіщень: {0}"
},
"nav": {
"chats": "Локальні балачки",
"timelines": "Стрічки",
"twkn": "Уся відома мережа",
"about": "Інформація",
"preferences": "Налаштування",
"friend_requests": "Запити послідовників",
"who_to_follow": "Кого відстежувати",
"search": "Пошук",
"user_search": "Пошук користувача",
"bookmarks": "Закладки",
"timeline": "Домашня стрічка",
"public_tl": "Публічна стрічка",
"dms": "Приватні повідомлення",
"interactions": "Взаємодії",
"mentions": "Згадування",
"back": "Назад",
"administration": "Адміністрування"
},
"media_modal": {
"next": "Наступна",
"previous": "Попередня"
},
"password_reset": {
"instruction": "Введіть свою адресу електронної пошти або ім’я користувача. Ми надішлемо вам посилання для скидання пароля.",
"placeholder": "Ваша електронна адреса або ім'я користувача",
"check_email": "Перевірте електронну пошту на наявність посилання для скидання пароля.",
"return_home": "Повернутися на головну сторінку",
"too_many_requests": "Ви досягли ліміту спроб, спробуйте ще раз пізніше.",
"password_reset_required_but_mailer_is_disabled": "Ви повинні скинути свій пароль, але скидання пароля вимкнено. Зверніться до адміністратора інстансу.",
"password_reset_disabled": "Скидання пароля вимкнено. Зверніться до адміністратора інстансу.",
"password_reset_required": "Для входу потрібно скинути пароль.",
"password_reset": "Відновити пароль",
"forgot_password": "Забули пароль?"
},
"chats": {
"you": "Ви:",
"message_user": "Повідомлення для {nickname}",
"delete": "Видалити",
"chats": "Чати",
"new": "Новий чат",
"empty_message_error": "Не вдається опублікувати порожнє повідомлення",
"more": "Більше",
"delete_confirm": "Ви дійсно хочете видалити це повідомлення?",
"error_loading_chat": "Під час завантаження чату сталася помилка.",
"error_sending_message": "Під час надсилання повідомлення сталася помилка.",
"empty_chat_list_placeholder": "У вас ще немає чатів. Почніть новий чат!"
},
"file_type": {
"audio": "Аудіо",
"video": "Відео",
"image": "Зображення",
"file": "Файл"
},
"display_date": {
"today": "Сьогодні"
},
"interactions": {
"load_older": "Завантажити давніші взаємодії",
"follows": "Нові підписки",
"favs_repeats": "Повтори та вподобайки",
"moves": "Міграції користувачів"
},
"errors": {
"storage_unavailable": "Pleroma не змогла отримати доступ до сховища браузеру. Ваша сесія та налаштування не будуть збережені, це може спричинити непередбачувані проблеми. Спробуйте увімкнути cookie."
},
"emoji": {
"stickers": "Стікери",
"custom": "Користувацькі емодзі",
"search_emoji": "Пошук емодзі",
"keep_open": "Тримати панель відкритою",
"add_emoji": "Додати емодзі",
"emoji": "Емодзі",
"load_all": "Всі {emojiAmount} эмодзі завантажуються",
"load_all_hint": "Завантажені перші {saneAmount} емодзі, завантаження всіх емодзі може призвести до проблем з продуктивністю.",
"unicode": "Стандартні емодзі"
},
"post_status": {
"content_type": {
"text/bbcode": "BBCode",
"text/markdown": "Markdown",
"text/html": "HTML",
"text/plain": "Простий текст"
},
"attachments_sensitive": "Позначити вкладення як чутливі",
"account_not_locked_warning_link": "замкнена",
"account_not_locked_warning": "Ваша обліковка не {0}. Будь-хто може відстежувати вас для перегляду дописів тільки для відстежувачів.",
"new_status": "Створити допис",
"direct_warning_to_first_only": "Цей допис побачать лише користувачі, що були згадані на початку повідомлення.",
"direct_warning_to_all": "Цей допис побачать всі згадані користувачі.",
"default": "Що нового?",
"content_warning": "Тема (необов'язково)",
"preview": "Попередній перегляд",
"posting": "Відправляється",
"empty_status_error": "Не можу опублікувати пустий статус без вкладень",
"scope": {
"unlisted": "Непублічний - цей допис буде відсутній у публічних стрічках",
"public": "Піблічний - цей допис побачать усі",
"private": "Для читачів - цей допис побачать лише ваші читачі",
"direct": "Приватний - цей допис побачать лише згадані користувачі"
},
"scope_notice": {
"unlisted": "Цей допис не буде видно в публічній стрічці та усій відомій мережі",
"private": "Цей допис побачать лише ваші підписники",
"public": "Цей допис бачитимуть усі"
},
"preview_empty": "Пустий",
"media_description_error": "Не вдалось оновити медіа, спробуйте ще раз",
"media_description": "Опис медіа"
},
"settings": {
"blocks_imported": "Блокування імпортовані! Їх обробка триватиме певний час.",
"block_import_error": "Помилка імпортування блокувань",
"block_import": "Імпорт блокувань",
"block_export_button": "Експорт блокувань у файл CSV",
"block_export": "Експорт блокувань",
"bio": "Про Вас",
"background": "Обкладинка",
"app_name": "Назва програми",
"follow_export": "Експортувати відстежуваних",
"filtering_explanation": "Усі статуси з цими словами будуть приховані, один на рядок",
"filtering": "Фільтрування",
"export_theme": "Зберегти переднабір",
"avatar_size_instruction": "Рекомендований мінімальний розмір для зображень аватара становить 150x150 пікселів.",
"delete_account_instructions": "Введіть ваш пароль в поле нижче, аби підтвердити видалення облікового запису.",
"delete_account_error": "Під час видалення вашого облікового запису виникла проблема. Якщо це трапляється постійно, будь ласка, зверніться до адміністратора вашого сервера.",
"delete_account_description": "Остаточно видалити ваш обліковий запис та усі ваші повідомлення.",
"delete_account": "Видалити обліковий запис",
"default_vis": "Обсяг видимості за замовчуванням",
"data_import_export_tab": "Імпорт/експорт даних",
"current_password": "Поточний пароль",
"confirm_new_password": "Підтвердіть новий пароль",
"composing": "Складання відповіді",
"collapse_subject": "Згорнути дописи з темами",
"changed_password": "Пароль успішно змінено!",
"change_password_error": "Не вдалося змінити пароль.",
"change_password": "Змінити пароль",
"cRed": "Червоний (Скасувати)",
"cGreen": "Зелений (Поширити)",
"cOrange": "Жовтогарячий (Вподобайки)",
"cBlue": "Блакитний (Відповісти, читати)",
"btnRadius": "Кнопки",
"blocks_tab": "Блокування",
"avatarRadius": "Аватарки",
"avatarAltRadius": "Аватарки у сповіщеннях",
"avatar": "Аватар",
"attachments": "Вкладення",
"attachmentRadius": "Вкладення",
"general": "Загальні",
"foreground": "Передній план",
"follows_imported": "Відстежуваних імпортовано! Їхня обробка потребує часу.",
"follow_import_error": "Помилка імпортування відстежуваних",
"follow_import": "Імпортувати відстежуваних",
"follow_export_button": "Експортувати відстежуваних до csv файлу",
"lock_account_description": "Обмежте свій обліковий запис лише схваленими читачами",
"links": "Посилання",
"limited_availability": "Недоступно у вашому браузері",
"invalid_theme_imported": "Вибраний файл не є темою Pleroma. У вашу тему не внесено жодних змін.",
"interfaceLanguage": "Мова оболонки",
"interface": "Оболонка",
"instance_default_simple": "(за замовчуванням)",
"instance_default": "(за замовчуванням: {value})",
"checkboxRadius": "Прапорці",
"inputRadius": "Поля вводу",
"import_theme": "Завантажити переднабір",
"import_followers_from_a_csv_file": "Імпортувати відстежуваних з csv файлу",
"import_blocks_from_a_csv_file": "Імпортувати заблокованих з csv файлу",
"hide_filtered_statuses": "Сховати відфільтровані статуси",
"hide_user_stats": "Приховувати статистику користувачів (напр. кількість відстежувачів)",
"hide_post_stats": "Приховувати статистику дописів (напр. кількість вподобаних)",
"use_one_click_nsfw": "Відкривати NSFW вкладення одним кліком миші",
"preload_images": "Передзавантажувати світлини",
"hide_isp": "Сховати панель з особливостями сервера",
"max_thumbnails": "Максимальна кількість мініатюр на повідомлення",
"hide_muted_posts": "Приховати повідомлення приглушених користувачів",
"hide_attachments_in_tl": "Приховувати вкладення у стрічці",
"hide_attachments_in_convo": "Приховувати вкладення у розмовах",
"mutes_tab": "Заглушені",
"loop_video_silent_only": "Зациклити відео без звуку (напр. Mastodon \"gifs\")",
"loop_video": "Зациклити відео",
"mfa": {
"verify": {
"desc": "Щоб увімкнути двофакторну автентифікацію, введіть код з вашого застосунку для двофакторної автентифікації:"
},
"scan": {
"desc": "Відскануйте цей QR-код за допомогою програми двофакторної автентифікації або введіть текстовий ключ:",
"title": "Сканування",
"secret_code": "Ключ"
},
"authentication_methods": "Методи автентифікації",
"recovery_codes_warning": "Запишіть ці коди і тримайте в безпечному місці - інакше ви їх ніколи не побачите. Якщо ви втратите доступ до OTP додатку - без резервних кодів ви не зможете отримати доступ до свого облікового запису.",
"waiting_a_recovery_codes": "Отримую резервні коди…",
"recovery_codes": "Резервні коди.",
"warning_of_generate_new_codes": "Після отримання нових резервних кодів, старі перестануть працювати.",
"generate_new_recovery_codes": "Згенерувати нові резервні коди",
"title": "Двофакторна автентифікація",
"confirm_and_enable": "Підтвердити та увімкнути OTP",
"wait_pre_setup_otp": "попереднє налаштування OTP",
"setup_otp": "Налаштування OTP",
"otp": "OTP"
},
"enter_current_password_to_confirm": "Введіть свій поточний пароль",
"security": "Безпека",
"domain_mutes": "Домени",
"discoverable": "Дозволити виявлення цього облікового запису в результатах пошуку та інших службах",
"mutes_and_blocks": "Заглушені та блоковані",
"changed_email": "Email успішно змінено!",
"change_email_error": "Сталася помилка під час зміни email.",
"change_email": "Змінити email",
"bot": "Це обліковий запис бота",
"import_mutes_from_a_csv_file": "Імпорт заглушених з csv файлу",
"mutes_imported": "Заглушені імпортовані! Їх обробка триватиме певний час.",
"mute_export_button": "Експорт заглушених у csv файл",
"mute_import_error": "Під час імпорту заглушених сталася помилка",
"mute_import": "Імпорт ігнорувань",
"mute_export": "Експорт ігнорувань",
"new_password": "Новий пароль",
"new_email": "Нова ел. пошта",
"name_bio": "Особисті дані",
"set_new_profile_banner": "Встановити новий банер",
"set_new_avatar": "Встановити новий аватар",
"security_tab": "Безпека",
"saving_ok": "Налаштування збережені",
"saving_err": "Помилка при збереженні налаштувань",
"reply_visibility_self": "Показувати лише адресовані мені відповіді",
"reply_visibility_following": "Показувати відповіді адресовані лише мені або користувачам, яких я читаю",
"reply_visibility_all": "Показати всі відповіді",
"replies_in_timeline": "Відповіді в стрічці",
"profile_tab": "Профіль",
"profile_banner": "Банер профілю",
"profile_background": "Обкладинка профілю",
"revoke_token": "Відкликати",
"oauth_tokens": "OAuth ключі",
"token": "Ключ",
"refresh_token": "Оновити ключ",
"valid_until": "Діє до",
"use_contain_fit": "Не обрізати краї мініатюр",
"name": "Ім'я",
"profile_fields": {
"value": "Зміст",
"name": "Назва",
"add_field": "Додати поле",
"label": "Метадані профілю"
},
"play_videos_in_modal": "Відтворювати відео у спливаючій рамці",
"accent": "Акцент",
"chatMessageRadius": "Повідомлення в бесіді",
"notification_mutes": "Щоб перестати отримувати сповіщення від певного користувача, заглушіть його.",
"user_mutes": "Користувачі",
"no_mutes": "Заглушені відсутні",
"emoji_reactions_on_timeline": "Показувати реакції емоджі на стрічці",
"pad_emoji": "Додавати простір з обидвох сторін емоджі, при додаванні з панелі",
"allow_following_move": "Дозволити автостеження при переміщенні на інший інстанс",
"set_new_profile_background": "Встановити нову обкладинку профілю",
"radii_help": "Радіус заокруглення кутів інтерфейсу (в пікселях)",
"presets": "Переднабір",
"show_moderator_badge": "Показувати значок модератора в моєму профілі",
"show_admin_badge": "Показувати значок адміністратора в моєму профілі",
"hide_followers_description": "Не показувати хто підписаний на мене",
"hide_follows_description": "Не показувати на кого я підписаний",
"no_rich_text_description": "Видалення всього форматування тексту з усіх дописів",
"notification_visibility_emoji_reactions": "Реакції",
"notification_visibility_moves": "Міграція користувача",
"notification_visibility_repeats": "Поширення допису",
"notification_visibility_mentions": "Згадування",
"notification_visibility_likes": "Вподобайки",
"notification_visibility_follows": "Нові підписки",
"notification_visibility": "Отримувати сповіщення про наступні події",
"settings": "Налаштування",
"panelRadius": "Панелі",
"text": "Текст",
"tooltipRadius": "Підказки/попередження",
"values": {
"true": "так",
"false": "ні"
},
"user_settings": "Користувацькі налаштування",
"upload_a_photo": "Завантажити фото",
"theme": "Тема",
"style": {
"switcher": {
"keep_fonts": "Залишити шрифти",
"keep_roundness": "Залишити скруглення",
"keep_opacity": "Залишити прозорості",
"keep_shadows": "Залишити тіні",
"keep_color": "Залишити кольори",
"use_source": "Нова версія",
"use_snapshot": "Стара версія",
"load_theme": "Завантажити тему",
"reset": "Скинути",
"clear_all": "Очистити все",
"help": {
"older_version_imported": "Імпортований файл було створено в старішій версії FE.",
"future_version_imported": "Імпортований файл було створено в новішій версії FE.",
"v2_imported": "Файл, який ви імпортували, був створений для старішої версії інтерфейсу Pleroma. Ми намагаємось покращити сумісність, але все одно можуть бути розбіжності.",
"upgraded_from_v2": "PleromaFE було оновлено, тема може дещо відрізнятися від тієї, яку ви пам’ятаєте.",
"snapshot_source_mismatch": "Конфлікт версій: Швидше за все, FE повернуто до попередньої версії та оновлено знову, якщо ви змінили тему за допомогою старішої версії FE, швидше за все, ви хочете використовувати стару версію, інакше використовуйте нову версію.",
"migration_napshot_gone": "З якоїсь причини знімок зник, деякі речі можуть бути не такими, як ви пам’ятаєте.",
"migration_snapshot_ok": "Для безпеки, знімок теми завантажено. Ви можете спробувати завантажити дані теми.",
"fe_downgraded": "Версію PleromaFE змінено на старшу.",
"fe_upgraded": "Двигун теми PleromaFE оновлено.",
"snapshot_missing": "У файлі немає жодного знімка теми, тому він може виглядати інакше, ніж передбачалося спочатку.",
"snapshot_present": "Знімок теми завантажено, тому всі значення було перезаписано. Натомість ви можете завантажити правильні дані теми."
},
"keep_as_is": "Залишити як є",
"clear_opacity": "Очистити прозорість",
"save_load_hint": "Параметри \"Зберегти\" зберігають встановлені на даний момент параметри під час вибору або завантаження тем, вони також зберігають зазначені параметри під час експорту теми. Коли всі прапорці знято, експортування теми збереже все."
},
"common": {
"color": "Колір",
"contrast": {
"context": {
"text": "для тексту",
"18pt": "для великого (18pt+) тексту"
},
"level": {
"bad": "Не відповідає жодним вимогам щодо доступності",
"aaa": "відповідає вимогам рівня ААA (рекомендований)",
"aa": "відповідає вимогам рівня АА (мінімальний)"
},
"hint": "Рівень контрасту: {ratio}, {level} {context}"
},
"opacity": "Прозорість"
},
"preview": {
"mono": "змісту",
"text": "Трохи більше {0} та {1}",
"button": "Кнопка",
"error": "Приклад помилки",
"content": "Зміст",
"header": "Попередній перегляд",
"link": "невеличке посилання",
"header_faint": "Це нормально",
"input": "Що нового?",
"checkbox": "Я переглянув умови використання",
"fine_print": "Прочитайте наш {0} аби нічого нового не дізнатись!",
"faint_link": "корисний підручник"
},
"shadows": {
"components": {
"button": "Кнопка",
"input": "Поле вводу",
"panel": "Панель",
"panelHeader": "Заголовок панелі",
"avatarStatus": "Аватар користувача (в стрічці)",
"avatar": "Аватар користувача (профіль)",
"buttonPressedHover": "Кнопка (натиснута + наведенний курсор)",
"buttonPressed": "Кнопка (натиснута)",
"buttonHover": "Кнопка (при наведенні)",
"popup": "Спливаючі вікна та підказки"
},
"component": "Компонент",
"filter_hint": {
"inset_classic": "Тіні спрямовані всередину використовуватимуть {0}",
"spread_zero": "Тіні з поширенням > 0 відображатимуться так, ніби було встановлено нуль",
"avatar_inset": "Зауважте, що використання як вставних, так і невставних тіней на аватарах може привести до непередбачуваних результатів із прозорими аватарами.",
"drop_shadow_syntax": "{0} не підтримує параметр {1} та ключове слово {2}.",
"always_drop_shadow": "Увага! Ця тінь завжди використовує {0}, якщо підтримується браузером."
},
"inset": "Всередину",
"blur": "Розмиття",
"shadow_id": "Тінь №{value}",
"override": "Перевизначити",
"_tab_label": "Тінь і підсвічування",
"hintV3": "Для тіней ви також можете використовувати позначення {0} для використання іншого кольорового слота."
},
"fonts": {
"components": {
"input": "Поля вводу",
"interface": "Інтерфейс",
"postCode": "Моноширинний текст в дописі (форматований текст)",
"post": "Текст допису"
},
"_tab_label": "Шрифти",
"size": "Розмір (в пікселях)",
"custom": "Нестандартний",
"weight": "Товщина",
"family": "Назва шрифту",
"help": "Виберіть шрифт для елементів інтерфейсу. Для \"нестандартного\" потрібно ввести точну назву шрифту, так як вона відображається в системі."
},
"advanced_colors": {
"alert_warning": "Попередження",
"underlay": "Тло",
"inputs": "Поля входу",
"buttons": "Кнопки",
"borders": "Кордони",
"top_bar": "Верхня панель",
"panel_header": "Заголовок панелі",
"badge_notification": "Сповіщення",
"popover": "Підказки, меню, поповери",
"badge": "Тло значків",
"post": "Дописи/Дані користувачів",
"alert_neutral": "Нейтральний",
"alert_error": "Помилки",
"alert": "Фон сповіщень",
"_tab_label": "Додатково",
"selectedPost": "Вибраний допис",
"highlight": "Виділені елементи",
"poll": "Діаграма опитування",
"icons": "Іконки",
"faint_text": "Затемнений текст",
"chat": {
"border": "Кайма",
"outgoing": "Вихідні повідомлення",
"incoming": "Вхідні повідомлення"
},
"toggled": "Переключено",
"disabled": "Вимкнено",
"selectedMenu": "Вибраний пункт меню",
"tabs": "Вкладки",
"pressed": "Натиснуто"
},
"common_colors": {
"rgbo": "Піктограми, акценти, значки",
"foreground_hint": "Перегляньте вкладку \"Додатково\" для більшого контролю",
"main": "Загальні кольори",
"_tab_label": "Загальні"
},
"radii": {
"_tab_label": "Округлість"
}
},
"enable_web_push_notifications": "Увімкнути web push-сповіщення",
"notifications": "Сповіщення",
"fun": "Розваги",
"notification_setting_privacy": "Приватність",
"notification_setting_filters": "Фільтри",
"reset_avatar": "Скинути аватар",
"reset_profile_background": "Скинути обкладинку профілю",
"reset_avatar_confirm": "Ви дійсно хочете скинути аватар?",
"reset_profile_banner": "Скинули банер профілю",
"hide_follows_count_description": "Не показувати на кого я підписаний",
"reset_banner_confirm": "Ви дійсно хочете скинути банер?",
"reset_background_confirm": "Ви дійсно хочете скинути обкладинку?",
"subject_line_behavior": "Вигляд теми при відповіді",
"subject_input_always_show": "Завжди показувати поле для вводу теми",
"minimal_scopes_mode": "Мінімізувати набір варіантів осягу для допису",
"scope_copy": "Копіювати осяг при відповіді (завжди ввімкнено для особистих повідомлень)",
"search_user_to_mute": "Шукайте кого ви хочете заглушити",
"search_user_to_block": "Шукайте кого ви хочете заблокувати",
"autohide_floating_post_button": "Автоматично ховати кнопку \"Новий допис\" (в мобільній версії)",
"pause_on_unfocused": "Призупинити трансляцію, коли вкладка неактивна",
"hide_followers_count_description": "Не показувати кількість читачів",
"notification_blocks": "Блокування користувача зупиняє всі сповіщення від нього, а також скасовує його відстеження.",
"notification_setting_hide_notification_contents": "Ховати відправника та вміст push-сповіщень",
"notification_setting_block_from_strangers": "Блокувати сповіщення від користувачів за якими ви не слідкуєте",
"type_domains_to_mute": "Пошук доменів для заглушення",
"nsfw_clickthrough": "Увімкнути приховування NSFW медіа",
"greentext": "Мемний текст",
"virtual_scrolling": "Оптимізувати оновлення стрчки",
"theme_help_v2_2": "Піктограми під деякими записами є показниками контрасту між фоном та текстом. Коли ви наведете на них курсор, ви отримаєте детальну інформацію. Пам'ятайте, якщо ви використовуєте прозорість, індикатори показують найгірший варіант.",
"theme_help_v2_1": "Ви також можете замінити кольори та видимість окремих компонентів, перемикаючи прапорці, використовуйте \"Очистити все\", щоб видалити всі заміни.",
"theme_help": "Використовувати шістнадцяткові коди кольору (#rrggbb) щоб редагувати тему.",
"no_blocks": "Блокування відсутні",
"subject_line_mastodon": "Як в mastodon: просто скопіювати",
"subject_line_email": "Як в email: \"re: тема\"",
"useStreamingApiWarning": "(Не рекомендується, експериментально, повідомлення можуть зникати)",
"useStreamingApi": "Отримувати повідомлення та сповіщення в режимі реального часу",
"streaming": "Ввімкнути автоматичне завантаження нових повідомлень при прокручуванні вгору",
"stop_gifs": "Відтворювати GIF анімації тільки при наведенні",
"post_status_content_type": "Тип вмісту допису",
"subject_line_noop": "Не копіювати",
"version": {
"frontend_version": "Версія фронтенду",
"backend_version": "Версія бекенду",
"title": "Версія"
}
},
"selectable_list": {
"select_all": "Вибрати все"
},
"remote_user_resolver": {
"error": "Не знайдено.",
"searching_for": "Шукаю",
"remote_user_resolver": "Пошукова система для віддалених користувачів"
},
"registration": {
"validations": {
"password_confirmation_match": "пароль та підтвердження паролю мають співпадати",
"password_confirmation_required": "не може бути порожнім",
"password_required": "не може бути порожнім",
"email_required": "не може бути порожнім",
"fullname_required": "не може бути порожнім",
"username_required": "не може бути порожнім"
},
"bio_placeholder": "напр.\nНаш народ завжди прагне волі для себе і бажає її для інших народів. Він боровся і бореться за правду і справедливість. Ми хочемо жити у згоді і взаємному шануванні з усіми народами доброї волі. Такі самі права визнаємо за іншими народами, за які боремося для себе.",
"fullname_placeholder": "напр. Степан Бандера",
"username_placeholder": "напр. stepan",
"new_captcha": "Натисніть на зображення, щоб оновити код, якщо він нерозбірливий",
"token": "Ключ запрошення",
"registration": "Реєстрація",
"password_confirm": "Підтвердження паролю",
"fullname": "Відображене ім'я",
"email": "Ел. пошта",
"bio": "Про себе",
"captcha": "CAPTCHA"
},
"who_to_follow": {
"who_to_follow": "На кого підписатися",
"more": "Більше"
},
"tool_tip": {
"repeat": "Поширити",
"reply": "Відповісти",
"add_reaction": "Додати реакцію",
"user_settings": "Налаштування користувача",
"favorite": "Подобається",
"reject_follow_request": "Відхилити запит на підписку",
"accept_follow_request": "Прийняти запит на підписку",
"media_upload": "Завантажити медіа"
},
"upload": {
"error": {
"base": "Збій при завантаженні.",
"file_too_big": "Файл завеликий [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Спробуйте ще раз пізніше"
},
"file_size_units": {
"TiB": "ТіБ",
"GiB": "ГіБ",
"MiB": "МіБ",
"KiB": "КіБ",
"B": "Б"
}
},
"time": {
"weeks_short": "{0}тижд.",
"week_short": "{0}тижд.",
"years_short": "{0}р",
"year_short": "{0}р",
"years": "{0} роки",
"year": "{0} рік",
"weeks": "{0} тижднів",
"week": "{0} тиждень",
"second_short": "{0}с",
"second": "{0} секунда",
"now_short": "щойно",
"now": "щойно",
"months_short": "{0}міс.",
"month_short": "{0}міс.",
"months": "{0} місяці",
"month": "{0} місяць",
"minutes_short": "{0}хв",
"hours_short": "{0}год",
"hour_short": "{0}год",
"day_short": "{0}д",
"minute_short": "{0}хв",
"minutes": "{0} хвилини",
"minute": "{0} хвилина",
"in_past": "{0} тому",
"hours": "{0} години",
"hour": "{0} година",
"days_short": "{0}д",
"days": "{0} дні",
"day": "{0} день",
"seconds_short": "{0}с",
"seconds": "{0} секунди",
"in_future": "через {0}"
},
"search": {
"no_results": "Немає результатів",
"hashtags": "Хештеги",
"people": "Люди"
},
"user_card": {
"statuses": "Дописи",
"message": "Повідомлення",
"follow": "Підписатись",
"follow_unfollow": "Відписатись",
"follow_again": "Відправити запит знову?",
"follow_sent": "Запит відправлено!",
"blocked": "Заблоковано!",
"admin_menu": {
"activate_account": "Активувати обліковий запис",
"deactivate_account": "Деактивувати обліковий запис",
"delete_account": "Видалити аккаунт",
"moderation": "Модерація",
"delete_user_confirmation": "Ви абсолютно впевнені? Цю дію неможливо буде скасовувати.",
"delete_user": "Видалити обліковий запис",
"strip_media": "Вилучити медіа з дописів користувача",
"force_nsfw": "Позначити всі дописи як NSFW"
},
"deny": "Відмовити",
"block": "Заблокувати",
"approve": "Схвалити",
"mention": "Згадати",
"unsubscribe": "Відписатись",
"subscribe": "Підписатись",
"report": "Поскаржитись",
"per_day": "на день",
"favorites": "Вподобання",
"media": "Медіа"
},
"status": {
"copy_link": "Скопіювати посилання на допис",
"status_unavailable": "Допис недоступний",
"replies_list": "Відповіді:",
"delete_confirm": "Ви дійсно хочете видалити цей допис?",
"delete": "Видалити допис",
"pin": "Закріпити в профілі",
"status_deleted": "Цей допис був видалений",
"favorites": "Вподобане",
"hide_content": "Сховати вміст",
"show_content": "Показати вміст",
"hide_full_subject": "Сховати всю тему",
"show_full_subject": "Показати всю тему",
"thread_muted_and_words": ", має слова:",
"mute_conversation": "Заглушити розмову",
"reply_to": "Відповідь",
"unbookmark": "Видалити із закладок",
"bookmark": "Додати до закладок",
"pinned": "Закріплено",
"unpin": "Відкріпити від профілю",
"repeats": "Повтори"
},
"timeline": {
"no_more_statuses": "Більше немає дописів",
"up_to_date": "Оновлено",
"reload": "Оновити",
"show_new": "Показати нові",
"load_older": "Завантажити давніші дописи",
"error": "Помилка завантаження стрічки: {0}",
"collapse": "Згорнути",
"conversation": "Розмова",
"no_statuses": "Ніяких статусів",
"repeated": "поширив(-ла)",
"no_retweet_hint": "Запис, позначено як \"тільки для відстежувачів\" або \"особисте\" і тому не може бути повторений"
},
"user_reporting": {
"submit": "Відправити",
"forward_to": "Переслати до {0}",
"forward_description": "Цей обліковий запис належить іншому інстансу. Відправити їм копію скарги?",
"additional_comments": "Додаткове пояснення",
"add_comment_description": "Скарга буде надіслана модераторам вашого інстансу. Нижче Ви можете додати пояснення чому ви вирішили поскаржитись на цей обліковий запис:",
"title": "Поскаржитись на {0}",
"generic_error": "Виникла помилка під час обробки вашого запиту."
},
"user_profile": {
"profile_loading_error": "Вибачте, під час завантаження цього профілю виникла помилка.",
"profile_does_not_exist": "Вибачте, цей профіль більше не існує."
}
}

View File

@ -22,7 +22,7 @@
},
"general": {
"apply": "应用",
"submit": "提交",
"submit": "发送",
"more": "更多",
"generic_error": "发生了一个错误",
"optional": "可选",
@ -297,7 +297,7 @@
"hide_follows_description": "不要显示我所关注的人",
"hide_followers_description": "不要显示关注我的人",
"show_admin_badge": "显示管理徽章",
"show_moderator_badge": "显示版主徽章",
"show_moderator_badge": "在我的个人资料中显示监察员标志",
"nsfw_clickthrough": "将不和谐附件隐藏,点击才能打开",
"oauth_tokens": "OAuth令牌",
"token": "令牌",
@ -655,8 +655,8 @@
"moderation": "权限",
"grant_admin": "赋予管理权限",
"revoke_admin": "撤销管理权限",
"grant_moderator": "赋予版主权限",
"revoke_moderator": "撤销版主权限",
"grant_moderator": "赋予监察员权限",
"revoke_moderator": "撤销监察员权限",
"activate_account": "激活账号",
"deactivate_account": "关闭账号",
"delete_account": "删除账号",
@ -683,7 +683,7 @@
},
"user_reporting": {
"title": "报告 {0}",
"add_comment_description": "此报告会发送给您的实例管理员。您可以在下面提供更多详细信息解释报告的缘由:",
"add_comment_description": "此报告会发送给您的实例监察员。您可以在下面提供更多详细信息解释报告的缘由:",
"additional_comments": "其它信息",
"forward_description": "这个账号是从另外一个服务器。同时发送一个副本到那里?",
"forward_to": "转发 {0}",

View File

@ -21,7 +21,7 @@ const clear = (storage) => {
failedMessageIds.push(message.id)
} else {
delete storage.idIndex[message.id]
delete storage.idempotencyKeyIndex[message.id]
delete storage.idempotencyKeyIndex[message.idempotency_key]
}
}

File diff suppressed because it is too large Load Diff

67
tools/emoji_merger.js Normal file
View File

@ -0,0 +1,67 @@
/*
Emoji merger script, quick hack of a tool to:
- update some missing emoji from an external source
- sort the emoji
- remove all multipart emoji (reactions don't allow them)
Merges emoji from here: https://gist.github.com/oliveratgithub/0bf11a9aff0d6da7b46f1490f86a71eb
to the simpler format we're using.
*/
// Existing emojis we have
const oldEmojiFilename = '../static/emoji.json'
// The file downloaded from https://gist.github.com/oliveratgithub/0bf11a9aff0d6da7b46f1490f86a71eb
const newEmojiFilename = 'emojis.json'
// Output, replace the static/emoji.json with this file if it looks correct
const outputFilename = 'output.json'
const run = () => {
const fs = require('fs')
let newEmojisObject = {}
let emojisObject = {}
let data = fs.readFileSync(newEmojiFilename, 'utf8')
// First filter out anything that's more than one codepoint
const newEmojis = JSON.parse(data).emojis.filter(e => e.emoji.length <= 2)
// Create a table with format { shortname: emoji }, remove the :
newEmojis.forEach(e => {
const name = e.shortname.slice(1, e.shortname.length - 1).toLowerCase()
if (name.length > 0) {
newEmojisObject[name] = e.emoji
}
})
data = fs.readFileSync(oldEmojiFilename, 'utf8')
emojisObject = JSON.parse(data)
// Get rid of longer emojis that don't play nice with reactions
Object.keys(emojisObject).forEach(e => {
if (emojisObject[e].length > 2) emojisObject[e] = undefined
})
// Add new emojis from the new tables to the old table
Object.keys(newEmojisObject).forEach(e => {
if (!emojisObject[e] && newEmojisObject[e].length <= 2) {
emojisObject[e] = newEmojisObject[e]
}
})
// Sort by key
const sorted = Object.keys(emojisObject).sort().reduce((acc, key) => {
if (key.length === 0) return acc
acc[key] = emojisObject[key]
return acc
}, {})
fs.writeFile(outputFilename, JSON.stringify(sorted, null, 2), 'utf8', (err) => {
if (err) console.log('Error writing file', err)
})
}
run()

4036
tools/emojis.json Normal file

File diff suppressed because it is too large Load Diff