diff --git a/.babelrc b/.babelrc index 373d2c59..d9059016 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,9 @@ { "presets": ["@babel/preset-env"], - "plugins": ["@babel/plugin-transform-runtime", "lodash", "@vue/babel-plugin-jsx"], + "plugins": [ + "@babel/plugin-transform-runtime", + "lodash", + "@vue/babel-plugin-jsx" + ], "comments": false } diff --git a/.eslintrc.js b/.eslintrc.js index 28d39d03..66f54ee5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,14 +5,9 @@ module.exports = { sourceType: 'module' }, // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style - extends: [ - 'plugin:vue/recommended' - ], + extends: ['plugin:vue/recommended', 'plugin:prettier/recommended'], // required to lint *.vue files - plugins: [ - 'vue', - 'import' - ], + plugins: ['vue', 'import'], // add your custom rules here rules: { // allow paren-less arrow functions diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..983b1f48 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "trailingComma": "none", + "singleQuote": true, + "semi": false, + "singleAttributePerLine": true +} diff --git a/build/build.js b/build/build.js index b3c9aad4..cbc09871 100644 --- a/build/build.js +++ b/build/build.js @@ -11,14 +11,17 @@ 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' + ' Built files are meant to be served over an HTTP server.\n' + + " Opening index.html over file:// won't work.\n" ) var spinner = ora('building for production...') spinner.start() -var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) +var assetsPath = path.join( + config.build.assetsRoot, + config.build.assetsSubDirectory +) rm('-rf', assetsPath) mkdir('-p', assetsPath) cp('-R', 'static/*', assetsPath) @@ -26,11 +29,13 @@ cp('-R', 'static/*', assetsPath) webpack(webpackConfig, function (err, stats) { spinner.stop() if (err) throw err - process.stdout.write(stats.toString({ - colors: true, - modules: false, - children: false, - chunks: false, - chunkModules: false - }) + '\n') + process.stdout.write( + stats.toString({ + colors: true, + modules: false, + children: false, + chunks: false, + chunkModules: false + }) + '\n' + ) }) diff --git a/build/check-versions.js b/build/check-versions.js index e2b6cf74..aceda3e9 100644 --- a/build/check-versions.js +++ b/build/check-versions.js @@ -2,8 +2,7 @@ var semver = require('semver') var chalk = require('chalk') var packageConfig = require('../package.json') var exec = function (cmd) { - return require('child_process') - .execSync(cmd).toString().trim() + return require('child_process').execSync(cmd).toString().trim() } var versionRequirements = [ @@ -24,16 +23,23 @@ module.exports = function () { for (var i = 0; i < versionRequirements.length; i++) { var mod = versionRequirements[i] if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { - warnings.push(mod.name + ': ' + - chalk.red(mod.currentVersion) + ' should be ' + - chalk.green(mod.versionRequirement) + warnings.push( + mod.name + + ': ' + + chalk.red(mod.currentVersion) + + ' should be ' + + chalk.green(mod.versionRequirement) ) } } if (warnings.length) { console.log('') - console.log(chalk.yellow('To use this template, you must update following to modules:')) + console.log( + chalk.yellow( + 'To use this template, you must update following to modules:' + ) + ) console.log() for (var i = 0; i < warnings.length; i++) { var warning = warnings[i] diff --git a/build/dev-server.js b/build/dev-server.js index 5acd0fed..b16557ec 100644 --- a/build/dev-server.js +++ b/build/dev-server.js @@ -6,9 +6,10 @@ var express = require('express') var webpack = require('webpack') var opn = require('opn') var proxyMiddleware = require('http-proxy-middleware') -var webpackConfig = process.env.NODE_ENV === 'testing' - ? require('./webpack.prod.conf') - : require('./webpack.dev.conf') +var webpackConfig = + process.env.NODE_ENV === 'testing' + ? require('./webpack.prod.conf') + : require('./webpack.dev.conf') // default port where dev server listens for incoming traffic var port = process.env.PORT || config.dev.port @@ -50,7 +51,10 @@ app.use(devMiddleware) app.use(hotMiddleware) // serve pure static assets -var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) +var staticPath = path.posix.join( + config.dev.assetsPublicPath, + config.dev.assetsSubDirectory +) app.use(staticPath, express.static('./static')) module.exports = app.listen(port, function (err) { diff --git a/build/utils.js b/build/utils.js index c094c3c8..3908c4fa 100644 --- a/build/utils.js +++ b/build/utils.js @@ -4,7 +4,8 @@ var sass = require('sass') var MiniCssExtractPlugin = require('mini-css-extract-plugin') exports.assetsPath = function (_path) { - var assetsSubDirectory = process.env.NODE_ENV === 'production' + var assetsSubDirectory = + process.env.NODE_ENV === 'production' ? config.build.assetsSubDirectory : config.dev.assetsSubDirectory return path.posix.join(assetsSubDirectory, _path) @@ -13,7 +14,7 @@ exports.assetsPath = function (_path) { exports.cssLoaders = function (options) { options = options || {} - function generateLoaders (loaders) { + function generateLoaders(loaders) { // Extract CSS when that option is specified // (which is the case during production build) if (options.extract) { @@ -27,11 +28,11 @@ exports.cssLoaders = function (options) { return [ { test: /\.(post)?css$/, - use: generateLoaders(['css-loader', 'postcss-loader']), + use: generateLoaders(['css-loader', 'postcss-loader']) }, { test: /\.less$/, - use: generateLoaders(['css-loader', 'postcss-loader', 'less-loader']), + use: generateLoaders(['css-loader', 'postcss-loader', 'less-loader']) }, { test: /\.sass$/, @@ -52,8 +53,8 @@ exports.cssLoaders = function (options) { }, { test: /\.styl(us)?$/, - use: generateLoaders(['css-loader', 'postcss-loader', 'stylus-loader']), - }, + use: generateLoaders(['css-loader', 'postcss-loader', 'stylus-loader']) + } ] } diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index 2a3db96e..3ccdcac0 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -7,8 +7,8 @@ var { VueLoaderPlugin } = require('vue-loader') var env = process.env.NODE_ENV // check env & config/index.js to decide weither to enable CSS Sourcemaps for the // various preprocessor loaders added to vue-loader at the end of this file -var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) -var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) +var cssSourceMapDev = env === 'development' && config.dev.cssSourceMap +var cssSourceMapProd = env === 'production' && config.build.productionSourceMap var useCssSourceMap = cssSourceMapDev || cssSourceMapProd var now = Date.now() @@ -18,9 +18,12 @@ module.exports = { app: './src/main.js' }, output: { - hashFunction: "sha256", // Workaround for builds with OpenSSL 3. + hashFunction: 'sha256', // Workaround for builds with OpenSSL 3. path: config.build.assetsRoot, - publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, + publicPath: + process.env.NODE_ENV === 'production' + ? config.build.assetsPublicPath + : config.dev.assetsPublicPath, filename: '[name].js' }, optimization: { @@ -30,17 +33,15 @@ module.exports = { }, resolve: { extensions: ['.js', '.jsx', '.vue', '.mjs'], - modules: [ - path.join(__dirname, '../node_modules') - ], + modules: [path.join(__dirname, '../node_modules')], fallback: { - "url": require.resolve("url/"), + url: require.resolve('url/') }, alias: { - 'static': path.resolve(__dirname, '../static'), - 'src': path.resolve(__dirname, '../src'), - 'assets': path.resolve(__dirname, '../src/assets'), - 'components': path.resolve(__dirname, '../src/components'), + static: path.resolve(__dirname, '../static'), + src: path.resolve(__dirname, '../src'), + assets: path.resolve(__dirname, '../src/assets'), + components: path.resolve(__dirname, '../src/components'), 'vue-i18n': 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js' } }, @@ -66,14 +67,15 @@ module.exports = { test: /\.(json5?|ya?ml)$/, // target json, json5, yaml and yml files type: 'javascript/auto', loader: '@intlify/vue-i18n-loader', - include: [ // Use `Rule.include` to specify the files of locale messages to be pre-compiled + include: [ + // Use `Rule.include` to specify the files of locale messages to be pre-compiled path.resolve(__dirname, '../src/i18n') ] }, { - test: /\.mjs$/, - include: /node_modules/, - type: "javascript/auto" + test: /\.mjs$/, + include: /node_modules/, + type: 'javascript/auto' }, { test: /\.vue$/, @@ -114,10 +116,8 @@ module.exports = { name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } - }, + } ] }, - plugins: [ - new VueLoaderPlugin() - ] + plugins: [new VueLoaderPlugin()] } diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index 8c7ac5d7..16d2d3f3 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -7,7 +7,9 @@ var HtmlWebpackPlugin = require('html-webpack-plugin') // add hot-reload related code to entry chunks Object.keys(baseWebpackConfig.entry).forEach(function (name) { - baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) + baseWebpackConfig.entry[name] = ['./build/dev-client'].concat( + baseWebpackConfig.entry[name] + ) }) module.exports = merge(baseWebpackConfig, { @@ -20,10 +22,10 @@ module.exports = merge(baseWebpackConfig, { plugins: [ new webpack.DefinePlugin({ 'process.env': config.dev.env, - 'COMMIT_HASH': JSON.stringify('DEV'), - 'DEV_OVERRIDES': JSON.stringify(config.dev.settings), - '__VUE_OPTIONS_API__': true, - '__VUE_PROD_DEVTOOLS__': false + COMMIT_HASH: JSON.stringify('DEV'), + DEV_OVERRIDES: JSON.stringify(config.dev.settings), + __VUE_OPTIONS_API__: true, + __VUE_PROD_DEVTOOLS__: false }), // https://github.com/glenjamin/webpack-hot-middleware#installation--usage new webpack.HotModuleReplacementPlugin(), diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index d528cb0e..6843ed45 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -2,23 +2,27 @@ var path = require('path') var config = require('../config') var utils = require('./utils') var webpack = require('webpack') -const WorkboxPlugin = require('workbox-webpack-plugin'); +const WorkboxPlugin = require('workbox-webpack-plugin') var { merge } = require('webpack-merge') var baseWebpackConfig = require('./webpack.base.conf') var MiniCssExtractPlugin = require('mini-css-extract-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') : config.build.env let commitHash = require('child_process') - .execSync('git rev-parse --short HEAD') - .toString(); + .execSync('git rev-parse --short HEAD') + .toString() var webpackConfig = merge(baseWebpackConfig, { mode: 'production', module: { - rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, extract: true }) + rules: utils.styleLoaders({ + sourceMap: config.dev.cssSourceMap, + extract: true + }) }, devtool: 'source-map', optimization: { @@ -36,15 +40,15 @@ var webpackConfig = merge(baseWebpackConfig, { new WorkboxPlugin.InjectManifest({ swSrc: path.join(__dirname, '..', 'src/sw.js'), swDest: 'sw-pleroma.js', - maximumFileSizeToCacheInBytes: 15 * 1024 * 1024, + maximumFileSizeToCacheInBytes: 15 * 1024 * 1024 }), // http://vuejs.github.io/vue-loader/workflow/production.html new webpack.DefinePlugin({ 'process.env': env, - 'COMMIT_HASH': JSON.stringify(commitHash), - 'DEV_OVERRIDES': JSON.stringify(undefined), - '__VUE_OPTIONS_API__': true, - '__VUE_PROD_DEVTOOLS__': false + COMMIT_HASH: JSON.stringify(commitHash), + DEV_OVERRIDES: JSON.stringify(undefined), + __VUE_OPTIONS_API__: true, + __VUE_PROD_DEVTOOLS__: false }), // extract css into its own file new MiniCssExtractPlugin({ @@ -54,9 +58,8 @@ var webpackConfig = merge(baseWebpackConfig, { // you can customize output by editing /index.html // see https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ - filename: process.env.NODE_ENV === 'testing' - ? 'index.html' - : config.build.index, + filename: + process.env.NODE_ENV === 'testing' ? 'index.html' : config.build.index, template: 'index.html', inject: true, minify: { @@ -69,7 +72,7 @@ var webpackConfig = merge(baseWebpackConfig, { }, // necessary to consistently work with multiple chunks via CommonsChunkPlugin chunksSortMode: 'auto' - }), + }) // split vendor js into its own file // extract webpack runtime and module manifest to its own file in order to // prevent vendor hash from being updated whenever app bundle is updated @@ -87,9 +90,7 @@ if (config.build.productionGzip) { asset: '[path].gz[query]', algorithm: 'gzip', test: new RegExp( - '\\.(' + - config.build.productionGzipExtensions.join('|') + - ')$' + '\\.(' + config.build.productionGzipExtensions.join('|') + ')$' ), threshold: 10240, minRatio: 0.8 diff --git a/config/index.js b/config/index.js index 4a21e718..2e2f6d71 100644 --- a/config/index.js +++ b/config/index.js @@ -38,7 +38,7 @@ module.exports = { assetsSubDirectory: 'static', assetsPublicPath: '/', proxyTable: { - '/manifest.json': { + '/manifest.json': { target, changeOrigin: true, cookieDomainRewrite: 'localhost' @@ -59,7 +59,7 @@ module.exports = { cookieDomainRewrite: 'localhost', ws: true, headers: { - 'Origin': target + Origin: target } }, '/oauth/revoke': { @@ -76,7 +76,7 @@ module.exports = { target, changeOrigin: true, cookieDomainRewrite: 'localhost' - }, + } }, // CSS Sourcemaps off by default because relative paths are "buggy" // with this option, according to the CSS-Loader README diff --git a/index.html b/index.html index 79613dd2..aa011cef 100644 --- a/index.html +++ b/index.html @@ -1,18 +1,46 @@ - - + + Akkoma - - - - - - + + + + + + - - + + diff --git a/package.json b/package.json index 19a7e186..ed5e30d2 100644 --- a/package.json +++ b/package.json @@ -56,7 +56,7 @@ "@vue/babel-plugin-jsx": "1.1.1", "@vue/compiler-sfc": "^3.1.0", "@vue/test-utils": "^2.0.2", - "autoprefixer": "6.7.7", + "autoprefixer": "^10.4.13", "babel-loader": "^9.1.0", "babel-plugin-lodash": "3.3.4", "chai": "^4.3.7", @@ -67,11 +67,13 @@ "css-loader": "^6.7.2", "custom-event-polyfill": "^1.0.7", "eslint": "^7.32.0", + "eslint-config-prettier": "^8.5.0", "eslint-config-standard": "^17.0.0", "eslint-friendly-formatter": "^4.0.1", "eslint-loader": "^4.0.2", "eslint-plugin-import": "^2.26.0", "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^6.1.1", "eslint-plugin-standard": "^5.0.0", "eslint-plugin-vue": "^9.7.0", @@ -101,9 +103,11 @@ "nightwatch": "0.9.21", "opn": "4.0.2", "ora": "0.4.1", + "postcss": "^8.4.19", "postcss-html": "^1.5.0", - "postcss-loader": "3.0.0", + "postcss-loader": "^7.0.2", "postcss-sass": "^0.5.0", + "prettier": "2.8.1", "raw-loader": "0.5.1", "sass": "^1.56.0", "sass-loader": "^13.2.0", diff --git a/postcss.config.js b/postcss.config.js index 88752c6c..944b80ab 100644 --- a/postcss.config.js +++ b/postcss.config.js @@ -1,5 +1,3 @@ module.exports = { - plugins: [ - require('autoprefixer') - ] + plugins: [require('autoprefixer')] } diff --git a/renovate.json b/renovate.json index 39a2b6e9..4bd832f5 100644 --- a/renovate.json +++ b/renovate.json @@ -1,6 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:base" - ] + "extends": ["config:base"] } diff --git a/src/App.js b/src/App.js index d4b3b41a..83e535b9 100644 --- a/src/App.js +++ b/src/App.js @@ -24,7 +24,9 @@ export default { components: { UserPanel, NavPanel, - Notifications: defineAsyncComponent(() => import('./components/notifications/notifications.vue')), + Notifications: defineAsyncComponent(() => + import('./components/notifications/notifications.vue') + ), InstanceSpecificPanel, FeaturesPanel, WhoToFollowPanel, @@ -44,17 +46,20 @@ export default { data: () => ({ mobileActivePanel: 'timeline' }), - created () { + created() { // Load the locale from the storage const val = this.$store.getters.mergedConfig.interfaceLanguage - this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) + this.$store.dispatch('setOption', { + name: 'interfaceLanguage', + value: val + }) window.addEventListener('resize', this.updateMobileState) }, - unmounted () { + unmounted() { window.removeEventListener('resize', this.updateMobileState) }, computed: { - classes () { + classes() { return [ { '-reverse': this.reverseLayout, @@ -64,48 +69,76 @@ export default { '-' + this.layoutType ] }, - currentUser () { return this.$store.state.users.currentUser }, - userBackground () { return this.currentUser.background_image }, - instanceBackground () { + currentUser() { + return this.$store.state.users.currentUser + }, + userBackground() { + return this.currentUser.background_image + }, + instanceBackground() { return this.mergedConfig.hideInstanceWallpaper ? null : this.$store.state.instance.background }, - background () { return this.userBackground || this.instanceBackground }, - bgStyle () { + background() { + return this.userBackground || this.instanceBackground + }, + bgStyle() { if (this.background) { return { '--body-background-image': `url(${this.background})` } } }, - suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled }, - showInstanceSpecificPanel () { - return this.$store.state.instance.showInstanceSpecificPanel && + suggestionsEnabled() { + return this.$store.state.instance.suggestionsEnabled + }, + showInstanceSpecificPanel() { + return ( + this.$store.state.instance.showInstanceSpecificPanel && !this.$store.getters.mergedConfig.hideISP && this.$store.state.instance.instanceSpecificPanelContent + ) }, - newPostButtonShown () { - return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile' + newPostButtonShown() { + return ( + this.$store.getters.mergedConfig.alwaysShowNewPostButton || + this.layoutType === 'mobile' + ) }, - showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, - editingAvailable () { return this.$store.state.instance.editingAvailable }, - layoutType () { return this.$store.state.interface.layoutType }, - privateMode () { return this.$store.state.instance.private }, - reverseLayout () { - const { thirdColumnMode, sidebarRight: reverseSetting } = this.$store.getters.mergedConfig + showFeaturesPanel() { + return this.$store.state.instance.showFeaturesPanel + }, + editingAvailable() { + return this.$store.state.instance.editingAvailable + }, + layoutType() { + return this.$store.state.interface.layoutType + }, + privateMode() { + return this.$store.state.instance.private + }, + reverseLayout() { + const { thirdColumnMode, sidebarRight: reverseSetting } = + this.$store.getters.mergedConfig if (this.layoutType !== 'wide') { return reverseSetting } else { - return thirdColumnMode === 'notifications' ? reverseSetting : !reverseSetting + return thirdColumnMode === 'notifications' + ? reverseSetting + : !reverseSetting } }, - noSticky () { return this.$store.getters.mergedConfig.disableStickyHeaders }, - showScrollbars () { return this.$store.getters.mergedConfig.showScrollbars }, + noSticky() { + return this.$store.getters.mergedConfig.disableStickyHeaders + }, + showScrollbars() { + return this.$store.getters.mergedConfig.showScrollbars + }, ...mapGetters(['mergedConfig']) }, methods: { - updateMobileState () { + updateMobileState() { this.$store.dispatch('setLayoutWidth', windowWidth()) this.$store.dispatch('setLayoutHeight', windowHeight()) } diff --git a/src/App.scss b/src/App.scss index 7e6d0dfc..bbf231ce 100644 --- a/src/App.scss +++ b/src/App.scss @@ -12,8 +12,8 @@ html { } body { - font-family: sans-serif; - font-family: var(--interfaceFont, sans-serif); + font-family: $system-sans-serif; + font-family: var(--interfaceFont, $system-sans-serif); margin: 0; color: $fallback--text; color: var(--text, $fallback--text); @@ -22,84 +22,13 @@ body { overscroll-behavior-y: none; overflow-x: clip; overflow-y: scroll; + background: var(--bg); &.hidden { display: none; } } -// ## Custom scrollbars -// Only show custom scrollbars on devices which -// have a cursor/pointer to operate them -@media (any-pointer: fine) { - * { - scrollbar-color: var(--btn) transparent; - - &::-webkit-scrollbar { - background: transparent; - } - - &::-webkit-scrollbar-button, - &::-webkit-scrollbar-thumb { - background-color: var(--btn); - box-shadow: var(--buttonShadow); - border-radius: var(--btnRadius); - } - - // horizontal/vertical/increment/decrement are webkit-specific stuff - // that indicates whether we're affecting vertical scrollbar, increase button etc - // stylelint-disable selector-pseudo-class-no-unknown - &::-webkit-scrollbar-button { - --___bgPadding: 2px; - - color: var(--btnText); - background-repeat: no-repeat, no-repeat; - - &:horizontal { - background-size: 50% calc(50% - var(--___bgPadding)), 50% calc(50% - var(--___bgPadding)); - - &:increment { - background-image: - linear-gradient(45deg, var(--btnText) 50%, transparent 51%), - linear-gradient(-45deg, transparent 50%, var(--btnText) 51%); - background-position: top var(--___bgPadding) left 50%, right 50% bottom var(--___bgPadding); - } - - &:decrement { - background-image: - linear-gradient(45deg, transparent 50%, var(--btnText) 51%), - linear-gradient(-45deg, var(--btnText) 50%, transparent 51%); - background-position: bottom var(--___bgPadding) right 50%, left 50% top var(--___bgPadding); - } - } - - &:vertical { - background-size: calc(50% - var(--___bgPadding)) 50%, calc(50% - var(--___bgPadding)) 50%; - - &:increment { - background-image: - linear-gradient(-45deg, transparent 50%, var(--btnText) 51%), - linear-gradient(45deg, transparent 50%, var(--btnText) 51%); - background-position: right var(--___bgPadding) top 50%, left var(--___bgPadding) top 50%; - } - - &:decrement { - background-image: - linear-gradient(-45deg, var(--btnText) 50%, transparent 51%), - linear-gradient(45deg, var(--btnText) 50%, transparent 51%); - background-position: left var(--___bgPadding) top 50%, right var(--___bgPadding) top 50%; - } - } - } - // stylelint-enable selector-pseudo-class-no-unknown - } - // Body should have background to scrollbar otherwise it will use white (body color?) - html { - scrollbar-color: var(--selectedMenu) var(--wallpaper); - background: var(--wallpaper); - } -} - a { text-decoration: none; color: $fallback--link; @@ -110,7 +39,7 @@ h4 { margin: 0; } -i[class*=icon-], +i[class*='icon-'], .svg-inline--fa { color: $fallback--icon; color: var(--icon, $fallback--icon); @@ -126,8 +55,9 @@ nav { box-shadow: 0 0 4px rgba(0, 0, 0, 0.6); box-shadow: var(--topBarShadow); box-sizing: border-box; - height: var(--navbar-height); + height: calc(var(--navbar-height) + 1px); position: fixed; + backdrop-filter: blur(12px) saturate(1.2); } #sidebar { @@ -182,7 +112,7 @@ nav { position: relative; display: grid; grid-template-columns: var(--miniColumn) var(--maxiColumn); - grid-template-areas: "sidebar content"; + grid-template-areas: 'sidebar content'; grid-template-rows: 1fr; box-sizing: border-box; margin: 0 auto; @@ -228,7 +158,9 @@ nav { overflow-y: auto; overflow-x: hidden; margin-left: calc(var(--___paddingIncrease) * -1); - padding-left: calc(var(--___paddingIncrease) + var(--___columnMargin) / 2); + padding-left: calc( + var(--___paddingIncrease) + var(--___columnMargin) / 2 + ); // On browsers that don't support hiding scrollbars we enforce "show scrolbars" mode // might implement old style of hiding scrollbars later if there's demand @@ -236,7 +168,9 @@ nav { &:not(.-show-scrollbar) { scrollbar-width: none; margin-right: calc(var(--___paddingIncrease) * -1); - padding-right: calc(var(--___paddingIncrease) + var(--___columnMargin) / 2); + padding-right: calc( + var(--___paddingIncrease) + var(--___columnMargin) / 2 + ); &::-webkit-scrollbar { display: block; @@ -276,21 +210,21 @@ nav { &.-reverse:not(.-wide):not(.-mobile) { grid-template-columns: var(--maxiColumn) var(--miniColumn); - grid-template-areas: "content sidebar"; + grid-template-areas: 'content sidebar'; } &.-wide { grid-template-columns: var(--miniColumn) var(--maxiColumn) var(--miniColumn); - grid-template-areas: "sidebar content notifs"; + grid-template-areas: 'sidebar content notifs'; &.-reverse { - grid-template-areas: "notifs content sidebar"; + grid-template-areas: 'notifs content sidebar'; } } &.-mobile { grid-template-columns: 100vw; - grid-template-areas: "content"; + grid-template-areas: 'content'; padding: 0; .column { @@ -347,7 +281,7 @@ nav { background: transparent; } - i[class*=icon-], + i[class*='icon-'], .svg-inline--fa { color: $fallback--text; color: var(--btnText, $fallback--text); @@ -363,7 +297,9 @@ nav { } &:active { - box-shadow: 0 0 4px 0 rgba(255, 255, 255, 0.3), 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset; + box-shadow: 0 0 4px 0 rgba(255, 255, 255, 0.3), + 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, + 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset; box-shadow: var(--buttonPressedShadow); color: $fallback--text; color: var(--btnPressedText, $fallback--text); @@ -396,7 +332,9 @@ nav { color: var(--btnToggledText, $fallback--text); background-color: $fallback--fg; background-color: var(--btnToggled, $fallback--fg); - box-shadow: 0 0 4px 0 rgba(255, 255, 255, 0.3), 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset; + box-shadow: 0 0 4px 0 rgba(255, 255, 255, 0.3), + 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, + 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset; box-shadow: var(--buttonPressedShadow); svg, @@ -461,7 +399,8 @@ textarea, border: none; border-radius: $fallback--inputRadius; border-radius: var(--inputRadius, $fallback--inputRadius); - box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset, 0 0 2px 0 rgba(0, 0, 0, 1) inset; + box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, + 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset, 0 0 2px 0 rgba(0, 0, 0, 1) inset; box-shadow: var(--inputShadow); background-color: $fallback--fg; background-color: var(--input, $fallback--fg); @@ -479,13 +418,13 @@ textarea, padding: 0 var(--_padding); &:disabled, - &[disabled=disabled], + &[disabled='disabled'], &.disabled { cursor: not-allowed; opacity: 0.5; } - &[type=range] { + &[type='range'] { background: none; border: none; margin: 0; @@ -493,7 +432,7 @@ textarea, flex: 1; } - &[type=radio] { + &[type='radio'] { display: none; &:checked + label::before { @@ -533,7 +472,7 @@ textarea, } } - &[type=checkbox] { + &[type='checkbox'] { display: none; &:checked + label::before { @@ -594,8 +533,8 @@ option { .hide-number-spinner { -moz-appearance: textfield; - &[type=number]::-webkit-inner-spin-button, - &[type=number]::-webkit-outer-spin-button { + &[type='number']::-webkit-inner-spin-button, + &[type='number']::-webkit-outer-spin-button { opacity: 0; display: none; } diff --git a/src/App.vue b/src/App.vue index 80ebb525..65b6e35b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -43,7 +43,7 @@ :to="{ name: 'login' }" class="panel-body" > - {{ $t("login.hint") }} + {{ $t('login.hint') }} diff --git a/src/_variables.scss b/src/_variables.scss index 65ce4027..5dbf6d2c 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -4,7 +4,7 @@ $darkened-background: whitesmoke; $fallback--bg: #121a24; $fallback--fg: #182230; -$fallback--faint: rgba(185, 185, 186, .5); +$fallback--faint: rgba(185, 185, 186, 0.5); $fallback--text: #b9b9ba; $fallback--link: #d8a070; $fallback--icon: #666; @@ -16,8 +16,8 @@ $fallback--cBlue: #0095ff; $fallback--cGreen: #0fa00f; $fallback--cOrange: orange; -$fallback--alertError: rgba(211,16,20,.5); -$fallback--alertWarning: rgba(111,111,20,.5); +$fallback--alertError: rgba(211, 16, 20, 0.5); +$fallback--alertWarning: rgba(111, 111, 20, 0.5); $fallback--panelRadius: 10px; $fallback--checkboxRadius: 2px; @@ -28,6 +28,14 @@ $fallback--avatarRadius: 4px; $fallback--avatarAltRadius: 10px; $fallback--attachmentRadius: 10px; -$fallback--buttonShadow: 0px 0px 2px 0px rgba(0, 0, 0, 1), 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; +$fallback--buttonShadow: 0px 0px 2px 0px rgba(0, 0, 0, 1), + 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, + 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset; $status-margin: 0.75em; + +$system-sans-serif: -apple-system, BlinkMacSystemFont, avenir next, avenir, + segoe ui, helvetica neue, helvetica, Cantarell, Ubuntu, roboto, noto, arial, + sans-serif; +$system-mono: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, + monospace; diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 4bafca1d..c09403ba 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -3,13 +3,19 @@ import { createApp } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import vClickOutside from 'click-outside-vue3' -import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome' +import { + FontAwesomeIcon, + FontAwesomeLayers +} from '@fortawesome/vue-fontawesome' import App from '../App.vue' import routes from './routes' import VBodyScrollLock from 'src/directives/body_scroll_lock' -import { windowWidth, windowHeight } from '../services/window_utils/window_utils' +import { + windowWidth, + windowHeight +} from '../services/window_utils/window_utils' import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js' @@ -23,7 +29,9 @@ const parsedInitialResults = () => { return null } if (!staticInitialResults) { - staticInitialResults = JSON.parse(document.getElementById('initial-results').textContent) + staticInitialResults = JSON.parse( + document.getElementById('initial-results').textContent + ) } return staticInitialResults } @@ -71,18 +79,30 @@ const getInstanceConfig = async ({ store }) => { const textlimit = data.max_toot_chars const vapidPublicKey = data.pleroma.vapid_public_key - store.dispatch('setInstanceOption', { name: 'textlimit', value: textlimit }) - store.dispatch('setInstanceOption', { name: 'accountApprovalRequired', value: data.approval_required }) + store.dispatch('setInstanceOption', { + name: 'textlimit', + value: textlimit + }) + store.dispatch('setInstanceOption', { + name: 'accountApprovalRequired', + value: data.approval_required + }) // don't override cookie if set if (!Cookies.get('userLanguage')) { - store.dispatch('setOption', { name: 'interfaceLanguage', value: resolveLanguage(data.languages) }) + store.dispatch('setOption', { + name: 'interfaceLanguage', + value: resolveLanguage(data.languages) + }) } if (vapidPublicKey) { - store.dispatch('setInstanceOption', { name: 'vapidPublicKey', value: vapidPublicKey }) + store.dispatch('setInstanceOption', { + name: 'vapidPublicKey', + value: vapidPublicKey + }) } } else { - throw (res) + throw res } } catch (error) { console.error('Could not load instance config, potentially fatal') @@ -97,10 +117,12 @@ const getBackendProvidedConfig = async ({ store }) => { const data = await res.json() return data.pleroma_fe } else { - throw (res) + throw res } } catch (error) { - console.error('Could not load backend-provided frontend config, potentially fatal') + console.error( + 'Could not load backend-provided frontend config, potentially fatal' + ) console.error(error) } } @@ -111,7 +133,7 @@ const getStaticConfig = async () => { if (res.ok) { return res.json() } else { - throw (res) + throw res } } catch (error) { console.warn('Failed to load static/config.json, continuing without it.') @@ -154,16 +176,12 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => { store.dispatch('setInstanceOption', { name: 'logoMask', - value: typeof config.logoMask === 'undefined' - ? true - : config.logoMask + value: typeof config.logoMask === 'undefined' ? true : config.logoMask }) store.dispatch('setInstanceOption', { name: 'logoMargin', - value: typeof config.logoMargin === 'undefined' - ? 0 - : config.logoMargin + value: typeof config.logoMargin === 'undefined' ? 0 : config.logoMargin }) copyInstanceOption('logoLeft') store.commit('authFlow/setInitialStrategy', config.loginMethod) @@ -191,7 +209,7 @@ const getTOS = async ({ store }) => { const html = await res.text() store.dispatch('setInstanceOption', { name: 'tos', value: html }) } else { - throw (res) + throw res } } catch (e) { console.warn("Can't load TOS") @@ -204,9 +222,12 @@ const getInstancePanel = async ({ store }) => { const res = await preloadFetch('/instance/panel.html') if (res.ok) { const html = await res.text() - store.dispatch('setInstanceOption', { name: 'instanceSpecificPanelContent', value: html }) + store.dispatch('setInstanceOption', { + name: 'instanceSpecificPanelContent', + value: html + }) } else { - throw (res) + throw res } } catch (e) { console.warn("Can't load instance panel") @@ -219,25 +240,30 @@ const getStickers = async ({ store }) => { const res = await window.fetch('/static/stickers.json') if (res.ok) { const values = await res.json() - const stickers = (await Promise.all( - Object.entries(values).map(async ([name, path]) => { - const resPack = await window.fetch(path + 'pack.json') - var meta = {} - if (resPack.ok) { - meta = await resPack.json() - } - return { - pack: name, - path, - meta - } - }) - )).sort((a, b) => { + const stickers = ( + await Promise.all( + Object.entries(values).map(async ([name, path]) => { + const resPack = await window.fetch(path + 'pack.json') + var meta = {} + if (resPack.ok) { + meta = await resPack.json() + } + return { + pack: name, + path, + meta + } + }) + ) + ).sort((a, b) => { return a.meta.title.localeCompare(b.meta.title) }) - store.dispatch('setInstanceOption', { name: 'stickers', value: stickers }) + store.dispatch('setInstanceOption', { + name: 'stickers', + value: stickers + }) } else { - throw (res) + throw res } } catch (e) { console.warn("Can't load stickers") @@ -252,13 +278,19 @@ const getAppSecret = async ({ store }) => { .then((app) => getClientToken({ ...app, instance: instance.server })) .then((token) => { commit('setAppToken', token.access_token) - commit('setBackendInteractor', backendInteractorService(store.getters.getToken())) + commit( + 'setBackendInteractor', + backendInteractorService(store.getters.getToken()) + ) }) } const resolveStaffAccounts = ({ store, accounts }) => { - const nicknames = accounts.map(uri => uri.split('/').pop()) - store.dispatch('setInstanceOption', { name: 'staffAccounts', value: nicknames }) + const nicknames = accounts.map((uri) => uri.split('/').pop()) + store.dispatch('setInstanceOption', { + name: 'staffAccounts', + value: nicknames + }) } const getNodeInfo = async ({ store }) => { @@ -268,65 +300,137 @@ const getNodeInfo = async ({ store }) => { const data = await res.json() const metadata = data.metadata const features = metadata.features - store.dispatch('setInstanceOption', { name: 'name', value: metadata.nodeName }) - store.dispatch('setInstanceOption', { name: 'registrationOpen', value: data.openRegistrations }) - store.dispatch('setInstanceOption', { name: 'mediaProxyAvailable', value: features.includes('media_proxy') }) - store.dispatch('setInstanceOption', { name: 'safeDM', value: features.includes('safe_dm_mentions') }) - store.dispatch('setInstanceOption', { name: 'pollsAvailable', value: features.includes('polls') }) - store.dispatch('setInstanceOption', { name: 'editingAvailable', value: features.includes('editing') }) - store.dispatch('setInstanceOption', { name: 'pollLimits', value: metadata.pollLimits }) - store.dispatch('setInstanceOption', { name: 'mailerEnabled', value: metadata.mailerEnabled }) - store.dispatch('setInstanceOption', { name: 'translationEnabled', value: features.includes('akkoma:machine_translation') }) + store.dispatch('setInstanceOption', { + name: 'name', + value: metadata.nodeName + }) + store.dispatch('setInstanceOption', { + name: 'registrationOpen', + value: data.openRegistrations + }) + store.dispatch('setInstanceOption', { + name: 'mediaProxyAvailable', + value: features.includes('media_proxy') + }) + store.dispatch('setInstanceOption', { + name: 'safeDM', + value: features.includes('safe_dm_mentions') + }) + store.dispatch('setInstanceOption', { + name: 'pollsAvailable', + value: features.includes('polls') + }) + store.dispatch('setInstanceOption', { + name: 'editingAvailable', + value: features.includes('editing') + }) + store.dispatch('setInstanceOption', { + name: 'pollLimits', + value: metadata.pollLimits + }) + store.dispatch('setInstanceOption', { + name: 'mailerEnabled', + value: metadata.mailerEnabled + }) + store.dispatch('setInstanceOption', { + name: 'translationEnabled', + value: features.includes('akkoma:machine_translation') + }) const uploadLimits = metadata.uploadLimits - store.dispatch('setInstanceOption', { name: 'uploadlimit', value: parseInt(uploadLimits.general) }) - store.dispatch('setInstanceOption', { name: 'avatarlimit', value: parseInt(uploadLimits.avatar) }) - store.dispatch('setInstanceOption', { name: 'backgroundlimit', value: parseInt(uploadLimits.background) }) - store.dispatch('setInstanceOption', { name: 'bannerlimit', value: parseInt(uploadLimits.banner) }) - store.dispatch('setInstanceOption', { name: 'fieldsLimits', value: metadata.fieldsLimits }) + store.dispatch('setInstanceOption', { + name: 'uploadlimit', + value: parseInt(uploadLimits.general) + }) + store.dispatch('setInstanceOption', { + name: 'avatarlimit', + value: parseInt(uploadLimits.avatar) + }) + store.dispatch('setInstanceOption', { + name: 'backgroundlimit', + value: parseInt(uploadLimits.background) + }) + store.dispatch('setInstanceOption', { + name: 'bannerlimit', + value: parseInt(uploadLimits.banner) + }) + store.dispatch('setInstanceOption', { + name: 'fieldsLimits', + value: metadata.fieldsLimits + }) - store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames }) - store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats }) + store.dispatch('setInstanceOption', { + name: 'restrictedNicknames', + value: metadata.restrictedNicknames + }) + store.dispatch('setInstanceOption', { + name: 'postFormats', + value: metadata.postFormats + }) const suggestions = metadata.suggestions - store.dispatch('setInstanceOption', { name: 'suggestionsEnabled', value: suggestions.enabled }) - store.dispatch('setInstanceOption', { name: 'suggestionsWeb', value: suggestions.web }) + store.dispatch('setInstanceOption', { + name: 'suggestionsEnabled', + value: suggestions.enabled + }) + store.dispatch('setInstanceOption', { + name: 'suggestionsWeb', + value: suggestions.web + }) const software = data.software - store.dispatch('setInstanceOption', { name: 'backendVersion', value: software.version }) - store.dispatch('setInstanceOption', { name: 'pleromaBackend', value: software.name === 'pleroma' }) + store.dispatch('setInstanceOption', { + name: 'backendVersion', + value: software.version + }) + store.dispatch('setInstanceOption', { + name: 'pleromaBackend', + value: software.name === 'pleroma' + }) const priv = metadata.private store.dispatch('setInstanceOption', { name: 'private', value: priv }) const frontendVersion = window.___pleromafe_commit_hash - store.dispatch('setInstanceOption', { name: 'frontendVersion', value: frontendVersion }) + store.dispatch('setInstanceOption', { + name: 'frontendVersion', + value: frontendVersion + }) const federation = metadata.federation store.dispatch('setInstanceOption', { name: 'tagPolicyAvailable', - value: typeof federation.mrf_policies === 'undefined' - ? false - : metadata.federation.mrf_policies.includes('TagPolicy') + value: + typeof federation.mrf_policies === 'undefined' + ? false + : metadata.federation.mrf_policies.includes('TagPolicy') }) - store.dispatch('setInstanceOption', { name: 'federationPolicy', value: federation }) - store.dispatch('setInstanceOption', { name: 'localBubbleInstances', value: metadata.localBubbleInstances }) + store.dispatch('setInstanceOption', { + name: 'federationPolicy', + value: federation + }) + store.dispatch('setInstanceOption', { + name: 'localBubbleInstances', + value: metadata.localBubbleInstances + }) store.dispatch('setInstanceOption', { name: 'federating', - value: typeof federation.enabled === 'undefined' - ? true - : federation.enabled + value: + typeof federation.enabled === 'undefined' ? true : federation.enabled }) const accountActivationRequired = metadata.accountActivationRequired - store.dispatch('setInstanceOption', { name: 'accountActivationRequired', value: accountActivationRequired }) + store.dispatch('setInstanceOption', { + name: 'accountActivationRequired', + value: accountActivationRequired + }) const accounts = metadata.staffAccounts resolveStaffAccounts({ store, accounts }) } else { - throw (res) + throw res } } catch (e) { console.warn('Could not load nodeinfo') @@ -336,11 +440,16 @@ const getNodeInfo = async ({ store }) => { const setConfig = async ({ store }) => { // apiConfig, staticConfig - const configInfos = await Promise.all([getBackendProvidedConfig({ store }), getStaticConfig()]) + const configInfos = await Promise.all([ + getBackendProvidedConfig({ store }), + getStaticConfig() + ]) const apiConfig = configInfos[0] const staticConfig = configInfos[1] - await setSettings({ store, apiConfig, staticConfig }).then(getAppSecret({ store })) + await setSettings({ store, apiConfig, staticConfig }).then( + getAppSecret({ store }) + ) } const checkOAuthToken = async ({ store }) => { @@ -363,7 +472,10 @@ const afterStoreSetup = async ({ store, i18n }) => { FaviconService.initFaviconService() const overrides = window.___pleromafe_dev_overrides || {} - const server = (typeof overrides.target !== 'undefined') ? overrides.target : window.location.origin + const server = + typeof overrides.target !== 'undefined' + ? overrides.target + : window.location.origin store.dispatch('setInstanceOption', { name: 'server', value: server }) await setConfig({ store }) @@ -373,7 +485,10 @@ const afterStoreSetup = async ({ store, i18n }) => { const customThemePresent = customThemeSource || customTheme if (customThemePresent) { - if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) { + if ( + customThemeSource && + customThemeSource.themeEngineVersion === CURRENT_VERSION + ) { applyTheme(customThemeSource) } else { applyTheme(customTheme) @@ -404,7 +519,7 @@ const afterStoreSetup = async ({ store, i18n }) => { history: createWebHistory(), routes: routes(store), scrollBehavior: (to, _from, savedPosition) => { - if (to.matched.some(m => m.meta.dontScroll)) { + if (to.matched.some((m) => m.meta.dontScroll)) { return {} } diff --git a/src/boot/routes.js b/src/boot/routes.js index 93a94a9b..e2294663 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -35,51 +35,145 @@ export default (store) => { } let routes = [ - { name: 'root', + { + name: 'root', path: '/', - redirect: _to => { - return (store.state.users.currentUser - ? store.state.instance.redirectRootLogin - : store.state.instance.redirectRootNoLogin) || '/main/all' + redirect: (_to) => { + return ( + (store.state.users.currentUser + ? store.state.instance.redirectRootLogin + : store.state.instance.redirectRootNoLogin) || '/main/all' + ) } }, - { name: 'public-external-timeline', path: '/main/all', component: PublicAndExternalTimeline }, - { name: 'public-timeline', path: '/main/public', component: PublicTimeline }, - { name: 'bubble-timeline', path: '/main/bubble', component: BubbleTimeline }, - { name: 'friends', path: '/main/friends', component: FriendsTimeline, beforeEnter: validateAuthenticatedRoute }, + { + name: 'public-external-timeline', + path: '/main/all', + component: PublicAndExternalTimeline + }, + { + name: 'public-timeline', + path: '/main/public', + component: PublicTimeline + }, + { + name: 'bubble-timeline', + path: '/main/bubble', + component: BubbleTimeline + }, + { + name: 'friends', + path: '/main/friends', + component: FriendsTimeline, + beforeEnter: validateAuthenticatedRoute + }, { name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline }, { name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline }, - { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, - { name: 'remote-user-profile-acct', + { + name: 'conversation', + path: '/notice/:id', + component: ConversationPage, + meta: { dontScroll: true } + }, + { + name: 'remote-user-profile-acct', path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)', component: RemoteUserResolver, beforeEnter: validateAuthenticatedRoute }, - { name: 'remote-user-profile', + { + name: 'remote-user-profile', path: '/remote-users/:hostname/:username', component: RemoteUserResolver, beforeEnter: validateAuthenticatedRoute }, - { name: 'external-user-profile', path: '/users/:id', component: UserProfile, meta: { dontScroll: true } }, - { name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute }, - { name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute }, + { + name: 'external-user-profile', + path: '/users/:id', + component: UserProfile, + meta: { dontScroll: true } + }, + { + name: 'interactions', + path: '/users/:username/interactions', + component: Interactions, + beforeEnter: validateAuthenticatedRoute + }, + { + name: 'dms', + path: '/users/:username/dms', + component: DMs, + beforeEnter: validateAuthenticatedRoute + }, { name: 'registration', path: '/registration', component: Registration }, - { name: 'registration-request-sent', path: '/registration-request-sent', component: RegistrationRequestSent }, - { name: 'awaiting-email-confirmation', path: '/awaiting-email-confirmation', component: AwaitingEmailConfirmation }, - { name: 'password-reset', path: '/password-reset', component: PasswordReset, props: true }, - { name: 'registration-token', path: '/registration/:token', component: Registration }, - { name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute }, - { name: 'notifications', path: '/:username/notifications', component: Notifications, props: () => ({ disableTeleport: true }), beforeEnter: validateAuthenticatedRoute }, + { + name: 'registration-request-sent', + path: '/registration-request-sent', + component: RegistrationRequestSent + }, + { + name: 'awaiting-email-confirmation', + path: '/awaiting-email-confirmation', + component: AwaitingEmailConfirmation + }, + { + name: 'password-reset', + path: '/password-reset', + component: PasswordReset, + props: true + }, + { + name: 'registration-token', + path: '/registration/:token', + component: Registration + }, + { + name: 'friend-requests', + path: '/friend-requests', + component: FollowRequests, + beforeEnter: validateAuthenticatedRoute + }, + { + name: 'notifications', + path: '/:username/notifications', + component: Notifications, + props: () => ({ disableTeleport: true }), + beforeEnter: validateAuthenticatedRoute + }, { name: 'login', path: '/login', component: AuthForm }, - { name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) }, - { 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: 'oauth-callback', + path: '/oauth-callback', + component: OAuthCallback, + props: (route) => ({ code: route.query.code }) + }, + { + 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: 'about', path: '/about', component: About }, { name: 'lists', path: '/lists', component: Lists }, { name: 'list-timeline', path: '/lists/:id', component: ListTimeline }, { name: 'list-edit', path: '/lists/:id/edit', component: ListEdit }, - { name: 'announcements', path: '/announcements', component: AnnouncementsPage }, - { name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile, meta: { dontScroll: true } } + { + name: 'announcements', + path: '/announcements', + component: AnnouncementsPage + }, + { + name: 'user-profile', + path: '/:_(users)?/:name', + component: UserProfile, + meta: { dontScroll: true } + } ] return routes diff --git a/src/components/about/about.js b/src/components/about/about.js index 7998c2d3..c8bc9f51 100644 --- a/src/components/about/about.js +++ b/src/components/about/about.js @@ -15,13 +15,17 @@ const About = { LocalBubblePanel }, computed: { - showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, - showInstanceSpecificPanel () { - return this.$store.state.instance.showInstanceSpecificPanel && + showFeaturesPanel() { + return this.$store.state.instance.showFeaturesPanel + }, + showInstanceSpecificPanel() { + return ( + this.$store.state.instance.showInstanceSpecificPanel && !this.$store.getters.mergedConfig.hideISP && this.$store.state.instance.instanceSpecificPanelContent + ) }, - showLocalBubblePanel () { + showLocalBubblePanel() { return this.$store.state.instance.localBubbleInstances.length > 0 } } diff --git a/src/components/about/about.vue b/src/components/about/about.vue index df9bb196..9126b3ff 100644 --- a/src/components/about/about.vue +++ b/src/components/about/about.vue @@ -9,7 +9,6 @@ - + - + diff --git a/src/components/account_actions/account_actions.js b/src/components/account_actions/account_actions.js index 0f348474..92b8679f 100644 --- a/src/components/account_actions/account_actions.js +++ b/src/components/account_actions/account_actions.js @@ -3,19 +3,13 @@ import Popover from '../popover/popover.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { mapState } from 'vuex' -import { - faEllipsisV -} from '@fortawesome/free-solid-svg-icons' +import { faEllipsisV } from '@fortawesome/free-solid-svg-icons' -library.add( - faEllipsisV -) +library.add(faEllipsisV) const AccountActions = { - props: [ - 'user', 'relationship' - ], - data () { + props: ['user', 'relationship'], + data() { return { showingConfirmBlock: false } @@ -26,56 +20,59 @@ const AccountActions = { ConfirmModal }, methods: { - refetchRelationship () { + refetchRelationship() { return this.$store.dispatch('fetchUserRelationship', this.user.id) }, - showConfirmBlock () { + showConfirmBlock() { this.showingConfirmBlock = true }, - hideConfirmBlock () { + hideConfirmBlock() { this.showingConfirmBlock = false }, - showRepeats () { + showRepeats() { this.$store.dispatch('showReblogs', this.user.id) }, - hideRepeats () { + hideRepeats() { this.$store.dispatch('hideReblogs', this.user.id) }, - blockUser () { + blockUser() { if (!this.shouldConfirmBlock) { this.doBlockUser() } else { this.showConfirmBlock() } }, - doBlockUser () { + doBlockUser() { this.$store.dispatch('blockUser', this.user.id) this.hideConfirmBlock() }, - unblockUser () { + unblockUser() { this.$store.dispatch('unblockUser', this.user.id) }, - removeUserFromFollowers () { + removeUserFromFollowers() { this.$store.dispatch('removeUserFromFollowers', this.user.id) }, - reportUser () { + reportUser() { this.$store.dispatch('openUserReportingModal', { userId: this.user.id }) }, - muteDomain () { - this.$store.dispatch('muteDomain', this.user.screen_name.split('@')[1]) + muteDomain() { + this.$store + .dispatch('muteDomain', this.user.screen_name.split('@')[1]) .then(() => this.refetchRelationship()) }, - unmuteDomain () { - this.$store.dispatch('unmuteDomain', this.user.screen_name.split('@')[1]) + unmuteDomain() { + this.$store + .dispatch('unmuteDomain', this.user.screen_name.split('@')[1]) .then(() => this.refetchRelationship()) } }, computed: { - shouldConfirmBlock () { + shouldConfirmBlock() { return this.$store.getters.mergedConfig.modalOnBlock }, ...mapState({ - pleromaChatMessagesAvailable: state => state.instance.pleromaChatMessagesAvailable + pleromaChatMessagesAvailable: (state) => + state.instance.pleromaChatMessagesAvailable }) } } diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue index 126f6fa9..1ad96c7f 100644 --- a/src/components/account_actions/account_actions.vue +++ b/src/components/account_actions/account_actions.vue @@ -6,7 +6,7 @@ :bound-to="{ x: 'container' }" remove-padding > -