Compare commits
95 Commits
13.0.0-bet
...
13.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4c8dbcc20d | ||
![]() |
416dcf884d | ||
![]() |
09d3ce444a | ||
![]() |
27c2ca5048 | ||
![]() |
fceeb1b108 | ||
![]() |
b442c38f41 | ||
![]() |
7c2d2676f7 | ||
![]() |
1f6a41cea7 | ||
![]() |
0d7ee20a77 | ||
![]() |
dcca2350dd | ||
![]() |
1cfdd4c41a | ||
![]() |
25f4ee7030 | ||
![]() |
5320f23017 | ||
![]() |
4ffbbbe6d8 | ||
![]() |
132e45dff4 | ||
![]() |
01652b72b3 | ||
![]() |
8b1fdb5a3b | ||
![]() |
192add376c | ||
![]() |
244ea9593a | ||
![]() |
f20d7cba74 | ||
![]() |
a3e282bc75 | ||
![]() |
49a95c34bf | ||
![]() |
ecbefce2aa | ||
![]() |
91356b1805 | ||
![]() |
2e2ed1385f | ||
![]() |
49f3090edd | ||
![]() |
4594fb11de | ||
![]() |
b93e56d2e5 | ||
![]() |
c550dafb81 | ||
![]() |
8709574f3d | ||
![]() |
1b7043fa79 | ||
![]() |
55ef2393fb | ||
![]() |
7769095efb | ||
![]() |
b8248bdd65 | ||
![]() |
6f4ad581dc | ||
![]() |
aec94920ab | ||
![]() |
155ca39063 | ||
![]() |
58bfb4dca4 | ||
![]() |
49a0b6c48b | ||
![]() |
799a653b44 | ||
![]() |
d09e1f4925 | ||
![]() |
cac784af8a | ||
![]() |
d7e0ddcbca | ||
![]() |
8c0811a442 | ||
![]() |
bab6f75260 | ||
![]() |
54e3fccd87 | ||
![]() |
6a992b6982 | ||
![]() |
ecd6fc1db8 | ||
![]() |
d99be6697e | ||
![]() |
d2d77b5dc1 | ||
![]() |
91503405b4 | ||
![]() |
c336201084 | ||
![]() |
0f3399753d | ||
![]() |
5ec89ea0c3 | ||
![]() |
a42b03c154 | ||
![]() |
4b181a30da | ||
![]() |
70805e00eb | ||
![]() |
3551ac328e | ||
![]() |
e36e5df635 | ||
![]() |
3e7d8b5f17 | ||
![]() |
5846198eee | ||
![]() |
c14063a921 | ||
![]() |
457670e730 | ||
![]() |
513cef50a2 | ||
![]() |
88c64ece78 | ||
![]() |
a11672d0a5 | ||
![]() |
46af9515b0 | ||
![]() |
c5cb786054 | ||
![]() |
4d2d6154a3 | ||
![]() |
495d513efd | ||
![]() |
3b617fafdd | ||
![]() |
82c4f694a0 | ||
![]() |
dc5b4a0402 | ||
![]() |
6adc0521d8 | ||
![]() |
9ac86dacbb | ||
![]() |
88f0c10d09 | ||
![]() |
4abef6161e | ||
![]() |
f6b6f1bc8b | ||
![]() |
6b2b403d94 | ||
![]() |
e2ca90b0a1 | ||
![]() |
9aececc921 | ||
![]() |
d25f214a09 | ||
![]() |
aefc8fb7b5 | ||
![]() |
372a17d7f0 | ||
![]() |
bcc3380cfc | ||
![]() |
047262ab20 | ||
![]() |
58ae2ccbfa | ||
![]() |
29f6f5fa5c | ||
![]() |
8df7530b54 | ||
![]() |
ded8584fdd | ||
![]() |
9734ad42a1 | ||
![]() |
d890383a00 | ||
![]() |
1cae688ccb | ||
![]() |
6f9aa94e3a | ||
![]() |
df291b00d8 |
30
CHANGELOG.md
@@ -11,19 +11,35 @@ You should also include the user name that made the change.
|
|||||||
|
|
||||||
## 13.0.0 (unreleased)
|
## 13.0.0 (unreleased)
|
||||||
|
|
||||||
|
### TL;DR
|
||||||
|
- New features (Play, new widgets, new charts, etc)
|
||||||
|
- Rewriten backend
|
||||||
|
- Better performance (backend and frontend)
|
||||||
|
- Various usability improvements
|
||||||
|
- Various UI tweaks
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
#### For server admins
|
||||||
- Node.js 18.x or later is required
|
- Node.js 18.x or later is required
|
||||||
|
- PostgreSQL 15.x is required
|
||||||
|
- Misskey not using 15 specific features at 13.0.0, but may do so in the future.
|
||||||
- Elasticsearchのサポートが削除されました
|
- Elasticsearchのサポートが削除されました
|
||||||
- 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
|
- 代わりに今後任意の検索プロバイダを設定できる仕組みを構想しています。その仕組みを使えば今まで通りElasticsearchも利用できます
|
||||||
- ノートのウォッチ機能が削除されました
|
|
||||||
- Migrate to Yarn Berry (v3.2.1) @ThatOneCalculator
|
- Migrate to Yarn Berry (v3.2.1) @ThatOneCalculator
|
||||||
- You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic
|
- You may have to `yarn run clean-all`, `sudo corepack enable` and `yarn set version berry` before running `yarn install` if you're still on yarn classic
|
||||||
|
|
||||||
|
#### For users
|
||||||
|
- ノートのウォッチ機能が削除されました
|
||||||
|
- アンケートに投票された際に通知が作成されなくなりました
|
||||||
- 新たに動的なPagesを作ることはできなくなりました
|
- 新たに動的なPagesを作ることはできなくなりました
|
||||||
- 代わりにAiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能が実装されています。
|
- 代わりにAiScriptを用いてより柔軟に動的なコンテンツを作成できるMisskey Play機能が実装されています。
|
||||||
- AiScriptが0.12.0にアップデートされました
|
- AiScriptが0.12.2にアップデートされました
|
||||||
- 0.12.0の変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120
|
- 0.12.xの変更点についてはこちら https://github.com/syuilo/aiscript/blob/master/CHANGELOG.md#0120
|
||||||
- 0.12.0未満のプラグインは読み込むことはできません
|
- 0.12.x未満のプラグインは読み込むことはできません
|
||||||
- iOS15以下のデバイスはサポートされなくなりました
|
- iOS15以下のデバイスはサポートされなくなりました
|
||||||
|
- Firefox109以下はサポートされなくなりました
|
||||||
|
|
||||||
|
#### For app developers
|
||||||
- API: カスタム絵文字エンティティに`url`プロパティが含まれなくなりました
|
- API: カスタム絵文字エンティティに`url`プロパティが含まれなくなりました
|
||||||
- 絵文字画像を表示するには、`<instance host>/emoji/<emoji name>.webp`にリクエストすると画像が返ります。
|
- 絵文字画像を表示するには、`<instance host>/emoji/<emoji name>.webp`にリクエストすると画像が返ります。
|
||||||
- e.g. `https://p1.a9z.dev/emoji/misskey.webp`
|
- e.g. `https://p1.a9z.dev/emoji/misskey.webp`
|
||||||
@@ -62,12 +78,17 @@ You should also include the user name that made the change.
|
|||||||
- Client: Improve RSS widget @tamaina
|
- Client: Improve RSS widget @tamaina
|
||||||
- Client: show Unicode emoji tooltip with its name in MkReactionsViewer.reaction @saschanaz
|
- Client: show Unicode emoji tooltip with its name in MkReactionsViewer.reaction @saschanaz
|
||||||
- Client: OpenSearch support @SoniEx2 @chaoticryptidz
|
- Client: OpenSearch support @SoniEx2 @chaoticryptidz
|
||||||
|
- Client: Support remote objects in search @SoniEx2
|
||||||
|
- Client: user activity page @syuilo
|
||||||
- Client: add user list widget @syuilo
|
- Client: add user list widget @syuilo
|
||||||
- Client: add heatmap of daily active users to about page @syuilo
|
- Client: add heatmap of daily active users to about page @syuilo
|
||||||
- Client: introduce fluent emoji @syuilo
|
- Client: introduce fluent emoji @syuilo
|
||||||
|
- Client: add new theme @syuilo
|
||||||
|
- Client: show fireworks when visit user who today is birthday @syuilo
|
||||||
- Client: show bot warning on screen when logged in as bot account @syuilo
|
- Client: show bot warning on screen when logged in as bot account @syuilo
|
||||||
- Client: improve overall performance of client @syuilo
|
- Client: improve overall performance of client @syuilo
|
||||||
- Client: ui tweaks @syuilo
|
- Client: ui tweaks @syuilo
|
||||||
|
- Client: clicker game @syuilo
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- Server: 引用内の文章がnyaizeされてしまう問題を修正 @kabo2468
|
- Server: 引用内の文章がnyaizeされてしまう問題を修正 @kabo2468
|
||||||
@@ -82,6 +103,7 @@ You should also include the user name that made the change.
|
|||||||
- Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina
|
- Client: InAppウィンドウが操作できなくなることがあるのを修正 @tamaina
|
||||||
- Client: use proxied image for instance icon @syuilo
|
- Client: use proxied image for instance icon @syuilo
|
||||||
- Client: Webhookの編集画面で、内容を保存することができない問題を修正 @m-hayabusa
|
- Client: Webhookの編集画面で、内容を保存することができない問題を修正 @m-hayabusa
|
||||||
|
- Client: Page編集でブロックの移動が行えない問題を修正 @syuilo
|
||||||
- Client: update emoji picker immediately on all input @saschanaz
|
- Client: update emoji picker immediately on all input @saschanaz
|
||||||
- Client: チャートのツールチップが画面に残ることがあるのを修正 @syuilo
|
- Client: チャートのツールチップが画面に残ることがあるのを修正 @syuilo
|
||||||
- Client: fix wrong link in tutorial @syuilo
|
- Client: fix wrong link in tutorial @syuilo
|
||||||
|
@@ -380,6 +380,7 @@ administrator: "المدير"
|
|||||||
token: "الرمز المميز"
|
token: "الرمز المميز"
|
||||||
twoStepAuthentication: "الإستيثاق بعاملَيْن"
|
twoStepAuthentication: "الإستيثاق بعاملَيْن"
|
||||||
moderator: "مشرِف"
|
moderator: "مشرِف"
|
||||||
|
moderation: "الإشراف"
|
||||||
nUsersMentioned: "{n} مستخدمين أُشير إليهم"
|
nUsersMentioned: "{n} مستخدمين أُشير إليهم"
|
||||||
securityKey: "مفتاح الأمان"
|
securityKey: "مفتاح الأمان"
|
||||||
securityKeyName: "اسم المفتاح"
|
securityKeyName: "اسم المفتاح"
|
||||||
@@ -813,6 +814,9 @@ colored: "ملوّن"
|
|||||||
label: "التسمية"
|
label: "التسمية"
|
||||||
localOnly: "المحلي فقط"
|
localOnly: "المحلي فقط"
|
||||||
account: "الحسابات"
|
account: "الحسابات"
|
||||||
|
cannotLoad: "تعذر التحميل"
|
||||||
|
like: "أعجبني"
|
||||||
|
show: "المظهر"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "هذا البريد الإلكتروني مستخدم"
|
used: "هذا البريد الإلكتروني مستخدم"
|
||||||
format: "صيغة البريد الإلكتروني غير صالحة"
|
format: "صيغة البريد الإلكتروني غير صالحة"
|
||||||
@@ -1228,6 +1232,11 @@ _timelines:
|
|||||||
local: "المحلي"
|
local: "المحلي"
|
||||||
social: "الاجتماعي"
|
social: "الاجتماعي"
|
||||||
global: "الشامل"
|
global: "الشامل"
|
||||||
|
_play:
|
||||||
|
viewSource: "اظهر المصدر"
|
||||||
|
featured: "الأكثر شعبية"
|
||||||
|
title: "العنوان"
|
||||||
|
summary: "الوصف"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "أنشئ صفحة جديدة"
|
newPage: "أنشئ صفحة جديدة"
|
||||||
editPage: "عدّل الصفحة"
|
editPage: "عدّل الصفحة"
|
||||||
@@ -1293,6 +1302,7 @@ _notification:
|
|||||||
yourFollowRequestAccepted: "قُبل طلب المتابعة"
|
yourFollowRequestAccepted: "قُبل طلب المتابعة"
|
||||||
youWereInvitedToGroup: "دُعيت إلى فريقٍ"
|
youWereInvitedToGroup: "دُعيت إلى فريقٍ"
|
||||||
pollEnded: "ظهرت نتائج الاستطلاع"
|
pollEnded: "ظهرت نتائج الاستطلاع"
|
||||||
|
unreadAntennaNote: "هوائي {name}"
|
||||||
_types:
|
_types:
|
||||||
all: "الكل"
|
all: "الكل"
|
||||||
follow: "متابِعون جدد"
|
follow: "متابِعون جدد"
|
||||||
|
@@ -851,6 +851,8 @@ colored: "রঙ্গিন"
|
|||||||
label: "লেবেল"
|
label: "লেবেল"
|
||||||
localOnly: "শুধুমাত্র লোকাল"
|
localOnly: "শুধুমাত্র লোকাল"
|
||||||
account: "অ্যাকাউন্টগুলি"
|
account: "অ্যাকাউন্টগুলি"
|
||||||
|
like: "পছন্দ করা"
|
||||||
|
show: "প্রদর্শন"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "এই ইমেইল ঠিকানাটি ইতোমধ্যে ব্যবহৃত হয়েছে"
|
used: "এই ইমেইল ঠিকানাটি ইতোমধ্যে ব্যবহৃত হয়েছে"
|
||||||
format: "এই ইমেল ঠিকানাটি সঠিকভাবে লিখা হয়নি"
|
format: "এই ইমেল ঠিকানাটি সঠিকভাবে লিখা হয়নি"
|
||||||
@@ -1319,6 +1321,12 @@ _timelines:
|
|||||||
local: "স্থানীয়"
|
local: "স্থানীয়"
|
||||||
social: "সামাজিক"
|
social: "সামাজিক"
|
||||||
global: "গ্লোবাল"
|
global: "গ্লোবাল"
|
||||||
|
_play:
|
||||||
|
viewSource: "উৎস দেখুন"
|
||||||
|
featured: "জনপ্রিয়"
|
||||||
|
title: "শিরোনাম"
|
||||||
|
script: "স্ক্রিপ্ট"
|
||||||
|
summary: "বর্ণনা"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "নতুন পৃষ্ঠা বানান"
|
newPage: "নতুন পৃষ্ঠা বানান"
|
||||||
editPage: "পৃষ্ঠাটি সম্পাদনা করুন"
|
editPage: "পৃষ্ঠাটি সম্পাদনা করুন"
|
||||||
|
@@ -610,6 +610,7 @@ speed: "Rychlost"
|
|||||||
slow: "Pomalá"
|
slow: "Pomalá"
|
||||||
fast: "Rychlá"
|
fast: "Rychlá"
|
||||||
account: "Účty"
|
account: "Účty"
|
||||||
|
show: "Zobrazit"
|
||||||
_ad:
|
_ad:
|
||||||
back: "Zpět"
|
back: "Zpět"
|
||||||
_gallery:
|
_gallery:
|
||||||
@@ -748,6 +749,9 @@ _charts:
|
|||||||
_timelines:
|
_timelines:
|
||||||
home: "Domů"
|
home: "Domů"
|
||||||
global: "Globální"
|
global: "Globální"
|
||||||
|
_play:
|
||||||
|
script: "Skript"
|
||||||
|
summary: "Popis"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Vytvořit novou stránku"
|
newPage: "Vytvořit novou stránku"
|
||||||
editPage: "Upravit stránku"
|
editPage: "Upravit stránku"
|
||||||
|
@@ -609,7 +609,7 @@ regexpErrorDescription: "Im regulären Ausdruck deiner {tab}en Wortstummschaltun
|
|||||||
instanceMute: "Instanzstummschaltungen"
|
instanceMute: "Instanzstummschaltungen"
|
||||||
userSaysSomething: "{name} hat etwas gesagt"
|
userSaysSomething: "{name} hat etwas gesagt"
|
||||||
makeActive: "Aktivieren"
|
makeActive: "Aktivieren"
|
||||||
display: "Anzeigeart"
|
display: "Anzeigen"
|
||||||
copy: "Kopieren"
|
copy: "Kopieren"
|
||||||
metrics: "Metriken"
|
metrics: "Metriken"
|
||||||
overview: "Übersicht"
|
overview: "Übersicht"
|
||||||
@@ -916,6 +916,14 @@ loggedInAsBot: "Momentan als Bot angemeldet"
|
|||||||
tools: "Werkzeuge"
|
tools: "Werkzeuge"
|
||||||
cannotLoad: "Kann nicht geladen werden"
|
cannotLoad: "Kann nicht geladen werden"
|
||||||
numberOfProfileView: "Profilaufrufe"
|
numberOfProfileView: "Profilaufrufe"
|
||||||
|
like: "Gefällt mir"
|
||||||
|
unlike: "\"Gefällt mir\" entfernen"
|
||||||
|
numberOfLikes: "\"Gefällt mir\"-Anzahl"
|
||||||
|
show: "Anzeigen"
|
||||||
|
neverShow: "Nicht wieder anzeigen"
|
||||||
|
remindMeLater: "Vielleicht später"
|
||||||
|
didYouLikeMisskey: "Gefällt dir Misskey?"
|
||||||
|
pleaseDonate: "Misskey ist die kostenlose Software, die von {host} verwendet wird. Wir würden uns über Spenden freuen, damit dessen Entwicklung weitergeführt werden kann!"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht."
|
description: "Ermöglicht eine Erleichterung der Servermoderation durch die automatische Erkennungen von NSFW-Medien unter Verwendung von Machine Learning. Hierdurch wird die Serverlast etwas erhöht."
|
||||||
sensitivity: "Erkennungssensitivität"
|
sensitivity: "Erkennungssensitivität"
|
||||||
@@ -1315,6 +1323,7 @@ _widgets:
|
|||||||
jobQueue: "Job-Warteschlange"
|
jobQueue: "Job-Warteschlange"
|
||||||
serverMetric: "Servermetriken"
|
serverMetric: "Servermetriken"
|
||||||
aiscript: "AiScript-Konsole"
|
aiscript: "AiScript-Konsole"
|
||||||
|
aiscriptApp: "AiScript-Anwendung"
|
||||||
aichan: "Ai"
|
aichan: "Ai"
|
||||||
userList: "Benutzerliste"
|
userList: "Benutzerliste"
|
||||||
_userList:
|
_userList:
|
||||||
@@ -1420,6 +1429,21 @@ _timelines:
|
|||||||
local: "Lokal"
|
local: "Lokal"
|
||||||
social: "Sozial"
|
social: "Sozial"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
|
_play:
|
||||||
|
new: "Play erstellen"
|
||||||
|
edit: "Play bearbeiten"
|
||||||
|
created: "Play erfolgreich erstellt"
|
||||||
|
updated: "Play erfolgreich aktualisiert"
|
||||||
|
deleted: "Play erfolgreich gelöscht"
|
||||||
|
pageSetting: "Play-Einstellungen"
|
||||||
|
editThisPage: "Dieses Play bearbeiten"
|
||||||
|
viewSource: "Quelltext anzeigen"
|
||||||
|
my: "Meine Plays"
|
||||||
|
liked: "Mit \"Gefällt mir\" markierte Plays"
|
||||||
|
featured: "Beliebt"
|
||||||
|
title: "Titel"
|
||||||
|
script: "Skript"
|
||||||
|
summary: "Beschreibung"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Seite erstellen"
|
newPage: "Seite erstellen"
|
||||||
editPage: "Seite bearbeiten"
|
editPage: "Seite bearbeiten"
|
||||||
|
@@ -916,6 +916,14 @@ loggedInAsBot: "Currently logged in as bot"
|
|||||||
tools: "Tools"
|
tools: "Tools"
|
||||||
cannotLoad: "Unable to load"
|
cannotLoad: "Unable to load"
|
||||||
numberOfProfileView: "Profile views"
|
numberOfProfileView: "Profile views"
|
||||||
|
like: "Like"
|
||||||
|
unlike: "Unlike"
|
||||||
|
numberOfLikes: "Likes"
|
||||||
|
show: "Show"
|
||||||
|
neverShow: "Don't show again"
|
||||||
|
remindMeLater: "Maybe later"
|
||||||
|
didYouLikeMisskey: "Have you taken a liking to Misskey?"
|
||||||
|
pleaseDonate: "{host} uses the free software, Misskey. We would highly appreciate your donations so development of Misskey can continue!"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
|
description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
|
||||||
sensitivity: "Detection sensitivity"
|
sensitivity: "Detection sensitivity"
|
||||||
@@ -1315,6 +1323,7 @@ _widgets:
|
|||||||
jobQueue: "Job Queue"
|
jobQueue: "Job Queue"
|
||||||
serverMetric: "Server metrics"
|
serverMetric: "Server metrics"
|
||||||
aiscript: "AiScript console"
|
aiscript: "AiScript console"
|
||||||
|
aiscriptApp: "AiScript App"
|
||||||
aichan: "Ai"
|
aichan: "Ai"
|
||||||
userList: "User list"
|
userList: "User list"
|
||||||
_userList:
|
_userList:
|
||||||
@@ -1420,6 +1429,21 @@ _timelines:
|
|||||||
local: "Local"
|
local: "Local"
|
||||||
social: "Social"
|
social: "Social"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
|
_play:
|
||||||
|
new: "Create Play"
|
||||||
|
edit: "Edit Play"
|
||||||
|
created: "Play created"
|
||||||
|
updated: "Play edited"
|
||||||
|
deleted: "Play deleted"
|
||||||
|
pageSetting: "Play settings"
|
||||||
|
editThisPage: "Edit this Play"
|
||||||
|
viewSource: "View source"
|
||||||
|
my: "My Plays"
|
||||||
|
liked: "Liked Plays"
|
||||||
|
featured: "Popular"
|
||||||
|
title: "Title"
|
||||||
|
script: "Script"
|
||||||
|
summary: "Description"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Create a new Page"
|
newPage: "Create a new Page"
|
||||||
editPage: "Edit this Page"
|
editPage: "Edit this Page"
|
||||||
|
@@ -916,6 +916,8 @@ loggedInAsBot: "Inicio sesión como cuenta bot."
|
|||||||
tools: "Utilidades"
|
tools: "Utilidades"
|
||||||
cannotLoad: "No se puede cargar."
|
cannotLoad: "No se puede cargar."
|
||||||
numberOfProfileView: "Número de vistas de perfil"
|
numberOfProfileView: "Número de vistas de perfil"
|
||||||
|
like: "¡Muy bien!"
|
||||||
|
show: "Apariencia"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor."
|
description: "Reduce el esfuerzo de la moderación el el servidor a través del reconocimiento automático de contenido NSFW usando 'Machine Learning'. Esto puede incrementar ligeramente la carga en el servidor."
|
||||||
sensitivity: "Sensibilidad de detección"
|
sensitivity: "Sensibilidad de detección"
|
||||||
@@ -1420,6 +1422,12 @@ _timelines:
|
|||||||
local: "Local"
|
local: "Local"
|
||||||
social: "Social"
|
social: "Social"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
|
_play:
|
||||||
|
viewSource: "Ver la fuente"
|
||||||
|
featured: "Popular"
|
||||||
|
title: "Título"
|
||||||
|
script: "Script"
|
||||||
|
summary: "Descripción"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Crear página"
|
newPage: "Crear página"
|
||||||
editPage: "Editar página"
|
editPage: "Editar página"
|
||||||
|
@@ -910,6 +910,8 @@ caption: "Libellé"
|
|||||||
loggedInAsBot: "Connecté actuellement en tant que bot"
|
loggedInAsBot: "Connecté actuellement en tant que bot"
|
||||||
tools: "Outils"
|
tools: "Outils"
|
||||||
cannotLoad: "Chargement impossible"
|
cannotLoad: "Chargement impossible"
|
||||||
|
like: "J'aime"
|
||||||
|
show: "Affichage"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement."
|
description: "L'apprentissage automatique peut être utilisé pour détecter automatiquement les médias sensibles à modérer. La sollicitation des serveurs augmente légèrement."
|
||||||
sensitivity: "Sensibilité de la détection"
|
sensitivity: "Sensibilité de la détection"
|
||||||
@@ -1411,6 +1413,12 @@ _timelines:
|
|||||||
local: "Local"
|
local: "Local"
|
||||||
social: "Social"
|
social: "Social"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
|
_play:
|
||||||
|
viewSource: "Afficher la source"
|
||||||
|
featured: "Populaire"
|
||||||
|
title: "Titre"
|
||||||
|
script: "Script"
|
||||||
|
summary: "Description"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Créer une page"
|
newPage: "Créer une page"
|
||||||
editPage: "Modifier une page"
|
editPage: "Modifier une page"
|
||||||
|
@@ -855,6 +855,10 @@ colored: "Diwarnai"
|
|||||||
label: "Label"
|
label: "Label"
|
||||||
localOnly: "Hanya lokal"
|
localOnly: "Hanya lokal"
|
||||||
account: "Akun"
|
account: "Akun"
|
||||||
|
like: "Suka"
|
||||||
|
unlike: "Tidak Suka"
|
||||||
|
numberOfLikes: "Jumlah yang disukai"
|
||||||
|
show: "Tampilkan"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "Alamat surel ini telah digunakan"
|
used: "Alamat surel ini telah digunakan"
|
||||||
format: "Format tidak valid."
|
format: "Format tidak valid."
|
||||||
@@ -1220,6 +1224,7 @@ _widgets:
|
|||||||
jobQueue: "Antrian kerja"
|
jobQueue: "Antrian kerja"
|
||||||
serverMetric: "Statistik peladen"
|
serverMetric: "Statistik peladen"
|
||||||
aiscript: "Konsol AiScript"
|
aiscript: "Konsol AiScript"
|
||||||
|
aiscriptApp: "Aplikasi AiScript"
|
||||||
aichan: "Ai"
|
aichan: "Ai"
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "Pilih daftar"
|
chooseList: "Pilih daftar"
|
||||||
@@ -1323,6 +1328,21 @@ _timelines:
|
|||||||
local: "Lokal"
|
local: "Lokal"
|
||||||
social: "Sosial"
|
social: "Sosial"
|
||||||
global: "Global"
|
global: "Global"
|
||||||
|
_play:
|
||||||
|
new: "Membuat Permainan"
|
||||||
|
edit: "Menyunting Permainan"
|
||||||
|
created: "Permainan sudah dibuat"
|
||||||
|
updated: "Permainan sudah diperbaharui"
|
||||||
|
deleted: "Hapus permainan"
|
||||||
|
pageSetting: "Pengaturan permainan"
|
||||||
|
editThisPage: "Sunting Permainan ini"
|
||||||
|
viewSource: "Lihat sumber"
|
||||||
|
my: "Permainan saya"
|
||||||
|
liked: "Permainan Disukai"
|
||||||
|
featured: "Populer"
|
||||||
|
title: "Judul"
|
||||||
|
script: "Script"
|
||||||
|
summary: "Deskripsi"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Buat halaman baru"
|
newPage: "Buat halaman baru"
|
||||||
editPage: "Sunting halaman"
|
editPage: "Sunting halaman"
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
_lang_: "Italiano"
|
_lang_: "Italiano"
|
||||||
headlineMisskey: "Rete collegata tramite note"
|
headlineMisskey: "Rete collegata tramite note"
|
||||||
introMisskey: "Benvenut@! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \nScrivi \"note\" per condividere ciò che sta succedendo adesso o per dire a tutti qualcosa di te. 📡\nGrazie alla funzione \"reazioni\" puoi anche mandare reazioni rapide alle note delle altre persone del Fediverso. 👍\nEsplora un nuovo mondo! 🚀"
|
introMisskey: "Eccoci! Misskey è un servizio di microblogging decentralizzato, libero e aperto. \n📡 Puoi pubblicare «Note» per condividere ciò che sta succedendo o per dire a tutti qualcosa su di te. \n👍 Puoi reagire inviando emoji rapidi alle «Note» provenienti da altri profili nel Fediverso.\n🚀 Esplora un nuovo mondo insieme a noi!"
|
||||||
poweredByMisskeyDescription: "{name} è uno dei servizi (chiamati istanze) che utilizzano la piattaforma open source <b>Misskey</b>."
|
poweredByMisskeyDescription: "{name} è uno dei servizi (chiamati istanze) che utilizzano la piattaforma open source <b>Misskey</b>."
|
||||||
monthAndDay: "{day}/{month}"
|
monthAndDay: "{day}/{month}"
|
||||||
search: "Cerca"
|
search: "Cerca"
|
||||||
@@ -28,7 +28,7 @@ timeline: "Timeline"
|
|||||||
noAccountDescription: "L'utente non ha ancora scritto niente nella biografia di profilo."
|
noAccountDescription: "L'utente non ha ancora scritto niente nella biografia di profilo."
|
||||||
login: "Accedi"
|
login: "Accedi"
|
||||||
loggingIn: "Accesso in corso..."
|
loggingIn: "Accesso in corso..."
|
||||||
logout: "Esci"
|
logout: "Uscita"
|
||||||
signup: "Iscriviti"
|
signup: "Iscriviti"
|
||||||
uploading: "Caricamento..."
|
uploading: "Caricamento..."
|
||||||
save: "Salva"
|
save: "Salva"
|
||||||
@@ -876,7 +876,7 @@ deleteAccount: "Eliminazione profilo"
|
|||||||
document: "Documento"
|
document: "Documento"
|
||||||
numberOfPageCache: "Numero di pagine cache"
|
numberOfPageCache: "Numero di pagine cache"
|
||||||
numberOfPageCacheDescription: "Aumenta l'usabilità, ma aumenta anche il carico e l'utilizzo della memoria."
|
numberOfPageCacheDescription: "Aumenta l'usabilità, ma aumenta anche il carico e l'utilizzo della memoria."
|
||||||
logoutConfirm: "Sei sicuro di voler effettuare il logout?"
|
logoutConfirm: "Vuoi davvero uscire da Misskey? "
|
||||||
lastActiveDate: "Data dell'ultimo utilizzo"
|
lastActiveDate: "Data dell'ultimo utilizzo"
|
||||||
statusbar: "Barra di stato"
|
statusbar: "Barra di stato"
|
||||||
pleaseSelect: "Scegli un'opzione"
|
pleaseSelect: "Scegli un'opzione"
|
||||||
@@ -916,6 +916,8 @@ loggedInAsBot: "Connessione come Bot"
|
|||||||
tools: "Strumenti"
|
tools: "Strumenti"
|
||||||
cannotLoad: "Caricamento impossibile"
|
cannotLoad: "Caricamento impossibile"
|
||||||
numberOfProfileView: "Visualizzazioni profilo"
|
numberOfProfileView: "Visualizzazioni profilo"
|
||||||
|
like: "Mi piace!"
|
||||||
|
show: "Visualizza"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "L'apprendimento automatico può essere utilizzato per individuare automaticamente i media sensibili da moderare. Il carico del server aumenta leggermente."
|
description: "L'apprendimento automatico può essere utilizzato per individuare automaticamente i media sensibili da moderare. Il carico del server aumenta leggermente."
|
||||||
sensitivity: "Sensibilità di rilevamento"
|
sensitivity: "Sensibilità di rilevamento"
|
||||||
@@ -1067,7 +1069,7 @@ _mfm:
|
|||||||
sparkleDescription: "Aggiungere effetti particellari scintillanti."
|
sparkleDescription: "Aggiungere effetti particellari scintillanti."
|
||||||
rotate: "Ruota"
|
rotate: "Ruota"
|
||||||
rotateDescription: "Ruota con un angolo specificato."
|
rotateDescription: "Ruota con un angolo specificato."
|
||||||
plain: "aereo"
|
plain: "Testo semplice"
|
||||||
plainDescription: "Disattiva tutta la sintassi interna."
|
plainDescription: "Disattiva tutta la sintassi interna."
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "Nascondi"
|
none: "Nascondi"
|
||||||
@@ -1205,13 +1207,13 @@ _time:
|
|||||||
day: "giorni"
|
day: "giorni"
|
||||||
_tutorial:
|
_tutorial:
|
||||||
title: "Come usare Misskey"
|
title: "Come usare Misskey"
|
||||||
step1_1: "Benvenuto/a!"
|
step1_1: "Eccoci!"
|
||||||
step1_2: "Questa pagina si chiama una \" Timeline \". Mostra in ordine cronologico le \" note \" delle persone che segui."
|
step1_2: "Questa pagina si chiama una \" Timeline \". Mostra in ordine cronologico le \" note \" delle persone che segui."
|
||||||
step1_3: "Attualmente la tua Timeline è vuota perché non segui alcun profilo e non hai pubblicato alcuna nota ancora."
|
step1_3: "Attualmente la tua Timeline è vuota perché non segui alcun profilo e non hai pubblicato alcuna nota ancora."
|
||||||
step2_1: "Prima di scrivere una nota o di seguire altri profili, imposta il tuo di profilo!"
|
step2_1: "Prima di scrivere una «Nota» o di seguire altri profili, prepara il tuo profilo!"
|
||||||
step2_2: "Aggiungere qualche informazione su di te aumenterà le tue possibilità di essere seguit@ da altre persone. "
|
step2_2: "Aggiungere qualche informazione su di te aumenterà le tue possibilità di essere seguit@ da altre persone. "
|
||||||
step3_1: "Hai finito di impostare il tuo profilo?"
|
step3_1: "Hai finito di impostare il tuo profilo?"
|
||||||
step3_2: "Ora, puoi pubblicare una nota. Facciamo una prova! Premi il pulsante a forma di penna in cima allo schermo per aprire una finestra di dialogo. "
|
step3_2: "Ora puoi pubblicare una «Nota». Proviamo subito! Premi il bottone con l'icona «penna» per iniziare a scrivere in una finestra di dialogo. "
|
||||||
step3_3: "Scritto il testo della nota, puoi pubblicarla premendo il pulsante nella parte superiore destra della finestra di dialogo."
|
step3_3: "Scritto il testo della nota, puoi pubblicarla premendo il pulsante nella parte superiore destra della finestra di dialogo."
|
||||||
step3_4: "Non ti viene niente in mente? Perché non scrivi semplicemente \"Ho appena cominciato a usare Misskey\"?"
|
step3_4: "Non ti viene niente in mente? Perché non scrivi semplicemente \"Ho appena cominciato a usare Misskey\"?"
|
||||||
step4_1: "Hai pubblicato qualcosa?"
|
step4_1: "Hai pubblicato qualcosa?"
|
||||||
@@ -1223,7 +1225,7 @@ _tutorial:
|
|||||||
step6_1: "Adesso, dovresti essere in grado di vedere le note dagli altri profili sulla tua timeline."
|
step6_1: "Adesso, dovresti essere in grado di vedere le note dagli altri profili sulla tua timeline."
|
||||||
step6_2: "Puoi anche rispondere alle note con un click, scegliendo le reazioni immediate."
|
step6_2: "Puoi anche rispondere alle note con un click, scegliendo le reazioni immediate."
|
||||||
step6_3: "Per inviare una reazione, premi l'icona + della nota e scegli l'emoji che vuoi mandare."
|
step6_3: "Per inviare una reazione, premi l'icona + della nota e scegli l'emoji che vuoi mandare."
|
||||||
step7_1: "Complimenti! Sei arrivat@ alla fine dell'esercitazione di base su come usare Misskey. "
|
step7_1: "Congratulazioni! Hai completato l'esercitazione iniziale su come usare Misskey."
|
||||||
step7_2: "Se vuoi saperne di più su Misskey, puoi dare un'occhiata alla sezione {help}."
|
step7_2: "Se vuoi saperne di più su Misskey, puoi dare un'occhiata alla sezione {help}."
|
||||||
step7_3: "Da ultimo, buon divertimento su Misskey! 🚀"
|
step7_3: "Da ultimo, buon divertimento su Misskey! 🚀"
|
||||||
step8_1: "Per concludere, vuoi attivare le notifiche push?"
|
step8_1: "Per concludere, vuoi attivare le notifiche push?"
|
||||||
@@ -1315,7 +1317,7 @@ _widgets:
|
|||||||
jobQueue: "Coda di lavoro"
|
jobQueue: "Coda di lavoro"
|
||||||
serverMetric: "Statistiche server"
|
serverMetric: "Statistiche server"
|
||||||
aiscript: "Console AiScript"
|
aiscript: "Console AiScript"
|
||||||
aichan: "indaco (tintura)"
|
aichan: "Mascotte Ai"
|
||||||
userList: "Elenco utenti"
|
userList: "Elenco utenti"
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "Seleziona una lista"
|
chooseList: "Seleziona una lista"
|
||||||
@@ -1420,6 +1422,12 @@ _timelines:
|
|||||||
local: "Locale"
|
local: "Locale"
|
||||||
social: "Sociale"
|
social: "Sociale"
|
||||||
global: "Federata"
|
global: "Federata"
|
||||||
|
_play:
|
||||||
|
viewSource: "Visualizza sorgente"
|
||||||
|
featured: "Popolari"
|
||||||
|
title: "Titolo"
|
||||||
|
script: "Script"
|
||||||
|
summary: "Descrizione"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Crea pagina"
|
newPage: "Crea pagina"
|
||||||
editPage: "Modifica pagina"
|
editPage: "Modifica pagina"
|
||||||
|
@@ -920,6 +920,10 @@ like: "いいね!"
|
|||||||
unlike: "いいねを解除"
|
unlike: "いいねを解除"
|
||||||
numberOfLikes: "いいね数"
|
numberOfLikes: "いいね数"
|
||||||
show: "表示"
|
show: "表示"
|
||||||
|
neverShow: "今後表示しない"
|
||||||
|
remindMeLater: "また後で"
|
||||||
|
didYouLikeMisskey: "Misskeyを気に入っていただけましたか?"
|
||||||
|
pleaseDonate: "Misskeyは{host}が使用している無料のソフトウェアです。これからも開発を続けられるように、ぜひ寄付をお願いします!"
|
||||||
|
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"
|
description: "機械学習を使って自動でセンシティブなメディアを検出し、モデレーションに役立てることができます。サーバーの負荷が少し増えます。"
|
||||||
@@ -1357,6 +1361,7 @@ _widgets:
|
|||||||
userList: "ユーザーリスト"
|
userList: "ユーザーリスト"
|
||||||
_userList:
|
_userList:
|
||||||
chooseList: "リストを選択"
|
chooseList: "リストを選択"
|
||||||
|
clicker: "クリッカー"
|
||||||
|
|
||||||
_cw:
|
_cw:
|
||||||
hide: "隠す"
|
hide: "隠す"
|
||||||
@@ -1546,7 +1551,6 @@ _notification:
|
|||||||
youGotReply: "{name}からのリプライ"
|
youGotReply: "{name}からのリプライ"
|
||||||
youGotQuote: "{name}による引用"
|
youGotQuote: "{name}による引用"
|
||||||
youRenoted: "{name}がRenoteしました"
|
youRenoted: "{name}がRenoteしました"
|
||||||
youGotPoll: "{name}が投票しました"
|
|
||||||
youGotMessagingMessageFromUser: "{name}からのチャットがあります"
|
youGotMessagingMessageFromUser: "{name}からのチャットがあります"
|
||||||
youGotMessagingMessageFromGroup: "{name}のチャットがあります"
|
youGotMessagingMessageFromGroup: "{name}のチャットがあります"
|
||||||
youWereFollowed: "フォローされました"
|
youWereFollowed: "フォローされました"
|
||||||
@@ -1565,7 +1569,6 @@ _notification:
|
|||||||
renote: "Renote"
|
renote: "Renote"
|
||||||
quote: "引用"
|
quote: "引用"
|
||||||
reaction: "リアクション"
|
reaction: "リアクション"
|
||||||
pollVote: "アンケートに投票された"
|
|
||||||
pollEnded: "アンケートが終了"
|
pollEnded: "アンケートが終了"
|
||||||
receiveFollowRequest: "フォロー申請を受け取った"
|
receiveFollowRequest: "フォロー申請を受け取った"
|
||||||
followRequestAccepted: "フォローが受理された"
|
followRequestAccepted: "フォローが受理された"
|
||||||
|
@@ -915,6 +915,8 @@ caption: "キャプション"
|
|||||||
loggedInAsBot: "Botアカウントでログイン中やで"
|
loggedInAsBot: "Botアカウントでログイン中やで"
|
||||||
tools: "ツール"
|
tools: "ツール"
|
||||||
cannotLoad: "読み込めへんで"
|
cannotLoad: "読み込めへんで"
|
||||||
|
like: "ええやん!"
|
||||||
|
show: "表示"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "機械学習を使って自動でセンシティブなメディアを検出して、モデレーションに役立てることができるで。サーバーの負荷が少し増えてまうなあ。"
|
description: "機械学習を使って自動でセンシティブなメディアを検出して、モデレーションに役立てることができるで。サーバーの負荷が少し増えてまうなあ。"
|
||||||
sensitivity: "検出感度やで"
|
sensitivity: "検出感度やで"
|
||||||
@@ -1418,6 +1420,12 @@ _timelines:
|
|||||||
local: "ローカル"
|
local: "ローカル"
|
||||||
social: "ソーシャル"
|
social: "ソーシャル"
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
|
_play:
|
||||||
|
viewSource: "ソースを表示"
|
||||||
|
featured: "人気"
|
||||||
|
title: "タイトル"
|
||||||
|
script: "スクリプト"
|
||||||
|
summary: "説明"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "ページを作る"
|
newPage: "ページを作る"
|
||||||
editPage: "ページの編集"
|
editPage: "ページの編集"
|
||||||
|
@@ -916,6 +916,14 @@ loggedInAsBot: "봇 계정으로 로그인중"
|
|||||||
tools: "도구"
|
tools: "도구"
|
||||||
cannotLoad: "불러오지 못했습니다"
|
cannotLoad: "불러오지 못했습니다"
|
||||||
numberOfProfileView: "프로필 뷰 수"
|
numberOfProfileView: "프로필 뷰 수"
|
||||||
|
like: "좋아요!"
|
||||||
|
unlike: "좋아요 취소"
|
||||||
|
numberOfLikes: "좋아요 수"
|
||||||
|
show: "표시"
|
||||||
|
neverShow: "다시 보지 않기"
|
||||||
|
remindMeLater: "나중에 알림"
|
||||||
|
didYouLikeMisskey: "Misskey가 마음에 드시나요?"
|
||||||
|
pleaseDonate: "{host}은(는) 무료 소프트웨어 Misskey를 사용합니다. 후원을 통해 저희의 개발이 이어질 수 있게 도와주세요!"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "기계학습을 통해 자동으로 민감한 미디어를 탐지하여, 모더레이션에 참고할 수 있도록 합니다. 서버의 부하를 약간 증가시킵니다."
|
description: "기계학습을 통해 자동으로 민감한 미디어를 탐지하여, 모더레이션에 참고할 수 있도록 합니다. 서버의 부하를 약간 증가시킵니다."
|
||||||
sensitivity: "탐지 민감도"
|
sensitivity: "탐지 민감도"
|
||||||
@@ -1315,6 +1323,7 @@ _widgets:
|
|||||||
jobQueue: "작업 대기열"
|
jobQueue: "작업 대기열"
|
||||||
serverMetric: "서버 통계"
|
serverMetric: "서버 통계"
|
||||||
aiscript: "AiScript 콘솔"
|
aiscript: "AiScript 콘솔"
|
||||||
|
aiscriptApp: "AiScript 앱"
|
||||||
aichan: "아이"
|
aichan: "아이"
|
||||||
userList: "사용자 목록"
|
userList: "사용자 목록"
|
||||||
_userList:
|
_userList:
|
||||||
@@ -1420,6 +1429,21 @@ _timelines:
|
|||||||
local: "로컬"
|
local: "로컬"
|
||||||
social: "소셜"
|
social: "소셜"
|
||||||
global: "글로벌"
|
global: "글로벌"
|
||||||
|
_play:
|
||||||
|
new: "Play 만들기"
|
||||||
|
edit: "Play 수정하기"
|
||||||
|
created: "Play를 생성했습니다"
|
||||||
|
updated: "Play를 갱신했습니다"
|
||||||
|
deleted: "Play를 삭제했습니다"
|
||||||
|
pageSetting: "Play 설정"
|
||||||
|
editThisPage: "이 Play를 수정"
|
||||||
|
viewSource: "소스 보기"
|
||||||
|
my: "나의 Play"
|
||||||
|
liked: "좋아요 한 Play"
|
||||||
|
featured: "인기"
|
||||||
|
title: "제목"
|
||||||
|
script: "스크립트"
|
||||||
|
summary: "설명"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "페이지 만들기"
|
newPage: "페이지 만들기"
|
||||||
editPage: "페이지 수정"
|
editPage: "페이지 수정"
|
||||||
|
@@ -866,6 +866,8 @@ pushNotificationNotSupported: "Przeglądarka lub instancja nie obsługuje powiad
|
|||||||
sendPushNotificationReadMessage: "Usuń powiadomienia push po przeczytaniu powiadomień i wiadomości."
|
sendPushNotificationReadMessage: "Usuń powiadomienia push po przeczytaniu powiadomień i wiadomości."
|
||||||
sendPushNotificationReadMessageCaption: "Chwilowo pojawi się powiadomienie \"{emptyPushNotificationMessage}\". Może wzrosnąć zużycie baterii urządzenia."
|
sendPushNotificationReadMessageCaption: "Chwilowo pojawi się powiadomienie \"{emptyPushNotificationMessage}\". Może wzrosnąć zużycie baterii urządzenia."
|
||||||
loggedInAsBot: "Jesteś obecnie zalogowany/a jako bot"
|
loggedInAsBot: "Jesteś obecnie zalogowany/a jako bot"
|
||||||
|
like: "Polub"
|
||||||
|
show: "Wyświetlanie"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie zwiększy obciążenie serwera."
|
description: "Zmniejsza wysiłek związany z moderacją serwera dzięki automatycznemu rozpoznawaniu zawartości NSFW za pomocą uczenia maszynowego. To nieznacznie zwiększy obciążenie serwera."
|
||||||
setSensitiveFlagAutomatically: "Oznacz jako NSFW"
|
setSensitiveFlagAutomatically: "Oznacz jako NSFW"
|
||||||
@@ -1313,6 +1315,12 @@ _timelines:
|
|||||||
local: "Lokalne"
|
local: "Lokalne"
|
||||||
social: "Społeczność"
|
social: "Społeczność"
|
||||||
global: "Globalna"
|
global: "Globalna"
|
||||||
|
_play:
|
||||||
|
viewSource: "Zobacz źródło"
|
||||||
|
featured: "Wyróżnione"
|
||||||
|
title: "Tytuł"
|
||||||
|
script: "Skrypt"
|
||||||
|
summary: "Opis"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Utwórz stronę"
|
newPage: "Utwórz stronę"
|
||||||
editPage: "Edytuj tę stronę"
|
editPage: "Edytuj tę stronę"
|
||||||
|
@@ -647,6 +647,7 @@ middle: "Mediu"
|
|||||||
sent: "Trimite"
|
sent: "Trimite"
|
||||||
searchByGoogle: "Caută"
|
searchByGoogle: "Caută"
|
||||||
file: "Fișiere"
|
file: "Fișiere"
|
||||||
|
show: "Arată"
|
||||||
_email:
|
_email:
|
||||||
_follow:
|
_follow:
|
||||||
title: "te-a urmărit"
|
title: "te-a urmărit"
|
||||||
@@ -690,6 +691,9 @@ _charts:
|
|||||||
federation: "Federație"
|
federation: "Federație"
|
||||||
_timelines:
|
_timelines:
|
||||||
home: "Acasă"
|
home: "Acasă"
|
||||||
|
_play:
|
||||||
|
script: "Script"
|
||||||
|
summary: "Descriere"
|
||||||
_pages:
|
_pages:
|
||||||
blocks:
|
blocks:
|
||||||
image: "Imagini"
|
image: "Imagini"
|
||||||
|
@@ -864,6 +864,8 @@ enableAutoSensitiveDescription: "Если доступно, используйт
|
|||||||
account: "Учётные записи"
|
account: "Учётные записи"
|
||||||
windowMaximize: "Развернуть"
|
windowMaximize: "Развернуть"
|
||||||
windowRestore: "Восстановить"
|
windowRestore: "Восстановить"
|
||||||
|
like: "Нравится!"
|
||||||
|
show: "Отображение"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно."
|
description: "Машинное обучение может быть использовано для автоматического обнаружения чувствительных медиа для модерации. Нагрузка на сервер увеличивается незначительно."
|
||||||
setSensitiveFlagAutomatically: "Установить флаг NSFW"
|
setSensitiveFlagAutomatically: "Установить флаг NSFW"
|
||||||
@@ -1332,6 +1334,12 @@ _timelines:
|
|||||||
local: "Местная"
|
local: "Местная"
|
||||||
social: "Социальная"
|
social: "Социальная"
|
||||||
global: "Всеобщая"
|
global: "Всеобщая"
|
||||||
|
_play:
|
||||||
|
viewSource: "Просмотр исходника"
|
||||||
|
featured: "Популярные"
|
||||||
|
title: "Заголовок"
|
||||||
|
script: "Скрипт"
|
||||||
|
summary: "Описание"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Создать страницу"
|
newPage: "Создать страницу"
|
||||||
editPage: "Править страницу"
|
editPage: "Править страницу"
|
||||||
|
@@ -911,6 +911,12 @@ windowRestore: "Obnoviť"
|
|||||||
caption: "Nadpis"
|
caption: "Nadpis"
|
||||||
tools: "Nástroje"
|
tools: "Nástroje"
|
||||||
cannotLoad: "Nedá sa načítať."
|
cannotLoad: "Nedá sa načítať."
|
||||||
|
like: "Páči sa mi"
|
||||||
|
show: "Zobraziť"
|
||||||
|
neverShow: "Nabudúce nezobrazovať"
|
||||||
|
remindMeLater: "Pripomenúť neskôr"
|
||||||
|
didYouLikeMisskey: "Páči sa vám Misskey?"
|
||||||
|
pleaseDonate: "Misskey je bezplatný softvér, ktorý používa {host}. Prosím, prispejte, aby sme ho mohli ďalej rozvíjať!"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Strojové učenie sa použije na automatickú detekciu citlivých médií na účely ich moderovania. Mierne sa zvýši zaťaženie servera."
|
description: "Strojové učenie sa použije na automatickú detekciu citlivých médií na účely ich moderovania. Mierne sa zvýši zaťaženie servera."
|
||||||
sensitivity: "Citlivosť detekcie"
|
sensitivity: "Citlivosť detekcie"
|
||||||
@@ -1413,6 +1419,12 @@ _timelines:
|
|||||||
local: "Lokálne"
|
local: "Lokálne"
|
||||||
social: "Sociálne"
|
social: "Sociálne"
|
||||||
global: "Globálne"
|
global: "Globálne"
|
||||||
|
_play:
|
||||||
|
viewSource: "Ukázať zdroj"
|
||||||
|
featured: "Význačné"
|
||||||
|
title: "Nadpis"
|
||||||
|
script: "Skript"
|
||||||
|
summary: "Popis"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Vytvoriť novú stránku"
|
newPage: "Vytvoriť novú stránku"
|
||||||
editPage: "Upraviť túto stránku"
|
editPage: "Upraviť túto stránku"
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
_lang_: "Svenska"
|
_lang_: "Svenska"
|
||||||
headlineMisskey: "Ett nätverk kopplat av noter"
|
headlineMisskey: "Ett nätverk kopplat av noter"
|
||||||
introMisskey: "Välkommen! Misskey är en öppen och decentraliserad mikrobloggningstjänst.\nSkapa en \"not\" och dela dina tankar med alla runtomkring dig. 📡\nMed \"reaktioner\" kan du snabbt uttrycka dina känslor kring andras noter.👍\nLåt oss utforska en nya värld!🚀"
|
introMisskey: "Välkommen! Misskey är en öppen och decentraliserad mikrobloggningstjänst.\nSkapa en \"not\" och dela dina tankar med alla runtomkring dig. 📡\nMed \"reaktioner\" kan du snabbt uttrycka dina känslor kring andras noter.👍\nLåt oss utforska en nya värld!🚀"
|
||||||
|
poweredByMisskeyDescription: "{name} är en tjänst driven av den öppna källkodsplatformen <b>Misskey</b> (benämns \"Misskey instans\")."
|
||||||
monthAndDay: "{day}/{month}"
|
monthAndDay: "{day}/{month}"
|
||||||
search: "Sök"
|
search: "Sök"
|
||||||
notifications: "Notifikationer"
|
notifications: "Notifikationer"
|
||||||
@@ -12,6 +13,7 @@ fetchingAsApObject: "Hämtar från Fediversum..."
|
|||||||
ok: "OK"
|
ok: "OK"
|
||||||
gotIt: "Uppfattat!"
|
gotIt: "Uppfattat!"
|
||||||
cancel: "Avbryt"
|
cancel: "Avbryt"
|
||||||
|
noThankYou: "Nej tack"
|
||||||
enterUsername: "Ange användarnamn"
|
enterUsername: "Ange användarnamn"
|
||||||
renotedBy: "Omnoterad av {user}"
|
renotedBy: "Omnoterad av {user}"
|
||||||
noNotes: "Inga noteringar"
|
noNotes: "Inga noteringar"
|
||||||
@@ -47,11 +49,13 @@ deleteAndEdit: "Radera och ändra"
|
|||||||
deleteAndEditConfirm: "Är du säker att du vill radera denna not och ändra den? Du kommer förlora alla reaktioner, omnoteringar och svar till den."
|
deleteAndEditConfirm: "Är du säker att du vill radera denna not och ändra den? Du kommer förlora alla reaktioner, omnoteringar och svar till den."
|
||||||
addToList: "Lägg till i lista"
|
addToList: "Lägg till i lista"
|
||||||
sendMessage: "Skicka ett meddelande"
|
sendMessage: "Skicka ett meddelande"
|
||||||
|
copyRSS: "Kopiera RSS"
|
||||||
copyUsername: "Kopiera användarnamn"
|
copyUsername: "Kopiera användarnamn"
|
||||||
searchUser: "Sök användare"
|
searchUser: "Sök användare"
|
||||||
reply: "Svara"
|
reply: "Svara"
|
||||||
loadMore: "Ladda mer"
|
loadMore: "Ladda mer"
|
||||||
showMore: "Visa mer"
|
showMore: "Visa mer"
|
||||||
|
showLess: "Stäng"
|
||||||
youGotNewFollower: "följde dig"
|
youGotNewFollower: "följde dig"
|
||||||
receiveFollowRequest: "Följarförfrågan mottagen"
|
receiveFollowRequest: "Följarförfrågan mottagen"
|
||||||
followRequestAccepted: "Följarförfrågan accepterad"
|
followRequestAccepted: "Följarförfrågan accepterad"
|
||||||
@@ -238,6 +242,17 @@ saved: "Sparad"
|
|||||||
messaging: "Chatt"
|
messaging: "Chatt"
|
||||||
upload: "Ladda upp"
|
upload: "Ladda upp"
|
||||||
keepOriginalUploading: "Behåll originalbild"
|
keepOriginalUploading: "Behåll originalbild"
|
||||||
|
keepOriginalUploadingDescription: "Sparar den originellt uppladdade bilden i sitt i befintliga skick. Om avstängd, kommer en webbversion bli genererad vid uppladdning."
|
||||||
|
fromDrive: "Från Drive"
|
||||||
|
fromUrl: "Från en länk"
|
||||||
|
uploadFromUrl: "Ladda upp från länk"
|
||||||
|
uploadFromUrlDescription: "Länken av filen du vill ladda upp"
|
||||||
|
uploadFromUrlRequested: "Uppladdning begärd"
|
||||||
|
uploadFromUrlMayTakeTime: "Det kan ta tid tills att uppladdningen blir klar."
|
||||||
|
explore: "Utforska"
|
||||||
|
messageRead: "Läs"
|
||||||
|
noMoreHistory: "Det finns ingen mer historik"
|
||||||
|
startMessaging: "Starta en chatt"
|
||||||
nsfw: "Känsligt innehåll"
|
nsfw: "Känsligt innehåll"
|
||||||
pinnedNotes: "Fästad not"
|
pinnedNotes: "Fästad not"
|
||||||
userList: "Listor"
|
userList: "Listor"
|
||||||
|
@@ -916,6 +916,10 @@ loggedInAsBot: "ล็อกอินเป็นบอตอยู่ในข
|
|||||||
tools: "เครื่องมือ"
|
tools: "เครื่องมือ"
|
||||||
cannotLoad: "ไม่สามารถโหลดได้"
|
cannotLoad: "ไม่สามารถโหลดได้"
|
||||||
numberOfProfileView: "มุมมองโปรไฟล์"
|
numberOfProfileView: "มุมมองโปรไฟล์"
|
||||||
|
like: "ชื่นชอบ"
|
||||||
|
unlike: "ไม่ชอบ"
|
||||||
|
numberOfLikes: "จำนวนไลค์"
|
||||||
|
show: "แสดงผล"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "ลดความพยายามในการดูแลเซิร์ฟเวอร์ผ่านการจดจำสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่อง การทำสิ่งนี้อาจจะเพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย"
|
description: "ลดความพยายามในการดูแลเซิร์ฟเวอร์ผ่านการจดจำสื่อ NSFW โดยอัตโนมัติผ่านการเรียนรู้ของเครื่อง การทำสิ่งนี้อาจจะเพิ่มภาระบนเซิร์ฟเวอร์เล็กน้อย"
|
||||||
sensitivity: "การตรวจจับความไว"
|
sensitivity: "การตรวจจับความไว"
|
||||||
@@ -1315,6 +1319,7 @@ _widgets:
|
|||||||
jobQueue: "คิวงาน"
|
jobQueue: "คิวงาน"
|
||||||
serverMetric: "ตัวชี้วัดเซิร์ฟเวอร์"
|
serverMetric: "ตัวชี้วัดเซิร์ฟเวอร์"
|
||||||
aiscript: "AiScript คอนโซล"
|
aiscript: "AiScript คอนโซล"
|
||||||
|
aiscriptApp: "AiScript แอพ"
|
||||||
aichan: "เอไอ"
|
aichan: "เอไอ"
|
||||||
userList: "รายชื่อผู้ใช้"
|
userList: "รายชื่อผู้ใช้"
|
||||||
_userList:
|
_userList:
|
||||||
@@ -1420,6 +1425,21 @@ _timelines:
|
|||||||
local: "ในพื้นที่"
|
local: "ในพื้นที่"
|
||||||
social: "โซเชี่ยล"
|
social: "โซเชี่ยล"
|
||||||
global: "ทั่วโลก"
|
global: "ทั่วโลก"
|
||||||
|
_play:
|
||||||
|
new: "สร้างการเล่น"
|
||||||
|
edit: "แก้ไขเล่น"
|
||||||
|
created: "สร้างการเล่นแล้ว"
|
||||||
|
updated: "แก้ไขการเล่นแล้ว"
|
||||||
|
deleted: "ลบการเล่นแล้ว"
|
||||||
|
pageSetting: "ตั้งค่าการเล่น"
|
||||||
|
editThisPage: "แก้ไข Play นี้"
|
||||||
|
viewSource: "ดูต้นฉบับ"
|
||||||
|
my: "มาย เพลย์"
|
||||||
|
liked: "ไลค์ เพลย์"
|
||||||
|
featured: "เป็นที่นิยม"
|
||||||
|
title: "หัวข้อ"
|
||||||
|
script: "สคริปต์"
|
||||||
|
summary: "รายละเอียด"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "สร้างหน้าเพจใหม่"
|
newPage: "สร้างหน้าเพจใหม่"
|
||||||
editPage: "แก้ไขหน้าเพจ"
|
editPage: "แก้ไขหน้าเพจ"
|
||||||
|
@@ -892,6 +892,8 @@ unsubscribePushNotification: "Вимкнути push-сповіщення"
|
|||||||
windowMaximize: "Розгорнути"
|
windowMaximize: "Розгорнути"
|
||||||
windowRestore: "Відновити"
|
windowRestore: "Відновити"
|
||||||
caption: "Підпис"
|
caption: "Підпис"
|
||||||
|
like: "Вподобати"
|
||||||
|
show: "Відображення"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
sensitivity: "Чутливість детектування"
|
sensitivity: "Чутливість детектування"
|
||||||
setSensitiveFlagAutomatically: "Позначити як NSFW"
|
setSensitiveFlagAutomatically: "Позначити як NSFW"
|
||||||
@@ -1348,6 +1350,12 @@ _timelines:
|
|||||||
local: "Локальна"
|
local: "Локальна"
|
||||||
social: "Соціальна"
|
social: "Соціальна"
|
||||||
global: "Глобальна"
|
global: "Глобальна"
|
||||||
|
_play:
|
||||||
|
viewSource: "Переглянути вихідний код"
|
||||||
|
featured: "Популярні"
|
||||||
|
title: "Заголовок"
|
||||||
|
script: "Скрипт"
|
||||||
|
summary: "Опис"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Створити сторінку"
|
newPage: "Створити сторінку"
|
||||||
editPage: "Редагувати сторінку"
|
editPage: "Редагувати сторінку"
|
||||||
|
@@ -894,6 +894,8 @@ navbar: "Thanh điều hướng"
|
|||||||
shuffle: "Xáo trộn"
|
shuffle: "Xáo trộn"
|
||||||
account: "Tài khoản của bạn"
|
account: "Tài khoản của bạn"
|
||||||
move: "Di chuyển"
|
move: "Di chuyển"
|
||||||
|
like: "Thích"
|
||||||
|
show: "Hiển thị"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "Giảm nỗ lực kiểm duyệt máy chủ thông qua việc tự động nhận dạng media NSFW thông qua học máy. Điều này sẽ làm tăng một chút áp lực trên máy chủ."
|
description: "Giảm nỗ lực kiểm duyệt máy chủ thông qua việc tự động nhận dạng media NSFW thông qua học máy. Điều này sẽ làm tăng một chút áp lực trên máy chủ."
|
||||||
sensitivity: "Phát hiện nhạy cảm"
|
sensitivity: "Phát hiện nhạy cảm"
|
||||||
@@ -1393,6 +1395,12 @@ _timelines:
|
|||||||
local: "Máy chủ này"
|
local: "Máy chủ này"
|
||||||
social: "Xã hội"
|
social: "Xã hội"
|
||||||
global: "Liên hợp"
|
global: "Liên hợp"
|
||||||
|
_play:
|
||||||
|
viewSource: "Xem mã nguồn"
|
||||||
|
featured: "Nổi tiếng"
|
||||||
|
title: "Tựa đề"
|
||||||
|
script: "Kịch bản"
|
||||||
|
summary: "Mô tả"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "Tạo Trang mới"
|
newPage: "Tạo Trang mới"
|
||||||
editPage: "Sửa Trang này"
|
editPage: "Sửa Trang này"
|
||||||
|
@@ -916,6 +916,10 @@ loggedInAsBot: "以Bot账户登录"
|
|||||||
tools: "工具"
|
tools: "工具"
|
||||||
cannotLoad: "无法加载"
|
cannotLoad: "无法加载"
|
||||||
numberOfProfileView: "个人资料展示次数"
|
numberOfProfileView: "个人资料展示次数"
|
||||||
|
like: "点赞!"
|
||||||
|
unlike: "取消赞"
|
||||||
|
numberOfLikes: "点赞数"
|
||||||
|
show: "显示"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。"
|
description: "可以使用机器学习技术自动检测敏感媒体,以便进行审核。服务器负载将略微增加。"
|
||||||
sensitivity: "检测敏感度"
|
sensitivity: "检测敏感度"
|
||||||
@@ -1049,8 +1053,8 @@ _mfm:
|
|||||||
shakeDescription: "显示摇晃的动画效果。"
|
shakeDescription: "显示摇晃的动画效果。"
|
||||||
twitch: "动画(颤抖)"
|
twitch: "动画(颤抖)"
|
||||||
twitchDescription: "显示强烈颤抖的动画效果。"
|
twitchDescription: "显示强烈颤抖的动画效果。"
|
||||||
spin: "动画(回转)"
|
spin: "动画(旋转)"
|
||||||
spinDescription: "显示回转的动画效果。"
|
spinDescription: "显示旋转的动画效果。"
|
||||||
x2: "大"
|
x2: "大"
|
||||||
x2Description: "以大尺寸显示内容。"
|
x2Description: "以大尺寸显示内容。"
|
||||||
x3: "非常大"
|
x3: "非常大"
|
||||||
@@ -1315,6 +1319,7 @@ _widgets:
|
|||||||
jobQueue: "作业队列"
|
jobQueue: "作业队列"
|
||||||
serverMetric: "服务器指标"
|
serverMetric: "服务器指标"
|
||||||
aiscript: "AiScript控制台"
|
aiscript: "AiScript控制台"
|
||||||
|
aiscriptApp: "AiScript App"
|
||||||
aichan: "小蓝"
|
aichan: "小蓝"
|
||||||
userList: "用户列表"
|
userList: "用户列表"
|
||||||
_userList:
|
_userList:
|
||||||
@@ -1420,6 +1425,21 @@ _timelines:
|
|||||||
local: "本地"
|
local: "本地"
|
||||||
social: "社交"
|
social: "社交"
|
||||||
global: "全局"
|
global: "全局"
|
||||||
|
_play:
|
||||||
|
new: "创建Play"
|
||||||
|
edit: "编辑Play"
|
||||||
|
created: "创建了一个Play"
|
||||||
|
updated: "更新了Play"
|
||||||
|
deleted: "删除了Play"
|
||||||
|
pageSetting: "Play设置"
|
||||||
|
editThisPage: "编辑此Play"
|
||||||
|
viewSource: "查看源代码"
|
||||||
|
my: "我的Play"
|
||||||
|
liked: "点赞的Play"
|
||||||
|
featured: "热门"
|
||||||
|
title: "标题"
|
||||||
|
script: "脚本"
|
||||||
|
summary: "描述"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "创建页面"
|
newPage: "创建页面"
|
||||||
editPage: "编辑页面"
|
editPage: "编辑页面"
|
||||||
|
@@ -916,6 +916,13 @@ loggedInAsBot: "以機器人帳號登入中"
|
|||||||
tools: "工具"
|
tools: "工具"
|
||||||
cannotLoad: "無法載入"
|
cannotLoad: "無法載入"
|
||||||
numberOfProfileView: "個人檔案檢視次數"
|
numberOfProfileView: "個人檔案檢視次數"
|
||||||
|
like: "讚"
|
||||||
|
unlike: "收回讚"
|
||||||
|
numberOfLikes: "讚數"
|
||||||
|
show: "檢視"
|
||||||
|
neverShow: "不再顯示"
|
||||||
|
remindMeLater: "以後再說"
|
||||||
|
didYouLikeMisskey: "您是否喜愛Misskey呢?"
|
||||||
_sensitiveMediaDetection:
|
_sensitiveMediaDetection:
|
||||||
description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。"
|
description: "您可以使用機器學習自動檢測敏感媒體並將其用於審核。 伺服器的負荷會稍微增加。"
|
||||||
sensitivity: "檢測敏感度"
|
sensitivity: "檢測敏感度"
|
||||||
@@ -1315,6 +1322,7 @@ _widgets:
|
|||||||
jobQueue: "佇列"
|
jobQueue: "佇列"
|
||||||
serverMetric: "服務器指標 "
|
serverMetric: "服務器指標 "
|
||||||
aiscript: "AiScript控制台"
|
aiscript: "AiScript控制台"
|
||||||
|
aiscriptApp: "AiScript App"
|
||||||
aichan: "小藍"
|
aichan: "小藍"
|
||||||
userList: "使用者列表"
|
userList: "使用者列表"
|
||||||
_userList:
|
_userList:
|
||||||
@@ -1420,6 +1428,21 @@ _timelines:
|
|||||||
local: "本地"
|
local: "本地"
|
||||||
social: "社群"
|
social: "社群"
|
||||||
global: "公開"
|
global: "公開"
|
||||||
|
_play:
|
||||||
|
new: "新增Play"
|
||||||
|
edit: "編輯Play"
|
||||||
|
created: "已新增Play"
|
||||||
|
updated: "已更新Play"
|
||||||
|
deleted: "已刪除Play"
|
||||||
|
pageSetting: "Play設定"
|
||||||
|
editThisPage: "編輯這個Play"
|
||||||
|
viewSource: "檢視原始碼"
|
||||||
|
my: "自己的Play"
|
||||||
|
liked: "按了讚的Play"
|
||||||
|
featured: "人氣"
|
||||||
|
title: "標題"
|
||||||
|
script: "腳本"
|
||||||
|
summary: "描述"
|
||||||
_pages:
|
_pages:
|
||||||
newPage: "建立頁面"
|
newPage: "建立頁面"
|
||||||
editPage: "編輯頁面"
|
editPage: "編輯頁面"
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "13.0.0-beta.22",
|
"version": "13.0.0-beta.31",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -53,10 +53,10 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/gulp": "4.0.10",
|
"@types/gulp": "4.0.10",
|
||||||
"@types/gulp-rename": "2.0.1",
|
"@types/gulp-rename": "2.0.1",
|
||||||
"@typescript-eslint/eslint-plugin": "5.47.1",
|
"@typescript-eslint/eslint-plugin": "5.48.0",
|
||||||
"@typescript-eslint/parser": "5.47.1",
|
"@typescript-eslint/parser": "5.48.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "12.2.0",
|
"cypress": "12.3.0",
|
||||||
"eslint": "^8.31.0",
|
"eslint": "^8.31.0",
|
||||||
"start-server-and-test": "1.15.2",
|
"start-server-and-test": "1.15.2",
|
||||||
"typescript": "4.9.4"
|
"typescript": "4.9.4"
|
||||||
|
BIN
packages/backend/assets/emoji-unknown.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
@@ -1,5 +0,0 @@
|
|||||||
Font Awesome Icons
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
Ⓒ Font Awesome
|
|
||||||
CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)
|
|
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 577 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 844 B |
Before Width: | Height: | Size: 507 B |
Before Width: | Height: | Size: 689 B |
Before Width: | Height: | Size: 772 B |
Before Width: | Height: | Size: 930 B |
Before Width: | Height: | Size: 798 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 991 B |
24
packages/backend/assets/tabler-badges/LICENSE
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Tabler Icons
|
||||||
|
https://github.com/tabler/tabler-icons/blob/master/LICENSE
|
||||||
|
====
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020-2022 Paweł Kuna
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
BIN
packages/backend/assets/tabler-badges/antenna.png
Normal file
After Width: | Height: | Size: 516 B |
BIN
packages/backend/assets/tabler-badges/arrow-back-up.png
Normal file
After Width: | Height: | Size: 952 B |
BIN
packages/backend/assets/tabler-badges/at.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
packages/backend/assets/tabler-badges/chart-arrows.png
Normal file
After Width: | Height: | Size: 829 B |
BIN
packages/backend/assets/tabler-badges/circle-check.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
packages/backend/assets/tabler-badges/messages.png
Normal file
After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 174 B After Width: | Height: | Size: 174 B |
BIN
packages/backend/assets/tabler-badges/plus.png
Normal file
After Width: | Height: | Size: 414 B |
BIN
packages/backend/assets/tabler-badges/quote.png
Normal file
After Width: | Height: | Size: 1011 B |
BIN
packages/backend/assets/tabler-badges/repeat.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
packages/backend/assets/tabler-badges/user-plus.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
packages/backend/assets/tabler-badges/users.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
@@ -21,9 +21,9 @@
|
|||||||
"@tensorflow/tfjs-node": "4.1.0"
|
"@tensorflow/tfjs-node": "4.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@bull-board/api": "^4.10.0",
|
"@bull-board/api": "^4.10.1",
|
||||||
"@bull-board/fastify": "^4.10.0",
|
"@bull-board/fastify": "^4.10.1",
|
||||||
"@bull-board/ui": "^4.10.0",
|
"@bull-board/ui": "^4.10.1",
|
||||||
"@discordapp/twemoji": "14.0.2",
|
"@discordapp/twemoji": "14.0.2",
|
||||||
"@fastify/accepts": "4.1.0",
|
"@fastify/accepts": "4.1.0",
|
||||||
"@fastify/cookie": "^8.3.0",
|
"@fastify/cookie": "^8.3.0",
|
||||||
@@ -38,10 +38,10 @@
|
|||||||
"@peertube/http-signature": "1.7.0",
|
"@peertube/http-signature": "1.7.0",
|
||||||
"@sinonjs/fake-timers": "10.0.2",
|
"@sinonjs/fake-timers": "10.0.2",
|
||||||
"accepts": "^1.3.8",
|
"accepts": "^1.3.8",
|
||||||
"ajv": "8.11.2",
|
"ajv": "8.12.0",
|
||||||
"archiver": "5.3.1",
|
"archiver": "5.3.1",
|
||||||
"autwh": "0.1.0",
|
"autwh": "0.1.0",
|
||||||
"aws-sdk": "2.1286.0",
|
"aws-sdk": "2.1289.0",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"blurhash": "2.0.4",
|
"blurhash": "2.0.4",
|
||||||
"bull": "4.10.2",
|
"bull": "4.10.2",
|
||||||
@@ -110,8 +110,8 @@
|
|||||||
"stringz": "2.1.0",
|
"stringz": "2.1.0",
|
||||||
"summaly": "2.7.0",
|
"summaly": "2.7.0",
|
||||||
"syslog-pro": "git+https://github.com/misskey-dev/SyslogPro#0.2.9-misskey.2",
|
"syslog-pro": "git+https://github.com/misskey-dev/SyslogPro#0.2.9-misskey.2",
|
||||||
"systeminformation": "5.16.9",
|
"systeminformation": "5.17.1",
|
||||||
"tinycolor2": "1.5.1",
|
"tinycolor2": "1.5.2",
|
||||||
"tmp": "0.2.1",
|
"tmp": "0.2.1",
|
||||||
"tsc-alias": "1.8.2",
|
"tsc-alias": "1.8.2",
|
||||||
"tsconfig-paths": "4.1.2",
|
"tsconfig-paths": "4.1.2",
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@redocly/openapi-core": "1.0.0-beta.117",
|
"@redocly/openapi-core": "1.0.0-beta.117",
|
||||||
"@swc/core": "1.3.24",
|
"@swc/core": "1.3.25",
|
||||||
"@swc/jest": "0.2.24",
|
"@swc/jest": "0.2.24",
|
||||||
"@types/accepts": "1.3.5",
|
"@types/accepts": "1.3.5",
|
||||||
"@types/archiver": "5.3.1",
|
"@types/archiver": "5.3.1",
|
||||||
@@ -172,8 +172,8 @@
|
|||||||
"@types/web-push": "3.3.2",
|
"@types/web-push": "3.3.2",
|
||||||
"@types/websocket": "1.0.5",
|
"@types/websocket": "1.0.5",
|
||||||
"@types/ws": "8.5.4",
|
"@types/ws": "8.5.4",
|
||||||
"@typescript-eslint/eslint-plugin": "5.47.1",
|
"@typescript-eslint/eslint-plugin": "5.48.0",
|
||||||
"@typescript-eslint/parser": "5.47.1",
|
"@typescript-eslint/parser": "5.48.0",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"eslint": "8.31.0",
|
"eslint": "8.31.0",
|
||||||
"eslint-plugin-import": "2.26.0",
|
"eslint-plugin-import": "2.26.0",
|
||||||
|
@@ -92,13 +92,6 @@ export class PollService {
|
|||||||
choice: choice,
|
choice: choice,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Notify
|
|
||||||
this.createNotificationService.createNotification(note.userId, 'pollVote', {
|
|
||||||
notifierId: user.id,
|
|
||||||
noteId: note.id,
|
|
||||||
choice: choice,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@bindThis
|
@bindThis
|
||||||
|
@@ -98,7 +98,7 @@ export class NotificationEntityService implements OnModuleInit {
|
|||||||
}),
|
}),
|
||||||
reaction: notification.reaction,
|
reaction: notification.reaction,
|
||||||
} : {}),
|
} : {}),
|
||||||
...(notification.type === 'pollVote' ? {
|
...(notification.type === 'pollVote' ? { // TODO: そのうち消す
|
||||||
note: this.noteEntityService.pack(notification.note ?? notification.noteId!, { id: notification.notifieeId }, {
|
note: this.noteEntityService.pack(notification.note ?? notification.noteId!, { id: notification.notifieeId }, {
|
||||||
detail: true,
|
detail: true,
|
||||||
_hint_: options._hintForEachNotes_,
|
_hint_: options._hintForEachNotes_,
|
||||||
|
@@ -3,6 +3,7 @@ import { FILE_TYPE_BROWSERSAFE } from '@/const.js';
|
|||||||
const dictionary = {
|
const dictionary = {
|
||||||
'safe-file': FILE_TYPE_BROWSERSAFE,
|
'safe-file': FILE_TYPE_BROWSERSAFE,
|
||||||
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/avif', 'image/svg+xml'],
|
'sharp-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/apng', 'image/vnd.mozilla.apng', 'image/webp', 'image/avif', 'image/svg+xml'],
|
||||||
|
'sharp-animation-convertible-image': ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/avif', 'image/svg+xml'],
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isMimeImage = (mime: string, type: keyof typeof dictionary): boolean => dictionary[type].includes(mime);
|
export const isMimeImage = (mime: string, type: keyof typeof dictionary): boolean => dictionary[type].includes(mime);
|
||||||
|
@@ -55,11 +55,11 @@ export class Notification {
|
|||||||
* 通知の種類。
|
* 通知の種類。
|
||||||
* follow - フォローされた
|
* follow - フォローされた
|
||||||
* mention - 投稿で自分が言及された
|
* mention - 投稿で自分が言及された
|
||||||
* reply - (自分または自分がWatchしている)投稿が返信された
|
* reply - 投稿に返信された
|
||||||
* renote - (自分または自分がWatchしている)投稿がRenoteされた
|
* renote - 投稿がRenoteされた
|
||||||
* quote - (自分または自分がWatchしている)投稿が引用Renoteされた
|
* quote - 投稿が引用Renoteされた
|
||||||
* reaction - (自分または自分がWatchしている)投稿にリアクションされた
|
* reaction - 投稿にリアクションされた
|
||||||
* pollVote - (自分または自分がWatchしている)投稿のアンケートに投票された
|
* pollVote - 投稿のアンケートに投票された (廃止)
|
||||||
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
* pollEnded - 自分のアンケートもしくは自分が投票したアンケートが終了した
|
||||||
* receiveFollowRequest - フォローリクエストされた
|
* receiveFollowRequest - フォローリクエストされた
|
||||||
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
|
* followRequestAccepted - 自分の送ったフォローリクエストが承認された
|
||||||
|
@@ -79,10 +79,18 @@ export class MediaProxyServerService {
|
|||||||
|
|
||||||
const { mime, ext } = await this.fileInfoService.detectType(path);
|
const { mime, ext } = await this.fileInfoService.detectType(path);
|
||||||
const isConvertibleImage = isMimeImage(mime, 'sharp-convertible-image');
|
const isConvertibleImage = isMimeImage(mime, 'sharp-convertible-image');
|
||||||
|
const isAnimationConvertibleImage = isMimeImage(mime, 'sharp-animation-convertible-image');
|
||||||
|
|
||||||
let image: IImage;
|
let image: IImage;
|
||||||
if ('emoji' in request.query && isConvertibleImage) {
|
if ('emoji' in request.query && isConvertibleImage) {
|
||||||
const data = await sharp(path, { animated: !('static' in request.query) })
|
if (!isAnimationConvertibleImage && !('static' in request.query)) {
|
||||||
|
image = {
|
||||||
|
data: fs.readFileSync(path),
|
||||||
|
ext,
|
||||||
|
type: mime,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const data = await sharp(path, { animated: !('static' in request.query) })
|
||||||
.resize({
|
.resize({
|
||||||
height: 128,
|
height: 128,
|
||||||
withoutEnlargement: true,
|
withoutEnlargement: true,
|
||||||
@@ -90,11 +98,12 @@ export class MediaProxyServerService {
|
|||||||
.webp(webpDefault)
|
.webp(webpDefault)
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
|
|
||||||
image = {
|
image = {
|
||||||
data,
|
data,
|
||||||
ext: 'webp',
|
ext: 'webp',
|
||||||
type: 'image/webp',
|
type: 'image/webp',
|
||||||
};
|
};
|
||||||
|
}
|
||||||
} else if ('static' in request.query && isConvertibleImage) {
|
} else if ('static' in request.query && isConvertibleImage) {
|
||||||
image = await this.imageProcessingService.convertToWebp(path, 498, 280);
|
image = await this.imageProcessingService.convertToWebp(path, 498, 280);
|
||||||
} else if ('preview' in request.query && isConvertibleImage) {
|
} else if ('preview' in request.query && isConvertibleImage) {
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
import cluster from 'node:cluster';
|
import cluster from 'node:cluster';
|
||||||
import * as fs from 'node:fs';
|
import * as fs from 'node:fs';
|
||||||
import * as http from 'node:http';
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import Fastify from 'fastify';
|
import Fastify from 'fastify';
|
||||||
import { IsNull } from 'typeorm';
|
import { IsNull } from 'typeorm';
|
||||||
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
import { GlobalEventService } from '@/core/GlobalEventService.js';
|
||||||
import type { Config } from '@/config.js';
|
import type { Config } from '@/config.js';
|
||||||
import type { UserProfilesRepository, UsersRepository } from '@/models/index.js';
|
import type { EmojisRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
|
||||||
import { DI } from '@/di-symbols.js';
|
import { DI } from '@/di-symbols.js';
|
||||||
import type Logger from '@/logger.js';
|
import type Logger from '@/logger.js';
|
||||||
import { envOption } from '@/env.js';
|
import { envOption } from '@/env.js';
|
||||||
@@ -39,6 +38,9 @@ export class ServerService {
|
|||||||
@Inject(DI.userProfilesRepository)
|
@Inject(DI.userProfilesRepository)
|
||||||
private userProfilesRepository: UserProfilesRepository,
|
private userProfilesRepository: UserProfilesRepository,
|
||||||
|
|
||||||
|
@Inject(DI.emojisRepository)
|
||||||
|
private emojisRepository: EmojisRepository,
|
||||||
|
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private apiServerService: ApiServerService,
|
private apiServerService: ApiServerService,
|
||||||
private streamingApiServerService: StreamingApiServerService,
|
private streamingApiServerService: StreamingApiServerService,
|
||||||
@@ -77,6 +79,43 @@ export class ServerService {
|
|||||||
fastify.register(this.nodeinfoServerService.createServer);
|
fastify.register(this.nodeinfoServerService.createServer);
|
||||||
fastify.register(this.wellKnownServerService.createServer);
|
fastify.register(this.wellKnownServerService.createServer);
|
||||||
|
|
||||||
|
fastify.get<{ Params: { path: string }; Querystring: { static?: any; }; }>('/emoji/:path(.*)', async (request, reply) => {
|
||||||
|
const path = request.params.path;
|
||||||
|
|
||||||
|
if (!path.match(/^[a-zA-Z0-9\-_@\.]+?\.webp$/)) {
|
||||||
|
reply.code(404);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
reply.header('Cache-Control', 'public, max-age=86400');
|
||||||
|
|
||||||
|
const name = path.split('@')[0].replace('.webp', '');
|
||||||
|
const host = path.split('@')[1]?.replace('.webp', '');
|
||||||
|
|
||||||
|
const emoji = await this.emojisRepository.findOneBy({
|
||||||
|
// `@.` is the spec of ReactionService.decodeReaction
|
||||||
|
host: (host == null || host === '.') ? IsNull() : host,
|
||||||
|
name: name,
|
||||||
|
});
|
||||||
|
|
||||||
|
reply.header('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\'');
|
||||||
|
|
||||||
|
if (emoji == null) {
|
||||||
|
return await reply.redirect('/static-assets/emoji-unknown.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
const url = new URL('/proxy/emoji.webp', this.config.url);
|
||||||
|
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
|
||||||
|
url.searchParams.set('url', emoji.publicUrl || emoji.originalUrl);
|
||||||
|
url.searchParams.set('emoji', '1');
|
||||||
|
if ('static' in request.query) url.searchParams.set('static', '1');
|
||||||
|
|
||||||
|
return await reply.redirect(
|
||||||
|
301,
|
||||||
|
url.toString(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
fastify.get<{ Params: { acct: string } }>('/avatar/@:acct', async (request, reply) => {
|
fastify.get<{ Params: { acct: string } }>('/avatar/@:acct', async (request, reply) => {
|
||||||
const { username, host } = Acct.parse(request.params.acct);
|
const { username, host } = Acct.parse(request.params.acct);
|
||||||
const user = await this.usersRepository.findOne({
|
const user = await this.usersRepository.findOne({
|
||||||
|
@@ -8,7 +8,7 @@ import { DriveFileEntityService } from '@/core/entities/DriveFileEntityService.j
|
|||||||
export const meta = {
|
export const meta = {
|
||||||
tags: ['admin'],
|
tags: ['admin'],
|
||||||
|
|
||||||
requireCredential: false,
|
requireCredential: true,
|
||||||
requireModerator: true,
|
requireModerator: true,
|
||||||
|
|
||||||
res: {
|
res: {
|
||||||
|
@@ -64,8 +64,8 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
case '-followers': query.orderBy('instance.followersCount', 'ASC'); break;
|
case '-followers': query.orderBy('instance.followersCount', 'ASC'); break;
|
||||||
case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break;
|
case '+caughtAt': query.orderBy('instance.caughtAt', 'DESC'); break;
|
||||||
case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break;
|
case '-caughtAt': query.orderBy('instance.caughtAt', 'ASC'); break;
|
||||||
case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC'); break;
|
case '+latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'DESC', 'NULLS LAST'); break;
|
||||||
case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC'); break;
|
case '-latestRequestReceivedAt': query.orderBy('instance.latestRequestReceivedAt', 'ASC', 'NULLS FIRST'); break;
|
||||||
|
|
||||||
default: query.orderBy('instance.id', 'DESC'); break;
|
default: query.orderBy('instance.id', 'DESC'); break;
|
||||||
}
|
}
|
||||||
|
@@ -162,13 +162,6 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
|||||||
userId: me.id,
|
userId: me.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Notify
|
|
||||||
this.createNotificationService.createNotification(note.userId, 'pollVote', {
|
|
||||||
notifierId: me.id,
|
|
||||||
noteId: note.id,
|
|
||||||
choice: ps.choice,
|
|
||||||
});
|
|
||||||
|
|
||||||
// リモート投票の場合リプライ送信
|
// リモート投票の場合リプライ送信
|
||||||
if (note.userHost != null) {
|
if (note.userHost != null) {
|
||||||
const pollOwner = await this.usersRepository.findOneByOrFail({ id: note.userId }) as IRemoteUser;
|
const pollOwner = await this.usersRepository.findOneByOrFail({ id: note.userId }) as IRemoteUser;
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { dirname } from 'node:path';
|
import { dirname } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath } from 'node:url';
|
||||||
import { PathOrFileDescriptor, readFileSync } from 'node:fs';
|
|
||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { createBullBoard } from '@bull-board/api';
|
import { createBullBoard } from '@bull-board/api';
|
||||||
import { BullAdapter } from '@bull-board/api/bullAdapter.js';
|
import { BullAdapter } from '@bull-board/api/bullAdapter.js';
|
||||||
@@ -26,9 +25,10 @@ import { PageEntityService } from '@/core/entities/PageEntityService.js';
|
|||||||
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
import { GalleryPostEntityService } from '@/core/entities/GalleryPostEntityService.js';
|
||||||
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
import { ClipEntityService } from '@/core/entities/ClipEntityService.js';
|
||||||
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
import { ChannelEntityService } from '@/core/entities/ChannelEntityService.js';
|
||||||
import type { ChannelsRepository, ClipsRepository, EmojisRepository, GalleryPostsRepository, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
|
import type { ChannelsRepository, ClipsRepository, EmojisRepository, FlashsRepository, GalleryPostsRepository, NotesRepository, PagesRepository, UserProfilesRepository, UsersRepository } from '@/models/index.js';
|
||||||
import { deepClone } from '@/misc/clone.js';
|
import { deepClone } from '@/misc/clone.js';
|
||||||
import { bindThis } from '@/decorators.js';
|
import { bindThis } from '@/decorators.js';
|
||||||
|
import { FlashEntityService } from '@/core/entities/FlashEntityService.js';
|
||||||
import manifest from './manifest.json' assert { type: 'json' };
|
import manifest from './manifest.json' assert { type: 'json' };
|
||||||
import { FeedService } from './FeedService.js';
|
import { FeedService } from './FeedService.js';
|
||||||
import { UrlPreviewService } from './UrlPreviewService.js';
|
import { UrlPreviewService } from './UrlPreviewService.js';
|
||||||
@@ -70,9 +70,10 @@ export class ClientServerService {
|
|||||||
@Inject(DI.pagesRepository)
|
@Inject(DI.pagesRepository)
|
||||||
private pagesRepository: PagesRepository,
|
private pagesRepository: PagesRepository,
|
||||||
|
|
||||||
@Inject(DI.emojisRepository)
|
@Inject(DI.flashsRepository)
|
||||||
private emojisRepository: EmojisRepository,
|
private flashsRepository: FlashsRepository,
|
||||||
|
|
||||||
|
private flashEntityService: FlashEntityService,
|
||||||
private userEntityService: UserEntityService,
|
private userEntityService: UserEntityService,
|
||||||
private noteEntityService: NoteEntityService,
|
private noteEntityService: NoteEntityService,
|
||||||
private pageEntityService: PageEntityService,
|
private pageEntityService: PageEntityService,
|
||||||
@@ -220,44 +221,6 @@ export class ClientServerService {
|
|||||||
return reply.sendFile('/apple-touch-icon.png', staticAssets);
|
return reply.sendFile('/apple-touch-icon.png', staticAssets);
|
||||||
});
|
});
|
||||||
|
|
||||||
fastify.get<{ Params: { path: string }; Querystring: { static?: any; }; }>('/emoji/:path(.*)', async (request, reply) => {
|
|
||||||
const path = request.params.path;
|
|
||||||
|
|
||||||
if (!path.match(/^[a-zA-Z0-9\-_@\.]+?\.webp$/)) {
|
|
||||||
reply.code(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reply.header('Cache-Control', 'public, max-age=86400');
|
|
||||||
|
|
||||||
const name = path.split('@')[0].replace('.webp', '');
|
|
||||||
const host = path.split('@')[1]?.replace('.webp', '');
|
|
||||||
|
|
||||||
const emoji = await this.emojisRepository.findOneBy({
|
|
||||||
// `@.` is the spec of ReactionService.decodeReaction
|
|
||||||
host: (host == null || host === '.') ? IsNull() : host,
|
|
||||||
name: name,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (emoji == null) {
|
|
||||||
reply.code(404);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
reply.header('Content-Security-Policy', 'default-src \'none\'; style-src \'unsafe-inline\'');
|
|
||||||
|
|
||||||
const url = new URL('/proxy/emoji.webp', this.config.url);
|
|
||||||
// || emoji.originalUrl してるのは後方互換性のため(publicUrlはstringなので??はだめ)
|
|
||||||
url.searchParams.set('url', emoji.publicUrl || emoji.originalUrl);
|
|
||||||
url.searchParams.set('emoji', '1');
|
|
||||||
if ('static' in request.query) url.searchParams.set('static', '1');
|
|
||||||
|
|
||||||
return await reply.redirect(
|
|
||||||
301,
|
|
||||||
url.toString(),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
fastify.get<{ Params: { path: string } }>('/fluent-emoji/:path(.*)', async (request, reply) => {
|
fastify.get<{ Params: { path: string } }>('/fluent-emoji/:path(.*)', async (request, reply) => {
|
||||||
const path = request.params.path;
|
const path = request.params.path;
|
||||||
|
|
||||||
@@ -352,7 +315,7 @@ export class ClientServerService {
|
|||||||
const name = meta.name || 'Misskey';
|
const name = meta.name || 'Misskey';
|
||||||
let content = '';
|
let content = '';
|
||||||
content += '<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">';
|
content += '<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:moz="http://www.mozilla.org/2006/browser/search/">';
|
||||||
content += `<ShortName>${name} Search</ShortName>`;
|
content += `<ShortName>${name}</ShortName>`;
|
||||||
content += `<Description>${name} Search</Description>`;
|
content += `<Description>${name} Search</Description>`;
|
||||||
content += '<InputEncoding>UTF-8</InputEncoding>';
|
content += '<InputEncoding>UTF-8</InputEncoding>';
|
||||||
content += `<Image width="16" height="16" type="image/x-icon">${this.config.url}/favicon.ico</Image>`;
|
content += `<Image width="16" height="16" type="image/x-icon">${this.config.url}/favicon.ico</Image>`;
|
||||||
@@ -545,6 +508,30 @@ export class ClientServerService {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Flash
|
||||||
|
fastify.get<{ Params: { id: string; } }>('/play/:id', async (request, reply) => {
|
||||||
|
const flash = await this.flashsRepository.findOneBy({
|
||||||
|
id: request.params.id,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (flash) {
|
||||||
|
const _flash = await this.flashEntityService.pack(flash);
|
||||||
|
const profile = await this.userProfilesRepository.findOneByOrFail({ userId: flash.userId });
|
||||||
|
const meta = await this.metaService.fetch();
|
||||||
|
reply.header('Cache-Control', 'public, max-age=15');
|
||||||
|
return await reply.view('flash', {
|
||||||
|
flash: _flash,
|
||||||
|
profile,
|
||||||
|
avatarUrl: await this.userEntityService.getAvatarUrl(await this.usersRepository.findOneByOrFail({ id: flash.userId })),
|
||||||
|
instanceName: meta.name ?? 'Misskey',
|
||||||
|
icon: meta.iconUrl,
|
||||||
|
themeColor: meta.themeColor,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return await renderBase(reply);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Clip
|
// Clip
|
||||||
// TODO: 非publicなclipのハンドリング
|
// TODO: 非publicなclipのハンドリング
|
||||||
fastify.get<{ Params: { clip: string; } }>('/clips/:clip', async (request, reply) => {
|
fastify.get<{ Params: { clip: string; } }>('/clips/:clip', async (request, reply) => {
|
||||||
|
@@ -31,7 +31,7 @@ html
|
|||||||
link(rel='icon' href= icon || '/favicon.ico')
|
link(rel='icon' href= icon || '/favicon.ico')
|
||||||
link(rel='apple-touch-icon' href= icon || '/apple-touch-icon.png')
|
link(rel='apple-touch-icon' href= icon || '/apple-touch-icon.png')
|
||||||
link(rel='manifest' href='/manifest.json')
|
link(rel='manifest' href='/manifest.json')
|
||||||
link(rel='search' type='application/opensearchdescription+xml' title=((title || "Misskey") + " Search") href=`${url}/opensearch.xml`)
|
link(rel='search' type='application/opensearchdescription+xml' title=(title || "Misskey") href=`${url}/opensearch.xml`)
|
||||||
link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg')
|
link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg')
|
||||||
link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg')
|
link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg')
|
||||||
link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg')
|
link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg')
|
||||||
|
31
packages/backend/src/server/web/views/flash.pug
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
extends ./base
|
||||||
|
|
||||||
|
block vars
|
||||||
|
- const user = flash.user;
|
||||||
|
- const title = flash.title;
|
||||||
|
- const url = `${config.url}/play/${flash.id}`;
|
||||||
|
|
||||||
|
block title
|
||||||
|
= `${title} | ${instanceName}`
|
||||||
|
|
||||||
|
block desc
|
||||||
|
meta(name='description' content= flash.summary)
|
||||||
|
|
||||||
|
block og
|
||||||
|
meta(property='og:type' content='article')
|
||||||
|
meta(property='og:title' content= title)
|
||||||
|
meta(property='og:description' content= flash.summary)
|
||||||
|
meta(property='og:url' content= url)
|
||||||
|
meta(property='og:image' content= avatarUrl)
|
||||||
|
|
||||||
|
block meta
|
||||||
|
if profile.noCrawle
|
||||||
|
meta(name='robots' content='noindex')
|
||||||
|
|
||||||
|
meta(name='misskey:user-username' content=user.username)
|
||||||
|
meta(name='misskey:user-id' content=user.id)
|
||||||
|
meta(name='misskey:flash-id' content=flash.id)
|
||||||
|
|
||||||
|
// todo
|
||||||
|
if user.twitter
|
||||||
|
meta(name='twitter:creator' content=`@${user.twitter.screenName}`)
|
BIN
packages/frontend/assets/cookie.png
Normal file
After Width: | Height: | Size: 38 KiB |
@@ -11,7 +11,7 @@
|
|||||||
"@rollup/plugin-alias": "4.0.2",
|
"@rollup/plugin-alias": "4.0.2",
|
||||||
"@rollup/plugin-json": "6.0.0",
|
"@rollup/plugin-json": "6.0.0",
|
||||||
"@rollup/pluginutils": "5.0.2",
|
"@rollup/pluginutils": "5.0.2",
|
||||||
"@syuilo/aiscript": "0.12.0",
|
"@syuilo/aiscript": "0.12.2",
|
||||||
"@tabler/icons": "^1.118.0",
|
"@tabler/icons": "^1.118.0",
|
||||||
"@vitejs/plugin-vue": "4.0.0",
|
"@vitejs/plugin-vue": "4.0.0",
|
||||||
"@vue/compiler-sfc": "3.2.45",
|
"@vue/compiler-sfc": "3.2.45",
|
||||||
@@ -20,7 +20,8 @@
|
|||||||
"blurhash": "2.0.4",
|
"blurhash": "2.0.4",
|
||||||
"broadcast-channel": "4.19.1",
|
"broadcast-channel": "4.19.1",
|
||||||
"browser-image-resizer": "git+https://github.com/misskey-dev/browser-image-resizer#v2.2.1-misskey.3",
|
"browser-image-resizer": "git+https://github.com/misskey-dev/browser-image-resizer#v2.2.1-misskey.3",
|
||||||
"chart.js": "4.1.1",
|
"canvas-confetti": "^1.6.0",
|
||||||
|
"chart.js": "4.1.2",
|
||||||
"chartjs-adapter-date-fns": "3.0.0",
|
"chartjs-adapter-date-fns": "3.0.0",
|
||||||
"chartjs-chart-matrix": "^1.3.0",
|
"chartjs-chart-matrix": "^1.3.0",
|
||||||
"chartjs-plugin-gradient": "0.6.1",
|
"chartjs-plugin-gradient": "0.6.1",
|
||||||
@@ -35,7 +36,7 @@
|
|||||||
"insert-text-at-cursor": "0.3.0",
|
"insert-text-at-cursor": "0.3.0",
|
||||||
"is-file-animated": "1.0.2",
|
"is-file-animated": "1.0.2",
|
||||||
"json5": "2.2.3",
|
"json5": "2.2.3",
|
||||||
"katex": "0.15.6",
|
"katex": "0.16.4",
|
||||||
"matter-js": "0.18.0",
|
"matter-js": "0.18.0",
|
||||||
"mfm-js": "0.23.0",
|
"mfm-js": "0.23.0",
|
||||||
"misskey-js": "0.0.14",
|
"misskey-js": "0.0.14",
|
||||||
@@ -44,7 +45,7 @@
|
|||||||
"punycode": "2.1.1",
|
"punycode": "2.1.1",
|
||||||
"querystring": "0.2.1",
|
"querystring": "0.2.1",
|
||||||
"rndstr": "1.0.0",
|
"rndstr": "1.0.0",
|
||||||
"rollup": "3.9.0",
|
"rollup": "3.9.1",
|
||||||
"s-age": "1.1.2",
|
"s-age": "1.1.2",
|
||||||
"sanitize-html": "^2.8.1",
|
"sanitize-html": "^2.8.1",
|
||||||
"sass": "1.57.1",
|
"sass": "1.57.1",
|
||||||
@@ -55,14 +56,14 @@
|
|||||||
"textarea-caret": "3.1.0",
|
"textarea-caret": "3.1.0",
|
||||||
"three": "0.148.0",
|
"three": "0.148.0",
|
||||||
"throttle-debounce": "5.0.0",
|
"throttle-debounce": "5.0.0",
|
||||||
"tinycolor2": "1.5.1",
|
"tinycolor2": "1.5.2",
|
||||||
"tsc-alias": "1.8.2",
|
"tsc-alias": "1.8.2",
|
||||||
"tsconfig-paths": "4.1.2",
|
"tsconfig-paths": "4.1.2",
|
||||||
"twemoji-parser": "14.0.0",
|
"twemoji-parser": "14.0.0",
|
||||||
"typescript": "4.9.4",
|
"typescript": "4.9.4",
|
||||||
"uuid": "9.0.0",
|
"uuid": "9.0.0",
|
||||||
"vanilla-tilt": "1.8.0",
|
"vanilla-tilt": "1.8.0",
|
||||||
"vite": "4.0.3",
|
"vite": "4.0.4",
|
||||||
"vue": "3.2.45",
|
"vue": "3.2.45",
|
||||||
"vue-prism-editor": "2.0.0-alpha.2",
|
"vue-prism-editor": "2.0.0-alpha.2",
|
||||||
"vuedraggable": "next"
|
"vuedraggable": "next"
|
||||||
@@ -72,7 +73,7 @@
|
|||||||
"@types/glob": "8.0.0",
|
"@types/glob": "8.0.0",
|
||||||
"@types/gulp": "4.0.10",
|
"@types/gulp": "4.0.10",
|
||||||
"@types/gulp-rename": "2.0.1",
|
"@types/gulp-rename": "2.0.1",
|
||||||
"@types/katex": "0.14.0",
|
"@types/katex": "0.16.0",
|
||||||
"@types/matter-js": "0.18.2",
|
"@types/matter-js": "0.18.2",
|
||||||
"@types/punycode": "2.1.0",
|
"@types/punycode": "2.1.0",
|
||||||
"@types/sanitize-html": "^2.8.0",
|
"@types/sanitize-html": "^2.8.0",
|
||||||
@@ -82,16 +83,16 @@
|
|||||||
"@types/uuid": "9.0.0",
|
"@types/uuid": "9.0.0",
|
||||||
"@types/websocket": "1.0.5",
|
"@types/websocket": "1.0.5",
|
||||||
"@types/ws": "8.5.4",
|
"@types/ws": "8.5.4",
|
||||||
"@typescript-eslint/eslint-plugin": "5.47.1",
|
"@typescript-eslint/eslint-plugin": "5.48.0",
|
||||||
"@typescript-eslint/parser": "5.47.1",
|
"@typescript-eslint/parser": "5.48.0",
|
||||||
"@vue/runtime-core": "3.2.45",
|
"@vue/runtime-core": "3.2.45",
|
||||||
"cross-env": "7.0.3",
|
"cross-env": "7.0.3",
|
||||||
"cypress": "12.2.0",
|
"cypress": "12.3.0",
|
||||||
"eslint": "8.31.0",
|
"eslint": "8.31.0",
|
||||||
"eslint-plugin-import": "2.26.0",
|
"eslint-plugin-import": "2.26.0",
|
||||||
"eslint-plugin-vue": "9.8.0",
|
"eslint-plugin-vue": "9.8.0",
|
||||||
"start-server-and-test": "1.15.2",
|
"start-server-and-test": "1.15.2",
|
||||||
"vue-eslint-parser": "^9.1.0",
|
"vue-eslint-parser": "^9.1.0",
|
||||||
"vue-tsc": "^1.0.19"
|
"vue-tsc": "^1.0.22"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -6,12 +6,13 @@ import { del, get, set } from '@/scripts/idb-proxy';
|
|||||||
import { apiUrl } from '@/config';
|
import { apiUrl } from '@/config';
|
||||||
import { waiting, api, popup, popupMenu, success, alert } from '@/os';
|
import { waiting, api, popup, popupMenu, success, alert } from '@/os';
|
||||||
import { unisonReload, reloadChannel } from '@/scripts/unison-reload';
|
import { unisonReload, reloadChannel } from '@/scripts/unison-reload';
|
||||||
|
import { miLocalStorage } from './local-storage';
|
||||||
|
|
||||||
// TODO: 他のタブと永続化されたstateを同期
|
// TODO: 他のタブと永続化されたstateを同期
|
||||||
|
|
||||||
type Account = misskey.entities.MeDetailed;
|
type Account = misskey.entities.MeDetailed;
|
||||||
|
|
||||||
const accountData = localStorage.getItem('account');
|
const accountData = miLocalStorage.getItem('account');
|
||||||
|
|
||||||
// TODO: 外部からはreadonlyに
|
// TODO: 外部からはreadonlyに
|
||||||
export const $i = accountData ? reactive(JSON.parse(accountData) as Account) : null;
|
export const $i = accountData ? reactive(JSON.parse(accountData) as Account) : null;
|
||||||
@@ -21,7 +22,7 @@ export const iAmAdmin = $i != null && $i.isAdmin;
|
|||||||
|
|
||||||
export async function signout() {
|
export async function signout() {
|
||||||
waiting();
|
waiting();
|
||||||
localStorage.removeItem('account');
|
miLocalStorage.removeItem('account');
|
||||||
|
|
||||||
await removeAccount($i.id);
|
await removeAccount($i.id);
|
||||||
|
|
||||||
@@ -119,7 +120,7 @@ export function updateAccount(accountData) {
|
|||||||
for (const [key, value] of Object.entries(accountData)) {
|
for (const [key, value] of Object.entries(accountData)) {
|
||||||
$i[key] = value;
|
$i[key] = value;
|
||||||
}
|
}
|
||||||
localStorage.setItem('account', JSON.stringify($i));
|
miLocalStorage.setItem('account', JSON.stringify($i));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function refreshAccount() {
|
export function refreshAccount() {
|
||||||
@@ -130,7 +131,7 @@ export async function login(token: Account['token'], redirect?: string) {
|
|||||||
waiting();
|
waiting();
|
||||||
if (_DEV_) console.log('logging as token ', token);
|
if (_DEV_) console.log('logging as token ', token);
|
||||||
const me = await fetchAccount(token);
|
const me = await fetchAccount(token);
|
||||||
localStorage.setItem('account', JSON.stringify(me));
|
miLocalStorage.setItem('account', JSON.stringify(me));
|
||||||
document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardの認証とかで使う
|
document.cookie = `token=${token}; path=/; max-age=31536000`; // bull dashboardの認証とかで使う
|
||||||
await addAccount(me.id, token);
|
await addAccount(me.id, token);
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="bcekxzvu _gap _panel">
|
<div class="bcekxzvu _margin _panel">
|
||||||
<div class="target">
|
<div class="target">
|
||||||
<MkA v-user-preview="report.targetUserId" class="info" :to="`/user-info/${report.targetUserId}`">
|
<MkA v-user-preview="report.targetUserId" class="info" :to="`/user-info/${report.targetUserId}`">
|
||||||
<MkAvatar class="avatar" :user="report.targetUser" :show-indicator="true" :disable-link="true"/>
|
<MkAvatar class="avatar" :user="report.targetUser" :show-indicator="true" :disable-link="true"/>
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
<MkAcct class="acct" :user="report.targetUser" style="display: block;"/>
|
<MkAcct class="acct" :user="report.targetUser" style="display: block;"/>
|
||||||
</div>
|
</div>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkKeyValue class="_formBlock">
|
<MkKeyValue>
|
||||||
<template #key>{{ i18n.ts.registeredDate }}</template>
|
<template #key>{{ i18n.ts.registeredDate }}</template>
|
||||||
<template #value>{{ dateString(report.targetUser.createdAt) }} (<MkTime :time="report.targetUser.createdAt"/>)</template>
|
<template #value>{{ dateString(report.targetUser.createdAt) }} (<MkTime :time="report.targetUser.createdAt"/>)</template>
|
||||||
</MkKeyValue>
|
</MkKeyValue>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkSwitch from '@/components/form/switch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkKeyValue from '@/components/MkKeyValue.vue';
|
import MkKeyValue from '@/components/MkKeyValue.vue';
|
||||||
import { acct, userPage } from '@/filters/user';
|
import { acct, userPage } from '@/filters/user';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<XWindow ref="uiWindow" :initial-width="400" :initial-height="500" :can-resize="true" @closed="emit('closed')">
|
<MkWindow ref="uiWindow" :initial-width="400" :initial-height="500" :can-resize="true" @closed="emit('closed')">
|
||||||
<template #header>
|
<template #header>
|
||||||
<i class="ti ti-exclamation-circle" style="margin-right: 0.5em;"></i>
|
<i class="ti ti-exclamation-circle" style="margin-right: 0.5em;"></i>
|
||||||
<I18n :src="i18n.ts.reportAbuseOf" tag="span">
|
<I18n :src="i18n.ts.reportAbuseOf" tag="span">
|
||||||
@@ -8,25 +8,27 @@
|
|||||||
</template>
|
</template>
|
||||||
</I18n>
|
</I18n>
|
||||||
</template>
|
</template>
|
||||||
<div class="dpvffvvy _monolithic_">
|
<MkSpacer :margin-min="20" :margin-max="28">
|
||||||
<div class="_section">
|
<div class="dpvffvvy _gaps_m">
|
||||||
<MkTextarea v-model="comment">
|
<div class="">
|
||||||
<template #label>{{ i18n.ts.details }}</template>
|
<MkTextarea v-model="comment">
|
||||||
<template #caption>{{ i18n.ts.fillAbuseReportDescription }}</template>
|
<template #label>{{ i18n.ts.details }}</template>
|
||||||
</MkTextarea>
|
<template #caption>{{ i18n.ts.fillAbuseReportDescription }}</template>
|
||||||
|
</MkTextarea>
|
||||||
|
</div>
|
||||||
|
<div class="">
|
||||||
|
<MkButton primary full :disabled="comment.length === 0" @click="send">{{ i18n.ts.send }}</MkButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="_section">
|
</MkSpacer>
|
||||||
<MkButton primary full :disabled="comment.length === 0" @click="send">{{ i18n.ts.send }}</MkButton>
|
</MkWindow>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</XWindow>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, shallowRef } from 'vue';
|
import { ref, shallowRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XWindow from '@/components/MkWindow.vue';
|
import MkWindow from '@/components/MkWindow.vue';
|
||||||
import MkTextarea from '@/components/form/textarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
@@ -40,7 +42,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const uiWindow = shallowRef<InstanceType<typeof XWindow>>();
|
const uiWindow = shallowRef<InstanceType<typeof MkWindow>>();
|
||||||
const comment = ref(props.initialComment || '');
|
const comment = ref(props.initialComment || '');
|
||||||
|
|
||||||
function send() {
|
function send() {
|
||||||
|
@@ -8,7 +8,7 @@
|
|||||||
<span v-else-if="c.type === 'text'" :class="{ [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace' }" :style="{ fontSize: c.size ? `${c.size * 100}%` : null, fontWeight: c.bold ? 'bold' : null, color: c.color ?? null }">{{ c.text }}</span>
|
<span v-else-if="c.type === 'text'" :class="{ [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace' }" :style="{ fontSize: c.size ? `${c.size * 100}%` : null, fontWeight: c.bold ? 'bold' : null, color: c.color ?? null }">{{ c.text }}</span>
|
||||||
<Mfm v-else-if="c.type === 'mfm'" :class="{ [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace' }" :style="{ fontSize: c.size ? `${c.size * 100}%` : null, color: c.color ?? null }" :text="c.text"/>
|
<Mfm v-else-if="c.type === 'mfm'" :class="{ [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace' }" :style="{ fontSize: c.size ? `${c.size * 100}%` : null, color: c.color ?? null }" :text="c.text"/>
|
||||||
<MkButton v-else-if="c.type === 'button'" :primary="c.primary" :rounded="c.rounded" :small="size === 'small'" @click="c.onClick">{{ c.text }}</MkButton>
|
<MkButton v-else-if="c.type === 'button'" :primary="c.primary" :rounded="c.rounded" :small="size === 'small'" @click="c.onClick">{{ c.text }}</MkButton>
|
||||||
<div v-else-if="c.type === 'buttons'" style="display: flex; gap: 8px; flex-wrap: wrap;">
|
<div v-else-if="c.type === 'buttons'" class="_buttons">
|
||||||
<MkButton v-for="button in c.buttons" :primary="button.primary" :rounded="button.rounded" :small="size === 'small'" @click="button.onClick">{{ button.text }}</MkButton>
|
<MkButton v-for="button in c.buttons" :primary="button.primary" :rounded="button.rounded" :small="size === 'small'" @click="button.onClick">{{ button.text }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
<MkSwitch v-else-if="c.type === 'switch'" :model-value="valueForSwitch" @update:model-value="onSwitchUpdate">
|
<MkSwitch v-else-if="c.type === 'switch'" :model-value="valueForSwitch" @update:model-value="onSwitchUpdate">
|
||||||
@@ -33,6 +33,12 @@
|
|||||||
<option v-for="item in c.items" :key="item.value" :value="item.value">{{ item.text }}</option>
|
<option v-for="item in c.items" :key="item.value" :value="item.value">{{ item.text }}</option>
|
||||||
</MkSelect>
|
</MkSelect>
|
||||||
<MkButton v-else-if="c.type === 'postFormButton'" :primary="c.primary" :rounded="c.rounded" :small="size === 'small'" @click="openPostForm">{{ c.text }}</MkButton>
|
<MkButton v-else-if="c.type === 'postFormButton'" :primary="c.primary" :rounded="c.rounded" :small="size === 'small'" @click="openPostForm">{{ c.text }}</MkButton>
|
||||||
|
<FormFolder v-else-if="c.type === 'folder'" :default-open="c.opened">
|
||||||
|
<template #label>{{ c.title }}</template>
|
||||||
|
<template v-for="child in c.children" :key="child">
|
||||||
|
<MkAsUi v-if="!g(child).hidden" :component="g(child)" :components="props.components" :size="size"/>
|
||||||
|
</template>
|
||||||
|
</FormFolder>
|
||||||
<div v-else-if="c.type === 'container'" :class="[$style.container, { [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace', [$style.containerCenter]: c.align === 'center' }]" :style="{ backgroundColor: c.bgColor ?? null, color: c.fgColor ?? null, borderWidth: c.borderWidth ? `${c.borderWidth}px` : 0, borderColor: c.borderColor ?? 'var(--divider)', padding: c.padding ? `${c.padding}px` : 0, borderRadius: c.rounded ? '8px' : 0 }">
|
<div v-else-if="c.type === 'container'" :class="[$style.container, { [$style.fontSerif]: c.font === 'serif', [$style.fontMonospace]: c.font === 'monospace', [$style.containerCenter]: c.align === 'center' }]" :style="{ backgroundColor: c.bgColor ?? null, color: c.fgColor ?? null, borderWidth: c.borderWidth ? `${c.borderWidth}px` : 0, borderColor: c.borderColor ?? 'var(--divider)', padding: c.padding ? `${c.padding}px` : 0, borderRadius: c.rounded ? '8px' : 0 }">
|
||||||
<template v-for="child in c.children" :key="child">
|
<template v-for="child in c.children" :key="child">
|
||||||
<MkAsUi v-if="!g(child).hidden" :component="g(child)" :components="props.components" :size="size"/>
|
<MkAsUi v-if="!g(child).hidden" :component="g(child)" :components="props.components" :size="size"/>
|
||||||
@@ -45,11 +51,12 @@
|
|||||||
import { computed, defineAsyncComponent, onMounted, onUnmounted, Ref } from 'vue';
|
import { computed, defineAsyncComponent, onMounted, onUnmounted, Ref } from 'vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/form/input.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkSwitch from '@/components/form/switch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import MkTextarea from '@/components/form/textarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import MkSelect from '@/components/form/select.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import { AsUiComponent } from '@/scripts/aiscript/ui';
|
import { AsUiComponent } from '@/scripts/aiscript/ui';
|
||||||
|
import FormFolder from '@/components/form/folder.vue';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
component: AsUiComponent;
|
component: AsUiComponent;
|
||||||
|
@@ -46,6 +46,7 @@ import { defaultStore } from '@/store';
|
|||||||
import { emojilist } from '@/scripts/emojilist';
|
import { emojilist } from '@/scripts/emojilist';
|
||||||
import { instance } from '@/instance';
|
import { instance } from '@/instance';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
import { miLocalStorage } from '@/local-storage';
|
||||||
|
|
||||||
type EmojiDef = {
|
type EmojiDef = {
|
||||||
emoji: string;
|
emoji: string;
|
||||||
@@ -208,7 +209,7 @@ function exec() {
|
|||||||
}
|
}
|
||||||
} else if (props.type === 'hashtag') {
|
} else if (props.type === 'hashtag') {
|
||||||
if (!props.q || props.q === '') {
|
if (!props.q || props.q === '') {
|
||||||
hashtags.value = JSON.parse(localStorage.getItem('hashtags') || '[]');
|
hashtags.value = JSON.parse(miLocalStorage.getItem('hashtags') || '[]');
|
||||||
fetching.value = false;
|
fetching.value = false;
|
||||||
} else {
|
} else {
|
||||||
const cacheKey = `autocomplete:hashtag:${props.q}`;
|
const cacheKey = `autocomplete:hashtag:${props.q}`;
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
*/
|
*/
|
||||||
import { onMounted, ref, shallowRef, watch, PropType, onUnmounted } from 'vue';
|
import { onMounted, ref, shallowRef, watch, PropType, onUnmounted } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import { enUS } from 'date-fns/locale';
|
|
||||||
import gradient from 'chartjs-plugin-gradient';
|
import gradient from 'chartjs-plugin-gradient';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
@@ -186,6 +185,10 @@ const render = () => {
|
|||||||
time: {
|
time: {
|
||||||
stepSize: 1,
|
stepSize: 1,
|
||||||
unit: props.span === 'day' ? 'month' : 'day',
|
unit: props.span === 'day' ? 'month' : 'day',
|
||||||
|
displayFormats: {
|
||||||
|
day: 'M/d',
|
||||||
|
month: 'Y/M',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
},
|
},
|
||||||
@@ -194,11 +197,6 @@ const render = () => {
|
|||||||
maxRotation: 0,
|
maxRotation: 0,
|
||||||
autoSkipPadding: 16,
|
autoSkipPadding: 16,
|
||||||
},
|
},
|
||||||
adapters: {
|
|
||||||
date: {
|
|
||||||
locale: enUS,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
min: getDate(props.limit).getTime(),
|
min: getDate(props.limit).getTime(),
|
||||||
},
|
},
|
||||||
y: {
|
y: {
|
||||||
|
@@ -72,4 +72,11 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@container (max-width: 500px) {
|
||||||
|
.root {
|
||||||
|
font-size: 90%;
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
70
packages/frontend/src/components/MkClickerGame.vue
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<div v-if="game.ready" :class="$style.game">
|
||||||
|
<div :class="$style.count" class=""><i class="ti ti-cookie" style="font-size: 70%;"></i> {{ number(cookies) }}</div>
|
||||||
|
<button v-click-anime class="_button" :class="$style.button" @click="onClick">
|
||||||
|
<img src="/client-assets/cookie.png" :class="$style.img">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<MkLoading/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { computed, defineAsyncComponent, onMounted, onUnmounted } from 'vue';
|
||||||
|
import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import { useInterval } from '@/scripts/use-interval';
|
||||||
|
import * as game from '@/scripts/clicker-game';
|
||||||
|
import number from '@/filters/number';
|
||||||
|
|
||||||
|
defineProps<{
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const saveData = game.saveData;
|
||||||
|
const cookies = computed(() => saveData.value?.cookies);
|
||||||
|
|
||||||
|
function onClick(ev: MouseEvent) {
|
||||||
|
saveData.value!.cookies++;
|
||||||
|
saveData.value!.clicked++;
|
||||||
|
|
||||||
|
const x = ev.clientX;
|
||||||
|
const y = ev.clientY;
|
||||||
|
os.popup(MkPlusOneEffect, { x, y }, {}, 'end');
|
||||||
|
}
|
||||||
|
|
||||||
|
useInterval(game.save, 1000 * 5, {
|
||||||
|
immediate: false,
|
||||||
|
afterMounted: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await game.load();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
game.save();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.game {
|
||||||
|
padding: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.count {
|
||||||
|
font-size: 1.3em;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
max-width: 90px;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -74,7 +74,7 @@ function onMousedown(evt: Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.fade-enter-active, .fade-leave-active {
|
.fade-enter-active, .fade-leave-active {
|
||||||
transition: opacity 0.5s cubic-bezier(0.16, 1, 0.3, 1), transform 0.5s cubic-bezier(0.16, 1, 0.3, 1);
|
transition: opacity 0.3s cubic-bezier(0.16, 1, 0.3, 1), transform 0.3s cubic-bezier(0.16, 1, 0.3, 1);
|
||||||
transform-origin: left top;
|
transform-origin: left top;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<XModalWindow
|
<MkModalWindow
|
||||||
ref="dialogEl"
|
ref="dialogEl"
|
||||||
:width="800"
|
:width="800"
|
||||||
:height="500"
|
:height="500"
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</XModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
@@ -30,7 +30,7 @@ import { nextTick, onMounted } from 'vue';
|
|||||||
import * as misskey from 'misskey-js';
|
import * as misskey from 'misskey-js';
|
||||||
import Cropper from 'cropperjs';
|
import Cropper from 'cropperjs';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import XModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { $i } from '@/account';
|
import { $i } from '@/account';
|
||||||
import { defaultStore } from '@/store';
|
import { defaultStore } from '@/store';
|
||||||
@@ -50,7 +50,7 @@ const props = defineProps<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
const imgUrl = getProxiedImageUrl(props.file.url);
|
const imgUrl = getProxiedImageUrl(props.file.url);
|
||||||
let dialogEl = $shallowRef<InstanceType<typeof XModalWindow>>();
|
let dialogEl = $shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
let imgEl = $shallowRef<HTMLImageElement>();
|
let imgEl = $shallowRef<HTMLImageElement>();
|
||||||
let cropper: Cropper | null = null;
|
let cropper: Cropper | null = null;
|
||||||
let loading = $ref(true);
|
let loading = $ref(true);
|
||||||
|
@@ -42,8 +42,8 @@
|
|||||||
import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue';
|
import { onBeforeUnmount, onMounted, ref, shallowRef } from 'vue';
|
||||||
import MkModal from '@/components/MkModal.vue';
|
import MkModal from '@/components/MkModal.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/form/input.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import MkSelect from '@/components/form/select.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
type Input = {
|
type Input = {
|
||||||
|
109
packages/frontend/src/components/MkDonation.vue
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
<template>
|
||||||
|
<div class="_panel _shadow" :class="$style.root">
|
||||||
|
<!-- TODO: インスタンス運営者が任意のテキストとリンクを設定できるようにする -->
|
||||||
|
<div :class="$style.icon">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-pig-money" width="40" height="40" viewBox="0 0 24 24" stroke-width="1" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||||
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
||||||
|
<path d="M15 11v.01"></path>
|
||||||
|
<path d="M5.173 8.378a3 3 0 1 1 4.656 -1.377"></path>
|
||||||
|
<path d="M16 4v3.803a6.019 6.019 0 0 1 2.658 3.197h1.341a1 1 0 0 1 1 1v2a1 1 0 0 1 -1 1h-1.342c-.336 .95 -.907 1.8 -1.658 2.473v2.027a1.5 1.5 0 0 1 -3 0v-.583a6.04 6.04 0 0 1 -1 .083h-4a6.04 6.04 0 0 1 -1 -.083v.583a1.5 1.5 0 0 1 -3 0v-2l.001 -.027a6 6 0 0 1 3.999 -10.473h2.5l4.5 -3h.001z"></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<div :class="$style.main">
|
||||||
|
<div :class="$style.title">{{ i18n.ts.didYouLikeMisskey }}</div>
|
||||||
|
<div :class="$style.text">
|
||||||
|
<I18n :src="i18n.ts.pleaseDonate" tag="span">
|
||||||
|
<template #host>
|
||||||
|
{{ $instance.name ?? host }}
|
||||||
|
</template>
|
||||||
|
</I18n>
|
||||||
|
<div style="margin-top: 0.2em;">
|
||||||
|
<MkLink target="_blank" url="https://misskey-hub.net/docs/donate.html">{{ i18n.ts.learnMore }}</MkLink>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="_buttons">
|
||||||
|
<MkButton @click="close">{{ i18n.ts.remindMeLater }}</MkButton>
|
||||||
|
<MkButton @click="neverShow">{{ i18n.ts.neverShow }}</MkButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button class="_button" :class="$style.close" @click="close"><i class="ti ti-x"></i></button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { onMounted, shallowRef } from 'vue';
|
||||||
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import MkLink from '@/components/MkLink.vue';
|
||||||
|
import { host } from '@/config';
|
||||||
|
import { i18n } from '@/i18n';
|
||||||
|
import * as os from '@/os';
|
||||||
|
import { miLocalStorage } from '@/local-storage';
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(ev: 'closed'): void;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const zIndex = os.claimZIndex('low');
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
miLocalStorage.setItem('latestDonationInfoShownAt', Date.now().toString());
|
||||||
|
emit('closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
function neverShow() {
|
||||||
|
miLocalStorage.setItem('neverShowDonationInfo', 'true')
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.root {
|
||||||
|
position: fixed;
|
||||||
|
z-index: v-bind(zIndex);
|
||||||
|
bottom: var(--margin);
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
margin: auto;
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: calc(100% - (var(--margin) * 2));
|
||||||
|
max-width: 500px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 25px;
|
||||||
|
width: 100px;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.icon {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 450px) {
|
||||||
|
.icon {
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
padding: 25px 25px 25px 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
right: 8px;
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
margin: 0.7em 0 1em 0;
|
||||||
|
}
|
||||||
|
</style>
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<XModalWindow
|
<MkModalWindow
|
||||||
ref="dialog"
|
ref="dialog"
|
||||||
:width="800"
|
:width="800"
|
||||||
:height="500"
|
:height="500"
|
||||||
@@ -15,14 +15,14 @@
|
|||||||
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
|
<span v-if="selected.length > 0" style="margin-left: 8px; opacity: 0.5;">({{ number(selected.length) }})</span>
|
||||||
</template>
|
</template>
|
||||||
<XDrive :multiple="multiple" :select="type" @change-selection="onChangeSelection" @selected="ok()"/>
|
<XDrive :multiple="multiple" :select="type" @change-selection="onChangeSelection" @selected="ok()"/>
|
||||||
</XModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { ref, shallowRef } from 'vue';
|
import { ref, shallowRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XDrive from '@/components/MkDrive.vue';
|
import XDrive from '@/components/MkDrive.vue';
|
||||||
import XModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import number from '@/filters/number';
|
import number from '@/filters/number';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = shallowRef<InstanceType<typeof XModalWindow>>();
|
const dialog = shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
const selected = ref<Misskey.entities.DriveFile[]>([]);
|
const selected = ref<Misskey.entities.DriveFile[]>([]);
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<XWindow
|
<MkWindow
|
||||||
ref="window"
|
ref="window"
|
||||||
:initial-width="800"
|
:initial-width="800"
|
||||||
:initial-height="500"
|
:initial-height="500"
|
||||||
@@ -10,14 +10,14 @@
|
|||||||
{{ i18n.ts.drive }}
|
{{ i18n.ts.drive }}
|
||||||
</template>
|
</template>
|
||||||
<XDrive :initial-folder="initialFolder"/>
|
<XDrive :initial-folder="initialFolder"/>
|
||||||
</XWindow>
|
</MkWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { } from 'vue';
|
import { } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XDrive from '@/components/MkDrive.vue';
|
import XDrive from '@/components/MkDrive.vue';
|
||||||
import XWindow from '@/components/MkWindow.vue';
|
import MkWindow from '@/components/MkWindow.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
defineProps<{
|
defineProps<{
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
|
<div class="omfetrab" :class="['s' + size, 'w' + width, 'h' + height, { asDrawer, asWindow }]" :style="{ maxHeight: maxHeight ? maxHeight + 'px' : undefined }">
|
||||||
<input ref="search" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keyup.enter="done()">
|
<input ref="search" :value="q" class="search" data-prevent-emoji-insert :class="{ filled: q != null && q != '' }" :placeholder="i18n.ts.search" type="search" @input="input()" @paste.stop="paste" @keyup.enter="done()">
|
||||||
<div ref="emojis" class="emojis">
|
<div ref="emojis" class="emojis">
|
||||||
<section class="result">
|
<section class="result">
|
||||||
@@ -94,6 +94,7 @@ const props = withDefaults(defineProps<{
|
|||||||
asReactionPicker?: boolean;
|
asReactionPicker?: boolean;
|
||||||
maxHeight?: number;
|
maxHeight?: number;
|
||||||
asDrawer?: boolean;
|
asDrawer?: boolean;
|
||||||
|
asWindow?: boolean;
|
||||||
}>(), {
|
}>(), {
|
||||||
showPinned: true,
|
showPinned: true,
|
||||||
});
|
});
|
||||||
@@ -440,6 +441,28 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.asWindow {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
|
||||||
|
> .emojis {
|
||||||
|
::v-deep(section) {
|
||||||
|
> .body {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: var(--columns);
|
||||||
|
font-size: 30px;
|
||||||
|
|
||||||
|
> .item {
|
||||||
|
aspect-ratio: 1 / 1;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> .search {
|
> .search {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
@@ -1,13 +1,13 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkWindow ref="window"
|
<MkWindow ref="window"
|
||||||
:initial-width="null"
|
:initial-width="300"
|
||||||
:initial-height="null"
|
:initial-height="290"
|
||||||
:can-resize="false"
|
:can-resize="true"
|
||||||
:mini="true"
|
:mini="true"
|
||||||
:front="true"
|
:front="true"
|
||||||
@closed="emit('closed')"
|
@closed="emit('closed')"
|
||||||
>
|
>
|
||||||
<MkEmojiPicker :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" @chosen="chosen"/>
|
<MkEmojiPicker :show-pinned="showPinned" :as-reaction-picker="asReactionPicker" as-window @chosen="chosen" :class="$style.picker"/>
|
||||||
</MkWindow>
|
</MkWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -34,147 +34,8 @@ function chosen(emoji: any) {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" module>
|
||||||
.omfetrab {
|
.picker {
|
||||||
$pad: 8px;
|
height: 100%;
|
||||||
--eachSize: 40px;
|
|
||||||
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
contain: content;
|
|
||||||
|
|
||||||
&.big {
|
|
||||||
--eachSize: 44px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.w1 {
|
|
||||||
width: calc((var(--eachSize) * 5) + (#{$pad} * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
&.w2 {
|
|
||||||
width: calc((var(--eachSize) * 6) + (#{$pad} * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
&.w3 {
|
|
||||||
width: calc((var(--eachSize) * 7) + (#{$pad} * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
&.h1 {
|
|
||||||
--height: calc((var(--eachSize) * 4) + (#{$pad} * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
&.h2 {
|
|
||||||
--height: calc((var(--eachSize) * 6) + (#{$pad} * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
&.h3 {
|
|
||||||
--height: calc((var(--eachSize) * 8) + (#{$pad} * 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
> .search {
|
|
||||||
width: 100%;
|
|
||||||
padding: 12px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 1em;
|
|
||||||
outline: none;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
color: var(--fg);
|
|
||||||
|
|
||||||
&:not(.filled) {
|
|
||||||
order: 1;
|
|
||||||
z-index: 2;
|
|
||||||
box-shadow: 0px -1px 0 0px var(--divider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .emojis {
|
|
||||||
height: var(--height);
|
|
||||||
overflow-y: auto;
|
|
||||||
overflow-x: hidden;
|
|
||||||
|
|
||||||
scrollbar-width: none;
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .index {
|
|
||||||
min-height: var(--height);
|
|
||||||
position: relative;
|
|
||||||
border-bottom: solid 0.5px var(--divider);
|
|
||||||
|
|
||||||
> .arrow {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
padding: 16px 0;
|
|
||||||
text-align: center;
|
|
||||||
opacity: 0.5;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
> header {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
z-index: 1;
|
|
||||||
padding: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
|
||||||
padding: $pad;
|
|
||||||
|
|
||||||
> button {
|
|
||||||
position: relative;
|
|
||||||
padding: 0;
|
|
||||||
width: var(--eachSize);
|
|
||||||
height: var(--eachSize);
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&:focus-visible {
|
|
||||||
outline: solid 2px var(--focus);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: var(--accent);
|
|
||||||
box-shadow: inset 0 0.15em 0.3em rgba(27, 31, 35, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
> * {
|
|
||||||
font-size: 24px;
|
|
||||||
height: 1.25em;
|
|
||||||
vertical-align: -.25em;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.result {
|
|
||||||
border-bottom: solid 0.5px var(--divider);
|
|
||||||
|
|
||||||
&:empty {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.unicode {
|
|
||||||
min-height: 384px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.custom {
|
|
||||||
min-height: 64px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<XModalWindow
|
<MkModalWindow
|
||||||
ref="dialog"
|
ref="dialog"
|
||||||
:width="400"
|
:width="400"
|
||||||
:height="450"
|
:height="450"
|
||||||
@@ -16,14 +16,14 @@
|
|||||||
<template #label>{{ i18n.ts.caption }}</template>
|
<template #label>{{ i18n.ts.caption }}</template>
|
||||||
</MkTextarea>
|
</MkTextarea>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</XModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { } from 'vue';
|
import { } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import XModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkTextarea from '@/components/form/textarea.vue';
|
import MkTextarea from '@/components/MkTextarea.vue';
|
||||||
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const dialog = $shallowRef<InstanceType<typeof XModalWindow>>();
|
const dialog = $shallowRef<InstanceType<typeof MkModalWindow>>();
|
||||||
|
|
||||||
let caption = $ref(props.default);
|
let caption = $ref(props.default);
|
||||||
|
|
||||||
|
@@ -54,8 +54,6 @@ const props = defineProps<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.urempief {
|
.urempief {
|
||||||
margin-top: var(--margin);
|
|
||||||
|
|
||||||
&.list {
|
&.list {
|
||||||
> .file {
|
> .file {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -89,7 +87,6 @@ const props = defineProps<{
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
|
||||||
grid-gap: 12px;
|
grid-gap: 12px;
|
||||||
margin: var(--margin) 0;
|
|
||||||
|
|
||||||
> .file {
|
> .file {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkA :to="`/play/${flash.id}`" class="vhpxefrk _block" tabindex="-1">
|
<MkA :to="`/play/${flash.id}`" class="vhpxefrk _panel" tabindex="-1">
|
||||||
<article>
|
<article>
|
||||||
<header>
|
<header>
|
||||||
<h1 :title="flash.title">{{ flash.title }}</h1>
|
<h1 :title="flash.title">{{ flash.title }}</h1>
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ssazuxis">
|
<div class="ssazuxis">
|
||||||
<header class="_button" :style="{ background: bg }" @click="showBody = !showBody">
|
<header class="_button" :style="{ background: bg }" @click="showBody = !showBody">
|
||||||
<div class="title"><slot name="header"></slot></div>
|
<div class="title"><div><slot name="header"></slot></div></div>
|
||||||
<div class="divider"></div>
|
<div class="divider"></div>
|
||||||
<button class="_button">
|
<button class="_button">
|
||||||
<template v-if="showBody"><i class="ti ti-chevron-up"></i></template>
|
<template v-if="showBody"><i class="ti ti-chevron-up"></i></template>
|
||||||
@@ -25,8 +25,9 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
import { miLocalStorage } from '@/local-storage';
|
||||||
|
|
||||||
const localStoragePrefix = 'ui:folder:';
|
const miLocalStoragePrefix = 'ui:folder:' as const;
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
props: {
|
props: {
|
||||||
@@ -44,13 +45,13 @@ export default defineComponent({
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
bg: null,
|
bg: null,
|
||||||
showBody: (this.persistKey && localStorage.getItem(localStoragePrefix + this.persistKey)) ? localStorage.getItem(localStoragePrefix + this.persistKey) === 't' : this.expanded,
|
showBody: (this.persistKey && miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`)) ? (miLocalStorage.getItem(`${miLocalStoragePrefix}${this.persistKey}`) === 't') : this.expanded,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
showBody() {
|
showBody() {
|
||||||
if (this.persistKey) {
|
if (this.persistKey) {
|
||||||
localStorage.setItem(localStoragePrefix + this.persistKey, this.showBody ? 't' : 'f');
|
miLocalStorage.setItem(`${miLocalStoragePrefix}${this.persistKey}`, this.showBody ? 't' : 'f');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -126,14 +127,6 @@ export default defineComponent({
|
|||||||
place-content: center;
|
place-content: center;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 12px 16px 12px 0;
|
padding: 12px 16px 12px 0;
|
||||||
|
|
||||||
> i {
|
|
||||||
margin-right: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:empty {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
> .divider {
|
> .divider {
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<XModalWindow ref="dialog"
|
<MkModalWindow
|
||||||
|
ref="dialog"
|
||||||
:width="370"
|
:width="370"
|
||||||
:height="400"
|
:height="400"
|
||||||
@close="dialog.close()"
|
@close="dialog.close()"
|
||||||
@@ -8,18 +9,18 @@
|
|||||||
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
<template #header>{{ i18n.ts.forgotPassword }}</template>
|
||||||
|
|
||||||
<form v-if="instance.enableEmail" class="bafeceda" @submit.prevent="onSubmit">
|
<form v-if="instance.enableEmail" class="bafeceda" @submit.prevent="onSubmit">
|
||||||
<div class="main _formRoot">
|
<div class="main _gaps_m">
|
||||||
<MkInput v-model="username" class="_formBlock" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required>
|
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" :spellcheck="false" autofocus required>
|
||||||
<template #label>{{ i18n.ts.username }}</template>
|
<template #label>{{ i18n.ts.username }}</template>
|
||||||
<template #prefix>@</template>
|
<template #prefix>@</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkInput v-model="email" class="_formBlock" type="email" :spellcheck="false" required>
|
<MkInput v-model="email" type="email" :spellcheck="false" required>
|
||||||
<template #label>{{ i18n.ts.emailAddress }}</template>
|
<template #label>{{ i18n.ts.emailAddress }}</template>
|
||||||
<template #caption>{{ i18n.ts._forgotPassword.enterEmail }}</template>
|
<template #caption>{{ i18n.ts._forgotPassword.enterEmail }}</template>
|
||||||
</MkInput>
|
</MkInput>
|
||||||
|
|
||||||
<MkButton class="_formBlock" type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ i18n.ts.send }}</MkButton>
|
<MkButton type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ i18n.ts.send }}</MkButton>
|
||||||
</div>
|
</div>
|
||||||
<div class="sub">
|
<div class="sub">
|
||||||
<MkA to="/about" class="_link">{{ i18n.ts._forgotPassword.ifNoEmail }}</MkA>
|
<MkA to="/about" class="_link">{{ i18n.ts._forgotPassword.ifNoEmail }}</MkA>
|
||||||
@@ -28,14 +29,14 @@
|
|||||||
<div v-else class="bafecedb">
|
<div v-else class="bafecedb">
|
||||||
{{ i18n.ts._forgotPassword.contactAdmin }}
|
{{ i18n.ts._forgotPassword.contactAdmin }}
|
||||||
</div>
|
</div>
|
||||||
</XModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { } from 'vue';
|
import { } from 'vue';
|
||||||
import XModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkInput from '@/components/form/input.vue';
|
import MkInput from '@/components/MkInput.vue';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { instance } from '@/instance';
|
import { instance } from '@/instance';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
@@ -45,7 +46,7 @@ const emit = defineEmits<{
|
|||||||
(ev: 'closed'): void;
|
(ev: 'closed'): void;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let dialog: InstanceType<typeof XModalWindow> = $ref();
|
let dialog: InstanceType<typeof MkModalWindow> = $ref();
|
||||||
|
|
||||||
let username = $ref('');
|
let username = $ref('');
|
||||||
let email = $ref('');
|
let email = $ref('');
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<XModalWindow
|
<MkModalWindow
|
||||||
ref="dialog"
|
ref="dialog"
|
||||||
:width="450"
|
:width="450"
|
||||||
:can-close="false"
|
:can-close="false"
|
||||||
@@ -15,66 +15,66 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<MkSpacer :margin-min="20" :margin-max="32">
|
<MkSpacer :margin-min="20" :margin-max="32">
|
||||||
<div class="xkpnjxcv _formRoot">
|
<div class="xkpnjxcv _gaps_m">
|
||||||
<template v-for="item in Object.keys(form).filter(item => !form[item].hidden)">
|
<template v-for="item in Object.keys(form).filter(item => !form[item].hidden)">
|
||||||
<FormInput v-if="form[item].type === 'number'" v-model="values[item]" type="number" :step="form[item].step || 1" class="_formBlock">
|
<MkInput v-if="form[item].type === 'number'" v-model="values[item]" type="number" :step="form[item].step || 1">
|
||||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||||
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
||||||
</FormInput>
|
</MkInput>
|
||||||
<FormInput v-else-if="form[item].type === 'string' && !form[item].multiline" v-model="values[item]" type="text" class="_formBlock">
|
<MkInput v-else-if="form[item].type === 'string' && !form[item].multiline" v-model="values[item]" type="text">
|
||||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||||
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
||||||
</FormInput>
|
</MkInput>
|
||||||
<FormTextarea v-else-if="form[item].type === 'string' && form[item].multiline" v-model="values[item]" class="_formBlock">
|
<MkTextarea v-else-if="form[item].type === 'string' && form[item].multiline" v-model="values[item]">
|
||||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||||
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
||||||
</FormTextarea>
|
</MkTextarea>
|
||||||
<FormSwitch v-else-if="form[item].type === 'boolean'" v-model="values[item]" class="_formBlock">
|
<MkSwitch v-else-if="form[item].type === 'boolean'" v-model="values[item]">
|
||||||
<span v-text="form[item].label || item"></span>
|
<span v-text="form[item].label || item"></span>
|
||||||
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
||||||
</FormSwitch>
|
</MkSwitch>
|
||||||
<FormSelect v-else-if="form[item].type === 'enum'" v-model="values[item]" class="_formBlock">
|
<MkSelect v-else-if="form[item].type === 'enum'" v-model="values[item]">
|
||||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||||
<option v-for="item in form[item].enum" :key="item.value" :value="item.value">{{ item.label }}</option>
|
<option v-for="item in form[item].enum" :key="item.value" :value="item.value">{{ item.label }}</option>
|
||||||
</FormSelect>
|
</MkSelect>
|
||||||
<FormRadios v-else-if="form[item].type === 'radio'" v-model="values[item]" class="_formBlock">
|
<MkRadios v-else-if="form[item].type === 'radio'" v-model="values[item]">
|
||||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||||
<option v-for="item in form[item].options" :key="item.value" :value="item.value">{{ item.label }}</option>
|
<option v-for="item in form[item].options" :key="item.value" :value="item.value">{{ item.label }}</option>
|
||||||
</FormRadios>
|
</MkRadios>
|
||||||
<FormRange v-else-if="form[item].type === 'range'" v-model="values[item]" :min="form[item].min" :max="form[item].max" :step="form[item].step" :text-converter="form[item].textConverter" class="_formBlock">
|
<MkRange v-else-if="form[item].type === 'range'" v-model="values[item]" :min="form[item].min" :max="form[item].max" :step="form[item].step" :text-converter="form[item].textConverter">
|
||||||
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
<template #label><span v-text="form[item].label || item"></span><span v-if="form[item].required === false"> ({{ $ts.optional }})</span></template>
|
||||||
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
<template v-if="form[item].description" #caption>{{ form[item].description }}</template>
|
||||||
</FormRange>
|
</MkRange>
|
||||||
<MkButton v-else-if="form[item].type === 'button'" class="_formBlock" @click="form[item].action($event, values)">
|
<MkButton v-else-if="form[item].type === 'button'" @click="form[item].action($event, values)">
|
||||||
<span v-text="form[item].content || item"></span>
|
<span v-text="form[item].content || item"></span>
|
||||||
</MkButton>
|
</MkButton>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</MkSpacer>
|
</MkSpacer>
|
||||||
</XModalWindow>
|
</MkModalWindow>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent } from 'vue';
|
import { defineComponent } from 'vue';
|
||||||
import FormInput from './form/input.vue';
|
import MkInput from './MkInput.vue';
|
||||||
import FormTextarea from './form/textarea.vue';
|
import MkTextarea from './MkTextarea.vue';
|
||||||
import FormSwitch from './form/switch.vue';
|
import MkSwitch from './MkSwitch.vue';
|
||||||
import FormSelect from './form/select.vue';
|
import MkSelect from './MkSelect.vue';
|
||||||
import FormRange from './form/range.vue';
|
import MkRange from './MkRange.vue';
|
||||||
import MkButton from './MkButton.vue';
|
import MkButton from './MkButton.vue';
|
||||||
import FormRadios from './form/radios.vue';
|
import MkRadios from './MkRadios.vue';
|
||||||
import XModalWindow from '@/components/MkModalWindow.vue';
|
import MkModalWindow from '@/components/MkModalWindow.vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
components: {
|
components: {
|
||||||
XModalWindow,
|
MkModalWindow,
|
||||||
FormInput,
|
MkInput,
|
||||||
FormTextarea,
|
MkTextarea,
|
||||||
FormSwitch,
|
MkSwitch,
|
||||||
FormSelect,
|
MkSelect,
|
||||||
FormRange,
|
MkRange,
|
||||||
MkButton,
|
MkButton,
|
||||||
FormRadios,
|
MkRadios,
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
import { markRaw, version as vueVersion, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import { enUS } from 'date-fns/locale';
|
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
import { MatrixController, MatrixElement } from 'chartjs-chart-matrix';
|
import { MatrixController, MatrixElement } from 'chartjs-chart-matrix';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
@@ -149,7 +148,9 @@ async function renderChart() {
|
|||||||
round: 'week',
|
round: 'week',
|
||||||
isoWeekday: 0,
|
isoWeekday: 0,
|
||||||
displayFormats: {
|
displayFormats: {
|
||||||
week: 'MMM dd',
|
day: 'M/d',
|
||||||
|
month: 'Y/M',
|
||||||
|
week: 'M/d',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
|
@@ -78,7 +78,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { onMounted } from 'vue';
|
import { onMounted } from 'vue';
|
||||||
import { Chart } from 'chart.js';
|
import { Chart } from 'chart.js';
|
||||||
import MkSelect from '@/components/form/select.vue';
|
import MkSelect from '@/components/MkSelect.vue';
|
||||||
import MkChart from '@/components/MkChart.vue';
|
import MkChart from '@/components/MkChart.vue';
|
||||||
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
|
import { useChartTooltip } from '@/scripts/use-chart-tooltip';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
|
@@ -31,7 +31,7 @@
|
|||||||
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
<span v-if="item.indicate" class="indicator"><i class="_indicatorCircle"></i></span>
|
||||||
</button>
|
</button>
|
||||||
<span v-else-if="item.type === 'switch'" :tabindex="i" class="item" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
<span v-else-if="item.type === 'switch'" :tabindex="i" class="item" @mouseenter.passive="onItemMouseEnter(item)" @mouseleave.passive="onItemMouseLeave(item)">
|
||||||
<FormSwitch v-model="item.ref" :disabled="item.disabled" class="form-switch">{{ item.text }}</FormSwitch>
|
<MkSwitch v-model="item.ref" :disabled="item.disabled" class="form-switch">{{ item.text }}</MkSwitch>
|
||||||
</span>
|
</span>
|
||||||
<button v-else-if="item.type === 'parent'" :tabindex="i" class="_button item parent" :class="{ childShowing: childShowingItem === item }" @mouseenter="showChildren(item, $event)">
|
<button v-else-if="item.type === 'parent'" :tabindex="i" class="_button item parent" :class="{ childShowing: childShowingItem === item }" @mouseenter="showChildren(item, $event)">
|
||||||
<i v-if="item.icon" class="ti-fw" :class="item.icon"></i>
|
<i v-if="item.icon" class="ti-fw" :class="item.icon"></i>
|
||||||
@@ -58,7 +58,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
import { defineAsyncComponent, nextTick, onBeforeUnmount, onMounted, onUnmounted, Ref, ref, watch } from 'vue';
|
||||||
import { focusPrev, focusNext } from '@/scripts/focus';
|
import { focusPrev, focusNext } from '@/scripts/focus';
|
||||||
import FormSwitch from '@/components/form/switch.vue';
|
import MkSwitch from '@/components/MkSwitch.vue';
|
||||||
import { MenuItem, InnerMenuItem, MenuPending, MenuAction } from '@/types/menu';
|
import { MenuItem, InnerMenuItem, MenuPending, MenuAction } from '@/types/menu';
|
||||||
import * as os from '@/os';
|
import * as os from '@/os';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
@@ -251,17 +251,18 @@ onBeforeUnmount(() => {
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
background: #d42e2e;
|
background: #d42e2e !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&:active,
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--fgOnAccent);
|
color: var(--fgOnAccent) !important;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
background: var(--accent);
|
background: var(--accent) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<Transition :name="transitionName" :duration="transitionDuration" appear @after-leave="emit('closed')" @enter="emit('opening')" @after-enter="onOpened">
|
<Transition :name="transitionName" :duration="transitionDuration" appear @after-leave="emit('closed')" @enter="emit('opening')" @after-enter="onOpened">
|
||||||
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" class="qzhlnise" :class="{ drawer: type === 'drawer', dialog: type === 'dialog' || type === 'dialog:top', popup: type === 'popup' }" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
<div v-show="manualShowing != null ? manualShowing : showing" v-hotkey.global="keymap" class="qzhlnise" :class="{ drawer: type === 'drawer', dialog: type === 'dialog' || type === 'dialog:top', popup: type === 'popup' }" :style="{ zIndex, pointerEvents: (manualShowing != null ? manualShowing : showing) ? 'auto' : 'none', '--transformOrigin': transformOrigin }">
|
||||||
<div class="bg _modalBg" :class="{ transparent: transparentBg && (type === 'popup') }" :style="{ zIndex }" @click="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
|
<div class="bg _modalBg" :class="{ transparent: transparentBg && (type === 'popup') }" :style="{ zIndex }" @click="onBgClick" @mousedown="onBgClick" @contextmenu.prevent.stop="() => {}"></div>
|
||||||
<div ref="content" class="content" :class="{ fixed, top: type === 'dialog:top' }" :style="{ zIndex }" @click.self="onBgClick">
|
<div ref="content" class="content" :class="{ fixed, top: type === 'dialog:top' }" :style="{ zIndex }" @click.self="onBgClick">
|
||||||
<slot :max-height="maxHeight" :type="type"></slot>
|
<slot :max-height="maxHeight" :type="type"></slot>
|
||||||
</div>
|
</div>
|
||||||
@@ -63,6 +63,7 @@ let transformOrigin = $ref('center');
|
|||||||
let showing = $ref(true);
|
let showing = $ref(true);
|
||||||
let content = $shallowRef<HTMLElement>();
|
let content = $shallowRef<HTMLElement>();
|
||||||
const zIndex = os.claimZIndex(props.zPriority);
|
const zIndex = os.claimZIndex(props.zPriority);
|
||||||
|
let useSendAnime = $ref(false);
|
||||||
const type = $computed<ModalTypes>(() => {
|
const type = $computed<ModalTypes>(() => {
|
||||||
if (props.preferType === 'auto') {
|
if (props.preferType === 'auto') {
|
||||||
if (!defaultStore.state.disableDrawer && isTouchUsing && deviceKind === 'smartphone') {
|
if (!defaultStore.state.disableDrawer && isTouchUsing && deviceKind === 'smartphone') {
|
||||||
@@ -74,15 +75,34 @@ const type = $computed<ModalTypes>(() => {
|
|||||||
return props.preferType!;
|
return props.preferType!;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let transitionName = $ref(defaultStore.state.animation ? (type === 'drawer') ? 'modal-drawer' : (type === 'popup') ? 'modal-popup' : 'modal' : '');
|
let transitionName = $computed((() =>
|
||||||
let transitionDuration = $ref(defaultStore.state.animation ? 200 : 0);
|
defaultStore.state.animation
|
||||||
|
? useSendAnime
|
||||||
|
? 'send'
|
||||||
|
: type === 'drawer'
|
||||||
|
? 'modal-drawer'
|
||||||
|
: type === 'popup'
|
||||||
|
? 'modal-popup'
|
||||||
|
: 'modal'
|
||||||
|
: ''
|
||||||
|
));
|
||||||
|
let transitionDuration = $computed((() =>
|
||||||
|
transitionName === 'send'
|
||||||
|
? 400
|
||||||
|
: transitionName === 'modal-popup'
|
||||||
|
? 100
|
||||||
|
: transitionName === 'modal'
|
||||||
|
? 200
|
||||||
|
: transitionName === 'modal-drawer'
|
||||||
|
? 200
|
||||||
|
: 0
|
||||||
|
));
|
||||||
|
|
||||||
let contentClicking = false;
|
let contentClicking = false;
|
||||||
|
|
||||||
function close(opts: { useSendAnimation?: boolean } = {}) {
|
function close(opts: { useSendAnimation?: boolean } = {}) {
|
||||||
if (opts.useSendAnimation) {
|
if (opts.useSendAnimation) {
|
||||||
transitionName = 'send';
|
useSendAnime = true;
|
||||||
transitionDuration = 400;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line vue/no-mutating-props
|
// eslint-disable-next-line vue/no-mutating-props
|
||||||
@@ -267,9 +287,8 @@ defineExpose({
|
|||||||
}
|
}
|
||||||
|
|
||||||
> .content {
|
> .content {
|
||||||
transform-style: preserve-3d;
|
transform: translateY(0px);
|
||||||
transform: perspective(50cm) translateZ(0px) translateY(0px) rotateX(0deg);
|
transition: opacity 0.3s ease-in, transform 0.3s cubic-bezier(.5,-0.5,1,.5) !important;
|
||||||
transition: opacity 0.4s cubic-bezier(.5,-0.5,.75,1), transform 0.4s cubic-bezier(.5,-0.5,.75,1) !important;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.send-enter-from, .send-leave-to {
|
.send-enter-from, .send-leave-to {
|
||||||
@@ -280,8 +299,7 @@ defineExpose({
|
|||||||
> .content {
|
> .content {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform-style: preserve-3d;
|
transform: translateY(-300px);
|
||||||
transform: perspective(50cm) translateZ(-300px) translateY(-200px) rotateX(40deg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,12 +328,12 @@ defineExpose({
|
|||||||
|
|
||||||
.modal-popup-enter-active, .modal-popup-leave-active {
|
.modal-popup-enter-active, .modal-popup-leave-active {
|
||||||
> .bg {
|
> .bg {
|
||||||
transition: opacity 0.2s !important;
|
transition: opacity 0.1s !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .content {
|
> .content {
|
||||||
transform-origin: var(--transformOrigin);
|
transform-origin: var(--transformOrigin);
|
||||||
transition: opacity 0.2s cubic-bezier(0, 0, 0.2, 1), transform 0.2s cubic-bezier(0, 0, 0.2, 1) !important;
|
transition: opacity 0.1s cubic-bezier(0, 0, 0.2, 1), transform 0.1s cubic-bezier(0, 0, 0.2, 1) !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.modal-popup-enter-from, .modal-popup-leave-to {
|
.modal-popup-enter-from, .modal-popup-leave-to {
|
||||||
@@ -383,7 +401,6 @@ defineExpose({
|
|||||||
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 32px, rgba(0,0,0,1) calc(100% - 32px), rgba(0,0,0,0) 100%);
|
mask-image: linear-gradient(0deg, rgba(0,0,0,0) 0%, rgba(0,0,0,1) 32px, rgba(0,0,0,1) calc(100% - 32px), rgba(0,0,0,0) 100%);
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
container-type: inline-size;
|
|
||||||
|
|
||||||
@media (max-width: 500px) {
|
@media (max-width: 500px) {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
|
<MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
|
||||||
<div ref="rootEl" class="hrmcaedk _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
|
<div ref="rootEl" class="hrmcaedk" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
|
||||||
<div class="header" @contextmenu="onContextmenu">
|
<div class="header" @contextmenu="onContextmenu">
|
||||||
<button v-if="history.length > 0" v-tooltip="$ts.goBack" class="_button" @click="back()"><i class="ti ti-arrow-left"></i></button>
|
<button v-if="history.length > 0" v-tooltip="$ts.goBack" class="_button" @click="back()"><i class="ti ti-arrow-left"></i></button>
|
||||||
<span v-else style="display: inline-block; width: 20px"></span>
|
<span v-else style="display: inline-block; width: 20px"></span>
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<MkModal ref="modal" :prefer-type="'dialog'" @click="onBgClick" @closed="$emit('closed')">
|
<MkModal ref="modal" :prefer-type="'dialog'" @click="onBgClick" @closed="$emit('closed')">
|
||||||
<div ref="rootEl" class="ebkgoccj _narrow_" :style="{ width: `${width}px`, height: scroll ? (height ? `${height}px` : null) : (height ? `min(${height}px, 100%)` : '100%') }" @keydown="onKeydown">
|
<div ref="rootEl" class="ebkgoccj" :style="{ width: `${width}px`, height: scroll ? (height ? `${height}px` : null) : (height ? `min(${height}px, 100%)` : '100%') }" @keydown="onKeydown">
|
||||||
<div ref="headerEl" class="header">
|
<div ref="headerEl" class="header">
|
||||||
<button v-if="withOkButton" class="_button" @click="$emit('close')"><i class="ti ti-x"></i></button>
|
<button v-if="withOkButton" class="_button" @click="$emit('close')"><i class="ti ti-x"></i></button>
|
||||||
<span class="title">
|
<span class="title">
|
||||||
@@ -89,6 +89,7 @@ defineExpose({
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
contain: content;
|
contain: content;
|
||||||
|
container-type: inline-size;
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
|
|
||||||
--root-margin: 24px;
|
--root-margin: 24px;
|
||||||
|
@@ -13,7 +13,7 @@
|
|||||||
<div v-if="appearNote._prId_" class="info"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="ti ti-x"></i></button></div>
|
<div v-if="appearNote._prId_" class="info"><i class="fas fa-bullhorn"></i> {{ i18n.ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ i18n.ts.hideThisNote }} <i class="ti ti-x"></i></button></div>
|
||||||
<div v-if="appearNote._featuredId_" class="info"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>
|
<div v-if="appearNote._featuredId_" class="info"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>
|
||||||
<div v-if="isRenote" class="renote">
|
<div v-if="isRenote" class="renote">
|
||||||
<MkAvatar class="avatar" :user="note.user"/>
|
<MkAvatar v-once class="avatar" :user="note.user"/>
|
||||||
<i class="ti ti-repeat"></i>
|
<i class="ti ti-repeat"></i>
|
||||||
<I18n :src="i18n.ts.renotedBy" tag="span">
|
<I18n :src="i18n.ts.renotedBy" tag="span">
|
||||||
<template #user>
|
<template #user>
|
||||||
@@ -27,11 +27,16 @@
|
|||||||
<i v-if="isMyRenote" class="ti ti-dots dropdownIcon"></i>
|
<i v-if="isMyRenote" class="ti ti-dots dropdownIcon"></i>
|
||||||
<MkTime :time="note.createdAt"/>
|
<MkTime :time="note.createdAt"/>
|
||||||
</button>
|
</button>
|
||||||
<MkVisibility :note="note"/>
|
<span v-if="note.visibility !== 'public'" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility[note.visibility]">
|
||||||
|
<i v-if="note.visibility === 'home'" class="ti ti-home"></i>
|
||||||
|
<i v-else-if="note.visibility === 'followers'" class="ti ti-lock-open"></i>
|
||||||
|
<i v-else-if="note.visibility === 'specified'" ref="specified" class="ti ti-mail"></i>
|
||||||
|
</span>
|
||||||
|
<span v-if="note.localOnly" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility['localOnly']"><i class="ti ti-world-off"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<article class="article" @contextmenu.stop="onContextmenu">
|
<article class="article" @contextmenu.stop="onContextmenu">
|
||||||
<MkAvatar class="avatar" :user="appearNote.user"/>
|
<MkAvatar v-once class="avatar" :user="appearNote.user"/>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<MkNoteHeader class="header" :note="appearNote" :mini="true"/>
|
<MkNoteHeader class="header" :note="appearNote" :mini="true"/>
|
||||||
<MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
|
<MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
|
||||||
@@ -44,7 +49,7 @@
|
|||||||
<div class="text">
|
<div class="text">
|
||||||
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ i18n.ts.private }})</span>
|
||||||
<MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
|
<MkA v-if="appearNote.replyId" class="reply" :to="`/notes/${appearNote.replyId}`"><i class="ti ti-arrow-back-up"></i></MkA>
|
||||||
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i"/>
|
<Mfm v-if="appearNote.text" v-once :text="appearNote.text" :author="appearNote.user" :i="$i"/>
|
||||||
<a v-if="appearNote.renote != null" class="rp">RN:</a>
|
<a v-if="appearNote.renote != null" class="rp">RN:</a>
|
||||||
<div v-if="translating || translation" class="translation">
|
<div v-if="translating || translation" class="translation">
|
||||||
<MkLoading v-if="translating" mini/>
|
<MkLoading v-if="translating" mini/>
|
||||||
@@ -75,14 +80,25 @@
|
|||||||
<i class="ti ti-arrow-back-up"></i>
|
<i class="ti ti-arrow-back-up"></i>
|
||||||
<p v-if="appearNote.repliesCount > 0" class="count">{{ appearNote.repliesCount }}</p>
|
<p v-if="appearNote.repliesCount > 0" class="count">{{ appearNote.repliesCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<MkRenoteButton ref="renoteButton" class="button" :note="appearNote" :count="appearNote.renoteCount"/>
|
<button
|
||||||
<button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @click="react()">
|
v-if="canRenote"
|
||||||
|
ref="renoteButton"
|
||||||
|
class="button _button"
|
||||||
|
@mousedown="renote()"
|
||||||
|
>
|
||||||
|
<i class="ti ti-repeat"></i>
|
||||||
|
<p v-if="appearNote.renoteCount > 0" class="count">{{ appearNote.renoteCount }}</p>
|
||||||
|
</button>
|
||||||
|
<button v-else class="button _button" disabled>
|
||||||
|
<i class="ti ti-ban"></i>
|
||||||
|
</button>
|
||||||
|
<button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()">
|
||||||
<i class="ti ti-plus"></i>
|
<i class="ti ti-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
|
<button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
|
||||||
<i class="ti ti-minus"></i>
|
<i class="ti ti-minus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button ref="menuButton" class="button _button" @click="menu()">
|
<button ref="menuButton" class="button _button" @mousedown="menu()">
|
||||||
<i class="ti ti-dots"></i>
|
<i class="ti ti-dots"></i>
|
||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -111,10 +127,9 @@ import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
|||||||
import MkMediaList from '@/components/MkMediaList.vue';
|
import MkMediaList from '@/components/MkMediaList.vue';
|
||||||
import MkCwButton from '@/components/MkCwButton.vue';
|
import MkCwButton from '@/components/MkCwButton.vue';
|
||||||
import MkPoll from '@/components/MkPoll.vue';
|
import MkPoll from '@/components/MkPoll.vue';
|
||||||
import MkRenoteButton from '@/components/MkRenoteButton.vue';
|
import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
|
||||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||||
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
||||||
import MkVisibility from '@/components/MkVisibility.vue';
|
|
||||||
import { pleaseLogin } from '@/scripts/please-login';
|
import { pleaseLogin } from '@/scripts/please-login';
|
||||||
import { focusPrev, focusNext } from '@/scripts/focus';
|
import { focusPrev, focusNext } from '@/scripts/focus';
|
||||||
import { checkWordMute } from '@/scripts/check-word-mute';
|
import { checkWordMute } from '@/scripts/check-word-mute';
|
||||||
@@ -128,6 +143,7 @@ import { i18n } from '@/i18n';
|
|||||||
import { getNoteMenu } from '@/scripts/get-note-menu';
|
import { getNoteMenu } from '@/scripts/get-note-menu';
|
||||||
import { useNoteCapture } from '@/scripts/use-note-capture';
|
import { useNoteCapture } from '@/scripts/use-note-capture';
|
||||||
import { deepClone } from '@/scripts/clone';
|
import { deepClone } from '@/scripts/clone';
|
||||||
|
import { useTooltip } from '@/scripts/use-tooltip';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
note: misskey.entities.Note;
|
note: misskey.entities.Note;
|
||||||
@@ -158,7 +174,7 @@ const isRenote = (
|
|||||||
|
|
||||||
const el = shallowRef<HTMLElement>();
|
const el = shallowRef<HTMLElement>();
|
||||||
const menuButton = shallowRef<HTMLElement>();
|
const menuButton = shallowRef<HTMLElement>();
|
||||||
const renoteButton = shallowRef<InstanceType<typeof MkRenoteButton>>();
|
const renoteButton = shallowRef<HTMLElement>();
|
||||||
const renoteTime = shallowRef<HTMLElement>();
|
const renoteTime = shallowRef<HTMLElement>();
|
||||||
const reactButton = shallowRef<HTMLElement>();
|
const reactButton = shallowRef<HTMLElement>();
|
||||||
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
|
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
|
||||||
@@ -175,6 +191,7 @@ const translation = ref(null);
|
|||||||
const translating = ref(false);
|
const translating = ref(false);
|
||||||
const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null;
|
const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null;
|
||||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
|
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
|
||||||
|
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || appearNote.userId === $i.id);
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
'r': () => reply(true),
|
'r': () => reply(true),
|
||||||
@@ -193,6 +210,47 @@ useNoteCapture({
|
|||||||
isDeletedRef: isDeleted,
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useTooltip(renoteButton, async (showing) => {
|
||||||
|
const renotes = await os.api('notes/renotes', {
|
||||||
|
noteId: appearNote.id,
|
||||||
|
limit: 11,
|
||||||
|
});
|
||||||
|
|
||||||
|
const users = renotes.map(x => x.user);
|
||||||
|
|
||||||
|
if (users.length < 1) return;
|
||||||
|
|
||||||
|
os.popup(MkUsersTooltip, {
|
||||||
|
showing,
|
||||||
|
users,
|
||||||
|
count: appearNote.renoteCount,
|
||||||
|
targetElement: renoteButton.value,
|
||||||
|
}, {}, 'closed');
|
||||||
|
});
|
||||||
|
|
||||||
|
function renote(viaKeyboard = false) {
|
||||||
|
pleaseLogin();
|
||||||
|
os.popupMenu([{
|
||||||
|
text: i18n.ts.renote,
|
||||||
|
icon: 'ti ti-repeat',
|
||||||
|
action: () => {
|
||||||
|
os.api('notes/create', {
|
||||||
|
renoteId: appearNote.id,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
text: i18n.ts.quote,
|
||||||
|
icon: 'ti ti-quote',
|
||||||
|
action: () => {
|
||||||
|
os.post({
|
||||||
|
renote: appearNote,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}], renoteButton.value, {
|
||||||
|
viaKeyboard,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function reply(viaKeyboard = false): void {
|
function reply(viaKeyboard = false): void {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
os.post({
|
os.post({
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
v-show="!isDeleted"
|
v-show="!isDeleted"
|
||||||
ref="el"
|
ref="el"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
class="lxwezrsl _block"
|
class="lxwezrsl"
|
||||||
:tabindex="!isDeleted ? '-1' : null"
|
:tabindex="!isDeleted ? '-1' : null"
|
||||||
:class="{ renote: isRenote }"
|
:class="{ renote: isRenote }"
|
||||||
>
|
>
|
||||||
@@ -25,7 +25,12 @@
|
|||||||
<i v-if="isMyRenote" class="ti ti-dots dropdownIcon"></i>
|
<i v-if="isMyRenote" class="ti ti-dots dropdownIcon"></i>
|
||||||
<MkTime :time="note.createdAt"/>
|
<MkTime :time="note.createdAt"/>
|
||||||
</button>
|
</button>
|
||||||
<MkVisibility :note="note"/>
|
<span v-if="note.visibility !== 'public'" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility[note.visibility]">
|
||||||
|
<i v-if="note.visibility === 'home'" class="ti ti-home"></i>
|
||||||
|
<i v-else-if="note.visibility === 'followers'" class="ti ti-lock-open"></i>
|
||||||
|
<i v-else-if="note.visibility === 'specified'" ref="specified" class="ti ti-mail"></i>
|
||||||
|
</span>
|
||||||
|
<span v-if="note.localOnly" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility['localOnly']"><i class="ti ti-world-off"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<article class="article" @contextmenu.stop="onContextmenu">
|
<article class="article" @contextmenu.stop="onContextmenu">
|
||||||
@@ -38,7 +43,12 @@
|
|||||||
</MkA>
|
</MkA>
|
||||||
<span v-if="appearNote.user.isBot" class="is-bot">bot</span>
|
<span v-if="appearNote.user.isBot" class="is-bot">bot</span>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<MkVisibility :note="appearNote"/>
|
<span v-if="appearNote.visibility !== 'public'" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility[appearNote.visibility]">
|
||||||
|
<i v-if="appearNote.visibility === 'home'" class="ti ti-home"></i>
|
||||||
|
<i v-else-if="appearNote.visibility === 'followers'" class="ti ti-lock-open"></i>
|
||||||
|
<i v-else-if="appearNote.visibility === 'specified'" ref="specified" class="ti ti-mail"></i>
|
||||||
|
</span>
|
||||||
|
<span v-if="appearNote.localOnly" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility['localOnly']"><i class="ti ti-world-off"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="username"><MkAcct :user="appearNote.user"/></div>
|
<div class="username"><MkAcct :user="appearNote.user"/></div>
|
||||||
@@ -85,14 +95,25 @@
|
|||||||
<i class="ti ti-arrow-back-up"></i>
|
<i class="ti ti-arrow-back-up"></i>
|
||||||
<p v-if="appearNote.repliesCount > 0" class="count">{{ appearNote.repliesCount }}</p>
|
<p v-if="appearNote.repliesCount > 0" class="count">{{ appearNote.repliesCount }}</p>
|
||||||
</button>
|
</button>
|
||||||
<MkRenoteButton ref="renoteButton" class="button" :note="appearNote" :count="appearNote.renoteCount"/>
|
<button
|
||||||
<button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @click="react()">
|
v-if="canRenote"
|
||||||
|
ref="renoteButton"
|
||||||
|
class="button _button"
|
||||||
|
@mousedown="renote()"
|
||||||
|
>
|
||||||
|
<i class="ti ti-repeat"></i>
|
||||||
|
<p v-if="appearNote.renoteCount > 0" class="count">{{ appearNote.renoteCount }}</p>
|
||||||
|
</button>
|
||||||
|
<button v-else class="button _button" disabled>
|
||||||
|
<i class="ti ti-ban"></i>
|
||||||
|
</button>
|
||||||
|
<button v-if="appearNote.myReaction == null" ref="reactButton" class="button _button" @mousedown="react()">
|
||||||
<i class="ti ti-plus"></i>
|
<i class="ti ti-plus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
|
<button v-if="appearNote.myReaction != null" ref="reactButton" class="button _button reacted" @click="undoReact(appearNote)">
|
||||||
<i class="ti ti-minus"></i>
|
<i class="ti ti-minus"></i>
|
||||||
</button>
|
</button>
|
||||||
<button ref="menuButton" class="button _button" @click="menu()">
|
<button ref="menuButton" class="button _button" @mousedown="menu()">
|
||||||
<i class="ti ti-dots"></i>
|
<i class="ti ti-dots"></i>
|
||||||
</button>
|
</button>
|
||||||
</footer>
|
</footer>
|
||||||
@@ -121,10 +142,9 @@ import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
|||||||
import MkMediaList from '@/components/MkMediaList.vue';
|
import MkMediaList from '@/components/MkMediaList.vue';
|
||||||
import MkCwButton from '@/components/MkCwButton.vue';
|
import MkCwButton from '@/components/MkCwButton.vue';
|
||||||
import MkPoll from '@/components/MkPoll.vue';
|
import MkPoll from '@/components/MkPoll.vue';
|
||||||
import MkRenoteButton from '@/components/MkRenoteButton.vue';
|
import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
|
||||||
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
import MkUrlPreview from '@/components/MkUrlPreview.vue';
|
||||||
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
import MkInstanceTicker from '@/components/MkInstanceTicker.vue';
|
||||||
import MkVisibility from '@/components/MkVisibility.vue';
|
|
||||||
import { pleaseLogin } from '@/scripts/please-login';
|
import { pleaseLogin } from '@/scripts/please-login';
|
||||||
import { checkWordMute } from '@/scripts/check-word-mute';
|
import { checkWordMute } from '@/scripts/check-word-mute';
|
||||||
import { userPage } from '@/filters/user';
|
import { userPage } from '@/filters/user';
|
||||||
@@ -138,6 +158,7 @@ import { i18n } from '@/i18n';
|
|||||||
import { getNoteMenu } from '@/scripts/get-note-menu';
|
import { getNoteMenu } from '@/scripts/get-note-menu';
|
||||||
import { useNoteCapture } from '@/scripts/use-note-capture';
|
import { useNoteCapture } from '@/scripts/use-note-capture';
|
||||||
import { deepClone } from '@/scripts/clone';
|
import { deepClone } from '@/scripts/clone';
|
||||||
|
import { useTooltip } from '@/scripts/use-tooltip';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
note: misskey.entities.Note;
|
note: misskey.entities.Note;
|
||||||
@@ -168,7 +189,7 @@ const isRenote = (
|
|||||||
|
|
||||||
const el = shallowRef<HTMLElement>();
|
const el = shallowRef<HTMLElement>();
|
||||||
const menuButton = shallowRef<HTMLElement>();
|
const menuButton = shallowRef<HTMLElement>();
|
||||||
const renoteButton = shallowRef<InstanceType<typeof MkRenoteButton>>();
|
const renoteButton = shallowRef<HTMLElement>();
|
||||||
const renoteTime = shallowRef<HTMLElement>();
|
const renoteTime = shallowRef<HTMLElement>();
|
||||||
const reactButton = shallowRef<HTMLElement>();
|
const reactButton = shallowRef<HTMLElement>();
|
||||||
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
|
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
|
||||||
@@ -182,6 +203,7 @@ const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : n
|
|||||||
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
|
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && appearNote.user.instance);
|
||||||
const conversation = ref<misskey.entities.Note[]>([]);
|
const conversation = ref<misskey.entities.Note[]>([]);
|
||||||
const replies = ref<misskey.entities.Note[]>([]);
|
const replies = ref<misskey.entities.Note[]>([]);
|
||||||
|
const canRenote = computed(() => ['public', 'home'].includes(appearNote.visibility) || appearNote.userId === $i.id);
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
'r': () => reply(true),
|
'r': () => reply(true),
|
||||||
@@ -198,6 +220,47 @@ useNoteCapture({
|
|||||||
isDeletedRef: isDeleted,
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useTooltip(renoteButton, async (showing) => {
|
||||||
|
const renotes = await os.api('notes/renotes', {
|
||||||
|
noteId: appearNote.id,
|
||||||
|
limit: 11,
|
||||||
|
});
|
||||||
|
|
||||||
|
const users = renotes.map(x => x.user);
|
||||||
|
|
||||||
|
if (users.length < 1) return;
|
||||||
|
|
||||||
|
os.popup(MkUsersTooltip, {
|
||||||
|
showing,
|
||||||
|
users,
|
||||||
|
count: appearNote.renoteCount,
|
||||||
|
targetElement: renoteButton.value,
|
||||||
|
}, {}, 'closed');
|
||||||
|
});
|
||||||
|
|
||||||
|
function renote(viaKeyboard = false) {
|
||||||
|
pleaseLogin();
|
||||||
|
os.popupMenu([{
|
||||||
|
text: i18n.ts.renote,
|
||||||
|
icon: 'ti ti-repeat',
|
||||||
|
action: () => {
|
||||||
|
os.api('notes/create', {
|
||||||
|
renoteId: appearNote.id,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}, {
|
||||||
|
text: i18n.ts.quote,
|
||||||
|
icon: 'ti ti-quote',
|
||||||
|
action: () => {
|
||||||
|
os.post({
|
||||||
|
renote: appearNote,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}], renoteButton.value, {
|
||||||
|
viaKeyboard,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function reply(viaKeyboard = false): void {
|
function reply(viaKeyboard = false): void {
|
||||||
pleaseLogin();
|
pleaseLogin();
|
||||||
os.post({
|
os.post({
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<header class="kkwtjztg">
|
<header class="kkwtjztg">
|
||||||
<MkA v-user-preview="note.user.id" class="name" :to="userPage(note.user)">
|
<MkA v-once v-user-preview="note.user.id" class="name" :to="userPage(note.user)">
|
||||||
<MkUserName :user="note.user"/>
|
<MkUserName :user="note.user"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<div v-if="note.user.isBot" class="is-bot">bot</div>
|
<div v-if="note.user.isBot" class="is-bot">bot</div>
|
||||||
@@ -9,7 +9,12 @@
|
|||||||
<MkA class="created-at" :to="notePage(note)">
|
<MkA class="created-at" :to="notePage(note)">
|
||||||
<MkTime :time="note.createdAt"/>
|
<MkTime :time="note.createdAt"/>
|
||||||
</MkA>
|
</MkA>
|
||||||
<MkVisibility :note="note"/>
|
<span v-if="note.visibility !== 'public'" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility[note.visibility]">
|
||||||
|
<i v-if="note.visibility === 'home'" class="ti ti-home"></i>
|
||||||
|
<i v-else-if="note.visibility === 'followers'" class="ti ti-lock-open"></i>
|
||||||
|
<i v-else-if="note.visibility === 'specified'" ref="specified" class="ti ti-mail"></i>
|
||||||
|
</span>
|
||||||
|
<span v-if="note.localOnly" style="{ margin-left: 0.5em; }" :title="i18n.ts._visibility['localOnly']"><i class="ti ti-world-off"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
</template>
|
</template>
|
||||||
@@ -17,7 +22,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { } from 'vue';
|
import { } from 'vue';
|
||||||
import * as misskey from 'misskey-js';
|
import * as misskey from 'misskey-js';
|
||||||
import MkVisibility from '@/components/MkVisibility.vue';
|
import { i18n } from '@/i18n';
|
||||||
import { notePage } from '@/filters/note';
|
import { notePage } from '@/filters/note';
|
||||||
import { userPage } from '@/filters/user';
|
import { userPage } from '@/filters/user';
|
||||||
|
|
||||||
|