Compare commits
118 Commits
Author | SHA1 | Date | |
---|---|---|---|
247bd43ae2 | |||
a6685b1559 | |||
66c4e8064b | |||
9d1fa3f202 | |||
a6985d7dc7 | |||
027c021ac9 | |||
604205ec09 | |||
77db016866 | |||
c6a009dbae | |||
4299e3f90c | |||
19f4812c03 | |||
d01c465a8d | |||
4f1409601e | |||
52cffe0864 | |||
0866d5c055 | |||
78c08f6503 | |||
27d0ac3d75 | |||
a8776002f3 | |||
31aa008566 | |||
9d405b4581 | |||
80c490a18b | |||
30c9c3739f | |||
ee0e7a09e0 | |||
bfd9577f0d | |||
0cada4ca76 | |||
a718ccc0b6 | |||
1fcfd8e645 | |||
c6dd932a0b | |||
b79eed01e0 | |||
3a7dbe9764 | |||
bef2534fa8 | |||
888dcd2559 | |||
2b69fca6bd | |||
7d088d42b4 | |||
f8ad303b13 | |||
3c59c6fc9b | |||
7353d729d7 | |||
62591e0e7a | |||
012f15d84b | |||
e57c6f94d2 | |||
40b27e8ad8 | |||
055e9f21b7 | |||
d7085b17fe | |||
0d4d7c9c0c | |||
99209d36e1 | |||
e2a9a0ff3d | |||
ab166959a4 | |||
ab692cfa3d | |||
c3ae6f3a4a | |||
5ef4a52bbd | |||
582768a5e4 | |||
1852d1cc6f | |||
7a5a541a4e | |||
72b03e009c | |||
1b113c1045 | |||
54959557ea | |||
d44cb7f256 | |||
3d063c95d1 | |||
09cab605fc | |||
666c8c0498 | |||
d3e764d7f9 | |||
7060625adf | |||
21b6e23e98 | |||
a0f794e372 | |||
9195504329 | |||
8c5d9dd549 | |||
580f6a5b6c | |||
74e76b460b | |||
c4570b37b7 | |||
cd0b0012d9 | |||
c055b4d32d | |||
75a9ff832a | |||
b64d3af1f3 | |||
fb6605bb40 | |||
3bfae80fa7 | |||
cb16cb0610 | |||
0baed1a275 | |||
42162c8015 | |||
0fab0c416d | |||
e2e262c8ce | |||
cf6596203b | |||
471911a54f | |||
9394f4f540 | |||
4e968216ad | |||
84a7a9555f | |||
8d12fd152b | |||
629b765abc | |||
63a89fa84a | |||
a3f89236a0 | |||
01560abafb | |||
b5698026ba | |||
6258ce75b7 | |||
6f34c74027 | |||
8add4f359b | |||
d8933c135f | |||
eb350e8d6c | |||
615fedd64d | |||
25bd82ecaa | |||
e0938e5e3a | |||
ec5e6c8443 | |||
25d8077474 | |||
06083f40d9 | |||
ec203f7f79 | |||
1b30d7d47a | |||
d9be9c958f | |||
ed09796e0d | |||
4bfa29c0ab | |||
4804bbb211 | |||
749102f9c2 | |||
0bcb1434b0 | |||
2e537e618c | |||
fe3b7a2ad3 | |||
90db793fd0 | |||
7bd2a6ad61 | |||
745f4d2439 | |||
254cfaea28 | |||
d4da5a1eea | |||
c0f8297414 |
@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
_lang_: "العربية"
|
_lang_: "العربية"
|
||||||
|
introMisskey: "اهلا بك! ميسكي هو منصة تدوين مصغر لا مركزية ومفتوحة المصدر.\nيمكنك مشاركة \"ملاحظات\" عن ما يجري حولك، وإخبار الجميع عن نفسك 📡\nتسمح لك \"الانفعالات\" بتعبير عن شعورك حول ملاحظات الآخرين 👍\nاكتشف عالمًا جديدًا 🚀"
|
||||||
monthAndDay: "{day}/{month}"
|
monthAndDay: "{day}/{month}"
|
||||||
search: "البحث"
|
search: "البحث"
|
||||||
notifications: "الإشعارات"
|
notifications: "الإشعارات"
|
||||||
@ -32,6 +33,7 @@ favorite: "إضافة إلى المفضلة"
|
|||||||
favorites: "المفضلات"
|
favorites: "المفضلات"
|
||||||
unfavorite: "إزالة من المفضلة"
|
unfavorite: "إزالة من المفضلة"
|
||||||
pin: "دبّسها على الصفحة الشخصية"
|
pin: "دبّسها على الصفحة الشخصية"
|
||||||
|
unpin: "ألغ تثبيتها من ملفك الشخصي"
|
||||||
copyContent: "انسخ المحتوى"
|
copyContent: "انسخ المحتوى"
|
||||||
copyLink: "انسخ الرابط"
|
copyLink: "انسخ الرابط"
|
||||||
delete: "حذف"
|
delete: "حذف"
|
||||||
@ -78,6 +80,7 @@ followRequest: "طلب اشتراك"
|
|||||||
followRequests: "طلبات الإشتراك"
|
followRequests: "طلبات الإشتراك"
|
||||||
unfollow: "إلغاء الاشتراك"
|
unfollow: "إلغاء الاشتراك"
|
||||||
followRequestPending: "طلبات الإشتراك المعلّقة"
|
followRequestPending: "طلبات الإشتراك المعلّقة"
|
||||||
|
enterEmoji: "أدخل إيموجي"
|
||||||
unrenote: "إلغاء مشاركة الملاحظة"
|
unrenote: "إلغاء مشاركة الملاحظة"
|
||||||
quote: "اقتبس"
|
quote: "اقتبس"
|
||||||
pinnedNote: "ملاحظة مدبسة"
|
pinnedNote: "ملاحظة مدبسة"
|
||||||
@ -93,6 +96,8 @@ mute: "اكتم"
|
|||||||
unmute: "إلغاء الكتم"
|
unmute: "إلغاء الكتم"
|
||||||
block: "احجب"
|
block: "احجب"
|
||||||
unblock: "إلغاء الحجب"
|
unblock: "إلغاء الحجب"
|
||||||
|
suspend: "علِق"
|
||||||
|
unsuspend: "ألغ التعليق"
|
||||||
blockConfirm: "أمتأكد من حجب هذا الحساب؟"
|
blockConfirm: "أمتأكد من حجب هذا الحساب؟"
|
||||||
unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
|
unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
|
||||||
selectList: "اختر قائمة"
|
selectList: "اختر قائمة"
|
||||||
@ -280,7 +285,6 @@ unregister: "إلغاء التسجيل"
|
|||||||
passwordLessLogin: "لِج مِن دون كلمة سرية"
|
passwordLessLogin: "لِج مِن دون كلمة سرية"
|
||||||
resetPassword: "أعد تعيين كلمتك السرية"
|
resetPassword: "أعد تعيين كلمتك السرية"
|
||||||
newPasswordIs: "كلمتك السرية الجديدة هي {password}"
|
newPasswordIs: "كلمتك السرية الجديدة هي {password}"
|
||||||
autoNoteWatch: "راقب الملاحظات تلقائيا"
|
|
||||||
share: "شارِك"
|
share: "شارِك"
|
||||||
notFound: "غير موجود"
|
notFound: "غير موجود"
|
||||||
help: "المساعدة"
|
help: "المساعدة"
|
||||||
@ -304,6 +308,7 @@ noteOf: "ملاحظات {user}"
|
|||||||
inviteToGroup: "دعوة إلى فريق"
|
inviteToGroup: "دعوة إلى فريق"
|
||||||
noMessagesYet: "ليس هناك رسائل بعد"
|
noMessagesYet: "ليس هناك رسائل بعد"
|
||||||
newMessageExists: "لقد تلقيت رسالة جديدة"
|
newMessageExists: "لقد تلقيت رسالة جديدة"
|
||||||
|
invitations: "دعوة"
|
||||||
invitationCode: "رمز الدعوة"
|
invitationCode: "رمز الدعوة"
|
||||||
checking: "التحقق جارٍ"
|
checking: "التحقق جارٍ"
|
||||||
available: "متوفر"
|
available: "متوفر"
|
||||||
@ -374,6 +379,13 @@ smtpHost: "المضيف"
|
|||||||
smtpUser: "اسم المستخدم"
|
smtpUser: "اسم المستخدم"
|
||||||
smtpPass: "الكلمة السرية"
|
smtpPass: "الكلمة السرية"
|
||||||
display: "المظهر"
|
display: "المظهر"
|
||||||
|
_mfm:
|
||||||
|
mention: "أشر الى"
|
||||||
|
quote: "اقتبس"
|
||||||
|
emoji: "إيموجي مخصص"
|
||||||
|
search: "البحث"
|
||||||
|
_reversi:
|
||||||
|
total: "المجموع"
|
||||||
_channel:
|
_channel:
|
||||||
featured: "المتداوَلة"
|
featured: "المتداوَلة"
|
||||||
_sidebar:
|
_sidebar:
|
||||||
|
@ -18,7 +18,7 @@ instance: "Instanz"
|
|||||||
settings: "Einstellungen"
|
settings: "Einstellungen"
|
||||||
basicSettings: "Allgemeine Einstellungen"
|
basicSettings: "Allgemeine Einstellungen"
|
||||||
otherSettings: "Andere Einstellungen"
|
otherSettings: "Andere Einstellungen"
|
||||||
openInWindow: "In neuem Fenster öffnen"
|
openInWindow: "In Fenster öffnen"
|
||||||
profile: "Profil"
|
profile: "Profil"
|
||||||
timeline: "Chronik"
|
timeline: "Chronik"
|
||||||
noAccountDescription: "Dieser Nutzer hat seine Profilbeschreibung noch nicht ausgefüllt."
|
noAccountDescription: "Dieser Nutzer hat seine Profilbeschreibung noch nicht ausgefüllt."
|
||||||
@ -373,8 +373,6 @@ unregister: "Deaktivieren"
|
|||||||
passwordLessLogin: "Passwortloses Anmelden einrichten"
|
passwordLessLogin: "Passwortloses Anmelden einrichten"
|
||||||
resetPassword: "Passwort zurücksetzen"
|
resetPassword: "Passwort zurücksetzen"
|
||||||
newPasswordIs: "Das neue Passwort ist \"{password}\""
|
newPasswordIs: "Das neue Passwort ist \"{password}\""
|
||||||
autoNoteWatch: "Notizen automatisch beobachten"
|
|
||||||
autoNoteWatchDescription: "Werde über Notizen, auf die du reagiert oder geantwortet hast, informiert"
|
|
||||||
reduceUiAnimation: "Animationen der Benutzeroberfläche reduzieren"
|
reduceUiAnimation: "Animationen der Benutzeroberfläche reduzieren"
|
||||||
share: "Teilen"
|
share: "Teilen"
|
||||||
notFound: "Nicht gefunden"
|
notFound: "Nicht gefunden"
|
||||||
@ -412,6 +410,7 @@ noMessagesYet: "Noch keine Nachrichten"
|
|||||||
newMessageExists: "Du hast eine neue Nachricht"
|
newMessageExists: "Du hast eine neue Nachricht"
|
||||||
onlyOneFileCanBeAttached: "Es kann pro Nachricht nur eine Datei angehängt werden"
|
onlyOneFileCanBeAttached: "Es kann pro Nachricht nur eine Datei angehängt werden"
|
||||||
signinRequired: "Anmeldung erforderlich"
|
signinRequired: "Anmeldung erforderlich"
|
||||||
|
invitations: "Einladungen"
|
||||||
invitationCode: "Einladungscode"
|
invitationCode: "Einladungscode"
|
||||||
checking: "Wird überprüft..."
|
checking: "Wird überprüft..."
|
||||||
available: "Verfügbar"
|
available: "Verfügbar"
|
||||||
@ -484,7 +483,7 @@ newNoteRecived: "Es gibt neue Notizen"
|
|||||||
sounds: "Töne"
|
sounds: "Töne"
|
||||||
listen: "Anhören"
|
listen: "Anhören"
|
||||||
none: "Keine"
|
none: "Keine"
|
||||||
showInPage: "In Seiten anzeigen"
|
showInPage: "In Seite anzeigen"
|
||||||
popout: "Pop-Up"
|
popout: "Pop-Up"
|
||||||
volume: "Lautstärke"
|
volume: "Lautstärke"
|
||||||
details: "Details"
|
details: "Details"
|
||||||
@ -541,6 +540,7 @@ pluginInstallWarn: "Installiere nur vertrauenswürdige Plugins."
|
|||||||
deck: "Deck"
|
deck: "Deck"
|
||||||
undeck: "Deck verlassen"
|
undeck: "Deck verlassen"
|
||||||
useBlurEffectForModal: "Weichzeichnungseffekt für Modals verwenden"
|
useBlurEffectForModal: "Weichzeichnungseffekt für Modals verwenden"
|
||||||
|
useFullReactionPicker: "Vollständige Reaktionsauswahl nutzen"
|
||||||
generateAccessToken: "Zugriffstoken generieren"
|
generateAccessToken: "Zugriffstoken generieren"
|
||||||
permission: "Berechtigungen"
|
permission: "Berechtigungen"
|
||||||
enableAll: "Alle aktivieren"
|
enableAll: "Alle aktivieren"
|
||||||
@ -593,6 +593,61 @@ fillAbuseReportDescription: "Bitte gib Details für diese Meldung an. Falls es s
|
|||||||
abuseReported: "Die Meldung wurde versendet. Vielen Dank."
|
abuseReported: "Die Meldung wurde versendet. Vielen Dank."
|
||||||
send: "Senden"
|
send: "Senden"
|
||||||
abuseMarkAsResolved: "Meldung als gelöst markieren"
|
abuseMarkAsResolved: "Meldung als gelöst markieren"
|
||||||
|
openInNewTab: "In neuem Tab öffnen"
|
||||||
|
openInSideView: "In Seitenansicht öffnen"
|
||||||
|
defaultNavigationBehaviour: "Standardnavigationsverhalten"
|
||||||
|
editTheseSettingsMayBreakAccount: "Bei Bearbeitung dieser Einstellungen besteht die Gefahr, dein Benutzerkonto zu beschädigen."
|
||||||
|
instanceTicker: "Instanz-Informationen von Notizen"
|
||||||
|
waitingFor: "Warte auf {x}"
|
||||||
|
random: "Zufällig"
|
||||||
|
system: "System"
|
||||||
|
switchUi: "UI wechseln"
|
||||||
|
desktop: "Desktop"
|
||||||
|
_mfm:
|
||||||
|
mention: "Erwähnung"
|
||||||
|
hashtag: "Hashtag"
|
||||||
|
link: "Link"
|
||||||
|
center: "Bestandteile zentrieren"
|
||||||
|
quote: "Zitieren"
|
||||||
|
emoji: "Benutzerdefinierte Emojis"
|
||||||
|
search: "Suchen"
|
||||||
|
_reversi:
|
||||||
|
reversi: "Reversi"
|
||||||
|
gameSettings: "Spieleinstellungen"
|
||||||
|
chooseBoard: "Spielbrett auswählen"
|
||||||
|
blackOrWhite: "Schwarz/Weiß"
|
||||||
|
blackIs: "{name} spielt Schwarz"
|
||||||
|
rules: "Regeln"
|
||||||
|
botSettings: "Optionen des Computergegners"
|
||||||
|
thisGameIsStartedSoon: "Dieses Spiel beginnt in wenigen Sekunden"
|
||||||
|
waitingForOther: "Warte auf den Zug des Gegenspielers"
|
||||||
|
waitingForMe: "Warte auf deinen Zug"
|
||||||
|
waitingBoth: "Mach dich bereit"
|
||||||
|
ready: "Bereit"
|
||||||
|
cancelReady: "Nicht bereit"
|
||||||
|
opponentTurn: "Zug deines Gegners"
|
||||||
|
myTurn: "Dein Zug"
|
||||||
|
turnOf: "Zug von {name}"
|
||||||
|
pastTurnOf: "Zug von {name}"
|
||||||
|
surrender: "Aufgeben"
|
||||||
|
surrendered: "durch Aufgabe"
|
||||||
|
drawn: "Unentschieden"
|
||||||
|
won: "{name} hat gesiegt"
|
||||||
|
black: "Schwarz"
|
||||||
|
white: "Weiß"
|
||||||
|
total: "Gesamt"
|
||||||
|
turnCount: " Zug {count}"
|
||||||
|
myGames: "Meine Runden"
|
||||||
|
allGames: "Alle Runden"
|
||||||
|
ended: "Beendet"
|
||||||
|
playing: "Laufend"
|
||||||
|
isLlotheo: "Der mit weniger Steinen gewinnt (Llotheo)"
|
||||||
|
loopedMap: "Wiederholendes Spielbrett"
|
||||||
|
canPutEverywhere: "Steine können überall platziert werden"
|
||||||
|
_instanceTicker:
|
||||||
|
none: "Nie anzeigen"
|
||||||
|
remote: "Für Benutzer fremder Instanzen anzeigen"
|
||||||
|
always: "Immer anzeigen"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "Automatisch aktualisieren"
|
reload: "Automatisch aktualisieren"
|
||||||
dialog: "Warnungsfenster zeigen"
|
dialog: "Warnungsfenster zeigen"
|
||||||
|
@ -18,7 +18,7 @@ instance: "Instance"
|
|||||||
settings: "Settings"
|
settings: "Settings"
|
||||||
basicSettings: "Basic Settings"
|
basicSettings: "Basic Settings"
|
||||||
otherSettings: "Other Settings"
|
otherSettings: "Other Settings"
|
||||||
openInWindow: "Open in new window"
|
openInWindow: "Open in window"
|
||||||
profile: "Profile"
|
profile: "Profile"
|
||||||
timeline: "Timeline"
|
timeline: "Timeline"
|
||||||
noAccountDescription: "This user has not written their bio yet."
|
noAccountDescription: "This user has not written their bio yet."
|
||||||
@ -373,8 +373,6 @@ unregister: "Unregister"
|
|||||||
passwordLessLogin: "Set up password-less login"
|
passwordLessLogin: "Set up password-less login"
|
||||||
resetPassword: "Reset password"
|
resetPassword: "Reset password"
|
||||||
newPasswordIs: "The new password is \"{password}\""
|
newPasswordIs: "The new password is \"{password}\""
|
||||||
autoNoteWatch: "Watch note automatically"
|
|
||||||
autoNoteWatchDescription: "Get notified about the notes which you reactioned or replied."
|
|
||||||
reduceUiAnimation: "Reduce UI animation"
|
reduceUiAnimation: "Reduce UI animation"
|
||||||
share: "Share"
|
share: "Share"
|
||||||
notFound: "Not found"
|
notFound: "Not found"
|
||||||
@ -405,13 +403,14 @@ next: "Next"
|
|||||||
retype: "Enter again"
|
retype: "Enter again"
|
||||||
noteOf: "{user}'s notes"
|
noteOf: "{user}'s notes"
|
||||||
inviteToGroup: "Invite to group"
|
inviteToGroup: "Invite to group"
|
||||||
maxNoteTextLength: "Character limit of the note"
|
maxNoteTextLength: "Character limit of notes"
|
||||||
quoteAttached: "Quoted"
|
quoteAttached: "Quoted"
|
||||||
quoteQuestion: "Do you want to append a quote?"
|
quoteQuestion: "Do you want to append a quote?"
|
||||||
noMessagesYet: "No messages yet"
|
noMessagesYet: "No messages yet"
|
||||||
newMessageExists: "You've got a new message"
|
newMessageExists: "You've got a new message"
|
||||||
onlyOneFileCanBeAttached: "You can only attach one file to a message"
|
onlyOneFileCanBeAttached: "You can only attach one file to a message"
|
||||||
signinRequired: "Please sign in"
|
signinRequired: "Please sign in"
|
||||||
|
invitations: "Invitations"
|
||||||
invitationCode: "Invitation code"
|
invitationCode: "Invitation code"
|
||||||
checking: "Checking"
|
checking: "Checking"
|
||||||
available: "Available"
|
available: "Available"
|
||||||
@ -484,7 +483,7 @@ newNoteRecived: "You've got a new note"
|
|||||||
sounds: "Sounds"
|
sounds: "Sounds"
|
||||||
listen: "Listen"
|
listen: "Listen"
|
||||||
none: "None"
|
none: "None"
|
||||||
showInPage: "Show in Pages"
|
showInPage: "Show in page"
|
||||||
popout: "Pop-out"
|
popout: "Pop-out"
|
||||||
volume: "Volume"
|
volume: "Volume"
|
||||||
details: "Details"
|
details: "Details"
|
||||||
@ -541,6 +540,7 @@ pluginInstallWarn: "Please do not install untrustworthy plugins."
|
|||||||
deck: "Deck"
|
deck: "Deck"
|
||||||
undeck: "Leave Deck"
|
undeck: "Leave Deck"
|
||||||
useBlurEffectForModal: "Use blur effect for modals"
|
useBlurEffectForModal: "Use blur effect for modals"
|
||||||
|
useFullReactionPicker: "Use full-size reaction picker"
|
||||||
generateAccessToken: "Generate access token"
|
generateAccessToken: "Generate access token"
|
||||||
permission: "Permissions"
|
permission: "Permissions"
|
||||||
enableAll: "Enable all"
|
enableAll: "Enable all"
|
||||||
@ -593,6 +593,61 @@ fillAbuseReportDescription: "Please fill in the report details. If it is about a
|
|||||||
abuseReported: "Your report has been sent. Thank you very much."
|
abuseReported: "Your report has been sent. Thank you very much."
|
||||||
send: "Send"
|
send: "Send"
|
||||||
abuseMarkAsResolved: "Mark report as resolved"
|
abuseMarkAsResolved: "Mark report as resolved"
|
||||||
|
openInNewTab: "Open in new tab"
|
||||||
|
openInSideView: "Open in side view"
|
||||||
|
defaultNavigationBehaviour: "Default navigation behavior"
|
||||||
|
editTheseSettingsMayBreakAccount: "Editing these settings may damage your account."
|
||||||
|
instanceTicker: "Instance information of notes"
|
||||||
|
waitingFor: "Waiting for {x}"
|
||||||
|
random: "Random"
|
||||||
|
system: "System"
|
||||||
|
switchUi: "Switch UI"
|
||||||
|
desktop: "Desktop"
|
||||||
|
_mfm:
|
||||||
|
mention: "Mention"
|
||||||
|
hashtag: "Hashtag"
|
||||||
|
link: "Link"
|
||||||
|
center: "Center elements"
|
||||||
|
quote: "Quote"
|
||||||
|
emoji: "Custom Emoji"
|
||||||
|
search: "Search"
|
||||||
|
_reversi:
|
||||||
|
reversi: "Reversi"
|
||||||
|
gameSettings: "Game settings"
|
||||||
|
chooseBoard: "Choose a board"
|
||||||
|
blackOrWhite: "Black/White"
|
||||||
|
blackIs: "{name} is playing Black"
|
||||||
|
rules: "Rules"
|
||||||
|
botSettings: "Bot options"
|
||||||
|
thisGameIsStartedSoon: "The game will start in a few seconds"
|
||||||
|
waitingForOther: "Waiting for the opponent's turn"
|
||||||
|
waitingForMe: "Waiting for your turn"
|
||||||
|
waitingBoth: "Get ready"
|
||||||
|
ready: "Ready"
|
||||||
|
cancelReady: "Cancel ready"
|
||||||
|
opponentTurn: "Opponent's turn"
|
||||||
|
myTurn: "Your turn"
|
||||||
|
turnOf: "{name}'s turn"
|
||||||
|
pastTurnOf: "{name}'s turn"
|
||||||
|
surrender: "Surrender"
|
||||||
|
surrendered: "By surrender"
|
||||||
|
drawn: "Draw"
|
||||||
|
won: "{name}'s win"
|
||||||
|
black: "Black"
|
||||||
|
white: "White"
|
||||||
|
total: "Total"
|
||||||
|
turnCount: "Turn {count}"
|
||||||
|
myGames: "My rounds"
|
||||||
|
allGames: "All rounds"
|
||||||
|
ended: "Ended"
|
||||||
|
playing: "Currently playing"
|
||||||
|
isLlotheo: "The one with fewer stones wins (Llotheo)"
|
||||||
|
loopedMap: "Looped map"
|
||||||
|
canPutEverywhere: "Tiles are placeable everywhere"
|
||||||
|
_instanceTicker:
|
||||||
|
none: "Never show"
|
||||||
|
remote: "Show for remote users"
|
||||||
|
always: "Always show"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "Automatically reload"
|
reload: "Automatically reload"
|
||||||
dialog: "Show warning dialog"
|
dialog: "Show warning dialog"
|
||||||
|
@ -16,6 +16,9 @@ noNotes: "No hay notas"
|
|||||||
noNotifications: "No hay notificaciones"
|
noNotifications: "No hay notificaciones"
|
||||||
instance: "Instancia"
|
instance: "Instancia"
|
||||||
settings: "Configuración"
|
settings: "Configuración"
|
||||||
|
basicSettings: "Configuración Básica"
|
||||||
|
otherSettings: "Configuración avanzada"
|
||||||
|
openInWindow: "Abrir en una ventana"
|
||||||
profile: "Perfil"
|
profile: "Perfil"
|
||||||
timeline: "Linea de tiempo"
|
timeline: "Linea de tiempo"
|
||||||
noAccountDescription: "Este usuario no tiene una descripción"
|
noAccountDescription: "Este usuario no tiene una descripción"
|
||||||
@ -40,6 +43,7 @@ deleteAndEditConfirm: "¿Quieres borrar y editar este nota? Las reacciones, reno
|
|||||||
addToList: "Agregar a lista"
|
addToList: "Agregar a lista"
|
||||||
sendMessage: "Énviar mensaje"
|
sendMessage: "Énviar mensaje"
|
||||||
copyUsername: "Copiar nombre de usuario"
|
copyUsername: "Copiar nombre de usuario"
|
||||||
|
searchUser: "Búsqueda de usuarios"
|
||||||
reply: "Responder"
|
reply: "Responder"
|
||||||
loadMore: "Ver más"
|
loadMore: "Ver más"
|
||||||
youGotNewFollower: "te ha seguido"
|
youGotNewFollower: "te ha seguido"
|
||||||
@ -66,7 +70,11 @@ followers: "Seguidores"
|
|||||||
followsYou: "Te sigue"
|
followsYou: "Te sigue"
|
||||||
createList: "Crear lista"
|
createList: "Crear lista"
|
||||||
manageLists: "Administrar listas"
|
manageLists: "Administrar listas"
|
||||||
|
error: "Error"
|
||||||
|
somethingHappened: "Ocurrió un error"
|
||||||
retry: "Reintentar"
|
retry: "Reintentar"
|
||||||
|
pageLoadError: "Error al leer la página"
|
||||||
|
pageLoadErrorDescription: "Normalmente es debido a la red o al caché del navegador. Por favor limpie el caché o intente más tarde."
|
||||||
enterListName: "Ingrese nombre de lista"
|
enterListName: "Ingrese nombre de lista"
|
||||||
privacy: "Privacidad"
|
privacy: "Privacidad"
|
||||||
makeFollowManuallyApprove: "Aprobar manualmente las solicitudes de seguimiento"
|
makeFollowManuallyApprove: "Aprobar manualmente las solicitudes de seguimiento"
|
||||||
@ -105,6 +113,8 @@ unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?"
|
|||||||
selectList: "Seleccione una lista"
|
selectList: "Seleccione una lista"
|
||||||
selectAntenna: "Seleccionar antena"
|
selectAntenna: "Seleccionar antena"
|
||||||
selectWidget: "Seleccionar widget"
|
selectWidget: "Seleccionar widget"
|
||||||
|
editWidgets: "Editar widgets"
|
||||||
|
editWidgetsExit: "Terminar edición"
|
||||||
customEmojis: "Emojis personalizados"
|
customEmojis: "Emojis personalizados"
|
||||||
emoji: "Emoji"
|
emoji: "Emoji"
|
||||||
emojiName: "Nombre del emoji"
|
emojiName: "Nombre del emoji"
|
||||||
@ -363,8 +373,6 @@ unregister: "Cancelar registro"
|
|||||||
passwordLessLogin: "Iniciar sesión sin contraseña"
|
passwordLessLogin: "Iniciar sesión sin contraseña"
|
||||||
resetPassword: "Resetear contraseña"
|
resetPassword: "Resetear contraseña"
|
||||||
newPasswordIs: "La nueva contraseña es \"{password}\""
|
newPasswordIs: "La nueva contraseña es \"{password}\""
|
||||||
autoNoteWatch: "Ver nota automáticamente"
|
|
||||||
autoNoteWatchDescription: "Recibe notificaciones sobre las notas de otros usuarios que a los que respondiste y reaccionaste"
|
|
||||||
reduceUiAnimation: "Reducir la animación de la UI"
|
reduceUiAnimation: "Reducir la animación de la UI"
|
||||||
share: "Compartir"
|
share: "Compartir"
|
||||||
notFound: "No se encuentra"
|
notFound: "No se encuentra"
|
||||||
@ -402,6 +410,7 @@ noMessagesYet: "Aún no hay chat"
|
|||||||
newMessageExists: "Tienes un mensaje nuevo"
|
newMessageExists: "Tienes un mensaje nuevo"
|
||||||
onlyOneFileCanBeAttached: "Solo se puede añadir un archivo al mensaje"
|
onlyOneFileCanBeAttached: "Solo se puede añadir un archivo al mensaje"
|
||||||
signinRequired: "Iniciar sesión"
|
signinRequired: "Iniciar sesión"
|
||||||
|
invitations: "Invitar"
|
||||||
invitationCode: "Código de invitación"
|
invitationCode: "Código de invitación"
|
||||||
checking: "Comprobando"
|
checking: "Comprobando"
|
||||||
available: "Disponible"
|
available: "Disponible"
|
||||||
@ -443,6 +452,7 @@ total: "Total"
|
|||||||
weekOverWeekChanges: "Dif semanal"
|
weekOverWeekChanges: "Dif semanal"
|
||||||
dayOverDayChanges: "Dif diaria"
|
dayOverDayChanges: "Dif diaria"
|
||||||
appearance: "Apariencia"
|
appearance: "Apariencia"
|
||||||
|
clientSettings: "Configuración del cliente"
|
||||||
accountSettings: "Ajustes de cuenta"
|
accountSettings: "Ajustes de cuenta"
|
||||||
promotion: "Promovido"
|
promotion: "Promovido"
|
||||||
promote: "Promover"
|
promote: "Promover"
|
||||||
@ -473,6 +483,8 @@ newNoteRecived: "Tienes una nota nuevo"
|
|||||||
sounds: "Sonidos"
|
sounds: "Sonidos"
|
||||||
listen: "Escuchar"
|
listen: "Escuchar"
|
||||||
none: "Ninguna"
|
none: "Ninguna"
|
||||||
|
showInPage: "Mostrar en la página"
|
||||||
|
popout: "Popout"
|
||||||
volume: "Volumen"
|
volume: "Volumen"
|
||||||
details: "Detalles"
|
details: "Detalles"
|
||||||
chooseEmoji: "Elije un emoji"
|
chooseEmoji: "Elije un emoji"
|
||||||
@ -566,6 +578,75 @@ notificationSetting: "Ajustes de Notificaciones"
|
|||||||
notificationSettingDesc: "Por favor elija el tipo de notificación a mostrar"
|
notificationSettingDesc: "Por favor elija el tipo de notificación a mostrar"
|
||||||
useGlobalSetting: "Usar ajustes globales"
|
useGlobalSetting: "Usar ajustes globales"
|
||||||
useGlobalSettingDesc: "Al activarse, se usará la configuración de notificaciones de la cuenta, al desactivarse se pueden hacer configuraciones particulares."
|
useGlobalSettingDesc: "Al activarse, se usará la configuración de notificaciones de la cuenta, al desactivarse se pueden hacer configuraciones particulares."
|
||||||
|
other: "Otro"
|
||||||
|
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"
|
||||||
|
sample: "Muestra"
|
||||||
|
abuseReports: "Reportes"
|
||||||
|
reportAbuse: "Reportar"
|
||||||
|
reportAbuseOf: "Reportar a {name}"
|
||||||
|
fillAbuseReportDescription: "Ingrese los detalles del reporte. Si hay una nota en particular, ingrese la URL de esta."
|
||||||
|
abuseReported: "Se ha enviado el reporte. Muchas gracias."
|
||||||
|
send: "Enviar"
|
||||||
|
abuseMarkAsResolved: "Marcar reporte como resuelto"
|
||||||
|
openInNewTab: "Abrir en una Nueva Pestaña"
|
||||||
|
openInSideView: "Abrir en una vista al costado"
|
||||||
|
defaultNavigationBehaviour: "Navegación por defecto"
|
||||||
|
editTheseSettingsMayBreakAccount: "Editar estas configuraciones puede dañar su cuenta."
|
||||||
|
instanceTicker: "Información de notas de la instancia"
|
||||||
|
waitingFor: "Esperando a {x}"
|
||||||
|
random: "Aleatorio"
|
||||||
|
system: "Sistema"
|
||||||
|
switchUi: "Cambiar interfaz de usuario"
|
||||||
|
desktop: "Escritorio"
|
||||||
|
_mfm:
|
||||||
|
mention: "Menciones"
|
||||||
|
hashtag: "Hashtag"
|
||||||
|
link: "Vínculo"
|
||||||
|
center: "Centrar"
|
||||||
|
quote: "Citar"
|
||||||
|
emoji: "Emojis personalizados"
|
||||||
|
search: "Buscar"
|
||||||
|
_reversi:
|
||||||
|
reversi: "Reversi"
|
||||||
|
gameSettings: "Configuración del juego"
|
||||||
|
chooseBoard: "Elegir tablero"
|
||||||
|
blackOrWhite: "Blancas/Negras"
|
||||||
|
blackIs: "{name} juega con fichas negras"
|
||||||
|
rules: "Reglas"
|
||||||
|
botSettings: "Opciones del bot"
|
||||||
|
thisGameIsStartedSoon: "El juego empezará en segundos"
|
||||||
|
waitingForOther: "Esperando el turno del adversario"
|
||||||
|
waitingForMe: "Esperando mi turno"
|
||||||
|
waitingBoth: "Prepárate"
|
||||||
|
ready: "Listo"
|
||||||
|
cancelReady: "No estoy listo"
|
||||||
|
opponentTurn: "Turno del adversario"
|
||||||
|
myTurn: "Mi turno"
|
||||||
|
turnOf: "Turno de {name}"
|
||||||
|
pastTurnOf: "Turno de {name}"
|
||||||
|
surrender: "Rendirse"
|
||||||
|
surrendered: "Por rendirse"
|
||||||
|
drawn: "Empate"
|
||||||
|
won: "{name} ha ganado"
|
||||||
|
black: "Negro"
|
||||||
|
white: "Blanco"
|
||||||
|
total: "Total"
|
||||||
|
turnCount: "Turno {count}"
|
||||||
|
myGames: "Mis juegos"
|
||||||
|
allGames: "Todos los juegos"
|
||||||
|
ended: "Finalizado"
|
||||||
|
playing: "Jugando"
|
||||||
|
isLlotheo: "El que tenga menos fichas gana (LLoTheO)"
|
||||||
|
loopedMap: "Mapa en bucle"
|
||||||
|
canPutEverywhere: "Puedes colocar donde quieras"
|
||||||
|
_instanceTicker:
|
||||||
|
none: "No mostrar"
|
||||||
|
remote: "Mostrar a usuarios remotos"
|
||||||
|
always: "Mostrar siempre"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "Recargar automáticamente"
|
reload: "Recargar automáticamente"
|
||||||
dialog: "Mostrar diálogo de advertencia"
|
dialog: "Mostrar diálogo de advertencia"
|
||||||
|
@ -372,8 +372,6 @@ unregister: "Se désinscrire"
|
|||||||
passwordLessLogin: "Connectez-vous sans mot de passe"
|
passwordLessLogin: "Connectez-vous sans mot de passe"
|
||||||
resetPassword: "Réinitialiser mot de passe"
|
resetPassword: "Réinitialiser mot de passe"
|
||||||
newPasswordIs: "Votre nouveau mot de passe est \"{password}\""
|
newPasswordIs: "Votre nouveau mot de passe est \"{password}\""
|
||||||
autoNoteWatch: "Surveiller les notes automatiquement"
|
|
||||||
autoNoteWatchDescription: "Soyez informé des notes auxquelles vous avez réagi ou répondu."
|
|
||||||
reduceUiAnimation: "Réduire les animations dans l’interface"
|
reduceUiAnimation: "Réduire les animations dans l’interface"
|
||||||
share: "Partager"
|
share: "Partager"
|
||||||
notFound: "Non trouvé"
|
notFound: "Non trouvé"
|
||||||
@ -411,6 +409,7 @@ noMessagesYet: "Pas encore discuté"
|
|||||||
newMessageExists: "Vous avez un nouveau message"
|
newMessageExists: "Vous avez un nouveau message"
|
||||||
onlyOneFileCanBeAttached: "Vous ne pouvez joindre qu’un seul fichier au message"
|
onlyOneFileCanBeAttached: "Vous ne pouvez joindre qu’un seul fichier au message"
|
||||||
signinRequired: "Veuillez vous connecter"
|
signinRequired: "Veuillez vous connecter"
|
||||||
|
invitations: "Inviter"
|
||||||
invitationCode: "Code d’invitation"
|
invitationCode: "Code d’invitation"
|
||||||
checking: "Vérification"
|
checking: "Vérification"
|
||||||
available: "Disponible"
|
available: "Disponible"
|
||||||
@ -580,6 +579,17 @@ regenerateLoginToken: "Régénérer le jeton de connexion"
|
|||||||
setMultipleBySeparatingWithSpace: "Vous pouvez définir plus d’un, séparés par des espaces."
|
setMultipleBySeparatingWithSpace: "Vous pouvez définir plus d’un, séparés par des espaces."
|
||||||
fileIdOrUrl: "ID du fichier ou URL"
|
fileIdOrUrl: "ID du fichier ou URL"
|
||||||
chatOpenBehavior: "Comportement de la fenêtre de discussion lors de son ouverture"
|
chatOpenBehavior: "Comportement de la fenêtre de discussion lors de son ouverture"
|
||||||
|
random: "Aléatoire"
|
||||||
|
_mfm:
|
||||||
|
mention: "Mentionner"
|
||||||
|
hashtag: "Hashtags"
|
||||||
|
link: "Lien"
|
||||||
|
center: "Centrée"
|
||||||
|
quote: "Citer"
|
||||||
|
emoji: "Émojis personnalisés"
|
||||||
|
search: "Rechercher"
|
||||||
|
_reversi:
|
||||||
|
total: "Total"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "Rechargement automatique"
|
reload: "Rechargement automatique"
|
||||||
_channel:
|
_channel:
|
||||||
|
@ -15,17 +15,24 @@ const merge = (...args) => args.reduce((a, c) => ({
|
|||||||
|
|
||||||
const languages = [
|
const languages = [
|
||||||
'ar-SA',
|
'ar-SA',
|
||||||
//'cs-CZ',
|
'cs-CZ',
|
||||||
//'da-DK',
|
'da-DK',
|
||||||
'de-DE',
|
'de-DE',
|
||||||
'en-US',
|
'en-US',
|
||||||
'es-ES',
|
'es-ES',
|
||||||
'fr-FR',
|
'fr-FR',
|
||||||
'ja-JP',
|
'ja-JP',
|
||||||
'ja-KS',
|
'ja-KS',
|
||||||
|
'kab-KAB',
|
||||||
|
'kn-IN',
|
||||||
'ko-KR',
|
'ko-KR',
|
||||||
//'nl-NL',
|
'nl-NL',
|
||||||
//'pl-PL',
|
'no-NO',
|
||||||
|
'pl-PL',
|
||||||
|
'pt-PT',
|
||||||
|
'ru-RU',
|
||||||
|
'ug-CN',
|
||||||
|
'uk-UA',
|
||||||
'zh-CN',
|
'zh-CN',
|
||||||
'zh-TW',
|
'zh-TW',
|
||||||
];
|
];
|
||||||
|
@ -373,8 +373,6 @@ unregister: "登録を解除"
|
|||||||
passwordLessLogin: "パスワード無しログイン"
|
passwordLessLogin: "パスワード無しログイン"
|
||||||
resetPassword: "パスワードをリセット"
|
resetPassword: "パスワードをリセット"
|
||||||
newPasswordIs: "新しいパスワードは「{password}」です"
|
newPasswordIs: "新しいパスワードは「{password}」です"
|
||||||
autoNoteWatch: "ノートの自動ウォッチ"
|
|
||||||
autoNoteWatchDescription: "あなたがリアクションしたり返信したりした他のユーザーのノートに関する通知を受け取るようにします。"
|
|
||||||
reduceUiAnimation: "UIのアニメーションを減らす"
|
reduceUiAnimation: "UIのアニメーションを減らす"
|
||||||
share: "共有"
|
share: "共有"
|
||||||
notFound: "見つかりません"
|
notFound: "見つかりません"
|
||||||
@ -412,6 +410,7 @@ noMessagesYet: "まだチャットはありません"
|
|||||||
newMessageExists: "新しいメッセージがあります"
|
newMessageExists: "新しいメッセージがあります"
|
||||||
onlyOneFileCanBeAttached: "メッセージに添付できるファイルはひとつです"
|
onlyOneFileCanBeAttached: "メッセージに添付できるファイルはひとつです"
|
||||||
signinRequired: "ログインしてください"
|
signinRequired: "ログインしてください"
|
||||||
|
invitations: "招待"
|
||||||
invitationCode: "招待コード"
|
invitationCode: "招待コード"
|
||||||
checking: "確認しています"
|
checking: "確認しています"
|
||||||
available: "利用できます"
|
available: "利用できます"
|
||||||
@ -541,6 +540,7 @@ pluginInstallWarn: "信頼できないプラグインはインストールしな
|
|||||||
deck: "デッキ"
|
deck: "デッキ"
|
||||||
undeck: "デッキ解除"
|
undeck: "デッキ解除"
|
||||||
useBlurEffectForModal: "モーダルにぼかし効果を使用"
|
useBlurEffectForModal: "モーダルにぼかし効果を使用"
|
||||||
|
useFullReactionPicker: "フル機能リアクションピッカーを使用"
|
||||||
generateAccessToken: "アクセストークンの発行"
|
generateAccessToken: "アクセストークンの発行"
|
||||||
permission: "権限"
|
permission: "権限"
|
||||||
enableAll: "全て有効にする"
|
enableAll: "全て有効にする"
|
||||||
@ -593,6 +593,104 @@ fillAbuseReportDescription: "通報理由の詳細を記入してください。
|
|||||||
abuseReported: "内容が送信されました。ご報告ありがとうございました。"
|
abuseReported: "内容が送信されました。ご報告ありがとうございました。"
|
||||||
send: "送信"
|
send: "送信"
|
||||||
abuseMarkAsResolved: "対応済みにする"
|
abuseMarkAsResolved: "対応済みにする"
|
||||||
|
openInNewTab: "新しいタブで開く"
|
||||||
|
openInSideView: "サイドビューで開く"
|
||||||
|
defaultNavigationBehaviour: "デフォルトのナビゲーション"
|
||||||
|
editTheseSettingsMayBreakAccount: "これらの設定を編集するとアカウントが破損する可能性があります。"
|
||||||
|
instanceTicker: "ノートのインスタンス情報"
|
||||||
|
waitingFor: "{x}を待っています"
|
||||||
|
random: "ランダム"
|
||||||
|
system: "システム"
|
||||||
|
switchUi: "UI切り替え"
|
||||||
|
desktop: "デスクトップ"
|
||||||
|
|
||||||
|
_mfm:
|
||||||
|
cheatSheet: "MFMチートシート"
|
||||||
|
intro: "MFMは、Misskey内の様々な場所で使用できる専用のマークアップ言語です。ここでは、MFMで使用可能な構文一覧が確認できます。"
|
||||||
|
dummy: "MisskeyでFediverseの世界が広がります"
|
||||||
|
mention: "メンション"
|
||||||
|
mentionDescription: "アットマーク + ユーザー名で、特定のユーザーを示すことができます。"
|
||||||
|
hashtag: "ハッシュタグ"
|
||||||
|
hashtagDescription: "ナンバーサイン + タグで、ハッシュタグを示すことができます。"
|
||||||
|
url: "URL"
|
||||||
|
urlDescription: "URLを示すことができます。"
|
||||||
|
link: "リンク"
|
||||||
|
linkDescription: "文章の特定の範囲を、URLに紐づけることができます。"
|
||||||
|
bold: "太字"
|
||||||
|
boldDescription: "文字を太く表示して強調することができます。"
|
||||||
|
small: "目立たなく"
|
||||||
|
smallDescription: "内容を小さく・薄く表示させることができます。"
|
||||||
|
center: "中央寄せ"
|
||||||
|
centerDescription: "内容を中央寄せで表示させることができます。"
|
||||||
|
inlineCode: "コード(インライン)"
|
||||||
|
inlineCodeDescription: "プログラムなどのコードをインラインでシンタックスハイライトします。"
|
||||||
|
blockCode: "コード(ブロック)"
|
||||||
|
blockCodeDescription: "複数行のプログラムなどのコードをブロックでシンタックスハイライトします。"
|
||||||
|
inlineMath: "数式(インライン)"
|
||||||
|
inlineMathDescription: "数式(KaTeX)をインラインで表示します。"
|
||||||
|
blockMath: "数式(ブロック)"
|
||||||
|
blockMathDescription: "複数行の数式(KaTeX)をブロックで表示します。"
|
||||||
|
quote: "引用"
|
||||||
|
quoteDescription: "内容が引用であることを示すことができます。"
|
||||||
|
emoji: "カスタム絵文字"
|
||||||
|
emojiDescription: "コロンでカスタム絵文字名を囲むと、カスタム絵文字を表示させることができます。"
|
||||||
|
search: "検索"
|
||||||
|
searchDescription: "入力済み検索ボックスを表示させることができます。"
|
||||||
|
flip: "反転"
|
||||||
|
flipDescription: "内容を上下または左右に反転させます。"
|
||||||
|
jelly: "アニメーション(びよんびよん)"
|
||||||
|
jellyDescription: "びよんびよんするアニメーションを与えます。"
|
||||||
|
tada: "アニメーション(じゃーん)"
|
||||||
|
tadaDescription: "ジャーン!という感じのアニメーションを与えます。"
|
||||||
|
jump: "アニメーション(ジャンプ)"
|
||||||
|
jumpDescription: "飛び跳ねるようなアニメーションを与えます。"
|
||||||
|
bounce: "アニメーション(バウンド)"
|
||||||
|
bounceDescription: "ぽよんぽよん弾むようなアニメーションを与えます。"
|
||||||
|
shake: "アニメーション(ぶるぶる)"
|
||||||
|
shakeDescription: "ぶるぶるするアニメーションを与えます。"
|
||||||
|
twitch: "アニメーション(ブレ)"
|
||||||
|
twitchDescription: "激しくブレるアニメーションを与えます。"
|
||||||
|
spin: "アニメーション(回転)"
|
||||||
|
spinDescription: "回転するアニメーションを与えます。"
|
||||||
|
|
||||||
|
_reversi:
|
||||||
|
reversi: "リバーシ"
|
||||||
|
gameSettings: "対局の設定"
|
||||||
|
chooseBoard: "ボードを選択"
|
||||||
|
blackOrWhite: "先行/後攻"
|
||||||
|
blackIs: "{name}が黒(先行)"
|
||||||
|
rules: "ルール"
|
||||||
|
botSettings: "Botのオプション"
|
||||||
|
thisGameIsStartedSoon: "対局は数秒後に開始されます"
|
||||||
|
waitingForOther: "相手の準備が完了するのを待っています"
|
||||||
|
waitingForMe: "あなたの準備が完了するのを待っています"
|
||||||
|
waitingBoth: "準備してください"
|
||||||
|
ready: "準備完了"
|
||||||
|
cancelReady: "準備を再開"
|
||||||
|
opponentTurn: "相手のターンです"
|
||||||
|
myTurn: "あなたのターンです"
|
||||||
|
turnOf: "{name}のターンです"
|
||||||
|
pastTurnOf: "{name}のターン"
|
||||||
|
surrender: "投了"
|
||||||
|
surrendered: "投了により"
|
||||||
|
drawn: "引き分け"
|
||||||
|
won: "{name}の勝ち"
|
||||||
|
black: "黒"
|
||||||
|
white: "白"
|
||||||
|
total: "合計"
|
||||||
|
turnCount: "{count}ターン目"
|
||||||
|
myGames: "自分の対局"
|
||||||
|
allGames: "みんなの対局"
|
||||||
|
ended: "終了"
|
||||||
|
playing: "対局中"
|
||||||
|
isLlotheo: "石の少ない方が勝ち(ロセオ)"
|
||||||
|
loopedMap: "ループマップ"
|
||||||
|
canPutEverywhere: "どこでも置けるモード"
|
||||||
|
|
||||||
|
_instanceTicker:
|
||||||
|
none: "表示しない"
|
||||||
|
remote: "リモートユーザーに表示"
|
||||||
|
always: "常に表示"
|
||||||
|
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "自動でリロード"
|
reload: "自動でリロード"
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
---
|
---
|
||||||
_lang_: "日本語 (関西弁)"
|
_lang_: "日本語 (関西弁)"
|
||||||
introMisskey: "ようこそ!Misskeyは、オープンソースの分散型マイクロブログサービスやねん。\n「ノート」を作成しぃ、いま起こっとることを共有したり、あんたについて皆に発信しよう📡\n「リアクション」機能で、皆のノートに素はよ反応を追加することもできます✌\n新しい世界を探検しよう🚀"
|
introMisskey: "ようこそ!Misskeyってのは、オープンソースの分散型マイクロブログサービスやねん。\n「ノート」を作成し、いま起こっとることを共有したり、あんたんこととか皆に伝えていこう📡\n「リアクション」機能で、皆のノートに素はよ反応を追加することもできるんやで✌\n新しい世界を探検してみらん?🚀"
|
||||||
monthAndDay: "{month}月 {day}日"
|
monthAndDay: "{month}月 {day}日"
|
||||||
search: "探す"
|
search: "探す"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
username: "ユーザー名"
|
username: "ユーザー名"
|
||||||
password: "パスワード"
|
password: "パスワード"
|
||||||
fetchingAsApObject: "連合に照会中"
|
fetchingAsApObject: "今ちと連合に照会しとるで"
|
||||||
ok: "おっけー"
|
ok: "おっけー"
|
||||||
gotIt: "ほい"
|
gotIt: "ほい"
|
||||||
cancel: "やめとくわ"
|
cancel: "やめとくわ"
|
||||||
@ -16,35 +16,40 @@ noNotes: "ノートはあらへん"
|
|||||||
noNotifications: "通知はあらへん"
|
noNotifications: "通知はあらへん"
|
||||||
instance: "インスタンス"
|
instance: "インスタンス"
|
||||||
settings: "設定"
|
settings: "設定"
|
||||||
|
basicSettings: "基本設定"
|
||||||
|
otherSettings: "その他の設定"
|
||||||
|
openInWindow: "ウィンドウで開いてや"
|
||||||
profile: "プロフィール"
|
profile: "プロフィール"
|
||||||
timeline: "タイムライン"
|
timeline: "タイムライン"
|
||||||
noAccountDescription: "自己紹介はあらへん"
|
noAccountDescription: "自己紹介はあらへん"
|
||||||
login: "ログイン"
|
login: "ログイン"
|
||||||
loggingIn: "ログインしとります"
|
loggingIn: "ログインしよるで"
|
||||||
logout: "ログアウト"
|
logout: "ログアウト"
|
||||||
signup: "新規登録"
|
signup: "新規登録"
|
||||||
uploading: "アップロードしとります"
|
uploading: "アップロードしよるで"
|
||||||
save: "保存"
|
save: "とっとく"
|
||||||
users: "ユーザー"
|
users: "ユーザー"
|
||||||
addUser: "ユーザー増やす"
|
addUser: "ユーザーを追加や"
|
||||||
favorite: "お気に入り"
|
favorite: "お気に入り"
|
||||||
favorites: "お気に入り"
|
favorites: "お気に入り"
|
||||||
unfavorite: "お気に入りやめる"
|
unfavorite: "やっぱ気に入らん"
|
||||||
pin: "ピン留め"
|
pin: "ピン留めしとく"
|
||||||
unpin: "ピン留めやめる"
|
unpin: "やっぱピン留めせん"
|
||||||
copyContent: "内容をコピー"
|
copyContent: "内容をコピー"
|
||||||
copyLink: "リンクをコピー"
|
copyLink: "リンクをコピー"
|
||||||
delete: "ほかす"
|
delete: "ほかす"
|
||||||
deleteAndEdit: "ほかして直す"
|
deleteAndEdit: "ほかして直す"
|
||||||
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Remote、返信も全部消えんで"
|
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Renote、返信も全部消えるんやけどそれでもええん?"
|
||||||
addToList: "リストに入れたる"
|
addToList: "リストに入れたる"
|
||||||
sendMessage: "メッセージを送る"
|
sendMessage: "メッセージを送る"
|
||||||
copyUsername: "ユーザー名をコピー"
|
copyUsername: "ユーザー名をコピー"
|
||||||
|
searchUser: "ユーザーを検索"
|
||||||
reply: "返す"
|
reply: "返す"
|
||||||
loadMore: "もっとあるやろ!"
|
loadMore: "もっとあるやろ!"
|
||||||
youGotNewFollower: "フォローされたで"
|
youGotNewFollower: "フォローされたで"
|
||||||
receiveFollowRequest: "フォローリクエストされたで"
|
receiveFollowRequest: "フォローリクエストされたで"
|
||||||
followRequestAccepted: "フォローが承認されたで"
|
followRequestAccepted: "フォローが承認されたで"
|
||||||
|
mention: "メンション"
|
||||||
mentions: "あんた宛て"
|
mentions: "あんた宛て"
|
||||||
directNotes: "ダイレクト投稿"
|
directNotes: "ダイレクト投稿"
|
||||||
importAndExport: "インポートとエクスポート"
|
importAndExport: "インポートとエクスポート"
|
||||||
@ -57,7 +62,7 @@ unfollowConfirm: "{name}のフォローを解除してもええんか?"
|
|||||||
exportRequested: "エクスポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。エクスポート終わったら「ドライブ」に突っ込んどくで。"
|
exportRequested: "エクスポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。エクスポート終わったら「ドライブ」に突っ込んどくで。"
|
||||||
importRequested: "インポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。"
|
importRequested: "インポートしてな、ってリクエストしたけど、これ多分めっちゃ時間かかるで。"
|
||||||
lists: "リスト"
|
lists: "リスト"
|
||||||
noLists: "リストはあらへん"
|
noLists: "リストなんてあらへんで"
|
||||||
note: "ノート"
|
note: "ノート"
|
||||||
notes: "ノート"
|
notes: "ノート"
|
||||||
following: "フォロー"
|
following: "フォロー"
|
||||||
@ -65,31 +70,35 @@ followers: "フォロワー"
|
|||||||
followsYou: "フォローされとるで"
|
followsYou: "フォローされとるで"
|
||||||
createList: "リスト作る"
|
createList: "リスト作る"
|
||||||
manageLists: "リストの管理"
|
manageLists: "リストの管理"
|
||||||
retry: "もっぺんやってみる"
|
error: "エラー"
|
||||||
|
somethingHappened: "なんかアカンことが起こったで"
|
||||||
|
retry: "もっぺんやる?"
|
||||||
|
pageLoadError: "ページの読み込みに失敗してしもうたで…"
|
||||||
|
pageLoadErrorDescription: "これは普通、ネットワークかブラウザキャッシュが原因やからね。キャッシュをクリアするか、もうちっとだけ待ってくれへんか?"
|
||||||
enterListName: "リスト名を入れてや"
|
enterListName: "リスト名を入れてや"
|
||||||
privacy: "プライバシーってなんや?オカンの年齢か?"
|
privacy: "プライバシーってなんぞや?"
|
||||||
makeFollowManuallyApprove: "他人のフォローは許可してからや!"
|
makeFollowManuallyApprove: "他人からのフォローは自分が決める"
|
||||||
defaultNoteVisibility: "もとからの公開範囲"
|
defaultNoteVisibility: "もとからの公開範囲"
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
followRequest: "フォロー許してくれや!言うてみる"
|
followRequest: "フォローを頼む"
|
||||||
followRequests: "フォロー許してくれや!"
|
followRequests: "フォローを頼む"
|
||||||
unfollow: "フォローやめる"
|
unfollow: "フォローやめる"
|
||||||
followRequestPending: "フォロー許してくれるん待っとる"
|
followRequestPending: "フォロー許してくれるん待っとる"
|
||||||
enterEmoji: "絵文字を入れてや"
|
enterEmoji: "絵文字を入れてや"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
unrenote: "Renoteやめる"
|
unrenote: "Renoteやめる"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
pinnedNote: "ピン留めされたノート"
|
pinnedNote: "ピン留めされとるノート"
|
||||||
you: "あんた"
|
you: "あんた"
|
||||||
clickToShow: "押してみ、見せたるわ"
|
clickToShow: "押したら見えるようになるで"
|
||||||
sensitive: "見たらあかんで"
|
sensitive: "ちょっとアカンやつやで"
|
||||||
add: "増やす"
|
add: "増やす"
|
||||||
reaction: "リアクション"
|
reaction: "リアクション"
|
||||||
reactionSettingDescription: "リアクションピッカーに出しとくリアクションを選んでや。"
|
reactionSettingDescription: "リアクションピッカーに出しとくリアクションを選んでや。"
|
||||||
rememberNoteVisibility: "公開範囲覚えといて"
|
rememberNoteVisibility: "公開範囲覚えといて"
|
||||||
attachCancel: "くっつけるのやめよか"
|
attachCancel: "やっぱ添付やめてくれん?"
|
||||||
markAsSensitive: "ちょっと見せられへんわ"
|
markAsSensitive: "ちょっとこれはアカン"
|
||||||
unmarkAsSensitive: "別にええんじゃね?"
|
unmarkAsSensitive: "そこまでアカンことないやろ"
|
||||||
enterFileName: "ファイル名を入れてや"
|
enterFileName: "ファイル名を入れてや"
|
||||||
mute: "ミュート"
|
mute: "ミュート"
|
||||||
unmute: "ミュートやめたる"
|
unmute: "ミュートやめたる"
|
||||||
@ -97,30 +106,35 @@ block: "ブロック"
|
|||||||
unblock: "ブロックやめたる"
|
unblock: "ブロックやめたる"
|
||||||
suspend: "凍結"
|
suspend: "凍結"
|
||||||
unsuspend: "溶かす"
|
unsuspend: "溶かす"
|
||||||
blockConfirm: "ブロックしてしもうてええか?"
|
blockConfirm: "ブロックしてもええんか?"
|
||||||
unblockConfirm: "ブロックすんのやめるけどええか?"
|
unblockConfirm: "ブロックやめたるってほんまか?"
|
||||||
suspendConfirm: "凍結してしもうてええか?"
|
suspendConfirm: "凍結してしもうてええか?"
|
||||||
unsuspendConfirm: "解凍するけどええか?"
|
unsuspendConfirm: "解凍するけどええか?"
|
||||||
selectList: "リストを選ぶ"
|
selectList: "リストを選ぶ"
|
||||||
|
selectAntenna: "アンテナを選ぶ"
|
||||||
|
selectWidget: "ウィジェットを選ぶ"
|
||||||
|
editWidgets: "ウィジェットをいじる"
|
||||||
|
editWidgetsExit: "編集終ったで"
|
||||||
customEmojis: "カスタム絵文字"
|
customEmojis: "カスタム絵文字"
|
||||||
|
emoji: "絵文字"
|
||||||
emojiName: "絵文字名"
|
emojiName: "絵文字名"
|
||||||
emojiUrl: "絵文字画像URL"
|
emojiUrl: "絵文字画像URL"
|
||||||
addEmoji: "絵文字を追加"
|
addEmoji: "絵文字を追加"
|
||||||
settingGuide: "ええ感じの設定"
|
settingGuide: "ええ感じの設定"
|
||||||
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
cacheRemoteFiles: "リモートのファイルをキャッシュする"
|
||||||
cacheRemoteFilesDescription: "この設定をチャラにすると、リモートファイルをキャッシュせず直リンクするようになります。サーバーのストレージを節約できますが、サムネイルが生成されへんので通信量が増加します。"
|
cacheRemoteFilesDescription: "この設定を切っとくと、リモートファイルをキャッシュせず直リンクするようになってしまうんやで? サーバーのストレージは節約できるんやけど、かわりにサムネイルが作られんくなるから通信量が増えるで?"
|
||||||
flagAsBot: "Botやでと言っとく"
|
flagAsBot: "Botやで"
|
||||||
flagAsCat: "Catやでと言っとく"
|
flagAsCat: "Catやで"
|
||||||
autoAcceptFollowed: "フォローしとるユーザーからのフォロリクは全部勝手にええでって言うで"
|
autoAcceptFollowed: "フォローしとるユーザーからのフォローリクエストには勝手に許可しとくで。"
|
||||||
addAcount: "アカウント追加"
|
addAcount: "アカウント追加"
|
||||||
loginFailed: "ログインに失敗してん"
|
loginFailed: "ログインに失敗してしもうた…"
|
||||||
showOnRemote: "リモートで見る"
|
showOnRemote: "リモートで見る"
|
||||||
general: "全般"
|
general: "全般"
|
||||||
wallpaper: "壁紙"
|
wallpaper: "壁紙"
|
||||||
setWallpaper: "壁紙を設定"
|
setWallpaper: "壁紙を設定"
|
||||||
removeWallpaper: "壁紙ほかす"
|
removeWallpaper: "壁紙を削除"
|
||||||
searchWith: "検索: {q}"
|
searchWith: "検索: {q}"
|
||||||
youHaveNoLists: "リストはあらへん"
|
youHaveNoLists: "リストがあらへんで?"
|
||||||
followConfirm: "{name}をフォローしてええか?"
|
followConfirm: "{name}をフォローしてええか?"
|
||||||
proxyAccount: "プロキシアカウント"
|
proxyAccount: "プロキシアカウント"
|
||||||
proxyAccountDescription: "プロキシアカウントは、代わりにフォローしてくれるアカウントや。例えば、551に豚まんが無いときやったり、ユーザーがリモートユーザーをアカウントに入れたとき、リストに入れられたユーザーが誰からもフォローされてないと寂しいやん。寂しいし、アクティビティも配達されへんから、プロキシアカウントがフォローしてくれるで。ええやつやん…"
|
proxyAccountDescription: "プロキシアカウントは、代わりにフォローしてくれるアカウントや。例えば、551に豚まんが無いときやったり、ユーザーがリモートユーザーをアカウントに入れたとき、リストに入れられたユーザーが誰からもフォローされてないと寂しいやん。寂しいし、アクティビティも配達されへんから、プロキシアカウントがフォローしてくれるで。ええやつやん…"
|
||||||
@ -130,7 +144,7 @@ recipient: "宛先"
|
|||||||
annotation: "注釈"
|
annotation: "注釈"
|
||||||
federation: "連合"
|
federation: "連合"
|
||||||
instances: "インスタンス"
|
instances: "インスタンス"
|
||||||
registeredAt: "一見さんになった日"
|
registeredAt: "初観測"
|
||||||
latestRequestSentAt: "ちょっと前のリクエスト送信"
|
latestRequestSentAt: "ちょっと前のリクエスト送信"
|
||||||
latestRequestReceivedAt: "ちょっと前のリクエスト受信"
|
latestRequestReceivedAt: "ちょっと前のリクエスト受信"
|
||||||
latestStatus: "ちょっと前のステータス"
|
latestStatus: "ちょっと前のステータス"
|
||||||
@ -257,7 +271,8 @@ copyUrl: "URLをコピー"
|
|||||||
rename: "名前を変えるで"
|
rename: "名前を変えるで"
|
||||||
avatar: "アイコン"
|
avatar: "アイコン"
|
||||||
banner: "バナー"
|
banner: "バナー"
|
||||||
nsfw: "見たらあかんで"
|
nsfw: "ちょっとアカンやつやで"
|
||||||
|
whenServerDisconnected: "サーバーとの接続が失くなってしもうたとき"
|
||||||
disconnectedFromServer: "サーバーが機嫌悪いねん"
|
disconnectedFromServer: "サーバーが機嫌悪いねん"
|
||||||
reload: "リロード"
|
reload: "リロード"
|
||||||
doNothing: "何もせんとく"
|
doNothing: "何もせんとく"
|
||||||
@ -293,7 +308,19 @@ proxyRemoteFilesDescription: "この設定を入れると、保存しとらん
|
|||||||
driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量"
|
driveCapacityPerLocalAccount: "ローカルユーザーひとりあたりのドライブ容量"
|
||||||
driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量"
|
driveCapacityPerRemoteAccount: "リモートユーザーひとりあたりのドライブ容量"
|
||||||
inMb: "メガバイト単位"
|
inMb: "メガバイト単位"
|
||||||
|
iconUrl: "アイコン画像のURL"
|
||||||
|
bannerUrl: "バナー画像のURL"
|
||||||
|
basicInfo: "基本情報"
|
||||||
|
pinnedUsers: "ピン留めしたユーザー"
|
||||||
|
pinnedUsersDescription: "「みつける」ページとかにピン留めしたいユーザーをここに書けばええんやで。他ん人との名前は改行で区切ればええんやで。"
|
||||||
|
hcaptcha: "hCaptcha(キャプチャ)"
|
||||||
|
enableHcaptcha: "hCaptcha(キャプチャ)をつけとく"
|
||||||
|
hcaptchaSiteKey: "サイトキー"
|
||||||
|
hcaptchaSecretKey: "シークレットキー"
|
||||||
recaptcha: "reCAPTCHA"
|
recaptcha: "reCAPTCHA"
|
||||||
|
enableRecaptcha: "reCAPTCHA(リキャプチャ)を有効にする"
|
||||||
|
recaptchaSiteKey: "サイトキー"
|
||||||
|
recaptchaSecretKey: "シークレットキー"
|
||||||
avoidMultiCaptchaConfirm: "ぎょうさんのCaptchaをつこてしまうと、仲良うせんことがあるんや。他のCaptchaをなおしとこか?別にキャンセルしてもろうたらCaptchaは消されへんで済むけど知らんで。"
|
avoidMultiCaptchaConfirm: "ぎょうさんのCaptchaをつこてしまうと、仲良うせんことがあるんや。他のCaptchaをなおしとこか?別にキャンセルしてもろうたらCaptchaは消されへんで済むけど知らんで。"
|
||||||
antennas: "アンテナ"
|
antennas: "アンテナ"
|
||||||
manageAntennas: "アンテナいじる"
|
manageAntennas: "アンテナいじる"
|
||||||
@ -346,17 +373,58 @@ unregister: "登録やめる"
|
|||||||
passwordLessLogin: "パスワード無くてもログインできるようにする"
|
passwordLessLogin: "パスワード無くてもログインできるようにする"
|
||||||
resetPassword: "パスワードをリセット"
|
resetPassword: "パスワードをリセット"
|
||||||
newPasswordIs: "今度のパスワードは「{password}」や"
|
newPasswordIs: "今度のパスワードは「{password}」や"
|
||||||
|
reduceUiAnimation: "UIの動きやアニメーションを減らしてくれや。"
|
||||||
|
share: "わけわけ"
|
||||||
|
notFound: "見つからへんね"
|
||||||
notFoundDescription: "指定されたURLに該当するページはあらへんやった。"
|
notFoundDescription: "指定されたURLに該当するページはあらへんやった。"
|
||||||
|
uploadFolder: "とりあえずここへアップロード"
|
||||||
|
cacheClear: "キャッシュをほかす"
|
||||||
|
markAsReadAllNotifications: "通知はもう全て読んだわっ"
|
||||||
|
markAsReadAllUnreadNotes: "投稿は全て読んだわっ"
|
||||||
|
markAsReadAllTalkMessages: "チャットはもうぜんぶ読んだわっ"
|
||||||
|
help: "ヘルプ"
|
||||||
|
inputMessageHere: "ここにメッセージ書いてや"
|
||||||
close: "さいなら"
|
close: "さいなら"
|
||||||
|
group: "グループ"
|
||||||
|
groups: "グループ"
|
||||||
|
createGroup: "グループを作るで"
|
||||||
|
ownedGroups: "所有しとるグループ"
|
||||||
joinedGroups: "参加しとるグループ"
|
joinedGroups: "参加しとるグループ"
|
||||||
invites: "来てや"
|
invites: "来てや"
|
||||||
|
groupName: "グループ名"
|
||||||
|
members: "メンバー"
|
||||||
|
transfer: "譲渡"
|
||||||
|
messagingWithUser: "ユーザーとチャット"
|
||||||
|
messagingWithGroup: "グループでチャット"
|
||||||
|
title: "タイトル"
|
||||||
|
text: "テキスト"
|
||||||
|
enable: "有効にするで"
|
||||||
|
next: "次"
|
||||||
|
retype: "もっかい入力"
|
||||||
|
noteOf: "{user}のノート"
|
||||||
|
inviteToGroup: "グループに招く"
|
||||||
|
maxNoteTextLength: "ノートの文字数制限"
|
||||||
|
quoteAttached: "引用付いとるで"
|
||||||
|
quoteQuestion: "引用として添付してもええか?"
|
||||||
|
noMessagesYet: "まだチャットはあらへんで"
|
||||||
|
newMessageExists: "新しいメッセージがきたで"
|
||||||
|
onlyOneFileCanBeAttached: "すまん、メッセージに添付できるファイルはひとつだけなんや。"
|
||||||
|
invitations: "来てや"
|
||||||
|
invitationCode: "招待コード"
|
||||||
|
checking: "確認しとるで"
|
||||||
smtpHost: "ホスト"
|
smtpHost: "ホスト"
|
||||||
smtpUser: "ユーザー名"
|
smtpUser: "ユーザー名"
|
||||||
smtpPass: "パスワード"
|
smtpPass: "パスワード"
|
||||||
|
_mfm:
|
||||||
|
mention: "メンション"
|
||||||
|
quote: "引用"
|
||||||
|
emoji: "カスタム絵文字"
|
||||||
|
search: "探す"
|
||||||
_sidebar:
|
_sidebar:
|
||||||
icon: "アイコン"
|
icon: "アイコン"
|
||||||
_theme:
|
_theme:
|
||||||
keys:
|
keys:
|
||||||
|
mention: "メンション"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "ノート"
|
note: "ノート"
|
||||||
@ -440,6 +508,7 @@ _notification:
|
|||||||
youWereFollowed: "フォローされたで"
|
youWereFollowed: "フォローされたで"
|
||||||
_types:
|
_types:
|
||||||
follow: "フォロー"
|
follow: "フォロー"
|
||||||
|
mention: "メンション"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "リアクション"
|
reaction: "リアクション"
|
||||||
|
@ -35,6 +35,9 @@ userList: "Tibdarin"
|
|||||||
uiLanguage: "Tutlayt n wegrudem"
|
uiLanguage: "Tutlayt n wegrudem"
|
||||||
smtpUser: "Isem n umseqdac"
|
smtpUser: "Isem n umseqdac"
|
||||||
smtpPass: "Awal uffir"
|
smtpPass: "Awal uffir"
|
||||||
|
_mfm:
|
||||||
|
mention: "Bder"
|
||||||
|
search: "Nadi"
|
||||||
_theme:
|
_theme:
|
||||||
keys:
|
keys:
|
||||||
mention: "Bder"
|
mention: "Bder"
|
||||||
|
@ -56,6 +56,8 @@ instances: "ನಿದರ್ಶನ"
|
|||||||
remove: "ಅಳಿಸು"
|
remove: "ಅಳಿಸು"
|
||||||
smtpUser: "ಬಳಕೆಹೆಸರು"
|
smtpUser: "ಬಳಕೆಹೆಸರು"
|
||||||
smtpPass: "ಗುಪ್ತಪದ"
|
smtpPass: "ಗುಪ್ತಪದ"
|
||||||
|
_mfm:
|
||||||
|
search: "ಹುಡುಕು"
|
||||||
_sfx:
|
_sfx:
|
||||||
notification: "ಅಧಿಸೂಚನೆಗಳು"
|
notification: "ಅಧಿಸೂಚನೆಗಳು"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
@ -362,8 +362,6 @@ unregister: "등록 해제"
|
|||||||
passwordLessLogin: "비밀번호 없이 로그인"
|
passwordLessLogin: "비밀번호 없이 로그인"
|
||||||
resetPassword: "비밀번호 재설정"
|
resetPassword: "비밀번호 재설정"
|
||||||
newPasswordIs: "새로운 비밀번호는 \"{password}\" 입니다"
|
newPasswordIs: "새로운 비밀번호는 \"{password}\" 입니다"
|
||||||
autoNoteWatch: "노트를 자동으로 지켜보기"
|
|
||||||
autoNoteWatchDescription: "리액션하거나 답글을 남긴 다른 유저의 노트에 대한 알림을 받습니다."
|
|
||||||
reduceUiAnimation: "UI의 애니메이션을 줄이기"
|
reduceUiAnimation: "UI의 애니메이션을 줄이기"
|
||||||
share: "공유"
|
share: "공유"
|
||||||
notFound: "찾을 수 없습니다"
|
notFound: "찾을 수 없습니다"
|
||||||
@ -401,6 +399,7 @@ noMessagesYet: "아직 대화가 없습니다"
|
|||||||
newMessageExists: "새 메시지가 있습니다"
|
newMessageExists: "새 메시지가 있습니다"
|
||||||
onlyOneFileCanBeAttached: "메시지에 첨부할 수 있는 파일은 하나까지입니다"
|
onlyOneFileCanBeAttached: "메시지에 첨부할 수 있는 파일은 하나까지입니다"
|
||||||
signinRequired: "로그인 해주세요"
|
signinRequired: "로그인 해주세요"
|
||||||
|
invitations: "초대"
|
||||||
invitationCode: "초대 코드"
|
invitationCode: "초대 코드"
|
||||||
checking: "확인하는 중입니다"
|
checking: "확인하는 중입니다"
|
||||||
available: "사용 가능합니다"
|
available: "사용 가능합니다"
|
||||||
@ -548,6 +547,17 @@ copy: "복사"
|
|||||||
logs: "로그"
|
logs: "로그"
|
||||||
database: "데이터베이스"
|
database: "데이터베이스"
|
||||||
channel: "채널"
|
channel: "채널"
|
||||||
|
random: "랜덤"
|
||||||
|
_mfm:
|
||||||
|
mention: "멘션"
|
||||||
|
hashtag: "해시태그"
|
||||||
|
link: "링크"
|
||||||
|
center: "가운데 정렬"
|
||||||
|
quote: "인용"
|
||||||
|
emoji: "커스텀 이모지"
|
||||||
|
search: "검색"
|
||||||
|
_reversi:
|
||||||
|
total: "합계"
|
||||||
_channel:
|
_channel:
|
||||||
create: "채널 생성"
|
create: "채널 생성"
|
||||||
setBanner: "배너 설정"
|
setBanner: "배너 설정"
|
||||||
|
@ -10,6 +10,8 @@ cancel: "Anuluj"
|
|||||||
enterUsername: "Wprowadź nazwę użytkownika"
|
enterUsername: "Wprowadź nazwę użytkownika"
|
||||||
smtpUser: "Nazwa użytkownika"
|
smtpUser: "Nazwa użytkownika"
|
||||||
smtpPass: "Hasło"
|
smtpPass: "Hasło"
|
||||||
|
_mfm:
|
||||||
|
search: "Szukaj"
|
||||||
_sfx:
|
_sfx:
|
||||||
notification: "Powiadomienia"
|
notification: "Powiadomienia"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
1222
locales/ru-RU.yml
1222
locales/ru-RU.yml
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,5 @@
|
|||||||
---
|
---
|
||||||
_lang_: "ياپونچە"
|
_lang_: "ياپونچە"
|
||||||
search: "ئىزدەش"
|
search: "ئىزدەش"
|
||||||
|
_mfm:
|
||||||
|
search: "ئىزدەش"
|
||||||
|
326
locales/uk-UA.yml
Normal file
326
locales/uk-UA.yml
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
---
|
||||||
|
_lang_: "Українська"
|
||||||
|
monthAndDay: "{month}/{day}"
|
||||||
|
search: "Пошук"
|
||||||
|
notifications: "Сповіщення"
|
||||||
|
username: "Ім'я користувача"
|
||||||
|
password: "Пароль"
|
||||||
|
ok: "OK"
|
||||||
|
gotIt: "Зрозуміло!"
|
||||||
|
cancel: "Скасувати"
|
||||||
|
enterUsername: "Введіть ім'я користувача"
|
||||||
|
renotedBy: "Поширено {user}"
|
||||||
|
noNotes: "Немає дописів"
|
||||||
|
noNotifications: "Немає сповіщень"
|
||||||
|
instance: "Інстанс"
|
||||||
|
settings: "Налаштування"
|
||||||
|
basicSettings: "Основні налаштування"
|
||||||
|
otherSettings: "Інші налаштування"
|
||||||
|
openInWindow: "Відкрити у вікні"
|
||||||
|
profile: "Профіль"
|
||||||
|
timeline: "Стрічка"
|
||||||
|
noAccountDescription: "Цей користувач ще нічого не написав про себе"
|
||||||
|
login: "Увійти"
|
||||||
|
loggingIn: "Здійснюємо вхід..."
|
||||||
|
logout: "Вийти"
|
||||||
|
signup: "Реєстрація"
|
||||||
|
uploading: "Завантаження..."
|
||||||
|
save: "Зберегти"
|
||||||
|
users: "Користувачі"
|
||||||
|
addUser: "Додати користувача"
|
||||||
|
favorite: "Обране"
|
||||||
|
favorites: "Обране"
|
||||||
|
unfavorite: "Видалити з обраного"
|
||||||
|
pin: "Закріпити"
|
||||||
|
unpin: "Відкріпити"
|
||||||
|
copyContent: "Скопіювати контент"
|
||||||
|
copyLink: "Скопіювати посилання"
|
||||||
|
delete: "Видалити"
|
||||||
|
deleteAndEdit: "Видалити й редагувати"
|
||||||
|
addToList: "Додати до списку"
|
||||||
|
sendMessage: "Надіслати повідомлення"
|
||||||
|
copyUsername: "Скопіювати ім’я користувача"
|
||||||
|
searchUser: "Пошук користувачів"
|
||||||
|
reply: "Відповісти"
|
||||||
|
loadMore: "Показати більше"
|
||||||
|
youGotNewFollower: "У вас новий підписник"
|
||||||
|
receiveFollowRequest: "Отримано запит на підписку"
|
||||||
|
followRequestAccepted: "Запит на підписку прийнято"
|
||||||
|
mention: "Згадка"
|
||||||
|
mentions: "Згадки"
|
||||||
|
directNotes: "Прямі повідомлення"
|
||||||
|
importAndExport: "Імпорт та експорт"
|
||||||
|
import: "Імпорт"
|
||||||
|
export: "Експорт"
|
||||||
|
files: "Файли"
|
||||||
|
download: "Завантажити"
|
||||||
|
unfollowConfirm: "Ви впевнені, що хочете відписатися від {name}?"
|
||||||
|
lists: "Списки"
|
||||||
|
noLists: "Немає списків"
|
||||||
|
note: "Дописи"
|
||||||
|
notes: "Дописи"
|
||||||
|
following: "Підписки"
|
||||||
|
followers: "Підписники"
|
||||||
|
followsYou: "Підписаний(-а) на вас"
|
||||||
|
createList: "Створити список"
|
||||||
|
manageLists: "Управління списками"
|
||||||
|
error: "Помилка"
|
||||||
|
somethingHappened: "Щось пішло не так"
|
||||||
|
retry: "Спробувати знову"
|
||||||
|
pageLoadError: "Помилка при завантаженні сторінки"
|
||||||
|
enterListName: "Введіть назву списку"
|
||||||
|
privacy: "Приватність"
|
||||||
|
makeFollowManuallyApprove: "Підтверджувати підписників уручну"
|
||||||
|
defaultNoteVisibility: "Видимість допису за замовчуванням"
|
||||||
|
follow: "Підписка"
|
||||||
|
followRequest: "Запит на підписку"
|
||||||
|
followRequests: "Запити на підписку"
|
||||||
|
unfollow: "Відписатися"
|
||||||
|
followRequestPending: "Очікуючі запити на підписку"
|
||||||
|
enterEmoji: "Введіть емодзі"
|
||||||
|
renote: "Поширити"
|
||||||
|
unrenote: "Відміна поширення"
|
||||||
|
quote: "Цитата"
|
||||||
|
pinnedNote: "Закріплений допис"
|
||||||
|
you: "Ви"
|
||||||
|
clickToShow: "Натисніть для перегляду"
|
||||||
|
sensitive: "NSFW"
|
||||||
|
add: "Додати"
|
||||||
|
reaction: "Реакції"
|
||||||
|
rememberNoteVisibility: "Пам’ятати видимість дописів"
|
||||||
|
attachCancel: "Видалити вкладення"
|
||||||
|
markAsSensitive: "Позначити як NSFW"
|
||||||
|
unmarkAsSensitive: "Зняти позначку NSFW"
|
||||||
|
enterFileName: "Введіть ім'я файлу"
|
||||||
|
mute: "Ігнорувати"
|
||||||
|
unmute: "Показувати"
|
||||||
|
block: "Заблокувати"
|
||||||
|
unblock: "Розблокувати"
|
||||||
|
suspend: "Призупинити"
|
||||||
|
unsuspend: "Відновити"
|
||||||
|
blockConfirm: "Ви впевнені, що хочете заблокувати цей акаунт?"
|
||||||
|
unblockConfirm: "Ви впевнені, що хочете розблокувати цей акаунт?"
|
||||||
|
suspendConfirm: "Ви впевнені, що хочете призупинити цей акаунт?"
|
||||||
|
unsuspendConfirm: "Ви впевнені, що хочете відновити цей акаунт?"
|
||||||
|
selectList: "Виберіть список"
|
||||||
|
selectAntenna: "Виберіть антену"
|
||||||
|
selectWidget: "Виберіть віджет"
|
||||||
|
editWidgets: "Редагувати віджети"
|
||||||
|
editWidgetsExit: "Готово"
|
||||||
|
customEmojis: "Кастомні емоджі"
|
||||||
|
emoji: "Емоджі"
|
||||||
|
emojiName: "Назва емоджі"
|
||||||
|
addEmoji: "Додати емодзі"
|
||||||
|
settingGuide: "Рекомендована конфігурація"
|
||||||
|
cacheRemoteFiles: "Кешувати дані з інших інстансів"
|
||||||
|
flagAsBot: "Акаунт бота"
|
||||||
|
flagAsCat: "Акаунт кота"
|
||||||
|
autoAcceptFollowed: "Автоматично приймати запити на підписку від користувачів, на яких ви підписані"
|
||||||
|
addAcount: "Додати акаунт"
|
||||||
|
loginFailed: "Не вдалося увійти"
|
||||||
|
showOnRemote: "Переглянути в оригіналі"
|
||||||
|
general: "Загальне"
|
||||||
|
wallpaper: "Шпалери"
|
||||||
|
setWallpaper: "Встановити шпалери"
|
||||||
|
removeWallpaper: "Прибрати шпалери"
|
||||||
|
searchWith: "Шукати з {q}"
|
||||||
|
youHaveNoLists: "У вас немає списків"
|
||||||
|
followConfirm: "Підписатися на {name}?"
|
||||||
|
proxyAccount: "Проксі-акаунт"
|
||||||
|
host: "Хост"
|
||||||
|
selectUser: "Виберіть користувача"
|
||||||
|
recipient: "Кому"
|
||||||
|
annotation: "Коментар"
|
||||||
|
federation: "Федіверс"
|
||||||
|
instances: "Інстанс"
|
||||||
|
registeredAt: "Приєднався(-лась)"
|
||||||
|
latestRequestSentAt: "Останній запит надіслано"
|
||||||
|
latestRequestReceivedAt: "Останній запит прийнято"
|
||||||
|
latestStatus: "Останній статус"
|
||||||
|
storageUsage: "Використання простіру"
|
||||||
|
charts: "Графіки"
|
||||||
|
perHour: "Щогодини"
|
||||||
|
perDay: "Щоденно"
|
||||||
|
blockThisInstance: "Заблокувати цей інстанс"
|
||||||
|
operations: "Операції"
|
||||||
|
software: "Програмне забезпечення"
|
||||||
|
version: "Версія"
|
||||||
|
metadata: "Метадані"
|
||||||
|
withNFiles: "файли: {n}"
|
||||||
|
monitor: "Монітор"
|
||||||
|
jobQueue: "Черга завдань"
|
||||||
|
cpuAndMemory: "ЦП та пам'ять"
|
||||||
|
network: "Мережа"
|
||||||
|
disk: "Диск"
|
||||||
|
instanceInfo: "Про цей інстанс"
|
||||||
|
statistics: "Статистика"
|
||||||
|
clearQueue: "Очистити чергу"
|
||||||
|
clearCachedFiles: "Очистити кеш"
|
||||||
|
blockedInstances: "Заблоковані інстанси"
|
||||||
|
muteAndBlock: "Ігнор і блокування"
|
||||||
|
mutedUsers: "Ігноровані користувачі"
|
||||||
|
blockedUsers: "Заблоковані користувачі"
|
||||||
|
noUsers: "Немає користувачів"
|
||||||
|
editProfile: "Редагувати профіль"
|
||||||
|
noteDeleteConfirm: "Ви дійсно хочете видалити цей допис?"
|
||||||
|
pinLimitExceeded: "Більше дописів не можна закріпити"
|
||||||
|
done: "Готово"
|
||||||
|
processing: "Обробка"
|
||||||
|
preview: "Передогляд"
|
||||||
|
default: "За умовчанням"
|
||||||
|
noCustomEmojis: "Немає кастомних емоджі"
|
||||||
|
noJobs: "Немає завдань"
|
||||||
|
federating: "Федерується"
|
||||||
|
blocked: "Заблоковано"
|
||||||
|
notResponding: "Не відповідає"
|
||||||
|
changePassword: "Змінити пароль"
|
||||||
|
security: "Безпека"
|
||||||
|
currentPassword: "Поточний пароль"
|
||||||
|
newPassword: "Новий пароль"
|
||||||
|
newPasswordRetype: "Новий пароль (повторно)"
|
||||||
|
attachFile: "Вкласти файл"
|
||||||
|
more: "Бiльше!"
|
||||||
|
featured: "Виділено"
|
||||||
|
noSuchUser: "Користувача не знайдено"
|
||||||
|
lookup: "Пошук"
|
||||||
|
announcements: "Оголошення"
|
||||||
|
imageUrl: "URL зображення"
|
||||||
|
remove: "Видалити"
|
||||||
|
removed: "Видалено"
|
||||||
|
saved: "Збережено"
|
||||||
|
messaging: "Чати"
|
||||||
|
upload: "Завантажити"
|
||||||
|
fromDrive: "З диска"
|
||||||
|
fromUrl: "З URL"
|
||||||
|
uploadFromUrl: "Завантажити з URL"
|
||||||
|
explore: "Огляд"
|
||||||
|
games: "Ігри Misskey"
|
||||||
|
start: "Розпочати"
|
||||||
|
activity: "Активність"
|
||||||
|
images: "Зображення"
|
||||||
|
birthday: "День народження"
|
||||||
|
yearsOld: "{age} років"
|
||||||
|
registeredDate: "Приєднався(-лась)"
|
||||||
|
location: "Локація"
|
||||||
|
theme: "Тема"
|
||||||
|
themeForLightMode: "Світла тема"
|
||||||
|
themeForDarkMode: "Темна тема"
|
||||||
|
light: "Світла"
|
||||||
|
dark: "Темна"
|
||||||
|
lightThemes: "Світлі теми"
|
||||||
|
darkThemes: "Темні теми"
|
||||||
|
drive: "Диск"
|
||||||
|
fileName: "Ім'я файлу"
|
||||||
|
selectFile: "Вибрати файл"
|
||||||
|
selectFiles: "Вибрати файли"
|
||||||
|
selectFolder: "Вибрати теку"
|
||||||
|
selectFolders: "Вибрати теки"
|
||||||
|
renameFile: "Перейменувати файл"
|
||||||
|
folderName: "Ім'я теки"
|
||||||
|
createFolder: "Створити теку"
|
||||||
|
renameFolder: "Перейменувати теку"
|
||||||
|
deleteFolder: "Видалити теку"
|
||||||
|
addFile: "Додати файл"
|
||||||
|
copyUrl: "Копіювати URL"
|
||||||
|
rename: "Перейменувати"
|
||||||
|
avatar: "Аватар"
|
||||||
|
banner: "Банер"
|
||||||
|
nsfw: "NSFW"
|
||||||
|
reload: "Оновити"
|
||||||
|
watch: "Стежити"
|
||||||
|
unwatch: "Не стежити"
|
||||||
|
instanceName: "Назва інстансу"
|
||||||
|
maintainerName: "Ім'я адміністратора"
|
||||||
|
maintainerEmail: "Email адміністратора"
|
||||||
|
thisYear: "Рік"
|
||||||
|
thisMonth: "Місяць"
|
||||||
|
today: "День"
|
||||||
|
dayX: "{day}"
|
||||||
|
monthX: "{month}"
|
||||||
|
yearX: "{year}"
|
||||||
|
pages: "Сторінки"
|
||||||
|
connectSerice: "Під’єднатися"
|
||||||
|
disconnectSerice: "Відключитися"
|
||||||
|
exploreUsersCount: "{count} користувачів"
|
||||||
|
userList: "Списки"
|
||||||
|
showInPage: "Показати на сторінці"
|
||||||
|
smtpHost: "Хост"
|
||||||
|
smtpUser: "Ім'я користувача"
|
||||||
|
smtpPass: "Пароль"
|
||||||
|
_mfm:
|
||||||
|
mention: "Згадка"
|
||||||
|
quote: "Цитата"
|
||||||
|
emoji: "Кастомні емоджі"
|
||||||
|
search: "Пошук"
|
||||||
|
_sidebar:
|
||||||
|
icon: "Аватар"
|
||||||
|
_theme:
|
||||||
|
keys:
|
||||||
|
mention: "Згадка"
|
||||||
|
renote: "Поширити"
|
||||||
|
_sfx:
|
||||||
|
note: "Дописи"
|
||||||
|
notification: "Сповіщення"
|
||||||
|
chat: "Чати"
|
||||||
|
_antennaSources:
|
||||||
|
homeTimeline: "Дописи тих, на кого ви підписані"
|
||||||
|
_widgets:
|
||||||
|
notifications: "Сповіщення"
|
||||||
|
timeline: "Стрічка"
|
||||||
|
activity: "Активність"
|
||||||
|
federation: "Федіверс"
|
||||||
|
_cw:
|
||||||
|
show: "Показати більше"
|
||||||
|
_visibility:
|
||||||
|
home: "Головна"
|
||||||
|
followers: "Підписники"
|
||||||
|
_postForm:
|
||||||
|
replyPlaceholder: "Відповідь на допис..."
|
||||||
|
_profile:
|
||||||
|
username: "Ім'я користувача"
|
||||||
|
_exportOrImport:
|
||||||
|
followingList: "Підписки"
|
||||||
|
muteList: "Ігнорувати"
|
||||||
|
blockingList: "Заблокувати"
|
||||||
|
userLists: "Списки"
|
||||||
|
_rooms:
|
||||||
|
_roomType:
|
||||||
|
default: "За умовчанням"
|
||||||
|
_furnitures:
|
||||||
|
monitor: "Монітор"
|
||||||
|
_pages:
|
||||||
|
blocks:
|
||||||
|
image: "Зображення"
|
||||||
|
script:
|
||||||
|
categories:
|
||||||
|
list: "Списки"
|
||||||
|
blocks:
|
||||||
|
_join:
|
||||||
|
arg1: "Списки"
|
||||||
|
_randomPick:
|
||||||
|
arg1: "Списки"
|
||||||
|
_dailyRandomPick:
|
||||||
|
arg1: "Списки"
|
||||||
|
_seedRandomPick:
|
||||||
|
arg2: "Списки"
|
||||||
|
_pick:
|
||||||
|
arg1: "Списки"
|
||||||
|
_listLen:
|
||||||
|
arg1: "Списки"
|
||||||
|
types:
|
||||||
|
array: "Списки"
|
||||||
|
_notification:
|
||||||
|
youRenoted: "{name} поширив(ла) ваш допис"
|
||||||
|
youWereFollowed: "У вас новий підписник"
|
||||||
|
_types:
|
||||||
|
follow: "Підписки"
|
||||||
|
mention: "Згадка"
|
||||||
|
renote: "Поширити"
|
||||||
|
quote: "Цитата"
|
||||||
|
reaction: "Реакції"
|
||||||
|
_deck:
|
||||||
|
_columns:
|
||||||
|
notifications: "Сповіщення"
|
||||||
|
tl: "Стрічка"
|
||||||
|
list: "Списки"
|
||||||
|
mentions: "Згадки"
|
@ -164,7 +164,7 @@ jobQueue: "作业队列"
|
|||||||
cpuAndMemory: "CPU使用量"
|
cpuAndMemory: "CPU使用量"
|
||||||
network: "网络"
|
network: "网络"
|
||||||
disk: "存储"
|
disk: "存储"
|
||||||
instanceInfo: "实例情报"
|
instanceInfo: "实例信息"
|
||||||
statistics: "统计"
|
statistics: "统计"
|
||||||
clearQueue: "清除队列"
|
clearQueue: "清除队列"
|
||||||
clearQueueConfirmTitle: "确定清除队列?"
|
clearQueueConfirmTitle: "确定清除队列?"
|
||||||
@ -353,7 +353,7 @@ popularTags: "热门标签"
|
|||||||
userList: "列表"
|
userList: "列表"
|
||||||
about: "关于"
|
about: "关于"
|
||||||
aboutMisskey: "关于 Misskey"
|
aboutMisskey: "关于 Misskey"
|
||||||
aboutMisskeyText: "Misskey是由syuilo于2014年开发的开放源代码软件。"
|
aboutMisskeyText: "Misskey是由syuilo于2014年开发的开源软件。"
|
||||||
misskeyMembers: "现在由以下成员进行开发和维护:"
|
misskeyMembers: "现在由以下成员进行开发和维护:"
|
||||||
misskeySource: "源代码在这里公开:"
|
misskeySource: "源代码在这里公开:"
|
||||||
misskeyTranslation: "与我们一同进行Misskey的翻译工作:"
|
misskeyTranslation: "与我们一同进行Misskey的翻译工作:"
|
||||||
@ -373,8 +373,6 @@ unregister: "删除账户"
|
|||||||
passwordLessLogin: "无密码登录"
|
passwordLessLogin: "无密码登录"
|
||||||
resetPassword: "重置密码"
|
resetPassword: "重置密码"
|
||||||
newPasswordIs: "新的密码是「{password}」"
|
newPasswordIs: "新的密码是「{password}」"
|
||||||
autoNoteWatch: "自动关注帖子"
|
|
||||||
autoNoteWatchDescription: "让您能够收到关于「回应」和回复其他用户的帖子的通知。"
|
|
||||||
reduceUiAnimation: "减少UI动画"
|
reduceUiAnimation: "减少UI动画"
|
||||||
share: "分享"
|
share: "分享"
|
||||||
notFound: "未找到"
|
notFound: "未找到"
|
||||||
@ -412,6 +410,7 @@ noMessagesYet: "现在没有新的聊天"
|
|||||||
newMessageExists: "新信息"
|
newMessageExists: "新信息"
|
||||||
onlyOneFileCanBeAttached: "只能添加一个附件"
|
onlyOneFileCanBeAttached: "只能添加一个附件"
|
||||||
signinRequired: "请先登录"
|
signinRequired: "请先登录"
|
||||||
|
invitations: "邀请"
|
||||||
invitationCode: "邀请码"
|
invitationCode: "邀请码"
|
||||||
checking: "正在确认"
|
checking: "正在确认"
|
||||||
available: "可用"
|
available: "可用"
|
||||||
@ -541,6 +540,7 @@ pluginInstallWarn: "请不要安装不明来源的插件"
|
|||||||
deck: "Deck"
|
deck: "Deck"
|
||||||
undeck: "取消Deck"
|
undeck: "取消Deck"
|
||||||
useBlurEffectForModal: "模态框使用模糊效果"
|
useBlurEffectForModal: "模态框使用模糊效果"
|
||||||
|
useFullReactionPicker: "使用全功能的回应工具栏"
|
||||||
generateAccessToken: "生成访问令牌"
|
generateAccessToken: "生成访问令牌"
|
||||||
permission: "权限"
|
permission: "权限"
|
||||||
enableAll: "启用全部"
|
enableAll: "启用全部"
|
||||||
@ -593,6 +593,61 @@ fillAbuseReportDescription: "请填写举报的详细原因。如果有对方发
|
|||||||
abuseReported: "内容已发送。感谢您的报告。"
|
abuseReported: "内容已发送。感谢您的报告。"
|
||||||
send: "发送"
|
send: "发送"
|
||||||
abuseMarkAsResolved: "处理完毕"
|
abuseMarkAsResolved: "处理完毕"
|
||||||
|
openInNewTab: "在新标签页中打开"
|
||||||
|
openInSideView: "在侧边栏中打开"
|
||||||
|
defaultNavigationBehaviour: "默认导航"
|
||||||
|
editTheseSettingsMayBreakAccount: "编辑这些设置可以会损坏您的账号"
|
||||||
|
instanceTicker: "帖子的实例信息"
|
||||||
|
waitingFor: "等待{x}"
|
||||||
|
random: "随机"
|
||||||
|
system: "系统"
|
||||||
|
switchUi: "切换界面"
|
||||||
|
desktop: "桌面"
|
||||||
|
_mfm:
|
||||||
|
mention: "提及"
|
||||||
|
hashtag: "话题标签"
|
||||||
|
link: "链接"
|
||||||
|
center: "居中"
|
||||||
|
quote: "引用"
|
||||||
|
emoji: "自定义Emoji"
|
||||||
|
search: "搜索"
|
||||||
|
_reversi:
|
||||||
|
reversi: "黑白棋"
|
||||||
|
gameSettings: "对局设置"
|
||||||
|
chooseBoard: "棋盘选择"
|
||||||
|
blackOrWhite: "先手/后手"
|
||||||
|
blackIs: "{name}执黑(先走)"
|
||||||
|
rules: "规则"
|
||||||
|
botSettings: "机器人设置"
|
||||||
|
thisGameIsStartedSoon: "对局在几秒后开始"
|
||||||
|
waitingForOther: "等待对手准备"
|
||||||
|
waitingForMe: "等待您的准备"
|
||||||
|
waitingBoth: "请准备"
|
||||||
|
ready: "准备就绪"
|
||||||
|
cancelReady: "重新准备"
|
||||||
|
opponentTurn: "对手的会合"
|
||||||
|
myTurn: "您的回合"
|
||||||
|
turnOf: "{name}的回合"
|
||||||
|
pastTurnOf: "{name}的回合"
|
||||||
|
surrender: "认输 "
|
||||||
|
surrendered: "对手认输"
|
||||||
|
drawn: "平局"
|
||||||
|
won: "{name}获胜"
|
||||||
|
black: "黑"
|
||||||
|
white: "白"
|
||||||
|
total: "总计"
|
||||||
|
turnCount: "{count}回合"
|
||||||
|
myGames: "我的对局"
|
||||||
|
allGames: "所有对局"
|
||||||
|
ended: "结束"
|
||||||
|
playing: "对局中"
|
||||||
|
isLlotheo: "棋子较少一方获胜(LLoTheO规则)"
|
||||||
|
loopedMap: "循环棋盘"
|
||||||
|
canPutEverywhere: "可以下在任意位置"
|
||||||
|
_instanceTicker:
|
||||||
|
none: "不显示"
|
||||||
|
remote: "显示给远程用户"
|
||||||
|
always: "始终显示"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "自动重载"
|
reload: "自动重载"
|
||||||
dialog: "对话框警告"
|
dialog: "对话框警告"
|
||||||
|
@ -4,10 +4,10 @@ introMisskey: "歡迎! Misskey是一個開源的去中心化的社群網站。
|
|||||||
monthAndDay: "{month}月 {day}日"
|
monthAndDay: "{month}月 {day}日"
|
||||||
search: "搜尋"
|
search: "搜尋"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
username: "使用名稱"
|
username: "使用者名稱"
|
||||||
password: "密碼"
|
password: "密碼"
|
||||||
fetchingAsApObject: "從 Fediverse 查詢中..."
|
fetchingAsApObject: "從 Fediverse 查詢中..."
|
||||||
ok: "確定"
|
ok: "OK"
|
||||||
gotIt: "知道了"
|
gotIt: "知道了"
|
||||||
cancel: "取消"
|
cancel: "取消"
|
||||||
enterUsername: "輸入使用者名稱"
|
enterUsername: "輸入使用者名稱"
|
||||||
@ -99,8 +99,8 @@ attachCancel: "移除附件"
|
|||||||
markAsSensitive: "標記為敏感內容"
|
markAsSensitive: "標記為敏感內容"
|
||||||
unmarkAsSensitive: "取消標記為敏感內容"
|
unmarkAsSensitive: "取消標記為敏感內容"
|
||||||
enterFileName: "請輸入檔案名稱"
|
enterFileName: "請輸入檔案名稱"
|
||||||
mute: "消音"
|
mute: "靜音"
|
||||||
unmute: "解除消音"
|
unmute: "解除靜音"
|
||||||
block: "封鎖"
|
block: "封鎖"
|
||||||
unblock: "解除封鎖"
|
unblock: "解除封鎖"
|
||||||
suspend: "凍結"
|
suspend: "凍結"
|
||||||
@ -121,9 +121,9 @@ emojiUrl: "表情符號URL"
|
|||||||
addEmoji: "新增表情符號"
|
addEmoji: "新增表情符號"
|
||||||
settingGuide: "推薦設定"
|
settingGuide: "推薦設定"
|
||||||
cacheRemoteFiles: "緩存非遠程檔案"
|
cacheRemoteFiles: "緩存非遠程檔案"
|
||||||
cacheRemoteFilesDescription: "如果禁用此設定,遠程文件將會被直接連結而非緩存。禁用將節省服務器上的存儲空間,但會因為沒有生成預覽圖而增加流量。"
|
cacheRemoteFilesDescription: "禁用此設定會停止遠端檔案的緩存,從而節省儲存空間。但資料會因直接連線從而產生額外連接數據。"
|
||||||
flagAsBot: "此帳戶是Bot"
|
flagAsBot: "此使用者是機器人"
|
||||||
flagAsCat: "此帳戶是Cat"
|
flagAsCat: "此使用者是貓"
|
||||||
autoAcceptFollowed: "自動許可追隨"
|
autoAcceptFollowed: "自動許可追隨"
|
||||||
addAcount: "新增帳號"
|
addAcount: "新增帳號"
|
||||||
loginFailed: "登入失敗"
|
loginFailed: "登入失敗"
|
||||||
@ -171,8 +171,8 @@ clearCachedFiles: "清除快取資料"
|
|||||||
clearCachedFilesConfirm: "確定要清除緩存資料嗎?"
|
clearCachedFilesConfirm: "確定要清除緩存資料嗎?"
|
||||||
blockedInstances: "已封鎖的實例"
|
blockedInstances: "已封鎖的實例"
|
||||||
blockedInstancesDescription: "請逐行輸入需要封鎖的實例。已封鎖的實例將無法與本實例進行通訊。"
|
blockedInstancesDescription: "請逐行輸入需要封鎖的實例。已封鎖的實例將無法與本實例進行通訊。"
|
||||||
muteAndBlock: "禁言 / 封鎖"
|
muteAndBlock: "靜音/封鎖"
|
||||||
mutedUsers: "已禁言用戶"
|
mutedUsers: "已靜音用戶"
|
||||||
blockedUsers: "已封鎖用戶"
|
blockedUsers: "已封鎖用戶"
|
||||||
noUsers: "無用戶"
|
noUsers: "無用戶"
|
||||||
editProfile: "編輯個人檔案"
|
editProfile: "編輯個人檔案"
|
||||||
@ -227,6 +227,7 @@ messageRead: "已讀"
|
|||||||
noMoreHistory: "沒有更多歷史紀錄"
|
noMoreHistory: "沒有更多歷史紀錄"
|
||||||
startMessaging: "開始傳送訊息"
|
startMessaging: "開始傳送訊息"
|
||||||
nUsersRead: "{n}人已讀"
|
nUsersRead: "{n}人已讀"
|
||||||
|
agreeTo: "我同意{0}"
|
||||||
tos: "使用條款"
|
tos: "使用條款"
|
||||||
start: "開始"
|
start: "開始"
|
||||||
home: "首頁"
|
home: "首頁"
|
||||||
@ -369,8 +370,6 @@ unregister: "刪除賬戶"
|
|||||||
passwordLessLogin: "設置無密碼登入"
|
passwordLessLogin: "設置無密碼登入"
|
||||||
resetPassword: "重置密碼"
|
resetPassword: "重置密碼"
|
||||||
newPasswordIs: "新密碼為「{password}」"
|
newPasswordIs: "新密碼為「{password}」"
|
||||||
autoNoteWatch: "自動追隨貼文"
|
|
||||||
autoNoteWatchDescription: "收到反應或回覆過的貼文的通知"
|
|
||||||
reduceUiAnimation: "減少介面的動態視覺"
|
reduceUiAnimation: "減少介面的動態視覺"
|
||||||
share: "分享"
|
share: "分享"
|
||||||
notFound: "找不到"
|
notFound: "找不到"
|
||||||
@ -408,6 +407,7 @@ noMessagesYet: "沒有訊息"
|
|||||||
newMessageExists: "有新的訊息"
|
newMessageExists: "有新的訊息"
|
||||||
onlyOneFileCanBeAttached: "只能添加一個附件"
|
onlyOneFileCanBeAttached: "只能添加一個附件"
|
||||||
signinRequired: "請先登入"
|
signinRequired: "請先登入"
|
||||||
|
invitations: "邀請"
|
||||||
invitationCode: "邀請碼"
|
invitationCode: "邀請碼"
|
||||||
checking: "確認中"
|
checking: "確認中"
|
||||||
available: "可用的"
|
available: "可用的"
|
||||||
@ -444,9 +444,22 @@ openImageInNewTab: "於新分頁中開啟圖片"
|
|||||||
local: "本地"
|
local: "本地"
|
||||||
remote: "遠端"
|
remote: "遠端"
|
||||||
total: "合計"
|
total: "合計"
|
||||||
|
weekOverWeekChanges: "與上週相比"
|
||||||
|
dayOverDayChanges: "與前一日相比"
|
||||||
appearance: "外觀"
|
appearance: "外觀"
|
||||||
accountSettings: "帳戶設置"
|
clientSettings: "用戶端設定"
|
||||||
|
accountSettings: "帳號設定"
|
||||||
|
promotion: "推廣貼文"
|
||||||
|
promote: "推廣"
|
||||||
|
numberOfDays: "有效天數"
|
||||||
|
hideThisNote: "隱藏此貼文"
|
||||||
|
showFeaturedNotesInTimeline: "在時間軸上顯示熱門推薦"
|
||||||
|
objectStorageBaseUrl: "Base URL"
|
||||||
|
objectStorageBucket: "儲存空間(Bucket)"
|
||||||
objectStoragePrefix: "前綴"
|
objectStoragePrefix: "前綴"
|
||||||
|
objectStorageEndpoint: "訪問網域名稱(Endpoint)"
|
||||||
|
objectStorageEndpointDesc: "如要使用AWS S3,請留空。否則請根據伺服器要求以'<host>'或 '<host>:<port>'的形式設定訪問網域名稱(Endpoint)。"
|
||||||
|
objectStorageRegion: "地域(Region)"
|
||||||
objectStorageUseSSL: "使用SSL"
|
objectStorageUseSSL: "使用SSL"
|
||||||
objectStorageUseProxy: "使用網路代理"
|
objectStorageUseProxy: "使用網路代理"
|
||||||
serverLogs: "伺服器日誌"
|
serverLogs: "伺服器日誌"
|
||||||
@ -512,24 +525,63 @@ tokenRequested: "允許訪問帳號"
|
|||||||
notificationType: "通知形式"
|
notificationType: "通知形式"
|
||||||
edit: "編輯"
|
edit: "編輯"
|
||||||
useStarForReactionFallback: "以★代替未知的表情符號"
|
useStarForReactionFallback: "以★代替未知的表情符號"
|
||||||
emailConfig: "電郵服務器設定"
|
emailConfig: "電子郵件伺服器設定"
|
||||||
enableEmail: "啟用發送電郵功能"
|
enableEmail: "啟用發送電郵功能"
|
||||||
emailConfigInfo: "用於確認電郵地址及密碼重置"
|
emailConfigInfo: "用於確認電郵地址及密碼重置"
|
||||||
email: "電郵地址"
|
email: "電郵地址"
|
||||||
smtpConfig: "SMTP服務器設定"
|
smtpConfig: "SMTP伺服器設定"
|
||||||
smtpHost: "主機"
|
smtpHost: "主機"
|
||||||
smtpPort: "端口"
|
smtpPort: "端口"
|
||||||
smtpUser: "使用名稱"
|
smtpUser: "使用者名稱"
|
||||||
smtpPass: "密碼"
|
smtpPass: "密碼"
|
||||||
|
emptyToDisableSmtpAuth: "留空使用者名稱和密碼以禁用SMTP驗證。"
|
||||||
|
testEmail: "郵件測試發送"
|
||||||
|
wordMute: "靜音文字"
|
||||||
display: "檢視"
|
display: "檢視"
|
||||||
copy: "複製"
|
copy: "複製"
|
||||||
metrics: "指標"
|
metrics: "指標"
|
||||||
|
overview: "概覽"
|
||||||
logs: "日誌"
|
logs: "日誌"
|
||||||
delayed: "延遲"
|
delayed: "延遲"
|
||||||
database: "資料庫"
|
database: "資料庫"
|
||||||
channel: "頻道"
|
channel: "頻道"
|
||||||
create: "新增"
|
create: "新增"
|
||||||
notificationSetting: "管理通知"
|
notificationSetting: "通知設定"
|
||||||
|
other: "其他"
|
||||||
|
regenerateLoginTokenDescription: "再生用於登入的內部權杖。一般情況下是不需要這樣做的。一旦再生,所有裝置將會被登出。"
|
||||||
|
sample: "範例 "
|
||||||
|
abuseReports: "檢舉"
|
||||||
|
reportAbuse: "檢舉"
|
||||||
|
reportAbuseOf: "檢舉{name}"
|
||||||
|
send: "發送"
|
||||||
|
openInNewTab: "在新分頁中開啟"
|
||||||
|
random: "隨機"
|
||||||
|
system: "系統"
|
||||||
|
_mfm:
|
||||||
|
mention: "提及"
|
||||||
|
hashtag: "#tag"
|
||||||
|
link: "鏈接"
|
||||||
|
quote: "引用"
|
||||||
|
emoji: "自訂表情符號"
|
||||||
|
search: "搜尋"
|
||||||
|
_reversi:
|
||||||
|
reversi: "黑白棋"
|
||||||
|
gameSettings: "對弈設定"
|
||||||
|
chooseBoard: "選擇棋盤"
|
||||||
|
rules: "規則"
|
||||||
|
botSettings: "機器人設定"
|
||||||
|
opponentTurn: "對手回合"
|
||||||
|
myTurn: "你的回合"
|
||||||
|
turnOf: "{name}的回合"
|
||||||
|
pastTurnOf: "{name}的回合"
|
||||||
|
surrender: "認輸"
|
||||||
|
black: "黑"
|
||||||
|
white: "白"
|
||||||
|
total: "合計"
|
||||||
|
ended: "已結束"
|
||||||
|
playing: "正在對弈"
|
||||||
|
_instanceTicker:
|
||||||
|
always: "總是顯示"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "自動重載"
|
reload: "自動重載"
|
||||||
dialog: "以對話框警告"
|
dialog: "以對話框警告"
|
||||||
@ -537,7 +589,7 @@ _serverDisconnectedBehavior:
|
|||||||
_channel:
|
_channel:
|
||||||
create: "建立頻道"
|
create: "建立頻道"
|
||||||
edit: "編輯頻道"
|
edit: "編輯頻道"
|
||||||
setBanner: "設置封面圖"
|
setBanner: "設定橫幅"
|
||||||
removeBanner: "移除封面圖"
|
removeBanner: "移除封面圖"
|
||||||
featured: "流行"
|
featured: "流行"
|
||||||
owned: "管理中"
|
owned: "管理中"
|
||||||
@ -549,16 +601,30 @@ _sidebar:
|
|||||||
hide: "隱藏"
|
hide: "隱藏"
|
||||||
_wordMute:
|
_wordMute:
|
||||||
muteWords: "加入靜音文字"
|
muteWords: "加入靜音文字"
|
||||||
|
mutedNotes: "已靜音的貼文"
|
||||||
_theme:
|
_theme:
|
||||||
|
constant: "常數"
|
||||||
|
defaultValue: "預設值"
|
||||||
color: "顏色"
|
color: "顏色"
|
||||||
func: "函数"
|
func: "函数"
|
||||||
|
argument: "引數"
|
||||||
|
alpha: "透明度"
|
||||||
|
darken: "暗度"
|
||||||
|
lighten: "亮度"
|
||||||
keys:
|
keys:
|
||||||
bg: "背景"
|
bg: "背景"
|
||||||
|
fg: "文本"
|
||||||
|
shadow: "陰影"
|
||||||
|
link: "鏈接"
|
||||||
|
hashtag: "#tag"
|
||||||
mention: "提及"
|
mention: "提及"
|
||||||
|
mentionMe: "提及我"
|
||||||
renote: "轉發貼文"
|
renote: "轉發貼文"
|
||||||
divider: "分割線"
|
divider: "分割線"
|
||||||
infoBg: "資訊背景"
|
infoBg: "資訊背景"
|
||||||
infoFg: "資訊內容"
|
infoFg: "資訊內容"
|
||||||
|
infoWarnBg: "警告背景"
|
||||||
|
infoWarnFg: "警告字元"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "貼文"
|
note: "貼文"
|
||||||
noteMy: "我的貼文"
|
noteMy: "我的貼文"
|
||||||
@ -595,6 +661,7 @@ _tutorial:
|
|||||||
step4_1: "筆記發出去了嗎?"
|
step4_1: "筆記發出去了嗎?"
|
||||||
step4_2: "如果你的貼文有顯示在時間軸上,就代表已經發文成功。"
|
step4_2: "如果你的貼文有顯示在時間軸上,就代表已經發文成功。"
|
||||||
step5_1: "現在試試看追隨其他人來讓你的時間軸變得更生動吧。"
|
step5_1: "現在試試看追隨其他人來讓你的時間軸變得更生動吧。"
|
||||||
|
step5_2: "你可以在{featured}上看到受歡迎的貼文,你也可以選擇從列表中追隨你喜歡的人,或者在{explore}上找到熱門使用者。"
|
||||||
step5_3: "想要追隨其他人,只要點擊他們的頭像並按「追隨」即可。"
|
step5_3: "想要追隨其他人,只要點擊他們的頭像並按「追隨」即可。"
|
||||||
step5_4: "如果使用者的名字旁有鎖頭的圖示,代表他們需要手動核准你的追隨請求。"
|
step5_4: "如果使用者的名字旁有鎖頭的圖示,代表他們需要手動核准你的追隨請求。"
|
||||||
step6_1: "現在你可以在時間軸上看到其他用戶的貼文"
|
step6_1: "現在你可以在時間軸上看到其他用戶的貼文"
|
||||||
@ -602,6 +669,8 @@ _tutorial:
|
|||||||
step6_3: "在他人的貼文按下「+」的圖示即可選擇想要的表情符號來進行「反應」。"
|
step6_3: "在他人的貼文按下「+」的圖示即可選擇想要的表情符號來進行「反應」。"
|
||||||
step7_1: "以上為Misskey的基本操作說明,教學在此告一段落。辛苦了。"
|
step7_1: "以上為Misskey的基本操作說明,教學在此告一段落。辛苦了。"
|
||||||
step7_2: "歡迎到{help}來瞭解更多Misskey相關介紹。"
|
step7_2: "歡迎到{help}來瞭解更多Misskey相關介紹。"
|
||||||
|
_2fa:
|
||||||
|
registerDevice: "註冊裝置"
|
||||||
_permissions:
|
_permissions:
|
||||||
"read:blocks": "已封鎖用戶名單"
|
"read:blocks": "已封鎖用戶名單"
|
||||||
"write:blocks": "編輯已封鎖用戶名單"
|
"write:blocks": "編輯已封鎖用戶名單"
|
||||||
@ -610,15 +679,32 @@ _permissions:
|
|||||||
"read:favorites": "瀏覽已收藏"
|
"read:favorites": "瀏覽已收藏"
|
||||||
"write:favorites": "編輯收藏清單"
|
"write:favorites": "編輯收藏清單"
|
||||||
"write:following": "追隨/解除追隨"
|
"write:following": "追隨/解除追隨"
|
||||||
|
"read:messaging": "顯示訊息"
|
||||||
|
"write:messaging": "撰寫或刪除私人訊息"
|
||||||
|
"read:mutes": "顯示已靜音列表"
|
||||||
|
"write:mutes": "編輯已靜音列表"
|
||||||
"write:notes": "撰寫或刪除貼文"
|
"write:notes": "撰寫或刪除貼文"
|
||||||
"read:notifications": "查看通知"
|
"read:notifications": "查看通知"
|
||||||
|
"write:notifications": "編輯通知"
|
||||||
"read:reactions": "查看反應"
|
"read:reactions": "查看反應"
|
||||||
"write:reactions": "編輯反應"
|
"write:reactions": "編輯反應"
|
||||||
"write:votes": "投票"
|
"write:votes": "投票"
|
||||||
|
"read:pages": "顯示頁面"
|
||||||
|
"write:pages": "編輯頁面"
|
||||||
|
"read:page-likes": "顯示頁面的已喜歡"
|
||||||
|
"write:page-likes": "編輯頁面上喜歡"
|
||||||
|
"read:user-groups": "顯示使用者群組"
|
||||||
|
"write:user-groups": "編輯使用者群組"
|
||||||
"read:channels": "已查看的頻道"
|
"read:channels": "已查看的頻道"
|
||||||
"write:channels": "操作頻道"
|
"write:channels": "編輯頻道"
|
||||||
|
_auth:
|
||||||
|
shareAccess: "要授權「“{name}”」存取您的帳戶嗎?"
|
||||||
_antennaSources:
|
_antennaSources:
|
||||||
all: "全部貼文"
|
all: "全部貼文"
|
||||||
|
homeTimeline: "來自已追隨使用者的貼文"
|
||||||
|
users: "來自特定使用者的貼文"
|
||||||
|
userList: "來自特定清單中的貼文"
|
||||||
|
userGroup: "來自特定群組的貼文"
|
||||||
_weekday:
|
_weekday:
|
||||||
sunday: "週日"
|
sunday: "週日"
|
||||||
monday: "週一"
|
monday: "週一"
|
||||||
@ -648,68 +734,216 @@ _poll:
|
|||||||
noOnlyOneChoice: "至少需要兩個選項。"
|
noOnlyOneChoice: "至少需要兩個選項。"
|
||||||
expiration: "期限"
|
expiration: "期限"
|
||||||
infinite: "無期限"
|
infinite: "無期限"
|
||||||
|
at: "結束時間"
|
||||||
deadlineDate: "截止日期"
|
deadlineDate: "截止日期"
|
||||||
deadlineTime: "小時"
|
deadlineTime: "小時"
|
||||||
|
duration: "時長"
|
||||||
votesCount: "{n}票"
|
votesCount: "{n}票"
|
||||||
totalVotes: "一共{n}票"
|
totalVotes: "一共{n}票"
|
||||||
vote: "投票"
|
vote: "投票"
|
||||||
showResult: "顯示結果"
|
showResult: "顯示結果"
|
||||||
voted: "已投票"
|
voted: "已投票"
|
||||||
closed: "已結束"
|
closed: "已結束"
|
||||||
|
remainingDays: "{d}天{h}小時後結束"
|
||||||
_visibility:
|
_visibility:
|
||||||
|
public: "公開"
|
||||||
home: "首頁"
|
home: "首頁"
|
||||||
followers: "追隨者"
|
followers: "追隨者"
|
||||||
|
specified: "指定使用者"
|
||||||
|
specifiedDescription: "僅發送至指定使用者"
|
||||||
localOnly: "僅限本地"
|
localOnly: "僅限本地"
|
||||||
|
localOnlyDescription: "對遠端使用者隱藏"
|
||||||
_postForm:
|
_postForm:
|
||||||
|
replyPlaceholder: "回覆此貼文..."
|
||||||
|
quotePlaceholder: "引用此貼文..."
|
||||||
channelPlaceholder: "發佈到頻道"
|
channelPlaceholder: "發佈到頻道"
|
||||||
|
_placeholders:
|
||||||
|
a: "今天過得如何?"
|
||||||
|
b: "有什麼新鮮事嗎?"
|
||||||
|
c: "有什麼新鮮想法嗎?"
|
||||||
|
d: "想要發布些什麼嗎?"
|
||||||
|
e: "寫些什麼吧..."
|
||||||
|
f: "期待你發佈的內容..."
|
||||||
_profile:
|
_profile:
|
||||||
name: "名稱"
|
name: "名稱"
|
||||||
username: "使用名稱"
|
username: "使用者名稱"
|
||||||
|
description: "關於我"
|
||||||
|
youCanIncludeHashtags: "你也可以在「關於我」中加上 #tag"
|
||||||
|
metadata: "更多資訊"
|
||||||
metadataLabel: "標籤"
|
metadataLabel: "標籤"
|
||||||
metadataContent: "内容"
|
metadataContent: "内容"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
allNotes: "全部貼文"
|
allNotes: "全部貼文"
|
||||||
followingList: "追隨中"
|
followingList: "追隨中"
|
||||||
muteList: "消音"
|
muteList: "靜音"
|
||||||
blockingList: "封鎖"
|
blockingList: "封鎖"
|
||||||
userLists: "清單"
|
userLists: "清單"
|
||||||
_charts:
|
_charts:
|
||||||
|
usersIncDec: "使用者増減"
|
||||||
|
usersTotal: "使用者合共"
|
||||||
|
activeUsers: "活躍使用者"
|
||||||
|
notesIncDec: "貼文増減"
|
||||||
|
localNotesIncDec: "本地貼文増減"
|
||||||
remoteNotesIncDec: "非本地貼文的數目增减"
|
remoteNotesIncDec: "非本地貼文的數目增减"
|
||||||
|
notesTotal: "貼文合共"
|
||||||
|
filesIncDec: "檔案増減"
|
||||||
|
filesTotal: "累計檔案"
|
||||||
|
storageUsageIncDec: "儲存空間的増減"
|
||||||
|
storageUsageTotal: "已使用的儲存空間合共"
|
||||||
_instanceCharts:
|
_instanceCharts:
|
||||||
|
requests: "請求"
|
||||||
|
users: "使用者増減"
|
||||||
|
usersTotal: "總計使用者"
|
||||||
|
notes: "貼文増減"
|
||||||
|
notesTotal: "累計貼文"
|
||||||
|
ff: "追隨/追隨者的増減"
|
||||||
|
ffTotal: "追隨/追隨者累計"
|
||||||
cacheSize: "增加或減少快取用量"
|
cacheSize: "增加或減少快取用量"
|
||||||
cacheSizeTotal: "快取大小總計"
|
cacheSizeTotal: "快取大小總計"
|
||||||
|
files: "檔案數量的増減"
|
||||||
|
filesTotal: "檔案數量總計"
|
||||||
_timelines:
|
_timelines:
|
||||||
home: "首頁"
|
home: "首頁"
|
||||||
|
local: "本地"
|
||||||
|
social: "社群"
|
||||||
|
global: "全域"
|
||||||
_rooms:
|
_rooms:
|
||||||
|
roomOf: "{user}的房間"
|
||||||
|
addFurniture: "擺放家具"
|
||||||
|
translate: "移動 "
|
||||||
|
rotate: "旋轉"
|
||||||
|
exit: "返回"
|
||||||
|
remove: "移除"
|
||||||
|
clear: "全部移除"
|
||||||
|
clearConfirm: "確定要移除全部家具嗎?"
|
||||||
|
leaveConfirm: "修改未儲存,是否要離開?"
|
||||||
|
chooseImage: "選擇圖像"
|
||||||
|
roomType: "房間種類"
|
||||||
|
carpetColor: "地板顏色"
|
||||||
_roomType:
|
_roomType:
|
||||||
default: "預設"
|
default: "預設"
|
||||||
|
washitsu: "和室"
|
||||||
_furnitures:
|
_furnitures:
|
||||||
|
milk: "牛奶盒"
|
||||||
|
bed: "床"
|
||||||
|
low-table: "咖啡桌"
|
||||||
|
desk: "書桌"
|
||||||
|
chair: "椅子"
|
||||||
|
chair2: "椅子2"
|
||||||
|
fan: "通風機"
|
||||||
|
pc: "電腦"
|
||||||
|
plant: "觀葉植物"
|
||||||
|
plant2: "觀葉植物2"
|
||||||
|
eraser: "橡皮擦"
|
||||||
|
pencil: "鉛筆"
|
||||||
|
pudding: "布丁"
|
||||||
|
cardboard-box: "紙板箱"
|
||||||
|
cardboard-box2: "紙板箱2"
|
||||||
|
cardboard-box3: "紙板箱3"
|
||||||
|
book: "讀物"
|
||||||
|
book2: "讀物2"
|
||||||
|
piano: "鋼琴"
|
||||||
|
moon: "月亮"
|
||||||
|
corkboard: "木栓板"
|
||||||
|
mousepad: "滑鼠墊"
|
||||||
monitor: "監視器"
|
monitor: "監視器"
|
||||||
keyboard: "鍵盤"
|
keyboard: "鍵盤"
|
||||||
|
carpet-stripe: "條紋地毯"
|
||||||
|
bin: "垃圾箱"
|
||||||
|
cup-noodle: "杯面"
|
||||||
|
holo-display: "投影機"
|
||||||
|
energy-drink: "能量飲料"
|
||||||
|
doll-ai: "小藍的人偶公仔"
|
||||||
|
banknote: "大疊鈔票"
|
||||||
_pages:
|
_pages:
|
||||||
|
newPage: "建立頁面"
|
||||||
|
editPage: "編輯頁面"
|
||||||
|
created: "頁面已建立"
|
||||||
|
updated: "頁面已更新"
|
||||||
deleted: "頁面已被刪除"
|
deleted: "頁面已被刪除"
|
||||||
|
editThisPage: "編輯此頁面"
|
||||||
|
viewSource: "檢視原始碼"
|
||||||
|
viewPage: "顯示頁面"
|
||||||
like: "喜歡"
|
like: "喜歡"
|
||||||
unlike: "收回喜歡"
|
unlike: "收回喜歡"
|
||||||
|
my: "我的頁面"
|
||||||
|
liked: "已喜歡的頁面"
|
||||||
|
inspector: "面板檢查"
|
||||||
|
variables: "變數"
|
||||||
|
title: "標題"
|
||||||
|
url: "頁面網址"
|
||||||
|
font: "字型"
|
||||||
|
fontSerif: "襯線體"
|
||||||
|
fontSansSerif: "無襯線體"
|
||||||
|
inputBlocks: "輸入"
|
||||||
blocks:
|
blocks:
|
||||||
|
text: "文本"
|
||||||
|
textarea: "文字區域"
|
||||||
|
section: "區段"
|
||||||
image: "圖片"
|
image: "圖片"
|
||||||
|
button: "按鈕"
|
||||||
|
if: "如果"
|
||||||
|
_if:
|
||||||
|
variable: "變數"
|
||||||
_post:
|
_post:
|
||||||
text: "内容"
|
text: "内容"
|
||||||
|
canvasId: "畫布ID"
|
||||||
|
textInput: "插入文字"
|
||||||
|
_textInput:
|
||||||
|
name: "變數名稱"
|
||||||
|
text: "標題"
|
||||||
|
default: "預設值"
|
||||||
|
textareaInput: "多行文字输入"
|
||||||
_textareaInput:
|
_textareaInput:
|
||||||
name: "變數名稱"
|
name: "變數名稱"
|
||||||
|
text: "標題"
|
||||||
|
default: "預設值"
|
||||||
numberInput: "輸入數值"
|
numberInput: "輸入數值"
|
||||||
_numberInput:
|
_numberInput:
|
||||||
name: "變數名稱"
|
name: "變數名稱"
|
||||||
_canvas:
|
|
||||||
width: "寬度"
|
|
||||||
_counter:
|
|
||||||
text: "標題"
|
text: "標題"
|
||||||
|
default: "預設值"
|
||||||
|
canvas: "畫布"
|
||||||
|
_canvas:
|
||||||
|
id: "畫布ID"
|
||||||
|
width: "寬度"
|
||||||
|
height: "高度"
|
||||||
|
switch: "開關"
|
||||||
|
_switch:
|
||||||
|
name: "變數名稱"
|
||||||
|
text: "標題"
|
||||||
|
default: "預設值"
|
||||||
|
counter: "計數器"
|
||||||
|
_counter:
|
||||||
|
name: "變數名稱"
|
||||||
|
text: "標題"
|
||||||
|
inc: "増加値"
|
||||||
_button:
|
_button:
|
||||||
text: "標題"
|
text: "標題"
|
||||||
|
colored: "彩色"
|
||||||
|
action: "按下按鈕後發生的行為"
|
||||||
_action:
|
_action:
|
||||||
_dialog:
|
_dialog:
|
||||||
content: "内容"
|
content: "内容"
|
||||||
|
resetRandom: "重設亂數"
|
||||||
|
pushEvent: "發送事件"
|
||||||
|
_pushEvent:
|
||||||
|
event: "事件名稱"
|
||||||
|
no-variable: "沒有"
|
||||||
|
callAiScript: "調用AiScript"
|
||||||
|
_callAiScript:
|
||||||
|
functionName: "函數名稱"
|
||||||
|
radioButton: "選項"
|
||||||
|
_radioButton:
|
||||||
|
name: "變數名稱"
|
||||||
|
title: "標題"
|
||||||
|
default: "預設值"
|
||||||
script:
|
script:
|
||||||
categories:
|
categories:
|
||||||
|
logical: "邏輯運算"
|
||||||
|
operation: "計算"
|
||||||
|
comparison: "對比"
|
||||||
|
random: "隨機"
|
||||||
value: "數值 "
|
value: "數值 "
|
||||||
fn: "函数"
|
fn: "函数"
|
||||||
text: "文本操作"
|
text: "文本操作"
|
||||||
@ -719,6 +953,8 @@ _pages:
|
|||||||
text: "文本"
|
text: "文本"
|
||||||
multiLineText: "文本 (多行)"
|
multiLineText: "文本 (多行)"
|
||||||
textList: "文本列表"
|
textList: "文本列表"
|
||||||
|
_strLen:
|
||||||
|
arg1: "文本"
|
||||||
_strPick:
|
_strPick:
|
||||||
arg1: "文本"
|
arg1: "文本"
|
||||||
arg2: "字元位置"
|
arg2: "字元位置"
|
||||||
@ -732,18 +968,22 @@ _pages:
|
|||||||
_add:
|
_add:
|
||||||
arg1: "A"
|
arg1: "A"
|
||||||
arg2: "B"
|
arg2: "B"
|
||||||
|
subtract: "减去"
|
||||||
_subtract:
|
_subtract:
|
||||||
arg1: "A"
|
arg1: "A"
|
||||||
arg2: "B"
|
arg2: "B"
|
||||||
|
multiply: "乘"
|
||||||
_multiply:
|
_multiply:
|
||||||
arg1: "A"
|
arg1: "A"
|
||||||
arg2: "B"
|
arg2: "B"
|
||||||
|
divide: "除"
|
||||||
_divide:
|
_divide:
|
||||||
arg1: "A"
|
arg1: "A"
|
||||||
arg2: "B"
|
arg2: "B"
|
||||||
_mod:
|
_mod:
|
||||||
arg1: "A"
|
arg1: "A"
|
||||||
arg2: "B"
|
arg2: "B"
|
||||||
|
round: "四舍五入"
|
||||||
_round:
|
_round:
|
||||||
arg1: "數值"
|
arg1: "數值"
|
||||||
eq: "A和B相等"
|
eq: "A和B相等"
|
||||||
@ -785,6 +1025,7 @@ _pages:
|
|||||||
not: "否"
|
not: "否"
|
||||||
_not:
|
_not:
|
||||||
arg1: "否"
|
arg1: "否"
|
||||||
|
random: "隨機"
|
||||||
_random:
|
_random:
|
||||||
arg1: "機率"
|
arg1: "機率"
|
||||||
rannum: "亂數"
|
rannum: "亂數"
|
||||||
@ -827,6 +1068,8 @@ _pages:
|
|||||||
arg1: "文字"
|
arg1: "文字"
|
||||||
_numberToString:
|
_numberToString:
|
||||||
arg1: "數值"
|
arg1: "數值"
|
||||||
|
_splitStrByLine:
|
||||||
|
arg1: "文本"
|
||||||
ref: "變數"
|
ref: "變數"
|
||||||
aiScriptVar: "AiScript的變數"
|
aiScriptVar: "AiScript的變數"
|
||||||
fn: "函数"
|
fn: "函数"
|
||||||
@ -842,6 +1085,7 @@ _pages:
|
|||||||
array: "清單"
|
array: "清單"
|
||||||
stringArray: "文本列表"
|
stringArray: "文本列表"
|
||||||
enviromentVariables: "環境變數"
|
enviromentVariables: "環境變數"
|
||||||
|
pageVariables: "頁面元素"
|
||||||
_relayStatus:
|
_relayStatus:
|
||||||
requesting: "等待核准"
|
requesting: "等待核准"
|
||||||
accepted: "已通過核准"
|
accepted: "已通過核准"
|
||||||
@ -853,15 +1097,31 @@ _notification:
|
|||||||
yourFollowRequestAccepted: "您的追隨請求已通過"
|
yourFollowRequestAccepted: "您的追隨請求已通過"
|
||||||
youWereInvitedToGroup: "您有新的群組邀請"
|
youWereInvitedToGroup: "您有新的群組邀請"
|
||||||
_types:
|
_types:
|
||||||
|
all: "全部 "
|
||||||
follow: "追隨中"
|
follow: "追隨中"
|
||||||
mention: "提及"
|
mention: "提及"
|
||||||
|
reply: "回覆"
|
||||||
renote: "轉發貼文"
|
renote: "轉發貼文"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "反應"
|
reaction: "反應"
|
||||||
|
receiveFollowRequest: "已收到追隨請求"
|
||||||
|
followRequestAccepted: "追隨請求已接受"
|
||||||
|
app: "應用程式通知"
|
||||||
_deck:
|
_deck:
|
||||||
|
alwaysShowMainColumn: "總是顯示主欄"
|
||||||
|
columnAlign: "對齊欄位"
|
||||||
|
addColumn: "新增欄位"
|
||||||
|
swapLeft: "向左移動"
|
||||||
|
swapRight: "向右移動"
|
||||||
|
swapUp: "往上移動"
|
||||||
|
swapDown: "往下移動"
|
||||||
|
stackLeft: "向左折疊"
|
||||||
|
popRight: "向右彈出"
|
||||||
_columns:
|
_columns:
|
||||||
|
widgets: "小工具"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
tl: "時間軸"
|
tl: "時間軸"
|
||||||
antenna: "天線"
|
antenna: "天線"
|
||||||
list: "清單"
|
list: "清單"
|
||||||
mentions: "提及"
|
mentions: "提及"
|
||||||
|
direct: "指定使用者"
|
||||||
|
@ -11,7 +11,7 @@ export class refineAbuseUserReport1603094348345 implements MigrationInterface {
|
|||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "assigneeId" character varying(32)`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "assigneeId" character varying(32)`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "resolved" boolean NOT NULL DEFAULT false`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "resolved" boolean NOT NULL DEFAULT false`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "comment"`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "comment"`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "comment" character varying(2048) NOT NULL`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "comment" character varying(2048) NOT NULL DEFAULT '{}'::varchar[]`);
|
||||||
await queryRunner.query(`CREATE INDEX "IDX_2b15aaf4a0dc5be3499af7ab6a" ON "abuse_user_report" ("resolved") `);
|
await queryRunner.query(`CREATE INDEX "IDX_2b15aaf4a0dc5be3499af7ab6a" ON "abuse_user_report" ("resolved") `);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_08b883dd5fdd6f9c4c1572b36de" FOREIGN KEY ("assigneeId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_08b883dd5fdd6f9c4c1572b36de" FOREIGN KEY ("assigneeId") REFERENCES "user"("id") ON DELETE SET NULL ON UPDATE NO ACTION`);
|
||||||
}
|
}
|
||||||
@ -20,7 +20,7 @@ export class refineAbuseUserReport1603094348345 implements MigrationInterface {
|
|||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_08b883dd5fdd6f9c4c1572b36de"`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_08b883dd5fdd6f9c4c1572b36de"`);
|
||||||
await queryRunner.query(`DROP INDEX "IDX_2b15aaf4a0dc5be3499af7ab6a"`);
|
await queryRunner.query(`DROP INDEX "IDX_2b15aaf4a0dc5be3499af7ab6a"`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "comment"`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "comment"`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "comment" character varying(512) NOT NULL`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "comment" character varying(512) NOT NULL DEFAULT '{}'::varchar[]`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "resolved"`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "resolved"`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "assigneeId"`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "assigneeId"`);
|
||||||
await queryRunner.query(`ALTER TABLE "abuse_user_report" RENAME COLUMN "targetUserId" TO "userId"`);
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" RENAME COLUMN "targetUserId" TO "userId"`);
|
||||||
|
14
migration/1603776877564-instance-theme-color.ts
Normal file
14
migration/1603776877564-instance-theme-color.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class instanceThemeColor1603776877564 implements MigrationInterface {
|
||||||
|
name = 'instanceThemeColor1603776877564'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" ADD "themeColor" character varying(64) DEFAULT null`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "themeColor"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
migration/1603781553011-instance-favicon.ts
Normal file
14
migration/1603781553011-instance-favicon.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class instanceFavicon1603781553011 implements MigrationInterface {
|
||||||
|
name = 'instanceFavicon1603781553011'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" ADD "faviconUrl" character varying(256) DEFAULT null`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "instance" DROP COLUMN "faviconUrl"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
14
migration/1604821689616-delete-auto-watch.ts
Normal file
14
migration/1604821689616-delete-auto-watch.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class deleteAutoWatch1604821689616 implements MigrationInterface {
|
||||||
|
name = 'deleteAutoWatch1604821689616'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" DROP COLUMN "autoWatch"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "user_profile" ADD "autoWatch" boolean NOT NULL DEFAULT false`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
53
package.json
53
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||||
"version": "12.49.1",
|
"version": "12.55.0",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@ -99,51 +99,50 @@
|
|||||||
"@types/tmp": "0.2.0",
|
"@types/tmp": "0.2.0",
|
||||||
"@types/uuid": "8.3.0",
|
"@types/uuid": "8.3.0",
|
||||||
"@types/web-push": "3.3.0",
|
"@types/web-push": "3.3.0",
|
||||||
"@types/webpack": "4.41.22",
|
"@types/webpack": "4.41.24",
|
||||||
"@types/webpack-stream": "3.2.11",
|
"@types/webpack-stream": "3.2.11",
|
||||||
"@types/websocket": "1.0.1",
|
"@types/websocket": "1.0.1",
|
||||||
"@types/ws": "7.2.7",
|
"@types/ws": "7.2.7",
|
||||||
"@typescript-eslint/parser": "4.4.0",
|
"@typescript-eslint/parser": "4.6.1",
|
||||||
"@vue/compiler-sfc": "3.0.2",
|
"@vue/compiler-sfc": "3.0.2",
|
||||||
"abort-controller": "3.0.0",
|
"abort-controller": "3.0.0",
|
||||||
"apexcharts": "3.22.0",
|
"apexcharts": "3.22.1",
|
||||||
"autobind-decorator": "2.4.0",
|
"autobind-decorator": "2.4.0",
|
||||||
"autosize": "4.0.2",
|
"autosize": "4.0.2",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
"aws-sdk": "2.770.0",
|
"aws-sdk": "2.787.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "1.1.3",
|
"blurhash": "1.1.3",
|
||||||
"bull": "3.18.0",
|
"bull": "3.18.1",
|
||||||
"cafy": "15.2.1",
|
"cafy": "15.2.1",
|
||||||
"cbor": "5.1.0",
|
"cbor": "5.1.0",
|
||||||
"chalk": "4.1.0",
|
"chalk": "4.1.0",
|
||||||
"chart.js": "2.9.3",
|
"chart.js": "2.9.4",
|
||||||
"cli-highlight": "2.1.4",
|
"cli-highlight": "2.1.4",
|
||||||
"commander": "4.1.1",
|
"commander": "4.1.1",
|
||||||
"content-disposition": "0.5.3",
|
"content-disposition": "0.5.3",
|
||||||
"core-js": "3.6.5",
|
"core-js": "3.7.0",
|
||||||
"crc-32": "1.2.0",
|
"crc-32": "1.2.0",
|
||||||
"css-loader": "5.0.0",
|
"css-loader": "5.0.1",
|
||||||
"cssnano": "4.1.10",
|
"cssnano": "4.1.10",
|
||||||
"dateformat": "3.0.3",
|
"dateformat": "3.0.3",
|
||||||
"deep-entries": "3.1.0",
|
"deep-entries": "3.1.0",
|
||||||
"diskusage": "1.1.3",
|
"diskusage": "1.1.3",
|
||||||
"double-ended-queue": "2.1.0-0",
|
"double-ended-queue": "2.1.0-0",
|
||||||
"escape-regexp": "0.0.1",
|
"escape-regexp": "0.0.1",
|
||||||
"eslint": "7.11.0",
|
"eslint": "7.12.1",
|
||||||
"eslint-plugin-vue": "7.1.0",
|
"eslint-plugin-vue": "7.1.0",
|
||||||
"eventemitter3": "4.0.7",
|
"eventemitter3": "4.0.7",
|
||||||
"feed": "4.2.1",
|
"feed": "4.2.1",
|
||||||
"fibers": "5.0.0",
|
"fibers": "5.0.0",
|
||||||
"file-type": "16.0.0",
|
"file-type": "16.0.1",
|
||||||
"fluent-ffmpeg": "2.1.2",
|
"fluent-ffmpeg": "2.1.2",
|
||||||
"glob": "7.1.6",
|
"glob": "7.1.6",
|
||||||
"got": "11.7.0",
|
"got": "11.8.0",
|
||||||
"gulp": "4.0.2",
|
"gulp": "4.0.2",
|
||||||
"gulp-rename": "2.0.0",
|
"gulp-rename": "2.0.0",
|
||||||
"gulp-replace": "1.0.0",
|
"gulp-replace": "1.0.0",
|
||||||
"gulp-sourcemaps": "2.6.5",
|
"gulp-sourcemaps": "2.6.5",
|
||||||
"gulp-terser": "1.4.0",
|
|
||||||
"gulp-tslint": "8.1.4",
|
"gulp-tslint": "8.1.4",
|
||||||
"gulp-typescript": "6.0.0-alpha.1",
|
"gulp-typescript": "6.0.0-alpha.1",
|
||||||
"hard-source-webpack-plugin": "0.13.1",
|
"hard-source-webpack-plugin": "0.13.1",
|
||||||
@ -176,24 +175,24 @@
|
|||||||
"lookup-dns-cache": "2.1.0",
|
"lookup-dns-cache": "2.1.0",
|
||||||
"markdown-it": "11.0.1",
|
"markdown-it": "11.0.1",
|
||||||
"markdown-it-anchor": "6.0.0",
|
"markdown-it-anchor": "6.0.0",
|
||||||
"mocha": "8.1.3",
|
"mocha": "8.2.1",
|
||||||
"moji": "0.5.1",
|
"moji": "0.5.1",
|
||||||
"ms": "2.1.2",
|
"ms": "2.1.2",
|
||||||
"multer": "1.4.2",
|
"multer": "1.4.2",
|
||||||
"nested-property": "4.0.0",
|
"nested-property": "4.0.0",
|
||||||
"node-fetch": "2.6.1",
|
"node-fetch": "2.6.1",
|
||||||
"nodemailer": "6.4.13",
|
"nodemailer": "6.4.15",
|
||||||
"object-assign-deep": "0.4.0",
|
"object-assign-deep": "0.4.0",
|
||||||
"os-utils": "0.0.14",
|
"os-utils": "0.0.14",
|
||||||
"p-cancelable": "2.0.0",
|
"p-cancelable": "2.0.0",
|
||||||
"parse5": "6.0.1",
|
"parse5": "6.0.1",
|
||||||
"parsimmon": "1.16.0",
|
"parsimmon": "1.16.0",
|
||||||
"pg": "8.4.1",
|
"pg": "8.4.2",
|
||||||
"portscanner": "2.2.0",
|
"portscanner": "2.2.0",
|
||||||
"postcss": "8.1.2",
|
"postcss": "8.1.6",
|
||||||
"postcss-loader": "4.0.4",
|
"postcss-loader": "4.0.4",
|
||||||
"prismjs": "1.22.0",
|
"prismjs": "1.22.0",
|
||||||
"probe-image-size": "5.0.0",
|
"probe-image-size": "6.0.0",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
"promise-sequential": "1.1.1",
|
"promise-sequential": "1.1.1",
|
||||||
"pug": "2.0.4",
|
"pug": "2.0.4",
|
||||||
@ -215,8 +214,8 @@
|
|||||||
"rimraf": "3.0.2",
|
"rimraf": "3.0.2",
|
||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sass": "1.27.0",
|
"sass": "1.29.0",
|
||||||
"sass-loader": "10.0.3",
|
"sass-loader": "10.0.5",
|
||||||
"seedrandom": "3.0.5",
|
"seedrandom": "3.0.5",
|
||||||
"sharp": "0.26.2",
|
"sharp": "0.26.2",
|
||||||
"speakeasy": "2.0.0",
|
"speakeasy": "2.0.0",
|
||||||
@ -224,18 +223,18 @@
|
|||||||
"style-loader": "2.0.0",
|
"style-loader": "2.0.0",
|
||||||
"summaly": "2.4.0",
|
"summaly": "2.4.0",
|
||||||
"syslog-pro": "1.0.0",
|
"syslog-pro": "1.0.0",
|
||||||
"systeminformation": "4.27.8",
|
"systeminformation": "4.28.1",
|
||||||
"syuilo-password-strength": "0.0.1",
|
"syuilo-password-strength": "0.0.1",
|
||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"three": "0.117.1",
|
"three": "0.117.1",
|
||||||
"tinycolor2": "1.4.2",
|
"tinycolor2": "1.4.2",
|
||||||
"tmp": "0.2.1",
|
"tmp": "0.2.1",
|
||||||
"ts-loader": "8.0.6",
|
"ts-loader": "8.0.9",
|
||||||
"ts-node": "9.0.0",
|
"ts-node": "9.0.0",
|
||||||
"tslint": "6.1.3",
|
"tslint": "6.1.3",
|
||||||
"tslint-sonarts": "1.9.0",
|
"tslint-sonarts": "1.9.0",
|
||||||
"typeorm": "0.2.28",
|
"typeorm": "0.2.29",
|
||||||
"typescript": "4.0.3",
|
"typescript": "4.0.5",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.3.0",
|
||||||
"url-loader": "4.1.1",
|
"url-loader": "4.1.1",
|
||||||
"uuid": "8.3.1",
|
"uuid": "8.3.1",
|
||||||
@ -244,7 +243,7 @@
|
|||||||
"vue-color": "2.7.1",
|
"vue-color": "2.7.1",
|
||||||
"vue-draggable-next": "1.0.8",
|
"vue-draggable-next": "1.0.8",
|
||||||
"vue-i18n": "9.0.0-beta.6",
|
"vue-i18n": "9.0.0-beta.6",
|
||||||
"vue-json-pretty": "1.7.0",
|
"vue-json-pretty": "1.7.1",
|
||||||
"vue-loader": "16.0.0-beta.8",
|
"vue-loader": "16.0.0-beta.8",
|
||||||
"vue-prism-editor": "1.2.2",
|
"vue-prism-editor": "1.2.2",
|
||||||
"vue-router": "4.0.0-beta.13",
|
"vue-router": "4.0.0-beta.13",
|
||||||
@ -253,8 +252,8 @@
|
|||||||
"vuex": "4.0.0-beta.4",
|
"vuex": "4.0.0-beta.4",
|
||||||
"vuex-persistedstate": "3.1.0",
|
"vuex-persistedstate": "3.1.0",
|
||||||
"web-push": "3.4.4",
|
"web-push": "3.4.4",
|
||||||
"webpack": "5.1.3",
|
"webpack": "5.4.0",
|
||||||
"webpack-cli": "4.1.0",
|
"webpack-cli": "4.2.0",
|
||||||
"websocket": "1.0.32",
|
"websocket": "1.0.32",
|
||||||
"ws": "7.3.1",
|
"ws": "7.3.1",
|
||||||
"xev": "2.0.1"
|
"xev": "2.0.1"
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, markRaw } from 'vue';
|
||||||
import { emojilist } from '../../misc/emojilist';
|
import { emojilist } from '../../misc/emojilist';
|
||||||
import contains from '@/scripts/contains';
|
import contains from '@/scripts/contains';
|
||||||
import { twemojiSvgBase } from '../../misc/twemoji-base';
|
import { twemojiSvgBase } from '../../misc/twemoji-base';
|
||||||
@ -122,17 +122,13 @@ export default defineComponent({
|
|||||||
users: [],
|
users: [],
|
||||||
hashtags: [],
|
hashtags: [],
|
||||||
emojis: [],
|
emojis: [],
|
||||||
|
items: [],
|
||||||
select: -1,
|
select: -1,
|
||||||
emojilist,
|
|
||||||
emojiDb: [] as EmojiDef[]
|
emojiDb: [] as EmojiDef[]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
items(): HTMLCollection {
|
|
||||||
return (this.$refs.suggests as Element).children;
|
|
||||||
},
|
|
||||||
|
|
||||||
useOsNativeEmojis(): boolean {
|
useOsNativeEmojis(): boolean {
|
||||||
return this.$store.state.device.useOsNativeEmojis;
|
return this.$store.state.device.useOsNativeEmojis;
|
||||||
}
|
}
|
||||||
@ -148,6 +144,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
updated() {
|
updated() {
|
||||||
this.setPosition();
|
this.setPosition();
|
||||||
|
this.items = (this.$refs.suggests as Element | undefined)?.children || [];
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -180,7 +177,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
|
emojiDefinitions.sort((a, b) => a.name.length - b.name.length);
|
||||||
|
|
||||||
this.emojiDb = emojiDefinitions.concat(emjdb);
|
this.emojiDb = markRaw(emojiDefinitions.concat(emjdb));
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
this.textarea.addEventListener('keydown', this.onKeydown);
|
this.textarea.addEventListener('keydown', this.onKeydown);
|
||||||
@ -371,6 +368,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
selectNext() {
|
selectNext() {
|
||||||
if (++this.select >= this.items.length) this.select = 0;
|
if (++this.select >= this.items.length) this.select = 0;
|
||||||
|
if (this.items.length === 0) this.select = -1;
|
||||||
this.applySelect();
|
this.applySelect();
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -384,8 +382,10 @@ export default defineComponent({
|
|||||||
el.removeAttribute('data-selected');
|
el.removeAttribute('data-selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.select !== -1) {
|
||||||
this.items[this.select].setAttribute('data-selected', 'true');
|
this.items[this.select].setAttribute('data-selected', 'true');
|
||||||
(this.items[this.select] as any).focus();
|
(this.items[this.select] as any).focus();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
chooseUser() {
|
chooseUser() {
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
<span class="eiwwqkts" :class="{ cat }" :title="acct(user)" v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" @click="onClick">
|
<span class="eiwwqkts" :class="{ cat }" :title="acct(user)" v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" @click="onClick">
|
||||||
<img class="inner" :src="url"/>
|
<img class="inner" :src="url"/>
|
||||||
</span>
|
</span>
|
||||||
<router-link class="eiwwqkts" :class="{ cat }" :to="userPage(user)" :title="acct(user)" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
|
<MkA class="eiwwqkts" :class="{ cat }" :to="userPage(user)" :title="acct(user)" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
|
||||||
<img class="inner" :src="url"/>
|
<img class="inner" :src="url"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<router-link :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1">
|
<MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1">
|
||||||
<div class="banner" v-if="channel.bannerUrl" :style="`background-image: url('${channel.bannerUrl}')`">
|
<div class="banner" :style="bannerStyle">
|
||||||
<div class="fade"></div>
|
<div class="fade"></div>
|
||||||
<div class="name"><Fa :icon="faSatelliteDish"/> {{ channel.name }}</div>
|
<div class="name"><Fa :icon="faSatelliteDish"/> {{ channel.name }}</div>
|
||||||
<div class="status">
|
<div class="status">
|
||||||
@ -30,7 +30,7 @@
|
|||||||
{{ $t('updatedAt') }}: <MkTime :time="channel.lastNotedAt"/>
|
{{ $t('updatedAt') }}: <MkTime :time="channel.lastNotedAt"/>
|
||||||
</span>
|
</span>
|
||||||
</footer>
|
</footer>
|
||||||
</router-link>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -45,6 +45,16 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
bannerStyle() {
|
||||||
|
if (this.channel.bannerUrl) {
|
||||||
|
return { backgroundImage: `url(${this.channel.bannerUrl})` };
|
||||||
|
} else {
|
||||||
|
return { backgroundColor: '#4c5e6d' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
faSatelliteDish, faUsers, faPencilAlt,
|
faSatelliteDish, faUsers, faPencilAlt,
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="icon" v-if="icon">
|
<div class="icon" v-if="icon">
|
||||||
<Fa :icon="icon"/>
|
<Fa :icon="icon"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="icon" v-else-if="!input && !select && !user" :class="type">
|
<div class="icon" v-else-if="!input && !select" :class="type">
|
||||||
<Fa :icon="faCheck" v-if="type === 'success'"/>
|
<Fa :icon="faCheck" v-if="type === 'success'"/>
|
||||||
<Fa :icon="faTimesCircle" v-if="type === 'error'"/>
|
<Fa :icon="faTimesCircle" v-if="type === 'error'"/>
|
||||||
<Fa :icon="faExclamationTriangle" v-if="type === 'warning'"/>
|
<Fa :icon="faExclamationTriangle" v-if="type === 'warning'"/>
|
||||||
@ -12,11 +12,9 @@
|
|||||||
<Fa :icon="faQuestionCircle" v-if="type === 'question'"/>
|
<Fa :icon="faQuestionCircle" v-if="type === 'question'"/>
|
||||||
<Fa :icon="faSpinner" pulse v-if="type === 'waiting'"/>
|
<Fa :icon="faSpinner" pulse v-if="type === 'waiting'"/>
|
||||||
</div>
|
</div>
|
||||||
<header v-if="title" v-html="title"></header>
|
<header v-if="title"><Mfm :text="title"/></header>
|
||||||
<header v-if="title == null && user">{{ $t('enterUsername') }}</header>
|
<div class="body" v-if="text"><Mfm :text="text"/></div>
|
||||||
<div class="body" v-if="text" v-html="text"></div>
|
|
||||||
<MkInput v-if="input" v-model:value="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></MkInput>
|
<MkInput v-if="input" v-model:value="inputValue" autofocus :type="input.type || 'text'" :placeholder="input.placeholder" @keydown="onInputKeydown"></MkInput>
|
||||||
<MkInput v-if="user" v-model:value="userInputValue" autofocus @keydown="onInputKeydown"><template #prefix>@</template></MkInput>
|
|
||||||
<MkSelect v-if="select" v-model:value="selectedValue" autofocus>
|
<MkSelect v-if="select" v-model:value="selectedValue" autofocus>
|
||||||
<template v-if="select.items">
|
<template v-if="select.items">
|
||||||
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
|
<option v-for="item in select.items" :value="item.value">{{ item.text }}</option>
|
||||||
@ -28,8 +26,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
<div class="buttons" v-if="(showOkButton || showCancelButton) && !actions">
|
<div class="buttons" v-if="(showOkButton || showCancelButton) && !actions">
|
||||||
<MkButton inline @click="ok" v-if="showOkButton" primary :autofocus="!input && !select && !user" :disabled="!canOk">{{ (showCancelButton || input || select || user) ? $t('ok') : $t('gotIt') }}</MkButton>
|
<MkButton inline @click="ok" v-if="showOkButton" primary :autofocus="!input && !select">{{ (showCancelButton || input || select) ? $t('ok') : $t('gotIt') }}</MkButton>
|
||||||
<MkButton inline @click="cancel" v-if="showCancelButton || input || select || user">{{ $t('cancel') }}</MkButton>
|
<MkButton inline @click="cancel" v-if="showCancelButton || input || select">{{ $t('cancel') }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons" v-if="actions">
|
<div class="buttons" v-if="actions">
|
||||||
<MkButton v-for="action in actions" inline @click="() => { action.callback(); close(); }" :primary="action.primary" :key="action.text">{{ action.text }}</MkButton>
|
<MkButton v-for="action in actions" inline @click="() => { action.callback(); close(); }" :primary="action.primary" :key="action.text">{{ action.text }}</MkButton>
|
||||||
@ -46,8 +44,6 @@ import MkModal from '@/components/ui/modal.vue';
|
|||||||
import MkButton from '@/components/ui/button.vue';
|
import MkButton from '@/components/ui/button.vue';
|
||||||
import MkInput from '@/components/ui/input.vue';
|
import MkInput from '@/components/ui/input.vue';
|
||||||
import MkSelect from '@/components/ui/select.vue';
|
import MkSelect from '@/components/ui/select.vue';
|
||||||
import parseAcct from '../../misc/acct/parse';
|
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -77,9 +73,6 @@ export default defineComponent({
|
|||||||
select: {
|
select: {
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
user: {
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
icon: {
|
icon: {
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
@ -105,28 +98,12 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
inputValue: this.input && this.input.default ? this.input.default : null,
|
inputValue: this.input && this.input.default ? this.input.default : null,
|
||||||
userInputValue: null,
|
|
||||||
selectedValue: this.select ? this.select.default ? this.select.default : this.select.items ? this.select.items[0].value : this.select.groupedItems[0].items[0].value : null,
|
selectedValue: this.select ? this.select.default ? this.select.default : this.select.items ? this.select.items[0].value : this.select.groupedItems[0].items[0].value : null,
|
||||||
canOk: true,
|
|
||||||
faTimesCircle, faQuestionCircle, faSpinner, faInfoCircle, faExclamationTriangle, faCheck
|
faTimesCircle, faQuestionCircle, faSpinner, faInfoCircle, faExclamationTriangle, faCheck
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
|
||||||
userInputValue() {
|
|
||||||
if (this.user) {
|
|
||||||
os.api('users/show', parseAcct(this.userInputValue)).then(u => {
|
|
||||||
this.canOk = u != null;
|
|
||||||
}).catch(() => {
|
|
||||||
this.canOk = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.user) this.canOk = false;
|
|
||||||
|
|
||||||
document.addEventListener('keydown', this.onKeydown);
|
document.addEventListener('keydown', this.onKeydown);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -141,21 +118,13 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
async ok() {
|
async ok() {
|
||||||
if (!this.canOk) return;
|
|
||||||
if (!this.showOkButton) return;
|
if (!this.showOkButton) return;
|
||||||
|
|
||||||
if (this.user) {
|
|
||||||
const user = await os.api('users/show', parseAcct(this.userInputValue));
|
|
||||||
if (user) {
|
|
||||||
this.done(false, user);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const result =
|
const result =
|
||||||
this.input ? this.inputValue :
|
this.input ? this.inputValue :
|
||||||
this.select ? this.selectedValue :
|
this.select ? this.selectedValue :
|
||||||
true;
|
true;
|
||||||
this.done(false, result);
|
this.done(false, result);
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
@ -200,15 +169,15 @@ export default defineComponent({
|
|||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
|
|
||||||
&.success {
|
&.success {
|
||||||
color: var(--accent);
|
color: var(--success);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.error {
|
&.error {
|
||||||
color: #ec4137;
|
color: var(--error);
|
||||||
}
|
}
|
||||||
|
|
||||||
&.warning {
|
&.warning {
|
||||||
color: #ecb637;
|
color: var(--warn);
|
||||||
}
|
}
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
|
70
src/client/components/drive-select-dialog.vue
Normal file
70
src/client/components/drive-select-dialog.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<XModalWindow ref="dialog"
|
||||||
|
:width="800"
|
||||||
|
:height="500"
|
||||||
|
:with-ok-button="true"
|
||||||
|
:ok-button-disabled="(type === 'file') && (selected.length === 0)"
|
||||||
|
@click="cancel()"
|
||||||
|
@close="cancel()"
|
||||||
|
@ok="ok()"
|
||||||
|
@closed="$emit('closed')"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
{{ multiple ? ((type === 'file') ? $t('selectFiles') : $t('selectFolders')) : ((type === 'file') ? $t('selectFile') : $t('selectFolder')) }}
|
||||||
|
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
|
||||||
|
</template>
|
||||||
|
<XDrive :multiple="multiple" @changeSelection="onChangeSelection" @selected="ok()" :select="type"/>
|
||||||
|
</XModalWindow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import XDrive from './drive.vue';
|
||||||
|
import XModalWindow from '@/components/ui/modal-window.vue';
|
||||||
|
import number from '@/filters/number';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XDrive,
|
||||||
|
XModalWindow,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
type: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: 'file'
|
||||||
|
},
|
||||||
|
multiple: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['done', 'closed'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
selected: []
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
ok() {
|
||||||
|
this.$emit('done', this.selected);
|
||||||
|
this.$refs.dialog.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.$emit('done');
|
||||||
|
this.$refs.dialog.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
onChangeSelection(xs) {
|
||||||
|
this.selected = xs;
|
||||||
|
},
|
||||||
|
|
||||||
|
number
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@ -1,72 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<XModalWindow ref="dialog"
|
<XWindow ref="window"
|
||||||
:width="800"
|
:initial-width="800"
|
||||||
:height="500"
|
:initial-height="500"
|
||||||
:with-ok-button="true"
|
:can-resize="true"
|
||||||
:ok-button-disabled="(type === 'file') && (selected.length === 0)"
|
|
||||||
@click="cancel()"
|
|
||||||
@close="cancel()"
|
|
||||||
@ok="ok()"
|
|
||||||
@closed="$emit('closed')"
|
@closed="$emit('closed')"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
{{ multiple ? ((type === 'file') ? $t('selectFiles') : $t('selectFolders')) : ((type === 'file') ? $t('selectFile') : $t('selectFolder')) }}
|
{{ $t('drive') }}
|
||||||
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
|
|
||||||
</template>
|
</template>
|
||||||
<div>
|
<XDrive :initial-folder="initialFolder"/>
|
||||||
<XDrive :multiple="multiple" @changeSelection="onChangeSelection" @selected="ok()" :select="type"/>
|
</XWindow>
|
||||||
</div>
|
|
||||||
</XModalWindow>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import XDrive from './drive.vue';
|
import XDrive from './drive.vue';
|
||||||
import XModalWindow from '@/components/ui/modal-window.vue';
|
import XWindow from '@/components/ui/window.vue';
|
||||||
import number from '@/filters/number';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XDrive,
|
XDrive,
|
||||||
XModalWindow,
|
XWindow,
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
type: {
|
initialFolder: {
|
||||||
type: String,
|
type: Object,
|
||||||
required: false,
|
required: false
|
||||||
default: 'file'
|
|
||||||
},
|
},
|
||||||
multiple: {
|
|
||||||
type: Boolean,
|
|
||||||
default: false
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['done', 'closed'],
|
emits: ['closed'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
selected: []
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
ok() {
|
|
||||||
this.$emit('done', this.selected);
|
|
||||||
this.$refs.dialog.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
cancel() {
|
|
||||||
this.$emit('done');
|
|
||||||
this.$refs.dialog.close();
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeSelection(xs) {
|
|
||||||
this.selected = xs;
|
|
||||||
},
|
|
||||||
|
|
||||||
number
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
<div class="rghtznwe"
|
<div class="rghtznwe"
|
||||||
:class="{ draghover }"
|
:class="{ draghover }"
|
||||||
@click="onClick"
|
@click="onClick"
|
||||||
|
@contextmenu.stop="onContextmenu"
|
||||||
@mouseover="onMouseover"
|
@mouseover="onMouseover"
|
||||||
@mouseout="onMouseout"
|
@mouseout="onMouseout"
|
||||||
@dragover.prevent.stop="onDragover"
|
@dragover.prevent.stop="onDragover"
|
||||||
@ -27,8 +28,9 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { faFolder, faFolderOpen } from '@fortawesome/free-regular-svg-icons';
|
import { faFolder, faFolderOpen, faTrashAlt, faWindowRestore } from '@fortawesome/free-regular-svg-icons';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
import { faICursor } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@ -241,6 +243,28 @@ export default defineComponent({
|
|||||||
value: this.folder.id
|
value: this.folder.id
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onContextmenu(e) {
|
||||||
|
os.contextMenu([{
|
||||||
|
text: this.$t('openInWindow'),
|
||||||
|
icon: faWindowRestore,
|
||||||
|
action: () => {
|
||||||
|
os.popup(import('./drive-window.vue'), {
|
||||||
|
initialFolder: this.folder
|
||||||
|
}, {
|
||||||
|
}, 'closed');
|
||||||
|
}
|
||||||
|
}, null, {
|
||||||
|
text: this.$t('rename'),
|
||||||
|
icon: faICursor,
|
||||||
|
action: this.rename
|
||||||
|
}, null, {
|
||||||
|
text: this.$t('delete'),
|
||||||
|
icon: faTrashAlt,
|
||||||
|
danger: true,
|
||||||
|
action: this.deleteFolder
|
||||||
|
}], e);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@ -64,7 +64,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
initFolder: {
|
initialFolder: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
@ -151,8 +151,8 @@ export default defineComponent({
|
|||||||
this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated);
|
this.connection.on('folderUpdated', this.onStreamDriveFolderUpdated);
|
||||||
this.connection.on('folderDeleted', this.onStreamDriveFolderDeleted);
|
this.connection.on('folderDeleted', this.onStreamDriveFolderDeleted);
|
||||||
|
|
||||||
if (this.initFolder) {
|
if (this.initialFolder) {
|
||||||
this.move(this.initFolder);
|
this.move(this.initialFolder);
|
||||||
} else {
|
} else {
|
||||||
this.fetch();
|
this.fetch();
|
||||||
}
|
}
|
||||||
@ -639,6 +639,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.yfudmmck {
|
.yfudmmck {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
> nav {
|
> nav {
|
||||||
display: block;
|
display: block;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@ -698,6 +702,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
> .main {
|
> .main {
|
||||||
|
flex: 1;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
&, * {
|
&, * {
|
||||||
|
@ -1,75 +1,104 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
|
<MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
|
||||||
<div class="omfetrab _popup">
|
<div class="omfetrab _popup">
|
||||||
<header>
|
<input ref="search" class="search" v-model.trim="q" :placeholder="$t('search')" @paste.stop="paste" @keyup.enter="done()" autofocus>
|
||||||
<button v-for="(category, i) in categories"
|
|
||||||
class="_button"
|
|
||||||
@click="go(category)"
|
|
||||||
:class="{ active: category.isActive }"
|
|
||||||
:key="i"
|
|
||||||
>
|
|
||||||
<Fa :icon="category.icon" fixed-width/>
|
|
||||||
</button>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<div class="emojis">
|
<div class="emojis">
|
||||||
<template v-if="categories[0].isActive">
|
<section class="result">
|
||||||
<header class="category"><Fa :icon="faHistory" fixed-width/> {{ $t('recentUsed') }}</header>
|
<div v-if="searchResultCustom.length > 0">
|
||||||
<div class="list">
|
<button v-for="emoji in searchResultCustom"
|
||||||
<button v-for="emoji in ($store.state.device.recentEmojis || [])"
|
|
||||||
class="_button"
|
class="_button"
|
||||||
:title="emoji.name"
|
:title="emoji.name"
|
||||||
@click="chosen(emoji)"
|
@click="chosen(emoji, $event)"
|
||||||
:key="emoji"
|
:key="emoji"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<MkEmoji v-if="emoji.char != null" :emoji="emoji.char"/>
|
<MkEmoji v-if="emoji.char != null" :emoji="emoji.char"/>
|
||||||
<img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
<img v-else :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="searchResultUnicode.length > 0">
|
||||||
<header class="category"><Fa :icon="faAsterisk" fixed-width/> {{ $t('customEmojis') }}</header>
|
<button v-for="emoji in searchResultUnicode"
|
||||||
</template>
|
|
||||||
|
|
||||||
<template v-if="categories.find(x => x.isActive).name">
|
|
||||||
<div class="list">
|
|
||||||
<button v-for="emoji in emojilist.filter(e => e.category === categories.find(x => x.isActive).name)"
|
|
||||||
class="_button"
|
class="_button"
|
||||||
:title="emoji.name"
|
:title="emoji.name"
|
||||||
@click="chosen(emoji)"
|
@click="chosen(emoji, $event)"
|
||||||
:key="emoji.name"
|
:key="emoji.name"
|
||||||
|
tabindex="0"
|
||||||
>
|
>
|
||||||
<MkEmoji :emoji="emoji.char"/>
|
<MkEmoji :emoji="emoji.char"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</section>
|
||||||
<template v-else>
|
|
||||||
<div v-for="(key, i) in Object.keys(customEmojis)" :key="i">
|
<div class="index">
|
||||||
<header class="sub" v-if="key">{{ key }}</header>
|
<section>
|
||||||
<div class="list">
|
<div>
|
||||||
<button v-for="emoji in customEmojis[key]"
|
<button v-for="emoji in pinned"
|
||||||
|
class="_button"
|
||||||
|
@click="chosen(emoji, $event)"
|
||||||
|
tabindex="0"
|
||||||
|
>
|
||||||
|
<MkEmoji :emoji="emoji" :normal="true"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section>
|
||||||
|
<header class="_acrylic"><Fa :icon="faHistory" fixed-width/> {{ $t('recentUsed') }}</header>
|
||||||
|
<div>
|
||||||
|
<button v-for="emoji in $store.state.device.recentlyUsedEmojis"
|
||||||
|
class="_button"
|
||||||
|
@click="chosen(emoji, $event)"
|
||||||
|
:key="emoji"
|
||||||
|
>
|
||||||
|
<MkEmoji :emoji="emoji" :normal="true"/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="arrow"><Fa :icon="faChevronDown"/></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section v-for="category in customEmojiCategories" :key="'custom:' + category" class="custom">
|
||||||
|
<header class="_acrylic" v-appear="() => visibleCategories[category] = true">{{ category || $t('other') }}</header>
|
||||||
|
<div v-if="visibleCategories[category]">
|
||||||
|
<button v-for="emoji in customEmojis.filter(e => e.category === category)"
|
||||||
class="_button"
|
class="_button"
|
||||||
:title="emoji.name"
|
:title="emoji.name"
|
||||||
@click="chosen(emoji)"
|
@click="chosen(emoji, $event)"
|
||||||
:key="emoji.name"
|
:key="emoji.name"
|
||||||
>
|
>
|
||||||
<img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
<img :src="$store.state.device.disableShowingAnimatedImages ? getStaticImageUrl(emoji.url) : emoji.url"/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section v-for="category in categories" :key="category.name" class="unicode">
|
||||||
|
<header class="_acrylic" v-appear="() => category.isActive = true"><Fa :icon="category.icon" fixed-width/> {{ category.name }}</header>
|
||||||
|
<div v-if="category.isActive">
|
||||||
|
<button v-for="emoji in emojilist.filter(e => e.category === category.name)"
|
||||||
|
class="_button"
|
||||||
|
:title="emoji.name"
|
||||||
|
@click="chosen(emoji, $event)"
|
||||||
|
:key="emoji.name"
|
||||||
|
>
|
||||||
|
<MkEmoji :emoji="emoji.char"/>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</MkModal>
|
</MkModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, markRaw } from 'vue';
|
||||||
import { emojilist } from '../../misc/emojilist';
|
import { emojilist } from '../../misc/emojilist';
|
||||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||||
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser } from '@fortawesome/free-solid-svg-icons';
|
import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faHistory, faUser, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
|
import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { groupByX } from '../../prelude/array';
|
|
||||||
import MkModal from '@/components/ui/modal.vue';
|
import MkModal from '@/components/ui/modal.vue';
|
||||||
|
import Particle from '@/components/particle.vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -80,20 +109,26 @@ export default defineComponent({
|
|||||||
src: {
|
src: {
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
overridePinned: {
|
||||||
|
required: false
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['done', 'closed'],
|
emits: ['done', 'closed'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
emojilist,
|
emojilist: markRaw(emojilist),
|
||||||
getStaticImageUrl,
|
getStaticImageUrl,
|
||||||
customEmojis: {},
|
pinned: this.overridePinned || this.$store.state.settings.reactions,
|
||||||
faGlobe, faHistory,
|
customEmojiCategories: this.$store.getters['instance/emojiCategories'],
|
||||||
|
customEmojis: this.$store.state.instance.meta.emojis,
|
||||||
|
visibleCategories: {},
|
||||||
|
q: null,
|
||||||
|
searchResultCustom: [],
|
||||||
|
searchResultUnicode: [],
|
||||||
|
faGlobe, faHistory, faChevronDown,
|
||||||
categories: [{
|
categories: [{
|
||||||
icon: faAsterisk,
|
|
||||||
isActive: true
|
|
||||||
}, {
|
|
||||||
name: 'face',
|
name: 'face',
|
||||||
icon: faLaugh,
|
icon: faLaugh,
|
||||||
isActive: false
|
isActive: false
|
||||||
@ -134,38 +169,209 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
watch: {
|
||||||
let local = this.$store.state.instance.meta.emojis;
|
q() {
|
||||||
local = groupByX(local, (x: any) => x.category || '');
|
if (this.q == null || this.q === '') {
|
||||||
this.customEmojis = local;
|
this.searchResultCustom = [];
|
||||||
|
this.searchResultUnicode = [];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const q = this.q.replace(/:/g, '');
|
||||||
|
|
||||||
|
const searchCustom = () => {
|
||||||
|
const max = 8;
|
||||||
|
const emojis = this.customEmojis;
|
||||||
|
const matches = new Set();
|
||||||
|
|
||||||
|
const exactMatch = emojis.find(e => e.name === q);
|
||||||
|
if (exactMatch) matches.add(exactMatch);
|
||||||
|
|
||||||
|
if (q.includes(' ')) { // AND検索
|
||||||
|
const keywords = q.split(' ');
|
||||||
|
|
||||||
|
// 名前にキーワードが含まれている
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (keywords.every(keyword => emoji.name.includes(keyword))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
// 名前またはエイリアスにキーワードが含まれている
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (keywords.every(keyword => emoji.name.includes(keyword) || emoji.aliases.some(alias => alias.includes(keyword)))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.name.startsWith(q)) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.aliases.some(alias => alias.startsWith(q))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.name.includes(q)) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.aliases.some(alias => alias.includes(q))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
const searchUnicode = () => {
|
||||||
|
const max = 8;
|
||||||
|
const emojis = this.emojilist;
|
||||||
|
const matches = new Set();
|
||||||
|
|
||||||
|
const exactMatch = emojis.find(e => e.name === q);
|
||||||
|
if (exactMatch) matches.add(exactMatch);
|
||||||
|
|
||||||
|
if (q.includes(' ')) { // AND検索
|
||||||
|
const keywords = q.split(' ');
|
||||||
|
|
||||||
|
// 名前にキーワードが含まれている
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (keywords.every(keyword => emoji.name.includes(keyword))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
// 名前またはエイリアスにキーワードが含まれている
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (keywords.every(keyword => emoji.name.includes(keyword) || emoji.keywords.some(alias => alias.includes(keyword)))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.name.startsWith(q)) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.keywords.some(keyword => keyword.startsWith(q))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.name.includes(q)) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (matches.size >= max) return matches;
|
||||||
|
|
||||||
|
for (const emoji of emojis) {
|
||||||
|
if (emoji.keywords.some(keyword => keyword.includes(q))) {
|
||||||
|
matches.add(emoji);
|
||||||
|
if (matches.size >= max) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matches;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.searchResultCustom = Array.from(searchCustom());
|
||||||
|
this.searchResultUnicode = Array.from(searchUnicode());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.$refs.search.focus({
|
||||||
|
preventScroll: true
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
go(category: any) {
|
getKey(emoji: any) {
|
||||||
this.goCategory(category.name);
|
return typeof emoji === 'string' ? emoji : (emoji.char || `:${emoji.name}:`);
|
||||||
},
|
},
|
||||||
|
|
||||||
goCategory(name: string) {
|
chosen(emoji: any, ev) {
|
||||||
let matched = false;
|
if (ev) {
|
||||||
for (const c of this.categories) {
|
const el = ev.currentTarget || ev.target;
|
||||||
c.isActive = c.name === name;
|
const rect = el.getBoundingClientRect();
|
||||||
if (c.isActive) {
|
const x = rect.left + (el.clientWidth / 2);
|
||||||
matched = true;
|
const y = rect.top + (el.clientHeight / 2);
|
||||||
|
os.popup(Particle, { x, y }, {}, 'end');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!matched) {
|
|
||||||
this.categories[0].isActive = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
chosen(emoji: any) {
|
const key = this.getKey(emoji);
|
||||||
const getKey = (emoji: any) => emoji.char || `:${emoji.name}:`;
|
this.$emit('done', key);
|
||||||
let recents = this.$store.state.device.recentEmojis || [];
|
|
||||||
recents = recents.filter((e: any) => getKey(e) !== getKey(emoji));
|
|
||||||
recents.unshift(emoji)
|
|
||||||
this.$store.commit('device/set', { key: 'recentEmojis', value: recents.splice(0, 16) });
|
|
||||||
this.$emit('done', getKey(emoji));
|
|
||||||
this.$refs.modal.close();
|
this.$refs.modal.close();
|
||||||
|
|
||||||
|
// 最近使った絵文字更新
|
||||||
|
if (!this.pinned.includes(key)) {
|
||||||
|
let recents = this.$store.state.device.recentlyUsedEmojis;
|
||||||
|
recents = recents.filter((e: any) => e !== key);
|
||||||
|
recents.unshift(key);
|
||||||
|
this.$store.commit('device/set', { key: 'recentlyUsedEmojis', value: recents.splice(0, 16) });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
paste(event) {
|
||||||
|
const paste = (event.clipboardData || window.clipboardData).getData('text');
|
||||||
|
if (this.done(paste)) {
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
done(query) {
|
||||||
|
if (query == null) query = this.q;
|
||||||
|
if (query == null) return;
|
||||||
|
const q = query.replace(/:/g, '');
|
||||||
|
const exactMatchCustom = this.customEmojis.find(e => e.name === q);
|
||||||
|
if (exactMatchCustom) {
|
||||||
|
this.chosen(exactMatchCustom);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const exactMatchUnicode = this.emojilist.find(e => e.char === q || e.name === q);
|
||||||
|
if (exactMatchUnicode) {
|
||||||
|
this.chosen(exactMatchUnicode);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this.searchResultCustom.length > 0) {
|
||||||
|
this.chosen(this.searchResultCustom[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (this.searchResultUnicode.length > 0) {
|
||||||
|
this.chosen(this.searchResultUnicode[0]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -174,49 +380,54 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.omfetrab {
|
.omfetrab {
|
||||||
width: 350px;
|
width: 350px;
|
||||||
|
contain: content;
|
||||||
|
|
||||||
> header {
|
> .search {
|
||||||
display: flex;
|
width: 100%;
|
||||||
|
padding: 12px;
|
||||||
> button {
|
box-sizing: border-box;
|
||||||
flex: 1;
|
font-size: 1em;
|
||||||
padding: 10px 0;
|
outline: none;
|
||||||
font-size: 16px;
|
border: none;
|
||||||
transition: color 0.2s ease;
|
background: transparent;
|
||||||
|
color: var(--fg);
|
||||||
&:hover {
|
|
||||||
color: var(--textHighlighted);
|
|
||||||
transition: color 0s;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
color: var(--accent);
|
|
||||||
transition: color 0s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .emojis {
|
> .emojis {
|
||||||
height: 300px;
|
$height: 300px;
|
||||||
|
|
||||||
|
height: $height;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
> header.category {
|
> .index {
|
||||||
|
min-height: $height;
|
||||||
|
position: relative;
|
||||||
|
border-bottom: solid 1px var(--divider);
|
||||||
|
|
||||||
|
> .arrow {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px 0;
|
||||||
|
text-align: center;
|
||||||
|
opacity: 0.5;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
> header {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
background: var(--panel);
|
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
header.sub {
|
> div {
|
||||||
padding: 4px 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.list {
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||||
gap: 4px;
|
gap: 4px;
|
||||||
@ -227,6 +438,11 @@ export default defineComponent({
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
outline: solid 2px var(--focus);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
@ -255,6 +471,19 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.result {
|
||||||
|
border-bottom: solid 1px var(--divider);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unicode {
|
||||||
|
min-height: 384px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.custom {
|
||||||
|
min-height: 64px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -2,24 +2,19 @@
|
|||||||
<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt"/>
|
<img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt"/>
|
||||||
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt"/>
|
<img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt"/>
|
||||||
<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
|
<span v-else-if="char && useOsNativeEmojis">{{ char }}</span>
|
||||||
<span v-else>:{{ name }}:</span>
|
<span v-else>{{ emoji }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
import { getStaticImageUrl } from '@/scripts/get-static-image-url';
|
||||||
import { twemojiSvgBase } from '../../misc/twemoji-base';
|
import { twemojiSvgBase } from '../../misc/twemoji-base';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
emoji: {
|
emoji: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false
|
required: true
|
||||||
},
|
},
|
||||||
normal: {
|
normal: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -50,6 +45,10 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
isCustom(): boolean {
|
||||||
|
return this.emoji.startsWith(':');
|
||||||
|
},
|
||||||
|
|
||||||
alt(): string {
|
alt(): string {
|
||||||
return this.customEmoji ? `:${this.customEmoji.name}:` : this.char;
|
return this.customEmoji ? `:${this.customEmoji.name}:` : this.char;
|
||||||
},
|
},
|
||||||
@ -69,8 +68,8 @@ export default defineComponent({
|
|||||||
watch: {
|
watch: {
|
||||||
ce: {
|
ce: {
|
||||||
handler() {
|
handler() {
|
||||||
if (this.name) {
|
if (this.isCustom) {
|
||||||
const customEmoji = this.ce.find(x => x.name == this.name);
|
const customEmoji = this.ce.find(x => x.name === this.emoji.substr(1, this.emoji.length - 2));
|
||||||
if (customEmoji) {
|
if (customEmoji) {
|
||||||
this.customEmoji = customEmoji;
|
this.customEmoji = customEmoji;
|
||||||
this.url = this.$store.state.device.disableShowingAnimatedImages
|
this.url = this.$store.state.device.disableShowingAnimatedImages
|
||||||
@ -84,7 +83,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (!this.name) {
|
if (!this.isCustom) {
|
||||||
this.char = this.emoji;
|
this.char = this.emoji;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,10 +41,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.xubzgfga {
|
.xubzgfga {
|
||||||
max-width: 1024px;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
> header,
|
> header,
|
||||||
> footer {
|
> footer {
|
||||||
|
align-self: center;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 6px 9px;
|
padding: 6px 9px;
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
@ -60,7 +63,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
> img {
|
> img {
|
||||||
display: block;
|
display: block;
|
||||||
max-width: 100%;
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
object-fit: contain;
|
||||||
|
width: 100%;
|
||||||
cursor: zoom-out;
|
cursor: zoom-out;
|
||||||
image-orientation: from-image;
|
image-orientation: from-image;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { App } from 'vue';
|
import { App } from 'vue';
|
||||||
|
|
||||||
import mfm from './misskey-flavored-markdown.vue';
|
import mfm from './misskey-flavored-markdown.vue';
|
||||||
|
import a from './ui/a.vue';
|
||||||
import acct from './acct.vue';
|
import acct from './acct.vue';
|
||||||
import avatar from './avatar.vue';
|
import avatar from './avatar.vue';
|
||||||
import emoji from './emoji.vue';
|
import emoji from './emoji.vue';
|
||||||
@ -10,10 +11,10 @@ import time from './time.vue';
|
|||||||
import url from './url.vue';
|
import url from './url.vue';
|
||||||
import loading from './loading.vue';
|
import loading from './loading.vue';
|
||||||
import error from './error.vue';
|
import error from './error.vue';
|
||||||
import streamIndicator from './stream-indicator.vue';
|
|
||||||
|
|
||||||
export default function(app: App) {
|
export default function(app: App) {
|
||||||
app.component('Mfm', mfm);
|
app.component('Mfm', mfm);
|
||||||
|
app.component('MkA', a);
|
||||||
app.component('MkAcct', acct);
|
app.component('MkAcct', acct);
|
||||||
app.component('MkAvatar', avatar);
|
app.component('MkAvatar', avatar);
|
||||||
app.component('MkEmoji', emoji);
|
app.component('MkEmoji', emoji);
|
||||||
@ -23,5 +24,4 @@ export default function(app: App) {
|
|||||||
app.component('MkUrl', url);
|
app.component('MkUrl', url);
|
||||||
app.component('MkLoading', loading);
|
app.component('MkLoading', loading);
|
||||||
app.component('MkError', error);
|
app.component('MkError', error);
|
||||||
app.component('StreamIndicator', streamIndicator);
|
|
||||||
}
|
}
|
||||||
|
62
src/client/components/instance-ticker.vue
Normal file
62
src/client/components/instance-ticker.vue
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<div class="hpaizdrt" :style="bg">
|
||||||
|
<img v-if="info.faviconUrl" class="icon" :src="info.faviconUrl"/>
|
||||||
|
<span class="name">{{ info.name }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { instanceName } from '@/config';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
instance: {
|
||||||
|
type: Object,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
info: this.instance || {
|
||||||
|
faviconUrl: '/favicon.ico',
|
||||||
|
name: instanceName,
|
||||||
|
themeColor: (document.querySelector('meta[name="theme-color-orig"]') as HTMLMetaElement)?.content
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
bg(): any {
|
||||||
|
const themeColor = this.info.themeColor || '#777777';
|
||||||
|
return {
|
||||||
|
background: `linear-gradient(90deg, ${themeColor}, ${themeColor + '00'})`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.hpaizdrt {
|
||||||
|
$height: 1.1rem;
|
||||||
|
|
||||||
|
height: $height;
|
||||||
|
border-radius: 4px 0 0 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
> .icon {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .name {
|
||||||
|
margin-left: 4px;
|
||||||
|
line-height: $height;
|
||||||
|
font-size: 0.9em;
|
||||||
|
vertical-align: top;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="self ? 'router-link' : 'a'" class="xlcxczvw _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
<component :is="self ? 'MkA' : 'a'" class="xlcxczvw _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
||||||
@mouseover="onMouseover"
|
@mouseover="onMouseover"
|
||||||
@mouseleave="onMouseleave"
|
@mouseleave="onMouseleave"
|
||||||
:title="url"
|
:title="url"
|
||||||
@ -46,7 +46,7 @@ export default defineComponent({
|
|||||||
if (!document.body.contains(this.$el)) return;
|
if (!document.body.contains(this.$el)) return;
|
||||||
if (this.close) return;
|
if (this.close) return;
|
||||||
|
|
||||||
const { dispose } = os.popup(await import('@/components/url-preview-popup.vue'), {
|
const { dispose } = await os.popup(import('@/components/url-preview-popup.vue'), {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
source: this.$el
|
source: this.$el
|
||||||
});
|
});
|
||||||
|
@ -32,8 +32,6 @@ export default defineComponent({
|
|||||||
raw: {
|
raw: {
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
// specify the parent element
|
|
||||||
parentElement: {}
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -66,7 +64,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
if (this.$refs.gridOuter) {
|
if (this.$refs.gridOuter) {
|
||||||
let height = 287;
|
let height = 287;
|
||||||
const parent = this.parentElement || this.$parent.$el;
|
const parent = this.$parent.$el;
|
||||||
|
|
||||||
if (this.$refs.gridOuter.clientHeight) {
|
if (this.$refs.gridOuter.clientHeight) {
|
||||||
height = this.$refs.gridOuter.clientHeight;
|
height = this.$refs.gridOuter.clientHeight;
|
||||||
@ -81,11 +79,6 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
|
||||||
parentElement() {
|
|
||||||
this.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<router-link class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
|
<MkA class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
|
||||||
<span class="me" v-if="isMe">{{ $t('you') }}</span>
|
<span class="me" v-if="isMe">{{ $t('you') }}</span>
|
||||||
<span class="main">
|
<span class="main">
|
||||||
<span class="username">@{{ username }}</span>
|
<span class="username">@{{ username }}</span>
|
||||||
<span class="host" v-if="(host != localHost) || $store.state.settings.showFullAcct">@{{ toUnicode(host) }}</span>
|
<span class="host" v-if="(host != localHost) || $store.state.settings.showFullAcct">@{{ toUnicode(host) }}</span>
|
||||||
</span>
|
</span>
|
||||||
</router-link>
|
</MkA>
|
||||||
<a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else>
|
<a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else>
|
||||||
<span class="main">
|
<span class="main">
|
||||||
<span class="username">@{{ username }}</span>
|
<span class="username">@{{ username }}</span>
|
||||||
|
@ -9,8 +9,8 @@ import { concat } from '../../prelude/array';
|
|||||||
import MkFormula from './formula.vue';
|
import MkFormula from './formula.vue';
|
||||||
import MkCode from './code.vue';
|
import MkCode from './code.vue';
|
||||||
import MkGoogle from './google.vue';
|
import MkGoogle from './google.vue';
|
||||||
|
import MkA from './ui/a.vue';
|
||||||
import { host } from '@/config';
|
import { host } from '@/config';
|
||||||
import { RouterLink } from 'vue-router';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@ -77,9 +77,61 @@ export default defineComponent({
|
|||||||
}, genEl(token.children));
|
}, genEl(token.children));
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'big': {
|
case 'fn': {
|
||||||
return h('strong', {
|
// TODO: CSSを文字列で組み立てていくと token.node.props.args.~~~ 経由でCSSインジェクションできるのでよしなにやる
|
||||||
style: `display: inline-block; font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: anime-tada 1s linear infinite both;' : ''),
|
let style;
|
||||||
|
switch (token.node.props.name) {
|
||||||
|
case 'tada': {
|
||||||
|
style = `font-size: 150%;` + (this.$store.state.device.animatedMfm ? 'animation: tada 1s linear infinite both;' : '');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'jelly': {
|
||||||
|
const speed = token.node.props.args.speed || '1s';
|
||||||
|
style = (this.$store.state.device.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'twitch': {
|
||||||
|
const speed = token.node.props.args.speed || '0.5s';
|
||||||
|
style = this.$store.state.device.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'shake': {
|
||||||
|
const speed = token.node.props.args.speed || '0.5s';
|
||||||
|
style = this.$store.state.device.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'spin': {
|
||||||
|
const direction =
|
||||||
|
token.node.props.args.left ? 'reverse' :
|
||||||
|
token.node.props.args.alternate ? 'alternate' :
|
||||||
|
'normal';
|
||||||
|
const anime =
|
||||||
|
token.node.props.args.x ? 'mfm-spinX' :
|
||||||
|
token.node.props.args.y ? 'mfm-spinY' :
|
||||||
|
'mfm-spin';
|
||||||
|
const speed = token.node.props.args.speed || '1.5s';
|
||||||
|
style = this.$store.state.device.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'jump': {
|
||||||
|
style = this.$store.state.device.animatedMfm ? 'animation: mfm-jump 0.75s linear infinite;' : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'bounce': {
|
||||||
|
style = this.$store.state.device.animatedMfm ? 'animation: mfm-bounce 0.75s linear infinite; transform-origin: center bottom;' : '';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'flip': {
|
||||||
|
const transform =
|
||||||
|
(token.node.props.args.h && token.node.props.args.v) ? 'scale(-1, -1)' :
|
||||||
|
token.node.props.args.v ? 'scaleY(-1)' :
|
||||||
|
'scaleX(-1)';
|
||||||
|
style = `transform: ${transform};`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h('span', {
|
||||||
|
style: 'display: inline-block;' + style,
|
||||||
}, genEl(token.children));
|
}, genEl(token.children));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,36 +147,6 @@ export default defineComponent({
|
|||||||
}, genEl(token.children))];
|
}, genEl(token.children))];
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'motion': {
|
|
||||||
return h('span', {
|
|
||||||
style: 'display: inline-block;' + (this.$store.state.device.animatedMfm ? 'animation: anime-rubberBand 1s linear infinite both;' : ''),
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'spin': {
|
|
||||||
const direction =
|
|
||||||
token.node.props.attr == 'left' ? 'reverse' :
|
|
||||||
token.node.props.attr == 'alternate' ? 'alternate' :
|
|
||||||
'normal';
|
|
||||||
const style = this.$store.state.device.animatedMfm
|
|
||||||
? `animation: anime-spin 1.5s linear infinite; animation-direction: ${direction};` : '';
|
|
||||||
return h('span', {
|
|
||||||
style: 'display: inline-block;' + style
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'jump': {
|
|
||||||
return h('span', {
|
|
||||||
style: this.$store.state.device.animatedMfm ? 'display: inline-block; animation: anime-jump 0.75s linear infinite;' : 'display: inline-block;'
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'flip': {
|
|
||||||
return h('span', {
|
|
||||||
style: 'display: inline-block; transform: scaleX(-1);'
|
|
||||||
}, genEl(token.children));
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'url': {
|
case 'url': {
|
||||||
return [h(MkUrl, {
|
return [h(MkUrl, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
@ -150,7 +172,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'hashtag': {
|
case 'hashtag': {
|
||||||
return [h(RouterLink, {
|
return [h(MkA, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
to: this.isNote ? `/tags/${encodeURIComponent(token.node.props.hashtag)}` : `/explore/tags/${encodeURIComponent(token.node.props.hashtag)}`,
|
to: this.isNote ? `/tags/${encodeURIComponent(token.node.props.hashtag)}` : `/explore/tags/${encodeURIComponent(token.node.props.hashtag)}`,
|
||||||
style: 'color:var(--hashtag);'
|
style: 'color:var(--hashtag);'
|
||||||
@ -186,17 +208,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'title': {
|
|
||||||
return [h('div', {
|
|
||||||
class: 'title'
|
|
||||||
}, genEl(token.children))];
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'emoji': {
|
case 'emoji': {
|
||||||
return [h(MkEmoji, {
|
return [h(MkEmoji, {
|
||||||
key: Math.random(),
|
key: Math.random(),
|
||||||
emoji: token.node.props.emoji,
|
emoji: token.node.props.name ? `:${token.node.props.name}:` : token.node.props.emoji,
|
||||||
name: token.node.props.name,
|
|
||||||
customEmojis: this.customEmojis,
|
customEmojis: this.customEmojis,
|
||||||
normal: this.plain
|
normal: this.plain
|
||||||
})];
|
})];
|
||||||
|
@ -13,6 +13,103 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@keyframes mfm-spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-spinX {
|
||||||
|
0% { transform: perspective(128px) rotateX(0deg); }
|
||||||
|
100% { transform: perspective(128px) rotateX(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-spinY {
|
||||||
|
0% { transform: perspective(128px) rotateY(0deg); }
|
||||||
|
100% { transform: perspective(128px) rotateY(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-jump {
|
||||||
|
0% { transform: translateY(0); }
|
||||||
|
25% { transform: translateY(-16px); }
|
||||||
|
50% { transform: translateY(0); }
|
||||||
|
75% { transform: translateY(-8px); }
|
||||||
|
100% { transform: translateY(0); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-bounce {
|
||||||
|
0% { transform: translateY(0) scale(1, 1); }
|
||||||
|
25% { transform: translateY(-16px) scale(1, 1); }
|
||||||
|
50% { transform: translateY(0) scale(1, 1); }
|
||||||
|
75% { transform: translateY(0) scale(1.5, 0.75); }
|
||||||
|
100% { transform: translateY(0) scale(1, 1); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// const val = () => `translate(${Math.floor(Math.random() * 20) - 10}px, ${Math.floor(Math.random() * 20) - 10}px)`;
|
||||||
|
// let css = '';
|
||||||
|
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
|
||||||
|
@keyframes mfm-twitch {
|
||||||
|
0% { transform: translate(7px, -2px) }
|
||||||
|
5% { transform: translate(-3px, 1px) }
|
||||||
|
10% { transform: translate(-7px, -1px) }
|
||||||
|
15% { transform: translate(0px, -1px) }
|
||||||
|
20% { transform: translate(-8px, 6px) }
|
||||||
|
25% { transform: translate(-4px, -3px) }
|
||||||
|
30% { transform: translate(-4px, -6px) }
|
||||||
|
35% { transform: translate(-8px, -8px) }
|
||||||
|
40% { transform: translate(4px, 6px) }
|
||||||
|
45% { transform: translate(-3px, 1px) }
|
||||||
|
50% { transform: translate(2px, -10px) }
|
||||||
|
55% { transform: translate(-7px, 0px) }
|
||||||
|
60% { transform: translate(-2px, 4px) }
|
||||||
|
65% { transform: translate(3px, -8px) }
|
||||||
|
70% { transform: translate(6px, 7px) }
|
||||||
|
75% { transform: translate(-7px, -2px) }
|
||||||
|
80% { transform: translate(-7px, -8px) }
|
||||||
|
85% { transform: translate(9px, 3px) }
|
||||||
|
90% { transform: translate(-3px, -2px) }
|
||||||
|
95% { transform: translate(-10px, 2px) }
|
||||||
|
100% { transform: translate(-2px, -6px) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// const val = () => `translate(${Math.floor(Math.random() * 6) - 3}px, ${Math.floor(Math.random() * 6) - 3}px) rotate(${Math.floor(Math.random() * 24) - 12}deg)`;
|
||||||
|
// let css = '';
|
||||||
|
// for (let i = 0; i <= 100; i += 5) { css += `${i}% { transform: ${val()} }\n`; }
|
||||||
|
@keyframes mfm-shake {
|
||||||
|
0% { transform: translate(-3px, -1px) rotate(-8deg) }
|
||||||
|
5% { transform: translate(0px, -1px) rotate(-10deg) }
|
||||||
|
10% { transform: translate(1px, -3px) rotate(0deg) }
|
||||||
|
15% { transform: translate(1px, 1px) rotate(11deg) }
|
||||||
|
20% { transform: translate(-2px, 1px) rotate(1deg) }
|
||||||
|
25% { transform: translate(-1px, -2px) rotate(-2deg) }
|
||||||
|
30% { transform: translate(-1px, 2px) rotate(-3deg) }
|
||||||
|
35% { transform: translate(2px, 1px) rotate(6deg) }
|
||||||
|
40% { transform: translate(-2px, -3px) rotate(-9deg) }
|
||||||
|
45% { transform: translate(0px, -1px) rotate(-12deg) }
|
||||||
|
50% { transform: translate(1px, 2px) rotate(10deg) }
|
||||||
|
55% { transform: translate(0px, -3px) rotate(8deg) }
|
||||||
|
60% { transform: translate(1px, -1px) rotate(8deg) }
|
||||||
|
65% { transform: translate(0px, -1px) rotate(-7deg) }
|
||||||
|
70% { transform: translate(-1px, -3px) rotate(6deg) }
|
||||||
|
75% { transform: translate(0px, -2px) rotate(4deg) }
|
||||||
|
80% { transform: translate(-2px, -1px) rotate(3deg) }
|
||||||
|
85% { transform: translate(1px, -3px) rotate(-10deg) }
|
||||||
|
90% { transform: translate(1px, 0px) rotate(3deg) }
|
||||||
|
95% { transform: translate(-2px, 0px) rotate(-3deg) }
|
||||||
|
100% { transform: translate(2px, 1px) rotate(2deg) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes mfm-rubberBand {
|
||||||
|
from { transform: scale3d(1, 1, 1); }
|
||||||
|
30% { transform: scale3d(1.25, 0.75, 1); }
|
||||||
|
40% { transform: scale3d(0.75, 1.25, 1); }
|
||||||
|
50% { transform: scale3d(1.15, 0.85, 1); }
|
||||||
|
65% { transform: scale3d(0.95, 1.05, 1); }
|
||||||
|
75% { transform: scale3d(1.05, 0.95, 1); }
|
||||||
|
to { transform: scale3d(1, 1, 1); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.havbbuyv {
|
.havbbuyv {
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
@ -42,10 +139,5 @@ export default defineComponent({
|
|||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep(.title) {
|
|
||||||
text-align: center;
|
|
||||||
border-bottom: solid 1px var(--divider);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<header class="kkwtjztg">
|
<header class="kkwtjztg">
|
||||||
<router-link class="name" :to="userPage(note.user)" v-user-preview="note.user.id">
|
<MkA class="name" :to="userPage(note.user)" v-user-preview="note.user.id">
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<span class="is-bot" v-if="note.user.isBot">bot</span>
|
<span class="is-bot" v-if="note.user.isBot">bot</span>
|
||||||
<span class="username"><MkAcct :user="note.user"/></span>
|
<span class="username"><MkAcct :user="note.user"/></span>
|
||||||
<span class="admin" v-if="note.user.isAdmin"><Fa :icon="faBookmark"/></span>
|
<span class="admin" v-if="note.user.isAdmin"><Fa :icon="faBookmark"/></span>
|
||||||
<span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><Fa :icon="farBookmark"/></span>
|
<span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><Fa :icon="farBookmark"/></span>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<span class="mobile" v-if="note.viaMobile"><Fa :icon="faMobileAlt"/></span>
|
<span class="mobile" v-if="note.viaMobile"><Fa :icon="faMobileAlt"/></span>
|
||||||
<router-link class="created-at" :to="notePage(note)">
|
<MkA class="created-at" :to="notePage(note)">
|
||||||
<MkTime :time="note.createdAt"/>
|
<MkTime :time="note.createdAt"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<span class="visibility" v-if="note.visibility !== 'public'">
|
<span class="visibility" v-if="note.visibility !== 'public'">
|
||||||
<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
|
<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
|
||||||
<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
|
<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
<Fa :icon="faRetweet"/>
|
<Fa :icon="faRetweet"/>
|
||||||
<i18n-t keypath="renotedBy" tag="span">
|
<i18n-t keypath="renotedBy" tag="span">
|
||||||
<template #user>
|
<template #user>
|
||||||
<router-link class="name" :to="userPage(note.user)" v-user-preview="note.userId">
|
<MkA class="name" :to="userPage(note.user)" v-user-preview="note.userId">
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
@ -40,7 +40,8 @@
|
|||||||
<MkAvatar class="avatar" :user="appearNote.user"/>
|
<MkAvatar class="avatar" :user="appearNote.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<XNoteHeader class="header" :note="appearNote" :mini="true"/>
|
<XNoteHeader class="header" :note="appearNote" :mini="true"/>
|
||||||
<div class="body" ref="noteBody">
|
<MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
|
||||||
|
<div class="body">
|
||||||
<p v-if="appearNote.cw != null" class="cw">
|
<p v-if="appearNote.cw != null" class="cw">
|
||||||
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
|
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
|
||||||
<XCwButton v-model:value="showContent" :note="appearNote"/>
|
<XCwButton v-model:value="showContent" :note="appearNote"/>
|
||||||
@ -48,18 +49,18 @@
|
|||||||
<div class="content" v-show="appearNote.cw == null || showContent">
|
<div class="content" v-show="appearNote.cw == null || showContent">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
|
||||||
<router-link class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></router-link>
|
<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
|
||||||
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
|
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
|
||||||
<a class="rp" v-if="appearNote.renote != null">RN:</a>
|
<a class="rp" v-if="appearNote.renote != null">RN:</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="files" v-if="appearNote.files.length > 0">
|
<div class="files" v-if="appearNote.files.length > 0">
|
||||||
<XMediaList :media-list="appearNote.files" :parent-element="noteBody"/>
|
<XMediaList :media-list="appearNote.files"/>
|
||||||
</div>
|
</div>
|
||||||
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
<XPoll v-if="appearNote.poll" :note="appearNote" ref="pollViewer" class="poll"/>
|
||||||
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="detail" class="url-preview"/>
|
<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="detail" class="url-preview"/>
|
||||||
<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
|
<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
|
||||||
</div>
|
</div>
|
||||||
<router-link v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</router-link>
|
<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</MkA>
|
||||||
</div>
|
</div>
|
||||||
<footer class="footer">
|
<footer class="footer">
|
||||||
<XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
|
<XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
|
||||||
@ -91,9 +92,9 @@
|
|||||||
<div v-else class="_panel muted" @click="muted = false">
|
<div v-else class="_panel muted" @click="muted = false">
|
||||||
<i18n-t keypath="userSaysSomething" tag="small">
|
<i18n-t keypath="userSaysSomething" tag="small">
|
||||||
<template #name>
|
<template #name>
|
||||||
<router-link class="name" :to="userPage(appearNote.user)" v-user-preview="appearNote.userId">
|
<MkA class="name" :to="userPage(appearNote.user)" v-user-preview="appearNote.userId">
|
||||||
<MkUserName :user="appearNote.user"/>
|
<MkUserName :user="appearNote.user"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
</i18n-t>
|
</i18n-t>
|
||||||
</div>
|
</div>
|
||||||
@ -139,12 +140,13 @@ export default defineComponent({
|
|||||||
XCwButton,
|
XCwButton,
|
||||||
XPoll,
|
XPoll,
|
||||||
MkUrlPreview: defineAsyncComponent(() => import('@/components/url-preview.vue')),
|
MkUrlPreview: defineAsyncComponent(() => import('@/components/url-preview.vue')),
|
||||||
|
MkInstanceTicker: defineAsyncComponent(() => import('@/components/instance-ticker.vue')),
|
||||||
},
|
},
|
||||||
|
|
||||||
inject: {
|
inject: {
|
||||||
inChannel: {
|
inChannel: {
|
||||||
default: null
|
default: null
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
@ -174,7 +176,6 @@ export default defineComponent({
|
|||||||
showContent: false,
|
showContent: false,
|
||||||
isDeleted: false,
|
isDeleted: false,
|
||||||
muted: false,
|
muted: false,
|
||||||
noteBody: this.$refs.noteBody,
|
|
||||||
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish
|
faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -258,6 +259,12 @@ export default defineComponent({
|
|||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
showTicker() {
|
||||||
|
if (this.$store.state.device.instanceTicker === 'always') return true;
|
||||||
|
if (this.$store.state.device.instanceTicker === 'remote' && this.appearNote.user.instance) return true;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -301,8 +308,6 @@ export default defineComponent({
|
|||||||
if (this.$store.getters.isSignedIn) {
|
if (this.$store.getters.isSignedIn) {
|
||||||
this.connection.on('_connected_', this.onStreamConnected);
|
this.connection.on('_connected_', this.onStreamConnected);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.noteBody = this.$refs.noteBody;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeUnmount() {
|
beforeUnmount() {
|
||||||
@ -493,7 +498,22 @@ export default defineComponent({
|
|||||||
react(viaKeyboard = false) {
|
react(viaKeyboard = false) {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
this.blur();
|
this.blur();
|
||||||
os.popup(defineAsyncComponent(() => import('@/components/reaction-picker.vue')), {
|
if (this.$store.state.device.useFullReactionPicker) {
|
||||||
|
os.popup(import('@/components/emoji-picker.vue'), {
|
||||||
|
src: this.$refs.reactButton,
|
||||||
|
}, {
|
||||||
|
done: reaction => {
|
||||||
|
if (reaction) {
|
||||||
|
os.api('notes/reactions/create', {
|
||||||
|
noteId: this.appearNote.id,
|
||||||
|
reaction: reaction
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.focus();
|
||||||
|
},
|
||||||
|
}, 'closed');
|
||||||
|
} else {
|
||||||
|
os.popup(import('@/components/reaction-picker.vue'), {
|
||||||
showFocus: viaKeyboard,
|
showFocus: viaKeyboard,
|
||||||
src: this.$refs.reactButton,
|
src: this.$refs.reactButton,
|
||||||
}, {
|
}, {
|
||||||
@ -507,6 +527,7 @@ export default defineComponent({
|
|||||||
this.focus();
|
this.focus();
|
||||||
},
|
},
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
reactDirectly(reaction) {
|
reactDirectly(reaction) {
|
||||||
@ -581,11 +602,6 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
|
|
||||||
menu = [{
|
menu = [{
|
||||||
type: 'link',
|
|
||||||
icon: faInfoCircle,
|
|
||||||
text: this.$t('details'),
|
|
||||||
to: '/notes/' + this.appearNote.id
|
|
||||||
}, null, {
|
|
||||||
icon: faCopy,
|
icon: faCopy,
|
||||||
text: this.$t('copyContent'),
|
text: this.$t('copyContent'),
|
||||||
action: this.copyContent
|
action: this.copyContent
|
||||||
@ -644,7 +660,7 @@ export default defineComponent({
|
|||||||
text: this.$t('reportAbuse'),
|
text: this.$t('reportAbuse'),
|
||||||
action: () => {
|
action: () => {
|
||||||
const u = `${url}/notes/${this.appearNote.id}`;
|
const u = `${url}/notes/${this.appearNote.id}`;
|
||||||
os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), {
|
os.popup(import('@/components/abuse-report-window.vue'), {
|
||||||
user: this.appearNote.user,
|
user: this.appearNote.user,
|
||||||
initialComment: `Note: ${u}\n-----\n`
|
initialComment: `Note: ${u}\n-----\n`
|
||||||
}, {}, 'closed');
|
}, {}, 'closed');
|
||||||
|
@ -18,34 +18,34 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="tail">
|
<div class="tail">
|
||||||
<header>
|
<header>
|
||||||
<router-link v-if="notification.user" class="name" :to="userPage(notification.user)" v-user-preview="notification.user.id"><MkUserName :user="notification.user"/></router-link>
|
<MkA v-if="notification.user" class="name" :to="userPage(notification.user)" v-user-preview="notification.user.id"><MkUserName :user="notification.user"/></MkA>
|
||||||
<span v-else>{{ notification.header }}</span>
|
<span v-else>{{ notification.header }}</span>
|
||||||
<MkTime :time="notification.createdAt" v-if="withTime"/>
|
<MkTime :time="notification.createdAt" v-if="withTime" class="time"/>
|
||||||
</header>
|
</header>
|
||||||
<router-link v-if="notification.type === 'reaction'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-if="notification.type === 'reaction'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Fa :icon="faQuoteLeft"/>
|
<Fa :icon="faQuoteLeft"/>
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
||||||
<Fa :icon="faQuoteRight"/>
|
<Fa :icon="faQuoteRight"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<router-link v-if="notification.type === 'renote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
|
<MkA v-if="notification.type === 'renote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
|
||||||
<Fa :icon="faQuoteLeft"/>
|
<Fa :icon="faQuoteLeft"/>
|
||||||
<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.renote.emojis"/>
|
<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.renote.emojis"/>
|
||||||
<Fa :icon="faQuoteRight"/>
|
<Fa :icon="faQuoteRight"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<router-link v-if="notification.type === 'reply'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-if="notification.type === 'reply'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<router-link v-if="notification.type === 'mention'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-if="notification.type === 'mention'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<router-link v-if="notification.type === 'quote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-if="notification.type === 'quote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<router-link v-if="notification.type === 'pollVote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
<MkA v-if="notification.type === 'pollVote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||||
<Fa :icon="faQuoteLeft"/>
|
<Fa :icon="faQuoteLeft"/>
|
||||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
|
||||||
<Fa :icon="faQuoteRight"/>
|
<Fa :icon="faQuoteRight"/>
|
||||||
</router-link>
|
</MkA>
|
||||||
<span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ $t('youGotNewFollower') }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
|
<span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ $t('youGotNewFollower') }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
|
||||||
<span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ $t('followRequestAccepted') }}</span>
|
<span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ $t('followRequestAccepted') }}</span>
|
||||||
<span v-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ $t('receiveFollowRequest') }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ $t('accept') }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ $t('reject') }}</button></div></span>
|
<span v-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ $t('receiveFollowRequest') }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ $t('accept') }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ $t('reject') }}</button></div></span>
|
||||||
@ -260,7 +260,7 @@ export default defineComponent({
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .mk-time {
|
> .time {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<router-link :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1">
|
<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1">
|
||||||
<div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div>
|
<div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div>
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
@ -11,7 +11,7 @@
|
|||||||
<p>{{ userName(page.user) }}</p>
|
<p>{{ userName(page.user) }}</p>
|
||||||
</footer>
|
</footer>
|
||||||
</article>
|
</article>
|
||||||
</router-link>
|
</MkA>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -1,11 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="$emit('closed')">
|
<XWindow ref="window"
|
||||||
|
:initial-width="700"
|
||||||
|
:initial-height="500"
|
||||||
|
:can-resize="true"
|
||||||
|
:close-right="true"
|
||||||
|
:contextmenu="contextmenu"
|
||||||
|
@closed="$emit('closed')"
|
||||||
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<XHeader :info="pageInfo" :with-back="false"/>
|
<XHeader :info="pageInfo" :with-back="false"/>
|
||||||
</template>
|
</template>
|
||||||
<template #buttons>
|
<template #buttons>
|
||||||
<button class="_button" @click="expand" v-tooltip="$t('showInPage')"><Fa :icon="faExpandAlt"/></button>
|
<button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button>
|
||||||
<button class="_button" @click="popout" v-tooltip="$t('popout')"><Fa :icon="faExternalLinkAlt"/></button>
|
<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
|
||||||
</template>
|
</template>
|
||||||
<div class="yrolvcoq" style="min-height: 100%; background: var(--bg);">
|
<div class="yrolvcoq" style="min-height: 100%; background: var(--bg);">
|
||||||
<component :is="component" v-bind="props" :ref="changePage"/>
|
<component :is="component" v-bind="props" :ref="changePage"/>
|
||||||
@ -14,11 +21,14 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, markRaw } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { faExternalLinkAlt, faExpandAlt } from '@fortawesome/free-solid-svg-icons';
|
import { faExternalLinkAlt, faExpandAlt, faLink, faChevronLeft, faColumns } from '@fortawesome/free-solid-svg-icons';
|
||||||
import XWindow from '@/components/ui/window.vue';
|
import XWindow from '@/components/ui/window.vue';
|
||||||
import XHeader from '@/ui/_common_/header.vue';
|
import XHeader from '@/ui/_common_/header.vue';
|
||||||
import { popout } from '@/scripts/popout';
|
import { popout } from '@/scripts/popout';
|
||||||
|
import copyToClipboard from '@/scripts/copy-to-clipboard';
|
||||||
|
import { resolve } from '@/router';
|
||||||
|
import { url } from '@/config';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@ -26,8 +36,22 @@ export default defineComponent({
|
|||||||
XHeader,
|
XHeader,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
inject: {
|
||||||
|
sideViewHook: {
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
provide() {
|
||||||
|
return {
|
||||||
|
navHook: (path) => {
|
||||||
|
this.navigate(path);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
initialUrl: {
|
initialPath: {
|
||||||
type: String,
|
type: String,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
@ -38,7 +62,7 @@ export default defineComponent({
|
|||||||
initialProps: {
|
initialProps: {
|
||||||
type: Object,
|
type: Object,
|
||||||
required: false,
|
required: false,
|
||||||
default: {},
|
default: () => {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -47,21 +71,53 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
pageInfo: null,
|
pageInfo: null,
|
||||||
url: this.initialUrl,
|
path: this.initialPath,
|
||||||
component: this.initialComponent,
|
component: this.initialComponent,
|
||||||
props: this.initialProps,
|
props: this.initialProps,
|
||||||
faExternalLinkAlt, faExpandAlt,
|
history: [],
|
||||||
|
faChevronLeft,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
provide() {
|
computed: {
|
||||||
return {
|
url(): string {
|
||||||
navHook: (url, component, props) => {
|
return url + this.path;
|
||||||
this.url = url;
|
},
|
||||||
this.component = markRaw(component);
|
|
||||||
this.props = props;
|
contextmenu() {
|
||||||
|
return [{
|
||||||
|
type: 'label',
|
||||||
|
text: this.path,
|
||||||
|
}, {
|
||||||
|
icon: faExpandAlt,
|
||||||
|
text: this.$t('showInPage'),
|
||||||
|
action: this.expand
|
||||||
|
}, this.sideViewHook ? {
|
||||||
|
icon: faColumns,
|
||||||
|
text: this.$t('openInSideView'),
|
||||||
|
action: () => {
|
||||||
|
this.sideViewHook(this.path);
|
||||||
|
this.$refs.window.close();
|
||||||
}
|
}
|
||||||
};
|
} : undefined, {
|
||||||
|
icon: faExternalLinkAlt,
|
||||||
|
text: this.$t('popout'),
|
||||||
|
action: this.popout
|
||||||
|
}, null, {
|
||||||
|
icon: faExternalLinkAlt,
|
||||||
|
text: this.$t('openInNewTab'),
|
||||||
|
action: () => {
|
||||||
|
window.open(this.url, '_blank');
|
||||||
|
this.$refs.window.close();
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
icon: faLink,
|
||||||
|
text: this.$t('copyLink'),
|
||||||
|
action: () => {
|
||||||
|
copyToClipboard(this.url);
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@ -72,13 +128,25 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
navigate(path, record = true) {
|
||||||
|
if (record) this.history.push(this.path);
|
||||||
|
this.path = path;
|
||||||
|
const { component, props } = resolve(path);
|
||||||
|
this.component = component;
|
||||||
|
this.props = props;
|
||||||
|
},
|
||||||
|
|
||||||
|
back() {
|
||||||
|
this.navigate(this.history.pop(), false);
|
||||||
|
},
|
||||||
|
|
||||||
expand() {
|
expand() {
|
||||||
this.$router.push(this.url);
|
this.$router.push(this.path);
|
||||||
this.$refs.window.close();
|
this.$refs.window.close();
|
||||||
},
|
},
|
||||||
|
|
||||||
popout() {
|
popout() {
|
||||||
popout(this.url, this.$el);
|
popout(this.path, this.$el);
|
||||||
this.$refs.window.close();
|
this.$refs.window.close();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -378,13 +378,13 @@ export default defineComponent({
|
|||||||
this.saveDraft();
|
this.saveDraft();
|
||||||
},
|
},
|
||||||
|
|
||||||
async setVisibility() {
|
setVisibility() {
|
||||||
if (this.channel) {
|
if (this.channel) {
|
||||||
// TODO: information dialog
|
// TODO: information dialog
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
os.popup(await import('./visibility-picker.vue'), {
|
os.popup(import('./visibility-picker.vue'), {
|
||||||
currentVisibility: this.visibility,
|
currentVisibility: this.visibility,
|
||||||
currentLocalOnly: this.localOnly,
|
currentLocalOnly: this.localOnly,
|
||||||
src: this.$refs.visibilityButton
|
src: this.$refs.visibilityButton
|
||||||
@ -562,6 +562,10 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
this.posting = false;
|
this.posting = false;
|
||||||
|
os.dialog({
|
||||||
|
type: 'error',
|
||||||
|
text: err.message + '\n' + (err as any).id,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkEmoji :emoji="reaction.startsWith(':') ? null : reaction" :name="reaction.startsWith(':') ? reaction.substr(1, reaction.length - 2) : null" :customEmojis="customEmojis" :is-reaction="true" :normal="true" :no-style="noStyle"/>
|
<MkEmoji :emoji="reaction" :custom-emojis="customEmojis" :is-reaction="true" :normal="true" :no-style="noStyle"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';import * as os from '@/os';
|
import { defineComponent } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div class="bqxuuuey">
|
<div class="bqxuuuey">
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div>{{ reaction.replace('@.', '') }}</div>
|
<div>{{ reaction.replace('@.', '') }}</div>
|
||||||
<XReactionIcon :reaction="reaction" :custom-emojis="emojis" class="icon"/>
|
<XReactionIcon :reaction="reaction" :custom-emojis="emojis" class="icon" :no-style="true"/>
|
||||||
</div>
|
</div>
|
||||||
<template v-if="users.length <= 10">
|
<template v-if="users.length <= 10">
|
||||||
<b v-for="u in users" :key="u.id" style="margin-right: 12px;">
|
<b v-for="u in users" :key="u.id" style="margin-right: 12px;">
|
||||||
@ -66,7 +66,6 @@ export default defineComponent({
|
|||||||
> .icon {
|
> .icon {
|
||||||
display: block;
|
display: block;
|
||||||
width: 60px;
|
width: 60px;
|
||||||
height: 60px;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,33 +11,30 @@
|
|||||||
<transition name="nav">
|
<transition name="nav">
|
||||||
<nav class="nav" :class="{ iconOnly, hidden }" v-show="showing">
|
<nav class="nav" :class="{ iconOnly, hidden }" v-show="showing">
|
||||||
<div>
|
<div>
|
||||||
<button class="item _button account" @click="openAccountMenu" v-if="$store.getters.isSignedIn">
|
<button class="item _button account" @click="openAccountMenu">
|
||||||
<MkAvatar :user="$store.state.i" class="avatar"/><MkAcct class="text" :user="$store.state.i"/>
|
<MkAvatar :user="$store.state.i" class="avatar"/><MkAcct class="text" :user="$store.state.i"/>
|
||||||
</button>
|
</button>
|
||||||
<button class="item _button index active" @click="top()" v-if="$route.name === 'index'">
|
<MkA class="item index" active-class="active" to="/" exact>
|
||||||
<Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
|
<Fa :icon="faHome" fixed-width/><span class="text">{{ $t('timeline') }}</span>
|
||||||
</button>
|
</MkA>
|
||||||
<router-link class="item index" active-class="active" to="/" exact v-else>
|
|
||||||
<Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
|
|
||||||
</router-link>
|
|
||||||
<template v-for="item in menu">
|
<template v-for="item in menu">
|
||||||
<div v-if="item === '-'" class="divider"></div>
|
<div v-if="item === '-'" class="divider"></div>
|
||||||
<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to">
|
<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'MkA' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to">
|
||||||
<Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span>
|
<Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span>
|
||||||
<i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i>
|
<i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i>
|
||||||
</component>
|
</component>
|
||||||
</template>
|
</template>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.getters.isSignedIn && ($store.state.i.isAdmin || $store.state.i.isModerator)" @click="oepnInstanceMenu">
|
<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$store.state.i.isAdmin || $store.state.i.isModerator" @click="oepnInstanceMenu">
|
||||||
<Fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span>
|
<Fa :icon="faServer" fixed-width/><span class="text">{{ $t('instance') }}</span>
|
||||||
</button>
|
</button>
|
||||||
<button class="item _button" @click="more">
|
<button class="item _button" @click="more">
|
||||||
<Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span>
|
<Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span>
|
||||||
<i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i>
|
<i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i>
|
||||||
</button>
|
</button>
|
||||||
<router-link class="item" active-class="active" to="/settings">
|
<MkA class="item" active-class="active" to="/settings">
|
||||||
<Fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span>
|
<Fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span>
|
||||||
</router-link>
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
</transition>
|
</transition>
|
||||||
@ -74,7 +71,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
otherNavItemIndicated(): boolean {
|
otherNavItemIndicated(): boolean {
|
||||||
if (!this.$store.getters.isSignedIn) return false;
|
|
||||||
for (const def in this.menuDef) {
|
for (const def in this.menuDef) {
|
||||||
if (this.menu.includes(def)) continue;
|
if (this.menu.includes(def)) continue;
|
||||||
if (this.menuDef[def].indicated) return true;
|
if (this.menuDef[def].indicated) return true;
|
||||||
@ -120,10 +116,6 @@ export default defineComponent({
|
|||||||
this.showing = true;
|
this.showing = true;
|
||||||
},
|
},
|
||||||
|
|
||||||
top() {
|
|
||||||
window.scroll({ top: 0, behavior: 'smooth' });
|
|
||||||
},
|
|
||||||
|
|
||||||
search() {
|
search() {
|
||||||
if (this.searching) return;
|
if (this.searching) return;
|
||||||
|
|
||||||
@ -246,7 +238,7 @@ export default defineComponent({
|
|||||||
icon: faQuestionCircle,
|
icon: faQuestionCircle,
|
||||||
}, {
|
}, {
|
||||||
type: 'link',
|
type: 'link',
|
||||||
text: this.$t('aboutX', { x: instanceName || host }),
|
text: this.$t('aboutX', { x: instanceName }),
|
||||||
to: '/about',
|
to: '/about',
|
||||||
icon: faInfoCircle,
|
icon: faInfoCircle,
|
||||||
}, {
|
}, {
|
||||||
@ -257,8 +249,8 @@ export default defineComponent({
|
|||||||
}], ev.currentTarget || ev.target);
|
}], ev.currentTarget || ev.target);
|
||||||
},
|
},
|
||||||
|
|
||||||
async addAcount() {
|
addAcount() {
|
||||||
os.popup(await import('./signin-dialog.vue'), {}, {
|
os.popup(import('./signin-dialog.vue'), {}, {
|
||||||
done: res => {
|
done: res => {
|
||||||
this.$store.dispatch('addAcount', res);
|
this.$store.dispatch('addAcount', res);
|
||||||
os.success();
|
os.success();
|
||||||
@ -266,8 +258,8 @@ export default defineComponent({
|
|||||||
}, 'closed');
|
}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
async createAccount() {
|
createAccount() {
|
||||||
os.popup(await import('./signup-dialog.vue'), {}, {
|
os.popup(import('./signup-dialog.vue'), {}, {
|
||||||
done: res => {
|
done: res => {
|
||||||
this.$store.dispatch('addAcount', res);
|
this.$store.dispatch('addAcount', res);
|
||||||
this.switchAccountWithToken(res.i);
|
this.switchAccountWithToken(res.i);
|
||||||
@ -275,7 +267,7 @@ export default defineComponent({
|
|||||||
}, 'closed');
|
}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
async switchAccount(account: any) {
|
switchAccount(account: any) {
|
||||||
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
|
const token = this.$store.state.device.accounts.find((x: any) => x.id === account.id).token;
|
||||||
this.switchAccountWithToken(token);
|
this.switchAccountWithToken(token);
|
||||||
},
|
},
|
||||||
@ -422,9 +414,9 @@ export default defineComponent({
|
|||||||
> .item {
|
> .item {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: block;
|
display: block;
|
||||||
padding-left: 32px;
|
padding-left: 24px;
|
||||||
font-size: $ui-font-size;
|
font-size: $ui-font-size;
|
||||||
line-height: 3.2rem;
|
line-height: 3rem;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -7,9 +7,7 @@
|
|||||||
>
|
>
|
||||||
<template #header>{{ $t('login') }}</template>
|
<template #header>{{ $t('login') }}</template>
|
||||||
|
|
||||||
<div class="_section">
|
|
||||||
<MkSignin :auto-set="autoSet" @login="onLogin"/>
|
<MkSignin :auto-set="autoSet" @login="onLogin"/>
|
||||||
</div>
|
|
||||||
</XModalWindow>
|
</XModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<form class="eppvobhk" :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
|
<form class="eppvobhk" :class="{ signing, totpLogin }" @submit.prevent="onSubmit">
|
||||||
|
<div class="auth _section">
|
||||||
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
|
<div class="avatar" :style="{ backgroundImage: user ? `url('${ user.avatarUrl }')` : null }" v-show="withAvatar"></div>
|
||||||
<div class="normal-signin" v-if="!totpLogin">
|
<div class="normal-signin" v-if="!totpLogin">
|
||||||
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:value="onUsernameChange">
|
<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required @update:value="onUsernameChange">
|
||||||
@ -12,9 +13,6 @@
|
|||||||
<template #prefix><Fa :icon="faLock"/></template>
|
<template #prefix><Fa :icon="faLock"/></template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $t('loggingIn') : $t('login') }}</MkButton>
|
<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $t('loggingIn') : $t('login') }}</MkButton>
|
||||||
<a class="_panelButton" style="margin: 8px auto;" v-if="meta && meta.enableTwitterIntegration" :href="`${apiUrl}/signin/twitter`"><Fa :icon="faTwitter" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Twitter' }) }}</a>
|
|
||||||
<a class="_panelButton" style="margin: 8px auto;" v-if="meta && meta.enableGithubIntegration" :href="`${apiUrl}/signin/github`"><Fa :icon="faGithub" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'GitHub' }) }}</a>
|
|
||||||
<a class="_panelButton" style="margin: 8px auto;" v-if="meta && meta.enableDiscordIntegration" :href="`${apiUrl}/signin/discord`"><Fa :icon="faDiscord" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Discord' }) }}</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="2fa-signin" v-if="totpLogin" :class="{ securityKeys: user && user.securityKeys }">
|
<div class="2fa-signin" v-if="totpLogin" :class="{ securityKeys: user && user.securityKeys }">
|
||||||
<div v-if="user && user.securityKeys" class="twofa-group tap-group">
|
<div v-if="user && user.securityKeys" class="twofa-group tap-group">
|
||||||
@ -39,6 +37,12 @@
|
|||||||
<MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? $t('loggingIn') : $t('login') }}</MkButton>
|
<MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? $t('loggingIn') : $t('login') }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="social _section">
|
||||||
|
<a class="_borderButton _vMargin" v-if="meta && meta.enableTwitterIntegration" :href="`${apiUrl}/signin/twitter`"><Fa :icon="faTwitter" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Twitter' }) }}</a>
|
||||||
|
<a class="_borderButton _vMargin" v-if="meta && meta.enableGithubIntegration" :href="`${apiUrl}/signin/github`"><Fa :icon="faGithub" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'GitHub' }) }}</a>
|
||||||
|
<a class="_borderButton _vMargin" v-if="meta && meta.enableDiscordIntegration" :href="`${apiUrl}/signin/discord`"><Fa :icon="faDiscord" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Discord' }) }}</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -203,6 +207,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.eppvobhk {
|
.eppvobhk {
|
||||||
|
> .auth {
|
||||||
> .avatar {
|
> .avatar {
|
||||||
margin: 0 auto 0 auto;
|
margin: 0 auto 0 auto;
|
||||||
width: 64px;
|
width: 64px;
|
||||||
@ -213,4 +218,5 @@ export default defineComponent({
|
|||||||
border-radius: 100%;
|
border-radius: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
<div class="body">
|
<div class="body">
|
||||||
<span v-if="note.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
|
<span v-if="note.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
|
||||||
<span v-if="note.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
|
<span v-if="note.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
|
||||||
<router-link class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></router-link>
|
<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></MkA>
|
||||||
<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis"/>
|
<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis"/>
|
||||||
<router-link class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</router-link>
|
<MkA class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
|
||||||
</div>
|
</div>
|
||||||
<details v-if="note.files.length > 0">
|
<details v-if="note.files.length > 0">
|
||||||
<summary>({{ $t('withNFiles', { n: note.files.length }) }})</summary>
|
<summary>({{ $t('withNFiles', { n: note.files.length }) }})</summary>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="pxhvhrfw" v-size="{ max: [500] }">
|
<div class="pxhvhrfw" v-size="{ max: [500] }">
|
||||||
<button v-for="item in items" class="_button" @click="$emit('update:value', item.value)" :class="{ active: value === item.value }" :key="item.value"><Fa v-if="item.icon" :icon="item.icon" class="icon"/>{{ item.label }}</button>
|
<button v-for="item in items" class="_button" @click="$emit('update:value', item.value)" :class="{ active: value === item.value }" :disabled="value === item.value" :key="item.value"><Fa v-if="item.icon" :icon="item.icon" class="icon"/>{{ item.label }}</button>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -23,19 +23,26 @@ export default defineComponent({
|
|||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.pxhvhrfw {
|
.pxhvhrfw {
|
||||||
display: flex;
|
display: flex;
|
||||||
max-width: var(--baseContentWidth);
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
> button {
|
> button {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 15px 12px 12px 12px;
|
padding: 15px 12px 12px 12px;
|
||||||
border-bottom: solid 3px transparent;
|
border-bottom: solid 3px transparent;
|
||||||
|
|
||||||
|
&:disabled {
|
||||||
|
opacity: 1 !important;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
border-bottom-color: var(--accent);
|
border-bottom-color: var(--accent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:not(.active):hover {
|
||||||
|
color: var(--fgHighlighted);
|
||||||
|
}
|
||||||
|
|
||||||
> .icon {
|
> .icon {
|
||||||
margin-right: 6px;
|
margin-right: 6px;
|
||||||
}
|
}
|
||||||
|
70
src/client/components/taskmanager.api-window.vue
Normal file
70
src/client/components/taskmanager.api-window.vue
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<XWindow ref="window"
|
||||||
|
:initial-width="370"
|
||||||
|
:initial-height="450"
|
||||||
|
:can-resize="true"
|
||||||
|
@close="$refs.window.close()"
|
||||||
|
@closed="$emit('closed')"
|
||||||
|
>
|
||||||
|
<template #header>Req Viewer</template>
|
||||||
|
|
||||||
|
<div class="rlkneywz">
|
||||||
|
<MkTab v-model:value="tab" :items="[{ label: 'Request', value: 'req', }, { label: 'Response', value: 'res', }]" style="border-bottom: solid 1px var(--divider);"/>
|
||||||
|
|
||||||
|
<code v-if="tab === 'req'">{{ reqStr }}</code>
|
||||||
|
<code v-if="tab === 'res'">{{ resStr }}</code>
|
||||||
|
</div>
|
||||||
|
</XWindow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import * as JSON5 from 'json5';
|
||||||
|
import XWindow from '@/components/ui/window.vue';
|
||||||
|
import MkTab from '@/components/tab.vue';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XWindow,
|
||||||
|
MkTab,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
req: {
|
||||||
|
required: true,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['closed'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
tab: 'req',
|
||||||
|
reqStr: JSON5.stringify(this.req.req, null, '\t'),
|
||||||
|
resStr: JSON5.stringify(this.req.res, null, '\t'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.rlkneywz {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
> code {
|
||||||
|
display: block;
|
||||||
|
flex: 1;
|
||||||
|
padding: 8px;
|
||||||
|
overflow: auto;
|
||||||
|
font-size: 0.9em;
|
||||||
|
tab-size: 2;
|
||||||
|
white-space: pre;
|
||||||
|
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
231
src/client/components/taskmanager.vue
Normal file
231
src/client/components/taskmanager.vue
Normal file
@ -0,0 +1,231 @@
|
|||||||
|
<template>
|
||||||
|
<XWindow ref="window" :initial-width="650" :initial-height="420" :can-resize="true" @closed="$emit('closed')">
|
||||||
|
<template #header>
|
||||||
|
<Fa :icon="faTerminal" style="margin-right: 0.5em;"/>Task Manager
|
||||||
|
</template>
|
||||||
|
<div class="qljqmnzj">
|
||||||
|
<MkTab v-model:value="tab" :items="[{ label: 'Windows', value: 'windows', }, { label: 'Stream', value: 'stream', }, { label: 'Stream (Pool)', value: 'streamPool', }, { label: 'API', value: 'api', }]" style="border-bottom: solid 1px var(--divider);"/>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
<div v-if="tab === 'windows'" class="windows" v-follow>
|
||||||
|
<div class="header">
|
||||||
|
<div>#ID</div>
|
||||||
|
<div>Component</div>
|
||||||
|
<div>Action</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="p in popups">
|
||||||
|
<div>#{{ p.id }}</div>
|
||||||
|
<div>{{ p.component.name ? p.component.name : '<anonymous>' }}</div>
|
||||||
|
<div><button class="_textButton" @click="killPopup(p)">Kill</button></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="tab === 'stream'" class="stream" v-follow>
|
||||||
|
<div class="header">
|
||||||
|
<div>#ID</div>
|
||||||
|
<div>Ch</div>
|
||||||
|
<div>Handle</div>
|
||||||
|
<div>In</div>
|
||||||
|
<div>Out</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="c in connections">
|
||||||
|
<div>#{{ c.id }}</div>
|
||||||
|
<div>{{ c.channel }}</div>
|
||||||
|
<div v-if="c.users !== null">(shared)<span v-if="c.name">{{ ' ' + c.name }}</span></div>
|
||||||
|
<div v-else>{{ c.name ? c.name : '<anonymous>' }}</div>
|
||||||
|
<div>{{ c.in }}</div>
|
||||||
|
<div>{{ c.out }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="tab === 'streamPool'" class="streamPool" v-follow>
|
||||||
|
<div class="header">
|
||||||
|
<div>#ID</div>
|
||||||
|
<div>Ch</div>
|
||||||
|
<div>Users</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="p in pools">
|
||||||
|
<div>#{{ p.id }}</div>
|
||||||
|
<div>{{ p.channel }}</div>
|
||||||
|
<div>{{ p.users }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="tab === 'api'" class="api" v-follow>
|
||||||
|
<div class="header">
|
||||||
|
<div>#ID</div>
|
||||||
|
<div>Endpoint</div>
|
||||||
|
<div>State</div>
|
||||||
|
</div>
|
||||||
|
<div v-for="req in apiRequests" @click="showReq(req)">
|
||||||
|
<div>#{{ req.id }}</div>
|
||||||
|
<div>{{ req.endpoint }}</div>
|
||||||
|
<div class="state" :class="req.state">{{ req.state }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer>
|
||||||
|
<div><span class="label">Windows</span>{{ popups.length }}</div>
|
||||||
|
<div><span class="label">Stream</span>{{ connections.length }}</div>
|
||||||
|
<div><span class="label">Stream (Pool)</span>{{ pools.length }}</div>
|
||||||
|
</footer>
|
||||||
|
</div>
|
||||||
|
</XWindow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, markRaw, onBeforeUnmount, ref, shallowRef } from 'vue';
|
||||||
|
import { faTerminal } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import XWindow from '@/components/ui/window.vue';
|
||||||
|
import MkTab from '@/components/tab.vue';
|
||||||
|
import MkButton from '@/components/ui/button.vue';
|
||||||
|
import follow from '@/directives/follow-append';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XWindow,
|
||||||
|
MkTab,
|
||||||
|
MkButton,
|
||||||
|
},
|
||||||
|
|
||||||
|
directives: {
|
||||||
|
follow
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['closed'],
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const connections = shallowRef([]);
|
||||||
|
const pools = shallowRef([]);
|
||||||
|
const refreshStreamInfo = () => {
|
||||||
|
console.log(os.stream.sharedConnectionPools, os.stream.sharedConnections, os.stream.nonSharedConnections);
|
||||||
|
const conn = os.stream.sharedConnections.map(c => ({
|
||||||
|
id: c.id, name: c.name, channel: c.channel, users: c.pool.users, in: c.inCount, out: c.outCount,
|
||||||
|
})).concat(os.stream.nonSharedConnections.map(c => ({
|
||||||
|
id: c.id, name: c.name, channel: c.channel, users: null, in: c.inCount, out: c.outCount,
|
||||||
|
})));
|
||||||
|
conn.sort((a, b) => (a.id > b.id) ? 1 : -1);
|
||||||
|
connections.value = conn;
|
||||||
|
pools.value = os.stream.sharedConnectionPools;
|
||||||
|
};
|
||||||
|
const interval = setInterval(refreshStreamInfo, 1000);
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
clearInterval(interval);
|
||||||
|
});
|
||||||
|
|
||||||
|
const killPopup = p => {
|
||||||
|
os.popups.value = os.popups.value.filter(x => x !== p);
|
||||||
|
};
|
||||||
|
|
||||||
|
const showReq = req => {
|
||||||
|
os.popup(import('./taskmanager.api-window.vue'), {
|
||||||
|
req: req
|
||||||
|
}, {
|
||||||
|
}, 'closed');
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
tab: ref('stream'),
|
||||||
|
popups: os.popups,
|
||||||
|
apiRequests: os.apiRequests,
|
||||||
|
connections,
|
||||||
|
pools,
|
||||||
|
killPopup,
|
||||||
|
showReq,
|
||||||
|
faTerminal,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.qljqmnzj {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
|
||||||
|
|
||||||
|
> .content {
|
||||||
|
flex: 1;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: table;
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: table-row;
|
||||||
|
|
||||||
|
&:nth-child(even) {
|
||||||
|
//background: rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.header {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
> div {
|
||||||
|
display: table-cell;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.api {
|
||||||
|
> div {
|
||||||
|
&:not(.header) {
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .state {
|
||||||
|
&.pending {
|
||||||
|
color: var(--warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
color: var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.failed {
|
||||||
|
color: var(--error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> footer {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-top: solid 1px var(--divider);
|
||||||
|
font-size: 0.9em;
|
||||||
|
|
||||||
|
> div {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
> .label {
|
||||||
|
opacity: 0.7;
|
||||||
|
margin-right: 0.5em;
|
||||||
|
|
||||||
|
&:after {
|
||||||
|
content: ":";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<time class="mk-time" :title="absolute">
|
<time :title="absolute">
|
||||||
<template v-if="mode == 'relative'">{{ relative }}</template>
|
<template v-if="mode == 'relative'">{{ relative }}</template>
|
||||||
<template v-else-if="mode == 'absolute'">{{ absolute }}</template>
|
<template v-else-if="mode == 'absolute'">{{ absolute }}</template>
|
||||||
<template v-else-if="mode == 'detail'">{{ absolute }} ({{ relative }})</template>
|
<template v-else-if="mode == 'detail'">{{ absolute }} ({{ relative }})</template>
|
||||||
|
133
src/client/components/ui/a.vue
Normal file
133
src/client/components/ui/a.vue
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<template>
|
||||||
|
<a :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu">
|
||||||
|
<slot></slot>
|
||||||
|
</a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { faExpandAlt, faColumns, faExternalLinkAlt, faLink, faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import copyToClipboard from '@/scripts/copy-to-clipboard';
|
||||||
|
import { router } from '@/router';
|
||||||
|
import { ui, url } from '@/config';
|
||||||
|
import { popout } from '@/scripts/popout';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
inject: {
|
||||||
|
navHook: {
|
||||||
|
default: null
|
||||||
|
},
|
||||||
|
sideViewHook: {
|
||||||
|
default: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
to: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
activeClass: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
behavior: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
active() {
|
||||||
|
if (this.activeClass == null) return false;
|
||||||
|
const resolved = router.resolve(this.to);
|
||||||
|
if (resolved.path == this.$route.path) return true;
|
||||||
|
if (resolved.name == null) return false;
|
||||||
|
if (this.$route.name == null) return false;
|
||||||
|
return resolved.name == this.$route.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
onContextmenu(e) {
|
||||||
|
if (window.getSelection().toString() !== '') return;
|
||||||
|
os.contextMenu([{
|
||||||
|
type: 'label',
|
||||||
|
text: this.to,
|
||||||
|
}, {
|
||||||
|
icon: faWindowMaximize,
|
||||||
|
text: this.$t('openInWindow'),
|
||||||
|
action: () => {
|
||||||
|
os.pageWindow(this.to);
|
||||||
|
}
|
||||||
|
}, this.sideViewHook ? {
|
||||||
|
icon: faColumns,
|
||||||
|
text: this.$t('openInSideView'),
|
||||||
|
action: () => {
|
||||||
|
this.sideViewHook(this.to);
|
||||||
|
}
|
||||||
|
} : undefined, {
|
||||||
|
icon: faExpandAlt,
|
||||||
|
text: this.$t('showInPage'),
|
||||||
|
action: () => {
|
||||||
|
this.$router.push(this.to);
|
||||||
|
}
|
||||||
|
}, null, {
|
||||||
|
icon: faExternalLinkAlt,
|
||||||
|
text: this.$t('openInNewTab'),
|
||||||
|
action: () => {
|
||||||
|
window.open(this.to, '_blank');
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
icon: faLink,
|
||||||
|
text: this.$t('copyLink'),
|
||||||
|
action: () => {
|
||||||
|
copyToClipboard(`${url}${this.to}`);
|
||||||
|
}
|
||||||
|
}], e);
|
||||||
|
},
|
||||||
|
|
||||||
|
window() {
|
||||||
|
os.pageWindow(this.to);
|
||||||
|
},
|
||||||
|
|
||||||
|
popout() {
|
||||||
|
popout(this.to);
|
||||||
|
},
|
||||||
|
|
||||||
|
nav() {
|
||||||
|
if (this.to.startsWith('/my/messaging')) {
|
||||||
|
if (this.$store.state.device.chatOpenBehavior === 'window') return this.window();
|
||||||
|
if (this.$store.state.device.chatOpenBehavior === 'popout') return this.popout();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.behavior) {
|
||||||
|
if (this.behavior === 'window') {
|
||||||
|
return this.window();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.navHook) {
|
||||||
|
this.navHook(this.to);
|
||||||
|
} else {
|
||||||
|
if (this.$store.state.device.defaultSideView && this.sideViewHook && this.to !== '/') {
|
||||||
|
return this.sideViewHook(this.to);
|
||||||
|
}
|
||||||
|
if (this.$store.state.device.deckNavWindow && (ui === 'deck') && this.to !== '/') {
|
||||||
|
return this.window();
|
||||||
|
}
|
||||||
|
if (ui === 'desktop') {
|
||||||
|
return this.window();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.$router.currentRoute.value.path === this.to) {
|
||||||
|
window.scroll({ top: 0, behavior: 'smooth' });
|
||||||
|
} else {
|
||||||
|
this.$router.push(this.to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@ -1,7 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="nvlagfpb">
|
<transition :name="$store.state.device.animation ? 'fade' : ''" appear>
|
||||||
|
<div class="nvlagfpb" @contextmenu.prevent.stop="() => {}">
|
||||||
<MkMenu :items="items" @close="$emit('closed')" class="_popup _shadow" :align="'left'"/>
|
<MkMenu :items="items" @close="$emit('closed')" class="_popup _shadow" :align="'left'"/>
|
||||||
</div>
|
</div>
|
||||||
|
</transition>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
@ -35,8 +37,30 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$el.style.top = this.ev.pageY + 'px';
|
let left = this.ev.pageX + 1; // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
|
||||||
this.$el.style.left = this.ev.pageX + 'px';
|
let top = this.ev.pageY + 1; // 間違って右ダブルクリックした場合に意図せずアイテムがクリックされるのを防ぐため + 1
|
||||||
|
|
||||||
|
const width = this.$el.offsetWidth;
|
||||||
|
const height = this.$el.offsetHeight;
|
||||||
|
|
||||||
|
if (left + width - window.pageXOffset > window.innerWidth) {
|
||||||
|
left = window.innerWidth - width + window.pageXOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top + height - window.pageYOffset > window.innerHeight) {
|
||||||
|
top = window.innerHeight - height + window.pageYOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (top < 0) {
|
||||||
|
top = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left < 0) {
|
||||||
|
left = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$el.style.top = top + 'px';
|
||||||
|
this.$el.style.left = left + 'px';
|
||||||
|
|
||||||
for (const el of Array.from(document.querySelectorAll('body *'))) {
|
for (const el of Array.from(document.querySelectorAll('body *'))) {
|
||||||
el.addEventListener('mousedown', this.onMousedown);
|
el.addEventListener('mousedown', this.onMousedown);
|
||||||
@ -60,4 +84,14 @@ export default defineComponent({
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 65535;
|
z-index: 65535;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fade-enter-active, .fade-leave-active {
|
||||||
|
transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
|
transform-origin: left top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-enter-from, .fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.9);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -132,7 +132,7 @@ export default defineComponent({
|
|||||||
&.max-width_500px {
|
&.max-width_500px {
|
||||||
> header {
|
> header {
|
||||||
> .title {
|
> .title {
|
||||||
padding: 8px 10px;
|
padding: 8px 10px 8px 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,22 +12,22 @@
|
|||||||
<span v-else-if="item.type === 'pending'" :tabindex="i" class="pending item">
|
<span v-else-if="item.type === 'pending'" :tabindex="i" class="pending item">
|
||||||
<span><MkEllipsis/></span>
|
<span><MkEllipsis/></span>
|
||||||
</span>
|
</span>
|
||||||
<router-link v-else-if="item.type === 'link'" :to="item.to" @click.passive="close()" :tabindex="i" class="_button item">
|
<MkA v-else-if="item.type === 'link'" :to="item.to" @click.passive="close()" :tabindex="i" class="_button item">
|
||||||
<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||||
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
|
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
|
||||||
</router-link>
|
</MkA>
|
||||||
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item">
|
<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item">
|
||||||
<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
|
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
|
||||||
</a>
|
</a>
|
||||||
<button v-else-if="item.type === 'user'" @click="clicked(item.action)" :tabindex="i" class="_button item">
|
<button v-else-if="item.type === 'user'" @click="clicked(item.action, $event)" :tabindex="i" class="_button item">
|
||||||
<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
|
<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
|
||||||
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
|
<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-else @click="clicked(item.action)" :tabindex="i" class="_button item" :class="{ danger: item.danger }">
|
<button v-else @click="clicked(item.action, $event)" :tabindex="i" class="_button item" :class="{ danger: item.danger }">
|
||||||
<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
|
||||||
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
@ -115,8 +115,8 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
clicked(fn) {
|
clicked(fn, ev) {
|
||||||
fn();
|
fn(ev);
|
||||||
this.close();
|
this.close();
|
||||||
},
|
},
|
||||||
close() {
|
close() {
|
||||||
|
@ -175,7 +175,7 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
.modal-popup-content-enter-active, .modal-popup-content-leave-active {
|
.modal-popup-content-enter-active, .modal-popup-content-leave-active {
|
||||||
transition: opacity 0.3s, transform 0.3s !important;
|
transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
||||||
}
|
}
|
||||||
.modal-popup-content-enter-from, .modal-popup-content-leave-to {
|
.modal-popup-content-enter-from, .modal-popup-content-leave-to {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="cxiknjgy" :class="{ autoMargin }">
|
<div class="cxiknjgy">
|
||||||
<slot :items="items"></slot>
|
<slot :items="items"></slot>
|
||||||
<div class="empty" v-if="empty" key="_empty_">
|
<div class="empty" v-if="empty" key="_empty_">
|
||||||
<slot name="empty"></slot>
|
<slot name="empty"></slot>
|
||||||
@ -31,24 +31,12 @@ export default defineComponent({
|
|||||||
pagination: {
|
pagination: {
|
||||||
required: true
|
required: true
|
||||||
},
|
},
|
||||||
autoMargin: {
|
|
||||||
required: false,
|
|
||||||
default: true
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.cxiknjgy {
|
.cxiknjgy {
|
||||||
&.autoMargin > *:not(:last-child) {
|
|
||||||
margin-bottom: 16px;
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .more > .button {
|
> .more > .button {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
|
@ -51,7 +51,8 @@ export default defineComponent({
|
|||||||
.novjtctn {
|
.novjtctn {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 0 32px 0 0;
|
margin: 16px 32px 0 0;
|
||||||
|
text-align: left;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 0.3s;
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
<div class="adhpbeos" :class="{ focused, filled, tall, pre }">
|
<div class="adhpbeos" :class="{ focused, filled, tall, pre }">
|
||||||
<div class="input">
|
<div class="input">
|
||||||
<span class="label" ref="label"><slot></slot></span>
|
<span class="label" ref="label"><slot></slot></span>
|
||||||
<textarea ref="input"
|
<textarea ref="input" :class="{ code }"
|
||||||
:value="value"
|
:value="value"
|
||||||
:required="required"
|
:required="required"
|
||||||
:readonly="readonly"
|
:readonly="readonly"
|
||||||
:pattern="pattern"
|
:pattern="pattern"
|
||||||
:autocomplete="autocomplete"
|
:autocomplete="autocomplete"
|
||||||
|
:spellcheck="!code"
|
||||||
@input="onInput"
|
@input="onInput"
|
||||||
@focus="focused = true"
|
@focus="focused = true"
|
||||||
@blur="focused = false"
|
@blur="focused = false"
|
||||||
@ -20,7 +21,6 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@ -43,6 +43,10 @@ export default defineComponent({
|
|||||||
type: String,
|
type: String,
|
||||||
required: false
|
required: false
|
||||||
},
|
},
|
||||||
|
code: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false
|
||||||
|
},
|
||||||
tall: {
|
tall: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false,
|
required: false,
|
||||||
@ -159,6 +163,11 @@ export default defineComponent({
|
|||||||
outline: none;
|
outline: none;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
|
|
||||||
|
&.code {
|
||||||
|
tab-size: 2;
|
||||||
|
font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,14 +2,16 @@
|
|||||||
<transition :name="$store.state.device.animation ? 'window' : ''" appear @after-leave="$emit('closed')">
|
<transition :name="$store.state.device.animation ? 'window' : ''" appear @after-leave="$emit('closed')">
|
||||||
<div class="ebkgocck" v-if="showing">
|
<div class="ebkgocck" v-if="showing">
|
||||||
<div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
|
<div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
|
||||||
<div class="header">
|
<div class="header" @contextmenu.prevent.stop="onContextmenu">
|
||||||
<button class="_button" @click="close()"><Fa :icon="faTimes"/></button>
|
<slot v-if="closeRight" name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
|
||||||
|
<button v-else class="_button" @click="close()"><Fa :icon="faTimes"/></button>
|
||||||
|
|
||||||
<span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
|
<span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
|
||||||
<slot name="header"></slot>
|
<slot name="header"></slot>
|
||||||
</span>
|
</span>
|
||||||
<slot name="buttons">
|
|
||||||
<button class="_button" style="pointer-events: none;"></button>
|
<button v-if="closeRight" class="_button" @click="close()"><Fa :icon="faTimes"/></button>
|
||||||
</slot>
|
<slot v-else name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
|
||||||
</div>
|
</div>
|
||||||
<div class="body" v-if="padding">
|
<div class="body" v-if="padding">
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
@ -85,6 +87,15 @@ export default defineComponent({
|
|||||||
required: false,
|
required: false,
|
||||||
default: false,
|
default: false,
|
||||||
},
|
},
|
||||||
|
closeRight: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
contextmenu: {
|
||||||
|
type: Array,
|
||||||
|
required: false,
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['closed'],
|
emits: ['closed'],
|
||||||
@ -108,6 +119,9 @@ export default defineComponent({
|
|||||||
z: Number(document.defaultView.getComputedStyle(this.$el, null).zIndex)
|
z: Number(document.defaultView.getComputedStyle(this.$el, null).zIndex)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 他のウィンドウ内のボタンなどを押してこのウィンドウが開かれた場合、親が最前面になろうとするのでそれに隠されないようにする
|
||||||
|
this.top();
|
||||||
|
|
||||||
window.addEventListener('resize', this.onBrowserResize);
|
window.addEventListener('resize', this.onBrowserResize);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -129,6 +143,12 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onContextmenu(e) {
|
||||||
|
if (this.contextmenu) {
|
||||||
|
os.contextMenu(this.contextmenu, e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
// 最前面へ移動
|
// 最前面へ移動
|
||||||
top() {
|
top() {
|
||||||
let z = 0;
|
let z = 0;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div v-else class="mk-url-preview" v-size="{ max: [400, 350] }">
|
<div v-else class="mk-url-preview" v-size="{ max: [400, 350] }">
|
||||||
<transition name="zoom" mode="out-in">
|
<transition name="zoom" mode="out-in">
|
||||||
<component :is="self ? 'router-link' : 'a'" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url" v-if="!fetching">
|
<component :is="self ? 'MkA' : 'a'" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url" v-if="!fetching">
|
||||||
<div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`">
|
<div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`">
|
||||||
<button class="_button" v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$t('enablePlayer')"><Fa :icon="faPlayCircle"/></button>
|
<button class="_button" v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$t('enablePlayer')"><Fa :icon="faPlayCircle"/></button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<component :is="self ? 'router-link' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
<component :is="self ? 'MkA' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
|
||||||
@mouseover="onMouseover"
|
@mouseover="onMouseover"
|
||||||
@mouseleave="onMouseleave"
|
@mouseleave="onMouseleave"
|
||||||
>
|
>
|
||||||
@ -71,7 +71,7 @@ export default defineComponent({
|
|||||||
if (!document.body.contains(this.$el)) return;
|
if (!document.body.contains(this.$el)) return;
|
||||||
if (this.close) return;
|
if (this.close) return;
|
||||||
|
|
||||||
const { dispose } = os.popup(await import('@/components/url-preview-popup.vue'), {
|
const { dispose } = await os.popup(import('@/components/url-preview-popup.vue'), {
|
||||||
url: this.url,
|
url: this.url,
|
||||||
source: this.$el
|
source: this.$el
|
||||||
});
|
});
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
|
<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
|
||||||
<MkAvatar class="avatar" :user="user" :disable-preview="true"/>
|
<MkAvatar class="avatar" :user="user" :disable-preview="true"/>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<router-link class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></router-link>
|
<MkA class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
|
||||||
<p class="username"><MkAcct :user="user"/></p>
|
<p class="username"><MkAcct :user="user"/></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
@ -96,7 +96,7 @@ export default defineComponent({
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: var(--text);
|
color: var(--fg);
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,7 +125,7 @@ export default defineComponent({
|
|||||||
> p {
|
> p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
color: var(--text);
|
color: var(--fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
|
<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
|
||||||
<MkAvatar class="avatar" :user="user" :disable-preview="true"/>
|
<MkAvatar class="avatar" :user="user" :disable-preview="true"/>
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<router-link class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></router-link>
|
<MkA class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
|
||||||
<p class="username"><MkAcct :user="user"/></p>
|
<p class="username"><MkAcct :user="user"/></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
@ -151,7 +151,7 @@ export default defineComponent({
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: var(--text);
|
color: var(--fg);
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,7 +159,7 @@ export default defineComponent({
|
|||||||
> .description {
|
> .description {
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
color: var(--text);
|
color: var(--fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
> .status {
|
> .status {
|
||||||
@ -172,7 +172,7 @@ export default defineComponent({
|
|||||||
> p {
|
> p {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 0.7em;
|
font-size: 0.7em;
|
||||||
color: var(--text);
|
color: var(--fg);
|
||||||
}
|
}
|
||||||
|
|
||||||
> span {
|
> span {
|
||||||
|
@ -14,10 +14,10 @@
|
|||||||
<MkInput v-model:value="host" class="input" @update:value="search"><span>{{ $t('host') }}</span><template #prefix>@</template></MkInput>
|
<MkInput v-model:value="host" class="input" @update:value="search"><span>{{ $t('host') }}</span><template #prefix>@</template></MkInput>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="tbhwbxda _section" :style="users.length > 0 ? 'padding: 0;' : ''">
|
<div class="tbhwbxda _section result" v-if="username != '' || host != ''" :class="{ hit: users.length > 0 }">
|
||||||
<div class="users" v-if="users.length > 0">
|
<div class="users" v-if="users.length > 0">
|
||||||
<div class="user" v-for="user in users" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
|
<div class="user" v-for="user in users" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
|
||||||
<MkAvatar :user="user" class="avatar" :disable-link="true"/>
|
<MkAvatar :user="user" class="avatar"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<MkUserName :user="user" class="name"/>
|
<MkUserName :user="user" class="name"/>
|
||||||
<MkAcct :user="user" class="acct"/>
|
<MkAcct :user="user" class="acct"/>
|
||||||
@ -28,6 +28,17 @@
|
|||||||
<span>{{ $t('noUsers') }}</span>
|
<span>{{ $t('noUsers') }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="tbhwbxda _section recent" v-if="username == '' && host == ''">
|
||||||
|
<div class="users">
|
||||||
|
<div class="user" v-for="user in recentUsers" :key="user.id" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
|
||||||
|
<MkAvatar :user="user" class="avatar"/>
|
||||||
|
<div class="body">
|
||||||
|
<MkUserName :user="user" class="name"/>
|
||||||
|
<MkAcct :user="user" class="acct"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</XModalWindow>
|
</XModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -53,18 +64,23 @@ export default defineComponent({
|
|||||||
return {
|
return {
|
||||||
username: '',
|
username: '',
|
||||||
host: '',
|
host: '',
|
||||||
|
recentUsers: [],
|
||||||
users: [],
|
users: [],
|
||||||
selected: null,
|
selected: null,
|
||||||
faTimes, faCheck
|
faTimes, faCheck
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
async mounted() {
|
||||||
this.focus();
|
this.focus();
|
||||||
|
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.focus();
|
this.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.recentUsers = await os.api('users/show', {
|
||||||
|
userIds: this.$store.state.device.recentlyUsedUsers
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@ -90,6 +106,12 @@ export default defineComponent({
|
|||||||
ok() {
|
ok() {
|
||||||
this.$emit('ok', this.selected);
|
this.$emit('ok', this.selected);
|
||||||
this.$refs.dialog.close();
|
this.$refs.dialog.close();
|
||||||
|
|
||||||
|
// 最近使ったユーザー更新
|
||||||
|
let recents = this.$store.state.device.recentlyUsedUsers;
|
||||||
|
recents = recents.filter(x => x !== this.selected.id);
|
||||||
|
recents.unshift(this.selected.id);
|
||||||
|
this.$store.commit('device/set', { key: 'recentlyUsedUsers', value: recents.splice(0, 16) });
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
@ -107,6 +129,14 @@ export default defineComponent({
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
&.result.hit {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.recent {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
> .inputs {
|
> .inputs {
|
||||||
> .input {
|
> .input {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
@ -6,13 +6,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="users">
|
<div class="users">
|
||||||
<router-link v-for="item in items" class="user" :key="item.id" :to="userPage(extract ? extract(item) : item)">
|
<MkA v-for="item in items" class="user" :key="item.id" :to="userPage(extract ? extract(item) : item)">
|
||||||
<MkAvatar :user="extract ? extract(item) : item" class="avatar" :disable-link="true"/>
|
<MkAvatar :user="extract ? extract(item) : item" class="avatar" :disable-link="true"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<MkUserName :user="extract ? extract(item) : item" class="name"/>
|
<MkUserName :user="extract ? extract(item) : item" class="name"/>
|
||||||
<MkAcct :user="extract ? extract(item) : item" class="acct"/>
|
<MkAcct :user="extract ? extract(item) : item" class="acct"/>
|
||||||
</div>
|
</div>
|
||||||
</router-link>
|
</MkA>
|
||||||
</div>
|
</div>
|
||||||
<button class="more _button" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching">
|
<button class="more _button" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching">
|
||||||
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
|
||||||
|
@ -12,5 +12,6 @@ export const lang = localStorage.getItem('lang');
|
|||||||
export const langs = _LANGS_;
|
export const langs = _LANGS_;
|
||||||
export const getLocale = async () => Object.fromEntries((await entries(clientDb.i18n)) as [string, string][]);
|
export const getLocale = async () => Object.fromEntries((await entries(clientDb.i18n)) as [string, string][]);
|
||||||
export const version = _VERSION_;
|
export const version = _VERSION_;
|
||||||
export const instanceName = siteName === 'Misskey' ? null : siteName;
|
export const instanceName = siteName === 'Misskey' ? host : siteName;
|
||||||
export const deckmode = localStorage.getItem('deckmode') === 'true';
|
export const ui = localStorage.getItem('ui');
|
||||||
|
export const debug = localStorage.getItem('debug') === 'true';
|
||||||
|
25
src/client/directives/follow-append.ts
Normal file
25
src/client/directives/follow-append.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { Directive } from 'vue';
|
||||||
|
import { getScrollContainer, getScrollPosition } from '@/scripts/scroll';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
mounted(src, binding, vn) {
|
||||||
|
const ro = new ResizeObserver((entries, observer) => {
|
||||||
|
const pos = getScrollPosition(src);
|
||||||
|
const container = getScrollContainer(src);
|
||||||
|
const viewHeight = container.clientHeight;
|
||||||
|
const height = container.scrollHeight;
|
||||||
|
if (pos + viewHeight > height - 32) {
|
||||||
|
container.scrollTop = height;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ro.observe(src);
|
||||||
|
|
||||||
|
// TODO: 新たにプロパティを作るのをやめMapを使う
|
||||||
|
src._ro_ = ro;
|
||||||
|
},
|
||||||
|
|
||||||
|
unmounted(src, binding, vn) {
|
||||||
|
src._ro_.unobserve(src);
|
||||||
|
}
|
||||||
|
} as Directive;
|
@ -23,13 +23,13 @@ export default {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const show = async e => {
|
const show = e => {
|
||||||
if (!document.body.contains(el)) return;
|
if (!document.body.contains(el)) return;
|
||||||
if (self._close) return;
|
if (self._close) return;
|
||||||
if (self.text == null) return;
|
if (self.text == null) return;
|
||||||
|
|
||||||
const showing = ref(true);
|
const showing = ref(true);
|
||||||
popup(await import('@/components/ui/tooltip.vue'), {
|
popup(import('@/components/ui/tooltip.vue'), {
|
||||||
showing,
|
showing,
|
||||||
text: self.text,
|
text: self.text,
|
||||||
source: el
|
source: el
|
||||||
|
@ -18,13 +18,13 @@ export class UserPreview {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@autobind
|
@autobind
|
||||||
private async show() {
|
private show() {
|
||||||
if (!document.body.contains(this.el)) return;
|
if (!document.body.contains(this.el)) return;
|
||||||
if (this.promise) return;
|
if (this.promise) return;
|
||||||
|
|
||||||
const showing = ref(true);
|
const showing = ref(true);
|
||||||
|
|
||||||
popup(await import('@/components/user-preview.vue'), {
|
popup(import('@/components/user-preview.vue'), {
|
||||||
showing,
|
showing,
|
||||||
q: this.user,
|
q: this.user,
|
||||||
source: this.el
|
source: this.el
|
||||||
|
@ -7,11 +7,10 @@ import '@/style.scss';
|
|||||||
import { createApp } from 'vue';
|
import { createApp } from 'vue';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
|
||||||
|
|
||||||
import Root from './root.vue';
|
|
||||||
import widgets from './widgets';
|
import widgets from './widgets';
|
||||||
import directives from './directives';
|
import directives from './directives';
|
||||||
import components from '@/components';
|
import components from '@/components';
|
||||||
import { version, apiUrl } from '@/config';
|
import { version, apiUrl, ui } from '@/config';
|
||||||
import { store } from './store';
|
import { store } from './store';
|
||||||
import { router } from './router';
|
import { router } from './router';
|
||||||
import { applyTheme } from '@/scripts/theme';
|
import { applyTheme } from '@/scripts/theme';
|
||||||
@ -152,7 +151,13 @@ store.dispatch('instance/fetch').then(() => {
|
|||||||
|
|
||||||
stream.init(store.state.i);
|
stream.init(store.state.i);
|
||||||
|
|
||||||
const app = createApp(Root);
|
const app = createApp(await (
|
||||||
|
window.location.search === '?zen' ? import('@/ui/zen.vue') :
|
||||||
|
!store.getters.isSignedIn ? import('@/ui/visitor.vue') :
|
||||||
|
ui === 'deck' ? import('@/ui/deck.vue') :
|
||||||
|
ui === 'desktop' ? import('@/ui/desktop.vue') :
|
||||||
|
import('@/ui/default.vue')
|
||||||
|
).then(x => x.default));
|
||||||
|
|
||||||
if (_DEV_) {
|
if (_DEV_) {
|
||||||
app.config.performance = true;
|
app.config.performance = true;
|
||||||
@ -248,7 +253,7 @@ if (store.getters.isSignedIn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const main = stream.useSharedConnection('main');
|
const main = stream.useSharedConnection('main', 'System');
|
||||||
|
|
||||||
// 自分の情報が更新されたとき
|
// 自分の情報が更新されたとき
|
||||||
main.on('meUpdated', i => {
|
main.on('meUpdated', i => {
|
||||||
|
@ -2,38 +2,41 @@ import { Component, defineAsyncComponent, markRaw, reactive, Ref, ref } from 'vu
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import Stream from '@/scripts/stream';
|
import Stream from '@/scripts/stream';
|
||||||
import { store } from '@/store';
|
import { store } from '@/store';
|
||||||
import { apiUrl } from '@/config';
|
import { apiUrl, debug } from '@/config';
|
||||||
import MkPostFormDialog from '@/components/post-form-dialog.vue';
|
import MkPostFormDialog from '@/components/post-form-dialog.vue';
|
||||||
import MkWaitingDialog from '@/components/waiting-dialog.vue';
|
import MkWaitingDialog from '@/components/waiting-dialog.vue';
|
||||||
|
import { resolve } from '@/router';
|
||||||
|
|
||||||
const ua = navigator.userAgent.toLowerCase();
|
const ua = navigator.userAgent.toLowerCase();
|
||||||
export const isMobile = /mobile|iphone|ipad|android/.test(ua);
|
export const isMobile = /mobile|iphone|ipad|android/.test(ua);
|
||||||
|
|
||||||
export const stream = new Stream();
|
export const stream = markRaw(new Stream());
|
||||||
|
|
||||||
export const pendingApiRequestsCount = ref(0);
|
export const pendingApiRequestsCount = ref(0);
|
||||||
|
let apiRequestsCount = 0; // for debug
|
||||||
|
export const apiRequests = ref([]); // for debug
|
||||||
|
|
||||||
export const windows = new Map();
|
export const windows = new Map();
|
||||||
|
|
||||||
export function api(endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) {
|
export function api(endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined) {
|
||||||
pendingApiRequestsCount.value++;
|
pendingApiRequestsCount.value++;
|
||||||
|
|
||||||
if (_DEV_) {
|
|
||||||
performance.mark(_PERF_PREFIX_ + 'api:begin');
|
|
||||||
}
|
|
||||||
|
|
||||||
const onFinally = () => {
|
const onFinally = () => {
|
||||||
pendingApiRequestsCount.value--;
|
pendingApiRequestsCount.value--;
|
||||||
|
|
||||||
if (_DEV_) {
|
|
||||||
performance.mark(_PERF_PREFIX_ + 'api:end');
|
|
||||||
|
|
||||||
performance.measure(_PERF_PREFIX_ + 'api',
|
|
||||||
_PERF_PREFIX_ + 'api:begin',
|
|
||||||
_PERF_PREFIX_ + 'api:end');
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const log = debug ? reactive({
|
||||||
|
id: ++apiRequestsCount,
|
||||||
|
endpoint,
|
||||||
|
req: markRaw(data),
|
||||||
|
res: null,
|
||||||
|
state: 'pending',
|
||||||
|
}) : null;
|
||||||
|
if (debug) {
|
||||||
|
apiRequests.value.push(log);
|
||||||
|
if (apiRequests.value.length > 128) apiRequests.value.shift();
|
||||||
|
}
|
||||||
|
|
||||||
const promise = new Promise((resolve, reject) => {
|
const promise = new Promise((resolve, reject) => {
|
||||||
// Append a credential
|
// Append a credential
|
||||||
if (store.getters.isSignedIn) (data as any).i = store.state.i.token;
|
if (store.getters.isSignedIn) (data as any).i = store.state.i.token;
|
||||||
@ -50,10 +53,21 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
|
|||||||
|
|
||||||
if (res.status === 200) {
|
if (res.status === 200) {
|
||||||
resolve(body);
|
resolve(body);
|
||||||
|
if (debug) {
|
||||||
|
log.res = markRaw(body);
|
||||||
|
log.state = 'success';
|
||||||
|
}
|
||||||
} else if (res.status === 204) {
|
} else if (res.status === 204) {
|
||||||
resolve();
|
resolve();
|
||||||
|
if (debug) {
|
||||||
|
log.state = 'success';
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
reject(body.error);
|
reject(body.error);
|
||||||
|
if (debug) {
|
||||||
|
log.res = markRaw(body.error);
|
||||||
|
log.state = 'failed';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}).catch(reject);
|
}).catch(reject);
|
||||||
});
|
});
|
||||||
@ -74,7 +88,7 @@ export function apiWithDialog(
|
|||||||
promiseDialog(promise, onSuccess, onFailure ? onFailure : (e) => {
|
promiseDialog(promise, onSuccess, onFailure ? onFailure : (e) => {
|
||||||
dialog({
|
dialog({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
text: e.message + '<br>' + (e as any).id,
|
text: e.message + '\n' + (e as any).id,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -126,17 +140,20 @@ function isModule(x: any): x is typeof import('*.vue') {
|
|||||||
return x.default != null;
|
return x.default != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let popupIdCount = 0;
|
||||||
export const popups = ref([]) as Ref<{
|
export const popups = ref([]) as Ref<{
|
||||||
id: any;
|
id: any;
|
||||||
component: any;
|
component: any;
|
||||||
props: Record<string, any>;
|
props: Record<string, any>;
|
||||||
}[]>;
|
}[]>;
|
||||||
|
|
||||||
export function popup(component: Component | typeof import('*.vue'), props: Record<string, any>, events = {}, disposeEvent?: string) {
|
export async function popup(component: Component | typeof import('*.vue') | Promise<Component | typeof import('*.vue')>, props: Record<string, any>, events = {}, disposeEvent?: string) {
|
||||||
|
if (component.then) component = await component;
|
||||||
|
|
||||||
if (isModule(component)) component = component.default;
|
if (isModule(component)) component = component.default;
|
||||||
markRaw(component);
|
markRaw(component);
|
||||||
|
|
||||||
const id = Math.random().toString(); // TODO: uuidとか使う
|
const id = ++popupIdCount;
|
||||||
const dispose = () => {
|
const dispose = () => {
|
||||||
if (_DEV_) console.log('os:popup close', id, component, props, events);
|
if (_DEV_) console.log('os:popup close', id, component, props, events);
|
||||||
// このsetTimeoutが無いと挙動がおかしくなる(autocompleteが閉じなくなる)。Vueのバグ?
|
// このsetTimeoutが無いと挙動がおかしくなる(autocompleteが閉じなくなる)。Vueのバグ?
|
||||||
@ -162,9 +179,10 @@ export function popup(component: Component | typeof import('*.vue'), props: Reco
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pageWindow(url: string, component: Component | typeof import('*.vue'), props: Record<string, any>) {
|
export function pageWindow(path: string) {
|
||||||
popup(defineAsyncComponent(() => import('@/components/page-window.vue')), {
|
const { component, props } = resolve(path);
|
||||||
initialUrl: url,
|
popup(import('@/components/page-window.vue'), {
|
||||||
|
initialPath: path,
|
||||||
initialComponent: markRaw(component),
|
initialComponent: markRaw(component),
|
||||||
initialProps: props,
|
initialProps: props,
|
||||||
}, {}, 'closed');
|
}, {}, 'closed');
|
||||||
@ -172,7 +190,7 @@ export function pageWindow(url: string, component: Component | typeof import('*.
|
|||||||
|
|
||||||
export function dialog(props: Record<string, any>) {
|
export function dialog(props: Record<string, any>) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/dialog.vue')), props, {
|
popup(import('@/components/dialog.vue'), props, {
|
||||||
done: result => {
|
done: result => {
|
||||||
resolve(result ? result : { canceled: true });
|
resolve(result ? result : { canceled: true });
|
||||||
},
|
},
|
||||||
@ -186,7 +204,7 @@ export function success() {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
showing.value = false;
|
showing.value = false;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
popup(defineAsyncComponent(() => import('@/components/waiting-dialog.vue')), {
|
popup(import('@/components/waiting-dialog.vue'), {
|
||||||
success: true,
|
success: true,
|
||||||
showing: showing
|
showing: showing
|
||||||
}, {
|
}, {
|
||||||
@ -198,7 +216,7 @@ export function success() {
|
|||||||
export function waiting() {
|
export function waiting() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const showing = ref(true);
|
const showing = ref(true);
|
||||||
popup(defineAsyncComponent(() => import('@/components/waiting-dialog.vue')), {
|
popup(import('@/components/waiting-dialog.vue'), {
|
||||||
success: false,
|
success: false,
|
||||||
showing: showing
|
showing: showing
|
||||||
}, {
|
}, {
|
||||||
@ -209,7 +227,7 @@ export function waiting() {
|
|||||||
|
|
||||||
export function form(title, form) {
|
export function form(title, form) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/form-dialog.vue')), { title, form }, {
|
popup(import('@/components/form-dialog.vue'), { title, form }, {
|
||||||
done: result => {
|
done: result => {
|
||||||
resolve(result);
|
resolve(result);
|
||||||
},
|
},
|
||||||
@ -219,7 +237,7 @@ export function form(title, form) {
|
|||||||
|
|
||||||
export async function selectUser() {
|
export async function selectUser() {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/user-select-dialog.vue')), {}, {
|
popup(import('@/components/user-select-dialog.vue'), {}, {
|
||||||
ok: user => {
|
ok: user => {
|
||||||
resolve(user);
|
resolve(user);
|
||||||
},
|
},
|
||||||
@ -229,7 +247,7 @@ export async function selectUser() {
|
|||||||
|
|
||||||
export async function selectDriveFile(multiple: boolean) {
|
export async function selectDriveFile(multiple: boolean) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/drive-window.vue')), {
|
popup(import('@/components/drive-select-dialog.vue'), {
|
||||||
type: 'file',
|
type: 'file',
|
||||||
multiple
|
multiple
|
||||||
}, {
|
}, {
|
||||||
@ -244,7 +262,7 @@ export async function selectDriveFile(multiple: boolean) {
|
|||||||
|
|
||||||
export async function selectDriveFolder(multiple: boolean) {
|
export async function selectDriveFolder(multiple: boolean) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/drive-window.vue')), {
|
popup(import('@/components/drive-select-dialog.vue'), {
|
||||||
type: 'folder',
|
type: 'folder',
|
||||||
multiple
|
multiple
|
||||||
}, {
|
}, {
|
||||||
@ -259,7 +277,7 @@ export async function selectDriveFolder(multiple: boolean) {
|
|||||||
|
|
||||||
export async function pickEmoji(src?: HTMLElement) {
|
export async function pickEmoji(src?: HTMLElement) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
popup(defineAsyncComponent(() => import('@/components/emoji-picker.vue')), {
|
popup(import('@/components/emoji-picker.vue'), {
|
||||||
src
|
src
|
||||||
}, {
|
}, {
|
||||||
done: emoji => {
|
done: emoji => {
|
||||||
@ -271,7 +289,8 @@ export async function pickEmoji(src?: HTMLElement) {
|
|||||||
|
|
||||||
export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: string; viaKeyboard?: boolean }) {
|
export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: string; viaKeyboard?: boolean }) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/ui/modal-menu.vue')), {
|
let dispose;
|
||||||
|
popup(import('@/components/ui/modal-menu.vue'), {
|
||||||
items,
|
items,
|
||||||
src,
|
src,
|
||||||
align: options?.align,
|
align: options?.align,
|
||||||
@ -281,6 +300,8 @@ export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: s
|
|||||||
resolve();
|
resolve();
|
||||||
dispose();
|
dispose();
|
||||||
},
|
},
|
||||||
|
}).then(res => {
|
||||||
|
dispose = res.dispose;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -288,7 +309,8 @@ export function modalMenu(items: any[], src?: HTMLElement, options?: { align?: s
|
|||||||
export function contextMenu(items: any[], ev: MouseEvent) {
|
export function contextMenu(items: any[], ev: MouseEvent) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const { dispose } = popup(defineAsyncComponent(() => import('@/components/ui/context-menu.vue')), {
|
let dispose;
|
||||||
|
popup(import('@/components/ui/context-menu.vue'), {
|
||||||
items,
|
items,
|
||||||
ev,
|
ev,
|
||||||
}, {
|
}, {
|
||||||
@ -296,6 +318,8 @@ export function contextMenu(items: any[], ev: MouseEvent) {
|
|||||||
resolve();
|
resolve();
|
||||||
dispose();
|
dispose();
|
||||||
},
|
},
|
||||||
|
}).then(res => {
|
||||||
|
dispose = res.dispose;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -307,11 +331,14 @@ export function post(props: Record<string, any>) {
|
|||||||
// Vueが渡されたコンポーネントに内部的に__propsというプロパティを生やす影響で、
|
// Vueが渡されたコンポーネントに内部的に__propsというプロパティを生やす影響で、
|
||||||
// 複数のpost formを開いたときに場合によってはエラーになる
|
// 複数のpost formを開いたときに場合によってはエラーになる
|
||||||
// もちろん複数のpost formを開けること自体Misskeyサイドのバグなのだが
|
// もちろん複数のpost formを開けること自体Misskeyサイドのバグなのだが
|
||||||
const { dispose } = popup(MkPostFormDialog, props, {
|
let dispose;
|
||||||
|
popup(MkPostFormDialog, props, {
|
||||||
closed: () => {
|
closed: () => {
|
||||||
resolve();
|
resolve();
|
||||||
dispose();
|
dispose();
|
||||||
},
|
},
|
||||||
|
}).then(res => {
|
||||||
|
dispose = res.dispose;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -22,10 +22,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('error'),
|
title: this.$t('error'),
|
||||||
icon: faExclamationTriangle
|
icon: faExclamationTriangle
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
faExclamationTriangle
|
faExclamationTriangle
|
||||||
};
|
};
|
||||||
|
@ -87,10 +87,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('aboutMisskey'),
|
title: this.$t('aboutMisskey'),
|
||||||
icon: null
|
icon: null
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
version,
|
version,
|
||||||
faInfoCircle
|
faInfoCircle
|
||||||
|
@ -37,10 +37,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('about'),
|
title: this.$t('about'),
|
||||||
icon: faInfoCircle
|
icon: faInfoCircle
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
version,
|
version,
|
||||||
serverInfo: null,
|
serverInfo: null,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content" ref="list">
|
<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content" ref="list">
|
||||||
<section class="_card announcement" v-for="(announcement, i) in items" :key="announcement.id">
|
<section class="_card announcement _vMargin" v-for="(announcement, i) in items" :key="announcement.id">
|
||||||
<div class="_title"><span v-if="$store.getters.isSignedIn && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
|
<div class="_title"><span v-if="$store.getters.isSignedIn && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<Mfm :text="announcement.text"/>
|
<Mfm :text="announcement.text"/>
|
||||||
@ -31,10 +31,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('announcements'),
|
title: this.$t('announcements'),
|
||||||
icon: faBroadcastTower
|
icon: faBroadcastTower
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
endpoint: 'announcements',
|
endpoint: 'announcements',
|
||||||
|
94
src/client/pages/api-console.vue
Normal file
94
src/client/pages/api-console.vue
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<section class="_section">
|
||||||
|
<MkInput v-model:value="endpoint" :datalist="endpoints" @update:value="onEndpointChange()">
|
||||||
|
<span>Endpoint</span>
|
||||||
|
</MkInput>
|
||||||
|
<MkTextarea v-model:value="body" code>
|
||||||
|
<span>Params (JSON or JSON5)</span>
|
||||||
|
</MkTextarea>
|
||||||
|
<MkSwitch v-model:value="withCredential">
|
||||||
|
With credential
|
||||||
|
</MkSwitch>
|
||||||
|
<MkButton primary full @click="send" :disabled="sending">
|
||||||
|
<template v-if="sending"><MkEllipsis/></template>
|
||||||
|
<template v-else><Fa :icon="faPaperPlane"/> Send</template>
|
||||||
|
</MkButton>
|
||||||
|
</section>
|
||||||
|
<section class="_section" v-if="res">
|
||||||
|
<MkTextarea v-model:value="res" code readonly tall>
|
||||||
|
<span>Response</span>
|
||||||
|
</MkTextarea>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { faTerminal, faPaperPlane } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import * as JSON5 from 'json5';
|
||||||
|
import MkButton from '@/components/ui/button.vue';
|
||||||
|
import MkInput from '@/components/ui/input.vue';
|
||||||
|
import MkTextarea from '@/components/ui/textarea.vue';
|
||||||
|
import MkSwitch from '@/components/ui/switch.vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
MkButton, MkInput, MkTextarea, MkSwitch,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
INFO: {
|
||||||
|
title: 'API console',
|
||||||
|
icon: faTerminal
|
||||||
|
},
|
||||||
|
|
||||||
|
endpoint: '',
|
||||||
|
body: '{}',
|
||||||
|
res: null,
|
||||||
|
sending: false,
|
||||||
|
endpoints: [],
|
||||||
|
withCredential: true,
|
||||||
|
|
||||||
|
faPaperPlane
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
os.api('endpoints').then(endpoints => {
|
||||||
|
this.endpoints = endpoints;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
send() {
|
||||||
|
this.sending = true;
|
||||||
|
os.api(this.endpoint, JSON5.parse(this.body)).then(res => {
|
||||||
|
this.sending = false;
|
||||||
|
this.res = JSON5.stringify(res, null, 2);
|
||||||
|
}, err => {
|
||||||
|
this.sending = false;
|
||||||
|
this.res = JSON5.stringify(err, null, 2);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onEndpointChange() {
|
||||||
|
os.api('endpoint', { endpoint: this.endpoint }, this.withCredential ? undefined : null).then(endpoint => {
|
||||||
|
const body = {};
|
||||||
|
for (const p of endpoint.params) {
|
||||||
|
body[p.name] =
|
||||||
|
p.type === 'String' ? '' :
|
||||||
|
p.type === 'Number' ? 0 :
|
||||||
|
p.type === 'Boolean' ? false :
|
||||||
|
p.type === 'Array' ? [] :
|
||||||
|
p.type === 'Object' ? {} :
|
||||||
|
null;
|
||||||
|
}
|
||||||
|
this.body = JSON5.stringify(body, null, 2);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@ -51,10 +51,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('installedApps'),
|
title: this.$t('installedApps'),
|
||||||
icon: faPlug,
|
icon: faPlug,
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
endpoint: 'i/apps',
|
endpoint: 'i/apps',
|
||||||
|
@ -46,15 +46,11 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: computed(() => this.channelId ? {
|
INFO: computed(() => this.channelId ? {
|
||||||
header: [{
|
|
||||||
title: this.$t('_channel.edit'),
|
title: this.$t('_channel.edit'),
|
||||||
icon: faSatelliteDish,
|
icon: faSatelliteDish,
|
||||||
}],
|
|
||||||
} : {
|
} : {
|
||||||
header: [{
|
|
||||||
title: this.$t('_channel.create'),
|
title: this.$t('_channel.create'),
|
||||||
icon: faSatelliteDish,
|
icon: faSatelliteDish,
|
||||||
}],
|
|
||||||
}),
|
}),
|
||||||
channel: null,
|
channel: null,
|
||||||
name: null,
|
name: null,
|
||||||
|
@ -54,10 +54,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: computed(() => this.channel ? {
|
INFO: computed(() => this.channel ? {
|
||||||
header: [{
|
|
||||||
title: this.channel.name,
|
title: this.channel.name,
|
||||||
icon: faSatelliteDish,
|
icon: faSatelliteDish,
|
||||||
}],
|
|
||||||
} : null),
|
} : null),
|
||||||
channel: null,
|
channel: null,
|
||||||
showBanner: true,
|
showBanner: true,
|
||||||
|
@ -43,10 +43,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('channel'),
|
title: this.$t('channel'),
|
||||||
icon: faSatelliteDish
|
icon: faSatelliteDish
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
tab: 'featured',
|
tab: 'featured',
|
||||||
featuredPagination: {
|
featuredPagination: {
|
||||||
|
@ -43,10 +43,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.title,
|
title: this.title,
|
||||||
icon: faFileAlt
|
icon: faFileAlt
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
faFileAlt,
|
faFileAlt,
|
||||||
title: '',
|
title: '',
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
<div class="_content">
|
<div class="_content">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="doc in docs" :key="doc.path">
|
<li v-for="doc in docs" :key="doc.path">
|
||||||
<router-link :to="`/docs/${doc.path}`">{{ doc.title }}</router-link>
|
<MkA :to="`/docs/${doc.path}`">{{ doc.title }}</MkA>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -21,10 +21,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('help'),
|
title: this.$t('help'),
|
||||||
icon: faQuestionCircle
|
icon: faQuestionCircle
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
docs: [],
|
docs: [],
|
||||||
faQuestionCircle
|
faQuestionCircle
|
||||||
|
@ -18,10 +18,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: computed(() => this.folder ? this.folder.name : this.$t('drive')),
|
title: computed(() => this.folder ? this.folder.name : this.$t('drive')),
|
||||||
icon: faCloud,
|
icon: faCloud,
|
||||||
}],
|
|
||||||
action: {
|
action: {
|
||||||
icon: faEllipsisH,
|
icon: faEllipsisH,
|
||||||
handler: this.menu
|
handler: this.menu
|
||||||
|
@ -38,8 +38,8 @@
|
|||||||
<template #header><Fa :icon="faHashtag" fixed-width style="margin-right: 0.5em;"/>{{ $t('popularTags') }}</template>
|
<template #header><Fa :icon="faHashtag" fixed-width style="margin-right: 0.5em;"/>{{ $t('popularTags') }}</template>
|
||||||
|
|
||||||
<div class="vxjfqztj">
|
<div class="vxjfqztj">
|
||||||
<router-link v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</router-link>
|
<MkA v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</MkA>
|
||||||
<router-link v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</router-link>
|
<MkA v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</MkA>
|
||||||
</div>
|
</div>
|
||||||
</MkFolder>
|
</MkFolder>
|
||||||
|
|
||||||
@ -93,10 +93,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('explore'),
|
title: this.$t('explore'),
|
||||||
icon: faHashtag
|
icon: faHashtag
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
pinnedUsers: { endpoint: 'pinned-users' },
|
pinnedUsers: { endpoint: 'pinned-users' },
|
||||||
popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: {
|
popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: {
|
||||||
|
@ -19,10 +19,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('favorites'),
|
title: this.$t('favorites'),
|
||||||
icon: faStar
|
icon: faStar
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
endpoint: 'i/favorites',
|
endpoint: 'i/favorites',
|
||||||
|
@ -18,10 +18,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('featured'),
|
title: this.$t('featured'),
|
||||||
icon: faFireAlt
|
icon: faFireAlt
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
endpoint: 'notes/featured',
|
endpoint: 'notes/featured',
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
<MkAvatar class="avatar" :user="req.follower"/>
|
<MkAvatar class="avatar" :user="req.follower"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<router-link class="name" :to="userPage(req.follower)" v-user-preview="req.follower.id"><MkUserName :user="req.follower"/></router-link>
|
<MkA class="name" :to="userPage(req.follower)" v-user-preview="req.follower.id"><MkUserName :user="req.follower"/></MkA>
|
||||||
<p class="acct">@{{ acct(req.follower) }}</p>
|
<p class="acct">@{{ acct(req.follower) }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="description" v-if="req.follower.description" :title="req.follower.description">
|
<div class="description" v-if="req.follower.description" :title="req.follower.description">
|
||||||
@ -44,10 +44,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('followRequests'),
|
title: this.$t('followRequests'),
|
||||||
icon: faUserClock,
|
icon: faUserClock,
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
pagination: {
|
pagination: {
|
||||||
endpoint: 'following/requests/list',
|
endpoint: 'following/requests/list',
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
</div>
|
</div>
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<MkPagination :pagination="pagination" #default="{items}" ref="reports" :auto-margin="false" style="margin-top: var(--margin);">
|
<MkPagination :pagination="pagination" #default="{items}" ref="reports" style="margin-top: var(--margin);">
|
||||||
<div class="bcekxzvu _card _vMargin" v-for="report in items" :key="report.id">
|
<div class="bcekxzvu _card _vMargin" v-for="report in items" :key="report.id">
|
||||||
<div class="_content target">
|
<div class="_content target">
|
||||||
<MkAvatar class="avatar" :user="report.targetUser"/>
|
<MkAvatar class="avatar" :user="report.targetUser"/>
|
||||||
@ -84,10 +84,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('abuseReports'),
|
title: this.$t('abuseReports'),
|
||||||
icon: faExclamationCircle
|
icon: faExclamationCircle
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
searchUsername: '',
|
searchUsername: '',
|
||||||
searchHost: '',
|
searchHost: '',
|
||||||
|
@ -45,10 +45,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('announcements'),
|
title: this.$t('announcements'),
|
||||||
icon: faBroadcastTower
|
icon: faBroadcastTower
|
||||||
}]
|
|
||||||
},
|
},
|
||||||
announcements: [],
|
announcements: [],
|
||||||
faBroadcastTower, faSave, faTrashAlt, faPlus
|
faBroadcastTower, faSave, faTrashAlt, faPlus
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
<div class="_content local" v-if="tab === 'local'">
|
<div class="local" v-if="tab === 'local'">
|
||||||
<MkButton primary @click="add" style="margin: 0 auto var(--margin) auto;"><Fa :icon="faPlus"/> {{ $t('addEmoji') }}</MkButton>
|
<MkButton primary @click="add" style="margin: 0 auto var(--margin) auto;"><Fa :icon="faPlus"/> {{ $t('addEmoji') }}</MkButton>
|
||||||
<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $t('search') }}</span></MkInput>
|
<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $t('search') }}</span></MkInput>
|
||||||
<MkPagination :pagination="pagination" ref="emojis">
|
<MkPagination :pagination="pagination" ref="emojis">
|
||||||
@ -24,7 +24,7 @@
|
|||||||
</MkPagination>
|
</MkPagination>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="_content remote" v-else-if="tab === 'remote'">
|
<div class="remote" v-else-if="tab === 'remote'">
|
||||||
<MkInput v-model:value="queryRemote" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $t('search') }}</span></MkInput>
|
<MkInput v-model:value="queryRemote" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $t('search') }}</span></MkInput>
|
||||||
<MkInput v-model:value="host" :debounce="true"><span>{{ $t('host') }}</span></MkInput>
|
<MkInput v-model:value="host" :debounce="true"><span>{{ $t('host') }}</span></MkInput>
|
||||||
<MkPagination :pagination="remotePagination" ref="remoteEmojis">
|
<MkPagination :pagination="remotePagination" ref="remoteEmojis">
|
||||||
@ -68,10 +68,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('customEmojis'),
|
title: this.$t('customEmojis'),
|
||||||
icon: faLaugh
|
icon: faLaugh,
|
||||||
}],
|
|
||||||
action: {
|
action: {
|
||||||
icon: faPlus,
|
icon: faPlus,
|
||||||
handler: this.add
|
handler: this.add
|
||||||
@ -83,14 +81,14 @@ export default defineComponent({
|
|||||||
host: '',
|
host: '',
|
||||||
pagination: {
|
pagination: {
|
||||||
endpoint: 'admin/emoji/list',
|
endpoint: 'admin/emoji/list',
|
||||||
limit: 15,
|
limit: 30,
|
||||||
params: computed(() => ({
|
params: computed(() => ({
|
||||||
query: (this.query && this.query !== '') ? this.query : null
|
query: (this.query && this.query !== '') ? this.query : null
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
remotePagination: {
|
remotePagination: {
|
||||||
endpoint: 'admin/emoji/list-remote',
|
endpoint: 'admin/emoji/list-remote',
|
||||||
limit: 15,
|
limit: 30,
|
||||||
params: computed(() => ({
|
params: computed(() => ({
|
||||||
query: (this.queryRemote && this.queryRemote !== '') ? this.queryRemote : null,
|
query: (this.queryRemote && this.queryRemote !== '') ? this.queryRemote : null,
|
||||||
host: (this.host && this.host !== '') ? this.host : null
|
host: (this.host && this.host !== '') ? this.host : null
|
||||||
@ -113,8 +111,8 @@ export default defineComponent({
|
|||||||
os.promiseDialog(promise);
|
os.promiseDialog(promise);
|
||||||
},
|
},
|
||||||
|
|
||||||
async edit(emoji) {
|
edit(emoji) {
|
||||||
os.popup(await import('./emoji-edit-dialog.vue'), {
|
os.popup(import('./emoji-edit-dialog.vue'), {
|
||||||
emoji: emoji
|
emoji: emoji
|
||||||
}, {
|
}, {
|
||||||
done: result => {
|
done: result => {
|
||||||
|
@ -79,10 +79,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('federation'),
|
title: this.$t('federation'),
|
||||||
icon: faGlobe
|
icon: faGlobe
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
host: '',
|
host: '',
|
||||||
state: 'federating',
|
state: 'federating',
|
||||||
|
@ -84,8 +84,8 @@ export default defineComponent({
|
|||||||
Progress.done();
|
Progress.done();
|
||||||
},
|
},
|
||||||
|
|
||||||
async showUser() {
|
showUser() {
|
||||||
os.popup(await import('./user-dialog.vue'), {
|
os.popup(import('./user-dialog.vue'), {
|
||||||
userId: this.file.userId
|
userId: this.file.userId
|
||||||
}, {}, 'closed');
|
}, {}, 'closed');
|
||||||
},
|
},
|
||||||
|
@ -34,7 +34,7 @@
|
|||||||
<span>{{ $t('type') }}</span>
|
<span>{{ $t('type') }}</span>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
</div>
|
</div>
|
||||||
<MkPagination :pagination="pagination" #default="{items}" class="urempief" ref="files" :auto-margin="false">
|
<MkPagination :pagination="pagination" #default="{items}" class="urempief" ref="files">
|
||||||
<button class="file _panel _button _vMargin" v-for="file in items" :key="file.id" @click="show(file, $event)">
|
<button class="file _panel _button _vMargin" v-for="file in items" :key="file.id" @click="show(file, $event)">
|
||||||
<MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/>
|
<MkDriveFileThumbnail class="thumbnail" :file="file" fit="contain"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
@ -42,7 +42,8 @@
|
|||||||
<small style="opacity: 0.7;">{{ file.name }}</small>
|
<small style="opacity: 0.7;">{{ file.name }}</small>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<MkAcct :user="file.user"/>
|
<MkAcct v-if="file.user" :user="file.user"/>
|
||||||
|
<div v-else>{{ $t('system') }}</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span style="margin-right: 1em;">{{ file.type }}</span>
|
<span style="margin-right: 1em;">{{ file.type }}</span>
|
||||||
@ -83,10 +84,8 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
|
||||||
title: this.$t('files'),
|
title: this.$t('files'),
|
||||||
icon: faCloud
|
icon: faCloud
|
||||||
}],
|
|
||||||
},
|
},
|
||||||
q: null,
|
q: null,
|
||||||
origin: 'local',
|
origin: 'local',
|
||||||
@ -130,8 +129,8 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
async show(file, ev) {
|
show(file, ev) {
|
||||||
os.popup(await import('./file-dialog.vue'), {
|
os.popup(import('./file-dialog.vue'), {
|
||||||
fileId: file.id
|
fileId: file.id
|
||||||
}, {}, 'closed');
|
}, {}, 'closed');
|
||||||
},
|
},
|
||||||
|
@ -86,7 +86,7 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
INFO: {
|
INFO: {
|
||||||
header: [{
|
tabs: [{
|
||||||
id: 'index',
|
id: 'index',
|
||||||
title: null,
|
title: null,
|
||||||
tooltip: this.$t('instance'),
|
tooltip: this.$t('instance'),
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user