Merge branch 'develop' into feat/report-notification
This commit is contained in:
commit
1fd1553a1c
100 changed files with 6513 additions and 1627 deletions
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -5,9 +5,23 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
|
||||||
|
|
||||||
## [Unreleased]
|
## [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
|
||||||
- Fixed the occasional bug where screen would scroll 1px when typing into a reply form
|
- 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 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
|
||||||
|
- Made reply/fav/repeat etc buttons easier to hit
|
||||||
|
|
||||||
|
|
||||||
## [2.2.1] - 2020-11-11
|
## [2.2.1] - 2020-11-11
|
||||||
|
@ -22,6 +36,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
- Import/export a muted users
|
- Import/export a muted users
|
||||||
- Proper handling of deletes when using websocket streaming
|
- Proper handling of deletes when using websocket streaming
|
||||||
- Added optimistic chat message sending, so you can start writing next message before the previous one has been sent
|
- Added optimistic chat message sending, so you can start writing next message before the previous one has been sent
|
||||||
|
- Added a small red badge to the favicon when there's unread notifications
|
||||||
|
- Added the NSFW alert to link previews
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Fixed clicking NSFW hider through status popover
|
- Fixed clicking NSFW hider through status popover
|
||||||
|
|
65
src/App.scss
65
src/App.scss
|
@ -33,6 +33,7 @@ h4 {
|
||||||
max-width: 980px;
|
max-width: 980px;
|
||||||
align-content: flex-start;
|
align-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.underlay {
|
.underlay {
|
||||||
background-color: rgba(0,0,0,0.15);
|
background-color: rgba(0,0,0,0.15);
|
||||||
background-color: var(--underlay, 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);
|
color: var(--link, $fallback--link);
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
.button-default {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnText, $fallback--text);
|
color: var(--btnText, $fallback--text);
|
||||||
|
@ -85,7 +86,8 @@ button {
|
||||||
font-family: sans-serif;
|
font-family: sans-serif;
|
||||||
font-family: var(--interfaceFont, sans-serif);
|
font-family: var(--interfaceFont, sans-serif);
|
||||||
|
|
||||||
i[class*=icon-], .svg-inline--fa {
|
i[class*=icon-],
|
||||||
|
.svg-inline--fa {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnText, $fallback--text);
|
color: var(--btnText, $fallback--text);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +109,8 @@ button {
|
||||||
background-color: $fallback--fg;
|
background-color: $fallback--fg;
|
||||||
background-color: var(--btnPressed, $fallback--fg);
|
background-color: var(--btnPressed, $fallback--fg);
|
||||||
|
|
||||||
svg, i {
|
svg,
|
||||||
|
i {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnPressedText, $fallback--text);
|
color: var(--btnPressedText, $fallback--text);
|
||||||
}
|
}
|
||||||
|
@ -120,7 +123,8 @@ button {
|
||||||
background-color: $fallback--fg;
|
background-color: $fallback--fg;
|
||||||
background-color: var(--btnDisabled, $fallback--fg);
|
background-color: var(--btnDisabled, $fallback--fg);
|
||||||
|
|
||||||
svg, i {
|
svg,
|
||||||
|
i {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnDisabledText, $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: 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);
|
box-shadow: var(--buttonPressedShadow);
|
||||||
|
|
||||||
svg, i {
|
svg,
|
||||||
|
i {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnToggledText, $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 {
|
input, textarea, .select, .input {
|
||||||
|
|
||||||
&.unstyled {
|
&.unstyled {
|
||||||
|
@ -442,6 +471,7 @@ main-router {
|
||||||
color: $fallback--faint;
|
color: $fallback--faint;
|
||||||
color: var(--panelFaint, $fallback--faint);
|
color: var(--panelFaint, $fallback--faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
.faint-link {
|
.faint-link {
|
||||||
color: $fallback--faint;
|
color: $fallback--faint;
|
||||||
color: var(--faintLink, $fallback--faint);
|
color: var(--faintLink, $fallback--faint);
|
||||||
|
@ -453,11 +483,8 @@ main-router {
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
.button-default,
|
||||||
flex-shrink: 0;
|
.alert {
|
||||||
}
|
|
||||||
|
|
||||||
button, .alert {
|
|
||||||
// height: 100%;
|
// height: 100%;
|
||||||
line-height: 21px;
|
line-height: 21px;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
|
@ -468,8 +495,11 @@ main-router {
|
||||||
align-self: stretch;
|
align-self: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
.button-default {
|
||||||
&, i[class*=icon-] {
|
flex-shrink: 0;
|
||||||
|
|
||||||
|
&,
|
||||||
|
i[class*=icon-] {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnPanelText, $fallback--text);
|
color: var(--btnPanelText, $fallback--text);
|
||||||
}
|
}
|
||||||
|
@ -492,7 +522,8 @@ main-router {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a,
|
||||||
|
.-link {
|
||||||
color: $fallback--link;
|
color: $fallback--link;
|
||||||
color: var(--panelLink, $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 $fallback--panelRadius $fallback--panelRadius;
|
||||||
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
|
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
|
||||||
|
|
||||||
|
|
||||||
.faint {
|
.faint {
|
||||||
color: $fallback--faint;
|
color: $fallback--faint;
|
||||||
color: var(--panelFaint, $fallback--faint);
|
color: var(--panelFaint, $fallback--faint);
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a,
|
||||||
|
.-link {
|
||||||
color: $fallback--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;
|
min-height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
|
||||||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||||
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
||||||
import { applyTheme } from '../services/style_setter/style_setter.js'
|
import { applyTheme } from '../services/style_setter/style_setter.js'
|
||||||
|
import FaviconService from '../services/favicon_service/favicon_service.js'
|
||||||
|
|
||||||
let staticInitialResults = null
|
let staticInitialResults = null
|
||||||
|
|
||||||
|
@ -326,6 +327,8 @@ const afterStoreSetup = async ({ store, i18n }) => {
|
||||||
const width = windowWidth()
|
const width = windowWidth()
|
||||||
store.dispatch('setMobileLayout', width <= 800)
|
store.dispatch('setMobileLayout', width <= 800)
|
||||||
|
|
||||||
|
FaviconService.initFaviconService()
|
||||||
|
|
||||||
const overrides = window.___pleromafe_dev_overrides || {}
|
const overrides = window.___pleromafe_dev_overrides || {}
|
||||||
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
|
const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin
|
||||||
store.dispatch('setInstanceOption', { name: 'server', value: server })
|
store.dispatch('setInstanceOption', { name: 'server', value: server })
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
trigger="click"
|
trigger="click"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
|
remove-padding
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
slot="content"
|
slot="content"
|
||||||
|
@ -13,14 +14,14 @@
|
||||||
<template v-if="relationship.following">
|
<template v-if="relationship.following">
|
||||||
<button
|
<button
|
||||||
v-if="relationship.showing_reblogs"
|
v-if="relationship.showing_reblogs"
|
||||||
class="btn btn-default dropdown-item"
|
class="btn button-default dropdown-item"
|
||||||
@click="hideRepeats"
|
@click="hideRepeats"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.hide_repeats') }}
|
{{ $t('user_card.hide_repeats') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!relationship.showing_reblogs"
|
v-if="!relationship.showing_reblogs"
|
||||||
class="btn btn-default dropdown-item"
|
class="btn button-default dropdown-item"
|
||||||
@click="showRepeats"
|
@click="showRepeats"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.show_repeats') }}
|
{{ $t('user_card.show_repeats') }}
|
||||||
|
@ -32,27 +33,27 @@
|
||||||
</template>
|
</template>
|
||||||
<button
|
<button
|
||||||
v-if="relationship.blocking"
|
v-if="relationship.blocking"
|
||||||
class="btn btn-default btn-block dropdown-item"
|
class="btn button-default btn-block dropdown-item"
|
||||||
@click="unblockUser"
|
@click="unblockUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.unblock') }}
|
{{ $t('user_card.unblock') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-default btn-block dropdown-item"
|
class="btn button-default btn-block dropdown-item"
|
||||||
@click="blockUser"
|
@click="blockUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.block') }}
|
{{ $t('user_card.block') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default btn-block dropdown-item"
|
class="btn button-default btn-block dropdown-item"
|
||||||
@click="reportUser"
|
@click="reportUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.report') }}
|
{{ $t('user_card.report') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="pleromaChatMessagesAvailable"
|
v-if="pleromaChatMessagesAvailable"
|
||||||
class="btn btn-default btn-block dropdown-item"
|
class="btn button-default btn-block dropdown-item"
|
||||||
@click="openChat"
|
@click="openChat"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.message') }}
|
{{ $t('user_card.message') }}
|
||||||
|
@ -61,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
class="btn btn-default ellipsis-button"
|
class="ellipsis-button"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="icon"
|
class="icon"
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
{{ $t('general.error_retry') }}
|
{{ $t('general.error_retry') }}
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="retry"
|
@click="retry"
|
||||||
>
|
>
|
||||||
{{ $t('general.retry') }}
|
{{ $t('general.retry') }}
|
||||||
|
|
|
@ -8,14 +8,18 @@ import {
|
||||||
faFile,
|
faFile,
|
||||||
faMusic,
|
faMusic,
|
||||||
faImage,
|
faImage,
|
||||||
faVideo
|
faVideo,
|
||||||
|
faPlayCircle,
|
||||||
|
faTimes
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faFile,
|
faFile,
|
||||||
faMusic,
|
faMusic,
|
||||||
faImage,
|
faImage,
|
||||||
faVideo
|
faVideo,
|
||||||
|
faPlayCircle,
|
||||||
|
faTimes
|
||||||
)
|
)
|
||||||
|
|
||||||
const Attachment = {
|
const Attachment = {
|
||||||
|
|
|
@ -42,15 +42,13 @@
|
||||||
icon="play-circle"
|
icon="play-circle"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<div
|
<button
|
||||||
v-if="nsfw && hideNsfwLocal && !hidden"
|
v-if="nsfw && hideNsfwLocal && !hidden"
|
||||||
class="hider"
|
class="button-unstyled hider"
|
||||||
|
@click.prevent="toggleHidden"
|
||||||
>
|
>
|
||||||
<a
|
<FAIcon icon="times" />
|
||||||
href="#"
|
</button>
|
||||||
@click.prevent="toggleHidden"
|
|
||||||
>Hide</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a
|
<a
|
||||||
v-if="type === 'image' && (!hidden || preloadImage)"
|
v-if="type === 'image' && (!hidden || preloadImage)"
|
||||||
|
@ -234,15 +232,23 @@
|
||||||
.hider {
|
.hider {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
white-space: nowrap;
|
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
padding: 5px;
|
padding: 0;
|
||||||
background: rgba(230,230,230,0.6);
|
|
||||||
font-weight: bold;
|
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
line-height: 1;
|
|
||||||
border-radius: $fallback--tooltipRadius;
|
border-radius: $fallback--tooltipRadius;
|
||||||
border-radius: var(--tooltipRadius, $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 {
|
video {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="block-card-content-container">
|
<div class="block-card-content-container">
|
||||||
<button
|
<button
|
||||||
v-if="blocked"
|
v-if="blocked"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="progress"
|
:disabled="progress"
|
||||||
@click="unblockUser"
|
@click="unblockUser"
|
||||||
>
|
>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="progress"
|
:disabled="progress"
|
||||||
@click="blockUser"
|
@click="blockUser"
|
||||||
>
|
>
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
<span class="title">
|
<span class="title">
|
||||||
{{ $t("chats.chats") }}
|
{{ $t("chats.chats") }}
|
||||||
</span>
|
</span>
|
||||||
<button @click="newChat">
|
<button
|
||||||
|
class="button-default"
|
||||||
|
@click="newChat"
|
||||||
|
>
|
||||||
{{ $t("chats.new") }}
|
{{ $t("chats.new") }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,9 +31,6 @@
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--text, $fallback--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
border-radius: $fallback--chatMessageRadius;
|
|
||||||
border-radius: var(--chatMessageRadius, $fallback--chatMessageRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover {
|
.popover {
|
||||||
|
|
|
@ -53,7 +53,7 @@
|
||||||
<div slot="content">
|
<div slot="content">
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<button
|
<button
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click="deleteMessage"
|
@click="deleteMessage"
|
||||||
>
|
>
|
||||||
<FAIcon icon="times" /> {{ $t("chats.delete") }}
|
<FAIcon icon="times" /> {{ $t("chats.delete") }}
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
class="menu-icon"
|
class="button-default menu-icon"
|
||||||
:title="$t('chats.more')"
|
:title="$t('chats.more')"
|
||||||
>
|
>
|
||||||
<FAIcon icon="ellipsis-h" />
|
<FAIcon icon="ellipsis-h" />
|
||||||
|
|
|
@ -10,12 +10,13 @@
|
||||||
class="panel-heading conversation-heading"
|
class="panel-heading conversation-heading"
|
||||||
>
|
>
|
||||||
<span class="title"> {{ $t('timeline.conversation') }} </span>
|
<span class="title"> {{ $t('timeline.conversation') }} </span>
|
||||||
<span v-if="collapsable">
|
<button
|
||||||
<a
|
v-if="collapsable"
|
||||||
href="#"
|
class="button-unstyled -link"
|
||||||
@click.prevent="toggleExpanded"
|
@click.prevent="toggleExpanded"
|
||||||
>{{ $t('timeline.collapse') }}</a>
|
>
|
||||||
</span>
|
{{ $t('timeline.collapse') }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<status
|
<status
|
||||||
v-for="status in conversation"
|
v-for="status in conversation"
|
||||||
|
@ -57,13 +58,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-expanded {
|
&.-expanded {
|
||||||
.conversation-status {
|
|
||||||
border-color: $fallback--border;
|
|
||||||
border-color: var(--border, $fallback--border);
|
|
||||||
border-left-color: $fallback--cRed;
|
|
||||||
border-left-color: var(--cRed, $fallback--cRed);
|
|
||||||
}
|
|
||||||
|
|
||||||
.conversation-status:last-child {
|
.conversation-status:last-child {
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
|
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
grid-template-areas: "logo sitename actions";
|
grid-template-areas: "logo sitename actions";
|
||||||
}
|
}
|
||||||
|
|
||||||
button {
|
.button-default {
|
||||||
&, svg {
|
&, svg {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnTopBarText, $fallback--text);
|
color: var(--btnTopBarText, $fallback--text);
|
||||||
|
@ -80,12 +80,13 @@
|
||||||
.nav-icon {
|
.nav-icon {
|
||||||
margin-left: 0.2em;
|
margin-left: 0.2em;
|
||||||
width: 2em;
|
width: 2em;
|
||||||
|
height: 100%;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
|
||||||
|
|
||||||
a, a svg {
|
.svg-inline--fa {
|
||||||
color: $fallback--link;
|
color: $fallback--link;
|
||||||
color: var(--topBarLink, $fallback--link);
|
color: var(--topBarLink, $fallback--link);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.sitename {
|
.sitename {
|
||||||
|
|
|
@ -36,9 +36,8 @@
|
||||||
@toggled="onSearchBarToggled"
|
@toggled="onSearchBarToggled"
|
||||||
@click.stop.native
|
@click.stop.native
|
||||||
/>
|
/>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled nav-icon"
|
||||||
class="nav-icon"
|
|
||||||
@click.stop="openSettingsModal"
|
@click.stop="openSettingsModal"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -47,29 +46,32 @@
|
||||||
icon="cog"
|
icon="cog"
|
||||||
:title="$t('nav.preferences')"
|
:title="$t('nav.preferences')"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<a
|
||||||
v-if="currentUser && currentUser.role === 'admin'"
|
v-if="currentUser && currentUser.role === 'admin'"
|
||||||
href="/pleroma/admin/#/login-pleroma"
|
href="/pleroma/admin/#/login-pleroma"
|
||||||
class="nav-icon"
|
class="nav-icon"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
><FAIcon
|
>
|
||||||
fixed-width
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding"
|
fixed-width
|
||||||
icon="tachometer-alt"
|
class="fa-scale-110 fa-old-padding"
|
||||||
:title="$t('nav.administration')"
|
icon="tachometer-alt"
|
||||||
/></a>
|
:title="$t('nav.administration')"
|
||||||
<a
|
/>
|
||||||
|
</a>
|
||||||
|
<button
|
||||||
v-if="currentUser"
|
v-if="currentUser"
|
||||||
href="#"
|
class="button-unstyled nav-icon"
|
||||||
class="nav-icon"
|
|
||||||
@click.prevent="logout"
|
@click.prevent="logout"
|
||||||
><FAIcon
|
>
|
||||||
fixed-width
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding"
|
fixed-width
|
||||||
icon="sign-out-alt"
|
class="fa-scale-110 fa-old-padding"
|
||||||
:title="$t('login.logout')"
|
icon="sign-out-alt"
|
||||||
/></a>
|
:title="$t('login.logout')"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-if="muted"
|
v-if="muted"
|
||||||
:click="unmuteDomain"
|
:click="unmuteDomain"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('domain_mute_card.unmute') }}
|
{{ $t('domain_mute_card.unmute') }}
|
||||||
<template slot="progress">
|
<template slot="progress">
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-else
|
v-else
|
||||||
:click="muteDomain"
|
:click="muteDomain"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('domain_mute_card.mute') }}
|
{{ $t('domain_mute_card.mute') }}
|
||||||
<template slot="progress">
|
<template slot="progress">
|
||||||
|
|
|
@ -114,7 +114,8 @@ const EmojiInput = {
|
||||||
showPicker: false,
|
showPicker: false,
|
||||||
temporarilyHideSuggestions: false,
|
temporarilyHideSuggestions: false,
|
||||||
keepOpen: false,
|
keepOpen: false,
|
||||||
disableClickOutside: false
|
disableClickOutside: false,
|
||||||
|
suggestions: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -124,21 +125,6 @@ const EmojiInput = {
|
||||||
padEmoji () {
|
padEmoji () {
|
||||||
return this.$store.getters.mergedConfig.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 () {
|
showSuggestions () {
|
||||||
return this.focused &&
|
return this.focused &&
|
||||||
this.suggestions &&
|
this.suggestions &&
|
||||||
|
@ -188,6 +174,23 @@ const EmojiInput = {
|
||||||
watch: {
|
watch: {
|
||||||
showSuggestions: function (newValue) {
|
showSuggestions: function (newValue) {
|
||||||
this.$emit('shown', 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: {
|
methods: {
|
||||||
|
|
|
@ -6,13 +6,13 @@
|
||||||
>
|
>
|
||||||
<slot />
|
<slot />
|
||||||
<template v-if="enableEmojiPicker">
|
<template v-if="enableEmojiPicker">
|
||||||
<div
|
<button
|
||||||
v-if="!hideEmojiButton"
|
v-if="!hideEmojiButton"
|
||||||
class="emoji-picker-icon"
|
class="button-unstyled emoji-picker-icon"
|
||||||
@click.prevent="togglePicker"
|
@click.prevent="togglePicker"
|
||||||
>
|
>
|
||||||
<FAIcon :icon="['far', 'smile-beam']" />
|
<FAIcon :icon="['far', 'smile-beam']" />
|
||||||
</div>
|
</button>
|
||||||
<EmojiPicker
|
<EmojiPicker
|
||||||
v-if="enableEmojiPicker"
|
v-if="enableEmojiPicker"
|
||||||
ref="picker"
|
ref="picker"
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
v-for="(suggestion, index) in suggestions"
|
v-for="(suggestion, index) in suggestions"
|
||||||
:key="index"
|
:key="index"
|
||||||
class="autocomplete-item"
|
class="autocomplete-item"
|
||||||
:class="{ highlighted: suggestion.highlighted }"
|
:class="{ highlighted: index === highlighted }"
|
||||||
@click.stop.prevent="onClick($event, suggestion)"
|
@click.stop.prevent="onClick($event, suggestion)"
|
||||||
>
|
>
|
||||||
<span class="image">
|
<span class="image">
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { debounce } from 'lodash'
|
|
||||||
/**
|
/**
|
||||||
* suggest - generates a suggestor function to be used by emoji-input
|
* suggest - generates a suggestor function to be used by emoji-input
|
||||||
* data: object providing source information for specific types of suggestions:
|
* 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.
|
* doesn't support user linking you can just provide only emoji.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const debounceUserSearch = debounce((data, input) => {
|
export default data => {
|
||||||
data.updateUsersList(input)
|
const emojiCurry = suggestEmoji(data.emoji)
|
||||||
}, 500)
|
const usersCurry = data.store && suggestUsers(data.store)
|
||||||
|
return input => {
|
||||||
export default data => input => {
|
const firstChar = input[0]
|
||||||
const firstChar = input[0]
|
if (firstChar === ':' && data.emoji) {
|
||||||
if (firstChar === ':' && data.emoji) {
|
return emojiCurry(input)
|
||||||
return suggestEmoji(data.emoji)(input)
|
}
|
||||||
|
if (firstChar === '@' && usersCurry) {
|
||||||
|
return usersCurry(input)
|
||||||
|
}
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
if (firstChar === '@' && data.users) {
|
|
||||||
return suggestUsers(data)(input)
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const suggestEmoji = emojis => input => {
|
export const suggestEmoji = emojis => input => {
|
||||||
|
@ -57,50 +56,75 @@ export const suggestEmoji = emojis => input => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const suggestUsers = data => input => {
|
export const suggestUsers = ({ dispatch, state }) => {
|
||||||
const noPrefix = input.toLowerCase().substr(1)
|
// Keep some persistent values in closure, most importantly for the
|
||||||
const users = data.users
|
// 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(
|
const userSearch = (query) => dispatch('searchUsers', { query })
|
||||||
user =>
|
const debounceUserSearch = (query) => {
|
||||||
user.screen_name.toLowerCase().startsWith(noPrefix) ||
|
cancelUserSearch && cancelUserSearch()
|
||||||
user.name.toLowerCase().startsWith(noPrefix)
|
return new Promise((resolve, reject) => {
|
||||||
|
timeout = setTimeout(() => {
|
||||||
/* taking only 20 results so that sorting is a bit cheaper, we display
|
userSearch(query).then(resolve).catch(reject)
|
||||||
* only 5 anyway. could be inaccurate, but we ideally we should query
|
}, 300)
|
||||||
* backend anyway
|
cancelUserSearch = () => {
|
||||||
*/
|
clearTimeout(timeout)
|
||||||
).slice(0, 20).sort((a, b) => {
|
resolve([])
|
||||||
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
|
return async input => {
|
||||||
bScore += b.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
|
const noPrefix = input.toLowerCase().substr(1)
|
||||||
|
if (previousQuery === noPrefix) return suggestions
|
||||||
// Matches on name takes second priority
|
|
||||||
aScore += a.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
|
suggestions = []
|
||||||
bScore += b.name.toLowerCase().startsWith(noPrefix) ? 1 : 0
|
previousQuery = noPrefix
|
||||||
|
// Fetch more and wait, don't fetch if there's the 2nd @ because
|
||||||
const diff = (bScore - aScore) * 10
|
// the backend user search can't deal with it.
|
||||||
|
// Reference semantics make it so that we get the updated data after
|
||||||
// Then sort alphabetically
|
// the await.
|
||||||
const nameAlphabetically = a.name > b.name ? 1 : -1
|
if (!noPrefix.includes('@')) {
|
||||||
const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
|
await debounceUserSearch(noPrefix)
|
||||||
|
}
|
||||||
return diff + nameAlphabetically + screenNameAlphabetically
|
|
||||||
/* eslint-disable camelcase */
|
const newSuggestions = state.users.users.filter(
|
||||||
}).map(({ screen_name, name, profile_image_url_original }) => ({
|
user =>
|
||||||
displayText: screen_name,
|
user.screen_name.toLowerCase().startsWith(noPrefix) ||
|
||||||
detailText: name,
|
user.name.toLowerCase().startsWith(noPrefix)
|
||||||
imageUrl: profile_image_url_original,
|
).slice(0, 20).sort((a, b) => {
|
||||||
replacement: '@' + screen_name + ' '
|
let aScore = 0
|
||||||
}))
|
let bScore = 0
|
||||||
|
|
||||||
// BE search users to get more comprehensive results
|
// Matches on screen name (i.e. user@instance) makes a priority
|
||||||
if (data.updateUsersList) {
|
aScore += a.screen_name.toLowerCase().startsWith(noPrefix) ? 2 : 0
|
||||||
debounceUserSearch(data, noPrefix)
|
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 */
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
:users="accountsForEmoji[reaction.name]"
|
:users="accountsForEmoji[reaction.name]"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="emoji-reaction btn btn-default"
|
class="emoji-reaction btn button-default"
|
||||||
:class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
|
:class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
|
||||||
@click="emojiOnClick(reaction.name, $event)"
|
@click="emojiOnClick(reaction.name, $event)"
|
||||||
@mouseenter="fetchEmojiReactionsByIfMissing()"
|
@mouseenter="fetchEmojiReactionsByIfMissing()"
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
<div class="import-export-container">
|
<div class="import-export-container">
|
||||||
<slot name="before" />
|
<slot name="before" />
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="exportData"
|
@click="exportData"
|
||||||
>
|
>
|
||||||
{{ exportLabel }}
|
{{ exportLabel }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="importData"
|
@click="importData"
|
||||||
>
|
>
|
||||||
{{ importLabel }}
|
{{ importLabel }}
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="process"
|
@click="process"
|
||||||
>
|
>
|
||||||
{{ exportButtonLabel }}
|
{{ exportButtonLabel }}
|
||||||
|
|
|
@ -2,8 +2,9 @@
|
||||||
<Popover
|
<Popover
|
||||||
trigger="click"
|
trigger="click"
|
||||||
placement="top"
|
placement="top"
|
||||||
class="extra-button-popover"
|
:offset="{ y: 5 }"
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
|
remove-padding
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
slot="content"
|
slot="content"
|
||||||
|
@ -12,7 +13,7 @@
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<button
|
<button
|
||||||
v-if="canMute && !status.thread_muted"
|
v-if="canMute && !status.thread_muted"
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="muteConversation"
|
@click.prevent="muteConversation"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -22,7 +23,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canMute && status.thread_muted"
|
v-if="canMute && status.thread_muted"
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="unmuteConversation"
|
@click.prevent="unmuteConversation"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!status.pinned && canPin"
|
v-if="!status.pinned && canPin"
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="pinStatus"
|
@click.prevent="pinStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="status.pinned && canPin"
|
v-if="status.pinned && canPin"
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="unpinStatus"
|
@click.prevent="unpinStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -54,7 +55,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!status.bookmarked"
|
v-if="!status.bookmarked"
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="bookmarkStatus"
|
@click.prevent="bookmarkStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -65,7 +66,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="status.bookmarked"
|
v-if="status.bookmarked"
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="unbookmarkStatus"
|
@click.prevent="unbookmarkStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -76,7 +77,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canDelete"
|
v-if="canDelete"
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="deleteStatus"
|
@click.prevent="deleteStatus"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -86,7 +87,7 @@
|
||||||
/><span>{{ $t("status.delete") }}</span>
|
/><span>{{ $t("status.delete") }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="button-default dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="copyLink"
|
@click.prevent="copyLink"
|
||||||
@click="close"
|
@click="close"
|
||||||
>
|
>
|
||||||
|
@ -97,9 +98,12 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span slot="trigger">
|
<span
|
||||||
|
slot="trigger"
|
||||||
|
class="ExtraButtons"
|
||||||
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="ExtraButtons fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
icon="ellipsis-h"
|
icon="ellipsis-h"
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
@ -112,11 +116,11 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.ExtraButtons {
|
.ExtraButtons {
|
||||||
cursor: pointer;
|
|
||||||
position: static;
|
position: static;
|
||||||
|
padding: 10px;
|
||||||
|
margin: -10px;
|
||||||
|
|
||||||
&:hover,
|
&:hover .svg-inline--fa {
|
||||||
.extra-button-popover.open & {
|
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--text, $fallback--text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,11 +31,6 @@ const FavoriteButton = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
classes () {
|
|
||||||
return {
|
|
||||||
'-favorited': this.status.favorited
|
|
||||||
}
|
|
||||||
},
|
|
||||||
...mapGetters(['mergedConfig'])
|
...mapGetters(['mergedConfig'])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +1,31 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="loggedIn">
|
<div class="FavoriteButton">
|
||||||
<FAIcon
|
<button
|
||||||
:class="classes"
|
v-if="loggedIn"
|
||||||
class="FavoriteButton fa-scale-110 fa-old-padding -interactive"
|
class="button-unstyled interactive"
|
||||||
|
:class="status.favorited && '-favorited'"
|
||||||
:title="$t('tool_tip.favorite')"
|
:title="$t('tool_tip.favorite')"
|
||||||
:icon="[status.favorited ? 'fas' : 'far', 'star']"
|
|
||||||
:spin="animated"
|
|
||||||
@click.prevent="favorite()"
|
@click.prevent="favorite()"
|
||||||
/>
|
>
|
||||||
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
|
<FAIcon
|
||||||
</div>
|
class="fa-scale-110 fa-old-padding"
|
||||||
<div v-else>
|
:icon="[status.favorited ? 'fas' : 'far', 'star']"
|
||||||
<FAIcon
|
:spin="animated"
|
||||||
:class="classes"
|
/>
|
||||||
class="FavoriteButton fa-scale-110 fa-old-padding"
|
</button>
|
||||||
:title="$t('tool_tip.favorite')"
|
<span v-else>
|
||||||
:icon="['far', 'star']"
|
<FAIcon
|
||||||
/>
|
class="fa-scale-110 fa-old-padding"
|
||||||
<span v-if="!mergedConfig.hidePostStats && status.fave_num > 0">{{ status.fave_num }}</span>
|
: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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -27,19 +35,28 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.FavoriteButton {
|
.FavoriteButton {
|
||||||
&.-interactive {
|
display: flex;
|
||||||
cursor: pointer;
|
|
||||||
animation-duration: 0.6s;
|
|
||||||
|
|
||||||
&: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: $fallback--cOrange;
|
||||||
color: var(--cOrange, $fallback--cOrange);
|
color: var(--cOrange, $fallback--cOrange);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-favorited {
|
|
||||||
color: $fallback--cOrange;
|
|
||||||
color: var(--cOrange, $fallback--cOrange);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default follow-button"
|
class="btn button-default follow-button"
|
||||||
:class="{ toggled: isPressed }"
|
:class="{ toggled: isPressed }"
|
||||||
:disabled="inProgress"
|
:disabled="inProgress"
|
||||||
:title="title"
|
:title="title"
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
<basic-user-card :user="user">
|
<basic-user-card :user="user">
|
||||||
<div class="follow-request-card-content-container">
|
<div class="follow-request-card-content-container">
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="approveUser"
|
@click="approveUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.approve') }}
|
{{ $t('user_card.approve') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="denyUser"
|
@click="denyUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.deny') }}
|
{{ $t('user_card.deny') }}
|
||||||
|
|
|
@ -11,21 +11,21 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="image-cropper-buttons-wrapper">
|
<div class="image-cropper-buttons-wrapper">
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="button-default btn"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="submitting"
|
:disabled="submitting"
|
||||||
@click="submit()"
|
@click="submit()"
|
||||||
v-text="saveText"
|
v-text="saveText"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="button-default btn"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="submitting"
|
:disabled="submitting"
|
||||||
@click="destroy"
|
@click="destroy"
|
||||||
v-text="cancelText"
|
v-text="cancelText"
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="button-default btn"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="submitting"
|
:disabled="submitting"
|
||||||
@click="submit(false)"
|
@click="submit(false)"
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="submit"
|
@click="submit"
|
||||||
>
|
>
|
||||||
{{ submitButtonLabel }}
|
{{ submitButtonLabel }}
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { mapGetters } from 'vuex'
|
||||||
|
|
||||||
const LinkPreview = {
|
const LinkPreview = {
|
||||||
name: 'LinkPreview',
|
name: 'LinkPreview',
|
||||||
props: [
|
props: [
|
||||||
|
@ -15,11 +17,20 @@ const LinkPreview = {
|
||||||
// Currently BE shoudn't give cards if tagged NSFW, this is a bit paranoid
|
// Currently BE shoudn't give cards if tagged NSFW, this is a bit paranoid
|
||||||
// as it makes sure to hide the image if somehow NSFW tagged preview can
|
// as it makes sure to hide the image if somehow NSFW tagged preview can
|
||||||
// exist.
|
// exist.
|
||||||
return this.card.image && !this.nsfw && this.size !== 'hide'
|
return this.card.image && !this.censored && this.size !== 'hide'
|
||||||
|
},
|
||||||
|
censored () {
|
||||||
|
return this.nsfw && this.hideNsfwConfig
|
||||||
},
|
},
|
||||||
useDescription () {
|
useDescription () {
|
||||||
return this.card.description && /\S/.test(this.card.description)
|
return this.card.description && /\S/.test(this.card.description)
|
||||||
}
|
},
|
||||||
|
hideNsfwConfig () {
|
||||||
|
return this.mergedConfig.hideNsfw
|
||||||
|
},
|
||||||
|
...mapGetters([
|
||||||
|
'mergedConfig'
|
||||||
|
])
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
if (this.useImage) {
|
if (this.useImage) {
|
||||||
|
|
|
@ -9,12 +9,17 @@
|
||||||
<div
|
<div
|
||||||
v-if="useImage && imageLoaded"
|
v-if="useImage && imageLoaded"
|
||||||
class="card-image"
|
class="card-image"
|
||||||
:class="{ 'small-image': size === 'small' }"
|
|
||||||
>
|
>
|
||||||
<img :src="card.image">
|
<img :src="card.image">
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<span class="card-host faint">{{ card.provider_name }}</span>
|
<span class="card-host faint">
|
||||||
|
<span
|
||||||
|
v-if="censored"
|
||||||
|
class="nsfw-alert alert warning"
|
||||||
|
>{{ $t('status.nsfw') }}</span>
|
||||||
|
{{ card.provider_name }}
|
||||||
|
</span>
|
||||||
<h4 class="card-title">{{ card.title }}</h4>
|
<h4 class="card-title">{{ card.title }}</h4>
|
||||||
<p
|
<p
|
||||||
v-if="useDescription"
|
v-if="useDescription"
|
||||||
|
@ -50,10 +55,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.small-image {
|
|
||||||
width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-content {
|
.card-content {
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
margin: 0.5em;
|
margin: 0.5em;
|
||||||
|
@ -76,6 +77,10 @@
|
||||||
max-height: calc(1.2em * 3 - 1px);
|
max-height: calc(1.2em * 3 - 1px);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nsfw-alert {
|
||||||
|
margin: 2em 0;
|
||||||
|
}
|
||||||
|
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--text, $fallback--text);
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
<button
|
<button
|
||||||
:disabled="loggingIn"
|
:disabled="loggingIn"
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('login.login') }}
|
{{ $t('login.login') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,33 +1,29 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<label
|
||||||
class="media-upload"
|
class="media-upload"
|
||||||
:class="{ disabled: disabled }"
|
:class="{ disabled: disabled }"
|
||||||
|
:title="$t('tool_tip.media_upload')"
|
||||||
>
|
>
|
||||||
<label
|
<FAIcon
|
||||||
class="label"
|
v-if="uploading"
|
||||||
:title="$t('tool_tip.media_upload')"
|
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
|
</label>
|
||||||
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>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./media_upload.js" ></script>
|
<script src="./media_upload.js" ></script>
|
||||||
|
@ -36,12 +32,6 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.media-upload {
|
.media-upload {
|
||||||
.label {
|
cursor: pointer;
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -23,23 +23,23 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="login-bottom">
|
<div class="login-bottom">
|
||||||
<div>
|
<div>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link"
|
||||||
@click.prevent="requireTOTP"
|
@click.prevent="requireTOTP"
|
||||||
>
|
>
|
||||||
{{ $t('login.enter_two_factor_code') }}
|
{{ $t('login.enter_two_factor_code') }}
|
||||||
</a>
|
</button>
|
||||||
<br>
|
<br>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link"
|
||||||
@click.prevent="abortMFA"
|
@click.prevent="abortMFA"
|
||||||
>
|
>
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('general.verify') }}
|
{{ $t('general.verify') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -25,23 +25,23 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<div class="login-bottom">
|
<div class="login-bottom">
|
||||||
<div>
|
<div>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link"
|
||||||
@click.prevent="requireRecovery"
|
@click.prevent="requireRecovery"
|
||||||
>
|
>
|
||||||
{{ $t('login.enter_recovery_code') }}
|
{{ $t('login.enter_recovery_code') }}
|
||||||
</a>
|
</button>
|
||||||
<br>
|
<br>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link"
|
||||||
@click.prevent="abortMFA"
|
@click.prevent="abortMFA"
|
||||||
>
|
>
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('general.verify') }}
|
{{ $t('general.verify') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -9,9 +9,8 @@
|
||||||
@click="scrollToTop()"
|
@click="scrollToTop()"
|
||||||
>
|
>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled mobile-nav-button"
|
||||||
class="mobile-nav-button"
|
|
||||||
@click.stop.prevent="toggleMobileSidebar()"
|
@click.stop.prevent="toggleMobileSidebar()"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -22,7 +21,7 @@
|
||||||
v-if="unreadChatCount"
|
v-if="unreadChatCount"
|
||||||
class="alert-dot"
|
class="alert-dot"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
<router-link
|
<router-link
|
||||||
v-if="!hideSitename"
|
v-if="!hideSitename"
|
||||||
class="site-name"
|
class="site-name"
|
||||||
|
@ -33,10 +32,9 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
</div>
|
</div>
|
||||||
<div class="item right">
|
<div class="item right">
|
||||||
<a
|
<button
|
||||||
v-if="currentUser"
|
v-if="currentUser"
|
||||||
class="mobile-nav-button"
|
class="button-unstyled mobile-nav-button"
|
||||||
href="#"
|
|
||||||
@click.stop.prevent="openMobileNotifications()"
|
@click.stop.prevent="openMobileNotifications()"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -47,7 +45,7 @@
|
||||||
v-if="unseenNotificationsCount"
|
v-if="unseenNotificationsCount"
|
||||||
class="alert-dot"
|
class="alert-dot"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="isLoggedIn">
|
<div v-if="isLoggedIn">
|
||||||
<button
|
<button
|
||||||
class="new-status-button"
|
class="button-default new-status-button"
|
||||||
:class="{ 'hidden': isHidden }"
|
:class="{ 'hidden': isHidden }"
|
||||||
@click="openPostForm"
|
@click="openPostForm"
|
||||||
>
|
>
|
||||||
|
|
|
@ -12,13 +12,13 @@
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<span v-if="user.is_local">
|
<span v-if="user.is_local">
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleRight("admin")"
|
@click="toggleRight("admin")"
|
||||||
>
|
>
|
||||||
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
|
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleRight("moderator")"
|
@click="toggleRight("moderator")"
|
||||||
>
|
>
|
||||||
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
|
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
|
||||||
|
@ -29,13 +29,13 @@
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleActivationStatus()"
|
@click="toggleActivationStatus()"
|
||||||
>
|
>
|
||||||
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
|
{{ $t(!!user.deactivated ? 'user_card.admin_menu.activate_account' : 'user_card.admin_menu.deactivate_account') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="deleteUserDialog(true)"
|
@click="deleteUserDialog(true)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.delete_account') }}
|
{{ $t('user_card.admin_menu.delete_account') }}
|
||||||
|
@ -47,7 +47,7 @@
|
||||||
/>
|
/>
|
||||||
<span v-if="hasTagPolicy">
|
<span v-if="hasTagPolicy">
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleTag(tags.FORCE_NSFW)"
|
@click="toggleTag(tags.FORCE_NSFW)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.force_nsfw') }}
|
{{ $t('user_card.admin_menu.force_nsfw') }}
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleTag(tags.STRIP_MEDIA)"
|
@click="toggleTag(tags.STRIP_MEDIA)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.strip_media') }}
|
{{ $t('user_card.admin_menu.strip_media') }}
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleTag(tags.FORCE_UNLISTED)"
|
@click="toggleTag(tags.FORCE_UNLISTED)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.force_unlisted') }}
|
{{ $t('user_card.admin_menu.force_unlisted') }}
|
||||||
|
@ -77,7 +77,7 @@
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleTag(tags.SANDBOX)"
|
@click="toggleTag(tags.SANDBOX)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.sandbox') }}
|
{{ $t('user_card.admin_menu.sandbox') }}
|
||||||
|
@ -88,7 +88,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="user.is_local"
|
v-if="user.is_local"
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
|
@click="toggleTag(tags.DISABLE_REMOTE_SUBSCRIPTION)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
|
{{ $t('user_card.admin_menu.disable_remote_subscription') }}
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="user.is_local"
|
v-if="user.is_local"
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
|
@click="toggleTag(tags.DISABLE_ANY_SUBSCRIPTION)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.disable_any_subscription') }}
|
{{ $t('user_card.admin_menu.disable_any_subscription') }}
|
||||||
|
@ -110,7 +110,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="user.is_local"
|
v-if="user.is_local"
|
||||||
class="dropdown-item"
|
class="button-default dropdown-item"
|
||||||
@click="toggleTag(tags.QUARANTINE)"
|
@click="toggleTag(tags.QUARANTINE)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.quarantine') }}
|
{{ $t('user_card.admin_menu.quarantine') }}
|
||||||
|
@ -124,7 +124,7 @@
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
slot="trigger"
|
slot="trigger"
|
||||||
class="btn btn-default btn-block"
|
class="btn button-default btn-block"
|
||||||
:class="{ toggled }"
|
:class="{ toggled }"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.moderation') }}
|
{{ $t('user_card.admin_menu.moderation') }}
|
||||||
|
@ -141,13 +141,13 @@
|
||||||
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
|
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
|
||||||
<template slot="footer">
|
<template slot="footer">
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="deleteUserDialog(false)"
|
@click="deleteUserDialog(false)"
|
||||||
>
|
>
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default danger"
|
class="btn button-default danger"
|
||||||
@click="deleteUser()"
|
@click="deleteUser()"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.delete_user') }}
|
{{ $t('user_card.admin_menu.delete_user') }}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<div class="mute-card-content-container">
|
<div class="mute-card-content-container">
|
||||||
<button
|
<button
|
||||||
v-if="muted"
|
v-if="muted"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="progress"
|
:disabled="progress"
|
||||||
@click="unmuteUser"
|
@click="unmuteUser"
|
||||||
>
|
>
|
||||||
|
@ -16,7 +16,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="progress"
|
:disabled="progress"
|
||||||
@click="muteUser"
|
@click="muteUser"
|
||||||
>
|
>
|
||||||
|
|
|
@ -14,14 +14,15 @@
|
||||||
{{ notification.from_profile.screen_name }}
|
{{ notification.from_profile.screen_name }}
|
||||||
</router-link>
|
</router-link>
|
||||||
</small>
|
</small>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled unmute"
|
||||||
class="unmute"
|
|
||||||
@click.prevent="toggleMute"
|
@click.prevent="toggleMute"
|
||||||
><FAIcon
|
>
|
||||||
class="fa-scale-110 fa-old-padding"
|
<FAIcon
|
||||||
icon="eye-slash"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/></a>
|
icon="eye-slash"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
|
@ -132,14 +133,16 @@
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<button
|
||||||
v-if="needMute"
|
v-if="needMute"
|
||||||
href="#"
|
class="button-unstyled"
|
||||||
@click.prevent="toggleMute"
|
@click.prevent="toggleMute"
|
||||||
><FAIcon
|
>
|
||||||
class="fa-scale-110 fa-old-padding"
|
<FAIcon
|
||||||
icon="eye-slash"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/></a>
|
icon="eye-slash"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
</span>
|
</span>
|
||||||
<div
|
<div
|
||||||
v-if="notification.type === 'follow' || notification.type === 'follow_request'"
|
v-if="notification.type === 'follow' || notification.type === 'follow_request'"
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
filteredNotificationsFromStore,
|
filteredNotificationsFromStore,
|
||||||
unseenNotificationsFromStore
|
unseenNotificationsFromStore
|
||||||
} from '../../services/notification_utils/notification_utils.js'
|
} from '../../services/notification_utils/notification_utils.js'
|
||||||
|
import FaviconService from '../../services/favicon_service/favicon_service.js'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
@ -75,8 +76,10 @@ const Notifications = {
|
||||||
watch: {
|
watch: {
|
||||||
unseenCountTitle (count) {
|
unseenCountTitle (count) {
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
|
FaviconService.drawFaviconBadge()
|
||||||
this.$store.dispatch('setPageTitle', `(${count})`)
|
this.$store.dispatch('setPageTitle', `(${count})`)
|
||||||
} else {
|
} else {
|
||||||
|
FaviconService.clearFaviconBadge()
|
||||||
this.$store.dispatch('setPageTitle', '')
|
this.$store.dispatch('setPageTitle', '')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,16 +15,9 @@
|
||||||
class="badge badge-notification unseen-count"
|
class="badge badge-notification unseen-count"
|
||||||
>{{ unseenCount }}</span>
|
>{{ unseenCount }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
v-if="error"
|
|
||||||
class="loadmore-error alert error"
|
|
||||||
@click.prevent
|
|
||||||
>
|
|
||||||
{{ $t('timeline.error_fetching') }}
|
|
||||||
</div>
|
|
||||||
<button
|
<button
|
||||||
v-if="unseenCount"
|
v-if="unseenCount"
|
||||||
class="read-button"
|
class="button-default read-button"
|
||||||
@click.prevent="markAsSeen"
|
@click.prevent="markAsSeen"
|
||||||
>
|
>
|
||||||
{{ $t('notifications.read') }}
|
{{ $t('notifications.read') }}
|
||||||
|
@ -48,15 +41,15 @@
|
||||||
>
|
>
|
||||||
{{ $t('notifications.no_more_notifications') }}
|
{{ $t('notifications.no_more_notifications') }}
|
||||||
</div>
|
</div>
|
||||||
<a
|
<button
|
||||||
v-else-if="!loading"
|
v-else-if="!loading"
|
||||||
href="#"
|
class="button-unstyled -link -fullwidth"
|
||||||
@click.prevent="fetchOlderNotifications()"
|
@click.prevent="fetchOlderNotifications()"
|
||||||
>
|
>
|
||||||
<div class="new-status-notification text-center panel-footer">
|
<div class="new-status-notification text-center panel-footer">
|
||||||
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
|
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older') }}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</button>
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="new-status-notification text-center panel-footer"
|
class="new-status-notification text-center panel-footer"
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
<button
|
<button
|
||||||
:disabled="isPending"
|
:disabled="isPending"
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-default btn-block"
|
class="btn button-default btn-block"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -49,7 +49,7 @@
|
||||||
<div class="footer faint">
|
<div class="footer faint">
|
||||||
<button
|
<button
|
||||||
v-if="!showResults"
|
v-if="!showResults"
|
||||||
class="btn btn-default poll-vote-button"
|
class="btn button-default poll-vote-button"
|
||||||
type="button"
|
type="button"
|
||||||
:disabled="isDisabled"
|
:disabled="isDisabled"
|
||||||
@click="vote"
|
@click="vote"
|
||||||
|
|
|
@ -21,7 +21,10 @@ const Popover = {
|
||||||
// Replaces the classes you may want for the popover container.
|
// Replaces the classes you may want for the popover container.
|
||||||
// Use 'popover-default' in addition to get the default popover
|
// Use 'popover-default' in addition to get the default popover
|
||||||
// styles with your custom class.
|
// 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 () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -96,9 +99,15 @@ const Popover = {
|
||||||
if (origin.y + content.offsetHeight > yBounds.max) usingTop = true
|
if (origin.y + content.offsetHeight > yBounds.max) usingTop = true
|
||||||
if (origin.y - content.offsetHeight < yBounds.min) usingTop = false
|
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 yOffset = (this.offset && this.offset.y) || 0
|
||||||
const translateY = usingTop
|
const translateY = usingTop
|
||||||
? -anchorEl.offsetHeight - yOffset - content.offsetHeight
|
? -anchorEl.offsetHeight + vPadding - yOffset - content.offsetHeight
|
||||||
: yOffset
|
: yOffset
|
||||||
|
|
||||||
const xOffset = (this.offset && this.offset.x) || 0
|
const xOffset = (this.offset && this.offset.x) || 0
|
||||||
|
|
|
@ -3,12 +3,13 @@
|
||||||
@mouseenter="onMouseenter"
|
@mouseenter="onMouseenter"
|
||||||
@mouseleave="onMouseleave"
|
@mouseleave="onMouseleave"
|
||||||
>
|
>
|
||||||
<div
|
<button
|
||||||
ref="trigger"
|
ref="trigger"
|
||||||
|
class="button-unstyled -fullwidth popover-trigger-button"
|
||||||
@click="onClick"
|
@click="onClick"
|
||||||
>
|
>
|
||||||
<slot name="trigger" />
|
<slot name="trigger" />
|
||||||
</div>
|
</button>
|
||||||
<div
|
<div
|
||||||
v-if="!hidden"
|
v-if="!hidden"
|
||||||
ref="content"
|
ref="content"
|
||||||
|
@ -30,6 +31,10 @@
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
|
.popover-trigger-button {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.popover {
|
.popover {
|
||||||
z-index: 8;
|
z-index: 8;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
@ -159,8 +159,7 @@ const PostStatusForm = {
|
||||||
...this.$store.state.instance.emoji,
|
...this.$store.state.instance.emoji,
|
||||||
...this.$store.state.instance.customEmoji
|
...this.$store.state.instance.customEmoji
|
||||||
],
|
],
|
||||||
users: this.$store.state.users.users,
|
store: this.$store
|
||||||
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
emojiSuggestor () {
|
emojiSuggestor () {
|
||||||
|
|
|
@ -24,12 +24,12 @@
|
||||||
tag="p"
|
tag="p"
|
||||||
class="visibility-notice"
|
class="visibility-notice"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link"
|
||||||
@click="openProfileTab"
|
@click="openProfileTab"
|
||||||
>
|
>
|
||||||
{{ $t('post_status.account_not_locked_warning_link') }}
|
{{ $t('post_status.account_not_locked_warning_link') }}
|
||||||
</a>
|
</button>
|
||||||
</i18n>
|
</i18n>
|
||||||
<p
|
<p
|
||||||
v-if="!hideScopeNotice && newStatus.visibility === 'public'"
|
v-if="!hideScopeNotice && newStatus.visibility === 'public'"
|
||||||
|
@ -243,38 +243,34 @@
|
||||||
@upload-failed="uploadFailed"
|
@upload-failed="uploadFailed"
|
||||||
@all-uploaded="finishedUploadingFiles"
|
@all-uploaded="finishedUploadingFiles"
|
||||||
/>
|
/>
|
||||||
<div
|
<button
|
||||||
class="emoji-icon"
|
class="emoji-icon button-unstyled"
|
||||||
|
:title="$t('emoji.add_emoji')"
|
||||||
|
@click="showEmojiPicker"
|
||||||
>
|
>
|
||||||
<div
|
<FAIcon icon="smile-beam" />
|
||||||
:title="$t('emoji.add_emoji')"
|
</button>
|
||||||
class="btn btn-default"
|
<button
|
||||||
@click="showEmojiPicker"
|
|
||||||
>
|
|
||||||
<FAIcon icon="smile-beam" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="pollsAvailable"
|
v-if="pollsAvailable"
|
||||||
class="poll-icon"
|
class="poll-icon button-unstyled"
|
||||||
:class="{ selected: pollFormVisible }"
|
:class="{ selected: pollFormVisible }"
|
||||||
:title="$t('polls.add_poll')"
|
:title="$t('polls.add_poll')"
|
||||||
@click="togglePollForm"
|
@click="togglePollForm"
|
||||||
>
|
>
|
||||||
<FAIcon icon="poll-h" />
|
<FAIcon icon="poll-h" />
|
||||||
</div>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
v-if="posting"
|
v-if="posting"
|
||||||
disabled
|
disabled
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('post_status.posting') }}
|
{{ $t('post_status.posting') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else-if="isOverLengthLimit"
|
v-else-if="isOverLengthLimit"
|
||||||
disabled
|
disabled
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
</button>
|
</button>
|
||||||
|
@ -282,7 +278,7 @@
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
:disabled="uploadingFiles || disableSubmit"
|
:disabled="uploadingFiles || disableSubmit"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@touchstart.stop.prevent="postStatus($event, newStatus)"
|
@touchstart.stop.prevent="postStatus($event, newStatus)"
|
||||||
@click.stop.prevent="postStatus($event, newStatus)"
|
@click.stop.prevent="postStatus($event, newStatus)"
|
||||||
>
|
>
|
||||||
|
|
|
@ -27,13 +27,21 @@ const ReactButton = {
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
commonEmojis () {
|
commonEmojis () {
|
||||||
return ['👍', '😠', '👀', '😂', '🔥']
|
return [
|
||||||
|
{ displayText: 'thumbsup', replacement: '👍' },
|
||||||
|
{ displayText: 'angry', replacement: '😠' },
|
||||||
|
{ displayText: 'eyes', replacement: '👀' },
|
||||||
|
{ displayText: 'joy', replacement: '😂' },
|
||||||
|
{ displayText: 'fire', replacement: '🔥' }
|
||||||
|
]
|
||||||
},
|
},
|
||||||
emojis () {
|
emojis () {
|
||||||
if (this.filterWord !== '') {
|
if (this.filterWord !== '') {
|
||||||
const filterWordLowercase = this.filterWord.toLowerCase()
|
const filterWordLowercase = this.filterWord.toLowerCase()
|
||||||
let orderedEmojiList = []
|
let orderedEmojiList = []
|
||||||
for (const emoji of this.$store.state.instance.emoji) {
|
for (const emoji of this.$store.state.instance.emoji) {
|
||||||
|
if (emoji.replacement === this.filterWord) return [emoji]
|
||||||
|
|
||||||
const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase)
|
const indexOfFilterWord = emoji.displayText.toLowerCase().indexOf(filterWordLowercase)
|
||||||
if (indexOfFilterWord > -1) {
|
if (indexOfFilterWord > -1) {
|
||||||
if (!Array.isArray(orderedEmojiList[indexOfFilterWord])) {
|
if (!Array.isArray(orderedEmojiList[indexOfFilterWord])) {
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
trigger="click"
|
trigger="click"
|
||||||
placement="top"
|
placement="top"
|
||||||
:offset="{ y: 5 }"
|
:offset="{ y: 5 }"
|
||||||
class="react-button-popover"
|
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
|
remove-padding
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
slot="content"
|
slot="content"
|
||||||
|
@ -22,15 +22,17 @@
|
||||||
v-for="emoji in commonEmojis"
|
v-for="emoji in commonEmojis"
|
||||||
:key="emoji"
|
:key="emoji"
|
||||||
class="emoji-button"
|
class="emoji-button"
|
||||||
|
:title="emoji.displayText"
|
||||||
@click="addReaction($event, emoji, close)"
|
@click="addReaction($event, emoji, close)"
|
||||||
>
|
>
|
||||||
{{ emoji }}
|
{{ emoji.replacement }}
|
||||||
</span>
|
</span>
|
||||||
<div class="reaction-picker-divider" />
|
<div class="reaction-picker-divider" />
|
||||||
<span
|
<span
|
||||||
v-for="(emoji, key) in emojis"
|
v-for="(emoji, key) in emojis"
|
||||||
:key="key"
|
:key="key"
|
||||||
class="emoji-button"
|
class="emoji-button"
|
||||||
|
:title="emoji.displayText"
|
||||||
@click="addReaction($event, emoji.replacement, close)"
|
@click="addReaction($event, emoji.replacement, close)"
|
||||||
>
|
>
|
||||||
{{ emoji.replacement }}
|
{{ emoji.replacement }}
|
||||||
|
@ -38,11 +40,14 @@
|
||||||
<div class="reaction-bottom-fader" />
|
<div class="reaction-bottom-fader" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<span slot="trigger">
|
<span
|
||||||
|
slot="trigger"
|
||||||
|
class="ReactButton"
|
||||||
|
:title="$t('tool_tip.add_reaction')"
|
||||||
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding add-reaction-button"
|
class="fa-scale-110 fa-old-padding"
|
||||||
:icon="['far', 'smile-beam']"
|
:icon="['far', 'smile-beam']"
|
||||||
:title="$t('tool_tip.add_reaction')"
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
@ -102,10 +107,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-reaction-button {
|
.ReactButton {
|
||||||
cursor: pointer;
|
padding: 10px;
|
||||||
|
margin: -10px;
|
||||||
|
|
||||||
&:hover {
|
&:hover .svg-inline--fa {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--text, $fallback--text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -211,7 +211,7 @@
|
||||||
<button
|
<button
|
||||||
:disabled="isPending"
|
:disabled="isPending"
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -1,20 +1,28 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="ReplyButton">
|
||||||
<FAIcon
|
<button
|
||||||
v-if="loggedIn"
|
v-if="loggedIn"
|
||||||
class="ReplyButton fa-scale-110 fa-old-padding -interactive"
|
class="button-unstyled interactive"
|
||||||
icon="reply"
|
|
||||||
:title="$t('tool_tip.reply')"
|
|
||||||
:class="{'-active': replying}"
|
: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')"
|
:title="$t('tool_tip.reply')"
|
||||||
/>
|
@click.prevent="$emit('toggle')"
|
||||||
<span v-if="status.replies_count > 0">
|
>
|
||||||
|
<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 }}
|
{{ status.replies_count }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -26,14 +34,25 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.ReplyButton {
|
.ReplyButton {
|
||||||
&.-interactive {
|
display: flex;
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover,
|
> :first-child {
|
||||||
&.-active {
|
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: $fallback--cBlue;
|
||||||
color: var(--cBlue, $fallback--cBlue);
|
color: var(--cBlue, $fallback--cBlue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -24,11 +24,6 @@ const RetweetButton = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
classes () {
|
|
||||||
return {
|
|
||||||
'-repeated': this.status.repeated
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mergedConfig () {
|
mergedConfig () {
|
||||||
return this.$store.getters.mergedConfig
|
return this.$store.getters.mergedConfig
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,38 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-if="loggedIn">
|
<div class="RetweetButton">
|
||||||
<template v-if="visibility !== 'private' && visibility !== 'direct'">
|
<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
|
<FAIcon
|
||||||
:class="classes"
|
class="fa-scale-110 fa-old-padding"
|
||||||
class="RetweetButton fa-scale-110 fa-old-padding -interactive"
|
|
||||||
icon="retweet"
|
icon="retweet"
|
||||||
:spin="animated"
|
:spin="animated"
|
||||||
:title="$t('tool_tip.repeat')"
|
|
||||||
@click.prevent="retweet()"
|
|
||||||
/>
|
/>
|
||||||
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
|
</button>
|
||||||
</template>
|
<span v-else-if="loggedIn">
|
||||||
<template v-else>
|
|
||||||
<FAIcon
|
<FAIcon
|
||||||
:class="classes"
|
class="fa-scale-110 fa-old-padding"
|
||||||
class="RetweetButton fa-scale-110 fa-old-padding"
|
|
||||||
icon="lock"
|
icon="lock"
|
||||||
:title="$t('timeline.no_retweet_hint')"
|
:title="$t('timeline.no_retweet_hint')"
|
||||||
/>
|
/>
|
||||||
</template>
|
</span>
|
||||||
</div>
|
<span v-else>
|
||||||
<div v-else-if="!loggedIn">
|
<FAIcon
|
||||||
<FAIcon
|
class="fa-scale-110 fa-old-padding"
|
||||||
:class="classes"
|
icon="retweet"
|
||||||
class="fa-scale-110 fa-old-padding"
|
:title="$t('tool_tip.repeat')"
|
||||||
icon="retweet"
|
/>
|
||||||
:title="$t('tool_tip.repeat')"
|
</span>
|
||||||
/>
|
<span
|
||||||
<span v-if="!mergedConfig.hidePostStats && status.repeat_num > 0">{{ status.repeat_num }}</span>
|
v-if="!mergedConfig.hidePostStats && status.repeat_num > 0"
|
||||||
|
class="no-event"
|
||||||
|
>
|
||||||
|
{{ status.repeat_num }}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -37,19 +42,28 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.RetweetButton {
|
.RetweetButton {
|
||||||
&.-interactive {
|
display: flex;
|
||||||
cursor: pointer;
|
|
||||||
animation-duration: 0.6s;
|
|
||||||
|
|
||||||
&: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: $fallback--cGreen;
|
||||||
color: var(--cGreen, $fallback--cGreen);
|
color: var(--cGreen, $fallback--cGreen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-repeated {
|
|
||||||
color: $fallback--cGreen;
|
|
||||||
color: var(--cGreen, $fallback--cGreen);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
v-if="!showNothing"
|
v-if="!showNothing"
|
||||||
class="ScopeSelector"
|
class="ScopeSelector"
|
||||||
>
|
>
|
||||||
<span
|
<button
|
||||||
v-if="showDirect"
|
v-if="showDirect"
|
||||||
class="scope"
|
class="button-unstyled scope"
|
||||||
:class="css.direct"
|
:class="css.direct"
|
||||||
:title="$t('post_status.scope.direct')"
|
:title="$t('post_status.scope.direct')"
|
||||||
@click="changeVis('direct')"
|
@click="changeVis('direct')"
|
||||||
|
@ -14,10 +14,10 @@
|
||||||
icon="envelope"
|
icon="envelope"
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/>
|
/>
|
||||||
</span>
|
</button>
|
||||||
<span
|
<button
|
||||||
v-if="showPrivate"
|
v-if="showPrivate"
|
||||||
class="scope"
|
class="button-unstyled scope"
|
||||||
:class="css.private"
|
:class="css.private"
|
||||||
:title="$t('post_status.scope.private')"
|
:title="$t('post_status.scope.private')"
|
||||||
@click="changeVis('private')"
|
@click="changeVis('private')"
|
||||||
|
@ -26,10 +26,10 @@
|
||||||
icon="lock"
|
icon="lock"
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/>
|
/>
|
||||||
</span>
|
</button>
|
||||||
<span
|
<button
|
||||||
v-if="showUnlisted"
|
v-if="showUnlisted"
|
||||||
class="scope"
|
class="button-unstyled scope"
|
||||||
:class="css.unlisted"
|
:class="css.unlisted"
|
||||||
:title="$t('post_status.scope.unlisted')"
|
:title="$t('post_status.scope.unlisted')"
|
||||||
@click="changeVis('unlisted')"
|
@click="changeVis('unlisted')"
|
||||||
|
@ -38,10 +38,10 @@
|
||||||
icon="lock-open"
|
icon="lock-open"
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/>
|
/>
|
||||||
</span>
|
</button>
|
||||||
<span
|
<button
|
||||||
v-if="showPublic"
|
v-if="showPublic"
|
||||||
class="scope"
|
class="button-unstyled scope"
|
||||||
:class="css.public"
|
:class="css.public"
|
||||||
:title="$t('post_status.scope.public')"
|
:title="$t('post_status.scope.public')"
|
||||||
@click="changeVis('public')"
|
@click="changeVis('public')"
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
icon="globe"
|
icon="globe"
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/>
|
/>
|
||||||
</span>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
@keyup.enter="newQuery(searchTerm)"
|
@keyup.enter="newQuery(searchTerm)"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn search-button"
|
class="btn button-default search-button"
|
||||||
@click="newQuery(searchTerm)"
|
@click="newQuery(searchTerm)"
|
||||||
>
|
>
|
||||||
<FAIcon icon="search" />
|
<FAIcon icon="search" />
|
||||||
|
|
|
@ -3,17 +3,18 @@
|
||||||
class="SearchBar"
|
class="SearchBar"
|
||||||
:class="{ '-expanded': !hidden }"
|
:class="{ '-expanded': !hidden }"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
v-if="hidden"
|
v-if="hidden"
|
||||||
href="#"
|
class="button-unstyled nav-icon"
|
||||||
class="nav-icon"
|
|
||||||
:title="$t('nav.search')"
|
:title="$t('nav.search')"
|
||||||
><FAIcon
|
|
||||||
fixed-width
|
|
||||||
class="fa-scale-110 fa-old-padding"
|
|
||||||
icon="search"
|
|
||||||
@click.prevent.stop="toggleHidden"
|
@click.prevent.stop="toggleHidden"
|
||||||
/></a>
|
>
|
||||||
|
<FAIcon
|
||||||
|
fixed-width
|
||||||
|
class="fa-scale-110 fa-old-padding"
|
||||||
|
icon="search"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<input
|
<input
|
||||||
id="search-bar-input"
|
id="search-bar-input"
|
||||||
|
@ -25,7 +26,7 @@
|
||||||
@keyup.enter="find(searchTerm)"
|
@keyup.enter="find(searchTerm)"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn search-button"
|
class="button-default search-button"
|
||||||
@click="find(searchTerm)"
|
@click="find(searchTerm)"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -33,14 +34,16 @@
|
||||||
icon="search"
|
icon="search"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<span>
|
<button
|
||||||
|
class="button-unstyled cancel-search"
|
||||||
|
@click.prevent.stop="toggleHidden"
|
||||||
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
fixed-width
|
fixed-width
|
||||||
icon="times"
|
icon="times"
|
||||||
class="cancel-icon fa-scale-110 fa-old-padding"
|
class="cancel-icon fa-scale-110 fa-old-padding"
|
||||||
@click.prevent.stop="toggleHidden"
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</button>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -69,8 +72,11 @@
|
||||||
flex: 1 0 auto;
|
flex: 1 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cancel-search {
|
||||||
|
height: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
.cancel-icon {
|
.cancel-icon {
|
||||||
cursor: pointer;
|
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--btnTopBarText, $fallback--text);
|
color: var(--btnTopBarText, $fallback--text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,13 +30,13 @@
|
||||||
</template>
|
</template>
|
||||||
</transition>
|
</transition>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="peekModal"
|
@click="peekModal"
|
||||||
>
|
>
|
||||||
{{ $t('general.peek') }}
|
{{ $t('general.peek') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="closeModal"
|
@click="closeModal"
|
||||||
>
|
>
|
||||||
{{ $t('general.close') }}
|
{{ $t('general.close') }}
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
<div class="bulk-actions">
|
<div class="bulk-actions">
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-if="selected.length > 0"
|
v-if="selected.length > 0"
|
||||||
class="btn btn-default bulk-action-button"
|
class="btn button-default bulk-action-button"
|
||||||
:click="() => blockUsers(selected)"
|
:click="() => blockUsers(selected)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.block') }}
|
{{ $t('user_card.block') }}
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
</ProgressButton>
|
</ProgressButton>
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-if="selected.length > 0"
|
v-if="selected.length > 0"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:click="() => unblockUsers(selected)"
|
:click="() => unblockUsers(selected)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.unblock') }}
|
{{ $t('user_card.unblock') }}
|
||||||
|
@ -85,7 +85,7 @@
|
||||||
<div class="bulk-actions">
|
<div class="bulk-actions">
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-if="selected.length > 0"
|
v-if="selected.length > 0"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:click="() => muteUsers(selected)"
|
:click="() => muteUsers(selected)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.mute') }}
|
{{ $t('user_card.mute') }}
|
||||||
|
@ -95,7 +95,7 @@
|
||||||
</ProgressButton>
|
</ProgressButton>
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-if="selected.length > 0"
|
v-if="selected.length > 0"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:click="() => unmuteUsers(selected)"
|
:click="() => unmuteUsers(selected)"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.unmute') }}
|
{{ $t('user_card.unmute') }}
|
||||||
|
@ -141,7 +141,7 @@
|
||||||
<div class="bulk-actions">
|
<div class="bulk-actions">
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-if="selected.length > 0"
|
v-if="selected.length > 0"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:click="() => unmuteDomains(selected)"
|
:click="() => unmuteDomains(selected)"
|
||||||
>
|
>
|
||||||
{{ $t('domain_mute_card.unmute') }}
|
{{ $t('domain_mute_card.unmute') }}
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
<p>{{ $t('settings.notification_mutes') }}</p>
|
<p>{{ $t('settings.notification_mutes') }}</p>
|
||||||
<p>{{ $t('settings.notification_blocks') }}</p>
|
<p>{{ $t('settings.notification_blocks') }}</p>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="updateNotificationSettings"
|
@click="updateNotificationSettings"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
|
|
|
@ -68,8 +68,7 @@ const ProfileTab = {
|
||||||
...this.$store.state.instance.emoji,
|
...this.$store.state.instance.emoji,
|
||||||
...this.$store.state.instance.customEmoji
|
...this.$store.state.instance.customEmoji
|
||||||
],
|
],
|
||||||
users: this.$store.state.users.users,
|
store: this.$store
|
||||||
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
emojiSuggestor () {
|
emojiSuggestor () {
|
||||||
|
@ -79,10 +78,7 @@ const ProfileTab = {
|
||||||
] })
|
] })
|
||||||
},
|
},
|
||||||
userSuggestor () {
|
userSuggestor () {
|
||||||
return suggestor({
|
return suggestor({ store: this.$store })
|
||||||
users: this.$store.state.users.users,
|
|
||||||
updateUsersList: (query) => this.$store.dispatch('searchUsers', { query })
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
fieldsLimits () {
|
fieldsLimits () {
|
||||||
return this.$store.state.instance.fieldsLimits
|
return this.$store.state.instance.fieldsLimits
|
||||||
|
|
|
@ -150,7 +150,7 @@
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
:disabled="newName && newName.length === 0"
|
:disabled="newName && newName.length === 0"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="updateProfile"
|
@click="updateProfile"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
|
@ -179,7 +179,7 @@
|
||||||
<button
|
<button
|
||||||
v-show="pickAvatarBtnVisible"
|
v-show="pickAvatarBtnVisible"
|
||||||
id="pick-avatar"
|
id="pick-avatar"
|
||||||
class="btn"
|
class="button-default btn"
|
||||||
type="button"
|
type="button"
|
||||||
>
|
>
|
||||||
{{ $t('settings.upload_a_photo') }}
|
{{ $t('settings.upload_a_photo') }}
|
||||||
|
@ -224,7 +224,7 @@
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
v-else-if="bannerPreview"
|
v-else-if="bannerPreview"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="submitBanner(banner)"
|
@click="submitBanner(banner)"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
|
@ -274,7 +274,7 @@
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
v-else-if="backgroundPreview"
|
v-else-if="backgroundPreview"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="submitBackground(background)"
|
@click="submitBackground(background)"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
|
|
|
@ -2,14 +2,14 @@
|
||||||
<div>
|
<div>
|
||||||
<slot />
|
<slot />
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@click="confirm"
|
@click="confirm"
|
||||||
>
|
>
|
||||||
{{ $t('general.confirm') }}
|
{{ $t('general.confirm') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
@click="cancel"
|
@click="cancel"
|
||||||
>
|
>
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
/>
|
/>
|
||||||
<button
|
<button
|
||||||
v-if="!confirmNewBackupCodes"
|
v-if="!confirmNewBackupCodes"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="getBackupCodes"
|
@click="getBackupCodes"
|
||||||
>
|
>
|
||||||
{{ $t('settings.mfa.generate_new_recovery_codes') }}
|
{{ $t('settings.mfa.generate_new_recovery_codes') }}
|
||||||
|
@ -61,7 +61,7 @@
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="canSetupOTP"
|
v-if="canSetupOTP"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="cancelSetup"
|
@click="cancelSetup"
|
||||||
>
|
>
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
|
@ -69,7 +69,7 @@
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="canSetupOTP"
|
v-if="canSetupOTP"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="setupOTP"
|
@click="setupOTP"
|
||||||
>
|
>
|
||||||
{{ $t('settings.mfa.setup_otp') }}
|
{{ $t('settings.mfa.setup_otp') }}
|
||||||
|
@ -108,13 +108,13 @@
|
||||||
>
|
>
|
||||||
<div class="confirm-otp-actions">
|
<div class="confirm-otp-actions">
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="doConfirmOTP"
|
@click="doConfirmOTP"
|
||||||
>
|
>
|
||||||
{{ $t('settings.mfa.confirm_and_enable') }}
|
{{ $t('settings.mfa.confirm_and_enable') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="cancelSetup"
|
@click="cancelSetup"
|
||||||
>
|
>
|
||||||
{{ $t('general.cancel') }}
|
{{ $t('general.cancel') }}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<strong>{{ $t('settings.mfa.otp') }}</strong>
|
<strong>{{ $t('settings.mfa.otp') }}</strong>
|
||||||
<button
|
<button
|
||||||
v-if="!isActivated"
|
v-if="!isActivated"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="doActivate"
|
@click="doActivate"
|
||||||
>
|
>
|
||||||
{{ $t('general.enable') }}
|
{{ $t('general.enable') }}
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="isActivated"
|
v-if="isActivated"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="deactivate"
|
:disabled="deactivate"
|
||||||
@click="doDeactivate"
|
@click="doDeactivate"
|
||||||
>
|
>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="changeEmail"
|
@click="changeEmail"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
|
@ -57,7 +57,7 @@
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="changePassword"
|
@click="changePassword"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
|
@ -92,7 +92,7 @@
|
||||||
<td>{{ oauthToken.validUntil }}</td>
|
<td>{{ oauthToken.validUntil }}</td>
|
||||||
<td class="actions">
|
<td class="actions">
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="revokeToken(oauthToken.id)"
|
@click="revokeToken(oauthToken.id)"
|
||||||
>
|
>
|
||||||
{{ $t('settings.revoke_token') }}
|
{{ $t('settings.revoke_token') }}
|
||||||
|
@ -116,7 +116,7 @@
|
||||||
type="password"
|
type="password"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="deleteAccount"
|
@click="deleteAccount"
|
||||||
>
|
>
|
||||||
{{ $t('settings.delete_account') }}
|
{{ $t('settings.delete_account') }}
|
||||||
|
@ -130,7 +130,7 @@
|
||||||
</p>
|
</p>
|
||||||
<button
|
<button
|
||||||
v-if="!deletingAccount"
|
v-if="!deletingAccount"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
@click="confirmDelete"
|
@click="confirmDelete"
|
||||||
>
|
>
|
||||||
{{ $t('general.submit') }}
|
{{ $t('general.submit') }}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<span class="alert error">
|
<span class="alert error">
|
||||||
{{ $t('settings.style.preview.error') }}
|
{{ $t('settings.style.preview.error') }}
|
||||||
</span>
|
</span>
|
||||||
<button class="btn">
|
<button class="btn button-default">
|
||||||
{{ $t('settings.style.preview.button') }}
|
{{ $t('settings.style.preview.button') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -102,7 +102,7 @@
|
||||||
>
|
>
|
||||||
<label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
|
<label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
|
||||||
</span>
|
</span>
|
||||||
<button class="btn">
|
<button class="btn button-default">
|
||||||
{{ $t('settings.style.preview.button') }}
|
{{ $t('settings.style.preview.button') }}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,13 +12,13 @@
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<template v-if="themeWarning.type === 'snapshot_source_mismatch'">
|
<template v-if="themeWarning.type === 'snapshot_source_mismatch'">
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="forceLoad"
|
@click="forceLoad"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.use_source') }}
|
{{ $t('settings.style.switcher.use_source') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="forceSnapshot"
|
@click="forceSnapshot"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.use_snapshot') }}
|
{{ $t('settings.style.switcher.use_snapshot') }}
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="themeWarning.noActionsPossible">
|
<template v-else-if="themeWarning.noActionsPossible">
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="dismissWarning"
|
@click="dismissWarning"
|
||||||
>
|
>
|
||||||
{{ $t('general.dismiss') }}
|
{{ $t('general.dismiss') }}
|
||||||
|
@ -34,13 +34,13 @@
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="forceLoad"
|
@click="forceLoad"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.load_theme') }}
|
{{ $t('settings.style.switcher.load_theme') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="dismissWarning"
|
@click="dismissWarning"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.keep_as_is') }}
|
{{ $t('settings.style.switcher.keep_as_is') }}
|
||||||
|
@ -131,13 +131,13 @@
|
||||||
<p>{{ $t('settings.theme_help') }}</p>
|
<p>{{ $t('settings.theme_help') }}</p>
|
||||||
<div class="tab-header-buttons">
|
<div class="tab-header-buttons">
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearOpacity"
|
@click="clearOpacity"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.clear_opacity') }}
|
{{ $t('settings.style.switcher.clear_opacity') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearV1"
|
@click="clearV1"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.clear_all') }}
|
{{ $t('settings.style.switcher.clear_all') }}
|
||||||
|
@ -238,13 +238,13 @@
|
||||||
<div class="tab-header">
|
<div class="tab-header">
|
||||||
<p>{{ $t('settings.theme_help') }}</p>
|
<p>{{ $t('settings.theme_help') }}</p>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearOpacity"
|
@click="clearOpacity"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.clear_opacity') }}
|
{{ $t('settings.style.switcher.clear_opacity') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearV1"
|
@click="clearV1"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.clear_all') }}
|
{{ $t('settings.style.switcher.clear_all') }}
|
||||||
|
@ -806,7 +806,7 @@
|
||||||
<div class="tab-header">
|
<div class="tab-header">
|
||||||
<p>{{ $t('settings.radii_help') }}</p>
|
<p>{{ $t('settings.radii_help') }}</p>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearRoundness"
|
@click="clearRoundness"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.clear_all') }}
|
{{ $t('settings.style.switcher.clear_all') }}
|
||||||
|
@ -936,7 +936,7 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearShadows"
|
@click="clearShadows"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.clear_all') }}
|
{{ $t('settings.style.switcher.clear_all') }}
|
||||||
|
@ -980,7 +980,7 @@
|
||||||
<div class="tab-header">
|
<div class="tab-header">
|
||||||
<p>{{ $t('settings.style.fonts.help') }}</p>
|
<p>{{ $t('settings.style.fonts.help') }}</p>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearFonts"
|
@click="clearFonts"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.clear_all') }}
|
{{ $t('settings.style.switcher.clear_all') }}
|
||||||
|
@ -1017,14 +1017,14 @@
|
||||||
|
|
||||||
<div class="apply-container">
|
<div class="apply-container">
|
||||||
<button
|
<button
|
||||||
class="btn submit"
|
class="btn button-default submit"
|
||||||
:disabled="!themeValid"
|
:disabled="!themeValid"
|
||||||
@click="setCustomTheme"
|
@click="setCustomTheme"
|
||||||
>
|
>
|
||||||
{{ $t('general.apply') }}
|
{{ $t('general.apply') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn"
|
class="btn button-default"
|
||||||
@click="clearAll"
|
@click="clearAll"
|
||||||
>
|
>
|
||||||
{{ $t('settings.style.switcher.reset') }}
|
{{ $t('settings.style.switcher.reset') }}
|
||||||
|
|
|
@ -84,7 +84,7 @@
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="!ready || !present"
|
:disabled="!ready || !present"
|
||||||
@click="del"
|
@click="del"
|
||||||
>
|
>
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="!moveUpValid"
|
:disabled="!moveUpValid"
|
||||||
@click="moveUp"
|
@click="moveUp"
|
||||||
>
|
>
|
||||||
|
@ -104,7 +104,7 @@
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="!moveDnValid"
|
:disabled="!moveDnValid"
|
||||||
@click="moveDn"
|
@click="moveDn"
|
||||||
>
|
>
|
||||||
|
@ -114,7 +114,7 @@
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="usingFallback"
|
:disabled="usingFallback"
|
||||||
@click="add"
|
@click="add"
|
||||||
>
|
>
|
||||||
|
|
|
@ -144,8 +144,8 @@
|
||||||
</router-link>
|
</router-link>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleDrawer">
|
<li @click="toggleDrawer">
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link -fullwidth"
|
||||||
@click="openSettingsModal"
|
@click="openSettingsModal"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -153,7 +153,7 @@
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
icon="cog"
|
icon="cog"
|
||||||
/> {{ $t("settings.settings") }}
|
/> {{ $t("settings.settings") }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
<li @click="toggleDrawer">
|
<li @click="toggleDrawer">
|
||||||
<router-link :to="{ name: 'about'}">
|
<router-link :to="{ name: 'about'}">
|
||||||
|
@ -183,8 +183,8 @@
|
||||||
v-if="currentUser"
|
v-if="currentUser"
|
||||||
@click="toggleDrawer"
|
@click="toggleDrawer"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link -fullwidth"
|
||||||
@click="doLogout"
|
@click="doLogout"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -192,7 +192,7 @@
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
icon="sign-out-alt"
|
icon="sign-out-alt"
|
||||||
/> {{ $t("login.logout") }}
|
/> {{ $t("login.logout") }}
|
||||||
</a>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -331,7 +331,7 @@
|
||||||
.side-drawer li {
|
.side-drawer li {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
a {
|
a, button {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
display: block;
|
display: block;
|
||||||
height: 3em;
|
height: 3em;
|
||||||
|
|
|
@ -29,6 +29,8 @@ $status-margin: 0.75em;
|
||||||
&.-conversation {
|
&.-conversation {
|
||||||
border-left-width: 4px;
|
border-left-width: 4px;
|
||||||
border-left-style: solid;
|
border-left-style: solid;
|
||||||
|
border-left-color: $fallback--cRed;
|
||||||
|
border-left-color: var(--cRed, $fallback--cRed);
|
||||||
}
|
}
|
||||||
|
|
||||||
.gravestone {
|
.gravestone {
|
||||||
|
|
|
@ -47,16 +47,15 @@
|
||||||
>
|
>
|
||||||
{{ muteWordHits.join(', ') }}
|
{{ muteWordHits.join(', ') }}
|
||||||
</small>
|
</small>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="unmute button-unstyled"
|
||||||
class="unmute fa-scale-110 fa-old-padding"
|
|
||||||
@click.prevent="toggleMute"
|
@click.prevent="toggleMute"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
icon="eye-slash"
|
icon="eye-slash"
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
@ -201,9 +200,9 @@
|
||||||
icon="external-link-square-alt"
|
icon="external-link-square-alt"
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<button
|
||||||
v-if="expandable && !isPreview"
|
v-if="expandable && !isPreview"
|
||||||
href="#"
|
class="button-unstyled"
|
||||||
title="Expand"
|
title="Expand"
|
||||||
@click.prevent="toggleExpanded"
|
@click.prevent="toggleExpanded"
|
||||||
>
|
>
|
||||||
|
@ -211,17 +210,17 @@
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
icon="plus-square"
|
icon="plus-square"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
v-if="unmuted"
|
v-if="unmuted"
|
||||||
href="#"
|
class="button-unstyled"
|
||||||
@click.prevent="toggleMute"
|
@click.prevent="toggleMute"
|
||||||
>
|
>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
icon="eye-slash"
|
icon="eye-slash"
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -237,9 +236,8 @@
|
||||||
style="min-width: 0"
|
style="min-width: 0"
|
||||||
:class="{ '-strikethrough': !status.parent_visible }"
|
:class="{ '-strikethrough': !status.parent_visible }"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
class="reply-to"
|
class="button-unstyled reply-to"
|
||||||
href="#"
|
|
||||||
:aria-label="$t('tool_tip.reply')"
|
:aria-label="$t('tool_tip.reply')"
|
||||||
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
|
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
|
||||||
>
|
>
|
||||||
|
@ -253,7 +251,7 @@
|
||||||
>
|
>
|
||||||
{{ $t('status.reply_to') }}
|
{{ $t('status.reply_to') }}
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</button>
|
||||||
</StatusPopover>
|
</StatusPopover>
|
||||||
|
|
||||||
<span
|
<span
|
||||||
|
@ -286,11 +284,12 @@
|
||||||
:key="reply.id"
|
:key="reply.id"
|
||||||
:status-id="reply.id"
|
:status-id="reply.id"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
href="#"
|
class="button-unstyled -link reply-link"
|
||||||
class="reply-link"
|
|
||||||
@click.prevent="gotoOriginal(reply.id)"
|
@click.prevent="gotoOriginal(reply.id)"
|
||||||
>{{ reply.name }}</a>
|
>
|
||||||
|
{{ reply.name }}
|
||||||
|
</button>
|
||||||
</StatusPopover>
|
</StatusPopover>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -12,35 +12,34 @@
|
||||||
@click.prevent="linkClicked"
|
@click.prevent="linkClicked"
|
||||||
v-html="status.summary_html"
|
v-html="status.summary_html"
|
||||||
/>
|
/>
|
||||||
<a
|
<button
|
||||||
v-if="longSubject && showingLongSubject"
|
v-if="longSubject && showingLongSubject"
|
||||||
href="#"
|
class="button-unstyled -link tall-subject-hider"
|
||||||
class="tall-subject-hider"
|
|
||||||
@click.prevent="showingLongSubject=false"
|
@click.prevent="showingLongSubject=false"
|
||||||
>{{ $t("status.hide_full_subject") }}</a>
|
>
|
||||||
<a
|
{{ $t("status.hide_full_subject") }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
v-else-if="longSubject"
|
v-else-if="longSubject"
|
||||||
class="tall-subject-hider"
|
class="button-unstyled -link tall-subject-hider"
|
||||||
:class="{ 'tall-subject-hider_focused': focused }"
|
:class="{ 'tall-subject-hider_focused': focused }"
|
||||||
href="#"
|
|
||||||
@click.prevent="showingLongSubject=true"
|
@click.prevent="showingLongSubject=true"
|
||||||
>
|
>
|
||||||
{{ $t("status.show_full_subject") }}
|
{{ $t("status.show_full_subject") }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
:class="{'tall-status': hideTallStatus}"
|
:class="{'tall-status': hideTallStatus}"
|
||||||
class="status-content-wrapper"
|
class="status-content-wrapper"
|
||||||
>
|
>
|
||||||
<a
|
<button
|
||||||
v-if="hideTallStatus"
|
v-if="hideTallStatus"
|
||||||
class="tall-status-hider"
|
class="button-unstyled -link tall-status-hider"
|
||||||
:class="{ 'tall-status-hider_focused': focused }"
|
:class="{ 'tall-status-hider_focused': focused }"
|
||||||
href="#"
|
|
||||||
@click.prevent="toggleShowMore"
|
@click.prevent="toggleShowMore"
|
||||||
>
|
>
|
||||||
{{ $t("general.show_more") }}
|
{{ $t("general.show_more") }}
|
||||||
</a>
|
</button>
|
||||||
<div
|
<div
|
||||||
v-if="!hideSubjectStatus"
|
v-if="!hideSubjectStatus"
|
||||||
:class="{ 'single-line': singleLine }"
|
:class="{ 'single-line': singleLine }"
|
||||||
|
@ -48,10 +47,9 @@
|
||||||
@click.prevent="linkClicked"
|
@click.prevent="linkClicked"
|
||||||
v-html="postBodyHtml"
|
v-html="postBodyHtml"
|
||||||
/>
|
/>
|
||||||
<a
|
<button
|
||||||
v-if="hideSubjectStatus"
|
v-if="hideSubjectStatus"
|
||||||
href="#"
|
class="button-unstyled -link cw-status-hider"
|
||||||
class="cw-status-hider"
|
|
||||||
@click.prevent="toggleShowMore"
|
@click.prevent="toggleShowMore"
|
||||||
>
|
>
|
||||||
{{ $t("status.show_content") }}
|
{{ $t("status.show_content") }}
|
||||||
|
@ -79,15 +77,14 @@
|
||||||
v-if="status.card"
|
v-if="status.card"
|
||||||
icon="link"
|
icon="link"
|
||||||
/>
|
/>
|
||||||
</a>
|
</button>
|
||||||
<a
|
<button
|
||||||
v-if="showingMore && !fullContent"
|
v-if="showingMore && !fullContent"
|
||||||
href="#"
|
class="button-unstyled -link status-unhider"
|
||||||
class="status-unhider"
|
|
||||||
@click.prevent="toggleShowMore"
|
@click.prevent="toggleShowMore"
|
||||||
>
|
>
|
||||||
{{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
|
{{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
|
||||||
</a>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="status.poll && status.poll.options && !hideSubjectStatus">
|
<div v-if="status.poll && status.poll.options && !hideSubjectStatus">
|
||||||
|
|
|
@ -81,7 +81,7 @@ export default Vue.component('tab-switcher', {
|
||||||
const tabs = this.$slots.default
|
const tabs = this.$slots.default
|
||||||
.map((slot, index) => {
|
.map((slot, index) => {
|
||||||
if (!slot.tag) return
|
if (!slot.tag) return
|
||||||
const classesTab = ['tab']
|
const classesTab = ['tab', 'button-default']
|
||||||
const classesWrapper = ['tab-wrapper']
|
const classesWrapper = ['tab-wrapper']
|
||||||
if (this.activeIndex === index) {
|
if (this.activeIndex === index) {
|
||||||
classesTab.push('active')
|
classesTab.push('active')
|
||||||
|
|
|
@ -50,17 +50,10 @@ const Timeline = {
|
||||||
TimelineMenu
|
TimelineMenu
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
timelineError () {
|
|
||||||
return this.$store.state.statuses.error
|
|
||||||
},
|
|
||||||
errorData () {
|
|
||||||
return this.$store.state.statuses.errorData
|
|
||||||
},
|
|
||||||
newStatusCount () {
|
newStatusCount () {
|
||||||
return this.timeline.newStatusCount
|
return this.timeline.newStatusCount
|
||||||
},
|
},
|
||||||
showLoadButton () {
|
showLoadButton () {
|
||||||
if (this.timelineError || this.errorData) return false
|
|
||||||
return this.timeline.newStatusCount > 0 || this.timeline.flushMarker !== 0
|
return this.timeline.newStatusCount > 0 || this.timeline.flushMarker !== 0
|
||||||
},
|
},
|
||||||
loadButtonString () {
|
loadButtonString () {
|
||||||
|
@ -171,11 +164,12 @@ const Timeline = {
|
||||||
userId: this.userId,
|
userId: this.userId,
|
||||||
tag: this.tag
|
tag: this.tag
|
||||||
}).then(({ statuses }) => {
|
}).then(({ statuses }) => {
|
||||||
store.commit('setLoading', { timeline: this.timelineName, value: false })
|
|
||||||
if (statuses && statuses.length === 0) {
|
if (statuses && statuses.length === 0) {
|
||||||
this.bottomedOut = true
|
this.bottomedOut = true
|
||||||
}
|
}
|
||||||
})
|
}).finally(() =>
|
||||||
|
store.commit('setLoading', { timeline: this.timelineName, value: false })
|
||||||
|
)
|
||||||
}, 1000, this),
|
}, 1000, this),
|
||||||
determineVisibleStatuses () {
|
determineVisibleStatuses () {
|
||||||
if (!this.$refs.timeline) return
|
if (!this.$refs.timeline) return
|
||||||
|
|
|
@ -2,23 +2,9 @@
|
||||||
<div :class="[classes.root, 'Timeline']">
|
<div :class="[classes.root, 'Timeline']">
|
||||||
<div :class="classes.header">
|
<div :class="classes.header">
|
||||||
<TimelineMenu v-if="!embedded" />
|
<TimelineMenu v-if="!embedded" />
|
||||||
<div
|
|
||||||
v-if="timelineError"
|
|
||||||
class="loadmore-error alert error"
|
|
||||||
@click.prevent
|
|
||||||
>
|
|
||||||
{{ $t('timeline.error_fetching') }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-else-if="errorData"
|
|
||||||
class="loadmore-error alert error"
|
|
||||||
@click.prevent
|
|
||||||
>
|
|
||||||
{{ errorData.statusText }}
|
|
||||||
</div>
|
|
||||||
<button
|
<button
|
||||||
v-else-if="showLoadButton"
|
v-if="showLoadButton"
|
||||||
class="loadmore-button"
|
class="button-default loadmore-button"
|
||||||
@click.prevent="showNewStatuses"
|
@click.prevent="showNewStatuses"
|
||||||
>
|
>
|
||||||
{{ loadButtonString }}
|
{{ loadButtonString }}
|
||||||
|
@ -75,19 +61,15 @@
|
||||||
>
|
>
|
||||||
{{ $t('timeline.no_more_statuses') }}
|
{{ $t('timeline.no_more_statuses') }}
|
||||||
</div>
|
</div>
|
||||||
<a
|
<button
|
||||||
v-else-if="!timeline.loading && !errorData"
|
v-else-if="!timeline.loading"
|
||||||
href="#"
|
class="button-unstyled -link -fullwidth"
|
||||||
@click.prevent="fetchOlderStatuses()"
|
@click.prevent="fetchOlderStatuses()"
|
||||||
>
|
>
|
||||||
<div class="new-status-notification text-center panel-footer">{{ $t('timeline.load_older') }}</div>
|
<div class="new-status-notification text-center panel-footer">
|
||||||
</a>
|
{{ $t('timeline.load_older') }}
|
||||||
<a
|
</div>
|
||||||
v-else-if="errorData"
|
</button>
|
||||||
href="#"
|
|
||||||
>
|
|
||||||
<div class="new-status-notification text-center panel-footer">{{ errorData.error }}</div>
|
|
||||||
</a>
|
|
||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
class="new-status-notification text-center panel-footer"
|
class="new-status-notification text-center panel-footer"
|
||||||
|
|
|
@ -19,7 +19,7 @@ library.add(
|
||||||
faChevronDown
|
faChevronDown
|
||||||
)
|
)
|
||||||
|
|
||||||
// Route -> i18n key mapping, exported andnot in the computed
|
// Route -> i18n key mapping, exported and not in the computed
|
||||||
// because nav panel benefits from the same information.
|
// because nav panel benefits from the same information.
|
||||||
export const timelineNames = () => {
|
export const timelineNames = () => {
|
||||||
return {
|
return {
|
||||||
|
@ -27,8 +27,7 @@ export const timelineNames = () => {
|
||||||
'bookmarks': 'nav.bookmarks',
|
'bookmarks': 'nav.bookmarks',
|
||||||
'dms': 'nav.dms',
|
'dms': 'nav.dms',
|
||||||
'public-timeline': 'nav.public_tl',
|
'public-timeline': 'nav.public_tl',
|
||||||
'public-external-timeline': 'nav.twkn',
|
'public-external-timeline': 'nav.twkn'
|
||||||
'tag-timeline': 'tag'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,7 +162,7 @@
|
||||||
<template v-if="relationship.following">
|
<template v-if="relationship.following">
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-if="!relationship.subscribing"
|
v-if="!relationship.subscribing"
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:click="subscribeUser"
|
:click="subscribeUser"
|
||||||
:title="$t('user_card.subscribe')"
|
:title="$t('user_card.subscribe')"
|
||||||
>
|
>
|
||||||
|
@ -170,7 +170,7 @@
|
||||||
</ProgressButton>
|
</ProgressButton>
|
||||||
<ProgressButton
|
<ProgressButton
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-default toggled"
|
class="btn button-default toggled"
|
||||||
:click="unsubscribeUser"
|
:click="unsubscribeUser"
|
||||||
:title="$t('user_card.unsubscribe')"
|
:title="$t('user_card.unsubscribe')"
|
||||||
>
|
>
|
||||||
|
@ -192,14 +192,14 @@
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
v-if="relationship.muting"
|
v-if="relationship.muting"
|
||||||
class="btn btn-default btn-block toggled"
|
class="btn button-default btn-block toggled"
|
||||||
@click="unmuteUser"
|
@click="unmuteUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.muted') }}
|
{{ $t('user_card.muted') }}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-else
|
v-else
|
||||||
class="btn btn-default btn-block"
|
class="btn button-default btn-block"
|
||||||
@click="muteUser"
|
@click="muteUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.mute') }}
|
{{ $t('user_card.mute') }}
|
||||||
|
@ -207,7 +207,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default btn-block"
|
class="btn button-default btn-block"
|
||||||
@click="mentionUser"
|
@click="mentionUser"
|
||||||
>
|
>
|
||||||
{{ $t('user_card.mention') }}
|
{{ $t('user_card.mention') }}
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<button
|
<button
|
||||||
class="btn btn-default"
|
class="btn button-default"
|
||||||
:disabled="processing"
|
:disabled="processing"
|
||||||
@click="reportUser"
|
@click="reportUser"
|
||||||
>
|
>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<video
|
<video
|
||||||
class="video"
|
class="video"
|
||||||
|
preload="metadata"
|
||||||
:src="attachment.url"
|
:src="attachment.url"
|
||||||
:loop="loopVideo"
|
:loop="loopVideo"
|
||||||
:controls="controls"
|
:controls="controls"
|
||||||
|
|
|
@ -91,7 +91,11 @@ const withLoadMore = ({
|
||||||
{children}
|
{children}
|
||||||
</WrappedComponent>
|
</WrappedComponent>
|
||||||
<div class="with-load-more-footer">
|
<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 && <FAIcon spin icon="circle-notch"/>}
|
||||||
{!this.error && !this.loading && !this.bottomedOut && <a onClick={this.fetchEntries}>{this.$t('general.more')}</a>}
|
{!this.error && !this.loading && !this.bottomedOut && <a onClick={this.fetchEntries}>{this.$t('general.more')}</a>}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -130,6 +130,7 @@
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"broken_favorite": "Unknown status, searching for it…",
|
"broken_favorite": "Unknown status, searching for it…",
|
||||||
|
"error": "Error fetching notifications: {0}",
|
||||||
"favorited_you": "favorited your status",
|
"favorited_you": "favorited your status",
|
||||||
"followed_you": "followed you",
|
"followed_you": "followed you",
|
||||||
"follow_request": "wants to follow you",
|
"follow_request": "wants to follow you",
|
||||||
|
@ -376,7 +377,7 @@
|
||||||
"hide_followers_count_description": "Don't show follower count",
|
"hide_followers_count_description": "Don't show follower count",
|
||||||
"show_admin_badge": "Show Admin badge in my profile",
|
"show_admin_badge": "Show Admin badge in my profile",
|
||||||
"show_moderator_badge": "Show Moderator badge in my profile",
|
"show_moderator_badge": "Show Moderator badge in my profile",
|
||||||
"nsfw_clickthrough": "Enable clickthrough NSFW attachment hiding",
|
"nsfw_clickthrough": "Enable clickthrough attachment and link preview image hiding for NSFW statuses",
|
||||||
"oauth_tokens": "OAuth tokens",
|
"oauth_tokens": "OAuth tokens",
|
||||||
"token": "Token",
|
"token": "Token",
|
||||||
"refresh_token": "Refresh Token",
|
"refresh_token": "Refresh Token",
|
||||||
|
@ -634,7 +635,7 @@
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Collapse",
|
"collapse": "Collapse",
|
||||||
"conversation": "Conversation",
|
"conversation": "Conversation",
|
||||||
"error_fetching": "Error fetching updates",
|
"error": "Error fetching timeline: {0}",
|
||||||
"load_older": "Load older statuses",
|
"load_older": "Load older statuses",
|
||||||
"no_retweet_hint": "Post is marked as followers-only or direct and cannot be repeated",
|
"no_retweet_hint": "Post is marked as followers-only or direct and cannot be repeated",
|
||||||
"repeated": "repeated",
|
"repeated": "repeated",
|
||||||
|
@ -666,7 +667,8 @@
|
||||||
"hide_full_subject": "Hide full subject",
|
"hide_full_subject": "Hide full subject",
|
||||||
"show_content": "Show content",
|
"show_content": "Show content",
|
||||||
"hide_content": "Hide content",
|
"hide_content": "Hide content",
|
||||||
"status_deleted": "This post was deleted"
|
"status_deleted": "This post was deleted",
|
||||||
|
"nsfw": "NSFW"
|
||||||
},
|
},
|
||||||
"user_card": {
|
"user_card": {
|
||||||
"approve": "Approve",
|
"approve": "Approve",
|
||||||
|
|
|
@ -134,14 +134,14 @@
|
||||||
"registration": {
|
"registration": {
|
||||||
"bio": "Priskribo",
|
"bio": "Priskribo",
|
||||||
"email": "Retpoŝtadreso",
|
"email": "Retpoŝtadreso",
|
||||||
"fullname": "Vidiga nomo",
|
"fullname": "Prezenta nomo",
|
||||||
"password_confirm": "Konfirmo de pasvorto",
|
"password_confirm": "Konfirmo de pasvorto",
|
||||||
"registration": "Registriĝo",
|
"registration": "Registriĝo",
|
||||||
"token": "Invita ĵetono",
|
"token": "Invita ĵetono",
|
||||||
"captcha": "TESTO DE HOMECO",
|
"captcha": "TESTO DE HOMECO",
|
||||||
"new_captcha": "Klaku la bildon por akiri novan teston",
|
"new_captcha": "Klaku la bildon por akiri novan teston",
|
||||||
"username_placeholder": "ekz. lain",
|
"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 ».",
|
"bio_placeholder": "ekz.\nSaluton, mi estas Lain.\nMi estas animea knabino vivanta en Japanujo. Eble vi konas min pro la retejo « Wired ».",
|
||||||
"validations": {
|
"validations": {
|
||||||
"username_required": "ne povas resti malplena",
|
"username_required": "ne povas resti malplena",
|
||||||
|
@ -164,7 +164,7 @@
|
||||||
"blocks_tab": "Blokitoj",
|
"blocks_tab": "Blokitoj",
|
||||||
"btnRadius": "Butonoj",
|
"btnRadius": "Butonoj",
|
||||||
"cBlue": "Blua (respondi, aboni)",
|
"cBlue": "Blua (respondi, aboni)",
|
||||||
"cGreen": "Verda (kunhavigi)",
|
"cGreen": "Verda (diskonigi)",
|
||||||
"cOrange": "Oranĝa (ŝati)",
|
"cOrange": "Oranĝa (ŝati)",
|
||||||
"cRed": "Ruĝa (nuligi)",
|
"cRed": "Ruĝa (nuligi)",
|
||||||
"change_password": "Ŝanĝi pasvorton",
|
"change_password": "Ŝanĝi pasvorton",
|
||||||
|
@ -207,8 +207,8 @@
|
||||||
"import_theme": "Enlegi antaŭagordojn",
|
"import_theme": "Enlegi antaŭagordojn",
|
||||||
"inputRadius": "Enigaj kampoj",
|
"inputRadius": "Enigaj kampoj",
|
||||||
"checkboxRadius": "Markbutonoj",
|
"checkboxRadius": "Markbutonoj",
|
||||||
"instance_default": "(implicita: {value})",
|
"instance_default": "(originale: {value})",
|
||||||
"instance_default_simple": "(implicita)",
|
"instance_default_simple": "(originale)",
|
||||||
"interface": "Fasado",
|
"interface": "Fasado",
|
||||||
"interfaceLanguage": "Lingvo de 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.",
|
"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)",
|
"loop_video_silent_only": "Ripetadi nur filmojn sen sono (ekz. la «GIF-ojn» de Mastodon)",
|
||||||
"mutes_tab": "Silentigoj",
|
"mutes_tab": "Silentigoj",
|
||||||
"play_videos_in_modal": "Ludi filmojn en ŝpruca kadro",
|
"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": "Nomo",
|
||||||
"name_bio": "Nomo kaj priskribo",
|
"name_bio": "Nomo kaj priskribo",
|
||||||
"new_password": "Nova pasvorto",
|
"new_password": "Nova pasvorto",
|
||||||
|
@ -265,7 +265,7 @@
|
||||||
"subject_line_email": "Kiel retpoŝto: «re: temo»",
|
"subject_line_email": "Kiel retpoŝto: «re: temo»",
|
||||||
"subject_line_mastodon": "Kiel Mastodon: kopii senŝanĝe",
|
"subject_line_mastodon": "Kiel Mastodon: kopii senŝanĝe",
|
||||||
"subject_line_noop": "Ne kopii",
|
"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",
|
"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",
|
"streaming": "Ŝalti memagan fluigon de novaj afiŝoj kiam vi vidas la supron de la paĝo",
|
||||||
"text": "Teksto",
|
"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.",
|
"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": {
|
"filter_hint": {
|
||||||
"always_drop_shadow": "Averto: ĉi tiu ombro ĉiam uzas {0} kiam la foliumilo tion subtenas.",
|
"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.",
|
"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",
|
"spread_zero": "Ombroj kun vastigo > 0 aperos kvazaŭ ĝi estus fakte nulo",
|
||||||
"inset_classic": "Internaj ombroj uzos {0}"
|
"inset_classic": "Internaj ombroj uzos {0}"
|
||||||
|
@ -394,7 +394,7 @@
|
||||||
"button": "Butono",
|
"button": "Butono",
|
||||||
"buttonHover": "Butono (je ŝvebo)",
|
"buttonHover": "Butono (je ŝvebo)",
|
||||||
"buttonPressed": "Butono (premita)",
|
"buttonPressed": "Butono (premita)",
|
||||||
"buttonPressedHover": "Butono (premita kaj je ŝvebo)",
|
"buttonPressedHover": "Butono (je premo kaj ŝvebo)",
|
||||||
"input": "Eniga kampo"
|
"input": "Eniga kampo"
|
||||||
},
|
},
|
||||||
"hintV3": "Kolorojn de ombroj vi ankaŭ povas skribi per la sistemo {0}."
|
"hintV3": "Kolorojn de ombroj vi ankaŭ povas skribi per la sistemo {0}."
|
||||||
|
@ -683,7 +683,7 @@
|
||||||
"replace": "Anstataŭigi",
|
"replace": "Anstataŭigi",
|
||||||
"reject": "Rifuzi",
|
"reject": "Rifuzi",
|
||||||
"ftl_removal": "Forigo el la historio de «La tuta konata reto»",
|
"ftl_removal": "Forigo el la historio de «La tuta konata reto»",
|
||||||
"keyword_policies": "Politiko pri ŝlosilvortoj"
|
"keyword_policies": "Politiko pri ĉefvortoj"
|
||||||
},
|
},
|
||||||
"federation": "Federado",
|
"federation": "Federado",
|
||||||
"mrf_policies_desc": "Politikoj de Mesaĝa ŝanĝilaro (MRF) efikas sur federa konduto de la nodo. La sekvaj politikoj estas ŝaltitaj:"
|
"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",
|
"week_short": "{0}s",
|
||||||
"weeks": "{0} semajnoj",
|
"weeks": "{0} semajnoj",
|
||||||
"week": "{0} semajno",
|
"week": "{0} semajno",
|
||||||
"seconds_short": "{0}s",
|
"seconds_short": "{0}sek",
|
||||||
"second_short": "{0}s",
|
"second_short": "{0}sek",
|
||||||
"seconds": "{0} sekundoj",
|
"seconds": "{0} sekundoj",
|
||||||
"second": "{0} sekundo",
|
"second": "{0} sekundo",
|
||||||
"now_short": "nun",
|
"now_short": "nun",
|
||||||
|
@ -749,14 +749,14 @@
|
||||||
"month_short": "{0}m",
|
"month_short": "{0}m",
|
||||||
"months": "{0} monatoj",
|
"months": "{0} monatoj",
|
||||||
"month": "{0} monato",
|
"month": "{0} monato",
|
||||||
"minutes_short": "{0}m",
|
"minutes_short": "{0}min",
|
||||||
"minute_short": "{0}m",
|
"minute_short": "{0}min",
|
||||||
"minutes": "{0} minutoj",
|
"minutes": "{0} minutoj",
|
||||||
"minute": "{0} minuto",
|
"minute": "{0} minuto",
|
||||||
"in_past": "antaŭ {0}",
|
"in_past": "antaŭ {0}",
|
||||||
"in_future": "post {0}",
|
"in_future": "post {0}",
|
||||||
"hours_short": "{0}h",
|
"hours_short": "{0}hor",
|
||||||
"hour_short": "{0}h",
|
"hour_short": "{0}hor",
|
||||||
"hours": "{0} horoj",
|
"hours": "{0} horoj",
|
||||||
"hour": "{0} horo",
|
"hour": "{0} horo",
|
||||||
"days_short": "{0}t",
|
"days_short": "{0}t",
|
||||||
|
|
|
@ -104,7 +104,8 @@
|
||||||
"no_more_notifications": "No hay más notificaciones",
|
"no_more_notifications": "No hay más notificaciones",
|
||||||
"reacted_with": "reaccionó con {0}",
|
"reacted_with": "reaccionó con {0}",
|
||||||
"migrated_to": "migrado a",
|
"migrated_to": "migrado a",
|
||||||
"follow_request": "quiere seguirte"
|
"follow_request": "quiere seguirte",
|
||||||
|
"error": "Error obteniendo notificaciones:{0}"
|
||||||
},
|
},
|
||||||
"polls": {
|
"polls": {
|
||||||
"add_poll": "Añadir encuesta",
|
"add_poll": "Añadir encuesta",
|
||||||
|
@ -313,7 +314,7 @@
|
||||||
"hide_followers_count_description": "No mostrar el número de cuentas que me siguen",
|
"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_admin_badge": "Mostrar la insignia de Administrador en mi perfil",
|
||||||
"show_moderator_badge": "Mostrar la insignia de Moderador 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",
|
"oauth_tokens": "Tokens de OAuth",
|
||||||
"token": "Token",
|
"token": "Token",
|
||||||
"refresh_token": "Actualizar el token",
|
"refresh_token": "Actualizar el token",
|
||||||
|
@ -605,7 +606,8 @@
|
||||||
"up_to_date": "Actualizado",
|
"up_to_date": "Actualizado",
|
||||||
"no_more_statuses": "No hay más estados",
|
"no_more_statuses": "No hay más estados",
|
||||||
"no_statuses": "Sin estados",
|
"no_statuses": "Sin estados",
|
||||||
"reload": "Recargar"
|
"reload": "Recargar",
|
||||||
|
"error": "Error obteniendo la linea de tiempo:{0}"
|
||||||
},
|
},
|
||||||
"status": {
|
"status": {
|
||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
|
@ -628,7 +630,9 @@
|
||||||
"copy_link": "Copiar el enlace al estado",
|
"copy_link": "Copiar el enlace al estado",
|
||||||
"status_unavailable": "Estado no disponible",
|
"status_unavailable": "Estado no disponible",
|
||||||
"bookmark": "Marcar",
|
"bookmark": "Marcar",
|
||||||
"unbookmark": "Desmarcar"
|
"unbookmark": "Desmarcar",
|
||||||
|
"status_deleted": "Esta entrada ha sido eliminada",
|
||||||
|
"nsfw": "NSFW (No apropiado para el trabajo)"
|
||||||
},
|
},
|
||||||
"user_card": {
|
"user_card": {
|
||||||
"approve": "Aprobar",
|
"approve": "Aprobar",
|
||||||
|
|
|
@ -390,5 +390,13 @@
|
||||||
"GiB": "GiB",
|
"GiB": "GiB",
|
||||||
"TiB": "TiB"
|
"TiB": "TiB"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"about": {
|
||||||
|
"mrf": {
|
||||||
|
"keyword": {
|
||||||
|
"keyword_policies": "פוליסת מילות מפתח"
|
||||||
|
},
|
||||||
|
"federation": "פדרציה"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,8 @@
|
||||||
"follow_request": "vuole seguirti",
|
"follow_request": "vuole seguirti",
|
||||||
"no_more_notifications": "Fine delle notifiche",
|
"no_more_notifications": "Fine delle notifiche",
|
||||||
"migrated_to": "è migrato verso",
|
"migrated_to": "è migrato verso",
|
||||||
"reacted_with": "ha reagito con {0}"
|
"reacted_with": "ha reagito con {0}",
|
||||||
|
"error": "Errore nel caricare le notifiche: {0}"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"attachments": "Allegati",
|
"attachments": "Allegati",
|
||||||
|
@ -427,7 +428,8 @@
|
||||||
"repeated": "condiviso",
|
"repeated": "condiviso",
|
||||||
"no_statuses": "Nessun messaggio",
|
"no_statuses": "Nessun messaggio",
|
||||||
"no_more_statuses": "Fine dei messaggi",
|
"no_more_statuses": "Fine dei messaggi",
|
||||||
"reload": "Ricarica"
|
"reload": "Ricarica",
|
||||||
|
"error": "Errore nel caricare la sequenza: {0}"
|
||||||
},
|
},
|
||||||
"user_card": {
|
"user_card": {
|
||||||
"follow": "Segui",
|
"follow": "Segui",
|
||||||
|
@ -703,7 +705,8 @@
|
||||||
"delete_confirm": "Vuoi veramente eliminare questo messaggio?",
|
"delete_confirm": "Vuoi veramente eliminare questo messaggio?",
|
||||||
"unbookmark": "Rimuovi segnalibro",
|
"unbookmark": "Rimuovi segnalibro",
|
||||||
"bookmark": "Aggiungi segnalibro",
|
"bookmark": "Aggiungi segnalibro",
|
||||||
"status_deleted": "Questo messagio è stato cancellato"
|
"status_deleted": "Questo messagio è stato cancellato",
|
||||||
|
"nsfw": "Pruriginoso"
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"years_short": "{0}a",
|
"years_short": "{0}a",
|
||||||
|
|
|
@ -18,7 +18,13 @@
|
||||||
"generic_error": "Произошла ошибка",
|
"generic_error": "Произошла ошибка",
|
||||||
"optional": "не обязательно",
|
"optional": "не обязательно",
|
||||||
"show_less": "Показать меньше",
|
"show_less": "Показать меньше",
|
||||||
"show_more": "Показать больше"
|
"show_more": "Показать больше",
|
||||||
|
"peek": "Взглянуть",
|
||||||
|
"dismiss": "Закрыть",
|
||||||
|
"retry": "Попробуйте еще раз",
|
||||||
|
"error_retry": "Пожалуйста попробуйте еще раз",
|
||||||
|
"close": "Закрыть",
|
||||||
|
"loading": "Загрузка…"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"login": "Войти",
|
"login": "Войти",
|
||||||
|
@ -468,7 +474,9 @@
|
||||||
"media_proxy": "Прокси для внешних вложений",
|
"media_proxy": "Прокси для внешних вложений",
|
||||||
"text_limit": "Лимит символов",
|
"text_limit": "Лимит символов",
|
||||||
"title": "Особенности",
|
"title": "Особенности",
|
||||||
"gopher": "Gopher"
|
"gopher": "Gopher",
|
||||||
|
"who_to_follow": "Предложения кого читать",
|
||||||
|
"pleroma_chat_messages": "Pleroma Чат"
|
||||||
},
|
},
|
||||||
"tool_tip": {
|
"tool_tip": {
|
||||||
"accept_follow_request": "Принять запрос на чтение",
|
"accept_follow_request": "Принять запрос на чтение",
|
||||||
|
@ -477,6 +485,7 @@
|
||||||
"image_cropper": {
|
"image_cropper": {
|
||||||
"save_without_cropping": "Сохранить не обрезая",
|
"save_without_cropping": "Сохранить не обрезая",
|
||||||
"save": "Сохранить",
|
"save": "Сохранить",
|
||||||
"crop_picture": "Обрезать картинку"
|
"crop_picture": "Обрезать картинку",
|
||||||
|
"cancel": "Отмена"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
99
src/i18n/uk.json
Normal file
99
src/i18n/uk.json
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
{
|
||||||
|
"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": "Увійти"
|
||||||
|
},
|
||||||
|
"importer": {
|
||||||
|
"error": "Під час імпортування файлу сталася помилка.",
|
||||||
|
"success": "Імпортовано успішно.",
|
||||||
|
"submit": "Відправити"
|
||||||
|
},
|
||||||
|
"image_cropper": {
|
||||||
|
"cancel": "Відмінити",
|
||||||
|
"save_without_cropping": "Зберегти не обрізаючи",
|
||||||
|
"crop_picture": "Обрізати малюнок",
|
||||||
|
"save": "Зберегти"
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,7 +22,7 @@
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"apply": "应用",
|
"apply": "应用",
|
||||||
"submit": "提交",
|
"submit": "发送",
|
||||||
"more": "更多",
|
"more": "更多",
|
||||||
"generic_error": "发生了一个错误",
|
"generic_error": "发生了一个错误",
|
||||||
"optional": "可选",
|
"optional": "可选",
|
||||||
|
@ -297,7 +297,7 @@
|
||||||
"hide_follows_description": "不要显示我所关注的人",
|
"hide_follows_description": "不要显示我所关注的人",
|
||||||
"hide_followers_description": "不要显示关注我的人",
|
"hide_followers_description": "不要显示关注我的人",
|
||||||
"show_admin_badge": "显示管理徽章",
|
"show_admin_badge": "显示管理徽章",
|
||||||
"show_moderator_badge": "显示版主徽章",
|
"show_moderator_badge": "在我的个人资料中显示监察员标志",
|
||||||
"nsfw_clickthrough": "将不和谐附件隐藏,点击才能打开",
|
"nsfw_clickthrough": "将不和谐附件隐藏,点击才能打开",
|
||||||
"oauth_tokens": "OAuth令牌",
|
"oauth_tokens": "OAuth令牌",
|
||||||
"token": "令牌",
|
"token": "令牌",
|
||||||
|
@ -655,8 +655,8 @@
|
||||||
"moderation": "权限",
|
"moderation": "权限",
|
||||||
"grant_admin": "赋予管理权限",
|
"grant_admin": "赋予管理权限",
|
||||||
"revoke_admin": "撤销管理权限",
|
"revoke_admin": "撤销管理权限",
|
||||||
"grant_moderator": "赋予版主权限",
|
"grant_moderator": "赋予监察员权限",
|
||||||
"revoke_moderator": "撤销版主权限",
|
"revoke_moderator": "撤销监察员权限",
|
||||||
"activate_account": "激活账号",
|
"activate_account": "激活账号",
|
||||||
"deactivate_account": "关闭账号",
|
"deactivate_account": "关闭账号",
|
||||||
"delete_account": "删除账号",
|
"delete_account": "删除账号",
|
||||||
|
@ -683,7 +683,7 @@
|
||||||
},
|
},
|
||||||
"user_reporting": {
|
"user_reporting": {
|
||||||
"title": "报告 {0}",
|
"title": "报告 {0}",
|
||||||
"add_comment_description": "此报告会发送给您的实例管理员。您可以在下面提供更多详细信息解释报告的缘由:",
|
"add_comment_description": "此报告会发送给您的实例监察员。您可以在下面提供更多详细信息解释报告的缘由:",
|
||||||
"additional_comments": "其它信息",
|
"additional_comments": "其它信息",
|
||||||
"forward_description": "这个账号是从另外一个服务器。同时发送一个副本到那里?",
|
"forward_description": "这个账号是从另外一个服务器。同时发送一个副本到那里?",
|
||||||
"forward_to": "转发 {0}",
|
"forward_to": "转发 {0}",
|
||||||
|
|
|
@ -39,8 +39,7 @@ const emptyNotifications = () => ({
|
||||||
minId: Number.POSITIVE_INFINITY,
|
minId: Number.POSITIVE_INFINITY,
|
||||||
data: [],
|
data: [],
|
||||||
idStore: {},
|
idStore: {},
|
||||||
loading: false,
|
loading: false
|
||||||
error: false
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export const defaultState = () => ({
|
export const defaultState = () => ({
|
||||||
|
@ -50,8 +49,6 @@ export const defaultState = () => ({
|
||||||
maxId: 0,
|
maxId: 0,
|
||||||
notifications: emptyNotifications(),
|
notifications: emptyNotifications(),
|
||||||
favorites: new Set(),
|
favorites: new Set(),
|
||||||
error: false,
|
|
||||||
errorData: null,
|
|
||||||
timelines: {
|
timelines: {
|
||||||
mentions: emptyTl(),
|
mentions: emptyTl(),
|
||||||
public: emptyTl(),
|
public: emptyTl(),
|
||||||
|
@ -462,18 +459,9 @@ export const mutations = {
|
||||||
const newStatus = state.allStatusesObject[id]
|
const newStatus = state.allStatusesObject[id]
|
||||||
newStatus.nsfw = nsfw
|
newStatus.nsfw = nsfw
|
||||||
},
|
},
|
||||||
setError (state, { value }) {
|
|
||||||
state.error = value
|
|
||||||
},
|
|
||||||
setErrorData (state, { value }) {
|
|
||||||
state.errorData = value
|
|
||||||
},
|
|
||||||
setNotificationsLoading (state, { value }) {
|
setNotificationsLoading (state, { value }) {
|
||||||
state.notifications.loading = value
|
state.notifications.loading = value
|
||||||
},
|
},
|
||||||
setNotificationsError (state, { value }) {
|
|
||||||
state.notifications.error = value
|
|
||||||
},
|
|
||||||
setNotificationsSilence (state, { value }) {
|
setNotificationsSilence (state, { value }) {
|
||||||
state.notifications.desktopNotificationSilence = value
|
state.notifications.desktopNotificationSilence = value
|
||||||
},
|
},
|
||||||
|
@ -588,18 +576,9 @@ const statuses = {
|
||||||
}
|
}
|
||||||
commit('addNewNotifications', { dispatch, notifications, older, rootGetters, newNotificationSideEffects })
|
commit('addNewNotifications', { dispatch, notifications, older, rootGetters, newNotificationSideEffects })
|
||||||
},
|
},
|
||||||
setError ({ rootState, commit }, { value }) {
|
|
||||||
commit('setError', { value })
|
|
||||||
},
|
|
||||||
setErrorData ({ rootState, commit }, { value }) {
|
|
||||||
commit('setErrorData', { value })
|
|
||||||
},
|
|
||||||
setNotificationsLoading ({ rootState, commit }, { value }) {
|
setNotificationsLoading ({ rootState, commit }, { value }) {
|
||||||
commit('setNotificationsLoading', { value })
|
commit('setNotificationsLoading', { value })
|
||||||
},
|
},
|
||||||
setNotificationsError ({ rootState, commit }, { value }) {
|
|
||||||
commit('setNotificationsError', { value })
|
|
||||||
},
|
|
||||||
setNotificationsSilence ({ rootState, commit }, { value }) {
|
setNotificationsSilence ({ rootState, commit }, { value }) {
|
||||||
commit('setNotificationsSilence', { value })
|
commit('setNotificationsSilence', { value })
|
||||||
},
|
},
|
||||||
|
|
|
@ -137,11 +137,11 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
saveFriendIds (state, { id, friendIds }) {
|
saveFriendIds (state, { id, friendIds }) {
|
||||||
const user = state.usersObject[id]
|
const user = state.usersObject[id]
|
||||||
user.friendIds = uniq(concat(user.friendIds, friendIds))
|
user.friendIds = uniq(concat(user.friendIds || [], friendIds))
|
||||||
},
|
},
|
||||||
saveFollowerIds (state, { id, followerIds }) {
|
saveFollowerIds (state, { id, followerIds }) {
|
||||||
const user = state.usersObject[id]
|
const user = state.usersObject[id]
|
||||||
user.followerIds = uniq(concat(user.followerIds, followerIds))
|
user.followerIds = uniq(concat(user.followerIds || [], followerIds))
|
||||||
},
|
},
|
||||||
// Because frontend doesn't have a reason to keep these stuff in memory
|
// Because frontend doesn't have a reason to keep these stuff in memory
|
||||||
// outside of viewing someones user profile.
|
// outside of viewing someones user profile.
|
||||||
|
@ -202,7 +202,9 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
setPinnedToUser (state, status) {
|
setPinnedToUser (state, status) {
|
||||||
const user = state.usersObject[status.user.id]
|
const user = state.usersObject[status.user.id]
|
||||||
|
user.pinnedStatusIds = user.pinnedStatusIds || []
|
||||||
const index = user.pinnedStatusIds.indexOf(status.id)
|
const index = user.pinnedStatusIds.indexOf(status.id)
|
||||||
|
|
||||||
if (status.pinned && index === -1) {
|
if (status.pinned && index === -1) {
|
||||||
user.pinnedStatusIds.push(status.id)
|
user.pinnedStatusIds.push(status.id)
|
||||||
} else if (!status.pinned && index !== -1) {
|
} else if (!status.pinned && index !== -1) {
|
||||||
|
|
|
@ -560,7 +560,7 @@ const fetchTimeline = ({
|
||||||
})
|
})
|
||||||
.then((data) => data.json())
|
.then((data) => data.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
if (!data.error) {
|
if (!data.errors) {
|
||||||
return { data: data.map(isNotifications ? parseNotification : parseStatus), pagination }
|
return { data: data.map(isNotifications ? parseNotification : parseStatus), pagination }
|
||||||
} else {
|
} else {
|
||||||
data.status = status
|
data.status = status
|
||||||
|
|
|
@ -21,7 +21,7 @@ const clear = (storage) => {
|
||||||
failedMessageIds.push(message.id)
|
failedMessageIds.push(message.id)
|
||||||
} else {
|
} else {
|
||||||
delete storage.idIndex[message.id]
|
delete storage.idIndex[message.id]
|
||||||
delete storage.idempotencyKeyIndex[message.id]
|
delete storage.idempotencyKeyIndex[message.idempotency_key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,15 @@ import escape from 'escape-html'
|
||||||
import parseLinkHeader from 'parse-link-header'
|
import parseLinkHeader from 'parse-link-header'
|
||||||
import { isStatusNotification } from '../notification_utils/notification_utils.js'
|
import { isStatusNotification } from '../notification_utils/notification_utils.js'
|
||||||
|
|
||||||
|
/** NOTICE! **
|
||||||
|
* Do not initialize UI-generated data here.
|
||||||
|
* It will override existing data.
|
||||||
|
*
|
||||||
|
* i.e. user.pinnedStatusIds was set to [] here
|
||||||
|
* UI code would update it with data but upon next user fetch
|
||||||
|
* it would be reverted back to []
|
||||||
|
*/
|
||||||
|
|
||||||
const qvitterStatusType = (status) => {
|
const qvitterStatusType = (status) => {
|
||||||
if (status.is_post_verb) {
|
if (status.is_post_verb) {
|
||||||
return 'status'
|
return 'status'
|
||||||
|
@ -173,9 +182,6 @@ export const parseUser = (data) => {
|
||||||
output.locked = data.locked
|
output.locked = data.locked
|
||||||
output.followers_count = data.followers_count
|
output.followers_count = data.followers_count
|
||||||
output.statuses_count = data.statuses_count
|
output.statuses_count = data.statuses_count
|
||||||
output.friendIds = []
|
|
||||||
output.followerIds = []
|
|
||||||
output.pinnedStatusIds = []
|
|
||||||
|
|
||||||
if (data.pleroma) {
|
if (data.pleroma) {
|
||||||
output.follow_request_count = data.pleroma.follow_request_count
|
output.follow_request_count = data.pleroma.follow_request_count
|
||||||
|
|
61
src/services/favicon_service/favicon_service.js
Normal file
61
src/services/favicon_service/favicon_service.js
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
import { find } from 'lodash'
|
||||||
|
|
||||||
|
const createFaviconService = () => {
|
||||||
|
let favimg, favcanvas, favcontext, favicon
|
||||||
|
const faviconWidth = 128
|
||||||
|
const faviconHeight = 128
|
||||||
|
const badgeRadius = 32
|
||||||
|
|
||||||
|
const initFaviconService = () => {
|
||||||
|
const nodes = document.getElementsByTagName('link')
|
||||||
|
favicon = find(nodes, node => node.rel === 'icon')
|
||||||
|
if (favicon) {
|
||||||
|
favcanvas = document.createElement('canvas')
|
||||||
|
favcanvas.width = faviconWidth
|
||||||
|
favcanvas.height = faviconHeight
|
||||||
|
favimg = new Image()
|
||||||
|
favimg.src = favicon.href
|
||||||
|
favcontext = favcanvas.getContext('2d')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const isImageLoaded = (img) => img.complete && img.naturalHeight !== 0
|
||||||
|
|
||||||
|
const clearFaviconBadge = () => {
|
||||||
|
if (!favimg || !favcontext || !favicon) return
|
||||||
|
|
||||||
|
favcontext.clearRect(0, 0, faviconWidth, faviconHeight)
|
||||||
|
if (isImageLoaded(favimg)) {
|
||||||
|
favcontext.drawImage(favimg, 0, 0, favimg.width, favimg.height, 0, 0, faviconWidth, faviconHeight)
|
||||||
|
}
|
||||||
|
favicon.href = favcanvas.toDataURL('image/png')
|
||||||
|
}
|
||||||
|
|
||||||
|
const drawFaviconBadge = () => {
|
||||||
|
if (!favimg || !favcontext || !favcontext) return
|
||||||
|
|
||||||
|
clearFaviconBadge()
|
||||||
|
|
||||||
|
const style = getComputedStyle(document.body)
|
||||||
|
const badgeColor = `${style.getPropertyValue('--badgeNotification') || 'rgb(240, 100, 100)'}`
|
||||||
|
|
||||||
|
if (isImageLoaded(favimg)) {
|
||||||
|
favcontext.drawImage(favimg, 0, 0, favimg.width, favimg.height, 0, 0, faviconWidth, faviconHeight)
|
||||||
|
}
|
||||||
|
favcontext.fillStyle = badgeColor
|
||||||
|
favcontext.beginPath()
|
||||||
|
favcontext.arc(faviconWidth - badgeRadius, badgeRadius, badgeRadius, 0, 2 * Math.PI, false)
|
||||||
|
favcontext.fill()
|
||||||
|
favicon.href = favcanvas.toDataURL('image/png')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
initFaviconService,
|
||||||
|
clearFaviconBadge,
|
||||||
|
drawFaviconBadge
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const FaviconService = createFaviconService()
|
||||||
|
|
||||||
|
export default FaviconService
|
|
@ -2,7 +2,6 @@ import apiService from '../api/api.service.js'
|
||||||
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||||
|
|
||||||
const update = ({ store, notifications, older }) => {
|
const update = ({ store, notifications, older }) => {
|
||||||
store.dispatch('setNotificationsError', { value: false })
|
|
||||||
store.dispatch('addNewNotifications', { notifications, older })
|
store.dispatch('addNewNotifications', { notifications, older })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,11 +46,22 @@ const fetchAndUpdate = ({ store, credentials, older = false }) => {
|
||||||
|
|
||||||
const fetchNotifications = ({ store, args, older }) => {
|
const fetchNotifications = ({ store, args, older }) => {
|
||||||
return apiService.fetchTimeline(args)
|
return apiService.fetchTimeline(args)
|
||||||
.then(({ data: notifications }) => {
|
.then((response) => {
|
||||||
|
if (response.errors) {
|
||||||
|
throw new Error(`${response.status} ${response.statusText}`)
|
||||||
|
}
|
||||||
|
const notifications = response.data
|
||||||
update({ store, notifications, older })
|
update({ store, notifications, older })
|
||||||
return notifications
|
return notifications
|
||||||
}, () => store.dispatch('setNotificationsError', { value: true }))
|
})
|
||||||
.catch(() => store.dispatch('setNotificationsError', { value: true }))
|
.catch((error) => {
|
||||||
|
store.dispatch('pushGlobalNotice', {
|
||||||
|
level: 'error',
|
||||||
|
messageKey: 'notifications.error',
|
||||||
|
messageArgs: [error.message],
|
||||||
|
timeout: 5000
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const startFetching = ({ credentials, store }) => {
|
const startFetching = ({ credentials, store }) => {
|
||||||
|
|
|
@ -6,9 +6,6 @@ import { promiseInterval } from '../promise_interval/promise_interval.js'
|
||||||
const update = ({ store, statuses, timeline, showImmediately, userId, pagination }) => {
|
const update = ({ store, statuses, timeline, showImmediately, userId, pagination }) => {
|
||||||
const ccTimeline = camelCase(timeline)
|
const ccTimeline = camelCase(timeline)
|
||||||
|
|
||||||
store.dispatch('setError', { value: false })
|
|
||||||
store.dispatch('setErrorData', { value: null })
|
|
||||||
|
|
||||||
store.dispatch('addNewStatuses', {
|
store.dispatch('addNewStatuses', {
|
||||||
timeline: ccTimeline,
|
timeline: ccTimeline,
|
||||||
userId,
|
userId,
|
||||||
|
@ -52,9 +49,8 @@ const fetchAndUpdate = ({
|
||||||
|
|
||||||
return apiService.fetchTimeline(args)
|
return apiService.fetchTimeline(args)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.error) {
|
if (response.errors) {
|
||||||
store.dispatch('setErrorData', { value: response })
|
throw new Error(`${response.status} ${response.statusText}`)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const { data: statuses, pagination } = response
|
const { data: statuses, pagination } = response
|
||||||
|
@ -63,7 +59,15 @@ const fetchAndUpdate = ({
|
||||||
}
|
}
|
||||||
update({ store, statuses, timeline, showImmediately, userId, pagination })
|
update({ store, statuses, timeline, showImmediately, userId, pagination })
|
||||||
return { statuses, pagination }
|
return { statuses, pagination }
|
||||||
}, () => store.dispatch('setError', { value: true }))
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
store.dispatch('pushGlobalNotice', {
|
||||||
|
level: 'error',
|
||||||
|
messageKey: 'timeline.error',
|
||||||
|
messageArgs: [error.message],
|
||||||
|
timeout: 5000
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, tag = false }) => {
|
const startFetching = ({ timeline = 'friends', credentials, store, userId = false, tag = false }) => {
|
||||||
|
|
2396
static/emoji.json
2396
static/emoji.json
File diff suppressed because it is too large
Load diff
|
@ -8,8 +8,7 @@ const localVue = createLocalVue()
|
||||||
localVue.use(Vuex)
|
localVue.use(Vuex)
|
||||||
|
|
||||||
const mutations = {
|
const mutations = {
|
||||||
clearTimeline: () => {},
|
clearTimeline: () => {}
|
||||||
setError: () => {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
|
|
67
tools/emoji_merger.js
Normal file
67
tools/emoji_merger.js
Normal 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
4036
tools/emojis.json
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue