mirror of
				https://akkoma.dev/lamp/akkoma-fe.git
				synced 2025-11-03 20:22:09 -05:00 
			
		
		
		
	Compare commits
	
		
			219 Commits
		
	
	
		
			4d91a7b2c3
			...
			589d8ea29f
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 589d8ea29f | |||
| 
						 | 
					52b27396b9 | ||
| 
						 | 
					c2db0e66ef | ||
| 
						 | 
					9f8eba3464 | ||
| 
						 | 
					762676e105 | ||
| 
						 | 
					d6e8d785c8 | ||
| 
						 | 
					1fa242232e | ||
| 
						 | 
					539977de9d | ||
| 
						 | 
					d2995ada16 | ||
| 
						 | 
					bcd15ef858 | ||
| 
						 | 
					900ac68ca6 | ||
| 
						 | 
					34bbcef83e | ||
| 
						 | 
					37ce8352a9 | ||
| 
						 | 
					f48138c979 | ||
| 
						 | 
					5baa2ce40f | ||
| 
						 | 
					fef531b8a0 | ||
| 
						 | 
					bf0c137057 | ||
| 
						 | 
					5a50ceb3aa | ||
| 
						 | 
					f08a961199 | ||
| 
						 | 
					d252e10543 | ||
| 
						 | 
					7c84854b10 | ||
| 
						 | 
					ab606c6160 | ||
| 
						 | 
					38d8a9751a | ||
| 
						 | 
					2c92467dcd | ||
| 
						 | 
					bb71635d12 | ||
| 
						 | 
					e1b4d8f59a | ||
| 
						 | 
					2455bb70f3 | ||
| 
						 | 
					fbc6cd59bc | ||
| 
						 | 
					873048de2e | ||
| 
						 | 
					7a4e2a8644 | ||
| 
						 | 
					a1d92ffd86 | ||
| 
						 | 
					b60f42b959 | ||
| 
						 | 
					55dff3a9bd | ||
| 
						 | 
					9ef8effeed | ||
| 
						 | 
					9c15db16a6 | ||
| 
						 | 
					674a816453 | ||
| 
						 | 
					be2207fa42 | ||
| 
						 | 
					3f3ea32f81 | ||
| 
						 | 
					abc6b299e0 | ||
| 
						 | 
					b8b18c67b1 | ||
| 
						 | 
					4cf4b5e2d0 | ||
| 
						 | 
					d617a9596a | ||
| 
						 | 
					4734e9668d | ||
| 
						 | 
					9787f43343 | ||
| 
						 | 
					61bdedc82f | ||
| 
						 | 
					a4eddc7f1c | ||
| 
						 | 
					94c5998593 | ||
| 
						 | 
					851dd263c0 | ||
| 
						 | 
					473ba89355 | ||
| 
						 | 
					4ce8ffcec1 | ||
| 
						 | 
					e62b154228 | ||
| 
						 | 
					e87a9ced61 | ||
| 
						 | 
					7245775b27 | ||
| 
						 | 
					6373c5a05d | ||
| 
						 | 
					cfbf3ecb6d | ||
| 
						 | 
					2914eaf1ca | ||
| 
						 | 
					578ef52df6 | ||
| 
						 | 
					0bf9cb0660 | ||
| 
						 | 
					65cb3b95e0 | ||
| 
						 | 
					f15b94d566 | ||
| 
						 | 
					06ba190e2e | ||
| 
						 | 
					2086522d64 | ||
| 
						 | 
					cb63cc38c1 | ||
| 
						 | 
					fa294e0003 | ||
| 
						 | 
					d3fa5cfad0 | ||
| 
						 | 
					9552287442 | ||
| 
						 | 
					6b7c8f0def | ||
| 
						 | 
					3386692e26 | ||
| 
						 | 
					ad6bb47003 | ||
| 
						 | 
					9838545904 | ||
| 
						 | 
					868c6e41ac | ||
| 
						 | 
					b3f25e5d84 | ||
| 
						 | 
					248509073e | ||
| 
						 | 
					a7d6235131 | ||
| 
						 | 
					177d96f977 | ||
| 
						 | 
					42ba77ebf4 | ||
| 
						 | 
					4a50b1273d | ||
| 
						 | 
					c76dc6d79e | ||
| 
						 | 
					cb4c581cde | ||
| 
						 | 
					8231c8f0b6 | ||
| 
						 | 
					ef242a1ddd | ||
| 
						 | 
					35cf3327c8 | ||
| 
						 | 
					1ae09458c6 | ||
| 
						 | 
					f391cf70a4 | ||
| 
						 | 
					fa8fde2ab1 | ||
| 
						 | 
					1f2c96a485 | ||
| 
						 | 
					25681cf5f6 | ||
| 
						 | 
					6c178aa257 | ||
| 
						 | 
					6666a273a4 | ||
| 
						 | 
					3210873d7f | ||
| 
						 | 
					f5f9949253 | ||
| 
						 | 
					ba4ae5badb | ||
| 
						 | 
					56a59e1b55 | ||
| 
						 | 
					3065416c93 | ||
| 
						 | 
					94141dcb3c | ||
| 
						 | 
					92e278d406 | ||
| 
						 | 
					3349fe6ff2 | ||
| 
						 | 
					94ed0991bc | ||
| 
						 | 
					e274adf47d | ||
| 
						 | 
					e955eb4503 | ||
| 
						 | 
					c39d9fa64b | ||
| 
						 | 
					a74a631793 | ||
| 
						 | 
					2e83ccefdc | ||
| 
						 | 
					cf11b2523e | ||
| 
						 | 
					8765491399 | ||
| 
						 | 
					85001814a2 | ||
| 
						 | 
					c902219997 | ||
| 
						 | 
					2e2e87db75 | ||
| 
						 | 
					b2af067fd3 | ||
| 
						 | 
					4211e05a75 | ||
| 
						 | 
					a3251a1ba6 | ||
| 
						 | 
					e5608f4009 | ||
| 
						 | 
					1092d43802 | ||
| 
						 | 
					98a3622172 | ||
| 
						 | 
					24b9e350e2 | ||
| 
						 | 
					7ab4d22a4c | ||
| 
						 | 
					8489f6d5ae | ||
| 
						 | 
					754cd2fa57 | ||
| 
						 | 
					31055fb4f2 | ||
| 
						 | 
					918b0e3770 | ||
| 
						 | 
					88aae1706a | ||
| 
						 | 
					3d2a8a3ca2 | ||
| 
						 | 
					a24fff5d5b | ||
| 
						 | 
					4abddf5e6a | ||
| 
						 | 
					1b4df9e79d | ||
| 
						 | 
					45fe334cd7 | ||
| 
						 | 
					dd32a33d59 | ||
| 
						 | 
					74b651a3a2 | ||
| 
						 | 
					21fe7d76d3 | ||
| 
						 | 
					b2cab6d088 | ||
| 
						 | 
					3ebaba6fa7 | ||
| 
						 | 
					f1058567b9 | ||
| 
						 | 
					49a850a1e9 | ||
| 
						 | 
					b2de68239f | ||
| 
						 | 
					c68595345f | ||
| 
						 | 
					a5d4b0a68c | ||
| 
						 | 
					bd263587b2 | ||
| 
						 | 
					c19fb198ca | ||
| 
						 | 
					97966045cb | ||
| 
						 | 
					aad023c8a0 | ||
| 
						 | 
					c952b2335c | ||
| 
						 | 
					0baf31f498 | ||
| 
						 | 
					8fa24d0c40 | ||
| 
						 | 
					5848c18ec8 | ||
| 
						 | 
					54dbead22c | ||
| 
						 | 
					3e86db24d3 | ||
| 
						 | 
					d8f3f5002f | ||
| 
						 | 
					7789c5def6 | ||
| 
						 | 
					a45f482c79 | ||
| 
						 | 
					ed22c480f9 | ||
| 
						 | 
					f3934afbd8 | ||
| 
						 | 
					3797495e53 | ||
| 
						 | 
					0b437ab6fd | ||
| 
						 | 
					a7dea2f70f | ||
| 
						 | 
					2c9da4a58c | ||
| 
						 | 
					8964dce609 | ||
| 
						 | 
					156b036caa | ||
| 
						 | 
					1a49a1b3ac | ||
| 
						 | 
					61d82a2a07 | ||
| 
						 | 
					1adef56603 | ||
| 
						 | 
					b9bf0f0002 | ||
| 
						 | 
					5aaa605df0 | ||
| 
						 | 
					7136ea80b9 | ||
| 
						 | 
					71e287d56c | ||
| 
						 | 
					a64cdda725 | ||
| 
						 | 
					70275684bf | ||
| 
						 | 
					7e7f03aece | ||
| 
						 | 
					29ff2ef455 | ||
| 
						 | 
					8c49474dea | ||
| 
						 | 
					62e0dd858c | ||
| 
						 | 
					cc709394c5 | ||
| 
						 | 
					57beea6a0d | ||
| 
						 | 
					45524552a0 | ||
| 
						 | 
					ee66b69ab5 | ||
| 
						 | 
					d42e374704 | ||
| 
						 | 
					ce8a9d2b4a | ||
| 
						 | 
					d2b7ac6d8c | ||
| 
						 | 
					754c72cb24 | ||
| 
						 | 
					f5bd195422 | ||
| 
						 | 
					d49fd46554 | ||
| 
						 | 
					9982373853 | ||
| 
						 | 
					5206b5cf9c | ||
| 
						 | 
					a65a06ca04 | ||
| 
						 | 
					c10b38afbc | ||
| 
						 | 
					009941ea2c | ||
| 
						 | 
					042e8c78dc | ||
| 
						 | 
					0e07d88afa | ||
| 
						 | 
					1f5f8665c8 | ||
| 
						 | 
					428ed70b0d | ||
| 
						 | 
					7cc6c35654 | ||
| 
						 | 
					228679e49e | ||
| 
						 | 
					d610a46c32 | ||
| 
						 | 
					0925763267 | ||
| 
						 | 
					e292af4211 | ||
| 
						 | 
					4e7d5d3a08 | ||
| 
						 | 
					f2d0c4c7d5 | ||
| 
						 | 
					02a6591f20 | ||
| 
						 | 
					94c70f8914 | ||
| 
						 | 
					3ba8c90e1e | ||
| 
						 | 
					83db80f88c | ||
| 
						 | 
					1489d92997 | ||
| 
						 | 
					db5c9572dc | ||
| 
						 | 
					5bb53c8b0d | ||
| 
						 | 
					665f88f5c7 | ||
| 
						 | 
					e7a558a533 | ||
| 
						 | 
					5106fcedd6 | ||
| 
						 | 
					1db322bae6 | ||
| 
						 | 
					e530c2b462 | ||
| 
						 | 
					9aa64d82c9 | ||
| 
						 | 
					85abc62213 | ||
| 
						 | 
					8569b5946e | ||
| 
						 | 
					9c9b4cc07c | ||
| 
						 | 
					2c9b73646c | ||
| 
						 | 
					80a519d7e4 | ||
| 
						 | 
					975f04bf5a | ||
| 
						 | 
					c8c8d40827 | ||
| 
						 | 
					d7499a1f91 | ||
| 
						 | 
					5972d89117 | ||
| 
						 | 
					d03872d598 | 
@ -1,2 +0,0 @@
 | 
				
			|||||||
build/*.js
 | 
					 | 
				
			||||||
config/*.js
 | 
					 | 
				
			||||||
							
								
								
									
										30
									
								
								.eslintrc.js
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								.eslintrc.js
									
									
									
									
									
								
							@ -1,30 +0,0 @@
 | 
				
			|||||||
module.exports = {
 | 
					 | 
				
			||||||
  root: true,
 | 
					 | 
				
			||||||
  parserOptions: {
 | 
					 | 
				
			||||||
    parser: '@babel/eslint-parser',
 | 
					 | 
				
			||||||
    sourceType: 'module'
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
 | 
					 | 
				
			||||||
  extends: [
 | 
					 | 
				
			||||||
    'plugin:vue/recommended'
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  // required to lint *.vue files
 | 
					 | 
				
			||||||
  plugins: [
 | 
					 | 
				
			||||||
    'vue',
 | 
					 | 
				
			||||||
    'import'
 | 
					 | 
				
			||||||
  ],
 | 
					 | 
				
			||||||
  // add your custom rules here
 | 
					 | 
				
			||||||
  rules: {
 | 
					 | 
				
			||||||
    // allow paren-less arrow functions
 | 
					 | 
				
			||||||
    'arrow-parens': 0,
 | 
					 | 
				
			||||||
    // allow async-await
 | 
					 | 
				
			||||||
    'generator-star-spacing': 0,
 | 
					 | 
				
			||||||
    // allow debugger during development
 | 
					 | 
				
			||||||
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
 | 
					 | 
				
			||||||
    'vue/require-prop-types': 0,
 | 
					 | 
				
			||||||
    'vue/no-unused-vars': 0,
 | 
					 | 
				
			||||||
    'no-tabs': 0,
 | 
					 | 
				
			||||||
    'vue/multi-word-component-names': 0,
 | 
					 | 
				
			||||||
    'vue/no-reserved-component-names': 0
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@ -1 +0,0 @@
 | 
				
			|||||||
7.2.1
 | 
					 | 
				
			||||||
							
								
								
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.tool-versions
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					nodejs 20.12.2
 | 
				
			||||||
@ -1,20 +1,21 @@
 | 
				
			|||||||
platform: linux/amd64
 | 
					labels:
 | 
				
			||||||
pipeline:
 | 
					  platform: linux/amd64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					steps:
 | 
				
			||||||
  lint:
 | 
					  lint:
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event:
 | 
					      event:
 | 
				
			||||||
      - pull_request
 | 
					      - pull_request
 | 
				
			||||||
    image: node:18
 | 
					    image: node:20
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
    - yarn
 | 
					    - yarn
 | 
				
			||||||
    - yarn lint
 | 
					    - yarn lint
 | 
				
			||||||
    #- yarn stylelint
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  test:
 | 
					  test:
 | 
				
			||||||
    when:
 | 
					    when:
 | 
				
			||||||
      event:
 | 
					      event:
 | 
				
			||||||
      - pull_request
 | 
					      - pull_request
 | 
				
			||||||
    image: node:18
 | 
					    image: node:20
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
    - apt update
 | 
					    - apt update
 | 
				
			||||||
    - apt install firefox-esr -y --no-install-recommends
 | 
					    - apt install firefox-esr -y --no-install-recommends
 | 
				
			||||||
@ -28,7 +29,7 @@ pipeline:
 | 
				
			|||||||
      branch:
 | 
					      branch:
 | 
				
			||||||
      - develop
 | 
					      - develop
 | 
				
			||||||
      - stable
 | 
					      - stable
 | 
				
			||||||
    image: node:18
 | 
					    image: node:20
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
    - yarn
 | 
					    - yarn
 | 
				
			||||||
    - yarn build
 | 
					    - yarn build
 | 
				
			||||||
@ -40,15 +41,18 @@ pipeline:
 | 
				
			|||||||
      branch:
 | 
					      branch:
 | 
				
			||||||
      - develop
 | 
					      - develop
 | 
				
			||||||
      - stable
 | 
					      - stable
 | 
				
			||||||
    image: node:18
 | 
					    image: node:20
 | 
				
			||||||
    secrets:
 | 
					    environment:
 | 
				
			||||||
    - SCW_ACCESS_KEY
 | 
					      SCW_ACCESS_KEY:
 | 
				
			||||||
    - SCW_SECRET_KEY
 | 
					        from_secret: SCW_ACCESS_KEY
 | 
				
			||||||
    - SCW_DEFAULT_ORGANIZATION_ID
 | 
					      SCW_SECRET_KEY:
 | 
				
			||||||
 | 
					        from_secret: SCW_SECRET_KEY
 | 
				
			||||||
 | 
					      SCW_DEFAULT_ORGANIZATION_ID:
 | 
				
			||||||
 | 
					        from_secret: SCW_DEFAULT_ORGANIZATION_ID
 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
      - apt-get update && apt-get install -y rclone wget zip
 | 
					      - apt-get update && apt-get install -y rclone wget zip
 | 
				
			||||||
      - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64
 | 
					      - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.30.0/scaleway-cli_2.30.0_linux_amd64
 | 
				
			||||||
      - mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli
 | 
					      - mv scaleway-cli_2.30.0_linux_amd64 scaleway-cli
 | 
				
			||||||
      - chmod +x scaleway-cli
 | 
					      - chmod +x scaleway-cli
 | 
				
			||||||
      - ./scaleway-cli object config install type=rclone
 | 
					      - ./scaleway-cli object config install type=rclone
 | 
				
			||||||
      - zip akkoma-fe.zip -r dist
 | 
					      - zip akkoma-fe.zip -r dist
 | 
				
			||||||
@ -63,15 +67,17 @@ pipeline:
 | 
				
			|||||||
      - stable
 | 
					      - stable
 | 
				
			||||||
    environment:
 | 
					    environment:
 | 
				
			||||||
      CI: "true"
 | 
					      CI: "true"
 | 
				
			||||||
 | 
					      SCW_ACCESS_KEY:
 | 
				
			||||||
 | 
					        from_secret: SCW_ACCESS_KEY
 | 
				
			||||||
 | 
					      SCW_SECRET_KEY:
 | 
				
			||||||
 | 
					        from_secret: SCW_SECRET_KEY
 | 
				
			||||||
 | 
					      SCW_DEFAULT_ORGANIZATION_ID:
 | 
				
			||||||
 | 
					        from_secret: SCW_DEFAULT_ORGANIZATION_ID
 | 
				
			||||||
    image: python:3.10-slim
 | 
					    image: python:3.10-slim
 | 
				
			||||||
    secrets:
 | 
					 | 
				
			||||||
    - SCW_ACCESS_KEY
 | 
					 | 
				
			||||||
    - SCW_SECRET_KEY
 | 
					 | 
				
			||||||
    - SCW_DEFAULT_ORGANIZATION_ID
 | 
					 | 
				
			||||||
    commands:
 | 
					    commands:
 | 
				
			||||||
    - apt-get update && apt-get install -y rclone wget git zip
 | 
					    - apt-get update && apt-get install -y rclone wget git zip
 | 
				
			||||||
    - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64
 | 
					    - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.30.0/scaleway-cli_2.30.0_linux_amd64
 | 
				
			||||||
    - mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli
 | 
					    - mv scaleway-cli_2.30.0_linux_amd64 scaleway-cli
 | 
				
			||||||
    - chmod +x scaleway-cli
 | 
					    - chmod +x scaleway-cli
 | 
				
			||||||
    - ./scaleway-cli object config install type=rclone
 | 
					    - ./scaleway-cli object config install type=rclone
 | 
				
			||||||
    - cd docs
 | 
					    - cd docs
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,8 @@ To use Akkoma-FE in Akkoma, use the [frontend](https://docs.akkoma.dev/stable/ad
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
## Build Setup
 | 
					## Build Setup
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Make sure you have [Node.js](https://nodejs.org/) installed. You can check `/.woodpecker.yml` for which node version the Akkoma CI currently uses.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
``` bash
 | 
					``` bash
 | 
				
			||||||
# install dependencies
 | 
					# install dependencies
 | 
				
			||||||
corepack enable
 | 
					corepack enable
 | 
				
			||||||
 | 
				
			|||||||
@ -1,36 +1,36 @@
 | 
				
			|||||||
// https://github.com/shelljs/shelljs
 | 
					// https://github.com/shelljs/shelljs
 | 
				
			||||||
require('./check-versions')()
 | 
					require("./check-versions")();
 | 
				
			||||||
require('shelljs/global')
 | 
					require("shelljs/global");
 | 
				
			||||||
env.NODE_ENV = 'production'
 | 
					env.NODE_ENV = "production";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var path = require('path')
 | 
					var path = require("path");
 | 
				
			||||||
var config = require('../config')
 | 
					var config = require("../config");
 | 
				
			||||||
var ora = require('ora')
 | 
					var webpack = require("webpack");
 | 
				
			||||||
var webpack = require('webpack')
 | 
					var webpackConfig = require("./webpack.prod.conf");
 | 
				
			||||||
var webpackConfig = require('./webpack.prod.conf')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
console.log(
 | 
					console.log(
 | 
				
			||||||
  '  Tip:\n' +
 | 
					  "  Tip:\n" +
 | 
				
			||||||
  '  Built files are meant to be served over an HTTP server.\n' +
 | 
					    "  Built files are meant to be served over an HTTP server.\n" +
 | 
				
			||||||
  '  Opening index.html over file:// won\'t work.\n'
 | 
					    "  Opening index.html over file:// won't work.\n",
 | 
				
			||||||
)
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var spinner = ora('building for production...')
 | 
					var assetsPath = path.join(
 | 
				
			||||||
spinner.start()
 | 
					  config.build.assetsRoot,
 | 
				
			||||||
 | 
					  config.build.assetsSubDirectory,
 | 
				
			||||||
var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory)
 | 
					);
 | 
				
			||||||
rm('-rf', assetsPath)
 | 
					rm("-rf", assetsPath);
 | 
				
			||||||
mkdir('-p', assetsPath)
 | 
					mkdir("-p", assetsPath);
 | 
				
			||||||
cp('-R', 'static/*', assetsPath)
 | 
					cp("-R", "static/*", assetsPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
webpack(webpackConfig, function (err, stats) {
 | 
					webpack(webpackConfig, function (err, stats) {
 | 
				
			||||||
  spinner.stop()
 | 
					  if (err) throw err;
 | 
				
			||||||
  if (err) throw err
 | 
					  process.stdout.write(
 | 
				
			||||||
  process.stdout.write(stats.toString({
 | 
					    stats.toString({
 | 
				
			||||||
      colors: true,
 | 
					      colors: true,
 | 
				
			||||||
      modules: false,
 | 
					      modules: false,
 | 
				
			||||||
      children: false,
 | 
					      children: false,
 | 
				
			||||||
      chunks: false,
 | 
					      chunks: false,
 | 
				
			||||||
    chunkModules: false
 | 
					      chunkModules: false,
 | 
				
			||||||
  }) + '\n')
 | 
					    }) + "\n",
 | 
				
			||||||
})
 | 
					  );
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@ var path = require('path')
 | 
				
			|||||||
var express = require('express')
 | 
					var express = require('express')
 | 
				
			||||||
var webpack = require('webpack')
 | 
					var webpack = require('webpack')
 | 
				
			||||||
var opn = require('opn')
 | 
					var opn = require('opn')
 | 
				
			||||||
var proxyMiddleware = require('http-proxy-middleware')
 | 
					const { createProxyMiddleware } = require('http-proxy-middleware');
 | 
				
			||||||
var webpackConfig = process.env.NODE_ENV === 'testing'
 | 
					var webpackConfig = process.env.NODE_ENV === 'testing'
 | 
				
			||||||
  ? require('./webpack.prod.conf')
 | 
					  ? require('./webpack.prod.conf')
 | 
				
			||||||
  : require('./webpack.dev.conf')
 | 
					  : require('./webpack.dev.conf')
 | 
				
			||||||
@ -36,7 +36,13 @@ 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))
 | 
					  const targetUrl = new URL(options.target);
 | 
				
			||||||
 | 
					  // add path
 | 
				
			||||||
 | 
					  targetUrl.pathname = context;
 | 
				
			||||||
 | 
					  options.target = targetUrl.toString();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  console.log("Proxying", context, "to", options.target);
 | 
				
			||||||
 | 
					  app.use(context, createProxyMiddleware(options))
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// handle fallback for HTML5 history API
 | 
					// handle fallback for HTML5 history API
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@ var config = require('../config')
 | 
				
			|||||||
var utils = require('./utils')
 | 
					var utils = require('./utils')
 | 
				
			||||||
var projectRoot = path.resolve(__dirname, '../')
 | 
					var projectRoot = path.resolve(__dirname, '../')
 | 
				
			||||||
var { VueLoaderPlugin } = require('vue-loader')
 | 
					var { VueLoaderPlugin } = require('vue-loader')
 | 
				
			||||||
 | 
					const ESLintPlugin = require('eslint-webpack-plugin');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
var env = process.env.NODE_ENV
 | 
					var env = process.env.NODE_ENV
 | 
				
			||||||
// check env & config/index.js to decide weither to enable CSS Sourcemaps for the
 | 
					// check env & config/index.js to decide weither to enable CSS Sourcemaps for the
 | 
				
			||||||
@ -35,6 +36,7 @@ module.exports = {
 | 
				
			|||||||
    ],
 | 
					    ],
 | 
				
			||||||
    fallback: {
 | 
					    fallback: {
 | 
				
			||||||
      "url": require.resolve("url/"),
 | 
					      "url": require.resolve("url/"),
 | 
				
			||||||
 | 
					      querystring: require.resolve("querystring-es3")
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    alias: {
 | 
					    alias: {
 | 
				
			||||||
      'static': path.resolve(__dirname, '../static'),
 | 
					      'static': path.resolve(__dirname, '../static'),
 | 
				
			||||||
@ -47,20 +49,6 @@ module.exports = {
 | 
				
			|||||||
  module: {
 | 
					  module: {
 | 
				
			||||||
    noParse: /node_modules\/localforage\/dist\/localforage.js/,
 | 
					    noParse: /node_modules\/localforage\/dist\/localforage.js/,
 | 
				
			||||||
    rules: [
 | 
					    rules: [
 | 
				
			||||||
      {
 | 
					 | 
				
			||||||
        enforce: 'pre',
 | 
					 | 
				
			||||||
        test: /\.(js|vue)$/,
 | 
					 | 
				
			||||||
        include: projectRoot,
 | 
					 | 
				
			||||||
        exclude: /node_modules/,
 | 
					 | 
				
			||||||
        use: {
 | 
					 | 
				
			||||||
          loader: 'eslint-loader',
 | 
					 | 
				
			||||||
          options: {
 | 
					 | 
				
			||||||
            formatter: require('eslint-friendly-formatter'),
 | 
					 | 
				
			||||||
            sourceMap: config.build.productionSourceMap,
 | 
					 | 
				
			||||||
            extract: true
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      },
 | 
					 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
        enforce: 'post',
 | 
					        enforce: 'post',
 | 
				
			||||||
        test: /\.(json5?|ya?ml)$/, // target json, json5, yaml and yml files
 | 
					        test: /\.(json5?|ya?ml)$/, // target json, json5, yaml and yml files
 | 
				
			||||||
@ -118,6 +106,9 @@ module.exports = {
 | 
				
			|||||||
    ]
 | 
					    ]
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  plugins: [
 | 
					  plugins: [
 | 
				
			||||||
    new VueLoaderPlugin()
 | 
					    new VueLoaderPlugin(),
 | 
				
			||||||
 | 
					    new ESLintPlugin({
 | 
				
			||||||
 | 
					      configType: 'flat'
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
  ]
 | 
					  ]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -2,5 +2,4 @@ var { merge } = require('webpack-merge')
 | 
				
			|||||||
var devEnv = require('./dev.env')
 | 
					var devEnv = require('./dev.env')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
module.exports = merge(devEnv, {
 | 
					module.exports = merge(devEnv, {
 | 
				
			||||||
  NODE_ENV: '"testing"'
 | 
					 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
 | 
				
			|||||||
@ -15,12 +15,13 @@ put a file that looks like this
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
```json
 | 
					```json
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  "myPack": "/static/stickers/myPack"
 | 
					  "myPack": "/static/stickers/myPack/"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
This file is a mapping from name to pack directory location. It says "we have a pack called myPack, look for
 | 
					This file is a mapping from name to pack directory location. It says "we have a pack called myPack, look for
 | 
				
			||||||
it at `/static/stickers/myPack`". You can add as many packs as you like in this manner.
 | 
					it inside `/static/stickers/myPack`". You can add as many packs as you like in this manner.
 | 
				
			||||||
 | 
					Note that a single leading and a trailing slash are **required** to work correctly!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Creating the pack
 | 
					## Creating the pack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										31
									
								
								eslint.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								eslint.config.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					const pluginVue = require('eslint-plugin-vue')
 | 
				
			||||||
 | 
					const pluginImport = require('eslint-plugin-import')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = [
 | 
				
			||||||
 | 
					  ...pluginVue.configs['flat/recommended'],
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    languageOptions: {
 | 
				
			||||||
 | 
					      parserOptions: {
 | 
				
			||||||
 | 
					        parser: '@babel/eslint-parser',
 | 
				
			||||||
 | 
					        sourceType: 'module'
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    rules: {
 | 
				
			||||||
 | 
					      // allow paren-less arrow functions
 | 
				
			||||||
 | 
					      'arrow-parens': 0,
 | 
				
			||||||
 | 
					      // allow async-await
 | 
				
			||||||
 | 
					      'generator-star-spacing': 0,
 | 
				
			||||||
 | 
					      // allow debugger during development
 | 
				
			||||||
 | 
					      'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
 | 
				
			||||||
 | 
					      'vue/require-prop-types': 0,
 | 
				
			||||||
 | 
					      'vue/no-unused-vars': 0,
 | 
				
			||||||
 | 
					      'no-tabs': 0,
 | 
				
			||||||
 | 
					      'vue/multi-word-component-names': 0,
 | 
				
			||||||
 | 
					      'vue/no-reserved-component-names': 0
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    ignores: [
 | 
				
			||||||
 | 
					      'build/*.js',
 | 
				
			||||||
 | 
					      'config/*.js'
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
@ -6,7 +6,6 @@
 | 
				
			|||||||
    <title>Akkoma</title>
 | 
					    <title>Akkoma</title>
 | 
				
			||||||
    <link rel="stylesheet" href="/static/font/tiresias.css">
 | 
					    <link rel="stylesheet" href="/static/font/tiresias.css">
 | 
				
			||||||
    <link rel="stylesheet" href="/static/font/css/lato.css">
 | 
					    <link rel="stylesheet" href="/static/font/css/lato.css">
 | 
				
			||||||
    <link rel="stylesheet" href="/static/mfm.css">
 | 
					 | 
				
			||||||
    <link rel="stylesheet" href="/static/custom.css">
 | 
					    <link rel="stylesheet" href="/static/custom.css">
 | 
				
			||||||
    <link rel="stylesheet" href="/static/theme-holder.css" id="theme-holder">
 | 
					    <link rel="stylesheet" href="/static/theme-holder.css" id="theme-holder">
 | 
				
			||||||
    <!--server-generated-meta-->
 | 
					    <!--server-generated-meta-->
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										164
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										164
									
								
								package.json
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "name": "pleroma_fe",
 | 
					  "name": "pleroma_fe",
 | 
				
			||||||
  "version": "3.10.0",
 | 
					  "version": "3.12.0",
 | 
				
			||||||
  "description": "A frontend for Akkoma instances",
 | 
					  "description": "A frontend for Akkoma instances",
 | 
				
			||||||
  "author": "Roger Braun <roger@rogerbraun.net>",
 | 
					  "author": "Roger Braun <roger@rogerbraun.net>",
 | 
				
			||||||
  "private": true,
 | 
					  "private": true,
 | 
				
			||||||
@ -12,120 +12,118 @@
 | 
				
			|||||||
    "e2e": "node test/e2e/runner.js",
 | 
					    "e2e": "node test/e2e/runner.js",
 | 
				
			||||||
    "test": "npm run unit && npm run e2e",
 | 
					    "test": "npm run unit && npm run e2e",
 | 
				
			||||||
    "stylelint": "stylelint src/**/*.scss",
 | 
					    "stylelint": "stylelint src/**/*.scss",
 | 
				
			||||||
    "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs",
 | 
					    "lint": "eslint src test/unit/specs test/e2e/specs",
 | 
				
			||||||
    "lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
 | 
					    "lint-fix": "eslint --fix src test/unit/specs test/e2e/specs"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "@babel/runtime": "7.17.8",
 | 
					    "@babel/runtime": "7.17.8",
 | 
				
			||||||
    "@chenfengyuan/vue-qrcode": "2.0.0",
 | 
					    "@chenfengyuan/vue-qrcode": "^2.0.0",
 | 
				
			||||||
    "@floatingghost/pinch-zoom-element": "^1.3.1",
 | 
					    "@floatingghost/pinch-zoom-element": "^1.3.1",
 | 
				
			||||||
    "@fortawesome/fontawesome-svg-core": "1.3.0",
 | 
					    "@fortawesome/fontawesome-svg-core": "^6.5.2",
 | 
				
			||||||
    "@fortawesome/free-regular-svg-icons": "^6.1.2",
 | 
					    "@fortawesome/free-regular-svg-icons": "^6.5.2",
 | 
				
			||||||
    "@fortawesome/free-solid-svg-icons": "^6.2.0",
 | 
					    "@fortawesome/free-solid-svg-icons": "^6.5.2",
 | 
				
			||||||
    "@fortawesome/vue-fontawesome": "3.0.1",
 | 
					    "@fortawesome/vue-fontawesome": "^3.0.8",
 | 
				
			||||||
    "@vuelidate/core": "^2.0.0",
 | 
					    "@vuelidate/core": "^2.0.3",
 | 
				
			||||||
    "@vuelidate/validators": "^2.0.0",
 | 
					    "@vuelidate/validators": "^2.0.4",
 | 
				
			||||||
    "blurhash": "^2.0.4",
 | 
					    "blurhash": "^2.0.5",
 | 
				
			||||||
    "body-scroll-lock": "2.7.1",
 | 
					    "body-scroll-lock": "^3.1.5",
 | 
				
			||||||
    "chromatism": "3.0.0",
 | 
					    "chromatism": "^3.0.0",
 | 
				
			||||||
    "click-outside-vue3": "4.0.1",
 | 
					    "click-outside-vue3": "^4.0.1",
 | 
				
			||||||
    "cropperjs": "1.5.12",
 | 
					    "cropperjs": "^1.6.2",
 | 
				
			||||||
    "diff": "3.5.0",
 | 
					    "diff": "^5.2.0",
 | 
				
			||||||
    "escape-html": "1.0.3",
 | 
					    "escape-html": "^1.0.3",
 | 
				
			||||||
    "iso-639-1": "^2.1.15",
 | 
					    "iso-639-1": "^2.1.15",
 | 
				
			||||||
    "js-cookie": "^3.0.1",
 | 
					    "js-cookie": "^3.0.1",
 | 
				
			||||||
    "localforage": "1.10.0",
 | 
					    "localforage": "^1.10.0",
 | 
				
			||||||
    "parse-link-header": "^2.0.0",
 | 
					    "parse-link-header": "^2.0.0",
 | 
				
			||||||
    "phoenix": "1.6.2",
 | 
					    "phoenix": "^1.7.12",
 | 
				
			||||||
    "punycode.js": "2.1.0",
 | 
					    "punycode.js": "^2.3.1",
 | 
				
			||||||
    "qrcode": "1",
 | 
					    "qrcode": "^1.5.3",
 | 
				
			||||||
    "url": "^0.11.0",
 | 
					    "querystring-es3": "^0.2.1",
 | 
				
			||||||
    "vue": "^3.2.31",
 | 
					    "url": "^0.11.3",
 | 
				
			||||||
    "vue-i18n": "^9.2.2",
 | 
					    "vue": "^3.4.38",
 | 
				
			||||||
    "vue-router": "4.0.14",
 | 
					    "vue-i18n": "^9.14.0",
 | 
				
			||||||
    "vue-template-compiler": "2.6.11",
 | 
					    "vue-router": "^4.4.3",
 | 
				
			||||||
    "vuex": "4.0.2"
 | 
					    "vue-template-compiler": "^2.7.16",
 | 
				
			||||||
 | 
					    "vuex": "^4.1.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "@babel/core": "7.17.8",
 | 
					    "@babel/core": "^7.24.6",
 | 
				
			||||||
    "@babel/eslint-parser": "^7.19.1",
 | 
					    "@babel/eslint-parser": "^7.19.1",
 | 
				
			||||||
    "@babel/plugin-transform-runtime": "7.17.0",
 | 
					    "@babel/plugin-transform-runtime": "^7.24.6",
 | 
				
			||||||
    "@babel/preset-env": "7.16.11",
 | 
					    "@babel/preset-env": "^7.24.6",
 | 
				
			||||||
    "@babel/register": "7.17.7",
 | 
					    "@babel/register": "^7.24.6",
 | 
				
			||||||
    "@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.4",
 | 
				
			||||||
    "@vue/babel-helper-vue-jsx-merge-props": "1.2.1",
 | 
					    "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0",
 | 
				
			||||||
    "@vue/babel-plugin-jsx": "1.1.1",
 | 
					    "@vue/babel-plugin-jsx": "^1.2.2",
 | 
				
			||||||
    "@vue/compiler-sfc": "^3.1.0",
 | 
					    "@vue/compiler-sfc": "^3.1.0",
 | 
				
			||||||
    "@vue/test-utils": "^2.0.2",
 | 
					    "@vue/test-utils": "^2.0.2",
 | 
				
			||||||
    "autoprefixer": "6.7.7",
 | 
					    "autoprefixer": "^10.4.19",
 | 
				
			||||||
    "babel-loader": "^9.1.0",
 | 
					    "babel-loader": "^9.1.0",
 | 
				
			||||||
    "babel-plugin-lodash": "3.3.4",
 | 
					    "babel-plugin-lodash": "^3.3.4",
 | 
				
			||||||
    "chai": "^4.3.7",
 | 
					    "chai": "^4.3.7",
 | 
				
			||||||
    "chalk": "1.1.3",
 | 
					    "chalk": "^1.1.3",
 | 
				
			||||||
    "chromedriver": "^107.0.3",
 | 
					    "chromedriver": "^119.0.1",
 | 
				
			||||||
    "connect-history-api-fallback": "^2.0.0",
 | 
					    "connect-history-api-fallback": "^2.0.0",
 | 
				
			||||||
    "cross-spawn": "^7.0.3",
 | 
					    "cross-spawn": "^7.0.3",
 | 
				
			||||||
    "css-loader": "^6.7.2",
 | 
					    "css-loader": "^7.1.2",
 | 
				
			||||||
    "custom-event-polyfill": "^1.0.7",
 | 
					    "custom-event-polyfill": "^1.0.7",
 | 
				
			||||||
    "eslint": "^7.32.0",
 | 
					    "eslint": "^9.3.0",
 | 
				
			||||||
    "eslint-config-standard": "^17.0.0",
 | 
					    "eslint-config-standard": "^17.1.0",
 | 
				
			||||||
    "eslint-friendly-formatter": "^4.0.1",
 | 
					    "eslint-friendly-formatter": "^4.0.1",
 | 
				
			||||||
    "eslint-loader": "^4.0.2",
 | 
					    "eslint-plugin-import": "^2.29.1",
 | 
				
			||||||
    "eslint-plugin-import": "^2.26.0",
 | 
					 | 
				
			||||||
    "eslint-plugin-node": "^11.1.0",
 | 
					    "eslint-plugin-node": "^11.1.0",
 | 
				
			||||||
    "eslint-plugin-promise": "^6.1.1",
 | 
					    "eslint-plugin-promise": "^6.2.0",
 | 
				
			||||||
    "eslint-plugin-standard": "^5.0.0",
 | 
					    "eslint-plugin-standard": "^5.0.0",
 | 
				
			||||||
    "eslint-plugin-vue": "^9.7.0",
 | 
					    "eslint-plugin-vue": "^9.26.0",
 | 
				
			||||||
    "eventsource-polyfill": "0.9.6",
 | 
					    "eslint-webpack-plugin": "^4.2.0",
 | 
				
			||||||
    "express": "4.17.3",
 | 
					    "eventsource-polyfill": "^0.9.6",
 | 
				
			||||||
 | 
					    "express": "^4.19.2",
 | 
				
			||||||
    "file-loader": "^6.2.0",
 | 
					    "file-loader": "^6.2.0",
 | 
				
			||||||
    "function-bind": "1.1.1",
 | 
					    "function-bind": "^1.1.2",
 | 
				
			||||||
    "html-webpack-plugin": "^5.5.0",
 | 
					    "html-webpack-plugin": "^5.5.0",
 | 
				
			||||||
    "http-proxy-middleware": "0.21.0",
 | 
					    "http-proxy-middleware": "^3.0.0",
 | 
				
			||||||
    "inject-loader": "2.0.1",
 | 
					    "json-loader": "^0.5.7",
 | 
				
			||||||
    "isparta-loader": "2.0.0",
 | 
					    "karma": "^6.4.3",
 | 
				
			||||||
    "json-loader": "0.5.7",
 | 
					    "karma-coverage": "^2.2.1",
 | 
				
			||||||
    "karma": "6.3.17",
 | 
					    "karma-firefox-launcher": "^2.1.3",
 | 
				
			||||||
    "karma-coverage": "1.1.2",
 | 
					    "karma-mocha": "^2.0.1",
 | 
				
			||||||
    "karma-firefox-launcher": "1.3.0",
 | 
					    "karma-mocha-reporter": "^2.2.5",
 | 
				
			||||||
    "karma-mocha": "2.0.1",
 | 
					    "karma-sinon-chai": "^2.0.2",
 | 
				
			||||||
    "karma-mocha-reporter": "2.2.5",
 | 
					    "karma-sourcemap-loader": "^0.4.0",
 | 
				
			||||||
    "karma-sinon-chai": "2.0.2",
 | 
					    "karma-spec-reporter": "^0.0.36",
 | 
				
			||||||
    "karma-sourcemap-loader": "0.3.8",
 | 
					 | 
				
			||||||
    "karma-spec-reporter": "0.0.33",
 | 
					 | 
				
			||||||
    "karma-webpack": "^5.0.0",
 | 
					    "karma-webpack": "^5.0.0",
 | 
				
			||||||
    "lodash": "4.17.21",
 | 
					    "lodash": "^4.17.21",
 | 
				
			||||||
    "lolex": "1.6.0",
 | 
					    "lolex": "^6.0.0",
 | 
				
			||||||
    "mini-css-extract-plugin": "0.12.0",
 | 
					    "mini-css-extract-plugin": "^2.9.0",
 | 
				
			||||||
    "mocha": "3.5.3",
 | 
					    "mocha": "^10.4.0",
 | 
				
			||||||
    "nightwatch": "0.9.21",
 | 
					    "nightwatch": "^3.6.3",
 | 
				
			||||||
    "opn": "4.0.2",
 | 
					    "opn": "^6.0.0",
 | 
				
			||||||
    "ora": "0.4.1",
 | 
					 | 
				
			||||||
    "postcss-html": "^1.5.0",
 | 
					    "postcss-html": "^1.5.0",
 | 
				
			||||||
    "postcss-loader": "3.0.0",
 | 
					    "postcss-loader": "^8.1.1",
 | 
				
			||||||
    "postcss-sass": "^0.5.0",
 | 
					    "postcss-sass": "^0.5.0",
 | 
				
			||||||
    "raw-loader": "0.5.1",
 | 
					    "raw-loader": "^4.0.2",
 | 
				
			||||||
    "sass": "^1.56.0",
 | 
					    "sass": "^1.77.2",
 | 
				
			||||||
    "sass-loader": "^13.2.0",
 | 
					    "sass-loader": "^14.2.1",
 | 
				
			||||||
    "selenium-server": "2.53.1",
 | 
					    "selenium-server": "^3.141.59",
 | 
				
			||||||
    "semver": "5.7.1",
 | 
					    "semver": "^7.6.2",
 | 
				
			||||||
    "shelljs": "0.8.5",
 | 
					    "shelljs": "^0.8.5",
 | 
				
			||||||
    "sinon": "2.4.1",
 | 
					    "sinon": "^18.0.0",
 | 
				
			||||||
    "sinon-chai": "2.14.0",
 | 
					    "sinon-chai": "^3.7.0",
 | 
				
			||||||
    "stylelint": "^14.15.0",
 | 
					    "stylelint": "^14.15.0",
 | 
				
			||||||
    "stylelint-config-recommended-vue": "^1.4.0",
 | 
					    "stylelint-config-recommended-vue": "^1.4.0",
 | 
				
			||||||
    "stylelint-config-standard": "^29.0.0",
 | 
					    "stylelint-config-standard": "^29.0.0",
 | 
				
			||||||
    "stylelint-config-standard-scss": "^6.1.0",
 | 
					    "stylelint-config-standard-scss": "^6.1.0",
 | 
				
			||||||
    "stylelint-rscss": "^0.4.0",
 | 
					    "stylelint-rscss": "^0.4.0",
 | 
				
			||||||
    "url-loader": "^4.1.1",
 | 
					    "url-loader": "^4.1.1",
 | 
				
			||||||
    "vue-loader": "^17.0.0",
 | 
					    "vue-loader": "^17.4.2",
 | 
				
			||||||
    "vue-style-loader": "^4.1.2",
 | 
					    "vue-style-loader": "^4.1.3",
 | 
				
			||||||
    "webpack": "^5.75.0",
 | 
					    "webpack": "^5.91.0",
 | 
				
			||||||
    "webpack-dev-middleware": "^5.3.3",
 | 
					    "webpack-dev-middleware": "^7.2.1",
 | 
				
			||||||
    "webpack-hot-middleware": "^2.25.1",
 | 
					    "webpack-hot-middleware": "^2.26.1",
 | 
				
			||||||
    "webpack-merge": "^5.8.0",
 | 
					    "webpack-merge": "^5.10.0",
 | 
				
			||||||
    "workbox-webpack-plugin": "^6.5.4"
 | 
					    "workbox-webpack-plugin": "^7.1.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "engines": {
 | 
					  "engines": {
 | 
				
			||||||
    "node": ">= 16.0.0",
 | 
					    "node": ">= 16.0.0",
 | 
				
			||||||
 | 
				
			|||||||
@ -59,7 +59,8 @@ export default {
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
          '-reverse': this.reverseLayout,
 | 
					          '-reverse': this.reverseLayout,
 | 
				
			||||||
          '-no-sticky-headers': this.noSticky,
 | 
					          '-no-sticky-headers': this.noSticky,
 | 
				
			||||||
          '-has-new-post-button': this.newPostButtonShown
 | 
					          '-has-new-post-button': this.newPostButtonShown,
 | 
				
			||||||
 | 
					          '-wide-timeline': this.widenTimeline
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        '-' + this.layoutType
 | 
					        '-' + this.layoutType
 | 
				
			||||||
      ]
 | 
					      ]
 | 
				
			||||||
@ -93,6 +94,9 @@ export default {
 | 
				
			|||||||
    newPostButtonShown () {
 | 
					    newPostButtonShown () {
 | 
				
			||||||
      return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile'
 | 
					      return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile'
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    widenTimeline () {
 | 
				
			||||||
 | 
					      return this.$store.getters.mergedConfig.widenTimeline
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
 | 
					    showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
 | 
				
			||||||
    editingAvailable () { return this.$store.state.instance.editingAvailable },
 | 
					    editingAvailable () { return this.$store.state.instance.editingAvailable },
 | 
				
			||||||
    layoutType () { return this.$store.state.interface.layoutType },
 | 
					    layoutType () { return this.$store.state.interface.layoutType },
 | 
				
			||||||
 | 
				
			|||||||
@ -172,6 +172,10 @@ nav {
 | 
				
			|||||||
  background-color: rgba(0, 0, 0, 0.15);
 | 
					  background-color: rgba(0, 0, 0, 0.15);
 | 
				
			||||||
  background-color: var(--underlay, rgba(0, 0, 0, 0.15));
 | 
					  background-color: var(--underlay, rgba(0, 0, 0, 0.15));
 | 
				
			||||||
  z-index: -1000;
 | 
					  z-index: -1000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .-wide-timeline & {
 | 
				
			||||||
 | 
					    margin:0 calc(var(--columnGap) / -2);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.app-layout {
 | 
					.app-layout {
 | 
				
			||||||
@ -187,12 +191,17 @@ nav {
 | 
				
			|||||||
  grid-template-rows: 1fr;
 | 
					  grid-template-rows: 1fr;
 | 
				
			||||||
  box-sizing: border-box;
 | 
					  box-sizing: border-box;
 | 
				
			||||||
  margin: 0 auto;
 | 
					  margin: 0 auto;
 | 
				
			||||||
 | 
					  padding: 0 calc(var(--columnGap) / 2);
 | 
				
			||||||
  align-content: flex-start;
 | 
					  align-content: flex-start;
 | 
				
			||||||
  flex-wrap: wrap;
 | 
					  flex-wrap: wrap;
 | 
				
			||||||
  justify-content: center;
 | 
					  justify-content: center;
 | 
				
			||||||
  min-height: 100vh;
 | 
					  min-height: 100vh;
 | 
				
			||||||
  overflow-x: clip;
 | 
					  overflow-x: clip;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.-wide-timeline {
 | 
				
			||||||
 | 
					    --maxiColumn: minmax(var(--miniColumn), 1fr);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .column {
 | 
					  .column {
 | 
				
			||||||
    --___columnMargin: var(--columnGap);
 | 
					    --___columnMargin: var(--columnGap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -183,6 +183,12 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
 | 
				
			|||||||
  copyInstanceOption('renderMisskeyMarkdown')
 | 
					  copyInstanceOption('renderMisskeyMarkdown')
 | 
				
			||||||
  copyInstanceOption('sidebarRight')
 | 
					  copyInstanceOption('sidebarRight')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config.backendCommitUrl)
 | 
				
			||||||
 | 
					    copyInstanceOption('backendCommitUrl')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (config.frontendCommitUrl)
 | 
				
			||||||
 | 
					    copyInstanceOption('frontendCommitUrl')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return store.dispatch('setTheme', config['theme'])
 | 
					  return store.dispatch('setTheme', config['theme'])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./about.js" ></script>
 | 
					<script src="./about.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
      :bound-to="{ x: 'container' }"
 | 
					      :bound-to="{ x: 'container' }"
 | 
				
			||||||
      remove-padding
 | 
					      remove-padding
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <template v-slot:content>
 | 
					      <template #content>
 | 
				
			||||||
        <div class="dropdown-menu">
 | 
					        <div class="dropdown-menu">
 | 
				
			||||||
          <template v-if="relationship.following">
 | 
					          <template v-if="relationship.following">
 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
@ -71,7 +71,7 @@
 | 
				
			|||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <template v-slot:trigger>
 | 
					      <template #trigger>
 | 
				
			||||||
        <button class="button-unstyled ellipsis-button">
 | 
					        <button class="button-unstyled ellipsis-button">
 | 
				
			||||||
          <FAIcon
 | 
					          <FAIcon
 | 
				
			||||||
            class="icon"
 | 
					            class="icon"
 | 
				
			||||||
@ -93,7 +93,7 @@
 | 
				
			|||||||
          keypath="user_card.block_confirm"
 | 
					          keypath="user_card.block_confirm"
 | 
				
			||||||
          tag="span"
 | 
					          tag="span"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template v-slot:user>
 | 
					          <template #user>
 | 
				
			||||||
            <span
 | 
					            <span
 | 
				
			||||||
              v-text="user.screen_name_ui"
 | 
					              v-text="user.screen_name_ui"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
 | 
				
			|||||||
@ -16,9 +16,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  .attachment-wrapper {
 | 
					  .attachment-wrapper {
 | 
				
			||||||
    flex: 1 1 auto;
 | 
					    flex: 1 1 auto;
 | 
				
			||||||
    height: 200px;
 | 
					    min-height: 200px;
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    overflow: hidden;
 | 
					    overflow: hidden;
 | 
				
			||||||
 | 
					    align-content: center;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .status-popover & {
 | 
				
			||||||
 | 
					      height: 200px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .description-container {
 | 
					  .description-container {
 | 
				
			||||||
@ -115,6 +120,22 @@
 | 
				
			|||||||
    align-items: center;
 | 
					    align-items: center;
 | 
				
			||||||
    justify-content: center;
 | 
					    justify-content: center;
 | 
				
			||||||
    padding-top: 0.5em;
 | 
					    padding-top: 0.5em;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    p {
 | 
				
			||||||
 | 
					      line-height: 1.5;
 | 
				
			||||||
 | 
					      padding: 0 0.5em;
 | 
				
			||||||
 | 
					      white-space: pre-line;
 | 
				
			||||||
 | 
					      text-align: center;
 | 
				
			||||||
 | 
					      max-height: 200px;
 | 
				
			||||||
 | 
					      overflow-y: auto;
 | 
				
			||||||
 | 
					      scrollbar-color: var(--border) #0000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .status-popover & {
 | 
				
			||||||
 | 
					        text-overflow: ellipsis;
 | 
				
			||||||
 | 
					        overflow: hidden;
 | 
				
			||||||
 | 
					        height: 1lh;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -246,8 +246,8 @@
 | 
				
			|||||||
          ref="flash"
 | 
					          ref="flash"
 | 
				
			||||||
          class="flash"
 | 
					          class="flash"
 | 
				
			||||||
          :src="attachment.large_thumb_url || attachment.url"
 | 
					          :src="attachment.large_thumb_url || attachment.url"
 | 
				
			||||||
          @playerOpened="setFlashLoaded(true)"
 | 
					          @player-opened="setFlashLoaded(true)"
 | 
				
			||||||
          @playerClosed="setFlashLoaded(false)"
 | 
					          @player-closed="setFlashLoaded(false)"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </span>
 | 
					      </span>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./avatar_list.js" ></script>
 | 
					<script src="./avatar_list.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -22,12 +22,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
export default {
 | 
					export default {
 | 
				
			||||||
  emits: ['update:modelValue'],
 | 
					 | 
				
			||||||
  props: [
 | 
					  props: [
 | 
				
			||||||
    'modelValue',
 | 
					    'modelValue',
 | 
				
			||||||
    'indeterminate',
 | 
					    'indeterminate',
 | 
				
			||||||
    'disabled'
 | 
					    'disabled'
 | 
				
			||||||
  ]
 | 
					  ],
 | 
				
			||||||
 | 
					  emits: ['update:modelValue']
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
      :model-value="present"
 | 
					      :model-value="present"
 | 
				
			||||||
      :disabled="disabled"
 | 
					      :disabled="disabled"
 | 
				
			||||||
      class="opt"
 | 
					      class="opt"
 | 
				
			||||||
      @update:modelValue="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
 | 
					      @update:model-value="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <div class="input color-input-field">
 | 
					    <div class="input color-input-field">
 | 
				
			||||||
      <input
 | 
					      <input
 | 
				
			||||||
@ -46,7 +46,6 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
<style lang="scss" src="./color_input.scss"></style>
 | 
					 | 
				
			||||||
<script>
 | 
					<script>
 | 
				
			||||||
import Checkbox from '../checkbox/checkbox.vue'
 | 
					import Checkbox from '../checkbox/checkbox.vue'
 | 
				
			||||||
import { hex2rgb } from '../../services/color_convert/color_convert.js'
 | 
					import { hex2rgb } from '../../services/color_convert/color_convert.js'
 | 
				
			||||||
@ -108,6 +107,7 @@ export default {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					<style lang="scss" src="./color_input.scss"></style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
.color-control {
 | 
					.color-control {
 | 
				
			||||||
 | 
				
			|||||||
@ -25,6 +25,8 @@
 | 
				
			|||||||
  </dialog-modal>
 | 
					  </dialog-modal>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script src="./confirm_modal.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss" scoped>
 | 
					<style lang="scss" scoped>
 | 
				
			||||||
@import '../../_variables';
 | 
					@import '../../_variables';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -35,5 +37,3 @@
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
					 | 
				
			||||||
<script src="./confirm_modal.js"></script>
 | 
					 | 
				
			||||||
 | 
				
			|||||||
@ -267,11 +267,11 @@ const conversation = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    replies () {
 | 
					    replies () {
 | 
				
			||||||
      let i = 1
 | 
					      let i = 1
 | 
				
			||||||
      // eslint-disable-next-line camelcase
 | 
					
 | 
				
			||||||
      return reduce(this.conversation, (result, { id, in_reply_to_status_id }) => {
 | 
					      return reduce(this.conversation, (result, { id, in_reply_to_status_id }) => {
 | 
				
			||||||
        /* eslint-disable camelcase */
 | 
					
 | 
				
			||||||
        const irid = in_reply_to_status_id
 | 
					        const irid = in_reply_to_status_id
 | 
				
			||||||
        /* eslint-enable camelcase */
 | 
					
 | 
				
			||||||
        if (irid) {
 | 
					        if (irid) {
 | 
				
			||||||
          result[irid] = result[irid] || []
 | 
					          result[irid] = result[irid] || []
 | 
				
			||||||
          result[irid].push({
 | 
					          result[irid].push({
 | 
				
			||||||
@ -414,6 +414,14 @@ const conversation = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    toggleExpanded () {
 | 
					    toggleExpanded () {
 | 
				
			||||||
      this.expanded = !this.expanded
 | 
					      this.expanded = !this.expanded
 | 
				
			||||||
 | 
					      const navHeight = document.getElementById("nav").offsetHeight
 | 
				
			||||||
 | 
					      const headingHeight = document.getElementsByClassName("timeline-heading")[0].offsetHeight
 | 
				
			||||||
 | 
					      document.documentElement.style.setProperty("--timeline-scroll-margin-top", `${navHeight + headingHeight}px`)
 | 
				
			||||||
 | 
					      this.$nextTick(() => {
 | 
				
			||||||
 | 
					        if (!this.expanded) {
 | 
				
			||||||
 | 
					          this.$el.scrollIntoView({ block: 'nearest' })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    getConversationId (statusId) {
 | 
					    getConversationId (statusId) {
 | 
				
			||||||
      const status = this.$store.state.statuses.allStatusesObject[statusId]
 | 
					      const status = this.$store.state.statuses.allStatusesObject[statusId]
 | 
				
			||||||
 | 
				
			|||||||
@ -91,7 +91,7 @@
 | 
				
			|||||||
              :controlled-set-media-playing="(newVal) => toggleStatusContentProperty(status.id, 'mediaPlaying', newVal)"
 | 
					              :controlled-set-media-playing="(newVal) => toggleStatusContentProperty(status.id, 'mediaPlaying', newVal)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              @goto="setHighlight"
 | 
					              @goto="setHighlight"
 | 
				
			||||||
              @toggleExpanded="toggleExpanded"
 | 
					              @toggle-expanded="toggleExpanded"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
            <div
 | 
					            <div
 | 
				
			||||||
              v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).length > 1"
 | 
					              v-if="showOtherRepliesButtonBelowStatus && getReplies(status.id).length > 1"
 | 
				
			||||||
@ -184,7 +184,7 @@
 | 
				
			|||||||
          :toggle-status-content-property="toggleStatusContentProperty"
 | 
					          :toggle-status-content-property="toggleStatusContentProperty"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          @goto="setHighlight"
 | 
					          @goto="setHighlight"
 | 
				
			||||||
          @toggleExpanded="toggleExpanded"
 | 
					          @toggle-expanded="toggleExpanded"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@ -278,5 +278,7 @@
 | 
				
			|||||||
  &.-expanded.status-fadein {
 | 
					  &.-expanded.status-fadein {
 | 
				
			||||||
    margin: calc(var(--status-margin, $status-margin) / 2);
 | 
					    margin: calc(var(--status-margin, $status-margin) / 2);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  scroll-margin-block-start: var(--timeline-scroll-margin-top);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
				
			|||||||
@ -44,9 +44,9 @@
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
          </router-link>
 | 
					          </router-link>
 | 
				
			||||||
          <router-link
 | 
					          <router-link
 | 
				
			||||||
 | 
					            v-if="publicTimelineVisible"
 | 
				
			||||||
            :to="{ name: 'public-timeline' }"
 | 
					            :to="{ name: 'public-timeline' }"
 | 
				
			||||||
            class="nav-icon"
 | 
					            class="nav-icon"
 | 
				
			||||||
            v-if="publicTimelineVisible"
 | 
					 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <FAIcon
 | 
					            <FAIcon
 | 
				
			||||||
              fixed-width
 | 
					              fixed-width
 | 
				
			||||||
@ -68,9 +68,9 @@
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
          </router-link>
 | 
					          </router-link>
 | 
				
			||||||
          <router-link
 | 
					          <router-link
 | 
				
			||||||
 | 
					            v-if="federatedTimelineVisible"
 | 
				
			||||||
            :to="{ name: 'public-external-timeline' }"
 | 
					            :to="{ name: 'public-external-timeline' }"
 | 
				
			||||||
            class="nav-icon"
 | 
					            class="nav-icon"
 | 
				
			||||||
            v-if="federatedTimelineVisible"
 | 
					 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <FAIcon
 | 
					            <FAIcon
 | 
				
			||||||
              fixed-width
 | 
					              fixed-width
 | 
				
			||||||
 | 
				
			|||||||
@ -9,7 +9,7 @@
 | 
				
			|||||||
      class="btn button-default"
 | 
					      class="btn button-default"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {{ $t('domain_mute_card.unmute') }}
 | 
					      {{ $t('domain_mute_card.unmute') }}
 | 
				
			||||||
      <template v-slot:progress>
 | 
					      <template #progress>
 | 
				
			||||||
        {{ $t('domain_mute_card.unmute_progress') }}
 | 
					        {{ $t('domain_mute_card.unmute_progress') }}
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </ProgressButton>
 | 
					    </ProgressButton>
 | 
				
			||||||
@ -19,7 +19,7 @@
 | 
				
			|||||||
      class="btn button-default"
 | 
					      class="btn button-default"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      {{ $t('domain_mute_card.mute') }}
 | 
					      {{ $t('domain_mute_card.mute') }}
 | 
				
			||||||
      <template v-slot:progress>
 | 
					      <template #progress>
 | 
				
			||||||
        {{ $t('domain_mute_card.mute_progress') }}
 | 
					        {{ $t('domain_mute_card.mute_progress') }}
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </ProgressButton>
 | 
					    </ProgressButton>
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
  <Modal
 | 
					  <Modal
 | 
				
			||||||
    v-if="isFormVisible"
 | 
					    v-if="isFormVisible"
 | 
				
			||||||
    class="edit-form-modal-view"
 | 
					    class="edit-form-modal-view"
 | 
				
			||||||
    @backdropClicked="closeModal"
 | 
					    @backdrop-clicked="closeModal"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <div class="edit-form-modal-panel panel">
 | 
					    <div class="edit-form-modal-panel panel">
 | 
				
			||||||
      <div class="panel-heading">
 | 
					      <div class="panel-heading">
 | 
				
			||||||
@ -11,10 +11,10 @@
 | 
				
			|||||||
      <PostStatusForm
 | 
					      <PostStatusForm
 | 
				
			||||||
        class="panel-body"
 | 
					        class="panel-body"
 | 
				
			||||||
        v-bind="params"
 | 
					        v-bind="params"
 | 
				
			||||||
        @posted="closeModal"
 | 
					        :disable-polls="true"
 | 
				
			||||||
        :disablePolls="true"
 | 
					        :disable-visibility-selector="true"
 | 
				
			||||||
        :disableVisibilitySelector="true"
 | 
					 | 
				
			||||||
        :post-handler="doEditStatus"
 | 
					        :post-handler="doEditStatus"
 | 
				
			||||||
 | 
					        @posted="closeModal"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </Modal>
 | 
					  </Modal>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,3 +1,5 @@
 | 
				
			|||||||
 | 
					import StillImage from '../still-image/still-image.vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const EMOJI_SIZE = 32 + 8
 | 
					const EMOJI_SIZE = 32 + 8
 | 
				
			||||||
const GROUP_TITLE_HEIGHT = 24
 | 
					const GROUP_TITLE_HEIGHT = 24
 | 
				
			||||||
const BUFFER_SIZE = 3 * EMOJI_SIZE
 | 
					const BUFFER_SIZE = 3 * EMOJI_SIZE
 | 
				
			||||||
@ -17,6 +19,9 @@ const EmojiGrid = {
 | 
				
			|||||||
      resizeObserver: null
 | 
					      resizeObserver: null
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  components: {
 | 
				
			||||||
 | 
					    StillImage
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  mounted () {
 | 
					  mounted () {
 | 
				
			||||||
    const rect = this.$refs.container.getBoundingClientRect()
 | 
					    const rect = this.$refs.container.getBoundingClientRect()
 | 
				
			||||||
    this.containerWidth = rect.width
 | 
					    this.containerWidth = rect.width
 | 
				
			||||||
 | 
				
			|||||||
@ -34,10 +34,11 @@
 | 
				
			|||||||
          @click.stop.prevent="onEmoji(item.emoji)"
 | 
					          @click.stop.prevent="onEmoji(item.emoji)"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <span v-if="!item.emoji.imageUrl">{{ item.emoji.replacement }}</span>
 | 
					          <span v-if="!item.emoji.imageUrl">{{ item.emoji.replacement }}</span>
 | 
				
			||||||
          <img
 | 
					          <StillImage
 | 
				
			||||||
            v-else
 | 
					            v-else
 | 
				
			||||||
            :src="item.emoji.imageUrl"
 | 
					            :src="item.emoji.imageUrl"
 | 
				
			||||||
          >
 | 
					            noStopGifs="true"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
import Completion from '../../services/completion/completion.js'
 | 
					import Completion from '../../services/completion/completion.js'
 | 
				
			||||||
import EmojiPicker from '../emoji_picker/emoji_picker.vue'
 | 
					import EmojiPicker from '../emoji_picker/emoji_picker.vue'
 | 
				
			||||||
 | 
					import StillImage from '../still-image/still-image.vue'
 | 
				
			||||||
import { take } from 'lodash'
 | 
					import { take } from 'lodash'
 | 
				
			||||||
import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
 | 
					import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -120,7 +121,8 @@ const EmojiInput = {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
    EmojiPicker
 | 
					    EmojiPicker,
 | 
				
			||||||
 | 
					    StillImage
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    padEmoji () {
 | 
					    padEmoji () {
 | 
				
			||||||
 | 
				
			|||||||
@ -20,6 +20,7 @@
 | 
				
			|||||||
        ref="picker"
 | 
					        ref="picker"
 | 
				
			||||||
        show-keep-open
 | 
					        show-keep-open
 | 
				
			||||||
        :class="{ hide: !showPicker }"
 | 
					        :class="{ hide: !showPicker }"
 | 
				
			||||||
 | 
					        :visible="showPicker"
 | 
				
			||||||
        :enable-sticker-picker="enableStickerPicker"
 | 
					        :enable-sticker-picker="enableStickerPicker"
 | 
				
			||||||
        class="emoji-picker-panel"
 | 
					        class="emoji-picker-panel"
 | 
				
			||||||
        @emoji="insert"
 | 
					        @emoji="insert"
 | 
				
			||||||
@ -43,11 +44,15 @@
 | 
				
			|||||||
          :class="{ highlighted: index === highlighted }"
 | 
					          :class="{ highlighted: index === highlighted }"
 | 
				
			||||||
          @click.stop.prevent="onClick($event, suggestion)"
 | 
					          @click.stop.prevent="onClick($event, suggestion)"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <span v-if="!suggestion.mfm" class="image">
 | 
					          <span
 | 
				
			||||||
            <img
 | 
					            v-if="!suggestion.mfm"
 | 
				
			||||||
 | 
					            class="image"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            <StillImage
 | 
				
			||||||
              v-if="suggestion.img"
 | 
					              v-if="suggestion.img"
 | 
				
			||||||
              :src="suggestion.img"
 | 
					              :src="suggestion.img"
 | 
				
			||||||
            >
 | 
					              noStopGifs="true"
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
            <span v-else>{{ suggestion.replacement }}</span>
 | 
					            <span v-else>{{ suggestion.replacement }}</span>
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
          <div class="label">
 | 
					          <div class="label">
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
const MFM_TAGS = ['blur', 'bounce', 'flip', 'font', 'jelly', 'jump', 'rainbow', 'rotate', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4']
 | 
					const MFM_TAGS = ['bg', 'blur', 'bounce', 'center', 'fg', 'flip', 'font', 'jelly', 'jump', 'position', 'rainbow', 'rotate', 'scale', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4']
 | 
				
			||||||
  .map(tag => ({ displayText: tag, detailText: '$[' + tag + ' ]', replacement: '$[' + tag + ' ]', mfm: true }))
 | 
					  .map(tag => ({ displayText: tag, detailText: '$[' + tag + ' ]', replacement: '$[' + tag + ' ]', mfm: true }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -122,14 +122,14 @@ export const suggestUsers = ({ dispatch, state }) => {
 | 
				
			|||||||
      const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
 | 
					      const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      return diff + nameAlphabetically + screenNameAlphabetically
 | 
					      return diff + nameAlphabetically + screenNameAlphabetically
 | 
				
			||||||
      /* eslint-disable camelcase */
 | 
					       
 | 
				
			||||||
    }).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
 | 
					    }).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
 | 
				
			||||||
      displayText: screen_name_ui,
 | 
					      displayText: screen_name_ui,
 | 
				
			||||||
      detailText: name,
 | 
					      detailText: name,
 | 
				
			||||||
      imageUrl: profile_image_url_original,
 | 
					      imageUrl: profile_image_url_original,
 | 
				
			||||||
      replacement: '@' + screen_name + ' '
 | 
					      replacement: '@' + screen_name + ' '
 | 
				
			||||||
    }))
 | 
					    }))
 | 
				
			||||||
    /* eslint-enable camelcase */
 | 
					     
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    suggestions = newSuggestions || []
 | 
					    suggestions = newSuggestions || []
 | 
				
			||||||
    return suggestions
 | 
					    return suggestions
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,7 @@
 | 
				
			|||||||
import { defineAsyncComponent } from 'vue'
 | 
					import { defineAsyncComponent } from 'vue'
 | 
				
			||||||
import Checkbox from '../checkbox/checkbox.vue'
 | 
					import Checkbox from '../checkbox/checkbox.vue'
 | 
				
			||||||
import EmojiGrid from '../emoji_grid/emoji_grid.vue'
 | 
					import EmojiGrid from '../emoji_grid/emoji_grid.vue'
 | 
				
			||||||
 | 
					import StillImage from '../still-image/still-image.vue'
 | 
				
			||||||
import { library } from '@fortawesome/fontawesome-svg-core'
 | 
					import { library } from '@fortawesome/fontawesome-svg-core'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  faBoxOpen,
 | 
					  faBoxOpen,
 | 
				
			||||||
@ -26,12 +27,17 @@ const EmojiPicker = {
 | 
				
			|||||||
      required: false,
 | 
					      required: false,
 | 
				
			||||||
      type: Boolean,
 | 
					      type: Boolean,
 | 
				
			||||||
      default: false
 | 
					      default: false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    visible: {
 | 
				
			||||||
 | 
					      required: false,
 | 
				
			||||||
 | 
					      type: Boolean,
 | 
				
			||||||
 | 
					      default: true
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data () {
 | 
					  data () {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      keyword: '',
 | 
					      keyword: '',
 | 
				
			||||||
      activeGroup: 'standard',
 | 
					      activeGroup: this.getDefaultGroup(),
 | 
				
			||||||
      showingStickers: false,
 | 
					      showingStickers: false,
 | 
				
			||||||
      keepOpen: false
 | 
					      keepOpen: false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -39,7 +45,8 @@ const EmojiPicker = {
 | 
				
			|||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
    StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')),
 | 
					    StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')),
 | 
				
			||||||
    Checkbox,
 | 
					    Checkbox,
 | 
				
			||||||
    EmojiGrid
 | 
					    EmojiGrid,
 | 
				
			||||||
 | 
					    StillImage
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    debouncedSearch: debounce(function (e) {
 | 
					    debouncedSearch: debounce(function (e) {
 | 
				
			||||||
@ -82,6 +89,11 @@ const EmojiPicker = {
 | 
				
			|||||||
      return list.filter(emoji => {
 | 
					      return list.filter(emoji => {
 | 
				
			||||||
        return (regex.test(emoji.displayText) || (!emoji.imageUrl && emoji.replacement === this.keyword))
 | 
					        return (regex.test(emoji.displayText) || (!emoji.imageUrl && emoji.replacement === this.keyword))
 | 
				
			||||||
      })
 | 
					      })
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    getDefaultGroup () {
 | 
				
			||||||
 | 
					      if (!this.visible) return null
 | 
				
			||||||
 | 
					      const recentEmojis = this.$store.getters.recentEmojis
 | 
				
			||||||
 | 
					      return recentEmojis.length === 0 ? 'standard' : 'recent'
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
@ -148,6 +160,13 @@ const EmojiPicker = {
 | 
				
			|||||||
    stickerPickerEnabled () {
 | 
					    stickerPickerEnabled () {
 | 
				
			||||||
      return (this.$store.state.instance.stickers || []).length !== 0 && this.enableStickerPicker
 | 
					      return (this.$store.state.instance.stickers || []).length !== 0 && this.enableStickerPicker
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  watch: {
 | 
				
			||||||
 | 
					    visible (val, oldVal) {
 | 
				
			||||||
 | 
					      if (val && this.activeGroup === null) {
 | 
				
			||||||
 | 
					        this.activeGroup = this.getDefaultGroup()
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -18,10 +18,11 @@
 | 
				
			|||||||
          @click.prevent="highlight(group.id)"
 | 
					          @click.prevent="highlight(group.id)"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <span v-if="!group.first.imageUrl">{{ group.first.replacement }}</span>
 | 
					          <span v-if="!group.first.imageUrl">{{ group.first.replacement }}</span>
 | 
				
			||||||
          <img
 | 
					          <StillImage
 | 
				
			||||||
            v-else
 | 
					            v-else
 | 
				
			||||||
            :src="group.first.imageUrl"
 | 
					            :src="group.first.imageUrl"
 | 
				
			||||||
          >
 | 
					            noStopGifs="true"
 | 
				
			||||||
 | 
					          />
 | 
				
			||||||
        </span>
 | 
					        </span>
 | 
				
			||||||
        <span
 | 
					        <span
 | 
				
			||||||
          v-if="stickerPickerEnabled"
 | 
					          v-if="stickerPickerEnabled"
 | 
				
			||||||
 | 
				
			|||||||
@ -11,7 +11,7 @@
 | 
				
			|||||||
        @click="emojiOnClick(reaction.name, $event)"
 | 
					        @click="emojiOnClick(reaction.name, $event)"
 | 
				
			||||||
        @mouseenter="fetchEmojiReactionsByIfMissing()"
 | 
					        @mouseenter="fetchEmojiReactionsByIfMissing()"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <span
 | 
					        <template
 | 
				
			||||||
          v-if="reaction.url !== null"
 | 
					          v-if="reaction.url !== null"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <StillImage
 | 
					          <StillImage
 | 
				
			||||||
@ -19,16 +19,15 @@
 | 
				
			|||||||
            :title="reaction.name"
 | 
					            :title="reaction.name"
 | 
				
			||||||
            :alt="reaction.name"
 | 
					            :alt="reaction.name"
 | 
				
			||||||
            class="reaction-emoji"
 | 
					            class="reaction-emoji"
 | 
				
			||||||
            height="2.55em"
 | 
					 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          {{ reaction.count }}
 | 
					          {{ reaction.count }}
 | 
				
			||||||
        </span>
 | 
					        </template>
 | 
				
			||||||
        <span v-else>
 | 
					        <template v-else>
 | 
				
			||||||
          <span class="reaction-emoji unicode-emoji">
 | 
					          <span class="reaction-emoji unicode-emoji">
 | 
				
			||||||
            {{ reaction.name }}
 | 
					            {{ reaction.name }}
 | 
				
			||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
          <span>{{ reaction.count }}</span>
 | 
					          <span>{{ reaction.count }}</span>
 | 
				
			||||||
        </span>
 | 
					        </template>
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
    </UserListPopover>
 | 
					    </UserListPopover>
 | 
				
			||||||
    <a
 | 
					    <a
 | 
				
			||||||
@ -42,7 +41,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./emoji_reactions.js" ></script>
 | 
					<script src="./emoji_reactions.js"></script>
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -53,23 +52,26 @@
 | 
				
			|||||||
  container-type: inline-size;
 | 
					  container-type: inline-size;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.unicode-emoji {
 | 
					 | 
				
			||||||
  font-size: 210%;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.emoji-reaction {
 | 
					.emoji-reaction {
 | 
				
			||||||
  padding: 0 0.5em;
 | 
					  padding: 2px 0.5em;
 | 
				
			||||||
  margin-right: 0.5em;
 | 
					  margin-right: 0.5em;
 | 
				
			||||||
  margin-top: 0.5em;
 | 
					  margin-top: 0.5em;
 | 
				
			||||||
  display: flex;
 | 
					  display: flex;
 | 
				
			||||||
  align-items: center;
 | 
					  align-items: end;
 | 
				
			||||||
  justify-content: center;
 | 
					
 | 
				
			||||||
  box-sizing: border-box;
 | 
					 | 
				
			||||||
  .reaction-emoji {
 | 
					  .reaction-emoji {
 | 
				
			||||||
    width: auto;
 | 
					    width: auto;
 | 
				
			||||||
    max-width: 96cqw;
 | 
					    max-width: 96cqw;
 | 
				
			||||||
    height: 2.55em !important;
 | 
					 | 
				
			||||||
    margin-right: 0.25em;
 | 
					    margin-right: 0.25em;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.still-image {
 | 
				
			||||||
 | 
					      height: 2.55em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    &.unicode-emoji {
 | 
				
			||||||
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
					      font-size: 2.125em; // assuming default line height of 1.2rem and emojis that don't exceed line height
 | 
				
			||||||
 | 
					      line-height: 2.55rem;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  &:focus {
 | 
					  &:focus {
 | 
				
			||||||
    outline: none;
 | 
					    outline: none;
 | 
				
			||||||
@ -97,9 +99,9 @@
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.button-default.picked-reaction {
 | 
					.button-default.picked-reaction {
 | 
				
			||||||
  border: 1px solid var(--accent, $fallback--link);
 | 
					  &, &:hover {
 | 
				
			||||||
  margin-left: -1px; // offset the border, can't use inset shadows either
 | 
					    box-shadow: inset 0 0 0 1px var(--accent, $fallback--link);
 | 
				
			||||||
  margin-right: calc(0.5em - 1px);
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
</style>
 | 
					</style>
 | 
				
			||||||
 | 
				
			|||||||
@ -7,7 +7,7 @@
 | 
				
			|||||||
    :bound-to="{ x: 'container' }"
 | 
					    :bound-to="{ x: 'container' }"
 | 
				
			||||||
    remove-padding
 | 
					    remove-padding
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <template v-slot:content="{close}">
 | 
					    <template #content="{close}">
 | 
				
			||||||
      <div class="dropdown-menu">
 | 
					      <div class="dropdown-menu">
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          v-if="canMute && !status.thread_muted"
 | 
					          v-if="canMute && !status.thread_muted"
 | 
				
			||||||
@ -172,7 +172,7 @@
 | 
				
			|||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
    <template v-slot:trigger>
 | 
					    <template #trigger>
 | 
				
			||||||
      <button class="button-unstyled popover-trigger">
 | 
					      <button class="button-unstyled popover-trigger">
 | 
				
			||||||
        <FAIcon
 | 
					        <FAIcon
 | 
				
			||||||
          class="fa-scale-110 fa-old-padding"
 | 
					          class="fa-scale-110 fa-old-padding"
 | 
				
			||||||
@ -205,7 +205,7 @@
 | 
				
			|||||||
  </Popover>
 | 
					  </Popover>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./extra_buttons.js" ></script>
 | 
					<script src="./extra_buttons.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -35,7 +35,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./favorite_button.js" ></script>
 | 
					<script src="./favorite_button.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -23,7 +23,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./features_panel.js" ></script>
 | 
					<script src="./features_panel.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
  .features-panel li {
 | 
					  .features-panel li {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,8 @@
 | 
				
			|||||||
<template>
 | 
					<template>
 | 
				
			||||||
  <basic-user-card :user="user" v-if="show">
 | 
					  <basic-user-card
 | 
				
			||||||
 | 
					    v-if="show"
 | 
				
			||||||
 | 
					    :user="user"
 | 
				
			||||||
 | 
					  >
 | 
				
			||||||
    <div class="follow-request-card-content-container">
 | 
					    <div class="follow-request-card-content-container">
 | 
				
			||||||
      <button
 | 
					      <button
 | 
				
			||||||
        class="btn button-default"
 | 
					        class="btn button-default"
 | 
				
			||||||
 | 
				
			|||||||
@ -47,7 +47,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./font_control.js" ></script>
 | 
					<script src="./font_control.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -88,10 +88,8 @@ const Gallery = {
 | 
				
			|||||||
      set(this.sizes, id, { width, height })
 | 
					      set(this.sizes, id, { width, height })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    rowStyle (row) {
 | 
					    rowStyle (row) {
 | 
				
			||||||
      if (row.audio) {
 | 
					      if (!row.audio && !row.minimal && !row.grid) {
 | 
				
			||||||
        return { 'padding-bottom': '25%' } // fixed reduced height for audio
 | 
					        return { 'aspect-ratio': `1/${(1 / (row.items.length + 0.6))}` }
 | 
				
			||||||
      } else if (!row.minimal && !row.grid) {
 | 
					 | 
				
			||||||
        return { 'padding-bottom': `${(100 / (row.items.length + 0.6))}%` }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    itemStyle (id, row) {
 | 
					    itemStyle (id, row) {
 | 
				
			||||||
 | 
				
			|||||||
@ -31,8 +31,8 @@
 | 
				
			|||||||
            :description="descriptions && descriptions[attachment.id]"
 | 
					            :description="descriptions && descriptions[attachment.id]"
 | 
				
			||||||
            :hide-description="size === 'small' || tooManyAttachments && hidingLong"
 | 
					            :hide-description="size === 'small' || tooManyAttachments && hidingLong"
 | 
				
			||||||
            :style="itemStyle(attachment.id, row.items)"
 | 
					            :style="itemStyle(attachment.id, row.items)"
 | 
				
			||||||
            @setMedia="onMedia"
 | 
					            @set-media="onMedia"
 | 
				
			||||||
            @naturalSizeLoad="onNaturalSizeLoad"
 | 
					            @natural-size-load="onNaturalSizeLoad"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
@ -96,9 +96,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  .gallery-row {
 | 
					  .gallery-row {
 | 
				
			||||||
    position: relative;
 | 
					    position: relative;
 | 
				
			||||||
    height: 0;
 | 
					 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    flex-grow: 1;
 | 
					    flex-grow: 1;
 | 
				
			||||||
 | 
					    .Status & {
 | 
				
			||||||
 | 
					      max-height: 30em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.-audio {
 | 
				
			||||||
 | 
					      aspect-ratio: 4/1; // this is terrible, but it's how it was before so I'm not changing it >:(
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &:not(:first-child) {
 | 
					    &:not(:first-child) {
 | 
				
			||||||
      margin-top: 0.5em;
 | 
					      margin-top: 0.5em;
 | 
				
			||||||
 | 
				
			|||||||
@ -14,6 +14,6 @@
 | 
				
			|||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./hashtag_link.js"/>
 | 
					<script src="./hashtag_link.js" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss" src="./hashtag_link.scss"/>
 | 
					<style lang="scss" src="./hashtag_link.scss" />
 | 
				
			||||||
 | 
				
			|||||||
@ -10,4 +10,4 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./instance_specific_panel.js" ></script>
 | 
					<script src="./instance_specific_panel.js"></script>
 | 
				
			||||||
 | 
				
			|||||||
@ -42,6 +42,7 @@ export default {
 | 
				
			|||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.list {
 | 
					.list {
 | 
				
			||||||
 | 
					  min-height: 1em;
 | 
				
			||||||
  &-item:not(:last-child) {
 | 
					  &-item:not(:last-child) {
 | 
				
			||||||
    border-bottom: 1px solid;
 | 
					    border-bottom: 1px solid;
 | 
				
			||||||
    border-bottom-color: $fallback--border;
 | 
					    border-bottom-color: $fallback--border;
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="panel-body">
 | 
					      <div class="panel-body">
 | 
				
			||||||
        <p>{{ $t("about.bubble_instances_description")}}:</p>
 | 
					        <p>{{ $t("about.bubble_instances_description") }}:</p>
 | 
				
			||||||
        <ul>
 | 
					        <ul>
 | 
				
			||||||
          <li
 | 
					          <li
 | 
				
			||||||
            v-for="instance in bubbleInstances"
 | 
					            v-for="instance in bubbleInstances"
 | 
				
			||||||
 | 
				
			|||||||
@ -90,7 +90,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./login_form.js" ></script>
 | 
					<script src="./login_form.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
  <Modal
 | 
					  <Modal
 | 
				
			||||||
    v-if="showing"
 | 
					    v-if="showing"
 | 
				
			||||||
    class="media-modal-view"
 | 
					    class="media-modal-view"
 | 
				
			||||||
    @backdropClicked="hideIfNotSwiped"
 | 
					    @backdrop-clicked="hideIfNotSwiped"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <SwipeClick
 | 
					    <SwipeClick
 | 
				
			||||||
      v-if="type === 'image'"
 | 
					      v-if="type === 'image'"
 | 
				
			||||||
@ -24,14 +24,15 @@
 | 
				
			|||||||
        :min-scale="pinchZoomMinScale"
 | 
					        :min-scale="pinchZoomMinScale"
 | 
				
			||||||
        :reset-to-min-scale-limit="pinchZoomScaleResetLimit"
 | 
					        :reset-to-min-scale-limit="pinchZoomScaleResetLimit"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <img
 | 
					        <StillImage
 | 
				
			||||||
          :class="{ loading }"
 | 
					          :class="{ loading }"
 | 
				
			||||||
          class="modal-image"
 | 
					          class="modal-image"
 | 
				
			||||||
          :src="currentMedia.url"
 | 
					          :src="currentMedia.url"
 | 
				
			||||||
          :alt="currentMedia.description"
 | 
					          :alt="currentMedia.description"
 | 
				
			||||||
          :title="currentMedia.description"
 | 
					          :title="currentMedia.description"
 | 
				
			||||||
          @load="onImageLoaded"
 | 
					          @load="onImageLoaded"
 | 
				
			||||||
        >
 | 
					          noStopGifs="true"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
      </PinchZoom>
 | 
					      </PinchZoom>
 | 
				
			||||||
    </SwipeClick>
 | 
					    </SwipeClick>
 | 
				
			||||||
    <VideoAttachment
 | 
					    <VideoAttachment
 | 
				
			||||||
 | 
				
			|||||||
@ -42,7 +42,7 @@ const mediaUpload = {
 | 
				
			|||||||
        .then((fileData) => {
 | 
					        .then((fileData) => {
 | 
				
			||||||
          self.$emit('uploaded', fileData)
 | 
					          self.$emit('uploaded', fileData)
 | 
				
			||||||
          self.decreaseUploadCount()
 | 
					          self.decreaseUploadCount()
 | 
				
			||||||
        }, (error) => { // eslint-disable-line handle-callback-err
 | 
					        }, (error) => {  
 | 
				
			||||||
          self.$emit('upload-failed', 'default')
 | 
					          self.$emit('upload-failed', 'default')
 | 
				
			||||||
          self.decreaseUploadCount()
 | 
					          self.decreaseUploadCount()
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
 | 
				
			|||||||
@ -26,7 +26,7 @@
 | 
				
			|||||||
  </label>
 | 
					  </label>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./media_upload.js" ></script>
 | 
					<script src="./media_upload.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -66,6 +66,6 @@
 | 
				
			|||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./mention_link.js"/>
 | 
					<script src="./mention_link.js" />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss" src="./mention_link.scss"/>
 | 
					<style lang="scss" src="./mention_link.scss" />
 | 
				
			||||||
 | 
				
			|||||||
@ -37,5 +37,5 @@
 | 
				
			|||||||
    </span>
 | 
					    </span>
 | 
				
			||||||
  </span>
 | 
					  </span>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
<script src="./mentions_line.js" ></script>
 | 
					<script src="./mentions_line.js"></script>
 | 
				
			||||||
<style lang="scss" src="./mentions_line.scss" />
 | 
					<style lang="scss" src="./mentions_line.scss" />
 | 
				
			||||||
 | 
				
			|||||||
@ -69,4 +69,4 @@
 | 
				
			|||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
<script src="./recovery_form.js" ></script>
 | 
					<script src="./recovery_form.js"></script>
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@
 | 
				
			|||||||
          <input
 | 
					          <input
 | 
				
			||||||
            id="code"
 | 
					            id="code"
 | 
				
			||||||
            v-model="code"
 | 
					            v-model="code"
 | 
				
			||||||
 | 
					            autocomplete="one-time-code"
 | 
				
			||||||
            class="form-control"
 | 
					            class="form-control"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -4,7 +4,7 @@
 | 
				
			|||||||
      class="panel-heading"
 | 
					      class="panel-heading"
 | 
				
			||||||
      @click="toggleHidden"
 | 
					      @click="toggleHidden"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <h4>{{ $t('moderation.reports.report') + ' ' + this.account.screen_name }}</h4>
 | 
					      <h4>{{ $t('moderation.reports.report') + ' ' + account.screen_name }}</h4>
 | 
				
			||||||
      <button
 | 
					      <button
 | 
				
			||||||
        v-if="isOpen"
 | 
					        v-if="isOpen"
 | 
				
			||||||
        class="button-default"
 | 
					        class="button-default"
 | 
				
			||||||
@ -35,7 +35,10 @@
 | 
				
			|||||||
        <div v-if="content">
 | 
					        <div v-if="content">
 | 
				
			||||||
          {{ decode(content) }}
 | 
					          {{ decode(content) }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <i v-else class="faint">
 | 
					        <i
 | 
				
			||||||
 | 
					          v-else
 | 
				
			||||||
 | 
					          class="faint"
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
          {{ $t('moderation.reports.no_content') }}
 | 
					          {{ $t('moderation.reports.no_content') }}
 | 
				
			||||||
        </i>
 | 
					        </i>
 | 
				
			||||||
        <div class="report-author">
 | 
					        <div class="report-author">
 | 
				
			||||||
@ -43,12 +46,12 @@
 | 
				
			|||||||
            class="small-avatar"
 | 
					            class="small-avatar"
 | 
				
			||||||
            :user="actor"
 | 
					            :user="actor"
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
          {{ this.actor.screen_name }}
 | 
					          {{ actor.screen_name }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
 | 
					        v-if="!hidden && statuses.length > 0"
 | 
				
			||||||
        class="dropdown"
 | 
					        class="dropdown"
 | 
				
			||||||
        v-if="!hidden && this.statuses.length > 0"
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          class="button button-unstyled dropdown-header"
 | 
					          class="button button-unstyled dropdown-header"
 | 
				
			||||||
@ -74,8 +77,8 @@
 | 
				
			|||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
 | 
					        v-if="!hidden && notes.length > 0"
 | 
				
			||||||
        class="dropdown"
 | 
					        class="dropdown"
 | 
				
			||||||
        v-if="!hidden && this.notes.length > 0"
 | 
					 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          class="button button-unstyled dropdown-header"
 | 
					          class="button button-unstyled dropdown-header"
 | 
				
			||||||
@ -99,9 +102,9 @@
 | 
				
			|||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="report-add-note">
 | 
					      <div class="report-add-note">
 | 
				
			||||||
        <textarea
 | 
					        <textarea
 | 
				
			||||||
 | 
					          v-model.trim="note"
 | 
				
			||||||
          rows="1"
 | 
					          rows="1"
 | 
				
			||||||
          cols="1"
 | 
					          cols="1"
 | 
				
			||||||
          v-model.trim="note"
 | 
					 | 
				
			||||||
          :placeholder="$t('moderation.reports.note_placeholder')"
 | 
					          :placeholder="$t('moderation.reports.note_placeholder')"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
@ -134,7 +137,7 @@
 | 
				
			|||||||
        :offset="{ y: 5 }"
 | 
					        :offset="{ y: 5 }"
 | 
				
			||||||
        remove-padding
 | 
					        remove-padding
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <template v-slot:trigger>
 | 
					        <template #trigger>
 | 
				
			||||||
          <button
 | 
					          <button
 | 
				
			||||||
            class="btn button-default"
 | 
					            class="btn button-default"
 | 
				
			||||||
            :disabled="!tagPolicyEnabled"
 | 
					            :disabled="!tagPolicyEnabled"
 | 
				
			||||||
@ -147,7 +150,7 @@
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
          </button>
 | 
					          </button>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
        <template v-slot:content="{close}">
 | 
					        <template #content="{close}">
 | 
				
			||||||
          <div
 | 
					          <div
 | 
				
			||||||
            class="dropdown-menu"
 | 
					            class="dropdown-menu"
 | 
				
			||||||
            :disabled="!tagPolicyEnabled"
 | 
					            :disabled="!tagPolicyEnabled"
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
          class="small-avatar"
 | 
					          class="small-avatar"
 | 
				
			||||||
          :user="user"
 | 
					          :user="user"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        {{ this.user.screen_name }}
 | 
					        {{ user.screen_name }}
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
      <div class="header-right">
 | 
					      <div class="header-right">
 | 
				
			||||||
        <Timeago
 | 
					        <Timeago
 | 
				
			||||||
 | 
				
			|||||||
@ -22,6 +22,9 @@ export default {
 | 
				
			|||||||
      default: false
 | 
					      default: false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  emits: [
 | 
				
			||||||
 | 
					    'backdropClicked',
 | 
				
			||||||
 | 
					  ],
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    classes () {
 | 
					    classes () {
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@
 | 
				
			|||||||
      @show="setToggled(true)"
 | 
					      @show="setToggled(true)"
 | 
				
			||||||
      @close="setToggled(false)"
 | 
					      @close="setToggled(false)"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <template v-slot:content>
 | 
					      <template #content>
 | 
				
			||||||
        <div class="dropdown-menu">
 | 
					        <div class="dropdown-menu">
 | 
				
			||||||
          <span v-if="user.is_local">
 | 
					          <span v-if="user.is_local">
 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
@ -122,7 +122,7 @@
 | 
				
			|||||||
          </span>
 | 
					          </span>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <template v-slot:trigger>
 | 
					      <template #trigger>
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          class="btn button-default btn-block moderation-tools-button"
 | 
					          class="btn button-default btn-block moderation-tools-button"
 | 
				
			||||||
          :class="{ toggled }"
 | 
					          :class="{ toggled }"
 | 
				
			||||||
@ -137,11 +137,11 @@
 | 
				
			|||||||
        v-if="showDeleteUserDialog"
 | 
					        v-if="showDeleteUserDialog"
 | 
				
			||||||
        :on-cancel="deleteUserDialog.bind(this, false)"
 | 
					        :on-cancel="deleteUserDialog.bind(this, false)"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <template v-slot:header>
 | 
					        <template #header>
 | 
				
			||||||
          {{ $t('user_card.admin_menu.delete_user') }}
 | 
					          {{ $t('user_card.admin_menu.delete_user') }}
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
        <p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
 | 
					        <p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
 | 
				
			||||||
        <template v-slot:footer>
 | 
					        <template #footer>
 | 
				
			||||||
          <button
 | 
					          <button
 | 
				
			||||||
            class="btn button-default"
 | 
					            class="btn button-default"
 | 
				
			||||||
            @click="deleteUserDialog(false)"
 | 
					            @click="deleteUserDialog(false)"
 | 
				
			||||||
 | 
				
			|||||||
@ -102,7 +102,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./nav_panel.js" ></script>
 | 
					<script src="./nav_panel.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,7 @@ import UserCard from '../user_card/user_card.vue'
 | 
				
			|||||||
import Timeago from '../timeago/timeago.vue'
 | 
					import Timeago from '../timeago/timeago.vue'
 | 
				
			||||||
import RichContent from 'src/components/rich_content/rich_content.jsx'
 | 
					import RichContent from 'src/components/rich_content/rich_content.jsx'
 | 
				
			||||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
 | 
					import ConfirmModal from '../confirm_modal/confirm_modal.vue'
 | 
				
			||||||
 | 
					import StillImage from '../still-image/still-image.vue'
 | 
				
			||||||
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
 | 
					import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'
 | 
				
			||||||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
 | 
					import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
 | 
				
			||||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 | 
					import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 | 
				
			||||||
@ -50,7 +51,8 @@ const Notification = {
 | 
				
			|||||||
    Timeago,
 | 
					    Timeago,
 | 
				
			||||||
    Status,
 | 
					    Status,
 | 
				
			||||||
    RichContent,
 | 
					    RichContent,
 | 
				
			||||||
    ConfirmModal
 | 
					    ConfirmModal,
 | 
				
			||||||
 | 
					    StillImage
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    toggleUserExpanded () {
 | 
					    toggleUserExpanded () {
 | 
				
			||||||
 | 
				
			|||||||
@ -101,4 +101,8 @@
 | 
				
			|||||||
    color: $fallback--cBlue;
 | 
					    color: $fallback--cBlue;
 | 
				
			||||||
    color: var(--cBlue, $fallback--cBlue);
 | 
					    color: var(--cBlue, $fallback--cBlue);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .attachment-wrapper {
 | 
				
			||||||
 | 
					    min-height: unset;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -116,12 +116,13 @@
 | 
				
			|||||||
                  scope="global"
 | 
					                  scope="global"
 | 
				
			||||||
                  keypath="notifications.reacted_with"
 | 
					                  keypath="notifications.reacted_with"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  <img
 | 
					                  <still-image
 | 
				
			||||||
                    v-if="notification.emoji_url !== null"
 | 
					                    v-if="notification.emoji_url !== null"
 | 
				
			||||||
                    class="notification-reaction-emoji"
 | 
					                    class="notification-reaction-emoji"
 | 
				
			||||||
                    :src="notification.emoji_url"
 | 
					                    :src="notification.emoji_url"
 | 
				
			||||||
                    :name="notification.emoji"
 | 
					                    :title="notification.emoji"
 | 
				
			||||||
                  >
 | 
					                    :alt="notification.emoji"
 | 
				
			||||||
 | 
					                  />
 | 
				
			||||||
                  <span
 | 
					                  <span
 | 
				
			||||||
                    v-else
 | 
					                    v-else
 | 
				
			||||||
                    class="emoji-reaction-emoji"
 | 
					                    class="emoji-reaction-emoji"
 | 
				
			||||||
 | 
				
			|||||||
@ -5,7 +5,7 @@
 | 
				
			|||||||
    placement="bottom"
 | 
					    placement="bottom"
 | 
				
			||||||
    :bound-to="{ x: 'container' }"
 | 
					    :bound-to="{ x: 'container' }"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <template v-slot:content>
 | 
					    <template #content>
 | 
				
			||||||
      <div class="dropdown-menu">
 | 
					      <div class="dropdown-menu">
 | 
				
			||||||
        <button
 | 
					        <button
 | 
				
			||||||
          class="button-default dropdown-item"
 | 
					          class="button-default dropdown-item"
 | 
				
			||||||
@ -72,7 +72,7 @@
 | 
				
			|||||||
        </button>
 | 
					        </button>
 | 
				
			||||||
      </div>
 | 
					      </div>
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
    <template v-slot:trigger>
 | 
					    <template #trigger>
 | 
				
			||||||
      <button class="filter-trigger-button button-unstyled">
 | 
					      <button class="filter-trigger-button button-unstyled">
 | 
				
			||||||
        <FAIcon icon="filter" />
 | 
					        <FAIcon icon="filter" />
 | 
				
			||||||
      </button>
 | 
					      </button>
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,7 @@
 | 
				
			|||||||
      :model-value="present"
 | 
					      :model-value="present"
 | 
				
			||||||
      :disabled="disabled"
 | 
					      :disabled="disabled"
 | 
				
			||||||
      class="opt"
 | 
					      class="opt"
 | 
				
			||||||
      @update:modelValue="$emit('update:modelValue', !present ? fallback : undefined)"
 | 
					      @update:model-value="$emit('update:modelValue', !present ? fallback : undefined)"
 | 
				
			||||||
    />
 | 
					    />
 | 
				
			||||||
    <input
 | 
					    <input
 | 
				
			||||||
      :id="name"
 | 
					      :id="name"
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,6 @@
 | 
				
			|||||||
  <pinch-zoom
 | 
					  <pinch-zoom
 | 
				
			||||||
    class="pinch-zoom-parent"
 | 
					    class="pinch-zoom-parent"
 | 
				
			||||||
    v-bind="$attrs"
 | 
					    v-bind="$attrs"
 | 
				
			||||||
    v-on="$listeners"
 | 
					 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <slot />
 | 
					    <slot />
 | 
				
			||||||
  </pinch-zoom>
 | 
					  </pinch-zoom>
 | 
				
			||||||
 | 
				
			|||||||
@ -50,6 +50,13 @@ export default {
 | 
				
			|||||||
    totalVotesCount () {
 | 
					    totalVotesCount () {
 | 
				
			||||||
      return this.poll.votes_count
 | 
					      return this.poll.votes_count
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    totalFractionBase () {
 | 
				
			||||||
 | 
					      // Due to a backend bug, we might not have any voter count info for remote polls
 | 
				
			||||||
 | 
					      // in this case, fall back to count of votes even for multiple cjoice polls
 | 
				
			||||||
 | 
					      // to be able to at least display _something_
 | 
				
			||||||
 | 
					      const total_base = this.poll.multiple ? this.poll.voters_count : this.poll.votes_count
 | 
				
			||||||
 | 
					      return total_base > 0 ? total_base : this.poll.votes_count
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    containerClass () {
 | 
					    containerClass () {
 | 
				
			||||||
      return {
 | 
					      return {
 | 
				
			||||||
        loading: this.loading
 | 
					        loading: this.loading
 | 
				
			||||||
@ -70,10 +77,11 @@ export default {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    percentageForOption (count) {
 | 
					    percentageForOption (count) {
 | 
				
			||||||
      return this.totalVotesCount === 0 ? 0 : Math.round(count / this.totalVotesCount * 100)
 | 
					      const total = this.totalFractionBase
 | 
				
			||||||
 | 
					      return total === 0 ? 0 : Math.round(count / total * 100)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    resultTitle (option) {
 | 
					    resultTitle (option) {
 | 
				
			||||||
      return `${option.votes_count}/${this.totalVotesCount} ${this.$t('polls.votes')}`
 | 
					      return `${option.votes_count}/${this.totalFractionBase} ${this.$t('polls.votes')}`
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    fetchPoll () {
 | 
					    fetchPoll () {
 | 
				
			||||||
      this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
 | 
					      this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
 | 
				
			||||||
 | 
				
			|||||||
@ -24,6 +24,7 @@
 | 
				
			|||||||
      <button
 | 
					      <button
 | 
				
			||||||
        v-if="options.length > 2"
 | 
					        v-if="options.length > 2"
 | 
				
			||||||
        class="delete-option button-unstyled -hover-highlight"
 | 
					        class="delete-option button-unstyled -hover-highlight"
 | 
				
			||||||
 | 
					        type="button"
 | 
				
			||||||
        @click="deleteOption(index)"
 | 
					        @click="deleteOption(index)"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <FAIcon icon="times" />
 | 
					        <FAIcon icon="times" />
 | 
				
			||||||
@ -32,6 +33,7 @@
 | 
				
			|||||||
    <button
 | 
					    <button
 | 
				
			||||||
      v-if="options.length < maxOptions"
 | 
					      v-if="options.length < maxOptions"
 | 
				
			||||||
      class="add-option faint button-unstyled -hover-highlight"
 | 
					      class="add-option faint button-unstyled -hover-highlight"
 | 
				
			||||||
 | 
					      type="button"
 | 
				
			||||||
      @click="addOption"
 | 
					      @click="addOption"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <FAIcon
 | 
					      <FAIcon
 | 
				
			||||||
 | 
				
			|||||||
@ -9,11 +9,13 @@ import StatusContent from '../status_content/status_content.vue'
 | 
				
			|||||||
import fileTypeService from '../../services/file_type/file_type.service.js'
 | 
					import fileTypeService from '../../services/file_type/file_type.service.js'
 | 
				
			||||||
import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
 | 
					import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
 | 
				
			||||||
import { reject, map, uniqBy, debounce } from 'lodash'
 | 
					import { reject, map, uniqBy, debounce } from 'lodash'
 | 
				
			||||||
 | 
					import { usePostLanguageOptions } from 'src/lib/post_language'
 | 
				
			||||||
 | 
					import scopeUtils from 'src/lib/scope_utils.js'
 | 
				
			||||||
import suggestor from '../emoji_input/suggestor.js'
 | 
					import suggestor from '../emoji_input/suggestor.js'
 | 
				
			||||||
import { mapGetters, mapState } from 'vuex'
 | 
					import { mapGetters, mapState } from 'vuex'
 | 
				
			||||||
import Checkbox from '../checkbox/checkbox.vue'
 | 
					import Checkbox from '../checkbox/checkbox.vue'
 | 
				
			||||||
import Select from '../select/select.vue'
 | 
					import Select from '../select/select.vue'
 | 
				
			||||||
import iso6391 from 'iso-639-1'
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { library } from '@fortawesome/fontawesome-svg-core'
 | 
					import { library } from '@fortawesome/fontawesome-svg-core'
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@ -62,6 +64,13 @@ const deleteDraft = (draftKey) => {
 | 
				
			|||||||
	localStorage.setItem('drafts', JSON.stringify(draftData));
 | 
						localStorage.setItem('drafts', JSON.stringify(draftData));
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const interfaceToISOLanguage = (ilang) => {
 | 
				
			||||||
 | 
					    const sep = ilang.indexOf("_");
 | 
				
			||||||
 | 
					    return sep < 0 ?
 | 
				
			||||||
 | 
					        ilang :
 | 
				
			||||||
 | 
					        ilang.substr(0, sep);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const PostStatusForm = {
 | 
					const PostStatusForm = {
 | 
				
			||||||
  props: [
 | 
					  props: [
 | 
				
			||||||
    'statusId',
 | 
					    'statusId',
 | 
				
			||||||
@ -77,6 +86,7 @@ const PostStatusForm = {
 | 
				
			|||||||
    'quoteId',
 | 
					    'quoteId',
 | 
				
			||||||
    'repliedUser',
 | 
					    'repliedUser',
 | 
				
			||||||
    'attentions',
 | 
					    'attentions',
 | 
				
			||||||
 | 
					    'copyMessageLanguage',
 | 
				
			||||||
    'copyMessageScope',
 | 
					    'copyMessageScope',
 | 
				
			||||||
    'subject',
 | 
					    'subject',
 | 
				
			||||||
    'disableSubject',
 | 
					    'disableSubject',
 | 
				
			||||||
@ -129,6 +139,13 @@ const PostStatusForm = {
 | 
				
			|||||||
      this.$refs.textarea.focus()
 | 
					      this.$refs.textarea.focus()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
 | 
					  setup() {
 | 
				
			||||||
 | 
					    const {postLanguageOptions} = usePostLanguageOptions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {
 | 
				
			||||||
 | 
					      postLanguageOptions,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  data () {
 | 
					  data () {
 | 
				
			||||||
    const preset = this.$route.query.message
 | 
					    const preset = this.$route.query.message
 | 
				
			||||||
    let statusText = preset || ''
 | 
					    let statusText = preset || ''
 | 
				
			||||||
@ -138,7 +155,7 @@ const PostStatusForm = {
 | 
				
			|||||||
      statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
 | 
					      statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage, alwaysShowSubjectInput } = this.$store.getters.mergedConfig
 | 
					    const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, alwaysShowSubjectInput } = this.$store.getters.mergedConfig
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let statusParams = {
 | 
					    let statusParams = {
 | 
				
			||||||
      spoilerText: this.subject || '',
 | 
					      spoilerText: this.subject || '',
 | 
				
			||||||
@ -149,7 +166,7 @@ const PostStatusForm = {
 | 
				
			|||||||
      poll: {},
 | 
					      poll: {},
 | 
				
			||||||
      mediaDescriptions: {},
 | 
					      mediaDescriptions: {},
 | 
				
			||||||
      visibility: this.suggestedVisibility(),
 | 
					      visibility: this.suggestedVisibility(),
 | 
				
			||||||
      language: interfaceLanguage,
 | 
					      language: this.suggestedLanguage(),
 | 
				
			||||||
      contentType
 | 
					      contentType
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -164,7 +181,7 @@ const PostStatusForm = {
 | 
				
			|||||||
        poll: this.statusPoll || {},
 | 
					        poll: this.statusPoll || {},
 | 
				
			||||||
        mediaDescriptions: this.statusMediaDescriptions || {},
 | 
					        mediaDescriptions: this.statusMediaDescriptions || {},
 | 
				
			||||||
        visibility: this.statusScope || this.suggestedVisibility(),
 | 
					        visibility: this.statusScope || this.suggestedVisibility(),
 | 
				
			||||||
        language: this.statusLanguage || interfaceLanguage,
 | 
					        language: this.statusLanguage || this.suggestedLanguage(),
 | 
				
			||||||
        contentType: statusContentType
 | 
					        contentType: statusContentType
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -309,13 +326,11 @@ const PostStatusForm = {
 | 
				
			|||||||
    ...mapState({
 | 
					    ...mapState({
 | 
				
			||||||
      mobileLayout: state => state.interface.mobileLayout
 | 
					      mobileLayout: state => state.interface.mobileLayout
 | 
				
			||||||
    }),
 | 
					    }),
 | 
				
			||||||
    isoLanguages () {
 | 
					 | 
				
			||||||
      return iso6391.getAllCodes();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  watch: {
 | 
					  watch: {
 | 
				
			||||||
    'newStatus': {
 | 
					    'newStatus': {
 | 
				
			||||||
      deep: true,
 | 
					      deep: true,
 | 
				
			||||||
 | 
					      flush: 'sync',
 | 
				
			||||||
      handler () {
 | 
					      handler () {
 | 
				
			||||||
        this.statusChanged()
 | 
					        this.statusChanged()
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -328,17 +343,22 @@ const PostStatusForm = {
 | 
				
			|||||||
      this.saveDraft()
 | 
					      this.saveDraft()
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    clearStatus () {
 | 
					    clearStatus () {
 | 
				
			||||||
      const newStatus = this.newStatus
 | 
					      const config = this.$store.getters.mergedConfig
 | 
				
			||||||
      this.newStatus = {
 | 
					      this.newStatus = {
 | 
				
			||||||
        status: '',
 | 
					        status: '',
 | 
				
			||||||
        spoilerText: '',
 | 
					        spoilerText: '',
 | 
				
			||||||
        files: [],
 | 
					        files: [],
 | 
				
			||||||
        visibility: newStatus.visibility,
 | 
					        nsfw: !!config.sensitiveByDefault,
 | 
				
			||||||
        contentType: newStatus.contentType,
 | 
					        visibility: this.suggestedVisibility(),
 | 
				
			||||||
        language: newStatus.language,
 | 
					        contentType: config.postContentType,
 | 
				
			||||||
 | 
					        language: this.suggestedLanguage(),
 | 
				
			||||||
        poll: {},
 | 
					        poll: {},
 | 
				
			||||||
        mediaDescriptions: {}
 | 
					        mediaDescriptions: {}
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					      const scopeselector = this.$refs.scopeselector
 | 
				
			||||||
 | 
					      if (scopeselector) {
 | 
				
			||||||
 | 
					        scopeselector.currentScope = this.newStatus.visibility
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
      this.pollFormVisible = false
 | 
					      this.pollFormVisible = false
 | 
				
			||||||
      this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
 | 
					      this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
 | 
				
			||||||
      this.clearPollForm()
 | 
					      this.clearPollForm()
 | 
				
			||||||
@ -498,7 +518,7 @@ const PostStatusForm = {
 | 
				
			|||||||
    addMediaFile (fileInfo) {
 | 
					    addMediaFile (fileInfo) {
 | 
				
			||||||
      this.newStatus.files.push(fileInfo)
 | 
					      this.newStatus.files.push(fileInfo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this.$store.getters.mergedConfig.sensitiveIfSubject && this.newStatus.spoilerText !== '') {
 | 
					      if (this.$store.getters.mergedConfig.sensitiveIfSubject && this.newStatus.spoilerText !== '' || !!this.$store.getters.mergedConfig.sensitiveByDefault) {
 | 
				
			||||||
        this.newStatus.nsfw = true
 | 
					        this.newStatus.nsfw = true
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      this.$emit('resize', { delayed: true })
 | 
					      this.$emit('resize', { delayed: true })
 | 
				
			||||||
@ -747,16 +767,19 @@ const PostStatusForm = {
 | 
				
			|||||||
    openProfileTab () {
 | 
					    openProfileTab () {
 | 
				
			||||||
      this.$store.dispatch('openSettingsModalTab', 'profile')
 | 
					      this.$store.dispatch('openSettingsModalTab', 'profile')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    suggestedLanguage () {
 | 
				
			||||||
 | 
					      // Make sure the inherited language is actually valid
 | 
				
			||||||
 | 
					      if (this.postLanguageOptions.find(o => o.value === this.copyMessageLanguage)) {
 | 
				
			||||||
 | 
					        return this.copyMessageLanguage
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const { postLanguage: defaultPostLanguage, interfaceLanguage } = this.$store.getters.mergedConfig
 | 
				
			||||||
 | 
					      const postLanguage = defaultPostLanguage || interfaceToISOLanguage(interfaceLanguage)
 | 
				
			||||||
 | 
					      return postLanguage
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    suggestedVisibility () {
 | 
					    suggestedVisibility () {
 | 
				
			||||||
      if (this.copyMessageScope) {
 | 
					      const maxScope = this.copyMessageScope
 | 
				
			||||||
        if (this.copyMessageScope === 'direct') {
 | 
					      const defaultScope = this.$store.state.users.currentUser.default_scope
 | 
				
			||||||
          return this.copyMessageScope
 | 
					      return scopeUtils.negotiate(defaultScope, maxScope)
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (this.copyMessageScope !== 'public' && this.$store.state.users.currentUser.default_scope !== 'private') {
 | 
					 | 
				
			||||||
          return this.copyMessageScope
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
      return this.$store.state.users.currentUser.default_scope
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -18,6 +18,7 @@
 | 
				
			|||||||
        >
 | 
					        >
 | 
				
			||||||
          <button
 | 
					          <button
 | 
				
			||||||
            class="button-unstyled -link"
 | 
					            class="button-unstyled -link"
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
            @click="openProfileTab"
 | 
					            @click="openProfileTab"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            {{ $t('post_status.account_not_locked_warning_link') }}
 | 
					            {{ $t('post_status.account_not_locked_warning_link') }}
 | 
				
			||||||
@ -118,8 +119,8 @@
 | 
				
			|||||||
          />
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
        <EmojiInput
 | 
					        <EmojiInput
 | 
				
			||||||
          ref="subject-emoji-input"
 | 
					 | 
				
			||||||
          v-if="subjectVisible"
 | 
					          v-if="subjectVisible"
 | 
				
			||||||
 | 
					          ref="subject-emoji-input"
 | 
				
			||||||
          v-model="newStatus.spoilerText"
 | 
					          v-model="newStatus.spoilerText"
 | 
				
			||||||
          enable-emoji-picker
 | 
					          enable-emoji-picker
 | 
				
			||||||
          hide-emoji-button
 | 
					          hide-emoji-button
 | 
				
			||||||
@ -136,6 +137,7 @@
 | 
				
			|||||||
            class="form-post-subject"
 | 
					            class="form-post-subject"
 | 
				
			||||||
            @input="onSubjectInput"
 | 
					            @input="onSubjectInput"
 | 
				
			||||||
            @focus="focusSubjectInput()"
 | 
					            @focus="focusSubjectInput()"
 | 
				
			||||||
 | 
					            @keydown.exact.enter.prevent
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
        </EmojiInput>
 | 
					        </EmojiInput>
 | 
				
			||||||
        <i18n-t
 | 
					        <i18n-t
 | 
				
			||||||
@ -170,7 +172,7 @@
 | 
				
			|||||||
            cols="1"
 | 
					            cols="1"
 | 
				
			||||||
            :disabled="posting && !optimisticPosting"
 | 
					            :disabled="posting && !optimisticPosting"
 | 
				
			||||||
            class="form-post-body"
 | 
					            class="form-post-body"
 | 
				
			||||||
            :class="{ 'scrollable-form': !!maxHeight }"
 | 
					            :class="{ 'scrollable-form': !!maxHeight, '-has-subject': subjectVisible }"
 | 
				
			||||||
            @keydown.exact.enter="submitOnEnter && postStatus($event, newStatus)"
 | 
					            @keydown.exact.enter="submitOnEnter && postStatus($event, newStatus)"
 | 
				
			||||||
            @keydown.meta.enter="postStatus($event, newStatus)"
 | 
					            @keydown.meta.enter="postStatus($event, newStatus)"
 | 
				
			||||||
            @keydown.ctrl.enter="!submitOnEnter && postStatus($event, newStatus)"
 | 
					            @keydown.ctrl.enter="!submitOnEnter && postStatus($event, newStatus)"
 | 
				
			||||||
@ -190,8 +192,10 @@
 | 
				
			|||||||
        <div
 | 
					        <div
 | 
				
			||||||
          v-if="!disableScopeSelector"
 | 
					          v-if="!disableScopeSelector"
 | 
				
			||||||
          class="visibility-tray"
 | 
					          class="visibility-tray"
 | 
				
			||||||
 | 
					          :class="{ 'visibility-tray-edit': isEdit }"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <scope-selector
 | 
					          <scope-selector
 | 
				
			||||||
 | 
					            ref="scopeselector"
 | 
				
			||||||
            v-if="!disableVisibilitySelector"
 | 
					            v-if="!disableVisibilitySelector"
 | 
				
			||||||
            :user-default="userDefaultScope"
 | 
					            :user-default="userDefaultScope"
 | 
				
			||||||
            :original-scope="copyMessageScope"
 | 
					            :original-scope="copyMessageScope"
 | 
				
			||||||
@ -200,7 +204,9 @@
 | 
				
			|||||||
          />
 | 
					          />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          <div
 | 
					          <div
 | 
				
			||||||
            class="language-selector"
 | 
					            class="format-selector-container">
 | 
				
			||||||
 | 
					            <div
 | 
				
			||||||
 | 
					              class="format-selector"
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
              <Select
 | 
					              <Select
 | 
				
			||||||
                id="post-language"
 | 
					                id="post-language"
 | 
				
			||||||
@ -208,17 +214,17 @@
 | 
				
			|||||||
                class="form-control"
 | 
					                class="form-control"
 | 
				
			||||||
              >
 | 
					              >
 | 
				
			||||||
                <option
 | 
					                <option
 | 
				
			||||||
                v-for="language in isoLanguages"
 | 
					                  v-for="language in postLanguageOptions"
 | 
				
			||||||
                :key="language"
 | 
					                  :key="language.key"
 | 
				
			||||||
                :value="language"
 | 
					                  :value="language.value"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                {{ language }}
 | 
					                  {{ language.label }}
 | 
				
			||||||
                </option>
 | 
					                </option>
 | 
				
			||||||
              </Select>
 | 
					              </Select>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div
 | 
					            <div
 | 
				
			||||||
              v-if="postFormats.length > 1"
 | 
					              v-if="postFormats.length > 1"
 | 
				
			||||||
            class="text-format"
 | 
					              class="text-format format-selector"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <Select
 | 
					              <Select
 | 
				
			||||||
                id="post-content-type"
 | 
					                id="post-content-type"
 | 
				
			||||||
@ -236,7 +242,7 @@
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div
 | 
					            <div
 | 
				
			||||||
              v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
 | 
					              v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
 | 
				
			||||||
            class="text-format"
 | 
					              class="text-format format-selector"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <span class="only-format">
 | 
					              <span class="only-format">
 | 
				
			||||||
                {{ $t(`post_status.content_type["${postFormats[0]}"]`) }}
 | 
					                {{ $t(`post_status.content_type["${postFormats[0]}"]`) }}
 | 
				
			||||||
@ -244,6 +250,7 @@
 | 
				
			|||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
      <poll-form
 | 
					      <poll-form
 | 
				
			||||||
        v-if="pollsAvailable"
 | 
					        v-if="pollsAvailable"
 | 
				
			||||||
        ref="pollForm"
 | 
					        ref="pollForm"
 | 
				
			||||||
@ -268,6 +275,7 @@
 | 
				
			|||||||
          <button
 | 
					          <button
 | 
				
			||||||
            class="emoji-icon button-unstyled"
 | 
					            class="emoji-icon button-unstyled"
 | 
				
			||||||
            :title="$t('emoji.add_emoji')"
 | 
					            :title="$t('emoji.add_emoji')"
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
            @click="showEmojiPicker"
 | 
					            @click="showEmojiPicker"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <FAIcon icon="smile-beam" />
 | 
					            <FAIcon icon="smile-beam" />
 | 
				
			||||||
@ -277,6 +285,7 @@
 | 
				
			|||||||
            class="poll-icon button-unstyled"
 | 
					            class="poll-icon button-unstyled"
 | 
				
			||||||
            :class="{ selected: pollFormVisible }"
 | 
					            :class="{ selected: pollFormVisible }"
 | 
				
			||||||
            :title="$t('polls.add_poll')"
 | 
					            :title="$t('polls.add_poll')"
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
            @click="togglePollForm"
 | 
					            @click="togglePollForm"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <FAIcon icon="poll-h" />
 | 
					            <FAIcon icon="poll-h" />
 | 
				
			||||||
@ -286,6 +295,7 @@
 | 
				
			|||||||
            class="spoiler-icon button-unstyled"
 | 
					            class="spoiler-icon button-unstyled"
 | 
				
			||||||
            :class="{ selected: subjectVisible }"
 | 
					            :class="{ selected: subjectVisible }"
 | 
				
			||||||
            :title="$t('post_status.toggle_content_warning')"
 | 
					            :title="$t('post_status.toggle_content_warning')"
 | 
				
			||||||
 | 
					            type="button"
 | 
				
			||||||
            @click="toggleSubjectVisible"
 | 
					            @click="toggleSubjectVisible"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <FAIcon icon="eye-slash" />
 | 
					            <FAIcon icon="eye-slash" />
 | 
				
			||||||
@ -460,6 +470,10 @@
 | 
				
			|||||||
    align-items: baseline;
 | 
					    align-items: baseline;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .visibility-tray-edit {
 | 
				
			||||||
 | 
					    justify-content: right;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .visibility-notice.edit-warning {
 | 
					  .visibility-notice.edit-warning {
 | 
				
			||||||
    > :first-child {
 | 
					    > :first-child {
 | 
				
			||||||
      margin-top: 0;
 | 
					      margin-top: 0;
 | 
				
			||||||
@ -470,6 +484,12 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .format-selector-container {
 | 
				
			||||||
 | 
					    .format-selector {
 | 
				
			||||||
 | 
					      display: inline-block;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .media-upload-icon, .poll-icon, .emoji-icon, .spoiler-icon {
 | 
					  .media-upload-icon, .poll-icon, .emoji-icon, .spoiler-icon {
 | 
				
			||||||
    font-size: 1.85em;
 | 
					    font-size: 1.85em;
 | 
				
			||||||
    line-height: 1.1;
 | 
					    line-height: 1.1;
 | 
				
			||||||
@ -570,6 +590,11 @@
 | 
				
			|||||||
    line-height: 1.85;
 | 
					    line-height: 1.85;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .form-post-subject {
 | 
				
			||||||
 | 
					    border-bottom-left-radius: 0;
 | 
				
			||||||
 | 
					    border-bottom-right-radius: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .form-post-body {
 | 
					  .form-post-body {
 | 
				
			||||||
    // TODO: make a resizable textarea component?
 | 
					    // TODO: make a resizable textarea component?
 | 
				
			||||||
    box-sizing: content-box; // needed for easier computation of dynamic size
 | 
					    box-sizing: content-box; // needed for easier computation of dynamic size
 | 
				
			||||||
@ -582,6 +607,11 @@
 | 
				
			|||||||
    min-height: calc(var(--post-line-height) * 1em);
 | 
					    min-height: calc(var(--post-line-height) * 1em);
 | 
				
			||||||
    resize: none;
 | 
					    resize: none;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.-has-subject {
 | 
				
			||||||
 | 
					      border-top-left-radius: 0;
 | 
				
			||||||
 | 
					      border-top-right-radius: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    &.scrollable-form {
 | 
					    &.scrollable-form {
 | 
				
			||||||
      overflow-y: auto;
 | 
					      overflow-y: auto;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -3,7 +3,7 @@
 | 
				
			|||||||
    v-if="isLoggedIn && !resettingForm"
 | 
					    v-if="isLoggedIn && !resettingForm"
 | 
				
			||||||
    :is-open="modalActivated"
 | 
					    :is-open="modalActivated"
 | 
				
			||||||
    class="post-form-modal-view"
 | 
					    class="post-form-modal-view"
 | 
				
			||||||
    @backdropClicked="closeModal"
 | 
					    @backdrop-clicked="closeModal"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <div class="post-form-modal-panel panel">
 | 
					    <div class="post-form-modal-panel panel">
 | 
				
			||||||
      <div class="panel-heading">
 | 
					      <div class="panel-heading">
 | 
				
			||||||
 | 
				
			|||||||
@ -8,13 +8,13 @@
 | 
				
			|||||||
    remove-padding
 | 
					    remove-padding
 | 
				
			||||||
    @show="focusInput"
 | 
					    @show="focusInput"
 | 
				
			||||||
  >
 | 
					  >
 | 
				
			||||||
    <template v-slot:content="{close}">
 | 
					    <template #content="{close}">
 | 
				
			||||||
      <EmojiPicker
 | 
					      <EmojiPicker
 | 
				
			||||||
        :enable-sticker-picker="false"
 | 
					        :enable-sticker-picker="false"
 | 
				
			||||||
        @emoji="addReaction($event, close)"
 | 
					        @emoji="addReaction($event, close)"
 | 
				
			||||||
      />
 | 
					      />
 | 
				
			||||||
    </template>
 | 
					    </template>
 | 
				
			||||||
    <template v-slot:trigger>
 | 
					    <template #trigger>
 | 
				
			||||||
      <button
 | 
					      <button
 | 
				
			||||||
        class="button-unstyled popover-trigger"
 | 
					        class="button-unstyled popover-trigger"
 | 
				
			||||||
        :title="$t('tool_tip.add_reaction')"
 | 
					        :title="$t('tool_tip.add_reaction')"
 | 
				
			||||||
@ -28,7 +28,7 @@
 | 
				
			|||||||
  </Popover>
 | 
					  </Popover>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./react_button.js" ></script>
 | 
					<script src="./react_button.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@ export default {
 | 
				
			|||||||
  props: [ 'user' ],
 | 
					  props: [ 'user' ],
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    subscribeUrl () {
 | 
					    subscribeUrl () {
 | 
				
			||||||
      // eslint-disable-next-line no-undef
 | 
					       
 | 
				
			||||||
      const serverUrl = new URL(this.user.statusnet_profile_url)
 | 
					      const serverUrl = new URL(this.user.statusnet_profile_url)
 | 
				
			||||||
      return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
 | 
					      return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,6 @@
 | 
				
			|||||||
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
 | 
					import ConfirmModal from '../confirm_modal/confirm_modal.vue'
 | 
				
			||||||
 | 
					import ScopeSelector from '../scope_selector/scope_selector.vue'
 | 
				
			||||||
 | 
					import scopeUtils from 'src/lib/scope_utils.js'
 | 
				
			||||||
import { library } from '@fortawesome/fontawesome-svg-core'
 | 
					import { library } from '@fortawesome/fontawesome-svg-core'
 | 
				
			||||||
import { faRetweet } from '@fortawesome/free-solid-svg-icons'
 | 
					import { faRetweet } from '@fortawesome/free-solid-svg-icons'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -7,12 +9,14 @@ library.add(faRetweet)
 | 
				
			|||||||
const RetweetButton = {
 | 
					const RetweetButton = {
 | 
				
			||||||
  props: ['status', 'loggedIn', 'visibility'],
 | 
					  props: ['status', 'loggedIn', 'visibility'],
 | 
				
			||||||
  components: {
 | 
					  components: {
 | 
				
			||||||
    ConfirmModal
 | 
					    ConfirmModal,
 | 
				
			||||||
 | 
					    ScopeSelector
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  data () {
 | 
					  data () {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      animated: false,
 | 
					      animated: false,
 | 
				
			||||||
      showingConfirmDialog: false
 | 
					      showingConfirmDialog: false,
 | 
				
			||||||
 | 
					      retweetVisibility: this.$store.state.users.currentUser.default_scope
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
@ -25,7 +29,7 @@ const RetweetButton = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    doRetweet () {
 | 
					    doRetweet () {
 | 
				
			||||||
      if (!this.status.repeated) {
 | 
					      if (!this.status.repeated) {
 | 
				
			||||||
        this.$store.dispatch('retweet', { id: this.status.id })
 | 
					        this.$store.dispatch('retweet', { id: this.status.id, visibility: this.retweetVisibility })
 | 
				
			||||||
      } else {
 | 
					      } else {
 | 
				
			||||||
        this.$store.dispatch('unretweet', { id: this.status.id })
 | 
					        this.$store.dispatch('unretweet', { id: this.status.id })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
@ -40,6 +44,9 @@ const RetweetButton = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    hideConfirmDialog () {
 | 
					    hideConfirmDialog () {
 | 
				
			||||||
      this.showingConfirmDialog = false
 | 
					      this.showingConfirmDialog = false
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    changeVis (visibility) {
 | 
				
			||||||
 | 
					      this.retweetVisibility = visibility
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
@ -54,6 +61,15 @@ const RetweetButton = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    remoteInteractionLink () {
 | 
					    remoteInteractionLink () {
 | 
				
			||||||
      return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
 | 
					      return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    userDefaultScope () {
 | 
				
			||||||
 | 
					      return this.$store.state.users.currentUser.default_scope
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    statusScope () {
 | 
				
			||||||
 | 
					      return this.status.visibility
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    initialScope () {
 | 
				
			||||||
 | 
					      return scopeUtils.negotiate(this.userDefaultScope, this.status.visibility)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -49,12 +49,18 @@
 | 
				
			|||||||
        @cancelled="hideConfirmDialog"
 | 
					        @cancelled="hideConfirmDialog"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        {{ $t('status.repeat_confirm') }}
 | 
					        {{ $t('status.repeat_confirm') }}
 | 
				
			||||||
 | 
					        <scope-selector
 | 
				
			||||||
 | 
					          :user-default="userDefaultScope"
 | 
				
			||||||
 | 
					          :original-scope="statusScope"
 | 
				
			||||||
 | 
					          :initial-scope="initialScope"
 | 
				
			||||||
 | 
					          :on-scope-change="changeVis"
 | 
				
			||||||
 | 
					        />
 | 
				
			||||||
      </confirm-modal>
 | 
					      </confirm-modal>
 | 
				
			||||||
    </teleport>
 | 
					    </teleport>
 | 
				
			||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./retweet_button.js" ></script>
 | 
					<script src="./retweet_button.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -121,6 +121,19 @@ export default {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const mfmStyleFromDataAttributes = (attributes) => {
 | 
				
			||||||
 | 
					      // CSS selectors can check if a data-* attribute is true, but can't use other values, so we want to add them to the style attribute
 | 
				
			||||||
 | 
					      // Here we turn e.g. `{'data-mfm-some': '1deg', 'data-mfm-thing': '5s'}` to "--mfm-some: 1deg;--mfm-thing: 5s;"
 | 
				
			||||||
 | 
					      // Note that we only add the value to `style` when they contain only letters, numbers, dot, or minus signs
 | 
				
			||||||
 | 
					      // At the moment of writing, this should be enough for legitimate purposes and reduces the chance of injection by using special characters
 | 
				
			||||||
 | 
					      // There is a special case for the `color` value, who is provided without `#`, but requires this in the `style` attribute
 | 
				
			||||||
 | 
					      return Object.keys(attributes).filter(
 | 
				
			||||||
 | 
					        (key) => key.startsWith('data-mfm-') && attributes[key] !== true && /^[a-zA-Z0-9.\-]*$/.test(attributes[key])
 | 
				
			||||||
 | 
					      ).map(
 | 
				
			||||||
 | 
					        (key) => '--mfm-' + key.substr(9) + (key === 'data-mfm-color' ? ': #' : ': ') + attributes[key] + ';'
 | 
				
			||||||
 | 
					      ).reduce((a,v) => a+v, '')
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Processor to use with html_tree_converter
 | 
					    // Processor to use with html_tree_converter
 | 
				
			||||||
    const processItem = (item, index, array, what) => {
 | 
					    const processItem = (item, index, array, what) => {
 | 
				
			||||||
      // Handle text nodes - just add emoji
 | 
					      // Handle text nodes - just add emoji
 | 
				
			||||||
@ -191,6 +204,15 @@ export default {
 | 
				
			|||||||
            if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) {
 | 
					            if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) {
 | 
				
			||||||
              return ['', children.map(processItem), '']
 | 
					              return ['', children.map(processItem), '']
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            let mfm_style = mfmStyleFromDataAttributes(attrs)
 | 
				
			||||||
 | 
					            if (mfm_style !== '') {
 | 
				
			||||||
 | 
					              return [
 | 
				
			||||||
 | 
					                opener.slice(0,-1) + ' style="' + mfm_style + '">',
 | 
				
			||||||
 | 
					                children.map(processItem),
 | 
				
			||||||
 | 
					                closer
 | 
				
			||||||
 | 
					              ]
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (children !== undefined) {
 | 
					        if (children !== undefined) {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,6 +6,8 @@ import {
 | 
				
			|||||||
  faGlobe
 | 
					  faGlobe
 | 
				
			||||||
} from '@fortawesome/free-solid-svg-icons'
 | 
					} from '@fortawesome/free-solid-svg-icons'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import scopeUtils from 'src/lib/scope_utils.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
library.add(
 | 
					library.add(
 | 
				
			||||||
  faEnvelope,
 | 
					  faEnvelope,
 | 
				
			||||||
  faGlobe,
 | 
					  faGlobe,
 | 
				
			||||||
@ -13,18 +15,11 @@ library.add(
 | 
				
			|||||||
  faLockOpen
 | 
					  faLockOpen
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const SCOPE_LEVELS = {
 | 
					 | 
				
			||||||
  'direct': 0,
 | 
					 | 
				
			||||||
  'private': 1,
 | 
					 | 
				
			||||||
  'local': 2,
 | 
					 | 
				
			||||||
  'unlisted': 2,
 | 
					 | 
				
			||||||
  'public': 3
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const ScopeSelector = {
 | 
					const ScopeSelector = {
 | 
				
			||||||
  props: [
 | 
					  props: [
 | 
				
			||||||
    'showAll',
 | 
					    'showAll',
 | 
				
			||||||
    'userDefault',
 | 
					    'userDefault',
 | 
				
			||||||
 | 
					    // scope of parent object
 | 
				
			||||||
    'originalScope',
 | 
					    'originalScope',
 | 
				
			||||||
    'initialScope',
 | 
					    'initialScope',
 | 
				
			||||||
    'onScopeChange'
 | 
					    'onScopeChange'
 | 
				
			||||||
@ -39,16 +34,16 @@ const ScopeSelector = {
 | 
				
			|||||||
      return !this.showPublic && !this.showUnlisted && !this.showPrivate && !this.showDirect
 | 
					      return !this.showPublic && !this.showUnlisted && !this.showPrivate && !this.showDirect
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    showPublic () {
 | 
					    showPublic () {
 | 
				
			||||||
      return this.originalScope !== 'direct' && this.shouldShow('public')
 | 
					      return this.shouldShow('public')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    showLocal () {
 | 
					    showLocal () {
 | 
				
			||||||
      return this.originalScope !== 'direct' && this.shouldShow('local')
 | 
					      return this.shouldShow('local')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    showUnlisted () {
 | 
					    showUnlisted () {
 | 
				
			||||||
      return this.originalScope !== 'direct' && this.shouldShow('unlisted')
 | 
					      return this.shouldShow('unlisted')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    showPrivate () {
 | 
					    showPrivate () {
 | 
				
			||||||
      return this.originalScope !== 'direct' && this.shouldShow('private')
 | 
					      return this.shouldShow('private')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    showDirect () {
 | 
					    showDirect () {
 | 
				
			||||||
      return this.shouldShow('direct')
 | 
					      return this.shouldShow('direct')
 | 
				
			||||||
@ -65,15 +60,10 @@ const ScopeSelector = {
 | 
				
			|||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    shouldShow (scope) {
 | 
					    shouldShow (scope) {
 | 
				
			||||||
      if (!this.originalScope) {
 | 
					      if (!this.originalScope)
 | 
				
			||||||
        return true
 | 
					        return true
 | 
				
			||||||
      }
 | 
					      else
 | 
				
			||||||
 | 
					        return scopeUtils.compare(scope, this.originalScope) <= 0
 | 
				
			||||||
      if (this.originalScope === 'local') {
 | 
					 | 
				
			||||||
        return scope === 'direct' || scope === 'local'
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      return SCOPE_LEVELS[scope] <= SCOPE_LEVELS[this.originalScope]
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    changeVis (scope) {
 | 
					    changeVis (scope) {
 | 
				
			||||||
      this.currentScope = scope
 | 
					      this.currentScope = scope
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@
 | 
				
			|||||||
      :items="items"
 | 
					      :items="items"
 | 
				
			||||||
      :get-key="getKey"
 | 
					      :get-key="getKey"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <template v-slot:item="{item}">
 | 
					      <template #item="{item}">
 | 
				
			||||||
        <div
 | 
					        <div
 | 
				
			||||||
          class="selectable-list-item-inner"
 | 
					          class="selectable-list-item-inner"
 | 
				
			||||||
          :class="{ 'selectable-list-item-selected-inner': isSelected(item) }"
 | 
					          :class="{ 'selectable-list-item-selected-inner': isSelected(item) }"
 | 
				
			||||||
@ -41,7 +41,7 @@
 | 
				
			|||||||
          />
 | 
					          />
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <template v-slot:empty>
 | 
					      <template #empty>
 | 
				
			||||||
        <slot name="empty" />
 | 
					        <slot name="empty" />
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
    </List>
 | 
					    </List>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
    <Checkbox
 | 
					    <Checkbox
 | 
				
			||||||
      :model-value="state"
 | 
					      :model-value="state"
 | 
				
			||||||
      :disabled="disabled"
 | 
					      :disabled="disabled"
 | 
				
			||||||
      @update:modelValue="update"
 | 
					      @update:model-value="update"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <span
 | 
					      <span
 | 
				
			||||||
        v-if="!!$slots.default"
 | 
					        v-if="!!$slots.default"
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@
 | 
				
			|||||||
    <Select
 | 
					    <Select
 | 
				
			||||||
      :model-value="state"
 | 
					      :model-value="state"
 | 
				
			||||||
      :disabled="disabled"
 | 
					      :disabled="disabled"
 | 
				
			||||||
      @update:modelValue="update"
 | 
					      @update:model-value="update"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <option
 | 
					      <option
 | 
				
			||||||
        v-for="option in options"
 | 
					        v-for="option in options"
 | 
				
			||||||
 | 
				
			|||||||
@ -6,14 +6,14 @@
 | 
				
			|||||||
    <Popover
 | 
					    <Popover
 | 
				
			||||||
      trigger="hover"
 | 
					      trigger="hover"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <template v-slot:trigger>
 | 
					      <template #trigger>
 | 
				
			||||||
         
 | 
					         
 | 
				
			||||||
        <FAIcon
 | 
					        <FAIcon
 | 
				
			||||||
          icon="wrench"
 | 
					          icon="wrench"
 | 
				
			||||||
          :aria-label="$t('settings.setting_changed')"
 | 
					          :aria-label="$t('settings.setting_changed')"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <template v-slot:content>
 | 
					      <template #content>
 | 
				
			||||||
        <div class="modified-tooltip">
 | 
					        <div class="modified-tooltip">
 | 
				
			||||||
          {{ $t('settings.setting_changed') }}
 | 
					          {{ $t('settings.setting_changed') }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -6,14 +6,14 @@
 | 
				
			|||||||
    <Popover
 | 
					    <Popover
 | 
				
			||||||
      trigger="hover"
 | 
					      trigger="hover"
 | 
				
			||||||
    >
 | 
					    >
 | 
				
			||||||
      <template v-slot:trigger>
 | 
					      <template #trigger>
 | 
				
			||||||
         
 | 
					         
 | 
				
			||||||
        <FAIcon
 | 
					        <FAIcon
 | 
				
			||||||
          icon="server"
 | 
					          icon="server"
 | 
				
			||||||
          :aria-label="$t('settings.setting_server_side')"
 | 
					          :aria-label="$t('settings.setting_server_side')"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
      </template>
 | 
					      </template>
 | 
				
			||||||
      <template v-slot:content>
 | 
					      <template #content>
 | 
				
			||||||
        <div class="serverside-tooltip">
 | 
					        <div class="serverside-tooltip">
 | 
				
			||||||
          {{ $t('settings.setting_server_side') }}
 | 
					          {{ $t('settings.setting_server_side') }}
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
				
			|||||||
@ -69,7 +69,7 @@ const SettingsModal = {
 | 
				
			|||||||
      this.$store.dispatch('closeSettingsModal')
 | 
					      this.$store.dispatch('closeSettingsModal')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    logout () {
 | 
					    logout () {
 | 
				
			||||||
      this.$router.replace('/main/public')
 | 
					      this.$router.replace(this.$store.state.instance.redirectRootNoLogin || '/main/all')
 | 
				
			||||||
      this.$store.dispatch('closeSettingsModal')
 | 
					      this.$store.dispatch('closeSettingsModal')
 | 
				
			||||||
      this.$store.dispatch('logout')
 | 
					      this.$store.dispatch('logout')
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
				
			|||||||
@ -108,7 +108,7 @@
 | 
				
			|||||||
        <Checkbox
 | 
					        <Checkbox
 | 
				
			||||||
          :model-value="!!expertLevel"
 | 
					          :model-value="!!expertLevel"
 | 
				
			||||||
          class="expertMode"
 | 
					          class="expertMode"
 | 
				
			||||||
          @update:modelValue="expertLevel = Number($event)"
 | 
					          @update:model-value="expertLevel = Number($event)"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          {{ $t("settings.expert_mode") }}
 | 
					          {{ $t("settings.expert_mode") }}
 | 
				
			||||||
        </Checkbox>
 | 
					        </Checkbox>
 | 
				
			||||||
 | 
				
			|||||||
@ -72,7 +72,7 @@ const DataImportExportTab = {
 | 
				
			|||||||
        // check is it's a local user
 | 
					        // check is it's a local user
 | 
				
			||||||
        if (user && user.is_local) {
 | 
					        if (user && user.is_local) {
 | 
				
			||||||
          // append the instance address
 | 
					          // append the instance address
 | 
				
			||||||
          // eslint-disable-next-line no-undef
 | 
					           
 | 
				
			||||||
          return user.screen_name + '@' + location.hostname
 | 
					          return user.screen_name + '@' + location.hostname
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return user.screen_name
 | 
					        return user.screen_name
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ 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 InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
 | 
					import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import { usePostLanguageOptions } from 'src/lib/post_language'
 | 
				
			||||||
import SharedComputedObject from '../helpers/shared_computed_object.js'
 | 
					import SharedComputedObject from '../helpers/shared_computed_object.js'
 | 
				
			||||||
import ServerSideIndicator from '../helpers/server_side_indicator.vue'
 | 
					import ServerSideIndicator from '../helpers/server_side_indicator.vue'
 | 
				
			||||||
import { library } from '@fortawesome/fontawesome-svg-core'
 | 
					import { library } from '@fortawesome/fontawesome-svg-core'
 | 
				
			||||||
@ -17,6 +18,11 @@ library.add(
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const GeneralTab = {
 | 
					const GeneralTab = {
 | 
				
			||||||
 | 
					  setup() {
 | 
				
			||||||
 | 
					    const {postLanguageOptions} = usePostLanguageOptions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return {postLanguageOptions}
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
  data () {
 | 
					  data () {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      subjectLineOptions: ['email', 'noop', 'masto'].map(mode => ({
 | 
					      subjectLineOptions: ['email', 'noop', 'masto'].map(mode => ({
 | 
				
			||||||
@ -118,6 +124,12 @@ const GeneralTab = {
 | 
				
			|||||||
        this.$store.dispatch('setOption', { name: 'translationLanguage', value: val })
 | 
					        this.$store.dispatch('setOption', { name: 'translationLanguage', value: val })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    postLanguage: {
 | 
				
			||||||
 | 
					      get: function () { return this.$store.getters.mergedConfig.postLanguage },
 | 
				
			||||||
 | 
					      set: function (val) {
 | 
				
			||||||
 | 
					        this.$store.dispatch('setOption', { name: 'postLanguage', value: val })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    ...SharedComputedObject()
 | 
					    ...SharedComputedObject()
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
 | 
				
			|||||||
@ -44,7 +44,6 @@
 | 
				
			|||||||
          <template
 | 
					          <template
 | 
				
			||||||
            v-if="profilesExpanded"
 | 
					            v-if="profilesExpanded"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
 | 
					 | 
				
			||||||
            <div
 | 
					            <div
 | 
				
			||||||
              v-for="profile in settingsProfiles"
 | 
					              v-for="profile in settingsProfiles"
 | 
				
			||||||
              :key="profile.id"
 | 
					              :key="profile.id"
 | 
				
			||||||
@ -73,15 +72,24 @@
 | 
				
			|||||||
                </button>
 | 
					                </button>
 | 
				
			||||||
              </template>
 | 
					              </template>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <button class="btn button-default" @click="refreshProfiles()">
 | 
					            <button
 | 
				
			||||||
 | 
					              class="btn button-default"
 | 
				
			||||||
 | 
					              @click="refreshProfiles()"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
              {{ $t('settings.settings_profiles_refresh') }}
 | 
					              {{ $t('settings.settings_profiles_refresh') }}
 | 
				
			||||||
              <FAIcon icon="sync" @click="refreshProfiles()" />
 | 
					              <FAIcon
 | 
				
			||||||
 | 
					                icon="sync"
 | 
				
			||||||
 | 
					                @click="refreshProfiles()"
 | 
				
			||||||
 | 
					              />
 | 
				
			||||||
            </button>
 | 
					            </button>
 | 
				
			||||||
            <h3>{{ $t('settings.settings_profile_creation') }}</h3>
 | 
					            <h3>{{ $t('settings.settings_profile_creation') }}</h3>
 | 
				
			||||||
            <label for="settings-profile-new-name">
 | 
					            <label for="settings-profile-new-name">
 | 
				
			||||||
              {{ $t('settings.settings_profile_creation_new_name_label') }}
 | 
					              {{ $t('settings.settings_profile_creation_new_name_label') }}
 | 
				
			||||||
            </label>
 | 
					            </label>
 | 
				
			||||||
            <input v-model="newProfileName" id="settings-profile-new-name">
 | 
					            <input
 | 
				
			||||||
 | 
					              id="settings-profile-new-name"
 | 
				
			||||||
 | 
					              v-model="newProfileName"
 | 
				
			||||||
 | 
					            >
 | 
				
			||||||
            <button
 | 
					            <button
 | 
				
			||||||
              class="btn button-default"
 | 
					              class="btn button-default"
 | 
				
			||||||
              @click="createSettingsProfile"
 | 
					              @click="createSettingsProfile"
 | 
				
			||||||
@ -151,6 +159,16 @@
 | 
				
			|||||||
            {{ $t('settings.show_page_backgrounds') }}
 | 
					            {{ $t('settings.show_page_backgrounds') }}
 | 
				
			||||||
          </BooleanSetting>
 | 
					          </BooleanSetting>
 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <BooleanSetting path="centerAlignBio">
 | 
				
			||||||
 | 
					            {{ $t('settings.center_align_bio') }}
 | 
				
			||||||
 | 
					          </BooleanSetting>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <BooleanSetting path="compactUserInfo">
 | 
				
			||||||
 | 
					            {{ $t('settings.compact_user_info') }}
 | 
				
			||||||
 | 
					          </BooleanSetting>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
        <li>
 | 
					        <li>
 | 
				
			||||||
          <BooleanSetting path="stopGifs">
 | 
					          <BooleanSetting path="stopGifs">
 | 
				
			||||||
            {{ $t('settings.stop_gifs') }}
 | 
					            {{ $t('settings.stop_gifs') }}
 | 
				
			||||||
@ -261,6 +279,11 @@
 | 
				
			|||||||
            {{ $t('settings.right_sidebar') }}
 | 
					            {{ $t('settings.right_sidebar') }}
 | 
				
			||||||
          </BooleanSetting>
 | 
					          </BooleanSetting>
 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <BooleanSetting path="widenTimeline">
 | 
				
			||||||
 | 
					            {{ $t('settings.widen_timeline') }}
 | 
				
			||||||
 | 
					          </BooleanSetting>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
        <li>
 | 
					        <li>
 | 
				
			||||||
          <ChoiceSetting
 | 
					          <ChoiceSetting
 | 
				
			||||||
            v-if="user"
 | 
					            v-if="user"
 | 
				
			||||||
@ -585,6 +608,15 @@
 | 
				
			|||||||
            {{ $t('settings.post_status_content_type') }}
 | 
					            {{ $t('settings.post_status_content_type') }}
 | 
				
			||||||
          </ChoiceSetting>
 | 
					          </ChoiceSetting>
 | 
				
			||||||
        </li>
 | 
					        </li>
 | 
				
			||||||
 | 
					        <li>
 | 
				
			||||||
 | 
					          <ChoiceSetting
 | 
				
			||||||
 | 
					            id="postLanguage"
 | 
				
			||||||
 | 
					            path="postLanguage"
 | 
				
			||||||
 | 
					            :options="postLanguageOptions"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
 | 
					            {{ $t('settings.post_language') }}
 | 
				
			||||||
 | 
					          </ChoiceSetting>
 | 
				
			||||||
 | 
					        </li>
 | 
				
			||||||
        <li>
 | 
					        <li>
 | 
				
			||||||
          <BooleanSetting
 | 
					          <BooleanSetting
 | 
				
			||||||
            path="alwaysShowNewPostButton"
 | 
					            path="alwaysShowNewPostButton"
 | 
				
			||||||
 | 
				
			|||||||
@ -85,7 +85,7 @@ const MutesAndBlocks = {
 | 
				
			|||||||
        // check is it's a local user
 | 
					        // check is it's a local user
 | 
				
			||||||
        if (user && user.is_local) {
 | 
					        if (user && user.is_local) {
 | 
				
			||||||
          // append the instance address
 | 
					          // append the instance address
 | 
				
			||||||
          // eslint-disable-next-line no-undef
 | 
					           
 | 
				
			||||||
          return user.screen_name + '@' + location.hostname
 | 
					          return user.screen_name + '@' + location.hostname
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return user.screen_name
 | 
					        return user.screen_name
 | 
				
			||||||
 | 
				
			|||||||
@ -10,7 +10,7 @@
 | 
				
			|||||||
          :query="queryUserIds"
 | 
					          :query="queryUserIds"
 | 
				
			||||||
          :placeholder="$t('settings.search_user_to_block')"
 | 
					          :placeholder="$t('settings.search_user_to_block')"
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
          <template v-slot="row">
 | 
					          <template #default="row">
 | 
				
			||||||
            <BlockCard
 | 
					            <BlockCard
 | 
				
			||||||
              :user-id="row.item"
 | 
					              :user-id="row.item"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
@ -21,7 +21,7 @@
 | 
				
			|||||||
        :refresh="true"
 | 
					        :refresh="true"
 | 
				
			||||||
        :get-key="i => i"
 | 
					        :get-key="i => i"
 | 
				
			||||||
      >
 | 
					      >
 | 
				
			||||||
        <template v-slot:header="{selected}">
 | 
					        <template #header="{selected}">
 | 
				
			||||||
          <div class="bulk-actions">
 | 
					          <div class="bulk-actions">
 | 
				
			||||||
            <ProgressButton
 | 
					            <ProgressButton
 | 
				
			||||||
              v-if="selected.length > 0"
 | 
					              v-if="selected.length > 0"
 | 
				
			||||||
@ -29,7 +29,7 @@
 | 
				
			|||||||
              :click="() => blockUsers(selected)"
 | 
					              :click="() => blockUsers(selected)"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {{ $t('user_card.block') }}
 | 
					              {{ $t('user_card.block') }}
 | 
				
			||||||
              <template v-slot:progress>
 | 
					              <template #progress>
 | 
				
			||||||
                {{ $t('user_card.block_progress') }}
 | 
					                {{ $t('user_card.block_progress') }}
 | 
				
			||||||
              </template>
 | 
					              </template>
 | 
				
			||||||
            </ProgressButton>
 | 
					            </ProgressButton>
 | 
				
			||||||
@ -39,16 +39,16 @@
 | 
				
			|||||||
              :click="() => unblockUsers(selected)"
 | 
					              :click="() => unblockUsers(selected)"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              {{ $t('user_card.unblock') }}
 | 
					              {{ $t('user_card.unblock') }}
 | 
				
			||||||
              <template v-slot:progress>
 | 
					              <template #progress>
 | 
				
			||||||
                {{ $t('user_card.unblock_progress') }}
 | 
					                {{ $t('user_card.unblock_progress') }}
 | 
				
			||||||
              </template>
 | 
					              </template>
 | 
				
			||||||
            </ProgressButton>
 | 
					            </ProgressButton>
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
        <template v-slot:item="{item}">
 | 
					        <template #item="{item}">
 | 
				
			||||||
          <BlockCard :user-id="item" />
 | 
					          <BlockCard :user-id="item" />
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
        <template v-slot:empty>
 | 
					        <template #empty>
 | 
				
			||||||
          {{ $t('settings.no_blocks') }}
 | 
					          {{ $t('settings.no_blocks') }}
 | 
				
			||||||
        </template>
 | 
					        </template>
 | 
				
			||||||
      </BlockList>
 | 
					      </BlockList>
 | 
				
			||||||
@ -63,7 +63,7 @@
 | 
				
			|||||||
              :query="queryUserIds"
 | 
					              :query="queryUserIds"
 | 
				
			||||||
              :placeholder="$t('settings.search_user_to_mute')"
 | 
					              :placeholder="$t('settings.search_user_to_mute')"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <template v-slot="row">
 | 
					              <template #default="row">
 | 
				
			||||||
                <MuteCard
 | 
					                <MuteCard
 | 
				
			||||||
                  :user-id="row.item"
 | 
					                  :user-id="row.item"
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
@ -74,7 +74,7 @@
 | 
				
			|||||||
            :refresh="true"
 | 
					            :refresh="true"
 | 
				
			||||||
            :get-key="i => i"
 | 
					            :get-key="i => i"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <template v-slot:header="{selected}">
 | 
					            <template #header="{selected}">
 | 
				
			||||||
              <div class="bulk-actions">
 | 
					              <div class="bulk-actions">
 | 
				
			||||||
                <ProgressButton
 | 
					                <ProgressButton
 | 
				
			||||||
                  v-if="selected.length > 0"
 | 
					                  v-if="selected.length > 0"
 | 
				
			||||||
@ -82,7 +82,7 @@
 | 
				
			|||||||
                  :click="() => muteUsers(selected)"
 | 
					                  :click="() => muteUsers(selected)"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  {{ $t('user_card.mute') }}
 | 
					                  {{ $t('user_card.mute') }}
 | 
				
			||||||
                  <template v-slot:progress>
 | 
					                  <template #progress>
 | 
				
			||||||
                    {{ $t('user_card.mute_progress') }}
 | 
					                    {{ $t('user_card.mute_progress') }}
 | 
				
			||||||
                  </template>
 | 
					                  </template>
 | 
				
			||||||
                </ProgressButton>
 | 
					                </ProgressButton>
 | 
				
			||||||
@ -92,16 +92,16 @@
 | 
				
			|||||||
                  :click="() => unmuteUsers(selected)"
 | 
					                  :click="() => unmuteUsers(selected)"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  {{ $t('user_card.unmute') }}
 | 
					                  {{ $t('user_card.unmute') }}
 | 
				
			||||||
                  <template v-slot:progress>
 | 
					                  <template #progress>
 | 
				
			||||||
                    {{ $t('user_card.unmute_progress') }}
 | 
					                    {{ $t('user_card.unmute_progress') }}
 | 
				
			||||||
                  </template>
 | 
					                  </template>
 | 
				
			||||||
                </ProgressButton>
 | 
					                </ProgressButton>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
            <template v-slot:item="{item}">
 | 
					            <template #item="{item}">
 | 
				
			||||||
              <MuteCard :user-id="item" />
 | 
					              <MuteCard :user-id="item" />
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
            <template v-slot:empty>
 | 
					            <template #empty>
 | 
				
			||||||
              {{ $t('settings.no_mutes') }}
 | 
					              {{ $t('settings.no_mutes') }}
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
          </MuteList>
 | 
					          </MuteList>
 | 
				
			||||||
@ -114,7 +114,7 @@
 | 
				
			|||||||
              :query="queryKnownDomains"
 | 
					              :query="queryKnownDomains"
 | 
				
			||||||
              :placeholder="$t('settings.type_domains_to_mute')"
 | 
					              :placeholder="$t('settings.type_domains_to_mute')"
 | 
				
			||||||
            >
 | 
					            >
 | 
				
			||||||
              <template v-slot="row">
 | 
					              <template #default="row">
 | 
				
			||||||
                <DomainMuteCard
 | 
					                <DomainMuteCard
 | 
				
			||||||
                  :domain="row.item"
 | 
					                  :domain="row.item"
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
@ -125,7 +125,7 @@
 | 
				
			|||||||
            :refresh="true"
 | 
					            :refresh="true"
 | 
				
			||||||
            :get-key="i => i"
 | 
					            :get-key="i => i"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
            <template v-slot:header="{selected}">
 | 
					            <template #header="{selected}">
 | 
				
			||||||
              <div class="bulk-actions">
 | 
					              <div class="bulk-actions">
 | 
				
			||||||
                <ProgressButton
 | 
					                <ProgressButton
 | 
				
			||||||
                  v-if="selected.length > 0"
 | 
					                  v-if="selected.length > 0"
 | 
				
			||||||
@ -133,16 +133,16 @@
 | 
				
			|||||||
                  :click="() => unmuteDomains(selected)"
 | 
					                  :click="() => unmuteDomains(selected)"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  {{ $t('domain_mute_card.unmute') }}
 | 
					                  {{ $t('domain_mute_card.unmute') }}
 | 
				
			||||||
                  <template v-slot:progress>
 | 
					                  <template #progress>
 | 
				
			||||||
                    {{ $t('domain_mute_card.unmute_progress') }}
 | 
					                    {{ $t('domain_mute_card.unmute_progress') }}
 | 
				
			||||||
                  </template>
 | 
					                  </template>
 | 
				
			||||||
                </ProgressButton>
 | 
					                </ProgressButton>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
            <template v-slot:item="{item}">
 | 
					            <template #item="{item}">
 | 
				
			||||||
              <DomainMuteCard :domain="item" />
 | 
					              <DomainMuteCard :domain="item" />
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
            <template v-slot:empty>
 | 
					            <template #empty>
 | 
				
			||||||
              {{ $t('settings.no_mutes') }}
 | 
					              {{ $t('settings.no_mutes') }}
 | 
				
			||||||
            </template>
 | 
					            </template>
 | 
				
			||||||
          </DomainMuteList>
 | 
					          </DomainMuteList>
 | 
				
			||||||
 | 
				
			|||||||
@ -130,7 +130,7 @@ const ProfileTab = {
 | 
				
			|||||||
        note: this.newBio,
 | 
					        note: this.newBio,
 | 
				
			||||||
        locked: this.newLocked,
 | 
					        locked: this.newLocked,
 | 
				
			||||||
        // Backend notation.
 | 
					        // Backend notation.
 | 
				
			||||||
        /* eslint-disable camelcase */
 | 
					         
 | 
				
			||||||
        display_name: this.newName,
 | 
					        display_name: this.newName,
 | 
				
			||||||
        fields_attributes: this.newFields.filter(el => el != null),
 | 
					        fields_attributes: this.newFields.filter(el => el != null),
 | 
				
			||||||
        bot: this.bot,
 | 
					        bot: this.bot,
 | 
				
			||||||
@ -138,7 +138,7 @@ const ProfileTab = {
 | 
				
			|||||||
        status_ttl_days: this.expirePosts ? this.newPostTTLDays : -1,
 | 
					        status_ttl_days: this.expirePosts ? this.newPostTTLDays : -1,
 | 
				
			||||||
        permit_followback: this.permit_followback,
 | 
					        permit_followback: this.permit_followback,
 | 
				
			||||||
        accepts_direct_messages_from: this.userAcceptsDirectMessagesFrom
 | 
					        accepts_direct_messages_from: this.userAcceptsDirectMessagesFrom
 | 
				
			||||||
        /* eslint-enable camelcase */
 | 
					         
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (this.emailLanguage) {
 | 
					      if (this.emailLanguage) {
 | 
				
			||||||
@ -187,7 +187,7 @@ const ProfileTab = {
 | 
				
			|||||||
        })
 | 
					        })
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      // eslint-disable-next-line no-undef
 | 
					       
 | 
				
			||||||
      const reader = new FileReader()
 | 
					      const reader = new FileReader()
 | 
				
			||||||
      reader.onload = ({ target }) => {
 | 
					      reader.onload = ({ target }) => {
 | 
				
			||||||
        const img = target.result
 | 
					        const img = target.result
 | 
				
			||||||
 | 
				
			|||||||
@ -110,11 +110,9 @@
 | 
				
			|||||||
          max="730"
 | 
					          max="730"
 | 
				
			||||||
          class="expire-posts-days"
 | 
					          class="expire-posts-days"
 | 
				
			||||||
          :placeholder="$t('settings.expire_posts_input_placeholder')"
 | 
					          :placeholder="$t('settings.expire_posts_input_placeholder')"
 | 
				
			||||||
        />
 | 
					        >
 | 
				
			||||||
      </p>
 | 
					 | 
				
			||||||
      <p>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      </p>
 | 
					      </p>
 | 
				
			||||||
 | 
					      <p />
 | 
				
			||||||
      <p>
 | 
					      <p>
 | 
				
			||||||
        <interface-language-switcher
 | 
					        <interface-language-switcher
 | 
				
			||||||
          :prompt-text="$t('settings.email_language')"
 | 
					          :prompt-text="$t('settings.email_language')"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,22 +1,25 @@
 | 
				
			|||||||
import { extractCommit } from 'src/services/version/version.service'
 | 
					import { extractCommit } from 'src/services/version/version.service'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const pleromaFeCommitUrl = 'https://akkoma.dev/AkkomaGang/pleroma-fe/commit/'
 | 
					function joinURL(base, subpath) {
 | 
				
			||||||
const pleromaBeCommitUrl = 'https://akkoma.dev/AkkomaGang/akkoma/commit/'
 | 
					  return URL.parse(subpath, base)?.href || "invalid base URL"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const VersionTab = {
 | 
					const VersionTab = {
 | 
				
			||||||
  data () {
 | 
					  data () {
 | 
				
			||||||
    const instance = this.$store.state.instance
 | 
					    const instance = this.$store.state.instance
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
 | 
					      backendCommitUrl: instance.backendCommitUrl,
 | 
				
			||||||
      backendVersion: instance.backendVersion,
 | 
					      backendVersion: instance.backendVersion,
 | 
				
			||||||
 | 
					      frontendCommitUrl: instance.frontendCommitUrl,
 | 
				
			||||||
      frontendVersion: instance.frontendVersion
 | 
					      frontendVersion: instance.frontendVersion
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
    frontendVersionLink () {
 | 
					    frontendVersionLink () {
 | 
				
			||||||
      return pleromaFeCommitUrl + this.frontendVersion
 | 
					      return joinURL(this.frontendCommitUrl, this.frontendVersion)
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    backendVersionLink () {
 | 
					    backendVersionLink () {
 | 
				
			||||||
      return pleromaBeCommitUrl + extractCommit(this.backendVersion)
 | 
					      return joinURL(this.backendCommitUrl, extractCommit(this.backendVersion))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -215,7 +215,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./shadow_control.js" ></script>
 | 
					<script src="./shadow_control.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -218,7 +218,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./side_drawer.js" ></script>
 | 
					<script src="./side_drawer.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
@import '../../_variables.scss';
 | 
					@import '../../_variables.scss';
 | 
				
			||||||
 | 
				
			|||||||
@ -24,7 +24,7 @@
 | 
				
			|||||||
  </div>
 | 
					  </div>
 | 
				
			||||||
</template>
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./staff_panel.js" ></script>
 | 
					<script src="./staff_panel.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<style lang="scss">
 | 
					<style lang="scss">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -266,6 +266,16 @@
 | 
				
			|||||||
      color: $fallback--cGreen;
 | 
					      color: $fallback--cGreen;
 | 
				
			||||||
      color: var(--cGreen, $fallback--cGreen);
 | 
					      color: var(--cGreen, $fallback--cGreen);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .right-side {
 | 
				
			||||||
 | 
					      display: flex;
 | 
				
			||||||
 | 
					      align-items: center;
 | 
				
			||||||
 | 
					      gap: 0.3em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    .repeat-tooltip {
 | 
				
			||||||
 | 
					      flex-shrink: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .repeater-avatar {
 | 
					  .repeater-avatar {
 | 
				
			||||||
 | 
				
			|||||||
@ -83,7 +83,7 @@
 | 
				
			|||||||
          :user="statusoid.user"
 | 
					          :user="statusoid.user"
 | 
				
			||||||
        />
 | 
					        />
 | 
				
			||||||
        <div class="right-side faint">
 | 
					        <div class="right-side faint">
 | 
				
			||||||
          <span
 | 
					          <div
 | 
				
			||||||
            class="status-username repeater-name"
 | 
					            class="status-username repeater-name"
 | 
				
			||||||
            :title="retweeter"
 | 
					            :title="retweeter"
 | 
				
			||||||
          >
 | 
					          >
 | 
				
			||||||
@ -100,8 +100,12 @@
 | 
				
			|||||||
              v-else
 | 
					              v-else
 | 
				
			||||||
              :to="retweeterProfileLink"
 | 
					              :to="retweeterProfileLink"
 | 
				
			||||||
            >{{ retweeter }}</router-link>
 | 
					            >{{ retweeter }}</router-link>
 | 
				
			||||||
          </span>
 | 
					          </div>
 | 
				
			||||||
          {{ ' ' }}
 | 
					          {{ ' ' }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          <div
 | 
				
			||||||
 | 
					            class="repeat-tooltip"
 | 
				
			||||||
 | 
					          >
 | 
				
			||||||
             <FAIcon
 | 
					             <FAIcon
 | 
				
			||||||
               icon="retweet"
 | 
					               icon="retweet"
 | 
				
			||||||
               class="repeat-icon"
 | 
					               class="repeat-icon"
 | 
				
			||||||
@ -110,6 +114,7 @@
 | 
				
			|||||||
             {{ $t('timeline.repeated') }}
 | 
					             {{ $t('timeline.repeated') }}
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 | 
					      </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      <div
 | 
					      <div
 | 
				
			||||||
        v-if="!deleted"
 | 
					        v-if="!deleted"
 | 
				
			||||||
@ -368,7 +373,7 @@
 | 
				
			|||||||
              :controlled-toggle-showing-long-subject="controlledToggleShowingLongSubject"
 | 
					              :controlled-toggle-showing-long-subject="controlledToggleShowingLongSubject"
 | 
				
			||||||
              @mediaplay="addMediaPlaying($event)"
 | 
					              @mediaplay="addMediaPlaying($event)"
 | 
				
			||||||
              @mediapause="removeMediaPlaying($event)"
 | 
					              @mediapause="removeMediaPlaying($event)"
 | 
				
			||||||
              @parseReady="setHeadTailLinks"
 | 
					              @parse-ready="setHeadTailLinks"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -476,8 +481,8 @@
 | 
				
			|||||||
            />
 | 
					            />
 | 
				
			||||||
            <extra-buttons
 | 
					            <extra-buttons
 | 
				
			||||||
              :status="status"
 | 
					              :status="status"
 | 
				
			||||||
              @onError="showError"
 | 
					              @on-error="showError"
 | 
				
			||||||
              @onSuccess="clearError"
 | 
					              @on-success="clearError"
 | 
				
			||||||
            />
 | 
					            />
 | 
				
			||||||
          </div>
 | 
					          </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
@ -514,6 +519,7 @@
 | 
				
			|||||||
          :reply-to="status.id"
 | 
					          :reply-to="status.id"
 | 
				
			||||||
          :attentions="status.attentions"
 | 
					          :attentions="status.attentions"
 | 
				
			||||||
          :replied-user="status.user"
 | 
					          :replied-user="status.user"
 | 
				
			||||||
 | 
					          :copy-message-language="status.language"
 | 
				
			||||||
          :copy-message-scope="status.visibility"
 | 
					          :copy-message-scope="status.visibility"
 | 
				
			||||||
          :subject="replySubject"
 | 
					          :subject="replySubject"
 | 
				
			||||||
          @posted="toggleReplying"
 | 
					          @posted="toggleReplying"
 | 
				
			||||||
@ -528,6 +534,7 @@
 | 
				
			|||||||
          :quote-id="status.id"
 | 
					          :quote-id="status.id"
 | 
				
			||||||
          :attentions="[status.user]"
 | 
					          :attentions="[status.user]"
 | 
				
			||||||
          :replied-user="status.user"
 | 
					          :replied-user="status.user"
 | 
				
			||||||
 | 
					          :copy-message-language="status.language"
 | 
				
			||||||
          :copy-message-scope="status.visibility"
 | 
					          :copy-message-scope="status.visibility"
 | 
				
			||||||
          :subject="replySubject"
 | 
					          :subject="replySubject"
 | 
				
			||||||
          @posted="toggleQuoting"
 | 
					          @posted="toggleQuoting"
 | 
				
			||||||
 | 
				
			|||||||
@ -41,7 +41,8 @@ const StatusContent = {
 | 
				
			|||||||
      postLength: this.status.text.length,
 | 
					      postLength: this.status.text.length,
 | 
				
			||||||
      parseReadyDone: false,
 | 
					      parseReadyDone: false,
 | 
				
			||||||
      renderMisskeyMarkdown,
 | 
					      renderMisskeyMarkdown,
 | 
				
			||||||
      translateFrom: null
 | 
					      translateFrom: null,
 | 
				
			||||||
 | 
					      translating: false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  computed: {
 | 
					  computed: {
 | 
				
			||||||
@ -135,7 +136,10 @@ const StatusContent = {
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    translateStatus () {
 | 
					    translateStatus () {
 | 
				
			||||||
      const translateTo = this.$store.getters.mergedConfig.translationLanguage || this.$store.state.instance.interfaceLanguage
 | 
					      const translateTo = this.$store.getters.mergedConfig.translationLanguage || this.$store.state.instance.interfaceLanguage
 | 
				
			||||||
      this.$store.dispatch('translateStatus', { id: this.status.id, language: translateTo, from: this.translateFrom })
 | 
					      this.translating = true
 | 
				
			||||||
 | 
					      this.$store.dispatch(
 | 
				
			||||||
 | 
					        'translateStatus', { id: this.status.id, language: translateTo, from: this.translateFrom }
 | 
				
			||||||
 | 
					      ).finally(() => { this.translating = false })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user