Compare commits

...

70 Commits

Author SHA1 Message Date
b14e347da1 12.101.0 2021-12-29 13:41:50 +09:00
034b8f09df enhance(client): 2021-12-29 13:36:17 +09:00
c537a0ba93 enhance(client): 2021-12-29 13:14:19 +09:00
897d775b14 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-12-29 05:09:34 +09:00
4f43f019e0 fix(test): ignore ResizeObserver error 2021-12-29 05:09:26 +09:00
1ea0aaef76 update deps 2021-12-29 05:00:39 +09:00
fd1cfcff5f New Crowdin updates (#8066)
* New translations ja-JP.yml (Chinese Simplified)

* 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 (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 (Chinese Simplified)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* 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 (French)

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

* 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 (Korean)

* New translations ja-JP.yml (Italian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Polish)

* New translations ja-JP.yml (Russian)

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

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)

* New translations ja-JP.yml (Esperanto)
2021-12-29 04:55:29 +09:00
c7308f4178 fix(client): fix sidebar style 2021-12-29 04:38:25 +09:00
5cc65c5bd3 update deps 2021-12-29 04:30:38 +09:00
f216dd7617 clean up 2021-12-29 04:30:12 +09:00
af022fd8b8 fix html blockquote conversion (#8069) 2021-12-29 04:15:28 +09:00
5c7181ca21 feat(client): svg sparkle effect
Resolve #8088
2021-12-29 04:13:45 +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
35cd9e621a 12.100.1 2021-12-17 19:42:50 +09:00
ea66080197 fix(client): fix zindex issue 2021-12-17 19:38:17 +09:00
06837662a9 fix(client): tweak style 2021-12-17 19:36:18 +09:00
f9024a0058 improve(client): tweak drawer max height 2021-12-17 19:34:58 +09:00
493ff2eed5 fix(client): fix zindex issue 2021-12-17 17:37:58 +09:00
ac82435014 12.100.0 2021-12-17 16:17:56 +09:00
d9257a5c0e 🎨 2021-12-17 16:14:43 +09:00
f7c90b58d6 enhance(client): リアクションピッカーの表示方法を選択できるように 2021-12-17 16:14:31 +09:00
2f8e3559b5 update deps 2021-12-17 14:12:34 +09:00
e96a914b6b 🎨 2021-12-17 13:15:06 +09:00
6ab2c7780c enhance(client): improve modal menu for mobile 2021-12-17 02:14:40 +09:00
6d6162333e chore: remove ms-vscode.typescript-javascript-grammar (#8061) 2021-12-16 23:46:18 +09:00
58b9dc581e fix(client): fix zindex issues
Fix #8060
2021-12-16 10:57:07 +09:00
fa8eb43eaf fix(client): 一部のコンポーネントが裏に隠れるのを修正 2021-12-15 21:44:41 +09:00
cf5fe2d107 12.99.3 2021-12-14 23:28:19 +09:00
50f2025421 fix(client): オートコンプリートがダイアログの裏に隠れる問題を修正 2021-12-14 23:27:38 +09:00
1894df882b 12.99.2 2021-12-14 23:13:31 +09:00
983599bdae Update 1639325650583-chart-v3.js 2021-12-14 23:13:09 +09:00
6319dd1bfb 12.99.1 2021-12-14 23:03:45 +09:00
d1ea8654e6 fix: YAMLファイルへのバックスペース文字混入対策 2021-12-14 23:03:18 +09:00
118 changed files with 1615 additions and 1909 deletions

View File

@ -2,7 +2,6 @@
"recommendations": [
"editorconfig.editorconfig",
"eg2.vscode-npm-script",
"ms-vscode.typescript-javascript-grammar",
"dbaeumer.vscode-eslint",
"johnsoncodehk.volar",
"sysoev.language-stylus"

View File

@ -7,6 +7,46 @@
-->
## 12.101.0 (2021/12/29)
### Improvements
- クライアント: ノートプレビューの精度を改善
- クライアント: MFM sparkleエフェクトの改善
- クライアント: デザインの調整
- セキュリティの向上
### Bugfixes
- クライアント: 一部のコンポーネントが裏に隠れるのを修正
- fix html blockquote conversion
## 12.100.2 (2021/12/18)
### Bugfixes
- クライアント: Deckカラムの増減がページをリロードするまで正しく反映されない問題を修正
- クライアント: 一部のコンポーネントが裏に隠れるのを修正
- クライアント: カスタム絵文字一覧ページの負荷が高いのを修正
## 12.100.1 (2021/12/17)
### Bugfixes
- クライアント: デザインの調整
## 12.100.0 (2021/12/17)
### Improvements
- クライアント: モバイルでの各種メニュー、リアクションピッカーの表示を改善
### Bugfixes
- クライアント: 一部のコンポーネントが裏に隠れるのを修正
## 12.99.3 (2021/12/14)
### Bugfixes
- クライアント: オートコンプリートがダイアログの裏に隠れる問題を修正
## 12.99.2 (2021/12/14)
## 12.99.1 (2021/12/14)
## 12.99.0 (2021/12/14)
### Improvements

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

@ -18,3 +18,9 @@ import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')
Cypress.on('uncaught:exception', (err, runnable) => {
if (err.message.includes('ResizeObserver loop limit exceeded')) {
return false
}
});

View File

@ -106,7 +106,6 @@ clickToShow: "اضغط للعرض"
sensitive: "محتوى حساس"
add: "إضافة"
reaction: "التفاعلات"
reactionSettingDescription: "اختر التفاعلات المفضلة التي تريد تثبيتها في منتقي التفاعلات."
reactionSettingDescription2: "اسحب لترتيب ، انقر للحذف ، استخدم \"+\" للإضافة."
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
attachCancel: "أزل المرفق"
@ -581,7 +580,6 @@ regenerateLoginToken: "أعد توليد الرمز"
regenerateLoginTokenDescription: "ينشئ رمز استيثاق جديد في العادة هذا ليس ضروريًا ؛ عند إنشاء رمز جديد ستُخرج جميع الأجهزة."
setMultipleBySeparatingWithSpace: "يمكنك ادخال أكثر من مدخل واحد وذلك بفصلها بمسافات."
fileIdOrUrl: "معرف الملف أو رابط"
chatOpenBehavior: "سلوك نفاذة المحادثة عند فتحها"
behavior: "السلوك"
sample: "مثال"
abuseReports: "البلاغات"

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"
@ -448,6 +448,7 @@ uiLanguage: "Sprache der Benutzeroberfläche"
groupInvited: "Du wurdest in eine Gruppe eingeladen"
aboutX: "Über {x}"
useOsNativeEmojis: "Eingebaute Emojis des Betriebssystems benutzen"
disableDrawer: "Keine ausfahrbaren Menüs verwenden"
youHaveNoGroups: "Keine Gruppen vorhanden"
joinOrCreateGroup: "Lass dich zu einer Gruppe einladen oder erstelle deine eigene."
noHistory: "Kein Verlauf"
@ -613,7 +614,6 @@ regenerateLoginToken: "Anmeldungstoken regenerieren"
regenerateLoginTokenDescription: "Den zur Anmeldung intern verwendeten Token regenerieren. Normalerweise wird dies nicht benötigt. Bei Regeneration werden alle Geräte ausgeloggt."
setMultipleBySeparatingWithSpace: "Trenne Elemente durch ein Leerzeichen um mehrere Einstellungen zu kofigurieren."
fileIdOrUrl: "Datei-ID oder URL"
chatOpenBehavior: "Verhalten des Chatfensters bei Öffnung"
behavior: "Verhalten"
sample: "Beispiel"
abuseReports: "Meldungen"
@ -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,11 @@ 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}"
clickToFinishEmailVerification: "Drücke bitte auf [{ok}], um die Email-Bestätigung abzuschließen."
_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"
@ -448,6 +448,7 @@ uiLanguage: "User interface language"
groupInvited: "You've been invited to a group"
aboutX: "About {x}"
useOsNativeEmojis: "Use OS native Emoji"
disableDrawer: "Don't use drawer-style menus"
youHaveNoGroups: "You have no groups"
joinOrCreateGroup: "Get invited to a group or create your own."
noHistory: "No history available"
@ -613,7 +614,6 @@ regenerateLoginToken: "Regenerate login token"
regenerateLoginTokenDescription: "Regenerate the token used internally during login. Normally this action is not necessary. If regenerated, all devices will be logged out."
setMultipleBySeparatingWithSpace: "Separate multiple entries with spaces."
fileIdOrUrl: "File-ID or URL"
chatOpenBehavior: "Behavior of the chat window when opened"
behavior: "Behavior"
sample: "Sample"
abuseReports: "Reports"
@ -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,11 @@ 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}"
clickToFinishEmailVerification: "Please click [{ok}] to complete email verification."
_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"
@ -23,7 +23,7 @@ otherSettings: "Aliaj agordoj"
openInWindow: "Malfermi en nova fenestro"
profile: "Profilo"
timeline: "Templinio"
noAccountDescription: "Neniu priskribo"
noAccountDescription: "La uzanto ankoraŭ ne skribis la sinprezenton en sia profilo."
login: "Saluti"
loggingIn: "Salutado…"
logout: "Adiaŭi"
@ -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,8 +101,8 @@ 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"
reactionSetting: "Reagoj aperontaj en la elektilo de reagoj"
rememberNoteVisibility: "Rememori la agordon de videbleco de la lasta afiŝado"
attachCancel: "Deigi aldonaĵon"
markAsSensitive: "Troviĝi NSFW"
unmarkAsSensitive: "Ne troviĝi NSFW"
@ -122,6 +122,7 @@ selectAntenna: "Elekti antenon"
selectWidget: "Elekti enestraĵon"
editWidgets: "Redakti fenestraĵon"
editWidgetsExit: "Fini la redaktadon"
customEmojis: "Federaj emoĵioj"
emoji: "Emoĵio"
emojis: "Emoĵio"
emojiName: "Nomo de la emoĵio"
@ -129,11 +130,12 @@ 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"
flagAsCatDescription: "Se vi estas kato, ebligu la agordon."
flagAsBot: "Marki kiel esti uzanto de roboto"
flagAsCat: "Marki kiel esti kato"
flagAsCatDescription: "Se vi estas kato, faru ĉi tiun flagon"
autoAcceptFollowed: "Aŭtomate akcepti la peton de sekvado far uzantoj kiujn vi sekvas"
addAccount: "Aldoni konton"
loginFailed: "Saluto malsukcesis"
showOnRemote: "Vidi ĉe la surloka nodo"
general: "Ĝenerala"
wallpaper: "Ekranfonoj"
@ -149,6 +151,7 @@ recipient: "Ricevonton"
annotation: "Komentarioj"
federation: "Federaĵo"
instances: "Nodoj"
registeredAt: "Registrita je"
latestRequestSentAt: "La laste sendita peto"
latestRequestReceivedAt: "La laste ricevita peto "
latestStatus: "Laŭstato"
@ -280,7 +283,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"
@ -320,8 +323,11 @@ antennas: "Antenoj"
manageAntennas: "Administri antenojn"
name: "Nomo"
antennaSource: "Fonto de la anteno"
antennaKeywords: "Ricevi per ĉefterminoj"
antennaExcludeKeywords: "Krom ĉefterminoj"
notifyAntenna: "Oni sciigos novajn notojn"
withFileAntenna: "Nur kun aldonaĵo"
enableServiceworker: "Aktivigi ServiceWorker"
withReplies: "Inkluzive respondoj"
connectedTo: "Sekva konto estas konektita"
notesAndReplies: "Kun respondoj"
@ -331,10 +337,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 +354,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 +365,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 +388,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."
@ -452,9 +459,9 @@ nothing: "Neniu"
installedDate: "Dato de instalado"
lastUsedDate: "Lastfoje uzita je"
state: "Stato"
sort: "Ordigado"
ascendingOrder: "Kreski"
descendingOrder: "Malkreski"
sort: "Ordigi laŭ"
ascendingOrder: "Kreska ordo"
descendingOrder: "Malkreska ordo"
scratchpad: "Malneta redaktilo"
output: "Elmeto"
script: "Skripto"
@ -481,7 +488,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,14 +506,14 @@ 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"
smtpUser: "Uzantnomo"
smtpPass: "Pasvorto"
wordMute: "Silentigi specifajn vortojn"
userSaysSomething: "{name} parolis ion"
userSaysSomething: "{name} diras ion"
makeActive: "Aktivigi"
display: "Vidi"
copy: "Kopii"
@ -522,7 +529,6 @@ useGlobalSetting: "Oni uzas malloka agordo"
other: "Aliaj"
regenerateLoginToken: "Regeneri la aŭtentikigan pecon"
fileIdOrUrl: "Dosiera identigilo aŭ URL"
chatOpenBehavior: "Konduto por malfermi la fenestron de babilejo"
behavior: "Konduto"
sample: "Ekzemplo"
abuseReports: "Signaloj"
@ -569,6 +575,7 @@ left: "Maldekstra"
center: "Centra"
wide: "Vasta"
narrow: "Malvasta"
needReloadToApply: "Tiu agordo estos aplikita nur poste reŝargi."
showTitlebar: "Videbligi titolan stangon"
clearCache: "Malplenigi staplon"
onlineUsersCount: "{n} uzantoj estas surlineaj"
@ -586,7 +593,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 +615,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 +638,17 @@ 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"
muteThread: "Silentigi la mesaĝaron"
unmuteThread: "Malsilentigi la mesaĝaron"
ffVisibility: "Videbleco de la sekvadoj pri vi"
ffVisibilityDescription: "Tie ĉi vi povas agordi la videblecon pri kiuj povas vidi tiujn, kiujn vi sekvas kaj kiuj sekvas vin."
continueThread: "Pli vidi la mesaĝaron"
incorrectPassword: "Nevalida pasvorto"
leaveGroup: "Eliĝi el la grupo"
leaveGroupConfirm: "Ĉu vi certas ke vi volas eliĝi el la grupo {name}?"
welcomeBackWithName: "Alvenbenon! {name}"
_emailUnavailable:
used: "La retpoŝto jam estas uzita."
format: "Nevalida formato."
@ -642,7 +656,7 @@ _emailUnavailable:
smtp: "Tiu retpoŝta servilo ne respondas"
_ffVisibility:
public: "Publika"
followers: "Afiŝi nur al sekvantoj"
followers: "Nur al sekvantoj"
private: "Malpublikigita"
_signup:
emailAddressInfo: "Entajpu vian retpoŝton"
@ -662,7 +676,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"
@ -689,6 +703,7 @@ _mfm:
inlineMath: "Formulo (en linio)"
blockMath: "Formulo (bloko)"
quote: "Citi"
emoji: "Federaj emoĵioj"
search: "Serĉi"
flip: "Inversa"
x2: "Granda"
@ -709,10 +724,12 @@ _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:
sideFull: "Flanko"
sideIcon: "Flanko (bildsimbolo)"
top: "Supro"
hide: "Kaŝi"
_wordMute:
@ -721,11 +738,12 @@ _wordMute:
hard: "Per la servilo"
mutedNotes: "Silentigitaj notoj"
_theme:
manage: "Administri kolorarojn"
manage: "Bonteni kolorarojn"
code: "Kolorara kodo"
description: "Priskribo"
defaultValue: "Implicitaĵa valoro"
color: "Koloro"
func: "Funkcio"
darken: "Malbrileco"
lighten: "Brileco"
keys:
@ -738,7 +756,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"
@ -778,10 +796,10 @@ _permissions:
"write:drive": "Ĉia operacio por skribi, forviŝi, aŭ alimaniere ŝanĝi la informon de dosiero en via disko de Misskey"
"read:favorites": "Vidi vian liston de preferaĵoj"
"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:following": "Vidi la infomojn pri la sekvadoj pri vi"
"write:following": "Sekvi/Malsekvi alian uzanton"
"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"
@ -794,7 +812,7 @@ _permissions:
"read:channels": "Vidi kanalojn"
_antennaSources:
all: "Ĉiuj notoj"
homeTimeline: "Notoj far uzantoj kiujn vi sekvas"
homeTimeline: "Notoj de uzantoj kiujn vi sekvas"
_weekday:
sunday: "Dimanĉo"
monday: "Lundo"
@ -826,19 +844,25 @@ _poll:
closed: "Oni jam balotis ĝin"
_visibility:
public: "Publika"
publicDescription: "Afiŝi al ĉiuj en la Fediverso"
publicDescription: "Publikigi al ĉiuj en la Fediverso"
home: "Hejma"
homeDescription: "Dissendi nur sur hejma templinio"
followers: "Nur al sekvantoj"
followersDescription: "Afiŝi nur al sekvantoj"
specified: "Rekte"
specifiedDescription: "Afiŝi nur al specifaj uzantoj"
followersDescription: "Videbligi nur al sekvantoj"
specified: "Rekte montrita"
specifiedDescription: "Montri nur al specifaj uzantoj"
localOnly: "Nur loka"
localOnlyDescription: "Ne afiŝi al foraj uzantoj"
localOnlyDescription: "Ne videbligi al foraj uzantoj"
_postForm:
replyPlaceholder: "Respondi la noton…"
quotePlaceholder: "Citi la noton…"
channelPlaceholder: "Mencii en la kanalo…"
_placeholders:
a: "Kiel vi fartas?"
b: "Kio okazis ĉirkaŭ vi?"
c: "Kion vi pensas?"
d: "Kion vi parolos?"
e: "Komencu skribi…"
_profile:
name: "Nomo"
username: "Uzantnomo"
@ -901,6 +925,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"
@ -946,6 +971,9 @@ _pages:
default: "Implicitaĵa valoro"
script:
categories:
random: "Hazardo"
value: "Valoro"
fn: "Funkcio"
text: "Manipulo de teksto"
list: "Listoj"
blocks:
@ -963,6 +991,7 @@ _pages:
_join:
arg1: "Listoj"
arg2: "apartigilo"
random: "Hazardo"
_randomPick:
arg1: "Listoj"
_dailyRandomPick:
@ -980,6 +1009,7 @@ _pages:
arg1: "Teksto"
_splitStrByLine:
arg1: "Teksto"
fn: "Funkcio"
_fn:
slots: "Juntoj"
arg1: "Elmeto"
@ -1001,9 +1031,9 @@ _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}"
youWereFollowed: "eksekvis vin"
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."
youWereInvitedToGroup: "Invitita al grupo"
@ -1016,7 +1046,7 @@ _notification:
quote: "Citi"
reaction: "Reagoj"
receiveFollowRequest: "Ricevi peton de sekvado"
followRequestAccepted: "Akceptita peto por sekvado"
followRequestAccepted: "Akceptita peto de sekvado"
groupInvited: "Invitita al grupo"
_deck:
profile: "Agordaro"

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"
@ -610,7 +609,6 @@ regenerateLoginToken: "Regenerar token de login"
regenerateLoginTokenDescription: "Regenerar el token usado internamente durante el login. No siempre es necesario hacerlo. Al hacerlo de nuevo, se deslogueará en todos los dispositivos."
setMultipleBySeparatingWithSpace: "Puedes añadir mas de uno, separado por espacios."
fileIdOrUrl: "Id del archivo o URL"
chatOpenBehavior: "Comportamiento al abrir el chat"
behavior: "Comportamiento"
sample: "Muestra"
abuseReports: "Reportes"

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é"
@ -612,7 +611,6 @@ regenerateLoginToken: "Régénérer le jeton de connexion"
regenerateLoginTokenDescription: "Générer un nouveau jeton d'authentification. Cette opération ne devrait pas être nécessaire ; lors de la génération d'un nouveau jeton, tous les appareils seront déconnectés. "
setMultipleBySeparatingWithSpace: "Vous pouvez en définir plusieurs, en les séparant par des espaces."
fileIdOrUrl: "ID du fichier ou URL"
chatOpenBehavior: "Comportement de la fenêtre de discussion lors de son ouverture"
behavior: "Comportement"
sample: "Exemple"
abuseReports: "Signalements"

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"
@ -612,7 +611,6 @@ regenerateLoginToken: "Perbarui token login"
regenerateLoginTokenDescription: "Perbarui token yang digunakan secara internal saat login. Normalnya aksi ini tidak diperlukan. Jika diperbarui, semua perangkat akan dilogout."
setMultipleBySeparatingWithSpace: "Kamu dapat menyetel banyak dengan memisahkannya menggunakan spasi."
fileIdOrUrl: "File-ID atau URL"
chatOpenBehavior: "Perilaku jendelan obrolan ketika dibuka"
behavior: "Perilaku"
sample: "Contoh"
abuseReports: "Laporkan"

View File

@ -46,7 +46,10 @@ const primaries = {
'zh': 'CN',
};
const locales = languages.reduce((a, c) => (a[c] = yaml.load(fs.readFileSync(`${__dirname}/${c}.yml`, 'utf-8')) || {}, a), {});
// 何故か文字列にバックスペース文字が混入することがあり、YAMLが壊れるので取り除く
const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g'), '');
const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(`${__dirname}/${c}.yml`, 'utf-8'))) || {}, a), {});
module.exports = Object.entries(locales)
.reduce((a, [k ,v]) => (a[k] = (() => {

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"
@ -591,7 +590,6 @@ other: "Avanzate"
regenerateLoginToken: "Genera di nuovo un token di connessione"
regenerateLoginTokenDescription: "Genera un nuovo token di autenticazione. Solitamente questa operazione non è necessaria: quando si genera un nuovo token, tutti i dispositivi vanno disconnessi."
fileIdOrUrl: "ID o URL del file"
chatOpenBehavior: "Comportamento della finestra di chat quando viene aperta"
behavior: "Comportamento"
abuseReports: "Segnalazioni"
reportAbuse: "Segnalazioni"

View File

@ -106,7 +106,7 @@ clickToShow: "クリックして表示"
sensitive: "閲覧注意"
add: "追加"
reaction: "リアクション"
reactionSettingDescription: "リアクションピッカーに表示するリアクションを設定します。"
reactionSetting: "ピッカーに表示するリアクション"
reactionSettingDescription2: "ドラッグして並び替え、クリックして削除、+を押して追加します。"
rememberNoteVisibility: "公開範囲を記憶する"
attachCancel: "添付取り消し"
@ -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}人がオンライン"
@ -815,6 +816,9 @@ voteConfirm: "「{choice}」に投票しますか?"
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:

View File

@ -106,7 +106,6 @@ clickToShow: "클릭하여 보기"
sensitive: "열람주의"
add: "추가"
reaction: "리액션"
reactionSettingDescription: "리액션 선택 상자에 표시할 리액션을 설정합니다."
reactionSettingDescription2: "끌어서 순서 변경, 클릭해서 삭제, +를 눌러서 추가할 수 있습니다."
rememberNoteVisibility: "공개 범위를 기억하기"
attachCancel: "첨부 취소"
@ -613,7 +612,6 @@ regenerateLoginToken: "로그인 토큰을 재생성"
regenerateLoginTokenDescription: "로그인할 때 사용되는 내부 토큰을 재생성합니다. 일반적으로 이 작업을 실행할 필요는 없습니다. 이 기능을 사용하면 이 계정으로 로그인한 모든 기기에서 로그아웃됩니다."
setMultipleBySeparatingWithSpace: "공백으로 구분하여 여러 개 설정할 수 있습니다."
fileIdOrUrl: "파일 ID 또는 URL"
chatOpenBehavior: "대화를 열 때의 동작"
behavior: "동작"
sample: "예시"
abuseReports: "신고"

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

@ -81,6 +81,8 @@ somethingHappened: "Coś poszło nie tak"
retry: "Spróbuj ponownie"
pageLoadError: "Nie udało się załadować strony"
pageLoadErrorDescription: "Zwykle jest to spowodowane problemem z siecią lub cache przeglądarki. Spróbuj wyczyścić cache i sprawdź jeszcze raz za chwilę."
serverIsDead: "Serwer nie odpowiada. Zaczekaj chwilę i spróbuj ponownie."
youShouldUpgradeClient: "Odśwież stronę, by zaaktualizować klienta."
enterListName: "Nazwa listy"
privacy: "Prywatność"
makeFollowManuallyApprove: "Prośby o możliwość obserwacji wymagają zatwierdzenia"
@ -104,7 +106,7 @@ clickToShow: "Kliknij, aby wyświetlić"
sensitive: "NSFW"
add: "Dodaj"
reaction: "Reakcja"
reactionSettingDescription: "Przypisz swoje ulubione reakcje, które chcesz przypiąć w wyborze reakcji."
reactionSetting: "Reakcje do pokazania w wyborniku 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"
@ -181,6 +183,7 @@ instanceInfo: "Informacje o instancji"
statistics: "Statystyki"
clearQueue: "Wyczyść kolejkę"
clearQueueConfirmTitle: "Czy na pewno chcesz wyczyścić kolejkę?"
clearQueueConfirmText: "Wszystkie niewysłane wpisy z kolejki nie zostaną wysłane. Zwykle to nie jest konieczne."
clearCachedFiles: "Wyczyść pamięć podręczną"
clearCachedFilesConfirm: "Czy na pewno chcesz usunąć wszystkie zdalne pliki z pamięci podręcznej?"
blockedInstances: "Zablokowane instancje"
@ -220,6 +223,7 @@ more: "Więcej!"
featured: "Wyróżnione"
usernameOrUserId: "Nazwa lub id użytkownika"
noSuchUser: "Nie znaleziono użytkownika"
lookup: "Zapytania"
announcements: "Ogłoszenia"
imageUrl: "Adres URL obrazka"
remove: "Usuń"
@ -309,22 +313,28 @@ monthX: "{month}"
yearX: "{year}"
pages: "Strony"
integration: "Integracja"
connectService: "Połącz"
disconnectService: "Rozłącz"
enableLocalTimeline: "Włącz lokalną oś czasu"
enableGlobalTimeline: "Włącz globalną oś czasu"
disablingTimelinesInfo: "Administratorzy i moderatorzy będą zawsze mieć dostęp do wszystkich osi czasu, nawet gdy są one wyłączone."
registration: "Zarejestruj się"
enableRegistration: "Włącz rejestrację nowych użytkowników"
invite: "Zaproś"
proxyRemoteFiles: "Przekierowuj pliki obcych instancji przez proxy"
proxyRemoteFilesDescription: "Gdy ta opcja jest włączona, zdalne pliki które nie są przechowywane lokalnie, lub zostały usunięte z powodu przekroczenia limitu miejsca będą kierowane przez proxy, razem z generowaniem miniatur. Nie ma to żadnego wpływu na przestrzeń dyskową serwera."
driveCapacityPerLocalAccount: "Powierzchnia dyskowa na lokalnego użytkownika"
driveCapacityPerRemoteAccount: "Powierzchnia dyskowa na zdalnego użytkownika"
inMb: "W megabajtach"
iconUrl: "Adres URL ikony"
bannerUrl: "Adres URL banera"
backgroundImageUrl: "Adres URL tła"
basicInfo: "Podstawowe informacje"
pinnedUsers: "Przypięty użytkownik"
pinnedUsersDescription: "Wypisz po jednej nazwie użytkownika w wierszu. Podani użytkownicy zostaną przypięci pod kartą „Eksploruj”."
pinnedPages: "Przypięte strony"
pinnedPagesDescription: "Wprowadź ścieżki stron które chcesz przypiąć na głównej stronie instancji, oddzielone znakiem nowego wiersza."
pinnedClipId: "ID przypiętego klipu"
pinnedNotes: "Przypięty wpis"
hcaptcha: "hCaptcha"
enableHcaptcha: "Włącz hCaptcha"
@ -339,7 +349,9 @@ antennas: "Anteny"
manageAntennas: "Zarządzaj Antenami"
name: "Nazwa"
antennaSource: "Źródło Anteny"
antennaKeywords: "Słowa kluczowe do obserwacji"
antennaExcludeKeywords: "Wykluczone słowa kluczowe"
antennaKeywordsDescription: "Oddziel spacjami dla warunku AND, albo wymuś koniec linii dla warunku OR"
notifyAntenna: "Powiadamiaj o nowych wpisach"
withFileAntenna: "Filtruj tylko wpisy z załączonym plikiem"
enableServiceworker: "Włącz ServiceWorker"
@ -587,8 +599,9 @@ useGlobalSetting: "Użyj globalnych ustawień"
useGlobalSettingDesc: "Jeżeli włączone, zostaną wykorzystane ustawienia powiadomień Twojego konta. Jeżeli wyłączone, mogą zostać wykonane oddzielne konfiguracje."
other: "Inne"
regenerateLoginToken: "Generuj token logowania ponownie"
regenerateLoginTokenDescription: "Regeneruje token używany wewnętrznie podczas logowania. Zazwyczaj nie jest to konieczne. Po regeneracji wszystkie urządzenia zostaną wylogowane."
setMultipleBySeparatingWithSpace: "Możesz ustawić wiele, oddzielając je spacjami."
chatOpenBehavior: "Zachowanie okna czatu po otwarciu"
fileIdOrUrl: "ID pliku albo URL"
behavior: "Zachowanie"
sample: "Przykład"
abuseReports: "Zgłoszenia"
@ -596,6 +609,8 @@ reportAbuse: "Zgłoś"
reportAbuseOf: "Zgłoś {name}"
fillAbuseReportDescription: "Wypełnij szczegóły zgłoszenia. Jeżeli dotyczy ono określonego wpisu, uwzględnij jego adres URL."
abuseReported: "Twoje zgłoszenie zostało wysłane. Dziękujemy."
reporteeOrigin: "Pochodzenie zgłoszonego"
reporterOrigin: "Pochodzenie zgłaszającego"
send: "Wyślij"
abuseMarkAsResolved: "Oznacz zgłoszenie jako rozwiązane"
openInNewTab: "Otwórz w nowej karcie"
@ -608,7 +623,7 @@ random: "Losowe"
system: "System"
switchUi: "Przełącz interfejs użytkownika"
desktop: "Pulpit"
createNew: "Utworzy nowy"
createNew: "Utwórz nowy"
optional: "Nieobowiązkowe"
public: "Publiczny"
i18nInfo: "Misskey jest tłumaczone na wiele języków przez wolontariuszy. Możesz pomóc na {link}."
@ -631,6 +646,7 @@ driveFilesCount: "Liczba plików na dysku"
driveUsage: "Użycie przestrzeni dyskowej"
noCrawle: "Odrzuć indeksowanie przez crawlery"
noCrawleDescription: "Proś wyszukiwarki internetowe, aby nie indeksowały Twojego profilu, wpisów, stron itd."
lockedAccountInfo: "Dopóki nie ustawisz widoczności wpisu na \"Obserwujący\", twoje wpisy będą mogli widzieć wszyscy, nawet jeśli ustawisz manualne zatwierdzanie obserwujących."
alwaysMarkSensitive: "Oznacz domyślnie jako NSFW"
loadRawImages: "Wyświetlaj zdjęcia w załącznikach w całości zamiast miniatur"
disableShowingAnimatedImages: "Nie odtwarzaj animowanych obrazów"
@ -654,6 +670,7 @@ center: "Wyśsrodkuj"
wide: "Szerokie"
narrow: "Wąskie"
reloadToApplySetting: "To ustawienie zostanie zastosowane po odświeżeniu strony. Chcesz odświeżyć?"
needReloadToApply: "To ustawienie zostanie zastosowane po odświeżeniu strony"
showTitlebar: "Pokazuj pasek tytułowy"
clearCache: "Wyczyść pamięć podręczną"
onlineUsersCount: "{n} osób jest online"
@ -698,6 +715,8 @@ unlikeConfirm: "Na pewno chcesz usunąć polubienie?"
fullView: "Pełny widok"
quitFullView: "Opuść pełny widok"
addDescription: "Dodaj opis"
userPagePinTip: "Możesz wyświetlać wpisy w tym miejscu po wybraniu \"Przypnij do profilu\" z menu pojedyńczego wpisu"
notSpecifiedMentionWarning: "Ten wpis zawiera wzmianki o użytkownikach niezawartych jako odbiorcy"
info: "Informacje"
userInfo: "Informacje o użykowniku"
unknown: "Nieznane"
@ -735,9 +754,15 @@ middle: "Średnie"
low: "Niski"
emailNotConfiguredWarning: "Nie podano adresu e-mail"
ratio: "Stosunek"
previewNoteText: "Pokaż podgląd"
customCss: "Własny CSS"
customCssWarn: "Używaj tego ustawienia tylko wtedy, gdy wiesz co ono robi. Nieprawidłowe wpisy mogą spowodować, że klient przestanie działać poprawnie."
global: "Globalna"
squareAvatars: "Wyświetlaj kwadratowe awatary"
sent: "Wyślij"
received: "Otrzymane"
hashtags: "Hashtag"
pubSub: "Konta Pub/Sub"
hide: "Ukryj"
_ffVisibility:
public: "Publikuj"
@ -978,6 +1003,7 @@ _tutorial:
step1_3: "Twoja oś czasu jest jeszcze pusta, ponieważ nie opublikowałeś(-aś) jeszcze żadnych wpisów i nie obserwujesz jeszcze nikogo."
step2_1: "Ukończmy konfigurację profilu zanim utworzymy wpis lub zaczniemy kogoś obserwować."
step3_1: "Zakończyłeś(-aś) konfigurację profilu?"
step3_3: "Wypełnij pole i kliknij przycisk w prawym górnym rogu by wysłać post."
_2fa:
registerDevice: "Zarejestruj nowe urządzenie"
step1: "Najpierw, zainstaluj aplikację uwierzytelniającą (taką jak {a} lub {b}) na swoim urządzeniu."
@ -1049,7 +1075,7 @@ _poll:
deadlineDate: "Data zakończenia"
deadlineTime: "godz."
duration: "Czas trwania"
votesCount: "{} głosów"
votesCount: "{n} głosów"
totalVotes: "Łącznie {n} głosów"
vote: "Głosowanie w ankiecie"
showResult: "Pokaż wyniki"

View File

@ -106,7 +106,6 @@ clickToShow: "Нажмите для просмотра"
sensitive: "Содержимое не для всех"
add: "Добавить"
reaction: "Реакции"
reactionSettingDescription: "Подберите, что будет у вас в палитре реакций"
reactionSettingDescription2: "Расставляйте перетаскиванием, удаляйте нажатием, добавляйте кнопкой «+»."
rememberNoteVisibility: "Запоминать видимость заметок"
attachCancel: "Удалить вложение"
@ -612,7 +611,6 @@ regenerateLoginToken: "Создать новый токен для входа"
regenerateLoginTokenDescription: "Создаёт новый токен, используемый внутри программы во время входа. Обычно в этом нет необходимости. При создании все устройства будут отключены."
setMultipleBySeparatingWithSpace: "Можно написать несколько через пробел"
fileIdOrUrl: "Идентификатор файла или ссылка"
chatOpenBehavior: "Поведение окна чата при открытии"
behavior: "Поведение"
sample: "Пример"
abuseReports: "Жалобы"
@ -684,6 +682,7 @@ center: "По центру"
wide: "Толстый"
narrow: "Тонкий"
reloadToApplySetting: "Это настройка вступает в силу при загрузке страницы. Перезагрузить сейчас?"
needReloadToApply: "Чтобы это вступило в силу, требуется перезагрузка."
showTitlebar: "Показать заголовок"
clearCache: "Очистить кэш"
onlineUsersCount: "Пользователей сейчас в сети: {n}"
@ -802,10 +801,16 @@ makeReactionsPublicDescription: "Список сделанных вами реа
classic: "Классика"
unmuteThread: "Отключить звук"
ffVisibilityDescription: "Вы можете установить объем вашей следующей/последней информации."
voteConfirm: "Вы бы проголосовали за \"{choice}\"?"
hide: "Спрятать"
leaveGroup: "Покинуть группу"
leaveGroupConfirm: "Вы хотите оставить \"{name}\"?"
welcomeBackWithName: "С возвращением, {name}!"
clickToFinishEmailVerification: "Пожалуйста, нажмите [{ok}], чтобы завершить подтверждение адреса электронной почты."
_emailUnavailable:
used: "Уже используется"
format: "Неправильный формат"
mx: "Это неправильный почтовый сервер!"
smtp: "Почтовый сервер не отвечает"
_ffVisibility:
public: "Опубликовать"
@ -1263,6 +1268,7 @@ _exportOrImport:
muteList: "Скрытые"
blockingList: "Заблокированные"
userLists: "Списки"
excludeMutingUsers: "Исключение отключенных пользователей"
_charts:
federationInstancesIncDec: "Изменение внешних связей"
federationInstancesTotal: "Количество внешних связей"

View File

@ -103,7 +103,6 @@ clickToShow: "Натисніть для перегляду"
sensitive: "NSFW"
add: "Додати"
reaction: "Реакції"
reactionSettingDescription: "Виберіть свої улюблені реакції, які хочете закріпити в селекторі реакцій."
reactionSettingDescription2: "Перемістити щоб змінити порядок, Клацнути мишою щоб видалити, Натиснути \"+\" щоб додати."
rememberNoteVisibility: "Пам’ятати параметри видимісті"
attachCancel: "Видалити вкладення"
@ -593,7 +592,6 @@ regenerateLoginToken: "Оновити Login Token"
regenerateLoginTokenDescription: "Регенерувати внутрішній ключ використовуваний під час входу. Зазвичай цього не потрібно робити. При регенерації всі пристрої вийдуть з системи."
setMultipleBySeparatingWithSpace: "Можна вказати кілька значень, відділивши їх пробілом."
fileIdOrUrl: "Ідентифікатор файлу або посилання"
chatOpenBehavior: "Поводження вікна переписки під час відкриття"
behavior: "Поведінка"
sample: "Приклад"
abuseReports: "Скарги"

View File

@ -106,7 +106,7 @@ clickToShow: "点击以显示"
sensitive: "敏感内容"
add: "添加"
reaction: "回应"
reactionSettingDescription: "选择您想要置顶的回应"
reactionSetting: "选择器中显示的回应"
reactionSettingDescription2: "拖动重新排序,单击删除,点击 + 添加。"
rememberNoteVisibility: "保存上次设置的可见性"
attachCancel: "删除附件"
@ -448,6 +448,7 @@ uiLanguage: "显示语言"
groupInvited: "您有新的群组邀请"
aboutX: "关于 {x}"
useOsNativeEmojis: "使用系统的原生表情符号"
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}人在线"
@ -813,6 +814,11 @@ deleteAccountConfirm: "将要删除账户。是否确认?"
incorrectPassword: "密码错误"
voteConfirm: "确定投给“{choice}” "
hide: "隐藏"
leaveGroup: "离开群组"
leaveGroupConfirm: "确定离开「{name}」?"
useDrawerReactionPickerForMobile: "在移动设备上使用抽屉显示"
welcomeBackWithName: "欢迎回来,{name}"
clickToFinishEmailVerification: "点击 [{ok}] 完成电子邮件地址认证。"
_emailUnavailable:
used: "已经被使用过"
format: "无效的格式"

View File

@ -104,7 +104,6 @@ clickToShow: "按一下以顯示"
sensitive: "敏感內容"
add: "新增"
reaction: "情感"
reactionSettingDescription: "置頂「反應」表情符號\n"
reactionSettingDescription2: "拖動以重新列序,點擊以刪除,按下 + 添加。"
rememberNoteVisibility: "記住貼文可見性"
attachCancel: "移除附件"
@ -598,7 +597,6 @@ regenerateLoginToken: "重新產生登入權杖"
regenerateLoginTokenDescription: "重新產生用於登入的內部權杖。一般情況下是不需要這樣做的。一旦重產,所有裝置將會被登出。"
setMultipleBySeparatingWithSpace: "您可以使用空格分隔多個項目。"
fileIdOrUrl: "檔案ID或URL"
chatOpenBehavior: "開啟聊天窗口時的行為"
behavior: "行為"
sample: "範例"
abuseReports: "檢舉"

View File

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

View File

@ -4,6 +4,8 @@ module.exports = class chartV31639325650583 {
name = 'chartV31639325650583'
async up(queryRunner) {
await queryRunner.query(`DELETE FROM "__chart__per_user_drive" WHERE "group" IS NULL`);
await queryRunner.query(`DROP INDEX "public"."IDX_dd907becf76104e4b656659e6b"`);
await queryRunner.query(`DROP INDEX "public"."IDX_eddfed8fb40305a04c6f941050"`);
await queryRunner.query(`DROP INDEX "public"."IDX_f09d543e3acb16c5976bdb31fa"`);

View File

@ -170,7 +170,7 @@
"strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0",
"style-loader": "3.3.1",
"summaly": "2.4.1",
"summaly": "2.5.0",
"syslog-pro": "1.0.0",
"systeminformation": "5.9.9",
"throttle-debounce": "3.0.1",

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

@ -168,7 +168,7 @@ export function fromHtml(html: string, hashtagNames?: string[]): string | null {
case 'blockquote': {
const t = getText(node);
if (t) {
text += '> ';
text += '\n> ';
text += t.split('\n').join(`\n> `);
}
break;

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

@ -188,6 +188,11 @@
node-fetch "^2.6.1"
yaml-ast-parser "0.0.43"
"@sindresorhus/is@^3.0.0":
version "3.1.2"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-3.1.2.tgz#548650de521b344e3781fbdb0ece4aa6f729afb8"
integrity sha512-JiX9vxoKMmu8Y3Zr2RVathBL1Cdu4Nt4MuNWemt1Nc06A0RAin9c5FArkhGsyMBWfCu4zj+9b+GxtjAnE4qqLQ==
"@sindresorhus/is@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.0.0.tgz#2ff674e9611b45b528896d820d3d7a812de2f0e4"
@ -314,13 +319,6 @@
dependencies:
cbor "*"
"@types/cheerio@0.22.18":
version "0.22.18"
resolved "https://registry.yarnpkg.com/@types/cheerio/-/cheerio-0.22.18.tgz#19018dceae691509901e339d63edf1e935978fe6"
integrity sha512-Fq7R3fINAPSdUEhOyjG4iVxgHrOnqDJbY0/BUuiN0pvD/rfmZWekVZnv+vcs8TtpA2XF50uv50LaE4EnpEL/Hw==
dependencies:
"@types/node" "*"
"@types/color-name@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
@ -738,11 +736,6 @@
dependencies:
"@types/node" "*"
"@types/rsvp@^4.0.4":
version "4.0.4"
resolved "https://registry.yarnpkg.com/@types/rsvp/-/rsvp-4.0.4.tgz#55e93e7054027f1ad4b4ebc1e60e59eb091e2d32"
integrity sha512-J3Ol++HCC7/hwZhanDvggFYU/GtxHxE/e7cGRWxR04BF7Tt3TqJZ84BkzQgDxmX0uu8IagiyfmfoUlBACh2Ilg==
"@types/sanitize-html@2.5.0":
version "2.5.0"
resolved "https://registry.yarnpkg.com/@types/sanitize-html/-/sanitize-html-2.5.0.tgz#bfef58fbcf2674b20ffcc23c3506faa68c3a13e3"
@ -1230,7 +1223,7 @@ ajv-keywords@^3.5.2:
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.5.5:
ajv@^6.10.0, ajv@^6.12.4, ajv@^6.12.5:
version "6.12.5"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.5.tgz#19b0e8bae8f476e5ba666300387775fb1a00a4da"
integrity sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==
@ -1290,7 +1283,7 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0:
"@types/color-name" "^1.1.1"
color-convert "^2.0.1"
any-promise@^1.0.0, any-promise@^1.1.0:
any-promise@^1.0.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
integrity sha1-q8av7tzqUugJzcA3au0845Y10X8=
@ -1483,16 +1476,6 @@ aws-sdk@2.1013.0:
uuid "3.3.2"
xml2js "0.4.19"
aws-sign2@~0.7.0:
version "0.7.0"
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
aws4@^1.8.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
axios@^0.19.2:
version "0.19.2"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
@ -1882,11 +1865,6 @@ canonicalize@^1.0.1:
resolved "https://registry.yarnpkg.com/canonicalize/-/canonicalize-1.0.1.tgz#657b4f3fa38a6ecb97a9e5b7b26d7a19cc6e0da9"
integrity sha512-N3cmB3QLhS5TJ5smKFf1w42rJXWe6C1qP01z4dxJiI5v269buii4fLHWETDyf7yEd0azGLNC63VxNMiPd2u0Cg==
caseless@~0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
cbor@*:
version "7.0.5"
resolved "https://registry.yarnpkg.com/cbor/-/cbor-7.0.5.tgz#ed54cdbc19fa7352bb328d00a5393aa7ce45a10f"
@ -1964,31 +1942,7 @@ chartjs-plugin-zoom@1.1.1:
dependencies:
hammerjs "^2.0.8"
cheerio-httpcli@0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/cheerio-httpcli/-/cheerio-httpcli-0.8.2.tgz#0189bda71c8bd2852de78e154291e2288184fbf2"
integrity sha512-grIzTwQg/nE7Oy6VvL19pf0UlM6wiluy/AOpXfQLVFrSi21F8wnO3dLchtaH2hfMF6jz68ot0/ngyQQVrp2VTw==
dependencies:
"@types/cheerio" "0.22.18"
"@types/rsvp" "^4.0.4"
async "^3.2.0"
cheerio "^0.22.0"
colors "^1.4.0"
foreach "^2.0.5"
he "^1.2.0"
iconv-lite "^0.6.3"
import-fresh "^3.3.0"
jschardet "^3.0.0"
object-assign "^4.1.1"
os-locale "^5.0.0"
prettyjson "^1.2.1"
request "^2.88.2"
rsvp "^4.8.5"
tough-cookie "^2.5.0"
type-of "^2.0.1"
valid-url "^1.0.9"
cheerio@^0.22.0:
cheerio@0.22.0:
version "0.22.0"
resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e"
integrity sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=
@ -2169,12 +2123,7 @@ colorette@^1.2.0, colorette@^1.2.1, colorette@^1.2.2:
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
colors@^1.1.2, colors@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
@ -2329,7 +2278,7 @@ cross-env@7.0.3:
dependencies:
cross-spawn "^7.0.1"
cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -2535,14 +2484,14 @@ debug@4, debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
dependencies:
ms "2.1.2"
debug@4.3.2, debug@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
debug@4.3.3:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
debug@=3.1.0, debug@~3.1.0:
debug@=3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
@ -2563,6 +2512,13 @@ debug@^3.2.7:
dependencies:
ms "^2.1.1"
debug@^4.3.2:
version "4.3.2"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
dependencies:
ms "2.1.2"
debuglog@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
@ -3296,21 +3252,6 @@ execa@6.0.0:
signal-exit "^3.0.5"
strip-final-newline "^3.0.0"
execa@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a"
integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==
dependencies:
cross-spawn "^7.0.0"
get-stream "^5.0.0"
human-signals "^1.1.1"
is-stream "^2.0.0"
merge-stream "^2.0.0"
npm-run-path "^4.0.0"
onetime "^5.1.0"
signal-exit "^3.0.2"
strip-final-newline "^2.0.0"
exit-on-epipe@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692"
@ -3342,11 +3283,6 @@ extend-shallow@^2.0.1:
dependencies:
is-extendable "^0.1.0"
extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
extsprintf@1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
@ -3509,16 +3445,6 @@ follow-redirects@1.5.10:
dependencies:
debug "=3.1.0"
foreach@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99"
integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k=
forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
form-data@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
@ -3528,15 +3454,6 @@ form-data@^3.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
form-data@~2.3.2:
version "2.3.3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.6"
mime-types "^2.1.12"
fresh@~0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
@ -3623,7 +3540,7 @@ get-port@^5.1.1:
resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193"
integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==
get-stream@^5.0.0, get-stream@^5.1.0:
get-stream@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
@ -3744,6 +3661,23 @@ globby@^11.0.4:
merge2 "^1.3.0"
slash "^3.0.0"
got@11.5.1:
version "11.5.1"
resolved "https://registry.yarnpkg.com/got/-/got-11.5.1.tgz#bf098a270fe80b3fb88ffd5a043a59ebb0a391db"
integrity sha512-reQEZcEBMTGnujmQ+Wm97mJs/OK6INtO6HmLI+xt3+9CvnRwWjXutUvb2mqr+Ao4Lu05Rx6+udx9sOQAmExMxA==
dependencies:
"@sindresorhus/is" "^3.0.0"
"@szmarczak/http-timer" "^4.0.5"
"@types/cacheable-request" "^6.0.1"
"@types/responselike" "^1.0.0"
cacheable-lookup "^5.0.3"
cacheable-request "^7.0.1"
decompress-response "^6.0.0"
http2-wrapper "^1.0.0-beta.5.0"
lowercase-keys "^2.0.0"
p-cancelable "^2.0.0"
responselike "^2.0.0"
got@11.8.2:
version "11.8.2"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599"
@ -3786,19 +3720,6 @@ hammerjs@^2.0.8:
resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.8.tgz#04ef77862cff2bb79d30f7692095930222bf60f1"
integrity sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=
har-schema@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
har-validator@~5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
dependencies:
ajv "^6.5.5"
har-schema "^2.0.0"
has-bigints@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113"
@ -3843,7 +3764,7 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
he@1.2.0, he@^1.2.0:
he@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
@ -3963,14 +3884,13 @@ http-signature@1.3.5:
jsprim "^1.2.2"
sshpk "^1.14.1"
http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
http2-wrapper@^1.0.0-beta.5.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
dependencies:
assert-plus "^1.0.0"
jsprim "^1.2.2"
sshpk "^1.7.0"
quick-lru "^5.1.1"
resolve-alpn "^1.0.0"
http2-wrapper@^1.0.0-beta.5.2:
version "1.0.0-beta.5.2"
@ -3995,11 +3915,6 @@ https-proxy-agent@^5.0.0:
agent-base "6"
debug "4"
human-signals@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3"
integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==
human-signals@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5"
@ -4031,13 +3946,6 @@ iconv-lite@^0.6.2:
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
iconv-lite@^0.6.3:
version "0.6.3"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
icss-utils@^5.0.0, icss-utils@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
@ -4083,14 +3991,6 @@ import-fresh@^3.0.0, import-fresh@^3.2.1:
parent-module "^1.0.0"
resolve-from "^4.0.0"
import-fresh@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
dependencies:
parent-module "^1.0.0"
resolve-from "^4.0.0"
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
@ -4158,11 +4058,6 @@ internal-slot@^1.0.3:
has "^1.0.3"
side-channel "^1.0.4"
invert-kv@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-3.0.1.tgz#a93c7a3d4386a1dc8325b97da9bb1620c0282523"
integrity sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==
ioredis@^4.27.0:
version "4.27.6"
resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.27.6.tgz#a53d427d3fe75fbd10ed7ad150ce00559df8dcf8"
@ -4418,11 +4313,6 @@ is-shared-array-buffer@^1.0.1:
resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6"
integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==
is-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
is-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
@ -4456,7 +4346,7 @@ is-symbol@^1.0.3:
dependencies:
has-symbols "^1.0.2"
is-typedarray@^1.0.0, is-typedarray@~1.0.0:
is-typedarray@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
@ -4498,11 +4388,6 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
jest-worker@^26.6.2:
version "26.6.2"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
@ -4575,7 +4460,7 @@ jsbn@~0.1.0:
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
jschardet@^3.0.0:
jschardet@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-3.0.0.tgz#898d2332e45ebabbdb6bf2feece9feea9a99e882"
integrity sha512-lJH6tJ77V8Nzd5QWRkFYCLc13a3vADkh3r/Fi8HupZGWk2OVVDfnZP8V/VgQgZ+lzW0kG2UGb5hFgt3V3ndotQ==
@ -4643,7 +4528,7 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1:
json-stringify-safe@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
@ -4773,26 +4658,11 @@ koa-bodyparser@4.3.0:
co-body "^6.0.0"
copy-to "^2.0.1"
koa-compose@^3.0.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7"
integrity sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=
dependencies:
any-promise "^1.1.0"
koa-compose@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877"
integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==
koa-convert@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0"
integrity sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=
dependencies:
co "^4.6.0"
koa-compose "^3.0.0"
koa-convert@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-2.0.0.tgz#86a0c44d81d40551bae22fee6709904573eea4f5"
@ -4877,35 +4747,6 @@ koa-views@7.0.2:
pretty "^2.0.0"
resolve-path "^1.4.0"
koa@2.13.1:
version "2.13.1"
resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.1.tgz#6275172875b27bcfe1d454356a5b6b9f5a9b1051"
integrity sha512-Lb2Dloc72auj5vK4X4qqL7B5jyDPQaZucc9sR/71byg7ryoD1NCaCm63CShk9ID9quQvDEi1bGR/iGjCG7As3w==
dependencies:
accepts "^1.3.5"
cache-content-type "^1.0.0"
content-disposition "~0.5.2"
content-type "^1.0.4"
cookies "~0.8.0"
debug "~3.1.0"
delegates "^1.0.0"
depd "^2.0.0"
destroy "^1.0.4"
encodeurl "^1.0.2"
escape-html "^1.0.3"
fresh "~0.5.2"
http-assert "^1.3.0"
http-errors "^1.6.3"
is-generator-function "^1.0.7"
koa-compose "^4.1.0"
koa-convert "^1.2.0"
on-finished "^2.3.0"
only "~0.0.2"
parseurl "^1.3.2"
statuses "^1.5.0"
type-is "^1.6.16"
vary "^1.1.2"
koa@2.13.4:
version "2.13.4"
resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.4.tgz#ee5b0cb39e0b8069c38d115139c774833d32462e"
@ -4960,13 +4801,6 @@ lazystream@^1.0.0:
dependencies:
readable-stream "^2.0.5"
lcid@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lcid/-/lcid-3.1.1.tgz#9030ec479a058fc36b5e8243ebaac8b6ac582fd0"
integrity sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==
dependencies:
invert-kv "^3.0.0"
levn@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade"
@ -5193,13 +5027,6 @@ make-fetch-happen@^8.0.14:
socks-proxy-agent "^5.0.0"
ssri "^8.0.0"
map-age-cleaner@^0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
dependencies:
p-defer "^1.0.0"
mdn-data@2.0.14:
version "2.0.14"
resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
@ -5210,15 +5037,6 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
mem@^5.0.0:
version "5.1.1"
resolved "https://registry.yarnpkg.com/mem/-/mem-5.1.1.tgz#7059b67bf9ac2c924c9f1cff7155a064394adfb3"
integrity sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==
dependencies:
map-age-cleaner "^0.1.3"
mimic-fn "^2.1.0"
p-is-promise "^2.1.0"
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@ -5284,18 +5102,13 @@ mime-types@2.1.34:
dependencies:
mime-db "1.51.0"
mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.24:
mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@~2.1.24:
version "2.1.27"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f"
integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==
dependencies:
mime-db "1.44.0"
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-fn@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
@ -5690,13 +5503,6 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
npm-run-path@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
dependencies:
path-key "^3.0.0"
npm-run-path@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.0.1.tgz#748dd68ed7de377bb1f7132c7dafe657be5ab400"
@ -5738,11 +5544,6 @@ nwsapi@^2.2.0:
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
oauth-sign@~0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
oauth@0.9.15:
version "0.9.15"
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
@ -5824,13 +5625,6 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0:
dependencies:
wrappy "1"
onetime@^5.1.0:
version "5.1.2"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
dependencies:
mimic-fn "^2.1.0"
onetime@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4"
@ -5877,15 +5671,6 @@ os-homedir@^1.0.0:
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
os-locale@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-5.0.0.tgz#6d26c1d95b6597c5d5317bf5fba37eccec3672e0"
integrity sha512-tqZcNEDAIZKBEPnHPlVDvKrp7NzgLi7jRmhKiUoa2NUmhl13FtkAGLUVR+ZsYvApBQdBfYm43A4tXXQ4IrYLBA==
dependencies:
execa "^4.0.0"
lcid "^3.0.0"
mem "^5.0.0"
os-tmpdir@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@ -5909,21 +5694,11 @@ p-cancelable@^2.0.0:
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.0.0.tgz#4a3740f5bdaf5ed5d7c3e34882c6fb5d6b266a6e"
integrity sha512-wvPXDmbMmu2ksjkB4Z3nZWTSkJEb9lqVdMaCKpZUGJG9TMiNp9XcbG3fn9fPKjem04fJMJnXoyFPk2FmgiaiNg==
p-defer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
p-is-promise@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
p-limit@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8"
@ -6066,7 +5841,7 @@ path-is-absolute@1.0.1, path-is-absolute@^1.0.0:
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
path-key@^3.0.0, path-key@^3.1.0:
path-key@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
@ -6096,11 +5871,6 @@ peek-readable@^4.0.1:
resolved "https://registry.yarnpkg.com/peek-readable/-/peek-readable-4.0.1.tgz#9a045f291db254111c3412c1ce4fec27ddd4d202"
integrity sha512-7qmhptnR0WMSpxT5rMHG9bW/mYSR1uqaPFj2MHvT+y/aOUu6msJijpKt5SkTDKySwg65OWG2JwTMBlgcbwMHrQ==
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
pg-connection-string@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34"
@ -6529,14 +6299,6 @@ pretty@^2.0.0:
extend-shallow "^2.0.1"
js-beautify "^1.6.12"
prettyjson@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/prettyjson/-/prettyjson-1.2.1.tgz#fcffab41d19cab4dfae5e575e64246619b12d289"
integrity sha1-/P+rQdGcq0365eV15kJGYZsS0ok=
dependencies:
colors "^1.1.2"
minimist "^1.2.0"
printj@~1.1.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/printj/-/printj-1.1.2.tgz#d90deb2975a8b9f600fb3a1c94e3f4c53c78a222"
@ -6620,7 +6382,7 @@ pseudomap@^1.0.2:
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
psl@^1.1.28, psl@^1.1.33:
psl@^1.1.33:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
@ -6778,11 +6540,6 @@ qs@^6.4.0, qs@^6.5.2:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.3.tgz#bfadcd296c2d549f1dffa560619132c977f5008e"
integrity sha512-EbZYNarm6138UKKq46tdx08Yo/q9ZhFoAXAI1meAFd2GtbRDhbZY2WQSICskT0c5q99aFzLG1D4nvTk9tqfXIw==
qs@~6.5.2:
version "6.5.2"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
querystring@0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
@ -6966,22 +6723,6 @@ rename@1.0.4:
dependencies:
debug "^2.5.2"
request-promise-core@1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f"
integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==
dependencies:
lodash "^4.17.19"
request-promise-native@1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28"
integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==
dependencies:
request-promise-core "1.1.4"
stealthy-require "^1.1.1"
tough-cookie "^2.3.3"
request-stats@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/request-stats/-/request-stats-3.0.0.tgz#769155dc8974d78d4a1cb87bbf14eaab985afe25"
@ -6990,32 +6731,6 @@ request-stats@3.0.0:
http-headers "^3.0.1"
once "^1.4.0"
request@2.88.2, request@^2.88.2:
version "2.88.2"
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
dependencies:
aws-sign2 "~0.7.0"
aws4 "^1.8.0"
caseless "~0.12.0"
combined-stream "~1.0.6"
extend "~3.0.2"
forever-agent "~0.6.1"
form-data "~2.3.2"
har-validator "~5.1.3"
http-signature "~1.2.0"
is-typedarray "~1.0.0"
isstream "~0.1.2"
json-stringify-safe "~5.0.1"
mime-types "~2.1.19"
oauth-sign "~0.9.0"
performance-now "^2.1.0"
qs "~6.5.2"
safe-buffer "^5.1.2"
tough-cookie "~2.5.0"
tunnel-agent "^0.6.0"
uuid "^3.3.2"
require-all@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/require-all/-/require-all-3.0.0.tgz#473d49704be310115ce124f77383b1ebd8671312"
@ -7102,11 +6817,6 @@ rndstr@1.0.0:
rangestr "0.0.1"
seedrandom "2.4.2"
rsvp@^4.8.5:
version "4.8.5"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734"
integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==
run-parallel@^1.1.9:
version "1.1.9"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
@ -7132,7 +6842,7 @@ safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0:
safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
@ -7294,7 +7004,7 @@ sigmund@^1.0.1:
resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590"
integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=
signal-exit@^3.0.0, signal-exit@^3.0.2:
signal-exit@^3.0.0:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
@ -7404,7 +7114,7 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
sshpk@^1.14.1, sshpk@^1.7.0:
sshpk@^1.14.1:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
@ -7441,11 +7151,6 @@ standard-as-callback@^2.1.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
stealthy-require@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
stream-parser@~0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/stream-parser/-/stream-parser-0.3.1.tgz#1618548694420021a1182ff0af1911c129761773"
@ -7614,11 +7319,6 @@ strip-bom@^3.0.0:
resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3"
integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=
strip-final-newline@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
strip-final-newline@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
@ -7655,18 +7355,19 @@ stylehacks@^5.0.1:
browserslist "^4.16.0"
postcss-selector-parser "^6.0.4"
summaly@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/summaly/-/summaly-2.4.1.tgz#d2a8fa6bad10c1651eb0b849aab3009e87216a3d"
integrity sha512-1gETEQXqK5RD7yIGgdGeTwGL1uh+uj14u99atzNLNmvsxwdtZbPvDHZBPXkAW0cqsd8teoBJln5Dh1QeAhvGIg==
summaly@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/summaly/-/summaly-2.5.0.tgz#ec5af6e84857efcb6c844d896e83569e64a923ea"
integrity sha512-IzvO2s7yj/PUyH42qWjVjSPpIiPlgTRWGh33t4cIZKOqPQJ2INo7e83hXhHFr4hXTb3JRcIdCuM1ELjlrujiUQ==
dependencies:
cheerio-httpcli "0.8.2"
debug "4.3.2"
cheerio "0.22.0"
debug "4.3.3"
escape-regexp "0.0.1"
got "11.5.1"
html-entities "2.3.2"
koa "2.13.1"
request "2.88.2"
request-promise-native "1.0.9"
jschardet "3.0.0"
koa "2.13.4"
private-ip "2.3.3"
require-all "3.0.0"
trace-redirect "1.0.6"
@ -7889,14 +7590,6 @@ token-types@^4.1.1:
"@tokenizer/token" "^0.3.0"
ieee754 "^1.2.1"
tough-cookie@^2.3.3, tough-cookie@^2.5.0, tough-cookie@~2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
dependencies:
psl "^1.1.28"
punycode "^2.1.1"
tough-cookie@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
@ -8055,11 +7748,6 @@ type-is@^1.6.14, type-is@^1.6.16, type-is@^1.6.4:
media-typer "0.3.0"
mime-types "~2.1.24"
type-of@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/type-of/-/type-of-2.0.1.tgz#e72a1741896568e9f628378d816d6912f7f23972"
integrity sha1-5yoXQYllaOn2KDeNgW1pEvfyOXI=
type@^1.0.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0"
@ -8223,21 +7911,11 @@ uuid@8.3.2, uuid@^8.3.0:
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
uuid@^3.3.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
v8-compile-cache@^2.0.3:
version "2.2.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132"
integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==
valid-url@^1.0.9:
version "1.0.9"
resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200"
integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=
vary@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 B

View File

@ -27,39 +27,39 @@
"@types/oauth": "0.9.1",
"@types/parse5": "6.0.3",
"@types/punycode": "2.1.0",
"@types/qrcode": "1.4.1",
"@types/qrcode": "1.4.2",
"@types/random-seed": "0.3.3",
"@types/request-stats": "3.0.0",
"@types/seedrandom": "2.4.28",
"@types/throttle-debounce": "2.1.0",
"@types/tinycolor2": "1.4.3",
"@types/tmp": "0.2.2",
"@types/tmp": "0.2.3",
"@types/uuid": "8.3.3",
"@types/web-push": "3.3.2",
"@types/webpack": "5.28.0",
"@types/webpack-stream": "3.2.12",
"@types/websocket": "1.0.4",
"@types/ws": "8.2.2",
"@typescript-eslint/parser": "5.6.0",
"@vue/compiler-sfc": "3.2.24",
"@typescript-eslint/parser": "5.8.1",
"@vue/compiler-sfc": "3.2.26",
"abort-controller": "3.0.0",
"autobind-decorator": "2.4.0",
"autosize": "4.0.4",
"autwh": "0.1.0",
"blurhash": "1.1.4",
"broadcast-channel": "4.7.0",
"chart.js": "3.6.2",
"broadcast-channel": "4.9.0",
"chart.js": "3.7.0",
"chartjs-adapter-date-fns": "2.0.0",
"chartjs-plugin-zoom": "1.2.0",
"compare-versions": "3.6.0",
"content-disposition": "0.5.3",
"content-disposition": "0.5.4",
"crc-32": "1.2.0",
"css-loader": "6.5.1",
"cssnano": "5.0.12",
"date-fns": "2.27.0",
"cssnano": "5.0.14",
"date-fns": "2.28.0",
"dateformat": "4.5.1",
"escape-regexp": "0.0.1",
"eslint": "8.4.1",
"eslint": "8.5.0",
"eslint-plugin-vue": "8.2.0",
"eventemitter3": "4.0.7",
"feed": "4.2.2",
@ -80,7 +80,7 @@
"parse5": "6.0.1",
"photoswipe": "git://github.com/dimsemenov/photoswipe#v5-beta",
"portscanner": "2.2.0",
"postcss": "8.4.4",
"postcss": "8.4.5",
"postcss-loader": "6.2.1",
"prismjs": "1.25.0",
"private-ip": "2.3.3",
@ -94,7 +94,7 @@
"request-stats": "3.0.0",
"rndstr": "1.0.0",
"s-age": "1.1.2",
"sass": "1.44.0",
"sass": "1.45.1",
"sass-loader": "12.4.0",
"seedrandom": "3.0.5",
"strict-event-emitter-types": "2.0.0",
@ -111,11 +111,11 @@
"tsc-alias": "1.4.2",
"tsconfig-paths": "3.12.0",
"twemoji-parser": "13.1.0",
"typescript": "4.5.2",
"typescript": "4.5.4",
"uuid": "8.3.2",
"v-debounce": "0.1.2",
"vanilla-tilt": "1.7.2",
"vue": "3.2.24",
"vue": "3.2.26",
"vue-loader": "16.8.3",
"vue-prism-editor": "2.0.0-alpha.2",
"vue-router": "4.0.5",
@ -126,14 +126,14 @@
"webpack": "5.65.0",
"webpack-cli": "4.9.1",
"websocket": "1.0.34",
"ws": "8.3.0"
"ws": "8.4.0"
},
"devDependencies": {
"@redocly/openapi-core": "1.0.0-beta.54",
"@types/fluent-ffmpeg": "2.1.17",
"@typescript-eslint/eslint-plugin": "5.4.0",
"@typescript-eslint/eslint-plugin": "5.8.1",
"cross-env": "7.0.3",
"cypress": "8.5.0",
"cypress": "9.2.0",
"eslint-plugin-import": "2.25.3",
"start-server-and-test": "1.14.0"
}

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

@ -1,5 +1,5 @@
<template>
<div class="swhvrteh _popup _shadow" @contextmenu.prevent="() => {}">
<div class="swhvrteh _popup _shadow" :style="{ zIndex }" @contextmenu.prevent="() => {}">
<ol v-if="type === 'user'" ref="suggests" class="users">
<li v-for="user in users" tabindex="-1" class="user" @click="complete(type, user)" @keydown="onKeydown">
<img class="avatar" :src="user.avatarUrl"/>
@ -157,6 +157,7 @@ export default defineComponent({
items: [],
mfmTags: [],
select: -1,
zIndex: os.claimZIndex('high'),
}
},
@ -403,7 +404,6 @@ export default defineComponent({
<style lang="scss" scoped>
.swhvrteh {
position: fixed;
z-index: 65535;
max-width: 100%;
margin-top: calc(1em + 8px);
overflow: hidden;

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" :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,17 +1,17 @@
<template>
<MkPopup ref="popup" v-slot="{ point, close }" :manual-showing="manualShowing" :src="src" :front="true" @click="close()" @opening="opening" @close="$emit('close')" @closed="$emit('closed')">
<MkEmojiPicker ref="picker" class="ryghynhb _popup _shadow" :class="{ pointer: point === 'top' }" :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" @chosen="chosen"/>
</MkPopup>
<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>
<script lang="ts">
import { defineComponent, markRaw } from 'vue';
import MkPopup from '@/components/ui/popup.vue';
import MkModal from '@/components/ui/modal.vue';
import MkEmojiPicker from '@/components/emoji-picker.vue';
export default defineComponent({
components: {
MkPopup,
MkModal,
MkEmojiPicker,
},
@ -44,7 +44,7 @@ export default defineComponent({
methods: {
chosen(emoji: any) {
this.$emit('done', emoji);
this.$refs.popup.close();
this.$refs.modal.close();
},
opening() {
@ -57,20 +57,10 @@ export default defineComponent({
<style lang="scss" scoped>
.ryghynhb {
&.pointer {
&:before {
--size: 8px;
content: '';
display: block;
position: absolute;
top: calc(0px - (var(--size) * 2));
left: 0;
right: 0;
width: 0;
margin: auto;
border: solid var(--size) transparent;
border-bottom-color: var(--popup);
}
&.drawer {
border-radius: 24px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<div class="omfetrab" :class="['w' + width, 'h' + height, { big }]">
<div class="omfetrab" :class="['w' + width, 'h' + height, { big, asDrawer }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : null }">
<input ref="search" v-model.trim="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="$ts.search" @paste.stop="paste" @keyup.enter="done()">
<div ref="emojis" class="emojis">
<section class="result">
@ -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';
@ -92,9 +92,17 @@ export default defineComponent({
props: {
showPinned: {
required: false,
default: true
default: true,
},
asReactionPicker: {
required: false,
},
maxHeight: {
type: Number,
required: false,
},
asDrawer: {
type: Boolean,
required: false
},
},
@ -288,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);
@ -353,26 +361,60 @@ export default defineComponent({
&.w1 {
width: calc((var(--eachSize) * 5) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr;
}
&.w2 {
width: calc((var(--eachSize) * 6) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr 1fr;
}
&.w3 {
width: calc((var(--eachSize) * 7) + (#{$pad} * 2));
--columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
}
&.h1 {
--height: calc((var(--eachSize) * 4) + (#{$pad} * 2));
height: calc((var(--eachSize) * 4) + (#{$pad} * 2));
}
&.h2 {
--height: calc((var(--eachSize) * 6) + (#{$pad} * 2));
height: calc((var(--eachSize) * 6) + (#{$pad} * 2));
}
&.h3 {
--height: calc((var(--eachSize) * 8) + (#{$pad} * 2));
height: calc((var(--eachSize) * 8) + (#{$pad} * 2));
}
&.asDrawer {
width: 100% !important;
> .emojis {
::v-deep(section) {
> header {
height: 32px;
line-height: 32px;
padding: 0 12px;
font-size: 15px;
}
> div {
display: grid;
grid-template-columns: var(--columns);
> button {
aspect-ratio: 1 / 1;
width: auto;
height: auto;
min-width: 0;
> * {
font-size: 30px;
}
}
}
}
}
}
> .search {
@ -409,7 +451,7 @@ export default defineComponent({
}
> .emojis {
height: var(--height);
height: 100%;
overflow-y: auto;
overflow-x: hidden;

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

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkModal ref="modal" :prefer-type="'dialog'" @click="$refs.modal.close()" @closed="$emit('closed')">
<div class="szkkfdyq _popup">
<div class="main">
<template v-for="item in items">

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

@ -175,14 +175,7 @@ export default defineComponent({
if (!this.$store.state.animatedMfm) {
return genEl(token.children);
}
let count = token.props.args.count ? parseInt(token.props.args.count) : 10;
if (count > 100) {
count = 100;
}
const speed = token.props.args.speed ? parseFloat(token.props.args.speed) : 1;
return h(MkSparkle, {
count, speed,
}, genEl(token.children));
return h(MkSparkle, {}, genEl(token.children));
}
case 'rotate': {
const degrees = parseInt(token.props.args.deg) || '90';

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

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" :position="'top'" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkModal ref="modal" :prefer-type="'dialog:top'" @click="$refs.modal.close()" @closed="$emit('closed')">
<MkPostForm v-bind="$attrs" @posted="$refs.modal.close()" @cancel="$refs.modal.close()" @esc="$refs.modal.close()"/>
</MkModal>
</template>

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,161 +1,121 @@
<template>
<span class="mk-sparkle">
<span ref="content">
<span ref="el">
<slot></slot>
</span>
<canvas ref="canvas"></canvas>
<!-- なぜか path に対する key が機能しないため
<svg :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg">
<path v-for="particle in particles" :key="particle.id" style="transform-origin: center; transform-box: fill-box;"
:transform="`translate(${particle.x} ${particle.y})`"
:fill="particle.color"
d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z"
>
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
from="0 0 0"
to="360 0 0"
:dur="`${particle.dur}ms`"
repeatCount="indefinite"
additive="sum"
/>
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
:values="`0; ${particle.size}; 0`"
:dur="`${particle.dur}ms`"
repeatCount="indefinite"
additive="sum"
/>
</path>
</svg>
-->
<svg v-for="particle in particles" :key="particle.id" :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg">
<path style="transform-origin: center; transform-box: fill-box;"
:transform="`translate(${particle.x} ${particle.y})`"
:fill="particle.color"
d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z"
>
<animateTransform
attributeName="transform"
attributeType="XML"
type="rotate"
from="0 0 0"
to="360 0 0"
:dur="`${particle.dur}ms`"
repeatCount="1"
additive="sum"
/>
<animateTransform
attributeName="transform"
attributeType="XML"
type="scale"
:values="`0; ${particle.size}; 0`"
:dur="`${particle.dur}ms`"
repeatCount="1"
additive="sum"
/>
</path>
</svg>
</span>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
import * as os from '@/os';
const sprite = new Image();
sprite.src = '/client-assets/sparkle-spritesheet.png';
export default defineComponent({
props: {
count: {
type: Number,
required: true,
},
speed: {
type: Number,
required: true,
},
},
data() {
return {
sprites: [0,6,13,20],
particles: [],
anim: null,
ctx: null,
};
},
unmounted() {
window.cancelAnimationFrame(this.anim);
},
mounted() {
this.ctx = this.$refs.canvas.getContext('2d');
setup() {
const particles = ref([]);
const el = ref<HTMLElement>();
const width = ref(0);
const height = ref(0);
const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202'];
new ResizeObserver(this.resize).observe(this.$refs.content);
this.resize();
this.tick();
},
updated() {
this.resize();
},
methods: {
createSparkles(w, h, count) {
const holder = [];
for (let i = 0; i < count; i++) {
const color = '#' + ('000000' + Math.floor(Math.random() * 16777215).toString(16)).slice(-6);
holder[i] = {
position: {
x: Math.floor(Math.random() * w),
y: Math.floor(Math.random() * h)
},
style: this.sprites[ Math.floor(Math.random() * 4) ],
delta: {
x: Math.floor(Math.random() * 1000) - 500,
y: Math.floor(Math.random() * 1000) - 500
},
color: color,
opacity: Math.random(),
onMounted(() => {
const ro = new ResizeObserver((entries, observer) => {
width.value = el.value?.offsetWidth + 64;
height.value = el.value?.offsetHeight + 64;
});
ro.observe(el.value);
let stop = false;
const add = () => {
if (stop) return;
const x = (Math.random() * (width.value - 64));
const y = (Math.random() * (height.value - 64));
const sizeFactor = Math.random();
const particle = {
id: Math.random().toString(),
x,
y,
size: 0.2 + ((sizeFactor / 10) * 3),
dur: 1000 + (sizeFactor * 1000),
color: colors[Math.floor(Math.random() * colors.length)],
};
particles.value.push(particle);
window.setTimeout(() => {
particles.value = particles.value.filter(x => x.id !== particle.id);
}, particle.dur - 100);
}
return holder;
},
draw(time) {
this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height);
this.ctx.beginPath();
const particleSize = Math.floor(this.fontSize / 2);
this.particles.forEach((particle) => {
var modulus = Math.floor(Math.random()*7);
if (Math.floor(time) % modulus === 0) {
particle.style = this.sprites[ Math.floor(Math.random()*4) ];
}
this.ctx.save();
this.ctx.globalAlpha = particle.opacity;
this.ctx.drawImage(sprite, particle.style, 0, 7, 7, particle.position.x, particle.position.y, particleSize, particleSize);
this.ctx.globalCompositeOperation = "source-atop";
this.ctx.globalAlpha = 0.5;
this.ctx.fillStyle = particle.color;
this.ctx.fillRect(particle.position.x, particle.position.y, particleSize, particleSize);
this.ctx.restore();
window.setTimeout(() => {
add();
}, 500 + (Math.random() * 500));
};
add();
onUnmounted(() => {
ro.disconnect();
stop = true;
});
this.ctx.stroke();
},
tick() {
this.anim = window.requestAnimationFrame((time) => {
if (!this.$refs.canvas) {
return;
}
this.particles.forEach((particle) => {
if (!particle) {
return;
}
var randX = Math.random() > Math.random() * 2;
var randY = Math.random() > Math.random() * 3;
});
if (randX) {
particle.position.x += (particle.delta.x * this.speed) / 1500;
}
if (!randY) {
particle.position.y -= (particle.delta.y * this.speed) / 800;
}
if( particle.position.x > this.$refs.canvas.width ) {
particle.position.x = -7;
} else if (particle.position.x < -7) {
particle.position.x = this.$refs.canvas.width;
}
if (particle.position.y > this.$refs.canvas.height) {
particle.position.y = -7;
particle.position.x = Math.floor(Math.random() * this.$refs.canvas.width);
} else if (particle.position.y < -7) {
particle.position.y = this.$refs.canvas.height;
particle.position.x = Math.floor(Math.random() * this.$refs.canvas.width);
}
particle.opacity -= 0.005;
if (particle.opacity <= 0) {
particle.opacity = 1;
}
});
this.draw(time);
this.tick();
});
},
resize() {
if (this.$refs.content) {
const contentRect = this.$refs.content.getBoundingClientRect();
this.fontSize = parseFloat(getComputedStyle(this.$refs.content).fontSize);
const padding = this.fontSize * 0.2;
this.$refs.canvas.width = parseInt(contentRect.width + padding);
this.$refs.canvas.height = parseInt(contentRect.height + padding);
this.particles = this.createSparkles(this.$refs.canvas.width, this.$refs.canvas.height, this.count);
}
},
return {
el,
width,
height,
particles,
};
},
});
</script>
@ -169,10 +129,10 @@ export default defineComponent({
display: inline-block;
}
> canvas {
> svg {
position: absolute;
top: -0.1em;
left: -0.1em;
top: -32px;
left: -32px;
pointer-events: none;
}
}

View File

@ -1,73 +1,70 @@
<template>
<div class="mk-toast">
<transition name="notification-slide" appear @after-leave="$emit('closed')">
<XNotification v-if="showing" :notification="notification" class="notification _acrylic"/>
<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
showing: 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;
z-index: 10000;
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

@ -1,8 +1,8 @@
<template>
<div ref="items" v-hotkey="keymap"
class="rrevdjwt"
:class="{ center: align === 'center' }"
:style="{ width: width ? width + 'px' : null, maxHeight: maxHeight ? maxHeight + 'px' : null }"
:class="{ center: align === 'center', asDrawer }"
:style="{ width: (width && !asDrawer) ? width + 'px' : null, maxHeight: maxHeight ? maxHeight + 'px' : null }"
@contextmenu.self="e => e.preventDefault()"
>
<template v-for="(item, i) in items2">
@ -56,6 +56,10 @@ export default defineComponent({
type: Boolean,
required: false
},
asDrawer: {
type: Boolean,
required: false
},
align: {
type: String,
requried: false
@ -276,8 +280,31 @@ export default defineComponent({
> .divider {
margin: 8px 0;
height: 1px;
background: var(--divider);
border-top: solid 0.5px var(--divider);
}
&.asDrawer {
padding: 12px 0 calc(env(safe-area-inset-bottom, 0px) + 12px) 0;
width: 100%;
> .item {
font-size: 1em;
padding: 12px 24px;
&:before {
width: calc(100% - 24px);
border-radius: 12px;
}
> i {
margin-right: 14px;
width: 24px;
}
}
> .divider {
margin: 12px 0;
}
}
}
</style>

View File

@ -1,5 +1,5 @@
<template>
<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
<MkModal ref="modal" :prefer-type="'dialog'" @click="$emit('click')" @closed="$emit('closed')">
<div class="ebkgoccj _window _narrow_" :style="{ width: `${width}px`, height: scroll ? (height ? `${height}px` : null) : (height ? `min(${height}px, 100%)` : '100%') }" @keydown="onKeydown">
<div class="header">
<button v-if="withOkButton" class="_button" @click="$emit('close')"><i class="fas fa-times"></i></button>

View File

@ -1,17 +1,19 @@
<template>
<transition :name="$store.state.animation ? popup ? 'modal-popup' : 'modal' : ''" :duration="$store.state.animation ? popup ? 500 : 300 : 0" appear @after-leave="onClosed" @enter="$emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" class="qzhlnise" :style="{ pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<div class="bg _modalBg" :style="{ zIndex }" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
<div ref="content" class="content" :class="{ popup, fixed, top: position === 'top' }" :style="{ zIndex }" @click.self="onBgClick">
<slot></slot>
<transition :name="$store.state.animation ? (type === 'drawer') ? 'modal-drawer' : (type === 'popup') ? 'modal-popup' : 'modal' : ''" :duration="$store.state.animation ? 200 : 0" appear @after-leave="$emit('closed')" @enter="$emit('opening')" @after-enter="childRendered">
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" class="qzhlnise" :class="{ drawer: type === 'drawer', dialog: type === 'dialog' || type === 'dialog:top', popup: type === 'popup' }" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<div class="bg _modalBg" :class="{ transparent: transparentBg && (type === 'popup') }" :style="{ zIndex }" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
<div ref="content" class="content" :class="{ fixed, top: type === 'dialog:top' }" :style="{ zIndex }" @click.self="onBgClick">
<slot :max-height="maxHeight" :type="type"></slot>
</div>
</div>
</transition>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
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;
@ -27,6 +29,7 @@ export default defineComponent({
provide: {
modal: true
},
props: {
manualShowing: {
type: Boolean,
@ -38,61 +41,86 @@ export default defineComponent({
required: false
},
src: {
type: Object as PropType<HTMLElement>,
required: false,
default: null,
},
position: {
required: false
preferType: {
required: false,
type: String,
default: 'auto',
},
front: {
zPriority: {
type: String as PropType<'low' | 'middle' | 'high'>,
required: false,
default: 'low',
},
noOverlap: {
type: Boolean,
required: false,
default: true,
},
transparentBg: {
type: Boolean,
required: false,
default: false,
}
},
emits: ['opening', 'click', 'esc', 'close', 'closed'],
data() {
return {
zIndex: os.claimZIndex(this.front),
showing: true,
fixed: false,
transformOrigin: 'center',
contentClicking: false,
};
},
computed: {
keymap(): any {
return {
'esc': () => this.$emit('esc'),
};
},
popup(): boolean {
return this.src != null;
}
},
mounted() {
this.$watch('src', () => {
this.fixed = getFixedContainer(this.src) != null;
this.$nextTick(() => {
this.align();
});
}, { immediate: true });
this.$nextTick(() => {
const popover = this.$refs.content as any;
new ResizeObserver((entries, observer) => {
this.align();
}).observe(popover);
emits: ['opening', 'click', 'esc', 'close', 'closed'],
setup(props, context) {
const maxHeight = ref<number>();
const fixed = ref(false);
const transformOrigin = ref('center');
const showing = ref(true);
const content = ref<HTMLElement>();
const zIndex = os.claimZIndex(props.zPriority);
const type = computed(() => {
if (props.preferType === 'auto') {
if (!defaultStore.state.disableDrawer && isTouchUsing && window.innerWidth < 500 && window.innerHeight < 1000) {
return 'drawer';
} else {
return props.src != null ? 'popup' : 'dialog';
}
} else {
return props.preferType;
}
});
},
methods: {
align() {
if (!this.popup) return;
let contentClicking = false;
const popover = this.$refs.content as any;
const close = () => {
// eslint-disable-next-line vue/no-mutating-props
if (props.src) props.src.style.pointerEvents = 'auto';
showing.value = false;
context.emit('close');
};
const onBgClick = () => {
if (contentClicking) return;
context.emit('click');
};
if (type.value === 'drawer') {
maxHeight.value = window.innerHeight / 2;
}
const keymap = {
'esc': () => context.emit('esc'),
};
const MARGIN = 16;
const align = () => {
if (props.src == null) return;
if (type.value === 'drawer') return;
const popover = content.value!;
if (popover == null) return;
const rect = this.src.getBoundingClientRect();
const rect = props.src.getBoundingClientRect();
const width = popover.offsetWidth;
const height = popover.offsetHeight;
@ -100,102 +128,143 @@ export default defineComponent({
let left;
let top;
if (this.srcCenter) {
const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.src.offsetWidth / 2);
const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + (this.src.offsetHeight / 2);
if (props.srcCenter) {
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + (props.src.offsetHeight / 2);
left = (x - (width / 2));
top = (y - (height / 2));
} else {
const x = rect.left + (this.fixed ? 0 : window.pageXOffset) + (this.src.offsetWidth / 2);
const y = rect.top + (this.fixed ? 0 : window.pageYOffset) + this.src.offsetHeight;
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + props.src.offsetHeight;
left = (x - (width / 2));
top = y;
}
if (this.fixed) {
if (fixed.value) {
// 画面から横にはみ出る場合
if (left + width > window.innerWidth) {
left = window.innerWidth - width;
}
if (top + height > window.innerHeight) {
top = window.innerHeight - height;
// 画面から縦にはみ出る場合
if (top + height > (window.innerHeight - MARGIN)) {
if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - top;
const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = (upperSpace + MARGIN) - height;
}
} else {
top = (window.innerHeight - MARGIN) - height;
}
}
} else {
// 画面から横にはみ出る場合
if (left + width - window.pageXOffset > window.innerWidth) {
left = window.innerWidth - width + window.pageXOffset - 1;
}
if (top + height - window.pageYOffset > window.innerHeight) {
top = window.innerHeight - height + window.pageYOffset - 1;
// 画面から縦にはみ出る場合
if (top + height - window.pageYOffset > (window.innerHeight - MARGIN)) {
if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - (top - window.pageYOffset);
const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = window.pageYOffset + ((upperSpace + MARGIN) - height);
}
} else {
top = (window.innerHeight - MARGIN) - height + window.pageYOffset - 1;
}
}
}
if (top < 0) {
top = 0;
top = MARGIN;
}
if (left < 0) {
left = 0;
}
if (top > rect.top + (this.fixed ? 0 : window.pageYOffset)) {
this.transformOrigin = 'center top';
if (top > rect.top + (fixed.value ? 0 : window.pageYOffset)) {
transformOrigin.value = 'center top';
} else if ((top + height) <= rect.top + (fixed.value ? 0 : window.pageYOffset)) {
transformOrigin.value = 'center bottom';
} else {
this.transformOrigin = 'center';
transformOrigin.value = 'center';
}
popover.style.left = left + 'px';
popover.style.top = top + 'px';
},
};
childRendered() {
const childRendered = () => {
// モーダルコンテンツにマウスボタンが押され、コンテンツ外でマウスボタンが離されたときにモーダルバックグラウンドクリックと判定させないためにマウスイベントを監視しフラグ管理する
const content = this.$refs.content.children[0];
content.addEventListener('mousedown', e => {
this.contentClicking = true;
const el = content.value!.children[0];
el.addEventListener('mousedown', e => {
contentClicking = true;
window.addEventListener('mouseup', e => {
// click イベントより先に mouseup イベントが発生するかもしれないのでちょっと待つ
setTimeout(() => {
this.contentClicking = false;
contentClicking = false;
}, 100);
}, { passive: true, once: true });
}, { passive: true });
},
};
close() {
this.showing = false;
this.$emit('close');
},
onMounted(() => {
watch(() => props.src, async () => {
if (props.src) {
// eslint-disable-next-line vue/no-mutating-props
props.src.style.pointerEvents = 'none';
}
fixed.value = (type.value === 'drawer') || (getFixedContainer(props.src) != null);
onBgClick() {
if (this.contentClicking) return;
this.$emit('click');
},
await nextTick()
align();
}, { immediate: true, });
onClosed() {
this.$emit('closed');
}
}
nextTick(() => {
const popover = content.value;
new ResizeObserver((entries, observer) => {
align();
}).observe(popover!);
});
});
return {
showing,
type,
fixed,
content,
transformOrigin,
maxHeight,
close,
zIndex,
keymap,
onBgClick,
childRendered,
};
},
});
</script>
<style lang="scss">
.modal-popup-enter-active, .modal-popup-leave-active,
.modal-enter-from, .modal-leave-to {
> .content {
transform-origin: var(--transformOrigin);
}
}
</style>
<style lang="scss" scoped>
.modal-enter-active, .modal-leave-active {
> .bg {
transition: opacity 0.3s !important;
transition: opacity 0.2s !important;
}
> .content {
transition: opacity 0.3s, transform 0.3s !important;
transform-origin: var(--transformOrigin);
transition: opacity 0.2s, transform 0.2s !important;
}
}
.modal-enter-from, .modal-leave-to {
@ -206,17 +275,19 @@ export default defineComponent({
> .content {
pointer-events: none;
opacity: 0;
transform-origin: var(--transformOrigin);
transform: scale(0.9);
}
}
.modal-popup-enter-active, .modal-popup-leave-active {
> .bg {
transition: opacity 0.3s !important;
transition: opacity 0.2s !important;
}
> .content {
transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1) !important;
transform-origin: var(--transformOrigin);
transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), transform 0.2s cubic-bezier(0, 0, 0.2, 1) !important;
}
}
.modal-popup-enter-from, .modal-popup-leave-to {
@ -227,48 +298,112 @@ export default defineComponent({
> .content {
pointer-events: none;
opacity: 0;
transform-origin: var(--transformOrigin);
transform: scale(0.9);
}
}
.modal-drawer-enter-active {
> .bg {
transition: opacity 0.2s !important;
}
> .content {
transition: transform 0.2s cubic-bezier(0,.5,0,1) !important;
}
}
.modal-drawer-leave-active {
> .bg {
transition: opacity 0.2s !important;
}
> .content {
transition: transform 0.2s cubic-bezier(0,.5,0,1) !important;
}
}
.modal-drawer-enter-from, .modal-drawer-leave-to {
> .bg {
opacity: 0;
}
> .content {
pointer-events: none;
transform: translateY(100%);
}
}
.qzhlnise {
> .content:not(.popup) {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
padding: 32px;
// TODO: mask-imageはiOSだとやたら重い。なんとかしたい
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 32px, rgba(0,0,0,1) calc(100% - 32px), rgba(0,0,0,0) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 32px, rgba(0,0,0,1) calc(100% - 32px), rgba(0,0,0,0) 100%);
overflow: auto;
display: flex;
@media (max-width: 500px) {
padding: 16px;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
> .bg {
&.transparent {
background: transparent;
-webkit-backdrop-filter: none;
backdrop-filter: none;
}
}
> ::v-deep(*) {
&.dialog {
> .content {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
padding: 32px;
// TODO: mask-imageはiOSだとやたら重い。なんとかしたい
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 32px, rgba(0,0,0,1) calc(100% - 32px), rgba(0,0,0,0) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 32px, rgba(0,0,0,1) calc(100% - 32px), rgba(0,0,0,0) 100%);
overflow: auto;
display: flex;
@media (max-width: 500px) {
padding: 16px;
-webkit-mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 16px, rgba(0,0,0,1) calc(100% - 16px), rgba(0,0,0,0) 100%);
}
&.top {
> ::v-deep(*) {
margin-top: 0;
margin: auto;
}
&.top {
> ::v-deep(*) {
margin-top: 0;
}
}
}
}
> .content.popup {
position: absolute;
&.popup {
> .content {
position: absolute;
&.fixed {
position: fixed;
&.fixed {
position: fixed;
}
}
}
&.drawer {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: clip;
> .content {
position: fixed;
bottom: 0;
left: 0;
right: 0;
margin: auto;
> ::v-deep(*) {
margin: auto;
}
}
}
}
</style>

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,17 +1,17 @@
<template>
<MkPopup ref="popup" v-slot="{ maxHeight, close }" :src="src" @closed="$emit('closed')">
<MkMenu :items="items" :align="align" :width="width" :max-height="maxHeight" class="_popup _shadow" @close="close()"/>
</MkPopup>
<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>
<script lang="ts">
import { defineComponent } from 'vue';
import MkPopup from './popup.vue';
import MkModal from './modal.vue';
import MkMenu from './menu.vue';
export default defineComponent({
components: {
MkPopup,
MkModal,
MkMenu,
},
@ -40,3 +40,13 @@ export default defineComponent({
emits: ['close', 'closed'],
});
</script>
<style lang="scss" scoped>
.sfhdhdhq {
&.drawer {
border-radius: 24px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
}
</style>

View File

@ -1,237 +0,0 @@
<template>
<transition :name="$store.state.animation ? 'popup-menu' : ''" appear @after-leave="$emit('closed')" @enter="$emit('opening')">
<div v-show="manualShowing != null ? manualShowing : showing" ref="content" class="ccczpooj" :class="{ fixed, top: position === 'top' }" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
<slot :max-height="maxHeight" :close="close"></slot>
</div>
</transition>
</template>
<script lang="ts">
import { defineComponent, nextTick, onMounted, onUnmounted, PropType, ref, watch } from 'vue';
import * as os from '@/os';
function getFixedContainer(el: Element | null | undefined): Element | null {
if (el == null || el.tagName === 'BODY') return null;
const position = window.getComputedStyle(el).getPropertyValue('position');
if (position === 'fixed') {
return el;
} else {
return getFixedContainer(el.parentElement);
}
}
export default defineComponent({
props: {
manualShowing: {
type: Boolean,
required: false,
default: null,
},
srcCenter: {
type: Boolean,
required: false
},
src: {
type: Object as PropType<HTMLElement>,
required: false,
},
position: {
required: false
},
front: {
type: Boolean,
required: false,
default: false,
},
noOverlap: {
type: Boolean,
required: false,
default: true,
},
},
emits: ['opening', 'click', 'esc', 'close', 'closed'],
setup(props, context) {
const maxHeight = ref<number>();
const fixed = ref(false);
const transformOrigin = ref('center');
const showing = ref(true);
const content = ref<HTMLElement>();
const zIndex = os.claimZIndex(props.front);
const close = () => {
// eslint-disable-next-line vue/no-mutating-props
if (props.src) props.src.style.pointerEvents = 'auto';
showing.value = false;
context.emit('close');
};
const MARGIN = 16;
const align = () => {
if (props.src == null) return;
const popover = content.value!;
if (popover == null) return;
const rect = props.src.getBoundingClientRect();
const width = popover.offsetWidth;
const height = popover.offsetHeight;
let left;
let top;
if (props.srcCenter) {
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + (props.src.offsetHeight / 2);
left = (x - (width / 2));
top = (y - (height / 2));
} else {
const x = rect.left + (fixed.value ? 0 : window.pageXOffset) + (props.src.offsetWidth / 2);
const y = rect.top + (fixed.value ? 0 : window.pageYOffset) + props.src.offsetHeight;
left = (x - (width / 2));
top = y;
}
if (fixed.value) {
// 画面から横にはみ出る場合
if (left + width > window.innerWidth) {
left = window.innerWidth - width;
}
// 画面から縦にはみ出る場合
if (top + height > (window.innerHeight - MARGIN)) {
if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - top;
const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = (upperSpace + MARGIN) - height;
}
} else {
top = (window.innerHeight - MARGIN) - height;
}
}
} else {
// 画面から横にはみ出る場合
if (left + width - window.pageXOffset > window.innerWidth) {
left = window.innerWidth - width + window.pageXOffset - 1;
}
// 画面から縦にはみ出る場合
if (top + height - window.pageYOffset > (window.innerHeight - MARGIN)) {
if (props.noOverlap) {
const underSpace = (window.innerHeight - MARGIN) - (top - window.pageYOffset);
const upperSpace = (rect.top - MARGIN);
if (underSpace >= (upperSpace / 3)) {
maxHeight.value = underSpace;
} else {
maxHeight.value = upperSpace;
top = window.pageYOffset + ((upperSpace + MARGIN) - height);
}
} else {
top = (window.innerHeight - MARGIN) - height + window.pageYOffset - 1;
}
}
}
if (top < 0) {
top = MARGIN;
}
if (left < 0) {
left = 0;
}
if (top > rect.top + (fixed.value ? 0 : window.pageYOffset)) {
transformOrigin.value = 'center top';
} else if ((top + height) <= rect.top + (fixed.value ? 0 : window.pageYOffset)) {
transformOrigin.value = 'center bottom';
} else {
transformOrigin.value = 'center';
}
popover.style.left = left + 'px';
popover.style.top = top + 'px';
};
const onDocumentClick = (ev: MouseEvent) => {
const flyoutElement = content.value;
let targetElement = ev.target;
do {
if (targetElement === flyoutElement) {
return;
}
targetElement = targetElement.parentNode;
} while (targetElement);
close();
};
onMounted(() => {
watch(() => props.src, async () => {
if (props.src) {
// eslint-disable-next-line vue/no-mutating-props
props.src.style.pointerEvents = 'none';
}
fixed.value = getFixedContainer(props.src) != null;
await nextTick()
align();
}, { immediate: true, });
nextTick(() => {
const popover = content.value;
new ResizeObserver((entries, observer) => {
align();
}).observe(popover!);
});
document.addEventListener('mousedown', onDocumentClick, { passive: true });
onUnmounted(() => {
document.removeEventListener('mousedown', onDocumentClick);
});
});
return {
showing,
fixed,
content,
transformOrigin,
maxHeight,
close,
zIndex,
};
},
});
</script>
<style lang="scss" scoped>
.popup-menu-enter-active {
transform-origin: var(--transformOrigin);
transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), transform 0.2s cubic-bezier(0, 0, 0.2, 1) !important;
}
.popup-menu-leave-active {
transform-origin: var(--transformOrigin);
transition: opacity 0.2s cubic-bezier(0.4, 0, 1, 1), transform 0.2s cubic-bezier(0.4, 0, 1, 1) !important;
}
.popup-menu-enter-from, .popup-menu-leave-to {
pointer-events: none;
opacity: 0;
transform: scale(0.9);
}
.ccczpooj {
position: absolute;
&.fixed {
position: fixed;
}
}
</style>

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,7 +1,7 @@
<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="title"><MkSparkle>{{ $ts.misskeyUpdated }}</MkSparkle></div>
<div class="version">{{ version }}🚀</div>
<MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton>
<MkButton class="gotIt" primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton>
@ -9,31 +9,19 @@
</MkModal>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
<script lang="ts" setup>
import { ref } from 'vue';
import MkModal from '@/components/ui/modal.vue';
import MkButton from '@/components/ui/button.vue';
import MkSparkle from '@/components/sparkle.vue';
import { version } from '@/config';
export default defineComponent({
components: {
MkModal,
MkButton,
},
const modal = ref();
data() {
return {
version: version,
};
},
methods: {
whatIsNew() {
this.$refs.modal.close();
window.open(`https://misskey-hub.net/docs/releases.html#_${version.replace(/\./g, '-')}`, '_blank');
}
}
});
const whatIsNew = () => {
modal.value.close();
window.open(`https://misskey-hub.net/docs/releases.html#_${version.replace(/\./g, '-')}`, '_blank');
};
</script>
<style lang="scss" scoped>

View File

@ -1,5 +1,5 @@
<template>
<div class="fgmtyycl" :style="{ top: top + 'px', left: left + 'px' }">
<div class="fgmtyycl" :style="{ zIndex, top: top + 'px', left: left + 'px' }">
<transition name="zoom" @after-leave="$emit('closed')">
<MkUrlPreview v-if="showing" class="_popup _shadow" :url="url"/>
</transition>
@ -35,6 +35,7 @@ export default defineComponent({
u: null,
top: 0,
left: 0,
zIndex: os.claimZIndex('middle'),
};
},
@ -52,7 +53,6 @@ export default defineComponent({
<style lang="scss" scoped>
.fgmtyycl {
position: absolute;
z-index: 11000;
width: 500px;
max-width: calc(90vw - 12px);
pointer-events: none;

View File

@ -1,6 +1,6 @@
<template>
<transition name="popup" appear @after-leave="$emit('closed')">
<div v-if="showing" class="fxxzrfni _popup _shadow" :style="{ top: top + 'px', left: left + 'px' }" @mouseover="() => { $emit('mouseover'); }" @mouseleave="() => { $emit('mouseleave'); }">
<div v-if="showing" class="fxxzrfni _popup _shadow" :style="{ zIndex, top: top + 'px', left: left + 'px' }" @mouseover="() => { $emit('mouseover'); }" @mouseleave="() => { $emit('mouseleave'); }">
<div v-if="fetched" class="info">
<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
<MkAvatar class="avatar" :user="user" :disable-preview="true" :show-indicator="true"/>
@ -65,6 +65,7 @@ export default defineComponent({
fetched: false,
top: 0,
left: 0,
zIndex: os.claimZIndex('middle'),
};
},
@ -109,7 +110,6 @@ export default defineComponent({
.fxxzrfni {
position: absolute;
z-index: 11000;
width: 300px;
overflow: hidden;
transform-origin: center top;

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" @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

@ -2,7 +2,7 @@
<div class="mk-group-page">
<transition name="zoom" mode="out-in">
<div v-if="group" class="_section">
<div class="_content">
<div class="_content" style="display: flex; gap: var(--margin); flex-wrap: wrap;">
<MkButton inline @click="invite()">{{ $ts.invite }}</MkButton>
<MkButton inline @click="renameGroup()">{{ $ts.rename }}</MkButton>
<MkButton inline @click="transfer()">{{ $ts.transfer }}</MkButton>
@ -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

@ -29,11 +29,17 @@
<option :value="2">{{ $ts.medium }}</option>
<option :value="3">{{ $ts.large }}</option>
</FormRadios>
<FormSwitch v-model="reactionPickerUseDrawerForMobile" class="_formBlock">
{{ $ts.useDrawerReactionPickerForMobile }}
<template #caption>{{ $ts.needReloadToApply }}</template>
</FormSwitch>
<FormSection>
<FormButton @click="preview"><i class="fas fa-eye"></i> {{ $ts.preview }}</FormButton>
</FormSection>
<FormSection>
<FormButton danger @click="setDefault"><i class="fas fa-undo"></i> {{ $ts.default }}</FormButton>
<div style="display: flex; gap: var(--margin); flex-wrap: wrap;">
<FormButton inline @click="preview"><i class="fas fa-eye"></i> {{ $ts.preview }}</FormButton>
<FormButton inline danger @click="setDefault"><i class="fas fa-undo"></i> {{ $ts.default }}</FormButton>
</div>
</FormSection>
</div>
</template>
@ -46,6 +52,7 @@ import FormRadios from '@/components/form/radios.vue';
import FromSlot from '@/components/form/slot.vue';
import FormButton from '@/components/ui/button.vue';
import FormSection from '@/components/form/section.vue';
import FormSwitch from '@/components/form/switch.vue';
import * as os from '@/os';
import { defaultStore } from '@/store';
import * as symbols from '@/symbols';
@ -57,6 +64,7 @@ export default defineComponent({
FromSlot,
FormRadios,
FormSection,
FormSwitch,
XDraggable,
},
@ -80,6 +88,7 @@ export default defineComponent({
computed: {
reactionPickerWidth: defaultStore.makeGetterSetter('reactionPickerWidth'),
reactionPickerHeight: defaultStore.makeGetterSetter('reactionPickerHeight'),
reactionPickerUseDrawerForMobile: defaultStore.makeGetterSetter('reactionPickerUseDrawerForMobile'),
},
watch: {

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: {

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