Compare commits

...

178 Commits

Author SHA1 Message Date
Puniko 30e91de97f Merge branch 'develop' into fedi-absturztau-be 2023-04-22 07:55:09 +02:00
Puniko 4d954b48bc resolve merge conflicts 2023-02-12 09:20:49 +01:00
Puniko 4919f32ce4 Merge branch 'develop' into fedi-absturztau-be 2023-01-21 09:12:47 +01:00
Puniko a69ed0898e Merge branch 'develop' into fedi-absturztau-be 2022-12-18 15:22:23 +01:00
Puniko 59a3e3fcbb Merge branch 'develop' into fedi-absturztau-be 2022-11-27 09:57:22 +01:00
Puniko b6280ae97d resolve merge conflicts 2022-11-20 08:37:26 +01:00
Puniko 1b190db9ed Merge branch 'develop' into fedi-absturztau-be 2022-10-19 17:48:12 +02:00
Puniko 31fa6223ec resolve merge conflicts 2022-09-17 11:17:40 +02:00
Absturztaube dccf5ed1c0 resolve merge conflicts 2022-08-28 10:34:00 +02:00
Absturztaube 504a11c9da Merge branch 'develop' into fedi-absturztau-be 2022-08-07 11:46:50 +02:00
Absturztaube d3d13d50d4 resolve merge conflicts 2022-07-26 12:22:07 +02:00
Absturztaube 6b10df2d89 merged akkoma-fe develop 2022-07-26 10:44:11 +02:00
Absturztaube d237c3cc6d fix loading crash on emoji reacts 2022-06-11 11:21:48 +02:00
Sol Fisher Romanoff 65b13849b9 Add emoji name as title tag 2022-06-11 10:59:28 +02:00
sadposter 0d67481109 fix width 2022-06-11 10:59:14 +02:00
FloatingGhost d2bce51941 resolve merge conflicts 2022-06-11 10:58:50 +02:00
FloatingGhost 07d4433e25 force width 2022-06-11 10:57:26 +02:00
FloatingGhost 66604e987c allow custom reactions 2022-06-11 10:57:16 +02:00
FloatingGhost ca5d0bea60 allow customs 2022-06-11 10:57:06 +02:00
Absturztaube 89a37d84b2 resolve merge conflicts 2022-06-11 10:55:23 +02:00
Absturztaube 38158bd561 Merge branch 'develop' into fedi-absturztau-be 2022-05-21 13:56:07 +02:00
Absturztaube 221aa7e0b4 resolve merge conflicts 2022-04-26 20:47:46 +02:00
Absturztaube ef986724ef add dom2component mixin 2022-04-03 19:50:02 +02:00
Absturztaube 5ce9136d89 resolve merge conflicts 2022-04-03 19:03:36 +02:00
Absturztaube 643e087404 resolve merge conflicts 2022-03-16 20:21:33 +01:00
Lynne 1b712bc1a0 Remove ruffle
This patch removes Ruffle completely, significantly speeding up the
loading of the frontend, making it a little more responsive,
and reducing its compressed size.
2021-12-15 21:10:12 +01:00
Absturztaube 12db1d8719 Merge branch 'develop' into fedi-absturztau-be 2021-12-15 20:50:39 +01:00
Absturztaube b4b906689f add threading 2021-10-02 19:46:22 +02:00
Absturztaube d34cef391b resolve merge confilcts 2021-10-02 19:31:29 +02:00
Tusooa Zhu fe0e7bd63c
Fix timeline jump when scrolling
Ref: tree-threading
2021-09-16 10:05:07 -04:00
Tusooa Zhu 78f573af47
Make replying and mediaPlaying controlled
$refs is not a reliable way to deal with child components under
tree threading as it is not reactive, but the children may change at
any time. The only good way seems to be making these states aggregated on
the conversation component.

Ref: tree-threading
2021-09-16 00:34:14 -04:00
Tusooa Zhu 12ed9a1799
Fix virtual scrolling for tree threading
Ref: tree-threading
2021-09-16 00:34:14 -04:00
Tusooa Zhu 0b576b64e2
Clean up debug code for tree threading 2021-09-10 15:24:23 -04:00
Tusooa Zhu 708633d6b1
Fix controlled status display toggles 2021-09-10 15:10:10 -04:00
Tusooa Zhu 59a2f65a33
Add English translations for other replies count 2021-09-10 15:10:10 -04:00
Tusooa Zhu c069a9f799
Add other replies count for reply list link 2021-09-10 15:10:10 -04:00
Tusooa Zhu c634e15305
Do not display replies inside status as link if there are no other replies 2021-09-10 15:10:03 -04:00
Tusooa Zhu a1404f7735
Add English translation for position of other replies button pref 2021-09-09 00:26:08 -04:00
Tusooa Zhu 70ec3ad09e
Make position of other replies button a pref 2021-09-09 00:26:08 -04:00
Tusooa Zhu 8a4c0bfa18
Add English translation for show all conversation button improvement 2021-09-09 00:26:08 -04:00
Tusooa Zhu 00cc721344
Improve "show full conversation" interaction
Now we only show that button when there are other statuses out of sight
(other toplevel statuses exist outside of the current thread tree).
2021-09-09 00:26:08 -04:00
Tusooa Zhu a917bdc34b
Make other replies button stretch along the row 2021-09-09 00:26:08 -04:00
Tusooa Zhu 4648bc6f72
Optimise thread ancestor borders 2021-09-09 00:26:08 -04:00
Tusooa Zhu 5643314922
Optimise thread ancestor display style 2021-09-09 00:26:08 -04:00
Tusooa Zhu 89761743b8
Reset thread open state when collapsed 2021-09-09 00:26:07 -04:00
Tusooa Zhu e01445b1d9
Clean up 2021-09-09 00:26:07 -04:00
Tusooa Zhu 5a37ea5a8e
Highlight ancestor of the current status when diving back to top 2021-09-09 00:26:07 -04:00
Tusooa Zhu 1fdba77ae5
Add English translation for Misskey-style tree view 2021-09-09 00:26:07 -04:00
Tusooa Zhu 7dd5e0fc8e
Implement Misskey-style tree view
Now the tree will be always rooted at the highlighted status, and
all its ancestors shown linearly on the top.

Enhancement: If an ancestor has more
than one reply (i.e. it has a child that is not on current status's
ancestor chain), we are given a link to root the thread at that status.
2021-09-09 00:26:07 -04:00
Tusooa Zhu 38a67cc2e2
Remove horizontal border and thicken vertical border in a thread tree 2021-09-09 00:26:07 -04:00
Tusooa Zhu 2c91a020bc
Make dive/undive button clickable along the whole row 2021-09-09 00:23:48 -04:00
Tusooa Zhu 2a6f0c4a34
Optimize thread border radius 2021-09-09 00:23:48 -04:00
Tusooa Zhu f8d25d2c2a
Optimize thread display 2021-09-09 00:23:48 -04:00
Tusooa Zhu b7e179c1fe
Fix the bug where toggleShowingTall does not work 2021-09-09 00:23:47 -04:00
Tusooa Zhu 46feecee70
Fix status undefined in parentOf 2021-09-09 00:23:09 -04:00
Tusooa Zhu 9029344e1f
Add English translations for max depth in thread 2021-09-09 00:22:53 -04:00
Tusooa Zhu 891fb00107
Add settings for max depth in thread 2021-09-09 00:22:53 -04:00
Tusooa Zhu 640d3041ef
Use mergedConfig properly 2021-09-09 00:22:32 -04:00
Tusooa Zhu 28469988dd
Fallback to simpleTree style 2021-09-09 00:22:15 -04:00
Tusooa Zhu ac464be063
Undive when collapsed 2021-09-09 00:21:37 -04:00
Tusooa Zhu c221805695
Clean up 2021-09-09 00:21:23 -04:00
Tusooa Zhu 49398566d3
Lint 2021-09-09 00:21:14 -04:00
Tusooa Zhu 9ccc374feb
Add English translation for simple tree 2021-09-09 00:21:00 -04:00
Tusooa Zhu ad5c0abe14
Add simple tree style navigation 2021-09-09 00:20:51 -04:00
Tusooa Zhu ff59c5a785
Add English translation for diving 2021-09-09 00:20:29 -04:00
Tusooa Zhu 93bcee9516
Add dive functionality 2021-09-09 00:20:22 -04:00
Tusooa Zhu f0c717ce5f
Add English translations for diving 2021-09-09 00:19:15 -04:00
Tusooa Zhu 4f775b6be4
Support diving into one status in a conversation 2021-09-09 00:19:15 -04:00
Tusooa Zhu 436597a906
Make status display controlled 2021-09-09 00:19:15 -04:00
Tusooa Zhu e6120df550
Add English translations for message threading 2021-09-09 00:19:15 -04:00
Tusooa Zhu a4a0858110
Make show full thread message account for numbers 2021-09-09 00:19:15 -04:00
Tusooa Zhu b1f4b1bff3
Implement thread folding/expanding 2021-09-09 00:19:15 -04:00
Tusooa Zhu 814a27749a
Add tree-style thread display 2021-09-09 00:19:15 -04:00
Absturztaube a0cf440fac swap of react and fav 2021-08-07 15:01:13 +02:00
Absturztaube d5e091e9af update readme 2021-08-07 11:55:40 +02:00
Absturztaube 5a5320b71c Merge branch 'tusooa/pleroma-fe-from/develop/tusooa/media-touch-actions' into fedi-absturztau-be 2021-08-07 11:54:30 +02:00
Absturztaube 7fe7339ea7 resolve merge conflicts 2021-08-07 11:46:39 +02:00
Tusooa Zhu 3b6b8b96c4
Bump pinch-zoom-element version 2021-08-02 23:25:38 -04:00
Tusooa Zhu 4c2a7aabe5
Clean up 2021-08-02 22:47:19 -04:00
Tusooa Zhu 3366c915e9
Check whether we swiped only for mouse pointer 2021-08-02 22:29:49 -04:00
Tusooa Zhu db71bbf358
Scale swipe threshold with viewport width 2021-08-02 22:29:48 -04:00
Tusooa Zhu 7b77c0c884
Update pinch-zoom-element 2021-08-02 22:29:48 -04:00
Tusooa Zhu 1478e72fcc
Allow pinch-zoom to fill the whole screen 2021-08-02 22:29:48 -04:00
Tusooa Zhu 33384af5df
Use native click for hiding overlay
The pointerup strategy is unsuccessful, as some other overlays
(Firefox's Inspect Element) will pass down pointerup events.
2021-08-02 22:29:48 -04:00
Tusooa Zhu 9d4dd64276
Reset position on swipe end even if we cannot navigate 2021-08-02 22:29:48 -04:00
Tusooa Zhu e2f3929872
Make lint happy 2021-08-02 22:29:47 -04:00
Tusooa Zhu 4552c28e06
Prevent the click event from firing on content below modal 2021-08-02 22:29:47 -04:00
Tusooa Zhu 214338b9f0
Add missing swipe click component 2021-08-02 22:29:47 -04:00
Tusooa Zhu cd9384adae
Clean up 2021-08-02 22:29:47 -04:00
Tusooa Zhu 7469849c39
Add swipe-click handler to media modal
Now swiping will correctly change the current media, and with a good
preview. Clicking without swiping closes the overlay.
2021-08-02 22:29:47 -04:00
Tusooa Zhu 0a63208da7
Use pinch-zoom-element for pinch zoom functionality 2021-08-02 22:29:46 -04:00
Tusooa Zhu 0421c06d47
Add pan threshold 2021-08-02 22:29:46 -04:00
Tusooa Zhu 7d767f840b
Handle pinch action 2021-08-02 22:29:46 -04:00
Tusooa Zhu aa70c31950
Preview swipe action 2021-08-02 22:29:46 -04:00
Tusooa Zhu 61509d1b1e
Make media modal be aware of multi-touch actions
Originally the media viewer would think every touch is a swipe (one-finger
touch event), so we would encounter the case where a two-finger scale event
would incorrectly change the current media. This is now fixed.
2021-08-02 22:28:16 -04:00
Absturztaube 2b6974dcad fix chats 2021-07-04 19:04:12 +02:00
Absturztaube 6594cdaa63 remove sorting because performance 2021-07-03 17:29:35 +02:00
Absturztaube b5cc8ec3ae update readme 2021-07-03 17:25:46 +02:00
Absturztaube 0fc86d5bfe add tags as buttons to posts 2021-07-03 17:23:25 +02:00
Absturztaube 77f8537f61 improved sidebar ordering when 3rd column is active 2021-06-28 22:54:33 +02:00
Absturztaube 240bce92cd Merge branch 'fix-themes-select' into fedi-absturztau-be 2021-06-28 22:47:31 +02:00
Absturztaube 9be1cc34ba temporary fix for external links 2021-06-28 21:51:12 +02:00
Absturztaube 3336572a74 remove order style when sidebarAlign is active 2021-06-21 14:05:01 +02:00
Absturztaube fcf1c7b4b4 resolve merge conflicts 2021-06-21 13:58:30 +02:00
Absturztaube c8e517828e Merge branch 'develop' into fedi-absturztau-be 2021-05-12 13:50:27 +02:00
Absturztaube c44f2bbcd6 Merge branch 'develop' into fedi-absturztau-be 2021-04-19 11:45:22 +02:00
Absturztaube 6064e31c5d Merge branch 'develop' into fedi-absturztau-be 2021-03-31 11:02:05 +02:00
Absturztaube 97113bc5df minor fix to sub menu in nav panel 2021-03-16 11:29:03 +01:00
Absturztaube 7f05730e9b resolve merge conflicts and update fixes 2021-03-16 11:20:22 +01:00
Absturztaube 6ef591bdcc Merge branch 'develop' into fedi-absturztau-be 2021-03-09 17:14:31 +01:00
Absturztaube 6e43a7d23c update readme 2021-02-28 01:03:48 +01:00
Absturztaube 862a5a86e7 compact user panel 2021-02-28 00:40:54 +01:00
Absturztaube f304fed1e9 added compact nav panel 2021-02-28 00:09:30 +01:00
Absturztaube 5ef3133f75 fix move notification column checkbox 2021-02-20 17:06:29 +01:00
Absturztaube 0cfd263ef4 Merge branch 'develop' into fedi-absturztau-be 2021-02-13 10:59:52 +01:00
Absturztaube 94c96345e1 fix language stuff 2021-01-30 10:58:06 +01:00
Absturztaube ba808076ca resolve merge conflicts 2021-01-30 10:22:55 +01:00
Absturztaube eaaa64dde8 ble 2021-01-09 20:06:06 +01:00
Absturztaube 6b6558d924 add changes in readme 2021-01-09 20:04:54 +01:00
Absturztaube ecd5d78bc2 add zero width space when padding of emojis is disabled 2021-01-09 19:58:30 +01:00
Absturztaube a85c1d562c resolve merge conflicts 2021-01-08 17:36:47 +01:00
Absturztaube 2a71d425cd change repo paths 2020-12-29 13:02:33 +01:00
Absturztaube 381c4e7f82 resolve merge conflicts 2020-12-29 13:00:48 +01:00
Absturztaube 026dc263e5 Merge branch 'develop' into fedi-absturztau-be 2020-12-16 12:00:58 +01:00
Absturztaube e15095d0dd Merge branch 'develop' into fedi-absturztau-be 2020-12-07 08:02:54 +01:00
Absturztaube ad728d9046 resolve conflichts 2020-12-04 20:45:10 +01:00
Absturztaube a6822d26bb Merge branch 'develop' into fedi-absturztau-be 2020-11-23 09:21:56 +01:00
Absturztaube 8065afc4d7 resolve merge conflicts 2020-11-08 14:04:17 +01:00
Absturztaube a43623c5a5 Merge branch 'develop' into fedi-absturztau-be 2020-10-29 09:24:25 +01:00
Absturztaube 7a9bd70a09 Merge branch 'develop' into fedi-absturztau-be 2020-10-07 18:51:14 +02:00
Absturztaube 575ce2c65e Merge branch 'develop' into fedi-absturztau-be 2020-09-11 20:47:04 +02:00
Absturztaube 07853ed322 Merge branch 'develop' into fedi-absturztau-be 2020-08-27 21:41:14 +02:00
Absturztaube aabd393e15 add settings for third column 2020-07-26 20:36:03 +02:00
Absturztaube 1e65016d71 fix flex 2020-07-26 12:50:47 +02:00
Absturztaube 2478d8b04e change width 2020-07-26 12:20:17 +02:00
Absturztaube 2e2a261e3d move features panel to the right 2020-07-26 12:15:00 +02:00
Absturztaube ee67b579c5 add 3rd column for testing 2020-07-26 12:10:06 +02:00
Absturztaube 6a77b27a42 resolve merge conflicts 2020-07-26 11:17:14 +02:00
Absturztaube e77cd1d625 fix pleroma-mod-loader ref 2020-07-08 22:10:04 +02:00
Absturztaube f2f11f7f63 add to language switcher 2020-07-08 21:57:34 +02:00
Absturztaube 7668321c98 add en nyan 2020-07-08 21:55:58 +02:00
Absturztaube 2cd6d336ba remove dublicate 2020-07-08 21:53:44 +02:00
Absturztaube ee45f689ac remove dublicate add mod loader 2020-07-08 21:48:08 +02:00
Absturztaube 7b0425c985 Merge branch 'direct-conversations' into fedi-absturztau-be 2020-07-08 21:45:23 +02:00
Absturztaube 7fa2dfecc6 Merge branch 'direct-conversations' of https://git.pleroma.social/eugenijm/pleroma-fe into direct-conversations 2020-07-08 19:16:44 +02:00
eugenijm 0d7d8e9f33 Submit on enter fixes 2020-05-30 20:26:24 +03:00
eugenijm f2b3d1e6b0 Use streaming for real time updates instead of notifications, disable
polling when streaming is enabled.
2020-05-30 17:59:35 +03:00
eugenijm 6c2c0883ce Use since_id when pulling the current chat messages 2020-05-30 13:47:48 +03:00
eugenijm fdef990c6a Submit on enter, start a new line on shift+enter 2020-05-29 09:43:52 +03:00
eugenijm 5fc9ef0bfb WIP chat fixes 2020-05-29 09:43:52 +03:00
eugenijm b05a86b280 WIP keep the on screen keyboard after a message send. 2020-05-29 09:43:52 +03:00
eugenijm 5996954c4a Reset the chat list on logout 2020-05-29 09:43:52 +03:00
eugenijm c82436cd8a WIP Chat refactoring 2020-05-29 09:43:52 +03:00
eugenijm 93049e9d52 WIP preserve scroll position during posting form resize, attachment upload, window resize, disable auto-focus for mobile 2020-05-29 09:43:52 +03:00
eugenijm 5f7494f134 Chat header alignment fixes for the mobile layout 2020-05-29 09:43:52 +03:00
eugenijm c1faeacee8 Set file limit in the chat posting form 2020-05-29 09:43:52 +03:00
eugenijm 6b272b9c99 WIP chat improvements 2020-05-29 09:43:52 +03:00
eugenijm 3dbe0d1e61 WIP display updated_at in the chat list, use updated_at to keep the chat list sorted 2020-05-29 09:43:52 +03:00
eugenijm cf4d3ee1bf WIP display attachment type in the last message 2020-05-29 09:43:52 +03:00
eugenijm c9870a9d43 WIP keep last_message updated 2020-05-29 09:43:52 +03:00
eugenijm 09da927def WIP chat refactoring 2020-05-29 09:43:52 +03:00
eugenijm 99de78b80e WIP chat 2020-05-29 09:43:52 +03:00
eugenijm d2456d5fea Chat message deletion 2020-05-29 09:43:52 +03:00
eugenijm 855f36eeda wip 2020-05-29 09:43:52 +03:00
eugenijm 1b51b02483 WIP chat fixes 2020-05-29 09:43:52 +03:00
eugenijm 6c487f0c58 WIP attachments 2020-05-29 09:43:52 +03:00
eugenijm fc3d7a7565 WIP: add custom emoji 2020-05-29 09:43:52 +03:00
eugenijm 8a8a9ad562 WIP notification count 2020-05-29 09:43:52 +03:00
eugenijm d48b7a7d58 WIP chat 2020-05-29 09:43:52 +03:00
eugenijm 5fdb5c554d WIP load chat messages on scroll up 2020-05-29 09:43:52 +03:00
eugenijm 86cc4ce08d WIP attachments 2020-05-29 09:43:52 +03:00
eugenijm c273560408 WIP display the last message in the chat list 2020-05-29 09:43:52 +03:00
eugenijm 0f3c667eb8 wip 2020-05-29 09:43:52 +03:00
eugenijm bd5b3e8922 wip 2020-05-29 09:43:52 +03:00
eugenijm aa1f2a1c3f wip 2020-05-29 09:43:52 +03:00
eugenijm 5e93ca3edb WIP chat avatars 2020-05-29 09:43:52 +03:00
eugenijm f06ec18cd7 Chat fixes 2020-05-29 09:43:52 +03:00
eugenijm 804cf3abc5 WIP: Chats 2020-05-29 09:43:52 +03:00
35 changed files with 1247 additions and 206 deletions

View File

@ -6,6 +6,19 @@ This is a fork of Akkoma-FE from the Pleroma project, with support for new Akkom
- MFM support via [marked-mfm](https://akkoma.dev/sfr/marked-mfm)
- Custom emoji reactions
# Changes in this Fork
* script tag in index.html for [pleroma-mod-loader](https://git.pleroma.social/absturztaube/pleroma-mod-loader)
* ability to move notifications to a seperate column
* insert zero width space when padding of emojis is disabled
* add custom language "English (Nyan)"
* pointing version links to my gitlab repos
* optional compact styles provided by craftplacer
* tags as buttons bellow a post
* [pinch and pan media](https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1403)
* swap of react and favorite button in status
* adding __vueComponent__ to DOM nodes to make new mods work
# For Translators
The [Weblate UI](https://translate.akkoma.dev/projects/akkoma/pleroma-fe/) is recommended for adding or modifying translations for Akkoma-FE.

View File

@ -21,7 +21,6 @@ var compiler = webpack(webpackConfig)
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
writeToDisk: true,
stats: {
colors: true,
chunks: false

View File

@ -18,5 +18,6 @@
<div id="app"></div>
<div id="modal"></div>
<!-- built files will be auto injected -->
<script type="text/javascript" src="/instance/pleroma-mod-loader.js"></script>
</body>
</html>

View File

@ -18,6 +18,8 @@ import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
import { applyTheme } from '../services/style_setter/style_setter.js'
import FaviconService from '../services/favicon_service/favicon_service.js'
import DomNodeToComponent from '../modules/domNodeToComponent.js'
let staticInitialResults = null
const parsedInitialResults = () => {
@ -422,6 +424,7 @@ const afterStoreSetup = async ({ store, i18n }) => {
app.use(vClickOutside)
app.use(VBodyScrollLock)
app.use(DomNodeToComponent)
app.component('FAIcon', FontAwesomeIcon)
app.component('FALayers', FontAwesomeLayers)

View File

@ -1,5 +1,4 @@
import StillImage from '../still-image/still-image.vue'
import Flash from '../flash/flash.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue'
import nsfwImage from '../../assets/nsfw.png'
import fileTypeService from '../../services/file_type/file_type.service.js'
@ -62,7 +61,6 @@ const Attachment = {
}
},
components: {
Flash,
StillImage,
VideoAttachment,
Blurhash

View File

@ -0,0 +1,108 @@
const ChatLayout = {
methods: {
setChatLayout () {
let body = document.querySelector('body')
if (body) {
body.style.overscrollBehavior = 'none'
}
if (this.isMobileLayout) {
this.setMobileChatLayout()
}
},
unsetChatLayout () {
this.unsetMobileChatLayout()
let body = document.querySelector('body')
if (body) {
body.style.overscrollBehavior = 'unset'
}
},
setMobileChatLayout () {
// This is a hacky way to adjust the global layout to the mobile chat (without modifying the rest of the app).
// This layout prevents empty spaces from being visible at the bottom
// of the chat on iOS Safari (`safe-area-inset`) when
// - the on-screen keyboard appears and the user starts typing
// - the user selects the text inside the input area
// - the user selects and deletes the text that is multiple lines long
// TODO: unify the chat layout with the global layout.
let html = document.querySelector('html')
if (html) {
html.style.overflow = 'hidden'
html.style.height = '100%'
}
let body = document.querySelector('body')
if (body) {
body.style.height = '100%'
}
let app = document.getElementById('app')
if (app) {
app.style.height = '100%'
app.style.overflow = 'hidden'
app.style.minHeight = 'auto'
}
let appBgWrapper = window.document.getElementById('app_bg_wrapper')
if (appBgWrapper) {
appBgWrapper.style.overflow = 'hidden'
}
let main = document.getElementsByClassName('main')[0]
if (main) {
main.style.overflow = 'hidden'
main.style.height = '100%'
}
let content = document.getElementById('content')
if (content) {
content.style.paddingTop = '0'
content.style.height = '100%'
content.style.overflow = 'visible'
}
this.$nextTick(() => {
this.updateSize()
})
},
unsetMobileChatLayout () {
let html = document.querySelector('html')
if (html) {
html.style.overflow = 'visible'
html.style.height = 'unset'
}
let body = document.querySelector('body')
if (body) {
body.style.height = 'unset'
}
let app = document.getElementById('app')
if (app) {
app.style.height = '100%'
app.style.overflow = 'visible'
app.style.minHeight = '100vh'
}
let appBgWrapper = document.getElementById('app_bg_wrapper')
if (appBgWrapper) {
appBgWrapper.style.overflow = 'visible'
}
let main = document.getElementsByClassName('main')[0]
if (main) {
main.style.overflow = 'visible'
main.style.height = 'unset'
}
let content = document.getElementById('content')
if (content) {
content.style.paddingTop = '60px'
content.style.height = 'unset'
content.style.overflow = 'unset'
}
}
}
}
export default ChatLayout

View File

@ -0,0 +1,34 @@
import StillImage from '../still-image/still-image.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { mapState } from 'vuex'
const ChatAvatar = {
props: ['users', 'fallbackUser', 'width', 'height'],
components: {
StillImage
},
methods: {
getUserProfileLink (user) {
return generateProfileLink(user.id, user.screen_name)
}
},
computed: {
firstUser () {
return this.users[0] || this.fallbackUser
},
secondUser () {
return this.users[1]
},
thirdUser () {
return this.users[2]
},
fourthUser () {
return this.users[3]
},
...mapState({
betterShadow: state => state.interface.browserSupport.cssFilter
})
}
}
export default ChatAvatar

View File

@ -0,0 +1,130 @@
<template>
<div
v-if="firstUser && secondUser"
class="direct-conversation-multi-user-avatar"
:style="{ 'width': width, 'height': height }"
>
<StillImage
v-if="fourthUser"
class="avatar avatar-fourth direct-conversation-avatar"
:alt="fourthUser.screen_name"
:title="fourthUser.screen_name"
:src="fourthUser.profile_image_url_original"
error-src="/images/avi.png"
:class="{ 'better-shadow': betterShadow }"
/>
<StillImage
v-if="thirdUser"
class="avatar avatar-third direct-conversation-avatar"
:alt="thirdUser.screen_name"
:title="thirdUser.screen_name"
:src="thirdUser.profile_image_url_original"
error-src="/images/avi.png"
:class="{ 'better-shadow': betterShadow }"
/>
<StillImage
class="avatar avatar-second direct-conversation-avatar"
:alt="secondUser.screen_name"
:title="secondUser.screen_name"
:src="secondUser.profile_image_url_original"
error-src="/images/avi.png"
:class="{ 'better-shadow': betterShadow }"
:style="{ 'height': fourthUser ? '50%' : '100%' }"
/>
<StillImage
class="avatar avatar-first direct-conversation-avatar"
:alt="firstUser.screen_name"
:title="firstUser.screen_name"
:src="firstUser.profile_image_url_original"
error-src="/images/avi.png"
:class="{ 'better-shadow': betterShadow }"
:style="{ 'height': thirdUser ? '50%' : '100%' }"
/>
</div>
<router-link
v-else
:to="getUserProfileLink(firstUser)"
>
<StillImage
:style="{ 'width': width, 'height': height }"
class="avatar direct-conversation-avatar single-user"
:alt="firstUser.screen_name"
:title="firstUser.screen_name"
:src="firstUser.profile_image_url_original"
error-src="/images/avi.png"
:class="{ 'better-shadow': betterShadow }"
/>
</router-link>
</template>
<script src="./chat_avatar.js"></script>
<style lang="scss">
@import '../../_variables.scss';
.direct-conversation-multi-user-avatar {
position: relative;
cursor: pointer;
width: 48px;
height: 48px;
border-radius: 50%;
overflow: hidden;
.avatar.still-image {
width: 50%;
height: 50%;
border-radius: 0;
img, canvas {
object-fit: cover;
}
&.avatar-first {
float: right;
position: absolute;
bottom: 0;
}
&.avatar-second {
float: right;
}
&.avatar-third {
float: right;
position: absolute;
}
&.avatar-fourth {
float: right;
position: absolute;
bottom: 0;
right: 0;
}
}
}
.direct-conversation-avatar {
display: inline-block;
vertical-align: middle;
&.single-user {
border-radius: $fallback--avatarAltRadius;
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
}
.avatar.still-image {
width: 48px;
height: 48px;
box-shadow: var(--avatarStatusShadow);
border-radius: 0;
&.better-shadow {
box-shadow: var(--avatarStatusShadowInset);
filter: var(--avatarStatusShadowFilter)
}
&.animated::before {
display: none;
}
}
}
</style>

View File

@ -18,7 +18,7 @@ export default {
if (this.date.getTime() === today.getTime()) {
return this.$t('display_date.today')
} else {
return this.date.toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale), { day: 'numeric', month: 'long' })
return this.date.toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale.split('_')[0]), { day: 'numeric', month: 'long' })
}
}
}

View File

@ -249,8 +249,8 @@ const EmojiInput = {
* them, masto seem to be rendering :emoji::emoji: correctly now so why not
*/
const isSpaceRegex = /\s/
const spaceBefore = (surroundingSpace && !isSpaceRegex.exec(before.slice(-1)) && before.length && this.padEmoji > 0) ? ' ' : ''
const spaceAfter = (surroundingSpace && !isSpaceRegex.exec(after[0]) && this.padEmoji) ? ' ' : ''
const spaceBefore = (surroundingSpace && !isSpaceRegex.exec(before.slice(-1)) && before.length && this.padEmoji > 0) ? ' ' : ''
const spaceAfter = (surroundingSpace && !isSpaceRegex.exec(after[0]) && this.padEmoji) ? ' ' : ''
const newValue = [
before,

View File

@ -1,53 +0,0 @@
import RuffleService from '../../services/ruffle_service/ruffle_service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faStop,
faExclamationTriangle
} from '@fortawesome/free-solid-svg-icons'
library.add(
faStop,
faExclamationTriangle
)
const Flash = {
props: [ 'src' ],
data () {
return {
player: false, // can be true, "hidden", false. hidden = element exists
loaded: false,
ruffleInstance: null
}
},
methods: {
openPlayer () {
if (this.player) return // prevent double-loading, or re-loading on failure
this.player = 'hidden'
RuffleService.getRuffle().then((ruffle) => {
const player = ruffle.newest().createPlayer()
player.config = {
letterbox: 'on'
}
const container = this.$refs.container
container.appendChild(player)
player.style.width = '100%'
player.style.height = '100%'
player.load(this.src).then(() => {
this.player = true
}).catch((e) => {
console.error('Error loading ruffle', e)
this.player = 'error'
})
this.ruffleInstance = player
this.$emit('playerOpened')
})
},
closePlayer () {
this.ruffleInstance && this.ruffleInstance.remove()
this.player = false
this.$emit('playerClosed')
}
}
}
export default Flash

View File

@ -1,84 +0,0 @@
<template>
<div class="Flash">
<div
v-if="player === true || player === 'hidden'"
ref="container"
class="player"
:class="{ hidden: player === 'hidden' }"
/>
<button
v-if="player !== true"
class="button-unstyled placeholder"
@click="openPlayer"
>
<span
v-if="player === 'hidden'"
class="label"
>
{{ $t('general.loading') }}
</span>
<span
v-if="player === 'error'"
class="label"
>
{{ $t('general.flash_fail') }}
</span>
<span
v-else
class="label"
>
<p>
{{ $t('general.flash_content') }}
</p>
<p>
<FAIcon icon="exclamation-triangle" />
{{ $t('general.flash_security') }}
</p>
</span>
</button>
</div>
</template>
<script src="./flash.js"></script>
<style lang="scss">
@import '../../_variables.scss';
.Flash {
display: inline-block;
width: 100%;
height: 100%;
position: relative;
.player {
height: 100%;
width: 100%;
}
.placeholder {
height: 100%;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: var(--bg);
color: var(--link);
}
.hider {
top: 0;
}
.label {
text-align: center;
flex: 1 1 0;
line-height: 1.2;
white-space: normal;
word-wrap: normal;
}
.hidden {
display: none;
visibility: 'hidden';
}
}
</style>

View File

@ -4,7 +4,6 @@ import Modal from '../modal/modal.vue'
import PinchZoom from '../pinch_zoom/pinch_zoom.vue'
import SwipeClick from '../swipe_click/swipe_click.vue'
import GestureService from '../../services/gesture_service/gesture_service'
import Flash from 'src/components/flash/flash.vue'
import fileTypeService from '../../services/file_type/file_type.service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
@ -27,8 +26,7 @@ const MediaModal = {
VideoAttachment,
PinchZoom,
SwipeClick,
Modal,
Flash
Modal
},
data () {
return {

View File

@ -48,13 +48,6 @@
:title="currentMedia.description"
controls
/>
<Flash
v-if="type === 'flash'"
class="modal-image"
:src="currentMedia.url"
:alt="currentMedia.description"
:title="currentMedia.description"
/>
<button
v-if="canNavigate"
:title="$t('media_modal.previous')"

View File

@ -47,6 +47,9 @@ const NavPanel = {
}
},
computed: {
compactNavPanel () {
return this.$store.getters.mergedConfig.compactNavPanel || false
},
...mapState({
currentUser: state => state.users.currentUser,
privateMode: state => state.instance.private,

View File

@ -1,5 +1,8 @@
<template>
<div class="NavPanel">
<div
class="NavPanel"
:class="{ compact: compactNavPanel }"
>
<div class="panel panel-default">
<ul>
<li v-if="currentUser || !privateMode">
@ -211,5 +214,83 @@
right: 0.6rem;
top: 1.25em;
}
&.compact {
.panel {
overflow: visible;
ul > li:hover > a:not(.router-link-active) > .button-icon {
color: var(--selectedMenuText,#b9b9ba);
}
ul > li > .router-link-active > .button-icon {
color: var(--selectedMenuLightText);
}
ul {
display: flex;
height: 100%;
padding: 0;
}
li {
width: -moz-available;
width: -webkit-fill-available;
border-bottom: none;
a {
border-radius: 0 !important;
}
}
.timelines-chevron {
display: none;
}
.timelines-background {
position: absolute;
z-index: 10000;
}
a, button {
font-size: 0;
height: 100%;
display: flex;
position: relative;
padding-top: 7px;
padding-bottom: 7px;
}
.button-icon, svg.svg-inline--fa {
margin: auto;
font-size: 20px;
color: var(--link,#d8a070);
}
.badge {
position: absolute;
right: 0;
background-color: red;
background-color: var(--badgeNotification,red);
color: #fff;
color: var(--badgeNotificationText,#fff);
// remove layout
padding: 0;
margin: 0;
box-shadow: black 0 1px 5px;
display: inline-block;
border-radius: 99px;
min-width: 22px;
line-height: 22px;
min-height: 22px;
max-height: 22px;
font-size: 14px;
font-weight: normal;
font-style: normal;
font-family: inherit;
}
}
}
}
</style>

View File

@ -1,9 +1,9 @@
import StatusContent from '../status_content/status_content.vue'
import { mapState } from 'vuex'
import Status from '../status/status.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import UserCard from '../user_card/user_card.vue'
import Timeago from '../timeago/timeago.vue'
import StatusContent from '../status_content/status_content.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import { isStatusNotification } from '../../services/notification_utils/notification_utils.js'

View File

@ -489,6 +489,7 @@ const PostStatusForm = {
}
},
addMediaFile (fileInfo) {
this.$emit('resize')
this.newStatus.files.push(fileInfo)
if (this.$store.getters.mergedConfig.sensitiveIfSubject && this.newStatus.spoilerText !== '') {
@ -497,6 +498,7 @@ const PostStatusForm = {
this.$emit('resize', { delayed: true })
},
removeMediaFile (fileInfo) {
this.$emit('resize')
let index = this.newStatus.files.indexOf(fileInfo)
this.newStatus.files.splice(index, 1)
this.$emit('resize')

View File

@ -616,4 +616,5 @@
border: 2px dashed var(--text, $fallback--text);
}
}
</style>

View File

@ -102,11 +102,41 @@
{{ $t('settings.hide_isp') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="showThirdColumn">
{{ $t('settings.show_third_column') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="sidebarRight">
{{ $t('settings.right_sidebar') }}
</BooleanSetting>
</li>
<li v-if="instanceWallpaperUsed">
<BooleanSetting path="hideInstanceWallpaper">
{{ $t('settings.hide_wallpaper') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="compactNavPanel">
{{ $t('settings.compact_nav_panel') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="compactUserPanel">
{{ $t('settings.compact_user_panel') }}
</BooleanSetting>
</li>
<li v-if="instanceShoutboxPresent">
<BooleanSetting path="hideShoutbox">
{{ $t('settings.hide_shoutbox') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('nav.timeline') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting
path="hideSiteFavicon"

View File

@ -48,7 +48,7 @@ const SecurityTab = {
return {
id: oauthToken.id,
appName: oauthToken.app_name,
validUntil: new Date(oauthToken.valid_until).toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale))
validUntil: new Date(oauthToken.valid_until).toLocaleDateString(localeService.internalToBrowserLocale(this.$i18n.locale.split('_')[0]))
}
})
}

View File

@ -1,7 +1,7 @@
import { extractCommit } from 'src/services/version/version.service'
const pleromaFeCommitUrl = 'https://akkoma.dev/AkkomaGang/pleroma-fe/commit/'
const pleromaBeCommitUrl = 'https://akkoma.dev/AkkomaGang/akkoma/commit/'
const pleromaFeCommitUrl = 'https://akkoma.dev/puniko/pleroma-fe/commit/'
const pleromaBeCommitUrl = 'https://akkoma.dev/puniko/akkoma/commits/'
const VersionTab = {
data () {

View File

@ -466,12 +466,16 @@
:logged-in="loggedIn"
:status="status"
/>
<ReactButton
v-if="swapReacts && loggedIn"
:status="status"
/>
<favorite-button
:logged-in="loggedIn"
:status="status"
/>
<ReactButton
v-if="loggedIn"
v-if="!swapReacts && loggedIn"
:status="status"
/>
<extra-buttons

View File

@ -34,7 +34,7 @@ export default {
},
computed: {
localeDateString () {
const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale).split('_')[0]
return typeof this.time === 'string'
? new Date(Date.parse(this.time)).toLocaleString(browserLocale)
: this.time.toLocaleString(browserLocale)

View File

@ -6,6 +6,9 @@ import { mapState } from 'vuex'
const UserPanel = {
computed: {
signedIn () { return this.user },
compactUserPanel () {
return this.$store.getters.mergedConfig.compactUserPanel || false
},
...mapState({ user: state => state.users.currentUser })
},
components: {

View File

@ -1,5 +1,8 @@
<template>
<div class="user-panel">
<div
class="user-panel"
:class="{ compact: compactUserPanel }"
>
<div
v-if="signedIn"
key="user-panel-signed"
@ -26,4 +29,22 @@
overflow: visible;
z-index: 10;
}
.user-panel.compact {
.background-image {
mask: unset; -webkit-mask: unset;
background-position: center;
}
.user-info .Avatar { width: 24px; height: 24px; }
.user-summary { margin-left: 1em; font-weight: bold; }
.user-info .container { padding-top: 6px; padding-bottom: 0; }
.bottom-line { display: none; }
.form-group .visibility-notice { margin: 0; }
}
</style>

775
src/i18n/en_nyan.json Normal file
View File

@ -0,0 +1,775 @@
{
"about": {
"mrf": {
"federation": "Federation",
"keyword": {
"keyword_policies": "Keyword Policies",
"ftl_removal": "Removal from \"The Whole Known Network\" Timeline",
"reject": "Reject",
"replace": "Replace",
"is_replaced_by": "→"
},
"mrf_policies": "Enabled MRF Policies",
"mrf_policies_desc": "MRF policies manipulate the federation behaviour of the instance. The following policies are enabled:",
"simple": {
"simple_policies": "Instance-specific Policies",
"accept": "Accept",
"accept_desc": "This instance only accepts messages from the following instances:",
"reject": "Reject",
"reject_desc": "This instance will not accept messages from the following instances:",
"quarantine": "Quarantine",
"quarantine_desc": "This instance will send only public posts to the following instances:",
"ftl_removal": "Removal from \"The Whole Known Network\" Timeline",
"ftl_removal_desc": "This instance removes these instances from \"The Whole Known Network\" timeline:",
"media_removal": "Media Removal",
"media_removal_desc": "This instance removes media from posts on the following instances:",
"media_nsfw": "Media Force-set As Sensitive",
"media_nsfw_desc": "This instance forces media to be set sensitive in posts on the following instances:"
}
},
"staff": "Staff"
},
"chat": {
"title": "Chat"
},
"domain_mute_card": {
"mute": "Mute",
"mute_progress": "Muting...",
"unmute": "Unmute",
"unmute_progress": "Unmuting..."
},
"exporter": {
"export": "Export",
"processing": "Processing, you'll soon be asked to download your file"
},
"features_panel": {
"chat": "Chat",
"gopher": "Gopher",
"media_proxy": "Media proxy",
"scope_options": "Scope options",
"text_limit": "Text limit",
"title": "Features",
"who_to_follow": "Who to follow"
},
"finder": {
"error_fetching_user": "Error fetching user",
"find_user": "Find user"
},
"general": {
"apply": "Apply",
"submit": "Nyan",
"more": "More",
"generic_error": "An error occured",
"optional": "optional",
"show_more": "Show more",
"show_less": "Show less",
"dismiss": "Dismiss",
"cancel": "Cancel",
"disable": "Disable",
"enable": "Enable",
"confirm": "Confirm",
"verify": "Verify"
},
"image_cropper": {
"crop_picture": "Crop picture",
"save": "Save",
"save_without_cropping": "Save without cropping",
"cancel": "Cancel"
},
"importer": {
"submit": "Submit",
"success": "Imported successfully.",
"error": "An error occured while importing this file."
},
"login": {
"login": "Log in",
"description": "Log in with OAuth",
"logout": "Log out",
"password": "Password",
"placeholder": "e.g. lain",
"register": "Register",
"username": "Username",
"hint": "Log in to join the discussion",
"authentication_code": "Authentication code",
"enter_recovery_code": "Enter a recovery code",
"enter_two_factor_code": "Enter a two-factor code",
"recovery_code": "Recovery code",
"heading" : {
"totp" : "Two-factor authentication",
"recovery" : "Two-factor recovery"
}
},
"media_modal": {
"previous": "Previous",
"next": "Next"
},
"nav": {
"about": "About",
"administration": "Administration",
"back": "Back",
"chat": "Local Chat",
"friend_requests": "Follow Requests",
"mentions": "Mentions",
"interactions": "Interactions",
"dms": "Direct Messages",
"public_tl": "Public Timeline",
"timeline": "Timeline",
"twkn": "The Whole Known Network",
"user_search": "User Search",
"search": "Search",
"who_to_follow": "Who to follow",
"preferences": "Preferences",
"chats": "Chats"
},
"notifications": {
"broken_favorite": "Unknown status, searching for it...",
"favorited_you": "patted your status",
"followed_you": "snuggled you",
"follow_request": "wants to snuggle you",
"load_older": "Load older notifications",
"notifications": "Notifications",
"read": "Read!",
"repeated_you": "renyaned your status",
"no_more_notifications": "No more notifications",
"migrated_to": "migrated to",
"reacted_with": "reacted with {0}"
},
"polls": {
"add_poll": "Add Poll",
"add_option": "Add Option",
"option": "Option",
"votes": "votes",
"vote": "Vote",
"type": "Poll type",
"single_choice": "Single choice",
"multiple_choices": "Multiple choices",
"expiry": "Poll age",
"expires_in": "Poll ends in {0}",
"expired": "Poll ended {0} ago",
"not_enough_options": "Too few unique options in poll"
},
"emoji": {
"stickers": "Stickers",
"emoji": "Emoji",
"keep_open": "Keep picker open",
"search_emoji": "Search for an emoji",
"add_emoji": "Insert emoji",
"custom": "Custom emoji",
"unicode": "Unicode emoji",
"load_all_hint": "Loaded first {saneAmount} emoji, loading all emoji may cause performance issues.",
"load_all": "Loading all {emojiAmount} emoji"
},
"interactions": {
"favs_repeats": "Renyans and Pats",
"follows": "New Snuggles",
"moves": "User migrates",
"load_older": "Load older interactions"
},
"post_status": {
"new_status": "Nyan new status",
"account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only nyans.",
"account_not_locked_warning_link": "locked",
"attachments_sensitive": "Mark attachments as sensitive",
"content_type": {
"text/plain": "Plain text",
"text/html": "HTML",
"text/markdown": "Markdown",
"text/bbcode": "BBCode"
},
"content_warning": "Subject (optional)",
"default": "A nyanbox to nyan",
"direct_warning_to_all": "This nyan will be visible to all the mentioned users.",
"direct_warning_to_first_only": "This nyan will only be visible to the mentioned users at the beginning of the message.",
"posting": "Nyaning",
"scope_notice": {
"public": "This nyan will be visible to everyone",
"private": "This nyan will be visible to your followers only",
"unlisted": "This nyan will not be visible in Public Timeline and The Whole Known Network"
},
"scope": {
"direct": "Direct - Nyan to mentioned users only",
"private": "Followers-only - Nyan to followers only",
"public": "Public - Nyan to public timelines",
"unlisted": "Unlisted - Do not nyan to public timelines"
}
},
"registration": {
"bio": "Bio",
"email": "Email",
"fullname": "Display name",
"password_confirm": "Password confirmation",
"registration": "Registration",
"token": "Invite token",
"captcha": "CAPTCHA",
"new_captcha": "Click the image to get a new captcha",
"username_placeholder": "e.g. lain",
"fullname_placeholder": "e.g. Lain Iwakura",
"bio_placeholder": "e.g.\nHi, I'm Lain.\nIm an anime girl living in suburban Japan. You may know me from the Wired.",
"validations": {
"username_required": "cannot be left blank",
"fullname_required": "cannot be left blank",
"email_required": "cannot be left blank",
"password_required": "cannot be left blank",
"password_confirmation_required": "cannot be left blank",
"password_confirmation_match": "should be the same as password"
}
},
"remote_user_resolver": {
"remote_user_resolver": "Remote user resolver",
"searching_for": "Searching for",
"error": "Not found."
},
"selectable_list": {
"select_all": "Select all"
},
"settings": {
"app_name": "App name",
"security": "Security",
"enter_current_password_to_confirm": "Enter your current password to confirm your identity",
"mfa": {
"otp" : "OTP",
"setup_otp" : "Setup OTP",
"wait_pre_setup_otp" : "presetting OTP",
"confirm_and_enable" : "Confirm & enable OTP",
"title": "Two-factor Authentication",
"generate_new_recovery_codes" : "Generate new recovery codes",
"warning_of_generate_new_codes" : "When you generate new recovery codes, your old codes wont work anymore.",
"recovery_codes" : "Recovery codes.",
"waiting_a_recovery_codes": "Receiving backup codes...",
"recovery_codes_warning" : "Write the codes down or save them somewhere secure - otherwise you won't see them again. If you lose access to your 2FA app and recovery codes you'll be locked out of your account.",
"authentication_methods" : "Authentication methods",
"scan": {
"title": "Scan",
"desc": "Using your two-factor app, scan this QR code or enter text key:",
"secret_code": "Key"
},
"verify": {
"desc": "To enable two-factor authentication, enter the code from your two-factor app:"
}
},
"allow_following_move": "Allow auto-follow when following account moves",
"attachmentRadius": "Attachments",
"attachments": "Attachments",
"autoload": "Enable automatic loading when scrolled to the bottom",
"avatar": "Avatar",
"avatarAltRadius": "Avatars (Notifications)",
"avatarRadius": "Avatars",
"background": "Background",
"bio": "Bio",
"block_export": "Block export",
"block_export_button": "Export your blocks to a csv file",
"block_import": "Block import",
"block_import_error": "Error importing blocks",
"blocks_imported": "Blocks imported! Processing them will take a while.",
"blocks_tab": "Blocks",
"btnRadius": "Buttons",
"cBlue": "Blue (Reply, follow)",
"cGreen": "Green (Retweet)",
"cOrange": "Orange (Favorite)",
"cRed": "Red (Cancel)",
"change_email": "Change Email",
"change_email_error": "There was an issue changing your email.",
"changed_email": "Email changed successfully!",
"change_password": "Change Password",
"change_password_error": "There was an issue changing your password.",
"changed_password": "Password changed successfully!",
"chatMessageRadius": "Chat message",
"collapse_subject": "Collapse posts with subjects",
"composing": "Composing",
"confirm_new_password": "Confirm new password",
"current_avatar": "Your current avatar",
"current_password": "Current password",
"current_profile_banner": "Your current profile banner",
"data_import_export_tab": "Data Import / Export",
"default_vis": "Default visibility scope",
"delete_account": "Delete Account",
"delete_account_description": "Permanently delete your data and deactivate your account.",
"delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.",
"delete_account_instructions": "Type your password in the input below to confirm account deletion.",
"discoverable": "Allow discovery of this account in search results and other services",
"domain_mutes": "Domains",
"avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",
"pad_emoji": "Pad emoji with spaces when adding from picker",
"emoji_reactions_on_timeline": "Show emoji reactions on timeline",
"export_theme": "Save preset",
"filtering": "Filtering",
"filtering_explanation": "All statuses containing these words will be muted, one per line",
"follow_export": "Follow export",
"follow_export_button": "Export your follows to a csv file",
"follow_import": "Follow import",
"follow_import_error": "Error importing followers",
"follows_imported": "Follows imported! Processing them will take a while.",
"accent": "Accent",
"foreground": "Foreground",
"general": "General",
"hide_attachments_in_convo": "Hide attachments in conversations",
"hide_attachments_in_tl": "Hide attachments in timeline",
"hide_muted_posts": "Hide posts of muted users",
"max_thumbnails": "Maximum amount of thumbnails per post",
"hide_isp": "Hide instance-specific panel",
"preload_images": "Preload images",
"use_one_click_nsfw": "Open NSFW attachments with just one click",
"hide_post_stats": "Hide post statistics (e.g. the number of favorites)",
"hide_user_stats": "Hide user statistics (e.g. the number of followers)",
"hide_filtered_statuses": "Hide filtered statuses",
"import_blocks_from_a_csv_file": "Import blocks from a csv file",
"import_followers_from_a_csv_file": "Import follows from a csv file",
"import_theme": "Load preset",
"inputRadius": "Input fields",
"checkboxRadius": "Checkboxes",
"instance_default": "(default: {value})",
"instance_default_simple": "(default)",
"interface": "Interface",
"interfaceLanguage": "Interface language",
"invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.",
"limited_availability": "Unavailable in your browser",
"links": "Links",
"lock_account_description": "Restrict your account to approved followers only",
"loop_video": "Loop videos",
"loop_video_silent_only": "Loop only videos without sound (i.e. Mastodon's \"gifs\")",
"mutes_tab": "Mutes",
"play_videos_in_modal": "Play videos in a popup frame",
"use_contain_fit": "Don't crop the attachment in thumbnails",
"name": "Name",
"name_bio": "Name & Bio",
"new_email": "New Email",
"new_password": "New password",
"notification_visibility": "Types of notifications to show",
"notification_visibility_follows": "Follows",
"notification_visibility_likes": "Likes",
"notification_visibility_mentions": "Mentions",
"notification_visibility_repeats": "Repeats",
"notification_visibility_moves": "User Migrates",
"notification_visibility_emoji_reactions": "Reactions",
"no_rich_text_description": "Strip rich text formatting from all posts",
"no_blocks": "No blocks",
"no_mutes": "No mutes",
"hide_follows_description": "Don't show who I'm following",
"hide_followers_description": "Don't show who's following me",
"hide_follows_count_description": "Don't show follow count",
"hide_followers_count_description": "Don't show follower count",
"show_admin_badge": "Show Admin badge in my profile",
"show_moderator_badge": "Show Moderator badge in my profile",
"nsfw_clickthrough": "Enable clickthrough NSFW attachment hiding",
"oauth_tokens": "OAuth tokens",
"token": "Token",
"refresh_token": "Refresh Token",
"valid_until": "Valid Until",
"revoke_token": "Revoke",
"panelRadius": "Panels",
"pause_on_unfocused": "Pause streaming when tab is not focused",
"presets": "Presets",
"profile_background": "Profile Background",
"profile_banner": "Profile Banner",
"profile_tab": "Profile",
"radii_help": "Set up interface edge rounding (in pixels)",
"replies_in_timeline": "Replies in timeline",
"reply_link_preview": "Enable reply-link preview on mouse hover",
"reply_visibility_all": "Show all replies",
"reply_visibility_following": "Only show replies directed at me or users I'm following",
"reply_visibility_self": "Only show replies directed at me",
"autohide_floating_post_button": "Automatically hide New Post button (mobile)",
"saving_err": "Error saving settings",
"saving_ok": "Settings saved",
"search_user_to_block": "Search whom you want to block",
"search_user_to_mute": "Search whom you want to mute",
"security_tab": "Security",
"scope_copy": "Copy scope when replying (DMs are always copied)",
"minimal_scopes_mode": "Minimize post scope selection options",
"set_new_avatar": "Set new avatar",
"set_new_profile_background": "Set new profile background",
"set_new_profile_banner": "Set new profile banner",
"settings": "Settings",
"subject_input_always_show": "Always show subject field",
"subject_line_behavior": "Copy subject when replying",
"subject_line_email": "Like email: \"re: subject\"",
"subject_line_mastodon": "Like mastodon: copy as is",
"subject_line_noop": "Do not copy",
"post_status_content_type": "Post status content type",
"stop_gifs": "Play-on-hover GIFs",
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
"user_mutes": "Users",
"useStreamingApi": "Receive posts and notifications real-time",
"useStreamingApiWarning": "(Not recommended, experimental, known to skip posts)",
"text": "Text",
"theme": "Theme",
"theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
"theme_help_v2_1": "You can also override certain component's colors and opacity by toggling the checkbox, use \"Clear all\" button to clear all overrides.",
"theme_help_v2_2": "Icons underneath some entries are background/text contrast indicators, hover over for detailed info. Please keep in mind that when using transparency contrast indicators show the worst possible case.",
"tooltipRadius": "Tooltips/alerts",
"type_domains_to_mute": "Type in domains to mute",
"upload_a_photo": "Upload a photo",
"user_settings": "User Settings",
"values": {
"false": "no",
"true": "yes"
},
"fun": "Fun",
"greentext": "Meme arrows",
"notifications": "Notifications",
"notification_setting_filters": "Filters",
"notification_setting": "Receive notifications from:",
"notification_setting_follows": "Users you follow",
"notification_setting_non_follows": "Users you do not follow",
"notification_setting_followers": "Users who follow you",
"notification_setting_non_followers": "Users who do not follow you",
"notification_setting_privacy": "Privacy",
"notification_setting_privacy_option": "Hide the sender and contents of push notifications",
"notification_mutes": "To stop receiving notifications from a specific user, use a mute.",
"notification_blocks": "Blocking a user stops all notifications as well as unsubscribes them.",
"enable_web_push_notifications": "Enable web push notifications",
"style": {
"switcher": {
"keep_color": "Keep colors",
"keep_shadows": "Keep shadows",
"keep_opacity": "Keep opacity",
"keep_roundness": "Keep roundness",
"keep_fonts": "Keep fonts",
"save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme. When all checkboxes unset, exporting theme will save everything.",
"reset": "Reset",
"clear_all": "Clear all",
"clear_opacity": "Clear opacity",
"load_theme": "Load theme",
"keep_as_is": "Keep as is",
"use_snapshot": "Old version",
"use_source": "New version",
"help": {
"upgraded_from_v2": "PleromaFE has been upgraded, theme could look a little bit different than you remember.",
"v2_imported": "File you imported was made for older FE. We try to maximize compatibility but there still could be inconsistencies.",
"future_version_imported": "File you imported was made in newer version of FE.",
"older_version_imported": "File you imported was made in older version of FE.",
"snapshot_present": "Theme snapshot is loaded, so all values are overriden. You can load theme's actual data instead.",
"snapshot_missing": "No theme snapshot was in the file so it could look different than originally envisioned.",
"fe_upgraded": "PleromaFE's theme engine upgraded after version update.",
"fe_downgraded": "PleromaFE's version rolled back.",
"migration_snapshot_ok": "Just to be safe, theme snapshot loaded. You can try loading theme data.",
"migration_napshot_gone": "For whatever reason snapshot was missing, some stuff could look different than you remember.",
"snapshot_source_mismatch": "Versions conflict: most likely FE was rolled back and updated again, if you changed theme using older version of FE you most likely want to use old version, otherwise use new version."
}
},
"common": {
"color": "Color",
"opacity": "Opacity",
"contrast": {
"hint": "Contrast ratio is {ratio}, it {level} {context}",
"level": {
"aa": "meets Level AA guideline (minimal)",
"aaa": "meets Level AAA guideline (recommended)",
"bad": "doesn't meet any accessibility guidelines"
},
"context": {
"18pt": "for large (18pt+) text",
"text": "for text"
}
}
},
"common_colors": {
"_tab_label": "Common",
"main": "Common colors",
"foreground_hint": "See \"Advanced\" tab for more detailed control",
"rgbo": "Icons, accents, badges"
},
"advanced_colors": {
"_tab_label": "Advanced",
"alert": "Alert background",
"alert_error": "Error",
"alert_warning": "Warning",
"alert_neutral": "Neutral",
"post": "Posts/User bios",
"badge": "Badge background",
"popover": "Tooltips, menus, popovers",
"badge_notification": "Notification",
"panel_header": "Panel header",
"top_bar": "Top bar",
"borders": "Borders",
"buttons": "Buttons",
"inputs": "Input fields",
"faint_text": "Faded text",
"underlay": "Underlay",
"poll": "Poll graph",
"icons": "Icons",
"highlight": "Highlighted elements",
"pressed": "Pressed",
"selectedPost": "Selected post",
"selectedMenu": "Selected menu item",
"disabled": "Disabled",
"toggled": "Toggled",
"tabs": "Tabs",
"chat": {
"incoming_background": "Incoming background",
"incoming_text": "Incoming text",
"incoming_link": "Incoming link",
"incoming_border": "Incoming border",
"outgoing_background": "Outgoing background",
"outgoing_text": "Outgoing text",
"outgoing_link": "Outgoing link",
"outgoing_border": "Outgoing border"
}
},
"radii": {
"_tab_label": "Roundness"
},
"shadows": {
"_tab_label": "Shadow and lighting",
"component": "Component",
"override": "Override",
"shadow_id": "Shadow #{value}",
"blur": "Blur",
"spread": "Spread",
"inset": "Inset",
"hintV3": "For shadows you can also use the {0} notation to use other color slot.",
"filter_hint": {
"always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.",
"drop_shadow_syntax": "{0} does not support {1} parameter and {2} keyword.",
"avatar_inset": "Please note that combining both inset and non-inset shadows on avatars might give unexpected results with transparent avatars.",
"spread_zero": "Shadows with spread > 0 will appear as if it was set to zero",
"inset_classic": "Inset shadows will be using {0}"
},
"components": {
"panel": "Panel",
"panelHeader": "Panel header",
"topBar": "Top bar",
"avatar": "User avatar (in profile view)",
"avatarStatus": "User avatar (in post display)",
"popup": "Popups and tooltips",
"button": "Button",
"buttonHover": "Button (hover)",
"buttonPressed": "Button (pressed)",
"buttonPressedHover": "Button (pressed+hover)",
"input": "Input field"
}
},
"fonts": {
"_tab_label": "Fonts",
"help": "Select font to use for elements of UI. For \"custom\" you have to enter exact font name as it appears in system.",
"components": {
"interface": "Interface",
"input": "Input fields",
"post": "Post text",
"postCode": "Monospaced text in a post (rich text)"
},
"family": "Font name",
"size": "Size (in px)",
"weight": "Weight (boldness)",
"custom": "Custom"
},
"preview": {
"header": "Preview",
"content": "Content",
"error": "Example error",
"button": "Button",
"text": "A bunch of more {0} and {1}",
"mono": "content",
"input": "Just landed in L.A.",
"faint_link": "helpful manual",
"fine_print": "Read our {0} to learn nothing useful!",
"header_faint": "This is fine",
"checkbox": "I have skimmed over terms and conditions",
"link": "a nice lil' link"
}
},
"version": {
"title": "Version",
"backend_version": "Backend Version",
"frontend_version": "Frontend Version"
}
},
"time": {
"day": "{0} day",
"days": "{0} days",
"day_short": "{0}d",
"days_short": "{0}d",
"hour": "{0} hour",
"hours": "{0} hours",
"hour_short": "{0}h",
"hours_short": "{0}h",
"in_future": "in {0}",
"in_past": "{0} ago",
"minute": "{0} minute",
"minutes": "{0} minutes",
"minute_short": "{0}min",
"minutes_short": "{0}min",
"month": "{0} month",
"months": "{0} months",
"month_short": "{0}mo",
"months_short": "{0}mo",
"now": "just now",
"now_short": "now",
"second": "{0} second",
"seconds": "{0} seconds",
"second_short": "{0}s",
"seconds_short": "{0}s",
"week": "{0} week",
"weeks": "{0} weeks",
"week_short": "{0}w",
"weeks_short": "{0}w",
"year": "{0} year",
"years": "{0} years",
"year_short": "{0}y",
"years_short": "{0}y"
},
"timeline": {
"collapse": "Collapse",
"conversation": "Conversation",
"error_fetching": "Error fetching updates",
"load_older": "Load older nyans",
"no_retweet_hint": "Nyan is marked as followers-only or direct and cannot be renyaned",
"repeated": "renyaned",
"show_new": "Show new",
"up_to_date": "Up-to-date",
"no_more_statuses": "No more statuses",
"no_statuses": "No statuses"
},
"status": {
"favorites": "Favorites",
"repeats": "Repeats",
"delete": "Delete status",
"pin": "Pin on profile",
"unpin": "Unpin from profile",
"pinned": "Pinned",
"delete_confirm": "Do you really want to delete this status?",
"reply_to": "Reply to",
"replies_list": "Replies:",
"mute_conversation": "Mute conversation",
"unmute_conversation": "Unmute conversation",
"status_unavailable": "Status unavailable",
"copy_link": "Copy link to status"
},
"user_card": {
"approve": "Approve",
"block": "Block",
"blocked": "Blocked!",
"deny": "Deny",
"favorites": "Favorites",
"follow": "Follow",
"follow_sent": "Request sent!",
"follow_progress": "Requesting…",
"follow_again": "Send request again?",
"follow_unfollow": "Unfollow",
"followees": "Following",
"followers": "Followers",
"following": "Following!",
"follows_you": "Follows you!",
"hidden": "Hidden",
"its_you": "It's you!",
"media": "Media",
"mention": "Mention",
"message": "Message",
"mute": "Mute",
"muted": "Muted",
"per_day": "per day",
"remote_follow": "Remote follow",
"report": "Report",
"statuses": "Statuses",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"unblock": "Unblock",
"unblock_progress": "Unblocking...",
"block_progress": "Blocking...",
"unmute": "Unmute",
"unmute_progress": "Unmuting...",
"mute_progress": "Muting...",
"hide_repeats": "Hide repeats",
"show_repeats": "Show repeats",
"admin_menu": {
"moderation": "Moderation",
"grant_admin": "Grant Admin",
"revoke_admin": "Revoke Admin",
"grant_moderator": "Grant Moderator",
"revoke_moderator": "Revoke Moderator",
"activate_account": "Activate account",
"deactivate_account": "Deactivate account",
"delete_account": "Delete account",
"force_nsfw": "Mark all posts as NSFW",
"strip_media": "Remove media from posts",
"force_unlisted": "Force posts to be unlisted",
"sandbox": "Force posts to be followers-only",
"disable_remote_subscription": "Disallow following user from remote instances",
"disable_any_subscription": "Disallow following user at all",
"quarantine": "Disallow user posts from federating",
"delete_user": "Delete user",
"delete_user_confirmation": "Are you absolutely sure? This action cannot be undone."
}
},
"user_profile": {
"timeline_title": "User Timeline",
"profile_does_not_exist": "Sorry, this profile does not exist.",
"profile_loading_error": "Sorry, there was an error loading this profile."
},
"user_reporting": {
"title": "Reporting {0}",
"add_comment_description": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
"additional_comments": "Additional comments",
"forward_description": "The account is from another server. Send a copy of the report there as well?",
"forward_to": "Forward to {0}",
"submit": "Submit",
"generic_error": "An error occurred while processing your request."
},
"who_to_follow": {
"more": "More",
"who_to_follow": "Who to follow"
},
"tool_tip": {
"media_upload": "Upload Media",
"repeat": "Renyan",
"reply": "Reply",
"favorite": "Pat",
"add_reaction": "Add Reaction",
"user_settings": "User Settings",
"accept_follow_request": "Accept snuggle request",
"reject_follow_request": "Reject snuggle request"
},
"upload":{
"error": {
"base": "Upload failed.",
"file_too_big": "File too big [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Try again later"
},
"file_size_units": {
"B": "B",
"KiB": "KiB",
"MiB": "MiB",
"GiB": "GiB",
"TiB": "TiB"
}
},
"search": {
"people": "People",
"hashtags": "Hashtags",
"person_talking": "{count} person talking",
"people_talking": "{count} people talking",
"no_results": "No results"
},
"password_reset": {
"forgot_password": "Forgot password?",
"password_reset": "Password reset",
"instruction": "Enter your email address or username. We will send you a link to reset your password.",
"placeholder": "Your email or username",
"check_email": "Check your email for a link to reset your password.",
"return_home": "Return to the home page",
"not_found": "We couldn't find that email or username.",
"too_many_requests": "You have reached the limit of attempts, try again later.",
"password_reset_disabled": "Password reset is disabled. Please contact your instance administrator.",
"password_reset_required": "You must reset your password to log in.",
"password_reset_required_but_mailer_is_disabled": "You must reset your password, but password reset is disabled. Please contact your instance administrator."
},
"chats": {
"message_user": "Message {nickname}",
"write_message": "Write a message",
"delete": "Delete",
"chats": "Chats",
"new": "New Chat",
"empty_message_error": "Cannot post empty message",
"more": "More",
"delete_confirm": "Do you really want to delete this message?"
},
"file_type": {
"audio": "Audio",
"video": "Video",
"image": "Image",
"file": "File"
},
"display_date": {
"today": "Today"
}
}

View File

@ -8,6 +8,7 @@
// There's only problem that apostrophe character ' gets replaced by \\ so you have to fix it manually, sorry.
const loaders = {
en_nyan: () => import('./en_nyan.json'),
ar: () => import('./ar.json'),
ca: () => import('./ca.json'),
cs: () => import('./cs.json'),

View File

@ -27,6 +27,9 @@ export const defaultState = {
colors: {},
theme: undefined,
customTheme: undefined,
showThirdColumn: false,
compactNavPanel: false,
compactUserPanel: false,
customThemeSource: undefined,
hideISP: false,
hideInstanceWallpaper: false,
@ -38,6 +41,7 @@ export const defaultState = {
muteBotStatuses: undefined, // instance default
collapseMessageWithSubject: true, // instance default
padEmoji: true,
swapReacts: true,
showNavShortcuts: undefined, // instance default
showPanelNavShortcuts: undefined, // instance default
showWiderShortcuts: undefined, // instance default

View File

@ -0,0 +1,9 @@
export default {
install: (Vue, options) => {
Vue.mixin({
mounted () {
this.$el.__vueComponent__ = this
}
})
}
}

View File

@ -717,6 +717,14 @@ const statuses = {
commit('dismissNotification', { id })
rootState.api.backendInteractor.dismissNotification({ id })
},
markMultipleNotificationsAsSeen ({ rootState, commit }, { finder }) {
const notifications = rootState.statuses.notifications.data.filter(finder)
notifications.forEach(n => {
commit('markSingleNotificationAsSeen', { id: n.id })
rootState.api.backendInteractor.markNotificationsAsSeen({ id: n.id, single: true })
})
},
updateNotification ({ rootState, commit }, { id, updater }) {
commit('updateNotification', { id, updater })
},

View File

@ -2,10 +2,6 @@
// or the entire service could be just mimetype service that only operates
// on mimetypes and not files. Currently the naming is confusing.
const fileType = mimetype => {
if (mimetype.match(/flash/)) {
return 'flash'
}
if (mimetype.match(/text\/html/)) {
return 'html'
}

View File

@ -3,6 +3,7 @@ import ISO6391 from 'iso-639-1'
import _ from 'lodash'
const specialLanguageCodes = {
'en_nyan': 'en-NYAN',
'ja_easy': 'ja',
'zh_Hant': 'zh-HANT',
'zh': 'zh-Hans'
@ -14,6 +15,7 @@ const internalToBackendLocale = code => internalToBrowserLocale(code).replace('_
const getLanguageName = (code) => {
const specialLanguageNames = {
'en_nyan': 'English (Nyan)',
'ja_easy': 'やさしいにほんご',
'zh': '简体中文',
'zh_Hant': '繁體中文'

View File

@ -1,40 +0,0 @@
const createRuffleService = () => {
let ruffleInstance = null
const getRuffle = () => new Promise((resolve, reject) => {
if (ruffleInstance) {
resolve(ruffleInstance)
return
}
// Ruffle needs these to be set before it's loaded
// https://github.com/ruffle-rs/ruffle/issues/3952
window.RufflePlayer = {}
window.RufflePlayer.config = {
polyfills: false,
publicPath: '/static/ruffle'
}
// Currently it's seems like a better way of loading ruffle
// because it needs the wasm publically accessible, but it needs path to it
// and filename of wasm seems to be pseudo-randomly generated (is it a hash?)
const script = document.createElement('script')
// see webpack config, using CopyPlugin to copy it from node_modules
// provided via ruffle-mirror
script.src = '/static/ruffle/ruffle.js'
script.type = 'text/javascript'
script.onerror = (e) => { reject(e) }
script.onabort = (e) => { reject(e) }
script.oncancel = (e) => { reject(e) }
script.onload = () => {
ruffleInstance = window.RufflePlayer
resolve(ruffleInstance)
}
document.body.appendChild(script)
})
return { getRuffle }
}
const RuffleService = createRuffleService()
export default RuffleService

View File

@ -115,7 +115,8 @@
"cOrange": "#f67400",
"btnPressed": "--accent",
"selectedMenu": "--accent",
"selectedMenuPopover": "--accent"
"selectedMenuPopover": "--accent",
"chatMessageIncomingBorder": "#3d4349"
},
"radii": {
"btn": "2",