Merge remote-tracking branch 'origin/develop' into scrolltotop
* origin/develop: (47 commits) Update dependency eslint-plugin-vue to v9.4.0 Update dependency opn to v5 fix notices being under the navbar, also change offset to use variable fix modals not having proper z index reduce indexes to be below 9999 so that develop error messages appear above Fix react & extra buttons not styled on tab-focus Fix popover not popping up Fix styling on Safari Use :focus-visible instead of :focus for focus markers Optimize Reply badge position Add badges to status interacting buttons Update dependency nightwatch to v2 Update dependency eslint-plugin-n to v15.2.5 Update dependency mocha to v10 Update dependency karma-coverage to v2 Update dependency sass to v1.54.5 Update dependency karma-firefox-launcher to v2 Update dependency vue-template-compiler to v2.7.9 Pin dependencies Refresh yarn.lock ...
This commit is contained in:
commit
4e339d9be3
|
@ -29,18 +29,20 @@ var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||||
})
|
})
|
||||||
|
|
||||||
var hotMiddleware = require('webpack-hot-middleware')(compiler)
|
var hotMiddleware = require('webpack-hot-middleware')(compiler)
|
||||||
// force page reload when html-webpack-plugin template changes
|
|
||||||
compiler.plugin('compilation', function (compilation) {
|
|
||||||
compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
|
||||||
// FIXME: This supposed to reload whole page when index.html is changed,
|
|
||||||
// however now it reloads entire page on every breath, i suppose the order
|
|
||||||
// of plugins changed or something. It's a minor thing and douesn't hurt
|
|
||||||
// disabling it, constant reloads hurt much more
|
|
||||||
|
|
||||||
// hotMiddleware.publish({ action: 'reload' })
|
// FIXME: The statement below gives error about hooks being required in webpack 5.
|
||||||
// cb()
|
// force page reload when html-webpack-plugin template changes
|
||||||
})
|
// compiler.plugin('compilation', function (compilation) {
|
||||||
})
|
// compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) {
|
||||||
|
// // FIXME: This supposed to reload whole page when index.html is changed,
|
||||||
|
// // however now it reloads entire page on every breath, i suppose the order
|
||||||
|
// // of plugins changed or something. It's a minor thing and douesn't hurt
|
||||||
|
// // disabling it, constant reloads hurt much more
|
||||||
|
|
||||||
|
// // hotMiddleware.publish({ action: 'reload' })
|
||||||
|
// // cb()
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
|
||||||
// proxy api requests
|
// proxy api requests
|
||||||
Object.keys(proxyTable).forEach(function (context) {
|
Object.keys(proxyTable).forEach(function (context) {
|
||||||
|
@ -48,7 +50,7 @@ Object.keys(proxyTable).forEach(function (context) {
|
||||||
if (typeof options === 'string') {
|
if (typeof options === 'string') {
|
||||||
options = { target: options }
|
options = { target: options }
|
||||||
}
|
}
|
||||||
app.use(proxyMiddleware(context, options))
|
app.use(proxyMiddleware.createProxyMiddleware(context, options))
|
||||||
})
|
})
|
||||||
|
|
||||||
// handle fallback for HTML5 history API
|
// handle fallback for HTML5 history API
|
||||||
|
|
|
@ -2,7 +2,7 @@ var path = require('path')
|
||||||
var config = require('../config')
|
var config = require('../config')
|
||||||
var utils = require('./utils')
|
var utils = require('./utils')
|
||||||
var projectRoot = path.resolve(__dirname, '../')
|
var projectRoot = path.resolve(__dirname, '../')
|
||||||
var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin')
|
var ServiceWorkerWebpackPlugin = require('serviceworker-webpack5-plugin')
|
||||||
var CopyPlugin = require('copy-webpack-plugin');
|
var CopyPlugin = require('copy-webpack-plugin');
|
||||||
var { VueLoaderPlugin } = require('vue-loader')
|
var { VueLoaderPlugin } = require('vue-loader')
|
||||||
var ESLintPlugin = require('eslint-webpack-plugin');
|
var ESLintPlugin = require('eslint-webpack-plugin');
|
||||||
|
@ -42,6 +42,10 @@ module.exports = {
|
||||||
'assets': path.resolve(__dirname, '../src/assets'),
|
'assets': path.resolve(__dirname, '../src/assets'),
|
||||||
'components': path.resolve(__dirname, '../src/components'),
|
'components': path.resolve(__dirname, '../src/components'),
|
||||||
'vue-i18n': 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js'
|
'vue-i18n': 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js'
|
||||||
|
},
|
||||||
|
fallback: {
|
||||||
|
'querystring': require.resolve('querystring-es3'),
|
||||||
|
'url': require.resolve('url/')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
@ -78,22 +82,16 @@ module.exports = {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
use: {
|
type: 'asset',
|
||||||
loader: 'url-loader',
|
generator: {
|
||||||
options: {
|
filename: utils.assetsPath('img/[name].[hash:7][ext]')
|
||||||
limit: 10000,
|
|
||||||
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
use: {
|
type: 'asset',
|
||||||
loader: 'url-loader',
|
generator: {
|
||||||
options: {
|
filename: utils.assetsPath('fonts/[name].[hash:7][ext]')
|
||||||
limit: 10000,
|
|
||||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -117,9 +115,8 @@ module.exports = {
|
||||||
new CopyPlugin({
|
new CopyPlugin({
|
||||||
patterns: [
|
patterns: [
|
||||||
{
|
{
|
||||||
from: "node_modules/@ruffle-rs/ruffle/*",
|
from: "node_modules/@ruffle-rs/ruffle/**/*",
|
||||||
to: "static/ruffle",
|
to: "static/ruffle/[name][ext]"
|
||||||
flatten: true
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
options: {
|
options: {
|
||||||
|
|
|
@ -16,7 +16,7 @@ module.exports = merge(baseWebpackConfig, {
|
||||||
},
|
},
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
// eval-source-map is faster for development
|
// eval-source-map is faster for development
|
||||||
devtool: '#eval-source-map',
|
devtool: 'eval-source-map',
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
'process.env': config.dev.env,
|
'process.env': config.dev.env,
|
||||||
|
|
|
@ -5,6 +5,7 @@ var webpack = require('webpack')
|
||||||
var merge = require('webpack-merge')
|
var merge = require('webpack-merge')
|
||||||
var baseWebpackConfig = require('./webpack.base.conf')
|
var baseWebpackConfig = require('./webpack.base.conf')
|
||||||
var MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
var MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||||
|
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin")
|
||||||
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
var HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
var env = process.env.NODE_ENV === 'testing'
|
var env = process.env.NODE_ENV === 'testing'
|
||||||
? require('../config/test.env')
|
? require('../config/test.env')
|
||||||
|
@ -19,12 +20,16 @@ var webpackConfig = merge(baseWebpackConfig, {
|
||||||
module: {
|
module: {
|
||||||
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, extract: true })
|
rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, extract: true })
|
||||||
},
|
},
|
||||||
devtool: config.build.productionSourceMap ? '#source-map' : false,
|
devtool: config.build.productionSourceMap ? 'source-map' : false,
|
||||||
optimization: {
|
optimization: {
|
||||||
minimize: true,
|
minimize: true,
|
||||||
splitChunks: {
|
splitChunks: {
|
||||||
chunks: 'all'
|
chunks: 'all'
|
||||||
}
|
},
|
||||||
|
minimizer: [
|
||||||
|
`...`,
|
||||||
|
new CssMinimizerPlugin()
|
||||||
|
]
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
path: config.build.assetsRoot,
|
path: config.build.assetsRoot,
|
||||||
|
@ -60,9 +65,7 @@ var webpackConfig = merge(baseWebpackConfig, {
|
||||||
ignoreCustomComments: [/server-generated-meta/]
|
ignoreCustomComments: [/server-generated-meta/]
|
||||||
// more options:
|
// more options:
|
||||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||||
},
|
}
|
||||||
// necessary to consistently work with multiple chunks via CommonsChunkPlugin
|
|
||||||
chunksSortMode: 'dependency'
|
|
||||||
}),
|
}),
|
||||||
// split vendor js into its own file
|
// split vendor js into its own file
|
||||||
// extract webpack runtime and module manifest to its own file in order to
|
// extract webpack runtime and module manifest to its own file in order to
|
||||||
|
|
56
package.json
56
package.json
|
@ -34,91 +34,91 @@
|
||||||
"escape-html": "1.0.3",
|
"escape-html": "1.0.3",
|
||||||
"js-cookie": "3.0.1",
|
"js-cookie": "3.0.1",
|
||||||
"localforage": "1.10.0",
|
"localforage": "1.10.0",
|
||||||
"parse-link-header": "1.0.1",
|
"parse-link-header": "2.0.0",
|
||||||
"phoenix": "1.6.2",
|
"phoenix": "1.6.2",
|
||||||
"punycode.js": "2.1.0",
|
"punycode.js": "2.1.0",
|
||||||
"qrcode": "1.5.0",
|
"qrcode": "1.5.0",
|
||||||
|
"querystring-es3": "0.2.1",
|
||||||
|
"url": "0.11.0",
|
||||||
"utf8": "3.0.0",
|
"utf8": "3.0.0",
|
||||||
"vue": "3.2.37",
|
"vue": "3.2.37",
|
||||||
"vue-i18n": "9.2.2",
|
"vue-i18n": "9.2.2",
|
||||||
"vue-router": "4.1.3",
|
"vue-router": "4.1.3",
|
||||||
"vue-template-compiler": "2.7.8",
|
"vue-template-compiler": "2.7.9",
|
||||||
"vuex": "4.0.2"
|
"vuex": "4.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.18.10",
|
"@babel/core": "7.18.10",
|
||||||
|
"@babel/eslint-parser": "7.18.9",
|
||||||
"@babel/plugin-transform-runtime": "7.18.10",
|
"@babel/plugin-transform-runtime": "7.18.10",
|
||||||
"@babel/preset-env": "7.18.10",
|
"@babel/preset-env": "7.18.10",
|
||||||
"@babel/register": "7.18.9",
|
"@babel/register": "7.18.9",
|
||||||
"@babel/eslint-parser": "7.18.9",
|
|
||||||
"@intlify/vue-i18n-loader": "5.0.0",
|
"@intlify/vue-i18n-loader": "5.0.0",
|
||||||
"@ungap/event-target": "0.2.3",
|
"@ungap/event-target": "0.2.3",
|
||||||
"@vue/babel-helper-vue-jsx-merge-props": "1.2.1",
|
"@vue/babel-helper-vue-jsx-merge-props": "1.2.1",
|
||||||
"@vue/babel-plugin-jsx": "1.1.1",
|
"@vue/babel-plugin-jsx": "1.1.1",
|
||||||
"@vue/compiler-sfc": "3.2.37",
|
"@vue/compiler-sfc": "3.2.37",
|
||||||
"@vue/test-utils": "2.0.2",
|
"@vue/test-utils": "2.0.2",
|
||||||
"autoprefixer": "6.7.7",
|
"autoprefixer": "10.4.8",
|
||||||
"babel-loader": "8.2.5",
|
"babel-loader": "8.2.5",
|
||||||
"babel-plugin-lodash": "3.3.4",
|
"babel-plugin-lodash": "3.3.4",
|
||||||
"chai": "4.3.6",
|
"chai": "4.3.6",
|
||||||
"chalk": "1.1.3",
|
"chalk": "1.1.3",
|
||||||
"chromedriver": "104.0.0",
|
"chromedriver": "104.0.0",
|
||||||
"connect-history-api-fallback": "2.0.0",
|
"connect-history-api-fallback": "2.0.0",
|
||||||
"copy-webpack-plugin": "6.4.1",
|
"copy-webpack-plugin": "11.0.0",
|
||||||
"cross-spawn": "7.0.3",
|
"cross-spawn": "7.0.3",
|
||||||
"css-loader": "0.28.11",
|
"css-loader": "6.7.1",
|
||||||
|
"css-minimizer-webpack-plugin": "4.0.0",
|
||||||
"custom-event-polyfill": "1.0.7",
|
"custom-event-polyfill": "1.0.7",
|
||||||
"eslint": "8.22.0",
|
"eslint": "8.22.0",
|
||||||
"eslint-config-standard": "17.0.0",
|
"eslint-config-standard": "17.0.0",
|
||||||
"eslint-formatter-friendly": "7.0.0",
|
"eslint-formatter-friendly": "7.0.0",
|
||||||
"eslint-webpack-plugin": "2.7.0",
|
|
||||||
"eslint-plugin-import": "2.26.0",
|
"eslint-plugin-import": "2.26.0",
|
||||||
"eslint-plugin-n": "15.2.4",
|
"eslint-plugin-n": "15.2.5",
|
||||||
"eslint-plugin-promise": "6.0.0",
|
"eslint-plugin-promise": "6.0.0",
|
||||||
"eslint-plugin-vue": "9.3.0",
|
"eslint-plugin-vue": "9.4.0",
|
||||||
|
"eslint-webpack-plugin": "3.2.0",
|
||||||
"eventsource-polyfill": "0.9.6",
|
"eventsource-polyfill": "0.9.6",
|
||||||
"express": "4.18.1",
|
"express": "4.18.1",
|
||||||
"file-loader": "3.0.1",
|
|
||||||
"function-bind": "1.1.1",
|
"function-bind": "1.1.1",
|
||||||
"html-webpack-plugin": "3.2.0",
|
"html-webpack-plugin": "5.5.0",
|
||||||
"http-proxy-middleware": "0.21.0",
|
"http-proxy-middleware": "2.0.6",
|
||||||
"inject-loader": "2.0.1",
|
|
||||||
"iso-639-1": "2.1.15",
|
"iso-639-1": "2.1.15",
|
||||||
"isparta-loader": "2.0.0",
|
"isparta-loader": "2.0.0",
|
||||||
"json-loader": "0.5.7",
|
"json-loader": "0.5.7",
|
||||||
"karma": "6.4.0",
|
"karma": "6.4.0",
|
||||||
"karma-coverage": "1.1.2",
|
"karma-coverage": "2.2.0",
|
||||||
"karma-firefox-launcher": "1.3.0",
|
"karma-firefox-launcher": "2.1.2",
|
||||||
"karma-mocha": "2.0.1",
|
"karma-mocha": "2.0.1",
|
||||||
"karma-mocha-reporter": "2.2.5",
|
"karma-mocha-reporter": "2.2.5",
|
||||||
"karma-sinon-chai": "2.0.2",
|
"karma-sinon-chai": "2.0.2",
|
||||||
"karma-sourcemap-loader": "0.3.8",
|
"karma-sourcemap-loader": "0.3.8",
|
||||||
"karma-spec-reporter": "0.0.34",
|
"karma-spec-reporter": "0.0.34",
|
||||||
"karma-webpack": "4.0.2",
|
"karma-webpack": "5.0.0",
|
||||||
"lodash": "4.17.21",
|
"lodash": "4.17.21",
|
||||||
"lolex": "1.6.0",
|
"lolex": "1.6.0",
|
||||||
"mini-css-extract-plugin": "0.12.0",
|
"mini-css-extract-plugin": "2.6.1",
|
||||||
"mocha": "3.5.3",
|
"mocha": "10.0.0",
|
||||||
"nightwatch": "0.9.21",
|
"nightwatch": "2.3.3",
|
||||||
"opn": "4.0.2",
|
"opn": "5.5.0",
|
||||||
"ora": "0.4.1",
|
"ora": "0.4.1",
|
||||||
"postcss-loader": "3.0.0",
|
"postcss": "8.4.16",
|
||||||
"raw-loader": "0.5.1",
|
"postcss-loader": "7.0.1",
|
||||||
"sass": "1.54.4",
|
"sass": "1.54.5",
|
||||||
"sass-loader": "7.3.1",
|
"sass-loader": "13.0.2",
|
||||||
"selenium-server": "2.53.1",
|
"selenium-server": "2.53.1",
|
||||||
"semver": "5.7.1",
|
"semver": "5.7.1",
|
||||||
"serviceworker-webpack-plugin": "1.0.1",
|
"serviceworker-webpack5-plugin": "2.0.0",
|
||||||
"shelljs": "0.8.5",
|
"shelljs": "0.8.5",
|
||||||
"sinon": "2.4.1",
|
"sinon": "2.4.1",
|
||||||
"sinon-chai": "2.14.0",
|
"sinon-chai": "2.14.0",
|
||||||
"stylelint": "13.13.1",
|
"stylelint": "13.13.1",
|
||||||
"stylelint-config-standard": "20.0.0",
|
"stylelint-config-standard": "20.0.0",
|
||||||
"stylelint-rscss": "0.4.0",
|
"stylelint-rscss": "0.4.0",
|
||||||
"url-loader": "1.1.2",
|
"vue-loader": "17.0.0",
|
||||||
"vue-loader": "16.8.3",
|
|
||||||
"vue-style-loader": "4.1.3",
|
"vue-style-loader": "4.1.3",
|
||||||
"webpack": "4.46.0",
|
"webpack": "5.74.0",
|
||||||
"webpack-dev-middleware": "3.7.3",
|
"webpack-dev-middleware": "3.7.3",
|
||||||
"webpack-hot-middleware": "2.25.2",
|
"webpack-hot-middleware": "2.25.2",
|
||||||
"webpack-merge": "0.20.0"
|
"webpack-merge": "0.20.0"
|
||||||
|
|
|
@ -60,6 +60,13 @@ export default {
|
||||||
'-' + this.layoutType
|
'-' + this.layoutType
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
navClasses () {
|
||||||
|
const { navbarColumnStretch } = this.$store.getters.mergedConfig
|
||||||
|
return [
|
||||||
|
'-' + this.layoutType,
|
||||||
|
...(navbarColumnStretch ? ['-column-stretch'] : [])
|
||||||
|
]
|
||||||
|
},
|
||||||
currentUser () { return this.$store.state.users.currentUser },
|
currentUser () { return this.$store.state.users.currentUser },
|
||||||
userBackground () { return this.currentUser.background_image },
|
userBackground () { return this.currentUser.background_image },
|
||||||
instanceBackground () {
|
instanceBackground () {
|
||||||
|
|
41
src/App.scss
41
src/App.scss
|
@ -5,12 +5,12 @@
|
||||||
--navbar-height: 3.5rem;
|
--navbar-height: 3.5rem;
|
||||||
--post-line-height: 1.4;
|
--post-line-height: 1.4;
|
||||||
// Z-Index stuff
|
// Z-Index stuff
|
||||||
--ZI_media_modal: 90000;
|
--ZI_media_modal: 9000;
|
||||||
--ZI_modals_popovers: 85000;
|
--ZI_modals_popovers: 8500;
|
||||||
--ZI_modals: 80000;
|
--ZI_modals: 8000;
|
||||||
--ZI_navbar_popovers: 75000;
|
--ZI_navbar_popovers: 7500;
|
||||||
--ZI_navbar: 70000;
|
--ZI_navbar: 7000;
|
||||||
--ZI_popovers: 60000;
|
--ZI_popovers: 6000;
|
||||||
}
|
}
|
||||||
|
|
||||||
html {
|
html {
|
||||||
|
@ -141,6 +141,11 @@ nav {
|
||||||
grid-area: sidebar;
|
grid-area: sidebar;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#modal {
|
||||||
|
position: absolute;
|
||||||
|
z-index: var(--ZI_modals);
|
||||||
|
}
|
||||||
|
|
||||||
.column.-scrollable {
|
.column.-scrollable {
|
||||||
top: var(--navbar-height);
|
top: var(--navbar-height);
|
||||||
position: sticky;
|
position: sticky;
|
||||||
|
@ -182,13 +187,18 @@ nav {
|
||||||
|
|
||||||
.app-layout {
|
.app-layout {
|
||||||
--miniColumn: 25rem;
|
--miniColumn: 25rem;
|
||||||
--maxiColumn: minmax(var(--miniColumn), 45rem);
|
--maxiColumn: 45rem;
|
||||||
--columnGap: 1em;
|
--columnGap: 1em;
|
||||||
--status-margin: 0.75em;
|
--status-margin: 0.75em;
|
||||||
|
--effectiveSidebarColumnWidth: minmax(var(--miniColumn), var(--sidebarColumnWidth, var(--miniColumn)));
|
||||||
|
--effectiveNotifsColumnWidth: minmax(var(--miniColumn), var(--notifsColumnWidth, var(--miniColumn)));
|
||||||
|
--effectiveContentColumnWidth: minmax(var(--miniColumn), var(--contentColumnWidth, var(--maxiColumn)));
|
||||||
|
|
||||||
position: relative;
|
position: relative;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: var(--miniColumn) var(--maxiColumn);
|
grid-template-columns:
|
||||||
|
var(--effectiveSidebarColumnWidth)
|
||||||
|
var(--effectiveContentColumnWidth);
|
||||||
grid-template-areas: "sidebar content";
|
grid-template-areas: "sidebar content";
|
||||||
grid-template-rows: 1fr;
|
grid-template-rows: 1fr;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
@ -282,15 +292,24 @@ nav {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-reverse:not(.-wide):not(.-mobile) {
|
&.-reverse:not(.-wide):not(.-mobile) {
|
||||||
grid-template-columns: var(--maxiColumn) var(--miniColumn);
|
grid-template-columns:
|
||||||
|
var(--effectiveContentColumnWidth)
|
||||||
|
var(--effectiveSidebarColumnWidth);
|
||||||
grid-template-areas: "content sidebar";
|
grid-template-areas: "content sidebar";
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-wide {
|
&.-wide {
|
||||||
grid-template-columns: var(--miniColumn) var(--maxiColumn) var(--miniColumn);
|
grid-template-columns:
|
||||||
|
var(--effectiveSidebarColumnWidth)
|
||||||
|
var(--effectiveContentColumnWidth)
|
||||||
|
var(--effectiveNotifsColumnWidth);
|
||||||
grid-template-areas: "sidebar content notifs";
|
grid-template-areas: "sidebar content notifs";
|
||||||
|
|
||||||
&.-reverse {
|
&.-reverse {
|
||||||
|
grid-template-columns:
|
||||||
|
var(--effectiveNotifsColumnWidth)
|
||||||
|
var(--effectiveContentColumnWidth)
|
||||||
|
var(--effectiveSidebarColumnWidth);
|
||||||
grid-template-areas: "notifs content sidebar";
|
grid-template-areas: "notifs content sidebar";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -752,7 +771,7 @@ option {
|
||||||
}
|
}
|
||||||
|
|
||||||
.fa-old-padding {
|
.fa-old-padding {
|
||||||
&.svg-inline--fa {
|
&.svg-inline--fa, &-layer {
|
||||||
padding: 0 0.3em;
|
padding: 0 0.3em;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,10 @@
|
||||||
class="app-bg-wrapper"
|
class="app-bg-wrapper"
|
||||||
/>
|
/>
|
||||||
<MobileNav v-if="layoutType === 'mobile'" />
|
<MobileNav v-if="layoutType === 'mobile'" />
|
||||||
<DesktopNav v-else />
|
<DesktopNav
|
||||||
|
v-else
|
||||||
|
:class="navClasses"
|
||||||
|
/>
|
||||||
<Notifications v-if="currentUser" />
|
<Notifications v-if="currentUser" />
|
||||||
<div
|
<div
|
||||||
id="content"
|
id="content"
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
@mixin unfocused-style {
|
||||||
|
@content;
|
||||||
|
|
||||||
|
&:focus:not(:focus-visible):not(:hover) {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@mixin focused-style {
|
||||||
|
&:hover, &:focus {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus-visible {
|
||||||
|
@content;
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,7 +12,7 @@ import { windowWidth, windowHeight } from '../services/window_utils/window_utils
|
||||||
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
|
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 { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
||||||
import { applyTheme } from '../services/style_setter/style_setter.js'
|
import { applyTheme, 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'
|
||||||
|
|
||||||
let staticInitialResults = null
|
let staticInitialResults = null
|
||||||
|
@ -360,6 +360,8 @@ const afterStoreSetup = async ({ store, i18n }) => {
|
||||||
console.error('Failed to load any theme!')
|
console.error('Failed to load any theme!')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applyConfig(store.state.config)
|
||||||
|
|
||||||
// Now we can try getting the server settings and logging in
|
// Now we can try getting the server settings and logging in
|
||||||
// Most of these are preloaded into the index.html so blocking is minimized
|
// Most of these are preloaded into the index.html so blocking is minimized
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
|
|
@ -61,7 +61,7 @@ export default (store) => {
|
||||||
component: RemoteUserResolver,
|
component: RemoteUserResolver,
|
||||||
beforeEnter: validateAuthenticatedRoute
|
beforeEnter: validateAuthenticatedRoute
|
||||||
},
|
},
|
||||||
{ name: 'external-user-profile', path: '/users/:id', component: UserProfile },
|
{ name: 'external-user-profile', path: '/users/$:id', component: UserProfile },
|
||||||
{ name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute },
|
{ name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute },
|
{ name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'registration', path: '/registration', component: Registration },
|
{ name: 'registration', path: '/registration', component: Registration },
|
||||||
|
@ -75,7 +75,8 @@ export default (store) => {
|
||||||
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
|
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
|
||||||
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
|
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'about', path: '/about', component: About },
|
{ name: 'about', path: '/about', component: About },
|
||||||
{ name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile },
|
{ name: 'user-profile', path: '/users/:name', component: UserProfile },
|
||||||
|
{ name: 'legacy-user-profile', path: '/:name', component: UserProfile },
|
||||||
{ name: 'lists', path: '/lists', component: Lists },
|
{ name: 'lists', path: '/lists', component: Lists },
|
||||||
{ name: 'lists-timeline', path: '/lists/:id', component: ListsTimeline },
|
{ name: 'lists-timeline', path: '/lists/:id', component: ListsTimeline },
|
||||||
{ name: 'lists-edit', path: '/lists/:id/edit', component: ListsEdit }
|
{ name: 'lists-edit', path: '/lists/:id/edit', component: ListsEdit }
|
||||||
|
|
|
@ -23,6 +23,26 @@
|
||||||
max-width: 980px;
|
max-width: 980px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.-column-stretch .inner-nav {
|
||||||
|
--miniColumn: 25rem;
|
||||||
|
--maxiColumn: 45rem;
|
||||||
|
--columnGap: 1em;
|
||||||
|
max-width: calc(
|
||||||
|
var(--sidebarColumnWidth, var(--miniColumn)) +
|
||||||
|
var(--contentColumnWidth, var(--maxiColumn)) +
|
||||||
|
var(--columnGap)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.-column-stretch.-wide .inner-nav {
|
||||||
|
max-width: calc(
|
||||||
|
var(--sidebarColumnWidth, var(--miniColumn)) +
|
||||||
|
var(--contentColumnWidth, var(--maxiColumn)) +
|
||||||
|
var(--notifsColumnWidth, var(--miniColumn)) +
|
||||||
|
var(--columnGap)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
&.-logoLeft .inner-nav {
|
&.-logoLeft .inner-nav {
|
||||||
grid-template-columns: auto 2fr 2fr;
|
grid-template-columns: auto 2fr 2fr;
|
||||||
grid-template-areas: "logo sitename actions";
|
grid-template-areas: "logo sitename actions";
|
||||||
|
|
|
@ -6,7 +6,9 @@ import {
|
||||||
faEyeSlash,
|
faEyeSlash,
|
||||||
faThumbtack,
|
faThumbtack,
|
||||||
faShareAlt,
|
faShareAlt,
|
||||||
faExternalLinkAlt
|
faExternalLinkAlt,
|
||||||
|
faPlus,
|
||||||
|
faTimes
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import {
|
import {
|
||||||
faBookmark as faBookmarkReg,
|
faBookmark as faBookmarkReg,
|
||||||
|
@ -21,13 +23,26 @@ library.add(
|
||||||
faThumbtack,
|
faThumbtack,
|
||||||
faShareAlt,
|
faShareAlt,
|
||||||
faExternalLinkAlt,
|
faExternalLinkAlt,
|
||||||
faFlag
|
faFlag,
|
||||||
|
faPlus,
|
||||||
|
faTimes
|
||||||
)
|
)
|
||||||
|
|
||||||
const ExtraButtons = {
|
const ExtraButtons = {
|
||||||
props: ['status'],
|
props: ['status'],
|
||||||
components: { Popover },
|
components: { Popover },
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
expanded: false
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
onShow () {
|
||||||
|
this.expanded = true
|
||||||
|
},
|
||||||
|
onClose () {
|
||||||
|
this.expanded = false
|
||||||
|
},
|
||||||
deleteStatus () {
|
deleteStatus () {
|
||||||
const confirmed = window.confirm(this.$t('status.delete_confirm'))
|
const confirmed = window.confirm(this.$t('status.delete_confirm'))
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
:offset="{ y: 5 }"
|
:offset="{ y: 5 }"
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
remove-padding
|
remove-padding
|
||||||
|
@show="onShow"
|
||||||
|
@close="onClose"
|
||||||
>
|
>
|
||||||
<template #content="{close}">
|
<template #content="{close}">
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
|
@ -122,10 +124,24 @@
|
||||||
</template>
|
</template>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<span class="button-unstyled popover-trigger">
|
<span class="button-unstyled popover-trigger">
|
||||||
|
<FALayers class="fa-old-padding-layer">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 "
|
||||||
icon="ellipsis-h"
|
icon="ellipsis-h"
|
||||||
/>
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-show="!expanded"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-8 right-16"
|
||||||
|
icon="plus"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-show="expanded"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-8 right-16"
|
||||||
|
icon="times"
|
||||||
|
/>
|
||||||
|
</FALayers>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
@ -135,6 +151,7 @@
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
@import '../../_mixins.scss';
|
||||||
|
|
||||||
.ExtraButtons {
|
.ExtraButtons {
|
||||||
/* override of popover internal stuff */
|
/* override of popover internal stuff */
|
||||||
|
@ -151,6 +168,21 @@
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--text, $fallback--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-trigger-button {
|
||||||
|
@include unfocused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include focused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,13 +1,21 @@
|
||||||
import { mapGetters } from 'vuex'
|
import { mapGetters } from 'vuex'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faStar } from '@fortawesome/free-solid-svg-icons'
|
import {
|
||||||
|
faStar,
|
||||||
|
faPlus,
|
||||||
|
faMinus,
|
||||||
|
faCheck
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
import {
|
import {
|
||||||
faStar as faStarRegular
|
faStar as faStarRegular
|
||||||
} from '@fortawesome/free-regular-svg-icons'
|
} from '@fortawesome/free-regular-svg-icons'
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faStar,
|
faStar,
|
||||||
faStarRegular
|
faStarRegular,
|
||||||
|
faPlus,
|
||||||
|
faMinus,
|
||||||
|
faCheck
|
||||||
)
|
)
|
||||||
|
|
||||||
const FavoriteButton = {
|
const FavoriteButton = {
|
||||||
|
|
|
@ -7,11 +7,31 @@
|
||||||
:title="$t('tool_tip.favorite')"
|
:title="$t('tool_tip.favorite')"
|
||||||
@click.prevent="favorite()"
|
@click.prevent="favorite()"
|
||||||
>
|
>
|
||||||
|
<FALayers class="fa-scale-110 fa-old-padding-layer">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110"
|
||||||
:icon="[status.favorited ? 'fas' : 'far', 'star']"
|
:icon="[status.favorited ? 'fas' : 'far', 'star']"
|
||||||
:spin="animated"
|
:spin="animated"
|
||||||
/>
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-if="status.favorited"
|
||||||
|
class="active-marker"
|
||||||
|
transform="shrink-6 up-9 right-12"
|
||||||
|
icon="check"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-if="!status.favorited"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9 right-12"
|
||||||
|
icon="plus"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-else
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9 right-12"
|
||||||
|
icon="minus"
|
||||||
|
/>
|
||||||
|
</FALayers>
|
||||||
</button>
|
</button>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -33,6 +53,7 @@
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
@import '../../_mixins.scss';
|
||||||
|
|
||||||
.FavoriteButton {
|
.FavoriteButton {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -57,6 +78,26 @@
|
||||||
color: $fallback--cOrange;
|
color: $fallback--cOrange;
|
||||||
color: var(--cOrange, $fallback--cOrange);
|
color: var(--cOrange, $fallback--cOrange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include unfocused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include focused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -29,10 +29,10 @@
|
||||||
|
|
||||||
.global-notice-list {
|
.global-notice-list {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50px;
|
top: calc(var(--navbar-height) + 0.5em);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: var(--ZI_popovers);
|
z-index: var(--ZI_navbar_popovers);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
|
@ -1,15 +1,21 @@
|
||||||
import Popover from '../popover/popover.vue'
|
import Popover from '../popover/popover.vue'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
import { faPlus, faTimes } from '@fortawesome/free-solid-svg-icons'
|
||||||
import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
|
import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
|
||||||
import { trim } from 'lodash'
|
import { trim } from 'lodash'
|
||||||
|
|
||||||
library.add(faSmileBeam)
|
library.add(
|
||||||
|
faPlus,
|
||||||
|
faTimes,
|
||||||
|
faSmileBeam
|
||||||
|
)
|
||||||
|
|
||||||
const ReactButton = {
|
const ReactButton = {
|
||||||
props: ['status'],
|
props: ['status'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
filterWord: ''
|
filterWord: '',
|
||||||
|
expanded: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -25,6 +31,13 @@ const ReactButton = {
|
||||||
}
|
}
|
||||||
close()
|
close()
|
||||||
},
|
},
|
||||||
|
onShow () {
|
||||||
|
this.expanded = true
|
||||||
|
this.focusInput()
|
||||||
|
},
|
||||||
|
onClose () {
|
||||||
|
this.expanded = false
|
||||||
|
},
|
||||||
focusInput () {
|
focusInput () {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const input = this.$el.querySelector('input')
|
const input = this.$el.querySelector('input')
|
||||||
|
|
|
@ -7,7 +7,8 @@
|
||||||
:bound-to="{ x: 'container' }"
|
:bound-to="{ x: 'container' }"
|
||||||
remove-padding
|
remove-padding
|
||||||
popover-class="ReactButton popover-default"
|
popover-class="ReactButton popover-default"
|
||||||
@show="focusInput"
|
@show="onShow"
|
||||||
|
@close="onClose"
|
||||||
>
|
>
|
||||||
<template #content="{close}">
|
<template #content="{close}">
|
||||||
<div class="reaction-picker-filter">
|
<div class="reaction-picker-filter">
|
||||||
|
@ -46,10 +47,24 @@
|
||||||
class="button-unstyled popover-trigger"
|
class="button-unstyled popover-trigger"
|
||||||
:title="$t('tool_tip.add_reaction')"
|
:title="$t('tool_tip.add_reaction')"
|
||||||
>
|
>
|
||||||
|
<FALayers>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110 fa-old-padding"
|
||||||
:icon="['far', 'smile-beam']"
|
:icon="['far', 'smile-beam']"
|
||||||
/>
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-show="!expanded"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9 right-17"
|
||||||
|
icon="plus"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-show="expanded"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9 right-17"
|
||||||
|
icon="times"
|
||||||
|
/>
|
||||||
|
</FALayers>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
@ -59,6 +74,7 @@
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
@import '../../_mixins.scss';
|
||||||
|
|
||||||
.ReactButton {
|
.ReactButton {
|
||||||
.reaction-picker-filter {
|
.reaction-picker-filter {
|
||||||
|
@ -125,6 +141,21 @@
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--text, $fallback--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-trigger-button {
|
||||||
|
@include unfocused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include focused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,15 @@
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faReply } from '@fortawesome/free-solid-svg-icons'
|
import {
|
||||||
|
faReply,
|
||||||
|
faPlus,
|
||||||
|
faTimes
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
library.add(faReply)
|
library.add(
|
||||||
|
faReply,
|
||||||
|
faPlus,
|
||||||
|
faTimes
|
||||||
|
)
|
||||||
|
|
||||||
const ReplyButton = {
|
const ReplyButton = {
|
||||||
name: 'ReplyButton',
|
name: 'ReplyButton',
|
||||||
|
|
|
@ -7,10 +7,24 @@
|
||||||
:title="$t('tool_tip.reply')"
|
:title="$t('tool_tip.reply')"
|
||||||
@click.prevent="$emit('toggle')"
|
@click.prevent="$emit('toggle')"
|
||||||
>
|
>
|
||||||
|
<FALayers class="fa-old-padding-layer">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110"
|
||||||
icon="reply"
|
icon="reply"
|
||||||
/>
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-if="!replying"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-8 right-11"
|
||||||
|
icon="plus"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-else
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-8 right-11"
|
||||||
|
icon="times"
|
||||||
|
/>
|
||||||
|
</FALayers>
|
||||||
</button>
|
</button>
|
||||||
<span v-else>
|
<span v-else>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -32,6 +46,7 @@
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
@import '../../_mixins.scss';
|
||||||
|
|
||||||
.ReplyButton {
|
.ReplyButton {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -52,6 +67,18 @@
|
||||||
color: $fallback--cBlue;
|
color: $fallback--cBlue;
|
||||||
color: var(--cBlue, $fallback--cBlue);
|
color: var(--cBlue, $fallback--cBlue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include unfocused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include focused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,17 @@
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { faRetweet } from '@fortawesome/free-solid-svg-icons'
|
import {
|
||||||
|
faRetweet,
|
||||||
|
faPlus,
|
||||||
|
faMinus,
|
||||||
|
faCheck
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
library.add(faRetweet)
|
library.add(
|
||||||
|
faRetweet,
|
||||||
|
faPlus,
|
||||||
|
faMinus,
|
||||||
|
faCheck
|
||||||
|
)
|
||||||
|
|
||||||
const RetweetButton = {
|
const RetweetButton = {
|
||||||
props: ['status', 'loggedIn', 'visibility'],
|
props: ['status', 'loggedIn', 'visibility'],
|
||||||
|
|
|
@ -7,11 +7,31 @@
|
||||||
:title="$t('tool_tip.repeat')"
|
:title="$t('tool_tip.repeat')"
|
||||||
@click.prevent="retweet()"
|
@click.prevent="retweet()"
|
||||||
>
|
>
|
||||||
|
<FALayers class="fa-old-padding-layer">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="fa-scale-110 fa-old-padding"
|
class="fa-scale-110"
|
||||||
icon="retweet"
|
icon="retweet"
|
||||||
:spin="animated"
|
:spin="animated"
|
||||||
/>
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-if="status.repeated"
|
||||||
|
class="active-marker"
|
||||||
|
transform="shrink-6 up-9 right-12"
|
||||||
|
icon="check"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-if="!status.repeated"
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9 right-12"
|
||||||
|
icon="plus"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-else
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9 right-12"
|
||||||
|
icon="minus"
|
||||||
|
/>
|
||||||
|
</FALayers>
|
||||||
</button>
|
</button>
|
||||||
<span v-else-if="loggedIn">
|
<span v-else-if="loggedIn">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
|
@ -40,6 +60,7 @@
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
@import '../../_mixins.scss';
|
||||||
|
|
||||||
.RetweetButton {
|
.RetweetButton {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -64,6 +85,26 @@
|
||||||
color: $fallback--cGreen;
|
color: $fallback--cGreen;
|
||||||
color: var(--cGreen, $fallback--cGreen);
|
color: var(--cGreen, $fallback--cGreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@include unfocused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include focused-style {
|
||||||
|
.focus-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -42,6 +42,9 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
update (e) {
|
update (e) {
|
||||||
set(this.$parent, this.path, e)
|
set(this.$parent, this.path, e)
|
||||||
|
},
|
||||||
|
reset () {
|
||||||
|
set(this.$parent, this.path, this.defaultState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,12 @@
|
||||||
<slot />
|
<slot />
|
||||||
</span>
|
</span>
|
||||||
{{ ' ' }}
|
{{ ' ' }}
|
||||||
<ModifiedIndicator :changed="isChanged" /><ServerSideIndicator :server-side="isServerSide" /> </Checkbox>
|
<ModifiedIndicator
|
||||||
|
:changed="isChanged"
|
||||||
|
:onclick="reset"
|
||||||
|
/>
|
||||||
|
<ServerSideIndicator :server-side="isServerSide" />
|
||||||
|
</Checkbox>
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,9 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
update (e) {
|
update (e) {
|
||||||
set(this.$parent, this.path, e)
|
set(this.$parent, this.path, e)
|
||||||
|
},
|
||||||
|
reset () {
|
||||||
|
set(this.$parent, this.path, this.defaultState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,10 @@
|
||||||
{{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }}
|
{{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }}
|
||||||
</option>
|
</option>
|
||||||
</Select>
|
</Select>
|
||||||
<ModifiedIndicator :changed="isChanged" />
|
<ModifiedIndicator
|
||||||
|
:changed="isChanged"
|
||||||
|
:onclick="reset"
|
||||||
|
/>
|
||||||
<ServerSideIndicator :server-side="isServerSide" />
|
<ServerSideIndicator :server-side="isServerSide" />
|
||||||
</label>
|
</label>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -36,6 +36,9 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
update (e) {
|
update (e) {
|
||||||
set(this.$parent, this.path, parseInt(e.target.value))
|
set(this.$parent, this.path, parseInt(e.target.value))
|
||||||
|
},
|
||||||
|
reset () {
|
||||||
|
set(this.$parent, this.path, this.defaultState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,10 @@
|
||||||
@change="update"
|
@change="update"
|
||||||
>
|
>
|
||||||
{{ ' ' }}
|
{{ ' ' }}
|
||||||
<ModifiedIndicator :changed="isChanged" />
|
<ModifiedIndicator
|
||||||
|
:changed="isChanged"
|
||||||
|
:onclick="reset"
|
||||||
|
/>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
import { get, set } from 'lodash'
|
||||||
|
import ModifiedIndicator from './modified_indicator.vue'
|
||||||
|
import Select from 'src/components/select/select.vue'
|
||||||
|
|
||||||
|
export const allCssUnits = ['cm', 'mm', 'in', 'px', 'pt', 'pc', 'em', 'ex', 'ch', 'rem', 'vw', 'vh', 'vmin', 'vmax', '%']
|
||||||
|
export const defaultHorizontalUnits = ['px', 'rem', 'vw']
|
||||||
|
export const defaultVerticalUnits = ['px', 'rem', 'vh']
|
||||||
|
|
||||||
|
export default {
|
||||||
|
components: {
|
||||||
|
ModifiedIndicator,
|
||||||
|
Select
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
path: String,
|
||||||
|
disabled: Boolean,
|
||||||
|
min: Number,
|
||||||
|
units: {
|
||||||
|
type: [String],
|
||||||
|
default: () => allCssUnits
|
||||||
|
},
|
||||||
|
expert: [Number, String]
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
pathDefault () {
|
||||||
|
const [firstSegment, ...rest] = this.path.split('.')
|
||||||
|
return [firstSegment + 'DefaultValue', ...rest].join('.')
|
||||||
|
},
|
||||||
|
stateUnit () {
|
||||||
|
return (this.state || '').replace(/\d+/, '')
|
||||||
|
},
|
||||||
|
stateValue () {
|
||||||
|
return (this.state || '').replace(/\D+/, '')
|
||||||
|
},
|
||||||
|
state () {
|
||||||
|
const value = get(this.$parent, this.path)
|
||||||
|
if (value === undefined) {
|
||||||
|
return this.defaultState
|
||||||
|
} else {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
},
|
||||||
|
defaultState () {
|
||||||
|
return get(this.$parent, this.pathDefault)
|
||||||
|
},
|
||||||
|
isChanged () {
|
||||||
|
return this.state !== this.defaultState
|
||||||
|
},
|
||||||
|
matchesExpertLevel () {
|
||||||
|
return (this.expert || 0) <= this.$parent.expertLevel
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
update (e) {
|
||||||
|
set(this.$parent, this.path, e)
|
||||||
|
},
|
||||||
|
reset () {
|
||||||
|
set(this.$parent, this.path, this.defaultState)
|
||||||
|
},
|
||||||
|
updateValue (e) {
|
||||||
|
set(this.$parent, this.path, parseInt(e.target.value) + this.stateUnit)
|
||||||
|
},
|
||||||
|
updateUnit (e) {
|
||||||
|
set(this.$parent, this.path, this.stateValue + e.target.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
<template>
|
||||||
|
<span
|
||||||
|
v-if="matchesExpertLevel"
|
||||||
|
class="SizeSetting"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
:for="path"
|
||||||
|
class="size-label"
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
:id="path"
|
||||||
|
class="number-input"
|
||||||
|
type="number"
|
||||||
|
step="1"
|
||||||
|
:disabled="disabled"
|
||||||
|
:min="min || 0"
|
||||||
|
:value="stateValue"
|
||||||
|
@change="updateValue"
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
:id="path"
|
||||||
|
:model-value="stateUnit"
|
||||||
|
:disabled="disabled"
|
||||||
|
class="css-unit-input"
|
||||||
|
@change="updateUnit"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
v-for="option in units"
|
||||||
|
:key="option"
|
||||||
|
:value="option"
|
||||||
|
>
|
||||||
|
{{ option }}
|
||||||
|
</option>
|
||||||
|
</Select>
|
||||||
|
{{ ' ' }}
|
||||||
|
<ModifiedIndicator
|
||||||
|
:changed="isChanged"
|
||||||
|
:onclick="reset"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./size_setting.js"></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.css-unit-input, .css-unit-input select {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
width: 4em !important;
|
||||||
|
max-width: 4em !important;
|
||||||
|
min-width: 4em !important;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -2,6 +2,7 @@ import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||||
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
|
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
|
||||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||||
|
import SizeSetting, { defaultHorizontalUnits } from '../helpers/size_setting.vue'
|
||||||
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
|
||||||
|
|
||||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
import SharedComputedObject from '../helpers/shared_computed_object.js'
|
||||||
|
@ -43,6 +44,11 @@ const GeneralTab = {
|
||||||
value: mode,
|
value: mode,
|
||||||
label: this.$t(`settings.third_column_mode_${mode}`)
|
label: this.$t(`settings.third_column_mode_${mode}`)
|
||||||
})),
|
})),
|
||||||
|
userPopoverAvatarActionOptions: ['close', 'zoom', 'open'].map(mode => ({
|
||||||
|
key: mode,
|
||||||
|
value: mode,
|
||||||
|
label: this.$t(`settings.user_popover_avatar_action_${mode}`)
|
||||||
|
})),
|
||||||
loopSilentAvailable:
|
loopSilentAvailable:
|
||||||
// Firefox
|
// Firefox
|
||||||
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
|
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
|
||||||
|
@ -56,11 +62,15 @@ const GeneralTab = {
|
||||||
BooleanSetting,
|
BooleanSetting,
|
||||||
ChoiceSetting,
|
ChoiceSetting,
|
||||||
IntegerSetting,
|
IntegerSetting,
|
||||||
|
SizeSetting,
|
||||||
InterfaceLanguageSwitcher,
|
InterfaceLanguageSwitcher,
|
||||||
ScopeSelector,
|
ScopeSelector,
|
||||||
ServerSideIndicator
|
ServerSideIndicator
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
horizontalUnits () {
|
||||||
|
return defaultHorizontalUnits
|
||||||
|
},
|
||||||
postFormats () {
|
postFormats () {
|
||||||
return this.$store.state.instance.postFormats || []
|
return this.$store.state.instance.postFormats || []
|
||||||
},
|
},
|
||||||
|
@ -71,6 +81,17 @@ const GeneralTab = {
|
||||||
label: this.$t(`post_status.content_type["${format}"]`)
|
label: this.$t(`post_status.content_type["${format}"]`)
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
columns () {
|
||||||
|
const mode = this.$store.getters.mergedConfig.thirdColumnMode
|
||||||
|
|
||||||
|
const notif = mode === 'none' ? [] : ['notifs']
|
||||||
|
|
||||||
|
if (this.$store.getters.mergedConfig.sidebarRight || mode === 'postform') {
|
||||||
|
return [...notif, 'content', 'sidebar']
|
||||||
|
} else {
|
||||||
|
return ['sidebar', 'content', ...notif]
|
||||||
|
}
|
||||||
|
},
|
||||||
instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel },
|
instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel },
|
||||||
instanceWallpaperUsed () {
|
instanceWallpaperUsed () {
|
||||||
return this.$store.state.instance.background &&
|
return this.$store.state.instance.background &&
|
||||||
|
|
|
@ -15,11 +15,6 @@
|
||||||
{{ $t('settings.hide_isp') }}
|
{{ $t('settings.hide_isp') }}
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<BooleanSetting path="sidebarRight">
|
|
||||||
{{ $t('settings.right_sidebar') }}
|
|
||||||
</BooleanSetting>
|
|
||||||
</li>
|
|
||||||
<li v-if="instanceWallpaperUsed">
|
<li v-if="instanceWallpaperUsed">
|
||||||
<BooleanSetting path="hideInstanceWallpaper">
|
<BooleanSetting path="hideInstanceWallpaper">
|
||||||
{{ $t('settings.hide_wallpaper') }}
|
{{ $t('settings.hide_wallpaper') }}
|
||||||
|
@ -65,22 +60,14 @@
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<BooleanSetting path="disableStickyHeaders">
|
<ChoiceSetting
|
||||||
{{ $t('settings.disable_sticky_headers') }}
|
id="userPopoverAvatarAction"
|
||||||
</BooleanSetting>
|
path="userPopoverAvatarAction"
|
||||||
</li>
|
:options="userPopoverAvatarActionOptions"
|
||||||
<li>
|
|
||||||
<BooleanSetting path="showScrollbars">
|
|
||||||
{{ $t('settings.show_scrollbars') }}
|
|
||||||
</BooleanSetting>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<BooleanSetting
|
|
||||||
path="userPopoverZoom"
|
|
||||||
expert="1"
|
expert="1"
|
||||||
>
|
>
|
||||||
{{ $t('settings.user_popover_avatar_zoom') }}
|
{{ $t('settings.user_popover_avatar_action') }}
|
||||||
</BooleanSetting>
|
</ChoiceSetting>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<BooleanSetting
|
<BooleanSetting
|
||||||
|
@ -90,16 +77,6 @@
|
||||||
{{ $t('settings.user_popover_avatar_overlay') }}
|
{{ $t('settings.user_popover_avatar_overlay') }}
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
|
||||||
<ChoiceSetting
|
|
||||||
v-if="user"
|
|
||||||
id="thirdColumnMode"
|
|
||||||
path="thirdColumnMode"
|
|
||||||
:options="thirdColumnModeOptions"
|
|
||||||
>
|
|
||||||
{{ $t('settings.third_column_mode') }}
|
|
||||||
</ChoiceSetting>
|
|
||||||
</li>
|
|
||||||
<li>
|
<li>
|
||||||
<BooleanSetting
|
<BooleanSetting
|
||||||
path="alwaysShowNewPostButton"
|
path="alwaysShowNewPostButton"
|
||||||
|
@ -147,6 +124,11 @@
|
||||||
{{ $t('settings.right_sidebar') }}
|
{{ $t('settings.right_sidebar') }}
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<BooleanSetting path="navbarColumnStretch">
|
||||||
|
{{ $t('settings.navbar_column_stretch') }}
|
||||||
|
</BooleanSetting>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<ChoiceSetting
|
<ChoiceSetting
|
||||||
v-if="user"
|
v-if="user"
|
||||||
|
@ -480,3 +462,16 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./general_tab.js"></script>
|
<script src="./general_tab.js"></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.column-settings {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.column-settings .size-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -11,8 +11,8 @@ const UserPopover = {
|
||||||
Popover: defineAsyncComponent(() => import('../popover/popover.vue'))
|
Popover: defineAsyncComponent(() => import('../popover/popover.vue'))
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
userPopoverZoom () {
|
userPopoverAvatarAction () {
|
||||||
return this.$store.getters.mergedConfig.userPopoverZoom
|
return this.$store.getters.mergedConfig.userPopoverAvatarAction
|
||||||
},
|
},
|
||||||
userPopoverOverlay () {
|
userPopoverOverlay () {
|
||||||
return this.$store.getters.mergedConfig.userPopoverOverlay
|
return this.$store.getters.mergedConfig.userPopoverOverlay
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
class="user-popover"
|
class="user-popover"
|
||||||
:user-id="userId"
|
:user-id="userId"
|
||||||
:hide-bio="true"
|
:hide-bio="true"
|
||||||
:avatar-action="userPopoverZoom ? 'zoom' : close"
|
:avatar-action="userPopoverAvatarAction == 'close' ? close : userPopoverAvatarAction"
|
||||||
:on-close="close"
|
:on-close="close"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -45,7 +45,7 @@ const UserProfile = {
|
||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
const routeParams = this.$route.params
|
const routeParams = this.$route.params
|
||||||
this.load(routeParams.name || routeParams.id)
|
this.load({ name: routeParams.name, id: routeParams.id })
|
||||||
this.tab = get(this.$route, 'query.tab', defaultTabKey)
|
this.tab = get(this.$route, 'query.tab', defaultTabKey)
|
||||||
},
|
},
|
||||||
unmounted () {
|
unmounted () {
|
||||||
|
@ -106,12 +106,17 @@ const UserProfile = {
|
||||||
this.userId = null
|
this.userId = null
|
||||||
this.error = false
|
this.error = false
|
||||||
|
|
||||||
|
const maybeId = userNameOrId.id
|
||||||
|
const maybeName = userNameOrId.name
|
||||||
|
|
||||||
// Check if user data is already loaded in store
|
// Check if user data is already loaded in store
|
||||||
const user = this.$store.getters.findUser(userNameOrId)
|
const user = maybeId ? this.$store.getters.findUser(maybeId) : this.$store.getters.findUserByName(maybeName)
|
||||||
if (user) {
|
if (user) {
|
||||||
loadById(user.id)
|
loadById(user.id)
|
||||||
} else {
|
} else {
|
||||||
this.$store.dispatch('fetchUser', userNameOrId)
|
(maybeId
|
||||||
|
? this.$store.dispatch('fetchUser', maybeId)
|
||||||
|
: this.$store.dispatch('fetchUserByName', maybeName))
|
||||||
.then(({ id }) => loadById(id))
|
.then(({ id }) => loadById(id))
|
||||||
.catch((reason) => {
|
.catch((reason) => {
|
||||||
const errorMessage = get(reason, 'error.error')
|
const errorMessage = get(reason, 'error.error')
|
||||||
|
@ -150,12 +155,12 @@ const UserProfile = {
|
||||||
watch: {
|
watch: {
|
||||||
'$route.params.id': function (newVal) {
|
'$route.params.id': function (newVal) {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
this.switchUser(newVal)
|
this.switchUser({ id: newVal })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'$route.params.name': function (newVal) {
|
'$route.params.name': function (newVal) {
|
||||||
if (newVal) {
|
if (newVal) {
|
||||||
this.switchUser(newVal)
|
this.switchUser({ name: newVal })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'$route.query': function (newVal) {
|
'$route.query': function (newVal) {
|
||||||
|
|
|
@ -412,6 +412,7 @@
|
||||||
"hide_isp": "Hide instance-specific panel",
|
"hide_isp": "Hide instance-specific panel",
|
||||||
"hide_shoutbox": "Hide instance shoutbox",
|
"hide_shoutbox": "Hide instance shoutbox",
|
||||||
"right_sidebar": "Reverse order of columns",
|
"right_sidebar": "Reverse order of columns",
|
||||||
|
"navbar_column_stretch": "Stretch navbar to columns width",
|
||||||
"always_show_post_button": "Always show floating New Post button",
|
"always_show_post_button": "Always show floating New Post button",
|
||||||
"hide_wallpaper": "Hide instance wallpaper",
|
"hide_wallpaper": "Hide instance wallpaper",
|
||||||
"preload_images": "Preload images",
|
"preload_images": "Preload images",
|
||||||
|
@ -533,6 +534,11 @@
|
||||||
"third_column_mode_none": "Don't show third column at all",
|
"third_column_mode_none": "Don't show third column at all",
|
||||||
"third_column_mode_notifications": "Notifications column",
|
"third_column_mode_notifications": "Notifications column",
|
||||||
"third_column_mode_postform": "Main post form and navigation",
|
"third_column_mode_postform": "Main post form and navigation",
|
||||||
|
"columns": "Columns",
|
||||||
|
"column_sizes": "Column sizes",
|
||||||
|
"column_sizes_sidebar": "Sidebar",
|
||||||
|
"column_sizes_content": "Content",
|
||||||
|
"column_sizes_notifs": "Notifications",
|
||||||
"tree_advanced": "Allow more flexible navigation in tree view",
|
"tree_advanced": "Allow more flexible navigation in tree view",
|
||||||
"tree_fade_ancestors": "Display ancestors of the current status in faint text",
|
"tree_fade_ancestors": "Display ancestors of the current status in faint text",
|
||||||
"conversation_display_linear": "Linear-style",
|
"conversation_display_linear": "Linear-style",
|
||||||
|
@ -573,7 +579,10 @@
|
||||||
"mention_link_show_avatar_quick": "Show user avatar next to mentions",
|
"mention_link_show_avatar_quick": "Show user avatar next to mentions",
|
||||||
"mention_link_fade_domain": "Fade domains (e.g. {'@'}example.org in {'@'}foo{'@'}example.org)",
|
"mention_link_fade_domain": "Fade domains (e.g. {'@'}example.org in {'@'}foo{'@'}example.org)",
|
||||||
"mention_link_bolden_you": "Highlight mention of you when you are mentioned",
|
"mention_link_bolden_you": "Highlight mention of you when you are mentioned",
|
||||||
"user_popover_avatar_zoom": "Clicking on user avatar in popover zooms it instead of closing the popover",
|
"user_popover_avatar_action": "Popover avatar click action",
|
||||||
|
"user_popover_avatar_action_zoom": "Zoom the avatar",
|
||||||
|
"user_popover_avatar_action_close": "Close the popover",
|
||||||
|
"user_popover_avatar_action_open": "Open profile",
|
||||||
"user_popover_avatar_overlay": "Show user popover over user avatar",
|
"user_popover_avatar_overlay": "Show user popover over user avatar",
|
||||||
"fun": "Fun",
|
"fun": "Fun",
|
||||||
"greentext": "Meme arrows",
|
"greentext": "Meme arrows",
|
||||||
|
|
|
@ -456,6 +456,15 @@
|
||||||
"subject_line_mastodon": "Как в Mastodon: скопировать как есть",
|
"subject_line_mastodon": "Как в Mastodon: скопировать как есть",
|
||||||
"subject_line_email": "Как в электронной почте: \"re: тема\"",
|
"subject_line_email": "Как в электронной почте: \"re: тема\"",
|
||||||
"subject_line_behavior": "Копировать тему в ответах",
|
"subject_line_behavior": "Копировать тему в ответах",
|
||||||
|
"third_column_mode": "Когда недостаточно места, показывать третью колонку содержащую",
|
||||||
|
"third_column_mode_none": "Не показывать третью колонку совсем",
|
||||||
|
"third_column_mode_notifications": "Колонку уведомлений",
|
||||||
|
"third_column_mode_postform": "Форму отправки сообщения и навигацию",
|
||||||
|
"columns": "Колонки",
|
||||||
|
"column_sizes": "Размеры колонок",
|
||||||
|
"column_sizes_sidebar": "Боковой",
|
||||||
|
"column_sizes_content": "Содержимого",
|
||||||
|
"column_sizes_notifs": "Уведомлений",
|
||||||
"no_mutes": "Нет игнорируемых",
|
"no_mutes": "Нет игнорируемых",
|
||||||
"no_blocks": "Нет блокировок",
|
"no_blocks": "Нет блокировок",
|
||||||
"notification_visibility_emoji_reactions": "Реакции",
|
"notification_visibility_emoji_reactions": "Реакции",
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Cookies from 'js-cookie'
|
import Cookies from 'js-cookie'
|
||||||
import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
|
import { setPreset, applyTheme, applyConfig } from '../services/style_setter/style_setter.js'
|
||||||
import messages from '../i18n/messages'
|
import messages from '../i18n/messages'
|
||||||
import localeService from '../services/locale/locale.service.js'
|
import localeService from '../services/locale/locale.service.js'
|
||||||
|
|
||||||
|
@ -17,7 +17,8 @@ export const multiChoiceProperties = [
|
||||||
'subjectLineBehavior',
|
'subjectLineBehavior',
|
||||||
'conversationDisplay', // tree | linear
|
'conversationDisplay', // tree | linear
|
||||||
'conversationOtherRepliesButton', // below | inside
|
'conversationOtherRepliesButton', // below | inside
|
||||||
'mentionLinkDisplay' // short | full_for_remote | full
|
'mentionLinkDisplay', // short | full_for_remote | full
|
||||||
|
'userPopoverAvatarAction' // close | zoom | open
|
||||||
]
|
]
|
||||||
|
|
||||||
export const defaultState = {
|
export const defaultState = {
|
||||||
|
@ -82,11 +83,12 @@ export const defaultState = {
|
||||||
useContainFit: true,
|
useContainFit: true,
|
||||||
disableStickyHeaders: false,
|
disableStickyHeaders: false,
|
||||||
showScrollbars: false,
|
showScrollbars: false,
|
||||||
userPopoverZoom: false,
|
userPopoverAvatarAction: 'close',
|
||||||
userPopoverOverlay: true,
|
userPopoverOverlay: true,
|
||||||
sidebarColumnWidth: '25rem',
|
sidebarColumnWidth: '25rem',
|
||||||
contentColumnWidth: '45rem',
|
contentColumnWidth: '45rem',
|
||||||
notifsColumnWidth: '25rem',
|
notifsColumnWidth: '25rem',
|
||||||
|
navbarColumnStretch: false,
|
||||||
listsNavigation: false,
|
listsNavigation: false,
|
||||||
greentext: undefined, // instance default
|
greentext: undefined, // instance default
|
||||||
useAtIcon: undefined, // instance default
|
useAtIcon: undefined, // instance default
|
||||||
|
@ -165,12 +167,17 @@ const config = {
|
||||||
setHighlight ({ commit, dispatch }, { user, color, type }) {
|
setHighlight ({ commit, dispatch }, { user, color, type }) {
|
||||||
commit('setHighlight', { user, color, type })
|
commit('setHighlight', { user, color, type })
|
||||||
},
|
},
|
||||||
setOption ({ commit, dispatch }, { name, value }) {
|
setOption ({ commit, dispatch, state }, { name, value }) {
|
||||||
commit('setOption', { name, value })
|
commit('setOption', { name, value })
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'theme':
|
case 'theme':
|
||||||
setPreset(value)
|
setPreset(value)
|
||||||
break
|
break
|
||||||
|
case 'sidebarColumnWidth':
|
||||||
|
case 'contentColumnWidth':
|
||||||
|
case 'notifsColumnWidth':
|
||||||
|
applyConfig(state)
|
||||||
|
break
|
||||||
case 'customTheme':
|
case 'customTheme':
|
||||||
case 'customThemeSource':
|
case 'customThemeSource':
|
||||||
applyTheme(value)
|
applyTheme(value)
|
||||||
|
|
|
@ -16,9 +16,6 @@ export const mergeOrAdd = (arr, obj, item) => {
|
||||||
// This is a new item, prepare it
|
// This is a new item, prepare it
|
||||||
arr.push(item)
|
arr.push(item)
|
||||||
obj[item.id] = item
|
obj[item.id] = item
|
||||||
if (item.screen_name && !item.screen_name.includes('@')) {
|
|
||||||
obj[item.screen_name.toLowerCase()] = item
|
|
||||||
}
|
|
||||||
return { item, new: true }
|
return { item, new: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,7 +159,11 @@ export const mutations = {
|
||||||
if (user.relationship) {
|
if (user.relationship) {
|
||||||
state.relationships[user.relationship.id] = user.relationship
|
state.relationships[user.relationship.id] = user.relationship
|
||||||
}
|
}
|
||||||
mergeOrAdd(state.users, state.usersObject, user)
|
const res = mergeOrAdd(state.users, state.usersObject, user)
|
||||||
|
const item = res.item
|
||||||
|
if (res.new && item.screen_name && !item.screen_name.includes('@')) {
|
||||||
|
state.usersByNameObject[item.screen_name.toLowerCase()] = item
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
updateUserRelationship (state, relationships) {
|
updateUserRelationship (state, relationships) {
|
||||||
|
@ -239,12 +240,10 @@ export const mutations = {
|
||||||
|
|
||||||
export const getters = {
|
export const getters = {
|
||||||
findUser: state => query => {
|
findUser: state => query => {
|
||||||
const result = state.usersObject[query]
|
return state.usersObject[query]
|
||||||
// In case it's a screen_name, we can try searching case-insensitive
|
},
|
||||||
if (!result && typeof query === 'string') {
|
findUserByName: state => query => {
|
||||||
return state.usersObject[query.toLowerCase()]
|
return state.usersByNameObject[query.toLowerCase()]
|
||||||
}
|
|
||||||
return result
|
|
||||||
},
|
},
|
||||||
findUserByUrl: state => query => {
|
findUserByUrl: state => query => {
|
||||||
return state.users
|
return state.users
|
||||||
|
@ -263,6 +262,7 @@ export const defaultState = {
|
||||||
currentUser: false,
|
currentUser: false,
|
||||||
users: [],
|
users: [],
|
||||||
usersObject: {},
|
usersObject: {},
|
||||||
|
usersByNameObject: {},
|
||||||
signUpPending: false,
|
signUpPending: false,
|
||||||
signUpErrors: [],
|
signUpErrors: [],
|
||||||
relationships: {}
|
relationships: {}
|
||||||
|
@ -285,6 +285,13 @@ const users = {
|
||||||
return user
|
return user
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
fetchUserByName (store, name) {
|
||||||
|
return store.rootState.api.backendInteractor.fetchUserByName({ name })
|
||||||
|
.then((user) => {
|
||||||
|
store.commit('addNewUsers', [user])
|
||||||
|
return user
|
||||||
|
})
|
||||||
|
},
|
||||||
fetchUserRelationship (store, id) {
|
fetchUserRelationship (store, id) {
|
||||||
if (store.state.currentUser) {
|
if (store.state.currentUser) {
|
||||||
store.rootState.api.backendInteractor.fetchUserRelationship({ id })
|
store.rootState.api.backendInteractor.fetchUserRelationship({ id })
|
||||||
|
|
|
@ -50,6 +50,7 @@ const MASTODON_USER_HOME_TIMELINE_URL = '/api/v1/timelines/home'
|
||||||
const MASTODON_STATUS_URL = id => `/api/v1/statuses/${id}`
|
const MASTODON_STATUS_URL = id => `/api/v1/statuses/${id}`
|
||||||
const MASTODON_STATUS_CONTEXT_URL = id => `/api/v1/statuses/${id}/context`
|
const MASTODON_STATUS_CONTEXT_URL = id => `/api/v1/statuses/${id}/context`
|
||||||
const MASTODON_USER_URL = '/api/v1/accounts'
|
const MASTODON_USER_URL = '/api/v1/accounts'
|
||||||
|
const MASTODON_USER_LOOKUP_URL = '/api/v1/accounts/lookup'
|
||||||
const MASTODON_USER_RELATIONSHIPS_URL = '/api/v1/accounts/relationships'
|
const MASTODON_USER_RELATIONSHIPS_URL = '/api/v1/accounts/relationships'
|
||||||
const MASTODON_USER_TIMELINE_URL = id => `/api/v1/accounts/${id}/statuses`
|
const MASTODON_USER_TIMELINE_URL = id => `/api/v1/accounts/${id}/statuses`
|
||||||
const MASTODON_LIST_URL = id => `/api/v1/lists/${id}`
|
const MASTODON_LIST_URL = id => `/api/v1/lists/${id}`
|
||||||
|
@ -318,6 +319,25 @@ const fetchUser = ({ id, credentials }) => {
|
||||||
.then((data) => parseUser(data))
|
.then((data) => parseUser(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fetchUserByName = ({ name, credentials }) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: MASTODON_USER_LOOKUP_URL,
|
||||||
|
credentials,
|
||||||
|
params: { acct: name }
|
||||||
|
})
|
||||||
|
.then(data => data.id)
|
||||||
|
.catch(error => {
|
||||||
|
if (error && error.statusCode === 404) {
|
||||||
|
// Either the backend does not support lookup endpoint,
|
||||||
|
// or there is no user with such name. Fallback and treat name as id.
|
||||||
|
return name
|
||||||
|
} else {
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(id => fetchUser({ id, credentials }))
|
||||||
|
}
|
||||||
|
|
||||||
const fetchUserRelationship = ({ id, credentials }) => {
|
const fetchUserRelationship = ({ id, credentials }) => {
|
||||||
const url = `${MASTODON_USER_RELATIONSHIPS_URL}/?id=${id}`
|
const url = `${MASTODON_USER_RELATIONSHIPS_URL}/?id=${id}`
|
||||||
return fetch(url, { headers: authHeaders(credentials) })
|
return fetch(url, { headers: authHeaders(credentials) })
|
||||||
|
@ -1481,6 +1501,7 @@ const apiService = {
|
||||||
blockUser,
|
blockUser,
|
||||||
unblockUser,
|
unblockUser,
|
||||||
fetchUser,
|
fetchUser,
|
||||||
|
fetchUserByName,
|
||||||
fetchUserRelationship,
|
fetchUserRelationship,
|
||||||
favorite,
|
favorite,
|
||||||
unfavorite,
|
unfavorite,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import runtime from 'serviceworker-webpack-plugin/lib/runtime'
|
import runtime from 'serviceworker-webpack5-plugin/lib/runtime'
|
||||||
|
|
||||||
function urlBase64ToUint8Array (base64String) {
|
function urlBase64ToUint8Array (base64String) {
|
||||||
const padding = '='.repeat((4 - base64String.length % 4) % 4)
|
const padding = '='.repeat((4 - base64String.length % 4) % 4)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { convert } from 'chromatism'
|
import { convert } from 'chromatism'
|
||||||
import { rgb2hex, hex2rgb, rgba2css, getCssColor, relativeLuminance } from '../color_convert/color_convert.js'
|
import { rgb2hex, hex2rgb, rgba2css, getCssColor, relativeLuminance } from '../color_convert/color_convert.js'
|
||||||
import { getColors, computeDynamicColor, getOpacitySlot } from '../theme_data/theme_data.service.js'
|
import { getColors, computeDynamicColor, getOpacitySlot } from '../theme_data/theme_data.service.js'
|
||||||
|
import { defaultState } from '../../modules/config.js'
|
||||||
|
|
||||||
export const applyTheme = (input) => {
|
export const applyTheme = (input) => {
|
||||||
const { rules } = generatePreset(input)
|
const { rules } = generatePreset(input)
|
||||||
|
@ -20,6 +21,36 @@ export const applyTheme = (input) => {
|
||||||
body.classList.remove('hidden')
|
body.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const configColumns = ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth }) =>
|
||||||
|
({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth })
|
||||||
|
|
||||||
|
const defaultConfigColumns = configColumns(defaultState)
|
||||||
|
|
||||||
|
export const applyConfig = (config) => {
|
||||||
|
const columns = configColumns(config)
|
||||||
|
|
||||||
|
if (columns === defaultConfigColumns) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const head = document.head
|
||||||
|
const body = document.body
|
||||||
|
body.classList.add('hidden')
|
||||||
|
|
||||||
|
const rules = Object
|
||||||
|
.entries(columns)
|
||||||
|
.filter(([k, v]) => v)
|
||||||
|
.map(([k, v]) => `--${k}: ${v}`).join(';')
|
||||||
|
|
||||||
|
const styleEl = document.createElement('style')
|
||||||
|
head.appendChild(styleEl)
|
||||||
|
const styleSheet = styleEl.sheet
|
||||||
|
|
||||||
|
styleSheet.toString()
|
||||||
|
styleSheet.insertRule(`:root { ${rules} }`, 'index-max')
|
||||||
|
body.classList.remove('hidden')
|
||||||
|
}
|
||||||
|
|
||||||
export const getCssShadow = (input, usesDropShadow) => {
|
export const getCssShadow = (input, usesDropShadow) => {
|
||||||
if (input.length === 0) {
|
if (input.length === 0) {
|
||||||
return 'none'
|
return 'none'
|
||||||
|
|
|
@ -16,7 +16,7 @@ const webpackConfig = merge(baseConfig, {
|
||||||
module: {
|
module: {
|
||||||
rules: utils.styleLoaders()
|
rules: utils.styleLoaders()
|
||||||
},
|
},
|
||||||
devtool: '#inline-source-map',
|
devtool: 'inline-source-map',
|
||||||
// vue: {
|
// vue: {
|
||||||
// loaders: {
|
// loaders: {
|
||||||
// js: 'isparta'
|
// js: 'isparta'
|
||||||
|
|
|
@ -15,6 +15,7 @@ const actions = {
|
||||||
|
|
||||||
const testGetters = {
|
const testGetters = {
|
||||||
findUser: state => getters.findUser(state.users),
|
findUser: state => getters.findUser(state.users),
|
||||||
|
findUserByName: state => getters.findUserByName(state.users),
|
||||||
relationship: state => getters.relationship(state.users),
|
relationship: state => getters.relationship(state.users),
|
||||||
mergedConfig: state => ({
|
mergedConfig: state => ({
|
||||||
colors: '',
|
colors: '',
|
||||||
|
@ -95,6 +96,7 @@ const externalProfileStore = createStore({
|
||||||
credentials: ''
|
credentials: ''
|
||||||
},
|
},
|
||||||
usersObject: { 100: extUser },
|
usersObject: { 100: extUser },
|
||||||
|
usersByNameObject: {},
|
||||||
users: [extUser],
|
users: [extUser],
|
||||||
relationships: {}
|
relationships: {}
|
||||||
}
|
}
|
||||||
|
@ -163,7 +165,8 @@ const localProfileStore = createStore({
|
||||||
currentUser: {
|
currentUser: {
|
||||||
credentials: ''
|
credentials: ''
|
||||||
},
|
},
|
||||||
usersObject: { 100: localUser, testuser: localUser },
|
usersObject: { 100: localUser },
|
||||||
|
usersByNameObject: { testuser: localUser },
|
||||||
users: [localUser],
|
users: [localUser],
|
||||||
relationships: {}
|
relationships: {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,24 +57,27 @@ describe('The users module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('findUser', () => {
|
describe('findUser', () => {
|
||||||
it('returns user with matching screen_name', () => {
|
it('does not return user with matching screen_name', () => {
|
||||||
const user = { screen_name: 'Guy', id: '1' }
|
const user = { screen_name: 'Guy', id: '1' }
|
||||||
const state = {
|
const state = {
|
||||||
usersObject: {
|
usersObject: {
|
||||||
1: user,
|
1: user
|
||||||
|
},
|
||||||
|
usersByNameObject: {
|
||||||
guy: user
|
guy: user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const name = 'Guy'
|
const name = 'Guy'
|
||||||
const expected = { screen_name: 'Guy', id: '1' }
|
expect(getters.findUser(state)(name)).to.eql(undefined)
|
||||||
expect(getters.findUser(state)(name)).to.eql(expected)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('returns user with matching id', () => {
|
it('returns user with matching id', () => {
|
||||||
const user = { screen_name: 'Guy', id: '1' }
|
const user = { screen_name: 'Guy', id: '1' }
|
||||||
const state = {
|
const state = {
|
||||||
usersObject: {
|
usersObject: {
|
||||||
1: user,
|
1: user
|
||||||
|
},
|
||||||
|
usersByNameObject: {
|
||||||
guy: user
|
guy: user
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,4 +86,35 @@ describe('The users module', () => {
|
||||||
expect(getters.findUser(state)(id)).to.eql(expected)
|
expect(getters.findUser(state)(id)).to.eql(expected)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('findUserByName', () => {
|
||||||
|
it('returns user with matching screen_name', () => {
|
||||||
|
const user = { screen_name: 'Guy', id: '1' }
|
||||||
|
const state = {
|
||||||
|
usersObject: {
|
||||||
|
1: user
|
||||||
|
},
|
||||||
|
usersByNameObject: {
|
||||||
|
guy: user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const name = 'Guy'
|
||||||
|
const expected = { screen_name: 'Guy', id: '1' }
|
||||||
|
expect(getters.findUserByName(state)(name)).to.eql(expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not return user with matching id', () => {
|
||||||
|
const user = { screen_name: 'Guy', id: '1' }
|
||||||
|
const state = {
|
||||||
|
usersObject: {
|
||||||
|
1: user
|
||||||
|
},
|
||||||
|
usersByNameObject: {
|
||||||
|
guy: user
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const id = '1'
|
||||||
|
expect(getters.findUserByName(state)(id)).to.eql(undefined)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in New Issue