Merge remote-tracking branch 'origin/develop' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2025-05-21 20:47:48 +03:00
commit 4a1914d71c
24 changed files with 1265 additions and 951 deletions

View file

View file

@ -0,0 +1 @@
Fix error styling for user profiles

View file

@ -0,0 +1 @@
Indicate currently active V3 theme as a body element class

View file

@ -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",

View file

@ -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')

View file

@ -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] || []
},

View file

@ -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)"

View file

@ -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: {

View file

@ -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

View file

@ -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: {

View file

@ -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)
}
}
}

View file

@ -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()

View file

@ -26,7 +26,7 @@ const ThreadTree = {
pinnedStatusIdsObject: Object,
profileUserId: String,
focused: Function,
isFocusedFunction: Function,
highlight: String,
getReplies: Function,
setHighlight: Function,

View file

@ -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"

View file

@ -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>

View file

@ -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"

View file

@ -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
}

View file

@ -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

View file

@ -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])

View file

@ -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

View file

@ -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 = (() => {

View 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
}
}
});

2021
yarn.lock

File diff suppressed because it is too large Load diff