Merge remote-tracking branch 'origin/develop' into from/develop/tusooa/sw-cache-assets
This commit is contained in:
commit
a1f43234cd
235 changed files with 6354 additions and 4065 deletions
|
|
@ -1 +1 @@
|
||||||
18.20.7
|
18.20.8
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
{
|
{
|
||||||
"extends": [
|
"extends": [
|
||||||
"stylelint-rscss/config",
|
|
||||||
"stylelint-config-standard",
|
"stylelint-config-standard",
|
||||||
"stylelint-config-recommended-scss",
|
"stylelint-config-recommended-scss",
|
||||||
"stylelint-config-html",
|
"stylelint-config-html",
|
||||||
|
|
@ -8,15 +7,6 @@
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
"declaration-no-important": true,
|
"declaration-no-important": true,
|
||||||
"rscss/no-descendant-combinator": false,
|
|
||||||
"rscss/class-format": [
|
|
||||||
false,
|
|
||||||
{
|
|
||||||
"component": "pascal-case",
|
|
||||||
"variant": "^-[a-z]\\w+",
|
|
||||||
"element": "^[a-z]\\w+"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"selector-class-pattern": null,
|
"selector-class-pattern": null,
|
||||||
"import-notation": null,
|
"import-notation": null,
|
||||||
"custom-property-pattern": null,
|
"custom-property-pattern": null,
|
||||||
|
|
|
||||||
68
CHANGELOG.md
68
CHANGELOG.md
|
|
@ -2,6 +2,74 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||||
|
## 2.8.0
|
||||||
|
### Changed
|
||||||
|
- BREAKING: static/img/nsfw.2958239.png is now static/img/nsfw.DepQPhG0.png, which may affect people who specify exactly this path as the cover image
|
||||||
|
- BREAKING: static/emoji.json is replaced with a properly hashed path under static/js in the production build, meaning server admins cannot provide their own set of unicode emojis by overriding this file (custom (image-based) emojis not affected)
|
||||||
|
- Speed up initial boot.
|
||||||
|
- Updated our build system to support browsers:
|
||||||
|
Safari >= 15
|
||||||
|
Firefox >= 115
|
||||||
|
Android > 4
|
||||||
|
no Opera Mini support
|
||||||
|
no IE support
|
||||||
|
no "dead" (unmaintained) browsers support
|
||||||
|
|
||||||
|
This does not guarantee that browsers will or will not work.
|
||||||
|
|
||||||
|
- Use /api/v1/accounts/:id/follow for account subscriptions instead of the deprecated routes
|
||||||
|
- Modal layout for mobile has new layout to make it easy to use
|
||||||
|
- Better display of mute reason on posts
|
||||||
|
- Simplify the OAuth client_name to 'PleromaFE'
|
||||||
|
- Partially migrated from vuex to pinia
|
||||||
|
- Authenticate and subscribe to streaming after connection
|
||||||
|
- Tabs now have indentation for better visibility of which tab is currently active
|
||||||
|
- Upgraded Vue to version 3.5
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Support bookmark folders
|
||||||
|
- Some new default color schemes
|
||||||
|
- Added support for fetching /{resource}.custom.ext to allow adding instance-specific themes without altering sourcetree
|
||||||
|
- Post actions customization
|
||||||
|
- Support displaying time in absolute format
|
||||||
|
- Add draft management system
|
||||||
|
- Compress most kinds of images on upload.
|
||||||
|
- Added option to always convert images to JPEG format instead of using WebP when compressing images.
|
||||||
|
- Added configurable image compression option in general settings, allowing users to control whether images are compressed before upload.
|
||||||
|
- Inform users that Smithereen public polls are public
|
||||||
|
- Splash screen + loading indicator to make process of identifying initialization issues and load performance
|
||||||
|
- UI for making v3 themes and palettes, support for bundling v3 themes
|
||||||
|
- Make UserLink wrappable
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- Fixed occasional overflows in emoji picker and made header scrollable
|
||||||
|
- Updated shadow editor, hopefully fixed long-standing bugs, added ability to specify shadow's name.
|
||||||
|
- Checkbox vertical alignment
|
||||||
|
- Check for canvas extract permission when initializing favicon service
|
||||||
|
- Fix some of the color manipulation functions
|
||||||
|
- Fix draft saving when auto-save is off
|
||||||
|
- Switch from class hack to normalButton attribute for emoji count popover
|
||||||
|
- Fix emoji inconsistencies in notifications,
|
||||||
|
- Fix some emoji not scaling with interface
|
||||||
|
- Make sure hover style is also applied to :focus-visible
|
||||||
|
- Improved ToS and registration
|
||||||
|
- Fix small markup inconsistencies
|
||||||
|
- Fixed modals buttons overflow
|
||||||
|
- Fix whitespaces for multiple status mute reasons, display bot status reason
|
||||||
|
- Create an OAuth app only when needed
|
||||||
|
- Fix CSS compatibility issues in style_setter.js for older browsers like Palemoon
|
||||||
|
- Proper sticky header for conversations on user page
|
||||||
|
- Add text label for more actions button in post status form
|
||||||
|
- Reply-or-quote buttons now take less space
|
||||||
|
- Allow repeats of own posts with private scopes
|
||||||
|
- Bookmarks visible again on mobile
|
||||||
|
- Remove focusability on hidden popover in subject input
|
||||||
|
- Show only month and day instead of weird "day, hour" format.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
- BREAKING: drop support for browsers that do not support `<script type="module">`
|
||||||
|
- BREAKING: css source map does not work in production (see https://github.com/vitejs/vite/issues/2830 )
|
||||||
|
- Remove emoji annotations code for unused languages from final build
|
||||||
|
|
||||||
## 2.7.1
|
## 2.7.1
|
||||||
Bugfix release. Added small optimizations to emoji picker that should make it a bit more responsive, however it needs rather large change to make it more performant which might come in a major release.
|
Bugfix release. Added small optimizations to emoji picker that should make it a bit more responsive, however it needs rather large change to make it more performant which might come in a major release.
|
||||||
|
|
|
||||||
64
build/emojis_plugin.js
Normal file
64
build/emojis_plugin.js
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
import { access } from 'node:fs/promises'
|
||||||
|
import { languages, langCodeToCldrName } from '../src/i18n/languages.js'
|
||||||
|
|
||||||
|
const annotationsImportPrefix = '@kazvmoe-infra/unicode-emoji-json/annotations/'
|
||||||
|
const specialAnnotationsLocale = {
|
||||||
|
ja_easy: 'ja'
|
||||||
|
}
|
||||||
|
|
||||||
|
const internalToAnnotationsLocale = (internal) => specialAnnotationsLocale[internal] || internal
|
||||||
|
|
||||||
|
// This gets all the annotations that are accessible (whose language
|
||||||
|
// can be chosen in the settings). Data for other languages are
|
||||||
|
// discarded because there is no way for it to be fetched.
|
||||||
|
const getAllAccessibleAnnotations = async (projectRoot) => {
|
||||||
|
const imports = (await Promise.all(
|
||||||
|
languages
|
||||||
|
.map(async lang => {
|
||||||
|
const destLang = internalToAnnotationsLocale(lang)
|
||||||
|
const importModule = `${annotationsImportPrefix}${destLang}.json`
|
||||||
|
const importFile = resolve(projectRoot, 'node_modules', importModule)
|
||||||
|
try {
|
||||||
|
await access(importFile)
|
||||||
|
return `'${lang}': () => import('${importModule}')`
|
||||||
|
} catch (e) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
.filter(k => k)
|
||||||
|
.join(',\n')
|
||||||
|
|
||||||
|
return `
|
||||||
|
export const annotationsLoader = {
|
||||||
|
${imports}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
const emojiAnnotationsId = 'virtual:pleroma-fe/emoji-annotations'
|
||||||
|
const emojiAnnotationsIdResolved = '\0' + emojiAnnotationsId
|
||||||
|
|
||||||
|
const emojisPlugin = () => {
|
||||||
|
let projectRoot
|
||||||
|
return {
|
||||||
|
name: 'emojis-plugin',
|
||||||
|
configResolved (conf) {
|
||||||
|
projectRoot = conf.root
|
||||||
|
},
|
||||||
|
resolveId (id) {
|
||||||
|
if (id === emojiAnnotationsId) {
|
||||||
|
return emojiAnnotationsIdResolved
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
async load (id) {
|
||||||
|
if (id === emojiAnnotationsIdResolved) {
|
||||||
|
return await getAllAccessibleAnnotations(projectRoot)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default emojisPlugin
|
||||||
28
build/msw_plugin.js
Normal file
28
build/msw_plugin.js
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { resolve } from 'node:path'
|
||||||
|
import { readFile } from 'node:fs/promises'
|
||||||
|
|
||||||
|
const target = 'node_modules/msw/lib/mockServiceWorker.js'
|
||||||
|
|
||||||
|
const mswPlugin = () => {
|
||||||
|
let projectRoot
|
||||||
|
return {
|
||||||
|
name: 'msw-plugin',
|
||||||
|
apply: 'serve',
|
||||||
|
configResolved (conf) {
|
||||||
|
projectRoot = conf.root
|
||||||
|
},
|
||||||
|
configureServer (server) {
|
||||||
|
server.middlewares.use(async (req, res, next) => {
|
||||||
|
if (req.path === '/mockServiceWorker.js') {
|
||||||
|
const file = await readFile(resolve(projectRoot, target))
|
||||||
|
res.set('Content-Type', 'text/javascript')
|
||||||
|
res.send(file)
|
||||||
|
} else {
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default mswPlugin
|
||||||
1
changelog.d/akkoma-sharkey-net-support.add
Normal file
1
changelog.d/akkoma-sharkey-net-support.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Added support for Akkoma and IceShrimp.NET backend
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Added option to always convert images to JPEG format instead of using WebP when compressing images.
|
|
||||||
2
changelog.d/arithmetic-blend.add
Normal file
2
changelog.d/arithmetic-blend.add
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
Add arithmetic blend ISS function
|
||||||
|
|
||||||
1
changelog.d/better-scroll-button.add
Normal file
1
changelog.d/better-scroll-button.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Add support for detachable scrollTop button
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Updated shadow editor, hopefully fixed long-standing bugs, added ability to specify shadow's name.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Support bookmark folders
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Speed up initial boot.
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
Updated our build system to support browsers:
|
|
||||||
Safari >= 15
|
|
||||||
Firefox >= 115
|
|
||||||
Android > 4
|
|
||||||
no Opera Mini support
|
|
||||||
no IE support
|
|
||||||
no "dead" (unmaintained) browsers support
|
|
||||||
|
|
||||||
This does not guarantee that browsers will or will not work.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
checkbox vertical alignment has been fixed
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Some new default color schemes
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix some of the color manipulation functions
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
BREAKING: static/img/nsfw.2958239.png is now static/img/nsfw.DepQPhG0.png, which may affect people who specify exactly this path as the cover image
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Added support for fetching /{resource}.custom.ext to allow adding instance-specific themes without altering sourcetree
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Post actions can be customized
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Support displaying time in absolute format
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Use /api/v1/accounts/:id/follow for account subscriptions instead of the deprecated routes
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix draft saving when auto-save is off
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Add draft management system
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
fixed occasional overflows in emoji picker and made header scrollable
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
fix emoji inconsistencies in notifications, fix some emoji not scaling with interface
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Added configurable image compression option in general settings, allowing users to control whether images are compressed before upload.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix few markup panel inconsistencies; better ToS and registration
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix small markup inconsistencies
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
modal layout for mobile has new layout to make it easy to use
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
fixed modals buttons overflow
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Fix whitespaces for multiple status mute reasons, display bot status reason
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Added missing EN translation key for status.muted_user
|
|
||||||
1
changelog.d/mutes-sync.add
Normal file
1
changelog.d/mutes-sync.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Synchronized mutes, advanced mute control (regexp, expiry, naming)
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
better display of mute reason on posts
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
BREAKING: drop support for browsers that do not support `<script type="module">`
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
BREAKING: css source map does not work in production (see https://github.com/vitejs/vite/issues/2830 )
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Inform users that Smithereen public polls are public
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Simplify the OAuth client_name to 'PleromaFE'
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
proper sticky header for conversations on user page
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Partially migrated from vuex to pinia
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Add text label for more actions button in post status form
|
|
||||||
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 +0,0 @@
|
||||||
BREAKING: static/emoji.json is replaced with a properly hashed path under static/js in the production build, meaning server admins cannot provide their own set of unicode emojis by overriding this file (custom (image-based) emojis not affected)
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
reply-or-quote buttons now take less space
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Bookmarks visible again on mobile
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Splash screen + loading indicator to make process of identifying initialization issues and load performance
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Authenticate and subscribe to streaming after connection
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Tabs now have indentation for better visibility of which tab is currently active
|
|
||||||
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
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
UI for making v3 themes and palettes, support for bundling v3 themes
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Resize most kinds of images on upload.
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Make UserLink wrappable
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Upgraded Vue to version 3.5
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
Show only month and day instead of weird "day, hour" format. While at it, fixed typo "defualt" in a comment.
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
|
||||||
<link rel="preload" href="/static/config.json" as="fetch" crossorigin />
|
<link rel="preload" href="/static/config.json" as="fetch" crossorigin />
|
||||||
<link rel="preload" href="/api/pleroma/frontend_configurations" as="fetch" crossorigin />
|
<link rel="preload" href="/api/pleroma/frontend_configurations" as="fetch" crossorigin />
|
||||||
|
<link rel="preload" href="/nodeinfo/2.0.json" as="fetch" crossorigin />
|
||||||
<link rel="preload" href="/nodeinfo/2.1.json" as="fetch" crossorigin />
|
<link rel="preload" href="/nodeinfo/2.1.json" as="fetch" crossorigin />
|
||||||
<link rel="preload" href="/api/v1/instance" as="fetch" crossorigin />
|
<link rel="preload" href="/api/v1/instance" as="fetch" crossorigin />
|
||||||
<link rel="preload" href="/static/pleromatan_apology_fox_small.webp" as="image" />
|
<link rel="preload" href="/static/pleromatan_apology_fox_small.webp" as="image" />
|
||||||
|
|
|
||||||
77
package.json
77
package.json
|
|
@ -17,7 +17,7 @@
|
||||||
"lint-fix": "eslint --fix src test/unit/specs test/e2e/specs"
|
"lint-fix": "eslint --fix src test/unit/specs test/e2e/specs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "7.26.9",
|
"@babel/runtime": "7.27.1",
|
||||||
"@chenfengyuan/vue-qrcode": "2.0.0",
|
"@chenfengyuan/vue-qrcode": "2.0.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "6.7.2",
|
"@fortawesome/fontawesome-svg-core": "6.7.2",
|
||||||
"@fortawesome/free-regular-svg-icons": "6.7.2",
|
"@fortawesome/free-regular-svg-icons": "6.7.2",
|
||||||
|
|
@ -32,82 +32,83 @@
|
||||||
"body-scroll-lock": "3.1.5",
|
"body-scroll-lock": "3.1.5",
|
||||||
"chromatism": "3.0.0",
|
"chromatism": "3.0.0",
|
||||||
"click-outside-vue3": "4.0.1",
|
"click-outside-vue3": "4.0.1",
|
||||||
"cropperjs": "1.6.2",
|
"cropperjs": "2.0.0",
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
"hash-sum": "^2.0.0",
|
"hash-sum": "^2.0.0",
|
||||||
"js-cookie": "3.0.5",
|
"js-cookie": "3.0.5",
|
||||||
"localforage": "1.10.0",
|
"localforage": "1.10.0",
|
||||||
"parse-link-header": "2.0.0",
|
"parse-link-header": "2.0.0",
|
||||||
"phoenix": "1.7.19",
|
"phoenix": "1.7.21",
|
||||||
"pinia": "^2.0.33",
|
"pinia": "^3.0.0",
|
||||||
"punycode.js": "2.3.1",
|
"punycode.js": "2.3.1",
|
||||||
"qrcode": "1.5.4",
|
"qrcode": "1.5.4",
|
||||||
"querystring-es3": "0.2.1",
|
"querystring-es3": "0.2.1",
|
||||||
"url": "0.11.4",
|
"url": "0.11.4",
|
||||||
"utf8": "3.0.0",
|
"utf8": "3.0.0",
|
||||||
"vue": "3.5.13",
|
"uuid": "11.1.0",
|
||||||
"vue-i18n": "10",
|
"vue": "3.5.17",
|
||||||
"vue-router": "4.5.0",
|
"vue-i18n": "11",
|
||||||
|
"vue-router": "4.5.1",
|
||||||
"vue-virtual-scroller": "^2.0.0-beta.7",
|
"vue-virtual-scroller": "^2.0.0-beta.7",
|
||||||
"vuex": "4.1.0"
|
"vuex": "4.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.26.9",
|
"@babel/core": "7.27.1",
|
||||||
"@babel/eslint-parser": "7.26.8",
|
"@babel/eslint-parser": "7.27.1",
|
||||||
"@babel/plugin-transform-runtime": "7.26.9",
|
"@babel/plugin-transform-runtime": "7.27.1",
|
||||||
"@babel/preset-env": "7.26.9",
|
"@babel/preset-env": "7.27.2",
|
||||||
"@babel/register": "7.25.9",
|
"@babel/register": "7.27.1",
|
||||||
"@ungap/event-target": "0.2.4",
|
"@ungap/event-target": "0.2.4",
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||||
"@vitest/browser": "^3.0.7",
|
"@vitest/browser": "^3.0.7",
|
||||||
"@vitest/ui": "^3.0.7",
|
"@vitest/ui": "^3.0.7",
|
||||||
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
|
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
|
||||||
"@vue/babel-plugin-jsx": "1.2.5",
|
"@vue/babel-plugin-jsx": "1.4.0",
|
||||||
"@vue/compiler-sfc": "3.5.13",
|
"@vue/compiler-sfc": "3.5.17",
|
||||||
"@vue/test-utils": "2.4.6",
|
"@vue/test-utils": "2.4.6",
|
||||||
"autoprefixer": "10.4.20",
|
"autoprefixer": "10.4.21",
|
||||||
"babel-plugin-lodash": "3.3.4",
|
"babel-plugin-lodash": "3.3.4",
|
||||||
"chai": "4.5.0",
|
"chai": "5.2.0",
|
||||||
"chalk": "5.4.1",
|
"chalk": "5.4.1",
|
||||||
"chromedriver": "133.0.2",
|
"chromedriver": "135.0.4",
|
||||||
"connect-history-api-fallback": "2.0.0",
|
"connect-history-api-fallback": "2.0.0",
|
||||||
"cross-spawn": "7.0.6",
|
"cross-spawn": "7.0.6",
|
||||||
"custom-event-polyfill": "1.0.7",
|
"custom-event-polyfill": "1.0.7",
|
||||||
"eslint": "9.20.1",
|
"eslint": "9.26.0",
|
||||||
|
"vue-eslint-parser": "10.1.3",
|
||||||
"eslint-config-standard": "17.1.0",
|
"eslint-config-standard": "17.1.0",
|
||||||
"eslint-formatter-friendly": "7.0.0",
|
"eslint-formatter-friendly": "7.0.0",
|
||||||
"eslint-plugin-import": "2.31.0",
|
"eslint-plugin-import": "2.31.0",
|
||||||
"eslint-plugin-n": "17.15.1",
|
"eslint-plugin-n": "17.18.0",
|
||||||
"eslint-plugin-promise": "7.2.1",
|
"eslint-plugin-promise": "7.2.1",
|
||||||
"eslint-plugin-vue": "9.32.0",
|
"eslint-plugin-vue": "10.1.0",
|
||||||
"eventsource-polyfill": "0.9.6",
|
"eventsource-polyfill": "0.9.6",
|
||||||
"express": "4.21.2",
|
"express": "5.1.0",
|
||||||
"function-bind": "1.1.2",
|
"function-bind": "1.1.2",
|
||||||
"http-proxy-middleware": "3.0.3",
|
"http-proxy-middleware": "3.0.5",
|
||||||
"iso-639-1": "3.1.5",
|
"iso-639-1": "3.1.5",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"nightwatch": "2.6.25",
|
"msw": "2.10.2",
|
||||||
"opn": "5.5.0",
|
"nightwatch": "3.12.1",
|
||||||
"ora": "0.4.1",
|
"playwright": "1.52.0",
|
||||||
"playwright": "1.49.1",
|
"postcss": "8.5.3",
|
||||||
"postcss": "8.5.2",
|
|
||||||
"postcss-html": "^1.5.0",
|
"postcss-html": "^1.5.0",
|
||||||
"postcss-scss": "^4.0.6",
|
"postcss-scss": "^4.0.6",
|
||||||
"sass": "1.85.0",
|
"sass": "1.89.2",
|
||||||
"selenium-server": "3.141.59",
|
"selenium-server": "3.141.59",
|
||||||
"semver": "7.7.1",
|
"semver": "7.7.2",
|
||||||
"serve-static": "1.16.2",
|
"serve-static": "2.2.0",
|
||||||
"shelljs": "0.8.5",
|
"shelljs": "0.10.0",
|
||||||
"sinon": "15.2.0",
|
"sinon": "20.0.0",
|
||||||
"sinon-chai": "3.7.0",
|
"sinon-chai": "4.0.0",
|
||||||
"stylelint": "14.16.1",
|
"stylelint": "16.19.1",
|
||||||
"stylelint-config-html": "^1.1.0",
|
"stylelint-config-html": "^1.1.0",
|
||||||
"stylelint-config-recommended-scss": "^8.0.0",
|
"stylelint-config-recommended": "^16.0.0",
|
||||||
"stylelint-config-recommended-vue": "^1.4.0",
|
"stylelint-config-recommended-scss": "^14.0.0",
|
||||||
"stylelint-config-standard": "29.0.0",
|
"stylelint-config-recommended-vue": "^1.6.0",
|
||||||
"stylelint-rscss": "0.4.0",
|
"stylelint-config-standard": "38.0.0",
|
||||||
"vite": "^6.1.0",
|
"vite": "^6.1.0",
|
||||||
"vite-plugin-eslint2": "^5.0.3",
|
"vite-plugin-eslint2": "^5.0.3",
|
||||||
"vite-plugin-stylelint": "^6.0.0",
|
"vite-plugin-stylelint": "^6.0.0",
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@
|
||||||
accent: #1CA4F3;
|
accent: #1CA4F3;
|
||||||
cBlue: #1CA4F3;
|
cBlue: #1CA4F3;
|
||||||
cRed: #f41a51;
|
cRed: #f41a51;
|
||||||
cGreen: #1af46e;
|
cGreen: #0b6a30;
|
||||||
cOrange: #f4af1a;
|
cOrange: #f4af1a;
|
||||||
border: #d8e6f9;
|
border: #d8e6f9;
|
||||||
link: #1CA4F3;
|
link: #1CA4F3;
|
||||||
|
|
@ -39,7 +39,7 @@
|
||||||
accent: #1CA4F3;
|
accent: #1CA4F3;
|
||||||
cRed: #f41a51;
|
cRed: #f41a51;
|
||||||
cBlue: #1CA4F3;
|
cBlue: #1CA4F3;
|
||||||
cGreen: #1af46e;
|
cGreen: #0b6a30;
|
||||||
cOrange: #f4af1a;
|
cOrange: #f4af1a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,45 +47,46 @@ Root {
|
||||||
--badgeNotification: color | --cRed;
|
--badgeNotification: color | --cRed;
|
||||||
--buttonDefaultHoverGlow: shadow | inset 0 0 0 1 --accent / 1;
|
--buttonDefaultHoverGlow: shadow | inset 0 0 0 1 --accent / 1;
|
||||||
--buttonDefaultFocusGlow: shadow | inset 0 0 0 1 --accent / 1;
|
--buttonDefaultFocusGlow: shadow | inset 0 0 0 1 --accent / 1;
|
||||||
--buttonDefaultShadow: shadow | inset 0 0 0 1 --parent--text / 0.35, 0 5 5 -5 #000000 / 0.35;
|
--buttonDefaultShadow: shadow | inset 0 0 0 1 --text / 0.35, 0 5 5 -5 #000000 / 0.35;
|
||||||
--buttonDefaultBevel: shadow | inset 0 14 14 -14 #FFFFFF / 0.1;
|
--buttonDefaultBevel: shadow | inset 0 14 14 -14 #FFFFFF / 0.1;
|
||||||
--buttonPressedBevel: shadow | inset 0 -20 20 -20 #000000 / 0.05;
|
--buttonPressedBevel: shadow | inset 0 -20 20 -20 #000000 / 0.05;
|
||||||
--defaultInputBevel: shadow | inset 0 0 0 1 --parent--text / 0.35;
|
--defaultInputBevel: shadow | inset 0 0 0 1 --text / 0.35;
|
||||||
--defaultInputHoverGlow: shadow | 0 0 0 1 --accent / 1;
|
--defaultInputHoverGlow: shadow | 0 0 0 1 --accent / 1;
|
||||||
--defaultInputFocusGlow: shadow | 0 0 0 1 --link / 1;
|
--defaultInputFocusGlow: shadow | 0 0 0 1 --link / 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
background: --parent;
|
||||||
|
}
|
||||||
|
|
||||||
Button:disabled {
|
Button:disabled {
|
||||||
shadow: --buttonDefaultBevel, --buttonDefaultShadow
|
shadow: --buttonDefaultBevel, --buttonDefaultShadow
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:hover {
|
Button:hover {
|
||||||
|
background: --inheritedBackground;
|
||||||
shadow: --buttonDefaultHoverGlow, --buttonDefaultBevel, --buttonDefaultShadow
|
shadow: --buttonDefaultHoverGlow, --buttonDefaultBevel, --buttonDefaultShadow
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:toggled {
|
Button:toggled {
|
||||||
background: $blend(--bg 0.3 --accent)
|
background: $blend(--inheritedBackground 0.3 --accent)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:pressed {
|
Button:pressed {
|
||||||
background: $blend(--bg 0.8 --accent)
|
background: $blend(--inheritedBackground 0.8 --accent)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:pressed:toggled {
|
Button:pressed:toggled {
|
||||||
background: $blend(--bg 0.2 --accent)
|
background: $blend(--inheritedBackground 0.2 --accent)
|
||||||
}
|
}
|
||||||
|
|
||||||
Button:toggled:hover {
|
Button:toggled:hover {
|
||||||
background: $blend(--bg 0.3 --accent)
|
background: $blend(--inheritedBackground 0.3 --accent)
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
background: --parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Input {
|
Input {
|
||||||
shadow: --defaultInputBevel;
|
shadow: --defaultInputBevel;
|
||||||
background: --parent;
|
background: $mod(--bg -10);
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelHeader {
|
PanelHeader {
|
||||||
|
|
@ -97,5 +98,5 @@ Tab:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
Tab {
|
Tab {
|
||||||
background: --parent;
|
background: --bg;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,21 @@ PanelHeader {
|
||||||
background: --fg
|
background: --fg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PanelHeader ButtonUnstyled Icon {
|
||||||
|
textColor: --text;
|
||||||
|
textAuto: 'no-preserve'
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelHeader Button Icon {
|
||||||
|
textColor: --text;
|
||||||
|
textAuto: 'no-preserve'
|
||||||
|
}
|
||||||
|
|
||||||
|
PanelHeader Button Text {
|
||||||
|
textColor: --text;
|
||||||
|
textAuto: 'no-preserve'
|
||||||
|
}
|
||||||
|
|
||||||
Tab:hover {
|
Tab:hover {
|
||||||
background: --bg;
|
background: --bg;
|
||||||
shadow: --buttonDefaultBevel
|
shadow: --buttonDefaultBevel
|
||||||
|
|
@ -172,6 +187,14 @@ MenuItem:hover {
|
||||||
background: --fg
|
background: --fg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MenuItem:active {
|
||||||
|
background: --fg
|
||||||
|
}
|
||||||
|
|
||||||
|
MenuItem:active:hover {
|
||||||
|
background: --fg
|
||||||
|
}
|
||||||
|
|
||||||
Popover {
|
Popover {
|
||||||
shadow: --buttonDefaultBevel, 5 5 0 0 #000000 / 0.2;
|
shadow: --buttonDefaultBevel, 5 5 0 0 #000000 / 0.2;
|
||||||
roundness: 0
|
roundness: 0
|
||||||
|
|
|
||||||
57
src/App.js
57
src/App.js
|
|
@ -21,6 +21,8 @@ import { defineAsyncComponent } from 'vue'
|
||||||
import { useShoutStore } from './stores/shout'
|
import { useShoutStore } from './stores/shout'
|
||||||
import { useInterfaceStore } from './stores/interface'
|
import { useInterfaceStore } from './stores/interface'
|
||||||
|
|
||||||
|
import { throttle } from 'lodash'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'app',
|
name: 'app',
|
||||||
components: {
|
components: {
|
||||||
|
|
@ -51,6 +53,9 @@ export default {
|
||||||
themeApplied () {
|
themeApplied () {
|
||||||
this.removeSplash()
|
this.removeSplash()
|
||||||
},
|
},
|
||||||
|
currentTheme () {
|
||||||
|
this.setThemeBodyClass()
|
||||||
|
},
|
||||||
layoutType () {
|
layoutType () {
|
||||||
document.getElementById('modal').classList = ['-' + this.layoutType]
|
document.getElementById('modal').classList = ['-' + this.layoutType]
|
||||||
}
|
}
|
||||||
|
|
@ -59,22 +64,41 @@ export default {
|
||||||
// Load the locale from the storage
|
// Load the locale from the storage
|
||||||
const val = this.$store.getters.mergedConfig.interfaceLanguage
|
const val = this.$store.getters.mergedConfig.interfaceLanguage
|
||||||
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
|
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
|
||||||
window.addEventListener('resize', this.updateMobileState)
|
|
||||||
document.getElementById('modal').classList = ['-' + this.layoutType]
|
document.getElementById('modal').classList = ['-' + this.layoutType]
|
||||||
|
|
||||||
|
// Create bound handlers
|
||||||
|
this.updateScrollState = throttle(this.scrollHandler, 200)
|
||||||
|
this.updateMobileState = throttle(this.resizeHandler, 200)
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
window.addEventListener('resize', this.updateMobileState)
|
||||||
|
this.scrollParent.addEventListener('scroll', this.updateScrollState)
|
||||||
|
|
||||||
if (useInterfaceStore().themeApplied) {
|
if (useInterfaceStore().themeApplied) {
|
||||||
|
this.setThemeBodyClass()
|
||||||
this.removeSplash()
|
this.removeSplash()
|
||||||
}
|
}
|
||||||
getOrCreateServiceWorker()
|
getOrCreateServiceWorker()
|
||||||
},
|
},
|
||||||
unmounted () {
|
unmounted () {
|
||||||
window.removeEventListener('resize', this.updateMobileState)
|
window.removeEventListener('resize', this.updateMobileState)
|
||||||
|
this.scrollParent.removeEventListener('scroll', this.updateScrollState)
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
themeApplied () {
|
themeApplied () {
|
||||||
return useInterfaceStore().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 () {
|
layoutModalClass () {
|
||||||
return '-' + this.layoutType
|
return '-' + this.layoutType
|
||||||
},
|
},
|
||||||
|
|
@ -148,13 +172,42 @@ export default {
|
||||||
},
|
},
|
||||||
noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
|
noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders },
|
||||||
showScrollbars () { return this.$store.getters.mergedConfig.showScrollbars },
|
showScrollbars () { return this.$store.getters.mergedConfig.showScrollbars },
|
||||||
|
scrollParent () { return window; /* this.$refs.appContentRef */ },
|
||||||
...mapGetters(['mergedConfig'])
|
...mapGetters(['mergedConfig'])
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateMobileState () {
|
resizeHandler () {
|
||||||
useInterfaceStore().setLayoutWidth(windowWidth())
|
useInterfaceStore().setLayoutWidth(windowWidth())
|
||||||
useInterfaceStore().setLayoutHeight(windowHeight())
|
useInterfaceStore().setLayoutHeight(windowHeight())
|
||||||
},
|
},
|
||||||
|
scrollHandler () {
|
||||||
|
const scrollPosition = this.scrollParent === window ? window.scrollY : this.scrollParent.scrollTop
|
||||||
|
|
||||||
|
if (scrollPosition != 0) {
|
||||||
|
this.$refs.appContentRef.classList.add(['-scrolled'])
|
||||||
|
} else {
|
||||||
|
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 () {
|
removeSplash () {
|
||||||
document.querySelector('#status').textContent = this.$t('splash.fun_' + Math.ceil(Math.random() * 4))
|
document.querySelector('#status').textContent = this.$t('splash.fun_' + Math.ceil(Math.random() * 4))
|
||||||
const splashscreenRoot = document.querySelector('#splash')
|
const splashscreenRoot = document.querySelector('#splash')
|
||||||
|
|
|
||||||
17
src/App.scss
17
src/App.scss
|
|
@ -34,8 +34,7 @@ body {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
overscroll-behavior-y: none;
|
overscroll-behavior-y: none;
|
||||||
overflow-x: clip;
|
overflow: clip scroll;
|
||||||
overflow-y: scroll;
|
|
||||||
|
|
||||||
&.hidden {
|
&.hidden {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
@ -224,9 +223,8 @@ nav {
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
align-content: flex-start;
|
place-content: flex-start center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
overflow-x: clip;
|
overflow-x: clip;
|
||||||
|
|
||||||
|
|
@ -262,8 +260,7 @@ nav {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: var(--navbar-height);
|
top: var(--navbar-height);
|
||||||
max-height: calc(100vh - var(--navbar-height));
|
max-height: calc(100vh - var(--navbar-height));
|
||||||
overflow-y: auto;
|
overflow: hidden auto;
|
||||||
overflow-x: hidden;
|
|
||||||
margin-left: calc(var(--___paddingIncrease) * -1);
|
margin-left: calc(var(--___paddingIncrease) * -1);
|
||||||
padding-left: calc(var(--___paddingIncrease) + var(--___columnMargin) / 2);
|
padding-left: calc(var(--___paddingIncrease) + var(--___columnMargin) / 2);
|
||||||
|
|
||||||
|
|
@ -388,6 +385,10 @@ nav {
|
||||||
&:disabled {
|
&:disabled {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translate(1px, 1px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menu-item {
|
.menu-item {
|
||||||
|
|
@ -828,7 +829,7 @@ option {
|
||||||
.login-hint {
|
.login-hint {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
@media all and (min-width: 801px) {
|
@media all and (width >= 801px) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -850,7 +851,7 @@ option {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media all and (max-width: 800px) {
|
@media all and (width <= 800px) {
|
||||||
.mobile-hidden {
|
.mobile-hidden {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
<Notifications v-if="currentUser" />
|
<Notifications v-if="currentUser" />
|
||||||
<div
|
<div
|
||||||
id="content"
|
id="content"
|
||||||
|
ref="appContentRef"
|
||||||
class="app-layout container"
|
class="app-layout container"
|
||||||
:class="classes"
|
:class="classes"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* global process */
|
||||||
import { createApp } from 'vue'
|
import { createApp } from 'vue'
|
||||||
import { createRouter, createWebHistory } from 'vue-router'
|
import { createRouter, createWebHistory } from 'vue-router'
|
||||||
import vClickOutside from 'click-outside-vue3'
|
import vClickOutside from 'click-outside-vue3'
|
||||||
|
|
@ -11,12 +12,12 @@ import routes from './routes'
|
||||||
import VBodyScrollLock from 'src/directives/body_scroll_lock'
|
import VBodyScrollLock from 'src/directives/body_scroll_lock'
|
||||||
|
|
||||||
import { windowWidth, windowHeight } from '../services/window_utils/window_utils'
|
import { windowWidth, windowHeight } from '../services/window_utils/window_utils'
|
||||||
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
|
|
||||||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||||
import { applyConfig } from '../services/style_setter/style_setter.js'
|
import { applyConfig } from '../services/style_setter/style_setter.js'
|
||||||
import FaviconService from '../services/favicon_service/favicon_service.js'
|
import FaviconService from '../services/favicon_service/favicon_service.js'
|
||||||
import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
|
import { initServiceWorker, updateFocus } from '../services/sw/sw.js'
|
||||||
|
|
||||||
|
import { useOAuthStore } from 'src/stores/oauth'
|
||||||
import { useI18nStore } from 'src/stores/i18n'
|
import { useI18nStore } from 'src/stores/i18n'
|
||||||
import { useInterfaceStore } from 'src/stores/interface'
|
import { useInterfaceStore } from 'src/stores/interface'
|
||||||
import { useAnnouncementsStore } from 'src/stores/announcements'
|
import { useAnnouncementsStore } from 'src/stores/announcements'
|
||||||
|
|
@ -62,10 +63,11 @@ const getInstanceConfig = async ({ store }) => {
|
||||||
const textlimit = data.max_toot_chars
|
const textlimit = data.max_toot_chars
|
||||||
const vapidPublicKey = data.pleroma.vapid_public_key
|
const vapidPublicKey = data.pleroma.vapid_public_key
|
||||||
|
|
||||||
|
store.dispatch('setInstanceOption', { name: 'pleromaExtensionsAvailable', value: data.pleroma })
|
||||||
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
|
store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit })
|
||||||
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
|
store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required })
|
||||||
store.dispatch('setInstanceOption', { name: 'birthdayRequired', value: !!data.pleroma.metadata.birthday_required })
|
store.dispatch('setInstanceOption', { name: 'birthdayRequired', value: !!data.pleroma?.metadata.birthday_required })
|
||||||
store.dispatch('setInstanceOption', { name: 'birthdayMinAge', value: data.pleroma.metadata.birthday_min_age || 0 })
|
store.dispatch('setInstanceOption', { name: 'birthdayMinAge', value: data.pleroma?.metadata.birthday_min_age || 0 })
|
||||||
|
|
||||||
if (vapidPublicKey) {
|
if (vapidPublicKey) {
|
||||||
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
|
store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey })
|
||||||
|
|
@ -77,6 +79,8 @@ const getInstanceConfig = async ({ store }) => {
|
||||||
console.error('Could not load instance config, potentially fatal')
|
console.error('Could not load instance config, potentially fatal')
|
||||||
console.error(error)
|
console.error(error)
|
||||||
}
|
}
|
||||||
|
// We should check for scrobbles support here but it requires userId
|
||||||
|
// so instead we check for it where it's fetched (statuses.js)
|
||||||
}
|
}
|
||||||
|
|
||||||
const getBackendProvidedConfig = async () => {
|
const getBackendProvidedConfig = async () => {
|
||||||
|
|
@ -228,17 +232,9 @@ const getStickers = async ({ store }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const getAppSecret = async ({ store }) => {
|
const getAppSecret = async ({ store }) => {
|
||||||
const { state, commit } = store
|
const oauth = useOAuthStore()
|
||||||
const { oauth, instance } = state
|
|
||||||
if (oauth.userToken) {
|
if (oauth.userToken) {
|
||||||
commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
|
store.commit('setBackendInteractor', backendInteractorService(oauth.getToken))
|
||||||
} else {
|
|
||||||
return getOrCreateApp({ ...oauth, instance: instance.server, commit })
|
|
||||||
.then((app) => getClientToken({ ...app, instance: instance.server }))
|
|
||||||
.then((token) => {
|
|
||||||
commit('setAppToken', token.access_token)
|
|
||||||
commit('setBackendInteractor', backendInteractorService(store.getters.getToken()))
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,7 +245,8 @@ const resolveStaffAccounts = ({ store, accounts }) => {
|
||||||
|
|
||||||
const getNodeInfo = async ({ store }) => {
|
const getNodeInfo = async ({ store }) => {
|
||||||
try {
|
try {
|
||||||
const res = await preloadFetch('/nodeinfo/2.1.json')
|
let res = await preloadFetch('/nodeinfo/2.1.json')
|
||||||
|
if (!res.ok) res = await preloadFetch('/nodeinfo/2.0.json')
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json()
|
const data = await res.json()
|
||||||
const metadata = data.metadata
|
const metadata = data.metadata
|
||||||
|
|
@ -269,6 +266,7 @@ const getNodeInfo = async ({ store }) => {
|
||||||
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
|
store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled })
|
||||||
store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') })
|
store.dispatch('setInstanceOption', { name: 'quotingAvailable', value: features.includes('quote_posting') })
|
||||||
store.dispatch('setInstanceOption', { name: 'groupActorAvailable', value: features.includes('pleroma:group_actors') })
|
store.dispatch('setInstanceOption', { name: 'groupActorAvailable', value: features.includes('pleroma:group_actors') })
|
||||||
|
store.dispatch('setInstanceOption', { name: 'localBubbleInstances', value: metadata.localBubbleInstances ?? [] })
|
||||||
|
|
||||||
const uploadLimits = metadata.uploadLimits
|
const uploadLimits = metadata.uploadLimits
|
||||||
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
|
store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) })
|
||||||
|
|
@ -287,7 +285,6 @@ const getNodeInfo = async ({ store }) => {
|
||||||
const software = data.software
|
const software = data.software
|
||||||
store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version })
|
store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version })
|
||||||
store.dispatch('setInstanceOption', { name: 'backendRepository', value: software.repository })
|
store.dispatch('setInstanceOption', { name: 'backendRepository', value: software.repository })
|
||||||
store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' })
|
|
||||||
|
|
||||||
const priv = metadata.private
|
const priv = metadata.private
|
||||||
store.dispatch('setInstanceOption', { name: 'private', value: priv })
|
store.dispatch('setInstanceOption', { name: 'private', value: priv })
|
||||||
|
|
@ -332,20 +329,65 @@ const setConfig = async ({ store }) => {
|
||||||
const apiConfig = configInfos[0]
|
const apiConfig = configInfos[0]
|
||||||
const staticConfig = configInfos[1]
|
const staticConfig = configInfos[1]
|
||||||
|
|
||||||
await setSettings({ store, apiConfig, staticConfig }).then(getAppSecret({ store }))
|
getAppSecret({ store })
|
||||||
|
await setSettings({ store, apiConfig, staticConfig })
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkOAuthToken = async ({ store }) => {
|
const checkOAuthToken = async ({ store }) => {
|
||||||
if (store.getters.getUserToken()) {
|
const oauth = useOAuthStore()
|
||||||
return store.dispatch('loginUser', store.getters.getUserToken())
|
if (oauth.getUserToken) {
|
||||||
|
return store.dispatch('loginUser', oauth.getUserToken)
|
||||||
}
|
}
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
const afterStoreSetup = async ({ pinia, store, storageError, i18n }) => {
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
// Must have app use pinia before we do anything that touches the store
|
||||||
|
// https://pinia.vuejs.org/core-concepts/plugins.html#Introduction
|
||||||
|
// "Plugins are only applied to stores created after the plugins themselves, and after pinia is passed to the app, otherwise they won't be applied."
|
||||||
app.use(pinia)
|
app.use(pinia)
|
||||||
|
|
||||||
|
const waitForAllStoresToLoad = async () => {
|
||||||
|
// the stores that do not persist technically do not need to be awaited here,
|
||||||
|
// but that involves either hard-coding the stores in some place (prone to errors)
|
||||||
|
// or writing another vite plugin to analyze which stores needs persisting (++load time)
|
||||||
|
const allStores = import.meta.glob('../stores/*.js', { eager: true })
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
// do some checks to avoid common errors
|
||||||
|
if (!Object.keys(allStores).length) {
|
||||||
|
throw new Error('No stores are available. Check the code in src/boot/after_store.js')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(allStores)
|
||||||
|
.map(async ([name, mod]) => {
|
||||||
|
const isStoreName = name => name.startsWith('use')
|
||||||
|
if (process.env.NODE_ENV === 'development') {
|
||||||
|
if (Object.keys(mod).filter(isStoreName).length !== 1) {
|
||||||
|
throw new Error('Each store file must export exactly one store as a named export. Check your code in src/stores/')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const storeFuncName = Object.keys(mod).find(isStoreName)
|
||||||
|
if (storeFuncName && typeof mod[storeFuncName] === 'function') {
|
||||||
|
const p = mod[storeFuncName]().$persistLoaded
|
||||||
|
if (!(p instanceof Promise)) {
|
||||||
|
throw new Error(`${name} store's $persistLoaded is not a Promise. The persist plugin is not applied.`)
|
||||||
|
}
|
||||||
|
await p
|
||||||
|
} else {
|
||||||
|
throw new Error(`Store module ${name} does not export a 'use...' function`)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await waitForAllStoresToLoad()
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Cannot load stores:', e)
|
||||||
|
storageError = e
|
||||||
|
}
|
||||||
|
|
||||||
if (storageError) {
|
if (storageError) {
|
||||||
useInterfaceStore().pushGlobalNotice({ messageKey: 'errors.storage_unavailable', level: 'error' })
|
useInterfaceStore().pushGlobalNotice({ messageKey: 'errors.storage_unavailable', level: 'error' })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import PublicTimeline from 'components/public_timeline/public_timeline.vue'
|
import PublicTimeline from 'components/public_timeline/public_timeline.vue'
|
||||||
|
import BubbleTimeline from 'components/bubble_timeline/bubble_timeline.vue'
|
||||||
import PublicAndExternalTimeline from 'components/public_and_external_timeline/public_and_external_timeline.vue'
|
import PublicAndExternalTimeline from 'components/public_and_external_timeline/public_and_external_timeline.vue'
|
||||||
import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue'
|
import FriendsTimeline from 'components/friends_timeline/friends_timeline.vue'
|
||||||
import TagTimeline from 'components/tag_timeline/tag_timeline.vue'
|
import TagTimeline from 'components/tag_timeline/tag_timeline.vue'
|
||||||
|
|
@ -54,6 +55,7 @@ export default (store) => {
|
||||||
{ name: 'friends', path: '/main/friends', component: FriendsTimeline, beforeEnter: validateAuthenticatedRoute },
|
{ name: 'friends', path: '/main/friends', component: FriendsTimeline, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
||||||
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
|
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
|
||||||
|
{ name: 'bubble', path: '/bubble', component: BubbleTimeline },
|
||||||
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
||||||
{ name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },
|
{ name: 'quotes', path: '/notice/:id/quotes', component: QuotesTimeline },
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@
|
||||||
.post-textarea {
|
.post-textarea {
|
||||||
resize: vertical;
|
resize: vertical;
|
||||||
height: 10em;
|
height: 10em;
|
||||||
overflow: none;
|
overflow: visible;
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,8 @@
|
||||||
.text {
|
.text {
|
||||||
flex: 2;
|
flex: 2;
|
||||||
margin: 8px;
|
margin: 8px;
|
||||||
word-break: break-all;
|
overflow-wrap: break-word;
|
||||||
|
text-wrap: pretty;
|
||||||
|
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ export default {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
component: 'Button',
|
component: 'Button',
|
||||||
parent: { component: 'Attachment' },
|
parent: {
|
||||||
|
component: 'Attachment'
|
||||||
|
},
|
||||||
directives: {
|
directives: {
|
||||||
background: '#FFFFFF',
|
background: '#FFFFFF',
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
|
|
|
||||||
18
src/components/bubble_timeline/bubble_timeline.js
Normal file
18
src/components/bubble_timeline/bubble_timeline.js
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import Timeline from '../timeline/timeline.vue'
|
||||||
|
const BubbleTimeline = {
|
||||||
|
components: {
|
||||||
|
Timeline
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
timeline () { return this.$store.state.statuses.timelines.bubble }
|
||||||
|
},
|
||||||
|
created () {
|
||||||
|
this.$store.dispatch('startFetchingTimeline', { timeline: 'bubble' })
|
||||||
|
},
|
||||||
|
unmounted () {
|
||||||
|
this.$store.dispatch('stopFetchingTimeline', 'bubble')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BubbleTimeline
|
||||||
9
src/components/bubble_timeline/bubble_timeline.vue
Normal file
9
src/components/bubble_timeline/bubble_timeline.vue
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<template>
|
||||||
|
<Timeline
|
||||||
|
:title="$t('nav.bubble')"
|
||||||
|
:timeline="timeline"
|
||||||
|
:timeline-name="'bubble'"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./bubble_timeline.js"></script>
|
||||||
|
|
@ -9,9 +9,9 @@ export default {
|
||||||
// However, cascading still works, so resulting state will be result of merging of all relevant states/variants
|
// However, cascading still works, so resulting state will be result of merging of all relevant states/variants
|
||||||
// normal: '' // normal state is implicitly added, it is always included
|
// normal: '' // normal state is implicitly added, it is always included
|
||||||
toggled: '.toggled',
|
toggled: '.toggled',
|
||||||
focused: ':focus-visible',
|
focused: ':focus-within',
|
||||||
pressed: ':focus:active',
|
pressed: ':focus:active',
|
||||||
hover: ':hover:not(:disabled)',
|
hover: ':is(:hover, :focus-visible):not(:disabled)',
|
||||||
disabled: ':disabled'
|
disabled: ':disabled'
|
||||||
},
|
},
|
||||||
// Variants are mutually exclusive, each component implicitly has "normal" variant, and all other variants inherit from it.
|
// Variants are mutually exclusive, each component implicitly has "normal" variant, and all other variants inherit from it.
|
||||||
|
|
@ -89,6 +89,13 @@ export default {
|
||||||
shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel']
|
shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
state: ['toggled', 'focused'],
|
||||||
|
directives: {
|
||||||
|
background: '--accent,-24.2',
|
||||||
|
shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
state: ['toggled', 'disabled'],
|
state: ['toggled', 'disabled'],
|
||||||
directives: {
|
directives: {
|
||||||
|
|
@ -99,7 +106,7 @@ export default {
|
||||||
{
|
{
|
||||||
state: ['disabled'],
|
state: ['disabled'],
|
||||||
directives: {
|
directives: {
|
||||||
background: '$blend(--accent 0.25 --parent)',
|
background: '$blend(--inheritedBackground 0.25 --parent)',
|
||||||
shadow: ['--buttonDefaultBevel']
|
shadow: ['--buttonDefaultBevel']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ export default {
|
||||||
states: {
|
states: {
|
||||||
toggled: '.toggled',
|
toggled: '.toggled',
|
||||||
disabled: ':disabled',
|
disabled: ':disabled',
|
||||||
hover: ':hover:not(:disabled)',
|
hover: ':is(:hover, :focus-visible):not(:disabled)',
|
||||||
focused: ':focus-within'
|
focused: ':focus-within:not(:is(:focus-visible))'
|
||||||
},
|
},
|
||||||
validInnerComponents: [
|
validInnerComponents: [
|
||||||
'Text',
|
'Text',
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
.heading {
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,7 @@
|
||||||
.outgoing {
|
.outgoing {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
align-content: end;
|
place-content: end flex-end;
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
.chat-message-inner {
|
.chat-message-inner {
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,6 @@
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
display: inline;
|
display: inline;
|
||||||
word-wrap: break-word;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<label
|
<label
|
||||||
class="checkbox"
|
class="checkbox"
|
||||||
:class="{ disabled, indeterminate, 'indeterminate-fix': indeterminateTransitionFix }"
|
:class="[{ disabled, indeterminate, 'indeterminate-fix': indeterminateTransitionFix }, radio ? '-radio' : '-checkbox']"
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
v-if="!!$slots.before"
|
v-if="!!$slots.before"
|
||||||
|
|
@ -19,9 +19,9 @@
|
||||||
@change="$emit('update:modelValue', $event.target.checked)"
|
@change="$emit('update:modelValue', $event.target.checked)"
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
class="input -checkbox checkbox-indicator"
|
class="input checkbox-indicator"
|
||||||
:aria-hidden="true"
|
:aria-hidden="true"
|
||||||
:class="{ disabled }"
|
:class="[{ disabled }, radio ? '-radio' : '-checkbox']"
|
||||||
@transitionend.capture="onTransitionEnd"
|
@transitionend.capture="onTransitionEnd"
|
||||||
/>
|
/>
|
||||||
<span
|
<span
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: [
|
props: [
|
||||||
|
'radio',
|
||||||
'modelValue',
|
'modelValue',
|
||||||
'indeterminate',
|
'indeterminate',
|
||||||
'disabled'
|
'disabled'
|
||||||
|
|
@ -107,6 +108,19 @@ export default {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.-radio {
|
||||||
|
.checkbox-indicator {
|
||||||
|
&,
|
||||||
|
&::before {
|
||||||
|
border-radius: 9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "•";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.disabled {
|
.disabled {
|
||||||
.checkbox-indicator::before {
|
.checkbox-indicator::before {
|
||||||
background-color: var(--background);
|
background-color: var(--background);
|
||||||
|
|
|
||||||
|
|
@ -190,21 +190,16 @@ export default {
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
grid-area: header;
|
grid-area: header;
|
||||||
justify-self: center;
|
place-self: baseline center;
|
||||||
align-self: baseline;
|
|
||||||
line-height: 2;
|
line-height: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
.invalid-container {
|
.invalid-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
inset: 0;
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
align-items: center;
|
place-items: center center;
|
||||||
justify-items: center;
|
background-color: rgb(100 0 0 / 50%);
|
||||||
background-color: rgba(100 0 0 / 50%);
|
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
padding: 0.5em 1em;
|
padding: 0.5em 1em;
|
||||||
|
|
@ -214,7 +209,7 @@ export default {
|
||||||
.assists {
|
.assists {
|
||||||
grid-area: assists;
|
grid-area: assists;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-auto-flow: rows;
|
grid-auto-flow: row;
|
||||||
grid-auto-rows: 2em;
|
grid-auto-rows: 2em;
|
||||||
grid-gap: 0.5em;
|
grid-gap: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
@ -266,14 +261,14 @@ export default {
|
||||||
.preview-window {
|
.preview-window {
|
||||||
--__grid-color1: rgb(102 102 102);
|
--__grid-color1: rgb(102 102 102);
|
||||||
--__grid-color2: rgb(153 153 153);
|
--__grid-color2: rgb(153 153 153);
|
||||||
--__grid-color1-disabled: rgba(102 102 102 / 20%);
|
--__grid-color1-disabled: rgb(102 102 102 / 20%);
|
||||||
--__grid-color2-disabled: rgba(153 153 153 / 20%);
|
--__grid-color2-disabled: rgb(153 153 153 / 20%);
|
||||||
|
|
||||||
&.-light-grid {
|
&.-light-grid {
|
||||||
--__grid-color1: rgb(205 205 205);
|
--__grid-color1: rgb(205 205 205);
|
||||||
--__grid-color2: rgb(255 255 255);
|
--__grid-color2: rgb(255 255 255);
|
||||||
--__grid-color1-disabled: rgba(205 205 205 / 20%);
|
--__grid-color1-disabled: rgb(205 205 205 / 20%);
|
||||||
--__grid-color2-disabled: rgba(255 255 255 / 20%);
|
--__grid-color2-disabled: rgb(255 255 255 / 20%);
|
||||||
}
|
}
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
||||||
|
|
@ -339,11 +339,6 @@ const conversation = {
|
||||||
canDive () {
|
canDive () {
|
||||||
return this.isTreeView && this.isExpanded
|
return this.isTreeView && this.isExpanded
|
||||||
},
|
},
|
||||||
focused () {
|
|
||||||
return (id) => {
|
|
||||||
return (this.isExpanded) && id === this.highlight
|
|
||||||
}
|
|
||||||
},
|
|
||||||
maybeHighlight () {
|
maybeHighlight () {
|
||||||
return this.isExpanded ? this.highlight : null
|
return this.isExpanded ? this.highlight : null
|
||||||
},
|
},
|
||||||
|
|
@ -406,6 +401,9 @@ const conversation = {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
isFocused (id) {
|
||||||
|
return (this.isExpanded) && id === this.highlight
|
||||||
|
},
|
||||||
getReplies (id) {
|
getReplies (id) {
|
||||||
return this.replies[id] || []
|
return this.replies[id] || []
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@
|
||||||
:statusoid="status"
|
:statusoid="status"
|
||||||
:expandable="!isExpanded"
|
:expandable="!isExpanded"
|
||||||
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
|
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
|
||||||
:focused="focused(status.id)"
|
:focused="isFocused(status.id)"
|
||||||
:in-conversation="isExpanded"
|
:in-conversation="isExpanded"
|
||||||
:highlight="getHighlight()"
|
:highlight="getHighlight()"
|
||||||
:replies="getReplies(status.id)"
|
:replies="getReplies(status.id)"
|
||||||
|
|
@ -168,7 +168,7 @@
|
||||||
:pinned-status-ids-object="pinnedStatusIdsObject"
|
:pinned-status-ids-object="pinnedStatusIdsObject"
|
||||||
:profile-user-id="profileUserId"
|
:profile-user-id="profileUserId"
|
||||||
|
|
||||||
:focused="focused"
|
:is-focused-function="isFocused"
|
||||||
:get-replies="getReplies"
|
:get-replies="getReplies"
|
||||||
:highlight="maybeHighlight"
|
:highlight="maybeHighlight"
|
||||||
:set-highlight="setHighlight"
|
:set-highlight="setHighlight"
|
||||||
|
|
@ -199,7 +199,7 @@
|
||||||
:statusoid="status"
|
:statusoid="status"
|
||||||
:expandable="!isExpanded"
|
:expandable="!isExpanded"
|
||||||
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
|
:show-pinned="pinnedStatusIdsObject && pinnedStatusIdsObject[status.id]"
|
||||||
:focused="focused(status.id)"
|
:focused="isFocused(status.id)"
|
||||||
:in-conversation="isExpanded"
|
:in-conversation="isExpanded"
|
||||||
:highlight="getHighlight()"
|
:highlight="getHighlight()"
|
||||||
:replies="getReplies(status.id)"
|
:replies="getReplies(status.id)"
|
||||||
|
|
@ -322,10 +322,7 @@
|
||||||
content: "";
|
content: "";
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: calc(var(--___margin) * -1);
|
inset: calc(var(--___margin) * -1);
|
||||||
bottom: calc(var(--___margin) * -1);
|
|
||||||
left: calc(var(--___margin) * -1);
|
|
||||||
right: calc(var(--___margin) * -1);
|
|
||||||
background: var(--background);
|
background: var(--background);
|
||||||
backdrop-filter: var(--__panel-backdrop-filter);
|
backdrop-filter: var(--__panel-backdrop-filter);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
transition-timing-function: ease-out;
|
transition-timing-function: ease-out;
|
||||||
transition-duration: 100ms;
|
transition-duration: 100ms;
|
||||||
|
|
||||||
@media all and (min-width: 800px) {
|
@media all and (width >= 800px) {
|
||||||
/* stylelint-disable-next-line declaration-no-important */
|
/* stylelint-disable-next-line declaration-no-important */
|
||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
}
|
}
|
||||||
|
|
@ -70,10 +70,7 @@
|
||||||
mask-size: contain;
|
mask-size: contain;
|
||||||
background-color: var(--text);
|
background-color: var(--text);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
inset: 0;
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,11 @@
|
||||||
// TODO: unify with other modals.
|
// TODO: unify with other modals.
|
||||||
.dark-overlay {
|
.dark-overlay {
|
||||||
&::before {
|
&::before {
|
||||||
bottom: 0;
|
inset: 0;
|
||||||
content: " ";
|
content: " ";
|
||||||
display: block;
|
display: block;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
left: 0;
|
|
||||||
position: fixed;
|
position: fixed;
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
background: rgb(27 31 35 / 50%);
|
background: rgb(27 31 35 / 50%);
|
||||||
z-index: 2000;
|
z-index: 2000;
|
||||||
}
|
}
|
||||||
|
|
@ -45,13 +42,9 @@
|
||||||
.dialog-container {
|
.dialog-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 0;
|
inset: 0;
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
place-items: center center;
|
||||||
justify-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dialog-modal.panel {
|
.dialog-modal.panel {
|
||||||
|
|
@ -98,8 +91,7 @@
|
||||||
#modal.-mobile {
|
#modal.-mobile {
|
||||||
.dialog-container {
|
.dialog-container {
|
||||||
justify-content: stretch;
|
justify-content: stretch;
|
||||||
align-items: end;
|
place-items: end stretch;
|
||||||
justify-items: stretch;
|
|
||||||
|
|
||||||
&.-center-mobile {
|
&.-center-mobile {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
@ -114,7 +106,6 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-auto-columns: none;
|
|
||||||
grid-auto-rows: auto;
|
grid-auto-rows: auto;
|
||||||
grid-auto-flow: row dense;
|
grid-auto-flow: row dense;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,6 @@
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
word-wrap: break-word;
|
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
}
|
}
|
||||||
|
|
@ -135,8 +134,7 @@
|
||||||
.poll-indicator-container {
|
.poll-indicator-container {
|
||||||
border-radius: var(--roundness);
|
border-radius: var(--roundness);
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-items: center;
|
place-items: center center;
|
||||||
align-items: center;
|
|
||||||
align-self: start;
|
align-self: start;
|
||||||
height: 0;
|
height: 0;
|
||||||
padding-bottom: 62.5%;
|
padding-bottom: 62.5%;
|
||||||
|
|
@ -147,13 +145,9 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border: 1px solid var(--border);
|
border: 1px solid var(--border);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
inset: 0;
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-items: center;
|
place-items: center center;
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
ref="suggestorPopover"
|
ref="suggestorPopover"
|
||||||
class="autocomplete-panel"
|
class="autocomplete-panel"
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
:trigger-attrs="{ 'aria-hidden': true }"
|
:hide-trigger="true"
|
||||||
>
|
>
|
||||||
<template #content>
|
<template #content>
|
||||||
<div
|
<div
|
||||||
|
|
@ -159,10 +159,7 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
inset: 0;
|
||||||
bottom: 0;
|
|
||||||
right: 0;
|
|
||||||
left: 0;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
/* DEBUG STUFF */
|
/* DEBUG STUFF */
|
||||||
|
|
|
||||||
|
|
@ -64,8 +64,7 @@
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
overflow-x: auto;
|
overflow: auto hidden;
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.additional-tabs {
|
.additional-tabs {
|
||||||
|
|
@ -153,7 +152,13 @@
|
||||||
transition: mask-size 150ms;
|
transition: mask-size 150ms;
|
||||||
mask-size: 100% 20px, 100% 20px, auto;
|
mask-size: 100% 20px, 100% 20px, auto;
|
||||||
// Autoprefixed seem to ignore this one, and also syntax is different
|
// Autoprefixed seem to ignore this one, and also syntax is different
|
||||||
|
/* stylelint-disable mask-composite */
|
||||||
|
/* stylelint-disable declaration-property-value-no-unknown */
|
||||||
|
|
||||||
|
/* TODO check if this is still needed */
|
||||||
mask-composite: xor;
|
mask-composite: xor;
|
||||||
|
/* stylelint-enable declaration-property-value-no-unknown */
|
||||||
|
/* stylelint-enable mask-composite */
|
||||||
mask-composite: exclude;
|
mask-composite: exclude;
|
||||||
|
|
||||||
&.scrolled {
|
&.scrolled {
|
||||||
|
|
@ -197,8 +202,7 @@
|
||||||
&-group {
|
&-group {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(var(--__amount), 1fr);
|
grid-template-columns: repeat(var(--__amount), 1fr);
|
||||||
align-items: center;
|
place-items: center center;
|
||||||
justify-items: center;
|
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
grid-template-rows: repeat(1, auto);
|
grid-template-rows: repeat(1, auto);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
ref="popover"
|
ref="popover"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
popover-class="emoji-picker popover-default"
|
popover-class="emoji-picker popover-default"
|
||||||
:trigger-attrs="{ 'aria-hidden': true, tabindex: -1 }"
|
:hide-trigger="true"
|
||||||
@show="onPopoverShown"
|
@show="onPopoverShown"
|
||||||
@close="onPopoverClosed"
|
@close="onPopoverClosed"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,6 @@ const EmojiReactions = {
|
||||||
counterTriggerAttrs (reaction) {
|
counterTriggerAttrs (reaction) {
|
||||||
return {
|
return {
|
||||||
class: [
|
class: [
|
||||||
'btn',
|
|
||||||
'button-default',
|
|
||||||
'emoji-reaction-count-button',
|
'emoji-reaction-count-button',
|
||||||
{
|
{
|
||||||
'-picked-reaction': this.reactedWith(reaction.name),
|
'-picked-reaction': this.reactedWith(reaction.name),
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@
|
||||||
<UserListPopover
|
<UserListPopover
|
||||||
:users="accountsForEmoji[reaction.name]"
|
:users="accountsForEmoji[reaction.name]"
|
||||||
class="emoji-reaction-popover"
|
class="emoji-reaction-popover"
|
||||||
|
:normal-button="true"
|
||||||
:trigger-attrs="counterTriggerAttrs(reaction)"
|
:trigger-attrs="counterTriggerAttrs(reaction)"
|
||||||
@show="fetchEmojiReactionsByIfMissing()"
|
@show="fetchEmojiReactionsByIfMissing()"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue