Compare commits

..

1 Commits

Author SHA1 Message Date
lamp 4d91a7b2c3 Fix public favorites
Show favorites tab to anyone when "Don't show list of my favorites" is unchecked.

Adapted from upstream changes by marcin mikołajczak <git@mkljczk.pl>:
https://git.pleroma.social/pleroma/pleroma-fe/-/commit/6f452d672fe740035cf1d29d03bcda0d39438753?merge_request_iid=1883
https://git.pleroma.social/pleroma/pleroma-fe/-/commit/1ceffb4e713b4b20d70121fba92d2b50f2d3cadf?merge_request_iid=1908
2024-05-06 17:55:10 -07:00
167 changed files with 6463 additions and 9738 deletions
+2
View File
@@ -0,0 +1,2 @@
build/*.js
config/*.js
+30
View File
@@ -0,0 +1,30 @@
module.exports = {
root: true,
parserOptions: {
parser: '@babel/eslint-parser',
sourceType: 'module'
},
// https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
extends: [
'plugin:vue/recommended'
],
// required to lint *.vue files
plugins: [
'vue',
'import'
],
// add your custom rules here
rules: {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'vue/require-prop-types': 0,
'vue/no-unused-vars': 0,
'no-tabs': 0,
'vue/multi-word-component-names': 0,
'vue/no-reserved-component-names': 0
}
}
+1
View File
@@ -0,0 +1 @@
7.2.1
-1
View File
@@ -1 +0,0 @@
nodejs 20.12.2
+19 -25
View File
@@ -1,21 +1,20 @@
labels:
platform: linux/amd64
steps:
platform: linux/amd64
pipeline:
lint:
when:
event:
- pull_request
image: node:20
image: node:18
commands:
- yarn
- yarn lint
#- yarn stylelint
test:
when:
event:
- pull_request
image: node:20
image: node:18
commands:
- apt update
- apt install firefox-esr -y --no-install-recommends
@@ -29,7 +28,7 @@ steps:
branch:
- develop
- stable
image: node:20
image: node:18
commands:
- yarn
- yarn build
@@ -41,18 +40,15 @@ steps:
branch:
- develop
- stable
image: node:20
environment:
SCW_ACCESS_KEY:
from_secret: SCW_ACCESS_KEY
SCW_SECRET_KEY:
from_secret: SCW_SECRET_KEY
SCW_DEFAULT_ORGANIZATION_ID:
from_secret: SCW_DEFAULT_ORGANIZATION_ID
image: node:18
secrets:
- SCW_ACCESS_KEY
- SCW_SECRET_KEY
- SCW_DEFAULT_ORGANIZATION_ID
commands:
- apt-get update && apt-get install -y rclone wget zip
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.30.0/scaleway-cli_2.30.0_linux_amd64
- mv scaleway-cli_2.30.0_linux_amd64 scaleway-cli
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64
- mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli
- chmod +x scaleway-cli
- ./scaleway-cli object config install type=rclone
- zip akkoma-fe.zip -r dist
@@ -67,17 +63,15 @@ steps:
- stable
environment:
CI: "true"
SCW_ACCESS_KEY:
from_secret: SCW_ACCESS_KEY
SCW_SECRET_KEY:
from_secret: SCW_SECRET_KEY
SCW_DEFAULT_ORGANIZATION_ID:
from_secret: SCW_DEFAULT_ORGANIZATION_ID
image: python:3.10-slim
secrets:
- SCW_ACCESS_KEY
- SCW_SECRET_KEY
- SCW_DEFAULT_ORGANIZATION_ID
commands:
- apt-get update && apt-get install -y rclone wget git zip
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.30.0/scaleway-cli_2.30.0_linux_amd64
- mv scaleway-cli_2.30.0_linux_amd64 scaleway-cli
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64
- mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli
- chmod +x scaleway-cli
- ./scaleway-cli object config install type=rclone
- cd docs
-2
View File
@@ -20,8 +20,6 @@ To use Akkoma-FE in Akkoma, use the [frontend](https://docs.akkoma.dev/stable/ad
## Build Setup
Make sure you have [Node.js](https://nodejs.org/) installed. You can check `/.woodpecker.yml` for which node version the Akkoma CI currently uses.
``` bash
# install dependencies
corepack enable
+29 -29
View File
@@ -1,36 +1,36 @@
// https://github.com/shelljs/shelljs
require("./check-versions")();
require("shelljs/global");
env.NODE_ENV = "production";
require('./check-versions')()
require('shelljs/global')
env.NODE_ENV = 'production'
var path = require("path");
var config = require("../config");
var webpack = require("webpack");
var webpackConfig = require("./webpack.prod.conf");
var path = require('path')
var config = require('../config')
var ora = require('ora')
var webpack = require('webpack')
var webpackConfig = require('./webpack.prod.conf')
console.log(
" Tip:\n" +
" Built files are meant to be served over an HTTP server.\n" +
" Opening index.html over file:// won't work.\n",
);
' Tip:\n' +
' Built files are meant to be served over an HTTP server.\n' +
' Opening index.html over file:// won\'t work.\n'
)
var assetsPath = path.join(
config.build.assetsRoot,
config.build.assetsSubDirectory,
);
rm("-rf", assetsPath);
mkdir("-p", assetsPath);
cp("-R", "static/*", assetsPath);
var spinner = ora('building for production...')
spinner.start()
var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
rm('-rf', assetsPath)
mkdir('-p', assetsPath)
cp('-R', 'static/*', assetsPath)
webpack(webpackConfig, function (err, stats) {
if (err) throw err;
process.stdout.write(
stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
}) + "\n",
);
});
spinner.stop()
if (err) throw err
process.stdout.write(stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false
}) + '\n')
})
+2 -8
View File
@@ -5,7 +5,7 @@ var path = require('path')
var express = require('express')
var webpack = require('webpack')
var opn = require('opn')
const { createProxyMiddleware } = require('http-proxy-middleware');
var proxyMiddleware = require('http-proxy-middleware')
var webpackConfig = process.env.NODE_ENV === 'testing'
? require('./webpack.prod.conf')
: require('./webpack.dev.conf')
@@ -36,13 +36,7 @@ Object.keys(proxyTable).forEach(function (context) {
if (typeof options === 'string') {
options = { target: options }
}
const targetUrl = new URL(options.target);
// add path
targetUrl.pathname = context;
options.target = targetUrl.toString();
console.log("Proxying", context, "to", options.target);
app.use(context, createProxyMiddleware(options))
app.use(proxyMiddleware(context, options))
})
// handle fallback for HTML5 history API
+15 -6
View File
@@ -3,7 +3,6 @@ var config = require('../config')
var utils = require('./utils')
var projectRoot = path.resolve(__dirname, '../')
var { VueLoaderPlugin } = require('vue-loader')
const ESLintPlugin = require('eslint-webpack-plugin');
var env = process.env.NODE_ENV
// check env & config/index.js to decide weither to enable CSS Sourcemaps for the
@@ -36,7 +35,6 @@ module.exports = {
],
fallback: {
"url": require.resolve("url/"),
querystring: require.resolve("querystring-es3")
},
alias: {
'static': path.resolve(__dirname, '../static'),
@@ -49,6 +47,20 @@ module.exports = {
module: {
noParse: /node_modules\/localforage\/dist\/localforage.js/,
rules: [
{
enforce: 'pre',
test: /\.(js|vue)$/,
include: projectRoot,
exclude: /node_modules/,
use: {
loader: 'eslint-loader',
options: {
formatter: require('eslint-friendly-formatter'),
sourceMap: config.build.productionSourceMap,
extract: true
}
}
},
{
enforce: 'post',
test: /\.(json5?|ya?ml)$/, // target json, json5, yaml and yml files
@@ -106,9 +118,6 @@ module.exports = {
]
},
plugins: [
new VueLoaderPlugin(),
new ESLintPlugin({
configType: 'flat'
})
new VueLoaderPlugin()
]
}
+1
View File
@@ -2,4 +2,5 @@ var { merge } = require('webpack-merge')
var devEnv = require('./dev.env')
module.exports = merge(devEnv, {
NODE_ENV: '"testing"'
})
-3
View File
@@ -70,9 +70,6 @@ Default post formatting option (markdown/bbcode/plaintext/etc...)
### `redirectRootNoLogin`, `redirectRootLogin`
These two settings should point to where FE should redirect visitor when they login/open up website root
### `scopeCopy`
Copy post scope (visibility) when replying to a post. Instance-default.
### `sidebarRight`
Change alignment of sidebar and panels to the right. Defaults to `false`.
+2 -3
View File
@@ -15,13 +15,12 @@ put a file that looks like this
```json
{
"myPack": "/static/stickers/myPack/"
"myPack": "/static/stickers/myPack"
}
```
This file is a mapping from name to pack directory location. It says "we have a pack called myPack, look for
it inside `/static/stickers/myPack`". You can add as many packs as you like in this manner.
Note that a single leading and a trailing slash are **required** to work correctly!
it at `/static/stickers/myPack`". You can add as many packs as you like in this manner.
## Creating the pack
-31
View File
@@ -1,31 +0,0 @@
const pluginVue = require('eslint-plugin-vue')
const pluginImport = require('eslint-plugin-import')
module.exports = [
...pluginVue.configs['flat/recommended'],
{
languageOptions: {
parserOptions: {
parser: '@babel/eslint-parser',
sourceType: 'module'
}
},
rules: {
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
'generator-star-spacing': 0,
// allow debugger during development
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
'vue/require-prop-types': 0,
'vue/no-unused-vars': 0,
'no-tabs': 0,
'vue/multi-word-component-names': 0,
'vue/no-reserved-component-names': 0
},
ignores: [
'build/*.js',
'config/*.js'
]
}
]
+1
View File
@@ -6,6 +6,7 @@
<title>Akkoma</title>
<link rel="stylesheet" href="/static/font/tiresias.css">
<link rel="stylesheet" href="/static/font/css/lato.css">
<link rel="stylesheet" href="/static/mfm.css">
<link rel="stylesheet" href="/static/custom.css">
<link rel="stylesheet" href="/static/theme-holder.css" id="theme-holder">
<!--server-generated-meta-->
+83 -81
View File
@@ -1,6 +1,6 @@
{
"name": "pleroma_fe",
"version": "3.12.0",
"version": "3.10.0",
"description": "A frontend for Akkoma instances",
"author": "Roger Braun <roger@rogerbraun.net>",
"private": true,
@@ -12,118 +12,120 @@
"e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e",
"stylelint": "stylelint src/**/*.scss",
"lint": "eslint src test/unit/specs test/e2e/specs",
"lint-fix": "eslint --fix src test/unit/specs test/e2e/specs"
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
},
"dependencies": {
"@babel/runtime": "7.17.8",
"@chenfengyuan/vue-qrcode": "^2.0.0",
"@chenfengyuan/vue-qrcode": "2.0.0",
"@floatingghost/pinch-zoom-element": "^1.3.1",
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-regular-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "^3.0.8",
"@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.4",
"blurhash": "^2.0.5",
"body-scroll-lock": "^3.1.5",
"chromatism": "^3.0.0",
"click-outside-vue3": "^4.0.1",
"cropperjs": "^1.6.2",
"diff": "^5.2.0",
"escape-html": "^1.0.3",
"@fortawesome/fontawesome-svg-core": "1.3.0",
"@fortawesome/free-regular-svg-icons": "^6.1.2",
"@fortawesome/free-solid-svg-icons": "^6.2.0",
"@fortawesome/vue-fontawesome": "3.0.1",
"@vuelidate/core": "^2.0.0",
"@vuelidate/validators": "^2.0.0",
"blurhash": "^2.0.4",
"body-scroll-lock": "2.7.1",
"chromatism": "3.0.0",
"click-outside-vue3": "4.0.1",
"cropperjs": "1.5.12",
"diff": "3.5.0",
"escape-html": "1.0.3",
"iso-639-1": "^2.1.15",
"js-cookie": "^3.0.1",
"localforage": "^1.10.0",
"localforage": "1.10.0",
"parse-link-header": "^2.0.0",
"phoenix": "^1.7.12",
"punycode.js": "^2.3.1",
"qrcode": "^1.5.3",
"querystring-es3": "^0.2.1",
"url": "^0.11.3",
"vue": "^3.4.38",
"vue-i18n": "^9.14.0",
"vue-router": "^4.4.3",
"vue-template-compiler": "^2.7.16",
"vuex": "^4.1.0"
"phoenix": "1.6.2",
"punycode.js": "2.1.0",
"qrcode": "1",
"url": "^0.11.0",
"vue": "^3.2.31",
"vue-i18n": "^9.2.2",
"vue-router": "4.0.14",
"vue-template-compiler": "2.6.11",
"vuex": "4.0.2"
},
"devDependencies": {
"@babel/core": "^7.24.6",
"@babel/core": "7.17.8",
"@babel/eslint-parser": "^7.19.1",
"@babel/plugin-transform-runtime": "^7.24.6",
"@babel/preset-env": "^7.24.6",
"@babel/register": "^7.24.6",
"@babel/plugin-transform-runtime": "7.17.0",
"@babel/preset-env": "7.16.11",
"@babel/register": "7.17.7",
"@intlify/vue-i18n-loader": "^5.0.0",
"@ungap/event-target": "^0.2.4",
"@vue/babel-helper-vue-jsx-merge-props": "^1.4.0",
"@vue/babel-plugin-jsx": "^1.2.2",
"@ungap/event-target": "0.2.3",
"@vue/babel-helper-vue-jsx-merge-props": "1.2.1",
"@vue/babel-plugin-jsx": "1.1.1",
"@vue/compiler-sfc": "^3.1.0",
"@vue/test-utils": "^2.0.2",
"autoprefixer": "^10.4.19",
"autoprefixer": "6.7.7",
"babel-loader": "^9.1.0",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-lodash": "3.3.4",
"chai": "^4.3.7",
"chalk": "^1.1.3",
"chromedriver": "^119.0.1",
"chalk": "1.1.3",
"chromedriver": "^107.0.3",
"connect-history-api-fallback": "^2.0.0",
"cross-spawn": "^7.0.3",
"css-loader": "^7.1.2",
"css-loader": "^6.7.2",
"custom-event-polyfill": "^1.0.7",
"eslint": "^9.3.0",
"eslint-config-standard": "^17.1.0",
"eslint": "^7.32.0",
"eslint-config-standard": "^17.0.0",
"eslint-friendly-formatter": "^4.0.1",
"eslint-plugin-import": "^2.29.1",
"eslint-loader": "^4.0.2",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.2.0",
"eslint-plugin-promise": "^6.1.1",
"eslint-plugin-standard": "^5.0.0",
"eslint-plugin-vue": "^9.26.0",
"eslint-webpack-plugin": "^4.2.0",
"eventsource-polyfill": "^0.9.6",
"express": "^4.19.2",
"eslint-plugin-vue": "^9.7.0",
"eventsource-polyfill": "0.9.6",
"express": "4.17.3",
"file-loader": "^6.2.0",
"function-bind": "^1.1.2",
"function-bind": "1.1.1",
"html-webpack-plugin": "^5.5.0",
"http-proxy-middleware": "^3.0.0",
"json-loader": "^0.5.7",
"karma": "^6.4.3",
"karma-coverage": "^2.2.1",
"karma-firefox-launcher": "^2.1.3",
"karma-mocha": "^2.0.1",
"karma-mocha-reporter": "^2.2.5",
"karma-sinon-chai": "^2.0.2",
"karma-sourcemap-loader": "^0.4.0",
"karma-spec-reporter": "^0.0.36",
"http-proxy-middleware": "0.21.0",
"inject-loader": "2.0.1",
"isparta-loader": "2.0.0",
"json-loader": "0.5.7",
"karma": "6.3.17",
"karma-coverage": "1.1.2",
"karma-firefox-launcher": "1.3.0",
"karma-mocha": "2.0.1",
"karma-mocha-reporter": "2.2.5",
"karma-sinon-chai": "2.0.2",
"karma-sourcemap-loader": "0.3.8",
"karma-spec-reporter": "0.0.33",
"karma-webpack": "^5.0.0",
"lodash": "^4.17.21",
"lolex": "^6.0.0",
"mini-css-extract-plugin": "^2.9.0",
"mocha": "^10.4.0",
"nightwatch": "^3.6.3",
"opn": "^6.0.0",
"lodash": "4.17.21",
"lolex": "1.6.0",
"mini-css-extract-plugin": "0.12.0",
"mocha": "3.5.3",
"nightwatch": "0.9.21",
"opn": "4.0.2",
"ora": "0.4.1",
"postcss-html": "^1.5.0",
"postcss-loader": "^8.1.1",
"postcss-loader": "3.0.0",
"postcss-sass": "^0.5.0",
"raw-loader": "^4.0.2",
"sass": "^1.77.2",
"sass-loader": "^14.2.1",
"selenium-server": "^3.141.59",
"semver": "^7.6.2",
"shelljs": "^0.8.5",
"sinon": "^18.0.0",
"sinon-chai": "^3.7.0",
"raw-loader": "0.5.1",
"sass": "^1.56.0",
"sass-loader": "^13.2.0",
"selenium-server": "2.53.1",
"semver": "5.7.1",
"shelljs": "0.8.5",
"sinon": "2.4.1",
"sinon-chai": "2.14.0",
"stylelint": "^14.15.0",
"stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^29.0.0",
"stylelint-config-standard-scss": "^6.1.0",
"stylelint-rscss": "^0.4.0",
"url-loader": "^4.1.1",
"vue-loader": "^17.4.2",
"vue-style-loader": "^4.1.3",
"webpack": "^5.91.0",
"webpack-dev-middleware": "^7.2.1",
"webpack-hot-middleware": "^2.26.1",
"webpack-merge": "^5.10.0",
"workbox-webpack-plugin": "^7.1.0"
"vue-loader": "^17.0.0",
"vue-style-loader": "^4.1.2",
"webpack": "^5.75.0",
"webpack-dev-middleware": "^5.3.3",
"webpack-hot-middleware": "^2.25.1",
"webpack-merge": "^5.8.0",
"workbox-webpack-plugin": "^6.5.4"
},
"engines": {
"node": ">= 16.0.0",
+1 -5
View File
@@ -59,8 +59,7 @@ export default {
{
'-reverse': this.reverseLayout,
'-no-sticky-headers': this.noSticky,
'-has-new-post-button': this.newPostButtonShown,
'-wide-timeline': this.widenTimeline
'-has-new-post-button': this.newPostButtonShown
},
'-' + this.layoutType
]
@@ -94,9 +93,6 @@ export default {
newPostButtonShown () {
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile'
},
widenTimeline () {
return this.$store.getters.mergedConfig.widenTimeline
},
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
editingAvailable () { return this.$store.state.instance.editingAvailable },
layoutType () { return this.$store.state.interface.layoutType },
-9
View File
@@ -172,10 +172,6 @@ nav {
background-color: rgba(0, 0, 0, 0.15);
background-color: var(--underlay, rgba(0, 0, 0, 0.15));
z-index: -1000;
.-wide-timeline & {
margin:0 calc(var(--columnGap) / -2);
}
}
.app-layout {
@@ -191,17 +187,12 @@ nav {
grid-template-rows: 1fr;
box-sizing: border-box;
margin: 0 auto;
padding: 0 calc(var(--columnGap) / 2);
align-content: flex-start;
flex-wrap: wrap;
justify-content: center;
min-height: 100vh;
overflow-x: clip;
&.-wide-timeline {
--maxiColumn: minmax(var(--miniColumn), 1fr);
}
.column {
--___columnMargin: var(--columnGap);
-8
View File
@@ -173,10 +173,8 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('redirectRootNoLogin')
copyInstanceOption('redirectRootLogin')
copyInstanceOption('showInstanceSpecificPanel')
copyInstanceOption('minimalScopesMode')
copyInstanceOption('hideMutedPosts')
copyInstanceOption('collapseMessageWithSubject')
copyInstanceOption('scopeCopy')
copyInstanceOption('subjectLineBehavior')
copyInstanceOption('postContentType')
copyInstanceOption('alwaysShowSubjectInput')
@@ -185,12 +183,6 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('renderMisskeyMarkdown')
copyInstanceOption('sidebarRight')
if (config.backendCommitUrl)
copyInstanceOption('backendCommitUrl')
if (config.frontendCommitUrl)
copyInstanceOption('frontendCommitUrl')
return store.dispatch('setTheme', config['theme'])
}
+1 -1
View File
@@ -9,7 +9,7 @@
</div>
</template>
<script src="./about.js"></script>
<script src="./about.js" ></script>
<style lang="scss">
</style>
@@ -6,7 +6,7 @@
:bound-to="{ x: 'container' }"
remove-padding
>
<template #content>
<template v-slot:content>
<div class="dropdown-menu">
<template v-if="relationship.following">
<button
@@ -71,7 +71,7 @@
</button>
</div>
</template>
<template #trigger>
<template v-slot:trigger>
<button class="button-unstyled ellipsis-button">
<FAIcon
class="icon"
@@ -93,7 +93,7 @@
keypath="user_card.block_confirm"
tag="span"
>
<template #user>
<template v-slot:user>
<span
v-text="user.screen_name_ui"
/>
+1 -22
View File
@@ -16,14 +16,9 @@
.attachment-wrapper {
flex: 1 1 auto;
min-height: 200px;
height: 200px;
position: relative;
overflow: hidden;
align-content: center;
.status-popover & {
height: 200px;
}
}
.description-container {
@@ -120,22 +115,6 @@
align-items: center;
justify-content: center;
padding-top: 0.5em;
p {
line-height: 1.5;
padding: 0 0.5em;
white-space: pre-line;
text-align: center;
max-height: 200px;
overflow-y: auto;
scrollbar-color: var(--border) #0000;
.status-popover & {
text-overflow: ellipsis;
overflow: hidden;
height: 1lh;
}
}
}
+2 -2
View File
@@ -246,8 +246,8 @@
ref="flash"
class="flash"
:src="attachment.large_thumb_url || attachment.url"
@player-opened="setFlashLoaded(true)"
@player-closed="setFlashLoaded(false)"
@playerOpened="setFlashLoaded(true)"
@playerClosed="setFlashLoaded(false)"
/>
</span>
</div>
+1 -1
View File
@@ -14,7 +14,7 @@
</div>
</template>
<script src="./avatar_list.js"></script>
<script src="./avatar_list.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
+2 -2
View File
@@ -22,12 +22,12 @@
<script>
export default {
emits: ['update:modelValue'],
props: [
'modelValue',
'indeterminate',
'disabled'
],
emits: ['update:modelValue']
]
}
</script>
+2 -2
View File
@@ -14,7 +14,7 @@
:model-value="present"
:disabled="disabled"
class="opt"
@update:model-value="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
@update:modelValue="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
/>
<div class="input color-input-field">
<input
@@ -46,6 +46,7 @@
</div>
</div>
</template>
<style lang="scss" src="./color_input.scss"></style>
<script>
import Checkbox from '../checkbox/checkbox.vue'
import { hex2rgb } from '../../services/color_convert/color_convert.js'
@@ -107,7 +108,6 @@ export default {
}
}
</script>
<style lang="scss" src="./color_input.scss"></style>
<style lang="scss">
.color-control {
@@ -25,8 +25,6 @@
</dialog-modal>
</template>
<script src="./confirm_modal.js"></script>
<style lang="scss" scoped>
@import '../../_variables';
@@ -37,3 +35,5 @@
}
}
</style>
<script src="./confirm_modal.js"></script>
+3 -11
View File
@@ -267,11 +267,11 @@ const conversation = {
},
replies () {
let i = 1
// eslint-disable-next-line camelcase
return reduce(this.conversation, (result, { id, in_reply_to_status_id }) => {
/* eslint-disable camelcase */
const irid = in_reply_to_status_id
/* eslint-enable camelcase */
if (irid) {
result[irid] = result[irid] || []
result[irid].push({
@@ -414,14 +414,6 @@ const conversation = {
},
toggleExpanded () {
this.expanded = !this.expanded
const navHeight = document.getElementById("nav").offsetHeight
const headingHeight = document.getElementsByClassName("timeline-heading")[0].offsetHeight
document.documentElement.style.setProperty("--timeline-scroll-margin-top", `${navHeight + headingHeight}px`)
this.$nextTick(() => {
if (!this.expanded) {
this.$el.scrollIntoView({ block: 'nearest' })
}
})
},
getConversationId (statusId) {
const status = this.$store.state.statuses.allStatusesObject[statusId]
+2 -4
View File
@@ -91,7 +91,7 @@
:controlled-set-media-playing="(newVal) => toggleStatusContentProperty(status.id, 'mediaPlaying', newVal)"
@goto="setHighlight"
@toggle-expanded="toggleExpanded"
@toggleExpanded="toggleExpanded"
/>
<div
v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).length > 1"
@@ -184,7 +184,7 @@
:toggle-status-content-property="toggleStatusContentProperty"
@goto="setHighlight"
@toggle-expanded="toggleExpanded"
@toggleExpanded="toggleExpanded"
/>
</div>
</div>
@@ -278,7 +278,5 @@
&.-expanded.status-fadein {
margin: calc(var(--status-margin, $status-margin) / 2);
}
scroll-margin-block-start: var(--timeline-scroll-margin-top);
}
</style>
+2 -2
View File
@@ -44,9 +44,9 @@
/>
</router-link>
<router-link
v-if="publicTimelineVisible"
:to="{ name: 'public-timeline' }"
class="nav-icon"
v-if="publicTimelineVisible"
>
<FAIcon
fixed-width
@@ -68,9 +68,9 @@
/>
</router-link>
<router-link
v-if="federatedTimelineVisible"
:to="{ name: 'public-external-timeline' }"
class="nav-icon"
v-if="federatedTimelineVisible"
>
<FAIcon
fixed-width
@@ -9,7 +9,7 @@
class="btn button-default"
>
{{ $t('domain_mute_card.unmute') }}
<template #progress>
<template v-slot:progress>
{{ $t('domain_mute_card.unmute_progress') }}
</template>
</ProgressButton>
@@ -19,7 +19,7 @@
class="btn button-default"
>
{{ $t('domain_mute_card.mute') }}
<template #progress>
<template v-slot:progress>
{{ $t('domain_mute_card.mute_progress') }}
</template>
</ProgressButton>
@@ -2,7 +2,7 @@
<Modal
v-if="isFormVisible"
class="edit-form-modal-view"
@backdrop-clicked="closeModal"
@backdropClicked="closeModal"
>
<div class="edit-form-modal-panel panel">
<div class="panel-heading">
@@ -11,10 +11,10 @@
<PostStatusForm
class="panel-body"
v-bind="params"
:disable-polls="true"
:disable-visibility-selector="true"
:post-handler="doEditStatus"
@posted="closeModal"
:disablePolls="true"
:disableVisibilitySelector="true"
:post-handler="doEditStatus"
/>
</div>
</Modal>
-5
View File
@@ -1,5 +1,3 @@
import StillImage from '../still-image/still-image.vue'
const EMOJI_SIZE = 32 + 8
const GROUP_TITLE_HEIGHT = 24
const BUFFER_SIZE = 3 * EMOJI_SIZE
@@ -19,9 +17,6 @@ const EmojiGrid = {
resizeObserver: null
}
},
components: {
StillImage
},
mounted () {
const rect = this.$refs.container.getBoundingClientRect()
this.containerWidth = rect.width
+2 -3
View File
@@ -34,11 +34,10 @@
@click.stop.prevent="onEmoji(item.emoji)"
>
<span v-if="!item.emoji.imageUrl">{{ item.emoji.replacement }}</span>
<StillImage
<img
v-else
:src="item.emoji.imageUrl"
noStopGifs="true"
/>
>
</span>
</template>
</div>
+1 -3
View File
@@ -1,6 +1,5 @@
import Completion from '../../services/completion/completion.js'
import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import StillImage from '../still-image/still-image.vue'
import { take } from 'lodash'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
@@ -121,8 +120,7 @@ const EmojiInput = {
}
},
components: {
EmojiPicker,
StillImage
EmojiPicker
},
computed: {
padEmoji () {
+3 -8
View File
@@ -20,7 +20,6 @@
ref="picker"
show-keep-open
:class="{ hide: !showPicker }"
:visible="showPicker"
:enable-sticker-picker="enableStickerPicker"
class="emoji-picker-panel"
@emoji="insert"
@@ -44,15 +43,11 @@
:class="{ highlighted: index === highlighted }"
@click.stop.prevent="onClick($event, suggestion)"
>
<span
v-if="!suggestion.mfm"
class="image"
>
<StillImage
<span v-if="!suggestion.mfm" class="image">
<img
v-if="suggestion.img"
:src="suggestion.img"
noStopGifs="true"
/>
>
<span v-else>{{ suggestion.replacement }}</span>
</span>
<div class="label">
+3 -3
View File
@@ -1,4 +1,4 @@
const MFM_TAGS = ['bg', 'blur', 'bounce', 'center', 'fg', 'flip', 'font', 'jelly', 'jump', 'position', 'rainbow', 'rotate', 'scale', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4']
const MFM_TAGS = ['blur', 'bounce', 'flip', 'font', 'jelly', 'jump', 'rainbow', 'rotate', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4']
.map(tag => ({ displayText: tag, detailText: '$[' + tag + ' ]', replacement: '$[' + tag + ' ]', mfm: true }))
/**
@@ -122,14 +122,14 @@ export const suggestUsers = ({ dispatch, state }) => {
const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
return diff + nameAlphabetically + screenNameAlphabetically
/* eslint-disable camelcase */
}).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
displayText: screen_name_ui,
detailText: name,
imageUrl: profile_image_url_original,
replacement: '@' + screen_name + ' '
}))
/* eslint-enable camelcase */
suggestions = newSuggestions || []
return suggestions
+2 -21
View File
@@ -1,7 +1,6 @@
import { defineAsyncComponent } from 'vue'
import Checkbox from '../checkbox/checkbox.vue'
import EmojiGrid from '../emoji_grid/emoji_grid.vue'
import StillImage from '../still-image/still-image.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faBoxOpen,
@@ -27,17 +26,12 @@ const EmojiPicker = {
required: false,
type: Boolean,
default: false
},
visible: {
required: false,
type: Boolean,
default: true
}
},
data () {
return {
keyword: '',
activeGroup: this.getDefaultGroup(),
activeGroup: 'standard',
showingStickers: false,
keepOpen: false
}
@@ -45,8 +39,7 @@ const EmojiPicker = {
components: {
StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')),
Checkbox,
EmojiGrid,
StillImage
EmojiGrid
},
methods: {
debouncedSearch: debounce(function (e) {
@@ -89,11 +82,6 @@ const EmojiPicker = {
return list.filter(emoji => {
return (regex.test(emoji.displayText) || (!emoji.imageUrl && emoji.replacement === this.keyword))
})
},
getDefaultGroup () {
if (!this.visible) return null
const recentEmojis = this.$store.getters.recentEmojis
return recentEmojis.length === 0 ? 'standard' : 'recent'
}
},
computed: {
@@ -160,13 +148,6 @@ const EmojiPicker = {
stickerPickerEnabled () {
return (this.$store.state.instance.stickers || []).length !== 0 && this.enableStickerPicker
}
},
watch: {
visible (val, oldVal) {
if (val && this.activeGroup === null) {
this.activeGroup = this.getDefaultGroup()
}
}
}
}
+2 -3
View File
@@ -18,11 +18,10 @@
@click.prevent="highlight(group.id)"
>
<span v-if="!group.first.imageUrl">{{ group.first.replacement }}</span>
<StillImage
<img
v-else
:src="group.first.imageUrl"
noStopGifs="true"
/>
>
</span>
<span
v-if="stickerPickerEnabled"
@@ -11,7 +11,7 @@
@click="emojiOnClick(reaction.name, $event)"
@mouseenter="fetchEmojiReactionsByIfMissing()"
>
<template
<span
v-if="reaction.url !== null"
>
<StillImage
@@ -19,15 +19,16 @@
:title="reaction.name"
:alt="reaction.name"
class="reaction-emoji"
height="2.55em"
/>
{{ reaction.count }}
</template>
<template v-else>
</span>
<span v-else>
<span class="reaction-emoji unicode-emoji">
{{ reaction.name }}
</span>
<span>{{ reaction.count }}</span>
</template>
</span>
</button>
</UserListPopover>
<a
@@ -41,7 +42,7 @@
</div>
</template>
<script src="./emoji_reactions.js"></script>
<script src="./emoji_reactions.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
@@ -52,26 +53,23 @@
container-type: inline-size;
}
.unicode-emoji {
font-size: 210%;
}
.emoji-reaction {
padding: 2px 0.5em;
padding: 0 0.5em;
margin-right: 0.5em;
margin-top: 0.5em;
display: flex;
align-items: end;
align-items: center;
justify-content: center;
box-sizing: border-box;
.reaction-emoji {
width: auto;
max-width: 96cqw;
height: 2.55em !important;
margin-right: 0.25em;
&.still-image {
height: 2.55em;
}
&.unicode-emoji {
display: inline-block;
font-size: 2.125em; // assuming default line height of 1.2rem and emojis that don't exceed line height
line-height: 2.55rem;
}
}
&:focus {
outline: none;
@@ -99,9 +97,9 @@
}
.button-default.picked-reaction {
&, &:hover {
box-shadow: inset 0 0 0 1px var(--accent, $fallback--link);
}
border: 1px solid var(--accent, $fallback--link);
margin-left: -1px; // offset the border, can't use inset shadows either
margin-right: calc(0.5em - 1px);
}
</style>
@@ -7,7 +7,7 @@
:bound-to="{ x: 'container' }"
remove-padding
>
<template #content="{close}">
<template v-slot:content="{close}">
<div class="dropdown-menu">
<button
v-if="canMute && !status.thread_muted"
@@ -172,7 +172,7 @@
</button>
</div>
</template>
<template #trigger>
<template v-slot:trigger>
<button class="button-unstyled popover-trigger">
<FAIcon
class="fa-scale-110 fa-old-padding"
@@ -205,7 +205,7 @@
</Popover>
</template>
<script src="./extra_buttons.js"></script>
<script src="./extra_buttons.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
@@ -35,7 +35,7 @@
</div>
</template>
<script src="./favorite_button.js"></script>
<script src="./favorite_button.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
@@ -4,7 +4,6 @@ const FeaturesPanel = {
computed: {
whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled },
mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable },
minimalScopesMode: function () { return this.$store.state.instance.minimalScopesMode },
textlimit: function () { return this.$store.state.instance.textlimit },
uploadlimit: function () { return fileSizeFormatService.fileSizeFormat(this.$store.state.instance.uploadlimit) }
}
@@ -23,7 +23,7 @@
</div>
</template>
<script src="./features_panel.js"></script>
<script src="./features_panel.js" ></script>
<style lang="scss">
.features-panel li {
@@ -1,8 +1,5 @@
<template>
<basic-user-card
v-if="show"
:user="user"
>
<basic-user-card :user="user" v-if="show">
<div class="follow-request-card-content-container">
<button
class="btn button-default"
+1 -1
View File
@@ -47,7 +47,7 @@
</div>
</template>
<script src="./font_control.js"></script>
<script src="./font_control.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
+4 -2
View File
@@ -88,8 +88,10 @@ const Gallery = {
set(this.sizes, id, { width, height })
},
rowStyle (row) {
if (!row.audio && !row.minimal && !row.grid) {
return { 'aspect-ratio': `1/${(1 / (row.items.length + 0.6))}` }
if (row.audio) {
return { 'padding-bottom': '25%' } // fixed reduced height for audio
} else if (!row.minimal && !row.grid) {
return { 'padding-bottom': `${(100 / (row.items.length + 0.6))}%` }
}
},
itemStyle (id, row) {
+3 -9
View File
@@ -31,8 +31,8 @@
:description="descriptions && descriptions[attachment.id]"
:hide-description="size === 'small' || tooManyAttachments && hidingLong"
:style="itemStyle(attachment.id, row.items)"
@set-media="onMedia"
@natural-size-load="onNaturalSizeLoad"
@setMedia="onMedia"
@naturalSizeLoad="onNaturalSizeLoad"
/>
</div>
</div>
@@ -96,15 +96,9 @@
.gallery-row {
position: relative;
height: 0;
width: 100%;
flex-grow: 1;
.Status & {
max-height: 30em;
}
&.-audio {
aspect-ratio: 4/1; // this is terrible, but it's how it was before so I'm not changing it >:(
}
&:not(:first-child) {
margin-top: 0.5em;
+2 -2
View File
@@ -14,6 +14,6 @@
</span>
</template>
<script src="./hashtag_link.js" />
<script src="./hashtag_link.js"/>
<style lang="scss" src="./hashtag_link.scss" />
<style lang="scss" src="./hashtag_link.scss"/>
@@ -10,4 +10,4 @@
</div>
</template>
<script src="./instance_specific_panel.js"></script>
<script src="./instance_specific_panel.js" ></script>
-1
View File
@@ -42,7 +42,6 @@ export default {
@import '../../_variables.scss';
.list {
min-height: 1em;
&-item:not(:last-child) {
border-bottom: 1px solid;
border-bottom-color: $fallback--border;
@@ -10,7 +10,7 @@
</div>
</div>
<div class="panel-body">
<p>{{ $t("about.bubble_instances_description") }}:</p>
<p>{{ $t("about.bubble_instances_description")}}:</p>
<ul>
<li
v-for="instance in bubbleInstances"
+1 -1
View File
@@ -90,7 +90,7 @@
</div>
</template>
<script src="./login_form.js"></script>
<script src="./login_form.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
+3 -4
View File
@@ -2,7 +2,7 @@
<Modal
v-if="showing"
class="media-modal-view"
@backdrop-clicked="hideIfNotSwiped"
@backdropClicked="hideIfNotSwiped"
>
<SwipeClick
v-if="type === 'image'"
@@ -24,15 +24,14 @@
:min-scale="pinchZoomMinScale"
:reset-to-min-scale-limit="pinchZoomScaleResetLimit"
>
<StillImage
<img
:class="{ loading }"
class="modal-image"
:src="currentMedia.url"
:alt="currentMedia.description"
:title="currentMedia.description"
@load="onImageLoaded"
noStopGifs="true"
/>
>
</PinchZoom>
</SwipeClick>
<VideoAttachment
+1 -1
View File
@@ -42,7 +42,7 @@ const mediaUpload = {
.then((fileData) => {
self.$emit('uploaded', fileData)
self.decreaseUploadCount()
}, (error) => {
}, (error) => { // eslint-disable-line handle-callback-err
self.$emit('upload-failed', 'default')
self.decreaseUploadCount()
})
+1 -1
View File
@@ -26,7 +26,7 @@
</label>
</template>
<script src="./media_upload.js"></script>
<script src="./media_upload.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
+2 -2
View File
@@ -66,6 +66,6 @@
</span>
</template>
<script src="./mention_link.js" />
<script src="./mention_link.js"/>
<style lang="scss" src="./mention_link.scss" />
<style lang="scss" src="./mention_link.scss"/>
@@ -37,5 +37,5 @@
</span>
</span>
</template>
<script src="./mentions_line.js"></script>
<script src="./mentions_line.js" ></script>
<style lang="scss" src="./mentions_line.scss" />
+1 -1
View File
@@ -69,4 +69,4 @@
</div>
</div>
</template>
<script src="./recovery_form.js"></script>
<script src="./recovery_form.js" ></script>
-1
View File
@@ -18,7 +18,6 @@
<input
id="code"
v-model="code"
autocomplete="one-time-code"
class="form-control"
>
</div>
@@ -4,7 +4,7 @@
class="panel-heading"
@click="toggleHidden"
>
<h4>{{ $t('moderation.reports.report') + ' ' + account.screen_name }}</h4>
<h4>{{ $t('moderation.reports.report') + ' ' + this.account.screen_name }}</h4>
<button
v-if="isOpen"
class="button-default"
@@ -24,7 +24,7 @@
class="button-default"
@click.stop="updateReportState('open')"
>
{{ $t('moderation.reports.reopen') }}
{{ $t('moderation.reports.reopen') }}
</button>
</div>
<div
@@ -35,10 +35,7 @@
<div v-if="content">
{{ decode(content) }}
</div>
<i
v-else
class="faint"
>
<i v-else class="faint">
{{ $t('moderation.reports.no_content') }}
</i>
<div class="report-author">
@@ -46,12 +43,12 @@
class="small-avatar"
:user="actor"
/>
{{ actor.screen_name }}
{{ this.actor.screen_name }}
</div>
</div>
<div
v-if="!hidden && statuses.length > 0"
class="dropdown"
v-if="!hidden && this.statuses.length > 0"
>
<button
class="button button-unstyled dropdown-header"
@@ -77,8 +74,8 @@
</div>
</div>
<div
v-if="!hidden && notes.length > 0"
class="dropdown"
v-if="!hidden && this.notes.length > 0"
>
<button
class="button button-unstyled dropdown-header"
@@ -102,9 +99,9 @@
</div>
<div class="report-add-note">
<textarea
v-model.trim="note"
rows="1"
cols="1"
v-model.trim="note"
:placeholder="$t('moderation.reports.note_placeholder')"
/>
<button
@@ -137,7 +134,7 @@
:offset="{ y: 5 }"
remove-padding
>
<template #trigger>
<template v-slot:trigger>
<button
class="btn button-default"
:disabled="!tagPolicyEnabled"
@@ -150,7 +147,7 @@
/>
</button>
</template>
<template #content="{close}">
<template v-slot:content="{close}">
<div
class="dropdown-menu"
:disabled="!tagPolicyEnabled"
@@ -6,7 +6,7 @@
class="small-avatar"
:user="user"
/>
{{ user.screen_name }}
{{ this.user.screen_name }}
</div>
<div class="header-right">
<Timeago
-3
View File
@@ -22,9 +22,6 @@ export default {
default: false
}
},
emits: [
'backdropClicked',
],
computed: {
classes () {
return {
@@ -8,7 +8,7 @@
@show="setToggled(true)"
@close="setToggled(false)"
>
<template #content>
<template v-slot:content>
<div class="dropdown-menu">
<span v-if="user.is_local">
<button
@@ -122,7 +122,7 @@
</span>
</div>
</template>
<template #trigger>
<template v-slot:trigger>
<button
class="btn button-default btn-block moderation-tools-button"
:class="{ toggled }"
@@ -137,11 +137,11 @@
v-if="showDeleteUserDialog"
:on-cancel="deleteUserDialog.bind(this, false)"
>
<template #header>
<template v-slot:header>
{{ $t('user_card.admin_menu.delete_user') }}
</template>
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
<template #footer>
<template v-slot:footer>
<button
class="btn button-default"
@click="deleteUserDialog(false)"
+1 -1
View File
@@ -102,7 +102,7 @@
</div>
</template>
<script src="./nav_panel.js"></script>
<script src="./nav_panel.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
+1 -3
View File
@@ -6,7 +6,6 @@ import UserCard from '../user_card/user_card.vue'
import Timeago from '../timeago/timeago.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import StillImage from '../still-image/still-image.vue'
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
@@ -51,8 +50,7 @@ const Notification = {
Timeago,
Status,
RichContent,
ConfirmModal,
StillImage
ConfirmModal
},
methods: {
toggleUserExpanded () {
@@ -101,8 +101,4 @@
color: $fallback--cBlue;
color: var(--cBlue, $fallback--cBlue);
}
.attachment-wrapper {
min-height: unset;
}
}
+3 -4
View File
@@ -116,13 +116,12 @@
scope="global"
keypath="notifications.reacted_with"
>
<still-image
<img
v-if="notification.emoji_url !== null"
class="notification-reaction-emoji"
:src="notification.emoji_url"
:title="notification.emoji"
:alt="notification.emoji"
/>
:name="notification.emoji"
>
<span
v-else
class="emoji-reaction-emoji"
@@ -5,7 +5,7 @@
placement="bottom"
:bound-to="{ x: 'container' }"
>
<template #content>
<template v-slot:content>
<div class="dropdown-menu">
<button
class="button-default dropdown-item"
@@ -72,7 +72,7 @@
</button>
</div>
</template>
<template #trigger>
<template v-slot:trigger>
<button class="filter-trigger-button button-unstyled">
<FAIcon icon="filter" />
</button>
@@ -14,7 +14,7 @@
:model-value="present"
:disabled="disabled"
class="opt"
@update:model-value="$emit('update:modelValue', !present ? fallback : undefined)"
@update:modelValue="$emit('update:modelValue', !present ? fallback : undefined)"
/>
<input
:id="name"
+1
View File
@@ -2,6 +2,7 @@
<pinch-zoom
class="pinch-zoom-parent"
v-bind="$attrs"
v-on="$listeners"
>
<slot />
</pinch-zoom>
+2 -10
View File
@@ -50,13 +50,6 @@ export default {
totalVotesCount () {
return this.poll.votes_count
},
totalFractionBase () {
// Due to a backend bug, we might not have any voter count info for remote polls
// in this case, fall back to count of votes even for multiple cjoice polls
// to be able to at least display _something_
const total_base = this.poll.multiple ? this.poll.voters_count : this.poll.votes_count
return total_base > 0 ? total_base : this.poll.votes_count
},
containerClass () {
return {
loading: this.loading
@@ -77,11 +70,10 @@ export default {
},
methods: {
percentageForOption (count) {
const total = this.totalFractionBase
return total === 0 ? 0 : Math.round(count / total * 100)
return this.totalVotesCount === 0 ? 0 : Math.round(count / this.totalVotesCount * 100)
},
resultTitle (option) {
return `${option.votes_count}/${this.totalFractionBase} ${this.$t('polls.votes')}`
return `${option.votes_count}/${this.totalVotesCount} ${this.$t('polls.votes')}`
},
fetchPoll () {
this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
-2
View File
@@ -24,7 +24,6 @@
<button
v-if="options.length > 2"
class="delete-option button-unstyled -hover-highlight"
type="button"
@click="deleteOption(index)"
>
<FAIcon icon="times" />
@@ -33,7 +32,6 @@
<button
v-if="options.length < maxOptions"
class="add-option faint button-unstyled -hover-highlight"
type="button"
@click="addOption"
>
<FAIcon
@@ -9,13 +9,11 @@ import StatusContent from '../status_content/status_content.vue'
import fileTypeService from '../../services/file_type/file_type.service.js'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
import { reject, map, uniqBy, debounce } from 'lodash'
import { usePostLanguageOptions } from 'src/lib/post_language'
import scopeUtils from 'src/lib/scope_utils.js'
import suggestor from '../emoji_input/suggestor.js'
import { mapGetters, mapState } from 'vuex'
import Checkbox from '../checkbox/checkbox.vue'
import Select from '../select/select.vue'
import iso6391 from 'iso-639-1'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
@@ -64,13 +62,6 @@ const deleteDraft = (draftKey) => {
localStorage.setItem('drafts', JSON.stringify(draftData));
}
const interfaceToISOLanguage = (ilang) => {
const sep = ilang.indexOf("_");
return sep < 0 ?
ilang :
ilang.substr(0, sep);
}
const PostStatusForm = {
props: [
'statusId',
@@ -86,7 +77,6 @@ const PostStatusForm = {
'quoteId',
'repliedUser',
'attentions',
'copyMessageLanguage',
'copyMessageScope',
'subject',
'disableSubject',
@@ -139,13 +129,6 @@ const PostStatusForm = {
this.$refs.textarea.focus()
}
},
setup() {
const {postLanguageOptions} = usePostLanguageOptions()
return {
postLanguageOptions,
}
},
data () {
const preset = this.$route.query.message
let statusText = preset || ''
@@ -155,7 +138,7 @@ const PostStatusForm = {
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
}
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, alwaysShowSubjectInput } = this.$store.getters.mergedConfig
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage, alwaysShowSubjectInput } = this.$store.getters.mergedConfig
let statusParams = {
spoilerText: this.subject || '',
@@ -166,7 +149,7 @@ const PostStatusForm = {
poll: {},
mediaDescriptions: {},
visibility: this.suggestedVisibility(),
language: this.suggestedLanguage(),
language: interfaceLanguage,
contentType
}
@@ -181,7 +164,7 @@ const PostStatusForm = {
poll: this.statusPoll || {},
mediaDescriptions: this.statusMediaDescriptions || {},
visibility: this.statusScope || this.suggestedVisibility(),
language: this.statusLanguage || this.suggestedLanguage(),
language: this.statusLanguage || interfaceLanguage,
contentType: statusContentType
}
}
@@ -247,9 +230,6 @@ const PostStatusForm = {
userDefaultScope () {
return this.$store.state.users.currentUser.default_scope
},
showAllScopes () {
return !this.mergedConfig.minimalScopesMode
},
emojiUserSuggestor () {
return suggestor({
emoji: [
@@ -291,9 +271,6 @@ const PostStatusForm = {
isOverLengthLimit () {
return this.hasStatusLengthLimit && (this.charactersLeft < 0)
},
minimalScopesMode () {
return this.$store.state.instance.minimalScopesMode
},
alwaysShowSubject () {
return this.mergedConfig.alwaysShowSubjectInput
},
@@ -332,11 +309,13 @@ const PostStatusForm = {
...mapState({
mobileLayout: state => state.interface.mobileLayout
}),
isoLanguages () {
return iso6391.getAllCodes();
}
},
watch: {
'newStatus': {
deep: true,
flush: 'sync',
handler () {
this.statusChanged()
}
@@ -349,22 +328,17 @@ const PostStatusForm = {
this.saveDraft()
},
clearStatus () {
const config = this.$store.getters.mergedConfig
const newStatus = this.newStatus
this.newStatus = {
status: '',
spoilerText: '',
files: [],
nsfw: !!config.sensitiveByDefault,
visibility: this.suggestedVisibility(),
contentType: config.postContentType,
language: this.suggestedLanguage(),
visibility: newStatus.visibility,
contentType: newStatus.contentType,
language: newStatus.language,
poll: {},
mediaDescriptions: {}
}
const scopeselector = this.$refs.scopeselector
if (scopeselector) {
scopeselector.currentScope = this.newStatus.visibility
}
this.pollFormVisible = false
this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
this.clearPollForm()
@@ -524,7 +498,7 @@ const PostStatusForm = {
addMediaFile (fileInfo) {
this.newStatus.files.push(fileInfo)
if (this.$store.getters.mergedConfig.sensitiveIfSubject && this.newStatus.spoilerText !== '' || !!this.$store.getters.mergedConfig.sensitiveByDefault) {
if (this.$store.getters.mergedConfig.sensitiveIfSubject && this.newStatus.spoilerText !== '') {
this.newStatus.nsfw = true
}
this.$emit('resize', { delayed: true })
@@ -773,19 +747,16 @@ const PostStatusForm = {
openProfileTab () {
this.$store.dispatch('openSettingsModalTab', 'profile')
},
suggestedLanguage () {
// Make sure the inherited language is actually valid
if (this.postLanguageOptions.find(o => o.value === this.copyMessageLanguage)) {
return this.copyMessageLanguage
}
const { postLanguage: defaultPostLanguage, interfaceLanguage } = this.$store.getters.mergedConfig
const postLanguage = defaultPostLanguage || interfaceToISOLanguage(interfaceLanguage)
return postLanguage
},
suggestedVisibility () {
const maxScope = this.copyMessageScope
const defaultScope = this.$store.state.users.currentUser.default_scope
return scopeUtils.negotiate(defaultScope, maxScope)
if (this.copyMessageScope) {
if (this.copyMessageScope === 'direct') {
return this.copyMessageScope
}
if (this.copyMessageScope !== 'public' && this.$store.state.users.currentUser.default_scope !== 'private') {
return this.copyMessageScope
}
}
return this.$store.state.users.currentUser.default_scope
}
}
}
@@ -18,7 +18,6 @@
>
<button
class="button-unstyled -link"
type="button"
@click="openProfileTab"
>
{{ $t('post_status.account_not_locked_warning_link') }}
@@ -119,8 +118,8 @@
/>
</div>
<EmojiInput
v-if="subjectVisible"
ref="subject-emoji-input"
v-if="subjectVisible"
v-model="newStatus.spoilerText"
enable-emoji-picker
hide-emoji-button
@@ -137,7 +136,6 @@
class="form-post-subject"
@input="onSubjectInput"
@focus="focusSubjectInput()"
@keydown.exact.enter.prevent
>
</EmojiInput>
<i18n-t
@@ -172,7 +170,7 @@
cols="1"
:disabled="posting && !optimisticPosting"
class="form-post-body"
:class="{ 'scrollable-form': !!maxHeight, '-has-subject': subjectVisible }"
:class="{ 'scrollable-form': !!maxHeight }"
@keydown.exact.enter="submitOnEnter && postStatus($event, newStatus)"
@keydown.meta.enter="postStatus($event, newStatus)"
@keydown.ctrl.enter="!submitOnEnter && postStatus($event, newStatus)"
@@ -192,12 +190,9 @@
<div
v-if="!disableScopeSelector"
class="visibility-tray"
:class="{ 'visibility-tray-edit': isEdit }"
>
<scope-selector
ref="scopeselector"
v-if="!disableVisibilitySelector"
:show-all="showAllScopes"
:user-default="userDefaultScope"
:original-scope="copyMessageScope"
:initial-scope="newStatus.visibility"
@@ -205,50 +200,47 @@
/>
<div
class="format-selector-container">
<div
class="format-selector"
>
<Select
id="post-language"
v-model="newStatus.language"
class="form-control"
>
<option
v-for="language in postLanguageOptions"
:key="language.key"
:value="language.value"
>
{{ language.label }}
</option>
</Select>
</div>
<div
v-if="postFormats.length > 1"
class="text-format format-selector"
class="language-selector"
>
<Select
id="post-content-type"
v-model="newStatus.contentType"
class="form-control"
>
<option
v-for="postFormat in postFormats"
:key="postFormat"
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }}
</option>
</Select>
</div>
<div
v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
class="text-format format-selector"
<Select
id="post-language"
v-model="newStatus.language"
class="form-control"
>
<span class="only-format">
{{ $t(`post_status.content_type["${postFormats[0]}"]`) }}
</span>
</div>
<option
v-for="language in isoLanguages"
:key="language"
:value="language"
>
{{ language }}
</option>
</Select>
</div>
<div
v-if="postFormats.length > 1"
class="text-format"
>
<Select
id="post-content-type"
v-model="newStatus.contentType"
class="form-control"
>
<option
v-for="postFormat in postFormats"
:key="postFormat"
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }}
</option>
</Select>
</div>
<div
v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
class="text-format"
>
<span class="only-format">
{{ $t(`post_status.content_type["${postFormats[0]}"]`) }}
</span>
</div>
</div>
</div>
@@ -276,7 +268,6 @@
<button
class="emoji-icon button-unstyled"
:title="$t('emoji.add_emoji')"
type="button"
@click="showEmojiPicker"
>
<FAIcon icon="smile-beam" />
@@ -286,7 +277,6 @@
class="poll-icon button-unstyled"
:class="{ selected: pollFormVisible }"
:title="$t('polls.add_poll')"
type="button"
@click="togglePollForm"
>
<FAIcon icon="poll-h" />
@@ -296,7 +286,6 @@
class="spoiler-icon button-unstyled"
:class="{ selected: subjectVisible }"
:title="$t('post_status.toggle_content_warning')"
type="button"
@click="toggleSubjectVisible"
>
<FAIcon icon="eye-slash" />
@@ -471,10 +460,6 @@
align-items: baseline;
}
.visibility-tray-edit {
justify-content: right;
}
.visibility-notice.edit-warning {
> :first-child {
margin-top: 0;
@@ -485,12 +470,6 @@
}
}
.format-selector-container {
.format-selector {
display: inline-block;
}
}
.media-upload-icon, .poll-icon, .emoji-icon, .spoiler-icon {
font-size: 1.85em;
line-height: 1.1;
@@ -591,11 +570,6 @@
line-height: 1.85;
}
.form-post-subject {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.form-post-body {
// TODO: make a resizable textarea component?
box-sizing: content-box; // needed for easier computation of dynamic size
@@ -608,11 +582,6 @@
min-height: calc(var(--post-line-height) * 1em);
resize: none;
&.-has-subject {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
&.scrollable-form {
overflow-y: auto;
}
@@ -3,7 +3,7 @@
v-if="isLoggedIn && !resettingForm"
:is-open="modalActivated"
class="post-form-modal-view"
@backdrop-clicked="closeModal"
@backdropClicked="closeModal"
>
<div class="post-form-modal-panel panel">
<div class="panel-heading">
+3 -3
View File
@@ -8,13 +8,13 @@
remove-padding
@show="focusInput"
>
<template #content="{close}">
<template v-slot:content="{close}">
<EmojiPicker
:enable-sticker-picker="false"
@emoji="addReaction($event, close)"
/>
</template>
<template #trigger>
<template v-slot:trigger>
<button
class="button-unstyled popover-trigger"
:title="$t('tool_tip.add_reaction')"
@@ -28,7 +28,7 @@
</Popover>
</template>
<script src="./react_button.js"></script>
<script src="./react_button.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
@@ -2,7 +2,7 @@ export default {
props: [ 'user' ],
computed: {
subscribeUrl () {
// eslint-disable-next-line no-undef
const serverUrl = new URL(this.user.statusnet_profile_url)
return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
}
@@ -1,6 +1,4 @@
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import ScopeSelector from '../scope_selector/scope_selector.vue'
import scopeUtils from 'src/lib/scope_utils.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faRetweet } from '@fortawesome/free-solid-svg-icons'
@@ -9,14 +7,12 @@ library.add(faRetweet)
const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'],
components: {
ConfirmModal,
ScopeSelector
ConfirmModal
},
data () {
return {
animated: false,
showingConfirmDialog: false,
retweetVisibility: this.$store.state.users.currentUser.default_scope
showingConfirmDialog: false
}
},
methods: {
@@ -29,7 +25,7 @@ const RetweetButton = {
},
doRetweet () {
if (!this.status.repeated) {
this.$store.dispatch('retweet', { id: this.status.id, visibility: this.retweetVisibility })
this.$store.dispatch('retweet', { id: this.status.id })
} else {
this.$store.dispatch('unretweet', { id: this.status.id })
}
@@ -44,9 +40,6 @@ const RetweetButton = {
},
hideConfirmDialog () {
this.showingConfirmDialog = false
},
changeVis (visibility) {
this.retweetVisibility = visibility
}
},
computed: {
@@ -61,15 +54,6 @@ const RetweetButton = {
},
remoteInteractionLink () {
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
},
userDefaultScope () {
return this.$store.state.users.currentUser.default_scope
},
statusScope () {
return this.status.visibility
},
initialScope () {
return scopeUtils.negotiate(this.userDefaultScope, this.status.visibility)
}
}
}
@@ -49,18 +49,12 @@
@cancelled="hideConfirmDialog"
>
{{ $t('status.repeat_confirm') }}
<scope-selector
:user-default="userDefaultScope"
:original-scope="statusScope"
:initial-scope="initialScope"
:on-scope-change="changeVis"
/>
</confirm-modal>
</teleport>
</div>
</template>
<script src="./retweet_button.js"></script>
<script src="./retweet_button.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
@@ -121,19 +121,6 @@ export default {
}
}
const mfmStyleFromDataAttributes = (attributes) => {
// CSS selectors can check if a data-* attribute is true, but can't use other values, so we want to add them to the style attribute
// Here we turn e.g. `{'data-mfm-some': '1deg', 'data-mfm-thing': '5s'}` to "--mfm-some: 1deg;--mfm-thing: 5s;"
// Note that we only add the value to `style` when they contain only letters, numbers, dot, or minus signs
// At the moment of writing, this should be enough for legitimate purposes and reduces the chance of injection by using special characters
// There is a special case for the `color` value, who is provided without `#`, but requires this in the `style` attribute
return Object.keys(attributes).filter(
(key) => key.startsWith('data-mfm-') && attributes[key] !== true && /^[a-zA-Z0-9.\-]*$/.test(attributes[key])
).map(
(key) => '--mfm-' + key.substr(9) + (key === 'data-mfm-color' ? ': #' : ': ') + attributes[key] + ';'
).reduce((a,v) => a+v, '')
}
// Processor to use with html_tree_converter
const processItem = (item, index, array, what) => {
// Handle text nodes - just add emoji
@@ -204,15 +191,6 @@ export default {
if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) {
return ['', children.map(processItem), '']
}
let mfm_style = mfmStyleFromDataAttributes(attrs)
if (mfm_style !== '') {
return [
opener.slice(0,-1) + ' style="' + mfm_style + '">',
children.map(processItem),
closer
]
}
}
if (children !== undefined) {
+20 -10
View File
@@ -6,8 +6,6 @@ import {
faGlobe
} from '@fortawesome/free-solid-svg-icons'
import scopeUtils from 'src/lib/scope_utils.js'
library.add(
faEnvelope,
faGlobe,
@@ -15,11 +13,18 @@ library.add(
faLockOpen
)
const SCOPE_LEVELS = {
'direct': 0,
'private': 1,
'local': 2,
'unlisted': 2,
'public': 3
}
const ScopeSelector = {
props: [
'showAll',
'userDefault',
// scope of parent object
'originalScope',
'initialScope',
'onScopeChange'
@@ -34,16 +39,16 @@ const ScopeSelector = {
return !this.showPublic && !this.showUnlisted && !this.showPrivate && !this.showDirect
},
showPublic () {
return this.shouldShow('public')
return this.originalScope !== 'direct' && this.shouldShow('public')
},
showLocal () {
return this.shouldShow('local')
return this.originalScope !== 'direct' && this.shouldShow('local')
},
showUnlisted () {
return this.shouldShow('unlisted')
return this.originalScope !== 'direct' && this.shouldShow('unlisted')
},
showPrivate () {
return this.shouldShow('private')
return this.originalScope !== 'direct' && this.shouldShow('private')
},
showDirect () {
return this.shouldShow('direct')
@@ -60,10 +65,15 @@ const ScopeSelector = {
},
methods: {
shouldShow (scope) {
if (!this.originalScope)
if (!this.originalScope) {
return true
else
return scopeUtils.compare(scope, this.originalScope) <= 0
}
if (this.originalScope === 'local') {
return scope === 'direct' || scope === 'local'
}
return SCOPE_LEVELS[scope] <= SCOPE_LEVELS[this.originalScope]
},
changeVis (scope) {
this.currentScope = scope
@@ -24,7 +24,7 @@
:items="items"
:get-key="getKey"
>
<template #item="{item}">
<template v-slot:item="{item}">
<div
class="selectable-list-item-inner"
:class="{ 'selectable-list-item-selected-inner': isSelected(item) }"
@@ -41,7 +41,7 @@
/>
</div>
</template>
<template #empty>
<template v-slot:empty>
<slot name="empty" />
</template>
</List>
@@ -6,7 +6,7 @@
<Checkbox
:model-value="state"
:disabled="disabled"
@update:model-value="update"
@update:modelValue="update"
>
<span
v-if="!!$slots.default"
@@ -8,7 +8,7 @@
<Select
:model-value="state"
:disabled="disabled"
@update:model-value="update"
@update:modelValue="update"
>
<option
v-for="option in options"
@@ -6,14 +6,14 @@
<Popover
trigger="hover"
>
<template #trigger>
<template v-slot:trigger>
&nbsp;
<FAIcon
icon="wrench"
:aria-label="$t('settings.setting_changed')"
/>
</template>
<template #content>
<template v-slot:content>
<div class="modified-tooltip">
{{ $t('settings.setting_changed') }}
</div>
@@ -6,14 +6,14 @@
<Popover
trigger="hover"
>
<template #trigger>
<template v-slot:trigger>
&nbsp;
<FAIcon
icon="server"
:aria-label="$t('settings.setting_server_side')"
/>
</template>
<template #content>
<template v-slot:content>
<div class="serverside-tooltip">
{{ $t('settings.setting_server_side') }}
</div>
@@ -69,7 +69,7 @@ const SettingsModal = {
this.$store.dispatch('closeSettingsModal')
},
logout () {
this.$router.replace(this.$store.state.instance.redirectRootNoLogin || '/main/all')
this.$router.replace('/main/public')
this.$store.dispatch('closeSettingsModal')
this.$store.dispatch('logout')
},
@@ -108,7 +108,7 @@
<Checkbox
:model-value="!!expertLevel"
class="expertMode"
@update:model-value="expertLevel = Number($event)"
@update:modelValue="expertLevel = Number($event)"
>
{{ $t("settings.expert_mode") }}
</Checkbox>
@@ -72,7 +72,7 @@ const DataImportExportTab = {
// check is it's a local user
if (user && user.is_local) {
// append the instance address
// eslint-disable-next-line no-undef
return user.screen_name + '@' + location.hostname
}
return user.screen_name
@@ -4,7 +4,6 @@ import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import IntegerSetting from '../helpers/integer_setting.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import { usePostLanguageOptions } from 'src/lib/post_language'
import SharedComputedObject from '../helpers/shared_computed_object.js'
import ServerSideIndicator from '../helpers/server_side_indicator.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
@@ -18,11 +17,6 @@ library.add(
)
const GeneralTab = {
setup() {
const {postLanguageOptions} = usePostLanguageOptions()
return {postLanguageOptions}
},
data () {
return {
subjectLineOptions: ['email', 'noop', 'masto'].map(mode => ({
@@ -124,12 +118,6 @@ const GeneralTab = {
this.$store.dispatch('setOption', { name: 'translationLanguage', value: val })
}
},
postLanguage: {
get: function () { return this.$store.getters.mergedConfig.postLanguage },
set: function (val) {
this.$store.dispatch('setOption', { name: 'postLanguage', value: val })
}
},
...SharedComputedObject()
},
methods: {
@@ -44,6 +44,7 @@
<template
v-if="profilesExpanded"
>
<div
v-for="profile in settingsProfiles"
:key="profile.id"
@@ -72,24 +73,15 @@
</button>
</template>
</div>
<button
class="btn button-default"
@click="refreshProfiles()"
>
<button class="btn button-default" @click="refreshProfiles()">
{{ $t('settings.settings_profiles_refresh') }}
<FAIcon
icon="sync"
@click="refreshProfiles()"
/>
<FAIcon icon="sync" @click="refreshProfiles()" />
</button>
<h3>{{ $t('settings.settings_profile_creation') }}</h3>
<label for="settings-profile-new-name">
{{ $t('settings.settings_profile_creation_new_name_label') }}
</label>
<input
id="settings-profile-new-name"
v-model="newProfileName"
>
<input v-model="newProfileName" id="settings-profile-new-name">
<button
class="btn button-default"
@click="createSettingsProfile"
@@ -159,16 +151,6 @@
{{ $t('settings.show_page_backgrounds') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="centerAlignBio">
{{ $t('settings.center_align_bio') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="compactUserInfo">
{{ $t('settings.compact_user_info') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }}
@@ -279,11 +261,6 @@
{{ $t('settings.right_sidebar') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="widenTimeline">
{{ $t('settings.widen_timeline') }}
</BooleanSetting>
</li>
<li>
<ChoiceSetting
v-if="user"
@@ -565,18 +542,12 @@
{{ $t('settings.default_vis') }} <ServerSideIndicator :server-side="true" />
<ScopeSelector
class="scope-selector"
:show-all="true"
:user-default="serverSide_defaultScope"
:initial-scope="serverSide_defaultScope"
:on-scope-change="changeDefaultScope"
/>
</label>
</li>
<li>
<BooleanSetting path="minimalScopesMode">
{{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="sensitiveByDefault">
{{ $t('settings.sensitive_by_default') }}
@@ -587,14 +558,6 @@
{{ $t('settings.sensitive_if_subject') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="scopeCopy"
expert="1"
>
{{ $t('settings.scope_copy') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowSubjectInput"
@@ -622,23 +585,6 @@
{{ $t('settings.post_status_content_type') }}
</ChoiceSetting>
</li>
<li>
<ChoiceSetting
id="postLanguage"
path="postLanguage"
:options="postLanguageOptions"
>
{{ $t('settings.post_language') }}
</ChoiceSetting>
</li>
<li>
<BooleanSetting
path="minimalScopesMode"
expert="1"
>
{{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowNewPostButton"
@@ -85,7 +85,7 @@ const MutesAndBlocks = {
// check is it's a local user
if (user && user.is_local) {
// append the instance address
// eslint-disable-next-line no-undef
return user.screen_name + '@' + location.hostname
}
return user.screen_name
@@ -10,7 +10,7 @@
:query="queryUserIds"
:placeholder="$t('settings.search_user_to_block')"
>
<template #default="row">
<template v-slot="row">
<BlockCard
:user-id="row.item"
/>
@@ -21,7 +21,7 @@
:refresh="true"
:get-key="i => i"
>
<template #header="{selected}">
<template v-slot:header="{selected}">
<div class="bulk-actions">
<ProgressButton
v-if="selected.length > 0"
@@ -29,7 +29,7 @@
:click="() => blockUsers(selected)"
>
{{ $t('user_card.block') }}
<template #progress>
<template v-slot:progress>
{{ $t('user_card.block_progress') }}
</template>
</ProgressButton>
@@ -39,16 +39,16 @@
:click="() => unblockUsers(selected)"
>
{{ $t('user_card.unblock') }}
<template #progress>
<template v-slot:progress>
{{ $t('user_card.unblock_progress') }}
</template>
</ProgressButton>
</div>
</template>
<template #item="{item}">
<template v-slot:item="{item}">
<BlockCard :user-id="item" />
</template>
<template #empty>
<template v-slot:empty>
{{ $t('settings.no_blocks') }}
</template>
</BlockList>
@@ -63,7 +63,7 @@
:query="queryUserIds"
:placeholder="$t('settings.search_user_to_mute')"
>
<template #default="row">
<template v-slot="row">
<MuteCard
:user-id="row.item"
/>
@@ -74,7 +74,7 @@
:refresh="true"
:get-key="i => i"
>
<template #header="{selected}">
<template v-slot:header="{selected}">
<div class="bulk-actions">
<ProgressButton
v-if="selected.length > 0"
@@ -82,7 +82,7 @@
:click="() => muteUsers(selected)"
>
{{ $t('user_card.mute') }}
<template #progress>
<template v-slot:progress>
{{ $t('user_card.mute_progress') }}
</template>
</ProgressButton>
@@ -92,16 +92,16 @@
:click="() => unmuteUsers(selected)"
>
{{ $t('user_card.unmute') }}
<template #progress>
<template v-slot:progress>
{{ $t('user_card.unmute_progress') }}
</template>
</ProgressButton>
</div>
</template>
<template #item="{item}">
<template v-slot:item="{item}">
<MuteCard :user-id="item" />
</template>
<template #empty>
<template v-slot:empty>
{{ $t('settings.no_mutes') }}
</template>
</MuteList>
@@ -114,7 +114,7 @@
:query="queryKnownDomains"
:placeholder="$t('settings.type_domains_to_mute')"
>
<template #default="row">
<template v-slot="row">
<DomainMuteCard
:domain="row.item"
/>
@@ -125,7 +125,7 @@
:refresh="true"
:get-key="i => i"
>
<template #header="{selected}">
<template v-slot:header="{selected}">
<div class="bulk-actions">
<ProgressButton
v-if="selected.length > 0"
@@ -133,16 +133,16 @@
:click="() => unmuteDomains(selected)"
>
{{ $t('domain_mute_card.unmute') }}
<template #progress>
<template v-slot:progress>
{{ $t('domain_mute_card.unmute_progress') }}
</template>
</ProgressButton>
</div>
</template>
<template #item="{item}">
<template v-slot:item="{item}">
<DomainMuteCard :domain="item" />
</template>
<template #empty>
<template v-slot:empty>
{{ $t('settings.no_mutes') }}
</template>
</DomainMuteList>
@@ -130,7 +130,7 @@ const ProfileTab = {
note: this.newBio,
locked: this.newLocked,
// Backend notation.
/* eslint-disable camelcase */
display_name: this.newName,
fields_attributes: this.newFields.filter(el => el != null),
bot: this.bot,
@@ -138,7 +138,7 @@ const ProfileTab = {
status_ttl_days: this.expirePosts ? this.newPostTTLDays : -1,
permit_followback: this.permit_followback,
accepts_direct_messages_from: this.userAcceptsDirectMessagesFrom
/* eslint-enable camelcase */
}
if (this.emailLanguage) {
@@ -187,7 +187,7 @@ const ProfileTab = {
})
return
}
// eslint-disable-next-line no-undef
const reader = new FileReader()
reader.onload = ({ target }) => {
const img = target.result
@@ -110,9 +110,11 @@
max="730"
class="expire-posts-days"
:placeholder="$t('settings.expire_posts_input_placeholder')"
>
/>
</p>
<p>
</p>
<p />
<p>
<interface-language-switcher
:prompt-text="$t('settings.email_language')"
@@ -1,25 +1,22 @@
import { extractCommit } from 'src/services/version/version.service'
function joinURL(base, subpath) {
return URL.parse(subpath, base)?.href || "invalid base URL"
}
const pleromaFeCommitUrl = 'https://akkoma.dev/AkkomaGang/pleroma-fe/commit/'
const pleromaBeCommitUrl = 'https://akkoma.dev/AkkomaGang/akkoma/commit/'
const VersionTab = {
data () {
const instance = this.$store.state.instance
return {
backendCommitUrl: instance.backendCommitUrl,
backendVersion: instance.backendVersion,
frontendCommitUrl: instance.frontendCommitUrl,
frontendVersion: instance.frontendVersion
}
},
computed: {
frontendVersionLink () {
return joinURL(this.frontendCommitUrl, this.frontendVersion)
return pleromaFeCommitUrl + this.frontendVersion
},
backendVersionLink () {
return joinURL(this.backendCommitUrl, extractCommit(this.backendVersion))
return pleromaBeCommitUrl + extractCommit(this.backendVersion)
}
}
}
@@ -215,7 +215,7 @@
</div>
</template>
<script src="./shadow_control.js"></script>
<script src="./shadow_control.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
+1 -1
View File
@@ -218,7 +218,7 @@
</div>
</template>
<script src="./side_drawer.js"></script>
<script src="./side_drawer.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
+1 -1
View File
@@ -24,7 +24,7 @@
</div>
</template>
<script src="./staff_panel.js"></script>
<script src="./staff_panel.js" ></script>
<style lang="scss">
-10
View File
@@ -266,16 +266,6 @@
color: $fallback--cGreen;
color: var(--cGreen, $fallback--cGreen);
}
.right-side {
display: flex;
align-items: center;
gap: 0.3em;
}
.repeat-tooltip {
flex-shrink: 0;
}
}
.repeater-avatar {

Some files were not shown because too many files have changed in this diff Show More