Compare commits

...

81 commits

Author SHA1 Message Date
4a50b1273d Merge pull request 'fix panel z-index conflicting with heading popover' (#422) from tea/akkoma-fe:fix/panel-z-index into develop
Reviewed-on: AkkomaGang/akkoma-fe#422
2024-10-26 03:42:48 +00:00
c76dc6d79e Merge pull request 'Fix redirect on logout' (#420) from Oneric/akkoma-fe:logout-redirect into develop
Reviewed-on: AkkomaGang/akkoma-fe#420
2024-10-26 03:42:23 +00:00
cb4c581cde Merge pull request 'Add proper autocomplete prop for TOTP login field' (#424) from tudbut/akkoma-fe:develop into develop
Reviewed-on: AkkomaGang/akkoma-fe#424
2024-10-26 03:41:15 +00:00
TudbuT
8231c8f0b6
add proper autocomplete prop for TOTP login field 2024-10-19 19:19:15 +02:00
tea
35cf3327c8 fix panel z-index conflicting with heading popover
resolves #342
2024-10-05 10:59:46 +02:00
1ae09458c6 Fix redirect on logout
An instance may restrict access to the public timeline (among others)
to authenticated users and there already is a setting to decide which page
to show authenticated and unauthenticated viewers by default each.
However, the logout redirect didn't honour this setting
leading to potentially broken pages and errors on logout
2024-09-28 17:47:28 +02:00
f391cf70a4 Merge pull request 'README: Add line to install Node.js' (#409) from ilja/akkoma-fe:README_add_to_install_node into develop
Reviewed-on: AkkomaGang/akkoma-fe#409
2024-08-25 09:09:35 +00:00
fa8fde2ab1 Merge pull request 'Upgrade vue packages' (#411) from Oneric/akkoma-fe:vue-mathml into develop
Reviewed-on: AkkomaGang/akkoma-fe#411
2024-08-25 09:08:04 +00:00
1f2c96a485 Merge pull request 'Fix setting restore from file' (#406) from Oneric/akkoma-fe:fix-file-restore into develop
Reviewed-on: AkkomaGang/akkoma-fe#406
2024-08-25 09:07:18 +00:00
6c178aa257 Upgrade vue packages
Bumping past vue 3.4.0 guarantees MathML support for FEP-dc88.

Related to: AkkomaGang/akkoma#642
2024-08-17 18:01:59 +02:00
ilja
3349fe6ff2 Add line to install Node.js
For someone who isn't used to building fe things like this, it's
not always clear to install Node.js or what version.

A line has been added to the installation instructions pointing to
resources where to get it and what version to use. For version I
point to the woodpecker config because that is what the CI uses and
therefor always "tested".

There was a file .node-version who contained a node version, but
this was seriously outdated and removing it didn't seem to break
anything. Assuming it indeed doesn't do anything any more, it seems
better to remove to avoid confusion.
2024-08-03 09:54:14 +02:00
e274adf47d Fix setting restore from file
Previously restoring from file would also restore the old version value
breaking upload of the new settings to the server.

Additionallly it didn’t even attempt to sync settings after restore and
was insufferably slow due to individually updating every single setting
with a dispatch. Instead only update changed settings like on server
syncs which usually speeds the process up considerably.

Fixes: AkkomaGang/akkoma-fe#405
2024-07-06 01:59:42 +02:00
8765491399 Do not try to destructure when we don't need to 2024-06-27 02:58:52 +01:00
4211e05a75 Merge pull request 'status component: Fix repeater name overflowing' (#383) from yukijoou/akkoma-fe:fix-status-usernames into develop
Reviewed-on: AkkomaGang/akkoma-fe#383
2024-06-25 21:34:15 +00:00
a3251a1ba6 Merge remote-tracking branch 'origin/translations' into develop 2024-06-23 03:03:40 +01:00
e5608f4009 remove ora as a dep 2024-06-23 03:03:11 +01:00
1092d43802 remove nonsense dep 2024-06-23 03:02:45 +01:00
Weblate
98a3622172 Merge branch 'origin/develop' into Weblate. 2024-06-17 21:40:59 +00:00
24b9e350e2 Merge pull request 'added minimum space to empty timeline' (#400) from Riedler/akkoma-fe:empty-tl-minspace into develop
Reviewed-on: AkkomaGang/akkoma-fe#400
2024-06-17 21:40:56 +00:00
Weblate
7ab4d22a4c Merge branch 'origin/develop' into Weblate. 2024-06-17 21:40:29 +00:00
8489f6d5ae Merge pull request 'visually fuse CW line and post body textarea' (#401) from Riedler/akkoma-fe:fuse-cw-to-post-body into develop
Reviewed-on: AkkomaGang/akkoma-fe#401
2024-06-17 21:40:26 +00:00
b2cab6d088 only flatten top of post body textarea if subject line is visible 2024-06-16 16:26:44 +02:00
3ebaba6fa7 smushed subject line and post body together, kinda 2024-06-16 16:14:16 +02:00
f1058567b9 also set min height for other lists (e.g. follow requests), not just the timeline 2024-06-16 16:12:15 +02:00
49a850a1e9 added minimum space to empty timeline 2024-06-16 15:49:52 +02:00
Weblate
b2de68239f Merge branch 'origin/develop' into Weblate. 2024-06-15 12:41:26 +00:00
c68595345f Merge pull request 'ANNOYING dependency update' (#397) from dep-update into develop
Reviewed-on: AkkomaGang/akkoma-fe#397
2024-06-15 12:41:23 +00:00
a5d4b0a68c Merge branch 'develop' into dep-update 2024-06-15 13:38:40 +01:00
bd263587b2 Merge branch 'develop' into dep-update 2024-06-15 13:36:24 +01:00
Weblate
c19fb198ca Merge branch 'origin/develop' into Weblate. 2024-06-15 12:33:42 +00:00
97966045cb Merge pull request 'make status form selectors justified properly' (#398) from rat/akkoma-fe:status-form-selector into develop
Reviewed-on: AkkomaGang/akkoma-fe#398
2024-06-15 12:33:38 +00:00
rat
aad023c8a0 make status form selectors justified properly 2024-06-10 17:20:51 -07:00
c952b2335c correct eslint plugin 2024-05-29 04:04:56 +01:00
0baf31f498 correct package.json lint task 2024-05-29 04:01:29 +01:00
8fa24d0c40 migrate to eslint 9 syntax 2024-05-29 03:59:37 +01:00
5848c18ec8 remove unused CI file 2024-05-29 03:43:41 +01:00
Weblate
54dbead22c Merge branch 'origin/develop' into Weblate. 2024-05-28 21:33:19 +00:00
3e86db24d3 Update .woodpecker.yml 2024-05-28 21:33:15 +00:00
Weblate
d8f3f5002f Merge branch 'origin/develop' into Weblate. 2024-05-28 21:31:51 +00:00
7789c5def6 Update .woodpecker.yml 2024-05-28 21:31:46 +00:00
a45f482c79 remove a useless log 2024-05-28 04:18:32 +01:00
Weblate
ed22c480f9 Merge branch 'origin/develop' into Weblate. 2024-05-28 03:17:19 +00:00
f3934afbd8 make sure we normalise interfaceLanguage 2024-05-28 04:17:04 +01:00
Weblate
3797495e53 Merge branch 'origin/develop' into Weblate. 2024-05-28 03:15:47 +00:00
0b437ab6fd remove line left over in conflict 2024-05-28 04:15:35 +01:00
a7dea2f70f ANNOYING dependency update 2024-05-28 04:02:17 +01:00
Weblate
2c9da4a58c Merge branch 'origin/develop' into Weblate. 2024-05-28 02:25:05 +00:00
8964dce609 Merge pull request 'Make animated emojis in reactions pause' (#378) from sarayalth/akkoma-fe:pause-animated-reaction into develop
Reviewed-on: AkkomaGang/akkoma-fe#378
2024-05-28 02:25:02 +00:00
Weblate
156b036caa Merge branch 'origin/develop' into Weblate. 2024-05-28 02:24:09 +00:00
1a49a1b3ac Merge pull request 'Expand Unicode emoji map' (#385) from Oneric/akkoma-fe:emoji_update into develop
Reviewed-on: AkkomaGang/akkoma-fe#385
2024-05-28 02:24:06 +00:00
Weblate
61d82a2a07 Merge branch 'origin/develop' into Weblate. 2024-05-28 02:22:11 +00:00
1adef56603 Merge remote-tracking branch 'partizan/386-default-post-lang' into develop 2024-05-28 03:22:03 +01:00
Weblate
b9bf0f0002 Merge branch 'origin/develop' into Weblate. 2024-05-28 02:14:58 +00:00
5aaa605df0 add asdf tool file 2024-05-28 03:14:50 +01:00
Weblate
7136ea80b9 Merge branch 'origin/develop' into Weblate. 2024-05-28 02:14:48 +00:00
71e287d56c update CI to v2 2024-05-28 03:14:37 +01:00
Weblate
a64cdda725 Merge branch 'origin/develop' into Weblate. 2024-05-28 02:10:18 +00:00
70275684bf Merge pull request 'Fix posting for "special" interface languages' (#377) from Oneric/akkoma-fe:post-language-specialcodes into develop
Reviewed-on: AkkomaGang/akkoma-fe#377
2024-05-28 02:10:15 +00:00
Weblate
7e7f03aece Merge branch 'origin/develop' into Weblate. 2024-05-28 02:07:18 +00:00
29ff2ef455 Merge pull request 'Fix ordering of favourites timeline' (#392) from Oneric/akkoma-fe:favourite-ordering into develop
Reviewed-on: AkkomaGang/akkoma-fe#392
2024-05-28 02:07:15 +00:00
8c49474dea status component: Fix repeater name overflowing
If someone repeating a post had a long username, their username would
overflow beyond the bounds of the post.

This fixes this isse by turning the bar displaying the username and
repeat icon into a flexbox.
2024-05-18 01:25:15 +02:00
62e0dd858c Fix ordering of favourites timeline
The backend returns them order by when the post was favourited;
reordering them by post date jumbles everything up each addition
and serves no purpose.

Fixes: AkkomaGang/akkoma-fe#391
2024-05-15 18:47:47 +02:00
cc709394c5 remove unused classes on notifications 2024-05-14 18:09:21 +02:00
57beea6a0d fix: Use label and key for options 2024-05-13 16:13:58 +03:00
Weblate
45524552a0 Translated using Weblate (Vietnamese)
Currently translated at 91.9% (964 of 1048 strings)

Translated using Weblate (Vietnamese)

Currently translated at 92.2% (965 of 1046 strings)

Translated using Weblate (Vietnamese)

Currently translated at 92.2% (965 of 1046 strings)

Translated using Weblate (Vietnamese)

Currently translated at 84.3% (882 of 1046 strings)

Translated using Weblate (Vietnamese)

Currently translated at 84.3% (882 of 1046 strings)

Translated using Weblate (Vietnamese)

Currently translated at 79.8% (835 of 1046 strings)

Translated using Weblate (Vietnamese)

Currently translated at 79.8% (835 of 1046 strings)

Co-authored-by: Nguyễn Gia Phong <cnx@loang.net>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: xarvos <huyngo@disroot.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/vi/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
ee66b69ab5 Translated using Weblate (Japanese)
Currently translated at 0.2% (3 of 1046 strings)

Added translation using Weblate (Japanese)

Co-authored-by: Nakaya <s_fpfb_sub-second@yahoo.co.jp>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/ja/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
d42e374704 Translated using Weblate (Greek)
Currently translated at 15.9% (167 of 1046 strings)

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: getimiskon <getimiskon@disroot.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/el/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
ce8a9d2b4a Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1048 of 1048 strings)

Merge branch 'origin/develop' into Weblate.

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (1046 of 1046 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/zh_Hans/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
d2b7ac6d8c Translated using Weblate (Polish)
Currently translated at 99.7% (1045 of 1048 strings)

Translated using Weblate (Polish)

Currently translated at 99.7% (1045 of 1048 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (1046 of 1046 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (1046 of 1046 strings)

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: subtype <subtype@hollow.capital>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/pl/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
754c72cb24 Translated using Weblate (Portuguese)
Currently translated at 100.0% (1048 of 1048 strings)

Co-authored-by: Jammer Lammer <akHarINlMYExpSmVPDRT@proton.me>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/pt/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
f5bd195422 Translated using Weblate (Russian)
Currently translated at 68.7% (719 of 1046 strings)

Co-authored-by: Mel <hi@mel.gg>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/ru/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
d49fd46554 Translated using Weblate (Japanese (ja_EASY))
Currently translated at 72.3% (757 of 1046 strings)

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: kazari <6c577a54-aac9-482a-955e-745c858445e3@simplelogin.com>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/ja_EASY/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
9982373853 Translated using Weblate (Italian)
Currently translated at 80.4% (841 of 1045 strings)

Translated using Weblate (Italian)

Currently translated at 65.3% (683 of 1045 strings)

Co-authored-by: Cuche <cuche@mailbox.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/it/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
5206b5cf9c Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (1048 of 1048 strings)

Translated using Weblate (Chinese (Traditional))

Currently translated at 99.2% (1040 of 1048 strings)

Co-authored-by: Toot <toothpicker@users.noreply.translate.akkoma.dev>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/zh_Hant/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
a65a06ca04 Translated using Weblate (Catalan)
Currently translated at 100.0% (1048 of 1048 strings)

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: fadelkon <fadelkon@posteo.net>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/ca/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
c10b38afbc Translated using Weblate (Indonesian)
Currently translated at 71.9% (753 of 1046 strings)

Co-authored-by: Aldiantoro Nugroho <kriwil@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/id/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
Weblate
009941ea2c Translated using Weblate (Spanish)
Currently translated at 93.7% (983 of 1048 strings)

Translated using Weblate (Spanish)

Currently translated at 93.9% (983 of 1046 strings)

Translated using Weblate (Spanish)

Currently translated at 92.5% (967 of 1045 strings)

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: taretka <info@tarteka.net>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/es/
Translation: Pleroma fe/pleroma-fe
2024-04-29 14:09:37 +00:00
042e8c78dc feat: Add "Default post language" option
Refs #386
2024-04-20 16:07:03 +03:00
0e07d88afa Expand Unicode emoji map
This pulls in 267 new emoji:
  - all 258 non-deprecated country or macro region
    flags (composed by two regional indicators)
  - all 3 regional flags currently recommended for general use
    (Wales, Scotland, England)
  - a few random ones i picked out
    - goose
    - heart on fire
    - heart mending
    - transgender flag
    - rainbow flag
    - pirate flag

The new names are derived from official Unicode names
with minor modifications to fit into the usual shortcode scheme
and dropping the flag_ prefix from country indicators.
Due to a naming conflict the old "japan" emoji
U+1F5FE SILHOUETTE OF JAPAN was renamed to "japan_silhouette".
2024-04-04 21:52:33 +02:00
1f5f8665c8 make animated reactions pause unless hovered on notifications 2024-03-01 20:02:19 +01:00
428ed70b0d Fix posting for special interface languages
Easy Japanses (ja_easy) and traditional Chinses (zh_Hant) use
(custom) non-ISO codes in the interface. Because MastoAPI only accepts
ISO 639 codes, the backend will return an error rendering users
unable to do anything unless the post’s language was explicitly set.
2024-02-26 08:05:55 +01:00
127 changed files with 8075 additions and 5808 deletions

View file

@ -1,2 +0,0 @@
build/*.js
config/*.js

View file

@ -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
}
}

View file

@ -1 +0,0 @@
7.2.1

1
.tool-versions Normal file
View file

@ -0,0 +1 @@
nodejs 20.12.2

View file

@ -1,24 +1,25 @@
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
- yarn - yarn
- yarn unit - yarn unit
build: build:
@ -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,15 @@ pipeline:
branch: branch:
- develop - develop
- stable - stable
image: node:18 image: node:20
secrets: secrets:
- SCW_ACCESS_KEY - SCW_ACCESS_KEY
- SCW_SECRET_KEY - SCW_SECRET_KEY
- SCW_DEFAULT_ORGANIZATION_ID - 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
@ -70,8 +71,8 @@ pipeline:
- SCW_DEFAULT_ORGANIZATION_ID - 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
@ -79,4 +80,4 @@ pipeline:
- mkdocs build - mkdocs build
- zip -r docs.zip site/* - zip -r docs.zip site/*
- cd site - cd site
- rclone copy . scaleway:akkoma-docs/frontend/$CI_COMMIT_BRANCH/ - rclone copy . scaleway:akkoma-docs/frontend/$CI_COMMIT_BRANCH/

View file

@ -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

View file

@ -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",
}) );
});

View file

@ -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

View file

@ -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'
})
] ]
} }

View file

@ -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"'
}) })

31
eslint.config.js Normal file
View 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'
]
}
]

View file

@ -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",

View file

@ -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>

View file

@ -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"
/> />

View file

@ -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>

View file

@ -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';

View file

@ -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>

View file

@ -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 {

View file

@ -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>

View file

@ -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({

View file

@ -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>

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -43,7 +43,10 @@
: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
v-if="!suggestion.mfm"
class="image"
>
<img <img
v-if="suggestion.img" v-if="suggestion.img"
:src="suggestion.img" :src="suggestion.img"

View file

@ -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

View file

@ -42,7 +42,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';

View file

@ -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';

View file

@ -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';

View file

@ -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 {

View file

@ -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"

View file

@ -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';

View file

@ -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>

View file

@ -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" />

View file

@ -10,4 +10,4 @@
</div> </div>
</template> </template>
<script src="./instance_specific_panel.js" ></script> <script src="./instance_specific_panel.js"></script>

View file

@ -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;

View file

@ -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"

View file

@ -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';

View file

@ -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'"

View file

@ -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()
}) })

View file

@ -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';

View file

@ -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" />

View file

@ -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" />

View file

@ -69,4 +69,4 @@
</div> </div>
</div> </div>
</template> </template>
<script src="./recovery_form.js" ></script> <script src="./recovery_form.js"></script>

View file

@ -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>

View file

@ -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"
@ -24,7 +24,7 @@
class="button-default" class="button-default"
@click.stop="updateReportState('open')" @click.stop="updateReportState('open')"
> >
{{ $t('moderation.reports.reopen') }} {{ $t('moderation.reports.reopen') }}
</button> </button>
</div> </div>
<div <div
@ -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"

View file

@ -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

View file

@ -22,6 +22,9 @@ export default {
default: false default: false
} }
}, },
emits: [
'backdropClicked',
],
computed: { computed: {
classes () { classes () {
return { return {

View file

@ -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)"

View file

@ -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';

View file

@ -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 () {

View file

@ -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"

View file

@ -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>

View file

@ -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"

View file

@ -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>

View file

@ -9,11 +9,12 @@ 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 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 +63,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',
@ -129,6 +137,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 +153,8 @@ 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, postLanguage: defaultPostLanguage, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage, alwaysShowSubjectInput } = this.$store.getters.mergedConfig
const postLanguage = defaultPostLanguage || interfaceToISOLanguage(interfaceLanguage)
let statusParams = { let statusParams = {
spoilerText: this.subject || '', spoilerText: this.subject || '',
@ -149,7 +165,7 @@ const PostStatusForm = {
poll: {}, poll: {},
mediaDescriptions: {}, mediaDescriptions: {},
visibility: this.suggestedVisibility(), visibility: this.suggestedVisibility(),
language: interfaceLanguage, language: postLanguage,
contentType contentType
} }
@ -164,7 +180,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 || postLanguage,
contentType: statusContentType contentType: statusContentType
} }
} }
@ -309,9 +325,6 @@ const PostStatusForm = {
...mapState({ ...mapState({
mobileLayout: state => state.interface.mobileLayout mobileLayout: state => state.interface.mobileLayout
}), }),
isoLanguages () {
return iso6391.getAllCodes();
}
}, },
watch: { watch: {
'newStatus': { 'newStatus': {

View file

@ -118,8 +118,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
@ -170,7 +170,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,6 +190,7 @@
<div <div
v-if="!disableScopeSelector" v-if="!disableScopeSelector"
class="visibility-tray" class="visibility-tray"
:class="{ 'visibility-tray-edit': isEdit }"
> >
<scope-selector <scope-selector
v-if="!disableVisibilitySelector" v-if="!disableVisibilitySelector"
@ -200,47 +201,50 @@
/> />
<div <div
class="language-selector" class="format-selector-container">
> <div
<Select class="format-selector"
id="post-language"
v-model="newStatus.language"
class="form-control"
>
<option
v-for="language in isoLanguages"
:key="language"
:value="language"
> >
{{ language }} <Select
</option> id="post-language"
</Select> v-model="newStatus.language"
</div> class="form-control"
<div
v-if="postFormats.length > 1"
class="text-format"
>
<Select
id="post-content-type"
v-model="newStatus.contentType"
class="form-control"
>
<option
v-for="postFormat in postFormats"
:key="postFormat"
:value="postFormat"
> >
{{ $t(`post_status.content_type["${postFormat}"]`) }} <option
</option> v-for="language in postLanguageOptions"
</Select> :key="language.key"
</div> :value="language.value"
<div >
v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'" {{ language.label }}
class="text-format" </option>
> </Select>
<span class="only-format"> </div>
{{ $t(`post_status.content_type["${postFormats[0]}"]`) }} <div
</span> v-if="postFormats.length > 1"
class="text-format format-selector"
>
<Select
id="post-content-type"
v-model="newStatus.contentType"
class="form-control"
>
<option
v-for="postFormat in postFormats"
:key="postFormat"
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }}
</option>
</Select>
</div>
<div
v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
class="text-format format-selector"
>
<span class="only-format">
{{ $t(`post_status.content_type["${postFormats[0]}"]`) }}
</span>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -460,6 +464,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 +478,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 +584,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 +601,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;
} }

View file

@ -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">

View file

@ -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';

View file

@ -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`
} }

View file

@ -54,7 +54,7 @@
</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';

View file

@ -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>

View file

@ -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"

View file

@ -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"

View file

@ -6,14 +6,14 @@
<Popover <Popover
trigger="hover" trigger="hover"
> >
<template v-slot:trigger> <template #trigger>
&nbsp; &nbsp;
<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>

View file

@ -6,14 +6,14 @@
<Popover <Popover
trigger="hover" trigger="hover"
> >
<template v-slot:trigger> <template #trigger>
&nbsp; &nbsp;
<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>

View file

@ -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')
}, },

View file

@ -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>

View file

@ -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

View file

@ -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: {

View file

@ -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"
@ -585,6 +593,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"

View file

@ -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

View file

@ -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>

View file

@ -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

View file

@ -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')"

View file

@ -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';

View file

@ -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';

View file

@ -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">

View file

@ -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 {

View file

@ -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,14 +100,19 @@
v-else v-else
:to="retweeterProfileLink" :to="retweeterProfileLink"
>{{ retweeter }}</router-link> >{{ retweeter }}</router-link>
</span> </div>
{{ ' ' }} {{ ' ' }}
<FAIcon
icon="retweet" <div
class="repeat-icon" class="repeat-tooltip"
:title="$t('tool_tip.repeat')" >
/> <FAIcon
{{ $t('timeline.repeated') }} icon="retweet"
class="repeat-icon"
:title="$t('tool_tip.repeat')"
/>
{{ $t('timeline.repeated') }}
</div>
</div> </div>
</div> </div>
@ -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>

View file

@ -54,7 +54,7 @@
:mfm="renderMisskeyMarkdown && (status.media_type === 'text/x.misskeymarkdown')" :mfm="renderMisskeyMarkdown && (status.media_type === 'text/x.misskeymarkdown')"
:greentext="mergedConfig.greentext" :greentext="mergedConfig.greentext"
:attentions="status.attentions" :attentions="status.attentions"
@parseReady="onParseReady" @parse-ready="onParseReady"
/> />
<div <div
v-if="status.translation" v-if="status.translation"
@ -70,7 +70,7 @@
:mfm="renderMisskeyMarkdown && (status.media_type === 'text/x.misskeymarkdown')" :mfm="renderMisskeyMarkdown && (status.media_type === 'text/x.misskeymarkdown')"
:greentext="mergedConfig.greentext" :greentext="mergedConfig.greentext"
:attentions="status.attentions" :attentions="status.attentions"
@parseReady="onParseReady" @parse-ready="onParseReady"
/> />
<div> <div>
<label class="label">{{ $t('status.override_translation_source_language') }}</label> <label class="label">{{ $t('status.override_translation_source_language') }}</label>
@ -89,7 +89,10 @@
</option> </option>
</Select> </Select>
{{ ' ' }} {{ ' ' }}
<button @click="translateStatus" class="btn button-default"> <button
class="btn button-default"
@click="translateStatus"
>
{{ $t('status.translate') }} {{ $t('status.translate') }}
</button> </button>
</div> </div>
@ -138,5 +141,5 @@
<slot v-if="!hideSubjectStatus" /> <slot v-if="!hideSubjectStatus" />
</div> </div>
</template> </template>
<script src="./status_body.js" ></script> <script src="./status_body.js"></script>
<style lang="scss" src="./status_body.scss" /> <style lang="scss" src="./status_body.scss" />

View file

@ -14,7 +14,7 @@
:toggle-showing-tall="toggleShowingTall" :toggle-showing-tall="toggleShowingTall"
:toggle-expanding-subject="toggleExpandingSubject" :toggle-expanding-subject="toggleExpandingSubject"
:toggle-showing-long-subject="toggleShowingLongSubject" :toggle-showing-long-subject="toggleShowingLongSubject"
@parseReady="$emit('parseReady', $event)" @parse-ready="$emit('parseReady', $event)"
> >
<div v-if="status.poll && status.poll.options && !compact"> <div v-if="status.poll && status.poll.options && !compact">
<Poll <Poll
@ -63,7 +63,7 @@
</div> </div>
</template> </template>
<script src="./status_content.js" ></script> <script src="./status_content.js"></script>
<style lang="scss"> <style lang="scss">
.StatusContent { .StatusContent {
flex: 1; flex: 1;

View file

@ -2,7 +2,7 @@
<Modal <Modal
v-if="modalActivated" v-if="modalActivated"
class="status-history-modal-view" class="status-history-modal-view"
@backdropClicked="closeModal" @backdrop-clicked="closeModal"
> >
<div class="status-history-modal-panel panel"> <div class="status-history-modal-panel panel">
<div class="panel-heading"> <div class="panel-heading">
@ -17,9 +17,9 @@
v-for="status in history" v-for="status in history"
:key="status.id" :key="status.id"
:statusoid="status" :statusoid="status"
:isPreview="true" :is-preview="true"
class="conversation-status status-fadein panel-body" class="conversation-status status-fadein panel-body"
/> />
</div> </div>
</div> </div>
</div> </div>

View file

@ -5,10 +5,10 @@
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
@show="enter" @show="enter"
> >
<template v-slot:trigger> <template #trigger>
<slot /> <slot />
</template> </template>
<template v-slot:content> <template #content>
<Status <Status
v-if="status" v-if="status"
:is-preview="true" :is-preview="true"
@ -35,7 +35,7 @@
</Popover> </Popover>
</template> </template>
<script src="./status_popover.js" ></script> <script src="./status_popover.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';

View file

@ -7,8 +7,9 @@
> >
<div <div
v-if="animated && imageTypeLabel" v-if="animated && imageTypeLabel"
class="image-type-label"> class="image-type-label"
{{ imageTypeLabel }} >
{{ imageTypeLabel }}
</div> </div>
<canvas <canvas
v-if="animated" v-if="animated"

View file

@ -13,7 +13,7 @@
</div> </div>
</template> </template>
<script src="./terms_of_service_panel.js" ></script> <script src="./terms_of_service_panel.js"></script>
<style lang="scss"> <style lang="scss">
.tos-content { .tos-content {

View file

@ -32,7 +32,7 @@
:dive="dive ? () => dive(status.id) : undefined" :dive="dive ? () => dive(status.id) : undefined"
@goto="setHighlight" @goto="setHighlight"
@toggleExpanded="toggleExpanded" @toggle-expanded="toggleExpanded"
/> />
<div <div
v-if="currentReplies.length && threadShowing" v-if="currentReplies.length && threadShowing"

View file

@ -28,4 +28,7 @@
} }
} }
} }
.timeline {
min-height: 1em;
}
} }

View file

@ -4,7 +4,7 @@
class="TimelineQuickSettings" class="TimelineQuickSettings"
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
> >
<template v-slot:content> <template #content>
<div class="dropdown-menu"> <div class="dropdown-menu">
<div v-if="loggedIn"> <div v-if="loggedIn">
<button <button
@ -80,7 +80,7 @@
</button> </button>
</div> </div>
</template> </template>
<template v-slot:trigger> <template #trigger>
<button class="button-unstyled"> <button class="button-unstyled">
<FAIcon icon="filter" /> <FAIcon icon="filter" />
</button> </button>

View file

@ -9,12 +9,12 @@
@show="openMenu" @show="openMenu"
@close="() => isOpen = false" @close="() => isOpen = false"
> >
<template v-slot:content> <template #content>
<div class="timeline-menu-popover popover-default"> <div class="timeline-menu-popover popover-default">
<TimelineMenuContent /> <TimelineMenuContent />
</div> </div>
</template> </template>
<template v-slot:trigger> <template #trigger>
<button class="button-unstyled title timeline-menu-title"> <button class="button-unstyled title timeline-menu-title">
<span class="timeline-title">{{ timelineName() }}</span> <span class="timeline-title">{{ timelineName() }}</span>
<span> <span>
@ -32,7 +32,7 @@
</Popover> </Popover>
</template> </template>
<script src="./timeline_menu.js" ></script> <script src="./timeline_menu.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';

View file

@ -62,7 +62,6 @@
:title="$t('nav.twkn_timeline_description')" :title="$t('nav.twkn_timeline_description')"
:aria-label="$t('nav.twkn_timeline_description')" :aria-label="$t('nav.twkn_timeline_description')"
>{{ $t("nav.twkn") }}</span> >{{ $t("nav.twkn") }}</span>
</router-link> </router-link>
</li> </li>
<li v-if="currentUser"> <li v-if="currentUser">
@ -100,7 +99,7 @@
</ul> </ul>
</template> </template>
<script src="./timeline_menu_content.js" ></script> <script src="./timeline_menu_content.js"></script>
<style lang="scss"> <style lang="scss">
@import "../../_variables.scss"; @import "../../_variables.scss";

View file

@ -99,7 +99,7 @@
</ul> </ul>
</template> </template>
<script src="./timeline_menu_content.js" ></script> <script src="./timeline_menu_content.js"></script>
<style lang="scss"> <style lang="scss">
@import "../../_variables.scss"; @import "../../_variables.scss";

View file

@ -16,9 +16,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
@ -40,9 +40,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
@ -55,7 +55,7 @@
</div> </div>
</template> </template>
<script src="./timeline_menu_tabs.js" ></script> <script src="./timeline_menu_tabs.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';

View file

@ -66,7 +66,7 @@ export default {
return this.user.id !== this.$store.state.users.currentUser.id return this.user.id !== this.$store.state.users.currentUser.id
}, },
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`
}, },

View file

@ -4,10 +4,10 @@
placement="top" placement="top"
:offset="{ y: 5 }" :offset="{ y: 5 }"
> >
<template v-slot:trigger> <template #trigger>
<slot /> <slot />
</template> </template>
<template v-slot:content> <template #content>
<div class="user-list-popover"> <div class="user-list-popover">
<template v-if="users.length"> <template v-if="users.length">
<div <div
@ -45,7 +45,7 @@
</Popover> </Popover>
</template> </template>
<script src="./user_list_popover.js" ></script> <script src="./user_list_popover.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';

View file

@ -121,8 +121,8 @@
</FriendList> </FriendList>
</div> </div>
<div <div
key="tags"
v-if="isUs" v-if="isUs"
key="tags"
:label="$t('user_card.followed_tags')" :label="$t('user_card.followed_tags')"
> >
<FollowedTagList <FollowedTagList
@ -133,7 +133,7 @@
<FollowedTagCard :tag="item" /> <FollowedTagCard :tag="item" />
</template> </template>
<template #empty> <template #empty>
{{ $t('user_card.not_following_any_hashtags')}} {{ $t('user_card.not_following_any_hashtags') }}
</template> </template>
</FollowedTagList> </FollowedTagList>
</div> </div>

View file

@ -1,7 +1,7 @@
<template> <template>
<Modal <Modal
v-if="isOpen" v-if="isOpen"
@backdropClicked="closeModal" @backdrop-clicked="closeModal"
> >
<div class="user-reporting-panel panel"> <div class="user-reporting-panel panel">
<div class="panel-heading"> <div class="panel-heading">
@ -45,7 +45,7 @@
</div> </div>
<div class="user-reporting-panel-right"> <div class="user-reporting-panel-right">
<List :items="statuses"> <List :items="statuses">
<template v-slot:item="{item}"> <template #item="{item}">
<div class="status-fadein user-reporting-panel-sitem"> <div class="status-fadein user-reporting-panel-sitem">
<Status <Status
:in-conversation="false" :in-conversation="false"

View file

@ -27,7 +27,7 @@
</div> </div>
</template> </template>
<script src="./who_to_follow_panel.js" ></script> <script src="./who_to_follow_panel.js"></script>
<style lang="scss"> <style lang="scss">
.who-to-follow * { .who-to-follow * {

View file

@ -84,6 +84,7 @@
"keep_open": "Mantindre el selector obert", "keep_open": "Mantindre el selector obert",
"load_all": "Carregant tots els {emojiAmount} emoji", "load_all": "Carregant tots els {emojiAmount} emoji",
"load_all_hint": "Carregat el primer {saneAmount} emoji, carregar tots els emoji pot causar problemes de rendiment.", "load_all_hint": "Carregat el primer {saneAmount} emoji, carregar tots els emoji pot causar problemes de rendiment.",
"recent": "Recents",
"search_emoji": "Buscar un emoji", "search_emoji": "Buscar un emoji",
"stickers": "Adhesius", "stickers": "Adhesius",
"unicode": "Emojis unicode" "unicode": "Emojis unicode"
@ -254,6 +255,10 @@
"hint": "Entra per a participar en la conversa", "hint": "Entra per a participar en la conversa",
"login": "Inicia sessió", "login": "Inicia sessió",
"logout": "Tanca la sessió", "logout": "Tanca la sessió",
"logout_confirm": "Segur que vols tancar la sessió?",
"logout_confirm_accept_button": "Surt",
"logout_confirm_cancel_button": "Canceŀla",
"logout_confirm_title": "Tanca la sessió",
"password": "Contrasenya", "password": "Contrasenya",
"placeholder": "el meu nom d'usuari", "placeholder": "el meu nom d'usuari",
"recovery_code": "Codi de recuperació", "recovery_code": "Codi de recuperació",
@ -266,6 +271,32 @@
"next": "Següent", "next": "Següent",
"previous": "Anterior" "previous": "Anterior"
}, },
"moderation": {
"moderation": "Moderació",
"reports": {
"add_note": "Afegeix una nota",
"close": "Tanca",
"delete_note": "Esborra la nota",
"delete_note_accept": "Sí, esborra-la",
"delete_note_cancel": "No, conserva-la",
"delete_note_confirm": "Segur que vols esborrar aquesta nota?",
"delete_note_title": "Cal confirmació",
"no_content": "Sense descripció",
"no_reports": "No hi ha informes per mostrar",
"note_placeholder": "Deixa una nota",
"notes": "{ count } nota | { count } notes",
"reopen": "Reobre",
"report": "Denuncia-ho",
"reports": "Denúncies",
"resolve": "Resol",
"show_closed": "Mostra les tancades",
"statuses": "{ count } post| { count } posts",
"tag_policy_notice": "Activa la restricció de publicacions segons la TagPolicy MRF",
"tags": "Estableix restriccions a les publicacions"
},
"statuses": "Publicacions",
"users": "Usuàries"
},
"nav": { "nav": {
"about": "Quant a", "about": "Quant a",
"administration": "Administració", "administration": "Administració",
@ -282,6 +313,7 @@
"interactions": "Interaccions", "interactions": "Interaccions",
"lists": "Llistes", "lists": "Llistes",
"mentions": "Mencions", "mentions": "Mencions",
"moderation": "Moderació",
"preferences": "Preferències", "preferences": "Preferències",
"public_timeline_description": "Apunts públics des d'aquesta instància", "public_timeline_description": "Apunts públics des d'aquesta instància",
"public_tl": "Línia de temps Pública", "public_tl": "Línia de temps Pública",
@ -375,9 +407,12 @@
"private": "Aquest apunt serà visible només per els teus seguidors", "private": "Aquest apunt serà visible només per els teus seguidors",
"public": "Aquest apunt serà visible per a tothom", "public": "Aquest apunt serà visible per a tothom",
"unlisted": "Aquest apunt no es veurà ni a la Línia de temps Pública ni a Tota la Xarxa Coneguda" "unlisted": "Aquest apunt no es veurà ni a la Línia de temps Pública ni a Tota la Xarxa Coneguda"
} },
"toggle_content_warning": "Des/activa l'avís de contingut"
}, },
"registration": { "registration": {
"awaiting_email_confirmation": "S'ha registrat el teu compte i s'ha enviat un correu a la teva adreça. Consulta el correu per completar el registre.",
"awaiting_email_confirmation_title": "Pendent de confirmar l'adreça de correu",
"bio": "Bio", "bio": "Bio",
"bio_placeholder": "p.e.\nHola! Benvingut a la meva bio.\nM'encanta veure anime i jugar a jocs. Espero que podrem ser amics!", "bio_placeholder": "p.e.\nHola! Benvingut a la meva bio.\nM'encanta veure anime i jugar a jocs. Espero que podrem ser amics!",
"captcha": "CAPTCHA", "captcha": "CAPTCHA",
@ -391,6 +426,8 @@
"reason_placeholder": "Aquesta instància aprova els registres manualment.\nExplica a l'administració per què vols registrar-te.", "reason_placeholder": "Aquesta instància aprova els registres manualment.\nExplica a l'administració per què vols registrar-te.",
"register": "Registre", "register": "Registre",
"registration": "Registre", "registration": "Registre",
"request_sent": "La teva soŀlicitud de registre s'ha enviat. Rebràs un correu quan sigui aprovada.",
"request_sent_title": "Soŀlicitud de registre",
"token": "Codi d'invitació", "token": "Codi d'invitació",
"username_placeholder": "p. ex. akko", "username_placeholder": "p. ex. akko",
"validations": { "validations": {
@ -500,6 +537,8 @@
"enable_web_push_notifications": "Habilitar notificacions del navegador", "enable_web_push_notifications": "Habilitar notificacions del navegador",
"enter_current_password_to_confirm": "Posa la teva contrasenya actual per a confirmar la teva identitat", "enter_current_password_to_confirm": "Posa la teva contrasenya actual per a confirmar la teva identitat",
"expert_mode": "Mostra avançat", "expert_mode": "Mostra avançat",
"expire_posts_enabled": "Esborra les publicacions després d'un cert nombre de dies",
"expire_posts_input_placeholder": "Nombre de dies",
"export_theme": "Desa el tema", "export_theme": "Desa el tema",
"file_export_import": { "file_export_import": {
"backup_restore": "Còpia de seguretat de la configuració", "backup_restore": "Còpia de seguretat de la configuració",
@ -641,6 +680,7 @@
"pad_emoji": "Acompanya els emojis amb espais al afegir-los des del selector", "pad_emoji": "Acompanya els emojis amb espais al afegir-los des del selector",
"panelRadius": "Panells", "panelRadius": "Panells",
"pause_on_unfocused": "Pausa quan la pestanya perdi el focus", "pause_on_unfocused": "Pausa quan la pestanya perdi el focus",
"permit_followback_description": "Aprova automàticament les soŀlicituds de seguiment que vinguin d'usuàries que ja segueixes",
"play_videos_in_modal": "Reproduir vídeos en un marc emergent", "play_videos_in_modal": "Reproduir vídeos en un marc emergent",
"post_look_feel": "Aspecte i Sensació dels apunts", "post_look_feel": "Aspecte i Sensació dels apunts",
"post_status_content_type": "Tipus de contingut d'apunt predeterminat", "post_status_content_type": "Tipus de contingut d'apunt predeterminat",
@ -709,6 +749,7 @@
"show_admin_badge": "Mostra l'insígnia \"Administrador\" en el meu perfil", "show_admin_badge": "Mostra l'insígnia \"Administrador\" en el meu perfil",
"show_moderator_badge": "Mostra l'insígnia \"Moderador\" en el meu perfil", "show_moderator_badge": "Mostra l'insígnia \"Moderador\" en el meu perfil",
"show_nav_shortcuts": "Mostra els accessos directes addicionals en el panell superior", "show_nav_shortcuts": "Mostra els accessos directes addicionals en el panell superior",
"show_page_backgrounds": "Mostra fons de pantalla específics de pàgines, com en les pàgines de perfil d'usuari",
"show_panel_nav_shortcuts": "Mostra els accessos directes de navegació de la línia de temps en el panell superior", "show_panel_nav_shortcuts": "Mostra els accessos directes de navegació de la línia de temps en el panell superior",
"show_scrollbars": "Mostra les barres de desplaçament de la columna lateral", "show_scrollbars": "Mostra les barres de desplaçament de la columna lateral",
"show_wider_shortcuts": "Mostra més separats els accessos directes del panell superior", "show_wider_shortcuts": "Mostra més separats els accessos directes del panell superior",
@ -884,8 +925,13 @@
"upload_a_photo": "Pujar una foto", "upload_a_photo": "Pujar una foto",
"useStreamingApi": "Rebre apunts i notificacions en temps real", "useStreamingApi": "Rebre apunts i notificacions en temps real",
"useStreamingApiWarning": "És genial emprar-lo. Si es trenca, refresca, suposo?", "useStreamingApiWarning": "És genial emprar-lo. Si es trenca, refresca, suposo?",
"use_blurhash": "Fes borroses les miniatures d'imatges NSFW",
"use_contain_fit": "No retallar els adjunts en miniatures", "use_contain_fit": "No retallar els adjunts en miniatures",
"use_one_click_nsfw": "Obre els adjunts NSFW amb només un clic", "use_one_click_nsfw": "Obre els adjunts NSFW amb només un clic",
"user_accepts_direct_messages_from": "Accepta missatges directes de",
"user_accepts_direct_messages_from_everybody": "Qualsevol",
"user_accepts_direct_messages_from_nobody": "Ningú",
"user_accepts_direct_messages_from_people_i_follow": "Comptes que segueixo",
"user_mutes": "Usuaris", "user_mutes": "Usuaris",
"user_profile_default_tab": "Pestanya per defecte en el Perfil d'Usuari", "user_profile_default_tab": "Pestanya per defecte en el Perfil d'Usuari",
"user_profiles": "Perfils d'usuari", "user_profiles": "Perfils d'usuari",
@ -1008,6 +1054,7 @@
"collapse": "Replega", "collapse": "Replega",
"conversation": "Conversa", "conversation": "Conversa",
"error": "Error carregant la línia de temps: {0}", "error": "Error carregant la línia de temps: {0}",
"follow_tag": "Segueix l'etiqueta",
"load_older": "Carrega apunts anteriors", "load_older": "Carrega apunts anteriors",
"no_more_statuses": "No hi ha més apunts", "no_more_statuses": "No hi ha més apunts",
"no_retweet_hint": "L'apunt és només per a seguidors o és \"directe\" i no es pot repetir o citar", "no_retweet_hint": "L'apunt és només per a seguidors o és \"directe\" i no es pot repetir o citar",
@ -1017,6 +1064,7 @@
"show_new": "Mostra els nous", "show_new": "Mostra els nous",
"socket_broke": "Connexió a temps real perduda: codi CloseEvent {0}", "socket_broke": "Connexió a temps real perduda: codi CloseEvent {0}",
"socket_reconnected": "Connexió a temps real establerta", "socket_reconnected": "Connexió a temps real establerta",
"unfollow_tag": "Deixa de seguir l'etiqueta",
"up_to_date": "Actualitzat" "up_to_date": "Actualitzat"
}, },
"toast": { "toast": {
@ -1081,6 +1129,7 @@
"block_confirm_title": "Bloqueja l'usuari", "block_confirm_title": "Bloqueja l'usuari",
"block_progress": "Bloquejant…", "block_progress": "Bloquejant…",
"blocked": "Bloquejat!", "blocked": "Bloquejat!",
"blocks_you": "Et té bloquejadi!",
"bot": "Bot", "bot": "Bot",
"deactivated": "Desactivat", "deactivated": "Desactivat",
"deny": "Denega", "deny": "Denega",
@ -1095,7 +1144,10 @@
"follow_cancel": "Cancel·la la sol·licitud", "follow_cancel": "Cancel·la la sol·licitud",
"follow_progress": "Sol·licitant…", "follow_progress": "Sol·licitant…",
"follow_sent": "Petició enviada!", "follow_sent": "Petició enviada!",
"follow_tag": "Segueix l'etiqueta",
"follow_unfollow": "Deixa de seguir", "follow_unfollow": "Deixa de seguir",
"followed_tags": "Etiquetes que segueixes",
"followed_users": "Usuaris que segueixes",
"followees": "Seguint", "followees": "Seguint",
"followers": "Seguidors", "followers": "Seguidors",
"following": "Seguint!", "following": "Seguint!",
@ -1120,12 +1172,14 @@
"mute_domain": "Bloqueja el domini", "mute_domain": "Bloqueja el domini",
"mute_progress": "Silenciant…", "mute_progress": "Silenciant…",
"muted": "Silenciat", "muted": "Silenciat",
"not_following_any_hashtags": "No estàs seguint cap etiqueta",
"note": "Nota privada", "note": "Nota privada",
"per_day": "per dia", "per_day": "per dia",
"remote_follow": "Seguiment remot", "remote_follow": "Seguiment remot",
"remove_follower": "Esborra seguidor", "remove_follower": "Esborra seguidor",
"replies": "Amb respostes", "replies": "Amb respostes",
"report": "Informa", "report": "Informa",
"requested_by": "Et vol seguir",
"show_repeats": "Mostra les repeticions", "show_repeats": "Mostra les repeticions",
"statuses": "Apunts", "statuses": "Apunts",
"subscribe": "Subscriu-te", "subscribe": "Subscriu-te",
@ -1135,11 +1189,13 @@
"unfollow_confirm_accept_button": "Sí, deixa'l de seguir", "unfollow_confirm_accept_button": "Sí, deixa'l de seguir",
"unfollow_confirm_cancel_button": "No, no el deixis de seguir", "unfollow_confirm_cancel_button": "No, no el deixis de seguir",
"unfollow_confirm_title": "Deixa de seguir l'usuari", "unfollow_confirm_title": "Deixa de seguir l'usuari",
"unfollow_tag": "Deixa de seguir l'etiqueta",
"unmute": "Deixa de silenciar", "unmute": "Deixa de silenciar",
"unmute_progress": "Deixant de silenciar…", "unmute_progress": "Deixant de silenciar…",
"unsubscribe": "Anul·la la subscripció" "unsubscribe": "Anul·la la subscripció"
}, },
"user_profile": { "user_profile": {
"field_validated": "Enllaç verificat",
"profile_does_not_exist": "Disculpes, aquest perfil no existeix.", "profile_does_not_exist": "Disculpes, aquest perfil no existeix.",
"profile_loading_error": "Disculpes, hi ha hagut un error carregant aquest perfil.", "profile_loading_error": "Disculpes, hi ha hagut un error carregant aquest perfil.",
"timeline_title": "Línia de temps del usuari" "timeline_title": "Línia de temps del usuari"

View file

@ -18,7 +18,8 @@
"reason": "Λόγος", "reason": "Λόγος",
"simple_policies": "Πολιτικές του instance" "simple_policies": "Πολιτικές του instance"
} }
} },
"staff": "Προσωπικό"
}, },
"announcements": { "announcements": {
"all_day_prompt": "Αυτό είναι ένα ολοήμερο συμβάν", "all_day_prompt": "Αυτό είναι ένα ολοήμερο συμβάν",
@ -27,10 +28,14 @@
"delete_action": "Διαγραφή", "delete_action": "Διαγραφή",
"edit_action": "Επεξεργασία", "edit_action": "Επεξεργασία",
"end_time_display": "Λήγει στις {time}", "end_time_display": "Λήγει στις {time}",
"end_time_prompt": "Λήξη: ",
"inactive_message": "Αυτή η ανακοίνωση είναι ανενεργή",
"page_header": "Ανακοινώσεις", "page_header": "Ανακοινώσεις",
"post_action": "Ανάρτηση",
"title": "Ανακοίνωση" "title": "Ανακοίνωση"
}, },
"chats": { "chats": {
"delete_confirm": "Θέλετε σίγουρα να διαγράψετε αυτό το μήνυμα;",
"empty_message_error": "Δε μπορεί να σταλεί κενό μήνυμα", "empty_message_error": "Δε μπορεί να σταλεί κενό μήνυμα",
"error_sending_message": "Κάτι πήγε λάθος κατά την αποστολή του μηνύματος.", "error_sending_message": "Κάτι πήγε λάθος κατά την αποστολή του μηνύματος.",
"message_user": "Στείλε μήνυμα στον/στην {nickname}", "message_user": "Στείλε μήνυμα στον/στην {nickname}",

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