Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ef6bf38a | ||
|
|
b427bf70a8 | ||
|
|
c75fc266e9 | ||
|
|
e98740c285 | ||
|
|
56b23a64a3 | ||
|
|
ee5b417354 | ||
|
|
2f48d109dd | ||
|
|
784fc7b3f5 | ||
|
|
b55d26387b | ||
|
|
9ddf62d8b7 | ||
|
|
a8feed1eff | ||
|
|
f5bfc6f0c1 | ||
|
|
ee03ab8d2c | ||
|
|
3c7e1ff92e | ||
|
|
ac7e2ecb59 | ||
|
|
f28aea9e30 | ||
|
|
1ac7c154d7 | ||
|
|
ef860a8f84 | ||
|
|
f6f269194f | ||
|
|
e1d41063cd | ||
|
|
5d02405a98 | ||
|
|
998c2b692a | ||
|
|
19c0027605 | ||
|
|
9349f72227 | ||
|
|
5af8b77d28 | ||
|
|
f74d9c7ed0 | ||
|
|
7d9c273dac | ||
|
|
f2da79ad43 | ||
|
|
73a1372940 | ||
|
|
0138c3b00e | ||
|
|
6f33be6c75 | ||
|
|
3004fe573d | ||
|
|
040f9927dd | ||
|
|
abc1bdf218 | ||
|
|
e73e56be8f | ||
|
|
b0616b52ea | ||
|
|
6b6b767199 | ||
|
|
e1bdecb9c1 | ||
|
|
a32c6267be | ||
|
|
54df243b90 | ||
|
|
b44597d5d8 | ||
|
|
7b70b6c3cd | ||
|
|
5cc0219ff2 | ||
|
|
4a0b0b135a | ||
|
|
8bd2d6328a | ||
|
|
9351fb9617 | ||
|
|
7b29e36d64 | ||
|
|
9cc36ef32d | ||
|
|
000f876084 | ||
|
|
2d11c558fa | ||
|
|
ac6b02af40 | ||
|
|
7d91912cfd | ||
|
|
3c504b4b08 | ||
|
|
adad4bcfe3 | ||
|
|
b3e8671dd9 | ||
|
|
0f8c890761 | ||
|
|
512e451f24 | ||
|
|
ca0d53ec5d | ||
|
|
686a709e87 | ||
|
|
83fb629f0b | ||
|
|
35eeeb25e3 | ||
|
|
19035c676c | ||
|
|
61ffe7417c | ||
|
|
7651353f39 | ||
|
|
3f5b81060f | ||
|
|
63dc66769f | ||
|
|
e0fc8cbf8f | ||
|
|
f9d1bc340e | ||
|
|
0b269e79fd | ||
|
|
6159cfd138 | ||
|
|
6a5bbd335b | ||
|
|
39e269db8c | ||
|
|
70fe23a3ce | ||
|
|
a6a8a7fb85 | ||
|
|
6641b13b4c | ||
|
|
5136b05c9b | ||
|
|
803c2144f4 | ||
|
|
b69a079514 | ||
|
|
2aa800cd55 | ||
|
|
6e61a36d05 | ||
|
|
f80bf1fb1c | ||
|
|
d465e85239 | ||
|
|
deed25a2ff | ||
|
|
a486716520 | ||
|
|
2361e11e98 | ||
|
|
cd1f2adca7 |
@@ -131,11 +131,20 @@ proxyBypassHosts:
|
||||
|
||||
# Media Proxy
|
||||
# Reference Implementation: https://github.com/misskey-dev/media-proxy
|
||||
# * Deliver a common cache between instances
|
||||
# * Perform image compression (on a different server resource than the main process)
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
# Proxy remote files by this instance or mediaProxy to prevent remote files from running in remote domains.
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
# Movie Thumbnail Generation URL
|
||||
# There is no reference implementation.
|
||||
# For example, Misskey will point to the following URL:
|
||||
# https://example.com/thumbnail.webp?thumbnail=1&url=https%3A%2F%2Fstorage.example.com%2Fpath%2Fto%2Fvideo.mp4
|
||||
#videoThumbnailGenerator: https://example.com
|
||||
|
||||
# Sign to ActivityPub GET request (default: true)
|
||||
signToActivityPubGet: true
|
||||
|
||||
|
||||
1
.devcontainer/Dockerfile
Normal file
1
.devcontainer/Dockerfile
Normal file
@@ -0,0 +1 @@
|
||||
FROM mcr.microsoft.com/devcontainers/javascript-node:0-18
|
||||
11
.devcontainer/devcontainer.json
Normal file
11
.devcontainer/devcontainer.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "Misskey",
|
||||
"dockerComposeFile": "docker-compose.yml",
|
||||
"service": "app",
|
||||
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
|
||||
"features": {
|
||||
"ghcr.io/devcontainers-contrib/features/pnpm:2": {}
|
||||
},
|
||||
"forwardPorts": [3000],
|
||||
"postCreateCommand": ".devcontainer/init.sh"
|
||||
}
|
||||
146
.devcontainer/devcontainer.yml
Normal file
146
.devcontainer/devcontainer.yml
Normal file
@@ -0,0 +1,146 @@
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
# Misskey configuration
|
||||
#━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
||||
|
||||
# ┌─────┐
|
||||
#───┘ URL └─────────────────────────────────────────────────────
|
||||
|
||||
# Final accessible URL seen by a user.
|
||||
url: http://127.0.0.1:3000/
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# URL SETTINGS AFTER THAT!
|
||||
|
||||
# ┌───────────────────────┐
|
||||
#───┘ Port and TLS settings └───────────────────────────────────
|
||||
|
||||
#
|
||||
# Misskey requires a reverse proxy to support HTTPS connections.
|
||||
#
|
||||
# +----- https://example.tld/ ------------+
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# | User | ---> || Proxy (443) | ---> | Misskey (3000) ||
|
||||
# +------+ |+-------------+ +----------------+|
|
||||
# +---------------------------------------+
|
||||
#
|
||||
# You need to set up a reverse proxy. (e.g. nginx)
|
||||
# An encrypted connection with HTTPS is highly recommended
|
||||
# because tokens may be transferred in GET requests.
|
||||
|
||||
# The port that your Misskey server should listen on.
|
||||
port: 3000
|
||||
|
||||
# ┌──────────────────────────┐
|
||||
#───┘ PostgreSQL configuration └────────────────────────────────
|
||||
|
||||
db:
|
||||
host: db
|
||||
port: 5432
|
||||
|
||||
# Database name
|
||||
db: misskey
|
||||
|
||||
# Auth
|
||||
user: postgres
|
||||
pass: postgres
|
||||
|
||||
# Whether disable Caching queries
|
||||
#disableCache: true
|
||||
|
||||
# Extra Connection options
|
||||
#extra:
|
||||
# ssl: true
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Redis configuration └─────────────────────────────────────
|
||||
|
||||
redis:
|
||||
host: redis
|
||||
port: 6379
|
||||
#family: 0 # 0=Both, 4=IPv4, 6=IPv6
|
||||
#pass: example-pass
|
||||
#prefix: example-prefix
|
||||
#db: 1
|
||||
|
||||
# ┌─────────────────────────────┐
|
||||
#───┘ Elasticsearch configuration └─────────────────────────────
|
||||
|
||||
#elasticsearch:
|
||||
# host: localhost
|
||||
# port: 9200
|
||||
# ssl: false
|
||||
# user:
|
||||
# pass:
|
||||
|
||||
# ┌───────────────┐
|
||||
#───┘ ID generation └───────────────────────────────────────────
|
||||
|
||||
# You can select the ID generation method.
|
||||
# You don't usually need to change this setting, but you can
|
||||
# change it according to your preferences.
|
||||
|
||||
# Available methods:
|
||||
# aid ... Short, Millisecond accuracy
|
||||
# meid ... Similar to ObjectID, Millisecond accuracy
|
||||
# ulid ... Millisecond accuracy
|
||||
# objectid ... This is left for backward compatibility
|
||||
|
||||
# ONCE YOU HAVE STARTED THE INSTANCE, DO NOT CHANGE THE
|
||||
# ID SETTINGS AFTER THAT!
|
||||
|
||||
id: 'aid'
|
||||
|
||||
# ┌─────────────────────┐
|
||||
#───┘ Other configuration └─────────────────────────────────────
|
||||
|
||||
# Whether disable HSTS
|
||||
#disableHsts: true
|
||||
|
||||
# Number of worker processes
|
||||
#clusterLimit: 1
|
||||
|
||||
# Job concurrency per worker
|
||||
# deliverJobConcurrency: 128
|
||||
# inboxJobConcurrency: 16
|
||||
|
||||
# Job rate limiter
|
||||
# deliverJobPerSec: 128
|
||||
# inboxJobPerSec: 16
|
||||
|
||||
# Job attempts
|
||||
# deliverJobMaxAttempts: 12
|
||||
# inboxJobMaxAttempts: 8
|
||||
|
||||
# IP address family used for outgoing request (ipv4, ipv6 or dual)
|
||||
#outgoingAddressFamily: ipv4
|
||||
|
||||
# Proxy for HTTP/HTTPS
|
||||
#proxy: http://127.0.0.1:3128
|
||||
|
||||
proxyBypassHosts:
|
||||
- api.deepl.com
|
||||
- api-free.deepl.com
|
||||
- www.recaptcha.net
|
||||
- hcaptcha.com
|
||||
- challenges.cloudflare.com
|
||||
|
||||
# Proxy for SMTP/SMTPS
|
||||
#proxySmtp: http://127.0.0.1:3128 # use HTTP/1.1 CONNECT
|
||||
#proxySmtp: socks4://127.0.0.1:1080 # use SOCKS4
|
||||
#proxySmtp: socks5://127.0.0.1:1080 # use SOCKS5
|
||||
|
||||
# Media Proxy
|
||||
#mediaProxy: https://example.com/proxy
|
||||
|
||||
# Proxy remote files (default: false)
|
||||
#proxyRemoteFiles: true
|
||||
|
||||
# Sign to ActivityPub GET request (default: true)
|
||||
signToActivityPubGet: true
|
||||
|
||||
allowedPrivateNetworks: [
|
||||
'127.0.0.1/32'
|
||||
]
|
||||
|
||||
# Upload or download file size limits (bytes)
|
||||
#maxFileSize: 262144000
|
||||
52
.devcontainer/docker-compose.yml
Normal file
52
.devcontainer/docker-compose.yml
Normal file
@@ -0,0 +1,52 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
|
||||
volumes:
|
||||
- ../..:/workspaces:cached
|
||||
|
||||
command: sleep infinity
|
||||
|
||||
networks:
|
||||
- internal_network
|
||||
- external_network
|
||||
|
||||
redis:
|
||||
restart: always
|
||||
image: redis:7-alpine
|
||||
networks:
|
||||
- internal_network
|
||||
volumes:
|
||||
- ../redis:/data
|
||||
healthcheck:
|
||||
test: "redis-cli ping"
|
||||
interval: 5s
|
||||
retries: 20
|
||||
|
||||
db:
|
||||
restart: unless-stopped
|
||||
image: postgres:15-alpine
|
||||
networks:
|
||||
- internal_network
|
||||
environment:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: misskey
|
||||
volumes:
|
||||
- ../db:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"
|
||||
interval: 5s
|
||||
retries: 20
|
||||
|
||||
volumes:
|
||||
postgres-data:
|
||||
|
||||
networks:
|
||||
internal_network:
|
||||
internal: true
|
||||
external_network:
|
||||
9
.devcontainer/init.sh
Executable file
9
.devcontainer/init.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -xe
|
||||
|
||||
git submodule update --init
|
||||
pnpm install --frozen-lockfile
|
||||
cp .devcontainer/devcontainer.yml .config/default.yml
|
||||
pnpm build
|
||||
pnpm migrate
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -33,6 +33,7 @@ coverage
|
||||
!/.config/docker_example.yml
|
||||
!/.config/docker_example.env
|
||||
docker-compose.yml
|
||||
!/.devcontainer/docker-compose.yml
|
||||
|
||||
# misskey
|
||||
/build
|
||||
|
||||
50
CHANGELOG.md
50
CHANGELOG.md
@@ -8,6 +8,56 @@
|
||||
|
||||
You should also include the user name that made the change.
|
||||
-->
|
||||
## 13.6.1 (2023/02/12)
|
||||
|
||||
### Improvements
|
||||
- アニメーションを少なくする設定の時、MkPageHeaderのタブアニメーションを無効化
|
||||
- Backend: activitypub情報がcorsでブロックされないようヘッダーを追加
|
||||
- enhance: レートリミットを0%にできるように
|
||||
- チャンネル内Renoteを行えるように
|
||||
|
||||
### Bugfixes
|
||||
- Client: ユーザーページでアクティビティを見ることができない問題を修正
|
||||
|
||||
## 13.6.0 (2023/02/11)
|
||||
|
||||
### Improvements
|
||||
- MkPageHeaderをごっそり変えた
|
||||
* モバイルではヘッダーは上下に分割され、下段にタブが表示されるように
|
||||
* iconOnlyのタブ項目がアクティブな場合にはタブのタイトルを表示するように
|
||||
* メインタイムラインではタイトルを表示しない
|
||||
* メインタイムラインかつモバイルで表示される左上のアバターを選択するとアカウントメニューが開くように
|
||||
- ユーザーページのノート一覧をタブとして分離
|
||||
- コンディショナルロールもバッジとして表示可能に
|
||||
- enhance(client): ロールをより簡単に付与できるように
|
||||
- enhance(client): 一度見たノートのRenoteは省略して表示するように
|
||||
- enhance(client): 迷惑になる可能性のある投稿を行う前に警告を表示
|
||||
- リアクションの数が多い場合の表示を改善
|
||||
- 一部のMFM構文をopt-outに
|
||||
|
||||
### Bugfixes
|
||||
- Client: ユーザーページでタブがほとんど見れないことがないように
|
||||
|
||||
## 13.5.6 (2023/02/10)
|
||||
|
||||
### Improvements
|
||||
- 非ログイン時にMiAuthを踏んだ際にMiAuthであることを表示する
|
||||
- /auth/のUIをアップデート
|
||||
- 利用規約同意UIの調整
|
||||
- クロップ時の質問を分かりやすく
|
||||
|
||||
### Bugfixes
|
||||
- fix: prevent clipping audio plyr's tooltip
|
||||
|
||||
## 13.5.4 (2023/02/09)
|
||||
|
||||
### Improvements
|
||||
- Server: UIのHTML(ノートなどの特別なページを除く)のキャッシュ時間を15秒から30秒に
|
||||
- i/notificationsのレートリミットを緩和
|
||||
|
||||
### Bugfixes
|
||||
- fix(client): validate url to improve security
|
||||
- fix(client): dateの初期値が正常に入らない時がある
|
||||
|
||||
## 13.5.3 (2023/02/09)
|
||||
|
||||
|
||||
@@ -111,6 +111,25 @@ command.
|
||||
- Vite HMR (just the `vite` command) is available. The behavior may be different from production.
|
||||
- Service Worker is watched by esbuild.
|
||||
|
||||
### Dev Container
|
||||
Instead of running `pnpm` locally, you can use Dev Container to set up your development environment.
|
||||
To use Dev Container, open the project directory on VSCode with Dev Containers installed.
|
||||
|
||||
It will run the following command automatically inside the container.
|
||||
``` bash
|
||||
git submodule update --init
|
||||
pnpm install --frozen-lockfile
|
||||
cp .devcontainer/devcontainer.yml .config/default.yml
|
||||
pnpm build
|
||||
pnpm migrate
|
||||
```
|
||||
|
||||
After finishing the migration, run the `pnpm dev` command to start the development server.
|
||||
|
||||
``` bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Testing
|
||||
- Test codes are located in [`/packages/backend/test`](/packages/backend/test).
|
||||
|
||||
|
||||
@@ -886,56 +886,6 @@ _nsfw:
|
||||
respect: "اخف الوسائط ذات المحتوى الحساس"
|
||||
ignore: "اعرض الوسائط ذات المحتوى الحساس"
|
||||
force: "اخف كل الوسائط"
|
||||
_mfm:
|
||||
cheatSheet: "مرجع ملخص عن MFM"
|
||||
intro: "MFM هي لغة ترميزية مخصصة يمكن استخدامها في عدّة أماكن في ميسكي. يمكنك مراجعة كل تعابيرها مع كيفية استخدامها هنا."
|
||||
mention: "أشر الى"
|
||||
mentionDescription: "يمكنك الإشارة لمستخدم معيّن من خلال كتابة @ متبوعة باسم مستخدم."
|
||||
hashtag: "الوسوم"
|
||||
hashtagDescription: "يمكنك تعيين وسم من خلال كتابة # متبوعة بالنص المطلوب."
|
||||
url: "الرابط"
|
||||
urlDescription: "يمكن عرض الروابط"
|
||||
link: "رابط"
|
||||
bold: "عريض"
|
||||
boldDescription: "جعل الحروف أثخن لإبرازها."
|
||||
small: "صغير"
|
||||
smallDescription: "يعرض المحتوى صغيرًا ورفيعًا."
|
||||
center: "وسط"
|
||||
centerDescription: "يمركز المحتوى في الوَسَط."
|
||||
quote: "اقتبس"
|
||||
quoteDescription: "يعرض المحتوى كاقتباس"
|
||||
emoji: "إيموجي مخصص"
|
||||
emojiDescription: "إحاطة اسم الإيموجي بنقطتي تفسير سيستبدله بصورة الإيموجي."
|
||||
search: "البحث"
|
||||
searchDescription: "يعرض نصًا في صندوق البحث"
|
||||
flip: "اقلب"
|
||||
flipDescription: "يقلب المحتوى عموديًا أو أفقيًا"
|
||||
jelly: "تأثير (هلام)"
|
||||
jellyDescription: "يمنح المحتوى حركة هلامية."
|
||||
tada: "تأثير (تادا)"
|
||||
tadaDescription: "يمنح للمحتوى تأثير تادا"
|
||||
jump: "تأثير (قفز)"
|
||||
jumpDescription: "يمنح للمحتوى حركة قفز."
|
||||
bounce: "تأثير (ارتداد)"
|
||||
bounceDescription: "يمنح للمحتوى حركة ارتدادية"
|
||||
shake: "تأثير (اهتزاز)"
|
||||
shakeDescription: "يمنح المحتوى حركة اهتزازية."
|
||||
spin: "تأثير (دوران)"
|
||||
spinDescription: "يمنح المحتوى حركة دورانية."
|
||||
x2: "كبير"
|
||||
x2Description: "يُكبر المحتوى"
|
||||
x3: "كبير جداً"
|
||||
x3Description: "يُضخم المحتوى"
|
||||
x4: "هائل"
|
||||
x4Description: "يُضخم المحتوى أكثر مما سبق."
|
||||
blur: "طمس"
|
||||
blurDescription: "يطمس المحتوى، لكن بالتمرير فوقه سيظهر بوضوح."
|
||||
font: "الخط"
|
||||
fontDescription: "الخط المستخدم لعرض المحتوى."
|
||||
rainbow: "قوس قزح"
|
||||
rainbowDescription: "اجعل المحتوى يظهر بألوان الطيف"
|
||||
rotate: "تدوير"
|
||||
rotateDescription: "يُدير المحتوى بزاوية معيّنة."
|
||||
_instanceTicker:
|
||||
none: "لا تظهره بتاتًا"
|
||||
remote: "أظهر للمستخدمين البِعاد"
|
||||
|
||||
@@ -455,7 +455,6 @@ youHaveNoGroups: "আপনার কোন গ্রুপ নেই "
|
||||
joinOrCreateGroup: "একটি বিদ্যমান গ্রুপের আমন্ত্রণ পান বা একটি নতুন গ্রুপ তৈরি করুন৷"
|
||||
noHistory: "কোনো ইতিহাস নেই"
|
||||
signinHistory: "প্রবেশ করার ইতিহাস"
|
||||
disableAnimatedMfm: "অ্যানিমেটেড MFM অক্ষম করুন"
|
||||
doing: "প্রক্রিয়া করছে..."
|
||||
category: "বিভাগ"
|
||||
tags: "ট্যাগসমূহ"
|
||||
@@ -923,70 +922,6 @@ _nsfw:
|
||||
respect: "স্পর্শকাতর মিডিয়া লুকান"
|
||||
ignore: "স্পর্শকাতর মিডিয়া লুকাবেন না"
|
||||
force: "সকল মিডিয়া লুকান"
|
||||
_mfm:
|
||||
cheatSheet: "MFM চিটশিট"
|
||||
intro: "MFM একটি মার্কআপ ভাষা যা Misskey-এর মধ্যে বিভিন্ন জায়গায় ব্যবহার করা যেতে পারে। এখানে আপনি MFM-এর সিনট্যাক্সগুলির একটি তালিকা দেখতে পারবেন।"
|
||||
dummy: "মিসকি ফেডিভার্সের বিশ্বকে প্রসারিত করে"
|
||||
mention: "উল্লেখ"
|
||||
mentionDescription: "@ চিহ্ন + ব্যবহারকারীর নাম একটি নির্দিষ্ট ব্যবহারকারীকে নির্দেশ করতে ব্যবহার করা যায়।"
|
||||
hashtag: "হ্যাশট্যাগ"
|
||||
hashtagDescription: "আপনি একটি # চিহ্ন + ট্যাগ সহ একটি হ্যাশট্যাগ নির্দেশ করতে পারেন।"
|
||||
url: "URL"
|
||||
urlDescription: "URL দেখানো সম্ভব।"
|
||||
link: "লিংক"
|
||||
linkDescription: "আপনি পাঠ্যের একটি নির্দিষ্ট অংশকে URL হিসাবে দেখাতে পারেন৷"
|
||||
bold: "গাঢ়"
|
||||
boldDescription: "অক্ষরগুলিকে মোটাকরে প্রদর্শন করা হবে।"
|
||||
small: "ছোট"
|
||||
smallDescription: "লেখা ছোট এবং পাতলা করে দেখানো হবে।"
|
||||
center: "সেন্টার"
|
||||
centerDescription: "লেখা মাঝ বরাবর দেখানো হবে"
|
||||
inlineCode: "কোড (ইনলাইন)"
|
||||
inlineCodeDescription: " প্রোগ্রামের কোডের জন্য ইনলাইন সিনট্যাক্স হাইলাইটিং করা হবে"
|
||||
blockCode: "কোড (ব্লক)"
|
||||
blockCodeDescription: "মাল্টি-লাইন প্রোগ্রামের কোডের জন্য সিনট্যাক্স হাইলাইট করে।"
|
||||
inlineMath: "গাণিতিক সূত্র (ইনলাইন)"
|
||||
inlineMathDescription: "গাণিতিক সূত্র প্রদর্শন করুন (KaTeX) ইনলাইন।"
|
||||
blockMath: "গাণিতিক সূত্র (ব্লক)"
|
||||
blockMathDescription: "একটি ব্লকে একাধিক লাইনের গাণিতিক সূত্র প্রদর্শন করুন (KaTeX)।"
|
||||
quote: "উদ্ধৃতি"
|
||||
quoteDescription: "বিষয়বস্তুকে একটি উদ্ধৃতি হিসাবে দেখানো হবে।"
|
||||
emoji: "স্বনির্ধারিত ইমোজিগুলি"
|
||||
emojiDescription: "আপনি একটি কাস্টম ইমোজির নাম কোলনে আবদ্ধ করে কাস্টম ইমোজিটি দেখাতে পারেন৷"
|
||||
search: "খুঁজুন"
|
||||
searchDescription: "পূর্ব-টাইপ করা পাঠ্য সহ একটি অনুসন্ধান বাক্স প্রদর্শন করে।"
|
||||
flip: "উল্টান"
|
||||
flipDescription: "বিষয়বস্তু উপরে/নীচে বা বাম/ডানে উল্টান।"
|
||||
jelly: "অ্যানিমেশন (জেলি)"
|
||||
jellyDescription: "জেলির মত অ্যানিমেশন দেখায়।"
|
||||
tada: "অ্যানিমেশন (টাডা)"
|
||||
tadaDescription: "\"টাডা!\" এর মত অ্যানিমেশন দেখায়।"
|
||||
jump: "অ্যানিমেশন (লাফ)"
|
||||
jumpDescription: "বিষয়বস্তুতে লাফ মারার মত অ্যানিমেশন দেখায়।"
|
||||
bounce: "অ্যানিমেশন (তিড়িং বিড়িং)"
|
||||
bounceDescription: "তিড়িং বিড়িং করার মত অ্যানিমেশন দেখায়।"
|
||||
shake: "অ্যানিমেশন (ঝাঁকি)"
|
||||
shakeDescription: "ঝাঁকির মত অ্যানিমেশন দেখায়।"
|
||||
twitch: "অ্যানিমেশন (মোচড়ানো)"
|
||||
twitchDescription: "মোচড়ানোর মত অ্যানিমেশন দেখায়।"
|
||||
spin: "অ্যানিমেশন (ঘুরা)"
|
||||
spinDescription: "ঘুরার মত অ্যানিমেশন দেখায়।"
|
||||
x2: "বড়"
|
||||
x2Description: "বিষয়বস্তু বড় করে দেখায়।"
|
||||
x3: "অনেক বড়"
|
||||
x3Description: "বিষয়বস্তু আরও বড় করে দেখায়।"
|
||||
x4: "অস্বাভাবিক বড়"
|
||||
x4Description: "বিষয়বস্তুকে আগের থেকেও আরও বড় করে দেখায়।"
|
||||
blur: "ব্লার"
|
||||
blurDescription: "বিষয়বস্তুকে ব্লার করতে পারেন। আপনি এর উপর মাউস কার্সার রাখলে, এটি পরিষ্কারভাবে দেখতে পাবেন।"
|
||||
font: "ফন্ট"
|
||||
fontDescription: "বিষয়বস্তুকে কোন ফন্টে দেখানো হবে তা নির্ধারণ করে।"
|
||||
rainbow: "রেইনবো"
|
||||
rainbowDescription: "বিষয়বস্তুকে রংধনুর রং গুলিতে প্রদর্শন করে।"
|
||||
sparkle: "চিক চিক"
|
||||
sparkleDescription: "বিষয়বস্তুকে একটি চিকচিকে কণা প্রভাব দেয়।"
|
||||
rotate: "ঘুরান"
|
||||
rotateDescription: "বিষয়বস্তুকে একটি নির্দিষ্ট কোনে ঘুরায়।"
|
||||
_instanceTicker:
|
||||
none: "দেখাবেন না"
|
||||
remote: "রিমোট ব্যাবহারকারীদের জন্য দেখান"
|
||||
|
||||
@@ -375,11 +375,6 @@ file: "Fitxers"
|
||||
_email:
|
||||
_follow:
|
||||
title: "t'ha seguit"
|
||||
_mfm:
|
||||
mention: "Menció"
|
||||
quote: "Citar"
|
||||
emoji: "Emojis personalitzats"
|
||||
search: "Cercar"
|
||||
_instanceMute:
|
||||
instanceMuteDescription: "Silencia tots els impulsos dels servidors seleccionats, també els usuaris que responen a altres d'un servidor silenciat."
|
||||
_theme:
|
||||
|
||||
@@ -642,19 +642,6 @@ _registry:
|
||||
_aboutMisskey:
|
||||
allContributors: "Všichni přispěvatelé"
|
||||
source: "Zdrojový kód"
|
||||
_mfm:
|
||||
mention: "Zmínění"
|
||||
hashtag: "Hashtag"
|
||||
link: "Odkaz"
|
||||
bold: "Tučně"
|
||||
quote: "Citovat"
|
||||
emoji: "Vlastní emoji"
|
||||
search: "Vyhledávání"
|
||||
flip: "Otočit"
|
||||
tada: "Animace (tadá)"
|
||||
blur: "Rozmazání"
|
||||
font: "Font"
|
||||
rainbow: "Duha"
|
||||
_channel:
|
||||
featured: "Trendy"
|
||||
_menuDisplay:
|
||||
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "Möchtest du diese Blockierung wirklich aufheben?"
|
||||
suspendConfirm: "Möchtest du diesen Benutzer wirklich sperren?"
|
||||
unsuspendConfirm: "Möchtest du diesen Benutzer wirklich entsperren?"
|
||||
selectList: "Liste auswählen"
|
||||
selectChannel: "Kanal auswählen"
|
||||
selectAntenna: "Antenne auswählen"
|
||||
selectWidget: "Widget auswählen"
|
||||
editWidgets: "Widgets bearbeiten"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "Kein weiterer Verlauf vorhanden"
|
||||
startMessaging: "Neuen Chat erstellen"
|
||||
nUsersRead: "Von {n} Benutzern gelesen"
|
||||
agreeTo: "Ich stimme {0} zu"
|
||||
agreeBelow: "Ich stimme Untenstehendem zu"
|
||||
basicNotesBeforeCreateAccount: "Wichtige Infos"
|
||||
tos: "Nutzungsbedingungen"
|
||||
start: "Anfangen"
|
||||
home: "Startseite"
|
||||
@@ -464,7 +467,6 @@ youHaveNoGroups: "Keine Gruppen vorhanden"
|
||||
joinOrCreateGroup: "Lass dich zu einer Gruppe einladen oder erstelle deine eigene."
|
||||
noHistory: "Kein Verlauf gefunden"
|
||||
signinHistory: "Anmeldungsverlauf"
|
||||
disableAnimatedMfm: "MFM, die Animationen enthalten, deaktivieren"
|
||||
doing: "In Bearbeitung …"
|
||||
category: "Kategorie"
|
||||
tags: "Schlagwörter"
|
||||
@@ -861,6 +863,8 @@ failedToFetchAccountInformation: "Benutzerkontoinformationen konnten nicht abgef
|
||||
rateLimitExceeded: "Versuchsanzahl überschritten"
|
||||
cropImage: "Bild zuschneiden"
|
||||
cropImageAsk: "Möchtest du das Bild zuschneiden?"
|
||||
cropYes: "Zuschneiden"
|
||||
cropNo: "Unbearbeitet verwenden"
|
||||
file: "Datei"
|
||||
recentNHours: "Letzten {n} Stunden"
|
||||
recentNDays: "Letzten {n} Tage"
|
||||
@@ -939,6 +943,8 @@ cannotPerformTemporaryDescription: "Diese Aktion ist wegen des Überschreitenes
|
||||
preset: "Vorlage"
|
||||
selectFromPresets: "Aus Vorlagen wählen"
|
||||
achievements: "Errungenschaften"
|
||||
gotInvalidResponseError: "Ungültige Antwort des Servers"
|
||||
gotInvalidResponseErrorDescription: "Eventuell ist der Server momentan nicht erreichbar oder untergeht Wartungsarbeiten. Bitte versuche es später noch einmal."
|
||||
_achievements:
|
||||
earnedAt: "Freigeschaltet am"
|
||||
_types:
|
||||
@@ -1323,72 +1329,6 @@ _nsfw:
|
||||
respect: "Als NSFW markierte Bilder verbergen"
|
||||
ignore: "Als NSFW markierte Bilder nicht verbergen"
|
||||
force: "Alle Medien verbergen"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Spickzettel"
|
||||
intro: "MFM ist eine Misskey-exklusive Markup-Sprache, die in Misskey an vielen Stellen verwendet werden kann. Hier kannst du eine Liste von verfügbarer MFM-Syntax einsehen."
|
||||
dummy: "Misskey erweitert die Welt des Fediverse"
|
||||
mention: "Erwähnung"
|
||||
mentionDescription: "Mit At-Zeichen und Benutzername kann ein individueller Nutzer angegeben werden."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Mit einer Raute und Text kann ein Hashtag angegeben werden."
|
||||
url: "URL"
|
||||
urlDescription: "Zeigt URLs an."
|
||||
link: "Link"
|
||||
linkDescription: "Zeigt spezifische Textabschnitte als URL an."
|
||||
bold: "Fett"
|
||||
boldDescription: "Zeichen zur Betonung dicker erscheinen lassen."
|
||||
small: "Klein"
|
||||
smallDescription: "Inhalt klein und dünn erscheinen lassen."
|
||||
center: "Zentrieren"
|
||||
centerDescription: "Inhalt zentriert anzeigen."
|
||||
inlineCode: "Code (Eingebettet)"
|
||||
inlineCodeDescription: "Syntax-Hervorhebung für (Programm-)Code eingebettet anzeigen."
|
||||
blockCode: "Code (Block)"
|
||||
blockCodeDescription: "Syntax-Hervorhebung für mehrzeiligen (Programm-)Code als Block anzeigen."
|
||||
inlineMath: "Mathe (Eingebettet)"
|
||||
inlineMathDescription: "Mathematische Formeln (KaTeX) eingebettet anzeigen."
|
||||
blockMath: "Mathe (Block)"
|
||||
blockMathDescription: "Mehrzeilige mathematische Formeln (KaTeX) als Block einbetten."
|
||||
quote: "Zitationen"
|
||||
quoteDescription: "Inhalt als Zitat anzeigen."
|
||||
emoji: "Benutzerdefinierte Emojis"
|
||||
emojiDescription: "Durch das Umschließen von Emoji-Namen durch Doppelpunkte können benutzerdefinierte Emojis angezeigt werden."
|
||||
search: "Suche"
|
||||
searchDescription: "Eine vorgefertige Suchanfragebox anzeigen."
|
||||
flip: "Spiegelung"
|
||||
flipDescription: "Inhalt horizontal oder vertikal gespiegelt anzeigen."
|
||||
jelly: "Animation (Dehnen)"
|
||||
jellyDescription: "Verleiht Inhalt eine sich dehnende Animation."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Verleiht Inhalt eine Animation mit \"Tada!\"-Gefühl"
|
||||
jump: "Animation (Sprung)"
|
||||
jumpDescription: "Verleiht Inhalt eine springende Animation."
|
||||
bounce: "Animation (Federn)"
|
||||
bounceDescription: "Verleiht Inhalt eine federnde Animation."
|
||||
shake: "Animation (Zittern)"
|
||||
shakeDescription: "Verleiht Inhalt eine zitternde Animation."
|
||||
twitch: "Animation (Zucken)"
|
||||
twitchDescription: "Verleiht Inhalt eine sehr stark zuckende Animation."
|
||||
spin: "Animation (Rotieren)"
|
||||
spinDescription: "Verleiht Inhalt eine rotierende Animation."
|
||||
x2: "Groß"
|
||||
x2Description: "Inhalte größer anzeigen."
|
||||
x3: "Sehr groß"
|
||||
x3Description: "Inhalte noch größer anzeigen."
|
||||
x4: "Unglaublich groß"
|
||||
x4Description: "Lässt Inhalte noch größer als größer als groß angezeigt werden."
|
||||
blur: "Weichzeichnen"
|
||||
blurDescription: "Inhalte durch Weihzeichnung verschwimmen lassen. Durch das Bewegen des Mauszeigers über den Inhalt wird er klar angezeigt."
|
||||
font: "Schriftart"
|
||||
fontDescription: "Setzt die Schriftart des Inhaltes fest."
|
||||
rainbow: "Regenbogen"
|
||||
rainbowDescription: "Lässt den Inhalt in Regenbogenfarben erscheinen."
|
||||
sparkle: "Glitzer"
|
||||
sparkleDescription: "Verleiht Inhalt einen glitzernden Partikeleffekt."
|
||||
rotate: "Drehen"
|
||||
rotateDescription: "Dreht den Inhalt um einen angegebenen Winkel."
|
||||
plain: "Schlicht"
|
||||
plainDescription: "Deaktiviert jegliche MFM-Syntax, die sich innerhalb dieses MFM-Effekts befindet."
|
||||
_instanceTicker:
|
||||
none: "Nie anzeigen"
|
||||
remote: "Für Benutzer fremder Instanzen anzeigen"
|
||||
@@ -1593,12 +1533,15 @@ _permissions:
|
||||
"read:gallery-likes": "Liste deiner mit \"Gefällt mir\" markierten Galerie-Beiträge lesen"
|
||||
"write:gallery-likes": "Liste deiner mit \"Gefällt mir\" markierten Galerie-Beiträge bearbeiten"
|
||||
_auth:
|
||||
shareAccessTitle: "Verteilung von App-Berechtigungen"
|
||||
shareAccess: "Möchtest du „{name}“ authorisieren, auf dieses Benutzerkonto zugreifen zu können?"
|
||||
shareAccessAsk: "Bist du dir sicher, dass du diese Anwendung authorisieren möchtest, auf dein Benutzerkonto zugreifen zu können?"
|
||||
permission: "{name} fordert folgende Berechtigungen"
|
||||
permissionAsk: "Diese Anwendung fordert folgende Berechtigungen"
|
||||
pleaseGoBack: "Bitte kehre zur Anwendung zurück"
|
||||
callback: "Es wird zur Anwendung zurückgekehrt"
|
||||
denied: "Zugriff verweigert"
|
||||
pleaseLogin: "Bitte logge dich ein, um Apps zu authorisieren."
|
||||
_antennaSources:
|
||||
all: "Alle Notizen"
|
||||
homeTimeline: "Notizen von Benutzern, denen gefolgt wird"
|
||||
@@ -1869,6 +1812,6 @@ _deck:
|
||||
tl: "Chronik"
|
||||
antenna: "Antennen"
|
||||
list: "Listen"
|
||||
channel: "Kanäle"
|
||||
channel: "Kanal"
|
||||
mentions: "Erwähnungen"
|
||||
direct: "Direktnachrichten"
|
||||
|
||||
@@ -298,11 +298,6 @@ cannotUploadBecauseNoFreeSpace: "Το ανέβασμα απέτυχε λόγω
|
||||
_email:
|
||||
_follow:
|
||||
title: "Έχετε ένα νέο ακόλουθο"
|
||||
_mfm:
|
||||
mention: "Επισήμανση"
|
||||
quote: "Παράθεση"
|
||||
emoji: "Επιπλέον emoji"
|
||||
search: "Αναζήτηση"
|
||||
_channel:
|
||||
featured: "Δημοφιλή"
|
||||
_theme:
|
||||
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "Are you sure that you want to unblock this account?"
|
||||
suspendConfirm: "Are you sure that you want to suspend this account?"
|
||||
unsuspendConfirm: "Are you sure that you want to unsuspend this account?"
|
||||
selectList: "Select a list"
|
||||
selectChannel: "Select a channel"
|
||||
selectAntenna: "Select an antenna"
|
||||
selectWidget: "Select a widget"
|
||||
editWidgets: "Edit widgets"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "There is no further history"
|
||||
startMessaging: "Start a new chat"
|
||||
nUsersRead: "read by {n}"
|
||||
agreeTo: "I agree to {0}"
|
||||
agreeBelow: "I agree to the below"
|
||||
basicNotesBeforeCreateAccount: "Important notes"
|
||||
tos: "Terms of Service"
|
||||
start: "Begin"
|
||||
home: "Home"
|
||||
@@ -464,7 +467,8 @@ youHaveNoGroups: "You have no groups"
|
||||
joinOrCreateGroup: "Get invited to a group or create your own."
|
||||
noHistory: "No history available"
|
||||
signinHistory: "Login history"
|
||||
disableAnimatedMfm: "Disable MFM with animation"
|
||||
enableAdvancedMfm: "Enable advanced MFM"
|
||||
enableAnimatedMfm: "Enable MFM with animation"
|
||||
doing: "Processing..."
|
||||
category: "Category"
|
||||
tags: "Tags"
|
||||
@@ -861,6 +865,8 @@ failedToFetchAccountInformation: "Could not fetch account information"
|
||||
rateLimitExceeded: "Rate limit exceeded"
|
||||
cropImage: "Crop image"
|
||||
cropImageAsk: "Do you want to crop this image?"
|
||||
cropYes: "Crop"
|
||||
cropNo: "Use as-is"
|
||||
file: "File"
|
||||
recentNHours: "Last {n} hours"
|
||||
recentNDays: "Last {n} days"
|
||||
@@ -939,6 +945,12 @@ cannotPerformTemporaryDescription: "This action cannot be performed temporarily
|
||||
preset: "Preset"
|
||||
selectFromPresets: "Choose from presets"
|
||||
achievements: "Achievements"
|
||||
gotInvalidResponseError: "Invalid server response"
|
||||
gotInvalidResponseErrorDescription: "The server may be unreachable or undergoing maintenance. Please try again later."
|
||||
thisPostMayBeAnnoying: "This note may annoy others."
|
||||
thisPostMayBeAnnoyingHome: "Post to home timeline"
|
||||
thisPostMayBeAnnoyingCancel: "Cancel"
|
||||
thisPostMayBeAnnoyingIgnore: "Post anyway"
|
||||
_achievements:
|
||||
earnedAt: "Unlocked at"
|
||||
_types:
|
||||
@@ -1323,72 +1335,6 @@ _nsfw:
|
||||
respect: "Hide NSFW media"
|
||||
ignore: "Don't hide NSFW media"
|
||||
force: "Hide all media"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Cheatsheet"
|
||||
intro: "MFM is a Misskey-exclusive markup language that can be used in many places. Here you can view a list of all available MFM syntax."
|
||||
dummy: "Misskey expands the world of the Fediverse"
|
||||
mention: "Mention"
|
||||
mentionDescription: "You can specify a user by using an At-Symbol and a username."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "You can specify a hashtag using a number sign and text."
|
||||
url: "URL"
|
||||
urlDescription: "URLs can be displayed."
|
||||
link: "Link"
|
||||
linkDescription: "Specific parts of text can be displayed as a URL."
|
||||
bold: "Bold"
|
||||
boldDescription: "Highlights letters by making them thicker."
|
||||
small: "Small"
|
||||
smallDescription: "Displays content small and thin."
|
||||
center: "Center"
|
||||
centerDescription: "Displays content centered."
|
||||
inlineCode: "Code (Inline)"
|
||||
inlineCodeDescription: "Displays inline syntax highlighting for (program) code."
|
||||
blockCode: "Code (Block)"
|
||||
blockCodeDescription: "Displays syntax highlighting for multi-line (program) code in a block."
|
||||
inlineMath: "Math (Inline)"
|
||||
inlineMathDescription: "Display math formulas (KaTeX) in-line"
|
||||
blockMath: "Math (Block)"
|
||||
blockMathDescription: "Display multi-line math formulas (KaTeX) in a block"
|
||||
quote: "Quote"
|
||||
quoteDescription: "Displays content as a quote."
|
||||
emoji: "Custom Emoji"
|
||||
emojiDescription: "By surrounding a custom emoji name with colons, custom emoji can be displayed."
|
||||
search: "Search"
|
||||
searchDescription: "Displays a search box with pre-entered text."
|
||||
flip: "Flip"
|
||||
flipDescription: "Flips content horizontally or vertically."
|
||||
jelly: "Animation (Jelly)"
|
||||
jellyDescription: "Gives content a jelly-like animation."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Gives content a \"Tada!\"-like animation."
|
||||
jump: "Animation (Jump)"
|
||||
jumpDescription: "Gives content a jumping animation."
|
||||
bounce: "Animation (Bounce)"
|
||||
bounceDescription: "Gives content a bouncy animation."
|
||||
shake: "Animation (Shake)"
|
||||
shakeDescription: "Gives content a shaking animation."
|
||||
twitch: "Animation (Twitch)"
|
||||
twitchDescription: "Gives content a strongly twitching animation."
|
||||
spin: "Animation (Spin)"
|
||||
spinDescription: "Gives content a spinning animation."
|
||||
x2: "Big"
|
||||
x2Description: "Displays content bigger."
|
||||
x3: "Very big"
|
||||
x3Description: "Displays content even bigger."
|
||||
x4: "Unbelievably big"
|
||||
x4Description: "Displays content even bigger than bigger than big."
|
||||
blur: "Blur"
|
||||
blurDescription: "Blurs content. It will be displayed clearly when hovered over."
|
||||
font: "Font"
|
||||
fontDescription: "Sets the font to display content in."
|
||||
rainbow: "Rainbow"
|
||||
rainbowDescription: "Makes the content appear in rainbow colors."
|
||||
sparkle: "Sparkle"
|
||||
sparkleDescription: "Gives content a sparkling particle effect."
|
||||
rotate: "Rotate"
|
||||
rotateDescription: "Turns content by a specified angle."
|
||||
plain: "Plain"
|
||||
plainDescription: "Deactivates the effects of all MFM contained within this MFM effect."
|
||||
_instanceTicker:
|
||||
none: "Never show"
|
||||
remote: "Show for remote users"
|
||||
@@ -1593,12 +1539,15 @@ _permissions:
|
||||
"read:gallery-likes": "View your list of liked gallery posts"
|
||||
"write:gallery-likes": "Edit your list of liked gallery posts"
|
||||
_auth:
|
||||
shareAccessTitle: "Granting application permissions"
|
||||
shareAccess: "Would you like to authorize \"{name}\" to access this account?"
|
||||
shareAccessAsk: "Are you sure you want to authorize this application to access your account?"
|
||||
permission: "{name} requests the following permissions"
|
||||
permissionAsk: "This application requests the following permissions"
|
||||
pleaseGoBack: "Please go back to the application"
|
||||
callback: "Returning to the application"
|
||||
denied: "Access denied"
|
||||
pleaseLogin: "Please log in to authorize applications."
|
||||
_antennaSources:
|
||||
all: "All notes"
|
||||
homeTimeline: "Notes from followed users"
|
||||
@@ -1869,6 +1818,6 @@ _deck:
|
||||
tl: "Timeline"
|
||||
antenna: "Antennas"
|
||||
list: "List"
|
||||
channel: "Channels"
|
||||
channel: "Channel"
|
||||
mentions: "Mentions"
|
||||
direct: "Direct notes"
|
||||
|
||||
@@ -56,7 +56,7 @@ reply: "Responder"
|
||||
loadMore: "Ver más"
|
||||
showMore: "Ver más"
|
||||
showLess: "Cerrar"
|
||||
youGotNewFollower: "te ha seguido"
|
||||
youGotNewFollower: "ahora te sigue"
|
||||
receiveFollowRequest: "Recibiste una solicitud de seguimiento"
|
||||
followRequestAccepted: "La solicitud de seguimiento fue aceptada"
|
||||
mention: "Menciones"
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "¿Quiere dejar de bloquear esta cuenta?"
|
||||
suspendConfirm: "¿Quiere suspender esta cuenta?"
|
||||
unsuspendConfirm: "¿Quiere dejar de suspender esta cuenta?"
|
||||
selectList: "Seleccione una lista"
|
||||
selectChannel: "Seleccionar canal"
|
||||
selectAntenna: "Seleccionar antena"
|
||||
selectWidget: "Seleccionar widget"
|
||||
editWidgets: "Editar widgets"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "El historial se ha acabado"
|
||||
startMessaging: "Iniciar chat"
|
||||
nUsersRead: "Leído por {n} personas"
|
||||
agreeTo: "De acuerdo con {0}"
|
||||
agreeBelow: "Estoy de acuerdo con lo siguiente"
|
||||
basicNotesBeforeCreateAccount: "Notas básicas"
|
||||
tos: "Términos de uso"
|
||||
start: "Comenzar"
|
||||
home: "Inicio"
|
||||
@@ -464,7 +467,6 @@ youHaveNoGroups: "Sin grupos"
|
||||
joinOrCreateGroup: "Obtenga una invitación para unirse al grupos o puede crear su propio grupo."
|
||||
noHistory: "No hay datos en el historial"
|
||||
signinHistory: "Historial de ingresos"
|
||||
disableAnimatedMfm: "Deshabilitar MFM que tiene animaciones"
|
||||
doing: "Voy en camino"
|
||||
category: "Categoría"
|
||||
tags: "Etiqueta"
|
||||
@@ -939,6 +941,8 @@ cannotPerformTemporaryDescription: "Esta acción no se puede realizar porque se
|
||||
preset: "Predefinido"
|
||||
selectFromPresets: "Escoger desde predefinidos"
|
||||
achievements: "Logros"
|
||||
gotInvalidResponseError: "Respuesta del servidor inválida"
|
||||
gotInvalidResponseErrorDescription: "Puede que el servidor esté caído o en mantenimiento. Favor de intentar más tarde"
|
||||
_achievements:
|
||||
earnedAt: "Desbloqueado el"
|
||||
_types:
|
||||
@@ -1323,72 +1327,6 @@ _nsfw:
|
||||
respect: "Ocultar medios NSFW"
|
||||
ignore: "No esconder medios NSFW "
|
||||
force: "Ocultar todos los medios"
|
||||
_mfm:
|
||||
cheatSheet: "Hoja de referencia de MFM"
|
||||
intro: "MFM es un lenguaje de marcado dedicado que se puede usar en varios lugares dentro de Misskey. Aquí puede ver una lista de sintaxis disponibles en MFM."
|
||||
dummy: "Misskey expande el mundo de la Fediverso"
|
||||
mention: "Menciones"
|
||||
mentionDescription: "El signo @ seguido de un nombre de usuario se puede utilizar para notificar a un usuario en particular."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Puede especificar un hashtag con un numeral y el texto."
|
||||
url: "URL"
|
||||
urlDescription: "Se pueden mostrar las URL"
|
||||
link: "Vínculo"
|
||||
linkDescription: "Se pueden asociar partes de texto a la URL"
|
||||
bold: "Negrita"
|
||||
boldDescription: "Muestra el texto con las letras más gruesas"
|
||||
small: "Pequeño"
|
||||
smallDescription: "Muestra el texto más pequeño y delgado"
|
||||
center: "Centrar"
|
||||
centerDescription: "Muestra el texto centrado"
|
||||
inlineCode: "Código (insertado)"
|
||||
inlineCodeDescription: "Muestra el código de un programa resaltando su sintaxis"
|
||||
blockCode: "Código (bloque)"
|
||||
blockCodeDescription: "Código de resaltado de sintaxis, como programas de varias líneas con bloques."
|
||||
inlineMath: "Fórmula (insertado)"
|
||||
inlineMathDescription: "Muestra fórmulas (KaTeX) insertadas"
|
||||
blockMath: "Fórmula (bloque)"
|
||||
blockMathDescription: "Muestra fórmulas (KaTeX) de varias líneas en un bloque"
|
||||
quote: "Citar"
|
||||
quoteDescription: "Muestra el contenido como una cita"
|
||||
emoji: "Emojis personalizados"
|
||||
emojiDescription: "Muestra los emojis personalizados encerrados entre dos puntos."
|
||||
search: "Buscar"
|
||||
searchDescription: "Muestra una caja de búsqueda con texto pre-escrito"
|
||||
flip: "Echar de un capirotazo"
|
||||
flipDescription: "Voltea el contenido hacia arriba / abajo o hacia la izquierda / derecha."
|
||||
jelly: "Animación (gelatina)"
|
||||
jellyDescription: "Aplica un efecto de animación tipo gelatina"
|
||||
tada: "Animación (tadá)"
|
||||
tadaDescription: "Aplica un efecto de animación al estilo \"Tadá\""
|
||||
jump: "Animación (saltar)"
|
||||
jumpDescription: "Aplica un efecto de animación tipo salto"
|
||||
bounce: "Animación (rebotar)"
|
||||
bounceDescription: "Aplica un efecto de animación tipo rebote"
|
||||
shake: "Animación (temblor)"
|
||||
shakeDescription: "Aplica un efecto de animación tipo temblor"
|
||||
twitch: "Animación (sacudida)"
|
||||
twitchDescription: "Aplica un efecto de animación tipo sacudida"
|
||||
spin: "Animación (giro)"
|
||||
spinDescription: "Aplica un efecto de animación tipo rotación"
|
||||
x2: "Grande"
|
||||
x2Description: "Muestra el contenido más grande"
|
||||
x3: "Muy grande"
|
||||
x3Description: "Muestra el contenido mucho más grande"
|
||||
x4: "Totalmente grande"
|
||||
x4Description: "Muestra el contenido totalmente grande"
|
||||
blur: "Desenfoque"
|
||||
blurDescription: "Para desenfocar el contenido. Se muestra claramente al colocar el puntero encima."
|
||||
font: "Fuente"
|
||||
fontDescription: "Elegir la fuente del contenido"
|
||||
rainbow: "Arcoíris"
|
||||
rainbowDescription: "Muestra el contenido con los colores del arcoíris"
|
||||
sparkle: "Parpadeante"
|
||||
sparkleDescription: "Aplica un efecto de partículas parpadeantes"
|
||||
rotate: "Rotar"
|
||||
rotateDescription: "Rota el contenido a un ángulo especificado."
|
||||
plain: "Plano"
|
||||
plainDescription: "Desactiva los efectos de todo el contenido MFM con este efecto MFM."
|
||||
_instanceTicker:
|
||||
none: "No mostrar"
|
||||
remote: "Mostrar a usuarios remotos"
|
||||
@@ -1593,12 +1531,15 @@ _permissions:
|
||||
"read:gallery-likes": "Ver favoritos de la galería"
|
||||
"write:gallery-likes": "Editar favoritos de la galería"
|
||||
_auth:
|
||||
shareAccessTitle: "Permisos de la aplicación"
|
||||
shareAccess: "¿Desea permitir el acceso a la cuenta \"{name}\"?"
|
||||
shareAccessAsk: "¿Está seguro de que desea autorizar esta aplicación para acceder a su cuenta?"
|
||||
permission: "{name} solicita los siguientes permisos"
|
||||
permissionAsk: "Esta aplicación requiere los siguientes permisos"
|
||||
pleaseGoBack: "Por favor, vuelve a la aplicación"
|
||||
callback: "Volviendo a la aplicación"
|
||||
denied: "Acceso denegado"
|
||||
pleaseLogin: "Se requiere un inicio de sesión para darle permisos a la aplicación"
|
||||
_antennaSources:
|
||||
all: "Todas las notas"
|
||||
homeTimeline: "Notas de los usuarios que sigues"
|
||||
|
||||
@@ -464,7 +464,6 @@ youHaveNoGroups: "Vous n’avez aucun groupe"
|
||||
joinOrCreateGroup: "Vous pouvez être invité·e à rejoindre des groupes existants ou créer votre propre nouveau groupe."
|
||||
noHistory: "Pas d'historique"
|
||||
signinHistory: "Historique de connexion"
|
||||
disableAnimatedMfm: "Désactiver MFM ayant des animations"
|
||||
doing: "En cours..."
|
||||
category: "Catégorie"
|
||||
tags: "Étiquettes"
|
||||
@@ -1011,72 +1010,6 @@ _nsfw:
|
||||
respect: "Cacher les médias marqués comme contenu sensible"
|
||||
ignore: "Afficher les médias sensibles"
|
||||
force: "Cacher tous les médias"
|
||||
_mfm:
|
||||
cheatSheet: "Antisèche MFM"
|
||||
intro: "MFM est un langage Markdown spécifique utilisable ici et là dans Misskey. Vous pouvez vérifier ici les structures utilisables avec MFM."
|
||||
dummy: "La Fédiverse s'agrandit avec Misskey"
|
||||
mention: "Mentionner"
|
||||
mentionDescription: "Vous pouvez afficher un utilisateur spécifique en indiquant une arobase suivie d'un nom d'utilisateur"
|
||||
hashtag: "Hashtags"
|
||||
hashtagDescription: "Vous pouvez afficher un mot-dièse en utilisant un croisillon et du texte"
|
||||
url: "URL"
|
||||
urlDescription: "L'adresse web peut être affichée."
|
||||
link: "Lien"
|
||||
linkDescription: "Une partie précise d'une phrase peut être liée à l'adresse web."
|
||||
bold: "Gras"
|
||||
boldDescription: "Il est possible de mettre le texte en exergue en le mettant en gras."
|
||||
small: "Diminuer l'emphase"
|
||||
smallDescription: "Le contenu peut être affiché en petit et fin."
|
||||
center: "Centrer"
|
||||
centerDescription: "Le contenu peut être centré"
|
||||
inlineCode: "Code (inline)"
|
||||
inlineCodeDescription: "Coloration syntaxique des lignes de code."
|
||||
blockCode: "Bloc de code"
|
||||
blockCodeDescription: "Coloration syntaxique des lignes de code pour les blocs multi-lignes."
|
||||
inlineMath: "Formule mathématique (inline)"
|
||||
inlineMathDescription: "Afficher les formules mathématiques (KaTeX)."
|
||||
blockMath: "Formule mathématique (bloc)"
|
||||
blockMathDescription: "Afficher les formules mathématiques (KaTeX) multi-lignes dans un bloc."
|
||||
quote: "Citer"
|
||||
quoteDescription: "Affiche le contenu sous forme de citation."
|
||||
emoji: "Émojis personnalisés"
|
||||
emojiDescription: "Entourez le nom de l'émoji personnalisé de deux points pour l'afficher."
|
||||
search: "Rechercher"
|
||||
searchDescription: "Affiche une boîte de recherche avec du texte pré-saisi."
|
||||
flip: "Inverser"
|
||||
flipDescription: "Rotation verticale ou horizontale du contenu"
|
||||
jelly: "Animation (Gelée)"
|
||||
jellyDescription: "Donne une animation d'étirement."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Donne une animation qui donne une impression de \"Tada !\""
|
||||
jump: "Animation (Saut)"
|
||||
jumpDescription: "Donne une animation qui saute."
|
||||
bounce: "Animation (Rebond)"
|
||||
bounceDescription: "Donne une animation de rebondissement."
|
||||
shake: "Animation (Secousse)"
|
||||
shakeDescription: "Donne une animation tremblante."
|
||||
twitch: "Animation (Tremblement)"
|
||||
twitchDescription: "Donne une animation de tremblement intense."
|
||||
spin: "Animation (Rotation)"
|
||||
spinDescription: "Donne une animation de rotation."
|
||||
x2: "Grand"
|
||||
x2Description: "Afficher le contenu en grand."
|
||||
x3: "Très grand"
|
||||
x3Description: "Afficher le contenu en très grand."
|
||||
x4: "Plus grand"
|
||||
x4Description: "Afficher le contenu en plus grand."
|
||||
blur: "Flou"
|
||||
blurDescription: "Le contenu peut être flouté ; il sera visible en le survolant avec le curseur."
|
||||
font: "Police de caractères"
|
||||
fontDescription: "Il est possible de choisir la police."
|
||||
rainbow: "Arc-en-ciel"
|
||||
rainbowDescription: "Permet d'afficher le contenu en couleurs arc-en-ciel."
|
||||
sparkle: "Paillettes"
|
||||
sparkleDescription: "Ajoute un effet scintillant au contenu."
|
||||
rotate: "Pivoter"
|
||||
rotateDescription: "Faire pivoter à un angle spécifié."
|
||||
plain: "Vu texte non formaté"
|
||||
plainDescription: "Désactive toute la syntaxe interne."
|
||||
_instanceTicker:
|
||||
none: "Cacher "
|
||||
remote: "Montrer pour les utilisateur·ice·s distant·e·s"
|
||||
|
||||
@@ -464,7 +464,6 @@ youHaveNoGroups: "Kamu tidak memiliki grup"
|
||||
joinOrCreateGroup: "Bergabunglah dengan grup atau kamu dapat membuat grupmu sendiri."
|
||||
noHistory: "Tidak ada riwayat"
|
||||
signinHistory: "Riwayat masuk"
|
||||
disableAnimatedMfm: "Nonaktifkan MFM dengan animasi"
|
||||
doing: "Sedang berkerja..."
|
||||
category: "Kategori"
|
||||
tags: "Tandai"
|
||||
@@ -1131,70 +1130,6 @@ _nsfw:
|
||||
respect: "Sembunyikan media NSFW"
|
||||
ignore: "Jangan sembunyikan media NSFW"
|
||||
force: "Sembunyikan semua media"
|
||||
_mfm:
|
||||
cheatSheet: "Contekan MFM"
|
||||
intro: "MFM adalah Misskey-exclusive Markup Language yang dapat digunakan di banyak tempat. Berikut kamu bisa melihat daftar dari syntax MFM yang ada."
|
||||
dummy: "Misskey membentangkan dunia Fediverse"
|
||||
mention: "Sebut"
|
||||
mentionDescription: "Kamu dapat menentukan pengguna tertentu dengan menggunakan simbol-At dan nama engguna mereka."
|
||||
hashtag: "Tagar"
|
||||
hashtagDescription: "Kamu dapat menentukan tagar dengan menggunakan angka dan teks."
|
||||
url: "URL"
|
||||
urlDescription: "URL dapat ditampilkan."
|
||||
link: "Tautan"
|
||||
linkDescription: "Bagian tertentu dari teks dapat ditampilka sebagai URL."
|
||||
bold: "Tebal"
|
||||
boldDescription: "Sorot tulisan dengan membuatnya tebal."
|
||||
small: "Kecil"
|
||||
smallDescription: "Tampilkan konten kecil dan tipis."
|
||||
center: "Tengah"
|
||||
centerDescription: "Tampilkan konten di tengah."
|
||||
inlineCode: "Kode (Dalam baris)"
|
||||
inlineCodeDescription: "Menampilkan sorotan sintaks dalam baris untuk kode(program-)."
|
||||
blockCode: "Kode (Blok)"
|
||||
blockCodeDescription: "Menampilkan sorotan sintaks untuk kode(program-) multi baris dalam sebuah blok."
|
||||
inlineMath: "Matematika (Dalam baris)"
|
||||
inlineMathDescription: "Menampilkan formula matematika (KaTeX) dalam baris."
|
||||
blockMath: "Matematika (Blok)"
|
||||
blockMathDescription: "Menampilkan formula matematika (KaTeX) multibaris dalam sebuah blok."
|
||||
quote: "Kutip"
|
||||
quoteDescription: "Menampilkan konten sebagai kutipan."
|
||||
emoji: "Emoji kustom"
|
||||
emojiDescription: "Emoji kustom dapat ditampilkan dengan mengurung nama emoji kustom menggunakan tanda titik dua."
|
||||
search: "Penelusuran"
|
||||
searchDescription: "Menampilkan kotak pencarian dengan teks yang sudah dimasukkan."
|
||||
flip: "Balik"
|
||||
flipDescription: "Balikkan konten secara horizontal atau vertikal."
|
||||
jelly: "Animasi (Jelly)"
|
||||
jellyDescription: "Menerapkan animasi seperti jelly"
|
||||
tada: "Animasi (Tada)"
|
||||
tadaDescription: "Menerapkan animasi seperti \"Kejutan!\"."
|
||||
jump: "Animasi (Loncat)"
|
||||
jumpDescription: "Menerapkan animasi melompat."
|
||||
bounce: "Animasi (Melambung)"
|
||||
bounceDescription: "Menerapkan animasi melambung."
|
||||
shake: "Animasi (Goyang)"
|
||||
shakeDescription: "Menerapkan animasi bergoyang."
|
||||
twitch: "Animasi (Cubit)"
|
||||
twitchDescription: "Terapkan animasi cubit yang kuat."
|
||||
spin: "Animasi (Putar)"
|
||||
spinDescription: "Terapkan animasi putar."
|
||||
x2: "Besar"
|
||||
x2Description: "Tampilkan konten menjadi besar."
|
||||
x3: "Lebih besar"
|
||||
x3Description: "Tampilkan konten menjadi lebih besar."
|
||||
x4: "Sangat besar"
|
||||
x4Description: "Tampilka konten menjadi sangat besar."
|
||||
blur: "Buram"
|
||||
blurDescription: "Konten dapat diburamkan dengan efek ini. Konten dapat ditampilkan dengan jelas dengan melayangkan kursor tetikus di atasnya."
|
||||
font: "Font"
|
||||
fontDescription: "Setel font yang ditampilkan untuk konten."
|
||||
rainbow: "Pelangi"
|
||||
rainbowDescription: "Membuat konten muncul dalam warna pelangi."
|
||||
sparkle: "Kelap-kelip"
|
||||
sparkleDescription: "Memberikan konten efek partikel kelap-kelip."
|
||||
rotate: "Putar"
|
||||
rotateDescription: "Putar konten sesuai sudut yang ditentukan."
|
||||
_instanceTicker:
|
||||
none: "Jangan tampilkan"
|
||||
remote: "Tampilkan untuk pengguna luar"
|
||||
|
||||
@@ -464,7 +464,6 @@ youHaveNoGroups: "Nessun gruppo"
|
||||
joinOrCreateGroup: "Puoi creare il tuo gruppo o essere invitat@ a gruppi che già esistono."
|
||||
noHistory: "Nessuna cronologia"
|
||||
signinHistory: "Storico degli accessi al profilo"
|
||||
disableAnimatedMfm: "Disabilità i MFM animati"
|
||||
doing: "In corso..."
|
||||
category: "Categoria"
|
||||
tags: "Tag"
|
||||
@@ -1323,72 +1322,6 @@ _nsfw:
|
||||
respect: "Nascondere i media segnati come sensibli"
|
||||
ignore: "Visualizzare i media segnati come sensibili"
|
||||
force: "Nascondere tutti i media"
|
||||
_mfm:
|
||||
cheatSheet: "Bigliettino MFM"
|
||||
intro: "MFM è un linguaggio Markdown particolare che si può usare in diverse parti di Misskey. Qui puoi visualizzare a colpo d'occhio tutta la sintassi MFM utile."
|
||||
dummy: "Il Fediverso si espande con Misskey"
|
||||
mention: "Menzioni"
|
||||
mentionDescription: "Si può menzionare un utente specifico digitando il suo nome utente subito dopo il segno @."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Per indicare un hashtag si può usare il segno numerico + tag."
|
||||
url: "URL"
|
||||
urlDescription: "È possibile indicare gli URL"
|
||||
link: "Link"
|
||||
linkDescription: "È possibile associare specifici intervalli di testo agli URL"
|
||||
bold: "Grassetto"
|
||||
boldDescription: "Il testo può essere grassettato per enfasi"
|
||||
small: "vistosamente"
|
||||
smallDescription: "Il contenuto può essere visualizzato più piccolo e più sottile"
|
||||
center: "centratura"
|
||||
centerDescription: "Il contenuto può essere centrato"
|
||||
inlineCode: "Codice (inline)"
|
||||
inlineCodeDescription: "Evidenziazione della sintassi in linea di programmi e altro codice"
|
||||
blockCode: "Codice (blocco)"
|
||||
blockCodeDescription: "Evidenziazione della sintassi di programmi multilinea e di altro codice in blocchi"
|
||||
inlineMath: "Espressione matematica(Immersione)"
|
||||
inlineMathDescription: "Visualizza le formule (KaTeX) in linea."
|
||||
blockMath: "Formula matematica (blocco)"
|
||||
blockMathDescription: "Visualizzazione di formule multilinea (KaTeX) in blocchi."
|
||||
quote: "Cita il nota"
|
||||
quoteDescription: "Può indicare che il contenuto è una citazione."
|
||||
emoji: "Emoji personalizzati"
|
||||
emojiDescription: "Utilizzare i due punti per racchiudere il nome di un'emoji personalizzata e visualizzarla."
|
||||
search: "Cerca"
|
||||
searchDescription: "È possibile visualizzare una casella di ricerca precompilata."
|
||||
flip: "Inverti"
|
||||
flipDescription: "Capovolgere il contenuto verso l'alto o verso il basso, a sinistra o a destra."
|
||||
jelly: "Animazione (Biyon Biyon)."
|
||||
jellyDescription: "Dà un'animazione di salto."
|
||||
tada: "Animazione (jang)."
|
||||
tadaDescription: "Ta-da! dà un'animazione che assomiglia a."
|
||||
jump: "Animazione(salto)"
|
||||
jumpDescription: "Da un animazione che salta su e giù."
|
||||
bounce: "Animazione(rimbalzo)"
|
||||
bounceDescription: "Rende il testo rimbalzante"
|
||||
shake: "rimbalzante"
|
||||
shakeDescription: "Rende il testo traballante"
|
||||
twitch: "testo"
|
||||
twitchDescription: "Fa tremare il testo"
|
||||
spin: "Animazione (rotazione)"
|
||||
spinDescription: "Fornisce un'animazione rotante."
|
||||
x2: "Più grande"
|
||||
x2Description: "Mostra il contenuto ingrandito."
|
||||
x3: "Molto più grande"
|
||||
x3Description: "Mostra il contenuto molto più ingrandito."
|
||||
x4: "Estremamente più grande"
|
||||
x4Description: "Mostra il contenuto estremamente più ingrandito."
|
||||
blur: "Sfocatura"
|
||||
blurDescription: "È possibile rendere sfocato il contenuto. Spostando il cursore su di esso tornerà visibile chiaramente."
|
||||
font: "Tipo di carattere"
|
||||
fontDescription: "Puoi scegliere il tipo di carattere per il contenuto."
|
||||
rainbow: "Arcobaleno"
|
||||
rainbowDescription: "Arcobaleno il contenuto."
|
||||
sparkle: "brillantini"
|
||||
sparkleDescription: "Aggiungere effetti particellari scintillanti."
|
||||
rotate: "Ruota"
|
||||
rotateDescription: "Ruota con un angolo specificato."
|
||||
plain: "Testo semplice"
|
||||
plainDescription: "Disattiva tutta la sintassi interna."
|
||||
_instanceTicker:
|
||||
none: "Nascondi"
|
||||
remote: "Mostra solo per i profili remoti"
|
||||
|
||||
@@ -103,6 +103,8 @@ renoted: "Renoteしました。"
|
||||
cantRenote: "この投稿はRenoteできません。"
|
||||
cantReRenote: "RenoteをRenoteすることはできません。"
|
||||
quote: "引用"
|
||||
inChannelRenote: "チャンネル内Renote"
|
||||
inChannelQuote: "チャンネル内引用"
|
||||
pinnedNote: "ピン留めされたノート"
|
||||
pinned: "ピン留め"
|
||||
you: "あなた"
|
||||
@@ -257,6 +259,8 @@ noMoreHistory: "これより過去の履歴はありません"
|
||||
startMessaging: "チャットを開始"
|
||||
nUsersRead: "{n}人が読みました"
|
||||
agreeTo: "{0}に同意"
|
||||
agreeBelow: "下記に同意する"
|
||||
basicNotesBeforeCreateAccount: "基本的な注意事項"
|
||||
tos: "利用規約"
|
||||
start: "始める"
|
||||
home: "ホーム"
|
||||
@@ -465,7 +469,8 @@ youHaveNoGroups: "グループがありません"
|
||||
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループを作成してください。"
|
||||
noHistory: "履歴はありません"
|
||||
signinHistory: "ログイン履歴"
|
||||
disableAnimatedMfm: "動きのあるMFMを無効にする"
|
||||
enableAdvancedMfm: "高度なMFMを有効にする"
|
||||
enableAnimatedMfm: "動きのあるMFMを有効にする"
|
||||
doing: "やっています"
|
||||
category: "カテゴリ"
|
||||
tags: "タグ"
|
||||
@@ -862,6 +867,8 @@ failedToFetchAccountInformation: "アカウント情報の取得に失敗しま
|
||||
rateLimitExceeded: "レート制限を超えました"
|
||||
cropImage: "画像のクロップ"
|
||||
cropImageAsk: "画像をクロップしますか?"
|
||||
cropYes: "クロップする"
|
||||
cropNo: "そのまま使う"
|
||||
file: "ファイル"
|
||||
recentNHours: "直近{n}時間"
|
||||
recentNDays: "直近{n}日"
|
||||
@@ -940,6 +947,16 @@ cannotPerformTemporaryDescription: "操作回数が制限を超過するため
|
||||
preset: "プリセット"
|
||||
selectFromPresets: "プリセットから選択"
|
||||
achievements: "実績"
|
||||
gotInvalidResponseError: "サーバーの応答が無効です"
|
||||
gotInvalidResponseErrorDescription: "サーバーがダウンまたはメンテナンスしている可能性があります。しばらくしてから再度お試しください。"
|
||||
thisPostMayBeAnnoying: "この投稿は迷惑になる可能性があります。"
|
||||
thisPostMayBeAnnoyingHome: "ホームに投稿"
|
||||
thisPostMayBeAnnoyingCancel: "やめる"
|
||||
thisPostMayBeAnnoyingIgnore: "このまま投稿"
|
||||
collapseRenotes: "見たことのあるRenoteを省略して表示"
|
||||
internalServerError: "サーバー内部エラー"
|
||||
internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
|
||||
copyErrorInfo: "エラー情報をコピー"
|
||||
|
||||
_achievements:
|
||||
earnedAt: "獲得日時"
|
||||
@@ -1341,73 +1358,6 @@ _nsfw:
|
||||
ignore: "閲覧注意のメディアを隠さない"
|
||||
force: "常にメディアを隠す"
|
||||
|
||||
_mfm:
|
||||
cheatSheet: "MFMチートシート"
|
||||
intro: "MFMは、Misskey内の様々な場所で使用できる専用のマークアップ言語です。ここでは、MFMで使用可能な構文一覧が確認できます。"
|
||||
dummy: "MisskeyでFediverseの世界が広がります"
|
||||
mention: "メンション"
|
||||
mentionDescription: "アットマーク + ユーザー名で、特定のユーザーを示すことができます。"
|
||||
hashtag: "ハッシュタグ"
|
||||
hashtagDescription: "ナンバーサイン + タグで、ハッシュタグを示すことができます。"
|
||||
url: "URL"
|
||||
urlDescription: "URLを示すことができます。"
|
||||
link: "リンク"
|
||||
linkDescription: "文章の特定の範囲を、URLに紐づけることができます。"
|
||||
bold: "太字"
|
||||
boldDescription: "文字を太く表示して強調することができます。"
|
||||
small: "目立たなく"
|
||||
smallDescription: "内容を小さく・薄く表示させることができます。"
|
||||
center: "中央寄せ"
|
||||
centerDescription: "内容を中央寄せで表示させることができます。"
|
||||
inlineCode: "コード(インライン)"
|
||||
inlineCodeDescription: "プログラムなどのコードをインラインでシンタックスハイライトします。"
|
||||
blockCode: "コード(ブロック)"
|
||||
blockCodeDescription: "複数行のプログラムなどのコードをブロックでシンタックスハイライトします。"
|
||||
inlineMath: "数式(インライン)"
|
||||
inlineMathDescription: "数式(KaTeX)をインラインで表示します。"
|
||||
blockMath: "数式(ブロック)"
|
||||
blockMathDescription: "複数行の数式(KaTeX)をブロックで表示します。"
|
||||
quote: "引用"
|
||||
quoteDescription: "内容が引用であることを示すことができます。"
|
||||
emoji: "カスタム絵文字"
|
||||
emojiDescription: "コロンでカスタム絵文字名を囲むと、カスタム絵文字を表示させることができます。"
|
||||
search: "検索"
|
||||
searchDescription: "入力済み検索ボックスを表示させることができます。"
|
||||
flip: "反転"
|
||||
flipDescription: "内容を上下または左右に反転させます。"
|
||||
jelly: "アニメーション(びよんびよん)"
|
||||
jellyDescription: "びよんびよんするアニメーションを与えます。"
|
||||
tada: "アニメーション(じゃーん)"
|
||||
tadaDescription: "ジャーン!という感じのアニメーションを与えます。"
|
||||
jump: "アニメーション(ジャンプ)"
|
||||
jumpDescription: "飛び跳ねるようなアニメーションを与えます。"
|
||||
bounce: "アニメーション(バウンド)"
|
||||
bounceDescription: "ぽよんぽよん弾むようなアニメーションを与えます。"
|
||||
shake: "アニメーション(ぶるぶる)"
|
||||
shakeDescription: "ぶるぶる震えるアニメーションを与えます。"
|
||||
twitch: "アニメーション(ブレ)"
|
||||
twitchDescription: "激しくブレるアニメーションを与えます。"
|
||||
spin: "アニメーション(回転)"
|
||||
spinDescription: "回転するアニメーションを与えます。"
|
||||
x2: "大きく"
|
||||
x2Description: "内容を大きく表示します。"
|
||||
x3: "とても大きく"
|
||||
x3Description: "内容をとても大きく表示します。"
|
||||
x4: "究極に大きく"
|
||||
x4Description: "内容を究極に大きく表示します。"
|
||||
blur: "ぼかし"
|
||||
blurDescription: "内容をぼかすことができます。ポインターを上に乗せるとはっきり見えるようになります。"
|
||||
font: "フォント"
|
||||
fontDescription: "内容のフォントを指定することができます。"
|
||||
rainbow: "レインボー"
|
||||
rainbowDescription: "内容をレインボーにします。"
|
||||
sparkle: "キラキラ"
|
||||
sparkleDescription: "キラキラしたパーティクルのエフェクトを追加します。"
|
||||
rotate: "回転"
|
||||
rotateDescription: "指定した角度で回転させます。"
|
||||
plain: "プレーン"
|
||||
plainDescription: "内側の構文を全て無効にします。"
|
||||
|
||||
_instanceTicker:
|
||||
none: "表示しない"
|
||||
remote: "リモートユーザーに表示"
|
||||
@@ -1626,12 +1576,15 @@ _permissions:
|
||||
"write:gallery-likes": "ギャラリーのいいねを操作する"
|
||||
|
||||
_auth:
|
||||
shareAccessTitle: "アプリへのアクセス許可"
|
||||
shareAccess: "「{name}」がアカウントにアクセスすることを許可しますか?"
|
||||
shareAccessAsk: "アカウントへのアクセスを許可しますか?"
|
||||
permission: "{name}は次の権限を要求しています"
|
||||
permissionAsk: "このアプリは次の権限を要求しています"
|
||||
pleaseGoBack: "アプリケーションに戻ってやっていってください"
|
||||
callback: "アプリケーションに戻っています"
|
||||
denied: "アクセスを拒否しました"
|
||||
pleaseLogin: "アプリケーションにアクセス許可を与えるには、ログインが必要です。"
|
||||
|
||||
_antennaSources:
|
||||
all: "全てのノート"
|
||||
|
||||
@@ -46,7 +46,7 @@ copyContent: "内容をコピー"
|
||||
copyLink: "リンクをコピー"
|
||||
delete: "ほかす"
|
||||
deleteAndEdit: "ほかして直す"
|
||||
deleteAndEditConfirm: "このノートをほかして書き直すんか?このノートへのリアクション、Renote、返信も全部消えてまうで。"
|
||||
deleteAndEditConfirm: "このノートをほかしてもっかい直す?このノートへのリアクション、Renote、返信も全部消えるんやけどそれでもええん?"
|
||||
addToList: "リストに入れたる"
|
||||
sendMessage: "メッセージを送る"
|
||||
copyRSS: "RSSをコピー"
|
||||
@@ -89,7 +89,7 @@ serverIsDead: "サーバーからの応答がないで。もうちょい待っ
|
||||
youShouldUpgradeClient: "このページを表示するには、リロードして新しいバージョンのクライアントを使ってなー。"
|
||||
enterListName: "リスト名を入れてや"
|
||||
privacy: "プライバシー"
|
||||
makeFollowManuallyApprove: "自分が認めた人だけがこのアカウントをフォローできるようにする"
|
||||
makeFollowManuallyApprove: "他人のフォローは許可してからや!"
|
||||
defaultNoteVisibility: "もとからの公開範囲"
|
||||
follow: "フォロー"
|
||||
followRequest: "フォローを頼む"
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "ブロックやめたるってほんまか?"
|
||||
suspendConfirm: "凍結してしもうてええか?"
|
||||
unsuspendConfirm: "解凍するけどええか?"
|
||||
selectList: "リストを選ぶ"
|
||||
selectChannel: "チャンネルを選ぶ"
|
||||
selectAntenna: "アンテナを選ぶ"
|
||||
selectWidget: "ウィジェットを選ぶ"
|
||||
editWidgets: "ウィジェットをいじる"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "これより過去の履歴はあらへんで"
|
||||
startMessaging: "チャットやるで"
|
||||
nUsersRead: "{n}人が読んでもうた"
|
||||
agreeTo: "{0}に同意したで"
|
||||
agreeBelow: "下記に同意したる"
|
||||
basicNotesBeforeCreateAccount: "よう読んでやってや"
|
||||
tos: "利用規約"
|
||||
start: "始める"
|
||||
home: "ホーム"
|
||||
@@ -300,7 +303,7 @@ avatar: "アイコン"
|
||||
banner: "バナー"
|
||||
nsfw: "閲覧注意"
|
||||
whenServerDisconnected: "サーバーとの接続が切れたとき"
|
||||
disconnectedFromServer: "サーバーとの通信が切れたで"
|
||||
disconnectedFromServer: "サーバーが機嫌悪いねん"
|
||||
reload: "リロード"
|
||||
doNothing: "何もせんとく"
|
||||
reloadConfirm: "リロードしてええか?"
|
||||
@@ -464,7 +467,8 @@ youHaveNoGroups: "グループがあらへんねぇ。"
|
||||
joinOrCreateGroup: "既存のグループに招待してもらうか、新しくグループ作ってからやってな"
|
||||
noHistory: "履歴はあらへんねぇ。"
|
||||
signinHistory: "ログイン履歴"
|
||||
disableAnimatedMfm: "動きがやかましいMFMを止める"
|
||||
enableAdvancedMfm: "ややこしいMFMもありにする"
|
||||
enableAnimatedMfm: "動きがやかましいMFMも許したる"
|
||||
doing: "やっとるがな"
|
||||
category: "カテゴリ"
|
||||
tags: "タグ"
|
||||
@@ -673,8 +677,8 @@ sentReactionsCount: "リアクションした数やで"
|
||||
receivedReactionsCount: "リアクションされた数"
|
||||
pollVotesCount: "アンケートに投票した数"
|
||||
pollVotedCount: "アンケートに投票された数"
|
||||
yes: "はい"
|
||||
no: "いいえ"
|
||||
yes: "ええで"
|
||||
no: "あかんで"
|
||||
driveFilesCount: "ドライブのファイル数"
|
||||
driveUsage: "ドライブ使用量やで"
|
||||
noCrawle: "クローラーによるインデックスを拒否するで"
|
||||
@@ -861,6 +865,8 @@ failedToFetchAccountInformation: "アカウントの取得に失敗したみた
|
||||
rateLimitExceeded: "レート制限が超えたみたいやで"
|
||||
cropImage: "画像のクロップ"
|
||||
cropImageAsk: "画像をクロップしたってええか?"
|
||||
cropYes: "切り抜いたる"
|
||||
cropNo: "切り抜かへん"
|
||||
file: "ファイル"
|
||||
recentNHours: "直近{n}時間"
|
||||
recentNDays: "直近{n}日"
|
||||
@@ -938,6 +944,39 @@ cannotPerformTemporary: "一時的に利用できへんで"
|
||||
cannotPerformTemporaryDescription: "操作回数が制限を超えたから一時的に利用できへんくなったで。ちょっと時間置いてからもう一回やってやー。"
|
||||
preset: "プリセット"
|
||||
selectFromPresets: "プリセットから選ぶ"
|
||||
achievements: "実績"
|
||||
gotInvalidResponseError: "サーバー黙っとるわ、知らんけど"
|
||||
gotInvalidResponseErrorDescription: "サーバーいま日曜日。またきて月曜日。"
|
||||
thisPostMayBeAnnoying: "この投稿は迷惑かもしらんで。"
|
||||
collapseRenotes: "見たことあるRenoteは省略やで"
|
||||
_achievements:
|
||||
earnedAt: "貰った日ぃ"
|
||||
_types:
|
||||
_notes1:
|
||||
title: "まいど!"
|
||||
description: "初めてノート投稿したった"
|
||||
_notes10:
|
||||
title: "ノートの天保山"
|
||||
_notes100:
|
||||
title: "ノートの真田山"
|
||||
_notes500:
|
||||
title: "ノートの生駒山"
|
||||
_notes5000:
|
||||
title: "箕面の滝からノート"
|
||||
_login3:
|
||||
flavor: "今日からワシはミスキストやで"
|
||||
_iLoveMisskey:
|
||||
title: "Misskey好きやねん"
|
||||
_foundTreasure:
|
||||
title: "なんでも鑑定団"
|
||||
_client30min:
|
||||
title: "ねんね"
|
||||
_noteDeletedWithin1min:
|
||||
title: "*おおっと*"
|
||||
_open3windows:
|
||||
title: "マド開けすぎ"
|
||||
_driveFolderCircularReference:
|
||||
title: "環状線"
|
||||
_role:
|
||||
new: "ロールの作成"
|
||||
edit: "ロールの編集"
|
||||
@@ -1083,72 +1122,6 @@ _nsfw:
|
||||
respect: "閲覧注意のメディアは隠すで"
|
||||
ignore: "閲覧注意のメディアは隠さへんで"
|
||||
force: "常にメディアを隠すで"
|
||||
_mfm:
|
||||
cheatSheet: "MFMチートシート"
|
||||
intro: "MFMは、Misskey内の色んな所で使える専用のマークアップ言語やで。このページでMFMで使える構文一覧が確認できるで。"
|
||||
dummy: "MisskeyでFediverseの世界が広がります"
|
||||
mention: "メンション"
|
||||
mentionDescription: "アットマーク + ユーザー名で、特定のユーザーを示すことができるで。"
|
||||
hashtag: "ハッシュタグ"
|
||||
hashtagDescription: "ナンバーサイン + タグで、ハッシュタグを示すことができるで。"
|
||||
url: "URL"
|
||||
urlDescription: "URLを示すことができるで。"
|
||||
link: "リンク"
|
||||
linkDescription: "文章の特定の範囲をURLに紐づけることができるで"
|
||||
bold: "太字"
|
||||
boldDescription: "文字を太く表示して強調することができるで"
|
||||
small: "目立たなく"
|
||||
smallDescription: "内容を小さく・薄く表示することができるで"
|
||||
center: "中央寄せ"
|
||||
centerDescription: "内容を中央寄せで表示することができるで"
|
||||
inlineCode: "コード(インライン)"
|
||||
inlineCodeDescription: "プログラムとかのコードをインラインでシンタックスハイライトするで"
|
||||
blockCode: "コード(ブロック)"
|
||||
blockCodeDescription: "複数行のプログラムとかのコードをブロックでシンタックスハイライトするで"
|
||||
inlineMath: "数式(インライン)"
|
||||
inlineMathDescription: "数式(KaTeX)をインラインで表示するで"
|
||||
blockMath: "数式(ブロック)"
|
||||
blockMathDescription: "複数行の数式(KaTeX)をブロックで表示するで"
|
||||
quote: "引用"
|
||||
quoteDescription: "内容が引用ってことを示すことができるで"
|
||||
emoji: "カスタム絵文字"
|
||||
emojiDescription: "コロンでカスタム絵文字名を囲んだると、カスタム絵文字を表示させることができるで"
|
||||
search: "探す"
|
||||
searchDescription: "入力済み検索ボックスを表示することができるで"
|
||||
flip: "反転"
|
||||
flipDescription: "内容を上下または左右に反転するで"
|
||||
jelly: "アニメーション(びよんびよん)"
|
||||
jellyDescription: "びよんびよんするアニメーションやな。"
|
||||
tada: "アニメーション(じゃーん)"
|
||||
tadaDescription: "ジャーン!ってな感じのアニメーションやな。"
|
||||
jump: "アニメーション(ジャンプ)"
|
||||
jumpDescription: "飛び跳ねるようなアニメーションやな。"
|
||||
bounce: "アニメーション(バウンド)"
|
||||
bounceDescription: "ぽよんぽよん弾むようなアニメーションやな。"
|
||||
shake: "アニメーション(ぶるぶる)"
|
||||
shakeDescription: "ぶるぶる震えるアニメーションやな。"
|
||||
twitch: "アニメーション(ブレ)"
|
||||
twitchDescription: "激しくブレるアニメーションやな。"
|
||||
spin: "アニメーション(回転)"
|
||||
spinDescription: "回転するアニメーションやな。"
|
||||
x2: "大きく"
|
||||
x2Description: "内容を大きく表示するで"
|
||||
x3: "とても大きく"
|
||||
x3Description: "内容をとても大きく表示するで"
|
||||
x4: "究極に大きく"
|
||||
x4Description: "内容を究極に大きく表示するで"
|
||||
blur: "ぼかし"
|
||||
blurDescription: "内容をぼかすことができるで。ポインターを上に乗せるとはっきり見えるようになるで"
|
||||
font: "フォント"
|
||||
fontDescription: "内容のフォントを指定することができるで"
|
||||
rainbow: "レインボー"
|
||||
rainbowDescription: "内容をレインボーにするで"
|
||||
sparkle: "キラキラ"
|
||||
sparkleDescription: "キラキラしたバーティ来るのエフェクトを追加するで"
|
||||
rotate: "回転"
|
||||
rotateDescription: "指定した角度で回転させるで"
|
||||
plain: "プレーン"
|
||||
plainDescription: "内側の構文を全部無効にするで"
|
||||
_instanceTicker:
|
||||
none: "表示せん"
|
||||
remote: "リモートユーザーに表示"
|
||||
@@ -1355,10 +1328,12 @@ _permissions:
|
||||
_auth:
|
||||
shareAccess: "「{name}」がアカウントにアクセスすることを許可してええか?"
|
||||
shareAccessAsk: "アカウントのアクセスを許可してもええか?"
|
||||
permission: "{name}に次の権限つけたってやって"
|
||||
permissionAsk: "このアプリは次の権限を要求しとるで"
|
||||
pleaseGoBack: "アプリケーションに戻ってええよ"
|
||||
callback: "アプリケーションに戻っとるで"
|
||||
denied: "アクセスを拒否ったで"
|
||||
pleaseLogin: "アプリにアクセスさせるんやったら、ログインしてや。"
|
||||
_antennaSources:
|
||||
all: "みんなのノート"
|
||||
homeTimeline: "フォローしとるユーザーのノート"
|
||||
@@ -1587,6 +1562,7 @@ _notification:
|
||||
pollEnded: "アンケートの結果が出たみたいや"
|
||||
unreadAntennaNote: "アンテナ {name}"
|
||||
emptyPushNotificationMessage: "プッシュ通知の更新をしといたで"
|
||||
achievementEarned: "実績を獲得しとるで"
|
||||
_types:
|
||||
all: "すべて"
|
||||
follow: "フォロー"
|
||||
|
||||
@@ -61,10 +61,6 @@ account: "Imiḍan"
|
||||
_email:
|
||||
_follow:
|
||||
title: "Yeṭṭafaṛ-ik·em-id"
|
||||
_mfm:
|
||||
mention: "Bder"
|
||||
search: "Nadi"
|
||||
font: "Tasefsit"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Bder"
|
||||
|
||||
@@ -64,8 +64,6 @@ file: "ಕಡತಗಳು"
|
||||
_email:
|
||||
_follow:
|
||||
title: "ಹಿಂಬಾಲಿಸಿದರು"
|
||||
_mfm:
|
||||
search: "ಹುಡುಕು"
|
||||
_sfx:
|
||||
notification: "ಅಧಿಸೂಚನೆಗಳು"
|
||||
_widgets:
|
||||
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "이 계정의 차단을 해제하시겠습니까?"
|
||||
suspendConfirm: "이 계정을 정지하시겠습니까?"
|
||||
unsuspendConfirm: "이 계정의 정지를 해제하시겠습니까?"
|
||||
selectList: "리스트 선택"
|
||||
selectChannel: "채널 선택"
|
||||
selectAntenna: "안테나 선택"
|
||||
selectWidget: "위젯 선택"
|
||||
editWidgets: "위젯 편집"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "이것보다 과거의 기록이 없습니다"
|
||||
startMessaging: "대화 시작하기"
|
||||
nUsersRead: "{n}명이 읽음"
|
||||
agreeTo: "{0}에 동의"
|
||||
agreeBelow: "아래 내용에 동의합니다"
|
||||
basicNotesBeforeCreateAccount: "기본적인 주의사항"
|
||||
tos: "이용 약관"
|
||||
start: "시작하기"
|
||||
home: "홈"
|
||||
@@ -464,7 +467,8 @@ youHaveNoGroups: "그룹이 없습니다"
|
||||
joinOrCreateGroup: "다른 그룹의 초대를 받거나, 직접 새 그룹을 만들어 보세요."
|
||||
noHistory: "기록이 없습니다"
|
||||
signinHistory: "로그인 기록"
|
||||
disableAnimatedMfm: "움직임이 있는 MFM을 비활성화"
|
||||
enableAdvancedMfm: "고급 MFM을 활성화"
|
||||
enableAnimatedMfm: "움직임이 있는 MFM을 활성화"
|
||||
doing: "잠시만요"
|
||||
category: "카테고리"
|
||||
tags: "태그"
|
||||
@@ -861,6 +865,8 @@ failedToFetchAccountInformation: "계정 정보를 가져오지 못했습니다"
|
||||
rateLimitExceeded: "요청 제한 횟수를 초과하였습니다"
|
||||
cropImage: "이미지 자르기"
|
||||
cropImageAsk: "이미지를 자르시겠습니까?"
|
||||
cropYes: "잘라내기"
|
||||
cropNo: "그대로 사용"
|
||||
file: "파일"
|
||||
recentNHours: "최근 {n}시간"
|
||||
recentNDays: "최근 {n}일"
|
||||
@@ -939,6 +945,12 @@ cannotPerformTemporaryDescription: "조작 횟수 제한을 초과하여 일시
|
||||
preset: "프리셋"
|
||||
selectFromPresets: "프리셋에서 선택"
|
||||
achievements: "도전 과제"
|
||||
gotInvalidResponseError: "서버의 응답이 올바르지 않습니다"
|
||||
gotInvalidResponseErrorDescription: " 서버가 다운되었거나 점검중일 가능성이 있습니다. 잠시후에 다시 시도해 주십시오."
|
||||
thisPostMayBeAnnoying: "이 게시물은 다른 유저에게 피해를 줄 가능성이 있습니다."
|
||||
thisPostMayBeAnnoyingHome: "홈에 게시"
|
||||
thisPostMayBeAnnoyingCancel: "그만두기"
|
||||
thisPostMayBeAnnoyingIgnore: "이대로 게시"
|
||||
_achievements:
|
||||
earnedAt: "달성 일시"
|
||||
_types:
|
||||
@@ -1195,6 +1207,9 @@ _role:
|
||||
baseRole: "기본 역할"
|
||||
useBaseValue: "기본값 사용"
|
||||
chooseRoleToAssign: "할당할 역할 선택"
|
||||
iconUrl: "아이콘 URL"
|
||||
asBadge: "뱃지로 표시"
|
||||
descriptionOfAsBadge: "활성화하면 유저명 옆에 역할의 아이콘이 표시됩니다."
|
||||
canEditMembersByModerator: "모더레이터의 역할 수정 허용"
|
||||
descriptionOfCanEditMembersByModerator: "이 옵션을 켜면 모더레이터도 이 역할에 사용자를 할당하거나 삭제할 수 있습니다. 꺼져 있으면 관리자만 할당이 가능합니다."
|
||||
priority: "우선순위"
|
||||
@@ -1320,72 +1335,6 @@ _nsfw:
|
||||
respect: "열람주의로 설정된 미디어 숨기기"
|
||||
ignore: "열람 주의 미디어 항상 표시"
|
||||
force: "미디어 항상 숨기기"
|
||||
_mfm:
|
||||
cheatSheet: "MFM 도움말"
|
||||
intro: "MFM는 Misskey의 다양한 곳에서 사용할 수 있는 전용 마크업 언어입니다. 여기에서는 MFM에서 사용할 수 있는 구문을 확인할 수 있습니다."
|
||||
dummy: "Misskey로 연합우주의 세계가 펼쳐집니다"
|
||||
mention: "멘션"
|
||||
mentionDescription: "골뱅이표(@) 뒤에 사용자명을 넣어 특정 유저를 나타낼 수 있습니다."
|
||||
hashtag: "해시태그"
|
||||
hashtagDescription: "샵 또는 우물정자(#)를 앞에 붙여서 해시태그를 나타낼 수 있습니다."
|
||||
url: "URL"
|
||||
urlDescription: "URL을 나타낼 수 있습니다."
|
||||
link: "링크"
|
||||
linkDescription: "문장의 특정 범위를 URL로 표시합니다."
|
||||
bold: "굵음/볼드체"
|
||||
boldDescription: "문자를 굵게 강조합니다."
|
||||
small: "눈에 띄지 않음"
|
||||
smallDescription: "내용을 작고 연하게 보이게 합니다."
|
||||
center: "가운데 정렬"
|
||||
centerDescription: "내용을 가운데 정렬로 보이게 합니다."
|
||||
inlineCode: "코드(인라인)"
|
||||
inlineCodeDescription: "여러 행의 코드를 문법 강조를 적용하여 인라인으로 표시합니다."
|
||||
blockCode: "코드(블록)"
|
||||
blockCodeDescription: "여러 행의 코드를 문법 강조를 적용하여 블록으로 표시합니다."
|
||||
inlineMath: "수식(인라인)"
|
||||
inlineMathDescription: "수식(KaTeX)를 인라인으로 보이게 합니다."
|
||||
blockMath: "수식(블록)"
|
||||
blockMathDescription: "여러 줄의 수식(KaTeX)를 블록으로 보이게 합니다."
|
||||
quote: "인용"
|
||||
quoteDescription: "내용을 인용문으로 표시합니다."
|
||||
emoji: "커스텀 이모지"
|
||||
emojiDescription: "커스텀 이모지의 이름을 쌍점(:)으로 감싸서 커스텀 이모지를 사용합니다."
|
||||
search: "검색"
|
||||
searchDescription: "주어진 키워드가 입력된 검색창을 보이게 합니다."
|
||||
flip: "플립"
|
||||
flipDescription: "내용을 상하 또는 좌우로 반전시킵니다."
|
||||
jelly: "애니메이션 (젤리)"
|
||||
jellyDescription: "젤리처럼 탱글탱글한 느낌의 효과를 줍니다."
|
||||
tada: "애니메이션 (짠!)"
|
||||
tadaDescription: "짠! 하는 느낌의 효과를 줍니다."
|
||||
jump: "애니메이션(점프)"
|
||||
jumpDescription: "펄쩍 뛸 듯한 느낌의 효과를 줍니다."
|
||||
bounce: "애니메이션 (바운스)"
|
||||
bounceDescription: "통통 튀는 느낌의 효과를 줍니다."
|
||||
shake: "애니메이션 (부들부들)"
|
||||
shakeDescription: "부들부들 떠는 느낌의 효과를 줍니다."
|
||||
twitch: "애니메이션 (경련)"
|
||||
twitchDescription: "격하게 흔들리는 느낌의 효과를 줍니다."
|
||||
spin: "애니메이션 (회전)"
|
||||
spinDescription: "회전 효과를 줍니다."
|
||||
x2: "크게"
|
||||
x2Description: "내용을 크게 표시합니다."
|
||||
x3: "더 크게"
|
||||
x3Description: "내용을 더 크게 표시합니다."
|
||||
x4: "매우 크게"
|
||||
x4Description: "내용을 매우 크게 표시합니다."
|
||||
blur: "흐림"
|
||||
blurDescription: "내용이 흐리게 보입니다. 마우스를 위에 올려두면 내용이 보입니다."
|
||||
font: "폰트"
|
||||
fontDescription: "내용의 글꼴을 지정할 수 있습니다."
|
||||
rainbow: "무지개"
|
||||
rainbowDescription: "내용을 무지개로 표시합니다."
|
||||
sparkle: "반짝반짝"
|
||||
sparkleDescription: "반짝이는 파티클 효과를 추가합니다."
|
||||
rotate: "회전"
|
||||
rotateDescription: "지정한 각도로 회전시킵니다."
|
||||
plain: "평문"
|
||||
plainDescription: "안에 있는 MFM 구문을 모두 무시하고 평문으로 표시합니다."
|
||||
_instanceTicker:
|
||||
none: "보이지 않음"
|
||||
remote: "리모트 유저에게만 보이기"
|
||||
@@ -1590,12 +1539,15 @@ _permissions:
|
||||
"read:gallery-likes": "갤러리의 좋아요를 확인합니다"
|
||||
"write:gallery-likes": "갤러리에 좋아요를 추가하거나 취소합니다"
|
||||
_auth:
|
||||
shareAccessTitle: "어플리케이션의 접근 허가"
|
||||
shareAccess: "\"{name}\" 이 계정에 접근하는 것을 허용하시겠습니까?"
|
||||
shareAccessAsk: "이 애플리케이션이 계정에 접근하는 것을 허용하시겠습니까?"
|
||||
permission: "{name}에서 다음 권한을 요청하였습니다"
|
||||
permissionAsk: "이 앱은 다음의 권한을 요청합니다"
|
||||
pleaseGoBack: "앱으로 돌아가서 시도해 주세요"
|
||||
callback: "앱으로 돌아갑니다"
|
||||
denied: "접근이 거부되었습니다"
|
||||
pleaseLogin: "어플리케이션의 접근을 허가하려면 로그인하십시오."
|
||||
_antennaSources:
|
||||
all: "모든 노트"
|
||||
homeTimeline: "팔로우중인 유저의 노트"
|
||||
|
||||
@@ -49,24 +49,191 @@ deleteAndEdit: "ລົບແລະແກ້ໄຂ"
|
||||
deleteAndEditConfirm: "ເຈົ້າແນ່ໃຈບໍ່? ທີ່ທ່ານຕ້ອງການທີ່ຈະລຶບບັນທຶກນີ້ແລະແກ້ໄຂມັນ ທ່ານອາດຈະສູນເສຍການໂຕ້ຕອບ, ບັນທຶກ, ແລະການຕອບກັບທັງໝົດ"
|
||||
addToList: "ເພີ່ມໃສ່ລາຍຊື່"
|
||||
sendMessage: "ສົ່ງຂໍ້ຄວາມ"
|
||||
copyRSS: "ສຳເນົາ RSS"
|
||||
copyUsername: "ສຳເນົາຊື່ຜູ້ໃຊ້"
|
||||
searchUser: "ຄົ້ນຫາຜູ້ໃຊ້"
|
||||
reply: "ຕອບໄປທີ"
|
||||
loadMore: "ໂຫຼດເພີ່ມເຕີມ"
|
||||
showMore: "ໂຫຼດເພີ່ມເຕີມ"
|
||||
showLess: "ປິດ"
|
||||
youGotNewFollower: "ໄດ້ຕິດຕາມທ່ານ"
|
||||
receiveFollowRequest: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍທີ່ໄດ້ຮັບ"
|
||||
followRequestAccepted: "ຜູ້ຕິດຕາມໄດ້ຍອມຮັບຄໍາຮ້ອງຂໍຂອງທ່ານ"
|
||||
mention: "ໄດ້ກ່າວມາ"
|
||||
mentions: "ກ່າວເຖິງ"
|
||||
directNotes: "ໂດຍກົງຫມາຍເຫດ"
|
||||
importAndExport: "ນໍາເຂົ້າ / ສົ່ງອອກ"
|
||||
import: "ນຳເຂົ້າ"
|
||||
export: "ນຳອອກ"
|
||||
files: "ໄຟລ໌"
|
||||
download: "ດາວໂຫລດ"
|
||||
driveFileDeleteConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການລຶບໄຟລ໌ \"{name}\"? ບັນທຶກທີ່ມີໄຟລ໌ແນບນີ້ຈະຖືກລຶບຖິ້ມ"
|
||||
unfollowConfirm: "ທ່ານແນ່ໃຈບໍ່ວ່າຕ້ອງການເຊົາຕິດຕາມ {name}?"
|
||||
exportRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການສົ່ງອອກ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ ແລະມັນຈະຖືກເພີ່ມໃສ່ drive ຂອງທ່ານເມື່ອມັນສຳເລັດແລ້ວ"
|
||||
importRequested: "ໃນເວລາທີ່ທ່ານໄດ້ຮ້ອງຂໍການນໍາເຂົ້າ ມັນອາດຈະໃຊ້ເວລາບາງເວລາ"
|
||||
lists: "ລາຍການ"
|
||||
noLists: "ທ່ານບໍ່ມີລາຍການໃດໆ"
|
||||
note: "ບັນທຶກ"
|
||||
notes: "ບັນທຶກ"
|
||||
following: "ກຳລັງຕິດຕາມ"
|
||||
followers: "ຜູ້ຕິດຕາມ"
|
||||
followsYou: "ຕິດຕາມເຈົ້າ"
|
||||
createList: "ສ້າງລາຍຊື່"
|
||||
manageLists: "ການບໍລິຫານບັນຊີລາຍການ"
|
||||
error: "ຂໍ້ຜິດພາດ"
|
||||
somethingHappened: "ອຸຍ, ມີບາງຢ່າງຜິດພາດ"
|
||||
retry: "ລອງໃຫມ່"
|
||||
pageLoadError: "ເກີດຄວາມຜິດພາດໃນການໂຫລດໜ້ານີ້"
|
||||
pageLoadErrorDescription: "ປົກກະຕິແລ້ວມັນເກີດຈາກຄວາມຜິດພາດເຄືອຂ່າຍ ຫຼື cache ຂອງຕົວທ່ອງເວັບ ລອງລຶບລ້າງແຄດແລ້ວລອງໃໝ່ພາຍຫຼັງສອງສາມນາທີ"
|
||||
serverIsDead: "ເຊີບເວີນີ້ບໍ່ຕອບສະໜອງ ກະລຸນາລໍຖ້າຈັກໜ່ອຍແລ້ວລອງໃໝ່ອີກຄັ້ງ"
|
||||
youShouldUpgradeClient: "ເພື່ອເບິ່ງໜ້ານີ້, ກະລຸນາໂຫຼດຂໍ້ມູນຄືນໃໝ່ເພື່ອອັບເດດລູກຄ້າຂອງທ່ານ"
|
||||
enterListName: "ໃສ່ຊື່ສຳລັບລາຍຊື່"
|
||||
privacy: "ຄວາມເປັນສ່ວນຕົວ"
|
||||
makeFollowManuallyApprove: "ປະຕິບັດຕາມການຮ້ອງຂໍຮຽກຮ້ອງໃຫ້ມີການອະນຸມັດ"
|
||||
defaultNoteVisibility: "ເປັນຄ່າເລີ່ມຕົ້ນ"
|
||||
follow: "ກຳລັງຕິດຕາມ"
|
||||
followRequest: "ສົ່ງການຮ້ອງຂໍປະຕິບຕາມ"
|
||||
followRequests: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍ"
|
||||
unfollow: "ເຊົາຕິດຕາມ"
|
||||
followRequestPending: "ປະຕິບັດຕາມຄໍາຮ້ອງຂໍທີ່ລໍຖ້າຢູ່"
|
||||
enterEmoji: "ປ້ອນອີໂມຈິ"
|
||||
renote: "Renote"
|
||||
unrenote: "ເລີກ Renote"
|
||||
renoted: "ເກັບບັນທຶກໄວ້"
|
||||
quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
|
||||
pinnedNote: "ບັນທຶກທີ່ປັກໝຸດໄວ້"
|
||||
pinned: "ປັກໝຸດໄປຫາໂປຣໄຟລ໌"
|
||||
you: "ເຈົ້າ"
|
||||
clickToShow: "ກົດເພື່ອສະແດງໃຫ້ເຫັນ"
|
||||
sensitive: "NSFW"
|
||||
add: "ເພີ່ມ"
|
||||
reaction: "ປະຕິກິລິຍາ"
|
||||
reactions: "ປະຕິກິລິຍາ"
|
||||
mute: "ປີດສຽງ"
|
||||
unmute: "ເປີດສຽງ"
|
||||
block: "ບ໋ອກ"
|
||||
unblock: "ຍົກເລີກກາຮົບລັອກ"
|
||||
suspend: "ລະງັບ"
|
||||
unsuspend: "ເຊົາລະງັບ"
|
||||
selectList: "ເລືອກບັນຊີລາຍການ"
|
||||
selectWidget: "ເລືອກວິກເຈັດ"
|
||||
editWidgets: "ແກ້ໄຂ Widget"
|
||||
editWidgetsExit: "ສຳເລັດແລ້ວ"
|
||||
customEmojis: "ອີໂມຈິແບບກຳນົດເອງ"
|
||||
emoji: "ອີໂມຈິ"
|
||||
emojis: "ອີໂມຈິ"
|
||||
emojiName: "ຊື່ Emoji"
|
||||
emojiUrl: "URL ອີໂມຈິ"
|
||||
addEmoji: "ຕື່ມອີໂມຈິ"
|
||||
flagAsBot: "ໝາຍບັນຊີນີ້ເປັນບັອດ"
|
||||
flagAsCat: "ໝາຍບັນຊີນີ້ເປັນແມວ"
|
||||
flagAsCatDescription: "ເປີດໃຊ້ຕົວເລືອກນີ້ເພື່ອໝາຍບັນຊີນີ້ເປັນແມວ"
|
||||
flagShowTimelineReplies: "ສະແດງການຕອບກັບໃນທາມລາຍ"
|
||||
flagShowTimelineRepliesDescription: "ສະແດງການຕອບກັບຂອງຜູ້ໃຊ້ຕໍ່ກັບບັນທຶກຂອງຜູ້ໃຊ້ອື່ນໃນທາມລາຍຖ້າເປີດໃຊ້ງານ"
|
||||
autoAcceptFollowed: "ອະນຸມັດອັດຕະໂນມັດຕາມຄຳຮ້ອງຂໍຈາກຜູ້ໃຊ້ທີ່ທ່ານກຳລັງຕິດຕາມຢູ່"
|
||||
addAccount: "ເພີ່ມບັນຊີ"
|
||||
loginFailed: "ການເຂົ້າສູ່ລະບົບບໍ່ສຳເລັດ"
|
||||
general: "ທົ່ວໄປ"
|
||||
wallpaper: "ພາບພື້ນຫລັງ"
|
||||
setWallpaper: "ຕັ້ງເປັນພາບພື້ນຫຼັງ"
|
||||
instances: "ອີນສະແຕນ"
|
||||
instanceInfo: "ອີນສະແຕນ"
|
||||
statistics: "ສະຖິຕິ"
|
||||
clearQueue: "ລ້າງຄິວ"
|
||||
clearCachedFiles: "ລຶບລ້າງແຄສ"
|
||||
editProfile: "ແກ້ໄຂໂປຣໄຟລ໌"
|
||||
done: "ສຳເລັດ"
|
||||
processing: "ກຳລັງປະມວນຜົນ"
|
||||
preview: "ສະແດງເປັນຕົວຢ່າງ"
|
||||
default: "ຄ່າເລີ່ມຕົ້ນ"
|
||||
blocked: "ບລັອກແລ້ວ "
|
||||
all: "ທັງໝົດ"
|
||||
subscribing: "ສະໝັກສະມາຊິກແລັວ"
|
||||
publishing: "ການພິມເຜີຍແຜ່"
|
||||
notResponding: "ບໍ່ຕອບສະໜອງ"
|
||||
instanceFollowing: "ກຳລັງຕິດຕາມສຸດຕົວຢ່າງ"
|
||||
instanceFollowers: "ຜູ້ຕິດຕາມຕົວຢ່າງ"
|
||||
instanceUsers: "ຜູ້ຊົມໃຊ້ຂອງຕົວຢ່າງນີ້"
|
||||
changePassword: "ປ່ຽນລະຫັດຜ່ານ"
|
||||
featured: "ໄຮໄລທ໌"
|
||||
announcements: "ປະກາດ"
|
||||
remove: "ລຶບ"
|
||||
messaging: "ແຊ໋ດ"
|
||||
tos: "ເງື່ອນໄຂການໃຫ້ບໍລິການ"
|
||||
start: "ເລີ່ມຕົ້ນນຳໃຊ້ເລີຍ"
|
||||
home: "ໜ້າຫຼັກ"
|
||||
images: "ຮູບພາບ"
|
||||
birthday: "ວັນເກີດ"
|
||||
registeredDate: "ວັນທີ່ເປັນສະມາຊິກ"
|
||||
location: "ທີ່ຕັ້ງ"
|
||||
theme: "ແທ໋ມ"
|
||||
light: "ສະຫວ່າງ"
|
||||
dark: "ມືດ"
|
||||
lightThemes: "ຊຸດຮູບແບບສະຫວ່າງ"
|
||||
darkThemes: "ຮູບແບບສີສັນມືດ"
|
||||
fileName: "ຊື່ໄຟລ໌"
|
||||
selectFile: "ເລືອກໄຟລ໌"
|
||||
selectFiles: "ເລືອກໄຟລ໌"
|
||||
nsfw: "NSFW"
|
||||
accept: "ອະນຸຍາດ"
|
||||
pinnedNotes: "ບັນທຶກທີ່ປັກໝຸດໄວ້"
|
||||
userList: "ລາຍການ"
|
||||
smtpUser: "ຊື່ຜູ້ໃຊ້"
|
||||
smtpPass: "ລະຫັດຜ່ານ"
|
||||
clearCache: "ລຶບລ້າງແຄສ"
|
||||
user: "ຜູ້ໃຊ້ຕ່າງໆ"
|
||||
searchByGoogle: "ຄົ້ນຫາ"
|
||||
_mfm:
|
||||
search: "ຄົ້ນຫາ"
|
||||
file: "ໄຟລ໌"
|
||||
_email:
|
||||
_follow:
|
||||
title: "ໄດ້ຕິດຕາມທ່ານ"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "ໄດ້ກ່າວມາ"
|
||||
renote: "Renote"
|
||||
_sfx:
|
||||
note: "ບັນທຶກ"
|
||||
notification: "ການແຈ້ງເຕືອນ"
|
||||
chat: "ແຊ໋ດ"
|
||||
_widgets:
|
||||
profile: "ໂພຼຟາຍ"
|
||||
instanceInfo: "ອີນສະແຕນ"
|
||||
notifications: "ການແຈ້ງເຕືອນ"
|
||||
timeline: "ເສັ້ນກຳນົດເວລາ"
|
||||
_userList:
|
||||
chooseList: "ເລືອກບັນຊີລາຍການ"
|
||||
_cw:
|
||||
show: "ໂຫຼດເພີ່ມເຕີມ"
|
||||
_visibility:
|
||||
home: "ໜ້າຫຼັກ"
|
||||
followers: "ຜູ້ຕິດຕາມ"
|
||||
_profile:
|
||||
username: "ຊື່ຜູ້ໃຊ້"
|
||||
_exportOrImport:
|
||||
followingList: "ກຳລັງຕິດຕາມ"
|
||||
muteList: "ປີດສຽງ"
|
||||
blockingList: "ບ໋ອກ"
|
||||
userLists: "ລາຍການ"
|
||||
_timelines:
|
||||
home: "ໜ້າຫຼັກ"
|
||||
_pages:
|
||||
blocks:
|
||||
image: "ຮູບພາບ"
|
||||
_notification:
|
||||
youWereFollowed: "ໄດ້ຕິດຕາມທ່ານ"
|
||||
_types:
|
||||
follow: "ກຳລັງຕິດຕາມ"
|
||||
mention: "ໄດ້ກ່າວມາ"
|
||||
renote: "Renote"
|
||||
quote: "ລວມຂໍ້ຄວາມອ້າງອີງ"
|
||||
reaction: "ປະຕິກິລິຍາ"
|
||||
_actions:
|
||||
reply: "ຕອບໄປທີ"
|
||||
renote: "Renote"
|
||||
_deck:
|
||||
_columns:
|
||||
notifications: "ການແຈ້ງເຕືອນ"
|
||||
tl: "ເສັ້ນກຳນົດເວລາ"
|
||||
list: "ລາຍການ"
|
||||
channel: "ຊ່ອງ"
|
||||
mentions: "ກ່າວເຖິງ"
|
||||
|
||||
@@ -427,11 +427,6 @@ loggedInAsBot: "Momenteel als bot ingelogd"
|
||||
_email:
|
||||
_follow:
|
||||
title: "volgde jou"
|
||||
_mfm:
|
||||
mention: "Vermelding"
|
||||
quote: "Quote"
|
||||
emoji: "Maatwerk emoji"
|
||||
search: "Zoeken"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Vermelding"
|
||||
|
||||
@@ -461,7 +461,6 @@ youHaveNoGroups: "Nie masz żadnych grup"
|
||||
joinOrCreateGroup: "Uzyskaj zaproszenie do dołączenia do grupy lub utwórz własną grupę."
|
||||
noHistory: "Brak historii"
|
||||
signinHistory: "Historia logowania"
|
||||
disableAnimatedMfm: "Wyłącz MFM z animacją"
|
||||
doing: "Przetwarzanie..."
|
||||
category: "Kategoria"
|
||||
tags: "Tagi"
|
||||
@@ -958,68 +957,6 @@ _nsfw:
|
||||
respect: "Ukrywaj media NSFW"
|
||||
ignore: "Nie ukrywaj mediów NSFW"
|
||||
force: "Ukrywaj wszystkie media"
|
||||
_mfm:
|
||||
cheatSheet: "Ściąga MFM"
|
||||
intro: "MFM to język składniowy wyjątkowy dla Misskey, który może być użyty w wielu miejscach. Tu znajdziesz listę wszystkich możliwych elementów składni MFM."
|
||||
dummy: "Misskey rozszerza świat Fediwersum"
|
||||
mention: "Wspomnij"
|
||||
mentionDescription: "Używając znaku @ i nazwy użytkownika, możesz określić danego użytkownika."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Używając kratki i tekstu, możesz określić hashtag."
|
||||
url: "Adres URL"
|
||||
urlDescription: "Adresy URL mogą być wyświetlane"
|
||||
link: "Odnośnik"
|
||||
linkDescription: "Określone części tekstu mogą być wyświetlane jako adres URL."
|
||||
bold: "Pogrubienie"
|
||||
boldDescription: "Wyróżnia litery pogrubiając je."
|
||||
small: "Małe"
|
||||
smallDescription: "Wyświetla treść jako małą i cienką."
|
||||
center: "Wyśrodkowanie"
|
||||
centerDescription: "Wyśrodkowuje zawartość."
|
||||
inlineCode: "Kod (w wierszu)"
|
||||
blockCode: "Kod (blok)"
|
||||
blockCodeDescription: "Wyświetla kod z podświetlaną składnią składający się z wielu linii."
|
||||
blockMath: "Matematyka (Blok)"
|
||||
quote: "Cytuj"
|
||||
quoteDescription: "Wyświetla treść jako cytat."
|
||||
emoji: "Niestandardowe emoji"
|
||||
emojiDescription: "Otaczając nazwę niestandardowego emoji dwukropkami, możesz użyć niestandardowego emoji."
|
||||
search: "Szukaj"
|
||||
searchDescription: "Wyświetla pole wyszukiwania z wcześniej wpisanym tekstem."
|
||||
flip: "Odwróć"
|
||||
flipDescription: "Przerzuca treść poziomo lub pionowo."
|
||||
jelly: "Animacja (Galaretka)"
|
||||
jellyDescription: "Nadaje treści galaretowatą animację."
|
||||
tada: "Animation (Tada)"
|
||||
tadaDescription: "Nadaje treści animację podobną do \"Tada!\"."
|
||||
jump: "Animacja (Skok)"
|
||||
jumpDescription: "Nadaje treści animację skakania."
|
||||
bounce: "Animacja (Odbijanie)"
|
||||
bounceDescription: "Nadaje treści animację odbijania się."
|
||||
shake: "Animacja (Wstrząsanie)"
|
||||
shakeDescription: "Nadaje treści animację wstrząsania."
|
||||
twitch: "Animacja (Drganie)"
|
||||
twitchDescription: "Nadaje treści mocno drgającą animację."
|
||||
spin: "Animacja (Obrót)"
|
||||
spinDescription: "Nadaje treści animację obracania."
|
||||
x2: "Duże"
|
||||
x2Description: "Czyni treść większą."
|
||||
x3: "Bardzo duże"
|
||||
x3Description: "Czyni treść jeszcze większą."
|
||||
x4: "Ogromne"
|
||||
x4Description: "Czyni treść jeszcze większą niż jeszcze większa."
|
||||
blur: "Rozmycie"
|
||||
blurDescription: "Rozmywa treść. Zostanie wyraźnie wyświetlona po najechaniu."
|
||||
font: "Czcionka"
|
||||
fontDescription: "Wybiera czcionkę do wyświetlania treści."
|
||||
rainbow: "Tęcza"
|
||||
rainbowDescription: "Sprawia, że zawartość pojawia się w kolorach tęczy."
|
||||
sparkle: "Blask"
|
||||
sparkleDescription: "Nadaje zawartości efekt lśniącego brokatu."
|
||||
rotate: "Obróć"
|
||||
rotateDescription: "Obraca zawartość o określony kąt."
|
||||
plain: "Zwyczajny"
|
||||
plainDescription: "Wyłącza efekty wszystkich MFM zawartych w tym efekcie MFM."
|
||||
_instanceTicker:
|
||||
none: "Nigdy nie pokazuj"
|
||||
remote: "Pokaż dla zdalnych użytkowników"
|
||||
|
||||
@@ -475,11 +475,6 @@ file: "Ficheiros"
|
||||
_email:
|
||||
_follow:
|
||||
title: "Você tem um novo seguidor"
|
||||
_mfm:
|
||||
mention: "Menção"
|
||||
quote: "Citar"
|
||||
emoji: "Emoji personalizado"
|
||||
search: "Buscar"
|
||||
_theme:
|
||||
keys:
|
||||
mention: "Menção"
|
||||
|
||||
@@ -455,7 +455,6 @@ youHaveNoGroups: "Nu ai niciun grup"
|
||||
joinOrCreateGroup: "Primește o invitație într-un grup sau creează unul nou."
|
||||
noHistory: "Nu există istoric"
|
||||
signinHistory: "Istoric autentificări"
|
||||
disableAnimatedMfm: "Dezactivează MFM cu animații"
|
||||
doing: "Se procesează..."
|
||||
category: "Categorie"
|
||||
tags: "Etichete"
|
||||
@@ -655,11 +654,6 @@ _role:
|
||||
_email:
|
||||
_follow:
|
||||
title: "te-a urmărit"
|
||||
_mfm:
|
||||
mention: "Mențiune"
|
||||
quote: "Citează"
|
||||
emoji: "Emoji personalizat"
|
||||
search: "Caută"
|
||||
_theme:
|
||||
description: "Descriere"
|
||||
keys:
|
||||
|
||||
@@ -462,7 +462,6 @@ youHaveNoGroups: "У вас нет ни одной группы"
|
||||
joinOrCreateGroup: "Получайте приглашения в группы или создавайте свои собственные"
|
||||
noHistory: "История пока пуста"
|
||||
signinHistory: "Журнал посещений"
|
||||
disableAnimatedMfm: "Отключение анимированной разметки MFM"
|
||||
doing: "В процессе"
|
||||
category: "Категория"
|
||||
tags: "Метки"
|
||||
@@ -1309,72 +1308,6 @@ _nsfw:
|
||||
respect: "Скрывать содержимое не для всех"
|
||||
ignore: "Показывать содержимое не для всех"
|
||||
force: "Скрывать вообще все файлы"
|
||||
_mfm:
|
||||
cheatSheet: "Подсказка по разметке MFM"
|
||||
intro: "MFM — язык оформления текста, который придуман специально для Misskey и готов для применения во многих местах. На этой странице собраны и кратко изложены способы его использовать."
|
||||
dummy: "Misskey расширяет границы Федиверса."
|
||||
mention: "Упоминание"
|
||||
mentionDescription: "При помощи знака «собака» перед именем можно упомянуть какого-нибудь пользователя."
|
||||
hashtag: "Хэштег"
|
||||
hashtagDescription: "При помощи знака «решётка» перед словом задаётся хэштег."
|
||||
url: "Простая ссылка (URL)"
|
||||
urlDescription: "Ссылки могут отображаться непосредственно."
|
||||
link: "Ссылка с пояснением"
|
||||
linkDescription: "Можно ссылку оформить в виде произвольного текста."
|
||||
bold: "Жирный шрифт"
|
||||
boldDescription: "Выделяет текст, делая буквы жирнее."
|
||||
small: "Мелкий шрифт"
|
||||
smallDescription: "Делает текст маленьким и незаметным."
|
||||
center: "Выровнять элементы по центру"
|
||||
centerDescription: "Так можно выровнять что-то по центру."
|
||||
inlineCode: "Программа (в тексте)"
|
||||
inlineCodeDescription: "Подсвечивает фрагмент программы внутри сплошного текста."
|
||||
blockCode: "Программа (блок)"
|
||||
blockCodeDescription: "Оформляет текст программы в виде отдельного блокоа. Он может состоять из множества строк."
|
||||
inlineMath: "Математическое выражение (в тексте)"
|
||||
inlineMathDescription: "Позволяет вставлять математические выражения внутрь текста при помощи языка KaTeX."
|
||||
blockMath: "Математическое выражение (блок)"
|
||||
blockMathDescription: "Оформляет математическое выражение (KaTeX) на отдельной строке."
|
||||
quote: "Цитата"
|
||||
quoteDescription: "Так можно процитировать чей-то текст."
|
||||
emoji: "Собственные эмодзи"
|
||||
emojiDescription: "Можно вставить эмодзи в текст, окружив название двоеточиями."
|
||||
search: "Поиск"
|
||||
searchDescription: "Можно добавить форму для поиска, сразу задав, что искать."
|
||||
flip: "Переворот"
|
||||
flipDescription: "Позволяет отразить текст зеркально по вертикали или горизонтали."
|
||||
jelly: "Анимация желе (шлёп-плёп)"
|
||||
jellyDescription: "Напоминает горку джема, дёргающуюся от шлепков."
|
||||
tada: "Анимация (та-дам!)"
|
||||
tadaDescription: "Получается нечто выпрыгивающее, как бы крича: «а вот и я!»"
|
||||
jump: "Анимация прыжков (прыг-скок)"
|
||||
jumpDescription: "Побуждает радостно подпрыгивать."
|
||||
bounce: "Анимация отскоков (бум-бум)"
|
||||
bounceDescription: "Это будет скакать как мяч."
|
||||
shake: "Анимация дрожи (б-р-р-р)"
|
||||
shakeDescription: "Такое дрожит, словно от холода. Или от страха."
|
||||
twitch: "Анимация тряски"
|
||||
twitchDescription: "Заставляет трястись как одержимого"
|
||||
spin: "Вращение"
|
||||
spinDescription: "Так можно крутить содержимое в разных направлениях."
|
||||
x2: "Крупный шрифт"
|
||||
x2Description: "Увеличивает содержимое."
|
||||
x3: "Ещё крупнее"
|
||||
x3Description: "Сильнее увеличивает содержимое."
|
||||
x4: "Совсем крупно"
|
||||
x4Description: "Увеличивает содержимое совсем сильно."
|
||||
blur: "Размытие"
|
||||
blurDescription: "Размывает текст до нечитаемости, будто его поместили за матовое стекло. Наведение указателя мыши на размытый текст возвращает чёткость."
|
||||
font: "Шрифт"
|
||||
fontDescription: "Так можно писать произвольным шрифтом."
|
||||
rainbow: "Радуга"
|
||||
rainbowDescription: "Заставлять содержимое отображаться в цветах радуги."
|
||||
sparkle: "Искры"
|
||||
sparkleDescription: "Добавляет эффект искрящихся частиц."
|
||||
rotate: "Повернуть"
|
||||
rotateDescription: "Поворачивает на заданный угол."
|
||||
plain: "Буквально"
|
||||
plainDescription: "MFM внутри отключается, и текст отображается как есть"
|
||||
_instanceTicker:
|
||||
none: "Не показывать"
|
||||
remote: "Только для других сайтов"
|
||||
|
||||
@@ -464,7 +464,6 @@ youHaveNoGroups: "Nemáte žiadne skupiny"
|
||||
joinOrCreateGroup: "Požiadajte o pozvanie do existujúcej skupiny alebo vytvorte novú."
|
||||
noHistory: "Žiadna história"
|
||||
signinHistory: "História prihlásení"
|
||||
disableAnimatedMfm: "Vypnúť MFM s animáciou"
|
||||
doing: "Pracujem..."
|
||||
category: "Kategórie"
|
||||
tags: "Značky"
|
||||
@@ -1013,72 +1012,6 @@ _nsfw:
|
||||
respect: "Skryť NSFW médiá"
|
||||
ignore: "Neskrývať NSFW médiá"
|
||||
force: "Skryť všetky médiá"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Cheatsheet"
|
||||
intro: "MFM je Misskey exkluzívny značkovací jazyk, ktorý sa dá používať na viacerých miestach. Tu môžete vidieť zoznam všetkej dostupnej MFM syntaxe."
|
||||
dummy: "Misskey rozširuje svet Fediverza"
|
||||
mention: "Zmienka"
|
||||
mentionDescription: "Používateľa spomeniete použítím zavináča a mena používateľa"
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Môžete zadať hashtag použitím mriežky a textu"
|
||||
url: "URL"
|
||||
urlDescription: "URL sa dajú zobraziť."
|
||||
link: "Odkaz"
|
||||
linkDescription: "Jednotlivé časti texty sa dajú zobraziť ako URL."
|
||||
bold: "Tučné"
|
||||
boldDescription: "Zvýrazní písmená tým, že budú tučnejšie."
|
||||
small: "Malé"
|
||||
smallDescription: "Zobrazí obsah malý a tenký."
|
||||
center: "Vystrediť prvky"
|
||||
centerDescription: "Zobrazí obsah v strede"
|
||||
inlineCode: "Kód (inline)"
|
||||
inlineCodeDescription: "Zobrazí kód so zvýraznením syntaxe."
|
||||
blockCode: "Kód (blok)"
|
||||
blockCodeDescription: "Zobrazí viacriadkový kód so zvýraznením syntaxe v bloku."
|
||||
inlineMath: "Vzorec (inline)"
|
||||
inlineMathDescription: "Zobrazí matematický vzorec (KaTeX) v riadku."
|
||||
blockMath: "Vzorec (blok)"
|
||||
blockMathDescription: "Zobrazí viacriadkový matematický vzorec (KaTeX) v bloku"
|
||||
quote: "Citovať"
|
||||
quoteDescription: "Zobrazí obsah ako citát."
|
||||
emoji: "Vlastné emoji"
|
||||
emojiDescription: "Pridaním dvojbodiek pred a za názov vlastnej emoji, sa dá zobraziť vlastná emoji."
|
||||
search: "Hľadať"
|
||||
searchDescription: "Zobrazí vyhľadávacie pole so zadaným textom."
|
||||
flip: "Preklopiť"
|
||||
flipDescription: "Preklopí obsah horizontálne alebo vertikálne"
|
||||
jelly: "Animácia (želé)"
|
||||
jellyDescription: "Obsah sa bude hýbať ako želé."
|
||||
tada: "Animácia (tadá)"
|
||||
tadaDescription: "Obsah sa bude hýbať ako Tada!"
|
||||
jump: "Animácia (skok)"
|
||||
jumpDescription: "Obsah skočí."
|
||||
bounce: "Animácia (odraz)"
|
||||
bounceDescription: "Obsah sa bude odrážať."
|
||||
shake: "Animácia (trasenie)"
|
||||
shakeDescription: "Obsah sa bude triasť."
|
||||
twitch: "Animácia (myknutie)"
|
||||
twitchDescription: "Obsahu dá animáciu silného trasenia."
|
||||
spin: "Animácia (rotácia)"
|
||||
spinDescription: "Obsahu pridá otáčajúcu animáciu."
|
||||
x2: "Veľký"
|
||||
x2Description: "Zobrazí obsah väčší."
|
||||
x3: "Veľmi veľký"
|
||||
x3Description: "Zobrazí obsah ešte väčší."
|
||||
x4: "Neuveriteľne veľký"
|
||||
x4Description: "Zobrazí obsah ešte viac veľký než veľmi veľký."
|
||||
blur: "Rozmazanie"
|
||||
blurDescription: "Týmto efektom môže byť obsah rozmazaný. Zaostrí sa keď ned neho príde kurzor."
|
||||
font: "Písmo"
|
||||
fontDescription: "Nastaví písmo, ktorým sa zobrazí text."
|
||||
rainbow: "Dúha"
|
||||
rainbowDescription: "Zobrazí obsah vo farbách dúhy."
|
||||
sparkle: "Trblietky"
|
||||
sparkleDescription: "Obsahu dodá trblietajúci efekt."
|
||||
rotate: "Otáčať"
|
||||
rotateDescription: "Otočí obsah o určitý uhol."
|
||||
plain: "Obyčajné"
|
||||
plainDescription: "Bez akejkoľvej syntaxe"
|
||||
_instanceTicker:
|
||||
none: "Nikdy nezobrazovať"
|
||||
remote: "Zobraziť pre vzdialených používateľov"
|
||||
|
||||
@@ -371,11 +371,6 @@ pushNotificationNotSupported: "Din webbläsare eller instans har inte stöd för
|
||||
_email:
|
||||
_follow:
|
||||
title: "följde dig"
|
||||
_mfm:
|
||||
mention: "Nämn"
|
||||
quote: "Citat"
|
||||
emoji: "Anpassa emoji"
|
||||
search: "Sök"
|
||||
_channel:
|
||||
setBanner: "Välj banner"
|
||||
removeBanner: "Ta bort banner"
|
||||
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "คุณแน่ใจแล้วเหรอ? ว่าต
|
||||
suspendConfirm: "นายแน่ใจแล้วเหรอว่าต้องการระงับบัญชีนี้อ่ะ?"
|
||||
unsuspendConfirm: "นายแน่ใจแล้วหรอ? ว่าต้องการยกเลิกการระงับบัญชีนี้"
|
||||
selectList: "เลือกรายการ"
|
||||
selectChannel: "เลือกแชนแนล"
|
||||
selectAntenna: "เลือกเสาอากาศ"
|
||||
selectWidget: "เลือกวิดเจ็ต"
|
||||
editWidgets: "แก้ไขวิดเจ็ต"
|
||||
@@ -464,7 +465,6 @@ youHaveNoGroups: "คุณยังไม่มีกลุ่ม"
|
||||
joinOrCreateGroup: "รับเชิญเข้าร่วมกลุ่มหรือสร้างกลุ่มของคุณเองเลยนะ"
|
||||
noHistory: "ไม่มีรายการ"
|
||||
signinHistory: "ประวัติการเข้าสู่ระบบ"
|
||||
disableAnimatedMfm: "ปิดการใช้งาน MFM ด้วยแอนิเมชั่น"
|
||||
doing: "กำลังประมวลผล......"
|
||||
category: "หมวดหมู่"
|
||||
tags: "แท็ก"
|
||||
@@ -939,6 +939,8 @@ cannotPerformTemporaryDescription: "การดําเนินการน
|
||||
preset: "พรีเซ็ต"
|
||||
selectFromPresets: "เลือกจากการพรีเซ็ต"
|
||||
achievements: "ความสำเร็จ"
|
||||
gotInvalidResponseError: "การตอบสนองเซิร์ฟเวอร์ไม่ถูกต้อง"
|
||||
gotInvalidResponseErrorDescription: "เซิร์ฟเวอร์อาจไม่สามารถเข้าถึงได้หรืออาจจะกำลังอยู่ในระหว่างปรับปรุง กรุณาลองใหม่อีกครั้งในภายหลังนะคะ"
|
||||
_achievements:
|
||||
earnedAt: "ได้รับเมื่อ"
|
||||
_types:
|
||||
@@ -1323,72 +1325,6 @@ _nsfw:
|
||||
respect: "ซ่อนสื่อ NSFW"
|
||||
ignore: "อย่าซ่อนสื่อ NSFW"
|
||||
force: "ซ่อนสื่อทั้งหมด"
|
||||
_mfm:
|
||||
cheatSheet: "โค้ด MFM Cheat Sheet"
|
||||
intro: "MFM เป็นภาษามาร์กอัปพิเศษเฉพาะของ Misskey ที่สามารถใช้ได้ในหลายที่ คุณยังสามารถดูรายการไวยากรณ์ MFM ที่มีอยู่ทั้งหมดได้ที่นี่นะ"
|
||||
dummy: "Misskey ขยายโลกของ Fediverse"
|
||||
mention: "กล่าวถึง"
|
||||
mentionDescription: "คุณสามารถระบุผู้ใช้โดยใช้ At-Symbol และชื่อผู้ใช้ได้นะ"
|
||||
hashtag: "แฮชแท็ก"
|
||||
hashtagDescription: "คุณสามารถระบุชื่อแฮชแท็กได้โดยใช้เครื่องหมายตัวเลขและข้อความได้นะ"
|
||||
url: "URL"
|
||||
urlDescription: "สามารถแสดง URL ได้นะ"
|
||||
link: "ลิงก์"
|
||||
linkDescription: "เจาะจงเฉพาะ ส่วนของข้อความที่สามารถแสดงเป็น URL ได้"
|
||||
bold: "ตัวหนา"
|
||||
boldDescription: "ไฮไลท์ตัวอักษรโดยทำให้หนาขึ้น"
|
||||
small: "ขนาดเล็ก"
|
||||
smallDescription: "แสดงผลเนื้อหาขนาดเล็กและบาง"
|
||||
center: "เซ็นเตอร์"
|
||||
centerDescription: "แสดงผลเนื้อหาเป็นศูนย์กลาง"
|
||||
inlineCode: "โค้ด (อินไลน์)"
|
||||
inlineCodeDescription: "แสดงผลการเน้นไวยากรณ์แบบอินไลน์สำหรับโค้ด (โปรแกรม)"
|
||||
blockCode: "โค้ด (บล็อก)"
|
||||
blockCodeDescription: "แสดงผลการเน้นไวยากรณ์สำหรับโค้ดหลายบรรทัด (โปรแกรม) ในบล็อก"
|
||||
inlineMath: "คณิต (อินไลน์)"
|
||||
inlineMathDescription: "แสดงผลสูตรคณิต (KaTeX) ในบรรทัด"
|
||||
blockMath: "คณิต (บล็อก)"
|
||||
blockMathDescription: "แสดงผลสูตรคณิตหลายบรรทัด (KaTeX) ในบล็อก"
|
||||
quote: "อ้างคำพูด"
|
||||
quoteDescription: "แสดงผลเนื้อหาเป็นใบเสนอราคา"
|
||||
emoji: "กำหนดอีโมจิเอง"
|
||||
emojiDescription: "โดยล้อมรอบชื่ออีโมจิที่กำหนดเองด้วยเครื่องหมายทวิภาค จะสามารถแสดงผลอีโมจิที่กำหนดเองได้"
|
||||
search: "ค้นหา"
|
||||
searchDescription: "แสดงผลกล่องค้นหาพร้อมกับข้อความที่ป้อนไว้ล่วงหน้า"
|
||||
flip: "พลิก"
|
||||
flipDescription: "พลิกเนื้อหาในแนวนอนหรือแนวตั้ง"
|
||||
jelly: "แอนิเมชั่น (เยลลี่)"
|
||||
jellyDescription: "ให้เนื้อหาเป็นแอนิเมชั่นเหมือนเยลลี่"
|
||||
tada: "แอนิเมชั่น (ธาดา)"
|
||||
tadaDescription: "ให้เนื้อหาเป็นแอนิเมชั่นเหมือน \"ทาด้า!\""
|
||||
jump: "อนิเมชั่น (กระโดด)"
|
||||
jumpDescription: "ให้เนื้อหามีภาพเคลื่อนไหวแบบกระโดด"
|
||||
bounce: "อนิเมชั่น (เด้ง)"
|
||||
bounceDescription: "ให้เนื้อหามีอนิเมชั่นเด้ง"
|
||||
shake: "อนิเมชั่น (เขย่า)"
|
||||
shakeDescription: "ให้เนื้อหามีภาพเคลื่อนไหวสั่น"
|
||||
twitch: "แอนิเมชั่น (Twitch)"
|
||||
twitchDescription: "ให้เนื้อหามีแอนิเมชั่นกระตุกอย่างแรง"
|
||||
spin: "แอนิเมชั่น (สปิน)"
|
||||
spinDescription: "ให้เนื้อหาเป็นภาพเคลื่อนไหวแบบหมุน"
|
||||
x2: "ขนาดใหญ่"
|
||||
x2Description: "แสดงเนื้อหาที่ใหญ่ขึ้น"
|
||||
x3: "ใหญ่มาก"
|
||||
x3Description: "แสดงเนื้อหาอีเว้นท์ที่ใหญ่ขึ้น"
|
||||
x4: "ใหญ่อย่างไม่น่าเชื่อ"
|
||||
x4Description: "แสดงผลเนื้อหาที่ใหญ่กว่าใหญ่กว่าขนาดใหญ่"
|
||||
blur: "เบลอ"
|
||||
blurDescription: "เบลอเนื้อหา จะแสดงผลอย่างชัดเจนต่อเมื่อวางเมาส์เหนือ"
|
||||
font: "ตัวอักษร"
|
||||
fontDescription: "ตั้งค่าตัวอักษรเพื่อแสดงเนื้อหาใน"
|
||||
rainbow: "สายรุ้ง"
|
||||
rainbowDescription: "ทำให้เนื้อหานั้นปรากฏเป็นสีรุ้ง"
|
||||
sparkle: "กลิตเตอร์"
|
||||
sparkleDescription: "ให้เนื้อหานั้นมีเอฟเฟกต์แบบอนุภาคประกาย"
|
||||
rotate: "หมุนหน้าจอ"
|
||||
rotateDescription: "เปลี่ยนเนื้อหาตามด้วยมุมที่ระบุไว้"
|
||||
plain: "เรียบง่าย"
|
||||
plainDescription: "ปิดการใช้งานเอฟเฟกต์ของ MFM ทั้งหมดที่มีอยู่ในเอฟเฟกต์ MFM นี้"
|
||||
_instanceTicker:
|
||||
none: "ไม่ต้องแสดง"
|
||||
remote: "แสดงสำหรับผู้ใช้ระยะไกล"
|
||||
@@ -1593,12 +1529,15 @@ _permissions:
|
||||
"read:gallery-likes": "ดูรายการโพสต์ในแกลเลอรีที่ชอบของคุณ"
|
||||
"write:gallery-likes": "แก้ไขรายการโพสต์ในแกลเลอรีที่ชอบของคุณ"
|
||||
_auth:
|
||||
shareAccessTitle: "การให้สิทธิ์แอปพลิเคชัน"
|
||||
shareAccess: "คุณต้องการอนุญาตให้ \"{name}\" เข้าถึงบัญชีนี้เลยมั้ย?"
|
||||
shareAccessAsk: "คุณแน่ใจแล้วจริงๆหรอว่าต้องการอนุญาตให้แอปพลิเคชันนี้เข้าถึงบัญชีของคุณแน่ใจแล้วหรอ?"
|
||||
permission: "{name} ได้ขอสิทธิ์การเข้าถึงดังต่อไปนี้"
|
||||
permissionAsk: "แอปพลิเคชันนี้ขอสิทธิ์ดังต่อไปนี้"
|
||||
pleaseGoBack: "กรุณากลับไปที่แอปพลิเคชัน"
|
||||
callback: "กำลังกลับไปที่แอปพลิเคชัน"
|
||||
denied: "ปฏิเสธการเข้าใช้"
|
||||
pleaseLogin: "กรุณาเข้าสู่ระบบเพื่ออนุมัติแอปพลิเคชัน"
|
||||
_antennaSources:
|
||||
all: "โน้ตทั้งหมด"
|
||||
homeTimeline: "โน้ตจากผู้ใช้ที่ติดตาม"
|
||||
|
||||
@@ -48,8 +48,6 @@ smtpUser: "Kullanıcı Adı"
|
||||
smtpPass: "Şifre"
|
||||
user: "Kullanıcı"
|
||||
searchByGoogle: "Arama"
|
||||
_mfm:
|
||||
search: "Arama"
|
||||
_sfx:
|
||||
notification: "Bildirim"
|
||||
_widgets:
|
||||
|
||||
@@ -2,5 +2,3 @@
|
||||
_lang_: "ياپونچە"
|
||||
search: "ئىزدەش"
|
||||
searchByGoogle: "ئىزدەش"
|
||||
_mfm:
|
||||
search: "ئىزدەش"
|
||||
|
||||
@@ -166,7 +166,7 @@ recipient: "Отримувач"
|
||||
annotation: "Коментарі"
|
||||
federation: "Федіверс"
|
||||
instances: "Інстанс"
|
||||
registeredAt: "Приєднався(лась)"
|
||||
registeredAt: "Реєстрація"
|
||||
latestRequestReceivedAt: "Останній запит прийнято"
|
||||
latestStatus: "Останній статус"
|
||||
storageUsage: "Використання простору"
|
||||
@@ -263,7 +263,7 @@ activity: "Активність"
|
||||
images: "Зображення"
|
||||
birthday: "День народження"
|
||||
yearsOld: "{age} років"
|
||||
registeredDate: "Приєднався(лась)"
|
||||
registeredDate: "Приєднання"
|
||||
location: "Локація"
|
||||
theme: "Тема"
|
||||
themeForLightMode: "Світла тема"
|
||||
@@ -461,7 +461,6 @@ youHaveNoGroups: "Немає груп"
|
||||
joinOrCreateGroup: "Отримуйте запрошення до груп або створюйте свої власні групи."
|
||||
noHistory: "Історія порожня"
|
||||
signinHistory: "Історія входів"
|
||||
disableAnimatedMfm: "Відключити анімації MFM"
|
||||
doing: "Виконується"
|
||||
category: "Категорія"
|
||||
tags: "Теги"
|
||||
@@ -1087,6 +1086,9 @@ _achievements:
|
||||
_outputHelloWorldOnScratchpad:
|
||||
title: "Hello, world!"
|
||||
description: "Вивести \"hello world\" у Скретчпаді"
|
||||
_reactWithoutRead:
|
||||
title: "Прочитали як слід?"
|
||||
description: "Реакція на нотатку, що містить понад 100 символів, протягом 3 секунд після її публікації"
|
||||
_clickedClickHere:
|
||||
title: "Натисніть тут"
|
||||
description: "Натиснуто тут"
|
||||
@@ -1191,65 +1193,6 @@ _nsfw:
|
||||
respect: "Приховувати NSFW медіа"
|
||||
ignore: "Не приховувати NSFW медіа"
|
||||
force: "Приховувати всі медіа файли"
|
||||
_mfm:
|
||||
cheatSheet: " Довідка MFM"
|
||||
intro: "MFM це ексклюзивна мова розмітки тексту в Misskey, яку можна використовувати в багатьох місцях. Тут ви можете переглянути приклади її синтаксису."
|
||||
dummy: "Misskey розширює світ Федіверсу"
|
||||
mention: "Згадка"
|
||||
mentionDescription: "За допомогою знака \"@\" перед ім'ям можна згадати конкретного користувача."
|
||||
hashtag: "Хештеґ"
|
||||
hashtagDescription: "За допомогою знака \"решітка\" перед словом задається хештег."
|
||||
url: "URL"
|
||||
urlDescription: "Відображаються URL-адреси."
|
||||
link: "Посилання"
|
||||
linkDescription: "Окремі частини тексту можуть містити посилання"
|
||||
bold: "Жирний шрифт"
|
||||
boldDescription: "Виділяє літери, роблячи їх товще"
|
||||
small: "Дрібний шрифт"
|
||||
smallDescription: "Робить текст маленьким і тонким"
|
||||
center: "По центру"
|
||||
centerDescription: "Показує вміст у центрі"
|
||||
inlineCode: "Код (у рядку)"
|
||||
inlineCodeDescription: "Показує фрагмент тексту у рядку як програмний код"
|
||||
blockCode: "Код (блок)"
|
||||
blockCodeDescription: "Показує кілька рядків тексту як блок програмного кода"
|
||||
inlineMath: "Формула (у рядку)"
|
||||
inlineMathDescription: "Відображення математичних формул (KaTeX) у рядку"
|
||||
blockMath: "Формули (блок)"
|
||||
blockMathDescription: "Відображати багаторядкові формули (KaTeX) блоками"
|
||||
quote: "Цитата"
|
||||
quoteDescription: "Відображає зміст як цитату."
|
||||
emoji: "Кастомні емоджі"
|
||||
emojiDescription: "Щоб показати нетиповий емоджі, потрібно ввести його назву в двокрапках."
|
||||
search: "Пошук"
|
||||
searchDescription: "Відображає вікно пошуку з попередньо введеним текстом"
|
||||
flip: "Перевернути"
|
||||
flipDescription: "Віддзеркалює вміст по горизонталі або вертикалі"
|
||||
jelly: "Анімація (желе)"
|
||||
jellyDescription: "Створює желеподібну анімацію"
|
||||
tada: "Анімація (Тада!)"
|
||||
tadaDescription: "Створює анімацію з відчуттям \"Тада!\""
|
||||
jump: "Анімація (стрибки)"
|
||||
jumpDescription: "Показує стрибаючу анімацію"
|
||||
bounce: "Анімація (пружина)"
|
||||
bounceDescription: "Надає вмісту стрибаючу анімацію."
|
||||
shake: "Анімація (Shake)"
|
||||
shakeDescription: "Надає вмісту тремтливу анімацію."
|
||||
twitch: "Анімація (Twitch)"
|
||||
spin: "Анімація (Spin)"
|
||||
x2: "Великий"
|
||||
x2Description: "Показує контент збільшеним."
|
||||
x3: "Дуже великий"
|
||||
x3Description: "Показує контент ще більшим."
|
||||
x4: "Надзвичайно великий"
|
||||
x4Description: "Показує контент надзвичайно великим."
|
||||
blur: "Розмиття"
|
||||
blurDescription: "Цей ефект зробить контент розмитим. Контент можна зробити чітким, якщо навести на нього вказівник миші."
|
||||
font: "Шрифт"
|
||||
fontDescription: "Встановлює шрифт для контенту."
|
||||
rotate: "Обертати"
|
||||
plain: "Звичайний"
|
||||
plainDescription: "Деактивує всі ефекти MFM, що містяться в цьому ефекті MFM."
|
||||
_instanceTicker:
|
||||
none: "Не відображати"
|
||||
remote: "Відображати для віддалених користувачів"
|
||||
|
||||
@@ -457,7 +457,6 @@ youHaveNoGroups: "Không có nhóm nào"
|
||||
joinOrCreateGroup: "Tham gia hoặc tạo một nhóm mới."
|
||||
noHistory: "Không có dữ liệu"
|
||||
signinHistory: "Lịch sử đăng nhập"
|
||||
disableAnimatedMfm: "Tắt MFM với chuyển động"
|
||||
doing: "Đang xử lý..."
|
||||
category: "Phân loại"
|
||||
tags: "Thẻ"
|
||||
@@ -992,72 +991,6 @@ _nsfw:
|
||||
respect: "Ẩn nội dung NSFW"
|
||||
ignore: "Hiện nội dung NSFW"
|
||||
force: "Ẩn mọi media"
|
||||
_mfm:
|
||||
cheatSheet: "MFM Cheatsheet"
|
||||
intro: "MFM là ngôn ngữ phát triển độc quyền của Misskey có thể được sử dụng ở nhiều nơi. Tại đây bạn có thể xem danh sách tất cả các cú pháp MFM có sẵn."
|
||||
dummy: "Misskey mở rộng thế giới Fediverse"
|
||||
mention: "Nhắc đến"
|
||||
mentionDescription: "Bạn có thể nhắc đến ai đó bằng cách sử dụng @tên người dùng."
|
||||
hashtag: "Hashtag"
|
||||
hashtagDescription: "Bạn có thể tạo một hashtag bằng #chữ hoặc #số."
|
||||
url: "URL"
|
||||
urlDescription: "Những URL có thể hiển thị."
|
||||
link: "Đường dẫn"
|
||||
linkDescription: "Các phần cụ thể của văn bản có thể được hiển thị dưới dạng URL."
|
||||
bold: "In đậm"
|
||||
boldDescription: "Nổi bật các chữ cái bằng cách làm chúng dày hơn."
|
||||
small: "Nhỏ"
|
||||
smallDescription: "Hiển thị nội dung nhỏ và mỏng."
|
||||
center: "Giữa"
|
||||
centerDescription: "Hiển thị nội dung căn giữa."
|
||||
inlineCode: "Mã (Trong dòng)"
|
||||
inlineCodeDescription: "Hiển thị tô sáng cú pháp trong dòng cho mã (chương trình)."
|
||||
blockCode: "Mã (Khối)"
|
||||
blockCodeDescription: "Hiển thị tô sáng cú pháp cho mã nhiều dòng (chương trình) trong một khối."
|
||||
inlineMath: "Toán học (Trong dòng)"
|
||||
inlineMathDescription: "Hiển thị công thức toán (KaTeX) trong dòng"
|
||||
blockMath: "Toán học (Khối)"
|
||||
blockMathDescription: "Hiển thị công thức toán học nhiều dòng (KaTeX) trong một khối"
|
||||
quote: "Trích dẫn"
|
||||
quoteDescription: "Hiển thị nội dung dạng lời trích dạng."
|
||||
emoji: "Tùy chỉnh emoji"
|
||||
emojiDescription: "Hiển thị emoji với cú pháp :tên emoji:"
|
||||
search: "Tìm kiếm"
|
||||
searchDescription: "Hiển thị hộp tìm kiếm với văn bản được nhập trước."
|
||||
flip: "Lật"
|
||||
flipDescription: "Lật nội dung theo chiều ngang hoặc chiều dọc."
|
||||
jelly: "Chuyển động (Thạch rau câu)"
|
||||
jellyDescription: "Cho phép nội dung chuyển động giống như thạch rau câu."
|
||||
tada: "Chuyển động (Tada)"
|
||||
tadaDescription: "Cho phép nội dung chuyển động kiểu \"Tada!\"."
|
||||
jump: "Chuyển động (Nhảy múa)"
|
||||
jumpDescription: "Cho phép nội dung chuyển động nhảy nhót."
|
||||
bounce: "Chuyển động (Cà tưng)"
|
||||
bounceDescription: "Cho phép nội dung chuyển động cà tưng."
|
||||
shake: "Chuyển động (Rung)"
|
||||
shakeDescription: "Cho phép nội dung chuyển động rung lắc."
|
||||
twitch: "Chuyển động (Co rút)"
|
||||
twitchDescription: "Cho phép nội dung chuyển động co rút."
|
||||
spin: "Chuyển động (Xoay tít)"
|
||||
spinDescription: "Cho phép nội dung chuyển động xoay tít."
|
||||
x2: "Lớn"
|
||||
x2Description: "Hiển thị nội dung cỡ lớn hơn."
|
||||
x3: "Rất lớn"
|
||||
x3Description: "Hiển thị nội dung cỡ lớn hơn nữa."
|
||||
x4: "Khổng lồ"
|
||||
x4Description: "Hiển thị nội dung cỡ khổng lồ."
|
||||
blur: "Làm mờ"
|
||||
blurDescription: "Làm mờ nội dung. Nó sẽ được hiển thị rõ ràng khi di chuột qua."
|
||||
font: "Phông chữ"
|
||||
fontDescription: "Chọn phông chữ để hiển thị nội dung."
|
||||
rainbow: "Cầu vồng"
|
||||
rainbowDescription: "Làm cho nội dung hiển thị với màu sắc cầu vồng."
|
||||
sparkle: "Lấp lánh"
|
||||
sparkleDescription: "Làm cho nội dung hiệu ứng hạt lấp lánh."
|
||||
rotate: "Xoay"
|
||||
rotateDescription: "Xoay nội dung theo một góc cụ thể."
|
||||
plain: "Đơn giản"
|
||||
plainDescription: "Vô hiệu hóa mọi hiệu ứng MFM chứa trong hiệu ứng MFM này."
|
||||
_instanceTicker:
|
||||
none: "Không hiển thị"
|
||||
remote: "Hiện cho người dùng từ máy chủ khác"
|
||||
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "确定要解除拉黑吗?"
|
||||
suspendConfirm: "要冻结吗?"
|
||||
unsuspendConfirm: "要解除冻结吗?"
|
||||
selectList: "选择列表"
|
||||
selectChannel: "选择频道"
|
||||
selectAntenna: "选择天线"
|
||||
selectWidget: "选择小工具"
|
||||
editWidgets: "编辑部件"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "没有更多的历史记录"
|
||||
startMessaging: "添加聊天"
|
||||
nUsersRead: "{n}人已读"
|
||||
agreeTo: "勾选则表示已阅读并同意{0}"
|
||||
agreeBelow: "同意以下观点"
|
||||
basicNotesBeforeCreateAccount: "基本注意事项"
|
||||
tos: "服务条款"
|
||||
start: "开始"
|
||||
home: "首页"
|
||||
@@ -464,7 +467,8 @@ youHaveNoGroups: "没有群组"
|
||||
joinOrCreateGroup: "请加入一个现有的群组,或者创建新群组。"
|
||||
noHistory: "没有历史记录"
|
||||
signinHistory: "登录历史"
|
||||
disableAnimatedMfm: "禁用MFM动画"
|
||||
enableAdvancedMfm: "启用扩展MFM"
|
||||
enableAnimatedMfm: "启用MFM动画"
|
||||
doing: "正在进行"
|
||||
category: "类别"
|
||||
tags: "标签"
|
||||
@@ -861,6 +865,8 @@ failedToFetchAccountInformation: "获取账户信息失败"
|
||||
rateLimitExceeded: "已超過速率限制"
|
||||
cropImage: "剪裁图像"
|
||||
cropImageAsk: "是否要裁剪图像?"
|
||||
cropYes: "已裁剪"
|
||||
cropNo: "就这样吧!"
|
||||
file: "文件"
|
||||
recentNHours: "最近{n}小时"
|
||||
recentNDays: "最近{n}天"
|
||||
@@ -939,6 +945,12 @@ cannotPerformTemporaryDescription: "因操作过于频繁,暂时不可用,
|
||||
preset: "預設值"
|
||||
selectFromPresets: "從預設值中選擇"
|
||||
achievements: "成就"
|
||||
gotInvalidResponseError: "服务器无应答"
|
||||
gotInvalidResponseErrorDescription: "您的网络连接可能出现了问题, 或是远程服务器暂时不可用. 请稍后重试。"
|
||||
thisPostMayBeAnnoying: "这个帖子可能会让其他人感到困扰。"
|
||||
thisPostMayBeAnnoyingHome: "发到首页"
|
||||
thisPostMayBeAnnoyingCancel: "取消"
|
||||
thisPostMayBeAnnoyingIgnore: "就这样发布"
|
||||
_achievements:
|
||||
earnedAt: "达成时间"
|
||||
_types:
|
||||
@@ -1122,7 +1134,7 @@ _achievements:
|
||||
description: "在0点发布一篇帖子"
|
||||
flavor: "嘣 嘣 嘣 Biu——!"
|
||||
_selfQuote:
|
||||
title: "自我提及"
|
||||
title: "自我引用"
|
||||
description: "引用了自己的帖子"
|
||||
_htl20npm:
|
||||
title: "流动的时间线"
|
||||
@@ -1323,72 +1335,6 @@ _nsfw:
|
||||
respect: "隐藏敏感内容"
|
||||
ignore: "不隐藏敏感内容"
|
||||
force: "总是隐藏内容"
|
||||
_mfm:
|
||||
cheatSheet: "MFM代码速查表"
|
||||
intro: "MFM是一种在Misskey中的各个位置使用的专用标记语言。在这里您可以看到MFM中可用的语法列表。"
|
||||
dummy: "通过Misskey扩展联邦宇宙的世界"
|
||||
mention: "提及"
|
||||
mentionDescription: "可以使用 @+用户名 来指示特定用户"
|
||||
hashtag: "话题标签"
|
||||
hashtagDescription: "可以使用井号+文字来表示话题标签。"
|
||||
url: "URL"
|
||||
urlDescription: "可以表示URL地址。"
|
||||
link: "链接"
|
||||
linkDescription: "可以将部分文字和URL关联起来。"
|
||||
bold: "粗体"
|
||||
boldDescription: "可以将文字显示为粗体来表示强调。"
|
||||
small: "缩小"
|
||||
smallDescription: "可以使内容文字变小、变淡。"
|
||||
center: "居中"
|
||||
centerDescription: "可以将内容居中显示。"
|
||||
inlineCode: "代码(内嵌)"
|
||||
inlineCodeDescription: "将文字中的程序代码语法高亮显示。"
|
||||
blockCode: "代码(块)"
|
||||
blockCodeDescription: "语法高亮显示整块程序代码。"
|
||||
inlineMath: "数学公式(内嵌)"
|
||||
inlineMathDescription: "显示内嵌的KaTex公式。"
|
||||
blockMath: "数学公式(块)"
|
||||
blockMathDescription: "显示整块的多行KaTex数学公式。"
|
||||
quote: "引用"
|
||||
quoteDescription: "可以用来表示引用的内容。"
|
||||
emoji: "自定义表情符号"
|
||||
emojiDescription: "可以将自定义表情符号使用冒号括起来,就可以显示自定义表情符号了。"
|
||||
search: "搜索"
|
||||
searchDescription: "显示含有搜索内容示例的搜索框。"
|
||||
flip: "翻转"
|
||||
flipDescription: "将内容上下或左右翻转。"
|
||||
jelly: "动画(果冻)"
|
||||
jellyDescription: "显示果冻一样的动画效果。"
|
||||
tada: "动画(锵锵)"
|
||||
tadaDescription: "显示\"锵锵!\"的动画效果。"
|
||||
jump: "动画(跳动)"
|
||||
jumpDescription: "显示跳动的动画效果。"
|
||||
bounce: "动画(弹性)"
|
||||
bounceDescription: "显示弹性一样的动画效果。"
|
||||
shake: "动画(摇晃)"
|
||||
shakeDescription: "显示摇晃的动画效果。"
|
||||
twitch: "动画(颤抖)"
|
||||
twitchDescription: "显示强烈颤抖的动画效果。"
|
||||
spin: "动画(旋转)"
|
||||
spinDescription: "显示旋转的动画效果。"
|
||||
x2: "大"
|
||||
x2Description: "以大尺寸显示内容。"
|
||||
x3: "非常大"
|
||||
x3Description: "以更大尺寸显示内容。"
|
||||
x4: "最大"
|
||||
x4Description: "以最大尺寸显示内容。"
|
||||
blur: "模糊"
|
||||
blurDescription: "产生模糊效果。将鼠标指针放在上面即可将内容显示出来。"
|
||||
font: "字体"
|
||||
fontDescription: "可以设置内容所使用的字体。"
|
||||
rainbow: "彩虹"
|
||||
rainbowDescription: "用彩虹色来显示内容。"
|
||||
sparkle: "闪光"
|
||||
sparkleDescription: "添加发光粒子效果。"
|
||||
rotate: "旋转"
|
||||
rotateDescription: "旋转指定的角度。"
|
||||
plain: "简洁"
|
||||
plainDescription: "禁用所有内部语法。"
|
||||
_instanceTicker:
|
||||
none: "不显示"
|
||||
remote: "仅远程用户"
|
||||
@@ -1593,12 +1539,15 @@ _permissions:
|
||||
"read:gallery-likes": "读取喜欢的图片"
|
||||
"write:gallery-likes": "操作喜欢的图片"
|
||||
_auth:
|
||||
shareAccessTitle: "应用程序授权许可"
|
||||
shareAccess: "您要授权允许“{name}”访问您的帐户吗?"
|
||||
shareAccessAsk: "您确定要授权此应用程序访问您的帐户吗?"
|
||||
permission: "{name}需要以下权限"
|
||||
permissionAsk: "这个应用程序需要以下权限"
|
||||
pleaseGoBack: "请返回到应用程序"
|
||||
callback: "回到应用程序"
|
||||
denied: "拒绝访问"
|
||||
pleaseLogin: "在对应用进行授权许可之前,请先登录"
|
||||
_antennaSources:
|
||||
all: "所有帖子"
|
||||
homeTimeline: "已关注用户的帖子"
|
||||
|
||||
@@ -129,6 +129,7 @@ unblockConfirm: "確定解除封鎖此用戶?"
|
||||
suspendConfirm: "確定凍結此帳號?"
|
||||
unsuspendConfirm: "確定解凍此帳號?"
|
||||
selectList: "選擇清單"
|
||||
selectChannel: "選擇頻道"
|
||||
selectAntenna: "選擇天線"
|
||||
selectWidget: "選擇小工具"
|
||||
editWidgets: "編輯小工具"
|
||||
@@ -256,6 +257,8 @@ noMoreHistory: "沒有更多歷史紀錄"
|
||||
startMessaging: "開始聊天"
|
||||
nUsersRead: "{n}人已讀"
|
||||
agreeTo: "我同意{0}"
|
||||
agreeBelow: "同意以下內容"
|
||||
basicNotesBeforeCreateAccount: "基本注意事項"
|
||||
tos: "使用條款"
|
||||
start: "開始"
|
||||
home: "首頁"
|
||||
@@ -464,7 +467,8 @@ youHaveNoGroups: "找不到群組"
|
||||
joinOrCreateGroup: "請加入現有群組,或創建新群組。"
|
||||
noHistory: "沒有歷史紀錄"
|
||||
signinHistory: "登入歷史"
|
||||
disableAnimatedMfm: "禁用MFM動畫"
|
||||
enableAdvancedMfm: "啟用高級MFM"
|
||||
enableAnimatedMfm: "啟用MFM動畫"
|
||||
doing: "正在進行"
|
||||
category: "類別"
|
||||
tags: "標籤"
|
||||
@@ -861,6 +865,8 @@ failedToFetchAccountInformation: "取得帳戶資訊失敗"
|
||||
rateLimitExceeded: "已超過速率限制"
|
||||
cropImage: "圖片裁剪"
|
||||
cropImageAsk: "要剪裁圖片嗎?"
|
||||
cropYes: "裁剪"
|
||||
cropNo: "使用原圖"
|
||||
file: "檔案"
|
||||
recentNHours: "過去{n}小時"
|
||||
recentNDays: "過去{n}天"
|
||||
@@ -939,6 +945,13 @@ cannotPerformTemporaryDescription: "由於超過操作次數限制,暫時無
|
||||
preset: "預設值"
|
||||
selectFromPresets: "從預設值中選擇"
|
||||
achievements: "成就"
|
||||
gotInvalidResponseError: "伺服器的回應無效"
|
||||
gotInvalidResponseErrorDescription: "伺服器可能已關閉或者在維護中,請稍後再試。"
|
||||
thisPostMayBeAnnoying: "這篇貼文可能會造成別人的困擾。"
|
||||
thisPostMayBeAnnoyingHome: "發布到首頁"
|
||||
thisPostMayBeAnnoyingCancel: "退出"
|
||||
thisPostMayBeAnnoyingIgnore: "直接發布貼文"
|
||||
collapseRenotes: "省略顯示已看過的轉發貼文"
|
||||
_achievements:
|
||||
earnedAt: "獲得日期"
|
||||
_types:
|
||||
@@ -1323,72 +1336,6 @@ _nsfw:
|
||||
respect: "隱藏敏感內容"
|
||||
ignore: "不隱藏敏感內容"
|
||||
force: "隱藏所有內容"
|
||||
_mfm:
|
||||
cheatSheet: "MFM代碼小抄"
|
||||
intro: "MFM是Misskey專用的標記語言,可以在Misskey中的各個位置使用。 您可以這裏看到MFM可用語法列表。"
|
||||
dummy: "Misskey拓展了Fediverse的世界"
|
||||
mention: "提及"
|
||||
mentionDescription: "透過 @+用戶名 來標示特定使用者。"
|
||||
hashtag: "#tag"
|
||||
hashtagDescription: "可以使用\"#\"符號後加文字表示話題標籤。"
|
||||
url: "URL"
|
||||
urlDescription: "可以展示URL位址。"
|
||||
link: "鏈接"
|
||||
linkDescription: "您可以將特定範圍的文章與 URL 相關聯。 "
|
||||
bold: "粗體"
|
||||
boldDescription: "可以將文字顯示为粗體来強調。"
|
||||
small: "縮小"
|
||||
smallDescription: "可以使內容文字變小、變淡。"
|
||||
center: "置中"
|
||||
centerDescription: "可以將內容置中顯示。"
|
||||
inlineCode: "程式碼(内嵌)"
|
||||
inlineCodeDescription: "在行內用高亮度顯示,例如程式碼語法。"
|
||||
blockCode: "程式碼(區塊)"
|
||||
blockCodeDescription: "在區塊中用高亮度顯示,例如複數行的程式碼語法。"
|
||||
inlineMath: "數學公式(內嵌)"
|
||||
inlineMathDescription: "顯示內嵌的KaTex數學公式。"
|
||||
blockMath: "數學公式(方塊)"
|
||||
blockMathDescription: "以區塊顯示複數行的KaTex數學式。"
|
||||
quote: "引用"
|
||||
quoteDescription: "可以用來表示引用的内容。"
|
||||
emoji: "自訂表情符號"
|
||||
emojiDescription: "您可以通過將自定義表情符號名稱括在冒號中來顯示自定義表情符號。 "
|
||||
search: "搜尋"
|
||||
searchDescription: "您可以顯示所輸入的搜索框。"
|
||||
flip: "翻轉"
|
||||
flipDescription: "將內容上下或左右翻轉。"
|
||||
jelly: "動畫(果凍)"
|
||||
jellyDescription: "顯示果凍一樣的動畫效果。"
|
||||
tada: "動畫(鏘~)"
|
||||
tadaDescription: "顯示「鏘~!」這種感覺的動畫效果。"
|
||||
jump: "動畫(跳動)"
|
||||
jumpDescription: "顯示跳動的動畫效果。"
|
||||
bounce: "動畫(反彈)"
|
||||
bounceDescription: "顯示有彈性的動畫效果。"
|
||||
shake: "動畫(搖晃)"
|
||||
shakeDescription: "顯示顫抖的動畫效果。"
|
||||
twitch: "動畫(顫抖)"
|
||||
twitchDescription: "顯示強烈顫抖的動畫效果。"
|
||||
spin: "動畫(旋轉)"
|
||||
spinDescription: "顯示旋轉的動畫效果。"
|
||||
x2: "大"
|
||||
x2Description: "放大顯示內容。"
|
||||
x3: "較大"
|
||||
x3Description: "放大顯示內容。"
|
||||
x4: "最大"
|
||||
x4Description: "將顯示內容放至最大。"
|
||||
blur: "模糊"
|
||||
blurDescription: "產生模糊效果。将游標放在上面即可將内容顯示出來。"
|
||||
font: "字型"
|
||||
fontDescription: "您可以設定顯示內容的字型"
|
||||
rainbow: "彩虹"
|
||||
rainbowDescription: "用彩虹色來顯示內容。"
|
||||
sparkle: "閃閃發光"
|
||||
sparkleDescription: "添加閃閃發光的粒子效果。"
|
||||
rotate: "旋轉"
|
||||
rotateDescription: "以指定的角度旋轉。"
|
||||
plain: "簡潔"
|
||||
plainDescription: "停用全部的內部語法。"
|
||||
_instanceTicker:
|
||||
none: "隱藏"
|
||||
remote: "向遠端使用者顯示"
|
||||
@@ -1593,12 +1540,15 @@ _permissions:
|
||||
"read:gallery-likes": "讀取喜歡的圖片"
|
||||
"write:gallery-likes": "操作喜歡的圖片"
|
||||
_auth:
|
||||
shareAccessTitle: "應用程式的存取權限"
|
||||
shareAccess: "要授權「“{name}”」存取您的帳戶嗎?"
|
||||
shareAccessAsk: "您確定要授權這個應用程式使用您的帳戶嗎?"
|
||||
permission: "{name}要求以下的權限"
|
||||
permissionAsk: "此應用程式需要以下權限"
|
||||
pleaseGoBack: "請返回至應用程式"
|
||||
callback: "回到應用程式"
|
||||
denied: "拒絕訪問"
|
||||
pleaseLogin: "必須登入以提供應用程式的存取權限。"
|
||||
_antennaSources:
|
||||
all: "全部貼文"
|
||||
homeTimeline: "來自已追隨使用者的貼文"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "misskey",
|
||||
"version": "13.5.3",
|
||||
"version": "13.6.1",
|
||||
"codename": "nasubi",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/misskey-dev/misskey.git"
|
||||
},
|
||||
"packageManager": "pnpm@7.24.3",
|
||||
"packageManager": "pnpm@7.27.0",
|
||||
"workspaces": [
|
||||
"packages/frontend",
|
||||
"packages/backend",
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
"tsc-alias": "1.8.2",
|
||||
"tsconfig-paths": "4.1.2",
|
||||
"twemoji-parser": "14.0.0",
|
||||
"typeorm": "0.3.12",
|
||||
"typeorm": "0.3.11",
|
||||
"typescript": "4.9.5",
|
||||
"ulid": "2.3.0",
|
||||
"unzipper": "0.10.11",
|
||||
|
||||
@@ -67,6 +67,7 @@ export type Source = {
|
||||
|
||||
mediaProxy?: string;
|
||||
proxyRemoteFiles?: boolean;
|
||||
videoThumbnailGenerator?: string;
|
||||
|
||||
signToActivityPubGet?: boolean;
|
||||
};
|
||||
@@ -89,6 +90,7 @@ export type Mixin = {
|
||||
clientManifestExists: boolean;
|
||||
mediaProxy: string;
|
||||
externalMediaProxyEnabled: boolean;
|
||||
videoThumbnailGenerator: string | null;
|
||||
};
|
||||
|
||||
export type Config = Source & Mixin;
|
||||
@@ -144,6 +146,10 @@ export function loadConfig() {
|
||||
mixin.mediaProxy = externalMediaProxy ?? internalMediaProxy;
|
||||
mixin.externalMediaProxyEnabled = externalMediaProxy !== null && externalMediaProxy !== internalMediaProxy;
|
||||
|
||||
mixin.videoThumbnailGenerator = config.videoThumbnailGenerator ?
|
||||
config.videoThumbnailGenerator.endsWith('/') ? config.videoThumbnailGenerator.substring(0, config.videoThumbnailGenerator.length - 1) : config.videoThumbnailGenerator
|
||||
: null;
|
||||
|
||||
if (!config.redis.prefix) config.redis.prefix = mixin.host;
|
||||
|
||||
return Object.assign(config, mixin);
|
||||
|
||||
@@ -250,6 +250,14 @@ export class DriveService {
|
||||
@bindThis
|
||||
public async generateAlts(path: string, type: string, generateWeb: boolean) {
|
||||
if (type.startsWith('video/')) {
|
||||
if (this.config.videoThumbnailGenerator != null) {
|
||||
// videoThumbnailGeneratorが指定されていたら動画サムネイル生成はスキップ
|
||||
return {
|
||||
webpublic: null,
|
||||
thumbnail: null,
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const thumbnail = await this.videoProcessingService.generateVideoThumbnail(path);
|
||||
return {
|
||||
|
||||
@@ -211,8 +211,14 @@ export class RoleService implements OnApplicationShutdown {
|
||||
const assignedRoleIds = assigns.map(x => x.roleId);
|
||||
const roles = await this.rolesCache.fetch(null, () => this.rolesRepository.findBy({}));
|
||||
const assignedBadgeRoles = roles.filter(r => r.asBadge && assignedRoleIds.includes(r.id));
|
||||
// コンディショナルロールも含めるのは負荷高そうだから一旦無し
|
||||
return assignedBadgeRoles;
|
||||
const badgeCondRoles = roles.filter(r => r.asBadge && (r.target === 'conditional'));
|
||||
if (badgeCondRoles.length > 0) {
|
||||
const user = roles.some(r => r.target === 'conditional') ? await this.userCacheService.findById(userId) : null;
|
||||
const matchedBadgeCondRoles = badgeCondRoles.filter(r => this.evalCond(user!, r.condFormula));
|
||||
return [...assignedBadgeRoles, ...matchedBadgeCondRoles];
|
||||
} else {
|
||||
return assignedBadgeRoles;
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
|
||||
@@ -14,6 +14,8 @@ import { RoleService } from '@/core/RoleService.js';
|
||||
|
||||
@Injectable()
|
||||
export class UserListService {
|
||||
public static TooManyUsersError = class extends Error {};
|
||||
|
||||
constructor(
|
||||
@Inject(DI.usersRepository)
|
||||
private usersRepository: UsersRepository,
|
||||
@@ -36,7 +38,7 @@ export class UserListService {
|
||||
userListId: list.id,
|
||||
});
|
||||
if (currentCount > (await this.roleService.getUserPolicies(me.id)).userEachUserListsLimit) {
|
||||
throw new Error('Too many users');
|
||||
throw new UserListService.TooManyUsersError();
|
||||
}
|
||||
|
||||
await this.userListJoiningsRepository.insert({
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ImageProcessingService } from '@/core/ImageProcessingService.js';
|
||||
import type { IImage } from '@/core/ImageProcessingService.js';
|
||||
import { createTempDir } from '@/misc/create-temp.js';
|
||||
import { bindThis } from '@/decorators.js';
|
||||
import { appendQuery, query } from '@/misc/prelude/url.js';
|
||||
|
||||
@Injectable()
|
||||
export class VideoProcessingService {
|
||||
@@ -41,5 +42,18 @@ export class VideoProcessingService {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public getExternalVideoThumbnailUrl(url: string): string | null {
|
||||
if (this.config.videoThumbnailGenerator == null) return null;
|
||||
|
||||
return appendQuery(
|
||||
`${this.config.videoThumbnailGenerator}/thumbnail.webp`,
|
||||
query({
|
||||
thumbnail: '1',
|
||||
url,
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import { deepClone } from '@/misc/clone.js';
|
||||
import { UtilityService } from '../UtilityService.js';
|
||||
import { UserEntityService } from './UserEntityService.js';
|
||||
import { DriveFolderEntityService } from './DriveFolderEntityService.js';
|
||||
import { VideoProcessingService } from '../VideoProcessingService.js';
|
||||
|
||||
type PackOptions = {
|
||||
detail?: boolean,
|
||||
@@ -43,6 +44,7 @@ export class DriveFileEntityService {
|
||||
|
||||
private utilityService: UtilityService,
|
||||
private driveFolderEntityService: DriveFolderEntityService,
|
||||
private videoProcessingService: VideoProcessingService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -72,40 +74,63 @@ export class DriveFileEntityService {
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public getPublicUrl(file: DriveFile, mode? : 'static' | 'avatar'): string | null { // static = thumbnail
|
||||
const proxiedUrl = (url: string) => appendQuery(
|
||||
private getProxiedUrl(url: string, mode?: 'static' | 'avatar'): string | null {
|
||||
return appendQuery(
|
||||
`${this.config.mediaProxy}/${mode ?? 'image'}.webp`,
|
||||
query({
|
||||
url,
|
||||
...(mode ? { [mode]: '1' } : {}),
|
||||
})
|
||||
);
|
||||
)
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public getThumbnailUrl(file: DriveFile): string | null {
|
||||
if (file.type.startsWith('video')) {
|
||||
if (file.thumbnailUrl) return file.thumbnailUrl;
|
||||
|
||||
if (this.config.videoThumbnailGenerator == null) {
|
||||
return this.videoProcessingService.getExternalVideoThumbnailUrl(file.webpublicUrl ?? file.url ?? file.uri);
|
||||
}
|
||||
} else if (file.uri != null && file.userHost != null && this.config.externalMediaProxyEnabled) {
|
||||
// 動画ではなくリモートかつメディアプロキシ
|
||||
return this.getProxiedUrl(file.uri, 'static');
|
||||
}
|
||||
|
||||
if (file.uri != null && file.isLink && this.config.proxyRemoteFiles) {
|
||||
// リモートかつ期限切れはローカルプロキシを試みる
|
||||
// 従来は/files/${thumbnailAccessKey}にアクセスしていたが、
|
||||
// /filesはメディアプロキシにリダイレクトするようにしたため直接メディアプロキシを指定する
|
||||
return this.getProxiedUrl(file.uri, 'static');
|
||||
}
|
||||
|
||||
const url = file.webpublicUrl ?? file.url;
|
||||
|
||||
return file.thumbnailUrl ?? (isMimeImage(file.type, 'sharp-convertible-image') ? this.getProxiedUrl(url, 'static') : null);
|
||||
}
|
||||
|
||||
@bindThis
|
||||
public getPublicUrl(file: DriveFile, mode?: 'avatar'): string | null { // static = thumbnail
|
||||
// リモートかつメディアプロキシ
|
||||
if (file.uri != null && file.userHost != null && this.config.externalMediaProxyEnabled) {
|
||||
if (!(mode === 'static' && file.type.startsWith('video'))) {
|
||||
return proxiedUrl(file.uri);
|
||||
}
|
||||
return this.getProxiedUrl(file.uri, mode);
|
||||
}
|
||||
|
||||
// リモートかつ期限切れはローカルプロキシを試みる
|
||||
if (file.uri != null && file.isLink && this.config.proxyRemoteFiles) {
|
||||
const key = mode === 'static' ? file.thumbnailAccessKey : file.webpublicAccessKey;
|
||||
const key = file.webpublicAccessKey;
|
||||
|
||||
if (key && !key.match('/')) { // 古いものはここにオブジェクトストレージキーが入ってるので除外
|
||||
const url = `${this.config.url}/files/${key}`;
|
||||
if (mode === 'avatar') return proxiedUrl(file.uri);
|
||||
if (mode === 'avatar') return this.getProxiedUrl(file.uri, 'avatar');
|
||||
return url;
|
||||
}
|
||||
}
|
||||
|
||||
const url = file.webpublicUrl ?? file.url;
|
||||
|
||||
if (mode === 'static') {
|
||||
return file.thumbnailUrl ?? (isMimeImage(file.type, 'sharp-convertible-image') ? proxiedUrl(url) : null);
|
||||
}
|
||||
if (mode === 'avatar') {
|
||||
return proxiedUrl(url);
|
||||
return this.getProxiedUrl(url, 'avatar');
|
||||
}
|
||||
return url;
|
||||
}
|
||||
@@ -183,7 +208,7 @@ export class DriveFileEntityService {
|
||||
blurhash: file.blurhash,
|
||||
properties: opts.self ? file.properties : this.getPublicProperties(file),
|
||||
url: opts.self ? file.url : this.getPublicUrl(file),
|
||||
thumbnailUrl: this.getPublicUrl(file, 'static'),
|
||||
thumbnailUrl: this.getThumbnailUrl(file),
|
||||
comment: file.comment,
|
||||
folderId: file.folderId,
|
||||
folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
|
||||
@@ -218,7 +243,7 @@ export class DriveFileEntityService {
|
||||
blurhash: file.blurhash,
|
||||
properties: opts.self ? file.properties : this.getPublicProperties(file),
|
||||
url: opts.self ? file.url : this.getPublicUrl(file),
|
||||
thumbnailUrl: this.getPublicUrl(file, 'static'),
|
||||
thumbnailUrl: this.getThumbnailUrl(file),
|
||||
comment: file.comment,
|
||||
folderId: file.folderId,
|
||||
folder: opts.detail && file.folderId ? this.driveFolderEntityService.pack(file.folderId, {
|
||||
|
||||
@@ -441,6 +441,14 @@ export class ActivityPubServerService {
|
||||
fastify.addContentTypeParser('application/activity+json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'));
|
||||
fastify.addContentTypeParser('application/ld+json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'));
|
||||
|
||||
fastify.addHook('onRequest', (request, reply, done) => {
|
||||
reply.header('Access-Control-Allow-Headers', 'Accept');
|
||||
reply.header('Access-Control-Allow-Methods', 'GET, OPTIONS');
|
||||
reply.header('Access-Control-Allow-Origin', '*');
|
||||
reply.header('Access-Control-Expose-Headers', 'Vary');
|
||||
done();
|
||||
});
|
||||
|
||||
//#region Routing
|
||||
// inbox (limit: 64kb)
|
||||
fastify.post('/inbox', { bodyLimit: 1024 * 64 }, async (request, reply) => await this.inbox(request, reply));
|
||||
|
||||
@@ -150,6 +150,12 @@ export class FileServerService {
|
||||
file.cleanup();
|
||||
return await reply.redirect(301, url.toString());
|
||||
} else if (file.mime.startsWith('video/')) {
|
||||
const externalThumbnail = this.videoProcessingService.getExternalVideoThumbnailUrl(file.url);
|
||||
if (externalThumbnail) {
|
||||
file.cleanup();
|
||||
return await reply.redirect(301, externalThumbnail);
|
||||
}
|
||||
|
||||
image = await this.videoProcessingService.generateVideoThumbnail(file.path);
|
||||
}
|
||||
}
|
||||
@@ -255,8 +261,21 @@ export class FileServerService {
|
||||
const isConvertibleImage = isMimeImage(file.mime, 'sharp-convertible-image');
|
||||
const isAnimationConvertibleImage = isMimeImage(file.mime, 'sharp-animation-convertible-image');
|
||||
|
||||
if (
|
||||
'emoji' in request.query ||
|
||||
'avatar' in request.query ||
|
||||
'static' in request.query ||
|
||||
'preview' in request.query ||
|
||||
'badge' in request.query
|
||||
) {
|
||||
if (!isConvertibleImage) {
|
||||
// 画像でないなら404でお茶を濁す
|
||||
throw new StatusError('Unexpected mime', 404);
|
||||
}
|
||||
}
|
||||
|
||||
let image: IImageStreamable | null = null;
|
||||
if (('emoji' in request.query || 'avatar' in request.query) && isConvertibleImage) {
|
||||
if ('emoji' in request.query || 'avatar' in request.query) {
|
||||
if (!isAnimationConvertibleImage && !('static' in request.query)) {
|
||||
image = {
|
||||
data: fs.createReadStream(file.path),
|
||||
@@ -277,16 +296,11 @@ export class FileServerService {
|
||||
type: 'image/webp',
|
||||
};
|
||||
}
|
||||
} else if ('static' in request.query && isConvertibleImage) {
|
||||
} else if ('static' in request.query) {
|
||||
image = this.imageProcessingService.convertToWebpStream(file.path, 498, 280);
|
||||
} else if ('preview' in request.query && isConvertibleImage) {
|
||||
} else if ('preview' in request.query) {
|
||||
image = this.imageProcessingService.convertToWebpStream(file.path, 200, 200);
|
||||
} else if ('badge' in request.query) {
|
||||
if (!isConvertibleImage) {
|
||||
// 画像でないなら404でお茶を濁す
|
||||
throw new StatusError('Unexpected mime', 404);
|
||||
}
|
||||
|
||||
const mask = sharp(file.path)
|
||||
.resize(96, 96, {
|
||||
fit: 'inside',
|
||||
|
||||
@@ -227,15 +227,17 @@ export class ApiCallService implements OnApplicationShutdown {
|
||||
// TODO: 毎リクエスト計算するのもあれだしキャッシュしたい
|
||||
const factor = user ? (await this.roleService.getUserPolicies(user.id)).rateLimitFactor : 1;
|
||||
|
||||
// Rate limit
|
||||
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor, factor).catch(err => {
|
||||
throw new ApiError({
|
||||
message: 'Rate limit exceeded. Please try again later.',
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef',
|
||||
httpStatusCode: 429,
|
||||
if (factor > 0) {
|
||||
// Rate limit
|
||||
await this.rateLimiterService.limit(limit as IEndpointMeta['limit'] & { key: NonNullable<string> }, limitActor, factor).catch(err => {
|
||||
throw new ApiError({
|
||||
message: 'Rate limit exceeded. Please try again later.',
|
||||
code: 'RATE_LIMIT_EXCEEDED',
|
||||
id: 'd5826d14-3982-4d2e-8011-b9e9f02499ef',
|
||||
httpStatusCode: 429,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (ep.meta.requireCredential || ep.meta.requireModerator || ep.meta.requireAdmin) {
|
||||
|
||||
@@ -15,8 +15,8 @@ export const meta = {
|
||||
requireCredential: true,
|
||||
|
||||
limit: {
|
||||
duration: 60000,
|
||||
max: 15,
|
||||
duration: 30000,
|
||||
max: 30,
|
||||
},
|
||||
|
||||
kind: 'read:notifications',
|
||||
|
||||
@@ -45,6 +45,12 @@ export const meta = {
|
||||
code: 'YOU_HAVE_BEEN_BLOCKED',
|
||||
id: '990232c5-3f9d-4d83-9f3f-ef27b6332a4b',
|
||||
},
|
||||
|
||||
tooManyUsers: {
|
||||
message: 'You can not push users any more.',
|
||||
code: 'TOO_MANY_USERS',
|
||||
id: '2dd9752e-a338-413d-8eec-41814430989b',
|
||||
},
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -110,8 +116,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> {
|
||||
throw new ApiError(meta.errors.alreadyAdded);
|
||||
}
|
||||
|
||||
// Push the user
|
||||
await this.userListService.push(user, userList, me);
|
||||
try {
|
||||
await this.userListService.push(user, userList, me);
|
||||
} catch (err) {
|
||||
if (err instanceof UserListService.TooManyUsersError) {
|
||||
throw new ApiError(meta.errors.tooManyUsers);
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ export class ClientServerService {
|
||||
|
||||
const renderBase = async (reply: FastifyReply) => {
|
||||
const meta = await this.metaService.fetch();
|
||||
reply.header('Cache-Control', 'public, max-age=15');
|
||||
reply.header('Cache-Control', 'public, max-age=30');
|
||||
return await reply.view('base', {
|
||||
img: meta.bannerUrl,
|
||||
title: meta.name ?? 'Misskey',
|
||||
|
||||
@@ -11,6 +11,9 @@ window.onload = async () => {
|
||||
|
||||
// Send request
|
||||
fetch(endpoint.indexOf('://') > -1 ? endpoint : `/api/${endpoint}`, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
credentials: 'omit',
|
||||
|
||||
@@ -35,7 +35,8 @@ html
|
||||
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/error.jpg')
|
||||
link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css')
|
||||
//- https://github.com/misskey-dev/misskey/issues/9842
|
||||
link(rel='stylesheet' href='/assets/tabler-icons/tabler-icons.min.css?v2.2.0')
|
||||
link(rel='modulepreload' href=`/vite/${clientEntry.file}`)
|
||||
|
||||
if !config.clientManifestExists
|
||||
|
||||
@@ -107,6 +107,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
.iconFrame {
|
||||
position: relative;
|
||||
width: 58px;
|
||||
height: 58px;
|
||||
padding: 6px;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<button class="_button" :class="$style.root" @click="toggle">
|
||||
<button class="_button" :class="$style.root" @mousedown="toggle">
|
||||
<b>{{ modelValue ? i18n.ts._cw.hide : i18n.ts._cw.show }}</b>
|
||||
<span v-if="!modelValue" :class="$style.label">{{ label }}</span>
|
||||
</button>
|
||||
|
||||
@@ -28,11 +28,11 @@
|
||||
</template>
|
||||
</MkSelect>
|
||||
<div v-if="(showOkButton || showCancelButton) && !actions" :class="$style.buttons">
|
||||
<MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ (showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt }}</MkButton>
|
||||
<MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ i18n.ts.cancel }}</MkButton>
|
||||
<MkButton v-if="showOkButton" inline primary :autofocus="!input && !select" @click="ok">{{ okText ?? ((showCancelButton || input || select) ? i18n.ts.ok : i18n.ts.gotIt) }}</MkButton>
|
||||
<MkButton v-if="showCancelButton || input || select" inline @click="cancel">{{ cancelText ?? i18n.ts.cancel }}</MkButton>
|
||||
</div>
|
||||
<div v-if="actions" :class="$style.buttons">
|
||||
<MkButton v-for="action in actions" :key="action.text" inline :primary="action.primary" @click="() => { action.callback(); close(); }">{{ action.text }}</MkButton>
|
||||
<MkButton v-for="action in actions" :key="action.text" inline :primary="action.primary" @click="() => { action.callback(); modal?.close(); }">{{ action.text }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</MkModal>
|
||||
@@ -82,6 +82,8 @@ const props = withDefaults(defineProps<{
|
||||
showOkButton?: boolean;
|
||||
showCancelButton?: boolean;
|
||||
cancelableByBgClick?: boolean;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
}>(), {
|
||||
type: 'info',
|
||||
showOkButton: true,
|
||||
|
||||
@@ -42,7 +42,7 @@ import { i18n } from '@/i18n';
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string | number;
|
||||
type?: 'text' | 'number' | 'password' | 'email' | 'url' | 'date' | 'time' | 'search';
|
||||
type?: 'text' | 'number' | 'password' | 'email' | 'url' | 'date' | 'time' | 'search' | 'datetime-local';
|
||||
required?: boolean;
|
||||
readonly?: boolean;
|
||||
disabled?: boolean;
|
||||
|
||||
@@ -56,7 +56,7 @@ onMounted(() => {
|
||||
width: 100%;
|
||||
border-radius: 4px;
|
||||
margin-top: 4px;
|
||||
overflow: clip;
|
||||
// overflow: clip;
|
||||
|
||||
--plyr-color-main: var(--accent);
|
||||
--plyr-audio-controls-background: var(--bg);
|
||||
@@ -99,7 +99,7 @@ onMounted(() => {
|
||||
|
||||
> .audio {
|
||||
border-radius: 8px;
|
||||
overflow: clip;
|
||||
// overflow: clip;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else :class="$style.visible">
|
||||
<div v-else :class="$style.visible" :style="defaultStore.state.darkMode ? '--c: rgb(255 255 255 / 2%);' : '--c: rgb(0 0 0 / 2%);'">
|
||||
<a
|
||||
:class="$style.imageContainer"
|
||||
:href="image.url"
|
||||
@@ -78,7 +78,6 @@ watch(() => props.image, () => {
|
||||
position: relative;
|
||||
//box-shadow: 0 0 0 1px var(--divider) inset;
|
||||
background: var(--bg);
|
||||
--c: rgb(0 0 0 / 2%);
|
||||
background-image: linear-gradient(45deg, var(--c) 16.67%, var(--bg) 16.67%, var(--bg) 50%, var(--c) 50%, var(--c) 66.67%, var(--bg) 66.67%, var(--bg) 100%);
|
||||
background-size: 16px 16px;
|
||||
}
|
||||
|
||||
@@ -134,6 +134,9 @@ const previewable = (file: misskey.entities.DriveFile): boolean => {
|
||||
display: grid;
|
||||
grid-gap: 8px;
|
||||
|
||||
// for webkit
|
||||
height: 100%;
|
||||
|
||||
&.n1 {
|
||||
aspect-ratio: 16/9;
|
||||
grid-template-rows: 1fr;
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
ref="el"
|
||||
v-hotkey="keymap"
|
||||
:class="$style.root"
|
||||
:tabindex="!isDeleted ? '-1' : null"
|
||||
:tabindex="!isDeleted ? '-1' : undefined"
|
||||
>
|
||||
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||
<MkNoteSub v-if="appearNote.reply && !renoteCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
|
||||
<div v-if="pinned" :class="$style.tip"><i class="ti ti-pin"></i> {{ i18n.ts.pinnedNote }}</div>
|
||||
<!--<div v-if="appearNote._prId_" class="tip"><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="tip"><i class="ti ti-bolt"></i> {{ i18n.ts.featured }}</div>-->
|
||||
<div v-if="isRenote" :class="$style.renote">
|
||||
<MkAvatar v-once :class="$style.renoteAvatar" :user="note.user" link preview/>
|
||||
<MkAvatar :class="$style.renoteAvatar" :user="note.user" link preview/>
|
||||
<i class="ti ti-repeat" style="margin-right: 4px;"></i>
|
||||
<I18n :src="i18n.ts.renotedBy" tag="span" :class="$style.renoteText">
|
||||
<template #user>
|
||||
@@ -34,8 +34,12 @@
|
||||
<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>
|
||||
<article :class="$style.article" @contextmenu.stop="onContextmenu">
|
||||
<MkAvatar v-once :class="$style.avatar" :user="appearNote.user" link preview/>
|
||||
<div v-if="renoteCollapsed" :class="$style.collapsedRenoteTarget">
|
||||
<MkAvatar :class="$style.collapsedRenoteTargetAvatar" :user="appearNote.user" link preview/>
|
||||
<Mfm :text="getNoteSummary(appearNote)" :plain="true" :nowrap="true" :author="appearNote.user" :class="$style.collapsedRenoteTargetText" @click="renoteCollapsed = false"/>
|
||||
</div>
|
||||
<article v-else :class="$style.article" @contextmenu.stop="onContextmenu">
|
||||
<MkAvatar :class="$style.avatar" :user="appearNote.user" link preview/>
|
||||
<div :class="$style.main">
|
||||
<MkNoteHeader :class="$style.header" :note="appearNote" :mini="true"/>
|
||||
<MkInstanceTicker v-if="showTicker" :class="$style.ticker" :instance="appearNote.user.instance"/>
|
||||
@@ -60,7 +64,7 @@
|
||||
<div v-if="appearNote.files.length > 0" :class="$style.files">
|
||||
<MkMediaList :media-list="appearNote.files"/>
|
||||
</div>
|
||||
<MkPoll v-if="appearNote.poll" ref="pollViewer" :note="appearNote" :class="$style.poll"/>
|
||||
<MkPoll v-if="appearNote.poll" :note="appearNote" :class="$style.poll"/>
|
||||
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false" :class="$style.urlPreview"/>
|
||||
<div v-if="appearNote.renote" :class="$style.quote"><MkNoteSimple :note="appearNote.renote" :class="$style.quoteNote"/></div>
|
||||
<button v-if="isLong && collapsed" :class="$style.collapsed" class="_button" @click="collapsed = false">
|
||||
@@ -73,7 +77,13 @@
|
||||
<MkA v-if="appearNote.channel && !inChannel" :class="$style.channel" :to="`/channels/${appearNote.channel.id}`"><i class="ti ti-device-tv"></i> {{ appearNote.channel.name }}</MkA>
|
||||
</div>
|
||||
<footer :class="$style.footer">
|
||||
<MkReactionsViewer ref="reactionsViewer" :note="appearNote"/>
|
||||
<MkReactionsViewer :note="appearNote" :max-number="16">
|
||||
<template #more>
|
||||
<button class="_button" :class="$style.reactionDetailsButton" @click="showReactions">
|
||||
{{ i18n.ts.more }}
|
||||
</button>
|
||||
</template>
|
||||
</MkReactionsViewer>
|
||||
<button :class="$style.footerButton" class="_button" @click="reply()">
|
||||
<i class="ti ti-arrow-back-up"></i>
|
||||
<p v-if="appearNote.repliesCount > 0" :class="$style.footerButtonCount">{{ appearNote.repliesCount }}</p>
|
||||
@@ -116,7 +126,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef, Ref } from 'vue';
|
||||
import { computed, inject, onMounted, onUnmounted, reactive, ref, shallowRef, Ref, defineAsyncComponent } from 'vue';
|
||||
import * as mfm from 'mfm-js';
|
||||
import * as misskey from 'misskey-js';
|
||||
import MkNoteSub from '@/components/MkNoteSub.vue';
|
||||
@@ -144,6 +154,9 @@ import { useNoteCapture } from '@/scripts/use-note-capture';
|
||||
import { deepClone } from '@/scripts/clone';
|
||||
import { useTooltip } from '@/scripts/use-tooltip';
|
||||
import { claimAchievement } from '@/scripts/achievements';
|
||||
import { getNoteSummary } from '@/scripts/get-note-summary';
|
||||
import { shownNoteIds } from '@/os';
|
||||
import { MenuItem } from '@/types/menu';
|
||||
|
||||
const props = defineProps<{
|
||||
note: misskey.entities.Note;
|
||||
@@ -180,18 +193,23 @@ const reactButton = shallowRef<HTMLElement>();
|
||||
let appearNote = $computed(() => isRenote ? note.renote as misskey.entities.Note : note);
|
||||
const isMyRenote = $i && ($i.id === note.userId);
|
||||
const showContent = ref(false);
|
||||
const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null;
|
||||
const isLong = (appearNote.cw == null && appearNote.text != null && (
|
||||
(appearNote.text.split('\n').length > 9) ||
|
||||
(appearNote.text.length > 500)
|
||||
(appearNote.text.length > 500) ||
|
||||
(appearNote.files.length >= 5) ||
|
||||
(urls && urls.length >= 4)
|
||||
));
|
||||
const collapsed = ref(appearNote.cw == null && isLong);
|
||||
const isDeleted = ref(false);
|
||||
const muted = ref(checkWordMute(appearNote, $i, defaultStore.state.mutedWords));
|
||||
const translation = ref(null);
|
||||
const translation = ref<any>(null);
|
||||
const translating = ref(false);
|
||||
const urls = appearNote.text ? extractUrlFromMfm(mfm.parse(appearNote.text)) : null;
|
||||
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);
|
||||
let renoteCollapsed = $ref(defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId)) || shownNoteIds.has(appearNote.id)));
|
||||
|
||||
shownNoteIds.add(appearNote.id);
|
||||
|
||||
const keymap = {
|
||||
'r': () => reply(true),
|
||||
@@ -230,7 +248,32 @@ useTooltip(renoteButton, async (showing) => {
|
||||
|
||||
function renote(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
os.popupMenu([{
|
||||
|
||||
let items = [] as MenuItem[];
|
||||
|
||||
if (appearNote.channel) {
|
||||
items = items.concat([{
|
||||
text: i18n.ts.inChannelRenote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
os.api('notes/create', {
|
||||
renoteId: appearNote.id,
|
||||
channelId: appearNote.channelId,
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.inChannelQuote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: appearNote,
|
||||
channel: appearNote.channel,
|
||||
});
|
||||
},
|
||||
}, null]);
|
||||
}
|
||||
|
||||
items = items.concat([{
|
||||
text: i18n.ts.renote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
@@ -246,7 +289,9 @@ function renote(viaKeyboard = false) {
|
||||
renote: appearNote,
|
||||
});
|
||||
},
|
||||
}], renoteButton.value, {
|
||||
}]);
|
||||
|
||||
os.popupMenu(items, renoteButton.value, {
|
||||
viaKeyboard,
|
||||
});
|
||||
}
|
||||
@@ -350,6 +395,12 @@ function readPromo() {
|
||||
});
|
||||
isDeleted.value = true;
|
||||
}
|
||||
|
||||
function showReactions(): void {
|
||||
os.popup(defineAsyncComponent(() => import('@/components/MkReactedUsersDialog.vue')), {
|
||||
noteId: appearNote.id,
|
||||
}, {}, 'closed');
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
@@ -433,7 +484,6 @@ function readPromo() {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin: 0 8px 0 0;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.renoteText {
|
||||
@@ -461,6 +511,36 @@ function readPromo() {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.collapsedRenoteTarget {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
line-height: 28px;
|
||||
white-space: pre;
|
||||
padding: 0 32px 18px;
|
||||
}
|
||||
|
||||
.collapsedRenoteTargetAvatar {
|
||||
flex-shrink: 0;
|
||||
display: inline-block;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
margin: 0 8px 0 0;
|
||||
}
|
||||
|
||||
.collapsedRenoteTargetText {
|
||||
overflow: hidden;
|
||||
flex-shrink: 1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 90%;
|
||||
opacity: 0.7;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.article {
|
||||
display: flex;
|
||||
padding: 28px 32px 18px;
|
||||
@@ -614,6 +694,11 @@ function readPromo() {
|
||||
padding: 8px 16px 0 16px;
|
||||
}
|
||||
|
||||
.collapsedRenoteTarget {
|
||||
padding: 0 16px 9px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.article {
|
||||
padding: 14px 16px 9px;
|
||||
}
|
||||
@@ -647,9 +732,30 @@ function readPromo() {
|
||||
}
|
||||
}
|
||||
|
||||
@container (max-width: 250px) {
|
||||
.quoteNote {
|
||||
padding: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.muted {
|
||||
padding: 8px;
|
||||
text-align: center;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.reactionDetailsButton {
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
margin: 2px;
|
||||
padding: 0 6px;
|
||||
border: dashed 1px var(--divider);
|
||||
border-radius: 4px;
|
||||
background: transparent;
|
||||
opacity: .8;
|
||||
|
||||
&:hover {
|
||||
background: var(--X5);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -160,6 +160,7 @@ import { useNoteCapture } from '@/scripts/use-note-capture';
|
||||
import { deepClone } from '@/scripts/clone';
|
||||
import { useTooltip } from '@/scripts/use-tooltip';
|
||||
import { claimAchievement } from '@/scripts/achievements';
|
||||
import { MenuItem } from '@/types/menu';
|
||||
|
||||
const props = defineProps<{
|
||||
note: misskey.entities.Note;
|
||||
@@ -241,7 +242,32 @@ useTooltip(renoteButton, async (showing) => {
|
||||
|
||||
function renote(viaKeyboard = false) {
|
||||
pleaseLogin();
|
||||
os.popupMenu([{
|
||||
|
||||
let items = [] as MenuItem[];
|
||||
|
||||
if (appearNote.channel) {
|
||||
items = items.concat([{
|
||||
text: i18n.ts.inChannelRenote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
os.api('notes/create', {
|
||||
renoteId: appearNote.id,
|
||||
channelId: appearNote.channelId,
|
||||
});
|
||||
},
|
||||
}, {
|
||||
text: i18n.ts.inChannelQuote,
|
||||
icon: 'ti ti-quote',
|
||||
action: () => {
|
||||
os.post({
|
||||
renote: appearNote,
|
||||
channel: appearNote.channel,
|
||||
});
|
||||
},
|
||||
}, null]);
|
||||
}
|
||||
|
||||
items = items.concat([{
|
||||
text: i18n.ts.renote,
|
||||
icon: 'ti ti-repeat',
|
||||
action: () => {
|
||||
@@ -257,7 +283,9 @@ function renote(viaKeyboard = false) {
|
||||
renote: appearNote,
|
||||
});
|
||||
},
|
||||
}], renoteButton.value, {
|
||||
}]);
|
||||
|
||||
os.popupMenu(items, renoteButton.value, {
|
||||
viaKeyboard,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<header :class="$style.root">
|
||||
<MkA v-once v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)">
|
||||
<MkA v-user-preview="note.user.id" :class="$style.name" :to="userPage(note.user)">
|
||||
<MkUserName :user="note.user"/>
|
||||
</MkA>
|
||||
<div v-if="note.user.isBot" :class="$style.isBot">bot</div>
|
||||
@@ -90,7 +90,7 @@ defineProps<{
|
||||
vertical-align: -20%;
|
||||
|
||||
& + .badgeRole {
|
||||
margin-left: .125em;
|
||||
margin-left: 0.2em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -44,8 +44,8 @@ const showContent = $ref(false);
|
||||
flex-shrink: 0;
|
||||
display: block;
|
||||
margin: 0 10px 0 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@@ -72,6 +72,14 @@ const showContent = $ref(false);
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@container (min-width: 250px) {
|
||||
.avatar {
|
||||
margin: 0 10px 0 0;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
@container (min-width: 350px) {
|
||||
.avatar {
|
||||
margin: 0 10px 0 0;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div ref="elRef" :class="$style.root">
|
||||
<div v-once :class="$style.head">
|
||||
<div :class="$style.head">
|
||||
<MkAvatar v-if="notification.type === 'pollEnded'" :class="$style.icon" :user="notification.note.user" link preview/>
|
||||
<MkAvatar v-else-if="notification.type === 'achievementEarned'" :class="$style.icon" :user="$i" link preview/>
|
||||
<MkAvatar v-else-if="notification.user" :class="$style.icon" :user="notification.user" link preview/>
|
||||
@@ -35,7 +35,7 @@
|
||||
<span v-else>{{ notification.header }}</span>
|
||||
<MkTime v-if="withTime" :time="notification.createdAt" :class="$style.headerTime"/>
|
||||
</header>
|
||||
<div v-once :class="$style.content">
|
||||
<div :class="$style.content">
|
||||
<MkA v-if="notification.type === 'reaction'" :class="$style.text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
|
||||
<i class="ti ti-quote" :class="$style.quote"></i>
|
||||
<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="true" :author="notification.note.user"/>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
<div v-else ref="rootEl">
|
||||
<div v-show="pagination.reversed && more" key="_more_" class="_margin">
|
||||
<MkButton v-if="!moreFetching" v-appear="(enableInfiniteScroll && !props.disableAutoLoad) ? fetchMore : null" :class="$style.more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary @click="fetchMore">
|
||||
<MkButton v-if="!moreFetching" v-appear="(enableInfiniteScroll && !props.disableAutoLoad) ? fetchMoreAhead : null" :class="$style.more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary @click="fetchMoreAhead">
|
||||
{{ i18n.ts.loadMore }}
|
||||
</MkButton>
|
||||
<MkLoading v-else class="loading"/>
|
||||
|
||||
@@ -109,7 +109,7 @@ const props = withDefaults(defineProps<{
|
||||
mention?: misskey.entities.User;
|
||||
specified?: misskey.entities.User;
|
||||
initialText?: string;
|
||||
initialVisibility?: typeof misskey.noteVisibilities;
|
||||
initialVisibility?: (typeof misskey.noteVisibilities)[number];
|
||||
initialFiles?: misskey.entities.DriveFile[];
|
||||
initialLocalOnly?: boolean;
|
||||
initialVisibleUsers?: misskey.entities.User[];
|
||||
@@ -579,6 +579,36 @@ async function post(ev?: MouseEvent) {
|
||||
os.popup(MkRippleEffect, { x, y }, {}, 'end');
|
||||
}
|
||||
|
||||
const annoying =
|
||||
text.includes('$[x2') ||
|
||||
text.includes('$[x3') ||
|
||||
text.includes('$[x4') ||
|
||||
text.includes('$[scale') ||
|
||||
text.includes('$[position');
|
||||
if (annoying) {
|
||||
const { canceled, result } = await os.actions({
|
||||
type: 'warning',
|
||||
text: i18n.ts.thisPostMayBeAnnoying,
|
||||
actions: [{
|
||||
value: 'home',
|
||||
text: i18n.ts.thisPostMayBeAnnoyingHome,
|
||||
primary: true,
|
||||
}, {
|
||||
value: 'cancel',
|
||||
text: i18n.ts.thisPostMayBeAnnoyingCancel,
|
||||
}, {
|
||||
value: 'ignore',
|
||||
text: i18n.ts.thisPostMayBeAnnoyingIgnore,
|
||||
}],
|
||||
});
|
||||
|
||||
if (canceled) return;
|
||||
if (result === 'cancel') return;
|
||||
if (result === 'home') {
|
||||
visibility = 'home';
|
||||
}
|
||||
}
|
||||
|
||||
let postData = {
|
||||
text: text === '' ? undefined : text,
|
||||
fileIds: files.length > 0 ? files.map(f => f.id) : undefined,
|
||||
|
||||
@@ -107,7 +107,7 @@ useTooltip(buttonEl, async (showing) => {
|
||||
border-radius: 4px;
|
||||
|
||||
&.canToggle {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
background: var(--buttonBg);
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
|
||||
@@ -7,23 +7,60 @@
|
||||
:move-class="$store.state.animation ? $style.transition_x_move : ''"
|
||||
tag="div" :class="$style.root"
|
||||
>
|
||||
<XReaction v-for="(count, reaction) in note.reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/>
|
||||
<XReaction v-for="[reaction, count] in reactions" :key="reaction" :reaction="reaction" :count="count" :is-initial="initialReactions.has(reaction)" :note="note"/>
|
||||
<slot v-if="hasMoreReactions" name="more" />
|
||||
</TransitionGroup>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import * as misskey from 'misskey-js';
|
||||
import { $i } from '@/account';
|
||||
import XReaction from '@/components/MkReactionsViewer.reaction.vue';
|
||||
import { watch } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
note: misskey.entities.Note;
|
||||
}>();
|
||||
const props = withDefaults(defineProps<{
|
||||
note: misskey.entities.Note;
|
||||
maxNumber?: number;
|
||||
}>(), {
|
||||
maxNumber: Infinity,
|
||||
});
|
||||
|
||||
const initialReactions = new Set(Object.keys(props.note.reactions));
|
||||
|
||||
const isMe = computed(() => $i && $i.id === props.note.userId);
|
||||
let reactions = $ref<[string, number][]>([]);
|
||||
let hasMoreReactions = $ref(false);
|
||||
|
||||
if (props.note.myReaction && !Object.keys(reactions).includes(props.note.myReaction)) {
|
||||
reactions[props.note.myReaction] = props.note.reactions[props.note.myReaction];
|
||||
}
|
||||
|
||||
watch([() => props.note.reactions, () => props.maxNumber], ([newSource, maxNumber]) => {
|
||||
let newReactions: [string, number][] = [];
|
||||
hasMoreReactions = Object.keys(newSource).length > maxNumber;
|
||||
|
||||
for (let i = 0; i < reactions.length; i++) {
|
||||
const reaction = reactions[i][0];
|
||||
if (reaction in newSource && newSource[reaction] !== 0) {
|
||||
reactions[i][1] = newSource[reaction];
|
||||
newReactions.push(reactions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const newReactionsNames = newReactions.map(([x]) => x);
|
||||
newReactions = [
|
||||
...newReactions,
|
||||
...Object.entries(newSource)
|
||||
.sort(([, a], [, b]) => b - a)
|
||||
.filter(([y], i) => i < maxNumber && !newReactionsNames.includes(y)),
|
||||
]
|
||||
|
||||
newReactions = newReactions.slice(0, props.maxNumber);
|
||||
|
||||
if (props.note.myReaction && !newReactions.map(([x]) => x).includes(props.note.myReaction)) {
|
||||
newReactions.push([props.note.myReaction, newSource[props.note.myReaction]]);
|
||||
}
|
||||
|
||||
reactions = newReactions;
|
||||
}, { immediate: true, deep: true });
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
|
||||
@@ -50,13 +50,13 @@
|
||||
<span v-if="passwordRetypeState == 'not-match'" style="color: var(--error)"><i class="ti ti-alert-triangle ti-fw"></i> {{ i18n.ts.passwordNotMatched }}</span>
|
||||
</template>
|
||||
</MkInput>
|
||||
<MkSwitch v-if="instance.tosUrl" v-model="ToSAgreement" class="tou">
|
||||
<I18n :src="i18n.ts.agreeTo">
|
||||
<template #0>
|
||||
<a :href="instance.tosUrl" class="_link" target="_blank">{{ i18n.ts.tos }}</a>
|
||||
</template>
|
||||
</I18n>
|
||||
<MkSwitch v-model="ToSAgreement" class="tou">
|
||||
<template #label>{{ i18n.ts.agreeBelow }}</template>
|
||||
</MkSwitch>
|
||||
<ul style="margin: 0; padding-left: 2em;">
|
||||
<li v-if="instance.tosUrl"><a :href="instance.tosUrl" class="_link" target="_blank">{{ i18n.ts.tos }}</a></li>
|
||||
<li><a href="https://misskey-hub.net/docs/notes.html" class="_link" target="_blank">{{ i18n.ts.basicNotesBeforeCreateAccount }}</a></li>
|
||||
</ul>
|
||||
<MkCaptcha v-if="instance.enableHcaptcha" ref="hcaptcha" v-model="hCaptchaResponse" class="captcha" provider="hcaptcha" :sitekey="instance.hcaptchaSiteKey"/>
|
||||
<MkCaptcha v-if="instance.enableRecaptcha" ref="recaptcha" v-model="reCaptchaResponse" class="captcha" provider="recaptcha" :sitekey="instance.recaptchaSiteKey"/>
|
||||
<MkCaptcha v-if="instance.enableTurnstile" ref="turnstile" v-model="turnstileResponse" class="captcha" provider="turnstile" :sitekey="instance.turnstileSiteKey"/>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<p>{{ $ts.followers }}</p><span>{{ user.followersCount }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="menu _button" @click="showMenu"><i class="ti ti-dots"></i></button>
|
||||
<MkFollowButton v-if="$i && user.id != $i.id" class="koudoku-button" :user="user" mini/>
|
||||
</div>
|
||||
<div v-else>
|
||||
@@ -40,6 +41,7 @@ import * as misskey from 'misskey-js';
|
||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||
import { userPage } from '@/filters/user';
|
||||
import * as os from '@/os';
|
||||
import { getUserMenu } from '@/scripts/get-user-menu';
|
||||
|
||||
const props = defineProps<{
|
||||
showing: boolean;
|
||||
@@ -58,6 +60,10 @@ let user = $ref<misskey.entities.UserDetailed | null>(null);
|
||||
let top = $ref(0);
|
||||
let left = $ref(0);
|
||||
|
||||
function showMenu(ev: MouseEvent) {
|
||||
os.popupMenu(getUserMenu(user), ev.currentTarget ?? ev.target);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (typeof props.q === 'object') {
|
||||
user = props.q;
|
||||
@@ -174,6 +180,13 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
|
||||
> .menu {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 42px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
> .koudoku-button {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
<template>
|
||||
<span v-if="!link" v-user-preview="preview ? user.id : undefined" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" class="_noSelect" :style="{ color }" :title="acct(user)" @click="onClick">
|
||||
<span v-if="!link" v-user-preview="preview ? user.id : undefined" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :title="acct(user)" @click="onClick">
|
||||
<img :class="$style.inner" :src="url" decoding="async"/>
|
||||
<MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/>
|
||||
<template v-if="user.isCat">
|
||||
<div :class="$style.earLeft"/>
|
||||
<div :class="$style.earRight"/>
|
||||
</template>
|
||||
</span>
|
||||
<MkA v-else v-user-preview="preview ? user.id : undefined" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :to="userPage(user)" :title="acct(user)" :target="target">
|
||||
<MkA v-else v-user-preview="preview ? user.id : undefined" class="_noSelect" :class="[$style.root, { [$style.cat]: user.isCat, [$style.square]: $store.state.squareAvatars }]" :style="{ color }" :title="acct(user)" :to="userPage(user)" :target="target">
|
||||
<img :class="$style.inner" :src="url" decoding="async"/>
|
||||
<MkUserOnlineIndicator v-if="indicator" :class="$style.indicator" :user="user"/>
|
||||
<template v-if="user.isCat">
|
||||
<div :class="$style.earLeft"/>
|
||||
<div :class="$style.earRight"/>
|
||||
</template>
|
||||
</MkA>
|
||||
</template>
|
||||
|
||||
@@ -110,32 +118,41 @@ watch(() => props.user.avatarBlurhash, () => {
|
||||
}
|
||||
|
||||
.cat {
|
||||
&:before, &:after {
|
||||
background: #df548f;
|
||||
border: solid 4px currentColor;
|
||||
box-sizing: border-box;
|
||||
content: '';
|
||||
> .earLeft,
|
||||
> .earRight {
|
||||
contain: strict;
|
||||
display: inline-block;
|
||||
height: 50%;
|
||||
width: 50%;
|
||||
background: currentColor;
|
||||
|
||||
&::before {
|
||||
contain: strict;
|
||||
content: '';
|
||||
display: block;
|
||||
width: 60%;
|
||||
height: 60%;
|
||||
margin: 20%;
|
||||
background: #df548f;
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
> .earLeft {
|
||||
border-radius: 0 75% 75%;
|
||||
transform: rotate(37.5deg) skew(30deg);
|
||||
}
|
||||
|
||||
&:after {
|
||||
> .earRight {
|
||||
border-radius: 75% 0 75% 75%;
|
||||
transform: rotate(-37.5deg) skew(-30deg);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:before {
|
||||
> .earLeft {
|
||||
animation: earwiggleleft 1s infinite;
|
||||
}
|
||||
|
||||
&:after {
|
||||
> .earRight {
|
||||
animation: earwiggleright 1s infinite;
|
||||
}
|
||||
}
|
||||
|
||||
234
packages/frontend/src/components/global/MkPageHeader.tabs.vue
Normal file
234
packages/frontend/src/components/global/MkPageHeader.tabs.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<div ref="el" :class="$style.tabs" @wheel="onTabWheel">
|
||||
<div :class="$style.tabsInner">
|
||||
<button v-for="t in tabs" :ref="(el) => tabRefs[t.key] = (el as HTMLElement)" v-tooltip.noDelay="t.title"
|
||||
class="_button" :class="[$style.tab, { [$style.active]: t.key != null && t.key === props.tab, [$style.animate]: defaultStore.reactiveState.animation.value }]"
|
||||
@mousedown="(ev) => onTabMousedown(t, ev)" @click="(ev) => onTabClick(t, ev)">
|
||||
<div :class="$style.tabInner">
|
||||
<i v-if="t.icon" :class="[$style.tabIcon, t.icon]"></i>
|
||||
<div v-if="!t.iconOnly || (!defaultStore.reactiveState.animation.value && t.key === tab)"
|
||||
:class="$style.tabTitle">{{ t.title }}</div>
|
||||
<Transition v-else @enter="enter" @after-enter="afterEnter" @leave="leave" @after-leave="afterLeave"
|
||||
mode="in-out">
|
||||
<div v-show="t.key === tab" :class="[$style.tabTitle, $style.animate]">{{ t.title }}</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div ref="tabHighlightEl"
|
||||
:class="[$style.tabHighlight, { [$style.animate]: defaultStore.reactiveState.animation.value }]"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export type Tab = {
|
||||
key: string;
|
||||
title: string;
|
||||
icon?: string;
|
||||
iconOnly?: boolean;
|
||||
onClick?: (ev: MouseEvent) => void;
|
||||
} & {
|
||||
iconOnly: true;
|
||||
iccn: string;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, watch, nextTick, Transition, shallowRef } from 'vue';
|
||||
import { defaultStore } from '@/store';
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
tabs?: Tab[];
|
||||
tab?: string;
|
||||
rootEl?: HTMLElement;
|
||||
}>(), {
|
||||
tabs: () => ([] as Tab[]),
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(ev: 'update:tab', key: string);
|
||||
(ev: 'tabClick', key: string);
|
||||
}>();
|
||||
|
||||
const el = shallowRef<HTMLElement | null>(null);
|
||||
const tabRefs: Record<string, HTMLElement | null> = {};
|
||||
const tabHighlightEl = shallowRef<HTMLElement | null>(null);
|
||||
|
||||
function onTabMousedown(tab: Tab, ev: MouseEvent): void {
|
||||
// ユーザビリティの観点からmousedown時にはonClickは呼ばない
|
||||
if (tab.key) {
|
||||
emit('update:tab', tab.key);
|
||||
}
|
||||
}
|
||||
|
||||
function onTabClick(t: Tab, ev: MouseEvent): void {
|
||||
emit('tabClick', t.key);
|
||||
|
||||
if (t.onClick) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
t.onClick(ev);
|
||||
}
|
||||
|
||||
if (t.key) {
|
||||
emit('update:tab', t.key);
|
||||
}
|
||||
}
|
||||
|
||||
function renderTab() {
|
||||
const tabEl = props.tab ? tabRefs[props.tab] : undefined;
|
||||
if (tabEl && tabHighlightEl.value && tabHighlightEl.value.parentElement) {
|
||||
// offsetWidth や offsetLeft は少数を丸めてしまうため getBoundingClientRect を使う必要がある
|
||||
// https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetWidth#%E5%80%A4
|
||||
const parentRect = tabHighlightEl.value.parentElement.getBoundingClientRect();
|
||||
const rect = tabEl.getBoundingClientRect();
|
||||
tabHighlightEl.value.style.width = rect.width + 'px';
|
||||
tabHighlightEl.value.style.left = (rect.left - parentRect.left + tabHighlightEl.value.parentElement.scrollLeft) + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
function onTabWheel(ev: WheelEvent) {
|
||||
if (ev.deltaY !== 0 && ev.deltaX === 0) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
(ev.currentTarget as HTMLElement).scrollBy({
|
||||
left: ev.deltaY,
|
||||
behavior: 'smooth',
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
let entering = false;
|
||||
|
||||
async function enter(el: HTMLElement) {
|
||||
entering = true;
|
||||
const elementWidth = el.getBoundingClientRect().width;
|
||||
el.style.width = '0';
|
||||
el.style.paddingLeft = '0';
|
||||
el.offsetWidth; // force reflow
|
||||
el.style.width = elementWidth + 'px';
|
||||
el.style.paddingLeft = '';
|
||||
nextTick(() => {
|
||||
entering = false;
|
||||
});
|
||||
|
||||
setTimeout(renderTab, 170);
|
||||
}
|
||||
function afterEnter(el: HTMLElement) {
|
||||
//el.style.width = '';
|
||||
}
|
||||
async function leave(el: HTMLElement) {
|
||||
const elementWidth = el.getBoundingClientRect().width;
|
||||
el.style.width = elementWidth + 'px';
|
||||
el.style.paddingLeft = '';
|
||||
el.offsetWidth; // force reflow
|
||||
el.style.width = '0';
|
||||
el.style.paddingLeft = '0';
|
||||
}
|
||||
function afterLeave(el: HTMLElement) {
|
||||
el.style.width = '';
|
||||
}
|
||||
|
||||
let ro2: ResizeObserver | null;
|
||||
|
||||
onMounted(() => {
|
||||
watch([() => props.tab, () => props.tabs], () => {
|
||||
nextTick(() => {
|
||||
if (entering) return;
|
||||
renderTab();
|
||||
});
|
||||
}, {
|
||||
immediate: true,
|
||||
});
|
||||
|
||||
if (props.rootEl) {
|
||||
ro2 = new ResizeObserver((entries, observer) => {
|
||||
if (document.body.contains(el.value as HTMLElement)) {
|
||||
nextTick(() => renderTab());
|
||||
}
|
||||
});
|
||||
ro2.observe(props.rootEl);
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
if (ro2) ro2.disconnect();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.tabs {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin: 0;
|
||||
height: var(--height);
|
||||
font-size: 0.8em;
|
||||
text-align: center;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
scrollbar-width: none;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.tabsInner {
|
||||
display: inline-block;
|
||||
height: var(--height);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 0 10px;
|
||||
height: 100%;
|
||||
font-weight: normal;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.animate {
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.tabInner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tabIcon+.tabTitle {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.tabTitle {
|
||||
overflow: hidden;
|
||||
|
||||
&.animate {
|
||||
transition: width .15s linear, padding-left .15s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.tabHighlight {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 3px;
|
||||
background: var(--accent);
|
||||
border-radius: 999px;
|
||||
transition: none;
|
||||
pointer-events: none;
|
||||
|
||||
&.animate {
|
||||
transition: width 0.15s ease, left 0.15s ease;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,57 +1,46 @@
|
||||
<template>
|
||||
<div v-if="show" ref="el" :class="[$style.root, { [$style.slim]: narrow, [$style.thin]: thin_ }]" :style="{ background: bg }" @click="onClick">
|
||||
<div v-if="narrow" :class="$style.buttonsLeft">
|
||||
<MkAvatar v-if="props.displayMyAvatar && $i" :class="$style.avatar" :user="$i"/>
|
||||
</div>
|
||||
<template v-if="metadata">
|
||||
<div v-if="!hideTitle" :class="$style.titleContainer" @click="showTabsPopup">
|
||||
<MkAvatar v-if="metadata.avatar" :class="$style.titleAvatar" :user="metadata.avatar" indicator/>
|
||||
<i v-else-if="metadata.icon" :class="[$style.titleIcon, metadata.icon]"></i>
|
||||
<div v-if="show" ref="el" :class="[$style.root]" :style="{ background: bg }">
|
||||
<div :class="[$style.upper, { [$style.slim]: narrow, [$style.thin]: thin_ }]">
|
||||
<div v-if="!thin_ && narrow && props.displayMyAvatar && $i" class="_button" :class="$style.buttonsLeft" @click="openAccountMenu">
|
||||
<MkAvatar :class="$style.avatar" :user="$i" />
|
||||
</div>
|
||||
<div v-else-if="!thin_ && narrow && !hideTitle" :class="$style.buttonsLeft" />
|
||||
|
||||
<div :class="$style.title">
|
||||
<MkUserName v-if="metadata.userName" :user="metadata.userName" :nowrap="true"/>
|
||||
<div v-else-if="metadata.title">{{ metadata.title }}</div>
|
||||
<div v-if="!narrow && metadata.subtitle" :class="$style.subtitle">
|
||||
{{ metadata.subtitle }}
|
||||
</div>
|
||||
<div v-if="narrow && hasTabs" :class="[$style.subtitle, $style.activeTab]">
|
||||
{{ tabs.find(tab => tab.key === props.tab)?.title }}
|
||||
<i class="ti ti-chevron-down" :class="$style.chevron"></i>
|
||||
<template v-if="metadata">
|
||||
<div v-if="!hideTitle" :class="$style.titleContainer" @click="top">
|
||||
<MkAvatar v-if="metadata.avatar" :class="$style.titleAvatar" :user="metadata.avatar" indicator/>
|
||||
<i v-else-if="metadata.icon" :class="[$style.titleIcon, metadata.icon]"></i>
|
||||
|
||||
<div :class="$style.title">
|
||||
<MkUserName v-if="metadata.userName" :user="metadata.userName" :nowrap="true"/>
|
||||
<div v-else-if="metadata.title">{{ metadata.title }}</div>
|
||||
<div v-if="metadata.subtitle" :class="$style.subtitle">
|
||||
{{ metadata.subtitle }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!narrow || hideTitle" :class="$style.tabs">
|
||||
<button v-for="tab in tabs" :ref="(el) => tabRefs[tab.key] = (el as HTMLElement)" v-tooltip.noDelay="tab.title" class="_button" :class="[$style.tab, { [$style.active]: tab.key != null && tab.key === props.tab }]" @mousedown="(ev) => onTabMousedown(tab, ev)" @click="(ev) => onTabClick(tab, ev)">
|
||||
<i v-if="tab.icon" :class="[$style.tabIcon, tab.icon]"></i>
|
||||
<span v-if="!tab.iconOnly" :class="$style.tabTitle">{{ tab.title }}</span>
|
||||
</button>
|
||||
<div ref="tabHighlightEl" :class="$style.tabHighlight"></div>
|
||||
</div>
|
||||
</template>
|
||||
<div :class="$style.buttonsRight">
|
||||
<template v-for="action in actions">
|
||||
<button v-tooltip.noDelay="action.text" class="_button" :class="[$style.button, { [$style.highlighted]: action.highlighted }]" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
|
||||
<XTabs v-if="!narrow || hideTitle" :class="$style.tabs" :tab="tab" @update:tab="key => emit('update:tab', key)" :tabs="tabs" :root-el="el" @tab-click="onTabClick"/>
|
||||
</template>
|
||||
<div v-if="(!thin_ && narrow && !hideTitle) || (actions && actions.length > 0)" :class="$style.buttonsRight">
|
||||
<template v-for="action in actions">
|
||||
<button v-tooltip.noDelay="action.text" class="_button" :class="[$style.button, { [$style.highlighted]: action.highlighted }]" @click.stop="action.handler" @touchstart="preventDrag"><i :class="action.icon"></i></button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="(narrow && !hideTitle) && hasTabs" :class="[$style.lower, { [$style.slim]: narrow, [$style.thin]: thin_ }]">
|
||||
<XTabs :class="$style.tabs" :tab="tab" @update:tab="key => emit('update:tab', key)" :tabs="tabs" :root-el="el" @tab-click="onTabClick"/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, onUnmounted, ref, inject, watch, nextTick } from 'vue';
|
||||
import { onMounted, onUnmounted, ref, inject } from 'vue';
|
||||
import tinycolor from 'tinycolor2';
|
||||
import { popupMenu } from '@/os';
|
||||
import { scrollToTop } from '@/scripts/scroll';
|
||||
import { globalEvents } from '@/events';
|
||||
import { injectPageMetadata } from '@/scripts/page-metadata';
|
||||
import { $i } from '@/account';
|
||||
|
||||
type Tab = {
|
||||
key: string;
|
||||
title: string;
|
||||
icon?: string;
|
||||
iconOnly?: boolean;
|
||||
onClick?: (ev: MouseEvent) => void;
|
||||
};
|
||||
import { $i, openAccountMenu as openAccountMenu_ } from '@/account';
|
||||
import XTabs, { Tab } from './MkPageHeader.tabs.vue'
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
tabs?: Tab[];
|
||||
@@ -77,9 +66,7 @@ const metadata = injectPageMetadata();
|
||||
const hideTitle = inject('shouldOmitHeaderTitle', false);
|
||||
const thin_ = props.thin || inject('shouldHeaderThin', false);
|
||||
|
||||
const el = $shallowRef<HTMLElement | undefined>(undefined);
|
||||
const tabRefs: Record<string, HTMLElement | null> = {};
|
||||
const tabHighlightEl = $shallowRef<HTMLElement | null>(null);
|
||||
let el = $shallowRef<HTMLElement | undefined>(undefined);
|
||||
const bg = ref<string | undefined>(undefined);
|
||||
let narrow = $ref(false);
|
||||
const hasTabs = $computed(() => props.tabs.length > 0);
|
||||
@@ -88,48 +75,24 @@ const show = $computed(() => {
|
||||
return !hideTitle || hasTabs || hasActions;
|
||||
});
|
||||
|
||||
const showTabsPopup = (ev: MouseEvent) => {
|
||||
if (!hasTabs) return;
|
||||
if (!narrow) return;
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const menu = props.tabs.map(tab => ({
|
||||
text: tab.title,
|
||||
icon: tab.icon,
|
||||
active: tab.key != null && tab.key === props.tab,
|
||||
action: (ev) => {
|
||||
onTabClick(tab, ev);
|
||||
},
|
||||
}));
|
||||
popupMenu(menu, (ev.currentTarget ?? ev.target) as HTMLElement);
|
||||
};
|
||||
|
||||
const preventDrag = (ev: TouchEvent) => {
|
||||
ev.stopPropagation();
|
||||
};
|
||||
|
||||
const onClick = () => {
|
||||
const top = () => {
|
||||
if (el) {
|
||||
scrollToTop(el as HTMLElement, { behavior: 'smooth' });
|
||||
}
|
||||
};
|
||||
|
||||
function onTabMousedown(tab: Tab, ev: MouseEvent): void {
|
||||
// ユーザビリティの観点からmousedown時にはonClickは呼ばない
|
||||
if (tab.key) {
|
||||
emit('update:tab', tab.key);
|
||||
}
|
||||
function openAccountMenu(ev: MouseEvent) {
|
||||
openAccountMenu_({
|
||||
withExtraOperation: true,
|
||||
}, ev);
|
||||
}
|
||||
|
||||
function onTabClick(tab: Tab, ev: MouseEvent): void {
|
||||
if (tab.onClick) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
tab.onClick(ev);
|
||||
}
|
||||
if (tab.key) {
|
||||
emit('update:tab', tab.key);
|
||||
}
|
||||
function onTabClick(): void {
|
||||
top();
|
||||
}
|
||||
|
||||
const calcBg = () => {
|
||||
@@ -145,26 +108,10 @@ onMounted(() => {
|
||||
calcBg();
|
||||
globalEvents.on('themeChanged', calcBg);
|
||||
|
||||
watch(() => [props.tab, props.tabs], () => {
|
||||
nextTick(() => {
|
||||
const tabEl = props.tab ? tabRefs[props.tab] : undefined;
|
||||
if (tabEl && tabHighlightEl && tabEl.parentElement) {
|
||||
// offsetWidth や offsetLeft は少数を丸めてしまうため getBoundingClientRect を使う必要がある
|
||||
// https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/offsetWidth#%E5%80%A4
|
||||
const parentRect = tabEl.parentElement.getBoundingClientRect();
|
||||
const rect = tabEl.getBoundingClientRect();
|
||||
tabHighlightEl.style.width = rect.width + 'px';
|
||||
tabHighlightEl.style.left = (rect.left - parentRect.left) + 'px';
|
||||
}
|
||||
});
|
||||
}, {
|
||||
immediate: true,
|
||||
});
|
||||
|
||||
if (el && el.parentElement) {
|
||||
narrow = el.parentElement.offsetWidth < 500;
|
||||
ro = new ResizeObserver((entries, observer) => {
|
||||
if (el.parentElement && document.body.contains(el as HTMLElement)) {
|
||||
if (el && el.parentElement && document.body.contains(el as HTMLElement)) {
|
||||
narrow = el.parentElement.offsetWidth < 500;
|
||||
}
|
||||
});
|
||||
@@ -180,15 +127,35 @@ onUnmounted(() => {
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
--height: 50px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
-webkit-backdrop-filter: var(--blur, blur(15px));
|
||||
backdrop-filter: var(--blur, blur(15px));
|
||||
border-bottom: solid 0.5px var(--divider);
|
||||
contain: strict;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.upper,
|
||||
.lower {
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.upper {
|
||||
--height: 50px;
|
||||
display: flex;
|
||||
gap: var(--margin);
|
||||
height: var(--height);
|
||||
|
||||
.tabs:first-child {
|
||||
margin-left: auto;
|
||||
}
|
||||
.tabs:not(:first-child) {
|
||||
padding-left: 16px;
|
||||
mask-image: linear-gradient(90deg, rgba(0,0,0,0), rgb(0,0,0) 16px, rgb(0,0,0) 100%);
|
||||
}
|
||||
.tabs {
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
&.thin {
|
||||
--height: 42px;
|
||||
|
||||
@@ -201,30 +168,29 @@ onUnmounted(() => {
|
||||
|
||||
&.slim {
|
||||
text-align: center;
|
||||
gap: 0;
|
||||
|
||||
.tabs:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
> .titleContainer {
|
||||
flex: 1;
|
||||
margin: 0 auto;
|
||||
|
||||
> *:first-child {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
> *:last-child {
|
||||
margin-right: auto;
|
||||
}
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lower {
|
||||
--height: 40px;
|
||||
height: var(--height);
|
||||
}
|
||||
|
||||
.buttons {
|
||||
--margin: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: var(--height);
|
||||
height: var(--height);
|
||||
margin: 0 var(--margin);
|
||||
|
||||
&:empty {
|
||||
width: var(--height);
|
||||
}
|
||||
@@ -232,12 +198,12 @@ onUnmounted(() => {
|
||||
|
||||
.buttonsLeft {
|
||||
composes: buttons;
|
||||
margin-right: auto;
|
||||
margin: 0 var(--margin) 0 0;
|
||||
}
|
||||
|
||||
.buttonsRight {
|
||||
composes: buttons;
|
||||
margin-left: auto;
|
||||
margin: 0 0 0 var(--margin);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
@@ -247,15 +213,14 @@ onUnmounted(() => {
|
||||
height: $size;
|
||||
vertical-align: bottom;
|
||||
margin: 0 8px;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: calc(var(--height) - (var(--margin) * 2));
|
||||
width: calc(var(--height) - (var(--margin) * 2));
|
||||
height: var(--height);
|
||||
width: calc(var(--height) - (var(--margin)));
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
border-radius: 5px;
|
||||
@@ -278,12 +243,12 @@ onUnmounted(() => {
|
||||
.titleContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 400px;
|
||||
max-width: min(30vw, 400px);
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
flex-shrink: 0;
|
||||
flex-shrink: 1;
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
@@ -328,43 +293,4 @@ onUnmounted(() => {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabs {
|
||||
position: relative;
|
||||
margin-left: 16px;
|
||||
font-size: 0.8em;
|
||||
overflow: auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.tab {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
padding: 0 10px;
|
||||
height: 100%;
|
||||
font-weight: normal;
|
||||
opacity: 0.7;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&.active {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.tabIcon + .tabTitle {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.tabHighlight {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
height: 3px;
|
||||
background: var(--accent);
|
||||
border-radius: 999px;
|
||||
transition: all 0.2s ease;
|
||||
pointer-events: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -12,6 +12,7 @@ import MkSparkle from '@/components/MkSparkle.vue';
|
||||
import MkA from '@/components/global/MkA.vue';
|
||||
import { host } from '@/config';
|
||||
import { MFM_TAGS } from '@/scripts/mfm-tags';
|
||||
import { defaultStore } from '@/store';
|
||||
|
||||
const QUOTE_STYLE = `
|
||||
display: block;
|
||||
@@ -64,6 +65,8 @@ export default defineComponent({
|
||||
return t.match(/^[0-9.]+s$/) ? t : null;
|
||||
};
|
||||
|
||||
const useAnim = defaultStore.state.advancedMfm && defaultStore.state.animatedMfm;
|
||||
|
||||
const genEl = (ast: mfm.MfmNode[]) => ast.map((token): VNode | string | (VNode | string)[] => {
|
||||
switch (token.type) {
|
||||
case 'text': {
|
||||
@@ -102,22 +105,22 @@ export default defineComponent({
|
||||
switch (token.props.name) {
|
||||
case 'tada': {
|
||||
const speed = validTime(token.props.args.speed) ?? '1s';
|
||||
style = 'font-size: 150%;' + (this.$store.state.animatedMfm ? `animation: tada ${speed} linear infinite both;` : '');
|
||||
style = 'font-size: 150%;' + (useAnim ? `animation: tada ${speed} linear infinite both;` : '');
|
||||
break;
|
||||
}
|
||||
case 'jelly': {
|
||||
const speed = validTime(token.props.args.speed) ?? '1s';
|
||||
style = (this.$store.state.animatedMfm ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
|
||||
style = (useAnim ? `animation: mfm-rubberBand ${speed} linear infinite both;` : '');
|
||||
break;
|
||||
}
|
||||
case 'twitch': {
|
||||
const speed = validTime(token.props.args.speed) ?? '0.5s';
|
||||
style = this.$store.state.animatedMfm ? `animation: mfm-twitch ${speed} ease infinite;` : '';
|
||||
style = useAnim ? `animation: mfm-twitch ${speed} ease infinite;` : '';
|
||||
break;
|
||||
}
|
||||
case 'shake': {
|
||||
const speed = validTime(token.props.args.speed) ?? '0.5s';
|
||||
style = this.$store.state.animatedMfm ? `animation: mfm-shake ${speed} ease infinite;` : '';
|
||||
style = useAnim ? `animation: mfm-shake ${speed} ease infinite;` : '';
|
||||
break;
|
||||
}
|
||||
case 'spin': {
|
||||
@@ -130,17 +133,17 @@ export default defineComponent({
|
||||
token.props.args.y ? 'mfm-spinY' :
|
||||
'mfm-spin';
|
||||
const speed = validTime(token.props.args.speed) ?? '1.5s';
|
||||
style = this.$store.state.animatedMfm ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
|
||||
style = useAnim ? `animation: ${anime} ${speed} linear infinite; animation-direction: ${direction};` : '';
|
||||
break;
|
||||
}
|
||||
case 'jump': {
|
||||
const speed = validTime(token.props.args.speed) ?? '0.75s';
|
||||
style = this.$store.state.animatedMfm ? `animation: mfm-jump ${speed} linear infinite;` : '';
|
||||
style = useAnim ? `animation: mfm-jump ${speed} linear infinite;` : '';
|
||||
break;
|
||||
}
|
||||
case 'bounce': {
|
||||
const speed = validTime(token.props.args.speed) ?? '0.75s';
|
||||
style = this.$store.state.animatedMfm ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom;` : '';
|
||||
style = useAnim ? `animation: mfm-bounce ${speed} linear infinite; transform-origin: center bottom;` : '';
|
||||
break;
|
||||
}
|
||||
case 'flip': {
|
||||
@@ -153,17 +156,17 @@ export default defineComponent({
|
||||
}
|
||||
case 'x2': {
|
||||
return h('span', {
|
||||
class: 'mfm-x2',
|
||||
class: defaultStore.state.advancedMfm ? 'mfm-x2' : '',
|
||||
}, genEl(token.children));
|
||||
}
|
||||
case 'x3': {
|
||||
return h('span', {
|
||||
class: 'mfm-x3',
|
||||
class: defaultStore.state.advancedMfm ? 'mfm-x3' : '',
|
||||
}, genEl(token.children));
|
||||
}
|
||||
case 'x4': {
|
||||
return h('span', {
|
||||
class: 'mfm-x4',
|
||||
class: defaultStore.state.advancedMfm ? 'mfm-x4' : '',
|
||||
}, genEl(token.children));
|
||||
}
|
||||
case 'font': {
|
||||
@@ -185,11 +188,11 @@ export default defineComponent({
|
||||
}
|
||||
case 'rainbow': {
|
||||
const speed = validTime(token.props.args.speed) ?? '1s';
|
||||
style = this.$store.state.animatedMfm ? `animation: mfm-rainbow ${speed} linear infinite;` : '';
|
||||
style = useAnim ? `animation: mfm-rainbow ${speed} linear infinite;` : '';
|
||||
break;
|
||||
}
|
||||
case 'sparkle': {
|
||||
if (!this.$store.state.animatedMfm) {
|
||||
if (!useAnim) {
|
||||
return genEl(token.children);
|
||||
}
|
||||
return h(MkSparkle, {}, genEl(token.children));
|
||||
@@ -200,12 +203,17 @@ export default defineComponent({
|
||||
break;
|
||||
}
|
||||
case 'position': {
|
||||
if (!defaultStore.state.advancedMfm) break;
|
||||
const x = parseFloat(token.props.args.x ?? '0');
|
||||
const y = parseFloat(token.props.args.y ?? '0');
|
||||
style = `transform: translateX(${x}em) translateY(${y}em);`;
|
||||
break;
|
||||
}
|
||||
case 'scale': {
|
||||
if (!defaultStore.state.advancedMfm) {
|
||||
style = '';
|
||||
break;
|
||||
}
|
||||
const x = Math.min(parseFloat(token.props.args.x ?? '1'), 5);
|
||||
const y = Math.min(parseFloat(token.props.args.y ?? '1'), 5);
|
||||
style = `transform: scale(${x}, ${y});`;
|
||||
|
||||
@@ -17,6 +17,7 @@ import MkEmojiPickerWindow from '@/components/MkEmojiPickerWindow.vue';
|
||||
import MkPopupMenu from '@/components/MkPopupMenu.vue';
|
||||
import MkContextMenu from '@/components/MkContextMenu.vue';
|
||||
import { MenuItem } from '@/types/menu';
|
||||
import copyToClipboard from './scripts/copy-to-clipboard';
|
||||
|
||||
export const openingWindowsCount = ref(0);
|
||||
|
||||
@@ -26,15 +27,40 @@ export const apiWithDialog = ((
|
||||
token?: string | null | undefined,
|
||||
) => {
|
||||
const promise = api(endpoint, data, token);
|
||||
promiseDialog(promise, null, (err) => {
|
||||
promiseDialog(promise, null, async (err) => {
|
||||
let title = null;
|
||||
let text = err.message + '\n' + (err as any).id;
|
||||
if (err.code === 'RATE_LIMIT_EXCEEDED') {
|
||||
if (err.code === 'INTERNAL_ERROR') {
|
||||
title = i18n.ts.internalServerError;
|
||||
text = i18n.ts.internalServerErrorDescription;
|
||||
const date = new Date().toISOString();
|
||||
const { result } = await actions({
|
||||
type: 'error',
|
||||
title,
|
||||
text,
|
||||
actions: [{
|
||||
value: 'ok',
|
||||
text: i18n.ts.gotIt,
|
||||
primary: true,
|
||||
}, {
|
||||
value: 'copy',
|
||||
text: i18n.ts.copyErrorInfo,
|
||||
}],
|
||||
});
|
||||
if (result === 'copy') {
|
||||
copyToClipboard(`Endpoint: ${endpoint}\nInfo: ${JSON.stringify(err.info)}\nDate: ${date}`);
|
||||
success();
|
||||
}
|
||||
return;
|
||||
} else if (err.code === 'RATE_LIMIT_EXCEEDED') {
|
||||
title = i18n.ts.cannotPerformTemporary;
|
||||
text = i18n.ts.cannotPerformTemporaryDescription;
|
||||
} else if (err.code.startsWith('TOO_MANY')) {
|
||||
title = i18n.ts.youCannotCreateAnymore;
|
||||
text = `${i18n.ts.error}: ${err.id}`;
|
||||
} else if (err.message.startsWith('Unexpected token')) {
|
||||
title = i18n.ts.gotInvalidResponseError;
|
||||
text = i18n.ts.gotInvalidResponseErrorDescription;
|
||||
}
|
||||
alert({
|
||||
type: 'error',
|
||||
@@ -168,6 +194,8 @@ export function confirm(props: {
|
||||
type: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
||||
title?: string | null;
|
||||
text?: string | null;
|
||||
okText?: string;
|
||||
cancelText?: string;
|
||||
}): Promise<{ canceled: boolean }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
popup(MkDialog, {
|
||||
@@ -181,6 +209,38 @@ export function confirm(props: {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: const T extends ... にしたい
|
||||
// https://zenn.dev/general_link/articles/813e47b7a0eef7#const-type-parameters
|
||||
export function actions<T extends {
|
||||
value: string;
|
||||
text: string;
|
||||
primary?: boolean,
|
||||
}[]>(props: {
|
||||
type: 'error' | 'info' | 'success' | 'warning' | 'waiting' | 'question';
|
||||
title?: string | null;
|
||||
text?: string | null;
|
||||
actions: T;
|
||||
}): Promise<{ canceled: true; result: undefined; } | {
|
||||
canceled: false; result: T[number]['value'];
|
||||
}> {
|
||||
return new Promise((resolve, reject) => {
|
||||
popup(MkDialog, {
|
||||
...props,
|
||||
actions: props.actions.map(a => ({
|
||||
text: a.text,
|
||||
primary: a.primary,
|
||||
callback: () => {
|
||||
resolve({ canceled: false, result: a.value });
|
||||
},
|
||||
})),
|
||||
}, {
|
||||
done: result => {
|
||||
resolve(result ? result : { canceled: true });
|
||||
},
|
||||
}, 'closed');
|
||||
});
|
||||
}
|
||||
|
||||
export function inputText(props: {
|
||||
type?: 'text' | 'email' | 'password' | 'url';
|
||||
title?: string | null;
|
||||
@@ -535,3 +595,9 @@ export function checkExistence(fileData: ArrayBuffer): Promise<any> {
|
||||
});
|
||||
});
|
||||
}*/
|
||||
|
||||
export const shownNoteIds = new Set();
|
||||
|
||||
window.setInterval(() => {
|
||||
shownNoteIds.clear();
|
||||
}, 1000 * 60 * 5);
|
||||
|
||||
@@ -73,7 +73,13 @@
|
||||
</FormSection>
|
||||
<FormSection>
|
||||
<template #label><Mfm text="$[jelly ❤]"/> {{ i18n.ts._aboutMisskey.patrons }}</template>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); grid-gap: 12px;">
|
||||
<div :class="$style.patronsWithIcon">
|
||||
<div v-for="patron in patronsWithIcon" :class="$style.patronWithIcon">
|
||||
<img :src="patron.icon" :class="$style.patronIcon">
|
||||
<span :class="$style.patronName">{{ patron.name }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 16px; display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); grid-gap: 12px;">
|
||||
<div v-for="patron in patrons" :key="patron">{{ patron }}</div>
|
||||
</div>
|
||||
<p>{{ i18n.ts._aboutMisskey.morePatrons }}</p>
|
||||
@@ -99,6 +105,14 @@ import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { claimAchievement, claimedAchievements } from '@/scripts/achievements';
|
||||
import { $i } from '@/account';
|
||||
|
||||
const patronsWithIcon = [{
|
||||
name: 'カイヤン',
|
||||
icon: 'https://misskey-hub.net/patrons/a2820716883e408cb87773e377ce7c8d.jpg',
|
||||
}, {
|
||||
name: 'だれかさん',
|
||||
icon: 'https://misskey-hub.net/patrons/f7409b5e5a88477a9b9d740c408de125.jpg',
|
||||
}];
|
||||
|
||||
const patrons = [
|
||||
'まっちゃとーにゅ',
|
||||
'mametsuko',
|
||||
@@ -178,6 +192,7 @@ const patrons = [
|
||||
'蝉暮せせせ',
|
||||
'ThatOneCalculator',
|
||||
'pixeldesu',
|
||||
'あめ玉',
|
||||
];
|
||||
|
||||
let thereIsTreasure = $ref($i && !claimedAchievements.includes('foundTreasure'));
|
||||
@@ -352,4 +367,27 @@ definePageMetadata({
|
||||
.contributorUsername {
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
.patronsWithIcon {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
||||
grid-gap: 12px;
|
||||
}
|
||||
|
||||
.patronWithIcon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px;
|
||||
background: var(--buttonBg);
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.patronIcon {
|
||||
width: 24px;
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.patronName {
|
||||
margin-left: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<MkInput v-model="ad.ratio" type="number">
|
||||
<template #label>{{ i18n.ts.ratio }}</template>
|
||||
</MkInput>
|
||||
<MkInput v-model="ad.expiresAt" type="date">
|
||||
<MkInput v-model="ad.expiresAt" type="datetime-local">
|
||||
<template #label>{{ i18n.ts.expiration }}</template>
|
||||
</MkInput>
|
||||
</FormSplit>
|
||||
@@ -60,8 +60,19 @@ import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
let ads: any[] = $ref([]);
|
||||
|
||||
// ISO形式はTZがUTCになってしまうので、TZ分ずらして時間を初期化
|
||||
const localTime = new Date();
|
||||
const localTimeDiff = localTime.getTimezoneOffset() * 60 * 1000;
|
||||
|
||||
os.api('admin/ad/list').then(adsResponse => {
|
||||
ads = adsResponse;
|
||||
ads = adsResponse.map(r => {
|
||||
const date = new Date(r.expiresAt);
|
||||
date.setMilliseconds(date.getMilliseconds() - localTimeDiff);
|
||||
return {
|
||||
...r,
|
||||
expiresAt: date.toISOString().slice(0, 16),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
function add() {
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
<MkSwitch v-model="policies.rateLimitFactor.useDefault" :readonly="readonly">
|
||||
<template #label>{{ i18n.ts._role.useBaseValue }}</template>
|
||||
</MkSwitch>
|
||||
<MkRange :model-value="policies.rateLimitFactor.value * 100" :min="30" :max="300" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => policies.rateLimitFactor.value = (v / 100)">
|
||||
<MkRange :model-value="policies.rateLimitFactor.value * 100" :min="0" :max="400" :step="10" :text-converter="(v) => `${v}%`" @update:model-value="v => policies.rateLimitFactor.value = (v / 100)">
|
||||
<template #label>{{ i18n.ts._role._options.rateLimitFactor }}</template>
|
||||
<template #caption>{{ i18n.ts._role._options.descriptionOfRateLimitFactor }}</template>
|
||||
</MkRange>
|
||||
|
||||
@@ -98,6 +98,7 @@ definePageMetadata(computed(() => antenna ? {
|
||||
top: calc(var(--stickyTop, 0px) + 16px);
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
margin: calc(-0.675em - 8px - var(--margin)) 0 calc(-0.675em - 8px);
|
||||
|
||||
> button {
|
||||
display: block;
|
||||
|
||||
@@ -1,60 +1,66 @@
|
||||
<template>
|
||||
<section class="">
|
||||
<div class="">{{ $t('_auth.shareAccess', { name: app.name }) }}</div>
|
||||
<div class="">
|
||||
<h2>{{ app.name }}</h2>
|
||||
<p class="id">{{ app.id }}</p>
|
||||
<p class="description">{{ app.description }}</p>
|
||||
</div>
|
||||
<div class="">
|
||||
<h2>{{ $ts._auth.permissionAsk }}</h2>
|
||||
<ul>
|
||||
<li v-for="p in app.permission" :key="p">{{ $t(`_permissions.${p}`) }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="">
|
||||
<MkButton inline @click="cancel">{{ $ts.cancel }}</MkButton>
|
||||
<MkButton inline primary @click="accept">{{ $ts.accept }}</MkButton>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<div v-if="app.permission.length > 0">
|
||||
<p>{{ $t('_auth.permission', { name }) }}</p>
|
||||
<ul>
|
||||
<li v-for="p in app.permission" :key="p">{{ $t(`_permissions.${p}`) }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>{{ i18n.t('_auth.shareAccess', { name: `${name} (${app.id})` }) }}</div>
|
||||
<div :class="$style.buttons">
|
||||
<MkButton inline @click="cancel">{{ i18n.ts.cancel }}</MkButton>
|
||||
<MkButton inline primary @click="accept">{{ i18n.ts.accept }}</MkButton>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { } from 'vue';
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os';
|
||||
import { i18n } from '@/i18n';
|
||||
import { AuthSession } from 'misskey-js/built/entities';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MkButton,
|
||||
},
|
||||
props: ['session'],
|
||||
computed: {
|
||||
name(): string {
|
||||
const el = document.createElement('div');
|
||||
el.textContent = this.app.name;
|
||||
return el.innerHTML;
|
||||
},
|
||||
app(): any {
|
||||
return this.session.app;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
cancel() {
|
||||
os.api('auth/deny', {
|
||||
token: this.session.token,
|
||||
}).then(() => {
|
||||
this.$emit('denied');
|
||||
});
|
||||
},
|
||||
const props = defineProps<{
|
||||
session: AuthSession;
|
||||
}>();
|
||||
|
||||
accept() {
|
||||
os.api('auth/accept', {
|
||||
token: this.session.token,
|
||||
}).then(() => {
|
||||
this.$emit('accepted');
|
||||
});
|
||||
},
|
||||
},
|
||||
const emit = defineEmits<{
|
||||
(event: 'accepted'): void;
|
||||
(event: 'denied'): void;
|
||||
}>();
|
||||
|
||||
const app = $computed(() => props.session.app);
|
||||
|
||||
const name = $computed(() => {
|
||||
const el = document.createElement('div');
|
||||
el.textContent = app.name;
|
||||
return el.innerHTML;
|
||||
});
|
||||
|
||||
function cancel() {
|
||||
os.api('auth/deny', {
|
||||
token: props.session.token,
|
||||
}).then(() => {
|
||||
emit('denied');
|
||||
});
|
||||
}
|
||||
|
||||
function accept() {
|
||||
os.api('auth/accept', {
|
||||
token: props.session.token,
|
||||
}).then(() => {
|
||||
emit('accepted');
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.buttons {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,91 +1,105 @@
|
||||
<template>
|
||||
<div v-if="$i && fetching" class="">
|
||||
<MkLoading/>
|
||||
</div>
|
||||
<div v-else-if="$i">
|
||||
<XForm
|
||||
v-if="state == 'waiting'"
|
||||
ref="form"
|
||||
class="form"
|
||||
:session="session"
|
||||
@denied="state = 'denied'"
|
||||
@accepted="accepted"
|
||||
/>
|
||||
<div v-if="state == 'denied'" class="denied">
|
||||
<h1>{{ $ts._auth.denied }}</h1>
|
||||
</div>
|
||||
<div v-if="state == 'accepted'" class="accepted">
|
||||
<h1>{{ session.app.isAuthorized ? $t('already-authorized') : $ts.allowed }}</h1>
|
||||
<p v-if="session.app.callbackUrl">{{ $ts._auth.callback }}<MkEllipsis/></p>
|
||||
<p v-if="!session.app.callbackUrl">{{ $ts._auth.pleaseGoBack }}</p>
|
||||
</div>
|
||||
<div v-if="state == 'fetch-session-error'" class="error">
|
||||
<p>{{ $ts.somethingHappened }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="signin">
|
||||
<MkSignin @login="onLogin"/>
|
||||
</div>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs" /></template>
|
||||
<MkSpacer :content-max="500">
|
||||
<div v-if="state == 'fetch-session-error'">
|
||||
<p>{{ i18n.ts.somethingHappened }}</p>
|
||||
</div>
|
||||
<div v-else-if="$i && !session">
|
||||
<MkLoading />
|
||||
</div>
|
||||
<div v-else-if="$i && session">
|
||||
<XForm
|
||||
v-if="state == 'waiting'"
|
||||
class="form"
|
||||
:session="session"
|
||||
@denied="state = 'denied'"
|
||||
@accepted="accepted"
|
||||
/>
|
||||
<div v-if="state == 'denied'">
|
||||
<h1>{{ i18n.ts._auth.denied }}</h1>
|
||||
</div>
|
||||
<div v-if="state == 'accepted' && session">
|
||||
<h1>{{ session.app.isAuthorized ? $t('already-authorized') : i18n.ts.allowed }}</h1>
|
||||
<p v-if="session.app.callbackUrl">{{ i18n.ts._auth.callback }}
|
||||
<MkEllipsis />
|
||||
</p>
|
||||
<p v-if="!session.app.callbackUrl">{{ i18n.ts._auth.pleaseGoBack }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p>
|
||||
<MkSignin @login="onLogin" />
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
<script lang="ts" setup>
|
||||
import { onMounted } from 'vue';
|
||||
import XForm from './auth.form.vue';
|
||||
import MkSignin from '@/components/MkSignin.vue';
|
||||
import * as os from '@/os';
|
||||
import { login } from '@/account';
|
||||
import { $i, login } from '@/account';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { AuthSession } from 'misskey-js/built/entities';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
XForm,
|
||||
MkSignin,
|
||||
},
|
||||
props: ['token'],
|
||||
data() {
|
||||
return {
|
||||
state: null,
|
||||
session: null,
|
||||
fetching: true,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (!this.$i) return;
|
||||
const props = defineProps<{
|
||||
token: string;
|
||||
}>();
|
||||
|
||||
// Fetch session
|
||||
os.api('auth/session/show', {
|
||||
token: this.token,
|
||||
}).then(session => {
|
||||
this.session = session;
|
||||
this.fetching = false;
|
||||
let state = $ref<'waiting' | 'accepted' | 'fetch-session-error' | 'denied' | null>(null);
|
||||
let session = $ref<AuthSession | null>(null);
|
||||
|
||||
// 既に連携していた場合
|
||||
if (this.session.app.isAuthorized) {
|
||||
os.api('auth/accept', {
|
||||
token: this.session.token,
|
||||
}).then(() => {
|
||||
this.accepted();
|
||||
});
|
||||
} else {
|
||||
this.state = 'waiting';
|
||||
}
|
||||
}).catch(error => {
|
||||
this.state = 'fetch-session-error';
|
||||
this.fetching = false;
|
||||
function accepted() {
|
||||
state = 'accepted';
|
||||
if (session && session.app.callbackUrl) {
|
||||
const url = new URL(session.app.callbackUrl);
|
||||
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(url.protocol)) throw new Error('invalid url');
|
||||
location.href = `${session.app.callbackUrl}?token=${session.token}`;
|
||||
}
|
||||
}
|
||||
|
||||
function onLogin(res) {
|
||||
login(res.i);
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
if (!$i) return;
|
||||
|
||||
try {
|
||||
session = await os.api('auth/session/show', {
|
||||
token: props.token,
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
accepted() {
|
||||
this.state = 'accepted';
|
||||
if (this.session.app.callbackUrl) {
|
||||
location.href = `${this.session.app.callbackUrl}?token=${this.session.token}`;
|
||||
}
|
||||
}, onLogin(res) {
|
||||
login(res.i);
|
||||
},
|
||||
},
|
||||
|
||||
// 既に連携していた場合
|
||||
if (session.app.isAuthorized) {
|
||||
await os.api('auth/accept', {
|
||||
token: session.token,
|
||||
});
|
||||
accepted();
|
||||
} else {
|
||||
state = 'waiting';
|
||||
}
|
||||
} catch (e) {
|
||||
state = 'fetch-session-error';
|
||||
}
|
||||
});
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._auth.shareAccessTitle,
|
||||
icon: 'ti ti-apps',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
<style lang="scss" module>
|
||||
.loginMessage {
|
||||
text-align: center;
|
||||
margin: 8px 0 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,377 +0,0 @@
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader/></template>
|
||||
<MkSpacer :content-max="800">
|
||||
<div class="mwysmxbg">
|
||||
<div>{{ i18n.ts._mfm.intro }}</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.mention }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.mentionDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_mention"/>
|
||||
<MkTextarea v-model="preview_mention"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.hashtag }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.hashtagDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_hashtag"/>
|
||||
<MkTextarea v-model="preview_hashtag"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.url }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.urlDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_url"/>
|
||||
<MkTextarea v-model="preview_url"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.link }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.linkDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_link"/>
|
||||
<MkTextarea v-model="preview_link"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.emoji }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.emojiDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_emoji"/>
|
||||
<MkTextarea v-model="preview_emoji"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.bold }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.boldDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_bold"/>
|
||||
<MkTextarea v-model="preview_bold"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.small }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.smallDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_small"/>
|
||||
<MkTextarea v-model="preview_small"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.quote }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.quoteDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_quote"/>
|
||||
<MkTextarea v-model="preview_quote"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.center }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.centerDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_center"/>
|
||||
<MkTextarea v-model="preview_center"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.inlineCode }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.inlineCodeDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_inlineCode"/>
|
||||
<MkTextarea v-model="preview_inlineCode"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.blockCode }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.blockCodeDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_blockCode"/>
|
||||
<MkTextarea v-model="preview_blockCode"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- deprecated
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.search }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.searchDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_search"/>
|
||||
<MkTextarea v-model="preview_search"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.flip }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.flipDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_flip"/>
|
||||
<MkTextarea v-model="preview_flip"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.font }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.fontDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_font"/>
|
||||
<MkTextarea v-model="preview_font"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.x2 }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.x2Description }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_x2"/>
|
||||
<MkTextarea v-model="preview_x2"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.x3 }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.x3Description }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_x3"/>
|
||||
<MkTextarea v-model="preview_x3"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.x4 }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.x4Description }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_x4"/>
|
||||
<MkTextarea v-model="preview_x4"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.blur }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.blurDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_blur"/>
|
||||
<MkTextarea v-model="preview_blur"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.jelly }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.jellyDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_jelly"/>
|
||||
<MkTextarea v-model="preview_jelly"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.tada }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.tadaDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_tada"/>
|
||||
<MkTextarea v-model="preview_tada"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.jump }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.jumpDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_jump"/>
|
||||
<MkTextarea v-model="preview_jump"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.bounce }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.bounceDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_bounce"/>
|
||||
<MkTextarea v-model="preview_bounce"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.spin }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.spinDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_spin"/>
|
||||
<MkTextarea v-model="preview_spin"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.shake }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.shakeDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_shake"/>
|
||||
<MkTextarea v-model="preview_shake"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.twitch }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.twitchDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_twitch"/>
|
||||
<MkTextarea v-model="preview_twitch"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.rainbow }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.rainbowDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_rainbow"/>
|
||||
<MkTextarea v-model="preview_rainbow"><template #label>MFM</template></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.sparkle }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.sparkleDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_sparkle"/>
|
||||
<MkTextarea v-model="preview_sparkle"><span>MFM</span></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.rotate }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.rotateDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_rotate"/>
|
||||
<MkTextarea v-model="preview_rotate"><span>MFM</span></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<div class="title">{{ i18n.ts._mfm.plain }}</div>
|
||||
<div class="content">
|
||||
<p>{{ i18n.ts._mfm.plainDescription }}</p>
|
||||
<div class="preview">
|
||||
<Mfm :text="preview_plain"/>
|
||||
<MkTextarea v-model="preview_plain"><span>MFM</span></MkTextarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineComponent } from 'vue';
|
||||
import MkTextarea from '@/components/MkTextarea.vue';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import { i18n } from '@/i18n';
|
||||
import { instance } from '@/instance';
|
||||
import { customEmojis } from '@/custom-emojis';
|
||||
|
||||
let preview_mention = $ref('@example');
|
||||
let preview_hashtag = $ref('#test');
|
||||
let preview_url = $ref('https://example.com');
|
||||
let preview_link = $ref(`[${i18n.ts._mfm.dummy}](https://example.com)`);
|
||||
let preview_emoji = $ref(customEmojis.value.length ? `:${customEmojis.value[0].name}:` : ':emojiname:');
|
||||
let preview_bold = $ref(`**${i18n.ts._mfm.dummy}**`);
|
||||
let preview_small = $ref(`<small>${i18n.ts._mfm.dummy}</small>`);
|
||||
let preview_center = $ref(`<center>${i18n.ts._mfm.dummy}</center>`);
|
||||
let preview_inlineCode = $ref('`<: "Hello, world!"`');
|
||||
let preview_blockCode = $ref('```\n~ (#i, 100) {\n\t<: ? ((i % 15) = 0) "FizzBuzz"\n\t\t.? ((i % 3) = 0) "Fizz"\n\t\t.? ((i % 5) = 0) "Buzz"\n\t\t. i\n}\n```');
|
||||
let preview_quote = $ref(`> ${i18n.ts._mfm.dummy}`);
|
||||
let preview_search = $ref(`${i18n.ts._mfm.dummy} 検索`);
|
||||
let preview_jelly = $ref('$[jelly 🍮] $[jelly.speed=5s 🍮]');
|
||||
let preview_tada = $ref('$[tada 🍮] $[tada.speed=5s 🍮]');
|
||||
let preview_jump = $ref('$[jump 🍮] $[jump.speed=5s 🍮]');
|
||||
let preview_bounce = $ref('$[bounce 🍮] $[bounce.speed=5s 🍮]');
|
||||
let preview_shake = $ref('$[shake 🍮] $[shake.speed=5s 🍮]');
|
||||
let preview_twitch = $ref('$[twitch 🍮] $[twitch.speed=5s 🍮]');
|
||||
let preview_spin = $ref('$[spin 🍮] $[spin.left 🍮] $[spin.alternate 🍮]\n$[spin.x 🍮] $[spin.x,left 🍮] $[spin.x,alternate 🍮]\n$[spin.y 🍮] $[spin.y,left 🍮] $[spin.y,alternate 🍮]\n\n$[spin.speed=5s 🍮]');
|
||||
let preview_flip = $ref(`$[flip ${i18n.ts._mfm.dummy}]\n$[flip.v ${i18n.ts._mfm.dummy}]\n$[flip.h,v ${i18n.ts._mfm.dummy}]`);
|
||||
let preview_font = $ref(`$[font.serif ${i18n.ts._mfm.dummy}]\n$[font.monospace ${i18n.ts._mfm.dummy}]\n$[font.cursive ${i18n.ts._mfm.dummy}]\n$[font.fantasy ${i18n.ts._mfm.dummy}]`);
|
||||
let preview_x2 = $ref('$[x2 🍮]');
|
||||
let preview_x3 = $ref('$[x3 🍮]');
|
||||
let preview_x4 = $ref('$[x4 🍮]');
|
||||
let preview_blur = $ref(`$[blur ${i18n.ts._mfm.dummy}]`);
|
||||
let preview_rainbow = $ref('$[rainbow 🍮] $[rainbow.speed=5s 🍮]');
|
||||
let preview_sparkle = $ref('$[sparkle 🍮]');
|
||||
let preview_rotate = $ref('$[rotate 🍮]');
|
||||
let preview_plain = $ref('<plain>**bold** @mention #hashtag `code` $[x2 🍮]</plain>');
|
||||
|
||||
definePageMetadata({
|
||||
title: i18n.ts._mfm.cheatSheet,
|
||||
icon: 'ti ti-question-circle',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mwysmxbg {
|
||||
background: var(--bg);
|
||||
|
||||
> .section {
|
||||
> .title {
|
||||
position: sticky;
|
||||
z-index: 1;
|
||||
top: var(--stickyTop, 0px);
|
||||
padding: 16px;
|
||||
font-weight: bold;
|
||||
-webkit-backdrop-filter: var(--blur, blur(10px));
|
||||
backdrop-filter: var(--blur, blur(10px));
|
||||
background-color: var(--X16);
|
||||
}
|
||||
|
||||
> .content {
|
||||
> p {
|
||||
margin: 0;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
> .preview {
|
||||
border-top: solid 0.5px var(--divider);
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,41 +1,40 @@
|
||||
<template>
|
||||
<MkSpacer :content-max="800">
|
||||
<div v-if="$i">
|
||||
<div v-if="state == 'waiting'" class="waiting">
|
||||
<div class="">
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs" /></template>
|
||||
<MkSpacer :content-max="800">
|
||||
<div v-if="$i">
|
||||
<div v-if="state == 'waiting'">
|
||||
<MkLoading/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="state == 'denied'" class="denied">
|
||||
<div class="">
|
||||
<div v-if="state == 'denied'">
|
||||
<p>{{ i18n.ts._auth.denied }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="state == 'accepted'" class="accepted">
|
||||
<div class="">
|
||||
<div v-else-if="state == 'accepted'" class="accepted">
|
||||
<p v-if="callback">{{ i18n.ts._auth.callback }}<MkEllipsis/></p>
|
||||
<p v-else>{{ i18n.ts._auth.pleaseGoBack }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="">
|
||||
<div v-if="name" class="">{{ $t('_auth.shareAccess', { name: name }) }}</div>
|
||||
<div v-else class="">{{ i18n.ts._auth.shareAccessAsk }}</div>
|
||||
<div class="">
|
||||
<p>{{ i18n.ts._auth.permissionAsk }}</p>
|
||||
<ul>
|
||||
<li v-for="p in _permissions" :key="p">{{ $t(`_permissions.${p}`) }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="">
|
||||
<MkButton inline @click="deny">{{ i18n.ts.cancel }}</MkButton>
|
||||
<MkButton inline primary @click="accept">{{ i18n.ts.accept }}</MkButton>
|
||||
<div v-else>
|
||||
<div v-if="_permissions.length > 0">
|
||||
<p v-if="name">{{ $t('_auth.permission', { name }) }}</p>
|
||||
<p v-else>{{ i18n.ts._auth.permissionAsk }}</p>
|
||||
<ul>
|
||||
<li v-for="p in _permissions" :key="p">{{ $t(`_permissions.${p}`) }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="name">{{ $t('_auth.shareAccess', { name }) }}</div>
|
||||
<div v-else>{{ i18n.ts._auth.shareAccessAsk }}</div>
|
||||
<div :class="$style.buttons">
|
||||
<MkButton inline @click="deny">{{ i18n.ts.cancel }}</MkButton>
|
||||
<MkButton inline primary @click="accept">{{ i18n.ts.accept }}</MkButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="signin">
|
||||
<MkSignin @login="onLogin"/>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
<div v-else>
|
||||
<p :class="$style.loginMessage">{{ i18n.ts._auth.pleaseLogin }}</p>
|
||||
<MkSignin @login="onLogin"/>
|
||||
</div>
|
||||
</MkSpacer>
|
||||
</MkStickyContainer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -45,6 +44,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||
import * as os from '@/os';
|
||||
import { $i, login } from '@/account';
|
||||
import { i18n } from '@/i18n';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
|
||||
const props = defineProps<{
|
||||
session: string;
|
||||
@@ -54,7 +54,7 @@ const props = defineProps<{
|
||||
permission: string; // コンマ区切り
|
||||
}>();
|
||||
|
||||
const _permissions = props.permission.split(',');
|
||||
const _permissions = props.permission ? props.permission.split(',') : [];
|
||||
|
||||
let state = $ref<string | null>(null);
|
||||
|
||||
@@ -70,7 +70,7 @@ async function accept(): Promise<void> {
|
||||
state = 'accepted';
|
||||
if (props.callback) {
|
||||
const cbUrl = new URL(props.callback);
|
||||
if (!['http:', 'https:'].includes(cbUrl.protocol)) throw new Error('invalid url');
|
||||
if (['javascript:', 'file:', 'data:', 'mailto:', 'tel:'].includes(cbUrl.protocol)) throw new Error('invalid url');
|
||||
cbUrl.searchParams.set('session', props.session);
|
||||
location.href = cbUrl.href;
|
||||
}
|
||||
@@ -83,8 +83,27 @@ function deny(): void {
|
||||
function onLogin(res): void {
|
||||
login(res.i);
|
||||
}
|
||||
|
||||
const headerActions = $computed(() => []);
|
||||
|
||||
const headerTabs = $computed(() => []);
|
||||
|
||||
definePageMetadata({
|
||||
title: 'MiAuth',
|
||||
icon: 'ti ti-apps',
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style lang="scss" module>
|
||||
.buttons {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.loginMessage {
|
||||
text-align: center;
|
||||
margin: 8px 0 24px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -45,7 +45,9 @@
|
||||
|
||||
<div class="_gaps_m">
|
||||
<div class="_gaps_s">
|
||||
<MkSwitch v-model="disableAnimatedMfm">{{ i18n.ts.disableAnimatedMfm }}</MkSwitch>
|
||||
<MkSwitch v-model="collapseRenotes">{{ i18n.ts.collapseRenotes }}</MkSwitch>
|
||||
<MkSwitch v-model="advancedMfm">{{ i18n.ts.enableAdvancedMfm }}</MkSwitch>
|
||||
<MkSwitch v-if="advancedMfm" v-model="animatedMfm">{{ i18n.ts.enableAnimatedMfm }}</MkSwitch>
|
||||
<MkSwitch v-model="reduceAnimation">{{ i18n.ts.reduceUiAnimation }}</MkSwitch>
|
||||
<MkSwitch v-model="useBlurEffect">{{ i18n.ts.useBlurEffect }}</MkSwitch>
|
||||
<MkSwitch v-model="useBlurEffectForModal">{{ i18n.ts.useBlurEffectForModal }}</MkSwitch>
|
||||
@@ -138,11 +140,13 @@ async function reloadAsk() {
|
||||
|
||||
const overridedDeviceKind = computed(defaultStore.makeGetterSetter('overridedDeviceKind'));
|
||||
const serverDisconnectedBehavior = computed(defaultStore.makeGetterSetter('serverDisconnectedBehavior'));
|
||||
const collapseRenotes = computed(defaultStore.makeGetterSetter('collapseRenotes'));
|
||||
const reduceAnimation = computed(defaultStore.makeGetterSetter('animation', v => !v, v => !v));
|
||||
const useBlurEffectForModal = computed(defaultStore.makeGetterSetter('useBlurEffectForModal'));
|
||||
const useBlurEffect = computed(defaultStore.makeGetterSetter('useBlurEffect'));
|
||||
const showGapBetweenNotesInTimeline = computed(defaultStore.makeGetterSetter('showGapBetweenNotesInTimeline'));
|
||||
const disableAnimatedMfm = computed(defaultStore.makeGetterSetter('animatedMfm', v => !v, v => !v));
|
||||
const animatedMfm = computed(defaultStore.makeGetterSetter('animatedMfm'));
|
||||
const advancedMfm = computed(defaultStore.makeGetterSetter('advancedMfm'));
|
||||
const emojiStyle = computed(defaultStore.makeGetterSetter('emojiStyle'));
|
||||
const disableDrawer = computed(defaultStore.makeGetterSetter('disableDrawer'));
|
||||
const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('disableShowingAnimatedImages'));
|
||||
|
||||
@@ -62,6 +62,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
|
||||
'nsfw',
|
||||
'animation',
|
||||
'animatedMfm',
|
||||
'advancedMfm',
|
||||
'loadRawImages',
|
||||
'imageNewTab',
|
||||
'disableShowingAnimatedImages',
|
||||
|
||||
@@ -150,6 +150,8 @@ function changeAvatar(ev) {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.t('cropImageAsk'),
|
||||
okText: i18n.ts.cropYes,
|
||||
cancelText: i18n.ts.cropNo,
|
||||
});
|
||||
|
||||
if (!canceled) {
|
||||
@@ -174,6 +176,8 @@ function changeBanner(ev) {
|
||||
const { canceled } = await os.confirm({
|
||||
type: 'question',
|
||||
text: i18n.t('cropImageAsk'),
|
||||
okText: i18n.ts.cropYes,
|
||||
cancelText: i18n.ts.cropNo,
|
||||
});
|
||||
|
||||
if (!canceled) {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<MkStickyContainer>
|
||||
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
|
||||
<MkSpacer :content-max="800">
|
||||
<XPostForm
|
||||
<MkPostForm
|
||||
v-if="state === 'writing'"
|
||||
fixed
|
||||
:instant="true"
|
||||
@@ -37,17 +37,17 @@ import { i18n } from '@/i18n';
|
||||
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const localOnlyQuery = urlParams.get('localOnly');
|
||||
const visibilityQuery = urlParams.get('visibility');
|
||||
const visibilityQuery = urlParams.get('visibility') as typeof noteVisibilities[number];
|
||||
|
||||
let state = $ref('fetching' as 'fetching' | 'writing' | 'posted');
|
||||
let title = $ref(urlParams.get('title'));
|
||||
const text = urlParams.get('text');
|
||||
const url = urlParams.get('url');
|
||||
let initialText = $ref(null as string | null);
|
||||
let reply = $ref(null as Misskey.entities.Note | null);
|
||||
let renote = $ref(null as Misskey.entities.Note | null);
|
||||
let visibility = $ref(noteVisibilities.includes(visibilityQuery) ? visibilityQuery : null);
|
||||
let localOnly = $ref(localOnlyQuery === '0' ? false : localOnlyQuery === '1' ? true : null);
|
||||
let initialText = $ref<string | undefined>();
|
||||
let reply = $ref<Misskey.entities.Note | undefined>();
|
||||
let renote = $ref<Misskey.entities.Note | undefined>();
|
||||
let visibility = $ref(noteVisibilities.includes(visibilityQuery) ? visibilityQuery : undefined);
|
||||
let localOnly = $ref(localOnlyQuery === '0' ? false : localOnlyQuery === '1' ? true : undefined);
|
||||
let files = $ref([] as Misskey.entities.DriveFile[]);
|
||||
let visibleUsers = $ref([] as Misskey.entities.User[]);
|
||||
|
||||
@@ -130,7 +130,7 @@ async function init() {
|
||||
);
|
||||
}
|
||||
//#endregion
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
os.alert({
|
||||
type: 'error',
|
||||
title: err.message,
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, computed, watch } from 'vue';
|
||||
import { defineAsyncComponent, computed, watch, provide } from 'vue';
|
||||
import XTimeline from '@/components/MkTimeline.vue';
|
||||
import MkPostForm from '@/components/MkPostForm.vue';
|
||||
import { scroll } from '@/scripts/scroll';
|
||||
@@ -32,6 +32,9 @@ import { i18n } from '@/i18n';
|
||||
import { instance } from '@/instance';
|
||||
import { $i } from '@/account';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
|
||||
|
||||
provide('shouldOmitHeaderTitle', true);
|
||||
|
||||
const XTutorial = defineAsyncComponent(() => import('./timeline.tutorial.vue'));
|
||||
|
||||
@@ -55,7 +58,7 @@ function queueUpdated(q: number): void {
|
||||
}
|
||||
|
||||
function top(): void {
|
||||
scroll(rootEl, { top: 0 });
|
||||
if (rootEl) scroll(rootEl, { top: 0 });
|
||||
}
|
||||
|
||||
async function chooseList(ev: MouseEvent): Promise<void> {
|
||||
@@ -148,7 +151,7 @@ const headerTabs = $computed(() => [{
|
||||
title: i18n.ts.channel,
|
||||
iconOnly: true,
|
||||
onClick: chooseChannel,
|
||||
}]);
|
||||
}] as Tab[]);
|
||||
|
||||
const headerTabsWhenNotLogin = $computed(() => [
|
||||
...(isLocalTimelineAvailable ? [{
|
||||
@@ -163,7 +166,7 @@ const headerTabsWhenNotLogin = $computed(() => [
|
||||
icon: 'ti ti-whirl',
|
||||
iconOnly: true,
|
||||
}] : []),
|
||||
]);
|
||||
] as Tab[]);
|
||||
|
||||
definePageMetadata(computed(() => ({
|
||||
title: i18n.ts.timeline,
|
||||
@@ -177,6 +180,11 @@ definePageMetadata(computed(() => ({
|
||||
top: calc(var(--stickyTop, 0px) + 16px);
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
margin: calc(-0.675em - 8px) 0;
|
||||
|
||||
&:first-child {
|
||||
margin-top: calc(-0.675em - 8px - var(--margin));
|
||||
}
|
||||
|
||||
> button {
|
||||
display: block;
|
||||
|
||||
@@ -91,6 +91,7 @@ definePageMetadata(computed(() => list ? {
|
||||
top: calc(var(--stickyTop, 0px) + 16px);
|
||||
z-index: 1000;
|
||||
width: 100%;
|
||||
margin: calc(-0.675em - 8px - var(--margin)) 0 calc(-0.675em - 8px);
|
||||
|
||||
> button {
|
||||
display: block;
|
||||
|
||||
@@ -75,15 +75,15 @@
|
||||
</dl>
|
||||
</div>
|
||||
<div class="status">
|
||||
<MkA v-click-anime :to="userPage(user)" :class="{ active: page === 'index' }">
|
||||
<MkA v-click-anime :to="userPage(user)">
|
||||
<b>{{ number(user.notesCount) }}</b>
|
||||
<span>{{ i18n.ts.notes }}</span>
|
||||
</MkA>
|
||||
<MkA v-click-anime :to="userPage(user, 'following')" :class="{ active: page === 'following' }">
|
||||
<MkA v-click-anime :to="userPage(user, 'following')">
|
||||
<b>{{ number(user.followingCount) }}</b>
|
||||
<span>{{ i18n.ts.following }}</span>
|
||||
</MkA>
|
||||
<MkA v-click-anime :to="userPage(user, 'followers')" :class="{ active: page === 'followers' }">
|
||||
<MkA v-click-anime :to="userPage(user, 'followers')">
|
||||
<b>{{ number(user.followersCount) }}</b>
|
||||
<span>{{ i18n.ts.followers }}</span>
|
||||
</MkA>
|
||||
@@ -100,9 +100,7 @@
|
||||
<XPhotos :key="user.id" :user="user"/>
|
||||
<XActivity :key="user.id" :user="user"/>
|
||||
</template>
|
||||
</div>
|
||||
<div>
|
||||
<XUserTimeline :user="user"/>
|
||||
<XNotes :no-gap="true" :pagination="pagination"/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!narrow" class="sub _gaps" style="container-type: inline-size;">
|
||||
@@ -117,7 +115,6 @@
|
||||
import { defineAsyncComponent, computed, inject, onMounted, onUnmounted, watch } from 'vue';
|
||||
import calcAge from 's-age';
|
||||
import * as misskey from 'misskey-js';
|
||||
import XUserTimeline from './index.timeline.vue';
|
||||
import XNote from '@/components/MkNote.vue';
|
||||
import MkFollowButton from '@/components/MkFollowButton.vue';
|
||||
import MkContainer from '@/components/MkContainer.vue';
|
||||
@@ -136,6 +133,7 @@ import { i18n } from '@/i18n';
|
||||
import { $i } from '@/account';
|
||||
import { dateString } from '@/filters/date';
|
||||
import { confetti } from '@/scripts/confetti';
|
||||
import XNotes from '@/components/MkNotes.vue';
|
||||
|
||||
const XPhotos = defineAsyncComponent(() => import('./index.photos.vue'));
|
||||
const XActivity = defineAsyncComponent(() => import('./index.activity.vue'));
|
||||
@@ -152,6 +150,14 @@ let narrow = $ref<null | boolean>(null);
|
||||
let rootEl = $ref<null | HTMLElement>(null);
|
||||
let bannerEl = $ref<null | HTMLElement>(null);
|
||||
|
||||
const pagination = {
|
||||
endpoint: 'users/notes' as const,
|
||||
limit: 10,
|
||||
params: computed(() => ({
|
||||
userId: props.user.id,
|
||||
})),
|
||||
};
|
||||
|
||||
const style = $computed(() => {
|
||||
if (props.user.bannerUrl == null) return {};
|
||||
return {
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<MkStickyContainer>
|
||||
<template #header>
|
||||
<MkTab v-model="include" :class="$style.tab">
|
||||
<option :value="null">{{ i18n.ts.notes }}</option>
|
||||
<option value="replies">{{ i18n.ts.notesAndReplies }}</option>
|
||||
<option value="files">{{ i18n.ts.withFiles }}</option>
|
||||
</MkTab>
|
||||
</template>
|
||||
<XNotes :no-gap="true" :pagination="pagination"/>
|
||||
</MkStickyContainer>
|
||||
<MkSpacer :content-max="800" style="padding-top: 0">
|
||||
<MkStickyContainer>
|
||||
<template #header>
|
||||
<MkTab v-model="include" :class="$style.tab">
|
||||
<option :value="null">{{ i18n.ts.notes }}</option>
|
||||
<option value="replies">{{ i18n.ts.notesAndReplies }}</option>
|
||||
<option value="files">{{ i18n.ts.withFiles }}</option>
|
||||
</MkTab>
|
||||
</template>
|
||||
<XNotes :no-gap="true" :pagination="pagination" :class="$style.tl"/>
|
||||
</MkStickyContainer>
|
||||
</MkSpacer>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
@@ -42,4 +44,10 @@ const pagination = {
|
||||
padding: calc(var(--margin) / 2) 0;
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.tl {
|
||||
background: var(--bg);
|
||||
border-radius: var(--radius);
|
||||
overflow: clip;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<Transition name="fade" mode="out-in">
|
||||
<div v-if="user">
|
||||
<XHome v-if="tab === 'home'" :user="user"/>
|
||||
<XTimeline v-else-if="tab === 'notes'" :user="user" />
|
||||
<XActivity v-else-if="tab === 'activity'" :user="user"/>
|
||||
<XAchievements v-else-if="tab === 'achievements'" :user="user"/>
|
||||
<XReactions v-else-if="tab === 'reactions'" :user="user"/>
|
||||
@@ -20,13 +21,10 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { defineAsyncComponent, computed, inject, onMounted, onUnmounted, watch } from 'vue';
|
||||
import calcAge from 's-age';
|
||||
import { defineAsyncComponent, computed, watch } from 'vue';
|
||||
import * as Acct from 'misskey-js/built/acct';
|
||||
import * as misskey from 'misskey-js';
|
||||
import { getScrollPosition } from '@/scripts/scroll';
|
||||
import number from '@/filters/number';
|
||||
import { userPage, acct as getAcct } from '@/filters/user';
|
||||
import { acct as getAcct } from '@/filters/user';
|
||||
import * as os from '@/os';
|
||||
import { useRouter } from '@/router';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata';
|
||||
@@ -34,6 +32,7 @@ import { i18n } from '@/i18n';
|
||||
import { $i } from '@/account';
|
||||
|
||||
const XHome = defineAsyncComponent(() => import('./home.vue'));
|
||||
const XTimeline = defineAsyncComponent(() => import('./index.timeline.vue'));
|
||||
const XActivity = defineAsyncComponent(() => import('./activity.vue'));
|
||||
const XAchievements = defineAsyncComponent(() => import('./achievements.vue'));
|
||||
const XReactions = defineAsyncComponent(() => import('./reactions.vue'));
|
||||
@@ -48,8 +47,6 @@ const props = withDefaults(defineProps<{
|
||||
page: 'home',
|
||||
});
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
let tab = $ref(props.page);
|
||||
let user = $ref<null | misskey.entities.UserDetailed>(null);
|
||||
let error = $ref(null);
|
||||
@@ -74,6 +71,10 @@ const headerTabs = $computed(() => user ? [{
|
||||
key: 'home',
|
||||
title: i18n.ts.overview,
|
||||
icon: 'ti ti-home',
|
||||
}, {
|
||||
key: 'notes',
|
||||
title: i18n.ts.notes,
|
||||
icon: 'ti ti-pencil',
|
||||
}, {
|
||||
key: 'activity',
|
||||
title: i18n.ts.activity,
|
||||
|
||||
@@ -224,9 +224,6 @@ export const routes = [{
|
||||
path: '/api-console',
|
||||
component: page(() => import('./pages/api-console.vue')),
|
||||
loginRequired: true,
|
||||
}, {
|
||||
path: '/mfm-cheat-sheet',
|
||||
component: page(() => import('./pages/mfm-cheat-sheet.vue')),
|
||||
}, {
|
||||
path: '/scratchpad',
|
||||
component: page(() => import('./pages/scratchpad.vue')),
|
||||
|
||||
@@ -203,6 +203,20 @@ export function getUserMenu(user, router: Router = mainRouter) {
|
||||
action: () => {
|
||||
router.push('/user-info/' + user.id + '#moderation');
|
||||
},
|
||||
}, {
|
||||
icon: 'ti ti-badges',
|
||||
text: i18n.ts.roles,
|
||||
action: async () => {
|
||||
const roles = await os.api('admin/roles/list');
|
||||
|
||||
const { canceled, result: roleId } = await os.select({
|
||||
title: i18n.ts._role.chooseRoleToAssign,
|
||||
items: roles.map(r => ({ text: r.name, value: r.id })),
|
||||
});
|
||||
if (canceled) return;
|
||||
|
||||
await os.apiWithDialog('admin/roles/assign', { roleId, userId: user.id });
|
||||
},
|
||||
}]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||
where: 'account',
|
||||
default: false,
|
||||
},
|
||||
collapseRenotes: {
|
||||
where: 'account',
|
||||
default: true,
|
||||
},
|
||||
rememberNoteVisibility: {
|
||||
where: 'account',
|
||||
default: false,
|
||||
@@ -158,6 +162,10 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||
where: 'device',
|
||||
default: false,
|
||||
},
|
||||
advancedMfm: {
|
||||
where: 'device',
|
||||
default: true,
|
||||
},
|
||||
loadRawImages: {
|
||||
where: 'device',
|
||||
default: false,
|
||||
|
||||
@@ -127,12 +127,11 @@ hr {
|
||||
}
|
||||
|
||||
.ti {
|
||||
vertical-align: -14%;
|
||||
vertical-align: -12%;
|
||||
line-height: 1em;
|
||||
|
||||
&:before {
|
||||
display: inline-block;
|
||||
font-size: 130%;
|
||||
font-size: 128%;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user