pleroma-fe boots once again
This commit is contained in:
parent
58e18d48df
commit
c926ed7ac1
26 changed files with 1763 additions and 2245 deletions
|
@ -38,6 +38,7 @@
|
|||
"pako": "^2.1.0",
|
||||
"parse-link-header": "2.0.0",
|
||||
"phoenix": "1.7.18",
|
||||
"pinia": "^2.0.33",
|
||||
"punycode.js": "2.3.1",
|
||||
"qrcode": "1.5.4",
|
||||
"querystring-es3": "0.2.1",
|
||||
|
|
|
@ -62,7 +62,7 @@ export default {
|
|||
document.getElementById('modal').classList = ['-' + this.layoutType]
|
||||
},
|
||||
mounted () {
|
||||
if (this.$store.state.interface.themeApplied) {
|
||||
if (useInterfaceStore().themeApplied) {
|
||||
this.removeSplash()
|
||||
}
|
||||
},
|
||||
|
@ -71,7 +71,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
themeApplied () {
|
||||
return this.$store.state.interface.themeApplied
|
||||
return useInterfaceStore().themeApplied
|
||||
},
|
||||
layoutModalClass () {
|
||||
return '-' + this.layoutType
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div
|
||||
v-show="$store.state.interface.themeApplied"
|
||||
v-show="themeApplied"
|
||||
id="app-loaded"
|
||||
:style="bgStyle"
|
||||
>
|
||||
|
|
|
@ -359,7 +359,7 @@ const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
|||
|
||||
await setConfig({ store })
|
||||
try {
|
||||
await store.dispatch('applyTheme').catch((e) => { console.error('Error setting theme', e) })
|
||||
await useInterfaceStore().applyTheme().catch((e) => { console.error('Error setting theme', e) })
|
||||
} catch (e) {
|
||||
window.splashError(e)
|
||||
return Promise.reject(e)
|
||||
|
|
|
@ -3,8 +3,10 @@ import Status from '../status/status.vue'
|
|||
import ThreadTree from '../thread_tree/thread_tree.vue'
|
||||
import { WSConnectionStatus } from '../../services/api/api.service.js'
|
||||
import { mapGetters, mapState } from 'vuex'
|
||||
import { mapState as mapPiniaState } from 'pinia'
|
||||
import QuickFilterSettings from '../quick_filter_settings/quick_filter_settings.vue'
|
||||
import QuickViewSettings from '../quick_view_settings/quick_view_settings.vue'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -350,8 +352,10 @@ const conversation = {
|
|||
},
|
||||
...mapGetters(['mergedConfig']),
|
||||
...mapState({
|
||||
mobileLayout: state => state.interface.layoutType === 'mobile',
|
||||
mastoUserSocketStatus: state => state.api.mastoUserSocketStatus
|
||||
}),
|
||||
...mapPiniaState(useInterfaceStore, {
|
||||
mobileLayout: store => store.layoutType === 'mobile'
|
||||
})
|
||||
},
|
||||
components: {
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { mapGetters } from 'vuex'
|
||||
import { mapState as mapPiniaState } from 'pinia'
|
||||
import { useAnnouncementsStore } from '../../stores/announcements'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -33,7 +35,10 @@ const ExtraNotifications = {
|
|||
currentUser () {
|
||||
return this.$store.state.users.currentUser
|
||||
},
|
||||
...mapGetters(['unreadChatCount', 'unreadAnnouncementCount', 'followRequestCount', 'mergedConfig'])
|
||||
...mapGetters(['unreadChatCount', 'followRequestCount', 'mergedConfig']),
|
||||
...mapPiniaState(useAnnouncementsStore, {
|
||||
unreadAnnouncementCount: 'unreadAnnouncementCount'
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
openNotificationSettings () {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Select from '../select/select.vue'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -50,10 +51,10 @@ export default {
|
|||
return typeof this.modelValue !== 'undefined'
|
||||
},
|
||||
localFontsList () {
|
||||
return this.$store.state.interface.localFonts
|
||||
return useInterfaceStore().localFonts
|
||||
},
|
||||
localFontsSize () {
|
||||
return this.$store.state.interface.localFonts?.length
|
||||
return useInterfaceStore().localFonts?.length
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import { filterNavigation } from 'src/components/navigation/filter.js'
|
|||
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
||||
import NavigationPins from 'src/components/navigation/navigation_pins.vue'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -24,7 +25,6 @@ import {
|
|||
faBullhorn,
|
||||
faFilePen
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { useAnnouncementsStore } from '../../stores/announcements'
|
||||
|
||||
library.add(
|
||||
faUsers,
|
||||
|
|
|
@ -17,7 +17,8 @@ import {
|
|||
faStream,
|
||||
faList
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { useListsStore } from '../../stores/lists'
|
||||
import { useListsStore } from 'src/stores/lists'
|
||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||
|
||||
library.add(
|
||||
faUsers,
|
||||
|
@ -48,6 +49,9 @@ const NavPanel = {
|
|||
...mapPiniaState(useListsStore, {
|
||||
lists: getListEntries
|
||||
}),
|
||||
...mapPiniaState(useAnnouncementsStore, {
|
||||
supportsAnnouncements: store => store.supportsAnnouncements
|
||||
}),
|
||||
...mapState({
|
||||
bookmarks: getBookmarkFolderEntries,
|
||||
currentUser: state => state.users.currentUser,
|
||||
|
@ -55,7 +59,6 @@ const NavPanel = {
|
|||
privateMode: state => state.instance.private,
|
||||
federating: state => state.instance.federating,
|
||||
pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable,
|
||||
supportsAnnouncements: state => state.announcements.supportsAnnouncements,
|
||||
pinnedItems: state => new Set(state.serverSideStorage.prefsStorage.collections.pinnedNavItems)
|
||||
}),
|
||||
pinnedList () {
|
||||
|
|
|
@ -7,6 +7,7 @@ import Checkbox from 'src/components/checkbox/checkbox.vue'
|
|||
import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue'
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { cloneDeep, isEqual } from 'lodash'
|
||||
import { mapState as mapPiniaState } from 'pinia'
|
||||
import {
|
||||
newImporter,
|
||||
newExporter
|
||||
|
@ -167,24 +168,15 @@ const SettingsModal = {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
currentSaveStateNotice () {
|
||||
return useInterfaceStore().settings.currentSaveStateNotice
|
||||
},
|
||||
modalActivated () {
|
||||
return useInterfaceStore().settingsModalState !== 'hidden'
|
||||
},
|
||||
modalMode () {
|
||||
return useInterfaceStore().settingsModalMode
|
||||
},
|
||||
modalOpenedOnceUser () {
|
||||
return useInterfaceStore().settingsModalLoadedUser
|
||||
},
|
||||
modalOpenedOnceAdmin () {
|
||||
return useInterfaceStore().settingsModalLoadedAdmin
|
||||
},
|
||||
modalPeeked () {
|
||||
return useInterfaceStore().settingsModalState === 'minimized'
|
||||
},
|
||||
...mapPiniaState(useInterfaceStore, {
|
||||
temporaryChangesTimeoutId: store => store.layoutType === 'mobile',
|
||||
currentSaveStateNotice: store => store.settings.currentSaveStateNotice,
|
||||
modalActivated: store => store.settingsModalState !== 'hidden',
|
||||
modalMode: store => store.settingsModalMode,
|
||||
modalOpenedOnceUser: store => store.settingsModalLoadedUser,
|
||||
modalOpenedOnceAdmin: store => store.settingsModalLoadedAdmin,
|
||||
modalPeeked: store => store.settingsModalState === 'minimized'
|
||||
}),
|
||||
expertLevel: {
|
||||
get () {
|
||||
return this.$store.state.config.expertLevel > 0
|
||||
|
|
|
@ -158,7 +158,7 @@
|
|||
</div>
|
||||
<teleport to="#modal">
|
||||
<ConfirmModal
|
||||
v-if="$store.state.interface.temporaryChangesTimeoutId"
|
||||
v-if="temporaryChangesTimeoutId"
|
||||
:title="$t('settings.confirm_new_setting')"
|
||||
:cancel-text="$t('settings.revert')"
|
||||
:confirm-text="$t('settings.confirm')"
|
||||
|
|
|
@ -4,6 +4,7 @@ import InstanceTab from './admin_tabs/instance_tab.vue'
|
|||
import LimitsTab from './admin_tabs/limits_tab.vue'
|
||||
import FrontendsTab from './admin_tabs/frontends_tab.vue'
|
||||
import EmojiTab from './admin_tabs/emoji_tab.vue'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -45,10 +46,10 @@ const SettingsModalAdminContent = {
|
|||
return !!this.$store.state.users.currentUser
|
||||
},
|
||||
open () {
|
||||
return this.$store.state.interface.settingsModalState !== 'hidden'
|
||||
return useInterfaceStore().settingsModalState !== 'hidden'
|
||||
},
|
||||
bodyLock () {
|
||||
return this.$store.state.interface.settingsModalState === 'visible'
|
||||
return useInterfaceStore().settingsModalState === 'visible'
|
||||
},
|
||||
adminDbLoaded () {
|
||||
return this.$store.state.adminSettings.loaded
|
||||
|
@ -67,7 +68,7 @@ const SettingsModalAdminContent = {
|
|||
},
|
||||
methods: {
|
||||
onOpen () {
|
||||
const targetTab = this.$store.state.interface.settingsModalTargetTab
|
||||
const targetTab = useInterfaceStore().settingsModalTargetTab
|
||||
// We're being told to open in specific tab
|
||||
if (targetTab) {
|
||||
const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => {
|
||||
|
|
|
@ -25,7 +25,7 @@ import {
|
|||
faInfo,
|
||||
faWindowRestore
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
import { useInterfaceStore } from '../../stores/interface'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
||||
library.add(
|
||||
faWrench,
|
||||
|
@ -70,7 +70,7 @@ const SettingsModalContent = {
|
|||
return this.$store.state.config.expertLevel
|
||||
},
|
||||
isMobileLayout () {
|
||||
return this.$store.state.interface.layoutType === 'mobile'
|
||||
return useInterfaceStore().layoutType === 'mobile'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -7,7 +7,7 @@ import PaletteEditor from 'src/components/palette_editor/palette_editor.vue'
|
|||
|
||||
import FontControl from 'src/components/font_control/font_control.vue'
|
||||
|
||||
import { normalizeThemeData } from 'src/modules/interface'
|
||||
import { useInterfaceStore, normalizeThemeData } from 'src/stores/interface'
|
||||
|
||||
import { newImporter } from 'src/services/export_import/export_import.js'
|
||||
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||
|
@ -131,7 +131,7 @@ const AppearanceTab = {
|
|||
}))
|
||||
})
|
||||
|
||||
this.userPalette = this.$store.state.interface.paletteDataUsed || {}
|
||||
this.userPalette = useInterfaceStore().paletteDataUsed || {}
|
||||
|
||||
updateIndex('palette').then(bundledPalettes => {
|
||||
bundledPalettes.forEach(([key, palettePromise]) => palettePromise.then(v => {
|
||||
|
@ -187,10 +187,10 @@ const AppearanceTab = {
|
|||
},
|
||||
computed: {
|
||||
switchInProgress () {
|
||||
return this.$store.state.interface.themeChangeInProgress
|
||||
return useInterfaceStore().themeChangeInProgress
|
||||
},
|
||||
paletteDataUsed () {
|
||||
return this.$store.state.interface.paletteDataUsed
|
||||
return useInterfaceStore().paletteDataUsed
|
||||
},
|
||||
availableStyles () {
|
||||
return [
|
||||
|
@ -205,7 +205,7 @@ const AppearanceTab = {
|
|||
]
|
||||
},
|
||||
stylePalettes () {
|
||||
const ruleset = this.$store.state.interface.styleDataUsed || []
|
||||
const ruleset = useInterfaceStore().styleDataUsed || []
|
||||
if (!ruleset && ruleset.length === 0) return
|
||||
const meta = ruleset.find(x => x.component === '@meta')
|
||||
const result = ruleset.filter(x => x.component.startsWith('@palette'))
|
||||
|
@ -273,7 +273,7 @@ const AppearanceTab = {
|
|||
}
|
||||
},
|
||||
customThemeVersion () {
|
||||
const { themeVersion } = this.$store.state.interface
|
||||
const { themeVersion } = useInterfaceStore()
|
||||
return themeVersion
|
||||
},
|
||||
isCustomThemeUsed () {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { ref, reactive, computed, watch, watchEffect, provide, getCurrentInstance } from 'vue'
|
||||
import { useStore } from 'vuex'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
import { get, set, unset, throttle } from 'lodash'
|
||||
|
||||
import Select from 'src/components/select/select.vue'
|
||||
|
@ -81,9 +82,10 @@ export default {
|
|||
setup (props, context) {
|
||||
const exports = {}
|
||||
const store = useStore()
|
||||
const interfaceStore = useInterfaceStore()
|
||||
// All rules that are made by editor
|
||||
const allEditedRules = ref(store.state.interface.styleDataUsed || {})
|
||||
const styleDataUsed = computed(() => store.state.interface.styleDataUsed)
|
||||
const allEditedRules = ref(interfaceStore.styleDataUsed || {})
|
||||
const styleDataUsed = computed(() => interfaceStore.styleDataUsed)
|
||||
|
||||
watch([styleDataUsed], (value) => {
|
||||
onImport(store.state.interface.styleDataUsed)
|
||||
|
|
|
@ -297,7 +297,7 @@ export default {
|
|||
}
|
||||
},
|
||||
themeDataUsed () {
|
||||
return this.$store.state.interface.themeDataUsed
|
||||
return useInterfaceStore().themeDataUsed
|
||||
},
|
||||
shadowsAvailable () {
|
||||
return Object.keys(DEFAULT_SHADOWS).sort()
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import StillImage from '../still-image/still-image.vue'
|
||||
import { useInterfaceStore } from 'src/stores/interface'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
|
||||
|
@ -22,7 +23,7 @@ const UserAvatar = {
|
|||
return {
|
||||
showPlaceholder: false,
|
||||
defaultAvatar: `${this.$store.state.instance.server + this.$store.state.instance.defaultAvatar}`,
|
||||
betterShadow: this.$store.state.interface.browserSupport.cssFilter
|
||||
betterShadow: useInterfaceStore().browserSupport.cssFilter
|
||||
}
|
||||
},
|
||||
components: {
|
||||
|
|
11
src/main.js
11
src/main.js
|
@ -14,18 +14,11 @@ import configModule from './modules/config.js'
|
|||
import profileConfigModule from './modules/profileConfig.js'
|
||||
import serverSideStorageModule from './modules/serverSideStorage.js'
|
||||
import adminSettingsModule from './modules/adminSettings.js'
|
||||
import shoutModule from './modules/shout.js'
|
||||
import oauthModule from './modules/oauth.js'
|
||||
import authFlowModule from './modules/auth_flow.js'
|
||||
import oauthTokensModule from './modules/oauth_tokens.js'
|
||||
import reportsModule from './modules/reports.js'
|
||||
import pollsModule from './modules/polls.js'
|
||||
import postStatusModule from './modules/postStatus.js'
|
||||
import editStatusModule from './modules/editStatus.js'
|
||||
import statusHistoryModule from './modules/statusHistory.js'
|
||||
import draftsModule from './modules/drafts.js'
|
||||
import chatsModule from './modules/chats.js'
|
||||
import announcementsModule from './modules/announcements.js'
|
||||
import bookmarkFoldersModule from './modules/bookmark_folders.js'
|
||||
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
@ -101,6 +94,7 @@ const persistedStateOptions = {
|
|||
instance: instanceModule,
|
||||
// TODO refactor users/statuses modules, they depend on each other
|
||||
users: usersModule,
|
||||
lists: listsModule,
|
||||
statuses: statusesModule,
|
||||
notifications: notificationsModule,
|
||||
api: apiModule,
|
||||
|
@ -122,10 +116,11 @@ const persistedStateOptions = {
|
|||
strict: false // Socket modifies itself, let's ignore this for now.
|
||||
// strict: process.env.NODE_ENV !== 'production'
|
||||
})
|
||||
window.vuex = store
|
||||
if (storageError) {
|
||||
// Temporarily passing pinia and vuex stores along with storageError result until migration is fully complete.
|
||||
store.dispatch('pushGlobalNotice', { messageKey: 'errors.storage_unavailable', level: 'error' })
|
||||
}
|
||||
// Temporarily passing pinia and vuex stores along with storageError result until migration is fully complete.
|
||||
return await afterStoreSetup({ pinia, store, storageError, i18n })
|
||||
} catch (e) {
|
||||
splashError(i18n, e)
|
||||
|
|
|
@ -6,6 +6,8 @@ import localeService from '../services/locale/locale.service.js'
|
|||
import { useI18nStore } from '../stores/i18n.js'
|
||||
import { useInterfaceStore } from '../stores/interface.js'
|
||||
|
||||
import { defaultState } from './default_config_state.js'
|
||||
|
||||
const BACKEND_LANGUAGE_COOKIE_NAME = 'userLanguage'
|
||||
const APPEARANCE_SETTINGS_KEYS = new Set([
|
||||
'sidebarColumnWidth',
|
||||
|
@ -19,8 +21,6 @@ const APPEARANCE_SETTINGS_KEYS = new Set([
|
|||
'emojiReactionsScale'
|
||||
])
|
||||
|
||||
const browserLocale = (window.navigator.language || 'en').split('-')[0]
|
||||
|
||||
/* TODO this is a bit messy.
|
||||
* We need to declare settings with their types and also deal with
|
||||
* instance-default settings in some way, hopefully try to avoid copy-pasta
|
||||
|
@ -36,168 +36,7 @@ export const multiChoiceProperties = [
|
|||
'unsavedPostAction' // save | discard | confirm
|
||||
]
|
||||
|
||||
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
|
||||
}
|
||||
console.log('TEST', defaultState)
|
||||
|
||||
// caching the instance default properties
|
||||
export const instanceDefaultProperties = Object.entries(defaultState)
|
||||
|
@ -261,7 +100,7 @@ const config = {
|
|||
commit('setHighlight', { user, color, type })
|
||||
},
|
||||
setOptionTemporarily ({ commit, dispatch, state, rootState }, { name, value }) {
|
||||
if (rootState.interface.temporaryChangesTimeoutId !== null) {
|
||||
if (useInterfaceStore().temporaryChangesTimeoutId !== null) {
|
||||
console.warn('Can\'t track more than one temporary change')
|
||||
return
|
||||
}
|
||||
|
|
164
src/modules/default_config_state.js
Normal file
164
src/modules/default_config_state.js
Normal file
|
@ -0,0 +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
|
||||
}
|
|
@ -11,6 +11,8 @@ import {
|
|||
closeAllDesktopNotifications
|
||||
} from '../services/desktop_notification_utils/desktop_notification_utils.js'
|
||||
|
||||
import { useReportsStore } from '../stores/reports.js'
|
||||
|
||||
const emptyNotifications = () => ({
|
||||
desktopNotificationSilence: true,
|
||||
maxId: 0,
|
||||
|
@ -94,7 +96,7 @@ export const notifications = {
|
|||
|
||||
validNotifications.forEach(notification => {
|
||||
if (notification.type === 'pleroma:report') {
|
||||
dispatch('addReport', notification.report)
|
||||
useReportsStore().addReport(notification.report)
|
||||
}
|
||||
|
||||
if (notification.type === 'pleroma:emoji_reaction') {
|
||||
|
|
|
@ -13,7 +13,6 @@ import {
|
|||
omitBy
|
||||
} from 'lodash'
|
||||
import apiService from '../services/api/api.service.js'
|
||||
import { useReportsStore } from '../stores/reports.js'
|
||||
|
||||
const emptyTl = (userId = 0) => ({
|
||||
statuses: [],
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { muteWordHits } from '../status_parser/status_parser.js'
|
||||
import { showDesktopNotification } from '../desktop_notification_utils/desktop_notification_utils.js'
|
||||
import { useI18nStore } from '../../stores/i18n.js'
|
||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||
|
||||
import FaviconService from 'src/services/favicon_service/favicon_service.js'
|
||||
|
||||
|
@ -169,7 +170,7 @@ export const countExtraNotifications = (store) => {
|
|||
|
||||
return [
|
||||
mergedConfig.showChatsInExtraNotifications ? rootGetters.unreadChatCount : 0,
|
||||
mergedConfig.showAnnouncementsInExtraNotifications ? rootGetters.unreadAnnouncementCount : 0,
|
||||
mergedConfig.showAnnouncementsInExtraNotifications ? useAnnouncementsStore().unreadAnnouncementCount : 0,
|
||||
mergedConfig.showFollowRequestsInExtraNotifications ? rootGetters.followRequestCount : 0
|
||||
].reduce((a, c) => a + c, 0)
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import { init, getEngineChecksum } from '../theme_data/theme_data_3.service.js'
|
||||
import { getCssRules } from '../theme_data/css_utils.js'
|
||||
import { defaultState } from '../../modules/config.js'
|
||||
import { defaultState } from 'src/modules/default_config_state.js'
|
||||
import { chunk } from 'lodash'
|
||||
import pako from 'pako'
|
||||
import localforage from 'localforage'
|
||||
|
||||
console.log('CONFIG', defaultState)
|
||||
|
||||
// On platforms where this is not supported, it will return undefined
|
||||
// Otherwise it will return an array
|
||||
const supportsAdoptedStyleSheets = !!document.adoptedStyleSheets
|
||||
|
@ -212,6 +214,7 @@ const extractStyleConfig = ({
|
|||
return result
|
||||
}
|
||||
|
||||
console.log(defaultState)
|
||||
const defaultStyleConfig = extractStyleConfig(defaultState)
|
||||
|
||||
export const applyConfig = (input, i18n) => {
|
||||
|
|
|
@ -1,10 +1,31 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
import { CURRENT_VERSION, generatePreset } from 'src/services/theme_data/theme_data.service.js'
|
||||
import { getResourcesIndex, applyTheme, tryLoadCache } from '../services/style_setter/style_setter.js'
|
||||
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||
import { deserialize } from '../services/theme_data/iss_deserializer.js'
|
||||
|
||||
export const useInterfaceStore = defineStore('interface', {
|
||||
state: () => ({
|
||||
localFonts: null,
|
||||
themeApplied: false,
|
||||
themeChangeInProgress: false,
|
||||
themeVersion: 'v3',
|
||||
styleNameUsed: null,
|
||||
styleDataUsed: null,
|
||||
useStylePalette: false, // hack for applying styles from appearance tab
|
||||
paletteNameUsed: null,
|
||||
paletteDataUsed: null,
|
||||
themeNameUsed: null,
|
||||
themeDataUsed: null,
|
||||
temporaryChangesTimeoutId: null, // used for temporary options that revert after a timeout
|
||||
temporaryChangesConfirm: () => {}, // used for applying temporary options
|
||||
temporaryChangesRevert: () => {}, // used for reverting temporary options
|
||||
settingsModalState: 'hidden',
|
||||
settingsModalLoaded: false,
|
||||
settingsModalLoadedUser: false,
|
||||
settingsModalLoadedAdmin: false,
|
||||
settingsModalTargetTab: null,
|
||||
settingsModalMode: 'user',
|
||||
settings: {
|
||||
currentSaveStateNotice: null,
|
||||
noticeClearTimeout: null,
|
||||
|
@ -46,10 +67,17 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
closeSettingsModal () {
|
||||
this.settingsModalState = 'hidden'
|
||||
},
|
||||
openSettingsModal () {
|
||||
openSettingsModal (value) {
|
||||
this.settingsModalMode = value
|
||||
this.settingsModalState = 'visible'
|
||||
if (!this.settingsModalLoaded) {
|
||||
this.settingsModalLoaded = true
|
||||
if (value === 'user') {
|
||||
if (!this.settingsModalLoadedUser) {
|
||||
this.settingsModalLoadedUser = true
|
||||
}
|
||||
} else if (value === 'admin') {
|
||||
if (!this.settingsModalLoadedAdmin) {
|
||||
this.settingsModalLoadedAdmin = true
|
||||
}
|
||||
}
|
||||
},
|
||||
togglePeekSettingsModal () {
|
||||
|
@ -121,6 +149,500 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
},
|
||||
setLastTimeline (value) {
|
||||
this.lastTimeline = value
|
||||
},
|
||||
async fetchPalettesIndex () {
|
||||
try {
|
||||
const value = await getResourcesIndex('/static/palettes/index.json')
|
||||
window.vuex.commit('setInstanceOption', { name: 'palettesIndex', value })
|
||||
return value
|
||||
} catch (e) {
|
||||
console.error('Could not fetch palettes index', e)
|
||||
window.vuex.commit('setInstanceOption', { name: 'palettesIndex', value: { _error: e } })
|
||||
return Promise.resolve({})
|
||||
}
|
||||
},
|
||||
setPalette (value) {
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
||||
window.vuex.commit('setOption', { name: 'palette', value })
|
||||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
setPaletteCustom (value) {
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
||||
window.vuex.commit('setOption', { name: 'paletteCustomData', value })
|
||||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
async fetchStylesIndex () {
|
||||
try {
|
||||
const value = await getResourcesIndex(
|
||||
'/static/styles/index.json',
|
||||
deserialize
|
||||
)
|
||||
window.vuex.commit('setInstanceOption', { name: 'stylesIndex', value })
|
||||
return value
|
||||
} catch (e) {
|
||||
console.error('Could not fetch styles index', e)
|
||||
window.vuex.commit('setInstanceOption', { name: 'stylesIndex', value: { _error: e } })
|
||||
return Promise.resolve({})
|
||||
}
|
||||
},
|
||||
setStyle (value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV2()
|
||||
this.resetThemeV3Palette()
|
||||
|
||||
window.vuex.commit('setOption', { name: 'style', value })
|
||||
this.useStylePalette = true
|
||||
|
||||
this.applyTheme({ recompile: true }).then(() => {
|
||||
this.useStylePalette = false
|
||||
})
|
||||
},
|
||||
setStyleCustom (value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV2()
|
||||
this.resetThemeV3Palette()
|
||||
|
||||
window.vuex.commit('setOption', { name: 'styleCustomData', value })
|
||||
|
||||
this.useStylePalette = true
|
||||
this.applyTheme({ recompile: true }).then(() => {
|
||||
this.useStylePalette = false
|
||||
})
|
||||
},
|
||||
async fetchThemesIndex () {
|
||||
try {
|
||||
const value = await getResourcesIndex('/static/styles.json')
|
||||
window.vuex.commit('setInstanceOption', { name: 'themesIndex', value })
|
||||
return value
|
||||
} catch (e) {
|
||||
console.error('Could not fetch themes index', e)
|
||||
window.vuex.commit('setInstanceOption', { name: 'themesIndex', value: { _error: e } })
|
||||
return Promise.resolve({})
|
||||
}
|
||||
},
|
||||
setTheme (value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
||||
window.vuex.commit('setOption', { name: 'theme', value })
|
||||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
setThemeCustom (value) {
|
||||
this.resetThemeV3()
|
||||
this.resetThemeV3Palette()
|
||||
this.resetThemeV2()
|
||||
|
||||
window.vuex.commit('setOption', { name: 'customTheme', value })
|
||||
window.vuex.commit('setOption', { name: 'customThemeSource', value })
|
||||
|
||||
this.applyTheme({ recompile: true })
|
||||
},
|
||||
resetThemeV3 () {
|
||||
window.vuex.commit('setOption', { name: 'style', value: null })
|
||||
window.vuex.commit('setOption', { name: 'styleCustomData', value: null })
|
||||
},
|
||||
resetThemeV3Palette () {
|
||||
window.vuex.commit('setOption', { name: 'palette', value: null })
|
||||
window.vuex.commit('setOption', { name: 'paletteCustomData', value: null })
|
||||
},
|
||||
resetThemeV2 () {
|
||||
window.vuex.commit('setOption', { name: 'theme', value: null })
|
||||
window.vuex.commit('setOption', { name: 'customTheme', value: null })
|
||||
window.vuex.commit('setOption', { name: 'customThemeSource', value: null })
|
||||
},
|
||||
async getThemeData () {
|
||||
const getData = async (resource, index, customData, name) => {
|
||||
const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
|
||||
const result = {}
|
||||
|
||||
if (customData) {
|
||||
result.nameUsed = 'custom' // custom data overrides name
|
||||
result.dataUsed = customData
|
||||
} else {
|
||||
result.nameUsed = name
|
||||
|
||||
if (result.nameUsed == null) {
|
||||
result.dataUsed = null
|
||||
return result
|
||||
}
|
||||
|
||||
let fetchFunc = index[result.nameUsed]
|
||||
// Fallbacks
|
||||
if (!fetchFunc) {
|
||||
if (resource === 'style' || resource === 'palette') {
|
||||
return result
|
||||
}
|
||||
const newName = Object.keys(index)[0]
|
||||
fetchFunc = index[newName]
|
||||
console.warn(`${capitalizedResource} with id '${this.styleNameUsed}' not found, trying back to '${newName}'`)
|
||||
if (!fetchFunc) {
|
||||
console.warn(`${capitalizedResource} doesn't have a fallback, defaulting to stock.`)
|
||||
fetchFunc = () => Promise.resolve(null)
|
||||
}
|
||||
}
|
||||
result.dataUsed = await fetchFunc()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
const {
|
||||
style: instanceStyleName,
|
||||
palette: instancePaletteName
|
||||
} = window.vuex.state.instance
|
||||
|
||||
let {
|
||||
theme: instanceThemeV2Name,
|
||||
themesIndex,
|
||||
stylesIndex,
|
||||
palettesIndex
|
||||
} = window.vuex.state.instance
|
||||
|
||||
const {
|
||||
style: userStyleName,
|
||||
styleCustomData: userStyleCustomData,
|
||||
palette: userPaletteName,
|
||||
paletteCustomData: userPaletteCustomData
|
||||
} = window.vuex.state.config
|
||||
|
||||
let {
|
||||
theme: userThemeV2Name,
|
||||
customTheme: userThemeV2Snapshot,
|
||||
customThemeSource: userThemeV2Source
|
||||
} = window.vuex.state.config
|
||||
|
||||
let majorVersionUsed
|
||||
|
||||
console.debug(
|
||||
`User V3 palette: ${userPaletteName}, style: ${userStyleName} , custom: ${!!userStyleCustomData}`
|
||||
)
|
||||
console.debug(
|
||||
`User V2 name: ${userThemeV2Name}, source: ${!!userThemeV2Source}, snapshot: ${!!userThemeV2Snapshot}`
|
||||
)
|
||||
|
||||
console.debug(`Instance V3 palette: ${instancePaletteName}, style: ${instanceStyleName}`)
|
||||
console.debug('Instance V2 theme: ' + instanceThemeV2Name)
|
||||
|
||||
if (userPaletteName || userPaletteCustomData ||
|
||||
userStyleName || userStyleCustomData ||
|
||||
(
|
||||
// User V2 overrides instance V3
|
||||
(instancePaletteName ||
|
||||
instanceStyleName) &&
|
||||
instanceThemeV2Name == null &&
|
||||
userThemeV2Name == null
|
||||
)
|
||||
) {
|
||||
// Palette and/or style overrides V2 themes
|
||||
instanceThemeV2Name = null
|
||||
userThemeV2Name = null
|
||||
userThemeV2Source = null
|
||||
userThemeV2Snapshot = null
|
||||
|
||||
majorVersionUsed = 'v3'
|
||||
} else if (
|
||||
(userThemeV2Name ||
|
||||
userThemeV2Snapshot ||
|
||||
userThemeV2Source ||
|
||||
instanceThemeV2Name)
|
||||
) {
|
||||
majorVersionUsed = 'v2'
|
||||
} else {
|
||||
// if all fails fallback to v3
|
||||
majorVersionUsed = 'v3'
|
||||
}
|
||||
|
||||
if (majorVersionUsed === 'v3') {
|
||||
const result = await Promise.all([
|
||||
this.fetchPalettesIndex(),
|
||||
this.fetchStylesIndex()
|
||||
])
|
||||
|
||||
palettesIndex = result[0]
|
||||
stylesIndex = result[1]
|
||||
} else {
|
||||
// Promise.all just to be uniform with v3
|
||||
const result = await Promise.all([
|
||||
this.fetchThemesIndex()
|
||||
])
|
||||
|
||||
themesIndex = result[0]
|
||||
}
|
||||
|
||||
this.themeVersion = majorVersionUsed
|
||||
|
||||
console.debug('Version used', majorVersionUsed)
|
||||
|
||||
if (majorVersionUsed === 'v3') {
|
||||
this.themeDataUsed = null
|
||||
this.themeNameUsed = null
|
||||
|
||||
const style = await getData(
|
||||
'style',
|
||||
stylesIndex,
|
||||
userStyleCustomData,
|
||||
userStyleName || instanceStyleName
|
||||
)
|
||||
this.styleNameUsed = style.nameUsed
|
||||
this.styleDataUsed = style.dataUsed
|
||||
|
||||
let firstStylePaletteName = null
|
||||
style
|
||||
.dataUsed
|
||||
?.filter(x => x.component === '@palette')
|
||||
.map(x => {
|
||||
const cleanDirectives = Object.fromEntries(
|
||||
Object
|
||||
.entries(x.directives)
|
||||
.filter(([k, v]) => k)
|
||||
)
|
||||
|
||||
return { name: x.variant, ...cleanDirectives }
|
||||
})
|
||||
.forEach(palette => {
|
||||
const key = 'style.' + palette.name.toLowerCase().replace(/ /g, '_')
|
||||
if (!firstStylePaletteName) firstStylePaletteName = key
|
||||
palettesIndex[key] = () => Promise.resolve(palette)
|
||||
})
|
||||
|
||||
const palette = await getData(
|
||||
'palette',
|
||||
palettesIndex,
|
||||
userPaletteCustomData,
|
||||
this.useStylePalette ? firstStylePaletteName : (userPaletteName || instancePaletteName)
|
||||
)
|
||||
|
||||
if (this.useStylePalette) {
|
||||
window.vuex.commit('setOption', { name: 'palette', value: firstStylePaletteName })
|
||||
}
|
||||
|
||||
this.paletteNameUsed = palette.nameUsed
|
||||
this.paletteDataUsed = palette.dataUsed
|
||||
|
||||
if (this.paletteDataUsed) {
|
||||
this.paletteDataUsed.link = this.paletteDataUsed.link || this.paletteDataUsed.accent
|
||||
this.paletteDataUsed.accent = this.paletteDataUsed.accent || this.paletteDataUsed.link
|
||||
}
|
||||
if (Array.isArray(this.paletteDataUsed)) {
|
||||
const [
|
||||
name,
|
||||
bg,
|
||||
fg,
|
||||
text,
|
||||
link,
|
||||
cRed = '#FF0000',
|
||||
cGreen = '#00FF00',
|
||||
cBlue = '#0000FF',
|
||||
cOrange = '#E3FF00'
|
||||
] = palette.dataUsed
|
||||
this.paletteDataUsed = {
|
||||
name,
|
||||
bg,
|
||||
fg,
|
||||
text,
|
||||
link,
|
||||
accent: link,
|
||||
cRed,
|
||||
cBlue,
|
||||
cGreen,
|
||||
cOrange
|
||||
}
|
||||
}
|
||||
console.debug('Palette data used', palette.dataUsed)
|
||||
} else {
|
||||
this.styleNameUsed = null
|
||||
this.styleDataUsed = null
|
||||
this.paletteNameUsed = null
|
||||
this.paletteDataUsed = null
|
||||
|
||||
const theme = await getData(
|
||||
'theme',
|
||||
themesIndex,
|
||||
userThemeV2Source || userThemeV2Snapshot,
|
||||
userThemeV2Name || instanceThemeV2Name
|
||||
)
|
||||
this.themeNameUsed = theme.nameUsed
|
||||
this.themeDataUsed = theme.dataUsed
|
||||
}
|
||||
},
|
||||
async setThemeApplied () {
|
||||
this.themeApplied = true
|
||||
},
|
||||
async applyTheme (
|
||||
{ recompile = false } = {}
|
||||
) {
|
||||
const {
|
||||
forceThemeRecompilation,
|
||||
themeDebug,
|
||||
theme3hacks
|
||||
} = window.vuex.state.config
|
||||
this.themeChangeInProgress = true
|
||||
// If we're not not forced to recompile try using
|
||||
// cache (tryLoadCache return true if load successful)
|
||||
|
||||
const forceRecompile = forceThemeRecompilation || recompile
|
||||
if (!forceRecompile && !themeDebug && await tryLoadCache()) {
|
||||
this.themeChangeInProgress = false
|
||||
return this.setThemeApplied()
|
||||
}
|
||||
window.splashUpdate('splash.theme')
|
||||
await this.getThemeData()
|
||||
|
||||
try {
|
||||
const paletteIss = (() => {
|
||||
if (!this.paletteDataUsed) return null
|
||||
const result = {
|
||||
component: 'Root',
|
||||
directives: {}
|
||||
}
|
||||
|
||||
Object
|
||||
.entries(this.paletteDataUsed)
|
||||
.filter(([k]) => k !== 'name')
|
||||
.forEach(([k, v]) => {
|
||||
let issRootDirectiveName
|
||||
switch (k) {
|
||||
case 'background':
|
||||
issRootDirectiveName = 'bg'
|
||||
break
|
||||
case 'foreground':
|
||||
issRootDirectiveName = 'fg'
|
||||
break
|
||||
default:
|
||||
issRootDirectiveName = k
|
||||
}
|
||||
result.directives['--' + issRootDirectiveName] = 'color | ' + v
|
||||
})
|
||||
return result
|
||||
})()
|
||||
|
||||
const theme2ruleset = this.themeDataUsed && convertTheme2To3(normalizeThemeData(this.themeDataUsed))
|
||||
const hacks = []
|
||||
|
||||
Object.entries(theme3hacks).forEach(([key, value]) => {
|
||||
switch (key) {
|
||||
case 'fonts': {
|
||||
Object.entries(theme3hacks.fonts).forEach(([fontKey, font]) => {
|
||||
if (!font?.family) return
|
||||
switch (fontKey) {
|
||||
case 'interface':
|
||||
hacks.push({
|
||||
component: 'Root',
|
||||
directives: {
|
||||
'--font': 'generic | ' + font.family
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'input':
|
||||
hacks.push({
|
||||
component: 'Input',
|
||||
directives: {
|
||||
'--font': 'generic | ' + font.family
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'post':
|
||||
hacks.push({
|
||||
component: 'RichContent',
|
||||
directives: {
|
||||
'--font': 'generic | ' + font.family
|
||||
}
|
||||
})
|
||||
break
|
||||
case 'monospace':
|
||||
hacks.push({
|
||||
component: 'Root',
|
||||
directives: {
|
||||
'--monoFont': 'generic | ' + font.family
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
case 'underlay': {
|
||||
if (value !== 'none') {
|
||||
const newRule = {
|
||||
component: 'Underlay',
|
||||
directives: {}
|
||||
}
|
||||
if (value === 'opaque') {
|
||||
newRule.directives.opacity = 1
|
||||
newRule.directives.background = '--wallpaper'
|
||||
}
|
||||
if (value === 'transparent') {
|
||||
newRule.directives.opacity = 0
|
||||
}
|
||||
hacks.push(newRule)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const rulesetArray = [
|
||||
theme2ruleset,
|
||||
this.styleDataUsed,
|
||||
paletteIss,
|
||||
hacks
|
||||
].filter(x => x)
|
||||
|
||||
return applyTheme(
|
||||
rulesetArray.flat(),
|
||||
() => this.setThemeApplied(),
|
||||
() => {
|
||||
this.themeChangeInProgress = false
|
||||
},
|
||||
themeDebug
|
||||
)
|
||||
} catch (e) {
|
||||
window.splashError(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const normalizeThemeData = (input) => {
|
||||
let themeData, themeSource
|
||||
|
||||
if (input.themeFileVerison === 1) {
|
||||
// this might not be even used at all, some leftover of unimplemented code in V2 editor
|
||||
return generatePreset(input).theme
|
||||
} else if (
|
||||
Object.prototype.hasOwnProperty.call(input, '_pleroma_theme_version') ||
|
||||
Object.prototype.hasOwnProperty.call(input, 'source') ||
|
||||
Object.prototype.hasOwnProperty.call(input, 'theme')
|
||||
) {
|
||||
// We got passed a full theme file
|
||||
themeData = input.theme
|
||||
themeSource = input.source
|
||||
} else if (
|
||||
Object.prototype.hasOwnProperty.call(input, 'themeEngineVersion') ||
|
||||
Object.prototype.hasOwnProperty.call(input, 'colors')
|
||||
) {
|
||||
// We got passed a source/snapshot
|
||||
themeData = input
|
||||
themeSource = input
|
||||
}
|
||||
// New theme presets don't have 'theme' property, they use 'source'
|
||||
|
||||
let out // shout, shout let it all out
|
||||
if (themeSource && themeSource.themeEngineVersion === CURRENT_VERSION) {
|
||||
// There are some themes in wild that have completely broken source
|
||||
out = { ...(themeData || {}), ...themeSource }
|
||||
} else {
|
||||
out = themeData
|
||||
}
|
||||
|
||||
// generatePreset here basically creates/updates "snapshot",
|
||||
// while also fixing the 2.2 -> 2.3 colors/shadows/etc
|
||||
return generatePreset(out).theme
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue