Compare commits
53 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
834cb2ea1a | ||
![]() |
d82769abd4 | ||
![]() |
adf01ed4a4 | ||
![]() |
09c007b3aa | ||
![]() |
526ff177aa | ||
![]() |
0e40d4e796 | ||
![]() |
172ebab7bd | ||
![]() |
aa4493fe5c | ||
![]() |
a68a88f79e | ||
![]() |
1de7dc94e1 | ||
![]() |
59cb7992e2 | ||
![]() |
87b15df47b | ||
![]() |
6932d86240 | ||
![]() |
87f61e714a | ||
![]() |
5762e2d9ba | ||
![]() |
f0691c8a4f | ||
![]() |
6d7e4fe2a1 | ||
![]() |
7dc789f470 | ||
![]() |
190d1bbf3c | ||
![]() |
a755dd5f9e | ||
![]() |
0846a7b94e | ||
![]() |
d8be0511f1 | ||
![]() |
fb07116a4c | ||
![]() |
fe453c15e3 | ||
![]() |
059aeef6a0 | ||
![]() |
30e25451d6 | ||
![]() |
7f0fd55c9a | ||
![]() |
0e9b496deb | ||
![]() |
8294c18e70 | ||
![]() |
39575b4696 | ||
![]() |
29e9801d5c | ||
![]() |
eaf83bffb0 | ||
![]() |
bb25ece745 | ||
![]() |
754b5629e4 | ||
![]() |
ee63403548 | ||
![]() |
87edeb41da | ||
![]() |
41fe804587 | ||
![]() |
02466acc4b | ||
![]() |
8470a64e6b | ||
![]() |
9939e0f9a9 | ||
![]() |
ce5f552d0c | ||
![]() |
7d4c535233 | ||
![]() |
57cd0fb93f | ||
![]() |
a15299ae53 | ||
![]() |
1df7abfbb9 | ||
![]() |
85a0f696bc | ||
![]() |
ba3c62bf9c | ||
![]() |
c17e97b6a6 | ||
![]() |
2d80cd0e7b | ||
![]() |
eedc572f0c | ||
![]() |
2de1df3514 | ||
![]() |
2d96af1255 | ||
![]() |
163325ef89 |
@@ -154,3 +154,6 @@ id: 'aid'
|
|||||||
|
|
||||||
# Media Proxy
|
# Media Proxy
|
||||||
#mediaProxy: https://example.com/proxy
|
#mediaProxy: https://example.com/proxy
|
||||||
|
|
||||||
|
# Sign to ActivityPub GET request (default: false)
|
||||||
|
#signToActivityPubGet: true
|
||||||
|
2613
CHANGELOG.md
2613
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
|||||||
[](http://makeapullrequest.com)
|
[](http://makeapullrequest.com)
|
||||||
[](https://github.com/humanetech-community/awesome-humane-tech)
|
[](https://github.com/humanetech-community/awesome-humane-tech)
|
||||||
|
|
||||||
**A forever evolving, sophisticated microblogging platform.**
|
**A forever evolving, professional microblogging platform.**
|
||||||
|
|
||||||
<p align="justify">
|
<p align="justify">
|
||||||
<a href="https://join.misskey.page/">Misskey</a> is a decentralized microblogging platform born on Earth.
|
<a href="https://join.misskey.page/">Misskey</a> is a decentralized microblogging platform born on Earth.
|
||||||
|
@@ -14,8 +14,12 @@ noNotes: "لم يتم العثور على أية ملاحظات"
|
|||||||
noNotifications: "ليس هناك أية اشعارات"
|
noNotifications: "ليس هناك أية اشعارات"
|
||||||
instance: "مثيل الخادم"
|
instance: "مثيل الخادم"
|
||||||
settings: "الاعدادات"
|
settings: "الاعدادات"
|
||||||
|
basicSettings: "الاعدادات الأساسية"
|
||||||
|
otherSettings: "إعدادات أخرى"
|
||||||
|
openInWindow: "افتح في نافذة جديدة"
|
||||||
profile: "الملف التعريفي"
|
profile: "الملف التعريفي"
|
||||||
timeline: "الخيط الزمني"
|
timeline: "الخيط الزمني"
|
||||||
|
noAccountDescription: "لم يكتب هذا المستخدم سيرته بعد."
|
||||||
login: "لِج"
|
login: "لِج"
|
||||||
loggingIn: "جارٍ تسجيل الدخول"
|
loggingIn: "جارٍ تسجيل الدخول"
|
||||||
logout: "الخروج"
|
logout: "الخروج"
|
||||||
@@ -32,18 +36,26 @@ copyContent: "انسخ المحتوى"
|
|||||||
copyLink: "انسخ الرابط"
|
copyLink: "انسخ الرابط"
|
||||||
delete: "حذف"
|
delete: "حذف"
|
||||||
deleteAndEdit: "إزالة وإعادة الصياغة"
|
deleteAndEdit: "إزالة وإعادة الصياغة"
|
||||||
|
deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها."
|
||||||
addToList: "أضفه إلى قائمة"
|
addToList: "أضفه إلى قائمة"
|
||||||
sendMessage: "أرسل رسالة"
|
sendMessage: "أرسل رسالة"
|
||||||
copyUsername: "انسخ اسم المستخدم"
|
copyUsername: "انسخ اسم المستخدم"
|
||||||
|
searchUser: "ابحث عن مستخدمين"
|
||||||
reply: "رد"
|
reply: "رد"
|
||||||
loadMore: "عرض المزيد"
|
loadMore: "عرض المزيد"
|
||||||
youGotNewFollower: "يتابعك"
|
youGotNewFollower: "يتابعك"
|
||||||
|
receiveFollowRequest: "تلقيت طلب متابعة"
|
||||||
|
followRequestAccepted: "قُبل طلب المتابعة"
|
||||||
|
mention: "أشر الى"
|
||||||
mentions: "الإشارات"
|
mentions: "الإشارات"
|
||||||
directNotes: "الملاحظات المباشرة"
|
directNotes: "الملاحظات المباشرة"
|
||||||
|
importAndExport: "إستورد / صدر"
|
||||||
import: "استيراد"
|
import: "استيراد"
|
||||||
export: "تصدير"
|
export: "تصدير"
|
||||||
files: "الملفات"
|
files: "الملفات"
|
||||||
download: "تنزيل"
|
download: "تنزيل"
|
||||||
|
driveFileDeleteConfirm: "أمتأكد من حذف ملف {name}؟ كل الملاحظات المُرفق بها هذا الملف ستحذف."
|
||||||
|
unfollowConfirm: "أمتأكد من إلغاء متابعة {name}؟"
|
||||||
lists: "القوائم"
|
lists: "القوائم"
|
||||||
noLists: "ليس لديك أية قائمة"
|
noLists: "ليس لديك أية قائمة"
|
||||||
note: "ملاحظة"
|
note: "ملاحظة"
|
||||||
@@ -53,8 +65,10 @@ followers: "المتابِعين"
|
|||||||
followsYou: "يتابعك"
|
followsYou: "يتابعك"
|
||||||
createList: "إنشاء قائمة"
|
createList: "إنشاء قائمة"
|
||||||
manageLists: "إدارة القوائم"
|
manageLists: "إدارة القوائم"
|
||||||
error: "حدث خطأ ما"
|
error: "خطأ"
|
||||||
|
somethingHappened: "حدث خطأ"
|
||||||
retry: "حاول مجددًا"
|
retry: "حاول مجددًا"
|
||||||
|
pageLoadError: "فشل تحميل الصفحة"
|
||||||
enterListName: "اسم القائمة"
|
enterListName: "اسم القائمة"
|
||||||
privacy: "الخصوصية"
|
privacy: "الخصوصية"
|
||||||
makeFollowManuallyApprove: "القبول يدويا طلبات الإشتراك"
|
makeFollowManuallyApprove: "القبول يدويا طلبات الإشتراك"
|
||||||
@@ -71,16 +85,24 @@ you: "أنت"
|
|||||||
clickToShow: "اضغط للعرض"
|
clickToShow: "اضغط للعرض"
|
||||||
sensitive: "محتوى حساس"
|
sensitive: "محتوى حساس"
|
||||||
add: "إضافة"
|
add: "إضافة"
|
||||||
|
reaction: "تفاعل"
|
||||||
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
|
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
|
||||||
|
attachCancel: "أزل المرفق"
|
||||||
enterFileName: "ادخل اسم الملف"
|
enterFileName: "ادخل اسم الملف"
|
||||||
mute: "اكتم"
|
mute: "اكتم"
|
||||||
unmute: "إلغاء الكتم"
|
unmute: "إلغاء الكتم"
|
||||||
block: "احجب"
|
block: "احجب"
|
||||||
unblock: "إلغاء الحجب"
|
unblock: "إلغاء الحجب"
|
||||||
|
blockConfirm: "أمتأكد من حجب هذا الحساب؟"
|
||||||
|
unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
|
||||||
selectList: "اختر قائمة"
|
selectList: "اختر قائمة"
|
||||||
|
editWidgetsExit: "تم"
|
||||||
customEmojis: "إيموجي مخصص"
|
customEmojis: "إيموجي مخصص"
|
||||||
addEmoji: "إضافة إيموجي"
|
addEmoji: "إضافة إيموجي"
|
||||||
|
cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة"
|
||||||
|
autoAcceptFollowed: "اقبل طلبات المتابعة تلقائيا من الحسابات المتابَعة"
|
||||||
addAcount: "إضافة حساب"
|
addAcount: "إضافة حساب"
|
||||||
|
loginFailed: "فشل الولوج"
|
||||||
showOnRemote: "رؤيته على مثيل الخادم البُعدي"
|
showOnRemote: "رؤيته على مثيل الخادم البُعدي"
|
||||||
general: "الرئيسية"
|
general: "الرئيسية"
|
||||||
wallpaper: "خلفية الشاشة"
|
wallpaper: "خلفية الشاشة"
|
||||||
@@ -88,6 +110,7 @@ setWallpaper: "استخدم خلفية الشاشة"
|
|||||||
removeWallpaper: "إزالة خلفية الشاشة"
|
removeWallpaper: "إزالة خلفية الشاشة"
|
||||||
searchWith: "البحث: {q}"
|
searchWith: "البحث: {q}"
|
||||||
youHaveNoLists: "لا تمتلك أية قائمة"
|
youHaveNoLists: "لا تمتلك أية قائمة"
|
||||||
|
followConfirm: "أتريد متابعة {name}؟"
|
||||||
proxyAccount: "حساب وكيل البروكسي"
|
proxyAccount: "حساب وكيل البروكسي"
|
||||||
host: "المضيف"
|
host: "المضيف"
|
||||||
selectUser: "حدّد مستخدمًا"
|
selectUser: "حدّد مستخدمًا"
|
||||||
@@ -96,6 +119,8 @@ annotation: "التعليقات"
|
|||||||
federation: "الفديرالية"
|
federation: "الفديرالية"
|
||||||
instances: "مثيل الخادم"
|
instances: "مثيل الخادم"
|
||||||
latestRequestSentAt: "آخر طلب أرسِل في"
|
latestRequestSentAt: "آخر طلب أرسِل في"
|
||||||
|
latestRequestReceivedAt: "آخر طلب تُلقي في"
|
||||||
|
storageUsage: "مساحة التخزين المستخدمة"
|
||||||
charts: "المنحنيات البيانية"
|
charts: "المنحنيات البيانية"
|
||||||
perHour: "في الساعة"
|
perHour: "في الساعة"
|
||||||
perDay: "في اليوم"
|
perDay: "في اليوم"
|
||||||
@@ -127,7 +152,6 @@ processing: "المعالجة جارية"
|
|||||||
preview: "معاينة"
|
preview: "معاينة"
|
||||||
default: "افتراضي"
|
default: "افتراضي"
|
||||||
noCustomEmojis: "ليس هناك إيموجيات"
|
noCustomEmojis: "ليس هناك إيموجيات"
|
||||||
customEmojisOfRemote: "الإيموجيات القادمة مِن مثيلات الخوادم الأخرى"
|
|
||||||
federating: "الفديرالية جارية"
|
federating: "الفديرالية جارية"
|
||||||
blocked: "محجوب"
|
blocked: "محجوب"
|
||||||
suspended: "مُعلّق"
|
suspended: "مُعلّق"
|
||||||
@@ -313,7 +337,6 @@ total: "المجموع"
|
|||||||
weekOverWeekChanges: "أسبوعيا"
|
weekOverWeekChanges: "أسبوعيا"
|
||||||
dayOverDayChanges: "يوميا"
|
dayOverDayChanges: "يوميا"
|
||||||
appearance: "المظهر"
|
appearance: "المظهر"
|
||||||
clinetSettings: "إعدادات التطبيق"
|
|
||||||
accountSettings: "إعدادات الحساب"
|
accountSettings: "إعدادات الحساب"
|
||||||
promotion: "ترقية"
|
promotion: "ترقية"
|
||||||
promote: "روِّج"
|
promote: "روِّج"
|
||||||
@@ -366,6 +389,7 @@ _theme:
|
|||||||
make: "إنشاء قالب"
|
make: "إنشاء قالب"
|
||||||
alpha: "الشفافية"
|
alpha: "الشفافية"
|
||||||
keys:
|
keys:
|
||||||
|
mention: "أشر الى"
|
||||||
messageBg: "خلفية الدردشة"
|
messageBg: "خلفية الدردشة"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "الملاحظات"
|
note: "الملاحظات"
|
||||||
@@ -508,7 +532,9 @@ _notification:
|
|||||||
youWereFollowed: "يتابعك"
|
youWereFollowed: "يتابعك"
|
||||||
_types:
|
_types:
|
||||||
follow: "المتابَعون"
|
follow: "المتابَعون"
|
||||||
|
mention: "أشر الى"
|
||||||
quote: "اقتبس"
|
quote: "اقتبس"
|
||||||
|
reaction: "تفاعل"
|
||||||
_deck:
|
_deck:
|
||||||
_columns:
|
_columns:
|
||||||
notifications: "الإشعارات"
|
notifications: "الإشعارات"
|
||||||
|
@@ -16,6 +16,9 @@ noNotes: "Keine Notizen"
|
|||||||
noNotifications: "Keine Benachrichtigungen"
|
noNotifications: "Keine Benachrichtigungen"
|
||||||
instance: "Instanz"
|
instance: "Instanz"
|
||||||
settings: "Einstellungen"
|
settings: "Einstellungen"
|
||||||
|
basicSettings: "Allgemeine Einstellungen"
|
||||||
|
otherSettings: "Andere Einstellungen"
|
||||||
|
openInWindow: "In neuem 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."
|
||||||
@@ -40,6 +43,7 @@ deleteAndEditConfirm: "Möchtest du diese Notiz wirklich löschen und bearbeiten
|
|||||||
addToList: "Zu Liste hinzufügen"
|
addToList: "Zu Liste hinzufügen"
|
||||||
sendMessage: "Nachricht senden"
|
sendMessage: "Nachricht senden"
|
||||||
copyUsername: "Benutzernamen kopieren"
|
copyUsername: "Benutzernamen kopieren"
|
||||||
|
searchUser: "Benutzersuche"
|
||||||
reply: "Antworten"
|
reply: "Antworten"
|
||||||
loadMore: "Mehr anzeigen"
|
loadMore: "Mehr anzeigen"
|
||||||
youGotNewFollower: "Du hast einen neuen Follower"
|
youGotNewFollower: "Du hast einen neuen Follower"
|
||||||
@@ -66,8 +70,11 @@ followers: "Gefolgt von"
|
|||||||
followsYou: "Folgt dir"
|
followsYou: "Folgt dir"
|
||||||
createList: "Liste erstellen"
|
createList: "Liste erstellen"
|
||||||
manageLists: "Listen verwalten"
|
manageLists: "Listen verwalten"
|
||||||
error: "Ein Problem ist aufgetreten"
|
error: "Fehler"
|
||||||
|
somethingHappened: "Ein Fehler ist aufgetreten"
|
||||||
retry: "Wiederholen"
|
retry: "Wiederholen"
|
||||||
|
pageLoadError: "Laden der Seite fehlgeschlagen."
|
||||||
|
pageLoadErrorDescription: "Dieser Fehler wird meist durch Netzwerkfehler oder den Browser-Cache verursacht. Versuche den Browser-Cache zu leeren und es nach kurzer Zeit noch einmal zu probieren."
|
||||||
enterListName: "Listennamen eingeben"
|
enterListName: "Listennamen eingeben"
|
||||||
privacy: "Privatsphäre"
|
privacy: "Privatsphäre"
|
||||||
makeFollowManuallyApprove: "Follow-Anfragen benötigen Bestätigung"
|
makeFollowManuallyApprove: "Follow-Anfragen benötigen Bestätigung"
|
||||||
@@ -106,6 +113,8 @@ unsuspendConfirm: "Möchtest du die Sperrung dieses Benutzers wirklich aufheben?
|
|||||||
selectList: "Wähle eine Liste aus"
|
selectList: "Wähle eine Liste aus"
|
||||||
selectAntenna: "Antenne auswählen"
|
selectAntenna: "Antenne auswählen"
|
||||||
selectWidget: "Widget auswählen"
|
selectWidget: "Widget auswählen"
|
||||||
|
editWidgets: "Widgets bearbeiten"
|
||||||
|
editWidgetsExit: "Fertig"
|
||||||
customEmojis: "Benutzerdefinierte Emojis"
|
customEmojis: "Benutzerdefinierte Emojis"
|
||||||
emoji: "Emoji"
|
emoji: "Emoji"
|
||||||
emojiName: "Emojiname"
|
emojiName: "Emojiname"
|
||||||
@@ -177,7 +186,6 @@ processing: "In Bearbeitung"
|
|||||||
preview: "Vorschau"
|
preview: "Vorschau"
|
||||||
default: "Standard"
|
default: "Standard"
|
||||||
noCustomEmojis: "Es existieren keine Emojis"
|
noCustomEmojis: "Es existieren keine Emojis"
|
||||||
customEmojisOfRemote: "Emojis von anderen Instanzen"
|
|
||||||
noJobs: "Es gibt keine Jobs"
|
noJobs: "Es gibt keine Jobs"
|
||||||
federating: "Föderiert"
|
federating: "Föderiert"
|
||||||
blocked: "Blockiert"
|
blocked: "Blockiert"
|
||||||
@@ -445,7 +453,7 @@ total: "Gesamt"
|
|||||||
weekOverWeekChanges: "Wöchentlich"
|
weekOverWeekChanges: "Wöchentlich"
|
||||||
dayOverDayChanges: "Täglich"
|
dayOverDayChanges: "Täglich"
|
||||||
appearance: "Aussehen"
|
appearance: "Aussehen"
|
||||||
clinetSettings: "Client-Einstellungen"
|
clientSettings: "Client-Einstellungen"
|
||||||
accountSettings: "Benutzerkonto-Einstellungen"
|
accountSettings: "Benutzerkonto-Einstellungen"
|
||||||
promotion: "Hervorgehoben"
|
promotion: "Hervorgehoben"
|
||||||
promote: "Hervorheben"
|
promote: "Hervorheben"
|
||||||
@@ -476,6 +484,8 @@ 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"
|
||||||
|
popout: "Pop-Up"
|
||||||
volume: "Lautstärke"
|
volume: "Lautstärke"
|
||||||
details: "Details"
|
details: "Details"
|
||||||
chooseEmoji: "Wähle ein Emoji"
|
chooseEmoji: "Wähle ein Emoji"
|
||||||
@@ -518,7 +528,6 @@ enableInfiniteScroll: "Automatisch mehr Notizen laden"
|
|||||||
visibility: "Sichtbarkeit"
|
visibility: "Sichtbarkeit"
|
||||||
poll: "Umfrage"
|
poll: "Umfrage"
|
||||||
useCw: "Inhalt verstecken"
|
useCw: "Inhalt verstecken"
|
||||||
fixedWidgetsPosition: "Widgetposition fixieren"
|
|
||||||
enablePlayer: "Video-Player öffnen"
|
enablePlayer: "Video-Player öffnen"
|
||||||
disablePlayer: "Video-Player schließen"
|
disablePlayer: "Video-Player schließen"
|
||||||
expandTweet: "Tweet ausklappen"
|
expandTweet: "Tweet ausklappen"
|
||||||
@@ -564,8 +573,26 @@ overview: "Übersicht"
|
|||||||
logs: "Logs"
|
logs: "Logs"
|
||||||
delayed: "Verzögert"
|
delayed: "Verzögert"
|
||||||
database: "Datenbank"
|
database: "Datenbank"
|
||||||
channel: "Kanal"
|
channel: "Kanäle"
|
||||||
create: "Erstellen"
|
create: "Erstellen"
|
||||||
|
notificationSetting: "Benachrichtigungseinstellungen"
|
||||||
|
notificationSettingDesc: "Wähle die Art der anzuzeigenden Benachrichtigung"
|
||||||
|
useGlobalSetting: "Globale Einstellung verwenden"
|
||||||
|
useGlobalSettingDesc: "Wenn dies eingeschaltet ist, werden die Benachrichtigungseinstellungen deines Benutzerkontos verwendet. Wenn dies ausgeschaltet ist, können individuelle Einstellungen vorgenommen werden."
|
||||||
|
other: "Andere"
|
||||||
|
regenerateLoginToken: "Login-Token regenerieren"
|
||||||
|
regenerateLoginTokenDescription: "Den bei Logins intern verwendeten Token regenerieren. Normalerweise wird dies nicht benötigt. Bei Regeneration werden alle Geräte ausgeloggt."
|
||||||
|
setMultipleBySeparatingWithSpace: "Trenne Elemente durch ein Leerzeichen um mehrere Einstellungen zu kofigurieren."
|
||||||
|
fileIdOrUrl: "Datei-ID oder URL"
|
||||||
|
chatOpenBehavior: "Verhalten des Chatfensters bei Öffnung"
|
||||||
|
sample: "Beispiel"
|
||||||
|
abuseReports: "Melden"
|
||||||
|
reportAbuse: "Melden"
|
||||||
|
reportAbuseOf: "{name} melden"
|
||||||
|
fillAbuseReportDescription: "Bitte gib Details für diese Meldung an. Falls es sich um eine spezielle Notiz handelt, bitte gib dessen URL an."
|
||||||
|
abuseReported: "Die Meldung wurde versendet. Vielen Dank."
|
||||||
|
send: "Senden"
|
||||||
|
abuseMarkAsResolved: "Meldung als gelöst markieren"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "Automatisch aktualisieren"
|
reload: "Automatisch aktualisieren"
|
||||||
dialog: "Warnungsfenster zeigen"
|
dialog: "Warnungsfenster zeigen"
|
||||||
@@ -576,13 +603,13 @@ _channel:
|
|||||||
setBanner: "Kanalbanner festlegen"
|
setBanner: "Kanalbanner festlegen"
|
||||||
removeBanner: "Kanalbanner entfernen"
|
removeBanner: "Kanalbanner entfernen"
|
||||||
featured: "Trends"
|
featured: "Trends"
|
||||||
owned: "Besitzer"
|
owned: "Besitzt"
|
||||||
following: "Folgt"
|
following: "Gefolgt"
|
||||||
usersCount: "{n} Teilnehmer"
|
usersCount: "{n} Teilnehmer"
|
||||||
notesCount: "{n} Notizen"
|
notesCount: "{n} Notizen"
|
||||||
_sidebar:
|
_sidebar:
|
||||||
full: "Voll"
|
full: "Voll"
|
||||||
icon: "Profilbild"
|
icon: "Symbol"
|
||||||
hide: "Ausblenden"
|
hide: "Ausblenden"
|
||||||
_wordMute:
|
_wordMute:
|
||||||
muteWords: "Wort stummschalten"
|
muteWords: "Wort stummschalten"
|
||||||
@@ -782,6 +809,7 @@ _widgets:
|
|||||||
photos: "Fotos"
|
photos: "Fotos"
|
||||||
digitalClock: "Digitaluhr"
|
digitalClock: "Digitaluhr"
|
||||||
federation: "Föderation"
|
federation: "Föderation"
|
||||||
|
postForm: "Neue Notiz anfertigen"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Ausblenden"
|
hide: "Ausblenden"
|
||||||
show: "Mehr anzeigen"
|
show: "Mehr anzeigen"
|
||||||
@@ -1238,14 +1266,17 @@ _notification:
|
|||||||
youWereInvitedToGroup: "Du wurdest in eine Gruppe eingeladen"
|
youWereInvitedToGroup: "Du wurdest in eine Gruppe eingeladen"
|
||||||
_types:
|
_types:
|
||||||
all: "Alle"
|
all: "Alle"
|
||||||
follow: "Folgt"
|
follow: "Neue Follower"
|
||||||
mention: "Erwähnung"
|
mention: "Erwähnungen"
|
||||||
reply: "Antworten"
|
reply: "Antworten"
|
||||||
renote: "Renote"
|
renote: "Renotes"
|
||||||
quote: "Zitieren"
|
quote: "Zitationen"
|
||||||
reaction: "Reaktionen"
|
reaction: "Reaktionen"
|
||||||
pollVote: "Umfragen"
|
pollVote: "Antworten auf Umfragen"
|
||||||
receiveFollowRequest: "Follow-Anfragen"
|
receiveFollowRequest: "Follow-Anfrage erhalten"
|
||||||
|
followRequestAccepted: "Follow-Anfrage akzeptiert"
|
||||||
|
groupInvited: "Gruppeneinladung erhalten"
|
||||||
|
app: "Benachrichtigungen von Apps"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
alwaysShowMainColumn: "Hauptspalte immer zeigen"
|
||||||
columnAlign: "Spalten ausrichten"
|
columnAlign: "Spalten ausrichten"
|
||||||
|
@@ -16,6 +16,9 @@ noNotes: "No notes"
|
|||||||
noNotifications: "No notifications"
|
noNotifications: "No notifications"
|
||||||
instance: "Instance"
|
instance: "Instance"
|
||||||
settings: "Settings"
|
settings: "Settings"
|
||||||
|
basicSettings: "Basic Settings"
|
||||||
|
otherSettings: "Other Settings"
|
||||||
|
openInWindow: "Open in new 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."
|
||||||
@@ -29,7 +32,7 @@ users: "Users"
|
|||||||
addUser: "Add a user"
|
addUser: "Add a user"
|
||||||
favorite: "Favorite"
|
favorite: "Favorite"
|
||||||
favorites: "Favorites"
|
favorites: "Favorites"
|
||||||
unfavorite: "Undo favorite"
|
unfavorite: "Unfavorite"
|
||||||
pin: "Pin to profile"
|
pin: "Pin to profile"
|
||||||
unpin: "Unpin from profile"
|
unpin: "Unpin from profile"
|
||||||
copyContent: "Copy contents"
|
copyContent: "Copy contents"
|
||||||
@@ -40,6 +43,7 @@ deleteAndEditConfirm: "Are you sure you want to delete this note and edit it? Yo
|
|||||||
addToList: "Add to list"
|
addToList: "Add to list"
|
||||||
sendMessage: "Send a message"
|
sendMessage: "Send a message"
|
||||||
copyUsername: "Copy username"
|
copyUsername: "Copy username"
|
||||||
|
searchUser: "User search"
|
||||||
reply: "Reply"
|
reply: "Reply"
|
||||||
loadMore: "Load more"
|
loadMore: "Load more"
|
||||||
youGotNewFollower: "Followed you"
|
youGotNewFollower: "Followed you"
|
||||||
@@ -66,8 +70,11 @@ followers: "Followers"
|
|||||||
followsYou: "Follows you"
|
followsYou: "Follows you"
|
||||||
createList: "Create list"
|
createList: "Create list"
|
||||||
manageLists: "Manage lists"
|
manageLists: "Manage lists"
|
||||||
error: "Something happened :("
|
error: "Error"
|
||||||
|
somethingHappened: "An error occurred"
|
||||||
retry: "Retry"
|
retry: "Retry"
|
||||||
|
pageLoadError: "Failed to load page"
|
||||||
|
pageLoadErrorDescription: "This is normally caused by network errors or the browser's cache. Try clearung the cache and then try again after waiting a little while."
|
||||||
enterListName: "List name"
|
enterListName: "List name"
|
||||||
privacy: "Privacy"
|
privacy: "Privacy"
|
||||||
makeFollowManuallyApprove: "Follow requests require approval"
|
makeFollowManuallyApprove: "Follow requests require approval"
|
||||||
@@ -106,6 +113,8 @@ unsuspendConfirm: "Are you sure you that want to unsuspend this account?"
|
|||||||
selectList: "Select a list"
|
selectList: "Select a list"
|
||||||
selectAntenna: "Select an Antenna"
|
selectAntenna: "Select an Antenna"
|
||||||
selectWidget: "Select a widget"
|
selectWidget: "Select a widget"
|
||||||
|
editWidgets: "Edit widgets"
|
||||||
|
editWidgetsExit: "Done"
|
||||||
customEmojis: "Custom Emoji"
|
customEmojis: "Custom Emoji"
|
||||||
emoji: "Emoji"
|
emoji: "Emoji"
|
||||||
emojiName: "Emoji name"
|
emojiName: "Emoji name"
|
||||||
@@ -177,7 +186,6 @@ processing: "Processing"
|
|||||||
preview: "Preview"
|
preview: "Preview"
|
||||||
default: "Default"
|
default: "Default"
|
||||||
noCustomEmojis: "There are no emojis"
|
noCustomEmojis: "There are no emojis"
|
||||||
customEmojisOfRemote: "Emojis from other instances"
|
|
||||||
noJobs: "There are no jobs"
|
noJobs: "There are no jobs"
|
||||||
federating: "Federating"
|
federating: "Federating"
|
||||||
blocked: "Blocked"
|
blocked: "Blocked"
|
||||||
@@ -445,7 +453,7 @@ total: "Total"
|
|||||||
weekOverWeekChanges: "Weekly"
|
weekOverWeekChanges: "Weekly"
|
||||||
dayOverDayChanges: "Daily"
|
dayOverDayChanges: "Daily"
|
||||||
appearance: "Appearance"
|
appearance: "Appearance"
|
||||||
clinetSettings: "Client Settings"
|
clientSettings: "Client settings"
|
||||||
accountSettings: "Account Settings"
|
accountSettings: "Account Settings"
|
||||||
promotion: "Promoted"
|
promotion: "Promoted"
|
||||||
promote: "Promote"
|
promote: "Promote"
|
||||||
@@ -476,6 +484,8 @@ newNoteRecived: "You've got a new note"
|
|||||||
sounds: "Sounds"
|
sounds: "Sounds"
|
||||||
listen: "Listen"
|
listen: "Listen"
|
||||||
none: "None"
|
none: "None"
|
||||||
|
showInPage: "Show in Pages"
|
||||||
|
popout: "Pop-out"
|
||||||
volume: "Volume"
|
volume: "Volume"
|
||||||
details: "Details"
|
details: "Details"
|
||||||
chooseEmoji: "Choose an emoji"
|
chooseEmoji: "Choose an emoji"
|
||||||
@@ -518,7 +528,6 @@ enableInfiniteScroll: "Enable infinite scrolling"
|
|||||||
visibility: "Visiblility"
|
visibility: "Visiblility"
|
||||||
poll: "Poll"
|
poll: "Poll"
|
||||||
useCw: "Hide content"
|
useCw: "Hide content"
|
||||||
fixedWidgetsPosition: "Make widget position fixed"
|
|
||||||
enablePlayer: "Open video player"
|
enablePlayer: "Open video player"
|
||||||
disablePlayer: "Close video player"
|
disablePlayer: "Close video player"
|
||||||
expandTweet: "Expand tweet"
|
expandTweet: "Expand tweet"
|
||||||
@@ -564,8 +573,26 @@ overview: "Overview"
|
|||||||
logs: "Logs"
|
logs: "Logs"
|
||||||
delayed: "Delayed"
|
delayed: "Delayed"
|
||||||
database: "Database"
|
database: "Database"
|
||||||
channel: "Channel"
|
channel: "Channels"
|
||||||
create: "Create"
|
create: "Create"
|
||||||
|
notificationSetting: "Notification settings"
|
||||||
|
notificationSettingDesc: "Select the type of notification to display"
|
||||||
|
useGlobalSetting: "Use global setting"
|
||||||
|
useGlobalSettingDesc: "If turned on, your account's notification settings will be used. If turned off, individual configurations can be made."
|
||||||
|
other: "Other"
|
||||||
|
regenerateLoginToken: "Regenerate login token"
|
||||||
|
regenerateLoginTokenDescription: "Regenerate the token used internally during login. Normally this action is not necessary. If regenerated, all devices will be logged out."
|
||||||
|
setMultipleBySeparatingWithSpace: "You can set multiple by separating them with spaces."
|
||||||
|
fileIdOrUrl: "File-ID or URL"
|
||||||
|
chatOpenBehavior: "Behavior of the chat window when opened"
|
||||||
|
sample: "Sample"
|
||||||
|
abuseReports: "Reports"
|
||||||
|
reportAbuse: "Report"
|
||||||
|
reportAbuseOf: "Report {name}"
|
||||||
|
fillAbuseReportDescription: "Please fill in the report details. If it is about a specific note, please include its URL."
|
||||||
|
abuseReported: "Your report has been sent. Thank you very much."
|
||||||
|
send: "Send"
|
||||||
|
abuseMarkAsResolved: "Mark report as resolved"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "Automatically reload"
|
reload: "Automatically reload"
|
||||||
dialog: "Show warning dialog"
|
dialog: "Show warning dialog"
|
||||||
@@ -576,8 +603,8 @@ _channel:
|
|||||||
setBanner: "Set banner"
|
setBanner: "Set banner"
|
||||||
removeBanner: "Remove banner"
|
removeBanner: "Remove banner"
|
||||||
featured: "Trending"
|
featured: "Trending"
|
||||||
owned: "Owner"
|
owned: "Owned"
|
||||||
following: "Following"
|
following: "Followed"
|
||||||
usersCount: "{n} Participants"
|
usersCount: "{n} Participants"
|
||||||
notesCount: "{n} Notes"
|
notesCount: "{n} Notes"
|
||||||
_sidebar:
|
_sidebar:
|
||||||
@@ -782,6 +809,7 @@ _widgets:
|
|||||||
photos: "Photos"
|
photos: "Photos"
|
||||||
digitalClock: "Digital clock"
|
digitalClock: "Digital clock"
|
||||||
federation: "Federation"
|
federation: "Federation"
|
||||||
|
postForm: "Compose a note"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Hide"
|
hide: "Hide"
|
||||||
show: "Load more"
|
show: "Load more"
|
||||||
@@ -1238,14 +1266,17 @@ _notification:
|
|||||||
youWereInvitedToGroup: "Invited to group"
|
youWereInvitedToGroup: "Invited to group"
|
||||||
_types:
|
_types:
|
||||||
all: "All"
|
all: "All"
|
||||||
follow: "Following"
|
follow: "Follows"
|
||||||
mention: "Mention"
|
mention: "Mentions"
|
||||||
reply: "Replies"
|
reply: "Replies"
|
||||||
renote: "Renote"
|
renote: "Renotes"
|
||||||
quote: "Quote"
|
quote: "Quotes"
|
||||||
reaction: "Reaction"
|
reaction: "Reactions"
|
||||||
pollVote: "Polls"
|
pollVote: "Votes on polls"
|
||||||
receiveFollowRequest: "Follow requests"
|
receiveFollowRequest: "Follow request received"
|
||||||
|
followRequestAccepted: "Follow request accepted"
|
||||||
|
groupInvited: "Invited to groups"
|
||||||
|
app: "Notifications from apps"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Always show main column"
|
alwaysShowMainColumn: "Always show main column"
|
||||||
columnAlign: "Align columns"
|
columnAlign: "Align columns"
|
||||||
|
@@ -66,7 +66,6 @@ followers: "Seguidores"
|
|||||||
followsYou: "Te sigue"
|
followsYou: "Te sigue"
|
||||||
createList: "Crear lista"
|
createList: "Crear lista"
|
||||||
manageLists: "Administrar listas"
|
manageLists: "Administrar listas"
|
||||||
error: "Ocurrió un problema"
|
|
||||||
retry: "Reintentar"
|
retry: "Reintentar"
|
||||||
enterListName: "Ingrese nombre de lista"
|
enterListName: "Ingrese nombre de lista"
|
||||||
privacy: "Privacidad"
|
privacy: "Privacidad"
|
||||||
@@ -177,7 +176,6 @@ processing: "Procesando"
|
|||||||
preview: "Vista previa"
|
preview: "Vista previa"
|
||||||
default: "Predeterminado"
|
default: "Predeterminado"
|
||||||
noCustomEmojis: "No hay emojis personalizados"
|
noCustomEmojis: "No hay emojis personalizados"
|
||||||
customEmojisOfRemote: "Emojis remotos"
|
|
||||||
noJobs: "No hay trabajos"
|
noJobs: "No hay trabajos"
|
||||||
federating: "Federando"
|
federating: "Federando"
|
||||||
blocked: "Bloqueando"
|
blocked: "Bloqueando"
|
||||||
@@ -445,7 +443,6 @@ total: "Total"
|
|||||||
weekOverWeekChanges: "Dif semanal"
|
weekOverWeekChanges: "Dif semanal"
|
||||||
dayOverDayChanges: "Dif diaria"
|
dayOverDayChanges: "Dif diaria"
|
||||||
appearance: "Apariencia"
|
appearance: "Apariencia"
|
||||||
clinetSettings: "Ajustes del cliente"
|
|
||||||
accountSettings: "Ajustes de cuenta"
|
accountSettings: "Ajustes de cuenta"
|
||||||
promotion: "Promovido"
|
promotion: "Promovido"
|
||||||
promote: "Promover"
|
promote: "Promover"
|
||||||
@@ -518,7 +515,6 @@ enableInfiniteScroll: "Activar scroll infinito"
|
|||||||
visibility: "Visibilidad"
|
visibility: "Visibilidad"
|
||||||
poll: "Encuesta"
|
poll: "Encuesta"
|
||||||
useCw: "Esconder contenidos"
|
useCw: "Esconder contenidos"
|
||||||
fixedWidgetsPosition: "Fijar la posición de los widgets"
|
|
||||||
enablePlayer: "Abrir reproductor"
|
enablePlayer: "Abrir reproductor"
|
||||||
disablePlayer: "Cerrar reproductor"
|
disablePlayer: "Cerrar reproductor"
|
||||||
expandTweet: "Expandir tweet"
|
expandTweet: "Expandir tweet"
|
||||||
@@ -566,6 +562,10 @@ delayed: "atrasado"
|
|||||||
database: "Base de datos"
|
database: "Base de datos"
|
||||||
channel: "Canal"
|
channel: "Canal"
|
||||||
create: "Crear"
|
create: "Crear"
|
||||||
|
notificationSetting: "Ajustes de Notificaciones"
|
||||||
|
notificationSettingDesc: "Por favor elija el tipo de notificación a mostrar"
|
||||||
|
useGlobalSetting: "Usar ajustes globales"
|
||||||
|
useGlobalSettingDesc: "Al activarse, se usará la configuración de notificaciones de la cuenta, al desactivarse se pueden hacer configuraciones particulares."
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "Recargar automáticamente"
|
reload: "Recargar automáticamente"
|
||||||
dialog: "Mostrar diálogo de advertencia"
|
dialog: "Mostrar diálogo de advertencia"
|
||||||
@@ -782,6 +782,7 @@ _widgets:
|
|||||||
photos: "Fotos"
|
photos: "Fotos"
|
||||||
digitalClock: "Reloj digital"
|
digitalClock: "Reloj digital"
|
||||||
federation: "Federación"
|
federation: "Federación"
|
||||||
|
postForm: "Formulario"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Ocultar"
|
hide: "Ocultar"
|
||||||
show: "Ver más"
|
show: "Ver más"
|
||||||
@@ -1244,8 +1245,11 @@ _notification:
|
|||||||
renote: "Renotar"
|
renote: "Renotar"
|
||||||
quote: "Citar"
|
quote: "Citar"
|
||||||
reaction: "Reacción"
|
reaction: "Reacción"
|
||||||
pollVote: "Encuestas"
|
pollVote: "Votado en la encuesta"
|
||||||
receiveFollowRequest: "Solicitudes de seguimiento"
|
receiveFollowRequest: "Recibió una solicitud de seguimiento"
|
||||||
|
followRequestAccepted: "El seguimiento fue aceptado"
|
||||||
|
groupInvited: "Invitado al grupo"
|
||||||
|
app: "Notificaciones desde aplicaciones"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Siempre mostrar la columna principal"
|
alwaysShowMainColumn: "Siempre mostrar la columna principal"
|
||||||
columnAlign: "Alinear columnas"
|
columnAlign: "Alinear columnas"
|
||||||
|
@@ -16,6 +16,9 @@ noNotes: "Aucune note"
|
|||||||
noNotifications: "Aucune notification"
|
noNotifications: "Aucune notification"
|
||||||
instance: "Instance"
|
instance: "Instance"
|
||||||
settings: "Paramètres"
|
settings: "Paramètres"
|
||||||
|
basicSettings: "Paramètres basiques"
|
||||||
|
otherSettings: "Autres paramètres"
|
||||||
|
openInWindow: "Ouvrir dans une nouvelle fenêtre"
|
||||||
profile: "Profil"
|
profile: "Profil"
|
||||||
timeline: "Fil"
|
timeline: "Fil"
|
||||||
noAccountDescription: "L’utilisateur·rice n’a pas encore renseigné de biographie de présentation sur son profil."
|
noAccountDescription: "L’utilisateur·rice n’a pas encore renseigné de biographie de présentation sur son profil."
|
||||||
@@ -40,6 +43,7 @@ deleteAndEditConfirm: "Êtes-vous sûr·e de vouloir supprimer cette note et la
|
|||||||
addToList: "Ajouter à une liste"
|
addToList: "Ajouter à une liste"
|
||||||
sendMessage: "Envoyer un message"
|
sendMessage: "Envoyer un message"
|
||||||
copyUsername: "Copier le nom d’utilisateur·rice"
|
copyUsername: "Copier le nom d’utilisateur·rice"
|
||||||
|
searchUser: "Chercher un·e utilisateur·rice"
|
||||||
reply: "Répondre"
|
reply: "Répondre"
|
||||||
loadMore: "Afficher plus …"
|
loadMore: "Afficher plus …"
|
||||||
youGotNewFollower: "Vous suit"
|
youGotNewFollower: "Vous suit"
|
||||||
@@ -66,8 +70,10 @@ followers: "Abonné·e·s"
|
|||||||
followsYou: "Vous suit"
|
followsYou: "Vous suit"
|
||||||
createList: "Créer une liste"
|
createList: "Créer une liste"
|
||||||
manageLists: "Gérer les listes"
|
manageLists: "Gérer les listes"
|
||||||
error: "Une erreur est survenue"
|
error: "Erreur"
|
||||||
|
somethingHappened: "Une erreur est survenue"
|
||||||
retry: "Réessayer"
|
retry: "Réessayer"
|
||||||
|
pageLoadError: "Le chargement de la page a échoué"
|
||||||
enterListName: "Nom de la liste"
|
enterListName: "Nom de la liste"
|
||||||
privacy: "Confidentialité"
|
privacy: "Confidentialité"
|
||||||
makeFollowManuallyApprove: "Accepter manuellement les demandes d’abonnement"
|
makeFollowManuallyApprove: "Accepter manuellement les demandes d’abonnement"
|
||||||
@@ -106,6 +112,8 @@ unsuspendConfirm: "Êtes-vous sûr·e de vouloir annuler la suspension de ce com
|
|||||||
selectList: "Sélectionner une liste"
|
selectList: "Sélectionner une liste"
|
||||||
selectAntenna: "Sélectionner une antenne"
|
selectAntenna: "Sélectionner une antenne"
|
||||||
selectWidget: "Sélectionner un widget"
|
selectWidget: "Sélectionner un widget"
|
||||||
|
editWidgets: "Modifier les widgets"
|
||||||
|
editWidgetsExit: "Fait"
|
||||||
customEmojis: "Émojis personnalisés"
|
customEmojis: "Émojis personnalisés"
|
||||||
emoji: "Émoji"
|
emoji: "Émoji"
|
||||||
emojiName: "Nom de l’émoji"
|
emojiName: "Nom de l’émoji"
|
||||||
@@ -177,7 +185,6 @@ processing: "Traitement en cours"
|
|||||||
preview: "Prévisualisation"
|
preview: "Prévisualisation"
|
||||||
default: "Par défaut"
|
default: "Par défaut"
|
||||||
noCustomEmojis: "Il n'y a pas d’émoji"
|
noCustomEmojis: "Il n'y a pas d’émoji"
|
||||||
customEmojisOfRemote: "Émojis provenant des autres instances"
|
|
||||||
noJobs: "Il n’y a aucune tâche planifiée"
|
noJobs: "Il n’y a aucune tâche planifiée"
|
||||||
federating: "En cours de fédération"
|
federating: "En cours de fédération"
|
||||||
blocked: "Bloqué·e"
|
blocked: "Bloqué·e"
|
||||||
@@ -264,6 +271,7 @@ rename: "Renommer"
|
|||||||
avatar: "Avatar"
|
avatar: "Avatar"
|
||||||
banner: "Bannière"
|
banner: "Bannière"
|
||||||
nsfw: "Contenu sensible"
|
nsfw: "Contenu sensible"
|
||||||
|
whenServerDisconnected: "Lorsque la connexion au serveur est perdue"
|
||||||
disconnectedFromServer: "Déconnecté·e du serveur"
|
disconnectedFromServer: "Déconnecté·e du serveur"
|
||||||
reload: "Rafraîchir"
|
reload: "Rafraîchir"
|
||||||
doNothing: "Ignorer"
|
doNothing: "Ignorer"
|
||||||
@@ -444,7 +452,7 @@ total: "Total"
|
|||||||
weekOverWeekChanges: "Diff hebdo"
|
weekOverWeekChanges: "Diff hebdo"
|
||||||
dayOverDayChanges: "Diff quotidien"
|
dayOverDayChanges: "Diff quotidien"
|
||||||
appearance: "Aspect"
|
appearance: "Aspect"
|
||||||
clinetSettings: "Paramètres du client"
|
clientSettings: "Paramètres du client"
|
||||||
accountSettings: "Paramètres du compte"
|
accountSettings: "Paramètres du compte"
|
||||||
promotion: "Promu"
|
promotion: "Promu"
|
||||||
promote: "Promouvoir"
|
promote: "Promouvoir"
|
||||||
@@ -474,6 +482,7 @@ newNoteRecived: "Vous avez une nouvelle note"
|
|||||||
sounds: "Sons"
|
sounds: "Sons"
|
||||||
listen: "Écouter"
|
listen: "Écouter"
|
||||||
none: "Rien"
|
none: "Rien"
|
||||||
|
popout: "Fenêtre contextuelle"
|
||||||
volume: "Volume"
|
volume: "Volume"
|
||||||
details: "Détails"
|
details: "Détails"
|
||||||
chooseEmoji: "Choisissez un émoji"
|
chooseEmoji: "Choisissez un émoji"
|
||||||
@@ -516,7 +525,6 @@ enableInfiniteScroll: "Activer le défilement infini"
|
|||||||
visibility: "Visibilité"
|
visibility: "Visibilité"
|
||||||
poll: "Sondage"
|
poll: "Sondage"
|
||||||
useCw: "Masquer le contenu"
|
useCw: "Masquer le contenu"
|
||||||
fixedWidgetsPosition: "Rendre la position du widget fixe"
|
|
||||||
enablePlayer: "Activer le lecteur vidéo"
|
enablePlayer: "Activer le lecteur vidéo"
|
||||||
disablePlayer: "Désactiver le lecteur vidéo"
|
disablePlayer: "Désactiver le lecteur vidéo"
|
||||||
expandTweet: "Étendre le tweet"
|
expandTweet: "Étendre le tweet"
|
||||||
@@ -538,6 +546,7 @@ tokenRequested: "Autoriser l'accès au compte"
|
|||||||
pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations définies ici."
|
pluginTokenRequestedDescription: "Ce plugin pourra utiliser les autorisations définies ici."
|
||||||
notificationType: "Type de notifications"
|
notificationType: "Type de notifications"
|
||||||
edit: "Editer"
|
edit: "Editer"
|
||||||
|
useStarForReactionFallback: "Utiliser ★ comme alternative si l’émoji de réaction est inconnu"
|
||||||
emailConfig: "Configuration du serveur email"
|
emailConfig: "Configuration du serveur email"
|
||||||
enableEmail: "Activer la distribution de courriel"
|
enableEmail: "Activer la distribution de courriel"
|
||||||
emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation de votre mot de passe en cas d’oubli."
|
emailConfigInfo: "Utilisé pour confirmer votre adresse de courriel et la réinitialisation de votre mot de passe en cas d’oubli."
|
||||||
@@ -549,16 +558,45 @@ smtpUser: "Nom d’utilisateur·rice"
|
|||||||
smtpPass: "Mot de passe"
|
smtpPass: "Mot de passe"
|
||||||
emptyToDisableSmtpAuth: "Laisser le nom d’utilisateur et le mot de passe vides pour désactiver la vérification SMTP"
|
emptyToDisableSmtpAuth: "Laisser le nom d’utilisateur et le mot de passe vides pour désactiver la vérification SMTP"
|
||||||
smtpSecure: "Utiliser SSL/TLS implicitement dans les connexions SMTP"
|
smtpSecure: "Utiliser SSL/TLS implicitement dans les connexions SMTP"
|
||||||
|
smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé"
|
||||||
|
testEmail: "Tester la distribution de courriel"
|
||||||
wordMute: "Filtre de mots"
|
wordMute: "Filtre de mots"
|
||||||
userSaysSomething: "{name} a dit quelque chose"
|
userSaysSomething: "{name} a dit quelque chose"
|
||||||
makeActive: "Activer"
|
makeActive: "Activer"
|
||||||
display: "Affichage"
|
display: "Affichage"
|
||||||
|
copy: "Copier"
|
||||||
|
metrics: "Métriques"
|
||||||
|
overview: "Aperçu"
|
||||||
|
logs: "Journaux"
|
||||||
|
delayed: "en retard"
|
||||||
|
database: "Base de données"
|
||||||
|
channel: "Canaux"
|
||||||
|
create: "Créer"
|
||||||
|
notificationSetting: "Paramètres des notifications "
|
||||||
|
notificationSettingDesc: "Sélectionnez le type de notification à afficher"
|
||||||
|
useGlobalSetting: "Utiliser paramètre général"
|
||||||
|
other: "Autre"
|
||||||
|
regenerateLoginToken: "Régénérer le jeton de connexion"
|
||||||
|
setMultipleBySeparatingWithSpace: "Vous pouvez définir plus d’un, séparés par des espaces."
|
||||||
|
fileIdOrUrl: "ID du fichier ou URL"
|
||||||
|
chatOpenBehavior: "Comportement de la fenêtre de discussion lors de son ouverture"
|
||||||
|
_serverDisconnectedBehavior:
|
||||||
|
reload: "Rechargement automatique"
|
||||||
_channel:
|
_channel:
|
||||||
|
create: "Créer un canal"
|
||||||
|
edit: "Éditer le canal"
|
||||||
|
removeBanner: "Supprimer la bannière"
|
||||||
featured: "Tendances"
|
featured: "Tendances"
|
||||||
|
usersCount: "{n} Participants"
|
||||||
|
notesCount: "{n} Notes"
|
||||||
_sidebar:
|
_sidebar:
|
||||||
full: "Complet"
|
full: "Complet"
|
||||||
icon: "Avatar"
|
icon: "Avatar"
|
||||||
hide: "Masquer"
|
hide: "Masquer"
|
||||||
|
_wordMute:
|
||||||
|
muteWords: "Mot à mettre en sourdine"
|
||||||
|
muteWordsDescription: "Séparer avec des espaces pour la condition AND. Séparer avec un saut de ligne pour une condition OR."
|
||||||
|
mutedNotes: "Notes mises en sourdine"
|
||||||
_theme:
|
_theme:
|
||||||
explore: "Explorer les thèmes"
|
explore: "Explorer les thèmes"
|
||||||
install: "Installer un thème"
|
install: "Installer un thème"
|
||||||
@@ -569,6 +607,8 @@ _theme:
|
|||||||
invalid: "Le format du thème n'est pas valide"
|
invalid: "Le format du thème n'est pas valide"
|
||||||
make: "Créer un thème"
|
make: "Créer un thème"
|
||||||
base: "Base"
|
base: "Base"
|
||||||
|
addConstant: "Ajouter une constante"
|
||||||
|
constant: "Constante"
|
||||||
defaultValue: "Valeur par défaut"
|
defaultValue: "Valeur par défaut"
|
||||||
color: "Couleur"
|
color: "Couleur"
|
||||||
key: "Clé "
|
key: "Clé "
|
||||||
@@ -594,6 +634,7 @@ _theme:
|
|||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
divider: "Séparateur"
|
divider: "Séparateur"
|
||||||
infoWarnFg: "Texte d’avertissement"
|
infoWarnFg: "Texte d’avertissement"
|
||||||
|
cwBg: "Arrière-plan du CW"
|
||||||
badge: "Badge"
|
badge: "Badge"
|
||||||
messageBg: "Arrière plan de la discussion"
|
messageBg: "Arrière plan de la discussion"
|
||||||
_sfx:
|
_sfx:
|
||||||
@@ -678,6 +719,8 @@ _permissions:
|
|||||||
"write:page-likes": "Mettre à jour les favoris sur les Pages"
|
"write:page-likes": "Mettre à jour les favoris sur les Pages"
|
||||||
"read:user-groups": "Voir les groupes d'utilisateur·rice·s"
|
"read:user-groups": "Voir les groupes d'utilisateur·rice·s"
|
||||||
"write:user-groups": "Éditer les groupes des utilisateur·rice·s"
|
"write:user-groups": "Éditer les groupes des utilisateur·rice·s"
|
||||||
|
"read:channels": "Lire les canaux"
|
||||||
|
"write:channels": "Modifier les canaux"
|
||||||
_auth:
|
_auth:
|
||||||
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
|
shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
|
||||||
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre compte?"
|
shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre compte?"
|
||||||
@@ -711,6 +754,7 @@ _widgets:
|
|||||||
photos: "Photos"
|
photos: "Photos"
|
||||||
digitalClock: "Horloge numérique"
|
digitalClock: "Horloge numérique"
|
||||||
federation: "Fédération"
|
federation: "Fédération"
|
||||||
|
postForm: "Formulaire à publier"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "Masquer"
|
hide: "Masquer"
|
||||||
show: "Afficher plus …"
|
show: "Afficher plus …"
|
||||||
@@ -752,6 +796,7 @@ _visibility:
|
|||||||
_postForm:
|
_postForm:
|
||||||
replyPlaceholder: "Répondre à cette note ..."
|
replyPlaceholder: "Répondre à cette note ..."
|
||||||
quotePlaceholder: "Citez cette note ..."
|
quotePlaceholder: "Citez cette note ..."
|
||||||
|
channelPlaceholder: "Publier vers le canal"
|
||||||
_placeholders:
|
_placeholders:
|
||||||
a: "Quoi de neuf ?"
|
a: "Quoi de neuf ?"
|
||||||
b: "Quoi de neuf ?"
|
b: "Quoi de neuf ?"
|
||||||
@@ -1165,11 +1210,15 @@ _notification:
|
|||||||
yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté"
|
yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté"
|
||||||
youWereInvitedToGroup: "Invité au groupe"
|
youWereInvitedToGroup: "Invité au groupe"
|
||||||
_types:
|
_types:
|
||||||
|
all: "Toutes"
|
||||||
follow: "Abonnements"
|
follow: "Abonnements"
|
||||||
mention: "Mentionner"
|
mention: "Mentionner"
|
||||||
|
reply: "Réponses"
|
||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
quote: "Citer"
|
quote: "Citer"
|
||||||
reaction: "Réactions"
|
reaction: "Réactions"
|
||||||
|
groupInvited: "Invité aux groupes"
|
||||||
|
app: "Notifications provenant des apps"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "Toujours afficher la colonne principale"
|
alwaysShowMainColumn: "Toujours afficher la colonne principale"
|
||||||
columnAlign: "Aligner les colonnes"
|
columnAlign: "Aligner les colonnes"
|
||||||
|
@@ -585,6 +585,14 @@ regenerateLoginTokenDescription: "ログインに使用される内部トーク
|
|||||||
setMultipleBySeparatingWithSpace: "スペースで区切って複数設定できます。"
|
setMultipleBySeparatingWithSpace: "スペースで区切って複数設定できます。"
|
||||||
fileIdOrUrl: "ファイルIDまたはURL"
|
fileIdOrUrl: "ファイルIDまたはURL"
|
||||||
chatOpenBehavior: "チャットを開くときの動作"
|
chatOpenBehavior: "チャットを開くときの動作"
|
||||||
|
sample: "サンプル"
|
||||||
|
abuseReports: "通報"
|
||||||
|
reportAbuse: "通報"
|
||||||
|
reportAbuseOf: "{name}を通報する"
|
||||||
|
fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のノートがある場合はそのURLも記入してください。"
|
||||||
|
abuseReported: "内容が送信されました。ご報告ありがとうございました。"
|
||||||
|
send: "送信"
|
||||||
|
abuseMarkAsResolved: "対応済みにする"
|
||||||
|
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "自動でリロード"
|
reload: "自動でリロード"
|
||||||
|
@@ -65,7 +65,6 @@ followers: "フォロワー"
|
|||||||
followsYou: "フォローされとるで"
|
followsYou: "フォローされとるで"
|
||||||
createList: "リスト作る"
|
createList: "リスト作る"
|
||||||
manageLists: "リストの管理"
|
manageLists: "リストの管理"
|
||||||
error: "問題が発生してん"
|
|
||||||
retry: "もっぺんやってみる"
|
retry: "もっぺんやってみる"
|
||||||
enterListName: "リスト名を入れてや"
|
enterListName: "リスト名を入れてや"
|
||||||
privacy: "プライバシーってなんや?オカンの年齢か?"
|
privacy: "プライバシーってなんや?オカンの年齢か?"
|
||||||
@@ -173,7 +172,6 @@ processing: "処理しとる"
|
|||||||
preview: "プレビュー"
|
preview: "プレビュー"
|
||||||
default: "デフォルト"
|
default: "デフォルト"
|
||||||
noCustomEmojis: "絵文字はあらへん"
|
noCustomEmojis: "絵文字はあらへん"
|
||||||
customEmojisOfRemote: "リモートの絵文字"
|
|
||||||
noJobs: "ジョブはあらへん"
|
noJobs: "ジョブはあらへん"
|
||||||
federating: "連合しとる"
|
federating: "連合しとる"
|
||||||
blocked: "ブロックしとる"
|
blocked: "ブロックしとる"
|
||||||
|
@@ -66,7 +66,6 @@ followers: "팔로워"
|
|||||||
followsYou: "당신을 팔로우합니다"
|
followsYou: "당신을 팔로우합니다"
|
||||||
createList: "리스트 만들기"
|
createList: "리스트 만들기"
|
||||||
manageLists: "리스트 관리"
|
manageLists: "리스트 관리"
|
||||||
error: "오류가 발생했습니다"
|
|
||||||
retry: "다시 시도"
|
retry: "다시 시도"
|
||||||
enterListName: "리스트 이름을 입력"
|
enterListName: "리스트 이름을 입력"
|
||||||
privacy: "프라이버시"
|
privacy: "프라이버시"
|
||||||
@@ -177,7 +176,6 @@ processing: "처리중"
|
|||||||
preview: "미리보기"
|
preview: "미리보기"
|
||||||
default: "기본값"
|
default: "기본값"
|
||||||
noCustomEmojis: "이모지가 없습니다"
|
noCustomEmojis: "이모지가 없습니다"
|
||||||
customEmojisOfRemote: "다른 인스턴스들의 이모지"
|
|
||||||
noJobs: "작업이 없습니다"
|
noJobs: "작업이 없습니다"
|
||||||
federating: "연합 중"
|
federating: "연합 중"
|
||||||
blocked: "차단됨"
|
blocked: "차단됨"
|
||||||
@@ -443,7 +441,6 @@ remote: "리모트"
|
|||||||
total: "합계"
|
total: "합계"
|
||||||
weekOverWeekChanges: "지난주보다"
|
weekOverWeekChanges: "지난주보다"
|
||||||
dayOverDayChanges: "어제보다"
|
dayOverDayChanges: "어제보다"
|
||||||
clinetSettings: "클라이언트 설정"
|
|
||||||
accountSettings: "계정 설정"
|
accountSettings: "계정 설정"
|
||||||
promotion: "프로모션"
|
promotion: "프로모션"
|
||||||
promote: "프로모션하기"
|
promote: "프로모션하기"
|
||||||
@@ -515,7 +512,6 @@ enableInfiniteScroll: "자동으로 좀 더 보기"
|
|||||||
visibility: "공개 범위"
|
visibility: "공개 범위"
|
||||||
poll: "투표"
|
poll: "투표"
|
||||||
useCw: "내용 숨기기"
|
useCw: "내용 숨기기"
|
||||||
fixedWidgetsPosition: "위젯의 위치 고정"
|
|
||||||
enablePlayer: "플레이어 열기"
|
enablePlayer: "플레이어 열기"
|
||||||
disablePlayer: "플레이어 닫기"
|
disablePlayer: "플레이어 닫기"
|
||||||
expandTweet: "트윗 확장하기"
|
expandTweet: "트윗 확장하기"
|
||||||
@@ -708,6 +704,7 @@ _widgets:
|
|||||||
photos: "사진"
|
photos: "사진"
|
||||||
digitalClock: "디지털 시계"
|
digitalClock: "디지털 시계"
|
||||||
federation: "연합"
|
federation: "연합"
|
||||||
|
postForm: "글 입력란"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "숨기기"
|
hide: "숨기기"
|
||||||
show: "더 보기"
|
show: "더 보기"
|
||||||
@@ -1165,7 +1162,6 @@ _notification:
|
|||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
quote: "인용"
|
quote: "인용"
|
||||||
reaction: "리액션"
|
reaction: "리액션"
|
||||||
receiveFollowRequest: "팔로우 요청"
|
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "메인 칼럼 항상 표시"
|
alwaysShowMainColumn: "메인 칼럼 항상 표시"
|
||||||
columnAlign: "칼럼 정렬"
|
columnAlign: "칼럼 정렬"
|
||||||
|
@@ -1,2 +1,21 @@
|
|||||||
---
|
---
|
||||||
_lang_: "język polski"
|
_lang_: "język polski"
|
||||||
|
search: "Szukaj"
|
||||||
|
notifications: "Powiadomienia"
|
||||||
|
username: "Nazwa użytkownika"
|
||||||
|
password: "Hasło"
|
||||||
|
ok: "OK"
|
||||||
|
gotIt: "Rozumiem!"
|
||||||
|
cancel: "Anuluj"
|
||||||
|
enterUsername: "Wprowadź nazwę użytkownika"
|
||||||
|
smtpUser: "Nazwa użytkownika"
|
||||||
|
smtpPass: "Hasło"
|
||||||
|
_sfx:
|
||||||
|
notification: "Powiadomienia"
|
||||||
|
_widgets:
|
||||||
|
notifications: "Powiadomienia"
|
||||||
|
_profile:
|
||||||
|
username: "Nazwa użytkownika"
|
||||||
|
_deck:
|
||||||
|
_columns:
|
||||||
|
notifications: "Powiadomienia"
|
||||||
|
@@ -1,45 +1,894 @@
|
|||||||
---
|
---
|
||||||
_lang_: "Русский язык"
|
_lang_: "Русский"
|
||||||
introMisskey: "Добро пожаловать! Misskey - это децентрализованный сервис микроблогов с открытым исходным кодом.\nСоздавайте «записи», чтобы поделиться происходящим или рассказать всем о себе 📡\nТакже Вы можете добавить быструю реакцию на все записи с помощью функции «реакция» 👍\nОткройте для себя новый мир 🚀"
|
introMisskey: "Добро пожаловать! Misskey - это децентрализованный сервис микроблогов с открытым исходным кодом.\nСоздавайте «записи», чтобы поделиться происходящим или рассказать всем о себе 📡\nТакже Вы можете добавить быструю реакцию на все записи с помощью функции «реакция» 👍\nОткройте для себя новый мир 🚀"
|
||||||
monthAndDay: "{day}.{month}"
|
monthAndDay: "{day}.{month}"
|
||||||
search: "Поиск"
|
search: "Поиск"
|
||||||
notifications: "Уведомления"
|
notifications: "Уведомления"
|
||||||
|
username: "Имя пользователя"
|
||||||
password: "Пароль"
|
password: "Пароль"
|
||||||
fetchingAsApObject: "Запрос на федерацию"
|
fetchingAsApObject: "Запрос на федерацию"
|
||||||
ok: "Окей"
|
ok: "Окей"
|
||||||
gotIt: "Отлично"
|
gotIt: "Отлично"
|
||||||
cancel: "Отмена"
|
cancel: "Отмена"
|
||||||
instance: "Экземпляр"
|
enterUsername: "Введите имя пользователя"
|
||||||
|
renotedBy: "{user} репостнул(а)"
|
||||||
|
noNotes: "Нет постов"
|
||||||
|
noNotifications: "Нет уведомлений"
|
||||||
|
instance: "Узел"
|
||||||
settings: "Настройки"
|
settings: "Настройки"
|
||||||
|
basicSettings: "Основное"
|
||||||
|
otherSettings: "Прочee"
|
||||||
|
openInWindow: "Открыть в окне"
|
||||||
profile: "Профиль"
|
profile: "Профиль"
|
||||||
timeline: "Лента"
|
timeline: "Лента"
|
||||||
|
noAccountDescription: "Описание отсутствует"
|
||||||
login: "Войти"
|
login: "Войти"
|
||||||
|
loggingIn: "Выполняется вход"
|
||||||
logout: "Выйти"
|
logout: "Выйти"
|
||||||
signup: "Регистрация"
|
signup: "Регистрация"
|
||||||
|
uploading: "Загрузка..."
|
||||||
save: "Сохранить"
|
save: "Сохранить"
|
||||||
|
users: "Пользователи"
|
||||||
|
addUser: "Добавить пользователя"
|
||||||
favorite: "Избранное"
|
favorite: "Избранное"
|
||||||
favorites: "Избранное"
|
favorites: "Избранное"
|
||||||
unfavorite: "Удалить из избранных"
|
unfavorite: "Удалить из избранных"
|
||||||
pin: "Закрепить"
|
pin: "Закрепить"
|
||||||
unpin: "Открепить"
|
unpin: "Открепить"
|
||||||
|
copyContent: "Скопировать содержимое"
|
||||||
copyLink: "Скопировать ссылку"
|
copyLink: "Скопировать ссылку"
|
||||||
delete: "Удалить"
|
delete: "Удалить"
|
||||||
|
deleteAndEdit: "Удалить и отредактировать"
|
||||||
|
deleteAndEditConfirm: "Удалить этот пост и отредактировать заново? Все реакции, репосты и ответы на него также будут удалены."
|
||||||
addToList: "Добавить в список"
|
addToList: "Добавить в список"
|
||||||
|
sendMessage: "Отправить сообщение"
|
||||||
|
copyUsername: "Скопировать имя пользователя"
|
||||||
|
searchUser: "Поиск людей"
|
||||||
reply: "Ответить"
|
reply: "Ответить"
|
||||||
loadMore: "Показать еще"
|
loadMore: "Показать еще"
|
||||||
|
youGotNewFollower: "Новый подписчик"
|
||||||
|
receiveFollowRequest: "Запрос на подписку"
|
||||||
|
followRequestAccepted: "Запрос на подписку принят"
|
||||||
|
mention: "Упоминание"
|
||||||
|
mentions: "Упоминания"
|
||||||
|
directNotes: "Прямые сообщения"
|
||||||
importAndExport: "Импорт / Экспорт"
|
importAndExport: "Импорт / Экспорт"
|
||||||
files: "Файл"
|
import: "Импорт"
|
||||||
instances: "Экземпляр"
|
export: "Экспорт"
|
||||||
|
files: "Файлы"
|
||||||
|
download: "Скачать"
|
||||||
|
driveFileDeleteConfirm: "Удалить файл {name} ? Посты с ним также будут удалены"
|
||||||
|
unfollowConfirm: "Удалить из подписок {name}?"
|
||||||
|
exportRequested: "Вы запросили экспорт. Это может занять некоторое время. По завершению результат будет добавлен на «Диск»."
|
||||||
|
importRequested: "Вы запросили импорт. Это может занять некоторое время."
|
||||||
|
lists: "Списки"
|
||||||
|
noLists: "Нет списков"
|
||||||
|
note: "Пост"
|
||||||
|
notes: "Посты"
|
||||||
|
following: "Подписки"
|
||||||
|
followers: "Подписчики"
|
||||||
|
followsYou: "Подписчики"
|
||||||
|
createList: "Создать список"
|
||||||
|
manageLists: "Управление списками"
|
||||||
|
error: "Ошибка"
|
||||||
|
somethingHappened: "Что-то пошло не так"
|
||||||
|
retry: "Повторить попытку"
|
||||||
|
pageLoadError: "Ошибка загрузки страницы"
|
||||||
|
pageLoadErrorDescription: "Обычно это вызвано сетевыми ошибками или кэшем браузера. Попробуйте очистить кэш, а затем попробуйте еще раз, немного подождав."
|
||||||
|
enterListName: "Введите имя списка"
|
||||||
|
privacy: "Приватность"
|
||||||
|
makeFollowManuallyApprove: "Подтверждать подписчиков вручную"
|
||||||
|
defaultNoteVisibility: "Видимость постов по умолчанию"
|
||||||
|
follow: "Подписки"
|
||||||
|
followRequest: "Запрос на подписку"
|
||||||
|
followRequests: "Запросы на подписку"
|
||||||
|
unfollow: "Отписаться"
|
||||||
|
followRequestPending: "Ожидающие запросы на подписку"
|
||||||
|
enterEmoji: "Введите эмодзи"
|
||||||
|
renote: "Репост"
|
||||||
|
unrenote: "Отмена репоста"
|
||||||
|
quote: "Цитата"
|
||||||
|
pinnedNote: "Закреплённый пост"
|
||||||
|
you: "Вы"
|
||||||
|
clickToShow: "Нажмите для просмотра"
|
||||||
|
sensitive: "NSFW"
|
||||||
|
add: "Добавить"
|
||||||
|
reaction: "Реакции"
|
||||||
|
reactionSettingDescription: "Выберите реакции для показа в селекторе реакций"
|
||||||
|
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: "Название эмодзи"
|
||||||
|
emojiUrl: "URL изображения"
|
||||||
|
addEmoji: "Добавить эмодзи"
|
||||||
|
settingGuide: "Рекомендуемые настройки"
|
||||||
|
cacheRemoteFiles: "Кешировать внешние файлы"
|
||||||
|
cacheRemoteFilesDescription: "Когда эта настройка отключена, удаленные файлы загружаются непосредственно из удаленного экземпляра. Отключение этого параметра уменьшит использование хранилища, но увеличит трафик, так как эскизы не будут генерироваться."
|
||||||
|
flagAsBot: "Учётка бота"
|
||||||
|
flagAsCat: "Учётка кота"
|
||||||
|
autoAcceptFollowed: "Принимать подписки автоматически"
|
||||||
|
addAcount: "Добавить учётку"
|
||||||
|
loginFailed: "Ошибка входа"
|
||||||
|
showOnRemote: "Посмотреть оригинал"
|
||||||
|
general: "Общее"
|
||||||
|
wallpaper: "Обои"
|
||||||
|
setWallpaper: "Установить обои"
|
||||||
|
removeWallpaper: "Удалить обои"
|
||||||
|
searchWith: "Искать в {q}"
|
||||||
|
youHaveNoLists: "Нет списков"
|
||||||
|
followConfirm: "Подписаться на {name}?"
|
||||||
|
proxyAccount: "Прокси аккаунт"
|
||||||
|
proxyAccountDescription: "Учетная запись прокси - это учетная запись, которая при определенных условиях действует в качестве удаленного последователя для пользователей. Например, когда пользователь добавляет удаленного пользователя в список, действия удаленного пользователя не будут доставляться экземпляру, если ни один локальный пользователь не следует за этим пользователем, поэтому вместо него будет действовать учетная запись прокси."
|
||||||
|
host: "Хост"
|
||||||
|
selectUser: "Выбор пользователя"
|
||||||
|
recipient: "Кому"
|
||||||
|
annotation: "Описание"
|
||||||
|
federation: "Федиверс"
|
||||||
|
instances: "Узел"
|
||||||
|
registeredAt: "Присоединился(ась)"
|
||||||
|
latestRequestSentAt: "Последний запрос отправлен"
|
||||||
|
latestRequestReceivedAt: "Последний запрос, поступивший по адресу"
|
||||||
|
latestStatus: "Последний статус"
|
||||||
|
storageUsage: "Использовано"
|
||||||
|
charts: "Диаграммы"
|
||||||
|
perHour: "Каждый час"
|
||||||
|
perDay: "Каждый день"
|
||||||
|
blockThisInstance: "Блокировать этот инстанс"
|
||||||
|
operations: "Операции"
|
||||||
|
software: "Программы"
|
||||||
|
version: "Версия"
|
||||||
|
metadata: "Метаданные"
|
||||||
|
withNFiles: "{n} файлов"
|
||||||
|
monitor: "Монитор"
|
||||||
|
jobQueue: "Очередь заданий"
|
||||||
|
cpuAndMemory: "CPU и память"
|
||||||
|
network: "Сеть"
|
||||||
|
disk: "Диск"
|
||||||
|
instanceInfo: "Информация об узле"
|
||||||
|
statistics: "Статистика"
|
||||||
|
clearQueue: "Очистить очередь"
|
||||||
|
clearQueueConfirmTitle: "Очистить очередь?"
|
||||||
|
clearQueueConfirmText: "Любые недоставленные записи, оставшиеся в очереди, не будут переданы. Обычно эта операция НЕ нужна."
|
||||||
|
clearCachedFiles: "Очистить кэш"
|
||||||
|
clearCachedFilesConfirm: "Хотите удалить все кешированные файлы?"
|
||||||
|
blockedInstances: "Заблокированные узлы"
|
||||||
|
blockedInstancesDescription: "Введите список узлов, которые хотите заблокировать. Они не смогут взаимодействовать с этим."
|
||||||
|
muteAndBlock: "Скрытие и блокировка"
|
||||||
|
mutedUsers: "Скрытые пользователи"
|
||||||
|
blockedUsers: "Заблокированные Пользователи"
|
||||||
|
noUsers: "Нет пользователей"
|
||||||
|
editProfile: "Изменить профиль"
|
||||||
|
noteDeleteConfirm: "Вы хотите удалить эту запись?"
|
||||||
|
pinLimitExceeded: "Превышен лимит"
|
||||||
|
intro: "Misskey установлен! Создайте учетную запись администратора"
|
||||||
|
done: "Завершено"
|
||||||
|
processing: "Обработка"
|
||||||
|
preview: "Превью"
|
||||||
|
default: "По умолчанию"
|
||||||
|
noCustomEmojis: "Нет эмодзи"
|
||||||
|
noJobs: "Нет заданий"
|
||||||
|
federating: "федеративный"
|
||||||
|
blocked: "Заблокировано"
|
||||||
|
suspended: "Приостановленный"
|
||||||
|
all: "Все"
|
||||||
|
subscribing: "Подписка"
|
||||||
|
publishing: "Публикация"
|
||||||
|
notResponding: "Нет ответа"
|
||||||
|
instanceFollowing: "Подписаться на инстанс"
|
||||||
|
instanceFollowers: "Подписчики инстанса"
|
||||||
|
instanceUsers: "Пользователи инстанса"
|
||||||
|
changePassword: "Изменить пароль"
|
||||||
|
security: "Безопасность"
|
||||||
|
retypedNotMatch: "Нет совпадений"
|
||||||
|
currentPassword: "Текущий пароль"
|
||||||
|
newPassword: "Новый пароль"
|
||||||
|
newPasswordRetype: "Новый пароль (повторно):"
|
||||||
|
attachFile: "Прикрепить файлы"
|
||||||
|
more: "Ещё!"
|
||||||
|
featured: "Рекомендуемые"
|
||||||
|
usernameOrUserId: "Имя пользователя или ID"
|
||||||
|
noSuchUser: "Пользователь не найден"
|
||||||
|
lookup: "Подписка"
|
||||||
|
announcements: "Уведомление"
|
||||||
|
imageUrl: "URL-адрес изображения"
|
||||||
remove: "Удалить"
|
remove: "Удалить"
|
||||||
|
removed: "Удалено"
|
||||||
|
removeAreYouSure: "Хочешь удалить \"{x}\"?"
|
||||||
|
saved: "Сохранено"
|
||||||
|
messaging: "Сообщения"
|
||||||
|
upload: "Загрузить"
|
||||||
|
fromDrive: "С диска"
|
||||||
|
fromUrl: "URL-адрес"
|
||||||
|
uploadFromUrl: "Загрузить по ссылке"
|
||||||
|
uploadFromUrlDescription: "URL-адрес файла, который вы хотите загрузить"
|
||||||
|
uploadFromUrlRequested: "Загрузить запрос"
|
||||||
|
uploadFromUrlMayTakeTime: "Загрузка может занять некоторое время."
|
||||||
|
explore: "Обзор"
|
||||||
|
games: "Игры Misskey"
|
||||||
|
messageRead: "Прочитанных"
|
||||||
|
noMoreHistory: "Истории больше нет"
|
||||||
|
startMessaging: "Отправить сообщение"
|
||||||
|
nUsersRead: "прочитано {n}"
|
||||||
|
agreeTo: "Я согласен с {0}"
|
||||||
|
tos: "Пользовательское соглашение"
|
||||||
|
start: "Начать"
|
||||||
|
home: "Главная"
|
||||||
|
remoteUserCaution: "Эта информация может быть неактуальной, так как пользователь является удаленным пользователем."
|
||||||
|
activity: "Активность"
|
||||||
|
images: "Изображение"
|
||||||
|
birthday: "День рождения"
|
||||||
|
yearsOld: "{age} лет"
|
||||||
|
registeredDate: "Дата регистрации"
|
||||||
|
location: "Местоположение"
|
||||||
|
theme: "Тема"
|
||||||
|
themeForLightMode: "Темы для использования в световом режиме"
|
||||||
|
themeForDarkMode: "Темы для использования в темном режиме"
|
||||||
|
light: "Светлый"
|
||||||
|
dark: "Тёмный"
|
||||||
|
lightThemes: "Светлые темы"
|
||||||
|
darkThemes: "Тёмные темы"
|
||||||
|
syncDeviceDarkMode: "Синхронизировать с темным режимом устройства"
|
||||||
|
drive: "Диск"
|
||||||
|
fileName: "Имя файла"
|
||||||
|
selectFile: "Выберите Файл"
|
||||||
|
selectFiles: "Выберите Файл"
|
||||||
|
selectFolder: "Выберите папку"
|
||||||
|
selectFolders: "Выберите папку"
|
||||||
|
renameFile: "Переименовать файл"
|
||||||
|
folderName: "Имя папки"
|
||||||
|
createFolder: "Создать папку"
|
||||||
|
renameFolder: "Переименовать папку"
|
||||||
|
deleteFolder: "Удалить папку"
|
||||||
|
addFile: "Добавить файл"
|
||||||
|
emptyDrive: "Диск пуст"
|
||||||
|
emptyFolder: "Папка пуста"
|
||||||
|
unableToDelete: "Удаление невозможно"
|
||||||
|
inputNewFileName: "Введите имя нового файла"
|
||||||
|
inputNewFolderName: "Пожалуйста, введите новое имя папки!"
|
||||||
|
circularReferenceFolder: "Конечная папка - это вложенная папка, которую вы хотите переместить."
|
||||||
|
hasChildFilesOrFolders: "Эта папка не пуста и не может быть удалена."
|
||||||
|
copyUrl: "Копировать URL"
|
||||||
|
rename: "Переименовать"
|
||||||
|
avatar: "Иконка"
|
||||||
|
banner: "Баннер"
|
||||||
|
nsfw: "NSFW"
|
||||||
|
whenServerDisconnected: "Когда соединение с сервером потеряно"
|
||||||
|
disconnectedFromServer: "Разорвано соединение с сервером"
|
||||||
|
reload: "Перезагрузить"
|
||||||
|
doNothing: "Ничего не делать"
|
||||||
|
reloadConfirm: "Подтвердить перезагрузку?"
|
||||||
|
watch: "Следить"
|
||||||
|
unwatch: "Отписаться"
|
||||||
|
accept: "Принять"
|
||||||
|
reject: "Отклонить"
|
||||||
|
normal: "Стабильно"
|
||||||
|
instanceName: "Имя экземпляра"
|
||||||
|
instanceDescription: "Описание инстанса"
|
||||||
|
maintainerName: "Имя администратора"
|
||||||
|
maintainerEmail: "email администратора"
|
||||||
|
tosUrl: "Пользовательское соглашение URL"
|
||||||
|
thisYear: "Текущий год"
|
||||||
|
thisMonth: "Текущий месяц"
|
||||||
|
today: "Сегодня"
|
||||||
|
dayX: "{day}дней"
|
||||||
|
monthX: "{month}месяц"
|
||||||
|
yearX: "{year}год"
|
||||||
|
pages: "Страница"
|
||||||
|
integration: "подключение"
|
||||||
|
connectSerice: "Соединение"
|
||||||
|
disconnectSerice: "Отключение"
|
||||||
|
enableLocalTimeline: "Включить локальную ленту"
|
||||||
|
enableGlobalTimeline: "Включить глобальную ленту"
|
||||||
|
disablingTimelinesInfo: "Администраторы и Модераторы всегда будут иметь доступ ко всем временным параметрам, даже если они не включены."
|
||||||
|
registration: "Регистрация"
|
||||||
|
enableRegistration: "Разрешить регистрацию"
|
||||||
|
invite: "Пригласить"
|
||||||
|
proxyRemoteFiles: "Удаленные файлы прокси"
|
||||||
|
proxyRemoteFilesDescription: "Если эта функция включена, удаленные файлы, которые (1) не хранятся локально или (2) были удалены с превышением лимита хранения, будут проксированы локально (с эскизами). Это не влияет на хранение на сервере."
|
||||||
|
driveCapacityPerLocalAccount: "Емкость диска для локального пользователя"
|
||||||
|
driveCapacityPerRemoteAccount: "Емкость диска для удаленного пользователя"
|
||||||
|
inMb: "В мегабайтах"
|
||||||
|
iconUrl: "URL-адрес иконки"
|
||||||
|
bannerUrl: "URL-адрес изображения баннера"
|
||||||
|
basicInfo: "Общая информация"
|
||||||
|
pinnedUsers: "Прикреплённый пользователь"
|
||||||
|
pinnedUsersDescription: "Перечислите по одному имени пользователя в строке. Пользователи, перечисленные здесь, будут привязаны к закладке \"Изучение\"."
|
||||||
|
hcaptcha: "hCaptcha"
|
||||||
|
enableHcaptcha: "Включить hCaptcha"
|
||||||
|
hcaptchaSiteKey: "Ключ сайта"
|
||||||
|
hcaptchaSecretKey: "Секретный ключ"
|
||||||
|
recaptcha: "reCAPTCHA"
|
||||||
|
enableRecaptcha: "Включить reCAPTCHA"
|
||||||
|
recaptchaSiteKey: "Ключ сайта"
|
||||||
|
recaptchaSecretKey: "Секретный ключ"
|
||||||
|
avoidMultiCaptchaConfirm: "Использование нескольких Captchas может вызвать помехи. Хотите отключить другую Captcha? Вы можете оставить несколько Captchas включенными, нажав \"Отмена\"."
|
||||||
|
antennas: "Антенны"
|
||||||
|
manageAntennas: "Настройки антенн"
|
||||||
|
name: "Имя"
|
||||||
|
antennaSource: "Источник антенны"
|
||||||
|
antennaKeywords: "Ключевые слова"
|
||||||
|
antennaExcludeKeywords: "Исключения"
|
||||||
|
antennaKeywordsDescription: "Разделяйте пробелами для условия \"И\". Разделяйте переводом строки для \"ИЛИ\"."
|
||||||
|
notifyAntenna: "Уведомлять о новых записях"
|
||||||
|
serviceworker: "ServiceWorker"
|
||||||
|
enableServiceworker: "Включить ServiceWorker"
|
||||||
|
caseSensitive: "С учётом регистра"
|
||||||
|
withReplies: "Включить ответы"
|
||||||
|
connectedTo: "Вы подключены к следующим аккаунтам"
|
||||||
|
notesAndReplies: "Посты и ответы"
|
||||||
|
withFiles: "с файлами"
|
||||||
|
silence: "Заглушить"
|
||||||
|
silenceConfirm: "Вы уверены, что хотите заглушить этого пользователя?"
|
||||||
|
unsilenceConfirm: "Ты уверен, что хочешь отменить глушение этого пользователя?"
|
||||||
|
popularUsers: "Популярные пользователи"
|
||||||
|
recentlyUpdatedUsers: "Недавно активные"
|
||||||
|
recentlyRegisteredUsers: "Недавно зарегистрированные пользователи"
|
||||||
|
recentlyDiscoveredUsers: "Недавно обнаруженные пользователи"
|
||||||
|
exploreUsersCount: "{count} пользователей"
|
||||||
|
exploreFediverse: "Исследуйте Fediverse"
|
||||||
|
popularTags: "Популярные теги"
|
||||||
|
userList: "Списки"
|
||||||
|
about: "Описание"
|
||||||
|
aboutMisskey: "О Misskey"
|
||||||
|
aboutMisskeyText: "Misskey - это программное обеспечение с открытым исходным кодом, разрабатываемое syuilo с 2014 года."
|
||||||
|
misskeyMembers: "В настоящее время он разрабатывается и поддерживается следующими членами:"
|
||||||
|
misskeySource: "Исходный код доступен здесь:"
|
||||||
|
misskeyTranslation: "Помогите нам перевести Misskey:"
|
||||||
|
misskeyDonate: "Вы можете поддержать развитие, пожертвовав Misskey:"
|
||||||
|
morePatrons: "Есть много других, кто поддержал нас. Спасибо 🥰."
|
||||||
|
patrons: "Поддержавшие"
|
||||||
|
administrator: "Администратор"
|
||||||
|
token: "Токен"
|
||||||
|
twoStepAuthentication: "Двухфакторная аутентификация"
|
||||||
|
moderator: "Модератор"
|
||||||
|
nUsersMentioned: "{n}указанные пользователи"
|
||||||
|
securityKey: "Ключ безопасности"
|
||||||
|
securityKeyName: "Имя ключа"
|
||||||
|
registerSecurityKey: "Зарегистрировать защитный ключ"
|
||||||
|
lastUsed: "Последнее использование"
|
||||||
|
unregister: "Отписаться"
|
||||||
|
resetPassword: "Сброс пароля:"
|
||||||
|
newPasswordIs: "Новый пароль - \"{пароль}\"."
|
||||||
|
autoNoteWatch: "Автоматически просматривать записи"
|
||||||
|
autoNoteWatchDescription: "Получать уведомления о заметках других пользователей, на которые вы отреагировали или на которые вы ответили."
|
||||||
|
reduceUiAnimation: "Уменьшить анимацию в пользовательском интерфейсе."
|
||||||
|
share: "Поделиться"
|
||||||
|
notFound: "Не найдено"
|
||||||
|
notFoundDescription: "Страница, соответствующая указанному URL, не найдена."
|
||||||
|
uploadFolder: "Место загрузки по умолчанию"
|
||||||
|
cacheClear: "Очистка кэша"
|
||||||
|
markAsReadAllNotifications: "Отметить все уведомления как прочитанные"
|
||||||
|
markAsReadAllUnreadNotes: "Отметьте все сообщения как прочитанные."
|
||||||
|
markAsReadAllTalkMessages: "Отметьте все сообщения как прочитанные"
|
||||||
|
help: "Помощь"
|
||||||
|
inputMessageHere: "Введите сообщение здесь"
|
||||||
|
close: "Закрыть"
|
||||||
|
group: "Группа"
|
||||||
|
groups: "Группы"
|
||||||
|
createGroup: "Создать группу"
|
||||||
|
ownedGroups: "Собственные группы"
|
||||||
|
joinedGroups: "Участие в группах"
|
||||||
|
invites: "Пригласить"
|
||||||
|
groupName: "Название группы"
|
||||||
|
members: "Участники"
|
||||||
|
transfer: "Перенос"
|
||||||
|
messagingWithUser: "Сообщения пользователей"
|
||||||
|
messagingWithGroup: "Чат в группе"
|
||||||
|
title: "Заголовок."
|
||||||
|
text: "Текст"
|
||||||
|
enable: "Включить."
|
||||||
|
next: "Следующий"
|
||||||
|
retype: "Введите повторно"
|
||||||
|
noteOf: "Посты {user}"
|
||||||
|
inviteToGroup: "Пригласить в группу"
|
||||||
|
maxNoteTextLength: "Максимальная длина текста"
|
||||||
|
quoteQuestion: "Хочешь добавить цитату?"
|
||||||
|
noMessagesYet: "Сообщений нет"
|
||||||
|
newMessageExists: "Новое сообщение"
|
||||||
|
onlyOneFileCanBeAttached: "К сообщению можно прикрепить только один файл."
|
||||||
|
signinRequired: "Пожалуйста, войдите."
|
||||||
|
invitationCode: "Код приглашения"
|
||||||
|
checking: "Проверка"
|
||||||
|
available: "Доступен"
|
||||||
|
unavailable: "Не доступно"
|
||||||
|
usernameInvalidFormat: "Вы можете использовать a-z, A-Z, 0-9 и _"
|
||||||
|
tooShort: "Слишком короткий"
|
||||||
|
tooLong: "Слишком длинный"
|
||||||
|
weakPassword: "Слабый пароль"
|
||||||
|
normalPassword: "Обычный пароль"
|
||||||
|
strongPassword: "Надёжный пароль"
|
||||||
|
passwordMatched: "Подходящий пароль"
|
||||||
|
passwordNotMatched: "Пароль не найден"
|
||||||
|
signinWith: "Войти в систему с помощью {x}"
|
||||||
|
signinFailed: "Невозможно войти в систему. Введенное вами имя пользователя или пароль неверны."
|
||||||
|
or: "или"
|
||||||
|
uiLanguage: "Язык интерфейса"
|
||||||
|
groupInvited: "Приглашение в группу"
|
||||||
|
aboutX: "Описание {x}"
|
||||||
|
useOsNativeEmojis: "Используйте родной для ОС Emojis"
|
||||||
|
youHaveNoGroups: "Группы не найдены"
|
||||||
|
joinOrCreateGroup: "Получите приглашение присоединиться к группам или вы можете создать свою собственную группу."
|
||||||
|
noHistory: "Ничего не найдено"
|
||||||
|
disableAnimatedMfm: "Отключение MFM в анимации"
|
||||||
|
doing: "В пути"
|
||||||
|
category: "Категория"
|
||||||
|
tags: "Теги"
|
||||||
|
docSource: "Источник документа"
|
||||||
|
createAccount: "Зарегистрироваться"
|
||||||
|
existingAcount: "У вас уже есть учетная запись?"
|
||||||
|
regenerate: "Восстановить"
|
||||||
|
fontSize: "Размер шрифта"
|
||||||
|
noFollowRequests: "У вас нет никаких ожидающих ответа запросов"
|
||||||
|
openImageInNewTab: "Открыть изображение в новой вкладке"
|
||||||
|
dashboard: "Панель управления"
|
||||||
|
local: "Локальный"
|
||||||
|
remote: "Удаленный"
|
||||||
|
total: "Всего"
|
||||||
|
weekOverWeekChanges: "Еженедельно"
|
||||||
|
dayOverDayChanges: "Ежедневно"
|
||||||
|
appearance: "Внешний вид"
|
||||||
|
clientSettings: "Настройки клиента"
|
||||||
|
accountSettings: "Настройки учетной записи"
|
||||||
|
promotion: "Опубликовано"
|
||||||
|
promote: "Продвинуть"
|
||||||
|
numberOfDays: "Количество дней"
|
||||||
|
hideThisNote: "Спрятать эту запись"
|
||||||
|
objectStorage: "Хранилище"
|
||||||
|
useObjectStorage: "Занято в хранилище"
|
||||||
|
objectStorageBaseUrl: "Базовый URL-адрес"
|
||||||
|
objectStorageBucket: "Bucket"
|
||||||
|
objectStoragePrefix: "Префикс"
|
||||||
|
objectStorageRegion: "Регион"
|
||||||
|
serverLogs: "Журнал сервера"
|
||||||
|
deleteAll: "Удалить всё"
|
||||||
|
sounds: "Звуки"
|
||||||
|
listen: "Слушать"
|
||||||
|
none: "Ничего"
|
||||||
|
showInPage: "Показать страницу"
|
||||||
|
popout: "Развернуть"
|
||||||
|
volume: "Громкость"
|
||||||
|
details: "Подробнее"
|
||||||
|
chooseEmoji: "Выберите эмодзи"
|
||||||
|
unableToProcess: "Я не могу завершить операцию."
|
||||||
|
recentUsed: "Последние использованные"
|
||||||
|
install: "Установить"
|
||||||
|
uninstall: "Удалить"
|
||||||
|
installedApps: "Установленные приложения"
|
||||||
|
nothing: "Ничего не найдено"
|
||||||
|
installedDate: "Дата установки"
|
||||||
|
lastUsedDate: "Дата использования"
|
||||||
|
state: "Состояние"
|
||||||
|
sort: "Сортировать"
|
||||||
|
ascendingOrder: "по возрастанию"
|
||||||
|
descendingOrder: "По убыванию"
|
||||||
|
scratchpad: "Редактор "
|
||||||
|
scratchpadDescription: "Scratchpad предоставляет экспериментальную среду для AiScript, позволяющую писать, запускать и проверять результаты кода, взаимодействующего с Misskey."
|
||||||
|
output: "Выходы"
|
||||||
|
script: "Скрипт"
|
||||||
|
disablePagesScript: "Отключение скриптов в Pages"
|
||||||
|
deleteAllFiles: "Удалить все файлы"
|
||||||
|
deleteAllFilesConfirm: "Вы хотите удалить все файлы?"
|
||||||
|
removeAllFollowing: "Удалить всех подписчиков"
|
||||||
|
userSuspended: "Этот пользователь был заморожен"
|
||||||
|
userSilenced: "Этот пользователь был заглушен"
|
||||||
|
sidebar: "Боковая панель"
|
||||||
|
divider: "Разделительная полоса"
|
||||||
|
addItem: "Добавить элемент"
|
||||||
|
rooms: "Комнаты"
|
||||||
|
relays: "Ретрансляторы"
|
||||||
|
addRelay: "Добавить ретранслятор"
|
||||||
|
addedRelays: "Добавленные ретрансляторы"
|
||||||
|
invisibleNote: "Личное сообщение"
|
||||||
|
visibility: "Видимость"
|
||||||
|
poll: "Опрос"
|
||||||
|
enablePlayer: "Включить плеер"
|
||||||
|
disablePlayer: "Выключить плеер"
|
||||||
|
themeEditor: "Редактор темы"
|
||||||
|
description: "Описание"
|
||||||
|
author: "Автор"
|
||||||
|
plugins: "Плагины"
|
||||||
|
permission: "Разрешения"
|
||||||
|
enableAll: "Включить все"
|
||||||
|
disableAll: "Выключить всё"
|
||||||
|
notificationType: "Тип уведомления"
|
||||||
|
edit: "Изменить"
|
||||||
|
emailConfig: "Настройки почтового сервера"
|
||||||
|
enableEmail: "Активировать функцию доставки электронной почты"
|
||||||
|
emailConfigInfo: "Он используется для подтверждения адреса электронной почты и сброса пароля."
|
||||||
|
email: "email"
|
||||||
|
smtpConfig: "Конфигурация SMTP-сервера"
|
||||||
|
smtpHost: "Хост"
|
||||||
|
smtpPort: "smtp порт"
|
||||||
|
smtpUser: "Имя пользователя"
|
||||||
smtpPass: "Пароль"
|
smtpPass: "Пароль"
|
||||||
|
emptyToDisableSmtpAuth: "Вы можете отключить SMTP аутентификацию, оставив ваше имя пользователя и пароль пустыми"
|
||||||
|
smtpSecure: "Использовать SSL/TLS для SMTP-соединений"
|
||||||
|
smtpSecureInfo: "Выключите его при использовании STARTTLS."
|
||||||
|
testEmail: "Проверка Email"
|
||||||
|
wordMute: "Скрытие слов"
|
||||||
|
makeActive: "Активировать"
|
||||||
|
display: "Показать"
|
||||||
|
copy: "Копировать"
|
||||||
|
metrics: "Метрика"
|
||||||
|
overview: "Обзор"
|
||||||
|
logs: "Лог-файлы"
|
||||||
|
delayed: "Задержка"
|
||||||
|
database: "База данных"
|
||||||
|
channel: "каналы"
|
||||||
|
create: "Создать"
|
||||||
|
notificationSetting: "Настройки уведомлений"
|
||||||
|
notificationSettingDesc: "Выберите тип уведомлений для отображения"
|
||||||
|
useGlobalSetting: "Использовать глобальные настройки"
|
||||||
|
useGlobalSettingDesc: "Использовать глобальные настройки"
|
||||||
|
other: "Другие"
|
||||||
|
regenerateLoginToken: "Восстановить токен входа"
|
||||||
|
regenerateLoginTokenDescription: "Восстановите токен, используемый внутри во время входа. Обычно в этом нет необходимости. При восстановлении все устройства будут отключены."
|
||||||
|
setMultipleBySeparatingWithSpace: "Вы можете установить несколько, разделив их пробелами."
|
||||||
|
fileIdOrUrl: "ID файла или URL-адрес"
|
||||||
|
chatOpenBehavior: "Поведение окна чата при открытии"
|
||||||
|
sample: "Пример"
|
||||||
|
abuseReports: "Отчеты"
|
||||||
|
reportAbuse: "Отчеты"
|
||||||
|
fillAbuseReportDescription: "Пожалуйста, заполните данные отчета. Если речь идет о конкретном сообщении, пожалуйста, укажите его URL."
|
||||||
|
abuseReported: "Содержимое отправлено. Спасибо за сообщение"
|
||||||
|
send: "Отправить"
|
||||||
|
abuseMarkAsResolved: "Отметить отчет как решенный"
|
||||||
|
_serverDisconnectedBehavior:
|
||||||
|
reload: "Автоматическая перезагрузка"
|
||||||
|
dialog: "Предупреждение"
|
||||||
|
quiet: "Показать ненавязчивое предупреждение"
|
||||||
|
_channel:
|
||||||
|
create: "Создать канал"
|
||||||
|
edit: "Редактировать канал"
|
||||||
|
setBanner: "Установить баннер"
|
||||||
|
removeBanner: "Удалить баннер"
|
||||||
|
featured: "В тренде"
|
||||||
|
owned: "Владелец"
|
||||||
|
usersCount: "{n} Участники"
|
||||||
|
notesCount: "{n} Записи"
|
||||||
|
_sidebar:
|
||||||
|
full: "Полный"
|
||||||
|
icon: "Иконка"
|
||||||
|
hide: "Спрятать"
|
||||||
|
_wordMute:
|
||||||
|
muteWords: "Скрыть слово"
|
||||||
|
muteWordsDescription: "Разделяйте пробелами для условия \"И\". Разделяйте переводом строки для \"ИЛИ\"."
|
||||||
|
muteWordsDescription2: "Округляйте ключевые слова слэшами для использования регулярных выражений."
|
||||||
|
soft: "Лёгкий "
|
||||||
|
hard: "Сложный"
|
||||||
|
mutedNotes: "Скрытые посты"
|
||||||
|
_theme:
|
||||||
|
explore: "Обзор"
|
||||||
|
install: "Установить тему"
|
||||||
|
manage: "Менеджер тем"
|
||||||
|
code: "Код темы"
|
||||||
|
installed: "{name} установлено "
|
||||||
|
alreadyInstalled: "Тема уже установлена"
|
||||||
|
invalid: "Формат темы некорректный "
|
||||||
|
make: "Создать тему"
|
||||||
|
base: "База"
|
||||||
|
addConstant: "Добавить константу"
|
||||||
|
constant: "Константа"
|
||||||
|
defaultValue: "Значение по умолчанию"
|
||||||
|
color: "Цвет"
|
||||||
|
refConst: "Ссылка на константу"
|
||||||
|
key: "Ключ"
|
||||||
|
func: "Функции"
|
||||||
|
funcKind: "Тип функции"
|
||||||
|
argument: "Аргумент"
|
||||||
|
basedProp: "Указанное свойство"
|
||||||
|
alpha: "Непрозрачность"
|
||||||
|
darken: "Темный"
|
||||||
|
inputConstantName: "Введите имя для константы"
|
||||||
|
importInfo: "Если вы введете код темы здесь, вы можете импортировать его в редактор тем."
|
||||||
|
deleteConstantConfirm: "Вы действительно хотите удалить константу {const}?"
|
||||||
|
keys:
|
||||||
|
bg: "Справочная информация"
|
||||||
|
fg: "Текст"
|
||||||
|
navHoverFg: "Текст на боковой панели (Навести)"
|
||||||
|
link: "Ссылка"
|
||||||
|
hashtag: "Хэштеги"
|
||||||
|
mention: "Упоминание"
|
||||||
|
renote: "Репост"
|
||||||
|
divider: "Разделительная полоса"
|
||||||
|
infoBg: "Справочная информация"
|
||||||
|
infoFg: "Текст информации"
|
||||||
_sfx:
|
_sfx:
|
||||||
|
note: "Посты"
|
||||||
notification: "Уведомления"
|
notification: "Уведомления"
|
||||||
|
chat: "Сообщения"
|
||||||
|
_ago:
|
||||||
|
secondsAgo: "{} секунд назад"
|
||||||
|
minutesAgo: "{} минут назад"
|
||||||
|
hoursAgo: "{} часов назад"
|
||||||
|
daysAgo: "{} дней назад"
|
||||||
|
weeksAgo: "{} недель назад"
|
||||||
|
monthsAgo: "{} месяцев назад"
|
||||||
|
yearsAgo: "{} лет назад"
|
||||||
|
_time:
|
||||||
|
second: "сек"
|
||||||
|
minute: "Мин."
|
||||||
|
_tutorial:
|
||||||
|
title: "Как пользоваться Misskey"
|
||||||
|
step1_1: "Добро пожаловать!"
|
||||||
|
step2_1: "Прежде чем создать заметку или следовать за кем-либо, сначала заполните свой профиль."
|
||||||
|
step3_1: "Вы хорошо подготовили свой профиль?"
|
||||||
|
step6_2: "Вы можете добавлять \"реакции\" к записям других людей, что облегчает общение с ними."
|
||||||
|
step6_3: "Чтобы добавить реакцию, нажмите на знак \"+\" в записке и выберите нужную реакцию."
|
||||||
|
step7_1: "На этом мы завершаем основные инструкции по использованию Misskey. Спасибо за вашу тяжёлую работу."
|
||||||
|
step7_2: "Если вы хотите узнать больше о Misskey, посмотрите в {хелп}."
|
||||||
|
_2fa:
|
||||||
|
alreadyRegistered: "Настройка завершена"
|
||||||
|
registerDevice: "Зарегистрируйте ваше устройство"
|
||||||
|
step1: "Во-первых, установите на устройство приложение для аутентификации, например, {a} или {b}."
|
||||||
|
step2: "Далее отсканируйте отображаемый QR-код при помощи приложения"
|
||||||
|
step3: "Введите токен, отображаемый в приложении, и все готово"
|
||||||
|
step4: "Когда вы войдете в систему, вы можете ввести свой токен тем же способом."
|
||||||
|
securityKeyInfo: "Вы можете настроить вход с помощью аппаратного ключа безопасности, поддерживающего FIDO2, или отпечатка пальца или PIN-кода на устройстве."
|
||||||
|
_permissions:
|
||||||
|
"read:account": "Просмотр информации об аккаунте"
|
||||||
|
"write:account": "Изменить информацию о вашем аккаунте"
|
||||||
|
"write:blocks": "Отредактируйте список людей, которых вы заблокировали"
|
||||||
|
"read:drive": "Доступ к файлам и папкам диска"
|
||||||
|
"write:drive": "Редактирование или удаление файлов и папок диска"
|
||||||
|
"read:favorites": "Просмотреть список избранных"
|
||||||
|
"write:favorites": "Редактирование списка избранных"
|
||||||
|
"read:messaging": "Просмотр сообщений"
|
||||||
|
"read:mutes": "Просмотр скрытых пользователей"
|
||||||
|
"write:mutes": "Изменение списка скрытых"
|
||||||
|
"read:notifications": "Просмотреть уведомления"
|
||||||
|
"write:reactions": "Редактировать реакции"
|
||||||
|
_weekday:
|
||||||
|
saturday: "Суббота"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
memo: "Заметка"
|
||||||
notifications: "Уведомления"
|
notifications: "Уведомления"
|
||||||
timeline: "Лента"
|
timeline: "Лента"
|
||||||
|
calendar: "Календарь"
|
||||||
|
trends: "В тренде"
|
||||||
|
clock: "Часы"
|
||||||
|
rss: "Ридер RSS"
|
||||||
|
activity: "Активность"
|
||||||
|
photos: "Фото"
|
||||||
|
digitalClock: "Цифровые Часы"
|
||||||
|
federation: "Федиверс"
|
||||||
|
postForm: "Форма отправки"
|
||||||
_cw:
|
_cw:
|
||||||
|
hide: "Спрятать"
|
||||||
show: "Показать еще"
|
show: "Показать еще"
|
||||||
|
chars: "{count} символов"
|
||||||
|
files: "{count} файлов"
|
||||||
|
_poll:
|
||||||
|
noOnlyOneChoice: "Нужно как минимум два варианта."
|
||||||
|
choiceN: "Выбрать{n}"
|
||||||
|
canMultipleVote: "Возможны несколько вариантов ответов"
|
||||||
|
expiration: "Истечение срока действия"
|
||||||
|
infinite: "Неограниченное количество"
|
||||||
|
deadlineDate: "Срок исполнения"
|
||||||
|
deadlineTime: "Длительность"
|
||||||
|
duration: "Продожительность"
|
||||||
|
totalVotes: "Всего {n} голосов"
|
||||||
|
vote: "Проголосовать"
|
||||||
|
showResult: "Смотреть результаты"
|
||||||
|
voted: "Проголосовали"
|
||||||
|
closed: "Завершено"
|
||||||
|
_visibility:
|
||||||
|
public: "Публичный"
|
||||||
|
publicDescription: "Открыт для всех пользователей"
|
||||||
|
home: "Главная"
|
||||||
|
followers: "Подписчики"
|
||||||
|
specifiedDescription: "Отправлять сообщения только указанным пользователям"
|
||||||
|
localOnly: "Только локально"
|
||||||
|
localOnlyDescription: "Не видно удаленным пользователям"
|
||||||
|
_postForm:
|
||||||
|
replyPlaceholder: "Ответьте на эту запись..."
|
||||||
|
quotePlaceholder: "Процитировать эту запись..."
|
||||||
|
channelPlaceholder: "Отправить в канал"
|
||||||
|
_placeholders:
|
||||||
|
a: "Что происходит?"
|
||||||
|
_profile:
|
||||||
|
name: "Имя"
|
||||||
|
username: "Имя пользователя"
|
||||||
|
metadataContent: "Содержание"
|
||||||
|
_exportOrImport:
|
||||||
|
allNotes: "Все записи\n"
|
||||||
|
followingList: "Подписки"
|
||||||
|
muteList: "Скрыть"
|
||||||
|
blockingList: "Заблокировать"
|
||||||
|
userLists: "Списки"
|
||||||
|
_timelines:
|
||||||
|
home: "Главная"
|
||||||
|
_rooms:
|
||||||
|
roomOf: "Комната {user}"
|
||||||
|
_roomType:
|
||||||
|
default: "По умолчанию"
|
||||||
|
_furnitures:
|
||||||
|
pencil: "Карандаш"
|
||||||
|
book: "Книга"
|
||||||
|
server: "Сервер"
|
||||||
|
monitor: "Монитор"
|
||||||
|
_pages:
|
||||||
|
title: "Заголовок."
|
||||||
|
url: "URL страницы"
|
||||||
|
hideTitleWhenPinned: "Скрыть заголовок страницы при привязке к профилю"
|
||||||
|
font: "Шрифт"
|
||||||
|
blocks:
|
||||||
|
section: "Раздел"
|
||||||
|
image: "Изображение"
|
||||||
|
button: "Кнопка"
|
||||||
|
if: "Если"
|
||||||
|
_if:
|
||||||
|
variable: "Переменная"
|
||||||
|
post: "Форма отправки"
|
||||||
|
_post:
|
||||||
|
text: "Содержание"
|
||||||
|
textInput: "Ввод текста"
|
||||||
|
_textInput:
|
||||||
|
name: "Имя переменной"
|
||||||
|
text: "Заголовок."
|
||||||
|
default: "Значение по умолчанию"
|
||||||
|
textareaInput: "Многострочный ввод текста"
|
||||||
|
_textareaInput:
|
||||||
|
name: "Имя переменной"
|
||||||
|
text: "Заголовок."
|
||||||
|
default: "Значение по умолчанию"
|
||||||
|
_numberInput:
|
||||||
|
name: "Имя переменной"
|
||||||
|
text: "Заголовок."
|
||||||
|
default: "Значение по умолчанию"
|
||||||
|
_switch:
|
||||||
|
name: "Имя переменной"
|
||||||
|
text: "Заголовок."
|
||||||
|
default: "Значение по умолчанию"
|
||||||
|
_counter:
|
||||||
|
name: "Имя переменной"
|
||||||
|
text: "Заголовок."
|
||||||
|
_button:
|
||||||
|
text: "Заголовок."
|
||||||
|
_action:
|
||||||
|
_dialog:
|
||||||
|
content: "Содержание"
|
||||||
|
_pushEvent:
|
||||||
|
no-variable: "Не найдено"
|
||||||
|
callAiScript: "Справка AiScript"
|
||||||
|
_callAiScript:
|
||||||
|
functionName: "Имя функции"
|
||||||
|
_radioButton:
|
||||||
|
name: "Имя переменной"
|
||||||
|
title: "Заголовок."
|
||||||
|
default: "Значение по умолчанию"
|
||||||
|
script:
|
||||||
|
categories:
|
||||||
|
list: "Списки"
|
||||||
|
blocks:
|
||||||
|
strLen: "Длина текста"
|
||||||
|
_strLen:
|
||||||
|
arg1: "Текст"
|
||||||
|
_strReplace:
|
||||||
|
arg1: "Текст"
|
||||||
|
_strReverse:
|
||||||
|
arg1: "Текст"
|
||||||
|
_join:
|
||||||
|
arg1: "Списки"
|
||||||
|
add: "Добавить"
|
||||||
|
_add:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_subtract:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_multiply:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_divide:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_mod:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_eq:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_notEq:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_and:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_or:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_lt:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_gt:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_ltEq:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_gtEq:
|
||||||
|
arg1: "А"
|
||||||
|
arg2: "Б"
|
||||||
|
_if:
|
||||||
|
arg1: "Если"
|
||||||
|
_rannum:
|
||||||
|
arg2: "Максимальное значение"
|
||||||
|
randomPick: "Случайный выбор из списка"
|
||||||
|
_randomPick:
|
||||||
|
arg1: "Списки"
|
||||||
|
_dailyRandom:
|
||||||
|
arg1: "Вероятность"
|
||||||
|
_dailyRannum:
|
||||||
|
arg2: "Максимальное значение"
|
||||||
|
_dailyRandomPick:
|
||||||
|
arg1: "Списки"
|
||||||
|
_seedRannum:
|
||||||
|
arg3: "Максимальное значение"
|
||||||
|
_seedRandomPick:
|
||||||
|
arg2: "Списки"
|
||||||
|
pick: "Выберите из списка"
|
||||||
|
_pick:
|
||||||
|
arg1: "Списки"
|
||||||
|
arg2: "Расположение"
|
||||||
|
_listLen:
|
||||||
|
arg1: "Списки"
|
||||||
|
number: "Номер"
|
||||||
|
_stringToNumber:
|
||||||
|
arg1: "Текст"
|
||||||
|
_numberToString:
|
||||||
|
arg1: "Номер"
|
||||||
|
ref: "Переменная"
|
||||||
|
aiScriptVar: "Переменная AiScript"
|
||||||
|
fn: "функции"
|
||||||
|
_fn:
|
||||||
|
slots: "Слоты"
|
||||||
|
_for:
|
||||||
|
arg1: "Количество повторений"
|
||||||
|
types:
|
||||||
|
array: "Списки"
|
||||||
|
_notification:
|
||||||
|
youWereFollowed: "Новый подписчик"
|
||||||
|
youReceivedFollowRequest: "Запрос на подписку"
|
||||||
|
youWereInvitedToGroup: "Приглашение в группу"
|
||||||
|
_types:
|
||||||
|
follow: "Подписки"
|
||||||
|
mention: "Упоминание"
|
||||||
|
renote: "Репост"
|
||||||
|
quote: "Цитата"
|
||||||
|
reaction: "Реакции"
|
||||||
|
app: "Уведомления из приложений"
|
||||||
_deck:
|
_deck:
|
||||||
|
alwaysShowMainColumn: "Всегда показывать главную колонку"
|
||||||
|
columnAlign: "Выравнивание колонн"
|
||||||
|
addColumn: "Добавить колонку"
|
||||||
|
swapLeft: "Переместить влево"
|
||||||
|
swapRight: "Переместить вправо"
|
||||||
|
swapUp: "Поднять вверх"
|
||||||
|
swapDown: "Переместить Вниз"
|
||||||
_columns:
|
_columns:
|
||||||
|
widgets: "Виджеты"
|
||||||
notifications: "Уведомления"
|
notifications: "Уведомления"
|
||||||
tl: "Лента"
|
tl: "Лента"
|
||||||
|
antenna: "Антенны"
|
||||||
|
list: "Списки"
|
||||||
|
mentions: "Упоминания"
|
||||||
|
@@ -16,6 +16,9 @@ noNotes: "没有帖文"
|
|||||||
noNotifications: "无通知"
|
noNotifications: "无通知"
|
||||||
instance: "实例"
|
instance: "实例"
|
||||||
settings: "设置"
|
settings: "设置"
|
||||||
|
basicSettings: "基本设置"
|
||||||
|
otherSettings: "其他设置"
|
||||||
|
openInWindow: "在新窗口中打开"
|
||||||
profile: "个人资料"
|
profile: "个人资料"
|
||||||
timeline: "时间线"
|
timeline: "时间线"
|
||||||
noAccountDescription: "这个人很懒,没有写自我介绍"
|
noAccountDescription: "这个人很懒,没有写自我介绍"
|
||||||
@@ -40,6 +43,7 @@ deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回
|
|||||||
addToList: "添加至列表"
|
addToList: "添加至列表"
|
||||||
sendMessage: "发送"
|
sendMessage: "发送"
|
||||||
copyUsername: "复制用户名"
|
copyUsername: "复制用户名"
|
||||||
|
searchUser: "搜索用户"
|
||||||
reply: "回复"
|
reply: "回复"
|
||||||
loadMore: "查看更多"
|
loadMore: "查看更多"
|
||||||
youGotNewFollower: "你有新的关注者"
|
youGotNewFollower: "你有新的关注者"
|
||||||
@@ -66,8 +70,11 @@ followers: "关注者"
|
|||||||
followsYou: "关注了你"
|
followsYou: "关注了你"
|
||||||
createList: "创建列表"
|
createList: "创建列表"
|
||||||
manageLists: "管理列表"
|
manageLists: "管理列表"
|
||||||
error: "有点小问题"
|
error: "错误"
|
||||||
|
somethingHappened: "出现了问题"
|
||||||
retry: "重试"
|
retry: "重试"
|
||||||
|
pageLoadError: "页面加载失败。"
|
||||||
|
pageLoadErrorDescription: "这通常是由于网络或浏览器缓存的原因。请清除缓存或等待片刻后重试。"
|
||||||
enterListName: "输入列表名称"
|
enterListName: "输入列表名称"
|
||||||
privacy: "隐私"
|
privacy: "隐私"
|
||||||
makeFollowManuallyApprove: "关注者请求需要批准"
|
makeFollowManuallyApprove: "关注者请求需要批准"
|
||||||
@@ -106,6 +113,8 @@ unsuspendConfirm: "要解除冻结吗?"
|
|||||||
selectList: "选择列表"
|
selectList: "选择列表"
|
||||||
selectAntenna: "天线选择"
|
selectAntenna: "天线选择"
|
||||||
selectWidget: "选择小工具"
|
selectWidget: "选择小工具"
|
||||||
|
editWidgets: "编辑小工具"
|
||||||
|
editWidgetsExit: "完成编辑"
|
||||||
customEmojis: "自定义Emoji"
|
customEmojis: "自定义Emoji"
|
||||||
emoji: "表情符号"
|
emoji: "表情符号"
|
||||||
emojiName: "Emoji 名称"
|
emojiName: "Emoji 名称"
|
||||||
@@ -177,7 +186,6 @@ processing: "处理中"
|
|||||||
preview: "预览"
|
preview: "预览"
|
||||||
default: "默认"
|
default: "默认"
|
||||||
noCustomEmojis: "无自定义Emoji"
|
noCustomEmojis: "无自定义Emoji"
|
||||||
customEmojisOfRemote: "远程Emoji"
|
|
||||||
noJobs: "没有任务"
|
noJobs: "没有任务"
|
||||||
federating: "联合中"
|
federating: "联合中"
|
||||||
blocked: "已拦截"
|
blocked: "已拦截"
|
||||||
@@ -286,7 +294,7 @@ dayX: "{day}日"
|
|||||||
monthX: "{month}月"
|
monthX: "{month}月"
|
||||||
yearX: "{year}年"
|
yearX: "{year}年"
|
||||||
pages: "页面"
|
pages: "页面"
|
||||||
integration: "连携"
|
integration: "关联"
|
||||||
connectSerice: "已连接"
|
connectSerice: "已连接"
|
||||||
disconnectSerice: "断开连接"
|
disconnectSerice: "断开连接"
|
||||||
enableLocalTimeline: "启用本地时间线功能"
|
enableLocalTimeline: "启用本地时间线功能"
|
||||||
@@ -445,7 +453,7 @@ total: "总计"
|
|||||||
weekOverWeekChanges: "与前一周相比"
|
weekOverWeekChanges: "与前一周相比"
|
||||||
dayOverDayChanges: "与前一日相比"
|
dayOverDayChanges: "与前一日相比"
|
||||||
appearance: "外观"
|
appearance: "外观"
|
||||||
clinetSettings: "客户端设置"
|
clientSettings: "客户端设置"
|
||||||
accountSettings: "账户设置"
|
accountSettings: "账户设置"
|
||||||
promotion: "推广"
|
promotion: "推广"
|
||||||
promote: "推广"
|
promote: "推广"
|
||||||
@@ -476,6 +484,8 @@ newNoteRecived: "有新的帖子"
|
|||||||
sounds: "声音"
|
sounds: "声音"
|
||||||
listen: "听"
|
listen: "听"
|
||||||
none: "空"
|
none: "空"
|
||||||
|
showInPage: "在页面中显示"
|
||||||
|
popout: "弹窗"
|
||||||
volume: "音量"
|
volume: "音量"
|
||||||
details: "详情"
|
details: "详情"
|
||||||
chooseEmoji: "选择表情符号"
|
chooseEmoji: "选择表情符号"
|
||||||
@@ -518,7 +528,6 @@ enableInfiniteScroll: "启用自动滚动页面模式"
|
|||||||
visibility: "可见性"
|
visibility: "可见性"
|
||||||
poll: "调查问卷"
|
poll: "调查问卷"
|
||||||
useCw: "隐藏内容"
|
useCw: "隐藏内容"
|
||||||
fixedWidgetsPosition: "固定小工具的位置"
|
|
||||||
enablePlayer: "打开播放器"
|
enablePlayer: "打开播放器"
|
||||||
disablePlayer: "关闭播放器"
|
disablePlayer: "关闭播放器"
|
||||||
expandTweet: "展开推文"
|
expandTweet: "展开推文"
|
||||||
@@ -566,6 +575,24 @@ delayed: "延迟"
|
|||||||
database: "数据库"
|
database: "数据库"
|
||||||
channel: "频道"
|
channel: "频道"
|
||||||
create: "创建"
|
create: "创建"
|
||||||
|
notificationSetting: "通知设置"
|
||||||
|
notificationSettingDesc: "选择要显示的通知类型。"
|
||||||
|
useGlobalSetting: "使用全局设置"
|
||||||
|
useGlobalSettingDesc: "启用时,将使用帐户通知设置。关闭时,则可以单独设置。"
|
||||||
|
other: "其他"
|
||||||
|
regenerateLoginToken: "重新生成登录令牌"
|
||||||
|
regenerateLoginTokenDescription: "重新生成用于登录的内部令牌。通常您不需要这样做。重新生成后,您将在所有设备上登出。"
|
||||||
|
setMultipleBySeparatingWithSpace: "您可以使用空格分隔多个项目。"
|
||||||
|
fileIdOrUrl: "文件ID或者URL"
|
||||||
|
chatOpenBehavior: "聊天窗口打开时的行为"
|
||||||
|
sample: "示例"
|
||||||
|
abuseReports: "举报"
|
||||||
|
reportAbuse: "举报"
|
||||||
|
reportAbuseOf: "举报{name}"
|
||||||
|
fillAbuseReportDescription: "请填写举报的详细原因。如果有对方发的帖子,请同时填写URL地址。"
|
||||||
|
abuseReported: "内容已发送。感谢您的报告。"
|
||||||
|
send: "发送"
|
||||||
|
abuseMarkAsResolved: "处理完毕"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "自动重载"
|
reload: "自动重载"
|
||||||
dialog: "对话框警告"
|
dialog: "对话框警告"
|
||||||
@@ -782,6 +809,7 @@ _widgets:
|
|||||||
photos: "照片"
|
photos: "照片"
|
||||||
digitalClock: "数字时钟"
|
digitalClock: "数字时钟"
|
||||||
federation: "联邦宇宙"
|
federation: "联邦宇宙"
|
||||||
|
postForm: "投稿窗口"
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隐藏"
|
hide: "隐藏"
|
||||||
show: "查看更多"
|
show: "查看更多"
|
||||||
@@ -1244,8 +1272,11 @@ _notification:
|
|||||||
renote: "转发"
|
renote: "转发"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "回应"
|
reaction: "回应"
|
||||||
pollVote: "投票"
|
pollVote: "问卷调查已投票"
|
||||||
receiveFollowRequest: "关注请求"
|
receiveFollowRequest: "收到关注请求"
|
||||||
|
followRequestAccepted: "关注请求已接受"
|
||||||
|
groupInvited: "加入群组邀请"
|
||||||
|
app: "关联应用的通知"
|
||||||
_deck:
|
_deck:
|
||||||
alwaysShowMainColumn: "总是显示主列"
|
alwaysShowMainColumn: "总是显示主列"
|
||||||
columnAlign: "列对齐"
|
columnAlign: "列对齐"
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
_lang_: "中文(繁體)"
|
_lang_: "繁體中文"
|
||||||
introMisskey: "歡迎! Misskey是一個開源的去中心化的社群網站。\n通過「貼文」來分享現在發生的事情吧! 📡\n「反應」功能,可以讓你快速的對大家的「帖子」來表達感情👍\n一起來探索新的世界吧! 🚀"
|
introMisskey: "歡迎! Misskey是一個開源的去中心化的社群網站。\n通過「貼文」來分享現在發生的事情吧! 📡\n「反應」功能,可以讓你快速的對大家的「帖子」來表達感情👍\n一起來探索新的世界吧! 🚀"
|
||||||
monthAndDay: "{month}月 {day}日"
|
monthAndDay: "{month}月 {day}日"
|
||||||
search: "搜尋"
|
search: "搜尋"
|
||||||
@@ -11,11 +11,14 @@ ok: "確定"
|
|||||||
gotIt: "知道了"
|
gotIt: "知道了"
|
||||||
cancel: "取消"
|
cancel: "取消"
|
||||||
enterUsername: "輸入使用者名稱"
|
enterUsername: "輸入使用者名稱"
|
||||||
renotedBy: "由{user}轉發"
|
renotedBy: "{user} 轉發了"
|
||||||
noNotes: "貼文不可用。"
|
noNotes: "貼文不可用。"
|
||||||
noNotifications: "沒有通知"
|
noNotifications: "沒有通知"
|
||||||
instance: "實例"
|
instance: "實例"
|
||||||
settings: "設定"
|
settings: "設定"
|
||||||
|
basicSettings: "基本設定"
|
||||||
|
otherSettings: "其他設定"
|
||||||
|
openInWindow: "在新視窗開啟"
|
||||||
profile: "個人檔案"
|
profile: "個人檔案"
|
||||||
timeline: "時間軸"
|
timeline: "時間軸"
|
||||||
noAccountDescription: "此用戶還沒有自我介紹"
|
noAccountDescription: "此用戶還沒有自我介紹"
|
||||||
@@ -40,6 +43,7 @@ deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有反應,
|
|||||||
addToList: "添加至清單"
|
addToList: "添加至清單"
|
||||||
sendMessage: "發送訊息"
|
sendMessage: "發送訊息"
|
||||||
copyUsername: "複製用戶名"
|
copyUsername: "複製用戶名"
|
||||||
|
searchUser: "搜尋用戶"
|
||||||
reply: "回覆"
|
reply: "回覆"
|
||||||
loadMore: "瀏覽更多"
|
loadMore: "瀏覽更多"
|
||||||
youGotNewFollower: "您有新的追隨者"
|
youGotNewFollower: "您有新的追隨者"
|
||||||
@@ -66,8 +70,10 @@ followers: "追隨者"
|
|||||||
followsYou: "追隨你的人"
|
followsYou: "追隨你的人"
|
||||||
createList: "建立清單"
|
createList: "建立清單"
|
||||||
manageLists: "管理清單"
|
manageLists: "管理清單"
|
||||||
error: "發生錯誤"
|
error: "錯誤"
|
||||||
|
somethingHappened: "發生錯誤"
|
||||||
retry: "重試"
|
retry: "重試"
|
||||||
|
pageLoadError: "載入頁面失敗"
|
||||||
enterListName: "輸入清單名稱"
|
enterListName: "輸入清單名稱"
|
||||||
privacy: "隱私"
|
privacy: "隱私"
|
||||||
makeFollowManuallyApprove: "手動審核追隨請求"
|
makeFollowManuallyApprove: "手動審核追隨請求"
|
||||||
@@ -106,13 +112,15 @@ unsuspendConfirm: "確定解凍此帳號?"
|
|||||||
selectList: "選擇清單"
|
selectList: "選擇清單"
|
||||||
selectAntenna: "選擇天線"
|
selectAntenna: "選擇天線"
|
||||||
selectWidget: "選擇小工具"
|
selectWidget: "選擇小工具"
|
||||||
|
editWidgets: "編輯小工具"
|
||||||
|
editWidgetsExit: "停止編輯"
|
||||||
customEmojis: "自訂表情符號"
|
customEmojis: "自訂表情符號"
|
||||||
emoji: "表情符號"
|
emoji: "表情符號"
|
||||||
emojiName: "表情符號名稱"
|
emojiName: "表情符號名稱"
|
||||||
emojiUrl: "表情符號URL"
|
emojiUrl: "表情符號URL"
|
||||||
addEmoji: "新增表情符號"
|
addEmoji: "新增表情符號"
|
||||||
settingGuide: "推薦設定"
|
settingGuide: "推薦設定"
|
||||||
cacheRemoteFiles: "遠程文件緩存"
|
cacheRemoteFiles: "緩存非遠程檔案"
|
||||||
cacheRemoteFilesDescription: "如果禁用此設定,遠程文件將會被直接連結而非緩存。禁用將節省服務器上的存儲空間,但會因為沒有生成預覽圖而增加流量。"
|
cacheRemoteFilesDescription: "如果禁用此設定,遠程文件將會被直接連結而非緩存。禁用將節省服務器上的存儲空間,但會因為沒有生成預覽圖而增加流量。"
|
||||||
flagAsBot: "此帳戶是Bot"
|
flagAsBot: "此帳戶是Bot"
|
||||||
flagAsCat: "此帳戶是Cat"
|
flagAsCat: "此帳戶是Cat"
|
||||||
@@ -176,7 +184,6 @@ processing: "處理中"
|
|||||||
preview: "預覽"
|
preview: "預覽"
|
||||||
default: "預設"
|
default: "預設"
|
||||||
noCustomEmojis: "沒有表情符號"
|
noCustomEmojis: "沒有表情符號"
|
||||||
customEmojisOfRemote: "來自其他實例的表情符號"
|
|
||||||
noJobs: "沒有任務"
|
noJobs: "沒有任務"
|
||||||
federating: "整合搜索中"
|
federating: "整合搜索中"
|
||||||
blocked: "已封鎖"
|
blocked: "已封鎖"
|
||||||
@@ -223,7 +230,7 @@ nUsersRead: "{n}人已讀"
|
|||||||
tos: "使用條款"
|
tos: "使用條款"
|
||||||
start: "開始"
|
start: "開始"
|
||||||
home: "首頁"
|
home: "首頁"
|
||||||
remoteUserCaution: "由於是遠程用戶,信息不完整。"
|
remoteUserCaution: "由於該用戶來自遠端實例,因此資料用戶並未即時更新。"
|
||||||
activity: "動態"
|
activity: "動態"
|
||||||
images: "圖片"
|
images: "圖片"
|
||||||
birthday: "生日"
|
birthday: "生日"
|
||||||
@@ -293,7 +300,7 @@ disablingTimelinesInfo: "即使您禁用了時間線功能,管理員和協調
|
|||||||
registration: "註冊"
|
registration: "註冊"
|
||||||
enableRegistration: "開啟新用戶註冊"
|
enableRegistration: "開啟新用戶註冊"
|
||||||
invite: "邀請"
|
invite: "邀請"
|
||||||
proxyRemoteFiles: "代理遠程檔案"
|
proxyRemoteFiles: "遠端代理檔案"
|
||||||
proxyRemoteFilesDescription: "啟用此設置後,由於超出存儲容量而未保存或刪除的遠程文件將被本地代理,並且將生成預覽圖。這不影響服務器的存儲。"
|
proxyRemoteFilesDescription: "啟用此設置後,由於超出存儲容量而未保存或刪除的遠程文件將被本地代理,並且將生成預覽圖。這不影響服務器的存儲。"
|
||||||
driveCapacityPerLocalAccount: "每個本地用戶的雲端容量"
|
driveCapacityPerLocalAccount: "每個本地用戶的雲端容量"
|
||||||
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量"
|
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量"
|
||||||
@@ -316,7 +323,7 @@ antennas: "天線"
|
|||||||
manageAntennas: "管理天線"
|
manageAntennas: "管理天線"
|
||||||
name: "名稱"
|
name: "名稱"
|
||||||
antennaSource: "接收來源"
|
antennaSource: "接收來源"
|
||||||
antennaKeywords: "包含的關鍵字"
|
antennaKeywords: "包含關鍵字"
|
||||||
antennaExcludeKeywords: "排除關鍵字"
|
antennaExcludeKeywords: "排除關鍵字"
|
||||||
antennaKeywordsDescription: "用空格分隔指定AND、用換行符分隔指定OR"
|
antennaKeywordsDescription: "用空格分隔指定AND、用換行符分隔指定OR"
|
||||||
notifyAntenna: "通知我有新的貼文"
|
notifyAntenna: "通知我有新的貼文"
|
||||||
@@ -430,12 +437,23 @@ category: "類別"
|
|||||||
tags: "標籤"
|
tags: "標籤"
|
||||||
docSource: "文件來源"
|
docSource: "文件來源"
|
||||||
createAccount: "建立帳戶"
|
createAccount: "建立帳戶"
|
||||||
|
existingAcount: "現有帳戶"
|
||||||
|
regenerate: "再生"
|
||||||
fontSize: "字體大小"
|
fontSize: "字體大小"
|
||||||
|
openImageInNewTab: "於新分頁中開啟圖片"
|
||||||
|
local: "本地"
|
||||||
|
remote: "遠端"
|
||||||
total: "合計"
|
total: "合計"
|
||||||
clinetSettings: "用戶端設定"
|
appearance: "外觀"
|
||||||
|
accountSettings: "帳戶設置"
|
||||||
|
objectStoragePrefix: "前綴"
|
||||||
|
objectStorageUseSSL: "使用SSL"
|
||||||
|
objectStorageUseProxy: "使用網路代理"
|
||||||
serverLogs: "伺服器日誌"
|
serverLogs: "伺服器日誌"
|
||||||
deleteAll: "刪除所有記錄"
|
deleteAll: "刪除所有記錄"
|
||||||
|
sounds: "音效"
|
||||||
none: "無"
|
none: "無"
|
||||||
|
showInPage: "在頁面中顯示"
|
||||||
volume: "音量"
|
volume: "音量"
|
||||||
details: "詳細資訊"
|
details: "詳細資訊"
|
||||||
chooseEmoji: "選擇您的表情符號\n"
|
chooseEmoji: "選擇您的表情符號\n"
|
||||||
@@ -443,14 +461,21 @@ unableToProcess: "操作無法完成"
|
|||||||
recentUsed: "最近使用"
|
recentUsed: "最近使用"
|
||||||
install: "安裝"
|
install: "安裝"
|
||||||
uninstall: "解除安裝"
|
uninstall: "解除安裝"
|
||||||
|
installedApps: "已授權的應用程式"
|
||||||
|
nothing: "未發現"
|
||||||
|
installedDate: "安裝時間"
|
||||||
lastUsedDate: "最後上線日期"
|
lastUsedDate: "最後上線日期"
|
||||||
state: "狀態"
|
state: "狀態"
|
||||||
|
sort: "排序"
|
||||||
ascendingOrder: "昇冪"
|
ascendingOrder: "昇冪"
|
||||||
descendingOrder: "降冪"
|
descendingOrder: "降冪"
|
||||||
scratchpad: "暫存記憶體"
|
scratchpad: "暫存記憶體"
|
||||||
output: "輸出"
|
output: "輸出"
|
||||||
|
script: "腳本"
|
||||||
|
updateRemoteUser: "更新非本地用戶資料"
|
||||||
deleteAllFiles: "刪除所有檔案"
|
deleteAllFiles: "刪除所有檔案"
|
||||||
deleteAllFilesConfirm: "要删除所有檔案吗?"
|
deleteAllFilesConfirm: "要删除所有檔案吗?"
|
||||||
|
removeAllFollowing: "解除所有追隨"
|
||||||
userSuspended: "該用戶已被凍結"
|
userSuspended: "該用戶已被凍結"
|
||||||
userSilenced: "該用戶已被禁言。"
|
userSilenced: "該用戶已被禁言。"
|
||||||
sidebar: "側邊列"
|
sidebar: "側邊列"
|
||||||
@@ -468,7 +493,6 @@ enableInfiniteScroll: "啟用自動滾動頁面模式"
|
|||||||
visibility: "公開範圍"
|
visibility: "公開範圍"
|
||||||
poll: "投票"
|
poll: "投票"
|
||||||
useCw: "隱藏內容"
|
useCw: "隱藏內容"
|
||||||
fixedWidgetsPosition: "固定小工具的位置"
|
|
||||||
enablePlayer: "打開播放器"
|
enablePlayer: "打開播放器"
|
||||||
disablePlayer: "關閉播放器"
|
disablePlayer: "關閉播放器"
|
||||||
expandTweet: "展開推文"
|
expandTweet: "展開推文"
|
||||||
@@ -497,8 +521,15 @@ smtpHost: "主機"
|
|||||||
smtpPort: "端口"
|
smtpPort: "端口"
|
||||||
smtpUser: "使用名稱"
|
smtpUser: "使用名稱"
|
||||||
smtpPass: "密碼"
|
smtpPass: "密碼"
|
||||||
|
display: "檢視"
|
||||||
|
copy: "複製"
|
||||||
|
metrics: "指標"
|
||||||
|
logs: "日誌"
|
||||||
|
delayed: "延遲"
|
||||||
|
database: "資料庫"
|
||||||
channel: "頻道"
|
channel: "頻道"
|
||||||
create: "新增"
|
create: "新增"
|
||||||
|
notificationSetting: "管理通知"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "自動重載"
|
reload: "自動重載"
|
||||||
dialog: "以對話框警告"
|
dialog: "以對話框警告"
|
||||||
@@ -515,12 +546,19 @@ _channel:
|
|||||||
notesCount: "有{n}個帖子"
|
notesCount: "有{n}個帖子"
|
||||||
_sidebar:
|
_sidebar:
|
||||||
icon: "頭像"
|
icon: "頭像"
|
||||||
|
hide: "隱藏"
|
||||||
|
_wordMute:
|
||||||
|
muteWords: "加入靜音文字"
|
||||||
_theme:
|
_theme:
|
||||||
|
color: "顏色"
|
||||||
func: "函数"
|
func: "函数"
|
||||||
keys:
|
keys:
|
||||||
|
bg: "背景"
|
||||||
mention: "提及"
|
mention: "提及"
|
||||||
renote: "轉發貼文"
|
renote: "轉發貼文"
|
||||||
divider: "分割線"
|
divider: "分割線"
|
||||||
|
infoBg: "資訊背景"
|
||||||
|
infoFg: "資訊內容"
|
||||||
_sfx:
|
_sfx:
|
||||||
note: "貼文"
|
note: "貼文"
|
||||||
noteMy: "我的貼文"
|
noteMy: "我的貼文"
|
||||||
@@ -579,6 +617,8 @@ _permissions:
|
|||||||
"write:votes": "投票"
|
"write:votes": "投票"
|
||||||
"read:channels": "已查看的頻道"
|
"read:channels": "已查看的頻道"
|
||||||
"write:channels": "操作頻道"
|
"write:channels": "操作頻道"
|
||||||
|
_antennaSources:
|
||||||
|
all: "全部貼文"
|
||||||
_weekday:
|
_weekday:
|
||||||
sunday: "週日"
|
sunday: "週日"
|
||||||
monday: "週一"
|
monday: "週一"
|
||||||
@@ -588,33 +628,53 @@ _weekday:
|
|||||||
friday: "週五"
|
friday: "週五"
|
||||||
saturday: "週六"
|
saturday: "週六"
|
||||||
_widgets:
|
_widgets:
|
||||||
|
memo: "備忘錄"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
timeline: "時間軸"
|
timeline: "時間軸"
|
||||||
|
calendar: "行事曆"
|
||||||
|
trends: "發燒貼文"
|
||||||
clock: "時鐘"
|
clock: "時鐘"
|
||||||
rss: "RSS閱讀器"
|
rss: "RSS閱讀器"
|
||||||
activity: "動態"
|
activity: "動態"
|
||||||
photos: "照片"
|
photos: "照片"
|
||||||
|
digitalClock: "電子時鐘"
|
||||||
federation: "聯邦宇宙"
|
federation: "聯邦宇宙"
|
||||||
_cw:
|
_cw:
|
||||||
|
hide: "隱藏"
|
||||||
show: "瀏覽更多"
|
show: "瀏覽更多"
|
||||||
|
chars: "{count}字元"
|
||||||
files: "{count} 個檔案"
|
files: "{count} 個檔案"
|
||||||
_poll:
|
_poll:
|
||||||
|
noOnlyOneChoice: "至少需要兩個選項。"
|
||||||
|
expiration: "期限"
|
||||||
|
infinite: "無期限"
|
||||||
|
deadlineDate: "截止日期"
|
||||||
deadlineTime: "小時"
|
deadlineTime: "小時"
|
||||||
|
votesCount: "{n}票"
|
||||||
|
totalVotes: "一共{n}票"
|
||||||
vote: "投票"
|
vote: "投票"
|
||||||
|
showResult: "顯示結果"
|
||||||
voted: "已投票"
|
voted: "已投票"
|
||||||
|
closed: "已結束"
|
||||||
_visibility:
|
_visibility:
|
||||||
home: "首頁"
|
home: "首頁"
|
||||||
followers: "追隨者"
|
followers: "追隨者"
|
||||||
|
localOnly: "僅限本地"
|
||||||
_postForm:
|
_postForm:
|
||||||
channelPlaceholder: "發佈到頻道"
|
channelPlaceholder: "發佈到頻道"
|
||||||
_profile:
|
_profile:
|
||||||
name: "名稱"
|
name: "名稱"
|
||||||
username: "使用名稱"
|
username: "使用名稱"
|
||||||
|
metadataLabel: "標籤"
|
||||||
|
metadataContent: "内容"
|
||||||
_exportOrImport:
|
_exportOrImport:
|
||||||
|
allNotes: "全部貼文"
|
||||||
followingList: "追隨中"
|
followingList: "追隨中"
|
||||||
muteList: "消音"
|
muteList: "消音"
|
||||||
blockingList: "封鎖"
|
blockingList: "封鎖"
|
||||||
userLists: "清單"
|
userLists: "清單"
|
||||||
|
_charts:
|
||||||
|
remoteNotesIncDec: "非本地貼文的數目增减"
|
||||||
_instanceCharts:
|
_instanceCharts:
|
||||||
cacheSize: "增加或減少快取用量"
|
cacheSize: "增加或減少快取用量"
|
||||||
cacheSizeTotal: "快取大小總計"
|
cacheSizeTotal: "快取大小總計"
|
||||||
@@ -632,6 +692,8 @@ _pages:
|
|||||||
unlike: "收回喜歡"
|
unlike: "收回喜歡"
|
||||||
blocks:
|
blocks:
|
||||||
image: "圖片"
|
image: "圖片"
|
||||||
|
_post:
|
||||||
|
text: "内容"
|
||||||
_textareaInput:
|
_textareaInput:
|
||||||
name: "變數名稱"
|
name: "變數名稱"
|
||||||
numberInput: "輸入數值"
|
numberInput: "輸入數值"
|
||||||
@@ -643,6 +705,9 @@ _pages:
|
|||||||
text: "標題"
|
text: "標題"
|
||||||
_button:
|
_button:
|
||||||
text: "標題"
|
text: "標題"
|
||||||
|
_action:
|
||||||
|
_dialog:
|
||||||
|
content: "内容"
|
||||||
script:
|
script:
|
||||||
categories:
|
categories:
|
||||||
value: "數值 "
|
value: "數值 "
|
||||||
@@ -782,6 +847,7 @@ _relayStatus:
|
|||||||
accepted: "已通過核准"
|
accepted: "已通過核准"
|
||||||
rejected: "已拒絕"
|
rejected: "已拒絕"
|
||||||
_notification:
|
_notification:
|
||||||
|
youRenoted: "{name} 轉發了你的貼文"
|
||||||
youGotPoll: "{name}已投票"
|
youGotPoll: "{name}已投票"
|
||||||
youWereFollowed: "您有新的追隨者"
|
youWereFollowed: "您有新的追隨者"
|
||||||
yourFollowRequestAccepted: "您的追隨請求已通過"
|
yourFollowRequestAccepted: "您的追隨請求已通過"
|
||||||
|
32
migration/1603094348345-refine-abuse-user-report.ts
Normal file
32
migration/1603094348345-refine-abuse-user-report.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class refineAbuseUserReport1603094348345 implements MigrationInterface {
|
||||||
|
name = 'refineAbuseUserReport1603094348345'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_d049123c413e68ca52abe734203"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_d049123c413e68ca52abe73420"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_5cd442c3b2e74fdd99dae20243"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" RENAME COLUMN "userId" TO "targetUserId"`);
|
||||||
|
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" DROP COLUMN "comment"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "comment" character varying(2048) NOT NULL`);
|
||||||
|
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`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP CONSTRAINT "FK_08b883dd5fdd6f9c4c1572b36de"`);
|
||||||
|
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" ADD "comment" character varying(512) NOT NULL`);
|
||||||
|
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" RENAME COLUMN "targetUserId" TO "userId"`);
|
||||||
|
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_5cd442c3b2e74fdd99dae20243" ON "abuse_user_report" ("userId", "reporterId") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_d049123c413e68ca52abe73420" ON "abuse_user_report" ("userId") `);
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD CONSTRAINT "FK_d049123c413e68ca52abe734203" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
20
migration/1603095701770-refine-abuse-user-report2.ts
Normal file
20
migration/1603095701770-refine-abuse-user-report2.ts
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import {MigrationInterface, QueryRunner} from "typeorm";
|
||||||
|
|
||||||
|
export class refineAbuseUserReport21603095701770 implements MigrationInterface {
|
||||||
|
name = 'refineAbuseUserReport21603095701770'
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "targetUserHost" character varying(128)`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" ADD "reporterHost" character varying(128)`);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_4ebbf7f93cdc10e8d1ef2fc6cd" ON "abuse_user_report" ("targetUserHost") `);
|
||||||
|
await queryRunner.query(`CREATE INDEX "IDX_f8d8b93740ad12c4ce8213a199" ON "abuse_user_report" ("reporterHost") `);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_f8d8b93740ad12c4ce8213a199"`);
|
||||||
|
await queryRunner.query(`DROP INDEX "IDX_4ebbf7f93cdc10e8d1ef2fc6cd"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "reporterHost"`);
|
||||||
|
await queryRunner.query(`ALTER TABLE "abuse_user_report" DROP COLUMN "targetUserHost"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
51
package.json
51
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
"author": "syuilo <syuilotan@yahoo.co.jp>",
|
||||||
"version": "12.48.0",
|
"version": "12.49.1",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -46,7 +46,7 @@
|
|||||||
"@koa/multer": "3.0.0",
|
"@koa/multer": "3.0.0",
|
||||||
"@koa/router": "9.0.1",
|
"@koa/router": "9.0.1",
|
||||||
"@sinonjs/fake-timers": "6.0.1",
|
"@sinonjs/fake-timers": "6.0.1",
|
||||||
"@syuilo/aiscript": "0.11.0",
|
"@syuilo/aiscript": "0.11.1",
|
||||||
"@types/bcryptjs": "2.4.2",
|
"@types/bcryptjs": "2.4.2",
|
||||||
"@types/bull": "3.14.0",
|
"@types/bull": "3.14.0",
|
||||||
"@types/cbor": "5.0.1",
|
"@types/cbor": "5.0.1",
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
"@types/request-stats": "3.0.0",
|
"@types/request-stats": "3.0.0",
|
||||||
"@types/rimraf": "3.0.0",
|
"@types/rimraf": "3.0.0",
|
||||||
"@types/seedrandom": "2.4.28",
|
"@types/seedrandom": "2.4.28",
|
||||||
"@types/sharp": "0.25.0",
|
"@types/sharp": "0.26.0",
|
||||||
"@types/sinonjs__fake-timers": "6.0.1",
|
"@types/sinonjs__fake-timers": "6.0.1",
|
||||||
"@types/speakeasy": "2.0.5",
|
"@types/speakeasy": "2.0.5",
|
||||||
"@types/tinycolor2": "1.4.2",
|
"@types/tinycolor2": "1.4.2",
|
||||||
@@ -104,7 +104,7 @@
|
|||||||
"@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.4.0",
|
||||||
"@vue/compiler-sfc": "3.0.0",
|
"@vue/compiler-sfc": "3.0.2",
|
||||||
"abort-controller": "3.0.0",
|
"abort-controller": "3.0.0",
|
||||||
"apexcharts": "3.22.0",
|
"apexcharts": "3.22.0",
|
||||||
"autobind-decorator": "2.4.0",
|
"autobind-decorator": "2.4.0",
|
||||||
@@ -123,21 +123,22 @@
|
|||||||
"content-disposition": "0.5.3",
|
"content-disposition": "0.5.3",
|
||||||
"core-js": "3.6.5",
|
"core-js": "3.6.5",
|
||||||
"crc-32": "1.2.0",
|
"crc-32": "1.2.0",
|
||||||
"css-loader": "4.3.0",
|
"css-loader": "5.0.0",
|
||||||
"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.10.0",
|
"eslint": "7.11.0",
|
||||||
"eslint-plugin-vue": "7.0.1",
|
"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": "15.0.1",
|
"file-type": "16.0.0",
|
||||||
"fluent-ffmpeg": "2.1.2",
|
"fluent-ffmpeg": "2.1.2",
|
||||||
"glob": "7.1.6",
|
"glob": "7.1.6",
|
||||||
|
"got": "11.7.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",
|
||||||
@@ -158,8 +159,8 @@
|
|||||||
"js-yaml": "3.14.0",
|
"js-yaml": "3.14.0",
|
||||||
"jsdom": "16.4.0",
|
"jsdom": "16.4.0",
|
||||||
"json5": "2.1.3",
|
"json5": "2.1.3",
|
||||||
"json5-loader": "4.0.0",
|
"json5-loader": "4.0.1",
|
||||||
"jsonld": "3.1.1",
|
"jsonld": "3.2.0",
|
||||||
"jsrsasign": "8.0.20",
|
"jsrsasign": "8.0.20",
|
||||||
"katex": "0.12.0",
|
"katex": "0.12.0",
|
||||||
"koa": "2.13.0",
|
"koa": "2.13.0",
|
||||||
@@ -189,9 +190,9 @@
|
|||||||
"parsimmon": "1.16.0",
|
"parsimmon": "1.16.0",
|
||||||
"pg": "8.4.1",
|
"pg": "8.4.1",
|
||||||
"portscanner": "2.2.0",
|
"portscanner": "2.2.0",
|
||||||
"postcss": "8.1.1",
|
"postcss": "8.1.2",
|
||||||
"postcss-loader": "4.0.3",
|
"postcss-loader": "4.0.4",
|
||||||
"prismjs": "1.21.0",
|
"prismjs": "1.22.0",
|
||||||
"probe-image-size": "5.0.0",
|
"probe-image-size": "5.0.0",
|
||||||
"promise-limit": "2.7.0",
|
"promise-limit": "2.7.0",
|
||||||
"promise-sequential": "1.1.1",
|
"promise-sequential": "1.1.1",
|
||||||
@@ -201,8 +202,8 @@
|
|||||||
"qrcode": "1.4.4",
|
"qrcode": "1.4.4",
|
||||||
"random-seed": "0.3.0",
|
"random-seed": "0.3.0",
|
||||||
"ratelimiter": "3.4.1",
|
"ratelimiter": "3.4.1",
|
||||||
"re2": "1.15.5",
|
"re2": "1.15.8",
|
||||||
"recaptcha-promise": "0.1.3",
|
"recaptcha-promise": "1.0.0",
|
||||||
"reconnecting-websocket": "4.4.0",
|
"reconnecting-websocket": "4.4.0",
|
||||||
"redis": "3.0.2",
|
"redis": "3.0.2",
|
||||||
"redis-lock": "0.1.4",
|
"redis-lock": "0.1.4",
|
||||||
@@ -215,12 +216,12 @@
|
|||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sass": "1.27.0",
|
"sass": "1.27.0",
|
||||||
"sass-loader": "10.0.2",
|
"sass-loader": "10.0.3",
|
||||||
"seedrandom": "3.0.5",
|
"seedrandom": "3.0.5",
|
||||||
"sharp": "0.26.1",
|
"sharp": "0.26.2",
|
||||||
"speakeasy": "2.0.0",
|
"speakeasy": "2.0.0",
|
||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"style-loader": "1.3.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.27.8",
|
||||||
@@ -229,33 +230,31 @@
|
|||||||
"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.4",
|
"ts-loader": "8.0.6",
|
||||||
"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.28",
|
||||||
"typescript": "4.0.3",
|
"typescript": "4.0.3",
|
||||||
"ulid": "2.3.0",
|
"ulid": "2.3.0",
|
||||||
"url-loader": "4.1.0",
|
"url-loader": "4.1.1",
|
||||||
"uuid": "8.3.1",
|
"uuid": "8.3.1",
|
||||||
"v-debounce": "0.1.2",
|
"v-debounce": "0.1.2",
|
||||||
"vue": "3.0.1",
|
"vue": "3.0.2",
|
||||||
"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.4",
|
"vue-i18n": "9.0.0-beta.6",
|
||||||
"vue-json-pretty": "1.7.0",
|
"vue-json-pretty": "1.7.0",
|
||||||
"vue-loader": "16.0.0-beta.7",
|
"vue-loader": "16.0.0-beta.8",
|
||||||
"vue-prism-component": "1.2.0",
|
|
||||||
"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",
|
||||||
"vue-style-loader": "4.1.2",
|
"vue-style-loader": "4.1.2",
|
||||||
"vue-svg-inline-loader-corejs3": "1.5.0",
|
|
||||||
"vue-template-compiler": "2.6.12",
|
"vue-template-compiler": "2.6.12",
|
||||||
"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.1.3",
|
||||||
"webpack-cli": "3.3.12",
|
"webpack-cli": "4.1.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"
|
||||||
|
3
src/client/@types/vuex-shim.d.ts
vendored
3
src/client/@types/vuex-shim.d.ts
vendored
@@ -2,10 +2,11 @@ import { ComponentCustomProperties } from 'vue';
|
|||||||
import { Store } from 'vuex';
|
import { Store } from 'vuex';
|
||||||
|
|
||||||
declare module '@vue/runtime-core' {
|
declare module '@vue/runtime-core' {
|
||||||
|
// tslint:disable-next-line:no-empty-interface
|
||||||
interface State {
|
interface State {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ComponentCustomProperties {
|
interface ComponentCustomProperties {
|
||||||
$store: Store<State>
|
$store: Store<State>;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
85
src/client/components/abuse-report-window.vue
Normal file
85
src/client/components/abuse-report-window.vue
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="$emit('closed')">
|
||||||
|
<template #header>
|
||||||
|
<Fa :icon="faExclamationCircle" style="margin-right: 0.5em;"/>
|
||||||
|
<i18n-t keypath="reportAbuseOf" tag="span">
|
||||||
|
<template #name>
|
||||||
|
<b><MkAcct :user="user"/></b>
|
||||||
|
</template>
|
||||||
|
</i18n-t>
|
||||||
|
</template>
|
||||||
|
<div class="dpvffvvy">
|
||||||
|
<div class="_section">
|
||||||
|
<div class="_content">
|
||||||
|
<MkTextarea v-model:value="comment">
|
||||||
|
<span>{{ $t('details') }}</span>
|
||||||
|
<template #desc>{{ $t('fillAbuseReportDescription') }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="_section">
|
||||||
|
<div class="_content">
|
||||||
|
<MkButton @click="send" primary full :disabled="comment.length === 0">{{ $t('send') }}</MkButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</XWindow>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, markRaw } from 'vue';
|
||||||
|
import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import XWindow from '@/components/ui/window.vue';
|
||||||
|
import MkTextarea from '@/components/ui/textarea.vue';
|
||||||
|
import MkButton from '@/components/ui/button.vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XWindow,
|
||||||
|
MkTextarea,
|
||||||
|
MkButton,
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
user: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
initialComment: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
emits: ['closed'],
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
comment: this.initialComment || '',
|
||||||
|
faExclamationCircle,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
send() {
|
||||||
|
os.apiWithDialog('users/report-abuse', {
|
||||||
|
userId: this.user.id,
|
||||||
|
comment: this.comment,
|
||||||
|
}, undefined, res => {
|
||||||
|
os.dialog({
|
||||||
|
type: 'success',
|
||||||
|
text: this.$t('abuseReported')
|
||||||
|
});
|
||||||
|
this.$refs.window.close();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.dpvffvvy {
|
||||||
|
--section-padding: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,17 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<XPrism :inline="inline" :language="prismLang">{{ code }}</XPrism>
|
<code v-if="inline" v-html="html" :class="`language-${prismLang}`"></code>
|
||||||
|
<pre v-else :class="`language-${prismLang}`"><code v-html="html" :class="`language-${prismLang}`"></code></pre>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import 'prismjs';
|
import 'prismjs';
|
||||||
import 'prismjs/themes/prism-okaidia.css';
|
import 'prismjs/themes/prism-okaidia.css';
|
||||||
import XPrism from 'vue-prism-component';import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
|
||||||
XPrism
|
|
||||||
},
|
|
||||||
props: {
|
props: {
|
||||||
code: {
|
code: {
|
||||||
type: String,
|
type: String,
|
||||||
@@ -29,6 +26,9 @@ export default defineComponent({
|
|||||||
computed: {
|
computed: {
|
||||||
prismLang() {
|
prismLang() {
|
||||||
return Prism.languages[this.lang] ? this.lang : 'js';
|
return Prism.languages[this.lang] ? this.lang : 'js';
|
||||||
|
},
|
||||||
|
html() {
|
||||||
|
return Prism.highlight(this.code, Prism.languages[this.prismLang], this.prismLang);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@@ -344,6 +344,7 @@ export default defineComponent({
|
|||||||
display: flex;
|
display: flex;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
line-height: $header-height;
|
line-height: $header-height;
|
||||||
|
height: $header-height;
|
||||||
padding: 0 16px;
|
padding: 0 16px;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
color: var(--panelHeaderFg);
|
color: var(--panelHeaderFg);
|
||||||
|
@@ -1,102 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="eqryymyo">
|
|
||||||
<div class="header">
|
|
||||||
<time ref="time" class="_ghost">
|
|
||||||
<span class="yyyymmdd">{{ yyyy }}/{{ mm }}/{{ dd }}</span>
|
|
||||||
<br>
|
|
||||||
<span class="hhnn">{{ hh }}<span :style="{ visibility: now.getSeconds() % 2 == 0 ? 'visible' : 'hidden' }">:</span>{{ nn }}</span>
|
|
||||||
</time>
|
|
||||||
</div>
|
|
||||||
<div class="content _panel _ghost">
|
|
||||||
<MkClock/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
import { defineComponent } from 'vue';
|
|
||||||
import MkClock from './analog-clock.vue';
|
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
|
||||||
components: {
|
|
||||||
MkClock
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
now: new Date(),
|
|
||||||
clock: null
|
|
||||||
};
|
|
||||||
},
|
|
||||||
computed: {
|
|
||||||
yyyy(): number {
|
|
||||||
return this.now.getFullYear();
|
|
||||||
},
|
|
||||||
mm(): string {
|
|
||||||
return ('0' + (this.now.getMonth() + 1)).slice(-2);
|
|
||||||
},
|
|
||||||
dd(): string {
|
|
||||||
return ('0' + this.now.getDate()).slice(-2);
|
|
||||||
},
|
|
||||||
hh(): string {
|
|
||||||
return ('0' + this.now.getHours()).slice(-2);
|
|
||||||
},
|
|
||||||
nn(): string {
|
|
||||||
return ('0' + this.now.getMinutes()).slice(-2);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.tick();
|
|
||||||
this.clock = setInterval(this.tick, 1000);
|
|
||||||
},
|
|
||||||
beforeUnmount() {
|
|
||||||
clearInterval(this.clock);
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
tick() {
|
|
||||||
this.now = new Date();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.eqryymyo {
|
|
||||||
display: inline-block;
|
|
||||||
overflow: visible;
|
|
||||||
|
|
||||||
> .header {
|
|
||||||
padding: 0 12px;
|
|
||||||
padding-top: 4px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
font-family: Lucida Console, Courier, monospace;
|
|
||||||
|
|
||||||
&:hover + .content {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
> time {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
height: 48px;
|
|
||||||
|
|
||||||
> .yyyymmdd {
|
|
||||||
opacity: 0.7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .content {
|
|
||||||
opacity: 0;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: auto;
|
|
||||||
right: 0;
|
|
||||||
margin: 16px 0 0 0;
|
|
||||||
padding: 16px;
|
|
||||||
width: 230px;
|
|
||||||
transition: opacity 0.2s ease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
@@ -6,7 +6,7 @@
|
|||||||
<footer>
|
<footer>
|
||||||
<span>{{ image.type }}</span>
|
<span>{{ image.type }}</span>
|
||||||
<span>{{ bytes(image.size) }}</span>
|
<span>{{ bytes(image.size) }}</span>
|
||||||
<span v-if="image.properties?.width">{{ number(image.properties.width) }}px × {{ number(image.properties.height) }}px</span>
|
<span v-if="image.properties && image.properties.width">{{ number(image.properties.width) }}px × {{ number(image.properties.height) }}px</span>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</MkModal>
|
</MkModal>
|
||||||
|
@@ -38,7 +38,9 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
|
|
||||||
> ::v-deep(code) {
|
> ::v-deep(code) {
|
||||||
|
font-size: 0.8em;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
::v-deep(.title) {
|
::v-deep(.title) {
|
||||||
|
@@ -101,7 +101,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { computed, defineAsyncComponent, defineComponent, markRaw, ref } from 'vue';
|
import { computed, defineAsyncComponent, defineComponent, markRaw, ref } from 'vue';
|
||||||
import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
|
import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { parse } from '../../mfm/parse';
|
import { parse } from '../../mfm/parse';
|
||||||
import { sum, unique } from '../../prelude/array';
|
import { sum, unique } from '../../prelude/array';
|
||||||
@@ -637,6 +637,21 @@ export default defineComponent({
|
|||||||
}]
|
}]
|
||||||
: []
|
: []
|
||||||
),
|
),
|
||||||
|
...(this.appearNote.userId != this.$store.state.i.id ? [
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
icon: faExclamationCircle,
|
||||||
|
text: this.$t('reportAbuse'),
|
||||||
|
action: () => {
|
||||||
|
const u = `${url}/notes/${this.appearNote.id}`;
|
||||||
|
os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), {
|
||||||
|
user: this.appearNote.user,
|
||||||
|
initialComment: `Note: ${u}\n-----\n`
|
||||||
|
}, {}, 'closed');
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
: []
|
||||||
|
),
|
||||||
...(this.appearNote.userId == this.$store.state.i.id || this.$store.state.i.isModerator || this.$store.state.i.isAdmin ? [
|
...(this.appearNote.userId == this.$store.state.i.id || this.$store.state.i.isModerator || this.$store.state.i.isAdmin ? [
|
||||||
null,
|
null,
|
||||||
this.appearNote.userId == this.$store.state.i.id ? {
|
this.appearNote.userId == this.$store.state.i.id ? {
|
||||||
@@ -708,6 +723,7 @@ export default defineComponent({
|
|||||||
os.modalMenu([{
|
os.modalMenu([{
|
||||||
text: this.$t('unrenote'),
|
text: this.$t('unrenote'),
|
||||||
icon: faTrashAlt,
|
icon: faTrashAlt,
|
||||||
|
danger: true,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.api('notes/delete', {
|
os.api('notes/delete', {
|
||||||
noteId: this.note.id
|
noteId: this.note.id
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<XWindow ref="window" :initial-width="400" :initial-height="450" :can-resize="true" @closed="$emit('closed')">
|
<XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="$emit('closed')">
|
||||||
<template #header>
|
<template #header>
|
||||||
<XHeader :info="pageInfo" :with-back="false"/>
|
<XHeader :info="pageInfo" :with-back="false"/>
|
||||||
</template>
|
</template>
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
<button class="_button" @click="expand" v-tooltip="$t('showInPage')"><Fa :icon="faExpandAlt"/></button>
|
<button class="_button" @click="expand" v-tooltip="$t('showInPage')"><Fa :icon="faExpandAlt"/></button>
|
||||||
<button class="_button" @click="popout" v-tooltip="$t('popout')"><Fa :icon="faExternalLinkAlt"/></button>
|
<button class="_button" @click="popout" v-tooltip="$t('popout')"><Fa :icon="faExternalLinkAlt"/></button>
|
||||||
</template>
|
</template>
|
||||||
<div 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"/>
|
||||||
</div>
|
</div>
|
||||||
</XWindow>
|
</XWindow>
|
||||||
@@ -84,3 +84,9 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.yrolvcoq {
|
||||||
|
--section-padding: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@@ -5,10 +5,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, defineAsyncComponent } from 'vue';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XBlock: defineAsyncComponent(() => import('./page.block.vue'))
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
required: true
|
required: true
|
||||||
@@ -23,8 +25,5 @@ export default defineComponent({
|
|||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate() {
|
|
||||||
this.$options.components.XBlock = require('./page.block.vue').default;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
@@ -44,14 +44,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
upload() {
|
upload() {
|
||||||
return new Promise((ok) => {
|
const promise = new Promise((ok) => {
|
||||||
const dialog = os.dialog({
|
|
||||||
type: 'waiting',
|
|
||||||
text: this.$t('uploading') + '...',
|
|
||||||
showOkButton: false,
|
|
||||||
showCancelButton: false,
|
|
||||||
cancelableByBgClick: false
|
|
||||||
});
|
|
||||||
const canvas = this.hpml.canvases[this.value.canvasId];
|
const canvas = this.hpml.canvases[this.value.canvasId];
|
||||||
canvas.toBlob(blob => {
|
canvas.toBlob(blob => {
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
@@ -67,11 +60,12 @@ export default defineComponent({
|
|||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(f => {
|
.then(f => {
|
||||||
dialog.close();
|
|
||||||
ok(f);
|
ok(f);
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
os.promiseDialog(promise);
|
||||||
|
return promise;
|
||||||
},
|
},
|
||||||
async post() {
|
async post() {
|
||||||
this.posting = true;
|
this.posting = true;
|
||||||
|
@@ -9,10 +9,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, defineAsyncComponent } from 'vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
XBlock: defineAsyncComponent(() => import('./page.block.vue'))
|
||||||
|
},
|
||||||
props: {
|
props: {
|
||||||
value: {
|
value: {
|
||||||
required: true
|
required: true
|
||||||
@@ -27,9 +30,6 @@ export default defineComponent({
|
|||||||
required: true
|
required: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
beforeCreate() {
|
|
||||||
this.$options.components.XBlock = require('./page.block.vue').default;
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@@ -5,7 +5,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import MkTextarea from '../ui/textarea.vue';
|
import MkTextarea from '../ui/textarea.vue';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
@@ -12,7 +12,6 @@ import { faHeart } from '@fortawesome/free-regular-svg-icons';
|
|||||||
import XBlock from './page.block.vue';
|
import XBlock from './page.block.vue';
|
||||||
import { Hpml } from '@/scripts/hpml/evaluator';
|
import { Hpml } from '@/scripts/hpml/evaluator';
|
||||||
import { url } from '@/config';
|
import { url } from '@/config';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
|
@@ -57,7 +57,6 @@ import MkInput from './ui/input.vue';
|
|||||||
import MkSelect from './ui/select.vue';
|
import MkSelect from './ui/select.vue';
|
||||||
import MkSwitch from './ui/switch.vue';
|
import MkSwitch from './ui/switch.vue';
|
||||||
import MkButton from './ui/button.vue';
|
import MkButton from './ui/button.vue';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
@@ -78,8 +77,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
choices: ['', ''],
|
choices: this.poll.choices,
|
||||||
multiple: false,
|
multiple: this.poll.multiple,
|
||||||
expiration: 'infinite',
|
expiration: 'infinite',
|
||||||
atDate: formatDateTimeString(addTime(new Date(), 1, 'day'), 'yyyy-MM-dd'),
|
atDate: formatDateTimeString(addTime(new Date(), 1, 'day'), 'yyyy-MM-dd'),
|
||||||
atTime: '00:00',
|
atTime: '00:00',
|
||||||
@@ -90,26 +89,6 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
poll: {
|
|
||||||
handler(poll) {
|
|
||||||
if (poll == null) return;
|
|
||||||
if (poll.choices.length == 0) return;
|
|
||||||
this.choices = poll.choices;
|
|
||||||
if (poll.choices.length == 1) this.choices = this.choices.concat('');
|
|
||||||
this.multiple = poll.multiple;
|
|
||||||
if (poll.expiresAt) {
|
|
||||||
this.expiration = 'at';
|
|
||||||
this.atDate = this.atTime = poll.expiresAt;
|
|
||||||
} else if (typeof poll.expiredAfter === 'number') {
|
|
||||||
this.expiration = 'after';
|
|
||||||
this.after = poll.expiredAfter;
|
|
||||||
} else {
|
|
||||||
this.expiration = 'infinite';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
deep: true,
|
|
||||||
immediate: true
|
|
||||||
},
|
|
||||||
choices: {
|
choices: {
|
||||||
handler() {
|
handler() {
|
||||||
this.$emit('updated', this.get());
|
this.$emit('updated', this.get());
|
||||||
@@ -136,6 +115,24 @@ export default defineComponent({
|
|||||||
this.$emit('updated', this.get());
|
this.$emit('updated', this.get());
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
unit: {
|
||||||
|
handler() {
|
||||||
|
this.$emit('updated', this.get());
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
created() {
|
||||||
|
const poll = this.poll;
|
||||||
|
if (poll.expiresAt) {
|
||||||
|
this.expiration = 'at';
|
||||||
|
this.atDate = this.atTime = poll.expiresAt;
|
||||||
|
} else if (typeof poll.expiredAfter === 'number') {
|
||||||
|
this.expiration = 'after';
|
||||||
|
this.after = poll.expiredAfter / 1000;
|
||||||
|
} else {
|
||||||
|
this.expiration = 'infinite';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')" :position="'top'">
|
<MkModal ref="modal" @click="$refs.modal.close()" @closed="$emit('closed')" :position="'top'">
|
||||||
<MkPostForm @done="$refs.modal.close()" @esc="$refs.modal.close()" v-bind="$attrs"/>
|
<MkPostForm @posted="$refs.modal.close()" @cancel="$refs.modal.close()" @esc="$refs.modal.close()" v-bind="$attrs"/>
|
||||||
</MkModal>
|
</MkModal>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@@ -125,7 +125,7 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['posted', 'done', 'esc'],
|
emits: ['posted', 'cancel', 'esc'],
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@@ -135,8 +135,8 @@ export default defineComponent({
|
|||||||
poll: null,
|
poll: null,
|
||||||
useCw: false,
|
useCw: false,
|
||||||
cw: null,
|
cw: null,
|
||||||
localOnly: false,
|
localOnly: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.localOnly : this.$store.state.settings.defaultNoteLocalOnly,
|
||||||
visibility: 'public',
|
visibility: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.visibility : this.$store.state.settings.defaultNoteVisibility,
|
||||||
visibleUsers: [],
|
visibleUsers: [],
|
||||||
autocomplete: null,
|
autocomplete: null,
|
||||||
draghover: false,
|
draghover: false,
|
||||||
@@ -202,12 +202,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
|
||||||
localOnly() {
|
|
||||||
this.$store.commit('deviceUser/setLocalOnly', this.localOnly);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
if (this.initialText) {
|
if (this.initialText) {
|
||||||
this.text = this.initialText;
|
this.text = this.initialText;
|
||||||
@@ -239,11 +233,9 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// デフォルト公開範囲
|
if (this.channel) {
|
||||||
if (this.channel == null) {
|
this.visibility = 'public';
|
||||||
this.applyVisibility(this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.visibility : this.$store.state.settings.defaultNoteVisibility);
|
this.localOnly = true; // TODO: チャンネルが連合するようになった折には消す
|
||||||
|
|
||||||
this.localOnly = this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.localOnly : this.$store.state.settings.defaultNoteLocalOnly;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
|
// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
|
||||||
@@ -295,7 +287,7 @@ export default defineComponent({
|
|||||||
this.text = draft.data.text;
|
this.text = draft.data.text;
|
||||||
this.useCw = draft.data.useCw;
|
this.useCw = draft.data.useCw;
|
||||||
this.cw = draft.data.cw;
|
this.cw = draft.data.cw;
|
||||||
this.applyVisibility(draft.data.visibility);
|
this.visibility = draft.data.visibility;
|
||||||
this.localOnly = draft.data.localOnly;
|
this.localOnly = draft.data.localOnly;
|
||||||
this.files = (draft.data.files || []).filter(e => e);
|
this.files = (draft.data.files || []).filter(e => e);
|
||||||
if (draft.data.poll) {
|
if (draft.data.poll) {
|
||||||
@@ -398,18 +390,20 @@ export default defineComponent({
|
|||||||
src: this.$refs.visibilityButton
|
src: this.$refs.visibilityButton
|
||||||
}, {
|
}, {
|
||||||
changeVisibility: visibility => {
|
changeVisibility: visibility => {
|
||||||
this.applyVisibility(visibility);
|
this.visibility = visibility;
|
||||||
|
if (this.$store.state.settings.rememberNoteVisibility) {
|
||||||
|
this.$store.commit('deviceUser/setVisibility', visibility);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
changeLocalOnly: localOnly => {
|
changeLocalOnly: localOnly => {
|
||||||
this.localOnly = localOnly;
|
this.localOnly = localOnly;
|
||||||
|
if (this.$store.state.settings.rememberNoteVisibility) {
|
||||||
|
this.$store.commit('deviceUser/setLocalOnly', localOnly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
applyVisibility(v: string) {
|
|
||||||
this.visibility = (noteVisibilities as unknown as string[]).includes(v) ? v : 'public'; // v11互換性のため
|
|
||||||
},
|
|
||||||
|
|
||||||
addVisibleUser() {
|
addVisibleUser() {
|
||||||
os.selectUser().then(user => {
|
os.selectUser().then(user => {
|
||||||
this.visibleUsers.push(user);
|
this.visibleUsers.push(user);
|
||||||
@@ -556,23 +550,23 @@ export default defineComponent({
|
|||||||
this.posting = true;
|
this.posting = true;
|
||||||
os.api('notes/create', data).then(() => {
|
os.api('notes/create', data).then(() => {
|
||||||
this.clear();
|
this.clear();
|
||||||
this.deleteDraft();
|
this.$nextTick(() => {
|
||||||
this.$emit('posted');
|
this.deleteDraft();
|
||||||
|
this.$emit('posted');
|
||||||
|
if (this.text && this.text != '') {
|
||||||
|
const hashtags = parse(this.text).filter(x => x.node.type === 'hashtag').map(x => x.node.props.hashtag);
|
||||||
|
const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
|
||||||
|
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history))));
|
||||||
|
}
|
||||||
|
this.posting = false;
|
||||||
|
});
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
}).then(() => {
|
|
||||||
this.posting = false;
|
this.posting = false;
|
||||||
this.$emit('done');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.text && this.text != '') {
|
|
||||||
const hashtags = parse(this.text).filter(x => x.node.type === 'hashtag').map(x => x.node.props.hashtag);
|
|
||||||
const history = JSON.parse(localStorage.getItem('hashtags') || '[]') as string[];
|
|
||||||
localStorage.setItem('hashtags', JSON.stringify(unique(hashtags.concat(history))));
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.$emit('done');
|
this.$emit('cancel');
|
||||||
},
|
},
|
||||||
|
|
||||||
insertMention() {
|
insertMention() {
|
||||||
|
116
src/client/components/sample.vue
Normal file
116
src/client/components/sample.vue
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div class="_card">
|
||||||
|
<div class="_content">
|
||||||
|
<MkInput v-model:value="text">
|
||||||
|
<span>Text</span>
|
||||||
|
</MkInput>
|
||||||
|
<MkSwitch v-model:value="flag">
|
||||||
|
<span>Switch is now {{ flag ? 'on' : 'off' }}</span>
|
||||||
|
</MkSwitch>
|
||||||
|
<div style="margin: 32px 0;">
|
||||||
|
<MkRadio v-model="radio" value="misskey">Misskey</MkRadio>
|
||||||
|
<MkRadio v-model="radio" value="mastodon">Mastodon</MkRadio>
|
||||||
|
<MkRadio v-model="radio" value="pleroma">Pleroma</MkRadio>
|
||||||
|
</div>
|
||||||
|
<MkButton inline>This is</MkButton>
|
||||||
|
<MkButton inline primary>the button</MkButton>
|
||||||
|
</div>
|
||||||
|
<div class="_content">
|
||||||
|
<Mfm :text="mfm"/>
|
||||||
|
</div>
|
||||||
|
<div class="_content">
|
||||||
|
<MkButton inline primary @click="openMenu">Open menu</MkButton>
|
||||||
|
<MkButton inline primary @click="openDialog">Open dialog</MkButton>
|
||||||
|
<MkButton inline primary @click="openForm">Open form</MkButton>
|
||||||
|
<MkButton inline primary @click="openDrive">Open drive</MkButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import MkButton from '@/components/ui/button.vue';
|
||||||
|
import MkInput from '@/components/ui/input.vue';
|
||||||
|
import MkSwitch from '@/components/ui/switch.vue';
|
||||||
|
import MkTextarea from '@/components/ui/textarea.vue';
|
||||||
|
import MkRadio from '@/components/ui/radio.vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import * as config from '@/config';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
MkButton,
|
||||||
|
MkInput,
|
||||||
|
MkSwitch,
|
||||||
|
MkTextarea,
|
||||||
|
MkRadio,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
text: '',
|
||||||
|
flag: false,
|
||||||
|
radio: 'misskey',
|
||||||
|
mfm: `Hello world! This is an @example mention. BTW you are @${this.$store.state.i.username}.\nAlso, here is ${config.url} and [example link](${config.url}). for more details, see https://example.com.\nAs you know #misskey is open-source software.`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
async openDialog() {
|
||||||
|
os.dialog({
|
||||||
|
type: 'warning',
|
||||||
|
title: 'Oh my Aichan',
|
||||||
|
text: 'Lorem ipsum dolor sit amet, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async openForm() {
|
||||||
|
os.form('Example form', {
|
||||||
|
foo: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
label: 'This is a boolean property'
|
||||||
|
},
|
||||||
|
bar: {
|
||||||
|
type: 'number',
|
||||||
|
default: 300,
|
||||||
|
label: 'This is a number property'
|
||||||
|
},
|
||||||
|
baz: {
|
||||||
|
type: 'string',
|
||||||
|
default: 'Misskey makes you happy.',
|
||||||
|
label: 'This is a string property'
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async openDrive() {
|
||||||
|
os.selectDriveFile();
|
||||||
|
},
|
||||||
|
|
||||||
|
async selectUser() {
|
||||||
|
os.selectUser();
|
||||||
|
},
|
||||||
|
|
||||||
|
async openMenu(ev) {
|
||||||
|
os.modalMenu([{
|
||||||
|
type: 'label',
|
||||||
|
text: 'Fruits'
|
||||||
|
}, {
|
||||||
|
text: 'Create some apples',
|
||||||
|
action: () => {},
|
||||||
|
}, {
|
||||||
|
text: 'Read some oranges',
|
||||||
|
action: () => {},
|
||||||
|
}, {
|
||||||
|
text: 'Update some melons',
|
||||||
|
action: () => {},
|
||||||
|
}, null, {
|
||||||
|
text: 'Delete some bananas',
|
||||||
|
danger: true,
|
||||||
|
action: () => {},
|
||||||
|
}], ev.currentTarget || ev.target);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
@@ -46,7 +46,7 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram, faStream } from '@fortawesome/free-solid-svg-icons';
|
import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram, faStream, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
|
import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { host, instanceName } from '@/config';
|
import { host, instanceName } from '@/config';
|
||||||
import { search } from '@/scripts/search';
|
import { search } from '@/scripts/search';
|
||||||
@@ -217,6 +217,11 @@ export default defineComponent({
|
|||||||
text: this.$t('announcements'),
|
text: this.$t('announcements'),
|
||||||
to: '/instance/announcements',
|
to: '/instance/announcements',
|
||||||
icon: faBroadcastTower,
|
icon: faBroadcastTower,
|
||||||
|
}, {
|
||||||
|
type: 'link',
|
||||||
|
text: this.$t('abuseReports'),
|
||||||
|
to: '/instance/abuses',
|
||||||
|
icon: faExclamationCircle,
|
||||||
}, {
|
}, {
|
||||||
type: 'link',
|
type: 'link',
|
||||||
text: this.$t('logs'),
|
text: this.$t('logs'),
|
||||||
|
@@ -26,7 +26,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@@ -7,7 +7,9 @@
|
|||||||
<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"></slot>
|
<slot 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">
|
||||||
@@ -313,11 +315,13 @@ export default defineComponent({
|
|||||||
|
|
||||||
// 高さを適用
|
// 高さを適用
|
||||||
applyTransformHeight(height) {
|
applyTransformHeight(height) {
|
||||||
|
if (height > window.innerHeight) height = window.innerHeight;
|
||||||
(this.$el as any).style.height = height + 'px';
|
(this.$el as any).style.height = height + 'px';
|
||||||
},
|
},
|
||||||
|
|
||||||
// 幅を適用
|
// 幅を適用
|
||||||
applyTransformWidth(width) {
|
applyTransformWidth(width) {
|
||||||
|
if (width > window.innerWidth) width = window.innerWidth;
|
||||||
(this.$el as any).style.width = width + 'px';
|
(this.$el as any).style.width = width + 'px';
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -371,15 +375,13 @@ export default defineComponent({
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
--section-padding: 16px;
|
|
||||||
|
|
||||||
> .header {
|
> .header {
|
||||||
$height: 50px;
|
$height: 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
box-shadow: 0px 1px var(--divider);
|
box-shadow: 0px 1px var(--divider);
|
||||||
cursor: move;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
height: $height;
|
height: $height;
|
||||||
|
|
||||||
@@ -399,6 +401,8 @@ export default defineComponent({
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
text-align: center;
|
||||||
|
cursor: move;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -55,11 +55,11 @@ export default defineComponent({
|
|||||||
props: {
|
props: {
|
||||||
currentVisibility: {
|
currentVisibility: {
|
||||||
type: String,
|
type: String,
|
||||||
required: false
|
required: true
|
||||||
},
|
},
|
||||||
currentLocalOnly: {
|
currentLocalOnly: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
required: false
|
required: true
|
||||||
},
|
},
|
||||||
src: {
|
src: {
|
||||||
required: false
|
required: false
|
||||||
@@ -68,7 +68,7 @@ export default defineComponent({
|
|||||||
emits: ['change-visibility', 'change-local-only', 'closed'],
|
emits: ['change-visibility', 'change-local-only', 'closed'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
v: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.visibility : (this.currentVisibility || this.$store.state.settings.defaultNoteVisibility),
|
v: this.currentVisibility,
|
||||||
localOnly: this.currentLocalOnly,
|
localOnly: this.currentLocalOnly,
|
||||||
faGlobe, faUnlock, faEnvelope, faHome, faBiohazard, faToggleOn, faToggleOff
|
faGlobe, faUnlock, faEnvelope, faHome, faBiohazard, faToggleOn, faToggleOff
|
||||||
}
|
}
|
||||||
@@ -81,9 +81,6 @@ export default defineComponent({
|
|||||||
methods: {
|
methods: {
|
||||||
choose(visibility) {
|
choose(visibility) {
|
||||||
this.v = visibility;
|
this.v = visibility;
|
||||||
if (this.$store.state.settings.rememberNoteVisibility) {
|
|
||||||
this.$store.commit('deviceUser/setVisibility', visibility);
|
|
||||||
}
|
|
||||||
this.$emit('change-visibility', visibility);
|
this.$emit('change-visibility', visibility);
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.$refs.modal.close();
|
this.$refs.modal.close();
|
||||||
|
@@ -1,8 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" @click="type === 'success' ? done() : () => {}" @closed="$emit('closed')">
|
<MkModal ref="modal" @click="success ? done() : () => {}" @closed="$emit('closed')">
|
||||||
<div class="iuyakobc" :class="type">
|
<div class="iuyakobc" :class="{ iconOnly: (text == null) || success }">
|
||||||
<Fa class="icon" v-if="type === 'success'" :icon="faCheck"/>
|
<Fa class="icon success" v-if="success" :icon="faCheck"/>
|
||||||
<Fa class="icon" v-else-if="type === 'waiting'" :icon="faSpinner" pulse/>
|
<Fa class="icon waiting" v-else :icon="faSpinner" pulse/>
|
||||||
|
<div class="text" v-if="text && !success">{{ text }}<MkEllipsis/></div>
|
||||||
</div>
|
</div>
|
||||||
</MkModal>
|
</MkModal>
|
||||||
</template>
|
</template>
|
||||||
@@ -18,12 +19,18 @@ export default defineComponent({
|
|||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
type: {
|
success: {
|
||||||
required: true
|
type: Boolean,
|
||||||
|
required: true,
|
||||||
},
|
},
|
||||||
showing: {
|
showing: {
|
||||||
required: true
|
type: Boolean,
|
||||||
}
|
required: true,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
emits: ['done', 'closed'],
|
emits: ['done', 'closed'],
|
||||||
@@ -57,17 +64,32 @@ export default defineComponent({
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
width: initial;
|
width: 250px;
|
||||||
font-size: 32px;
|
|
||||||
|
|
||||||
&.success {
|
&.iconOnly {
|
||||||
color: var(--accent);
|
padding: 0;
|
||||||
|
width: 96px;
|
||||||
|
height: 96px;
|
||||||
|
|
||||||
|
> .icon {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.waiting {
|
> .icon {
|
||||||
> .icon {
|
font-size: 32px;
|
||||||
|
|
||||||
|
&.success {
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.waiting {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .text {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@@ -51,7 +51,7 @@ if (_DEV_) {
|
|||||||
document.addEventListener('touchend', () => {}, { passive: true });
|
document.addEventListener('touchend', () => {}, { passive: true });
|
||||||
|
|
||||||
if (localStorage.getItem('theme') == null) {
|
if (localStorage.getItem('theme') == null) {
|
||||||
applyTheme(require('@/themes/white.json5'));
|
applyTheme(require('@/themes/l-white.json5'));
|
||||||
}
|
}
|
||||||
|
|
||||||
//#region SEE: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
//#region SEE: https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
||||||
|
@@ -4,6 +4,7 @@ import Stream from '@/scripts/stream';
|
|||||||
import { store } from '@/store';
|
import { store } from '@/store';
|
||||||
import { apiUrl } from '@/config';
|
import { apiUrl } 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';
|
||||||
|
|
||||||
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);
|
||||||
@@ -62,17 +63,39 @@ export function api(endpoint: string, data: Record<string, any> = {}, token?: st
|
|||||||
return promise;
|
return promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function apiWithDialog(endpoint: string, data: Record<string, any> = {}, token?: string | null | undefined, onSuccess?: (res: any) => void, onFailure?: (e: Error) => void) {
|
export function apiWithDialog(
|
||||||
const showing = ref(true);
|
endpoint: string,
|
||||||
const state = ref('waiting');
|
data: Record<string, any> = {},
|
||||||
|
token?: string | null | undefined,
|
||||||
|
onSuccess?: (res: any) => void,
|
||||||
|
onFailure?: (e: Error) => void,
|
||||||
|
) {
|
||||||
const promise = api(endpoint, data, token);
|
const promise = api(endpoint, data, token);
|
||||||
|
promiseDialog(promise, onSuccess, onFailure ? onFailure : (e) => {
|
||||||
|
dialog({
|
||||||
|
type: 'error',
|
||||||
|
text: e.message + '<br>' + (e as any).id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function promiseDialog<T extends Promise<any>>(
|
||||||
|
promise: T,
|
||||||
|
onSuccess?: (res: any) => void,
|
||||||
|
onFailure?: (e: Error) => void,
|
||||||
|
text?: string,
|
||||||
|
): T {
|
||||||
|
const showing = ref(true);
|
||||||
|
const success = ref(false);
|
||||||
|
|
||||||
promise.then(res => {
|
promise.then(res => {
|
||||||
if (onSuccess) {
|
if (onSuccess) {
|
||||||
showing.value = false;
|
showing.value = false;
|
||||||
onSuccess(res);
|
onSuccess(res);
|
||||||
} else {
|
} else {
|
||||||
state.value = 'success';
|
success.value = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
showing.value = false;
|
showing.value = false;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
@@ -89,9 +112,11 @@ export function apiWithDialog(endpoint: string, data: Record<string, any> = {},
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
popup(defineAsyncComponent(() => import('@/components/icon-dialog.vue')), {
|
// NOTE: dynamic importすると挙動がおかしくなる(showingの変更が伝播しない)
|
||||||
type: state,
|
popup(MkWaitingDialog, {
|
||||||
showing: showing
|
success: success,
|
||||||
|
showing: showing,
|
||||||
|
text: text,
|
||||||
}, {}, 'closed');
|
}, {}, 'closed');
|
||||||
|
|
||||||
return promise;
|
return promise;
|
||||||
@@ -161,8 +186,8 @@ export function success() {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
showing.value = false;
|
showing.value = false;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
popup(defineAsyncComponent(() => import('@/components/icon-dialog.vue')), {
|
popup(defineAsyncComponent(() => import('@/components/waiting-dialog.vue')), {
|
||||||
type: 'success',
|
success: true,
|
||||||
showing: showing
|
showing: showing
|
||||||
}, {
|
}, {
|
||||||
done: () => resolve(),
|
done: () => resolve(),
|
||||||
@@ -173,8 +198,8 @@ 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/icon-dialog.vue')), {
|
popup(defineAsyncComponent(() => import('@/components/waiting-dialog.vue')), {
|
||||||
type: 'waiting',
|
success: false,
|
||||||
showing: showing
|
showing: showing
|
||||||
}, {
|
}, {
|
||||||
done: () => resolve(),
|
done: () => resolve(),
|
||||||
@@ -278,6 +303,10 @@ export function contextMenu(items: any[], ev: MouseEvent) {
|
|||||||
export function post(props: Record<string, any>) {
|
export function post(props: Record<string, any>) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// NOTE: MkPostFormDialogをdynamic importするとiOSでテキストエリアに自動フォーカスできない
|
// NOTE: MkPostFormDialogをdynamic importするとiOSでテキストエリアに自動フォーカスできない
|
||||||
|
// NOTE: ただ、dynamic importしない場合、MkPostFormDialogインスタンスが使いまわされ、
|
||||||
|
// Vueが渡されたコンポーネントに内部的に__propsというプロパティを生やす影響で、
|
||||||
|
// 複数のpost formを開いたときに場合によってはエラーになる
|
||||||
|
// もちろん複数のpost formを開けること自体Misskeyサイドのバグなのだが
|
||||||
const { dispose } = popup(MkPostFormDialog, props, {
|
const { dispose } = popup(MkPostFormDialog, props, {
|
||||||
closed: () => {
|
closed: () => {
|
||||||
resolve();
|
resolve();
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="channel">
|
<div v-if="channel" class="_section">
|
||||||
<div class="wpgynlbz _panel _vMargin" :class="{ hide: !showBanner }">
|
<div class="wpgynlbz _content _panel _vMargin" :class="{ hide: !showBanner }">
|
||||||
<XChannelFollow-button :channel="channel" :full="true" class="subscribe"/>
|
<XChannelFollowButton :channel="channel" :full="true" class="subscribe"/>
|
||||||
<button class="_button toggle" @click="() => showBanner = !showBanner">
|
<button class="_button toggle" @click="() => showBanner = !showBanner">
|
||||||
<template v-if="showBanner"><Fa :icon="faAngleUp"/></template>
|
<template v-if="showBanner"><Fa :icon="faAngleUp"/></template>
|
||||||
<template v-else><Fa :icon="faAngleDown"/></template>
|
<template v-else><Fa :icon="faAngleDown"/></template>
|
||||||
@@ -10,8 +10,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner">
|
<div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner">
|
||||||
<div class="status">
|
<div class="status">
|
||||||
<div><Fa :icon="faUsers" fixed-width/><i18n path="_channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></i18n></div>
|
<div><Fa :icon="faUsers" fixed-width/><i18n-t keypath="_channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></i18n-t></div>
|
||||||
<div><Fa :icon="faPencilAlt" fixed-width/><i18n path="_channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></i18n></div>
|
<div><Fa :icon="faPencilAlt" fixed-width/><i18n-t keypath="_channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></i18n-t></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="fade"></div>
|
<div class="fade"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<XPostForm :channel="channel" class="post-form _panel _vMargin" fixed/>
|
<XPostForm :channel="channel" class="post-form _content _panel _vMargin" fixed/>
|
||||||
|
|
||||||
<XTimeline class="_vMargin" src="channel" :channel="channelId" @before="before" @after="after"/>
|
<XTimeline class="_content _vMargin" src="channel" :channel="channelId" @before="before" @after="after"/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -91,6 +91,8 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.wpgynlbz {
|
.wpgynlbz {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
> .subscribe {
|
> .subscribe {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
@@ -6,26 +6,24 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
import parseAcct from '../../misc/acct/parse';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
created() {
|
created() {
|
||||||
const acct = new URL(location.href).searchParams.get('acct');
|
const acct = new URL(location.href).searchParams.get('acct');
|
||||||
if (acct == null) return;
|
if (acct == null) return;
|
||||||
|
|
||||||
const dialog = os.dialog({
|
let promise;
|
||||||
type: 'waiting',
|
|
||||||
text: this.$t('fetchingAsApObject') + '...',
|
|
||||||
showOkButton: false,
|
|
||||||
showCancelButton: false,
|
|
||||||
cancelableByBgClick: false
|
|
||||||
});
|
|
||||||
|
|
||||||
if (acct.startsWith('https://')) {
|
if (acct.startsWith('https://')) {
|
||||||
os.api('ap/show', {
|
promise = os.api('ap/show', {
|
||||||
uri: acct
|
uri: acct
|
||||||
}).then(res => {
|
});
|
||||||
|
promise.then(res => {
|
||||||
if (res.type == 'User') {
|
if (res.type == 'User') {
|
||||||
this.follow(res.object);
|
this.follow(res.object);
|
||||||
|
} else if (res.type === 'Note') {
|
||||||
|
this.$router.push(`/notes/${res.object.id}`);
|
||||||
} else {
|
} else {
|
||||||
os.dialog({
|
os.dialog({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
@@ -34,30 +32,15 @@ export default defineComponent({
|
|||||||
window.close();
|
window.close();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
|
||||||
os.dialog({
|
|
||||||
type: 'error',
|
|
||||||
text: e
|
|
||||||
}).then(() => {
|
|
||||||
window.close();
|
|
||||||
});
|
|
||||||
}).finally(() => {
|
|
||||||
dialog.close();
|
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
os.api('users/show', parseAcct(acct)).then(user => {
|
promise = os.api('users/show', parseAcct(acct));
|
||||||
|
promise.then(user => {
|
||||||
this.follow(user);
|
this.follow(user);
|
||||||
}).catch(e => {
|
|
||||||
os.dialog({
|
|
||||||
type: 'error',
|
|
||||||
text: e
|
|
||||||
}).then(() => {
|
|
||||||
window.close();
|
|
||||||
});
|
|
||||||
}).finally(() => {
|
|
||||||
dialog.close();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
os.promiseDialog(promise, null, null, this.$t('fetchingAsApObject'));
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -73,19 +56,8 @@ export default defineComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
os.api('following/create', {
|
os.apiWithDialog('following/create', {
|
||||||
userId: user.id
|
userId: user.id
|
||||||
}).then(() => {
|
|
||||||
os.success().then(() => {
|
|
||||||
window.close();
|
|
||||||
});
|
|
||||||
}).catch(e => {
|
|
||||||
os.dialog({
|
|
||||||
type: 'error',
|
|
||||||
text: e
|
|
||||||
}).then(() => {
|
|
||||||
window.close();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
163
src/client/pages/instance/abuses.vue
Normal file
163
src/client/pages/instance/abuses.vue
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
<template>
|
||||||
|
<div class="">
|
||||||
|
<div class="_section reports">
|
||||||
|
<div class="_content">
|
||||||
|
<div class="inputs" style="display: flex;">
|
||||||
|
<MkSelect v-model:value="state" style="margin: 0; flex: 1;">
|
||||||
|
<template #label>{{ $t('state') }}</template>
|
||||||
|
<option value="all">{{ $t('all') }}</option>
|
||||||
|
<option value="unresolved">{{ $t('unresolved') }}</option>
|
||||||
|
<option value="resolved">{{ $t('resolved') }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
<MkSelect v-model:value="targetUserOrigin" style="margin: 0; flex: 1;">
|
||||||
|
<template #label>{{ $t('targetUserOrigin') }}</template>
|
||||||
|
<option value="combined">{{ $t('all') }}</option>
|
||||||
|
<option value="local">{{ $t('local') }}</option>
|
||||||
|
<option value="remote">{{ $t('remote') }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
<MkSelect v-model:value="reporterOrigin" style="margin: 0; flex: 1;">
|
||||||
|
<template #label>{{ $t('reporterOrigin') }}</template>
|
||||||
|
<option value="combined">{{ $t('all') }}</option>
|
||||||
|
<option value="local">{{ $t('local') }}</option>
|
||||||
|
<option value="remote">{{ $t('remote') }}</option>
|
||||||
|
</MkSelect>
|
||||||
|
</div>
|
||||||
|
<!-- TODO
|
||||||
|
<div class="inputs" style="display: flex; padding-top: 1.2em;">
|
||||||
|
<MkInput v-model:value="searchUsername" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:value="$refs.reports.reload()">
|
||||||
|
<span>{{ $t('username') }}</span>
|
||||||
|
</MkInput>
|
||||||
|
<MkInput v-model:value="searchHost" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:value="$refs.reports.reload()" :disabled="pagination.params().origin === 'local'">
|
||||||
|
<span>{{ $t('host') }}</span>
|
||||||
|
</MkInput>
|
||||||
|
</div>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<MkPagination :pagination="pagination" #default="{items}" ref="reports" :auto-margin="false" style="margin-top: var(--margin);">
|
||||||
|
<div class="bcekxzvu _card _vMargin" v-for="report in items" :key="report.id">
|
||||||
|
<div class="_content target">
|
||||||
|
<MkAvatar class="avatar" :user="report.targetUser"/>
|
||||||
|
<div class="info">
|
||||||
|
<MkUserName class="name" :user="report.targetUser"/>
|
||||||
|
<div class="acct">@{{ acct(report.targetUser) }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="_content">
|
||||||
|
<div>
|
||||||
|
<Mfm :text="report.comment"/>
|
||||||
|
</div>
|
||||||
|
<hr>
|
||||||
|
<div>Reporter: <MkAcct :user="report.reporter"/></div>
|
||||||
|
<div><MkTime :time="report.createdAt"/></div>
|
||||||
|
</div>
|
||||||
|
<div class="_footer">
|
||||||
|
<div v-if="report.assignee">Assignee: <MkAcct :user="report.assignee"/></div>
|
||||||
|
<MkButton @click="resolve(report)" primary v-if="!report.resolved">{{ $t('abuseMarkAsResolved') }}</MkButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</MkPagination>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
import { faPlus, faUsers, faSearch, faBookmark, faMicrophoneSlash, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import { faSnowflake, faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons';
|
||||||
|
import parseAcct from '../../../misc/acct/parse';
|
||||||
|
import MkButton from '@/components/ui/button.vue';
|
||||||
|
import MkInput from '@/components/ui/input.vue';
|
||||||
|
import MkSelect from '@/components/ui/select.vue';
|
||||||
|
import MkPagination from '@/components/ui/pagination.vue';
|
||||||
|
import { acct } from '../../filters/user';
|
||||||
|
import * as os from '@/os';
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
MkButton,
|
||||||
|
MkInput,
|
||||||
|
MkSelect,
|
||||||
|
MkPagination,
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
INFO: {
|
||||||
|
header: [{
|
||||||
|
title: this.$t('abuseReports'),
|
||||||
|
icon: faExclamationCircle
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
searchUsername: '',
|
||||||
|
searchHost: '',
|
||||||
|
state: 'unresolved',
|
||||||
|
reporterOrigin: 'combined',
|
||||||
|
targetUserOrigin: 'combined',
|
||||||
|
pagination: {
|
||||||
|
endpoint: 'admin/abuse-user-reports',
|
||||||
|
limit: 10,
|
||||||
|
params: () => ({
|
||||||
|
state: this.state,
|
||||||
|
reporterOrigin: this.reporterOrigin,
|
||||||
|
targetUserOrigin: this.targetUserOrigin,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
faPlus, faUsers, faSearch, faBookmark, farBookmark, faMicrophoneSlash, faSnowflake
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
watch: {
|
||||||
|
state() {
|
||||||
|
this.$refs.reports.reload();
|
||||||
|
},
|
||||||
|
|
||||||
|
reporterOrigin() {
|
||||||
|
this.$refs.reports.reload();
|
||||||
|
},
|
||||||
|
|
||||||
|
targetUserOrigin() {
|
||||||
|
this.$refs.reports.reload();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
acct,
|
||||||
|
|
||||||
|
resolve(report) {
|
||||||
|
os.apiWithDialog('admin/resolve-abuse-user-report', {
|
||||||
|
reportId: report.id,
|
||||||
|
}).then(() => {
|
||||||
|
this.$refs.reports.removeItem(item => item.id === report.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.bcekxzvu {
|
||||||
|
> .target {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-align: left;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> .avatar {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .info {
|
||||||
|
margin-left: 0.3em;
|
||||||
|
padding: 0 8px;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
> .name {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@@ -15,10 +15,8 @@
|
|||||||
<button class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="edit(emoji)">
|
<button class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="edit(emoji)">
|
||||||
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<span class="name">{{ emoji.name }}</span>
|
<div class="name">{{ emoji.name }}</div>
|
||||||
<span class="info">
|
<div class="info">{{ emoji.category }}</div>
|
||||||
<span class="category">{{ emoji.category }}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -36,8 +34,8 @@
|
|||||||
<div class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="remoteMenu(emoji, $event)">
|
<div class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="remoteMenu(emoji, $event)">
|
||||||
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
<img :src="emoji.url" class="img" :alt="emoji.name"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<span class="name">{{ emoji.name }}</span>
|
<div class="name">{{ emoji.name }}</div>
|
||||||
<span class="info">{{ emoji.host }}</span>
|
<div class="info">{{ emoji.host }}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,24 +104,13 @@ export default defineComponent({
|
|||||||
async add(e) {
|
async add(e) {
|
||||||
const files = await selectFile(e.currentTarget || e.target, null, true);
|
const files = await selectFile(e.currentTarget || e.target, null, true);
|
||||||
|
|
||||||
const dialog = os.dialog({
|
const promise = Promise.all(files.map(file => os.api('admin/emoji/add', {
|
||||||
type: 'waiting',
|
|
||||||
text: this.$t('doing') + '...',
|
|
||||||
showOkButton: false,
|
|
||||||
showCancelButton: false,
|
|
||||||
cancelableByBgClick: false
|
|
||||||
});
|
|
||||||
|
|
||||||
Promise.all(files.map(file => os.api('admin/emoji/add', {
|
|
||||||
fileId: file.id,
|
fileId: file.id,
|
||||||
})))
|
})));
|
||||||
.then(() => {
|
promise.then(() => {
|
||||||
this.$refs.emojis.reload();
|
this.$refs.emojis.reload();
|
||||||
os.success();
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
dialog.cancel();
|
|
||||||
});
|
});
|
||||||
|
os.promiseDialog(promise);
|
||||||
},
|
},
|
||||||
|
|
||||||
async edit(emoji) {
|
async edit(emoji) {
|
||||||
@@ -193,13 +180,14 @@ export default defineComponent({
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
> .name {
|
> .name {
|
||||||
display: block;
|
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .info {
|
> .info {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,14 +221,12 @@ export default defineComponent({
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
> .name {
|
> .name {
|
||||||
display: block;
|
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .info {
|
> .info {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
display: block;
|
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
<section class="_section info">
|
<section class="_section info">
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkInput v-model:value="maxNoteTextLength" type="number" :save="() => save()" style="margin:0;"><template #icon><Fa :icon="faPencilAlt"/></template>{{ $t('maxNoteTextLength') }}</MkInput>
|
<MkInput v-model:value="maxNoteTextLength" type="number" :save="() => save()"><template #icon><Fa :icon="faPencilAlt"/></template>{{ $t('maxNoteTextLength') }}</MkInput>
|
||||||
</div>
|
</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkSwitch v-model:value="enableLocalTimeline" @update:value="save()">{{ $t('enableLocalTimeline') }}</MkSwitch>
|
<MkSwitch v-model:value="enableLocalTimeline" @update:value="save()">{{ $t('enableLocalTimeline') }}</MkSwitch>
|
||||||
@@ -91,8 +91,8 @@
|
|||||||
<MkInfo>{{ $t('emptyToDisableSmtpAuth') }}</MkInfo>
|
<MkInfo>{{ $t('emptyToDisableSmtpAuth') }}</MkInfo>
|
||||||
<MkSwitch v-model:value="smtpSecure" :disabled="!enableEmail">{{ $t('smtpSecure') }}<template #desc>{{ $t('smtpSecureInfo') }}</template></MkSwitch>
|
<MkSwitch v-model:value="smtpSecure" :disabled="!enableEmail">{{ $t('smtpSecure') }}<template #desc>{{ $t('smtpSecureInfo') }}</template></MkSwitch>
|
||||||
<div>
|
<div>
|
||||||
|
<MkButton :disabled="!enableEmail" primary inline @click="save(true)"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
|
||||||
<MkButton :disabled="!enableEmail" inline @click="testEmail()">{{ $t('testEmail') }}</MkButton>
|
<MkButton :disabled="!enableEmail" inline @click="testEmail()">{{ $t('testEmail') }}</MkButton>
|
||||||
<MkButton :disabled="!enableEmail" primary inline @click="save(true)"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -131,7 +131,7 @@
|
|||||||
<MkSwitch v-model:value="cacheRemoteFiles">{{ $t('cacheRemoteFiles') }}<template #desc>{{ $t('cacheRemoteFilesDescription') }}</template></MkSwitch>
|
<MkSwitch v-model:value="cacheRemoteFiles">{{ $t('cacheRemoteFiles') }}<template #desc>{{ $t('cacheRemoteFilesDescription') }}</template></MkSwitch>
|
||||||
<MkSwitch v-model:value="proxyRemoteFiles">{{ $t('proxyRemoteFiles') }}<template #desc>{{ $t('proxyRemoteFilesDescription') }}</template></MkSwitch>
|
<MkSwitch v-model:value="proxyRemoteFiles">{{ $t('proxyRemoteFiles') }}<template #desc>{{ $t('proxyRemoteFilesDescription') }}</template></MkSwitch>
|
||||||
<MkInput v-model:value="localDriveCapacityMb" type="number">{{ $t('driveCapacityPerLocalAccount') }}<template #suffix>MB</template><template #desc>{{ $t('inMb') }}</template></MkInput>
|
<MkInput v-model:value="localDriveCapacityMb" type="number">{{ $t('driveCapacityPerLocalAccount') }}<template #suffix>MB</template><template #desc>{{ $t('inMb') }}</template></MkInput>
|
||||||
<MkInput v-model:value="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles" style="margin-bottom: 0;">{{ $t('driveCapacityPerRemoteAccount') }}<template #suffix>MB</template><template #desc>{{ $t('inMb') }}</template></MkInput>
|
<MkInput v-model:value="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles">{{ $t('driveCapacityPerRemoteAccount') }}<template #suffix>MB</template><template #desc>{{ $t('inMb') }}</template></MkInput>
|
||||||
</div>
|
</div>
|
||||||
<div class="_footer">
|
<div class="_footer">
|
||||||
<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
|
<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
<section class="_section">
|
<section class="_section">
|
||||||
<div class="_title"><Fa :icon="faGhost"/> {{ $t('proxyAccount') }}</div>
|
<div class="_title"><Fa :icon="faGhost"/> {{ $t('proxyAccount') }}</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkInput :value="proxyAccount ? proxyAccount.username : null" style="margin: 0;" disabled><template #prefix>@</template>{{ $t('proxyAccount') }}<template #desc>{{ $t('proxyAccountDescription') }}</template></MkInput>
|
<MkInput :value="proxyAccount ? proxyAccount.username : null" disabled><template #prefix>@</template>{{ $t('proxyAccount') }}<template #desc>{{ $t('proxyAccountDescription') }}</template></MkInput>
|
||||||
<MkButton primary @click="chooseProxyAccount">{{ $t('chooseProxyAccount') }}</MkButton>
|
<MkButton primary @click="chooseProxyAccount">{{ $t('chooseProxyAccount') }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="thvuemwp" :class="{ isMe }">
|
<div class="thvuemwp" :class="{ isMe }" v-size="{ max: [400, 500] }">
|
||||||
<MkAvatar class="avatar" :user="message.user"/>
|
<MkAvatar class="avatar" :user="message.user"/>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="balloon" :class="{ noText: message.text == null }" >
|
<div class="balloon" :class="{ noText: message.text == null }" >
|
||||||
@@ -92,11 +92,6 @@ export default defineComponent({
|
|||||||
width: 54px;
|
width: 54px;
|
||||||
height: 54px;
|
height: 54px;
|
||||||
transition: all 0.1s ease;
|
transition: all 0.1s ease;
|
||||||
|
|
||||||
@media (max-width: 400px) {
|
|
||||||
width: 48px;
|
|
||||||
height: 48px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .content {
|
> .content {
|
||||||
@@ -175,14 +170,6 @@ export default defineComponent({
|
|||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
color: rgba(#000, 0.8);
|
color: rgba(#000, 0.8);
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
padding: 8px 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 400px) {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
& + .file {
|
& + .file {
|
||||||
> a {
|
> a {
|
||||||
border-radius: 0 0 16px 16px;
|
border-radius: 0 0 16px 16px;
|
||||||
@@ -326,5 +313,34 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.max-width_400px {
|
||||||
|
> .avatar {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .content {
|
||||||
|
> .balloon {
|
||||||
|
> .content {
|
||||||
|
> .text {
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.max-width_500px {
|
||||||
|
> .content {
|
||||||
|
> .balloon {
|
||||||
|
> .content {
|
||||||
|
> .text {
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -8,8 +8,8 @@
|
|||||||
|
|
||||||
<div class="_section">
|
<div class="_section">
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" style="margin-bottom: var(--margin)"/>
|
<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_vMargin"/>
|
||||||
<XNote v-model:note="note" :key="note.id" :detail="true"/>
|
<XNote v-model:note="note" :key="note.id" :detail="true" class="_vMargin"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, defineAsyncComponent } from 'vue';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { faPlus, faQuestion } from '@fortawesome/free-solid-svg-icons';
|
import { faPlus, faQuestion } from '@fortawesome/free-solid-svg-icons';
|
||||||
import XContainer from '../page-editor.container.vue';
|
import XContainer from '../page-editor.container.vue';
|
||||||
@@ -34,7 +34,8 @@ import * as os from '@/os';
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XContainer, MkSelect
|
XContainer, MkSelect,
|
||||||
|
XBlocks: defineAsyncComponent(() => import('../page-editor.blocks.vue')),
|
||||||
},
|
},
|
||||||
|
|
||||||
inject: ['getPageBlockList'],
|
inject: ['getPageBlockList'],
|
||||||
@@ -54,10 +55,6 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeCreate() {
|
|
||||||
this.$options.components.XBlocks = require('../page-editor.blocks.vue').default
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.value.children == null) this.value.children = [];
|
if (this.value.children == null) this.value.children = [];
|
||||||
if (this.value.var === undefined) this.value.var = null;
|
if (this.value.var === undefined) this.value.var = null;
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent, defineAsyncComponent } from 'vue';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
|
import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
|
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
|
||||||
@@ -26,7 +26,8 @@ import * as os from '@/os';
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XContainer
|
XContainer,
|
||||||
|
XBlocks: defineAsyncComponent(() => import('../page-editor.blocks.vue')),
|
||||||
},
|
},
|
||||||
|
|
||||||
inject: ['getPageBlockList'],
|
inject: ['getPageBlockList'],
|
||||||
@@ -46,10 +47,6 @@ export default defineComponent({
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeCreate() {
|
|
||||||
this.$options.components.XBlocks = require('../page-editor.blocks.vue').default
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.value.title == null) this.value.title = null;
|
if (this.value.title == null) this.value.title = null;
|
||||||
if (this.value.children == null) this.value.children = [];
|
if (this.value.children == null) this.value.children = [];
|
||||||
|
@@ -28,7 +28,6 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { faBars, faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
|
import { faBars, faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
|
import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
|
||||||
import * as os from '@/os';
|
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
|
@@ -56,7 +56,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineAsyncComponent, defineComponent } from 'vue';
|
||||||
import { faPencilAlt, faPlug } from '@fortawesome/free-solid-svg-icons';
|
import { faPencilAlt, faPlug } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import XContainer from './page-editor.container.vue';
|
import XContainer from './page-editor.container.vue';
|
||||||
@@ -66,7 +66,8 @@ import * as os from '@/os';
|
|||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XContainer, MkTextarea
|
XContainer, MkTextarea,
|
||||||
|
XV: defineAsyncComponent(() => import('./page-editor.script-block.vue')),
|
||||||
},
|
},
|
||||||
|
|
||||||
inject: ['getScriptBlockList'],
|
inject: ['getScriptBlockList'],
|
||||||
@@ -135,10 +136,6 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeCreate() {
|
|
||||||
this.$options.components.XV = require('./page-editor.script-block.vue').default;
|
|
||||||
},
|
|
||||||
|
|
||||||
created() {
|
created() {
|
||||||
if (this.value.value == null) this.value.value = null;
|
if (this.value.value == null) this.value.value = null;
|
||||||
|
|
||||||
|
@@ -2,17 +2,19 @@
|
|||||||
<div>
|
<div>
|
||||||
<MkTab v-model:value="tab" :items="[{ label: $t('_pages.my'), value: 'my', icon: faEdit }, { label: $t('_pages.liked'), value: 'liked', icon: faHeart }]"/>
|
<MkTab v-model:value="tab" :items="[{ label: $t('_pages.my'), value: 'my', icon: faEdit }, { label: $t('_pages.liked'), value: 'liked', icon: faHeart }]"/>
|
||||||
|
|
||||||
<div class="rknalgpo my" v-if="tab === 'my'">
|
<div class="_section">
|
||||||
<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
|
<div class="rknalgpo _content my" v-if="tab === 'my'">
|
||||||
<MkPagination :pagination="myPagesPagination" #default="{items}">
|
<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
|
||||||
<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
|
<MkPagination :pagination="myPagesPagination" #default="{items}">
|
||||||
</MkPagination>
|
<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
|
||||||
</div>
|
</MkPagination>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="rknalgpo" v-if="tab === 'liked'">
|
<div class="rknalgpo _content" v-if="tab === 'liked'">
|
||||||
<MkPagination :pagination="likedPagesPagination" #default="{items}">
|
<MkPagination :pagination="likedPagesPagination" #default="{items}">
|
||||||
<MkPagePreview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/>
|
<MkPagePreview v-for="like in items" class="ckltabjg" :page="like.page" :key="like.page.id"/>
|
||||||
</MkPagination>
|
</MkPagination>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -64,8 +66,6 @@ export default defineComponent({
|
|||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.rknalgpo {
|
.rknalgpo {
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
&.my .ckltabjg:first-child {
|
&.my .ckltabjg:first-child {
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
}
|
}
|
||||||
|
@@ -44,6 +44,7 @@ export default defineComponent({
|
|||||||
this.exportTarget == 'following' ? 'i/export-following' :
|
this.exportTarget == 'following' ? 'i/export-following' :
|
||||||
this.exportTarget == 'blocking' ? 'i/export-blocking' :
|
this.exportTarget == 'blocking' ? 'i/export-blocking' :
|
||||||
this.exportTarget == 'user-lists' ? 'i/export-user-lists' :
|
this.exportTarget == 'user-lists' ? 'i/export-user-lists' :
|
||||||
|
this.exportTarget == 'mute' ? 'i/export-mute' :
|
||||||
null, {})
|
null, {})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
os.dialog({
|
os.dialog({
|
||||||
@@ -69,31 +70,15 @@ export default defineComponent({
|
|||||||
data.append('file', file);
|
data.append('file', file);
|
||||||
data.append('i', this.$store.state.i.token);
|
data.append('i', this.$store.state.i.token);
|
||||||
|
|
||||||
const dialog = os.dialog({
|
const promise = fetch(apiUrl + '/drive/files/create', {
|
||||||
type: 'waiting',
|
|
||||||
text: this.$t('uploading') + '...',
|
|
||||||
showOkButton: false,
|
|
||||||
showCancelButton: false,
|
|
||||||
cancelableByBgClick: false
|
|
||||||
});
|
|
||||||
|
|
||||||
fetch(apiUrl + '/drive/files/create', {
|
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: data
|
body: data
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(f => {
|
.then(f => {
|
||||||
this.reqImport(f);
|
this.reqImport(f);
|
||||||
})
|
|
||||||
.catch(e => {
|
|
||||||
os.dialog({
|
|
||||||
type: 'error',
|
|
||||||
text: e
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
dialog.close();
|
|
||||||
});
|
});
|
||||||
|
os.promiseDialog(promise);
|
||||||
},
|
},
|
||||||
|
|
||||||
reqImport(file) {
|
reqImport(file) {
|
||||||
|
@@ -106,6 +106,14 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="_card _vMargin">
|
||||||
|
<div class="_title">Waiting dialog</div>
|
||||||
|
<div class="_content">
|
||||||
|
<MkButton inline @click="openWaitingDialog()">icon only</MkButton>
|
||||||
|
<MkButton inline @click="openWaitingDialog('Doing')">with text</MkButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="_card _vMargin">
|
<div class="_card _vMargin">
|
||||||
<div class="_title">Messaging window</div>
|
<div class="_title">Messaging window</div>
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
@@ -224,6 +232,13 @@ export default defineComponent({
|
|||||||
os.pageWindow('/my/messaging', defineAsyncComponent(() => import('@/pages/messaging/index.vue')));
|
os.pageWindow('/my/messaging', defineAsyncComponent(() => import('@/pages/messaging/index.vue')));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openWaitingDialog(text?) {
|
||||||
|
const promise = new Promise((resolve, reject) => {
|
||||||
|
setTimeout(resolve, 2000);
|
||||||
|
});
|
||||||
|
os.promiseDialog(promise, null, null, text);
|
||||||
|
},
|
||||||
|
|
||||||
resetTutorial() {
|
resetTutorial() {
|
||||||
this.$store.dispatch('settings/set', { key: 'tutorial', value: 0 });
|
this.$store.dispatch('settings/set', { key: 'tutorial', value: 0 });
|
||||||
},
|
},
|
||||||
|
@@ -75,6 +75,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
<section class="_section">
|
||||||
|
<details class="_content">
|
||||||
|
<summary>{{ $t('sample') }}</summary>
|
||||||
|
<MkSample/>
|
||||||
|
</details>
|
||||||
|
</section>
|
||||||
<section class="_section">
|
<section class="_section">
|
||||||
<div class="_content">
|
<div class="_content">
|
||||||
<MkButton inline @click="preview">{{ $t('preview') }}</MkButton>
|
<MkButton inline @click="preview">{{ $t('preview') }}</MkButton>
|
||||||
@@ -88,16 +94,17 @@
|
|||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import { faPalette, faChevronDown, faKeyboard } from '@fortawesome/free-solid-svg-icons';
|
import { faPalette, faChevronDown, faKeyboard } from '@fortawesome/free-solid-svg-icons';
|
||||||
import * as JSON5 from 'json5';
|
import * as JSON5 from 'json5';
|
||||||
|
import { toUnicode } from 'punycode';
|
||||||
|
|
||||||
import MkRadio from '@/components/ui/radio.vue';
|
import MkRadio from '@/components/ui/radio.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 MkTextarea from '@/components/ui/textarea.vue';
|
import MkTextarea from '@/components/ui/textarea.vue';
|
||||||
import MkSelect from '@/components/ui/select.vue';
|
import MkSelect from '@/components/ui/select.vue';
|
||||||
|
import MkSample from '@/components/sample.vue';
|
||||||
|
|
||||||
import { convertToMisskeyTheme, ThemeValue, convertToViewModel, ThemeViewModel } from '@/scripts/theme-editor';
|
import { convertToMisskeyTheme, ThemeValue, convertToViewModel, ThemeViewModel } from '@/scripts/theme-editor';
|
||||||
import { Theme, applyTheme, lightTheme, darkTheme, themeProps, validateTheme } from '@/scripts/theme';
|
import { Theme, applyTheme, lightTheme, darkTheme, themeProps, validateTheme } from '@/scripts/theme';
|
||||||
import { toUnicode } from 'punycode';
|
|
||||||
import { host } from '@/config';
|
import { host } from '@/config';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
|
||||||
@@ -107,7 +114,8 @@ export default defineComponent({
|
|||||||
MkButton,
|
MkButton,
|
||||||
MkInput,
|
MkInput,
|
||||||
MkTextarea,
|
MkTextarea,
|
||||||
MkSelect
|
MkSelect,
|
||||||
|
MkSample,
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
|
@@ -49,47 +49,63 @@ export default defineComponent({
|
|||||||
menuOpened: false,
|
menuOpened: false,
|
||||||
queue: 0,
|
queue: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
INFO: {
|
INFO: computed(() => {
|
||||||
header: [{
|
const header = [{
|
||||||
id: 'home',
|
id: 'home',
|
||||||
title: null,
|
title: null,
|
||||||
tooltip: this.$t('_timelines.home'),
|
tooltip: this.$t('_timelines.home'),
|
||||||
icon: faHome,
|
icon: faHome,
|
||||||
onClick: () => { this.src = 'home'; this.saveSrc(); },
|
onClick: () => { this.src = 'home'; this.saveSrc(); },
|
||||||
selected: computed(() => this.src === 'home')
|
selected: computed(() => this.src === 'home')
|
||||||
}, {
|
}];
|
||||||
id: 'local',
|
|
||||||
title: null,
|
if (!this.$store.state.instance.meta.disableLocalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin) {
|
||||||
tooltip: this.$t('_timelines.local'),
|
header.push({
|
||||||
icon: faComments,
|
id: 'local',
|
||||||
onClick: () => { this.src = 'local'; this.saveSrc(); },
|
title: null,
|
||||||
selected: computed(() => this.src === 'local')
|
tooltip: this.$t('_timelines.local'),
|
||||||
}, {
|
icon: faComments,
|
||||||
id: 'social',
|
onClick: () => { this.src = 'local'; this.saveSrc(); },
|
||||||
title: null,
|
selected: computed(() => this.src === 'local')
|
||||||
tooltip: this.$t('_timelines.social'),
|
});
|
||||||
icon: faShareAlt,
|
|
||||||
onClick: () => { this.src = 'social'; this.saveSrc(); },
|
header.push({
|
||||||
selected: computed(() => this.src === 'social')
|
id: 'social',
|
||||||
}, {
|
title: null,
|
||||||
id: 'global',
|
tooltip: this.$t('_timelines.social'),
|
||||||
title: null,
|
icon: faShareAlt,
|
||||||
tooltip: this.$t('_timelines.global'),
|
onClick: () => { this.src = 'social'; this.saveSrc(); },
|
||||||
icon: faGlobe,
|
selected: computed(() => this.src === 'social')
|
||||||
onClick: () => { this.src = 'global'; this.saveSrc(); },
|
});
|
||||||
selected: computed(() => this.src === 'global')
|
}
|
||||||
}, {
|
|
||||||
|
if (!this.$store.state.instance.meta.disableGlobalTimeline || this.$store.state.i.isModerator || this.$store.state.i.isAdmin) {
|
||||||
|
header.push({
|
||||||
|
id: 'global',
|
||||||
|
title: null,
|
||||||
|
tooltip: this.$t('_timelines.global'),
|
||||||
|
icon: faGlobe,
|
||||||
|
onClick: () => { this.src = 'global'; this.saveSrc(); },
|
||||||
|
selected: computed(() => this.src === 'global')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
header.push({
|
||||||
id: 'other',
|
id: 'other',
|
||||||
title: null,
|
title: null,
|
||||||
icon: faEllipsisH,
|
icon: faEllipsisH,
|
||||||
onClick: this.choose,
|
onClick: this.choose,
|
||||||
indicate: computed(() => this.$store.state.i.hasUnreadAntenna || this.$store.state.i.hasUnreadChannel)
|
indicate: computed(() => this.$store.state.i.hasUnreadAntenna || this.$store.state.i.hasUnreadChannel)
|
||||||
}],
|
});
|
||||||
action: {
|
|
||||||
icon: faPencilAlt,
|
return {
|
||||||
handler: () => os.post()
|
header,
|
||||||
}
|
action: {
|
||||||
},
|
icon: faPencilAlt,
|
||||||
|
handler: () => os.post()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}),
|
||||||
faAngleDown, faAngleUp, faHome, faShareAlt, faGlobe, faComments, faListUl, faSatellite, faSatelliteDish, faCircle
|
faAngleDown, faAngleUp, faHome, faShareAlt, faGlobe, faComments, faListUl, faSatellite, faSatelliteDish, faCircle
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mk-user-page" v-if="user" v-size="{ max: [500] }">
|
<div class="mk-user-page" v-if="user" v-size="{ max: [500] }">
|
||||||
<MkRemoteCaution v-if="user.host != null" :href="user.url" style="margin-bottom: var(--margin)"/>
|
|
||||||
|
|
||||||
<!-- TODO -->
|
<!-- TODO -->
|
||||||
<!-- <div class="punished" v-if="user.isSuspended"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/> {{ $t('userSuspended') }}</div> -->
|
<!-- <div class="punished" v-if="user.isSuspended"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/> {{ $t('userSuspended') }}</div> -->
|
||||||
<!-- <div class="punished" v-if="user.isSilenced"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/> {{ $t('userSilenced') }}</div> -->
|
<!-- <div class="punished" v-if="user.isSilenced"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/> {{ $t('userSilenced') }}</div> -->
|
||||||
|
|
||||||
<div class="profile _section _fitBottom">
|
<div class="profile _section _fitBottom">
|
||||||
<div class="_content" :key="user.id">
|
<MkRemoteCaution v-if="user.host != null" :href="user.url" class="_content _vMargin"/>
|
||||||
|
|
||||||
|
<div class="_content _vMargin" :key="user.id">
|
||||||
<div class="banner-container" :style="style">
|
<div class="banner-container" :style="style">
|
||||||
<div class="banner" ref="banner" :style="style"></div>
|
<div class="banner" ref="banner" :style="style"></div>
|
||||||
<div class="fade"></div>
|
<div class="fade"></div>
|
||||||
@@ -85,8 +85,8 @@
|
|||||||
|
|
||||||
<router-view :user="user"></router-view>
|
<router-view :user="user"></router-view>
|
||||||
<template v-if="$route.name == 'user'">
|
<template v-if="$route.name == 'user'">
|
||||||
<div class="_section" v-if="user.pinnedNotes.length > 0">
|
<div class="_section">
|
||||||
<div class="_content _vMargin">
|
<div class="_content _vMargin" v-if="user.pinnedNotes.length > 0">
|
||||||
<XNote v-for="note in user.pinnedNotes" class="note _vMargin" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :detail="true" :pinned="true"/>
|
<XNote v-for="note in user.pinnedNotes" class="note _vMargin" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :detail="true" :pinned="true"/>
|
||||||
</div>
|
</div>
|
||||||
<MkFolder :body-togglable="true" class="_content _vMargin" persist-key="user-images">
|
<MkFolder :body-togglable="true" class="_content _vMargin" persist-key="user-images">
|
||||||
|
@@ -86,6 +86,7 @@ export const router = createRouter({
|
|||||||
{ path: '/instance/federation', component: page('instance/federation') },
|
{ path: '/instance/federation', component: page('instance/federation') },
|
||||||
{ path: '/instance/relays', component: page('instance/relays') },
|
{ path: '/instance/relays', component: page('instance/relays') },
|
||||||
{ path: '/instance/announcements', component: page('instance/announcements') },
|
{ path: '/instance/announcements', component: page('instance/announcements') },
|
||||||
|
{ path: '/instance/abuses', component: page('instance/abuses') },
|
||||||
{ path: '/notes/:note', name: 'note', component: page('note') },
|
{ path: '/notes/:note', name: 'note', component: page('note') },
|
||||||
{ path: '/tags/:tag', component: page('tag') },
|
{ path: '/tags/:tag', component: page('tag') },
|
||||||
{ path: '/auth/:token', component: page('auth') },
|
{ path: '/auth/:token', component: page('auth') },
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { faAt, faListUl, faEye, faEyeSlash, faBan, faPencilAlt, faComments, faUsers, faMicrophoneSlash, faPlug } from '@fortawesome/free-solid-svg-icons';
|
import { faAt, faListUl, faEye, faEyeSlash, faBan, faPencilAlt, faComments, faUsers, faMicrophoneSlash, faPlug, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
|
||||||
import { faSnowflake, faEnvelope } from '@fortawesome/free-regular-svg-icons';
|
import { faSnowflake, faEnvelope } from '@fortawesome/free-regular-svg-icons';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import copyToClipboard from '@/scripts/copy-to-clipboard';
|
import copyToClipboard from '@/scripts/copy-to-clipboard';
|
||||||
@@ -102,6 +102,12 @@ export function getUserMenu(user) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function reportAbuse() {
|
||||||
|
os.popup(await import('@/components/abuse-report-window.vue'), {
|
||||||
|
user: user,
|
||||||
|
}, {}, 'closed');
|
||||||
|
}
|
||||||
|
|
||||||
async function getConfirmed(text: string): Promise<boolean> {
|
async function getConfirmed(text: string): Promise<boolean> {
|
||||||
const confirm = await os.dialog({
|
const confirm = await os.dialog({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
@@ -157,6 +163,12 @@ export function getUserMenu(user) {
|
|||||||
action: toggleBlock
|
action: toggleBlock
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
|
menu = menu.concat([null, {
|
||||||
|
icon: faExclamationCircle,
|
||||||
|
text: i18n.global.t('reportAbuse'),
|
||||||
|
action: reportAbuse
|
||||||
|
}]);
|
||||||
|
|
||||||
if (store.getters.isSignedIn && (store.state.i.isAdmin || store.state.i.isModerator)) {
|
if (store.getters.isSignedIn && (store.state.i.isAdmin || store.state.i.isModerator)) {
|
||||||
menu = menu.concat([null, {
|
menu = menu.concat([null, {
|
||||||
icon: faMicrophoneSlash,
|
icon: faMicrophoneSlash,
|
||||||
|
@@ -7,6 +7,7 @@ import { createAiScriptEnv } from '../aiscript/api';
|
|||||||
import { collectPageVars } from '../collect-page-vars';
|
import { collectPageVars } from '../collect-page-vars';
|
||||||
import { initLib } from './lib';
|
import { initLib } from './lib';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
import { markRaw, ref, Ref } from 'vue';
|
||||||
|
|
||||||
type Fn = {
|
type Fn = {
|
||||||
slots: string[];
|
slots: string[];
|
||||||
@@ -23,7 +24,7 @@ export class Hpml {
|
|||||||
public aiscript?: AiScript;
|
public aiscript?: AiScript;
|
||||||
private pageVarUpdatedCallback;
|
private pageVarUpdatedCallback;
|
||||||
public canvases: Record<string, HTMLCanvasElement> = {};
|
public canvases: Record<string, HTMLCanvasElement> = {};
|
||||||
public vars: Record<string, any>;
|
public vars: Ref<Record<string, any>> = ref({});
|
||||||
public page: Record<string, any>;
|
public page: Record<string, any>;
|
||||||
|
|
||||||
private opts: {
|
private opts: {
|
||||||
@@ -38,7 +39,7 @@ export class Hpml {
|
|||||||
this.opts = opts;
|
this.opts = opts;
|
||||||
|
|
||||||
if (this.opts.enableAiScript) {
|
if (this.opts.enableAiScript) {
|
||||||
this.aiscript = new AiScript({ ...createAiScriptEnv({
|
this.aiscript = markRaw(new AiScript({ ...createAiScriptEnv({
|
||||||
storageKey: 'pages:' + this.page.id
|
storageKey: 'pages:' + this.page.id
|
||||||
}), ...initLib(this)}, {
|
}), ...initLib(this)}, {
|
||||||
in: (q) => {
|
in: (q) => {
|
||||||
@@ -56,7 +57,7 @@ export class Hpml {
|
|||||||
},
|
},
|
||||||
log: (type, params) => {
|
log: (type, params) => {
|
||||||
},
|
},
|
||||||
});
|
}));
|
||||||
|
|
||||||
this.aiscript.scope.opts.onUpdated = (name, value) => {
|
this.aiscript.scope.opts.onUpdated = (name, value) => {
|
||||||
this.eval();
|
this.eval();
|
||||||
@@ -89,7 +90,7 @@ export class Hpml {
|
|||||||
@autobind
|
@autobind
|
||||||
public eval() {
|
public eval() {
|
||||||
try {
|
try {
|
||||||
this.vars = this.evaluateVars();
|
this.vars.value = this.evaluateVars();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//this.onError(e);
|
//this.onError(e);
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,7 @@ export class Hpml {
|
|||||||
public interpolate(str: string) {
|
public interpolate(str: string) {
|
||||||
if (str == null) return null;
|
if (str == null) return null;
|
||||||
return str.replace(/{(.+?)}/g, match => {
|
return str.replace(/{(.+?)}/g, match => {
|
||||||
const v = this.vars ? this.vars[match.slice(1, -1).trim()] : null;
|
const v = this.vars[match.slice(1, -1).trim()];
|
||||||
return v == null ? 'NULL' : v.toString();
|
return v == null ? 'NULL' : v.toString();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -13,7 +13,7 @@ export function popout(path: string, w?: HTMLElement) {
|
|||||||
`width=${width}, height=${height}, top=${y}, left=${x}`);
|
`width=${width}, height=${height}, top=${y}, left=${x}`);
|
||||||
} else {
|
} else {
|
||||||
const width = 400;
|
const width = 400;
|
||||||
const height = 450;
|
const height = 500;
|
||||||
const x = window.top.outerHeight / 2 + window.top.screenY - (height / 2);
|
const x = window.top.outerHeight / 2 + window.top.screenY - (height / 2);
|
||||||
const y = window.top.outerWidth / 2 + window.top.screenX - (width / 2);
|
const y = window.top.outerWidth / 2 + window.top.screenX - (width / 2);
|
||||||
window.open(url, url,
|
window.open(url, url,
|
||||||
|
@@ -48,27 +48,18 @@ export async function search(q?: string | null | undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (q.startsWith('https://')) {
|
if (q.startsWith('https://')) {
|
||||||
const dialog = os.dialog({
|
const promise = os.api('ap/show', {
|
||||||
type: 'waiting',
|
uri: q
|
||||||
text: i18n.global.t('fetchingAsApObject') + '...',
|
|
||||||
showOkButton: false,
|
|
||||||
showCancelButton: false,
|
|
||||||
cancelableByBgClick: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
os.promiseDialog(promise, null, null, i18n.global.t('fetchingAsApObject'));
|
||||||
const res = await os.api('ap/show', {
|
|
||||||
uri: q
|
const res = await promise;
|
||||||
});
|
|
||||||
dialog.cancel();
|
if (res.type === 'User') {
|
||||||
if (res.type === 'User') {
|
router.push(`/@${res.object.username}@${res.object.host}`);
|
||||||
router.push(`/@${res.object.username}@${res.object.host}`);
|
} else if (res.type === 'Note') {
|
||||||
} else if (res.type === 'Note') {
|
router.push(`/notes/${res.object.id}`);
|
||||||
router.push(`/notes/${res.object.id}`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
dialog.cancel();
|
|
||||||
// TODO: Show error
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@@ -6,7 +6,7 @@ export type Theme = {
|
|||||||
author: string;
|
author: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
base?: 'dark' | 'light';
|
base?: 'dark' | 'light';
|
||||||
props: { [key: string]: string };
|
props: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const lightTheme: Theme = require('../themes/_light.json5');
|
export const lightTheme: Theme = require('../themes/_light.json5');
|
||||||
@@ -15,18 +15,19 @@ export const darkTheme: Theme = require('../themes/_dark.json5');
|
|||||||
export const themeProps = Object.keys(lightTheme.props).filter(key => !key.startsWith('X'));
|
export const themeProps = Object.keys(lightTheme.props).filter(key => !key.startsWith('X'));
|
||||||
|
|
||||||
export const builtinThemes = [
|
export const builtinThemes = [
|
||||||
require('../themes/white.json5'),
|
require('../themes/l-white.json5'),
|
||||||
require('../themes/black.json5'),
|
require('../themes/l-red.json5'),
|
||||||
require('../themes/lilac.json5'),
|
require('../themes/l-green.json5'),
|
||||||
require('../themes/halloween.json5'),
|
require('../themes/l-blue.json5'),
|
||||||
require('../themes/city.json5'),
|
require('../themes/l-apricot.json5'),
|
||||||
require('../themes/rainy.json5'),
|
|
||||||
require('../themes/urban.json5'),
|
require('../themes/d-black.json5'),
|
||||||
require('../themes/cafe.json5'),
|
require('../themes/d-red.json5'),
|
||||||
require('../themes/chocolate.json5'),
|
require('../themes/d-green.json5'),
|
||||||
require('../themes/danboard.json5'),
|
require('../themes/d-blue.json5'),
|
||||||
require('../themes/olive.json5'),
|
require('../themes/d-persimmon.json5'),
|
||||||
require('../themes/ocean.json5'),
|
|
||||||
|
require('../themes/d-battery-saver.json5'),
|
||||||
] as Theme[];
|
] as Theme[];
|
||||||
|
|
||||||
let timeout = null;
|
let timeout = null;
|
||||||
|
@@ -61,7 +61,7 @@ export const defaultDeviceSettings = {
|
|||||||
accounts: [],
|
accounts: [],
|
||||||
recentEmojis: [],
|
recentEmojis: [],
|
||||||
themes: [],
|
themes: [],
|
||||||
darkTheme: '8c539dc1-0fab-4d47-9194-39c508e9bfe1',
|
darkTheme: '8050783a-7f63-445a-b270-36d0f6ba1677',
|
||||||
lightTheme: '4eea646f-7afa-4645-83e9-83af0333cd37',
|
lightTheme: '4eea646f-7afa-4645-83e9-83af0333cd37',
|
||||||
darkMode: false,
|
darkMode: false,
|
||||||
deckMode: false,
|
deckMode: false,
|
||||||
|
@@ -109,6 +109,11 @@ textarea, input {
|
|||||||
-webkit-tap-highlight-color: transparent;
|
-webkit-tap-highlight-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
optgroup, option {
|
||||||
|
background: var(--panel);
|
||||||
|
color: var(--fg);
|
||||||
|
}
|
||||||
|
|
||||||
hr {
|
hr {
|
||||||
margin: var(--margin) 0 var(--margin) 0;
|
margin: var(--margin) 0 var(--margin) 0;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -319,6 +324,7 @@ hr {
|
|||||||
|
|
||||||
> ._title,
|
> ._title,
|
||||||
> ._content {
|
> ._content {
|
||||||
|
box-sizing: border-box;
|
||||||
max-width: var(--baseContentWidth);
|
max-width: var(--baseContentWidth);
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
id: 'bd6577b4-8154-4a2d-b7ce-7bf59f1fa3f5',
|
|
||||||
|
|
||||||
name: 'Chocolate',
|
|
||||||
author: 'syuilo',
|
|
||||||
desc: 'So sweet',
|
|
||||||
|
|
||||||
base: 'dark',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: 'rgb(199, 69, 32)',
|
|
||||||
bg: 'rgb(35, 25, 21)',
|
|
||||||
fg: 'rgb(216, 208, 199)',
|
|
||||||
panel: 'rgb(64, 39, 27)',
|
|
||||||
renote: '@accent',
|
|
||||||
link: '@accent',
|
|
||||||
mention: '@accent',
|
|
||||||
hashtag: '@accent',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
id: '8e4aa0ab-a439-43c8-b67d-16d5c03936de',
|
|
||||||
|
|
||||||
name: 'City',
|
|
||||||
author: 'Zheneha',
|
|
||||||
|
|
||||||
base: 'dark',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: 'rgb(255, 153, 0)',
|
|
||||||
panel: 'rgb(30, 30, 30)',
|
|
||||||
bg: 'rgb(0, 0, 0)',
|
|
||||||
fg: 'rgb(255, 255, 255)',
|
|
||||||
infoFg: '@accent',
|
|
||||||
infoBg: 'rgb(0, 0, 0)',
|
|
||||||
header: 'rgb(37, 37, 37)',
|
|
||||||
mention: '@accent',
|
|
||||||
hashtag: '@accent',
|
|
||||||
link: '@accent',
|
|
||||||
renote: 'rgb(118, 179, 40)',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,9 +1,8 @@
|
|||||||
{
|
{
|
||||||
id: '8c539dc1-0fab-4d47-9194-39c508e9bfe1',
|
id: '8c539dc1-0fab-4d47-9194-39c508e9bfe1',
|
||||||
|
|
||||||
name: 'Black',
|
name: 'Battery Saver',
|
||||||
author: 'syuilo',
|
author: 'syuilo',
|
||||||
desc: 'Basic dark theme',
|
|
||||||
|
|
||||||
base: 'dark',
|
base: 'dark',
|
||||||
|
|
29
src/client/themes/d-black.json5
Normal file
29
src/client/themes/d-black.json5
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
id: '8050783a-7f63-445a-b270-36d0f6ba1677',
|
||||||
|
|
||||||
|
name: 'Mi Black',
|
||||||
|
author: 'syuilo',
|
||||||
|
desc: 'Default light theme',
|
||||||
|
|
||||||
|
base: 'dark',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
bg: '#272727',
|
||||||
|
fg: 'rgb(199, 209, 216)',
|
||||||
|
fgHighlighted: '#fff',
|
||||||
|
divider: 'rgba(255, 255, 255, 0.14)',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderBg: '@panel',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
infoFg: '@accent',
|
||||||
|
infoBg: 'rgb(0, 0, 0)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: '#363636',
|
||||||
|
renote: '@accent',
|
||||||
|
mention: '#da6d35',
|
||||||
|
mentionMe: '#d44c4c',
|
||||||
|
hashtag: '#4cb8d4',
|
||||||
|
link: '@accent',
|
||||||
|
},
|
||||||
|
}
|
29
src/client/themes/d-blue.json5
Normal file
29
src/client/themes/d-blue.json5
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
id: 'ab4eb6d5-dcc0-4457-8a3c-98aad8ea3979',
|
||||||
|
|
||||||
|
name: 'Mi D Blue',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'dark',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
accent: 'rgb(81 185 189)',
|
||||||
|
bg: 'rgb(54, 54, 54)',
|
||||||
|
fg: 'rgb(199, 209, 216)',
|
||||||
|
fgHighlighted: '#fff',
|
||||||
|
divider: 'rgba(255, 255, 255, 0.14)',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderBg: '@panel',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
infoFg: '@accent',
|
||||||
|
infoBg: 'rgb(0, 0, 0)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: 'rgb(71, 71, 71)',
|
||||||
|
renote: '@accent',
|
||||||
|
mention: '#da6d35',
|
||||||
|
mentionMe: '#d44c4c',
|
||||||
|
hashtag: '#4cb8d4',
|
||||||
|
link: '@accent',
|
||||||
|
},
|
||||||
|
}
|
29
src/client/themes/d-green.json5
Normal file
29
src/client/themes/d-green.json5
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
id: '326dc4bf-29d9-45b4-889e-bdc33e84919b',
|
||||||
|
|
||||||
|
name: 'Mi D Green',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'dark',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
accent: 'rgb(152, 196, 69)',
|
||||||
|
bg: 'rgb(54, 54, 54)',
|
||||||
|
fg: 'rgb(199, 209, 216)',
|
||||||
|
fgHighlighted: '#fff',
|
||||||
|
divider: 'rgba(255, 255, 255, 0.14)',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderBg: '@panel',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
infoFg: '@accent',
|
||||||
|
infoBg: 'rgb(0, 0, 0)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: 'rgb(71, 71, 71)',
|
||||||
|
renote: '@accent',
|
||||||
|
mention: '#da6d35',
|
||||||
|
mentionMe: '#d44c4c',
|
||||||
|
hashtag: '#4cb8d4',
|
||||||
|
link: '@accent',
|
||||||
|
},
|
||||||
|
}
|
29
src/client/themes/d-persimmon.json5
Normal file
29
src/client/themes/d-persimmon.json5
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
id: 'c503d768-7c70-4db2-a4e6-08264304bc8d',
|
||||||
|
|
||||||
|
name: 'Ai Persimmon',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'dark',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
accent: 'rgb(206, 102, 65)',
|
||||||
|
bg: 'rgb(41, 43, 41)',
|
||||||
|
fg: '#cdd8c7',
|
||||||
|
fgHighlighted: '#fff',
|
||||||
|
divider: 'rgba(255, 255, 255, 0.14)',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderBg: '@panel',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
infoFg: '@accent',
|
||||||
|
infoBg: 'rgb(0, 0, 0)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: '#1f211f',
|
||||||
|
renote: '@accent',
|
||||||
|
mention: '@accent',
|
||||||
|
mentionMe: '#de6161',
|
||||||
|
hashtag: '#68bad0',
|
||||||
|
link: '#a1c758',
|
||||||
|
},
|
||||||
|
}
|
29
src/client/themes/d-red.json5
Normal file
29
src/client/themes/d-red.json5
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
id: '60960086-26da-4f3c-bb0c-f6a4f89e0f60',
|
||||||
|
|
||||||
|
name: 'Mi D Red',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'dark',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
accent: 'rgb(196 115 69)',
|
||||||
|
bg: 'rgb(54, 54, 54)',
|
||||||
|
fg: 'rgb(199, 209, 216)',
|
||||||
|
fgHighlighted: '#fff',
|
||||||
|
divider: 'rgba(255, 255, 255, 0.14)',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderBg: '@panel',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
infoFg: '@accent',
|
||||||
|
infoBg: 'rgb(0, 0, 0)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: 'rgb(71, 71, 71)',
|
||||||
|
renote: '@accent',
|
||||||
|
mention: '#da6d35',
|
||||||
|
mentionMe: '#d44c4c',
|
||||||
|
hashtag: '#4cb8d4',
|
||||||
|
link: '@accent',
|
||||||
|
},
|
||||||
|
}
|
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
id: '17587283-dd92-4a2c-a22c-be0637c9e22a',
|
|
||||||
|
|
||||||
name: 'Danboard',
|
|
||||||
author: 'syuilo',
|
|
||||||
|
|
||||||
base: 'light',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: 'rgb(218, 141, 49)',
|
|
||||||
bg: 'rgb(218, 212, 190)',
|
|
||||||
fg: 'rgb(115, 108, 92)',
|
|
||||||
panel: 'rgb(236, 232, 220)',
|
|
||||||
renote: 'rgb(100, 152, 106)',
|
|
||||||
link: 'rgb(100, 152, 106)',
|
|
||||||
mention: '@accent',
|
|
||||||
hashtag: 'rgb(100, 152, 106)',
|
|
||||||
header: 'rgba(239, 227, 213, 0.75)',
|
|
||||||
navBg: 'rgb(216, 206, 182)',
|
|
||||||
inputBorder: 'rgba(0, 0, 0, 0.1)',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
id: '42e4f09b-67d5-498c-af7d-29faa54745b0',
|
|
||||||
|
|
||||||
name: 'Halloween',
|
|
||||||
author: 'syuilo',
|
|
||||||
desc: 'Hello, Happy Halloween!',
|
|
||||||
|
|
||||||
base: 'dark',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: '#d67036',
|
|
||||||
panel: '#1f1d30',
|
|
||||||
bg: '#0f0e17',
|
|
||||||
fg: '#b1bee3',
|
|
||||||
renote: '@accent',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
id: '0ff48d43-aab3-46e7-ab12-8492110d2e2b',
|
id: '0ff48d43-aab3-46e7-ab12-8492110d2e2b',
|
||||||
|
|
||||||
name: 'Cafe',
|
name: 'Ai Apricot',
|
||||||
author: 'syuilo',
|
author: 'syuilo',
|
||||||
|
|
||||||
base: 'light',
|
base: 'light',
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
accent: 'rgb(234, 154, 82)',
|
accent: 'rgb(234, 154, 82)',
|
||||||
bg: '#DDD9D1',
|
bg: '#e6e5e2',
|
||||||
fg: 'rgb(149, 143, 139)',
|
fg: 'rgb(149, 143, 139)',
|
||||||
panel: '#EEECE8',
|
panel: '#EEECE8',
|
||||||
renote: '@accent',
|
renote: '@accent',
|
21
src/client/themes/l-blue.json5
Normal file
21
src/client/themes/l-blue.json5
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
id: 'ad18a23b-6af6-4af0-9ed4-600568250574',
|
||||||
|
|
||||||
|
name: 'Mi L Blue',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'light',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
accent: '#4dbccc',
|
||||||
|
bg: '#fff',
|
||||||
|
fg: '#5d5d5d',
|
||||||
|
divider: 'rgb(223, 223, 223)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: '@bg',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
messageBg: '#dedede',
|
||||||
|
},
|
||||||
|
}
|
21
src/client/themes/l-green.json5
Normal file
21
src/client/themes/l-green.json5
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
id: 'a55af79a-12bf-4f8d-a0cc-718957ad59b4',
|
||||||
|
|
||||||
|
name: 'Mi L Green',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'light',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
accent: '#8bcc4d',
|
||||||
|
bg: '#fff',
|
||||||
|
fg: '#5d5d5d',
|
||||||
|
divider: 'rgb(223, 223, 223)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: '@bg',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
messageBg: '#dedede',
|
||||||
|
},
|
||||||
|
}
|
21
src/client/themes/l-red.json5
Normal file
21
src/client/themes/l-red.json5
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
id: '957db7cb-30fb-4c80-bf0b-04198e7ae7e3',
|
||||||
|
|
||||||
|
name: 'Mi L Red',
|
||||||
|
author: 'syuilo',
|
||||||
|
|
||||||
|
base: 'light',
|
||||||
|
|
||||||
|
props: {
|
||||||
|
accent: '#fb734d',
|
||||||
|
bg: '#fff',
|
||||||
|
fg: '#5d5d5d',
|
||||||
|
divider: 'rgb(223, 223, 223)',
|
||||||
|
header: ':alpha<0.7<@bg',
|
||||||
|
navBg: '@bg',
|
||||||
|
panel: '@bg',
|
||||||
|
panelShadow: '" 0 0 0 1px var(--divider)',
|
||||||
|
panelHeaderDivider: '@divider',
|
||||||
|
messageBg: '#dedede',
|
||||||
|
},
|
||||||
|
}
|
@@ -1,16 +1,20 @@
|
|||||||
{
|
{
|
||||||
id: '4eea646f-7afa-4645-83e9-83af0333cd37',
|
id: '4eea646f-7afa-4645-83e9-83af0333cd37',
|
||||||
|
|
||||||
name: 'White',
|
name: 'Mi White',
|
||||||
author: 'syuilo',
|
author: 'syuilo',
|
||||||
desc: 'Basic light theme',
|
desc: 'Default light theme',
|
||||||
|
|
||||||
base: 'light',
|
base: 'light',
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
bg: '#F6F7F7',
|
bg: '#f9f9f9',
|
||||||
|
fg: '#636b71',
|
||||||
|
divider: 'rgb(223, 223, 223)',
|
||||||
header: ':alpha<0.7<@bg',
|
header: ':alpha<0.7<@bg',
|
||||||
navBg: '@bg',
|
navBg: '@bg',
|
||||||
|
panel: '#fff',
|
||||||
|
panelShadow: '" 0 8px 24px rgb(21 43 75 / 8%)',
|
||||||
panelHeaderDivider: '@divider',
|
panelHeaderDivider: '@divider',
|
||||||
messageBg: '#dedede',
|
messageBg: '#dedede',
|
||||||
},
|
},
|
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
id: 'e9c8c01d-9c15-48d0-9b5c-3d00843b5b36',
|
|
||||||
|
|
||||||
name: 'Lilac',
|
|
||||||
author: 'syuilo',
|
|
||||||
|
|
||||||
base: 'light',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: 'rgb(206, 147, 191)',
|
|
||||||
bg: 'rgb(253, 242, 243)',
|
|
||||||
fg: 'rgb(161, 139, 146)',
|
|
||||||
divider: '#ece7e7',
|
|
||||||
renote: '@accent',
|
|
||||||
link: '@accent',
|
|
||||||
mention: '@accent',
|
|
||||||
hashtag: '@accent',
|
|
||||||
panelHeaderDivider: '@divider',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,20 +0,0 @@
|
|||||||
{
|
|
||||||
id: '7e5e263e-c6c1-44e4-a3d2-39198e3cddb8',
|
|
||||||
|
|
||||||
name: 'Ocean',
|
|
||||||
author: 'simirall',
|
|
||||||
|
|
||||||
base: 'dark',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: '#1da1f2',
|
|
||||||
bg: '#10171E',
|
|
||||||
fg: '#fdfdfd',
|
|
||||||
panel: '#15202B',
|
|
||||||
header: 'rgba(20, 32, 43, 0.75)',
|
|
||||||
renote: '#17bf63',
|
|
||||||
link: '@accent',
|
|
||||||
mention: '@accent',
|
|
||||||
hashtag: '@accent',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,22 +0,0 @@
|
|||||||
{
|
|
||||||
id: '0d92cf9c-ed9e-42fe-b715-be4899f54d12',
|
|
||||||
|
|
||||||
name: 'Olive',
|
|
||||||
author: 'syuilo',
|
|
||||||
|
|
||||||
base: 'light',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: 'rgb(158, 177, 95)',
|
|
||||||
bg: 'rgb(230, 230, 223)',
|
|
||||||
fg: 'rgb(103, 115, 92)',
|
|
||||||
panel: 'rgb(243, 241, 233)',
|
|
||||||
renote: '@accent',
|
|
||||||
link: '@accent',
|
|
||||||
mention: '@accent',
|
|
||||||
hashtag: '@accent',
|
|
||||||
header: 'rgba(211, 214, 200, 0.75)',
|
|
||||||
navBg: 'rgb(220, 219, 206)',
|
|
||||||
inputBorder: 'rgba(0, 0, 0, 0.1)',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,16 +0,0 @@
|
|||||||
{
|
|
||||||
id: '2d7d1479-acb8-4e2e-85bb-565a2d8e6966',
|
|
||||||
|
|
||||||
name: 'Rainy',
|
|
||||||
author: 'syuilo',
|
|
||||||
|
|
||||||
base: 'light',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: 'rgb(147, 199, 206)',
|
|
||||||
bg: 'rgb(220, 229, 232)',
|
|
||||||
fg: 'rgb(139, 153, 161)',
|
|
||||||
renote: '@accent',
|
|
||||||
panelHeaderDivider: '@divider',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -1,18 +0,0 @@
|
|||||||
{
|
|
||||||
id: 'b9392635-8c3d-4397-aaf7-796e49781899',
|
|
||||||
|
|
||||||
name: 'Urban',
|
|
||||||
author: 'syuilo',
|
|
||||||
|
|
||||||
base: 'dark',
|
|
||||||
|
|
||||||
props: {
|
|
||||||
accent: 'rgb(212, 104, 48)',
|
|
||||||
panel: 'rgb(38, 44, 53)',
|
|
||||||
bg: 'rgb(26, 29, 33)',
|
|
||||||
fg: 'rgb(199, 209, 216)',
|
|
||||||
shadow: 'rgba(0, 0, 0, 0.2)',
|
|
||||||
header: 'rgba(51, 64, 72, 0.75)',
|
|
||||||
renote: '@accent',
|
|
||||||
},
|
|
||||||
}
|
|
@@ -293,6 +293,10 @@ export default defineComponent({
|
|||||||
|
|
||||||
> .spacer {
|
> .spacer {
|
||||||
height: 82px;
|
height: 82px;
|
||||||
|
|
||||||
|
@media (min-width: ($widgets-hide-threshold + 1px)) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -117,7 +117,6 @@ export default defineComponent({
|
|||||||
.mk-app {
|
.mk-app {
|
||||||
$header-height: 52px;
|
$header-height: 52px;
|
||||||
$ui-font-size: 1em; // TODO: どこかに集約したい
|
$ui-font-size: 1em; // TODO: どこかに集約したい
|
||||||
$widgets-hide-threshold: 1090px;
|
|
||||||
|
|
||||||
// ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
// ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
|
||||||
min-height: calc(var(--vh, 1vh) * 100);
|
min-height: calc(var(--vh, 1vh) * 100);
|
||||||
|
@@ -58,6 +58,8 @@ export type Source = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
mediaProxy?: string;
|
mediaProxy?: string;
|
||||||
|
|
||||||
|
signToActivityPubGet?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -5,6 +5,7 @@ import fetch, { HeadersInit } from 'node-fetch';
|
|||||||
import { HttpProxyAgent } from 'http-proxy-agent';
|
import { HttpProxyAgent } from 'http-proxy-agent';
|
||||||
import { HttpsProxyAgent } from 'https-proxy-agent';
|
import { HttpsProxyAgent } from 'https-proxy-agent';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
import { URL } from 'url';
|
||||||
|
|
||||||
export async function getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: HeadersInit) {
|
export async function getJson(url: string, accept = 'application/json, */*', timeout = 10000, headers?: HeadersInit) {
|
||||||
const res = await fetch(url, {
|
const res = await fetch(url, {
|
||||||
@@ -69,14 +70,14 @@ const _https = new https.Agent({
|
|||||||
* Get http proxy or non-proxy agent
|
* Get http proxy or non-proxy agent
|
||||||
*/
|
*/
|
||||||
export const httpAgent = config.proxy
|
export const httpAgent = config.proxy
|
||||||
? new HttpProxyAgent(config.proxy)
|
? new HttpProxyAgent(config.proxy) as unknown as http.Agent
|
||||||
: _http;
|
: _http;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get https proxy or non-proxy agent
|
* Get https proxy or non-proxy agent
|
||||||
*/
|
*/
|
||||||
export const httpsAgent = config.proxy
|
export const httpsAgent = config.proxy
|
||||||
? new HttpsProxyAgent(config.proxy)
|
? new HttpsProxyAgent(config.proxy) as unknown as https.Agent
|
||||||
: _https;
|
: _https;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -3,7 +3,6 @@ import { User } from './user';
|
|||||||
import { id } from '../id';
|
import { id } from '../id';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@Index(['userId', 'reporterId'], { unique: true })
|
|
||||||
export class AbuseUserReport {
|
export class AbuseUserReport {
|
||||||
@PrimaryColumn(id())
|
@PrimaryColumn(id())
|
||||||
public id: string;
|
public id: string;
|
||||||
@@ -16,13 +15,13 @@ export class AbuseUserReport {
|
|||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column(id())
|
@Column(id())
|
||||||
public userId: User['id'];
|
public targetUserId: User['id'];
|
||||||
|
|
||||||
@ManyToOne(type => User, {
|
@ManyToOne(type => User, {
|
||||||
onDelete: 'CASCADE'
|
onDelete: 'CASCADE'
|
||||||
})
|
})
|
||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public user: User | null;
|
public targetUser: User | null;
|
||||||
|
|
||||||
@Index()
|
@Index()
|
||||||
@Column(id())
|
@Column(id())
|
||||||
@@ -34,8 +33,42 @@ export class AbuseUserReport {
|
|||||||
@JoinColumn()
|
@JoinColumn()
|
||||||
public reporter: User | null;
|
public reporter: User | null;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
...id(),
|
||||||
|
nullable: true
|
||||||
|
})
|
||||||
|
public assigneeId: User['id'] | null;
|
||||||
|
|
||||||
|
@ManyToOne(type => User, {
|
||||||
|
onDelete: 'SET NULL'
|
||||||
|
})
|
||||||
|
@JoinColumn()
|
||||||
|
public assignee: User | null;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column('boolean', {
|
||||||
|
default: false
|
||||||
|
})
|
||||||
|
public resolved: boolean;
|
||||||
|
|
||||||
@Column('varchar', {
|
@Column('varchar', {
|
||||||
length: 512,
|
length: 2048,
|
||||||
})
|
})
|
||||||
public comment: string;
|
public comment: string;
|
||||||
|
|
||||||
|
//#region Denormalized fields
|
||||||
|
@Index()
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
comment: '[Denormalized]'
|
||||||
|
})
|
||||||
|
public targetUserHost: string | null;
|
||||||
|
|
||||||
|
@Index()
|
||||||
|
@Column('varchar', {
|
||||||
|
length: 128, nullable: true,
|
||||||
|
comment: '[Denormalized]'
|
||||||
|
})
|
||||||
|
public reporterHost: string | null;
|
||||||
|
//#endregion
|
||||||
}
|
}
|
||||||
|
@@ -15,14 +15,19 @@ export class AbuseUserReportRepository extends Repository<AbuseUserReport> {
|
|||||||
id: report.id,
|
id: report.id,
|
||||||
createdAt: report.createdAt,
|
createdAt: report.createdAt,
|
||||||
comment: report.comment,
|
comment: report.comment,
|
||||||
|
resolved: report.resolved,
|
||||||
reporterId: report.reporterId,
|
reporterId: report.reporterId,
|
||||||
userId: report.userId,
|
targetUserId: report.targetUserId,
|
||||||
|
assigneeId: report.assigneeId,
|
||||||
reporter: Users.pack(report.reporter || report.reporterId, null, {
|
reporter: Users.pack(report.reporter || report.reporterId, null, {
|
||||||
detail: true
|
detail: true
|
||||||
}),
|
}),
|
||||||
user: Users.pack(report.user || report.userId, null, {
|
targetUser: Users.pack(report.targetUser || report.targetUserId, null, {
|
||||||
detail: true
|
detail: true
|
||||||
}),
|
}),
|
||||||
|
assignee: report.assigneeId ? Users.pack(report.assignee || report.assigneeId, null, {
|
||||||
|
detail: true
|
||||||
|
}) : null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,8 +19,10 @@ export default async (actor: IRemoteUser, activity: IFlag): Promise<string> => {
|
|||||||
await AbuseUserReports.insert({
|
await AbuseUserReports.insert({
|
||||||
id: genId(),
|
id: genId(),
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
userId: users[0].id,
|
targetUserId: users[0].id,
|
||||||
|
targetUserHost: users[0].host,
|
||||||
reporterId: actor.id,
|
reporterId: actor.id,
|
||||||
|
reporterHost: actor.host,
|
||||||
comment: `${activity.content}\n${JSON.stringify(uris, null, 2)}`
|
comment: `${activity.content}\n${JSON.stringify(uris, null, 2)}`
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import * as http from 'http';
|
||||||
import * as https from 'https';
|
import * as https from 'https';
|
||||||
import { sign } from 'http-signature';
|
import { sign } from 'http-signature';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
@@ -7,6 +8,9 @@ import { ILocalUser } from '../../models/entities/user';
|
|||||||
import { UserKeypairs } from '../../models';
|
import { UserKeypairs } from '../../models';
|
||||||
import { ensure } from '../../prelude/ensure';
|
import { ensure } from '../../prelude/ensure';
|
||||||
import { getAgentByUrl } from '../../misc/fetch';
|
import { getAgentByUrl } from '../../misc/fetch';
|
||||||
|
import { URL } from 'url';
|
||||||
|
import got from 'got';
|
||||||
|
import * as Got from 'got';
|
||||||
|
|
||||||
export default async (user: ILocalUser, url: string, object: any) => {
|
export default async (user: ILocalUser, url: string, object: any) => {
|
||||||
const timeout = 10 * 1000;
|
const timeout = 10 * 1000;
|
||||||
@@ -62,3 +66,96 @@ export default async (user: ILocalUser, url: string, object: any) => {
|
|||||||
req.end(data);
|
req.end(data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get AP object with http-signature
|
||||||
|
* @param user http-signature user
|
||||||
|
* @param url URL to fetch
|
||||||
|
*/
|
||||||
|
export async function signedGet(url: string, user: ILocalUser) {
|
||||||
|
const timeout = 10 * 1000;
|
||||||
|
|
||||||
|
const keypair = await UserKeypairs.findOne({
|
||||||
|
userId: user.id
|
||||||
|
}).then(ensure);
|
||||||
|
|
||||||
|
const req = got.get<any>(url, {
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/activity+json, application/ld+json',
|
||||||
|
'User-Agent': config.userAgent,
|
||||||
|
},
|
||||||
|
responseType: 'json',
|
||||||
|
timeout,
|
||||||
|
hooks: {
|
||||||
|
beforeRequest: [
|
||||||
|
options => {
|
||||||
|
options.request = (url: URL, opt: http.RequestOptions, callback?: (response: any) => void) => {
|
||||||
|
// Select custom agent by URL
|
||||||
|
opt.agent = getAgentByUrl(url, false);
|
||||||
|
|
||||||
|
// Wrap original https?.request
|
||||||
|
const requestFunc = url.protocol === 'http:' ? http.request : https.request;
|
||||||
|
const clientRequest = requestFunc(url, opt, callback) as http.ClientRequest;
|
||||||
|
|
||||||
|
// HTTP-Signature
|
||||||
|
sign(clientRequest, {
|
||||||
|
authorizationHeaderName: 'Signature',
|
||||||
|
key: keypair.privateKey,
|
||||||
|
keyId: `${config.url}/users/${user.id}#main-key`,
|
||||||
|
headers: ['(request-target)', 'host', 'date', 'accept']
|
||||||
|
});
|
||||||
|
|
||||||
|
return clientRequest;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
retry: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await receiveResponce(req, 10 * 1024 * 1024);
|
||||||
|
|
||||||
|
return res.body;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive response (with size limit)
|
||||||
|
* @param req Request
|
||||||
|
* @param maxSize size limit
|
||||||
|
*/
|
||||||
|
export async function receiveResponce<T>(req: Got.CancelableRequest<Got.Response<T>>, maxSize: number) {
|
||||||
|
// 応答ヘッダでサイズチェック
|
||||||
|
req.on('response', (res: Got.Response) => {
|
||||||
|
const contentLength = res.headers['content-length'];
|
||||||
|
if (contentLength != null) {
|
||||||
|
const size = Number(contentLength);
|
||||||
|
if (size > maxSize) {
|
||||||
|
req.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 受信中のデータでサイズチェック
|
||||||
|
req.on('downloadProgress', (progress: Got.Progress) => {
|
||||||
|
if (progress.transferred > maxSize) {
|
||||||
|
req.cancel();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 応答取得 with ステータスコードエラーの整形
|
||||||
|
const res = await req.catch(e => {
|
||||||
|
if (e.name === 'HTTPError') {
|
||||||
|
const statusCode = (e as Got.HTTPError).response.statusCode;
|
||||||
|
const statusMessage = (e as Got.HTTPError).response.statusMessage;
|
||||||
|
throw {
|
||||||
|
name: `StatusError`,
|
||||||
|
statusCode,
|
||||||
|
message: `${statusCode} ${statusMessage}`,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
@@ -1,8 +1,13 @@
|
|||||||
|
import config from '../../config';
|
||||||
import { getJson } from '../../misc/fetch';
|
import { getJson } from '../../misc/fetch';
|
||||||
|
import { ILocalUser } from '../../models/entities/user';
|
||||||
|
import { getInstanceActor } from '../../services/instance-actor';
|
||||||
|
import { signedGet } from './request';
|
||||||
import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type';
|
import { IObject, isCollectionOrOrderedCollection, ICollection, IOrderedCollection } from './type';
|
||||||
|
|
||||||
export default class Resolver {
|
export default class Resolver {
|
||||||
private history: Set<string>;
|
private history: Set<string>;
|
||||||
|
private user?: ILocalUser;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.history = new Set();
|
this.history = new Set();
|
||||||
@@ -39,7 +44,13 @@ export default class Resolver {
|
|||||||
|
|
||||||
this.history.add(value);
|
this.history.add(value);
|
||||||
|
|
||||||
const object = await getJson(value, 'application/activity+json, application/ld+json');
|
if (config.signToActivityPubGet && !this.user) {
|
||||||
|
this.user = await getInstanceActor();
|
||||||
|
}
|
||||||
|
|
||||||
|
const object = this.user
|
||||||
|
? await signedGet(value, this.user)
|
||||||
|
: await getJson(value, 'application/activity+json, application/ld+json');
|
||||||
|
|
||||||
if (object == null || (
|
if (object == null || (
|
||||||
Array.isArray(object['@context']) ?
|
Array.isArray(object['@context']) ?
|
||||||
|
@@ -23,12 +23,50 @@ export const meta = {
|
|||||||
untilId: {
|
untilId: {
|
||||||
validator: $.optional.type(ID),
|
validator: $.optional.type(ID),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
state: {
|
||||||
|
validator: $.optional.nullable.str,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
reporterOrigin: {
|
||||||
|
validator: $.optional.str.or([
|
||||||
|
'combined',
|
||||||
|
'local',
|
||||||
|
'remote',
|
||||||
|
]),
|
||||||
|
default: 'combined'
|
||||||
|
},
|
||||||
|
|
||||||
|
targetUserOrigin: {
|
||||||
|
validator: $.optional.str.or([
|
||||||
|
'combined',
|
||||||
|
'local',
|
||||||
|
'remote',
|
||||||
|
]),
|
||||||
|
default: 'combined'
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default define(meta, async (ps) => {
|
export default define(meta, async (ps) => {
|
||||||
const query = makePaginationQuery(AbuseUserReports.createQueryBuilder('report'), ps.sinceId, ps.untilId);
|
const query = makePaginationQuery(AbuseUserReports.createQueryBuilder('report'), ps.sinceId, ps.untilId);
|
||||||
|
|
||||||
|
switch (ps.state) {
|
||||||
|
case 'resolved': query.andWhere('report.resolved = TRUE'); break;
|
||||||
|
case 'unresolved': query.andWhere('report.resolved = FALSE'); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ps.reporterOrigin) {
|
||||||
|
case 'local': query.andWhere('report.reporterHost IS NULL'); break;
|
||||||
|
case 'remote': query.andWhere('report.reporterHost IS NOT NULL'); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ps.targetUserOrigin) {
|
||||||
|
case 'local': query.andWhere('report.targetUserHost IS NULL'); break;
|
||||||
|
case 'remote': query.andWhere('report.targetUserHost IS NOT NULL'); break;
|
||||||
|
}
|
||||||
|
|
||||||
const reports = await query.take(ps.limit!).getMany();
|
const reports = await query.take(ps.limit!).getMany();
|
||||||
|
|
||||||
return await AbuseUserReports.packMany(reports);
|
return await AbuseUserReports.packMany(reports);
|
||||||
|
@@ -3,7 +3,6 @@ import { getConnection } from 'typeorm';
|
|||||||
|
|
||||||
export const meta = {
|
export const meta = {
|
||||||
requireCredential: true as const,
|
requireCredential: true as const,
|
||||||
requireAdmin: true,
|
|
||||||
requireModerator: true,
|
requireModerator: true,
|
||||||
|
|
||||||
desc: {
|
desc: {
|
||||||
|
@@ -16,12 +16,15 @@ export const meta = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default define(meta, async (ps) => {
|
export default define(meta, async (ps, me) => {
|
||||||
const report = await AbuseUserReports.findOne(ps.reportId);
|
const report = await AbuseUserReports.findOne(ps.reportId);
|
||||||
|
|
||||||
if (report == null) {
|
if (report == null) {
|
||||||
throw new Error('report not found');
|
throw new Error('report not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
await AbuseUserReports.delete(report.id);
|
await AbuseUserReports.update(report.id, {
|
||||||
|
resolved: true,
|
||||||
|
assigneeId: me.id,
|
||||||
|
});
|
||||||
});
|
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user