Compare commits

..

245 Commits

Author SHA1 Message Date
lamp 589d8ea29f Merge remote-tracking branch 'upstream/stable' into public-favorites 2025-10-14 14:45:50 -07:00
Hannah Ward 52b27396b9 Merge branch 'develop' into stable 2025-10-13 13:08:45 +01:00
Hannah Ward c2db0e66ef unset min-height for attachments in notifications 2025-10-13 13:07:57 +01:00
Floatingghost 9f8eba3464 Merge branch 'develop' into stable 2025-10-13 10:49:51 +01:00
Floatingghost 762676e105 and again 2025-10-13 10:49:35 +01:00
Floatingghost d6e8d785c8 Merge branch 'develop' into stable 2025-10-13 10:48:55 +01:00
Floatingghost 1fa242232e bump version 2025-10-13 10:48:46 +01:00
Weblate 539977de9d Merge branch 'origin/develop' into Weblate. 2025-10-04 22:05:59 +00:00
Oneric d2995ada16 Merge pull request 'Misc fixes' (#416) from novenary/akkoma-fe:misc-fixes/2024-09-17 into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/416
Reviewed-by: Oneric <oneric@noreply.akkoma>
2025-10-04 22:05:56 +00:00
Weblate bcd15ef858 Merge branch 'origin/develop' into Weblate. 2025-10-04 22:04:27 +00:00
Oneric 900ac68ca6 Merge pull request 'Use pixelated (up)scaling for custom emoji' (#448) from Riedler/akkoma-fe:pixemoji into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/448
Reviewed-by: Oneric <oneric@noreply.akkoma>
2025-10-04 22:04:24 +00:00
Weblate 34bbcef83e Merge branch 'origin/develop' into Weblate. 2025-10-04 22:04:15 +00:00
Oneric 37ce8352a9 Merge pull request 'fix multiline alt texts for generic attachments (e.g. zip files)' (#446) from Riedler/akkoma-fe:fix-attachalt into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/446
Reviewed-by: Oneric <oneric@noreply.akkoma>
2025-10-04 22:04:11 +00:00
Riedler f48138c979 oops! added it to media_modal as well 2025-09-24 18:04:43 +02:00
Riedler 5baa2ce40f apply pixel art detection to more places 2025-09-24 17:28:29 +02:00
novenary fef531b8a0 conversation: scrollIntoView when collapsed
This helps find the original context when collapsing a thread on the
timeline.
2025-09-24 15:37:06 +03:00
Riedler bf0c137057 conditionally render small emojis as pixelated 2025-09-24 13:49:16 +02:00
Nguyễn Gia Phong 5a50ceb3aa Use pixelated (up)scaling for custom emoji 2025-09-24 13:13:30 +02:00
Riedler f08a961199 fix: some days I hate CSS 2025-09-22 17:56:16 +02:00
Riedler d252e10543 fix: scrollable gallery rows for if contents are too long
like my peanits
2025-09-22 16:23:33 +02:00
novenary 7c84854b10 post_status_form: inherit language from parent
If I'm replying to a post in Klingon, chances are I'm going to write in
Klingon. This reduces friction for properly marking post language in a
conversation.
2025-09-20 11:10:01 +03:00
novenary ab606c6160 post_status_form: reset all to defaults on clear 2025-09-20 11:10:01 +03:00
novenary 38d8a9751a emoji_picker: select recents tab by default
This saves a click to get at your most commonly used emoji.
2025-09-20 11:09:59 +03:00
novenary 2c92467dcd post_status_form: fix enter key in subject field
This fixes random actions being triggered by the enter key while the
subject field is focused.

When pressing enter, the browser simulates a click on the first "submit"
button it finds in the form.
A submit button is a button without `type="button"` set.
Remediate this by setting the type attribute on all but the "Post"
button.

Additionally, inhibit the enter key in the subject field (ctrl+enter
still works).
2025-09-17 23:43:55 +03:00
Riedler bb71635d12 fix: no multiline alt text in post popovers 2025-09-10 03:13:13 +02:00
Riedler e1b4d8f59a fix: minor overflow issue in draft attachment alt text 2025-09-10 02:35:14 +02:00
Riedler 2455bb70f3 feat: since I'm already here, let's do some basic styling 2025-09-10 02:25:02 +02:00
Riedler fbc6cd59bc fix: multiline alt text no longer flows into itself 2025-09-10 02:10:38 +02:00
Weblate 873048de2e Translated using Weblate (Japanese (ja_EASY))
Currently translated at 72.0% (758 of 1052 strings)

Co-authored-by: Deleted User <noreply+21@weblate.org>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/ja_EASY/
Translation: Pleroma fe/pleroma-fe
2025-09-07 01:23:49 +00:00
Weblate 7a4e2a8644 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1052 of 1052 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
2025-09-07 01:23:49 +00:00
Weblate a1d92ffd86 Translated using Weblate (German)
Currently translated at 98.5% (1037 of 1052 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/de/
Translation: Pleroma fe/pleroma-fe
2025-09-07 01:23:49 +00:00
Oneric b60f42b959 woodpecker: fix obsolete secrets usage
The existing definition now only errors out
2025-09-07 00:00:00 +00:00
Oneric 55dff3a9bd Merge pull request 'Fix sensitive by default option' (#443) from norm/akkoma-fe:fix-sensitive into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/443
Reviewed-by: Oneric <oneric@noreply.akkoma>
2025-09-07 00:50:15 +00:00
Norm 9ef8effeed Clarify the sensitiveIfSUbject setting description 2025-09-06 08:31:26 -04:00
Norm 9c15db16a6 Fix sensitive by default option
Fixes https://akkoma.dev/AkkomaGang/akkoma-fe/issues/442
2025-09-03 20:54:12 -04:00
Weblate 674a816453 Merge branch 'origin/develop' into Weblate. 2025-08-04 00:27:08 +00:00
Weblate be2207fa42 Translated using Weblate (French)
Currently translated at 100.0% (1051 of 1051 strings)

Co-authored-by: Thomate <thomas@burdick.fr>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/fr/
Translation: Pleroma fe/pleroma-fe
2025-07-21 13:47:34 +00:00
Weblate 3f3ea32f81 Translated using Weblate (Greek)
Currently translated at 18.3% (193 of 1051 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
2025-07-21 13:47:34 +00:00
Weblate abc6b299e0 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1051 of 1051 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
2025-07-21 13:47:34 +00:00
Weblate b8b18c67b1 Translated using Weblate (Turkish)
Currently translated at 19.6% (207 of 1051 strings)

Co-authored-by: Hasan Yıldız <hasanyildiz0@yaani.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/tr/
Translation: Pleroma fe/pleroma-fe
2025-07-21 13:47:34 +00:00
Oneric 4cf4b5e2d0 Merge pull request 'Support selectable visibility of repeats' (#440) from Oneric/akkoma-fe:boost-scopes into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/440
2025-06-10 18:37:59 +00:00
jadiunr d617a9596a Add support selectable visibility of repeat
Co-authored-by: Oneric <oneric@oneric.stub>
2025-05-18 22:52:55 +02:00
Oneric 4734e9668d refactor: extract scope logic into shared module 2025-05-18 22:52:55 +02:00
Oneric 9787f43343 Merge pull request 'Check for canvas extract permission when initializing favicon service' (#432) from mkljczk/akkoma-fe:check-canvas-extract-permission into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/432
2025-05-09 18:34:53 +00:00
Oneric 61bdedc82f Merge pull request 'remove some jank in emoji reacts component' (#435) from Riedler/akkoma-fe:fix-reacts into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/435
2025-05-09 18:30:07 +00:00
Oneric a4eddc7f1c Merge pull request 'polls: base fractions on voters for multiple choice polls' (#436) from Oneric/akkoma-fe:poll-percentages into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/436
2025-05-09 18:29:54 +00:00
sn0w 94c5998593 Apply wordfilters to attachment alt-texts
EDITED to apply review suggestions:
  - short circuit search and immediately return once match found
  - Array.some() instead of for loop
2025-05-05 22:39:43 +02:00
Oneric 851dd263c0 docs/sticker: fix example setup 2025-04-25 00:45:04 +02:00
Oneric 473ba89355 polls: base fractions on voters for multiple choice polls
This allows discerning how many voters agreed
with an option and aligns with other clients.
However, a backend bug makes this impossible for
remote multiple choice polls, so retain current
behaviour for anything affected.
2025-04-04 19:27:30 +02:00
Riedler 4ce8ffcec1 fix: shrink unicode emojis in reactions slightly
some large ones exceeded container boundaries before
2025-03-26 09:09:56 +01:00
Riedler e62b154228 fix: uniform height sizing and layouting 2025-03-26 07:39:54 +01:00
Riedler e87a9ced61 fix: no more emojis bleeding into button borders 2025-03-26 07:12:45 +01:00
Riedler 7245775b27 fix: picked reactions should be positioned identically 2025-03-26 06:56:32 +01:00
mkljczk 6373c5a05d Check for canvas extract permission when initializing favicon service 2025-03-05 15:02:16 +00:00
Floatingghost cfbf3ecb6d Merge branch 'develop' into stable 2025-03-01 16:18:39 +00:00
Floatingghost 2914eaf1ca Revert "reduce gallery size"
This reverts commit 06ba190e2e.
2025-03-01 16:14:55 +00:00
Floatingghost 578ef52df6 Merge branch 'develop' into stable 2025-03-01 12:20:57 +00:00
floatingghost 0bf9cb0660 Merge pull request 'Optional widened main column' (#402) from Riedler/akkoma-fe:wide-columns-for-upstream into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/402
2025-03-01 12:00:33 +00:00
floatingghost 65cb3b95e0 Merge pull request 'Use FEP-c16b: Formatting MFM functions' (#410) from ilja/akkoma-fe:use_fep-c16b_formatting_mfm_functions into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/410
2025-02-27 12:04:41 +00:00
Riedler f15b94d566 made widenTimeline false by default 2025-02-07 03:50:44 +01:00
Riedler 06ba190e2e reduce gallery size 2025-02-07 03:49:57 +01:00
floatingghost 2086522d64 Merge pull request '(arguably) improved layouting of user profile page' (#403) from Riedler/akkoma-fe:user-profile-changes into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/403
2025-01-15 21:47:55 +00:00
Floatingghost cb63cc38c1 Merge branch 'develop' into stable 2025-01-05 16:32:12 +00:00
Weblate fa294e0003 Merge branch 'origin/develop' into Weblate. 2025-01-05 15:52:29 +00:00
floatingghost d3fa5cfad0 Merge pull request 'post_status_form: enable sync flush for watcher' (#414) from novenary/akkoma-fe:sticky-drafts into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/414
2025-01-05 15:52:26 +00:00
Weblate 9552287442 Merge branch 'origin/develop' into Weblate. 2025-01-05 15:52:19 +00:00
floatingghost 6b7c8f0def Merge pull request 'Allow using custom source URLs' (#421) from Oneric/akkoma-fe:custom-source into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/421
2025-01-05 15:52:15 +00:00
Weblate 3386692e26 Merge branch 'origin/develop' into Weblate. 2025-01-05 15:51:50 +00:00
floatingghost ad6bb47003 Merge pull request 'Add visual feedback when clicking translate' (#423) from ilja/akkoma-fe:provide_visual_feedback_when_clicking_translate_button into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/423
2025-01-05 15:51:47 +00:00
ilja 9838545904 Add visual feedback when clicking translate
In a status, we can choose to translate the status (assuming there's a translator enabled on the backend)

It will translate, in practice generally according to detected language, and also provide an option to override the source language.

Translating can take a while, and there wasn't really a visual feedback when it was translating.
Now the translate button will be dissabled while translating.
2024-12-01 14:04:49 +01:00
ilja space 868c6e41ac Improve readability for MFM styles code
The code to turn mdm-data-* attributes into a value for the style attribute is complex.
I wrapped it in it's own function now for better code readability.
A comment was already provided with what the code intents to do and why, this information has also been moved
to this function.
2024-12-01 12:24:23 +01:00
Weblate b3f25e5d84 Translated using Weblate (Polish)
Currently translated at 99.7% (1046 of 1049 strings)

Translated using Weblate (Polish)

Currently translated at 99.7% (1046 of 1049 strings)

Co-authored-by: ? <akkoma@mkljczk.pl>
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-11-22 04:56:24 +00:00
Weblate 248509073e Translated using Weblate (Italian)
Currently translated at 93.8% (985 of 1049 strings)

Co-authored-by: Steffo <akkoma@steffo.eu>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/it/
Translation: Pleroma fe/pleroma-fe
2024-11-22 04:56:24 +00:00
Weblate a7d6235131 Translated using Weblate (Lithuanian)
Currently translated at 8.1% (86 of 1049 strings)

Translated using Weblate (Lithuanian)

Currently translated at 5.5% (58 of 1049 strings)

Translated using Weblate (Lithuanian)

Currently translated at 1.9% (20 of 1049 strings)

Added translation using Weblate (Lithuanian)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: http://translate.akkoma.dev/projects/akkoma/pleroma-fe/lt/
Translation: Pleroma fe/pleroma-fe
2024-11-22 04:56:24 +00:00
ilja space 177d96f977 Improve how scaling is done
During code review a much better way was pointed out to do the emoji scaling, by using `em`.

*key uses 2em for emoji, which is smaller than Akkoma has. I now kept the 38px for Akkoma,
but when "zoom" (ie x2, x3, x4, tada) happens, we set to 2em and zoom from there.
2024-11-01 14:25:22 +01:00
Oneric 42ba77ebf4 Allow using custom source URLs 2024-10-26 16:32:14 +02:00
floatingghost 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: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/422
2024-10-26 03:42:48 +00:00
floatingghost c76dc6d79e Merge pull request 'Fix redirect on logout' (#420) from Oneric/akkoma-fe:logout-redirect into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/420
2024-10-26 03:42:23 +00:00
floatingghost cb4c581cde Merge pull request 'Add proper autocomplete prop for TOTP login field' (#424) from tudbut/akkoma-fe:develop into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/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
novenary ef242a1ddd post_status_form: enable sync flush for watcher
This fixes drafts not clearing after posting a reply.

Vue 3.3.11 changed watchers to stop firing after component unmount.
After posting a reply, the post form is removed, now causing the queued
event to be discarded.
Synchronous flush causes the handler to be called immediately when
changes happen, solving the problem.

The performance impact of this change seems non-existent. Even before,
typing would generate an event for each keystroke. Pasting is atomic.

See: https://github.com/vuejs/core/pull/7181
See: https://github.com/vuejs/docs/commit/80e2128d52603856a26a8bb7258606cfe80561e9
Fixes: a7dea2f70f
Fixes: #413
2024-10-15 00:16:45 +03:00
tea 35cf3327c8 fix panel z-index conflicting with heading popover
resolves #342
2024-10-05 10:59:46 +02:00
Oneric 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
floatingghost 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: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/409
2024-08-25 09:09:35 +00:00
floatingghost fa8fde2ab1 Merge pull request 'Upgrade vue packages' (#411) from Oneric/akkoma-fe:vue-mathml into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/411
2024-08-25 09:08:04 +00:00
floatingghost 1f2c96a485 Merge pull request 'Fix setting restore from file' (#406) from Oneric/akkoma-fe:fix-file-restore into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/406
2024-08-25 09:07:18 +00:00
ilja 25681cf5f6 Don't require # in the data-mfm-color attribute
For colour in MFM attributes, we expected a `#`, but that's apparently wrong. The BE
translates the `color` attribute in `$[fg.color=000 text]` into `data-mfm-color=000`.
But for the SCSS to work, we need to put it in the style attribute as `--mfm-color: #000`.

Generally we just add the attribute value as-is in the `style` attribute, but now we
have a special exception for color so we add a `#` before the value.
2024-08-18 15:48:22 +02:00
Oneric 6c178aa257 Upgrade vue packages
Bumping past vue 3.4.0 guarantees MathML support for FEP-dc88.

Related to: https://akkoma.dev/AkkomaGang/akkoma/pulls/642
2024-08-17 18:01:59 +02:00
ilja 6666a273a4 MFM only use sanitised data-* attribute values
We take the value from a data-* attribute and then add this to the style attribute.
This will probably be OK in most cases, but just to be sure, we check for "weird" characters first.
For now we only allow letters, numbers, dot, hash, and plus and minus sign, because those are the ones I currently know of who are used in MFM.
The data-* attribute remains because it was already considered proper HTML as-is.
2024-08-11 18:11:03 +02:00
ilja 3210873d7f MFM make all supported tags suggested
When typing MFM, a sugestor drop-down appears so you can see and/or choose what MFM function to use
The new MFM functions we support have now also been added
2024-08-10 13:55:52 +02:00
ilja f5f9949253 Fix mfm-position and mfm-scale
The `span`'s needed an inline-block for the transform to wrok
I also added an `overflow: hidden;` because these functions can make the text go beyond the borders of the StatusBody
With `overflow: hidden;`, it won't show outside of the borders
2024-08-10 13:13:47 +02:00
ilja ba4ae5badb Fix MFM functions x2, x3, and x4
These now work for the new, FEP-c16b compliant, representation
Nesting also works

It already worked for text and "normal" emoji, but now it also works for custom emoji
2024-08-10 12:45:37 +02:00
ilja 56a59e1b55 fill in data-mfm- variables
Things like `speed=0.1s` now work

I also noticed a class was set on StatusBody, but we don't use it, we use StatusContent.
Therefor I removed it now.

We do still pass the setting through StatusBody to RichContent bc it's used there to decide to not show greentext for arrows when MFM was used.
Note that while this setting still works
* You have to refresh the page to see it working (was already like this, so I didn't touch it here)
* It explicitly checks for content type. If womeone provides MFM-like HTML, then it will still show as greentext if that option is enabled
  I think it's a bit inconsistent, but otoh, the inconsistency to me seems more that we ignore the greentext option for one input type specifically

I do still notice generall bugs with MFM.
* Position doesn't seem to work, neither does scale.
* There also seems to be a regression where custom emojis don't become larger any more with e.g. `$[x2 :hehe: ]`

I don't assume the regression is made in this commit, so I add this already. The rest needs to be fixed before merging.
2024-08-05 17:23:15 +02:00
ilja 3065416c93 Make new SCSS work for non-variables
The SCSS that we took from Foundkey in a previous commit, is now working
The settings for disabling MFM or only show animation on hover are working
The previous representation also works and it's clearly marked in the code what is legacy
All the MFM SCSS is now located in one file specifically for MFM, ./src/components/status_content/mfm.scss

This is only SCSS:
* The variables who are provided as data-attributes are not working yet
* `sparkle` also doesn't work
2024-08-04 19:10:25 +02:00
Johann150 94141dcb3c Message from commiter: Add Foundkey MFM stylesheet
This is part of a bigger work to fix MFM in Akkoma
See <https://akkoma.dev/AkkomaGang/akkoma/issues/381>

Here we add the MFM stylesheet as it is used by Foundkey
See <https://akkoma.dev/FoundKeyGang/FoundKey/commit/b22e627089e589b720f42a6b99e671f1bab8c643>

Foundkey uses MFM and both the Founkey and Akkoma projects and communities, have historically been closely related
As such it makes sense to start with feature-parity with Foundkey

This commit only adds the stylesheet so that correct attribution is given
Properly integrating and making it work will happen in later commits
2024-08-04 17:55:32 +02:00
ilja 92e278d406 Move MFM SCSS to separate SCSS
MFM was defined in three places.
There was ./src/components/status_body/status_body.scss => I moved this to ./src/components/status_content/mfm.scss
There was ./src/components/status_content/status_content.vue => I moved this to ./src/components/status_content/mfm.scss
There's ./static/mfm.css => I kept this as-is

./src/components/status_content/mfm.scss is now being loaded in ./src/components/status_content/status_content.vue

I added a comment in both ./src/components/status_content/mfm.scss and ./static/mfm.css referencing each other

Note that this is just a first step in an overhoal of how MFM is handled. It seemed easier to do this as a first step and then build further on that.
2024-08-04 17:44:21 +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
RiedleroD 94ed0991bc reverted 2e83ccefdc and clarified that compact user info is only used with enough room 2024-07-06 14:54:24 +02:00
Oneric 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: https://akkoma.dev/AkkomaGang/akkoma-fe/issues/405
2024-07-06 01:59:42 +02:00
RiedleroD e955eb4503 oops, unfucked username placement 2024-07-03 18:58:50 +02:00
RiedleroD c39d9fa64b fixed stuff overflowing in user popup e.g. in notifs 2024-07-03 18:30:51 +02:00
RiedleroD a74a631793 stopped user handle from overflowing from its boundaries in user card 2024-07-03 17:45:40 +02:00
RiedleroD 2e83ccefdc disabled "compact user info" setting in mobile layout 2024-07-03 17:35:13 +02:00
RiedleroD cf11b2523e disabled compact user card in mobile layout 2024-07-03 17:26:09 +02:00
Floatingghost 8765491399 Do not try to destructure when we don't need to 2024-06-27 02:58:52 +01:00
RiedleroD 85001814a2 added setting for user info compactness 2024-06-26 18:09:13 +02:00
RiedleroD c902219997 added setting to switch between center and left-aligned user bio 2024-06-26 17:20:50 +02:00
RiedleroD 2e2e87db75 expand underlay to screen edges when TL is widened 2024-06-26 16:43:32 +02:00
RiedleroD b2af067fd3 reverted visual changes to underlay 2024-06-26 16:39:04 +02:00
floatingghost 4211e05a75 Merge pull request 'status component: Fix repeater name overflowing' (#383) from yukijoou/akkoma-fe:fix-status-usernames into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/383
2024-06-25 21:34:15 +00:00
Floatingghost a3251a1ba6 Merge remote-tracking branch 'origin/translations' into develop 2024-06-23 03:03:40 +01:00
Floatingghost e5608f4009 remove ora as a dep 2024-06-23 03:03:11 +01:00
Floatingghost 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
floatingghost 24b9e350e2 Merge pull request 'added minimum space to empty timeline' (#400) from Riedler/akkoma-fe:empty-tl-minspace into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/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
floatingghost 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: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/401
2024-06-17 21:40:26 +00:00
RiedleroD 754cd2fa57 slightly adjusted edit button spacing 2024-06-16 17:15:04 +02:00
RiedleroD 31055fb4f2 removed min-width statements that were messing up my layouts 2024-06-16 17:14:59 +02:00
RiedleroD 918b0e3770 stopped username from wrapping… 2024-06-16 17:14:14 +02:00
RiedleroD 88aae1706a oops, removed unneeded spacing 2024-06-16 17:14:08 +02:00
RiedleroD 3d2a8a3ca2 left-aligned bio text
why the fuck was it centered in the first place?!?
2024-06-16 17:14:03 +02:00
RiedleroD a24fff5d5b moved user stats to between user info and user actions 2024-06-16 17:14:00 +02:00
RiedleroD 4abddf5e6a made wide column layout optional 2024-06-16 16:37:33 +02:00
RiedleroD 1b4df9e79d reverted audio attachments to 4:1 aspect ratio 2024-06-16 16:37:30 +02:00
RiedleroD 45fe334cd7 fixed sizing issues with attachments in some non-status containers 2024-06-16 16:37:26 +02:00
RiedleroD dd32a33d59 fixed media attachment heights 2024-06-16 16:37:22 +02:00
RiedleroD 74b651a3a2 made attached images max size scale with font size
meta-comment: eliminated corner-case weirdness by replaced cursed CSS with slightly less cursed CSS
2024-06-16 16:37:07 +02:00
RiedleroD 21fe7d76d3 made columns use more space, fixed minor bug 2024-06-16 16:35:46 +02:00
RiedleroD b2cab6d088 only flatten top of post body textarea if subject line is visible 2024-06-16 16:26:44 +02:00
RiedleroD 3ebaba6fa7 smushed subject line and post body together, kinda 2024-06-16 16:14:16 +02:00
RiedleroD f1058567b9 also set min height for other lists (e.g. follow requests), not just the timeline 2024-06-16 16:12:15 +02:00
RiedleroD 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
floatingghost c68595345f Merge pull request 'ANNOYING dependency update' (#397) from dep-update into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/397
2024-06-15 12:41:23 +00:00
Floatingghost a5d4b0a68c Merge branch 'develop' into dep-update 2024-06-15 13:38:40 +01:00
Floatingghost 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
floatingghost 97966045cb Merge pull request 'make status form selectors justified properly' (#398) from rat/akkoma-fe:status-form-selector into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/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
Floatingghost c952b2335c correct eslint plugin 2024-05-29 04:04:56 +01:00
Floatingghost 0baf31f498 correct package.json lint task 2024-05-29 04:01:29 +01:00
Floatingghost 8fa24d0c40 migrate to eslint 9 syntax 2024-05-29 03:59:37 +01:00
Floatingghost 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
floatingghost 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
floatingghost 7789c5def6 Update .woodpecker.yml 2024-05-28 21:31:46 +00:00
Floatingghost 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
Floatingghost 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
Floatingghost 0b437ab6fd remove line left over in conflict 2024-05-28 04:15:35 +01:00
Floatingghost 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
floatingghost 8964dce609 Merge pull request 'Make animated emojis in reactions pause' (#378) from sarayalth/akkoma-fe:pause-animated-reaction into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/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
floatingghost 1a49a1b3ac Merge pull request 'Expand Unicode emoji map' (#385) from Oneric/akkoma-fe:emoji_update into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/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
Floatingghost 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
Floatingghost 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
Floatingghost 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
floatingghost 70275684bf Merge pull request 'Fix posting for "special" interface languages' (#377) from Oneric/akkoma-fe:post-language-specialcodes into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/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
floatingghost 29ff2ef455 Merge pull request 'Fix ordering of favourites timeline' (#392) from Oneric/akkoma-fe:favourite-ordering into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/392
2024-05-28 02:07:15 +00:00
Yuki Joou 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
Oneric 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: https://akkoma.dev/AkkomaGang/akkoma-fe/issues/391
2024-05-15 18:47:47 +02:00
sarah cc709394c5 remove unused classes on notifications 2024-05-14 18:09:21 +02:00
Serhii Tereshchenko 57beea6a0d fix: Use label and key for options 2024-05-13 16:13:58 +03:00
lamp 4d91a7b2c3 Fix public favorites
Show favorites tab to anyone when "Don't show list of my favorites" is unchecked.

Adapted from upstream changes by marcin mikołajczak <git@mkljczk.pl>:
https://git.pleroma.social/pleroma/pleroma-fe/-/commit/6f452d672fe740035cf1d29d03bcda0d39438753?merge_request_iid=1883
https://git.pleroma.social/pleroma/pleroma-fe/-/commit/1ceffb4e713b4b20d70121fba92d2b50f2d3cadf?merge_request_iid=1908
2024-05-06 17:55:10 -07:00
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
Serhii Tereshchenko 042e8c78dc feat: Add "Default post language" option
Refs #386
2024-04-20 16:07:03 +03:00
Oneric 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
sarah 1f5f8665c8 make animated reactions pause unless hovered on notifications 2024-03-01 20:02:19 +01:00
Oneric 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
FloatingGhost 7cc6c35654 Merge branch 'develop' into stable 2024-02-24 13:55:57 +00:00
FloatingGhost 228679e49e 2024.02 release 2024-02-24 13:55:10 +00:00
Weblate d610a46c32 Merge branch 'origin/develop' into Weblate. 2024-02-20 16:24:40 +00:00
floatingghost ed0b403c33 Merge pull request 'Auto-approve followbacks (frontend part)' (#365) from Oneric/akkoma-fe:followbacks-fe into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/365
2024-02-20 16:24:37 +00:00
Weblate 0925763267 Merge branch 'origin/develop' into Weblate. 2024-02-20 16:20:18 +00:00
floatingghost 0f842b300b Merge pull request 'Display profile background of other users' (#371) from Oneric/akkoma-fe:profile-backgrounds into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/371
2024-02-20 16:20:14 +00:00
Weblate e292af4211 Merge branch 'origin/develop' into Weblate. 2024-02-19 14:04:37 +00:00
floatingghost 865cb6f96a Merge pull request 'Add Indonesian translation' (#366) from leap123/akkoma-fe:leap123-patch-1 into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/366
2024-02-19 14:04:34 +00:00
Weblate 4e7d5d3a08 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-02-15 17:32:33 +00:00
Weblate f2d0c4c7d5 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-02-15 17:32:33 +00:00
Weblate 02a6591f20 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-02-15 17:32:33 +00:00
Weblate 94c70f8914 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-02-15 17:32:33 +00:00
Weblate 3ba8c90e1e 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-02-15 17:32:33 +00:00
Weblate 83db80f88c 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-02-15 17:32:32 +00:00
Weblate 1489d92997 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-02-15 17:32:32 +00:00
Weblate db5c9572dc 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-02-15 17:32:32 +00:00
Weblate 5bb53c8b0d 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-02-15 17:32:32 +00:00
Weblate 665f88f5c7 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-02-15 17:32:32 +00:00
Oneric 050c7df2e6 Display profile background of other users
And add a new frontend setting to hide other people's background.
2024-02-14 18:44:57 +01:00
Oneric a77a9e04d9 Expose new server-side permit_followback setting
Added to backend in https://akkoma.dev/AkkomaGang/akkoma/pulls/674
2024-02-04 22:19:14 +01:00
leap123 a57334991e Add Indonesian translation
The Indonesian translation is technically almost complete, just not added to messages.js
2024-01-19 04:27:26 +00:00
floatingghost 8dce31d0ad Merge pull request 'Improve UX of subject / Content Warning field' (#362) from hazelnoot/akkoma-fe:develop into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/362
2023-12-20 18:49:40 +00:00
Hazel Koehler ea9ad4d600 fix "always show content warning" setting 2023-12-20 12:39:31 -05:00
Hazel Koehler 34e2800f59 add button to toggle the spoiler / CW field 2023-12-16 14:44:26 -05:00
Hazel Koehler 3d65eccf04 use main emoji button for spoiler / CW field 2023-12-16 13:37:59 -05:00
floatingghost d304be654f Merge pull request 'Update build setup instructions' (#343) from norm/pleroma-fe:update-build-setup into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/343
2023-12-15 12:24:33 +00:00
floatingghost aee97fa948 Merge pull request 'Re-added extension checking for still-image' (#346) from Mergan/pleroma-fe:still-image-ultimate into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/346
2023-12-15 12:24:07 +00:00
floatingghost 7da1687f31 Merge pull request 'Use relative font size and set appropriate overflow behavior' (#355) from xarvos/pleroma-fe:update-css into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/355
2023-12-15 12:12:28 +00:00
floatingghost a8f193d4bd Merge pull request 'Stop constant movement of notifications due to changing timestamps' (#353) from Oneric/akkoma-fe:notification-writhing into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/353
2023-12-15 11:57:47 +00:00
floatingghost 81c82e11bc Merge pull request 'Explicitly set SameSite attribute for cookies' (#352) from Oneric/akkoma-fe:cookie-samesite into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/352
2023-12-15 11:54:15 +00:00
floatingghost 00cadce5b4 Merge pull request 'Format dates, times with window.navigator.language instead of UI i18n locale' (#354) from smitten/akkoma-fe:date-locale-fix-cherrypick into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/354
2023-12-15 11:52:59 +00:00
floatingghost 40a08f279b Merge pull request 'Drop broken "@ symbol as icon" setting' (#359) from Oneric/akkoma-fe:at-icon into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/359
2023-11-16 10:41:17 +00:00
Oneric c524a47e6f Drop broken "@ symbol as icon" setting
It was merged into pleroma-fe on 2022-02-03 in
76547fe66d and imported
into akkoma-fe on 2022-06-08 with the merge commit
f6cf509a04.

However, something went wrong in the merge and while the setting
and its infrastructure exist, it is never used anywhere and @ is
always displayed as text.

Given it existed in this broken state for nearly one and a half years,
never worked on akkoma-fe and no bugs were filed about this, it appears
nobody cares, so let’s just remove it.
2023-11-15 23:36:19 +01:00
Ngô Ngọc Đức Huy 235c734d37 Use overflow: auto for description
Previously it sets overflow: scroll, so there's an unnecessary
horizontal scroll.
overflow: auto only shows scrollbar when it overflows
2023-11-05 09:32:19 +07:00
Ngô Ngọc Đức Huy deaef1d0b9 Use relative unit for font size 2023-11-05 09:21:01 +07:00
smitten 1b28ec3b72 Match UI i18n configuration to browser locales 2023-11-01 23:10:57 -04:00
smitten c9dc8f00f9 Use window.navigator.language before interface i18n language 2023-10-30 23:56:53 -04:00
Oneric beee99e733 Stop notifications boxes from change size over time
Notifications about favourites and follows use .notification-right,
notifications about replies instead use .heading-right.

Previously only the former set a min-width, however the
chosen value of 3em was too small to fit the worst case.
As a consequence, when the timestamp text changes over time,
its element width changes, which may result in neighbouring text
(no longer) needing to wrap to a new line in turn changing the size
of the whole notification box pushing older notification boxes down/up.

These constant movements at the side of the screen can be quite
annoying and confusing when the cause cannot be immediately discerned.

Avoid this, by reserving enough space for any timestamp.

For English, the worst case is the five-character 'XXmin', since the
short identifier for minutes is the longest with three letters.
With two exceptions, all other current localisation also do not exceed
three letters in any short unit identifier up to days.
However, some localisations (e.g. Polish) additionally insert a space
between numerical value and unit. This matches SI recommendations
pushing the worst case to 6 characters.

6 characters will be sufficient for timestamps up to 3 weeks in all
languages (minus prev exceptions), which seems reasonable enough
as beyond this timestamps rarely change anyway.

The aforementioned exceptions being Vietnamese and Occitan,
but in the current localisation all or the relevant short unit
identifiers are identical to the long forms indicating this is
just due to incomplete translation.
Indeed, Vietnamese Wikipedia (read through machine translation) suggests
“ph” is commonly used as unit identifiers for minutes, but the current
localisation fully spells it out as “phút”.
2023-10-25 00:37:09 +02:00
Oneric ccb0ffdc8a Don't show direction in notification timestamps
Currently all notifications except follow-related once include
and explicit direction text. (It missing in follow notifs is due to an
omission in 804ba0cdb6b353e0c959c68f44c6a1316c0d6b10 which only added
the newly introduced with-direction to status-related notifs. Before,
presumably all notifs included direction text.)

But in the notification tray horizontal space is scarce
and notifs can already be assumed to only come from the past.
While it might not be too bad for the English localisation’s 4-letter
' ago' suffix, e.g. the Indonesian localisation’s ' yang lalu' needs
10 letters.

Thus instead of fixing the omission for follow-related notifs,
drop direction text from all notification timestamps.
2023-10-24 23:28:45 +02:00
Oneric ab250c2f3a Explicitly set SameSite attribute for cookies
Modern browsers start to tighten down on third-party access to cookies.
E.g. in current Firefox, a warning about the userLanguage cookie was
shown since it did not yet explicitly set the SameSite attribute and the
default is about to change.

The cookie name being referred to as BACKEND_LANGUAGE_COOKIE_NAME
suggests it should be readable by the actual Akkoma backend, which can
live at a different domain than akkoma-fe. Thus explicitly enable
sharing with third-party sites.

No warnings were shown for other cookies, so I assume
this was the only one not yet setting SameSite.
2023-10-19 01:05:59 +02:00
Norm 1de62fffcd Update config.example.json link and example domain 2023-10-06 04:52:04 -04:00
Norm 306cea04a1 Use corepack in build instructions 2023-10-06 04:51:59 -04:00
Mergan d9e1bc4d99 Re-added extension checking for still-image
- Bonus refactoring
2023-10-02 15:29:54 -07:00
FloatingGhost 52b0b6f008 add VI to messages.js 2023-10-02 13:28:23 +01:00
floatingghost 8afbe5e3bc Merge pull request 'Making still-image better' (#341) from Mergan/pleroma-fe:still-image-ultimate into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/341
2023-09-25 13:29:29 +00:00
floatingghost 58be48d164 Merge pull request 'Do not copy all emojis in recentEmoji getter' (#340) from sn0w/akkoma-fe:feature/optimize-recent-emojis into develop
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma-fe/pulls/340
2023-09-25 13:24:12 +00:00
Mergan 1056b89fd1 Disabled aggressive matching for reduced motion (we search for gif now) 2023-09-12 04:32:01 -07:00
Mergan 3e64d78d05 An oopsie 2023-09-12 04:17:28 -07:00
Mergan 3947aafeba Aligning canvas to image 2023-09-12 04:08:47 -07:00
Mergan 345934c2f3 Make label visible on avatar 2023-09-12 03:37:05 -07:00
Mergan 42a13b0f1b Modify label 2023-09-12 03:35:58 -07:00
Mergan e13c4b6b85 Revamped still-image 2023-09-12 02:48:53 -07:00
sn0w 6a1409e09b Do not copy all emojis in recentEmoji getter 2023-09-03 16:19:06 +02:00
FloatingGhost e7a558a533 Merge branch 'develop' into stable 2023-08-05 14:17:53 +01:00
FloatingGhost 174f98b1cb don't die on my arm box please 2023-08-05 14:17:42 +01:00
177 changed files with 9981 additions and 6529 deletions
-2
View File
@@ -1,2 +0,0 @@
build/*.js
config/*.js
-30
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
}
}
-1
View File
@@ -1 +0,0 @@
7.2.1
+1
View File
@@ -0,0 +1 @@
nodejs 20.12.2
+25 -18
View File
@@ -1,19 +1,21 @@
pipeline: labels:
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
@@ -27,7 +29,7 @@ pipeline:
branch: branch:
- develop - develop
- stable - stable
image: node:18 image: node:20
commands: commands:
- yarn - yarn
- yarn build - yarn build
@@ -39,15 +41,18 @@ pipeline:
branch: branch:
- develop - develop
- stable - stable
image: node:18 image: node:20
secrets: environment:
- SCW_ACCESS_KEY SCW_ACCESS_KEY:
- SCW_SECRET_KEY from_secret: SCW_ACCESS_KEY
- SCW_DEFAULT_ORGANIZATION_ID SCW_SECRET_KEY:
from_secret: SCW_SECRET_KEY
SCW_DEFAULT_ORGANIZATION_ID:
from_secret: SCW_DEFAULT_ORGANIZATION_ID
commands: commands:
- apt-get update && apt-get install -y rclone wget zip - apt-get update && apt-get install -y rclone wget zip
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64 - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.30.0/scaleway-cli_2.30.0_linux_amd64
- mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli - mv scaleway-cli_2.30.0_linux_amd64 scaleway-cli
- chmod +x scaleway-cli - chmod +x scaleway-cli
- ./scaleway-cli object config install type=rclone - ./scaleway-cli object config install type=rclone
- zip akkoma-fe.zip -r dist - zip akkoma-fe.zip -r dist
@@ -62,15 +67,17 @@ pipeline:
- stable - stable
environment: environment:
CI: "true" CI: "true"
SCW_ACCESS_KEY:
from_secret: SCW_ACCESS_KEY
SCW_SECRET_KEY:
from_secret: SCW_SECRET_KEY
SCW_DEFAULT_ORGANIZATION_ID:
from_secret: SCW_DEFAULT_ORGANIZATION_ID
image: python:3.10-slim image: python:3.10-slim
secrets:
- SCW_ACCESS_KEY
- SCW_SECRET_KEY
- SCW_DEFAULT_ORGANIZATION_ID
commands: commands:
- apt-get update && apt-get install -y rclone wget git zip - apt-get update && apt-get install -y rclone wget git zip
- wget https://github.com/scaleway/scaleway-cli/releases/download/v2.5.1/scaleway-cli_2.5.1_linux_amd64 - wget https://github.com/scaleway/scaleway-cli/releases/download/v2.30.0/scaleway-cli_2.30.0_linux_amd64
- mv scaleway-cli_2.5.1_linux_amd64 scaleway-cli - mv scaleway-cli_2.30.0_linux_amd64 scaleway-cli
- chmod +x scaleway-cli - chmod +x scaleway-cli
- ./scaleway-cli object config install type=rclone - ./scaleway-cli object config install type=rclone
- cd docs - cd docs
+4 -2
View File
@@ -20,9 +20,11 @@ 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
npm install -g yarn corepack enable
yarn yarn
# serve with hot reload at localhost:8080 # serve with hot reload at localhost:8080
@@ -37,7 +39,7 @@ npm run unit
# For Contributors: # For Contributors:
You can create file `/config/local.json` (see [example](https://git.pleroma.social/pleroma/pleroma-fe/blob/develop/config/local.example.json)) to enable some convenience dev options: You can create file `/config/local.json` (see [example](https://akkoma.dev/AkkomaGang/akkoma-fe/src/branch/develop/config/local.example.json)) to enable some convenience dev options:
* `target`: makes local dev server redirect to some existing instance's BE instead of local BE, useful for testing things in near-production environment and searching for real-life use-cases. * `target`: makes local dev server redirect to some existing instance's BE instead of local BE, useful for testing things in near-production environment and searching for real-life use-cases.
* `staticConfigPreference`: makes FE's `/static/config.json` take preference of BE-served `/api/statusnet/config.json`. Only works in dev mode. * `staticConfigPreference`: makes FE's `/static/config.json` take preference of BE-served `/api/statusnet/config.json`. Only works in dev mode.
+25 -25
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",
}) );
});
+8 -2
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
+6 -15
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'
})
] ]
} }
+1 -1
View File
@@ -1,4 +1,4 @@
{ {
"target": "https://pleroma.soykaf.com/", "target": "https://otp.akkoma.dev/",
"staticConfigPreference": false "staticConfigPreference": false
} }
-1
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"'
}) })
+3 -2
View File
@@ -15,12 +15,13 @@ put a file that looks like this
```json ```json
{ {
"myPack": "/static/stickers/myPack" "myPack": "/static/stickers/myPack/"
} }
``` ```
This file is a mapping from name to pack directory location. It says "we have a pack called myPack, look for This file is a mapping from name to pack directory location. It says "we have a pack called myPack, look for
it at `/static/stickers/myPack`". You can add as many packs as you like in this manner. it inside `/static/stickers/myPack`". You can add as many packs as you like in this manner.
Note that a single leading and a trailing slash are **required** to work correctly!
## Creating the pack ## Creating the pack
+31
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'
]
}
]
-1
View File
@@ -6,7 +6,6 @@
<title>Akkoma</title> <title>Akkoma</title>
<link rel="stylesheet" href="/static/font/tiresias.css"> <link rel="stylesheet" href="/static/font/tiresias.css">
<link rel="stylesheet" href="/static/font/css/lato.css"> <link rel="stylesheet" href="/static/font/css/lato.css">
<link rel="stylesheet" href="/static/mfm.css">
<link rel="stylesheet" href="/static/custom.css"> <link rel="stylesheet" href="/static/custom.css">
<link rel="stylesheet" href="/static/theme-holder.css" id="theme-holder"> <link rel="stylesheet" href="/static/theme-holder.css" id="theme-holder">
<!--server-generated-meta--> <!--server-generated-meta-->
+81 -83
View File
@@ -1,6 +1,6 @@
{ {
"name": "pleroma_fe", "name": "pleroma_fe",
"version": "3.10.0", "version": "3.12.0",
"description": "A frontend for Akkoma instances", "description": "A frontend for Akkoma instances",
"author": "Roger Braun <roger@rogerbraun.net>", "author": "Roger Braun <roger@rogerbraun.net>",
"private": true, "private": true,
@@ -12,120 +12,118 @@
"e2e": "node test/e2e/runner.js", "e2e": "node test/e2e/runner.js",
"test": "npm run unit && npm run e2e", "test": "npm run unit && npm run e2e",
"stylelint": "stylelint src/**/*.scss", "stylelint": "stylelint src/**/*.scss",
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs", "lint": "eslint src test/unit/specs test/e2e/specs",
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs" "lint-fix": "eslint --fix src test/unit/specs test/e2e/specs"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "7.17.8", "@babel/runtime": "7.17.8",
"@chenfengyuan/vue-qrcode": "2.0.0", "@chenfengyuan/vue-qrcode": "^2.0.0",
"@floatingghost/pinch-zoom-element": "^1.3.1", "@floatingghost/pinch-zoom-element": "^1.3.1",
"@fortawesome/fontawesome-svg-core": "1.3.0", "@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-regular-svg-icons": "^6.1.2", "@fortawesome/free-regular-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.2.0", "@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/vue-fontawesome": "3.0.1", "@fortawesome/vue-fontawesome": "^3.0.8",
"@vuelidate/core": "^2.0.0", "@vuelidate/core": "^2.0.3",
"@vuelidate/validators": "^2.0.0", "@vuelidate/validators": "^2.0.4",
"blurhash": "^2.0.4", "blurhash": "^2.0.5",
"body-scroll-lock": "2.7.1", "body-scroll-lock": "^3.1.5",
"chromatism": "3.0.0", "chromatism": "^3.0.0",
"click-outside-vue3": "4.0.1", "click-outside-vue3": "^4.0.1",
"cropperjs": "1.5.12", "cropperjs": "^1.6.2",
"diff": "3.5.0", "diff": "^5.2.0",
"escape-html": "1.0.3", "escape-html": "^1.0.3",
"iso-639-1": "^2.1.15", "iso-639-1": "^2.1.15",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.1",
"localforage": "1.10.0", "localforage": "^1.10.0",
"parse-link-header": "^2.0.0", "parse-link-header": "^2.0.0",
"phoenix": "1.6.2", "phoenix": "^1.7.12",
"punycode.js": "2.1.0", "punycode.js": "^2.3.1",
"qrcode": "1", "qrcode": "^1.5.3",
"url": "^0.11.0", "querystring-es3": "^0.2.1",
"vue": "^3.2.31", "url": "^0.11.3",
"vue-i18n": "^9.2.2", "vue": "^3.4.38",
"vue-router": "4.0.14", "vue-i18n": "^9.14.0",
"vue-template-compiler": "2.6.11", "vue-router": "^4.4.3",
"vuex": "4.0.2" "vue-template-compiler": "^2.7.16",
"vuex": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.17.8", "@babel/core": "^7.24.6",
"@babel/eslint-parser": "^7.19.1", "@babel/eslint-parser": "^7.19.1",
"@babel/plugin-transform-runtime": "7.17.0", "@babel/plugin-transform-runtime": "^7.24.6",
"@babel/preset-env": "7.16.11", "@babel/preset-env": "^7.24.6",
"@babel/register": "7.17.7", "@babel/register": "^7.24.6",
"@intlify/vue-i18n-loader": "^5.0.0", "@intlify/vue-i18n-loader": "^5.0.0",
"@ungap/event-target": "0.2.3", "@ungap/event-target": "^0.2.4",
"@vue/babel-helper-vue-jsx-merge-props": "1.2.1", "@vue/babel-helper-vue-jsx-merge-props": "^1.4.0",
"@vue/babel-plugin-jsx": "1.1.1", "@vue/babel-plugin-jsx": "^1.2.2",
"@vue/compiler-sfc": "^3.1.0", "@vue/compiler-sfc": "^3.1.0",
"@vue/test-utils": "^2.0.2", "@vue/test-utils": "^2.0.2",
"autoprefixer": "6.7.7", "autoprefixer": "^10.4.19",
"babel-loader": "^9.1.0", "babel-loader": "^9.1.0",
"babel-plugin-lodash": "3.3.4", "babel-plugin-lodash": "^3.3.4",
"chai": "^4.3.7", "chai": "^4.3.7",
"chalk": "1.1.3", "chalk": "^1.1.3",
"chromedriver": "^107.0.3", "chromedriver": "^119.0.1",
"connect-history-api-fallback": "^2.0.0", "connect-history-api-fallback": "^2.0.0",
"cross-spawn": "^7.0.3", "cross-spawn": "^7.0.3",
"css-loader": "^6.7.2", "css-loader": "^7.1.2",
"custom-event-polyfill": "^1.0.7", "custom-event-polyfill": "^1.0.7",
"eslint": "^7.32.0", "eslint": "^9.3.0",
"eslint-config-standard": "^17.0.0", "eslint-config-standard": "^17.1.0",
"eslint-friendly-formatter": "^4.0.1", "eslint-friendly-formatter": "^4.0.1",
"eslint-loader": "^4.0.2", "eslint-plugin-import": "^2.29.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^6.2.0",
"eslint-plugin-standard": "^5.0.0", "eslint-plugin-standard": "^5.0.0",
"eslint-plugin-vue": "^9.7.0", "eslint-plugin-vue": "^9.26.0",
"eventsource-polyfill": "0.9.6", "eslint-webpack-plugin": "^4.2.0",
"express": "4.17.3", "eventsource-polyfill": "^0.9.6",
"express": "^4.19.2",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"function-bind": "1.1.1", "function-bind": "^1.1.2",
"html-webpack-plugin": "^5.5.0", "html-webpack-plugin": "^5.5.0",
"http-proxy-middleware": "0.21.0", "http-proxy-middleware": "^3.0.0",
"inject-loader": "2.0.1", "json-loader": "^0.5.7",
"isparta-loader": "2.0.0", "karma": "^6.4.3",
"json-loader": "0.5.7", "karma-coverage": "^2.2.1",
"karma": "6.3.17", "karma-firefox-launcher": "^2.1.3",
"karma-coverage": "1.1.2", "karma-mocha": "^2.0.1",
"karma-firefox-launcher": "1.3.0", "karma-mocha-reporter": "^2.2.5",
"karma-mocha": "2.0.1", "karma-sinon-chai": "^2.0.2",
"karma-mocha-reporter": "2.2.5", "karma-sourcemap-loader": "^0.4.0",
"karma-sinon-chai": "2.0.2", "karma-spec-reporter": "^0.0.36",
"karma-sourcemap-loader": "0.3.8",
"karma-spec-reporter": "0.0.33",
"karma-webpack": "^5.0.0", "karma-webpack": "^5.0.0",
"lodash": "4.17.21", "lodash": "^4.17.21",
"lolex": "1.6.0", "lolex": "^6.0.0",
"mini-css-extract-plugin": "0.12.0", "mini-css-extract-plugin": "^2.9.0",
"mocha": "3.5.3", "mocha": "^10.4.0",
"nightwatch": "0.9.21", "nightwatch": "^3.6.3",
"opn": "4.0.2", "opn": "^6.0.0",
"ora": "0.4.1",
"postcss-html": "^1.5.0", "postcss-html": "^1.5.0",
"postcss-loader": "3.0.0", "postcss-loader": "^8.1.1",
"postcss-sass": "^0.5.0", "postcss-sass": "^0.5.0",
"raw-loader": "0.5.1", "raw-loader": "^4.0.2",
"sass": "^1.56.0", "sass": "^1.77.2",
"sass-loader": "^13.2.0", "sass-loader": "^14.2.1",
"selenium-server": "2.53.1", "selenium-server": "^3.141.59",
"semver": "5.7.1", "semver": "^7.6.2",
"shelljs": "0.8.5", "shelljs": "^0.8.5",
"sinon": "2.4.1", "sinon": "^18.0.0",
"sinon-chai": "2.14.0", "sinon-chai": "^3.7.0",
"stylelint": "^14.15.0", "stylelint": "^14.15.0",
"stylelint-config-recommended-vue": "^1.4.0", "stylelint-config-recommended-vue": "^1.4.0",
"stylelint-config-standard": "^29.0.0", "stylelint-config-standard": "^29.0.0",
"stylelint-config-standard-scss": "^6.1.0", "stylelint-config-standard-scss": "^6.1.0",
"stylelint-rscss": "^0.4.0", "stylelint-rscss": "^0.4.0",
"url-loader": "^4.1.1", "url-loader": "^4.1.1",
"vue-loader": "^17.0.0", "vue-loader": "^17.4.2",
"vue-style-loader": "^4.1.2", "vue-style-loader": "^4.1.3",
"webpack": "^5.75.0", "webpack": "^5.91.0",
"webpack-dev-middleware": "^5.3.3", "webpack-dev-middleware": "^7.2.1",
"webpack-hot-middleware": "^2.25.1", "webpack-hot-middleware": "^2.26.1",
"webpack-merge": "^5.8.0", "webpack-merge": "^5.10.0",
"workbox-webpack-plugin": "^6.5.4" "workbox-webpack-plugin": "^7.1.0"
}, },
"engines": { "engines": {
"node": ">= 16.0.0", "node": ">= 16.0.0",
+11 -2
View File
@@ -59,11 +59,17 @@ export default {
{ {
'-reverse': this.reverseLayout, '-reverse': this.reverseLayout,
'-no-sticky-headers': this.noSticky, '-no-sticky-headers': this.noSticky,
'-has-new-post-button': this.newPostButtonShown '-has-new-post-button': this.newPostButtonShown,
'-wide-timeline': this.widenTimeline
}, },
'-' + this.layoutType '-' + this.layoutType
] ]
}, },
pageBackground () {
return this.mergedConfig.displayPageBackgrounds
? this.$store.state.users.displayBackground
: null
},
currentUser () { return this.$store.state.users.currentUser }, currentUser () { return this.$store.state.users.currentUser },
userBackground () { return this.currentUser.background_image }, userBackground () { return this.currentUser.background_image },
instanceBackground () { instanceBackground () {
@@ -71,7 +77,7 @@ export default {
? null ? null
: this.$store.state.instance.background : this.$store.state.instance.background
}, },
background () { return this.userBackground || this.instanceBackground }, background () { return this.pageBackground || this.userBackground || this.instanceBackground },
bgStyle () { bgStyle () {
if (this.background) { if (this.background) {
return { return {
@@ -88,6 +94,9 @@ export default {
newPostButtonShown () { newPostButtonShown () {
return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile' return this.$store.getters.mergedConfig.alwaysShowNewPostButton || this.layoutType === 'mobile'
}, },
widenTimeline () {
return this.$store.getters.mergedConfig.widenTimeline
},
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel }, showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
editingAvailable () { return this.$store.state.instance.editingAvailable }, editingAvailable () { return this.$store.state.instance.editingAvailable },
layoutType () { return this.$store.state.interface.layoutType }, layoutType () { return this.$store.state.interface.layoutType },
+10 -1
View File
@@ -8,7 +8,7 @@
} }
html { html {
font-size: 14px; font-size: 0.875rem;
// overflow-x: clip causes my browser's tab to crash with SIGILL lul // overflow-x: clip causes my browser's tab to crash with SIGILL lul
} }
@@ -172,6 +172,10 @@ nav {
background-color: rgba(0, 0, 0, 0.15); background-color: rgba(0, 0, 0, 0.15);
background-color: var(--underlay, rgba(0, 0, 0, 0.15)); background-color: var(--underlay, rgba(0, 0, 0, 0.15));
z-index: -1000; z-index: -1000;
.-wide-timeline & {
margin:0 calc(var(--columnGap) / -2);
}
} }
.app-layout { .app-layout {
@@ -187,12 +191,17 @@ nav {
grid-template-rows: 1fr; grid-template-rows: 1fr;
box-sizing: border-box; box-sizing: border-box;
margin: 0 auto; margin: 0 auto;
padding: 0 calc(var(--columnGap) / 2);
align-content: flex-start; align-content: flex-start;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
min-height: 100vh; min-height: 100vh;
overflow-x: clip; overflow-x: clip;
&.-wide-timeline {
--maxiColumn: minmax(var(--miniColumn), 1fr);
}
.column { .column {
--___columnMargin: var(--columnGap); --___columnMargin: var(--columnGap);
+6
View File
@@ -183,6 +183,12 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
copyInstanceOption('renderMisskeyMarkdown') copyInstanceOption('renderMisskeyMarkdown')
copyInstanceOption('sidebarRight') copyInstanceOption('sidebarRight')
if (config.backendCommitUrl)
copyInstanceOption('backendCommitUrl')
if (config.frontendCommitUrl)
copyInstanceOption('frontendCommitUrl')
return store.dispatch('setTheme', config['theme']) return store.dispatch('setTheme', config['theme'])
} }
+1 -1
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>
@@ -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"
/> />
+23 -2
View File
@@ -16,9 +16,14 @@
.attachment-wrapper { .attachment-wrapper {
flex: 1 1 auto; flex: 1 1 auto;
height: 200px; min-height: 200px;
position: relative; position: relative;
overflow: hidden; overflow: hidden;
align-content: center;
.status-popover & {
height: 200px;
}
} }
.description-container { .description-container {
@@ -37,7 +42,7 @@
white-space: pre-line; white-space: pre-line;
word-break: break-word; word-break: break-word;
text-overflow: ellipsis; text-overflow: ellipsis;
overflow: scroll; overflow: auto;
} }
&.-static { &.-static {
@@ -115,6 +120,22 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding-top: 0.5em; padding-top: 0.5em;
p {
line-height: 1.5;
padding: 0 0.5em;
white-space: pre-line;
text-align: center;
max-height: 200px;
overflow-y: auto;
scrollbar-color: var(--border) #0000;
.status-popover & {
text-overflow: ellipsis;
overflow: hidden;
height: 1lh;
}
}
} }
+2 -2
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>
+1 -1
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';
+2 -2
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>
+2 -2
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 {
@@ -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>
+11 -3
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({
@@ -414,6 +414,14 @@ const conversation = {
}, },
toggleExpanded () { toggleExpanded () {
this.expanded = !this.expanded this.expanded = !this.expanded
const navHeight = document.getElementById("nav").offsetHeight
const headingHeight = document.getElementsByClassName("timeline-heading")[0].offsetHeight
document.documentElement.style.setProperty("--timeline-scroll-margin-top", `${navHeight + headingHeight}px`)
this.$nextTick(() => {
if (!this.expanded) {
this.$el.scrollIntoView({ block: 'nearest' })
}
})
}, },
getConversationId (statusId) { getConversationId (statusId) {
const status = this.$store.state.statuses.allStatusesObject[statusId] const status = this.$store.state.statuses.allStatusesObject[statusId]
+4 -2
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>
@@ -278,5 +278,7 @@
&.-expanded.status-fadein { &.-expanded.status-fadein {
margin: calc(var(--status-margin, $status-margin) / 2); margin: calc(var(--status-margin, $status-margin) / 2);
} }
scroll-margin-block-start: var(--timeline-scroll-margin-top);
} }
</style> </style>
+2 -2
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
@@ -9,7 +9,7 @@
class="btn button-default" class="btn button-default"
> >
{{ $t('domain_mute_card.unmute') }} {{ $t('domain_mute_card.unmute') }}
<template v-slot:progress> <template #progress>
{{ $t('domain_mute_card.unmute_progress') }} {{ $t('domain_mute_card.unmute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
@@ -19,7 +19,7 @@
class="btn button-default" class="btn button-default"
> >
{{ $t('domain_mute_card.mute') }} {{ $t('domain_mute_card.mute') }}
<template v-slot:progress> <template #progress>
{{ $t('domain_mute_card.mute_progress') }} {{ $t('domain_mute_card.mute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
@@ -2,7 +2,7 @@
<Modal <Modal
v-if="isFormVisible" v-if="isFormVisible"
class="edit-form-modal-view" class="edit-form-modal-view"
@backdropClicked="closeModal" @backdrop-clicked="closeModal"
> >
<div class="edit-form-modal-panel panel"> <div class="edit-form-modal-panel panel">
<div class="panel-heading"> <div class="panel-heading">
@@ -11,10 +11,10 @@
<PostStatusForm <PostStatusForm
class="panel-body" class="panel-body"
v-bind="params" v-bind="params"
@posted="closeModal" :disable-polls="true"
:disablePolls="true" :disable-visibility-selector="true"
:disableVisibilitySelector="true"
:post-handler="doEditStatus" :post-handler="doEditStatus"
@posted="closeModal"
/> />
</div> </div>
</Modal> </Modal>
+5
View File
@@ -1,3 +1,5 @@
import StillImage from '../still-image/still-image.vue'
const EMOJI_SIZE = 32 + 8 const EMOJI_SIZE = 32 + 8
const GROUP_TITLE_HEIGHT = 24 const GROUP_TITLE_HEIGHT = 24
const BUFFER_SIZE = 3 * EMOJI_SIZE const BUFFER_SIZE = 3 * EMOJI_SIZE
@@ -17,6 +19,9 @@ const EmojiGrid = {
resizeObserver: null resizeObserver: null
} }
}, },
components: {
StillImage
},
mounted () { mounted () {
const rect = this.$refs.container.getBoundingClientRect() const rect = this.$refs.container.getBoundingClientRect()
this.containerWidth = rect.width this.containerWidth = rect.width
+3 -2
View File
@@ -34,10 +34,11 @@
@click.stop.prevent="onEmoji(item.emoji)" @click.stop.prevent="onEmoji(item.emoji)"
> >
<span v-if="!item.emoji.imageUrl">{{ item.emoji.replacement }}</span> <span v-if="!item.emoji.imageUrl">{{ item.emoji.replacement }}</span>
<img <StillImage
v-else v-else
:src="item.emoji.imageUrl" :src="item.emoji.imageUrl"
> noStopGifs="true"
/>
</span> </span>
</template> </template>
</div> </div>
+3 -1
View File
@@ -1,5 +1,6 @@
import Completion from '../../services/completion/completion.js' import Completion from '../../services/completion/completion.js'
import EmojiPicker from '../emoji_picker/emoji_picker.vue' import EmojiPicker from '../emoji_picker/emoji_picker.vue'
import StillImage from '../still-image/still-image.vue'
import { take } from 'lodash' import { take } from 'lodash'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
@@ -120,7 +121,8 @@ const EmojiInput = {
} }
}, },
components: { components: {
EmojiPicker EmojiPicker,
StillImage
}, },
computed: { computed: {
padEmoji () { padEmoji () {
+8 -3
View File
@@ -20,6 +20,7 @@
ref="picker" ref="picker"
show-keep-open show-keep-open
:class="{ hide: !showPicker }" :class="{ hide: !showPicker }"
:visible="showPicker"
:enable-sticker-picker="enableStickerPicker" :enable-sticker-picker="enableStickerPicker"
class="emoji-picker-panel" class="emoji-picker-panel"
@emoji="insert" @emoji="insert"
@@ -43,11 +44,15 @@
:class="{ highlighted: index === highlighted }" :class="{ highlighted: index === highlighted }"
@click.stop.prevent="onClick($event, suggestion)" @click.stop.prevent="onClick($event, suggestion)"
> >
<span v-if="!suggestion.mfm" class="image"> <span
<img v-if="!suggestion.mfm"
class="image"
>
<StillImage
v-if="suggestion.img" v-if="suggestion.img"
:src="suggestion.img" :src="suggestion.img"
> noStopGifs="true"
/>
<span v-else>{{ suggestion.replacement }}</span> <span v-else>{{ suggestion.replacement }}</span>
</span> </span>
<div class="label"> <div class="label">
+3 -3
View File
@@ -1,4 +1,4 @@
const MFM_TAGS = ['blur', 'bounce', 'flip', 'font', 'jelly', 'jump', 'rainbow', 'rotate', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4'] const MFM_TAGS = ['bg', 'blur', 'bounce', 'center', 'fg', 'flip', 'font', 'jelly', 'jump', 'position', 'rainbow', 'rotate', 'scale', 'shake', 'sparkle', 'spin', 'tada', 'twitch', 'x2', 'x3', 'x4']
.map(tag => ({ displayText: tag, detailText: '$[' + tag + ' ]', replacement: '$[' + tag + ' ]', mfm: true })) .map(tag => ({ displayText: tag, detailText: '$[' + tag + ' ]', replacement: '$[' + tag + ' ]', mfm: true }))
/** /**
@@ -122,14 +122,14 @@ export const suggestUsers = ({ dispatch, state }) => {
const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1 const screenNameAlphabetically = a.screen_name > b.screen_name ? 1 : -1
return diff + nameAlphabetically + screenNameAlphabetically return diff + nameAlphabetically + screenNameAlphabetically
/* eslint-disable camelcase */
}).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({ }).map(({ screen_name, screen_name_ui, name, profile_image_url_original }) => ({
displayText: screen_name_ui, displayText: screen_name_ui,
detailText: name, detailText: name,
imageUrl: profile_image_url_original, imageUrl: profile_image_url_original,
replacement: '@' + screen_name + ' ' replacement: '@' + screen_name + ' '
})) }))
/* eslint-enable camelcase */
suggestions = newSuggestions || [] suggestions = newSuggestions || []
return suggestions return suggestions
+21 -2
View File
@@ -1,6 +1,7 @@
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
import Checkbox from '../checkbox/checkbox.vue' import Checkbox from '../checkbox/checkbox.vue'
import EmojiGrid from '../emoji_grid/emoji_grid.vue' import EmojiGrid from '../emoji_grid/emoji_grid.vue'
import StillImage from '../still-image/still-image.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
faBoxOpen, faBoxOpen,
@@ -26,12 +27,17 @@ const EmojiPicker = {
required: false, required: false,
type: Boolean, type: Boolean,
default: false default: false
},
visible: {
required: false,
type: Boolean,
default: true
} }
}, },
data () { data () {
return { return {
keyword: '', keyword: '',
activeGroup: 'standard', activeGroup: this.getDefaultGroup(),
showingStickers: false, showingStickers: false,
keepOpen: false keepOpen: false
} }
@@ -39,7 +45,8 @@ const EmojiPicker = {
components: { components: {
StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')), StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')),
Checkbox, Checkbox,
EmojiGrid EmojiGrid,
StillImage
}, },
methods: { methods: {
debouncedSearch: debounce(function (e) { debouncedSearch: debounce(function (e) {
@@ -82,6 +89,11 @@ const EmojiPicker = {
return list.filter(emoji => { return list.filter(emoji => {
return (regex.test(emoji.displayText) || (!emoji.imageUrl && emoji.replacement === this.keyword)) return (regex.test(emoji.displayText) || (!emoji.imageUrl && emoji.replacement === this.keyword))
}) })
},
getDefaultGroup () {
if (!this.visible) return null
const recentEmojis = this.$store.getters.recentEmojis
return recentEmojis.length === 0 ? 'standard' : 'recent'
} }
}, },
computed: { computed: {
@@ -148,6 +160,13 @@ const EmojiPicker = {
stickerPickerEnabled () { stickerPickerEnabled () {
return (this.$store.state.instance.stickers || []).length !== 0 && this.enableStickerPicker return (this.$store.state.instance.stickers || []).length !== 0 && this.enableStickerPicker
} }
},
watch: {
visible (val, oldVal) {
if (val && this.activeGroup === null) {
this.activeGroup = this.getDefaultGroup()
}
}
} }
} }
+3 -2
View File
@@ -18,10 +18,11 @@
@click.prevent="highlight(group.id)" @click.prevent="highlight(group.id)"
> >
<span v-if="!group.first.imageUrl">{{ group.first.replacement }}</span> <span v-if="!group.first.imageUrl">{{ group.first.replacement }}</span>
<img <StillImage
v-else v-else
:src="group.first.imageUrl" :src="group.first.imageUrl"
> noStopGifs="true"
/>
</span> </span>
<span <span
v-if="stickerPickerEnabled" v-if="stickerPickerEnabled"
@@ -11,7 +11,7 @@
@click="emojiOnClick(reaction.name, $event)" @click="emojiOnClick(reaction.name, $event)"
@mouseenter="fetchEmojiReactionsByIfMissing()" @mouseenter="fetchEmojiReactionsByIfMissing()"
> >
<span <template
v-if="reaction.url !== null" v-if="reaction.url !== null"
> >
<StillImage <StillImage
@@ -19,16 +19,15 @@
:title="reaction.name" :title="reaction.name"
:alt="reaction.name" :alt="reaction.name"
class="reaction-emoji" class="reaction-emoji"
height="2.55em"
/> />
{{ reaction.count }} {{ reaction.count }}
</span> </template>
<span v-else> <template v-else>
<span class="reaction-emoji unicode-emoji"> <span class="reaction-emoji unicode-emoji">
{{ reaction.name }} {{ reaction.name }}
</span> </span>
<span>{{ reaction.count }}</span> <span>{{ reaction.count }}</span>
</span> </template>
</button> </button>
</UserListPopover> </UserListPopover>
<a <a
@@ -42,7 +41,7 @@
</div> </div>
</template> </template>
<script src="./emoji_reactions.js" ></script> <script src="./emoji_reactions.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
@@ -53,23 +52,26 @@
container-type: inline-size; container-type: inline-size;
} }
.unicode-emoji {
font-size: 210%;
}
.emoji-reaction { .emoji-reaction {
padding: 0 0.5em; padding: 2px 0.5em;
margin-right: 0.5em; margin-right: 0.5em;
margin-top: 0.5em; margin-top: 0.5em;
display: flex; display: flex;
align-items: center; align-items: end;
justify-content: center;
box-sizing: border-box;
.reaction-emoji { .reaction-emoji {
width: auto; width: auto;
max-width: 96cqw; max-width: 96cqw;
height: 2.55em !important;
margin-right: 0.25em; margin-right: 0.25em;
&.still-image {
height: 2.55em;
}
&.unicode-emoji {
display: inline-block;
font-size: 2.125em; // assuming default line height of 1.2rem and emojis that don't exceed line height
line-height: 2.55rem;
}
} }
&:focus { &:focus {
outline: none; outline: none;
@@ -97,9 +99,9 @@
} }
.button-default.picked-reaction { .button-default.picked-reaction {
border: 1px solid var(--accent, $fallback--link); &, &:hover {
margin-left: -1px; // offset the border, can't use inset shadows either box-shadow: inset 0 0 0 1px var(--accent, $fallback--link);
margin-right: calc(0.5em - 1px); }
} }
</style> </style>
@@ -7,7 +7,7 @@
:bound-to="{ x: 'container' }" :bound-to="{ x: 'container' }"
remove-padding remove-padding
> >
<template v-slot:content="{close}"> <template #content="{close}">
<div class="dropdown-menu"> <div class="dropdown-menu">
<button <button
v-if="canMute && !status.thread_muted" v-if="canMute && !status.thread_muted"
@@ -172,7 +172,7 @@
</button> </button>
</div> </div>
</template> </template>
<template v-slot:trigger> <template #trigger>
<button class="button-unstyled popover-trigger"> <button class="button-unstyled popover-trigger">
<FAIcon <FAIcon
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"
@@ -205,7 +205,7 @@
</Popover> </Popover>
</template> </template>
<script src="./extra_buttons.js" ></script> <script src="./extra_buttons.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
@@ -35,7 +35,7 @@
</div> </div>
</template> </template>
<script src="./favorite_button.js" ></script> <script src="./favorite_button.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
@@ -23,7 +23,7 @@
</div> </div>
</template> </template>
<script src="./features_panel.js" ></script> <script src="./features_panel.js"></script>
<style lang="scss"> <style lang="scss">
.features-panel li { .features-panel li {
@@ -1,5 +1,8 @@
<template> <template>
<basic-user-card :user="user" v-if="show"> <basic-user-card
v-if="show"
:user="user"
>
<div class="follow-request-card-content-container"> <div class="follow-request-card-content-container">
<button <button
class="btn button-default" class="btn button-default"
+1 -1
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';
+2 -4
View File
@@ -88,10 +88,8 @@ const Gallery = {
set(this.sizes, id, { width, height }) set(this.sizes, id, { width, height })
}, },
rowStyle (row) { rowStyle (row) {
if (row.audio) { if (!row.audio && !row.minimal && !row.grid) {
return { 'padding-bottom': '25%' } // fixed reduced height for audio return { 'aspect-ratio': `1/${(1 / (row.items.length + 0.6))}` }
} else if (!row.minimal && !row.grid) {
return { 'padding-bottom': `${(100 / (row.items.length + 0.6))}%` }
} }
}, },
itemStyle (id, row) { itemStyle (id, row) {
+9 -3
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>
@@ -96,9 +96,15 @@
.gallery-row { .gallery-row {
position: relative; position: relative;
height: 0;
width: 100%; width: 100%;
flex-grow: 1; flex-grow: 1;
.Status & {
max-height: 30em;
}
&.-audio {
aspect-ratio: 4/1; // this is terrible, but it's how it was before so I'm not changing it >:(
}
&:not(:first-child) { &:not(:first-child) {
margin-top: 0.5em; margin-top: 0.5em;
+2 -2
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" />
@@ -10,4 +10,4 @@
</div> </div>
</template> </template>
<script src="./instance_specific_panel.js" ></script> <script src="./instance_specific_panel.js"></script>
+1
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;
@@ -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"
+1 -1
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';
+4 -3
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'"
@@ -24,14 +24,15 @@
:min-scale="pinchZoomMinScale" :min-scale="pinchZoomMinScale"
:reset-to-min-scale-limit="pinchZoomScaleResetLimit" :reset-to-min-scale-limit="pinchZoomScaleResetLimit"
> >
<img <StillImage
:class="{ loading }" :class="{ loading }"
class="modal-image" class="modal-image"
:src="currentMedia.url" :src="currentMedia.url"
:alt="currentMedia.description" :alt="currentMedia.description"
:title="currentMedia.description" :title="currentMedia.description"
@load="onImageLoaded" @load="onImageLoaded"
> noStopGifs="true"
/>
</PinchZoom> </PinchZoom>
</SwipeClick> </SwipeClick>
<VideoAttachment <VideoAttachment
+1 -1
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()
}) })
+1 -1
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';
@@ -93,9 +93,6 @@ const MentionLink = {
this.highlightType this.highlightType
] ]
}, },
useAtIcon () {
return this.mergedConfig.useAtIcon
},
isRemote () { isRemote () {
return this.userName !== this.userNameFull return this.userName !== this.userNameFull
}, },
+2 -2
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" />
@@ -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" />
+1 -1
View File
@@ -69,4 +69,4 @@
</div> </div>
</div> </div>
</template> </template>
<script src="./recovery_form.js" ></script> <script src="./recovery_form.js"></script>
+1
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>
@@ -4,7 +4,7 @@
class="panel-heading" class="panel-heading"
@click="toggleHidden" @click="toggleHidden"
> >
<h4>{{ $t('moderation.reports.report') + ' ' + this.account.screen_name }}</h4> <h4>{{ $t('moderation.reports.report') + ' ' + account.screen_name }}</h4>
<button <button
v-if="isOpen" v-if="isOpen"
class="button-default" class="button-default"
@@ -35,7 +35,10 @@
<div v-if="content"> <div v-if="content">
{{ decode(content) }} {{ decode(content) }}
</div> </div>
<i v-else class="faint"> <i
v-else
class="faint"
>
{{ $t('moderation.reports.no_content') }} {{ $t('moderation.reports.no_content') }}
</i> </i>
<div class="report-author"> <div class="report-author">
@@ -43,12 +46,12 @@
class="small-avatar" class="small-avatar"
:user="actor" :user="actor"
/> />
{{ this.actor.screen_name }} {{ actor.screen_name }}
</div> </div>
</div> </div>
<div <div
v-if="!hidden && statuses.length > 0"
class="dropdown" class="dropdown"
v-if="!hidden && this.statuses.length > 0"
> >
<button <button
class="button button-unstyled dropdown-header" class="button button-unstyled dropdown-header"
@@ -74,8 +77,8 @@
</div> </div>
</div> </div>
<div <div
v-if="!hidden && notes.length > 0"
class="dropdown" class="dropdown"
v-if="!hidden && this.notes.length > 0"
> >
<button <button
class="button button-unstyled dropdown-header" class="button button-unstyled dropdown-header"
@@ -99,9 +102,9 @@
</div> </div>
<div class="report-add-note"> <div class="report-add-note">
<textarea <textarea
v-model.trim="note"
rows="1" rows="1"
cols="1" cols="1"
v-model.trim="note"
:placeholder="$t('moderation.reports.note_placeholder')" :placeholder="$t('moderation.reports.note_placeholder')"
/> />
<button <button
@@ -134,7 +137,7 @@
:offset="{ y: 5 }" :offset="{ y: 5 }"
remove-padding remove-padding
> >
<template v-slot:trigger> <template #trigger>
<button <button
class="btn button-default" class="btn button-default"
:disabled="!tagPolicyEnabled" :disabled="!tagPolicyEnabled"
@@ -147,7 +150,7 @@
/> />
</button> </button>
</template> </template>
<template v-slot:content="{close}"> <template #content="{close}">
<div <div
class="dropdown-menu" class="dropdown-menu"
:disabled="!tagPolicyEnabled" :disabled="!tagPolicyEnabled"
@@ -6,7 +6,7 @@
class="small-avatar" class="small-avatar"
:user="user" :user="user"
/> />
{{ this.user.screen_name }} {{ user.screen_name }}
</div> </div>
<div class="header-right"> <div class="header-right">
<Timeago <Timeago
+3
View File
@@ -22,6 +22,9 @@ export default {
default: false default: false
} }
}, },
emits: [
'backdropClicked',
],
computed: { computed: {
classes () { classes () {
return { return {
@@ -8,7 +8,7 @@
@show="setToggled(true)" @show="setToggled(true)"
@close="setToggled(false)" @close="setToggled(false)"
> >
<template v-slot:content> <template #content>
<div class="dropdown-menu"> <div class="dropdown-menu">
<span v-if="user.is_local"> <span v-if="user.is_local">
<button <button
@@ -122,7 +122,7 @@
</span> </span>
</div> </div>
</template> </template>
<template v-slot:trigger> <template #trigger>
<button <button
class="btn button-default btn-block moderation-tools-button" class="btn button-default btn-block moderation-tools-button"
:class="{ toggled }" :class="{ toggled }"
@@ -137,11 +137,11 @@
v-if="showDeleteUserDialog" v-if="showDeleteUserDialog"
:on-cancel="deleteUserDialog.bind(this, false)" :on-cancel="deleteUserDialog.bind(this, false)"
> >
<template v-slot:header> <template #header>
{{ $t('user_card.admin_menu.delete_user') }} {{ $t('user_card.admin_menu.delete_user') }}
</template> </template>
<p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p> <p>{{ $t('user_card.admin_menu.delete_user_confirmation') }}</p>
<template v-slot:footer> <template #footer>
<button <button
class="btn button-default" class="btn button-default"
@click="deleteUserDialog(false)" @click="deleteUserDialog(false)"
+1 -1
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';
+3 -1
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 () {
@@ -101,4 +101,8 @@
color: $fallback--cBlue; color: $fallback--cBlue;
color: var(--cBlue, $fallback--cBlue); color: var(--cBlue, $fallback--cBlue);
} }
.attachment-wrapper {
min-height: unset;
}
} }
+4 -4
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"
@@ -151,7 +152,6 @@
> >
<Timeago <Timeago
:time="notification.created_at" :time="notification.created_at"
:with-direction="true"
:auto-update="240" :auto-update="240"
/> />
</router-link> </router-link>
@@ -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>
@@ -105,9 +105,12 @@
flex: 1; flex: 1;
padding-left: 0.8em; padding-left: 0.8em;
min-width: 0; min-width: 0;
}
.heading-right, .notification-right {
.timeago { .timeago {
min-width: 3em; display: inline-block;
min-width: 6em;
text-align: right; text-align: right;
} }
} }
@@ -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"
-1
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>
+10 -2
View File
@@ -50,6 +50,13 @@ export default {
totalVotesCount () { totalVotesCount () {
return this.poll.votes_count return this.poll.votes_count
}, },
totalFractionBase () {
// Due to a backend bug, we might not have any voter count info for remote polls
// in this case, fall back to count of votes even for multiple cjoice polls
// to be able to at least display _something_
const total_base = this.poll.multiple ? this.poll.voters_count : this.poll.votes_count
return total_base > 0 ? total_base : this.poll.votes_count
},
containerClass () { containerClass () {
return { return {
loading: this.loading loading: this.loading
@@ -70,10 +77,11 @@ export default {
}, },
methods: { methods: {
percentageForOption (count) { percentageForOption (count) {
return this.totalVotesCount === 0 ? 0 : Math.round(count / this.totalVotesCount * 100) const total = this.totalFractionBase
return total === 0 ? 0 : Math.round(count / total * 100)
}, },
resultTitle (option) { resultTitle (option) {
return `${option.votes_count}/${this.totalVotesCount} ${this.$t('polls.votes')}` return `${option.votes_count}/${this.totalFractionBase} ${this.$t('polls.votes')}`
}, },
fetchPoll () { fetchPoll () {
this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id }) this.$store.dispatch('refreshPoll', { id: this.statusId, pollId: this.poll.id })
+2
View File
@@ -24,6 +24,7 @@
<button <button
v-if="options.length > 2" v-if="options.length > 2"
class="delete-option button-unstyled -hover-highlight" class="delete-option button-unstyled -hover-highlight"
type="button"
@click="deleteOption(index)" @click="deleteOption(index)"
> >
<FAIcon icon="times" /> <FAIcon icon="times" />
@@ -32,6 +33,7 @@
<button <button
v-if="options.length < maxOptions" v-if="options.length < maxOptions"
class="add-option faint button-unstyled -hover-highlight" class="add-option faint button-unstyled -hover-highlight"
type="button"
@click="addOption" @click="addOption"
> >
<FAIcon <FAIcon
@@ -9,11 +9,13 @@ import StatusContent from '../status_content/status_content.vue'
import fileTypeService from '../../services/file_type/file_type.service.js' import fileTypeService from '../../services/file_type/file_type.service.js'
import { findOffset } from '../../services/offset_finder/offset_finder.service.js' import { findOffset } from '../../services/offset_finder/offset_finder.service.js'
import { reject, map, uniqBy, debounce } from 'lodash' import { reject, map, uniqBy, debounce } from 'lodash'
import { usePostLanguageOptions } from 'src/lib/post_language'
import scopeUtils from 'src/lib/scope_utils.js'
import suggestor from '../emoji_input/suggestor.js' import suggestor from '../emoji_input/suggestor.js'
import { mapGetters, mapState } from 'vuex' import { mapGetters, mapState } from 'vuex'
import Checkbox from '../checkbox/checkbox.vue' import Checkbox from '../checkbox/checkbox.vue'
import Select from '../select/select.vue' import Select from '../select/select.vue'
import iso6391 from 'iso-639-1'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@@ -62,6 +64,13 @@ const deleteDraft = (draftKey) => {
localStorage.setItem('drafts', JSON.stringify(draftData)); localStorage.setItem('drafts', JSON.stringify(draftData));
} }
const interfaceToISOLanguage = (ilang) => {
const sep = ilang.indexOf("_");
return sep < 0 ?
ilang :
ilang.substr(0, sep);
}
const PostStatusForm = { const PostStatusForm = {
props: [ props: [
'statusId', 'statusId',
@@ -77,6 +86,7 @@ const PostStatusForm = {
'quoteId', 'quoteId',
'repliedUser', 'repliedUser',
'attentions', 'attentions',
'copyMessageLanguage',
'copyMessageScope', 'copyMessageScope',
'subject', 'subject',
'disableSubject', 'disableSubject',
@@ -129,6 +139,13 @@ const PostStatusForm = {
this.$refs.textarea.focus() this.$refs.textarea.focus()
} }
}, },
setup() {
const {postLanguageOptions} = usePostLanguageOptions()
return {
postLanguageOptions,
}
},
data () { data () {
const preset = this.$route.query.message const preset = this.$route.query.message
let statusText = preset || '' let statusText = preset || ''
@@ -138,7 +155,7 @@ const PostStatusForm = {
statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser) statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
} }
const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, interfaceLanguage } = this.$store.getters.mergedConfig const { postContentType: contentType, sensitiveByDefault, sensitiveIfSubject, alwaysShowSubjectInput } = this.$store.getters.mergedConfig
let statusParams = { let statusParams = {
spoilerText: this.subject || '', spoilerText: this.subject || '',
@@ -149,7 +166,7 @@ const PostStatusForm = {
poll: {}, poll: {},
mediaDescriptions: {}, mediaDescriptions: {},
visibility: this.suggestedVisibility(), visibility: this.suggestedVisibility(),
language: interfaceLanguage, language: this.suggestedLanguage(),
contentType contentType
} }
@@ -164,7 +181,7 @@ const PostStatusForm = {
poll: this.statusPoll || {}, poll: this.statusPoll || {},
mediaDescriptions: this.statusMediaDescriptions || {}, mediaDescriptions: this.statusMediaDescriptions || {},
visibility: this.statusScope || this.suggestedVisibility(), visibility: this.statusScope || this.suggestedVisibility(),
language: this.statusLanguage || interfaceLanguage, language: this.statusLanguage || this.suggestedLanguage(),
contentType: statusContentType contentType: statusContentType
} }
} }
@@ -199,6 +216,10 @@ const PostStatusForm = {
} }
} }
// When first loading the form, hide the subject (CW) field if it's disabled or doesn't have a starting value.
// "disableSubject" seems to take priority over "alwaysShowSubjectInput".
const showSubject = !this.disableSubject && (statusParams.spoilerText || alwaysShowSubjectInput)
return { return {
dropFiles: [], dropFiles: [],
uploadingFiles: false, uploadingFiles: false,
@@ -213,7 +234,10 @@ const PostStatusForm = {
preview: null, preview: null,
previewLoading: false, previewLoading: false,
emojiInputShown: false, emojiInputShown: false,
idempotencyKey: '' idempotencyKey: '',
activeEmojiInput: undefined,
activeTextInput: undefined,
subjectVisible: showSubject
} }
}, },
computed: { computed: {
@@ -302,13 +326,11 @@ const PostStatusForm = {
...mapState({ ...mapState({
mobileLayout: state => state.interface.mobileLayout mobileLayout: state => state.interface.mobileLayout
}), }),
isoLanguages () {
return iso6391.getAllCodes();
}
}, },
watch: { watch: {
'newStatus': { 'newStatus': {
deep: true, deep: true,
flush: 'sync',
handler () { handler () {
this.statusChanged() this.statusChanged()
} }
@@ -321,17 +343,22 @@ const PostStatusForm = {
this.saveDraft() this.saveDraft()
}, },
clearStatus () { clearStatus () {
const newStatus = this.newStatus const config = this.$store.getters.mergedConfig
this.newStatus = { this.newStatus = {
status: '', status: '',
spoilerText: '', spoilerText: '',
files: [], files: [],
visibility: newStatus.visibility, nsfw: !!config.sensitiveByDefault,
contentType: newStatus.contentType, visibility: this.suggestedVisibility(),
language: newStatus.language, contentType: config.postContentType,
language: this.suggestedLanguage(),
poll: {}, poll: {},
mediaDescriptions: {} mediaDescriptions: {}
} }
const scopeselector = this.$refs.scopeselector
if (scopeselector) {
scopeselector.currentScope = this.newStatus.visibility
}
this.pollFormVisible = false this.pollFormVisible = false
this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile() this.$refs.mediaUpload && this.$refs.mediaUpload.clearFile()
this.clearPollForm() this.clearPollForm()
@@ -491,7 +518,7 @@ const PostStatusForm = {
addMediaFile (fileInfo) { addMediaFile (fileInfo) {
this.newStatus.files.push(fileInfo) this.newStatus.files.push(fileInfo)
if (this.$store.getters.mergedConfig.sensitiveIfSubject && this.newStatus.spoilerText !== '') { if (this.$store.getters.mergedConfig.sensitiveIfSubject && this.newStatus.spoilerText !== '' || !!this.$store.getters.mergedConfig.sensitiveByDefault) {
this.newStatus.nsfw = true this.newStatus.nsfw = true
} }
this.$emit('resize', { delayed: true }) this.$emit('resize', { delayed: true })
@@ -674,8 +701,33 @@ const PostStatusForm = {
this.$refs['emoji-input'].resize() this.$refs['emoji-input'].resize()
}, },
showEmojiPicker () { showEmojiPicker () {
this.$refs['textarea'].focus() if (!this.activeEmojiInput || !this.activeTextInput)
this.$refs['emoji-input'].triggerShowPicker() this.focusStatusInput()
this.$refs[this.activeTextInput].focus()
this.$refs[this.activeEmojiInput].triggerShowPicker()
},
focusStatusInput() {
this.activeEmojiInput = 'emoji-input'
this.activeTextInput = 'textarea'
},
focusSubjectInput() {
this.activeEmojiInput = 'subject-emoji-input'
this.activeTextInput = 'subject-input'
},
toggleSubjectVisible() {
// If hiding CW, then we need to clear the subject and reset focus
if (this.subjectVisible)
{
this.focusStatusInput()
// "nsfw" property is normally set by the @change listener, but this bypasses it.
// We need to clear it manually instead.
this.newStatus.spoilerText = ''
this.newStatus.nsfw = false
}
this.subjectVisible = !this.subjectVisible
}, },
clearError () { clearError () {
this.error = null this.error = null
@@ -715,16 +767,19 @@ const PostStatusForm = {
openProfileTab () { openProfileTab () {
this.$store.dispatch('openSettingsModalTab', 'profile') this.$store.dispatch('openSettingsModalTab', 'profile')
}, },
suggestedLanguage () {
// Make sure the inherited language is actually valid
if (this.postLanguageOptions.find(o => o.value === this.copyMessageLanguage)) {
return this.copyMessageLanguage
}
const { postLanguage: defaultPostLanguage, interfaceLanguage } = this.$store.getters.mergedConfig
const postLanguage = defaultPostLanguage || interfaceToISOLanguage(interfaceLanguage)
return postLanguage
},
suggestedVisibility () { suggestedVisibility () {
if (this.copyMessageScope) { const maxScope = this.copyMessageScope
if (this.copyMessageScope === 'direct') { const defaultScope = this.$store.state.users.currentUser.default_scope
return this.copyMessageScope return scopeUtils.negotiate(defaultScope, maxScope)
}
if (this.copyMessageScope !== 'public' && this.$store.state.users.currentUser.default_scope !== 'private') {
return this.copyMessageScope
}
}
return this.$store.state.users.currentUser.default_scope
} }
} }
} }
@@ -18,6 +18,7 @@
> >
<button <button
class="button-unstyled -link" class="button-unstyled -link"
type="button"
@click="openProfileTab" @click="openProfileTab"
> >
{{ $t('post_status.account_not_locked_warning_link') }} {{ $t('post_status.account_not_locked_warning_link') }}
@@ -118,13 +119,16 @@
/> />
</div> </div>
<EmojiInput <EmojiInput
v-if="!disableSubject && (newStatus.spoilerText || alwaysShowSubject)" v-if="subjectVisible"
ref="subject-emoji-input"
v-model="newStatus.spoilerText" v-model="newStatus.spoilerText"
enable-emoji-picker enable-emoji-picker
hide-emoji-button
:suggest="emojiSuggestor" :suggest="emojiSuggestor"
class="form-control" class="form-control"
> >
<input <input
ref="subject-input"
v-model="newStatus.spoilerText" v-model="newStatus.spoilerText"
type="text" type="text"
:placeholder="$t('post_status.content_warning')" :placeholder="$t('post_status.content_warning')"
@@ -132,6 +136,8 @@
size="1" size="1"
class="form-post-subject" class="form-post-subject"
@input="onSubjectInput" @input="onSubjectInput"
@focus="focusSubjectInput()"
@keydown.exact.enter.prevent
> >
</EmojiInput> </EmojiInput>
<i18n-t <i18n-t
@@ -166,13 +172,14 @@
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)"
@input="resize" @input="resize"
@compositionupdate="resize" @compositionupdate="resize"
@paste="paste" @paste="paste"
@focus="focusStatusInput()"
/> />
<p <p
v-if="hasStatusLengthLimit" v-if="hasStatusLengthLimit"
@@ -185,8 +192,10 @@
<div <div
v-if="!disableScopeSelector" v-if="!disableScopeSelector"
class="visibility-tray" class="visibility-tray"
:class="{ 'visibility-tray-edit': isEdit }"
> >
<scope-selector <scope-selector
ref="scopeselector"
v-if="!disableVisibilitySelector" v-if="!disableVisibilitySelector"
:user-default="userDefaultScope" :user-default="userDefaultScope"
:original-scope="copyMessageScope" :original-scope="copyMessageScope"
@@ -195,7 +204,9 @@
/> />
<div <div
class="language-selector" class="format-selector-container">
<div
class="format-selector"
> >
<Select <Select
id="post-language" id="post-language"
@@ -203,17 +214,17 @@
class="form-control" class="form-control"
> >
<option <option
v-for="language in isoLanguages" v-for="language in postLanguageOptions"
:key="language" :key="language.key"
:value="language" :value="language.value"
> >
{{ language }} {{ language.label }}
</option> </option>
</Select> </Select>
</div> </div>
<div <div
v-if="postFormats.length > 1" v-if="postFormats.length > 1"
class="text-format" class="text-format format-selector"
> >
<Select <Select
id="post-content-type" id="post-content-type"
@@ -231,7 +242,7 @@
</div> </div>
<div <div
v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'" v-if="postFormats.length === 1 && postFormats[0] !== 'text/plain'"
class="text-format" class="text-format format-selector"
> >
<span class="only-format"> <span class="only-format">
{{ $t(`post_status.content_type["${postFormats[0]}"]`) }} {{ $t(`post_status.content_type["${postFormats[0]}"]`) }}
@@ -239,6 +250,7 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<poll-form <poll-form
v-if="pollsAvailable" v-if="pollsAvailable"
ref="pollForm" ref="pollForm"
@@ -263,6 +275,7 @@
<button <button
class="emoji-icon button-unstyled" class="emoji-icon button-unstyled"
:title="$t('emoji.add_emoji')" :title="$t('emoji.add_emoji')"
type="button"
@click="showEmojiPicker" @click="showEmojiPicker"
> >
<FAIcon icon="smile-beam" /> <FAIcon icon="smile-beam" />
@@ -272,10 +285,21 @@
class="poll-icon button-unstyled" class="poll-icon button-unstyled"
:class="{ selected: pollFormVisible }" :class="{ selected: pollFormVisible }"
:title="$t('polls.add_poll')" :title="$t('polls.add_poll')"
type="button"
@click="togglePollForm" @click="togglePollForm"
> >
<FAIcon icon="poll-h" /> <FAIcon icon="poll-h" />
</button> </button>
<button
v-if="!disableSubject"
class="spoiler-icon button-unstyled"
:class="{ selected: subjectVisible }"
:title="$t('post_status.toggle_content_warning')"
type="button"
@click="toggleSubjectVisible"
>
<FAIcon icon="eye-slash" />
</button>
</div> </div>
<button <button
v-if="posting" v-if="posting"
@@ -446,6 +470,10 @@
align-items: baseline; align-items: baseline;
} }
.visibility-tray-edit {
justify-content: right;
}
.visibility-notice.edit-warning { .visibility-notice.edit-warning {
> :first-child { > :first-child {
margin-top: 0; margin-top: 0;
@@ -456,7 +484,13 @@
} }
} }
.media-upload-icon, .poll-icon, .emoji-icon { .format-selector-container {
.format-selector {
display: inline-block;
}
}
.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;
flex: 1; flex: 1;
@@ -499,6 +533,11 @@
.poll-icon { .poll-icon {
order: 3; order: 3;
justify-content: center;
}
.spoiler-icon {
order: 4;
justify-content: right; justify-content: right;
} }
@@ -551,6 +590,11 @@
line-height: 1.85; line-height: 1.85;
} }
.form-post-subject {
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.form-post-body { .form-post-body {
// TODO: make a resizable textarea component? // TODO: make a resizable textarea component?
box-sizing: content-box; // needed for easier computation of dynamic size box-sizing: content-box; // needed for easier computation of dynamic size
@@ -563,6 +607,11 @@
min-height: calc(var(--post-line-height) * 1em); min-height: calc(var(--post-line-height) * 1em);
resize: none; resize: none;
&.-has-subject {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
&.scrollable-form { &.scrollable-form {
overflow-y: auto; overflow-y: auto;
} }
@@ -3,7 +3,7 @@
v-if="isLoggedIn && !resettingForm" v-if="isLoggedIn && !resettingForm"
:is-open="modalActivated" :is-open="modalActivated"
class="post-form-modal-view" class="post-form-modal-view"
@backdropClicked="closeModal" @backdrop-clicked="closeModal"
> >
<div class="post-form-modal-panel panel"> <div class="post-form-modal-panel panel">
<div class="panel-heading"> <div class="panel-heading">
+3 -3
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';
@@ -2,7 +2,7 @@ export default {
props: [ 'user' ], props: [ 'user' ],
computed: { computed: {
subscribeUrl () { subscribeUrl () {
// eslint-disable-next-line no-undef
const serverUrl = new URL(this.user.statusnet_profile_url) const serverUrl = new URL(this.user.statusnet_profile_url)
return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus` return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
} }
@@ -1,4 +1,6 @@
import ConfirmModal from '../confirm_modal/confirm_modal.vue' import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import ScopeSelector from '../scope_selector/scope_selector.vue'
import scopeUtils from 'src/lib/scope_utils.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faRetweet } from '@fortawesome/free-solid-svg-icons' import { faRetweet } from '@fortawesome/free-solid-svg-icons'
@@ -7,12 +9,14 @@ library.add(faRetweet)
const RetweetButton = { const RetweetButton = {
props: ['status', 'loggedIn', 'visibility'], props: ['status', 'loggedIn', 'visibility'],
components: { components: {
ConfirmModal ConfirmModal,
ScopeSelector
}, },
data () { data () {
return { return {
animated: false, animated: false,
showingConfirmDialog: false showingConfirmDialog: false,
retweetVisibility: this.$store.state.users.currentUser.default_scope
} }
}, },
methods: { methods: {
@@ -25,7 +29,7 @@ const RetweetButton = {
}, },
doRetweet () { doRetweet () {
if (!this.status.repeated) { if (!this.status.repeated) {
this.$store.dispatch('retweet', { id: this.status.id }) this.$store.dispatch('retweet', { id: this.status.id, visibility: this.retweetVisibility })
} else { } else {
this.$store.dispatch('unretweet', { id: this.status.id }) this.$store.dispatch('unretweet', { id: this.status.id })
} }
@@ -40,6 +44,9 @@ const RetweetButton = {
}, },
hideConfirmDialog () { hideConfirmDialog () {
this.showingConfirmDialog = false this.showingConfirmDialog = false
},
changeVis (visibility) {
this.retweetVisibility = visibility
} }
}, },
computed: { computed: {
@@ -54,6 +61,15 @@ const RetweetButton = {
}, },
remoteInteractionLink () { remoteInteractionLink () {
return this.$store.getters.remoteInteractionLink({ statusId: this.status.id }) return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
},
userDefaultScope () {
return this.$store.state.users.currentUser.default_scope
},
statusScope () {
return this.status.visibility
},
initialScope () {
return scopeUtils.negotiate(this.userDefaultScope, this.status.visibility)
} }
} }
} }
@@ -49,12 +49,18 @@
@cancelled="hideConfirmDialog" @cancelled="hideConfirmDialog"
> >
{{ $t('status.repeat_confirm') }} {{ $t('status.repeat_confirm') }}
<scope-selector
:user-default="userDefaultScope"
:original-scope="statusScope"
:initial-scope="initialScope"
:on-scope-change="changeVis"
/>
</confirm-modal> </confirm-modal>
</teleport> </teleport>
</div> </div>
</template> </template>
<script src="./retweet_button.js" ></script> <script src="./retweet_button.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
@@ -121,6 +121,19 @@ export default {
} }
} }
const mfmStyleFromDataAttributes = (attributes) => {
// CSS selectors can check if a data-* attribute is true, but can't use other values, so we want to add them to the style attribute
// Here we turn e.g. `{'data-mfm-some': '1deg', 'data-mfm-thing': '5s'}` to "--mfm-some: 1deg;--mfm-thing: 5s;"
// Note that we only add the value to `style` when they contain only letters, numbers, dot, or minus signs
// At the moment of writing, this should be enough for legitimate purposes and reduces the chance of injection by using special characters
// There is a special case for the `color` value, who is provided without `#`, but requires this in the `style` attribute
return Object.keys(attributes).filter(
(key) => key.startsWith('data-mfm-') && attributes[key] !== true && /^[a-zA-Z0-9.\-]*$/.test(attributes[key])
).map(
(key) => '--mfm-' + key.substr(9) + (key === 'data-mfm-color' ? ': #' : ': ') + attributes[key] + ';'
).reduce((a,v) => a+v, '')
}
// Processor to use with html_tree_converter // Processor to use with html_tree_converter
const processItem = (item, index, array, what) => { const processItem = (item, index, array, what) => {
// Handle text nodes - just add emoji // Handle text nodes - just add emoji
@@ -191,6 +204,15 @@ export default {
if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) { if (this.handleLinks && attrs?.['class']?.includes?.('h-card')) {
return ['', children.map(processItem), ''] return ['', children.map(processItem), '']
} }
let mfm_style = mfmStyleFromDataAttributes(attrs)
if (mfm_style !== '') {
return [
opener.slice(0,-1) + ' style="' + mfm_style + '">',
children.map(processItem),
closer
]
}
} }
if (children !== undefined) { if (children !== undefined) {
+10 -20
View File
@@ -6,6 +6,8 @@ import {
faGlobe faGlobe
} from '@fortawesome/free-solid-svg-icons' } from '@fortawesome/free-solid-svg-icons'
import scopeUtils from 'src/lib/scope_utils.js'
library.add( library.add(
faEnvelope, faEnvelope,
faGlobe, faGlobe,
@@ -13,18 +15,11 @@ library.add(
faLockOpen faLockOpen
) )
const SCOPE_LEVELS = {
'direct': 0,
'private': 1,
'local': 2,
'unlisted': 2,
'public': 3
}
const ScopeSelector = { const ScopeSelector = {
props: [ props: [
'showAll', 'showAll',
'userDefault', 'userDefault',
// scope of parent object
'originalScope', 'originalScope',
'initialScope', 'initialScope',
'onScopeChange' 'onScopeChange'
@@ -39,16 +34,16 @@ const ScopeSelector = {
return !this.showPublic && !this.showUnlisted && !this.showPrivate && !this.showDirect return !this.showPublic && !this.showUnlisted && !this.showPrivate && !this.showDirect
}, },
showPublic () { showPublic () {
return this.originalScope !== 'direct' && this.shouldShow('public') return this.shouldShow('public')
}, },
showLocal () { showLocal () {
return this.originalScope !== 'direct' && this.shouldShow('local') return this.shouldShow('local')
}, },
showUnlisted () { showUnlisted () {
return this.originalScope !== 'direct' && this.shouldShow('unlisted') return this.shouldShow('unlisted')
}, },
showPrivate () { showPrivate () {
return this.originalScope !== 'direct' && this.shouldShow('private') return this.shouldShow('private')
}, },
showDirect () { showDirect () {
return this.shouldShow('direct') return this.shouldShow('direct')
@@ -65,15 +60,10 @@ const ScopeSelector = {
}, },
methods: { methods: {
shouldShow (scope) { shouldShow (scope) {
if (!this.originalScope) { if (!this.originalScope)
return true return true
} else
return scopeUtils.compare(scope, this.originalScope) <= 0
if (this.originalScope === 'local') {
return scope === 'direct' || scope === 'local'
}
return SCOPE_LEVELS[scope] <= SCOPE_LEVELS[this.originalScope]
}, },
changeVis (scope) { changeVis (scope) {
this.currentScope = scope this.currentScope = scope
@@ -24,7 +24,7 @@
:items="items" :items="items"
:get-key="getKey" :get-key="getKey"
> >
<template v-slot:item="{item}"> <template #item="{item}">
<div <div
class="selectable-list-item-inner" class="selectable-list-item-inner"
:class="{ 'selectable-list-item-selected-inner': isSelected(item) }" :class="{ 'selectable-list-item-selected-inner': isSelected(item) }"
@@ -41,7 +41,7 @@
/> />
</div> </div>
</template> </template>
<template v-slot:empty> <template #empty>
<slot name="empty" /> <slot name="empty" />
</template> </template>
</List> </List>
@@ -6,7 +6,7 @@
<Checkbox <Checkbox
:model-value="state" :model-value="state"
:disabled="disabled" :disabled="disabled"
@update:modelValue="update" @update:model-value="update"
> >
<span <span
v-if="!!$slots.default" v-if="!!$slots.default"
@@ -8,7 +8,7 @@
<Select <Select
:model-value="state" :model-value="state"
:disabled="disabled" :disabled="disabled"
@update:modelValue="update" @update:model-value="update"
> >
<option <option
v-for="option in options" v-for="option in options"
@@ -6,14 +6,14 @@
<Popover <Popover
trigger="hover" trigger="hover"
> >
<template v-slot:trigger> <template #trigger>
&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>
@@ -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>
@@ -69,7 +69,7 @@ const SettingsModal = {
this.$store.dispatch('closeSettingsModal') this.$store.dispatch('closeSettingsModal')
}, },
logout () { logout () {
this.$router.replace('/main/public') this.$router.replace(this.$store.state.instance.redirectRootNoLogin || '/main/all')
this.$store.dispatch('closeSettingsModal') this.$store.dispatch('closeSettingsModal')
this.$store.dispatch('logout') this.$store.dispatch('logout')
}, },
@@ -108,7 +108,7 @@
<Checkbox <Checkbox
:model-value="!!expertLevel" :model-value="!!expertLevel"
class="expertMode" class="expertMode"
@update:modelValue="expertLevel = Number($event)" @update:model-value="expertLevel = Number($event)"
> >
{{ $t("settings.expert_mode") }} {{ $t("settings.expert_mode") }}
</Checkbox> </Checkbox>
@@ -72,7 +72,7 @@ const DataImportExportTab = {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user && user.is_local) {
// append the instance address // append the instance address
// eslint-disable-next-line no-undef
return user.screen_name + '@' + location.hostname return user.screen_name + '@' + location.hostname
} }
return user.screen_name return user.screen_name
@@ -4,6 +4,7 @@ import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import IntegerSetting from '../helpers/integer_setting.vue' import IntegerSetting from '../helpers/integer_setting.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue' import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import { usePostLanguageOptions } from 'src/lib/post_language'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import ServerSideIndicator from '../helpers/server_side_indicator.vue' import ServerSideIndicator from '../helpers/server_side_indicator.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
@@ -17,6 +18,11 @@ library.add(
) )
const GeneralTab = { const GeneralTab = {
setup() {
const {postLanguageOptions} = usePostLanguageOptions()
return {postLanguageOptions}
},
data () { data () {
return { return {
subjectLineOptions: ['email', 'noop', 'masto'].map(mode => ({ subjectLineOptions: ['email', 'noop', 'masto'].map(mode => ({
@@ -118,6 +124,12 @@ const GeneralTab = {
this.$store.dispatch('setOption', { name: 'translationLanguage', value: val }) this.$store.dispatch('setOption', { name: 'translationLanguage', value: val })
} }
}, },
postLanguage: {
get: function () { return this.$store.getters.mergedConfig.postLanguage },
set: function (val) {
this.$store.dispatch('setOption', { name: 'postLanguage', value: val })
}
},
...SharedComputedObject() ...SharedComputedObject()
}, },
methods: { methods: {
@@ -44,7 +44,6 @@
<template <template
v-if="profilesExpanded" v-if="profilesExpanded"
> >
<div <div
v-for="profile in settingsProfiles" v-for="profile in settingsProfiles"
:key="profile.id" :key="profile.id"
@@ -73,15 +72,24 @@
</button> </button>
</template> </template>
</div> </div>
<button class="btn button-default" @click="refreshProfiles()"> <button
class="btn button-default"
@click="refreshProfiles()"
>
{{ $t('settings.settings_profiles_refresh') }} {{ $t('settings.settings_profiles_refresh') }}
<FAIcon icon="sync" @click="refreshProfiles()" /> <FAIcon
icon="sync"
@click="refreshProfiles()"
/>
</button> </button>
<h3>{{ $t('settings.settings_profile_creation') }}</h3> <h3>{{ $t('settings.settings_profile_creation') }}</h3>
<label for="settings-profile-new-name"> <label for="settings-profile-new-name">
{{ $t('settings.settings_profile_creation_new_name_label') }} {{ $t('settings.settings_profile_creation_new_name_label') }}
</label> </label>
<input v-model="newProfileName" id="settings-profile-new-name"> <input
id="settings-profile-new-name"
v-model="newProfileName"
>
<button <button
class="btn button-default" class="btn button-default"
@click="createSettingsProfile" @click="createSettingsProfile"
@@ -146,6 +154,21 @@
{{ $t('settings.show_wider_shortcuts') }} {{ $t('settings.show_wider_shortcuts') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li>
<BooleanSetting path="displayPageBackgrounds">
{{ $t('settings.show_page_backgrounds') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="centerAlignBio">
{{ $t('settings.center_align_bio') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="compactUserInfo">
{{ $t('settings.compact_user_info') }}
</BooleanSetting>
</li>
<li> <li>
<BooleanSetting path="stopGifs"> <BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }} {{ $t('settings.stop_gifs') }}
@@ -256,6 +279,11 @@
{{ $t('settings.right_sidebar') }} {{ $t('settings.right_sidebar') }}
</BooleanSetting> </BooleanSetting>
</li> </li>
<li>
<BooleanSetting path="widenTimeline">
{{ $t('settings.widen_timeline') }}
</BooleanSetting>
</li>
<li> <li>
<ChoiceSetting <ChoiceSetting
v-if="user" v-if="user"
@@ -483,14 +511,6 @@
</BooleanSetting> </BooleanSetting>
</li> </li>
</ul> </ul>
<li>
<BooleanSetting
path="useAtIcon"
expert="1"
>
{{ $t('settings.use_at_icon') }}
</BooleanSetting>
</li>
<li> <li>
<BooleanSetting path="mentionLinkShowAvatar"> <BooleanSetting path="mentionLinkShowAvatar">
{{ $t('settings.mention_link_show_avatar') }} {{ $t('settings.mention_link_show_avatar') }}
@@ -588,6 +608,15 @@
{{ $t('settings.post_status_content_type') }} {{ $t('settings.post_status_content_type') }}
</ChoiceSetting> </ChoiceSetting>
</li> </li>
<li>
<ChoiceSetting
id="postLanguage"
path="postLanguage"
:options="postLanguageOptions"
>
{{ $t('settings.post_language') }}
</ChoiceSetting>
</li>
<li> <li>
<BooleanSetting <BooleanSetting
path="alwaysShowNewPostButton" path="alwaysShowNewPostButton"
@@ -85,7 +85,7 @@ const MutesAndBlocks = {
// check is it's a local user // check is it's a local user
if (user && user.is_local) { if (user && user.is_local) {
// append the instance address // append the instance address
// eslint-disable-next-line no-undef
return user.screen_name + '@' + location.hostname return user.screen_name + '@' + location.hostname
} }
return user.screen_name return user.screen_name
@@ -10,7 +10,7 @@
:query="queryUserIds" :query="queryUserIds"
:placeholder="$t('settings.search_user_to_block')" :placeholder="$t('settings.search_user_to_block')"
> >
<template v-slot="row"> <template #default="row">
<BlockCard <BlockCard
:user-id="row.item" :user-id="row.item"
/> />
@@ -21,7 +21,7 @@
:refresh="true" :refresh="true"
:get-key="i => i" :get-key="i => i"
> >
<template v-slot:header="{selected}"> <template #header="{selected}">
<div class="bulk-actions"> <div class="bulk-actions">
<ProgressButton <ProgressButton
v-if="selected.length > 0" v-if="selected.length > 0"
@@ -29,7 +29,7 @@
:click="() => blockUsers(selected)" :click="() => blockUsers(selected)"
> >
{{ $t('user_card.block') }} {{ $t('user_card.block') }}
<template v-slot:progress> <template #progress>
{{ $t('user_card.block_progress') }} {{ $t('user_card.block_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
@@ -39,16 +39,16 @@
:click="() => unblockUsers(selected)" :click="() => unblockUsers(selected)"
> >
{{ $t('user_card.unblock') }} {{ $t('user_card.unblock') }}
<template v-slot:progress> <template #progress>
{{ $t('user_card.unblock_progress') }} {{ $t('user_card.unblock_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template v-slot:item="{item}"> <template #item="{item}">
<BlockCard :user-id="item" /> <BlockCard :user-id="item" />
</template> </template>
<template v-slot:empty> <template #empty>
{{ $t('settings.no_blocks') }} {{ $t('settings.no_blocks') }}
</template> </template>
</BlockList> </BlockList>
@@ -63,7 +63,7 @@
:query="queryUserIds" :query="queryUserIds"
:placeholder="$t('settings.search_user_to_mute')" :placeholder="$t('settings.search_user_to_mute')"
> >
<template v-slot="row"> <template #default="row">
<MuteCard <MuteCard
:user-id="row.item" :user-id="row.item"
/> />
@@ -74,7 +74,7 @@
:refresh="true" :refresh="true"
:get-key="i => i" :get-key="i => i"
> >
<template v-slot:header="{selected}"> <template #header="{selected}">
<div class="bulk-actions"> <div class="bulk-actions">
<ProgressButton <ProgressButton
v-if="selected.length > 0" v-if="selected.length > 0"
@@ -82,7 +82,7 @@
:click="() => muteUsers(selected)" :click="() => muteUsers(selected)"
> >
{{ $t('user_card.mute') }} {{ $t('user_card.mute') }}
<template v-slot:progress> <template #progress>
{{ $t('user_card.mute_progress') }} {{ $t('user_card.mute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
@@ -92,16 +92,16 @@
:click="() => unmuteUsers(selected)" :click="() => unmuteUsers(selected)"
> >
{{ $t('user_card.unmute') }} {{ $t('user_card.unmute') }}
<template v-slot:progress> <template #progress>
{{ $t('user_card.unmute_progress') }} {{ $t('user_card.unmute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template v-slot:item="{item}"> <template #item="{item}">
<MuteCard :user-id="item" /> <MuteCard :user-id="item" />
</template> </template>
<template v-slot:empty> <template #empty>
{{ $t('settings.no_mutes') }} {{ $t('settings.no_mutes') }}
</template> </template>
</MuteList> </MuteList>
@@ -114,7 +114,7 @@
:query="queryKnownDomains" :query="queryKnownDomains"
:placeholder="$t('settings.type_domains_to_mute')" :placeholder="$t('settings.type_domains_to_mute')"
> >
<template v-slot="row"> <template #default="row">
<DomainMuteCard <DomainMuteCard
:domain="row.item" :domain="row.item"
/> />
@@ -125,7 +125,7 @@
:refresh="true" :refresh="true"
:get-key="i => i" :get-key="i => i"
> >
<template v-slot:header="{selected}"> <template #header="{selected}">
<div class="bulk-actions"> <div class="bulk-actions">
<ProgressButton <ProgressButton
v-if="selected.length > 0" v-if="selected.length > 0"
@@ -133,16 +133,16 @@
:click="() => unmuteDomains(selected)" :click="() => unmuteDomains(selected)"
> >
{{ $t('domain_mute_card.unmute') }} {{ $t('domain_mute_card.unmute') }}
<template v-slot:progress> <template #progress>
{{ $t('domain_mute_card.unmute_progress') }} {{ $t('domain_mute_card.unmute_progress') }}
</template> </template>
</ProgressButton> </ProgressButton>
</div> </div>
</template> </template>
<template v-slot:item="{item}"> <template #item="{item}">
<DomainMuteCard :domain="item" /> <DomainMuteCard :domain="item" />
</template> </template>
<template v-slot:empty> <template #empty>
{{ $t('settings.no_mutes') }} {{ $t('settings.no_mutes') }}
</template> </template>
</DomainMuteList> </DomainMuteList>
@@ -33,6 +33,7 @@ const ProfileTab = {
newName: this.$store.state.users.currentUser.name_unescaped, newName: this.$store.state.users.currentUser.name_unescaped,
newBio: unescape(this.$store.state.users.currentUser.description), newBio: unescape(this.$store.state.users.currentUser.description),
newLocked: this.$store.state.users.currentUser.locked, newLocked: this.$store.state.users.currentUser.locked,
newPermitFollowback: this.$store.state.users.currentUser.permit_followback,
newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })), newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })),
showRole: this.$store.state.users.currentUser.show_role, showRole: this.$store.state.users.currentUser.show_role,
role: this.$store.state.users.currentUser.role, role: this.$store.state.users.currentUser.role,
@@ -129,14 +130,15 @@ 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,
show_role: this.showRole, show_role: this.showRole,
status_ttl_days: this.expirePosts ? this.newPostTTLDays : -1, status_ttl_days: this.expirePosts ? this.newPostTTLDays : -1,
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) {
@@ -185,7 +187,7 @@ const ProfileTab = {
}) })
return return
} }
// eslint-disable-next-line no-undef
const reader = new FileReader() const reader = new FileReader()
reader.onload = ({ target }) => { reader.onload = ({ target }) => {
const img = target.result const img = target.result
@@ -110,11 +110,9 @@
max="730" max="730"
class="expire-posts-days" class="expire-posts-days"
:placeholder="$t('settings.expire_posts_input_placeholder')" :placeholder="$t('settings.expire_posts_input_placeholder')"
/> >
</p>
<p>
</p> </p>
<p />
<p> <p>
<interface-language-switcher <interface-language-switcher
:prompt-text="$t('settings.email_language')" :prompt-text="$t('settings.email_language')"
@@ -259,6 +257,19 @@
<BooleanSetting path="serverSide_locked"> <BooleanSetting path="serverSide_locked">
{{ $t('settings.lock_account_description') }} {{ $t('settings.lock_account_description') }}
</BooleanSetting> </BooleanSetting>
<ul
class="setting-list suboptions"
:class="[{disabled: !serverSide_locked}]"
>
<li>
<BooleanSetting
path="serverSide_permitFollowback"
:disabled="!serverSide_locked"
>
{{ $t('settings.permit_followback_description') }}
</BooleanSetting>
</li>
</ul>
</li> </li>
<li> <li>
<BooleanSetting path="serverSide_discoverable"> <BooleanSetting path="serverSide_discoverable">
@@ -1,22 +1,25 @@
import { extractCommit } from 'src/services/version/version.service' import { extractCommit } from 'src/services/version/version.service'
const pleromaFeCommitUrl = 'https://akkoma.dev/AkkomaGang/pleroma-fe/commit/' function joinURL(base, subpath) {
const pleromaBeCommitUrl = 'https://akkoma.dev/AkkomaGang/akkoma/commit/' return URL.parse(subpath, base)?.href || "invalid base URL"
}
const VersionTab = { const VersionTab = {
data () { data () {
const instance = this.$store.state.instance const instance = this.$store.state.instance
return { return {
backendCommitUrl: instance.backendCommitUrl,
backendVersion: instance.backendVersion, backendVersion: instance.backendVersion,
frontendCommitUrl: instance.frontendCommitUrl,
frontendVersion: instance.frontendVersion frontendVersion: instance.frontendVersion
} }
}, },
computed: { computed: {
frontendVersionLink () { frontendVersionLink () {
return pleromaFeCommitUrl + this.frontendVersion return joinURL(this.frontendCommitUrl, this.frontendVersion)
}, },
backendVersionLink () { backendVersionLink () {
return pleromaBeCommitUrl + extractCommit(this.backendVersion) return joinURL(this.backendCommitUrl, extractCommit(this.backendVersion))
} }
} }
} }
@@ -215,7 +215,7 @@
</div> </div>
</template> </template>
<script src="./shadow_control.js" ></script> <script src="./shadow_control.js"></script>
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
+1 -1
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';
+1 -1
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">

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