Compare commits

...

208 commits

Author SHA1 Message Date
HJ
96a24ec625 Merge branch 'fix-discoverable-setting' into 'develop'
fix "allow discovery" setting misbehaving

See merge request pleroma/pleroma-fe!1518
2022-04-29 07:56:18 +00:00
Henry Jameson
91f833d1f0 fix "allow discovery" setting misbehaving 2022-04-29 10:52:16 +03:00
HJ
92b04ba7df Merge branch 'fix-chat-errors' into 'develop'
fix some chat errors/warnings that sometimes happen

See merge request pleroma/pleroma-fe!1515
2022-04-20 17:27:01 +00:00
Henry Jameson
895eda3714 fix some chat errors/warnings that sometimes happen 2022-04-20 20:19:22 +03:00
HJ
fb63e81ed1 Merge branch 'from/develop/tusooa/1157-popover-trigger' into 'develop'
Fix incorrect close of a status popover when clicking Expand inside it

Closes #1157

See merge request pleroma/pleroma-fe!1514
2022-04-20 09:15:18 +00:00
Tusooa Zhu
a4ea0a30bf
Fix incorrect close of a status popover when clicking Expand inside it
basically Vue (3 in particular?) will make changes to DOM before this event
listener is called, and if the target is displayed using v-if, it will not
be part of the DOM at that time, and contains() will return false. so it
goes to call hidePopover() which caused this bug.
2022-04-19 20:24:24 -04:00
HJ
1041a38f14 Merge branch 'fix-hashtags' into 'develop'
fix hashtags by explicitly putting attributes

See merge request pleroma/pleroma-fe!1513
2022-04-12 16:09:33 +00:00
Henry Jameson
0bb69d7fe0 fix tests 2022-04-12 19:04:32 +03:00
Henry Jameson
d175e86901 fix hashtags by explicitly putting attributes 2022-04-12 18:10:19 +03:00
HJ
c2a4051d72 Merge branch 'from/develop/tusooa/cropper-close' into 'develop'
Fix image cropper not closing correctly

See merge request pleroma/pleroma-fe!1512
2022-04-10 17:40:52 +00:00
Tusooa Zhu
169d13680a
Fix image cropper not closing correctly 2022-04-10 13:02:45 -04:00
HJ
4d15cbcbbd Merge branch 'from/develop/tusooa/1158-hidden-tabs' into 'develop'
Fix tab switcher not working when some tabs hidden

Closes #1158

See merge request pleroma/pleroma-fe!1511
2022-04-10 06:32:41 +00:00
Tusooa Zhu
3b02566e16
Fix tab switcher not working when some tabs hidden 2022-04-09 23:50:29 -04:00
HJ
87311cff09 Merge branch 'from/develop/tusooa/mobile-nav-link-col' into 'develop'
Fix mobile nav link text colour

See merge request pleroma/pleroma-fe!1510
2022-04-07 21:12:17 +00:00
Tusooa Zhu
6951fda0d6
Fix mobile nav link text colour 2022-04-07 15:59:03 -04:00
HJ
2d99cbc640 Merge branch 'from/develop/tusooa/1160-rm-shrug' into 'develop'
Fix shrug text in muted status

Closes #1160

See merge request pleroma/pleroma-fe!1509
2022-04-07 15:50:51 +00:00
Tusooa Zhu
22c70ae22a
Fix shrug text in muted status 2022-04-07 11:45:23 -04:00
HJ
d8324dd80b Merge branch 'from/develop/tusooa/shoutbox-icon-paneltext' into 'develop'
Use panel text instead of text for shoutbox icon

See merge request pleroma/pleroma-fe!1508
2022-04-07 07:24:40 +00:00
HJ
caacaf238c Merge branch 'from/develop/tusooa/popover-in-panel-style' into 'develop'
Fix popover in panel header styling

See merge request pleroma/pleroma-fe!1507
2022-04-07 07:24:22 +00:00
HJ
e4b8aaece6 Merge branch 'from/develop/tusooa/fix-shout-local' into 'develop'
Fix phoenix sockets in dev mode

See merge request pleroma/pleroma-fe!1506
2022-04-07 07:23:06 +00:00
HJ
bfc7b6af8f Merge branch 'from/develop/tusooa/1156-vue3-shoutbox' into 'develop'
Fix no reactivity on vuex 4 values

Closes #1156

See merge request pleroma/pleroma-fe!1505
2022-04-07 07:01:09 +00:00
Tusooa Zhu
fce9c5eeb2
Fix active popover style 2022-04-06 22:50:46 -04:00
Tusooa Zhu
6de87e8b65
Use panel text instead of text for shoutbox icon 2022-04-06 20:30:23 -04:00
Tusooa Zhu
041c72b07c
Fix dropdown menu style inside panel header 2022-04-06 20:14:17 -04:00
Tusooa Zhu
741a59e0cc
Fix phoenix sockets in dev mode
phoenix requires the Origin header to be set to the actual address,
so "http://localhost:xxxx" will not work.
2022-04-06 18:52:16 -04:00
Tusooa Zhu
4ddb6189dc
Fix no reactivity on vuex 4 values 2022-04-06 17:17:47 -04:00
HJ
0e56ac1c2b Merge branch 'fix-csp-vue3' into 'develop'
Makes develop usable on stock PleromaBE

See merge request pleroma/pleroma-fe!1504
2022-04-06 15:48:33 +00:00
Henry Jameson
853f5145be fix tegulu 2022-04-06 18:43:47 +03:00
Henry Jameson
b213d25711 heck 2022-04-06 15:48:07 +03:00
Henry Jameson
bd77f3a1a6 fix i18n for good?? 2022-04-06 15:45:44 +03:00
Henry Jameson
78817e37f7 force runtime build of i18n 2022-04-06 11:43:30 +03:00
Henry Jameson
2b0dd2cbae fix CSP by compiling the i18n templates as well 2022-04-05 23:45:26 +03:00
HJ
a613447105 Merge branch 'from/develop/tusooa/phoenix-1.6.2' into 'develop'
Fix phoenix at 1.6.2

See merge request pleroma/pleroma-fe!1502
2022-04-01 13:03:13 +00:00
Tusooa Zhu
a3233e31d0
Fix phoenix at 1.6.2
According to https://github.com/phoenixframework/phoenix/issues/4623 ,
1.6.2 seems to not have the disconnection bug.
2022-04-01 08:44:18 -04:00
HJ
f71f101fce Merge branch 'vue3-again' into 'develop'
Migration to Vue 3 (again)

See merge request pleroma/pleroma-fe!1385
2022-03-31 17:45:29 +00:00
HJ
afdc61b9b7 Merge branch 'vue3-no-compat' into 'vue3-again'
Remove Vue3 compat build

See merge request pleroma/pleroma-fe!1500
2022-03-31 17:39:08 +00:00
HJ
1d1ea7e703 Merge branch 'from/develop/tusooa/fix-feat-shoutbox-en' into 'develop'
Fix English translation of Shoutbox in features panel

See merge request pleroma/pleroma-fe!1489
2022-03-30 21:40:19 +00:00
Henry Jameson
052ad2fe3f Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  oops
2022-03-30 23:54:21 +03:00
Henry Jameson
a0099ecb66 oops 2022-03-30 23:54:11 +03:00
Henry Jameson
9940739f1f Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  fix some mishaps i noticed during self-review
2022-03-30 23:52:24 +03:00
Henry Jameson
afbe1a96ac fix some mishaps i noticed during self-review 2022-03-30 23:48:06 +03:00
Henry Jameson
e029c2864f Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  fix importer
2022-03-30 18:00:48 +03:00
Henry Jameson
dadf2f407f fix importer 2022-03-30 18:00:37 +03:00
Henry Jameson
6751c22a23 Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  make all clickable icons into actual buttons
2022-03-30 13:13:41 +03:00
Henry Jameson
1943991077 make all clickable icons into actual buttons 2022-03-30 12:34:27 +03:00
Henry Jameson
115170f35d Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  fix emoji input warning spam
  fix error clear icon
  Add controlledShowingLongSubject and toggle in StatusContent props
2022-03-30 01:26:35 +03:00
Henry Jameson
c3690b456e fix emoji input warning spam 2022-03-30 01:24:53 +03:00
Henry Jameson
70593e71e6 fix error clear icon 2022-03-30 01:24:17 +03:00
HJ
1c60609547 Merge branch 'vue3-again' into 'vue3-again'
Add controlledShowingLongSubject and toggle in StatusContent props

See merge request pleroma/pleroma-fe!1499
2022-03-29 18:13:27 +00:00
Tusooa Zhu
b84acfd7b7
Add controlledShowingLongSubject and toggle in StatusContent props 2022-03-29 13:56:42 -04:00
Henry Jameson
97e072d93a how did this get back?? 2022-03-29 20:23:44 +03:00
Henry Jameson
2179054384 Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  fix warning about custom component
  fix?
  fix some issues with trees
  removing uselsess stuff
  fix reset buttons in profile again
  fix spacing in poll expiration label
  registration fixes
2022-03-29 20:00:59 +03:00
Henry Jameson
a3f48fc3f4 fix warning about custom component 2022-03-29 19:55:30 +03:00
Henry Jameson
de2f968645 fix? 2022-03-29 19:44:07 +03:00
Henry Jameson
e1483488c7 fix some issues with trees 2022-03-29 19:23:30 +03:00
Henry Jameson
a1822f073d removing uselsess stuff 2022-03-29 19:21:13 +03:00
Henry Jameson
218b15b5fd fix reset buttons in profile again 2022-03-29 19:12:57 +03:00
Henry Jameson
bc029b0fa2 fix spacing in poll expiration label 2022-03-29 19:04:01 +03:00
Henry Jameson
2d7f242713 remove unused props to fix test 2022-03-29 16:33:34 +03:00
Henry Jameson
0afc955ebd registration fixes 2022-03-29 16:08:57 +03:00
Henry Jameson
e80e53d9d2 Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  re-fix i18n warnings again
  fix qr code
2022-03-29 16:00:56 +03:00
Henry Jameson
afcfcce2e6 re-fix i18n warnings again 2022-03-29 15:46:21 +03:00
Henry Jameson
3171241c6f fix qr code 2022-03-29 15:44:42 +03:00
Henry Jameson
3e0bb91ff2 Merge branch 'vue3-again' into vue3-no-compat
* vue3-again:
  lint + fixes for registration
  fix production build's reply not working in tree mode
  lock down version?
  manual lint
  Revert "fix weird thing i somehow missed"
  Revert "lint"
  fix weird thing i somehow missed
  lint
2022-03-29 15:35:47 +03:00
Henry Jameson
5bbc0e0bb5 lint + fixes for registration 2022-03-29 15:35:18 +03:00
Henry Jameson
3799983d4f fix production build's reply not working in tree mode 2022-03-29 12:43:42 +03:00
Henry Jameson
3f04ebd89a lock down version? 2022-03-29 12:27:59 +03:00
Henry Jameson
b93e5437bd manual lint 2022-03-29 12:04:09 +03:00
Henry Jameson
64d56e6515 Revert "fix weird thing i somehow missed"
This reverts commit b132581b3a.
2022-03-29 11:59:00 +03:00
Henry Jameson
d9d4d8954e Revert "lint"
This reverts commit f20ae34400.
2022-03-29 11:57:54 +03:00
Henry Jameson
b132581b3a fix weird thing i somehow missed 2022-03-29 11:47:22 +03:00
Henry Jameson
f20ae34400 lint 2022-03-29 01:04:37 +03:00
Henry Jameson
dc8bef7928 remove compat build 2022-03-29 00:58:17 +03:00
Henry Jameson
650e69c336 fix misc warnings 2022-03-29 00:02:02 +03:00
Henry Jameson
f21dc21a83 properly implement resettableAsyncComponent 2022-03-28 23:55:57 +03:00
Henry Jameson
9afbb12f95 fix opacity control again 2022-03-28 23:55:11 +03:00
Henry Jameson
7b10e47b21 rename some binding hooks according to new names 2022-03-28 23:54:30 +03:00
Henry Jameson
4b630c3c36 fix warnings 2022-03-28 17:37:26 +03:00
Henry Jameson
bdd240a230 fix some more warnings 2022-03-28 17:21:42 +03:00
Henry Jameson
c57af7e242 remove some warnings 2022-03-28 17:13:48 +03:00
Henry Jameson
f706234d77 fix being unable to set/reset background (and possibly avatar/banner) 2022-03-28 15:01:34 +03:00
Henry Jameson
805615d52b fix background not showing 2022-03-28 14:26:50 +03:00
Henry Jameson
8424b772b0 fix tabs in search 2022-03-27 14:43:16 +03:00
Henry Jameson
115f38c422 fix optional color inputs 2022-03-27 14:20:55 +03:00
Henry Jameson
48fd8a66ad fix opacity control 2022-03-27 14:18:02 +03:00
Henry Jameson
53cde52027 fix font control 2022-03-27 14:16:23 +03:00
Henry Jameson
75f6506bc7 fix (You) spacing 2022-03-27 14:10:45 +03:00
Henry Jameson
1d77063a4b fix shadow control in theme tab 2022-03-27 13:45:02 +03:00
Henry Jameson
ccd7378347 fix (roundness) ranges in theme tab 2022-03-27 13:31:56 +03:00
Henry Jameson
8e711e0587 get rid of portal-vue 2022-03-27 12:59:15 +03:00
Henry Jameson
87d420a92b port !1488 to vue3 2022-03-27 12:58:28 +03:00
Henry Jameson
d6bbccdd71 Merge remote-tracking branch 'origin/develop' into vue3-again
* origin/develop:
  Remove debugging code
  Fix overlapping buttons in Theme settings
  Update dependency ruffle-mirror to v2021.12.31
  Update dependency babel-loader to v8.2.4
2022-03-27 12:50:00 +03:00
Henry Jameson
913749739f fix user-list-popover 2022-03-27 12:29:28 +03:00
Henry Jameson
0b7a8dca15 fix duplicate setting (most likely a merge issue) 2022-03-27 12:26:51 +03:00
Henry Jameson
dd4672dc9a fix opening directly to filtering tab not working 2022-03-27 12:24:38 +03:00
Henry Jameson
9ac7046521 Fix notices not disappearing on their own 2022-03-27 12:21:33 +03:00
Henry Jameson
e4c804fac0 fix another spacing issue 2022-03-27 12:03:31 +03:00
HJ
fd77c583bf Merge branch 'from/develop/tusooa/fix-overlap-button' into 'develop'
Fix overlapping buttons in Theme settings

See merge request pleroma/pleroma-fe!1488
2022-03-25 13:22:06 +00:00
HJ
b319c0c72b Remove debugging code 2022-03-25 13:17:22 +00:00
Tusooa Zhu
c5551e834b
Fix English translation of Shoutbox in features panel 2022-03-24 19:28:15 -04:00
Tusooa Zhu
e58422889b
Fix overlapping buttons in Theme settings 2022-03-24 18:03:13 -04:00
Henry Jameson
b7755314b1 fix forms closing in timelines 2022-03-24 14:09:25 +02:00
Henry Jameson
3fb647b34b fix minor renames 2022-03-24 13:50:22 +02:00
Henry Jameson
0eb9c019e4 woah ima stupid 2022-03-24 13:41:52 +02:00
HJ
aa0b2e0723 Merge branch 'renovate/ruffle-mirror-2021.x' into 'develop'
Update dependency ruffle-mirror to v2021.12.31

See merge request pleroma/pleroma-fe!1486
2022-03-24 10:10:03 +00:00
Henry Jameson
4539feed40 fix checkboxes, specifically the NSFW one 2022-03-24 11:41:39 +02:00
Pleroma Renovate Bot
20c14a1d99 Update dependency ruffle-mirror to v2021.12.31 2022-03-24 09:05:00 +00:00
Henry Jameson
9793002070 cleanup console log 2022-03-23 16:53:57 +02:00
Henry Jameson
01d8fa4e54 fix i18n at places 2022-03-23 16:32:53 +02:00
Henry Jameson
961ca3a71b fix all the spacings i could find 2022-03-23 16:15:05 +02:00
Henry Jameson
08811e5a27 fix spacings in notifications 2022-03-23 16:08:45 +02:00
Henry Jameson
a6fae395da fix dupe id 2022-03-23 16:05:53 +02:00
Henry Jameson
d690b88c1c fix animations 2022-03-23 15:53:36 +02:00
Henry Jameson
322ec8681a cleanup 2022-03-23 15:44:37 +02:00
HJ
e1bfa6fbd3 Merge branch 'renovate/babel-monorepo' into 'develop'
Update dependency babel-loader to v8.2.4

See merge request pleroma/pleroma-fe!1484
2022-03-23 13:04:33 +00:00
Pleroma Renovate Bot
db0e1a2534 Update dependency babel-loader to v8.2.4 2022-03-23 09:05:04 +00:00
Henry Jameson
d524e98348 fix capitalization (and localization of tooltips for scope icon) 2022-03-22 20:42:29 +02:00
Henry Jameson
7afa6c9f40 listeners aren't actually used 2022-03-22 20:22:28 +02:00
Henry Jameson
538903f9d8 fix selects in settings screen 2022-03-22 20:17:25 +02:00
Henry Jameson
c5a6f40dff fix tabs not being able to be "disabled" 2022-03-22 20:15:21 +02:00
Henry Jameson
b817e09ee8 fix avatars not opening inline card 2022-03-22 19:43:11 +02:00
Henry Jameson
6b5791fda6 fix other weird route 2022-03-22 19:20:12 +02:00
Henry Jameson
3250e59266 fix routes test 2022-03-22 18:56:54 +02:00
Henry Jameson
e5ae0671ce skip user profile test for now https://github.com/vuejs/test-utils/issues/1382 2022-03-22 18:56:39 +02:00
Henry Jameson
9d7a7e2019 fix emoji input tests 2022-03-22 18:22:23 +02:00
Henry Jameson
c2cf13fc00 fix richcontent and its tests 2022-03-22 18:22:23 +02:00
Henry Jameson
c3546ea856 fix tests running 2022-03-22 18:22:23 +02:00
Henry Jameson
edb66ecade fix mobile post button being too square 2022-03-22 16:39:27 +02:00
Henry Jameson
c6a4a0a320 Merge remote-tracking branch 'origin/develop' into vue3-again
* origin/develop:
  quick fix for alignment in avatars, juggling multiple branches is confusing
  fix even more issues with avatars
  Update dependency ora to v0.4.1
  Update dependency mini-css-extract-plugin to v0.12.0
  Update dependency karma-firefox-launcher to v1.3.0
  fix avatars in mobile view
2022-03-22 12:14:02 +02:00
HJ
6a31962ca0 Merge branch 'fix-avatars3' into 'develop'
quick fix for alignment in avatars

See merge request pleroma/pleroma-fe!1483
2022-03-22 10:03:17 +00:00
Henry Jameson
fa99abf106 quick fix for alignment in avatars, juggling multiple branches is confusing 2022-03-22 11:57:21 +02:00
HJ
9be06d9f71 Merge branch 'renovate/mini-css-extract-plugin-0.x' into 'develop'
Update dependency mini-css-extract-plugin to v0.12.0

See merge request pleroma/pleroma-fe!1480
2022-03-22 09:54:23 +00:00
HJ
966919874e Merge branch 'fix-avatars2' into 'develop'
fix even more issues with avatars

See merge request pleroma/pleroma-fe!1482
2022-03-22 09:53:13 +00:00
HJ
a253c95170 Merge branch 'develop' into 'fix-avatars2'
# Conflicts:
#   src/components/status/status.scss
2022-03-22 09:47:24 +00:00
Henry Jameson
c6e0dcf08e fix even more issues with avatars 2022-03-22 11:43:51 +02:00
HJ
0147226b3d Merge branch 'renovate/ora-0.x' into 'develop'
Update dependency ora to v0.4.1

See merge request pleroma/pleroma-fe!1481
2022-03-22 09:20:54 +00:00
HJ
1571053fba Merge branch 'renovate/karma-firefox-launcher-1.x' into 'develop'
Update dependency karma-firefox-launcher to v1.3.0

See merge request pleroma/pleroma-fe!1475
2022-03-22 09:20:11 +00:00
Pleroma Renovate Bot
623aa3d20d Update dependency ora to v0.4.1 2022-03-22 09:06:15 +00:00
Pleroma Renovate Bot
636a55e72d Update dependency mini-css-extract-plugin to v0.12.0 2022-03-22 09:06:08 +00:00
Pleroma Renovate Bot
304f871332 Update dependency karma-firefox-launcher to v1.3.0 2022-03-22 09:06:00 +00:00
HJ
2cd8a3ec8d Merge branch 'fix-mobile-avatars' into 'develop'
fix avatars in mobile view

See merge request pleroma/pleroma-fe!1479
2022-03-22 08:24:42 +00:00
Henry Jameson
971cec024c fix avatars in mobile view 2022-03-22 10:20:45 +02:00
Henry Jameson
7a17eb7fec fix selects 2022-03-21 22:01:08 +02:00
Henry Jameson
4cb14c257c fix expert mode checkbox not working 2022-03-21 21:34:55 +02:00
Henry Jameson
1187727b60 fix tabswitcher bugs 2022-03-21 21:29:51 +02:00
Henry Jameson
54fd7e2be6 Merge remote-tracking branch 'origin/develop' into vue3-again
* origin/develop:
  improve the looks of bot indicator
  fix bot indicator appearing on retweeter avatar
  Update dependency localforage to v1.10.0
  Update dependency http-proxy-middleware to v0.21.0
  Update dependency eslint-plugin-standard to v4.1.0
  Update dependency eslint-plugin-import to v2.25.4
  Update babel monorepo to v7.17.8
  Update dependency iso-639-1 to v2.1.13
  Update dependency express to v4.17.3
  Update dependency eslint-plugin-promise to v4.3.1
  Update dependency eslint-loader to v2.2.1
2022-03-21 21:09:48 +02:00
HJ
0ef58696bf Merge branch 'bot-indicator-fixes' into 'develop'
Bot indicator fixes

See merge request pleroma/pleroma-fe!1477
2022-03-21 19:04:21 +00:00
Henry Jameson
9478a462a7 improve the looks of bot indicator 2022-03-21 20:59:25 +02:00
Henry Jameson
4e2fd7baf9 fix bot indicator appearing on retweeter avatar 2022-03-21 20:39:56 +02:00
HJ
66fb3987d6 Merge branch 'renovate/localforage-1.x' into 'develop'
Update dependency localforage to v1.10.0

See merge request pleroma/pleroma-fe!1476
2022-03-21 18:27:24 +00:00
HJ
1e60a491c4 Merge branch 'renovate/eslint-plugin-standard-4.x' into 'develop'
Update dependency eslint-plugin-standard to v4.1.0

See merge request pleroma/pleroma-fe!1471
2022-03-21 18:26:27 +00:00
HJ
12ce58a5a0 Merge branch 'renovate/babel-monorepo' into 'develop'
Update babel monorepo to v7.17.8

See merge request pleroma/pleroma-fe!1469
2022-03-21 18:25:29 +00:00
HJ
2f24f3312d Merge branch 'renovate/http-proxy-middleware-0.x' into 'develop'
Update dependency http-proxy-middleware to v0.21.0

See merge request pleroma/pleroma-fe!1473
2022-03-21 18:24:02 +00:00
HJ
1cc35b6df8 Merge branch 'renovate/eslint-plugin-import-2.x' into 'develop'
Update dependency eslint-plugin-import to v2.25.4

See merge request pleroma/pleroma-fe!1468
2022-03-21 18:19:24 +00:00
Pleroma Renovate Bot
4f2be206df Update dependency localforage to v1.10.0 2022-03-21 18:16:34 +00:00
Pleroma Renovate Bot
6074ad67ab Update dependency http-proxy-middleware to v0.21.0 2022-03-21 18:16:06 +00:00
Pleroma Renovate Bot
c5cb76ac3b Update dependency eslint-plugin-standard to v4.1.0 2022-03-21 18:15:53 +00:00
Pleroma Renovate Bot
e4b010321d Update dependency eslint-plugin-import to v2.25.4 2022-03-21 18:15:39 +00:00
Pleroma Renovate Bot
5e4ff5de7c Update babel monorepo to v7.17.8 2022-03-21 18:15:22 +00:00
HJ
6b14b645be Merge branch 'renovate/eslint-loader-2.x' into 'develop'
Update dependency eslint-loader to v2.2.1

See merge request pleroma/pleroma-fe!1467
2022-03-21 18:13:00 +00:00
HJ
79258f61be Merge branch 'renovate/eslint-plugin-promise-4.x' into 'develop'
Update dependency eslint-plugin-promise to v4.3.1

See merge request pleroma/pleroma-fe!1470
2022-03-21 18:10:10 +00:00
HJ
3ea442667f Merge branch 'renovate/express-4.x' into 'develop'
Update dependency express to v4.17.3

See merge request pleroma/pleroma-fe!1472
2022-03-21 18:05:16 +00:00
HJ
6c120cc576 Merge branch 'renovate/iso-639-1-2.x' into 'develop'
Update dependency iso-639-1 to v2.1.13

See merge request pleroma/pleroma-fe!1474
2022-03-21 18:01:48 +00:00
Pleroma Renovate Bot
89d6e624f2 Update dependency iso-639-1 to v2.1.13 2022-03-21 09:07:38 +00:00
Pleroma Renovate Bot
060aa41f35 Update dependency express to v4.17.3 2022-03-20 09:05:19 +00:00
Pleroma Renovate Bot
67f5cf3c03 Update dependency eslint-plugin-promise to v4.3.1 2022-03-19 09:07:04 +00:00
Henry Jameson
5948d20f00 mutes and blocks tab works 2022-03-18 13:36:08 +02:00
Henry Jameson
b3ed29ff02 made withLoadMore work... sorta 2022-03-18 13:32:36 +02:00
Pleroma Renovate Bot
5d973df5bd Update dependency eslint-loader to v2.2.1 2022-03-18 09:04:52 +00:00
Henry Jameson
26bfbdc2ad fix sw compilation 2022-03-18 11:02:00 +02:00
Henry Jameson
50ea6dd142 Merge remote-tracking branch 'origin/develop' into vue3-again
* origin/develop:
  Update dependency cropperjs to v1.5.12
  Update dependency body-scroll-lock to v2.7.1
  Update babel monorepo
2022-03-18 10:59:28 +02:00
Henry Jameson
fea0c91f74 bunp node version 2022-03-17 09:33:36 +02:00
Henry Jameson
051d51bcd9 fix suggest not working 2022-03-17 09:28:19 +02:00
Henry Jameson
5718c6491e fix selects being messed up 2022-03-17 09:06:05 +02:00
Henry Jameson
a97c07bfdf fix settings not persisting 2022-03-17 09:02:26 +02:00
Henry Jameson
d815f984fb fix i18n errors related to @ symbol 2022-03-17 08:53:45 +02:00
Henry Jameson
4993dc37e2 fix rich content not rendering stillimage nor links correctly 2022-03-17 08:53:45 +02:00
Henry Jameson
0671aa0dd0 fix tabswitcher 2022-03-17 08:53:45 +02:00
Henry Jameson
b62653c202 fix chat user titles 2022-03-17 08:37:01 +02:00
Henry Jameson
be4244acde fix some warnings 2022-03-17 08:35:19 +02:00
Henry Jameson
8311d4deba shit renders yo 2022-03-16 22:13:21 +02:00
Henry Jameson
e51144809f shit boots yo 2022-03-16 22:02:44 +02:00
Henry Jameson
cd4ad2df11 Merge remote-tracking branch 'origin/develop' into vue3-again
* origin/develop: (475 commits)
  Apply 1 suggestion(s) to 1 file(s)
  Update dependency @ungap/event-target to v0.2.3
  Update package.json
  fix broken icons after FA upgrade
  Update Font Awesome
  Update dependency webpack-dev-middleware to v3.7.3
  Update dependency vuelidate to v0.7.7
  Pin dependency @kazvmoe-infra/pinch-zoom-element to 1.2.0
  lint
  Make media modal buttons larger
  Add English translation for hide tooltip
  Add hide button to media modal
  Lint
  Prevent hiding media viewer if swiped over SwipeClick
  Fix webkit image blurs
  Fix video in media modal not displaying properly
  Add changelog for https://git.pleroma.social/pleroma/pleroma-fe/-/merge_requests/1403
  Remove image box-shadow in media modal
  Clean up debug code for image pinch zoom
  Bump @kazvmoe-infra/pinch-zoom-element to 1.2.0 on npm
  ...
2022-03-16 21:00:20 +02:00
Henry Jameson
8a9115b58e temp fix for now-unused resettable async component 2021-04-25 14:51:15 +03:00
Henry Jameson
b6e8c12dbc emoji picker fix 2021-04-25 14:51:00 +03:00
Henry Jameson
e73cb423b6 fix login form 2021-04-25 14:44:07 +03:00
Henry Jameson
e47d5ba53b fix importer/exporter i18n 2021-04-25 14:12:34 +03:00
Henry Jameson
8d46fd78c7 migrate to v-slot 2021-04-25 14:05:25 +03:00
Henry Jameson
95e74319e1 clean warnings from status 2021-04-25 14:05:25 +03:00
Henry Jameson
709b75198d fix portals/teleports 2021-04-25 14:05:25 +03:00
Henry Jameson
caed89f0ae destroyed -> unmounted 2021-04-25 13:44:50 +03:00
Henry Jameson
72956e2343 fix HOCs 2021-04-25 13:40:08 +03:00
Henry Jameson
4b18e0f36e fix status error 2021-04-25 13:33:02 +03:00
Henry Jameson
b479d80366 fix i18n in services 2021-04-25 13:30:18 +03:00
Henry Jameson
9e8513b312 i18n fixes 2021-04-25 13:25:42 +03:00
Henry Jameson
52835cf8bf work around modules cyclic dependencies 2021-04-25 13:25:04 +03:00
Henry Jameson
905b9771ec stop using vue.set 2021-04-25 13:24:08 +03:00
Henry Jameson
fca885e665 resolve TODO VUE3 2021-04-25 13:23:16 +03:00
Henry Jameson
6e687c0663 fix one async component preventing further load 2021-04-25 13:15:02 +03:00
Henry Jameson
180da297f6 Merge branch 'vue3compat-tabswitcher' into vue3-again
* vue3compat-tabswitcher:
  small refactoring to uncouple tab-switcher from settings modal
  fix theme tab, remove console.logs
  Changed some of TabSwitcher's internals for easier Vue3 migration
2021-04-25 12:51:45 +03:00
Henry Jameson
b774472fff Merge branch 'vue3compat-emoji-input' into vue3-again
* vue3compat-emoji-input:
  backport vue3 changes related to emoji-input
2021-04-25 12:51:21 +03:00
Henry Jameson
76a2e6befb remove Vue.component from hooks 2021-04-25 12:50:17 +03:00
Henry Jameson
1f5f612163 remove Vue.component, just export an object. Seems to be working 2021-04-25 12:47:52 +03:00
Henry Jameson
509ec99574 some minor fixes to get it to boot 2021-04-24 18:04:35 +03:00
Henry Jameson
ced9c0fa7e some bare minimum to get vue3 boot (no UI yet) 2021-04-24 17:56:00 +03:00
Henry Jameson
33777fab47 small refactoring to uncouple tab-switcher from settings modal 2021-04-18 15:39:06 +03:00
Henry Jameson
b0789fd6fd fix theme tab, remove console.logs 2021-04-18 15:03:28 +03:00
Henry Jameson
433ea02a18 Changed some of TabSwitcher's internals for easier Vue3 migration 2021-04-18 14:58:02 +03:00
136 changed files with 2509 additions and 2018 deletions

View file

@ -1,5 +1,5 @@
{ {
"presets": ["@babel/preset-env", "@vue/babel-preset-jsx"], "presets": ["@babel/preset-env"],
"plugins": ["@babel/plugin-transform-runtime", "lodash"], "plugins": ["@babel/plugin-transform-runtime", "lodash", "@vue/babel-plugin-jsx"],
"comments": false "comments": false
} }

View file

@ -1,7 +1,7 @@
# This file is a template, and might need editing before it works on your project. # This file is a template, and might need editing before it works on your project.
# Official framework image. Look for the different tagged releases at: # Official framework image. Look for the different tagged releases at:
# https://hub.docker.com/r/library/node/tags/ # https://hub.docker.com/r/library/node/tags/
image: node:10 image: node:12
stages: stages:
- lint - lint

View file

@ -4,6 +4,7 @@ var utils = require('./utils')
var projectRoot = path.resolve(__dirname, '../') var projectRoot = path.resolve(__dirname, '../')
var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin') var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin')
var CopyPlugin = require('copy-webpack-plugin'); var CopyPlugin = require('copy-webpack-plugin');
var { VueLoaderPlugin } = require('vue-loader')
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
@ -29,16 +30,16 @@ module.exports = {
} }
}, },
resolve: { resolve: {
extensions: ['.js', '.vue'], extensions: ['.js', '.jsx', '.vue'],
modules: [ modules: [
path.join(__dirname, '../node_modules') path.join(__dirname, '../node_modules')
], ],
alias: { alias: {
'vue$': 'vue/dist/vue.runtime.common',
'static': path.resolve(__dirname, '../static'), 'static': path.resolve(__dirname, '../static'),
'src': path.resolve(__dirname, '../src'), 'src': path.resolve(__dirname, '../src'),
'assets': path.resolve(__dirname, '../src/assets'), 'assets': path.resolve(__dirname, '../src/assets'),
'components': path.resolve(__dirname, '../src/components') 'components': path.resolve(__dirname, '../src/components'),
'vue-i18n': 'vue-i18n/dist/vue-i18n.runtime.esm-bundler.js'
} }
}, },
module: { module: {
@ -58,9 +59,28 @@ module.exports = {
} }
} }
}, },
{
enforce: 'post',
test: /\.(json5?|ya?ml)$/, // target json, json5, yaml and yml files
type: 'javascript/auto',
loader: '@intlify/vue-i18n-loader',
include: [ // Use `Rule.include` to specify the files of locale messages to be pre-compiled
path.resolve(__dirname, '../src/i18n')
]
},
{ {
test: /\.vue$/, test: /\.vue$/,
use: 'vue-loader' loader: 'vue-loader',
options: {
compilerOptions: {
isCustomElement(tag) {
if (tag === 'pinch-zoom') {
return true
}
return false
}
}
}
}, },
{ {
test: /\.jsx?$/, test: /\.jsx?$/,
@ -95,6 +115,7 @@ module.exports = {
entry: path.join(__dirname, '..', 'src/sw.js'), entry: path.join(__dirname, '..', 'src/sw.js'),
filename: 'sw-pleroma.js' filename: 'sw-pleroma.js'
}), }),
new VueLoaderPlugin(),
// This copies Ruffle's WASM to a directory so that JS side can access it // This copies Ruffle's WASM to a directory so that JS side can access it
new CopyPlugin({ new CopyPlugin({
patterns: [ patterns: [

View file

@ -21,7 +21,9 @@ module.exports = merge(baseWebpackConfig, {
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': config.dev.env, 'process.env': config.dev.env,
'COMMIT_HASH': JSON.stringify('DEV'), 'COMMIT_HASH': JSON.stringify('DEV'),
'DEV_OVERRIDES': JSON.stringify(config.dev.settings) 'DEV_OVERRIDES': JSON.stringify(config.dev.settings),
'__VUE_OPTIONS_API__': true,
'__VUE_PROD_DEVTOOLS__': false
}), }),
// https://github.com/glenjamin/webpack-hot-middleware#installation--usage // https://github.com/glenjamin/webpack-hot-middleware#installation--usage
new webpack.HotModuleReplacementPlugin(), new webpack.HotModuleReplacementPlugin(),

View file

@ -36,7 +36,9 @@ var webpackConfig = merge(baseWebpackConfig, {
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': env, 'process.env': env,
'COMMIT_HASH': JSON.stringify(commitHash), 'COMMIT_HASH': JSON.stringify(commitHash),
'DEV_OVERRIDES': JSON.stringify(undefined) 'DEV_OVERRIDES': JSON.stringify(undefined),
'__VUE_OPTIONS_API__': true,
'__VUE_PROD_DEVTOOLS__': false
}), }),
// extract css into its own file // extract css into its own file
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({

View file

@ -52,7 +52,10 @@ module.exports = {
target, target,
changeOrigin: true, changeOrigin: true,
cookieDomainRewrite: 'localhost', cookieDomainRewrite: 'localhost',
ws: true ws: true,
headers: {
'Origin': target
}
}, },
'/oauth/revoke': { '/oauth/revoke': {
target, target,

View file

@ -16,44 +16,47 @@
"lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs" "lint-fix": "eslint --fix --ext .js,.vue src test/unit/specs test/e2e/specs"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "7.17.7", "@babel/runtime": "7.17.8",
"@chenfengyuan/vue-qrcode": "1.0.2", "@chenfengyuan/vue-qrcode": "2.0.0",
"@fortawesome/fontawesome-svg-core": "1.3.0", "@fortawesome/fontawesome-svg-core": "1.3.0",
"@fortawesome/free-regular-svg-icons": "5.15.4", "@fortawesome/free-regular-svg-icons": "5.15.4",
"@fortawesome/free-solid-svg-icons": "5.15.4", "@fortawesome/free-solid-svg-icons": "5.15.4",
"@fortawesome/vue-fontawesome": "2.0.6", "@fortawesome/vue-fontawesome": "3.0.0-5",
"@kazvmoe-infra/pinch-zoom-element": "1.2.0", "@kazvmoe-infra/pinch-zoom-element": "1.2.0",
"@vuelidate/core": "2.0.0-alpha.35",
"@vuelidate/validators": "2.0.0-alpha.27",
"body-scroll-lock": "2.7.1", "body-scroll-lock": "2.7.1",
"chromatism": "3.0.0", "chromatism": "3.0.0",
"click-outside-vue3": "4.0.1",
"cropperjs": "1.5.12", "cropperjs": "1.5.12",
"diff": "3.5.0", "diff": "3.5.0",
"escape-html": "1.0.3", "escape-html": "1.0.3",
"localforage": "1.7.3", "localforage": "1.10.0",
"parse-link-header": "1.0.1", "parse-link-header": "1.0.1",
"phoenix": "1.4.0", "phoenix": "1.6.2",
"portal-vue": "2.1.7",
"punycode.js": "2.1.0", "punycode.js": "2.1.0",
"ruffle-mirror": "2021.4.11", "qrcode": "1",
"v-click-outside": "2.1.5", "ruffle-mirror": "2021.12.31",
"vue": "2.6.11", "vue": "^3.2.31",
"vue-i18n": "7.8.1", "vue-i18n": "^9.2.0-beta.34",
"vue-router": "3.0.2", "vue-router": "4.0.14",
"vue-template-compiler": "2.6.11", "vue-template-compiler": "2.6.11",
"vuelidate": "0.7.7", "vuex": "4.0.2"
"vuex": "3.0.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "7.17.7", "@babel/core": "7.17.8",
"@babel/plugin-transform-runtime": "7.17.0", "@babel/plugin-transform-runtime": "7.17.0",
"@babel/preset-env": "7.16.11", "@babel/preset-env": "7.16.11",
"@babel/register": "7.17.7", "@babel/register": "7.17.7",
"@intlify/vue-i18n-loader": "^5.0.0",
"@ungap/event-target": "0.2.3", "@ungap/event-target": "0.2.3",
"@vue/babel-helper-vue-jsx-merge-props": "1.2.1", "@vue/babel-helper-vue-jsx-merge-props": "1.2.1",
"@vue/babel-preset-jsx": "1.2.4", "@vue/babel-plugin-jsx": "1.1.1",
"@vue/test-utils": "1.0.0-beta.28", "@vue/compiler-sfc": "^3.1.0",
"@vue/test-utils": "2.0.0-rc.17",
"autoprefixer": "6.7.7", "autoprefixer": "6.7.7",
"babel-eslint": "7.2.3", "babel-eslint": "7.2.3",
"babel-loader": "8.2.3", "babel-loader": "8.2.4",
"babel-plugin-lodash": "3.3.4", "babel-plugin-lodash": "3.3.4",
"chai": "3.5.0", "chai": "3.5.0",
"chalk": "1.1.3", "chalk": "1.1.3",
@ -66,26 +69,26 @@
"eslint": "5.16.0", "eslint": "5.16.0",
"eslint-config-standard": "12.0.0", "eslint-config-standard": "12.0.0",
"eslint-friendly-formatter": "2.0.7", "eslint-friendly-formatter": "2.0.7",
"eslint-loader": "2.1.2", "eslint-loader": "2.2.1",
"eslint-plugin-import": "2.17.2", "eslint-plugin-import": "2.25.4",
"eslint-plugin-node": "7.0.1", "eslint-plugin-node": "7.0.1",
"eslint-plugin-promise": "4.1.1", "eslint-plugin-promise": "4.3.1",
"eslint-plugin-standard": "4.0.0", "eslint-plugin-standard": "4.1.0",
"eslint-plugin-vue": "5.2.3", "eslint-plugin-vue": "5.2.3",
"eventsource-polyfill": "0.9.6", "eventsource-polyfill": "0.9.6",
"express": "4.16.4", "express": "4.17.3",
"file-loader": "3.0.1", "file-loader": "3.0.1",
"function-bind": "1.1.1", "function-bind": "1.1.1",
"html-webpack-plugin": "3.2.0", "html-webpack-plugin": "3.2.0",
"http-proxy-middleware": "0.17.4", "http-proxy-middleware": "0.21.0",
"inject-loader": "2.0.1", "inject-loader": "2.0.1",
"iso-639-1": "2.0.3", "iso-639-1": "2.1.13",
"isparta-loader": "2.0.0", "isparta-loader": "2.0.0",
"json-loader": "0.5.7", "json-loader": "0.5.7",
"karma": "3.1.4", "karma": "6.3.17",
"karma-coverage": "1.1.2", "karma-coverage": "1.1.2",
"karma-firefox-launcher": "1.1.0", "karma-firefox-launcher": "1.3.0",
"karma-mocha": "1.3.0", "karma-mocha": "2.0.1",
"karma-mocha-reporter": "2.2.5", "karma-mocha-reporter": "2.2.5",
"karma-sinon-chai": "2.0.2", "karma-sinon-chai": "2.0.2",
"karma-sourcemap-loader": "0.3.8", "karma-sourcemap-loader": "0.3.8",
@ -93,11 +96,11 @@
"karma-webpack": "4.0.2", "karma-webpack": "4.0.2",
"lodash": "4.17.21", "lodash": "4.17.21",
"lolex": "1.6.0", "lolex": "1.6.0",
"mini-css-extract-plugin": "0.5.0", "mini-css-extract-plugin": "0.12.0",
"mocha": "3.5.3", "mocha": "3.5.3",
"nightwatch": "0.9.21", "nightwatch": "0.9.21",
"opn": "4.0.2", "opn": "4.0.2",
"ora": "0.3.0", "ora": "0.4.1",
"postcss-loader": "3.0.0", "postcss-loader": "3.0.0",
"raw-loader": "0.5.1", "raw-loader": "0.5.1",
"sass": "1.20.1", "sass": "1.20.1",
@ -112,7 +115,7 @@
"stylelint-config-standard": "20.0.0", "stylelint-config-standard": "20.0.0",
"stylelint-rscss": "0.4.0", "stylelint-rscss": "0.4.0",
"url-loader": "1.1.2", "url-loader": "1.1.2",
"vue-loader": "14.2.4", "vue-loader": "^16.0.0",
"vue-style-loader": "4.1.2", "vue-style-loader": "4.1.2",
"webpack": "4.46.0", "webpack": "4.46.0",
"webpack-dev-middleware": "3.7.3", "webpack-dev-middleware": "3.7.3",

View file

@ -46,7 +46,7 @@ export default {
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
window.addEventListener('resize', this.updateMobileState) window.addEventListener('resize', this.updateMobileState)
}, },
destroyed () { unmounted () {
window.removeEventListener('resize', this.updateMobileState) window.removeEventListener('resize', this.updateMobileState)
}, },
computed: { computed: {
@ -65,7 +65,7 @@ export default {
} }
} }
}, },
shout () { return this.$store.state.shout.channel.state === 'joined' }, shout () { return this.$store.state.shout.joined },
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled }, suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
showInstanceSpecificPanel () { showInstanceSpecificPanel () {
return this.$store.state.instance.showInstanceSpecificPanel && return this.$store.state.instance.showInstanceSpecificPanel &&

View file

@ -572,7 +572,7 @@ nav {
.fade-enter-active, .fade-leave-active { .fade-enter-active, .fade-leave-active {
transition: opacity .2s transition: opacity .2s
} }
.fade-enter, .fade-leave-active { .fade-enter-from, .fade-leave-active {
opacity: 0 opacity: 0
} }

View file

@ -1,6 +1,6 @@
<template> <template>
<div <div
id="app" id="app-loaded"
:style="bgStyle" :style="bgStyle"
> >
<div <div
@ -59,7 +59,7 @@
<UserReportingModal /> <UserReportingModal />
<PostStatusModal /> <PostStatusModal />
<SettingsModal /> <SettingsModal />
<portal-target name="modal" /> <div id="modal" />
<GlobalNoticeList /> <GlobalNoticeList />
</div> </div>
</template> </template>

View file

@ -1,7 +1,13 @@
import Vue from 'vue' import { createApp } from 'vue'
import VueRouter from 'vue-router' import { createRouter, createWebHistory } from 'vue-router'
import routes from './routes' import vClickOutside from 'click-outside-vue3'
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
import App from '../App.vue' import App from '../App.vue'
import routes from './routes'
import VBodyScrollLock from 'src/directives/body_scroll_lock'
import { windowWidth } from '../services/window_utils/window_utils' import { windowWidth } from '../services/window_utils/window_utils'
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js' import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
@ -367,25 +373,32 @@ const afterStoreSetup = async ({ store, i18n }) => {
getTOS({ store }) getTOS({ store })
getStickers({ store }) getStickers({ store })
const router = new VueRouter({ const router = createRouter({
mode: 'history', history: createWebHistory(),
routes: routes(store), routes: routes(store),
scrollBehavior: (to, _from, savedPosition) => { scrollBehavior: (to, _from, savedPosition) => {
if (to.matched.some(m => m.meta.dontScroll)) { if (to.matched.some(m => m.meta.dontScroll)) {
return false return false
} }
return savedPosition || { x: 0, y: 0 } return savedPosition || { left: 0, top: 0 }
} }
}) })
/* eslint-disable no-new */ const app = createApp(App)
return new Vue({
router, app.use(router)
store, app.use(store)
i18n, app.use(i18n)
el: '#app',
render: h => h(App) app.use(vClickOutside)
}) app.use(VBodyScrollLock)
app.component('FAIcon', FontAwesomeIcon)
app.component('FALayers', FontAwesomeLayers)
app.mount('#app')
return app
} }
export default afterStoreSetup export default afterStoreSetup

View file

@ -46,7 +46,7 @@ export default (store) => {
{ name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline }, { name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline },
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
{ name: 'remote-user-profile-acct', { name: 'remote-user-profile-acct',
path: '/remote-users/(@?):username([^/@]+)@:hostname([^/@]+)', path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)',
component: RemoteUserResolver, component: RemoteUserResolver,
beforeEnter: validateAuthenticatedRoute beforeEnter: validateAuthenticatedRoute
}, },
@ -69,7 +69,7 @@ export default (store) => {
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) }, { name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute }, { name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
{ name: 'about', path: '/about', component: About }, { name: 'about', path: '/about', component: About },
{ name: 'user-profile', path: '/(users/)?:name', component: UserProfile } { name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile }
] ]
if (store.state.instance.pleromaChatMessagesAvailable) { if (store.state.instance.pleromaChatMessagesAvailable) {

View file

@ -19,6 +19,7 @@
<script> <script>
export default { export default {
emits: ['resetAsyncComponent'],
methods: { methods: {
retry () { retry () {
this.$emit('resetAsyncComponent') this.$emit('resetAsyncComponent')

View file

@ -1,3 +1,4 @@
import { h, resolveComponent } from 'vue'
import LoginForm from '../login_form/login_form.vue' import LoginForm from '../login_form/login_form.vue'
import MFARecoveryForm from '../mfa_form/recovery_form.vue' import MFARecoveryForm from '../mfa_form/recovery_form.vue'
import MFATOTPForm from '../mfa_form/totp_form.vue' import MFATOTPForm from '../mfa_form/totp_form.vue'
@ -5,8 +6,8 @@ import { mapGetters } from 'vuex'
const AuthForm = { const AuthForm = {
name: 'AuthForm', name: 'AuthForm',
render (createElement) { render () {
return createElement('component', { is: this.authForm }) return h(resolveComponent(this.authForm))
}, },
computed: { computed: {
authForm () { authForm () {

View file

@ -4,7 +4,7 @@
<UserAvatar <UserAvatar
class="avatar" class="avatar"
:user="user" :user="user"
@click.prevent.native="toggleUserExpanded" @click.prevent="toggleUserExpanded"
/> />
</router-link> </router-link>
<div <div

View file

@ -9,7 +9,7 @@ const Bookmarks = {
components: { components: {
Timeline Timeline
}, },
destroyed () { unmounted () {
this.$store.commit('clearTimeline', { timeline: 'bookmarks' }) this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
} }
} }

View file

@ -57,7 +57,7 @@ const Chat = {
}) })
this.setChatLayout() this.setChatLayout()
}, },
destroyed () { unmounted () {
window.removeEventListener('scroll', this.handleScroll) window.removeEventListener('scroll', this.handleScroll)
window.removeEventListener('resize', this.handleLayoutChange) window.removeEventListener('resize', this.handleLayoutChange)
this.unsetChatLayout() this.unsetChatLayout()

View file

@ -26,73 +26,71 @@
/> />
</div> </div>
</div> </div>
<template> <div
<div ref="scrollable"
ref="scrollable" class="scrollable-message-list"
class="scrollable-message-list" :style="{ height: scrollableContainerHeight }"
:style="{ height: scrollableContainerHeight }" @scroll="handleScroll"
@scroll="handleScroll" >
> <template v-if="!errorLoadingChat">
<template v-if="!errorLoadingChat"> <ChatMessage
<ChatMessage v-for="chatViewItem in chatViewItems"
v-for="chatViewItem in chatViewItems" :key="chatViewItem.id"
:key="chatViewItem.id" :author="recipient"
:author="recipient" :chat-view-item="chatViewItem"
:chat-view-item="chatViewItem" :hovered-message-chain="chatViewItem.messageChainId === hoveredMessageChainId"
:hovered-message-chain="chatViewItem.messageChainId === hoveredMessageChainId" @hover="onMessageHover"
@hover="onMessageHover"
/>
</template>
<div
v-else
class="chat-loading-error"
>
<div class="alert error">
{{ $t('chats.error_loading_chat') }}
</div>
</div>
</div>
<div
ref="footer"
class="panel-body footer"
>
<div
class="jump-to-bottom-button"
:class="{ 'visible': jumpToBottomButtonVisible }"
@click="scrollDown({ behavior: 'smooth' })"
>
<span>
<FAIcon icon="chevron-down" />
<div
v-if="newMessageCount"
class="badge badge-notification unread-chat-count unread-message-count"
>
{{ newMessageCount }}
</div>
</span>
</div>
<PostStatusForm
:disable-subject="true"
:disable-scope-selector="true"
:disable-notice="true"
:disable-lock-warning="true"
:disable-polls="true"
:disable-sensitivity-checkbox="true"
:disable-submit="errorLoadingChat || !currentChat"
:disable-preview="true"
:optimistic-posting="true"
:post-handler="sendMessage"
:submit-on-enter="!mobileLayout"
:preserve-focus="!mobileLayout"
:auto-focus="!mobileLayout"
:placeholder="formPlaceholder"
:file-limit="1"
max-height="160"
emoji-picker-placement="top"
@resize="handleResize"
/> />
</template>
<div
v-else
class="chat-loading-error"
>
<div class="alert error">
{{ $t('chats.error_loading_chat') }}
</div>
</div> </div>
</template> </div>
<div
ref="footer"
class="panel-body footer"
>
<div
class="jump-to-bottom-button"
:class="{ 'visible': jumpToBottomButtonVisible }"
@click="scrollDown({ behavior: 'smooth' })"
>
<span>
<FAIcon icon="chevron-down" />
<div
v-if="newMessageCount"
class="badge badge-notification unread-chat-count unread-message-count"
>
{{ newMessageCount }}
</div>
</span>
</div>
<PostStatusForm
:disable-subject="true"
:disable-scope-selector="true"
:disable-notice="true"
:disable-lock-warning="true"
:disable-polls="true"
:disable-sensitivity-checkbox="true"
:disable-submit="errorLoadingChat || !currentChat"
:disable-preview="true"
:optimistic-posting="true"
:post-handler="sendMessage"
:submit-on-enter="!mobileLayout"
:preserve-focus="!mobileLayout"
:auto-focus="!mobileLayout"
:placeholder="formPlaceholder"
:file-limit="1"
max-height="160"
emoji-picker-placement="top"
@resize="handleResize"
/>
</div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -27,6 +27,7 @@ const ChatMessage = {
'chatViewItem', 'chatViewItem',
'hoveredMessageChain' 'hoveredMessageChain'
], ],
emits: ['hover'],
components: { components: {
Popover, Popover,
Attachment, Attachment,

View file

@ -1,11 +1,12 @@
import Vue from 'vue'
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'
import UserAvatar from '../user_avatar/user_avatar.vue' import UserAvatar from '../user_avatar/user_avatar.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
export default Vue.component('chat-title', { export default {
name: 'ChatTitle', name: 'ChatTitle',
components: { components: {
UserAvatar UserAvatar,
RichContent
}, },
props: [ props: [
'user', 'withAvatar' 'user', 'withAvatar'
@ -23,4 +24,4 @@ export default Vue.component('chat-title', {
return generateProfileLink(user.id, user.screen_name) return generateProfileLink(user.id, user.screen_name)
} }
} }
}) }

View file

@ -14,10 +14,11 @@
/> />
</router-link> </router-link>
<RichContent <RichContent
v-if="user"
class="username" class="username"
:title="'@'+user.screen_name_ui" :title="'@'+user.screen_name_ui"
:html="htmlTitle" :html="htmlTitle"
:emoji="user.emoji" :emoji="user.emoji || []"
/> />
</div> </div>
</template> </template>

View file

@ -6,9 +6,9 @@
<input <input
type="checkbox" type="checkbox"
:disabled="disabled" :disabled="disabled"
:checked="checked" :checked="modelValue"
:indeterminate.prop="indeterminate" :indeterminate="indeterminate"
@change="$emit('change', $event.target.checked)" @change="$emit('update:modelValue', $event.target.checked)"
> >
<i class="checkbox-indicator" /> <i class="checkbox-indicator" />
<span <span
@ -22,12 +22,9 @@
<script> <script>
export default { export default {
model: { emits: ['update:modelValue'],
prop: 'checked',
event: 'change'
},
props: [ props: [
'checked', 'modelValue',
'indeterminate', 'indeterminate',
'disabled' 'disabled'
] ]

View file

@ -11,28 +11,28 @@
</label> </label>
<Checkbox <Checkbox
v-if="typeof fallback !== 'undefined' && showOptionalTickbox" v-if="typeof fallback !== 'undefined' && showOptionalTickbox"
:checked="present" :model-value="present"
:disabled="disabled" :disabled="disabled"
class="opt" class="opt"
@change="$emit('input', typeof value === 'undefined' ? fallback : undefined)" @update:modelValue="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
/> />
<div class="input color-input-field"> <div class="input color-input-field">
<input <input
:id="name + '-t'" :id="name + '-t'"
class="textColor unstyled" class="textColor unstyled"
type="text" type="text"
:value="value || fallback" :value="modelValue || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
@input="$emit('input', $event.target.value)" @input="$emit('update:modelValue', $event.target.value)"
> >
<input <input
v-if="validColor" v-if="validColor"
:id="name" :id="name"
class="nativeColor unstyled" class="nativeColor unstyled"
type="color" type="color"
:value="value || fallback" :value="modelValue || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
@input="$emit('input', $event.target.value)" @input="$emit('update:modelValue', $event.target.value)"
> >
<div <div
v-if="transparentColor" v-if="transparentColor"
@ -67,7 +67,7 @@ export default {
}, },
// Color value, should be required but vue cannot tell the difference // Color value, should be required but vue cannot tell the difference
// between "property missing" and "property set to undefined" // between "property missing" and "property set to undefined"
value: { modelValue: {
required: false, required: false,
type: String, type: String,
default: undefined default: undefined
@ -91,18 +91,19 @@ export default {
default: true default: true
} }
}, },
emits: ['update:modelValue'],
computed: { computed: {
present () { present () {
return typeof this.value !== 'undefined' return typeof this.modelValue !== 'undefined'
}, },
validColor () { validColor () {
return hex2rgb(this.value || this.fallback) return hex2rgb(this.modelValue || this.fallback)
}, },
transparentColor () { transparentColor () {
return this.value === 'transparent' return this.modelValue === 'transparent'
}, },
computedColor () { computedColor () {
return this.value && this.value.startsWith('--') return this.modelValue && this.modelValue.startsWith('--')
} }
} }
} }

View file

@ -27,20 +27,24 @@
v-if="shouldShowAllConversationButton" v-if="shouldShowAllConversationButton"
class="conversation-dive-to-top-level-box" class="conversation-dive-to-top-level-box"
> >
<i18n <i18n-t
path="status.show_all_conversation_with_icon" keypath="status.show_all_conversation_with_icon"
tag="button" tag="button"
class="button-unstyled -link" class="button-unstyled -link"
@click.prevent="diveToTopLevel" @click.prevent="diveToTopLevel"
scope="global"
> >
<FAIcon <template #icon>
place="icon" <FAIcon
icon="angle-double-left" icon="angle-double-left"
/> />
<span place="text"> </template>
{{ $tc('status.show_all_conversation', otherTopLevelCount, { numStatus: otherTopLevelCount }) }} <template #text>
</span> <span>
</i18n> {{ $tc('status.show_all_conversation', otherTopLevelCount, { numStatus: otherTopLevelCount }) }}
</span>
</template>
</i18n-t>
</div> </div>
<div <div
v-if="shouldShowAncestors" v-if="shouldShowAncestors"
@ -96,20 +100,24 @@
<div <div
class="thread-ancestor-dive-box-inner" class="thread-ancestor-dive-box-inner"
> >
<i18n <i18n-t
tag="button" tag="button"
path="status.ancestor_follow_with_icon" scope="global"
keypath="status.ancestor_follow_with_icon"
class="button-unstyled -link thread-tree-show-replies-button" class="button-unstyled -link thread-tree-show-replies-button"
@click.prevent="diveIntoStatus(status.id)" @click.prevent="diveIntoStatus(status.id)"
> >
<FAIcon <template #icon>
place="icon" <FAIcon
icon="angle-double-right" icon="angle-double-right"
/> />
<span place="text"> </template>
{{ $tc('status.ancestor_follow', getReplies(status.id).length - 1, { numReplies: getReplies(status.id).length - 1 }) }} <template #text>
</span> <span>
</i18n> {{ $tc('status.ancestor_follow', getReplies(status.id).length - 1, { numReplies: getReplies(status.id).length - 1 }) }}
</span>
</template>
</i18n-t>
</div> </div>
</div> </div>
</div> </div>

View file

@ -34,7 +34,7 @@
<search-bar <search-bar
v-if="currentUser || !privateMode" v-if="currentUser || !privateMode"
@toggled="onSearchBarToggled" @toggled="onSearchBarToggled"
@click.stop.native @click.stop
/> />
<button <button
class="button-unstyled nav-icon" class="button-unstyled nav-icon"

View file

@ -31,6 +31,7 @@ library.add(
*/ */
const EmojiInput = { const EmojiInput = {
emits: ['update:modelValue', 'shown'],
props: { props: {
suggest: { suggest: {
/** /**
@ -57,8 +58,7 @@ const EmojiInput = {
required: true, required: true,
type: Function type: Function
}, },
// TODO VUE3: change to modelValue, change 'input' event to 'input' modelValue: {
value: {
/** /**
* Used for v-model * Used for v-model
*/ */
@ -137,8 +137,8 @@ const EmojiInput = {
return (this.wordAtCaret || {}).word || '' return (this.wordAtCaret || {}).word || ''
}, },
wordAtCaret () { wordAtCaret () {
if (this.value && this.caret) { if (this.modelValue && this.caret) {
const word = Completion.wordAtPosition(this.value, this.caret - 1) || {} const word = Completion.wordAtPosition(this.modelValue, this.caret - 1) || {}
return word return word
} }
} }
@ -189,8 +189,11 @@ const EmojiInput = {
img: imageUrl || '' img: imageUrl || ''
})) }))
}, },
suggestions (newValue) { suggestions: {
this.$nextTick(this.resize) handler (newValue) {
this.$nextTick(this.resize)
},
deep: true
} }
}, },
methods: { methods: {
@ -225,13 +228,13 @@ const EmojiInput = {
} }
}, },
replace (replacement) { replace (replacement) {
const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement) const newValue = Completion.replaceWord(this.modelValue, this.wordAtCaret, replacement)
this.$emit('input', newValue) this.$emit('update:modelValue', newValue)
this.caret = 0 this.caret = 0
}, },
insert ({ insertion, keepOpen, surroundingSpace = true }) { insert ({ insertion, keepOpen, surroundingSpace = true }) {
const before = this.value.substring(0, this.caret) || '' const before = this.modelValue.substring(0, this.caret) || ''
const after = this.value.substring(this.caret) || '' const after = this.modelValue.substring(this.caret) || ''
/* Using a bit more smart approach to padding emojis with spaces: /* Using a bit more smart approach to padding emojis with spaces:
* - put a space before cursor if there isn't one already, unless we * - put a space before cursor if there isn't one already, unless we
@ -259,7 +262,7 @@ const EmojiInput = {
after after
].join('') ].join('')
this.keepOpen = keepOpen this.keepOpen = keepOpen
this.$emit('input', newValue) this.$emit('update:modelValue', newValue)
const position = this.caret + (insertion + spaceAfter + spaceBefore).length const position = this.caret + (insertion + spaceAfter + spaceBefore).length
if (!keepOpen) { if (!keepOpen) {
this.input.focus() this.input.focus()
@ -278,8 +281,8 @@ const EmojiInput = {
if (len > 0 || suggestion) { if (len > 0 || suggestion) {
const chosenSuggestion = suggestion || this.suggestions[this.highlighted] const chosenSuggestion = suggestion || this.suggestions[this.highlighted]
const replacement = chosenSuggestion.replacement const replacement = chosenSuggestion.replacement
const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement) const newValue = Completion.replaceWord(this.modelValue, this.wordAtCaret, replacement)
this.$emit('input', newValue) this.$emit('update:modelValue', newValue)
this.highlighted = 0 this.highlighted = 0
const position = this.wordAtCaret.start + replacement.length const position = this.wordAtCaret.start + replacement.length
@ -455,7 +458,7 @@ const EmojiInput = {
this.showPicker = false this.showPicker = false
this.setCaret(e) this.setCaret(e)
this.resize() this.resize()
this.$emit('input', e.target.value) this.$emit('update:modelValue', e.target.value)
}, },
onClickInput (e) { onClickInput (e) {
this.showPicker = false this.showPicker = false

View file

@ -1,3 +1,4 @@
import { defineAsyncComponent } from 'vue'
import Checkbox from '../checkbox/checkbox.vue' import Checkbox from '../checkbox/checkbox.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -57,7 +58,7 @@ const EmojiPicker = {
} }
}, },
components: { components: {
StickerPicker: () => import('../sticker_picker/sticker_picker.vue'), StickerPicker: defineAsyncComponent(() => import('../sticker_picker/sticker_picker.vue')),
Checkbox Checkbox
}, },
methods: { methods: {
@ -79,7 +80,7 @@ const EmojiPicker = {
}, },
highlight (key) { highlight (key) {
const ref = this.$refs['group-' + key] const ref = this.$refs['group-' + key]
const top = ref[0].offsetTop const top = ref.offsetTop
this.setShowStickers(false) this.setShowStickers(false)
this.activeGroup = key this.activeGroup = key
this.$nextTick(() => { this.$nextTick(() => {
@ -96,7 +97,7 @@ const EmojiPicker = {
} }
}, },
triggerLoadMore (target) { triggerLoadMore (target) {
const ref = this.$refs['group-end-custom'][0] const ref = this.$refs['group-end-custom']
if (!ref) return if (!ref) return
const bottom = ref.offsetTop + ref.offsetHeight const bottom = ref.offsetTop + ref.offsetHeight
@ -119,7 +120,7 @@ const EmojiPicker = {
this.$nextTick(() => { this.$nextTick(() => {
this.emojisView.forEach(group => { this.emojisView.forEach(group => {
const ref = this.$refs['group-' + group.id] const ref = this.$refs['group-' + group.id]
if (ref[0].offsetTop <= top) { if (ref.offsetTop <= top) {
this.activeGroup = group.id this.activeGroup = group.id
} }
}) })

View file

@ -15,18 +15,8 @@ const Exporter = {
type: String, type: String,
default: 'export.csv' default: 'export.csv'
}, },
exportButtonLabel: { exportButtonLabel: { type: String },
type: String, processingMessage: { type: String }
default () {
return this.$t('exporter.export')
}
},
processingMessage: {
type: String,
default () {
return this.$t('exporter.processing')
}
}
}, },
data () { data () {
return { return {

View file

@ -7,14 +7,14 @@
spin spin
/> />
<span>{{ processingMessage }}</span> <span>{{ processingMessage || $t('exporter.processing') }}</span>
</div> </div>
<button <button
v-else v-else
class="btn button-default" class="btn button-default"
@click="process" @click="process"
> >
{{ exportButtonLabel }} {{ exportButtonLabel || $t('exporter.export') }}
</button> </button>
</div> </div>
</template> </template>

View file

@ -1,4 +1,4 @@
import { set } from 'vue' import { set } from 'lodash'
import Select from '../select/select.vue' import Select from '../select/select.vue'
export default { export default {
@ -6,11 +6,12 @@ export default {
Select Select
}, },
props: [ props: [
'name', 'label', 'value', 'fallback', 'options', 'no-inherit' 'name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'
], ],
emits: ['update:modelValue'],
data () { data () {
return { return {
lValue: this.value, lValue: this.modelValue,
availableOptions: [ availableOptions: [
this.noInherit ? '' : 'inherit', this.noInherit ? '' : 'inherit',
'custom', 'custom',
@ -22,7 +23,7 @@ export default {
} }
}, },
beforeUpdate () { beforeUpdate () {
this.lValue = this.value this.lValue = this.modelValue
}, },
computed: { computed: {
present () { present () {
@ -37,7 +38,7 @@ export default {
}, },
set (v) { set (v) {
set(this.lValue, 'family', v) set(this.lValue, 'family', v)
this.$emit('input', this.lValue) this.$emit('update:modelValue', this.lValue)
} }
}, },
isCustom () { isCustom () {

View file

@ -15,13 +15,14 @@
class="opt exlcude-disabled" class="opt exlcude-disabled"
type="checkbox" type="checkbox"
:checked="present" :checked="present"
@input="$emit('input', typeof value === 'undefined' ? fallback : undefined)" @change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
> >
<label <label
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
class="opt-l" class="opt-l"
:for="name + '-o'" :for="name + '-o'"
/> />
{{ ' ' }}
<Select <Select
:id="name + '-font-switcher'" :id="name + '-font-switcher'"
v-model="preset" v-model="preset"

View file

@ -1,5 +1,5 @@
import Attachment from '../attachment/attachment.vue' import Attachment from '../attachment/attachment.vue'
import { sumBy } from 'lodash' import { sumBy, set } from 'lodash'
const Gallery = { const Gallery = {
props: [ props: [
@ -85,7 +85,7 @@ const Gallery = {
}, },
methods: { methods: {
onNaturalSizeLoad ({ id, width, height }) { onNaturalSizeLoad ({ id, width, height }) {
this.$set(this.sizes, id, { width, height }) set(this.sizes, id, { width, height })
}, },
rowStyle (row) { rowStyle (row) {
if (row.audio) { if (row.audio) {

View file

@ -22,7 +22,6 @@
class="gallery-item" class="gallery-item"
:nsfw="nsfw" :nsfw="nsfw"
:attachment="attachment" :attachment="attachment"
:allow-play="false"
:size="size" :size="size"
:editable="editable" :editable="editable"
:remove="removeAttachment" :remove="removeAttachment"

View file

@ -117,7 +117,7 @@ const ImageCropper = {
const fileInput = this.$refs.input const fileInput = this.$refs.input
fileInput.addEventListener('change', this.readFile) fileInput.addEventListener('change', this.readFile)
}, },
beforeDestroy: function () { beforeUnmount: function () {
// remove the event listeners // remove the event listeners
const trigger = this.getTriggerDOM() const trigger = this.getTriggerDOM()
if (trigger) { if (trigger) {

View file

@ -15,24 +15,9 @@ const Importer = {
type: Function, type: Function,
required: true required: true
}, },
submitButtonLabel: { submitButtonLabel: { type: String },
type: String, successMessage: { type: String },
default () { errorMessage: { type: String }
return this.$t('importer.submit')
}
},
successMessage: {
type: String,
default () {
return this.$t('importer.success')
}
},
errorMessage: {
type: String,
default () {
return this.$t('importer.error')
}
}
}, },
data () { data () {
return { return {

View file

@ -18,21 +18,31 @@
class="btn button-default" class="btn button-default"
@click="submit" @click="submit"
> >
{{ submitButtonLabel }} {{ submitButtonLabel || $t('importer.submit') }}
</button> </button>
<div v-if="success"> <div v-if="success">
<FAIcon <button
icon="times" class="button-unstyled"
@click="dismiss" @click="dismiss"
/> >
<p>{{ successMessage }}</p> <FAIcon
icon="times"
/>
</button>
{{ ' ' }}
<span>{{ successMessage || $t('importer.success') }}</span>
</div> </div>
<div v-else-if="error"> <div v-else-if="error">
<FAIcon <button
icon="times" class="button-unstyled"
@click="dismiss" @click="dismiss"
/> >
<p>{{ errorMessage }}</p> <FAIcon
icon="times"
/>
</button>
{{ ' ' }}
<span>{{ errorMessage || $t('importer.error') }}</span>
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,4 +1,5 @@
import Notifications from '../notifications/notifications.vue' import Notifications from '../notifications/notifications.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
const tabModeDict = { const tabModeDict = {
mentions: ['mention'], mentions: ['mention'],
@ -20,7 +21,8 @@ const Interactions = {
} }
}, },
components: { components: {
Notifications Notifications,
TabSwitcher
} }
} }

View file

@ -3,6 +3,7 @@
<label for="interface-language-switcher"> <label for="interface-language-switcher">
{{ $t('settings.interfaceLanguage') }} {{ $t('settings.interfaceLanguage') }}
</label> </label>
{{ ' ' }}
<Select <Select
id="interface-language-switcher" id="interface-language-switcher"
v-model="language" v-model="language"

View file

@ -76,11 +76,15 @@
> >
<div class="alert error"> <div class="alert error">
{{ error }} {{ error }}
<FAIcon <button
class="fa-scale-110 fa-old-padding" class="button-unstyled"
icon="times"
@click="clearError" @click="clearError"
/> >
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -142,7 +142,7 @@ const MediaModal = {
document.addEventListener('keyup', this.handleKeyupEvent) document.addEventListener('keyup', this.handleKeyupEvent)
document.addEventListener('keydown', this.handleKeydownEvent) document.addEventListener('keydown', this.handleKeydownEvent)
}, },
destroyed () { unmounted () {
window.removeEventListener('popstate', this.hide) window.removeEventListener('popstate', this.hide)
document.removeEventListener('keyup', this.handleKeyupEvent) document.removeEventListener('keyup', this.handleKeyupEvent)
document.removeEventListener('keydown', this.handleKeydownEvent) document.removeEventListener('keydown', this.handleKeydownEvent)

View file

@ -41,10 +41,12 @@
class="serverName" class="serverName"
:class="{ '-faded': shouldFadeDomain }" :class="{ '-faded': shouldFadeDomain }"
v-html="'@' + serverName" v-html="'@' + serverName"
/></span><span />
</span>
<span
v-if="isYou && shouldShowYous" v-if="isYou && shouldShowYous"
:class="{ '-you': shouldBoldenYou }" :class="{ '-you': shouldBoldenYou }"
> {{ $t('status.you') }}</span> > {{ ' ' + $t('status.you') }}</span>
<!-- eslint-enable vue/no-v-html --> <!-- eslint-enable vue/no-v-html -->
</a><span </a><span
v-if="shouldShowTooltip" v-if="shouldShowTooltip"

View file

@ -6,7 +6,6 @@
class="mention-link" class="mention-link"
:content="mention.content" :content="mention.content"
:url="mention.url" :url="mention.url"
:first-mention="false"
/><span /><span
v-if="manyMentions" v-if="manyMentions"
class="extraMentions" class="extraMentions"
@ -21,7 +20,6 @@
class="mention-link" class="mention-link"
:content="mention.content" :content="mention.content"
:url="mention.url" :url="mention.url"
:first-mention="false"
/> />
</span><button </span><button
v-if="!expanded" v-if="!expanded"

View file

@ -56,11 +56,15 @@
> >
<div class="alert error"> <div class="alert error">
{{ error }} {{ error }}
<FAIcon <button
class="fa-scale-110 fa-old-padding" class="button-unstyled"
icon="times"
@click="clearError" @click="clearError"
/> >
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -58,12 +58,16 @@
> >
<div class="alert error"> <div class="alert error">
{{ error }} {{ error }}
<FAIcon <button
size="lg" class="button-unstyled"
class="fa-scale-110 fa-old-padding"
icon="times"
@click="clearError" @click="clearError"
/> >
<FAIcon
size="lg"
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div> </div>
</div> </div>
</div> </div>

View file

@ -99,6 +99,9 @@
width: 100%; width: 100%;
position: fixed; position: fixed;
box-sizing: border-box; box-sizing: border-box;
a {
color: var(--topBarLink, $fallback--link);
}
} }
.mobile-inner-nav { .mobile-inner-nav {

View file

@ -29,7 +29,7 @@ const MobilePostStatusButton = {
} }
window.addEventListener('resize', this.handleOSK) window.addEventListener('resize', this.handleOSK)
}, },
destroyed () { unmounted () {
if (this.autohideFloatingPostButton) { if (this.autohideFloatingPostButton) {
this.deactivateFloatingPostButtonAutohide() this.deactivateFloatingPostButtonAutohide()
} }

View file

@ -1,13 +1,12 @@
<template> <template>
<div v-if="isLoggedIn"> <button
<button v-if="isLoggedIn"
class="button-default new-status-button" class="MobilePostButton button-default new-status-button"
:class="{ 'hidden': isHidden, 'always-show': isPersistent }" :class="{ 'hidden': isHidden, 'always-show': isPersistent }"
@click="openPostForm" @click="openPostForm"
> >
<FAIcon icon="pen" /> <FAIcon icon="pen" />
</button> </button>
</div>
</template> </template>
<script src="./mobile_post_status_button.js"></script> <script src="./mobile_post_status_button.js"></script>
@ -15,25 +14,27 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.new-status-button { .MobilePostButton {
width: 5em; &.button-default {
height: 5em; width: 5em;
border-radius: 100%; height: 5em;
position: fixed; border-radius: 100%;
bottom: 1.5em; position: fixed;
right: 1.5em; bottom: 1.5em;
// TODO: this needs its own color, it has to stand out enough and link color right: 1.5em;
// is not very optimal for this particular use. // TODO: this needs its own color, it has to stand out enough and link color
background-color: $fallback--fg; // is not very optimal for this particular use.
background-color: var(--btn, $fallback--fg); background-color: $fallback--fg;
display: flex; background-color: var(--btn, $fallback--fg);
justify-content: center; display: flex;
align-items: center; justify-content: center;
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3), 0px 4px 6px rgba(0, 0, 0, 0.3); align-items: center;
z-index: 10; box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3), 0px 4px 6px rgba(0, 0, 0, 0.3);
z-index: 10;
transition: 0.35s transform; transition: 0.35s transform;
transition-timing-function: cubic-bezier(0, 1, 0.5, 1); transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
}
&.hidden { &.hidden {
transform: translateY(150%); transform: translateY(150%);

View file

@ -132,7 +132,7 @@
</button> </button>
</template> </template>
</Popover> </Popover>
<portal to="modal"> <teleport to="#modal">
<DialogModal <DialogModal
v-if="showDeleteUserDialog" v-if="showDeleteUserDialog"
:on-cancel="deleteUserDialog.bind(this, false)" :on-cancel="deleteUserDialog.bind(this, false)"
@ -156,7 +156,7 @@
</button> </button>
</template> </template>
</DialogModal> </DialogModal>
</portal> </teleport>
</div> </div>
</template> </template>

View file

@ -33,7 +33,7 @@
> >
<a <a
class="avatar-container" class="avatar-container"
:href="notification.from_profile.statusnet_profile_url" :href="$router.resolve(userProfileLink).href"
@click.stop.prevent.capture="toggleUserExpanded" @click.stop.prevent.capture="toggleUserExpanded"
> >
<UserAvatar <UserAvatar
@ -65,12 +65,16 @@
v-else v-else
class="username" class="username"
:title="'@'+notification.from_profile.screen_name_ui" :title="'@'+notification.from_profile.screen_name_ui"
>{{ notification.from_profile.name }}</span> >
{{ notification.from_profile.name }}
</span>
{{ ' ' }}
<span v-if="notification.type === 'like'"> <span v-if="notification.type === 'like'">
<FAIcon <FAIcon
class="type-icon" class="type-icon"
icon="star" icon="star"
/> />
{{ ' ' }}
<small>{{ $t('notifications.favorited_you') }}</small> <small>{{ $t('notifications.favorited_you') }}</small>
</span> </span>
<span v-if="notification.type === 'repeat'"> <span v-if="notification.type === 'repeat'">
@ -79,6 +83,7 @@
icon="retweet" icon="retweet"
:title="$t('tool_tip.repeat')" :title="$t('tool_tip.repeat')"
/> />
{{ ' ' }}
<small>{{ $t('notifications.repeated_you') }}</small> <small>{{ $t('notifications.repeated_you') }}</small>
</span> </span>
<span v-if="notification.type === 'follow'"> <span v-if="notification.type === 'follow'">
@ -86,6 +91,7 @@
class="type-icon" class="type-icon"
icon="user-plus" icon="user-plus"
/> />
{{ ' ' }}
<small>{{ $t('notifications.followed_you') }}</small> <small>{{ $t('notifications.followed_you') }}</small>
</span> </span>
<span v-if="notification.type === 'follow_request'"> <span v-if="notification.type === 'follow_request'">
@ -93,6 +99,7 @@
class="type-icon" class="type-icon"
icon="user" icon="user"
/> />
{{ ' ' }}
<small>{{ $t('notifications.follow_request') }}</small> <small>{{ $t('notifications.follow_request') }}</small>
</span> </span>
<span v-if="notification.type === 'move'"> <span v-if="notification.type === 'move'">
@ -100,13 +107,17 @@
class="type-icon" class="type-icon"
icon="suitcase-rolling" icon="suitcase-rolling"
/> />
{{ ' ' }}
<small>{{ $t('notifications.migrated_to') }}</small> <small>{{ $t('notifications.migrated_to') }}</small>
</span> </span>
<span v-if="notification.type === 'pleroma:emoji_reaction'"> <span v-if="notification.type === 'pleroma:emoji_reaction'">
<small> <small>
<i18n path="notifications.reacted_with"> <i18n-t
scope="global"
keypath="notifications.reacted_with"
>
<span class="emoji-reaction-emoji">{{ notification.emoji }}</span> <span class="emoji-reaction-emoji">{{ notification.emoji }}</span>
</i18n> </i18n-t>
</small> </small>
</span> </span>
</div> </div>
@ -161,18 +172,26 @@
v-if="notification.type === 'follow_request'" v-if="notification.type === 'follow_request'"
style="white-space: nowrap;" style="white-space: nowrap;"
> >
<FAIcon <button
icon="check" class="button-unstyled"
class="fa-scale-110 fa-old-padding follow-request-accept"
:title="$t('tool_tip.accept_follow_request')" :title="$t('tool_tip.accept_follow_request')"
@click="approveUser()" @click="approveUser()"
/> >
<FAIcon <FAIcon
icon="times" icon="check"
class="fa-scale-110 fa-old-padding follow-request-reject" class="fa-scale-110 fa-old-padding follow-request-accept"
/>
</button>
<button
class="button-unstyled"
:title="$t('tool_tip.reject_follow_request')" :title="$t('tool_tip.reject_follow_request')"
@click="denyUser()" @click="denyUser()"
/> >
<FAIcon
icon="times"
class="fa-scale-110 fa-old-padding follow-request-reject"
/>
</button>
</div> </div>
</div> </div>
<div <div

View file

@ -64,8 +64,6 @@
} }
.follow-request-accept { .follow-request-accept {
cursor: pointer;
&:hover { &:hover {
color: $fallback--text; color: $fallback--text;
color: var(--text, $fallback--text); color: var(--text, $fallback--text);
@ -73,8 +71,6 @@
} }
.follow-request-reject { .follow-request-reject {
cursor: pointer;
&:hover { &:hover {
color: $fallback--cRed; color: $fallback--cRed;
color: var(--cRed, $fallback--cRed); color: var(--cRed, $fallback--cRed);

View file

@ -11,21 +11,21 @@
</label> </label>
<Checkbox <Checkbox
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
:checked="present" :model-value="present"
:disabled="disabled" :disabled="disabled"
class="opt" class="opt"
@change="$emit('input', !present ? fallback : undefined)" @update:modelValue="$emit('update:modelValue', !present ? fallback : undefined)"
/> />
<input <input
:id="name" :id="name"
class="input-number" class="input-number"
type="number" type="number"
:value="value || fallback" :value="modelValue || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
max="1" max="1"
min="0" min="0"
step=".05" step=".05"
@input="$emit('input', $event.target.value)" @input="$emit('update:modelValue', $event.target.value)"
> >
</div> </div>
</template> </template>
@ -37,11 +37,12 @@ export default {
Checkbox Checkbox
}, },
props: [ props: [
'name', 'value', 'fallback', 'disabled' 'name', 'modelValue', 'fallback', 'disabled'
], ],
emits: ['update:modelValue'],
computed: { computed: {
present () { present () {
return typeof this.value !== 'undefined' return typeof this.modelValue !== 'undefined'
} }
} }
} }

View file

@ -21,7 +21,7 @@ export default {
} }
this.$store.dispatch('trackPoll', this.pollId) this.$store.dispatch('trackPoll', this.pollId)
}, },
destroyed () { unmounted () {
this.$store.dispatch('untrackPoll', this.pollId) this.$store.dispatch('untrackPoll', this.pollId)
}, },
computed: { computed: {

View file

@ -71,13 +71,18 @@
{{ $tc("polls.votes_count", poll.votes_count, { count: poll.votes_count }) }}&nbsp;·&nbsp; {{ $tc("polls.votes_count", poll.votes_count, { count: poll.votes_count }) }}&nbsp;·&nbsp;
</template> </template>
</div> </div>
<i18n :path="expired ? 'polls.expired' : 'polls.expires_in'"> <span>
<Timeago <i18n-t
:time="expiresAt" scope="global"
:auto-update="60" :keypath="expired ? 'polls.expired' : 'polls.expires_in'"
:now-threshold="0" >
/> <Timeago
</i18n> :time="expiresAt"
:auto-update="60"
:now-threshold="0"
/>
</i18n-t>
</span>
</div> </div>
</div> </div>
</template> </template>

View file

@ -72,6 +72,7 @@
:max="maxExpirationInCurrentUnit" :max="maxExpirationInCurrentUnit"
@change="expiryAmountChange" @change="expiryAmountChange"
> >
{{ ' ' }}
<Select <Select
v-model="expiryUnit" v-model="expiryUnit"
unstyled="true" unstyled="true"

View file

@ -178,7 +178,7 @@ const Popover = {
created () { created () {
document.addEventListener('click', this.onClickOutside) document.addEventListener('click', this.onClickOutside)
}, },
destroyed () { unmounted () {
document.removeEventListener('click', this.onClickOutside) document.removeEventListener('click', this.onClickOutside)
this.hidePopover() this.hidePopover()
} }

View file

@ -149,5 +149,30 @@
} }
} }
.button-default.dropdown-item {
&,
i[class*=icon-] {
color: $fallback--text;
color: var(--btnText, $fallback--text);
}
&:active {
background-color: $fallback--lightBg;
background-color: var(--selectedMenuPopover, $fallback--lightBg);
color: $fallback--link;
color: var(--selectedMenuPopoverText, $fallback--link);
}
&:disabled {
color: $fallback--text;
color: var(--btnDisabledText, $fallback--text);
}
&.toggled {
color: $fallback--text;
color: var(--btnToggledText, $fallback--text);
}
}
} }
</style> </style>

View file

@ -78,6 +78,12 @@ const PostStatusForm = {
'emojiPickerPlacement', 'emojiPickerPlacement',
'optimisticPosting' 'optimisticPosting'
], ],
emits: [
'posted',
'resize',
'mediaplay',
'mediapause'
],
components: { components: {
MediaUpload, MediaUpload,
EmojiInput, EmojiInput,

View file

@ -18,11 +18,12 @@
<FAIcon :icon="uploadFileLimitReached ? 'ban' : 'upload'" /> <FAIcon :icon="uploadFileLimitReached ? 'ban' : 'upload'" />
</div> </div>
<div class="form-group"> <div class="form-group">
<i18n <i18n-t
v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning" v-if="!$store.state.users.currentUser.locked && newStatus.visibility == 'private' && !disableLockWarning"
path="post_status.account_not_locked_warning" keypath="post_status.account_not_locked_warning"
tag="p" tag="p"
class="visibility-notice" class="visibility-notice"
scope="global"
> >
<button <button
class="button-unstyled -link" class="button-unstyled -link"
@ -30,7 +31,7 @@
> >
{{ $t('post_status.account_not_locked_warning_link') }} {{ $t('post_status.account_not_locked_warning_link') }}
</button> </button>
</i18n> </i18n-t>
<p <p
v-if="!hideScopeNotice && newStatus.visibility === 'public'" v-if="!hideScopeNotice && newStatus.visibility === 'public'"
class="visibility-notice notice-dismissible" class="visibility-notice notice-dismissible"
@ -281,11 +282,15 @@
class="alert error" class="alert error"
> >
Error: {{ error }} Error: {{ error }}
<FAIcon <button
class="fa-scale-110 fa-old-padding" class="button-unstyled"
icon="times"
@click="clearError" @click="clearError"
/> >
<FAIcon
class="fa-scale-110 fa-old-padding"
icon="times"
/>
</button>
</div> </div>
<gallery <gallery
v-if="newStatus.files && newStatus.files.length > 0" v-if="newStatus.files && newStatus.files.length > 0"

View file

@ -9,7 +9,7 @@ const PublicAndExternalTimeline = {
created () { created () {
this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' }) this.$store.dispatch('startFetchingTimeline', { timeline: 'publicAndExternal' })
}, },
destroyed () { unmounted () {
this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal') this.$store.dispatch('stopFetchingTimeline', 'publicAndExternal')
} }
} }

View file

@ -9,7 +9,7 @@ const PublicTimeline = {
created () { created () {
this.$store.dispatch('startFetchingTimeline', { timeline: 'public' }) this.$store.dispatch('startFetchingTimeline', { timeline: 'public' })
}, },
destroyed () { unmounted () {
this.$store.dispatch('stopFetchingTimeline', 'public') this.$store.dispatch('stopFetchingTimeline', 'public')
} }

View file

@ -15,7 +15,7 @@
class="opt" class="opt"
type="checkbox" type="checkbox"
:checked="present" :checked="present"
@input="$emit('input', !present ? fallback : undefined)" @change="$emit('update:modelValue', !present ? fallback : undefined)"
> >
<label <label
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
@ -26,23 +26,23 @@
:id="name" :id="name"
class="input-number" class="input-number"
type="range" type="range"
:value="value || fallback" :value="modelValue || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
:max="max || hardMax || 100" :max="max || hardMax || 100"
:min="min || hardMin || 0" :min="min || hardMin || 0"
:step="step || 1" :step="step || 1"
@input="$emit('input', $event.target.value)" @input="$emit('update:modelValue', $event.target.value)"
> >
<input <input
:id="name" :id="name"
class="input-number" class="input-number"
type="number" type="number"
:value="value || fallback" :value="modelValue || fallback"
:disabled="!present || disabled" :disabled="!present || disabled"
:max="hardMax" :max="hardMax"
:min="hardMin" :min="hardMin"
:step="step || 1" :step="step || 1"
@input="$emit('input', $event.target.value)" @input="$emit('update:modelValue', $event.target.value)"
> >
</div> </div>
</template> </template>
@ -50,11 +50,12 @@
<script> <script>
export default { export default {
props: [ props: [
'name', 'value', 'fallback', 'disabled', 'label', 'max', 'min', 'step', 'hardMin', 'hardMax' 'name', 'modelValue', 'fallback', 'disabled', 'label', 'max', 'min', 'step', 'hardMin', 'hardMax'
], ],
emits: ['update:modelValue'],
computed: { computed: {
present () { present () {
return typeof this.value !== 'undefined' return typeof this.modelValue !== 'undefined'
} }
} }
} }

View file

@ -1,9 +1,9 @@
import { validationMixin } from 'vuelidate' import useVuelidate from '@vuelidate/core'
import { required, requiredIf, sameAs } from 'vuelidate/lib/validators' import { required, requiredIf, sameAs } from '@vuelidate/validators'
import { mapActions, mapState } from 'vuex' import { mapActions, mapState } from 'vuex'
const registration = { const registration = {
mixins: [validationMixin], setup () { return { v$: useVuelidate() } },
data: () => ({ data: () => ({
user: { user: {
email: '', email: '',
@ -24,7 +24,7 @@ const registration = {
password: { required }, password: { required },
confirm: { confirm: {
required, required,
sameAsPassword: sameAs('password') sameAs: sameAs(this.user.password)
}, },
reason: { required: requiredIf(() => this.accountApprovalRequired) } reason: { required: requiredIf(() => this.accountApprovalRequired) }
} }
@ -65,9 +65,9 @@ const registration = {
this.user.captcha_token = this.captcha.token this.user.captcha_token = this.captcha.token
this.user.captcha_answer_data = this.captcha.answer_data this.user.captcha_answer_data = this.captcha.answer_data
this.$v.$touch() this.v$.$touch()
if (!this.$v.$invalid) { if (!this.v$.$invalid) {
try { try {
await this.signUp(this.user) await this.signUp(this.user)
this.$router.push({ name: 'friends' }) this.$router.push({ name: 'friends' })

View file

@ -12,7 +12,7 @@
<div class="text-fields"> <div class="text-fields">
<div <div
class="form-group" class="form-group"
:class="{ 'form-group--error': $v.user.username.$error }" :class="{ 'form-group--error': v$.user.username.$error }"
> >
<label <label
class="form--label" class="form--label"
@ -20,18 +20,18 @@
>{{ $t('login.username') }}</label> >{{ $t('login.username') }}</label>
<input <input
id="sign-up-username" id="sign-up-username"
v-model.trim="$v.user.username.$model" v-model.trim="v$.user.username.$model"
:disabled="isPending" :disabled="isPending"
class="form-control" class="form-control"
:placeholder="$t('registration.username_placeholder')" :placeholder="$t('registration.username_placeholder')"
> >
</div> </div>
<div <div
v-if="$v.user.username.$dirty" v-if="v$.user.username.$dirty"
class="form-error" class="form-error"
> >
<ul> <ul>
<li v-if="!$v.user.username.required"> <li v-if="!v$.user.username.required">
<span>{{ $t('registration.validations.username_required') }}</span> <span>{{ $t('registration.validations.username_required') }}</span>
</li> </li>
</ul> </ul>
@ -39,7 +39,7 @@
<div <div
class="form-group" class="form-group"
:class="{ 'form-group--error': $v.user.fullname.$error }" :class="{ 'form-group--error': v$.user.fullname.$error }"
> >
<label <label
class="form--label" class="form--label"
@ -47,18 +47,18 @@
>{{ $t('registration.fullname') }}</label> >{{ $t('registration.fullname') }}</label>
<input <input
id="sign-up-fullname" id="sign-up-fullname"
v-model.trim="$v.user.fullname.$model" v-model.trim="v$.user.fullname.$model"
:disabled="isPending" :disabled="isPending"
class="form-control" class="form-control"
:placeholder="$t('registration.fullname_placeholder')" :placeholder="$t('registration.fullname_placeholder')"
> >
</div> </div>
<div <div
v-if="$v.user.fullname.$dirty" v-if="v$.user.fullname.$dirty"
class="form-error" class="form-error"
> >
<ul> <ul>
<li v-if="!$v.user.fullname.required"> <li v-if="!v$.user.fullname.required">
<span>{{ $t('registration.validations.fullname_required') }}</span> <span>{{ $t('registration.validations.fullname_required') }}</span>
</li> </li>
</ul> </ul>
@ -66,7 +66,7 @@
<div <div
class="form-group" class="form-group"
:class="{ 'form-group--error': $v.user.email.$error }" :class="{ 'form-group--error': v$.user.email.$error }"
> >
<label <label
class="form--label" class="form--label"
@ -74,18 +74,18 @@
>{{ $t('registration.email') }}</label> >{{ $t('registration.email') }}</label>
<input <input
id="email" id="email"
v-model="$v.user.email.$model" v-model="v$.user.email.$model"
:disabled="isPending" :disabled="isPending"
class="form-control" class="form-control"
type="email" type="email"
> >
</div> </div>
<div <div
v-if="$v.user.email.$dirty" v-if="v$.user.email.$dirty"
class="form-error" class="form-error"
> >
<ul> <ul>
<li v-if="!$v.user.email.required"> <li v-if="!v$.user.email.required">
<span>{{ $t('registration.validations.email_required') }}</span> <span>{{ $t('registration.validations.email_required') }}</span>
</li> </li>
</ul> </ul>
@ -107,7 +107,7 @@
<div <div
class="form-group" class="form-group"
:class="{ 'form-group--error': $v.user.password.$error }" :class="{ 'form-group--error': v$.user.password.$error }"
> >
<label <label
class="form--label" class="form--label"
@ -122,11 +122,11 @@
> >
</div> </div>
<div <div
v-if="$v.user.password.$dirty" v-if="v$.user.password.$dirty"
class="form-error" class="form-error"
> >
<ul> <ul>
<li v-if="!$v.user.password.required"> <li v-if="!v$.user.password.required">
<span>{{ $t('registration.validations.password_required') }}</span> <span>{{ $t('registration.validations.password_required') }}</span>
</li> </li>
</ul> </ul>
@ -134,7 +134,7 @@
<div <div
class="form-group" class="form-group"
:class="{ 'form-group--error': $v.user.confirm.$error }" :class="{ 'form-group--error': v$.user.confirm.$error }"
> >
<label <label
class="form--label" class="form--label"
@ -149,14 +149,14 @@
> >
</div> </div>
<div <div
v-if="$v.user.confirm.$dirty" v-if="v$.user.confirm.$dirty"
class="form-error" class="form-error"
> >
<ul> <ul>
<li v-if="!$v.user.confirm.required"> <li v-if="!v$.user.confirm.required">
<span>{{ $t('registration.validations.password_confirmation_required') }}</span> <span>{{ $t('registration.validations.password_confirmation_required') }}</span>
</li> </li>
<li v-if="!$v.user.confirm.sameAsPassword"> <li v-if="!v$.user.confirm.sameAsPassword">
<span>{{ $t('registration.validations.password_confirmation_match') }}</span> <span>{{ $t('registration.validations.password_confirmation_match') }}</span>
</li> </li>
</ul> </ul>

View file

@ -1,4 +1,3 @@
import Vue from 'vue'
import { unescape, flattenDeep } from 'lodash' import { unescape, flattenDeep } from 'lodash'
import { getTagName, processTextForEmoji, getAttrs } from 'src/services/html_converter/utility.service.js' import { getTagName, processTextForEmoji, getAttrs } from 'src/services/html_converter/utility.service.js'
import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js' import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js'
@ -27,8 +26,12 @@ import './rich_content.scss'
* *
* Apart from that one small hiccup with emit in render this _should_ be vue3-ready * Apart from that one small hiccup with emit in render this _should_ be vue3-ready
*/ */
export default Vue.component('RichContent', { export default {
name: 'RichContent', name: 'RichContent',
components: {
MentionsLine,
HashtagLink
},
props: { props: {
// Original html content // Original html content
html: { html: {
@ -58,7 +61,7 @@ export default Vue.component('RichContent', {
} }
}, },
// NEVER EVER TOUCH DATA INSIDE RENDER // NEVER EVER TOUCH DATA INSIDE RENDER
render (h) { render () {
// Pre-process HTML // Pre-process HTML
const { newHtml: html } = preProcessPerLine(this.html, this.greentext) const { newHtml: html } = preProcessPerLine(this.html, this.greentext)
let currentMentions = null // Current chain of mentions, we group all mentions together let currentMentions = null // Current chain of mentions, we group all mentions together
@ -76,18 +79,19 @@ export default Vue.component('RichContent', {
const renderImage = (tag) => { const renderImage = (tag) => {
return <StillImage return <StillImage
{...{ attrs: getAttrs(tag) }} {...getAttrs(tag)}
class="img" class="img"
/> />
} }
const renderHashtag = (attrs, children, encounteredTextReverse) => { const renderHashtag = (attrs, children, encounteredTextReverse) => {
const linkData = getLinkData(attrs, children, tagsIndex++) const { index, ...linkData } = getLinkData(attrs, children, tagsIndex++)
writtenTags.push(linkData) writtenTags.push(linkData)
if (!encounteredTextReverse) { if (!encounteredTextReverse) {
lastTags.push(linkData) lastTags.push(linkData)
} }
return <HashtagLink {...{ props: linkData }}/> const { url, tag, content } = linkData
return <HashtagLink url={url} tag={tag} content={content}/>
} }
const renderMention = (attrs, children) => { const renderMention = (attrs, children) => {
@ -222,7 +226,7 @@ export default Vue.component('RichContent', {
attrs.target = '_blank' attrs.target = '_blank'
const newChildren = [...children].reverse().map(processItemReverse).reverse() const newChildren = [...children].reverse().map(processItemReverse).reverse()
return <a {...{ attrs }}> return <a {...attrs}>
{ newChildren } { newChildren }
</a> </a>
} }
@ -235,7 +239,7 @@ export default Vue.component('RichContent', {
const newChildren = Array.isArray(children) const newChildren = Array.isArray(children)
? [...children].reverse().map(processItemReverse).reverse() ? [...children].reverse().map(processItemReverse).reverse()
: children : children
return <Tag {...{ attrs: getAttrs(opener) }}> return <Tag {...getAttrs(opener)}>
{ newChildren } { newChildren }
</Tag> </Tag>
} else { } else {
@ -266,7 +270,7 @@ export default Vue.component('RichContent', {
return result return result
} }
}) }
const getLinkData = (attrs, children, index) => { const getLinkData = (attrs, children, index) => {
const stripTags = (item) => { const stripTags = (item) => {

View file

@ -16,6 +16,7 @@
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"
/> />
</button> </button>
{{ ' ' }}
<button <button
v-if="showPrivate" v-if="showPrivate"
class="button-unstyled scope" class="button-unstyled scope"
@ -29,6 +30,7 @@
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"
/> />
</button> </button>
{{ ' ' }}
<button <button
v-if="showUnlisted" v-if="showUnlisted"
class="button-unstyled scope" class="button-unstyled scope"
@ -42,6 +44,7 @@
class="fa-scale-110 fa-old-padding" class="fa-scale-110 fa-old-padding"
/> />
</button> </button>
{{ ' ' }}
<button <button
v-if="showPublic" v-if="showPublic"
class="button-unstyled scope" class="button-unstyled scope"

View file

@ -1,6 +1,7 @@
import FollowCard from '../follow_card/follow_card.vue' import FollowCard from '../follow_card/follow_card.vue'
import Conversation from '../conversation/conversation.vue' import Conversation from '../conversation/conversation.vue'
import Status from '../status/status.vue' import Status from '../status/status.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import map from 'lodash/map' import map from 'lodash/map'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
@ -17,7 +18,8 @@ const Search = {
components: { components: {
FollowCard, FollowCard,
Conversation, Conversation,
Status Status,
TabSwitcher
}, },
props: [ props: [
'query' 'query'

View file

@ -8,12 +8,9 @@ library.add(
) )
export default { export default {
model: { emits: ['update:modelValue'],
prop: 'value',
event: 'change'
},
props: [ props: [
'value', 'modelValue',
'disabled', 'disabled',
'unstyled', 'unstyled',
'kind' 'kind'

View file

@ -1,4 +1,3 @@
<template> <template>
<label <label
class="Select input" class="Select input"
@ -6,11 +5,12 @@
> >
<select <select
:disabled="disabled" :disabled="disabled"
:value="value" :value="modelValue"
@change="$emit('change', $event.target.value)" @change="$emit('update:modelValue', $event.target.value)"
> >
<slot /> <slot />
</select> </select>
{{ ' ' }}
<FAIcon <FAIcon
class="select-down-icon" class="select-down-icon"
icon="chevron-down" icon="chevron-down"
@ -23,7 +23,8 @@
<style lang="scss"> <style lang="scss">
@import '../../_variables.scss'; @import '../../_variables.scss';
.Select { /* TODO fix order of styles */
label.Select {
padding: 0; padding: 0;
select { select {

View file

@ -6,9 +6,9 @@
> >
<div class="selectable-list-checkbox-wrapper"> <div class="selectable-list-checkbox-wrapper">
<Checkbox <Checkbox
:checked="allSelected" :model-value="allSelected"
:indeterminate="someSelected" :indeterminate="someSelected"
@change="toggleAll" @update:model-value="toggleAll"
> >
{{ $t('selectable_list.select_all') }} {{ $t('selectable_list.select_all') }}
</Checkbox> </Checkbox>
@ -31,8 +31,8 @@
> >
<div class="selectable-list-checkbox-wrapper"> <div class="selectable-list-checkbox-wrapper">
<Checkbox <Checkbox
:checked="isSelected(item)" :model-value="isSelected(item)"
@change="checked => toggle(checked, item)" @update:model-value="checked => toggle(checked, item)"
/> />
</div> </div>
<slot <slot

View file

@ -4,9 +4,9 @@
class="BooleanSetting" class="BooleanSetting"
> >
<Checkbox <Checkbox
:checked="state" :model-value="state"
:disabled="disabled" :disabled="disabled"
@change="update" @update:modelValue="update"
> >
<span <span
v-if="!!$slots.default" v-if="!!$slots.default"
@ -14,6 +14,7 @@
> >
<slot /> <slot />
</span> </span>
{{ ' ' }}
<ModifiedIndicator :changed="isChanged" /><ServerSideIndicator :server-side="isServerSide" /> </Checkbox> <ModifiedIndicator :changed="isChanged" /><ServerSideIndicator :server-side="isServerSide" /> </Checkbox>
</label> </label>
</template> </template>

View file

@ -4,10 +4,11 @@
class="ChoiceSetting" class="ChoiceSetting"
> >
<slot /> <slot />
{{ ' ' }}
<Select <Select
:value="state" :model-value="state"
:disabled="disabled" :disabled="disabled"
@change="update" @update:modelValue="update"
> >
<option <option
v-for="option in options" v-for="option in options"

View file

@ -8,7 +8,7 @@ export default {
path: String, path: String,
disabled: Boolean, disabled: Boolean,
min: Number, min: Number,
expert: Number expert: [Number, String]
}, },
computed: { computed: {
pathDefault () { pathDefault () {

View file

@ -16,6 +16,7 @@
:value="state" :value="state"
@change="update" @change="update"
> >
{{ ' ' }}
<ModifiedIndicator :changed="isChanged" /> <ModifiedIndicator :changed="isChanged" />
</span> </span>
</template> </template>

View file

@ -56,8 +56,8 @@ const SettingsModal = {
SettingsModalContent: getResettableAsyncComponent( SettingsModalContent: getResettableAsyncComponent(
() => import('./settings_modal_content.vue'), () => import('./settings_modal_content.vue'),
{ {
loading: PanelLoading, loadingComponent: PanelLoading,
error: AsyncComponentError, errorComponent: AsyncComponentError,
delay: 0 delay: 0
} }
) )

View file

@ -54,5 +54,10 @@
>* { >* {
margin-right: 0.5em; margin-right: 0.5em;
} }
.extra-content {
display: flex;
flex-grow: 1;
}
} }
} }

View file

@ -11,7 +11,7 @@
{{ $t('settings.settings') }} {{ $t('settings.settings') }}
</span> </span>
<transition name="fade"> <transition name="fade">
<template v-if="currentSaveStateNotice"> <div v-if="currentSaveStateNotice">
<div <div
v-if="currentSaveStateNotice.error" v-if="currentSaveStateNotice.error"
class="alert error" class="alert error"
@ -27,7 +27,7 @@
> >
{{ $t('settings.saving_ok') }} {{ $t('settings.saving_ok') }}
</div> </div>
</template> </div>
</transition> </transition>
<button <button
class="btn button-default" class="btn button-default"
@ -68,6 +68,7 @@
:title="$t('general.close')" :title="$t('general.close')"
> >
<span>{{ $t("settings.file_export_import.backup_restore") }}</span> <span>{{ $t("settings.file_export_import.backup_restore") }}</span>
{{ ' ' }}
<FAIcon <FAIcon
icon="chevron-down" icon="chevron-down"
/> />
@ -109,9 +110,16 @@
</template> </template>
</Popover> </Popover>
<Checkbox v-model="expertLevel"> <Checkbox
:model-value="!!expertLevel"
@update:modelValue="expertLevel = Number($event)"
>
{{ $t("settings.expert_mode") }} {{ $t("settings.expert_mode") }}
</Checkbox> </Checkbox>
<span
id="unscrolled-content"
class="extra-content"
/>
</div> </div>
</div> </div>
</Modal> </Modal>

View file

@ -1,4 +1,4 @@
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import DataImportExportTab from './tabs/data_import_export_tab.vue' import DataImportExportTab from './tabs/data_import_export_tab.vue'
import MutesAndBlocksTab from './tabs/mutes_and_blocks_tab.vue' import MutesAndBlocksTab from './tabs/mutes_and_blocks_tab.vue'
@ -53,6 +53,9 @@ const SettingsModalContent = {
}, },
open () { open () {
return this.$store.state.interface.settingsModalState !== 'hidden' return this.$store.state.interface.settingsModalState !== 'hidden'
},
bodyLock () {
return this.$store.state.interface.settingsModalState === 'visible'
} }
}, },
methods: { methods: {
@ -60,8 +63,8 @@ const SettingsModalContent = {
const targetTab = this.$store.state.interface.settingsModalTargetTab const targetTab = this.$store.state.interface.settingsModalTargetTab
// We're being told to open in specific tab // We're being told to open in specific tab
if (targetTab) { if (targetTab) {
const tabIndex = this.$refs.tabSwitcher.$slots.default.findIndex(elm => { const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => {
return elm.data && elm.data.attrs['data-tab-name'] === targetTab return elm.props && elm.props['data-tab-name'] === targetTab
}) })
if (tabIndex >= 0) { if (tabIndex >= 0) {
this.$refs.tabSwitcher.setTab(tabIndex) this.$refs.tabSwitcher.setTab(tabIndex)

View file

@ -4,6 +4,7 @@
class="settings_tab-switcher" class="settings_tab-switcher"
:side-tab-bar="true" :side-tab-bar="true"
:scrollable-tabs="true" :scrollable-tabs="true"
:body-scroll-lock="bodyLock"
> >
<div <div
:label="$t('settings.general')" :label="$t('settings.general')"

View file

@ -72,22 +72,10 @@
<div>{{ $t('settings.filtering_explanation') }}</div> <div>{{ $t('settings.filtering_explanation') }}</div>
</li> </li>
<h3>{{ $t('settings.attachments') }}</h3> <h3>{{ $t('settings.attachments') }}</h3>
<li v-if="expertLevel > 0">
<label for="maxThumbnails">
{{ $t('settings.max_thumbnails') }}
</label>
<input
id="maxThumbnails"
path.number="maxThumbnails"
class="number-input"
type="number"
min="0"
step="1"
>
</li>
<li> <li>
<IntegerSetting <IntegerSetting
path="maxThumbnails" path="maxThumbnails"
expert="1"
:min="0" :min="0"
> >
{{ $t('settings.max_thumbnails') }} {{ $t('settings.max_thumbnails') }}

View file

@ -2,7 +2,7 @@ import get from 'lodash/get'
import map from 'lodash/map' import map from 'lodash/map'
import reject from 'lodash/reject' import reject from 'lodash/reject'
import Autosuggest from 'src/components/autosuggest/autosuggest.vue' import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import BlockCard from 'src/components/block_card/block_card.vue' import BlockCard from 'src/components/block_card/block_card.vue'
import MuteCard from 'src/components/mute_card/mute_card.vue' import MuteCard from 'src/components/mute_card/mute_card.vue'
import DomainMuteCard from 'src/components/domain_mute_card/domain_mute_card.vue' import DomainMuteCard from 'src/components/domain_mute_card/domain_mute_card.vue'

View file

@ -54,16 +54,20 @@
border-radius: var(--tooltipRadius, $fallback--tooltipRadius); border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
background-color: rgba(0, 0, 0, 0.6); background-color: rgba(0, 0, 0, 0.6);
opacity: 0.7; opacity: 0.7;
color: white;
width: 1.5em; width: 1.5em;
height: 1.5em; height: 1.5em;
text-align: center; text-align: center;
line-height: 1.5em; line-height: 1.5em;
font-size: 1.5em; font-size: 1.5em;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
opacity: 1; opacity: 1;
} }
svg {
color: white;
}
} }
.oauth-tokens { .oauth-tokens {

View file

@ -68,8 +68,9 @@
class="delete-field button-unstyled -hover-highlight" class="delete-field button-unstyled -hover-highlight"
@click="deleteField(i)" @click="deleteField(i)"
> >
<!-- TODO something is wrong with v-show here -->
<FAIcon <FAIcon
v-show="newFields.length > 1" v-if="newFields.length > 1"
icon="times" icon="times"
/> />
</button> </button>
@ -106,14 +107,17 @@
:src="user.profile_image_url_original" :src="user.profile_image_url_original"
class="current-avatar" class="current-avatar"
> >
<FAIcon <button
v-if="!isDefaultAvatar && pickAvatarBtnVisible" v-if="!isDefaultAvatar && pickAvatarBtnVisible"
:title="$t('settings.reset_avatar')" :title="$t('settings.reset_avatar')"
class="reset-button"
icon="times"
type="button"
@click="resetAvatar" @click="resetAvatar"
/> class="button-unstyled reset-button"
>
<FAIcon
icon="times"
type="button"
/>
</button>
</div> </div>
<p>{{ $t('settings.set_new_avatar') }}</p> <p>{{ $t('settings.set_new_avatar') }}</p>
<button <button
@ -135,14 +139,17 @@
<h2>{{ $t('settings.profile_banner') }}</h2> <h2>{{ $t('settings.profile_banner') }}</h2>
<div class="banner-background-preview"> <div class="banner-background-preview">
<img :src="user.cover_photo"> <img :src="user.cover_photo">
<FAIcon <button
v-if="!isDefaultBanner" v-if="!isDefaultBanner"
class="button-unstyled reset-button"
:title="$t('settings.reset_profile_banner')" :title="$t('settings.reset_profile_banner')"
class="reset-button"
icon="times"
type="button"
@click="resetBanner" @click="resetBanner"
/> >
<FAIcon
icon="times"
type="button"
/>
</button>
</div> </div>
<p>{{ $t('settings.set_new_profile_banner') }}</p> <p>{{ $t('settings.set_new_profile_banner') }}</p>
<img <img
@ -174,14 +181,17 @@
<h2>{{ $t('settings.profile_background') }}</h2> <h2>{{ $t('settings.profile_background') }}</h2>
<div class="banner-background-preview"> <div class="banner-background-preview">
<img :src="user.background_image"> <img :src="user.background_image">
<FAIcon <button
v-if="!isDefaultBackground" v-if="!isDefaultBackground"
class="button-unstyled reset-button"
:title="$t('settings.reset_profile_background')" :title="$t('settings.reset_profile_background')"
class="reset-button"
icon="times"
type="button"
@click="resetBackground" @click="resetBackground"
/> >
<FAIcon
icon="times"
type="button"
/>
</button>
</div> </div>
<p>{{ $t('settings.set_new_profile_background') }}</p> <p>{{ $t('settings.set_new_profile_background') }}</p>
<img <img

View file

@ -29,14 +29,14 @@
{{ $t('settings.style.preview.content') }} {{ $t('settings.style.preview.content') }}
</h4> </h4>
<i18n path="settings.style.preview.text"> <i18n-t scope="global" keypath="settings.style.preview.text">
<code style="font-family: var(--postCodeFont)"> <code style="font-family: var(--postCodeFont)">
{{ $t('settings.style.preview.mono') }} {{ $t('settings.style.preview.mono') }}
</code> </code>
<a style="color: var(--link)"> <a style="color: var(--link)">
{{ $t('settings.style.preview.link') }} {{ $t('settings.style.preview.link') }}
</a> </a>
</i18n> </i18n-t>
<div class="icons"> <div class="icons">
<FAIcon <FAIcon
@ -72,15 +72,16 @@
:^) :^)
</div> </div>
<div class="content"> <div class="content">
<i18n <i18n-t
path="settings.style.preview.fine_print" keypath="settings.style.preview.fine_print"
tag="span" tag="span"
class="faint" class="faint"
scope="global"
> >
<a style="color: var(--faintLink)"> <a style="color: var(--faintLink)">
{{ $t('settings.style.preview.faint_link') }} {{ $t('settings.style.preview.faint_link') }}
</a> </a>
</i18n> </i18n-t>
</div> </div>
</div> </div>
<div class="separator" /> <div class="separator" />

View file

@ -1,4 +1,3 @@
import { set, delete as del } from 'vue'
import { import {
rgb2hex, rgb2hex,
hex2rgb, hex2rgb,
@ -34,7 +33,7 @@ import OpacityInput from 'src/components/opacity_input/opacity_input.vue'
import ShadowControl from 'src/components/shadow_control/shadow_control.vue' import ShadowControl from 'src/components/shadow_control/shadow_control.vue'
import FontControl from 'src/components/font_control/font_control.vue' import FontControl from 'src/components/font_control/font_control.vue'
import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue' import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js' import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import Select from 'src/components/select/select.vue' import Select from 'src/components/select/select.vue'
@ -320,9 +319,9 @@ export default {
}, },
set (val) { set (val) {
if (val) { if (val) {
set(this.shadowsLocal, this.shadowSelected, this.currentShadowFallback.map(_ => Object.assign({}, _))) this.shadowsLocal[this.shadowSelected] = this.currentShadowFallback.map(_ => Object.assign({}, _))
} else { } else {
del(this.shadowsLocal, this.shadowSelected) delete this.shadowsLocal[this.shadowSelected]
} }
} }
}, },
@ -334,7 +333,7 @@ export default {
return this.shadowsLocal[this.shadowSelected] return this.shadowsLocal[this.shadowSelected]
}, },
set (v) { set (v) {
set(this.shadowsLocal, this.shadowSelected, v) this.shadowsLocal[this.shadowSelected] = v
} }
}, },
themeValid () { themeValid () {
@ -378,6 +377,10 @@ export default {
// To separate from other random JSON files and possible future source formats // To separate from other random JSON files and possible future source formats
_pleroma_theme_version: 2, theme, source _pleroma_theme_version: 2, theme, source
} }
},
isActive () {
const tabSwitcher = this.$parent
return tabSwitcher ? tabSwitcher.isActive('theme') : false
} }
}, },
components: { components: {
@ -557,7 +560,7 @@ export default {
.filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal')) .filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal'))
.filter(_ => !v1OnlyNames.includes(_)) .filter(_ => !v1OnlyNames.includes(_))
.forEach(key => { .forEach(key => {
set(this.$data, key, undefined) this.$data[key] = undefined
}) })
}, },
@ -565,7 +568,7 @@ export default {
Object.keys(this.$data) Object.keys(this.$data)
.filter(_ => _.endsWith('RadiusLocal')) .filter(_ => _.endsWith('RadiusLocal'))
.forEach(key => { .forEach(key => {
set(this.$data, key, undefined) this.$data[key] = undefined
}) })
}, },
@ -573,7 +576,7 @@ export default {
Object.keys(this.$data) Object.keys(this.$data)
.filter(_ => _.endsWith('OpacityLocal')) .filter(_ => _.endsWith('OpacityLocal'))
.forEach(key => { .forEach(key => {
set(this.$data, key, undefined) this.$data[key] = undefined
}) })
}, },

View file

@ -268,13 +268,6 @@
} }
} }
.apply-container {
justify-content: center;
position: absolute;
bottom: 8px;
right: 5px;
}
.radius-item, .radius-item,
.color-item { .color-item {
min-width: 20em; min-width: 20em;
@ -334,16 +327,25 @@
padding: 20px; padding: 20px;
} }
.apply-container {
.btn {
min-height: 28px;
min-width: 10em;
padding: 0 2em;
}
}
.btn { .btn {
margin-left: .25em; margin-left: .25em;
margin-right: .25em; margin-right: .25em;
} }
} }
.extra-content {
.apply-container {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-grow: 1;
.btn {
flex-grow: 1;
min-height: 28px;
min-width: 0;
max-width: 10em;
padding: 0;
}
}
}

View file

@ -903,6 +903,7 @@
<div class="tab-header shadow-selector"> <div class="tab-header shadow-selector">
<div class="select-container"> <div class="select-container">
{{ $t('settings.style.shadows.component') }} {{ $t('settings.style.shadows.component') }}
{{ ' ' }}
<Select <Select
id="shadow-switcher" id="shadow-switcher"
v-model="shadowSelected" v-model="shadowSelected"
@ -924,6 +925,7 @@
> >
{{ $t('settings.style.shadows.override') }} {{ $t('settings.style.shadows.override') }}
</label> </label>
{{ ' ' }}
<input <input
id="override" id="override"
v-model="currentShadowOverriden" v-model="currentShadowOverriden"
@ -949,27 +951,30 @@
:fallback="currentShadowFallback" :fallback="currentShadowFallback"
/> />
<div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'"> <div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'">
<i18n <i18n-t
path="settings.style.shadows.filter_hint.always_drop_shadow" scope="global"
keypath="settings.style.shadows.filter_hint.always_drop_shadow"
tag="p" tag="p"
> >
<code>filter: drop-shadow()</code> <code>filter: drop-shadow()</code>
</i18n> </i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p> <p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p>
<i18n <i18n-t
path="settings.style.shadows.filter_hint.drop_shadow_syntax" scope="global"
keypath="settings.style.shadows.filter_hint.drop_shadow_syntax"
tag="p" tag="p"
> >
<code>drop-shadow</code> <code>drop-shadow</code>
<code>spread-radius</code> <code>spread-radius</code>
<code>inset</code> <code>inset</code>
</i18n> </i18n-t>
<i18n <i18n-t
path="settings.style.shadows.filter_hint.inset_classic" scope="global"
keypath="settings.style.shadows.filter_hint.inset_classic"
tag="p" tag="p"
> >
<code>box-shadow</code> <code>box-shadow</code>
</i18n> </i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p> <p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p>
</div> </div>
</div> </div>
@ -1016,21 +1021,26 @@
</tab-switcher> </tab-switcher>
</keep-alive> </keep-alive>
<div class="apply-container"> <teleport
<button v-if="isActive"
class="btn button-default submit" to="#unscrolled-content"
:disabled="!themeValid" >
@click="setCustomTheme" <div class="apply-container">
> <button
{{ $t('general.apply') }} class="btn button-default submit"
</button> :disabled="!themeValid"
<button @click="setCustomTheme"
class="btn button-default" >
@click="clearAll" {{ $t('general.apply') }}
> </button>
{{ $t('settings.style.switcher.reset') }} <button
</button> class="btn button-default"
</div> @click="clearAll"
>
{{ $t('settings.style.switcher.reset') }}
</button>
</div>
</teleport>
</div> </div>
</template> </template>

View file

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

View file

@ -30,18 +30,19 @@ const toModel = (object = {}) => ({
}) })
export default { export default {
// 'Value' and 'Fallback' can be undefined, but if they are // 'modelValue' and 'Fallback' can be undefined, but if they are
// initially vue won't detect it when they become something else // initially vue won't detect it when they become something else
// therefore i'm using "ready" which should be passed as true when // therefore i'm using "ready" which should be passed as true when
// data becomes available // data becomes available
props: [ props: [
'value', 'fallback', 'ready' 'modelValue', 'fallback', 'ready'
], ],
emits: ['update:modelValue'],
data () { data () {
return { return {
selectedId: 0, selectedId: 0,
// TODO there are some bugs regarding display of array (it's not getting updated when deleting for some reason) // TODO there are some bugs regarding display of array (it's not getting updated when deleting for some reason)
cValue: (this.value || this.fallback || []).map(toModel) cValue: (this.modelValue || this.fallback || []).map(toModel)
} }
}, },
components: { components: {
@ -70,7 +71,7 @@ export default {
} }
}, },
beforeUpdate () { beforeUpdate () {
this.cValue = this.value || this.fallback this.cValue = this.modelValue || this.fallback
}, },
computed: { computed: {
anyShadows () { anyShadows () {
@ -105,7 +106,7 @@ export default {
!this.usingFallback !this.usingFallback
}, },
usingFallback () { usingFallback () {
return typeof this.value === 'undefined' return typeof this.modelValue === 'undefined'
}, },
rgb () { rgb () {
return hex2rgb(this.selected.color) return hex2rgb(this.selected.color)

View file

@ -204,12 +204,13 @@
v-model="selected.alpha" v-model="selected.alpha"
:disabled="!present" :disabled="!present"
/> />
<i18n <i18n-t
path="settings.style.shadows.hintV3" scope="global"
keypath="settings.style.shadows.hintV3"
tag="p" tag="p"
> >
<code>--variable,mod</code> <code>--variable,mod</code>
</i18n> </i18n-t>
</div> </div>
</div> </div>
</template> </template>

View file

@ -98,7 +98,7 @@
.icon { .icon {
color: $fallback--text; color: $fallback--text;
color: var(--text, $fallback--text); color: var(--panelText, $fallback--text);
margin-right: 0.5em; margin-right: 0.5em;
} }

View file

@ -49,7 +49,7 @@ const SideDrawer = {
currentUser () { currentUser () {
return this.$store.state.users.currentUser return this.$store.state.users.currentUser
}, },
shout () { return this.$store.state.shout.channel.state === 'joined' }, shout () { return this.$store.state.shout.joined },
unseenNotifications () { unseenNotifications () {
return unseenNotificationsFromStore(this.$store) return unseenNotificationsFromStore(this.$store)
}, },

View file

@ -69,7 +69,7 @@ const controlledOrUncontrolledGetters = list => list.reduce((res, name) => {
const controlledName = `controlled${camelized}` const controlledName = `controlled${camelized}`
const uncontrolledName = `uncontrolled${camelized}` const uncontrolledName = `uncontrolled${camelized}`
res[name] = function () { res[name] = function () {
return this[toggle] ? this[controlledName] : this[uncontrolledName] return ((this.$data[toggle] !== undefined || this.$props[toggle] !== undefined) && this[toggle]) ? this[controlledName] : this[uncontrolledName]
} }
return res return res
}, {}) }, {})
@ -225,12 +225,18 @@ const Status = {
muteWordHits () { muteWordHits () {
return muteWordHits(this.status, this.muteWords) return muteWordHits(this.status, this.muteWords)
}, },
rtBotStatus () {
return this.statusoid.user.bot
},
botStatus () { botStatus () {
return this.status.user.bot return this.status.user.bot
}, },
botIndicator () { botIndicator () {
return this.botStatus && !this.hideBotIndication return this.botStatus && !this.hideBotIndication
}, },
rtBotIndicator () {
return this.rtBotStatus && !this.hideBotIndication
},
mentionsLine () { mentionsLine () {
if (!this.headTailLinks) return [] if (!this.headTailLinks) return []
const writtenSet = new Set(this.headTailLinks.writtenMentions.map(_ => _.url)) const writtenSet = new Set(this.headTailLinks.writtenMentions.map(_ => _.url))
@ -305,7 +311,7 @@ const Status = {
return this.mergedConfig.hideWordFilteredPosts return this.mergedConfig.hideWordFilteredPosts
}, },
hideStatus () { hideStatus () {
return (this.virtualHidden || !this.shouldNotMute) && ( return (!this.shouldNotMute) && (
(this.muted && this.hideFilteredStatuses) || (this.muted && this.hideFilteredStatuses) ||
(this.userIsMuted && this.hideMutedUsers) || (this.userIsMuted && this.hideMutedUsers) ||
(this.status.thread_muted && this.hideMutedThreads) || (this.status.thread_muted && this.hideMutedThreads) ||
@ -383,6 +389,9 @@ const Status = {
}, },
threadShowing () { threadShowing () {
return this.controlledThreadDisplayStatus === 'showing' return this.controlledThreadDisplayStatus === 'showing'
},
visibilityLocalized () {
return this.$i18n.t('general.scope_in_timeline.' + this.status.visibility)
} }
}, },
methods: { methods: {
@ -472,11 +481,6 @@ const Status = {
'isSuspendable': function (val) { 'isSuspendable': function (val) {
this.suspendable = val this.suspendable = val
} }
},
filters: {
capitalize: function (str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
} }
} }

View file

@ -406,13 +406,13 @@
margin-left: 20px; margin-left: 20px;
} }
.avatar:not(.repeater-avatar) { .post-avatar {
width: 40px; width: 40px;
height: 40px; height: 40px;
// TODO define those other way somehow? // TODO define those other way somehow?
// stylelint-disable rscss/class-format // stylelint-disable rscss/class-format
&.avatar-compact { &.-compact {
width: 32px; width: 32px;
height: 32px; height: 32px;
} }

View file

@ -1,6 +1,7 @@
<template> <template>
<div <div
v-if="!hideStatus" v-if="!hideStatus"
ref="root"
class="Status" class="Status"
:class="[{ '-focused': isFocused }, { '-conversation': inlineExpanded }]" :class="[{ '-focused': isFocused }, { '-conversation': inlineExpanded }]"
> >
@ -77,7 +78,7 @@
<UserAvatar <UserAvatar
v-if="retweet" v-if="retweet"
class="left-side repeater-avatar" class="left-side repeater-avatar"
:bot="botIndicator" :bot="rtBotIndicator"
:better-shadow="betterShadow" :better-shadow="betterShadow"
:user="statusoid.user" :user="statusoid.user"
/> />
@ -100,6 +101,7 @@
:to="retweeterProfileLink" :to="retweeterProfileLink"
>{{ retweeter }}</router-link> >{{ retweeter }}</router-link>
</span> </span>
{{ ' ' }}
<FAIcon <FAIcon
icon="retweet" icon="retweet"
class="repeat-icon" class="repeat-icon"
@ -120,17 +122,18 @@
v-if="!noHeading" v-if="!noHeading"
class="left-side" class="left-side"
> >
<router-link <a
:to="userProfileLink" :href="$router.resolve(userProfileLink).href"
@click.stop.prevent.capture.native="toggleUserExpanded" @click.stop.prevent.capture="toggleUserExpanded"
> >
<UserAvatar <UserAvatar
class="post-avatar"
:bot="botIndicator" :bot="botIndicator"
:compact="compact" :compact="compact"
:better-shadow="betterShadow" :better-shadow="betterShadow"
:user="status.user" :user="status.user"
/> />
</router-link> </a>
</div> </div>
<div class="right-side"> <div class="right-side">
<UserCard <UserCard
@ -190,7 +193,7 @@
<span <span
v-if="status.visibility" v-if="status.visibility"
class="visibility-icon" class="visibility-icon"
:title="status.visibility | capitalize" :title="visibilityLocalized"
> >
<FAIcon <FAIcon
fixed-width fixed-width
@ -273,6 +276,7 @@
icon="reply" icon="reply"
flip="horizontal" flip="horizontal"
/> />
{{ ' ' }}
<span <span
class="reply-to-text" class="reply-to-text"
> >
@ -292,7 +296,6 @@
:url="replyProfileLink" :url="replyProfileLink"
:user-id="status.in_reply_to_user_id" :user-id="status.in_reply_to_user_id"
:user-screen-name="status.in_reply_to_screen_name" :user-screen-name="status.in_reply_to_screen_name"
:first-mention="false"
/> />
</span> </span>
@ -454,6 +457,7 @@
> >
<div class="left-side"> <div class="left-side">
<UserAvatar <UserAvatar
class="post-avatar"
:compact="compact" :compact="compact"
:bot="botIndicator" :bot="botIndicator"
/> />

View file

@ -15,14 +15,14 @@
:emoji="status.emojis" :emoji="status.emojis"
/> />
<button <button
v-if="longSubject && showingLongSubject" v-show="longSubject && showingLongSubject"
class="button-unstyled -link tall-subject-hider" class="button-unstyled -link tall-subject-hider"
@click.prevent="toggleShowingLongSubject" @click.prevent="toggleShowingLongSubject"
> >
{{ $t("status.hide_full_subject") }} {{ $t("status.hide_full_subject") }}
</button> </button>
<button <button
v-else-if="longSubject" v-show="longSubject && !showingLongSubject"
class="button-unstyled -link tall-subject-hider" class="button-unstyled -link tall-subject-hider"
@click.prevent="toggleShowingLongSubject" @click.prevent="toggleShowingLongSubject"
> >
@ -34,7 +34,7 @@
class="text-wrapper" class="text-wrapper"
> >
<button <button
v-if="hideTallStatus" v-show="hideTallStatus"
class="button-unstyled -link tall-status-hider" class="button-unstyled -link tall-status-hider"
:class="{ '-focused': focused }" :class="{ '-focused': focused }"
@click.prevent="toggleShowMore" @click.prevent="toggleShowMore"
@ -54,7 +54,7 @@
/> />
<button <button
v-if="hideSubjectStatus" v-show="hideSubjectStatus"
class="button-unstyled -link cw-status-hider" class="button-unstyled -link cw-status-hider"
@click.prevent="toggleShowMore" @click.prevent="toggleShowMore"
> >
@ -85,7 +85,7 @@
/> />
</button> </button>
<button <button
v-if="showingMore && !fullContent" v-show="showingMore && !fullContent"
class="button-unstyled -link status-unhider" class="button-unstyled -link status-unhider"
@click.prevent="toggleShowMore" @click.prevent="toggleShowMore"
> >

View file

@ -31,7 +31,7 @@ const controlledOrUncontrolledGetters = list => list.reduce((res, name) => {
const controlledName = `controlled${camelized}` const controlledName = `controlled${camelized}`
const uncontrolledName = `uncontrolled${camelized}` const uncontrolledName = `uncontrolled${camelized}`
res[name] = function () { res[name] = function () {
return this[toggle] ? this[controlledName] : this[uncontrolledName] return ((this.$data[toggle] !== undefined || this.$props[toggle] !== undefined) && this[toggle]) ? this[controlledName] : this[uncontrolledName]
} }
return res return res
}, {}) }, {})
@ -59,7 +59,9 @@ const StatusContent = {
'controlledShowingTall', 'controlledShowingTall',
'controlledExpandingSubject', 'controlledExpandingSubject',
'controlledToggleShowingTall', 'controlledToggleShowingTall',
'controlledToggleExpandingSubject' 'controlledToggleExpandingSubject',
'controlledShowingLongSubject',
'controlledToggleShowingLongSubject'
], ],
data () { data () {
return { return {

View file

@ -1,6 +1,7 @@
import { find } from 'lodash' import { find } from 'lodash'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faCircleNotch } from '@fortawesome/free-solid-svg-icons' import { faCircleNotch } from '@fortawesome/free-solid-svg-icons'
import { defineAsyncComponent } from 'vue'
library.add( library.add(
faCircleNotch faCircleNotch
@ -22,8 +23,8 @@ const StatusPopover = {
} }
}, },
components: { components: {
Status: () => import('../status/status.vue'), Status: defineAsyncComponent(() => import('../status/status.vue')),
Popover: () => import('../popover/popover.vue') Popover: defineAsyncComponent(() => import('../popover/popover.vue'))
}, },
methods: { methods: {
enter () { enter () {

View file

@ -1,6 +1,6 @@
/* eslint-env browser */ /* eslint-env browser */
import statusPosterService from '../../services/status_poster/status_poster.service.js' import statusPosterService from '../../services/status_poster/status_poster.service.js'
import TabSwitcher from '../tab_switcher/tab_switcher.js' import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
const StickerPicker = { const StickerPicker = {
components: { components: {

View file

@ -1,10 +1,13 @@
import Vue from 'vue' // eslint-disable-next-line no-unused
import { h, Fragment } from 'vue'
import { mapState } from 'vuex' import { mapState } from 'vuex'
import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome' import { FontAwesomeIcon as FAIcon } from '@fortawesome/vue-fontawesome'
import './tab_switcher.scss' import './tab_switcher.scss'
export default Vue.component('tab-switcher', { const findFirstUsable = (slots) => slots.findIndex(_ => _.props)
export default {
name: 'TabSwitcher', name: 'TabSwitcher',
props: { props: {
renderOnlyFocused: { renderOnlyFocused: {
@ -31,22 +34,33 @@ export default Vue.component('tab-switcher', {
required: false, required: false,
type: Boolean, type: Boolean,
default: false default: false
},
bodyScrollLock: {
required: false,
type: Boolean,
default: false
} }
}, },
data () { data () {
return { return {
active: this.$slots.default.findIndex(_ => _.tag) active: findFirstUsable(this.slots())
} }
}, },
computed: { computed: {
activeIndex () { activeIndex () {
// In case of controlled component // In case of controlled component
if (this.activeTab) { if (this.activeTab) {
return this.$slots.default.findIndex(slot => this.activeTab === slot.key) return this.slots().findIndex(slot => slot && slot.props && this.activeTab === slot.props.key)
} else { } else {
return this.active return this.active
} }
}, },
isActive () {
return tabName => {
const isWanted = slot => slot.props && slot.props['data-tab-name'] === tabName
return this.$slots.default().findIndex(isWanted) === this.activeIndex
}
},
settingsModalVisible () { settingsModalVisible () {
return this.settingsModalState === 'visible' return this.settingsModalState === 'visible'
}, },
@ -55,9 +69,9 @@ export default Vue.component('tab-switcher', {
}) })
}, },
beforeUpdate () { beforeUpdate () {
const currentSlot = this.$slots.default[this.active] const currentSlot = this.slots()[this.active]
if (!currentSlot.tag) { if (!currentSlot.props) {
this.active = this.$slots.default.findIndex(_ => _.tag) this.active = findFirstUsable(this.slots())
} }
}, },
methods: { methods: {
@ -67,9 +81,16 @@ export default Vue.component('tab-switcher', {
this.setTab(index) this.setTab(index)
} }
}, },
// DO NOT put it to computed, it doesn't work (caching?)
slots () {
if (this.$slots.default()[0].type === Fragment) {
return this.$slots.default()[0].children
}
return this.$slots.default()
},
setTab (index) { setTab (index) {
if (typeof this.onSwitch === 'function') { if (typeof this.onSwitch === 'function') {
this.onSwitch.call(null, this.$slots.default[index].key) this.onSwitch.call(null, this.slots()[index].key)
} }
this.active = index this.active = index
if (this.scrollableTabs) { if (this.scrollableTabs) {
@ -77,27 +98,28 @@ export default Vue.component('tab-switcher', {
} }
} }
}, },
render (h) { render () {
const tabs = this.$slots.default const tabs = this.slots()
.map((slot, index) => { .map((slot, index) => {
if (!slot.tag) return const props = slot.props
if (!props) return
const classesTab = ['tab', 'button-default'] const classesTab = ['tab', 'button-default']
const classesWrapper = ['tab-wrapper'] const classesWrapper = ['tab-wrapper']
if (this.activeIndex === index) { if (this.activeIndex === index) {
classesTab.push('active') classesTab.push('active')
classesWrapper.push('active') classesWrapper.push('active')
} }
if (slot.data.attrs.image) { if (props.image) {
return ( return (
<div class={classesWrapper.join(' ')}> <div class={classesWrapper.join(' ')}>
<button <button
disabled={slot.data.attrs.disabled} disabled={props.disabled}
onClick={this.clickTab(index)} onClick={this.clickTab(index)}
class={classesTab.join(' ')} class={classesTab.join(' ')}
type="button" type="button"
> >
<img src={slot.data.attrs.image} title={slot.data.attrs['image-tooltip']}/> <img src={props.image} title={props['image-tooltip']}/>
{slot.data.attrs.label ? '' : slot.data.attrs.label} {props.label ? '' : props.label}
</button> </button>
</div> </div>
) )
@ -105,25 +127,26 @@ export default Vue.component('tab-switcher', {
return ( return (
<div class={classesWrapper.join(' ')}> <div class={classesWrapper.join(' ')}>
<button <button
disabled={slot.data.attrs.disabled} disabled={props.disabled}
onClick={this.clickTab(index)} onClick={this.clickTab(index)}
class={classesTab.join(' ')} class={classesTab.join(' ')}
type="button" type="button"
> >
{!slot.data.attrs.icon ? '' : (<FAIcon class="tab-icon" size="2x" fixed-width icon={slot.data.attrs.icon}/>)} {!props.icon ? '' : (<FAIcon class="tab-icon" size="2x" fixed-width icon={props.icon}/>)}
<span class="text"> <span class="text">
{slot.data.attrs.label} {props.label}
</span> </span>
</button> </button>
</div> </div>
) )
}) })
const contents = this.$slots.default.map((slot, index) => { const contents = this.slots().map((slot, index) => {
if (!slot.tag) return const props = slot.props
if (!props) return
const active = this.activeIndex === index const active = this.activeIndex === index
const classes = [ active ? 'active' : 'hidden' ] const classes = [ active ? 'active' : 'hidden' ]
if (slot.data.attrs.fullHeight) { if (props.fullHeight) {
classes.push('full-height') classes.push('full-height')
} }
const renderSlot = (!this.renderOnlyFocused || active) const renderSlot = (!this.renderOnlyFocused || active)
@ -134,7 +157,7 @@ export default Vue.component('tab-switcher', {
<div class={classes}> <div class={classes}>
{ {
this.sideTabBar this.sideTabBar
? <h1 class="mobile-label">{slot.data.attrs.label}</h1> ? <h1 class="mobile-label">{props.label}</h1>
: '' : ''
} }
{renderSlot} {renderSlot}
@ -147,10 +170,14 @@ export default Vue.component('tab-switcher', {
<div class="tabs"> <div class="tabs">
{tabs} {tabs}
</div> </div>
<div ref="contents" class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')} v-body-scroll-lock={this.settingsModalVisible}> <div
ref="contents"
class={'contents' + (this.scrollableTabs ? ' scrollable-tabs' : '')}
v-body-scroll-lock={this.bodyScrollLock}
>
{contents} {contents}
</div> </div>
</div> </div>
) )
} }
}) }

View file

@ -166,13 +166,6 @@
position: relative; position: relative;
white-space: nowrap; white-space: nowrap;
padding: 6px 1em; padding: 6px 1em;
background-color: $fallback--fg;
background-color: var(--tab, $fallback--fg);
&, &:active .tab-icon {
color: $fallback--text;
color: var(--tabText, $fallback--text);
}
&:not(.active) { &:not(.active) {
z-index: 4; z-index: 4;

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