Page MenuHomePhorge

No OneTemporary

Size
41 KB
Referenced Files
None
Subscribers
None
diff --git a/src/components/mention_link/mention_link.js b/src/components/mention_link/mention_link.js
index d4d8e0f96b..ca5c24618f 100644
--- a/src/components/mention_link/mention_link.js
+++ b/src/components/mention_link/mention_link.js
@@ -1,158 +1,155 @@
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { mapGetters, mapState } from 'vuex'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import UserAvatar from '../user_avatar/user_avatar.vue'
import UnicodeDomainIndicator from '../unicode_domain_indicator/unicode_domain_indicator.vue'
import { defineAsyncComponent } from 'vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faAt
} from '@fortawesome/free-solid-svg-icons'
library.add(
faAt
)
const MentionLink = {
name: 'MentionLink',
components: {
UserAvatar,
UnicodeDomainIndicator,
UserPopover: defineAsyncComponent(() => import('../user_popover/user_popover.vue'))
},
props: {
url: {
required: true,
type: String
},
content: {
required: true,
type: String
},
userId: {
required: false,
type: String
},
userScreenName: {
required: false,
type: String
}
},
data () {
return {
hasSelection: false
}
},
methods: {
onClick () {
if (this.shouldShowTooltip) return
const link = generateProfileLink(
this.userId || this.user.id,
this.userScreenName || this.user.screen_name
)
this.$router.push(link)
},
handleSelection () {
if (this.$refs.full) {
this.hasSelection = document.getSelection().containsNode(this.$refs.full, true)
}
}
},
mounted () {
document.addEventListener('selectionchange', this.handleSelection)
},
unmounted () {
document.removeEventListener('selectionchange', this.handleSelection)
},
computed: {
user () {
return this.url && this.$store && this.$store.getters.findUserByUrl(this.url)
},
isYou () {
// FIXME why user !== currentUser???
return this.user && this.user.id === this.currentUser.id
},
userName () {
return this.user && this.userNameFullUi.split('@')[0]
},
serverName () {
// XXX assumed that domain does not contain @
return this.user && (this.userNameFullUi.split('@')[1] || this.$store.getters.instanceDomain)
},
userNameFull () {
return this.user && this.user.screen_name
},
userNameFullUi () {
return this.user && this.user.screen_name_ui
},
highlight () {
return this.user && this.mergedConfig.highlight[this.user.screen_name]
},
highlightType () {
return this.highlight && ('-' + this.highlight.type)
},
highlightClass () {
if (this.highlight) return highlightClass(this.user)
},
style () {
if (this.highlight) {
/* eslint-disable no-unused-vars */
const {
backgroundColor,
backgroundPosition,
backgroundImage,
...rest
} = highlightStyle(this.highlight)
/* eslint-enable no-unused-vars */
return rest
}
},
classnames () {
return [
{
'-you': this.isYou && this.shouldBoldenYou,
'-highlighted': this.highlight,
'-has-selection': this.hasSelection
},
this.highlightType
]
},
- useAtIcon () {
- return this.mergedConfig.useAtIcon
- },
isRemote () {
return this.userName !== this.userNameFull
},
shouldShowFullUserName () {
const conf = this.mergedConfig.mentionLinkDisplay
if (conf === 'short') {
return false
} else if (conf === 'full') {
return true
} else { // full_for_remote
return this.isRemote
}
},
shouldShowTooltip () {
return this.mergedConfig.mentionLinkShowTooltip
},
shouldShowAvatar () {
return this.mergedConfig.mentionLinkShowAvatar
},
shouldShowYous () {
return this.mergedConfig.mentionLinkShowYous
},
shouldBoldenYou () {
return this.mergedConfig.mentionLinkBoldenYou
},
shouldFadeDomain () {
return this.mergedConfig.mentionLinkFadeDomain
},
...mapGetters(['mergedConfig']),
...mapState({
currentUser: state => state.users.currentUser
})
}
}
export default MentionLink
diff --git a/src/components/mention_link/mention_link.vue b/src/components/mention_link/mention_link.vue
index 5db837a256..0452cad58c 100644
--- a/src/components/mention_link/mention_link.vue
+++ b/src/components/mention_link/mention_link.vue
@@ -1,75 +1,70 @@
<template>
<span
class="MentionLink"
>
<!-- eslint-disable vue/no-v-html -->
<a
v-if="!user"
:href="url"
class="original"
target="_blank"
v-html="content"
/><!-- eslint-enable vue/no-v-html -->
<UserPopover
v-else
:user-id="user.id"
:disabled="!shouldShowTooltip"
>
<span
v-if="user"
class="new"
:style="style"
:class="classnames"
>
<a
class="short"
:class="{ '-with-tooltip': shouldShowTooltip }"
:href="url"
@click.prevent="onClick"
>
<!-- eslint-disable vue/no-v-html -->
<UserAvatar
v-if="shouldShowAvatar"
class="mention-avatar"
:user="user"
/><span
class="shortName"
- ><FAIcon
- v-if="useAtIcon"
- size="sm"
- icon="at"
- class="at"
- />{{ !useAtIcon ? '@' : '' }}<span
+ >@<span
class="userName"
v-html="userName"
/><span
v-if="shouldShowFullUserName"
class="serverName"
:class="{ '-faded': shouldFadeDomain }"
v-html="'@' + serverName"
/><UnicodeDomainIndicator
v-if="shouldShowFullUserName"
:user="user"
/>
</span>
<span
v-if="isYou && shouldShowYous"
:class="{ '-you': shouldBoldenYou }"
> {{ ' ' + $t('status.you') }}</span>
<!-- eslint-enable vue/no-v-html -->
</a><span
ref="full"
class="full"
>
<!-- eslint-disable vue/no-v-html -->
@<span v-html="userName" /><span v-html="'@' + serverName" />
<!-- eslint-enable vue/no-v-html -->
</span>
</span>
</UserPopover>
</span>
</template>
<script src="./mention_link.js" />
<style lang="scss" src="./mention_link.scss" />
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index c8db96c5e7..02396114f8 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -1,523 +1,515 @@
<template>
<div :label="$t('settings.general')">
<div class="setting-item">
<h2>{{ $t('settings.interface') }}</h2>
<ul class="setting-list">
<li>
<interface-language-switcher
:prompt-text="$t('settings.interfaceLanguage')"
:language="language"
:set-language="val => language = val"
/>
</li>
<li v-if="instanceSpecificPanelPresent">
<BooleanSetting path="hideISP">
{{ $t('settings.hide_isp') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="streaming">
{{ $t('settings.streaming') }}
</BooleanSetting>
<ul class="setting-list suboptions">
<li>
<BooleanSetting
path="pauseOnUnfocused"
parent-path="streaming"
>
{{ $t('settings.pause_on_unfocused') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting
path="useStreamingApi"
expert="1"
>
{{ $t('settings.useStreamingApi') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="virtualScrolling"
expert="1"
>
{{ $t('settings.virtual_scrolling') }}
</BooleanSetting>
</li>
<li>
<ChoiceSetting
id="userPopoverAvatarAction"
path="userPopoverAvatarAction"
:options="userPopoverAvatarActionOptions"
expert="1"
>
{{ $t('settings.user_popover_avatar_action') }}
</ChoiceSetting>
</li>
<li>
<BooleanSetting
path="userPopoverOverlay"
expert="1"
>
{{ $t('settings.user_popover_avatar_overlay') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowNewPostButton"
expert="1"
>
{{ $t('settings.always_show_post_button') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="autohideFloatingPostButton"
expert="1"
>
{{ $t('settings.autohide_floating_post_button') }}
</BooleanSetting>
</li>
<li v-if="instanceShoutboxPresent">
<BooleanSetting
path="hideShoutbox"
expert="1"
>
{{ $t('settings.hide_shoutbox') }}
</BooleanSetting>
</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="modalOnMuteConversation">
{{ $t('settings.confirm_dialogs_mute_conversation') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnMuteDomain">
{{ $t('settings.confirm_dialogs_mute_domain') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnDelete">
{{ $t('settings.confirm_dialogs_delete') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="modalOnLogout">
{{ $t('settings.confirm_dialogs_logout') }}
</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>
<li>
<BooleanSetting path="modalOnRemoveUserFromFollowers">
{{ $t('settings.confirm_dialogs_remove_follower') }}
</BooleanSetting>
</li>
</ul>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.post_look_feel') }}</h2>
<ul class="setting-list">
<li>
<ChoiceSetting
id="conversationDisplay"
path="conversationDisplay"
:options="conversationDisplayOptions"
>
{{ $t('settings.conversation_display') }}
</ChoiceSetting>
</li>
<ul
v-if="mergedConfig.conversationDisplay !== 'linear'"
class="setting-list suboptions"
>
<li>
<BooleanSetting path="conversationTreeAdvanced">
{{ $t('settings.tree_advanced') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="conversationTreeFadeAncestors"
:expert="1"
>
{{ $t('settings.tree_fade_ancestors') }}
</BooleanSetting>
</li>
<li>
<IntegerSetting
path="maxDepthInThread"
:min="3"
:expert="1"
>
{{ $t('settings.max_depth_in_thread') }}
</IntegerSetting>
</li>
<li>
<ChoiceSetting
id="conversationOtherRepliesButton"
path="conversationOtherRepliesButton"
:options="conversationOtherRepliesButtonOptions"
:expert="1"
>
{{ $t('settings.conversation_other_replies_button') }}
</ChoiceSetting>
</li>
</ul>
<li>
<BooleanSetting path="collapseMessageWithSubject">
{{ $t('settings.collapse_subject') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="emojiReactionsOnTimeline"
expert="1"
>
{{ $t('settings.emoji_reactions_on_timeline') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
v-if="user"
source="profile"
path="stripRichContent"
expert="1"
>
{{ $t('settings.no_rich_text_description') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="useAbsoluteTimeFormat"
expert="1"
>
{{ $t('settings.absolute_time_format') }}
</BooleanSetting>
</li>
<ul
v-if="mergedConfig.useAbsoluteTimeFormat"
class="setting-list suboptions"
>
<li>
<UnitSetting
path="absoluteTimeFormatMinAge"
unit-set="time"
:units="['s', 'm', 'h', 'd']"
:min="0"
>
{{ $t('settings.absolute_time_format_min_age') }}
</UnitSetting>
</li>
<li>
<ChoiceSetting
id="absoluteTime12h"
path="absoluteTime12h"
:options="absoluteTime12hOptions"
:expert="1"
>
{{ $t('settings.absolute_time_format_12h') }}
</ChoiceSetting>
</li>
</ul>
<h3>{{ $t('settings.attachments') }}</h3>
<li>
<BooleanSetting
path="imageCompression"
expert="1"
>
{{ $t('settings.image_compression') }}
</BooleanSetting>
</li>
<ul class="setting-list suboptions">
<li>
<BooleanSetting
path="alwaysUseJpeg"
expert="1"
parent-path="imageCompression"
>
{{ $t('settings.always_use_jpeg') }}
</BooleanSetting>
</li>
</ul>
<li>
<BooleanSetting
path="useContainFit"
expert="1"
>
{{ $t('settings.use_contain_fit') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="hideNsfw">
{{ $t('settings.nsfw_clickthrough') }}
</BooleanSetting>
</li>
<ul class="setting-list suboptions">
<li>
<BooleanSetting
path="preloadImage"
expert="1"
parent-path="hideNsfw"
>
{{ $t('settings.preload_images') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="useOneClickNsfw"
expert="1"
parent-path="hideNsfw"
>
{{ $t('settings.use_one_click_nsfw') }}
</BooleanSetting>
</li>
</ul>
<li>
<BooleanSetting
path="loopVideo"
expert="1"
>
{{ $t('settings.loop_video') }}
</BooleanSetting>
<ul class="setting-list suboptions">
<li>
<BooleanSetting
path="loopVideoSilentOnly"
expert="1"
parent-path="loopVideo"
:disabled="!loopSilentAvailable"
>
{{ $t('settings.loop_video_silent_only') }}
</BooleanSetting>
<div
v-if="!loopSilentAvailable"
class="unavailable"
>
<FAIcon icon="globe" />! {{ $t('settings.limited_availability') }}
</div>
</li>
</ul>
</li>
<li>
<BooleanSetting
path="playVideosInModal"
expert="1"
>
{{ $t('settings.play_videos_in_modal') }}
</BooleanSetting>
</li>
<h3>{{ $t('settings.mention_links') }}</h3>
<li>
<ChoiceSetting
id="mentionLinkDisplay"
path="mentionLinkDisplay"
:options="mentionLinkDisplayOptions"
>
{{ $t('settings.mention_link_display') }}
</ChoiceSetting>
</li>
<li>
<BooleanSetting
path="mentionLinkShowTooltip"
expert="1"
>
{{ $t('settings.mention_link_use_tooltip') }}
</BooleanSetting>
</li>
- <li>
- <BooleanSetting
- path="useAtIcon"
- expert="1"
- >
- {{ $t('settings.use_at_icon') }}
- </BooleanSetting>
- </li>
<li>
<BooleanSetting path="mentionLinkShowAvatar">
{{ $t('settings.mention_link_show_avatar') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="mentionLinkFadeDomain"
expert="1"
>
{{ $t('settings.mention_link_fade_domain') }}
</BooleanSetting>
</li>
<li v-if="user">
<BooleanSetting
path="mentionLinkBoldenYou"
expert="1"
>
{{ $t('settings.mention_link_bolden_you') }}
</BooleanSetting>
</li>
<h3 v-if="expertLevel > 0">
{{ $t('settings.fun') }}
</h3>
<li>
<BooleanSetting
path="greentext"
expert="1"
>
{{ $t('settings.greentext') }}
</BooleanSetting>
</li>
<li v-if="user">
<BooleanSetting
path="mentionLinkShowYous"
expert="1"
>
{{ $t('settings.show_yous') }}
</BooleanSetting>
</li>
</ul>
</div>
<div
v-if="user"
class="setting-item"
>
<h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list">
<li>
<label for="default-vis">
{{ $t('settings.default_vis') }} <ProfileSettingIndicator :is-profile="true" />
<ScopeSelector
class="scope-selector"
:show-all="true"
:user-default="$store.state.profileConfig.defaultScope"
:initial-scope="$store.state.profileConfig.defaultScope"
:on-scope-change="changeDefaultScope"
/>
</label>
</li>
<li>
<!-- <BooleanSetting source="profile" path="defaultNSFW"> -->
<BooleanSetting path="sensitiveByDefault">
{{ $t('settings.sensitive_by_default') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="scopeCopy"
expert="1"
>
{{ $t('settings.scope_copy') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowSubjectInput"
expert="1"
>
{{ $t('settings.subject_input_always_show') }}
</BooleanSetting>
</li>
<li>
<ChoiceSetting
id="subjectLineBehavior"
path="subjectLineBehavior"
:options="subjectLineOptions"
expert="1"
>
{{ $t('settings.subject_line_behavior') }}
</ChoiceSetting>
</li>
<li v-if="postFormats.length > 0">
<ChoiceSetting
id="postContentType"
path="postContentType"
:options="postContentOptions"
>
{{ $t('settings.post_status_content_type') }}
</ChoiceSetting>
</li>
<li>
<BooleanSetting
path="minimalScopesMode"
expert="1"
>
{{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="padEmoji"
expert="1"
>
{{ $t('settings.pad_emoji') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="autocompleteSelect"
expert="1"
>
{{ $t('settings.autocomplete_select_first') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="autoSaveDraft"
>
{{ $t('settings.auto_save_draft') }}
</BooleanSetting>
</li>
<li v-if="!mergedConfig.autoSaveDraft">
<ChoiceSetting
id="unsavedPostAction"
path="unsavedPostAction"
:options="unsavedPostActionOptions"
>
{{ $t('settings.unsaved_post_action') }}
</ChoiceSetting>
</li>
</ul>
</div>
</div>
</template>
<script src="./general_tab.js"></script>
diff --git a/src/modules/default_config_state.js b/src/modules/default_config_state.js
index 388eb50996..2baa752a65 100644
--- a/src/modules/default_config_state.js
+++ b/src/modules/default_config_state.js
@@ -1,165 +1,164 @@
const browserLocale = (window.navigator.language || 'en').split('-')[0]
export const defaultState = {
expertLevel: 0, // used to track which settings to show and hide
// Theme stuff
theme: undefined, // Very old theme store, stores preset name, still in use
// V1
colors: {}, // VERY old theme store, just colors of V1, probably not even used anymore
// V2
customTheme: undefined, // "snapshot", previously was used as actual theme store for V2 so it's still used in case of PleromaFE downgrade event.
customThemeSource: undefined, // "source", stores original theme data
// V3
style: null,
styleCustomData: null,
palette: null,
paletteCustomData: null,
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
theme3hacks: { // Hacks, user overrides that are independent of theme used
underlay: 'none',
fonts: {
interface: undefined,
input: undefined,
post: undefined,
monospace: undefined
}
},
hideISP: false,
hideInstanceWallpaper: false,
hideShoutbox: false,
// bad name: actually hides posts of muted USERS
hideMutedPosts: undefined, // instance default
hideMutedThreads: undefined, // instance default
hideWordFilteredPosts: undefined, // instance default
muteBotStatuses: undefined, // instance default
muteSensitiveStatuses: undefined, // instance default
collapseMessageWithSubject: undefined, // instance default
padEmoji: true,
hideAttachments: false,
hideAttachmentsInConv: false,
hideScrobbles: false,
hideScrobblesAfter: '2d',
maxThumbnails: 16,
hideNsfw: true,
preloadImage: true,
loopVideo: true,
loopVideoSilentOnly: true,
streaming: false,
emojiReactionsOnTimeline: true,
alwaysShowNewPostButton: false,
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
stopGifs: true,
replyVisibility: 'all',
thirdColumnMode: 'notifications',
notificationVisibility: {
follows: true,
mentions: true,
statuses: true,
likes: true,
repeats: true,
moves: true,
emojiReactions: true,
followRequest: true,
reports: true,
chatMention: true,
polls: true
},
notificationNative: {
follows: true,
mentions: true,
statuses: true,
likes: false,
repeats: false,
moves: false,
emojiReactions: false,
followRequest: true,
reports: true,
chatMention: true,
polls: true
},
webPushNotifications: false,
webPushAlwaysShowNotifications: false,
muteWords: [],
highlight: {},
interfaceLanguage: browserLocale,
hideScopeNotice: false,
useStreamingApi: false,
sidebarRight: undefined, // instance default
scopeCopy: undefined, // instance default
subjectLineBehavior: undefined, // instance default
alwaysShowSubjectInput: undefined, // instance default
postContentType: undefined, // instance default
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
modalOnMuteConversation: undefined, // instance default
modalOnMuteDomain: undefined, // instance default
modalOnDelete: undefined, // instance default
modalOnLogout: undefined, // instance default
modalOnApproveFollow: undefined, // instance default
modalOnDenyFollow: undefined, // instance default
modalOnRemoveUserFromFollowers: undefined, // instance default
modalMobileCenter: undefined,
playVideosInModal: false,
useOneClickNsfw: false,
useContainFit: true,
disableStickyHeaders: false,
showScrollbars: false,
userPopoverAvatarAction: 'open',
userPopoverOverlay: false,
sidebarColumnWidth: '25rem',
contentColumnWidth: '45rem',
notifsColumnWidth: '25rem',
emojiReactionsScale: undefined,
textSize: undefined, // instance default
emojiSize: undefined, // instance default
navbarSize: undefined, // instance default
panelHeaderSize: undefined, // instance default
forcedRoundness: undefined, // instance default
navbarColumnStretch: false,
greentext: undefined, // instance default
- useAtIcon: undefined, // instance default
mentionLinkDisplay: undefined, // instance default
mentionLinkShowTooltip: undefined, // instance default
mentionLinkShowAvatar: undefined, // instance default
mentionLinkFadeDomain: undefined, // instance default
mentionLinkShowYous: undefined, // instance default
mentionLinkBoldenYou: undefined, // instance default
hidePostStats: undefined, // instance default
hideBotIndication: undefined, // instance default
hideUserStats: undefined, // instance default
virtualScrolling: undefined, // instance default
sensitiveByDefault: undefined, // instance default
conversationDisplay: undefined, // instance default
conversationTreeAdvanced: undefined, // instance default
conversationOtherRepliesButton: undefined, // instance default
conversationTreeFadeAncestors: undefined, // instance default
showExtraNotifications: undefined, // instance default
showExtraNotificationsTip: undefined, // instance default
showChatsInExtraNotifications: undefined, // instance default
showAnnouncementsInExtraNotifications: undefined, // instance default
showFollowRequestsInExtraNotifications: undefined, // instance default
maxDepthInThread: undefined, // instance default
autocompleteSelect: undefined, // instance default
closingDrawerMarksAsSeen: undefined, // instance default
unseenAtTop: undefined, // instance default
ignoreInactionableSeen: undefined, // instance default
unsavedPostAction: undefined, // instance default
autoSaveDraft: undefined, // instance default
useAbsoluteTimeFormat: undefined, // instance default
absoluteTimeFormatMinAge: undefined, // instance default
absoluteTime12h: undefined, // instance default
imageCompression: true,
alwaysUseJpeg: false
}
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 6f12089f47..38f6e76790 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -1,414 +1,413 @@
import apiService from '../services/api/api.service.js'
import { instanceDefaultProperties } from './config.js'
import { langCodeToCldrName, ensureFinalFallback } from '../i18n/languages.js'
import { useInterfaceStore } from 'src/stores/interface.js'
const SORTED_EMOJI_GROUP_IDS = [
'smileys-and-emotion',
'people-and-body',
'animals-and-nature',
'food-and-drink',
'travel-and-places',
'activities',
'objects',
'symbols',
'flags'
]
const REGIONAL_INDICATORS = (() => {
const start = 0x1F1E6
const end = 0x1F1FF
const A = 'A'.codePointAt(0)
const res = new Array(end - start + 1)
for (let i = start; i <= end; ++i) {
const letter = String.fromCodePoint(A + i - start)
res[i - start] = {
replacement: String.fromCodePoint(i),
imageUrl: false,
displayText: 'regional_indicator_' + letter,
displayTextI18n: {
key: 'emoji.regional_indicator',
args: { letter }
}
}
}
return res
})()
const REMOTE_INTERACTION_URL = '/main/ostatus'
const defaultState = {
// Stuff from apiConfig
name: 'Pleroma FE',
registrationOpen: true,
server: 'http://localhost:4040/',
textlimit: 5000,
themesIndex: undefined,
stylesIndex: undefined,
palettesIndex: undefined,
themeData: undefined, // used for theme editor v2
vapidPublicKey: undefined,
// Stuff from static/config.json
alwaysShowSubjectInput: true,
defaultAvatar: '/images/avi.png',
defaultBanner: '/images/banner.png',
background: '/static/aurora_borealis.jpg',
embeddedToS: true,
collapseMessageWithSubject: false,
greentext: false,
- useAtIcon: false,
mentionLinkDisplay: 'short',
mentionLinkShowTooltip: true,
mentionLinkShowAvatar: false,
mentionLinkFadeDomain: true,
mentionLinkShowYous: false,
mentionLinkBoldenYou: true,
hideFilteredStatuses: false,
// bad name: actually hides posts of muted USERS
hideMutedPosts: false,
hideMutedThreads: true,
hideWordFilteredPosts: false,
hidePostStats: false,
hideBotIndication: false,
hideSitename: false,
hideUserStats: false,
muteBotStatuses: false,
muteSensitiveStatuses: false,
modalOnRepeat: false,
modalOnUnfollow: false,
modalOnBlock: true,
modalOnMute: false,
modalOnMuteConversation: false,
modalOnMuteDomain: true,
modalOnDelete: true,
modalOnLogout: true,
modalOnApproveFollow: false,
modalOnDenyFollow: false,
modalOnRemoveUserFromFollowers: false,
modalMobileCenter: false,
loginMethod: 'password',
logo: '/static/logo.svg',
logoMargin: '.2em',
logoMask: true,
logoLeft: false,
disableUpdateNotification: false,
minimalScopesMode: false,
nsfwCensorImage: undefined,
postContentType: 'text/plain',
redirectRootLogin: '/main/friends',
redirectRootNoLogin: '/main/all',
scopeCopy: true,
showFeaturesPanel: true,
showInstanceSpecificPanel: false,
sidebarRight: false,
subjectLineBehavior: 'email',
theme: 'pleroma-dark',
palette: null,
style: null,
emojiReactionsScale: 0.5,
textSize: '14px',
emojiSize: '2.2rem',
navbarSize: '3.5rem',
panelHeaderSize: '3.2rem',
forcedRoundness: -1,
fontsOverride: {},
virtualScrolling: true,
sensitiveByDefault: false,
conversationDisplay: 'linear',
conversationTreeAdvanced: false,
conversationOtherRepliesButton: 'below',
conversationTreeFadeAncestors: false,
showExtraNotifications: true,
showExtraNotificationsTip: true,
showChatsInExtraNotifications: true,
showAnnouncementsInExtraNotifications: true,
showFollowRequestsInExtraNotifications: true,
maxDepthInThread: 6,
autocompleteSelect: false,
closingDrawerMarksAsSeen: true,
unseenAtTop: false,
ignoreInactionableSeen: false,
unsavedPostAction: 'confirm',
autoSaveDraft: false,
useAbsoluteTimeFormat: false,
absoluteTimeFormatMinAge: '0d',
absoluteTime12h: '24h',
// Nasty stuff
customEmoji: [],
customEmojiFetched: false,
emoji: {},
emojiFetched: false,
unicodeEmojiAnnotations: {},
pleromaBackend: true,
postFormats: [],
restrictedNicknames: [],
safeDM: true,
knownDomains: [],
birthdayRequired: false,
birthdayMinAge: 0,
// Feature-set, apparently, not everything here is reported...
shoutAvailable: false,
pleromaChatMessagesAvailable: false,
pleromaCustomEmojiReactionsAvailable: false,
pleromaBookmarkFoldersAvailable: false,
gopherAvailable: false,
mediaProxyAvailable: false,
suggestionsEnabled: false,
suggestionsWeb: '',
quotingAvailable: false,
groupActorAvailable: false,
// Html stuff
instanceSpecificPanelContent: '',
tos: '',
// Version Information
backendVersion: '',
backendRepository: '',
frontendVersion: '',
pollsAvailable: false,
pollLimits: {
max_options: 4,
max_option_chars: 255,
min_expiration: 60,
max_expiration: 60 * 60 * 24
}
}
const loadAnnotations = (lang) => {
return import(
/* webpackChunkName: "emoji-annotations/[request]" */
`@kazvmoe-infra/unicode-emoji-json/annotations/${langCodeToCldrName(lang)}.json`
)
.then(k => k.default)
}
const injectAnnotations = (emoji, annotations) => {
const availableLangs = Object.keys(annotations)
return {
...emoji,
annotations: availableLangs.reduce((acc, cur) => {
acc[cur] = annotations[cur][emoji.replacement]
return acc
}, {})
}
}
const injectRegionalIndicators = groups => {
groups.symbols.push(...REGIONAL_INDICATORS)
return groups
}
const instance = {
state: defaultState,
mutations: {
setInstanceOption (state, { name, value }) {
if (typeof value !== 'undefined') {
state[name] = value
}
},
setKnownDomains (state, domains) {
state.knownDomains = domains
},
setUnicodeEmojiAnnotations (state, { lang, annotations }) {
state.unicodeEmojiAnnotations[lang] = annotations
}
},
getters: {
instanceDefaultConfig (state) {
return instanceDefaultProperties
.map(key => [key, state[key]])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
},
groupedCustomEmojis (state) {
const packsOf = emoji => {
const packs = emoji.tags
.filter(k => k.startsWith('pack:'))
.map(k => {
const packName = k.slice(5) // remove 'pack:' prefix
return {
id: `custom-${packName}`,
text: packName
}
})
if (!packs.length) {
return [{
id: 'unpacked'
}]
} else {
return packs
}
}
return state.customEmoji
.reduce((res, emoji) => {
packsOf(emoji).forEach(({ id: packId, text: packName }) => {
if (!res[packId]) {
res[packId] = ({
id: packId,
text: packName,
image: emoji.imageUrl,
emojis: []
})
}
res[packId].emojis.push(emoji)
})
return res
}, {})
},
standardEmojiList (state) {
return SORTED_EMOJI_GROUP_IDS
.map(groupId => (state.emoji[groupId] || []).map(k => injectAnnotations(k, state.unicodeEmojiAnnotations)))
.reduce((a, b) => a.concat(b), [])
},
standardEmojiGroupList (state) {
return SORTED_EMOJI_GROUP_IDS.map(groupId => ({
id: groupId,
emojis: (state.emoji[groupId] || []).map(k => injectAnnotations(k, state.unicodeEmojiAnnotations))
}))
},
instanceDomain (state) {
return new URL(state.server).hostname
},
remoteInteractionLink (state) {
const server = state.server.endsWith('/') ? state.server.slice(0, -1) : state.server
const link = server + REMOTE_INTERACTION_URL
return ({ statusId, nickname }) => {
if (statusId) {
return `${link}?status_id=${statusId}`
} else {
return `${link}?nickname=${nickname}`
}
}
}
},
actions: {
setInstanceOption ({ commit, dispatch }, { name, value }) {
commit('setInstanceOption', { name, value })
switch (name) {
case 'name':
useInterfaceStore().setPageTitle()
break
case 'shoutAvailable':
if (value) {
dispatch('initializeSocket')
}
break
}
},
async getStaticEmoji ({ commit }) {
try {
const values = (await import(/* webpackChunkName: 'emoji' */ '../../static/emoji.json')).default
const emoji = Object.keys(values).reduce((res, groupId) => {
res[groupId] = values[groupId].map(e => ({
displayText: e.slug,
imageUrl: false,
replacement: e.emoji
}))
return res
}, {})
commit('setInstanceOption', { name: 'emoji', value: injectRegionalIndicators(emoji) })
} catch (e) {
console.warn("Can't load static emoji\n", e)
}
},
loadUnicodeEmojiData ({ commit, state }, language) {
const langList = ensureFinalFallback(language)
return Promise.all(
langList
.map(async lang => {
if (!state.unicodeEmojiAnnotations[lang]) {
try {
const annotations = await loadAnnotations(lang)
commit('setUnicodeEmojiAnnotations', { lang, annotations })
} catch (e) {
console.warn(`Error loading unicode emoji annotations for ${lang}: `, e)
// ignore
}
}
}))
},
async getCustomEmoji ({ commit, state }) {
try {
const res = await window.fetch('/api/pleroma/emoji.json')
if (res.ok) {
const result = await res.json()
const values = Array.isArray(result) ? Object.assign({}, ...result) : result
const caseInsensitiveStrCmp = (a, b) => {
const la = a.toLowerCase()
const lb = b.toLowerCase()
return la > lb ? 1 : (la < lb ? -1 : 0)
}
const noPackLast = (a, b) => {
const aNull = a === ''
const bNull = b === ''
if (aNull === bNull) {
return 0
} else if (aNull && !bNull) {
return 1
} else {
return -1
}
}
const byPackThenByName = (a, b) => {
const packOf = emoji => (emoji.tags.filter(k => k.startsWith('pack:'))[0] || '').slice(5)
const packOfA = packOf(a)
const packOfB = packOf(b)
return noPackLast(packOfA, packOfB) || caseInsensitiveStrCmp(packOfA, packOfB) || caseInsensitiveStrCmp(a.displayText, b.displayText)
}
const emoji = Object.entries(values).map(([key, value]) => {
const imageUrl = value.image_url
return {
displayText: key,
imageUrl: imageUrl ? state.server + imageUrl : value,
tags: imageUrl ? value.tags.sort((a, b) => a > b ? 1 : 0) : ['utf'],
replacement: `:${key}: `
}
// Technically could use tags but those are kinda useless right now,
// should have been "pack" field, that would be more useful
}).sort(byPackThenByName)
commit('setInstanceOption', { name: 'customEmoji', value: emoji })
} else {
throw (res)
}
} catch (e) {
console.warn("Can't load custom emojis\n", e)
}
},
fetchEmoji ({ dispatch, state }) {
if (!state.customEmojiFetched) {
state.customEmojiFetched = true
dispatch('getCustomEmoji')
}
if (!state.emojiFetched) {
state.emojiFetched = true
dispatch('getStaticEmoji')
}
},
async getKnownDomains ({ commit, rootState }) {
try {
const result = await apiService.fetchKnownDomains({
credentials: rootState.users.currentUser.credentials
})
commit('setKnownDomains', result)
} catch (e) {
console.warn("Can't load known domains\n", e)
}
}
}
}
export default instance

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 19, 2:24 AM (11 h, 34 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1764880
Default Alt Text
(41 KB)

Event Timeline