Compare commits
	
		
			34 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					2e537e618c | ||
| 
						 | 
					fe3b7a2ad3 | ||
| 
						 | 
					90db793fd0 | ||
| 
						 | 
					7bd2a6ad61 | ||
| 
						 | 
					745f4d2439 | ||
| 
						 | 
					254cfaea28 | ||
| 
						 | 
					d4da5a1eea | ||
| 
						 | 
					c0f8297414 | ||
| 
						 | 
					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 | 
							
								
								
									
										2613
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										2613
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -8,7 +8,7 @@
 | 
			
		||||
[](http://makeapullrequest.com)
 | 
			
		||||
[](https://github.com/humanetech-community/awesome-humane-tech)
 | 
			
		||||
 | 
			
		||||
**A forever evolving, sophisticated microblogging platform.**
 | 
			
		||||
**A forever evolving, professional microblogging platform.**
 | 
			
		||||
 | 
			
		||||
<p align="justify">
 | 
			
		||||
<a href="https://join.misskey.page/">Misskey</a> is a decentralized microblogging platform born on Earth.
 | 
			
		||||
 
 | 
			
		||||
@@ -14,8 +14,12 @@ noNotes: "لم يتم العثور على أية ملاحظات"
 | 
			
		||||
noNotifications: "ليس هناك أية اشعارات"
 | 
			
		||||
instance: "مثيل الخادم"
 | 
			
		||||
settings: "الاعدادات"
 | 
			
		||||
basicSettings: "الاعدادات الأساسية"
 | 
			
		||||
otherSettings: "إعدادات أخرى"
 | 
			
		||||
openInWindow: "افتح في نافذة جديدة"
 | 
			
		||||
profile: "الملف التعريفي"
 | 
			
		||||
timeline: "الخيط الزمني"
 | 
			
		||||
noAccountDescription: "لم يكتب هذا المستخدم سيرته بعد."
 | 
			
		||||
login: "لِج"
 | 
			
		||||
loggingIn: "جارٍ تسجيل الدخول"
 | 
			
		||||
logout: "الخروج"
 | 
			
		||||
@@ -32,18 +36,26 @@ copyContent: "انسخ المحتوى"
 | 
			
		||||
copyLink: "انسخ الرابط"
 | 
			
		||||
delete: "حذف"
 | 
			
		||||
deleteAndEdit: "إزالة وإعادة الصياغة"
 | 
			
		||||
deleteAndEditConfirm: "أمتأكد من حذف الملاحظة؟ ستفقد كل مشاركاتها، والتفاعلات، والردود عليها."
 | 
			
		||||
addToList: "أضفه إلى قائمة"
 | 
			
		||||
sendMessage: "أرسل رسالة"
 | 
			
		||||
copyUsername: "انسخ اسم المستخدم"
 | 
			
		||||
searchUser: "ابحث عن مستخدمين"
 | 
			
		||||
reply: "رد"
 | 
			
		||||
loadMore: "عرض المزيد"
 | 
			
		||||
youGotNewFollower: "يتابعك"
 | 
			
		||||
receiveFollowRequest: "تلقيت طلب متابعة"
 | 
			
		||||
followRequestAccepted: "قُبل طلب المتابعة"
 | 
			
		||||
mention: "أشر الى"
 | 
			
		||||
mentions: "الإشارات"
 | 
			
		||||
directNotes: "الملاحظات المباشرة"
 | 
			
		||||
importAndExport: "إستورد / صدر"
 | 
			
		||||
import: "استيراد"
 | 
			
		||||
export: "تصدير"
 | 
			
		||||
files: "الملفات"
 | 
			
		||||
download: "تنزيل"
 | 
			
		||||
driveFileDeleteConfirm: "أمتأكد من حذف ملف {name}؟ كل الملاحظات المُرفق بها هذا الملف ستحذف."
 | 
			
		||||
unfollowConfirm: "أمتأكد من إلغاء متابعة {name}؟"
 | 
			
		||||
lists: "القوائم"
 | 
			
		||||
noLists: "ليس لديك أية قائمة"
 | 
			
		||||
note: "ملاحظة"
 | 
			
		||||
@@ -53,8 +65,10 @@ followers: "المتابِعين"
 | 
			
		||||
followsYou: "يتابعك"
 | 
			
		||||
createList: "إنشاء قائمة"
 | 
			
		||||
manageLists: "إدارة القوائم"
 | 
			
		||||
error: "حدث خطأ ما"
 | 
			
		||||
error: "خطأ"
 | 
			
		||||
somethingHappened: "حدث خطأ"
 | 
			
		||||
retry: "حاول مجددًا"
 | 
			
		||||
pageLoadError: "فشل تحميل الصفحة"
 | 
			
		||||
enterListName: "اسم القائمة"
 | 
			
		||||
privacy: "الخصوصية"
 | 
			
		||||
makeFollowManuallyApprove: "القبول يدويا طلبات الإشتراك"
 | 
			
		||||
@@ -71,16 +85,24 @@ you: "أنت"
 | 
			
		||||
clickToShow: "اضغط للعرض"
 | 
			
		||||
sensitive: "محتوى حساس"
 | 
			
		||||
add: "إضافة"
 | 
			
		||||
reaction: "تفاعل"
 | 
			
		||||
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
 | 
			
		||||
attachCancel: "أزل المرفق"
 | 
			
		||||
enterFileName: "ادخل اسم الملف"
 | 
			
		||||
mute: "اكتم"
 | 
			
		||||
unmute: "إلغاء الكتم"
 | 
			
		||||
block: "احجب"
 | 
			
		||||
unblock: "إلغاء الحجب"
 | 
			
		||||
blockConfirm: "أمتأكد من حجب هذا الحساب؟"
 | 
			
		||||
unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
 | 
			
		||||
selectList: "اختر قائمة"
 | 
			
		||||
editWidgetsExit: "تم"
 | 
			
		||||
customEmojis: "إيموجي مخصص"
 | 
			
		||||
addEmoji: "إضافة إيموجي"
 | 
			
		||||
cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة"
 | 
			
		||||
autoAcceptFollowed: "اقبل طلبات المتابعة تلقائيا من الحسابات المتابَعة"
 | 
			
		||||
addAcount: "إضافة حساب"
 | 
			
		||||
loginFailed: "فشل الولوج"
 | 
			
		||||
showOnRemote: "رؤيته على مثيل الخادم البُعدي"
 | 
			
		||||
general: "الرئيسية"
 | 
			
		||||
wallpaper: "خلفية الشاشة"
 | 
			
		||||
@@ -88,6 +110,7 @@ setWallpaper: "استخدم خلفية الشاشة"
 | 
			
		||||
removeWallpaper: "إزالة خلفية الشاشة"
 | 
			
		||||
searchWith: "البحث: {q}"
 | 
			
		||||
youHaveNoLists: "لا تمتلك أية قائمة"
 | 
			
		||||
followConfirm: "أتريد متابعة {name}؟"
 | 
			
		||||
proxyAccount: "حساب وكيل البروكسي"
 | 
			
		||||
host: "المضيف"
 | 
			
		||||
selectUser: "حدّد مستخدمًا"
 | 
			
		||||
@@ -96,6 +119,8 @@ annotation: "التعليقات"
 | 
			
		||||
federation: "الفديرالية"
 | 
			
		||||
instances: "مثيل الخادم"
 | 
			
		||||
latestRequestSentAt: "آخر طلب أرسِل في"
 | 
			
		||||
latestRequestReceivedAt: "آخر طلب تُلقي في"
 | 
			
		||||
storageUsage: "مساحة التخزين المستخدمة"
 | 
			
		||||
charts: "المنحنيات البيانية"
 | 
			
		||||
perHour: "في الساعة"
 | 
			
		||||
perDay: "في اليوم"
 | 
			
		||||
@@ -127,7 +152,6 @@ processing: "المعالجة جارية"
 | 
			
		||||
preview: "معاينة"
 | 
			
		||||
default: "افتراضي"
 | 
			
		||||
noCustomEmojis: "ليس هناك إيموجيات"
 | 
			
		||||
customEmojisOfRemote: "الإيموجيات القادمة مِن مثيلات الخوادم الأخرى"
 | 
			
		||||
federating: "الفديرالية جارية"
 | 
			
		||||
blocked: "محجوب"
 | 
			
		||||
suspended: "مُعلّق"
 | 
			
		||||
@@ -313,7 +337,6 @@ total: "المجموع"
 | 
			
		||||
weekOverWeekChanges: "أسبوعيا"
 | 
			
		||||
dayOverDayChanges: "يوميا"
 | 
			
		||||
appearance: "المظهر"
 | 
			
		||||
clinetSettings: "إعدادات التطبيق"
 | 
			
		||||
accountSettings: "إعدادات الحساب"
 | 
			
		||||
promotion: "ترقية"
 | 
			
		||||
promote: "روِّج"
 | 
			
		||||
@@ -366,6 +389,7 @@ _theme:
 | 
			
		||||
  make: "إنشاء قالب"
 | 
			
		||||
  alpha: "الشفافية"
 | 
			
		||||
  keys:
 | 
			
		||||
    mention: "أشر الى"
 | 
			
		||||
    messageBg: "خلفية الدردشة"
 | 
			
		||||
_sfx:
 | 
			
		||||
  note: "الملاحظات"
 | 
			
		||||
@@ -508,7 +532,9 @@ _notification:
 | 
			
		||||
  youWereFollowed: "يتابعك"
 | 
			
		||||
  _types:
 | 
			
		||||
    follow: "المتابَعون"
 | 
			
		||||
    mention: "أشر الى"
 | 
			
		||||
    quote: "اقتبس"
 | 
			
		||||
    reaction: "تفاعل"
 | 
			
		||||
_deck:
 | 
			
		||||
  _columns:
 | 
			
		||||
    notifications: "الإشعارات"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,9 @@ noNotes: "Keine Notizen"
 | 
			
		||||
noNotifications: "Keine Benachrichtigungen"
 | 
			
		||||
instance: "Instanz"
 | 
			
		||||
settings: "Einstellungen"
 | 
			
		||||
basicSettings: "Allgemeine Einstellungen"
 | 
			
		||||
otherSettings: "Andere Einstellungen"
 | 
			
		||||
openInWindow: "In neuem Fenster öffnen"
 | 
			
		||||
profile: "Profil"
 | 
			
		||||
timeline: "Chronik"
 | 
			
		||||
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"
 | 
			
		||||
sendMessage: "Nachricht senden"
 | 
			
		||||
copyUsername: "Benutzernamen kopieren"
 | 
			
		||||
searchUser: "Benutzersuche"
 | 
			
		||||
reply: "Antworten"
 | 
			
		||||
loadMore: "Mehr anzeigen"
 | 
			
		||||
youGotNewFollower: "Du hast einen neuen Follower"
 | 
			
		||||
@@ -66,8 +70,11 @@ followers: "Gefolgt von"
 | 
			
		||||
followsYou: "Folgt dir"
 | 
			
		||||
createList: "Liste erstellen"
 | 
			
		||||
manageLists: "Listen verwalten"
 | 
			
		||||
error: "Ein Problem ist aufgetreten"
 | 
			
		||||
error: "Fehler"
 | 
			
		||||
somethingHappened: "Ein Fehler ist aufgetreten"
 | 
			
		||||
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"
 | 
			
		||||
privacy: "Privatsphäre"
 | 
			
		||||
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"
 | 
			
		||||
selectAntenna: "Antenne auswählen"
 | 
			
		||||
selectWidget: "Widget auswählen"
 | 
			
		||||
editWidgets: "Widgets bearbeiten"
 | 
			
		||||
editWidgetsExit: "Fertig"
 | 
			
		||||
customEmojis: "Benutzerdefinierte Emojis"
 | 
			
		||||
emoji: "Emoji"
 | 
			
		||||
emojiName: "Emojiname"
 | 
			
		||||
@@ -177,7 +186,6 @@ processing: "In Bearbeitung"
 | 
			
		||||
preview: "Vorschau"
 | 
			
		||||
default: "Standard"
 | 
			
		||||
noCustomEmojis: "Es existieren keine Emojis"
 | 
			
		||||
customEmojisOfRemote: "Emojis von anderen Instanzen"
 | 
			
		||||
noJobs: "Es gibt keine Jobs"
 | 
			
		||||
federating: "Föderiert"
 | 
			
		||||
blocked: "Blockiert"
 | 
			
		||||
@@ -445,7 +453,7 @@ total: "Gesamt"
 | 
			
		||||
weekOverWeekChanges: "Wöchentlich"
 | 
			
		||||
dayOverDayChanges: "Täglich"
 | 
			
		||||
appearance: "Aussehen"
 | 
			
		||||
clinetSettings: "Client-Einstellungen"
 | 
			
		||||
clientSettings: "Client-Einstellungen"
 | 
			
		||||
accountSettings: "Benutzerkonto-Einstellungen"
 | 
			
		||||
promotion: "Hervorgehoben"
 | 
			
		||||
promote: "Hervorheben"
 | 
			
		||||
@@ -476,6 +484,8 @@ newNoteRecived: "Es gibt neue Notizen"
 | 
			
		||||
sounds: "Töne"
 | 
			
		||||
listen: "Anhören"
 | 
			
		||||
none: "Keine"
 | 
			
		||||
showInPage: "In Seiten anzeigen"
 | 
			
		||||
popout: "Pop-Up"
 | 
			
		||||
volume: "Lautstärke"
 | 
			
		||||
details: "Details"
 | 
			
		||||
chooseEmoji: "Wähle ein Emoji"
 | 
			
		||||
@@ -518,7 +528,6 @@ enableInfiniteScroll: "Automatisch mehr Notizen laden"
 | 
			
		||||
visibility: "Sichtbarkeit"
 | 
			
		||||
poll: "Umfrage"
 | 
			
		||||
useCw: "Inhalt verstecken"
 | 
			
		||||
fixedWidgetsPosition: "Widgetposition fixieren"
 | 
			
		||||
enablePlayer: "Video-Player öffnen"
 | 
			
		||||
disablePlayer: "Video-Player schließen"
 | 
			
		||||
expandTweet: "Tweet ausklappen"
 | 
			
		||||
@@ -564,8 +573,26 @@ overview: "Übersicht"
 | 
			
		||||
logs: "Logs"
 | 
			
		||||
delayed: "Verzögert"
 | 
			
		||||
database: "Datenbank"
 | 
			
		||||
channel: "Kanal"
 | 
			
		||||
channel: "Kanäle"
 | 
			
		||||
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:
 | 
			
		||||
  reload: "Automatisch aktualisieren"
 | 
			
		||||
  dialog: "Warnungsfenster zeigen"
 | 
			
		||||
@@ -576,13 +603,13 @@ _channel:
 | 
			
		||||
  setBanner: "Kanalbanner festlegen"
 | 
			
		||||
  removeBanner: "Kanalbanner entfernen"
 | 
			
		||||
  featured: "Trends"
 | 
			
		||||
  owned: "Besitzer"
 | 
			
		||||
  following: "Folgt"
 | 
			
		||||
  owned: "Besitzt"
 | 
			
		||||
  following: "Gefolgt"
 | 
			
		||||
  usersCount: "{n} Teilnehmer"
 | 
			
		||||
  notesCount: "{n} Notizen"
 | 
			
		||||
_sidebar:
 | 
			
		||||
  full: "Voll"
 | 
			
		||||
  icon: "Profilbild"
 | 
			
		||||
  icon: "Symbol"
 | 
			
		||||
  hide: "Ausblenden"
 | 
			
		||||
_wordMute:
 | 
			
		||||
  muteWords: "Wort stummschalten"
 | 
			
		||||
@@ -782,6 +809,7 @@ _widgets:
 | 
			
		||||
  photos: "Fotos"
 | 
			
		||||
  digitalClock: "Digitaluhr"
 | 
			
		||||
  federation: "Föderation"
 | 
			
		||||
  postForm: "Neue Notiz anfertigen"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "Ausblenden"
 | 
			
		||||
  show: "Mehr anzeigen"
 | 
			
		||||
@@ -1238,14 +1266,17 @@ _notification:
 | 
			
		||||
  youWereInvitedToGroup: "Du wurdest in eine Gruppe eingeladen"
 | 
			
		||||
  _types:
 | 
			
		||||
    all: "Alle"
 | 
			
		||||
    follow: "Folgt"
 | 
			
		||||
    mention: "Erwähnung"
 | 
			
		||||
    follow: "Neue Follower"
 | 
			
		||||
    mention: "Erwähnungen"
 | 
			
		||||
    reply: "Antworten"
 | 
			
		||||
    renote: "Renote"
 | 
			
		||||
    quote: "Zitieren"
 | 
			
		||||
    renote: "Renotes"
 | 
			
		||||
    quote: "Zitationen"
 | 
			
		||||
    reaction: "Reaktionen"
 | 
			
		||||
    pollVote: "Umfragen"
 | 
			
		||||
    receiveFollowRequest: "Follow-Anfragen"
 | 
			
		||||
    pollVote: "Antworten auf Umfragen"
 | 
			
		||||
    receiveFollowRequest: "Follow-Anfrage erhalten"
 | 
			
		||||
    followRequestAccepted: "Follow-Anfrage akzeptiert"
 | 
			
		||||
    groupInvited: "Gruppeneinladung erhalten"
 | 
			
		||||
    app: "Benachrichtigungen von Apps"
 | 
			
		||||
_deck:
 | 
			
		||||
  alwaysShowMainColumn: "Hauptspalte immer zeigen"
 | 
			
		||||
  columnAlign: "Spalten ausrichten"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,9 @@ noNotes: "No notes"
 | 
			
		||||
noNotifications: "No notifications"
 | 
			
		||||
instance: "Instance"
 | 
			
		||||
settings: "Settings"
 | 
			
		||||
basicSettings: "Basic Settings"
 | 
			
		||||
otherSettings: "Other Settings"
 | 
			
		||||
openInWindow: "Open in new window"
 | 
			
		||||
profile: "Profile"
 | 
			
		||||
timeline: "Timeline"
 | 
			
		||||
noAccountDescription: "This user has not written their bio yet."
 | 
			
		||||
@@ -29,7 +32,7 @@ users: "Users"
 | 
			
		||||
addUser: "Add a user"
 | 
			
		||||
favorite: "Favorite"
 | 
			
		||||
favorites: "Favorites"
 | 
			
		||||
unfavorite: "Undo favorite"
 | 
			
		||||
unfavorite: "Unfavorite"
 | 
			
		||||
pin: "Pin to profile"
 | 
			
		||||
unpin: "Unpin from profile"
 | 
			
		||||
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"
 | 
			
		||||
sendMessage: "Send a message"
 | 
			
		||||
copyUsername: "Copy username"
 | 
			
		||||
searchUser: "User search"
 | 
			
		||||
reply: "Reply"
 | 
			
		||||
loadMore: "Load more"
 | 
			
		||||
youGotNewFollower: "Followed you"
 | 
			
		||||
@@ -66,8 +70,11 @@ followers: "Followers"
 | 
			
		||||
followsYou: "Follows you"
 | 
			
		||||
createList: "Create list"
 | 
			
		||||
manageLists: "Manage lists"
 | 
			
		||||
error: "Something happened :("
 | 
			
		||||
error: "Error"
 | 
			
		||||
somethingHappened: "An error occurred"
 | 
			
		||||
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"
 | 
			
		||||
privacy: "Privacy"
 | 
			
		||||
makeFollowManuallyApprove: "Follow requests require approval"
 | 
			
		||||
@@ -106,6 +113,8 @@ unsuspendConfirm: "Are you sure you that want to unsuspend this account?"
 | 
			
		||||
selectList: "Select a list"
 | 
			
		||||
selectAntenna: "Select an Antenna"
 | 
			
		||||
selectWidget: "Select a widget"
 | 
			
		||||
editWidgets: "Edit widgets"
 | 
			
		||||
editWidgetsExit: "Done"
 | 
			
		||||
customEmojis: "Custom Emoji"
 | 
			
		||||
emoji: "Emoji"
 | 
			
		||||
emojiName: "Emoji name"
 | 
			
		||||
@@ -177,7 +186,6 @@ processing: "Processing"
 | 
			
		||||
preview: "Preview"
 | 
			
		||||
default: "Default"
 | 
			
		||||
noCustomEmojis: "There are no emojis"
 | 
			
		||||
customEmojisOfRemote: "Emojis from other instances"
 | 
			
		||||
noJobs: "There are no jobs"
 | 
			
		||||
federating: "Federating"
 | 
			
		||||
blocked: "Blocked"
 | 
			
		||||
@@ -445,7 +453,7 @@ total: "Total"
 | 
			
		||||
weekOverWeekChanges: "Weekly"
 | 
			
		||||
dayOverDayChanges: "Daily"
 | 
			
		||||
appearance: "Appearance"
 | 
			
		||||
clinetSettings: "Client Settings"
 | 
			
		||||
clientSettings: "Client settings"
 | 
			
		||||
accountSettings: "Account Settings"
 | 
			
		||||
promotion: "Promoted"
 | 
			
		||||
promote: "Promote"
 | 
			
		||||
@@ -476,6 +484,8 @@ newNoteRecived: "You've got a new note"
 | 
			
		||||
sounds: "Sounds"
 | 
			
		||||
listen: "Listen"
 | 
			
		||||
none: "None"
 | 
			
		||||
showInPage: "Show in Pages"
 | 
			
		||||
popout: "Pop-out"
 | 
			
		||||
volume: "Volume"
 | 
			
		||||
details: "Details"
 | 
			
		||||
chooseEmoji: "Choose an emoji"
 | 
			
		||||
@@ -518,7 +528,6 @@ enableInfiniteScroll: "Enable infinite scrolling"
 | 
			
		||||
visibility: "Visiblility"
 | 
			
		||||
poll: "Poll"
 | 
			
		||||
useCw: "Hide content"
 | 
			
		||||
fixedWidgetsPosition: "Make widget position fixed"
 | 
			
		||||
enablePlayer: "Open video player"
 | 
			
		||||
disablePlayer: "Close video player"
 | 
			
		||||
expandTweet: "Expand tweet"
 | 
			
		||||
@@ -564,8 +573,26 @@ overview: "Overview"
 | 
			
		||||
logs: "Logs"
 | 
			
		||||
delayed: "Delayed"
 | 
			
		||||
database: "Database"
 | 
			
		||||
channel: "Channel"
 | 
			
		||||
channel: "Channels"
 | 
			
		||||
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:
 | 
			
		||||
  reload: "Automatically reload"
 | 
			
		||||
  dialog: "Show warning dialog"
 | 
			
		||||
@@ -576,8 +603,8 @@ _channel:
 | 
			
		||||
  setBanner: "Set banner"
 | 
			
		||||
  removeBanner: "Remove banner"
 | 
			
		||||
  featured: "Trending"
 | 
			
		||||
  owned: "Owner"
 | 
			
		||||
  following: "Following"
 | 
			
		||||
  owned: "Owned"
 | 
			
		||||
  following: "Followed"
 | 
			
		||||
  usersCount: "{n} Participants"
 | 
			
		||||
  notesCount: "{n} Notes"
 | 
			
		||||
_sidebar:
 | 
			
		||||
@@ -782,6 +809,7 @@ _widgets:
 | 
			
		||||
  photos: "Photos"
 | 
			
		||||
  digitalClock: "Digital clock"
 | 
			
		||||
  federation: "Federation"
 | 
			
		||||
  postForm: "Compose a note"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "Hide"
 | 
			
		||||
  show: "Load more"
 | 
			
		||||
@@ -1238,14 +1266,17 @@ _notification:
 | 
			
		||||
  youWereInvitedToGroup: "Invited to group"
 | 
			
		||||
  _types:
 | 
			
		||||
    all: "All"
 | 
			
		||||
    follow: "Following"
 | 
			
		||||
    mention: "Mention"
 | 
			
		||||
    follow: "Follows"
 | 
			
		||||
    mention: "Mentions"
 | 
			
		||||
    reply: "Replies"
 | 
			
		||||
    renote: "Renote"
 | 
			
		||||
    quote: "Quote"
 | 
			
		||||
    reaction: "Reaction"
 | 
			
		||||
    pollVote: "Polls"
 | 
			
		||||
    receiveFollowRequest: "Follow requests"
 | 
			
		||||
    renote: "Renotes"
 | 
			
		||||
    quote: "Quotes"
 | 
			
		||||
    reaction: "Reactions"
 | 
			
		||||
    pollVote: "Votes on polls"
 | 
			
		||||
    receiveFollowRequest: "Follow request received"
 | 
			
		||||
    followRequestAccepted: "Follow request accepted"
 | 
			
		||||
    groupInvited: "Invited to groups"
 | 
			
		||||
    app: "Notifications from apps"
 | 
			
		||||
_deck:
 | 
			
		||||
  alwaysShowMainColumn: "Always show main column"
 | 
			
		||||
  columnAlign: "Align columns"
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,6 @@ followers: "Seguidores"
 | 
			
		||||
followsYou: "Te sigue"
 | 
			
		||||
createList: "Crear lista"
 | 
			
		||||
manageLists: "Administrar listas"
 | 
			
		||||
error: "Ocurrió un problema"
 | 
			
		||||
retry: "Reintentar"
 | 
			
		||||
enterListName: "Ingrese nombre de lista"
 | 
			
		||||
privacy: "Privacidad"
 | 
			
		||||
@@ -177,7 +176,6 @@ processing: "Procesando"
 | 
			
		||||
preview: "Vista previa"
 | 
			
		||||
default: "Predeterminado"
 | 
			
		||||
noCustomEmojis: "No hay emojis personalizados"
 | 
			
		||||
customEmojisOfRemote: "Emojis remotos"
 | 
			
		||||
noJobs: "No hay trabajos"
 | 
			
		||||
federating: "Federando"
 | 
			
		||||
blocked: "Bloqueando"
 | 
			
		||||
@@ -445,7 +443,6 @@ total: "Total"
 | 
			
		||||
weekOverWeekChanges: "Dif semanal"
 | 
			
		||||
dayOverDayChanges: "Dif diaria"
 | 
			
		||||
appearance: "Apariencia"
 | 
			
		||||
clinetSettings: "Ajustes del cliente"
 | 
			
		||||
accountSettings: "Ajustes de cuenta"
 | 
			
		||||
promotion: "Promovido"
 | 
			
		||||
promote: "Promover"
 | 
			
		||||
@@ -518,7 +515,6 @@ enableInfiniteScroll: "Activar scroll infinito"
 | 
			
		||||
visibility: "Visibilidad"
 | 
			
		||||
poll: "Encuesta"
 | 
			
		||||
useCw: "Esconder contenidos"
 | 
			
		||||
fixedWidgetsPosition: "Fijar la posición de los widgets"
 | 
			
		||||
enablePlayer: "Abrir reproductor"
 | 
			
		||||
disablePlayer: "Cerrar reproductor"
 | 
			
		||||
expandTweet: "Expandir tweet"
 | 
			
		||||
@@ -566,6 +562,10 @@ delayed: "atrasado"
 | 
			
		||||
database: "Base de datos"
 | 
			
		||||
channel: "Canal"
 | 
			
		||||
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:
 | 
			
		||||
  reload: "Recargar automáticamente"
 | 
			
		||||
  dialog: "Mostrar diálogo de advertencia"
 | 
			
		||||
@@ -782,6 +782,7 @@ _widgets:
 | 
			
		||||
  photos: "Fotos"
 | 
			
		||||
  digitalClock: "Reloj digital"
 | 
			
		||||
  federation: "Federación"
 | 
			
		||||
  postForm: "Formulario"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "Ocultar"
 | 
			
		||||
  show: "Ver más"
 | 
			
		||||
@@ -1244,8 +1245,11 @@ _notification:
 | 
			
		||||
    renote: "Renotar"
 | 
			
		||||
    quote: "Citar"
 | 
			
		||||
    reaction: "Reacción"
 | 
			
		||||
    pollVote: "Encuestas"
 | 
			
		||||
    receiveFollowRequest: "Solicitudes de seguimiento"
 | 
			
		||||
    pollVote: "Votado en la encuesta"
 | 
			
		||||
    receiveFollowRequest: "Recibió una solicitud de seguimiento"
 | 
			
		||||
    followRequestAccepted: "El seguimiento fue aceptado"
 | 
			
		||||
    groupInvited: "Invitado al grupo"
 | 
			
		||||
    app: "Notificaciones desde aplicaciones"
 | 
			
		||||
_deck:
 | 
			
		||||
  alwaysShowMainColumn: "Siempre mostrar la columna principal"
 | 
			
		||||
  columnAlign: "Alinear columnas"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,9 @@ noNotes: "Aucune note"
 | 
			
		||||
noNotifications: "Aucune notification"
 | 
			
		||||
instance: "Instance"
 | 
			
		||||
settings: "Paramètres"
 | 
			
		||||
basicSettings: "Paramètres basiques"
 | 
			
		||||
otherSettings: "Autres paramètres"
 | 
			
		||||
openInWindow: "Ouvrir dans une nouvelle fenêtre"
 | 
			
		||||
profile: "Profil"
 | 
			
		||||
timeline: "Fil"
 | 
			
		||||
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"
 | 
			
		||||
sendMessage: "Envoyer un message"
 | 
			
		||||
copyUsername: "Copier le nom d’utilisateur·rice"
 | 
			
		||||
searchUser: "Chercher un·e utilisateur·rice"
 | 
			
		||||
reply: "Répondre"
 | 
			
		||||
loadMore: "Afficher plus …"
 | 
			
		||||
youGotNewFollower: "Vous suit"
 | 
			
		||||
@@ -66,8 +70,10 @@ followers: "Abonné·e·s"
 | 
			
		||||
followsYou: "Vous suit"
 | 
			
		||||
createList: "Créer une liste"
 | 
			
		||||
manageLists: "Gérer les listes"
 | 
			
		||||
error: "Une erreur est survenue"
 | 
			
		||||
error: "Erreur"
 | 
			
		||||
somethingHappened: "Une erreur est survenue"
 | 
			
		||||
retry: "Réessayer"
 | 
			
		||||
pageLoadError: "Le chargement de la page a échoué"
 | 
			
		||||
enterListName: "Nom de la liste"
 | 
			
		||||
privacy: "Confidentialité"
 | 
			
		||||
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"
 | 
			
		||||
selectAntenna: "Sélectionner une antenne"
 | 
			
		||||
selectWidget: "Sélectionner un widget"
 | 
			
		||||
editWidgets: "Modifier les widgets"
 | 
			
		||||
editWidgetsExit: "Fait"
 | 
			
		||||
customEmojis: "Émojis personnalisés"
 | 
			
		||||
emoji: "Émoji"
 | 
			
		||||
emojiName: "Nom de l’émoji"
 | 
			
		||||
@@ -177,7 +185,6 @@ processing: "Traitement en cours"
 | 
			
		||||
preview: "Prévisualisation"
 | 
			
		||||
default: "Par défaut"
 | 
			
		||||
noCustomEmojis: "Il n'y a pas d’émoji"
 | 
			
		||||
customEmojisOfRemote: "Émojis provenant des autres instances"
 | 
			
		||||
noJobs: "Il n’y a aucune tâche planifiée"
 | 
			
		||||
federating: "En cours de fédération"
 | 
			
		||||
blocked: "Bloqué·e"
 | 
			
		||||
@@ -264,6 +271,7 @@ rename: "Renommer"
 | 
			
		||||
avatar: "Avatar"
 | 
			
		||||
banner: "Bannière"
 | 
			
		||||
nsfw: "Contenu sensible"
 | 
			
		||||
whenServerDisconnected: "Lorsque la connexion au serveur est perdue"
 | 
			
		||||
disconnectedFromServer: "Déconnecté·e du serveur"
 | 
			
		||||
reload: "Rafraîchir"
 | 
			
		||||
doNothing: "Ignorer"
 | 
			
		||||
@@ -444,7 +452,7 @@ total: "Total"
 | 
			
		||||
weekOverWeekChanges: "Diff hebdo"
 | 
			
		||||
dayOverDayChanges: "Diff quotidien"
 | 
			
		||||
appearance: "Aspect"
 | 
			
		||||
clinetSettings: "Paramètres du client"
 | 
			
		||||
clientSettings: "Paramètres du client"
 | 
			
		||||
accountSettings: "Paramètres du compte"
 | 
			
		||||
promotion: "Promu"
 | 
			
		||||
promote: "Promouvoir"
 | 
			
		||||
@@ -474,6 +482,7 @@ newNoteRecived: "Vous avez une nouvelle note"
 | 
			
		||||
sounds: "Sons"
 | 
			
		||||
listen: "Écouter"
 | 
			
		||||
none: "Rien"
 | 
			
		||||
popout: "Fenêtre contextuelle"
 | 
			
		||||
volume: "Volume"
 | 
			
		||||
details: "Détails"
 | 
			
		||||
chooseEmoji: "Choisissez un émoji"
 | 
			
		||||
@@ -516,7 +525,6 @@ enableInfiniteScroll: "Activer le défilement infini"
 | 
			
		||||
visibility: "Visibilité"
 | 
			
		||||
poll: "Sondage"
 | 
			
		||||
useCw: "Masquer le contenu"
 | 
			
		||||
fixedWidgetsPosition: "Rendre la position du widget fixe"
 | 
			
		||||
enablePlayer: "Activer le lecteur vidéo"
 | 
			
		||||
disablePlayer: "Désactiver le lecteur vidéo"
 | 
			
		||||
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."
 | 
			
		||||
notificationType: "Type de notifications"
 | 
			
		||||
edit: "Editer"
 | 
			
		||||
useStarForReactionFallback: "Utiliser ★ comme alternative si l’émoji de réaction est inconnu"
 | 
			
		||||
emailConfig: "Configuration du serveur email"
 | 
			
		||||
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."
 | 
			
		||||
@@ -549,16 +558,45 @@ smtpUser: "Nom d’utilisateur·rice"
 | 
			
		||||
smtpPass: "Mot de passe"
 | 
			
		||||
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"
 | 
			
		||||
smtpSecureInfo: "Désactiver cette option lorsque STARTTLS est utilisé"
 | 
			
		||||
testEmail: "Tester la distribution de courriel"
 | 
			
		||||
wordMute: "Filtre de mots"
 | 
			
		||||
userSaysSomething: "{name} a dit quelque chose"
 | 
			
		||||
makeActive: "Activer"
 | 
			
		||||
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:
 | 
			
		||||
  create: "Créer un canal"
 | 
			
		||||
  edit: "Éditer le canal"
 | 
			
		||||
  removeBanner: "Supprimer la bannière"
 | 
			
		||||
  featured: "Tendances"
 | 
			
		||||
  usersCount: "{n} Participants"
 | 
			
		||||
  notesCount: "{n} Notes"
 | 
			
		||||
_sidebar:
 | 
			
		||||
  full: "Complet"
 | 
			
		||||
  icon: "Avatar"
 | 
			
		||||
  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:
 | 
			
		||||
  explore: "Explorer les thèmes"
 | 
			
		||||
  install: "Installer un thème"
 | 
			
		||||
@@ -569,6 +607,8 @@ _theme:
 | 
			
		||||
  invalid: "Le format du thème n'est pas valide"
 | 
			
		||||
  make: "Créer un thème"
 | 
			
		||||
  base: "Base"
 | 
			
		||||
  addConstant: "Ajouter une constante"
 | 
			
		||||
  constant: "Constante"
 | 
			
		||||
  defaultValue: "Valeur par défaut"
 | 
			
		||||
  color: "Couleur"
 | 
			
		||||
  key: "Clé "
 | 
			
		||||
@@ -594,6 +634,7 @@ _theme:
 | 
			
		||||
    renote: "Renote"
 | 
			
		||||
    divider: "Séparateur"
 | 
			
		||||
    infoWarnFg: "Texte d’avertissement"
 | 
			
		||||
    cwBg: "Arrière-plan du CW"
 | 
			
		||||
    badge: "Badge"
 | 
			
		||||
    messageBg: "Arrière plan de la discussion"
 | 
			
		||||
_sfx:
 | 
			
		||||
@@ -678,6 +719,8 @@ _permissions:
 | 
			
		||||
  "write:page-likes": "Mettre à jour les favoris sur les Pages"
 | 
			
		||||
  "read:user-groups": "Voir les groupes d'utilisateur·rice·s"
 | 
			
		||||
  "write:user-groups": "Éditer les groupes des utilisateur·rice·s"
 | 
			
		||||
  "read:channels": "Lire les canaux"
 | 
			
		||||
  "write:channels": "Modifier les canaux"
 | 
			
		||||
_auth:
 | 
			
		||||
  shareAccess: "Autoriser \"{name}\" à accéder à votre compte ?"
 | 
			
		||||
  shareAccessAsk: "Voulez-vous vraiment autoriser cette application à accéder à votre compte?"
 | 
			
		||||
@@ -711,6 +754,7 @@ _widgets:
 | 
			
		||||
  photos: "Photos"
 | 
			
		||||
  digitalClock: "Horloge numérique"
 | 
			
		||||
  federation: "Fédération"
 | 
			
		||||
  postForm: "Formulaire à publier"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "Masquer"
 | 
			
		||||
  show: "Afficher plus …"
 | 
			
		||||
@@ -752,6 +796,7 @@ _visibility:
 | 
			
		||||
_postForm:
 | 
			
		||||
  replyPlaceholder: "Répondre à cette note ..."
 | 
			
		||||
  quotePlaceholder: "Citez cette note ..."
 | 
			
		||||
  channelPlaceholder: "Publier vers le canal"
 | 
			
		||||
  _placeholders:
 | 
			
		||||
    a: "Quoi de neuf ?"
 | 
			
		||||
    b: "Quoi de neuf ?"
 | 
			
		||||
@@ -1165,11 +1210,15 @@ _notification:
 | 
			
		||||
  yourFollowRequestAccepted: "Votre demande d’abonnement a été accepté"
 | 
			
		||||
  youWereInvitedToGroup: "Invité au groupe"
 | 
			
		||||
  _types:
 | 
			
		||||
    all: "Toutes"
 | 
			
		||||
    follow: "Abonnements"
 | 
			
		||||
    mention: "Mentionner"
 | 
			
		||||
    reply: "Réponses"
 | 
			
		||||
    renote: "Renote"
 | 
			
		||||
    quote: "Citer"
 | 
			
		||||
    reaction: "Réactions"
 | 
			
		||||
    groupInvited: "Invité aux groupes"
 | 
			
		||||
    app: "Notifications provenant des apps"
 | 
			
		||||
_deck:
 | 
			
		||||
  alwaysShowMainColumn: "Toujours afficher la colonne principale"
 | 
			
		||||
  columnAlign: "Aligner les colonnes"
 | 
			
		||||
 
 | 
			
		||||
@@ -586,6 +586,17 @@ setMultipleBySeparatingWithSpace: "スペースで区切って複数設定でき
 | 
			
		||||
fileIdOrUrl: "ファイルIDまたはURL"
 | 
			
		||||
chatOpenBehavior: "チャットを開くときの動作"
 | 
			
		||||
sample: "サンプル"
 | 
			
		||||
abuseReports: "通報"
 | 
			
		||||
reportAbuse: "通報"
 | 
			
		||||
reportAbuseOf: "{name}を通報する"
 | 
			
		||||
fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のノートがある場合はそのURLも記入してください。"
 | 
			
		||||
abuseReported: "内容が送信されました。ご報告ありがとうございました。"
 | 
			
		||||
send: "送信"
 | 
			
		||||
abuseMarkAsResolved: "対応済みにする"
 | 
			
		||||
openInNewTab: "新しいタブで開く"
 | 
			
		||||
openInSideView: "サイドビューで開く"
 | 
			
		||||
defaultNavigationBehaviour: "デフォルトのナビゲーション"
 | 
			
		||||
editTheseSettingsMayBreakAccount: "これらの設定を編集するとアカウントが破損する可能性があります。"
 | 
			
		||||
 | 
			
		||||
_serverDisconnectedBehavior:
 | 
			
		||||
  reload: "自動でリロード"
 | 
			
		||||
 
 | 
			
		||||
@@ -65,7 +65,6 @@ followers: "フォロワー"
 | 
			
		||||
followsYou: "フォローされとるで"
 | 
			
		||||
createList: "リスト作る"
 | 
			
		||||
manageLists: "リストの管理"
 | 
			
		||||
error: "問題が発生してん"
 | 
			
		||||
retry: "もっぺんやってみる"
 | 
			
		||||
enterListName: "リスト名を入れてや"
 | 
			
		||||
privacy: "プライバシーってなんや?オカンの年齢か?"
 | 
			
		||||
@@ -173,7 +172,6 @@ processing: "処理しとる"
 | 
			
		||||
preview: "プレビュー"
 | 
			
		||||
default: "デフォルト"
 | 
			
		||||
noCustomEmojis: "絵文字はあらへん"
 | 
			
		||||
customEmojisOfRemote: "リモートの絵文字"
 | 
			
		||||
noJobs: "ジョブはあらへん"
 | 
			
		||||
federating: "連合しとる"
 | 
			
		||||
blocked: "ブロックしとる"
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,6 @@ followers: "팔로워"
 | 
			
		||||
followsYou: "당신을 팔로우합니다"
 | 
			
		||||
createList: "리스트 만들기"
 | 
			
		||||
manageLists: "리스트 관리"
 | 
			
		||||
error: "오류가 발생했습니다"
 | 
			
		||||
retry: "다시 시도"
 | 
			
		||||
enterListName: "리스트 이름을 입력"
 | 
			
		||||
privacy: "프라이버시"
 | 
			
		||||
@@ -177,7 +176,6 @@ processing: "처리중"
 | 
			
		||||
preview: "미리보기"
 | 
			
		||||
default: "기본값"
 | 
			
		||||
noCustomEmojis: "이모지가 없습니다"
 | 
			
		||||
customEmojisOfRemote: "다른 인스턴스들의 이모지"
 | 
			
		||||
noJobs: "작업이 없습니다"
 | 
			
		||||
federating: "연합 중"
 | 
			
		||||
blocked: "차단됨"
 | 
			
		||||
@@ -443,7 +441,6 @@ remote: "리모트"
 | 
			
		||||
total: "합계"
 | 
			
		||||
weekOverWeekChanges: "지난주보다"
 | 
			
		||||
dayOverDayChanges: "어제보다"
 | 
			
		||||
clinetSettings: "클라이언트 설정"
 | 
			
		||||
accountSettings: "계정 설정"
 | 
			
		||||
promotion: "프로모션"
 | 
			
		||||
promote: "프로모션하기"
 | 
			
		||||
@@ -515,7 +512,6 @@ enableInfiniteScroll: "자동으로 좀 더 보기"
 | 
			
		||||
visibility: "공개 범위"
 | 
			
		||||
poll: "투표"
 | 
			
		||||
useCw: "내용 숨기기"
 | 
			
		||||
fixedWidgetsPosition: "위젯의 위치 고정"
 | 
			
		||||
enablePlayer: "플레이어 열기"
 | 
			
		||||
disablePlayer: "플레이어 닫기"
 | 
			
		||||
expandTweet: "트윗 확장하기"
 | 
			
		||||
@@ -708,6 +704,7 @@ _widgets:
 | 
			
		||||
  photos: "사진"
 | 
			
		||||
  digitalClock: "디지털 시계"
 | 
			
		||||
  federation: "연합"
 | 
			
		||||
  postForm: "글 입력란"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "숨기기"
 | 
			
		||||
  show: "더 보기"
 | 
			
		||||
@@ -1165,7 +1162,6 @@ _notification:
 | 
			
		||||
    renote: "Renote"
 | 
			
		||||
    quote: "인용"
 | 
			
		||||
    reaction: "리액션"
 | 
			
		||||
    receiveFollowRequest: "팔로우 요청"
 | 
			
		||||
_deck:
 | 
			
		||||
  alwaysShowMainColumn: "메인 칼럼 항상 표시"
 | 
			
		||||
  columnAlign: "칼럼 정렬"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,2 +1,21 @@
 | 
			
		||||
---
 | 
			
		||||
_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,986 @@
 | 
			
		||||
---
 | 
			
		||||
_lang_: "Русский язык"
 | 
			
		||||
introMisskey: "Добро пожаловать! Misskey - это децентрализованный сервис микроблогов с открытым исходным кодом.\nСоздавайте «записи», чтобы поделиться происходящим или рассказать всем о себе 📡\nТакже Вы можете добавить быструю реакцию на все записи с помощью функции «реакция» 👍\nОткройте для себя новый мир 🚀"
 | 
			
		||||
_lang_: "Русский"
 | 
			
		||||
introMisskey: "Добро пожаловать! Misskey — это децентрализованный сервис микроблогов с открытым исходным кодом.\nПишите «заметки» — делитесь со всеми происходящим вокруг или рассказывайте о себе 📡\nСтавьте «реакции» — выражайте свои чувства и эмоции от заметок других 👍\nОткройте для себя новый мир 🚀"
 | 
			
		||||
monthAndDay: "{day}.{month}"
 | 
			
		||||
search: "Поиск"
 | 
			
		||||
notifications: "Уведомления"
 | 
			
		||||
username: "Имя пользователя"
 | 
			
		||||
password: "Пароль"
 | 
			
		||||
fetchingAsApObject: "Запрос на федерацию"
 | 
			
		||||
ok: "Окей"
 | 
			
		||||
gotIt: "Отлично"
 | 
			
		||||
fetchingAsApObject: "Приём с других сайтов…"
 | 
			
		||||
ok: "Согласен"
 | 
			
		||||
gotIt: "Понятно!"
 | 
			
		||||
cancel: "Отмена"
 | 
			
		||||
instance: "Экземпляр"
 | 
			
		||||
enterUsername: "Введите имя пользователя"
 | 
			
		||||
renotedBy: "{user} передаёт…"
 | 
			
		||||
noNotes: "Нет ни одной заметки"
 | 
			
		||||
noNotifications: "Нет ни одного уведомления"
 | 
			
		||||
instance: "Инстанс"
 | 
			
		||||
settings: "Настройки"
 | 
			
		||||
basicSettings: "Основные настройки"
 | 
			
		||||
otherSettings: "Прочие настройки"
 | 
			
		||||
openInWindow: "Открыть в окне"
 | 
			
		||||
profile: "Профиль"
 | 
			
		||||
timeline: "Лента"
 | 
			
		||||
noAccountDescription: "Пользователь ничего не написал про себя"
 | 
			
		||||
login: "Войти"
 | 
			
		||||
loggingIn: "Выполняется вход"
 | 
			
		||||
logout: "Выйти"
 | 
			
		||||
signup: "Регистрация"
 | 
			
		||||
uploading: "Загрузка..."
 | 
			
		||||
save: "Сохранить"
 | 
			
		||||
users: "Пользователи"
 | 
			
		||||
addUser: "Добавить пользователя"
 | 
			
		||||
favorite: "Избранное"
 | 
			
		||||
favorites: "Избранное"
 | 
			
		||||
unfavorite: "Удалить из избранных"
 | 
			
		||||
pin: "Закрепить"
 | 
			
		||||
unpin: "Открепить"
 | 
			
		||||
unfavorite: "Убрать из избранных"
 | 
			
		||||
pin: "Закрепить в профиле"
 | 
			
		||||
unpin: "Открепить от профиля"
 | 
			
		||||
copyContent: "Скопировать содержимое"
 | 
			
		||||
copyLink: "Скопировать ссылку"
 | 
			
		||||
delete: "Удалить"
 | 
			
		||||
deleteAndEdit: "Удалить и отредактировать"
 | 
			
		||||
deleteAndEditConfirm: "Удалить этот пост и создать отредактированный? Все реакции, ссылки и ответы на существующий будут будут потеряны."
 | 
			
		||||
addToList: "Добавить в список"
 | 
			
		||||
sendMessage: "Отправить сообщение"
 | 
			
		||||
copyUsername: "Скопировать имя пользователя"
 | 
			
		||||
searchUser: "Поиск людей"
 | 
			
		||||
reply: "Ответить"
 | 
			
		||||
loadMore: "Показать еще"
 | 
			
		||||
youGotNewFollower: "Новый подписчик"
 | 
			
		||||
receiveFollowRequest: "Получен запрос на подписку"
 | 
			
		||||
followRequestAccepted: "Запрос на подписку принят"
 | 
			
		||||
mention: "Упоминание"
 | 
			
		||||
mentions: "Упоминания"
 | 
			
		||||
directNotes: "Прямые сообщения"
 | 
			
		||||
importAndExport: "Импорт / Экспорт"
 | 
			
		||||
files: "Файл"
 | 
			
		||||
instances: "Экземпляр"
 | 
			
		||||
import: "Импорт"
 | 
			
		||||
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: "Содержимое не для всех"
 | 
			
		||||
add: "Добавить"
 | 
			
		||||
reaction: "Реакции"
 | 
			
		||||
reactionSettingDescription: "Выберите, что показывать в палитре реакций"
 | 
			
		||||
rememberNoteVisibility: "Запоминать видимость поста"
 | 
			
		||||
attachCancel: "Удалить вложение"
 | 
			
		||||
markAsSensitive: "Отметить как «не для всех»"
 | 
			
		||||
unmarkAsSensitive: "Снять отметку «не для всех»"
 | 
			
		||||
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: "Каждый день"
 | 
			
		||||
stopActivityDelivery: "Остановить отправку обновлений активности"
 | 
			
		||||
blockThisInstance: "Блокировать этот инстанс"
 | 
			
		||||
operations: "Операции"
 | 
			
		||||
software: "Программы"
 | 
			
		||||
version: "Версия"
 | 
			
		||||
metadata: "Метаданные"
 | 
			
		||||
withNFiles: "файлов: {n}"
 | 
			
		||||
monitor: "Монитор"
 | 
			
		||||
jobQueue: "Очередь заданий"
 | 
			
		||||
cpuAndMemory: "Процессор и память"
 | 
			
		||||
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: "Имя или идентификатор пользователя"
 | 
			
		||||
noSuchUser: "Таких пользователей не найдено"
 | 
			
		||||
lookup: "Запрос"
 | 
			
		||||
announcements: "Оповещения"
 | 
			
		||||
imageUrl: "Ссылка на изображение"
 | 
			
		||||
remove: "Удалить"
 | 
			
		||||
removed: "Удалено"
 | 
			
		||||
removeAreYouSure: "Хотите удалить «{x}»?"
 | 
			
		||||
saved: "Сохранено"
 | 
			
		||||
messaging: "Сообщения"
 | 
			
		||||
upload: "Загрузить"
 | 
			
		||||
fromDrive: "С «диска»"
 | 
			
		||||
fromUrl: "По ссылке"
 | 
			
		||||
uploadFromUrl: "Загрузить по ссылке"
 | 
			
		||||
uploadFromUrlDescription: "Ссылка на файл, который хотите загрузить"
 | 
			
		||||
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: "Содержимое не для всех"
 | 
			
		||||
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: "Отписаться"
 | 
			
		||||
passwordLessLogin: "Настроить вход без пароля"
 | 
			
		||||
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: "Максимальная длина текста"
 | 
			
		||||
quoteAttached: "Цитата"
 | 
			
		||||
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: "Префикс"
 | 
			
		||||
objectStorageEndpoint: "Конечная точка"
 | 
			
		||||
objectStorageRegion: "Регион"
 | 
			
		||||
objectStorageUseSSL: "Использовать SSL"
 | 
			
		||||
objectStorageUseProxy: "Использовать прокси"
 | 
			
		||||
serverLogs: "Журнал сервера"
 | 
			
		||||
deleteAll: "Удалить всё"
 | 
			
		||||
showFixedPostForm: "Показывать поле для ввода новой заметки наверху ленты."
 | 
			
		||||
newNoteRecived: "Есть новые посты"
 | 
			
		||||
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: "Удалить всех подписчиков"
 | 
			
		||||
removeAllFollowingDescription: "Отменить все подписки с домена {host}? Пожалуйста, применяйте это действие, если инстанс больше не существует."
 | 
			
		||||
userSuspended: "Этот пользователь был заморожен"
 | 
			
		||||
userSilenced: "Этот пользователь был заглушен"
 | 
			
		||||
sidebar: "Боковая панель"
 | 
			
		||||
divider: "Разделительная полоса"
 | 
			
		||||
addItem: "Добавить элемент"
 | 
			
		||||
rooms: "Комнаты"
 | 
			
		||||
relays: "Ретрансляторы"
 | 
			
		||||
addRelay: "Добавить ретранслятор"
 | 
			
		||||
addedRelays: "Добавленные ретрансляторы"
 | 
			
		||||
invisibleNote: "Личное сообщение"
 | 
			
		||||
visibility: "Видимость"
 | 
			
		||||
poll: "Опрос"
 | 
			
		||||
enablePlayer: "Включить плеер"
 | 
			
		||||
disablePlayer: "Выключить плеер"
 | 
			
		||||
themeEditor: "Редактор темы"
 | 
			
		||||
description: "Описание"
 | 
			
		||||
author: "Автор"
 | 
			
		||||
plugins: "Плагины"
 | 
			
		||||
deck: "Панель"
 | 
			
		||||
undeck: "Покинуть панель"
 | 
			
		||||
permission: "Разрешения"
 | 
			
		||||
enableAll: "Включить все"
 | 
			
		||||
disableAll: "Выключить всё"
 | 
			
		||||
notificationType: "Тип уведомления"
 | 
			
		||||
edit: "Изменить"
 | 
			
		||||
emailConfig: "Настройки почтового сервера"
 | 
			
		||||
enableEmail: "Активировать функцию доставки электронной почты"
 | 
			
		||||
emailConfigInfo: "Он используется для подтверждения адреса электронной почты и сброса пароля."
 | 
			
		||||
email: "email"
 | 
			
		||||
smtpConfig: "Конфигурация SMTP-сервера"
 | 
			
		||||
smtpHost: "Хост"
 | 
			
		||||
smtpPort: "smtp порт"
 | 
			
		||||
smtpUser: "Имя пользователя"
 | 
			
		||||
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: "Владелец"
 | 
			
		||||
  following: "Читаю"
 | 
			
		||||
  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: "Упоминание"
 | 
			
		||||
    mentionMe: "Упоминания вас"
 | 
			
		||||
    renote: "Репост"
 | 
			
		||||
    divider: "Разделительная полоса"
 | 
			
		||||
    infoBg: "Справочная информация"
 | 
			
		||||
    infoFg: "Текст информации"
 | 
			
		||||
_sfx:
 | 
			
		||||
  note: "Заметки"
 | 
			
		||||
  notification: "Уведомления"
 | 
			
		||||
  chat: "Сообщения"
 | 
			
		||||
_ago:
 | 
			
		||||
  unknown: "Когда-то"
 | 
			
		||||
  future: "Из будущего"
 | 
			
		||||
  justNow: "Только что"
 | 
			
		||||
  secondsAgo: "{n} с назад"
 | 
			
		||||
  minutesAgo: "{n} мин назад"
 | 
			
		||||
  hoursAgo: "{} часов назад"
 | 
			
		||||
  daysAgo: "{n} сут назад"
 | 
			
		||||
  weeksAgo: "{n} нед. назад"
 | 
			
		||||
  monthsAgo: "{n} мес. назад"
 | 
			
		||||
  yearsAgo: "{n} г. назад"
 | 
			
		||||
_time:
 | 
			
		||||
  second: "с"
 | 
			
		||||
  minute: "мин"
 | 
			
		||||
  hour: "ч"
 | 
			
		||||
  day: "сут"
 | 
			
		||||
_tutorial:
 | 
			
		||||
  title: "Как пользоваться Misskey"
 | 
			
		||||
  step1_1: "Добро пожаловать!"
 | 
			
		||||
  step1_2: "Эта страница называется «лента». Здесь будут появляться ваши «заметки» и тех, на кого вы «подписаны», и располагаться в порядке времени их появления."
 | 
			
		||||
  step1_3: "Правда, ваша лента пока пуста. Она начнёт заполняться, когда вы будете писать свои заметки и подписываться на других."
 | 
			
		||||
  step2_1: "Давайте, сначала заполним профиль, прежде чем начать писать заметки и подписываться на других."
 | 
			
		||||
  step2_2: "То, что вы расскажете в профиле, поможет многим лучше вас узнать, а значит, им будет легче присоединиться к вам — подписаться и читать заметки."
 | 
			
		||||
  step3_1: "Успешно заполнили профиль?"
 | 
			
		||||
  step3_2: "Что ж, теперь самое время опубликуовать заметку. Если нажать вверху страницы на изображение карандаша, появится форма для текста."
 | 
			
		||||
  step3_3: "Напишите в неё, что хотите, и нажмите на кнопку в правом верхнем углу."
 | 
			
		||||
  step3_4: "Ничего не приходит в голову? Как насчёт: «я новенький, пока осваиваюсь в Misskey»?"
 | 
			
		||||
  step4_1: "С написанием первой заметки покончено?"
 | 
			
		||||
  step4_2: "Отлично, теперь она должна появиться в вашей ленте."
 | 
			
		||||
  step5_1: "А теперь самое время немного оживить ленту, подписавшись на других."
 | 
			
		||||
  step5_2: "На странице «{featured}» собраны популярные сегодня заметки, читая которые, вы можете найти кого-то вам интересного, а на «{explore}» можно посмотреть, кто популярен у остальных."
 | 
			
		||||
  step5_3: "Чтобы подписаться на кого-нибудь, щёлкните по его аватару и в открывшемся профиле нажмите кнопку «Подписаться»."
 | 
			
		||||
  step5_4: "Некоторые пользователи (около их имени «висит замок») вручную подтверждают чужие подписки. Так что иногда подписка начинает работать не сразу.\n"
 | 
			
		||||
  step6_1: "Если теперь в ленте видны и чужие заметки, значит у вас получилось."
 | 
			
		||||
  step6_2: "Можете ставить «реакции» чужим заметкам, чтобы непринуждённо выразить свои чувства к ним."
 | 
			
		||||
  step6_3: "Отмечайте реакции, нажмая на символ «+» под заметкой и выбирая значок по душе."
 | 
			
		||||
  step7_1: "На этом вводный урок по использованию Misskey закончен. Спасибо, что прошли его до конца!"
 | 
			
		||||
  step7_2: "Хотите изучить Misskey глубже — добро пожаловать в раздел «{help}»."
 | 
			
		||||
  step7_3: "Приятно вам провести время с Misskey🚀"
 | 
			
		||||
_2fa:
 | 
			
		||||
  alreadyRegistered: "Настройка завершена"
 | 
			
		||||
  registerDevice: "Зарегистрируйте ваше устройство"
 | 
			
		||||
  step1: "Во-первых, установите на устройство приложение для аутентификации, например, {a} или {b}."
 | 
			
		||||
  step2: "Далее отсканируйте отображаемый QR-код при помощи приложения"
 | 
			
		||||
  step3: "Введите токен, отображаемый в приложении, и все готово"
 | 
			
		||||
  step4: "Когда вы войдете в систему, вы можете ввести свой токен тем же способом."
 | 
			
		||||
  securityKeyInfo: "Вы можете настроить вход с помощью аппаратного ключа безопасности, поддерживающего FIDO2, или отпечатка пальца или PIN-кода на устройстве."
 | 
			
		||||
_permissions:
 | 
			
		||||
  "read:account": "Просматривать данные учётной записи"
 | 
			
		||||
  "write:account": "Изменять данные учётной записи"
 | 
			
		||||
  "read:blocks": "Смотреть список блокировок"
 | 
			
		||||
  "write:blocks": "Изменять список блокировок"
 | 
			
		||||
  "read:drive": "Смотреть содержимое «диска»"
 | 
			
		||||
  "write:drive": "Изменять содержимое «диска»"
 | 
			
		||||
  "read:favorites": "Смотреть список избранного"
 | 
			
		||||
  "write:favorites": "Изменять список избранного"
 | 
			
		||||
  "read:following": "Смотреть спискок подписок"
 | 
			
		||||
  "write:following": "Изменять спискок подписок"
 | 
			
		||||
  "read:messaging": "Смотреть сообщения"
 | 
			
		||||
  "write:messaging": "Писать и удалять сообщения"
 | 
			
		||||
  "read:mutes": "Смотреть спискок скрытых пользователей"
 | 
			
		||||
  "write:mutes": "Изменять список скрытых пользователей"
 | 
			
		||||
  "write:notes": "Писать и удалять заметки"
 | 
			
		||||
  "read:notifications": "Смотреть уведомления"
 | 
			
		||||
  "write:notifications": "Изменять уведомления"
 | 
			
		||||
  "read:reactions": "Смотреть реакции"
 | 
			
		||||
  "write:reactions": "Изменять реакции"
 | 
			
		||||
  "write:votes": "Голосовать"
 | 
			
		||||
  "read:pages": "Смотреть страницы"
 | 
			
		||||
  "write:pages": "Изменять и удалять страницы"
 | 
			
		||||
  "read:page-likes": "Смотреть добавления страниц в избранное"
 | 
			
		||||
  "write:page-likes": "Изменять добавления страниц в избранное"
 | 
			
		||||
  "read:user-groups": "Смотреть группы пользователей"
 | 
			
		||||
  "write:user-groups": "Изменять и удалять группы пользователей"
 | 
			
		||||
  "read:channels": "Смотреть каналы"
 | 
			
		||||
  "write:channels": "Изменять каналы"
 | 
			
		||||
_auth:
 | 
			
		||||
  denied: "Доступ закрыт"
 | 
			
		||||
_weekday:
 | 
			
		||||
  sunday: "Воскресенье"
 | 
			
		||||
  monday: "Понедельник"
 | 
			
		||||
  tuesday: "Вторник"
 | 
			
		||||
  wednesday: "Среда"
 | 
			
		||||
  thursday: "Четверг"
 | 
			
		||||
  friday: "Пятница"
 | 
			
		||||
  saturday: "Суббота"
 | 
			
		||||
_widgets:
 | 
			
		||||
  memo: "Напоминания"
 | 
			
		||||
  notifications: "Уведомления"
 | 
			
		||||
  timeline: "Лента"
 | 
			
		||||
  calendar: "Календарь"
 | 
			
		||||
  trends: "Популярное"
 | 
			
		||||
  clock: "Часы"
 | 
			
		||||
  rss: "Просмотр RSS"
 | 
			
		||||
  activity: "Активность"
 | 
			
		||||
  photos: "Фото"
 | 
			
		||||
  digitalClock: "Цифровые часы"
 | 
			
		||||
  federation: "Федерация"
 | 
			
		||||
  postForm: "Форма отправки"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "Спрятать"
 | 
			
		||||
  show: "Показать еще"
 | 
			
		||||
  chars: "{count} символов"
 | 
			
		||||
  files: "{count} файлов"
 | 
			
		||||
_poll:
 | 
			
		||||
  noOnlyOneChoice: "Нужно хотя бы два варианта."
 | 
			
		||||
  choiceN: "Выбор {n}"
 | 
			
		||||
  noMore: "Больше вариантов добавить нельзя"
 | 
			
		||||
  canMultipleVote: "Можно выбрать несколько вариантов"
 | 
			
		||||
  expiration: "Опрос длится"
 | 
			
		||||
  infinite: "вечно"
 | 
			
		||||
  at: "до указанной даты"
 | 
			
		||||
  after: "заданное время"
 | 
			
		||||
  deadlineDate: "Дата окончания"
 | 
			
		||||
  deadlineTime: "Время"
 | 
			
		||||
  duration: "Длительность"
 | 
			
		||||
  votesCount: "Голосов: {n}"
 | 
			
		||||
  totalVotes: "Голосов всего: {n}"
 | 
			
		||||
  vote: "Проголосовать"
 | 
			
		||||
  showResult: "Смотреть результаты"
 | 
			
		||||
  voted: "Проголосовали"
 | 
			
		||||
  closed: "Завершено"
 | 
			
		||||
  remainingDays: "Осталось {d} сут {h} ч"
 | 
			
		||||
  remainingHours: "Осталось {h} ч {m} мин"
 | 
			
		||||
  remainingMinutes: "Осталось {m} мин {s} с"
 | 
			
		||||
  remainingSeconds: "Осталось {s} с"
 | 
			
		||||
_visibility:
 | 
			
		||||
  public: "Общедоступно"
 | 
			
		||||
  publicDescription: "Открыто для всех"
 | 
			
		||||
  home: "Домашняя"
 | 
			
		||||
  homeDescription: "Не появится в общих лентах (локальной и глобальной)"
 | 
			
		||||
  followers: "Для подписчиков"
 | 
			
		||||
  followersDescription: "Увидят только ваши подписчики"
 | 
			
		||||
  specified: "Личное"
 | 
			
		||||
  specifiedDescription: "Только для тех, кого укажете"
 | 
			
		||||
  localOnly: "Локально"
 | 
			
		||||
  localOnlyDescription: "Увидят только пользователи этого сайта"
 | 
			
		||||
_postForm:
 | 
			
		||||
  replyPlaceholder: "Ответ на заметку..."
 | 
			
		||||
  quotePlaceholder: "Пояснение к цитате..."
 | 
			
		||||
  channelPlaceholder: "Отправить в канал"
 | 
			
		||||
  _placeholders:
 | 
			
		||||
    a: "Как дела?"
 | 
			
		||||
    b: "Что интересного вокруг?"
 | 
			
		||||
    c: "Что грызёт тебя, дружище?"
 | 
			
		||||
    d: "Есть что сказать?.."
 | 
			
		||||
    e: "Напишите что-нибудь…"
 | 
			
		||||
    f: "В ожидании, когда вы напишете…"
 | 
			
		||||
_profile:
 | 
			
		||||
  name: "Имя"
 | 
			
		||||
  username: "Имя пользователя"
 | 
			
		||||
  description: "О себе"
 | 
			
		||||
  youCanIncludeHashtags: "Можете использовать здесь хэштеги"
 | 
			
		||||
  metadata: "Всякое"
 | 
			
		||||
  metadataLabel: "Метка"
 | 
			
		||||
  metadataContent: "Содержимое"
 | 
			
		||||
_exportOrImport:
 | 
			
		||||
  allNotes: "Все записи\n"
 | 
			
		||||
  followingList: "Подписки"
 | 
			
		||||
  muteList: "Скрытые"
 | 
			
		||||
  blockingList: "Заблокированные"
 | 
			
		||||
  userLists: "Списки"
 | 
			
		||||
_charts:
 | 
			
		||||
  federationInstancesIncDec: "Изменение внешних связей"
 | 
			
		||||
  federationInstancesTotal: "Количество внешних связей"
 | 
			
		||||
  usersIncDec: "Изменение числа пользователей"
 | 
			
		||||
  usersTotal: "Количество пользователей"
 | 
			
		||||
  activeUsers: "Активные пользователи"
 | 
			
		||||
  notesIncDec: "Изменение числа заметок"
 | 
			
		||||
  localNotesIncDec: "Изменения числа локальных заметок"
 | 
			
		||||
_instanceCharts:
 | 
			
		||||
  users: "Изменение числа пользователей"
 | 
			
		||||
  notes: "Изменение числа заметок"
 | 
			
		||||
_timelines:
 | 
			
		||||
  home: "Главная"
 | 
			
		||||
_rooms:
 | 
			
		||||
  roomOf: "Комната {user}"
 | 
			
		||||
  _roomType:
 | 
			
		||||
    default: "По умолчанию"
 | 
			
		||||
  _furnitures:
 | 
			
		||||
    pencil: "Карандаш"
 | 
			
		||||
    book: "Книга"
 | 
			
		||||
    server: "Сервер"
 | 
			
		||||
    monitor: "Монитор"
 | 
			
		||||
_pages:
 | 
			
		||||
  viewPage: "Смотреть страницы"
 | 
			
		||||
  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: "У вас новый запрос на подписку"
 | 
			
		||||
  yourFollowRequestAccepted: "Ваш запрос на подписку одобрен"
 | 
			
		||||
  youWereInvitedToGroup: "Приглашение в группу"
 | 
			
		||||
  _types:
 | 
			
		||||
    follow: "Подписки"
 | 
			
		||||
    mention: "Упоминание"
 | 
			
		||||
    renote: "Репост"
 | 
			
		||||
    quote: "Цитата"
 | 
			
		||||
    reaction: "Реакции"
 | 
			
		||||
    receiveFollowRequest: "Получен запрос на подписку"
 | 
			
		||||
    followRequestAccepted: "Запрос на подписку одобрен"
 | 
			
		||||
    app: "Уведомления из приложений"
 | 
			
		||||
_deck:
 | 
			
		||||
  alwaysShowMainColumn: "Всегда показывать главную колонку"
 | 
			
		||||
  columnAlign: "Выравнивание колонн"
 | 
			
		||||
  addColumn: "Добавить колонку"
 | 
			
		||||
  swapLeft: "Переместить влево"
 | 
			
		||||
  swapRight: "Переместить вправо"
 | 
			
		||||
  swapUp: "Поднять вверх"
 | 
			
		||||
  swapDown: "Переместить Вниз"
 | 
			
		||||
  _columns:
 | 
			
		||||
    widgets: "Виджеты"
 | 
			
		||||
    notifications: "Уведомления"
 | 
			
		||||
    tl: "Лента"
 | 
			
		||||
    antenna: "Антенны"
 | 
			
		||||
    list: "Списки"
 | 
			
		||||
    mentions: "Упоминания"
 | 
			
		||||
    direct: "Личное"
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,9 @@ noNotes: "没有帖文"
 | 
			
		||||
noNotifications: "无通知"
 | 
			
		||||
instance: "实例"
 | 
			
		||||
settings: "设置"
 | 
			
		||||
basicSettings: "基本设置"
 | 
			
		||||
otherSettings: "其他设置"
 | 
			
		||||
openInWindow: "在新窗口中打开"
 | 
			
		||||
profile: "个人资料"
 | 
			
		||||
timeline: "时间线"
 | 
			
		||||
noAccountDescription: "这个人很懒,没有写自我介绍"
 | 
			
		||||
@@ -40,6 +43,7 @@ deleteAndEditConfirm: "要删除此帖并再次编辑吗?对此帖的所有回
 | 
			
		||||
addToList: "添加至列表"
 | 
			
		||||
sendMessage: "发送"
 | 
			
		||||
copyUsername: "复制用户名"
 | 
			
		||||
searchUser: "搜索用户"
 | 
			
		||||
reply: "回复"
 | 
			
		||||
loadMore: "查看更多"
 | 
			
		||||
youGotNewFollower: "你有新的关注者"
 | 
			
		||||
@@ -66,8 +70,11 @@ followers: "关注者"
 | 
			
		||||
followsYou: "关注了你"
 | 
			
		||||
createList: "创建列表"
 | 
			
		||||
manageLists: "管理列表"
 | 
			
		||||
error: "有点小问题"
 | 
			
		||||
error: "错误"
 | 
			
		||||
somethingHappened: "出现了问题"
 | 
			
		||||
retry: "重试"
 | 
			
		||||
pageLoadError: "页面加载失败。"
 | 
			
		||||
pageLoadErrorDescription: "这通常是由于网络或浏览器缓存的原因。请清除缓存或等待片刻后重试。"
 | 
			
		||||
enterListName: "输入列表名称"
 | 
			
		||||
privacy: "隐私"
 | 
			
		||||
makeFollowManuallyApprove: "关注者请求需要批准"
 | 
			
		||||
@@ -106,6 +113,8 @@ unsuspendConfirm: "要解除冻结吗?"
 | 
			
		||||
selectList: "选择列表"
 | 
			
		||||
selectAntenna: "天线选择"
 | 
			
		||||
selectWidget: "选择小工具"
 | 
			
		||||
editWidgets: "编辑小工具"
 | 
			
		||||
editWidgetsExit: "完成编辑"
 | 
			
		||||
customEmojis: "自定义Emoji"
 | 
			
		||||
emoji: "表情符号"
 | 
			
		||||
emojiName: "Emoji 名称"
 | 
			
		||||
@@ -177,7 +186,6 @@ processing: "处理中"
 | 
			
		||||
preview: "预览"
 | 
			
		||||
default: "默认"
 | 
			
		||||
noCustomEmojis: "无自定义Emoji"
 | 
			
		||||
customEmojisOfRemote: "远程Emoji"
 | 
			
		||||
noJobs: "没有任务"
 | 
			
		||||
federating: "联合中"
 | 
			
		||||
blocked: "已拦截"
 | 
			
		||||
@@ -286,7 +294,7 @@ dayX: "{day}日"
 | 
			
		||||
monthX: "{month}月"
 | 
			
		||||
yearX: "{year}年"
 | 
			
		||||
pages: "页面"
 | 
			
		||||
integration: "连携"
 | 
			
		||||
integration: "关联"
 | 
			
		||||
connectSerice: "已连接"
 | 
			
		||||
disconnectSerice: "断开连接"
 | 
			
		||||
enableLocalTimeline: "启用本地时间线功能"
 | 
			
		||||
@@ -445,7 +453,7 @@ total: "总计"
 | 
			
		||||
weekOverWeekChanges: "与前一周相比"
 | 
			
		||||
dayOverDayChanges: "与前一日相比"
 | 
			
		||||
appearance: "外观"
 | 
			
		||||
clinetSettings: "客户端设置"
 | 
			
		||||
clientSettings: "客户端设置"
 | 
			
		||||
accountSettings: "账户设置"
 | 
			
		||||
promotion: "推广"
 | 
			
		||||
promote: "推广"
 | 
			
		||||
@@ -476,6 +484,8 @@ newNoteRecived: "有新的帖子"
 | 
			
		||||
sounds: "声音"
 | 
			
		||||
listen: "听"
 | 
			
		||||
none: "空"
 | 
			
		||||
showInPage: "在页面中显示"
 | 
			
		||||
popout: "弹窗"
 | 
			
		||||
volume: "音量"
 | 
			
		||||
details: "详情"
 | 
			
		||||
chooseEmoji: "选择表情符号"
 | 
			
		||||
@@ -518,7 +528,6 @@ enableInfiniteScroll: "启用自动滚动页面模式"
 | 
			
		||||
visibility: "可见性"
 | 
			
		||||
poll: "调查问卷"
 | 
			
		||||
useCw: "隐藏内容"
 | 
			
		||||
fixedWidgetsPosition: "固定小工具的位置"
 | 
			
		||||
enablePlayer: "打开播放器"
 | 
			
		||||
disablePlayer: "关闭播放器"
 | 
			
		||||
expandTweet: "展开推文"
 | 
			
		||||
@@ -566,6 +575,24 @@ delayed: "延迟"
 | 
			
		||||
database: "数据库"
 | 
			
		||||
channel: "频道"
 | 
			
		||||
create: "创建"
 | 
			
		||||
notificationSetting: "通知设置"
 | 
			
		||||
notificationSettingDesc: "选择要显示的通知类型。"
 | 
			
		||||
useGlobalSetting: "使用全局设置"
 | 
			
		||||
useGlobalSettingDesc: "启用时,将使用帐户通知设置。关闭时,则可以单独设置。"
 | 
			
		||||
other: "其他"
 | 
			
		||||
regenerateLoginToken: "重新生成登录令牌"
 | 
			
		||||
regenerateLoginTokenDescription: "重新生成用于登录的内部令牌。通常您不需要这样做。重新生成后,您将在所有设备上登出。"
 | 
			
		||||
setMultipleBySeparatingWithSpace: "您可以使用空格分隔多个项目。"
 | 
			
		||||
fileIdOrUrl: "文件ID或者URL"
 | 
			
		||||
chatOpenBehavior: "聊天窗口打开时的行为"
 | 
			
		||||
sample: "示例"
 | 
			
		||||
abuseReports: "举报"
 | 
			
		||||
reportAbuse: "举报"
 | 
			
		||||
reportAbuseOf: "举报{name}"
 | 
			
		||||
fillAbuseReportDescription: "请填写举报的详细原因。如果有对方发的帖子,请同时填写URL地址。"
 | 
			
		||||
abuseReported: "内容已发送。感谢您的报告。"
 | 
			
		||||
send: "发送"
 | 
			
		||||
abuseMarkAsResolved: "处理完毕"
 | 
			
		||||
_serverDisconnectedBehavior:
 | 
			
		||||
  reload: "自动重载"
 | 
			
		||||
  dialog: "对话框警告"
 | 
			
		||||
@@ -782,6 +809,7 @@ _widgets:
 | 
			
		||||
  photos: "照片"
 | 
			
		||||
  digitalClock: "数字时钟"
 | 
			
		||||
  federation: "联邦宇宙"
 | 
			
		||||
  postForm: "投稿窗口"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "隐藏"
 | 
			
		||||
  show: "查看更多"
 | 
			
		||||
@@ -1244,8 +1272,11 @@ _notification:
 | 
			
		||||
    renote: "转发"
 | 
			
		||||
    quote: "引用"
 | 
			
		||||
    reaction: "回应"
 | 
			
		||||
    pollVote: "投票"
 | 
			
		||||
    receiveFollowRequest: "关注请求"
 | 
			
		||||
    pollVote: "问卷调查已投票"
 | 
			
		||||
    receiveFollowRequest: "收到关注请求"
 | 
			
		||||
    followRequestAccepted: "关注请求已接受"
 | 
			
		||||
    groupInvited: "加入群组邀请"
 | 
			
		||||
    app: "关联应用的通知"
 | 
			
		||||
_deck:
 | 
			
		||||
  alwaysShowMainColumn: "总是显示主列"
 | 
			
		||||
  columnAlign: "列对齐"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
---
 | 
			
		||||
_lang_: "中文(繁體)"
 | 
			
		||||
_lang_: "繁體中文"
 | 
			
		||||
introMisskey: "歡迎! Misskey是一個開源的去中心化的社群網站。\n通過「貼文」來分享現在發生的事情吧! 📡\n「反應」功能,可以讓你快速的對大家的「帖子」來表達感情👍\n一起來探索新的世界吧! 🚀"
 | 
			
		||||
monthAndDay: "{month}月 {day}日"
 | 
			
		||||
search: "搜尋"
 | 
			
		||||
@@ -11,11 +11,14 @@ ok: "確定"
 | 
			
		||||
gotIt: "知道了"
 | 
			
		||||
cancel: "取消"
 | 
			
		||||
enterUsername: "輸入使用者名稱"
 | 
			
		||||
renotedBy: "由{user}轉發"
 | 
			
		||||
renotedBy: "{user} 轉發了"
 | 
			
		||||
noNotes: "貼文不可用。"
 | 
			
		||||
noNotifications: "沒有通知"
 | 
			
		||||
instance: "實例"
 | 
			
		||||
settings: "設定"
 | 
			
		||||
basicSettings: "基本設定"
 | 
			
		||||
otherSettings: "其他設定"
 | 
			
		||||
openInWindow: "在新視窗開啟"
 | 
			
		||||
profile: "個人檔案"
 | 
			
		||||
timeline: "時間軸"
 | 
			
		||||
noAccountDescription: "此用戶還沒有自我介紹"
 | 
			
		||||
@@ -40,6 +43,7 @@ deleteAndEditConfirm: "要刪除並再次編輯嗎?此貼文的所有反應,
 | 
			
		||||
addToList: "添加至清單"
 | 
			
		||||
sendMessage: "發送訊息"
 | 
			
		||||
copyUsername: "複製用戶名"
 | 
			
		||||
searchUser: "搜尋用戶"
 | 
			
		||||
reply: "回覆"
 | 
			
		||||
loadMore: "瀏覽更多"
 | 
			
		||||
youGotNewFollower: "您有新的追隨者"
 | 
			
		||||
@@ -66,8 +70,10 @@ followers: "追隨者"
 | 
			
		||||
followsYou: "追隨你的人"
 | 
			
		||||
createList: "建立清單"
 | 
			
		||||
manageLists: "管理清單"
 | 
			
		||||
error: "發生錯誤"
 | 
			
		||||
error: "錯誤"
 | 
			
		||||
somethingHappened: "發生錯誤"
 | 
			
		||||
retry: "重試"
 | 
			
		||||
pageLoadError: "載入頁面失敗"
 | 
			
		||||
enterListName: "輸入清單名稱"
 | 
			
		||||
privacy: "隱私"
 | 
			
		||||
makeFollowManuallyApprove: "手動審核追隨請求"
 | 
			
		||||
@@ -106,13 +112,15 @@ unsuspendConfirm: "確定解凍此帳號?"
 | 
			
		||||
selectList: "選擇清單"
 | 
			
		||||
selectAntenna: "選擇天線"
 | 
			
		||||
selectWidget: "選擇小工具"
 | 
			
		||||
editWidgets: "編輯小工具"
 | 
			
		||||
editWidgetsExit: "停止編輯"
 | 
			
		||||
customEmojis: "自訂表情符號"
 | 
			
		||||
emoji: "表情符號"
 | 
			
		||||
emojiName: "表情符號名稱"
 | 
			
		||||
emojiUrl: "表情符號URL"
 | 
			
		||||
addEmoji: "新增表情符號"
 | 
			
		||||
settingGuide: "推薦設定"
 | 
			
		||||
cacheRemoteFiles: "遠程文件緩存"
 | 
			
		||||
cacheRemoteFiles: "緩存非遠程檔案"
 | 
			
		||||
cacheRemoteFilesDescription: "如果禁用此設定,遠程文件將會被直接連結而非緩存。禁用將節省服務器上的存儲空間,但會因為沒有生成預覽圖而增加流量。"
 | 
			
		||||
flagAsBot: "此帳戶是Bot"
 | 
			
		||||
flagAsCat: "此帳戶是Cat"
 | 
			
		||||
@@ -176,7 +184,6 @@ processing: "處理中"
 | 
			
		||||
preview: "預覽"
 | 
			
		||||
default: "預設"
 | 
			
		||||
noCustomEmojis: "沒有表情符號"
 | 
			
		||||
customEmojisOfRemote: "來自其他實例的表情符號"
 | 
			
		||||
noJobs: "沒有任務"
 | 
			
		||||
federating: "整合搜索中"
 | 
			
		||||
blocked: "已封鎖"
 | 
			
		||||
@@ -223,7 +230,7 @@ nUsersRead: "{n}人已讀"
 | 
			
		||||
tos: "使用條款"
 | 
			
		||||
start: "開始"
 | 
			
		||||
home: "首頁"
 | 
			
		||||
remoteUserCaution: "由於是遠程用戶,信息不完整。"
 | 
			
		||||
remoteUserCaution: "由於該用戶來自遠端實例,因此資料用戶並未即時更新。"
 | 
			
		||||
activity: "動態"
 | 
			
		||||
images: "圖片"
 | 
			
		||||
birthday: "生日"
 | 
			
		||||
@@ -293,7 +300,7 @@ disablingTimelinesInfo: "即使您禁用了時間線功能,管理員和協調
 | 
			
		||||
registration: "註冊"
 | 
			
		||||
enableRegistration: "開啟新用戶註冊"
 | 
			
		||||
invite: "邀請"
 | 
			
		||||
proxyRemoteFiles: "代理遠程檔案"
 | 
			
		||||
proxyRemoteFiles: "遠端代理檔案"
 | 
			
		||||
proxyRemoteFilesDescription: "啟用此設置後,由於超出存儲容量而未保存或刪除的遠程文件將被本地代理,並且將生成預覽圖。這不影響服務器的存儲。"
 | 
			
		||||
driveCapacityPerLocalAccount: "每個本地用戶的雲端容量"
 | 
			
		||||
driveCapacityPerRemoteAccount: "每個非本地用戶的雲端容量"
 | 
			
		||||
@@ -316,7 +323,7 @@ antennas: "天線"
 | 
			
		||||
manageAntennas: "管理天線"
 | 
			
		||||
name: "名稱"
 | 
			
		||||
antennaSource: "接收來源"
 | 
			
		||||
antennaKeywords: "包含的關鍵字"
 | 
			
		||||
antennaKeywords: "包含關鍵字"
 | 
			
		||||
antennaExcludeKeywords: "排除關鍵字"
 | 
			
		||||
antennaKeywordsDescription: "用空格分隔指定AND、用換行符分隔指定OR"
 | 
			
		||||
notifyAntenna: "通知我有新的貼文"
 | 
			
		||||
@@ -430,12 +437,23 @@ category: "類別"
 | 
			
		||||
tags: "標籤"
 | 
			
		||||
docSource: "文件來源"
 | 
			
		||||
createAccount: "建立帳戶"
 | 
			
		||||
existingAcount: "現有帳戶"
 | 
			
		||||
regenerate: "再生"
 | 
			
		||||
fontSize: "字體大小"
 | 
			
		||||
openImageInNewTab: "於新分頁中開啟圖片"
 | 
			
		||||
local: "本地"
 | 
			
		||||
remote: "遠端"
 | 
			
		||||
total: "合計"
 | 
			
		||||
clinetSettings: "用戶端設定"
 | 
			
		||||
appearance: "外觀"
 | 
			
		||||
accountSettings: "帳戶設置"
 | 
			
		||||
objectStoragePrefix: "前綴"
 | 
			
		||||
objectStorageUseSSL: "使用SSL"
 | 
			
		||||
objectStorageUseProxy: "使用網路代理"
 | 
			
		||||
serverLogs: "伺服器日誌"
 | 
			
		||||
deleteAll: "刪除所有記錄"
 | 
			
		||||
sounds: "音效"
 | 
			
		||||
none: "無"
 | 
			
		||||
showInPage: "在頁面中顯示"
 | 
			
		||||
volume: "音量"
 | 
			
		||||
details: "詳細資訊"
 | 
			
		||||
chooseEmoji: "選擇您的表情符號\n"
 | 
			
		||||
@@ -443,14 +461,21 @@ unableToProcess: "操作無法完成"
 | 
			
		||||
recentUsed: "最近使用"
 | 
			
		||||
install: "安裝"
 | 
			
		||||
uninstall: "解除安裝"
 | 
			
		||||
installedApps: "已授權的應用程式"
 | 
			
		||||
nothing: "未發現"
 | 
			
		||||
installedDate: "安裝時間"
 | 
			
		||||
lastUsedDate: "最後上線日期"
 | 
			
		||||
state: "狀態"
 | 
			
		||||
sort: "排序"
 | 
			
		||||
ascendingOrder: "昇冪"
 | 
			
		||||
descendingOrder: "降冪"
 | 
			
		||||
scratchpad: "暫存記憶體"
 | 
			
		||||
output: "輸出"
 | 
			
		||||
script: "腳本"
 | 
			
		||||
updateRemoteUser: "更新非本地用戶資料"
 | 
			
		||||
deleteAllFiles: "刪除所有檔案"
 | 
			
		||||
deleteAllFilesConfirm: "要删除所有檔案吗?"
 | 
			
		||||
removeAllFollowing: "解除所有追隨"
 | 
			
		||||
userSuspended: "該用戶已被凍結"
 | 
			
		||||
userSilenced: "該用戶已被禁言。"
 | 
			
		||||
sidebar: "側邊列"
 | 
			
		||||
@@ -468,7 +493,6 @@ enableInfiniteScroll: "啟用自動滾動頁面模式"
 | 
			
		||||
visibility: "公開範圍"
 | 
			
		||||
poll: "投票"
 | 
			
		||||
useCw: "隱藏內容"
 | 
			
		||||
fixedWidgetsPosition: "固定小工具的位置"
 | 
			
		||||
enablePlayer: "打開播放器"
 | 
			
		||||
disablePlayer: "關閉播放器"
 | 
			
		||||
expandTweet: "展開推文"
 | 
			
		||||
@@ -497,8 +521,15 @@ smtpHost: "主機"
 | 
			
		||||
smtpPort: "端口"
 | 
			
		||||
smtpUser: "使用名稱"
 | 
			
		||||
smtpPass: "密碼"
 | 
			
		||||
display: "檢視"
 | 
			
		||||
copy: "複製"
 | 
			
		||||
metrics: "指標"
 | 
			
		||||
logs: "日誌"
 | 
			
		||||
delayed: "延遲"
 | 
			
		||||
database: "資料庫"
 | 
			
		||||
channel: "頻道"
 | 
			
		||||
create: "新增"
 | 
			
		||||
notificationSetting: "管理通知"
 | 
			
		||||
_serverDisconnectedBehavior:
 | 
			
		||||
  reload: "自動重載"
 | 
			
		||||
  dialog: "以對話框警告"
 | 
			
		||||
@@ -515,12 +546,19 @@ _channel:
 | 
			
		||||
  notesCount: "有{n}個帖子"
 | 
			
		||||
_sidebar:
 | 
			
		||||
  icon: "頭像"
 | 
			
		||||
  hide: "隱藏"
 | 
			
		||||
_wordMute:
 | 
			
		||||
  muteWords: "加入靜音文字"
 | 
			
		||||
_theme:
 | 
			
		||||
  color: "顏色"
 | 
			
		||||
  func: "函数"
 | 
			
		||||
  keys:
 | 
			
		||||
    bg: "背景"
 | 
			
		||||
    mention: "提及"
 | 
			
		||||
    renote: "轉發貼文"
 | 
			
		||||
    divider: "分割線"
 | 
			
		||||
    infoBg: "資訊背景"
 | 
			
		||||
    infoFg: "資訊內容"
 | 
			
		||||
_sfx:
 | 
			
		||||
  note: "貼文"
 | 
			
		||||
  noteMy: "我的貼文"
 | 
			
		||||
@@ -579,6 +617,8 @@ _permissions:
 | 
			
		||||
  "write:votes": "投票"
 | 
			
		||||
  "read:channels": "已查看的頻道"
 | 
			
		||||
  "write:channels": "操作頻道"
 | 
			
		||||
_antennaSources:
 | 
			
		||||
  all: "全部貼文"
 | 
			
		||||
_weekday:
 | 
			
		||||
  sunday: "週日"
 | 
			
		||||
  monday: "週一"
 | 
			
		||||
@@ -588,33 +628,53 @@ _weekday:
 | 
			
		||||
  friday: "週五"
 | 
			
		||||
  saturday: "週六"
 | 
			
		||||
_widgets:
 | 
			
		||||
  memo: "備忘錄"
 | 
			
		||||
  notifications: "通知"
 | 
			
		||||
  timeline: "時間軸"
 | 
			
		||||
  calendar: "行事曆"
 | 
			
		||||
  trends: "發燒貼文"
 | 
			
		||||
  clock: "時鐘"
 | 
			
		||||
  rss: "RSS閱讀器"
 | 
			
		||||
  activity: "動態"
 | 
			
		||||
  photos: "照片"
 | 
			
		||||
  digitalClock: "電子時鐘"
 | 
			
		||||
  federation: "聯邦宇宙"
 | 
			
		||||
_cw:
 | 
			
		||||
  hide: "隱藏"
 | 
			
		||||
  show: "瀏覽更多"
 | 
			
		||||
  chars: "{count}字元"
 | 
			
		||||
  files: "{count} 個檔案"
 | 
			
		||||
_poll:
 | 
			
		||||
  noOnlyOneChoice: "至少需要兩個選項。"
 | 
			
		||||
  expiration: "期限"
 | 
			
		||||
  infinite: "無期限"
 | 
			
		||||
  deadlineDate: "截止日期"
 | 
			
		||||
  deadlineTime: "小時"
 | 
			
		||||
  votesCount: "{n}票"
 | 
			
		||||
  totalVotes: "一共{n}票"
 | 
			
		||||
  vote: "投票"
 | 
			
		||||
  showResult: "顯示結果"
 | 
			
		||||
  voted: "已投票"
 | 
			
		||||
  closed: "已結束"
 | 
			
		||||
_visibility:
 | 
			
		||||
  home: "首頁"
 | 
			
		||||
  followers: "追隨者"
 | 
			
		||||
  localOnly: "僅限本地"
 | 
			
		||||
_postForm:
 | 
			
		||||
  channelPlaceholder: "發佈到頻道"
 | 
			
		||||
_profile:
 | 
			
		||||
  name: "名稱"
 | 
			
		||||
  username: "使用名稱"
 | 
			
		||||
  metadataLabel: "標籤"
 | 
			
		||||
  metadataContent: "内容"
 | 
			
		||||
_exportOrImport:
 | 
			
		||||
  allNotes: "全部貼文"
 | 
			
		||||
  followingList: "追隨中"
 | 
			
		||||
  muteList: "消音"
 | 
			
		||||
  blockingList: "封鎖"
 | 
			
		||||
  userLists: "清單"
 | 
			
		||||
_charts:
 | 
			
		||||
  remoteNotesIncDec: "非本地貼文的數目增减"
 | 
			
		||||
_instanceCharts:
 | 
			
		||||
  cacheSize: "增加或減少快取用量"
 | 
			
		||||
  cacheSizeTotal: "快取大小總計"
 | 
			
		||||
@@ -632,6 +692,8 @@ _pages:
 | 
			
		||||
  unlike: "收回喜歡"
 | 
			
		||||
  blocks:
 | 
			
		||||
    image: "圖片"
 | 
			
		||||
    _post:
 | 
			
		||||
      text: "内容"
 | 
			
		||||
    _textareaInput:
 | 
			
		||||
      name: "變數名稱"
 | 
			
		||||
    numberInput: "輸入數值"
 | 
			
		||||
@@ -643,6 +705,9 @@ _pages:
 | 
			
		||||
      text: "標題"
 | 
			
		||||
    _button:
 | 
			
		||||
      text: "標題"
 | 
			
		||||
      _action:
 | 
			
		||||
        _dialog:
 | 
			
		||||
          content: "内容"
 | 
			
		||||
  script:
 | 
			
		||||
    categories:
 | 
			
		||||
      value: "數值 "
 | 
			
		||||
@@ -782,6 +847,7 @@ _relayStatus:
 | 
			
		||||
  accepted: "已通過核准"
 | 
			
		||||
  rejected: "已拒絕"
 | 
			
		||||
_notification:
 | 
			
		||||
  youRenoted: "{name} 轉發了你的貼文"
 | 
			
		||||
  youGotPoll: "{name}已投票"
 | 
			
		||||
  youWereFollowed: "您有新的追隨者"
 | 
			
		||||
  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 DEFAULT '{}'::varchar[]`);
 | 
			
		||||
        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 DEFAULT '{}'::varchar[]`);
 | 
			
		||||
        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"`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								package.json
									
									
									
									
									
								
							@@ -1,7 +1,7 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "misskey",
 | 
			
		||||
	"author": "syuilo <syuilotan@yahoo.co.jp>",
 | 
			
		||||
	"version": "12.48.2",
 | 
			
		||||
	"version": "12.50.0",
 | 
			
		||||
	"codename": "indigo",
 | 
			
		||||
	"repository": {
 | 
			
		||||
		"type": "git",
 | 
			
		||||
@@ -46,7 +46,7 @@
 | 
			
		||||
		"@koa/multer": "3.0.0",
 | 
			
		||||
		"@koa/router": "9.0.1",
 | 
			
		||||
		"@sinonjs/fake-timers": "6.0.1",
 | 
			
		||||
		"@syuilo/aiscript": "0.11.0",
 | 
			
		||||
		"@syuilo/aiscript": "0.11.1",
 | 
			
		||||
		"@types/bcryptjs": "2.4.2",
 | 
			
		||||
		"@types/bull": "3.14.0",
 | 
			
		||||
		"@types/cbor": "5.0.1",
 | 
			
		||||
@@ -92,7 +92,7 @@
 | 
			
		||||
		"@types/request-stats": "3.0.0",
 | 
			
		||||
		"@types/rimraf": "3.0.0",
 | 
			
		||||
		"@types/seedrandom": "2.4.28",
 | 
			
		||||
		"@types/sharp": "0.25.0",
 | 
			
		||||
		"@types/sharp": "0.26.0",
 | 
			
		||||
		"@types/sinonjs__fake-timers": "6.0.1",
 | 
			
		||||
		"@types/speakeasy": "2.0.5",
 | 
			
		||||
		"@types/tinycolor2": "1.4.2",
 | 
			
		||||
@@ -104,7 +104,7 @@
 | 
			
		||||
		"@types/websocket": "1.0.1",
 | 
			
		||||
		"@types/ws": "7.2.7",
 | 
			
		||||
		"@typescript-eslint/parser": "4.4.0",
 | 
			
		||||
		"@vue/compiler-sfc": "3.0.0",
 | 
			
		||||
		"@vue/compiler-sfc": "3.0.2",
 | 
			
		||||
		"abort-controller": "3.0.0",
 | 
			
		||||
		"apexcharts": "3.22.0",
 | 
			
		||||
		"autobind-decorator": "2.4.0",
 | 
			
		||||
@@ -123,19 +123,19 @@
 | 
			
		||||
		"content-disposition": "0.5.3",
 | 
			
		||||
		"core-js": "3.6.5",
 | 
			
		||||
		"crc-32": "1.2.0",
 | 
			
		||||
		"css-loader": "4.3.0",
 | 
			
		||||
		"css-loader": "5.0.0",
 | 
			
		||||
		"cssnano": "4.1.10",
 | 
			
		||||
		"dateformat": "3.0.3",
 | 
			
		||||
		"deep-entries": "3.1.0",
 | 
			
		||||
		"diskusage": "1.1.3",
 | 
			
		||||
		"double-ended-queue": "2.1.0-0",
 | 
			
		||||
		"escape-regexp": "0.0.1",
 | 
			
		||||
		"eslint": "7.10.0",
 | 
			
		||||
		"eslint-plugin-vue": "7.0.1",
 | 
			
		||||
		"eslint": "7.11.0",
 | 
			
		||||
		"eslint-plugin-vue": "7.1.0",
 | 
			
		||||
		"eventemitter3": "4.0.7",
 | 
			
		||||
		"feed": "4.2.1",
 | 
			
		||||
		"fibers": "5.0.0",
 | 
			
		||||
		"file-type": "15.0.1",
 | 
			
		||||
		"file-type": "16.0.0",
 | 
			
		||||
		"fluent-ffmpeg": "2.1.2",
 | 
			
		||||
		"glob": "7.1.6",
 | 
			
		||||
		"got": "11.7.0",
 | 
			
		||||
@@ -159,8 +159,8 @@
 | 
			
		||||
		"js-yaml": "3.14.0",
 | 
			
		||||
		"jsdom": "16.4.0",
 | 
			
		||||
		"json5": "2.1.3",
 | 
			
		||||
		"json5-loader": "4.0.0",
 | 
			
		||||
		"jsonld": "3.1.1",
 | 
			
		||||
		"json5-loader": "4.0.1",
 | 
			
		||||
		"jsonld": "3.2.0",
 | 
			
		||||
		"jsrsasign": "8.0.20",
 | 
			
		||||
		"katex": "0.12.0",
 | 
			
		||||
		"koa": "2.13.0",
 | 
			
		||||
@@ -190,9 +190,9 @@
 | 
			
		||||
		"parsimmon": "1.16.0",
 | 
			
		||||
		"pg": "8.4.1",
 | 
			
		||||
		"portscanner": "2.2.0",
 | 
			
		||||
		"postcss": "8.1.1",
 | 
			
		||||
		"postcss-loader": "4.0.3",
 | 
			
		||||
		"prismjs": "1.21.0",
 | 
			
		||||
		"postcss": "8.1.3",
 | 
			
		||||
		"postcss-loader": "4.0.4",
 | 
			
		||||
		"prismjs": "1.22.0",
 | 
			
		||||
		"probe-image-size": "5.0.0",
 | 
			
		||||
		"promise-limit": "2.7.0",
 | 
			
		||||
		"promise-sequential": "1.1.1",
 | 
			
		||||
@@ -202,8 +202,8 @@
 | 
			
		||||
		"qrcode": "1.4.4",
 | 
			
		||||
		"random-seed": "0.3.0",
 | 
			
		||||
		"ratelimiter": "3.4.1",
 | 
			
		||||
		"re2": "1.15.5",
 | 
			
		||||
		"recaptcha-promise": "0.1.3",
 | 
			
		||||
		"re2": "1.15.8",
 | 
			
		||||
		"recaptcha-promise": "1.0.0",
 | 
			
		||||
		"reconnecting-websocket": "4.4.0",
 | 
			
		||||
		"redis": "3.0.2",
 | 
			
		||||
		"redis-lock": "0.1.4",
 | 
			
		||||
@@ -216,47 +216,45 @@
 | 
			
		||||
		"rndstr": "1.0.0",
 | 
			
		||||
		"s-age": "1.1.2",
 | 
			
		||||
		"sass": "1.27.0",
 | 
			
		||||
		"sass-loader": "10.0.2",
 | 
			
		||||
		"sass-loader": "10.0.4",
 | 
			
		||||
		"seedrandom": "3.0.5",
 | 
			
		||||
		"sharp": "0.26.1",
 | 
			
		||||
		"sharp": "0.26.2",
 | 
			
		||||
		"speakeasy": "2.0.0",
 | 
			
		||||
		"stringz": "2.1.0",
 | 
			
		||||
		"style-loader": "1.3.0",
 | 
			
		||||
		"style-loader": "2.0.0",
 | 
			
		||||
		"summaly": "2.4.0",
 | 
			
		||||
		"syslog-pro": "1.0.0",
 | 
			
		||||
		"systeminformation": "4.27.8",
 | 
			
		||||
		"systeminformation": "4.27.10",
 | 
			
		||||
		"syuilo-password-strength": "0.0.1",
 | 
			
		||||
		"textarea-caret": "3.1.0",
 | 
			
		||||
		"three": "0.117.1",
 | 
			
		||||
		"tinycolor2": "1.4.2",
 | 
			
		||||
		"tmp": "0.2.1",
 | 
			
		||||
		"ts-loader": "8.0.4",
 | 
			
		||||
		"ts-loader": "8.0.6",
 | 
			
		||||
		"ts-node": "9.0.0",
 | 
			
		||||
		"tslint": "6.1.3",
 | 
			
		||||
		"tslint-sonarts": "1.9.0",
 | 
			
		||||
		"typeorm": "0.2.28",
 | 
			
		||||
		"typescript": "4.0.3",
 | 
			
		||||
		"ulid": "2.3.0",
 | 
			
		||||
		"url-loader": "4.1.0",
 | 
			
		||||
		"url-loader": "4.1.1",
 | 
			
		||||
		"uuid": "8.3.1",
 | 
			
		||||
		"v-debounce": "0.1.2",
 | 
			
		||||
		"vue": "3.0.1",
 | 
			
		||||
		"vue": "3.0.2",
 | 
			
		||||
		"vue-color": "2.7.1",
 | 
			
		||||
		"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-loader": "16.0.0-beta.7",
 | 
			
		||||
		"vue-prism-component": "1.2.0",
 | 
			
		||||
		"vue-loader": "16.0.0-beta.8",
 | 
			
		||||
		"vue-prism-editor": "1.2.2",
 | 
			
		||||
		"vue-router": "4.0.0-beta.13",
 | 
			
		||||
		"vue-style-loader": "4.1.2",
 | 
			
		||||
		"vue-svg-inline-loader-corejs3": "1.5.0",
 | 
			
		||||
		"vue-template-compiler": "2.6.12",
 | 
			
		||||
		"vuex": "4.0.0-beta.4",
 | 
			
		||||
		"vuex-persistedstate": "3.1.0",
 | 
			
		||||
		"web-push": "3.4.4",
 | 
			
		||||
		"webpack": "5.1.3",
 | 
			
		||||
		"webpack-cli": "3.3.12",
 | 
			
		||||
		"webpack": "5.2.0",
 | 
			
		||||
		"webpack-cli": "4.1.0",
 | 
			
		||||
		"websocket": "1.0.32",
 | 
			
		||||
		"ws": "7.3.1",
 | 
			
		||||
		"xev": "2.0.1"
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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>
 | 
			
		||||
@@ -2,9 +2,9 @@
 | 
			
		||||
<span class="eiwwqkts" :class="{ cat }" :title="acct(user)" v-if="disableLink" v-user-preview="disablePreview ? undefined : user.id" @click="onClick">
 | 
			
		||||
	<img class="inner" :src="url"/>
 | 
			
		||||
</span>
 | 
			
		||||
<router-link class="eiwwqkts" :class="{ cat }" :to="userPage(user)" :title="acct(user)" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
 | 
			
		||||
<MkA class="eiwwqkts" :class="{ cat }" :to="userPage(user)" :title="acct(user)" :target="target" v-else v-user-preview="disablePreview ? undefined : user.id">
 | 
			
		||||
	<img class="inner" :src="url"/>
 | 
			
		||||
</router-link>
 | 
			
		||||
</MkA>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<router-link :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1">
 | 
			
		||||
<MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1">
 | 
			
		||||
	<div class="banner" v-if="channel.bannerUrl" :style="`background-image: url('${channel.bannerUrl}')`">
 | 
			
		||||
		<div class="fade"></div>
 | 
			
		||||
		<div class="name"><Fa :icon="faSatelliteDish"/> {{ channel.name }}</div>
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
			{{ $t('updatedAt') }}: <MkTime :time="channel.lastNotedAt"/>
 | 
			
		||||
		</span>
 | 
			
		||||
	</footer>
 | 
			
		||||
</router-link>
 | 
			
		||||
</MkA>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,14 @@
 | 
			
		||||
<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>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import 'prismjs';
 | 
			
		||||
import 'prismjs/themes/prism-okaidia.css';
 | 
			
		||||
import XPrism from 'vue-prism-component';import * as os from '@/os';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	components: {
 | 
			
		||||
		XPrism
 | 
			
		||||
	},
 | 
			
		||||
	props: {
 | 
			
		||||
		code: {
 | 
			
		||||
			type: String,
 | 
			
		||||
@@ -29,6 +26,9 @@ export default defineComponent({
 | 
			
		||||
	computed: {
 | 
			
		||||
		prismLang() {
 | 
			
		||||
			return Prism.languages[this.lang] ? this.lang : 'js';
 | 
			
		||||
		},
 | 
			
		||||
		html() {
 | 
			
		||||
			return Prism.highlight(this.code, Prism.languages[this.prismLang], this.prismLang);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 
 | 
			
		||||
@@ -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>
 | 
			
		||||
			<span>{{ image.type }}</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>
 | 
			
		||||
	</div>
 | 
			
		||||
</MkModal>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
import { App } from 'vue';
 | 
			
		||||
 | 
			
		||||
import mfm from './misskey-flavored-markdown.vue';
 | 
			
		||||
import a from './ui/a.vue';
 | 
			
		||||
import acct from './acct.vue';
 | 
			
		||||
import avatar from './avatar.vue';
 | 
			
		||||
import emoji from './emoji.vue';
 | 
			
		||||
@@ -10,10 +11,10 @@ import time from './time.vue';
 | 
			
		||||
import url from './url.vue';
 | 
			
		||||
import loading from './loading.vue';
 | 
			
		||||
import error from './error.vue';
 | 
			
		||||
import streamIndicator from './stream-indicator.vue';
 | 
			
		||||
 | 
			
		||||
export default function(app: App) {
 | 
			
		||||
	app.component('Mfm', mfm);
 | 
			
		||||
	app.component('MkA', a);
 | 
			
		||||
	app.component('MkAcct', acct);
 | 
			
		||||
	app.component('MkAvatar', avatar);
 | 
			
		||||
	app.component('MkEmoji', emoji);
 | 
			
		||||
@@ -23,5 +24,4 @@ export default function(app: App) {
 | 
			
		||||
	app.component('MkUrl', url);
 | 
			
		||||
	app.component('MkLoading', loading);
 | 
			
		||||
	app.component('MkError', error);
 | 
			
		||||
	app.component('StreamIndicator', streamIndicator);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<component :is="self ? 'router-link' : 'a'" class="xlcxczvw _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
 | 
			
		||||
<component :is="self ? 'MkA' : 'a'" class="xlcxczvw _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
 | 
			
		||||
	@mouseover="onMouseover"
 | 
			
		||||
	@mouseleave="onMouseleave"
 | 
			
		||||
	:title="url"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,11 @@
 | 
			
		||||
<template>
 | 
			
		||||
<router-link class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
 | 
			
		||||
<MkA class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')">
 | 
			
		||||
	<span class="me" v-if="isMe">{{ $t('you') }}</span>
 | 
			
		||||
	<span class="main">
 | 
			
		||||
		<span class="username">@{{ username }}</span>
 | 
			
		||||
		<span class="host" v-if="(host != localHost) || $store.state.settings.showFullAcct">@{{ toUnicode(host) }}</span>
 | 
			
		||||
	</span>
 | 
			
		||||
</router-link>
 | 
			
		||||
</MkA>
 | 
			
		||||
<a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else>
 | 
			
		||||
	<span class="main">
 | 
			
		||||
		<span class="username">@{{ username }}</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,8 +9,8 @@ import { concat } from '../../prelude/array';
 | 
			
		||||
import MkFormula from './formula.vue';
 | 
			
		||||
import MkCode from './code.vue';
 | 
			
		||||
import MkGoogle from './google.vue';
 | 
			
		||||
import MkA from './ui/a.vue';
 | 
			
		||||
import { host } from '@/config';
 | 
			
		||||
import { RouterLink } from 'vue-router';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	props: {
 | 
			
		||||
@@ -150,7 +150,7 @@ export default defineComponent({
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				case 'hashtag': {
 | 
			
		||||
					return [h(RouterLink, {
 | 
			
		||||
					return [h(MkA, {
 | 
			
		||||
						key: Math.random(),
 | 
			
		||||
						to: this.isNote ? `/tags/${encodeURIComponent(token.node.props.hashtag)}` : `/explore/tags/${encodeURIComponent(token.node.props.hashtag)}`,
 | 
			
		||||
						style: 'color:var(--hashtag);'
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,9 @@ export default defineComponent({
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	> ::v-deep(code) {
 | 
			
		||||
		font-size: 0.8em;
 | 
			
		||||
		word-break: break-all;
 | 
			
		||||
		padding: 4px 6px;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	::v-deep(.title) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,17 @@
 | 
			
		||||
<template>
 | 
			
		||||
<header class="kkwtjztg">
 | 
			
		||||
	<router-link class="name" :to="userPage(note.user)" v-user-preview="note.user.id">
 | 
			
		||||
	<MkA class="name" :to="userPage(note.user)" v-user-preview="note.user.id">
 | 
			
		||||
		<MkUserName :user="note.user"/>
 | 
			
		||||
	</router-link>
 | 
			
		||||
	</MkA>
 | 
			
		||||
	<span class="is-bot" v-if="note.user.isBot">bot</span>
 | 
			
		||||
	<span class="username"><MkAcct :user="note.user"/></span>
 | 
			
		||||
	<span class="admin" v-if="note.user.isAdmin"><Fa :icon="faBookmark"/></span>
 | 
			
		||||
	<span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><Fa :icon="farBookmark"/></span>
 | 
			
		||||
	<div class="info">
 | 
			
		||||
		<span class="mobile" v-if="note.viaMobile"><Fa :icon="faMobileAlt"/></span>
 | 
			
		||||
		<router-link class="created-at" :to="notePage(note)">
 | 
			
		||||
		<MkA class="created-at" :to="notePage(note)">
 | 
			
		||||
			<MkTime :time="note.createdAt"/>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<span class="visibility" v-if="note.visibility !== 'public'">
 | 
			
		||||
			<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
 | 
			
		||||
			<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
 | 
			
		||||
 
 | 
			
		||||
@@ -18,9 +18,9 @@
 | 
			
		||||
		<Fa :icon="faRetweet"/>
 | 
			
		||||
		<i18n-t keypath="renotedBy" tag="span">
 | 
			
		||||
			<template #user>
 | 
			
		||||
				<router-link class="name" :to="userPage(note.user)" v-user-preview="note.userId">
 | 
			
		||||
				<MkA class="name" :to="userPage(note.user)" v-user-preview="note.userId">
 | 
			
		||||
					<MkUserName :user="note.user"/>
 | 
			
		||||
				</router-link>
 | 
			
		||||
				</MkA>
 | 
			
		||||
			</template>
 | 
			
		||||
		</i18n-t>
 | 
			
		||||
		<div class="info">
 | 
			
		||||
@@ -48,7 +48,7 @@
 | 
			
		||||
				<div class="content" v-show="appearNote.cw == null || showContent">
 | 
			
		||||
					<div class="text">
 | 
			
		||||
						<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
 | 
			
		||||
						<router-link class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></router-link>
 | 
			
		||||
						<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
 | 
			
		||||
						<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$store.state.i" :custom-emojis="appearNote.emojis"/>
 | 
			
		||||
						<a class="rp" v-if="appearNote.renote != null">RN:</a>
 | 
			
		||||
					</div>
 | 
			
		||||
@@ -59,7 +59,7 @@
 | 
			
		||||
					<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="detail" class="url-preview"/>
 | 
			
		||||
					<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
 | 
			
		||||
				</div>
 | 
			
		||||
				<router-link v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</router-link>
 | 
			
		||||
				<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</MkA>
 | 
			
		||||
			</div>
 | 
			
		||||
			<footer class="footer">
 | 
			
		||||
				<XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
 | 
			
		||||
@@ -91,9 +91,9 @@
 | 
			
		||||
<div v-else class="_panel muted" @click="muted = false">
 | 
			
		||||
	<i18n-t keypath="userSaysSomething" tag="small">
 | 
			
		||||
		<template #name>
 | 
			
		||||
			<router-link class="name" :to="userPage(appearNote.user)" v-user-preview="appearNote.userId">
 | 
			
		||||
			<MkA class="name" :to="userPage(appearNote.user)" v-user-preview="appearNote.userId">
 | 
			
		||||
				<MkUserName :user="appearNote.user"/>
 | 
			
		||||
			</router-link>
 | 
			
		||||
			</MkA>
 | 
			
		||||
		</template>
 | 
			
		||||
	</i18n-t>
 | 
			
		||||
</div>
 | 
			
		||||
@@ -101,7 +101,7 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
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 { parse } from '../../mfm/parse';
 | 
			
		||||
import { sum, unique } from '../../prelude/array';
 | 
			
		||||
@@ -144,7 +144,7 @@ export default defineComponent({
 | 
			
		||||
	inject: {
 | 
			
		||||
		inChannel: {
 | 
			
		||||
			default: null
 | 
			
		||||
		}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
@@ -581,11 +581,6 @@ export default defineComponent({
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
				menu = [{
 | 
			
		||||
					type: 'link',
 | 
			
		||||
					icon: faInfoCircle,
 | 
			
		||||
					text: this.$t('details'),
 | 
			
		||||
					to: '/notes/' + this.appearNote.id
 | 
			
		||||
				}, null, {
 | 
			
		||||
					icon: faCopy,
 | 
			
		||||
					text: this.$t('copyContent'),
 | 
			
		||||
					action: this.copyContent
 | 
			
		||||
@@ -637,6 +632,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 ? [
 | 
			
		||||
					null,
 | 
			
		||||
					this.appearNote.userId == this.$store.state.i.id ? {
 | 
			
		||||
 
 | 
			
		||||
@@ -18,34 +18,34 @@
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="tail">
 | 
			
		||||
		<header>
 | 
			
		||||
			<router-link v-if="notification.user" class="name" :to="userPage(notification.user)" v-user-preview="notification.user.id"><MkUserName :user="notification.user"/></router-link>
 | 
			
		||||
			<MkA v-if="notification.user" class="name" :to="userPage(notification.user)" v-user-preview="notification.user.id"><MkUserName :user="notification.user"/></MkA>
 | 
			
		||||
			<span v-else>{{ notification.header }}</span>
 | 
			
		||||
			<MkTime :time="notification.createdAt" v-if="withTime"/>
 | 
			
		||||
		</header>
 | 
			
		||||
		<router-link v-if="notification.type === 'reaction'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
		<MkA v-if="notification.type === 'reaction'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
			<Fa :icon="faQuoteLeft"/>
 | 
			
		||||
			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
 | 
			
		||||
			<Fa :icon="faQuoteRight"/>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		<router-link v-if="notification.type === 'renote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<MkA v-if="notification.type === 'renote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
 | 
			
		||||
			<Fa :icon="faQuoteLeft"/>
 | 
			
		||||
			<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.renote.emojis"/>
 | 
			
		||||
			<Fa :icon="faQuoteRight"/>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		<router-link v-if="notification.type === 'reply'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<MkA v-if="notification.type === 'reply'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		<router-link v-if="notification.type === 'mention'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<MkA v-if="notification.type === 'mention'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		<router-link v-if="notification.type === 'quote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<MkA v-if="notification.type === 'quote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		<router-link v-if="notification.type === 'pollVote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<MkA v-if="notification.type === 'pollVote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 | 
			
		||||
			<Fa :icon="faQuoteLeft"/>
 | 
			
		||||
			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
 | 
			
		||||
			<Fa :icon="faQuoteRight"/>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ $t('youGotNewFollower') }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
 | 
			
		||||
		<span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ $t('followRequestAccepted') }}</span>
 | 
			
		||||
		<span v-if="notification.type === 'receiveFollowRequest'" class="text" style="opacity: 0.6;">{{ $t('receiveFollowRequest') }}<div v-if="full && !followRequestDone"><button class="_textButton" @click="acceptFollowRequest()">{{ $t('accept') }}</button> | <button class="_textButton" @click="rejectFollowRequest()">{{ $t('reject') }}</button></div></span>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<router-link :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1">
 | 
			
		||||
<MkA :to="`/@${page.user.username}/pages/${page.name}`" class="vhpxefrj" tabindex="-1">
 | 
			
		||||
	<div class="thumbnail" v-if="page.eyeCatchingImage" :style="`background-image: url('${page.eyeCatchingImage.thumbnailUrl}')`"></div>
 | 
			
		||||
	<article>
 | 
			
		||||
		<header>
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
			<p>{{ userName(page.user) }}</p>
 | 
			
		||||
		</footer>
 | 
			
		||||
	</article>
 | 
			
		||||
</router-link>
 | 
			
		||||
</MkA>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,24 +1,33 @@
 | 
			
		||||
<template>
 | 
			
		||||
<XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="$emit('closed')">
 | 
			
		||||
<XWindow ref="window"
 | 
			
		||||
	:initial-width="400"
 | 
			
		||||
	:initial-height="500"
 | 
			
		||||
	:can-resize="true"
 | 
			
		||||
	:close-right="true"
 | 
			
		||||
	:contextmenu="contextmenu"
 | 
			
		||||
	@closed="$emit('closed')"
 | 
			
		||||
>
 | 
			
		||||
	<template #header>
 | 
			
		||||
		<XHeader :info="pageInfo" :with-back="false"/>
 | 
			
		||||
	</template>
 | 
			
		||||
	<template #buttons>
 | 
			
		||||
		<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="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button>
 | 
			
		||||
		<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
 | 
			
		||||
	</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"/>
 | 
			
		||||
	</div>
 | 
			
		||||
</XWindow>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, markRaw } from 'vue';
 | 
			
		||||
import { faExternalLinkAlt, faExpandAlt } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import { faExternalLinkAlt, faExpandAlt, faLink, faChevronLeft } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import XWindow from '@/components/ui/window.vue';
 | 
			
		||||
import XHeader from '@/ui/_common_/header.vue';
 | 
			
		||||
import { popout } from '@/scripts/popout';
 | 
			
		||||
import copyToClipboard from '@/scripts/copy-to-clipboard';
 | 
			
		||||
import { resolve } from '@/router';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	components: {
 | 
			
		||||
@@ -26,6 +35,14 @@ export default defineComponent({
 | 
			
		||||
		XHeader,
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	provide() {
 | 
			
		||||
		return {
 | 
			
		||||
			navHook: (url) => {
 | 
			
		||||
				this.navigate(url);
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		initialUrl: {
 | 
			
		||||
			type: String,
 | 
			
		||||
@@ -38,7 +55,7 @@ export default defineComponent({
 | 
			
		||||
		initialProps: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: {},
 | 
			
		||||
			default: () => {},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
@@ -50,18 +67,39 @@ export default defineComponent({
 | 
			
		||||
			url: this.initialUrl,
 | 
			
		||||
			component: this.initialComponent,
 | 
			
		||||
			props: this.initialProps,
 | 
			
		||||
			faExternalLinkAlt, faExpandAlt,
 | 
			
		||||
			history: [],
 | 
			
		||||
			faChevronLeft,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	provide() {
 | 
			
		||||
		return {
 | 
			
		||||
			navHook: (url, component, props) => {
 | 
			
		||||
				this.url = url;
 | 
			
		||||
				this.component = markRaw(component);
 | 
			
		||||
				this.props = props;
 | 
			
		||||
			}
 | 
			
		||||
		};
 | 
			
		||||
	computed: {
 | 
			
		||||
		contextmenu() {
 | 
			
		||||
			return [{
 | 
			
		||||
				type: 'label',
 | 
			
		||||
				text: this.url,
 | 
			
		||||
			}, {
 | 
			
		||||
				icon: faExpandAlt,
 | 
			
		||||
				text: this.$t('showInPage'),
 | 
			
		||||
				action: this.expand
 | 
			
		||||
			}, {
 | 
			
		||||
				icon: faExternalLinkAlt,
 | 
			
		||||
				text: this.$t('popout'),
 | 
			
		||||
				action: this.popout
 | 
			
		||||
			}, null, {
 | 
			
		||||
				icon: faExternalLinkAlt,
 | 
			
		||||
				text: this.$t('openInNewTab'),
 | 
			
		||||
				action: () => {
 | 
			
		||||
					window.open(this.url, '_blank');
 | 
			
		||||
					this.$refs.window.close();
 | 
			
		||||
				}
 | 
			
		||||
			}, {
 | 
			
		||||
				icon: faLink,
 | 
			
		||||
				text: this.$t('copyLink'),
 | 
			
		||||
				action: () => {
 | 
			
		||||
					copyToClipboard(this.url);
 | 
			
		||||
				}
 | 
			
		||||
			}];
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
@@ -72,6 +110,18 @@ export default defineComponent({
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		navigate(url, record = true) {
 | 
			
		||||
			if (record) this.history.push(this.url);
 | 
			
		||||
			this.url = url;
 | 
			
		||||
			const { component, props } = resolve(url);
 | 
			
		||||
			this.component = component;
 | 
			
		||||
			this.props = props;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		back() {
 | 
			
		||||
			this.navigate(this.history.pop(), false);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		expand() {
 | 
			
		||||
			this.$router.push(this.url);
 | 
			
		||||
			this.$refs.window.close();
 | 
			
		||||
@@ -84,3 +134,9 @@ export default defineComponent({
 | 
			
		||||
	},
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.yrolvcoq {
 | 
			
		||||
	--section-padding: 16px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 
 | 
			
		||||
@@ -5,9 +5,12 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import { defineComponent, defineAsyncComponent } from 'vue';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	components: {
 | 
			
		||||
		XBlock: defineAsyncComponent(() => import('./page.block.vue'))
 | 
			
		||||
	},
 | 
			
		||||
	props: {
 | 
			
		||||
		value: {
 | 
			
		||||
			required: true
 | 
			
		||||
@@ -22,8 +25,5 @@ export default defineComponent({
 | 
			
		||||
			required: true
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	beforeCreate() {
 | 
			
		||||
		this.$options.components.XBlock = require('./page.block.vue').default;
 | 
			
		||||
	},
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 
 | 
			
		||||
@@ -9,10 +9,13 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import { defineComponent, defineAsyncComponent } from 'vue';
 | 
			
		||||
import * as os from '@/os';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	components: {
 | 
			
		||||
		XBlock: defineAsyncComponent(() => import('./page.block.vue'))
 | 
			
		||||
	},
 | 
			
		||||
	props: {
 | 
			
		||||
		value: {
 | 
			
		||||
			required: true
 | 
			
		||||
@@ -27,9 +30,6 @@ export default defineComponent({
 | 
			
		||||
			required: true
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	beforeCreate() {
 | 
			
		||||
		this.$options.components.XBlock = require('./page.block.vue').default;
 | 
			
		||||
	},
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
<template>
 | 
			
		||||
<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>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -125,7 +125,7 @@ export default defineComponent({
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	emits: ['posted', 'done', 'esc'],
 | 
			
		||||
	emits: ['posted', 'cancel', 'esc'],
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
@@ -135,8 +135,8 @@ export default defineComponent({
 | 
			
		||||
			poll: null,
 | 
			
		||||
			useCw: false,
 | 
			
		||||
			cw: null,
 | 
			
		||||
			localOnly: false,
 | 
			
		||||
			visibility: 'public',
 | 
			
		||||
			localOnly: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.localOnly : this.$store.state.settings.defaultNoteLocalOnly,
 | 
			
		||||
			visibility: this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.visibility : this.$store.state.settings.defaultNoteVisibility,
 | 
			
		||||
			visibleUsers: [],
 | 
			
		||||
			autocomplete: null,
 | 
			
		||||
			draghover: false,
 | 
			
		||||
@@ -202,12 +202,6 @@ export default defineComponent({
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: {
 | 
			
		||||
		localOnly() {
 | 
			
		||||
			this.$store.commit('deviceUser/setLocalOnly', this.localOnly);
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	mounted() {
 | 
			
		||||
		if (this.initialText) {
 | 
			
		||||
			this.text = this.initialText;
 | 
			
		||||
@@ -239,11 +233,9 @@ export default defineComponent({
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// デフォルト公開範囲
 | 
			
		||||
		if (this.channel == null) {
 | 
			
		||||
			this.applyVisibility(this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.visibility : this.$store.state.settings.defaultNoteVisibility);
 | 
			
		||||
 | 
			
		||||
			this.localOnly = this.$store.state.settings.rememberNoteVisibility ? this.$store.state.deviceUser.localOnly : this.$store.state.settings.defaultNoteLocalOnly;
 | 
			
		||||
		if (this.channel) {
 | 
			
		||||
			this.visibility = 'public';
 | 
			
		||||
			this.localOnly = true; // TODO: チャンネルが連合するようになった折には消す
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// 公開以外へのリプライ時は元の公開範囲を引き継ぐ
 | 
			
		||||
@@ -295,7 +287,7 @@ export default defineComponent({
 | 
			
		||||
					this.text = draft.data.text;
 | 
			
		||||
					this.useCw = draft.data.useCw;
 | 
			
		||||
					this.cw = draft.data.cw;
 | 
			
		||||
					this.applyVisibility(draft.data.visibility);
 | 
			
		||||
					this.visibility = draft.data.visibility;
 | 
			
		||||
					this.localOnly = draft.data.localOnly;
 | 
			
		||||
					this.files = (draft.data.files || []).filter(e => e);
 | 
			
		||||
					if (draft.data.poll) {
 | 
			
		||||
@@ -398,18 +390,20 @@ export default defineComponent({
 | 
			
		||||
				src: this.$refs.visibilityButton
 | 
			
		||||
			}, {
 | 
			
		||||
				changeVisibility: visibility => {
 | 
			
		||||
					this.applyVisibility(visibility);
 | 
			
		||||
					this.visibility = visibility;
 | 
			
		||||
					if (this.$store.state.settings.rememberNoteVisibility) {
 | 
			
		||||
						this.$store.commit('deviceUser/setVisibility', visibility);
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
				changeLocalOnly: localOnly => {
 | 
			
		||||
					this.localOnly = localOnly;
 | 
			
		||||
					if (this.$store.state.settings.rememberNoteVisibility) {
 | 
			
		||||
						this.$store.commit('deviceUser/setLocalOnly', localOnly);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}, 'closed');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		applyVisibility(v: string) {
 | 
			
		||||
			this.visibility = (noteVisibilities as unknown as string[]).includes(v) ? v : 'public'; // v11互換性のため
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		addVisibleUser() {
 | 
			
		||||
			os.selectUser().then(user => {
 | 
			
		||||
				this.visibleUsers.push(user);
 | 
			
		||||
@@ -556,23 +550,23 @@ export default defineComponent({
 | 
			
		||||
			this.posting = true;
 | 
			
		||||
			os.api('notes/create', data).then(() => {
 | 
			
		||||
				this.clear();
 | 
			
		||||
				this.deleteDraft();
 | 
			
		||||
				this.$emit('posted');
 | 
			
		||||
				this.$nextTick(() => {
 | 
			
		||||
					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 => {
 | 
			
		||||
			}).then(() => {
 | 
			
		||||
				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() {
 | 
			
		||||
			this.$emit('done');
 | 
			
		||||
			this.$emit('cancel');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		insertMention() {
 | 
			
		||||
 
 | 
			
		||||
@@ -17,12 +17,12 @@
 | 
			
		||||
				<button class="item _button index active" @click="top()" v-if="$route.name === 'index'">
 | 
			
		||||
					<Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
 | 
			
		||||
				</button>
 | 
			
		||||
				<router-link class="item index" active-class="active" to="/" exact v-else>
 | 
			
		||||
				<MkA class="item index" active-class="active" to="/" exact v-else>
 | 
			
		||||
					<Fa :icon="faHome" fixed-width/><span class="text">{{ $store.getters.isSignedIn ? $t('timeline') : $t('home') }}</span>
 | 
			
		||||
				</router-link>
 | 
			
		||||
				</MkA>
 | 
			
		||||
				<template v-for="item in menu">
 | 
			
		||||
					<div v-if="item === '-'" class="divider"></div>
 | 
			
		||||
					<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'router-link' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to">
 | 
			
		||||
					<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'MkA' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to">
 | 
			
		||||
						<Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $t(menuDef[item].title) }}</span>
 | 
			
		||||
						<i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i>
 | 
			
		||||
					</component>
 | 
			
		||||
@@ -35,9 +35,9 @@
 | 
			
		||||
					<Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $t('more') }}</span>
 | 
			
		||||
					<i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i>
 | 
			
		||||
				</button>
 | 
			
		||||
				<router-link class="item" active-class="active" to="/settings">
 | 
			
		||||
				<MkA class="item" active-class="active" to="/settings">
 | 
			
		||||
					<Fa :icon="faCog" fixed-width/><span class="text">{{ $t('settings') }}</span>
 | 
			
		||||
				</router-link>
 | 
			
		||||
				</MkA>
 | 
			
		||||
			</div>
 | 
			
		||||
		</nav>
 | 
			
		||||
	</transition>
 | 
			
		||||
@@ -46,7 +46,7 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
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 { host, instanceName } from '@/config';
 | 
			
		||||
import { search } from '@/scripts/search';
 | 
			
		||||
@@ -217,6 +217,11 @@ export default defineComponent({
 | 
			
		||||
				text: this.$t('announcements'),
 | 
			
		||||
				to: '/instance/announcements',
 | 
			
		||||
				icon: faBroadcastTower,
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'link',
 | 
			
		||||
				text: this.$t('abuseReports'),
 | 
			
		||||
				to: '/instance/abuses',
 | 
			
		||||
				icon: faExclamationCircle,
 | 
			
		||||
			}, {
 | 
			
		||||
				type: 'link',
 | 
			
		||||
				text: this.$t('logs'),
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@
 | 
			
		||||
	<div class="body">
 | 
			
		||||
		<span v-if="note.isHidden" style="opacity: 0.5">({{ $t('private') }})</span>
 | 
			
		||||
		<span v-if="note.deletedAt" style="opacity: 0.5">({{ $t('deleted') }})</span>
 | 
			
		||||
		<router-link class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></router-link>
 | 
			
		||||
		<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></MkA>
 | 
			
		||||
		<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$store.state.i" :custom-emojis="note.emojis"/>
 | 
			
		||||
		<router-link class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</router-link>
 | 
			
		||||
		<MkA class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
 | 
			
		||||
	</div>
 | 
			
		||||
	<details v-if="note.files.length > 0">
 | 
			
		||||
		<summary>({{ $t('withNFiles', { n: note.files.length }) }})</summary>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										104
									
								
								src/client/components/ui/a.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										104
									
								
								src/client/components/ui/a.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,104 @@
 | 
			
		||||
<template>
 | 
			
		||||
<a :href="to" :class="active ? activeClass : null" @click.prevent="nav" @contextmenu.prevent.stop="onContextmenu">
 | 
			
		||||
	<slot></slot>
 | 
			
		||||
</a>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import { faExpandAlt, faColumns, faExternalLinkAlt, faLink, faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import * as os from '@/os';
 | 
			
		||||
import copyToClipboard from '@/scripts/copy-to-clipboard';
 | 
			
		||||
import { router } from '@/router';
 | 
			
		||||
import { deckmode } from '@/config';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	inject: {
 | 
			
		||||
		navHook: {
 | 
			
		||||
			default: null
 | 
			
		||||
		},
 | 
			
		||||
		sideViewHook: {
 | 
			
		||||
			default: null
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		to: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true,
 | 
			
		||||
		},
 | 
			
		||||
		activeClass: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: false,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	computed: {
 | 
			
		||||
		active() {
 | 
			
		||||
			if (this.activeClass == null) return false;
 | 
			
		||||
			const resolved = router.resolve(this.to);
 | 
			
		||||
			if (resolved.path == this.$route.path) return true;
 | 
			
		||||
			if (resolved.name == null) return false;
 | 
			
		||||
			if (this.$route.name == null) return false;
 | 
			
		||||
			return resolved.name == this.$route.name;
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		onContextmenu(e) {
 | 
			
		||||
			if (window.getSelection().toString() !== '') return;
 | 
			
		||||
			os.contextMenu([{
 | 
			
		||||
				type: 'label',
 | 
			
		||||
				text: this.to,
 | 
			
		||||
			}, {
 | 
			
		||||
				icon: faWindowMaximize,
 | 
			
		||||
				text: this.$t('openInWindow'),
 | 
			
		||||
				action: () => {
 | 
			
		||||
					os.pageWindow(this.to);
 | 
			
		||||
				}
 | 
			
		||||
			}, !this.navHook && this.sideViewHook ? {
 | 
			
		||||
				icon: faColumns,
 | 
			
		||||
				text: this.$t('openInSideView'),
 | 
			
		||||
				action: () => {
 | 
			
		||||
					this.sideViewHook(this.to);
 | 
			
		||||
				}
 | 
			
		||||
			} : undefined, {
 | 
			
		||||
				icon: faExpandAlt,
 | 
			
		||||
				text: this.$t('showInPage'),
 | 
			
		||||
				action: () => {
 | 
			
		||||
					this.$router.push(this.to);
 | 
			
		||||
				}
 | 
			
		||||
			}, null, {
 | 
			
		||||
				icon: faExternalLinkAlt,
 | 
			
		||||
				text: this.$t('openInNewTab'),
 | 
			
		||||
				action: () => {
 | 
			
		||||
					window.open(this.to, '_blank');
 | 
			
		||||
				}
 | 
			
		||||
			}, {
 | 
			
		||||
				icon: faLink,
 | 
			
		||||
				text: this.$t('copyLink'),
 | 
			
		||||
				action: () => {
 | 
			
		||||
					copyToClipboard(this.to);
 | 
			
		||||
				}
 | 
			
		||||
			}], e);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		nav() {
 | 
			
		||||
			if (this.navHook) {
 | 
			
		||||
				this.navHook(this.to);
 | 
			
		||||
			} else {
 | 
			
		||||
				if (this.$store.state.device.defaultSideView && this.sideViewHook && this.to !== '/') {
 | 
			
		||||
					this.sideViewHook(this.to);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
				if (this.$store.state.device.deckNavWindow && deckmode && this.to !== '/') {
 | 
			
		||||
					os.pageWindow(this.to);
 | 
			
		||||
					return;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				this.$router.push(this.to);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="nvlagfpb">
 | 
			
		||||
<div class="nvlagfpb" @contextmenu.prevent.stop="() => {}">
 | 
			
		||||
	<MkMenu :items="items" @close="$emit('closed')" class="_popup _shadow" :align="'left'"/>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -12,12 +12,12 @@
 | 
			
		||||
		<span v-else-if="item.type === 'pending'" :tabindex="i" class="pending item">
 | 
			
		||||
			<span><MkEllipsis/></span>
 | 
			
		||||
		</span>
 | 
			
		||||
		<router-link v-else-if="item.type === 'link'" :to="item.to" @click.passive="close()" :tabindex="i" class="_button item">
 | 
			
		||||
		<MkA v-else-if="item.type === 'link'" :to="item.to" @click.passive="close()" :tabindex="i" class="_button item">
 | 
			
		||||
			<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
 | 
			
		||||
			<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
 | 
			
		||||
			<span>{{ item.text }}</span>
 | 
			
		||||
			<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		</MkA>
 | 
			
		||||
		<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item">
 | 
			
		||||
			<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
 | 
			
		||||
			<span>{{ item.text }}</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -51,7 +51,7 @@ export default defineComponent({
 | 
			
		||||
.novjtctn {
 | 
			
		||||
	position: relative;
 | 
			
		||||
	display: inline-block;
 | 
			
		||||
	margin: 0 32px 0 0;
 | 
			
		||||
	margin: 16px 32px 0 0;
 | 
			
		||||
	cursor: pointer;
 | 
			
		||||
	transition: all 0.3s;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,13 @@
 | 
			
		||||
<div class="adhpbeos" :class="{ focused, filled, tall, pre }">
 | 
			
		||||
	<div class="input">
 | 
			
		||||
		<span class="label" ref="label"><slot></slot></span>
 | 
			
		||||
		<textarea ref="input"
 | 
			
		||||
		<textarea ref="input" :class="{ code }"
 | 
			
		||||
			:value="value"
 | 
			
		||||
			:required="required"
 | 
			
		||||
			:readonly="readonly"
 | 
			
		||||
			:pattern="pattern"
 | 
			
		||||
			:autocomplete="autocomplete"
 | 
			
		||||
			:spellcheck="!code"
 | 
			
		||||
			@input="onInput"
 | 
			
		||||
			@focus="focused = true"
 | 
			
		||||
			@blur="focused = false"
 | 
			
		||||
@@ -20,7 +21,6 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import * as os from '@/os';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	props: {
 | 
			
		||||
@@ -43,6 +43,10 @@ export default defineComponent({
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: false
 | 
			
		||||
		},
 | 
			
		||||
		code: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			required: false
 | 
			
		||||
		},
 | 
			
		||||
		tall: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			required: false,
 | 
			
		||||
@@ -159,6 +163,11 @@ export default defineComponent({
 | 
			
		||||
			outline: none;
 | 
			
		||||
			box-shadow: none;
 | 
			
		||||
			color: var(--fg);
 | 
			
		||||
 | 
			
		||||
			&.code {
 | 
			
		||||
				tab-size: 2;
 | 
			
		||||
				font-family: Fira code, Fira Mono, Consolas, Menlo, Courier, monospace;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,12 +2,16 @@
 | 
			
		||||
<transition :name="$store.state.device.animation ? 'window' : ''" appear @after-leave="$emit('closed')">
 | 
			
		||||
	<div class="ebkgocck" v-if="showing">
 | 
			
		||||
		<div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
 | 
			
		||||
			<div class="header">
 | 
			
		||||
				<button class="_button" @click="close()"><Fa :icon="faTimes"/></button>
 | 
			
		||||
			<div class="header" @contextmenu.prevent.stop="onContextmenu">
 | 
			
		||||
				<slot v-if="closeRight" name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
 | 
			
		||||
				<button v-else class="_button" @click="close()"><Fa :icon="faTimes"/></button>
 | 
			
		||||
 | 
			
		||||
				<span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
 | 
			
		||||
					<slot name="header"></slot>
 | 
			
		||||
				</span>
 | 
			
		||||
				<slot name="buttons"></slot>
 | 
			
		||||
 | 
			
		||||
				<button v-if="closeRight" class="_button" @click="close()"><Fa :icon="faTimes"/></button>
 | 
			
		||||
				<slot v-else name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="body" v-if="padding">
 | 
			
		||||
				<div class="_section">
 | 
			
		||||
@@ -83,6 +87,15 @@ export default defineComponent({
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: false,
 | 
			
		||||
		},
 | 
			
		||||
		closeRight: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: false,
 | 
			
		||||
		},
 | 
			
		||||
		contextmenu: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			required: false,
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	emits: ['closed'],
 | 
			
		||||
@@ -127,6 +140,12 @@ export default defineComponent({
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		onContextmenu(e) {
 | 
			
		||||
			if (this.contextmenu) {
 | 
			
		||||
				os.contextMenu(this.contextmenu, e);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 最前面へ移動
 | 
			
		||||
		top() {
 | 
			
		||||
			let z = 0;
 | 
			
		||||
@@ -313,11 +332,13 @@ export default defineComponent({
 | 
			
		||||
 | 
			
		||||
		// 高さを適用
 | 
			
		||||
		applyTransformHeight(height) {
 | 
			
		||||
			if (height > window.innerHeight) height = window.innerHeight;
 | 
			
		||||
			(this.$el as any).style.height = height + 'px';
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 幅を適用
 | 
			
		||||
		applyTransformWidth(width) {
 | 
			
		||||
			if (width > window.innerWidth) width = window.innerWidth;
 | 
			
		||||
			(this.$el as any).style.width = width + 'px';
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
@@ -371,8 +392,6 @@ export default defineComponent({
 | 
			
		||||
		width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
 | 
			
		||||
		--section-padding: 16px;
 | 
			
		||||
 | 
			
		||||
		> .header {
 | 
			
		||||
			$height: 50px;
 | 
			
		||||
			display: flex;
 | 
			
		||||
@@ -380,7 +399,6 @@ export default defineComponent({
 | 
			
		||||
			z-index: 1;
 | 
			
		||||
			flex-shrink: 0;
 | 
			
		||||
			box-shadow: 0px 1px var(--divider);
 | 
			
		||||
			cursor: move;
 | 
			
		||||
			user-select: none;
 | 
			
		||||
			height: $height;
 | 
			
		||||
 | 
			
		||||
@@ -400,6 +418,8 @@ export default defineComponent({
 | 
			
		||||
				white-space: nowrap;
 | 
			
		||||
				overflow: hidden;
 | 
			
		||||
				text-overflow: ellipsis;
 | 
			
		||||
				text-align: center;
 | 
			
		||||
				cursor: move;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@
 | 
			
		||||
</div>
 | 
			
		||||
<div v-else class="mk-url-preview" v-size="{ max: [400, 350] }">
 | 
			
		||||
	<transition name="zoom" mode="out-in">
 | 
			
		||||
		<component :is="self ? 'router-link' : 'a'" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url" v-if="!fetching">
 | 
			
		||||
		<component :is="self ? 'MkA' : 'a'" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url" v-if="!fetching">
 | 
			
		||||
			<div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`">
 | 
			
		||||
				<button class="_button" v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$t('enablePlayer')"><Fa :icon="faPlayCircle"/></button>
 | 
			
		||||
			</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,5 @@
 | 
			
		||||
<template>
 | 
			
		||||
<component :is="self ? 'router-link' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
 | 
			
		||||
<component :is="self ? 'MkA' : 'a'" class="ieqqeuvs _link" :[attr]="self ? url.substr(local.length) : url" :rel="rel" :target="target"
 | 
			
		||||
	@mouseover="onMouseover"
 | 
			
		||||
	@mouseleave="onMouseleave"
 | 
			
		||||
>
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
	<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
 | 
			
		||||
	<MkAvatar class="avatar" :user="user" :disable-preview="true"/>
 | 
			
		||||
	<div class="title">
 | 
			
		||||
		<router-link class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></router-link>
 | 
			
		||||
		<MkA class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
 | 
			
		||||
		<p class="username"><MkAcct :user="user"/></p>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="description">
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
			<div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div>
 | 
			
		||||
			<MkAvatar class="avatar" :user="user" :disable-preview="true"/>
 | 
			
		||||
			<div class="title">
 | 
			
		||||
				<router-link class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></router-link>
 | 
			
		||||
				<MkA class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></MkA>
 | 
			
		||||
				<p class="username"><MkAcct :user="user"/></p>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="description">
 | 
			
		||||
 
 | 
			
		||||
@@ -6,13 +6,13 @@
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<div class="users">
 | 
			
		||||
		<router-link v-for="item in items" class="user" :key="item.id" :to="userPage(extract ? extract(item) : item)">
 | 
			
		||||
		<MkA v-for="item in items" class="user" :key="item.id" :to="userPage(extract ? extract(item) : item)">
 | 
			
		||||
			<MkAvatar :user="extract ? extract(item) : item" class="avatar" :disable-link="true"/>
 | 
			
		||||
			<div class="body">
 | 
			
		||||
				<MkUserName :user="extract ? extract(item) : item" class="name"/>
 | 
			
		||||
				<MkAcct :user="extract ? extract(item) : item" class="acct"/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</router-link>
 | 
			
		||||
		</MkA>
 | 
			
		||||
	</div>
 | 
			
		||||
	<button class="more _button" v-appear="$store.state.device.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching">
 | 
			
		||||
		<template v-if="!moreFetching">{{ $t('loadMore') }}</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -55,11 +55,11 @@ export default defineComponent({
 | 
			
		||||
	props: {
 | 
			
		||||
		currentVisibility: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: false
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		currentLocalOnly: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			required: false
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		src: {
 | 
			
		||||
			required: false
 | 
			
		||||
@@ -68,7 +68,7 @@ export default defineComponent({
 | 
			
		||||
	emits: ['change-visibility', 'change-local-only', 'closed'],
 | 
			
		||||
	data() {
 | 
			
		||||
		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,
 | 
			
		||||
			faGlobe, faUnlock, faEnvelope, faHome, faBiohazard, faToggleOn, faToggleOff
 | 
			
		||||
		}
 | 
			
		||||
@@ -81,9 +81,6 @@ export default defineComponent({
 | 
			
		||||
	methods: {
 | 
			
		||||
		choose(visibility) {
 | 
			
		||||
			this.v = visibility;
 | 
			
		||||
			if (this.$store.state.settings.rememberNoteVisibility) {
 | 
			
		||||
				this.$store.commit('deviceUser/setVisibility', visibility);
 | 
			
		||||
			}
 | 
			
		||||
			this.$emit('change-visibility', visibility);
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				this.$refs.modal.close();
 | 
			
		||||
 
 | 
			
		||||
@@ -4,14 +4,13 @@
 | 
			
		||||
 | 
			
		||||
import '@/style.scss';
 | 
			
		||||
 | 
			
		||||
import { createApp } from 'vue';
 | 
			
		||||
import { createApp, defineAsyncComponent } from 'vue';
 | 
			
		||||
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
 | 
			
		||||
 | 
			
		||||
import Root from './root.vue';
 | 
			
		||||
import widgets from './widgets';
 | 
			
		||||
import directives from './directives';
 | 
			
		||||
import components from '@/components';
 | 
			
		||||
import { version, apiUrl } from '@/config';
 | 
			
		||||
import { version, apiUrl, deckmode } from '@/config';
 | 
			
		||||
import { store } from './store';
 | 
			
		||||
import { router } from './router';
 | 
			
		||||
import { applyTheme } from '@/scripts/theme';
 | 
			
		||||
@@ -51,7 +50,7 @@ if (_DEV_) {
 | 
			
		||||
document.addEventListener('touchend', () => {}, { passive: true });
 | 
			
		||||
 | 
			
		||||
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/
 | 
			
		||||
@@ -152,7 +151,12 @@ store.dispatch('instance/fetch').then(() => {
 | 
			
		||||
 | 
			
		||||
stream.init(store.state.i);
 | 
			
		||||
 | 
			
		||||
const app = createApp(Root);
 | 
			
		||||
const app = createApp(await (
 | 
			
		||||
	window.location.search === '?zen' ? import('@/ui/zen.vue') :
 | 
			
		||||
	!store.getters.isSignedIn         ? import('@/ui/visitor.vue') :
 | 
			
		||||
	deckmode                          ? import('@/ui/deck.vue') :
 | 
			
		||||
	import('@/ui/default.vue')
 | 
			
		||||
).then(x => x.default));
 | 
			
		||||
 | 
			
		||||
if (_DEV_) {
 | 
			
		||||
	app.config.performance = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -4,6 +4,8 @@ import Stream from '@/scripts/stream';
 | 
			
		||||
import { store } from '@/store';
 | 
			
		||||
import { apiUrl } from '@/config';
 | 
			
		||||
import MkPostFormDialog from '@/components/post-form-dialog.vue';
 | 
			
		||||
import MkWaitingDialog from '@/components/waiting-dialog.vue';
 | 
			
		||||
import { resolve } from '@/router';
 | 
			
		||||
 | 
			
		||||
const ua = navigator.userAgent.toLowerCase();
 | 
			
		||||
export const isMobile = /mobile|iphone|ipad|android/.test(ua);
 | 
			
		||||
@@ -73,7 +75,7 @@ export function apiWithDialog(
 | 
			
		||||
	promiseDialog(promise, onSuccess, onFailure ? onFailure : (e) => {
 | 
			
		||||
		dialog({
 | 
			
		||||
			type: 'error',
 | 
			
		||||
			text: e.message + '\n' + (e as any).id,
 | 
			
		||||
			text: e.message + '<br>' + (e as any).id,
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
@@ -111,7 +113,8 @@ export function promiseDialog<T extends Promise<any>>(
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	popup(defineAsyncComponent(() => import('@/components/waiting-dialog.vue')), {
 | 
			
		||||
	// NOTE: dynamic importすると挙動がおかしくなる(showingの変更が伝播しない)
 | 
			
		||||
	popup(MkWaitingDialog, {
 | 
			
		||||
		success: success,
 | 
			
		||||
		showing: showing,
 | 
			
		||||
		text: text,
 | 
			
		||||
@@ -160,7 +163,8 @@ export function popup(component: Component | typeof import('*.vue'), props: Reco
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function pageWindow(url: string, component: Component | typeof import('*.vue'), props: Record<string, any>) {
 | 
			
		||||
export function pageWindow(url: string) {
 | 
			
		||||
	const { component, props } = resolve(url);
 | 
			
		||||
	popup(defineAsyncComponent(() => import('@/components/page-window.vue')), {
 | 
			
		||||
		initialUrl: url,
 | 
			
		||||
		initialComponent: markRaw(component),
 | 
			
		||||
@@ -301,6 +305,10 @@ export function contextMenu(items: any[], ev: MouseEvent) {
 | 
			
		||||
export function post(props: Record<string, any>) {
 | 
			
		||||
	return new Promise((resolve, reject) => {
 | 
			
		||||
		// NOTE: MkPostFormDialogをdynamic importするとiOSでテキストエリアに自動フォーカスできない
 | 
			
		||||
		// NOTE: ただ、dynamic importしない場合、MkPostFormDialogインスタンスが使いまわされ、
 | 
			
		||||
		//       Vueが渡されたコンポーネントに内部的に__propsというプロパティを生やす影響で、
 | 
			
		||||
		//       複数のpost formを開いたときに場合によってはエラーになる
 | 
			
		||||
		//       もちろん複数のpost formを開けること自体Misskeyサイドのバグなのだが
 | 
			
		||||
		const { dispose } = popup(MkPostFormDialog, props, {
 | 
			
		||||
			closed: () => {
 | 
			
		||||
				resolve();
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<ul>
 | 
			
		||||
				<li v-for="doc in docs" :key="doc.path">
 | 
			
		||||
					<router-link :to="`/docs/${doc.path}`">{{ doc.title }}</router-link>
 | 
			
		||||
					<MkA :to="`/docs/${doc.path}`">{{ doc.title }}</MkA>
 | 
			
		||||
				</li>
 | 
			
		||||
			</ul>
 | 
			
		||||
		</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -38,8 +38,8 @@
 | 
			
		||||
			<template #header><Fa :icon="faHashtag" fixed-width style="margin-right: 0.5em;"/>{{ $t('popularTags') }}</template>
 | 
			
		||||
 | 
			
		||||
			<div class="vxjfqztj">
 | 
			
		||||
				<router-link v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</router-link>
 | 
			
		||||
				<router-link v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</router-link>
 | 
			
		||||
				<MkA v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</MkA>
 | 
			
		||||
				<MkA v-for="tag in tagsRemote" :to="`/explore/tags/${tag.tag}`" :key="'remote:' + tag.tag">{{ tag.tag }}</MkA>
 | 
			
		||||
			</div>
 | 
			
		||||
		</MkFolder>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
				<MkAvatar class="avatar" :user="req.follower"/>
 | 
			
		||||
				<div class="body">
 | 
			
		||||
					<div class="name">
 | 
			
		||||
						<router-link class="name" :to="userPage(req.follower)" v-user-preview="req.follower.id"><MkUserName :user="req.follower"/></router-link>
 | 
			
		||||
						<MkA class="name" :to="userPage(req.follower)" v-user-preview="req.follower.id"><MkUserName :user="req.follower"/></MkA>
 | 
			
		||||
						<p class="acct">@{{ acct(req.follower) }}</p>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="description" v-if="req.follower.description" :title="req.follower.description">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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>
 | 
			
		||||
@@ -18,7 +18,7 @@
 | 
			
		||||
 | 
			
		||||
	<section class="_section info">
 | 
			
		||||
		<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 class="_content">
 | 
			
		||||
			<MkSwitch v-model:value="enableLocalTimeline" @update:value="save()">{{ $t('enableLocalTimeline') }}</MkSwitch>
 | 
			
		||||
@@ -91,8 +91,8 @@
 | 
			
		||||
			<MkInfo>{{ $t('emptyToDisableSmtpAuth') }}</MkInfo>
 | 
			
		||||
			<MkSwitch v-model:value="smtpSecure" :disabled="!enableEmail">{{ $t('smtpSecure') }}<template #desc>{{ $t('smtpSecureInfo') }}</template></MkSwitch>
 | 
			
		||||
			<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" primary inline @click="save(true)"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</section>
 | 
			
		||||
@@ -131,7 +131,7 @@
 | 
			
		||||
			<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>
 | 
			
		||||
			<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 class="_footer">
 | 
			
		||||
			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $t('save') }}</MkButton>
 | 
			
		||||
@@ -169,7 +169,7 @@
 | 
			
		||||
	<section class="_section">
 | 
			
		||||
		<div class="_title"><Fa :icon="faGhost"/> {{ $t('proxyAccount') }}</div>
 | 
			
		||||
		<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>
 | 
			
		||||
		</div>
 | 
			
		||||
	</section>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,13 +4,12 @@
 | 
			
		||||
		<MkButton @click="start" primary class="start"><Fa :icon="faPlus"/> {{ $t('startMessaging') }}</MkButton>
 | 
			
		||||
 | 
			
		||||
		<div class="history" v-if="messages.length > 0">
 | 
			
		||||
			<router-link v-for="(message, i) in messages"
 | 
			
		||||
			<MkA v-for="(message, i) in messages"
 | 
			
		||||
				class="message _panel"
 | 
			
		||||
				:class="{ isMe: isMe(message), isRead: message.groupId ? message.reads.includes($store.state.i.id) : message.isRead }"
 | 
			
		||||
				:to="message.groupId ? `/my/messaging/group/${message.groupId}` : `/my/messaging/${getAcct(isMe(message) ? message.recipient : message.user)}`"
 | 
			
		||||
				:data-index="i"
 | 
			
		||||
				:key="message.id"
 | 
			
		||||
				@click.prevent="go(message)"
 | 
			
		||||
			>
 | 
			
		||||
				<div>
 | 
			
		||||
					<MkAvatar class="avatar" :user="message.groupId ? message.user : isMe(message) ? message.recipient : message.user"/>
 | 
			
		||||
@@ -27,7 +26,7 @@
 | 
			
		||||
						<p class="text"><span class="me" v-if="isMe(message)">{{ $t('you') }}:</span>{{ message.text }}</p>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</router-link>
 | 
			
		||||
			</MkA>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="_fullinfo" v-if="!fetching && messages.length == 0">
 | 
			
		||||
			<img src="https://xn--931a.moe/assets/info.jpg" class="_ghost"/>
 | 
			
		||||
@@ -90,18 +89,6 @@ export default defineComponent({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		go(message) {
 | 
			
		||||
			const url = message.groupId ? `/my/messaging/group/${message.groupId}` : `/my/messaging/${getAcct(this.isMe(message) ? message.recipient : message.user)}`;
 | 
			
		||||
			if (this.navHook) {
 | 
			
		||||
				this.navHook(url, defineAsyncComponent(() => import('@/pages/messaging/messaging-room.vue')), {
 | 
			
		||||
					userAcct: message.groupId ? null : getAcct(this.isMe(message) ? message.recipient : message.user),
 | 
			
		||||
					groupId: message.groupId
 | 
			
		||||
				});
 | 
			
		||||
			} else {
 | 
			
		||||
				this.$router.push(url);
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getAcct,
 | 
			
		||||
 | 
			
		||||
		isMe(message) {
 | 
			
		||||
 
 | 
			
		||||
@@ -317,7 +317,7 @@ const Component = defineComponent({
 | 
			
		||||
				text: this.$t('openInWindow'),
 | 
			
		||||
				icon: faWindowMaximize,
 | 
			
		||||
				action: () => {
 | 
			
		||||
					os.pageWindow(url, Component, this.$props);
 | 
			
		||||
					os.pageWindow(url);
 | 
			
		||||
					this.$router.back();
 | 
			
		||||
				},
 | 
			
		||||
			}, this.inWindow ? undefined : {
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@
 | 
			
		||||
 | 
			
		||||
			<MkPagination :pagination="ownedPagination" #default="{items}" ref="owned">
 | 
			
		||||
				<div class="_card" v-for="group in items" :key="group.id">
 | 
			
		||||
					<div class="_title"><router-link :to="`/my/groups/${ group.id }`" class="_link">{{ group.name }}</router-link></div>
 | 
			
		||||
					<div class="_title"><MkA :to="`/my/groups/${ group.id }`" class="_link">{{ group.name }}</MkA></div>
 | 
			
		||||
					<div class="_content"><MkAvatars :user-ids="group.userIds"/></div>
 | 
			
		||||
				</div>
 | 
			
		||||
			</MkPagination>
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@
 | 
			
		||||
 | 
			
		||||
	<MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list">
 | 
			
		||||
		<div class="list _panel" v-for="(list, i) in items" :key="list.id">
 | 
			
		||||
			<router-link :to="`/my/lists/${ list.id }`">{{ list.name }}</router-link>
 | 
			
		||||
			<MkA :to="`/my/lists/${ list.id }`">{{ list.name }}</MkA>
 | 
			
		||||
		</div>
 | 
			
		||||
	</MkPagination>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,8 @@
 | 
			
		||||
 | 
			
		||||
		<div class="_section">
 | 
			
		||||
			<div class="_content">
 | 
			
		||||
				<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" style="margin-bottom: var(--margin)"/>
 | 
			
		||||
				<XNote v-model:note="note" :key="note.id" :detail="true"/>
 | 
			
		||||
				<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_vMargin"/>
 | 
			
		||||
				<XNote v-model:note="note" :key="note.id" :detail="true" class="_vMargin"/>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
@@ -42,6 +42,12 @@ export default defineComponent({
 | 
			
		||||
		MkRemoteCaution,
 | 
			
		||||
		MkButton,
 | 
			
		||||
	},
 | 
			
		||||
	props: {
 | 
			
		||||
		noteId: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			INFO: computed(() => this.note ? {
 | 
			
		||||
@@ -77,7 +83,7 @@ export default defineComponent({
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		$route: 'fetch'
 | 
			
		||||
		noteId: 'fetch'
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		this.fetch();
 | 
			
		||||
@@ -86,7 +92,7 @@ export default defineComponent({
 | 
			
		||||
		fetch() {
 | 
			
		||||
			Progress.start();
 | 
			
		||||
			os.api('notes/show', {
 | 
			
		||||
				noteId: this.$route.params.note
 | 
			
		||||
				noteId: this.noteId
 | 
			
		||||
			}).then(note => {
 | 
			
		||||
				Promise.all([
 | 
			
		||||
					os.api('users/notes', {
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import { defineComponent, defineAsyncComponent } from 'vue';
 | 
			
		||||
import { v4 as uuid } from 'uuid';
 | 
			
		||||
import { faPlus, faQuestion } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import XContainer from '../page-editor.container.vue';
 | 
			
		||||
@@ -34,7 +34,8 @@ import * as os from '@/os';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	components: {
 | 
			
		||||
		XContainer, MkSelect
 | 
			
		||||
		XContainer, MkSelect,
 | 
			
		||||
		XBlocks: defineAsyncComponent(() => import('../page-editor.blocks.vue')),
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	inject: ['getPageBlockList'],
 | 
			
		||||
@@ -54,10 +55,6 @@ export default defineComponent({
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	beforeCreate() {
 | 
			
		||||
		this.$options.components.XBlocks = require('../page-editor.blocks.vue').default
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	created() {
 | 
			
		||||
		if (this.value.children == null) this.value.children = [];
 | 
			
		||||
		if (this.value.var === undefined) this.value.var = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,7 @@
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import { defineComponent, defineAsyncComponent } from 'vue';
 | 
			
		||||
import { v4 as uuid } from 'uuid';
 | 
			
		||||
import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
@@ -26,7 +26,8 @@ import * as os from '@/os';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	components: {
 | 
			
		||||
		XContainer
 | 
			
		||||
		XContainer,
 | 
			
		||||
		XBlocks: defineAsyncComponent(() => import('../page-editor.blocks.vue')),
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	inject: ['getPageBlockList'],
 | 
			
		||||
@@ -46,10 +47,6 @@ export default defineComponent({
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	beforeCreate() {
 | 
			
		||||
		this.$options.components.XBlocks = require('../page-editor.blocks.vue').default
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	created() {
 | 
			
		||||
		if (this.value.title == null) this.value.title = null;
 | 
			
		||||
		if (this.value.children == null) this.value.children = [];
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,7 @@
 | 
			
		||||
			</header>
 | 
			
		||||
 | 
			
		||||
			<section>
 | 
			
		||||
				<router-link class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><Fa :icon="faExternalLinkSquareAlt"/> {{ $t('_pages.viewPage') }}</router-link>
 | 
			
		||||
				<MkA class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><Fa :icon="faExternalLinkSquareAlt"/> {{ $t('_pages.viewPage') }}</MkA>
 | 
			
		||||
 | 
			
		||||
				<MkInput v-model:value="title">
 | 
			
		||||
					<span>{{ $t('_pages.title') }}</span>
 | 
			
		||||
 
 | 
			
		||||
@@ -20,9 +20,9 @@
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="_section links">
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<router-link :to="`./${page.name}/view-source`" class="link">{{ $t('_pages.viewSource') }}</router-link>
 | 
			
		||||
			<MkA :to="`./${page.name}/view-source`" class="link">{{ $t('_pages.viewSource') }}</MkA>
 | 
			
		||||
			<template v-if="$store.getters.isSignedIn && $store.state.i.id === page.userId">
 | 
			
		||||
				<router-link :to="`/my/pages/edit/${page.id}`" class="link">{{ $t('_pages.editThisPage') }}</router-link>
 | 
			
		||||
				<MkA :to="`/my/pages/edit/${page.id}`" class="link">{{ $t('_pages.editThisPage') }}</MkA>
 | 
			
		||||
				<button v-if="$store.state.i.pinnedPageId === page.id" @click="pin(false)" class="link _textButton">{{ $t('unpin') }}</button>
 | 
			
		||||
				<button v-else @click="pin(true)" class="link _textButton">{{ $t('pin') }}</button>
 | 
			
		||||
			</template>
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,10 @@
 | 
			
		||||
<div class="_section">
 | 
			
		||||
	<section class="_card _vMargin">
 | 
			
		||||
		<div class="_title"><Fa :icon="faCog"/> {{ $t('general') }}</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<div>{{ $t('defaultNavigationBehaviour') }}</div>
 | 
			
		||||
			<MkSwitch v-model:value="defaultSideView">{{ $t('openInSideView') }}</MkSwitch>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<div>{{ $t('whenServerDisconnected') }}</div>
 | 
			
		||||
			<MkRadio v-model="serverDisconnectedBehavior" value="reload">{{ $t('_serverDisconnectedBehavior.reload') }}</MkRadio>
 | 
			
		||||
@@ -51,6 +55,10 @@
 | 
			
		||||
 | 
			
		||||
	<section class="_card _vMargin">
 | 
			
		||||
		<div class="_title"><Fa :icon="faColumns"/> {{ $t('deck') }}</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<div>{{ $t('defaultNavigationBehaviour') }}</div>
 | 
			
		||||
			<MkSwitch v-model:value="deckNavWindow">{{ $t('openInWindow') }}</MkSwitch>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<MkSwitch v-model:value="deckAlwaysShowMainColumn">
 | 
			
		||||
				{{ $t('_deck.alwaysShowMainColumn') }}
 | 
			
		||||
@@ -146,6 +154,16 @@ export default defineComponent({
 | 
			
		||||
			set(value) { this.$store.commit('device/set', { key: 'showFixedPostForm', value }); }
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		defaultSideView: {
 | 
			
		||||
			get() { return this.$store.state.device.defaultSideView; },
 | 
			
		||||
			set(value) { this.$store.commit('device/set', { key: 'defaultSideView', value }); }
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		deckNavWindow: {
 | 
			
		||||
			get() { return this.$store.state.device.deckNavWindow; },
 | 
			
		||||
			set(value) { this.$store.commit('device/set', { key: 'deckNavWindow', value }); }
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		chatOpenBehavior: {
 | 
			
		||||
			get() { return this.$store.state.device.chatOpenBehavior; },
 | 
			
		||||
			set(value) { this.$store.commit('device/set', { key: 'chatOpenBehavior', value }); }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,52 +1,57 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="vvcocwet" :class="{ wide: !narrow }" ref="el">
 | 
			
		||||
	<div class="nav" v-if="!narrow || $route.name === 'settings'">
 | 
			
		||||
	<div class="nav" v-if="!narrow || page == null">
 | 
			
		||||
		<div class="menu">
 | 
			
		||||
			<div class="label">{{ $t('basicSettings') }}</div>
 | 
			
		||||
			<router-link class="item" replace to="/settings/profile"><Fa :icon="faUser" fixed-width class="icon"/>{{ $t('profile') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/privacy"><Fa :icon="faLockOpen" fixed-width class="icon"/>{{ $t('privacy') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/reaction"><Fa :icon="faLaugh" fixed-width class="icon"/>{{ $t('reaction') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/notifications"><Fa :icon="faBell" fixed-width class="icon"/>{{ $t('notifications') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/integration"><Fa :icon="faShareAlt" fixed-width class="icon"/>{{ $t('integration') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/security"><Fa :icon="faLock" fixed-width class="icon"/>{{ $t('security') }}</router-link>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'profile' }" replace to="/settings/profile"><Fa :icon="faUser" fixed-width class="icon"/>{{ $t('profile') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'privacy' }" replace to="/settings/privacy"><Fa :icon="faLockOpen" fixed-width class="icon"/>{{ $t('privacy') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'reaction' }" replace to="/settings/reaction"><Fa :icon="faLaugh" fixed-width class="icon"/>{{ $t('reaction') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'notifications' }" replace to="/settings/notifications"><Fa :icon="faBell" fixed-width class="icon"/>{{ $t('notifications') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'integration' }" replace to="/settings/integration"><Fa :icon="faShareAlt" fixed-width class="icon"/>{{ $t('integration') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'security' }" replace to="/settings/security"><Fa :icon="faLock" fixed-width class="icon"/>{{ $t('security') }}</MkA>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="menu">
 | 
			
		||||
			<div class="label">{{ $t('clientSettings') }}</div>
 | 
			
		||||
			<router-link class="item" replace to="/settings/general"><Fa :icon="faCogs" fixed-width class="icon"/>{{ $t('general') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/theme"><Fa :icon="faPalette" fixed-width class="icon"/>{{ $t('theme') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/sidebar"><Fa :icon="faListUl" fixed-width class="icon"/>{{ $t('sidebar') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/sounds"><Fa :icon="faMusic" fixed-width class="icon"/>{{ $t('sounds') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/plugins"><Fa :icon="faPlug" fixed-width class="icon"/>{{ $t('plugins') }}</router-link>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'general' }" replace to="/settings/general"><Fa :icon="faCogs" fixed-width class="icon"/>{{ $t('general') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'theme' }" replace to="/settings/theme"><Fa :icon="faPalette" fixed-width class="icon"/>{{ $t('theme') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'sidebar' }" replace to="/settings/sidebar"><Fa :icon="faListUl" fixed-width class="icon"/>{{ $t('sidebar') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'sounds' }" replace to="/settings/sounds"><Fa :icon="faMusic" fixed-width class="icon"/>{{ $t('sounds') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'plugins' }" replace to="/settings/plugins"><Fa :icon="faPlug" fixed-width class="icon"/>{{ $t('plugins') }}</MkA>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="menu">
 | 
			
		||||
			<div class="label">{{ $t('otherSettings') }}</div>
 | 
			
		||||
			<router-link class="item" replace to="/settings/mute-block"><Fa :icon="faBan" fixed-width class="icon"/>{{ $t('muteAndBlock') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/word-mute"><Fa :icon="faCommentSlash" fixed-width class="icon"/>{{ $t('wordMute') }}</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/api"><Fa :icon="faKey" fixed-width class="icon"/>API</router-link>
 | 
			
		||||
			<router-link class="item" replace to="/settings/other"><Fa :icon="faEllipsisH" fixed-width class="icon"/>{{ $t('other') }}</router-link>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'mute-block' }" replace to="/settings/mute-block"><Fa :icon="faBan" fixed-width class="icon"/>{{ $t('muteAndBlock') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'word-mute' }" replace to="/settings/word-mute"><Fa :icon="faCommentSlash" fixed-width class="icon"/>{{ $t('wordMute') }}</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'api' }" replace to="/settings/api"><Fa :icon="faKey" fixed-width class="icon"/>API</MkA>
 | 
			
		||||
			<MkA class="item" :class="{ active: page === 'other' }" replace to="/settings/other"><Fa :icon="faEllipsisH" fixed-width class="icon"/>{{ $t('other') }}</MkA>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="menu">
 | 
			
		||||
			<button class="_button item" @click="logout">{{ $t('logout') }}</button>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="main">
 | 
			
		||||
		<router-view v-slot="{ Component }">
 | 
			
		||||
			<transition :name="($store.state.device.animation && !narrow) ? 'view-slide' : ''" appear mode="out-in">
 | 
			
		||||
				<component :is="Component" @info="onInfo"/>
 | 
			
		||||
			</transition>
 | 
			
		||||
		</router-view>
 | 
			
		||||
		<transition :name="($store.state.device.animation && !narrow) ? 'view-slide' : ''" appear mode="out-in">
 | 
			
		||||
			<component :is="component" @info="onInfo"/>
 | 
			
		||||
		</transition>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent, onMounted, ref } from 'vue';
 | 
			
		||||
import { computed, defineAsyncComponent, defineComponent, onMounted, ref } from 'vue';
 | 
			
		||||
import { faCog, faPalette, faPlug, faUser, faListUl, faLock, faCommentSlash, faMusic, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { faLaugh, faBell } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
import { store } from '@/store';
 | 
			
		||||
import { i18n } from '@/i18n';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	props: {
 | 
			
		||||
		page: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: false
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	setup(props, context) {
 | 
			
		||||
		const INFO = ref({
 | 
			
		||||
			header: [{
 | 
			
		||||
@@ -60,6 +65,28 @@ export default defineComponent({
 | 
			
		||||
		const onInfo = (viewInfo) => {
 | 
			
		||||
			INFO.value = viewInfo;
 | 
			
		||||
		};
 | 
			
		||||
		const component = computed(() => {
 | 
			
		||||
			switch (props.page) {
 | 
			
		||||
				case 'profile': return defineAsyncComponent(() => import('./profile.vue'));
 | 
			
		||||
				case 'privacy': return defineAsyncComponent(() => import('./privacy.vue'));
 | 
			
		||||
				case 'reaction': return defineAsyncComponent(() => import('./reaction.vue'));
 | 
			
		||||
				case 'notifications': return defineAsyncComponent(() => import('./notifications.vue'));
 | 
			
		||||
				case 'mute-block': return defineAsyncComponent(() => import('./mute-block.vue'));
 | 
			
		||||
				case 'word-mute': return defineAsyncComponent(() => import('./word-mute.vue'));
 | 
			
		||||
				case 'integration': return defineAsyncComponent(() => import('./integration.vue'));
 | 
			
		||||
				case 'security': return defineAsyncComponent(() => import('./security.vue'));
 | 
			
		||||
				case 'api': return defineAsyncComponent(() => import('./api.vue'));
 | 
			
		||||
				case 'other': return defineAsyncComponent(() => import('./other.vue'));
 | 
			
		||||
				case 'general': return defineAsyncComponent(() => import('./general.vue'));
 | 
			
		||||
				case 'theme': return defineAsyncComponent(() => import('./theme.vue'));
 | 
			
		||||
				case 'sidebar': return defineAsyncComponent(() => import('./sidebar.vue'));
 | 
			
		||||
				case 'sounds': return defineAsyncComponent(() => import('./sounds.vue'));
 | 
			
		||||
				case 'plugins': return defineAsyncComponent(() => import('./plugins.vue'));
 | 
			
		||||
				case 'import-export': return defineAsyncComponent(() => import('./import-export.vue'));
 | 
			
		||||
				case 'regedit': return defineAsyncComponent(() => import('./regedit.vue'));
 | 
			
		||||
				default: return null;
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		onMounted(() => {
 | 
			
		||||
			narrow.value = el.value.offsetWidth < 650;
 | 
			
		||||
@@ -71,6 +98,7 @@ export default defineComponent({
 | 
			
		||||
			view,
 | 
			
		||||
			el,
 | 
			
		||||
			onInfo,
 | 
			
		||||
			component,
 | 
			
		||||
			logout: () => {
 | 
			
		||||
				store.dispatch('logout');
 | 
			
		||||
				location.href = '/';
 | 
			
		||||
@@ -121,7 +149,7 @@ export default defineComponent({
 | 
			
		||||
					//border-top: solid 1px var(--divider);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				&.router-link-active {
 | 
			
		||||
				&.active {
 | 
			
		||||
					color: var(--accent);
 | 
			
		||||
					padding-left: 42px;
 | 
			
		||||
				}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,9 @@
 | 
			
		||||
			<template #empty><MkInfo>{{ $t('noUsers') }}</MkInfo></template>
 | 
			
		||||
			<template #default="{items}">
 | 
			
		||||
				<div class="user" v-for="mute in items" :key="mute.id">
 | 
			
		||||
					<router-link class="name" :to="userPage(mute.mutee)">
 | 
			
		||||
					<MkA class="name" :to="userPage(mute.mutee)">
 | 
			
		||||
						<MkAcct :user="mute.mutee"/>
 | 
			
		||||
					</router-link>
 | 
			
		||||
					</MkA>
 | 
			
		||||
				</div>
 | 
			
		||||
			</template>
 | 
			
		||||
		</MkPagination>
 | 
			
		||||
@@ -18,9 +18,9 @@
 | 
			
		||||
			<template #empty><MkInfo>{{ $t('noUsers') }}</MkInfo></template>
 | 
			
		||||
			<template #default="{items}">
 | 
			
		||||
				<div class="user" v-for="block in items" :key="block.id">
 | 
			
		||||
					<router-link class="name" :to="userPage(block.blockee)">
 | 
			
		||||
					<MkA class="name" :to="userPage(block.blockee)">
 | 
			
		||||
						<MkAcct :user="block.blockee"/>
 | 
			
		||||
					</router-link>
 | 
			
		||||
					</MkA>
 | 
			
		||||
				</div>
 | 
			
		||||
			</template>
 | 
			
		||||
		</MkPagination>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,17 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div class="_section">
 | 
			
		||||
	<div class="_card">
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<MkSwitch v-model:value="$store.state.i.injectFeaturedNote" @update:value="onChangeInjectFeaturedNote">
 | 
			
		||||
				{{ $t('showFeaturedNotesInTimeline') }}
 | 
			
		||||
			</MkSwitch>
 | 
			
		||||
<div>
 | 
			
		||||
	<div class="_section">
 | 
			
		||||
		<div class="_card">
 | 
			
		||||
			<div class="_content">
 | 
			
		||||
				<MkSwitch v-model:value="$store.state.i.injectFeaturedNote" @update:value="onChangeInjectFeaturedNote">
 | 
			
		||||
					{{ $t('showFeaturedNotesInTimeline') }}
 | 
			
		||||
				</MkSwitch>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="_section">
 | 
			
		||||
		<MkA to="/settings/regedit">RegEdit</MkA>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										77
									
								
								src/client/pages/settings/regedit.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/client/pages/settings/regedit.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
			
		||||
<template>
 | 
			
		||||
<div>
 | 
			
		||||
	<div class="_section">
 | 
			
		||||
		<MkInfo warn>{{ $t('editTheseSettingsMayBreakAccount') }}</MkInfo>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="_section">
 | 
			
		||||
		<div class="_title">Account</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<MkTextarea v-model:value="settings" code tall></MkTextarea>
 | 
			
		||||
			<!--<MkButton @click="saveSettings">Save</MkButton>-->
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="_section">
 | 
			
		||||
		<div class="_title">Device</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<MkTextarea v-model:value="deviceSettings" code tall></MkTextarea>
 | 
			
		||||
			<MkButton @click="saveDeviceSettings">Save</MkButton>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="_section">
 | 
			
		||||
		<div class="_title">Device (per account)</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<MkTextarea v-model:value="deviceUserSettings" code tall></MkTextarea>
 | 
			
		||||
			<MkButton @click="saveDeviceUserSettings">Save</MkButton>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import { faCode } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import * as JSON5 from 'json5';
 | 
			
		||||
import MkInfo from '@/components/ui/info.vue';
 | 
			
		||||
import MkButton from '@/components/ui/button.vue';
 | 
			
		||||
import MkTextarea from '@/components/ui/textarea.vue';
 | 
			
		||||
import * as os from '@/os';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
	components: {
 | 
			
		||||
		MkInfo, MkButton, MkTextarea
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	emits: ['info'],
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			INFO: {
 | 
			
		||||
				header: [{
 | 
			
		||||
					title: 'RegEdit',
 | 
			
		||||
					icon: faCode
 | 
			
		||||
				}]
 | 
			
		||||
			},
 | 
			
		||||
 | 
			
		||||
			settings: JSON5.stringify(this.$store.state.settings, null, '\t'),
 | 
			
		||||
			deviceSettings: JSON5.stringify(this.$store.state.device, null, '\t'),
 | 
			
		||||
			deviceUserSettings: JSON5.stringify(this.$store.state.deviceUser, null, '\t'),
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.$emit('info', this.INFO);
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		saveDeviceSettings() {
 | 
			
		||||
			const obj = JSON5.parse(this.deviceSettings);
 | 
			
		||||
			this.$store.commit('device/overwrite', obj);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		saveDeviceUserSettings() {
 | 
			
		||||
			const obj = JSON5.parse(this.deviceUserSettings);
 | 
			
		||||
			this.$store.commit('deviceUser/overwrite', obj);
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
</script>
 | 
			
		||||
@@ -43,7 +43,7 @@
 | 
			
		||||
					<option v-for="x in lightThemes" :value="x.id" :key="x.id">{{ x.name }}</option>
 | 
			
		||||
				</optgroup>
 | 
			
		||||
			</MkSelect>
 | 
			
		||||
			<a href="https://assets.msky.cafe/theme/list" rel="noopener" target="_blank" class="_link">{{ $t('_theme.explore') }}</a>・<router-link to="/theme-editor" class="_link">{{ $t('_theme.make') }}</router-link>
 | 
			
		||||
			<a href="https://assets.msky.cafe/theme/list" rel="noopener" target="_blank" class="_link">{{ $t('_theme.explore') }}</a>・<MkA to="/theme-editor" class="_link">{{ $t('_theme.make') }}</MkA>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="_content">
 | 
			
		||||
			<MkButton primary v-if="wallpaper == null" @click="setWallpaper">{{ $t('setWallpaper') }}</MkButton>
 | 
			
		||||
 
 | 
			
		||||
@@ -15,11 +15,18 @@ export default defineComponent({
 | 
			
		||||
		XNotes
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		tag: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			INFO: {
 | 
			
		||||
				header: [{
 | 
			
		||||
					title: this.$route.params.tag,
 | 
			
		||||
					title: this.tag,
 | 
			
		||||
					icon: faHashtag
 | 
			
		||||
				}],
 | 
			
		||||
			},
 | 
			
		||||
@@ -27,7 +34,7 @@ export default defineComponent({
 | 
			
		||||
				endpoint: 'notes/search-by-tag',
 | 
			
		||||
				limit: 10,
 | 
			
		||||
				params: () => ({
 | 
			
		||||
					tag: this.$route.params.tag,
 | 
			
		||||
					tag: this.tag,
 | 
			
		||||
				})
 | 
			
		||||
			},
 | 
			
		||||
			faHashtag
 | 
			
		||||
@@ -35,7 +42,7 @@ export default defineComponent({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: {
 | 
			
		||||
		$route() {
 | 
			
		||||
		tag() {
 | 
			
		||||
			(this.$refs.notes as any).reload();
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 
 | 
			
		||||
@@ -229,7 +229,7 @@ export default defineComponent({
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		messagingWindowOpen() {
 | 
			
		||||
			os.pageWindow('/my/messaging', defineAsyncComponent(() => import('@/pages/messaging/index.vue')));
 | 
			
		||||
			os.pageWindow('/my/messaging');
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		openWaitingDialog(text?) {
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@
 | 
			
		||||
	<div class="_content" v-else-if="tutorial === 1">
 | 
			
		||||
		<div>{{ $t('_tutorial.step2_1') }}</div>
 | 
			
		||||
		<div>{{ $t('_tutorial.step2_2') }}</div>
 | 
			
		||||
		<router-link class="_link" to="/settings/profile">{{ $t('editProfile') }}</router-link>
 | 
			
		||||
		<MkA class="_link" to="/settings/profile">{{ $t('editProfile') }}</MkA>
 | 
			
		||||
	</div>
 | 
			
		||||
	<div class="_content" v-else-if="tutorial === 2">
 | 
			
		||||
		<div>{{ $t('_tutorial.step3_1') }}</div>
 | 
			
		||||
@@ -25,10 +25,10 @@
 | 
			
		||||
		<div>{{ $t('_tutorial.step5_1') }}</div>
 | 
			
		||||
		<i18n-t keypath="_tutorial.step5_2" tag="div">
 | 
			
		||||
			<template #featured>
 | 
			
		||||
				<router-link class="_link" to="/featured">{{ $t('featured') }}</router-link>
 | 
			
		||||
				<MkA class="_link" to="/featured">{{ $t('featured') }}</MkA>
 | 
			
		||||
			</template>
 | 
			
		||||
			<template #explore>
 | 
			
		||||
				<router-link class="_link" to="/explore">{{ $t('explore') }}</router-link>
 | 
			
		||||
				<MkA class="_link" to="/explore">{{ $t('explore') }}</MkA>
 | 
			
		||||
			</template>
 | 
			
		||||
		</i18n-t>
 | 
			
		||||
		<div>{{ $t('_tutorial.step5_3') }}</div>
 | 
			
		||||
@@ -43,7 +43,7 @@
 | 
			
		||||
		<div>{{ $t('_tutorial.step7_1') }}</div>
 | 
			
		||||
		<i18n-t keypath="_tutorial.step7_2" tag="div">
 | 
			
		||||
			<template #help>
 | 
			
		||||
				<router-link class="_link" to="/docs">{{ $t('help') }}</router-link>
 | 
			
		||||
				<MkA class="_link" to="/docs">{{ $t('help') }}</MkA>
 | 
			
		||||
			</template>
 | 
			
		||||
		</i18n-t>
 | 
			
		||||
		<div>{{ $t('_tutorial.step7_3') }}</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,6 @@
 | 
			
		||||
 | 
			
		||||
<script lang="ts">
 | 
			
		||||
import { defineComponent } from 'vue';
 | 
			
		||||
import parseAcct from '../../../misc/acct/parse';
 | 
			
		||||
import MkUserInfo from '@/components/user-info.vue';
 | 
			
		||||
import MkPagination from '@/components/ui/pagination.vue';
 | 
			
		||||
import { userPage, acct } from '../../filters/user';
 | 
			
		||||
@@ -22,10 +21,14 @@ export default defineComponent({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		user: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		type: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true
 | 
			
		||||
		}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
@@ -34,7 +37,7 @@ export default defineComponent({
 | 
			
		||||
				endpoint: () => this.type === 'following' ? 'users/following' : 'users/followers',
 | 
			
		||||
				limit: 20,
 | 
			
		||||
				params: {
 | 
			
		||||
					...parseAcct(this.$route.params.user),
 | 
			
		||||
					userId: this.user.id,
 | 
			
		||||
				}
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
@@ -45,7 +48,7 @@ export default defineComponent({
 | 
			
		||||
			this.$refs.list.reload();
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		'$route'() {
 | 
			
		||||
		user() {
 | 
			
		||||
			this.$refs.list.reload();
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,11 @@
 | 
			
		||||
<div class="ujigsodd">
 | 
			
		||||
	<MkLoading v-if="fetching"/>
 | 
			
		||||
	<div class="stream" v-if="!fetching && images.length > 0">
 | 
			
		||||
		<router-link v-for="(image, i) in images" :key="i"
 | 
			
		||||
		<MkA v-for="image in images"
 | 
			
		||||
			class="img"
 | 
			
		||||
			:style="`background-image: url(${thumbnail(image.file)})`"
 | 
			
		||||
			:to="notePage(image.note)"
 | 
			
		||||
		></router-link>
 | 
			
		||||
		></MkA>
 | 
			
		||||
	</div>
 | 
			
		||||
	<p class="empty" v-if="!fetching && images.length == 0">{{ $t('nothing') }}</p>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,13 @@
 | 
			
		||||
<template>
 | 
			
		||||
<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 -->
 | 
			
		||||
	<!-- <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="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" ref="banner" :style="style"></div>
 | 
			
		||||
				<div class="fade"></div>
 | 
			
		||||
@@ -67,24 +67,23 @@
 | 
			
		||||
				</dl>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="status">
 | 
			
		||||
				<router-link :to="userPage(user)" :class="{ active: $route.name === 'user' }">
 | 
			
		||||
				<MkA :to="userPage(user)" :class="{ active: page === 'index' }">
 | 
			
		||||
					<b>{{ number(user.notesCount) }}</b>
 | 
			
		||||
					<span>{{ $t('notes') }}</span>
 | 
			
		||||
				</router-link>
 | 
			
		||||
				<router-link :to="userPage(user, 'following')" :class="{ active: $route.name === 'userFollowing' }">
 | 
			
		||||
				</MkA>
 | 
			
		||||
				<MkA :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
 | 
			
		||||
					<b>{{ number(user.followingCount) }}</b>
 | 
			
		||||
					<span>{{ $t('following') }}</span>
 | 
			
		||||
				</router-link>
 | 
			
		||||
				<router-link :to="userPage(user, 'followers')" :class="{ active: $route.name === 'userFollowers' }">
 | 
			
		||||
				</MkA>
 | 
			
		||||
				<MkA :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
 | 
			
		||||
					<b>{{ number(user.followersCount) }}</b>
 | 
			
		||||
					<span>{{ $t('followers') }}</span>
 | 
			
		||||
				</router-link>
 | 
			
		||||
				</MkA>
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
 | 
			
		||||
	<router-view :user="user"></router-view>
 | 
			
		||||
	<template v-if="$route.name == 'user'">
 | 
			
		||||
	<template v-if="page === 'index'">
 | 
			
		||||
		<div class="_section">
 | 
			
		||||
			<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"/>
 | 
			
		||||
@@ -106,6 +105,8 @@
 | 
			
		||||
			<XUserTimeline :user="user" class="_content"/>
 | 
			
		||||
		</div>
 | 
			
		||||
	</template>
 | 
			
		||||
	<XFollowList v-else-if="page === 'following'" type="following" :user="user"/>
 | 
			
		||||
	<XFollowList v-else-if="page === 'followers'" type="followers" :user="user"/>
 | 
			
		||||
</div>
 | 
			
		||||
<div v-else-if="error">
 | 
			
		||||
	<MkError @retry="fetch()"/>
 | 
			
		||||
@@ -128,7 +129,7 @@ import parseAcct from '../../../misc/acct/parse';
 | 
			
		||||
import { getScrollPosition } from '@/scripts/scroll';
 | 
			
		||||
import { getUserMenu } from '@/scripts/get-user-menu';
 | 
			
		||||
import number from '../../filters/number';
 | 
			
		||||
import { userPage, acct } from '../../filters/user';
 | 
			
		||||
import { userPage, acct as getAcct } from '../../filters/user';
 | 
			
		||||
import * as os from '@/os';
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
@@ -139,10 +140,23 @@ export default defineComponent({
 | 
			
		||||
		MkContainer,
 | 
			
		||||
		MkRemoteCaution,
 | 
			
		||||
		MkFolder,
 | 
			
		||||
		XFollowList: defineAsyncComponent(() => import('./follow-list.vue')),
 | 
			
		||||
		XPhotos: defineAsyncComponent(() => import('./index.photos.vue')),
 | 
			
		||||
		XActivity: defineAsyncComponent(() => import('./index.activity.vue')),
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		acct: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true
 | 
			
		||||
		},
 | 
			
		||||
		page: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: false,
 | 
			
		||||
			default: 'index'
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			INFO: computed(() => this.user ? {
 | 
			
		||||
@@ -176,7 +190,7 @@ export default defineComponent({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: {
 | 
			
		||||
		$route: 'fetch'
 | 
			
		||||
		acct: 'fetch'
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	created() {
 | 
			
		||||
@@ -192,10 +206,12 @@ export default defineComponent({
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		getAcct,
 | 
			
		||||
 | 
			
		||||
		fetch() {
 | 
			
		||||
			if (this.$route.params.user == null) return;
 | 
			
		||||
			if (this.acct == null) return;
 | 
			
		||||
			Progress.start();
 | 
			
		||||
			os.api('users/show', parseAcct(this.$route.params.user)).then(user => {
 | 
			
		||||
			os.api('users/show', parseAcct(this.acct)).then(user => {
 | 
			
		||||
				this.user = user;
 | 
			
		||||
			}).catch(e => {
 | 
			
		||||
				this.error = e;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
import { defineAsyncComponent } from 'vue';
 | 
			
		||||
import { defineAsyncComponent, markRaw } from 'vue';
 | 
			
		||||
import { createRouter, createWebHistory } from 'vue-router';
 | 
			
		||||
import MkLoading from '@/pages/_loading_.vue';
 | 
			
		||||
import MkError from '@/pages/_error_.vue';
 | 
			
		||||
@@ -18,30 +18,11 @@ export const router = createRouter({
 | 
			
		||||
	routes: [
 | 
			
		||||
		// NOTE: MkTimelineをdynamic importするとAsyncComponentWrapperが間に入るせいでkeep-aliveのコンポーネント指定が効かなくなる
 | 
			
		||||
		{ path: '/', name: 'index', component: store.getters.isSignedIn ? MkTimeline : page('welcome') },
 | 
			
		||||
		{ path: '/@:user', name: 'user', component: page('user/index'), children: [
 | 
			
		||||
			{ path: 'following', name: 'userFollowing', component: page('user/follow-list'), props: { type: 'following' } },
 | 
			
		||||
			{ path: 'followers', name: 'userFollowers', component: page('user/follow-list'), props: { type: 'followers' } },
 | 
			
		||||
		]},
 | 
			
		||||
		{ path: '/@:acct/:page?', name: 'user', component: page('user/index'), props: route => ({ acct: route.params.acct, page: route.params.page || 'index' }) },
 | 
			
		||||
		{ path: '/@:user/pages/:page', component: page('page'), props: route => ({ pageName: route.params.page, username: route.params.user }) },
 | 
			
		||||
		{ path: '/@:user/pages/:pageName/view-source', component: page('page-editor/page-editor'), props: route => ({ initUser: route.params.user, initPageName: route.params.pageName }) },
 | 
			
		||||
		{ path: '/@:acct/room', props: true, component: page('room/room') },
 | 
			
		||||
		{ path: '/settings', name: 'settings', component: page('settings/index'), children: [
 | 
			
		||||
			{ path: 'profile', component: page('settings/profile') },
 | 
			
		||||
			{ path: 'privacy', component: page('settings/privacy') },
 | 
			
		||||
			{ path: 'reaction', component: page('settings/reaction') },
 | 
			
		||||
			{ path: 'notifications', component: page('settings/notifications') },
 | 
			
		||||
			{ path: 'mute-block', component: page('settings/mute-block') },
 | 
			
		||||
			{ path: 'word-mute', component: page('settings/word-mute') },
 | 
			
		||||
			{ path: 'integration', component: page('settings/integration') },
 | 
			
		||||
			{ path: 'security', component: page('settings/security') },
 | 
			
		||||
			{ path: 'api', component: page('settings/api') },
 | 
			
		||||
			{ path: 'other', component: page('settings/other') },
 | 
			
		||||
			{ path: 'general', component: page('settings/general') },
 | 
			
		||||
			{ path: 'theme', component: page('settings/theme') },
 | 
			
		||||
			{ path: 'sidebar', component: page('settings/sidebar') },
 | 
			
		||||
			{ path: 'sounds', component: page('settings/sounds') },
 | 
			
		||||
			{ path: 'plugins', component: page('settings/plugins') },
 | 
			
		||||
		]},
 | 
			
		||||
		{ path: '/settings/:page?', name: 'settings', component: page('settings/index'), props: route => ({ page: route.params.page || null }) },
 | 
			
		||||
		{ path: '/announcements', component: page('announcements') },
 | 
			
		||||
		{ path: '/about', component: page('about') },
 | 
			
		||||
		{ path: '/about-misskey', component: page('about-misskey') },
 | 
			
		||||
@@ -86,8 +67,9 @@ export const router = createRouter({
 | 
			
		||||
		{ path: '/instance/federation', component: page('instance/federation') },
 | 
			
		||||
		{ path: '/instance/relays', component: page('instance/relays') },
 | 
			
		||||
		{ path: '/instance/announcements', component: page('instance/announcements') },
 | 
			
		||||
		{ path: '/notes/:note', name: 'note', component: page('note') },
 | 
			
		||||
		{ path: '/tags/:tag', component: page('tag') },
 | 
			
		||||
		{ path: '/instance/abuses', component: page('instance/abuses') },
 | 
			
		||||
		{ path: '/notes/:note', name: 'note', component: page('note'), props: route => ({ noteId: route.params.note }) },
 | 
			
		||||
		{ path: '/tags/:tag', component: page('tag'), props: route => ({ tag: route.params.tag }) },
 | 
			
		||||
		{ path: '/auth/:token', component: page('auth') },
 | 
			
		||||
		{ path: '/miauth/:session', component: page('miauth') },
 | 
			
		||||
		{ path: '/authorize-follow', component: page('follow') },
 | 
			
		||||
@@ -119,3 +101,13 @@ router.afterEach((to, from) => {
 | 
			
		||||
		indexScrollPos = window.scrollY;
 | 
			
		||||
	}
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
export function resolve(path: string) {
 | 
			
		||||
	const resolved = router.resolve(path);
 | 
			
		||||
	const route = resolved.matched[0];
 | 
			
		||||
	return {
 | 
			
		||||
		component: markRaw(route.components.default),
 | 
			
		||||
		// TODO: route.propsには関数以外も入る可能性があるのでよしなにハンドリングする
 | 
			
		||||
		props: route.props?.default ? route.props.default(resolved) : resolved.params
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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 { i18n } from '@/i18n';
 | 
			
		||||
import copyToClipboard from '@/scripts/copy-to-clipboard';
 | 
			
		||||
@@ -7,7 +7,6 @@ import getAcct from '../../misc/acct/render';
 | 
			
		||||
import * as os from '@/os';
 | 
			
		||||
import { store, userActions } from '@/store';
 | 
			
		||||
import { router } from '@/router';
 | 
			
		||||
import { defineAsyncComponent } from 'vue';
 | 
			
		||||
import { popout } from './popout';
 | 
			
		||||
 | 
			
		||||
export function getUserMenu(user) {
 | 
			
		||||
@@ -102,6 +101,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> {
 | 
			
		||||
		const confirm = await os.dialog({
 | 
			
		||||
			type: 'warning',
 | 
			
		||||
@@ -131,7 +136,7 @@ export function getUserMenu(user) {
 | 
			
		||||
		action: () => {
 | 
			
		||||
			const acct = getAcct(user);
 | 
			
		||||
			switch (store.state.device.chatOpenBehavior) {
 | 
			
		||||
				case 'window': { os.pageWindow('/my/messaging/' + acct, defineAsyncComponent(() => import('@/pages/messaging/messaging-room.vue')), { userAcct: acct }); break; }
 | 
			
		||||
				case 'window': { os.pageWindow('/my/messaging/' + acct); break; }
 | 
			
		||||
				case 'popout': { popout('/my/messaging'); break; }
 | 
			
		||||
				default: { router.push('/my/messaging'); break; }
 | 
			
		||||
			}
 | 
			
		||||
@@ -157,6 +162,12 @@ export function getUserMenu(user) {
 | 
			
		||||
			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)) {
 | 
			
		||||
			menu = menu.concat([null, {
 | 
			
		||||
				icon: faMicrophoneSlash,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ export type Theme = {
 | 
			
		||||
	author: string;
 | 
			
		||||
	desc?: string;
 | 
			
		||||
	base?: 'dark' | 'light';
 | 
			
		||||
	props: { [key: string]: string };
 | 
			
		||||
	props: Record<string, string>;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
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 builtinThemes = [
 | 
			
		||||
	require('../themes/white.json5'),
 | 
			
		||||
	require('../themes/black.json5'),
 | 
			
		||||
	require('../themes/lilac.json5'),
 | 
			
		||||
	require('../themes/halloween.json5'),
 | 
			
		||||
	require('../themes/city.json5'),
 | 
			
		||||
	require('../themes/rainy.json5'),
 | 
			
		||||
	require('../themes/urban.json5'),
 | 
			
		||||
	require('../themes/cafe.json5'),
 | 
			
		||||
	require('../themes/chocolate.json5'),
 | 
			
		||||
	require('../themes/danboard.json5'),
 | 
			
		||||
	require('../themes/olive.json5'),
 | 
			
		||||
	require('../themes/ocean.json5'),
 | 
			
		||||
	require('../themes/l-white.json5'),
 | 
			
		||||
	require('../themes/l-red.json5'),
 | 
			
		||||
	require('../themes/l-green.json5'),
 | 
			
		||||
	require('../themes/l-blue.json5'),
 | 
			
		||||
	require('../themes/l-apricot.json5'),
 | 
			
		||||
 | 
			
		||||
	require('../themes/d-black.json5'),
 | 
			
		||||
	require('../themes/d-red.json5'),
 | 
			
		||||
	require('../themes/d-green.json5'),
 | 
			
		||||
	require('../themes/d-blue.json5'),
 | 
			
		||||
	require('../themes/d-persimmon.json5'),
 | 
			
		||||
 | 
			
		||||
	require('../themes/d-battery-saver.json5'),
 | 
			
		||||
] as Theme[];
 | 
			
		||||
 | 
			
		||||
let timeout = null;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
import { faBell, faComments, faEnvelope } from '@fortawesome/free-regular-svg-icons';
 | 
			
		||||
import { faAt, faBroadcastTower, faCloud, faColumns, faDoorClosed, faFileAlt, faFireAlt, faGamepad, faHashtag, faListUl, faSatellite, faSatelliteDish, faSearch, faStar, faTerminal, faUserClock, faUsers } from '@fortawesome/free-solid-svg-icons';
 | 
			
		||||
import { computed, defineAsyncComponent } from 'vue';
 | 
			
		||||
import { computed } from 'vue';
 | 
			
		||||
import { store } from '@/store';
 | 
			
		||||
import { deckmode } from '@/config';
 | 
			
		||||
import { search } from '@/scripts/search';
 | 
			
		||||
@@ -23,7 +23,7 @@ export const sidebarDef = {
 | 
			
		||||
		indicated: computed(() => store.getters.isSignedIn && store.state.i.hasUnreadMessagingMessage),
 | 
			
		||||
		action: () => {
 | 
			
		||||
			switch (store.state.device.chatOpenBehavior) {
 | 
			
		||||
				case 'window': { os.pageWindow('/my/messaging', defineAsyncComponent(() => import('@/pages/messaging/index.vue'))); break; }
 | 
			
		||||
				case 'window': { os.pageWindow('/my/messaging'); break; }
 | 
			
		||||
				case 'popout': { popout('/my/messaging'); break; }
 | 
			
		||||
				default: { router.push('/my/messaging'); break; }
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,7 +61,7 @@ export const defaultDeviceSettings = {
 | 
			
		||||
	accounts: [],
 | 
			
		||||
	recentEmojis: [],
 | 
			
		||||
	themes: [],
 | 
			
		||||
	darkTheme: '8c539dc1-0fab-4d47-9194-39c508e9bfe1',
 | 
			
		||||
	darkTheme: '8050783a-7f63-445a-b270-36d0f6ba1677',
 | 
			
		||||
	lightTheme: '4eea646f-7afa-4645-83e9-83af0333cd37',
 | 
			
		||||
	darkMode: false,
 | 
			
		||||
	deckMode: false,
 | 
			
		||||
@@ -70,6 +70,8 @@ export const defaultDeviceSettings = {
 | 
			
		||||
	animatedMfm: true,
 | 
			
		||||
	imageNewTab: false,
 | 
			
		||||
	chatOpenBehavior: 'page',
 | 
			
		||||
	defaultSideView: false,
 | 
			
		||||
	deckNavWindow: true,
 | 
			
		||||
	showFixedPostForm: false,
 | 
			
		||||
	disablePagesScript: false,
 | 
			
		||||
	enableInfiniteScroll: true,
 | 
			
		||||
@@ -202,6 +204,15 @@ export const store = createStore({
 | 
			
		||||
			state: defaultDeviceSettings,
 | 
			
		||||
 | 
			
		||||
			mutations: {
 | 
			
		||||
				overwrite(state, x) {
 | 
			
		||||
					for (const k of Object.keys(state)) {
 | 
			
		||||
						if (x[k] === undefined) delete state[k];
 | 
			
		||||
					}
 | 
			
		||||
					for (const k of Object.keys(x)) {
 | 
			
		||||
						state[k] = x[k];
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
 | 
			
		||||
				set(state, x: { key: string; value: any }) {
 | 
			
		||||
					state[x.key] = x.value;
 | 
			
		||||
				},
 | 
			
		||||
@@ -218,6 +229,15 @@ export const store = createStore({
 | 
			
		||||
			state: defaultDeviceUserSettings,
 | 
			
		||||
 | 
			
		||||
			mutations: {
 | 
			
		||||
				overwrite(state, x) {
 | 
			
		||||
					for (const k of Object.keys(state)) {
 | 
			
		||||
						if (x[k] === undefined) delete state[k];
 | 
			
		||||
					}
 | 
			
		||||
					for (const k of Object.keys(x)) {
 | 
			
		||||
						state[k] = x[k];
 | 
			
		||||
					}
 | 
			
		||||
				},
 | 
			
		||||
 | 
			
		||||
				init(state, x) {
 | 
			
		||||
					for (const [key, value] of Object.entries(defaultDeviceUserSettings)) {
 | 
			
		||||
						if (x[key]) {
 | 
			
		||||
 
 | 
			
		||||
@@ -109,6 +109,11 @@ textarea, input {
 | 
			
		||||
	-webkit-tap-highlight-color: transparent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
optgroup, option {
 | 
			
		||||
	background: var(--panel);
 | 
			
		||||
	color: var(--fg);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
hr {
 | 
			
		||||
	margin: var(--margin) 0 var(--margin) 0;
 | 
			
		||||
	border: none;
 | 
			
		||||
@@ -319,6 +324,7 @@ hr {
 | 
			
		||||
 | 
			
		||||
	> ._title,
 | 
			
		||||
	> ._content {
 | 
			
		||||
		box-sizing: border-box;
 | 
			
		||||
		max-width: var(--baseContentWidth);
 | 
			
		||||
		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',
 | 
			
		||||
 | 
			
		||||
	name: 'Black',
 | 
			
		||||
	name: 'Battery Saver',
 | 
			
		||||
	author: 'syuilo',
 | 
			
		||||
	desc: 'Basic dark theme',
 | 
			
		||||
 | 
			
		||||
	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',
 | 
			
		||||
 | 
			
		||||
	name: 'Cafe',
 | 
			
		||||
	name: 'Ai Apricot',
 | 
			
		||||
	author: 'syuilo',
 | 
			
		||||
 | 
			
		||||
	base: 'light',
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		accent: 'rgb(234, 154, 82)',
 | 
			
		||||
		bg: '#DDD9D1',
 | 
			
		||||
		bg: '#e6e5e2',
 | 
			
		||||
		fg: 'rgb(149, 143, 139)',
 | 
			
		||||
		panel: '#EEECE8',
 | 
			
		||||
		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',
 | 
			
		||||
 | 
			
		||||
	name: 'White',
 | 
			
		||||
	name: 'Mi White',
 | 
			
		||||
	author: 'syuilo',
 | 
			
		||||
	desc: 'Basic light theme',
 | 
			
		||||
	desc: 'Default light theme',
 | 
			
		||||
 | 
			
		||||
	base: 'light',
 | 
			
		||||
 | 
			
		||||
	props: {
 | 
			
		||||
		bg: '#F6F7F7',
 | 
			
		||||
		bg: '#f9f9f9',
 | 
			
		||||
		fg: '#636b71',
 | 
			
		||||
		divider: 'rgb(223, 223, 223)',
 | 
			
		||||
		header: ':alpha<0.7<@bg',
 | 
			
		||||
		navBg: '@bg',
 | 
			
		||||
		panel: '#fff',
 | 
			
		||||
		panelShadow: '" 0 8px 24px rgb(21 43 75 / 8%)',
 | 
			
		||||
		panelHeaderDivider: '@divider',
 | 
			
		||||
		messageBg: '#dedede',
 | 
			
		||||
	},
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user