Compare commits

...

1656 commits

Author SHA1 Message Date
b217b4dc25
Merge branch 'pull-v0.13.2'
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-04-07 14:35:26 +02:00
f2edec194f
feat(config): switch default instance
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
set fedi.femby.page as default instance
2024-04-07 14:31:19 +02:00
087f8cc992
fix(ci): add missing docker pushes 2024-04-07 14:29:15 +02:00
6efbf8768b
fix(ci): add secrets 2024-04-07 14:29:15 +02:00
cd934fcd55
fix(ci): docker login 2024-04-07 14:29:15 +02:00
7f1e97a37c
fix(ci): remove docker login 2024-04-07 14:29:15 +02:00
58c84b2f9b
fix(ci): add docker login 2024-04-07 14:29:14 +02:00
322ffeef12
feat(ci): add docker push test 2024-04-07 14:29:14 +02:00
4a8110a52e
fix(ci): add missing flags docker buildx 2024-04-07 14:29:14 +02:00
d481c0ae7a
fix(ci): added missing flag for cut 2024-04-07 14:29:14 +02:00
68ffb627e7
fix(ci): deleted sh uncompatible line 2024-04-07 14:29:14 +02:00
b221687139
feat(ci): Made ci sh compatible (hopefully^^) 2024-04-07 14:29:14 +02:00
7b10620cca
feat(ci): Add build tags 2024-04-07 14:29:13 +02:00
498face3cf
test(ci): 2024-04-07 14:29:13 +02:00
672ff46072
test(ci): add git to image 2024-04-07 14:29:13 +02:00
81b5f8b8e7
test(ci): another syntax test 2024-04-07 14:29:13 +02:00
721e55be06
test(ci): another syntax test 2024-04-07 14:29:13 +02:00
eba4cc0757
test(ci): another syntax test 2024-04-07 14:29:13 +02:00
80818ed52d
test(ci): syntax test 2024-04-07 14:28:32 +02:00
patak-dev
25fb7c1c97 chore: release v0.13.2 2024-04-05 18:29:15 +02:00
TAKAHASHI Shuuji
839aa52e86
fix: adjust background spacing in direct message (#2764) 2024-04-05 16:23:52 +00:00
TAKAHASHI Shuuji
9ff55289ea
ci(ci.yml): limit maximum execution time of ci test (#2763) 2024-04-05 16:19:53 +00:00
Joaquín Sánchez
73293fbcd3
chore: update nuxt to 3.11.2 (#2755) 2024-04-05 14:34:42 +00:00
TAKAHASHI Shuuji
a27c218802
chore: update github avatar images (#2762) 2024-04-05 14:34:19 +00:00
Emanuel Pina
f8fc0efadc
feat(i18n): Update portuguese from Portugal translation (#2756) 2024-04-05 09:16:30 +00:00
Joaquín Sánchez
618a5b2df3
chore(ui): use full width in settings toggle items (#2754) 2024-04-05 09:16:11 +00:00
lazzzis
1146dca5f6
fix(ui): media preview card is misaligned (#2751) 2024-04-05 09:15:44 +00:00
Joaquín Sánchez
f86e856ee6
feat(i18n): add missing spanish translations (gifs, docs and contributing) (#2753) 2024-04-04 18:36:03 +00:00
renovate[bot]
6d13d61227
chore(deps): update devdependencies (#2725)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: TAKAHASHI Shuuji <shuuji3@gmail.com>
2024-04-04 16:47:27 +00:00
Francesco
0de9825bf2
feat(i18n): Update it-IT locale (#2750) 2024-04-04 13:25:09 +00:00
Joaquín Sánchez
3f0b234cc4
feat(ui): add max. file size check before upload attachment (#2709)
Co-authored-by: TAKAHASHI Shuuji <shuuji3@gmail.com>
2024-04-04 10:28:18 +00:00
lazzzis
8f04ea8eee
feat(ui): improve gif support (#2752) 2024-04-04 10:27:52 +00:00
Emanuel Pina
7dcafa3fe0
feat(i18n): Update portuguese from Portugal translation (#2747) 2024-04-04 05:17:03 +00:00
Joaquín Sánchez
bead2183b2
fix(ui): don't scroll on settings item click when external or _blank target link (#2742) 2024-04-03 13:59:42 +00:00
patak
59dda09cd4
fix: notifications in update timeline (#2740) 2024-04-03 13:59:24 +00:00
lazzzis
d0b115751f
feat(ui): style blockquote (#2744) 2024-04-03 04:17:52 +00:00
lazzzis
c6787aae3f
fix(ui): clicking on custom emoji does not navigate to status detail (#2743) 2024-04-03 04:17:30 +00:00
patak
9025416ab3
feat: update info dialog (#2741) 2024-04-02 03:17:45 +00:00
TAKAHASHI Shuuji
aa28257754
feat: add "Documentation" link to "About" page (#2734) 2024-04-01 14:57:11 +00:00
TAKAHASHI Shuuji
d807e06fa0
refactor: various typo fixes (#2735) 2024-04-01 14:56:30 +00:00
TAKAHASHI Shuuji
611d556936
feat: put sign-in icon to default "Sign in" button (#2736) 2024-04-01 14:55:31 +00:00
Xabi
4313002950
feat(i18n): update eu-ES.json (#2737) 2024-04-01 14:54:37 +00:00
TAKAHASHI Shuuji
de11a60b17
feat: add "How to contribute?" link next to language status (#2733) 2024-04-01 05:27:47 +00:00
TAKAHASHI Shuuji
5064b269e7
feat: show background color for direct post to reduce mistake (#2732) 2024-04-01 05:26:51 +00:00
TAKAHASHI Shuuji
d8d9975756
fix: hide duplicated status actions items on details page in zen mode (#2731) 2024-04-01 05:25:53 +00:00
TAKAHASHI Shuuji
eee671cdc3
fix: improve keyboard operability especially on search page and editor (#2730)
Co-authored-by: patak <583075+patak-dev@users.noreply.github.com>
2024-04-01 05:24:42 +00:00
lazzzis
587c063aba
fix(ui): remove a duplicated command (#2718) 2024-03-30 04:19:22 +00:00
lazzzis
28514e956d
fix(ui): wrong polls are removed (#2720) 2024-03-30 04:18:33 +00:00
lazzzis
42aeb8fa35
fix(ui): prevent from navigating to search page when opening command panel (#2719) 2024-03-30 04:15:58 +00:00
Joaquín Sánchez
f6f50a582e
fix(ui): change status actions title (#2717) 2024-03-29 20:04:55 +00:00
patak-dev
f86818867b chore: release v0.13.1 2024-03-29 16:37:28 +01:00
Sma11X
82d962a54b
fix: add missing notification event type (#2714) 2024-03-29 15:31:53 +00:00
renovate[bot]
1b189043e4
chore(deps): update devdependencies (major) (#2400)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-26 08:51:07 +00:00
renovate[bot]
a4867566d9
chore(deps): update devdependencies (#2697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-26 08:34:06 +00:00
renovate[bot]
0757db69b2
chore(deps): update dependency @types/prettier to v3 (#2712)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-26 08:33:11 +00:00
renovate[bot]
f0de25c992
chore(deps): update dependency @antfu/eslint-config to ^2.9.0 (#2711)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-26 08:32:33 +00:00
TAKAHASHI Shuuji
660549b08b
chore: update masto to v6.7.0 (#2708) 2024-03-21 15:18:53 +00:00
Joaquín Sánchez
7807730118
feat(i18n): add missing spanish mute duration dialog entries (#2696) 2024-03-21 12:37:57 +00:00
Joaquín Sánchez
b526db0860
chore: update i18n module to 8.2.0 (#2703) 2024-03-21 12:13:28 +00:00
Sma11X
0133324ded
fix: correct local timeline stream (#2707) 2024-03-21 10:08:51 +00:00
TAKAHASHI Shuuji
e9ab0cd40b
fix: prevent showing notification errors for dev for known emoji reaction types (#2704) 2024-03-19 15:04:16 +00:00
Joaquín Sánchez
9251ec496b
chore: add ofetch to typescript.hoist (#2693)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2024-03-19 12:56:14 +00:00
renovate[bot]
bd4cd02b2b
chore(deps): update pnpm to v8.15.5 (#2698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 12:40:13 +00:00
Joaquín Sánchez
74ccfece5d
chore: update nuxt to 3.11.1 (#2702) 2024-03-19 12:36:25 +00:00
35b4c80311
fix(ci): add missing docker pushes
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-03-18 14:50:56 +01:00
f6a081d199 Merge pull request 'feat-add-woodpecker' (#1) from feat-add-woodpecker into main
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #1
2024-03-18 13:42:55 +00:00
5e419045ed
fix(ci): add secrets
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
ci/woodpecker/pull_request_closed/woodpecker Pipeline was successful
2024-03-18 14:24:49 +01:00
cfdbb66b96
fix(ci): docker login 2024-03-18 14:16:41 +01:00
c717aace86
fix(ci): remove docker login 2024-03-18 14:10:31 +01:00
6713329a5e
fix(ci): add docker login 2024-03-18 14:00:02 +01:00
7470468077
feat(ci): add docker push test 2024-03-18 13:53:05 +01:00
9044b3bcad
fix(ci): add missing flags docker buildx 2024-03-18 13:41:39 +01:00
5bd9dce91e
fix(ci): added missing flag for cut 2024-03-18 13:39:40 +01:00
12e14cfc05
fix(ci): deleted sh uncompatible line 2024-03-18 13:37:51 +01:00
1ea4399765
feat(ci): Made ci sh compatible (hopefully^^) 2024-03-18 13:34:44 +01:00
991cb812da
feat(ci): Add build tags 2024-03-18 13:26:08 +01:00
Sma11X
c89e499f96
fix: pre tag overwritten by default style (#2699) 2024-03-18 11:34:03 +00:00
Dohány Tamás
89e3582dd7
feat(i18n): Update hu-HU.json (#2694) 2024-03-17 19:11:42 +00:00
TAKAHASHI Shuuji
48c013709a
ci(docker.yml): support linux/arm64 container (#2691) 2024-03-17 15:15:04 +00:00
renovate[bot]
f90f0a2e61
chore(deps): update pnpm to v8.15.4 (#2627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-17 15:14:19 +00:00
renovate[bot]
c58b585855
chore(deps): update lint (#2399)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-17 15:14:04 +00:00
Joaquín Sánchez
ded2e0f3d7
chore: update nuxt to 3.11.0 (#2692) 2024-03-17 14:32:02 +00:00
9b77efe1d7
test(ci): 2024-03-16 15:52:25 +01:00
aec670a903
test(ci): add git to image 2024-03-16 15:48:38 +01:00
1218f92133
test(ci): another syntax test 2024-03-16 15:45:13 +01:00
7c0986a005
test(ci): another syntax test 2024-03-16 15:42:49 +01:00
ac01207283
test(ci): another syntax test 2024-03-16 15:37:04 +01:00
ef169d682f
test(ci): syntax test 2024-03-16 15:33:04 +01:00
Joaquín Sánchez
21d5633233
chore: bump to eslint-config to 2.8.1 (#2685) 2024-03-13 06:39:28 +00:00
Joaquín Sánchez
7703565c75
fix(ui): hashtags not working when composing (#2686) 2024-03-12 20:47:05 +00:00
cuithon
5a9546ec0a
chore: fix typo (#2681)
Signed-off-by: cuithon <dscs@outlook.com>
2024-03-12 07:58:20 +00:00
patak
bc30a8bd82 chore: release v0.13.0 2024-03-11 12:08:52 +01:00
Duy
c432c2bd0d
feat(i18n): Update vi-VN.json (#2664) 2024-03-11 10:55:18 +00:00
Francesco
364fbd350b
feat(i18n): Update it-IT locale (#2666) 2024-03-11 10:55:05 +00:00
Xabi
c64580f782
feat(i18n): update eu-ES.json (#2670) 2024-03-11 10:54:53 +00:00
Emanuel Pina
e7dfdafd59
feat(i18n): Update portuguese from Portugal translation (#2671) 2024-03-11 10:54:38 +00:00
Ayo Ayco
b06ec9356d
feat(i18n): update Tagalog translations (#2677) 2024-03-11 10:54:20 +00:00
TAKAHASHI Shuuji
3b1a66c93c
fix: fix vue/no-ref-as-operand and vue/return-in-computed-property ESLint errors (#2679) 2024-03-11 10:53:25 +00:00
TAKAHASHI Shuuji
ed8a1811cc
chore: upgrade @vueuse/core from 10.8.0 to 10.9.0 (#2674) 2024-03-10 18:38:37 +00:00
TAKAHASHI Shuuji
dfbe2e080d
fix: prevent empty search keyword to send invalid request (#2676) 2024-03-10 18:37:32 +00:00
TAKAHASHI Shuuji
0fd9374e8c
fix: fix incorrect follow status on followers and following pages (#2669) 2024-03-09 19:31:40 +00:00
TAKAHASHI Shuuji
1c8e48bee4
fix: show loading spinner on follow button while fetching account relationship (#2667)
Co-authored-by: patak <583075+patak-dev@users.noreply.github.com>
2024-03-09 18:44:44 +00:00
TAKAHASHI Shuuji
3448335356
feat: allow to set mute duration and notifications mute option (#2665) 2024-03-09 09:52:41 +00:00
Joaquín Sánchez
4954473f50
chore: extract bg and theme colors to constants (#2662) 2024-03-07 19:15:35 +00:00
TAKAHASHI Shuuji
efa17caf5e
fix: consistent hover highlight styling in mobile bottom navigation menus (#2661) 2024-03-07 19:14:20 +00:00
Joaquín Sánchez
df165f0023
fix(pwa): wrong web manifest colors (#2659) 2024-03-07 14:55:27 +00:00
TAKAHASHI Shuuji
0f583ece28
feat: remember last accessed explore tab (#2658) 2024-03-07 14:33:25 +00:00
Ivan Demchuk
d579977790
feat(i18n): update Ukrainian translations (#2660) 2024-03-07 13:41:24 +00:00
TAKAHASHI Shuuji
8786c83db7
fix: remember last accessed notification tab (#2654) 2024-03-06 22:00:07 +00:00
patak
1ce913e69d chore: release v0.12.1 2024-03-06 16:52:16 +01:00
Joaquín Sánchez
48a8b74e7c
fix(ui): mentions not working when composing (#2655) 2024-03-06 15:42:41 +00:00
patak
1ff13952b0 chore: release v0.12.0 2024-03-06 08:48:14 +01:00
Francesco
02f7c4b291
feat(i18n): Update it-IT locale (#2652) 2024-03-05 20:12:05 +00:00
Joaquín Sánchez
9da77637b2
chore: bump to eslint-config v2.8.0 (#2651)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2024-03-05 14:48:58 +00:00
Joaquín Sánchez
62f70250d5
fix(ui): wrong reply to account (#2649) 2024-03-05 13:21:58 +00:00
Joaquín Sánchez
873c62e9ef
feat(i18n): add missing nav.hashtags entry for Spanish translation (#2650) 2024-03-05 13:21:12 +00:00
Emanuel Pina
b1ff1e6277
feat(i18n): Update portuguese from Portugal translation (#2648) 2024-03-05 13:20:44 +00:00
TAKAHASHI Shuuji
f644148844
feat: introduce new "Followed tags" page (#2642)
Co-authored-by: patak <583075+patak-dev@users.noreply.github.com>
2024-03-05 10:27:10 +00:00
Joaquín Sánchez
3120bbb77f
feat(content-rich html parsing): add paragraphs LTR/RTL direction support (#2545) 2024-03-05 06:25:58 +00:00
renovate[bot]
6cbe65c9d8
chore(deps): update devdependencies (#2646)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-04 20:39:12 +00:00
qezwan
1c908363cb
feat(i18n): Add central kurdish locale(ckb) (#2332)
Co-authored-by: userquin <userquin@gmail.com>
2024-03-04 20:28:57 +00:00
Jafar Farganlooj
c01a15c930
feat(i18n): Add Persian translation (#2535)
Co-authored-by: userquin <userquin@gmail.com>
2024-03-04 19:59:03 +00:00
nonnullish
0c15aa55d8
fix: fix emoji placement (#2626) (#2645) 2024-03-04 19:56:59 +00:00
Joaquín Sánchez
9f04e17e57
fix(ui): avoid fetching status account in replying to until visible (#2638) 2024-03-04 19:55:02 +00:00
Joaquín Sánchez
308b50cbad
feat(ui): fetch account data on demand (#2632) 2024-03-04 19:20:13 +00:00
TAKAHASHI Shuuji
e44833b18a
feat: show tag hover card when hovering cursor on hashtag links (#2621)
Co-authored-by: userquin <userquin@gmail.com>
2024-03-04 16:45:25 +00:00
Joaquín Sánchez
0fa87f71a4
chore(tests): fix vitest can't terminate worker (#2644) 2024-03-04 16:41:38 +00:00
Emanuel Pina
edfbe2c3ed
feat(i18n): Update portuguese from Portugal translation (#2633) 2024-03-04 16:02:35 +00:00
Joaquín Sánchez
70c7e93919
refactor: update no reactivity transform changes (#2639) 2024-03-04 16:01:56 +00:00
TAKAHASHI Shuuji
95e466146d
fix: show correct reply target user account in reply post header (#2640) 2024-02-29 20:55:46 +00:00
Joaquín Sánchez
efec212a9f
fix(pwa): update pwa plugin to fix broken prompt (#2634) 2024-02-29 16:55:31 +00:00
Kevin Pliester
1844af0a41
feat(i18n): German translation for new shortcuts (#2641) 2024-02-29 16:09:04 +00:00
Joaquín Sánchez
72b80d4984
fix(ui): missing replying to links (#2637) 2024-02-28 18:02:09 +00:00
Francesco
6dc5a68c80
feat(i18n): Update it-IT locale (#2630) 2024-02-26 13:22:51 +00:00
TAKAHASHI Shuuji
310b32c123
fix: allow to edit alt description of attached image again (#2631) 2024-02-26 13:11:21 +00:00
Joaquín Sánchez
748dd5e19f
fix(cache): return cached account as promise (#2623) 2024-02-25 19:43:34 +00:00
Joaquín Sánchez
c00d6f7bf8
feat(ui): add missing goto magic keys spanish translation entries (#2625) 2024-02-25 19:39:57 +00:00
Joaquín Sánchez
fc5d248094
fix(ui): account mentions not being fetched when visible (#2624) 2024-02-25 19:28:38 +00:00
Joaquín Sánchez
6f20ce5bba
chore(test): add hanging-process reporter on CI (#2622) 2024-02-25 14:13:27 +00:00
TAKAHASHI Shuuji
edcc8741bf
feat: add several new shortcut keys for navigation (#2618) 2024-02-24 19:28:56 +00:00
renovate[bot]
3584151fab
fix(deps): update tiptap to v2.2.4 (#2398)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: userquin <userquin@gmail.com>
2024-02-24 19:26:14 +00:00
Joaquín Sánchez
efb6967e6a
fix(ui): help preview tabindex, auto focus and buttons (#2616) 2024-02-24 18:24:55 +00:00
Joaquín Sánchez
eddbb1eee9
chore: cleanup isHydrated (#2614)
Co-authored-by: patak <583075+patak-dev@users.noreply.github.com>
2024-02-24 18:24:19 +00:00
Joaquín Sánchez
6b40319723
fix(ui): wrong tabindex usage 2 (#2617) 2024-02-24 18:23:37 +00:00
Joaquín Sánchez
913e2892f7
fix(ui): wrong tabindex usage (#2615) 2024-02-24 18:13:12 +00:00
renovate[bot]
a3c5272e07
chore(deps): update devdependencies (#2388)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-24 16:56:38 +00:00
Joaquín Sánchez
55037f04cd
chore: update nuxt to 3.10.3 (#2610) 2024-02-24 16:46:14 +00:00
patak
1fefb6e5b6
fix: paginator watch (#2613) 2024-02-24 14:51:51 +00:00
patak
3769176eaa
feat: . shortcut to show new items (#2612) 2024-02-24 14:46:54 +00:00
TAKAHASHI Shuuji
082650d458
fix: fix [object Object] on the mentions tab (#2611) 2024-02-24 14:18:13 +00:00
Joaquín Sánchez
36004a7eba
feat: bump to latest vue 3.4.19 (#2607)
Co-authored-by: patak <matias.capeletto@gmail.com>
2024-02-24 12:24:21 +00:00
Joaquín Sánchez
81ef8ff9aa
chore: include .gitattributes for eol (#2606) 2024-02-23 13:32:51 +00:00
Joaquín Sánchez
da163903b1
chore: bump to @vueuse/gesture v2.0.0 (#2605) 2024-02-23 13:04:44 +00:00
patak
ccfa7a8d10
refactor: no reactivity transform (#2600) 2024-02-21 15:20:08 +00:00
Xabi
b9394c2fa5
fix(i18n): update eu-ES.json (#2594) 2024-02-19 12:42:57 +00:00
Yudai Nishiyama
1954c34628
feat(i18n): Update ja-JP.json (#2588) 2024-02-19 12:05:02 +00:00
patak
9f005a0a59 chore: release v0.11.0 2024-02-19 10:33:00 +01:00
TAKAHASHI Shuuji
bf0c562794
fix(suggestion): allow case-insensitive emoji suggestion (#2565) 2024-02-19 09:23:58 +00:00
renovate[bot]
54fe0c1ab9
chore(deps): update dependency vitest to ^1.3.0 (#2556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-17 17:29:14 +00:00
Shinigami
1bbc2eca24
fix: notification badge (#2592)
Co-authored-by: Ayo <ramon.aycojr@gmail.com>
2024-02-16 16:48:53 +00:00
renovate[bot]
dcc1b74824
chore(deps): update pnpm to v8.15.3 (#2557)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-15 15:49:27 +00:00
ocavue
8eb6b2378a
refactor: migrate from shikiji to shiki v1 (#2591) 2024-02-15 07:43:09 +00:00
lazzzis
40415f34a4
fix: fix tooltip overlaps with editor tool popup on Mobile (#2582) 2024-02-11 06:39:45 +00:00
Emanuel Pina
be4752ee0c
feat(i18n): Update portuguese from Portugal translation (#2577) 2024-02-08 15:41:26 +00:00
Joaquín Sánchez
30e2295af4
feat(i18n): Update es.json (#2576) 2024-01-26 23:23:57 +00:00
华丽
285f83e2fa
feat: Add option to preserve whitespace in parseOptions (#2448) 2024-01-26 18:44:07 +00:00
Duy
8db37617d4
feat(i18n): Update vi-VN.json (#2574) 2024-01-26 18:43:07 +00:00
Francesco
172883a499
feat(i18n): Update it-IT locale (#2572) 2024-01-26 03:21:23 +00:00
TAKAHASHI Shuuji
2a59543836
fix: allow to translate "Lock" string on profile (#2571) 2024-01-24 15:48:24 +00:00
TAKAHASHI Shuuji
77b917a921
fix: rename tab label from "Mention" to "Mentions" (#2570) 2024-01-24 12:12:42 +00:00
Francesco
af8a6e6809
feat(i18n): Update it-IT locale (#2569) 2024-01-24 09:13:02 +00:00
Francesco
6d8b33a58a
feat(i18n): Update it-IT locale (#2567) 2024-01-23 05:26:09 +00:00
patak
7322711609
fix: subscribe to proper user.notification stream (#2566) 2024-01-21 08:52:52 +00:00
Duy
b8e8693342
feat(i18n): Update vi-VN.json (#2560) 2024-01-21 08:31:22 +00:00
TAKAHASHI Shuuji
f0bc78ba2c
refactor: fix lint warnings (#2564) 2024-01-21 09:30:15 +01:00
TAKAHASHI Shuuji
cadf1b4a7c
feat: add Bluesky and Friendica icons (#2563) 2024-01-18 10:21:49 +00:00
TAKAHASHI Shuuji
f79d84ad6e
feat: add new setting to disable blur for low-performance device (#2561) 2024-01-18 08:18:49 +00:00
renovate[bot]
b0125eb3fc
chore(deps): update docker/setup-qemu-action action to v3 (#2558)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-15 08:35:52 +00:00
Emanuel Pina
77175416a6
feat(i18n): Update portuguese from Portugal translation (#2555) 2024-01-10 15:31:28 +00:00
renovate[bot]
7836edd10a
chore(deps): update docker/metadata-action action to v5 (#2527)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 15:02:29 +00:00
renovate[bot]
0ae189207f
chore(deps): update docker/login-action action to v3 (#2515)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 14:01:10 +00:00
renovate[bot]
56d4967eb7
chore(deps): update docker/setup-buildx-action action to v3 (#2528)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 13:46:05 +00:00
TAKAHASHI Shuuji
0451ac98c9
feat: improve title and layout of the confirm dialog (#2307) 2024-01-09 19:51:36 +00:00
ghose
54e53889e5
feat(i18n): updated gl-ES translation (#2522)
Co-authored-by: Joaquín Sánchez <userquin@gmail.com>
Co-authored-by: patak <matias.capeletto@gmail.com>
2024-01-09 14:35:04 +01:00
yrming
149963c304
feat(i18n): complete the translation of copy_account_name (#2487) 2024-01-09 09:12:29 +00:00
Cesar Gomez
44f5ec1fa2
feat(i18n): missing and rewording es and es-419 keys (#2511)
Co-authored-by: patak <matias.capeletto@gmail.com>
2024-01-09 09:08:42 +00:00
patak
6c5bb83ac3
feat: upgrade to masto.js v6 (#2530) 2024-01-09 08:56:15 +00:00
Joshix-1
d8ea685803
fix: meta og:url should use the origin of the request instead of elk.zone (#2550) 2024-01-09 08:14:35 +00:00
Duy
3fa1fc349c
feat(i18n): update vi-VN.json (#2506) 2024-01-08 20:26:04 +00:00
Joaquín Sánchez
3adf92ea56
feat: add LTR/RTL in hashtags and mentions support (#2541)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2024-01-04 19:51:32 +00:00
Matty Jorgensen
b016320eaf
feat: add Vercel KV (#2533) 2024-01-02 10:58:37 +00:00
ocavue
77588c1890
fix: trigger code block highlighting when the highlighter is ready (#2539) 2024-01-01 16:46:37 +00:00
北雁云依
e43993770d
fix: spoiler button style in notifications (#2537) 2024-01-01 17:48:52 +01:00
TAKAHASHI Shuuji
9070fa4053
feat: add a new link icon (#2534) 2024-01-01 17:48:10 +01:00
Roshan Jossy
7f041c3ac8
docs: use GitHub markdown formatting for note in Readme (#2536) 2024-01-01 17:47:49 +01:00
Sebastian Di Luzio
b7c22287d6
chore: run unit tests in watch mode by default (#2525) 2023-12-22 21:50:59 +00:00
Sebastian Di Luzio
07042b9f31
fix: correct linking of theme colors (#2524) 2023-12-22 13:25:34 +01:00
Shinigami
c0bb6e293c
feat: show emoji tooltip (#2485) 2023-12-22 12:16:46 +00:00
ocavue
74138a9a58
refactor: migrate from shiki to shikiji (#2520) 2023-12-20 18:54:40 +00:00
renovate[bot]
e63473a5f8
chore(deps): update pnpm to v8.12.1 (#2514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-19 20:59:20 +00:00
renovate[bot]
24378e0be8
chore(deps): update dependency vitest to ^1.1.0 (#2338)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-19 20:58:50 +00:00
Daniel Roe
5ce005b55a
chore: correct type import from floating-vue (#2518) 2023-12-19 22:31:39 +01:00
Daniel Roe
3ae2d50bff
test: reenable nuxt runtime tests (with latest test-utils) (#2497) 2023-12-14 11:45:52 +00:00
renovate[bot]
2b421f1039
chore(deps): update pnpm to v8.12.0 (#2507)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-12 21:42:53 +00:00
renovate[bot]
e0ddbc1da2
chore(deps): update dependency vitest to v1 (#2508)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-12 21:42:19 +00:00
Xabi
ca3a818678
fix(i18n): update Basque localisation (#2503) 2023-12-09 16:05:10 +00:00
Joaquín Sánchez
9155c32ece
chore(pwa): improve DX for $pwa (#2498) 2023-12-09 16:04:41 +00:00
Cesar Gomez
3dbdb99118
feat(i18n): es & es-419 locales sync (#2505) 2023-12-09 16:03:43 +00:00
renovate[bot]
c3d96d2811
chore(deps): update dependency node to v20 (#2501)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-05 10:18:22 +00:00
renovate[bot]
429d1d7ce8
chore(deps): update actions/setup-node action to v4 (#2499)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-05 10:18:19 +00:00
Joaquín Sánchez
5503ecbea2
chore(pwa): change sw generation logic (#2494) 2023-12-01 17:28:31 +00:00
Tamas
21376e013a
feat(i18n): hu-HU.json update (#2489) 2023-11-29 22:27:04 +00:00
Daniel Roe
17f6d93c7c
chore: update nuxt to v3.8.2 (#2490) 2023-11-29 22:26:10 +00:00
renovate[bot]
0e701afb98
chore(deps): update all non-major dependencies (#2389)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 17:55:12 +00:00
renovate[bot]
cdcc89518a
chore(deps): update actions/checkout action to v4 (#2391)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 17:54:45 +00:00
renovate[bot]
1f6a7186f8
chore(deps): update docker/build-push-action action to v5 (#2401)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 17:54:13 +00:00
Tamas
ad1461bd2d
feat(i18n): hu-HU.json issue (#2486)
Co-authored-by: Tamas Dohany <iamdtms@gmail.com>
Co-authored-by: Tamas Dohany <dohany.tamas@atlatszo.hu>
2023-11-29 11:19:28 +00:00
Daniel Roe
7ba9b05d12
chore: bump @nuxtjs/color-mode (#2488) 2023-11-29 11:09:44 +00:00
yrming
9c39eed209
feat: unify the style of under construction page (#2483) 2023-11-28 10:54:22 +00:00
Francesco
7ed95e317f
feat(i18n): Update it-IT locale (#2473) 2023-11-27 17:55:51 +00:00
Tamas
46105c86c6
feat(i18n): update hu-HU.json (#2480)
Co-authored-by: Tamas Dohany <iamdtms@gmail.com>
2023-11-27 12:19:13 +00:00
Sma11X
7785f4fe06
feat(settings): convert metadata to text (#2444) 2023-11-27 12:17:58 +00:00
Emanuel Pina
585d8c6f0b
fix(i18n): Update portuguese from Portugal translation (#2482) 2023-11-27 12:11:11 +00:00
Alex
1f752e65ed
fix: move the ALT text button for video attahcments to the top (#2479) 2023-11-24 08:19:53 +00:00
Tamas
7595162a0e
feat(i18n): update hu-HU.json (#2477)
Co-authored-by: Tamas Dohany <iamdtms@gmail.com>
2023-11-22 18:10:22 +00:00
TAKAHASHI Shuuji
20c30e92a3
feat: support Threads icon in profile links (#2474) 2023-11-17 08:40:23 +00:00
TAKAHASHI Shuuji
e00e4074e1
feat: put account name copy button (#2347) 2023-11-14 14:34:56 +00:00
patak
7ec76ffed9 chore: release v0.10.3 2023-11-14 11:05:09 +01:00
patak
c41b427c2e
fix: btn-solid text color for dark mode (#2471) 2023-11-13 17:30:36 +00:00
Ayo Ayco
c55545612e
feat: allow https as frame-src (#2468) 2023-11-12 06:42:02 +00:00
Adityawarman Dewa Putra
dab0502319
feat(i18n): Update id-ID locale (#2460) 2023-11-11 09:21:20 +00:00
Adityawarman Dewa Putra
10bd555926
feat: add pinterest icon in profile metadata (#2461) 2023-11-11 09:20:41 +00:00
Xabi
53dc1f37ca
fix(i18n): update Basque localisation (#2465) 2023-11-11 09:18:41 +00:00
TAKAHASHI Shuuji
68f92e07b7
feat(a11y): improve button color contrast with white text (#2449) 2023-11-09 20:24:11 +00:00
Ayo Ayco
957f0d3b17
feat: display embedded media player (#2417) 2023-11-07 09:57:44 +00:00
JP
0bd1209bee
feat(i18n): Update arabic locale (#2459) 2023-11-06 07:42:17 +00:00
Tamas
00c4a369cc
feat(i18n): update hu-HU.json (#2458)
Co-authored-by: Tamas Dohany <iamdtms@gmail.com>
2023-11-06 07:41:52 +00:00
Adityawarman Dewa Putra
8a5ddb7c87
feat(i18n): Update the id-ID locale (#2456) 2023-11-06 07:40:50 +00:00
Francesco
90878f97b5
feat(i18n): Update it-IT locale (#2440) 2023-11-03 15:00:41 +00:00
Emanuel Pina
09189378e0
fix(i18n): Update portuguese from Portugal translation (#2446) 2023-11-03 15:00:16 +00:00
Ɗʊƴ
769968c2e8
fix(i18n): Add new strings (#2447) 2023-11-03 14:59:33 +00:00
Tom Doe
5d09e7d2ab
fix: #2439 - endMessage in CommonPaginator (#2441) 2023-10-24 13:01:57 +00:00
Francesco
0924c9d9be
feat(i18n): Update it-IT locale (#2438) 2023-10-22 20:47:46 -05:00
Sma11X
293534fb8b
fix: correct links content with query symbol (#2377) 2023-10-22 16:14:37 +00:00
Sma11X
5fceb70971
feat: handle follow request (#2339) 2023-10-22 16:11:00 +00:00
Emanuel Pina
d825a71d1f
fix(i18n): Update portuguese from Portugal translation (#2437) 2023-10-22 16:07:23 +00:00
Daniel Roe
a47071d341 chore: bump some lockfile dependencies 2023-10-18 09:47:29 +01:00
Daniel Roe
52c947f9e5 chore: update nuxt-vitest 2023-10-18 09:36:46 +01:00
Xabi
07b7f38386
fix(i18n): update eu-ES.json (#2432) 2023-10-17 08:09:47 +00:00
TAKAHASHI Shuuji
291f99cbea
feat(ui): add "search" to the keyboard shortcut help (#2429) 2023-10-16 10:51:37 +00:00
Sma11X
1fe598f554
fix: some keyboard shortcuts not working in non-english (#2324) 2023-10-13 07:13:37 +00:00
Sma11X
e9f274f304
feat: replace links in status after translated (#2385)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-10-13 07:12:48 +00:00
Daniel Roe
ca0afe585d chore: dedupe dependencies 2023-10-12 16:30:35 +01:00
Joaquín Sánchez
1a0e83365a
fix(pwa): add manifest-src to CSP (#2428) 2023-10-12 16:57:52 +02:00
Anthony Fu
77a3bd833d chore: update devtools 2023-10-11 17:46:23 +08:00
Abel Derderian
02abe2d920
feat(i18n): Update the fr-FR locale (#2421) 2023-10-09 21:24:23 +00:00
Joaquín Sánchez
c8d9c4b871
fix(ui): exclude notifications without the status (#2375) 2023-10-09 20:33:02 +00:00
Emanuel Pina
fee811dd75
fix(i18n): Update portguese from Portugal translation (#2364) 2023-10-09 20:20:42 +00:00
Xabi
1910a1d782
fix(i18n): update Basque localisation (#2376) 2023-10-09 20:19:14 +00:00
Joaquín Sánchez
c387702bb1
feat(i18n): include missing Spanish entries (#2381) 2023-10-09 20:17:33 +00:00
Sebastian Di Luzio
e015adcf4e
fix: profile header avatar being pushed lower on smaller devices (#2423) 2023-10-09 20:14:04 +00:00
Daniel Roe
12eaae6bbb chore: export Emoji as explicit type 2023-10-03 00:09:18 +01:00
patak
e199e02e79 chore: release v0.10.2 2023-10-02 09:24:30 +02:00
Pavel Ruzicka
b42e77af24
i18n: update cs-CZ.json (#2418) 2023-10-01 02:41:21 -05:00
patak
0343898146 fix: revert publish height (#2334)
This reverts commit b74eec6a03.
2023-09-30 09:59:03 +02:00
TAKAHASHI Shuuji
b5f2cea1dc
feat(i18n): update Japanese localization (#2415) 2023-09-28 12:03:44 +00:00
Ɗʊƴ
2a9f607049
fix(i18n): Update vi-VN.json (#2396)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-09-25 19:11:15 +00:00
Francesco
043883bd8e
feat(i18n): Update it-IT locale (#2408) 2023-09-25 19:10:05 +00:00
Francesco
ed5592260f
feat(i18n): Update it-IT locale (#2370) 2023-09-20 06:52:50 +00:00
Sebastian Di Luzio
f4b0be8aed
feat: make new users signup notifications link to their profile (#2406) 2023-09-20 06:52:05 +00:00
Tamas
b723d51786
feat(i18n): Add Hungarian translation (hu-HU) (#2373)
Co-authored-by: Tamas Dohany <iamdtms@gmail.com>
Co-authored-by: Zsolt Botykai <zsolt.botykai@gmail.com>
2023-09-15 21:25:34 +00:00
renovate[bot]
25d4325bd0
chore(deps): update lint (#2390)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-13 06:34:15 +00:00
Anthony Fu
319f9c4ece fix(ui): improve notifications alignment and icons consistenty 2023-09-08 18:14:19 +02:00
Anthony Fu
06ef226440 chore: clean up footer 2023-09-08 17:57:08 +02:00
Anthony Fu
3691ec389a fix: improve elk-group-hover shortcut, close #2386 2023-09-08 17:56:29 +02:00
YRMING
ca2ca2bef4
feat: unify the format of locale keys (#2380) 2023-09-06 12:51:01 +00:00
Ayo Ayco
907d9999dc
feat: filter notifications by type (#2371)
Co-authored-by: Xabi <xabi.rn@gmail.com>
Co-authored-by: userquin <userquin@gmail.com>
2023-09-06 09:13:16 +00:00
renovate[bot]
e9c5de577e
chore(deps): update dependency lint-staged to v14 (#2354)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 14:22:33 +00:00
renovate[bot]
87d6ed39eb
fix(deps): update dependency iso-639-1 to v3 (#2355)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 13:43:52 +00:00
renovate[bot]
cf20ac29db
chore(deps): update lint (#2311)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 13:42:20 +00:00
renovate[bot]
1a96f87da0
fix(deps): update tiptap to v2.1.8 (#2256)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 13:42:01 +00:00
renovate[bot]
0f825a6efb
chore(deps): update devdependencies (#2310)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-09-05 12:55:03 +00:00
renovate[bot]
1b8d72105d
chore(deps): update pnpm to v8.7.1 (#2337)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 11:57:03 +00:00
TAKAHASHI Shuuji
5ef2996b40
feat: add keyboard shortcut helper link or button (#2365) 2023-08-28 15:24:34 +00:00
Sma11X
1ac3164d0c
fix(i18n): add missing translation (#2340) 2023-08-24 11:09:54 +00:00
Liberal dev
e4725d433e
fix(i18n): fix Korean translation (#2335) 2023-08-24 11:09:35 +00:00
Valtteri Laitinen
3716e3af6e
feat(i18n): update and improve Finnish locale (#2341) 2023-08-24 11:08:56 +00:00
Francesco
366f3e07df
feat(i18n): Update it-IT locale (#2350) 2023-08-24 11:06:00 +00:00
Joaquín Sánchez
6801ea6c2d
fix: compose page error (#2360) 2023-08-23 10:33:26 +00:00
Sma11X
4b37d19f65
fix: change status focus style (#2356) 2023-08-23 10:32:59 +00:00
Sma11X
c1bca79c50
fix: shrink the height of avatar (#2361) 2023-08-22 21:58:31 +00:00
Valtteri Laitinen
ee88c111f2
fix(i18n): use "post" and "boost" consistently (#2344) 2023-08-20 21:41:02 +00:00
舜岳
067550720a
refactor: solve the problem that the title is not centered (#2353) 2023-08-19 10:35:11 +00:00
Valtteri Laitinen
c5b1b32f2c
fix(i18n): correct typo (#2343) 2023-08-15 16:13:44 +00:00
Joaquín Sánchez
bd7436e5d2
feat(i18n): Add missing Spanish translations (#2336) 2023-08-14 14:05:35 +00:00
Valtteri Laitinen
8b883dc957
fix(i18n): delete unused strings (#2345) 2023-08-14 13:57:38 +00:00
Valtteri Laitinen
06808da616
fix(i18n): use normal question mark (#2342) 2023-08-14 13:56:33 +00:00
Anthony Fu
0b900128c1 chore: release v0.10.1 2023-08-13 12:31:14 +02:00
Florian Martinez
b74eec6a03
fix: publish height (#2334) 2023-08-13 08:39:18 +00:00
Florian Martinez
92d0f18389
fix: role indicator (#2333) 2023-08-13 08:28:32 +00:00
Liberal dev
c0f936f8fe
feat(i18n): Improve Korean translation (#2320) 2023-08-12 10:27:37 +00:00
Francesco
7e492422fe
fix(i18n): it-IT typo (#2323) 2023-08-12 10:27:07 +00:00
lazzzis
4325bca22b
feat(a11y): enhance post-related a11y features (#2328) 2023-08-12 10:26:37 +00:00
Duy
5a765187ab
fix(i18n): Update vi-VN.json (#2330) 2023-08-12 10:25:40 +00:00
lazzzis
e9a02ca337
fix: like/bookmark button is disappeared (#2327) 2023-08-12 12:25:24 +02:00
Xabi
221a6f2fc3
fix(i18n): update Basque localisation (#2325) 2023-08-11 12:21:40 +00:00
lazzzis
2267db11c6
feat: disabled boost button (#2326) 2023-08-11 11:56:47 +00:00
lazzzis
a4d34323ed
feat(a11y): add checkbox role to toggle items (#2321) 2023-08-10 10:18:35 +00:00
lazzzis
91db9b03a8
docs: fix a broken link in README (#2322) 2023-08-10 10:06:52 +00:00
Liberal dev
0be47261c7
fix(i18n): Improve Korean translation (#2319) 2023-08-09 22:33:12 +00:00
Liberal dev
49b39b7fa8
fix(i18n): Update Korean translation (#2318) 2023-08-09 18:59:32 +02:00
Vee Satayamas
1f37e3ab8b
feat(i18n): Add Thai locale (#2115) 2023-08-09 11:51:07 +00:00
Eric
e183c62036
fix(i18n): Update zh-CN.json (#2313) 2023-08-09 11:50:25 +00:00
Mikhail
370c8dd58e
fix(i18n): Add missing translations for ru-RU (#2212) 2023-08-09 11:49:15 +00:00
Liberal dev
b19f73c870
feat(i18n): Improve Korean translation (#2316) 2023-08-09 11:48:04 +00:00
Emanuel Pina
dccdcbbbe2
fix(i18n): Update portuguese from Portugal translation (#2285) 2023-08-09 11:47:25 +00:00
Duy
280911b233
fix(i18n): Update vi-VN.json (#2303) 2023-08-09 11:46:46 +00:00
Liberal dev
f3d17d3be2
fix: improve default font family (#2314) 2023-08-09 11:46:26 +00:00
Francesco
3f6cc16850
fix(i18n): Update it-IT locale (#2294) 2023-08-09 11:46:13 +00:00
Daniel Roe
4ebc8b6798 fix: deduplicate unstorage version 2023-08-08 11:30:38 +01:00
三咲智子 Kevin Deng
7079564ffe
refactor: upgrade vue-macros 2023-08-08 02:32:35 +08:00
Ayaka Rizumu
991034115b
feat: pull down to close bottom nav sidebar (#2290) 2023-08-03 15:05:58 +00:00
Nicolas Lœuillet
57814915d6
fix(i18n): fr-FR typo (#2295)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-08-02 10:45:53 +00:00
Chanhwi Joo
8181738d48
fix(i18n): Update Korean localization (#2292) 2023-08-02 10:44:24 +00:00
TAKAHASHI Shuuji
0a8cc317a9
feat: show delete confirmation dialog when clicking "Delete & re-draft" menu (#2296)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-08-02 10:41:47 +00:00
renovate[bot]
8df73b13bd
chore(deps): update dependency prettier to v3 (#2257)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-08-02 10:37:43 +00:00
Sma11X
d975c6fc2c
fix: add attributes before status update (#2293) 2023-08-02 10:31:08 +00:00
renovate[bot]
67d5d5c00a
chore(deps): update lint (#2233)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-08-02 10:28:18 +00:00
Sma11X
603e10b6ca
fix: check login in zen mode (#2258) 2023-08-02 10:27:31 +00:00
Anthony Fu
9ae0d9b744 ci: add merge_group event for merge queue 2023-08-02 12:13:23 +02:00
Anthony Fu
28f9540113 pref: improve unocss perf 2023-08-02 12:12:48 +02:00
Sma11X
468a17ad58
fix: nav more menu not active (#2300) 2023-08-02 11:43:24 +02:00
renovate[bot]
b84a6ccc32
chore(deps): update devdependencies (#2236)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-01 22:57:32 +01:00
Daniel Roe
a45b7173e5
chore: update to nuxt v3.6.5 (#2299) 2023-08-01 22:11:26 +01:00
三咲智子 Kevin Deng
d23f1d39eb
refactor: replace defineModels with defineModel 2023-08-01 17:44:01 +08:00
Daniel Roe
e6172ad38b chore: update nuxt-vitest 2023-08-01 10:36:19 +01:00
Daniel Roe
5870e8d6e6 test: work around mocking issue 2023-07-31 23:56:21 +01:00
renovate[bot]
3d696646c5
chore(deps): update dependency vitest to ^0.33.0 (#2235)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-31 20:20:25 +01:00
Daniel Roe
6edb6ccb15 chore: update nuxt-vitest 2023-07-31 19:53:33 +01:00
renovate[bot]
6cb7fca3ab
chore(deps): update all non-major dependencies (#2234)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-31 19:48:59 +01:00
Daniel Roe
3375563e64 fix: augment vueCompilerOptions in pkg-types 2023-07-31 17:15:53 +01:00
Liberal dev
832ee35a93
fix(i18n): update Korean localisation (#2275) 2023-07-30 21:39:32 +02:00
TAKAHASHI Shuuji
550540fad0
fix: correct ratio of profile header avatar (#2288) 2023-07-30 21:24:06 +02:00
Alex
e59c2af818
fix: cannot fullscreen due to Permission-Policy (#2281) 2023-07-29 20:45:30 +02:00
TAKAHASHI Shuuji
ee6ee30df1
feat: hide original post area in the edit widget (#2283) 2023-07-29 20:38:13 +02:00
Niklas Wolf
675f5184a0
feat: use configured writing/post language of user from mastodon (#2282) 2023-07-29 14:01:17 +02:00
tzhao11
0a9f2d99d5
feat(i18n): Update zh-CN locale (#2200) 2023-07-29 11:43:18 +02:00
Sma11X
35dcf91a06
feat(i18n): sync zh-CN (#2248) 2023-07-29 11:42:59 +02:00
kernoeb
7876727a41
chore(docs): add notice for notifications on Brave browser (#2260) 2023-07-29 11:02:34 +02:00
Xabi
3c3fad808d
fix(i18n): update eu-ES.json (#2259) 2023-07-29 11:02:09 +02:00
TAKAHASHI Shuuji
357fac4d49
feat: show save failed error messages on the profile config page (#2274) 2023-07-29 10:52:57 +02:00
Duy
f45f51d44b
feat(i18n): Update vi-VN.json (#2278) 2023-07-29 10:31:07 +02:00
Duy
5bbbf14c92
feat(i18n): update vi-VN.json (#2268) 2023-07-26 15:39:35 +02:00
Florian Martinez
0a933614fa
feat: role labels wrap (#2266) 2023-07-25 17:29:54 +02:00
Florian Martinez
22a1388d50
feat: add roles into account header and info (#2265) 2023-07-25 16:43:26 +02:00
TAKAHASHI Shuuji
0719ad0afd
docs: fix image URLs (#2264) 2023-07-25 07:15:07 +01:00
patak
1671dfb617 chore: release v0.10.0 2023-07-24 10:26:17 +02:00
TAKAHASHI Shuuji
b730fab643
fix: prevent the lost of focus on compose icons (#2253) 2023-07-22 19:22:17 +02:00
Francesco
81e1383da5
feat(i18n): Update it-IT locale (#2249) 2023-07-22 14:00:21 +02:00
linjin
cdc43775a6
fix: display background when text is selected (#2222) 2023-07-21 14:55:00 +02:00
Natsu Kagami
2a57c64fa0
fix: only add domain when none was provided (#2225) 2023-07-21 14:52:55 +02:00
Kowlin
8a86282951
fix: Show lock indicator with the correct state (#2226) 2023-07-21 14:50:36 +02:00
Emanuel Pina
da31709677
fix(i18n): Update portuguese from Portugal translation (#2242) 2023-07-21 14:48:12 +02:00
klrtk
b14a8e63c6
fix: Use favorite star icon in notifications when enabled (#2229) 2023-07-21 14:41:43 +02:00
TAKAHASHI Shuuji
cc89692d80
fix(a11y): make the bottom menu button focusable and navigable with a11y label (#2247) 2023-07-21 12:17:32 +02:00
Francesco
5782c326b2
feat(i18n): Update it-IT locale (#2246) 2023-07-21 09:08:49 +02:00
Kevin Pliester
af444391b5
fix(i18n): add missing translations for de-DE (#2241) 2023-07-19 14:40:27 +02:00
Cesar Gomez
9bc44f44a0
feat(i18n): sync report keys into es lang (#2202) 2023-07-19 14:16:06 +02:00
Abel Derderian
f7f4167b06
feat(i18n): Update the fr-FR locale (#2231) 2023-07-17 12:14:31 +02:00
Xabi
8fa9c40e86
fix(i18n): update Basque localisation (#2136) 2023-07-17 10:53:25 +02:00
Xabi
31a4924186
fix(i18n): update Basque localisation (#2230) 2023-07-17 10:52:39 +02:00
Emanuel Pina
a6b9d4a82b
fix(i18n): update portuguese from Portugal translation (#2186) 2023-07-15 15:21:15 +02:00
Florian Martinez
ca897bdd2f
feat: add experimental features descriptions (#2228)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-07-14 21:01:35 +02:00
Ryan Cao
fa44850686
chore(renovate): ignore node version correctly (#2224) 2023-07-11 16:03:59 +01:00
Natsu Kagami
a6e4da8c41
fix: add domain when querying for user on GoToSocial (#2221) 2023-07-11 13:59:48 +01:00
Daniel Roe
895c1ecd8d chore(docs): bump docus version and remove baseURL 2023-07-11 11:33:28 +01:00
Aaron Ransley
ae35f9d11d
fix: Update command key in keyboard shortcuts modal (#2208) 2023-07-10 11:32:15 +02:00
Joaquín Sánchez
2506c02c39
fix(ui): stop question mark propagation (#2209) 2023-07-10 11:29:42 +02:00
Joaquín Sánchez
a08d9d147c
fix: installed pwa shortcuts (#2205) 2023-07-07 11:56:06 +01:00
Daniel Roe
cb109b49b8 fix: don't redirect to generated path 2023-07-06 21:19:01 +01:00
Daniel Roe
d51303cb8b
chore: update to nuxt v3.6.2 (#2203) 2023-07-06 21:13:25 +01:00
patak
c00354c833 fix: custom emojis 2023-07-06 21:33:01 +02:00
三咲智子 Kevin Deng
1ee0ec68c5
feat: show hint on empty timeline 2023-07-05 14:33:41 +08:00
三咲智子 Kevin Deng
5c1411b3de
chore: fix pwa type 2023-07-04 13:32:22 +08:00
三咲智子 Kevin Deng
2d8ec4ab89
chore: upgrade deps 2023-07-04 13:18:36 +08:00
三咲智子 Kevin Deng
c7e20296a2
chore: remove default npm option 2023-07-04 13:06:17 +08:00
Horváth Bálint
a98ca69382
fix: status card confusion (#2196) 2023-07-03 21:04:16 +02:00
Philip Sorst
886fc89df6
fix(i18n): add missing translations for de-DE (#2194) 2023-07-03 18:34:43 +02:00
三咲智子 Kevin Deng
112502155e
feat: add account share 2023-07-03 15:58:48 +08:00
Guto Carvalho
be446f5433
docs: add bolha.us server to readme (#2191) 2023-07-03 15:46:55 +08:00
Francesco
a9f5e4b5e7
fix(i18n): update it-IT locale (#2178) 2023-07-02 22:13:05 +02:00
Joaquín Sánchez
78b8b441ba
fix(ui): do not show poll expiration if missing (#2176) 2023-07-03 02:12:24 +08:00
三咲智子 Kevin Deng
d52755a153
feat: withdraw follow request
closes #2179
closes #2162
2023-07-03 02:09:30 +08:00
三咲智子 Kevin Deng
d5856b83c6
feat: add locked for account 2023-07-03 01:55:18 +08:00
三咲智子 Kevin Deng
338e203b6f
chore: upgrade devtools 2023-07-03 01:31:09 +08:00
renovate[bot]
026ef988c4
fix(deps): update dependency lru-cache to v10 (#2181)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-02 17:15:53 +00:00
renovate[bot]
5f2dca1979
chore(deps): update devdependencies (#2163)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-07-03 01:11:13 +08:00
三咲智子 Kevin Deng
676470bae2
chore: ignore deps 2023-07-03 01:07:55 +08:00
renovate[bot]
e0525e5f55
chore(deps): update dependency vitest to ^0.32.2 (#2097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-02 16:48:59 +00:00
三咲智子 Kevin Deng
d4ce90a7e8
fix: tsconfig in service worker 2023-07-03 00:41:25 +08:00
三咲智子 Kevin Deng
171f0ec857
refactor: upgrade volar 2023-07-03 00:34:39 +08:00
renovate[bot]
fbf49368c1
chore(deps): update lint (#2180)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-07-02 16:26:23 +00:00
三咲智子 Kevin Deng
3f8d68c7f7
chore: fix typo 2023-07-03 00:19:11 +08:00
renovate[bot]
0c6260367e
chore(deps): update pnpm to v8.6.5 (#2188)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-26 22:36:30 +08:00
Joaquín Sánchez
0b5797249f
feat(pwa): include window-controls-overlay in installed pwa logic (#2135) 2023-06-23 21:40:21 +02:00
Joaquín Sánchez
e453a316f7
chore: bump to pwa plugin 0.16.4 (#2159)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-06-23 21:39:02 +02:00
Pavel Biryukov
25a5d3fe7b
feat(i18n): Russial localization improvements (#2169)
Co-authored-by: Pavel Biryukov <birksovskiy@proton.me>
2023-06-23 21:37:32 +02:00
Ashwin Agarwal
34aca66fef
feat: Report posts (#2184) 2023-06-23 14:24:10 +02:00
Joaquín Sánchez
5ea09d323f
feat(i18n): add spanish translation for "polls" (#2166) 2023-06-14 16:13:22 +02:00
Francesco
4541486d0d
feat(i18n): Update it-IT locale (#2150) 2023-06-14 15:16:13 +02:00
Horváth Bálint
a94fe1c9d0
feat: media preview modal - better zoom support (#2133) 2023-06-12 20:46:53 +02:00
renovate[bot]
58f3ff6cd6
chore(deps): update pnpm to v8.6.2 (#2164)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-12 22:14:25 +08:00
Vince Chu
fbc779d174
chore: Add elk.mstdn.ca to README.md (#2154) 2023-06-08 19:01:59 +00:00
Eddie Coldrick
7c1873c4e3
chore: Add MastodonAppUK to README (#2157) 2023-06-08 20:59:02 +02:00
Daniel Roe
123cf13145
chore: copy across .npmrc to docker build (#2152) 2023-06-08 10:53:33 +01:00
renovate[bot]
58053d0b53
fix(deps): update dependency @vueuse/motion to v2.0.0 (#2131)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-08 05:26:48 +08:00
renovate[bot]
68d0d55532
chore(deps): update lint (#2144)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-08 05:24:22 +08:00
renovate[bot]
b6304ab18c
chore(deps): update pnpm to v8.6.1 (#2098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-08 05:24:03 +08:00
Eddie Coldrick
e996e53a64
chore: add elkmeuk to README (#2149) 2023-06-07 15:01:15 +02:00
Joaquín Sánchez
f15150c40d
docs: typo in the sharp-ico repository link (#2142) 2023-06-03 12:25:08 +01:00
Joaquín Sánchez
01486c2aef
chore: bump to vite-plugin-pwa 0.16.0 (#2141) 2023-06-01 08:11:11 +01:00
Ryan Cao
5ad32c9e26
fix: handle hidden followers/following count (#2120) 2023-05-31 17:59:54 +02:00
Laura Langdon
2b1a5072d7
docs: add alt text instructions (#2139) 2023-05-31 15:41:23 +02:00
Joaquín Sánchez
c6c4d52556
fix(pwa): pwa icons in dev and build (#2137) 2023-05-30 19:38:24 +02:00
Joaquín Sánchez
d601a117c0
chore: add generate pwa icons script (#2130) 2023-05-29 16:52:27 +02:00
renovate[bot]
0767df3f78
chore(deps): update devdependencies (#2084)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-29 14:45:10 +02:00
renovate[bot]
670a4ef632
chore(deps): update lint (#2085)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-29 14:44:08 +02:00
Daniel Roe
0633c09726
chore: bump to nuxt v3.5.2 (#2134) 2023-05-29 14:26:01 +02:00
Daniel Roe
d535ae6ee1 fix: work around volar parsing issue 2023-05-29 13:46:45 +02:00
Daniel Roe
209013af09 fix: re-key paginator slots 2023-05-29 13:42:18 +02:00
Xabi
dfa0e5f300
fix(i18n): update eu-ES.json (#2129) 2023-05-29 10:26:55 +02:00
Daniel Roe
897968027c
chore: upgrade to nuxt v3.5 and vue v3.3 (#2132) 2023-05-29 15:16:34 +08:00
Joaquín Sánchez
ad0725e9ae
fix(ui): hidden pwa badge and install prompt (#2127) 2023-05-26 15:25:11 +02:00
Paulina3xz
4a167c5bf5
feat(i18n): Added all missing Polish translations + translation fixes (#2082) 2023-05-22 17:31:46 +02:00
Duy
4c0c6f1325
feat(i18n): Update vi-VN.json (#2121) 2023-05-22 17:31:21 +02:00
Duy
dff36d5c43
feat(i18n): Add Vietnamese locale (#2116)
Co-authored-by: userquin <userquin@gmail.com>
2023-05-22 14:33:30 +02:00
Emanuel Pina
a50f97e5f3
fix(i18n): update portuguese from Portugal translation (#2118) 2023-05-22 10:37:59 +02:00
Tuur Martens
9c9a1f7c35
fix: poll would sometimes remove last entry (#2117) 2023-05-21 21:57:29 +02:00
Joshix-1
e251a8a50b
chore: publish docker images on forks (#2106) 2023-05-21 17:29:29 +01:00
Joaquín Sánchez
dfb5a665f0
feat(pwa): add screenshots and orientation to webmanifest (#2109) 2023-05-21 17:28:28 +01:00
Tuur Martens
22556984fa
feat: adhere to and display poll limits (#2114) 2023-05-21 13:37:33 +02:00
Tuur Martens
1fda33848e
feat: poll creation (#2111) 2023-05-20 21:23:41 +02:00
Arash
d9add9f670
fix(i18n): update tr-TR translations (#2108) 2023-05-19 21:04:27 +02:00
patak
49ee431676 chore: release v0.9.7 2023-05-16 10:46:03 +02:00
patak
0092c8cbe9 fix: force using username@server settings if present 2023-05-16 10:45:22 +02:00
patak
d0a4c51ef5 chore: release v0.9.6 2023-05-16 09:45:25 +02:00
patak
52b2d12bf9 fix: tweak sidebar max-height 2023-05-16 09:38:25 +02:00
Cesar Gomez
5e5fb0e287
chore(i18n): little es translated word change for no_bookmarks and no_fa… (#2101) 2023-05-16 08:48:59 +02:00
Francesco
886488a3c9
feat(i18n): Update it-IT locale (#2100) 2023-05-16 08:48:13 +02:00
Joaquín Sánchez
69f9004917
feat(docs): allow edit any locale file (#2099) 2023-05-15 14:35:43 +02:00
patak
f635e0a634 fix: personal notes on loading 2023-05-15 09:26:55 +02:00
patak
29f6a73de1
fix: user acct not respecting domain (#2088) 2023-05-10 13:19:50 +01:00
Elan Hasson
f28c90498b
docs: Update README.md to fix typo (#2087) 2023-05-10 12:29:48 +01:00
Joaquín Sánchez
66484bac80
fix(ui): check empty spoiler text (#2092) 2023-05-10 11:28:48 +00:00
Joaquín Sánchez
99077da1bf
fix(ui): handle empty spoiler text (#2091) 2023-05-10 13:17:58 +02:00
patak
fc97e8ff5b fix: pasting emojis 2023-05-08 21:10:52 +02:00
patak
9d3c7ef116
feat: review compose buttons (#2076) 2023-05-08 08:45:27 +02:00
patak
e9740fe693
feat: separate search and explore (#2075)
Co-authored-by: TAKAHASHI Shuuji <shuuji3@gmail.com>
2023-05-07 17:41:18 +02:00
Francesco
1fbd88c826
feat(i18n): Update it-IT locale (#2080) 2023-05-07 17:00:36 +02:00
Emanuel Pina
d3cdadd444
fix(i18n): update portuguese from Portugal translation (#2077) 2023-05-07 07:57:46 +02:00
TAKAHASHI Shuuji
582a9847a1
feat: add 'use star favorite icon' preference (#2067) 2023-05-06 17:52:33 +02:00
patak
126cd4d535
feat: search back to the right (#2071) 2023-05-06 17:49:15 +02:00
Bram Van der Sype
c9265028d2
fix(i18n): Updated nl-NL.json (#2054) 2023-05-06 17:47:23 +02:00
DoceAzedo
77717c960c
feat(i18n): add Brazilian Portuguese locale (#2073)
Co-authored-by: userquin <userquin@gmail.com>
Co-authored-by: emanuelpina <emanuelpina@users.noreply.github.com>
2023-05-06 17:45:42 +02:00
Ayo Ayco
454ad18f1b
fix: regression with media hidden (#2072) 2023-05-06 11:26:16 +02:00
Abel Derderian
4be5d81f17
feat(i18n): Update fr-FR locale (#2060) 2023-05-06 08:57:42 +02:00
patak
5ffb96baf6 chore: release v0.9.5 2023-05-05 19:36:06 +02:00
Natsu Kagami
1487932c1d
fix: Handle failure when fetching user preferences (#2069) 2023-05-05 19:34:43 +02:00
Ayo Ayco
d9e7a09d24
feat: respect Media Display preferences (#2065) 2023-05-05 18:12:07 +02:00
TAKAHASHI Shuuji
a3116e703a
feat(i18n): update Japanese localization (#2061) 2023-05-05 17:40:09 +02:00
Francesco
8dd29039cd
feat(i18n): Update it-IT locale (#2055) 2023-05-05 16:13:34 +02:00
enpitsulin
0034b22da4
fix: image preview should justify-center (#2062) 2023-05-05 10:22:41 +02:00
patak
eebe57840b chore: release v0.9.4 2023-05-04 22:58:24 +02:00
patak
d59cdb0aa4 fix: extra spacing when no media in posts 2023-05-04 22:49:12 +02:00
patak
16561845f8 fix: respect always expand content warnings 2023-05-04 22:29:47 +02:00
patak
e9de11000b fix: new compose button opens compose route 2023-05-04 21:09:23 +02:00
Nikita Karamov
c6c844f3fd
fix: notification templates for admin reports (#2045)
Co-authored-by: patak <matias.capeletto@gmail.com>
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-05-03 15:01:35 +00:00
patak
fb61891c29 chore: release v0.9.3 2023-05-03 09:51:13 +02:00
patak
94323c8fe1 fix: personal note flash on profile
Fixes #2053
2023-05-03 09:25:08 +02:00
patak
f1f5a96929 chore: release v0.9.2 2023-05-02 17:55:39 +02:00
patak
df0c30c2f2 fix: account for width on sidebar media queries 2023-05-02 17:44:34 +02:00
patak
68f2c3fc5b chore: release v0.9.1 2023-05-02 14:15:55 +02:00
patak
d0ede35e89 fix: respect zenMode preference default 2023-05-02 14:13:53 +02:00
patak
c54aed62fb chore: release v0.9.0 2023-05-02 13:42:22 +02:00
renovate[bot]
5adc5eecf1
chore(deps): update devdependencies (#1944)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-02 11:11:22 +01:00
renovate[bot]
4c1e37caa2
chore(deps): update lint (#2011)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-05-02 11:03:49 +01:00
Daniel Roe
847de1b39b chore: ignore vue and vue-tsc dependencies for now 2023-05-02 10:59:44 +01:00
Daniel Roe
0a98c5f13d
chore: upgrade to nuxt v3.4.3 (#2046) 2023-05-02 11:48:33 +02:00
Shinigami
835269fa1d
chore(deps): replace esno with tsx (#1966) 2023-05-02 02:04:12 +02:00
Anthony Fu
61526df93f chore: upgrade to VueUse v10 2023-05-02 01:58:55 +02:00
Shinigami
076c47b7b0
feat: prefer en language as top (#2042) 2023-05-01 19:30:57 +02:00
Emanuel Pina
98777f078c
fix(i18n): Update portuguese from Portugal translation (#2044) 2023-05-01 19:29:30 +02:00
patak
dcf0f93eb9
feat: compose button (#2037) 2023-05-01 18:08:09 +02:00
patak
656b789e7c
feat: height responsive sidebar (#2038) 2023-05-01 17:58:37 +02:00
Francesco
70cb620ccd
feat(i18n): Update it-IT locale (#2041) 2023-05-01 17:34:50 +02:00
Phojie Rengel
3c3324f070
feat(i18n): add Tagalog translation (#2019)
Co-authored-by: Ayo Ayco <ayo@ayco.io>
2023-05-01 11:55:49 +02:00
patak
f3e1b6db67 fix: empty glass header on large screens 2023-04-30 21:46:07 +02:00
patak
d4e0d5c5f5
feat: better messages for no favourites and bookmarks (#2031) 2023-04-30 17:49:33 +02:00
Alex
ccf115ca4c
fix: refresh status after edit (#2032) 2023-04-30 17:19:14 +02:00
patak
c7b77216c1 fix: long title and description for expansion not showing
Fixes #1948
2023-04-29 22:57:26 +02:00
patak
8b8de1182c fix: avoid flash of connected line while loading avatars 2023-04-29 21:53:41 +02:00
Mark Pinero
99dc8a0479
fix(default): update layout to use dynamic vh (#1817) 2023-04-28 19:44:58 +02:00
renovate[bot]
28a68f47eb
fix(deps): update tiptap to v2.0.3 (#1987) 2023-04-28 19:38:22 +02:00
Emanuel Pina
9cc4c23e50
fix(i18n): update portuguese from Portugal translation (#2009) 2023-04-28 19:34:35 +02:00
renovate[bot]
2b42f225dd
chore(deps): update pnpm to v8.3.1 (#2012) 2023-04-28 19:34:04 +02:00
Christof Dorner
320ed81555
fix: detect Takahe hashtags correctly (#2024) 2023-04-28 19:33:34 +02:00
Alex
5bd17d3006
docs: fix contributing_guide link (#2029) 2023-04-28 09:21:19 +01:00
Phojie Rengel
5dc136372b
refactor: button creation with v-for to remove redundancy (#2020) 2023-04-28 09:42:23 +02:00
Alex
5c3b8be055
feat: add wellbeing preference hide news (#2026) 2023-04-28 09:38:44 +02:00
Alex
cbba846c4f
fix: translation button still display when posts have no contents (#2027) 2023-04-28 09:36:05 +02:00
Alex
574d72af61
fix: reply remove-and-re-draft error (#2028) 2023-04-28 11:25:53 +08:00
Peter Budai
a0d036952d
feat(editor): Respect default privacy setting of the account (2nd) (#1733)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-04-27 20:41:10 +00:00
Shinigami
23c1dfec10
feat: lazy load images (#1969) 2023-04-26 22:46:00 +02:00
Phojie Rengel
1ceb3e2857
docs: update translation guide file to copy (#2017) 2023-04-25 17:41:51 +02:00
Francesco
3f1cdbbfa9
feat(i18n): Update it-IT locale (#2015) 2023-04-24 21:00:56 +02:00
Joaquín Sánchez
59e418e2e0
fix: content render receiving undefined when converting to vnode (#2016) 2023-04-24 20:46:17 +02:00
manuq
ac4188274c
feat(ui): add clear button to search input field (#1989)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-04-24 17:05:26 +02:00
Francesco
450908ecb2
feat(i18n): Update it-IT locale (#2014) 2023-04-24 16:50:37 +02:00
Francesco
85260e8aaa
feat(i18n): Update it-IT locale (#2008) 2023-04-24 13:42:54 +02:00
patak
b2c1a4ddef
fix: emoji sizing (#2007) 2023-04-24 07:19:29 +02:00
Peter Budai
85ac040c2f
fix: Re-enable user card hover over mentions in posts (#1745) 2023-04-23 21:40:55 +02:00
Alec LeFors
94d22fd488
fix: Allow account handles to wrap in AccountHeader (#1991) 2023-04-23 21:35:01 +02:00
Daniel Roe
5b1ad44875
chore: bump nuxt to v3.4.2 (#1998) 2023-04-23 21:27:52 +02:00
Francesco
21f57f1cfa
feat(i18n): Add Italian Localisation (#2005)
Co-authored-by: Joaquín Sánchez <userquin@gmail.com>
2023-04-23 20:10:24 +02:00
Joaquín Sánchez
6727e63626
feat(i18n): Update Spanish translations (#2006) 2023-04-23 17:03:37 +02:00
Joaquín Sánchez
54e2afa56b
feat(ui): use sticky position on settings mid panel (#2004) 2023-04-23 14:21:54 +02:00
manuq
56405f52bb
fix: Add zen mode to preferences, remove shortcut (#2003) 2023-04-23 12:21:33 +02:00
patak
9564985a4e
fix: unicode emojis when editing (#2002) 2023-04-22 19:12:17 +02:00
Xabi
aa77919925
fix(i18n): update Basque localisation (#2001) 2023-04-22 15:45:08 +02:00
JP
1eb47b98f5
fix(i18n): update Arabic localisation (#1993) 2023-04-22 14:36:41 +02:00
Liberal dev
acb2b80cdd
fix(i18n): update Korean localisation (#1996) 2023-04-22 14:35:39 +02:00
Tuur Martens
dbbbe8aa01
feat: improve personal notes (#1978) 2023-04-22 12:41:27 +02:00
patak
bda18e7ac5 chore: use "boosted" instead of "reblogged" 2023-04-21 21:38:45 +02:00
patak
ce149e4cb4 fix: notification with null status should be excluded
Fixes #1995
2023-04-21 21:35:39 +02:00
patak
6f19d54586 chore: release v0.8.1 2023-04-21 15:15:40 +02:00
Daniel Roe
6fc6517811 chore: fix lockfile 2023-04-20 12:16:49 +01:00
Daniel Roe
58a7f15216 chore: bump nuxt-vitest version 2023-04-20 12:15:12 +01:00
patak
ea44f8bc30 fix: allow custom emojis on profile metadata field names
Fixes #1992
2023-04-19 21:32:07 +02:00
patak
d34a5e6e96 chore: fix titleTemplate param type 2023-04-16 22:35:25 +02:00
patak
1f559fae08 fix: use @unhead/vue 2023-04-16 22:33:22 +02:00
Kingsley Yung
ca8d785d9e
feat: allow user to view follow list in "Hide following/follower count" mode (#1901) 2023-04-16 21:47:20 +02:00
Liberal dev
18ea4ffb6e
feat(i18n): add Korean translation (#1968) 2023-04-16 21:42:32 +02:00
Joaquín Sánchez
f07d32375a
fix: saving profile data breaks cache (#1937) 2023-04-16 21:39:33 +02:00
Joaquín Sánchez
c71259334c
fix: remove flashing text on page reload (#1939) 2023-04-16 21:33:51 +02:00
patak
13581323b0 chore: fix lint 2023-04-16 21:25:55 +02:00
Emanuel Pina
587f73c4a0
fix(i18n): update portuguese from Portugal translation (#1984) 2023-04-16 20:36:35 +02:00
Ivan Demchuk
2267556b8b
chore: add a script to cleanup old translations (#1963) 2023-04-16 14:28:45 +02:00
Emanuel Pina
dac044e6ad
fix(i18n): update portuguese from Portugal translation (#1975) 2023-04-16 14:27:59 +02:00
Shinigami
3442dfe75d
feat: hide status from suspended account (#1967) 2023-04-16 14:22:03 +02:00
Glaydus
ce5e81e160
fix(i18n): update Polish translations (#1982) 2023-04-16 14:17:31 +02:00
Cesar Gomez
621d280a96
feat(i18n): sync es base lang (#1979) 2023-04-15 18:57:52 +02:00
Daniel Roe
fb1ca7d8f1
fix: use purpose: any for normal pwa icon (#1981) 2023-04-15 17:16:20 +01:00
Anthony Fu
189d358b2a
chore: update all deps (#1976) 2023-04-12 14:35:35 +02:00
renovate[bot]
3acf87d5b6
chore(deps): update lint (#1971)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Shinigami92 <chrissi92@hotmail.de>
2023-04-11 08:04:22 -07:00
renovate[bot]
d33ac87c64
fix(deps): update dependency @unocss/nuxt to ^0.51.0 (#1973)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-11 07:03:27 -07:00
renovate[bot]
a037583631
chore(deps): update dependency vitest to ^0.30.1 (#1972)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-11 07:03:20 -07:00
renovate[bot]
d6e199b83a
chore(deps): update pnpm to v8 (#1970)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-11 06:44:14 -07:00
Tuur Martens
79538a65ee
fix: wrong profile showing on hover sometimes (#1913) (#1964) 2023-04-10 20:12:27 +02:00
Tuur Martens
2dc7ad27bf
feat: personal notes (#1960) 2023-04-09 21:11:37 +02:00
renovate[bot]
921eaae949
fix(deps): update tiptap to v2.0.2 (#1524)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 22:23:45 +02:00
Alex
2f79f53877
feat(i18n): sync zh-CN with en (#1865) 2023-04-03 15:34:59 +02:00
renovate[bot]
973805f16d
chore(deps): update dependency typescript to ^5.0.3 (#1945)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-03 15:34:33 +02:00
Joaquín Sánchez
685b16d403
chore: change pwa module name (#1947) 2023-04-03 15:34:19 +02:00
Joaquín Sánchez
ab2881b9a2
refactor: remove useHeadFixed workaround (#1938)
Co-authored-by: Ayaka Rizumu <464388324@qq.com>
2023-04-01 04:14:12 -07:00
Daniel Roe
60a37e0bf8 chore: update devtools 2023-03-31 11:50:34 +01:00
ghose
da94117f61
feat(i18n): Update Gaician translation (#1934) 2023-03-30 22:11:00 +02:00
三咲智子 Kevin Deng
605359b9df
chore: release v0.8.0 2023-03-31 03:21:30 +08:00
三咲智子 Kevin Deng
c513907dbb
chore(deps): upgrade tiptap 2023-03-31 03:16:51 +08:00
renovate[bot]
4cc0101a06
chore(deps): update devdependencies (#1927)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-30 19:13:27 +00:00
三咲智子 Kevin Deng
f4f6208420
refactor: remove unused function 2023-03-31 03:07:49 +08:00
renovate[bot]
3c43a1cdd1
chore(deps): update lint (#1928)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-03-30 19:01:24 +00:00
renovate[bot]
2838e18ff7
chore(deps): update dependency typescript to v5 (#1930)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-31 02:58:04 +08:00
renovate[bot]
da2ac06d8a
chore(deps): update pnpm to v7.30.5 (#1929) 2023-03-27 20:18:22 +02:00
Baptiste Girardeau
881a49e0d9
fix: syntax for robots.txt disallow rules (#1925) 2023-03-26 17:11:22 +02:00
Daniel Roe
e062fb5e52
perf: set maxAge for various public assets (#1916) 2023-03-26 16:53:07 +02:00
renovate[bot]
a1026d3aab
fix(deps): update dependencies (#1908)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-03-24 00:12:42 +00:00
renovate[bot]
42dc99929e
chore(deps): update devdependencies (#1736)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 08:02:15 +08:00
三咲智子 Kevin Deng
0916b05afd
refactor(docs): replace palette function 2023-03-24 07:51:30 +08:00
三咲智子 Kevin Deng
331d652ef0
fix(docs): remove npm lock file 2023-03-24 07:46:22 +08:00
renovate[bot]
e9ddf3e6a0
chore(deps): update docker/build-push-action action to v4 (#1919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 07:40:30 +08:00
renovate[bot]
5dd3a52865
chore(deps): update dependency vitest to ^0.29.7 (#1918)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-24 07:39:03 +08:00
renovate[bot]
a82558130a
chore(deps): update dependency prettier to ^2.8.5 (#1917)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-23 23:35:22 +00:00
三咲智子 Kevin Deng
b51bae5361
ci: disable nuxt tests temporally 2023-03-24 06:39:21 +08:00
Eddie Coldrick
c94ff39982
style: Change logo files with added left/right padding (#1896) 2023-03-21 12:59:24 +01:00
Kevin
5717e5e677
chore(deps): upgrade nuxt 2023-03-21 12:20:36 +08:00
Joaquín Sánchez
0dbea5915f
docs(fix): pwa plugin link (#1915) 2023-03-20 17:49:39 +00:00
tarquinwj
f533a10097
docs: VAPID protocol information is wrong (#1914) 2023-03-20 18:11:24 +01:00
Kevin
c0561e7eed
chore: upgrade vue-tsc 2023-03-20 23:45:02 +08:00
Kevin
0418d05753
refactor(list): improve form 2023-03-20 23:43:13 +08:00
Kevin
01d1a30413
chore: upgrade deps 2023-03-20 23:11:04 +08:00
Kevin
55e0f040a3
chore: switch full iconify package 2023-03-20 22:56:35 +08:00
renovate[bot]
60924e5f5d
chore(deps): update all non-major dependencies (#1735)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-20 22:44:07 +08:00
Kevin
776594ec3d
chore: ignore upgrading node dep 2023-03-20 22:37:45 +08:00
renovate[bot]
189695c767
chore(deps): update dependency bumpp to v9 (#1909)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-20 22:32:37 +08:00
Anthony Fu
791642fac4 fix: replying-to padding 2023-03-19 23:36:09 +01:00
Anthony Fu
5dd3f4bfa3
feat: simplify notifications (#1905) 2023-03-19 21:55:19 +01:00
Cesar Gomez
a25376b60d
feat(i18n): es base sync (#1884) 2023-03-19 18:38:12 +01:00
forenta
eea2511e1d
fix(i18n): de-DE: Small update (#1907) 2023-03-19 18:04:47 +01:00
kongmoumou
01ed4f68dc
fix: sticky hover style on mobile (#1513)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-03-19 12:24:27 +00:00
renovate[bot]
6abd2a8770
chore(deps): update lint (#1887)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-19 12:16:44 +00:00
Anthony Fu
9465c2fe89 chore: update lint 2023-03-19 13:12:20 +01:00
Kingsley Yung
c7558ee7c5
feat: Include following count in hide follower count setting (#1897) 2023-03-16 21:14:06 +01:00
Xabi
8c7dc5a6df
fix(i18n): update Basque localisation (#1899) 2023-03-16 21:09:42 +01:00
WhiskeyOmega
ae268de5bf
chore: update ecosytem link (#1900) 2023-03-16 20:23:31 +01:00
renovate[bot]
05f3f04578
chore(deps): update dependency vitest to ^0.29.3 (#1886) 2023-03-16 09:16:32 +01:00
Francis Gulotta
dc397e133c
docs: add mastodon link to header (#1885) 2023-03-13 11:32:54 +01:00
patak
3732a2cc16
fix: copy and paste custom-emoji (#1873) 2023-03-09 11:18:03 +00:00
Vjacheslav Trushkin
fa3cfd6059
fix: get custom emoji id from title attribute (#1871) 2023-03-08 21:19:53 +01:00
patak
c76e8e8f5e chore: release v0.7.5 2023-03-08 14:54:01 +01:00
Zaidhaan
9589bbae3a
fix(a11y): add aria labels to bottom navigation links (#1867) 2023-03-08 14:07:02 +01:00
Emanuel Pina
ecd17c6709
fix(i18n): Update portuguese from Portugal translation (#1868) 2023-03-08 14:04:04 +01:00
patak
0f477236ac fix: remove extra top margin from notifications 2023-03-07 21:43:23 +01:00
patak
82d6b2ad29 fix: avoid single metadata icon on last line 2023-03-07 21:02:00 +01:00
Hartmut
c4d8137186
feat: basic keyboard shortcuts (#319) 2023-03-07 20:32:21 +01:00
Zaidhaan
69c1bd8b6a
fix: wrap non-sensitive spoilers in spoiler status (#1864) 2023-03-07 19:41:00 +01:00
Zaidhaan
bc09a28af6
fix: render replies to fill the screen height (#1859) 2023-03-06 19:58:22 +01:00
Zaidhaan
cb0b7b58bb
fix: disallow media description exceeding limits (#1854) 2023-03-06 14:12:31 +01:00
Nicolò Ribaudo
8fd697126b
feat: add metadata icon for Matrix (#1860) 2023-03-06 13:45:14 +01:00
Daryl White
b72809c048
docs: Add content for feature page (#1853) 2023-03-05 09:51:13 +00:00
TAKAHASHI Shuuji
73a8e4f545
feat(i18n): update Japanese localization (#1850) 2023-03-04 14:35:37 +01:00
Zaidhaan
cd6d328266
fix: only use username part of mention (#1843) 2023-03-02 21:07:28 +01:00
Zaidhaan
dbfb450e23
fix: allow parsing codeblocks with multiple text nodes in children (#1842) 2023-03-02 15:27:32 +01:00
Jorge Caballero
f3ad179c69
docs: Add elk.fedified.com to ecosystem list (#1837) 2023-03-01 08:18:13 +01:00
Falko Zurell
4d88c79019
fix: extended docker-compose.yml to addres Bug #1696 (#1701) 2023-03-01 08:17:34 +01:00
Glaydus
b7ebf31bd9
feat(i18n): include missing Polish translations (#1820) 2023-02-28 23:12:14 +01:00
Basil
1445a57d8d
feat: copy content warning when replying (#1672) 2023-02-28 23:10:04 +01:00
Nathan Knowler
ddb765c4a2
fix(ui): make nav links unselectable on mobile (#1691) 2023-02-28 23:01:31 +01:00
Zaidhaan
32eaee82e2
fix: resize large images attachments on upload (#1824) 2023-02-28 22:58:19 +01:00
Zaidhaan
2842a5f383
fix: avoid bar width division by zero (#1826) 2023-02-28 22:44:15 +01:00
Carles Barreda
a5cece7b42
feat(i18n): Remove outdated keys for catala and valencia (#1827) 2023-02-28 22:42:55 +01:00
Joaquín Sánchez
baba3faa34
feat(i18n): ca-valencia language detection in Edge browser (#1828) 2023-02-28 22:36:05 +01:00
Jan van den Berg
2ccec5e09c
fix(i18n): Update nl-NL.json (#1229)
Co-authored-by: Joran Quinten <joran@joranquinten.nl>
2023-02-25 22:27:21 +01:00
Carles Barreda
1356f86b54
feat(i18n): add catalan and valencian translations (#1823) 2023-02-25 22:24:03 +01:00
gummipunkt
5259f6940f
fix(i18n): update de-DE locale (#1575)
Co-authored-by: gummipunkt <patti2012@gmail.com>
Co-authored-by: Shinigami <chrissi92@hotmail.de>
2023-02-25 14:24:52 +01:00
Valtteri Laitinen
5edf713bcc
fix(i18n): use American spelling (#1751) 2023-02-25 12:10:53 +01:00
Roni Laukkarinen
981d777682
fix: Custom-emoji size on editor revisited (#1799) 2023-02-25 12:10:03 +01:00
Xabi
9e455499b9
fix(i18n): update Basque localisation (#1807) 2023-02-25 12:09:41 +01:00
Joaquín Sánchez
3596d8bec3
fix: handle frozen state (#1792) 2023-02-25 12:09:24 +01:00
Zaidhaan
d810b2de3a
fix: do not overwrite status drafts (#1822) 2023-02-24 23:34:17 +01:00
Zaidhaan
8c783204d3
fix: display correct percentages for multiple choice polls (#1821) 2023-02-24 21:39:45 +01:00
Cristiano Verondini
958f5967b9
fix: unswap uid/gid in dockerfile (#1810) 2023-02-23 05:27:50 -08:00
三咲智子 Kevin Deng
bcf0965795
refactor: get short commit 2023-02-23 19:17:28 +08:00
Zaidhaan
f98c667613
fix: properly parse bolded italics (#1808) 2023-02-23 08:13:39 +01:00
patak
29b37e67c7
docs: fix typos in readme (#1805) 2023-02-20 15:42:25 +01:00
Emanuel Pina
015d8a944e
fix(i18n): update portuguese from Portugal translation (#1788) 2023-02-20 07:06:01 +01:00
Joaquín Sánchez
41175b02ca
feat(i18n): include missing Spanish translations (#1785) 2023-02-18 17:07:48 +01:00
Xabi
75ca138c6e
feat(i18n): add Euskara/Basque localisation (#1779) 2023-02-18 16:40:28 +01:00
Joaquín Sánchez
aeba239964
fix: installing deps on main error (#1790) 2023-02-18 13:44:28 +01:00
Joaquín Sánchez
fb01c467cb
docs(pwa): typo in Other browsers on iOS entry (#1783) 2023-02-18 13:01:17 +01:00
Michel EDIGHOFFER
6b649df218
chore(i18n): en as source language (#1597) 2023-02-18 12:21:09 +01:00
Anthony Fu
2a06cf26d8 chore: upgrade nuxt devtools 2023-02-18 10:57:09 +01:00
TAKAHASHI Shuuji
3ad0abce3b
feat(i18n): update Japanese localization (#1775)
Co-authored-by: kazuya kawaguchi <kawakazu80@gmail.com>
2023-02-18 08:31:14 +01:00
Kingsley Yung
1be6a8c6ec
fix: update masto.js to 5.9.2 (#1786) 2023-02-18 08:30:24 +01:00
Horváth Bálint
ff070ea9da
fix: better loading handling on status page (#1729)
Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>
2023-02-17 23:11:35 +01:00
Daryl White
76efc724eb
docs: Readme.md for docs and guide/index additions (#1773) 2023-02-17 17:32:45 +01:00
三咲智子 Kevin Deng
b7e565dedc
refactor: specific package manager for stale-dep 2023-02-17 15:30:23 +01:00
三咲智子 Kevin Deng
acf719775f
refactor: upgrade stale-dep 2023-02-17 15:17:47 +01:00
Santiago García Pimentel
1003a2a898
fix: Spanish translation for request to follow is incorrect (#1766) 2023-02-17 12:19:01 +01:00
Joaquín Sánchez
6f96c732f7
feat(pwa): add FAQ to PWA docs and link on push subscription error (#1767)
Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>
2023-02-17 12:11:19 +01:00
Emanuel Pina
aa8f8ddd79
fix(i18n): update portuguese from Portugal translation (#1768) 2023-02-17 12:10:10 +01:00
Michel EDIGHOFFER
4cc213c5b1
feat: french translations (#1771) 2023-02-17 11:41:35 +01:00
Alex
3ff39fb79f
feat(i18n): sync zh-CN translations (#1741)
Co-authored-by: Chris <1633711653@qq.com>
2023-02-17 11:06:04 +01:00
Horváth Bálint
b1dbd22cd4
docs: docs/pwa improvements (#1762)
Co-authored-by: Joaquín Sánchez <userquin@gmail.com>
2023-02-16 14:18:34 +01:00
Daniel Roe
436489461c
refactor: inject pwa client plugin from module (#1758) 2023-02-16 10:23:26 +01:00
yheuhtozr
523578ba7b
fix(ui): unintentionally hardcoded word order of status.replying_to (#1744) 2023-02-15 20:21:08 +01:00
Chee Aun
769b84867a
fix: limit pinch scale to minimum 0.5 (#1740) 2023-02-15 20:20:10 +01:00
Emanuel Pina
33a53de8d7
fix(i18n): update portuguese from Portugal translation (#1754) 2023-02-15 20:18:28 +01:00
Joaquín Sánchez
24eb181d6d
docs(i18n): include translation status in contributing guide (#1734)
Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>
2023-02-15 20:17:48 +01:00
Cesar Gomez
0fdbb17591
feat(i18n): Emojimart localization and fetching entry at en … (#1731)
Co-authored-by: userquin <userquin@gmail.com>
2023-02-15 20:15:11 +01:00
Joaquín Sánchez
3118ed6012
docs: add PWA cookbook (#1747)
Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>
2023-02-15 13:07:30 +01:00
Tuur Martens
fbe1463f17
feat: data saving mode (#1638) 2023-02-15 10:34:23 +00:00
Tuur Martens
52fbb70a08
fix(MainContent): disallow markdown usage in username (#1618) 2023-02-15 11:21:33 +01:00
baptiste0928
f73019c1fd
fix: return redirect for whatsapp user agent (#1753) 2023-02-15 02:13:43 -08:00
Michel EDIGHOFFER
ef680ab8b3
fix: remove alone vertical bar on start (#1687) 2023-02-14 14:42:53 +00:00
Joaquín Sánchez
1153421915
fix: prepare translations status on codeflow fails (#1749) 2023-02-14 13:59:21 +00:00
moshyfawn
f091e06d19
fix: remove bot icon auto focus (#1708) 2023-02-13 22:51:45 +01:00
Chris
271c78fdbb
fix(ui): fix button width shrinked (#1742) 2023-02-13 20:21:45 +01:00
Benben Weng
379f56795d
feat(i18n): add zh-TW translation (#1628)
Co-authored-by: Alex Liu <39984251+Mini-ghost@users.noreply.github.com>
2023-02-13 20:08:07 +01:00
patak
635d55befb
chore: add code of conduct (#1743) 2023-02-13 02:11:06 -08:00
Emanuel Pina
171963ae25
fix(i18n): update portuguese from Portugal translation (#1732) 2023-02-12 21:47:09 +01:00
patak
a3cc2cecfd chore: release v0.7.4 2023-02-12 20:27:57 +01:00
Glaydus
f295ddbcd2
feat(i18n): add missing Polish (and English) translation entries (#1669) 2023-02-12 17:59:07 +01:00
Joaquín Sánchez
da7cc78a7e
fix: revert #1699 (#1730) 2023-02-12 16:15:29 +01:00
Daniel Roe
54f020b165 fix: use nitro publicAssets to emit manifests 2023-02-12 15:49:20 +01:00
Daniel Roe
37036b4ca6
fix: add badge to bottom bar notifications icon (#1722) 2023-02-12 15:39:05 +01:00
ghose
059c1c7b33
feat(i18n): update gl-ES (#1720)
Co-authored-by: Joaquín Sánchez <userquin@gmail.com>
2023-02-12 14:27:55 +01:00
Emanuel Pina
90c98857ce
fix(i18n): update portuguese from Portugal translation (#1655) 2023-02-12 14:26:28 +01:00
Daniel Roe
788819ac97 chore: release v0.7.3 2023-02-12 13:22:36 +01:00
Daniel Roe
898a43b783 fix: update import for tauri 2023-02-12 13:21:57 +01:00
Daniel Roe
d7a95eab3b fix: use callback url with route param rather than query 2023-02-12 13:18:07 +01:00
Joaquín Sánchez
c6f0432d8d
fix(i18n): better login description for single instance server (#1727) 2023-02-12 04:10:14 -08:00
Daniel Roe
79d43515f5
chore: upgrade docs to nuxt 3.2.0 as well (#1728) 2023-02-12 04:09:55 -08:00
Daniel Roe
148fd63c24 refactor: move back to cf unstorage driver 2023-02-12 12:57:56 +01:00
Daniel Roe
efaeb67261
chore: upgrade to nuxt v3.2.0 (#1695) 2023-02-12 03:56:29 -08:00
Daniel Roe
73dc060578 fix: access headers outside of computed 2023-02-12 12:48:58 +01:00
Joaquín Sánchez
b9c2bc5c70
fix(pwa): configure sw and web manifest cache control headers (#1724) 2023-02-12 12:08:50 +01:00
Daniel Roe
c2ffdcf78b fix: only generate sourcemap in development 2023-02-12 11:22:43 +01:00
moshyfawn
a9427e2ea0
fix: default main content dir to ltr (#1710)
Co-authored-by: moshyfawn <oleg.butorov.98@gmail.com>
2023-02-11 21:43:21 +01:00
Joaquín Sánchez
c5fe184281
feat: add translation status to language settings (#1717) 2023-02-11 21:42:55 +01:00
Peter Budai
3e648f6fbc
feat(editor): Respect default privacy setting of the account (#1699) 2023-02-11 18:04:41 +01:00
三咲智子 Kevin Deng
db2892c4c0
refactor: disable reactivity transform from vue core
use the feature from vue macros instead
2023-02-11 17:51:14 +01:00
Joaquín Sánchez
972a13499f
feat(docs): add translation status (#1689)
Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>
2023-02-11 17:15:08 +01:00
TAKAHASHI Shuuji
0eefcfa281
feat(i18n): update Japanese localization (#1697)
Co-authored-by: kazuya kawaguchi <kawakazu80@gmail.com>
2023-02-10 07:50:37 -08:00
Michel EDIGHOFFER
328fd1bf70
fix: add margin on top of search width to make the border visible (#1700) 2023-02-10 10:53:05 +01:00
TAKAHASHI Shuuji
943b5f151d
fix(i18n): tiny fix on "Github" (#1698) 2023-02-10 10:50:39 +01:00
Daniel Roe
9578ed1e5d
fix: revert upgrade to nuxt v3.2.0 (#1692) 2023-02-09 15:32:30 -08:00
Daniel Roe
44c3dd762e
chore: upgrade to nuxt v3.2.0 (#1684) 2023-02-09 09:47:59 -08:00
三咲智子 Kevin Deng
4400818a31
fix: upgrade nuxt schema 2023-02-09 18:24:49 +01:00
Anthony Fu
11eaeeebbe feat: enable devtools 2023-02-09 17:03:18 +01:00
Daniel Roe
acd7010fbc test: disable stale-dep in test mode 2023-02-09 13:01:22 +01:00
Daniel Roe
f04b09a40d
refactor: use server auto-imports (#1675) 2023-02-08 12:00:43 -08:00
Daniel Roe
7da49afde5 refactor: use route rules for prerendering 2023-02-08 18:12:51 +01:00
Daniel Roe
c25715b26d
feat: allow using elk as a nuxt layer (#1665) 2023-02-08 01:51:16 -08:00
Milos Dimitrijevic
a3310b6ea2
chore: add .nvmrc to ensure node v18 (#1579) 2023-02-08 10:23:07 +01:00
三咲智子 Kevin Deng
11d179b13b
refactor: upgrade vue macros 2023-02-08 10:20:58 +01:00
Alexander Harding
36191c500f
fix: prevent videos from clipping when in fullscreen mode (#1397)
Co-authored-by: Tomasz Rymkiewicz <kreha1@pm.me>
2023-02-07 06:32:37 -08:00
Daniel Roe
2128d11238
refactor: move single instance config to runtime (#1664) 2023-02-07 04:10:43 -08:00
Peter Budai
9e09c9072f
fix(ui): Prevent word-wrap on "Replying To" (#1663) 2023-02-07 09:12:30 +01:00
Chris-Robin Ennen
f1087fd270
fix: only count 23 characters per link when composing (#1660) 2023-02-06 15:03:16 -08:00
Joaquín Sánchez
65bbc7c790
fix: close databases on page freeze event without pwa (#1662) 2023-02-06 15:01:30 -08:00
Joaquín Sánchez
32cfe6371f
fix: handle frozen page lifecycle state (#1658) 2023-02-06 14:22:56 -08:00
Joaquín Sánchez
f7a8d471a6
fix: sign-out and empty content (#1654) 2023-02-06 04:16:24 -08:00
Daniel Roe
6e7ac24821
fix: work around hotfix cloudflare kv storage bug (#1650) 2023-02-06 11:03:52 +01:00
Daniel Roe
6dc38c7d8e
perf: tree-shake dependencies from server (#1647) 2023-02-06 10:34:50 +01:00
renovate[bot]
357dff2140
chore(deps): update dependency typescript to ^4.9.5 (#1648)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-05 16:55:11 -08:00
renovate[bot]
4ff2dce87f
chore(deps): update dependency vitest to ^0.28.4 (#1649)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-05 16:47:21 -08:00
Daniel Roe
e31fc4087c fix: transpile masto 2023-02-05 17:44:37 +00:00
Alex Liu
2bd8dc2dd5
fix: character count should includes spoiler text (#1535)
* fix: character count should includes spoiler text

* fix: draft empty conditions exclude spoiler text
2023-02-05 09:36:33 -08:00
Joaquín Sánchez
04c4ff5225
feat(i18n): add missing spanish translation entries (#1635) 2023-02-05 17:11:30 +01:00
victordelva
b7a3e93097
feat: add bold and italic buttons to editor (#1469) 2023-02-05 16:11:09 +00:00
Michel EDIGHOFFER
7380e243c4
fix: make nav title sticky + add more grabbale area for native (#1602) 2023-02-05 16:35:21 +01:00
Niklas Wolf
76bad723ab
feat: prioritize user languages in language picker (#1614) 2023-02-05 07:14:26 -08:00
Kingsley Yung
297b104e1c
fix: repeated content on reblog without comment (re-open) (#1627) 2023-02-05 07:12:49 -08:00
Ayo Ayco
0fbe34c1e8
fix: filter and cw logic (#1633) 2023-02-05 07:05:42 -08:00
Tuur Martens
a1b2da3d5e
feat: adjust hide username emojis pref to only hide in timeline (#1631) 2023-02-05 14:00:25 +01:00
Daniel Roe
7dfe91bb9d docs: mention SINGLE_INSTANCE_SERVER 2023-02-05 12:16:07 +00:00
Joaquín Sánchez
53d0812efd
feat: allow running elk with a single server (#1606) 2023-02-05 04:10:19 -08:00
Niklas Wolf
61428cd9cd
fix: reply language defaults to status language (#1611) 2023-02-05 13:08:01 +01:00
Tuur Martens
d204b6b1fd
chore: remove dead gesture code (#1632) 2023-02-05 09:46:23 +01:00
Evan Boehs
5f2b5a584a
feat: introduce "request to follow" closes #1076 (#1615)
closes https://github.com/elk-zone/elk/issues/1076
closes https://github.com/elk-zone/elk/pull/1411
2023-02-04 22:26:37 +01:00
Emanuel Pina
8d9c043b7a
fix(i18n): Update portuguese from Portugal translation (#1624) 2023-02-04 20:40:47 +01:00
Joaquín Sánchez
0cc4c41315
feat(pwa): add more errors and elk repo link in push notifications subscription errors (#1610) 2023-02-04 19:43:24 +01:00
Tuur Martens
2cf8f591e8
feat: image pinch to zoom (#1620) 2023-02-04 19:05:55 +01:00
Tuur Martens
e92d1c6adf
feat: add preference to hide emojis in usernames (#1612) 2023-02-04 18:02:05 +01:00
Evan Boehs
0258894484 feat: organize preferences 2023-02-03 22:17:44 +01:00
Evan Boehs
4a74b16d24 feat: option to hide alt indicator closes #1410 2023-02-03 22:17:44 +01:00
Evan Boehs
87496e01af fix: remove saturation for links fixes #1528 2023-02-03 22:17:44 +01:00
Evan Boehs
97964ede5c feat: add outline to verified links closes #155 2023-02-03 22:17:44 +01:00
patak
34949e063e chore: release v0.7.2 2023-02-03 21:53:58 +01:00
Michel EDIGHOFFER
347b9ef43d
fix: hide side nav in zen mode (#1608) 2023-02-03 21:52:43 +01:00
patak
3f5f0d11fc chore: release v0.7.1 2023-02-03 18:10:17 +01:00
Joaquín Sánchez
6784f3a090
fix: undo changes on push notifications settings stops working (#1599) 2023-02-03 17:01:43 +01:00
JP
eb5748ac65
feat(i18n): update Arabic localization (#1493) 2023-02-03 15:27:05 +01:00
Emanuel Pina
95233b30d0
fix(i18n): Update portuguese from Portugal translation (#1520) 2023-02-03 15:26:42 +01:00
Michel EDIGHOFFER
832e15bf68
chore: add missing french translation + adding changes from KaKi87 (#1564)
Co-authored-by: KaKi87 <KaKi87@pm.me>
2023-02-03 14:25:04 +00:00
Tuur Martens
a8e7fd52a9
fix(Tiptap): don't consume key events if no items (#1594) 2023-02-03 15:21:29 +01:00
Horváth Bálint
faa96c7705
fix: Web Share Target text field merge (#1572)
Co-authored-by: userquin <userquin@gmail.com>
2023-02-03 15:20:32 +01:00
Michel EDIGHOFFER
6eedaa98bc
fix: lists link on side nav (#1596) 2023-02-03 15:19:08 +01:00
patak
f8ff30d31b chore: release v0.7.0 2023-02-03 13:26:12 +01:00
Glaydus
080f4afef0
feat(i18n): Update Polish translations (#1529) 2023-02-03 13:22:06 +01:00
JD Hartley
7f1b443f65
refactor: swap out the bot account indicator icon (#1478) 2023-02-03 13:12:16 +01:00
Joaquín Sánchez
6c1ec2a252
feat(lists): add error handling (#1593) 2023-02-03 13:09:08 +01:00
TAKAHASHI Shuuji
2daaad90a1
feat(i18n): update Japanese localization (#1592)
Co-authored-by: kazuya kawaguchi <kawakazu80@gmail.com>
2023-02-03 12:05:28 +01:00
Joaquín Sánchez
4fc468539e
fix(lists): focus lost when focusing buttons (#1591) 2023-02-03 11:48:27 +01:00
Michel EDIGHOFFER
4b1b18768d
feat: use explorer page as search for mobile only (#1301) 2023-02-03 11:40:54 +01:00
Joaquín Sánchez
a2fb458696
fix(ui): add viewport header to enable/disable pinch to zoom in Safari (#1590) 2023-02-03 10:05:17 +01:00
Alex
a46ec605e1
feat(i18n): sync zh-CN (#1571)
Co-authored-by: Ayaka Rizumu <rizumu@oqo.moe>
2023-02-03 00:14:54 +01:00
Evan Boehs
073ca13d7c
fix: make buttons consistent (#1583) 2023-02-03 00:09:12 +01:00
Evan Boehs
5947323538
fix(i18n): add the in delete (#1582) 2023-02-02 22:45:30 +01:00
Evan Boehs
3b3d4906be
feat(i18n): locales for alt text (#1580) 2023-02-02 22:42:21 +01:00
Joaquín Sánchez
fc706f9050
fix: list should be user-only (#1581) 2023-02-02 21:35:18 +00:00
Evan Boehs
e58d09b6cc
feat: finish list CRUD (#1532)
Co-authored-by: userquin <userquin@gmail.com>
closes https://github.com/elk-zone/elk/issues/372
2023-02-02 22:02:39 +01:00
Vasily Kuzin
809d4a6eb3
fix(i18n): update RU locale (#1514) 2023-02-02 12:11:36 +01:00
Svyatoslav Kryukov
cf76ba3114
fix: missed language code fallback (#1559) 2023-02-02 11:36:35 +01:00
Svyatoslav Kryukov
a025b3b434
fix: update GitHub card paths lookup (#1563) 2023-02-01 20:14:23 +01:00
Svyatoslav Kryukov
a287284664
fix: update stackblitz card to a new format (#1562) 2023-02-01 19:01:38 +01:00
Cesar Gomez
b41b9353b8
feat(i18n): es-419 cv translation support and separating some base strings for idiomatic context (#1505) 2023-02-01 18:01:14 +01:00
Joaquín Sánchez
4c054a37fd
feat: add opt-in pinch to zoom setting (#1557) 2023-02-01 15:43:27 +01:00
Shlee
22fea9d53a
docs: add elk.aus.social to the ecosystem (#1555) 2023-02-01 04:36:15 -08:00
WhiskeyOmega
2481071b2b
docs: add new elk instances (#1553) 2023-02-01 04:19:15 -08:00
Raistlingru
94f3a2c6fb
docs: add hostux.social to community instances (#1511)
* docs: add hostux.social to community instances

* Update README.md

---------

Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-31 11:19:31 -08:00
chouchoui
9190aeccdf
fix: viewport meta value for iOS PWA safe area (#1533) 2023-01-31 11:14:58 -08:00
Cyril Lambin
611b6bece7
fix: French translation revision (#1434) 2023-01-31 10:49:46 +01:00
Roni Laukkarinen
d39e23ebff
fix: Custom-emoji size on editor (#1503) 2023-01-31 04:46:21 +01:00
Chris
54f3695f50
fix(ui): statusCard style in RTL (#1499) 2023-01-31 04:44:55 +01:00
Clark Cui
e18fe70f80
fix: account setting button hover style (#1525) 2023-01-31 04:43:12 +01:00
Alex Liu
bd77d467c3
feat: refetch home page when click elk logo (#1129) 2023-01-31 04:42:46 +01:00
Cully Fung
b62fd01057
chore: update zh-cn locales (#1497) 2023-01-31 04:39:06 +01:00
Anthony Fu
04404e0c0b
chore: upgrade to Nuxt 3.1 (#1455)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-31 04:07:17 +01:00
Joaquín Sánchez
80a4ec502e
fix(a11y): allow pinch to zoom (#1515) 2023-01-30 05:32:27 -08:00
Anthony Fu
9c3a3de41d fix: initial default value in PublishWidget 2023-01-30 12:23:49 +01:00
Anthony Fu
e277832b61 fix: avoid reference context in getDefaultDraft 2023-01-30 12:20:22 +01:00
Anthony Fu
2a4862fb42 feat(ui): display post language 2023-01-30 12:09:04 +01:00
Anthony Fu
8d792d003d refactor: make auto import more explicit 2023-01-30 11:58:58 +01:00
Anthony Fu
fbdaf8bbef chore: cleanup 2023-01-30 10:36:39 +01:00
renovate[bot]
a29f52ee1a
chore(deps): update dependency vitest to ^0.28.3 (#1523)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-29 16:20:47 -08:00
Stanislas
72bf6fb6f0
fix: handle account switching when accounts have the same id (#1510) 2023-01-29 07:58:32 -08:00
Daniel Roe
fa44fae991
perf!: allow tree-shaking unstorage drivers (#1516)
* perf: allow tree-shaking unstorage drivers

* fix: allow overriding fsBase at runtime

* fix: remove `fsBase` export
2023-01-29 07:52:01 -08:00
Daniel Roe
415d36ce32
refactor: move pwa/build-info -> appConfig (#1508) 2023-01-29 06:18:27 -08:00
Anthony Fu
1c9004a731 chore: update lock 2023-01-29 14:25:44 +01:00
Anthony Fu
6dbf7ae74f chore: migrate to nuxt-vitest 2023-01-29 14:20:48 +01:00
Niklas Wolf
b48b7f4c16
feat: allow disabling translation for specific languages (#1371) 2023-01-29 04:18:49 -08:00
TAKAHASHI Shuuji
e197a1dbe9
fix: use "⌘" as modifier key name on macOS (#1506)
* fix: use 'Command' as modifier key name on macOS

* fix: use more reliable `useIsMac()` instead of `userAgentData`

* refactor: apply suggestion from @userquin

* fix: use `⌘` as Command key symbol
2023-01-28 23:41:42 -08:00
John HU
fda85e31bc
fix: disable user-select on StatusActionButton component (#1281) 2023-01-28 14:17:26 -08:00
John HU
7d127d397a
fix: correct federated timeline title icon (#1340) 2023-01-28 14:16:16 -08:00
sechi
8c76dad3c0
fix: prevent click event when publish button is disabled (#1481) 2023-01-28 14:00:20 -08:00
Roni Laukkarinen
ca65f7379e
fix(a11y): do not prevent arbitrary zooming on mobile devices (#1501) 2023-01-28 13:56:00 -08:00
Cesar Gomez
4f23bebf2e
feat(i18n): sync base es (#1496)
* feat(i18n): es-ES sync

* fix: improving confirmation dialogs entries

* fix: improving grayscale mode entry

* fix: hashtag entry translated
2023-01-28 09:32:44 -08:00
TAKAHASHI Shuuji
2ce7c462ae
feat(i18n): update Japanese localization (#1418) 2023-01-28 07:11:30 -08:00
Alex Liu
bdcb8f46fd
chore: adjust zh-TW translation wording (#1430) 2023-01-28 12:54:33 +01:00
Emanuel Pina
664c0a2ab7
fix(i18n): Update portuguese from Portugal translation (#1476) 2023-01-27 23:31:33 +01:00
Glaydus
1924ec8d07
fix(i18n): updated Polish translation (#1490)
Co-authored-by: Karol Krenski <kkrenski@gmail.com>
2023-01-27 23:27:40 +01:00
Osma Ahvenlampi
3e365fc30a
fix: updated Finnish localization with some errors fixed (#1489) 2023-01-27 16:56:16 +01:00
Evan Boehs
e393049f04
feat: more list support (#1479) 2023-01-27 16:15:46 +01:00
Osma Ahvenlampi
9d353fa07b
feat(i18n): revised Finnish localization (#1487) 2023-01-27 13:32:20 +01:00
Joaquín Sánchez
a15fd7b2ca
chore(i18n): update i18n module and en-US file (#1485) 2023-01-27 12:12:57 +01:00
ghose
068daf7a77
fix: update gl-ES (#1482) 2023-01-27 10:28:38 +01:00
Daniel Roe
541a1f93bc
feat: add privacy policy (#1484) 2023-01-27 09:45:23 +01:00
Evan Boehs
3904bc4d2d
feat: initial support for lists (#1474) 2023-01-26 22:41:28 +01:00
Joaquín Sánchez
901463301c
feat(pwa): don't show install widget if cancelled from widget (#1459) 2023-01-26 21:30:39 +01:00
Evan Boehs
d26510a766
feat: hide reply count (#1439)
* feat: hide reply count

* fix(i18n): rearrange strings

* style: new line
2023-01-26 13:41:43 +01:00
Anthony Fu
75c4fa54d7 chore: unstable test ci 2023-01-26 12:46:13 +01:00
Emanuel Pina
5eac588d6d
fix(i18n): Update portuguese from Portugal translation (#1447) 2023-01-25 21:30:04 +01:00
Joaquín Sánchez
050092b87a
fix(pwa): add maskable icon to web manifest (#1456) 2023-01-25 21:16:32 +01:00
三咲智子 Kevin Deng
bc78b50ee0
fix: upgrade vue macros 2023-01-26 00:53:26 +08:00
Joaquín Sánchez
d5653076f9
chore(pwa): reduce pwa prompts image opacity (#1452) 2023-01-25 17:06:16 +01:00
victordelva
adb17d7f14
fix: default user language when writing a publication (#1446) 2023-01-25 16:41:09 +01:00
Sakana
255c341a78
feat(i18n): add some Chinese translation (#1386) 2023-01-25 23:33:59 +08:00
Joaquín Sánchez
eda218de0b
fix(pwa): use 303 redirect in web share target api (#1448) 2023-01-25 16:32:52 +01:00
Joaquín Sánchez
f96cdae1ba
feat(pwa): add install PWA widget (#1451) 2023-01-25 16:26:51 +01:00
Joaquín Sánchez
3c888d3914
fix: unescape html entities in page title (#1392) 2023-01-25 05:12:55 -08:00
ghose
18af058e4d
feat(i18n): galician language contribution (#1417) 2023-01-25 06:50:20 +01:00
Alex Liu
1d1f4bccca
fix: make the user switcher's buttons fill container (#1437) 2023-01-25 06:49:31 +01:00
Joaquín Sánchez
0e021e4388
chore(i18n): initialize spanish properly (detect es-419) (#1428) 2023-01-24 23:35:26 +01:00
Shinigami
5527468258
fix: tag if condition (#1432) 2023-01-24 21:57:24 +00:00
wheat
46a8472001
feat(preferences): option to hide account hover card (#1431) 2023-01-24 21:46:33 +01:00
三咲智子 Kevin Deng
4e97c31caf
fix: back to rollup 2 2023-01-25 03:06:00 +08:00
三咲智子 Kevin Deng
3c59263f21
fix: pin vitest version 2023-01-25 03:02:20 +08:00
三咲智子 Kevin Deng
7545921385
fix: upgrade & downupgrade deps 2023-01-25 02:52:48 +08:00
三咲智子 Kevin Deng
d7bba4dbc9
fix: keep patches folder 2023-01-25 01:59:56 +08:00
Jay
84f45809ea
fix(i18n): Update zh-TW translations (#1429) 2023-01-25 01:58:34 +08:00
三咲智子 Kevin Deng
727cc5d495
chore: upgrade deps 2023-01-25 01:56:18 +08:00
Joaquín Sánchez
82694b87b6
chore(i18n): move country variants to avoid changing contributing guide (#1403) 2023-01-24 15:42:57 +01:00
Daniel Roe
8b34b8b6e6 chore: release v0.6.2 2023-01-24 14:18:23 +00:00
Glaydus
73ee6a0c2c
fix(i18n): Update pl-PL translation (#1384)
Co-authored-by: Karol Krenski <kkrenski@gmail.com>
2023-01-24 12:44:26 +01:00
Svyatoslav Kryukov
897ec00498
feat(i18n): refine Russian locale (#1412) 2023-01-24 09:27:13 +01:00
bytedefined
f1a3c8873c
feat(i18n): support for Russian locale (Russian Federation variant) (#1169) 2023-01-23 23:29:48 +01:00
Alex Liu
065d8a1c2d
feat: improve github status preview ui (#1407) 2023-01-23 23:22:26 +01:00
patak
66c9212a6f
feat: improve follows you grouping (#1408) 2023-01-23 21:49:00 +01:00
Emanuel Pina
dc23784c00
fix(i18n): Update and fix a typo on portuguese from Portugal translation (#1398) 2023-01-23 20:34:03 +01:00
Ayo Ayco
a08f56676d
feat: totally hide strict filters (#948) 2023-01-23 20:33:21 +01:00
Shinigami
1a7ae6f0ef
feat: follow tags from trends page (#1391) 2023-01-23 16:36:28 +00:00
luísbatista
677d6188b4
fix(i18n): typos corrections to the portuguese (pt-PT) translation. (#1347) 2023-01-23 16:35:42 +01:00
Joaquín Sánchez
804f66f203
feat(i18n): add country variants support (#1370) 2023-01-23 16:34:31 +01:00
renovate[bot]
9d94a09319
chore(deps): update dependency vitest to ^0.28.1 (#1400) 2023-01-23 13:51:01 +01:00
Rajat Dwivedi
8b72e178d8
fix: #1348 Fixed the follow button movement UI (#1383)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-01-23 12:05:46 +01:00
patak
2a836eda3d fix: revert default layout styles 2023-01-22 22:34:48 +01:00
Horváth Bálint
f504f778da
fix: css bg color typo in top bar on mobile (#1395) 2023-01-22 21:20:25 +01:00
patak
1a577343da
feat: range of font size (#1376) 2023-01-22 20:18:03 +00:00
Joaquín Sánchez
85be61a316
fix: settings navigation (#1389) 2023-01-22 19:53:04 +00:00
Shinigami
c28c95e36c
fix: tag link (#1390) 2023-01-22 20:21:34 +01:00
KS Edouard Song
edba79f6db
fix: remove whitespace wrapping on status aside (#1393) 2023-01-22 18:15:20 +00:00
Piotrek Tomczewski
45431ef504
fix: rendering of high emoji (#1352)
fix: #1350
2023-01-22 14:41:56 +01:00
Glaydus
844fb26d27
feat(i18n): added Polish translations (#1339)
Co-authored-by: Karol Krenski <kkrenski@gmail.com>
2023-01-22 12:13:33 +01:00
Ayaka Rizumu
29e5d6ddf7
fix: issue 1366 (#1382) 2023-01-22 10:57:30 +01:00
Arc_G
c35f8fdd33
fix: #1348 Improved the close button UI (#1381) 2023-01-22 08:47:49 +01:00
Daniel Roe
31d9308043
feat: add finnish locale (#1379)
Co-authored-by: Martin Vermeer
2023-01-22 08:19:16 +01:00
emilweth
331f517d75
feat(docker): run as non root user (#1380) 2023-01-22 08:18:50 +01:00
Daniel Roe
745e57fbe1 chore: set github token permissions 2023-01-21 22:51:18 +00:00
emilweth
c1b5f4361b
feat: add docker build & push to ghcr action (#1377) 2023-01-21 23:41:17 +01:00
patak
329c0fca8d style: use same color for logo and app name 2023-01-21 22:47:53 +01:00
patak
8f4ce68b97 fix: connecting line for xl font size 2023-01-21 22:21:49 +01:00
Michel EDIGHOFFER
db1d91a5e4
style: colorize antlers only (#1331) 2023-01-21 16:39:30 +01:00
Piotrek Tomczewski
1cf123b62b
feat(native): Improved layout in elk-native (#1359) 2023-01-21 15:55:20 +01:00
TAKAHASHI Shuuji
adbe31d523
feat(i18n): Update Japanese localization (#1294)
* feat(i18n): Update Japanese localization

* feat(i18n): apply feedback
2023-01-21 11:46:07 +00:00
dilinger
be5d32cb4a
fix: make attachement removal button static & more visible #1067 (#1286)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-01-21 10:52:36 +00:00
Niklas Wolf
801b8fe027
feat: add user preference to hide translation button (#1358) 2023-01-21 11:19:03 +01:00
Piotrek Tomczewski
5d94eabff6
feat: Use Twemoji in emoji picker (#1351) 2023-01-20 20:26:18 +01:00
patak
55e8c6b6f7
chore: bug report labels 2023-01-20 00:07:33 +01:00
patak
855f71ac22 chore: fix issue templates 2023-01-20 00:01:45 +01:00
patak
25dad31461 chore: avoid issues forms for now 2023-01-19 23:51:15 +01:00
Emanuel Pina
2667899b14
fix(i18n): Update portuguese from Portugal translation (#1334) 2023-01-19 23:39:28 +01:00
Michel EDIGHOFFER
e422bf9edb
feat(i18n): french translation of updater + auto play (#1330) 2023-01-19 22:15:08 +01:00
JD Hartley
86d62fd5de
fix: disable side nav item tooltip on small screen (#1327) 2023-01-19 22:14:44 +01:00
Niklas Wolf
126619be92
feat: added autoplay setting (#1303)
closes https://github.com/elk-zone/elk/issues/1235
2023-01-19 19:33:50 +01:00
Anthony Fu
33b5947170 fix: completely hide back button 2023-01-19 19:32:25 +01:00
patak
691ef029a4 chore: release v0.6.1 2023-01-19 19:09:53 +01:00
patak
d8bf96fd70
feat: normal text color for nav logo (#1321) 2023-01-19 19:08:33 +01:00
Anthony Fu
abaf4a2f54 docs: note about preview deploy 2023-01-19 19:04:59 +01:00
Alex Liu
1a074aaff6
refactor: reduce unnecessary html structures (#1319) 2023-01-19 19:00:56 +01:00
webfansplz
5465409fcb
fix: user server name getting clipped (#1308)
Closes https://github.com/elk-zone/elk/issues/1300
2023-01-20 00:34:33 +08:00
三咲智子 Kevin Deng
0f5476c190
feat(settings): support drop file on avatar&header 2023-01-20 00:33:17 +08:00
三咲智子 Kevin Deng
eb966976db
fix: remove protocol from instance uri 2023-01-20 00:20:56 +08:00
Peter Budai
c200abcc90
feat: add 'copy original link to this post' menu item (#1318) 2023-01-19 15:18:08 +00:00
TAKAHASHI Shuuji
61f2237121
feat(i18n): allow "Version" string on about page to localize (#1314) 2023-01-19 23:04:09 +08:00
patak
ae05d3bee5 chore: release v0.6.0 2023-01-19 14:10:14 +01:00
Michel EDIGHOFFER
f49d8619a1
feat(i18n): french update (#1317) 2023-01-19 14:02:11 +01:00
Michel EDIGHOFFER
644d761ee7
feat: use colorized logo (#1316) 2023-01-19 13:42:05 +01:00
patak
359cc4935b fix: leading space when hiding mentions 2023-01-19 12:12:58 +01:00
Ayaka Rizumu
fab1eb13b3
chore: update slimeform (#1312) 2023-01-19 18:50:56 +08:00
Alex Liu
c3b9f8fc2a
fix: respect the length seen (#1310) 2023-01-19 11:27:08 +01:00
webfansplz
09997c2f90
chore: preview header only when it's already set (#1311)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-19 11:26:40 +01:00
patak
a48524e7ad
feat: inline some mentions to reduce spacing (#1307) 2023-01-19 11:26:01 +01:00
Vivi
1f427e2538
docs: add guide to hosting on Netlify and CloudFlare (#1302) 2023-01-19 09:19:05 +00:00
patak
a81e8742d1 chore: remove unused snapshots 2023-01-19 01:01:48 +01:00
Rio Bahtiar
86192fad48
feat(i18n): Improvements for Indonesian translation 2023-01-18 23:50:46 +01:00
patak
5785047856 fix: properly hide redundant mentions 2023-01-18 19:23:14 +01:00
patak
3132f4fdea
feat: hide redudant mentions (#1293) 2023-01-18 16:59:37 +01:00
Anthony Fu
da2f19fb23 perf: remove unused fonts 2023-01-18 15:39:30 +01:00
webfansplz
cce467a54a
fix: arrow placement in draft dropdown (#1287) 2023-01-18 14:54:36 +01:00
baptiste0928
fb1f407016
feat(search): select first result on enter press (#1289) 2023-01-18 14:54:17 +01:00
Anthony Fu
88080573db fix: CSP for shiki 2023-01-18 14:51:44 +01:00
patak
40c0afb09d chore: fix typo 2023-01-18 08:01:50 +01:00
webfansplz
9c82df0a7a
fix: prevent default event when hide dropdown (#1277) 2023-01-18 07:07:07 +01:00
Jon McLaren
bc08ef07d3
fix: change Alt Text description pop up to wrap while preserving whitespace pre (#1130) 2023-01-17 22:56:17 +01:00
MiniNaim
dded8d929e
fix(i18n): fixing commas #1217 (#1217) 2023-01-17 22:55:12 +01:00
baptiste0928
6c1d0e7121
feat(ui): move alt text under the media preview (#863) 2023-01-17 22:54:03 +01:00
Alex
0b77ad3f43
fix: translate posts target language is not current selected language (#1263) 2023-01-17 22:41:26 +01:00
Joran Quinten
a7e1dad3d2
fix(i18n): improve several translations nl-NL (#1214) 2023-01-17 22:28:37 +01:00
MiniNaim
5b849baec7
fix(i18n): update Arabic (#1224) 2023-01-17 22:26:44 +01:00
Emanuel Pina
448b303106
fix(i18n): update pt-PT language (#1234) 2023-01-17 22:18:29 +01:00
Piotrek Tomczewski
db69a54090
fix(native): Fixed bug causing inability to enter text in search field (#1273) 2023-01-17 22:16:47 +01:00
Piotrek Tomczewski
2975a38650
fix(native): Enable window draging by the title bar (#1268) 2023-01-17 22:05:41 +01:00
Michael Stanclift
dd0333a6bb
docs: add vmst.io to community instances (#1269) 2023-01-17 18:48:15 +00:00
Alex
53b37a1cfb
feat: add docker-compose support (#1257) 2023-01-17 21:04:53 +08:00
Jeff Sikes
fd662b8864
feat: enhancements to profile account notifications (#1127) 2023-01-17 13:57:24 +01:00
Alex
85e163a0ad
feat: support showing publish failed messages (#1209) 2023-01-17 13:56:51 +01:00
rshigg
0b2b9a713b
feat: add grayscale mode to user preferences (#1177) 2023-01-17 13:55:36 +01:00
webfansplz
bb41c468bb
fix: show replying user in zen mode editor (#1250) 2023-01-17 13:50:21 +01:00
webfansplz
7aa8aeba3f
chore: add cursor pointer for input element (#1248) 2023-01-17 13:49:40 +01:00
patak
8a74e1abef fix: max lines for SB code snippets 2023-01-17 12:49:19 +01:00
Alex Liu
db9fb61134
feat(i18n): sync and update zh-TW translation (#1255)
Co-authored-by: Rock070 <a0938130702@gmail.com>
2023-01-17 19:46:50 +08:00
Svyatoslav Kryukov
08eebb651d
fix: use global regex to escape backticks (#1253) 2023-01-17 12:26:36 +01:00
patak
8d3be0f3cf feat: translation keys for SB card 2023-01-17 11:54:33 +01:00
Anthony Fu
3050350f25 fix: disable nuxt-security in dev 2023-01-17 11:51:32 +01:00
Daniel Roe
21b277ffce
perf: use server namespace to simplify kv querying (#1246) 2023-01-17 18:44:15 +08:00
Joaquín Sánchez
a91d3c1e92
perf: exclude pwa web manifests from sw precache (#1213) 2023-01-17 18:42:42 +08:00
Nya Candy
7059cfc7b4
feat: add docker support (#1052)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-17 18:37:07 +08:00
patak
8adb9f403b
feat: StackBlitz code block expansion (#1240)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-17 10:59:16 +01:00
John HU
486f1baf37
fix: make translate button visually less distracting (#1245) 2023-01-17 06:51:38 +00:00
Daniel Roe
406fe18302 fix: export highlighter function and rename in composable 2023-01-17 06:47:46 +00:00
Daniel Roe
98a4e8caaf refactor: fix typo in function name 2023-01-17 06:26:06 +00:00
webfansplz
295eb97a7a
fix(paginator): parse array in url query string correctly (#1242) 2023-01-17 05:48:26 +00:00
Daniel Roe
2587225b95 feat: add support for memory storage driver 2023-01-16 21:52:50 +00:00
Daniel Roe
80da856402 fix: handle parsing pure plain text 2023-01-16 20:41:42 +00:00
sechi
c4c15cf1c2
fix: disable selecting elements in user switcher (#1219) 2023-01-16 21:17:47 +01:00
Grégoire Paris
5354e58c2d
chore: typo (#1237) 2023-01-16 21:17:14 +01:00
Anthony Fu
1a1c0e4c5d fix: wrap theme color selector 2023-01-16 19:06:52 +01:00
Alex
f3a3a299e0
fix(ui): translation button loading style issue in light theme (#1218) 2023-01-16 19:04:51 +01:00
jviide
8c170961cb
feat: support all HTML elements allowed by Glitch (#1233)
Closes https://github.com/elk-zone/elk/issues/1230
2023-01-16 19:04:27 +01:00
Rio Bahtiar
9df47ea6c2
feat(i18n): add Indonesian translation (#1197)
Co-authored-by: Rio Bahtiar <rio.bahtiar@sekolahmu.co.id>
2023-01-17 00:44:27 +08:00
Daniel Roe
470da9a1be fix: unquote ol/li selectors 2023-01-16 12:50:39 +00:00
Anthony Fu
b759e21826 chore: improve eslint ignore 2023-01-16 13:36:32 +01:00
Anthony Fu
b049b40298
fix(editor): mention handling on post editing (#1223) 2023-01-16 12:36:22 +00:00
Anthony Fu
7389226c38 chore: more strict auto import 2023-01-16 12:42:48 +01:00
Anthony Fu
8bb6ee7639 refactor: fix auto import confliction 2023-01-16 12:40:47 +01:00
Anthony Fu
00379e23aa fix: allow wider media 2023-01-16 12:25:05 +01:00
Anthony Fu
8753a94aae
feat: theme colors (#1195) 2023-01-16 11:26:19 +01:00
Daniel Roe
2e79f3aa37 fix: use m.webtoo.ls 2023-01-16 10:25:34 +00:00
Emily Medhurst
998fa9ccb1
fix: post length should account for draft mentions (#1202) 2023-01-16 11:24:29 +01:00
patak
46bd13310a
chore: webtoo.ls as default server (#1215) 2023-01-16 10:24:14 +00:00
Anthony Fu
d21860487b chore: reduce emoji picker size 2023-01-16 11:22:49 +01:00
Yuexun Jiang
e847f8ef1d
feat(tiptap): add discord-style emoji suggestion support (#1066)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-16 11:22:26 +01:00
Daniel Roe
9898a19358
fix: fall back to votes count if voters count is not supplied (#1146) 2023-01-16 10:57:32 +01:00
Alex
d745bd0583
feat: improve posts translation logic (#1211) 2023-01-16 09:55:00 +00:00
Daniel Roe
3b73d11fd3 fix: disable nuxt-security on windows dev (pending nuxt 3.1.0) 2023-01-16 09:48:57 +00:00
TAKAHASHI Shuuji
e04972d5e2
feat(i18n): Update Japanese localization (#1158) 2023-01-16 10:35:16 +01:00
webfansplz
2d96d1358b
refactor(i18n): confirm module (#1210) 2023-01-16 09:56:36 +01:00
Anthony Fu
741eccf929
docs: note about the risk for 3rd-party deployments (#1204) 2023-01-16 09:52:58 +01:00
renovate[bot]
1cd9f61b3a
chore(deps): update dependency @iconify-json/twemoji to ^1.1.10 (#1203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-16 14:37:26 +08:00
renovate[bot]
57c820b701
chore(deps): update dependency vitest to ^0.27.1 (#1205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-16 14:36:56 +08:00
webfansplz
512d0901ce
feat: confirm before unfollow (#1208)
Closes https://github.com/elk-zone/elk/issues/35
2023-01-16 14:36:28 +08:00
webfansplz
46d350f442
docs: add contributors (#1207) 2023-01-16 06:28:57 +01:00
patak
bb2e3ab44f
fix: publish widget mentions (#1198) 2023-01-16 06:10:33 +01:00
jviide
d24c1da35e
feat: add security headers (with nuxt-security) (#1025) 2023-01-16 01:00:44 +00:00
ʀᴀʏ
7c58d89044
fix: even spacing of icons and text in navbar (#995) 2023-01-16 00:57:31 +00:00
Darius Kruythoff
95dda1fdb6
feat: have all emojis respect prefers-reduced-motion (#962) 2023-01-16 00:51:52 +00:00
Daniel Roe
97a02ef837 docs: update deployment list to add elk.h4.io 2023-01-16 00:37:48 +00:00
Byron Miller
61740ac665
docs: add universeodon.com as public client (#1017) 2023-01-16 00:36:08 +00:00
Daniel Roe
b9d998bca5
perf: improve perf on rendering long list of replies (#1201) 2023-01-16 00:33:07 +00:00
Anthony Fu
fe07c7effe i18n: shorten color mode names 2023-01-15 22:13:36 +01:00
Daniel Roe
cd8e2cb6a4
fix: initialise stream promise before stream is available (#1191) 2023-01-15 20:26:59 +00:00
webfansplz
a594f6f167
fix: should hide tooltip when click outside (#1123) 2023-01-15 19:56:13 +00:00
Shinigami
656fd4b62c
feat(i18n): de-DE update locale (#1188) 2023-01-15 20:38:51 +01:00
snail-coupe
6dd8fb3fa1
fix: Swap whitespace-pre for whitespace-pre-wrap on alt (#1193) 2023-01-15 20:28:29 +01:00
Michel EDIGHOFFER
18069356f9
fix: reply button on right on small screen (#1143) 2023-01-15 20:27:54 +01:00
Anthony Fu
3781e2f8d2
refactor: remove unused DM Sans (#1192) 2023-01-15 20:13:07 +01:00
Daniel Roe
bf25339bc9
test: add vitest-environment-nuxt (#1186) 2023-01-15 20:09:01 +01:00
webfansplz
3513f09148
feat: add unplugin-vue-inspector (#1116) 2023-01-15 23:52:50 +08:00
webfansplz
9f19e56b0f
fix: show status actions on DM (#1180)
Closes https://github.com/elk-zone/elk/issues/988
2023-01-15 23:44:28 +08:00
sechi
92b9746cd7
fix: disable selecting elements in navbar (#1147) 2023-01-15 15:42:16 +00:00
Emanuel Pina
185bfd1ee3
feat(i18n): add portuguese translation (#1107) 2023-01-15 23:19:02 +08:00
三咲智子 Kevin Deng
6b90131783
fix: i18n hydration on dev 2023-01-15 23:15:03 +08:00
三咲智子 Kevin Deng
f96a9417da
chore: lock mlly version 2023-01-15 22:55:16 +08:00
三咲智子 Kevin Deng
0cbbf914b9
chore: upgrade mlly 2023-01-15 22:48:07 +08:00
Daniel Roe
0dc0a1baa6
refactor: use internal nuxt helper (#1176) 2023-01-15 14:43:16 +00:00
Daniel Roe
5a6248a08f
fix: disallow all indexing on canary site and indexing of auth-only pages in prod (#1175) 2023-01-15 14:34:23 +00:00
Anthony Fu
5da5f9ac7d fix: show actions card details in zen mode 2023-01-15 15:20:48 +01:00
webfansplz
88c96cb304
refactor: preferences settings (#1173) 2023-01-15 22:19:22 +08:00
Daniel Roe
ccad8bf22b
fix: catch more bots with redirects (#1174) 2023-01-15 14:10:20 +00:00
Anthony Fu
18ad1c2333 fix: improve vote ui 2023-01-15 14:41:28 +01:00
三咲智子 Kevin Deng
83a1980273
fix: default language (#1171) 2023-01-15 20:23:47 +08:00
patak
b34147db4e chore: release v0.5.0 2023-01-15 11:52:02 +01:00
jviide
c15df78cbb
fix: prevent HTML injections to code blocks (#1165) 2023-01-15 10:48:22 +00:00
三咲智子 Kevin Deng
1a4fd19720
fix: ignore fetch node info error 2023-01-15 18:11:23 +08:00
rshigg
e7ccd00ad3
fix: Improve styling and add accessible text to notify button (#1138) 2023-01-15 10:00:39 +00:00
三咲智子 Kevin Deng
08293a107c
feat: add route alias for GoToSocial status 2023-01-15 17:55:58 +08:00
三咲智子 Kevin Deng
5247b36b6d
fix: account server in GoToSocial 2023-01-15 17:44:36 +08:00
三咲智子 Kevin Deng
ba5b89d5b8
feat: add delete oauth app for admin 2023-01-15 17:34:17 +08:00
三咲智子 Kevin Deng
2e7979817a
feat: support lookup account for gotosocial 2023-01-15 17:21:03 +08:00
webfansplz
20a90cc949
fix(i18n): update zh-TW translations (#1161) 2023-01-15 08:44:50 +00:00
三咲智子 Kevin Deng
4422a57f49
refactor: sync masto (#1121) 2023-01-15 16:38:02 +08:00
webfansplz
eb1f769e32
feat: add confirm for account handle (#1126) 2023-01-15 16:33:55 +08:00
webfansplz
274e182bdf
fix: make user dropdown to be fixed (#1148) 2023-01-15 09:26:43 +01:00
webfansplz
4c25a27c8d
feat(i18n): update zh-CN translations (#1155) 2023-01-15 16:17:04 +08:00
webfansplz
3353649147
chore: update pr template [skip ci] (#1160) 2023-01-15 16:15:48 +08:00
webfansplz
bfcdd02a0a
feat: add page title for compose page (#1157) 2023-01-15 08:54:54 +01:00
webfansplz
e9479da2a2
feat: add pr template [skip ci] (#1156) 2023-01-15 07:55:46 +01:00
webfansplz
399d7851e3
chore: use defineOptions instead of script (#1154) 2023-01-15 06:06:12 +00:00
2ed3373352
fix: [object Object] in page title of followers page #1151 (#1153) 2023-01-15 07:02:17 +01:00
Daniel Roe
896681d5b9 fix: remove duckduckgo from crawler list 2023-01-15 00:47:11 +00:00
Daniel Roe
d46ddbe2b4
feat: implement social previews by redirecting to origin server (#1144) 2023-01-15 00:51:12 +01:00
KaKi87
a8e1cb86f3
feat(i18n): Use "J'aime" & "Aimés" (#1133)
Co-authored-by: Michel EDIGHOFFER <edimitchel@gmail.com>
2023-01-15 00:43:25 +01:00
Daniel Roe
9a8e645e16
fix: use user id in cache key (#1139) 2023-01-14 22:56:47 +01:00
Alex Liu
5f7feac96b
fix(i18n): resolve zh-TW translation error (#1128) 2023-01-15 05:09:25 +08:00
Horváth Bálint
bede92404b
feat: add support for the Web Share Target API (#1100)
Co-authored-by: userquin <userquin@gmail.com>
2023-01-14 20:58:52 +00:00
三咲智子 Kevin Deng
a6a825e553
fix: using useSelfAccount
fix cfbb93045c
11fc2572d5
2023-01-14 21:04:44 +08:00
三咲智子 Kevin Deng
b3ff8a457d
fix: default value of zen mode 2023-01-14 20:59:00 +08:00
sechi
1cbaf68ea4
fix: hide actions panel in status detail when use zen mode (#1065) 2023-01-14 11:47:15 +01:00
Michel
72e2650702
fix: add whitespace-pre to display image ALT description (#1036) 2023-01-14 11:45:43 +01:00
Joaquín Sánchez
f227ad6e2f
chore(i18n): fix arabic on top to avoid changing contributing guide (#1088)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-01-14 11:45:12 +01:00
Anthony Fu
81e24440e7 fix(i18n): improve descriptions 2023-01-14 11:44:26 +01:00
Daniel Roe
c280ee389c
feat: support additional html elements (#1102) 2023-01-14 11:40:53 +01:00
webfansplz
10bf774a6b
chore: add cursor pointer for checkbox (#1108) 2023-01-14 11:40:14 +01:00
webfansplz
1d50616949
fix: rework tip for unavailable following/followers (#1110)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-01-14 11:39:49 +01:00
webfansplz
7e321e906a
fix: update suggestion renderer only when the editor is focused (#1115)
Closes https://github.com/elk-zone/elk/issues/898
2023-01-14 11:38:31 +01:00
Sakana
b0164deb27
fix: optimize search page bar display on mobile (#1109) 2023-01-14 11:12:35 +01:00
Alex Liu
6b9ea79a66
feat(i18n): adjust wording and sync zh-TW translations (#1112) 2023-01-14 11:11:42 +01:00
Anthony Fu
bef1371516 fix: zen mode on refresh 2023-01-14 11:09:27 +01:00
Anthony Fu
680b3493b3 pref: improve current user handle writting 2023-01-14 11:09:27 +01:00
Doğu Us
55a58f5509
feat(i18n): Add Turkish locale (#1099) 2023-01-14 17:56:46 +08:00
Anthony Fu
d2ef57bcfa perf: cache userSettings, improve #1013 2023-01-14 10:55:16 +01:00
Anthony Fu
55aff4778b refactor: use head script instead of cookie 2023-01-14 10:55:16 +01:00
Ricky de Laveaga
dcf0dd7018
trim desc_para3 open, help boosting out to boost (#1105) 2023-01-14 09:39:50 +00:00
Daniel Roe
cfbb93045c fix: revert using useSelfAccount (hotfix)
This reverts commit 11fc2572d5.
2023-01-13 20:57:47 +00:00
三咲智子 Kevin Deng
11fc2572d5
refactor: extract check self account 2023-01-14 03:01:24 +08:00
三咲智子 Kevin Deng
b6c916517c
feat: stale dep as a nuxt module 2023-01-14 02:57:31 +08:00
三咲智子 Kevin Deng
3defa7f110
fix: don't wrap color mode button 2023-01-14 02:29:12 +08:00
Sakana
53349604de
feat(i18n): complete some Chinese translations (#1094) 2023-01-14 02:28:45 +08:00
Michel EDIGHOFFER
313efddd64
fix: adjust background of account name when it's a link (#1061) 2023-01-14 02:22:08 +08:00
三咲智子 Kevin Deng
04480eef44
feat: i18n for sign page in mastodon 2023-01-14 02:10:51 +08:00
Joaquín Sánchez
88ac29ea14
fix: allow multiple accounts on same server (#1092) 2023-01-14 02:08:15 +08:00
Cesar Gomez
190caf0437
feat(i18n): Sync es-ES and 'add emojis' tooltip localized. (#1014) 2023-01-13 17:22:36 +01:00
Joaquín Sánchez
1e5b648a71
fix: remove Firefox icon border when using animate-spin (#1081) 2023-01-14 00:00:32 +08:00
webfansplz
f76628d4ab
fix: shiki fallback language (#1044) 2023-01-13 23:08:08 +08:00
Michel EDIGHOFFER
0407ef353f
fix(i18n): update french translation (#1083)
Co-authored-by: Florian LEFEBVRE <contact@florian-lefebvre.dev>
2023-01-13 23:07:10 +08:00
三咲智子 Kevin Deng
1275c41bd2
refactor(account): adjust notify button 2023-01-13 23:00:35 +08:00
Jeff Sikes
9b1ac596d3
feat: notification when followed account creates a new post (#1045)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fix https://github.com/elk-zone/elk/issues/538
2023-01-13 22:53:40 +08:00
Yuexun Jiang
341de5ffaa
fix: back button was not displayed on lg screen (#1049)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-13 22:49:52 +08:00
Joaquín Sánchez
1d151c53c4
fix: multiple push notifications susbscriptions on multiple account servers (#1069) 2023-01-13 13:54:30 +01:00
三咲智子 Kevin Deng
a733fbba08
ci: add permissions for workflows 2023-01-13 19:54:59 +08:00
sechi
f16465258d
fix(i18n): update zh-CN built_at translation for rationality (#1057) 2023-01-13 18:32:47 +08:00
Tom Sherman
0b120e8b42
fix: handle undefined ._ property on useUserLocalStorage (#1060)
Fixes https://github.com/elk-zone/elk/issues/1056
2023-01-13 11:31:16 +01:00
KaKi87
b51fa37b34
feat(i18n): Update French translations (#1051) 2023-01-13 11:24:25 +01:00
Michel EDIGHOFFER
5c9a21eb9a
fix: show placeholder on not loaded avatar to void showing alt text (#1054) 2023-01-13 10:23:51 +01:00
patak
3367ba6e30 fix: revert #1026
This reverts commit 6cb3183c2e.
2023-01-13 10:07:10 +01:00
patak
f78a7cd98d feat: link to github releases from version number in app 2023-01-13 10:03:05 +01:00
Jonas Kruckenberg
39f9e7b6ad
chore: reduce bundle size for Tauri target (#1053)
* feat(tauri): improve app size

* reorder modules so tauri can disable pwa

* don't strip the logo
2023-01-13 08:46:07 +00:00
Kushal Niroula
23532062f5
fix: empty server list throws console error on move (#1048)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-13 14:23:24 +08:00
Diu
6cb3183c2e
feat(ui): smoothly unblurring picture placeholders (#1026)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
resolves https://github.com/elk-zone/elk/issues/1022
2023-01-13 14:19:46 +08:00
Alex
5e940e58cb
fix: offline checker not show in large screen (#1043)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
closes https://github.com/elk-zone/elk/issues/1042
2023-01-13 05:49:48 +00:00
Anthony Fu
f758fc6bea feat: hide user handle in zen mode 2023-01-13 01:39:48 +01:00
Anthony Fu
9571d7338a feat: separate metions lines on replying 2023-01-13 01:33:04 +01:00
Anthony Fu
9476d14d6c fix: dedupe accounts in reply mentions 2023-01-13 01:19:24 +01:00
Anthony Fu
36ae8be40a
feat: collapse mentions (#1034) 2023-01-13 01:08:56 +01:00
patak
d39ea9a6de chore: release v0.4.1 2023-01-13 00:13:02 +01:00
Michel EDIGHOFFER
7f4a5587d7
fix: disable virtual scroll on notification page (#1037) 2023-01-13 00:05:09 +01:00
Daniel Roe
1e538cb8cd fix(types): ignore $fetch types 2023-01-12 22:58:41 +00:00
Daniel Roe
8c2aed0590 fix: use globalThis.$fetch for tauri support 2023-01-12 22:27:14 +00:00
Daniel Roe
27d1328c13 fix: add missing direct import (for tauri module) 2023-01-12 22:26:35 +00:00
Pavel
839331ae67
fix: non-showing hashtag charts (#1032) 2023-01-12 21:19:20 +00:00
Joaquín Sánchez
63adaaf4f9
docs: fix elk screenshot on mobile (#1023) 2023-01-12 21:06:17 +01:00
Joaquín Sánchez
3886ef69a5
docs(contributing): fix lang and i18n module links (#1019) 2023-01-12 21:05:21 +01:00
三咲智子 Kevin Deng
bc2a64ac58
fix(i18n): update Chinese intro 2023-01-13 02:54:15 +08:00
三咲智子 Kevin Deng
884227f560
fix: decrease count when cancel status action 2023-01-13 02:48:52 +08:00
三咲智子 Kevin Deng
a41a31732b
revert: "feat: display i18n text on SSR"
This reverts commit cafc995dde.
2023-01-13 02:35:26 +08:00
Tom Sherman
e9dccc9ef5
feat: add option to follow system color setting (#1012)
Co-authored-by: Daniel Roe <daniel@roe.dev>
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
Closes https://github.com/elk-zone/elk/issues/1007
2023-01-12 18:29:10 +00:00
三咲智子 Kevin Deng
c484117657
refactor: simplify code 2023-01-13 02:18:21 +08:00
Tom Sherman
11f1f62523
feat: hide server autocomplete when you enter a valid URL (#1009)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
closes https://github.com/elk-zone/elk/issues/1005
2023-01-13 02:14:34 +08:00
Sakana
cb2e39e854
fix(i18n): corrects Chinese dark/light mode (#1011) 2023-01-12 18:04:15 +00:00
Kushal Niroula
4f696175b3
feat(ui): highlight pick you server message in sign in form (#1010) 2023-01-13 02:03:39 +08:00
三咲智子 Kevin Deng
cafc995dde
feat: display i18n text on SSR 2023-01-13 01:58:31 +08:00
三咲智子 Kevin Deng
9a41b9b7d7
feat(settings): respect settings from server (#1013) 2023-01-13 01:52:52 +08:00
Daniel Roe
32aa47e701
perf: mock semver import (#1006) 2023-01-12 16:31:18 +00:00
Daniel Roe
dcec32338c fix: use open graph images on elk.zone 2023-01-12 16:26:04 +00:00
三咲智子 Kevin Deng
cd490fffec
fix: fetch the first page of data 2023-01-13 00:21:32 +08:00
三咲智子 Kevin Deng
4139be32f9
chore: cleanup 2023-01-13 00:04:37 +08:00
三咲智子 Kevin Deng
d0d0503a13
perf: fetch instance info only once 2023-01-13 00:01:18 +08:00
Alexander Lichter
ad70d9c475
chore(readme): remove non-sharing hint (#1008) 2023-01-12 14:03:27 +00:00
Emmanuel Salomon
b352fbf3f9
fix(i18n): corrects French mistakes (#998) 2023-01-12 21:24:57 +08:00
ʀᴀʏ
78530bfe68
fix(i18n): wrong zh-CN n-people-in-the-past-n-days translation (#1000) 2023-01-12 21:24:32 +08:00
Adam Cooper
9f368e50d2
feat: add additional profile icons (#992) 2023-01-12 19:18:06 +08:00
Vjacheslav Trushkin
79753fd508
fix: catch exceptions in HTML parser (#994) 2023-01-12 11:13:20 +00:00
Anthony Fu
70a4475eac docs: make mastodon link non-external 2023-01-12 11:54:38 +01:00
Sébastien Chopin
3e83ca375f
docs: add volta badge (#990)
Similar to CodeFlow
2023-01-12 18:48:47 +08:00
Anthony Fu
22e6b13151 chore: ignore pnpm ignore-workspace-root-check 2023-01-12 10:45:11 +01:00
təəna.vuə
34aef0a55f
feat: update hover color and bg for action more button (#983) 2023-01-12 17:40:49 +08:00
Svyatoslav Kryukov
2ddfdffa3d
chore: make Codeflow bot comment every issue (#984) 2023-01-12 10:26:46 +01:00
三咲智子 Kevin Deng
523846e0ef
chore: release v0.4.0 2023-01-12 17:14:09 +08:00
三咲智子 Kevin Deng
49ff5f8ab1
chore: check stale dep before running commands (#963) 2023-01-12 13:40:54 +08:00
三咲智子 Kevin Deng
25223d026b
feat: add tooltip for user picker (#938) 2023-01-12 13:39:39 +08:00
三咲智子 Kevin Deng
4e0777d723
refactor: output errors on devtools (#928) 2023-01-12 13:39:22 +08:00
patak
50c54144e6 chore: point GitHub links to the elk repo 2023-01-12 01:41:25 +01:00
patak
3ef1f8185d chore: prepare intro screen for opening up the repo 2023-01-12 01:39:53 +01:00
patak
2e64cd6c98 chore: add info from README.md to contributing.md 2023-01-12 01:09:42 +01:00
Daniel Roe
8da4a8e78a fix: escape backticks within codeblocks
resolves https://github.com/elk-zone/elk/issues/970
2023-01-11 23:54:45 +00:00
Daniel Roe
a12d3d09b1 feat: support page titles in opengraph data 2023-01-11 23:08:31 +00:00
Daniel Roe
da8594dbf1 feat: add large card support 2023-01-11 23:08:20 +00:00
Daniel Roe
3add7a5f40 chore: test open graph on edge 2023-01-11 22:51:23 +00:00
Daniel Roe
3a66944080 chore: remove /invite route preparatory to launch 2023-01-11 22:50:52 +00:00
Daniel Roe
3f9e39d244 chore: add basic open graph metadata 2023-01-11 22:42:52 +00:00
patak
07808384bf chore: add og image 2023-01-11 23:33:06 +01:00
Anthony Fu
e34bfee4a5 feat: sponsors in about page and nav footer 2023-01-11 23:24:05 +01:00
Daniel Roe
2b3b5fe4cb
chore: fix some typos 2023-01-11 22:13:46 +00:00
Anthony Fu
bf60ca05fa docs: update sponsorship 2023-01-11 22:58:03 +01:00
Kerunix
67f58a3335
fix: empty code blocks (#978) 2023-01-11 21:55:47 +01:00
Ayo Ayco
689ae0c701
fix: top and bottom padding of small preview card on mobile (#974) 2023-01-11 20:08:15 +01:00
Shinigami
c1e89582f8
fix: remove emoji in status title (#932)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-11 17:47:36 +00:00
Daniel Roe
c2850a34ae
fix: use mention accts within a status to render links (#955) 2023-01-11 18:18:06 +01:00
Daniel Roe
f9509f8987
fix: escape/textify the contents of inline and block code (#954) 2023-01-11 16:24:13 +00:00
Michel EDIGHOFFER
24d43699bb
fix(i18n): fr - use apprecier instead of aimer + add misisng trads (#956) 2023-01-11 16:14:49 +01:00
Daniel Roe
f04d7ac067
fix: defer loading text and server links until hydration (#926) 2023-01-11 14:50:47 +00:00
Ayo Ayco
c92fd7939e
feat: bring zen mode to mobile footer nav (#969) 2023-01-11 14:00:41 +00:00
Piotrek Tomczewski
af85a5ea8d
fix(hashtag): fixed hashtag follow button on larger screens (#862) 2023-01-11 14:39:20 +01:00
Joaquín Sánchez
dfed02efee
docs: include Semantic Pull Request in contributing guide (#965) 2023-01-11 10:22:53 +00:00
Joaquín Sánchez
0cc75a10b5
feat: use experimentalVirtualScroller on notifications (#940) 2023-01-11 17:59:47 +08:00
Pengsha Ying
46109d6dfa
docs: fix typo (#964) 2023-01-11 17:29:33 +08:00
wheat
2af1fec425
feat: use square avatar when on own profile (#961) 2023-01-11 09:39:49 +01:00
三咲智子 Kevin Deng
e690422266
fix(docs): correct twitter username 2023-01-11 16:32:23 +08:00
Clark Cui
c757e45762
fix: back button invalid (#958) 2023-01-11 12:31:35 +08:00
Daniel Roe
2281dc6bd0 fix: expose dropzone ref to publish widget 2023-01-10 22:51:25 +00:00
Daniel Roe
d36e21c5f1 fix(tauri): add /api/list-servers route 2023-01-10 22:44:46 +00:00
Michel EDIGHOFFER
0cb974fcf7
fix: just now french translation (#951) 2023-01-10 23:18:52 +01:00
JP
7a821fa648
feat(i18n): add ar-EG entries (#950) 2023-01-10 23:06:43 +01:00
Piotrek Tomczewski
7c651d450d
feat(tiptap): add undo and redo (#944) 2023-01-10 22:16:56 +01:00
Joaquín Sánchez
62b6020895
fix: add workbox-build dev dependency (#949) 2023-01-10 22:09:12 +01:00
Joaquín Sánchez
1b9fb99032
feat: add web manifest dark theme variants (#947) 2023-01-10 21:35:34 +01:00
Ivan Demchuk
6e7813020e
fix: properly close media dialog on Esc key (#946) 2023-01-10 20:57:12 +01:00
Clark Cui
74148d71b0
fix: disable back button when no back path (#936)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-11 00:01:24 +08:00
wheat
ba9a91a34e
feat: wellness settings (#927)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-10 22:45:17 +08:00
三咲智子 Kevin Deng
81c8a74748
feat(publish): add loading icon for sending 2023-01-10 21:32:50 +08:00
三咲智子 Kevin Deng
0ef99f2c8e
refactor(publish): extract to composables 2023-01-10 21:31:59 +08:00
三咲智子 Kevin Deng
df37e7c4de
chore: release v0.3.1 2023-01-10 20:31:27 +08:00
三咲智子 Kevin Deng
de696d0300
refactor: move notification to masto composables 2023-01-10 20:29:16 +08:00
Daniel Roe
60ccfc84fa fix: break out of infinite loop if there are no notifications 2023-01-10 12:25:23 +00:00
Alex
fa801f9912
feat(i18n): add missing zh-CN translations (#930)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-10 10:14:43 +00:00
三咲智子 Kevin Deng
4131949b1a
chore: release v0.3.0 2023-01-10 17:27:14 +08:00
patak
ad1e597b5c
feat: no borders in cards (#925) 2023-01-10 10:05:59 +01:00
三咲智子 Kevin Deng
971e273dc3
ci: create github release (#929) 2023-01-10 10:01:50 +01:00
三咲智子
34be0078c2
refactor(publish): check glitch edition 2023-01-10 16:36:06 +08:00
三咲智子
217f1ea567
feat(settings): up to 16 fields for glitch edition 2023-01-10 16:33:20 +08:00
三咲智子
88731ee18d
feat(account): predict relationship from context 2023-01-10 15:49:49 +08:00
三咲智子
b4cda4338f
fix(command): trim spaces 2023-01-10 15:24:14 +08:00
三咲智子
8fb9739f69
feat(status): show visibility icon when non-public
closes #920
2023-01-10 15:14:33 +08:00
三咲智子
c75a9092c7
fix: pin vite version of vitest 2023-01-10 14:37:16 +08:00
三咲智子
315ade28e2
fix: lock tiptap version 2023-01-10 14:28:01 +08:00
三咲智子
645aa9ead9
chore: upgrade deps 2023-01-10 14:15:33 +08:00
三咲智子
caa02446c7
refactor: upgrade masto 2023-01-10 14:10:26 +08:00
patak
e1332345ad
feat: dm style, take 4 (#923) 2023-01-10 06:58:07 +01:00
patak
7a061c1ff9 fix: increase padding of preview card info 2023-01-09 23:49:05 +01:00
patak
ee2f9f44c2 fix: remove github card bottom border 2023-01-09 23:29:03 +01:00
Daniel Roe
6f7bdf274f
refactor: use tiny-decode for parsing html entities (#922) 2023-01-09 23:08:42 +01:00
Michel EDIGHOFFER
3e0a29dff5
chore: add missing french translation keys (#914) 2023-01-09 20:34:50 +01:00
Joaquín Sánchez
04aac652cf
perf(pwa): exclude shiki from sw precache (#907) 2023-01-09 20:34:26 +01:00
Ayo Ayco
d0675cb391
fix: alt button covers audio play button (#911) 2023-01-09 20:33:21 +01:00
三咲智子
3dedc0dbbd
chore: move to dev dependencies 2023-01-10 02:12:32 +08:00
Sylwia Vargas
fcc16dfbe4
docs: fix word case (#916) 2023-01-10 01:48:19 +08:00
三咲智子
0a75205309
fix: paginator state lost after HMR 2023-01-10 01:43:28 +08:00
三咲智子
56ab163369
fix(paginator): empty when count equals button 2023-01-10 01:22:20 +08:00
三咲智子
8d77f9e9fb
fix: repeat preprocessing notifications
removed some logic of a8e0e06d84 before,
re-add it now
2023-01-09 23:39:59 +08:00
三咲智子
333cab0858
fix(paginator): item count less than buffer 2023-01-09 23:20:54 +08:00
三咲智子
01a24a6015
refactor: optimize paginator typings 2023-01-09 23:04:09 +08:00
jviide
162b56f5cb
fix: add nofollow noreferrer noopener to Twitter mentions (#910) 2023-01-09 15:47:41 +01:00
patak
0651c50a43 chore: remove unused buffer prop 2023-01-09 15:42:13 +01:00
三咲智子
9721bbf12b
refactor: change publish button text for replying 2023-01-09 22:31:30 +08:00
三咲智子 Kevin Deng
675a14db80
fix: replace a tag with NuxtLink (#906) 2023-01-09 14:22:19 +01:00
Anthony Fu
2de0974d6b fix: nitro patch 2023-01-09 13:23:48 +01:00
三咲智子
83db9f0c38
fix: group follow notification
append current group before push a single item
2023-01-09 20:23:15 +08:00
Daniel Roe
efe7d639c1
feat: enable virtual scroller by default (#892) 2023-01-09 12:32:49 +01:00
Daniel Roe
6a6e6bfb74
feat: track unread notifications using marker api (#891) 2023-01-09 12:31:56 +01:00
Ivan Demchuk
46c4fe1e5a
refactor: extract common code for number localization (#903) 2023-01-09 12:24:26 +01:00
Anthony Fu
71b19dbe68 fix: public assets build 2023-01-09 12:12:49 +01:00
三咲智子
571deed157
chore: upgrade eslint config 2023-01-09 18:04:25 +08:00
Michel EDIGHOFFER
68d0d48199
fix(tiptap): update placeholder in case of language change (#896) 2023-01-09 10:34:26 +01:00
三咲智子
886e2d6b73
chore: corrent word case
fixed by https://github.com/antfu/case-police
2023-01-09 17:33:21 +08:00
Joaquín Sánchez
52f81a34c3
fix(i18n): hint for settings on notifications page (#893)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-09 10:31:00 +01:00
三咲智子
e336ac928b
refactor: compress svg files 2023-01-09 17:25:48 +08:00
三咲智子
173ec8ff46
refactor: replace route when switching posts and followers page 2023-01-09 16:48:39 +08:00
三咲智子
5c8faca620
fix: display follow text when loading relationship 2023-01-09 16:46:28 +08:00
三咲智子
c28d1e1537
fix: trim spaces for search keyword 2023-01-09 16:36:29 +08:00
洪布斯
509eec5f87
feat: tips for empty search result (#900) 2023-01-09 15:50:07 +08:00
Cesar Gomez
7c83bd05a5
feat(i18n): sync es-ES and fixing some context translations (#901) 2023-01-09 07:25:35 +01:00
Daniel Roe
88b428dc09 fix: retry oauth call 3x rather than just once 2023-01-09 00:06:47 +00:00
Daniel Roe
759d9e257e
chore: move docs redirect into _redirects (#895) 2023-01-08 23:04:55 +00:00
Michel EDIGHOFFER
9e24cbe5aa
fix: remove all exclamation mark on publish action (#889) 2023-01-08 23:13:44 +01:00
Daniel Roe
e621c93b95
docs: add initial documentation (#842) 2023-01-08 22:42:59 +01:00
Michel EDIGHOFFER
1125bd1970
fix(i18n): update french + use always dot for better inclusive writing (#838)
Co-authored-by: PraZ <1631886+prazdevs@users.noreply.github.com>
2023-01-08 22:28:49 +01:00
patak
a8e0e06d84 feat: move notifications to preprocessing scheme 2023-01-08 22:25:25 +01:00
patak
80d3d8dd1d feat: preprocess new items too 2023-01-08 22:22:14 +01:00
Lucas Homer
4203778f57
feat: publish button disabled UX (#886) 2023-01-08 21:55:52 +01:00
Joaquín Sánchez
3c90fee07e
fix: use unshift on publicAssets (#885) 2023-01-08 21:23:04 +01:00
Nicolò Ribaudo
7e191d7296
feat: support showing who favorited and boosted a status (#881) 2023-01-08 21:08:45 +01:00
patak
19e4aa4ada fix: show remaining items in buffer on pagination end 2023-01-08 21:03:17 +01:00
Ivan Demchuk
1dcaf41c0f
feat(i18n): add Ukrainian localization (#882) 2023-01-08 20:35:48 +01:00
patak
efe406df5b
feat: avoid reordering pagination border effects (#877) 2023-01-08 17:04:26 +01:00
Joaquín Sánchez
f8692ed480
fix: ensure video element is ready before playing (#871) 2023-01-08 14:13:03 +00:00
Joaquín Sánchez
e92a983947
fix(pwa): handle sw registration error and status (#858) 2023-01-08 14:12:25 +00:00
三咲智子
5f07fd2515
feat(settings): add bot option for profile appearance 2023-01-08 22:08:21 +08:00
Piotrek Tomczewski
fcae855eea
fix(drafts): remove and do not focus empty reply drafts (#850) 2023-01-08 14:54:12 +01:00
三咲智子
805f7731ad
refactor(search): more search options 2023-01-08 21:42:53 +08:00
Ivan Demchuk
95a875f47b
fix: exclude unreviewed hashtags from autocomplete (#873) 2023-01-08 21:34:53 +08:00
Piotrek Tomczewski
7e17bdfd83
feat(profile): hide user's boosts toogle (#865)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
2023-01-08 13:33:25 +00:00
Anthony Fu
fd2c433644 fix: nitro config 2023-01-08 14:27:33 +01:00
三咲智子
b7b6f0d1ca
fix(status): disable reblog for non-public posts
closes #870
2023-01-08 21:25:06 +08:00
Joaquín Sánchez
5075fdf194
feat(i18n): add i18n to PublishWidgetFull (#872) 2023-01-08 20:54:05 +08:00
Anthony Fu
6e0ce3c916 chore: fix module path 2023-01-08 12:18:58 +01:00
Anthony Fu
0297ed868b feat: different logos for staging and dev 2023-01-08 12:17:16 +01:00
Anthony Fu
c647a87ba1 fix(content): twitter handle matching 2023-01-08 12:17:16 +01:00
三咲智子 Kevin Deng
559e3219f1
refactor: simplify generic type (#869) 2023-01-08 18:38:26 +08:00
Anthony Fu
9f71fd005f docs: update readme 2023-01-08 11:18:39 +01:00
Anthony Fu
51e5540d36 fix: patch mlly to solve bundle error 2023-01-08 11:15:21 +01:00
Anthony Fu
2df2fefdc9 fix(tiptap): mention transform, close #521 2023-01-08 10:39:16 +01:00
三咲智子
c7f4b33bf1
fix: v1 instance api 2023-01-08 17:31:47 +08:00
三咲智子
c5573cb10b
refactor: switch to v1 instance api
V2 instance api is too new, and we should
support more versions.
2023-01-08 17:16:15 +08:00
三咲智子
d415638bd9
refactor(settings): improve profile appearance
- move user info to bottom
- don't reset dirty form after pulling the latest info
2023-01-08 17:06:21 +08:00
Anthony Fu
2211383258 feat(ui): colorize reply and reblog 2023-01-08 10:03:31 +01:00
三咲智子
c64106c98a
refactor(status): rework edit history list 2023-01-08 16:52:18 +08:00
三咲智子
6308aa5c9a
refactor: use paginator for explore 2023-01-08 16:52:18 +08:00
Anthony Fu
3d25243166
feat(ui): new replying status design (#846) 2023-01-08 09:27:21 +01:00
Anthony Fu
a4c0e9dd2e chore: change top-level function style 2023-01-08 09:21:35 +01:00
Anthony Fu
76ccf5775e feat: support @username@twitter.com as link 2023-01-08 09:21:25 +01:00
三咲智子
4ca2053bb2
fix(search): error when not selected 2023-01-08 15:57:21 +08:00
三咲智子 Kevin Deng
b30ebc12f8
refactor: generic components (#868)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-01-08 15:49:32 +08:00
三咲智子 Kevin Deng
5c8f75b9b7
refactor: upgrade masto 5 (#867) 2023-01-08 14:21:09 +08:00
patak
39034c5777 chore: update snapshots 2023-01-07 23:53:40 +01:00
patak
3dc20ea2f9 fix: preserve paragraphs when editing a status 2023-01-07 23:42:30 +01:00
Piotrek Tomczewski
1817afdb23
feat(reply): navigate to thread on publish (#852) 2023-01-07 23:18:15 +01:00
patak
c1aac9d2dc fix: bring back borders to avatars 2023-01-07 23:00:26 +01:00
patak
1f92cdc1c9 fix: make composer line height closer to final post 2023-01-07 22:51:22 +01:00
Daniel Roe
57fd9aeae2
feat: allow setting default server via env (#854) 2023-01-07 22:38:31 +01:00
Daniel Roe
697a88ac3d
fix: default to local timeline when logged out (#855) 2023-01-07 13:35:42 -08:00
Joaquín Sánchez
b5e14810af
feat(i18n): add i18n to StatusReplyingTo (#857)
Co-authored-by: Michel Edighoffer <edimitchel@gmail.com>
2023-01-07 21:27:28 +01:00
Daniel Roe
31ae413da4
fix: allow logout without push notifications (#856) 2023-01-07 19:36:21 +01:00
三咲智子
0bf76fdf86
refactor: improve search UX 2023-01-07 22:59:57 +08:00
三咲智子
2b5badf235
refactor: cleanup unused props 2023-01-07 22:56:27 +08:00
三咲智子
1957a5c681
fix(search): replace button with div 2023-01-07 22:55:10 +08:00
三咲智子
cf561870f0
refactor: search 2023-01-07 22:52:58 +08:00
三咲智子
d386a2dbbe
fix: hashtag id 2023-01-07 22:21:52 +08:00
三咲智子
30e4ef57df
perf: don't destroy elements when zen mode
closes #834
2023-01-07 22:03:25 +08:00
三咲智子
bbc1580010
refactor: add bot indicator icon 2023-01-07 21:53:15 +08:00
Anthony Fu
6944a74653 refactor: html parsing 2023-01-07 10:31:48 +01:00
PraZ
d76e4bfaa5
feat: add post deletion confirm dialog (#818)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
2023-01-07 16:55:01 +08:00
Piotrek Tomczewski
2ff46bb8cb
feat(ui): opening the details page with the reply button (#840) 2023-01-07 08:55:07 +01:00
Daniel Roe
6a78f9c9e3
fix: prevent rounded background when avatar is square (#811) 2023-01-06 23:13:28 +01:00
Piotrek Tomczewski
0a79f4dc28
feat(publish): add hashtag autocomplete (#837) 2023-01-06 22:38:01 +01:00
三咲智子
5e38a768c9
fix: TS error in locales list
upgrade jiti
https://github.com/unjs/jiti/issues/106 is fixed
2023-01-07 05:18:22 +08:00
Joaquín Sánchez
907abd0b41
fix(pwa): add background_color to web manifest (#832) 2023-01-06 22:04:17 +01:00
Joaquín Sánchez
e04513d24c
chore: update pwa plugin version (#835) 2023-01-07 05:02:38 +08:00
dicarbene
a81de95d3d
chore: update contributing guide typo (#836) 2023-01-06 22:02:08 +01:00
三咲智子
5f7f7573c6
fix(tauri): upgrade target browser version
used top-level await, only Safari > 15 supports it
2023-01-07 04:00:19 +08:00
Joaquín Sánchez
731d68d53d
fix: hydration problem on default layout (#831) 2023-01-07 03:38:40 +08:00
三咲智子
c48ee6c35b
refactor: cleanup auto imports 2023-01-07 03:22:56 +08:00
三咲智子
230c8b68a4
feat(settings): preview display name and handle 2023-01-07 03:14:00 +08:00
三咲智子
2bbbfd51c1
refactor(account): extract display name component 2023-01-07 03:12:00 +08:00
三咲智子
c7756add7d
refactor: cleanup imports 2023-01-07 02:50:31 +08:00
三咲智子
e2dc90a889
chore: add cache for eslint 2023-01-07 02:48:55 +08:00
三咲智子
e0741d58a9
refactor: tidy composables 2023-01-07 02:43:49 +08:00
三咲智子
bf8070c4b9
refactor: auto import masto composables 2023-01-07 02:35:45 +08:00
三咲智子
79e4841f87
fix: rework tip for unavailable posts
refactor #767
2023-01-07 02:29:44 +08:00
Ryan Cao
a311e0ec80
feat: add aria-label for back button (#819) 2023-01-07 01:46:06 +08:00
Anthony Fu
1aa118283e
refactor: unify user settings (#821)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
2023-01-07 01:39:37 +08:00
三咲智子
35c9a871be
fix(command): remove compose action 2023-01-07 01:32:53 +08:00
Joaquín Sánchez
413f2e1fea
fix: refresh wide layout pages broken (#828) 2023-01-07 00:22:11 +08:00
三咲智子
c713add727
refactor: rename dev to canary 2023-01-07 00:20:12 +08:00
三咲智子
cffcddefb9
refactor: use defineModel 2023-01-06 23:46:36 +08:00
Joaquín Sánchez
85ac005570
feat: i18n PWA webmanifests (#805)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-06 20:48:43 +08:00
Joaquín Sánchez
18056038c7
fix: current nav side on pwa update (#823) 2023-01-06 13:47:49 +01:00
patak
37fa2b9117 chore: release v0.2.0 2023-01-06 13:45:52 +01:00
patak
915923162a chore: revert min-height for status (85316d0) 2023-01-06 11:59:03 +01:00
patak
7c6a81961b fix: extra top spacing on xl for all routes 2023-01-06 11:52:58 +01:00
patak
779fcf4177 feat: move compose to user category in sidebar 2023-01-06 11:41:47 +01:00
patak
36f11e48da feat: categorized sidebar 2023-01-06 10:44:07 +01:00
Mayank
c11a7cc225
fix: make code font-size smaller in displayed markdown (#817)
Co-authored-by: Mayank <mayank99@users.noreply.github.com>
2023-01-06 10:40:11 +01:00
Joaquín Sánchez
573bf48eda
fix: sync current account across tabs 2 (#816) 2023-01-06 10:34:18 +01:00
Joaquín Sánchez
d8eec1ed5e
fix: sync current account across tabs (#815) 2023-01-06 00:39:10 +01:00
patak
b1fbac6ba3
feat: use square avatar for publish widget (#814) 2023-01-06 00:35:35 +01:00
Anthony Fu
b4012a11bf fix(ui): style consistant 2023-01-06 00:04:51 +01:00
Anthony Fu
916793f5ae fix: ui search items 2023-01-06 00:04:51 +01:00
Adam Cooper
954a6bd5a1
feat: add link to the posting app (#807) 2023-01-05 22:57:04 +00:00
wheat
a35884c0a7
feat: update design of square avatar (#808) 2023-01-05 23:21:31 +01:00
Joaquín Sánchez
6bb9fd9553
fix(i18n): spanish app_desc_short (#806) 2023-01-05 18:38:27 +01:00
Ivan Demchuk
7e794aa641
feat: preserve media dialog state in browser history (#743) 2023-01-05 17:51:50 +01:00
Ivan Demchuk
c68c7ad507
fix: image thumbnail position (#731) 2023-01-05 17:49:59 +01:00
Joaquín Sánchez
85316d0518
feat: increase status body min height (#783) 2023-01-05 17:49:08 +01:00
三咲智子 Kevin Deng
acdb94de62
fix: type errors (#802) 2023-01-05 17:48:20 +01:00
Anthony Fu
272fb4a13d
feat: compose editor as a page (#804) 2023-01-05 16:42:36 +01:00
Jorge Barrera
9d5269e0c0
feat: update es-ES strings (#803) 2023-01-05 16:37:58 +01:00
patak
dede688bf2 fix: sign in button in md, lg 2023-01-05 15:03:45 +01:00
三咲智子
79bd9830c9
chore: configure volar completion 2023-01-05 21:43:34 +08:00
Shinigami
31ee71c0d1
refactor: convert CommonBlurhash to Vue SFC file (#795)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
2023-01-05 12:38:22 +00:00
patak
f177ea1ea8 feat: floating back button for xl 2023-01-05 13:35:08 +01:00
patak
b4408422a8 fix: user alignment 2023-01-05 13:18:09 +01:00
patak
597ebae042 fix: missed logged in users squares 2023-01-05 13:17:44 +01:00
patak
e5a9bd7370 feat: use square avatars for logged in user 2023-01-05 13:10:22 +01:00
patak
640075fed1 feat: continue style experiments 2023-01-05 12:33:09 +01:00
PraZ
1c2c4a251e
feat: use line icons (metadata fields) (#794) 2023-01-05 18:26:28 +08:00
Joaquín Sánchez
95c825522e
perf: use team avatars from local (#793) 2023-01-05 10:03:32 +00:00
Anthony Fu
d279d618a5 ui: move account settings link under profile 2023-01-05 09:59:49 +01:00
Arthur Fontaine
bd1b9fb5c8
fix: emoji replacement when pasting (#777) 2023-01-05 09:50:11 +01:00
Joaquín Sánchez
d4e99566b8
feat: notifications settings page (#782) 2023-01-05 09:47:58 +01:00
三咲智子 Kevin Deng
0d66038eaa
refactor: use github avatar (#789) 2023-01-05 09:21:02 +01:00
PraZ
22729eed70
feat(metadata): add pronouns metadata field icon (#784)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-05 08:10:29 +00:00
Lucas Homer
614bc274bc
feat(i18n): capitalize posts_count unit (#787) 2023-01-05 08:38:04 +01:00
jviide
5c0e1790fa
fix: sanitize HTML from Mastodon servers (#788) 2023-01-05 08:21:09 +01:00
Ryan Cao
777066508e
i18n: add missing simplified chinese translations (#785)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-05 07:14:56 +00:00
patak
fc48f8b90c feat: style experiments 2023-01-05 00:17:30 +01:00
Piotrek Tomczewski
1ff584bf8b
feat(publish): add hashtag autocomplete (#778) 2023-01-04 21:47:29 +01:00
Max
9d7b7b66ed
i18n(nl-NL): dutch locales (#745) 2023-01-05 04:10:09 +08:00
Piotrek Tomczewski
6b5b1f2aed
feat(search): show hashtag stats and chart in autocomplete (#779) 2023-01-04 21:08:05 +01:00
Ivan Demchuk
4eb9d52fc2
fix: loading status replies after page refresh (#780) 2023-01-04 20:55:57 +01:00
三咲智子
7d6904d73b
chore: release v0.1.18 2023-01-05 03:02:38 +08:00
PraZ
733c4003c9
feat(i18n): update french help modal locales (#770) 2023-01-04 16:49:44 +01:00
三咲智子
59761c1c04
ci: remove testing on netlify 2023-01-04 23:43:05 +08:00
三咲智子
3468c13e75
ci: switch back to github actions 2023-01-04 23:37:19 +08:00
Ryan Cao
2f88bf6824
i10n: localize font sizes in settings (#775) 2023-01-04 16:22:56 +01:00
Ryan Cao
8840205c98
feat: add link to account settings on instance (#772)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
2023-01-04 22:43:17 +08:00
三咲智子
482e8c1c3a
i18n: translate titles 2023-01-04 22:04:37 +08:00
三咲智子
377c015c91
feat: add titles for settings 2023-01-04 21:57:21 +08:00
三咲智子 Kevin Deng
9a167ee990
fix: git branch name (#771) 2023-01-04 21:41:48 +08:00
Yunwei Xiao
8a66174477
fix: fixed the style bug when toggle the dark mode (#754) 2023-01-04 21:26:51 +08:00
三咲智子 Kevin Deng
f892722220
refactor: env config (#769) 2023-01-04 14:26:30 +01:00
Ryan Cao
9d5dc1bc3d
fix: link to original instance for older unavailable posts (#767) 2023-01-04 14:21:03 +01:00
patak
6a7633b758 chore: rework timeline tests 2023-01-04 14:14:33 +01:00
patak
9890656477 feat: improve timeline reordering 2023-01-04 13:09:09 +01:00
三咲智子
bf0c3425fc
refactor(settings): improve profile metadata input style 2023-01-04 18:47:19 +08:00
三咲智子
73fe063a8f
refactor(publish): extract pickers 2023-01-04 18:41:19 +08:00
三咲智子
9677f742c8
refactor(status): remove null fields 2023-01-04 18:21:18 +08:00
三咲智子
b0d6f310a8
feat(publish): hoist selected language and none 2023-01-04 17:56:10 +08:00
三咲智子
154885ca96
fix(status): add language from status when redraft 2023-01-04 17:39:12 +08:00
三咲智子
8983edd1bb
fix: SSR render error on profile page 2023-01-04 17:26:31 +08:00
三咲智子
a8135197c9
fix: replace route for account tabs 2023-01-04 17:01:10 +08:00
Ryan Cao
9f7c5a2040
feat: add markdown support for glitch-soc instances (#752) 2023-01-04 09:59:59 +01:00
wheat
4354dd6a2e
feat: add image preview swipe (#749) 2023-01-04 09:15:24 +01:00
三咲智子
710511e589
fix(ui): don't shrink when wide layout 2023-01-04 15:55:11 +08:00
三咲智子
b419f34b63
chore: release v0.1.17 2023-01-04 15:18:00 +08:00
三咲智子
1ac1ce19fa
revert: "feat: reorder consecutive posts that have others in between"
This reverts commit 364acd998e.
2023-01-04 15:14:37 +08:00
patak
012432bf19 chore: release v0.1.16 2023-01-03 22:50:50 +01:00
patak
cc666ca8b7 fix: add bottom border to account tabs 2023-01-03 22:50:22 +01:00
patak
c0602555de fix: add bottom border in thread view 2023-01-03 22:38:06 +01:00
patak
364acd998e feat: reorder consecutive posts that have others in between 2023-01-03 22:34:52 +01:00
Joel Drake
69b528fc0c
fix: re-add extra spacing in threads (#741) 2023-01-03 21:52:52 +01:00
Anthony Fu
9871327a72 feat: basic post intent support 2023-01-03 18:46:04 +01:00
Anthony Fu
564a754a4d ui: clean up nav footer 2023-01-03 18:24:39 +01:00
Anthony Fu
64fa8d2bf4 ui: move settings to nav side 2023-01-03 18:16:04 +01:00
patak
db32d9343a fix: status detail avatar alignment 2023-01-03 17:25:43 +01:00
patak
d353f38ac9 fix: support /stars/user in GitHub cards 2023-01-03 16:59:49 +01:00
patak
f8703fc1c1 feat: keep timeline at 600px for md and lg screens 2023-01-03 14:48:13 +01:00
Vjacheslav Trushkin
61a141ae69
fix: revert em-emoji-picker style removal (#739) 2023-01-03 14:27:55 +01:00
Vjacheslav Trushkin
8b219cdb73
fix: modal focus scroll bug (#738) 2023-01-03 14:02:54 +01:00
Ivan Demchuk
055df9d28c
feat: add hover info and link to booster avatar (#736) 2023-01-03 13:40:16 +01:00
Nicolò Ribaudo
f4ff6ee35d
fix: prevent language&emoji pickers from overflowing (#735) 2023-01-03 13:17:04 +01:00
三咲智子
b14add8c83
refactor: tidy masto icons 2023-01-03 20:03:50 +08:00
三咲智子
ef417f3ccf
refactor: tidy injections of dropdown 2023-01-03 20:03:50 +08:00
patak
4a3cef9a01
fix: make paragraphs visible (#734) 2023-01-03 12:58:53 +01:00
三咲智子
a4eda1ce66
feat: change color for active tab 2023-01-03 19:53:40 +08:00
三咲智子
fe7bd2d7e3
feat(account): add tooltip for field icons 2023-01-03 19:41:26 +08:00
三咲智子
1d9bd6a9d4
fix: only reduce line-height for post content
relate PR #557
2023-01-03 19:35:58 +08:00
三咲智子
4308491e9c
feat(command): uncomment search tip 2023-01-03 19:19:17 +08:00
三咲智子
f0ed98c6ad
fix: hydrated error of built time ago 2023-01-03 19:16:16 +08:00
三咲智子
7ef26330fb
i18n: add spaces around number for Chinese 2023-01-03 19:16:16 +08:00
Ivan Demchuk
9727568d34
fix: intro screen closing immediately (#732) 2023-01-03 12:15:33 +01:00
三咲智子
b18bc7fad1
fix(pinned): layout & not signed in 2023-01-03 18:45:36 +08:00
三咲智子
b0766ab52f
i18n: translate intro dialog 2023-01-03 18:32:02 +08:00
三咲智子
4ea5d8ba60
fix(settings): don't submit when clicking icon buttons 2023-01-03 18:13:48 +08:00
Joaquín Sánchez
245a37db19
docs: update running mocked pwa script (#730) 2023-01-03 11:00:17 +01:00
Vjacheslav Trushkin
177df4aed7
fix: glob for emojis cache for pwa (#729) 2023-01-03 10:57:41 +01:00
三咲智子
6729666170
refactor: add onMastoInit 2023-01-03 17:53:45 +08:00
Vjacheslav Trushkin
6092b27da6
fix: remove unused emoji stuff (#727) 2023-01-03 10:42:05 +01:00
Nicolò Ribaudo
6e12402987
fix: update m.webtoo.ls/@elk links to open in Elk (#725) 2023-01-03 09:14:49 +01:00
三咲智子
269fc30afd
fix: don't resolve search when not signed in 2023-01-03 11:25:02 +08:00
三咲智子
f467958cd9
chore: release v0.1.15 2023-01-03 10:56:51 +08:00
Joaquín Sánchez
20598c6648
i18n(es): sync spanish translations (#723) 2023-01-03 10:31:10 +08:00
Joaquín Sánchez
34b0f28e75
docs: add missing backtick on contributing file (#724) 2023-01-03 10:30:29 +08:00
Joaquín Sánchez
c6f292a68c
fix: use top level await accessing users idb (#721)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
2023-01-03 08:18:01 +08:00
Linus Groh
029440421d
i18n: various i18n additions & fixes (#719) 2023-01-03 08:16:33 +08:00
Linus Groh
8a3cfcd089
feat: add account field icon for 'Language(s)' (#720) 2023-01-03 08:15:51 +08:00
Joaquín Sánchez
964a67fbf5
feat: update elk icons (#717)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-03 08:14:53 +08:00
三咲智子
f844648cbf
fix: repeat server in acct 2023-01-03 07:00:12 +08:00
patak
2d5038d046 chore: update mastodon usernames 2023-01-02 23:22:38 +01:00
Felix
33589acaee
feat: disable change-visibility button when editing status (#715) 2023-01-02 23:11:43 +01:00
三咲智子
26be3e5894
fix(settings): parse links in metadata 2023-01-03 06:00:23 +08:00
三咲智子
8a0f9176fb
chore: update @sxzz 's display name 2023-01-03 05:39:07 +08:00
三咲智子
7bc9f390db
feat(settings): add reset form 2023-01-03 05:17:24 +08:00
三咲智子
5dffd380b0
fix(settings): close dropdown after choosing icon 2023-01-03 05:17:24 +08:00
Ivan Demchuk
ddb6e90e21
feat: browser native post share (#714) 2023-01-02 22:00:51 +01:00
三咲智子
296a7b6eae
feat(publish): support search for language list 2023-01-03 04:56:21 +08:00
Joaquín Sánchez
bb4fd74ce3
docs: run PWA on dev server (#710) 2023-01-02 21:32:55 +01:00
三咲智子
c0a2aca98a
feat(settings): about page 2023-01-03 04:28:49 +08:00
Joaquín Sánchez
3563b58651
fix(pwa): exclude emojis/twemoji from sw precache manifest (#706) 2023-01-02 20:18:33 +01:00
Darius Kazemi
75f1a6b16e
docs: add note about pnpm install (#705) 2023-01-02 20:06:13 +01:00
Moritz Gießmann
190fb46fd9
fix: settings typo (#704) 2023-01-02 19:16:50 +01:00
Vjacheslav Trushkin
5c773149c9
fix: remove line-clamp from signatures in notifications (#703) 2023-01-02 18:42:05 +01:00
patak
b593977421 docs: fix images in readme 2023-01-02 18:06:06 +01:00
Joaquín Sánchez
05e7dd2b2d
docs: update contributing guide link (#701) 2023-01-02 17:36:35 +01:00
Vjacheslav Trushkin
c89dca05a0
chore: update RTL support section of Contributing Guide (#702) 2023-01-02 17:35:57 +01:00
Anthony Fu
95bedb5335
docs: sponsors (#689)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
Co-authored-by: patak <matias.capeletto@gmail.com>
Co-authored-by: userquin <userquin@gmail.com>
2023-01-02 17:01:17 +01:00
Joaquín Sánchez
bf9d7ee7fa
docs: add RTL and CI errors to contributing guide (#700) 2023-01-02 17:00:40 +01:00
三咲智子
2756732c33
i18n: correct Chinese translation 2023-01-02 23:03:40 +08:00
三咲智子 Kevin Deng
c216c81bb7
feat(settings): metadata (#699)
Co-authored-by: LittleSound <464388324@qq.com>
2023-01-02 23:00:11 +08:00
Joaquín Sánchez
f942ddc5a3
docs: fix Custom Plural Number Formatting Entries (#698) 2023-01-02 15:58:12 +01:00
三咲智子
e728ee0556
fix: publish button in mobile device
closes #694
2023-01-02 22:09:53 +08:00
Joaquín Sánchez
c2261370b4
docs: add contributing guide (#697) 2023-01-02 14:48:17 +01:00
Joaquín Sánchez
5e3156a638
fix: boots action count (#695) 2023-01-02 14:20:56 +01:00
Vjacheslav Trushkin
da7d85b1d0
fix: parse emojis in account page title (#690) 2023-01-02 10:00:00 +01:00
Vjacheslav Trushkin
fa9c418e21
feat: replace emoji with SVGs (#129) (#584)
Co-authored-by: Anthony Fu <anthonyfu117@hotmail.com>
2023-01-02 05:53:53 +01:00
Anthony Fu
41c5f94fbf ui: padding 2023-01-02 05:52:14 +01:00
Michel EDIGHOFFER
74249737d3
fix(i18n-fr): wrong usage of followers (#688) 2023-01-02 01:11:15 +01:00
Michel EDIGHOFFER
5d3aa5886e
fix(i18n-fr): remove status.thread unused translation key + not to translate keys (#686) 2023-01-02 01:00:47 +01:00
Daniel Roe
72ce43dde9
fix: remove history state fallback + asyncdata (#687) 2023-01-02 01:00:13 +01:00
Michel EDIGHOFFER
451c4a0701
feat(i18n): sync french translations (#685) 2023-01-02 00:48:55 +01:00
Daniel Roe
0187763c29
refactor: set hydrated value in nuxt plugin 2023-01-02 00:18:05 +01:00
三咲智子
b48a893614
chore: rename emit function 2023-01-02 06:06:27 +08:00
三咲智子
72e03f8109
refactor: move meta to nuxt config 2023-01-02 06:03:35 +08:00
三咲智子
aca6f16245
feat(publish): support status language
relate issue #332
2023-01-02 05:52:11 +08:00
Joaquín Sánchez
b8c7ed8157
feat(i18n): use compact number format on actions (#683) 2023-01-01 22:45:46 +01:00
三咲智子
d4268cfff8
fix: stop global zooming when previewing image
relate PR #668
2023-01-02 05:13:14 +08:00
三咲智子
23c7e68755
refactor(settings): replace file input with browser-fs-access 2023-01-02 04:48:23 +08:00
三咲智子 Kevin Deng
645da2f945
fix: omit value property of isHydrated in template (#681) 2023-01-01 21:43:09 +01:00
patak
64611083a5 feat: connect reblogged replies 2023-01-01 21:16:32 +01:00
Joaquín Sánchez
bd72ecd0e5
feat: image preview gestures (#668) 2023-01-01 20:59:31 +01:00
patak
9e8ee0da41 fix: self-boost style 2023-01-01 20:57:00 +01:00
三咲智子
fbf1906bd4
fix(settings): refresh profile after initted 2023-01-02 03:42:19 +08:00
Joaquín Sánchez
496da96072
feat(pwa): allow access elk users from service worker (#662)
Co-authored-by: patak <matias.capeletto@gmail.com>
2023-01-01 20:38:05 +01:00
Joaquín Sánchez
ca93f1a813
feat(i18n): use compact number format instead K/M suffix (#678) 2023-01-01 20:31:14 +01:00
三咲智子 Kevin Deng
d0567c0d18
feat: get origin from client (#679) 2023-01-01 20:30:39 +01:00
Joaquín Sánchez
d8abea75aa
fix: push notification request permission (#677) 2023-01-01 20:24:22 +01:00
Eamonn O'Brien-Strain
6c38477bc2
fix: prevent auto-capitalization and adding space after dot when signing in (#674) 2023-01-01 20:21:09 +01:00
patak
f0db2e9013
feat: wider DMs (#675) 2023-01-01 20:20:13 +01:00
patak
016da2e8c0
feat: rework avatar on avatar (#676) 2023-01-01 20:15:51 +01:00
三咲智子
9d6801ba46
i18n: add spaces for Chinese 2023-01-02 02:22:33 +08:00
Joaquín Sánchez
29fe2a10ac
feat: file upload errors (#671)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
2023-01-02 02:11:50 +08:00
三咲智子
e596953ada
fix: route params is empty
When navigating status not found page to /home, there will be a error
since `$route.params.account` is undefined, and
change it to `route` will be fixed.
2023-01-02 00:08:43 +08:00
三咲智子
22fcc1d68b
feat: go to new status after redraftting 2023-01-01 23:57:49 +08:00
三咲智子
d62292d219
fix: use html content for redrafting 2023-01-01 23:31:33 +08:00
三咲智子
ca1b7169f1
fix: click outside to hide autocompleted servers 2023-01-01 23:12:02 +08:00
Vjacheslav Trushkin
727d05915f
fix: layout fixes for RTL languages (#591)
* fix: rtl arrows on settings page

* fix: border on settings page for RTL languages

* fix: RTL fixes for logo, search box and logout icon

* fix: RTL layout bugs in conversations

* chore: remove rtl setting icon

* improve arabic locale

* add new entries to arabic locale

* chore: include number format

* fix: RTL layout on several pages

* fix: RTL layout of account header and sign in modal

* fix: always display account handle in LTR

* fix: move character counter in publish widget to left side for RTL

* fix: remove border-ss-none unocss rule

* fix: many RTL fixes

* fix: RTL fixes for many pages

* fix: use viewer's direction in all content

* chore: use new arabic plural rules

* chore: flip arrow on main content header

* chore: fix StatusPoll and show_new_items for zh-TW

* chore: StatusPoll tooltip on bottom

* chore: add `en` variants to i18n conf

* chore: update entry to use new plural rule

* fix: automatic content direction for status

* fix: direction for account handle

* fix: direction of polls

Co-authored-by: userquin <userquin@gmail.com>
Co-authored-by: Jean-Paul Khawam <jeanpaulkhawam@protonmail.com>
Co-authored-by: Daniel Roe <daniel@roe.dev>
2023-01-01 15:29:11 +01:00
patak
c5304be775 fix: round video attachments too 2023-01-01 11:54:58 +01:00
patak
9b33c7c884 fix: aspect ratio for avatars on search results 2023-01-01 11:54:17 +01:00
patak
17fecebcae fix: NavUser avatar height on small screens 2022-12-31 13:26:52 +01:00
Shane H
4713db9adc
fix: display error if attachments exceed limit (#666) 2022-12-31 10:02:55 +01:00
三咲智子 Kevin Deng
53fc28bf61
i18n: add zh-TW (#664) 2022-12-31 05:07:11 +01:00
patak
943a0b66fe fix(a11y): use Image as alt when there isn't a description 2022-12-30 23:52:32 +01:00
三咲智子
4da2fd05bb
feat(ui): transparent status bar 2022-12-31 06:45:39 +08:00
patak
b64d1add86 fix: ensure aspect ratio for avatars 2022-12-30 23:41:07 +01:00
三咲智子
a347515781
fix(user): disable spell check in domain input 2022-12-31 06:01:46 +08:00
三咲智子
4bc72905de
fix(poll): show poll times 2022-12-31 05:43:23 +08:00
三咲智子
58e51d4358
feat: transparent nav header 2022-12-31 05:35:25 +08:00
patak
b2153fa12e feat: limit max height of profile note 2022-12-30 21:54:38 +01:00
patak
d0b8c9b493
chore: update readme for codeflow 2022-12-30 21:30:23 +01:00
patak
6356c79eb4 chore: release v0.1.14 2022-12-30 19:16:35 +01:00
patak
ff73614228 fix: revert #660 + patch 2022-12-30 19:16:23 +01:00
Joel Drake
6a5383b595
fix: reply screen on mobile scroll to empty space (#616)
Co-authored-by: Joel Drake <joel.drake@ica.se>
2022-12-30 17:38:46 +01:00
patak
78a1981d87 chore: release v0.1.13 2022-12-30 17:29:47 +01:00
patak
6c59791682 fix(safari): account for larger header in notifications/explore 2022-12-30 17:25:40 +01:00
patak
1a532265fb fix: avoid icon larger than header in notifications 2022-12-30 17:24:21 +01:00
patak
5a4ec04661 feat: use timeline skeleton as default instead of spinner 2022-12-30 16:34:34 +01:00
Ayaka Rizumu
ca37b65962
fix: prevent hydration mismatch after refreshing settings (#663) 2022-12-30 16:29:34 +01:00
Joel Drake
1bb8963d98
fix: mobile header and footer prevent flicker on ios safari (#660) 2022-12-30 15:06:48 +01:00
Shane H
13887a33da
fix: Move character remaining count from Publish Editor to action bar (#656)
Co-authored-by: patak <matias.capeletto@gmail.com>
2022-12-30 07:10:29 +01:00
Joaquín Sánchez
d8b8c4e94d
fix: cannot update app from pwa prompt on ar-EG (#650) 2022-12-30 07:02:02 +01:00
Joaquín Sánchez
9de4a14b32
fix: push notification click (#643) 2022-12-29 23:43:23 +01:00
patak
861afe79b2
feat: improve color theme (#649) 2022-12-29 23:40:31 +01:00
patak
27419dc124 chore: release v0.1.12 2022-12-29 22:04:56 +01:00
patak
61349c6f0a feat: allow reordering reblogs of replies 2022-12-29 22:04:32 +01:00
三咲智子
28e26f6b12
fix(settings): hydration mismatch 2022-12-30 04:17:30 +08:00
patak
b0b0bb2f9c chore: release v0.1.11 2022-12-29 21:16:14 +01:00
三咲智子
7380609c93
fix(settings): hide profile when not login 2022-12-30 04:14:13 +08:00
patak
81869df4bd feat: simplify replying to badge in detailed view 2022-12-29 21:10:05 +01:00
三咲智子
55236dac98
feat(settings): show default font size 2022-12-30 04:08:50 +08:00
三咲智子
40481c91e8
feat(command): add description for settings items 2022-12-30 04:01:31 +08:00
三咲智子
fd93462f42
feat(command): add settings page 2022-12-30 03:58:00 +08:00
三咲智子
2332d7091a
fix(command): re-register when component activated 2022-12-30 03:57:39 +08:00
三咲智子
f1f2449559
refactor(settings): replace file input with browser-fs-access 2022-12-30 03:44:57 +08:00
patak
4460d0f59d feat: replace "Thread" with avatar for self replies 2022-12-29 20:41:11 +01:00
三咲智子
f4d4e415fb
i18n: Chinese translation 2022-12-30 03:34:29 +08:00
三咲智子
1054e556e8
fix: enable nav commands only once 2022-12-30 03:31:36 +08:00
Joaquín Sánchez
524f7005aa
fix: color mode settings button (#648) 2022-12-29 20:27:11 +01:00
patak
87eebd520e feat: simplify reply to current user 2022-12-29 20:20:47 +01:00
三咲智子
ca5cb2cfde
i18n: cleanup 2022-12-30 02:38:55 +08:00
三咲智子
8b06c48514
revert: "fix: TS error in locales list"
wait issue: https://github.com/unjs/jiti/issues/106

This reverts commit c8baff3186.
2022-12-30 02:30:41 +08:00
三咲智子
0420e3b288
i18n: translate Chinese 2022-12-30 02:30:14 +08:00
三咲智子
0c882a3576
chore: cleanup unused import 2022-12-30 01:53:26 +08:00
三咲智子
c8baff3186
fix: TS error in locales list 2022-12-30 01:52:12 +08:00
余声里
7aa3a571bc
feat(i18n): profile.appearance.label (#634)
Co-authored-by: 三咲智子 <sxzz@sxzz.moe>
2022-12-30 01:47:33 +08:00
Daniel Roe
3afbf712b3
fix: show body if there is no spoiler text (#642) 2022-12-29 17:31:04 +01:00
patak
bc868da226 feat: reordered replies in profile 2022-12-29 17:25:04 +01:00
Daniel Roe
12280afe70
feat: allow searching for statuses (#632) 2022-12-29 15:44:26 +01:00
Jacob Hands
86a604ae9c
fix: Add key to DynamicScroller slots to fix account hover (#631) 2022-12-29 14:55:09 +01:00
三咲智子
6cae9505ae
fix(status): optional boolean props 2022-12-29 21:50:11 +08:00
patak
bbc029c52f chore: release v0.1.10 2022-12-29 14:37:59 +01:00
patak
28af2f2efc feat: simplify replying to badge when it's the same as reblogger 2022-12-29 14:35:28 +01:00
patak
2a4e1bf8f6 feat: collpase self thread when possible 2022-12-29 14:21:11 +01:00
patak
3922db012f fix: edit indicator wrap for small screens 2022-12-29 14:14:52 +01:00
patak
b81ca280e5 fix: replying to self 2022-12-29 14:11:05 +01:00
Jacob Hands
7c594c68f7
fix: Remove redundant refresh in usePaginator (#626) 2022-12-29 13:30:05 +01:00
Daniel Roe
7a36fb8efd
refactor: use @nuxtjs/color-mode to manage ssr (#612) 2022-12-29 13:26:08 +01:00
Joel Drake
6fdcc558fc
fix: re-add back button (#618) 2022-12-29 13:21:00 +01:00
Joaquín Sánchez
121c90fc3a
fix: autoplay video only when on screen (#624) 2022-12-29 00:13:20 +01:00
patak
4787250df0
chore: fix readme link 2022-12-29 00:03:00 +01:00
Joaquín Sánchez
468ae88814
feat: auto play videos and gifs when on screen (#623) 2022-12-28 23:47:28 +01:00
patak
aebb02c27e chore: release v0.1.9 2022-12-28 22:46:19 +01:00
Daniel Roe
f65f9c9a1c
feat: support muting conversations (#614) 2022-12-28 22:44:23 +01:00
Jacob Hands
b6f0bd356a
fix: Streams slowing down page loads or not loading at all (#620) 2022-12-28 22:43:46 +01:00
patak
e9b1f17235
feat: simplify self reblog (#619) 2022-12-28 22:34:35 +01:00
patak
ab4ceae1e3 fix: avatar glitches in some OS/browsers 2022-12-28 22:14:29 +01:00
patak
8a338ed021 chore: release v0.1.8 2022-12-28 21:50:31 +01:00
patak
5c1a149358 fix: show explore in all screen sizes 2022-12-28 21:47:52 +01:00
Joaquín Sánchez
347cfff358
fix(a11y): disabled nav side links (#529)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2022-12-28 21:35:26 +01:00
patak
732011b520
fix: filtered post top border (#609) 2022-12-28 21:34:33 +01:00
Moritz Gießmann
80d952efa3
feat: replace "user" by "account" in German language file for gender neutrality (#617) 2022-12-28 21:33:26 +01:00
Daniel Roe
f780ed9be0
fix: respect instance media configuration (#615) 2022-12-28 20:42:31 +01:00
Joel Drake
5e86d2a3da
fix: Focus search input style on safari (#613) 2022-12-28 17:35:40 +01:00
Ayaka Rizumu
a775203bdc
feat: search in command panel (#576) 2022-12-28 17:29:07 +01:00
Daniel Roe
d585d4eeb7
fix: deduplicate incoming statuses 2022-12-28 17:21:58 +01:00
Daniel Roe
34dc2f7736
fix: handle no acct string 2022-12-28 17:01:13 +01:00
Daniel Roe
abe6af40f3
fix: cache servers (#611) 2022-12-28 16:17:37 +01:00
Daniel Roe
aeb5a40948
refactor: flatten composables and enable auto-imports on dirs (#608) 2022-12-28 15:57:06 +01:00
Daniel Roe
d569754b09
fix: allow clicking and scrolling autocompleted servers (#610) 2022-12-28 15:56:08 +01:00
Daniel Roe
377072bea7
fix: filter servers when listing them 2022-12-28 15:47:05 +01:00
patak
5c73a6f98e chore: release v0.1.7 2022-12-28 15:23:35 +01:00
patak
ae32cf87a7 fix: Notifications only mentions tab 2022-12-28 15:23:24 +01:00
Daniel Roe
726a581add
refactor: use nuxt plugin to provide pwa helpers globally (#604) 2022-12-28 15:08:03 +01:00
Chris
73cec49cf0
feat(ui): update RTL style (#592) 2022-12-28 15:05:33 +01:00
Lu[ke] Wilson
0501b98a2b
fix: change all DMs to primary colour (#602) 2022-12-28 13:30:29 +01:00
Daniel Roe
75047e878b
fix: update cache with poll votes (#598) 2022-12-28 12:49:47 +01:00
patak
15fee71c14 chore: release v0.1.6 2022-12-28 09:35:32 +01:00
patak
010bfc4179 feat: connect reblogs + direct reply in home timeline 2022-12-28 09:35:18 +01:00
Chris
107ac8a6b9
ui: fix left aside some buttons width (#588) 2022-12-28 15:00:49 +08:00
Jess
f4de4d3e3b
feat(i18n): separate en-US from en-GB locale (#589) 2022-12-28 14:50:26 +08:00
余声里
8fbf4a7628
feat(i18n): settings (#590) 2022-12-28 14:32:46 +08:00
Anthony Fu
3079867e2a refactor: setup 2022-12-28 04:50:29 +01:00
Anthony Fu
970b6538e2 fix: i18n SSR 2022-12-28 02:28:17 +01:00
Anthony Fu
d09b4deb52 fix: improve SSR for settings back button 2022-12-28 02:12:56 +01:00
Anthony Fu
d8d163dbd0 fix: rework setup to improve SSR compatibility 2022-12-28 02:06:54 +01:00
patak
fd7d30a38a chore: release v0.1.5 2022-12-28 00:26:59 +01:00
patak
7305a01d5b fix: connected replies for virtual scrolling 2022-12-28 00:25:41 +01:00
Joaquín Sánchez
ba91e0421e
fix: video autoplay (#587) 2022-12-28 00:07:33 +01:00
Anthony Fu
12942095de feat: move nav footer items to settings 2022-12-28 00:03:50 +01:00
Anthony Fu
378ba25997 ui: fix double borders 2022-12-27 23:18:16 +01:00
patak
4638a38deb fix: ltr avatar on avatar position 2022-12-27 22:48:19 +01:00
patak
26a26ba9f7
feat: search on small screens (#585) 2022-12-27 22:41:44 +01:00
Anthony Fu
ff0ad77676 fix: insert space around custom emojis 2022-12-27 22:08:48 +01:00
Joaquín Sánchez
6412127283
feat: cleanup locale conf and add some RTL stuff (#564) 2022-12-27 22:04:52 +01:00
Anthony Fu
29b7cb3838 chore: release v0.1.4 2022-12-27 21:57:17 +01:00
Anthony Fu
c38b8c13ca fix: ssr for emojis 2022-12-27 21:56:43 +01:00
Anthony Fu
2f8e47c947 chore: update snapshot 2022-12-27 21:50:40 +01:00
patak
6388b5287c fix: sorting of reblogs and favourites in grouped notifications 2022-12-27 21:49:38 +01:00
Anthony Fu
5c4cd7e992 chore: release v0.1.3 2022-12-27 21:49:00 +01:00
Anthony Fu
2d2dc64efc fix: emoji replacement error handling 2022-12-27 21:48:01 +01:00
Anthony Fu
dc94d707b0 fix: emoji replacement 2022-12-27 21:42:58 +01:00
Anthony Fu
c19dd3ee0f chore: release v0.1.2 2022-12-27 21:22:02 +01:00
Anthony Fu
fd5f817087 ui: hide info on no users 2022-12-27 21:21:53 +01:00
Anthony Fu
45d1a9a2bd feat: logged in users exports 2022-12-27 21:15:09 +01:00
patak
b1109c2ceb
feat: rework user picker (#568) 2022-12-27 21:07:19 +01:00
Anthony Fu
8bd93722e2 chore: update snapshot 2022-12-27 20:20:07 +01:00
Anthony Fu
2d4f5ddf76 chore: fix build error 2022-12-27 20:19:47 +01:00
Anthony Fu
8f68fa12e4 feat: custom emoji font in editor 2022-12-27 20:13:50 +01:00
Anthony Fu
e97068f000 chore: update snapshot 2022-12-27 19:41:01 +01:00
Joaquín Sánchez
4d21d27f94
feat: render custom server emojis on editor (#579) 2022-12-27 19:38:57 +01:00
Anthony Fu
847e64ef6d chore: clean up component 2022-12-27 19:37:53 +01:00
Anthony Fu
d9b0e85f63 feat: emoji font 2022-12-27 19:37:22 +01:00
Anthony Fu
30c8e82dbf ui: fix border 2022-12-27 19:16:45 +01:00
Anthony Fu
93c31cb2d1 ui: border for publish widget in status 2022-12-27 19:10:03 +01:00
余声里
c11f94a7e9
feat(i18n): add attachment.edit_title and action.apply (#577) 2022-12-28 02:02:40 +08:00
Anthony Fu
f621ef8b4b i18n: clean up unused keys 2022-12-27 19:00:42 +01:00
Anthony Fu
cf5e6ed5b5 i18n: rename keys 2022-12-27 18:49:23 +01:00
Anthony Fu
841959b51f feat: move flags to settings 2022-12-27 18:49:23 +01:00
patak
1b35b70e5c chore: release v0.1.1 2022-12-27 18:48:36 +01:00
patak
4f3a065927
feat: connected replies in home (#572) 2022-12-27 18:47:05 +01:00
Joaquín Sánchez
1c61aef83b
fix: emoji picker not showing emojis (#569) 2022-12-27 13:28:02 +01:00
Hopsken
f4bd2cab5c
fix: alignment issue on settings page on mobile (#571) 2022-12-27 07:07:29 +01:00
Anthony Fu
8a062f5573 ui: add more settings entry 2022-12-27 00:04:24 +01:00
Anthony Fu
93218f9d49 chore: release v0.1.0 2022-12-26 20:43:05 +01:00
Anthony Fu
e8dde2c2ba feat: display version 2022-12-26 20:33:19 +01:00
Anthony Fu
ee63bcb1b2 chore: script for release 2022-12-26 20:15:23 +01:00
三咲智子
1bf60dc4a2
fix: mention link in rich content 2022-12-27 02:39:29 +08:00
Ayo Ayco
e16b7dd9fe
fix: small "show more" button, a11y issue (#565) 2022-12-26 18:38:09 +01:00
JP
53109e7f23
feat(i18n): add arabic translations (#490)
Co-authored-by: userquin <userquin@gmail.com>
2022-12-26 16:12:04 +01:00
Daniel Roe
61df1e2da6
fix: avoid flash of sign-in button 2022-12-26 15:17:23 +01:00
Daniel Roe
4e79246df3
fix: defer loading accounts/tags until masto is initialised 2022-12-26 15:14:48 +01:00
Joaquín Sánchez
f28923f86f
fix: request push notifications on mobile (#553) 2022-12-26 10:13:59 +01:00
Ayaka Rizumu
613c5315b3
feat: added a profile settings and settings nav (#432) 2022-12-26 09:50:11 +01:00
Daniel Roe
c8a7e6e7e7
fix: use lazy pagination (#563) 2022-12-26 09:34:30 +01:00
patak
59d0cfa10e
feat: avatar on posts improvements (#561) 2022-12-26 09:00:57 +01:00
Daniel Roe
3e3a241474
fix: address some hydration issues 2022-12-26 08:47:23 +01:00
Daniel Roe
72855d7725
refactor: move post-login push logic to single place 2022-12-26 08:47:23 +01:00
patak
d9e8703882
feat: threads improvements (#562) 2022-12-26 08:37:42 +01:00
patak
baa2696d31
feat: re-apply timelines loading optimization (#524)
Co-authored-by: Daniel Roe <daniel@roe.dev>
2022-12-26 06:39:18 +01:00
Joaquín Sánchez
db7f82422e
feat: file upload error handling (#560) 2022-12-26 06:25:35 +01:00
patak
0530c6004e fix: main l/r borders 2022-12-25 21:20:14 +01:00
patak
5675d5aef9 fix: notifications spacing 2022-12-25 20:28:26 +01:00
Joaquín Sánchez
7405dee7f6
fix: emoji picker stops showing (#559) 2022-12-25 17:58:00 +01:00
Joaquín Sánchez
cf261c36cd
feat: add font size to bottom nav (#558) 2022-12-25 17:13:23 +01:00
Daniel Roe
12522d2a0c
chore: bump dependencies 2022-12-25 16:27:57 +01:00
patak
a04c84299f
feat: reduce line-height for posts (#557) 2022-12-25 16:26:43 +01:00
Daniel Roe
cca222ca6b
chore: upgrade dev dependencies 2022-12-25 16:01:57 +01:00
Daniel Roe
dc76ab2477
fix: update cache + timeline when items are updated/deleted (#556) 2022-12-25 15:52:37 +01:00
Daniel Roe
720b5114af
refactor: initialise masto outside of functions/handlers 2022-12-25 15:04:50 +01:00
Joaquín Sánchez
03d3775011
feat: show re-auth message when missing vapid_key (#542) 2022-12-25 13:45:37 +01:00
Chris
c8de9c45fa
feat(i18n): translate fontSize key (#551) 2022-12-25 13:44:59 +01:00
Lu[ke] Wilson
a1400b7fea
ui: make bio text less dim (#549) 2022-12-25 13:44:45 +01:00
Chris
bf99eca956
fix: duplicate boder in status detail (#552) 2022-12-25 13:44:18 +01:00
Joaquín Sánchez
95985d14a9
feat(i18n): font size translation for es-ES (#555) 2022-12-25 13:43:23 +01:00
Michel EDIGHOFFER
73fd577aaa
feat(i18n): update french translations (#539) 2022-12-24 15:21:22 +01:00
Anthony Fu
e7b9b5b8a6 fix: server autocomplete 2022-12-24 12:42:54 +01:00
Anthony Fu
ffe592cc57 fix: autocomplete direction 2022-12-24 02:06:46 +01:00
Anthony Fu
32f22f81d9 fix: normalize server name 2022-12-24 01:51:45 +01:00
Anthony Fu
fdf2d75d86 chore: workaround typeerror 2022-12-24 01:46:43 +01:00
Anthony Fu
b30e8a2b03 feat: server auto complete 2022-12-24 01:40:51 +01:00
Anthony Fu
52a8ae47fe feat(api): list servers 2022-12-24 01:07:38 +01:00
Anthony Fu
6c9908d030 chore: clean up 2022-12-24 00:22:57 +01:00
Anthony Fu
b40832a7eb fix: font-size ssr 2022-12-24 00:19:17 +01:00
Anthony Fu
597617b7e6 feat: custom emojis, close #500 2022-12-23 23:56:21 +01:00
patak
41ef187379 feat: font size preference 2022-12-23 23:47:13 +01:00
patak
99abb78ef1
feat: rework vertical spacing (#533) 2022-12-23 22:53:21 +01:00
Sebastian Di Luzio
823820e7c7
fix(i18n): german following (#530) 2022-12-23 21:49:38 +01:00
Anthony Fu
55443e4d8a
feat: init emoji picker (#532) 2022-12-23 20:15:19 +01:00
Joaquín Sánchez
6037700197
fix: logout without pwa (#528) 2022-12-23 19:28:10 +01:00
Anthony Fu
cd268c9bc7 ui: update button for mobile 2022-12-23 19:26:28 +01:00
Anthony Fu
589cf463bd ui: improve pwa prompt 2022-12-23 19:05:48 +01:00
Sebastian Di Luzio
41568b2c2d
fix(styling): make PWA update notification fit screen on mobile (#531) 2022-12-23 17:12:29 +01:00
Joaquín Sánchez
8bdc6d40cf
feat(a11y): aria announcer (#443) 2022-12-23 16:08:36 +01:00
Clark Cui
4b70c6b3e7
fix: image edit dialog apply button (#527) 2022-12-23 15:08:10 +01:00
Anthony Fu
0d4df4b269 ui: fix link line break 2022-12-23 11:32:00 +01:00
Clark Cui
8c53fff9af
feat: image edit dialog mobile style (#526) 2022-12-23 10:09:52 +01:00
patak
cc0472b9e6 fix: support orgs/ and sponsors/ for GitHub cards 2022-12-23 10:08:13 +01:00
patak
ef4a240800 fix: revert timelines loading optimization 2022-12-23 06:02:13 +01:00
patak
2e5270f453 fix: reverts /home special treatment
reverts commit 43515b243b.
2022-12-23 05:59:29 +01:00
patak
4f09794021 fix: replying to position for grouped likes 2022-12-22 22:39:07 +01:00
patak
43515b243b fix: revert loading optimization for /home to fix sign in 2022-12-22 22:10:50 +01:00
patak
84ea17e0cf feat: improve explore loading 2022-12-22 21:25:56 +01:00
Joaquín Sánchez
4d8b402b04
fix: account followers and following links (#519) 2022-12-22 21:15:06 +01:00
patak
fef082af13
feat: move timelines to components (#514) 2022-12-22 18:48:41 +01:00
Joaquín Sánchez
6b7a8baa8e
fix: disable push notifications & update push notifications texts (#518) 2022-12-22 18:22:00 +01:00
Clark Cui
2124e8046a
fix: content min-height (#517) 2022-12-22 17:48:57 +01:00
Sebastian Di Luzio
301c8b2612
fix: make german translation more consistent, fix typos (#499) 2022-12-22 17:32:36 +01:00
543 changed files with 51615 additions and 12486 deletions

18
.dockerignore Normal file
View file

@ -0,0 +1,18 @@
# Modified from .gitignore
node_modules
*.log
dist
.output
.nuxt
#.env # Not ignoring this file because it can contain build-related settings.
.DS_Store
.idea/
.vite-inspect
.netlify/
.eslintcache
public/emojis
*~
*swp
*swo

View file

@ -1,14 +1,19 @@
NUXT_PUBLIC_TRANSLATE_API= NUXT_PUBLIC_TRANSLATE_API=
NUXT_PUBLIC_DEFAULT_SERVER=
NUXT_PUBLIC_SINGLE_INSTANCE=
NUXT_PUBLIC_PRIVACY_POLICY_URL=
# Production only # Production only
NUXT_CLOUDFLARE_ACCOUNT_ID= NUXT_CLOUDFLARE_ACCOUNT_ID=
NUXT_CLOUDFLARE_NAMESPACE_ID= NUXT_CLOUDFLARE_NAMESPACE_ID=
NUXT_CLOUDFLARE_API_TOKEN= NUXT_CLOUDFLARE_API_TOKEN=
# 'cloudflare' | 'fs' # 'cloudflare' | 'vercel' | 'fs'
NUXT_STORAGE_DRIVER= NUXT_STORAGE_DRIVER=
NUXT_STORAGE_FS_BASE= NUXT_STORAGE_FS_BASE=
NUXT_ADMIN_KEY=
NUXT_PUBLIC_DISABLE_VERSION_CHECK= NUXT_PUBLIC_DISABLE_VERSION_CHECK=
NUXT_GITHUB_CLIENT_ID= NUXT_GITHUB_CLIENT_ID=

View file

@ -1,6 +0,0 @@
*.css
*.png
*.ico
*.toml
https-dev-config/localhost.crt
https-dev-config/localhost.key

View file

@ -1,12 +0,0 @@
{
"extends": "@antfu",
"ignorePatterns": ["!pages/public"],
"overrides": [
{
"files": ["locales/**.json"],
"rules": {
"jsonc/sort-keys": "error"
}
}
]
}

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
* text=auto eol=lf

3
.github/FUNDING.yml vendored
View file

@ -1 +1,2 @@
github: [antfu, patak-dev, sxzz, danielroe] github: [elk-zone]
open_collective: elk

5
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View file

@ -0,0 +1,5 @@
---
name: 🐞 Bug report
about: Report an issue
labels: ['s: pending triage', 'c: bug']
---

View file

@ -1,56 +0,0 @@
name: 🐞 Bug report
description: Report an issue
labels: ['s: pending triage', 'c: bug']
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
If you are unsure whether your problem is a bug or not, you can check the following:
- use our [Discord community](https://chat.elk.zone)
- open a new [discussion](https://github.com/elk-zone/elk/discussions) and ask your question there
- type: checkboxes
id: checkboxes
attributes:
label: Pre-Checks
description: Before submitting the issue, please make sure you do the following
options:
# - label: Follow our [Code of Conduct](https://github.com/elk-zone/elk/blob/main/CODE_OF_CONDUCT.md).
# required: true
# - label: Read the [Contributing Guidelines](https://github.com/elk-zone/elk/blob/main/CONTRIBUTING.md).
# required: true
- label: Check that there isn't [already an issue](https://github.com/elk-zone/elk/issues) that reports the same bug to avoid creating a duplicate.
required: true
- label: Check that this is a concrete bug. For Q&A open a [GitHub Discussion](https://github.com/elk-zone/elk/discussions) or join our [Discord Chat Server](https://chat.elk.zone).
required: true
- label: Providing a screenshot or video to reproduce the issue or show visually what was meant.
required: true
- label: I am willing to provide a PR.
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: A clear and concise description of what the bug is.
placeholder: I am doing ... What I expect is ... What actually happening is ...
validations:
required: true
- type: textarea
id: reproduction
attributes:
label: Reproduction video or screenshot
description: |
A video or screenshot that visually shows the issue.
**Tip:** You can attach images or recordings files by clicking this area to highlight it and then dragging files in.
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: |
Anything else relevant? Please tell us here, e.g. your used web browser and/or you are on desktop or mobile.
**Tip:** You can attach images or recordings files by clicking this area to highlight it and then dragging files in.

View file

@ -0,0 +1,5 @@
---
name: 🚀 New feature proposal
about: Propose a new feature
labels: 's: pending triage'
---

View file

@ -1,35 +0,0 @@
name: 🚀 New feature proposal
description: Propose a new feature
labels: ['s: pending triage'] # This will automatically assign the 's: pending triage' label
body:
- type: markdown
attributes:
value: Thanks for your interest in the project and taking the time to fill out this feature report!
- type: textarea
id: feature-description
attributes:
label: Clear and concise description of the problem
description: 'As a user I want [goal / wish] so that [benefit]. If you intend to submit a PR for this issue, tell us in the description. Thanks!'
validations:
required: true
- type: textarea
id: suggested-solution
attributes:
label: Suggested solution
description: 'In section [xy] we could provide following feature...'
validations:
required: true
- type: textarea
id: alternative
attributes:
label: Alternative
description: Clear and concise description of any alternative solutions or features you've considered.
- type: textarea
id: additional-context
attributes:
label: Additional context
description: Any other context about the feature request here.

View file

@ -1,5 +0,0 @@
---
name: Freestyle Report
about: Create a report to help us improve
labels: 'pending triage' # This will automatically assign the 'pending triage' label
---

View file

@ -1 +0,0 @@
GitHub Actions is temporary disabled as we are reaching the usage limit as a private repo. Tests have been moved to Netlify pipeline as an workaround. We shall recover this once we open up.

View file

@ -3,6 +3,14 @@
"extends": ["config:base", "schedule:weekly", "group:allNonMajor"], "extends": ["config:base", "schedule:weekly", "group:allNonMajor"],
"labels": ["c: dependencies"], "labels": ["c: dependencies"],
"rangeStrategy": "bump", "rangeStrategy": "bump",
"ignoreDeps": [
"vue",
"vue-tsc",
"typescript",
// Intl.Segmenter is not supported in Firefox
"string-length"
],
"packageRules": [ "packageRules": [
{ {
"groupName": "devDependencies", "groupName": "devDependencies",
@ -56,6 +64,10 @@
{ {
"groupName": "typescript", "groupName": "typescript",
"matchPackageNames": ["typescript"] "matchPackageNames": ["typescript"]
},
{
"matchDatasources": ["node-version"],
"enabled": false
} }
], ],
"vulnerabilityAlerts": { "vulnerabilityAlerts": {

View file

@ -1,5 +1,7 @@
name: ci name: ci
permissions: {}
on: on:
push: push:
branches: branches:
@ -7,17 +9,19 @@ on:
pull_request: pull_request:
branches: branches:
- main - main
workflow_dispatch: {}
merge_group: {}
jobs: jobs:
ci: ci:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- run: corepack enable - run: corepack enable
- uses: actions/setup-node@v3 - uses: actions/setup-node@v4
with: with:
node-version: 16 node-version: 20
cache: pnpm cache: pnpm
- name: 📦 Install dependencies - name: 📦 Install dependencies
@ -27,7 +31,8 @@ jobs:
run: pnpm nuxi prepare run: pnpm nuxi prepare
- name: 🧪 Test project - name: 🧪 Test project
run: pnpm test run: pnpm test:ci
timeout-minutes: 10
- name: 📝 Lint - name: 📝 Lint
run: pnpm lint run: pnpm lint

46
.github/workflows/docker.yml vendored Normal file
View file

@ -0,0 +1,46 @@
name: build & push docker container
on:
push:
branches:
- main
tags:
- '*'
pull_request:
branches:
- main
jobs:
docker:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Docker meta
id: metal
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository }}
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.metal.outputs.tags }}
labels: ${{ steps.metal.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

26
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,26 @@
name: Release
permissions:
contents: write
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set node
uses: actions/setup-node@v4
with:
node-version: 18
- run: npx changelogithub
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

View file

@ -19,6 +19,6 @@ jobs:
name: Semantic Pull Request name: Semantic Pull Request
steps: steps:
- name: Validate PR title - name: Validate PR title
uses: amannn/action-semantic-pull-request@v5.0.2 uses: amannn/action-semantic-pull-request@v5.4.0
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

5
.gitignore vendored
View file

@ -2,14 +2,17 @@ node_modules
*.log *.log
dist dist
.output .output
.pnpm-store
.nuxt .nuxt
.env .env
.DS_Store .DS_Store
.idea/ .idea/
.vite-inspect .vite-inspect
.netlify/ .netlify/
.eslintcache
elk-translation-status.json
public/shiki public/emojis
*~ *~
*swp *swp

2
.npmrc
View file

@ -1,3 +1,3 @@
shamefully-hoist=true shamefully-hoist=true
strict-peer-dependencies=false
shell-emulator=true shell-emulator=true
ignore-workspace-root-check=true

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
20

View file

@ -0,0 +1,7 @@
{
"bot": {
"issues": {
"trigger": "all-issues"
}
}
}

61
.vscode/settings.json vendored
View file

@ -1,23 +1,62 @@
{ {
"prettier.enable": false,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"files.associations": {
"*.css": "postcss"
},
"editor.formatOnSave": false,
"cSpell.words": [ "cSpell.words": [
"masto", "masto",
"Nuxtodon", "Nuxtodon",
"unmute", "unmute",
"unstorage" "unstorage"
], ],
"files.associations": {
"*.css": "postcss"
},
"i18n-ally.keysInUse": [
"time_ago_options.*",
"visibility.*"
],
"i18n-ally.keystyle": "nested",
"i18n-ally.localesPaths": [ "i18n-ally.localesPaths": [
"locales" "locales"
], ],
"i18n-ally.keystyle": "nested",
"i18n-ally.sourceLanguage": "en-US",
"i18n-ally.preferredDelimiter": "_", "i18n-ally.preferredDelimiter": "_",
"i18n-ally.sortKeys": true "i18n-ally.sortKeys": true,
"i18n-ally.sourceLanguage": "en",
// Enable the ESlint flat config support
"eslint.experimental.useFlatConfig": true,
// Disable the default formatter, use eslint instead
"prettier.enable": false,
"editor.formatOnSave": false,
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll": "explicit",
"source.organizeImports": "never"
},
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off" },
{ "rule": "*-indent", "severity": "off" },
{ "rule": "*-spacing", "severity": "off" },
{ "rule": "*-spaces", "severity": "off" },
{ "rule": "*-order", "severity": "off" },
{ "rule": "*-dangle", "severity": "off" },
{ "rule": "*-newline", "severity": "off" },
{ "rule": "*quotes", "severity": "off" },
{ "rule": "*semi", "severity": "off" }
],
// Enable eslint for all supported languages
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue",
"html",
"markdown",
"json",
"jsonc",
"yaml"
]
} }

22
.woodpecker.yml Normal file
View file

@ -0,0 +1,22 @@
steps:
- name: build docker
image: docker:25-cli
secrets: [user, pass]
commands:
- apk add git
- REPO=$(echo "$CI_REPO" | tr '[:upper:]' '[:lower:]')
- REGISTRY="dev.cat-enby.club"
- MAJOR=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 1 | tr -d 'v')
- MINOR=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 2)
- PATCH=$(echo ${CI_COMMIT_TAG} | cut -d '.' -f 3 | cut -d '-' -f 1)
- docker buildx build -t $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR:-0}.$${PATCH-0} -t $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR} -t $${REGISTRY}/$$REPO:v$${MAJOR:-0} -t $${REGISTRY}/$$REPO:latest .
- docker login --username $USER --password $PASS $${REGISTRY}
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR:-0}.$${PATCH-0}
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}.$${MINOR}
- docker push $${REGISTRY}/$${REPO}:v$${MAJOR:-0}
- docker push $${REGISTRY}/$${REPO}:latest
volumes:
- /var/run/docker.sock:/var/run/docker.sock
when:
- repo: nikurasu:elk-test-ci
- event: tag

45
CODE_OF_CONDUCT.md Normal file
View file

@ -0,0 +1,45 @@
# Code Of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, political party, or sexual identity and orientation. Note, however, that religion, political party, or other ideological affiliation provide no exemptions for the behavior we outline as unacceptable in this Code of Conduct.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
- Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team by DM at [the Elk Discord](https://chat.elk.zone). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org

189
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,189 @@
# Contributing Guide
Hi! We are excited that you are interested in contributing to Elk. Before submitting your contribution, please make sure to take a moment and read through the following guide.
Refer also to https://github.com/antfu/contribute.
For guidelines on contributing to the documentation, refer to the [docs README](./docs/README.md).
### Online
You can use [StackBlitz Codeflow](https://stackblitz.com/codeflow) to fix bugs or implement features. You'll also see a Codeflow button on PRs to review them without a local setup. Once the elk repo has been cloned in Codeflow, the dev server will start automatically and print the URL to open the App. You should receive a prompt in the bottom-right suggesting to open it in the Editor or in another Tab. To learn more, check out the [Codeflow docs](https://developer.stackblitz.com/codeflow/what-is-codeflow).
[![Open in Codeflow](https://developer.stackblitz.com/img/open_in_codeflow.svg)](https://pr.new/elk-zone/elk)
### Local Setup
To develop and test the Elk package:
1. Fork the Elk repository to your own GitHub account and then clone it to your local device.
2. Ensure using the latest Node.js (16.x).
If you have [nvm](https://github.com/nvm-sh/nvm), you can run `nvm i` to install the required version.
3. The package manager used to install and link dependencies must be [pnpm](https://pnpm.io/) v7. To use it you must first enable [Corepack](https://github.com/nodejs/corepack) by running `corepack enable`. (Note: on Linux in a standard Node 16+ environment, you should follow the instructions to install via Node's `corepack` rather than using the `curl` command)
4. Check out a branch where you can work and commit your changes:
```shell
git checkout -b my-new-branch
```
1. Run `pnpm i` in Elk's root folder
2. Run `pnpm nuxi prepare` in Elk's root folder
3. Run `pnpm dev` in Elk's root folder to start dev server or `pnpm dev:mocked` to start dev server with `@elkdev@universeodon.com` user.
We recommend installing [ni](https://github.com/antfu/ni#ni), that will use the right package manager in each of your projects. If `ni` is installed, you can instead run:
```
ni
nr dev
```
### Testing
Elk uses [Vitest](https://vitest.dev). You can run the test suite with:
```
nr test
```
### Running PWA on dev server
In order to run Elk with PWA enabled, run `pnpm dev:pwa` in Elk's root folder to start dev server or `pnpm dev:mocked:pwa` to start dev server with `@elkdev@universeodon.com` user.
You should test the Elk PWA application on private browsing mode on any Chromium-based browser: will not work on Firefox and Safari.
If not using private browsing mode, you will need to uninstall the PWA application from your browser once you finish testing:
- Open `Dev Tools` (`Option + ⌘ + J` on macOS, `Shift + CTRL + J` on Windows/Linux)
- Go to `Application > Storage`, you should check the following checkboxes:
- Application: [x] Unregister service worker
- Storage: [x] IndexedDB and [x] Local and session storage
- Cache: [x] Cache storage and [x] Application cache
- Click on `Clear site data` button
- Go to `Application > Service Workers` and check if the current `service worker` is missing or has the state `deleted` or `redundant`
## CI errors
Sometimes when you push your changes to create a new pull request (PR), the CI can fail, but we cannot check the logs to see what went wrong.
If you are getting **Semantic Pull Request** error, please check the [Semantic Pull Request](https://www.conventionalcommits.org/en/v1.0.0/#summary) documentation.
You can run the following commands on your local environment to fix CI errors:
- `pnpm test:unit` to run unit tests, maybe you also need to update snapshots
- `pnpm test:typecheck` to run TypeScript checks run on CI
## RTL Support
Elk supports `right-to-left` languages, we need to make sure that the UI is working correctly in both directions.
Simple approach used by most websites of relying on direction set in HTML element does not work because direction for various items, such as timeline, does not always match direction set in HTML.
We've added some `UnoCSS` utilities styles to help you with that:
- Do not use `left/right` padding and margin: for example `pl-1`. Use `padding-inline-start/end` instead. So `pl-1` should be `ps-1`, `pr-1` should be `pe-1`. The same rules apply to margin.
- Do not use `rtl-` classes, such as `rtl-left-0`.
- For icons that should be rotated for RTL, add `class="rtl-flip"`. This can only be used for icons outside of elements with `dir="auto"`, such as timeline, and is the only exception to the rule above. For icons inside the timeline, it might not work as expected.
- For absolute positioned elements, don't use `left/right`: for example `left-0`. Use `inset-inline-start/end` instead. `UnoCSS` shortcuts are `inset-is` for `inset-inline-start` and `inset-ie` for `inset-inline-end`. Example: `left-0` should be replaced with `inset-is-0`.
- If you need to change the border radius for an entire left or right side, use `border-inline-start/end`. `UnoCSS` shortcuts are `rounded-is` for left side, `rounded-ie` for right side. Example: `rounded-l-5` should be replaced with `rounded-ie-5`.
- If you need to change the border radius for one corner, use `border-start-end-radius` and similar rules. `UnoCSS` shortcuts are `rounded` + top/bottom as either `-bs` (top) or `-be` (bottom) + left/right as either `-is` (left) or `-ie` (right). Example: `rounded-tl-0` should be replaced with `rounded-bs-is-0`.
## Internationalization
We are using [vue-i18n](https://vue-i18n.intlify.dev/) via [nuxt-i18n](https://v8.i18n.nuxtjs.org/) to handle internationalization.
You can check the current [translation status](https://docs.elk.zone/docs/guide/contributing#translation-status): more instructions on the table caption.
If you are updating a translation in your local environment, you can run the following commands to check the status:
- from root folder: `nr prepare-translation-status`
- change to `docs` folder and run docs dev server `nr dev`
- open `http://localhost:3000/docs/guide/contributing#translation-status` in your browser
### Adding a new language
1. Add a new file in [locales](./locales) folder with the language code as the filename.
2. Copy [en](./locales/en.json) and translate the strings.
3. Add the language to the `locales` array in [config/i18n.ts](./config/i18n.ts#L61), below `en` and `ar`:
- If your language has multiple country variants, add the generic one for language only (only if there are a lot of common entries, you can always add it as a new one)
- Add all country variants in [country variants object](./config/i18n.ts#L12)
- Add all country variants files with empty `messages` object: `{}`
- Translate the strings in the generic language file
- Later, when anyone wants to add the corresponding translations for the country variant, just override any entry in the corresponding file: you can see an example with `en` variants.
- If the generic language already exists:
- If the translation doesn't differ from the generic language, then add the corresponding translations in the corresponding file
- If the translation differs from the generic language, then add the corresponding translations in the corresponding file and remove it from the country variants entry
4. If the language is `right-to-left`, add `dir` option with `rtl` value, for example, for [ar](./config/i18n.ts#L71)
5. If the language requires special pluralization rules, add `pluralRule` callback option, for example, for [ar](./config/i18n.ts#L72)
Check [Pluralization rule callback](https://vue-i18n.intlify.dev/guide/essentials/pluralization.html#custom-pluralization) for more info.
### Messages interpolation
Most of the messages used in Elk do not require any interpolation, however, some messages require interpolation: check [Message Format Syntax](https://vue-i18n.intlify.dev/guide/essentials/syntax.html) for more info.
We're using these types of interpolation:
- [List interpolation](https://vue-i18n.intlify.dev/guide/essentials/syntax.html#list-interpolation)
- [Named interpolation](https://vue-i18n.intlify.dev/guide/essentials/syntax.html#interpolations)
- [Linked messages](https://vue-i18n.intlify.dev/guide/essentials/syntax.html#linked-messages)
- [Literal interpolation](https://vue-i18n.intlify.dev/guide/essentials/syntax.html#literal-interpolation)
#### List interpolation
You can access the elements of the list using the object notation using the index: for example, `{0}` for the first element, `{1}` for the second, `{2}` for the third and so on.
#### Named interpolation
Elk will use named interpolation only to handle plurals for number formatting. We have 2 scenarios for this:
- using `plural` **with** `i18n-t` component
- using `plural` **without** `i18n-t` component
Check [Custom Plural Number Formatting Entries](#custom-plural-number-formatting-entries) for custom plural entries in Elk with available values for interpolation.
When using plural number formatting, we'll have always `{n}` available in the message, for example, `You have {n} new notifications|You have {n} new notification|You have {n} new notifications` or `You have no new notifications|You have 1 new notification|You have {n} new notifications`.
We've included `v` named parameter, it will be used to pass the formatted number using [Intl.NumberFormat::format](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/format): will be the number with separators symbols. The exception to the previous rule is when we're using `plural` **with** `i18n-t` component, in this case, we'll need to use `{0}` instead `{v}` to access the number.
Additionally, Elk will use [compact notation for numbers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#parameters) for some entries, check `notation` and `compactDisplay` options: for example, `1K` for `1000`, `1M` for `1000000`, `1B` for `1000000000` and so on. That entry will be available in the message using `{v}` named parameter (or `{0}` if using the message **with** `i18n-t` component).
You can run this code in your browser console to see how it works:
```ts
[1, 12, 123, 1234, 12345, 123456, 1234567].forEach((n) => {
const acc = {}
Array.from(['en-US', 'en-GB', 'de-DE', 'zh-CN', 'ja-JP', 'es-ES', 'fr-FR', 'cs-CZ', 'ar-EG']).forEach((l) => {
const nf = new Intl.NumberFormat(l, {
style: 'decimal',
maximumFractionDigits: 0,
})
const nf2 = new Intl.NumberFormat(l, {
notation: 'compact',
compactDisplay: 'short',
maximumFractionDigits: 1,
})
acc[l] = {
number: n,
format: nf.format(n),
compact: nf2.format(n),
}
})
console.table(acc)
})
```
#### Custom Plural Number Formatting Entries
**Warning**:
Either **{0}** or **{v}** should be used with the exception being custom plurals entries using the `{n}` placeholder.
This is the full list of entries that will be available for number formatting in Elk:
- `action.boost_count` (no need to be included, we should use always `en-US` entry): `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `action.favourite_count` (no need to be included, we should use always `en-US` entry): `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `action.reply_count` (no need to be included, we should use always `en-US` entry): `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `account.followers_count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `account.following_count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `account.posts_count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `compose.drafts`: `{v}` for formatted number and `{n}` for raw number - **{v} should be used**
- `notification.followed_you_count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `status.poll.count`: `{0}` for formatted number and `{n}` for raw number - **{0} should be used**
- `time_ago_options.*`: `{0}` for formatted number and `{n}` for raw number - **{0} should be used**: since numbers will be always small, we can also use `{n}`
- `timeline.show_new_items`: `{v}` for formatted number and `{n}` for raw number - **{v} should be used**

57
Dockerfile Normal file
View file

@ -0,0 +1,57 @@
FROM docker.io/library/node:lts-alpine AS base
# Prepare work directory
WORKDIR /elk
FROM base AS builder
# Prepare pnpm https://pnpm.io/installation#using-corepack
RUN corepack enable
# Prepare deps
RUN apk update
RUN apk add git --no-cache
# Prepare build deps ( ignore postinstall scripts for now )
COPY package.json ./
COPY .npmrc ./
COPY pnpm-lock.yaml ./
COPY patches ./patches
RUN pnpm i --frozen-lockfile --ignore-scripts
# Copy all source files
COPY . ./
# Run full install with every postinstall script ( This needs project file )
RUN pnpm i --frozen-lockfile
# Build
RUN pnpm build
FROM base AS runner
ARG UID=911
ARG GID=911
# Create a dedicated user and group
RUN set -eux; \
addgroup -g $GID elk; \
adduser -u $UID -D -G elk elk;
USER elk
ENV NODE_ENV=production
COPY --from=builder /elk/.output ./.output
EXPOSE 5314/tcp
ENV PORT=5314
# Specify container only environment variables ( can be overwritten by runtime env )
ENV NUXT_STORAGE_FS_BASE='/elk/data'
# Persistent storage data
VOLUME [ "/elk/data" ]
CMD ["node", ".output/server/index.mjs"]

129
README.md
View file

@ -1,35 +1,116 @@
# Elk
*A nimble Mastodon web client*
<p align="center"> <p align="center">
<a href="https://viteconf.org" target="_blank" rel="noopener noreferrer"> <a href="https://elk.zone" target="_blank" rel="noopener noreferrer">
<img width="180" src="https://elk.zone/logo.svg" alt="Vite logo"> <img width="160" height="160" src="./public/logo.svg" alt="Elk logo">
</a> </a>
</p> </p>
<h1 align="center"/>Elk <sup><em>alpha</em></sup></h1>
<p align="center">
A nimble Mastodon web client
</p>
<br/> <br/>
<p align="center"> <p align="center">
<a href="https://chat.elk.zone"><img src="https://img.shields.io/badge/chat-discord-blue?style=flat&logo=discord" alt="discord chat"></a> <a href="https://chat.elk.zone"><img src="https://img.shields.io/badge/chat-discord-blue?style=flat&logo=discord" alt="discord chat"></a>
<a href="https://pr.new/elk-zone/elk"><img src="https://developer.stackblitz.com/img/start_pr_dark_small.svg" alt="Start new PR in StackBlitz Codeflow"></a> <a href="https://pr.new/elk-zone/elk"><img src="https://developer.stackblitz.com/img/start_pr_dark_small.svg" alt="Start new PR in StackBlitz Codeflow"></a>
<a href="https://volta.net/elk-zone/elk?utm_source=elk_readme"><img src="https://user-images.githubusercontent.com/904724/209143798-32345f6c-3cf8-4e06-9659-f4ace4a6acde.svg" alt="Open board on Volta"></a>
</p> </p>
<br/> <br/>
# Elk is in early alpha ⚠️ <p align="center">
<a href="https://elk.zone/" target="_blank" rel="noopener noreferrer" >
<img src="./public/elk-og.png" alt="Elk screenshots" width="600" height="auto">
</a>
</p>
It is already quite usable, but it isn't ready for wide adoption yet. We recommend you to use if if you would like to help us building it. We appreciate your feedback and contributions. Check out the [Open Issues](https://github.com/elk-zone/elk/issues) and jump in the action. Join the [Elk discord server](https://chat.elk.zone) to chat with us and learn more about the project. ## ⚠️ Elk is in Alpha
The client is deployed to [elk.zone](https://elk.zone), you can share screenshots on social media but we prefer you avoid sharing this URL directly until the app is more polished. Feel free to share the URL with your friedns and invite others you think could be interested in helping to improve Elk. It is already quite usable, but it isn't ready for wide adoption yet. We recommend you use it if you would like to help us build it. We appreciate your feedback and contributions. Check out the [Open Issues](https://github.com/elk-zone/elk/issues) and jump in the action. Join the [Elk discord server](https://chat.elk.zone) to chat with us and learn more about the project.
# Contributing ## Deployment
### Official Deployment
The Elk team maintains a deployment at:
- 🦌 Production: [elk.zone](https://elk.zone)
- 🐙 Canary: [main.elk.zone](https://main.elk.zone) (deploys on every commit to `main` branch)
### Self-Host Docker Deployment
In order to host Elk yourself you can use the provided Dockerfile to build a container with elk. Be aware, that Elk only loads properly if the connection is done via SSL/TLS. The Docker container itself does not provide any SSL/TLS handling. You'll have to add this bit yourself.
One could put Elk behind popular reverse proxies with SSL Handling like Traefik, NGINX etc.
1. checkout source ```git clone https://github.com/elk-zone/elk.git```
1. got into new source dir: ```cd elk```
1. build Docker image: ```docker build .```
1. create local storage directory for settings: ```mkdir elk-storage```
1. adjust permissions of storage dir: ```sudo chown 911:911 ./elk-storage```
1. start container: ```docker-compose up -d```
> [!NOTE]
> The provided Dockerfile creates a container which will eventually run Elk as non-root user and create a persistent named Docker volume upon first start (if that volume does not yet exist). This volume is always created with root permission. Failing to change the permissions of ```/elk/data``` inside this volume to UID:GID 911 (as specified for Elk in the Dockerfile) will prevent Elk from storing it's config for user accounts. You either have to fix the permission in the created named volume, or mount a directory with the correct permission to ```/elk/data``` into the container.
### Ecosystem
These are known deployments using Elk as an alternative Web client for Mastodon servers or as a base for other projects in the fediverse:
- [elk.fedified.com](https://elk.fedified.com) - Use Elk to log into any compatible instance
- [elk.me.uk](https://elk.me.uk) - Use Elk to log into any compatible instance, hosted on Google Cloud Run with no Cloudflare proxy
- [elk.h4.io](https://elk.h4.io) - Use Elk for the `h4.io` Server
- [elk.universeodon.com](https://elk.universeodon.com) - Use Elk for the Universeodon Server
- [elk.vmst.io](https://elk.vmst.io) - Use Elk for the `vmst.io` Server
- [elk.hostux.social](https://elk.hostux.social) - Use Elk for the `hostux.social` Server
- [elk.cupoftea.social](https://elk.cupoftea.social) - Use Elk for the `cupoftea.social` Server
- [elk.aus.social](https://elk.aus.social) - Use Elk for the `aus.social` Server
- [elk.mstdn.ca](https://elk.mstdn.ca) - Use Elk for the `mstdn.ca` Server
- [elk.mastodonapp.uk](https://elk.mastodonapp.uk) - Use Elk for the `mastodonapp.uk` Server
- [elk.bolha.us](https://elk.bolha.us) - Use Elk for the `bolha.us` Server
> **Note**: Community deployments are **NOT** maintained by the Elk team. It may not be synced with Elk's source code. Please do your own research about the host servers before using them.
## 💖 Sponsors
We are grateful for the generous sponsorship and help of:
<a href="https://nuxtlabs.com/" target="_blank" rel="noopener noreferrer" >
<img src="./images/nuxtlabs.svg" alt="NuxtLabs" height="85">
</a>
<br><br>
<a href="https://stackblitz.com/" target="_blank" rel="noopener noreferrer" >
<img src="./images/stackblitz.svg" alt="StackBlitz" height="85">
</a>
<br><br>
And all the companies and individuals sponsoring Elk Team and the members. If you're enjoying the app, consider sponsoring us:
- [Elk Team's GitHub Sponsors](https://github.com/sponsors/elk-zone)
Or you can sponsor our core team members individually:
- [Anthony Fu](https://github.com/sponsors/antfu)
- [Daniel Roe](https://github.com/sponsors/danielroe)
- [三咲智子 Kevin Deng](https://github.com/sponsors/sxzz)
- [Patak](https://github.com/sponsors/patak-dev)
We would also appreciate sponsoring other contributors to the Elk project. If someone helps you solve an issue or implement a feature you wanted, supporting them would help make this project and OS more sustainable.
## 📍 Roadmap
[Open board on Volta](https://volta.net/elk-zone/elk)
## 🧑‍💻 Contributing
We're really excited that you're interested in contributing to Elk! Before submitting your contribution, please read through the following guide. We're really excited that you're interested in contributing to Elk! Before submitting your contribution, please read through the following guide.
## Online ### Online
You can use [StackBlitz CodeFlow](https://stackblitz.com/codeflow) to fix bugs or implement features. You'll also see a CodeFlow button on PRs to review them without a local setup. You can use [StackBlitz Codeflow](https://stackblitz.com/codeflow) to fix bugs or implement features. You'll also see a Codeflow button on PRs to review them without a local setup. Once the elk repo has been cloned in Codeflow, the dev server will start automatically and print the URL to open the App. You should receive a prompt in the bottom-right suggesting to open it in the Editor or in another Tab. To learn more, check out the [Codeflow docs](https://developer.stackblitz.com/codeflow/what-is-codeflow).
[![Open in Codeflow](https://developer.stackblitz.com/img/open_in_codeflow.svg)](https://pr.new/elk-zone/elk) [![Open in Codeflow](https://developer.stackblitz.com/img/open_in_codeflow.svg)](https://pr.new/elk-zone/elk)
## Local Setup ### Local Setup
Clone the repository and run on the root folder: Clone the repository and run on the root folder:
@ -38,6 +119,8 @@ pnpm i
pnpm run dev pnpm run dev
``` ```
`Warning`: you will need `corepack` enabled, check out the [Elk Contributing Guide](./CONTRIBUTING.md) for a detailed guide on how to set up the project locally.
We recommend installing [ni](https://github.com/antfu/ni#ni), that will use the right package manager in each of your projects. If `ni` is installed, you can instead run: We recommend installing [ni](https://github.com/antfu/ni#ni), that will use the right package manager in each of your projects. If `ni` is installed, you can instead run:
``` ```
@ -45,7 +128,7 @@ ni
nr dev nr dev
``` ```
## Testing ### Testing
Elk uses [Vitest](https://vitest.dev). You can run the test suite with: Elk uses [Vitest](https://vitest.dev). You can run the test suite with:
@ -53,7 +136,11 @@ Elk uses [Vitest](https://vitest.dev). You can run the test suite with:
nr test nr test
``` ```
# Stack ## 📲 PWA
You can consult the [PWA documentation](https://docs.elk.zone/pwa) to learn more about the PWA capabilities on Elk, how to install Elk PWA in your desktop or mobile device and some hints about PWA stuff on Elk.
## 🦄 Stack
- [Vite](https://vitejs.dev/) - Next Generation Frontend Tooling - [Vite](https://vitejs.dev/) - Next Generation Frontend Tooling
- [Nuxt](https://nuxt.com/) - The Intuitive Web Framework - [Nuxt](https://nuxt.com/) - The Intuitive Web Framework
@ -64,9 +151,15 @@ nr test
- [UnoCSS](https://uno.antfu.me/) - The instant on-demand atomic CSS engine - [UnoCSS](https://uno.antfu.me/) - The instant on-demand atomic CSS engine
- [Iconify](https://github.com/iconify/icon-sets#iconify-icon-sets-in-json-format) - Iconify icon sets in JSON format - [Iconify](https://github.com/iconify/icon-sets#iconify-icon-sets-in-json-format) - Iconify icon sets in JSON format
- [Masto.js](https://neet.github.io/masto.js) - Mastodon API client in TypeScript - [Masto.js](https://neet.github.io/masto.js) - Mastodon API client in TypeScript
- [shiki](https://shiki.matsu.io/) - A beautiful Syntax Highlighter - [shiki](https://shiki.style/) - A beautiful yet powerful syntax highlighter
- [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa) - Prompt for update and push notifications - [vite-plugin-pwa](https://github.com/vite-pwa/vite-plugin-pwa) - Prompt for update, Web Push Notifications and Web Share Target API
# License ## 👨‍💻 Contributors
MIT <a href="https://github.com/elk-zone/elk/graphs/contributors">
<img src="https://contrib.rocks/image?repo=elk-zone/elk" />
</a>
## 📄 License
[MIT](./LICENSE) &copy; 2022-PRESENT Elk contributors

26
app.vue
View file

@ -1,8 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
setupI18n()
setupPageHeader() setupPageHeader()
provideGlobalCommands() provideGlobalCommands()
const route = useRoute()
if (import.meta.server && !route.path.startsWith('/settings')) {
const url = useRequestURL()
useHead({
meta: [
{ property: 'og:url', content: `${url.origin}${route.path}` },
],
})
}
// We want to trigger rerendering the page when account changes // We want to trigger rerendering the page when account changes
const key = computed(() => `${currentUser.value?.server ?? currentServer.value}:${currentUser.value?.account.id || ''}`) const key = computed(() => `${currentUser.value?.server ?? currentServer.value}:${currentUser.value?.account.id || ''}`)
</script> </script>
@ -10,7 +21,16 @@ const key = computed(() => `${currentUser.value?.server ?? currentServer.value}:
<template> <template>
<NuxtLoadingIndicator color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)" /> <NuxtLoadingIndicator color="repeating-linear-gradient(to right,var(--c-primary) 0%,var(--c-primary-active) 100%)" />
<NuxtLayout :key="key"> <NuxtLayout :key="key">
<NuxtPage v-if="isMastoInitialised" /> <NuxtPage />
</NuxtLayout> </NuxtLayout>
<PWAPrompt /> <AriaAnnouncer />
<!-- Avatar Mask -->
<svg absolute op0 width="0" height="0">
<defs>
<clipPath id="avatar-mask" clipPathUnits="objectBoundingBox">
<path d="M 0,0.5 C 0,0 0,0 0.5,0 S 1,0 1,0.5 1,1 0.5,1 0,1 0,0.5" />
</clipPath>
</defs>
</svg>
</template> </template>

View file

@ -1,43 +0,0 @@
<script setup>
import { usePWA } from '~/composables/pwa'
const { close, needRefresh, updateServiceWorker } = usePWA()
</script>
<!-- TODO: remove shadow on mobile and position it above the bottom nav -->
<template>
<div
v-if="needRefresh"
role="alertdialog"
aria-labelledby="pwa-toast-title"
aria-describedby="pwa-toast-description"
animate animate-back-in-up md:animate-back-in-right
z11
fixed
bottom-14 md:bottom-0 right-0
m-2 p-4 w-100
bg-base border="~ base"
rounded
text-left
shadow
flex="~ gap-4"
>
<img src="/logo.svg" w-12 h-12 height="10" width="10" ma alt="logo">
<div>
<h2 id="pwa-toast-title" sr-only>
{{ $t('pwa.title') }}
</h2>
<div id="pwa-toast-message">
{{ $t('pwa.message') }}
</div>
<div mt2 flex="~ gap-4">
<button type="button" btn-solid px-4 py-1 text-center text-sm @click="updateServiceWorker()">
{{ $t('pwa.reload') }}
</button>
<button type="button" btn-outline filter-saturate-0 px-4 py-1 text-center text-sm @click="close">
{{ $t('pwa.dismiss') }}
</button>
</div>
</div>
</div>
</template>

View file

@ -1,22 +1,27 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
defineProps<{ defineProps<{
account: Account account: mastodon.v1.Account
square?: boolean
}>() }>()
const loaded = $ref(false) const loaded = ref(false)
const error = $ref(false) const error = ref(false)
</script> </script>
<template> <template>
<img <img
:key="account.avatar" :key="account.avatar"
:src="error ? 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' : account.avatar" width="400"
height="400"
select-none
:src="(error || !loaded) ? 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7' : account.avatar"
:alt="$t('account.avatar_description', [account.username])" :alt="$t('account.avatar_description', [account.username])"
loading="lazy" loading="lazy"
rounded-full class="account-avatar"
:class="loaded ? 'bg-base' : 'bg-gray:10'" :class="(loaded ? 'bg-base' : 'bg-gray:10') + (square ? ' ' : ' rounded-full')"
:style="{ 'clip-path': square ? `url(#avatar-mask)` : 'none' }"
v-bind="$attrs" v-bind="$attrs"
@load="loaded = true" @load="loaded = true"
@error="error = true" @error="error = true"

View file

@ -0,0 +1,17 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
// Avatar with a background base achieving a 3px border to be used in status cards
// The border is used for Avatar on Avatar for reblogs and connecting replies
defineProps<{
account: mastodon.v1.Account
square?: boolean
}>()
</script>
<template>
<div :key="account.avatar" v-bind="$attrs" :style="{ 'clip-path': square ? `url(#avatar-mask)` : 'none' }" :class="{ 'rounded-full': !square }" bg-base w-54px h-54px flex items-center justify-center>
<AccountAvatar :account="account" w-48px h-48px :square="square" />
</div>
</template>

View file

@ -1,15 +1,16 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { Account } from 'masto' import type { mastodon } from 'masto'
const { account, as = 'div' } = $defineProps<{
account: Account
as?: string
}>()
cacheAccount(account)
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false,
}) })
const { account, as = 'div' } = defineProps<{
account: mastodon.v1.Account
as?: string
}>()
cacheAccount(account)
</script> </script>
<template> <template>
@ -24,37 +25,30 @@ defineOptions({
<!-- User info --> <!-- User info -->
<div flex sm:flex-row flex-col flex-gap-2> <div flex sm:flex-row flex-col flex-gap-2>
<div flex items-center justify-between> <div flex items-center justify-between>
<div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ml--1> <div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ms--1>
<AccountAvatar :account="account" /> <AccountAvatar :account="account" />
</div> </div>
<a block sm:hidden href="javascript:;" @click.stop> <NuxtLink block sm:hidden href="javascript:;" @click.stop>
<AccountFollowButton :account="account" /> <AccountFollowButton :account="account" />
</a> </NuxtLink>
</div> </div>
<div sm:mt-2> <div sm:mt-2>
<div> <AccountDisplayName :account="account" font-bold text-lg line-clamp-1 ws-pre-wrap break-all />
<ContentRich
font-bold text-lg line-clamp-1 ws-pre-wrap break-all
:content="getDisplayName(account, { rich: true })"
:emojis="account.emojis"
/>
</div>
<AccountHandle text-sm :account="account" /> <AccountHandle text-sm :account="account" />
</div> </div>
</div> </div>
<!-- Note --> <!-- Note -->
<div v-if="account.note"> <div v-if="account.note" max-h-100 overflow-y-auto>
<ContentRich <ContentRich
:content="account.note" :emojis="account.emojis" :content="account.note" :emojis="account.emojis"
line-clamp-2
/> />
</div> </div>
<!-- Follow info --> <!-- Follow info -->
<div flex justify-between items-center> <div flex justify-between items-center>
<AccountPostsFollowers text-sm :account="account" /> <AccountPostsFollowers text-sm :account="account" />
<a sm:block hidden href="javascript:;" @click.stop> <NuxtLink sm:block hidden href="javascript:;" @click.stop>
<AccountFollowButton :account="account" /> <AccountFollowButton :account="account" />
</a> </NuxtLink>
</div> </div>
</div> </div>
</component> </component>

View file

@ -7,7 +7,7 @@
<!-- User info --> <!-- User info -->
<div flex sm:flex-row flex-col flex-gap-2> <div flex sm:flex-row flex-col flex-gap-2>
<div flex items-center justify-between> <div flex items-center justify-between>
<div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ml--1 of-hidden bg-base> <div w-17 h-17 rounded-full border-4 border-bg-base z-2 mt--2 ms--1 of-hidden bg-base>
<div class="flex skeleton-loading-bg" w-full h-full /> <div class="flex skeleton-loading-bg" w-full h-full />
</div> </div>
<div block sm:hidden class="skeleton-loading-bg" h-8 w-30 rounded-full /> <div block sm:hidden class="skeleton-loading-bg" h-8 w-30 rounded-full />

View file

@ -1,5 +1,21 @@
<script setup lang="ts">
defineProps<{
showLabel?: boolean
}>()
</script>
<template> <template>
<div flex="~" items-center border="~ base" text-secondary-light rounded-md px-1 text-xs my-auto> <div
{{ $t('account.bot') }} flex="~ gap1" items-center
:class="{ 'border border-base rounded-md px-1': showLabel }"
text-secondary-light
>
<slot name="prepend" />
<CommonTooltip no-auto-focus :content="$t('account.bot')" :disabled="showLabel">
<div i-mdi:robot-outline />
</CommonTooltip>
<div v-if="showLabel">
{{ $t('account.bot') }}
</div>
</div> </div>
</template> </template>

View file

@ -1,9 +1,10 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
const { account } = defineProps<{ const { account } = defineProps<{
account: Account account: mastodon.v1.Account
hoverCard?: boolean hoverCard?: boolean
relationshipContext?: 'followedBy' | 'following'
}>() }>()
cacheAccount(account) cacheAccount(account)
@ -18,8 +19,10 @@ cacheAccount(account)
overflow-hidden overflow-hidden
:to="getAccountRoute(account)" :to="getAccountRoute(account)"
/> />
<div h-full p1 shrink-0> <slot>
<AccountFollowButton :account="account" /> <div h-full p1 shrink-0>
</div> <AccountFollowButton :account="account" :context="relationshipContext" />
</div>
</slot>
</div> </div>
</template> </template>

View file

@ -0,0 +1,17 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
const { account, hideEmojis = false } = defineProps<{
account: mastodon.v1.Account
hideEmojis?: boolean
}>()
</script>
<template>
<ContentRich
:content="getDisplayName(account, { rich: true })"
:emojis="account.emojis"
:hide-emojis="hideEmojis"
:markdown="false"
/>
</template>

View file

@ -1,77 +1,71 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account, Relationship } from 'masto' import type { mastodon } from 'masto'
import { toggleFollowAccount, useRelationship } from '~~/composables/masto/relationship'
const { account, command, ...props } = defineProps<{ const { account, command, context, ...props } = defineProps<{
account: Account account: mastodon.v1.Account
relationship?: Relationship relationship?: mastodon.v1.Relationship
context?: 'followedBy' | 'following'
command?: boolean command?: boolean
}>() }>()
const isSelf = $computed(() => currentUser.value?.account.id === account.id) const { t } = useI18n()
const enable = $computed(() => !isSelf && currentUser.value) const isSelf = useSelfAccount(() => account)
const relationship = $computed(() => props.relationship || useRelationship(account).value) const enable = computed(() => !isSelf.value && currentUser.value)
const relationship = computed(() => props.relationship || useRelationship(account).value)
const isLoading = computed(() => relationship.value === undefined)
async function toggleFollow() { const { client } = useMasto()
relationship!.following = !relationship!.following
try {
const newRel = await useMasto().accounts[relationship!.following ? 'follow' : 'unfollow'](account.id)
Object.assign(relationship!, newRel)
}
catch {
// TODO error handling
relationship!.following = !relationship!.following
}
}
async function unblock() { async function unblock() {
relationship!.blocking = false relationship.value!.blocking = false
try { try {
const newRel = await useMasto().accounts.unblock(account.id) const newRel = await client.value.v1.accounts.$select(account.id).unblock()
Object.assign(relationship!, newRel) Object.assign(relationship!, newRel)
} }
catch { catch (err) {
console.error(err)
// TODO error handling // TODO error handling
relationship!.blocking = true relationship.value!.blocking = true
} }
} }
async function unmute() { async function unmute() {
relationship!.muting = false relationship.value!.muting = false
try { try {
const newRel = await useMasto().accounts.unmute(account.id) const newRel = await client.value.v1.accounts.$select(account.id).unmute()
Object.assign(relationship!, newRel) Object.assign(relationship!, newRel)
} }
catch { catch (err) {
console.error(err)
// TODO error handling // TODO error handling
relationship!.muting = true relationship.value!.muting = true
} }
} }
const { t } = useI18n()
useCommand({ useCommand({
scope: 'Actions', scope: 'Actions',
order: -2, order: -2,
visible: () => command && enable, visible: () => command && enable,
name: () => `${relationship?.following ? t('account.unfollow') : t('account.follow')} ${getShortHandle(account)}`, name: () => `${relationship.value?.following ? t('account.unfollow') : t('account.follow')} ${getShortHandle(account)}`,
icon: 'i-ri:star-line', icon: 'i-ri:star-line',
onActivate: () => toggleFollow(), onActivate: () => toggleFollowAccount(relationship.value!, account),
}) })
const buttonStyle = $computed(() => { const buttonStyle = computed(() => {
// Skeleton while loading, avoid primary color flash if (relationship.value?.blocking)
if (!relationship)
return 'text-inverted'
if (relationship.blocking)
return 'text-inverted bg-red border-red' return 'text-inverted bg-red border-red'
if (relationship.muting) if (relationship.value?.muting)
return 'text-base bg-code border-base' return 'text-base bg-card border-base'
// If following, use a label style with a strong border for Mutuals // If following, use a label style with a strong border for Mutuals
if (relationship.following) if (relationship.value ? relationship.value.following : context === 'following')
return `text-base ${relationship.followedBy ? 'border-strong' : 'border-base'}` return `text-base ${relationship.value?.followedBy ? 'border-strong' : 'border-base'}`
// If loading, use a plain style
if (isLoading.value)
return 'text-base border-base'
// If not following, use a button style // If not following, use a button style
return 'text-inverted bg-primary border-primary' return 'text-inverted bg-primary border-primary'
@ -82,34 +76,39 @@ const buttonStyle = $computed(() => {
<button <button
v-if="enable" v-if="enable"
gap-1 items-center group gap-1 items-center group
:disabled="relationship?.requested"
border-1 border-1
rounded-full flex="~ gap2 center" font-500 w-30 h-fit py1 rounded-full flex="~ gap2 center" font-500 min-w-30 h-fit px3 py1
:class="buttonStyle" :class="buttonStyle"
:hover="!relationship?.blocking && !relationship?.muting && relationship?.following ? 'border-red text-red' : 'bg-base border-primary text-primary'" :hover="!relationship?.blocking && !relationship?.muting && relationship?.following ? 'border-red text-red' : 'bg-base border-primary text-primary'"
@click="relationship?.blocking ? unblock() : relationship?.muting ? unmute() : toggleFollow()" @click="relationship?.blocking ? unblock() : relationship?.muting ? unmute() : toggleFollowAccount(relationship!, account)"
> >
<template v-if="relationship?.blocking"> <template v-if="isLoading">
<span group-hover="hidden">{{ $t('account.blocking') }}</span> <span i-svg-spinners-180-ring-with-bg />
<span hidden group-hover="inline">{{ $t('account.unblock') }}</span>
</template>
<template v-if="relationship?.muting">
<span group-hover="hidden">{{ $t('account.muting') }}</span>
<span hidden group-hover="inline">{{ $t('account.unmute') }}</span>
</template>
<template v-else-if="relationship?.following">
<span group-hover="hidden">{{ relationship?.followedBy ? $t('account.mutuals') : $t('account.following') }}</span>
<span hidden group-hover="inline">{{ $t('account.unfollow') }}</span>
</template>
<template v-else-if="relationship?.requested">
<span>{{ $t('account.follow_requested') }}</span>
</template>
<template v-else-if="relationship?.followedBy">
<span group-hover="hidden">{{ $t('account.follows_you') }}</span>
<span hidden group-hover="inline">{{ $t('account.follow_back') }}</span>
</template> </template>
<template v-else> <template v-else>
<span>{{ $t('account.follow') }}</span> <template v-if="relationship?.blocking">
<span elk-group-hover="hidden">{{ $t('account.blocking') }}</span>
<span hidden elk-group-hover="inline">{{ $t('account.unblock') }}</span>
</template>
<template v-if="relationship?.muting">
<span elk-group-hover="hidden">{{ $t('account.muting') }}</span>
<span hidden elk-group-hover="inline">{{ $t('account.unmute') }}</span>
</template>
<template v-else-if="relationship ? relationship.following : context === 'following'">
<span elk-group-hover="hidden">{{ relationship?.followedBy ? $t('account.mutuals') : $t('account.following') }}</span>
<span hidden elk-group-hover="inline">{{ $t('account.unfollow') }}</span>
</template>
<template v-else-if="relationship?.requested">
<span elk-group-hover="hidden">{{ $t('account.follow_requested') }}</span>
<span hidden elk-group-hover="inline">{{ $t('account.withdraw_follow_request') }}</span>
</template>
<template v-else-if="relationship ? relationship.followedBy : context === 'followedBy'">
<span elk-group-hover="hidden">{{ $t('account.follows_you') }}</span>
<span hidden elk-group-hover="inline">{{ account.locked ? $t('account.request_follow') : $t('account.follow_back') }}</span>
</template>
<template v-else>
<span>{{ account.locked ? $t('account.request_follow') : $t('account.follow') }}</span>
</template>
</template> </template>
</button> </button>
</template> </template>

View file

@ -0,0 +1,68 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
const { account, ...props } = defineProps<{
account: mastodon.v1.Account
relationship?: mastodon.v1.Relationship
}>()
const relationship = computed(() => props.relationship || useRelationship(account).value)
const { client } = useMasto()
async function authorizeFollowRequest() {
relationship.value!.requestedBy = false
relationship.value!.followedBy = true
try {
const newRel = await client.value.v1.followRequests.$select(account.id).authorize()
Object.assign(relationship!, newRel)
}
catch (err) {
console.error(err)
relationship.value!.requestedBy = true
relationship.value!.followedBy = false
}
}
async function rejectFollowRequest() {
relationship.value!.requestedBy = false
try {
const newRel = await client.value.v1.followRequests.$select(account.id).reject()
Object.assign(relationship!, newRel)
}
catch (err) {
console.error(err)
relationship.value!.requestedBy = true
}
}
</script>
<template>
<div flex gap-4>
<template v-if="relationship?.requestedBy">
<CommonTooltip :content="$t('account.authorize')" no-auto-focus>
<button
type="button"
rounded-full text-sm p2 border-1
hover:text-green transition-colors
@click="authorizeFollowRequest"
>
<span block text-current i-ri:check-fill />
</button>
</CommonTooltip>
<CommonTooltip :content="$t('account.reject')" no-auto-focus>
<button
type="button"
rounded-full text-sm p2 border-1
hover:text-red transition-colors
@click="rejectFollowRequest"
>
<span block text-current i-ri:close-fill />
</button>
</CommonTooltip>
</template>
<template v-else>
<span text-secondary>
{{ relationship?.followedBy ? $t('account.authorized') : $t('account.rejected') }}
</span>
</template>
</div>
</template>

View file

@ -1,15 +1,15 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
const { account } = defineProps<{ const { account } = defineProps<{
account: Account account: mastodon.v1.Account
}>() }>()
const serverName = $computed(() => getServerName(account)) const serverName = computed(() => getServerName(account))
</script> </script>
<template> <template>
<p line-clamp-1 whitespace-pre-wrap break-all text-secondary-light> <p line-clamp-1 whitespace-pre-wrap break-all text-secondary-light leading-tight dir="ltr">
<!-- fix: #274 only line-clamp-1 can be used here, using text-ellipsis is not valid --> <!-- fix: #274 only line-clamp-1 can be used here, using text-ellipsis is not valid -->
<span text-secondary>{{ getShortHandle(account) }}</span> <span text-secondary>{{ getShortHandle(account) }}</span>
<span v-if="serverName" text-secondary-light>@{{ serverName }}</span> <span v-if="serverName" text-secondary-light>@{{ serverName }}</span>

View file

@ -1,30 +1,37 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account, Field } from 'masto' import type { mastodon } from 'masto'
const { account } = defineProps<{ const { account } = defineProps<{
account: Account account: mastodon.v1.Account
command?: boolean command?: boolean
}>() }>()
const { client } = useMasto()
const { t } = useI18n() const { t } = useI18n()
const createdAt = $(useFormattedDateTime(() => account.createdAt, { const createdAt = useFormattedDateTime(() => account.createdAt, {
month: 'long', month: 'long',
day: 'numeric', day: 'numeric',
year: 'numeric', year: 'numeric',
})) })
const namedFields = ref<Field[]>([]) const relationship = useRelationship(account)
const iconFields = ref<Field[]>([])
const namedFields = ref<mastodon.v1.AccountField[]>([])
const iconFields = ref<mastodon.v1.AccountField[]>([])
const isEditingPersonalNote = ref<boolean>(false)
const hasHeader = computed(() => !account.header.endsWith('/original/missing.png'))
const isCopied = ref<boolean>(false)
function getFieldNameIcon(fieldName: string) {
const name = fieldName.trim().toLowerCase()
return ACCOUNT_FIELD_ICONS[name] || undefined
}
function getFieldIconTitle(fieldName: string) { function getFieldIconTitle(fieldName: string) {
return fieldName === 'Joined' ? t('account.joined') : fieldName return fieldName === 'Joined' ? t('account.joined') : fieldName
} }
function getNotificationIconTitle() {
return relationship.value?.notifying ? t('account.notifications_on_post_disable', { username: `@${account.username}` }) : t('account.notifications_on_post_enable', { username: `@${account.username}` })
}
function previewHeader() { function previewHeader() {
openMediaPreview([{ openMediaPreview([{
id: `${account.acct}:header`, id: `${account.acct}:header`,
@ -43,12 +50,24 @@ function previewAvatar() {
}]) }])
} }
async function toggleNotifications() {
relationship.value!.notifying = !relationship.value?.notifying
try {
const newRel = await client.value.v1.accounts.$select(account.id).follow({ notify: relationship.value?.notifying })
Object.assign(relationship!, newRel)
}
catch {
// TODO error handling
relationship.value!.notifying = !relationship.value?.notifying
}
}
watchEffect(() => { watchEffect(() => {
const named: Field[] = [] const named: mastodon.v1.AccountField[] = []
const icons: Field[] = [] const icons: mastodon.v1.AccountField[] = []
account.fields?.forEach((field) => { account.fields?.forEach((field) => {
const icon = getFieldNameIcon(field.name) const icon = getAccountFieldIcon(field.name)
if (icon) if (icon)
icons.push(field) icons.push(field)
else else
@ -56,66 +75,200 @@ watchEffect(() => {
}) })
icons.push({ icons.push({
name: 'Joined', name: 'Joined',
value: createdAt, value: createdAt.value,
}) })
namedFields.value = named namedFields.value = named
iconFields.value = icons iconFields.value = icons
}) })
const personalNoteDraft = ref(relationship.value?.note ?? '')
watch(relationship, (relationship, oldValue) => {
if (!oldValue && relationship)
personalNoteDraft.value = relationship.note ?? ''
})
async function editNote(event: Event) {
if (!event.target || !('value' in event.target) || !relationship.value)
return
const newNote = event.target?.value as string
if (relationship.value.note?.trim() === newNote.trim())
return
const newNoteApiResult = await client.value.v1.accounts.$select(account.id).note.create({ comment: newNote })
relationship.value.note = newNoteApiResult.note
personalNoteDraft.value = relationship.value.note ?? ''
}
const isSelf = useSelfAccount(() => account)
const isNotifiedOnPost = computed(() => !!relationship.value?.notifying)
const personalNoteMaxLength = 2000
async function copyAccountName() {
try {
const shortHandle = getShortHandle(account)
const serverName = getServerName(account)
const accountName = `${shortHandle}@${serverName}`
await navigator.clipboard.writeText(accountName)
}
catch (err) {
console.error('Failed to copy account name:', err)
}
isCopied.value = true
setTimeout(() => {
isCopied.value = false
}, 2000)
}
</script> </script>
<template> <template>
<div flex flex-col> <div flex flex-col>
<button border="b base" z-1> <div v-if="relationship?.requestedBy" p-4 flex justify-between items-center bg-card>
<img h-50 height="200" w-full object-cover :src="account.header" :alt="t('account.profile_description', [account.username])" @click="previewHeader"> <span text-primary font-bold>{{ $t('account.requested', [account.displayName]) }}</span>
</button> <AccountFollowRequestButton :account="account" :relationship="relationship" />
</div>
<component :is="hasHeader ? 'button' : 'div'" border="b base" z-1 @click="hasHeader ? previewHeader() : undefined">
<img h-50 height="200" w-full object-cover :src="account.header" :alt="t('account.profile_description', [account.username])">
</component>
<div p4 mt--18 flex flex-col gap-4> <div p4 mt--18 flex flex-col gap-4>
<div relative> <div relative>
<div flex="~ col gap-2 1"> <div flex justify-between>
<button w-30 h-30 rounded-full border-4 border-bg-base z-2 @click="previewAvatar"> <button shrink-0 h-full :class="{ 'rounded-full': !isSelf, 'squircle': isSelf }" p1 bg-base border-bg-base z-2 @click="previewAvatar">
<AccountAvatar :account="account" hover:opacity-90 transition-opacity /> <AccountAvatar :square="isSelf" :account="account" hover:opacity-90 transition-opacity w-28 h-28 />
</button> </button>
<div flex flex-col> <div inset-ie-0 flex="~ wrap row-reverse" gap-2 items-center pt18 justify-start>
<div flex justify-between> <!-- Edit profile -->
<ContentRich <NuxtLink
font-bold sm:text-2xl text-xl v-if="isSelf"
:content="getDisplayName(account, { rich: true })" to="/settings/profile/appearance"
:emojis="account.emojis" gap-1 items-center border="1" rounded-full flex="~ gap2 center" font-500 min-w-30 h-fit px3 py1
:markdown="false" hover="border-primary text-primary bg-active"
>
{{ $t('settings.profile.appearance.title') }}
</NuxtLink>
<AccountFollowButton :account="account" :command="command" />
<span inset-ie-0 flex gap-2 items-center>
<AccountMoreButton
:account="account" :command="command"
@add-note="isEditingPersonalNote = true"
@remove-note="() => { isEditingPersonalNote = false; personalNoteDraft = '' }"
/> />
<AccountBotIndicator v-if="account.bot" /> <CommonTooltip v-if="!isSelf && relationship?.following" :content="getNotificationIconTitle()">
</div> <button
<AccountHandle :account="account" /> :aria-pressed="isNotifiedOnPost"
:aria-label="t('account.notifications_on_post_enable', { username: `@${account.username}` })"
rounded-full text-sm p2 border-1 transition-colors
:class="isNotifiedOnPost ? 'text-primary border-primary hover:bg-red/20 hover:text-red hover:border-red' : 'border-base hover:text-primary'"
@click="toggleNotifications"
>
<span v-if="isNotifiedOnPost" i-ri:notification-4-fill block text-current />
<span v-else i-ri-notification-4-line block text-current />
</button>
</CommonTooltip>
<CommonTooltip :content="$t('list.modify_account')">
<VDropdown v-if="!isSelf && relationship?.following">
<button
:aria-label="$t('list.modify_account')"
rounded-full text-sm p2 border-1 transition-colors
border-base hover:text-primary
>
<span i-ri:play-list-add-fill block text-current />
</button>
<template #popper>
<ListLists :user-id="account.id" />
</template>
</VDropdown>
</CommonTooltip>
</span>
</div> </div>
</div> </div>
<div absolute top-18 right-0 flex gap-2 items-center> <div flex="~ col gap1" pt2>
<AccountMoreButton :account="account" :command="command" /> <div flex gap2 items-center flex-wrap>
<AccountFollowButton :account="account" :command="command" /> <AccountDisplayName :account="account" font-bold sm:text-2xl text-xl />
<!-- <button flex gap-1 items-center w-full rounded op75 hover="op100 text-purple" group> <AccountRolesIndicator v-if="account.roles?.length" :account="account" />
<div rounded p2 group-hover="bg-rose/10"> <AccountLockIndicator v-if="account.locked" show-label />
<div i-ri:bell-line /> <AccountBotIndicator v-if="account.bot" show-label />
</div> </div>
</button> -->
<div flex items-center gap-1>
<AccountHandle :account="account" overflow-unset line-clamp-unset />
<CommonTooltip placement="bottom" :content="$t('account.copy_account_name')" no-auto-focus flex>
<button text-secondary-light text-sm :class="isCopied ? 'i-ri:check-fill text-green' : 'i-ri:file-copy-line'" @click="copyAccountName">
<span sr-only>{{ $t('account.copy_account_name') }}</span>
</button>
</CommonTooltip>
</div>
</div> </div>
</div> </div>
<div v-if="account.note"> <label
<ContentRich text-4 text-secondary :content="account.note" :emojis="account.emojis" /> v-if="isEditingPersonalNote || (relationship?.note && relationship.note.length > 0)"
space-y-2
pb-4
block
border="b base"
>
<div flex flex-row space-x-2 flex-v-center>
<div i-ri-edit-2-line />
<p font-medium>
{{ $t('account.profile_personal_note') }}
</p>
<p text-secondary text-sm :class="{ 'text-orange': personalNoteDraft.length > (personalNoteMaxLength - 100) }">
{{ personalNoteDraft.length }} / {{ personalNoteMaxLength }}
</p>
</div>
<div position-relative>
<div
input-base
min-h-10ex
whitespace-pre-wrap
opacity-0
:class="{ 'trailing-newline': personalNoteDraft.endsWith('\n') }"
>
{{ personalNoteDraft }}
</div>
<textarea
v-model="personalNoteDraft"
input-base
position-absolute
style="height: 100%"
top-0
resize-none
:maxlength="personalNoteMaxLength"
@change="editNote"
/>
</div>
</label>
<div v-if="account.note" max-h-100 overflow-y-auto>
<ContentRich text-4 text-base :content="account.note" :emojis="account.emojis" />
</div> </div>
<div v-if="namedFields.length" flex="~ col wrap gap1"> <div v-if="namedFields.length" flex="~ col wrap gap1">
<div v-for="field in namedFields" :key="field.name" flex="~ gap-1" items-center> <div v-for="field in namedFields" :key="field.name" flex="~ gap-1" items-center>
<div text-secondary uppercase text-xs font-bold> <div mt="0.5" text-secondary uppercase text-xs font-bold>
{{ field.name }} | <ContentRich :content="field.name" :emojis="account.emojis" />
</div> </div>
<span text-secondary text-xs font-bold>|</span>
<ContentRich :content="field.value" :emojis="account.emojis" /> <ContentRich :content="field.value" :emojis="account.emojis" />
</div> </div>
</div> </div>
<div v-if="iconFields.length" flex="~ wrap gap-4"> <div v-if="iconFields.length" flex="~ wrap gap-2">
<div v-for="field in iconFields" :key="field.name" flex="~ gap-1" items-center> <div v-for="field in iconFields" :key="field.name" flex="~ gap-1" px1 items-center :class="`${field.verifiedAt ? 'border-1 rounded-full border-dark' : ''}`">
<div text-secondary :class="getFieldNameIcon(field.name)" :title="getFieldIconTitle(field.name)" /> <CommonTooltip :content="getFieldIconTitle(field.name)">
<ContentRich text-sm filter-saturate-0 :content="field.value" :emojis="account.emojis" /> <div text-secondary :class="getAccountFieldIcon(field.name)" :title="getFieldIconTitle(field.name)" />
</CommonTooltip>
<ContentRich text-sm :content="field.value" :emojis="account.emojis" />
</div> </div>
</div> </div>
<AccountPostsFollowers :account="account" /> <AccountPostsFollowers :account="account" />
</div> </div>
</div> </div>
</template> </template>
<style>
.trailing-newline::after {
content: '\a';
}
</style>

View file

@ -1,22 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
const { account } = defineProps<{ const { account } = defineProps<{
account: Account account: mastodon.v1.Account
}>() }>()
const relationship = $(useRelationship(account)) const relationship = useRelationship(account)
</script> </script>
<template> <template>
<div v-show="relationship" flex="~ col gap2" rounded min-w-90 max-w-120 z-100 overflow-hidden p-4> <div v-show="relationship" flex="~ col gap2" rounded min-w-90 max-w-120 z-100 overflow-hidden p-4>
<div flex="~ gap2" items-center> <div flex="~ gap2" items-center>
<NuxtLink :to="getAccountRoute(account)" flex-auto rounded-full hover:bg-active transition-100 pr5 mr-a> <NuxtLink :to="getAccountRoute(account)" flex-auto rounded-full hover:bg-active transition-100 pe5 me-a>
<AccountInfo :account="account" /> <AccountInfo :account="account" />
</NuxtLink> </NuxtLink>
<AccountFollowButton text-sm :account="account" :relationship="relationship" /> <AccountFollowButton text-sm :account="account" :relationship="relationship" />
</div> </div>
<ContentRich text-4 text-secondary :content="account.note" :emojis="account.emojis" /> <div v-if="account.note" max-h-100 overflow-y-auto>
<AccountPostsFollowers text-sm :account="account" /> <ContentRich text-4 text-secondary :content="account.note" :emojis="account.emojis" />
</div>
<AccountPostsFollowers text-sm :account="account" :is-hover-card="true" />
</div> </div>
</template> </template>

View file

@ -1,24 +1,69 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
import { fetchAccountByHandle } from '~/composables/cache'
type WatcherType = [acc?: mastodon.v1.Account | null, h?: string, v?: boolean]
defineOptions({
inheritAttrs: false,
})
const props = defineProps<{ const props = defineProps<{
account?: Account account?: mastodon.v1.Account | null
handle?: string handle?: string
disabled?: boolean disabled?: boolean
}>() }>()
const account = props.account || (props.handle ? useAccountByHandle(props.handle!) : undefined) const accountHover = ref()
defineOptions({ const hovered = useElementHover(accountHover)
inheritAttrs: false, const account = ref<mastodon.v1.Account | null | undefined>(props.account)
})
watch(
() => [props.account, props.handle, hovered.value] satisfies WatcherType,
([newAccount, newHandle, newVisible], oldProps) => {
if (!newVisible || process.test)
return
if (newAccount) {
account.value = newAccount
return
}
if (newHandle) {
const [_oldAccount, oldHandle, _oldVisible] = oldProps ?? [undefined, undefined, false]
if (!oldHandle || newHandle !== oldHandle || !account.value) {
// new handle can be wrong: using server instead of webDomain
fetchAccountByHandle(newHandle).then((acc) => {
if (newHandle === props.handle)
account.value = acc
})
}
return
}
account.value = undefined
},
{ immediate: true, flush: 'post' },
)
const userSettings = useUserSettings()
</script> </script>
<template> <template>
<VMenu v-if="!disabled && account" placement="bottom-start" :delay="{ show: 500, hide: 100 }" v-bind="$attrs" :close-on-content-click="false"> <span ref="accountHover">
<slot /> <VMenu
<template #popper> v-if="!disabled && account && !getPreferences(userSettings, 'hideAccountHoverCard')"
<AccountHoverCard v-if="account" :account="account" /> placement="bottom-start"
</template> :delay="{ show: 500, hide: 100 }"
</VMenu> v-bind="$attrs"
<slot v-else /> :close-on-content-click="false"
>
<slot />
<template #popper>
<AccountHoverCard v-if="account" :account="account" />
</template>
</VMenu>
<slot v-else />
</span>
</template> </template>

View file

@ -1,34 +1,33 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
const { account, as = 'div' } = defineProps<{
account: Account
as?: string
hoverCard?: boolean
}>()
defineOptions({ defineOptions({
inheritAttrs: false, inheritAttrs: false,
}) })
const { account, as = 'div' } = defineProps<{
account: mastodon.v1.Account
as?: string
hoverCard?: boolean
square?: boolean
}>()
</script> </script>
<!-- TODO: Make this work for both buttons and links --> <!-- TODO: Make this work for both buttons and links -->
<!-- This is sometimes (like in the sidebar) used directly as a button, and sometimes, like in follow notifications, as a link. I think this component may need a second refactor that either lets an implementation pass in a link or an action and adapt to what's passed in, or the implementations need to be updated to wrap in the action they want to take and this be just the layout for these items --> <!-- This is sometimes (like in the sidebar) used directly as a button, and sometimes, like in follow notifications, as a link. I think this component may need a second refactor that either lets an implementation pass in a link or an action and adapt to what's passed in, or the implementations need to be updated to wrap in the action they want to take and this be just the layout for these items -->
<template> <template>
<component :is="as" flex gap-3 v-bind="$attrs"> <component :is="as" flex gap-3 v-bind="$attrs">
<AccountHoverWrapper :disabled="!hoverCard" :account="account" shrink-0> <AccountHoverWrapper :disabled="!hoverCard" :account="account">
<AccountAvatar :account="account" w-12 h-12 /> <AccountBigAvatar :account="account" shrink-0 :square="square" />
</AccountHoverWrapper> </AccountHoverWrapper>
<div flex="~ col" shrink overflow-hidden> <div flex="~ col" shrink pt-1 h-full overflow-hidden justify-center leading-none select-none>
<div flex="~" gap-2> <div flex="~" gap-2>
<ContentRich <AccountDisplayName :account="account" font-bold line-clamp-1 ws-pre-wrap break-all text-lg />
font-bold line-clamp-1 ws-pre-wrap break-all <AccountRolesIndicator v-if="account.roles?.length" :account="account" :limit="1" />
:content="getDisplayName(account, { rich: true })" <AccountLockIndicator v-if="account.locked" text-xs />
:emojis="account.emojis" <AccountBotIndicator v-if="account.bot" text-xs />
/>
<AccountBotIndicator v-if="account.bot" />
</div> </div>
<AccountHandle :account="account" text-sm text-secondary-light /> <AccountHandle :account="account" text-secondary-light />
</div> </div>
</component> </component>
</template> </template>

View file

@ -1,26 +1,31 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
const { link = true, avatar = true } = defineProps<{ const { link = true, avatar = true } = defineProps<{
account: Account account: mastodon.v1.Account
link?: boolean link?: boolean
avatar?: boolean avatar?: boolean
}>() }>()
const userSettings = useUserSettings()
</script>
<script lang="ts">
export default {
inheritAttrs: false,
}
</script> </script>
<template> <template>
<AccountHoverWrapper :account="account"> <AccountHoverWrapper :account="account">
<NuxtLink <NuxtLink
:to="link ? getAccountRoute(account) : undefined" :to="link ? getAccountRoute(account) : undefined"
:class="link ? 'text-link-rounded ml-0 pl-0' : ''" :class="link ? 'text-link-rounded -ml-1.5rem pl-1.5rem rtl-(ml0 pl-0.5rem -mr-1.5rem pr-1.5rem)' : ''"
v-bind="$attrs"
min-w-0 flex gap-2 items-center min-w-0 flex gap-2 items-center
> >
<AccountAvatar v-if="avatar" :account="account" w-5 h-5 /> <AccountAvatar v-if="avatar" :account="account" w-5 h-5 />
<ContentRich <AccountDisplayName :account="account" :hide-emojis="getPreferences(userSettings, 'hideUsernameEmojis')" line-clamp-1 ws-pre-wrap break-all />
line-clamp-1 ws-pre-wrap break-all
:content="getDisplayName(account, { rich: true })"
:emojis="account.emojis"
/>
</NuxtLink> </NuxtLink>
</AccountHoverWrapper> </AccountHoverWrapper>
</template> </template>

View file

@ -0,0 +1,23 @@
<script setup lang="ts">
defineProps<{
showLabel?: boolean
}>()
const { t } = useI18n()
</script>
<template>
<div
flex="~ gap1" items-center
:class="{ 'border border-base rounded-md px-1': showLabel }"
text-secondary-light
>
<slot name="prepend" />
<CommonTooltip no-auto-focus content="Lock" :disabled="showLabel">
<div i-ri:lock-line />
</CommonTooltip>
<div v-if="showLabel">
{{ t('account.lock') }}
</div>
</div>
</template>

View file

@ -1,44 +1,63 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
import { toggleBlockAccount, toggleBlockDomain, toggleMuteAccount } from '~~/composables/masto/relationship'
const { account } = defineProps<{ const { account } = defineProps<{
account: Account account: mastodon.v1.Account
command?: boolean command?: boolean
}>() }>()
let relationship = $(useRelationship(account)) const emit = defineEmits<{
(evt: 'addNote'): void
(evt: 'removeNote'): void
}>()
const isSelf = $computed(() => currentUser.value?.account.id === account.id) const relationship = useRelationship(account)
const toggleMute = async () => { const isSelf = useSelfAccount(() => account)
// TODO: Add confirmation
relationship!.muting = !relationship!.muting const { t } = useI18n()
relationship = relationship!.muting const { client } = useMasto()
? await useMasto().accounts.mute(account.id, { const useStarFavoriteIcon = usePreferences('useStarFavoriteIcon')
// TODO support more options const { share, isSupported: isShareSupported } = useShare()
function shareAccount() {
share({ url: location.href })
}
async function toggleReblogs() {
if (!relationship.value!.showingReblogs) {
const dialogChoice = await openConfirmDialog({
title: t('confirm.show_reblogs.title'),
description: t('confirm.show_reblogs.description', [account.acct]),
confirm: t('confirm.show_reblogs.confirm'),
cancel: t('confirm.show_reblogs.cancel'),
}) })
: await useMasto().accounts.unmute(account.id) if (dialogChoice.choice !== 'confirm')
return
}
const showingReblogs = !relationship.value?.showingReblogs
relationship.value = await client.value.v1.accounts.$select(account.id).follow({ reblogs: showingReblogs })
} }
const toggleBlockUser = async () => { async function addUserNote() {
// TODO: Add confirmation emit('addNote')
relationship!.blocking = !relationship!.blocking
relationship = await useMasto().accounts[relationship!.blocking ? 'block' : 'unblock'](account.id)
} }
const toggleBlockDomain = async () => { async function removeUserNote() {
// TODO: Add confirmation if (!relationship.value!.note || relationship.value!.note.length === 0)
return
relationship!.domainBlocking = !relationship!.domainBlocking const newNote = await client.value.v1.accounts.$select(account.id).note.create({ comment: '' })
await useMasto().domainBlocks[relationship!.domainBlocking ? 'block' : 'unblock'](getServerName(account)) relationship.value!.note = newNote.note
emit('removeNote')
} }
</script> </script>
<template> <template>
<CommonDropdown :eager-mount="command"> <CommonDropdown :eager-mount="command">
<button flex gap-1 items-center w-full rounded op75 hover="op100 text-purple" group aria-label="More actions"> <button flex gap-1 items-center w-full rounded op75 hover="op100 text-purple" group aria-label="More actions">
<div rounded-5 p2 group-hover="bg-purple/10"> <div rounded-5 p2 elk-group-hover="bg-purple/10">
<div i-ri:more-2-fill /> <div i-ri:more-2-fill />
</div> </div>
</button> </button>
@ -51,6 +70,13 @@ const toggleBlockDomain = async () => {
:command="command" :command="command"
/> />
</NuxtLink> </NuxtLink>
<CommonDropdownItem
v-if="isShareSupported"
:text="$t('menu.share_account', [`@${account.acct}`])"
icon="i-ri:share-line"
:command="command"
@click="shareAccount()"
/>
<template v-if="currentUser"> <template v-if="currentUser">
<template v-if="!isSelf"> <template v-if="!isSelf">
@ -67,19 +93,49 @@ const toggleBlockDomain = async () => {
@click="directMessageUser(account)" @click="directMessageUser(account)"
/> />
<CommonDropdownItem
v-if="!relationship?.showingReblogs"
icon="i-ri:repeat-line"
:text="$t('menu.show_reblogs', [`@${account.acct}`])"
:command="command"
@click="toggleReblogs()"
/>
<CommonDropdownItem
v-else
:text="$t('menu.hide_reblogs', [`@${account.acct}`])"
icon="i-ri:repeat-line"
:command="command"
@click="toggleReblogs()"
/>
<CommonDropdownItem
v-if="!relationship?.note || relationship?.note?.length === 0"
:text="$t('menu.add_personal_note', [`@${account.acct}`])"
icon="i-ri-edit-2-line"
:command="command"
@click="addUserNote()"
/>
<CommonDropdownItem
v-else
:text="$t('menu.remove_personal_note', [`@${account.acct}`])"
icon="i-ri-edit-2-line"
:command="command"
@click="removeUserNote()"
/>
<CommonDropdownItem <CommonDropdownItem
v-if="!relationship?.muting" v-if="!relationship?.muting"
:text="$t('menu.mute_account', [`@${account.acct}`])" :text="$t('menu.mute_account', [`@${account.acct}`])"
icon="i-ri:volume-up-fill" icon="i-ri:volume-mute-line"
:command="command" :command="command"
@click="toggleMute" @click="toggleMuteAccount (relationship!, account)"
/> />
<CommonDropdownItem <CommonDropdownItem
v-else v-else
:text="$t('menu.unmute_account', [`@${account.acct}`])" :text="$t('menu.unmute_account', [`@${account.acct}`])"
icon="i-ri:volume-mute-line" icon="i-ri:volume-up-fill"
:command="command" :command="command"
@click="toggleMute" @click="toggleMuteAccount (relationship!, account)"
/> />
<CommonDropdownItem <CommonDropdownItem
@ -87,14 +143,14 @@ const toggleBlockDomain = async () => {
:text="$t('menu.block_account', [`@${account.acct}`])" :text="$t('menu.block_account', [`@${account.acct}`])"
icon="i-ri:forbid-2-line" icon="i-ri:forbid-2-line"
:command="command" :command="command"
@click="toggleBlockUser" @click="toggleBlockAccount (relationship!, account)"
/> />
<CommonDropdownItem <CommonDropdownItem
v-else v-else
:text="$t('menu.unblock_account', [`@${account.acct}`])" :text="$t('menu.unblock_account', [`@${account.acct}`])"
icon="i-ri:checkbox-circle-line" icon="i-ri:checkbox-circle-line"
:command="command" :command="command"
@click="toggleBlockUser" @click="toggleBlockAccount (relationship!, account)"
/> />
<template v-if="getServerName(account) !== currentServer"> <template v-if="getServerName(account) !== currentServer">
@ -103,16 +159,23 @@ const toggleBlockDomain = async () => {
:text="$t('menu.block_domain', [getServerName(account)])" :text="$t('menu.block_domain', [getServerName(account)])"
icon="i-ri:shut-down-line" icon="i-ri:shut-down-line"
:command="command" :command="command"
@click="toggleBlockDomain" @click="toggleBlockDomain(relationship!, account)"
/> />
<CommonDropdownItem <CommonDropdownItem
v-else v-else
:text="$t('menu.unblock_domain', [getServerName(account)])" :text="$t('menu.unblock_domain', [getServerName(account)])"
icon="i-ri:restart-line" icon="i-ri:restart-line"
:command="command" :command="command"
@click="toggleBlockDomain" @click="toggleBlockDomain(relationship!, account)"
/> />
</template> </template>
<CommonDropdownItem
:text="$t('menu.report_account', [`@${account.acct}`])"
icon="i-ri:flag-2-line"
:command="command"
@click="openReportDialog(account)"
/>
</template> </template>
<template v-else> <template v-else>
@ -120,7 +183,7 @@ const toggleBlockDomain = async () => {
<CommonDropdownItem :text="$t('account.pinned')" icon="i-ri:pushpin-line" :command="command" /> <CommonDropdownItem :text="$t('account.pinned')" icon="i-ri:pushpin-line" :command="command" />
</NuxtLink> </NuxtLink>
<NuxtLink to="/favourites"> <NuxtLink to="/favourites">
<CommonDropdownItem :text="$t('account.favourites')" icon="i-ri:heart-3-line" :command="command" /> <CommonDropdownItem :text="$t('account.favourites')" :icon="useStarFavoriteIcon ? 'i-ri:star-line' : 'i-ri:heart-3-line'" :command="command" />
</NuxtLink> </NuxtLink>
<NuxtLink to="/mutes"> <NuxtLink to="/mutes">
<CommonDropdownItem :text="$t('account.muted_users')" icon="i-ri:volume-mute-line" :command="command" /> <CommonDropdownItem :text="$t('account.muted_users')" icon="i-ri:volume-mute-line" :command="command" />

View file

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
defineProps<{ defineProps<{
account: Account account: mastodon.v1.Account
}>() }>()
</script> </script>
@ -14,15 +14,13 @@ defineProps<{
</div> </div>
<div flex> <div flex>
<NuxtLink :to="getAccountRoute(account.moved as any)"> <NuxtLink :to="getAccountRoute(account.moved!)">
<AccountInfo :account="account.moved" /> <AccountInfo :account="account.moved!" />
</NuxtLink> </NuxtLink>
<div flex-auto /> <div flex-auto />
<div flex items-center> <div flex items-center>
<NuxtLink :to="getAccountRoute(account.moved as any)"> <NuxtLink :to="getAccountRoute(account.moved as any)" btn-solid inline-block h-fit>
<button btn-solid h-fit> {{ $t('account.go_to_profile') }}
{{ $t('account.go_to_profile') }}
</button>
</NuxtLink> </NuxtLink>
</div> </div>
</div> </div>

View file

@ -1,9 +1,19 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account, Paginator } from 'masto' import type { mastodon } from 'masto'
const { paginator } = defineProps<{ const { paginator, account, context } = defineProps<{
paginator: Paginator<any, Account[]> paginator: mastodon.Paginator<mastodon.v1.Account[], mastodon.DefaultPaginationParams | undefined>
context?: 'following' | 'followers'
account?: mastodon.v1.Account
relationshipContext?: 'followedBy' | 'following'
}>() }>()
const fallbackContext = computed(() => {
return ['following', 'followers'].includes(context!)
})
const showOriginSite = computed(() =>
account && account.id !== currentUser.value?.account.id && getServerName(account) !== currentServer.value,
)
</script> </script>
<template> <template>
@ -11,9 +21,23 @@ const { paginator } = defineProps<{
<template #default="{ item }"> <template #default="{ item }">
<AccountCard <AccountCard
:account="item" :account="item"
:relationship-context="relationshipContext"
hover-card hover-card
border="b base" py2 px4 border="b base" py2 px4
/> />
</template> </template>
<template v-if="fallbackContext && showOriginSite" #done>
<div p5 text-secondary text-center flex flex-col items-center gap1>
<span italic>{{ $t(`account.view_other_${context}`) }}</span>
<NuxtLink
:href="account!.url" target="_blank" external
flex="~ gap-1" items-center text-primary
hover="underline text-primary-active"
>
<div i-ri:external-link-fill />
{{ $t('menu.open_in_original_site') }}
</NuxtLink>
</div>
</template>
</CommonPaginator> </CommonPaginator>
</template> </template>

View file

@ -1,65 +1,77 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Account } from 'masto' import type { mastodon } from 'masto'
const props = defineProps<{ defineProps<{
account: Account account: mastodon.v1.Account
isHoverCard?: boolean
}>() }>()
const { formatHumanReadableNumber, formatNumber, forSR } = useHumanReadableNumber()
const statusesCount = $computed(() => formatHumanReadableNumber(props.account.statusesCount)) const userSettings = useUserSettings()
const statusesCountSR = $computed(() => forSR(props.account.statusesCount))
const followingCount = $computed(() => formatHumanReadableNumber(props.account.followingCount))
const followingCountSR = $computed(() => forSR(props.account.followingCount))
const followersCount = $computed(() => formatHumanReadableNumber(props.account.followersCount))
const followersCountSR = $computed(() => forSR(props.account.followersCount))
</script> </script>
<template> <template>
<div flex gap-5> <div flex gap-5>
<NuxtLink <NuxtLink
:to="getAccountRoute(account)" :to="getAccountRoute(account)"
replace
text-secondary text-secondary
exact-active-class="text-primary" exact-active-class="text-primary"
:class="statusesCountSR ? 'flex gap-x-1' : null"
> >
<template #default="{ isExactActive }"> <template #default="{ isExactActive }">
<i18n-t keypath="account.posts_count" :plural="account.statusesCount"> <CommonLocalizedNumber
<CommonTooltip v-if="statusesCountSR" :content="formatNumber(account.statusesCount)" placement="bottom"> keypath="account.posts_count"
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ statusesCount }}</span> :count="account.statusesCount"
<span sr-only font-bold>{{ account.statusesCount }}</span> font-bold
</CommonTooltip> :class="isExactActive ? 'text-primary' : 'text-base'"
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ statusesCount }}</span> />
</i18n-t>
</template> </template>
</NuxtLink> </NuxtLink>
<NuxtLink <NuxtLink
v-if="!(isHoverCard && getPreferences(userSettings, 'hideFollowerCount'))"
:to="getAccountFollowingRoute(account)" :to="getAccountFollowingRoute(account)"
replace
text-secondary exact-active-class="text-primary" text-secondary exact-active-class="text-primary"
:class="followingCountSR ? 'flex gap-x-1' : null"
> >
<template #default="{ isExactActive }"> <template #default="{ isExactActive }">
<i18n-t keypath="account.following_count" :plural="account.followingCount"> <template
<CommonTooltip v-if="followingCountSR" :content="formatNumber(account.followingCount)" placement="bottom"> v-if="!getPreferences(userSettings, 'hideFollowerCount')"
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followingCount }}</span> >
<span sr-only font-bold>{{ account.followingCount }}</span> <CommonLocalizedNumber
</CommonTooltip> v-if="account.followingCount >= 0"
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followingCount }}</span> keypath="account.following_count"
</i18n-t> :count="account.followingCount"
font-bold
:class="isExactActive ? 'text-primary' : 'text-base'"
/>
<div v-else flex gap-x-1>
<span font-bold text-base>Hidden</span>
<span>{{ $t('account.following') }}</span>
</div>
</template>
<span v-else>{{ $t('account.following') }}</span>
</template> </template>
</NuxtLink> </NuxtLink>
<NuxtLink <NuxtLink
v-if="!(isHoverCard && getPreferences(userSettings, 'hideFollowerCount'))"
:to="getAccountFollowersRoute(account)" :to="getAccountFollowersRoute(account)"
text-secondary exact-active-class="text-primary" replace text-secondary
:class="followersCountSR ? 'flex gap-x-1' : null" exact-active-class="text-primary"
> >
<template #default="{ isExactActive }"> <template #default="{ isExactActive }">
<i18n-t keypath="account.followers_count" :plural="account.followersCount"> <template v-if="!getPreferences(userSettings, 'hideFollowerCount')">
<CommonTooltip v-if="followersCountSR" :content="formatNumber(account.followersCount)" placement="bottom"> <CommonLocalizedNumber
<span aria-hidden="true" font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followersCount }}</span> v-if="account.followersCount >= 0"
<span sr-only font-bold>{{ account.followersCount }}</span> keypath="account.followers_count"
</CommonTooltip> :count="account.followersCount"
<span v-else font-bold :class="isExactActive ? 'text-primary' : 'text-base'">{{ followersCount }}</span> font-bold
</i18n-t> :class="isExactActive ? 'text-primary' : 'text-base'"
/>
<div v-else flex gap-x-1>
<span font-bold text-base>Hidden</span>
<span>{{ $t('account.followers') }}</span>
</div>
</template>
<span v-else>{{ $t('account.followers') }}</span>
</template> </template>
</NuxtLink> </NuxtLink>
</div> </div>

View file

@ -0,0 +1,31 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
defineProps<{
account: mastodon.v1.Account
limit?: number
}>()
</script>
<template>
<div
flex="~ gap1" items-center
class="border border-base rounded-md px-1"
text-secondary-light
>
<slot name="prepend" />
<div v-for="role in account.roles?.slice(0, limit)" :key="role.id" flex>
<div :style="`color: ${role.color}; border-color: ${role.color}`">
{{ role.name }}
</div>
</div>
</div>
<div
v-if="limit && account.roles?.length > limit"
flex="~ gap1" items-center
class="border border-base rounded-md px-1"
text-secondary-light
>
+{{ account.roles?.length - limit }}
</div>
</template>

View file

@ -1,16 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CommonRouteTabOption } from '~/types'
const { t } = useI18n() const { t } = useI18n()
const route = useRoute() const route = useRoute()
const server = $(computedEager(() => route.params.server as string)) const server = computed(() => route.params.server as string)
const account = $(computedEager(() => route.params.account as string)) const account = computed(() => route.params.account as string)
const tabs = $computed(() => [ const tabs = computed<CommonRouteTabOption[]>(() => [
{ {
name: 'account-index', name: 'account-index',
to: { to: {
name: 'account-index', name: 'account-index',
params: { server, account }, params: { server: server.value, account: account.value },
}, },
display: t('tab.posts'), display: t('tab.posts'),
icon: 'i-ri:file-list-2-line', icon: 'i-ri:file-list-2-line',
@ -19,23 +21,23 @@ const tabs = $computed(() => [
name: 'account-replies', name: 'account-replies',
to: { to: {
name: 'account-replies', name: 'account-replies',
params: { server, account }, params: { server: server.value, account: account.value },
}, },
display: t('tab.posts_with_replies'), display: t('tab.posts_with_replies'),
icon: 'i-ri:chat-3-line', icon: 'i-ri:chat-1-line',
}, },
{ {
name: 'account-media', name: 'account-media',
to: { to: {
name: 'account-media', name: 'account-media',
params: { server, account }, params: { server: server.value, account: account.value },
}, },
display: t('tab.media'), display: t('tab.media'),
icon: 'i-ri:camera-2-line', icon: 'i-ri:camera-2-line',
}, },
] as const) ])
</script> </script>
<template> <template>
<CommonRouteTabs force :options="tabs" prevent-scroll-top command /> <CommonRouteTabs force replace :options="tabs" prevent-scroll-top command border="base b" />
</template> </template>

View file

@ -0,0 +1,45 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
defineOptions({
inheritAttrs: false,
})
const { tagName, disabled } = defineProps<{
tagName?: string
disabled?: boolean
}>()
const tag = ref<mastodon.v1.Tag>()
const tagHover = ref()
const hovered = useElementHover(tagHover)
watch(hovered, (newHovered) => {
if (newHovered && tagName) {
fetchTag(tagName).then((t) => {
tag.value = t
})
}
})
const userSettings = useUserSettings()
</script>
<template>
<span ref="tagHover">
<VMenu
v-if="!disabled && !getPreferences(userSettings, 'hideTagHoverCard')"
placement="bottom-start"
:delay="{ show: 500, hide: 100 }"
v-bind="$attrs"
:close-on-content-click="false"
>
<slot />
<template #popper>
<TagCardSkeleton v-if="!tag" />
<TagCard v-else :tag="tag" />
</template>
</VMenu>
<slot v-else />
</span>
</template>

View file

@ -0,0 +1,55 @@
<script setup lang="ts">
import type { LocaleObject } from '@nuxtjs/i18n'
import type { AriaAnnounceType, AriaLive } from '~/composables/aria'
const router = useRouter()
const { t, locale, locales } = useI18n()
const { ariaAnnouncer, announce } = useAriaAnnouncer()
const localeMap = (locales.value as LocaleObject[]).reduce((acc, l) => {
acc[l.code!] = l.name!
return acc
}, {} as Record<string, string>)
const ariaLive = ref<AriaLive>('polite')
const ariaMessage = ref<string>('')
function onMessage(event: AriaAnnounceType, message?: string) {
if (event === 'announce')
ariaMessage.value = message!
else if (event === 'mute')
ariaLive.value = 'off'
else
ariaLive.value = 'polite'
}
watch(locale, (l, ol) => {
if (ol) {
announce(t('a11y.locale_changing', [localeMap[ol] ?? ol]))
setTimeout(() => {
announce(t('a11y.locale_changed', [localeMap[l] ?? l]))
}, 1000)
}
}, { immediate: true })
onMounted(() => {
ariaAnnouncer.on(onMessage)
router.beforeEach(() => {
announce(t('a11y.loading_page'))
})
router.afterEach((to, from) => {
from && setTimeout(() => {
requestAnimationFrame(() => {
const title = document.title.trim().split('|')
announce(t('a11y.route_loaded', [title[0]]))
})
}, 512)
})
})
</script>
<template>
<p sr-only role="status" :aria-live="ariaLive">
{{ ariaMessage }}
</p>
</template>

View file

@ -0,0 +1,39 @@
<script setup lang="ts">
import type { AriaLive } from '~/composables/aria'
// tsc complaining when using $defineProps
withDefaults(defineProps<{
title: string
ariaLive?: AriaLive
messageKey?: (message: any) => any
heading?: 'h2' | 'h3' | 'h4' | 'h5' | 'h6'
}>(), {
heading: 'h2',
messageKey: (message: any) => message,
ariaLive: 'polite',
})
const { announceLogs, appendLogs, clearLogs, logs } = useAriaLog()
defineExpose({
announceLogs,
appendLogs,
clearLogs,
})
</script>
<template>
<slot />
<div sr-only role="log" :aria-live="ariaLive">
<component :is="heading">
{{ title }}
</component>
<ul>
<li v-for="log in logs" :key="messageKey(log)">
<slot name="log" :log="log">
{{ log }}
</slot>
</li>
</ul>
</div>
</template>

View file

@ -0,0 +1,26 @@
<script setup lang="ts">
import type { AriaLive } from '~/composables/aria'
// tsc complaining when using $defineProps
withDefaults(defineProps<{
ariaLive?: AriaLive
}>(), {
ariaLive: 'polite',
})
const { announceStatus, clearStatus, status } = useAriaStatus()
defineExpose({
announceStatus,
clearStatus,
})
</script>
<template>
<slot />
<p sr-only role="status" :aria-live="ariaLive">
<slot name="status" :status="status">
{{ status }}
</slot>
</p>
</template>

View file

@ -0,0 +1,58 @@
<script lang="ts" setup>
import type { ResolvedCommand } from '~/composables/command'
const {
cmd,
index,
active = false,
} = defineProps<{
cmd: ResolvedCommand
index: number
active?: boolean
}>()
const emit = defineEmits<{
(event: 'activate'): void
}>()
</script>
<template>
<div
class="flex px-3 py-2 my-1 items-center rounded-lg hover:bg-active transition-all duration-65 ease-in-out cursor-pointer scroll-m-10"
:class="{ 'bg-active': active }"
:data-index="index"
@click="emit('activate')"
>
<div v-if="cmd.icon" me-2 :class="cmd.icon" />
<div class="flex-1 flex items-baseline gap-2">
<div :class="{ 'font-medium': active }">
{{ cmd.name }}
</div>
<div v-if="cmd.description" class="text-xs text-secondary">
{{ cmd.description }}
</div>
</div>
<div
v-if="cmd.onComplete"
class="flex items-center gap-1 transition-all duration-65 ease-in-out"
:class="active ? 'opacity-100' : 'opacity-0'"
>
<div class="text-xs text-secondary">
{{ $t('command.complete') }}
</div>
<CommandKey name="Tab" />
</div>
<div
v-if="cmd.onActivate"
class="flex items-center gap-1 transition-all duration-65 ease-in-out"
:class="active ? 'opacity-100' : 'opacity-0'"
>
<div class="text-xs text-secondary">
{{ $t('command.activate') }}
</div>
<CommandKey name="Enter" />
</div>
</div>
</template>

View file

@ -5,7 +5,7 @@ const props = defineProps<{
const isMac = useIsMac() const isMac = useIsMac()
const keys = $computed(() => props.name.toLowerCase().split('+')) const keys = computed(() => props.name.toLowerCase().split('+'))
</script> </script>
<template> <template>

View file

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import type { CommandScope, QueryIndexedCommand } from '@/composables/command' import type { SearchResult as SearchResultType } from '~/composables/masto/search'
import type { CommandScope, QueryResult, QueryResultItem } from '~/composables/command'
const emit = defineEmits<{ const emit = defineEmits<{
(event: 'close'): void (event: 'close'): void
@ -7,60 +8,109 @@ const emit = defineEmits<{
const registry = useCommandRegistry() const registry = useCommandRegistry()
const inputEl = $ref<HTMLInputElement>() const router = useRouter()
const resultEl = $ref<HTMLDivElement>()
const scopes = $ref<CommandScope[]>([]) const inputEl = ref<HTMLInputElement>()
let input = $(commandPanelInput) const resultEl = ref<HTMLDivElement>()
const scopes = ref<CommandScope[]>([])
const input = commandPanelInput
onMounted(() => { onMounted(() => {
inputEl?.focus() inputEl.value?.focus()
}) })
const commandMode = $computed(() => input.startsWith('>')) const commandMode = computed(() => input.value.startsWith('>'))
const result = $computed(() => commandMode
? registry.query(scopes.map(s => s.id).join('.'), input.slice(1)) const query = computed(() => commandMode.value ? '' : input.value.trim())
: { length: 0, items: [], grouped: {} })
let active = $ref(0) const { accounts, hashtags, loading } = useSearch(query)
watch($$(result), (n, o) => {
function toSearchQueryResultItem(search: SearchResultType): QueryResultItem {
return {
index: 0,
type: 'search',
search,
onActivate: () => router.push(search.to),
}
}
const searchResult = computed<QueryResult>(() => {
if (query.value.length === 0 || loading.value)
return { length: 0, items: [], grouped: {} as any }
// TODO extract this scope
// duplicate in SearchWidget.vue
const hashtagList = hashtags.value.slice(0, 3).map(toSearchQueryResultItem)
const accountList = accounts.value.map(toSearchQueryResultItem)
const grouped: QueryResult['grouped'] = new Map()
grouped.set('Hashtags', hashtagList)
grouped.set('Users', accountList)
let index = 0
for (const items of grouped.values()) {
for (const item of items)
item.index = index++
}
return {
grouped,
items: [...hashtagList, ...accountList],
length: hashtagList.length + accountList.length,
}
})
const result = computed<QueryResult>(() => commandMode.value
? registry.query(scopes.value.map(s => s.id).join('.'), input.value.slice(1).trim())
: searchResult.value,
)
const isMac = useIsMac()
const modifierKeyName = computed(() => isMac.value ? '⌘' : 'Ctrl')
const active = ref(0)
watch(result, (n, o) => {
if (n.length !== o.length || !n.items.every((i, idx) => i === o.items[idx])) if (n.length !== o.length || !n.items.every((i, idx) => i === o.items[idx]))
active = 0 active.value = 0
}) })
const findItemEl = (index: number) => function findItemEl(index: number) {
resultEl?.querySelector(`[data-index="${index}"]`) as HTMLDivElement | null return resultEl.value?.querySelector(`[data-index="${index}"]`) as HTMLDivElement | null
const onCommandActivate = (item: QueryIndexedCommand) => { }
function onCommandActivate(item: QueryResultItem) {
if (item.onActivate) { if (item.onActivate) {
item.onActivate() item.onActivate()
emit('close') emit('close')
} }
else if (item.onComplete) { else if (item.onComplete) {
scopes.push(item.onComplete()) scopes.value.push(item.onComplete())
input = '>' input.value = '> '
} }
} }
const onCommandComplete = (item: QueryIndexedCommand) => { function onCommandComplete(item: QueryResultItem) {
if (item.onComplete) { if (item.onComplete) {
scopes.push(item.onComplete()) scopes.value.push(item.onComplete())
input = '>' input.value = '> '
} }
else if (item.onActivate) { else if (item.onActivate) {
item.onActivate() item.onActivate()
emit('close')
} }
} }
const intoView = (index: number) => { function intoView(index: number) {
const el = findItemEl(index) const el = findItemEl(index)
if (el) if (el)
el.scrollIntoView({ block: 'nearest' }) el.scrollIntoView({ block: 'nearest' })
} }
function setActive(index: number) { function setActive(index: number) {
const len = result.length const len = result.value.length
active = (index + len) % len active.value = (index + len) % len
intoView(active) intoView(active.value)
} }
const onKeyDown = (e: KeyboardEvent) => { function onKeyDown(e: KeyboardEvent) {
switch (e.key) { switch (e.key) {
case 'p': case 'p':
case 'ArrowUp': { case 'ArrowUp': {
@ -68,7 +118,7 @@ const onKeyDown = (e: KeyboardEvent) => {
break break
e.preventDefault() e.preventDefault()
setActive(active - 1) setActive(active.value - 1)
break break
} }
@ -78,7 +128,7 @@ const onKeyDown = (e: KeyboardEvent) => {
break break
e.preventDefault() e.preventDefault()
setActive(active + 1) setActive(active.value + 1)
break break
} }
@ -86,9 +136,9 @@ const onKeyDown = (e: KeyboardEvent) => {
case 'Home': { case 'Home': {
e.preventDefault() e.preventDefault()
active = 0 active.value = 0
intoView(active) intoView(active.value)
break break
} }
@ -96,7 +146,7 @@ const onKeyDown = (e: KeyboardEvent) => {
case 'End': { case 'End': {
e.preventDefault() e.preventDefault()
setActive(result.length - 1) setActive(result.value.length - 1)
break break
} }
@ -104,7 +154,7 @@ const onKeyDown = (e: KeyboardEvent) => {
case 'Enter': { case 'Enter': {
e.preventDefault() e.preventDefault()
const cmd = result.items[active] const cmd = result.value.items[active.value]
if (cmd) if (cmd)
onCommandActivate(cmd) onCommandActivate(cmd)
@ -114,7 +164,7 @@ const onKeyDown = (e: KeyboardEvent) => {
case 'Tab': { case 'Tab': {
e.preventDefault() e.preventDefault()
const cmd = result.items[active] const cmd = result.value.items[active.value]
if (cmd) if (cmd)
onCommandComplete(cmd) onCommandComplete(cmd)
@ -122,9 +172,9 @@ const onKeyDown = (e: KeyboardEvent) => {
} }
case 'Backspace': { case 'Backspace': {
if (input === '>' && scopes.length) { if (input.value === '>' && scopes.value.length) {
e.preventDefault() e.preventDefault()
scopes.pop() scopes.value.pop()
} }
break break
} }
@ -158,52 +208,30 @@ const onKeyDown = (e: KeyboardEvent) => {
<!-- Results --> <!-- Results -->
<div ref="resultEl" class="flex-1 mx-1 overflow-y-auto"> <div ref="resultEl" class="flex-1 mx-1 overflow-y-auto">
<template v-for="[scope, group] in result.grouped" :key="scope"> <template v-if="loading">
<div class="mt-2 px-2 py-1 text-sm text-secondary"> <SearchResultSkeleton />
{{ scope }} <SearchResultSkeleton />
</div> <SearchResultSkeleton />
</template>
<template v-for="cmd in group" :key="cmd.index"> <template v-else-if="result.length">
<div <template v-for="[scope, group] in result.grouped" :key="scope">
class="flex px-3 py-2 my-1 items-center rounded-lg hover:bg-active transition-all duration-65 ease-in-out cursor-pointer scroll-m-10" <div class="mt-2 px-2 py-1 text-sm text-secondary">
:class="{ 'bg-active': active === cmd.index }" {{ scope }}
:data-index="cmd.index"
@click="onCommandActivate(cmd)"
>
<div v-if="cmd.icon" mr-2 :class="cmd.icon" />
<div class="flex-1 flex items-baseline gap-2">
<div :class="{ 'font-medium': active === cmd.index }">
{{ cmd.name }}
</div>
<div v-if="cmd.description" class="text-xs text-secondary">
{{ cmd.description }}
</div>
</div>
<div
v-if="cmd.onComplete"
class="flex items-center gap-1 transition-all duration-65 ease-in-out"
:class="active === cmd.index ? 'opacity-100' : 'opacity-0'"
>
<div class="text-xs text-secondary">
{{ $t('command.complete') }}
</div>
<CommandKey name="Tab" />
</div>
<div
v-if="cmd.onActivate"
class="flex items-center gap-1 transition-all duration-65 ease-in-out"
:class="active === cmd.index ? 'opacity-100' : 'opacity-0'"
>
<div class="text-xs text-secondary">
{{ $t('command.activate') }}
</div>
<CommandKey name="Enter" />
</div>
</div> </div>
<template v-for="item in group" :key="item.index">
<SearchResult v-if="item.type === 'search'" :active="active === item.index" :result="item.search" />
<CommandItem v-else :index="item.index" :cmd="item.cmd" :active="active === item.index" @activate="onCommandActivate(item)" />
</template>
</template> </template>
</template> </template>
<div v-else p5 text-center text-secondary italic>
{{
input.trim().length
? $t('common.not_found')
: $t('search.search_desc')
}}
</div>
</div> </div>
<div class="w-full border-b-1 border-base" /> <div class="w-full border-b-1 border-base" />
@ -211,8 +239,8 @@ const onKeyDown = (e: KeyboardEvent) => {
<!-- Footer --> <!-- Footer -->
<div class="flex items-center px-3 py-1 text-xs"> <div class="flex items-center px-3 py-1 text-xs">
<div i-ri:lightbulb-flash-line /> Tip: Use <div i-ri:lightbulb-flash-line /> Tip: Use
<!-- <CommandKey name="Ctrl+K" /> to search, --> <CommandKey :name="`${modifierKeyName}+K`" /> to search,
<CommandKey name="Ctrl+/" /> to activate command mode. <CommandKey :name="`${modifierKeyName}+/`" /> to activate command mode.
</div> </div>
</div> </div>
</template> </template>

View file

@ -1,17 +1,11 @@
<script lang="ts" setup> <script lang="ts" setup>
const props = withDefaults(defineProps<{ const emit = defineEmits<{
modelValue?: boolean
}>(), {
modelValue: true,
})
const emits = defineEmits<{
(e: 'update:modelValue', v: boolean): void
(event: 'close'): void (event: 'close'): void
}>() }>()
const visible = useVModel(props, 'modelValue', emits, { passive: true }) const visible = defineModel<boolean>()
function close() { function close() {
emits('close') emit('close')
visible.value = false visible.value = false
} }
</script> </script>
@ -19,12 +13,12 @@ function close() {
<template> <template>
<div <div
flex="~ gap-2" justify-between items-center flex="~ gap-2" justify-between items-center
class="border-b border-base text-sm text-secondary px4 py2 sm:py4" border="b base" text-sm text-secondary px4 py2 sm:py4
> >
<div> <div>
<slot /> <slot />
</div> </div>
<button text-xl hover:text-primary bg-hover-overflow w-1.4em h-1.4em @click="close()"> <button text-xl hover:text-primary bg-hover-overflow w="1.2em" h="1.2em" @click="close()">
<div i-ri:close-line /> <div i-ri:close-line />
</button> </button>
</div> </div>

View file

@ -1,46 +0,0 @@
import { decode } from 'blurhash'
import { getDataUrlFromArr } from '~/composables/utils'
export default defineComponent({
inheritAttrs: false,
props: {
blurhash: {
type: String,
required: true,
},
src: {
type: String,
required: true,
},
srcset: {
type: String,
required: false,
},
},
setup(props, { attrs }) {
const placeholderSrc = ref<string>()
const isLoaded = ref(false)
onMounted(() => {
const img = document.createElement('img')
img.onload = () => {
isLoaded.value = true
}
img.src = props.src
if (props.srcset)
img.srcset = props.srcset
setTimeout(() => {
isLoaded.value = true
}, 3_000)
if (props.blurhash) {
const pixels = decode(props.blurhash, 32, 32)
placeholderSrc.value = getDataUrlFromArr(pixels, 32, 32)
}
})
return () => isLoaded.value || !placeholderSrc.value
? h('img', { ...attrs, src: props.src, srcset: props.srcset })
: h('img', { ...attrs, src: placeholderSrc.value })
},
})

View file

@ -0,0 +1,16 @@
<script setup lang="ts">
defineOptions({
inheritAttrs: false,
})
const { blurhash = '', src, srcset, shouldLoadImage = true } = defineProps<{
blurhash?: string
src: string
srcset?: string
shouldLoadImage?: boolean
}>()
</script>
<template>
<UnLazyImage v-bind="$attrs" :blurhash="blurhash" :src="src" :src-set="srcset" :lazy-load="shouldLoadImage" auto-sizes />
</template>

View file

@ -1,21 +1,29 @@
<script setup lang="ts"> <script setup lang="ts">
defineProps<{ defineProps<{
label: string label?: string
hover?: boolean hover?: boolean
iconChecked?: string
iconUnchecked?: string
checkedIconColor?: string
prependCheckbox?: boolean
}>() }>()
const { modelValue } = defineModel<{ const modelValue = defineModel<boolean | null>()
modelValue: boolean
}>()
</script> </script>
<template> <template>
<label <label
class="common-checkbox flex items-center cursor-pointer py-1 text-md w-full gap-y-1" class="common-checkbox flex items-center cursor-pointer py-1 text-md w-full gap-y-1"
:class="hover ? 'hover:bg-active ml--2 pl-4' : null" :class="hover ? 'hover:bg-active ms--2 px-4 py-2' : null"
v-bind="$attrs"
@click.prevent="modelValue = !modelValue" @click.prevent="modelValue = !modelValue"
> >
<span v-if="label && !prependCheckbox" flex-1 ms-2 pointer-events-none>{{ label }}</span>
<span <span
:class="modelValue ? 'i-ri:checkbox-line' : 'i-ri:checkbox-blank-line'" :class="[
modelValue ? (iconChecked ?? 'i-ri:checkbox-line') : (iconUnchecked ?? 'i-ri:checkbox-blank-line'),
modelValue && checkedIconColor,
]"
text-lg
aria-hidden="true" aria-hidden="true"
/> />
<input <input
@ -23,7 +31,7 @@ const { modelValue } = defineModel<{
type="checkbox" type="checkbox"
sr-only sr-only
> >
<span ml-2 pointer-events-none>{{ label }}</span> <span v-if="label && prependCheckbox" flex-1 ms-2 pointer-events-none>{{ label }}</span>
</label> </label>
</template> </template>

View file

@ -0,0 +1,103 @@
<script lang="ts" setup>
import type { Boundaries } from 'vue-advanced-cropper'
import { Cropper } from 'vue-advanced-cropper'
import 'vue-advanced-cropper/dist/style.css'
export interface Props {
/** Crop frame aspect ratio (width/height), default 1/1 */
stencilAspectRatio?: number
/** The ratio of the longest edge of the cut box to the length of the cut screen, default 0.9, not more than 1 */
stencilSizePercentage?: number
}
const props = withDefaults(defineProps<Props>(), {
stencilAspectRatio: 1 / 1,
stencilSizePercentage: 0.9,
})
const file = defineModel<File | null>()
const cropperDialog = ref(false)
const cropper = ref<InstanceType<typeof Cropper>>()
const cropperFlag = ref(false)
const cropperImage = reactive({
src: '',
type: 'image/jpg',
})
function stencilSize({ boundaries }: { boundaries: Boundaries }) {
return {
width: boundaries.width * props.stencilSizePercentage,
height: boundaries.height * props.stencilSizePercentage,
}
}
watch(file, (file, _, onCleanup) => {
let expired = false
onCleanup(() => expired = true)
if (file && !cropperFlag.value) {
cropperDialog.value = true
const reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (e) => {
if (expired)
return
cropperImage.src = e.target?.result as string
cropperImage.type = file.type
}
}
cropperFlag.value = false
})
function cropImage() {
if (cropper.value && file.value) {
cropperFlag.value = true
cropperDialog.value = false
const { canvas } = cropper.value.getResult()
canvas?.toBlob((blob) => {
file.value = new File([blob as any], `cropped${file.value?.name}` as string, { type: blob?.type })
}, cropperImage.type)
}
}
</script>
<template>
<ModalDialog v-model="cropperDialog" :use-v-if="false" max-w-500px flex>
<div flex-1 w-0>
<div text-lg text-center my2 px3>
<h1>
{{ $t('action.edit') }}
</h1>
</div>
<div aspect-ratio-1>
<Cropper
ref="cropper"
class="overflow-hidden w-full h-full"
:src="cropperImage.src"
:resize-image="{
adjustStencil: false,
}"
:stencil-size="stencilSize"
:stencil-props="{
aspectRatio: props.stencilAspectRatio,
movable: false,
resizable: false,
handlers: {},
}"
image-restriction="stencil"
/>
</div>
<div m-4>
<button
btn-solid w-full rounded text-sm
@click="cropImage()"
>
{{ $t('action.confirm') }}
</button>
</div>
</div>
</ModalDialog>
</template>

View file

@ -0,0 +1,19 @@
<script setup lang="ts">
defineProps<{ describedBy: string }>()
</script>
<template>
<div
role="alert"
aria-live="polite"
:aria-describedby="describedBy"
flex="~ col"
gap-1 text-sm
pt-1 ps-2 pe-1 pb-2
text-red-600 dark:text-red-400
border="~ base rounded red-600 dark:red-400"
v-bind="$attrs"
>
<slot />
</div>
</template>

View file

@ -0,0 +1,106 @@
<script lang="ts" setup>
import { fileOpen } from 'browser-fs-access'
import type { FileWithHandle } from 'browser-fs-access'
const props = withDefaults(defineProps<{
/** The image src before change */
original?: string
/** Allowed file types */
allowedFileTypes?: string[]
/** Allowed file size */
allowedFileSize?: number
imgClass?: string
loading?: boolean
}>(), {
allowedFileTypes: () => ['image/jpeg', 'image/png'],
allowedFileSize: 1024 * 1024 * 5, // 5 MB
})
const emit = defineEmits<{
(event: 'pick', value: FileWithHandle): void
(event: 'error', code: number, message: string): void
}>()
const file = defineModel<FileWithHandle | null>()
const { t } = useI18n()
const defaultImage = computed(() => props.original || '')
/** Preview of selected images */
const previewImage = ref('')
/** The current images on display */
const imageSrc = computed<string>(() => previewImage.value || defaultImage.value)
async function pickImage() {
if (import.meta.server)
return
const image = await fileOpen({
description: 'Image',
mimeTypes: props.allowedFileTypes,
})
if (!props.allowedFileTypes.includes(image.type)) {
emit('error', 1, t('error.unsupported_file_format'))
return
}
else if (image.size > props.allowedFileSize) {
emit('error', 2, t('error.file_size_cannot_exceed_n_mb', [5]))
return
}
file.value = image
emit('pick', file.value)
}
watch(file, (image, _, onCleanup) => {
let expired = false
onCleanup(() => expired = true)
if (!image) {
previewImage.value = ''
return
}
const reader = new FileReader()
reader.readAsDataURL(image)
reader.onload = (evt) => {
if (expired)
return
previewImage.value = evt.target?.result as string
}
})
</script>
<template>
<label
class="bg-slate-500/10 focus-within:(outline outline-primary)"
relative
flex justify-center items-center
cursor-pointer
of-hidden
@click="pickImage"
>
<img
v-if="imageSrc"
:src="imageSrc"
:class="imgClass || ''"
object-cover
w-full
h-full
>
<span absolute bg="black/50" text-white rounded-full text-xl w12 h12 flex justify-center items-center hover="bg-black/40 text-primary">
<span block i-ri:upload-line />
</span>
<span
v-if="loading"
absolute inset-0
bg="black/30" text-white
flex justify-center items-center
>
<span class="animate-spin animate-duration-[2.5s] preserve-3d">
<span block i-ri:loader-4-line text-4xl />
</span>
</span>
</label>
</template>

View file

@ -0,0 +1,13 @@
<script setup lang="ts">
const {
zIndex = 100,
background = 'transparent',
} = $defineProps<{
zIndex?: number
background?: string
}>()
</script>
<template>
<div fixed top-0 bottom-0 left-0 right-0 :style="{ background, zIndex }" />
</template>

View file

@ -1,30 +1,74 @@
<script setup lang="ts"> <script setup lang="ts" generic="T, O, U = T">
// @ts-expect-error missing types // @ts-expect-error missing types
import { DynamicScroller } from 'vue-virtual-scroller' import { DynamicScroller } from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css' import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
import type { Paginator, WsEvents } from 'masto' import type { mastodon } from 'masto'
import type { UnwrapRef } from 'vue'
const { paginator, stream, keyProp = 'id', virtualScroller = false, eventType = 'update' } = defineProps<{ const {
paginator: Paginator<any, any[]> paginator,
keyProp?: string stream,
eventType,
keyProp = 'id',
virtualScroller = false,
preprocess,
endMessage = true,
} = defineProps<{
paginator: mastodon.Paginator<T[], O>
keyProp?: keyof T
virtualScroller?: boolean virtualScroller?: boolean
stream?: WsEvents stream?: mastodon.streaming.Subscription
eventType?: 'notification' | 'update' eventType?: 'update' | 'notification'
preprocess?: (items: (U | T)[]) => U[]
endMessage?: boolean | string
}>() }>()
defineSlots<{ defineSlots<{
default: { default: (props: {
item: any items: U[]
item: U
index: number
active?: boolean active?: boolean
} older: U
updater: { newer: U // newer is undefined when index === 0
}) => void
items: (props: {
items: UnwrapRef<U[]>
}) => void
updater: (props: {
number: number number: number
update: () => void update: () => void
} }) => void
loading: {} loading: (props: object) => void
done: (props: { items: U[] }) => void
}>() }>()
const { items, prevItems, update, state, endAnchor, error } = usePaginator(paginator, stream, eventType) const { t } = useI18n()
const nuxtApp = useNuxtApp()
const { items, prevItems, update, state, endAnchor, error } = usePaginator(paginator, toRef(() => stream), eventType, preprocess)
nuxtApp.hook('elk-logo:click', () => {
update()
nuxtApp.$scrollToTop()
})
function createEntry(item: any) {
items.value = [...items.value, preprocess?.([item]) ?? item]
}
function updateEntry(item: any) {
const id = item[keyProp]
const index = items.value.findIndex(i => (i as any)[keyProp] === id)
if (index > -1)
items.value = [...items.value.slice(0, index), preprocess?.([item]) ?? item, ...items.value.slice(index + 1)]
}
function removeEntry(entryId: any) {
items.value = items.value.filter(i => (i as any)[keyProp] !== entryId)
}
defineExpose({ createEntry, removeEntry, updateEntry })
</script> </script>
<template> <template>
@ -33,35 +77,46 @@ const { items, prevItems, update, state, endAnchor, error } = usePaginator(pagin
<slot name="items" :items="items"> <slot name="items" :items="items">
<template v-if="virtualScroller"> <template v-if="virtualScroller">
<DynamicScroller <DynamicScroller
v-slot="{ item, active }" v-slot="{ item, active, index }"
:items="items" :items="items"
:min-item-size="200" :min-item-size="200"
:key-field="keyProp" :key-field="keyProp"
page-mode page-mode
> >
<slot :item="item" :active="active" /> <slot
v-bind="{ key: item[keyProp] }"
:item="item"
:active="active"
:older="items[index + 1] as U"
:newer="items[index - 1] as U"
:index="index"
:items="items as U[]"
/>
</DynamicScroller> </DynamicScroller>
</template> </template>
<template v-else> <template v-else>
<slot <slot
v-for="item of items" v-for="(item, index) of items"
:key="item[keyProp]" v-bind="{ key: (item as U)[keyProp as keyof U] }"
:item="item" :item="item as U"
:older="items[index + 1] as U"
:newer="items[index - 1] as U"
:index="index"
:items="items as U[]"
/> />
</template> </template>
</slot> </slot>
<div ref="endAnchor" /> <div ref="endAnchor" />
<slot v-if="state === 'loading'" name="loading"> <slot v-if="state === 'loading'" name="loading">
<div p5 text-center flex="~ col" items-center animate-pulse> <TimelineSkeleton />
<div text-secondary i-ri:loader-2-fill animate-spin text-2xl /> </slot>
<span text-secondary>{{ $t('state.loading') }}</span> <slot v-else-if="state === 'done' && endMessage !== false" name="done" :items="items as U[]">
<div p5 text-secondary italic text-center>
{{ t(typeof endMessage === 'string' && items.length <= 0 ? endMessage : 'common.end_of_list') }}
</div> </div>
</slot> </slot>
<div v-else-if="state === 'done'" p5 text-secondary italic text-center>
{{ $t('common.end_of_list') }}
</div>
<div v-else-if="state === 'error'" p5 text-secondary> <div v-else-if="state === 'error'" p5 text-secondary>
{{ $t('common.error') }}: {{ error }} {{ t('common.error') }}: {{ error }}
</div> </div>
</div> </div>
</template> </template>

View file

@ -0,0 +1,27 @@
<script setup lang="ts">
const build = useBuildInfo()
</script>
<template>
<div
m-2 p5 bg-rose:10 relative
rounded-lg of-hidden
flex="~ col gap-3"
>
<h2 font-bold text-rose>
{{ $t('help.build_preview.title') }}
</h2>
<p>
<i18n-t keypath="help.build_preview.desc1">
<NuxtLink :href="`https://github.com/elk-zone/elk/commit/${build.commit}`" target="_blank" text-rose hover:underline>
<code>{{ build.shortCommit }}</code>
</NuxtLink>
</i18n-t>
</p>
<p>{{ $t('help.build_preview.desc2') }}</p>
<p font-bold>
{{ $t('help.build_preview.desc3') }}
</p>
<div i-ri-git-pull-request-line absolute text-10em bottom--10 inset-ie--10 text-rose op10 class="-z-1" />
</div>
</template>

View file

@ -4,17 +4,16 @@ defineProps<{
value: any value: any
hover?: boolean hover?: boolean
}>() }>()
const { modelValue } = defineModel<{ const modelValue = defineModel()
modelValue: any
}>()
</script> </script>
<template> <template>
<label <label
class="common-radio flex items-center cursor-pointer py-1 text-md w-full gap-y-1" class="common-radio flex items-center cursor-pointer py-1 text-md w-full gap-y-1"
:class="hover ? 'hover:bg-active ml--2 pl-4' : null" :class="hover ? 'hover:bg-active ms--2 px-4 py-2' : null"
@click.prevent="modelValue = value" @click.prevent="modelValue = value"
> >
<span flex-1 ms-2 pointer-events-none>{{ label }}</span>
<span <span
:class="modelValue === value ? 'i-ri:radio-button-line' : 'i-ri:checkbox-blank-circle-line'" :class="modelValue === value ? 'i-ri:radio-button-line' : 'i-ri:checkbox-blank-circle-line'"
aria-hidden="true" aria-hidden="true"
@ -25,7 +24,6 @@ const { modelValue } = defineModel<{
:value="value" :value="value"
sr-only sr-only
> >
<span ml-2 pointer-events-none>{{ label }}</span>
</label> </label>
</template> </template>

View file

@ -1,24 +1,20 @@
<script setup lang="ts"> <script setup lang="ts">
import type { RouteLocationRaw } from 'vue-router' import type { CommonRouteTabMoreOption, CommonRouteTabOption } from '~/types'
const { options, command, replace, preventScrollTop = false } = $defineProps<{ const { options, command, replace, preventScrollTop = false, moreOptions } = defineProps<{
options: { options: CommonRouteTabOption[]
to: RouteLocationRaw moreOptions?: CommonRouteTabMoreOption
display: string
name?: string
icon?: string
}[]
command?: boolean command?: boolean
replace?: boolean replace?: boolean
preventScrollTop?: boolean preventScrollTop?: boolean
}>() }>()
const { t } = useI18n()
const router = useRouter() const router = useRouter()
useCommands(() => command useCommands(() => command
? options.map(tab => ({ ? options.map(tab => ({
scope: 'Tabs', scope: 'Tabs',
name: tab.display, name: tab.display,
icon: tab.icon ?? 'i-ri:file-list-2-line', icon: tab.icon ?? 'i-ri:file-list-2-line',
onActivate: () => router.replace(tab.to), onActivate: () => router.replace(tab.to),
@ -27,19 +23,64 @@ useCommands(() => command
</script> </script>
<template> <template>
<div flex w-full items-center lg:text-lg of-x-auto scrollbar-hide> <div flex w-full items-center lg:text-lg of-x-auto scrollbar-hide border="b base">
<NuxtLink <template
v-for="(option, index) in options" v-for="(option, index) in options.filter(item => !item.hide)"
:key="option?.name || index" :key="option?.name || index"
:to="option.to"
:replace="replace"
relative flex flex-auto cursor-pointer sm:px6 px2 rounded transition-all
tabindex="1"
hover:bg-active transition-100
exact-active-class="children:(font-bold !border-primary !op100)"
@click="!preventScrollTop && $scrollToTop()"
> >
<span ws-nowrap mxa sm:px2 sm:py3 py2 text-center border-b-3 op50 hover:op70 border-transparent>{{ option.display }}</span> <NuxtLink
</NuxtLink> v-if="!option.disabled"
:to="option.to"
:replace="replace"
relative flex flex-auto cursor-pointer sm:px6 px2 rounded transition-all
tabindex="0"
hover:bg-active transition-100
exact-active-class="children:(text-secondary !border-primary !op100 !text-base)"
@click="!preventScrollTop && $scrollToTop()"
>
<span ws-nowrap mxa sm:px2 sm:py3 xl:pb4 xl:pt5 py2 text-center border-b-3 text-secondary-light hover:text-secondary border-transparent>{{ option.display || '&nbsp;' }}</span>
</NuxtLink>
<div v-else flex flex-auto sm:px6 px2 xl:pb4 xl:pt5>
<span ws-nowrap mxa sm:px2 sm:py3 py2 text-center text-secondary-light op50>{{ option.display }}</span>
</div>
</template>
<template v-if="isHydrated && moreOptions?.options?.length">
<CommonDropdown placement="bottom" flex cursor-pointer mx-1.25rem>
<CommonTooltip placement="top" no-auto-focus :content="moreOptions.tooltip || t('action.more')">
<button
cursor-pointer
flex
gap-1
w-12
rounded
hover:bg-active
btn-action-icon
op75
px4
group
:aria-label="t('action.more')"
:class="moreOptions.match ? 'text-primary' : 'text-secondary'"
>
<span v-if="moreOptions.icon" :class="moreOptions.icon" text-sm me--1 block />
<span i-ri:arrow-down-s-line text-sm me--1 block />
</button>
</CommonTooltip>
<template #popper>
<NuxtLink
v-for="(option, index) in moreOptions.options.filter(item => !item.hide)"
:key="option?.name || index"
:to="option.to"
>
<CommonDropdownItem>
<span flex="~ row" gap-x-4 items-center :class="option.match ? 'text-primary' : ''">
<span v-if="option.icon" :class="[option.icon, option.match ? 'text-primary' : 'text.secondary']" text-md me--1 block />
<span v-else block>&#160;</span>
<span>{{ option.display }}</span>
</span>
</CommonDropdownItem>
</NuxtLink>
</template>
</commondropdown>
</template>
</div> </div>
</template> </template>

View file

@ -1,5 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
const { as = 'div', active } = defineProps<{ as: any; active: boolean }>() const { as = 'div', active } = defineProps<{
as: any
active: boolean
}>()
const el = ref() const el = ref()
watch(() => active, (active) => { watch(() => active, (active) => {

View file

@ -8,11 +8,9 @@ const { options, command } = defineProps<{
command?: boolean command?: boolean
}>() }>()
const { modelValue } = defineModel<{ const modelValue = defineModel<string>({ required: true })
modelValue: string
}>()
const tabs = $computed(() => { const tabs = computed(() => {
return options.map((option) => { return options.map((option) => {
if (typeof option === 'string') if (typeof option === 'string')
return { name: option, display: option } return { name: option, display: option }
@ -21,12 +19,12 @@ const tabs = $computed(() => {
}) })
}) })
function toValidName(otpion: string) { function toValidName(option: string) {
return otpion.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-') return option.toLowerCase().replace(/[^a-zA-Z0-9]/g, '-')
} }
useCommands(() => command useCommands(() => command
? tabs.map(tab => ({ ? tabs.value.map(tab => ({
scope: 'Tabs', scope: 'Tabs',
name: tab.display, name: tab.display,
@ -51,7 +49,7 @@ useCommands(() => command
><label ><label
flex flex-auto cursor-pointer px3 m1 rounded transition-all flex flex-auto cursor-pointer px3 m1 rounded transition-all
:for="`tab-${toValidName(option.name)}`" :for="`tab-${toValidName(option.name)}`"
tabindex="1" tabindex="0"
hover:bg-active transition-100 hover:bg-active transition-100
@keypress.enter="modelValue = option.name" @keypress.enter="modelValue = option.name"
><span ><span

View file

@ -1,14 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Popper as VTooltipType } from 'floating-vue/dist' import type { Popper as VTooltipType } from 'floating-vue'
defineProps<{ export interface Props extends Partial<typeof VTooltipType> {
content?: string content?: string
} & Partial<typeof VTooltipType>>() }
defineProps<Props>()
</script> </script>
<template> <template>
<VTooltip <VTooltip
v-if="isHydrated"
v-bind="$attrs" v-bind="$attrs"
auto-hide
> >
<slot /> <slot />
<template #popper> <template #popper>

View file

@ -1,23 +1,23 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { History } from 'masto' import type { mastodon } from 'masto'
const { const {
history, history,
maxDay = 2, maxDay = 2,
} = $defineProps<{ } = defineProps<{
history: History[] history: mastodon.v1.TagHistory[]
maxDay?: number maxDay?: number
}>() }>()
const ongoingHot = $computed(() => history.slice(0, maxDay)) const ongoingHot = computed(() => history.slice(0, maxDay))
const people = $computed(() => const people = computed(() =>
ongoingHot.reduce((total: number, item) => total + (Number(item.accounts) || 0), 0), ongoingHot.value.reduce((total: number, item) => total + (Number(item.accounts) || 0), 0),
) )
</script> </script>
<template> <template>
<p> <p>
{{ $t('command.n-people-in-the-past-n-days', [people, maxDay]) }} {{ $t('command.n_people_in_the_past_n_days', [people, maxDay]) }}
</p> </p>
</template> </template>

View file

@ -1,28 +1,33 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { History } from 'masto' import type { mastodon } from 'masto'
import sparkline from '@fnando/sparkline' import sparkline from '@fnando/sparkline'
const { const {
history, history,
} = $defineProps<{ width = 60,
history?: History[] height = 40,
} = defineProps<{
history?: mastodon.v1.TagHistory[]
width?: number
height?: number
}>() }>()
const historyNum = $computed(() => { const historyNum = computed(() => {
if (!history) if (!history)
return [1, 1, 1, 1, 1, 1, 1] return [1, 1, 1, 1, 1, 1, 1]
return [...history].reverse().map(item => Number(item.accounts) || 0) return [...history].reverse().map(item => Number(item.accounts) || 0)
}) })
const sparklineEl = $ref<SVGSVGElement>() const sparklineEl = ref<SVGSVGElement>()
const sparklineFn = typeof sparkline !== 'function' ? (sparkline as any).default : sparkline
watch([$$(historyNum), $$(sparklineEl)], ([historyNum, sparklineEl]) => { watch([historyNum, sparklineEl], ([historyNum, sparklineEl]) => {
if (!sparklineEl) if (!sparklineEl)
return return
sparkline(sparklineEl, historyNum) sparklineFn(sparklineEl, historyNum)
}) })
</script> </script>
<template> <template>
<svg ref="sparklineEl" class="sparkline" width="60" height="40" stroke-width="3" /> <svg ref="sparklineEl" class="sparkline" :width="width" :height="height" stroke-width="3" />
</template> </template>

View file

@ -0,0 +1,26 @@
<script setup lang="ts">
defineOptions({
inheritAttrs: false,
})
const props = defineProps<{
count: number
keypath: string
}>()
const { formatHumanReadableNumber, formatNumber, forSR } = useHumanReadableNumber()
const useSR = computed(() => forSR(props.count))
const rawNumber = computed(() => formatNumber(props.count))
const humanReadableNumber = computed(() => formatHumanReadableNumber(props.count))
</script>
<template>
<i18n-t :keypath="keypath" :plural="count" tag="span" class="flex gap-x-1">
<CommonTooltip v-if="useSR" :content="rawNumber" placement="bottom">
<span aria-hidden="true" v-bind="$attrs">{{ humanReadableNumber }}</span>
<span sr-only>{{ rawNumber }}</span>
</CommonTooltip>
<span v-else v-bind="$attrs">{{ humanReadableNumber }}</span>
</i18n-t>
</template>

View file

@ -1,7 +1,4 @@
<script setup lang="ts"> <script setup lang="ts">
defineProps<{
smallScreen: boolean
}>()
const online = useOnline() const online = useOnline()
</script> </script>

View file

@ -1,18 +1,28 @@
<script setup lang="ts"> <script setup lang="ts">
import { dropdownContextKey } from './ctx' import { InjectionKeyDropdownContext } from '~/constants/symbols'
defineProps<{ defineProps<{
placement?: string placement?: string
autoBoundaryMaxSize?: boolean
}>() }>()
const dropdown = $ref<any>() const dropdown = ref<any>()
const colorMode = useColorMode()
provide(dropdownContextKey, { function hide() {
hide: () => dropdown.hide(), return dropdown.value.hide()
}
provide(InjectionKeyDropdownContext, {
hide,
})
defineExpose({
hide,
}) })
</script> </script>
<template> <template>
<VDropdown v-bind="$attrs" ref="dropdown" :class="{ dark: isDark }" :placement="placement || 'auto'"> <VDropdown v-bind="$attrs" ref="dropdown" :class="colorMode.value" :placement="placement || 'auto'" :auto-boundary-max-size="autoBoundaryMaxSize">
<slot /> <slot />
<template #popper="scope"> <template #popper="scope">
<slot name="popper" v-bind="scope" /> <slot name="popper" v-bind="scope" />

View file

@ -1,20 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import { dropdownContextKey } from './ctx' const props = withDefaults(defineProps<{
is?: string
const props = defineProps<{
text?: string text?: string
description?: string description?: string
icon?: string icon?: string
checked?: boolean checked?: boolean
command?: boolean command?: boolean
}>() }>(), {
is: 'div',
})
const emit = defineEmits(['click']) const emit = defineEmits(['click'])
const { hide } = inject(dropdownContextKey, undefined) || {} const { hide } = useDropdownContext() || {}
const el = ref<HTMLDivElement>() const el = ref<HTMLDivElement>()
const handleClick = (evt: MouseEvent) => { function handleClick(evt: MouseEvent) {
hide?.() hide?.()
emit('click', evt) emit('click', evt)
} }
@ -41,9 +42,13 @@ useCommand({
</script> </script>
<template> <template>
<div <component
v-bind="$attrs" ref="el" v-bind="$attrs"
:is="is"
ref="el"
w-full
flex gap-3 items-center cursor-pointer px4 py3 flex gap-3 items-center cursor-pointer px4 py3
select-none
hover-bg-active hover-bg-active
:aria-label="text" :aria-label="text"
@click="handleClick" @click="handleClick"
@ -68,5 +73,5 @@ useCommand({
<div v-if="checked" i-ri:check-line /> <div v-if="checked" i-ri:check-line />
<slot name="actions" /> <slot name="actions" />
</div> </component>
</template> </template>

View file

@ -1,5 +0,0 @@
import type { InjectionKey } from 'vue'
export const dropdownContextKey: InjectionKey<{
hide: () => void
}> = Symbol('dropdownContextKey')

View file

@ -4,7 +4,7 @@ const props = defineProps<{
lang?: string lang?: string
}>() }>()
const raw = $computed(() => decodeURIComponent(props.code).replace(/&#39;/g, '\'')) const raw = computed(() => decodeURIComponent(props.code).replace(/&#39;/g, '\''))
const langMap: Record<string, string> = { const langMap: Record<string, string> = {
js: 'javascript', js: 'javascript',
@ -13,10 +13,11 @@ const langMap: Record<string, string> = {
} }
const highlighted = computed(() => { const highlighted = computed(() => {
return props.lang ? highlightCode(raw, (langMap[props.lang] || props.lang) as any) : raw return props.lang ? highlightCode(raw.value, (langMap[props.lang] || props.lang) as any) : raw
}) })
</script> </script>
<template> <template>
<pre class="code-block" v-html="highlighted" /> <pre v-if="lang" class="code-block" v-html="highlighted" />
<pre v-else class="code-block">{{ raw }}</pre>
</template> </template>

View file

@ -0,0 +1,11 @@
<script setup lang="ts">
defineProps<{
replying?: boolean
}>()
</script>
<template>
<p flex="~ gap-1 wrap" items-center text-sm :class="{ 'zen-none': !replying }">
<span i-ri-arrow-right-line ml--1 text-secondary-light /><slot />
</p>
</template>

View file

@ -1,21 +1,29 @@
import type { Emoji } from 'masto' import type { mastodon } from 'masto'
import { emojisArrayToObject } from '~/composables/utils'
defineOptions({ defineOptions({
name: 'ContentRich', name: 'ContentRich',
}) })
const { content, emojis, markdown = true } = defineProps<{ const {
content,
emojis,
hideEmojis = false,
markdown = true,
} = defineProps<{
content: string content: string
emojis?: mastodon.v1.CustomEmoji[]
hideEmojis?: boolean
markdown?: boolean markdown?: boolean
emojis?: Emoji[]
}>() }>()
const emojisObject = useEmojisFallback(() => emojis)
export default () => h( export default () => h(
'span', 'span',
{ class: 'content-rich' }, { class: 'content-rich', dir: 'auto' },
contentToVNode(content, { contentToVNode(content, {
emojis: emojisArrayToObject(emojis || []), emojis: emojisObject.value,
hideEmojis,
markdown, markdown,
}), }),
) )

View file

@ -1,11 +1,11 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Conversation } from 'masto' import type { mastodon } from 'masto'
const { conversation } = defineProps<{ const { conversation } = defineProps<{
conversation: Conversation conversation: mastodon.v1.Conversation
}>() }>()
const withAccounts = $computed(() => const withAccounts = computed(() =>
conversation.accounts.filter(account => account.id !== conversation.lastStatus?.account.id), conversation.accounts.filter(account => account.id !== conversation.lastStatus?.account.id),
) )
</script> </script>
@ -15,7 +15,7 @@ const withAccounts = $computed(() =>
<StatusCard v-if="conversation.lastStatus" :status="conversation.lastStatus" :actions="false"> <StatusCard v-if="conversation.lastStatus" :status="conversation.lastStatus" :actions="false">
<template #meta> <template #meta>
<div flex gap-2 text-sm text-secondary font-bold> <div flex gap-2 text-sm text-secondary font-bold>
<p mr-1> <p me-1>
{{ $t('conversation.with') }} {{ $t('conversation.with') }}
</p> </p>
<AccountAvatar v-for="account in withAccounts" :key="account.id" h-5 w-5 :account="account" /> <AccountAvatar v-for="account in withAccounts" :key="account.id" h-5 w-5 :account="account" />

View file

@ -1,13 +1,20 @@
<script setup lang="ts"> <script setup lang="ts">
import type { Conversation, Paginator } from 'masto' import type { mastodon } from 'masto'
const { paginator } = defineProps<{ const { paginator } = defineProps<{
paginator: Paginator<any, Conversation[]> paginator: mastodon.Paginator<mastodon.v1.Conversation[], mastodon.DefaultPaginationParams>
}>() }>()
function preprocess(items: mastodon.v1.Conversation[]): mastodon.v1.Conversation[] {
const isAuthored = (conversation: mastodon.v1.Conversation) => conversation.lastStatus ? conversation.lastStatus.account.id === currentUser.value?.account.id : false
return items.filter(item => isAuthored(item) || !item.lastStatus?.filtered?.find(
filter => filter.filter.filterAction === 'hide' && filter.filter.context.includes('thread'),
))
}
</script> </script>
<template> <template>
<CommonPaginator :paginator="paginator"> <CommonPaginator :paginator="paginator" :preprocess="preprocess">
<template #default="{ item }"> <template #default="{ item }">
<ConversationCard <ConversationCard
:conversation="item" :conversation="item"

View file

@ -0,0 +1,30 @@
<script setup lang="ts">
const { as, alt, dataEmojiId } = defineProps<{
as: string
alt?: string
dataEmojiId?: string
}>()
const title = ref<string | undefined>()
if (alt) {
if (alt.startsWith(':')) {
title.value = alt.replace(/:/g, '')
}
else {
import('node-emoji').then(({ find }) => {
title.value = find(alt)?.key.replace(/_/g, ' ')
})
}
}
// if it has a data-emoji-id, use that as the title instead
if (dataEmojiId)
title.value = dataEmojiId
</script>
<template>
<component :is="as" v-bind="$attrs" :alt="alt" :data-emoji-id="dataEmojiId" :title="title">
<slot />
</component>
</template>

View file

@ -1,50 +1,18 @@
<script setup lang="ts"> <script setup lang="ts">
interface Team {
github: string
display: string
twitter: string
mastodon: string
}
const emit = defineEmits<{ const emit = defineEmits<{
(event: 'close'): void (event: 'close'): void
}>() }>()
const teams: Team[] = [ const vAutoFocus = (el: HTMLElement) => el.focus()
{
github: 'antfu',
display: 'Anthony Fu',
twitter: 'antfu7',
mastodon: 'antfu@mas.to',
},
{
github: 'patak-dev',
display: 'Patak',
twitter: 'patak_dev',
mastodon: 'patak@webtoo.ls',
},
{
github: 'danielroe',
display: 'Daniel Roe',
twitter: 'danielcroe',
mastodon: 'daniel@roe.dev',
},
{
github: 'sxzz',
display: 'sxzz',
twitter: 'sanxiaozhizi',
mastodon: 'sxzz@mas.to',
},
].sort(() => Math.random() - 0.5)
</script> </script>
<template> <template>
<div my-8 px-3 sm:px-8 md:max-w-200 flex="~ col gap-4" relative> <div my-8 px-3 sm:px-8 md:max-w-200 flex="~ col gap-4" relative>
<button btn-action-icon absolute top--8 right-0 m1 aria-label="Close" @click="emit('close')"> <button v-auto-focus type="button" btn-action-icon absolute top--8 right-0 m1 aria-label="Close" @click="emit('close')">
<div i-ri:close-line /> <span i-ri:close-line />
</button> </button>
<img src="/logo.svg" w-20 h-20 height="80" width="80" mxa alt="logo"> <img :alt="$t('app_logo')" :src="`/${''}logo.svg`" w-20 h-20 height="80" width="80" mxa class="rtl-flip">
<h1 mxa text-4xl mb4> <h1 mxa text-4xl mb4>
{{ $t('help.title') }} {{ $t('help.title') }}
</h1> </h1>
@ -56,23 +24,29 @@ const teams: Team[] = [
{{ $t('help.desc_para2') }} {{ $t('help.desc_para2') }}
</p> </p>
<p> <p>
Before that, if you'd like to help with testing, giving feedback, or contributing, <a font-bold text-primary href="/m.webtoo.ls/@elk" target="_blank"> {{ $t('help.desc_para4') }}
reach out to us on Mastodon <NuxtLink font-bold text-primary href="https://github.com/elk-zone/elk" target="_blank">
</a> and get involved. {{ $t('help.desc_para5') }}
</NuxtLink>
{{ $t('help.desc_para6') }}
</p> </p>
{{ $t('help.desc_para3') }} <NuxtLink hover:text-primary href="https://github.com/sponsors/elk-zone" target="_blank">
<p flex="~ gap-2 wrap" mxa> {{ $t('help.desc_para3') }}
<template v-for="team of teams" :key="team.github"> </NuxtLink>
<a :href="`https://github.com/sponsors/${team.github}`" target="_blank" rounded-full transition duration-300 border="~ transparent" hover="scale-105 border-primary"> <p flex="~ gap-2 wrap justify-center" mxa>
<img :src="`https://res.cloudinary.com/dchoja2nb/image/twitter_name/h_120,w_120/f_auto/${team.twitter}.jpg`" :alt="team.display" rounded-full w-15 h-15 height="60" width="60"> <template v-for="team of elkTeamMembers" :key="team.github">
</a> <NuxtLink :href="team.link" target="_blank" external rounded-full transition duration-300 border="~ transparent" hover="scale-105 border-primary">
<img :src="`/avatars/${team.github}-100x100.png`" :alt="team.display" rounded-full w-15 h-15 height="60" width="60">
</NuxtLink>
</template> </template>
</p> </p>
<p italic flex justify-center w-full> <p italic flex justify-center w-full>
<span text-xl font-script>The Elk Team</span> <NuxtLink href="https://github.com/sponsors/elk-zone" target="_blank">
<span text-xl font-script hover:text-primary transition duration-300>{{ $t('help.footer_team') }}</span>
</NuxtLink>
</p> </p>
<button btn-solid mxa tabindex="2" @click="emit('close')"> <button type="button" btn-solid mxa @click="emit('close')">
{{ $t('action.enter_app') }} {{ $t('action.enter_app') }}
</button> </button>
</div> </div>

View file

@ -0,0 +1,55 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
const { account, list } = defineProps<{
account: mastodon.v1.Account
hoverCard?: boolean
list: string
}>()
cacheAccount(account)
const client = useMastoClient()
const isRemoved = ref(false)
async function edit() {
try {
isRemoved.value
? await client.v1.lists.$select(list).accounts.create({ accountIds: [account.id] })
: await client.v1.lists.$select(list).accounts.remove({ accountIds: [account.id] })
isRemoved.value = !isRemoved.value
}
catch (err) {
console.error(err)
}
}
</script>
<template>
<div flex justify-between hover:bg-active transition-100 items-center>
<AccountInfo
:account="account" hover p1 as="router-link"
:hover-card="hoverCard"
shrink
overflow-hidden
:to="getAccountRoute(account)"
/>
<div>
<CommonTooltip
:content="isRemoved ? $t('list.add_account') : $t('list.remove_account')"
:hover="isRemoved ? 'text-green' : 'text-red'"
no-auto-focus
>
<button
text-sm p2 border-1 transition-colors
border-dark
btn-action-icon
@click="edit"
>
<span :class="isRemoved ? 'i-ri:user-add-line' : 'i-ri:user-unfollow-line'" />
</button>
</CommonTooltip>
</div>
</div>
</template>

View file

@ -0,0 +1,211 @@
<script setup lang="ts">
import type { mastodon } from 'masto'
import { useForm } from 'slimeform'
const emit = defineEmits<{
(e: 'listUpdated', list: mastodon.v1.List): void
(e: 'listRemoved', id: string): void
}>()
const list = defineModel<mastodon.v1.List>({ required: true })
const { t } = useI18n()
const client = useMastoClient()
const { form, isDirty, submitter, reset } = useForm({
form: () => ({ ...list.value }),
})
const isEditing = ref<boolean>(false)
const deleting = ref<boolean>(false)
const actionError = ref<string | undefined>(undefined)
const input = ref<HTMLInputElement>()
const editBtn = ref<HTMLButtonElement>()
const deleteBtn = ref<HTMLButtonElement>()
async function prepareEdit() {
isEditing.value = true
actionError.value = undefined
await nextTick()
input.value?.focus()
}
async function cancelEdit() {
isEditing.value = false
actionError.value = undefined
reset()
await nextTick()
editBtn.value?.focus()
}
const { submit, submitting } = submitter(async () => {
try {
list.value = await client.v1.lists.$select(form.id).update({
title: form.title,
})
cancelEdit()
}
catch (err) {
console.error(err)
actionError.value = (err as Error).message
await nextTick()
input.value?.focus()
}
})
async function removeList() {
if (deleting.value)
return
const confirmDelete = await openConfirmDialog({
title: t('confirm.delete_list.title'),
description: t('confirm.delete_list.description', [list.value.title]),
confirm: t('confirm.delete_list.confirm'),
cancel: t('confirm.delete_list.cancel'),
})
deleting.value = true
actionError.value = undefined
await nextTick()
if (confirmDelete.choice === 'confirm') {
await nextTick()
try {
await client.v1.lists.$select(list.value.id).remove()
emit('listRemoved', list.value.id)
}
catch (err) {
console.error(err)
actionError.value = (err as Error).message
await nextTick()
deleteBtn.value?.focus()
}
finally {
deleting.value = false
}
}
else {
deleting.value = false
}
}
async function clearError() {
actionError.value = undefined
await nextTick()
if (isEditing.value)
input.value?.focus()
else
deleteBtn.value?.focus()
}
onDeactivated(cancelEdit)
</script>
<template>
<form
hover:bg-active flex justify-between items-center gap-x-2
:aria-describedby="actionError ? `action-list-error-${list.id}` : undefined"
:class="actionError ? 'border border-base border-rounded rounded-be-is-0 rounded-be-ie-0 border-b-unset border-$c-danger-active' : null"
@submit.prevent="submit"
>
<div
v-if="isEditing"
bg-base border="~ base" h10 m2 ps-1 pe-4 rounded-3 w-full flex="~ row"
items-center relative focus-within:box-shadow-outline gap-3
>
<CommonTooltip v-if="isEditing" :content="$t('list.cancel_edit')" no-auto-focus>
<button
type="button"
rounded-full text-sm p2 transition-colors
hover:text-primary
@click="cancelEdit()"
>
<span block text-current i-ri:close-fill />
</button>
</CommonTooltip>
<input
ref="input"
v-model="form.title"
rounded-3 w-full bg-transparent
outline="focus:none" pe-4 pb="1px"
flex-1 placeholder-text-secondary
@keydown.esc="cancelEdit()"
>
</div>
<NuxtLink v-else :to="`list/${list.id}`" block grow p4>
{{ form.title }}
</NuxtLink>
<div mr4 flex gap2>
<CommonTooltip v-if="isEditing" :content="$t('list.save')" no-auto-focus>
<button
type="submit"
text-sm p2 border-1 transition-colors
border-dark hover:text-primary
btn-action-icon
:disabled="deleting || !isDirty || submitting"
>
<template v-if="isEditing">
<span v-if="submitting" aria-hidden="true" block animate animate-spin preserve-3d class="rtl-flip">
<span block i-ri:loader-2-fill aria-hidden="true" />
</span>
<span v-else block text-current i-ri:save-2-fill class="rtl-flip" />
</template>
</button>
</CommonTooltip>
<CommonTooltip v-else :content="$t('list.edit')" no-auto-focus>
<button
ref="editBtn"
type="button"
text-sm p2 border-1 transition-colors
border-dark hover:text-primary
btn-action-icon
@click.prevent="prepareEdit"
>
<span block text-current i-ri:edit-2-line class="rtl-flip" />
</button>
</CommonTooltip>
<CommonTooltip :content="$t('list.delete')" no-auto-focus>
<button
type="button"
text-sm p2 border-1 transition-colors
border-dark hover:text-primary
btn-action-icon
:disabled="isEditing"
@click.prevent="removeList"
>
<span v-if="deleting" aria-hidden="true" block animate animate-spin preserve-3d class="rtl-flip">
<span block i-ri:loader-2-fill aria-hidden="true" />
</span>
<span v-else block text-current i-ri:delete-bin-2-line class="rtl-flip" />
</button>
</CommonTooltip>
</div>
</form>
<CommonErrorMessage
v-if="actionError"
:id="`action-list-error-${list.id}`"
:described-by="`action-list-failed-${list.id}`"
class="rounded-bs-is-0 rounded-bs-ie-0 border-t-dashed m-b-2"
>
<header :id="`action-list-failed-${list.id}`" flex justify-between>
<div flex items-center gap-x-2 font-bold>
<div aria-hidden="true" i-ri:error-warning-fill />
<p>{{ $t(`list.${isEditing ? 'edit_error' : 'delete_error'}`) }}</p>
</div>
<CommonTooltip placement="bottom" :content="$t('list.clear_error')" no-auto-focus>
<button
flex rounded-4 p1 hover:bg-active cursor-pointer transition-100 :aria-label="$t('list.clear_error')"
@click="clearError"
>
<span aria-hidden="true" w="1.75em" h="1.75em" i-ri:close-line />
</button>
</CommonTooltip>
</header>
<ol ps-2 sm:ps-1>
<li flex="~ col sm:row" gap-y-1 sm:gap-x-2>
<strong sr-only>{{ $t('list.error_prefix') }}</strong>
<span>{{ actionError }}</span>
</li>
</ol>
</CommonErrorMessage>
</template>

53
components/list/Lists.vue Normal file
View file

@ -0,0 +1,53 @@
<script lang="ts" setup>
const { userId } = defineProps<{
userId: string
}>()
const { client } = useMasto()
const paginator = client.value.v1.lists.list()
const listsWithUser = ref((await client.value.v1.accounts.$select(userId).lists.list()).map(list => list.id))
function indexOfUserInList(listId: string) {
return listsWithUser.value.indexOf(listId)
}
async function edit(listId: string) {
try {
const index = indexOfUserInList(listId)
if (index === -1) {
await client.value.v1.lists.$select(listId).accounts.create({ accountIds: [userId] })
listsWithUser.value.push(listId)
}
else {
await client.value.v1.lists.$select(listId).accounts.remove({ accountIds: [userId] })
listsWithUser.value = listsWithUser.value.filter(id => id !== listId)
}
}
catch (err) {
console.error(err)
}
}
</script>
<template>
<CommonPaginator :end-message="false" :paginator="paginator">
<template #default="{ item }">
<div p4 hover:bg-active block w="100%" flex justify-between items-center gap-4>
<p>{{ item.title }}</p>
<CommonTooltip
:content="indexOfUserInList(item.id) === -1 ? $t('list.add_account') : $t('list.remove_account')"
:hover="indexOfUserInList(item.id) === -1 ? 'text-green' : 'text-red'"
>
<button
text-sm p2 border-1 transition-colors
border-dark
btn-action-icon
@click="() => edit(item.id)"
>
<span :class="indexOfUserInList(item.id) === -1 ? 'i-ri:user-add-line' : 'i-ri:user-unfollow-line'" />
</button>
</CommonTooltip>
</div>
</template>
</CommonPaginator>
</template>

View file

@ -0,0 +1,166 @@
<script setup lang="ts">
const emit = defineEmits(['close'])
const { t } = useI18n()
/* TODOs:
* - I18n
*/
interface ShortcutDef {
keys: string[]
isSequence: boolean
}
interface ShortcutItem {
description: string
shortcut: ShortcutDef
}
interface ShortcutItemGroup {
name: string
items: ShortcutItem[]
}
const isMac = useIsMac()
const modifierKeyName = computed(() => isMac.value ? '⌘' : 'Ctrl')
const shortcutItemGroups = computed<ShortcutItemGroup[]>(() => [
{
name: t('magic_keys.groups.navigation.title'),
items: [
{
description: t('magic_keys.groups.navigation.shortcut_help'),
shortcut: { keys: ['?'], isSequence: false },
},
// {
// description: t('magic_keys.groups.navigation.next_status'),
// shortcut: { keys: ['j'], isSequence: false },
// },
// {
// description: t('magic_keys.groups.navigation.previous_status'),
// shortcut: { keys: ['k'], isSequence: false },
// },
{
description: t('magic_keys.groups.navigation.go_to_search'),
shortcut: { keys: ['/'], isSequence: false },
},
{
description: t('magic_keys.groups.navigation.go_to_home'),
shortcut: { keys: ['g', 'h'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_notifications'),
shortcut: { keys: ['g', 'n'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_conversations'),
shortcut: { keys: ['g', 'c'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_favourites'),
shortcut: { keys: ['g', 'f'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_bookmarks'),
shortcut: { keys: ['g', 'b'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_explore'),
shortcut: { keys: ['g', 'e'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_local'),
shortcut: { keys: ['g', 'l'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_federated'),
shortcut: { keys: ['g', 't'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_lists'),
shortcut: { keys: ['g', 'i'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_settings'),
shortcut: { keys: ['g', 's'], isSequence: true },
},
{
description: t('magic_keys.groups.navigation.go_to_profile'),
shortcut: { keys: ['g', 'p'], isSequence: true },
},
],
},
{
name: t('magic_keys.groups.actions.title'),
items: [
{
description: t('magic_keys.groups.actions.search'),
shortcut: { keys: [modifierKeyName.value, 'k'], isSequence: false },
},
{
description: t('magic_keys.groups.actions.command_mode'),
shortcut: { keys: [modifierKeyName.value, '/'], isSequence: false },
},
{
description: t('magic_keys.groups.actions.compose'),
shortcut: { keys: ['c'], isSequence: false },
},
{
description: t('magic_keys.groups.actions.show_new_items'),
shortcut: { keys: ['.'], isSequence: false },
},
{
description: t('magic_keys.groups.actions.favourite'),
shortcut: { keys: ['f'], isSequence: false },
},
{
description: t('magic_keys.groups.actions.boost'),
shortcut: { keys: ['b'], isSequence: false },
},
],
},
{
name: t('magic_keys.groups.media.title'),
items: [],
},
])
</script>
<template>
<div px-3 sm:px-5 py-2 sm:py-4 max-w-220 relative max-h-screen>
<button btn-action-icon absolute top-1 sm:top-2 right-1 sm:right-2 m1 :aria-label="$t('modals.aria_label_close')" @click="emit('close')">
<div i-ri:close-fill />
</button>
<h2 text-xl font-700 mb3>
{{ $t('magic_keys.dialog_header') }}
</h2>
<div mb2 grid grid-cols-1 md:grid-cols-3 gap-y- md:gap-x-6 lg:gap-x-8>
<div
v-for="group in shortcutItemGroups"
:key="group.name"
>
<h3 font-700 my-2 text-lg>
{{ group.name }}
</h3>
<div
v-for="item in group.items"
:key="item.description"
flex my-1 lg:my-2 justify-between place-items-center max-w-full text-base
>
<div mr-2 break-words overflow-hidden leading-4 h-full inline-block align-middle>
{{ item.description }}
</div>
<div>
<template
v-for="(key, idx) in item.shortcut.keys"
:key="idx"
>
<span v-if="idx !== 0" mx1 text-sm op80>{{ item.shortcut.isSequence ? $t('magic_keys.sequence_then') : '+' }}</span>
<code class="px2 md:px1.5 lg:px2 lg:px2 py0 lg:py-0.5" rounded bg-code border="px $c-border-code" shadow-sm my1 font-mono font-600>{{ key }}</code>
</template>
</div>
</div>
</div>
</div>
</div>
</template>

View file

@ -1,32 +1,69 @@
<script setup lang="ts"> <script setup lang="ts">
defineProps<{ defineProps<{
/** Show the back button on small screens */
backOnSmallScreen?: boolean
/** Show the back button on both small and big screens */
back?: boolean back?: boolean
/** Do not applying overflow hidden to let use floatable components in title */
noOverflowHidden?: boolean
}>() }>()
const container = ref()
const route = useRoute()
const userSettings = useUserSettings()
const { height: windowHeight } = useWindowSize()
const { height: containerHeight } = useElementBounding(container)
const wideLayout = computed(() => route.meta.wideLayout ?? false)
const sticky = computed(() => route.path?.startsWith('/settings/'))
const containerClass = computed(() => {
// we keep original behavior when not in settings page and when the window height is smaller than the container height
if (!isHydrated.value || !sticky.value || (windowHeight.value < containerHeight.value))
return null
return 'lg:sticky lg:top-0'
})
</script> </script>
<template> <template>
<div relative> <div ref="container" :class="containerClass">
<div <div
sticky top-0 z10 sticky top-0 z10
border="b base" bg-base pt="[env(safe-area-inset-top,0)]"
bg="[rgba(var(--rgb-bg-base),0.7)]"
class="native:lg:w-[calc(100vw-5rem)] native:xl:w-[calc(135%+(100vw-1200px)/2)]"
:class="{
'backdrop-blur': !getPreferences(userSettings, 'optimizeForLowPerformanceDevice'),
}"
> >
<div flex justify-between px5 py4> <div flex justify-between px5 py2 :class="{ 'xl:hidden': $route.name !== 'tag' }" class="native:xl:flex" border="b base">
<div flex gap-3 items-center overflow-hidden> <div flex gap-3 items-center :overflow-hidden="!noOverflowHidden ? '' : false" py2 w-full>
<NuxtLink v-if="back" flex="~ gap1" items-center btn-text p-0 @click="$router.go(-1)"> <NuxtLink
<div i-ri:arrow-left-line /> v-if="backOnSmallScreen || back" flex="~ gap1" items-center btn-text p-0 xl:hidden
:aria-label="$t('nav.back')"
@click="$router.go(-1)"
>
<div i-ri:arrow-left-line class="rtl-flip" />
</NuxtLink> </NuxtLink>
<div truncate> <div :truncate="!noOverflowHidden ? '' : false" flex w-full data-tauri-drag-region class="native-mac:justify-start native-mac:text-center">
<slot name="title" /> <slot name="title" />
</div> </div>
<div h-7 w-1px /> <div sm:hidden h-7 w-1px />
</div> </div>
<div flex items-center flex-shrink-0 gap-x-2> <div flex items-center flex-shrink-0 gap-x-2>
<slot name="actions" /> <slot name="actions" />
<NavUser v-if="isHydrated.value" /> <PwaBadge xl:hidden />
<NavUser v-if="isHydrated" />
<NavUserSkeleton v-else />
</div> </div>
</div> </div>
<slot name="header" /> <slot name="header">
<div hidden />
</slot>
</div>
<PwaInstallPrompt xl:hidden />
<div :class="isHydrated && wideLayout ? 'xl:w-full sm:max-w-600px' : 'sm:max-w-600px md:shrink-0'" m-auto>
<div hidden :class="{ 'xl:block': $route.name !== 'tag' && !$slots.header }" h-6 />
<slot />
</div> </div>
<slot />
</div> </div>
</template> </template>

View file

@ -0,0 +1,45 @@
<script setup lang="ts">
const model = defineModel<number>()
const isValid = defineModel<boolean>('isValid')
const days = ref<number | ''>(0)
const hours = ref<number | ''>(1)
const minutes = ref<number | ''>(0)
watchEffect(() => {
if (days.value === '' || hours.value === '' || minutes.value === '') {
isValid.value = false
return
}
const duration
= days.value * 24 * 60 * 60
+ hours.value * 60 * 60
+ minutes.value * 60
if (duration <= 0) {
isValid.value = false
return
}
isValid.value = true
model.value = duration
})
</script>
<template>
<div flex flex-grow-0 gap-2>
<label flex items-center gap-2>
<input v-model="days" type="number" min="0" max="1999" input-base :class="!isValid ? 'input-error' : null">
{{ $t('confirm.mute_account.days', days === '' ? 0 : days) }}
</label>
<label flex items-center gap-2>
<input v-model="hours" type="number" min="0" max="24" input-base :class="!isValid ? 'input-error' : null">
{{ $t('confirm.mute_account.hours', hours === '' ? 0 : hours) }}
</label>
<label flex items-center gap-2>
<input v-model="minutes" type="number" min="0" max="59" step="5" input-base :class="!isValid ? 'input-error' : null">
{{ $t('confirm.mute_account.minute', minutes === '' ? 0 : minutes) }}
</label>
</div>
</template>

View file

@ -0,0 +1,57 @@
<script setup lang="ts">
import type { ConfirmDialogChoice, ConfirmDialogOptions } from '~/types'
import DurationPicker from '~/components/modal/DurationPicker.vue'
const props = defineProps<ConfirmDialogOptions>()
const emit = defineEmits<{
(evt: 'choice', choice: ConfirmDialogChoice): void
}>()
const hasDuration = ref(false)
const isValidDuration = ref(true)
const duration = ref(60 * 60) // default to 1 hour
const shouldMuteNotifications = ref(true)
const isMute = computed(() => props.extraOptionType === 'mute')
function handleChoice(choice: ConfirmDialogChoice['choice']) {
const dialogChoice = {
choice,
...isMute.value && {
extraOptions: {
mute: {
duration: hasDuration.value ? duration.value : 0,
notifications: shouldMuteNotifications.value,
},
},
},
}
emit('choice', dialogChoice)
}
</script>
<template>
<div flex="~ col" gap-6>
<div font-bold text-lg>
{{ title }}
</div>
<div v-if="description">
{{ description }}
</div>
<div v-if="isMute" flex-col flex gap-4>
<CommonCheckbox v-model="hasDuration" :label="$t('confirm.mute_account.specify_duration')" prepend-checkbox checked-icon-color="text-primary" />
<DurationPicker v-if="hasDuration" v-model="duration" v-model:is-valid="isValidDuration" />
<CommonCheckbox v-model="shouldMuteNotifications" :label="$t('confirm.mute_account.notifications')" prepend-checkbox checked-icon-color="text-primary" />
</div>
<div flex justify-end gap-2>
<button btn-text @click="handleChoice('cancel')">
{{ cancel || $t('confirm.common.cancel') }}
</button>
<button btn-solid :disabled="!isValidDuration" @click="handleChoice('confirm')">
{{ confirm || $t('confirm.common.confirm') }}
</button>
</div>
</div>
</template>

View file

@ -1,10 +1,17 @@
<script setup lang="ts"> <script setup lang="ts">
import type { mastodon } from 'masto'
import type { ConfirmDialogChoice } from '~/types'
import { import {
isCommandPanelOpen, isCommandPanelOpen,
isConfirmDialogOpen,
isEditHistoryDialogOpen, isEditHistoryDialogOpen,
isErrorDialogOpen,
isFavouritedBoostedByDialogOpen,
isKeyboardShortcutsDialogOpen,
isMediaPreviewOpen, isMediaPreviewOpen,
isPreviewHelpOpen, isPreviewHelpOpen,
isPublishDialogOpen, isPublishDialogOpen,
isReportDialogOpen,
isSigninDialogOpen, isSigninDialogOpen,
} from '~/composables/dialog' } from '~/composables/dialog'
@ -17,41 +24,87 @@ const isMac = useIsMac()
// listen to ctrl+/ on windows/linux or cmd+/ on mac // listen to ctrl+/ on windows/linux or cmd+/ on mac
// or shift+ctrl+k on windows/linux or shift+cmd+k on mac // or shift+ctrl+k on windows/linux or shift+cmd+k on mac
useEventListener('keydown', (e: KeyboardEvent) => { useEventListener('keydown', (e: KeyboardEvent) => {
if (e.key === 'k' && (isMac.value ? e.metaKey : e.ctrlKey)) { if ((e.key === 'k' || e.key === 'л') && (isMac.value ? e.metaKey : e.ctrlKey)) {
e.preventDefault() e.preventDefault()
openCommandPanel(e.shiftKey) openCommandPanel(e.shiftKey)
} }
if (e.key === '/' && (isMac.value ? e.metaKey : e.ctrlKey)) { if ((e.key === '/' || e.key === ',') && (isMac.value ? e.metaKey : e.ctrlKey)) {
e.preventDefault() e.preventDefault()
openCommandPanel(true) openCommandPanel(true)
} }
}) })
function handlePublished(status: mastodon.v1.Status) {
lastPublishDialogStatus.value = status
isPublishDialogOpen.value = false
}
function handlePublishClose() {
lastPublishDialogStatus.value = null
}
function handleConfirmChoice(choice: ConfirmDialogChoice) {
confirmDialogChoice.value = choice
isConfirmDialogOpen.value = false
}
function handleFavouritedBoostedByClose() {
isFavouritedBoostedByDialogOpen.value = false
}
</script> </script>
<template> <template>
<template v-if="isMastoInitialised"> <template v-if="isHydrated">
<ModalDialog v-model="isSigninDialogOpen" py-4 px-8 max-w-125> <ModalDialog v-model="isSigninDialogOpen" py-4 px-8 max-w-125>
<UserSignIn /> <UserSignIn />
</ModalDialog> </ModalDialog>
<ModalDialog v-model="isPreviewHelpOpen" max-w-125> <ModalDialog v-model="isPreviewHelpOpen" keep-alive max-w-125>
<HelpPreview @close="closePreviewHelp()" /> <HelpPreview @close="closePreviewHelp()" />
</ModalDialog> </ModalDialog>
<ModalDialog v-model="isPublishDialogOpen" max-w-180 flex> <ModalDialog
v-model="isPublishDialogOpen"
max-w-180 flex
@close="handlePublishClose"
>
<!-- This `w-0` style is used to avoid overflow problems in flex layoutsso don't remove it unless you know what you're doing --> <!-- This `w-0` style is used to avoid overflow problems in flex layoutsso don't remove it unless you know what you're doing -->
<PublishWidget :draft-key="dialogDraftKey" expanded flex-1 w-0 /> <PublishWidget
v-if="dialogDraftKey"
:draft-key="dialogDraftKey" expanded flex-1 w-0
@published="handlePublished"
/>
</ModalDialog> </ModalDialog>
<ModalDialog <ModalDialog
v-model="isMediaPreviewOpen" :model-value="isMediaPreviewOpen"
w-full max-w-full h-full max-h-full w-full max-w-full h-full max-h-full
bg-transparent border-0 shadow-none bg-transparent border-0 shadow-none
@update:model-value="closeMediaPreview"
> >
<ModalMediaPreview v-if="isMediaPreviewOpen" @close="closeMediaPreview()" /> <ModalMediaPreview v-if="isMediaPreviewOpen" @close="closeMediaPreview()" />
</ModalDialog> </ModalDialog>
<ModalDialog v-model="isEditHistoryDialogOpen" max-w-125> <ModalDialog v-model="isEditHistoryDialogOpen" max-w-125>
<StatusEditPreview :edit="statusEdit" /> <StatusEditPreview v-if="statusEdit" :edit="statusEdit" />
</ModalDialog> </ModalDialog>
<ModalDialog v-model="isCommandPanelOpen" max-w-fit flex> <ModalDialog v-model="isCommandPanelOpen" max-w-fit flex>
<CommandPanel @close="closeCommandPanel()" /> <CommandPanel @close="closeCommandPanel()" />
</ModalDialog> </ModalDialog>
<ModalDialog v-model="isConfirmDialogOpen" py-4 px-8 max-w-125>
<ModalConfirm v-if="confirmDialogLabel" v-bind="confirmDialogLabel" @choice="handleConfirmChoice" />
</ModalDialog>
<ModalDialog v-model="isErrorDialogOpen" py-4 px-8 max-w-125>
<ModalError v-if="errorDialogData" v-bind="errorDialogData" />
</ModalDialog>
<ModalDialog
v-model="isFavouritedBoostedByDialogOpen"
max-w-180
@close="handleFavouritedBoostedByClose"
>
<StatusFavouritedBoostedBy />
</ModalDialog>
<ModalDialog v-model="isKeyboardShortcutsDialogOpen" max-w-full sm:max-w-140 md:max-w-170 lg:max-w-220 md:min-w-160>
<MagickeysKeyboardShortcuts @close="closeKeyboardShortcuts()" />
</ModalDialog>
<ModalDialog v-model="isReportDialogOpen" keep-alive max-w-175>
<ReportModal v-if="reportAccount" :account="reportAccount" :status="reportStatus" @close="closeReportDialog()" />
</ModalDialog>
</template> </template>
</template> </template>

View file

@ -1,11 +1,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap' import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
import { useDeactivated } from '~/composables/lifecycle'
export interface Props { export interface Props {
/** v-model dislog visibility */
modelValue: boolean
/** /**
* level of depth * level of depth
* *
@ -40,6 +36,10 @@ export interface Props {
dialogLabelledBy?: string dialogLabelledBy?: string
} }
defineOptions({
inheritAttrs: false,
})
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
zIndex: 100, zIndex: 100,
closeByMask: true, closeByMask: true,
@ -47,15 +47,16 @@ const props = withDefaults(defineProps<Props>(), {
keepAlive: false, keepAlive: false,
}) })
const emits = defineEmits<{ const emit = defineEmits<{
/** v-model dialog visibility */ /** v-model dialog visibility */
(event: 'update:modelValue', value: boolean): void (event: 'close'): void
}>() }>()
const visible = useVModel(props, 'modelValue', emits, { passive: true }) const visible = defineModel<boolean>({ required: true })
const deactivated = useDeactivated() const deactivated = useDeactivated()
const route = useRoute() const route = useRoute()
const userSettings = useUserSettings()
/** scrollable HTML element */ /** scrollable HTML element */
const elDialogMain = ref<HTMLDivElement>() const elDialogMain = ref<HTMLDivElement>()
@ -66,6 +67,8 @@ const { activate } = useFocusTrap(elDialogRoot, {
allowOutsideClick: true, allowOutsideClick: true,
clickOutsideDeactivates: true, clickOutsideDeactivates: true,
escapeDeactivates: true, escapeDeactivates: true,
preventScroll: true,
returnFocusOnDeactivate: true,
}) })
defineExpose({ defineExpose({
@ -75,7 +78,10 @@ defineExpose({
/** close the dialog */ /** close the dialog */
function close() { function close() {
if (!visible.value)
return
visible.value = false visible.value = false
emit('close')
} }
function clickMask() { function clickMask() {
@ -113,9 +119,11 @@ const isVShow = computed(() => {
: true : true
}) })
const bindTypeToAny = ($attrs: any) => $attrs as any function bindTypeToAny($attrs: any) {
return $attrs as any
}
const trapFocusDialog = () => { function trapFocusDialog() {
if (isVShow.value) if (isVShow.value)
nextTick().then(() => activate()) nextTick().then(() => activate())
} }
@ -130,12 +138,6 @@ useEventListener('keydown', (e: KeyboardEvent) => {
}) })
</script> </script>
<script lang="ts">
export default {
inheritAttrs: false,
}
</script>
<template> <template>
<Teleport to="body"> <Teleport to="body">
<!-- Dialog component --> <!-- Dialog component -->
@ -155,7 +157,13 @@ export default {
<!-- corresponding to issue: #106, so please don't remove it. --> <!-- corresponding to issue: #106, so please don't remove it. -->
<!-- Mask layer: blur --> <!-- Mask layer: blur -->
<div class="dialog-mask" absolute inset-0 z-0 bg-transparent opacity-100 backdrop-filter backdrop-blur-sm touch-none /> <div
class="dialog-mask"
:class="{
'backdrop-blur-sm': !getPreferences(userSettings, 'optimizeForLowPerformanceDevice'),
}"
absolute inset-0 z-0 bg-transparent opacity-100 backdrop-filter touch-none
/>
<!-- Mask layer: dimming --> <!-- Mask layer: dimming -->
<div class="dialog-mask" absolute inset-0 z-0 bg-black opacity-48 touch-none h="[calc(100%+0.5px)]" @click="clickMask" /> <div class="dialog-mask" absolute inset-0 z-0 bg-black opacity-48 touch-none h="[calc(100%+0.5px)]" @click="clickMask" />
<!-- Dialog container --> <!-- Dialog container -->

View file

@ -0,0 +1,31 @@
<script setup lang="ts">
import type { ErrorDialogData } from '~/types'
defineProps<ErrorDialogData>()
</script>
<template>
<div flex="~ col" gap-6>
<div font-bold text-lg text-center>
{{ title }}
</div>
<div
flex="~ col"
gap-1 text-sm
pt-1 ps-2 pe-1 pb-2
text-red-600 dark:text-red-400
border="~ base rounded red-600 dark:red-400"
>
<ol ps-2 sm:ps-1>
<li v-for="(message, i) in messages" :key="i" flex="~ col sm:row" gap-y-1 sm:gap-x-2>
{{ message }}
</li>
</ol>
</div>
<div flex justify-end gap-2>
<button btn-text @click="closeErrorDialog()">
{{ close }}
</button>
</div>
</div>
</template>

View file

@ -1,9 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
const emit = defineEmits(['close']) const emit = defineEmits(['close'])
const locked = useScrollLock(document.body)
// Use to avoid strange error when directlying assigning to v-model on ModelMediaPreviewCarousel
const index = mediaPreviewIndex
const current = computed(() => mediaPreviewList.value[mediaPreviewIndex.value]) const current = computed(() => mediaPreviewList.value[mediaPreviewIndex.value])
const hasNext = computed(() => mediaPreviewIndex.value < mediaPreviewList.value.length - 1) const hasNext = computed(() => index.value < mediaPreviewList.value.length - 1)
const hasPrev = computed(() => mediaPreviewIndex.value > 0) const hasPrev = computed(() => index.value > 0)
const keys = useMagicKeys() const keys = useMagicKeys()
@ -12,12 +17,12 @@ whenever(keys.arrowRight, next)
function next() { function next() {
if (hasNext.value) if (hasNext.value)
mediaPreviewIndex.value++ index.value++
} }
function prev() { function prev() {
if (hasPrev.value) if (hasPrev.value)
mediaPreviewIndex.value-- index.value--
} }
function onClick(e: MouseEvent) { function onClick(e: MouseEvent) {
@ -26,46 +31,51 @@ function onClick(e: MouseEvent) {
if (!el) if (!el)
emit('close') emit('close')
} }
onMounted(() => locked.value = true)
onUnmounted(() => locked.value = false)
</script> </script>
<template> <template>
<div relative h-full w-full flex pt-12 @click="onClick"> <div relative h-full w-full flex pt-12 @click="onClick">
<button <button
v-if="hasNext" pointer-events-auto btn-action-icon bg="black/20" :aria-label="$t('action.previous')" v-if="hasNext" pointer-events-auto btn-action-icon bg="black/20" :aria-label="$t('action.previous')"
hover:bg="black/40" dark:bg="white/30" dark:hover:bg="white/20" absolute top="1/2" right-1 hover:bg="black/40" dark:bg="white/30" dark-hover:bg="white/20" absolute top="1/2" right-1 z5
:title="$t('action.next')" @click="next" :title="$t('action.next')" @click="next"
> >
<div i-ri:arrow-right-s-line text-white /> <div i-ri:arrow-right-s-line text-white />
</button> </button>
<button <button
v-if="hasPrev" pointer-events-auto btn-action-icon bg="black/20" aria-label="action.next" v-if="hasPrev" pointer-events-auto btn-action-icon bg="black/20" aria-label="action.next"
hover:bg="black/40" dark:bg="white/30" dark:hover:bg="white/20" absolute top="1/2" left-1 hover:bg="black/40" dark:bg="white/30" dark:hover-bg="white/20" absolute top="1/2" left-1 z5
:title="$t('action.prev')" @click="prev" :title="$t('action.prev')" @click="prev"
> >
<div i-ri:arrow-left-s-line text-white /> <div i-ri:arrow-left-s-line text-white />
</button> </button>
<img
:src="current.url || current.previewUrl" :alt="current.description || ''" max-h-full max-w-full ma
>
<div absolute top-0 w-full flex justify-between> <div flex="~ col center" h-full w-full>
<button <ModalMediaPreviewCarousel v-model="index" :media="mediaPreviewList" @close="emit('close')" />
btn-action-icon bg="black/30" aria-label="action.close" hover:bg="black/40" dark:bg="white/30"
dark:hover:bg="white/20" pointer-events-auto shrink-0 @click="emit('close')" <div bg="black/30" dark:bg="white/10" mb-6 mt-4 text-white rounded-full flex="~ center shrink-0" overflow-hidden>
> <div v-if="mediaPreviewList.length > 1" p="y-1 x-3" rounded-r-0 shrink-0>
<div i-ri:close-line text-white /> {{ index + 1 }} / {{ mediaPreviewList.length }}
</button>
<div bg="black/30" dark:bg="white/10" ml-4 my-auto text-white rounded-full flex="~ center" overflow-hidden>
<div v-if="mediaPreviewList.length > 1" p="y-1 x-2" rounded-r-0 shrink-0>
{{ mediaPreviewIndex + 1 }} / {{ mediaPreviewList.length }}
</div> </div>
<p <p
v-if="current.description" bg="dark/30" dark:bg="white/10" p="y-1 x-2" rounded-r-full line-clamp-1 v-if="current.description" bg="dark/30" dark:bg="white/10" p="y-1 x-3" rounded-ie-full line-clamp-1
ws-pre-wrap break-all :title="current.description" w-full ws-pre-wrap break-all :title="current.description" w-full
> >
{{ current.description }} {{ current.description }}
</p> </p>
</div> </div>
</div> </div>
<div absolute top-0 w-full flex justify-end>
<button
btn-action-icon bg="black/30" aria-label="action.close" hover:bg="black/40" dark:bg="white/30"
dark:hover-bg="white/20" pointer-events-auto shrink-0 @click="emit('close')"
>
<div i-ri:close-line text-white />
</button>
</div>
</div> </div>
</template> </template>

View file

@ -0,0 +1,286 @@
<script setup lang="ts">
import type { Vector2 } from '@vueuse/gesture'
import { useGesture } from '@vueuse/gesture'
import { useReducedMotion } from '@vueuse/motion'
import type { mastodon } from 'masto'
const { media = [] } = defineProps<{
media?: mastodon.v1.MediaAttachment[]
}>()
const emit = defineEmits<{
(event: 'close'): void
}>()
const modelValue = defineModel<number>({ required: true })
const slideGap = 20
const doubleTapThreshold = 250
const view = ref()
const slider = ref()
const slide = ref()
const image = ref()
const reduceMotion = import.meta.server ? ref(false) : useReducedMotion()
const isInitialScrollDone = useTimeout(350)
const canAnimate = computed(() => isInitialScrollDone.value && !reduceMotion.value)
const scale = ref(1)
const x = ref(0)
const y = ref(0)
const isDragging = ref(false)
const isPinching = ref(false)
const maxZoomOut = ref(1)
const isZoomedIn = computed(() => scale.value > 1)
const enableAutoplay = usePreferences('enableAutoplay')
function goToFocusedSlide() {
scale.value = 1
x.value = slide.value[modelValue.value].offsetLeft * scale.value
y.value = 0
}
onMounted(() => {
const slideGapAsScale = slideGap / view.value.clientWidth
maxZoomOut.value = 1 - slideGapAsScale
goToFocusedSlide()
})
watch(modelValue, goToFocusedSlide)
let lastOrigin = [0, 0]
let initialScale = 0
useGesture({
onPinch({ first, initial: [initialDistance], movement: [deltaDistance], da: [distance], origin, touches }) {
isPinching.value = true
if (first) {
initialScale = scale.value
}
else {
if (touches === 0)
handleMouseWheelZoom(initialScale, deltaDistance, origin)
else
handlePinchZoom(initialScale, initialDistance, distance, origin)
}
lastOrigin = origin
},
onPinchEnd() {
isPinching.value = false
isDragging.value = false
if (!isZoomedIn.value)
goToFocusedSlide()
},
onDrag({ movement, delta, pinching, tap, last, swipe, event, xy }) {
event.preventDefault()
if (pinching)
return
if (last)
handleLastDrag(tap, swipe, movement, xy)
else
handleDrag(delta, movement)
},
}, {
domTarget: view,
eventOptions: {
passive: false,
},
})
const shiftRestrictions = computed(() => {
const focusedImage = image.value[modelValue.value]
const focusedSlide = slide.value[modelValue.value]
const scaledImageWidth = focusedImage.offsetWidth * scale.value
const scaledHorizontalOverflow = scaledImageWidth / 2 - view.value.clientWidth / 2 + slideGap
const horizontalOverflow = Math.max(0, scaledHorizontalOverflow / scale.value)
const scaledImageHeight = focusedImage.offsetHeight * scale.value
const scaledVerticalOverflow = scaledImageHeight / 2 - view.value.clientHeight / 2 + slideGap
const verticalOverflow = Math.max(0, scaledVerticalOverflow / scale.value)
return {
left: focusedSlide.offsetLeft - horizontalOverflow,
right: focusedSlide.offsetLeft + horizontalOverflow,
top: focusedSlide.offsetTop - verticalOverflow,
bottom: focusedSlide.offsetTop + verticalOverflow,
}
})
function handlePinchZoom(initialScale: number, initialDistance: number, distance: number, [originX, originY]: Vector2) {
scale.value = initialScale * (distance / initialDistance)
scale.value = Math.max(maxZoomOut.value, scale.value)
const deltaCenterX = originX - lastOrigin[0]
const deltaCenterY = originY - lastOrigin[1]
handleZoomDrag([deltaCenterX, deltaCenterY])
}
function handleMouseWheelZoom(initialScale: number, deltaDistance: number, [originX, originY]: Vector2) {
scale.value = initialScale + (deltaDistance / 1000)
scale.value = Math.max(maxZoomOut.value, scale.value)
const deltaCenterX = lastOrigin[0] - originX
const deltaCenterY = lastOrigin[1] - originY
handleZoomDrag([deltaCenterX, deltaCenterY])
}
function handleLastDrag(tap: boolean, swipe: Vector2, movement: Vector2, position: Vector2) {
isDragging.value = false
if (tap)
handleTap(position)
else if (swipe[0] || swipe[1])
handleSwipe(swipe, movement)
else if (!isZoomedIn.value)
slideToClosestSlide()
}
let lastTapAt = 0
function handleTap([positionX, positionY]: Vector2) {
const now = Date.now()
const isDoubleTap = now - lastTapAt < doubleTapThreshold
lastTapAt = now
if (!isDoubleTap)
return
if (isZoomedIn.value) {
goToFocusedSlide()
}
else {
const focusedSlideBounding = slide.value[modelValue.value].getBoundingClientRect()
const slideCenterX = focusedSlideBounding.left + focusedSlideBounding.width / 2
const slideCenterY = focusedSlideBounding.top + focusedSlideBounding.height / 2
scale.value = 3
x.value += positionX - slideCenterX
y.value += positionY - slideCenterY
restrictShiftToInsideSlide()
}
}
function handleSwipe([horiz, vert]: Vector2, [movementX, movementY]: Vector2) {
if (isZoomedIn.value || isPinching.value)
return
const isHorizontalDrag = Math.abs(movementX) >= Math.abs(movementY)
if (isHorizontalDrag) {
if (horiz === 1) // left
modelValue.value = Math.max(0, modelValue.value - 1)
if (horiz === -1) // right
modelValue.value = Math.min(media.length - 1, modelValue.value + 1)
}
else if (vert === 1 || vert === -1) {
emit('close')
}
goToFocusedSlide()
}
function slideToClosestSlide() {
const startOfFocusedSlide = slide.value[modelValue.value].offsetLeft * scale.value
const slideWidth = slide.value[modelValue.value].offsetWidth * scale.value
if (x.value > startOfFocusedSlide + slideWidth / 2)
modelValue.value = Math.min(media.length - 1, modelValue.value + 1)
else if (x.value < startOfFocusedSlide - slideWidth / 2)
modelValue.value = Math.max(0, modelValue.value - 1)
goToFocusedSlide()
}
function handleDrag(delta: Vector2, movement: Vector2) {
isDragging.value = true
if (isZoomedIn.value)
handleZoomDrag(delta)
else
handleSlideDrag(movement)
}
function handleZoomDrag([deltaX, deltaY]: Vector2) {
x.value -= deltaX / scale.value
y.value -= deltaY / scale.value
restrictShiftToInsideSlide()
}
function handleSlideDrag([movementX, movementY]: Vector2) {
goToFocusedSlide()
if (Math.abs(movementY) > Math.abs(movementX)) // vertical movement is more than horizontal
y.value -= movementY / scale.value
else
x.value -= movementX / scale.value
if (media.length === 1)
x.value = 0
}
function restrictShiftToInsideSlide() {
x.value = Math.min(shiftRestrictions.value.right, Math.max(shiftRestrictions.value.left, x.value))
y.value = Math.min(shiftRestrictions.value.bottom, Math.max(shiftRestrictions.value.top, y.value))
}
const sliderStyle = computed(() => {
const style = {
transform: `scale(${scale.value}) translate(${-x.value}px, ${-y.value}px)`,
transition: 'none',
gap: `${slideGap}px`,
}
if (canAnimate.value && !isDragging.value && !isPinching.value)
style.transition = 'all 0.3s ease'
return style
})
const imageStyle = computed(() => ({
cursor: isDragging.value ? 'grabbing' : 'grab',
}))
</script>
<template>
<div ref="view" flex flex-row h-full w-full overflow-hidden>
<div ref="slider" :style="sliderStyle" w-full h-full flex items-center>
<div
v-for="item in media"
:key="item.id"
ref="slide"
flex-shrink-0
w-full
h-full
flex
items-center
justify-center
>
<component
:is="item.type === 'gifv' ? 'video' : 'img'"
ref="image"
:autoplay="enableAutoplay"
controls
loop
select-none
max-w-full
max-h-full
:style="imageStyle"
:draggable="false"
:src="item.url || item.previewUrl"
:alt="item.description || ''"
/>
</div>
</div>
</div>
</template>

View file

@ -1,6 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
// only one icon can be lit up at the same time // only one icon can be lit up at the same time
import { STORAGE_KEY_LAST_ACCESSED_EXPLORE_ROUTE, STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE } from '~/constants'
const moreMenuVisible = ref(false) const moreMenuVisible = ref(false)
const { notifications } = useNotifications()
const lastAccessedNotificationRoute = useLocalStorage(STORAGE_KEY_LAST_ACCESSED_NOTIFICATION_ROUTE, '')
const lastAccessedExploreRoute = useLocalStorage(STORAGE_KEY_LAST_ACCESSED_EXPLORE_ROUTE, '')
</script> </script>
<template> <template>
@ -10,39 +16,45 @@ const moreMenuVisible = ref(false)
class="after-content-empty after:(h-[calc(100%+0.5px)] w-0.1px pointer-events-none)" class="after-content-empty after:(h-[calc(100%+0.5px)] w-0.1px pointer-events-none)"
> >
<!-- These weird styles above are used for scroll locking, don't change it unless you know exactly what you're doing. --> <!-- These weird styles above are used for scroll locking, don't change it unless you know exactly what you're doing. -->
<template v-if="isMastoInitialised && currentUser"> <template v-if="currentUser">
<NuxtLink to="/home" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 @click="$scrollToTop"> <NuxtLink to="/home" :aria-label="$t('nav.home')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
<div i-ri:home-5-line /> <div i-ri:home-5-line />
</NuxtLink> </NuxtLink>
<NuxtLink to="/notifications" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 @click="$scrollToTop"> <NuxtLink to="/search" :aria-label="$t('nav.search')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
<div i-ri:notification-4-line /> <div i-ri:search-line />
</NuxtLink> </NuxtLink>
</template> <NuxtLink :to="`/notifications/${lastAccessedNotificationRoute}`" :aria-label="$t('nav.notifications')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
<NuxtLink :to="`/${currentServer}/explore`" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 @click="$scrollToTop"> <div flex relative>
<div i-ri:hashtag /> <div class="i-ri:notification-4-line" text-xl />
</NuxtLink> <div v-if="notifications" class="top-[-0.3rem] right-[-0.3rem]" absolute font-bold rounded-full h-4 w-4 text-xs bg-primary text-inverted flex items-center justify-center>
<NuxtLink group :to="`/${currentServer}/public/local`" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 @click="$scrollToTop"> {{ notifications < 10 ? notifications : '•' }}
<div i-ri:group-2-line /> </div>
</NuxtLink> </div>
<template v-if="!isMastoInitialised || !currentUser">
<NuxtLink :to="`/${currentServer}/public`" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 @click="$scrollToTop">
<div i-ri:earth-line />
</NuxtLink> </NuxtLink>
</template> <NuxtLink to="/conversations" :aria-label="$t('nav.conversations')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
<template v-if="isMastoInitialised && currentUser">
<NuxtLink to="/conversations" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 @click="$scrollToTop">
<div i-ri:at-line /> <div i-ri:at-line />
</NuxtLink> </NuxtLink>
</template> </template>
<NavBottomMoreMenu v-slot="{ changeShow, show }" v-model="moreMenuVisible" flex flex-row items-center place-content-center h-full flex-1 cursor-pointer> <template v-else>
<label <NuxtLink :to="`/${currentServer}/explore/${lastAccessedExploreRoute}`" :aria-label="$t('nav.explore')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
<div i-ri:compass-3-line />
</NuxtLink>
<NuxtLink group :to="`/${currentServer}/public/local`" :aria-label="$t('nav.local')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
<div i-ri:group-2-line />
</NuxtLink>
<NuxtLink :to="`/${currentServer}/public`" :aria-label="$t('nav.federated')" :active-class="moreMenuVisible ? '' : 'text-primary'" flex flex-row items-center place-content-center h-full flex-1 class="coarse-pointer:select-none" @click="$scrollToTop">
<div i-ri:earth-line />
</NuxtLink>
</template>
<NavBottomMoreMenu v-slot="{ toggleVisible, show }" v-model="moreMenuVisible" flex flex-row items-center place-content-center h-full flex-1 cursor-pointer>
<button
flex items-center place-content-center h-full flex-1 class="select-none" flex items-center place-content-center h-full flex-1 class="select-none"
:class="show ? '!text-primary' : ''" :class="show ? '!text-primary' : ''"
aria-label="More menu"
@click="toggleVisible"
> >
<input type="checkbox" z="-1" absolute inset-0 opacity-0 @click="changeShow"> <span :class="show ? 'i-ri:close-fill' : 'i-ri:more-fill'" />
<span v-show="show" i-ri:close-fill /> </button>
<span v-show="!show" i-ri:more-fill />
</label>
</NavBottomMoreMenu> </NavBottomMoreMenu>
</nav> </nav>
</template> </template>

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