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

This commit is contained in:
Henry Jameson 2026-08-12 01:48:26 +03:00
commit ef31db498d
10 changed files with 85 additions and 6 deletions

View file

@ -0,0 +1 @@
Fixed server-side domain mutes rendering/api calls

View file

@ -0,0 +1 @@
Fix Theme 2 fonts falling back to serif after upgrade

View file

@ -0,0 +1 @@
Fixed status index approxmiation in timeline rendering for dynamically changing viewport geometries

View file

@ -153,7 +153,6 @@
</div> </div>
</template> </template>
<template #item="{item}"> <template #item="{item}">
{{ item }}
<DomainMuteCard :domain="item" /> <DomainMuteCard :domain="item" />
</template> </template>
<template #empty> <template #empty>

View file

@ -263,7 +263,10 @@ const Timeline = {
// Start from approximating the index of some visible status by using the // Start from approximating the index of some visible status by using the
// the center of the screen on the timeline. // the center of the screen on the timeline.
let approxIndex = Math.floor(statuses.length * (centerOfScreen / height)) let approxIndex = Math.min(
Math.floor(statuses.length * (centerOfScreen / height)),
statuses.length - 1,
)
let err = statuses[approxIndex].getBoundingClientRect().y let err = statuses[approxIndex].getBoundingClientRect().y
// if we have a previous scroll index that can be used, test if it's // if we have a previous scroll index that can be used, test if it's

View file

@ -37,8 +37,10 @@ import {
import { import {
blockUser as apiBlockUser, blockUser as apiBlockUser,
editUserNote as apiEditUserNote, editUserNote as apiEditUserNote,
muteDomain as apiMuteDomain,
muteUser as apiMuteUser, muteUser as apiMuteUser,
unblockUser as apiUnblockUser, unblockUser as apiUnblockUser,
unmuteDomain as apiUnmuteDomain,
unmuteUser as apiUnmuteUser, unmuteUser as apiUnmuteUser,
fetchBlocks, fetchBlocks,
fetchDomainMutes, fetchDomainMutes,
@ -170,14 +172,14 @@ const showReblogs = (store, userId) => {
} }
const muteDomain = (store, domain) => { const muteDomain = (store, domain) => {
return muteDomain({ return apiMuteDomain({
domain, domain,
credentials: useOAuthStore().token, credentials: useOAuthStore().token,
}).then(() => store.commit('addDomainMute', domain)) }).then(() => store.commit('addDomainMute', domain))
} }
const unmuteDomain = (store, domain) => { const unmuteDomain = (store, domain) => {
return unmuteDomain({ return apiUnmuteDomain({
domain, domain,
credentials: useOAuthStore().token, credentials: useOAuthStore().token,
}).then(() => store.commit('removeDomainMute', domain)) }).then(() => store.commit('removeDomainMute', domain))

View file

@ -92,6 +92,11 @@ export const adoptStyleSheets = throttle(() => {
const EAGER_STYLE_ID = 'pleroma-eager-styles' const EAGER_STYLE_ID = 'pleroma-eager-styles'
const LAZY_STYLE_ID = 'pleroma-lazy-styles' const LAZY_STYLE_ID = 'pleroma-lazy-styles'
export const hasInvalidCachedThemeRules = (data) =>
data
.flat()
.some((rule) => /--(?:mono)?font:\s*\[object Object\](?:;|$)/i.test(rule))
const generateTheme = (inputRuleset, callbacks, debug) => { const generateTheme = (inputRuleset, callbacks, debug) => {
const { const {
onNewRule = () => { onNewRule = () => {
@ -151,7 +156,8 @@ export const tryLoadCache = async () => {
if ( if (
cache.engineChecksum === getEngineChecksum() && cache.engineChecksum === getEngineChecksum() &&
cache.checksum !== undefined && cache.checksum !== undefined &&
cache.checksum === useMergedConfigStore().mergedConfig.themeChecksum cache.checksum === useMergedConfigStore().mergedConfig.themeChecksum &&
!hasInvalidCachedThemeRules(cache.data)
) { ) {
const eagerStyles = createStyleSheet(EAGER_STYLE_ID, 10) const eagerStyles = createStyleSheet(EAGER_STYLE_ID, 10)
const lazyStyles = createStyleSheet(LAZY_STYLE_ID, 20) const lazyStyles = createStyleSheet(LAZY_STYLE_ID, 20)

View file

@ -266,7 +266,7 @@ export const convertTheme2To3 = (data) => {
Object.keys(data.fonts || {}).forEach((key) => { Object.keys(data.fonts || {}).forEach((key) => {
if (!fontsKeys.has(key)) return if (!fontsKeys.has(key)) return
if (!data.fonts[key]) return if (!data.fonts[key]) return
const originalFont = data.fonts[key] const originalFont = data.fonts[key].family
const rule = { source: '2to3' } const rule = { source: '2to3' }
switch (key) { switch (key) {

View file

@ -0,0 +1,24 @@
import { hasInvalidCachedThemeRules } from 'src/services/style_setter/style_setter.js'
describe('style setter cache', () => {
it('rejects cached rules containing serialized objects', () => {
expect(
hasInvalidCachedThemeRules([
['html { --font: [object Object]; }'],
['.post { --font: sans-serif; }'],
]),
).to.equal(true)
})
it('accepts cached rules containing valid font families', () => {
expect(
hasInvalidCachedThemeRules([
['html { --font: sans-serif; }'],
[
'.post { --font: "Atkinson Hyperlegible"; }',
'.post::after { content: "[object Object]"; }',
],
]),
).to.equal(false)
})
})

View file

@ -0,0 +1,42 @@
import {
basePaletteKeys,
convertTheme2To3,
} from 'src/services/theme_data/theme2_to_theme3.js'
describe('Theme 2 to Theme 3 conversion', () => {
it('converts font descriptors to CSS font families', () => {
const colors = Object.fromEntries(
[...basePaletteKeys].map((key) => [key, '#000000']),
)
const rules = convertTheme2To3({
colors,
fonts: {
interface: { family: 'sans-serif' },
input: { family: 'Open Sans' },
post: { family: 'Atkinson Hyperlegible' },
postCode: { family: 'monospace' },
},
})
expect(rules).to.deep.include({
source: '2to3',
component: 'Root',
directives: { '--font': 'generic | sans-serif' },
})
expect(rules).to.deep.include({
source: '2to3',
component: 'Root',
directives: { '--monoFont': 'generic | monospace' },
})
expect(rules).to.deep.include({
source: '2to3',
component: 'Input',
directives: { '--font': 'generic | Open Sans' },
})
expect(rules).to.deep.include({
source: '2to3',
component: 'RichContent',
directives: { '--font': 'generic | Atkinson Hyperlegible' },
})
})
})