resolve merge conflicts

This commit is contained in:
Absturztaube 2022-08-28 10:34:00 +02:00
commit dccf5ed1c0
68 changed files with 1560 additions and 170 deletions

View file

@ -1,5 +1,7 @@
# Pleroma-FE
![English OK](https://img.shields.io/badge/English-OK-blueviolet) ![日本語OK](https://img.shields.io/badge/%E6%97%A5%E6%9C%AC%E8%AA%9E-OK-blueviolet)
This is a fork of Pleroma-FE from the Pleroma project, with support for new Akkoma features such as:
- MFM support via [marked-mfm](https://akkoma.dev/sfr/marked-mfm)
- Custom emoji reactions

View file

@ -15,6 +15,7 @@
<body class="hidden">
<noscript>To use Pleroma, please enable JavaScript.</noscript>
<div id="app"></div>
<div id="modal"></div>
<!-- built files will be auto injected -->
<script type="text/javascript" src="/instance/pleroma-mod-loader.js"></script>
</body>

View file

@ -19,7 +19,7 @@
"@babel/runtime": "7.17.8",
"@chenfengyuan/vue-qrcode": "2.0.0",
"@fortawesome/fontawesome-svg-core": "1.3.0",
"@fortawesome/free-regular-svg-icons": "5.15.4",
"@fortawesome/free-regular-svg-icons": "^6.1.2",
"@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/vue-fontawesome": "3.0.1",
"@kazvmoe-infra/pinch-zoom-element": "1.2.0",

View file

@ -59,7 +59,7 @@
<UserReportingModal />
<PostStatusModal />
<SettingsModal />
<div id="modal" />
<UpdateNotification />
<GlobalNoticeList />
</div>
</template>

View file

@ -1,3 +1,4 @@
import Cookies from 'js-cookie'
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import vClickOutside from 'click-outside-vue3'
@ -50,6 +51,20 @@ const preloadFetch = async (request) => {
}
}
const resolveLanguage = (instanceLanguages) => {
// First language in navigator.languages that is listed as an instance language
// falls back to first instance language
const navigatorLanguages = navigator.languages.map((x) => x.split('-')[0])
for (const navLanguage of navigatorLanguages) {
if (instanceLanguages.includes(navLanguage)) {
return navLanguage
}
}
return instanceLanguages[0]
}
const getInstanceConfig = async ({ store }) => {
try {
const res = await preloadFetch('/api/v1/instance')
@ -60,6 +75,10 @@ const getInstanceConfig = async ({ store }) => {
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
// don't override cookie if set
if (!Cookies.get('userLanguage')) {
store.dispatch('setOption', { name: 'interfaceLanguage', value: resolveLanguage(data.languages) })
}
if (vapidPublicKey) {
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
@ -126,6 +145,11 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('hideBotIndication')
copyInstanceOption('hideUserStats')
copyInstanceOption('hideFilteredStatuses')
copyInstanceOption('hideSiteName')
copyInstanceOption('hideSiteFavicon')
copyInstanceOption('showWiderShortcuts')
copyInstanceOption('showNavShortcuts')
copyInstanceOption('showPanelNavShortcuts')
copyInstanceOption('logo')
store.dispatch('setInstanceOption', {
@ -156,6 +180,7 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('alwaysShowSubjectInput')
copyInstanceOption('showFeaturesPanel')
copyInstanceOption('hideSitename')
copyInstanceOption('renderMisskeyMarkdown')
copyInstanceOption('sidebarRight')
return store.dispatch('setTheme', config['theme'])
@ -287,6 +312,7 @@ const getNodeInfo = async ({ store }) => {
})
store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation })
store.dispatch('setInstanceOption', { name: 'localBubbleInstances', value: metadata.localBubbleInstances })
store.dispatch('setInstanceOption', {
name: 'federating',
value: typeof federation.enabled === 'undefined'
@ -378,8 +404,9 @@ const afterStoreSetup = async ({ store, i18n }) => {
routes: routes(store),
scrollBehavior: (to, _from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) {
return false
return {}
}
return savedPosition || { left: 0, top: 0 }
}
})

View file

@ -58,7 +58,7 @@ export default (store) => {
component: RemoteUserResolver,
beforeEnter: validateAuthenticatedRoute
},
{ name: 'external-user-profile', path: '/users/:id', component: UserProfile },
{ name: 'external-user-profile', path: '/users/:id', component: UserProfile, meta: { dontScroll: true } },
{ name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute },
{ name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute },
{ name: 'registration', path: '/registration', component: Registration },
@ -75,7 +75,7 @@ export default (store) => {
{ name: 'list-timeline', path: '/lists/:id', component: ListTimeline },
{ name: 'list-edit', path: '/lists/:id/edit', component: ListEdit },
{ name: 'announcements', path: '/announcements', component: AnnouncementsPage },
{ name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile }
{ name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile, meta: { dontScroll: true } }
]
return routes

View file

@ -3,6 +3,7 @@ import FeaturesPanel from '../features_panel/features_panel.vue'
import TermsOfServicePanel from '../terms_of_service_panel/terms_of_service_panel.vue'
import StaffPanel from '../staff_panel/staff_panel.vue'
import MRFTransparencyPanel from '../mrf_transparency_panel/mrf_transparency_panel.vue'
import LocalBubblePanel from '../local_bubble_panel/local_bubble_panel.vue'
const About = {
components: {
@ -10,7 +11,8 @@ const About = {
FeaturesPanel,
TermsOfServicePanel,
StaffPanel,
MRFTransparencyPanel
MRFTransparencyPanel,
LocalBubblePanel
},
computed: {
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },

View file

@ -3,6 +3,7 @@
<instance-specific-panel v-if="showInstanceSpecificPanel" />
<staff-panel />
<terms-of-service-panel />
<LocalBubblePanel />
<MRFTransparencyPanel />
<features-panel v-if="showFeaturesPanel" />
</div>

View file

@ -1,6 +1,8 @@
import ProgressButton from '../progress_button/progress_button.vue'
import Popover from '../popover/popover.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { mapState } from 'vuex'
import {
faEllipsisV
} from '@fortawesome/free-solid-svg-icons'
@ -14,13 +16,22 @@ const AccountActions = {
'user', 'relationship'
],
data () {
return { }
return {
showingConfirmBlock: false
}
},
components: {
ProgressButton,
Popover
Popover,
ConfirmModal
},
methods: {
showConfirmBlock () {
this.showingConfirmBlock = true
},
hideConfirmBlock () {
this.showingConfirmBlock = false
},
showRepeats () {
this.$store.dispatch('showReblogs', this.user.id)
},
@ -28,7 +39,15 @@ const AccountActions = {
this.$store.dispatch('hideReblogs', this.user.id)
},
blockUser () {
if (!this.shouldConfirmBlock) {
this.doBlockUser()
} else {
this.showConfirmBlock()
}
},
doBlockUser () {
this.$store.dispatch('blockUser', this.user.id)
this.hideConfirmBlock()
},
unblockUser () {
this.$store.dispatch('unblockUser', this.user.id)
@ -36,6 +55,14 @@ const AccountActions = {
reportUser () {
this.$store.dispatch('openUserReportingModal', { userId: this.user.id })
}
},
computed: {
shouldConfirmBlock () {
return this.$store.getters.mergedConfig.modalOnBlock
},
...mapState({
pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable
})
}
}

View file

@ -59,6 +59,27 @@
</button>
</template>
</Popover>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmBlock"
:title="$t('user_card.block_confirm_title')"
:confirm-text="$t('user_card.block_confirm_accept_button')"
:cancel-text="$t('user_card.block_confirm_cancel_button')"
@accepted="doBlockUser"
@cancelled="hideConfirmBlock"
>
<i18n-t
keypath="user_card.block_confirm"
tag="span"
>
<template v-slot:user>
<span
v-text="user.screen_name_ui"
/>
</template>
</i18n-t>
</confirm-modal>
</teleport>
</div>
</template>

View file

@ -0,0 +1,37 @@
import DialogModal from '../dialog_modal/dialog_modal.vue'
/**
* This component emits the following events:
* cancelled, emitted when the action should not be performed;
* accepted, emitted when the action should be performed;
*
* The caller should close this dialog after receiving any of the two events.
*/
const ConfirmModal = {
components: {
DialogModal
},
props: {
title: {
type: String
},
cancelText: {
type: String
},
confirmText: {
type: String
}
},
computed: {
},
methods: {
onCancel () {
this.$emit('cancelled')
},
onAccept () {
this.$emit('accepted')
}
}
}
export default ConfirmModal

View file

@ -0,0 +1,39 @@
<template>
<dialog-modal
v-body-scroll-lock="true"
class="confirm-modal"
:on-cancel="onCancel"
>
<template #header>
<span v-text="title" />
</template>
<slot />
<template #footer>
<button
class="btn button-default"
@click.prevent="onCancel"
v-text="cancelText"
/>
<button
class="btn button-default button-positive"
@click.prevent="onAccept"
v-text="confirmText"
/>
</template>
</dialog-modal>
</template>
<style lang="scss" scoped>
@import '../../_variables';
.confirm-modal {
.button-positive {
border: 3px solid var(--accent, $fallback--link);
border-radius: var(--btnRadius, $fallback--btnRadius);
}
}
</style>
<script src="./confirm_modal.js"></script>

View file

@ -1,16 +1,21 @@
import SearchBar from 'components/search_bar/search_bar.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faSignInAlt,
faSignOutAlt,
faHome,
faComments,
faBell,
faUserPlus,
faBullhorn,
faSearch,
faTachometerAlt,
faCog,
faGlobe,
faBolt,
faUsers,
faCommentMedical,
faBookmark,
faInfoCircle
} from '@fortawesome/free-solid-svg-icons'
@ -19,18 +24,23 @@ library.add(
faSignOutAlt,
faHome,
faComments,
faBell,
faUserPlus,
faBullhorn,
faSearch,
faTachometerAlt,
faCog,
faGlobe,
faBolt,
faUsers,
faCommentMedical,
faBookmark,
faInfoCircle
)
export default {
components: {
SearchBar
SearchBar,
ConfirmModal
},
data: () => ({
searchBarHidden: true,
@ -40,7 +50,8 @@ export default {
window.CSS.supports('-moz-mask-size', 'contain') ||
window.CSS.supports('-ms-mask-size', 'contain') ||
window.CSS.supports('-o-mask-size', 'contain')
)
),
showingConfirmLogout: false
}),
computed: {
enableMask () { return this.supportsMask && this.$store.state.instance.logoMask },
@ -65,20 +76,34 @@ export default {
})
},
logo () { return this.$store.state.instance.logo },
mergedConfig () {
return this.$store.getters.mergedConfig
},
sitename () { return this.$store.state.instance.name },
showNavShortcuts () {
return this.mergedConfig.showNavShortcuts
},
showWiderShortcuts () {
return this.mergedConfig.showWiderShortcuts
},
hideSiteFavicon () {
return this.mergedConfig.hideSiteFavicon
},
hideSiteName () {
return this.mergedConfig.hideSiteName
},
hideSitename () { return this.$store.state.instance.hideSitename },
logoLeft () { return this.$store.state.instance.logoLeft },
currentUser () { return this.$store.state.users.currentUser },
privateMode () { return this.$store.state.instance.private }
privateMode () { return this.$store.state.instance.private },
shouldConfirmLogout () {
return this.$store.getters.mergedConfig.modalOnLogout
}
},
methods: {
scrollToTop () {
window.scrollTo(0, 0)
},
logout () {
this.$router.replace('/main/public')
this.$store.dispatch('logout')
},
onSearchBarToggled (hidden) {
this.searchBarHidden = hidden
},

View file

@ -15,16 +15,16 @@
display: grid;
grid-template-rows: var(--navbar-height);
grid-template-columns: 2fr auto 2fr;
grid-template-areas: "sitename logo actions";
grid-template-areas: "nav-left logo actions";
box-sizing: border-box;
padding: 0 1.2em;
margin: auto;
max-width: 980px;
max-width: 1110px;
}
&.-logoLeft .inner-nav {
grid-template-columns: auto 2fr 2fr;
grid-template-areas: "logo sitename actions";
grid-template-areas: "logo nav-left actions";
}
.button-default {
@ -84,14 +84,21 @@
}
.nav-icon {
margin-left: 1em;
margin-left: 0.2em;
width: 2em;
height: 100%;
font-size: 130%;
text-align: center;
&-logout {
margin-left: 2em;
&.router-link-active {
font-size: 1.2em;
margin-top: 0.05em;
.svg-inline--fa {
font-weight: bolder;
color: $fallback--text;
color: var(--selectedMenuText, $fallback--text);
--lightText: var(--selectedMenuLightText, $fallback--lightText);
}
}
.svg-inline--fa {
@ -100,8 +107,25 @@
}
}
.sitename {
grid-area: sitename;
.-wide {
.nav-icon {
margin-left: 0.7em;
}
}
.left {
padding-left: 5px;
display: flex;
}
.nav-left-wrapper {
grid-area: nav-left;
.favicon {
height: 28px;
vertical-align: middle;
padding-right: 5px;
}
}
.actions {

View file

@ -5,16 +5,79 @@
:class="{ '-logoLeft': logoLeft }"
@click="scrollToTop()"
>
<div class="inner-nav">
<div class="item sitename">
<div
class="inner-nav"
:class="{ '-wide': showWiderShortcuts }"
>
<div class="item nav-left-wrapper">
<router-link
v-if="!hideSitename"
class="site-name"
class="site-brand"
:to="{ name: 'root' }"
active-class="home"
>
{{ sitename }}
<img
v-if="!hideSiteFavicon"
class="favicon"
src="/favicon.png"
>
<span
v-if="!hideSiteName"
class="site-name"
>
{{ sitename }}
</span>
</router-link>
<div
v-if="(currentUser || !privateMode) && showNavShortcuts"
class="nav-items left"
>
<router-link
v-if="currentUser"
:to="{ name: 'friends' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="home"
:title="$t('nav.home_timeline')"
/>
</router-link>
<router-link
:to="{ name: 'public-timeline' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="users"
:title="$t('nav.public_tl')"
/>
</router-link>
<router-link
v-if="currentUser"
:to="{ name: 'bubble-timeline' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="circle"
:title="$t('nav.bubble_timeline')"
/>
</router-link>
<router-link
:to="{ name: 'public-external-timeline' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="globe"
:title="$t('nav.twkn')"
/>
</router-link>
</div>
</div>
<router-link
class="logo"
@ -36,6 +99,47 @@
@toggled="onSearchBarToggled"
@click.stop
/>
<div
v-if="(currentUser || !privateMode) && showNavShortcuts"
class="nav-items right"
>
<router-link
class="nav-icon"
v-if="currentUser"
:to="{ name: 'interactions', params: { username: currentUser.screen_name } }"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="bolt"
:title="$t('nav.interactions')"
/>
</router-link>
<router-link
v-if="currentUser"
:to="{ name: 'lists' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="list"
:title="$t('nav.lists')"
/>
</router-link>
<router-link
v-if="currentUser"
:to="{ name: 'bookmarks' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="bookmark"
:title="$t('nav.bookmarks')"
/>
</router-link>
</div>
<button
class="button-unstyled nav-icon"
@click.stop="openSettingsModal"
@ -61,20 +165,20 @@
:title="$t('nav.administration')"
/>
</a>
<button
v-if="currentUser"
class="button-unstyled nav-icon nav-icon-logout"
@click.prevent="logout"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="sign-out-alt"
:title="$t('login.logout')"
/>
</button>
</div>
</div>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmLogout"
:title="$t('login.logout_confirm_title')"
:confirm-text="$t('login.logout_confirm_accept_button')"
:cancel-text="$t('login.logout_confirm_cancel_button')"
@accepted="doLogout"
@cancelled="hideConfirmLogout"
>
{{ $t('login.logout_confirm') }}
</confirm-modal>
</teleport>
</nav>
</template>
<script src="./desktop_nav.js"></script>

View file

@ -39,7 +39,7 @@
right: 0;
top: 0;
background: rgba(27,31,35,.5);
z-index: 99;
z-index: 2000;
}
}
@ -51,7 +51,7 @@
margin: 15vh auto;
position: fixed;
transform: translateX(-50%);
z-index: 999;
z-index: 2001;
cursor: default;
display: block;
background-color: $fallback--bg;

View file

@ -491,11 +491,10 @@ const EmojiInput = {
},
setPlacement (container, target, offsetBottom) {
if (!container || !target) return
target.style.top = offsetBottom + 'px'
target.style.bottom = 'auto'
if (this.placement === 'top' || (this.placement === 'auto' && this.overflowsBottom(container))) {
if (this.placement === 'bottom' || (this.placement === 'auto' && !this.overflowsBottom(container))) {
target.style.top = offsetBottom + 'px'
target.style.bottom = 'auto'
} else {
target.style.top = 'auto'
target.style.bottom = this.input.offsetHeight + 'px'
}

View file

@ -27,7 +27,11 @@ const EmojiReactions = {
},
accountsForEmoji () {
return this.status.emoji_reactions.reduce((acc, reaction) => {
acc[reaction.name] = reaction.accounts || []
if (reaction.url) {
acc[reaction.url] = reaction.accounts || []
} else {
acc[reaction.name] = reaction.accounts || []
}
return acc
}, {})
},
@ -42,6 +46,14 @@ const EmojiReactions = {
reactedWith (emoji) {
return this.status.emoji_reactions.find(r => r.name === emoji).me
},
isLocalReaction (emojiUrl) {
if (!emojiUrl) return true
const reacted = this.accountsForEmoji[emojiUrl]
if (reacted.length === 0) {
return true
}
return reacted[0].is_local
},
fetchEmojiReactionsByIfMissing () {
const hasNoAccounts = this.status.emoji_reactions.find(r => !r.accounts)
if (hasNoAccounts) {

View file

@ -2,12 +2,13 @@
<div class="emoji-reactions">
<UserListPopover
v-for="(reaction) in emojiReactions"
:key="reaction.name"
:users="accountsForEmoji[reaction.name]"
:key="reaction.url || reaction.name"
:users="accountsForEmoji[reaction.url || reaction.name]"
>
<button
class="emoji-reaction btn button-default"
:class="{ 'picked-reaction': reactedWith(reaction.name), 'not-clickable': !loggedIn }"
:disabled="!isLocalReaction(reaction.url)"
@click="emojiOnClick(reaction.name, $event)"
@mouseenter="fetchEmojiReactionsByIfMissing()"
>

View file

@ -1,4 +1,5 @@
import Popover from '../popover/popover.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faEllipsisH,
@ -25,15 +26,35 @@ library.add(
)
const ExtraButtons = {
props: [ 'status' ],
components: { Popover },
props: ['status'],
components: {
Popover,
ConfirmModal
},
data () {
return {
expanded: false,
showingDeleteDialog: false
}
},
methods: {
deleteStatus () {
const confirmed = window.confirm(this.$t('status.delete_confirm'))
if (confirmed) {
this.$store.dispatch('deleteStatus', { id: this.status.id })
if (this.shouldConfirmDelete) {
this.showDeleteStatusConfirmDialog()
} else {
this.doDeleteStatus()
}
},
doDeleteStatus () {
this.$store.dispatch('deleteStatus', { id: this.status.id })
this.hideDeleteStatusConfirmDialog()
},
showDeleteStatusConfirmDialog () {
this.showingDeleteDialog = true
},
hideDeleteStatusConfirmDialog () {
this.showingDeleteDialog = false
},
pinStatus () {
this.$store.dispatch('pinStatus', this.status.id)
.then(() => this.$emit('onSuccess'))
@ -91,6 +112,9 @@ const ExtraButtons = {
},
statusLink () {
return `${this.$store.state.instance.server}${this.$router.resolve({ name: 'conversation', params: { id: this.status.id } }).href}`
},
shouldConfirmDelete () {
return this.$store.getters.mergedConfig.modalOnDelete
}
}
}

View file

@ -125,6 +125,18 @@
icon="ellipsis-h"
/>
</button>
<teleport to="#modal">
<ConfirmModal
v-if="showingDeleteDialog"
:title="$t('status.delete_confirm_title')"
:cancel-text="$t('status.delete_confirm_cancel_button')"
:confirm-text="$t('status.delete_confirm_accept_button')"
@cancelled="hideDeleteStatusConfirmDialog"
@accepted="doDeleteStatus"
>
{{ $t('status.delete_confirm') }}
</ConfirmModal>
</teleport>
</template>
</Popover>
</template>

View file

@ -1,12 +1,20 @@
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
export default {
props: ['relationship', 'user', 'labelFollowing', 'buttonClass'],
components: {
ConfirmModal
},
data () {
return {
inProgress: false
inProgress: false,
showingConfirmUnfollow: false
}
},
computed: {
shouldConfirmUnfollow () {
return this.$store.getters.mergedConfig.modalOnUnfollow
},
isPressed () {
return this.inProgress || this.relationship.following
},
@ -35,6 +43,12 @@ export default {
}
},
methods: {
showConfirmUnfollow () {
this.showingConfirmUnfollow = true
},
hideConfirmUnfollow () {
this.showingConfirmUnfollow = false
},
onClick () {
this.relationship.following || this.relationship.requested ? this.unfollow() : this.follow()
},
@ -45,12 +59,21 @@ export default {
})
},
unfollow () {
if (this.shouldConfirmUnfollow) {
this.showConfirmUnfollow()
} else {
this.doUnfollow()
}
},
doUnfollow () {
const store = this.$store
this.inProgress = true
requestUnfollow(this.relationship.id, store).then(() => {
this.inProgress = false
store.commit('removeStatus', { timeline: 'friends', userId: this.relationship.id })
})
this.hideConfirmUnfollow()
}
}
}

View file

@ -7,6 +7,27 @@
@click="onClick"
>
{{ label }}
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmUnfollow"
:title="$t('user_card.unfollow_confirm_title')"
:confirm-text="$t('user_card.unfollow_confirm_accept_button')"
:cancel-text="$t('user_card.unfollow_confirm_cancel_button')"
@accepted="doUnfollow"
@cancelled="hideConfirmUnfollow"
>
<i18n-t
keypath="user_card.unfollow_confirm"
tag="span"
>
<template #user>
<span
v-text="user.screen_name_ui"
/>
</template>
</i18n-t>
</confirm-modal>
</teleport>
</button>
</template>

View file

@ -1,10 +1,18 @@
import BasicUserCard from '../basic_user_card/basic_user_card.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { notificationsFromStore } from '../../services/notification_utils/notification_utils.js'
const FollowRequestCard = {
props: ['user'],
components: {
BasicUserCard
BasicUserCard,
ConfirmModal
},
data () {
return {
showingApproveConfirmDialog: false,
showingDenyConfirmDialog: false
}
},
methods: {
findFollowRequestNotificationId () {
@ -13,7 +21,26 @@ const FollowRequestCard = {
)
return notif && notif.id
},
showApproveConfirmDialog () {
this.showingApproveConfirmDialog = true
},
hideApproveConfirmDialog () {
this.showingApproveConfirmDialog = false
},
showDenyConfirmDialog () {
this.showingDenyConfirmDialog = true
},
hideDenyConfirmDialog () {
this.showingDenyConfirmDialog = false
},
approveUser () {
if (this.shouldConfirmApprove) {
this.showApproveConfirmDialog()
} else {
this.doApprove()
}
},
doApprove () {
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
this.$store.dispatch('removeFollowRequest', this.user)
@ -25,14 +52,34 @@ const FollowRequestCard = {
notification.type = 'follow'
}
})
this.hideApproveConfirmDialog()
},
denyUser () {
if (this.shouldConfirmDeny) {
this.showDenyConfirmDialog()
} else {
this.doDeny()
}
},
doDeny () {
const notifId = this.findFollowRequestNotificationId()
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
.then(() => {
this.$store.dispatch('dismissNotificationLocal', { id: notifId })
this.$store.dispatch('removeFollowRequest', this.user)
})
this.hideDenyConfirmDialog()
}
},
computed: {
mergedConfig () {
return this.$store.getters.mergedConfig
},
shouldConfirmApprove () {
return this.mergedConfig.modalOnApproveFollow
},
shouldConfirmDeny () {
return this.mergedConfig.modalOnDenyFollow
}
}
}

View file

@ -14,6 +14,28 @@
{{ $t('user_card.deny') }}
</button>
</div>
<teleport to="#modal">
<confirm-modal
v-if="showingApproveConfirmDialog"
:title="$t('user_card.approve_confirm_title')"
:confirm-text="$t('user_card.approve_confirm_accept_button')"
:cancel-text="$t('user_card.approve_confirm_cancel_button')"
@accepted="doApprove"
@cancelled="hideApproveConfirmDialog"
>
{{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }}
</confirm-modal>
<confirm-modal
v-if="showingDenyConfirmDialog"
:title="$t('user_card.deny_confirm_title')"
:confirm-text="$t('user_card.deny_confirm_accept_button')"
:cancel-text="$t('user_card.deny_confirm_cancel_button')"
@accepted="doDeny"
@cancelled="hideDenyConfirmDialog"
>
{{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }}
</confirm-modal>
</teleport>
</basic-user-card>
</template>

View file

@ -1,5 +1,6 @@
<template>
<div>
<FAIcon icon="globe" /> {{ ' ' }}
<label for="interface-language-switcher">
{{ promptText }}
</label>

View file

@ -0,0 +1,12 @@
import { mapState } from 'vuex'
import { get } from 'lodash'
const LocalBubblePanel = {
computed: {
...mapState({
bubbleInstances: state => get(state, 'instance.localBubbleInstances')
})
}
}
export default LocalBubblePanel

View file

@ -0,0 +1,21 @@
.mrf-section {
margin: 1em;
table {
width:100%;
text-align: left;
padding-left:10px;
padding-bottom:20px;
th, td {
width: 180px;
max-width: 360px;
overflow: hidden;
vertical-align: text-top;
}
th+th, td+td {
width: auto;
}
}
}

View file

@ -0,0 +1,31 @@
<template>
<div
v-if="bubbleInstances"
class="bubble-panel"
>
<div class="panel panel-default base01-background">
<div class="panel-heading timeline-heading base02-background">
<div class="title">
{{ $t("about.bubble_instances") }}
</div>
</div>
<div class="panel-body">
<p>{{ $t("about.bubble_instances_description")}}:</p>
<ul>
<li
v-for="instance in bubbleInstances"
:key="instance"
v-text="instance"
/>
</ul>
</div>
</div>
</div>
</template>
<script src="./local_bubble_panel.js"></script>
<style lang="scss">
@import '../../_variables.scss';
@import './local_bubble_panel.scss';
</style>

View file

@ -1,7 +1,9 @@
import SideDrawer from '../side_drawer/side_drawer.vue'
import Notifications from '../notifications/notifications.vue'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
import GestureService from '../../services/gesture_service/gesture_service'
import { mapGetters } from 'vuex'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes,
@ -18,11 +20,13 @@ library.add(
const MobileNav = {
components: {
SideDrawer,
Notifications
Notifications,
ConfirmModal
},
data: () => ({
notificationsCloseGesture: undefined,
notificationsOpen: false
notificationsOpen: false,
showingConfirmLogout: false
}),
created () {
this.notificationsCloseGesture = GestureService.swipeGesture(
@ -41,8 +45,17 @@ const MobileNav = {
unseenNotificationsCount () {
return this.unseenNotifications.length
},
hideSitename () { return this.$store.state.instance.hideSitename },
sitename () { return this.$store.state.instance.name }
mergedConfig () {
return this.$store.getters.mergedConfig
},
hideSiteName () {
return this.mergedConfig.hideSiteName
},
sitename () { return this.$store.state.instance.name },
shouldConfirmLogout () {
return this.$store.getters.mergedConfig.modalOnLogout
},
...mapGetters(['unreadChatCount'])
},
methods: {
toggleMobileSidebar () {
@ -68,9 +81,23 @@ const MobileNav = {
scrollToTop () {
window.scrollTo(0, 0)
},
showConfirmLogout () {
this.showingConfirmLogout = true
},
hideConfirmLogout () {
this.showingConfirmLogout = false
},
logout () {
if (!this.shouldConfirmLogout) {
this.doLogout()
} else {
this.showConfirmLogout()
}
},
doLogout () {
this.$router.replace('/main/public')
this.$store.dispatch('logout')
this.hideConfirmLogout()
},
markNotificationsAsSeen () {
// this.$refs.notifications.markAsSeen()

View file

@ -22,7 +22,7 @@
/>
</button>
<router-link
v-if="!hideSitename"
v-if="!hideSiteName"
class="site-name"
:to="{ name: 'root' }"
active-class="home"
@ -76,6 +76,18 @@
ref="sideDrawer"
:logout="logout"
/>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmLogout"
:title="$t('login.logout_confirm_title')"
:confirm-text="$t('login.logout_confirm_accept_button')"
:cancel-text="$t('login.logout_confirm_cancel_button')"
@accepted="doLogout"
@cancelled="hideConfirmLogout"
>
{{ $t('login.logout_confirm') }}
</confirm-modal>
</teleport>
</div>
</template>
@ -206,6 +218,14 @@
}
}
}
.confirm-modal.dark-overlay {
&::before {
z-index: 3000;
}
.dialog-modal.panel {
z-index: 3001;
}
}
}
</style>

View file

@ -13,13 +13,13 @@
<span v-if="user.is_local">
<button
class="button-default dropdown-item"
@click="toggleRight(&quot;admin&quot;)"
@click="toggleRight('admin')"
>
{{ $t(!!user.rights.admin ? 'user_card.admin_menu.revoke_admin' : 'user_card.admin_menu.grant_admin') }}
</button>
<button
class="button-default dropdown-item"
@click="toggleRight(&quot;moderator&quot;)"
@click="toggleRight('moderator')"
>
{{ $t(!!user.rights.moderator ? 'user_card.admin_menu.revoke_moderator' : 'user_card.admin_menu.grant_moderator') }}
</button>
@ -167,6 +167,7 @@
.moderation-tools-popover {
height: 100%;
z-index: 999;
.trigger {
display: flex !important;
height: 100%;

View file

@ -10,7 +10,7 @@ import {
faChevronDown,
faChevronUp,
faComments,
faBell,
faBolt,
faInfoCircle,
faStream,
faList,
@ -25,7 +25,7 @@ library.add(
faChevronDown,
faChevronUp,
faComments,
faBell,
faBolt,
faInfoCircle,
faStream,
faList,

View file

@ -48,7 +48,7 @@
<FAIcon
fixed-width
class="fa-scale-110"
icon="bell"
icon="bolt"
/>{{ $t("nav.interactions") }}
</router-link>
</li>

View file

@ -5,6 +5,7 @@ import UserCard from '../user_card/user_card.vue'
import Timeago from '../timeago/timeago.vue'
import StatusContent from '../status_content/status_content.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@ -36,7 +37,9 @@ const Notification = {
return {
userExpanded: false,
betterShadow: this.$store.state.interface.browserSupport.cssFilter,
unmuted: false
unmuted: false,
showingApproveConfirmDialog: false,
showingDenyConfirmDialog: false
}
},
props: [ 'notification' ],
@ -46,7 +49,8 @@ const Notification = {
UserCard,
Timeago,
Status,
RichContent
RichContent,
ConfirmModal
},
methods: {
toggleUserExpanded () {
@ -61,7 +65,26 @@ const Notification = {
toggleMute () {
this.unmuted = !this.unmuted
},
showApproveConfirmDialog () {
this.showingApproveConfirmDialog = true
},
hideApproveConfirmDialog () {
this.showingApproveConfirmDialog = false
},
showDenyConfirmDialog () {
this.showingDenyConfirmDialog = true
},
hideDenyConfirmDialog () {
this.showingDenyConfirmDialog = false
},
approveUser () {
if (this.shouldConfirmApprove) {
this.showApproveConfirmDialog()
} else {
this.doApprove()
}
},
doApprove () {
this.$store.state.api.backendInteractor.approveUser({ id: this.user.id })
this.$store.dispatch('removeFollowRequest', this.user)
this.$store.dispatch('markSingleNotificationAsSeen', { id: this.notification.id })
@ -71,13 +94,22 @@ const Notification = {
notification.type = 'follow'
}
})
this.hideApproveConfirmDialog()
},
denyUser () {
if (this.shouldConfirmDeny) {
this.showDenyConfirmDialog()
} else {
this.doDeny()
}
},
doDeny () {
this.$store.state.api.backendInteractor.denyUser({ id: this.user.id })
.then(() => {
this.$store.dispatch('dismissNotificationLocal', { id: this.notification.id })
this.$store.dispatch('removeFollowRequest', this.user)
})
this.hideDenyConfirmDialog()
}
},
computed: {
@ -107,6 +139,15 @@ const Notification = {
isStatusNotification () {
return isStatusNotification(this.notification.type)
},
mergedConfig () {
return this.$store.getters.mergedConfig
},
shouldConfirmApprove () {
return this.mergedConfig.modalOnApproveFollow
},
shouldConfirmDeny () {
return this.mergedConfig.modalOnDenyFollow
},
...mapState({
currentUser: state => state.users.currentUser
})

View file

@ -231,6 +231,28 @@
</template>
</div>
</div>
<teleport to="#modal">
<confirm-modal
v-if="showingApproveConfirmDialog"
:title="$t('user_card.approve_confirm_title')"
:confirm-text="$t('user_card.approve_confirm_accept_button')"
:cancel-text="$t('user_card.approve_confirm_cancel_button')"
@accepted="doApprove"
@cancelled="hideApproveConfirmDialog"
>
{{ $t('user_card.approve_confirm', { user: user.screen_name_ui }) }}
</confirm-modal>
<confirm-modal
v-if="showingDenyConfirmDialog"
:title="$t('user_card.deny_confirm_title')"
:confirm-text="$t('user_card.deny_confirm_accept_button')"
:cancel-text="$t('user_card.deny_confirm_cancel_button')"
@accepted="doDeny"
@cancelled="hideDenyConfirmDialog"
>
{{ $t('user_card.deny_confirm', { user: user.screen_name_ui }) }}
</confirm-modal>
</teleport>
</div>
</template>

View file

@ -1,3 +1,4 @@
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faRetweet } from '@fortawesome/free-solid-svg-icons'
@ -5,13 +6,24 @@ library.add(faRetweet)
const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'],
components: {
ConfirmModal
},
data () {
return {
animated: false
animated: false,
showingConfirmDialog: false
}
},
methods: {
retweet () {
if (!this.status.repeated && this.shouldConfirmRepeat) {
this.showConfirmDialog()
} else {
this.doRetweet()
}
},
doRetweet () {
if (!this.status.repeated) {
this.$store.dispatch('retweet', { id: this.status.id })
} else {
@ -21,6 +33,13 @@ const RetweetButton = {
setTimeout(() => {
this.animated = false
}, 500)
this.hideConfirmDialog()
},
showConfirmDialog () {
this.showingConfirmDialog = true
},
hideConfirmDialog () {
this.showingConfirmDialog = false
}
},
computed: {
@ -29,6 +48,9 @@ const RetweetButton = {
},
mergedConfig () {
return this.$store.getters.mergedConfig
},
shouldConfirmRepeat () {
return this.mergedConfig.modalOnRepeat
}
}
}

View file

@ -33,6 +33,18 @@
>
{{ status.repeat_num }}
</span>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmDialog"
:title="$t('status.repeat_confirm_title')"
:confirm-text="$t('status.repeat_confirm_accept_button')"
:cancel-text="$t('status.repeat_confirm_cancel_button')"
@accepted="doRetweet"
@cancelled="hideConfirmDialog"
>
{{ $t('status.repeat_confirm') }}
</confirm-modal>
</teleport>
</div>
</template>

View file

@ -148,20 +148,22 @@ export default {
mfmHtml.innerHTML = marked.parse(content)
// Add options with set values to CSS
Array.from(mfmHtml.content.firstChild.getElementsByClassName('mfm')).map((el) => {
if (el.dataset.speed) {
el.style.animationDuration = el.dataset.speed
}
if (el.dataset.deg) {
el.style.transform = `rotate(${el.dataset.deg}deg)`
}
if (Array.from(el.classList).includes('_mfm_font_')) {
const font = Object.keys(el.dataset)[0]
if (['serif', 'monospace', 'cursive', 'fantasy', 'emoji', 'math'].includes(font)) {
el.style.fontFamily = font
if (mfmHtml.content.firstChild) {
Array.from(mfmHtml.content.firstChild.getElementsByClassName('mfm')).map((el) => {
if (el.dataset.speed) {
el.style.animationDuration = el.dataset.speed
}
}
})
if (el.dataset.deg) {
el.style.transform = `rotate(${el.dataset.deg}deg)`
}
if (Array.from(el.classList).includes('_mfm_font_')) {
const font = Object.keys(el.dataset)[0]
if (['serif', 'monospace', 'cursive', 'fantasy', 'emoji', 'math'].includes(font)) {
el.style.fontFamily = font
}
}
})
}
return mfmHtml.innerHTML
}

View file

@ -14,6 +14,7 @@ import {
faTimes,
faFileUpload,
faFileDownload,
faSignOutAlt,
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
import {
@ -28,6 +29,7 @@ library.add(
faWindowMinimize,
faFileUpload,
faFileDownload,
faSignOutAlt,
faChevronDown
)
@ -66,6 +68,11 @@ const SettingsModal = {
closeModal () {
this.$store.dispatch('closeSettingsModal')
},
logout () {
this.$router.replace('/main/public')
this.$store.dispatch('closeSettingsModal')
this.$store.dispatch('logout')
},
peekModal () {
this.$store.dispatch('togglePeekSettingsModal')
},
@ -150,6 +157,7 @@ const SettingsModal = {
}
},
computed: {
currentUser () { return this.$store.state.users.currentUser },
currentSaveStateNotice () {
return this.$store.state.interface.settings.currentSaveStateNotice
},

View file

@ -71,5 +71,11 @@
display: flex;
flex-grow: 1;
}
.logout-button {
position: absolute;
right: 20px;
padding-right: 10px;
}
}
}

View file

@ -111,6 +111,20 @@
id="unscrolled-content"
class="extra-content"
/>
<button
v-if="currentUser"
class="button-default logout-button"
:title="$t('login.logout')"
:aria-label="$t('login.logout')"
@click.prevent="logout"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="sign-out-alt"
/>
<span>{{ $t('login.logout') }}</span>
</button>
</div>
</div>
</Modal>

View file

@ -50,6 +50,46 @@
<div class="setting-item">
<h2>{{ $t('nav.timeline') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting
path="hideSiteFavicon"
expert="1"
>
{{ $t('settings.hide_site_favicon') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="hideSiteName"
expert="1"
>
{{ $t('settings.hide_site_name') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="showNavShortcuts"
expert="1"
>
{{ $t('settings.show_nav_shortcuts') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="showPanelNavShortcuts"
expert="1"
>
{{ $t('settings.show_panel_nav_shortcuts') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="showWiderShortcuts"
expert="1"
>
{{ $t('settings.show_wider_shortcuts') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }}
@ -128,6 +168,18 @@
<BooleanSetting path="renderMisskeyMarkdown">
{{ $t('settings.render_mfm') }}
</BooleanSetting>
<ul
class="setting-list suboptions"
>
<li>
<BooleanSetting
path="renderMfmOnHover"
:disabled="!renderMisskeyMarkdown"
>
{{ $t('settings.render_mfm_on_hover') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting
@ -145,6 +197,77 @@
{{ $t('settings.autohide_floating_post_button') }}
</BooleanSetting>
</li>
<li>
<h3>{{ $t('settings.columns') }}</h3>
</li>
<li>
<BooleanSetting path="disableStickyHeaders">
{{ $t('settings.disable_sticky_headers') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="showScrollbars">
{{ $t('settings.show_scrollbars') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="sidebarRight">
{{ $t('settings.right_sidebar') }}
</BooleanSetting>
</li>
<li>
<ChoiceSetting
v-if="user"
id="thirdColumnMode"
path="thirdColumnMode"
:options="thirdColumnModeOptions"
>
{{ $t('settings.third_column_mode') }}
</ChoiceSetting>
</li>
<li>
<h3>{{ $t('settings.confirmation_dialogs') }}</h3>
</li>
<li class="select-multiple">
<span class="label">{{ $t('settings.confirm_dialogs') }}</span>
<ul class="option-list">
<li>
<BooleanSetting path="modalOnRepeat">
{{ $t('settings.confirm_dialogs_repeat') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnUnfollow">
{{ $t('settings.confirm_dialogs_unfollow') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnBlock">
{{ $t('settings.confirm_dialogs_block') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnMute">
{{ $t('settings.confirm_dialogs_mute') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnDelete">
{{ $t('settings.confirm_dialogs_delete') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnApproveFollow">
{{ $t('settings.confirm_dialogs_approve_follow') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnDenyFollow">
{{ $t('settings.confirm_dialogs_deny_follow') }}
</BooleanSetting>
</li>
</ul>
</li>
</ul>
</div>
<div class="setting-item">

View file

@ -8,7 +8,7 @@ import {
faSignOutAlt,
faHome,
faComments,
faBell,
faBolt,
faUserPlus,
faBullhorn,
faSearch,
@ -23,7 +23,7 @@ library.add(
faSignOutAlt,
faHome,
faComments,
faBell,
faBolt,
faUserPlus,
faBullhorn,
faSearch,

View file

@ -74,7 +74,7 @@
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="bell"
icon="bolt"
/> {{ $t("nav.interactions") }}
</router-link>
</li>

View file

@ -204,3 +204,4 @@
}
}
}

View file

@ -100,6 +100,12 @@ const StatusContent = {
maxThumbnails () {
return this.mergedConfig.maxThumbnails
},
renderMfmOnHover () {
return this.mergedConfig.renderMfmOnHover
},
renderMisskeyMarkdown () {
return this.mergedConfig.renderMisskeyMarkdown
},
...mapGetters(['mergedConfig']),
...mapState({
currentUser: state => state.users.currentUser

View file

@ -1,7 +1,7 @@
<template>
<div
class="StatusContent"
:class="{ '-compact': compact }"
:class="{ '-compact': compact, 'mfm-hover': renderMfmOnHover, 'mfm-disabled': !renderMisskeyMarkdown }"
>
<slot name="header" />
<StatusBody
@ -75,5 +75,22 @@
height: 50px;
}
}
&.mfm-hover:not(:hover) {
.mfm {
animation: none !important;
}
}
&.mfm-disabled {
.mfm {
animation: none !important;
}
}
}
.quote-inline,
.quote + .link-preview {
display: none;
}
</style>

View file

@ -51,6 +51,10 @@
width: 100%;
height: 100%;
object-fit: contain;
&::before {
line-height: 20px;
}
}
&.animated {

View file

@ -2,6 +2,7 @@ import Status from '../status/status.vue'
import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
import Conversation from '../conversation/conversation.vue'
import TimelineMenu from '../timeline_menu/timeline_menu.vue'
import TimelineMenuTabs from '../timeline_menu_tabs/timeline_menu_tabs.vue'
import TimelineQuickSettings from './timeline_quick_settings.vue'
import { debounce, throttle, keyBy } from 'lodash'
import { library } from '@fortawesome/fontawesome-svg-core'
@ -39,6 +40,7 @@ const Timeline = {
Status,
Conversation,
TimelineMenu,
TimelineMenuTabs,
TimelineQuickSettings
},
computed: {
@ -85,6 +87,9 @@ const Timeline = {
},
virtualScrollingEnabled () {
return this.$store.getters.mergedConfig.virtualScrolling
},
showPanelNavShortcuts () {
return this.$store.getters.mergedConfig.showPanelNavShortcuts
}
},
created () {
@ -145,7 +150,6 @@ const Timeline = {
this.$store.commit('showNewStatuses', { timeline: this.timelineName })
this.paused = false
}
window.scrollTo({ top: 0 })
},
fetchOlderStatuses: throttle(function () {
const store = this.$store

View file

@ -1,7 +1,11 @@
<template>
<div :class="['Timeline', classes.root]">
<div :class="classes.header">
<TimelineMenu v-if="!embedded" />
<template v-if="!embedded">
<TimelineMenuTabs v-if="showPanelNavShortcuts" />
<TimelineMenu v-else />
</template>
<button
v-if="showLoadButton"
class="button-default loadmore-button"

View file

@ -0,0 +1,30 @@
import { mapState } from 'vuex'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faUsers,
faGlobe,
faBookmark,
faEnvelope,
faHome
} from '@fortawesome/free-solid-svg-icons'
import { faCircle } from '@fortawesome/free-regular-svg-icons'
library.add(
faUsers,
faGlobe,
faBookmark,
faEnvelope,
faHome,
faCircle
)
const TimelineMenuContent = {
computed: {
...mapState({
currentUser: state => state.users.currentUser,
privateMode: state => state.instance.private,
federating: state => state.instance.federating
})
}
}
export default TimelineMenuContent

View file

@ -0,0 +1,114 @@
<template>
<ul>
<li v-if="currentUser">
<router-link
class="menu-item"
:to="{ name: 'friends' }"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding "
icon="home"
/>
<span
:title="$t('nav.home_timeline_description')"
:aria-label="$t('nav.home_timeline_description')"
>{{ $t("nav.home_timeline") }}</span>
</router-link>
</li>
<li v-if="currentUser">
<router-link
class="menu-item"
:to="{ name: 'bubble-timeline' }"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding "
:icon="['far', 'circle']"
/>
<span
:title="$t('nav.bubble_timeline_description')"
:aria-label="$t('nav.bubble_timeline_description')"
>{{ $t("nav.bubble_timeline") }}</span>
</router-link>
</li>
<li v-if="currentUser || !privateMode">
<router-link
class="menu-item"
:to="{ name: 'public-timeline' }"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding "
icon="users"
/>
<span
:title="$t('nav.public_timeline_description')"
:aria-label="$t('nav.public_timeline_description')"
>{{ $t("nav.public_tl") }}</span>
</router-link>
</li>
<li v-if="federating && (currentUser || !privateMode)">
<router-link
class="menu-item"
:to="{ name: 'public-external-timeline' }"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding "
icon="globe"
/>
<span
:title="$t('nav.twkn_timeline_description')"
:aria-label="$t('nav.twkn_timeline_description')"
>{{ $t("nav.twkn") }}</span>
</router-link>
</li>
<li v-if="currentUser">
<router-link
class="menu-item"
:to="{ name: 'bookmarks'}"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding "
icon="bookmark"
/>
<span
:title="$t('nav.bookmarks')"
:aria-label="$t('nav.bookmarks')"
>{{ $t("nav.bookmarks") }}</span>
</router-link>
</li>
<li v-if="currentUser">
<router-link
class="menu-item"
:to="{ name: 'dms', params: { username: currentUser.screen_name } }"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding "
icon="envelope"
/>
<span
:title="$t('nav.dms')"
:aria-label="$t('nav.dms')"
>{{ $t("nav.dms") }}</span>
</router-link>
</li>
</ul>
</template>
<script src="./timeline_menu_content.js" ></script>
<style lang="scss">
@import "../../_variables.scss";
.timeline-desc {
text-decoration: none;
color: var(--text, $fallback--text);
padding-left: 1em;
display: block;
background-color: scale(var(--bg, $fallback--bg), 0.1);
padding-bottom: 0.4em;
}
</style>

View file

@ -0,0 +1,61 @@
import Popover from '../popover/popover.vue'
import TimelineMenuContent from './timeline_menu_content.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faChevronDown
} from '@fortawesome/free-solid-svg-icons'
library.add(faChevronDown)
// Route -> i18n key mapping, exported and not in the computed
// because nav panel benefits from the same information.
export const timelineNames = () => {
return {
'friends': 'nav.home_timeline',
'bookmarks': 'nav.bookmarks',
'dms': 'nav.dms',
'public-timeline': 'nav.public_tl',
'public-external-timeline': 'nav.twkn',
'bubble-timeline': 'nav.bubble_timeline'
}
}
const TimelineMenuTabs = {
components: {
Popover,
TimelineMenuContent
},
data () {
return {
isOpen: false
}
},
created () {
if (timelineNames()[this.$route.name]) {
this.$store.dispatch('setLastTimeline', this.$route.name)
}
},
computed: {
currentUser () {
return this.$store.state.users.currentUser
},
privateMode () {
return this.$store.state.instance.private
}
},
methods: {
timelineName () {
const route = this.$route.name
if (route === 'tag-timeline') {
return '#' + this.$route.params.tag
}
if (route === 'list-timeline') {
return this.$store.getters.findListTitle(this.$route.params.id)
}
const i18nkey = timelineNames()[this.$route.name]
return i18nkey ? this.$t(i18nkey) : route
}
}
}
export default TimelineMenuTabs

View file

@ -0,0 +1,96 @@
<template>
<div
v-if="currentUser || !privateMode"
class="nav-items timeline-menu-tabs"
>
<router-link
v-if="currentUser"
:to="{ name: 'friends' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="home"
:title="$t('nav.home_timeline_description')"
/>
</router-link>
<router-link
:to="{ name: 'public-timeline' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="users"
:title="$t('nav.public_timeline_description')"
/>
</router-link>
<router-link
v-if="currentUser"
:to="{ name: 'bubble-timeline' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
:icon="['far', 'circle']"
:title="$t('nav.bubble_timeline_description')"
/>
</router-link>
<router-link
:to="{ name: 'public-external-timeline' }"
class="nav-icon"
>
<FAIcon
fixed-width
class="fa-scale-110 fa-old-padding"
icon="globe"
:title="$t('nav.twkn_timeline_description')"
/>
</router-link>
<span class="timeline-title">{{ timelineName() }}</span>
</div>
</template>
<script src="./timeline_menu_tabs.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
.timeline-menu-tabs {
.nav-icon {
margin-left: 0.7em;
width: 2em;
height: 100%;
text-align: center;
&.router-link-active {
border-bottom: 2px solid var(--selectedMenuText, $fallback--text);
padding-bottom: 0.8em;
.svg-inline--fa {
font-weight: bolder;
color: $fallback--text;
color: var(--selectedMenuText, $fallback--text);
--lightText: var(--selectedMenuLightText, $fallback--lightText);
}
}
}
.timeline-title {
margin-left: 1em;
font-size: 1.2em;
font-weight: bold;
color: var(--selectedMenuText, $fallback--text);
color: var(--selectedMenuText, $fallback--text);
--lightText: var(--selectedMenuLightText, $fallback--lightText);
}
@media all and (max-width: 900px) {
.timeline-title {
display: none;
}
}
}
</style>

View file

@ -6,6 +6,7 @@ import ModerationTools from '../moderation_tools/moderation_tools.vue'
import AccountActions from '../account_actions/account_actions.vue'
import Select from '../select/select.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { mapGetters } from 'vuex'
import { library } from '@fortawesome/fontawesome-svg-core'
@ -32,7 +33,8 @@ export default {
data () {
return {
followRequestInProgress: false,
betterShadow: this.$store.state.interface.browserSupport.cssFilter
betterShadow: this.$store.state.interface.browserSupport.cssFilter,
showingConfirmMute: false
}
},
created () {
@ -69,6 +71,7 @@ export default {
return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
},
loggedIn () {
console.log({ ...this.$store.state.users.currentUser })
return this.$store.state.users.currentUser
},
dailyAvg () {
@ -112,6 +115,9 @@ export default {
hideFollowersCount () {
return this.isOtherUser && this.user.hide_followers_count
},
shouldConfirmMute () {
return this.mergedConfig.modalOnMute
},
...mapGetters(['mergedConfig'])
},
components: {
@ -122,14 +128,29 @@ export default {
ProgressButton,
FollowButton,
Select,
RichContent
RichContent,
ConfirmModal
},
methods: {
refetchRelationship () {
return this.$store.dispatch('fetchUserRelationship', this.user.id)
},
showConfirmMute () {
this.showingConfirmMute = true
},
hideConfirmMute () {
this.showingConfirmMute = false
},
muteUser () {
if (!this.shouldConfirmMute) {
this.doMuteUser()
} else {
this.showConfirmMute()
}
},
doMuteUser () {
this.$store.dispatch('muteUser', this.user.id)
this.hideConfirmMute()
},
unmuteUser () {
this.$store.dispatch('unmuteUser', this.user.id)

View file

@ -245,7 +245,7 @@
</button>
</div>
<ModerationTools
v-if="loggedIn.role === &quot;admin&quot;"
v-if="loggedIn.role === 'admin'"
:user="user"
/>
</div>
@ -295,6 +295,27 @@
:handle-links="true"
/>
</div>
<teleport to="#modal">
<confirm-modal
v-if="showingConfirmMute"
:title="$t('user_card.mute_confirm_title')"
:confirm-text="$t('user_card.mute_confirm_accept_button')"
:cancel-text="$t('user_card.mute_confirm_cancel_button')"
@accepted="doMuteUser"
@cancelled="hideConfirmMute"
>
<i18n-t
keypath="user_card.mute_confirm"
tag="span"
>
<template #user>
<span
v-text="user.screen_name_ui"
/>
</template>
</i18n-t>
</confirm-modal>
</teleport>
</div>
</template>

View file

@ -49,7 +49,7 @@ const UserProfile = {
created () {
const routeParams = this.$route.params
this.load(routeParams.name || routeParams.id)
this.tab = get(this.$route, 'query.tab', defaultTabKey)
this.tab = get(this.$route, 'query.hash', defaultTabKey).replace(/^#/, '')
},
unmounted () {
this.stopFetching()
@ -146,7 +146,7 @@ const UserProfile = {
},
onTabSwitch (tab) {
this.tab = tab
this.$router.replace({ query: { tab } })
this.$router.replace({ hash: `#${tab}` })
},
linkClicked ({ target }) {
if (target.tagName === 'SPAN') {
@ -176,8 +176,8 @@ const UserProfile = {
this.switchUser(newVal)
}
},
'$route.query': function (newVal) {
this.tab = newVal.tab || defaultTabKey
'$route.hash': function (newVal) {
this.tab = newVal.replace(/^#/, '') || defaultTabKey
}
},
components: {

View file

@ -1,5 +1,7 @@
{
"about": {
"bubble_instances": "Instàncies de la Bombolla Local",
"bubble_instances_description": "Instàncies triades per els administradors per a representar l'àrea local d'aquesta instància",
"mrf": {
"federation": "Federació",
"keyword": {
@ -136,6 +138,7 @@
},
"scope_in_timeline": {
"direct": "Directe",
"local": "Local - només la teva instància veu aquest apunt",
"private": "Només seguidors",
"public": "Públic",
"unlisted": "No llistat"
@ -218,7 +221,7 @@
"search": "Cerca",
"timeline": "Línia de temps",
"timelines": "Línies de temps",
"twkn": "Xarxa coneguda",
"twkn": "Xarxa Coneguda",
"twkn_timeline_description": "Apunts de tota la xarxa",
"user_search": "Cerca d'usuaris",
"who_to_follow": "A qui seguir"
@ -226,7 +229,7 @@
"notifications": {
"broken_favorite": "Apunt desconegut, cercant-lo…",
"error": "Error obtenint notificacions: {0}",
"favorited_you": "ha afavorit un apunt teu",
"favorited_you": "ha afavorit el teu apunt",
"follow_request": "et vol seguir",
"followed_you": "ha començat a seguir-te",
"load_older": "Carrega notificacions més velles",
@ -281,11 +284,11 @@
"default": "Just ara he arribat a Catalunya",
"direct_warning_to_all": "Aquest apunt serà visible per a tots els usuaris mencionats.",
"direct_warning_to_first_only": "Aquest apunt només serà visible per als usuaris mencionats al principi del missatge.",
"empty_status_error": "No es pot publicar un apunt buit sense fitxers adjunts",
"empty_status_error": "No es pot enviar un apunt buit i sense fitxers adjunts",
"media_description": "Descripció multimèdia",
"media_description_error": "Ha fallat la pujada del Mèdia, prova de nou",
"media_not_sensitive_warning": "Tens un Avís de Contingut però els adjunts no estan marcats com a sensibles!",
"new_status": "Publica un nou apunt",
"new_status": "Nou apunt",
"post": "Apunt",
"posting": "Publicant",
"preview": "Vista prèvia",
@ -306,7 +309,7 @@
},
"registration": {
"bio": "Bio",
"bio_placeholder": "p.e.\nHola, sóc la Lain.\nSóc una noia anime que viu a un suburbi de Japó. Potser em coneixes per Wired.",
"bio_placeholder": "p.e.\nHola! Benvingut a la meva bio.\nM'encanta veure anime i jugar a jocs. Espero que podrem ser amics!",
"captcha": "CAPTCHA",
"email": "Adreça de Correu",
"email_language": "En quina llengua vols rebre els correus del servidor?",
@ -397,7 +400,7 @@
"conversation_display_linear": "Estil linear",
"conversation_display_tree": "Estil d'arbre",
"conversation_other_replies_button": "Mostra el botó \"altres respostes\"",
"conversation_other_replies_button_below": "Apunts a sota",
"conversation_other_replies_button_below": "Apunts de sota",
"conversation_other_replies_button_inside": "Apunts interiors",
"current_avatar": "El teu avatar actual",
"current_mascot": "La teva mascota actual",
@ -431,7 +434,7 @@
"restore_settings": "Restaurar configuració des d'un fitxer"
},
"filtering": "Filtrant",
"filtering_explanation": "Es silenciaran tots els apunts que continguin aquestes paraules, una per línia",
"filtering_explanation": "Tots els apunts que continguin aquestes paraules seran silenciats, un per línia",
"follow_export": "Exporta els seguits",
"follow_export_button": "Exporta els teus seguits a un fitxer CSV",
"follow_import": "Importa els seguits",
@ -441,7 +444,7 @@
"fun": "Divertit",
"general": "General",
"greentext": "Text verd (meme arrows)",
"hide_all_muted_posts": "Ocultar apunts silenciades",
"hide_all_muted_posts": "Amaga apunts silenciats",
"hide_attachments_in_convo": "Amaga els adjunts en les converses",
"hide_attachments_in_tl": "Amaga els adjunts en la línia de temps",
"hide_bot_indication": "Amaga l'indicació de bot en els apunts",
@ -453,11 +456,13 @@
"hide_follows_description": "No mostrar a qui segueixo",
"hide_isp": "Amaga el panell especific de l'instància",
"hide_list_aliases_error_action": "Tanca",
"hide_media_previews": "Ocultar les vistes prèvies multimèdia",
"hide_media_previews": "Amaga les vistes prèvies de multimèdia",
"hide_muted_posts": "Amaga els apunts de comptes silenciats",
"hide_muted_threads": "Amaga fils silenciats",
"hide_post_stats": "Amaga les estadístiques dels apunts (p. ex. el número de favorits)",
"hide_shoutbox": "Amaga la casella de gàbia de grills",
"hide_site_favicon": "Amaga el favicon de l'instància en el panell superior",
"hide_site_name": "Amaga el nom de l'instància en el panell superior",
"hide_threads_with_blocked_users": "Amaga els fils mencionant usuaris bloquejats",
"hide_user_stats": "Amaga les estadístiques de l'usuari (p. ex. el número de seguidors)",
"hide_wallpaper": "Amagar el fons de l'instància",
@ -482,7 +487,7 @@
"mascot": "Mascota de Mastodon FE",
"max_depth_in_thread": "Màxim número de nivells en el fil per mostrar per defecte",
"max_thumbnails": "Quantitat màxima de miniatures per apunt (buit = sense limit)",
"mention_link_bolden_you": "Destaca mencions per tu quan et mencionin",
"mention_link_bolden_you": "Destaca mencions per a tu quan et mencionin",
"mention_link_display": "Mostra els enllaços de mencions",
"mention_link_display_full": "sempre com a noms complets (p. ex. {'@'}maria{'@'}exemple.cat)",
"mention_link_display_full_for_remote": "com a noms complets només per a usuaris remots (p. ex.. {'@'}maria{'@'}exemple.cat)",
@ -519,7 +524,7 @@
"move_account_notes": "Si vols moure el compte a un altre lloc has d'anar a aquest altre compte i afegir un àlies que apunti a aquest.",
"move_account_target": "Compte destí (p.ex. {example})",
"moved_account": "El compte s'ha mogut.",
"mute_bot_posts": "Silencia publicacions de bot",
"mute_bot_posts": "Silencia apunts de bots",
"mute_export": "Exportar silenciats",
"mute_export_button": "Exportar els teus silenciats a un fitxer csv",
"mute_import": "Importar silenciats",
@ -543,13 +548,13 @@
"notification_setting_hide_notification_contents": "Amagar el remitent i els continguts de les notificacions push",
"notification_setting_privacy": "Privacitat",
"notification_visibility": "Tipus de notificacions a mostrar",
"notification_visibility_emoji_reactions": "reacciona",
"notification_visibility_follows": "em segueix",
"notification_visibility_likes": "m'afavoreix",
"notification_visibility_mentions": "em menciona",
"notification_visibility_moves": "es mou",
"notification_visibility_polls": "finalitza una enquesta on hi has votat",
"notification_visibility_repeats": "em repeteix",
"notification_visibility_emoji_reactions": "reaccionen",
"notification_visibility_follows": "em segueixen",
"notification_visibility_likes": "m'afavoreixen",
"notification_visibility_mentions": "em mencionen",
"notification_visibility_moves": "usuari es mou",
"notification_visibility_polls": "finalitza una enquesta que he votat",
"notification_visibility_repeats": "em repeteixen",
"notifications": "Notificacions",
"nsfw_clickthrough": "Amaga els Mèdia sensibles/NSFW",
"oauth_tokens": "Codis OAuth",
@ -558,7 +563,7 @@
"pause_on_unfocused": "Pausa quan la pestanya perdi el focus",
"play_videos_in_modal": "Reproduir vídeos en un marc emergent",
"post_look_feel": "Aspecte i Sensació dels apunts",
"post_status_content_type": "Tipus de contingut del apunt",
"post_status_content_type": "Tipus de contingut d'apunt predeterminat",
"posts": "Apunts",
"preload_images": "Precarregar les imatges",
"presets": "Temes",
@ -576,12 +581,13 @@
"remove_alias": "Elimina aquest àlies",
"remove_backup": "Treure",
"render_mfm": "Renderitza Markdown de Misskey",
"render_mfm_on_hover": "Pausa les animacions MFM fins que el cursor sigui sobre l'apunt",
"replies_in_timeline": "Respostes en línia de temps",
"reply_visibility_all": "Mostra totes les respostes",
"reply_visibility_following": "Mostra només les respostes dirigides a mi o a usuaris que segueixo",
"reply_visibility_following_short": "Mostrar respostes als meus seguits",
"reply_visibility_following_short": "Mostra respostes als meus seguits",
"reply_visibility_self": "Mostra només les respostes dirigides a mi",
"reply_visibility_self_short": "Mostrar només respostes a mi mateix",
"reply_visibility_self_short": "Mostra només respostes a mi mateix",
"reset_avatar": "Restablir l'avatar",
"reset_avatar_confirm": "Realment vols restablir l'avatar?",
"reset_background_confirm": "Realment vols restablir el fons?",
@ -598,7 +604,7 @@
"search_user_to_mute": "Busca a qui vols silenciar",
"security": "Seguretat",
"security_tab": "Seguretat",
"sensitive_by_default": "Marcar apunts com a sensibles per defecte",
"sensitive_by_default": "Marca apunts com a sensibles per defecte",
"sensitive_if_subject": "Marca automàticament les imatges com a sensibles si s'ha especificat la línia assumpte",
"set_new_avatar": "Establir un nou avatar",
"set_new_mascot": "Establir una nova mascota",
@ -609,9 +615,12 @@
"settings": "Configuració",
"show_admin_badge": "Mostra l'insígnia \"Administrador\" en el meu perfil",
"show_moderator_badge": "Mostra l'insígnia \"Moderador\" en el meu perfil",
"show_nav_shortcuts": "Mostra els accessos directes addicionals en el panell superior",
"show_panel_nav_shortcuts": "Mostra els accessos directes de navegació de la línia de temps en el panell superior",
"show_scrollbars": "Mostra les barres de desplaçament de la columna lateral",
"show_wider_shortcuts": "Mostra més separats els accessos directes del panell superior",
"show_yous": "Mostra (Tu)s",
"stop_gifs": "Anima les imatges animades fins que hi passis el cursor per sobre",
"stop_gifs": "Pausa les imatges animades fins que hi passis el cursor per sobre",
"streaming": "Mostra automàticament els nous apunts quan et desplacis a la part superior",
"style": {
"advanced_colors": {
@ -807,7 +816,7 @@
"attachment_stop_flash": "Para el reproductor Flash",
"bookmark": "Marcador",
"collapse_attachments": "Replega adjunts",
"copy_link": "Copia l'enllaç al apunt",
"copy_link": "Copia l'enllaç a l'apunt",
"delete": "Esborra l'apunt",
"delete_confirm": "Segur que vols esborrar aquest apunt?",
"expand": "Expandeix",
@ -817,7 +826,7 @@
"hide_content": "Amaga el contingut",
"hide_full_subject": "Amaga tot l'assumpte",
"many_attachments": "L'apunt té {number} adjunt | L'apunt té {number} adjunts",
"mentions": "Mencions",
"mentions": "Menciona",
"move_down": "Mou l'adjunt a la dreta",
"move_up": "Mou l'adjunt a l'esquerra",
"mute_conversation": "Silencia la conversa",
@ -832,7 +841,7 @@
"replies_list_with_others": "Respostes (+{numReplies} altre): | Respostes (+{numReplies} altres):",
"reply_to": "Respon a",
"show_all_attachments": "Mostra tots els adjunts",
"show_all_conversation": "Mostra la conversa sencera ({numStatus} altres apunts) | Mostra la conversa sencera ({numStatus} altres apunts)",
"show_all_conversation": "Mostra la conversa sencera ({numStatus} altre apunt) | Mostra la conversa sencera ({numStatus} altres apunts)",
"show_all_conversation_with_icon": "{icon} {text}",
"show_attachment_description": "Descripció prèvia (obre l'adjunt per a descripció sencera)",
"show_attachment_in_modal": "Mostra en el modal de Mèdia",
@ -841,13 +850,13 @@
"show_only_conversation_under_this": "Només mostra respostes a aquest apunt",
"status_deleted": "Aquest apunt ha estat esborrat",
"status_unavailable": "Apunt no disponible",
"thread_follow": "Mira la part restant del fil ({numStatus} apunts en total) | Mira la part restant del fil ({numStatus} apunts en total)",
"thread_follow": "Mira la part restant d'aquest fil ({numStatus} apunt en total) | Mira la part restant d'aquest fil ({numStatus} apunts en total)",
"thread_follow_with_icon": "{icon} {text}",
"thread_hide": "Amaga aquest fil",
"thread_muted": "Fil silenciat",
"thread_muted_and_words": ", té les paraules:",
"thread_show": "Mostra aquest fil",
"thread_show_full": "Mostra-ho tot sota aquest fil ({numStatus} apunts en total, màx. profunditat {depth}) | Mostra-ho tot sota aquest fil ({numStatus} apunts en total, màx. profunditat {depth})",
"thread_show_full": "Mostra-ho tot sota aquest fil ({numStatus} apunt en total, màx. profunditat {depth}) | Mostra-ho tot sota aquest fil ({numStatus} apunts en total, màx. profunditat {depth})",
"thread_show_full_with_icon": "{icon} {text}",
"unbookmark": "Desmarca",
"unmute_conversation": "Deixa de silenciar la conversa",

View file

@ -1,5 +1,7 @@
{
"about": {
"bubble_instances": "Local Bubble Instances",
"bubble_instances_description": "Instances chosen by the admins to represent the local area of this instance",
"mrf": {
"federation": "Federation",
"keyword": {
@ -392,13 +394,23 @@
"chatMessageRadius": "Chat message",
"checkboxRadius": "Checkboxes",
"collapse_subject": "Collapse posts with subjects",
"columns": "Columns",
"composing": "Composing",
"confirmation_dialogs": "Confirmation options",
"confirm_dialogs": "Require confirmation for:",
"confirm_dialogs_repeat": "Repeating a post",
"confirm_dialogs_unfollow": "Unfollowing someone",
"confirm_dialogs_block": "Blocking someone",
"confirm_dialogs_mute": "Muting someone",
"confirm_dialogs_delete": "Deleting a post",
"confirm_dialogs_approve_follow": "Accepting a follow request",
"confirm_dialogs_deny_follow": "Rejecting a follow request",
"confirm_new_password": "Confirm new password",
"conversation_display": "Conversation display style",
"conversation_display_linear": "Linear-style",
"conversation_display_tree": "Tree-style",
"conversation_other_replies_button": "Show the \"other replies\" button",
"conversation_other_replies_button_below": "Below statuses",
"conversation_other_replies_button_below": "Below posts",
"conversation_other_replies_button_inside": "Inside posts",
"current_avatar": "Your current avatar",
"current_mascot": "Your current mascot",
@ -459,6 +471,8 @@
"hide_muted_threads": "Hide muted threads",
"hide_post_stats": "Hide post statistics (e.g. the number of favorites)",
"hide_shoutbox": "Hide instance shoutbox",
"hide_site_favicon": "Hide instance favicon in top panel",
"hide_site_name": "Hide instance name in top panel",
"hide_threads_with_blocked_users": "Hide threads mentioning blocked users",
"hide_user_stats": "Hide user statistics (e.g. the number of followers)",
"hide_wallpaper": "Hide instance wallpaper",
@ -577,6 +591,7 @@
"remove_alias": "Remove this alias",
"remove_backup": "Remove",
"render_mfm": "Render Misskey Markdown",
"render_mfm_on_hover": "Pause MFM animations until post hover",
"replies_in_timeline": "Replies in timeline",
"reply_visibility_all": "Show all replies",
"reply_visibility_following": "Only show replies directed at me or users I'm following",
@ -610,7 +625,10 @@
"settings": "Settings",
"show_admin_badge": "Show \"Admin\" badge in my profile",
"show_moderator_badge": "Show \"Moderator\" badge in my profile",
"show_nav_shortcuts": "Show extra navigation shortcuts in top panel",
"show_panel_nav_shortcuts": "Show timeline navigation shortcuts at the top of the panel",
"show_scrollbars": "Show side column's scrollbars",
"show_wider_shortcuts": "Show wider gap between top panel shortcuts",
"show_yous": "Show (You)s",
"stop_gifs": "Pause animated images until you hover on them",
"streaming": "Automatically show new posts when scrolled to the top",
@ -811,6 +829,9 @@
"copy_link": "Copy link to post",
"delete": "Delete post",
"delete_confirm": "Do you really want to delete this post?",
"delete_confirm_title": "Confirm deletion",
"delete_confirm_accept_button": "Yes, delete it",
"delete_confirm_cancel_button": "No, keep it",
"expand": "Expand",
"external_source": "External source",
"favorites": "Favorites",
@ -832,6 +853,10 @@
"replies_list": "Replies:",
"replies_list_with_others": "Replies (+{numReplies} other): | Replies (+{numReplies} others):",
"reply_to": "Reply to",
"repeat_confirm": "Do you really want to repeat this post?",
"repeat_confirm_title": "Confirm repeat",
"repeat_confirm_accept_button": "Yes, repeat it",
"repeat_confirm_cancel_button": "No, don't repeat",
"show_all_attachments": "Show all attachments",
"show_all_conversation": "Show full conversation ({numStatus} other post) | Show full conversation ({numStatus} other posts)",
"show_all_conversation_with_icon": "{icon} {text}",
@ -940,12 +965,24 @@
"strip_media": "Remove media from posts"
},
"approve": "Approve",
"approve_confirm_title": "Approve follow request",
"approve_confirm": "Are you sure you want to let this user follow you?",
"approve_confirm_accept_button": "Yes, accept",
"approve_confirm_cancel_button": "No, cancel",
"block": "Block",
"block_confirm": "Are you sure you want to block {user}?",
"block_confirm_title": "Block user",
"block_confirm_cancel_button": "No, don't block",
"block_confirm_accept_button": "Yes, block",
"block_progress": "Blocking…",
"blocked": "Blocked!",
"bot": "Bot",
"deactivated": "Deactivated",
"deny": "Deny",
"deny_confirm_title": "Deny follow request",
"deny_confirm": "Are you sure you want to deny this user's follow request?",
"deny_confirm_accept_button": "Yes, deny",
"deny_confirm_cancel_button": "No, cancel",
"domain_muted": "Unblock domain",
"edit_profile": "Edit profile",
"favorites": "Favorites",
@ -971,6 +1008,10 @@
"mention": "Mention",
"message": "Message",
"mute": "Mute",
"mute_confirm": "Are you sure you want to mute {user}?",
"mute_confirm_title": "Mute user",
"mute_confirm_cancel_button": "No, don't mute",
"mute_confirm_accept_button": "Yes, mute",
"mute_domain": "Block domain",
"mute_progress": "Muting…",
"muted": "Muted",
@ -983,6 +1024,10 @@
"subscribe": "Subscribe",
"unblock": "Unblock",
"unblock_progress": "Unblocking…",
"unfollow_confirm": "Are you sure you want to unfollow {user}?",
"unfollow_confirm_title": "Unfollow user",
"unfollow_confirm_cancel_button": "No, don't unfollow",
"unfollow_confirm_accept_button": "Yes, unfollow",
"unmute": "Unmute",
"unmute_progress": "Unmuting…",
"unsubscribe": "Unsubscribe"

View file

@ -1,5 +1,7 @@
{
"about": {
"bubble_instances": "Instancias de burbuja local",
"bubble_instances_description": "Instancias elegidas por los/las adminstradores/as para representar el área local de esta instancia",
"mrf": {
"federation": "Federación",
"keyword": {
@ -137,7 +139,8 @@
"direct": "Directo",
"local": "Local - sólo tu instancia puede ver esta publicación",
"private": "Sólo para seguidores",
"public": "Público"
"public": "Público",
"unlisted": "No listado"
},
"show_less": "Mostrar menos",
"show_more": "Mostrar más",
@ -164,6 +167,8 @@
"lists": {
"create": "Crear",
"delete": "Eliminar lista",
"lists": "Listas",
"new": "Nueva Lista",
"save": "Guardar cambios",
"search": "Buscar cuentas",
"title": "Título de la lista"
@ -193,6 +198,7 @@
"nav": {
"about": "Acerca de",
"administration": "Administración",
"announcements": "Anuncios",
"back": "Volver",
"bookmarks": "Marcadores",
"chats": "Chats",
@ -200,13 +206,16 @@
"friend_requests": "Solicitudes de seguimiento",
"home_timeline": "Línea temporal personal",
"interactions": "Interacciones",
"lists": "Listas",
"mentions": "Menciones",
"preferences": "Preferencias",
"public_timeline_description": "Publicaciones públicas de esta instancia",
"public_tl": "Línea temporal pública",
"search": "Buscar",
"timeline": "Línea Temporal",
"timelines": "Líneas de Tiempo",
"twkn": "Red Conocida",
"twkn_timeline_description": "Publicaciones de la red conocida",
"user_search": "Búsqueda de Usuarios",
"who_to_follow": "A quién seguir"
},

View file

@ -1,5 +1,7 @@
{
"about": {
"bubble_instances": "Les instances de la bulle locale",
"bubble_instances_description": "Des instances choisies par l'administration pour representer la région de cette instance",
"mrf": {
"federation": "Fédération",
"keyword": {
@ -136,6 +138,7 @@
},
"scope_in_timeline": {
"direct": "Direct",
"local": "Local - visible seulement sur cette instance",
"private": "Abonné·e·s uniquement",
"public": "Public",
"unlisted": "Non-listé"
@ -281,11 +284,11 @@
"default": "Je viens d'arriver au QG de la NERV",
"direct_warning_to_all": "Ce message sera visible pour toutes les personnes mentionnées.",
"direct_warning_to_first_only": "Ce message sera visible uniquement pour personnes mentionnées au début du message.",
"empty_status_error": "Impossible de poster un statut vide sans pièces-jointes",
"empty_status_error": "Impossible de publier un statut vide sans pièces-jointes",
"media_description": "Description de la pièce-jointe",
"media_description_error": "Échec de téléversement du media, essayez encore",
"media_not_sensitive_warning": "Il y a un avertissment, mais les pièces jointes ne sont pas marquées comme sensibles !",
"new_status": "Poster un nouveau statut",
"new_status": "Nouveau statut",
"post": "Post",
"posting": "Envoi en cours",
"preview": "Prévisualisation",
@ -306,7 +309,7 @@
},
"registration": {
"bio": "Biographie",
"bio_placeholder": "ex.\nSalut, je suis Lain\nJe suis une héroïne d'animation qui vit dans une banlieue japonaise. Vous me connaissez peut-être du Wired.",
"bio_placeholder": "ex :\nSalut, je me présente ici !\nJadore les animés et les jeux vidéos. Jespère qu'on peut être amis⋅ies !",
"captcha": "CAPTCHA",
"email": "Courriel",
"email_language": "Dans quelle langue souhaitez-vous recevoir des courriels ?",
@ -458,6 +461,8 @@
"hide_muted_threads": "Masquer les fils de discussion silenciés",
"hide_post_stats": "Masquer les statistiques des messages (ex. le nombre de favoris)",
"hide_shoutbox": "Cacher la shoutbox de l'instance",
"hide_site_favicon": "Ne pas afficher le favicon de linstance dans le panneau supérieur",
"hide_site_name": "Ne pas afficher le nom de l'instance dans le panneau supérieur",
"hide_threads_with_blocked_users": "Masquer les fils qui mentionnent les personnes bloquées",
"hide_user_stats": "Masquer les statistiques de compte (ex. le nombre de suivis)",
"hide_wallpaper": "Cacher le fond d'écran",
@ -576,6 +581,7 @@
"remove_alias": "Supprimer ce pseudo",
"remove_backup": "Supprimer",
"render_mfm": "Afficher le contenu Misskey Markdown",
"render_mfm_on_hover": "Rester sur du contenu MFM pour déclencher les animations",
"replies_in_timeline": "Réponses dans le flux",
"reply_visibility_all": "Montrer toutes les réponses",
"reply_visibility_following": "Afficher uniquement les réponses adressées à moi ou aux personnes que je suis",
@ -609,7 +615,10 @@
"settings": "Paramètres",
"show_admin_badge": "Afficher le badge d'Admin sur mon profil",
"show_moderator_badge": "Afficher le badge de Modo' sur mon profil",
"show_nav_shortcuts": "Afficher plus de raccourcis de navigations dans le panneau supérieur",
"show_panel_nav_shortcuts": "Afficher les raccourcis de navigation du flux dans le panneau supérieur",
"show_scrollbars": "Afficher la barre de défilement",
"show_wider_shortcuts": "Plus d'espace entre les raccourcis dans le panneau supérieur",
"show_yous": "Afficher « Vous : »",
"stop_gifs": "N'animer les GIFS que lors du survol du curseur de la souris",
"streaming": "Charger automatiquement les nouveaux statuts lorsque vous êtes au haut de la page",
@ -1004,4 +1013,4 @@
"more": "Plus",
"who_to_follow": "À qui s'abonner"
}
}
}

View file

@ -1,5 +1,7 @@
{
"about": {
"bubble_instances": "ローカルバブルのインスタンス",
"bubble_instances_description": "管理者がおすすめしているインスタンス",
"mrf": {
"federation": "連合",
"keyword": {
@ -21,8 +23,10 @@
"media_nsfw_desc": "このインスタンスでは、以下のインスタンスからの投稿に対して、メディアを閲覧注意に設定します:",
"media_removal": "メディア除去",
"media_removal_desc": "このインスタンスでは、以下のインスタンスからの投稿に対して、メディアを除去します:",
"not_applicable": "なし",
"quarantine": "検疫",
"quarantine_desc": "このインスタンスでは、以下のインスタンスに対して公開投稿のみを送信します:",
"quarantine_desc": "このインスタンスでは、以下のインスタンスに投稿を送信しません",
"reason": "理由",
"reject": "拒否",
"reject_desc": "このインスタンスでは、以下のインスタンスからのメッセージを受け付けません:",
"simple_policies": "インスタンス固有のポリシー"
@ -31,7 +35,23 @@
"staff": "スタッフ"
},
"announcements": {
"page_header": "お知らせ"
"all_day_prompt": "一日中",
"cancel_edit_action": "キャンセル",
"close_error": "閉じる",
"delete_action": "削除",
"edit_action": "更新",
"end_time_display": "{time}に終わる",
"end_time_prompt": "終了時間 ",
"mark_as_read_action": "読んだ",
"page_header": "お知らせ",
"post_action": "投稿",
"post_error": "エラーが発生しました: {error}",
"post_form_header": "お知らせ作成",
"post_placeholder": "コンテンツ",
"published_time_display": "{time}に告知されました",
"start_time_display": "{time}で始まる",
"start_time_prompt": "開始時間 ",
"title": "お知らせ"
},
"chats": {
"chats": "チャット一覧",
@ -113,6 +133,13 @@
"admin": "管理者",
"moderator": "モデレーター"
},
"scope_in_timeline": {
"direct": "ダイレクト",
"local": "ローカル:このインスタンスのユーザーしか見えません",
"private": "フォロワー限定",
"public": "公開",
"unlisted": "アンリステッド"
},
"show_less": "たたむ",
"show_more": "もっと見る",
"submit": "送信",
@ -135,6 +162,16 @@
"load_older": "古いインタラクションを見る",
"moves": "ユーザーの引っ越し"
},
"lists": {
"create": "作成",
"delete": "削除",
"following_only": "フォローしているユーザーのみ",
"lists": "リスト",
"new": "リスト作成",
"save": "OK",
"search": "ユーザー探索",
"title": "リスト名"
},
"login": {
"authentication_code": "認証コード",
"description": "OAuthでログイン",
@ -148,12 +185,14 @@
"login": "ログイン",
"logout": "ログアウト",
"password": "パスワード",
"placeholder": "例: lain",
"placeholder": "例: user",
"recovery_code": "リカバリーコード",
"register": "登録",
"username": "ユーザー名"
},
"media_modal": {
"counter": "{current} / {total}",
"hide": "閉じる",
"next": "次",
"previous": "前"
},
@ -185,18 +224,19 @@
"who_to_follow": "おすすめユーザー"
},
"notifications": {
"broken_favorite": "ステータスが見つかりません。探しています…",
"broken_favorite": "投稿が見つかりません。探しています…",
"error": "通知の取得に失敗しました: {0}",
"favorited_you": "あなたのステータスがお気に入りされました",
"favorited_you": "あなたの投稿がいいねされました",
"follow_request": "あなたをフォローしたいです",
"followed_you": "フォローされました",
"load_older": "古い通知をみる",
"migrated_to": "インスタンスを引っ越しました",
"no_more_notifications": "通知はありません",
"notifications": "通知",
"poll_ended": "投票終了",
"reacted_with": "{0} でリアクションしました",
"read": "読んだ!",
"repeated_you": "あなたのステータスがリピートされました"
"repeated_you": "あなたの投稿がリピートされました"
},
"password_reset": {
"check_email": "パスワードをリセットするためのリンクが記載されたメールが届いているか確認してください。",
@ -234,7 +274,8 @@
"text/bbcode": "BBCode",
"text/html": "HTML",
"text/markdown": "Markdown",
"text/plain": "プレーンテキスト"
"text/plain": "プレーンテキスト",
"text/x.misskeymarkdown": "MFM"
},
"content_warning": "説明 (省略可)",
"default": "羽田空港に着きました。",
@ -243,6 +284,7 @@
"empty_status_error": "投稿内容を入力してください",
"media_description": "メディアの説明",
"media_description_error": "メディアのアップロードに失敗しました。もう一度お試しください",
"media_not_sensitive_warning": "注意: 説明が付けていますがNSFW警告が付けていません",
"new_status": "投稿する",
"post": "投稿",
"posting": "投稿",
@ -256,6 +298,7 @@
"unlisted": "アンリステッド: 公開タイムラインに届きません"
},
"scope_notice": {
"local": "このインスタンスのユーザーしか見えません",
"private": "この投稿は、あなたのフォロワーだけが、見ることができます",
"public": "この投稿は、誰でも見ることができます",
"unlisted": "この投稿は、パブリックタイムラインと、接続しているすべてのネットワークには、表示されません"
@ -266,6 +309,7 @@
"bio_placeholder": "例:\nこんにちは。私は玲音。\n私はアニメのキャラクターで、日本の郊外に住んでいます。私をWiredで見たことがあるかもしれません。",
"captcha": "CAPTCHA",
"email": "Eメール",
"email_language": "サーバーからのメールの言語",
"fullname": "スクリーンネーム",
"fullname_placeholder": "例: 岩倉玲音",
"new_captcha": "文字が読めないときは、画像をクリックすると、新しい画像になります",
@ -302,6 +346,11 @@
},
"settings": {
"accent": "アクセント",
"account_backup": "アカウントのバックアップ",
"account_backup_description": "投稿やアカウント情報をダウンロードできますが、インポートすることがまだできません",
"account_backup_table_head": "バックアップ",
"account_privacy": "プライバシー",
"add_backup": "バックアップ作成",
"allow_following_move": "フォロー中のアカウントが引っ越したとき、自動フォローを許可する",
"always_show_post_button": "投稿ボタンを常に表示",
"app_name": "アプリの名称",
@ -335,8 +384,21 @@
"chatMessageRadius": "チャットメッセージ",
"checkboxRadius": "チェックボックス",
"collapse_subject": "説明のある投稿をたたむ",
"columns": "カラム",
"composing": "投稿",
"confirm_dialogs": "選択しているアクションは確認必要があります",
"confirm_dialogs_approve_follow": "フォローリクエストを受け入れること",
"confirm_dialogs_block": "ユーザーをブロックすること",
"confirm_dialogs_delete": "投稿を削除すること",
"confirm_dialogs_deny_follow": "フォローリクエストを断ること",
"confirm_dialogs_mute": "ユーザーをミュートすること",
"confirm_dialogs_repeat": "投稿をリピートすること",
"confirm_dialogs_unfollow": "フォローをやめること",
"confirm_new_password": "新しいパスワードの確認",
"confirmation_dialogs": "確認設定",
"conversation_display": "スレッドの表示モード",
"conversation_display_linear": "リニアー",
"conversation_display_tree": "ツリー",
"current_avatar": "現在のアバター",
"current_password": "現在のパスワード",
"data_import_export_tab": "インポートとエクスポート",
@ -348,6 +410,8 @@
"disable_sticky_headers": "ヘッダーを追従させない",
"discoverable": "検索などのサービスでこのアカウントを見つけることを許可する",
"domain_mutes": "ドメイン",
"download_backup": "ダウンロード",
"email_language": "メールの表示言語",
"emoji_reactions_on_timeline": "絵文字リアクションをタイムラインに表示",
"enable_web_push_notifications": "ウェブプッシュ通知を許可する",
"enter_current_password_to_confirm": "あなたのアイデンティティを証明するため、現在のパスワードを入力してください",
@ -399,7 +463,7 @@
"instance_default": "(デフォルト: {value})",
"instance_default_simple": "(デフォルト)",
"interface": "インターフェース",
"interfaceLanguage": "インターフェースの言語",
"interfaceLanguage": "表示言語",
"invalid_theme_imported": "このファイルはPleromaのテーマではありません。テーマは変更されませんでした。",
"limited_availability": "あなたのブラウザではできません",
"links": "リンク",
@ -876,4 +940,4 @@
"more": "詳細",
"who_to_follow": "おすすめユーザー"
}
}
}

View file

@ -1,9 +1,11 @@
{
"about": {
"bubble_instances": "Lokale Bubbel-instanties",
"bubble_instances_description": "Instanties die gekozen zijn door de beheerders om de lokale omgeving van deze instantie te representeren",
"mrf": {
"federation": "Federatie",
"keyword": {
"ftl_removal": "Verwijderen van \"Het Gehele Netwerk\" Tijdlijn",
"ftl_removal": "Verwijderen van \"Het Globale Netwerk\" Tijdlijn",
"is_replaced_by": "→",
"keyword_policies": "Zoekwoordbeleid",
"reject": "Afwijzen",
@ -14,10 +16,10 @@
"simple": {
"accept": "Accepteren",
"accept_desc": "Deze instantie accepteert alleen berichten van de volgende instanties:",
"ftl_removal": "Verwijderen van \"Bekende Netwerk\" Tijdlijn",
"ftl_removal_desc": "Deze instantie verwijdert de volgende instanties van \"Bekende Netwerk\" tijdlijn:",
"ftl_removal": "Verwijderen van \"Globale Netwerk\" Tijdlijn",
"ftl_removal_desc": "Deze instantie verwijdert de volgende instanties van \"Globale Netwerk\" tijdlijn:",
"instance": "Instantie",
"media_nsfw": "Media als gevoelig forceren",
"media_nsfw": "Media als gevoelig markeren",
"media_nsfw_desc": "Deze instantie markeert media als gevoelig in berichten van de volgende instanties:",
"media_removal": "Verwijderen van media",
"media_removal_desc": "Deze instantie verwijdert media van berichten van de volgende instanties:",
@ -26,8 +28,8 @@
"quarantine_desc": "Deze instantie zal géén berichten sturen naar de volgende instanties:",
"reason": "Reden",
"reject": "Afwijzen",
"reject_desc": "Deze instantie zal geen berichten accepteren van de volgende instanties:",
"simple_policies": "Instantiespecifieke regels"
"reject_desc": "Deze instantie zal géén berichten accepteren van de volgende instanties:",
"simple_policies": "Instantie-specifieke regels"
}
},
"staff": "Personeel"
@ -219,15 +221,15 @@
"search": "Zoeken",
"timeline": "Tijdlijn",
"timelines": "Tijdlijnen",
"twkn": "Bekende Netwerk",
"twkn_timeline_description": "Berichten van het gehele netwerk",
"twkn": "Globale Netwerk",
"twkn_timeline_description": "Berichten van het globale netwerk",
"user_search": "Gebruiker Zoeken",
"who_to_follow": "Wie te volgen"
},
"notifications": {
"broken_favorite": "Onbekend bericht, aan het zoeken…",
"error": "Fout bij ophalen van meldingen: {0}",
"favorited_you": "vond je status leuk",
"favorited_you": "vond je bericht leuk",
"follow_request": "wil je volgen",
"followed_you": "volgt jou",
"load_older": "Oudere meldingen laden",
@ -243,10 +245,10 @@
"check_email": "Controleer je email inbox voor een link om je wachtwoord opnieuw in te stellen.",
"forgot_password": "Wachtwoord vergeten?",
"instruction": "Voer je email adres of gebruikersnaam in. We sturen je een link om je wachtwoord opnieuw in te stellen.",
"password_reset": "Wachtwoord opnieuw instellen",
"password_reset_disabled": "Wachtwoord reset is uitgeschakeld. Neem contact op met de beheerder van deze instantie.",
"password_reset": "Wachtwoord herstellen",
"password_reset_disabled": "Wachtwoordherstel is uitgeschakeld. Neem contact op met de beheerder van deze instantie.",
"password_reset_required": "Je dient je wachtwoord opnieuw in te stellen om in te kunnen loggen.",
"password_reset_required_but_mailer_is_disabled": "Je dient je wachtwoord opnieuw in te stellen, maar wachtwoord reset is uitgeschakeld. Neem contact op met de beheerder van deze instantie.",
"password_reset_required_but_mailer_is_disabled": "Je dient je wachtwoord opnieuw in te stellen, maar wachtwoordherstel is uitgeschakeld. Neem contact op met de beheerder van deze instantie.",
"placeholder": "Je email of gebruikersnaam",
"return_home": "Terugkeren naar de home pagina",
"too_many_requests": "Je hebt het maximaal aantal pogingen bereikt, probeer het later opnieuw."
@ -282,13 +284,13 @@
"default": "Zojuist gearriveerd op de Zweinstein Hogeschool",
"direct_warning_to_all": "Dit bericht zal zichtbaar zijn voor alle vermelde gebruikers.",
"direct_warning_to_first_only": "Dit bericht zal alleen zichtbaar zijn voor de vermelde gebruikers aan het begin van het bericht.",
"empty_status_error": "Kan geen lege status zonder bijlagen plaatsen",
"empty_status_error": "Kan geen leeg bericht zonder bijlagen plaatsen",
"media_description": "Mediaomschrijving",
"media_description_error": "Kon media niet ophalen, probeer het opnieuw",
"media_not_sensitive_warning": "Je hebt een Content Waarschuwing, maar de bijlagen zijn niet gemarkeerd als gevoelig!",
"new_status": "Nieuw bericht plaatsen",
"post": "Plaatsen",
"posting": "Plaatsen...",
"posting": "Aan het plaatsen",
"preview": "Voorbeeld",
"preview_empty": "Leeg",
"scope": {
@ -302,7 +304,7 @@
"local": "Dit bericht zal niet zichtbaar zijn op andere instanties",
"private": "Dit bericht zal voor alleen je volgers zichtbaar zijn",
"public": "Dit bericht zal voor iedereen zichtbaar zijn",
"unlisted": "Dit bericht zal niet zichtbaar zijn in de Openbare Tijdlijn en Het Gehele Netwerk"
"unlisted": "Dit bericht zal niet zichtbaar zijn in de Openbare Tijdlijn en Het Globale Netwerk"
}
},
"registration": {
@ -359,11 +361,11 @@
"added_alias": "Alias is toegevoegd.",
"added_backup": "Nieuwe back-up is toegevoegd.",
"allow_following_move": "Automatisch volgen toestaan wanneer een gevolgd account verhuist",
"always_show_post_button": "Altijd de zwevende Nieuw Bericht knop tonen",
"always_show_post_button": "Altijd de zwevende \"Bericht opstellen\"-knop tonen",
"app_name": "App naam",
"attachmentRadius": "Bijlagen",
"attachments": "Bijlagen",
"autohide_floating_post_button": "Nieuw Bericht knop automatisch verbergen (mobiel)",
"autohide_floating_post_button": "\"Bericht opstellen\"-knop automatisch verbergen (mobiel)",
"avatar": "Avatar",
"avatarAltRadius": "Avatars (meldingen)",
"avatarRadius": "Avatars",
@ -413,7 +415,7 @@
"discoverable": "Sta toe dat dit account ontdekt kan worden in zoekresultaten en andere diensten",
"domain_mutes": "Domeinen",
"download_backup": "Downloaden",
"email_language": "Taal voor emails van de server",
"email_language": "Taal voor e-mails van de server",
"emoji_reactions_on_timeline": "Toon emoji-reacties op de tijdlijn",
"enable_web_push_notifications": "Web push meldingen inschakelen",
"enter_current_password_to_confirm": "Voer je huidige wachtwoord in om je identiteit te bevestigen",
@ -459,6 +461,8 @@
"hide_muted_threads": "Genegeerde gesprekken verbergen",
"hide_post_stats": "Bericht-statistieken verbergen (bijv. het aantal favorieten)",
"hide_shoutbox": "Shoutbox verbergen",
"hide_site_favicon": "Favicon verbergen in top-paneel",
"hide_site_name": "Instantienaam verbergen in top paneel",
"hide_threads_with_blocked_users": "Gesprekken met geblokkeerde gebruikers verbergen",
"hide_user_stats": "Gebruikers-statistieken verbergen (bijv. het aantal volgers)",
"hide_wallpaper": "Achtergrond-afbeelding verbergen",
@ -559,7 +563,7 @@
"pause_on_unfocused": "Streamen pauzeren wanneer de tab niet in focus is",
"play_videos_in_modal": "Video's in een popup venster afspelen",
"post_look_feel": "Berichten Look & Feel",
"post_status_content_type": "Standaard bericht content type",
"post_status_content_type": "Standaard bericht content type",
"posts": "Berichten",
"preload_images": "Afbeeldingen vooraf laden",
"presets": "Presets",
@ -577,6 +581,7 @@
"remove_alias": "Deze alias verwijderen",
"remove_backup": "Verwijderen",
"render_mfm": "Misskey Markdown weergeven",
"render_mfm_on_hover": "MFM animaties afspelen bij zweven over bericht",
"replies_in_timeline": "Antwoorden in tijdlijn",
"reply_visibility_all": "Alle antwoorden tonen",
"reply_visibility_following": "Enkel antwoorden tonen die aan mij of gevolgde gebruikers gericht zijn",
@ -610,7 +615,10 @@
"settings": "Instellingen",
"show_admin_badge": "\"Beheerder\" badge in mijn profiel tonen",
"show_moderator_badge": "\"Moderator\" badge in mijn profiel tonen",
"show_nav_shortcuts": "Extra navigatie snelkoppelingen tonen in top paneel",
"show_panel_nav_shortcuts": "Tijdlijn navigatie-snelkoppelingen tonen bovenop het paneel",
"show_scrollbars": "Scrollbalk tonen in zijkolommen",
"show_wider_shortcuts": "Extra ruimte tonen tussen snelkoppelingen in top paneel",
"show_yous": "(Jij)'s tonen",
"stop_gifs": "Geanimeerde afbeeldingen afspelen bij zweven",
"streaming": "Automatisch streamen van nieuwe berichten inschakelen wanneer tot boven gescrold is",
@ -777,10 +785,11 @@
"token": "Token",
"tooltipRadius": "Tooltips/alarmen",
"tree_advanced": "Flexibelere navigatie toestaan in boom weergave",
"tree_fade_ancestors": "Ouders van huidige bericht met gedempte tekst tonen",
"type_domains_to_mute": "Zoek domeinen om te negeren",
"upload_a_photo": "Foto uploaden",
"useStreamingApi": "Berichten en meldingen in real-time ontvangen",
"useStreamingApiWarning": "Iets experimenteels met berichten streamen uwu miss kun je beter uit laten ofzo",
"useStreamingApiWarning": "Iets experimenteels met berichten streamen uwu miss kun je beter uit laten ofzo?",
"use_at_icon": "{'@'} symbool als icoon tonen in plaats van tekst",
"use_contain_fit": "Bijlage in miniaturen niet bijsnijden",
"use_one_click_nsfw": "Gevoelige bijlagen met slechts één klik openen",
@ -802,6 +811,7 @@
"wordfilter": "Woordfilter"
},
"status": {
"ancestor_follow": "{numReplies} ander antwoord onder dit bericht tonen | {numReplies} andere antwoorden onder dit bericht tonen",
"ancestor_follow_with_icon": "{icon} {text}",
"attachment_stop_flash": "Flash speler stoppen",
"bookmark": "Bladwijzer toevoegen",

View file

@ -40,6 +40,11 @@ export const defaultState = {
collapseMessageWithSubject: undefined, // instance default
padEmoji: true,
swapReacts: true,
showNavShortcuts: undefined, // instance default
showPanelNavShortcuts: undefined, // instance default
showWiderShortcuts: undefined, // instance default
hideSiteFavicon: undefined, // instance default
hideSiteName: undefined, // instance default
hideAttachments: false,
hideAttachmentsInConv: false,
maxThumbnails: 16,
@ -80,6 +85,14 @@ export const defaultState = {
minimalScopesMode: undefined, // instance default
// This hides statuses filtered via a word filter
hideFilteredStatuses: undefined, // instance default
modalOnRepeat: undefined, // instance default
modalOnUnfollow: undefined, // instance default
modalOnBlock: undefined, // instance default
modalOnMute: undefined, // instance default
modalOnDelete: undefined, // instance default
modalOnLogout: undefined, // instance default
modalOnApproveFollow: undefined, // instance default
modalOnDenyFollow: undefined, // instance default
playVideosInModal: false,
useOneClickNsfw: false,
useContainFit: true,
@ -100,6 +113,7 @@ export const defaultState = {
sensitiveByDefault: undefined, // instance default
sensitiveIfSubject: undefined,
renderMisskeyMarkdown: undefined,
renderMfmOnHover: undefined, // instance default
conversationDisplay: undefined, // instance default
conversationTreeAdvanced: undefined, // instance default
conversationOtherRepliesButton: undefined, // instance default

View file

@ -34,9 +34,18 @@ const defaultState = {
hideWordFilteredPosts: false,
hidePostStats: false,
hideBotIndication: false,
hideSitename: false,
hideSiteFavicon: false,
hideSiteName: false,
hideUserStats: false,
muteBotStatuses: false,
modalOnRepeat: false,
modalOnUnfollow: false,
modalOnBlock: true,
modalOnMute: false,
modalOnDelete: true,
modalOnLogout: true,
modalOnApproveFollow: false,
modalOnDenyFollow: false,
loginMethod: 'password',
logo: '/static/logo.svg',
logoMargin: '.2em',
@ -50,13 +59,16 @@ const defaultState = {
scopeCopy: true,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
showNavShortcuts: true,
showWiderShortcuts: true,
sidebarRight: false,
subjectLineBehavior: 'email',
theme: 'pleroma-dark',
virtualScrolling: true,
sensitiveByDefault: false,
sensitiveIfSubject: true,
renderMisskeyMarkdown: false,
renderMisskeyMarkdown: true,
renderMfmOnHover: false,
conversationDisplay: 'linear',
conversationTreeAdvanced: false,
conversationOtherRepliesButton: 'below',

View file

@ -49,7 +49,7 @@ const fetchAndUpdate = ({
args['listId'] = listId
args['tag'] = tag
args['withMuted'] = !hideMutedPosts
if (loggedIn && ['friends', 'public', 'publicAndExternal'].includes(timeline)) {
if (loggedIn && ['friends', 'public', 'publicAndExternal', 'bubble'].includes(timeline)) {
args['replyVisibility'] = replyVisibility
}

View file

@ -1085,6 +1085,11 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
"@fortawesome/fontawesome-common-types@6.1.2":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.2.tgz#c1095b1bbabf19f37f9ff0719db38d92a410bcfe"
integrity sha512-wBaAPGz1Awxg05e0PBRkDRuTsy4B3dpBm+zreTTyd9TH4uUM27cAL4xWyWR0rLJCrRwzVsQ4hF3FvM6rqydKPA==
"@fortawesome/fontawesome-common-types@^0.2.36":
version "0.2.36"
resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz#b44e52db3b6b20523e0c57ef8c42d315532cb903"
@ -1102,12 +1107,12 @@
dependencies:
"@fortawesome/fontawesome-common-types" "^0.3.0"
"@fortawesome/free-regular-svg-icons@5.15.4":
version "5.15.4"
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz#b97edab436954333bbeac09cfc40c6a951081a02"
integrity sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==
"@fortawesome/free-regular-svg-icons@^6.1.2":
version "6.1.2"
resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.1.2.tgz#9f04009098addcc11d0d185126f058ed042c3099"
integrity sha512-xR4hA+tAwsaTHGfb+25H1gVU/aJ0Rzu+xIUfnyrhaL13yNQ7TWiI2RvzniAaB+VGHDU2a+Pk96Ve+pkN3/+TTQ==
dependencies:
"@fortawesome/fontawesome-common-types" "^0.2.36"
"@fortawesome/fontawesome-common-types" "6.1.2"
"@fortawesome/free-solid-svg-icons@5.15.4":
version "5.15.4"