Compare commits

...

40 Commits

Author SHA1 Message Date
24896d4a36 Merge branch 'misskey-dev:develop' into sim-dev-ja-nya 2021-12-28 02:17:22 +09:00
8aea52e9b4 てぬきにゃ翻訳 2021-12-28 02:05:40 +09:00
30892ebfa3 Update .eslintrc.js 2021-12-28 00:33:27 +09:00
ae2d71553e enhance(client): 🎨 2021-12-27 22:59:14 +09:00
154e418c34 Update const.ts 2021-12-26 12:10:33 +09:00
cfd1888969 refactor 2021-12-26 12:08:22 +09:00
d53795184c enhance(server): better content type detection 2021-12-26 01:43:51 +09:00
fe3609451e enhance(client): 🎨 2021-12-26 01:42:50 +09:00
3692c9eb64 refactor 2021-12-26 01:42:06 +09:00
89a532eeac chore(client): tweak style 2021-12-25 16:53:15 +09:00
85740dd09f fix(client): fix sidebar style
Fix #8049
2021-12-25 16:03:57 +09:00
b05cfe4a84 enhance(client): improve note preview
Fix #8029
2021-12-25 15:49:37 +09:00
322b64c0b4 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-12-25 13:38:55 +09:00
601bc3e3cc clean up 2021-12-25 13:38:53 +09:00
c77fe1f2cf Truncate push notification message (#8089)
* Truncate push notification message

* fix
2021-12-25 02:01:35 +09:00
8e7744a695 fix(client): ドロワーメニューでセーフエリアを考慮するように 2021-12-24 23:25:23 +09:00
901d6894de Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-12-24 12:34:27 +09:00
b463663175 enhance(client): tweak ui 2021-12-24 12:34:24 +09:00
2294e9ffdc Update CONTRIBUTING.md 2021-12-24 01:31:37 +09:00
1122f7281e ノートページでRenoteである場合にnoindexを付加 (#8074) 2021-12-24 01:16:58 +09:00
99ced12ac5 fix(client): fix zindex issue
Fix #8086
2021-12-24 01:07:04 +09:00
2e80f9dfba clean up 2021-12-23 17:05:50 +09:00
3a990dce75 refactor(client): refactor 2021-12-23 17:05:26 +09:00
cc441258db enhance(client): tweak channel pages 2021-12-23 16:10:13 +09:00
ee144acea9 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-12-22 22:38:45 +09:00
35b7ce1a96 enhance(client): メールアドレスの認証にクリック必須に 2021-12-22 22:38:42 +09:00
dc0e55bf16 wip (#8077) 2021-12-21 00:20:30 +09:00
a3dceee7c0 12.100.2 2021-12-18 20:59:05 +09:00
7940417d23 New Crowdin updates (#8058)
* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Traditional)

* New translations ja-JP.yml (Ukrainian)

* New translations ja-JP.yml (Spanish)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Dutch)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Czech)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Japanese, Kansai)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (English)
2021-12-18 20:54:35 +09:00
b1751543aa fix(client): カスタム絵文字一覧ページの負荷が高いのを修正 2021-12-18 20:20:49 +09:00
034dcaeb9d clean up 2021-12-18 20:20:02 +09:00
936fb136d2 🎨 2021-12-18 20:12:09 +09:00
55ab528c87 Update CHANGELOG.md 2021-12-18 18:13:50 +09:00
c544e38f34 fix(client/deck): カラムの増減がページをリロードするまで正しく反映されない問題を修正
Fix #8065
2021-12-18 18:11:45 +09:00
9b771baa5e 🎨 2021-12-18 15:00:29 +09:00
f607faef0b refactor(client): improve $i type 2021-12-18 14:56:35 +09:00
cb16ff866c improve(client): show reload tip 2021-12-18 14:56:15 +09:00
d6e85ffb59 feat(client): improve toast component and show welcome message 2021-12-18 14:55:53 +09:00
f9e3fd7001 fix(client): fix zindex issue 2021-12-18 12:14:27 +09:00
ba1e14443c fix(client): fix zindex issue
Fix #8064
Fix #8063
2021-12-18 12:12:47 +09:00
101 changed files with 2459 additions and 602 deletions

View File

@ -7,6 +7,21 @@
-->
## 12.x.x (unreleased)
### Improvements
- クライアント: ノートプレビューの精度を改善
### Bugfixes
- クライアント: 一部のコンポーネントが裏に隠れるのを修正
## 12.100.2 (2021/12/18)
### Bugfixes
- クライアント: Deckカラムの増減がページをリロードするまで正しく反映されない問題を修正
- クライアント: 一部のコンポーネントが裏に隠れるのを修正
- クライアント: カスタム絵文字一覧ページの負荷が高いのを修正
## 12.100.1 (2021/12/17)
### Bugfixes

View File

@ -87,7 +87,7 @@ Configuration files are located in [`/.github/workflows`](/.github/workflows).
## Vue
Misskey uses Vue(v3) as its front-end framework.
**When creating a new component, please use the Composition API instead of the Options API.**
**When creating a new component, please use the Composition API (and [setup sugar](https://v3.vuejs.org/api/sfc-script-setup.html)) instead of the Options API.**
Some of the existing components are implemented in the Options API, but it is an old implementation. Refactors that migrate those components to the Composition API are also welcome.
## Adding MisskeyRoom items

View File

@ -106,7 +106,6 @@ clickToShow: "اضغط للعرض"
sensitive: "محتوى حساس"
add: "إضافة"
reaction: "التفاعلات"
reactionSettingDescription: "اختر التفاعلات المفضلة التي تريد تثبيتها في منتقي التفاعلات."
reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة."
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
attachCancel: "أزل المرفق"

View File

@ -88,7 +88,6 @@ clickToShow: "Klikněte pro zobrazení"
sensitive: "NSFW"
add: "Přidat"
reaction: "Reakce"
reactionSettingDescription: "Vyberte Vaší oblíbenou reakci, kterou chcete připnout ve výběru."
reactionSettingDescription2: "Přetažením změníte pořadí, kliknutím smažete, zmáčkněte \"+\" k přidání"
rememberNoteVisibility: "Zapamatovat nastavení zobrazení poznámky"
attachCancel: "Odstranit přílohu"

View File

@ -106,7 +106,7 @@ clickToShow: "Zum Anzeigen anklicken"
sensitive: "NSFW"
add: "Hinzufügen"
reaction: "Reaktionen"
reactionSettingDescription: "Wähle die Reaktionen aus, die in der Reaktionsauswahl angezeigt werden sollen."
reactionSetting: "In der Reaktionsauswahl anzuzeigende Reaktionen"
reactionSettingDescription2: "Ziehe zum Anordnen, klicke zum Löschen, drücke + zum Hinzufügen"
rememberNoteVisibility: "Notizsichtbarkeit merken"
attachCancel: "Anhang entfernen"
@ -685,6 +685,7 @@ center: "Mitte"
wide: "Breit"
narrow: "Schmal"
reloadToApplySetting: "Diese Einstellung tritt nach einer Aktualisierung der Seite in Kraft. Jetzt aktualisieren?"
needReloadToApply: "Diese Einstellung tritt nach einer Aktualisierung der Seite in Kraft."
showTitlebar: "Titelleiste anzeigen"
clearCache: "Cache leeren"
onlineUsersCount: "{n} Benutzer sind online"
@ -813,6 +814,10 @@ deleteAccountConfirm: "Dein Benutzerkonto wird unwiderruflich gelöscht. Trotzde
incorrectPassword: "Falsches Passwort."
voteConfirm: "Wirklich für \"{choice}\" abstimmen?"
hide: "Inhalt verbergen"
leaveGroup: "Gruppe verlassen"
leaveGroupConfirm: "Möchtest du \"{name}\" wirklich verlassen?"
useDrawerReactionPickerForMobile: "Auf mobilen Geräten ausfahrbare Reaktionsauswahl anzeigen"
welcomeBackWithName: "Willkommen zurück, {name}"
_emailUnavailable:
used: "Diese Email-Adresse wird bereits verwendet"
format: "Das Format dieser Email-Adresse ist ungültig"

View File

@ -106,7 +106,7 @@ clickToShow: "Click to show"
sensitive: "NSFW"
add: "Add"
reaction: "Reactions"
reactionSettingDescription: "Configure which reactions you want to display in the reaction picker."
reactionSetting: "Reactions to show in the reaction picker"
reactionSettingDescription2: "Drag to reorder, Click to delete, Press \"+\" to add"
rememberNoteVisibility: "Remember note visibility settings"
attachCancel: "Remove attachment"
@ -685,6 +685,7 @@ center: "Center"
wide: "Wide"
narrow: "Narrow"
reloadToApplySetting: "This setting will only apply after a page reload. Reload now?"
needReloadToApply: "This setting will only apply after a page reload."
showTitlebar: "Show title bar"
clearCache: "Clear cache"
onlineUsersCount: "{n} users are online"
@ -812,6 +813,10 @@ deleteAccountConfirm: "This will irreversibly delete your account. Proceed?"
incorrectPassword: "Incorrect password."
voteConfirm: "Confirm your vote for \"{choice}\"?"
hide: "Hide"
leaveGroup: "Leave Group"
leaveGroupConfirm: "Are you sure you want to leave \"{name}\"?"
useDrawerReactionPickerForMobile: "Display reaction picker as drawer on mobile"
welcomeBackWithName: "Welcome back, {name}"
_emailUnavailable:
used: "This email address is already being used"
format: "The format of this email address is invalid"

View File

@ -2,7 +2,7 @@
_lang_: "Esperanto"
headlineMisskey: "Reto konektita per notoj"
introMisskey: "Bonvenon! Misskey estas malfermitkoda malcentraliza etbloga servo.\nKreu \"noto\"n por diskonigi nunan aferon, aŭ por paroli vian penson al ĉiuj ĉirkaŭ vi. 📡\nLa funkcion \"reago\" ebligas esprimi rapide vian senton pri la noto de la alia en la Fediverso. 👍\nBonvole esploru novan mondon. 🚀"
monthAndDay: "la {day}a de la {month}a monato"
monthAndDay: "La {day}a de la {month}a monato"
search: "Serĉi"
notifications: "Sciigoj"
username: "Uzantnomo"
@ -67,13 +67,13 @@ driveFileDeleteConfirm: "Ĉu vi certas, ke vi volas forviŝi la dosieron \"{name
unfollowConfirm: "Ĉu vi certas, ke vi volas ĉesi sekvi {name}?"
lists: "Listoj"
noLists: "Neniu listo"
note: "Sendi"
note: "Noti"
notes: "Notoj"
following: "Sekvatoj"
followers: "Sekvantoj"
followsYou: "Sekvas vin"
createList: "Krei liston"
manageLists: "Administri liston"
manageLists: "Bonteni liston"
error: "Eraro"
somethingHappened: "Problemo okazis"
retry: "Provi denove"
@ -101,7 +101,6 @@ clickToShow: "Klaku por malkaŝu"
sensitive: "Enhavo ne estas deca por laborejo (NSFW)"
add: "Aldoni"
reaction: "Reagoj"
reactionSettingDescription: "Agordi la reagojn kiujn vi volas montrigi prefere ĉe la elektilo de reagoj"
rememberNoteVisibility: "Rememori la agordon de videbleco de la laste sendita"
attachCancel: "Deigi aldonaĵon"
markAsSensitive: "Troviĝi NSFW"
@ -129,8 +128,8 @@ emojiUrl: "URL de la emoĵio"
addEmoji: "Aldoni emoĵion"
settingGuide: "Agordaj rekomendoj"
cacheRemoteFiles: "Stapli forajn dosierojn"
flagAsBot: "Agordi por robota uzanto"
flagAsCat: "Agordi por kata uzanto"
flagAsBot: "Marki kiel uzata de roboto"
flagAsCat: "Agordi kiel kat-iĝa"
flagAsCatDescription: "Se vi estas kato, ebligu la agordon."
autoAcceptFollowed: "Aŭtomate akcepti la peton de sekvado far uzantoj kiujn vi sekvas"
addAccount: "Aldoni konton"
@ -280,7 +279,7 @@ normal: "Normala"
instanceName: "Nomo de la nodo"
instanceDescription: "Priskribo de la nodo "
maintainerName: "Nomo de la administranto"
maintainerEmail: "Retpoŝtadreso de la administranto"
maintainerEmail: "Retpoŝta adreso de la administranto"
tosUrl: "URL de kondiĉoj de uzado"
thisYear: "Ĉi-jare"
thisMonth: "Ĉi-monate"
@ -331,10 +330,10 @@ silenceConfirm: "Ĉu vi certas ke vi volas mutigi la uzanton?"
unsilence: "Malmutigi"
unsilenceConfirm: "Ĉu vi certas ke vi volas malmutigi la uzanton?"
popularUsers: "Popularaj uzantoj"
recentlyUpdatedUsers: "Uzantoj kiuj lastatempe sendis noton"
recentlyRegisteredUsers: "Novaliĝintaj uzantoj"
recentlyDiscoveredUsers: "Lastatempe trovitaj uzantoj"
exploreUsersCount: "Tio estas {count} uzantoj"
recentlyUpdatedUsers: "Lastatempe afiŝintaj uzantoj"
recentlyRegisteredUsers: "Lastatempe aniĝintaj uzantoj"
recentlyDiscoveredUsers: "Lastatempe eltrovitaj uzantoj"
exploreUsersCount: "Jen {count} uzantoj"
exploreFediverse: "Esplori la Fediverson"
popularTags: "Popularaj kradvortoj"
userList: "Listoj"
@ -348,7 +347,7 @@ nUsersMentioned: "{n} uzanto(j) menciis"
securityKey: "Sekureca ŝlosilo"
securityKeyName: "Nomo de la ŝlosilo"
registerSecurityKey: "Registri ŝlosilon de sekureco"
lastUsed: "Plej malnove uzita"
lastUsed: "La plej malnove uzita"
unregister: "Malregistriĝi"
passwordLessLogin: "Saluti sen pasvorto"
resetPassword: "Restarigi pasvorton"
@ -359,6 +358,7 @@ notFound: "Ne trovita"
uploadFolder: "Dosierujo implicita por alŝuto"
cacheClear: "Malplenigi staplon"
markAsReadAllNotifications: "Marki ĉiujn sciigojn kiel legita"
markAsReadAllTalkMessages: "Marki ĉiujn retbabiladojn kiel legita"
help: "Manlibro de uzado"
inputMessageHere: "Entajpu masaĝo tie ĉi"
close: "Fermi"
@ -381,7 +381,7 @@ retype: "Retajpu"
noteOf: "Noto de {user}"
inviteToGroup: "Inviti al grupo"
quoteAttached: "Kun citaĵo"
quoteQuestion: "Ĉu vi aldonas citaĵon?"
quoteQuestion: "Ĉu vi volas aldoni citaĵon?"
noMessagesYet: "Ankoraŭ neniu mesaĝo"
newMessageExists: "Vi ricevis novan mesaĝon."
onlyOneFileCanBeAttached: "Oni povas aldoni nur unu dosieron po mesaĝo."
@ -481,7 +481,7 @@ description: "Priskribo"
describeFile: "Priskribi la bildon"
enterFileDescription: "Priskribu"
author: "Aŭtoro"
manage: "Administro"
manage: "Bonteni"
plugins: "Kromaĵoj"
deck: "Kartaro"
useFullReactionPicker: "Uzi la tuton de la elektilon de reagoj"
@ -499,7 +499,7 @@ edit: "Redakti"
emailServer: "Retpoŝta servilo"
enableEmail: "Ebligi dissendon el retpoŝto"
email: "Retpoŝto"
emailAddress: "Retpoŝtadreso"
emailAddress: "Retpoŝta adreso"
smtpConfig: "Agordoj de SMTP servilo"
smtpHost: "Transa servilo"
smtpPort: "Pordo"
@ -586,7 +586,7 @@ saveConfirm: "Ĉu vi konservas la ŝanĝon?"
deleteConfirm: "Ĉu certas forviŝi?"
closeAccount: "Forigi konton"
currentVersion: "Nuna versio"
latestVersion: "Plej nova versio"
latestVersion: "La plej nova versio"
youAreRunningUpToDateClient: "Vi uzas la plej novan version de via kliento."
newVersionOfClientAvailable: "Nova versio de via kliento estas disponebla."
inUse: "Uzata"
@ -608,8 +608,9 @@ offline: "Forkonektita"
instanceBlocking: "Bloki specifajn nodojn"
selectAccount: "Elekti konton"
user: "Uzantoj"
administration: "Administro"
administration: "Bontenado"
accounts: "Kontoj"
recentPosts: "Novaj afiŝoj"
shareWithNote: "Kundividi en noto"
ads: "Reklamaĵo"
memo: "Memorigilo"
@ -630,11 +631,14 @@ breakFollow: "Ĉesigi la sekvadon al vi"
itsOn: "Ŝaltita"
unread: "Nelegita"
controlPanel: "Ŝaltpodio"
manageAccounts: "Bonteni la kontojn"
classic: "Klasika"
ffVisibility: "Videbleco pri viaj sekvataro/sekvantaro\n"
ffVisibilityDescription: "Agordi la videblecon kiu povas vidi tiujn kiujn vi sekvas kaj tiujn kiuj sekvas vin."
continueThread: "Vidi pli mesaĝarojn"
incorrectPassword: "Nevalida pasvorto"
leaveGroup: "Eliĝi el la grupo"
leaveGroupConfirm: "Ĉu vi certas ke vi volas eliĝi el la grupo {name}?"
_emailUnavailable:
used: "La retpoŝto jam estas uzita."
format: "Nevalida formato."
@ -662,7 +666,7 @@ _email:
title: "Vi ricevis peton de sekvado"
_plugin:
install: "Instali kromaĵon"
manage: "Administri kromaĵojn"
manage: "Bonteni kromaĵojn"
_registry:
key: "Ŝlosilo"
keys: "Ŝlosiloj"
@ -709,9 +713,9 @@ _channel:
edit: "Redakti kanalon"
setBanner: "Apliki standardan bildon"
removeBanner: "Forviŝi la standardan bildon"
owned: "Posedaĵo"
owned: "Bontenitaj de vi"
following: "Sekvante"
usersCount: "{n} partoprenanto(j)"
usersCount: "{n} partoprenantoj"
_menuDisplay:
top: "Supro"
hide: "Kaŝi"
@ -721,7 +725,7 @@ _wordMute:
hard: "Per la servilo"
mutedNotes: "Silentigitaj notoj"
_theme:
manage: "Administri kolorarojn"
manage: "Bonteni kolorarojn"
code: "Kolorara kodo"
description: "Priskribo"
defaultValue: "Implicitaĵa valoro"
@ -738,7 +742,7 @@ _theme:
renote: "Plusendita"
buttonBg: "Fono de butono"
driveFolderBg: "Fono de dosierujo de la disko"
messageBg: "Fono de retbabilejo"
messageBg: "Fono de la retbabilejo"
_sfx:
note: "Nova noto"
noteMy: "Mia noto"
@ -780,8 +784,8 @@ _permissions:
"write:favorites": "Redakti vian liston de preferaĵoj"
"read:following": "Vidi la infomaciojn pri tio, kion vi sekvas"
"write:following": "Sekvi aŭ malsekvi alian uzanton"
"read:messaging": "Vidi vian retbabiladon"
"write:messaging": "Retbabilejo"
"read:messaging": "Vidi viajn retbabiladojn"
"write:messaging": "Administri viajn retbabiladojn"
"read:mutes": "Vidi vian liston de silentigitoj"
"write:mutes": "Redakti vian liston de silentigitoj"
"write:notes": "Krei / Forviŝi noton"
@ -901,6 +905,7 @@ _pages:
title: "Temlinio"
url: "URL de paĝo"
alignCenter: "Centrigi"
hideTitleWhenPinned: "Kaŝi la titolon de la paĝo kiam alpinglita"
chooseBlock: "Aldoni blokon"
contentBlocks: "Enhavo"
inputBlocks: "Enigo"
@ -1001,8 +1006,8 @@ _notification:
youGotQuote: "{name} citis"
youRenoted: "{name} plusendis"
youGotPoll: "{name} balotis"
youGotMessagingMessageFromUser: "{name} sentis mesaĝon al vi."
youGotMessagingMessageFromGroup: "Retbabilan mesaĝon oni sendis al la grupo {name}"
youGotMessagingMessageFromUser: "{name} sendis al vi mesaĝon"
youGotMessagingMessageFromGroup: "Oni sendis al la grupo {name} mesaĝon"
youWereFollowed: "eksekvis vin"
youReceivedFollowRequest: "Vi ricevis peton de sekvado"
yourFollowRequestAccepted: "Via peto de sekvado estis akceptita."

View File

@ -104,7 +104,6 @@ clickToShow: "Click para ver"
sensitive: "Marcado como sensible"
add: "Agregar"
reaction: "Reacción"
reactionSettingDescription: "Asigne sus reacción favoritas que desean anclar en el selector de reacciones."
reactionSettingDescription2: "Arrastre para reordenar, click para borrar, apriete la tecla + para añadir."
rememberNoteVisibility: "Recordar visibilidad"
attachCancel: "Quitar adjunto"

View File

@ -106,7 +106,6 @@ clickToShow: "Cliquer pour afficher"
sensitive: "Contenu sensible"
add: "Ajouter"
reaction: "Réactions"
reactionSettingDescription: "Choisissez vos réactions préférées que vous souhaitez épingler dans le sélecteur de réactions."
reactionSettingDescription2: "Déplacer pour réorganiser, cliquer pour effacer, utiliser « + » pour ajouter."
rememberNoteVisibility: "Activer l'option \" se souvenir de la visibilité des notes \" vous permet de réutiliser automatiquement la visibilité utilisée lors de la publication de votre note précédente."
attachCancel: "Supprimer le fichier attaché"

View File

@ -106,7 +106,6 @@ clickToShow: "Klik untuk melihat"
sensitive: "Konten sensitif"
add: "Tambahkan"
reaction: "Reaksi"
reactionSettingDescription: "Masukkan reaksi favorit yang ingin kamu sematkan pada bilah reaksi"
reactionSettingDescription2: "Geser untuk memindah urutkan, klik untuk menghapus, tekan \"+\" untuk menambahkan"
rememberNoteVisibility: "Ingat pengaturan visibilitas catatan"
attachCancel: "Hapus lampiran"

View File

@ -103,7 +103,6 @@ clickToShow: "Clicca per visualizzare"
sensitive: "Contenuto sensibile"
add: "Aggiungi"
reaction: "Reazione"
reactionSettingDescription: "Scegli le reazioni che preferisci e fissale nel pannello di reazioni."
reactionSettingDescription2: "Trascina per riorganizzare, clicca per cancellare, usa il pulsante \"+\" per aggiungere."
rememberNoteVisibility: "Ricordare le impostazioni di visibilità delle note"
attachCancel: "Rimuovi allegato"

View File

@ -448,6 +448,7 @@ uiLanguage: "UIの表示言語"
groupInvited: "グループに招待されました"
aboutX: "{x}について"
useOsNativeEmojis: "OSネイティブの絵文字を使用"
disableDrawer: "メニューをドロワーで表示しない"
youHaveNoGroups: "グループがありません"
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。"
noHistory: "履歴はありません"
@ -613,7 +614,6 @@ regenerateLoginToken: "ログイントークンを再生成"
regenerateLoginTokenDescription: "ログインに使用される内部トークンを再生成します。通常この操作を行う必要はありません。再生成すると、全てのデバイスでログアウトされます。"
setMultipleBySeparatingWithSpace: "スペースで区切って複数設定できます。"
fileIdOrUrl: "ファイルIDまたはURL"
chatOpenBehavior: "チャットを開くときの動作"
behavior: "動作"
sample: "サンプル"
abuseReports: "通報"
@ -685,6 +685,7 @@ center: "中央"
wide: "広い"
narrow: "狭い"
reloadToApplySetting: "設定はページリロード後に反映されます。今すぐリロードしますか?"
needReloadToApply: "反映には再起動が必要です。"
showTitlebar: "タイトルバーを表示する"
clearCache: "キャッシュをクリア"
onlineUsersCount: "{n}人がオンライン"
@ -816,6 +817,8 @@ hide: "隠す"
leaveGroup: "グループから抜ける"
leaveGroupConfirm: "「{name}」から抜けますか?"
useDrawerReactionPickerForMobile: "モバイルデバイスのときドロワーで表示"
welcomeBackWithName: "おかえりなさい、{name}さん"
clickToFinishEmailVerification: "[{ok}]を押して、メールアドレスの確認を完了してください。"
_emailUnavailable:
used: "既に使用されています"

View File

@ -104,7 +104,6 @@ clickToShow: "押したら見えるで"
sensitive: "ちょっとアカンやつやで"
add: "増やす"
reaction: "リアクション"
reactionSettingDescription: "リアクションピッカーに出しとくリアクションを選んでや。"
reactionSettingDescription2: "ドラッグで並び替え、クリックで削除、+を押して追加やで。"
rememberNoteVisibility: "公開範囲覚えといて"
attachCancel: "のっけるのやめる"
@ -204,7 +203,7 @@ noJobs: "ジョブはあらへん"
federating: "連合しとる"
blocked: "ブロックしとる"
suspended: "配信せぇへん"
all: "みな"
all: "みな"
subscribing: "購読しとる"
publishing: "配信しとる"
notResponding: "応答してへんで"
@ -849,7 +848,7 @@ _permissions:
_auth:
permissionAsk: "このアプリは次の権限を要求しとるで"
_antennaSources:
all: "みなのノート"
all: "みなのノート"
homeTimeline: "フォローしとるユーザーのノート"
_weekday:
sunday: "日曜日"
@ -897,7 +896,7 @@ _poll:
votesCount: "{n}票"
vote: "投票する"
_visibility:
publicDescription: "みなのユーザーに公開"
publicDescription: "みなに公開"
home: "ホーム"
followers: "フォロワー"
_profile:

1779
locales/ja-NYA.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@ -106,7 +106,6 @@ clickToShow: "클릭하여 보기"
sensitive: "열람주의"
add: "추가"
reaction: "리액션"
reactionSettingDescription: "리액션 선택 상자에 표시할 리액션을 설정합니다."
reactionSettingDescription2: "끌어서 순서 변경, 클릭해서 삭제, +를 눌러서 추가할 수 있습니다."
rememberNoteVisibility: "공개 범위를 기억하기"
attachCancel: "첨부 취소"

View File

@ -106,7 +106,6 @@ clickToShow: "Klik om te bekijken"
sensitive: "NSFW"
add: "Toevoegen"
reaction: "Reacties"
reactionSettingDescription: "Configureer welke reacties je wilt weergeven in de reactiekiezer."
reactionSettingDescription2: "Sleep om opnieuw te ordenen, Klik om te verwijderen, Druk op \"+\" om toe te voegen"
rememberNoteVisibility: "Vergeet niet de notitie zichtbaarheidsinstellingen"
attachCancel: "Verwijder bijlage"

View File

@ -104,7 +104,6 @@ clickToShow: "Kliknij, aby wyświetlić"
sensitive: "NSFW"
add: "Dodaj"
reaction: "Reakcja"
reactionSettingDescription: "Przypisz swoje ulubione reakcje, które chcesz przypiąć w wyborze reakcji."
reactionSettingDescription2: "Przeciągnij aby zmienić kolejność, naciśnij aby usunąć, naciśnij „+” aby dodać"
rememberNoteVisibility: "Zapamiętuj ustawienia widoczności wpisu"
attachCancel: "Usuń załącznik"

View File

@ -106,7 +106,6 @@ clickToShow: "Нажмите для просмотра"
sensitive: "Содержимое не для всех"
add: "Добавить"
reaction: "Реакции"
reactionSettingDescription: "Подберите, что будет у вас в палитре реакций"
reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте кнопкой «+»."
rememberNoteVisibility: "Запоминать видимость заметок"
attachCancel: "Удалить вложение"
@ -803,6 +802,7 @@ classic: "Классика"
unmuteThread: "Отключить звук"
ffVisibilityDescription: "Вы можете установить объем вашей следующей/последней информации."
hide: "Спрятать"
leaveGroupConfirm: "Вы хотите оставить \"{name}\"?"
_emailUnavailable:
used: "Уже используется"
format: "Неправильный формат"

View File

@ -103,7 +103,6 @@ clickToShow: "Натисніть для перегляду"
sensitive: "NSFW"
add: "Додати"
reaction: "Реакції"
reactionSettingDescription: "Виберіть свої улюблені реакції, які хочете закріпити в селекторі реакцій."
reactionSettingDescription2: "Перемістити щоб змінити порядок, Клацнути мишою щоб видалити, Натиснути \"+\" щоб додати."
rememberNoteVisibility: "Пам’ятати параметри видимісті"
attachCancel: "Видалити вкладення"

View File

@ -106,7 +106,7 @@ clickToShow: "点击以显示"
sensitive: "敏感内容"
add: "添加"
reaction: "回应"
reactionSettingDescription: "选择您想要置顶的回应"
reactionSetting: "选择器中显示的回应"
reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。"
rememberNoteVisibility: "保存上次设置的可见性"
attachCancel: "删除附件"
@ -813,6 +813,9 @@ deleteAccountConfirm: "将要删除账户。是否确认?"
incorrectPassword: "密码错误"
voteConfirm: "确定投给“{choice}” "
hide: "隐藏"
leaveGroup: "离开群组"
leaveGroupConfirm: "确定离开「{name}」?"
useDrawerReactionPickerForMobile: "在移动设备上使用抽屉显示"
_emailUnavailable:
used: "已经被使用过"
format: "无效的格式"

View File

@ -104,7 +104,6 @@ clickToShow: "按一下以顯示"
sensitive: "敏感內容"
add: "新增"
reaction: "情感"
reactionSettingDescription: "置頂「反應」表情符號\n"
reactionSettingDescription2: "拖動以重新列序,點擊以刪除,按下 + 添加。"
rememberNoteVisibility: "記住貼文可見性"
attachCancel: "移除附件"

View File

@ -1,6 +1,6 @@
{
"name": "misskey",
"version": "12.100.1",
"version": "12.100.2",
"codename": "indigo",
"repository": {
"type": "git",

View File

@ -1,2 +1,47 @@
export const USER_ONLINE_THRESHOLD = 1000 * 60 * 10; // 10min
export const USER_ACTIVE_THRESHOLD = 1000 * 60 * 60 * 24 * 3; // 3days
// ブラウザで直接表示することを許可するファイルの種類のリスト
// ここに含まれないものは application/octet-stream としてレスポンスされる
// SVGはXSSを生むので許可しない
export const FILE_TYPE_BROWSERSAFE = [
// Images
'image/png',
'image/gif',
'image/jpeg',
'image/webp',
'image/apng',
'image/bmp',
'image/tiff',
'image/x-icon',
// OggS
'audio/opus',
'video/ogg',
'audio/ogg',
'application/ogg',
// ISO/IEC base media file format
'video/quicktime',
'video/mp4',
'audio/mp4',
'video/x-m4v',
'audio/x-m4a',
'video/3gpp',
'video/3gpp2',
'video/mpeg',
'audio/mpeg',
'video/webm',
'audio/webm',
'audio/aac',
'audio/x-flac',
'audio/vnd.wave',
];
/*
https://github.com/sindresorhus/file-type/blob/main/supported.js
https://github.com/sindresorhus/file-type/blob/main/core.js
https://developer.mozilla.org/en-US/docs/Web/Media/Formats/Containers
*/

View File

@ -99,7 +99,10 @@ export async function getFileInfo(path: string): Promise<FileInfo> {
/**
* Detect MIME Type and extension
*/
export async function detectType(path: string) {
export async function detectType(path: string): Promise<{
mime: string;
ext: string | null;
}> {
// Check 0 byte
const fileSize = await getFileSize(path);
if (fileSize === 0) {

View File

@ -14,6 +14,7 @@ import { detectType } from '@/misc/get-file-info';
import { convertToJpeg, convertToPngOrJpeg } from '@/services/drive/image-processor';
import { GenerateVideoThumbnail } from '@/services/drive/generate-video-thumbnail';
import { StatusError } from '@/misc/fetch';
import { FILE_TYPE_BROWSERSAFE } from '@/const';
//const _filename = fileURLToPath(import.meta.url);
const _filename = __filename;
@ -27,6 +28,7 @@ const commonReadableHandlerGenerator = (ctx: Koa.Context) => (e: Error): void =>
ctx.set('Cache-Control', 'max-age=300');
};
// eslint-disable-next-line import/no-default-export
export default async function(ctx: Koa.Context) {
const key = ctx.params.key;
@ -81,7 +83,7 @@ export default async function(ctx: Koa.Context) {
const image = await convertFile();
ctx.body = image.data;
ctx.set('Content-Type', image.type);
ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(image.type) ? image.type : 'application/octet-stream');
ctx.set('Cache-Control', 'max-age=31536000, immutable');
} catch (e) {
serverLogger.error(`${e}`);
@ -112,14 +114,14 @@ export default async function(ctx: Koa.Context) {
}).toString();
ctx.body = InternalStorage.read(key);
ctx.set('Content-Type', mime);
ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(mime) ? mime : 'application/octet-stream');
ctx.set('Cache-Control', 'max-age=31536000, immutable');
ctx.set('Content-Disposition', contentDisposition('inline', filename));
} else {
const readable = InternalStorage.read(file.accessKey!);
readable.on('error', commonReadableHandlerGenerator(ctx));
ctx.body = readable;
ctx.set('Content-Type', file.type);
ctx.set('Content-Type', FILE_TYPE_BROWSERSAFE.includes(file.type) ? file.type : 'application/octet-stream');
ctx.set('Cache-Control', 'max-age=31536000, immutable');
ctx.set('Content-Disposition', contentDisposition('inline', file.name));
}

View File

@ -6,6 +6,7 @@ import { createTemp } from '@/misc/create-temp';
import { downloadUrl } from '@/misc/download-url';
import { detectType } from '@/misc/get-file-info';
import { StatusError } from '@/misc/fetch';
import { FILE_TYPE_BROWSERSAFE } from '@/const';
export async function proxyMedia(ctx: Koa.Context) {
const url = 'url' in ctx.query ? ctx.query.url : 'https://' + ctx.params.url;
@ -18,7 +19,7 @@ export async function proxyMedia(ctx: Koa.Context) {
const { mime, ext } = await detectType(path);
if (!mime.startsWith('image/')) throw 403;
if (!FILE_TYPE_BROWSERSAFE.includes(mime)) throw 403;
let image: IImage;

View File

@ -4,6 +4,7 @@ block vars
- const user = note.user;
- const title = user.name ? `${user.name} (@${user.username})` : `@${user.username}`;
- const url = `${config.url}/notes/${note.id}`;
- const isRenote = note.renote && note.text == null && note.fileIds.length == 0 && note.poll == null;
block title
= `${title} | ${instanceName}`
@ -19,7 +20,7 @@ block og
meta(property='og:image' content= user.avatarUrl)
block meta
if user.host || profile.noCrawle
if user.host || isRenote || profile.noCrawle
meta(name='robots' content='noindex')
meta(name='misskey:user-username' content=user.username)

View File

@ -20,6 +20,7 @@ import { isDuplicateKeyValueError } from '@/misc/is-duplicate-key-value-error';
import * as S3 from 'aws-sdk/clients/s3';
import { getS3 } from './s3';
import * as sharp from 'sharp';
import { FILE_TYPE_BROWSERSAFE } from '@/const';
const logger = driveLogger.createSubLogger('register', 'yellow');
@ -241,6 +242,7 @@ export async function generateAlts(path: string, type: string, generateWeb: bool
*/
async function upload(key: string, stream: fs.ReadStream | Buffer, type: string, filename?: string) {
if (type === 'image/apng') type = 'image/png';
if (!FILE_TYPE_BROWSERSAFE.includes(type)) type = 'application/octet-stream';
const meta = await fetchMeta();

View File

@ -3,10 +3,33 @@ import config from '@/config/index';
import { SwSubscriptions } from '@/models/index';
import { fetchMeta } from '@/misc/fetch-meta';
import { Packed } from '@/misc/schema';
import { getNoteSummary } from '@/misc/get-note-summary';
type notificationType = 'notification' | 'unreadMessagingMessage';
type notificationBody = Packed<'Notification'> | Packed<'MessagingMessage'>;
// プッシュメッセージサーバーには文字数制限があるため、内容を削減します
function truncateNotification(notification: Packed<'Notification'>): any {
if (notification.note) {
return {
...notification,
note: {
...notification.note,
// textをgetNoteSummaryしたものに置き換える
text: getNoteSummary(notification.type === 'renote' ? notification.note.renote as Packed<'Note'> : notification.note),
...{
cw: undefined,
reply: undefined,
renote: undefined,
user: undefined as any, // 通知を受け取ったユーザーである場合が多いのでこれも捨てる
}
}
};
}
return notification;
}
export default async function(userId: string, type: notificationType, body: notificationBody) {
const meta = await fetchMeta();
@ -32,7 +55,9 @@ export default async function(userId: string, type: notificationType, body: noti
};
push.sendNotification(pushSubscription, JSON.stringify({
type, body,
type,
body: type === 'notification' ? truncateNotification(body as Packed<'Notification'>) : body,
userId,
}), {
proxy: config.proxy,
}).catch((err: any) => {

View File

@ -1,5 +1,6 @@
import { del, get, set } from '@/scripts/idb-proxy';
import { reactive } from 'vue';
import * as misskey from 'misskey-js';
import { apiUrl } from '@/config';
import { waiting, api, popup, popupMenu, success } from '@/os';
import { unisonReload, reloadChannel } from '@/scripts/unison-reload';
@ -8,13 +9,7 @@ import { i18n } from './i18n';
// TODO: 他のタブと永続化されたstateを同期
type Account = {
id: string;
token: string;
isModerator: boolean;
isAdmin: boolean;
isDeleted: boolean;
};
type Account = misskey.entities.MeDetailed;
const data = localStorage.getItem('account');

View File

@ -157,7 +157,7 @@ export default defineComponent({
items: [],
mfmTags: [],
select: -1,
zIndex: os.claimZIndex(true),
zIndex: os.claimZIndex('high'),
}
},

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" :prefer-type="'dialog'" :front="true" @click="done(true)" @closed="$emit('closed')">
<MkModal ref="modal" :prefer-type="'dialog'" :z-priority="'high'" @click="done(true)" @closed="$emit('closed')">
<div class="mk-dialog">
<div v-if="icon" class="icon">
<i :class="icon"></i>

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" v-slot="{ type, maxHeight }" :prefer-type="asReactionPicker && $store.state.reactionPickerUseDrawerForMobile === false ? 'popup' : 'auto'" :transparent-bg="true" :manual-showing="manualShowing" :src="src" :front="true" @click="$refs.modal.close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
<MkModal ref="modal" v-slot="{ type, maxHeight }" :z-priority="'middle'" :prefer-type="asReactionPicker && $store.state.reactionPickerUseDrawerForMobile === false ? 'popup' : 'auto'" :transparent-bg="true" :manual-showing="manualShowing" :src="src" @click="$refs.modal.close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
<MkEmojiPicker ref="picker" class="ryghynhb _popup _shadow" :class="{ drawer: type === 'drawer' }" :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" :as-drawer="type === 'drawer'" :max-height="maxHeight" @chosen="chosen"/>
</MkModal>
</template>

View File

@ -77,7 +77,7 @@
import { defineComponent, markRaw } from 'vue';
import { emojilist } from '@/scripts/emojilist';
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
import Particle from '@/components/particle.vue';
import Ripple from '@/components/ripple.vue';
import * as os from '@/os';
import { isTouchUsing } from '@/scripts/touch';
import { isMobile } from '@/scripts/is-mobile';
@ -296,9 +296,9 @@ export default defineComponent({
if (ev) {
const el = ev.currentTarget || ev.target;
const rect = el.getBoundingClientRect();
const x = rect.left + (el.clientWidth / 2);
const y = rect.top + (el.clientHeight / 2);
os.popup(Particle, { x, y }, {}, 'end');
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
os.popup(Ripple, { x, y }, {}, 'end');
}
const key = this.getKey(emoji);

View File

@ -5,7 +5,7 @@
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
<input ref="inputEl"
v-model="v"
v-panel
v-adaptive-border
:type="type"
:disabled="disabled"
:required="required"
@ -243,7 +243,8 @@ export default defineComponent({
font-weight: normal;
font-size: 1em;
color: var(--fg);
border: solid 0.5px var(--panel);
background: var(--panel);
border: solid 1px var(--panel);
border-radius: 6px;
outline: none;
box-shadow: none;
@ -251,7 +252,7 @@ export default defineComponent({
transition: border-color 0.1s ease-out;
&:hover {
border-color: var(--inputBorderHover);
border-color: var(--inputBorderHover) !important;
}
}
@ -298,7 +299,7 @@ export default defineComponent({
&.focused {
> input {
border-color: var(--accent);
border-color: var(--accent) !important;
//box-shadow: 0 0 0 4px var(--focus);
}
}

View File

@ -3,7 +3,9 @@
<div class="label" @click="focus"><slot name="label"></slot></div>
<div ref="container" class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick">
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
<select ref="inputEl" v-model="v" v-panel
<select ref="inputEl"
v-model="v"
v-adaptive-border
class="select"
:disabled="disabled"
:required="required"
@ -226,7 +228,7 @@ export default defineComponent({
&:hover {
> .select {
border-color: var(--inputBorderHover);
border-color: var(--inputBorderHover) !important;
}
}
@ -242,6 +244,7 @@ export default defineComponent({
font-weight: normal;
font-size: 1em;
color: var(--fg);
background: var(--panel);
border: solid 1px var(--panel);
border-radius: 6px;
outline: none;
@ -295,7 +298,7 @@ export default defineComponent({
&.focused {
> select {
border-color: var(--accent);
border-color: var(--accent) !important;
}
}

View File

@ -2,10 +2,6 @@
<div
class="ziffeoms"
:class="{ disabled, checked }"
role="switch"
:aria-checked="checked"
:aria-disabled="disabled"
@click.prevent="toggle"
>
<input
ref="input"
@ -13,18 +9,20 @@
:disabled="disabled"
@keydown.enter="toggle"
>
<span v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button">
<span class="handle"></span>
<span ref="button" v-adaptive-border v-tooltip="checked ? $ts.itsOn : $ts.itsOff" class="button" @click.prevent="toggle">
<i class="check fas fa-check"></i>
</span>
<span class="label">
<span><slot></slot></span>
<span @click="toggle"><slot></slot></span>
<p class="caption"><slot name="caption"></slot></p>
</span>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, ref, toRefs } from 'vue';
import * as os from '@/os';
import Ripple from '@/components/ripple.vue';
export default defineComponent({
props: {
@ -37,17 +35,28 @@ export default defineComponent({
default: false
}
},
computed: {
checked(): boolean {
return this.modelValue;
}
setup(props, context) {
const button = ref<HTMLElement>();
const checked = toRefs(props).modelValue;
const toggle = () => {
if (props.disabled) return;
context.emit('update:modelValue', !checked.value);
if (!checked.value) {
const rect = button.value.getBoundingClientRect();
const x = rect.left + (button.value.offsetWidth / 2);
const y = rect.top + (button.value.offsetHeight / 2);
os.popup(Ripple, { x, y, particle: false }, {}, 'end');
}
};
return {
button,
checked,
toggle,
};
},
methods: {
toggle() {
if (this.disabled) return;
this.$emit('update:modelValue', !this.checked);
}
}
});
</script>
@ -55,16 +64,7 @@ export default defineComponent({
.ziffeoms {
position: relative;
display: flex;
cursor: pointer;
transition: all 0.3s;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
transition: all 0.2s ease;
> * {
user-select: none;
@ -80,27 +80,32 @@ export default defineComponent({
> .button {
position: relative;
display: inline-block;
display: inline-flex;
flex-shrink: 0;
margin: 0;
width: 36px;
height: 26px;
background: var(--switchBg);
box-sizing: border-box;
width: 23px;
height: 23px;
outline: none;
border-radius: 999px;
background: var(--panel);
border: solid 1px var(--panel);
border-radius: 4px;
cursor: pointer;
transition: inherit;
> .handle {
position: absolute;
top: 0;
bottom: 0;
left: 5px;
margin: auto 0;
border-radius: 100%;
transition: background-color 0.3s, transform 0.3s;
width: 16px;
height: 16px;
background-color: #fff;
> .check {
margin: auto;
opacity: 0;
color: var(--fgOnAccent);
font-size: 13px;
transform: scale(0.5);
transition: all 0.2s ease;
}
}
&:hover {
> .button {
border-color: var(--inputBorderHover) !important;
}
}
@ -108,13 +113,13 @@ export default defineComponent({
margin-left: 16px;
margin-top: 2px;
display: block;
cursor: pointer;
transition: inherit;
color: var(--fg);
> span {
display: block;
line-height: 20px;
cursor: pointer;
transition: inherit;
}
@ -129,12 +134,6 @@ export default defineComponent({
}
}
&:hover {
> .button {
background-color: var(--accentedBg);
}
}
&.disabled {
opacity: 0.6;
cursor: not-allowed;
@ -142,11 +141,12 @@ export default defineComponent({
&.checked {
> .button {
background-color: var(--accent);
border-color: var(--accent);
background-color: var(--accent) !important;
border-color: var(--accent) !important;
> .handle {
transform: translateX(10px);
> .check {
opacity: 1;
transform: scale(1);
}
}
}

View File

@ -4,7 +4,7 @@
<div class="input" :class="{ disabled, focused, tall, pre }">
<textarea ref="inputEl"
v-model="v"
v-panel
v-adaptive-border
:class="{ code, _monospace: code }"
:disabled="disabled"
:required="required"
@ -210,7 +210,8 @@ export default defineComponent({
font-weight: normal;
font-size: 1em;
color: var(--fg);
border: solid 0.5px var(--panel);
background: var(--panel);
border: solid 1px var(--panel);
border-radius: 6px;
outline: none;
box-shadow: none;
@ -218,13 +219,13 @@ export default defineComponent({
transition: border-color 0.1s ease-out;
&:hover {
border-color: var(--inputBorderHover);
border-color: var(--inputBorderHover) !important;
}
}
&.focused {
> textarea {
border-color: var(--accent);
border-color: var(--accent) !important;
}
}

View File

@ -106,11 +106,6 @@ export default defineComponent({
return;
}
if (this.to.startsWith('/my/messaging')) {
if (ColdDeviceStorage.get('chatOpenBehavior') === 'window') return this.window();
if (ColdDeviceStorage.get('chatOpenBehavior') === 'popout') return this.popout();
}
if (this.behavior) {
if (this.behavior === 'window') {
return this.window();

View File

@ -6,7 +6,7 @@
<i v-else-if="info.icon" class="icon" :class="info.icon"></i>
<div class="title">
<MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="title"/>
<MkUserName v-if="info.userName" :user="info.userName" :nowrap="true" class="title"/>
<div v-else-if="info.title" class="title">{{ info.title }}</div>
<div v-if="!narrow && info.subtitle" class="subtitle">
{{ info.subtitle }}
@ -268,6 +268,7 @@ export default defineComponent({
> .titleContainer {
display: flex;
align-items: center;
max-width: 400px;
overflow: auto;
white-space: nowrap;
text-align: left;

View File

@ -1,7 +1,5 @@
<template>
<component :is="self ? 'MkA' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
@mouseover="onMouseover"
@mouseleave="onMouseleave"
<component :is="self ? 'MkA' : 'a'" ref="el" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
@contextmenu.stop="() => {}"
>
<template v-if="!self">
@ -20,11 +18,11 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, ref } from 'vue';
import { toUnicode as decodePunycode } from 'punycode/';
import { url as local } from '@/config';
import { isTouchUsing } from '@/scripts/touch';
import * as os from '@/os';
import { useTooltip } from '@/scripts/use-tooltip';
export default defineComponent({
props: {
@ -35,74 +33,36 @@ export default defineComponent({
rel: {
type: String,
required: false,
default: null,
}
},
data() {
const self = this.url.startsWith(local);
setup(props) {
const self = props.url.startsWith(local);
const url = new URL(props.url);
const el = ref();
useTooltip(el, (showing) => {
os.popup(import('@/components/url-preview-popup.vue'), {
showing,
url: props.url,
source: el.value,
}, {}, 'closed');
});
return {
local,
schema: null as string | null,
hostname: null as string | null,
port: null as string | null,
pathname: null as string | null,
query: null as string | null,
hash: null as string | null,
schema: url.protocol,
hostname: decodePunycode(url.hostname),
port: url.port,
pathname: decodeURIComponent(url.pathname),
query: decodeURIComponent(url.search),
hash: decodeURIComponent(url.hash),
self: self,
attr: self ? 'to' : 'href',
target: self ? null : '_blank',
showTimer: null,
hideTimer: null,
checkTimer: null,
close: null,
el,
};
},
created() {
const url = new URL(this.url);
this.schema = url.protocol;
this.hostname = decodePunycode(url.hostname);
this.port = url.port;
this.pathname = decodeURIComponent(url.pathname);
this.query = decodeURIComponent(url.search);
this.hash = decodeURIComponent(url.hash);
},
methods: {
async showPreview() {
if (!document.body.contains(this.$el)) return;
if (this.close) return;
const { dispose } = await os.popup(import('@/components/url-preview-popup.vue'), {
url: this.url,
source: this.$el
});
this.close = () => {
dispose();
};
this.checkTimer = setInterval(() => {
if (!document.body.contains(this.$el)) this.closePreview();
}, 1000);
},
closePreview() {
if (this.close) {
clearInterval(this.checkTimer);
this.close();
this.close = null;
}
},
onMouseover() {
if (isTouchUsing) return;
clearTimeout(this.showTimer);
clearTimeout(this.hideTimer);
this.showTimer = setTimeout(this.showPreview, 500);
},
onMouseleave() {
if (isTouchUsing) return;
clearTimeout(this.showTimer);
clearTimeout(this.hideTimer);
this.hideTimer = setTimeout(this.closePreview, 500);
}
}
});
</script>

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkModal ref="modal" :z-priority="'middle'" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="xubzgfga">
<header>{{ image.name }}</header>
<img :src="image.url" :alt="image.comment" :title="image.comment" @click="$refs.modal.close()"/>

View File

@ -105,6 +105,7 @@ export default defineComponent({
return {
previewable,
gallery,
pswpZIndex: os.claimZIndex('middle'),
};
},
});
@ -188,3 +189,11 @@ export default defineComponent({
}
}
</style>
<style lang="scss">
.pswp {
// なぜか機能しない
//z-index: v-bind(pswpZIndex);
z-index: 2000000;
}
</style>

View File

@ -7,7 +7,7 @@
</div>
<div class="body">
<div class="content">
<Mfm :text="text" :author="$i" :i="$i"/>
<Mfm :text="text.trim()" :author="$i" :i="$i"/>
</div>
</div>
</div>
@ -61,6 +61,7 @@ export default defineComponent({
width: 40px;
height: 40px;
border-radius: 8px;
pointer-events: none;
}
> .main {
@ -69,6 +70,7 @@ export default defineComponent({
> .header {
margin-bottom: 2px;
font-weight: bold;
}
> .body {

View File

@ -0,0 +1,74 @@
<template>
<div class="mk-notification-toast" :style="{ zIndex }">
<transition name="notification-toast" appear @after-leave="$emit('closed')">
<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/>
</transition>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XNotification from './notification.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XNotification
},
props: {
notification: {
type: Object,
required: true
}
},
emits: ['closed'],
data() {
return {
showing: true,
zIndex: os.claimZIndex('high'),
};
},
mounted() {
setTimeout(() => {
this.showing = false;
}, 6000);
}
});
</script>
<style lang="scss" scoped>
.notification-toast-enter-active, .notification-toast-leave-active {
transition: opacity 0.3s, transform 0.3s !important;
}
.notification-toast-enter-from, .notification-toast-leave-to {
opacity: 0;
transform: translateX(-250px);
}
.mk-notification-toast {
position: fixed;
left: 0;
width: 250px;
top: 32px;
padding: 0 32px;
pointer-events: none;
@media (max-width: 700px) {
top: initial;
bottom: 112px;
padding: 0 16px;
}
@media (max-width: 500px) {
bottom: 92px;
padding: 0 8px;
}
> .notification {
height: 100%;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
border-radius: 8px;
overflow: hidden;
}
}
</style>

View File

@ -16,7 +16,13 @@
<template #headerLeft>
<button v-if="history.length > 0" v-tooltip="$ts.goBack" class="_button" @click="back()"><i class="fas fa-arrow-left"></i></button>
</template>
<div class="yrolvcoq">
<template #headerRight>
<button v-tooltip="$ts.showInPage" class="_button" @click="expand()"><i class="fas fa-expand-alt"></i></button>
<button v-tooltip="$ts.popout" class="_button" @click="popout()"><i class="fas fa-external-link-alt"></i></button>
<button class="_button" @click="menu"><i class="fas fa-ellipsis-h"></i></button>
</template>
<div class="yrolvcoq" :style="{ background: pageInfo?.bg }">
<MkStickyContainer>
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
<component :is="component" v-bind="props" :ref="changePage"/>
@ -33,6 +39,7 @@ import copyToClipboard from '@/scripts/copy-to-clipboard';
import { resolve } from '@/router';
import { url } from '@/config';
import * as symbols from '@/symbols';
import * as os from '@/os';
export default defineComponent({
components: {
@ -139,6 +146,23 @@ export default defineComponent({
this.props = props;
},
menu(ev) {
os.popupMenu([{
icon: 'fas fa-external-link-alt',
text: this.$ts.openInNewTab,
action: () => {
window.open(this.url, '_blank');
this.$refs.window.close();
}
}, {
icon: 'fas fa-link',
text: this.$ts.copyLink,
action: () => {
copyToClipboard(this.url);
}
}], ev.currentTarget || ev.target);
},
back() {
this.navigate(this.history.pop(), false);
},

View File

@ -2,7 +2,7 @@
<button
v-if="count > 0"
ref="buttonRef"
v-particle="canToggle"
v-ripple="canToggle"
class="hkzvhatu _button"
:class="{ reacted: note.myReaction == reaction, canToggle }"
@click="toggleReaction()"

View File

@ -1,5 +1,5 @@
<template>
<div class="vswabwbm" :style="{ top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }">
<div class="vswabwbm" :style="{ zIndex, top: `${y - 64}px`, left: `${x - 64}px` }" :class="{ active }">
<svg width="128" height="128" viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg">
<circle fill="none" cx="64" cy="64">
<animate attributeName="r"
@ -52,7 +52,8 @@
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, onMounted } from 'vue';
import * as os from '@/os';
export default defineComponent({
props: {
@ -63,37 +64,46 @@ export default defineComponent({
y: {
type: Number,
required: true
},
particle: {
type: Boolean,
required: false,
default: true,
}
},
emits: ['end'],
data() {
setup(props, context) {
const particles = [];
const origin = 64;
const colors = ['#FF1493', '#00FFFF', '#FFE202'];
for (let i = 0; i < 12; i++) {
const angle = Math.random() * (Math.PI * 2);
const pos = Math.random() * 16;
const velocity = 16 + (Math.random() * 48);
particles.push({
size: 4 + (Math.random() * 8),
xA: origin + (Math.sin(angle) * pos),
yA: origin + (Math.cos(angle) * pos),
xB: origin + (Math.sin(angle) * (pos + velocity)),
yB: origin + (Math.cos(angle) * (pos + velocity)),
color: colors[Math.floor(Math.random() * colors.length)]
});
if (props.particle) {
for (let i = 0; i < 12; i++) {
const angle = Math.random() * (Math.PI * 2);
const pos = Math.random() * 16;
const velocity = 16 + (Math.random() * 48);
particles.push({
size: 4 + (Math.random() * 8),
xA: origin + (Math.sin(angle) * pos),
yA: origin + (Math.cos(angle) * pos),
xB: origin + (Math.sin(angle) * (pos + velocity)),
yB: origin + (Math.cos(angle) * (pos + velocity)),
color: colors[Math.floor(Math.random() * colors.length)]
});
}
}
onMounted(() => {
setTimeout(() => {
context.emit('end');
}, 1100);
});
return {
particles
particles,
zIndex: os.claimZIndex('high'),
};
},
mounted() {
setTimeout(() => {
this.$emit('end');
}, 1100);
}
});
</script>
@ -101,7 +111,6 @@ export default defineComponent({
.vswabwbm {
pointer-events: none;
position: fixed;
z-index: 1000000;
width: 128px;
height: 128px;

View File

@ -51,14 +51,13 @@
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</span>
</template>
</MkInput>
<label v-if="meta.tosUrl" class="_formBlock tou">
<input v-model="ToSAgreement" type="checkbox">
<MkSwitch v-if="meta.tosUrl" v-model="ToSAgreement" class="_formBlock tou">
<I18n :src="$ts.agreeTo">
<template #0>
<a :href="meta.tosUrl" class="_link" target="_blank">{{ $ts.tos }}</a>
</template>
</I18n>
</label>
</MkSwitch>
<captcha v-if="meta.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="_formBlock captcha" provider="hcaptcha" :sitekey="meta.hcaptchaSiteKey"/>
<captcha v-if="meta.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="_formBlock captcha" provider="recaptcha" :sitekey="meta.recaptchaSiteKey"/>
<MkButton class="_formBlock" type="submit" :disabled="shouldDisableSubmitting" gradate data-cy-signup-submit>{{ $ts.start }}</MkButton>
@ -258,11 +257,5 @@ export default defineComponent({
.captcha {
margin: 16px 0;
}
> .tou {
display: block;
margin: 16px 0;
cursor: pointer;
}
}
</style>

View File

@ -1,74 +1,70 @@
<template>
<div class="mk-toast" :style="{ zIndex }">
<transition name="notification-slide" appear @after-leave="$emit('closed')">
<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/>
<div class="mk-toast">
<transition name="toast" appear @after-leave="$emit('closed')">
<div v-if="showing" class="body _acrylic" :style="{ zIndex }">
<div class="message">
{{ message }}
</div>
</div>
</transition>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import XNotification from './notification.vue';
import * as os from '@/os';
export default defineComponent({
components: {
XNotification
},
props: {
notification: {
type: Object,
required: true
}
message: {
type: String,
required: true,
},
},
emits: ['closed'],
data() {
return {
showing: true,
zIndex: os.claimZIndex(true),
zIndex: os.claimZIndex('high'),
};
},
mounted() {
setTimeout(() => {
this.showing = false;
}, 6000);
}, 4000);
}
});
</script>
<style lang="scss" scoped>
.notification-slide-enter-active, .notification-slide-leave-active {
.toast-enter-active, .toast-leave-active {
transition: opacity 0.3s, transform 0.3s !important;
}
.notification-slide-enter-from, .notification-slide-leave-to {
.toast-enter-from, .toast-leave-to {
opacity: 0;
transform: translateX(-250px);
transform: translateY(-100%);
}
.mk-toast {
position: fixed;
left: 0;
width: 250px;
top: 32px;
padding: 0 32px;
pointer-events: none;
@media (max-width: 700px) {
top: initial;
bottom: 112px;
padding: 0 16px;
}
@media (max-width: 500px) {
bottom: 92px;
padding: 0 8px;
}
> .notification {
height: 100%;
> .body {
position: fixed;
left: 0;
right: 0;
top: 0;
margin: 0 auto;
margin-top: 16px;
min-width: 300px;
max-width: calc(100% - 32px);
width: min-content;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3);
border-radius: 8px;
overflow: hidden;
overflow: clip;
text-align: center;
pointer-events: none;
> .message {
padding: 16px 24px;
}
}
}
</style>

View File

@ -1,6 +1,6 @@
<template>
<transition :name="$store.state.animation ? 'fade' : ''" appear>
<div class="nvlagfpb" @contextmenu.prevent.stop="() => {}">
<div class="nvlagfpb" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}">
<MkMenu :items="items" class="_popup _shadow" :align="'left'" @close="$emit('closed')"/>
</div>
</transition>
@ -10,6 +10,7 @@
import { defineComponent } from 'vue';
import contains from '@/scripts/contains';
import MkMenu from './menu.vue';
import * as os from '@/os';
export default defineComponent({
components: {
@ -29,6 +30,11 @@ export default defineComponent({
},
},
emits: ['closed'],
data() {
return {
zIndex: os.claimZIndex('high'),
};
},
computed: {
keymap(): any {
return {
@ -82,7 +88,6 @@ export default defineComponent({
<style lang="scss" scoped>
.nvlagfpb {
position: absolute;
z-index: 65535;
}
.fade-enter-active, .fade-leave-active {

View File

@ -280,12 +280,11 @@ export default defineComponent({
> .divider {
margin: 8px 0;
height: 1px;
background: var(--divider);
border-top: solid 0.5px var(--divider);
}
&.asDrawer {
padding: 12px 0;
padding: 12px 0 calc(env(safe-area-inset-bottom, 0px) + 12px) 0;
width: 100%;
> .item {

View File

@ -13,6 +13,7 @@
import { defineComponent, nextTick, onMounted, computed, PropType, ref, watch } from 'vue';
import * as os from '@/os';
import { isTouchUsing } from '@/scripts/touch';
import { defaultStore } from '@/store';
function getFixedContainer(el: Element | null): Element | null {
if (el == null || el.tagName === 'BODY') return null;
@ -49,10 +50,10 @@ export default defineComponent({
type: String,
default: 'auto',
},
front: {
type: Boolean,
zPriority: {
type: String as PropType<'low' | 'middle' | 'high'>,
required: false,
default: false,
default: 'low',
},
noOverlap: {
type: Boolean,
@ -74,10 +75,10 @@ export default defineComponent({
const transformOrigin = ref('center');
const showing = ref(true);
const content = ref<HTMLElement>();
const zIndex = os.claimZIndex(props.front);
const zIndex = os.claimZIndex(props.zPriority);
const type = computed(() => {
if (props.preferType === 'auto') {
if (isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
if (!defaultStore.state.disableDrawer && isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
return 'drawer';
} else {
return props.src != null ? 'popup' : 'dialog';

View File

@ -5,7 +5,12 @@
<MkError v-else-if="error" @retry="init()"/>
<div v-else-if="empty" key="_empty_" class="empty">
<slot name="empty"></slot>
<slot name="empty">
<div class="_fullinfo">
<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
<div>{{ $ts.nothing }}</div>
</div>
</slot>
</div>
<div v-else class="cxiknjgy">

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" v-slot="{ type, maxHeight }" :src="src" :transparent-bg="true" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkModal ref="modal" v-slot="{ type, maxHeight }" :z-priority="'high'" :src="src" :transparent-bg="true" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkMenu :items="items" :align="align" :width="width" :max-height="maxHeight" :as-drawer="type === 'drawer'" class="sfhdhdhq _popup _shadow" :class="{ drawer: type === 'drawer' }" @close="$refs.modal.close()"/>
</MkModal>
</template>

View File

@ -34,7 +34,7 @@ export default defineComponent({
setup(props, context) {
const el = ref<HTMLElement>();
const zIndex = os.claimZIndex(true);
const zIndex = os.claimZIndex('high');
const setPosition = () => {
if (el.value == null) return;

View File

@ -155,7 +155,7 @@ export default defineComponent({
// 最前面へ移動
top() {
(this.$el as any).style.zIndex = os.claimZIndex(this.front);
(this.$el as any).style.zIndex = os.claimZIndex(this.front ? 'middle' : 'low');
},
onBodyMousedown() {
@ -414,6 +414,10 @@ export default defineComponent({
}
}
> .left {
min-width: 16px;
}
> .title {
flex: 1;
position: relative;
@ -421,7 +425,6 @@ export default defineComponent({
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
cursor: move;
}
}

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkModal ref="modal" :z-priority="'middle'" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="ewlycnyt">
<div class="title">{{ $ts.misskeyUpdated }}</div>
<div class="version">{{ version }}🚀</div>

View File

@ -35,7 +35,7 @@ export default defineComponent({
u: null,
top: 0,
left: 0,
zIndex: os.claimZIndex(),
zIndex: os.claimZIndex('middle'),
};
},

View File

@ -65,7 +65,7 @@ export default defineComponent({
fetched: false,
top: 0,
left: 0,
zIndex: os.claimZIndex(),
zIndex: os.claimZIndex('middle'),
};
},

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkModal ref="modal" :z-priority="'high'" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="gqyayizv _popup">
<button key="public" class="_button" :class="{ active: v == 'public' }" data-index="1" @click="choose('public')">
<div><i class="fas fa-globe"></i></div>

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" :prefer-type="'dialog'" @click="success ? done() : () => {}" @closed="$emit('closed')">
<MkModal ref="modal" :prefer-type="'dialog'" :z-priority="'high'" @click="success ? done() : () => {}" @closed="$emit('closed')">
<div class="iuyakobc" :class="{ iconOnly: (text == null) || success }">
<i v-if="success" class="fas fa-check icon success"></i>
<i v-else class="fas fa-spinner fa-pulse icon waiting"></i>

View File

@ -0,0 +1,24 @@
import { Directive } from 'vue';
export default {
mounted(src, binding, vn) {
const getBgColor = (el: HTMLElement) => {
const style = window.getComputedStyle(el);
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
return style.backgroundColor;
} else {
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
}
}
const parentBg = getBgColor(src.parentElement);
const myBg = window.getComputedStyle(src).backgroundColor;
if (parentBg === myBg) {
src.style.borderColor = 'var(--divider)';
} else {
src.style.borderColor = myBg;
}
},
} as Directive;

View File

@ -3,7 +3,7 @@ import { App } from 'vue';
import userPreview from './user-preview';
import size from './size';
import getSize from './get-size';
import particle from './particle';
import ripple from './ripple';
import tooltip from './tooltip';
import hotkey from './hotkey';
import appear from './appear';
@ -11,13 +11,14 @@ import anim from './anim';
import stickyContainer from './sticky-container';
import clickAnime from './click-anime';
import panel from './panel';
import adaptiveBorder from './adaptive-border';
export default function(app: App) {
app.directive('userPreview', userPreview);
app.directive('user-preview', userPreview);
app.directive('size', size);
app.directive('get-size', getSize);
app.directive('particle', particle);
app.directive('ripple', ripple);
app.directive('tooltip', tooltip);
app.directive('hotkey', hotkey);
app.directive('appear', appear);
@ -25,4 +26,5 @@ export default function(app: App) {
app.directive('click-anime', clickAnime);
app.directive('sticky-container', stickyContainer);
app.directive('panel', panel);
app.directive('adaptive-border', adaptiveBorder);
}

View File

@ -7,7 +7,7 @@ export default {
if (style.backgroundColor && !['rgba(0, 0, 0, 0)', 'rgba(0,0,0,0)', 'transparent'].includes(style.backgroundColor)) {
return style.backgroundColor;
} else {
return getBgColor(el.parentElement);
return el.parentElement ? getBgColor(el.parentElement) : 'transparent';
}
}

View File

@ -1,4 +1,4 @@
import Particle from '@/components/particle.vue';
import Ripple from '@/components/ripple.vue';
import { popup } from '@/os';
export default {
@ -9,10 +9,10 @@ export default {
el.addEventListener('click', () => {
const rect = el.getBoundingClientRect();
const x = rect.left + (el.clientWidth / 2);
const y = rect.top + (el.clientHeight / 2);
const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2);
popup(Particle, { x, y }, {}, 'end');
popup(Ripple, { x, y }, {}, 'end');
});
}
};

View File

@ -26,7 +26,7 @@ import { router } from '@/router';
import { applyTheme } from '@/scripts/theme';
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode';
import { i18n } from '@/i18n';
import { stream, confirm, alert, post, popup } from '@/os';
import { stream, confirm, alert, post, popup, toast } from '@/os';
import * as sound from '@/scripts/sound';
import { $i, refreshAccount, login, updateAccount, signout } from '@/account';
import { defaultStore, ColdDeviceStorage } from '@/store';
@ -342,6 +342,18 @@ if ($i) {
});
}
const lastUsed = localStorage.getItem('lastUsed');
if (lastUsed) {
const lastUsedDate = parseInt(lastUsed, 10);
// 二時間以上前なら
if (Date.now() - lastUsedDate > 1000 * 60 * 60 * 2) {
toast(i18n.t('welcomeBackWithName', {
name: $i.name || $i.username,
}));
}
}
localStorage.setItem('lastUsed', Date.now().toString());
if ('Notification' in window) {
// 許可を得ていなかったらリクエスト
if (Notification.permission === 'default') {

View File

@ -162,16 +162,14 @@ export const popups = ref([]) as Ref<{
props: Record<string, any>;
}[]>;
let popupZIndex = 1000000;
let popupZIndexForFront = 2000000;
export function claimZIndex(front = false): number {
if (front) {
popupZIndexForFront += 100;
return popupZIndexForFront;
} else {
popupZIndex += 100;
return popupZIndex;
}
const zIndexes = {
low: 1000000,
middle: 2000000,
high: 3000000,
};
export function claimZIndex(priority: 'low' | 'middle' | 'high' = 'low'): number {
zIndexes[priority] += 100;
return zIndexes[priority];
}
export async function popup(component: Component | typeof import('*.vue') | Promise<Component | typeof import('*.vue')>, props: Record<string, any>, events = {}, disposeEvent?: string) {
@ -223,7 +221,9 @@ export function modalPageWindow(path: string) {
}
export function toast(message: string) {
// TODO
popup(import('@/components/toast.vue'), {
message
}, {}, 'closed');
}
export function alert(props: {

View File

@ -40,7 +40,6 @@ import MkButton from '@/components/ui/button.vue';
import MkSwitch from '@/components/form/switch.vue';
import XModalWindow from '@/components/ui/modal-window.vue';
import MkDriveFileThumbnail from '@/components/drive-file-thumbnail.vue';
import Progress from '@/scripts/loading';
import bytes from '@/filters/bytes';
import * as os from '@/os';
@ -74,11 +73,9 @@ export default defineComponent({
methods: {
async fetch() {
Progress.start();
this.file = await os.api('drive/files/show', { fileId: this.fileId });
this.info = await os.api('admin/drive/show-file', { fileId: this.fileId });
this.isSensitive = this.file.isSensitive;
Progress.done();
},
showUser() {

View File

@ -7,8 +7,6 @@
src="antenna"
:antenna="antennaId"
:sound="true"
@before="before()"
@after="after()"
@queue="queueUpdated"
/>
</div>
@ -17,7 +15,6 @@
<script lang="ts">
import { defineComponent, defineAsyncComponent, computed } from 'vue';
import Progress from '@/scripts/loading';
import XTimeline from '@/components/timeline.vue';
import { scroll } from '@/scripts/scroll';
import * as os from '@/os';
@ -76,14 +73,6 @@ export default defineComponent({
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
},
queueUpdated(q) {
this.queue = q;
},

View File

@ -1,28 +1,26 @@
<template>
<div>
<div class="_section">
<div class="_content">
<MkInput v-model="name">
<template #label>{{ $ts.name }}</template>
</MkInput>
<MkSpacer :content-max="700">
<div class="_formRoot">
<MkInput v-model="name" class="_formBlock">
<template #label>{{ $ts.name }}</template>
</MkInput>
<MkTextarea v-model="description">
<template #label>{{ $ts.description }}</template>
</MkTextarea>
<MkTextarea v-model="description" class="_formBlock">
<template #label>{{ $ts.description }}</template>
</MkTextarea>
<div class="banner">
<MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton>
<div v-else-if="bannerUrl">
<img :src="bannerUrl" style="width: 100%;"/>
<MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton>
</div>
<div class="banner">
<MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton>
<div v-else-if="bannerUrl">
<img :src="bannerUrl" style="width: 100%;"/>
<MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton>
</div>
</div>
<div class="_footer">
<div class="_formBlock">
<MkButton primary @click="save()"><i class="fas fa-save"></i> {{ channelId ? $ts.save : $ts.create }}</MkButton>
</div>
</div>
</div>
</MkSpacer>
</template>
<script lang="ts">
@ -51,9 +49,11 @@ export default defineComponent({
[symbols.PAGE_INFO]: computed(() => this.channelId ? {
title: this.$ts._channel.edit,
icon: 'fas fa-satellite-dish',
bg: 'var(--bg)',
} : {
title: this.$ts._channel.create,
icon: 'fas fa-satellite-dish',
bg: 'var(--bg)',
}),
channel: null,
name: null,

View File

@ -1,29 +1,31 @@
<template>
<div v-if="channel" class="_section">
<div class="wpgynlbz _content _panel _gap" :class="{ hide: !showBanner }">
<XChannelFollowButton :channel="channel" :full="true" class="subscribe"/>
<button class="_button toggle" @click="() => showBanner = !showBanner">
<template v-if="showBanner"><i class="fas fa-angle-up"></i></template>
<template v-else><i class="fas fa-angle-down"></i></template>
</button>
<div v-if="!showBanner" class="hideOverlay">
</div>
<div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner">
<div class="status">
<div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div>
<div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div>
<MkSpacer :content-max="700">
<div v-if="channel">
<div class="wpgynlbz _panel _gap" :class="{ hide: !showBanner }">
<XChannelFollowButton :channel="channel" :full="true" class="subscribe"/>
<button class="_button toggle" @click="() => showBanner = !showBanner">
<template v-if="showBanner"><i class="fas fa-angle-up"></i></template>
<template v-else><i class="fas fa-angle-down"></i></template>
</button>
<div v-if="!showBanner" class="hideOverlay">
</div>
<div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner">
<div class="status">
<div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div>
<div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div>
</div>
<div class="fade"></div>
</div>
<div v-if="channel.description" class="description">
<Mfm :text="channel.description" :is-note="false" :i="$i"/>
</div>
<div class="fade"></div>
</div>
<div v-if="channel.description" class="description">
<Mfm :text="channel.description" :is-note="false" :i="$i"/>
</div>
<XPostForm v-if="$i" :channel="channel" class="post-form _panel _gap" fixed/>
<XTimeline :key="channelId" class="_gap" src="channel" :channel="channelId" @before="before" @after="after"/>
</div>
<XPostForm v-if="$i" :channel="channel" class="post-form _content _panel _gap" fixed/>
<XTimeline :key="channelId" class="_content _gap" src="channel" :channel="channelId" @before="before" @after="after"/>
</div>
</MkSpacer>
</template>
<script lang="ts">
@ -55,6 +57,12 @@ export default defineComponent({
[symbols.PAGE_INFO]: computed(() => this.channel ? {
title: this.channel.name,
icon: 'fas fa-satellite-dish',
bg: 'var(--bg)',
actions: [...(this.$i && this.$i.id === this.channel.userId ? [{
icon: 'fas fa-cog',
text: this.$ts.edit,
handler: this.edit,
}] : [])],
} : null),
channel: null,
showBanner: true,
@ -79,8 +87,10 @@ export default defineComponent({
}
},
created() {
methods: {
edit() {
this.$router.push(`/channels/${this.channel.id}/edit`);
}
},
});
</script>

View File

@ -1,58 +1,63 @@
<template>
<div>
<div v-if="$i" class="_section" style="padding: 0;">
<MkTab v-model="tab" class="_content">
<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._channel.featured }}</option>
<option value="following"><i class="fas fa-heart"></i> {{ $ts._channel.following }}</option>
<option value="owned"><i class="fas fa-edit"></i> {{ $ts._channel.owned }}</option>
</MkTab>
<MkSpacer :content-max="700">
<div v-if="tab === 'featured'" class="_content grwlizim featured">
<MkPagination v-slot="{items}" :pagination="featuredPagination">
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
</MkPagination>
</div>
<div class="_section">
<div v-if="tab === 'featured'" class="_content grwlizim featured">
<MkPagination v-slot="{items}" :pagination="featuredPagination">
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
</MkPagination>
</div>
<div v-if="tab === 'following'" class="_content grwlizim following">
<MkPagination v-slot="{items}" :pagination="followingPagination">
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
</MkPagination>
</div>
<div v-if="tab === 'owned'" class="_content grwlizim owned">
<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
<MkPagination v-slot="{items}" :pagination="ownedPagination">
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
</MkPagination>
</div>
<div v-else-if="tab === 'following'" class="_content grwlizim following">
<MkPagination v-slot="{items}" :pagination="followingPagination">
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
</MkPagination>
</div>
</div>
<div v-else-if="tab === 'owned'" class="_content grwlizim owned">
<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
<MkPagination v-slot="{items}" :pagination="ownedPagination">
<MkChannelPreview v-for="channel in items" :key="channel.id" class="_gap" :channel="channel"/>
</MkPagination>
</div>
</MkSpacer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { computed, defineComponent } from 'vue';
import MkChannelPreview from '@/components/channel-preview.vue';
import MkPagination from '@/components/ui/pagination.vue';
import MkButton from '@/components/ui/button.vue';
import MkTab from '@/components/tab.vue';
import * as symbols from '@/symbols';
export default defineComponent({
components: {
MkChannelPreview, MkPagination, MkButton, MkTab
MkChannelPreview, MkPagination, MkButton,
},
data() {
return {
[symbols.PAGE_INFO]: {
[symbols.PAGE_INFO]: computed(() => ({
title: this.$ts.channel,
icon: 'fas fa-satellite-dish',
action: {
bg: 'var(--bg)',
actions: [{
icon: 'fas fa-plus',
handler: this.create
}
},
text: this.$ts.create,
handler: this.create,
}],
tabs: [{
active: this.tab === 'featured',
title: this.$ts._channel.featured,
icon: 'fas fa-fire-alt',
onClick: () => { this.tab = 'featured'; },
}, {
active: this.tab === 'following',
title: this.$ts._channel.following,
icon: 'fas fa-heart',
onClick: () => { this.tab = 'following'; },
}, {
active: this.tab === 'owned',
title: this.$ts._channel.owned,
icon: 'fas fa-edit',
onClick: () => { this.tab = 'owned'; },
},]
})),
tab: 'featured',
featuredPagination: {
endpoint: 'channels/featured',

View File

@ -12,7 +12,6 @@
import { defineComponent } from 'vue';
import * as os from '@/os';
import copyToClipboard from '@/scripts/copy-to-clipboard';
import VanillaTilt from 'vanilla-tilt';
export default defineComponent({
props: {
@ -22,17 +21,6 @@ export default defineComponent({
}
},
mounted() {
if (this.$store.animation) {
VanillaTilt.init(this.$el, {
reverse: true,
gyroscope: false,
scale: 1.1,
speed: 500,
});
}
},
methods: {
menu(ev) {
os.popupMenu([{
@ -59,8 +47,6 @@ export default defineComponent({
text-align: left;
background: var(--panel);
border-radius: 8px;
transform-style: preserve-3d;
transform: perspective(1000px);
&:hover {
border-color: var(--accent);
@ -69,14 +55,12 @@ export default defineComponent({
> .img {
width: 42px;
height: 42px;
transform: translateZ(20px);
}
> .body {
padding: 0 0 0 8px;
white-space: nowrap;
overflow: hidden;
transform: translateZ(10px);
> .name {
text-overflow: ellipsis;

View File

@ -1,14 +1,13 @@
<template>
<div class="jmelgwjh">
<div class="body">
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'"/>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XNotes from '@/components/notes.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
@ -33,16 +32,6 @@ export default defineComponent({
},
};
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

View File

@ -1,12 +1,11 @@
<template>
<MkSpacer :content-max="800">
<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
<XNotes ref="notes" :pagination="pagination"/>
</MkSpacer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XNotes from '@/components/notes.vue';
import * as symbols from '@/symbols';
@ -29,15 +28,5 @@ export default defineComponent({
},
};
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

View File

@ -1,12 +1,11 @@
<template>
<MkSpacer :content-max="800">
<XNotes :pagination="pagination" @before="before()" @after="after()"/>
<XNotes :pagination="pagination"/>
</MkSpacer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XNotes from '@/components/notes.vue';
import * as symbols from '@/symbols';
@ -28,15 +27,5 @@ export default defineComponent({
},
};
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

View File

@ -1,12 +1,11 @@
<template>
<MkSpacer :content-max="800">
<XNotes :pagination="pagination" @before="before()" @after="after()"/>
<XNotes :pagination="pagination"/>
</MkSpacer>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XNotes from '@/components/notes.vue';
import * as symbols from '@/symbols';
@ -31,15 +30,5 @@ export default defineComponent({
},
};
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

View File

@ -35,7 +35,6 @@
<script lang="ts">
import { computed, defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import MkButton from '@/components/ui/button.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
@ -73,7 +72,6 @@ export default defineComponent({
methods: {
fetch() {
Progress.start();
os.api('users/groups/show', {
groupId: this.groupId
}).then(group => {
@ -82,7 +80,6 @@ export default defineComponent({
userIds: this.group.userIds
}).then(users => {
this.users = users;
Progress.done();
});
});
},

View File

@ -36,7 +36,6 @@
<script lang="ts">
import { computed, defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import MkButton from '@/components/ui/button.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
@ -68,7 +67,6 @@ export default defineComponent({
methods: {
fetch() {
Progress.start();
os.api('users/lists/show', {
listId: this.$route.params.list
}).then(list => {
@ -77,7 +75,6 @@ export default defineComponent({
userIds: this.list.userIds
}).then(users => {
this.users = users;
Progress.done();
});
});
},

View File

@ -1,14 +1,13 @@
<template>
<MkSpacer :content-max="800">
<div class="clupoqwt">
<XNotifications class="notifications" :include-types="includeTypes" :unread-only="tab === 'unread'" @before="before" @after="after"/>
<XNotifications class="notifications" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
</div>
</MkSpacer>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XNotifications from '@/components/notifications.vue';
import * as os from '@/os';
import * as symbols from '@/symbols';
@ -53,14 +52,6 @@ export default defineComponent({
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
},
setFilter(ev) {
const typeItems = notificationTypes.map(t => ({
text: this.$t(`_notification._types.${t}`),

View File

@ -1,14 +1,13 @@
<template>
<div class="_section">
<div class="_content">
<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
<XNotes ref="notes" :pagination="pagination"/>
</div>
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XNotes from '@/components/notes.vue';
import * as symbols from '@/symbols';
@ -39,15 +38,5 @@ export default defineComponent({
(this.$refs.notes as any).reload();
}
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

View File

@ -43,6 +43,7 @@
<FormSwitch v-model="useOsNativeEmojis" class="_formBlock">{{ $ts.useOsNativeEmojis }}
<div><Mfm :key="useOsNativeEmojis" text="🍮🍦🍭🍩🍰🍫🍬🥞🍪"/></div>
</FormSwitch>
<FormSwitch v-model="disableDrawer" class="_formBlock">{{ $ts.disableDrawer }}</FormSwitch>
<FormRadios v-model="fontSize" class="_formBlock">
<template #label>{{ $ts.fontSize }}</template>
@ -76,13 +77,6 @@
<FormSwitch v-model="defaultSideView">{{ $ts.openInSideView }}</FormSwitch>
</FormGroup>
<FormSelect v-model="chatOpenBehavior" class="_formBlock">
<template #label>{{ $ts.chatOpenBehavior }}</template>
<option value="page">{{ $ts.showInPage }}</option>
<option value="window">{{ $ts.openInWindow }}</option>
<option value="popout">{{ $ts.popout }}</option>
</FormSelect>
<FormLink to="/settings/deck" class="_formBlock">{{ $ts.deck }}</FormLink>
<FormLink to="/settings/custom-css" class="_formBlock"><template #icon><i class="fas fa-code"></i></template>{{ $ts.customCss }}</FormLink>
@ -140,6 +134,7 @@ export default defineComponent({
showGapBetweenNotesInTimeline: defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline'),
disableAnimatedMfm: defaultStore.makeGetterSetter('animatedMfm', v => !v, v => !v),
useOsNativeEmojis: defaultStore.makeGetterSetter('useOsNativeEmojis'),
disableDrawer: defaultStore.makeGetterSetter('disableDrawer'),
disableShowingAnimatedImages: defaultStore.makeGetterSetter('disableShowingAnimatedImages'),
loadRawImages: defaultStore.makeGetterSetter('loadRawImages'),
imageNewTab: defaultStore.makeGetterSetter('imageNewTab'),
@ -147,7 +142,6 @@ export default defineComponent({
disablePagesScript: defaultStore.makeGetterSetter('disablePagesScript'),
showFixedPostForm: defaultStore.makeGetterSetter('showFixedPostForm'),
defaultSideView: defaultStore.makeGetterSetter('defaultSideView'),
chatOpenBehavior: ColdDeviceStorage.makeGetterSetter('chatOpenBehavior'),
instanceTicker: defaultStore.makeGetterSetter('instanceTicker'),
enableInfiniteScroll: defaultStore.makeGetterSetter('enableInfiniteScroll'),
useReactionPickerForContextMenu: defaultStore.makeGetterSetter('useReactionPickerForContextMenu'),

View File

@ -30,7 +30,10 @@
<option :value="3">{{ $ts.large }}</option>
</FormRadios>
<FormSwitch v-model="reactionPickerUseDrawerForMobile" class="_formBlock">{{ $ts.useDrawerReactionPickerForMobile }}</FormSwitch>
<FormSwitch v-model="reactionPickerUseDrawerForMobile" class="_formBlock">
{{ $ts.useDrawerReactionPickerForMobile }}
<template #caption>{{ $ts.needReloadToApply }}</template>
</FormSwitch>
<FormSection>
<div style="display: flex; gap: var(--margin); flex-wrap: wrap;">

View File

@ -1,6 +1,6 @@
<template>
<div class="_formRoot">
<div v-panel class="rfqxtzch _formBlock">
<div v-adaptive-border class="rfqxtzch _panel _formBlock">
<div class="toggle">
<div class="toggleWrapper">
<input id="dn" v-model="darkMode" type="checkbox" class="dn"/>

View File

@ -31,12 +31,15 @@ export default defineComponent({
}
},
mounted() {
os.apiWithDialog('signup-pending', {
code: this.code,
}).then(res => {
login(res.i, '/');
async mounted() {
await os.alert({
type: 'info',
text: this.$t('clickToFinishEmailVerification', { ok: this.$ts.gotIt }),
});
const res = await os.apiWithDialog('signup-pending', {
code: this.code,
});
login(res.i, '/');
},
methods: {

View File

@ -1,12 +1,11 @@
<template>
<div class="_section">
<XNotes ref="notes" class="_content" :pagination="pagination" @before="before" @after="after"/>
<XNotes ref="notes" class="_content" :pagination="pagination"/>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XNotes from '@/components/notes.vue';
import * as symbols from '@/symbols';
@ -43,15 +42,5 @@ export default defineComponent({
(this.$refs.notes as any).reload();
}
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

View File

@ -10,8 +10,6 @@
class="tl"
:src="src"
:sound="true"
@before="before()"
@after="after()"
@queue="queueUpdated"
/>
</div>
@ -21,7 +19,6 @@
<script lang="ts">
import { defineComponent, defineAsyncComponent, computed } from 'vue';
import Progress from '@/scripts/loading';
import XTimeline from '@/components/timeline.vue';
import XPostForm from '@/components/post-form.vue';
import { scroll } from '@/scripts/scroll';
@ -118,14 +115,6 @@ export default defineComponent({
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
},
queueUpdated(q) {
this.queue = q;
},

View File

@ -7,8 +7,6 @@
src="list"
:list="listId"
:sound="true"
@before="before()"
@after="after()"
@queue="queueUpdated"
/>
</div>
@ -17,7 +15,6 @@
<script lang="ts">
import { defineComponent, defineAsyncComponent, computed } from 'vue';
import Progress from '@/scripts/loading';
import XTimeline from '@/components/timeline.vue';
import { scroll } from '@/scripts/scroll';
import * as os from '@/os';
@ -76,14 +73,6 @@ export default defineComponent({
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
},
queueUpdated(q) {
this.queue = q;
},

View File

@ -205,7 +205,6 @@ import MkFolder from '@/components/ui/folder.vue';
import MkRemoteCaution from '@/components/remote-caution.vue';
import MkTab from '@/components/tab.vue';
import MkInfo from '@/components/ui/info.vue';
import Progress from '@/scripts/loading';
import * as Acct from 'misskey-js/built/acct';
import { getScrollPosition } from '@/scripts/scroll';
import { getUserMenu } from '@/scripts/get-user-menu';
@ -328,13 +327,10 @@ export default defineComponent({
fetch() {
if (this.acct == null) return;
this.user = null;
Progress.start();
os.api('users/show', Acct.parse(this.acct)).then(user => {
this.user = user;
}).catch(e => {
this.error = e;
}).finally(() => {
Progress.done();
});
},

View File

@ -1,11 +0,0 @@
export default {
start: () => {
// TODO
},
done: () => {
// TODO
},
set: val => {
// TODO
}
};

View File

@ -1,4 +1,4 @@
import { Ref, ref, watch } from 'vue';
import { Ref, ref, watch, onUnmounted } from 'vue';
export function useTooltip(
elRef: Ref<HTMLElement | { $el: HTMLElement } | null | undefined>,
@ -18,6 +18,9 @@ export function useTooltip(
const open = () => {
close();
if (!isHovering) return;
if (elRef.value == null) return;
const el = elRef.value instanceof Element ? elRef.value : elRef.value.$el;
if (!document.body.contains(el)) return; // openしようとしたときに既に元要素がDOMから消えている場合があるため
const showing = ref(true);
onShow(showing);
@ -69,9 +72,14 @@ export function useTooltip(
el.addEventListener('mouseleave', onMouseleave, { passive: true });
el.addEventListener('touchstart', onTouchstart, { passive: true });
el.addEventListener('touchend', onTouchend, { passive: true });
el.addEventListener('click', close, { passive: true });
}
}, {
immediate: true,
flush: 'post',
});
onUnmounted(() => {
close();
});
}

View File

@ -138,6 +138,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: false
},
disableDrawer: {
where: 'device',
default: false
},
useBlurEffectForModal: {
where: 'device',
default: true
@ -241,7 +245,6 @@ export class ColdDeviceStorage {
lightTheme: require('@/themes/l-light.json5') as Theme,
darkTheme: require('@/themes/d-dark.json5') as Theme,
syncDeviceDarkMode: true,
chatOpenBehavior: 'page' as 'page' | 'window' | 'popout',
plugins: [] as Plugin[],
mediaVolume: 0.5,
sound_masterVolume: 0.3,

View File

@ -3,7 +3,6 @@
*/
declare var self: ServiceWorkerGlobalScope;
import { getNoteSummary } from '@/scripts/get-note-summary';
import * as misskey from 'misskey-js';
function getUserName(user: misskey.entities.User): string {
@ -26,37 +25,37 @@ export default async function(type, data, i18n): Promise<[string, NotificationOp
switch (data.type) {
case 'mention':
return [i18n.t('_notification.youGotMention', { name: getUserName(data.user) }), {
body: getNoteSummary(data.note, i18n.locale),
body: data.note.text,
icon: data.user.avatarUrl
}];
case 'reply':
return [i18n.t('_notification.youGotReply', { name: getUserName(data.user) }), {
body: getNoteSummary(data.note, i18n.locale),
body: data.note.text,
icon: data.user.avatarUrl
}];
case 'renote':
return [i18n.t('_notification.youRenoted', { name: getUserName(data.user) }), {
body: getNoteSummary(data.note, i18n.locale),
body: data.note.text,
icon: data.user.avatarUrl
}];
case 'quote':
return [i18n.t('_notification.youGotQuote', { name: getUserName(data.user) }), {
body: getNoteSummary(data.note, i18n.locale),
body: data.note.text,
icon: data.user.avatarUrl
}];
case 'reaction':
return [`${data.reaction} ${getUserName(data.user)}`, {
body: getNoteSummary(data.note, i18n.locale),
body: data.note.text,
icon: data.user.avatarUrl
}];
case 'pollVote':
return [i18n.t('_notification.youGotPoll', { name: getUserName(data.user) }), {
body: getNoteSummary(data.note, i18n.locale),
body: data.note.text,
icon: data.user.avatarUrl
}];

View File

@ -34,7 +34,7 @@ export default defineComponent({
id: notification.id
});
popup(import('@/components/toast.vue'), {
popup(import('@/components/notification-toast.vue'), {
notification
}, {}, 'closed');
}
@ -60,7 +60,7 @@ export default defineComponent({
#wait {
display: block;
position: fixed;
z-index: 3000000;
z-index: 4000000;
top: 15px;
right: 15px;

View File

@ -170,6 +170,8 @@ export default defineComponent({
}
&:hover, &.active {
color: var(--accent);
&:before {
content: "";
display: block;
@ -283,8 +285,10 @@ export default defineComponent({
}
&:before {
width: 100%;
border-radius: 0;
width: auto;
height: 100%;
aspect-ratio: 1/1;
border-radius: 8px;
}
&.post {
@ -296,8 +300,9 @@ export default defineComponent({
}
&.post:before {
width: calc(100% - 32px);
height: calc(100% - 32px);
width: calc(100% - 28px);
height: auto;
aspect-ratio: 1/1;
border-radius: 100%;
}
}

View File

@ -25,7 +25,7 @@ export default defineComponent({
data() {
return {
uploads: os.uploads,
zIndex: os.claimZIndex(true),
zIndex: os.claimZIndex('high'),
};
},
});

View File

@ -82,7 +82,7 @@ export default defineComponent({
});
const columns = deckStore.reactiveState.columns;
const layout = deckStore.reactiveState.layout.value;
const layout = deckStore.reactiveState.layout;
const menuIndicated = computed(() => {
if ($i == null) return false;
for (const def in menuDef) {

View File

@ -8,7 +8,6 @@
<script lang="ts">
import { defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XColumn from './column.vue';
import XNotes from '@/components/notes.vue';
import * as os from '@/os';
@ -41,15 +40,5 @@ export default defineComponent({
},
}
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

View File

@ -8,7 +8,6 @@
<script lang="ts">
import { defineComponent } from 'vue';
import Progress from '@/scripts/loading';
import XColumn from './column.vue';
import XNotes from '@/components/notes.vue';
import * as os from '@/os';
@ -38,15 +37,5 @@ export default defineComponent({
},
}
},
methods: {
before() {
Progress.start();
},
after() {
Progress.done();
}
}
});
</script>

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