Compare commits

...

56 Commits

Author SHA1 Message Date
github-actions[bot]
ac21fa7194 Bump version to 2025.3.2-alpha.3 2025-03-09 13:01:46 +00:00
syuilo
c76afce9a7 enhance(frontend): improve plugin management 2025-03-09 21:57:56 +09:00
github-actions[bot]
8e3304344f Bump version to 2025.3.2-alpha.2 2025-03-09 12:32:54 +00:00
饺子w (Yumechi)
db5c127cdd fix(backend): fix handling of invalid urls in user profile (#15635)
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2025-03-09 12:28:47 +00:00
syuilo
0402866b43 enhance(frontend): improve plugin management 2025-03-09 21:23:36 +09:00
syuilo
6cefabc6b6 chore(frontend): remove unused binding 2025-03-09 17:19:21 +09:00
syuilo
c9c04d8391 enhance(frontend): migrate overridedDeviceKind to preference 2025-03-09 17:14:48 +09:00
syuilo
27e8805dcb refactor(frontend): relocate plugin consts 2025-03-09 17:02:46 +09:00
github-actions[bot]
933abedc90 Bump version to 2025.3.2-alpha.1 2025-03-09 06:16:49 +00:00
syuilo
69eee9f050 enhance(frontend): ウィジェットもpreference管理に 2025-03-09 15:13:49 +09:00
syuilo
2918fb2609 refactor(frontend): relocate theme script 2025-03-09 14:32:29 +09:00
syuilo
fcd7fa62ba Merge branch 'develop' of https://github.com/misskey-dev/misskey into develop 2025-03-09 14:28:06 +09:00
syuilo
be7e3b9a0c refactor(frontend): scripts -> utility 2025-03-09 14:28:01 +09:00
github-actions[bot]
06e7272ca1 Bump version to 2025.3.2-alpha.0 2025-03-09 05:22:26 +00:00
かっこかり
f35eb0f6d9 enhnace(frontend): 文字列比較のためのローマナイズを強化(設定の検索) (#15632)
* enhnace(frontend): 文字列比較のためのローマナイズを強化

* docs

* fix

* fix

* fix

* comment

* wanakanaの初回ロードをコンポーネント内に移動

* comment

* fix

* add tests

---------

Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-03-09 14:21:23 +09:00
syuilo
bdb74539d4 enhance(frontend): tweak settings page 2025-03-09 14:18:50 +09:00
syuilo
abc1e9168d refactor 2025-03-09 12:39:43 +09:00
syuilo
d30ddd4c2e Refine preferences (#15597)
* wip

* wip

* wip

* test

* wip rollup pluginでsearchIndexの情報生成

* wip

* SPDX

* wip: markerIdを自動付与

* rollupでビルド時・devモード時に毎回uuidを生成するように

* 開発サーバーでだけ必要な挙動は開発サーバーのみで

* 条件が逆

* wip: childrenの生成

* update comment

* update comment

* rename auto generated file

* hashをパスと行数から決定

* Update privacy.vue

* Update privacy.vue

* wip

* Update general.vue

* Update general.vue

* wip

* wip

* Update SearchMarker.vue

* wip

* Update profile.vue

* Update mute-block.vue

* Update mute-block.vue

* Update general.vue

* Update general.vue

* childrenがduplicate key errorを吐く問題をいったん解決

* マーカーの形を成形

* loggerを置きかえ

* とりあえず省略記法に対応

* Refactor and Format codes

* wip

* Update settings-search-index.ts

* wip

* wip

* とりあえず不確定要因の仮置きidを削除

* hashの生成を正規化(絶対パスになっていたのを緩和)

* pathの入力を省略可能に

* adminでもパス生成できるように

* Update settings-search-index.ts

* Update privacy.vue

* wip

* build searchIndex

* wip

* build

* Update general.vue

* build

* Update sounds.vue

* build

* build

* Update sounds.vue

* 🎨

* 🎨

* Update privacy.vue

* Update privacy.vue

* Update security.vue

* create-search-indexを多少改善

* build

* Update 2fa.vue

* wip

* 必ずtransformCodeCacheを利用するように, キャッシュの明確な受け渡しを定義

* キャッシュはdevServerでなくても更新

* Revert "wip"

This reverts commit 41bffd3a13.

* inlining

* wip

* Update theme.vue

* 🎨

* wip normalize

* Update theme.vue

* キャッシュのパス変換

* build

* wip

* wip

* Update SearchMarker.vue

* i18n.ts['key'] の形式が取り出せない問題のFix

* build

* 仮でpath入れ

* 必ず絶対パスが使われるように

* wip

* 🎨

* storybookビルド時はcreateSearchIndexをしない

* inliningの構造化

* format code

* Update index.vue

* wip

* wip

* 🎨

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* clean up

* wip

* wip

* wip

* Update rollup-plugin-unwind-css-module-class-name.test.ts

* Update navbar.vue

* clean up

* wip

* wip

* wip

* wip

* wip

* Update preferences-backups.vue

* Update common.ts

* Update preferences.ts

* wip

* wip

* wip

* wip

* Update MkPreferenceContainer.vue

* Update MkPreferenceContainer.vue

* Update MkPreferenceContainer.vue

* enhance: 検索で上下矢印を使用することで検索結果を移動できるように

* Update main-boot.ts

* refactor

* wip

* Update sounds.vue

* fix(frontend): PageWindowでSearchMarkerが動作するように

* enhance(frontend): SearchMarkerの点滅を一定時間で止める

* wip

* lint fix

* fix: 子要素監視が抜けていたのを修正

* アニメーションの回数はCSSで制御するように

* refactor

* enhance(frontend): 検索インデックス作成時のログを削減

* revert

* fix

* fix

* Update preferences.ts

* Update preferences.ts

* wip

* Update preferences.ts

* wip

* 🎨

* wip

* Update MkPreferenceContainer.vue

* wip

* Update preferences.ts

* wip

* Update preferences.ts

* Update preferences.ts

* wip

* wip

* Update preferences.ts

* wip

* wip

* Update preferences.ts

* Update CHANGELOG.md

* Update preferences.ts

* Update deck-store.ts

* deckStoreをdefaultStoreに統合

* wip

* defaultStore -> store

* Update profile.ts

* wip

* refactor

* wip: plugin

* plugin

* plugin

* plugin

* Update plugin.ts

* wip

* Update plugin.vue

* Update preferences.ts

* Update main-boot.ts

* wip

* fix test

* Update plugin.vue

* Update plugin.vue

* Update utility.ts

* wip

* wip

* Update utility.ts

* wip

* wip

* clean up

* Update utility.ts

---------

Co-authored-by: tai-cha <dev@taichan.site>
Co-authored-by: taichan <40626578+tai-cha@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-03-09 12:34:08 +09:00
github-actions[bot]
05cdc095c0 [skip ci] Update CHANGELOG.md (prepend template) 2025-03-09 03:30:00 +00:00
github-actions[bot]
7c1dc3d632 Release: 2025.3.1 2025-03-09 03:29:54 +00:00
github-actions[bot]
c53349c3b4 Bump version to 2025.3.1-beta.3 2025-03-09 00:33:40 +00:00
饺子w (Yumechi)
a710af54ed fix(backend): fix ApPersonService unsound type cast (#15629)
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2025-03-09 00:11:34 +00:00
github-actions[bot]
ac07bb8d92 Bump version to 2025.3.1-beta.2 2025-03-08 10:15:42 +00:00
かっこかり
698505030e fix(test): fix federation test (#15630) 2025-03-08 19:11:09 +09:00
かっこかり
e16a14dcef fix(deps): pnpm v10でre2のインストールに失敗することがある問題を修正 (#15627)
* fix(deps): pnpm v10でre2のインストールに失敗することがある問題を修正

* fix

* fix docker build

* fix build failure on Windows
2025-03-08 18:56:53 +09:00
github-actions[bot]
6d93725084 Bump version to 2025.3.1-beta.1 2025-03-08 01:03:17 +00:00
おさむのひと
cb9981d4eb fix: Dockerのrunnerにpnpmのインストール手順が欠けていたのを修正 (#15623) 2025-03-08 10:02:15 +09:00
かっこかり
bee4db82bb fix(backend): follow-up of #15620
Removes unnecessary arg `disableGlobbing` from chokidar FSWatcher, as it is no longer supports globging
2025-03-07 20:10:32 +09:00
renovate[bot]
d7706ef1b5 fix(deps): update [root] update dependencies (major) (#15620)
* fix(deps): update [root] update dependencies

* fix: migrate tar library

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-03-07 19:42:39 +09:00
renovate[bot]
baf3f4a1d1 chore(deps): update [frontend] update dependencies to v10 (#15619)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-07 19:41:34 +09:00
renovate[bot]
c7a56c2c2b fix(deps): update [root] update dependencies (#15543)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-07 19:12:50 +09:00
github-actions[bot]
8dfff79ca2 Bump version to 2025.3.1-beta.0 2025-03-07 07:07:13 +00:00
かっこかり
83c3bb839f deps: update pnpm to v10 (#15588)
* Revert "fix(build): corepackのバグの回避 (#15387)"

This reverts commit 9c70a4e631.

* deps: update pnpm to v10

* fix broken lockfile

* update changelog

* fix

* fix

* Revert "fix"

This reverts commit 4abc6c194e.

* fix

* fix

* attempt to fix docker build

* lint fixes

* fix: revertしすぎた

* detect pnpm version and install it

* fix: そもそもpnpmを2回入れる必要がないかも

* fix

* refactor

* fix

* refactor: remove unnecessary arg

* Update Dockerfile

* update pnpm to v10.6.1

* Update Changelog

* chore: use node to avoid installing jq
2025-03-07 07:03:52 +00:00
syuilo
a9fe7eff0a New translations ja-jp.yml (Chinese Traditional) (#15618) 2025-03-07 16:01:32 +09:00
syuilo
d49ecab792 Update CHANGELOG.md 2025-03-07 14:46:10 +09:00
renovate[bot]
56459bbe68 chore(deps): update [tools] update dependencies (#15616)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-07 11:44:20 +09:00
renovate[bot]
6c150ef1fb fix(deps): update [frontend] update dependencies (#15617)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-07 11:44:04 +09:00
syuilo
c78f45ea20 Update CHANGELOG.md 2025-03-07 09:12:18 +09:00
syuilo
82481c01e0 tweak MkDisableSection style 🎨 2025-03-07 09:11:51 +09:00
syuilo
741cbc34e6 Update CHANGELOG.md 2025-03-07 08:53:03 +09:00
github-actions[bot]
5e86550de3 Bump version to 2025.3.1-alpha.0 2025-03-06 23:51:21 +00:00
syuilo
92aef300ee New Crowdin updates (#15611)
* New translations ja-jp.yml (English)

* New translations ja-jp.yml (Catalan)

* New translations ja-jp.yml (English)

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

* New translations ja-jp.yml (Italian)
2025-03-07 08:50:54 +09:00
syuilo
9ce1b68fd7 Update CHANGELOG.md 2025-03-07 08:50:32 +09:00
饺子w (Yumechi)
5be5c8bec4 fix(backend): fixup migration for incorrect extraction on system accounts table (#15613)
Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
2025-03-06 23:47:30 +00:00
syuilo
0214a0001f feat(frontend): 設定の検索 (#15505)
* wip

* wip

* wip

* test

* wip rollup pluginでsearchIndexの情報生成

* wip

* SPDX

* wip: markerIdを自動付与

* rollupでビルド時・devモード時に毎回uuidを生成するように

* 開発サーバーでだけ必要な挙動は開発サーバーのみで

* 条件が逆

* wip: childrenの生成

* update comment

* update comment

* rename auto generated file

* hashをパスと行数から決定

* Update privacy.vue

* Update privacy.vue

* wip

* Update general.vue

* Update general.vue

* wip

* wip

* Update SearchMarker.vue

* wip

* Update profile.vue

* Update mute-block.vue

* Update mute-block.vue

* Update general.vue

* Update general.vue

* childrenがduplicate key errorを吐く問題をいったん解決

* マーカーの形を成形

* loggerを置きかえ

* とりあえず省略記法に対応

* Refactor and Format codes

* wip

* Update settings-search-index.ts

* wip

* wip

* とりあえず不確定要因の仮置きidを削除

* hashの生成を正規化(絶対パスになっていたのを緩和)

* pathの入力を省略可能に

* adminでもパス生成できるように

* Update settings-search-index.ts

* Update privacy.vue

* wip

* build searchIndex

* wip

* build

* Update general.vue

* build

* Update sounds.vue

* build

* build

* Update sounds.vue

* 🎨

* 🎨

* Update privacy.vue

* Update privacy.vue

* Update security.vue

* create-search-indexを多少改善

* build

* Update 2fa.vue

* wip

* 必ずtransformCodeCacheを利用するように, キャッシュの明確な受け渡しを定義

* キャッシュはdevServerでなくても更新

* Revert "wip"

This reverts commit 41bffd3a13.

* inlining

* wip

* Update theme.vue

* 🎨

* wip normalize

* Update theme.vue

* キャッシュのパス変換

* build

* wip

* wip

* Update SearchMarker.vue

* i18n.ts['key'] の形式が取り出せない問題のFix

* build

* 仮でpath入れ

* 必ず絶対パスが使われるように

* wip

* 🎨

* storybookビルド時はcreateSearchIndexをしない

* inliningの構造化

* format code

* Update index.vue

* wip

* wip

* 🎨

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* wip

* clean up

* Update navbar.vue

* enhance: 検索で上下矢印を使用することで検索結果を移動できるように

* refactor

* fix(frontend): PageWindowでSearchMarkerが動作するように

* enhance(frontend): SearchMarkerの点滅を一定時間で止める

* lint fix

* fix: 子要素監視が抜けていたのを修正

* アニメーションの回数はCSSで制御するように

* refactor

* enhance(frontend): 検索インデックス作成時のログを削減

* revert

* fix

* fix

---------

Co-authored-by: tai-cha <dev@taichan.site>
Co-authored-by: taichan <40626578+tai-cha@users.noreply.github.com>
Co-authored-by: kakkokari-gtyih <67428053+kakkokari-gtyih@users.noreply.github.com>
2025-03-06 23:15:19 +09:00
github-actions[bot]
46067f6e17 [skip ci] Update CHANGELOG.md (prepend template) 2025-03-06 10:31:36 +00:00
github-actions[bot]
2b71bdf114 Release: 2025.3.0 2025-03-06 10:31:30 +00:00
github-actions[bot]
9d6b521351 Bump version to 2025.3.0-beta.2 2025-03-06 08:19:56 +00:00
syuilo
ad708d896b Merge pull request #15562 from misskey-dev/l10n_develop
New Crowdin updates
2025-03-06 17:06:09 +09:00
かっこかり
22228b6756 enhance: OAuth2 (IndieAuth) でロゴが提供されている場合は表示するように (#15578)
* enhance: OAuthでロゴが提供されている場合は表示するように

* Update Changelog

* refactor

* fix

* fix test
2025-03-06 08:05:14 +00:00
かっこかり
f7ea0c6991 fix(backend): S3互換オブジェクトストレージでファイルのアップロードに失敗することがある問題を修正 (#15583)
* fix(backend/object-storage): disable data integrity protections (MisskeyIO#895)

Cloudflare R2 does not support 'x-amz-checksum-*'

* Update Changelog

---------

Co-authored-by: あわわわとーにゅ <17376330+u1-liquid@users.noreply.github.com>
2025-03-06 08:03:57 +00:00
Sayamame-beans
60a3513cfc enhance(frontend): invert how to show the number of attachments(remains) on postform (#15599)
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
2025-03-06 07:45:46 +00:00
github-actions[bot]
377f002d68 Bump version to 2025.3.0-beta.1 2025-03-06 07:31:52 +00:00
syuilo
896bde1005 revert https://github.com/misskey-dev/misskey/pull/15545
see https://github.com/misskey-dev/misskey/issues/14498
2025-03-06 16:28:25 +09:00
かっこかり
6d0242277d fix(frontend): tabler-iconsが読み込めない問題を修正(正式リリースに差し替え) (#15608) 2025-03-06 05:34:24 +00:00
renovate[bot]
60f90ca649 chore(deps): update [misskey-js] update dependencies (#15594)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-03-06 07:09:01 +09:00
570 changed files with 10404 additions and 6004 deletions

View File

@@ -7,8 +7,8 @@
"ghcr.io/devcontainers/features/node:1": { "ghcr.io/devcontainers/features/node:1": {
"version": "22.11.0" "version": "22.11.0"
}, },
"ghcr.io/devcontainers-extra/features/corepack:1": { "ghcr.io/devcontainers-extra/features/pnpm:2": {
"version": "0.31.0" "version": "10.6.1"
} }
}, },
"forwardPorts": [3000], "forwardPorts": [3000],

View File

@@ -7,8 +7,6 @@ sudo apt-get update
sudo apt-get -y install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb sudo apt-get -y install libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libnss3 libxss1 libasound2 libxtst6 xauth xvfb
git config --global --add safe.directory /workspace git config --global --add safe.directory /workspace
git submodule update --init git submodule update --init
corepack install
corepack enable
pnpm config set store-dir /home/node/.local/share/pnpm/store pnpm config set store-dir /home/node/.local/share/pnpm/store
pnpm install --frozen-lockfile pnpm install --frozen-lockfile
cp .devcontainer/devcontainer.yml .config/default.yml cp .devcontainer/devcontainer.yml .config/default.yml

View File

@@ -9,10 +9,6 @@ on:
paths: paths:
- packages/misskey-js/** - packages/misskey-js/**
- .github/workflows/api-misskey-js.yml - .github/workflows/api-misskey-js.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
report: report:
@@ -22,7 +18,8 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
- run: corepack enable - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0

View File

@@ -9,10 +9,6 @@ on:
paths: paths:
- packages/backend/** - packages/backend/**
- .github/workflows/get-api-diff.yml - .github/workflows/get-api-diff.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
get-from-misskey: get-from-misskey:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -34,14 +30,13 @@ jobs:
with: with:
ref: ${{ matrix.ref }} ref: ${{ matrix.ref }}
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml - name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml

View File

@@ -28,10 +28,6 @@ on:
- packages/misskey-reversi/** - packages/misskey-reversi/**
- packages/shared/eslint.config.js - packages/shared/eslint.config.js
- .github/workflows/lint.yml - .github/workflows/lint.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
pnpm_install: pnpm_install:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -40,12 +36,12 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: pnpm/action-setup@v4 - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0 - uses: actions/setup-node@v4.2.0
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
lint: lint:
@@ -71,12 +67,12 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: pnpm/action-setup@v4 - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0 - uses: actions/setup-node@v4.2.0
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Restore eslint cache - name: Restore eslint cache
uses: actions/cache@v4.2.2 uses: actions/cache@v4.2.2
@@ -101,12 +97,12 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: pnpm/action-setup@v4 - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0 - uses: actions/setup-node@v4.2.0
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- run: pnpm --filter misskey-js run build - run: pnpm --filter misskey-js run build
if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'sw' }} if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'sw' }}

View File

@@ -9,10 +9,6 @@ on:
paths: paths:
- locales/** - locales/**
- .github/workflows/locale.yml - .github/workflows/locale.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
locale_verify: locale_verify:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -22,11 +18,11 @@ jobs:
with: with:
fetch-depth: 0 fetch-depth: 0
submodules: true submodules: true
- uses: pnpm/action-setup@v4 - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- uses: actions/setup-node@v4.2.0 - uses: actions/setup-node@v4.2.0
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- run: cd locales && node verify.js - run: cd locales && node verify.js

View File

@@ -6,9 +6,6 @@ on:
workflow_dispatch: workflow_dispatch:
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
publish-misskey-js: publish-misskey-js:
name: Publish misskey-js name: Publish misskey-js
@@ -26,8 +23,8 @@ jobs:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.2.2
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
@@ -36,7 +33,6 @@ jobs:
registry-url: 'https://registry.npmjs.org' registry-url: 'https://registry.npmjs.org'
- name: Publish package - name: Publish package
run: | run: |
corepack enable
pnpm i --frozen-lockfile pnpm i --frozen-lockfile
pnpm build pnpm build
pnpm --filter misskey-js publish --access public --no-git-checks --provenance pnpm --filter misskey-js publish --access public --no-git-checks --provenance

View File

@@ -13,9 +13,6 @@ on:
# This is a waste of chromatic build quota, so we don't run storybook CI on pull requests targets master. # This is a waste of chromatic build quota, so we don't run storybook CI on pull requests targets master.
- master - master
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
build: build:
# chromatic is not likely to be available for fork repositories, so we disable for fork repositories. # chromatic is not likely to be available for fork repositories, so we disable for fork repositories.
@@ -43,14 +40,13 @@ jobs:
run: | run: |
echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT
git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3) git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3)
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js 20.x - name: Use Node.js 20.x
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
node-version-file: '.node-version' node-version-file: '.node-version'
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml - name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml

View File

@@ -18,10 +18,6 @@ on:
- packages/misskey-js/** - packages/misskey-js/**
- .github/workflows/test-backend.yml - .github/workflows/test-backend.yml
- .github/misskey/test.yml - .github/misskey/test.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
unit: unit:
name: Unit tests (backend) name: Unit tests (backend)
@@ -48,8 +44,8 @@ jobs:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.2.2
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Install FFmpeg - name: Install FFmpeg
run: | run: |
for i in {1..3}; do for i in {1..3}; do
@@ -70,7 +66,6 @@ jobs:
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml - name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml
@@ -111,14 +106,13 @@ jobs:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.2.2
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml - name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml

View File

@@ -15,9 +15,6 @@ on:
- packages/misskey-js/** - packages/misskey-js/**
- .github/workflows/test-federation.yml - .github/workflows/test-federation.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
test: test:
name: Federation test name: Federation test
@@ -29,8 +26,8 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Install FFmpeg - name: Install FFmpeg
run: | run: |
for i in {1..3}; do for i in {1..3}; do
@@ -53,7 +50,6 @@ jobs:
cache: 'pnpm' cache: 'pnpm'
- name: Build Misskey - name: Build Misskey
run: | run: |
corepack enable && corepack prepare
pnpm i --frozen-lockfile pnpm i --frozen-lockfile
pnpm build pnpm build
- name: Setup - name: Setup

View File

@@ -22,10 +22,6 @@ on:
- packages/backend/** - packages/backend/**
- .github/workflows/test-frontend.yml - .github/workflows/test-frontend.yml
- .github/misskey/test.yml - .github/misskey/test.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
vitest: vitest:
name: Unit tests (frontend) name: Unit tests (frontend)
@@ -39,14 +35,13 @@ jobs:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.2.2
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml - name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml
@@ -95,14 +90,13 @@ jobs:
# if: ${{ matrix.browser == 'firefox' }} # if: ${{ matrix.browser == 'firefox' }}
#- uses: browser-actions/setup-firefox@latest #- uses: browser-actions/setup-firefox@latest
# if: ${{ matrix.browser == 'firefox' }} # if: ${{ matrix.browser == 'firefox' }}
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Copy Configure - name: Copy Configure
run: cp .github/misskey/test.yml .config run: cp .github/misskey/test.yml .config

View File

@@ -14,10 +14,6 @@ on:
paths: paths:
- packages/misskey-js/** - packages/misskey-js/**
- .github/workflows/test-misskey-js.yml - .github/workflows/test-misskey-js.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
test: test:
name: Unit tests (misskey.js) name: Unit tests (misskey.js)
@@ -33,7 +29,8 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4.2.2 uses: actions/checkout@v4.2.2
- run: corepack enable - name: Setup pnpm
uses: pnpm/action-setup@v4.1.0
- name: Setup Node.js ${{ matrix.node-version }} - name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0

View File

@@ -9,7 +9,6 @@ on:
env: env:
NODE_ENV: production NODE_ENV: production
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
production: production:
@@ -24,14 +23,13 @@ jobs:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.2.2
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
node-version: ${{ matrix.node-version }} node-version: ${{ matrix.node-version }}
cache: 'pnpm' cache: 'pnpm'
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml - name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml

View File

@@ -12,10 +12,6 @@ on:
paths: paths:
- packages/backend/** - packages/backend/**
- .github/workflows/validate-api-json.yml - .github/workflows/validate-api-json.yml
env:
COREPACK_DEFAULT_TO_LATEST: 0
jobs: jobs:
validate-api-json: validate-api-json:
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -28,8 +24,8 @@ jobs:
- uses: actions/checkout@v4.2.2 - uses: actions/checkout@v4.2.2
with: with:
submodules: true submodules: true
- name: Install pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4.1.0
- name: Use Node.js ${{ matrix.node-version }} - name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4.2.0 uses: actions/setup-node@v4.2.0
with: with:
@@ -37,7 +33,6 @@ jobs:
cache: 'pnpm' cache: 'pnpm'
- name: Install Redocly CLI - name: Install Redocly CLI
run: npm i -g @redocly/cli run: npm i -g @redocly/cli
- run: corepack enable
- run: pnpm i --frozen-lockfile - run: pnpm i --frozen-lockfile
- name: Check pnpm-lock.yaml - name: Check pnpm-lock.yaml
run: git diff --exit-code pnpm-lock.yaml run: git diff --exit-code pnpm-lock.yaml

2
.npmrc
View File

@@ -1 +1,3 @@
engine-strict = true engine-strict = true
save-exact = true
shell-emulator = true

View File

@@ -1,18 +1,52 @@
## 2025.3.2
### General
-
### Client
- Feat: 設定の管理が強化されました
- 自動でバックアップされるように
- Enhance: プラグインの管理が強化されました
### Server
- Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正
## 2025.3.1
### General
- pnpmをv10に更新
- Corepackを削除
### Client
- Feat: 設定の検索を追加(実験的)
- Enhance: 設定項目の再配置
### Server
- Fix: DBマイグレーション際にシステムアカウントのユーザーID判定が正しくない問題を修正
- Fix: user.featured列が状況によってJSON文字列になっていたのを修正
## 2025.3.0 ## 2025.3.0
### General ### General
- Enhance: プロキシアカウントをシステムアカウントとして作成するように - Enhance: プロキシアカウントをシステムアカウントとして作成するように
- Enhance: OAuthで外部アプリからロゴが提供されている場合、それを表示できるように
書式は https://indieauth.spec.indieweb.org/20220212/#example-2 に準じます。
- Fix: システムアカウントが削除できる問題を修正 - Fix: システムアカウントが削除できる問題を修正
### Client ### Client
- Enhance: モデレーターがセンシティブ設定を変更する際に確認ダイアログを出すように - Enhance: モデレーターがセンシティブ設定を変更する際に確認ダイアログを出すように
- Enhance: 「UIのアニメーションを減らす」で画面上のエフェクトも減らせるように - Enhance: 「UIのアニメーションを減らす」で画面上のエフェクトも減らせるように
- Fix: 削除して編集の削除タイミングを投稿後になるように `#14498` - Enhance: 投稿フォームにおける、メディアの添付可能個数のカウントを反転しました
- これまでの表示は`添付可能残り個数/上限数`でしたが、`添付個数/上限数`としました
- Fix: フォローされたときのメッセージがちらつくことがある問題を修正 - Fix: フォローされたときのメッセージがちらつくことがある問題を修正
- Fix: 投稿ダイアログがサイズ限界を超えた際にスクロールできない問題を修正 - Fix: 投稿ダイアログがサイズ限界を超えた際にスクロールできない問題を修正
### Server ### Server
- Fix: 特定のケースでActivityPubの処理がデッドロックになることがあるのを修正 - Fix: 特定のケースでActivityPubの処理がデッドロックになることがあるのを修正
- Fix: S3互換オブジェクトストレージでファイルのアップロードに失敗することがある問題を修正
(Cherry-picked from https://github.com/MisskeyIO/misskey/pull/895)
## 2025.2.1 ## 2025.2.1

View File

@@ -6,8 +6,6 @@ ARG NODE_VERSION=22.11.0-bookworm
FROM --platform=$BUILDPLATFORM node:${NODE_VERSION} AS native-builder FROM --platform=$BUILDPLATFORM node:${NODE_VERSION} AS native-builder
ENV COREPACK_DEFAULT_TO_LATEST=0
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
--mount=type=cache,target=/var/lib/apt,sharing=locked \ --mount=type=cache,target=/var/lib/apt,sharing=locked \
rm -f /etc/apt/apt.conf.d/docker-clean \ rm -f /etc/apt/apt.conf.d/docker-clean \
@@ -16,8 +14,6 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
&& apt-get install -yqq --no-install-recommends \ && apt-get install -yqq --no-install-recommends \
build-essential build-essential
RUN corepack enable
WORKDIR /misskey WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
@@ -33,6 +29,8 @@ COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bu
ARG NODE_ENV=production ARG NODE_ENV=production
RUN node -e "console.log(JSON.parse(require('node:fs').readFileSync('./package.json')).packageManager)" | xargs npm install -g
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output pnpm i --frozen-lockfile --aggregate-output
@@ -46,14 +44,10 @@ RUN rm -rf .git/
FROM --platform=$TARGETPLATFORM node:${NODE_VERSION} AS target-builder FROM --platform=$TARGETPLATFORM node:${NODE_VERSION} AS target-builder
ENV COREPACK_DEFAULT_TO_LATEST=0
RUN apt-get update \ RUN apt-get update \
&& apt-get install -yqq --no-install-recommends \ && apt-get install -yqq --no-install-recommends \
build-essential build-essential
RUN corepack enable
WORKDIR /misskey WORKDIR /misskey
COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"] COPY --link ["pnpm-lock.yaml", "pnpm-workspace.yaml", "package.json", "./"]
@@ -65,6 +59,8 @@ COPY --link ["packages/misskey-bubble-game/package.json", "./packages/misskey-bu
ARG NODE_ENV=production ARG NODE_ENV=production
RUN node -e "console.log(JSON.parse(require('node:fs').readFileSync('./package.json')).packageManager)" | xargs npm install -g
RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \ RUN --mount=type=cache,target=/root/.local/share/pnpm/store,sharing=locked \
pnpm i --frozen-lockfile --aggregate-output pnpm i --frozen-lockfile --aggregate-output
@@ -72,13 +68,11 @@ FROM --platform=$TARGETPLATFORM node:${NODE_VERSION}-slim AS runner
ARG UID="991" ARG UID="991"
ARG GID="991" ARG GID="991"
ENV COREPACK_DEFAULT_TO_LATEST=0
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends \ && apt-get install -y --no-install-recommends \
ffmpeg tini curl libjemalloc-dev libjemalloc2 \ ffmpeg tini curl libjemalloc-dev libjemalloc2 \
&& ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so \ && ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so \
&& corepack enable \
&& groupadd -g "${GID}" misskey \ && groupadd -g "${GID}" misskey \
&& useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \ && useradd -l -u "${UID}" -g "${GID}" -m -d /misskey misskey \
&& find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; \ && find / -type d -path /sys -prune -o -type d -path /proc -prune -o -type f -perm /u+s -ignore_readdir_race -exec chmod u-s {} \; \
@@ -86,13 +80,13 @@ RUN apt-get update \
&& apt-get clean \ && apt-get clean \
&& rm -rf /var/lib/apt/lists && rm -rf /var/lib/apt/lists
# add package.json to add pnpm
COPY ./package.json ./package.json
RUN node -e "console.log(JSON.parse(require('node:fs').readFileSync('./package.json')).packageManager)" | xargs npm install -g
USER misskey USER misskey
WORKDIR /misskey WORKDIR /misskey
# add package.json to add pnpm
COPY --chown=misskey:misskey ./package.json ./package.json
RUN corepack install
COPY --chown=misskey:misskey --from=target-builder /misskey/node_modules ./node_modules COPY --chown=misskey:misskey --from=target-builder /misskey/node_modules ./node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/backend/node_modules ./packages/backend/node_modules COPY --chown=misskey:misskey --from=target-builder /misskey/packages/backend/node_modules ./packages/backend/node_modules
COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-js/node_modules ./packages/misskey-js/node_modules COPY --chown=misskey:misskey --from=target-builder /misskey/packages/misskey-js/node_modules ./packages/misskey-js/node_modules

View File

@@ -111,7 +111,7 @@ followRequests: "Peticions de seguiment"
unfollow: "Deixar de seguir" unfollow: "Deixar de seguir"
followRequestPending: "Sol·licituds de seguiment pendents" followRequestPending: "Sol·licituds de seguiment pendents"
enterEmoji: "Introduir un emoji" enterEmoji: "Introduir un emoji"
renote: "Impulsos" renote: "Impulsar"
unrenote: "Anul·la l'impuls" unrenote: "Anul·la l'impuls"
renoted: "S'ha impulsat" renoted: "S'ha impulsat"
renotedToX: "Impulsat per {name}." renotedToX: "Impulsat per {name}."
@@ -260,7 +260,7 @@ noCustomEmojis: "No hi ha emojis personalitzats"
noJobs: "No hi ha feines" noJobs: "No hi ha feines"
federating: "Federant" federating: "Federant"
blocked: "Bloquejat" blocked: "Bloquejat"
suspended: "Suspés" suspended: "Anul·lar subscripció "
all: "tot" all: "tot"
subscribing: "Subscrit a" subscribing: "Subscrit a"
publishing: "S'està publicant" publishing: "S'està publicant"
@@ -1114,7 +1114,7 @@ forceShowAds: "Mostra els anuncis sempre "
addMemo: "Afegir recordatori" addMemo: "Afegir recordatori"
editMemo: "Editar recordatori" editMemo: "Editar recordatori"
reactionsList: "Reaccions" reactionsList: "Reaccions"
renotesList: "Impulsos" renotesList: "Llistat d'impulsos "
notificationDisplay: "Notificacions" notificationDisplay: "Notificacions"
leftTop: "Dalt a l'esquerra " leftTop: "Dalt a l'esquerra "
rightTop: "Dalt a la dreta " rightTop: "Dalt a la dreta "
@@ -1190,7 +1190,7 @@ pastAnnouncements: "Informes passats"
youHaveUnreadAnnouncements: "Tens informes per llegir." youHaveUnreadAnnouncements: "Tens informes per llegir."
useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey." useSecurityKey: "Segueix les instruccions del teu navegador O dispositiu per fer servir el teu passkey."
replies: "Respostes" replies: "Respostes"
renotes: "Impulsos" renotes: "Impulsar"
loadReplies: "Mostrar les respostes" loadReplies: "Mostrar les respostes"
loadConversation: "Mostrar la conversació " loadConversation: "Mostrar la conversació "
pinnedList: "Llista fixada" pinnedList: "Llista fixada"
@@ -1311,6 +1311,8 @@ federationSpecified: "Aquest servidor treballa amb una federació de llistes bla
federationDisabled: "La unió es troba deshabilitada en aquest servidor. No es pot interactuar amb usuaris d'altres servidors." federationDisabled: "La unió es troba deshabilitada en aquest servidor. No es pot interactuar amb usuaris d'altres servidors."
confirmOnReact: "Confirmar en reaccionar" confirmOnReact: "Confirmar en reaccionar"
reactAreYouSure: "Vols reaccionar amb \"{emoji}\"?" reactAreYouSure: "Vols reaccionar amb \"{emoji}\"?"
markAsSensitiveConfirm: "Vols marcar aquest contingut com a sensible?"
unmarkAsSensitiveConfirm: "Vols deixar de marcar com a sensible aquest contingut?"
_accountSettings: _accountSettings:
requireSigninToViewContents: "És obligatori l'inici de sessió per poder veure el contingut" requireSigninToViewContents: "És obligatori l'inici de sessió per poder veure el contingut"
requireSigninToViewContentsDescription1: "Es requereix l'inici de sessió per poder veure totes les notes i el contingut que has creat. Amb això esperem evitar que els rastrejadors recopilin informació." requireSigninToViewContentsDescription1: "Es requereix l'inici de sessió per poder veure totes les notes i el contingut que has creat. Amb això esperem evitar que els rastrejadors recopilin informació."
@@ -1332,7 +1334,7 @@ _abuseUserReport:
resolveTutorial: "Si l'informe és legítim selecciona \"Acceptar\" per resoldre'l positivament. Però si l'informe no és legítim selecciona \"Rebutjar\" per resoldre'l negativament." resolveTutorial: "Si l'informe és legítim selecciona \"Acceptar\" per resoldre'l positivament. Però si l'informe no és legítim selecciona \"Rebutjar\" per resoldre'l negativament."
_delivery: _delivery:
status: "Estat d'entrega " status: "Estat d'entrega "
stop: "Suspés" stop: "Anul·lar subscripció "
resume: "Torna a enviar" resume: "Torna a enviar"
_type: _type:
none: "S'està publicant" none: "S'està publicant"
@@ -2450,7 +2452,7 @@ _notification:
follow: "Segueix-me" follow: "Segueix-me"
mention: "Menció" mention: "Menció"
reply: "Respostes" reply: "Respostes"
renote: "Renotar" renote: "Impulsar"
quote: "Citar" quote: "Citar"
reaction: "Reaccions" reaction: "Reaccions"
pollEnded: "Enquesta terminada" pollEnded: "Enquesta terminada"
@@ -2465,7 +2467,7 @@ _notification:
_actions: _actions:
followBack: "També et segueix" followBack: "També et segueix"
reply: "Respondre" reply: "Respondre"
renote: "Renotar" renote: "Impulsos"
_deck: _deck:
alwaysShowMainColumn: "Mostrar sempre la columna principal" alwaysShowMainColumn: "Mostrar sempre la columna principal"
columnAlign: "Alinea les columnes" columnAlign: "Alinea les columnes"
@@ -2594,6 +2596,7 @@ _moderationLogTypes:
deletePage: "Esborrar la pàgina" deletePage: "Esborrar la pàgina"
deleteFlash: "Esborrar el guió" deleteFlash: "Esborrar el guió"
deleteGalleryPost: "Esborrar la publicació de la galeria" deleteGalleryPost: "Esborrar la publicació de la galeria"
updateProxyAccountDescription: "Actualitzar descripció del compte proxy"
_fileViewer: _fileViewer:
title: "Detall del fitxer" title: "Detall del fitxer"
type: "Tipus de fitxer" type: "Tipus de fitxer"

View File

@@ -5,6 +5,7 @@ introMisskey: "Vítejte! Misskey je otevřený a decentralizovaný microblogový
poweredByMisskeyDescription: "{name} je jeden ze serverů využívající open source platformu <b>Misskey<b> (nazývaná \"Misskey instance\")." poweredByMisskeyDescription: "{name} je jeden ze serverů využívající open source platformu <b>Misskey<b> (nazývaná \"Misskey instance\")."
monthAndDay: "{day}. {month}." monthAndDay: "{day}. {month}."
search: "Vyhledávání" search: "Vyhledávání"
reset: "Obnovit"
notifications: "Oznámení" notifications: "Oznámení"
username: "Uživatelské jméno" username: "Uživatelské jméno"
password: "Heslo" password: "Heslo"
@@ -365,8 +366,11 @@ hcaptcha: "hCaptcha"
enableHcaptcha: "Aktivovat hCaptchu" enableHcaptcha: "Aktivovat hCaptchu"
hcaptchaSiteKey: "Klíč stránky" hcaptchaSiteKey: "Klíč stránky"
hcaptchaSecretKey: "Tajný Klíč (Secret Key)" hcaptchaSecretKey: "Tajný Klíč (Secret Key)"
mcaptcha: "mCaptcha"
enableMcaptcha: "Aktivovat mCaptchu"
mcaptchaSiteKey: "Klíč stránky" mcaptchaSiteKey: "Klíč stránky"
mcaptchaSecretKey: "Tajný Klíč (Secret Key)" mcaptchaSecretKey: "Tajný Klíč (Secret Key)"
mcaptchaInstanceUrl: "URL mCaptcha serveru"
recaptcha: "reCAPTCHA" recaptcha: "reCAPTCHA"
enableRecaptcha: "Zapnout ReCAPTCHu" enableRecaptcha: "Zapnout ReCAPTCHu"
recaptchaSiteKey: "Klíč stránky" recaptchaSiteKey: "Klíč stránky"

View File

@@ -1311,6 +1311,8 @@ federationSpecified: "This server is operated in a whitelist federation. Interac
federationDisabled: "Federation is disabled on this server. You cannot interact with users on other servers." federationDisabled: "Federation is disabled on this server. You cannot interact with users on other servers."
confirmOnReact: "Confirm when reacting" confirmOnReact: "Confirm when reacting"
reactAreYouSure: "Would you like to add a \"{emoji}\" reaction?" reactAreYouSure: "Would you like to add a \"{emoji}\" reaction?"
markAsSensitiveConfirm: "Do you want to set this media as sensitive?"
unmarkAsSensitiveConfirm: "Do you want to remove the sensitive designation for this media?"
_accountSettings: _accountSettings:
requireSigninToViewContents: "Require sign-in to view contents" requireSigninToViewContents: "Require sign-in to view contents"
requireSigninToViewContentsDescription1: "Require login to view all notes and other content you have created. This will have the effect of preventing crawlers from collecting your information." requireSigninToViewContentsDescription1: "Require login to view all notes and other content you have created. This will have the effect of preventing crawlers from collecting your information."
@@ -2594,6 +2596,7 @@ _moderationLogTypes:
deletePage: "Page deleted" deletePage: "Page deleted"
deleteFlash: "Play deleted" deleteFlash: "Play deleted"
deleteGalleryPost: "Gallery post deleted" deleteGalleryPost: "Gallery post deleted"
updateProxyAccountDescription: "Update the description of the proxy account"
_fileViewer: _fileViewer:
title: "File details" title: "File details"
type: "File type" type: "File type"
@@ -2649,7 +2652,7 @@ _dataSaver:
description: "Prevents images/videos from being loaded automatically. Hidden images/videos will be loaded when tapped." description: "Prevents images/videos from being loaded automatically. Hidden images/videos will be loaded when tapped."
_avatar: _avatar:
title: "Avatar image" title: "Avatar image"
description: "Stop avatar image animation. Animated images can be larger in file size than normal images, potentially leading to further reductions in data traffic." description: "Stop avatar image animation. Animated images can be larger in file size than normal images, potentially leading to further reductions in data traffic."
_urlPreview: _urlPreview:
title: "URL preview thumbnails" title: "URL preview thumbnails"
description: "URL preview thumbnail images will no longer be loaded." description: "URL preview thumbnail images will no longer be loaded."
@@ -2857,4 +2860,8 @@ _bootErrors:
_search: _search:
searchScopeAll: "All" searchScopeAll: "All"
searchScopeLocal: "Local" searchScopeLocal: "Local"
searchScopeServer: "Specific server"
searchScopeUser: "Specific user" searchScopeUser: "Specific user"
pleaseEnterServerHost: "Enter the server host"
pleaseSelectUser: "Select user"
serverHostPlaceholder: "Example: misskey.example.com"

90
locales/index.d.ts vendored
View File

@@ -4971,7 +4971,7 @@ export interface Locale extends ILocale {
*/ */
"disableStreamingTimeline": string; "disableStreamingTimeline": string;
/** /**
* 通知をグルーピングして表示する * 通知をグルーピング
*/ */
"useGroupedNotifications": string; "useGroupedNotifications": string;
/** /**
@@ -5270,6 +5270,94 @@ export interface Locale extends ILocale {
* このメディアのセンシティブ指定を解除しますか? * このメディアのセンシティブ指定を解除しますか?
*/ */
"unmarkAsSensitiveConfirm": string; "unmarkAsSensitiveConfirm": string;
/**
* 環境設定
*/
"preferences": string;
/**
* アクセシビリティ
*/
"accessibility": string;
/**
* 設定のプロファイル
*/
"preferencesProfile": string;
/**
* 設定IDをコピー
*/
"copyPreferenceId": string;
/**
* 初期値に戻す
*/
"resetToDefaultValue": string;
/**
* アカウントで上書き
*/
"overrideByAccount": string;
/**
* 無題
*/
"untitled": string;
/**
* 名前はありません
*/
"noName": string;
/**
* スキップ
*/
"skip": string;
/**
* 復元
*/
"restore": string;
"_preferencesProfile": {
/**
* プロファイル名
*/
"profileName": string;
/**
* このデバイスを識別する名前を設定してください。
*/
"profileNameDescription": string;
/**
* 例: 「メインPC」、「スマホ」など
*/
"profileNameDescription2": string;
};
"_preferencesBackup": {
/**
* 自動バックアップ
*/
"autoBackup": string;
/**
* バックアップから復元
*/
"restoreFromBackup": string;
/**
* バックアップが見つかりませんでした
*/
"noBackupsFoundTitle": string;
/**
* 自動で作成されたバックアップは見つかりませんでしたが、バックアップファイルを手動で保存している場合、それをインポートして復元することはできます。
*/
"noBackupsFoundDescription": string;
/**
* 復元するバックアップを選択してください
*/
"selectBackupToRestore": string;
/**
* 自動バックアップを有効にするにはプロファイル名の設定が必要です。
*/
"youNeedToNameYourProfileToEnableAutoBackup": string;
/**
* このデバイスで設定の自動バックアップは有効になっていません。
*/
"autoPreferencesBackupIsNotEnabledForThisDevice": string;
/**
* 設定のバックアップが見つかりました
*/
"backupFound": string;
};
"_accountSettings": { "_accountSettings": {
/** /**
* コンテンツの表示にログインを必須にする * コンテンツの表示にログインを必須にする

View File

@@ -126,7 +126,7 @@ pinnedNote: "Nota in primo piano"
pinned: "Fissa sul profilo" pinned: "Fissa sul profilo"
you: "Tu" you: "Tu"
clickToShow: "Contenuto occultato, cliccare solo se si intende vedere" clickToShow: "Contenuto occultato, cliccare solo se si intende vedere"
sensitive: "Allegato esplicito" sensitive: "Esplicito"
add: "Aggiungi" add: "Aggiungi"
reaction: "Reazioni" reaction: "Reazioni"
reactions: "Reazioni" reactions: "Reazioni"
@@ -228,7 +228,7 @@ jobQueue: "Coda di lavoro"
cpuAndMemory: "CPU e Memoria" cpuAndMemory: "CPU e Memoria"
network: "Rete" network: "Rete"
disk: "Disco" disk: "Disco"
instanceInfo: "Informazioni sull'istanza" instanceInfo: "Informazioni sul server"
statistics: "Statistiche" statistics: "Statistiche"
clearQueue: "Svuota coda" clearQueue: "Svuota coda"
clearQueueConfirmTitle: "Vuoi davvero svuotare la coda?" clearQueueConfirmTitle: "Vuoi davvero svuotare la coda?"
@@ -445,7 +445,7 @@ exploreFediverse: "Esplora il Fediverso"
popularTags: "Hashtag popolari" popularTags: "Hashtag popolari"
userList: "Liste" userList: "Liste"
about: "Informazioni" about: "Informazioni"
aboutMisskey: "Informazioni di Misskey" aboutMisskey: "A proposito di Misskey"
administrator: "Amministratore" administrator: "Amministratore"
token: "Token" token: "Token"
2fa: "Autenticazione a due fattori" 2fa: "Autenticazione a due fattori"
@@ -893,7 +893,7 @@ searchResult: "Risultati della Ricerca"
hashtags: "Hashtag" hashtags: "Hashtag"
troubleshooting: "Risoluzione problemi" troubleshooting: "Risoluzione problemi"
useBlurEffect: "Utilizza effetto sfocatura" useBlurEffect: "Utilizza effetto sfocatura"
learnMore: "Più dettagli" learnMore: "Per saperne di più"
misskeyUpdated: "Misskey è stato aggiornato!" misskeyUpdated: "Misskey è stato aggiornato!"
whatIsNew: "Informazioni sull'aggiornamento" whatIsNew: "Informazioni sull'aggiornamento"
translate: "Traduci" translate: "Traduci"
@@ -901,7 +901,7 @@ translatedFrom: "Traduzione da {x}"
accountDeletionInProgress: "È in corso l'eliminazione del profilo" accountDeletionInProgress: "È in corso l'eliminazione del profilo"
usernameInfo: "Un nome per identificare univocamente il tuo profilo sull'istanza. Puoi utilizzare caratteri alfanumerici maiuscoli, minuscoli e il trattino basso (_). Non potrai cambiare nome utente in seguito." usernameInfo: "Un nome per identificare univocamente il tuo profilo sull'istanza. Puoi utilizzare caratteri alfanumerici maiuscoli, minuscoli e il trattino basso (_). Non potrai cambiare nome utente in seguito."
aiChanMode: "Modalità Ai" aiChanMode: "Modalità Ai"
devMode: "Modalità sviluppatori" devMode: "Modalità sviluppo"
keepCw: "Mostra i contenuti espliciti" keepCw: "Mostra i contenuti espliciti"
pubSub: "Publish/Subscribe del profilo" pubSub: "Publish/Subscribe del profilo"
lastCommunication: "La comunicazione più recente" lastCommunication: "La comunicazione più recente"
@@ -1049,7 +1049,7 @@ permissionDeniedError: "Errore, attività non autorizzata"
permissionDeniedErrorDescription: "Non si dispone dell'autorizzazione per eseguire questa operazione." permissionDeniedErrorDescription: "Non si dispone dell'autorizzazione per eseguire questa operazione."
preset: "Preimpostato" preset: "Preimpostato"
selectFromPresets: "Seleziona preimpostato" selectFromPresets: "Seleziona preimpostato"
achievements: "Obiettivi raggiunti" achievements: "Conquiste"
gotInvalidResponseError: "Risposta del server non valida" gotInvalidResponseError: "Risposta del server non valida"
gotInvalidResponseErrorDescription: "Il server potrebbe essere irraggiungibile o in manutenzione. Riprova più tardi." gotInvalidResponseErrorDescription: "Il server potrebbe essere irraggiungibile o in manutenzione. Riprova più tardi."
thisPostMayBeAnnoying: "Questa nota potrebbe essere offensiva" thisPostMayBeAnnoying: "Questa nota potrebbe essere offensiva"
@@ -1311,6 +1311,10 @@ federationSpecified: "Questo server è federato solo con istanze specifiche del
federationDisabled: "Questo server ha la federazione disabilitata. Non puoi interagire con profili provenienti da altri server." federationDisabled: "Questo server ha la federazione disabilitata. Non puoi interagire con profili provenienti da altri server."
confirmOnReact: "Confermare le reazioni" confirmOnReact: "Confermare le reazioni"
reactAreYouSure: "Vuoi davvero reagire con {emoji} ?" reactAreYouSure: "Vuoi davvero reagire con {emoji} ?"
markAsSensitiveConfirm: "Vuoi davvero indicare questo contenuto multimediale come esplicito?"
unmarkAsSensitiveConfirm: "Vuoi davvero indicare come non esplicito il contenuto multimediale?"
preferences: "Preferenze"
accessibility: "Accessibilità"
_accountSettings: _accountSettings:
requireSigninToViewContents: "Per vedere il contenuto, è necessaria l'iscrizione" requireSigninToViewContents: "Per vedere il contenuto, è necessaria l'iscrizione"
requireSigninToViewContentsDescription1: "Richiedere l'iscrizione per visualizzare tutte le Note e gli altri contenuti che hai creato. Probabilmente l'effetto è impedire la raccolta di informazioni da parte dei bot crawler." requireSigninToViewContentsDescription1: "Richiedere l'iscrizione per visualizzare tutte le Note e gli altri contenuti che hai creato. Probabilmente l'effetto è impedire la raccolta di informazioni da parte dei bot crawler."
@@ -1447,9 +1451,9 @@ _initialTutorial:
description: "Queste sono solamente alcune delle funzionalità principali di Misskey. Per ulteriori informazioni, {link}." description: "Queste sono solamente alcune delle funzionalità principali di Misskey. Per ulteriori informazioni, {link}."
_timelineDescription: _timelineDescription:
home: "Nella Timeline Home, la tua cronologia principale, puoi vedere le Note provenienti dai profili che segui (Following)." home: "Nella Timeline Home, la tua cronologia principale, puoi vedere le Note provenienti dai profili che segui (Following)."
local: "La Timeline Locale, è una cronologia di Note pubblicate da tutti i profili iscritti su questo server." local: "La Timeline Locale è un flusso di Note pubblicate dai profili iscritti a questo server."
social: "La Timeline Sociale, unisce in ordine cronologico l'elenco di Note presenti nella Timeline Home e quella Locale." social: "La Timeline Sociale elenca, in ordine cronologico, il flusso di Note nella Timeline Home e Locale."
global: "La Timeline Federata ti consente di vedere le Note pubblicate dai profili di tutti gli altri server federati a questo." global: "Nella Timeline Federata trovi il flusso di Note provenienti da profili iscritti ad altri server, federati a questo."
_serverRules: _serverRules:
description: "In Europa è necessario mostrare l'informativa sul trattamento dei dati personali, prima della registrazione al servizio." description: "In Europa è necessario mostrare l'informativa sul trattamento dei dati personali, prima della registrazione al servizio."
_serverSettings: _serverSettings:
@@ -1473,8 +1477,8 @@ _serverSettings:
_accountMigration: _accountMigration:
moveFrom: "Migra un altro profilo dentro a questo" moveFrom: "Migra un altro profilo dentro a questo"
moveFromSub: "Crea un alias verso un altro profilo remoto" moveFromSub: "Crea un alias verso un altro profilo remoto"
moveFromLabel: "Profilo da cui migrare #{n}" moveFromLabel: "Profilo da cui migrare n. {n}"
moveFromDescription: "Se desideri spostare i Follower da un altro profilo a questo, devi prima creare un alias qui. Assicurati averlo creato PRIMA di eseguire l'attività! Inserisci l'indirizzo del profilo mittente in questo modo: @persona@istanza.it" moveFromDescription: "Se desideri spostare i Follower da un altro profilo a questo, devi prima creare un alias qui. Assicurati averlo creato PRIMA di eseguire l'attività! Inserisci l'indirizzo del profilo mittente in questo modo: @persona@vecchia.istanza.it"
moveTo: "Migrare questo profilo verso un un altro" moveTo: "Migrare questo profilo verso un un altro"
moveToLabel: "Profilo verso cui migrare" moveToLabel: "Profilo verso cui migrare"
moveCannotBeUndone: "La migrazione è irreversibile, non può essere interrotta o annullata." moveCannotBeUndone: "La migrazione è irreversibile, non può essere interrotta o annullata."
@@ -1550,13 +1554,13 @@ _achievements:
title: "Principiante III" title: "Principiante III"
description: "Hai totalizzato 15 accessi!" description: "Hai totalizzato 15 accessi!"
_login30: _login30:
title: "Misskist I" title: "Missalcolista I"
description: "Hai totalizzato 30 accessi!" description: "Hai totalizzato 30 accessi!"
_login60: _login60:
title: "Misskeist II" title: "Missalcolista II"
description: "Hai totalizzato 60 accessi!" description: "Hai totalizzato 60 accessi!"
_login100: _login100:
title: "Misskeist III" title: "Missalcolista III"
description: "Hai totalizzato 100 accessi!" description: "Hai totalizzato 100 accessi!"
flavor: "Violent Misskeist" flavor: "Violent Misskeist"
_login200: _login200:
@@ -1642,10 +1646,10 @@ _achievements:
description: "Hai superato i 1.000 profili Follower" description: "Hai superato i 1.000 profili Follower"
_collectAchievements30: _collectAchievements30:
title: "Collezionista di successi" title: "Collezionista di successi"
description: "Hai raggiunto 30 obiettivi" description: "Hai raggiunto 30 conquiste"
_viewAchievements3min: _viewAchievements3min:
title: "Mi piacciono i risultati" title: "Mi piacciono i risultati"
description: "Guarda la tua collezione di obiettivi per almeno 3 minuti" description: "Ammira la tua collezione di conquiste per almeno 3 minuti"
_iLoveMisskey: _iLoveMisskey:
title: "I LOVE Misskey" title: "I LOVE Misskey"
description: "Pubblica «I ♥ #Misskey»" description: "Pubblica «I ♥ #Misskey»"
@@ -1910,7 +1914,7 @@ _registry:
domain: "Dominio" domain: "Dominio"
createKey: "Crea chiave" createKey: "Crea chiave"
_aboutMisskey: _aboutMisskey:
about: "Misskey è un software libero e open source, sviluppato da syuilo dal 2014." about: "Misskey è software libero, open source, sviluppato da Syuilo fin dal lontano 2014."
contributors: "Principali sostenitori" contributors: "Principali sostenitori"
allContributors: "Tutti i sostenitori" allContributors: "Tutti i sostenitori"
source: "Codice sorgente" source: "Codice sorgente"
@@ -2237,7 +2241,7 @@ _widgets:
userList: "Elenco utenti" userList: "Elenco utenti"
_userList: _userList:
chooseList: "Seleziona una lista" chooseList: "Seleziona una lista"
clicker: "Cliccaggio" clicker: "Cliccheria"
birthdayFollowings: "Compleanni del giorno" birthdayFollowings: "Compleanni del giorno"
_cw: _cw:
hide: "Nascondere" hide: "Nascondere"
@@ -2300,7 +2304,7 @@ _profile:
metadataContent: "Contenuto" metadataContent: "Contenuto"
changeAvatar: "Modifica immagine profilo" changeAvatar: "Modifica immagine profilo"
changeBanner: "Cambia intestazione" changeBanner: "Cambia intestazione"
verifiedLinkDescription: "Puoi verificare il tuo profilo mostrando una icona. Devi inserire la URL alla pagina che contiene un link al tuo profilo." verifiedLinkDescription: "Puoi verificare il tuo profilo mostrando una icona. Devi inserire la URL alla pagina che contiene un link al tuo profilo.\nPer verificare il profilo tramite la spunta di conferma, devi inserire la url alla pagina che contiene un link al tuo profilo Misskey. Deve avere attributo rel='me'."
avatarDecorationMax: "Puoi aggiungere fino a {max} decorazioni." avatarDecorationMax: "Puoi aggiungere fino a {max} decorazioni."
followedMessage: "Messaggio, quando qualcuno ti segue" followedMessage: "Messaggio, quando qualcuno ti segue"
followedMessageDescription: "Puoi impostare un breve messaggio da mostrare agli altri profili quando ti seguono." followedMessageDescription: "Puoi impostare un breve messaggio da mostrare agli altri profili quando ti seguono."
@@ -2594,6 +2598,7 @@ _moderationLogTypes:
deletePage: "Pagina eliminata" deletePage: "Pagina eliminata"
deleteFlash: "Play eliminato" deleteFlash: "Play eliminato"
deleteGalleryPost: "Eliminazione pubblicazione nella Galleria" deleteGalleryPost: "Eliminazione pubblicazione nella Galleria"
updateProxyAccountDescription: "Aggiornata la descrizione del profilo proxy"
_fileViewer: _fileViewer:
title: "Dettagli del file" title: "Dettagli del file"
type: "Tipo di file" type: "Tipo di file"
@@ -2811,8 +2816,8 @@ _selfXssPrevention:
description2: "Se non sai esattamente cosa stai facendo, %c smetti subito e chiudi questa finestra." description2: "Se non sai esattamente cosa stai facendo, %c smetti subito e chiudi questa finestra."
description3: "Per favore, controlla questo collegamento per avere maggiori dettagli. {link}" description3: "Per favore, controlla questo collegamento per avere maggiori dettagli. {link}"
_followRequest: _followRequest:
recieved: "Ricezione richiesta di Follow" recieved: "Richieste in ingresso"
sent: "Richiesta di Follow, inviata" sent: "Richieste in uscita"
_remoteLookupErrors: _remoteLookupErrors:
_federationNotAllowed: _federationNotAllowed:
title: "Server irraggiungibile" title: "Server irraggiungibile"
@@ -2857,4 +2862,8 @@ _bootErrors:
_search: _search:
searchScopeAll: "Tutte" searchScopeAll: "Tutte"
searchScopeLocal: "Locale" searchScopeLocal: "Locale"
searchScopeServer: "Specifiche del server"
searchScopeUser: "Profilo specifico" searchScopeUser: "Profilo specifico"
pleaseEnterServerHost: "Inserire il nome host"
pleaseSelectUser: "Per favore, seleziona un profilo"
serverHostPlaceholder: "Es: misskey.example.com"

View File

@@ -1238,7 +1238,7 @@ releaseToRefresh: "離してリロード"
refreshing: "リロード中" refreshing: "リロード中"
pullDownToRefresh: "引っ張ってリロード" pullDownToRefresh: "引っ張ってリロード"
disableStreamingTimeline: "タイムラインのリアルタイム更新を無効にする" disableStreamingTimeline: "タイムラインのリアルタイム更新を無効にする"
useGroupedNotifications: "通知をグルーピングして表示する" useGroupedNotifications: "通知をグルーピング"
signupPendingError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。" signupPendingError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。"
cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。" cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。"
doReaction: "リアクションする" doReaction: "リアクションする"
@@ -1313,6 +1313,31 @@ confirmOnReact: "リアクションする際に確認する"
reactAreYouSure: "\" {emoji} \" をリアクションしますか?" reactAreYouSure: "\" {emoji} \" をリアクションしますか?"
markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?" markAsSensitiveConfirm: "このメディアをセンシティブとして設定しますか?"
unmarkAsSensitiveConfirm: "このメディアのセンシティブ指定を解除しますか?" unmarkAsSensitiveConfirm: "このメディアのセンシティブ指定を解除しますか?"
preferences: "環境設定"
accessibility: "アクセシビリティ"
preferencesProfile: "設定のプロファイル"
copyPreferenceId: "設定IDをコピー"
resetToDefaultValue: "初期値に戻す"
overrideByAccount: "アカウントで上書き"
untitled: "無題"
noName: "名前はありません"
skip: "スキップ"
restore: "復元"
_preferencesProfile:
profileName: "プロファイル名"
profileNameDescription: "このデバイスを識別する名前を設定してください。"
profileNameDescription2: "例: 「メインPC」、「スマホ」など"
_preferencesBackup:
autoBackup: "自動バックアップ"
restoreFromBackup: "バックアップから復元"
noBackupsFoundTitle: "バックアップが見つかりませんでした"
noBackupsFoundDescription: "自動で作成されたバックアップは見つかりませんでしたが、バックアップファイルを手動で保存している場合、それをインポートして復元することはできます。"
selectBackupToRestore: "復元するバックアップを選択してください"
youNeedToNameYourProfileToEnableAutoBackup: "自動バックアップを有効にするにはプロファイル名の設定が必要です。"
autoPreferencesBackupIsNotEnabledForThisDevice: "このデバイスで設定の自動バックアップは有効になっていません。"
backupFound: "設定のバックアップが見つかりました"
_accountSettings: _accountSettings:
requireSigninToViewContents: "コンテンツの表示にログインを必須にする" requireSigninToViewContents: "コンテンツの表示にログインを必須にする"

View File

@@ -1311,6 +1311,10 @@ federationSpecified: "此服务器已开启联合白名单。只能与管理员
federationDisabled: "此服务器已禁用联合。无法与其它服务器上的用户通信。" federationDisabled: "此服务器已禁用联合。无法与其它服务器上的用户通信。"
confirmOnReact: "发送回应前需要确认" confirmOnReact: "发送回应前需要确认"
reactAreYouSure: "要用「{emoji}」进行回应吗?" reactAreYouSure: "要用「{emoji}」进行回应吗?"
markAsSensitiveConfirm: "要将此媒体标记为敏感吗?"
unmarkAsSensitiveConfirm: "要将此媒体解除敏感标记吗?"
preferences: "设置"
accessibility: "辅助功能"
_accountSettings: _accountSettings:
requireSigninToViewContents: "需要登录才能显示内容" requireSigninToViewContents: "需要登录才能显示内容"
requireSigninToViewContentsDescription1: "您发布的所有帖子将变成需要登入后才会显示。有望防止爬虫收集各种信息。" requireSigninToViewContentsDescription1: "您发布的所有帖子将变成需要登入后才会显示。有望防止爬虫收集各种信息。"
@@ -2594,6 +2598,7 @@ _moderationLogTypes:
deletePage: "删除了页面" deletePage: "删除了页面"
deleteFlash: "删除了 Play" deleteFlash: "删除了 Play"
deleteGalleryPost: "删除了图库稿件" deleteGalleryPost: "删除了图库稿件"
updateProxyAccountDescription: "更新代理账户的说明"
_fileViewer: _fileViewer:
title: "文件信息" title: "文件信息"
type: "文件类型" type: "文件类型"
@@ -2857,4 +2862,8 @@ _bootErrors:
_search: _search:
searchScopeAll: "全部" searchScopeAll: "全部"
searchScopeLocal: "本地" searchScopeLocal: "本地"
searchScopeUser: "用户指定" searchScopeServer: "指定服务器"
searchScopeUser: "指定用户"
pleaseEnterServerHost: "请填写服务器主机名"
pleaseSelectUser: "请选择用户"
serverHostPlaceholder: "如misskey.example.com"

View File

@@ -1311,6 +1311,10 @@ federationSpecified: "此伺服器以白名單聯邦的方式運作。除了管
federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。" federationDisabled: "此伺服器未開啟站台聯邦。無法與其他伺服器上的使用者互動。"
confirmOnReact: "反應時確認" confirmOnReact: "反應時確認"
reactAreYouSure: "用「 {emoji} 」反應嗎?" reactAreYouSure: "用「 {emoji} 」反應嗎?"
markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?"
unmarkAsSensitiveConfirm: "要解除這個媒體的敏感設定嗎?"
preferences: "環境設定"
accessibility: "輔助工具"
_accountSettings: _accountSettings:
requireSigninToViewContents: "須登入以顯示內容" requireSigninToViewContents: "須登入以顯示內容"
requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。" requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。"
@@ -2594,6 +2598,7 @@ _moderationLogTypes:
deletePage: "刪除頁面" deletePage: "刪除頁面"
deleteFlash: "刪除 Play" deleteFlash: "刪除 Play"
deleteGalleryPost: "刪除相簿的貼文" deleteGalleryPost: "刪除相簿的貼文"
updateProxyAccountDescription: "更新代理帳戶的說明"
_fileViewer: _fileViewer:
title: "檔案詳細資訊" title: "檔案詳細資訊"
type: "檔案類型 " type: "檔案類型 "
@@ -2857,4 +2862,8 @@ _bootErrors:
_search: _search:
searchScopeAll: "全部" searchScopeAll: "全部"
searchScopeLocal: "本地" searchScopeLocal: "本地"
searchScopeServer: "指定伺服器"
searchScopeUser: "指定使用者" searchScopeUser: "指定使用者"
pleaseEnterServerHost: "請輸入伺服器的主機名稱"
pleaseSelectUser: "請選擇使用者"
serverHostPlaceholder: "例misskey.example.com"

View File

@@ -1,12 +1,12 @@
{ {
"name": "misskey", "name": "misskey",
"version": "2025.3.0-beta.0", "version": "2025.3.2-alpha.3",
"codename": "nasubi", "codename": "nasubi",
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/misskey-dev/misskey.git" "url": "https://github.com/misskey-dev/misskey.git"
}, },
"packageManager": "pnpm@9.15.4", "packageManager": "pnpm@10.6.1",
"workspaces": [ "workspaces": [
"packages/frontend-shared", "packages/frontend-shared",
"packages/frontend", "packages/frontend",
@@ -47,35 +47,44 @@
"cleanall": "pnpm clean-all" "cleanall": "pnpm clean-all"
}, },
"resolutions": { "resolutions": {
"chokidar": "3.6.0", "chokidar": "4.0.3",
"lodash": "4.17.21" "lodash": "4.17.21"
}, },
"dependencies": { "dependencies": {
"cssnano": "7.0.6", "cssnano": "7.0.6",
"execa": "8.0.1", "execa": "9.5.2",
"fast-glob": "3.3.3", "fast-glob": "3.3.3",
"ignore-walk": "6.0.5", "ignore-walk": "7.0.0",
"js-yaml": "4.1.0", "js-yaml": "4.1.0",
"postcss": "8.5.2", "postcss": "8.5.3",
"tar": "6.2.1", "tar": "7.4.3",
"terser": "5.39.0", "terser": "5.39.0",
"typescript": "5.7.3", "typescript": "5.8.2",
"esbuild": "0.25.0", "esbuild": "0.25.0",
"glob": "11.0.1" "glob": "11.0.1"
}, },
"devDependencies": { "devDependencies": {
"@misskey-dev/eslint-plugin": "2.1.0", "@misskey-dev/eslint-plugin": "2.1.0",
"@types/node": "22.13.4", "@types/node": "22.13.9",
"@typescript-eslint/eslint-plugin": "8.24.0", "@typescript-eslint/eslint-plugin": "8.26.0",
"@typescript-eslint/parser": "8.24.0", "@typescript-eslint/parser": "8.26.0",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "14.0.3", "cypress": "14.1.0",
"eslint": "9.20.1", "eslint": "9.21.0",
"globals": "15.15.0", "globals": "16.0.0",
"ncp": "2.0.0", "ncp": "2.0.0",
"pnpm": "10.6.1",
"start-server-and-test": "2.0.10" "start-server-and-test": "2.0.10"
}, },
"optionalDependencies": { "optionalDependencies": {
"@tensorflow/tfjs-core": "4.22.0" "@tensorflow/tfjs-core": "4.22.0"
},
"pnpm": {
"overrides": {
"@aiscript-dev/aiscript-languageserver": "-"
},
"patchedDependencies": {
"re2": "scripts/dependency-patches/re2.patch"
}
} }
} }

View File

@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class SystemAccounts1741279404074 {
name = 'SystemAccounts1741279404074'
async up(queryRunner) {
const instanceActor = await queryRunner.query(`SELECT "id" FROM "user" WHERE "username" = 'instance.actor' AND "host" IS NULL AND "id" NOT IN (SELECT "userId" FROM "system_account" WHERE "type" = 'actor')`);
if (instanceActor.length > 0) {
console.warn('instance.actor was incorrect, updating...');
await queryRunner.query(`UPDATE "system_account" SET "id" = '${instanceActor[0].id}', "userId" = '${instanceActor[0].id}' WHERE "type" = 'actor'`);
}
const relayActor = await queryRunner.query(`SELECT "id" FROM "user" WHERE "username" = 'relay.actor' AND "host" IS NULL AND "id" NOT IN (SELECT "userId" FROM "system_account" WHERE "type" = 'relay')`);
if (relayActor.length > 0) {
console.warn('relay.actor was incorrect, updating...');
await queryRunner.query(`UPDATE "system_account" SET "id" = '${relayActor[0].id}', "userId" = '${relayActor[0].id}' WHERE "type" = 'relay'`);
}
}
async down(queryRunner) {
// fixup migration, no down migration
}
}

View File

@@ -0,0 +1,26 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
export class UserFeaturedFixup1741424411879 {
name = 'UserFeaturedFixup1741424411879'
async up(queryRunner) {
await queryRunner.query(`CREATE OR REPLACE FUNCTION pg_temp.extract_ap_id(text) RETURNS text AS $$
SELECT
CASE
WHEN $1 ~ '^https?://' THEN $1
WHEN $1 LIKE '{%' THEN COALESCE(jsonb_extract_path_text($1::jsonb, 'id'), null)
ELSE null
END;
$$ LANGUAGE sql IMMUTABLE;`);
// "host" is NOT NULL is not needed but just in case add it to prevent overwriting irreplaceable data
await queryRunner.query(`UPDATE "user" SET "featured" = pg_temp.extract_ap_id("featured") WHERE "host" IS NOT NULL`);
}
async down(queryRunner) {
// fixup migration, no down migration
}
}

View File

@@ -268,7 +268,6 @@ export class FileInfoService {
private async *asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand): AsyncGenerator<string, void> { private async *asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand): AsyncGenerator<string, void> {
const watcher = new FSWatcher({ const watcher = new FSWatcher({
cwd, cwd,
disableGlobbing: true,
}); });
let finished = false; let finished = false;
command.once('end', () => { command.once('end', () => {

View File

@@ -46,6 +46,8 @@ export class S3Service {
tls: meta.objectStorageUseSSL, tls: meta.objectStorageUseSSL,
forcePathStyle: meta.objectStorageEndpoint ? meta.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted forcePathStyle: meta.objectStorageEndpoint ? meta.objectStorageS3ForcePathStyle : false, // AWS with endPoint omitted
requestHandler: new NodeHttpHandler(handlerOption), requestHandler: new NodeHttpHandler(handlerOption),
requestChecksumCalculation: 'WHEN_REQUIRED',
responseChecksumValidation: 'WHEN_REQUIRED',
}); });
} }

View File

@@ -499,11 +499,28 @@ export class ApRendererService {
this.userProfilesRepository.findOneByOrFail({ userId: user.id }), this.userProfilesRepository.findOneByOrFail({ userId: user.id }),
]); ]);
const tryRewriteUrl = (maybeUrl: string) => {
const urlSafeRegex = /^(?:http[s]?:\/\/.)?(?:www\.)?[-a-zA-Z0-9@%._\+~#=]{2,256}\.[a-z]{2,6}\b(?:[-a-zA-Z0-9@:%_\+.~#?&\/\/=]*)/;
try {
const match = maybeUrl.match(urlSafeRegex);
if (!match) {
return maybeUrl;
}
const urlPart = match[0];
const urlPartParsed = new URL(urlPart);
const restPart = maybeUrl.slice(match[0].length);
return `<a href="${urlPartParsed.href}" rel="me nofollow noopener" target="_blank">${urlPart}</a>${restPart}`;
} catch (e) {
return maybeUrl;
}
};
const attachment = profile.fields.map(field => ({ const attachment = profile.fields.map(field => ({
type: 'PropertyValue', type: 'PropertyValue',
name: field.name, name: field.name,
value: (field.value.startsWith('http://') || field.value.startsWith('https://')) value: (field.value.startsWith('http://') || field.value.startsWith('https://'))
? `<a href="${new URL(field.value).href}" rel="me nofollow noopener" target="_blank">${new URL(field.value).href}</a>` ? tryRewriteUrl(field.value)
: field.value, : field.value,
})); }));

View File

@@ -560,7 +560,7 @@ export class ApPersonService implements OnModuleInit {
inbox: person.inbox, inbox: person.inbox,
sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null, sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null,
followersUri: person.followers ? getApId(person.followers) : undefined, followersUri: person.followers ? getApId(person.followers) : undefined,
featured: person.featured, featured: person.featured ? getApId(person.featured) : undefined,
emojis: emojiNames, emojis: emojiNames,
name: truncate(person.name, nameLength), name: truncate(person.name, nameLength),
tags, tags,

View File

@@ -751,7 +751,7 @@ export class ActivityPubServerService {
}); });
// follow // follow
fastify.get<{ Params: { followRequestId: string ; } }>('/follows/:followRequestId', async (request, reply) => { fastify.get<{ Params: { followRequestId: string; } }>('/follows/:followRequestId', async (request, reply) => {
// This may be used before the follow is completed, so we do not // This may be used before the follow is completed, so we do not
// check if the following exists and only check if the follow request exists. // check if the following exists and only check if the follow request exists.

View File

@@ -497,7 +497,7 @@ export class FileServerService {
@bindThis @bindThis
private async downloadAndDetectTypeFromUrl(url: string): Promise< private async downloadAndDetectTypeFromUrl(url: string): Promise<
{ state: 'remote' ; mime: string; ext: string | null; path: string; cleanup: () => void; filename: string; } { state: 'remote'; mime: string; ext: string | null; path: string; cleanup: () => void; filename: string; }
> { > {
const [path, cleanup] = await createTemp(); const [path, cleanup] = await createTemp();
try { try {

View File

@@ -95,6 +95,7 @@ interface ClientInformation {
id: string; id: string;
redirectUris: string[]; redirectUris: string[];
name: string; name: string;
logo: string | null;
} }
// https://indieauth.spec.indieweb.org/#client-information-discovery // https://indieauth.spec.indieweb.org/#client-information-discovery
@@ -124,11 +125,19 @@ async function discoverClientInformation(logger: Logger, httpRequestService: Htt
redirectUris.push(...[...fragment.querySelectorAll<HTMLLinkElement>('link[rel=redirect_uri][href]')].map(el => el.href)); redirectUris.push(...[...fragment.querySelectorAll<HTMLLinkElement>('link[rel=redirect_uri][href]')].map(el => el.href));
let name = id; let name = id;
let logo: string | null = null;
if (text) { if (text) {
const microformats = mf2(text, { baseUrl: res.url }); const microformats = mf2(text, { baseUrl: res.url });
const nameProperty = microformats.items.find(item => item.type?.includes('h-app') && item.properties.url.includes(id))?.properties.name[0]; const correspondingProperties = microformats.items.find(item => item.type?.includes('h-app') && item.properties.url.includes(id));
if (typeof nameProperty === 'string') { if (correspondingProperties) {
name = nameProperty; const nameProperty = correspondingProperties.properties.name?.[0];
if (typeof nameProperty === 'string') {
name = nameProperty;
}
const logoProperty = correspondingProperties.properties.logo?.[0];
if (typeof logoProperty === 'string') {
logo = logoProperty;
}
} }
} }
@@ -136,6 +145,7 @@ async function discoverClientInformation(logger: Logger, httpRequestService: Htt
id, id,
redirectUris: redirectUris.map(uri => new URL(uri, res.url).toString()), redirectUris: redirectUris.map(uri => new URL(uri, res.url).toString()),
name: typeof name === 'string' ? name : id, name: typeof name === 'string' ? name : id,
logo,
}; };
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@@ -379,6 +389,7 @@ export class OAuth2ProviderService {
return await reply.view('oauth', { return await reply.view('oauth', {
transactionId: oauth2.transactionID, transactionId: oauth2.transactionID,
clientName: oauth2.client.name, clientName: oauth2.client.name,
clientLogo: oauth2.client.logo,
scope: oauth2.req.scope.join(' '), scope: oauth2.req.scope.join(' '),
}); });
}); });

View File

@@ -6,4 +6,6 @@ block meta
//- XXX: Remove navigation bar in auth page? //- XXX: Remove navigation bar in auth page?
meta(name='misskey:oauth:transaction-id' content=transactionId) meta(name='misskey:oauth:transaction-id' content=transactionId)
meta(name='misskey:oauth:client-name' content=clientName) meta(name='misskey:oauth:client-name' content=clientName)
if clientLogo
meta(name='misskey:oauth:client-logo' content=clientLogo)
meta(name='misskey:oauth:scope' content=scope) meta(name='misskey:oauth:scope' content=scope)

View File

@@ -17,7 +17,6 @@ services:
- ./.config/docker.env - ./.config/docker.env
environment: environment:
- NODE_ENV=production - NODE_ENV=production
- COREPACK_DEFAULT_TO_LATEST=0
volumes: volumes:
- type: bind - type: bind
source: ../../../built source: ../../../built
@@ -75,6 +74,10 @@ services:
source: ../../../pnpm-workspace.yaml source: ../../../pnpm-workspace.yaml
target: /misskey/pnpm-workspace.yaml target: /misskey/pnpm-workspace.yaml
read_only: true read_only: true
- type: bind
source: ../../../scripts/dependency-patches
target: /misskey/scripts/dependency-patches
read_only: true
- type: bind - type: bind
source: ./certificates/rootCA.crt source: ./certificates/rootCA.crt
target: /usr/local/share/ca-certificates/rootCA.crt target: /usr/local/share/ca-certificates/rootCA.crt
@@ -82,7 +85,7 @@ services:
working_dir: /misskey working_dir: /misskey
command: > command: >
bash -c " bash -c "
corepack enable && corepack prepare npm install -g pnpm
pnpm -F backend migrate pnpm -F backend migrate
pnpm -F backend start pnpm -F backend start
" "

View File

@@ -9,7 +9,7 @@ services:
service: misskey service: misskey
command: > command: >
bash -c " bash -c "
corepack enable && corepack prepare npm install -g pnpm
pnpm -F backend i pnpm -F backend i
pnpm -F misskey-js i pnpm -F misskey-js i
pnpm -F misskey-reversi i pnpm -F misskey-reversi i
@@ -29,7 +29,6 @@ services:
environment: environment:
- NODE_ENV=development - NODE_ENV=development
- NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/rootCA.crt - NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/rootCA.crt
- COREPACK_DEFAULT_TO_LATEST=0
volumes: volumes:
- type: bind - type: bind
source: ../package.json source: ../package.json
@@ -71,6 +70,10 @@ services:
source: ../../../pnpm-workspace.yaml source: ../../../pnpm-workspace.yaml
target: /misskey/pnpm-workspace.yaml target: /misskey/pnpm-workspace.yaml
read_only: true read_only: true
- type: bind
source: ../../../scripts/dependency-patches
target: /misskey/scripts/dependency-patches
read_only: true
- type: bind - type: bind
source: ./certificates/rootCA.crt source: ./certificates/rootCA.crt
target: /usr/local/share/ca-certificates/rootCA.crt target: /usr/local/share/ca-certificates/rootCA.crt
@@ -78,7 +81,7 @@ services:
working_dir: /misskey working_dir: /misskey
entrypoint: > entrypoint: >
bash -c ' bash -c '
corepack enable && corepack prepare npm install -g pnpm
pnpm -F misskey-js i --frozen-lockfile pnpm -F misskey-js i --frozen-lockfile
pnpm -F backend i --frozen-lockfile pnpm -F backend i --frozen-lockfile
exec "$0" "$@" exec "$0" "$@"
@@ -90,8 +93,6 @@ services:
depends_on: depends_on:
redis.test: redis.test:
condition: service_healthy condition: service_healthy
environment:
- COREPACK_DEFAULT_TO_LATEST=0
volumes: volumes:
- type: bind - type: bind
source: ../package.json source: ../package.json
@@ -117,10 +118,14 @@ services:
source: ../../../pnpm-workspace.yaml source: ../../../pnpm-workspace.yaml
target: /misskey/pnpm-workspace.yaml target: /misskey/pnpm-workspace.yaml
read_only: true read_only: true
- type: bind
source: ../../../scripts/dependency-patches
target: /misskey/scripts/dependency-patches
read_only: true
working_dir: /misskey working_dir: /misskey
command: > command: >
bash -c " bash -c "
corepack enable && corepack prepare npm install -g pnpm
pnpm -F backend i --frozen-lockfile pnpm -F backend i --frozen-lockfile
pnpm exec tsc -p ./packages/backend/test-federation pnpm exec tsc -p ./packages/backend/test-federation
node ./packages/backend/test-federation/built/daemon.js node ./packages/backend/test-federation/built/daemon.js

View File

@@ -72,11 +72,12 @@ const clientConfig: ModuleOptions<'client_id'> = {
}, },
}; };
function getMeta(html: string): { transactionId: string | undefined, clientName: string | undefined } { function getMeta(html: string): { transactionId: string | undefined, clientName: string | undefined, clientLogo: string | undefined } {
const fragment = JSDOM.fragment(html); const fragment = JSDOM.fragment(html);
return { return {
transactionId: fragment.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:transaction-id"]')?.content, transactionId: fragment.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:transaction-id"]')?.content,
clientName: fragment.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-name"]')?.content, clientName: fragment.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-name"]')?.content,
clientLogo: fragment.querySelector<HTMLMetaElement>('meta[name="misskey:oauth:client-logo"]')?.content,
}; };
} }
@@ -915,6 +916,59 @@ describe('OAuth', () => {
assert.strictEqual(getMeta(await response.text()).clientName, `http://127.0.0.1:${clientPort}/`); assert.strictEqual(getMeta(await response.text()).clientName, `http://127.0.0.1:${clientPort}/`);
}); });
test('With Logo', async () => {
sender = (reply): void => {
reply.header('Link', '</redirect>; rel="redirect_uri"');
reply.send(`
<!DOCTYPE html>
<div class="h-app">
<a href="/" class="u-url p-name">Misklient</a>
<img src="/logo.png" class="u-logo" />
</div>
`);
reply.send();
};
const client = new AuthorizationCode(clientConfig);
const response = await fetch(client.authorizeURL({
redirect_uri,
scope: 'write:notes',
state: 'state',
code_challenge: 'code',
code_challenge_method: 'S256',
} as AuthorizationParamsExtended));
assert.strictEqual(response.status, 200);
const meta = getMeta(await response.text());
assert.strictEqual(meta.clientName, 'Misklient');
assert.strictEqual(meta.clientLogo, `http://127.0.0.1:${clientPort}/logo.png`);
});
test('Missing Logo', async () => {
sender = (reply): void => {
reply.header('Link', '</redirect>; rel="redirect_uri"');
reply.send(`
<!DOCTYPE html>
<div class="h-app"><a href="/" class="u-url p-name">Misklient
`);
reply.send();
};
const client = new AuthorizationCode(clientConfig);
const response = await fetch(client.authorizeURL({
redirect_uri,
scope: 'write:notes',
state: 'state',
code_challenge: 'code',
code_challenge_method: 'S256',
} as AuthorizationParamsExtended));
assert.strictEqual(response.status, 200);
const meta = getMeta(await response.text());
assert.strictEqual(meta.clientName, 'Misklient');
assert.strictEqual(meta.clientLogo, undefined);
});
test('Mismatching URL in h-app', async () => { test('Mismatching URL in h-app', async () => {
sender = (reply): void => { sender = (reply): void => {
reply.header('Link', '</redirect>; rel="redirect_uri"'); reply.header('Link', '</redirect>; rel="redirect_uri"');

View File

@@ -14,7 +14,7 @@
"@rollup/plugin-json": "6.1.0", "@rollup/plugin-json": "6.1.0",
"@rollup/plugin-replace": "6.0.2", "@rollup/plugin-replace": "6.0.2",
"@rollup/pluginutils": "5.1.4", "@rollup/pluginutils": "5.1.4",
"@tabler/icons-webfont": "https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.30.0-mi.1932+ab127beee.tar.gz", "@tabler/icons-webfont": "3.31.0",
"@twemoji/parser": "15.1.1", "@twemoji/parser": "15.1.1",
"@vitejs/plugin-vue": "5.2.1", "@vitejs/plugin-vue": "5.2.1",
"@vue/compiler-sfc": "3.5.13", "@vue/compiler-sfc": "3.5.13",
@@ -34,7 +34,7 @@
"typescript": "5.8.2", "typescript": "5.8.2",
"uuid": "11.1.0", "uuid": "11.1.0",
"json5": "2.2.3", "json5": "2.2.3",
"vite": "6.2.0", "vite": "6.2.1",
"vue": "3.5.13" "vue": "3.5.13"
}, },
"devDependencies": { "devDependencies": {
@@ -48,14 +48,14 @@
"@types/ws": "8.18.0", "@types/ws": "8.18.0",
"@typescript-eslint/eslint-plugin": "8.26.0", "@typescript-eslint/eslint-plugin": "8.26.0",
"@typescript-eslint/parser": "8.26.0", "@typescript-eslint/parser": "8.26.0",
"@vitest/coverage-v8": "3.0.7", "@vitest/coverage-v8": "3.0.8",
"@vue/runtime-core": "3.5.13", "@vue/runtime-core": "3.5.13",
"acorn": "8.14.0", "acorn": "8.14.1",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-vue": "9.33.0", "eslint-plugin-vue": "10.0.0",
"fast-glob": "3.3.3", "fast-glob": "3.3.3",
"happy-dom": "17.2.2", "happy-dom": "17.3.0",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"msw": "2.7.3", "msw": "2.7.3",
@@ -64,7 +64,7 @@
"start-server-and-test": "2.0.10", "start-server-and-test": "2.0.10",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vue-component-type-helpers": "2.2.8", "vue-component-type-helpers": "2.2.8",
"vue-eslint-parser": "9.4.3", "vue-eslint-parser": "10.1.1",
"vue-tsc": "2.2.8" "vue-tsc": "2.2.8"
} }
} }

View File

@@ -25,10 +25,10 @@
"@typescript-eslint/eslint-plugin": "8.26.0", "@typescript-eslint/eslint-plugin": "8.26.0",
"@typescript-eslint/parser": "8.26.0", "@typescript-eslint/parser": "8.26.0",
"esbuild": "0.25.0", "esbuild": "0.25.0",
"eslint-plugin-vue": "9.33.0", "eslint-plugin-vue": "10.0.0",
"nodemon": "3.1.9", "nodemon": "3.1.9",
"typescript": "5.8.2", "typescript": "5.8.2",
"vue-eslint-parser": "9.4.3" "vue-eslint-parser": "10.1.1"
}, },
"files": [ "files": [
"js-built" "js-built"

View File

@@ -39,6 +39,10 @@ const config = {
if (~replacePluginForIsChromatic) { if (~replacePluginForIsChromatic) {
config.plugins?.splice(replacePluginForIsChromatic, 1); config.plugins?.splice(replacePluginForIsChromatic, 1);
} }
//pluginsからcreateSearchIndexを削除、複数あるかもしれないので全て削除
config.plugins = config.plugins?.filter((plugin: Plugin) => plugin && plugin.name !== 'createSearchIndex') ?? [];
return mergeConfig(config, { return mergeConfig(config, {
plugins: [ plugins: [
{ {

View File

@@ -5,7 +5,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true" as="image" type="image/png" crossorigin="anonymous"> <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/about-icon.png?raw=true" as="image" type="image/png" crossorigin="anonymous">
<link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true" as="image" type="image/jpeg" crossorigin="anonymous"> <link rel="preload" href="https://github.com/misskey-dev/misskey/blob/master/packages/frontend/assets/fedi.jpg?raw=true" as="image" type="image/jpeg" crossorigin="anonymous">
<link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@3.3.0/dist/tabler-icons.min.css"> <link rel="stylesheet" href="https://unpkg.com/@tabler/icons-webfont@3.31.0/dist/tabler-icons.min.css">
<link rel="stylesheet" href="https://unpkg.com/@fontsource/m-plus-rounded-1c/index.css"> <link rel="stylesheet" href="https://unpkg.com/@fontsource/m-plus-rounded-1c/index.css">
<style> <style>
html { html {

View File

@@ -21,7 +21,7 @@ let moduleInitialized = false;
let unobserve = () => {}; let unobserve = () => {};
let misskeyOS = null; let misskeyOS = null;
function loadTheme(applyTheme: typeof import('../src/scripts/theme')['applyTheme']) { function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) {
unobserve(); unobserve();
const theme = themes[document.documentElement.dataset.misskeyTheme]; const theme = themes[document.documentElement.dataset.misskeyTheme];
if (theme) { if (theme) {
@@ -67,10 +67,10 @@ queueMicrotask(() => {
import('../src/components'), import('../src/components'),
import('../src/directives'), import('../src/directives'),
import('../src/widgets'), import('../src/widgets'),
import('../src/scripts/theme'), import('../src/theme'),
import('../src/store'), import('../src/preferences'),
import('../src/os'), import('../src/os'),
]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { defaultStore }, os]) => { ]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { prefer }, os]) => {
setup((app) => { setup((app) => {
moduleInitialized = true; moduleInitialized = true;
if (app[appInitialized]) { if (app[appInitialized]) {
@@ -83,7 +83,7 @@ queueMicrotask(() => {
widgets(app); widgets(app);
misskeyOS = os; misskeyOS = os;
if (isChromatic()) { if (isChromatic()) {
defaultStore.set('animation', false); prefer.set('animation', false);
} }
}); });
}); });
@@ -104,9 +104,9 @@ const preview = {
} }
}).catch(() => {}) }).catch(() => {})
: Promise.resolve(); : Promise.resolve();
const resetDefaultStorePromise = import('../src/store').then(({ defaultStore }) => { const resetDefaultStorePromise = import('../src/store').then(({ store }) => {
// @ts-expect-error // @ts-expect-error
defaultStore.init(); store.init();
}).catch(() => {}); }).catch(() => {});
Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => { Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => {
initLocalStorage(); initLocalStorage();

View File

@@ -4,7 +4,7 @@
*/ */
declare module '@@/themes/*.json5' { declare module '@@/themes/*.json5' {
import { Theme } from '@/scripts/theme.js'; import { Theme } from '@/theme.js';
const theme: Theme; const theme: Theme;

View File

@@ -58,7 +58,7 @@ describe(normalizeClass.name, () => {
it('Composition API (standard)', () => { it('Composition API (standard)', () => {
const ast = parse(` const ast = parse(`
import { c as api, d as defaultStore, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js'; import { c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc } from './app-!~{001}~.js';
import { M as MkContainer } from './MkContainer-!~{03M}~.js'; import { M as MkContainer } from './MkContainer-!~{03M}~.js';
import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js'; import { b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode } from './vue-!~{002}~.js';
import './photoswipe-!~{003}~.js'; import './photoswipe-!~{003}~.js';
@@ -74,7 +74,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
let fetching = ref(true); let fetching = ref(true);
let images = ref([]); let images = ref([]);
function thumbnail(image) { function thumbnail(image) {
return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; return store.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl;
} }
onMounted(() => { onMounted(() => {
const image = [ const image = [
@@ -173,7 +173,7 @@ export { index_photos as default };
`.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); `.slice(1), { ecmaVersion: 'latest', sourceType: 'module' });
unwindCssModuleClassName(ast); unwindCssModuleClassName(ast);
expect(generate(ast)).toBe(` expect(generate(ast)).toBe(`
import {c as api, d as defaultStore, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js'; import {c as api, d as store, i as i18n, aD as notePage, bN as ImgWithBlurhash, bY as getStaticImageUrl, _ as _export_sfc} from './app-!~{001}~.js';
import {M as MkContainer} from './MkContainer-!~{03M}~.js'; import {M as MkContainer} from './MkContainer-!~{03M}~.js';
import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js'; import {b as defineComponent, a as ref, e as onMounted, z as resolveComponent, g as openBlock, h as createBlock, i as withCtx, K as createTextVNode, E as toDisplayString, u as unref, l as createBaseVNode, q as normalizeClass, B as createCommentVNode, k as createElementBlock, F as Fragment, C as renderList, A as createVNode} from './vue-!~{002}~.js';
import './photoswipe-!~{003}~.js'; import './photoswipe-!~{003}~.js';
@@ -190,7 +190,7 @@ const index_photos = defineComponent({
let fetching = ref(true); let fetching = ref(true);
let images = ref([]); let images = ref([]);
function thumbnail(image) { function thumbnail(image) {
return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; return store.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl;
} }
onMounted(() => { onMounted(() => {
const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"]; const image = ["image/jpeg", "image/webp", "image/avif", "image/png", "image/gif", "image/apng", "image/vnd.mozilla.apng"];
@@ -268,7 +268,7 @@ export {index_photos as default};
it('Composition API (with `useCssModule()`)', () => { it('Composition API (with `useCssModule()`)', () => {
const ast = parse(` const ast = parse(`
import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js'; import { a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup } from './!~{002}~.js';
import { d as defaultStore, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js'; import { d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc } from './app-!~{001}~.js';
function isDebuggerEnabled(id) { function isDebuggerEnabled(id) {
try { try {
@@ -393,7 +393,7 @@ const _sfc_main = defineComponent({
el.style.left = ""; el.style.left = "";
} }
return () => h( return () => h(
defaultStore.state.animation ? TransitionGroup : "div", prefer.s.animation ? TransitionGroup : "div",
{ {
class: { class: {
[$style["date-separated-list"]]: true, [$style["date-separated-list"]]: true,
@@ -402,7 +402,7 @@ const _sfc_main = defineComponent({
[$style["direction-down"]]: props.direction === "down", [$style["direction-down"]]: props.direction === "down",
[$style["direction-up"]]: props.direction === "up" [$style["direction-up"]]: props.direction === "up"
}, },
...defaultStore.state.animation ? { ...prefer.s.animation ? {
name: "list", name: "list",
tag: "div", tag: "div",
onBeforeLeave, onBeforeLeave,
@@ -441,7 +441,7 @@ export { MkDateSeparatedList as M };
unwindCssModuleClassName(ast); unwindCssModuleClassName(ast);
expect(generate(ast)).toBe(` expect(generate(ast)).toBe(`
import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js'; import {a7 as getCurrentInstance, b as defineComponent, G as useCssModule, a1 as h, H as TransitionGroup} from './!~{002}~.js';
import {d as defaultStore, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js'; import {d as store, aK as toast, b5 as MkAd, i as i18n, _ as _export_sfc} from './app-!~{001}~.js';
function isDebuggerEnabled(id) { function isDebuggerEnabled(id) {
try { try {
return localStorage.getItem(\`DEBUG_\${id}\`) !== null; return localStorage.getItem(\`DEBUG_\${id}\`) !== null;
@@ -555,7 +555,7 @@ const _sfc_main = defineComponent({
el.style.top = ""; el.style.top = "";
el.style.left = ""; el.style.left = "";
} }
return () => h(defaultStore.state.animation ? TransitionGroup : "div", { return () => h(prefer.s.animation ? TransitionGroup : "div", {
class: { class: {
[$style["date-separated-list"]]: true, [$style["date-separated-list"]]: true,
[$style["date-separated-list-nogap"]]: props.noGap, [$style["date-separated-list-nogap"]]: props.noGap,
@@ -563,7 +563,7 @@ const _sfc_main = defineComponent({
[$style["direction-down"]]: props.direction === "down", [$style["direction-down"]]: props.direction === "down",
[$style["direction-up"]]: props.direction === "up" [$style["direction-up"]]: props.direction === "up"
}, },
...defaultStore.state.animation ? { ...prefer.s.animation ? {
name: "list", name: "list",
tag: "div", tag: "div",
onBeforeLeave, onBeforeLeave,

File diff suppressed because it is too large Load Diff

View File

@@ -25,7 +25,7 @@
"@rollup/plugin-replace": "6.0.2", "@rollup/plugin-replace": "6.0.2",
"@rollup/pluginutils": "5.1.4", "@rollup/pluginutils": "5.1.4",
"@syuilo/aiscript": "0.19.0", "@syuilo/aiscript": "0.19.0",
"@tabler/icons-webfont": "https://github.com/misskey-dev/tabler-icons/archive/refs/tags/3.30.0-mi.1932+ab127beee.tar.gz", "@tabler/icons-webfont": "3.31.0",
"@twemoji/parser": "15.1.1", "@twemoji/parser": "15.1.1",
"@vitejs/plugin-vue": "5.2.1", "@vitejs/plugin-vue": "5.2.1",
"@vue/compiler-sfc": "3.5.13", "@vue/compiler-sfc": "3.5.13",
@@ -51,6 +51,7 @@
"insert-text-at-cursor": "0.3.0", "insert-text-at-cursor": "0.3.0",
"is-file-animated": "1.0.2", "is-file-animated": "1.0.2",
"json5": "2.2.3", "json5": "2.2.3",
"magic-string": "0.30.17",
"matter-js": "0.20.0", "matter-js": "0.20.0",
"mfm-js": "0.24.0", "mfm-js": "0.24.0",
"misskey-bubble-game": "workspace:*", "misskey-bubble-game": "workspace:*",
@@ -72,30 +73,31 @@
"typescript": "5.8.2", "typescript": "5.8.2",
"uuid": "11.1.0", "uuid": "11.1.0",
"v-code-diff": "1.13.1", "v-code-diff": "1.13.1",
"vite": "6.2.0", "vite": "6.2.1",
"vue": "3.5.13", "vue": "3.5.13",
"vuedraggable": "next" "vuedraggable": "next",
"wanakana": "5.3.1"
}, },
"devDependencies": { "devDependencies": {
"@misskey-dev/summaly": "5.2.0", "@misskey-dev/summaly": "5.2.0",
"@storybook/addon-actions": "8.6.3", "@storybook/addon-actions": "8.6.4",
"@storybook/addon-essentials": "8.6.3", "@storybook/addon-essentials": "8.6.4",
"@storybook/addon-interactions": "8.6.3", "@storybook/addon-interactions": "8.6.4",
"@storybook/addon-links": "8.6.3", "@storybook/addon-links": "8.6.4",
"@storybook/addon-mdx-gfm": "8.6.3", "@storybook/addon-mdx-gfm": "8.6.4",
"@storybook/addon-storysource": "8.6.3", "@storybook/addon-storysource": "8.6.4",
"@storybook/blocks": "8.6.3", "@storybook/blocks": "8.6.4",
"@storybook/components": "8.6.3", "@storybook/components": "8.6.4",
"@storybook/core-events": "8.6.3", "@storybook/core-events": "8.6.4",
"@storybook/manager-api": "8.6.3", "@storybook/manager-api": "8.6.4",
"@storybook/preview-api": "8.6.3", "@storybook/preview-api": "8.6.4",
"@storybook/react": "8.6.3", "@storybook/react": "8.6.4",
"@storybook/react-vite": "8.6.3", "@storybook/react-vite": "8.6.4",
"@storybook/test": "8.6.3", "@storybook/test": "8.6.4",
"@storybook/theming": "8.6.3", "@storybook/theming": "8.6.4",
"@storybook/types": "8.6.3", "@storybook/types": "8.6.4",
"@storybook/vue3": "8.6.3", "@storybook/vue3": "8.6.4",
"@storybook/vue3-vite": "8.6.3", "@storybook/vue3-vite": "8.6.4",
"@testing-library/vue": "8.1.0", "@testing-library/vue": "8.1.0",
"@types/canvas-confetti": "1.9.0", "@types/canvas-confetti": "1.9.0",
"@types/estree": "1.0.6", "@types/estree": "1.0.6",
@@ -110,15 +112,15 @@
"@types/ws": "8.18.0", "@types/ws": "8.18.0",
"@typescript-eslint/eslint-plugin": "8.26.0", "@typescript-eslint/eslint-plugin": "8.26.0",
"@typescript-eslint/parser": "8.26.0", "@typescript-eslint/parser": "8.26.0",
"@vitest/coverage-v8": "3.0.7", "@vitest/coverage-v8": "3.0.8",
"@vue/runtime-core": "3.5.13", "@vue/runtime-core": "3.5.13",
"acorn": "8.14.0", "acorn": "8.14.1",
"cross-env": "7.0.3", "cross-env": "7.0.3",
"cypress": "14.1.0", "cypress": "14.1.0",
"eslint-plugin-import": "2.31.0", "eslint-plugin-import": "2.31.0",
"eslint-plugin-vue": "9.33.0", "eslint-plugin-vue": "10.0.0",
"fast-glob": "3.3.3", "fast-glob": "3.3.3",
"happy-dom": "17.2.2", "happy-dom": "17.3.0",
"intersection-observer": "0.12.2", "intersection-observer": "0.12.2",
"micromatch": "4.0.8", "micromatch": "4.0.8",
"msw": "2.7.3", "msw": "2.7.3",
@@ -129,13 +131,13 @@
"react-dom": "19.0.0", "react-dom": "19.0.0",
"seedrandom": "3.0.5", "seedrandom": "3.0.5",
"start-server-and-test": "2.0.10", "start-server-and-test": "2.0.10",
"storybook": "8.6.3", "storybook": "8.6.4",
"storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme", "storybook-addon-misskey-theme": "github:misskey-dev/storybook-addon-misskey-theme",
"vite-plugin-turbosnap": "1.0.3", "vite-plugin-turbosnap": "1.0.3",
"vitest": "3.0.7", "vitest": "3.0.8",
"vitest-fetch-mock": "0.4.5", "vitest-fetch-mock": "0.4.5",
"vue-component-type-helpers": "2.2.8", "vue-component-type-helpers": "2.2.8",
"vue-eslint-parser": "9.4.3", "vue-eslint-parser": "10.1.1",
"vue-tsc": "2.2.8" "vue-tsc": "2.2.8"
} }
} }

View File

@@ -8,13 +8,13 @@ import * as Misskey from 'misskey-js';
import { apiUrl } from '@@/js/config.js'; import { apiUrl } from '@@/js/config.js';
import type { MenuItem, MenuButton } from '@/types/menu.js'; import type { MenuItem, MenuButton } from '@/types/menu.js';
import { defaultMemoryStorage } from '@/memory-storage'; import { defaultMemoryStorage } from '@/memory-storage';
import { showSuspendedDialog } from '@/scripts/show-suspended-dialog.js'; import { showSuspendedDialog } from '@/utility/show-suspended-dialog.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { del, get, set } from '@/scripts/idb-proxy.js'; import { del, get, set } from '@/utility/idb-proxy.js';
import { waiting, popup, popupMenu, success, alert } from '@/os.js'; import { waiting, popup, popupMenu, success, alert } from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { unisonReload, reloadChannel } from '@/scripts/unison-reload.js'; import { unisonReload, reloadChannel } from '@/utility/unison-reload.js';
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期

View File

@@ -8,7 +8,7 @@ import * as Misskey from 'misskey-js';
import { url, lang } from '@@/js/config.js'; import { url, lang } from '@@/js/config.js';
import { assertStringAndIsIn } from './common.js'; import { assertStringAndIsIn } from './common.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { customEmojis } from '@/custom-emojis.js'; import { customEmojis } from '@/custom-emojis.js';

View File

@@ -6,26 +6,29 @@
import { computed, watch, version as vueVersion } from 'vue'; import { computed, watch, version as vueVersion } from 'vue';
import { compareVersions } from 'compare-versions'; import { compareVersions } from 'compare-versions';
import { version, lang, updateLocale, locale } from '@@/js/config.js'; import { version, lang, updateLocale, locale } from '@@/js/config.js';
import defaultLightTheme from '@@/themes/l-light.json5';
import defaultDarkTheme from '@@/themes/d-green-lime.json5';
import type { App } from 'vue'; import type { App } from 'vue';
import widgets from '@/widgets/index.js'; import widgets from '@/widgets/index.js';
import directives from '@/directives/index.js'; import directives from '@/directives/index.js';
import components from '@/components/index.js'; import components from '@/components/index.js';
import { applyTheme } from '@/scripts/theme.js'; import { applyTheme } from '@/theme.js';
import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js'; import { isDeviceDarkmode } from '@/utility/is-device-darkmode.js';
import { updateI18n, i18n } from '@/i18n.js'; import { updateI18n, i18n } from '@/i18n.js';
import { $i, refreshAccount, login } from '@/account.js'; import { $i, refreshAccount, login } from '@/account.js';
import { defaultStore, ColdDeviceStorage } from '@/store.js'; import { store } from '@/store.js';
import { fetchInstance, instance } from '@/instance.js'; import { fetchInstance, instance } from '@/instance.js';
import { deviceKind, updateDeviceKind } from '@/scripts/device-kind.js'; import { deviceKind, updateDeviceKind } from '@/utility/device-kind.js';
import { reloadChannel } from '@/scripts/unison-reload.js'; import { reloadChannel } from '@/utility/unison-reload.js';
import { getUrlWithoutLoginId } from '@/scripts/login-id.js'; import { getUrlWithoutLoginId } from '@/utility/login-id.js';
import { getAccountFromId } from '@/scripts/get-account-from-id.js'; import { getAccountFromId } from '@/utility/get-account-from-id.js';
import { deckStore } from '@/ui/deck/deck-store.js'; import { deckStore } from '@/ui/deck/deck-store.js';
import { analytics, initAnalytics } from '@/analytics.js'; import { analytics, initAnalytics } from '@/analytics.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { fetchCustomEmojis } from '@/custom-emojis.js'; import { fetchCustomEmojis } from '@/custom-emojis.js';
import { setupRouter } from '@/router/main.js'; import { setupRouter } from '@/router/main.js';
import { createMainRouter } from '@/router/definition.js'; import { createMainRouter } from '@/router/definition.js';
import { prefer } from '@/preferences.js';
export async function common(createVue: () => App<Element>) { export async function common(createVue: () => App<Element>) {
console.info(`Misskey v${version}`); console.info(`Misskey v${version}`);
@@ -38,7 +41,7 @@ export async function common(createVue: () => App<Element>) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).$i = $i; (window as any).$i = $i;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).$store = defaultStore; (window as any).$store = store;
window.addEventListener('error', event => { window.addEventListener('error', event => {
console.error(event); console.error(event);
@@ -123,7 +126,7 @@ export async function common(createVue: () => App<Element>) {
html.setAttribute('lang', lang); html.setAttribute('lang', lang);
//#endregion //#endregion
await defaultStore.ready; await store.ready;
await deckStore.ready; await deckStore.ready;
const fetchInstanceMetaPromise = fetchInstance(); const fetchInstanceMetaPromise = fetchInstance();
@@ -151,56 +154,63 @@ export async function common(createVue: () => App<Element>) {
//#endregion //#endregion
// NOTE: この処理は必ずクライアント更新チェック処理より後に来ること(テーマ再構築のため) // NOTE: この処理は必ずクライアント更新チェック処理より後に来ること(テーマ再構築のため)
watch(defaultStore.reactiveState.darkMode, (darkMode) => { watch(store.reactiveState.darkMode, (darkMode) => {
applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); applyTheme(darkMode
? (prefer.s.darkTheme ?? defaultDarkTheme)
: (prefer.s.lightTheme ?? defaultLightTheme),
);
}, { immediate: miLocalStorage.getItem('theme') == null }); }, { immediate: miLocalStorage.getItem('theme') == null });
document.documentElement.dataset.colorScheme = defaultStore.state.darkMode ? 'dark' : 'light'; document.documentElement.dataset.colorScheme = store.state.darkMode ? 'dark' : 'light';
const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); const darkTheme = prefer.model('darkTheme');
const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); const lightTheme = prefer.model('lightTheme');
watch(darkTheme, (theme) => { watch(darkTheme, (theme) => {
if (defaultStore.state.darkMode) { if (store.state.darkMode) {
applyTheme(theme); applyTheme(theme ?? defaultDarkTheme);
} }
}); });
watch(lightTheme, (theme) => { watch(lightTheme, (theme) => {
if (!defaultStore.state.darkMode) { if (!store.state.darkMode) {
applyTheme(theme); applyTheme(theme ?? defaultLightTheme);
} }
}); });
//#region Sync dark mode //#region Sync dark mode
if (ColdDeviceStorage.get('syncDeviceDarkMode')) { if (prefer.s.syncDeviceDarkMode) {
defaultStore.set('darkMode', isDeviceDarkmode()); store.set('darkMode', isDeviceDarkmode());
} }
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (mql) => { window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (mql) => {
if (ColdDeviceStorage.get('syncDeviceDarkMode')) { if (prefer.s.syncDeviceDarkMode) {
defaultStore.set('darkMode', mql.matches); store.set('darkMode', mql.matches);
} }
}); });
//#endregion //#endregion
if (prefer.s.darkTheme && store.state.darkMode) {
if (miLocalStorage.getItem('themeId') !== prefer.s.darkTheme.id) applyTheme(prefer.s.darkTheme);
} else if (prefer.s.lightTheme && !store.state.darkMode) {
if (miLocalStorage.getItem('themeId') !== prefer.s.lightTheme.id) applyTheme(prefer.s.lightTheme);
}
fetchInstanceMetaPromise.then(() => { fetchInstanceMetaPromise.then(() => {
if (defaultStore.state.themeInitial) { // TODO: instance.defaultLightTheme/instance.defaultDarkThemeが不正な形式だった場合のケア
if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON.parse(instance.defaultLightTheme)); if (prefer.s.lightTheme == null && instance.defaultLightTheme != null) prefer.set('lightTheme', JSON.parse(instance.defaultLightTheme));
if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON.parse(instance.defaultDarkTheme)); if (prefer.s.darkTheme == null && instance.defaultDarkTheme != null) prefer.set('darkTheme', JSON.parse(instance.defaultDarkTheme));
defaultStore.set('themeInitial', false);
}
}); });
watch(defaultStore.reactiveState.overridedDeviceKind, (kind) => { watch(prefer.r.overridedDeviceKind, (kind) => {
updateDeviceKind(kind); updateDeviceKind(kind);
}, { immediate: true }); }, { immediate: true });
watch(defaultStore.reactiveState.useBlurEffectForModal, v => { watch(prefer.r.useBlurEffectForModal, v => {
document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none'); document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none');
}, { immediate: true }); }, { immediate: true });
watch(defaultStore.reactiveState.useBlurEffect, v => { watch(prefer.r.useBlurEffect, v => {
if (v) { if (v) {
document.documentElement.style.removeProperty('--MI-blur'); document.documentElement.style.removeProperty('--MI-blur');
} else { } else {
@@ -214,7 +224,7 @@ export async function common(createVue: () => App<Element>) {
navigator.wakeLock.request('screen'); navigator.wakeLock.request('screen');
} }
}); });
if (defaultStore.state.keepScreenOn && 'wakeLock' in navigator) { if (prefer.s.keepScreenOn && 'wakeLock' in navigator) {
navigator.wakeLock.request('screen') navigator.wakeLock.request('screen')
.then(onVisibilityChange) .then(onVisibilityChange)
.catch(() => { .catch(() => {

View File

@@ -5,26 +5,29 @@
import { createApp, defineAsyncComponent, markRaw } from 'vue'; import { createApp, defineAsyncComponent, markRaw } from 'vue';
import { ui } from '@@/js/config.js'; import { ui } from '@@/js/config.js';
import { common } from './common.js';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { common } from './common.js';
import type { Component } from 'vue'; import type { Component } from 'vue';
import type { Keymap } from '@/utility/hotkey.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { alert, confirm, popup, post, toast } from '@/os.js'; import { alert, confirm, popup, post, toast } from '@/os.js';
import { useStream } from '@/stream.js'; import { useStream } from '@/stream.js';
import * as sound from '@/scripts/sound.js'; import * as sound from '@/utility/sound.js';
import { $i, signout, updateAccountPartial } from '@/account.js'; import { $i, signout, updateAccountPartial } from '@/account.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { ColdDeviceStorage, defaultStore } from '@/store.js'; import { ColdDeviceStorage, store } from '@/store.js';
import { reactionPicker } from '@/scripts/reaction-picker.js'; import { reactionPicker } from '@/utility/reaction-picker.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js'; import { claimAchievement, claimedAchievements } from '@/utility/achievements.js';
import { initializeSw } from '@/scripts/initialize-sw.js'; import { initializeSw } from '@/utility/initialize-sw.js';
import { deckStore } from '@/ui/deck/deck-store.js'; import { emojiPicker } from '@/utility/emoji-picker.js';
import { emojiPicker } from '@/scripts/emoji-picker.js';
import { mainRouter } from '@/router/main.js'; import { mainRouter } from '@/router/main.js';
import { makeHotkey } from '@/scripts/hotkey.js'; import { makeHotkey } from '@/utility/hotkey.js';
import type { Keymap } from '@/scripts/hotkey.js';
import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js'; import { addCustomEmoji, removeCustomEmojis, updateCustomEmojis } from '@/custom-emojis.js';
import { prefer } from '@/preferences.js';
import { misskeyApi } from '@/utility/misskey-api.js';
import { deckStore } from '@/ui/deck/deck-store.js';
import { launchPlugins } from '@/plugin.js';
export async function mainBoot() { export async function mainBoot() {
const { isClientUpdated } = await common(() => { const { isClientUpdated } = await common(() => {
@@ -34,7 +37,7 @@ export async function mainBoot() {
if (!$i) uiStyle = 'visitor'; if (!$i) uiStyle = 'visitor';
if (searchParams.has('zen')) uiStyle = 'zen'; if (searchParams.has('zen')) uiStyle = 'zen';
if (uiStyle === 'deck' && deckStore.state.useSimpleUiForNonRootPages && location.pathname !== '/') uiStyle = 'zen'; if (uiStyle === 'deck' && prefer.s['deck.useSimpleUiForNonRootPages'] && location.pathname !== '/') uiStyle = 'zen';
if (searchParams.has('ui')) uiStyle = searchParams.get('ui'); if (searchParams.has('ui')) uiStyle = searchParams.get('ui');
@@ -73,9 +76,9 @@ export async function mainBoot() {
let reloadDialogShowing = false; let reloadDialogShowing = false;
stream.on('_disconnected_', async () => { stream.on('_disconnected_', async () => {
if (defaultStore.state.serverDisconnectedBehavior === 'reload') { if (prefer.s.serverDisconnectedBehavior === 'reload') {
location.reload(); location.reload();
} else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { } else if (prefer.s.serverDisconnectedBehavior === 'dialog') {
if (reloadDialogShowing) return; if (reloadDialogShowing) return;
reloadDialogShowing = true; reloadDialogShowing = true;
const { canceled } = await confirm({ const { canceled } = await confirm({
@@ -102,30 +105,24 @@ export async function mainBoot() {
removeCustomEmojis(emojiData.emojis); removeCustomEmojis(emojiData.emojis);
}); });
for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) { launchPlugins();
import('@/plugin.js').then(async ({ install }) => {
// Workaround for https://bugs.webkit.org/show_bug.cgi?id=242740
await new Promise(r => setTimeout(r, 0));
install(plugin);
});
}
try { try {
if (defaultStore.state.enableSeasonalScreenEffect) { if (prefer.s.enableSeasonalScreenEffect) {
const month = new Date().getMonth() + 1; const month = new Date().getMonth() + 1;
if (defaultStore.state.hemisphere === 'S') { if (prefer.s.hemisphere === 'S') {
// ▼南半球 // ▼南半球
if (month === 7 || month === 8) { if (month === 7 || month === 8) {
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; const SnowfallEffect = (await import('@/utility/snowfall-effect.js')).SnowfallEffect;
new SnowfallEffect({}).render(); new SnowfallEffect({}).render();
} }
} else { } else {
// ▼北半球 // ▼北半球
if (month === 12 || month === 1) { if (month === 12 || month === 1) {
const SnowfallEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; const SnowfallEffect = (await import('@/utility/snowfall-effect.js')).SnowfallEffect;
new SnowfallEffect({}).render(); new SnowfallEffect({}).render();
} else if (month === 3 || month === 4) { } else if (month === 3 || month === 4) {
const SakuraEffect = (await import('@/scripts/snowfall-effect.js')).SnowfallEffect; const SakuraEffect = (await import('@/utility/snowfall-effect.js')).SnowfallEffect;
new SakuraEffect({ new SakuraEffect({
sakura: true, sakura: true,
}).render(); }).render();
@@ -138,8 +135,101 @@ export async function mainBoot() {
} }
if ($i) { if ($i) {
defaultStore.loaded.then(() => { store.loaded.then(async () => {
if (defaultStore.state.accountSetupWizard !== -1) { // prefereces migration
// TODO: そのうち消す
if (store.state.menu.length > 0) {
const themes = await misskeyApi('i/registry/get', { scope: ['client'], key: 'themes' }).catch(() => []);
if (themes.length > 0) {
prefer.set('themes', themes);
}
const plugins = ColdDeviceStorage.get('plugins');
prefer.set('plugins', plugins.map(p => ({
...p,
installId: (p as any).id,
id: undefined,
})));
prefer.set('lightTheme', ColdDeviceStorage.get('lightTheme'));
prefer.set('darkTheme', ColdDeviceStorage.get('darkTheme'));
prefer.set('syncDeviceDarkMode', ColdDeviceStorage.get('syncDeviceDarkMode'));
prefer.set('overridedDeviceKind', store.state.overridedDeviceKind);
prefer.set('widgets', store.state.widgets);
prefer.set('keepCw', store.state.keepCw);
prefer.set('collapseRenotes', store.state.collapseRenotes);
prefer.set('rememberNoteVisibility', store.state.rememberNoteVisibility);
prefer.set('uploadFolder', store.state.uploadFolder);
prefer.set('keepOriginalUploading', store.state.keepOriginalUploading);
prefer.set('menu', store.state.menu);
prefer.set('statusbars', store.state.statusbars);
prefer.set('pinnedUserLists', store.state.pinnedUserLists);
prefer.set('serverDisconnectedBehavior', store.state.serverDisconnectedBehavior);
prefer.set('nsfw', store.state.nsfw);
prefer.set('highlightSensitiveMedia', store.state.highlightSensitiveMedia);
prefer.set('animation', store.state.animation);
prefer.set('animatedMfm', store.state.animatedMfm);
prefer.set('advancedMfm', store.state.advancedMfm);
prefer.set('showReactionsCount', store.state.showReactionsCount);
prefer.set('enableQuickAddMfmFunction', store.state.enableQuickAddMfmFunction);
prefer.set('loadRawImages', store.state.loadRawImages);
prefer.set('imageNewTab', store.state.imageNewTab);
prefer.set('disableShowingAnimatedImages', store.state.disableShowingAnimatedImages);
prefer.set('emojiStyle', store.state.emojiStyle);
prefer.set('menuStyle', store.state.menuStyle);
prefer.set('useBlurEffectForModal', store.state.useBlurEffectForModal);
prefer.set('useBlurEffect', store.state.useBlurEffect);
prefer.set('showFixedPostForm', store.state.showFixedPostForm);
prefer.set('showFixedPostFormInChannel', store.state.showFixedPostFormInChannel);
prefer.set('enableInfiniteScroll', store.state.enableInfiniteScroll);
prefer.set('useReactionPickerForContextMenu', store.state.useReactionPickerForContextMenu);
prefer.set('showGapBetweenNotesInTimeline', store.state.showGapBetweenNotesInTimeline);
prefer.set('instanceTicker', store.state.instanceTicker);
prefer.set('emojiPickerScale', store.state.emojiPickerScale);
prefer.set('emojiPickerWidth', store.state.emojiPickerWidth);
prefer.set('emojiPickerHeight', store.state.emojiPickerHeight);
prefer.set('emojiPickerStyle', store.state.emojiPickerStyle);
prefer.set('reportError', store.state.reportError);
prefer.set('squareAvatars', store.state.squareAvatars);
prefer.set('showAvatarDecorations', store.state.showAvatarDecorations);
prefer.set('numberOfPageCache', store.state.numberOfPageCache);
prefer.set('showNoteActionsOnlyHover', store.state.showNoteActionsOnlyHover);
prefer.set('showClipButtonInNoteFooter', store.state.showClipButtonInNoteFooter);
prefer.set('reactionsDisplaySize', store.state.reactionsDisplaySize);
prefer.set('limitWidthOfReaction', store.state.limitWidthOfReaction);
prefer.set('forceShowAds', store.state.forceShowAds);
prefer.set('aiChanMode', store.state.aiChanMode);
prefer.set('devMode', store.state.devMode);
prefer.set('mediaListWithOneImageAppearance', store.state.mediaListWithOneImageAppearance);
prefer.set('notificationPosition', store.state.notificationPosition);
prefer.set('notificationStackAxis', store.state.notificationStackAxis);
prefer.set('enableCondensedLine', store.state.enableCondensedLine);
prefer.set('keepScreenOn', store.state.keepScreenOn);
prefer.set('disableStreamingTimeline', store.state.disableStreamingTimeline);
prefer.set('useGroupedNotifications', store.state.useGroupedNotifications);
prefer.set('dataSaver', store.state.dataSaver);
prefer.set('enableSeasonalScreenEffect', store.state.enableSeasonalScreenEffect);
prefer.set('enableHorizontalSwipe', store.state.enableHorizontalSwipe);
prefer.set('useNativeUiForVideoAudioPlayer', store.state.useNativeUIForVideoAudioPlayer);
prefer.set('keepOriginalFilename', store.state.keepOriginalFilename);
prefer.set('alwaysConfirmFollow', store.state.alwaysConfirmFollow);
prefer.set('confirmWhenRevealingSensitiveMedia', store.state.confirmWhenRevealingSensitiveMedia);
prefer.set('contextMenu', store.state.contextMenu);
prefer.set('skipNoteRender', store.state.skipNoteRender);
prefer.set('showSoftWordMutedWord', store.state.showSoftWordMutedWord);
prefer.set('confirmOnReact', store.state.confirmOnReact);
prefer.set('sound.masterVolume', store.state.sound_masterVolume);
prefer.set('sound.notUseSound', store.state.sound_notUseSound);
prefer.set('sound.useSoundOnlyWhenActive', store.state.sound_useSoundOnlyWhenActive);
prefer.set('sound.on.note', store.state.sound_note as any);
prefer.set('sound.on.noteMy', store.state.sound_noteMy as any);
prefer.set('sound.on.notification', store.state.sound_notification as any);
prefer.set('sound.on.reaction', store.state.sound_reaction as any);
store.set('deck.profile', deckStore.state.profile);
store.set('deck.columns', deckStore.state.columns);
store.set('deck.layout', deckStore.state.layout);
store.set('menu', []);
}
if (store.state.accountSetupWizard !== -1) {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, { const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, {
closed: () => dispose(), closed: () => dispose(),
}); });
@@ -154,7 +244,7 @@ export async function mainBoot() {
}); });
} }
function onAnnouncementCreated (ev: { announcement: Misskey.entities.Announcement }) { function onAnnouncementCreated(ev: { announcement: Misskey.entities.Announcement }) {
const announcement = ev.announcement; const announcement = ev.announcement;
if (announcement.display === 'dialog') { if (announcement.display === 'dialog') {
const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), {
@@ -412,7 +502,7 @@ export async function mainBoot() {
post(); post();
}, },
'd': () => { 'd': () => {
defaultStore.set('darkMode', !defaultStore.state.darkMode); store.set('darkMode', !store.state.darkMode);
}, },
's': () => { 's': () => {
mainRouter.push('/search'); mainRouter.push('/search');

View File

@@ -5,7 +5,7 @@
import { createApp, defineAsyncComponent } from 'vue'; import { createApp, defineAsyncComponent } from 'vue';
import { common } from './common.js'; import { common } from './common.js';
import { emojiPicker } from '@/scripts/emoji-picker.js'; import { emojiPicker } from '@/utility/emoji-picker.js';
export async function subBoot() { export async function subBoot() {
const { isClientUpdated } = await common(() => createApp( const { isClientUpdated } = await common(() => createApp(

View File

@@ -4,8 +4,8 @@
*/ */
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { Cache } from '@/scripts/cache.js'; import { Cache } from '@/utility/cache.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
export const clipsCache = new Cache<Misskey.entities.Clip[]>(1000 * 60 * 30, () => misskeyApi('clips/list')); export const clipsCache = new Cache<Misskey.entities.Clip[]>(1000 * 60 * 30, () => misskeyApi('clips/list'));
export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list')); export const rolesCache = new Cache(1000 * 60 * 30, () => misskeyApi('admin/roles/list'));

View File

@@ -90,7 +90,7 @@ import MkFolder from '@/components/MkFolder.vue';
import RouterView from '@/components/global/RouterView.vue'; import RouterView from '@/components/global/RouterView.vue';
import { useRouterFactory } from '@/router/supplier'; import { useRouterFactory } from '@/router/supplier';
import MkTextarea from '@/components/MkTextarea.vue'; import MkTextarea from '@/components/MkTextarea.vue';
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
const props = defineProps<{ const props = defineProps<{
report: Misskey.entities.AdminAbuseUserReportsResponse[number]; report: Misskey.entities.AdminAbuseUserReportsResponse[number];

View File

@@ -17,7 +17,7 @@ import * as Misskey from 'misskey-js';
import MkMention from './MkMention.vue'; import MkMention from './MkMention.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { host as localHost } from '@@/js/config.js'; import { host as localHost } from '@@/js/config.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
const user = ref<Misskey.entities.UserLite>(); const user = ref<Misskey.entities.UserLite>();

View File

@@ -9,7 +9,7 @@ import { HttpResponse, http } from 'msw';
import { userDetailed } from '../../.storybook/fakes.js'; import { userDetailed } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js'; import { commonHandlers } from '../../.storybook/mocks.js';
import MkAchievements from './MkAchievements.vue'; import MkAchievements from './MkAchievements.vue';
import { ACHIEVEMENT_TYPES } from '@/scripts/achievements.js'; import { ACHIEVEMENT_TYPES } from '@/utility/achievements.js';
export const Empty = { export const Empty = {
render(args) { render(args) {
return { return {

View File

@@ -55,9 +55,9 @@ SPDX-License-Identifier: AGPL-3.0-only
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { onMounted, ref, computed } from 'vue'; import { onMounted, ref, computed } from 'vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/scripts/achievements.js'; import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/utility/achievements.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
user: Misskey.entities.User; user: Misskey.entities.User;

View File

@@ -82,7 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed, onMounted, onBeforeUnmount, ref } from 'vue'; import { computed, onMounted, onBeforeUnmount, ref } from 'vue';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { globalEvents } from '@/events.js'; import { globalEvents } from '@/events.js';
import { defaultIdlingRenderScheduler } from '@/scripts/idle-render.js'; import { defaultIdlingRenderScheduler } from '@/utility/idle-render.js';
// https://stackoverflow.com/questions/1878907/how-can-i-find-the-difference-between-two-angles // https://stackoverflow.com/questions/1878907/how-can-i-find-the-difference-between-two-angles
const angleDiff = (a: number, b: number) => { const angleDiff = (a: number, b: number) => {

View File

@@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { onMounted, shallowRef } from 'vue'; import { onMounted, shallowRef } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import MkModal from '@/components/MkModal.vue'; import MkModal from '@/components/MkModal.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';

View File

@@ -59,10 +59,10 @@ import MkTextarea from '@/components/MkTextarea.vue';
import MkSelect from '@/components/MkSelect.vue'; import MkSelect from '@/components/MkSelect.vue';
import MkSwitch from '@/components/MkSwitch.vue'; import MkSwitch from '@/components/MkSwitch.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { deepMerge } from '@/scripts/merge.js'; import { deepMerge } from '@/utility/merge.js';
import type { DeepPartial } from '@/scripts/merge.js'; import type { DeepPartial } from '@/utility/merge.js';
type PartialAllowedAntenna = Omit<Misskey.entities.Antenna, 'id' | 'createdAt' | 'updatedAt'> & { type PartialAllowedAntenna = Omit<Misskey.entities.Antenna, 'id' | 'createdAt' | 'updatedAt'> & {
id?: string; id?: string;

View File

@@ -71,7 +71,7 @@ import MkInput from '@/components/MkInput.vue';
import MkSwitch from '@/components/MkSwitch.vue'; import MkSwitch from '@/components/MkSwitch.vue';
import MkTextarea from '@/components/MkTextarea.vue'; import MkTextarea from '@/components/MkTextarea.vue';
import MkSelect from '@/components/MkSelect.vue'; import MkSelect from '@/components/MkSelect.vue';
import type { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/scripts/aiscript/ui.js'; import type { AsUiComponent, AsUiRoot, AsUiPostFormButton } from '@/aiscript/ui.js';
import MkFolder from '@/components/MkFolder.vue'; import MkFolder from '@/components/MkFolder.vue';
import MkPostForm from '@/components/MkPostForm.vue'; import MkPostForm from '@/components/MkPostForm.vue';

View File

@@ -123,8 +123,8 @@ import MkButton from '@/components/MkButton.vue';
import { $i, getAccounts, getAccountWithSigninDialog, getAccountWithSignupDialog } from '@/account.js'; import { $i, getAccounts, getAccountWithSigninDialog, getAccountWithSignupDialog } from '@/account.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { getProxiedImageUrl } from '@/scripts/media-proxy.js'; import { getProxiedImageUrl } from '@/utility/media-proxy.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
const props = defineProps<{ const props = defineProps<{
name?: string; name?: string;

View File

@@ -12,7 +12,7 @@ import { userDetailed } from '../../.storybook/fakes.js';
import { commonHandlers } from '../../.storybook/mocks.js'; import { commonHandlers } from '../../.storybook/mocks.js';
import MkAutocomplete from './MkAutocomplete.vue'; import MkAutocomplete from './MkAutocomplete.vue';
import MkInput from './MkInput.vue'; import MkInput from './MkInput.vue';
import { tick } from '@/scripts/test-utils.js'; import { tick } from '@/utility/test-utils.js';
const common = { const common = {
render(args) { render(args) {
return { return {

View File

@@ -49,22 +49,23 @@ import sanitizeHtml from 'sanitize-html';
import { emojilist, getEmojiName } from '@@/js/emojilist.js'; import { emojilist, getEmojiName } from '@@/js/emojilist.js';
import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js'; import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js';
import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js'; import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js';
import type { EmojiDef } from '@/scripts/search-emoji.js'; import type { EmojiDef } from '@/utility/search-emoji.js';
import contains from '@/scripts/contains.js'; import contains from '@/utility/contains.js';
import { acct } from '@/filters/user.js'; import { acct } from '@/filters/user.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { defaultStore } from '@/store.js'; import { store } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { customEmojis } from '@/custom-emojis.js'; import { customEmojis } from '@/custom-emojis.js';
import { searchEmoji } from '@/scripts/search-emoji.js'; import { searchEmoji } from '@/utility/search-emoji.js';
import { prefer } from '@/preferences.js';
const lib = emojilist.filter(x => x.category !== 'flags'); const lib = emojilist.filter(x => x.category !== 'flags');
const emojiDb = computed(() => { const emojiDb = computed(() => {
//#region Unicode Emoji //#region Unicode Emoji
const char2path = defaultStore.reactiveState.emojiStyle.value === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath; const char2path = prefer.r.emojiStyle.value === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath;
const unicodeEmojiDB: EmojiDef[] = lib.map(x => ({ const unicodeEmojiDB: EmojiDef[] = lib.map(x => ({
emoji: x.char, emoji: x.char,
@@ -72,7 +73,7 @@ const emojiDb = computed(() => {
url: char2path(x.char), url: char2path(x.char),
})); }));
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
for (const [emoji, keywords] of Object.entries(index)) { for (const [emoji, keywords] of Object.entries(index)) {
for (const k of keywords) { for (const k of keywords) {
unicodeEmojiDB.push({ unicodeEmojiDB.push({
@@ -154,10 +155,10 @@ function complete(type: string, value: any) {
emit('done', { type, value }); emit('done', { type, value });
emit('closed'); emit('closed');
if (type === 'emoji') { if (type === 'emoji') {
let recents = defaultStore.state.recentlyUsedEmojis; let recents = store.state.recentlyUsedEmojis;
recents = recents.filter((emoji: any) => emoji !== value); recents = recents.filter((emoji: any) => emoji !== value);
recents.unshift(value); recents.unshift(value);
defaultStore.set('recentlyUsedEmojis', recents.splice(0, 32)); store.set('recentlyUsedEmojis', recents.splice(0, 32));
} }
} }
@@ -237,7 +238,7 @@ function exec() {
} else if (props.type === 'emoji') { } else if (props.type === 'emoji') {
if (!props.q || props.q === '') { if (!props.q || props.q === '') {
// 最近使った絵文字をサジェスト // 最近使った絵文字をサジェスト
emojis.value = defaultStore.state.recentlyUsedEmojis.map(emoji => emojiDb.value.find(dbEmoji => dbEmoji.emoji === emoji)).filter(x => x) as EmojiDef[]; emojis.value = store.state.recentlyUsedEmojis.map(emoji => emojiDb.value.find(dbEmoji => dbEmoji.emoji === emoji)).filter(x => x) as EmojiDef[];
return; return;
} }

View File

@@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref } from 'vue'; import { onMounted, ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
userIds: string[]; userIds: string[];

View File

@@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue'; import { ref, shallowRef, computed, onMounted, onBeforeUnmount, watch, onUnmounted } from 'vue';
import { defaultStore } from '@/store.js'; import { store } from '@/store.js';
// APIs provided by Captcha services // APIs provided by Captcha services
// see: https://docs.hcaptcha.com/configuration/#javascript-api // see: https://docs.hcaptcha.com/configuration/#javascript-api
@@ -154,7 +154,7 @@ async function requestRender() {
captchaWidgetId.value = captcha.value.render(elem, { captchaWidgetId.value = captcha.value.render(elem, {
sitekey: props.sitekey, sitekey: props.sitekey,
theme: defaultStore.state.darkMode ? 'dark' : 'light', theme: store.state.darkMode ? 'dark' : 'light',
callback: callback, callback: callback,
'expired-callback': () => callback(undefined), 'expired-callback': () => callback(undefined),
'error-callback': () => callback(undefined), 'error-callback': () => callback(undefined),

View File

@@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{

View File

@@ -53,15 +53,15 @@ export type ChartSrc =
import { onMounted, ref, shallowRef, watch } from 'vue'; import { onMounted, ref, shallowRef, watch } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { misskeyApiGet } from '@/scripts/misskey-api.js'; import { misskeyApiGet } from '@/utility/misskey-api.js';
import { defaultStore } from '@/store.js'; import { store } from '@/store.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js'; import { useChartTooltip } from '@/utility/use-chart-tooltip.js';
import { chartVLine } from '@/scripts/chart-vline.js'; import { chartVLine } from '@/utility/chart-vline.js';
import { alpha } from '@/scripts/color.js'; import { alpha } from '@/utility/color.js';
import date from '@/filters/date.js'; import date from '@/filters/date.js';
import bytes from '@/filters/bytes.js'; import bytes from '@/filters/bytes.js';
import { initChart } from '@/scripts/init-chart.js'; import { initChart } from '@/utility/init-chart.js';
import { chartLegend } from '@/scripts/chart-legend.js'; import { chartLegend } from '@/utility/chart-legend.js';
import MkChartLegend from '@/components/MkChartLegend.vue'; import MkChartLegend from '@/components/MkChartLegend.vue';
initChart(); initChart();
@@ -161,7 +161,7 @@ const render = () => {
chartInstance.destroy(); chartInstance.destroy();
} }
const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; const vLineColor = store.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)';
const maxes = chartData.series.map((x, i) => Math.max(...x.data.map(d => d.y))); const maxes = chartData.series.map((x, i) => Math.max(...x.data.map(d => d.y)));

View File

@@ -23,9 +23,9 @@ import { computed, onMounted, onUnmounted, ref } from 'vue';
import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue'; import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { useInterval } from '@@/js/use-interval.js'; import { useInterval } from '@@/js/use-interval.js';
import * as game from '@/scripts/clicker-game.js'; import * as game from '@/utility/clicker-game.js';
import number from '@/filters/number.js'; import number from '@/filters/number.js';
import { claimAchievement } from '@/scripts/achievements.js'; import { claimAchievement } from '@/utility/achievements.js';
const saveData = game.saveData; const saveData = game.saveData;
const cookies = computed(() => saveData.value?.cookies); const cookies = computed(() => saveData.value?.cookies);

View File

@@ -12,8 +12,8 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed, ref, watch } from 'vue'; import { computed, ref, watch } from 'vue';
import { bundledLanguagesInfo } from 'shiki/langs'; import { bundledLanguagesInfo } from 'shiki/langs';
import type { BundledLanguage } from 'shiki/langs'; import type { BundledLanguage } from 'shiki/langs';
import { getHighlighter, getTheme } from '@/scripts/code-highlighter.js'; import { getHighlighter, getTheme } from '@/utility/code-highlighter.js';
import { defaultStore } from '@/store.js'; import { store } from '@/store.js';
const props = defineProps<{ const props = defineProps<{
code: string; code: string;
@@ -22,7 +22,7 @@ const props = defineProps<{
}>(); }>();
const highlighter = await getHighlighter(); const highlighter = await getHighlighter();
const darkMode = defaultStore.reactiveState.darkMode; const darkMode = store.reactiveState.darkMode;
const codeLang = ref<BundledLanguage | 'aiscript'>('js'); const codeLang = ref<BundledLanguage | 'aiscript'>('js');
const [lightThemeName, darkThemeName] = await Promise.all([ const [lightThemeName, darkThemeName] = await Promise.all([

View File

@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</button> </button>
<Suspense> <Suspense>
<template #fallback> <template #fallback>
<MkLoading /> <MkLoading/>
</template> </template>
<XCode v-if="show && lang" :code="code" :lang="lang"/> <XCode v-if="show && lang" :code="code" :lang="lang"/>
<pre v-else-if="show" :class="$style.codeBlockFallbackRoot"><code :class="$style.codeBlockFallbackCode">{{ code }}</code></pre> <pre v-else-if="show" :class="$style.codeBlockFallbackRoot"><code :class="$style.codeBlockFallbackCode">{{ code }}</code></pre>
@@ -28,9 +28,9 @@ SPDX-License-Identifier: AGPL-3.0-only
import { defineAsyncComponent, ref } from 'vue'; import { defineAsyncComponent, ref } from 'vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import MkLoading from '@/components/global/MkLoading.vue'; import MkLoading from '@/components/global/MkLoading.vue';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { prefer } from '@/preferences.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
code: string; code: string;
@@ -42,7 +42,7 @@ const props = withDefaults(defineProps<{
forceShow: false, forceShow: false,
}); });
const show = ref(props.forceShow === true ? true : !defaultStore.state.dataSaver.code); const show = ref(props.forceShow === true ? true : !prefer.s.dataSaver.code);
const XCode = defineAsyncComponent(() => import('@/components/MkCode.core.vue')); const XCode = defineAsyncComponent(() => import('@/components/MkCode.core.vue'));

View File

@@ -19,10 +19,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</div> </div>
</header> </header>
<Transition <Transition
:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" :enterActiveClass="prefer.s.animation ? $style.transition_toggle_enterActive : ''"
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" :leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''"
:enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" :enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''"
:leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" :leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''"
@enter="enter" @enter="enter"
@afterEnter="afterEnter" @afterEnter="afterEnter"
@leave="leave" @leave="leave"
@@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'; import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{

View File

@@ -6,10 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<Transition <Transition
appear appear
:enterActiveClass="defaultStore.state.animation ? $style.transition_fade_enterActive : ''" :enterActiveClass="prefer.s.animation ? $style.transition_fade_enterActive : ''"
:leaveActiveClass="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''" :leaveActiveClass="prefer.s.animation ? $style.transition_fade_leaveActive : ''"
:enterFromClass="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''" :enterFromClass="prefer.s.animation ? $style.transition_fade_enterFrom : ''"
:leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''" :leaveToClass="prefer.s.animation ? $style.transition_fade_leaveTo : ''"
> >
<div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}"> <div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}">
<MkMenu :items="items" :align="'left'" @close="emit('closed')"/> <MkMenu :items="items" :align="'left'" @close="emit('closed')"/>
@@ -21,8 +21,8 @@ SPDX-License-Identifier: AGPL-3.0-only
import { onMounted, onBeforeUnmount, shallowRef, ref } from 'vue'; import { onMounted, onBeforeUnmount, shallowRef, ref } from 'vue';
import MkMenu from './MkMenu.vue'; import MkMenu from './MkMenu.vue';
import type { MenuItem } from '@/types/menu.js'; import type { MenuItem } from '@/types/menu.js';
import contains from '@/scripts/contains.js'; import contains from '@/utility/contains.js';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
const props = defineProps<{ const props = defineProps<{

View File

@@ -35,13 +35,13 @@ import { onMounted, shallowRef, ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import Cropper from 'cropperjs'; import Cropper from 'cropperjs';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { apiUrl } from '@@/js/config.js';
import MkModalWindow from '@/components/MkModalWindow.vue'; import MkModalWindow from '@/components/MkModalWindow.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { defaultStore } from '@/store.js';
import { apiUrl } from '@@/js/config.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { getProxiedImageUrl } from '@/scripts/media-proxy.js'; import { getProxiedImageUrl } from '@/utility/media-proxy.js';
import { prefer } from '@/preferences.js';
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'ok', cropped: Misskey.entities.DriveFile): void; (ev: 'ok', cropped: Misskey.entities.DriveFile): void;
@@ -81,8 +81,8 @@ const ok = async () => {
formData.append('i', $i!.token); formData.append('i', $i!.token);
if (props.uploadFolder) { if (props.uploadFolder) {
formData.append('folderId', props.uploadFolder); formData.append('folderId', props.uploadFolder);
} else if (props.uploadFolder !== null && defaultStore.state.uploadFolder) { } else if (props.uploadFolder !== null && prefer.s.uploadFolder) {
formData.append('folderId', defaultStore.state.uploadFolder); formData.append('folderId', prefer.s.uploadFolder);
} }
window.fetch(apiUrl + '/drive/files/create', { window.fetch(apiUrl + '/drive/files/create', {

View File

@@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
import { computed } from 'vue'; import { computed } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import type { PollEditorModelValue } from '@/components/MkPollEditor.vue'; import type { PollEditorModelValue } from '@/components/MkPollEditor.vue';
import { concat } from '@/scripts/array.js'; import { concat } from '@/utility/array.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';

View File

@@ -6,13 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts"> <script lang="ts">
import { defineComponent, h, TransitionGroup, useCssModule } from 'vue'; import { defineComponent, h, TransitionGroup, useCssModule } from 'vue';
import type { PropType } from 'vue'; import type { PropType } from 'vue';
import type { MisskeyEntity } from '@/types/date-separated-list.js';
import MkAd from '@/components/global/MkAd.vue'; import MkAd from '@/components/global/MkAd.vue';
import { isDebuggerEnabled, stackTraceInstances } from '@/debug.js'; import { isDebuggerEnabled, stackTraceInstances } from '@/debug.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
import type { MisskeyEntity } from '@/types/date-separated-list.js';
export default defineComponent({ export default defineComponent({
props: { props: {
@@ -150,7 +150,7 @@ export default defineComponent({
[$style['direction-up']]: props.direction === 'up', [$style['direction-up']]: props.direction === 'up',
}; };
return () => defaultStore.state.animation ? h(TransitionGroup, { return () => prefer.s.animation ? h(TransitionGroup, {
class: classes, class: classes,
name: 'list', name: 'list',
tag: 'div', tag: 'div',

View File

@@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from 'vue'; import { onMounted, onUnmounted, ref, watch } from 'vue';
import { defaultIdlingRenderScheduler } from '@/scripts/idle-render.js'; import { defaultIdlingRenderScheduler } from '@/utility/idle-render.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
showS?: boolean; showS?: boolean;

View File

@@ -24,7 +24,8 @@ defineProps<{
} }
.disabled { .disabled {
opacity: 0.7; opacity: 0.3;
filter: saturate(0.5);
} }
.cover { .cover {
@@ -34,7 +35,7 @@ defineProps<{
width: 100%; width: 100%;
height: 100%; height: 100%;
cursor: not-allowed; cursor: not-allowed;
--color: color(from var(--MI_THEME-error) srgb r g b / 0.25); --color: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
background-size: auto auto; background-size: auto auto;
background-image: repeating-linear-gradient(135deg, transparent, transparent 10px, var(--color) 4px, var(--color) 14px); background-image: repeating-linear-gradient(135deg, transparent, transparent 10px, var(--color) 4px, var(--color) 14px);
} }

View File

@@ -45,8 +45,8 @@ import bytes from '@/filters/bytes.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { getDriveFileMenu } from '@/scripts/get-drive-file-menu.js'; import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js';
import { deviceKind } from '@/scripts/device-kind.js'; import { deviceKind } from '@/utility/device-kind.js';
import { useRouter } from '@/router/supplier.js'; import { useRouter } from '@/router/supplier.js';
const router = useRouter(); const router = useRouter();

View File

@@ -24,7 +24,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-if="!hover"><i :class="$style.icon" class="ti ti-folder ti-fw"></i></template> <template v-if="!hover"><i :class="$style.icon" class="ti ti-folder ti-fw"></i></template>
{{ folder.name }} {{ folder.name }}
</p> </p>
<p v-if="defaultStore.state.uploadFolder == folder.id" :class="$style.upload"> <p v-if="prefer.s.uploadFolder == folder.id" :class="$style.upload">
{{ i18n.ts.uploadFolder }} {{ i18n.ts.uploadFolder }}
</p> </p>
<button v-if="selectMode" class="_button" :class="$style.checkboxWrapper" @click.prevent.stop="checkboxClicked"> <button v-if="selectMode" class="_button" :class="$style.checkboxWrapper" @click.prevent.stop="checkboxClicked">
@@ -38,11 +38,11 @@ import { computed, defineAsyncComponent, ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import type { MenuItem } from '@/types/menu.js'; import type { MenuItem } from '@/types/menu.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js'; import { claimAchievement } from '@/utility/achievements.js';
import { claimAchievement } from '@/scripts/achievements.js'; import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { prefer } from '@/preferences.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
folder: Misskey.entities.DriveFolder; folder: Misskey.entities.DriveFolder;
@@ -244,8 +244,8 @@ function deleteFolder() {
misskeyApi('drive/folders/delete', { misskeyApi('drive/folders/delete', {
folderId: props.folder.id, folderId: props.folder.id,
}).then(() => { }).then(() => {
if (defaultStore.state.uploadFolder === props.folder.id) { if (prefer.s.uploadFolder === props.folder.id) {
defaultStore.set('uploadFolder', null); prefer.set('uploadFolder', null);
} }
}).catch(err => { }).catch(err => {
switch (err.id) { switch (err.id) {
@@ -266,7 +266,7 @@ function deleteFolder() {
} }
function setAsUploadFolder() { function setAsUploadFolder() {
defaultStore.set('uploadFolder', props.folder.id); prefer.set('uploadFolder', props.folder.id);
} }
function onContextmenu(ev: MouseEvent) { function onContextmenu(ev: MouseEvent) {
@@ -295,7 +295,7 @@ function onContextmenu(ev: MouseEvent) {
danger: true, danger: true,
action: deleteFolder, action: deleteFolder,
}]; }];
if (defaultStore.state.devMode) { if (prefer.s.devMode) {
menu = menu.concat([{ type: 'divider' }, { menu = menu.concat([{ type: 'divider' }, {
icon: 'ti ti-id', icon: 'ti ti-id',
text: i18n.ts.copyFolderId, text: i18n.ts.copyFolderId,

View File

@@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { ref } from 'vue'; import { ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
const props = defineProps<{ const props = defineProps<{

View File

@@ -104,12 +104,12 @@ import XNavFolder from '@/components/MkDrive.navFolder.vue';
import XFolder from '@/components/MkDrive.folder.vue'; import XFolder from '@/components/MkDrive.folder.vue';
import XFile from '@/components/MkDrive.file.vue'; import XFile from '@/components/MkDrive.file.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { useStream } from '@/stream.js'; import { useStream } from '@/stream.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { uploadFile, uploads } from '@/scripts/upload.js'; import { uploadFile, uploads } from '@/utility/upload.js';
import { claimAchievement } from '@/scripts/achievements.js'; import { claimAchievement } from '@/utility/achievements.js';
import { prefer } from '@/preferences.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
initialFolder?: Misskey.entities.DriveFolder; initialFolder?: Misskey.entities.DriveFolder;
@@ -142,7 +142,7 @@ const selectedFiles = ref<Misskey.entities.DriveFile[]>([]);
const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]); const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]);
const uploadings = uploads; const uploadings = uploads;
const connection = useStream().useChannel('drive'); const connection = useStream().useChannel('drive');
const keepOriginal = ref<boolean>(defaultStore.state.keepOriginalUploading); // 外部渡しが多いので$refは使わないほうがよい const keepOriginal = ref<boolean>(prefer.s.keepOriginalUploading); // 外部渡しが多いので$refは使わないほうがよい
// ドロップされようとしているか // ドロップされようとしているか
const draghover = ref(false); const draghover = ref(false);
@@ -716,7 +716,7 @@ function onContextmenu(ev: MouseEvent) {
} }
onMounted(() => { onMounted(() => {
if (defaultStore.state.enableInfiniteScroll && loadMoreFiles.value) { if (prefer.s.enableInfiniteScroll && loadMoreFiles.value) {
nextTick(() => { nextTick(() => {
ilFilesObserver.observe(loadMoreFiles.value?.$el); ilFilesObserver.observe(loadMoreFiles.value?.$el);
}); });
@@ -737,7 +737,7 @@ onMounted(() => {
}); });
onActivated(() => { onActivated(() => {
if (defaultStore.state.enableInfiniteScroll) { if (prefer.s.enableInfiniteScroll) {
nextTick(() => { nextTick(() => {
ilFilesObserver.observe(loadMoreFiles.value?.$el); ilFilesObserver.observe(loadMoreFiles.value?.$el);
}); });

View File

@@ -105,8 +105,8 @@ import MkInfo from '@/components/MkInfo.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { copyToClipboard } from '@/utility/copy-to-clipboard.js';
import { normalizeEmbedParams, getEmbedCode } from '@/scripts/get-embed-code.js'; import { normalizeEmbedParams, getEmbedCode } from '@/utility/get-embed-code.js';
const emit = defineEmits<{ const emit = defineEmits<{
(ev: 'ok'): void; (ev: 'ok'): void;

View File

@@ -131,17 +131,18 @@ import type {
import XSection from '@/components/MkEmojiPicker.section.vue'; import XSection from '@/components/MkEmojiPicker.section.vue';
import MkRippleEffect from '@/components/MkRippleEffect.vue'; import MkRippleEffect from '@/components/MkRippleEffect.vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { isTouchUsing } from '@/scripts/touch.js'; import { isTouchUsing } from '@/utility/touch.js';
import { deviceKind } from '@/scripts/device-kind.js'; import { deviceKind } from '@/utility/device-kind.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { defaultStore } from '@/store.js'; import { store } from '@/store.js';
import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js'; import { customEmojiCategories, customEmojis, customEmojisMap } from '@/custom-emojis.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { checkReactionPermissions } from '@/scripts/check-reaction-permissions.js'; import { checkReactionPermissions } from '@/utility/check-reaction-permissions.js';
import { prefer } from '@/preferences.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
showPinned?: boolean; showPinned?: boolean;
pinnedEmojis?: string[]; pinnedEmojis?: string[];
maxHeight?: number; maxHeight?: number;
asDrawer?: boolean; asDrawer?: boolean;
asWindow?: boolean; asWindow?: boolean;
@@ -163,8 +164,9 @@ const {
emojiPickerScale, emojiPickerScale,
emojiPickerWidth, emojiPickerWidth,
emojiPickerHeight, emojiPickerHeight,
recentlyUsedEmojis, } = prefer.r;
} = defaultStore.reactiveState;
const recentlyUsedEmojis = store.reactiveState.recentlyUsedEmojis;
const recentlyUsedEmojisDef = computed(() => { const recentlyUsedEmojisDef = computed(() => {
return recentlyUsedEmojis.value.map(getDef); return recentlyUsedEmojis.value.map(getDef);
@@ -317,7 +319,7 @@ watch(q, () => {
} }
if (matches.size >= max) return matches; if (matches.size >= max) return matches;
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
for (const emoji of emojis) { for (const emoji of emojis) {
if (keywords.every(keyword => index[emoji.char].some(k => k.includes(keyword)))) { if (keywords.every(keyword => index[emoji.char].some(k => k.includes(keyword)))) {
matches.add(emoji); matches.add(emoji);
@@ -334,7 +336,7 @@ watch(q, () => {
} }
if (matches.size >= max) return matches; if (matches.size >= max) return matches;
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
for (const emoji of emojis) { for (const emoji of emojis) {
if (index[emoji.char].some(k => k.startsWith(newQ))) { if (index[emoji.char].some(k => k.startsWith(newQ))) {
matches.add(emoji); matches.add(emoji);
@@ -351,7 +353,7 @@ watch(q, () => {
} }
if (matches.size >= max) return matches; if (matches.size >= max) return matches;
for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { for (const index of Object.values(store.state.additionalUnicodeEmojiIndexes)) {
for (const emoji of emojis) { for (const emoji of emojis) {
if (index[emoji.char].some(k => k.includes(newQ))) { if (index[emoji.char].some(k => k.includes(newQ))) {
matches.add(emoji); matches.add(emoji);
@@ -413,7 +415,7 @@ function computeButtonTitle(ev: MouseEvent): void {
function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) { function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) {
const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined; const el = ev && (ev.currentTarget ?? ev.target) as HTMLElement | null | undefined;
if (el && defaultStore.state.animation) { if (el && prefer.s.animation) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
@@ -427,10 +429,10 @@ function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef,
// 最近使った絵文字更新 // 最近使った絵文字更新
if (!pinned.value?.includes(key)) { if (!pinned.value?.includes(key)) {
let recents = defaultStore.state.recentlyUsedEmojis; let recents = store.state.recentlyUsedEmojis;
recents = recents.filter((emoji) => emoji !== key); recents = recents.filter((emoji) => emoji !== key);
recents.unshift(key); recents.unshift(key);
defaultStore.set('recentlyUsedEmojis', recents.splice(0, 32)); store.set('recentlyUsedEmojis', recents.splice(0, 32));
} }
} }

View File

@@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="modal" ref="modal"
v-slot="{ type, maxHeight }" v-slot="{ type, maxHeight }"
:zPriority="'middle'" :zPriority="'middle'"
:preferType="defaultStore.state.emojiPickerStyle" :preferType="prefer.s.emojiPickerStyle"
:hasInteractionWithOtherFocusTrappedEls="true" :hasInteractionWithOtherFocusTrappedEls="true"
:transparentBg="true" :transparentBg="true"
:manualShowing="manualShowing" :manualShowing="manualShowing"
@@ -40,16 +40,16 @@ import * as Misskey from 'misskey-js';
import { shallowRef } from 'vue'; import { shallowRef } from 'vue';
import MkModal from '@/components/MkModal.vue'; import MkModal from '@/components/MkModal.vue';
import MkEmojiPicker from '@/components/MkEmojiPicker.vue'; import MkEmojiPicker from '@/components/MkEmojiPicker.vue';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
manualShowing?: boolean | null; manualShowing?: boolean | null;
src?: HTMLElement; src?: HTMLElement;
showPinned?: boolean; showPinned?: boolean;
pinnedEmojis?: string[], pinnedEmojis?: string[],
asReactionPicker?: boolean; asReactionPicker?: boolean;
targetNote?: Misskey.entities.Note; targetNote?: Misskey.entities.Note;
choseAndClose?: boolean; choseAndClose?: boolean;
}>(), { }>(), {
manualShowing: null, manualShowing: null,
showPinned: true, showPinned: true,

View File

@@ -14,10 +14,10 @@ SPDX-License-Identifier: AGPL-3.0-only
</button> </button>
</header> </header>
<Transition <Transition
:enterActiveClass="defaultStore.state.animation ? $style.folderToggleEnterActive : ''" :enterActiveClass="prefer.s.animation ? $style.folderToggleEnterActive : ''"
:leaveActiveClass="defaultStore.state.animation ? $style.folderToggleLeaveActive : ''" :leaveActiveClass="prefer.s.animation ? $style.folderToggleLeaveActive : ''"
:enterFromClass="defaultStore.state.animation ? $style.folderToggleEnterFrom : ''" :enterFromClass="prefer.s.animation ? $style.folderToggleEnterFrom : ''"
:leaveToClass="defaultStore.state.animation ? $style.folderToggleLeaveTo : ''" :leaveToClass="prefer.s.animation ? $style.folderToggleLeaveTo : ''"
@enter="enter" @enter="enter"
@afterEnter="afterEnter" @afterEnter="afterEnter"
@leave="leave" @leave="leave"
@@ -33,8 +33,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, ref, shallowRef, watch } from 'vue'; import { onMounted, ref, shallowRef, watch } from 'vue';
import { miLocalStorage } from '@/local-storage.js'; import { miLocalStorage } from '@/local-storage.js';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
import { getBgColor } from '@/scripts/get-bg-color.js'; import { getBgColor } from '@/utility/get-bg-color.js';
const miLocalStoragePrefix = 'ui:folder:' as const; const miLocalStoragePrefix = 'ui:folder:' as const;

View File

@@ -27,10 +27,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : undefined, overflow: maxHeight ? `auto` : undefined }" :aria-hidden="!opened"> <div v-if="openedAtLeastOnce" :class="[$style.body, { [$style.bgSame]: bgSame }]" :style="{ maxHeight: maxHeight ? `${maxHeight}px` : undefined, overflow: maxHeight ? `auto` : undefined }" :aria-hidden="!opened">
<Transition <Transition
:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" :enterActiveClass="prefer.s.animation ? $style.transition_toggle_enterActive : ''"
:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" :leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''"
:enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" :enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''"
:leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" :leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''"
@enter="enter" @enter="enter"
@afterEnter="afterEnter" @afterEnter="afterEnter"
@leave="leave" @leave="leave"
@@ -57,8 +57,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted, ref, shallowRef } from 'vue'; import { nextTick, onMounted, ref, shallowRef } from 'vue';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
import { getBgColor } from '@/scripts/get-bg-color.js'; import { getBgColor } from '@/utility/get-bg-color.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
defaultOpen?: boolean; defaultOpen?: boolean;

View File

@@ -39,13 +39,14 @@ import { onBeforeUnmount, onMounted, ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { host } from '@@/js/config.js'; import { host } from '@@/js/config.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { useStream } from '@/stream.js'; import { useStream } from '@/stream.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { claimAchievement } from '@/scripts/achievements.js'; import { claimAchievement } from '@/utility/achievements.js';
import { pleaseLogin } from '@/scripts/please-login.js'; import { pleaseLogin } from '@/utility/please-login.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { defaultStore } from '@/store.js'; import { store } from '@/store.js';
import { prefer } from '@/preferences.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
user: Misskey.entities.UserDetailed, user: Misskey.entities.UserDetailed,
@@ -100,7 +101,7 @@ async function onClick() {
userId: props.user.id, userId: props.user.id,
}); });
} else { } else {
if (defaultStore.state.alwaysConfirmFollow) { if (prefer.s.alwaysConfirmFollow) {
const { canceled } = await os.confirm({ const { canceled } = await os.confirm({
type: 'question', type: 'question',
text: i18n.tsx.followConfirm({ name: props.user.name || props.user.username }), text: i18n.tsx.followConfirm({ name: props.user.name || props.user.username }),
@@ -120,11 +121,11 @@ async function onClick() {
} else { } else {
await misskeyApi('following/create', { await misskeyApi('following/create', {
userId: props.user.id, userId: props.user.id,
withReplies: defaultStore.state.defaultWithReplies, withReplies: store.state.defaultWithReplies,
}); });
emit('update:user', { emit('update:user', {
...props.user, ...props.user,
withReplies: defaultStore.state.defaultWithReplies, withReplies: store.state.defaultWithReplies,
}); });
hasPendingFollowRequestFromYou.value = true; hasPendingFollowRequestFromYou.value = true;

View File

@@ -15,8 +15,8 @@ import * as Misskey from 'misskey-js';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { selectFile } from '@/scripts/select-file.js'; import { selectFile } from '@/utility/select-file.js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
const props = defineProps<{ const props = defineProps<{
fileId?: string | null; fileId?: string | null;

View File

@@ -80,7 +80,7 @@ import MkRange from './MkRange.vue';
import MkButton from './MkButton.vue'; import MkButton from './MkButton.vue';
import MkRadios from './MkRadios.vue'; import MkRadios from './MkRadios.vue';
import XFile from './MkFormDialog.file.vue'; import XFile from './MkFormDialog.file.vue';
import type { Form } from '@/scripts/form.js'; import type { Form } from '@/utility/form.js';
import MkModalWindow from '@/components/MkModalWindow.vue'; import MkModalWindow from '@/components/MkModalWindow.vue';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { infoImageUrl } from '@/instance.js'; import { infoImageUrl } from '@/instance.js';

View File

@@ -35,14 +35,14 @@ SPDX-License-Identifier: AGPL-3.0-only
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { computed, ref } from 'vue'; import { computed, ref } from 'vue';
import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue'; import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
const props = defineProps<{ const props = defineProps<{
post: Misskey.entities.GalleryPost; post: Misskey.entities.GalleryPost;
}>(); }>();
const hover = ref(false); const hover = ref(false);
const safe = computed(() => defaultStore.state.nsfw === 'ignore' || defaultStore.state.nsfw === 'respect' && !props.post.isSensitive); const safe = computed(() => prefer.s.nsfw === 'ignore' || prefer.s.nsfw === 'respect' && !props.post.isSensitive);
const show = computed(() => safe.value || hover.value); const show = computed(() => safe.value || hover.value);
function enterHover(): void { function enterHover(): void {

View File

@@ -16,11 +16,11 @@ SPDX-License-Identifier: AGPL-3.0-only
import { onMounted, nextTick, watch, shallowRef, ref } from 'vue'; import { onMounted, nextTick, watch, shallowRef, ref } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import { misskeyApi } from '@/scripts/misskey-api.js'; import { misskeyApi } from '@/utility/misskey-api.js';
import { defaultStore } from '@/store.js'; import { store } from '@/store.js';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js'; import { useChartTooltip } from '@/utility/use-chart-tooltip.js';
import { alpha } from '@/scripts/color.js'; import { alpha } from '@/utility/color.js';
import { initChart } from '@/scripts/init-chart.js'; import { initChart } from '@/utility/init-chart.js';
initChart(); initChart();
@@ -106,7 +106,7 @@ async function renderChart() {
await nextTick(); await nextTick();
const color = defaultStore.state.darkMode ? '#b4e900' : '#86b300'; const color = store.state.darkMode ? '#b4e900' : '#86b300';
// 視覚上の分かりやすさのため上から最も大きい3つの値の平均を最大値とする // 視覚上の分かりやすさのため上から最も大きい3つの値の平均を最大値とする
const max = values.slice().sort((a, b) => b - a).slice(0, 3).reduce((a, b) => a + b, 0) / 3; const max = values.slice().sort((a, b) => b - a).slice(0, 3).reduce((a, b) => a + b, 0) / 3;

View File

@@ -28,12 +28,11 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup> <script lang="ts" setup>
import { ref, shallowRef, computed, nextTick, watch } from 'vue'; import { ref, shallowRef, computed, nextTick, watch } from 'vue';
import type { Tab } from '@/components/global/MkPageHeader.tabs.vue'; import type { Tab } from '@/components/global/MkPageHeader.tabs.vue';
import { defaultStore } from '@/store.js'; import { isHorizontalSwipeSwiping as isSwiping } from '@/utility/touch.js';
import { isHorizontalSwipeSwiping as isSwiping } from '@/scripts/touch.js'; import { prefer } from '@/preferences.js';
const rootEl = shallowRef<HTMLDivElement>(); const rootEl = shallowRef<HTMLDivElement>();
// eslint-disable-next-line no-undef
const tabModel = defineModel<string>('tab'); const tabModel = defineModel<string>('tab');
const props = defineProps<{ const props = defineProps<{
@@ -44,7 +43,7 @@ const emit = defineEmits<{
(ev: 'swiped', newKey: string, direction: 'left' | 'right'): void; (ev: 'swiped', newKey: string, direction: 'left' | 'right'): void;
}>(); }>();
const shouldAnimate = computed(() => defaultStore.reactiveState.enableHorizontalSwipe.value || defaultStore.reactiveState.animation.value); const shouldAnimate = computed(() => prefer.r.enableHorizontalSwipe.value || prefer.r.animation.value);
// ▼ しきい値 ▼ // // ▼ しきい値 ▼ //
@@ -72,7 +71,7 @@ const isSwipingForClass = ref(false);
let swipeAborted = false; let swipeAborted = false;
function touchStart(event: TouchEvent) { function touchStart(event: TouchEvent) {
if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return; if (!prefer.r.enableHorizontalSwipe.value) return;
if (event.touches.length !== 1) return; if (event.touches.length !== 1) return;
@@ -83,7 +82,7 @@ function touchStart(event: TouchEvent) {
} }
function touchMove(event: TouchEvent) { function touchMove(event: TouchEvent) {
if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return; if (!prefer.r.enableHorizontalSwipe.value) return;
if (event.touches.length !== 1) return; if (event.touches.length !== 1) return;
@@ -134,7 +133,7 @@ function touchEnd(event: TouchEvent) {
return; return;
} }
if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return; if (!prefer.r.enableHorizontalSwipe.value) return;
if (event.touches.length !== 0) return; if (event.touches.length !== 0) return;

View File

@@ -6,13 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<template> <template>
<div ref="root" :class="['chromatic-ignore', $style.root, { [$style.cover]: cover }]" :title="title ?? ''"> <div ref="root" :class="['chromatic-ignore', $style.root, { [$style.cover]: cover }]" :title="title ?? ''">
<TransitionGroup <TransitionGroup
:duration="defaultStore.state.animation && props.transition?.duration || undefined" :duration="prefer.s.animation && props.transition?.duration || undefined"
:enterActiveClass="defaultStore.state.animation && props.transition?.enterActiveClass || undefined" :enterActiveClass="prefer.s.animation && props.transition?.enterActiveClass || undefined"
:leaveActiveClass="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style.transition_leaveActive) || undefined" :leaveActiveClass="prefer.s.animation && (props.transition?.leaveActiveClass ?? $style.transition_leaveActive) || undefined"
:enterFromClass="defaultStore.state.animation && props.transition?.enterFromClass || undefined" :enterFromClass="prefer.s.animation && props.transition?.enterFromClass || undefined"
:leaveToClass="defaultStore.state.animation && props.transition?.leaveToClass || undefined" :leaveToClass="prefer.s.animation && props.transition?.leaveToClass || undefined"
:enterToClass="defaultStore.state.animation && props.transition?.enterToClass || undefined" :enterToClass="prefer.s.animation && props.transition?.enterToClass || undefined"
:leaveFromClass="defaultStore.state.animation && props.transition?.leaveFromClass || undefined" :leaveFromClass="prefer.s.animation && props.transition?.leaveFromClass || undefined"
> >
<canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/> <canvas v-show="hide" key="canvas" ref="canvas" :class="$style.canvas" :width="canvasWidth" :height="canvasHeight" :title="title ?? undefined" tabindex="-1"/>
<img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/> <img v-show="!hide" key="img" ref="img" :height="imgHeight ?? undefined" :width="imgWidth ?? undefined" :class="$style.img" :src="src ?? undefined" :title="title ?? undefined" :alt="alt ?? undefined" loading="eager" decoding="async" tabindex="-1"/>
@@ -60,7 +60,7 @@ const canvasPromise = new Promise<WorkerMultiDispatch | HTMLCanvasElement>(resol
import { computed, nextTick, onMounted, onUnmounted, shallowRef, watch, ref } from 'vue'; import { computed, nextTick, onMounted, onUnmounted, shallowRef, watch, ref } from 'vue';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import { render } from 'buraha'; import { render } from 'buraha';
import { defaultStore } from '@/store.js'; import { prefer } from '@/preferences.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
transition?: { transition?: {

View File

@@ -50,8 +50,8 @@ import { debounce } from 'throttle-debounce';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { useInterval } from '@@/js/use-interval.js'; import { useInterval } from '@@/js/use-interval.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { Autocomplete } from '@/scripts/autocomplete.js'; import { Autocomplete } from '@/utility/autocomplete.js';
import type { SuggestionType } from '@/scripts/autocomplete.js'; import type { SuggestionType } from '@/utility/autocomplete.js';
const props = defineProps<{ const props = defineProps<{
modelValue: string | number | null; modelValue: string | number | null;

View File

@@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only
import { ref } from 'vue'; import { ref } from 'vue';
import * as Misskey from 'misskey-js'; import * as Misskey from 'misskey-js';
import MkMiniChart from '@/components/MkMiniChart.vue'; import MkMiniChart from '@/components/MkMiniChart.vue';
import { misskeyApiGet } from '@/scripts/misskey-api.js'; import { misskeyApiGet } from '@/utility/misskey-api.js';
import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js'; import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js';
const props = defineProps<{ const props = defineProps<{
instance: Misskey.entities.FederationInstance; instance: Misskey.entities.FederationInstance;

View File

@@ -88,10 +88,10 @@ import { onMounted, ref, computed, shallowRef } from 'vue';
import { Chart } from 'chart.js'; import { Chart } from 'chart.js';
import MkSelect from '@/components/MkSelect.vue'; import MkSelect from '@/components/MkSelect.vue';
import MkChart from '@/components/MkChart.vue'; import MkChart from '@/components/MkChart.vue';
import { useChartTooltip } from '@/scripts/use-chart-tooltip.js'; import { useChartTooltip } from '@/utility/use-chart-tooltip.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { misskeyApiGet } from '@/scripts/misskey-api.js'; import { misskeyApiGet } from '@/utility/misskey-api.js';
import { instance } from '@/instance.js'; import { instance } from '@/instance.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import MkHeatmap from '@/components/MkHeatmap.vue'; import MkHeatmap from '@/components/MkHeatmap.vue';
@@ -99,7 +99,7 @@ import type { HeatmapSource } from '@/components/MkHeatmap.vue';
import MkFoldableSection from '@/components/MkFoldableSection.vue'; import MkFoldableSection from '@/components/MkFoldableSection.vue';
import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue'; import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue';
import MkRetentionLineChart from '@/components/MkRetentionLineChart.vue'; import MkRetentionLineChart from '@/components/MkRetentionLineChart.vue';
import { initChart } from '@/scripts/init-chart.js'; import { initChart } from '@/utility/init-chart.js';
initChart(); initChart();

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