Merge remote-tracking branch 'origin/develop' into shigusegubu-themes3
This commit is contained in:
commit
4a1914d71c
24 changed files with 1265 additions and 951 deletions
0
changelog.d/filter-fixes.skip
Normal file
0
changelog.d/filter-fixes.skip
Normal file
1
changelog.d/profile-error.fix
Normal file
1
changelog.d/profile-error.fix
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fix error styling for user profiles
|
||||
1
changelog.d/theme3-body-class.add
Normal file
1
changelog.d/theme3-body-class.add
Normal file
|
|
@ -0,0 +1 @@
|
|||
Indicate currently active V3 theme as a body element class
|
||||
36
package.json
36
package.json
|
|
@ -17,7 +17,7 @@
|
|||
"lint-fix": "eslint --fix src test/unit/specs test/e2e/specs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.27.0",
|
||||
"@babel/runtime": "7.27.1",
|
||||
"@chenfengyuan/vue-qrcode": "2.0.0",
|
||||
"@fortawesome/fontawesome-svg-core": "6.7.2",
|
||||
"@fortawesome/free-regular-svg-icons": "6.7.2",
|
||||
|
|
@ -46,19 +46,19 @@
|
|||
"querystring-es3": "0.2.1",
|
||||
"url": "0.11.4",
|
||||
"utf8": "3.0.0",
|
||||
"uuid": "8.3.2",
|
||||
"uuid": "11.1.0",
|
||||
"vue": "3.5.13",
|
||||
"vue-i18n": "10",
|
||||
"vue-router": "4.5.0",
|
||||
"vue-i18n": "11",
|
||||
"vue-router": "4.5.1",
|
||||
"vue-virtual-scroller": "^2.0.0-beta.7",
|
||||
"vuex": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.26.10",
|
||||
"@babel/eslint-parser": "7.27.0",
|
||||
"@babel/plugin-transform-runtime": "7.26.10",
|
||||
"@babel/preset-env": "7.26.9",
|
||||
"@babel/register": "7.25.9",
|
||||
"@babel/core": "7.27.1",
|
||||
"@babel/eslint-parser": "7.27.1",
|
||||
"@babel/plugin-transform-runtime": "7.27.1",
|
||||
"@babel/preset-env": "7.27.2",
|
||||
"@babel/register": "7.27.1",
|
||||
"@ungap/event-target": "0.2.4",
|
||||
"@vitejs/plugin-vue": "^5.2.1",
|
||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||
|
|
@ -72,38 +72,38 @@
|
|||
"babel-plugin-lodash": "3.3.4",
|
||||
"chai": "5.2.0",
|
||||
"chalk": "5.4.1",
|
||||
"chromedriver": "135.0.0",
|
||||
"chromedriver": "135.0.4",
|
||||
"connect-history-api-fallback": "2.0.0",
|
||||
"cross-spawn": "7.0.6",
|
||||
"custom-event-polyfill": "1.0.7",
|
||||
"eslint": "9.24.0",
|
||||
"eslint": "9.26.0",
|
||||
"vue-eslint-parser": "10.1.3",
|
||||
"eslint-config-standard": "17.1.0",
|
||||
"eslint-formatter-friendly": "7.0.0",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-n": "17.17.0",
|
||||
"eslint-plugin-n": "17.18.0",
|
||||
"eslint-plugin-promise": "7.2.1",
|
||||
"eslint-plugin-vue": "10.0.0",
|
||||
"eslint-plugin-vue": "10.1.0",
|
||||
"eventsource-polyfill": "0.9.6",
|
||||
"express": "5.1.0",
|
||||
"function-bind": "1.1.2",
|
||||
"http-proxy-middleware": "3.0.3",
|
||||
"http-proxy-middleware": "3.0.5",
|
||||
"iso-639-1": "3.1.5",
|
||||
"lodash": "4.17.21",
|
||||
"msw": "2.7.3",
|
||||
"msw": "2.7.6",
|
||||
"nightwatch": "3.12.1",
|
||||
"playwright": "1.49.1",
|
||||
"playwright": "1.52.0",
|
||||
"postcss": "8.5.3",
|
||||
"postcss-html": "^1.5.0",
|
||||
"postcss-scss": "^4.0.6",
|
||||
"sass": "1.86.3",
|
||||
"sass": "1.87.0",
|
||||
"selenium-server": "3.141.59",
|
||||
"semver": "7.7.1",
|
||||
"serve-static": "2.2.0",
|
||||
"shelljs": "0.9.2",
|
||||
"sinon": "20.0.0",
|
||||
"sinon-chai": "4.0.0",
|
||||
"stylelint": "16.18.0",
|
||||
"stylelint": "16.19.1",
|
||||
"stylelint-config-html": "^1.1.0",
|
||||
"stylelint-config-recommended": "^16.0.0",
|
||||
"stylelint-config-recommended-scss": "^14.0.0",
|
||||
|
|
|
|||
34
src/App.js
34
src/App.js
|
|
@ -52,6 +52,9 @@ export default {
|
|||
themeApplied () {
|
||||
this.removeSplash()
|
||||
},
|
||||
currentTheme () {
|
||||
this.setThemeBodyClass()
|
||||
},
|
||||
layoutType () {
|
||||
document.getElementById('modal').classList = ['-' + this.layoutType]
|
||||
}
|
||||
|
|
@ -71,6 +74,7 @@ export default {
|
|||
this.scrollParent.addEventListener('scroll', this.updateScrollState)
|
||||
|
||||
if (useInterfaceStore().themeApplied) {
|
||||
this.setThemeBodyClass()
|
||||
this.removeSplash()
|
||||
}
|
||||
},
|
||||
|
|
@ -82,6 +86,17 @@ export default {
|
|||
themeApplied () {
|
||||
return useInterfaceStore().themeApplied
|
||||
},
|
||||
currentTheme () {
|
||||
if (useInterfaceStore().styleDataUsed) {
|
||||
const styleMeta = useInterfaceStore().styleDataUsed.find(x => x.component === '@meta')
|
||||
|
||||
if (styleMeta !== undefined) {
|
||||
return styleMeta.directives.name.replaceAll(" ", "-").toLowerCase()
|
||||
}
|
||||
}
|
||||
|
||||
return 'stock'
|
||||
},
|
||||
layoutModalClass () {
|
||||
return '-' + this.layoutType
|
||||
},
|
||||
|
|
@ -172,6 +187,25 @@ export default {
|
|||
this.$refs.appContentRef.classList.remove(['-scrolled'])
|
||||
}
|
||||
},
|
||||
setThemeBodyClass () {
|
||||
const themeName = this.currentTheme
|
||||
const classList = Array.from(document.body.classList)
|
||||
const oldTheme = classList.filter(c => c.startsWith('theme-'))
|
||||
|
||||
if (themeName !== null && themeName !== '') {
|
||||
const newTheme = `theme-${themeName.toLowerCase()}`
|
||||
|
||||
// remove old theme reference if there are any
|
||||
if (oldTheme.length) {
|
||||
document.body.classList.replace(oldTheme[0], newTheme)
|
||||
} else {
|
||||
document.body.classList.add(newTheme)
|
||||
}
|
||||
} else {
|
||||
// remove theme reference if non-V3 theme is used
|
||||
document.body.classList.remove(...oldTheme)
|
||||
}
|
||||
},
|
||||
removeSplash () {
|
||||
document.querySelector('#status').textContent = this.$t('splash.fun_' + Math.ceil(Math.random() * 4))
|
||||
const splashscreenRoot = document.querySelector('#splash')
|
||||
|
|
|
|||
|
|
@ -339,11 +339,6 @@ const conversation = {
|
|||
canDive () {
|
||||
return this.isTreeView && this.isExpanded
|
||||
},
|
||||
focused () {
|
||||
return (id) => {
|
||||
return (this.isExpanded) && id === this.highlight
|
||||
}
|
||||
},
|
||||
maybeHighlight () {
|
||||
return this.isExpanded ? this.highlight : null
|
||||
},
|
||||
|
|
@ -406,6 +401,9 @@ const conversation = {
|
|||
})
|
||||
}
|
||||
},
|
||||
isFocused (id) {
|
||||
return (this.isExpanded) && id === this.highlight
|
||||
},
|
||||
getReplies (id) {
|
||||
return this.replies[id] || []
|
||||
},
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@
|
|||
:statusoid="status"
|
||||
:expandable="!isExpanded"
|
||||
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
|
||||
:focused="focused(status.id)"
|
||||
:focused="isFocused(status.id)"
|
||||
:in-conversation="isExpanded"
|
||||
:highlight="getHighlight()"
|
||||
:replies="getReplies(status.id)"
|
||||
|
|
@ -168,7 +168,7 @@
|
|||
:pinned-status-ids-object="pinnedStatusIdsObject"
|
||||
:profile-user-id="profileUserId"
|
||||
|
||||
:focused="focused"
|
||||
:is-focused-function="isFocused"
|
||||
:get-replies="getReplies"
|
||||
:highlight="maybeHighlight"
|
||||
:set-highlight="setHighlight"
|
||||
|
|
@ -199,7 +199,7 @@
|
|||
:statusoid="status"
|
||||
:expandable="!isExpanded"
|
||||
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
|
||||
:focused="focused(status.id)"
|
||||
:focused="isFocused(status.id)"
|
||||
:in-conversation="isExpanded"
|
||||
:highlight="getHighlight()"
|
||||
:replies="getReplies(status.id)"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import Importer from 'src/components/importer/importer.vue'
|
|||
import Exporter from 'src/components/exporter/exporter.vue'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import { mapState } from 'vuex'
|
||||
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
|
||||
|
||||
const DataImportExportTab = {
|
||||
data () {
|
||||
|
|
@ -15,7 +16,7 @@ const DataImportExportTab = {
|
|||
}
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('fetchTokens')
|
||||
useOAuthTokensStore().fetchTokens()
|
||||
this.fetchBackups()
|
||||
},
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ const FilteringTab = {
|
|||
date.getFullYear(),
|
||||
'-',
|
||||
fmt.format(date.getMonth() + 1),
|
||||
'-',
|
||||
fmt.format(date.getDate()),
|
||||
'T',
|
||||
fmt.format(date.getHours()),
|
||||
':',
|
||||
|
|
@ -180,7 +182,6 @@ const FilteringTab = {
|
|||
updateFilter(id, field, value) {
|
||||
const filter = { ...this.muteFiltersDraftObject[id] }
|
||||
if (field === 'expires-never') {
|
||||
// filter[field] = value
|
||||
if (!value) {
|
||||
const offset = 1000 * 60 * 60 * 24 * 14 // 2 weeks
|
||||
const date = Date.now() + offset
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
|||
import withSubscription from 'src/components/../hocs/with_subscription/with_subscription'
|
||||
import withLoadMore from 'src/components/../hocs/with_load_more/with_load_more'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
|
||||
|
||||
const BlockList = withLoadMore({
|
||||
fetch: (props, $store) => $store.dispatch('fetchBlocks'),
|
||||
|
|
@ -39,7 +40,7 @@ const MutesAndBlocks = {
|
|||
}
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('fetchTokens')
|
||||
useOAuthTokensStore().fetchTokens()
|
||||
this.$store.dispatch('getKnownDomains')
|
||||
},
|
||||
components: {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import ProgressButton from 'src/components/progress_button/progress_button.vue'
|
|||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import Mfa from './mfa.vue'
|
||||
import localeService from 'src/services/locale/locale.service.js'
|
||||
import { useOAuthTokensStore } from 'src/stores/oauth_tokens'
|
||||
|
||||
const SecurityTab = {
|
||||
data () {
|
||||
|
|
@ -28,7 +29,7 @@ const SecurityTab = {
|
|||
}
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('fetchTokens')
|
||||
useOAuthTokensStore().fetchTokens()
|
||||
this.fetchAliases()
|
||||
},
|
||||
components: {
|
||||
|
|
@ -44,7 +45,7 @@ const SecurityTab = {
|
|||
return this.$store.state.instance.pleromaBackend
|
||||
},
|
||||
oauthTokens () {
|
||||
return this.$store.state.oauthTokens.tokens.map(oauthToken => {
|
||||
return useOAuthTokensStore().tokens.map(oauthToken => {
|
||||
return {
|
||||
id: oauthToken.id,
|
||||
appName: oauthToken.app_name,
|
||||
|
|
@ -151,7 +152,7 @@ const SecurityTab = {
|
|||
},
|
||||
revokeToken (id) {
|
||||
if (window.confirm(`${this.$i18n.t('settings.revoke_token')}?`)) {
|
||||
this.$store.dispatch('revokeToken', id)
|
||||
useOAuthTokensStore().revokeToken(id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ const Status = {
|
|||
(relationshipReblog && relationshipReblog.muting)
|
||||
},
|
||||
shouldNotMute () {
|
||||
if (this.isFocused) return true
|
||||
const { status } = this
|
||||
const { reblog } = status
|
||||
return (
|
||||
|
|
@ -535,6 +536,7 @@ const Status = {
|
|||
this.controlledToggleThreadDisplay()
|
||||
},
|
||||
scrollIfHighlighted (highlightId) {
|
||||
if (this.$el.getBoundingClientRect == null) return
|
||||
const id = highlightId
|
||||
if (this.status.id === id) {
|
||||
const rect = this.$el.getBoundingClientRect()
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ const ThreadTree = {
|
|||
pinnedStatusIdsObject: Object,
|
||||
profileUserId: String,
|
||||
|
||||
focused: Function,
|
||||
isFocusedFunction: Function,
|
||||
highlight: String,
|
||||
getReplies: Function,
|
||||
setHighlight: Function,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
:statusoid="status"
|
||||
:expandable="!isExpanded"
|
||||
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
|
||||
:focused="focused(status.id)"
|
||||
:focused="isFocusedFunction(status.id)"
|
||||
:in-conversation="isExpanded"
|
||||
:highlight="highlight"
|
||||
:replies="getReplies(status.id)"
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
:pinned-status-ids-object="pinnedStatusIdsObject"
|
||||
:profile-user-id="profileUserId"
|
||||
|
||||
:focused="focused"
|
||||
:is-focused-function="isFocusedFunction"
|
||||
:get-replies="getReplies"
|
||||
:highlight="highlight"
|
||||
:set-highlight="setHighlight"
|
||||
|
|
|
|||
|
|
@ -146,8 +146,13 @@
|
|||
{{ $t('settings.profile_tab') }}
|
||||
</h1>
|
||||
</div>
|
||||
<div>
|
||||
<span v-if="error">{{ error }}</span>
|
||||
<div class="panel-body">
|
||||
<div
|
||||
v-if="error"
|
||||
class="alert error"
|
||||
>
|
||||
<span class="error-message">{{ error }}</span>
|
||||
</div>
|
||||
<FAIcon
|
||||
v-else
|
||||
spin
|
||||
|
|
@ -235,6 +240,16 @@
|
|||
align-items: center;
|
||||
padding: 7em;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 0.75em 5em;
|
||||
border-width: 2px;
|
||||
|
||||
.error-message {
|
||||
color: var(--text);
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -439,7 +439,7 @@
|
|||
"import_failure": "The selected file is not a supported Pleroma filter.",
|
||||
"help": {
|
||||
"word": "Simple and RegExp filters test against post's content and subject.",
|
||||
"user": "User filter matches full user handle (user@domain) in the following: author, reply-to and mentions",
|
||||
"user": "User filter matches full user handle (user{'@'}domain) in the following: author, reply-to and mentions",
|
||||
"regexp": "Regex variants are more advanced and use {link} to match instead of simple substring search.",
|
||||
"regexp_link": "Regular Expressions",
|
||||
"regexp_url": "https://en.wikipedia.org/wiki/Regular_expression"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import config from './config.js'
|
|||
import profileConfig from './profileConfig.js'
|
||||
import adminSettings from './adminSettings.js'
|
||||
import authFlow from './auth_flow.js'
|
||||
import oauthTokens from './oauth_tokens.js'
|
||||
import drafts from './drafts.js'
|
||||
import chats from './chats.js'
|
||||
|
||||
|
|
@ -21,7 +20,6 @@ export default {
|
|||
profileConfig,
|
||||
adminSettings,
|
||||
authFlow,
|
||||
oauthTokens,
|
||||
drafts,
|
||||
chats
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
const oauthTokens = {
|
||||
state: {
|
||||
tokens: []
|
||||
},
|
||||
actions: {
|
||||
fetchTokens ({ rootState, commit }) {
|
||||
rootState.api.backendInteractor.fetchOAuthTokens().then((tokens) => {
|
||||
commit('swapTokens', tokens)
|
||||
})
|
||||
},
|
||||
revokeToken ({ rootState, commit, state }, id) {
|
||||
rootState.api.backendInteractor.revokeOAuthToken({ id }).then((response) => {
|
||||
if (response.status === 201) {
|
||||
commit('swapTokens', state.tokens.filter(token => token.id !== id))
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
mutations: {
|
||||
swapTokens (state, tokens) {
|
||||
state.tokens = tokens
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default oauthTokens
|
||||
|
|
@ -1366,7 +1366,7 @@ const search2 = ({ credentials, q, resolve, limit, offset, following, type }) =>
|
|||
}
|
||||
|
||||
if (type) {
|
||||
params.push(['following', type])
|
||||
params.push(['type', type])
|
||||
}
|
||||
|
||||
params.push(['with_relationships', true])
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ export const muteFilterHits = (muteFilters, status) => {
|
|||
const poster = status.user.screen_name.toLowerCase()
|
||||
const mentions = (status.attentions || []).map(att => att.screen_name.toLowerCase())
|
||||
|
||||
console.log(status)
|
||||
|
||||
return muteFilters.toSorted((a,b) => b.order - a.order).map(filter => {
|
||||
const { hide, expires, name, value, type, enabled} = filter
|
||||
|
|
@ -14,7 +13,8 @@ export const muteFilterHits = (muteFilters, status) => {
|
|||
if (expires !== null && expires < Date.now()) return false
|
||||
switch (type) {
|
||||
case 'word': {
|
||||
if (statusText.includes(value) || statusSummary.includes(value)) {
|
||||
const lowercaseValue = value.toLowerCase()
|
||||
if (statusText.toLowerCase().includes(lowercaseValue) || statusSummary.toLowerCase().includes(lowercaseValue)) {
|
||||
return { hide, name }
|
||||
}
|
||||
break
|
||||
|
|
|
|||
|
|
@ -521,16 +521,18 @@ export const useInterfaceStore = defineStore('interface', {
|
|||
theme3hacks
|
||||
} = window.vuex.state.config
|
||||
this.themeChangeInProgress = true
|
||||
// If we're not not forced to recompile try using
|
||||
// If we're not forced to recompile try using
|
||||
// cache (tryLoadCache return true if load successful)
|
||||
|
||||
const forceRecompile = forceThemeRecompilation || recompile
|
||||
|
||||
await this.getThemeData()
|
||||
|
||||
if (!forceRecompile && !themeDebug && await tryLoadCache()) {
|
||||
this.themeChangeInProgress = false
|
||||
return this.setThemeApplied()
|
||||
}
|
||||
window.splashUpdate('splash.theme')
|
||||
await this.getThemeData()
|
||||
|
||||
try {
|
||||
const paletteIss = (() => {
|
||||
|
|
|
|||
24
src/stores/oauth_tokens.js
Normal file
24
src/stores/oauth_tokens.js
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useOAuthTokensStore = defineStore('oauthTokens', {
|
||||
state: () => ({
|
||||
tokens: []
|
||||
}),
|
||||
actions: {
|
||||
fetchTokens () {
|
||||
window.vuex.state.api.backendInteractor.fetchOAuthTokens().then((tokens) => {
|
||||
this.swapTokens(tokens)
|
||||
})
|
||||
},
|
||||
revokeToken (id) {
|
||||
window.vuex.state.api.backendInteractor.revokeOAuthToken({ id }).then((response) => {
|
||||
if (response.status === 201) {
|
||||
this.swapTokens(this.tokens.filter(token => token.id !== id))
|
||||
}
|
||||
})
|
||||
},
|
||||
swapTokens (tokens) {
|
||||
this.tokens = tokens
|
||||
}
|
||||
}
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue