Compare commits

...

57 Commits

Author SHA1 Message Date
944250f7fd 12.95.0 2021-10-31 20:21:42 +09:00
ab0253ab07 Update CHANGELOG.md 2021-10-31 20:21:04 +09:00
758e054c92 🎨 2021-10-31 20:19:49 +09:00
187b44c7f3 New Crowdin updates (#7913)
* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations stream.md (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations links.md (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations timeline.md (English)

* New translations pages.md (English)

* New translations timeline.md (English)

* New translations keyboard-shortcut.md (English)

* New translations theme.md (English)

* New translations theme.md (English)

* New translations ja-JP.yml (Arabic)

* New translations glossary.md (Arabic)

* New translations note.md (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations note.md (Arabic)

* New translations share-page.md (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Esperanto)

* New translations share-page.md (Esperanto)

* New translations share-page.md (Esperanto)

* New translations share-page.md (Esperanto)

* New translations share-page.md (Esperanto)

* New translations share-page.md (Esperanto)

* New translations share-page.md (Esperanto)

* New translations share-page.md (Esperanto)

* New translations custom-emoji.md (Portuguese)

* New translations theme.md (Portuguese)

* New translations widgets.md (Portuguese)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)
2021-10-31 20:17:39 +09:00
587ea5b424 Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2021-10-31 19:37:21 +09:00
1a883f4f05 fix(client): コントロールパネルのカスタム絵文字タブが切り替わらないように見える問題を修正 2021-10-31 19:37:18 +09:00
540e6e4f99 fix(client): ページ編集時のドロップダウンメニューなどが動作しない問題を修正 2021-10-31 19:35:35 +09:00
baf3d8f3ee Update emojis.vue (#7915) 2021-10-31 19:22:19 +09:00
7a66c9b5f3 chore(client): Fix #7923
Close #7924
2021-10-31 19:19:28 +09:00
15cd563612 stop context menu handling for videos (#7927) 2021-10-31 19:12:19 +09:00
e2556189de fix: 削除したノートやユーザーがリモートから参照されると復活することがあるのを修正 (#7918)
* Fix #7557

* CHANGELOG

* Fix user

* CHANGELOG

* Tune CHANGELOG

* Tune CHANGELOG

* resolver

* Remove check

* Remove import

* CHANGELOG

* Tune

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-10-31 18:01:16 +09:00
9236a8fd6c ユーザー情報のhasUnreadChannelが常にfalseになってしまっているのを修正 (#7938) 2021-10-31 16:55:25 +09:00
303c5abfb4 feat: クライアントでログインするアカウントidを指定するクエリ(loginId=:userId) (#7929)
* feat: ログインするアカウントのIDをクエリ文字列で指定する機能

* await?

* rename
2021-10-31 16:01:50 +09:00
fc65190ef7 feat: thread mute (#7930)
* feat: thread mute

* chore: fix comment

* fix test

* fix

* refactor
2021-10-31 15:30:22 +09:00
f47a564819 fix: Fix #7895 (#7937)
* Fix #7895

* CHANGELOG
2021-10-31 15:18:46 +09:00
fa0814f939 fix e2e test 2021-10-28 22:00:38 +09:00
ddd931a0a3 fix e2e test 2021-10-28 17:12:57 +09:00
46010187c3 fix e2e test 2021-10-28 16:06:06 +09:00
877bd52ed7 Update test.yml 2021-10-28 01:34:31 +09:00
d964c5f27f remove circleci configuration 2021-10-28 01:24:55 +09:00
d35b02fa23 Improve CI 2021-10-28 01:16:13 +09:00
21ece52a9f fix test 2021-10-28 00:57:49 +09:00
c2ae160d23 refactor 2021-10-27 23:42:09 +09:00
9c74c5c5dc 要らなさそう 2021-10-26 01:11:07 +09:00
2e80cebc11 Remove CircleCI configuration 2021-10-26 01:10:27 +09:00
f418eaecf9 12.94.1 2021-10-25 03:57:00 +09:00
901436a095 fix(client): ユーザーページのナビゲーションが失敗する問題を修正 2021-10-25 03:56:20 +09:00
a905188e95 12.94.0 2021-10-25 02:34:46 +09:00
a21070c01b New Crowdin updates (#7912)
* New translations ja-JP.yml (Chinese Simplified)

* New translations stream.md (Chinese Simplified)

* New translations stream.md (Chinese Simplified)
2021-10-25 02:34:29 +09:00
5d0ee544f4 chore: clean up 2021-10-25 02:30:31 +09:00
e52a9e0a65 feat(client): Improve image viewer
Resolve #7545
Resolve #6811
Close #7808
2021-10-25 02:28:18 +09:00
67bf6ff3ce 🎨 2021-10-25 00:13:54 +09:00
000bee6327 update deps 2021-10-24 21:17:20 +09:00
19a232cad7 New Crowdin updates (#7904)
* New translations ja-JP.yml (Arabic)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (French)

* New translations ja-JP.yml (Russian)

* New translations ja-JP.yml (German)

* New translations ja-JP.yml (Korean)

* New translations ja-JP.yml (Chinese Simplified)

* New translations ja-JP.yml (English)

* New translations ja-JP.yml (Indonesian)

* New translations ja-JP.yml (Esperanto)
2021-10-24 21:12:32 +09:00
a744f75eb9 Update CHANGELOG.md 2021-10-24 21:11:33 +09:00
5cf07fc50f enhance: Provide Twemoji SVGs from Misskey server (#2) (#7897)
* Selfhosting Twemoji

* ちっ

* うざっ

* あ

* add test

Co-authored-by: mei23 <m@m544.net>
2021-10-24 21:10:45 +09:00
1143606bc8 Update CHANGELOG.md 2021-10-24 21:09:24 +09:00
09f4885f89 feat(client): メンションにユーザーのアバターを表示するように
Resolve #350
2021-10-24 21:02:50 +09:00
dfd92efa89 🎨 2021-10-24 20:16:55 +09:00
c3fcfad910 🎨 2021-10-24 15:05:37 +09:00
652588abed refactor client 2021-10-24 14:50:00 +09:00
2b4d5b73b9 Update tooltip.vue 2021-10-24 14:39:24 +09:00
c08d959b59 🎨 2021-10-24 14:39:08 +09:00
7783c1e0e1 🎨 2021-10-24 13:54:31 +09:00
6afa67089a Update reactions-viewer.reaction.vue (#7909) 2021-10-24 13:28:23 +09:00
26928ab407 Remove apexcharts
Resolve #7907
2021-10-24 12:32:41 +09:00
4f04421cb3 refactor clinet 2021-10-24 04:03:07 +09:00
4d1c723496 refactor clinet 2021-10-23 23:22:20 +09:00
ae5d537197 🎨 2021-10-23 22:43:42 +09:00
2d21685d22 🎨 2021-10-23 22:41:34 +09:00
d4c0d85cbc 🎨 2021-10-23 22:09:48 +09:00
781b57585b 12.93.2 2021-10-23 11:36:39 +09:00
a0b036a119 🎨 2021-10-23 11:34:41 +09:00
c6afc61c94 fix(client): ウィジェットを追加できない問題を修正
Fix #7905
2021-10-23 11:17:41 +09:00
4168addbb2 12.93.1 2021-10-23 02:46:34 +09:00
600394458c 🎨 2021-10-23 02:45:25 +09:00
f33785a09c Fix #7902 (#7903)
* Fix #7902

* Update notification.vue

Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
2021-10-23 02:44:52 +09:00
130 changed files with 2233 additions and 1741 deletions

View File

@ -1,49 +0,0 @@
version: 2.1
executors:
docker:
working_directory: /tmp/workspace
docker:
- image: docker:latest
jobs:
docker:
parameters:
with_deploy:
type: boolean
default: false
executor: docker
steps:
- checkout
- setup_remote_docker:
version: 19.03.13
- run:
name: Build
command: |
docker build -t misskey/misskey .
- when:
condition: <<parameters.with_deploy>>
steps:
- run:
name: Deploy
command: |
if [ "$DOCKERHUB_USERNAME$DOCKERHUB_PASSWORD" ]
then
apk update && apk add jq
docker tag misskey/misskey misskey/misskey:$(cat package.json | jq -r .version)
docker login -u $DOCKERHUB_USERNAME -p $DOCKERHUB_PASSWORD
docker push -a misskey/misskey
else
echo -e '\033[0;33mAborted deploying to Docker Hub\033[0;39m'
fi
workflows:
version: 2
docker:
jobs:
- docker:
name: auto-build
with_deploy: true
filters:
branches:
only: master

View File

@ -1,12 +0,0 @@
url: 'http://misskey.local'
port: 8080
db:
host: localhost
port: 5432
db: test-misskey
user: postgres
pass: ''
redis:
host: localhost
port: 6379
id: aid

38
.github/CODEOWNERS vendored
View File

@ -1,38 +0,0 @@
# PATH OWNERS
/.autogen/ @acid-chicken
/.circleci/ @syuilo @acid-chicken
/.config/ @syuilo @AyaMorisawa @mei23 @acid-chicken @rinsuki
# /.config/mongo_initdb_example.js @khws4v1
/.github/ @syuilo @AyaMorisawa @acid-chicken
/.vscode/ @acid-chicken
/assets/ @syuilo # @tamaina
/docs/ @syuilo
/docs/*.en.md @AyaMorisawa # @skid9000
# /docs/*.fr.md @BoFFire
# /docs/docker.*.md @khws4v1
/locales/ @syuilo
/src/ @syuilo @AyaMorisawa @mei23 @acid-chicken @rinsuki
# /src/crypto_key.cc @akihikodaki
# /src/crypto_key.d.ts @akihikodaki
/.dockerignore @syuilo # @khws4v1
/.editorconfig @syuilo @AyaMorisawa
/.eslintrc @syuilo
/.gitattributes @syuilo
/.gitignore @syuilo
/.npmrc @syuilo
/.vsls.json @AyaMorisawa
/CHANGELOG.md @syuilo
/CODE_OF_CONDUCT.md @syuilo
/CONTRIBUTING.md @syuilo
/Dockerfile @syuilo @AyaMorisawa @acid-chicken # @khws4v1
/LICENSE @syuilo
/README.md @syuilo @AyaMorisawa @acid-chicken # @nikhiljha
# /binding.gyp @akihikodaki
/crowdin.yml @syuilo
# /docker-compose.yml @khws4v1
/gulpfile.ts @syuilo @AyaMorisawa
/jsconfig.json @syuilo @AyaMorisawa
/package.json @syuilo @AyaMorisawa
/tsconfig.json @syuilo @AyaMorisawa
/tslint.json @syuilo @AyaMorisawa
/webpack.config.ts @syuilo @AyaMorisawa

21
.github/workflows/lint.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Lint
on:
push:
branches:
- master
- develop
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
submodules: true
- uses: actions/setup-node@v1
with:
node-version: 12.x
- run: yarn install
- run: yarn lint

View File

@ -1,4 +1,5 @@
name: Node.js CI name: Test
on: on:
push: push:
branches: branches:
@ -7,12 +8,12 @@ on:
pull_request: pull_request:
jobs: jobs:
build_and_test: mocha:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
matrix: matrix:
node-version: [14.x, 16.x] node-version: [16.x]
services: services:
postgres: postgres:
@ -44,16 +45,43 @@ jobs:
- name: Build - name: Build
run: yarn build run: yarn build
- name: Test - name: Test
run: yarn test run: yarn mocha
lint: e2e:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy:
matrix:
node-version: [16.x]
services:
postgres:
image: postgres:12.2-alpine
ports:
- 54312:5432
env:
POSTGRES_DB: test-misskey
POSTGRES_HOST_AUTH_METHOD: trust
redis:
image: redis:4.0-alpine
ports:
- 56312:6379
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
submodules: true submodules: true
- uses: actions/setup-node@v1 - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with: with:
node-version: 12.x node-version: ${{ matrix.node-version }}
- run: yarn install - name: Install dependencies
- run: yarn lint run: yarn install
- name: Check yarn.lock
run: git diff --exit-code yarn.lock
- name: Copy Configure
run: cp test/test.yml .config
- name: Build
run: yarn build
- name: Test
run: yarn e2e

View File

@ -7,6 +7,49 @@
--> -->
## 12.95.0 (2021/10/31)
### Improvements
- スレッドミュート機能
### Bugfixes
- リレー向けのActivityが一部実装で除外されてしまうことがあるのを修正
- 削除したノートやユーザーがリモートから参照されると復活することがあるのを修正
- クライアント: ページ編集時のドロップダウンメニューなどが動作しない問題を修正
- クライアント: コントロールパネルのカスタム絵文字タブが切り替わらないように見える問題を修正
- API: ユーザー情報の hasUnreadChannel が常に false になっている問題を修正
## 12.94.1 (2021/10/25)
### Improvements
### Bugfixes
- クライアント: ユーザーページのナビゲーションが失敗する問題を修正
## 12.94.0 (2021/10/25)
### Improvements
- クライアント: 画像ビューアを強化
- クライアント: メンションにユーザーのアバターを表示するように
- クライアント: デザインの調整
- クライアント: twemojiをセルフホスティングするように
### Bugfixes
- クライアント: CWで画像が隠されたとき、画像の高さがおかしいことになる問題を修正
### NOTE
- このバージョンから、iOS 15未満のサポートがされなくなります。対象のバージョンをお使いの方は、iOSのバージョンアップを行ってください。
## 12.93.2 (2021/10/23)
### Bugfixes
- クライアント: ウィジェットを追加できない問題を修正
## 12.93.1 (2021/10/23)
### Bugfixes
- クライアント: 通知上でローカルのリアクションが表示されないのを修正
## 12.93.0 (2021/10/23) ## 12.93.0 (2021/10/23)
### Improvements ### Improvements

View File

@ -4,7 +4,6 @@
<div align="center"> <div align="center">
[![CircleCI](https://img.shields.io/circleci/project/github/misskey-dev/misskey.svg?style=for-the-badge&logo=circleci)](https://circleci.com/gh/misskey-dev/misskey)
[![Dependencies](https://img.shields.io/david/misskey-dev/misskey.svg?style=for-the-badge&logo=npm)](https://david-dm.org/misskey-dev/misskey) [![Dependencies](https://img.shields.io/david/misskey-dev/misskey.svg?style=for-the-badge&logo=npm)](https://david-dm.org/misskey-dev/misskey)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge&logo=github)](http://makeapullrequest.com) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge&logo=github)](http://makeapullrequest.com)
[![Awesome Humane Tech](https://raw.githubusercontent.com/humanetech-community/awesome-humane-tech/main/humane-tech-badge.svg?sanitize=true)](https://github.com/humanetech-community/awesome-humane-tech) [![Awesome Humane Tech](https://raw.githubusercontent.com/humanetech-community/awesome-humane-tech/main/humane-tech-badge.svg?sanitize=true)](https://github.com/humanetech-community/awesome-humane-tech)

BIN
assets/user-unknown.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,3 +1,3 @@
{ {
"baseUrl": "http://localhost" "baseUrl": "http://localhost:61812"
} }

View File

@ -128,7 +128,8 @@ describe('After user signup', () => {
cy.get('[data-cy-signin-username] input').type('alice'); cy.get('[data-cy-signin-username] input').type('alice');
cy.get('[data-cy-signin-password] input').type('alice1234{enter}'); cy.get('[data-cy-signin-password] input').type('alice1234{enter}');
cy.contains('アカウントが凍結されています'); // TODO: cypressにブラウザの言語指定できる機能が実装され次第英語のみテストするようにする
cy.contains(/アカウントが凍結されています|This account has been suspended due to/gi);
}); });
}); });

View File

@ -1,5 +1,6 @@
--- ---
_lang_: "العربية" _lang_: "العربية"
headlineMisskey: "شبكة مرتبطة بالملاحظات"
introMisskey: "اهلا بك! ميسكي هو منصة تدوين مصغر لا مركزية ومفتوحة المصدر.\nيمكنك مشاركة \"ملاحظات\" عن ما يجري حولك، وإخبار الجميع عن نفسك 📡\nتسمح لك \"الانفعالات\" بتعبير عن شعورك حول ملاحظات الآخرين 👍\nاكتشف عالمًا جديدًا 🚀" introMisskey: "اهلا بك! ميسكي هو منصة تدوين مصغر لا مركزية ومفتوحة المصدر.\nيمكنك مشاركة \"ملاحظات\" عن ما يجري حولك، وإخبار الجميع عن نفسك 📡\nتسمح لك \"الانفعالات\" بتعبير عن شعورك حول ملاحظات الآخرين 👍\nاكتشف عالمًا جديدًا 🚀"
monthAndDay: "{day}/{month}" monthAndDay: "{day}/{month}"
search: "البحث" search: "البحث"
@ -12,6 +13,7 @@ ok: " حسناً"
gotIt: "فهِمت" gotIt: "فهِمت"
cancel: " إلغاء" cancel: " إلغاء"
enterUsername: "أدخِل إسم مسخدم" enterUsername: "أدخِل إسم مسخدم"
renotedBy: "أعاد {user} نشر ملاحظة"
noNotes: "لم يتم العثور على أية ملاحظات" noNotes: "لم يتم العثور على أية ملاحظات"
noNotifications: "ليس هناك أية اشعارات" noNotifications: "ليس هناك أية اشعارات"
instance: "مثيل الخادم" instance: "مثيل الخادم"
@ -26,7 +28,7 @@ login: "لِج"
loggingIn: "جارٍ تسجيل الدخول" loggingIn: "جارٍ تسجيل الدخول"
logout: "الخروج" logout: "الخروج"
signup: "أنشئ حسابًا" signup: "أنشئ حسابًا"
uploading: "عملية الإرسال جارية" uploading: "يرفع..."
save: "حفظ" save: "حفظ"
users: "المستخدمون" users: "المستخدمون"
addUser: "اضافة مستخدم" addUser: "اضافة مستخدم"
@ -37,7 +39,7 @@ favorited: "تمت الإضافة إلى المفضلة."
alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة." alreadyFavorited: "تمت إضافته بالفعل إلى المفضلة."
cantFavorite: "تعذرت الإضافة إلى المفضلة." cantFavorite: "تعذرت الإضافة إلى المفضلة."
pin: "دبّسها على الصفحة الشخصية" pin: "دبّسها على الصفحة الشخصية"
unpin: "ألغ تثبيتها من ملفك الشخصي" unpin: "ألغ تدبيسها من ملفك الشخصي"
copyContent: "انسخ المحتوى" copyContent: "انسخ المحتوى"
copyLink: "انسخ الرابط" copyLink: "انسخ الرابط"
delete: "حذف" delete: "حذف"
@ -63,13 +65,14 @@ files: "الملفات"
download: "تنزيل" download: "تنزيل"
driveFileDeleteConfirm: "أمتأكد من حذف ملف {name}؟ كل الملاحظات المُرفق بها هذا الملف ستحذف." driveFileDeleteConfirm: "أمتأكد من حذف ملف {name}؟ كل الملاحظات المُرفق بها هذا الملف ستحذف."
unfollowConfirm: "أمتأكد من إلغاء متابعة {name}؟" unfollowConfirm: "أمتأكد من إلغاء متابعة {name}؟"
exportRequested: "قد تستغرق عملية التصدير بعض الوقت. بمجرد الانتهاء ستتم إضافة الملف الناتج إلى قرص التخزين."
importRequested: "يستغرق الاستيراد بعض الوقت" importRequested: "يستغرق الاستيراد بعض الوقت"
lists: "القوائم" lists: "القوائم"
noLists: "ليس لديك أية قائمة" noLists: "ليس لديك أية قائمة"
note: "ملاحظة" note: "ملاحظة"
notes: "الملاحظات" notes: "الملاحظات"
following: "المتابَعون" following: "المتابَعون"
followers: "المتابِعين" followers: "المتابِعون"
followsYou: "يتابعك" followsYou: "يتابعك"
createList: "إنشاء قائمة" createList: "إنشاء قائمة"
manageLists: "إدارة القوائم" manageLists: "إدارة القوائم"
@ -77,10 +80,12 @@ error: "خطأ"
somethingHappened: "حدث خطأ" somethingHappened: "حدث خطأ"
retry: "حاول مجددًا" retry: "حاول مجددًا"
pageLoadError: "فشل تحميل الصفحة" pageLoadError: "فشل تحميل الصفحة"
pageLoadErrorDescription: "عادة ما يكون السبب خطأ في الشبكة أو التخزين المؤقت للمتصفح. امسح التخزين المؤقت ثم أعد المحاولة لاحقًا."
serverIsDead: "الخادم لا يستجيب، حاول بعد قليل" serverIsDead: "الخادم لا يستجيب، حاول بعد قليل"
youShouldUpgradeClient: "حدّث الصفحة لعرضها."
enterListName: "اسم القائمة" enterListName: "اسم القائمة"
privacy: "الخصوصية" privacy: "الخصوصية"
makeFollowManuallyApprove: "القبول يدويا طلبات الإشتراك" makeFollowManuallyApprove: "قبول طلبات الإشتراك يدويا"
defaultNoteVisibility: "مدى الرؤية الافتراضي" defaultNoteVisibility: "مدى الرؤية الافتراضي"
follow: "تابِع" follow: "تابِع"
followRequest: "طلب اشتراك" followRequest: "طلب اشتراك"
@ -88,7 +93,11 @@ followRequests: "طلبات الإشتراك"
unfollow: "إلغاء الاشتراك" unfollow: "إلغاء الاشتراك"
followRequestPending: "طلبات الإشتراك المعلّقة" followRequestPending: "طلبات الإشتراك المعلّقة"
enterEmoji: "أدخل إيموجي" enterEmoji: "أدخل إيموجي"
renote: "أعد النشر"
unrenote: "إلغاء مشاركة الملاحظة" unrenote: "إلغاء مشاركة الملاحظة"
renoted: "أُعيد نشره"
cantRenote: "لا يمكن إعادة نشر الملاحظة"
cantReRenote: "لا يمكنك إعادة نشر ملاحظة معاد نشرها"
quote: "اقتبس" quote: "اقتبس"
pinnedNote: "ملاحظة مدبسة" pinnedNote: "ملاحظة مدبسة"
pinned: "دبّسها على الصفحة الشخصية" pinned: "دبّسها على الصفحة الشخصية"
@ -97,9 +106,12 @@ clickToShow: "اضغط للعرض"
sensitive: "محتوى حساس" sensitive: "محتوى حساس"
add: "إضافة" add: "إضافة"
reaction: "تفاعل" reaction: "تفاعل"
reactionSettingDescription: "اختر التفاعلات المفضلة التي تريد تثبيتها في منتقي التفاعلات."
reactionSettingDescription2: "اسحب لإعادة التنظيم ، انقر للحذف ، استخدم \"+\" للإضافة."
rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات" rememberNoteVisibility: "تذكر إعدادت مدى رؤية الملاحظات"
attachCancel: "أزل المرفق" attachCancel: "أزل المرفق"
markAsSensitive: "علّمه كمحتوى حساس" markAsSensitive: "علّمه كمحتوى حساس"
unmarkAsSensitive: "ألغ تعيينه كمحتوى حساس"
enterFileName: "ادخل اسم الملف" enterFileName: "ادخل اسم الملف"
mute: "اكتم" mute: "اكتم"
unmute: "إلغاء الكتم" unmute: "إلغاء الكتم"
@ -109,7 +121,12 @@ suspend: "علِق"
unsuspend: "ألغ التعليق" unsuspend: "ألغ التعليق"
blockConfirm: "أمتأكد من حجب هذا الحساب؟" blockConfirm: "أمتأكد من حجب هذا الحساب؟"
unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟" unblockConfirm: "أمتأكد من إلغاء حجب هذا الحساب؟"
suspendConfirm: "أمتأكد من تعليق الحساب؟"
unsuspendConfirm: "أمتأكد من إلغاء تعليق؟"
selectList: "اختر قائمة" selectList: "اختر قائمة"
selectAntenna: "اختر هوائيًا"
selectWidget: "اختر ودجة"
editWidgets: "عدّل الودجات"
editWidgetsExit: "تم" editWidgetsExit: "تم"
customEmojis: "إيموجي مخصص" customEmojis: "إيموجي مخصص"
emoji: "الوجوه التعبيرية" emoji: "الوجوه التعبيرية"
@ -119,7 +136,12 @@ emojiUrl: "رابط الوجه التعبيري"
addEmoji: "إضافة إيموجي" addEmoji: "إضافة إيموجي"
settingGuide: "الإعدادات المستحسنة" settingGuide: "الإعدادات المستحسنة"
cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة" cacheRemoteFiles: "خزن مؤقتا الملفات البعيدة"
flagAsBot: "علّمه كحساب آلي"
flagAsBotDescription: "فعّل هذا الخيار إذا كان هذا الحساب يُدار عبر برمجية. إذا فُعل فسيكون بمثابة علامة للمطورين الآخرين لتجنب سلاسل لا متناعية من التفاعل بين حسابات الآلية وضبط أنظمة ميسكي للتعامل مع هذا الحساب كروبوت."
flagAsCat: "علّم هذا الحساب كحساب قط"
flagAsCatDescription: "فعّل هذا الخيار لوضع علامة على الحساب لتوضيح أنه حساب قط."
autoAcceptFollowed: "اقبل طلبات المتابعة تلقائيا من الحسابات المتابَعة" autoAcceptFollowed: "اقبل طلبات المتابعة تلقائيا من الحسابات المتابَعة"
addAccount: "أضف حساباً"
loginFailed: "فشل الولوج" loginFailed: "فشل الولوج"
showOnRemote: "رؤيته على مثيل الخادم البُعدي" showOnRemote: "رؤيته على مثيل الخادم البُعدي"
general: "الرئيسية" general: "الرئيسية"
@ -136,8 +158,10 @@ recipient: "المرسَل إليه·ها"
annotation: "التعليقات" annotation: "التعليقات"
federation: "الفديرالية" federation: "الفديرالية"
instances: "مثيل الخادم" instances: "مثيل الخادم"
registeredAt: "مسجل في"
latestRequestSentAt: "آخر طلب أرسِل في" latestRequestSentAt: "آخر طلب أرسِل في"
latestRequestReceivedAt: "آخر طلب تُلقي في" latestRequestReceivedAt: "آخر طلب تُلقي في"
latestStatus: "الحالات الأخيرة"
storageUsage: "مساحة التخزين المستخدمة" storageUsage: "مساحة التخزين المستخدمة"
charts: "المنحنيات البيانية" charts: "المنحنيات البيانية"
perHour: "في الساعة" perHour: "في الساعة"
@ -157,6 +181,11 @@ disk: "قرص التخزين"
instanceInfo: "معلومات مثيل الخادم" instanceInfo: "معلومات مثيل الخادم"
statistics: "الإحصائيات" statistics: "الإحصائيات"
clearQueue: "تفريغ قائمة الإنتظار" clearQueue: "تفريغ قائمة الإنتظار"
clearQueueConfirmTitle: "أتريد مسح الطابور؟"
clearCachedFiles: "امسح التخزين المؤقت"
clearCachedFilesConfirm: "أتريد حذف التخزين المؤقت للملفات البعيدة؟"
blockedInstances: "المثلاء المحجوبون"
blockedInstancesDescription: "قائمة بالمثلاء التي تريد حظرها بحيث كل نطاق في سطر لوحده. بعد إدراجهم لن يتمكنوا من التفاعل مع هذا المثيل."
muteAndBlock: "تم كتمها / تم حجبها" muteAndBlock: "تم كتمها / تم حجبها"
mutedUsers: "الحسابات التي تم كتمها" mutedUsers: "الحسابات التي تم كتمها"
blockedUsers: "الحسابات التي تم حظرها" blockedUsers: "الحسابات التي تم حظرها"
@ -183,7 +212,7 @@ usernameOrUserId: "اسم المستخدم أو معرّفه"
noSuchUser: "لم يُعثَر على المستخدم" noSuchUser: "لم يُعثَر على المستخدم"
lookup: "البحث" lookup: "البحث"
announcements: "الإعلانات" announcements: "الإعلانات"
imageUrl: "عنوان URL للصورة" imageUrl: "رابط الصورة"
remove: "حذف" remove: "حذف"
removed: "تم حذفه بنجاح" removed: "تم حذفه بنجاح"
removeAreYouSure: "متأكد من أنك تريد حذف {x}؟" removeAreYouSure: "متأكد من أنك تريد حذف {x}؟"
@ -191,11 +220,11 @@ deleteAreYouSure: "متأكد من أنك تريد حذف {x}؟"
resetAreYouSure: "هل تريد إعادة التعيين؟" resetAreYouSure: "هل تريد إعادة التعيين؟"
saved: "تم حفظه" saved: "تم حفظه"
messaging: "المحادثة" messaging: "المحادثة"
upload: "تحميل" upload: "ارفع"
fromDrive: "من المخزن" fromDrive: "من المخزن"
fromUrl: "من عنوان URL" fromUrl: "عبر رابط"
uploadFromUrl: "التحميل عبر URL" uploadFromUrl: "ارفع عبر رابط"
uploadFromUrlDescription: "رابط الملف المراد تحميله " uploadFromUrlDescription: "رابط الملف المراد رفعه"
uploadFromUrlRequested: "الرفع مطلوب" uploadFromUrlRequested: "الرفع مطلوب"
uploadFromUrlMayTakeTime: "سيستغرق بعض الوقت لاتمام الرفع " uploadFromUrlMayTakeTime: "سيستغرق بعض الوقت لاتمام الرفع "
explore: "استكشاف" explore: "استكشاف"
@ -240,7 +269,7 @@ unableToDelete: "لا يمكن حذفه"
inputNewFileName: "ادخل الإسم الجديد للملف" inputNewFileName: "ادخل الإسم الجديد للملف"
inputNewFolderName: "ادخل الإسم الجديد للمجلد" inputNewFolderName: "ادخل الإسم الجديد للمجلد"
hasChildFilesOrFolders: "الان الملف غير فارغ. لا يمكن حذفه" hasChildFilesOrFolders: "الان الملف غير فارغ. لا يمكن حذفه"
copyUrl: "انسخ عنوان URL" copyUrl: "انسخ الرابط"
rename: "إعادة التسمية" rename: "إعادة التسمية"
avatar: "الصورة الرمزية" avatar: "الصورة الرمزية"
banner: "الصورة الرأسية" banner: "الصورة الرأسية"
@ -259,7 +288,7 @@ instanceName: "اسم مثيل الخادم"
instanceDescription: "وصف مثيل الخادم" instanceDescription: "وصف مثيل الخادم"
maintainerName: "المدير" maintainerName: "المدير"
maintainerEmail: "عنوان بريد المدير الإلكتروني" maintainerEmail: "عنوان بريد المدير الإلكتروني"
tosUrl: "عنوان URL لشروط الخدمة" tosUrl: "رابط صفحة شروط الخدمة"
thisYear: "هذا العام" thisYear: "هذا العام"
thisMonth: "هذا الشهر" thisMonth: "هذا الشهر"
today: "اليوم" today: "اليوم"
@ -281,10 +310,10 @@ iconUrl: "رابط الأيقونة"
bannerUrl: "رابط صورة اللافتة" bannerUrl: "رابط صورة اللافتة"
backgroundImageUrl: "رابط صورة الخلفية" backgroundImageUrl: "رابط صورة الخلفية"
basicInfo: "المعلومات الأساسية " basicInfo: "المعلومات الأساسية "
pinnedUsers: "المستخدمون المثبتون" pinnedUsers: "المستخدمون المدبسون"
pinnedUsersDescription: "قائمة المستخدمين المثبتين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده." pinnedUsersDescription: "قائمة المستخدمين المدبسين في لسان \"استكشف\" ، اجعل كل اسم مستخدم في سطر لوحده."
pinnedPages: "الصفحات المثبتة" pinnedPages: "الصفحات المدبسة"
pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تثبيتها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده." pinnedPagesDescription: "أدخل مسار الصفحات التي تريد تدبيسها في أعلى هذا الموقع، اجعل كل مسار في سطر لوحده."
pinnedNotes: "ملاحظة مدبسة" pinnedNotes: "ملاحظة مدبسة"
hcaptchaSiteKey: "مفتاح الموقع" hcaptchaSiteKey: "مفتاح الموقع"
hcaptchaSecretKey: "المفتاح السري" hcaptchaSecretKey: "المفتاح السري"
@ -302,9 +331,11 @@ withFileAntenna: "ملاحظات تحوي ملفات فقط"
caseSensitive: "حساسية حالة الأحرف" caseSensitive: "حساسية حالة الأحرف"
withReplies: "بالردود" withReplies: "بالردود"
notesAndReplies: "الملاحظات والردود" notesAndReplies: "الملاحظات والردود"
withFiles: "بالمرفقات" withFiles: "ذات مرفقات"
silence: "اكتم" silence: "اكتم"
silenceConfirm: "أمتأكد من كتم هذا المستخدم؟"
unsilence: "إلغاء الكتم" unsilence: "إلغاء الكتم"
unsilenceConfirm: "أمتأكد من إلغاء كتم هذا المستخدم؟"
popularUsers: "المستخدمون الشائعون" popularUsers: "المستخدمون الشائعون"
recentlyUpdatedUsers: "أصحاب النشاطات الأخيرة" recentlyUpdatedUsers: "أصحاب النشاطات الأخيرة"
recentlyRegisteredUsers: "المستخدمون المنضمون حديثًا" recentlyRegisteredUsers: "المستخدمون المنضمون حديثًا"
@ -331,14 +362,20 @@ newPasswordIs: "كلمتك السرية الجديدة هي {password}"
reduceUiAnimation: "قلص تأثيرات الواجهة" reduceUiAnimation: "قلص تأثيرات الواجهة"
share: "شارِك" share: "شارِك"
notFound: "غير موجود" notFound: "غير موجود"
notFoundDescription: "تعذر العثور على صفحة يقود إليها هذا الرابط."
uploadFolder: "المجلد الافتراضي للرفع"
cacheClear: "مسح ذاكرة التخزين المؤقت" cacheClear: "مسح ذاكرة التخزين المؤقت"
markAsReadAllNotifications: "وضع جميع الإشعارات كأنها مقروءة" markAsReadAllNotifications: "وضع جميع الإشعارات كأنها مقروءة"
markAsReadAllUnreadNotes: "علّم جميع الملاحظات كمقروءة"
markAsReadAllTalkMessages: "علّم جميع الرسائل كمقروءة"
help: "المساعدة" help: "المساعدة"
inputMessageHere: "اكتب رسالتك هنا" inputMessageHere: "اكتب رسالتك هنا"
close: "اغلق" close: "اغلق"
group: "الفريق" group: "الفريق"
groups: "الفِرَق" groups: "الفِرَق"
createGroup: "انشئ فريقًا" createGroup: "انشئ فريقًا"
ownedGroups: "مجموعات المالك"
joinedGroups: "المجموعات المنضم إليها"
invites: "دعوة" invites: "دعوة"
groupName: "اسم الفريق" groupName: "اسم الفريق"
members: "الأعضاء" members: "الأعضاء"
@ -352,13 +389,18 @@ next: "التالية"
retype: "أعد الكتابة" retype: "أعد الكتابة"
noteOf: "ملاحظات {user}" noteOf: "ملاحظات {user}"
inviteToGroup: "دعوة إلى فريق" inviteToGroup: "دعوة إلى فريق"
maxNoteTextLength: "حد عدد المحارف لكل ملاحظة"
quoteAttached: "اِقتُبسَ"
noMessagesYet: "ليس هناك رسائل بعد" noMessagesYet: "ليس هناك رسائل بعد"
newMessageExists: "لقد تلقيت رسالة جديدة" newMessageExists: "لقد تلقيت رسالة جديدة"
onlyOneFileCanBeAttached: "يمكنك إرفاق ملف واحد بالرسالة"
signinRequired: "رجاءً لِج"
invitations: "دعوة" invitations: "دعوة"
invitationCode: "رمز الدعوة" invitationCode: "رمز الدعوة"
checking: "التحقق جارٍ" checking: "التحقق جارٍ"
available: "متوفر" available: "متوفر"
unavailable: "غير متوفر" unavailable: "غير متوفر"
usernameInvalidFormat: "يمكنك استخدام A-z، a-z، 0-9، _"
tooShort: "قصير جدًا" tooShort: "قصير جدًا"
tooLong: "طويل جدًا" tooLong: "طويل جدًا"
weakPassword: "الكلمة السرية ضعيفة" weakPassword: "الكلمة السرية ضعيفة"
@ -367,11 +409,15 @@ strongPassword: "الكلمة السرية قوية"
passwordMatched: "التطابق صحيح!" passwordMatched: "التطابق صحيح!"
passwordNotMatched: "غير متطابقتان" passwordNotMatched: "غير متطابقتان"
signinWith: "الولوج عبر {x}" signinWith: "الولوج عبر {x}"
signinFailed: "فشل الولوج، خطأ في اسم المستخدم أو كلمة المرور."
or: "أو" or: "أو"
language: "اللغة"
uiLanguage: "لغة واجهة المستخدم" uiLanguage: "لغة واجهة المستخدم"
groupInvited: "دُعيت إلى مجموعة"
aboutX: "عن {x}" aboutX: "عن {x}"
useOsNativeEmojis: "استخدم الإيموجيات الخاصة بنظام التشغيل" useOsNativeEmojis: "استخدم الإيموجيات الخاصة بنظام التشغيل"
youHaveNoGroups: "لا تمتلك أية فِرَق" youHaveNoGroups: "لا تمتلك أية فِرَق"
joinOrCreateGroup: "احصل على دعوة لمجموعة أو أنشئ واحدة."
noHistory: "السجل فارغ" noHistory: "السجل فارغ"
signinHistory: "تاريخ تسجيل الدخول" signinHistory: "تاريخ تسجيل الدخول"
doing: "انتظر لحظة" doing: "انتظر لحظة"
@ -379,8 +425,10 @@ category: "الفئات"
tags: "الوسوم" tags: "الوسوم"
docSource: "مصدر هذا المستند" docSource: "مصدر هذا المستند"
createAccount: "أنشئ حسابًا" createAccount: "أنشئ حسابًا"
existingAccount: "الحسابات الموجودة"
regenerate: "أعِد التوليد" regenerate: "أعِد التوليد"
fontSize: "حجم الخط" fontSize: "حجم الخط"
noFollowRequests: "ليس لديك طلبات متابعة معلقة"
openImageInNewTab: "إفتح الصورة بصفحة جديدة" openImageInNewTab: "إفتح الصورة بصفحة جديدة"
dashboard: "لوحة التحكم" dashboard: "لوحة التحكم"
local: "المحلي" local: "المحلي"
@ -421,13 +469,17 @@ nothing: "لا يوجد شيء هنا"
lastUsedDate: "آخر استخدام" lastUsedDate: "آخر استخدام"
state: "الحالة" state: "الحالة"
sort: "ترتيب حسب" sort: "ترتيب حسب"
ascendingOrder: "تصاعدي"
descendingOrder: "تنازلي"
output: "الخارجة" output: "الخارجة"
updateRemoteUser: "تحديث المعلومات عن المستخدم البعيد" updateRemoteUser: "تحديث المعلومات عن المستخدم البعيد"
deleteAllFiles: "حذف كافة الملفات" deleteAllFiles: "حذف كافة الملفات"
deleteAllFilesConfirm: "أتريد حذف كل الملفات؟" deleteAllFilesConfirm: "أتريد حذف كل الملفات؟"
removeAllFollowing: "ألغ متابعة كل المتابِعين" removeAllFollowing: "ألغ متابعة كل المتابَعين"
userSuspended: "تم تعليق هذا المستخدم." userSuspended: "تم تعليق هذا المستخدم."
userSilenced: "تم إسكات هذا المستخدم." userSilenced: "تم إسكات هذا المستخدم."
yourAccountSuspendedTitle: "هذا الحساب معلق"
menu: "القائمة"
addItem: "إضافة عنصر" addItem: "إضافة عنصر"
rooms: "الغرفة" rooms: "الغرفة"
relays: "المُرَحلات" relays: "المُرَحلات"
@ -435,9 +487,15 @@ addRelay: "إضافة مُرحّل"
addedRelays: "المرحلات التي تم إضافتها" addedRelays: "المرحلات التي تم إضافتها"
deletedNote: "ملاحظة محذوفة" deletedNote: "ملاحظة محذوفة"
invisibleNote: "ملاحظة مخفية" invisibleNote: "ملاحظة مخفية"
enableInfiniteScroll: "فعّل التمرير المتواصل"
visibility: "الظهور"
poll: "استطلاع رأي" poll: "استطلاع رأي"
useCw: "إخفاء المحتوى" useCw: "إخفاء المحتوى"
enablePlayer: "افتح مشغل الفيديو"
disablePlayer: "أغلق مشغل الفيديو"
themeEditor: "مصمم القوالب" themeEditor: "مصمم القوالب"
description: "الوصف"
leaveConfirm: "لديك تغييرات غير محفوظة. أتريد المتابعة دون حفظها؟"
manage: "إدارة " manage: "إدارة "
plugins: "الإضافات" plugins: "الإضافات"
width: "العرض" width: "العرض"
@ -445,12 +503,14 @@ height: "الإرتفاع"
large: "كبير" large: "كبير"
medium: "متوسط" medium: "متوسط"
small: "صغير" small: "صغير"
generateAccessToken: "ولّد رمز الوصول"
permission: "أذونات" permission: "أذونات"
enableAll: "تشغيل الكل" enableAll: "تشغيل الكل"
disableAll: "تعطيل الكل" disableAll: "تعطيل الكل"
tokenRequested: "منح حق الوصول إلى الحساب" tokenRequested: "منح حق الوصول إلى الحساب"
notificationType: "أنواع الإشعارات" notificationType: "أنواع الإشعارات"
edit: "التعديل" edit: "التعديل"
emailServer: "خادم البريد الإلكتروني"
email: "البريد الإلكتروني " email: "البريد الإلكتروني "
emailAddress: "عنوان البريد الالكتروني" emailAddress: "عنوان البريد الالكتروني"
smtpHost: "المضيف" smtpHost: "المضيف"
@ -461,6 +521,12 @@ makeActive: "تفعيل"
display: "المظهر" display: "المظهر"
copy: "نسخ" copy: "نسخ"
metrics: "المقاييس" metrics: "المقاييس"
channel: "القنوات"
create: "أنشئ"
notificationSetting: "إعدادات التنبيهات"
notificationSettingDesc: "اختر نوع التنبيهات المراد عرضها"
other: "منوعات"
regenerateLoginToken: "أعد توليد الرمز"
fileIdOrUrl: "معرف الملف أو رابط" fileIdOrUrl: "معرف الملف أو رابط"
chatOpenBehavior: "سلوك نفاذة المحادثة عند فتحها" chatOpenBehavior: "سلوك نفاذة المحادثة عند فتحها"
behavior: "السلوك" behavior: "السلوك"
@ -468,7 +534,7 @@ sample: "مثال"
abuseReports: "البلاغات" abuseReports: "البلاغات"
reportAbuse: "البلاغات" reportAbuse: "البلاغات"
reportAbuseOf: "أبلغ عن {name}" reportAbuseOf: "أبلغ عن {name}"
fillAbuseReportDescription: "أكتب بالتفصيل سبب الإبلاغ، إذا كنت تبلغ عن ملاحظة أرفق رابط لها." fillAbuseReportDescription: "أكتب بالتفصيل سبب البلاغ، إذا كنت تبلغ عن ملاحظة أرفق رابط لها."
abuseReported: "أُرسل البلاغ، شكرًا لك" abuseReported: "أُرسل البلاغ، شكرًا لك"
send: "أرسل" send: "أرسل"
abuseMarkAsResolved: "علّم البلاغ كمحلول" abuseMarkAsResolved: "علّم البلاغ كمحلول"
@ -486,7 +552,9 @@ manageAccessTokens: "إدارة رموز الوصول"
accountInfo: "معلومات الحساب" accountInfo: "معلومات الحساب"
notesCount: "عدد الملاحظات" notesCount: "عدد الملاحظات"
repliesCount: "عدد الردود المرسلة" repliesCount: "عدد الردود المرسلة"
renotesCount: "عدد الملاحظات المعاد نشرها (المرسلة)"
repliedCount: "عدد الردود المستلمة" repliedCount: "عدد الردود المستلمة"
renotedCount: "عدد الملاحظات المعاد نشرها (المستلمة)"
followingCount: "عدد الحسابات المتابَعة" followingCount: "عدد الحسابات المتابَعة"
followersCount: "عدد المتابِعين" followersCount: "عدد المتابِعين"
sentReactionsCount: "عدد الانفعالات المرسلة" sentReactionsCount: "عدد الانفعالات المرسلة"
@ -495,32 +563,141 @@ pollVotesCount: "عدد الاستطلاعات المرسلة"
pollVotedCount: "عدد الاستطلاعات المستلمة" pollVotedCount: "عدد الاستطلاعات المستلمة"
yes: "نعم" yes: "نعم"
no: "لا" no: "لا"
driveFilesCount: "عدد الملفات في قرص التخزين"
useSystemFont: "استخدم الخط الافتراضية للنظام"
experimentalFeatures: "ميّزات اختبارية"
developer: "المطور"
clearCache: "امسح التخزين المؤقت"
currentVersion: "الإصدار الحالي" currentVersion: "الإصدار الحالي"
latestVersion: "آخر نسخة مستقرة" latestVersion: "آخر نسخة مستقرة"
usageAmount: "الإستخدام" usageAmount: "الإستخدام"
capacity: "السعة" capacity: "السعة"
inUse: "مستخدم" inUse: "مستخدم"
useReactionPickerForContextMenu: "افتح منتقي التفاعلات عند التقر بالزر الأيمن"
typingUsers: "{users} يكتب(ون)..."
jumpToSpecifiedDate: "انتقل إلى التاريخ المحدد"
showingPastTimeline: "أنت تستعرض حاليًا خيطًا زمنيًا قديمًا"
markAllAsRead: "علّم الكل كمقروء"
goBack: "رجوع"
unlikeConfirm: "أتريد إلغاء إعجابك؟"
fullView: "ملء الشاشة"
quitFullView: "اخرج من وضع ملء للشاشة"
addDescription: "أضف وصفًا"
info: "عن" info: "عن"
userInfo: "معلومات المستخدم"
unknown: "مجهول"
onlineStatus: "الحالة"
hideOnlineStatus: "اخف الحالة"
online: "متصل"
active: "نشط"
offline: "غير متصل"
notRecommended: "غير مستحسن"
botProtection: "الحماية من الحسابات الآلية"
instanceBlocking: "المثيلات المحجوبة"
selectAccount: "اختر حسابًا"
enabled: "مفعّل"
disabled: "معطّل"
quickAction: "الإجراءات السّريعة"
user: "المستخدمون" user: "المستخدمون"
administration: "إدارة " administration: "إدارة "
accounts: "الحسابات"
switch: "بدّل"
noBotProtectionWarning: "لم تضبط الحماية من الحسابات الآلية"
configure: "اضبط"
postToGallery: "انشر في المعرض" postToGallery: "انشر في المعرض"
gallery: "المعرض" gallery: "المعرض"
recentPosts: "المشاركات الحديثة"
shareWithNote: "شاركه في ملاحظة"
ads: "الإعلانات"
expiration: "ينتهي استطلاع الرأي في" expiration: "ينتهي استطلاع الرأي في"
priority: "الأولوية"
high: "عالية"
middle: "متوسط" middle: "متوسط"
low: "منخفضة"
emailNotConfiguredWarning: "لم تعيّن بريدًا إلكترونيًا"
ratio: "النسبة"
previewNoteText: "اعرض معاينة"
customCss: "CSS مخصصة"
global: "الشامل" global: "الشامل"
squareAvatars: "اعرض شكل الصور الرمزية كمربعات"
sent: "أرسل" sent: "أرسل"
received: "اُستلم"
searchResult: "نتائج البحث"
hashtags: "الوسوم"
learnMore: "راجع المزيد"
misskeyUpdated: "حُدث ميسكي!"
whatIsNew: "اعرض التغييرات"
translate: "ترجم"
translatedFrom: "تُرجم من {x}"
accountDeletionInProgress: "حذف الحساب جارٍ"
usernameInfo: "الاسم الذي يميزك عن بافي مستخدمي هذا الخادم، يمكنك استخدام الحروف اللاتينية (a~z, A~Z) والأرقام (0~9) والشرطة السفلية (_). لا يمكنك تغييره بعد تسجيله."
lastCommunication: "آخر تواصل"
itsOn: "مفعّل"
itsOff: "معطّل"
emailRequiredForSignup: "عنوان البريد الإلكتروني إلزامي للتسجيل"
filter: "رشّح"
controlPanel: "لوحة التحكم"
manageAccounts: "إدارة الحسابات"
makeReactionsPublic: "اجعل سجل التفاعلات علنيًا"
makeReactionsPublicDescription: "هذا سيجعل قائمة تفاعلاتك مرئية للعلن."
classic: "تقليدي"
_docs: _docs:
admin: "إدارة " admin: "إدارة "
_gallery:
unlike: "أزل الإعجاب"
_email: _email:
_follow: _follow:
title: "يتابعك" title: "يتابعك"
_registry:
keys: "المفاتيح"
domain: "النّطاق"
createKey: "أنشئ مفتاحًا"
_aboutMisskey:
about: "ميسكي هو برمجية مفتوحة المصدر يطورها syuilo منذ 2014."
contributors: "المساهم الرئيسي"
allContributors: "كل المساهمين"
source: "الشفرة المصدرية"
translation: "ترجم ميسكي"
donate: "تبرع لميسكي"
morePatrons: "نحن نقدر الدعم الذي قدمه العديد من الأشخاص الذين لم نذكرهم. شكرًا لكم 🥰"
patrons: "الداعمون"
_nsfw:
force: "اخف كل الوسائط"
_mfm: _mfm:
mention: "أشر الى" mention: "أشر الى"
hashtag: "الوسوم"
url: "الرابط"
urlDescription: "يمكن عرض الروابط"
link: "رابط"
bold: "عريض"
small: "صغير"
quote: "اقتبس" quote: "اقتبس"
emoji: "إيموجي مخصص" emoji: "إيموجي مخصص"
search: "البحث" search: "البحث"
_reversi: _reversi:
gameSettings: "إعدادات اللعبة"
chooseBoard: "اختر اللوح"
blackOrWhite: "أسود/أبيض"
blackIs: "{name} سيلعب بالأسود"
botSettings: "خيارات الحسابات الآلية"
waitingBoth: "استعد"
ready: "جاهز"
cancelReady: "ألغ الجهوزية"
opponentTurn: "دور الخصم"
myTurn: "دورك"
turnOf: "دور {name}"
pastTurnOf: "دور {name}"
surrender: "استسلم"
drawn: "تعادل"
won: "فاز {name}"
black: "أسود"
white: "أبيض"
total: "المجموع" total: "المجموع"
turnCount: "الدور {count}"
myGames: "جولاتي"
allGames: "كل الجولات"
ended: "انتهت"
playing: "يُلعب الآن"
_channel: _channel:
featured: "المتداوَلة" featured: "المتداوَلة"
_menuDisplay: _menuDisplay:
@ -530,11 +707,15 @@ _theme:
install: "تنصيب قالب" install: "تنصيب قالب"
manage: "إدارة القوالب" manage: "إدارة القوالب"
code: "شيفرة القالب" code: "شيفرة القالب"
description: "الوصف"
installed: "تم تنصيب {name}" installed: "تم تنصيب {name}"
make: "إنشاء قالب" make: "إنشاء قالب"
alpha: "الشفافية" alpha: "الشفافية"
keys: keys:
link: "رابط"
hashtag: "وسم"
mention: "أشر الى" mention: "أشر الى"
renote: "أعد النشر"
messageBg: "خلفية المحادثة" messageBg: "خلفية المحادثة"
_sfx: _sfx:
note: "الملاحظات" note: "الملاحظات"
@ -560,11 +741,35 @@ _time:
_tutorial: _tutorial:
title: "كيف تستخدم Misskey" title: "كيف تستخدم Misskey"
step1_1: "مرحبًا!" step1_1: "مرحبًا!"
step1_2: "تدعى هذه الصفحة 'الخيط الزمني' وهي تحوي ملاحظات الأشخاص الذي تتابعهم مرتبة حسب تاريخ نشرها."
step1_3: "خيطك الزمني فارغ حاليًا بما أنك لا تتابع أي شخص ولم تنشر أي ملاحظة."
step2_1: "لننهي إعداد ملفك الشخصي قبل كتابة ملاحظة أو متابعة أشخاص."
step3_1: "هل أنهيت إعداد حسابك؟"
step3_2: "إذا تاليًا للنشر ملاحظة. أنقر على أيقونة القلم في أعلى الشاشة"
step5_3: "لمتابعة مستخدمين ادخل ملفهم الشخصي بالنقر على صورتهم الشخصية ثم اضغط زر 'تابع'."
_2fa: _2fa:
registerKey: "تسجيل مفتاح أمان جديد" registerKey: "تسجيل مفتاح أمان جديد"
_permissions: _permissions:
"read:account": "اعرض معلومات حسابك"
"write:account": "تعديل معلومات حسابك" "write:account": "تعديل معلومات حسابك"
"read:blocks": "اعرض قائمة المستخدمين المحجوبين"
"write:blocks": "عدّل قائمة المستخدمين المحجوبين"
"read:drive": "تصفح قرص التخزين"
"write:drive": "احذف أو عدّل محتويات قرص التخزين"
"read:favorites": "اعرض المفضلة"
"write:favorites": "عدّل المفضلة"
"read:notifications": "اظهر الإشعارات" "read:notifications": "اظهر الإشعارات"
"read:reactions": "اعرض تفاعلاتك"
"write:reactions": "عدّل تفاعلاتك"
"write:votes": "صوّت"
"read:pages": "اعرض صفحاتك"
"write:pages": "عدّل أو احذف صفحاتك"
"read:user-groups": "اعرض مجموعات المستخدمين"
"write:user-groups": "عدّل أو احذف مجموعات المستخدمين"
"read:gallery": "اعرض المعرض"
"write:gallery": "عدّل المعرض"
_auth:
shareAccess: "أتريد التفويض لـ \"{name}\" بالوصول لحسابك؟"
_weekday: _weekday:
sunday: "الأحد" sunday: "الأحد"
monday: "الإثنين" monday: "الإثنين"
@ -615,39 +820,74 @@ _poll:
_visibility: _visibility:
public: "للعامة" public: "للعامة"
home: "الرئيسي" home: "الرئيسي"
followers: "المتابِعين" followers: "المتابِعون"
specified: "مباشرة" specified: "مباشرة"
localOnly: "المحلي فقط" localOnly: "المحلي فقط"
_postForm: _postForm:
replyPlaceholder: "رد على هذه الملاحظة…" replyPlaceholder: "رد على هذه الملاحظة…"
quotePlaceholder: "اقتبس هذه الملاحظة…" quotePlaceholder: "اقتبس هذه الملاحظة…"
channelPlaceholder: "انشر في قناة..."
_placeholders:
c: "ما الذي تفكر فيه؟"
d: "ما الذي تريد قوله؟"
e: "أكتب..."
_profile: _profile:
name: "الإسم" name: "الإسم"
username: "اسم المستخدم" username: "اسم المستخدم"
description: "السيرة"
youCanIncludeHashtags: "يمكنك أيضًا إضافة وسوم إلى نبذتك التعريفية." youCanIncludeHashtags: "يمكنك أيضًا إضافة وسوم إلى نبذتك التعريفية."
metadata: "معلومات إضافية"
metadataEdit: "عدّل المعلومات الإضافية"
metadataDescription: "يُمكنك عرض 4 حقول معلومات في ملفك الشخصي"
metadataLabel: "التسمية"
metadataContent: "المحتوى"
changeAvatar: "غيّر الصورة الرمزية"
changeBanner: "غيّر اللافتة"
_exportOrImport: _exportOrImport:
allNotes: "كل الملاحظات" allNotes: "كل الملاحظات"
followingList: "المتابَعون" followingList: "المتابَعون"
muteList: "اكتم" muteList: "المستخدمون المكتومون"
blockingList: "احجب" blockingList: "المستخدمون المحجوبون"
userLists: "القوائم" userLists: "القوائم"
_charts: _charts:
usersTotal: "مجموع عدد المستخدمين والمستخدمات" usersTotal: "مجموع عدد المستخدمين والمستخدمات"
activeUsers: "المستخدمون النشطون" activeUsers: "المستخدمون النشطون"
notesTotal: "إجمالي الملاحظات"
_timelines: _timelines:
home: "الرئيسي" home: "الرئيسي"
local: "المحلي" local: "المحلي"
social: "الاجتماعي" social: "الاجتماعي"
global: "الشامل" global: "الشامل"
_rooms: _rooms:
leaveConfirm: "لديك تغييرات غير محفوظة. أتريد المتابعة دون حفظها؟"
chooseImage: "اختر صورة"
roomType: "نوع الغرفة"
_roomType: _roomType:
default: "افتراضي" default: "افتراضي"
washitsu: "الأسلوب الياباني"
_furnitures: _furnitures:
milk: "علبة حليب"
bed: "سرير"
low-table: "طاولة قصيرة"
desk: "مكتب"
chair: "كرسي"
chair2: "كرسي 2"
pc: "حاسوب"
monitor: "شاشة التحكم" monitor: "شاشة التحكم"
banknote: "أوراق نقدية" banknote: "أوراق نقدية"
_pages: _pages:
viewPage: "اعرض صفحاتك"
like: "أعجبني"
unlike: "أزل الإعجاب"
my: "صفحاتي"
blocks: blocks:
image: "الصور" image: "الصور"
_post:
text: "المحتوى"
_button:
_action:
_dialog:
content: "المحتوى"
script: script:
categories: categories:
list: "القوائم" list: "القوائم"
@ -676,9 +916,11 @@ _notification:
youGotMessagingMessageFromUser: "لقد تلقيت رسالة مِن {name}" youGotMessagingMessageFromUser: "لقد تلقيت رسالة مِن {name}"
youGotMessagingMessageFromGroup: "لقد أرسِلَت رسالة إلى الفريق {name}" youGotMessagingMessageFromGroup: "لقد أرسِلَت رسالة إلى الفريق {name}"
youWereFollowed: "يتابعك" youWereFollowed: "يتابعك"
youWereInvitedToGroup: "دُعيت إلى مجموعة"
_types: _types:
follow: "المتابَعون" follow: "المتابَعون"
mention: "أشر الى" mention: "أشر الى"
renote: "أعد النشر"
quote: "اقتبس" quote: "اقتبس"
reaction: "تفاعل" reaction: "تفاعل"
_deck: _deck:

View File

@ -795,10 +795,12 @@ itsOff: "Ausgeschaltet"
emailRequiredForSignup: "Angaben einer Email-Adresse als benötigt markieren" emailRequiredForSignup: "Angaben einer Email-Adresse als benötigt markieren"
unread: "Ungelesen" unread: "Ungelesen"
filter: "Filter" filter: "Filter"
controllPanel: "Systemsteuerung"
manageAccounts: "Benutzerkonten verwalten" manageAccounts: "Benutzerkonten verwalten"
makeReactionsPublic: "Reaktionsverlauf veröffentlichen" makeReactionsPublic: "Reaktionsverlauf veröffentlichen"
makeReactionsPublicDescription: "Jeder wird die Liste deiner gesendeten Reaktionen einsehen können." makeReactionsPublicDescription: "Jeder wird die Liste deiner gesendeten Reaktionen einsehen können."
classic: "Classic"
muteThread: "Thread stummschalten"
unmuteThread: "Threadstummschaltung aufheben"
_signup: _signup:
almostThere: "Fast geschafft" almostThere: "Fast geschafft"
emailAddressInfo: "Bitte gib deine Email-Adresse ein." emailAddressInfo: "Bitte gib deine Email-Adresse ein."

View File

@ -795,10 +795,13 @@ itsOff: "Disabled"
emailRequiredForSignup: "Require email address for sign-up" emailRequiredForSignup: "Require email address for sign-up"
unread: "Unread" unread: "Unread"
filter: "Filter" filter: "Filter"
controllPanel: "Control Panel" controlPanel: "Control Panel"
manageAccounts: "Manage Accounts" manageAccounts: "Manage Accounts"
makeReactionsPublic: "Set reaction history to public" makeReactionsPublic: "Set reaction history to public"
makeReactionsPublicDescription: "This will make the list of all your past reactions publicly visible." makeReactionsPublicDescription: "This will make the list of all your past reactions publicly visible."
classic: "Classic"
muteThread: "Mute thread"
unmuteThread: "Unmute thread"
_signup: _signup:
almostThere: "Almost there" almostThere: "Almost there"
emailAddressInfo: "Please enter your email address." emailAddressInfo: "Please enter your email address."

View File

@ -542,7 +542,8 @@ troubleshooting: "Problemsolvi"
learnMore: "Lernu pli" learnMore: "Lernu pli"
translate: "Traduki" translate: "Traduki"
translatedFrom: "Tradukita el {x}" translatedFrom: "Tradukita el {x}"
controllPanel: "Ŝaltpodio" controlPanel: "Ŝaltpodio"
classic: "Klasika"
_docs: _docs:
continueReading: "Legi plu" continueReading: "Legi plu"
features: "Funkcioj" features: "Funkcioj"

View File

@ -795,7 +795,7 @@ itsOff: "Désactivé"
emailRequiredForSignup: "Une adresse e-mail est nécessaire pour créer un compte" emailRequiredForSignup: "Une adresse e-mail est nécessaire pour créer un compte"
unread: "Non lu" unread: "Non lu"
filter: "Filtre" filter: "Filtre"
controllPanel: "Panneau de contrôle" controlPanel: "Panneau de contrôle"
manageAccounts: "Gérer les comptes" manageAccounts: "Gérer les comptes"
_signup: _signup:
almostThere: "Bientôt fini" almostThere: "Bientôt fini"

View File

@ -780,7 +780,7 @@ translatedFrom: "Terjemahkan dari {x}"
accountDeletionInProgress: "Penghapusan akun sedang dalam proses" accountDeletionInProgress: "Penghapusan akun sedang dalam proses"
usernameInfo: "Nama yang mengidentifikasikan akun kamu dari yang lain pada server ini. Kamu dapat menggunakan alfabet (a~z, A~Z), digit (0~9) atau garis bawah (_). Username tidak dapat diubah setelahnya." usernameInfo: "Nama yang mengidentifikasikan akun kamu dari yang lain pada server ini. Kamu dapat menggunakan alfabet (a~z, A~Z), digit (0~9) atau garis bawah (_). Username tidak dapat diubah setelahnya."
keepCw: "Biarkan Peringatan Konten" keepCw: "Biarkan Peringatan Konten"
controllPanel: "Panel kontrol" controlPanel: "Panel kontrol"
_accountDelete: _accountDelete:
accountDelete: "Hapus akun" accountDelete: "Hapus akun"
mayTakeTime: "Karena penghapusan akun merupakan proses yang berat dan intensif, kemungkinan dapat membutuhkan waktu untuk menyelesaikan tergantung daripada berapa banyak konten yang kamu buat dan berapa banyak berkas yang telah kamu unggah." mayTakeTime: "Karena penghapusan akun merupakan proses yang berat dan intensif, kemungkinan dapat membutuhkan waktu untuk menyelesaikan tergantung daripada berapa banyak konten yang kamu buat dan berapa banyak berkas yang telah kamu unggah."

View File

@ -795,10 +795,13 @@ itsOff: "オフになっています"
emailRequiredForSignup: "アカウント登録にメールアドレスを必須にする" emailRequiredForSignup: "アカウント登録にメールアドレスを必須にする"
unread: "未読" unread: "未読"
filter: "フィルタ" filter: "フィルタ"
controllPanel: "コントロールパネル" controlPanel: "コントロールパネル"
manageAccounts: "アカウントを管理" manageAccounts: "アカウントを管理"
makeReactionsPublic: "リアクション一覧を公開する" makeReactionsPublic: "リアクション一覧を公開する"
makeReactionsPublicDescription: "あなたがしたリアクション一覧を誰でも見れるようにします。" makeReactionsPublicDescription: "あなたがしたリアクション一覧を誰でも見れるようにします。"
classic: "クラシック"
muteThread: "スレッドをミュート"
unmuteThread: "スレッドのミュートを解除"
_signup: _signup:
almostThere: "ほとんど完了です" almostThere: "ほとんど完了です"

View File

@ -787,7 +787,7 @@ pubSub: "Pub/Sub 계정"
lastCommunication: "마지막 통신" lastCommunication: "마지막 통신"
resolved: "해결됨" resolved: "해결됨"
unresolved: "해결되지 않음" unresolved: "해결되지 않음"
controllPanel: "제어판" controlPanel: "제어판"
_accountDelete: _accountDelete:
accountDelete: "계정 삭제" accountDelete: "계정 삭제"
mayTakeTime: "계정 삭제는 서버에 부하를 가하기 때문에, 작성한 콘텐츠나 업로드한 파일의 수가 많으면 완료까지 시간이 걸릴 수 있습니다." mayTakeTime: "계정 삭제는 서버에 부하를 가하기 때문에, 작성한 콘텐츠나 업로드한 파일의 수가 많으면 완료까지 시간이 걸릴 수 있습니다."

View File

@ -784,7 +784,7 @@ accountDeletionInProgress: "В настоящее время выполняет
usernameInfo: "Имя, которое отличает вашу учетную запись от других на этом сервере. Вы можете использовать алфавит (a~z, A~Z), цифры (0~9) или символы подчеркивания (_). Имена пользователей не могут быть изменены позже." usernameInfo: "Имя, которое отличает вашу учетную запись от других на этом сервере. Вы можете использовать алфавит (a~z, A~Z), цифры (0~9) или символы подчеркивания (_). Имена пользователей не могут быть изменены позже."
aiChanMode: "ИИ режим" aiChanMode: "ИИ режим"
keepCw: "Сохраняйте Предупреждения о содержимом" keepCw: "Сохраняйте Предупреждения о содержимом"
controllPanel: "Панель управления" controlPanel: "Панель управления"
manageAccounts: "Управление аккаунтом" manageAccounts: "Управление аккаунтом"
_docs: _docs:
continueReading: "Читать подробнее" continueReading: "Читать подробнее"

View File

@ -795,8 +795,9 @@ itsOff: "已关闭"
emailRequiredForSignup: "注册账户需要电子邮件地址" emailRequiredForSignup: "注册账户需要电子邮件地址"
unread: "未读" unread: "未读"
filter: "筛选" filter: "筛选"
controllPanel: "控制面板" controlPanel: "控制面板"
manageAccounts: "管理账户" manageAccounts: "管理账户"
classic: "经典"
_signup: _signup:
almostThere: "即将完成" almostThere: "即将完成"
emailAddressInfo: "请输入您所使用的电子邮件地址" emailAddressInfo: "请输入您所使用的电子邮件地址"

View File

@ -0,0 +1,26 @@
import {MigrationInterface, QueryRunner} from "typeorm";
export class noteThreadMute1635500777168 implements MigrationInterface {
name = 'noteThreadMute1635500777168'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "note_thread_muting" ("id" character varying(32) NOT NULL, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "userId" character varying(32) NOT NULL, "threadId" character varying(256) NOT NULL, CONSTRAINT "PK_ec5936d94d1a0369646d12a3a47" PRIMARY KEY ("id"))`);
await queryRunner.query(`CREATE INDEX "IDX_29c11c7deb06615076f8c95b80" ON "note_thread_muting" ("userId") `);
await queryRunner.query(`CREATE INDEX "IDX_c426394644267453e76f036926" ON "note_thread_muting" ("threadId") `);
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_ae7aab18a2641d3e5f25e0c4ea" ON "note_thread_muting" ("userId", "threadId") `);
await queryRunner.query(`ALTER TABLE "note" ADD "threadId" character varying(256)`);
await queryRunner.query(`CREATE INDEX "IDX_d4ebdef929896d6dc4a3c5bb48" ON "note" ("threadId") `);
await queryRunner.query(`ALTER TABLE "note_thread_muting" ADD CONSTRAINT "FK_29c11c7deb06615076f8c95b80a" FOREIGN KEY ("userId") REFERENCES "user"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "note_thread_muting" DROP CONSTRAINT "FK_29c11c7deb06615076f8c95b80a"`);
await queryRunner.query(`DROP INDEX "public"."IDX_d4ebdef929896d6dc4a3c5bb48"`);
await queryRunner.query(`ALTER TABLE "note" DROP COLUMN "threadId"`);
await queryRunner.query(`DROP INDEX "public"."IDX_ae7aab18a2641d3e5f25e0c4ea"`);
await queryRunner.query(`DROP INDEX "public"."IDX_c426394644267453e76f036926"`);
await queryRunner.query(`DROP INDEX "public"."IDX_29c11c7deb06615076f8c95b80"`);
await queryRunner.query(`DROP TABLE "note_thread_muting"`);
}
}

View File

@ -1,7 +1,6 @@
{ {
"name": "misskey", "name": "misskey",
"author": "syuilo <syuilotan@yahoo.co.jp>", "version": "12.95.0",
"version": "12.93.0",
"codename": "indigo", "codename": "indigo",
"repository": { "repository": {
"type": "git", "type": "git",
@ -29,8 +28,9 @@
"lint": "tslint 'src/**/*.ts'", "lint": "tslint 'src/**/*.ts'",
"cy:open": "cypress open", "cy:open": "cypress open",
"cy:run": "cypress run", "cy:run": "cypress run",
"e2e": "start-server-and-test start:test http://localhost cy:run", "e2e": "start-server-and-test start:test http://localhost:61812 cy:run",
"test": "cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha", "mocha": "cross-env TS_NODE_FILES=true TS_NODE_TRANSPILE_ONLY=true TS_NODE_PROJECT=\"./test/tsconfig.json\" mocha",
"test": "npm run mocha",
"format": "gulp format" "format": "gulp format"
}, },
"resolutions": { "resolutions": {
@ -38,6 +38,7 @@
"lodash": "^4.17.21" "lodash": "^4.17.21"
}, },
"dependencies": { "dependencies": {
"@discordapp/twemoji": "13.1.0",
"@elastic/elasticsearch": "7.11.0", "@elastic/elasticsearch": "7.11.0",
"@koa/cors": "3.1.0", "@koa/cors": "3.1.0",
"@koa/multer": "3.0.0", "@koa/multer": "3.0.0",
@ -51,18 +52,15 @@
"@types/cbor": "6.0.0", "@types/cbor": "6.0.0",
"@types/dateformat": "3.0.1", "@types/dateformat": "3.0.1",
"@types/escape-regexp": "0.0.0", "@types/escape-regexp": "0.0.0",
"@types/glob": "7.1.4", "@types/glob": "7.2.0",
"@types/gulp": "4.0.9", "@types/gulp": "4.0.9",
"@types/gulp-rename": "2.0.1", "@types/gulp-rename": "2.0.1",
"@types/is-url": "1.2.30", "@types/is-url": "1.2.30",
"@types/js-yaml": "4.0.3", "@types/js-yaml": "4.0.4",
"@types/jsdom": "16.2.13", "@types/jsdom": "16.2.13",
"@types/jsonld": "1.5.6", "@types/jsonld": "1.5.6",
"@types/katex": "0.11.1", "@types/katex": "0.11.1",
"@types/koa": "2.13.4", "@types/koa": "2.13.4",
"@types/koa__cors": "3.0.3",
"@types/koa__multer": "2.0.3",
"@types/koa__router": "8.0.8",
"@types/koa-bodyparser": "4.3.3", "@types/koa-bodyparser": "4.3.3",
"@types/koa-cors": "0.0.2", "@types/koa-cors": "0.0.2",
"@types/koa-favicon": "2.0.21", "@types/koa-favicon": "2.0.21",
@ -70,15 +68,18 @@
"@types/koa-mount": "4.0.1", "@types/koa-mount": "4.0.1",
"@types/koa-send": "4.1.3", "@types/koa-send": "4.1.3",
"@types/koa-views": "7.0.0", "@types/koa-views": "7.0.0",
"@types/koa__cors": "3.0.3",
"@types/koa__multer": "2.0.4",
"@types/koa__router": "8.0.8",
"@types/markdown-it": "12.2.3", "@types/markdown-it": "12.2.3",
"@types/matter-js": "0.17.5", "@types/matter-js": "0.17.6",
"@types/mocha": "8.2.3", "@types/mocha": "8.2.3",
"@types/node": "16.10.3", "@types/node": "16.11.4",
"@types/node-fetch": "2.5.12", "@types/node-fetch": "2.5.12",
"@types/nodemailer": "6.4.4", "@types/nodemailer": "6.4.4",
"@types/nprogress": "0.2.0", "@types/nprogress": "0.2.0",
"@types/oauth": "0.9.1", "@types/oauth": "0.9.1",
"@types/parse5": "6.0.1", "@types/parse5": "6.0.2",
"@types/parsimmon": "1.10.6", "@types/parsimmon": "1.10.6",
"@types/portscanner": "2.1.1", "@types/portscanner": "2.1.1",
"@types/pug": "2.0.5", "@types/pug": "2.0.5",
@ -96,21 +97,20 @@
"@types/speakeasy": "2.0.6", "@types/speakeasy": "2.0.6",
"@types/throttle-debounce": "2.1.0", "@types/throttle-debounce": "2.1.0",
"@types/tinycolor2": "1.4.3", "@types/tinycolor2": "1.4.3",
"@types/tmp": "0.2.1", "@types/tmp": "0.2.2",
"@types/uuid": "8.3.1", "@types/uuid": "8.3.1",
"@types/web-push": "3.3.2", "@types/web-push": "3.3.2",
"@types/webpack": "5.28.0", "@types/webpack": "5.28.0",
"@types/webpack-stream": "3.2.12", "@types/webpack-stream": "3.2.12",
"@types/websocket": "1.0.4", "@types/websocket": "1.0.4",
"@types/ws": "8.2.0", "@types/ws": "8.2.0",
"@typescript-eslint/parser": "5.0.0", "@typescript-eslint/parser": "5.1.0",
"@vue/compiler-sfc": "3.2.20", "@vue/compiler-sfc": "3.2.20",
"abort-controller": "3.0.0", "abort-controller": "3.0.0",
"apexcharts": "3.28.3",
"autobind-decorator": "2.4.0", "autobind-decorator": "2.4.0",
"autosize": "4.0.4", "autosize": "4.0.4",
"autwh": "0.1.0", "autwh": "0.1.0",
"aws-sdk": "2.1003.0", "aws-sdk": "2.1013.0",
"bcryptjs": "2.4.3", "bcryptjs": "2.4.3",
"blurhash": "1.1.4", "blurhash": "1.1.4",
"broadcast-channel": "4.2.0", "broadcast-channel": "4.2.0",
@ -119,7 +119,7 @@
"cafy": "15.2.1", "cafy": "15.2.1",
"cbor": "8.0.2", "cbor": "8.0.2",
"chalk": "4.1.2", "chalk": "4.1.2",
"chart.js": "3.5.1", "chart.js": "3.6.0",
"chartjs-adapter-date-fns": "2.0.0", "chartjs-adapter-date-fns": "2.0.0",
"chartjs-plugin-zoom": "1.1.1", "chartjs-plugin-zoom": "1.1.1",
"cli-highlight": "2.1.11", "cli-highlight": "2.1.11",
@ -132,8 +132,8 @@
"date-fns": "2.25.0", "date-fns": "2.25.0",
"dateformat": "4.5.1", "dateformat": "4.5.1",
"escape-regexp": "0.0.1", "escape-regexp": "0.0.1",
"eslint": "8.0.1", "eslint": "8.1.0",
"eslint-plugin-vue": "7.19.1", "eslint-plugin-vue": "7.20.0",
"eventemitter3": "4.0.7", "eventemitter3": "4.0.7",
"feed": "4.2.2", "feed": "4.2.2",
"file-type": "16.5.3", "file-type": "16.5.3",
@ -159,7 +159,7 @@
"jsonld": "5.2.0", "jsonld": "5.2.0",
"jsrsasign": "8.0.20", "jsrsasign": "8.0.20",
"katex": "0.13.18", "katex": "0.13.18",
"koa": "2.13.3", "koa": "2.13.4",
"koa-bodyparser": "4.3.0", "koa-bodyparser": "4.3.0",
"koa-favicon": "2.1.0", "koa-favicon": "2.1.0",
"koa-json-body": "5.3.0", "koa-json-body": "5.3.0",
@ -173,7 +173,7 @@
"markdown-it-anchor": "7.1.0", "markdown-it-anchor": "7.1.0",
"matter-js": "0.17.1", "matter-js": "0.17.1",
"mfm-js": "0.20.0", "mfm-js": "0.20.0",
"misskey-js": "0.0.6", "misskey-js": "0.0.8",
"mocha": "8.4.0", "mocha": "8.4.0",
"ms": "2.1.3", "ms": "2.1.3",
"multer": "1.4.3", "multer": "1.4.3",
@ -183,8 +183,9 @@
"os-utils": "0.0.14", "os-utils": "0.0.14",
"parse5": "6.0.1", "parse5": "6.0.1",
"pg": "8.7.1", "pg": "8.7.1",
"photoswipe": "git://github.com/dimsemenov/photoswipe#v5-beta",
"portscanner": "2.2.0", "portscanner": "2.2.0",
"postcss": "8.3.9", "postcss": "8.3.11",
"postcss-loader": "6.2.0", "postcss-loader": "6.2.0",
"prismjs": "1.25.0", "prismjs": "1.25.0",
"private-ip": "2.3.0", "private-ip": "2.3.0",
@ -206,17 +207,17 @@
"rimraf": "3.0.2", "rimraf": "3.0.2",
"rndstr": "1.0.0", "rndstr": "1.0.0",
"s-age": "1.1.2", "s-age": "1.1.2",
"sass": "1.43.2", "sass": "1.43.3",
"sass-loader": "12.2.0", "sass-loader": "12.2.0",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"sharp": "0.29.1", "sharp": "0.29.2",
"speakeasy": "2.0.0", "speakeasy": "2.0.0",
"strict-event-emitter-types": "2.0.0", "strict-event-emitter-types": "2.0.0",
"stringz": "2.1.0", "stringz": "2.1.0",
"style-loader": "3.3.0", "style-loader": "3.3.1",
"summaly": "2.4.1", "summaly": "2.4.1",
"syslog-pro": "1.0.0", "syslog-pro": "1.0.0",
"systeminformation": "5.9.7", "systeminformation": "5.9.8",
"syuilo-password-strength": "0.0.1", "syuilo-password-strength": "0.0.1",
"textarea-caret": "3.1.0", "textarea-caret": "3.1.0",
"three": "0.117.1", "three": "0.117.1",
@ -224,7 +225,7 @@
"tinycolor2": "1.4.2", "tinycolor2": "1.4.2",
"tmp": "0.2.1", "tmp": "0.2.1",
"ts-loader": "9.2.6", "ts-loader": "9.2.6",
"ts-node": "10.3.0", "ts-node": "10.4.0",
"tsc-alias": "1.3.10", "tsc-alias": "1.3.10",
"tsconfig-paths": "3.11.0", "tsconfig-paths": "3.11.0",
"tslint": "6.1.3", "tslint": "6.1.3",
@ -244,8 +245,8 @@
"vue-svg-loader": "0.17.0-beta.2", "vue-svg-loader": "0.17.0-beta.2",
"vuedraggable": "4.0.1", "vuedraggable": "4.0.1",
"web-push": "3.4.5", "web-push": "3.4.5",
"webpack": "5.58.2", "webpack": "5.59.1",
"webpack-cli": "4.9.0", "webpack-cli": "4.9.1",
"websocket": "1.0.34", "websocket": "1.0.34",
"ws": "8.2.3", "ws": "8.2.3",
"xev": "2.0.1" "xev": "2.0.1"

View File

@ -1,5 +1,10 @@
<template> <template>
<canvas ref="chartEl"></canvas> <div class="cbbedffa">
<canvas ref="chartEl"></canvas>
<div v-if="fetching" class="fetching">
<MkLoading/>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -84,6 +89,16 @@ export default defineComponent({
required: false, required: false,
default: false default: false
}, },
stacked: {
type: Boolean,
required: false,
default: false
},
aspectRatio: {
type: Number,
required: false,
default: null
},
}, },
setup(props) { setup(props) {
@ -152,7 +167,7 @@ export default defineComponent({
})), })),
}, },
options: { options: {
aspectRatio: 2.5, aspectRatio: props.aspectRatio || 2.5,
layout: { layout: {
padding: { padding: {
left: 16, left: 16,
@ -169,7 +184,6 @@ export default defineComponent({
unit: props.span === 'day' ? 'month' : 'day', unit: props.span === 'day' ? 'month' : 'day',
}, },
grid: { grid: {
display: props.detailed,
color: gridColor, color: gridColor,
borderColor: 'rgb(0, 0, 0, 0)', borderColor: 'rgb(0, 0, 0, 0)',
}, },
@ -185,6 +199,7 @@ export default defineComponent({
}, },
y: { y: {
position: 'left', position: 'left',
stacked: props.stacked,
grid: { grid: {
color: gridColor, color: gridColor,
borderColor: 'rgb(0, 0, 0, 0)', borderColor: 'rgb(0, 0, 0, 0)',
@ -199,6 +214,7 @@ export default defineComponent({
}, },
plugins: { plugins: {
legend: { legend: {
display: props.detailed,
position: 'bottom', position: 'bottom',
labels: { labels: {
boxWidth: 16, boxWidth: 16,
@ -578,6 +594,30 @@ export default defineComponent({
}; };
}; };
const fetchPerUserNotesChart = async (): Promise<typeof data> => {
const raw = await os.api('charts/user/notes', { userId: props.args.user.id, limit: props.limit, span: props.span });
return {
series: [...(props.args.withoutAll ? [] : [{
name: 'All',
type: 'line',
borderDash: [5, 5],
data: format(sum(raw.inc, negate(raw.dec))),
}]), {
name: 'Renotes',
type: 'area',
data: format(raw.diffs.renote),
}, {
name: 'Replies',
type: 'area',
data: format(raw.diffs.reply),
}, {
name: 'Normal',
type: 'area',
data: format(raw.diffs.normal),
}],
};
};
const fetchAndRender = async () => { const fetchAndRender = async () => {
const fetchData = () => { const fetchData = () => {
switch (props.src) { switch (props.src) {
@ -606,6 +646,8 @@ export default defineComponent({
case 'instance-drive-usage-total': return fetchInstanceDriveUsageChart(true); case 'instance-drive-usage-total': return fetchInstanceDriveUsageChart(true);
case 'instance-drive-files': return fetchInstanceDriveFilesChart(false); case 'instance-drive-files': return fetchInstanceDriveFilesChart(false);
case 'instance-drive-files-total': return fetchInstanceDriveFilesChart(true); case 'instance-drive-files-total': return fetchInstanceDriveFilesChart(true);
case 'per-user-notes': return fetchPerUserNotesChart();
} }
}; };
fetching.value = true; fetching.value = true;
@ -622,7 +664,28 @@ export default defineComponent({
return { return {
chartEl, chartEl,
fetching,
}; };
}, },
}); });
</script> </script>
<style lang="scss" scoped>
.cbbedffa {
position: relative;
> .fetching {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
-webkit-backdrop-filter: var(--blur, blur(12px));
backdrop-filter: var(--blur, blur(12px));
display: flex;
justify-content: center;
align-items: center;
cursor: wait;
}
}
</style>

View File

@ -7,21 +7,21 @@
> >
<template #header>{{ $ts.forgotPassword }}</template> <template #header>{{ $ts.forgotPassword }}</template>
<form class="_monolithic_" @submit.prevent="onSubmit" v-if="$instance.enableEmail"> <form class="bafeceda" @submit.prevent="onSubmit" v-if="$instance.enableEmail">
<div class="_section"> <div class="main _formRoot">
<MkInput v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required> <MkInput class="_formBlock" v-model="username" type="text" pattern="^[a-zA-Z0-9_]+$" spellcheck="false" autofocus required>
<template #label>{{ $ts.username }}</template> <template #label>{{ $ts.username }}</template>
<template #prefix>@</template> <template #prefix>@</template>
</MkInput> </MkInput>
<MkInput v-model="email" type="email" spellcheck="false" required> <MkInput class="_formBlock" v-model="email" type="email" spellcheck="false" required>
<template #label>{{ $ts.emailAddress }}</template> <template #label>{{ $ts.emailAddress }}</template>
<template #caption>{{ $ts._forgotPassword.enterEmail }}</template> <template #caption>{{ $ts._forgotPassword.enterEmail }}</template>
</MkInput> </MkInput>
<MkButton type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ $ts.send }}</MkButton> <MkButton class="_formBlock" type="submit" :disabled="processing" primary style="margin: 0 auto;">{{ $ts.send }}</MkButton>
</div> </div>
<div class="_section"> <div class="sub">
<MkA to="/about" class="_link">{{ $ts._forgotPassword.ifNoEmail }}</MkA> <MkA to="/about" class="_link">{{ $ts._forgotPassword.ifNoEmail }}</MkA>
</div> </div>
</form> </form>
@ -69,3 +69,16 @@ export default defineComponent({
} }
}); });
</script> </script>
<style lang="scss" scoped>
.bafeceda {
> .main {
padding: 24px;
}
> .sub {
border-top: solid 0.5px var(--divider);
padding: 24px;
}
}
</style>

View File

@ -24,7 +24,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue'; import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, VNode } from 'vue';
import MkButton from '@client/components/ui/button.vue'; import MkButton from '@client/components/ui/button.vue';
import * as os from '@client/os'; import * as os from '@client/os';
@ -140,33 +140,36 @@ export default defineComponent({
const menu = []; const menu = [];
let options = context.slots.default(); let options = context.slots.default();
for (const optionOrOptgroup of options) { const pushOption = (option: VNode) => {
if (optionOrOptgroup.type === 'optgroup') { menu.push({
const optgroup = optionOrOptgroup; text: option.children,
active: v.value === option.props.value,
action: () => {
v.value = option.props.value;
},
});
};
const scanOptions = (options: VNode[]) => {
for (const vnode of options) {
if (vnode.type === 'optgroup') {
const optgroup = vnode;
menu.push({ menu.push({
type: 'label', type: 'label',
text: optgroup.props.label, text: optgroup.props.label,
}); });
for (const option of optgroup.children) { scanOptions(optgroup.children);
menu.push({ } else if (Array.isArray(vnode.children)) { // 何故かフラグメントになってくることがある
text: option.children, const fragment = vnode;
active: v.value === option.props.value, scanOptions(fragment.children);
action: () => {
v.value = option.props.value;
},
});
}
} else { } else {
const option = optionOrOptgroup; const option = vnode;
menu.push({ pushOption(option);
text: option.children,
active: v.value === option.props.value,
action: () => {
v.value = option.props.value;
},
});
} }
} }
};
scanOptions(options);
os.popupMenu(menu, container.value, { os.popupMenu(menu, container.value, {
width: container.value.offsetWidth, width: container.value.offsetWidth,

View File

@ -2,8 +2,8 @@
<div class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick" ref="el"> <div class="fdidabkb" :class="{ slim: narrow, thin: thin_ }" :style="{ background: bg }" @click="onClick" ref="el">
<template v-if="info"> <template v-if="info">
<div class="titleContainer" @click="showTabsPopup" v-if="!hideTitle"> <div class="titleContainer" @click="showTabsPopup" v-if="!hideTitle">
<i v-if="info.icon" class="icon" :class="info.icon"></i> <MkAvatar v-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
<MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/> <i v-else-if="info.icon" class="icon" :class="info.icon"></i>
<div class="title"> <div class="title">
<MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="title"/> <MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="title"/>
@ -162,11 +162,6 @@ export default defineComponent({
onUnmounted(() => { onUnmounted(() => {
ro.disconnect(); ro.disconnect();
}); });
setTimeout(() => {
const currentStickyTop = getComputedStyle(el.value.parentElement).getPropertyValue('--stickyTop') || '0px';
el.value.style.setProperty('--stickyTop', currentStickyTop);
el.value.parentElement.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${el.value.offsetHeight}px)`);
}, 100); // レンダリング順序の関係で親のstickyTopの設定が少し遅れることがあるため
} }
}); });

View File

@ -0,0 +1,74 @@
<template>
<div ref="rootEl">
<slot name="header"></slot>
<div ref="bodyEl">
<slot></slot>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent, onMounted, onUnmounted, ref } from 'vue';
export default defineComponent({
props: {
autoSticky: {
type: Boolean,
required: false,
default: false,
},
},
setup(props, context) {
const rootEl = ref<HTMLElement>(null);
const bodyEl = ref<HTMLElement>(null);
const calc = () => {
const currentStickyTop = getComputedStyle(rootEl.value).getPropertyValue('--stickyTop') || '0px';
const header = rootEl.value.children[0];
if (header === bodyEl.value) {
bodyEl.value.style.setProperty('--stickyTop', currentStickyTop);
} else {
bodyEl.value.style.setProperty('--stickyTop', `calc(${currentStickyTop} + ${header.offsetHeight}px)`);
if (props.autoSticky) {
header.style.setProperty('--stickyTop', currentStickyTop);
header.style.position = 'sticky';
header.style.top = 'var(--stickyTop)';
header.style.zIndex = '1';
}
}
};
onMounted(() => {
calc();
const observer = new MutationObserver(() => {
setTimeout(() => {
calc();
}, 100);
});
observer.observe(rootEl.value, {
attributes: false,
childList: true,
subtree: false,
});
onUnmounted(() => {
observer.disconnect();
});
});
return {
rootEl,
bodyEl,
};
},
});
</script>
<style lang="scss" module>
</style>

View File

@ -10,7 +10,12 @@ import { defineComponent } from 'vue';
import * as os from '@client/os'; import * as os from '@client/os';
export default defineComponent({ export default defineComponent({
props: ['q'], props: {
q: {
type: String,
required: true,
}
},
data() { data() {
return { return {
query: null, query: null,
@ -21,10 +26,7 @@ export default defineComponent({
}, },
methods: { methods: {
search() { search() {
const engine = this.$store.state.webSearchEngine || window.open(`https://www.google.com/search?q=${this.query}`, '_blank');
'https://www.google.com/search?q={{query}}';
const url = engine.replace('{{query}}', this.query)
window.open(url, '_blank');
} }
} }
}); });

View File

@ -15,6 +15,7 @@ import error from './global/error.vue';
import ad from './global/ad.vue'; import ad from './global/ad.vue';
import header from './global/header.vue'; import header from './global/header.vue';
import spacer from './global/spacer.vue'; import spacer from './global/spacer.vue';
import stickyContainer from './global/sticky-container.vue';
export default function(app: App) { export default function(app: App) {
app.component('I18n', i18n); app.component('I18n', i18n);
@ -32,4 +33,5 @@ export default function(app: App) {
app.component('MkAd', ad); app.component('MkAd', ad);
app.component('MkHeader', header); app.component('MkHeader', header);
app.component('MkSpacer', spacer); app.component('MkSpacer', spacer);
app.component('MkStickyContainer', stickyContainer);
} }

View File

@ -12,7 +12,6 @@
<a <a
:href="image.url" :href="image.url"
:title="image.name" :title="image.name"
@click.prevent="onClick"
> >
<ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.comment" :title="image.comment" :cover="false"/> <ImgWithBlurhash :hash="image.blurhash" :src="url" :alt="image.comment" :title="image.comment" :cover="false"/>
<div class="gif" v-if="image.type === 'image/gif'">GIF</div> <div class="gif" v-if="image.type === 'image/gif'">GIF</div>
@ -73,17 +72,6 @@ export default defineComponent({
immediate: true, immediate: true,
}); });
}, },
methods: {
onClick() {
if (this.$store.state.imageNewTab) {
window.open(this.image.url, '_blank');
} else {
os.popup(ImageViewer, {
image: this.image
}, {}, 'closed');
}
}
}
}); });
</script> </script>

View File

@ -1,11 +1,11 @@
<template> <template>
<div class="mk-media-list"> <div class="hoawjimk">
<XBanner v-for="media in mediaList.filter(media => !previewable(media))" :media="media" :key="media.id"/> <XBanner v-for="media in mediaList.filter(media => !previewable(media))" :media="media" :key="media.id"/>
<div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container" ref="gridOuter"> <div v-if="mediaList.filter(media => previewable(media)).length > 0" class="gird-container">
<div :data-count="mediaList.filter(media => previewable(media)).length" :style="gridInnerStyle"> <div :data-count="mediaList.filter(media => previewable(media)).length" ref="gallery">
<template v-for="media in mediaList"> <template v-for="media in mediaList">
<XVideo :video="media" :key="media.id" v-if="media.type.startsWith('video')"/> <XVideo :video="media" :key="media.id" v-if="media.type.startsWith('video')"/>
<XImage :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/> <XImage class="image" :data-id="media.id" :image="media" :key="media.id" v-else-if="media.type.startsWith('image')" :raw="raw"/>
</template> </template>
</div> </div>
</div> </div>
@ -13,11 +13,16 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent, onMounted, PropType, ref } from 'vue';
import * as misskey from 'misskey-js';
import PhotoSwipeLightbox from 'photoswipe/dist/photoswipe-lightbox.esm.js';
import PhotoSwipe from 'photoswipe/dist/photoswipe.esm.js';
import 'photoswipe/dist/photoswipe.css';
import XBanner from './media-banner.vue'; import XBanner from './media-banner.vue';
import XImage from './media-image.vue'; import XImage from './media-image.vue';
import XVideo from './media-video.vue'; import XVideo from './media-video.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import { defaultStore } from '@client/store';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -27,63 +32,63 @@ export default defineComponent({
}, },
props: { props: {
mediaList: { mediaList: {
required: true type: Array as PropType<misskey.entities.DriveFile[]>,
required: true,
}, },
raw: { raw: {
default: false default: false
}, },
}, },
data() { setup(props) {
return { const gallery = ref(null);
gridInnerStyle: {},
sizeWaiting: false
}
},
mounted() {
this.size();
window.addEventListener('resize', this.size);
},
beforeUnmount() {
window.removeEventListener('resize', this.size);
},
activated() {
this.size();
},
methods: {
previewable(file) {
return file.type.startsWith('video') || file.type.startsWith('image');
},
size() {
// for Safari bug
if (this.sizeWaiting) return;
this.sizeWaiting = true; onMounted(() => {
const lightbox = new PhotoSwipeLightbox({
window.requestAnimationFrame(() => { dataSource: props.mediaList.filter(media => media.type.startsWith('image')).map(media => ({
this.sizeWaiting = false; src: media.url,
w: media.properties.width,
if (this.$refs.gridOuter) { h: media.properties.height,
let height = 287; alt: media.name,
const parent = this.$parent.$el; })),
gallery: gallery.value,
if (this.$refs.gridOuter.clientHeight) { children: '.image',
height = this.$refs.gridOuter.clientHeight; thumbSelector: '.image',
} else if (parent) { pswpModule: PhotoSwipe
height = parent.getBoundingClientRect().width * 9 / 16;
}
this.gridInnerStyle = { height: `${height}px` };
} else {
this.gridInnerStyle = {};
}
}); });
}
lightbox.on('itemData', (e) => {
const { itemData } = e;
// element is children
const { element } = itemData;
const id = element.dataset.id;
const file = props.mediaList.find(media => media.id === id);
itemData.src = file.url;
itemData.w = Number(file.properties.width);
itemData.h = Number(file.properties.height);
itemData.msrc = file.thumbnailUrl;
itemData.thumbCropped = true;
});
lightbox.init();
});
const previewable = (file: misskey.entities.DriveFile): boolean => {
return file.type.startsWith('video') || file.type.startsWith('image');
};
return {
previewable,
gallery,
};
}, },
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.mk-media-list { .hoawjimk {
> .gird-container { > .gird-container {
position: relative; position: relative;
width: 100%; width: 100%;

View File

@ -11,6 +11,7 @@
:title="video.name" :title="video.name"
preload="none" preload="none"
controls controls
@contextmenu.stop
> >
<source <source
:src="video.url" :src="video.url"

View File

@ -1,12 +1,12 @@
<template> <template>
<MkA class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" v-if="url.startsWith('/')"> <MkA v-if="url.startsWith('/')" class="ldlomzub" :class="{ isMe }" :to="url" v-user-preview="canonical" :style="{ background: bg }">
<span class="me" v-if="isMe">{{ $ts.you }}</span> <img class="icon" :src="`/avatar/@${username}@${host}`" alt="">
<span class="main"> <span class="main">
<span class="username">@{{ username }}</span> <span class="username">@{{ username }}</span>
<span class="host" v-if="(host != localHost) || $store.state.showFullAcct">@{{ toUnicode(host) }}</span> <span class="host" v-if="(host != localHost) || $store.state.showFullAcct">@{{ toUnicode(host) }}</span>
</span> </span>
</MkA> </MkA>
<a class="ldlomzub" :href="url" target="_blank" rel="noopener" v-else> <a v-else class="ldlomzub" :href="url" target="_blank" rel="noopener" :style="{ background: bg }">
<span class="main"> <span class="main">
<span class="username">@{{ username }}</span> <span class="username">@{{ username }}</span>
<span class="host">@{{ toUnicode(host) }}</span> <span class="host">@{{ toUnicode(host) }}</span>
@ -16,10 +16,11 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import { toUnicode } from 'punycode/'; import * as tinycolor from 'tinycolor2';
import { toUnicode } from 'punycode';
import { host as localHost } from '@client/config'; import { host as localHost } from '@client/config';
import { wellKnownServices } from '../../well-known-services'; import { wellKnownServices } from '../../well-known-services';
import * as os from '@client/os'; import { $i } from '@client/account';
export default defineComponent({ export default defineComponent({
props: { props: {
@ -32,48 +33,48 @@ export default defineComponent({
required: true required: true
} }
}, },
data() {
setup(props) {
const canonical = props.host === localHost ? `@${props.username}` : `@${props.username}@${toUnicode(props.host)}`;
const wellKnown = wellKnownServices.find(x => x[0] === props.host);
const url = wellKnown ? wellKnown[1](props.username) : `/${canonical}`;
const isMe = $i && (
`@${props.username}@${toUnicode(props.host)}` === `@${$i.username}@${toUnicode(localHost)}`.toLowerCase()
);
const bg = tinycolor(getComputedStyle(document.documentElement).getPropertyValue(isMe ? '--mentionMe' : '--mention'));
bg.setAlpha(0.20);
return { return {
localHost localHost,
isMe,
url,
canonical,
toUnicode,
bg: bg.toRgbString(),
}; };
}, },
computed: {
url(): string {
const wellKnown = wellKnownServices.find(x => x[0] === this.host);
if (wellKnown) {
return wellKnown[1](this.username);
} else {
return `/${this.canonical}`;
}
},
canonical(): string {
return this.host === localHost ? `@${this.username}` : `@${this.username}@${toUnicode(this.host)}`;
},
isMe(): boolean {
return this.$i && (
`@${this.username}@${toUnicode(this.host)}` === `@${this.$i.username}@${toUnicode(localHost)}`.toLowerCase()
);
}
},
methods: {
toUnicode
}
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.ldlomzub { .ldlomzub {
display: inline-block;
padding: 4px 8px 4px 4px;
border-radius: 999px;
color: var(--mention); color: var(--mention);
&.isMe { &.isMe {
color: var(--mentionMe); color: var(--mentionMe);
} }
> .me { > .icon {
pointer-events: none; width: 1.5em;
user-select: none; margin: 0 0.2em 0 0;
font-size: 70%; vertical-align: bottom;
vertical-align: top; border-radius: 100%;
} }
> .main { > .main {

View File

@ -10,10 +10,13 @@
</span> </span>
<button class="_button" @click="$refs.modal.close()"><i class="fas fa-times"></i></button> <button class="_button" @click="$refs.modal.close()"><i class="fas fa-times"></i></button>
</div> </div>
<div class="body _fitSide_"> <div class="body">
<MkStickyContainer>
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
<keep-alive> <keep-alive>
<component :is="component" v-bind="props" :ref="changePage"/> <component :is="component" v-bind="props" :ref="changePage"/>
</keep-alive> </keep-alive>
</MkStickyContainer>
</div> </div>
</div> </div>
</MkModal> </MkModal>

View File

@ -601,6 +601,12 @@ export default defineComponent({
}); });
}, },
toggleThreadMute(mute: boolean) {
os.apiWithDialog(mute ? 'notes/thread-muting/create' : 'notes/thread-muting/delete', {
noteId: this.appearNote.id
});
},
getMenu() { getMenu() {
let menu; let menu;
if (this.$i) { if (this.$i) {
@ -657,6 +663,15 @@ export default defineComponent({
text: this.$ts.watch, text: this.$ts.watch,
action: () => this.toggleWatch(true) action: () => this.toggleWatch(true)
}) : undefined, }) : undefined,
statePromise.then(state => state.isMutedThread ? {
icon: 'fas fa-comment-slash',
text: this.$ts.unmuteThread,
action: () => this.toggleThreadMute(false)
} : {
icon: 'fas fa-comment-slash',
text: this.$ts.muteThread,
action: () => this.toggleThreadMute(true)
}),
this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? { this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
icon: 'fas fa-thumbtack', icon: 'fas fa-thumbtack',
text: this.$ts.unpin, text: this.$ts.unpin,

View File

@ -576,6 +576,12 @@ export default defineComponent({
}); });
}, },
toggleThreadMute(mute: boolean) {
os.apiWithDialog(mute ? 'notes/thread-muting/create' : 'notes/thread-muting/delete', {
noteId: this.appearNote.id
});
},
getMenu() { getMenu() {
let menu; let menu;
if (this.$i) { if (this.$i) {
@ -632,6 +638,15 @@ export default defineComponent({
text: this.$ts.watch, text: this.$ts.watch,
action: () => this.toggleWatch(true) action: () => this.toggleWatch(true)
}) : undefined, }) : undefined,
statePromise.then(state => state.isMutedThread ? {
icon: 'fas fa-comment-slash',
text: this.$ts.unmuteThread,
action: () => this.toggleThreadMute(false)
} : {
icon: 'fas fa-comment-slash',
text: this.$ts.muteThread,
action: () => this.toggleThreadMute(true)
}),
this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? { this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
icon: 'fas fa-thumbtack', icon: 'fas fa-thumbtack',
text: this.$ts.unpin, text: this.$ts.unpin,

View File

@ -13,7 +13,8 @@
<i v-else-if="notification.type === 'mention'" class="fas fa-at"></i> <i v-else-if="notification.type === 'mention'" class="fas fa-at"></i>
<i v-else-if="notification.type === 'quote'" class="fas fa-quote-left"></i> <i v-else-if="notification.type === 'quote'" class="fas fa-quote-left"></i>
<i v-else-if="notification.type === 'pollVote'" class="fas fa-poll-h"></i> <i v-else-if="notification.type === 'pollVote'" class="fas fa-poll-h"></i>
<XReactionIcon v-else-if="notification.type === 'reaction'" :reaction="notification.reaction" :custom-emojis="notification.note.emojis" :no-style="true"/> <!-- notification.reaction null になることはまずないがここでoptional chaining使うと一部ブラウザで刺さるので念の為 -->
<XReactionIcon v-else-if="notification.type === 'reaction'" :reaction="notification.reaction ? notification.reaction.replace(/^:(\w+):$/, ':$1@.:') : notification.reaction" :custom-emojis="notification.note.emojis" :no-style="true"/>
</div> </div>
</div> </div>
<div class="tail"> <div class="tail">

View File

@ -16,8 +16,11 @@
<template #headerLeft> <template #headerLeft>
<button v-if="history.length > 0" class="_button" @click="back()" v-tooltip="$ts.goBack"><i class="fas fa-arrow-left"></i></button> <button v-if="history.length > 0" class="_button" @click="back()" v-tooltip="$ts.goBack"><i class="fas fa-arrow-left"></i></button>
</template> </template>
<div class="yrolvcoq _fitSide_"> <div class="yrolvcoq">
<MkStickyContainer>
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
<component :is="component" v-bind="props" :ref="changePage"/> <component :is="component" v-bind="props" :ref="changePage"/>
</MkStickyContainer>
</div> </div>
</XWindow> </XWindow>
</template> </template>

View File

@ -79,6 +79,7 @@ export default defineComponent({
pointRadius: 0, pointRadius: 0,
tension: 0, tension: 0,
borderWidth: 2, borderWidth: 2,
borderJoinStyle: 'round',
borderColor: '#00E396', borderColor: '#00E396',
backgroundColor: alpha('#00E396', 0.1), backgroundColor: alpha('#00E396', 0.1),
data: [] data: []
@ -87,6 +88,7 @@ export default defineComponent({
pointRadius: 0, pointRadius: 0,
tension: 0, tension: 0,
borderWidth: 2, borderWidth: 2,
borderJoinStyle: 'round',
borderColor: '#00BCD4', borderColor: '#00BCD4',
backgroundColor: alpha('#00BCD4', 0.1), backgroundColor: alpha('#00BCD4', 0.1),
data: [] data: []
@ -95,17 +97,21 @@ export default defineComponent({
pointRadius: 0, pointRadius: 0,
tension: 0, tension: 0,
borderWidth: 2, borderWidth: 2,
borderJoinStyle: 'round',
borderColor: '#FFB300', borderColor: '#FFB300',
backgroundColor: alpha('#FFB300', 0.1), backgroundColor: alpha('#FFB300', 0.1),
yAxisID: 'y2',
data: [] data: []
}, { }, {
label: 'Delayed', label: 'Delayed',
pointRadius: 0, pointRadius: 0,
tension: 0, tension: 0,
borderWidth: 2, borderWidth: 2,
borderJoinStyle: 'round',
borderColor: '#E53935', borderColor: '#E53935',
borderDash: [5, 5], borderDash: [5, 5],
fill: false, fill: false,
yAxisID: 'y2',
data: [] data: []
}], }],
}, },
@ -122,15 +128,29 @@ export default defineComponent({
scales: { scales: {
x: { x: {
grid: { grid: {
display: false, display: true,
color: gridColor, color: gridColor,
borderColor: 'rgb(0, 0, 0, 0)', borderColor: 'rgb(0, 0, 0, 0)',
}, },
ticks: { ticks: {
display: false, display: false,
maxTicksLimit: 10
}, },
}, },
y: { y: {
min: 0,
stack: 'queue',
stackWeight: 2,
grid: {
color: gridColor,
borderColor: 'rgb(0, 0, 0, 0)',
},
},
y2: {
min: 0,
offset: true,
stack: 'queue',
stackWeight: 1,
grid: { grid: {
color: gridColor, color: gridColor,
borderColor: 'rgb(0, 0, 0, 0)', borderColor: 'rgb(0, 0, 0, 0)',

View File

@ -1,10 +1,11 @@
<template> <template>
<MkTooltip :source="source" ref="tooltip" @closed="$emit('closed')"> <MkTooltip :source="source" ref="tooltip" @closed="$emit('closed')" :max-width="340">
<div class="bqxuuuey"> <div class="bqxuuuey">
<div class="info"> <div class="reaction">
<div>{{ reaction.replace('@.', '') }}</div>
<XReactionIcon :reaction="reaction" :custom-emojis="emojis" class="icon" :no-style="true"/> <XReactionIcon :reaction="reaction" :custom-emojis="emojis" class="icon" :no-style="true"/>
<div class="name">{{ reaction.replace('@.', '') }}</div>
</div> </div>
<div class="users">
<template v-if="users.length <= 10"> <template v-if="users.length <= 10">
<b v-for="u in users" :key="u.id" style="margin-right: 12px;"> <b v-for="u in users" :key="u.id" style="margin-right: 12px;">
<MkAvatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/> <MkAvatar :user="u" style="width: 24px; height: 24px; margin-right: 2px;"/>
@ -19,6 +20,7 @@
<span slot="omitted">+{{ count - 10 }}</span> <span slot="omitted">+{{ count - 10 }}</span>
</template> </template>
</div> </div>
</div>
</MkTooltip> </MkTooltip>
</template> </template>
@ -59,8 +61,11 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.bqxuuuey { .bqxuuuey {
> .info { display: flex;
padding: 0 0 8px 0;
> .reaction {
flex: 1;
max-width: 100px;
text-align: center; text-align: center;
> .icon { > .icon {
@ -68,6 +73,19 @@ export default defineComponent({
width: 60px; width: 60px;
margin: 0 auto; margin: 0 auto;
} }
> .name {
font-size: 0.9em;
}
}
> .users {
flex: 1;
min-width: 0;
font-size: 0.9em;
border-left: solid 0.5px var(--divider);
padding-left: 10px;
margin-left: 10px;
} }
} }
</style> </style>

View File

@ -177,6 +177,7 @@ export default defineComponent({
> span { > span {
font-size: 0.9em; font-size: 0.9em;
line-height: 32px; line-height: 32px;
margin: 0 0 0 4px;
} }
} }
</style> </style>

View File

@ -153,10 +153,4 @@ export default defineComponent({
} }
} }
} }
._fitSide_ .ssazuxis {
> header {
padding: 0 16px;
}
}
</style> </style>

View File

@ -42,8 +42,4 @@ export default defineComponent({
margin-right: 4px; margin-right: 4px;
} }
} }
._fitSide_ .fpezltsf {
border-radius: 0;
}
</style> </style>

View File

@ -50,9 +50,6 @@ export default defineComponent({
border-top: solid 0.5px var(--divider); border-top: solid 0.5px var(--divider);
} }
margin-left: 16px;
margin-right: 16px;
> .title { > .title {
font-size: 0.9em; font-size: 0.9em;
opacity: 0.7; opacity: 0.7;
@ -120,7 +117,7 @@ export default defineComponent({
> .items { > .items {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
grid-gap: 8px; grid-gap: 8px;
padding: 0 16px; padding: 0 16px;

View File

@ -1,6 +1,6 @@
<template> <template>
<transition name="tooltip" appear @after-leave="$emit('closed')"> <transition name="tooltip" appear @after-leave="$emit('closed')">
<div class="buebdbiu _acrylic _shadow" v-show="showing" ref="content"> <div class="buebdbiu _acrylic _shadow" v-show="showing" ref="content" :style="{ maxWidth: maxWidth + 'px' }">
<slot>{{ text }}</slot> <slot>{{ text }}</slot>
</div> </div>
</transition> </transition>
@ -21,7 +21,12 @@ export default defineComponent({
text: { text: {
type: String, type: String,
required: false required: false
} },
maxWidth: {
type: Number,
required: false,
default: 250,
},
}, },
emits: ['closed'], emits: ['closed'],
@ -75,11 +80,12 @@ export default defineComponent({
.buebdbiu { .buebdbiu {
position: absolute; position: absolute;
z-index: 11000; z-index: 11000;
max-width: 240px;
font-size: 0.8em; font-size: 0.8em;
padding: 8px 12px; padding: 8px 12px;
box-sizing: border-box;
text-align: center; text-align: center;
border-radius: 4px; border-radius: 4px;
border: solid 0.5px var(--divider);
pointer-events: none; pointer-events: none;
transform-origin: center bottom; transform-origin: center bottom;
} }

View File

@ -4,7 +4,7 @@
<div class="title">{{ $ts.misskeyUpdated }}</div> <div class="title">{{ $ts.misskeyUpdated }}</div>
<div class="version">{{ version }}🚀</div> <div class="version">{{ version }}🚀</div>
<MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton> <MkButton full @click="whatIsNew">{{ $ts.whatIsNew }}</MkButton>
<MkButton primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton> <MkButton class="gotIt" primary full @click="$refs.modal.close()">{{ $ts.gotIt }}</MkButton>
</div> </div>
</MkModal> </MkModal>
</template> </template>
@ -54,5 +54,9 @@ export default defineComponent({
> .version { > .version {
margin: 1em 0; margin: 1em 0;
} }
> .gotIt {
margin: 8px 0 0 0;
}
} }
</style> </style>

View File

@ -37,6 +37,8 @@ import { isMobile } from '@client/scripts/is-mobile';
import { initializeSw } from '@client/scripts/initialize-sw'; import { initializeSw } from '@client/scripts/initialize-sw';
import { reloadChannel } from '@client/scripts/unison-reload'; import { reloadChannel } from '@client/scripts/unison-reload';
import { reactionPicker } from '@client/scripts/reaction-picker'; import { reactionPicker } from '@client/scripts/reaction-picker';
import { getUrlWithoutLoginId } from '@client/scripts/login-id';
import { getAccountFromId } from '@client/scripts/get-account-from-id';
console.info(`Misskey v${version}`); console.info(`Misskey v${version}`);
@ -116,6 +118,25 @@ const html = document.documentElement;
html.setAttribute('lang', lang); html.setAttribute('lang', lang);
//#endregion //#endregion
//#region loginId
const params = new URLSearchParams(location.search);
const loginId = params.get('loginId');
if (loginId) {
const target = getUrlWithoutLoginId(location.href);
if (!$i || $i.id !== loginId) {
const account = await getAccountFromId(loginId);
if (account) {
await login(account.token, target);
}
}
history.replaceState({ misskey: 'loginId' }, '', target);
}
//#endregion
//#region Fetch user //#region Fetch user
if ($i && $i.token) { if ($i && $i.token) {
if (_DEV_) { if (_DEV_) {
@ -166,8 +187,8 @@ const app = createApp(await (
ui === 'deck' ? import('@client/ui/deck.vue') : ui === 'deck' ? import('@client/ui/deck.vue') :
ui === 'desktop' ? import('@client/ui/desktop.vue') : ui === 'desktop' ? import('@client/ui/desktop.vue') :
ui === 'chat' ? import('@client/ui/chat/index.vue') : ui === 'chat' ? import('@client/ui/chat/index.vue') :
ui === 'pope' ? import('@client/ui/universal.vue') : ui === 'classic' ? import('@client/ui/classic.vue') :
import('@client/ui/default.vue') import('@client/ui/universal.vue')
).then(x => x.default)); ).then(x => x.default));
if (_DEV_) { if (_DEV_) {

View File

@ -2,6 +2,7 @@ import { computed, ref } from 'vue';
import { search } from '@client/scripts/search'; import { search } from '@client/scripts/search';
import * as os from '@client/os'; import * as os from '@client/os';
import { i18n } from '@client/i18n'; import { i18n } from '@client/i18n';
import { ui } from '@client/config';
import { $i } from './account'; import { $i } from './account';
import { unisonReload } from '@client/scripts/unison-reload'; import { unisonReload } from '@client/scripts/unison-reload';
import { router } from './router'; import { router } from './router';
@ -184,35 +185,40 @@ export const menuDef = {
action: (ev) => { action: (ev) => {
os.popupMenu([{ os.popupMenu([{
text: i18n.locale.default, text: i18n.locale.default,
active: ui === 'default' || ui === null,
action: () => { action: () => {
localStorage.setItem('ui', 'default'); localStorage.setItem('ui', 'default');
unisonReload(); unisonReload();
} }
}, { }, {
text: i18n.locale.deck, text: i18n.locale.deck,
active: ui === 'deck',
action: () => { action: () => {
localStorage.setItem('ui', 'deck'); localStorage.setItem('ui', 'deck');
unisonReload(); unisonReload();
} }
}, { }, {
text: 'pope', text: i18n.locale.classic,
active: ui === 'classic',
action: () => { action: () => {
localStorage.setItem('ui', 'pope'); localStorage.setItem('ui', 'classic');
unisonReload(); unisonReload();
} }
}, { }, {
text: 'Chat (β)', text: 'Chat (β)',
active: ui === 'chat',
action: () => { action: () => {
localStorage.setItem('ui', 'chat'); localStorage.setItem('ui', 'chat');
unisonReload(); unisonReload();
} }
}, { }, /*{
text: i18n.locale.desktop + ' (β)', text: i18n.locale.desktop + ' (β)',
active: ui === 'desktop',
action: () => { action: () => {
localStorage.setItem('ui', 'desktop'); localStorage.setItem('ui', 'desktop');
unisonReload(); unisonReload();
} }
}], ev.currentTarget || ev.target); }*/], ev.currentTarget || ev.target);
}, },
}, },
}; };

View File

@ -1,7 +1,5 @@
<template> <template>
<div> <div class="uqshojas">
<MkHeader :info="header"/>
<div class="uqshojas">
<section class="_card _gap ads" v-for="ad in ads"> <section class="_card _gap ads" v-for="ad in ads">
<div class="_content ad"> <div class="_content ad">
<MkAd v-if="ad.url" :specify="ad"/> <MkAd v-if="ad.url" :specify="ad"/>
@ -39,7 +37,6 @@
</div> </div>
</div> </div>
</section> </section>
</div>
</div> </div>
</template> </template>
@ -68,11 +65,6 @@ export default defineComponent({
title: this.$ts.ads, title: this.$ts.ads,
icon: 'fas fa-audio-description', icon: 'fas fa-audio-description',
bg: 'var(--bg)', bg: 'var(--bg)',
},
header: {
title: this.$ts.ads,
icon: 'fas fa-audio-description',
bg: 'var(--bg)',
actions: [{ actions: [{
asFullButton: true, asFullButton: true,
icon: 'fas fa-plus', icon: 'fas fa-plus',

View File

@ -1,8 +1,5 @@
<template> <template>
<div> <div class="ztgjmzrw">
<MkHeader :info="header"/>
<div class="ztgjmzrw">
<section class="_card _gap announcements" v-for="announcement in announcements"> <section class="_card _gap announcements" v-for="announcement in announcements">
<div class="_content announcement"> <div class="_content announcement">
<MkInput v-model="announcement.title"> <MkInput v-model="announcement.title">
@ -21,7 +18,6 @@
</div> </div>
</div> </div>
</section> </section>
</div>
</div> </div>
</template> </template>
@ -48,11 +44,6 @@ export default defineComponent({
title: this.$ts.announcements, title: this.$ts.announcements,
icon: 'fas fa-broadcast-tower', icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)', bg: 'var(--bg)',
},
header: {
title: this.$ts.announcements,
icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)',
actions: [{ actions: [{
asFullButton: true, asFullButton: true,
icon: 'fas fa-plus', icon: 'fas fa-plus',

View File

@ -1,7 +1,5 @@
<template> <template>
<div class="ogwlenmc"> <div class="ogwlenmc">
<MkHeader :info="header"/>
<div class="local" v-if="tab === 'local'"> <div class="local" v-if="tab === 'local'">
<MkInput v-model="query" :debounce="true" type="search" style="margin: var(--margin);"> <MkInput v-model="query" :debounce="true" type="search" style="margin: var(--margin);">
<template #prefix><i class="fas fa-search"></i></template> <template #prefix><i class="fas fa-search"></i></template>
@ -50,7 +48,7 @@
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineComponent } from 'vue'; import { computed, defineComponent, toRef } from 'vue';
import MkButton from '@client/components/ui/button.vue'; import MkButton from '@client/components/ui/button.vue';
import MkInput from '@client/components/form/input.vue'; import MkInput from '@client/components/form/input.vue';
import MkPagination from '@client/components/ui/pagination.vue'; import MkPagination from '@client/components/ui/pagination.vue';
@ -71,12 +69,7 @@ export default defineComponent({
data() { data() {
return { return {
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: computed(() => ({
title: this.$ts.customEmojis,
icon: 'fas fa-laugh',
bg: 'var(--bg)',
},
header: computed(() => ({
title: this.$ts.customEmojis, title: this.$ts.customEmojis,
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
bg: 'var(--bg)', bg: 'var(--bg)',
@ -119,7 +112,7 @@ export default defineComponent({
}, },
async mounted() { async mounted() {
this.$emit('info', this[symbols.PAGE_INFO]); this.$emit('info', toRef(this, symbols.PAGE_INFO));
}, },
methods: { methods: {
@ -175,6 +168,10 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.ogwlenmc { .ogwlenmc {
> .local { > .local {
.empty {
margin: var(--margin);
}
.ldhfsamy { .ldhfsamy {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
@ -217,6 +214,10 @@ export default defineComponent({
} }
> .remote { > .remote {
.empty {
margin: var(--margin);
}
.ldhfsamy { .ldhfsamy {
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));

View File

@ -3,7 +3,9 @@
<div class="nav" v-if="!narrow || page == null"> <div class="nav" v-if="!narrow || page == null">
<MkHeader :info="header"></MkHeader> <MkHeader :info="header"></MkHeader>
<MkSpacer :content-max="700">
<div class="lxpfedzu"> <div class="lxpfedzu">
<div class="banner">
<img :src="$instance.iconUrl || '/favicon.ico'" alt="" class="icon"/> <img :src="$instance.iconUrl || '/favicon.ico'" alt="" class="icon"/>
</div> </div>
@ -12,14 +14,19 @@
<MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu> <MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu>
</div> </div>
</MkSpacer>
</div>
<div class="main"> <div class="main">
<MkStickyContainer>
<template #header><MkHeader v-if="childInfo && !childInfo.hideHeader" :info="childInfo"/></template>
<component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/> <component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/>
</MkStickyContainer>
</div> </div>
</div> </div>
</template> </template>
<script lang="ts"> <script lang="ts">
import { computed, defineAsyncComponent, defineComponent, nextTick, onMounted, reactive, ref, watch } from 'vue'; import { computed, defineAsyncComponent, defineComponent, isRef, nextTick, onMounted, reactive, ref, watch } from 'vue';
import { i18n } from '@client/i18n'; import { i18n } from '@client/i18n';
import MkSuperMenu from '@client/components/ui/super-menu.vue'; import MkSuperMenu from '@client/components/ui/super-menu.vue';
import FormGroup from '@client/components/debobigego/group.vue'; import FormGroup from '@client/components/debobigego/group.vue';
@ -41,6 +48,10 @@ export default defineComponent({
MkInfo, MkInfo,
}, },
provide: {
shouldOmitHeaderTitle: false,
},
props: { props: {
initialPage: { initialPage: {
type: String, type: String,
@ -50,17 +61,25 @@ export default defineComponent({
setup(props, context) { setup(props, context) {
const indexInfo = { const indexInfo = {
title: i18n.locale.instance, title: i18n.locale.controlPanel,
icon: 'fas fa-cog', icon: 'fas fa-cog',
bg: 'var(--bg)', bg: 'var(--bg)',
hideHeader: true,
}; };
const INFO = ref(indexInfo); const INFO = ref(indexInfo);
const childInfo = ref(null);
const page = ref(props.initialPage); const page = ref(props.initialPage);
const narrow = ref(false); const narrow = ref(false);
const view = ref(null); const view = ref(null);
const el = ref(null); const el = ref(null);
const onInfo = (viewInfo) => { const onInfo = (viewInfo) => {
INFO.value = viewInfo; if (isRef(viewInfo)) {
watch(viewInfo, () => {
childInfo.value = viewInfo.value;
}, { immediate: true });
} else {
childInfo.value = viewInfo;
}
}; };
const pageProps = ref({}); const pageProps = ref({});
@ -306,7 +325,7 @@ export default defineComponent({
[symbols.PAGE_INFO]: INFO, [symbols.PAGE_INFO]: INFO,
menuDef, menuDef,
header: { header: {
title: i18n.locale.controllPanel, title: i18n.locale.controlPanel,
}, },
noMaintainerInformation, noMaintainerInformation,
noBotProtection, noBotProtection,
@ -315,6 +334,7 @@ export default defineComponent({
view, view,
el, el,
onInfo, onInfo,
childInfo,
pageProps, pageProps,
component, component,
invite, invite,
@ -343,18 +363,16 @@ export default defineComponent({
> .main { > .main {
flex: 1; flex: 1;
min-width: 0; min-width: 0;
--baseContentWidth: 100%;
} }
} }
> .nav { > .nav {
.lxpfedzu {
> .info { > .info {
margin: 16px; margin: 16px 0;
} }
}
}
.lxpfedzu { > .banner {
margin: 16px; margin: 16px;
> .icon { > .icon {
@ -363,5 +381,8 @@ export default defineComponent({
height: 42px; height: 42px;
border-radius: 8px; border-radius: 8px;
} }
}
}
}
} }
</style> </style>

View File

@ -1,8 +1,5 @@
<template> <template>
<div> <div class="edbbcaef" v-size="{ max: [740] }">
<MkHeader :info="header"/>
<div class="edbbcaef" v-size="{ max: [880] }">
<div v-if="stats" class="cfcdecdf" style="margin: var(--margin)"> <div v-if="stats" class="cfcdecdf" style="margin: var(--margin)">
<div class="number _panel"> <div class="number _panel">
<div class="label">Users</div> <div class="label">Users</div>
@ -65,7 +62,6 @@
</div> </div>
</div> </div>
</MkFolder> </MkFolder>
</div>
</div> </div>
</template> </template>
@ -107,10 +103,6 @@ export default defineComponent({
icon: 'fas fa-tachometer-alt', icon: 'fas fa-tachometer-alt',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.dashboard,
icon: 'fas fa-tachometer-alt',
},
version, version,
vueVersion, vueVersion,
url, url,
@ -225,12 +217,14 @@ export default defineComponent({
} }
} }
&.max-width_800px { &.max-width_740px {
> .queue { > .queue {
display: block; display: block;
> .deliver, > .deliver,
> .inbox { > .inbox {
width: 100%;
&:not(:first-child) { &:not(:first-child) {
margin-top: var(--margin); margin-top: var(--margin);
margin-left: 0; margin-left: 0;

View File

@ -1,7 +1,5 @@
<template> <template>
<div class="lknzcolw"> <div class="lknzcolw">
<MkHeader :info="header"/>
<div class="users"> <div class="users">
<div class="inputs"> <div class="inputs">
<MkSelect v-model="sort" style="flex: 1;"> <MkSelect v-model="sort" style="flex: 1;">
@ -90,11 +88,6 @@ export default defineComponent({
title: this.$ts.users, title: this.$ts.users,
icon: 'fas fa-users', icon: 'fas fa-users',
bg: 'var(--bg)', bg: 'var(--bg)',
},
header: {
title: this.$ts.users,
icon: 'fas fa-users',
bg: 'var(--bg)',
actions: [{ actions: [{
icon: 'fas fa-search', icon: 'fas fa-search',
text: this.$ts.search, text: this.$ts.search,
@ -109,7 +102,7 @@ export default defineComponent({
icon: 'fas fa-search', icon: 'fas fa-search',
text: this.$ts.lookup, text: this.$ts.lookup,
handler: this.lookupUser handler: this.lookupUser
}] }],
}, },
sort: '+createdAt', sort: '+createdAt',
state: 'all', state: 'all',

View File

@ -1,9 +1,7 @@
<template> <template>
<div> <MkSpacer :content-max="800">
<MkHeader :info="header"/>
<div class="_section">
<MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content"> <MkPagination :pagination="pagination" #default="{items}" class="ruryvtyk _content">
<section class="_card announcement _gap" v-for="(announcement, i) in items" :key="announcement.id"> <section class="_card announcement" v-for="(announcement, i) in items" :key="announcement.id">
<div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div> <div class="_title"><span v-if="$i && !announcement.isRead">🆕 </span>{{ announcement.title }}</div>
<div class="_content"> <div class="_content">
<Mfm :text="announcement.text"/> <Mfm :text="announcement.text"/>
@ -14,8 +12,7 @@
</div> </div>
</section> </section>
</MkPagination> </MkPagination>
</div> </MkSpacer>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -38,11 +35,6 @@ export default defineComponent({
icon: 'fas fa-broadcast-tower', icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.announcements,
icon: 'fas fa-broadcast-tower',
bg: 'var(--bg)',
},
pagination: { pagination: {
endpoint: 'announcements', endpoint: 'announcements',
limit: 10, limit: 10,
@ -66,6 +58,10 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.ruryvtyk { .ruryvtyk {
> .announcement { > .announcement {
&:not(:last-child) {
margin-bottom: var(--margin);
}
> ._content { > ._content {
> img { > img {
display: block; display: block;

View File

@ -1,9 +1,6 @@
<template> <template>
<div> <div :class="$style.root">
<MkHeader :info="header"/>
<div :class="$style.root">
<XCategory v-if="tab === 'category'"/> <XCategory v-if="tab === 'category'"/>
</div>
</div> </div>
</template> </template>
@ -25,11 +22,6 @@ export default defineComponent({
icon: 'fas fa-laugh', icon: 'fas fa-laugh',
bg: 'var(--bg)', bg: 'var(--bg)',
})), })),
header: computed(() => ({
title: this.$ts.customEmojis,
icon: 'fas fa-laugh',
bg: 'var(--bg)',
})),
tab: 'category', tab: 'category',
} }
}, },

View File

@ -1,7 +1,5 @@
<template> <template>
<div> <div>
<MkHeader :info="header"/>
<MkSpacer :content-max="1200"> <MkSpacer :content-max="1200">
<div class="lznhrdub"> <div class="lznhrdub">
<div v-if="tab === 'local'"> <div v-if="tab === 'local'">
@ -110,13 +108,7 @@ export default defineComponent({
data() { data() {
return { return {
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: computed(() => ({
title: this.$ts.explore,
icon: 'fas fa-hashtag',
bg: 'var(--bg)',
},
tab: 'local',
header: computed(() => ({
title: this.$ts.explore, title: this.$ts.explore,
icon: 'fas fa-hashtag', icon: 'fas fa-hashtag',
bg: 'var(--bg)', bg: 'var(--bg)',
@ -134,6 +126,7 @@ export default defineComponent({
onClick: () => { this.tab = 'search'; }, onClick: () => { this.tab = 'search'; },
},] },]
})), })),
tab: 'local',
pinnedUsers: { endpoint: 'pinned-users' }, pinnedUsers: { endpoint: 'pinned-users' },
popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: { popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: {
state: 'alive', state: 'alive',

View File

@ -1,11 +1,8 @@
<template> <template>
<div> <div class="jmelgwjh">
<MkHeader :info="header"/>
<div class="jmelgwjh">
<div class="body"> <div class="body">
<XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/> <XNotes class="notes" :pagination="pagination" :detail="true" :prop="'note'" @before="before()" @after="after()"/>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -28,11 +25,6 @@ export default defineComponent({
icon: 'fas fa-star', icon: 'fas fa-star',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.favorites,
icon: 'fas fa-star',
bg: 'var(--bg)',
},
pagination: { pagination: {
endpoint: 'i/favorites', endpoint: 'i/favorites',
limit: 10, limit: 10,

View File

@ -1,10 +1,7 @@
<template> <template>
<div> <MkSpacer :content-max="800">
<MkHeader :info="header"/> <XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
<div class="_section"> </MkSpacer>
<XNotes class="_content" ref="notes" :pagination="pagination" @before="before" @after="after"/>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -25,11 +22,6 @@ export default defineComponent({
icon: 'fas fa-fire-alt', icon: 'fas fa-fire-alt',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.featured,
icon: 'fas fa-fire-alt',
bg: 'var(--bg)',
},
pagination: { pagination: {
endpoint: 'notes/featured', endpoint: 'notes/featured',
limit: 10, limit: 10,

View File

@ -1,7 +1,5 @@
<template> <template>
<div> <div class="taeiyria">
<MkHeader :info="header"/>
<div class="taeiyria">
<div class="query"> <div class="query">
<MkInput v-model="host" :debounce="true" class=""> <MkInput v-model="host" :debounce="true" class="">
<template #prefix><i class="fas fa-search"></i></template> <template #prefix><i class="fas fa-search"></i></template>
@ -92,7 +90,6 @@
</MkA> </MkA>
</div> </div>
</MkPagination> </MkPagination>
</div>
</div> </div>
</template> </template>
@ -122,11 +119,6 @@ export default defineComponent({
icon: 'fas fa-globe', icon: 'fas fa-globe',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.federation,
icon: 'fas fa-globe',
bg: 'var(--bg)',
},
host: '', host: '',
state: 'federating', state: 'federating',
sort: '+pubSub', sort: '+pubSub',

View File

@ -1,10 +1,7 @@
<template> <template>
<div> <MkSpacer :content-max="800">
<MkHeader :info="header"/> <XNotes :pagination="pagination" @before="before()" @after="after()"/>
<div class="_section"> </MkSpacer>
<XNotes class="_content" :pagination="pagination" @before="before()" @after="after()"/>
</div>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -25,11 +22,6 @@ export default defineComponent({
icon: 'fas fa-at', icon: 'fas fa-at',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.mentions,
icon: 'fas fa-at',
bg: 'var(--bg)',
},
pagination: { pagination: {
endpoint: 'notes/mentions', endpoint: 'notes/mentions',
limit: 10, limit: 10,

View File

@ -1,10 +1,7 @@
<template> <template>
<div> <MkSpacer :content-max="800">
<MkHeader :info="header"/>
<div>
<XNotes :pagination="pagination" @before="before()" @after="after()"/> <XNotes :pagination="pagination" @before="before()" @after="after()"/>
</div> </MkSpacer>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -25,11 +22,6 @@ export default defineComponent({
icon: 'fas fa-envelope', icon: 'fas fa-envelope',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.directNotes,
icon: 'fas fa-envelope',
bg: 'var(--bg)',
},
pagination: { pagination: {
endpoint: 'notes/mentions', endpoint: 'notes/mentions',
limit: 10, limit: 10,

View File

@ -1,8 +1,6 @@
<template> <template>
<div> <MkSpacer :content-max="800">
<MkHeader :info="header"/> <div class="yweeujhr" v-size="{ max: [400] }">
<div class="yweeujhr _root" v-size="{ max: [400] }">
<MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton> <MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton>
<div class="history" v-if="messages.length > 0"> <div class="history" v-if="messages.length > 0">
@ -37,7 +35,7 @@
</div> </div>
<MkLoading v-if="fetching"/> <MkLoading v-if="fetching"/>
</div> </div>
</div> </MkSpacer>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -60,11 +58,6 @@ export default defineComponent({
icon: 'fas fa-comments', icon: 'fas fa-comments',
bg: 'var(--bg)', bg: 'var(--bg)',
}, },
header: {
title: this.$ts.messaging,
icon: 'fas fa-comments',
bg: 'var(--bg)',
},
fetching: true, fetching: true,
moreFetching: false, moreFetching: false,
messages: [], messages: [],
@ -177,7 +170,7 @@ export default defineComponent({
.yweeujhr { .yweeujhr {
> .start { > .start {
margin: var(--margin) auto var(--margin) auto; margin: 0 auto var(--margin) auto;
} }
> .history { > .history {

View File

@ -1,7 +1,5 @@
<template> <template>
<div> <div class="qkcjvfiv">
<MkHeader :info="header"/>
<div class="qkcjvfiv">
<MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton> <MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton>
<MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list"> <MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list">
@ -10,7 +8,6 @@
<MkAvatars :user-ids="list.userIds"/> <MkAvatars :user-ids="list.userIds"/>
</MkA> </MkA>
</MkPagination> </MkPagination>
</div>
</div> </div>
</template> </template>
@ -35,15 +32,10 @@ export default defineComponent({
title: this.$ts.manageLists, title: this.$ts.manageLists,
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
bg: 'var(--bg)', bg: 'var(--bg)',
},
header: {
title: this.$ts.manageLists,
icon: 'fas fa-list-ul',
bg: 'var(--bg)',
action: { action: {
icon: 'fas fa-plus', icon: 'fas fa-plus',
handler: this.create handler: this.create
} },
}, },
pagination: { pagination: {
endpoint: 'users/lists/list', endpoint: 'users/lists/list',

View File

@ -1,7 +1,5 @@
<template> <template>
<div> <div class="mk-list-page">
<MkHeader v-if="header" :info="header"/>
<div class="mk-list-page">
<transition name="zoom" mode="out-in"> <transition name="zoom" mode="out-in">
<div v-if="list" class="_section"> <div v-if="list" class="_section">
<div class="_content"> <div class="_content">
@ -31,7 +29,6 @@
</div> </div>
</div> </div>
</transition> </transition>
</div>
</div> </div>
</template> </template>
@ -53,10 +50,6 @@ export default defineComponent({
title: this.list.name, title: this.list.name,
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
} : null), } : null),
header: computed(() => this.list ? {
title: this.list.name,
icon: 'fas fa-list-ul',
} : null),
list: null, list: null,
users: [], users: [],
}; };

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="fcuexfpr"> <MkSpacer :content-max="800">
<div class="_root"> <div class="fcuexfpr">
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
<div v-if="note" class="note"> <div v-if="note" class="note">
<div class="_gap" v-if="showNext"> <div class="_gap" v-if="showNext">
@ -34,7 +34,7 @@
<MkLoading v-else/> <MkLoading v-else/>
</transition> </transition>
</div> </div>
</div> </MkSpacer>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -153,7 +153,6 @@ export default defineComponent({
.fcuexfpr { .fcuexfpr {
background: var(--bg); background: var(--bg);
> ._root {
> .note { > .note {
> .main { > .main {
> .load { > .load {
@ -206,6 +205,5 @@ export default defineComponent({
} }
} }
} }
}
} }
</style> </style>

View File

@ -1,12 +1,9 @@
<template> <template>
<div> <MkSpacer :content-max="800">
<MkHeader :info="header"/>
<MkSpacer :content-max="800">
<div class="clupoqwt"> <div class="clupoqwt">
<XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/> <XNotifications class="notifications" @before="before" @after="after" :include-types="includeTypes" :unread-only="tab === 'unread'"/>
</div> </div>
</MkSpacer> </MkSpacer>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -24,14 +21,7 @@ export default defineComponent({
data() { data() {
return { return {
[symbols.PAGE_INFO]: { [symbols.PAGE_INFO]: computed(() => ({
title: this.$ts.notifications,
icon: 'fas fa-bell',
bg: 'var(--bg)',
},
tab: 'all',
includeTypes: null,
header: computed(() => ({
title: this.$ts.notifications, title: this.$ts.notifications,
icon: 'fas fa-bell', icon: 'fas fa-bell',
bg: 'var(--bg)', bg: 'var(--bg)',
@ -57,6 +47,8 @@ export default defineComponent({
onClick: () => { this.tab = 'unread'; }, onClick: () => { this.tab = 'unread'; },
},] },]
})), })),
tab: 'all',
includeTypes: null,
}; };
}, },

View File

@ -1,8 +1,5 @@
<template> <template>
<div> <div>
<MkHeader :info="header"/>
<div class="_root">
<div class="jqqmcavi" style="margin: 16px;"> <div class="jqqmcavi" style="margin: 16px;">
<MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton> <MkButton v-if="pageId" class="button" inline link :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkButton>
<MkButton inline @click="save" primary class="button" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton> <MkButton inline @click="save" primary class="button" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
@ -78,7 +75,6 @@
<MkTextarea class="_code" v-model="script"/> <MkTextarea class="_code" v-model="script"/>
</div> </div>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -131,21 +127,6 @@ export default defineComponent({
data() { data() {
return { return {
[symbols.PAGE_INFO]: computed(() => { [symbols.PAGE_INFO]: computed(() => {
let title = this.$ts._pages.newPage;
if (this.initPageId) {
title = this.$ts._pages.editPage;
}
else if (this.initPageName && this.initUser) {
title = this.$ts._pages.readPage;
}
return {
title: title,
icon: 'fas fa-pencil-alt',
bg: 'var(--bg)',
};
}),
tab: 'settings',
header: computed(() => {
let title = this.$ts._pages.newPage; let title = this.$ts._pages.newPage;
if (this.initPageId) { if (this.initPageId) {
title = this.$ts._pages.editPage; title = this.$ts._pages.editPage;
@ -177,9 +158,10 @@ export default defineComponent({
title: this.$ts.script, title: this.$ts.script,
icon: 'fas fa-code', icon: 'fas fa-code',
onClick: () => { this.tab = 'script'; }, onClick: () => { this.tab = 'script'; },
}] }],
}; };
}), }),
tab: 'settings',
author: this.$i, author: this.$i,
readonly: false, readonly: false,
page: null, page: null,

View File

@ -1,8 +1,5 @@
<template> <template>
<div> <div>
<MkHeader :info="header"/>
<div class="_root">
<transition name="fade" mode="out-in"> <transition name="fade" mode="out-in">
<div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }"> <div v-if="page" class="xcukqgmh" :key="page.id" v-size="{ max: [450] }">
<div class="_block main"> <div class="_block main">
@ -59,7 +56,6 @@
<MkError v-else-if="error" @retry="fetch()"/> <MkError v-else-if="error" @retry="fetch()"/>
<MkLoading v-else/> <MkLoading v-else/>
</transition> </transition>
</div>
</div> </div>
</template> </template>
@ -101,10 +97,6 @@ export default defineComponent({
[symbols.PAGE_INFO]: computed(() => this.page ? { [symbols.PAGE_INFO]: computed(() => this.page ? {
title: computed(() => this.page.title || this.page.name), title: computed(() => this.page.title || this.page.name),
avatar: this.page.user, avatar: this.page.user,
} : null),
header: computed(() => this.page ? {
title: computed(() => this.page.title || this.page.name),
avatar: this.page.user,
path: `/@${this.page.user.username}/pages/${this.page.name}`, path: `/@${this.page.user.username}/pages/${this.page.name}`,
share: { share: {
title: this.page.title || this.page.name, title: this.page.title || this.page.name,

View File

@ -1,8 +1,5 @@
<template> <template>
<div> <MkSpacer>
<MkHeader :info="header"/>
<MkSpacer>
<!-- TODO: MkHeaderに統合 --> <!-- TODO: MkHeaderに統合 -->
<MkTab v-model="tab" v-if="$i"> <MkTab v-model="tab" v-if="$i">
<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option> <option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option>
@ -30,8 +27,7 @@
</MkPagination> </MkPagination>
</div> </div>
</div> </div>
</MkSpacer> </MkSpacer>
</div>
</template> </template>
<script lang="ts"> <script lang="ts">
@ -52,11 +48,6 @@ export default defineComponent({
title: this.$ts.pages, title: this.$ts.pages,
icon: 'fas fa-sticky-note', icon: 'fas fa-sticky-note',
bg: 'var(--bg)', bg: 'var(--bg)',
},
header: {
title: this.$ts.pages,
icon: 'fas fa-sticky-note',
bg: 'var(--bg)',
actions: [{ actions: [{
icon: 'fas fa-plus', icon: 'fas fa-plus',
text: this.$ts.create, text: this.$ts.create,

View File

@ -1,11 +1,8 @@
<template> <template>
<div> <div class="_section">
<MkHeader :info="header"/>
<div class="_section">
<div class="_content"> <div class="_content">
<XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/> <XNotes ref="notes" :pagination="pagination" @before="before" @after="after"/>
</div> </div>
</div>
</div> </div>
</template> </template>
@ -26,10 +23,6 @@ export default defineComponent({
title: computed(() => this.$t('searchWith', { q: this.$route.query.q })), title: computed(() => this.$t('searchWith', { q: this.$route.query.q })),
icon: 'fas fa-search', icon: 'fas fa-search',
}, },
header: {
title: computed(() => this.$t('searchWith', { q: this.$route.query.q })),
icon: 'fas fa-search',
},
pagination: { pagination: {
endpoint: 'notes/search', endpoint: 'notes/search',
limit: 10, limit: 10,

View File

@ -35,7 +35,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import * as tinycolor from 'tinycolor2'; import * as tinycolor from 'tinycolor2';
import ApexCharts from 'apexcharts';
import FormButton from '@client/components/debobigego/button.vue'; import FormButton from '@client/components/debobigego/button.vue';
import FormGroup from '@client/components/debobigego/group.vue'; import FormGroup from '@client/components/debobigego/group.vue';
import FormKeyValueView from '@client/components/debobigego/key-value-view.vue'; import FormKeyValueView from '@client/components/debobigego/key-value-view.vue';
@ -44,6 +43,8 @@ import * as os from '@client/os';
import bytes from '@client/filters/bytes'; import bytes from '@client/filters/bytes';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';
// TODO: render chart
export default defineComponent({ export default defineComponent({
components: { components: {
FormBase, FormBase,
@ -117,104 +118,6 @@ export default defineComponent({
}); });
}, },
renderChart() {
os.api('charts/user/drive', {
userId: this.$i.id,
span: 'day',
limit: 21
}).then(stats => {
const addition = [];
const deletion = [];
const now = new Date();
const y = now.getFullYear();
const m = now.getMonth();
const d = now.getDate();
for (let i = 0; i < 21; i++) {
const x = new Date(y, m, d - i);
addition.push([
x,
stats.incSize[i]
]);
deletion.push([
x,
-stats.decSize[i]
]);
}
const chart = new ApexCharts(this.$refs.chart, {
chart: {
type: 'bar',
stacked: true,
height: 150,
toolbar: {
show: false
},
zoom: {
enabled: false
}
},
plotOptions: {
bar: {
columnWidth: '80%'
}
},
grid: {
clipMarkers: false,
borderColor: 'rgba(0, 0, 0, 0.1)',
xaxis: {
lines: {
show: true,
}
},
},
tooltip: {
shared: true,
intersect: false,
theme: this.$store.state.darkMode ? 'dark' : 'light',
},
dataLabels: {
enabled: false
},
legend: {
show: false
},
series: [{
name: 'Additions',
data: addition
}, {
name: 'Deletions',
data: deletion
}],
xaxis: {
type: 'datetime',
labels: {
style: {
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--fg')).toRgbString()
}
},
axisBorder: {
color: 'rgba(0, 0, 0, 0.1)'
},
axisTicks: {
color: 'rgba(0, 0, 0, 0.1)'
},
crosshairs: {
width: 1,
opacity: 1
}
},
yaxis: {
labels: {
formatter: v => bytes(v, 0),
style: {
colors: tinycolor(getComputedStyle(document.documentElement).getPropertyValue('--fg')).toRgbString()
}
}
}
});
chart.render();
});
},
bytes bytes
} }
}); });

View File

@ -1,10 +1,14 @@
<template> <template>
<div class="vvcocwet" :class="{ wide: !narrow }" ref="el"> <div class="vvcocwet" :class="{ wide: !narrow }" ref="el">
<div class="nav" v-if="!narrow || page == null"> <div class="nav" v-if="!narrow || page == null">
<MkSpacer :content-max="700">
<div class="baaadecd">
<div class="title">{{ $ts.settings }}</div> <div class="title">{{ $ts.settings }}</div>
<MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo> <MkInfo v-if="emailNotConfigured" warn class="info">{{ $ts.emailNotConfiguredWarning }} <MkA to="/settings/email" class="_link">{{ $ts.configure }}</MkA></MkInfo>
<MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu> <MkSuperMenu :def="menuDef" :grid="page == null"></MkSuperMenu>
</div> </div>
</MkSpacer>
</div>
<div class="main"> <div class="main">
<component :is="component" :key="page" v-bind="pageProps"/> <component :is="component" :key="page" v-bind="pageProps"/>
</div> </div>
@ -41,6 +45,7 @@ export default defineComponent({
title: i18n.locale.settings, title: i18n.locale.settings,
icon: 'fas fa-cog', icon: 'fas fa-cog',
bg: 'var(--bg)', bg: 'var(--bg)',
hideHeader: true,
}; };
const INFO = ref(indexInfo); const INFO = ref(indexInfo);
const page = ref(props.initialPage); const page = ref(props.initialPage);
@ -271,6 +276,7 @@ export default defineComponent({
<style lang="scss" scoped> <style lang="scss" scoped>
.vvcocwet { .vvcocwet {
> .nav { > .nav {
.baaadecd {
> .title { > .title {
margin: 16px; margin: 16px;
font-size: 1.5em; font-size: 1.5em;
@ -290,6 +296,7 @@ export default defineComponent({
} }
} }
} }
}
&.wide { &.wide {
display: flex; display: flex;
@ -302,8 +309,10 @@ export default defineComponent({
box-sizing: border-box; box-sizing: border-box;
overflow: auto; overflow: auto;
.baaadecd {
> .title { > .title {
margin: 24px; margin: 24px 0;
}
} }
} }
@ -311,7 +320,6 @@ export default defineComponent({
flex: 1; flex: 1;
min-width: 0; min-width: 0;
overflow: auto; overflow: auto;
--baseContentWidth: 100%;
} }
} }
} }

View File

@ -1,7 +1,5 @@
<template> <template>
<div v-hotkey.global="keymap"> <div class="cmuxhskf" v-size="{ min: [800] }" v-hotkey.global="keymap">
<MkHeader :info="header"/>
<div class="cmuxhskf" v-size="{ min: [800] }">
<XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/> <XTutorial v-if="$store.reactiveState.tutorial.value != -1" class="tutorial _block"/>
<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/> <XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/>
@ -16,7 +14,6 @@
@queue="queueUpdated" @queue="queueUpdated"
/> />
</div> </div>
</div>
</div> </div>
</template> </template>
@ -46,11 +43,6 @@ export default defineComponent({
title: this.$ts.timeline, title: this.$ts.timeline,
icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home', icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home',
bg: 'var(--bg)', bg: 'var(--bg)',
})),
header: computed(() => ({
title: this.$ts.timeline,
icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home',
bg: 'var(--bg)',
actions: [{ actions: [{
icon: 'fas fa-list-ul', icon: 'fas fa-list-ul',
text: this.$ts.lists, text: this.$ts.lists,
@ -92,7 +84,7 @@ export default defineComponent({
icon: 'fas fa-globe', icon: 'fas fa-globe',
iconOnly: true, iconOnly: true,
onClick: () => { this.src = 'global'; this.saveSrc(); }, onClick: () => { this.src = 'global'; this.saveSrc(); },
}] }],
})), })),
}; };
}, },

View File

@ -3,20 +3,21 @@
<template #header><i class="fas fa-chart-bar" style="margin-right: 0.5em;"></i>{{ $ts.activity }}</template> <template #header><i class="fas fa-chart-bar" style="margin-right: 0.5em;"></i>{{ $ts.activity }}</template>
<div style="padding: 8px;"> <div style="padding: 8px;">
<div ref="chart"></div> <MkChart src="per-user-notes" :args="{ user, withoutAll: true }" span="day" :limit="limit" :stacked="true" :detailed="false" :aspect-ratio="6"/>
</div> </div>
</MkContainer> </MkContainer>
</template> </template>
<script lang="ts"> <script lang="ts">
import { defineComponent } from 'vue'; import { defineComponent } from 'vue';
import ApexCharts from 'apexcharts';
import * as os from '@client/os'; import * as os from '@client/os';
import MkContainer from '@client/components/ui/container.vue'; import MkContainer from '@client/components/ui/container.vue';
import MkChart from '@client/components/chart.vue';
export default defineComponent({ export default defineComponent({
components: { components: {
MkContainer, MkContainer,
MkChart,
}, },
props: { props: {
user: { user: {
@ -29,96 +30,5 @@ export default defineComponent({
default: 40 default: 40
} }
}, },
data() {
return {
fetching: true,
data: [],
peak: null,
};
},
mounted() {
os.api('charts/user/notes', {
userId: this.user.id,
span: 'day',
limit: this.limit
}).then(stats => {
const normal = [];
const reply = [];
const renote = [];
const now = new Date();
const y = now.getFullYear();
const m = now.getMonth();
const d = now.getDate();
for (let i = 0; i < this.limit; i++) {
const x = new Date(y, m, d - i);
normal.push([
x,
stats.diffs.normal[i]
]);
reply.push([
x,
stats.diffs.reply[i]
]);
renote.push([
x,
stats.diffs.renote[i]
]);
}
const chart = new ApexCharts(this.$refs.chart, {
chart: {
type: 'bar',
stacked: true,
height: 100,
sparkline: {
enabled: true
},
},
plotOptions: {
bar: {
columnWidth: '40%'
}
},
dataLabels: {
enabled: false
},
grid: {
clipMarkers: false,
padding: {
top: 0,
right: 8,
bottom: 0,
left: 8
}
},
tooltip: {
shared: true,
intersect: false,
theme: this.$store.state.darkMode ? 'dark' : 'light',
},
series: [{
name: 'Normal',
data: normal
}, {
name: 'Reply',
data: reply
}, {
name: 'Renote',
data: renote
}],
xaxis: {
type: 'datetime',
crosshairs: {
width: 1,
opacity: 1
}
}
});
chart.render();
});
}
}); });
</script> </script>

View File

@ -65,11 +65,4 @@ export default defineComponent({
background: var(--bg); background: var(--bg);
} }
} }
._fitSide_ .yrzkoczt {
> .tab {
padding-left: var(--margin);
padding-right: var(--margin);
}
}
</style> </style>

View File

@ -1,7 +1,6 @@
<template> <template>
<div> <div>
<MkHeader :info="header"/> <transition name="fade" mode="out-in">
<transition name="fade" mode="out-in">
<div class="ftskorzw wide" v-if="user && narrow === false"> <div class="ftskorzw wide" v-if="user && narrow === false">
<MkRemoteCaution v-if="user.host != null" :href="user.url"/> <MkRemoteCaution v-if="user.host != null" :href="user.url"/>
@ -81,7 +80,8 @@
</div> </div>
</div> </div>
</div> </div>
<div class="ftskorzw narrow _root" v-else-if="user && narrow === true" v-size="{ max: [500] }"> <MkSpacer v-else-if="user && narrow === true" :content-max="800">
<div class="ftskorzw narrow" v-size="{ max: [500] }">
<!-- TODO --> <!-- TODO -->
<!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSuspended }}</div> --> <!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSuspended }}</div> -->
<!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSilenced }}</div> --> <!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSilenced }}</div> -->
@ -173,7 +173,7 @@
</div> </div>
<MkInfo v-else-if="$i && $i.id === user.id">{{ $ts.userPagePinTip }}</MkInfo> <MkInfo v-else-if="$i && $i.id === user.id">{{ $ts.userPagePinTip }}</MkInfo>
<XPhotos :user="user" :key="user.id"/> <XPhotos :user="user" :key="user.id"/>
<XActivity :user="user" :key="user.id"/> <XActivity :user="user" :key="user.id" style="margin-top: var(--margin);"/>
</div> </div>
<div> <div>
<XUserTimeline :user="user"/> <XUserTimeline :user="user"/>
@ -187,9 +187,10 @@
<XGallery v-else-if="page === 'gallery'" :user="user" class="_gap"/> <XGallery v-else-if="page === 'gallery'" :user="user" class="_gap"/>
</div> </div>
</div> </div>
</MkSpacer>
<MkError v-else-if="error" @retry="fetch()"/> <MkError v-else-if="error" @retry="fetch()"/>
<MkLoading v-else/> <MkLoading v-else/>
</transition> </transition>
</div> </div>
</template> </template>
@ -248,14 +249,6 @@ export default defineComponent({
return { return {
[symbols.PAGE_INFO]: computed(() => this.user ? { [symbols.PAGE_INFO]: computed(() => this.user ? {
icon: 'fas fa-user', icon: 'fas fa-user',
title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`,
path: `/@${this.user.username}`,
share: {
title: this.user.name,
},
bg: 'var(--bg)',
} : null),
header: computed(() => this.user ? {
title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`, title: this.user.name ? `${this.user.name} (@${this.user.username})` : `@${this.user.username}`,
subtitle: `@${getAcct(this.user)}`, subtitle: `@${getAcct(this.user)}`,
userName: this.user, userName: this.user,
@ -290,7 +283,7 @@ export default defineComponent({
title: this.$ts.gallery, title: this.$ts.gallery,
icon: 'fas fa-icons', icon: 'fas fa-icons',
onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/gallery'); }, onClick: () => { this.$router.push('/@' + getAcct(this.user) + '/gallery'); },
}] }],
} : null), } : null),
user: null, user: null,
error: null, error: null,
@ -833,16 +826,4 @@ export default defineComponent({
} }
} }
} }
._fitSide_ .ftskorzw.narrow {
> .profile {
> .warn {
margin: 0;
}
> .main {
margin-top: 0;
}
}
}
</style> </style>

View File

@ -0,0 +1,11 @@
export function getUrlWithLoginId(url: string, loginId: string) {
const u = new URL(url, origin);
u.searchParams.append('loginId', loginId);
return u.toString();
}
export function getUrlWithoutLoginId(url: string) {
const u = new URL(url);
u.searchParams.delete('loginId');
return u.toString();
}

View File

@ -144,7 +144,7 @@ export const defaultStore = markRaw(new Storage('base', {
}, },
useBlurEffect: { useBlurEffect: {
where: 'device', where: 'device',
default: false default: true
}, },
showFixedPostForm: { showFixedPostForm: {
where: 'device', where: 'device',

View File

@ -1,7 +1,6 @@
@charset "utf-8"; @charset "utf-8";
:root { :root {
--baseContentWidth: 760px;
--radius: 12px; --radius: 12px;
--marginFull: 16px; --marginFull: 16px;
--marginHalf: 10px; --marginHalf: 10px;
@ -350,21 +349,6 @@ hr {
} }
// TODO: 廃止 // TODO: 廃止
._root {
box-sizing: border-box;
margin: var(--root-margin, 32px) auto;
max-width: min(var(--baseContentWidth), calc(100% - (var(--root-margin, 32px) * 2)));
// 子marginが突き抜けるのを防ぐため
// https://stackoverflow.com/questions/1762539/margin-on-child-element-moves-parent-element
padding-top: 1px;
margin-top: calc(var(--root-margin, 32px) - 1px);
@media (max-width: 500px) {
--root-margin: 10px;
}
}
._monolithic_ { ._monolithic_ {
._section:not(:empty) { ._section:not(:empty) {
box-sizing: border-box; box-sizing: border-box;
@ -380,33 +364,6 @@ hr {
} }
} }
._fitSide_ {
--root-margin: 0px;
--baseContentWidth: 100%;
--panelBorder: none;
._block {
//border-top: solid 0.5px var(--divider);
//border-bottom: solid 0.5px var(--divider);
border-radius: 0;
box-shadow: none;
}
._isolated {
margin: var(--margin);
}
._block._isolated {
border-radius: var(--radius);
}
@media (max-width: 500px) {
._root {
--root-margin: 0px;
}
}
}
._narrow_ ._card { ._narrow_ ._card {
> ._title { > ._title {
padding: 16px; padding: 16px;

View File

@ -15,5 +15,6 @@
navBg: '#fff', navBg: '#fff',
panel: '#fff', panel: '#fff',
panelHeaderDivider: '@divider', panelHeaderDivider: '@divider',
mentionMe: 'rgb(0, 179, 70)',
}, },
} }

View File

@ -26,7 +26,7 @@
</template> </template>
<div class="divider"></div> <div class="divider"></div>
<MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" v-click-anime> <MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" v-click-anime>
<i class="fas fa-server fa-fw"></i><span class="text">{{ $ts.instance }}</span> <i class="fas fa-door-open fa-fw"></i><span class="text">{{ $ts.controlPanel }}</span>
</MkA> </MkA>
<button class="item _button" @click="more" v-click-anime> <button class="item _button" @click="more" v-click-anime>
<i class="fa fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span> <i class="fa fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span>
@ -35,7 +35,7 @@
<MkA class="item" active-class="active" to="/settings" v-click-anime> <MkA class="item" active-class="active" to="/settings" v-click-anime>
<i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span> <i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span>
</MkA> </MkA>
<button class="item _button post" @click="post"> <button class="item _button post" @click="post" data-cy-open-post-form>
<i class="fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span> <i class="fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span>
</button> </button>
</div> </div>

View File

@ -3,7 +3,7 @@
<header class="header" @contextmenu.prevent.stop="onContextmenu"> <header class="header" @contextmenu.prevent.stop="onContextmenu">
<MkHeader class="title" :info="pageInfo" :center="false"/> <MkHeader class="title" :info="pageInfo" :center="false"/>
</header> </header>
<component :is="component" v-bind="props" :ref="changePage" class="body _fitSide_"/> <component :is="component" v-bind="props" :ref="changePage" class="body"/>
</div> </div>
</template> </template>

View File

@ -13,8 +13,8 @@
</component> </component>
</template> </template>
<div class="divider"></div> <div class="divider"></div>
<MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime v-tooltip="$ts.instance"> <MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime v-tooltip="$ts.controlPanel">
<i class="fas fa-server fa-fw"></i> <i class="fas fa-door-open fa-fw"></i>
</MkA> </MkA>
<button class="item _button" @click="more" v-click-anime> <button class="item _button" @click="more" v-click-anime>
<i class="fas fa-ellipsis-h fa-fw"></i> <i class="fas fa-ellipsis-h fa-fw"></i>

View File

@ -21,7 +21,7 @@
</template> </template>
<div class="divider"></div> <div class="divider"></div>
<MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime> <MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/admin" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime>
<i class="fas fa-server fa-fw"></i><span class="text">{{ $ts.instance }}</span> <i class="fas fa-door-open fa-fw"></i><span class="text">{{ $ts.controlPanel }}</span>
</MkA> </MkA>
<button class="item _button" @click="more" v-click-anime> <button class="item _button" @click="more" v-click-anime>
<i class="fas fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span> <i class="fas fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span>

View File

@ -13,7 +13,9 @@
</template> </template>
<main class="main" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }"> <main class="main" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
<div class="content" :class="{ _fitSide_: !fullView }"> <div class="content">
<MkStickyContainer>
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
<keep-alive :include="['timeline']"> <keep-alive :include="['timeline']">
@ -21,6 +23,7 @@
</keep-alive> </keep-alive>
</transition> </transition>
</router-view> </router-view>
</MkStickyContainer>
</div> </div>
</main> </main>
@ -61,7 +64,7 @@
import { defineComponent, defineAsyncComponent, markRaw } from 'vue'; import { defineComponent, defineAsyncComponent, markRaw } from 'vue';
import { instanceName } from '@client/config'; import { instanceName } from '@client/config';
import { StickySidebar } from '@client/scripts/sticky-sidebar'; import { StickySidebar } from '@client/scripts/sticky-sidebar';
import XSidebar from './default.sidebar.vue'; import XSidebar from './classic.sidebar.vue';
import XDrawerSidebar from '@client/ui/_common_/sidebar.vue'; import XDrawerSidebar from '@client/ui/_common_/sidebar.vue';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import * as os from '@client/os'; import * as os from '@client/os';
@ -76,8 +79,8 @@ export default defineComponent({
XCommon, XCommon,
XSidebar, XSidebar,
XDrawerSidebar, XDrawerSidebar,
XHeaderMenu: defineAsyncComponent(() => import('./default.header.vue')), XHeaderMenu: defineAsyncComponent(() => import('./classic.header.vue')),
XWidgets: defineAsyncComponent(() => import('./default.widgets.vue')), XWidgets: defineAsyncComponent(() => import('./classic.widgets.vue')),
}, },
provide() { provide() {

View File

@ -7,13 +7,16 @@
</template> </template>
</template> </template>
<router-view v-slot="{ Component }" class="_fitSide_"> <MkStickyContainer>
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
<router-view v-slot="{ Component }">
<transition> <transition>
<keep-alive :include="['timeline']"> <keep-alive :include="['timeline']">
<component :is="Component" :ref="changePage" @contextmenu.stop="onContextmenu"/> <component :is="Component" :ref="changePage" @contextmenu.stop="onContextmenu"/>
</keep-alive> </keep-alive>
</transition> </transition>
</router-view> </router-view>
</MkStickyContainer>
</XColumn> </XColumn>
</template> </template>

View File

@ -5,6 +5,8 @@
<div class="contents" ref="contents" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }"> <div class="contents" ref="contents" @contextmenu.stop="onContextmenu" :style="{ background: pageInfo?.bg }">
<main ref="main"> <main ref="main">
<div class="content"> <div class="content">
<MkStickyContainer>
<template #header><MkHeader v-if="pageInfo && !pageInfo.hideHeader" :info="pageInfo"/></template>
<router-view v-slot="{ Component }"> <router-view v-slot="{ Component }">
<transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition"> <transition :name="$store.state.animation ? 'page' : ''" mode="out-in" @enter="onTransition">
<keep-alive :include="['timeline']"> <keep-alive :include="['timeline']">
@ -12,6 +14,7 @@
</keep-alive> </keep-alive>
</transition> </transition>
</router-view> </router-view>
</MkStickyContainer>
</div> </div>
<div class="spacer"></div> <div class="spacer"></div>
</main> </main>
@ -55,7 +58,7 @@ import { instanceName } from '@client/config';
import { StickySidebar } from '@client/scripts/sticky-sidebar'; import { StickySidebar } from '@client/scripts/sticky-sidebar';
import XSidebar from '@client/ui/_common_/sidebar.vue'; import XSidebar from '@client/ui/_common_/sidebar.vue';
import XCommon from './_common_/common.vue'; import XCommon from './_common_/common.vue';
import XSide from './default.side.vue'; import XSide from './classic.side.vue';
import * as os from '@client/os'; import * as os from '@client/os';
import { menuDef } from '@client/menu'; import { menuDef } from '@client/menu';
import * as symbols from '@client/symbols'; import * as symbols from '@client/symbols';

View File

@ -3,7 +3,7 @@
<template #header><i class="fas fa-bell"></i>{{ $ts.notifications }}</template> <template #header><i class="fas fa-bell"></i>{{ $ts.notifications }}</template>
<template #func><button @click="configure()" class="_button"><i class="fas fa-cog"></i></button></template> <template #func><button @click="configure()" class="_button"><i class="fas fa-cog"></i></button></template>
<div class="_fitSide_"> <div>
<XNotifications :include-types="props.includingTypes"/> <XNotifications :include-types="props.includingTypes"/>
</div> </div>
</MkContainer> </MkContainer>

View File

@ -17,6 +17,7 @@ import { PollVote } from '@/models/entities/poll-vote';
import { Note } from '@/models/entities/note'; import { Note } from '@/models/entities/note';
import { NoteReaction } from '@/models/entities/note-reaction'; import { NoteReaction } from '@/models/entities/note-reaction';
import { NoteWatching } from '@/models/entities/note-watching'; import { NoteWatching } from '@/models/entities/note-watching';
import { NoteThreadMuting } from '@/models/entities/note-thread-muting';
import { NoteUnread } from '@/models/entities/note-unread'; import { NoteUnread } from '@/models/entities/note-unread';
import { Notification } from '@/models/entities/notification'; import { Notification } from '@/models/entities/notification';
import { Meta } from '@/models/entities/meta'; import { Meta } from '@/models/entities/meta';
@ -138,6 +139,7 @@ export const entities = [
NoteFavorite, NoteFavorite,
NoteReaction, NoteReaction,
NoteWatching, NoteWatching,
NoteThreadMuting,
NoteUnread, NoteUnread,
Page, Page,
PageLike, PageLike,

View File

@ -33,7 +33,7 @@
<dd>Renote先のUrlリモートのートオブジェクトを指定</dd> <dd>Renote先のUrlリモートのートオブジェクトを指定</dd>
</dl> </dl>
### 公開範囲 ### الظهور
※specifiedに相当する値はvisibility=specifiedとvisibleAccts/visibleUserIdsで指定する ※specifiedに相当する値はvisibility=specifiedとvisibleAccts/visibleUserIdsで指定する
<dl> <dl>

View File

@ -29,7 +29,7 @@
**ストリームでのやり取りはすべてJSONです。** **ストリームでのやり取りはすべてJSONです。**
## チャンネル ## القنوات
MisskeyのストリーミングAPIにはチャンネルという概念があります。これは、送受信する情報を分離するための仕組みです。 Misskeyのストリームに接続しただけでは、まだリアルタイムでタイムラインの投稿を受信したりはできません。 ストリーム上でチャンネルに接続することで、様々な情報を受け取ったり情報を送信したりすることができるようになります。 MisskeyのストリーミングAPIにはチャンネルという概念があります。これは、送受信する情報を分離するための仕組みです。 Misskeyのストリームに接続しただけでは、まだリアルタイムでタイムラインの投稿を受信したりはできません。 ストリーム上でチャンネルに接続することで、様々な情報を受け取ったり情報を送信したりすることができるようになります。
ひとつのストリーム上で、同時に複数のチャンネルに接続することができます。 ひとつのストリーム上で、同時に複数のチャンネルに接続することができます。

View File

@ -12,7 +12,7 @@
<div class="info"> コンピューターのクリップボードに画像データがある状態で、フォーム内のテキストボックスにペーストするとその画像を添付することができます。</div> <div class="info"> コンピューターのクリップボードに画像データがある状態で、フォーム内のテキストボックスにペーストするとその画像を添付することができます。</div>
<div class="info"> テキストボックス内で<kbd class="key">Ctrl + Enter</kbd>を押すことでも投稿できます。</div> <div class="info"> テキストボックス内で<kbd class="key">Ctrl + Enter</kbd>を押すことでも投稿できます。</div>
## Renote ## أعد النشر
既にあるートを引用、もしくはそのートを新しいートとして共有する行為、またそれによって作成されたートをRenoteと呼びます。 自分がフォローしているユーザーの、気に入ったノートを自分のフォロワーに共有したい場合や、過去の自分のノートを再度共有したい場合に使います。 同じートに対して無制限にRenoteを行うことができますが、あまり連続して使用すると迷惑になる場合もあるので、注意しましょう。 既にあるートを引用、もしくはそのートを新しいートとして共有する行為、またそれによって作成されたートをRenoteと呼びます。 自分がフォローしているユーザーの、気に入ったノートを自分のフォロワーに共有したい場合や、過去の自分のノートを再度共有したい場合に使います。 同じートに対して無制限にRenoteを行うことができますが、あまり連続して使用すると迷惑になる場合もあるので、注意しましょう。
<div class="warn">⚠️ 公開範囲がフォロワーやダイレクトのートはRenoteできません</div> <div class="warn">⚠️ 公開範囲がフォロワーやダイレクトのートはRenoteできません</div>
@ -21,7 +21,7 @@ Renoteを削除するには、Renoteの時刻表示の隣にある「...」を
## CW ## CW
Contents Warningの略で、ートの内容を、閲覧者の操作なしには表示しないようにできる機能です。主に長大な内容を隠すためや、ネタバレ防止などに使うことができます。 設定するには、フォームの「内容を隠す」ボタン(目のアイコン)を押します。すると新しい入力エリアが表れるので、そこに内容の要約を記入します。 Contents Warningの略で、ートの内容を、閲覧者の操作なしには表示しないようにできる機能です。主に長大な内容を隠すためや、ネタバレ防止などに使うことができます。 設定するには、フォームの「内容を隠す」ボタン(目のアイコン)を押します。すると新しい入力エリアが表れるので、そこに内容の要約を記入します。
## 公開範囲 ## الظهور
ノートごとに、そのノートが公開される範囲を設定することができます。フォームの「ノート」ボタンの左にあるアイコンを押すと公開範囲を以下から選択できます。 ノートごとに、そのノートが公開される範囲を設定することができます。フォームの「ノート」ボタンの左にあるアイコンを押すと公開範囲を以下から選択できます。
### للعامة ### للعامة

View File

@ -34,7 +34,7 @@ Misskeyに関する用語集です。
## NSFW ## NSFW
(読み: のっとせーふふぉーわーく) Not Safe For Workの略。画像を「閲覧注意」扱いにし、操作なしには表示しないようにすることができる機能。 (読み: のっとせーふふぉーわーく) Not Safe For Workの略。画像を「閲覧注意」扱いにし、操作なしには表示しないようにすることができる機能。
## Renote ## أعد النشر
(読み: りのーと) 既にあるノートを引用、もしくはそのノートを新しいノートとして共有する行為、またそれによって作成されたノート。詳細は[こちら。](../features/note) (読み: りのーと) 既にあるノートを引用、もしくはそのノートを新しいノートとして共有する行為、またそれによって作成されたノート。詳細は[こちら。](../features/note)
## STL ## STL

View File

@ -4,7 +4,7 @@
- [Official Discord](https://discord.gg/Wp8gVStHW3) - Misskey公式Discordサーバー - [Official Discord](https://discord.gg/Wp8gVStHW3) - Misskey公式Discordサーバー
- [Misskey Forum](https://forum.misskey.io/) - Misskeyに関する話題を扱うフォーラム - [Misskey Forum](https://forum.misskey.io/) - Misskeyに関する話題を扱うフォーラム
## アカウント ## الحسابات
- [@repo@misskey.io](https://misskey.io/@repo) - Misskeyのリポジトリの更新を投稿するbot - [@repo@misskey.io](https://misskey.io/@repo) - Misskeyのリポジトリの更新を投稿するbot
## ライブラリ ## ライブラリ

View File

@ -1,24 +1,24 @@
# キーボードショートカット # Keyboard shortcuts
## Global ## Global
これらのショートカットは基本的にどこでも使えます。 These shortcuts are usually available anywhere.
<table> <table>
<thead> <thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr> <tr><th>Shortcut</th><th>Effect</th><th>Why this key?</th></tr>
</thead> </thead>
<tbody> <tbody>
<tr><td><kbd class="key">P</kbd>, <kbd class="key">N</kbd></td><td>新規投稿</td><td><b>P</b>ost, <b>N</b>ew, <b>N</b>ote</td></tr> <tr><td><kbd class="key">P</kbd>, <kbd class="key">N</kbd></td><td>Create a note</td><td><b>P</b>ost, <b>N</b>ew, <b>N</b>ote</td></tr>
<tr><td><kbd class="key">T</kbd></td><td>タイムラインの最も新しい投稿にフォーカス</td><td><b>T</b>imeline, <b>T</b>op</td></tr> <tr><td><kbd class="key">T</kbd></td><td>Focus the latest note</td><td><b>T</b>imeline, <b>T</b>op</td></tr>
<tr><td><kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">N</kbd></kbd></td><td>通知を表示/隠す</td><td><b>N</b>otifications</td></tr> <tr><td><kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">N</kbd></kbd></td><td>Show/hide notifications</td><td><b>N</b>otifications</td></tr>
<tr><td><kbd class="key">S</kbd></td><td>Search</td><td><b>S</b>earch</td></tr> <tr><td><kbd class="key">S</kbd></td><td>Search</td><td><b>S</b>earch</td></tr>
<tr><td><kbd class="key">H</kbd>, <kbd class="key">?</kbd></td><td>ヘルプを表示</td><td><b>H</b>elp</td></tr> <tr><td><kbd class="key">H</kbd>, <kbd class="key">?</kbd></td><td>Show help</td><td><b>H</b>elp</td></tr>
</tbody> </tbody>
</table> </table>
## 投稿にフォーカスされた状態 ## 投稿にフォーカスされた状態
<table> <table>
<thead> <thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr> <tr><th>Shortcut</th><th>Effect</th><th>Why this key?</th></tr>
</thead> </thead>
<tbody> <tbody>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>上の投稿にフォーカスを移動</td><td>-</td></tr> <tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd>, <kbd class="group"><kbd class="key">Shift</kbd> + <kbd class="key">Tab</kbd></kbd></td><td>上の投稿にフォーカスを移動</td><td>-</td></tr>
@ -39,12 +39,12 @@
## Renoteフォーム ## Renoteフォーム
<table> <table>
<thead> <thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr> <tr><th>Shortcut</th><th>Effect</th><th>Why this key?</th></tr>
</thead> </thead>
<tbody> <tbody>
<tr><td><kbd class="key">Enter</kbd></td><td>Renoteする</td><td>-</td></tr> <tr><td><kbd class="key">Enter</kbd></td><td>Renote</td><td>-</td></tr>
<tr><td><kbd class="key">Q</kbd></td><td>フォームを展開する</td><td><b>Q</b>uote</td></tr> <tr><td><kbd class="key">Q</kbd></td><td>Expand form</td><td><b>Q</b>uote</td></tr>
<tr><td><kbd class="key">Esc</kbd></td><td>フォームを閉じる</td><td>-</td></tr> <tr><td><kbd class="key">Esc</kbd></td><td>Close form</td><td>-</td></tr>
</tbody> </tbody>
</table> </table>
@ -52,7 +52,7 @@
デフォルトで「👍」にフォーカスが当たっている状態です。 デフォルトで「👍」にフォーカスが当たっている状態です。
<table> <table>
<thead> <thead>
<tr><th>ショートカット</th><th>効果</th><th>由来</th></tr> <tr><th>Shortcut</th><th>Effect</th><th>Why this key?</th></tr>
</thead> </thead>
<tbody> <tbody>
<tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd></td><td>上のリアクションにフォーカスを移動</td><td>-</td></tr> <tr><td><kbd class="key"></kbd>, <kbd class="key">K</kbd></td><td>上のリアクションにフォーカスを移動</td><td>-</td></tr>

View File

@ -1,9 +1,9 @@
# Pages # Pages
## Variables ## Variables
変数を使うことで動的なページを作成できます。テキスト内で <b>{ 変数名 }</b> と書くとそこに変数の値を埋め込めます。例えば <b>Hello { thing } world!</b> というテキストで、変数(thing)の値が <b>ai</b> だった場合、テキストは <b>Hello ai world!</b> になります。 Use variables to create dynamic pages. Put <b>{ variable-name }</b> in your content to embed the value. For example, if a variable named "thing" has the value <b>ai</b>, the string <b>Hello { thing } world!</b> turns into <b>Hello ai world!</b>.
変数の評価(値を算出すること)は上から下に行われるので、ある変数の中で自分より下の変数を参照することはできません。例えば上から <b>A、B、C</b> と3つの変数を定義したとき、<b>C</b>の中で<b>A</b><b>B</b>を参照することはできますが、<b>A</b>の中で<b>B</b><b>C</b>を参照することはできません。 Variables are evaluated from top to bottom, so referencing variables before declaring is not possible. For example, when declaring the three variables <b>A, B, C</b> in this order, you can use <b>A</b> or <b>B</b> in <b>C</b>, but you cannot use <b>B</b> or <b>C</b> in <b>A</b>.
ユーザーからの入力を受け取るには、ページに「ユーザー入力」ブロックを設置し、「変数名」に入力を格納したい変数名を設定します(変数は自動で作成されます)。その変数を使ってユーザー入力に応じた動作を行えます。 ユーザーからの入力を受け取るには、ページに「ユーザー入力」ブロックを設置し、「変数名」に入力を格納したい変数名を設定します(変数は自動で作成されます)。その変数を使ってユーザー入力に応じた動作を行えます。

Some files were not shown because too many files have changed in this diff Show More