Compare commits
	
		
			55 Commits
		
	
	
		
			2025.3.1-a
			...
			2025.3.2-a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 794f360bc2 | ||
|   | f797765b1d | ||
|   | 9dce512fbb | ||
|   | 9e91f85370 | ||
|   | 9998cb84e8 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 5ed1101bbd | ||
|   | 6c9153300d | ||
|   | 7957ee5191 | ||
|   | b200743845 | ||
|   | 08f7e7d9b3 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 16ad6b3f6c | ||
|   | 4df9083bf0 | ||
|   | 6419af2179 | ||
|   | d9858b03c9 | ||
|   | 88efc0a3be | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | ac21fa7194 | ||
|   | c76afce9a7 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 8e3304344f | ||
|   | db5c127cdd | ||
|   | 0402866b43 | ||
|   | 6cefabc6b6 | ||
|   | c9c04d8391 | ||
|   | 27e8805dcb | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 933abedc90 | ||
|   | 69eee9f050 | ||
|   | 2918fb2609 | ||
|   | fcd7fa62ba | ||
|   | be7e3b9a0c | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 06e7272ca1 | ||
|   | f35eb0f6d9 | ||
|   | bdb74539d4 | ||
|   | abc1e9168d | ||
|   | d30ddd4c2e | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 05cdc095c0 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 7c1dc3d632 | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | c53349c3b4 | ||
|   | a710af54ed | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | ac07bb8d92 | ||
|   | 698505030e | ||
|   | e16a14dcef | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 6d93725084 | ||
|   | cb9981d4eb | ||
|   | bee4db82bb | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | d7706ef1b5 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | baf3f4a1d1 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | c7a56c2c2b | ||
| ![github-actions[bot]](/assets/img/avatar_default.png)  | 8dfff79ca2 | ||
|   | 83c3bb839f | ||
|   | a9fe7eff0a | ||
|   | d49ecab792 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 56459bbe68 | ||
| ![renovate[bot]](/assets/img/avatar_default.png)  | 6c150ef1fb | ||
|   | c78f45ea20 | ||
|   | 82481c01e0 | ||
|   | 741cbc34e6 | 
| @@ -7,8 +7,8 @@ | ||||
| 		"ghcr.io/devcontainers/features/node:1": { | ||||
| 			"version": "22.11.0" | ||||
| 		}, | ||||
| 		"ghcr.io/devcontainers-extra/features/corepack:1": { | ||||
| 			"version": "0.31.0" | ||||
| 		"ghcr.io/devcontainers-extra/features/pnpm:2": { | ||||
| 			"version": "10.6.1" | ||||
| 		} | ||||
| 	}, | ||||
| 	"forwardPorts": [3000], | ||||
|   | ||||
| @@ -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 | ||||
| git config --global --add safe.directory /workspace | ||||
| git submodule update --init | ||||
| corepack install | ||||
| corepack enable | ||||
| pnpm config set store-dir /home/node/.local/share/pnpm/store | ||||
| pnpm install --frozen-lockfile | ||||
| cp .devcontainer/devcontainer.yml .config/default.yml | ||||
|   | ||||
							
								
								
									
										7
									
								
								.github/workflows/api-misskey-js.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.github/workflows/api-misskey-js.yml
									
									
									
									
										vendored
									
									
								
							| @@ -9,10 +9,6 @@ on: | ||||
|     paths: | ||||
|       - packages/misskey-js/** | ||||
|       - .github/workflows/api-misskey-js.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   report: | ||||
|  | ||||
| @@ -22,7 +18,8 @@ jobs: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v4.2.2 | ||||
|  | ||||
|       - run: corepack enable | ||||
|       - name: Setup pnpm | ||||
|         uses: pnpm/action-setup@v4.1.0 | ||||
|  | ||||
|       - name: Setup Node.js | ||||
|         uses: actions/setup-node@v4.2.0 | ||||
|   | ||||
							
								
								
									
										9
									
								
								.github/workflows/get-api-diff.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/get-api-diff.yml
									
									
									
									
										vendored
									
									
								
							| @@ -9,10 +9,6 @@ on: | ||||
|     paths: | ||||
|       - packages/backend/** | ||||
|       - .github/workflows/get-api-diff.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   get-from-misskey: | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -34,14 +30,13 @@ jobs: | ||||
|       with: | ||||
|         ref: ${{ matrix.ref }} | ||||
|         submodules: true | ||||
|     - name: Install pnpm | ||||
|       uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - name: Use Node.js ${{ matrix.node-version }} | ||||
|       uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version: ${{ matrix.node-version }} | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Check pnpm-lock.yaml | ||||
|       run: git diff --exit-code pnpm-lock.yaml | ||||
|   | ||||
							
								
								
									
										16
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								.github/workflows/lint.yml
									
									
									
									
										vendored
									
									
								
							| @@ -28,10 +28,6 @@ on: | ||||
|       - packages/misskey-reversi/** | ||||
|       - packages/shared/eslint.config.js | ||||
|       - .github/workflows/lint.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   pnpm_install: | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -40,12 +36,12 @@ jobs: | ||||
|       with: | ||||
|         fetch-depth: 0 | ||||
|         submodules: true | ||||
|     - uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version-file: '.node-version' | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|  | ||||
|   lint: | ||||
| @@ -71,12 +67,12 @@ jobs: | ||||
|       with: | ||||
|         fetch-depth: 0 | ||||
|         submodules: true | ||||
|     - uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version-file: '.node-version' | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Restore eslint cache | ||||
|       uses: actions/cache@v4.2.2 | ||||
| @@ -101,12 +97,12 @@ jobs: | ||||
|       with: | ||||
|         fetch-depth: 0 | ||||
|         submodules: true | ||||
|     - uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version-file: '.node-version' | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - run: pnpm --filter misskey-js run build | ||||
|       if: ${{ matrix.workspace == 'backend' || matrix.workspace == 'sw' }} | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/locale.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/locale.yml
									
									
									
									
										vendored
									
									
								
							| @@ -9,10 +9,6 @@ on: | ||||
|     paths: | ||||
|       - locales/** | ||||
|       - .github/workflows/locale.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   locale_verify: | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -22,11 +18,11 @@ jobs: | ||||
|       with: | ||||
|         fetch-depth: 0 | ||||
|         submodules: true | ||||
|     - uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version-file: '.node-version' | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - run: cd locales && node verify.js | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/on-release-created.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/on-release-created.yml
									
									
									
									
										vendored
									
									
								
							| @@ -6,9 +6,6 @@ on: | ||||
|  | ||||
|   workflow_dispatch: | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   publish-misskey-js: | ||||
|     name: Publish misskey-js | ||||
| @@ -26,8 +23,8 @@ jobs: | ||||
|       - uses: actions/checkout@v4.2.2 | ||||
|         with: | ||||
|           submodules: true | ||||
|       - name: Install pnpm | ||||
|         uses: pnpm/action-setup@v4 | ||||
|       - name: Setup pnpm | ||||
|         uses: pnpm/action-setup@v4.1.0 | ||||
|       - name: Use Node.js ${{ matrix.node-version }} | ||||
|         uses: actions/setup-node@v4.2.0 | ||||
|         with: | ||||
| @@ -36,7 +33,6 @@ jobs: | ||||
|           registry-url: 'https://registry.npmjs.org' | ||||
|       - name: Publish package | ||||
|         run: | | ||||
|           corepack enable | ||||
|           pnpm i --frozen-lockfile | ||||
|           pnpm build | ||||
|           pnpm --filter misskey-js publish --access public --no-git-checks --provenance | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/storybook.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/storybook.yml
									
									
									
									
										vendored
									
									
								
							| @@ -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. | ||||
|       - master | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   build: | ||||
|     # chromatic is not likely to be available for fork repositories, so we disable for fork repositories. | ||||
| @@ -43,14 +40,13 @@ jobs: | ||||
|       run: | | ||||
|         echo "base=$(git rev-list --parents -n1 HEAD | cut -d" " -f2)" >> $GITHUB_OUTPUT | ||||
|         git checkout $(git rev-list --parents -n1 HEAD | cut -d" " -f3) | ||||
|     - name: Install pnpm | ||||
|       uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - name: Use Node.js 20.x | ||||
|       uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version-file: '.node-version' | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Check pnpm-lock.yaml | ||||
|       run: git diff --exit-code pnpm-lock.yaml | ||||
|   | ||||
							
								
								
									
										14
									
								
								.github/workflows/test-backend.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/test-backend.yml
									
									
									
									
										vendored
									
									
								
							| @@ -18,10 +18,6 @@ on: | ||||
|       - packages/misskey-js/** | ||||
|       - .github/workflows/test-backend.yml | ||||
|       - .github/misskey/test.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   unit: | ||||
|     name: Unit tests (backend) | ||||
| @@ -48,8 +44,8 @@ jobs: | ||||
|     - uses: actions/checkout@v4.2.2 | ||||
|       with: | ||||
|         submodules: true | ||||
|     - name: Install pnpm | ||||
|       uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - name: Install FFmpeg | ||||
|       run: | | ||||
|         for i in {1..3}; do | ||||
| @@ -70,7 +66,6 @@ jobs: | ||||
|       with: | ||||
|         node-version: ${{ matrix.node-version }} | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Check pnpm-lock.yaml | ||||
|       run: git diff --exit-code pnpm-lock.yaml | ||||
| @@ -111,14 +106,13 @@ jobs: | ||||
|       - uses: actions/checkout@v4.2.2 | ||||
|         with: | ||||
|           submodules: true | ||||
|       - name: Install pnpm | ||||
|         uses: pnpm/action-setup@v4 | ||||
|       - name: Setup pnpm | ||||
|         uses: pnpm/action-setup@v4.1.0 | ||||
|       - name: Use Node.js ${{ matrix.node-version }} | ||||
|         uses: actions/setup-node@v4.2.0 | ||||
|         with: | ||||
|           node-version: ${{ matrix.node-version }} | ||||
|           cache: 'pnpm' | ||||
|       - run: corepack enable | ||||
|       - run: pnpm i --frozen-lockfile | ||||
|       - name: Check pnpm-lock.yaml | ||||
|         run: git diff --exit-code pnpm-lock.yaml | ||||
|   | ||||
							
								
								
									
										8
									
								
								.github/workflows/test-federation.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.github/workflows/test-federation.yml
									
									
									
									
										vendored
									
									
								
							| @@ -15,9 +15,6 @@ on: | ||||
|       - packages/misskey-js/** | ||||
|       - .github/workflows/test-federation.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   test: | ||||
|     name: Federation test | ||||
| @@ -29,8 +26,8 @@ jobs: | ||||
|       - uses: actions/checkout@v4 | ||||
|         with: | ||||
|           submodules: true | ||||
|       - name: Install pnpm | ||||
|         uses: pnpm/action-setup@v4 | ||||
|       - name: Setup pnpm | ||||
|         uses: pnpm/action-setup@v4.1.0 | ||||
|       - name: Install FFmpeg | ||||
|         run: | | ||||
|           for i in {1..3}; do | ||||
| @@ -53,7 +50,6 @@ jobs: | ||||
|           cache: 'pnpm' | ||||
|       - name: Build Misskey | ||||
|         run: | | ||||
|           corepack enable && corepack prepare | ||||
|           pnpm i --frozen-lockfile | ||||
|           pnpm build | ||||
|       - name: Setup | ||||
|   | ||||
							
								
								
									
										14
									
								
								.github/workflows/test-frontend.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								.github/workflows/test-frontend.yml
									
									
									
									
										vendored
									
									
								
							| @@ -22,10 +22,6 @@ on: | ||||
|       - packages/backend/** | ||||
|       - .github/workflows/test-frontend.yml | ||||
|       - .github/misskey/test.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   vitest: | ||||
|     name: Unit tests (frontend) | ||||
| @@ -39,14 +35,13 @@ jobs: | ||||
|     - uses: actions/checkout@v4.2.2 | ||||
|       with: | ||||
|         submodules: true | ||||
|     - name: Install pnpm | ||||
|       uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - name: Use Node.js ${{ matrix.node-version }} | ||||
|       uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version: ${{ matrix.node-version }} | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Check pnpm-lock.yaml | ||||
|       run: git diff --exit-code pnpm-lock.yaml | ||||
| @@ -95,14 +90,13 @@ jobs: | ||||
|     #  if: ${{ matrix.browser == 'firefox' }} | ||||
|     #- uses: browser-actions/setup-firefox@latest | ||||
|     #  if: ${{ matrix.browser == 'firefox' }} | ||||
|     - name: Install pnpm | ||||
|       uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - name: Use Node.js ${{ matrix.node-version }} | ||||
|       uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version: ${{ matrix.node-version }} | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Copy Configure | ||||
|       run: cp .github/misskey/test.yml .config | ||||
|   | ||||
							
								
								
									
										7
									
								
								.github/workflows/test-misskey-js.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								.github/workflows/test-misskey-js.yml
									
									
									
									
										vendored
									
									
								
							| @@ -14,10 +14,6 @@ on: | ||||
|     paths: | ||||
|       - packages/misskey-js/** | ||||
|       - .github/workflows/test-misskey-js.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   test: | ||||
|     name: Unit tests (misskey.js) | ||||
| @@ -33,7 +29,8 @@ jobs: | ||||
|       - name: Checkout | ||||
|         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 }} | ||||
|         uses: actions/setup-node@v4.2.0 | ||||
|   | ||||
							
								
								
									
										6
									
								
								.github/workflows/test-production.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/test-production.yml
									
									
									
									
										vendored
									
									
								
							| @@ -9,7 +9,6 @@ on: | ||||
|  | ||||
| env: | ||||
|   NODE_ENV: production | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   production: | ||||
| @@ -24,14 +23,13 @@ jobs: | ||||
|     - uses: actions/checkout@v4.2.2 | ||||
|       with: | ||||
|         submodules: true | ||||
|     - name: Install pnpm | ||||
|       uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - name: Use Node.js ${{ matrix.node-version }} | ||||
|       uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
|         node-version: ${{ matrix.node-version }} | ||||
|         cache: 'pnpm' | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Check pnpm-lock.yaml | ||||
|       run: git diff --exit-code pnpm-lock.yaml | ||||
|   | ||||
							
								
								
									
										9
									
								
								.github/workflows/validate-api-json.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.github/workflows/validate-api-json.yml
									
									
									
									
										vendored
									
									
								
							| @@ -12,10 +12,6 @@ on: | ||||
|     paths: | ||||
|       - packages/backend/** | ||||
|       - .github/workflows/validate-api-json.yml | ||||
|  | ||||
| env: | ||||
|   COREPACK_DEFAULT_TO_LATEST: 0 | ||||
|  | ||||
| jobs: | ||||
|   validate-api-json: | ||||
|     runs-on: ubuntu-latest | ||||
| @@ -28,8 +24,8 @@ jobs: | ||||
|     - uses: actions/checkout@v4.2.2 | ||||
|       with: | ||||
|         submodules: true | ||||
|     - name: Install pnpm | ||||
|       uses: pnpm/action-setup@v4 | ||||
|     - name: Setup pnpm | ||||
|       uses: pnpm/action-setup@v4.1.0 | ||||
|     - name: Use Node.js ${{ matrix.node-version }} | ||||
|       uses: actions/setup-node@v4.2.0 | ||||
|       with: | ||||
| @@ -37,7 +33,6 @@ jobs: | ||||
|         cache: 'pnpm' | ||||
|     - name: Install Redocly CLI | ||||
|       run: npm i -g @redocly/cli | ||||
|     - run: corepack enable | ||||
|     - run: pnpm i --frozen-lockfile | ||||
|     - name: Check pnpm-lock.yaml | ||||
|       run: git diff --exit-code pnpm-lock.yaml | ||||
|   | ||||
							
								
								
									
										23
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,13 +1,32 @@ | ||||
| ## 2025.3.1 | ||||
| ## 2025.3.2 | ||||
|  | ||||
| ### General | ||||
| - | ||||
|  | ||||
| ### Client | ||||
| - Enhance: 設定の検索を追加(実験的) | ||||
| - Feat: 設定の管理が強化されました | ||||
|   - 自動でバックアップされるように | ||||
| - Enhance: プラグインの管理が強化されました | ||||
| - Enhance: テーマ設定画面のデザインを改善 | ||||
| - Fix: テーマ切り替え時に一部の色が変わらない問題を修正 | ||||
|  | ||||
| ### Server | ||||
| - Fix: プロフィール追加情報で無効なURLに入力された場合に照会エラーを出るのを修正 | ||||
|  | ||||
|  | ||||
| ## 2025.3.1 | ||||
|  | ||||
| ### General | ||||
| - pnpmをv10に更新 | ||||
| - Corepackを削除 | ||||
|  | ||||
| ### Client | ||||
| - Feat: 設定の検索を追加(実験的) | ||||
| - Enhance: 設定項目の再配置 | ||||
|  | ||||
| ### Server | ||||
| - Fix: DBマイグレーション際にシステムアカウントのユーザーID判定が正しくない問題を修正 | ||||
| - Fix: user.featured列が状況によってJSON文字列になっていたのを修正 | ||||
|  | ||||
|  | ||||
| ## 2025.3.0 | ||||
|   | ||||
							
								
								
									
										22
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								Dockerfile
									
									
									
									
									
								
							| @@ -6,8 +6,6 @@ ARG NODE_VERSION=22.11.0-bookworm | ||||
|  | ||||
| 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 \ | ||||
| 	--mount=type=cache,target=/var/lib/apt,sharing=locked \ | ||||
| 	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 \ | ||||
| 	build-essential | ||||
|  | ||||
| RUN corepack enable | ||||
|  | ||||
| WORKDIR /misskey | ||||
|  | ||||
| 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 | ||||
|  | ||||
| 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 \ | ||||
| 	pnpm i --frozen-lockfile --aggregate-output | ||||
|  | ||||
| @@ -46,14 +44,10 @@ RUN rm -rf .git/ | ||||
|  | ||||
| FROM --platform=$TARGETPLATFORM node:${NODE_VERSION} AS target-builder | ||||
|  | ||||
| ENV COREPACK_DEFAULT_TO_LATEST=0 | ||||
|  | ||||
| RUN apt-get update \ | ||||
| 	&& apt-get install -yqq --no-install-recommends \ | ||||
| 	build-essential | ||||
|  | ||||
| RUN corepack enable | ||||
|  | ||||
| WORKDIR /misskey | ||||
|  | ||||
| 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 | ||||
|  | ||||
| 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 \ | ||||
| 	pnpm i --frozen-lockfile --aggregate-output | ||||
|  | ||||
| @@ -72,13 +68,11 @@ FROM --platform=$TARGETPLATFORM node:${NODE_VERSION}-slim AS runner | ||||
|  | ||||
| ARG UID="991" | ||||
| ARG GID="991" | ||||
| ENV COREPACK_DEFAULT_TO_LATEST=0 | ||||
|  | ||||
| RUN apt-get update \ | ||||
| 	&& apt-get install -y --no-install-recommends \ | ||||
| 	ffmpeg tini curl libjemalloc-dev libjemalloc2 \ | ||||
| 	&& ln -s /usr/lib/$(uname -m)-linux-gnu/libjemalloc.so.2 /usr/local/lib/libjemalloc.so \ | ||||
| 	&& corepack enable \ | ||||
| 	&& groupadd -g "${GID}" 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 {} \; \ | ||||
| @@ -86,13 +80,13 @@ RUN apt-get update \ | ||||
| 	&& apt-get clean \ | ||||
| 	&& 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 | ||||
| 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/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 | ||||
|   | ||||
							
								
								
									
										88
									
								
								locales/index.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										88
									
								
								locales/index.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -5278,6 +5278,86 @@ export interface Locale extends ILocale { | ||||
|      * アクセシビリティ | ||||
|      */ | ||||
|     "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": { | ||||
|         /** | ||||
|          * コンテンツの表示にログインを必須にする | ||||
| @@ -5315,6 +5395,10 @@ export interface Locale extends ILocale { | ||||
|          * リモートサーバーに連合されたノートには効果が及ばない場合があります。 | ||||
|          */ | ||||
|         "mayNotEffectForFederatedNotes": string; | ||||
|         /** | ||||
|          * これらの制限は簡易的なものです。リモートサーバーでの閲覧やモデレーション時など、一部のシチュエーションでは適用されない場合があります。 | ||||
|          */ | ||||
|         "mayNotEffectSomeSituations": string; | ||||
|         /** | ||||
|          * 指定した時間を経過しているノート | ||||
|          */ | ||||
| @@ -7662,6 +7746,10 @@ export interface Locale extends ILocale { | ||||
|          * 標準のテーマ | ||||
|          */ | ||||
|         "builtinThemes": string; | ||||
|         /** | ||||
|          * サーバーのテーマ | ||||
|          */ | ||||
|         "instanceTheme": string; | ||||
|         /** | ||||
|          * そのテーマは既にインストールされています | ||||
|          */ | ||||
|   | ||||
| @@ -1315,6 +1315,29 @@ markAsSensitiveConfirm: "このメディアをセンシティブとして設定 | ||||
| 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: | ||||
|   requireSigninToViewContents: "コンテンツの表示にログインを必須にする" | ||||
| @@ -1326,6 +1349,7 @@ _accountSettings: | ||||
|   makeNotesHiddenBefore: "過去のノートを非公開化する" | ||||
|   makeNotesHiddenBeforeDescription: "この機能が有効になっている間、設定された日時より過去、または設定された時間を経過しているノートが自分のみ表示可能(非公開化)になります。無効に戻すと、ノートの公開状態も元に戻ります。" | ||||
|   mayNotEffectForFederatedNotes: "リモートサーバーに連合されたノートには効果が及ばない場合があります。" | ||||
|   mayNotEffectSomeSituations: "これらの制限は簡易的なものです。リモートサーバーでの閲覧やモデレーション時など、一部のシチュエーションでは適用されない場合があります。" | ||||
|   notesHavePassedSpecifiedPeriod: "指定した時間を経過しているノート" | ||||
|   notesOlderThanSpecifiedDateAndTime: "指定した日時より前のノート" | ||||
|  | ||||
| @@ -2007,6 +2031,7 @@ _theme: | ||||
|   installed: "{name}をインストールしました" | ||||
|   installedThemes: "インストールされたテーマ" | ||||
|   builtinThemes: "標準のテーマ" | ||||
|   instanceTheme: "サーバーのテーマ" | ||||
|   alreadyInstalled: "そのテーマは既にインストールされています" | ||||
|   invalid: "テーマの形式が間違っています" | ||||
|   make: "テーマを作る" | ||||
|   | ||||
| @@ -1313,6 +1313,8 @@ confirmOnReact: "反應時確認" | ||||
| reactAreYouSure: "用「 {emoji} 」反應嗎?" | ||||
| markAsSensitiveConfirm: "要將這個媒體設定為敏感嗎?" | ||||
| unmarkAsSensitiveConfirm: "要解除這個媒體的敏感設定嗎?" | ||||
| preferences: "環境設定" | ||||
| accessibility: "輔助工具" | ||||
| _accountSettings: | ||||
|   requireSigninToViewContents: "須登入以顯示內容" | ||||
|   requireSigninToViewContentsDescription1: "必須登入才會顯示您建立的貼文等內容。可望有效防止資訊被爬蟲蒐集。" | ||||
|   | ||||
							
								
								
									
										37
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								package.json
									
									
									
									
									
								
							| @@ -1,12 +1,12 @@ | ||||
| { | ||||
| 	"name": "misskey", | ||||
| 	"version": "2025.3.1-alpha.0", | ||||
| 	"version": "2025.3.2-alpha.5", | ||||
| 	"codename": "nasubi", | ||||
| 	"repository": { | ||||
| 		"type": "git", | ||||
| 		"url": "https://github.com/misskey-dev/misskey.git" | ||||
| 	}, | ||||
| 	"packageManager": "pnpm@9.15.4", | ||||
| 	"packageManager": "pnpm@10.6.1", | ||||
| 	"workspaces": [ | ||||
| 		"packages/frontend-shared", | ||||
| 		"packages/frontend", | ||||
| @@ -47,35 +47,44 @@ | ||||
| 		"cleanall": "pnpm clean-all" | ||||
| 	}, | ||||
| 	"resolutions": { | ||||
| 		"chokidar": "3.6.0", | ||||
| 		"chokidar": "4.0.3", | ||||
| 		"lodash": "4.17.21" | ||||
| 	}, | ||||
| 	"dependencies": { | ||||
| 		"cssnano": "7.0.6", | ||||
| 		"execa": "8.0.1", | ||||
| 		"execa": "9.5.2", | ||||
| 		"fast-glob": "3.3.3", | ||||
| 		"ignore-walk": "6.0.5", | ||||
| 		"ignore-walk": "7.0.0", | ||||
| 		"js-yaml": "4.1.0", | ||||
| 		"postcss": "8.5.2", | ||||
| 		"tar": "6.2.1", | ||||
| 		"postcss": "8.5.3", | ||||
| 		"tar": "7.4.3", | ||||
| 		"terser": "5.39.0", | ||||
| 		"typescript": "5.7.3", | ||||
| 		"typescript": "5.8.2", | ||||
| 		"esbuild": "0.25.0", | ||||
| 		"glob": "11.0.1" | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| 		"@misskey-dev/eslint-plugin": "2.1.0", | ||||
| 		"@types/node": "22.13.4", | ||||
| 		"@typescript-eslint/eslint-plugin": "8.24.0", | ||||
| 		"@typescript-eslint/parser": "8.24.0", | ||||
| 		"@types/node": "22.13.10", | ||||
| 		"@typescript-eslint/eslint-plugin": "8.26.0", | ||||
| 		"@typescript-eslint/parser": "8.26.0", | ||||
| 		"cross-env": "7.0.3", | ||||
| 		"cypress": "14.0.3", | ||||
| 		"eslint": "9.20.1", | ||||
| 		"globals": "15.15.0", | ||||
| 		"cypress": "14.1.0", | ||||
| 		"eslint": "9.22.0", | ||||
| 		"globals": "16.0.0", | ||||
| 		"ncp": "2.0.0", | ||||
| 		"pnpm": "10.6.1", | ||||
| 		"start-server-and-test": "2.0.10" | ||||
| 	}, | ||||
| 	"optionalDependencies": { | ||||
| 		"@tensorflow/tfjs-core": "4.22.0" | ||||
| 	}, | ||||
| 	"pnpm": { | ||||
| 		"overrides": { | ||||
| 			"@aiscript-dev/aiscript-languageserver": "-" | ||||
| 		}, | ||||
| 		"patchedDependencies": { | ||||
| 			"re2": "scripts/dependency-patches/re2.patch" | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -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 | ||||
|     } | ||||
| } | ||||
| @@ -268,7 +268,6 @@ export class FileInfoService { | ||||
| 	private async *asyncIterateFrames(cwd: string, command: FFmpeg.FfmpegCommand): AsyncGenerator<string, void> { | ||||
| 		const watcher = new FSWatcher({ | ||||
| 			cwd, | ||||
| 			disableGlobbing: true, | ||||
| 		}); | ||||
| 		let finished = false; | ||||
| 		command.once('end', () => { | ||||
|   | ||||
| @@ -499,11 +499,28 @@ export class ApRendererService { | ||||
| 			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 => ({ | ||||
| 			type: 'PropertyValue', | ||||
| 			name: field.name, | ||||
| 			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, | ||||
| 		})); | ||||
|  | ||||
|   | ||||
| @@ -560,7 +560,7 @@ export class ApPersonService implements OnModuleInit { | ||||
| 			inbox: person.inbox, | ||||
| 			sharedInbox: person.sharedInbox ?? person.endpoints?.sharedInbox ?? null, | ||||
| 			followersUri: person.followers ? getApId(person.followers) : undefined, | ||||
| 			featured: person.featured, | ||||
| 			featured: person.featured ? getApId(person.featured) : undefined, | ||||
| 			emojis: emojiNames, | ||||
| 			name: truncate(person.name, nameLength), | ||||
| 			tags, | ||||
|   | ||||
| @@ -751,7 +751,7 @@ export class ActivityPubServerService { | ||||
| 		}); | ||||
|  | ||||
| 		// 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 | ||||
| 			// check if the following exists and only check if the follow request exists. | ||||
|  | ||||
|   | ||||
| @@ -497,7 +497,7 @@ export class FileServerService { | ||||
|  | ||||
| 	@bindThis | ||||
| 	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(); | ||||
| 		try { | ||||
|   | ||||
| @@ -17,7 +17,6 @@ services: | ||||
|       - ./.config/docker.env | ||||
|     environment: | ||||
|       - NODE_ENV=production | ||||
|       - COREPACK_DEFAULT_TO_LATEST=0 | ||||
|     volumes: | ||||
|       - type: bind | ||||
|         source: ../../../built | ||||
| @@ -75,6 +74,10 @@ services: | ||||
|         source: ../../../pnpm-workspace.yaml | ||||
|         target: /misskey/pnpm-workspace.yaml | ||||
|         read_only: true | ||||
|       - type: bind | ||||
|         source: ../../../scripts/dependency-patches | ||||
|         target: /misskey/scripts/dependency-patches | ||||
|         read_only: true | ||||
|       - type: bind | ||||
|         source: ./certificates/rootCA.crt | ||||
|         target: /usr/local/share/ca-certificates/rootCA.crt | ||||
| @@ -82,7 +85,7 @@ services: | ||||
|     working_dir: /misskey | ||||
|     command: > | ||||
|       bash -c " | ||||
|         corepack enable && corepack prepare | ||||
|         npm install -g pnpm | ||||
|         pnpm -F backend migrate | ||||
|         pnpm -F backend start | ||||
|       " | ||||
|   | ||||
| @@ -9,7 +9,7 @@ services: | ||||
|       service: misskey | ||||
|     command: > | ||||
|       bash -c " | ||||
|         corepack enable && corepack prepare | ||||
|         npm install -g pnpm | ||||
|         pnpm -F backend i | ||||
|         pnpm -F misskey-js i | ||||
|         pnpm -F misskey-reversi i | ||||
| @@ -29,7 +29,6 @@ services: | ||||
|     environment: | ||||
|       - NODE_ENV=development | ||||
|       - NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/rootCA.crt | ||||
|       - COREPACK_DEFAULT_TO_LATEST=0 | ||||
|     volumes: | ||||
|       - type: bind | ||||
|         source: ../package.json | ||||
| @@ -71,6 +70,10 @@ services: | ||||
|         source: ../../../pnpm-workspace.yaml | ||||
|         target: /misskey/pnpm-workspace.yaml | ||||
|         read_only: true | ||||
|       - type: bind | ||||
|         source: ../../../scripts/dependency-patches | ||||
|         target: /misskey/scripts/dependency-patches | ||||
|         read_only: true | ||||
|       - type: bind | ||||
|         source: ./certificates/rootCA.crt | ||||
|         target: /usr/local/share/ca-certificates/rootCA.crt | ||||
| @@ -78,7 +81,7 @@ services: | ||||
|     working_dir: /misskey | ||||
|     entrypoint: > | ||||
|       bash -c ' | ||||
|         corepack enable && corepack prepare | ||||
|         npm install -g pnpm | ||||
|         pnpm -F misskey-js i --frozen-lockfile | ||||
|         pnpm -F backend i --frozen-lockfile | ||||
|         exec "$0" "$@" | ||||
| @@ -90,8 +93,6 @@ services: | ||||
|     depends_on: | ||||
|       redis.test: | ||||
|         condition: service_healthy | ||||
|     environment: | ||||
|       - COREPACK_DEFAULT_TO_LATEST=0 | ||||
|     volumes: | ||||
|       - type: bind | ||||
|         source: ../package.json | ||||
| @@ -117,10 +118,14 @@ services: | ||||
|         source: ../../../pnpm-workspace.yaml | ||||
|         target: /misskey/pnpm-workspace.yaml | ||||
|         read_only: true | ||||
|       - type: bind | ||||
|         source: ../../../scripts/dependency-patches | ||||
|         target: /misskey/scripts/dependency-patches | ||||
|         read_only: true | ||||
|     working_dir: /misskey | ||||
|     command: > | ||||
|       bash -c " | ||||
|         corepack enable && corepack prepare | ||||
|         npm install -g pnpm | ||||
|         pnpm -F backend i --frozen-lockfile | ||||
|         pnpm exec tsc -p ./packages/backend/test-federation | ||||
|         node ./packages/backend/test-federation/built/daemon.js | ||||
|   | ||||
| @@ -34,7 +34,7 @@ | ||||
| 		"typescript": "5.8.2", | ||||
| 		"uuid": "11.1.0", | ||||
| 		"json5": "2.2.3", | ||||
| 		"vite": "6.2.0", | ||||
| 		"vite": "6.2.1", | ||||
| 		"vue": "3.5.13" | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| @@ -48,14 +48,14 @@ | ||||
| 		"@types/ws": "8.18.0", | ||||
| 		"@typescript-eslint/eslint-plugin": "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", | ||||
| 		"acorn": "8.14.0", | ||||
| 		"acorn": "8.14.1", | ||||
| 		"cross-env": "7.0.3", | ||||
| 		"eslint-plugin-import": "2.31.0", | ||||
| 		"eslint-plugin-vue": "9.33.0", | ||||
| 		"eslint-plugin-vue": "10.0.0", | ||||
| 		"fast-glob": "3.3.3", | ||||
| 		"happy-dom": "17.2.2", | ||||
| 		"happy-dom": "17.3.0", | ||||
| 		"intersection-observer": "0.12.2", | ||||
| 		"micromatch": "4.0.8", | ||||
| 		"msw": "2.7.3", | ||||
| @@ -64,7 +64,7 @@ | ||||
| 		"start-server-and-test": "2.0.10", | ||||
| 		"vite-plugin-turbosnap": "1.0.3", | ||||
| 		"vue-component-type-helpers": "2.2.8", | ||||
| 		"vue-eslint-parser": "9.4.3", | ||||
| 		"vue-eslint-parser": "10.1.1", | ||||
| 		"vue-tsc": "2.2.8" | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -25,10 +25,10 @@ | ||||
| 		"@typescript-eslint/eslint-plugin": "8.26.0", | ||||
| 		"@typescript-eslint/parser": "8.26.0", | ||||
| 		"esbuild": "0.25.0", | ||||
| 		"eslint-plugin-vue": "9.33.0", | ||||
| 		"eslint-plugin-vue": "10.0.0", | ||||
| 		"nodemon": "3.1.9", | ||||
| 		"typescript": "5.8.2", | ||||
| 		"vue-eslint-parser": "9.4.3" | ||||
| 		"vue-eslint-parser": "10.1.1" | ||||
| 	}, | ||||
| 	"files": [ | ||||
| 		"js-built" | ||||
|   | ||||
| @@ -21,7 +21,7 @@ let moduleInitialized = false; | ||||
| let unobserve = () => {}; | ||||
| let misskeyOS = null; | ||||
|  | ||||
| function loadTheme(applyTheme: typeof import('../src/scripts/theme')['applyTheme']) { | ||||
| function loadTheme(applyTheme: typeof import('../src/theme')['applyTheme']) { | ||||
| 	unobserve(); | ||||
| 	const theme = themes[document.documentElement.dataset.misskeyTheme]; | ||||
| 	if (theme) { | ||||
| @@ -67,10 +67,10 @@ queueMicrotask(() => { | ||||
| 		import('../src/components'), | ||||
| 		import('../src/directives'), | ||||
| 		import('../src/widgets'), | ||||
| 		import('../src/scripts/theme'), | ||||
| 		import('../src/store'), | ||||
| 		import('../src/theme'), | ||||
| 		import('../src/preferences'), | ||||
| 		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) => { | ||||
| 			moduleInitialized = true; | ||||
| 			if (app[appInitialized]) { | ||||
| @@ -83,7 +83,7 @@ queueMicrotask(() => { | ||||
| 			widgets(app); | ||||
| 			misskeyOS = os; | ||||
| 			if (isChromatic()) { | ||||
| 				defaultStore.set('animation', false); | ||||
| 				prefer.set('animation', false); | ||||
| 			} | ||||
| 		}); | ||||
| 	}); | ||||
| @@ -104,9 +104,9 @@ const preview = { | ||||
| 							} | ||||
| 						}).catch(() => {}) | ||||
| 					: Promise.resolve(); | ||||
| 				const resetDefaultStorePromise = import('../src/store').then(({ defaultStore }) => { | ||||
| 				const resetDefaultStorePromise = import('../src/store').then(({ store }) => { | ||||
| 					// @ts-expect-error | ||||
| 					defaultStore.init(); | ||||
| 					store.init(); | ||||
| 				}).catch(() => {}); | ||||
| 				Promise.all([resetIndexedDBPromise, resetDefaultStorePromise]).then(() => { | ||||
| 					initLocalStorage(); | ||||
|   | ||||
							
								
								
									
										2
									
								
								packages/frontend/@types/theme.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								packages/frontend/@types/theme.d.ts
									
									
									
									
										vendored
									
									
								
							| @@ -4,7 +4,7 @@ | ||||
|  */ | ||||
|  | ||||
| declare module '@@/themes/*.json5' { | ||||
| 	import { Theme } from '@/scripts/theme.js'; | ||||
| 	import { Theme } from '@/theme.js'; | ||||
|  | ||||
| 	const theme: Theme; | ||||
|  | ||||
|   | ||||
| @@ -58,7 +58,7 @@ describe(normalizeClass.name, () => { | ||||
|  | ||||
| it('Composition API (standard)', () => { | ||||
| 	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 { 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'; | ||||
| @@ -74,7 +74,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({ | ||||
|     let fetching = ref(true); | ||||
|     let images = ref([]); | ||||
|     function thumbnail(image) { | ||||
|       return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; | ||||
|       return store.s.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; | ||||
|     } | ||||
|     onMounted(() => { | ||||
|       const image = [ | ||||
| @@ -173,7 +173,7 @@ export { index_photos as default }; | ||||
| `.slice(1), { ecmaVersion: 'latest', sourceType: 'module' }); | ||||
| 	unwindCssModuleClassName(ast); | ||||
| 	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 {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'; | ||||
| @@ -190,7 +190,7 @@ const index_photos = defineComponent({ | ||||
|     let fetching = ref(true); | ||||
|     let images = ref([]); | ||||
|     function thumbnail(image) { | ||||
|       return defaultStore.state.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; | ||||
|       return store.s.disableShowingAnimatedImages ? getStaticImageUrl(image.url) : image.thumbnailUrl; | ||||
|     } | ||||
|     onMounted(() => { | ||||
|       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()`)', () => { | ||||
| 	const ast = parse(` | ||||
| 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) { | ||||
|   try { | ||||
| @@ -393,7 +393,7 @@ const _sfc_main = defineComponent({ | ||||
|       el.style.left = ""; | ||||
|     } | ||||
|     return () => h( | ||||
|       defaultStore.state.animation ? TransitionGroup : "div", | ||||
|       prefer.s.animation ? TransitionGroup : "div", | ||||
|       { | ||||
|         class: { | ||||
|           [$style["date-separated-list"]]: true, | ||||
| @@ -402,7 +402,7 @@ const _sfc_main = defineComponent({ | ||||
|           [$style["direction-down"]]: props.direction === "down", | ||||
|           [$style["direction-up"]]: props.direction === "up" | ||||
|         }, | ||||
|         ...defaultStore.state.animation ? { | ||||
|         ...prefer.s.animation ? { | ||||
|           name: "list", | ||||
|           tag: "div", | ||||
|           onBeforeLeave, | ||||
| @@ -441,7 +441,7 @@ export { MkDateSeparatedList as M }; | ||||
| 	unwindCssModuleClassName(ast); | ||||
| 	expect(generate(ast)).toBe(` | ||||
| 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) { | ||||
|   try { | ||||
|     return localStorage.getItem(\`DEBUG_\${id}\`) !== null; | ||||
| @@ -555,7 +555,7 @@ const _sfc_main = defineComponent({ | ||||
|       el.style.top = ""; | ||||
|       el.style.left = ""; | ||||
|     } | ||||
|     return () => h(defaultStore.state.animation ? TransitionGroup : "div", { | ||||
|     return () => h(prefer.s.animation ? TransitionGroup : "div", { | ||||
|       class: { | ||||
|         [$style["date-separated-list"]]: true, | ||||
|         [$style["date-separated-list-nogap"]]: props.noGap, | ||||
| @@ -563,7 +563,7 @@ const _sfc_main = defineComponent({ | ||||
|         [$style["direction-down"]]: props.direction === "down", | ||||
|         [$style["direction-up"]]: props.direction === "up" | ||||
|       }, | ||||
|       ...defaultStore.state.animation ? { | ||||
|       ...prefer.s.animation ? { | ||||
|         name: "list", | ||||
|         tag: "div", | ||||
|         onBeforeLeave, | ||||
|   | ||||
| @@ -1213,22 +1213,37 @@ async function processVueFile( | ||||
| 	transformedCodeCache: Record<string, string> | ||||
| }> { | ||||
| 	const normalizedId = id.replace(/\\/g, '/'); // ファイルパスを正規化 | ||||
| 	// すでにキャッシュに存在する場合は、そのまま返す | ||||
| 	if (transformedCodeCache[normalizedId] && transformedCodeCache[normalizedId].includes('markerId=')) { | ||||
|  | ||||
| 	// 開発モード時はコード内容に変更があれば常に再処理する | ||||
| 	// コード内容が同じ場合のみキャッシュを使用 | ||||
| 	const isDevMode = process.env.NODE_ENV === 'development'; | ||||
|  | ||||
| 	const s = new MagicString(code); // magic-string のインスタンスを作成 | ||||
|  | ||||
| 	if (!isDevMode && transformedCodeCache[normalizedId] && transformedCodeCache[normalizedId].includes('markerId=')) { | ||||
| 		logger.info(`Using cached version for ${id}`); | ||||
| 		return { | ||||
| 			code: transformedCodeCache[normalizedId], | ||||
| 			map: null, | ||||
| 			map: s.generateMap({ source: id, includeContent: true }), | ||||
| 			transformedCodeCache | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	// すでに処理済みのファイルでコードに変更がない場合はキャッシュを返す | ||||
| 	if (transformedCodeCache[normalizedId] === code) { | ||||
| 		logger.info(`Code unchanged for ${id}, using cached version`); | ||||
| 		return { | ||||
| 			code: transformedCodeCache[normalizedId], | ||||
| 			map: s.generateMap({ source: id, includeContent: true }), | ||||
| 			transformedCodeCache | ||||
| 		}; | ||||
| 	} | ||||
|  | ||||
| 	const s = new MagicString(code); // magic-string のインスタンスを作成 | ||||
| 	const parsed = vueSfcParse(code, { filename: id }); | ||||
| 	if (!parsed.descriptor.template) { | ||||
| 		return { | ||||
| 			code, | ||||
| 			map: null, | ||||
| 			map: s.generateMap({ source: id, includeContent: true }), | ||||
| 			transformedCodeCache | ||||
| 		}; | ||||
| 	} | ||||
| @@ -1466,16 +1481,21 @@ export default function pluginCreateSearchIndex(options: Options): Plugin { | ||||
| 				if (isMatch) break; // いずれかのパターンでマッチしたら、outer loop も抜ける | ||||
| 			} | ||||
|  | ||||
|  | ||||
| 			if (!isMatch) { | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| 			// ファイルの内容が変更された場合は再処理を行う | ||||
| 			const normalizedId = id.replace(/\\/g, '/'); | ||||
| 			const hasContentChanged = !transformedCodeCache[normalizedId] || transformedCodeCache[normalizedId] !== code; | ||||
|  | ||||
| 			const transformed = await processVueFile(code, id, options, transformedCodeCache); | ||||
| 			transformedCodeCache = transformed.transformedCodeCache; // キャッシュを更新 | ||||
| 			if (isDevServer) { | ||||
| 				await analyzeVueProps({ ...options, transformedCodeCache }); // analyzeVueProps を呼び出す | ||||
|  | ||||
| 			if (isDevServer && hasContentChanged) { | ||||
| 				await analyzeVueProps({ ...options, transformedCodeCache }); // ファイルが変更されたときのみ分析を実行 | ||||
| 			} | ||||
|  | ||||
| 			return transformed; | ||||
| 		}, | ||||
|  | ||||
|   | ||||
| @@ -73,30 +73,31 @@ | ||||
| 		"typescript": "5.8.2", | ||||
| 		"uuid": "11.1.0", | ||||
| 		"v-code-diff": "1.13.1", | ||||
| 		"vite": "6.2.0", | ||||
| 		"vite": "6.2.1", | ||||
| 		"vue": "3.5.13", | ||||
| 		"vuedraggable": "next" | ||||
| 		"vuedraggable": "next", | ||||
| 		"wanakana": "5.3.1" | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| 		"@misskey-dev/summaly": "5.2.0", | ||||
| 		"@storybook/addon-actions": "8.6.3", | ||||
| 		"@storybook/addon-essentials": "8.6.3", | ||||
| 		"@storybook/addon-interactions": "8.6.3", | ||||
| 		"@storybook/addon-links": "8.6.3", | ||||
| 		"@storybook/addon-mdx-gfm": "8.6.3", | ||||
| 		"@storybook/addon-storysource": "8.6.3", | ||||
| 		"@storybook/blocks": "8.6.3", | ||||
| 		"@storybook/components": "8.6.3", | ||||
| 		"@storybook/core-events": "8.6.3", | ||||
| 		"@storybook/manager-api": "8.6.3", | ||||
| 		"@storybook/preview-api": "8.6.3", | ||||
| 		"@storybook/react": "8.6.3", | ||||
| 		"@storybook/react-vite": "8.6.3", | ||||
| 		"@storybook/test": "8.6.3", | ||||
| 		"@storybook/theming": "8.6.3", | ||||
| 		"@storybook/types": "8.6.3", | ||||
| 		"@storybook/vue3": "8.6.3", | ||||
| 		"@storybook/vue3-vite": "8.6.3", | ||||
| 		"@storybook/addon-actions": "8.6.4", | ||||
| 		"@storybook/addon-essentials": "8.6.4", | ||||
| 		"@storybook/addon-interactions": "8.6.4", | ||||
| 		"@storybook/addon-links": "8.6.4", | ||||
| 		"@storybook/addon-mdx-gfm": "8.6.4", | ||||
| 		"@storybook/addon-storysource": "8.6.4", | ||||
| 		"@storybook/blocks": "8.6.4", | ||||
| 		"@storybook/components": "8.6.4", | ||||
| 		"@storybook/core-events": "8.6.4", | ||||
| 		"@storybook/manager-api": "8.6.4", | ||||
| 		"@storybook/preview-api": "8.6.4", | ||||
| 		"@storybook/react": "8.6.4", | ||||
| 		"@storybook/react-vite": "8.6.4", | ||||
| 		"@storybook/test": "8.6.4", | ||||
| 		"@storybook/theming": "8.6.4", | ||||
| 		"@storybook/types": "8.6.4", | ||||
| 		"@storybook/vue3": "8.6.4", | ||||
| 		"@storybook/vue3-vite": "8.6.4", | ||||
| 		"@testing-library/vue": "8.1.0", | ||||
| 		"@types/canvas-confetti": "1.9.0", | ||||
| 		"@types/estree": "1.0.6", | ||||
| @@ -111,15 +112,15 @@ | ||||
| 		"@types/ws": "8.18.0", | ||||
| 		"@typescript-eslint/eslint-plugin": "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", | ||||
| 		"acorn": "8.14.0", | ||||
| 		"acorn": "8.14.1", | ||||
| 		"cross-env": "7.0.3", | ||||
| 		"cypress": "14.1.0", | ||||
| 		"eslint-plugin-import": "2.31.0", | ||||
| 		"eslint-plugin-vue": "9.33.0", | ||||
| 		"eslint-plugin-vue": "10.0.0", | ||||
| 		"fast-glob": "3.3.3", | ||||
| 		"happy-dom": "17.2.2", | ||||
| 		"happy-dom": "17.3.0", | ||||
| 		"intersection-observer": "0.12.2", | ||||
| 		"micromatch": "4.0.8", | ||||
| 		"msw": "2.7.3", | ||||
| @@ -130,13 +131,13 @@ | ||||
| 		"react-dom": "19.0.0", | ||||
| 		"seedrandom": "3.0.5", | ||||
| 		"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", | ||||
| 		"vite-plugin-turbosnap": "1.0.3", | ||||
| 		"vitest": "3.0.7", | ||||
| 		"vitest": "3.0.8", | ||||
| 		"vitest-fetch-mock": "0.4.5", | ||||
| 		"vue-component-type-helpers": "2.2.8", | ||||
| 		"vue-eslint-parser": "9.4.3", | ||||
| 		"vue-eslint-parser": "10.1.1", | ||||
| 		"vue-tsc": "2.2.8" | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -8,13 +8,13 @@ import * as Misskey from 'misskey-js'; | ||||
| import { apiUrl } from '@@/js/config.js'; | ||||
| import type { MenuItem, MenuButton } from '@/types/menu.js'; | ||||
| 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 { 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 { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { unisonReload, reloadChannel } from '@/scripts/unison-reload.js'; | ||||
| import { misskeyApi } from '@/utility/misskey-api.js'; | ||||
| import { unisonReload, reloadChannel } from '@/utility/unison-reload.js'; | ||||
|  | ||||
| // TODO: 他のタブと永続化されたstateを同期 | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ import * as Misskey from 'misskey-js'; | ||||
| import { url, lang } from '@@/js/config.js'; | ||||
| import { assertStringAndIsIn } from './common.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 { miLocalStorage } from '@/local-storage.js'; | ||||
| import { customEmojis } from '@/custom-emojis.js'; | ||||
| @@ -6,26 +6,29 @@ | ||||
| import { computed, watch, version as vueVersion } from 'vue'; | ||||
| import { compareVersions } from 'compare-versions'; | ||||
| 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 widgets from '@/widgets/index.js'; | ||||
| import directives from '@/directives/index.js'; | ||||
| import components from '@/components/index.js'; | ||||
| import { applyTheme } from '@/scripts/theme.js'; | ||||
| import { isDeviceDarkmode } from '@/scripts/is-device-darkmode.js'; | ||||
| import { applyTheme } from '@/theme.js'; | ||||
| import { isDeviceDarkmode } from '@/utility/is-device-darkmode.js'; | ||||
| import { updateI18n, i18n } from '@/i18n.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 { deviceKind, updateDeviceKind } from '@/scripts/device-kind.js'; | ||||
| import { reloadChannel } from '@/scripts/unison-reload.js'; | ||||
| import { getUrlWithoutLoginId } from '@/scripts/login-id.js'; | ||||
| import { getAccountFromId } from '@/scripts/get-account-from-id.js'; | ||||
| import { deviceKind, updateDeviceKind } from '@/utility/device-kind.js'; | ||||
| import { reloadChannel } from '@/utility/unison-reload.js'; | ||||
| import { getUrlWithoutLoginId } from '@/utility/login-id.js'; | ||||
| import { getAccountFromId } from '@/utility/get-account-from-id.js'; | ||||
| import { deckStore } from '@/ui/deck/deck-store.js'; | ||||
| import { analytics, initAnalytics } from '@/analytics.js'; | ||||
| import { miLocalStorage } from '@/local-storage.js'; | ||||
| import { fetchCustomEmojis } from '@/custom-emojis.js'; | ||||
| import { setupRouter } from '@/router/main.js'; | ||||
| import { createMainRouter } from '@/router/definition.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| export async function common(createVue: () => App<Element>) { | ||||
| 	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 | ||||
| 		(window as any).$i = $i; | ||||
| 		// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||
| 		(window as any).$store = defaultStore; | ||||
| 		(window as any).$store = store; | ||||
|  | ||||
| 		window.addEventListener('error', event => { | ||||
| 			console.error(event); | ||||
| @@ -123,7 +126,7 @@ export async function common(createVue: () => App<Element>) { | ||||
| 	html.setAttribute('lang', lang); | ||||
| 	//#endregion | ||||
|  | ||||
| 	await defaultStore.ready; | ||||
| 	await store.ready; | ||||
| 	await deckStore.ready; | ||||
|  | ||||
| 	const fetchInstanceMetaPromise = fetchInstance(); | ||||
| @@ -151,56 +154,63 @@ export async function common(createVue: () => App<Element>) { | ||||
| 	//#endregion | ||||
|  | ||||
| 	// NOTE: この処理は必ずクライアント更新チェック処理より後に来ること(テーマ再構築のため) | ||||
| 	watch(defaultStore.reactiveState.darkMode, (darkMode) => { | ||||
| 		applyTheme(darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')); | ||||
| 	watch(store.r.darkMode, (darkMode) => { | ||||
| 		applyTheme(darkMode | ||||
| 			? (prefer.s.darkTheme ?? defaultDarkTheme) | ||||
| 			: (prefer.s.lightTheme ?? defaultLightTheme), | ||||
| 		); | ||||
| 	}, { immediate: miLocalStorage.getItem('theme') == null }); | ||||
|  | ||||
| 	document.documentElement.dataset.colorScheme = defaultStore.state.darkMode ? 'dark' : 'light'; | ||||
| 	document.documentElement.dataset.colorScheme = store.s.darkMode ? 'dark' : 'light'; | ||||
|  | ||||
| 	const darkTheme = computed(ColdDeviceStorage.makeGetterSetter('darkTheme')); | ||||
| 	const lightTheme = computed(ColdDeviceStorage.makeGetterSetter('lightTheme')); | ||||
| 	const darkTheme = prefer.model('darkTheme'); | ||||
| 	const lightTheme = prefer.model('lightTheme'); | ||||
|  | ||||
| 	watch(darkTheme, (theme) => { | ||||
| 		if (defaultStore.state.darkMode) { | ||||
| 			applyTheme(theme); | ||||
| 		if (store.s.darkMode) { | ||||
| 			applyTheme(theme ?? defaultDarkTheme); | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
| 	watch(lightTheme, (theme) => { | ||||
| 		if (!defaultStore.state.darkMode) { | ||||
| 			applyTheme(theme); | ||||
| 		if (!store.s.darkMode) { | ||||
| 			applyTheme(theme ?? defaultLightTheme); | ||||
| 		} | ||||
| 	}); | ||||
|  | ||||
| 	//#region Sync dark mode | ||||
| 	if (ColdDeviceStorage.get('syncDeviceDarkMode')) { | ||||
| 		defaultStore.set('darkMode', isDeviceDarkmode()); | ||||
| 	if (prefer.s.syncDeviceDarkMode) { | ||||
| 		store.set('darkMode', isDeviceDarkmode()); | ||||
| 	} | ||||
|  | ||||
| 	window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (mql) => { | ||||
| 		if (ColdDeviceStorage.get('syncDeviceDarkMode')) { | ||||
| 			defaultStore.set('darkMode', mql.matches); | ||||
| 		if (prefer.s.syncDeviceDarkMode) { | ||||
| 			store.set('darkMode', mql.matches); | ||||
| 		} | ||||
| 	}); | ||||
| 	//#endregion | ||||
|  | ||||
| 	if (prefer.s.darkTheme && store.s.darkMode) { | ||||
| 		if (miLocalStorage.getItem('themeId') !== prefer.s.darkTheme.id) applyTheme(prefer.s.darkTheme); | ||||
| 	} else if (prefer.s.lightTheme && !store.s.darkMode) { | ||||
| 		if (miLocalStorage.getItem('themeId') !== prefer.s.lightTheme.id) applyTheme(prefer.s.lightTheme); | ||||
| 	} | ||||
|  | ||||
| 	fetchInstanceMetaPromise.then(() => { | ||||
| 		if (defaultStore.state.themeInitial) { | ||||
| 			if (instance.defaultLightTheme != null) ColdDeviceStorage.set('lightTheme', JSON.parse(instance.defaultLightTheme)); | ||||
| 			if (instance.defaultDarkTheme != null) ColdDeviceStorage.set('darkTheme', JSON.parse(instance.defaultDarkTheme)); | ||||
| 			defaultStore.set('themeInitial', false); | ||||
| 		} | ||||
| 		// TODO: instance.defaultLightTheme/instance.defaultDarkThemeが不正な形式だった場合のケア | ||||
| 		if (prefer.s.lightTheme == null && instance.defaultLightTheme != null) prefer.commit('lightTheme', JSON.parse(instance.defaultLightTheme)); | ||||
| 		if (prefer.s.darkTheme == null && instance.defaultDarkTheme != null) prefer.commit('darkTheme', JSON.parse(instance.defaultDarkTheme)); | ||||
| 	}); | ||||
|  | ||||
| 	watch(defaultStore.reactiveState.overridedDeviceKind, (kind) => { | ||||
| 	watch(prefer.r.overridedDeviceKind, (kind) => { | ||||
| 		updateDeviceKind(kind); | ||||
| 	}, { immediate: true }); | ||||
|  | ||||
| 	watch(defaultStore.reactiveState.useBlurEffectForModal, v => { | ||||
| 	watch(prefer.r.useBlurEffectForModal, v => { | ||||
| 		document.documentElement.style.setProperty('--MI-modalBgFilter', v ? 'blur(4px)' : 'none'); | ||||
| 	}, { immediate: true }); | ||||
|  | ||||
| 	watch(defaultStore.reactiveState.useBlurEffect, v => { | ||||
| 	watch(prefer.r.useBlurEffect, v => { | ||||
| 		if (v) { | ||||
| 			document.documentElement.style.removeProperty('--MI-blur'); | ||||
| 		} else { | ||||
| @@ -214,7 +224,7 @@ export async function common(createVue: () => App<Element>) { | ||||
| 			navigator.wakeLock.request('screen'); | ||||
| 		} | ||||
| 	}); | ||||
| 	if (defaultStore.state.keepScreenOn && 'wakeLock' in navigator) { | ||||
| 	if (prefer.s.keepScreenOn && 'wakeLock' in navigator) { | ||||
| 		navigator.wakeLock.request('screen') | ||||
| 			.then(onVisibilityChange) | ||||
| 			.catch(() => { | ||||
|   | ||||
| @@ -5,26 +5,29 @@ | ||||
|  | ||||
| import { createApp, defineAsyncComponent, markRaw } from 'vue'; | ||||
| import { ui } from '@@/js/config.js'; | ||||
| import { common } from './common.js'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { common } from './common.js'; | ||||
| import type { Component } from 'vue'; | ||||
| import type { Keymap } from '@/utility/hotkey.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { alert, confirm, popup, post, toast } from '@/os.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 { instance } from '@/instance.js'; | ||||
| import { ColdDeviceStorage, defaultStore } from '@/store.js'; | ||||
| import { reactionPicker } from '@/scripts/reaction-picker.js'; | ||||
| import { ColdDeviceStorage, store } from '@/store.js'; | ||||
| import { reactionPicker } from '@/utility/reaction-picker.js'; | ||||
| import { miLocalStorage } from '@/local-storage.js'; | ||||
| import { claimAchievement, claimedAchievements } from '@/scripts/achievements.js'; | ||||
| import { initializeSw } from '@/scripts/initialize-sw.js'; | ||||
| import { deckStore } from '@/ui/deck/deck-store.js'; | ||||
| import { emojiPicker } from '@/scripts/emoji-picker.js'; | ||||
| import { claimAchievement, claimedAchievements } from '@/utility/achievements.js'; | ||||
| import { initializeSw } from '@/utility/initialize-sw.js'; | ||||
| import { emojiPicker } from '@/utility/emoji-picker.js'; | ||||
| import { mainRouter } from '@/router/main.js'; | ||||
| import { makeHotkey } from '@/scripts/hotkey.js'; | ||||
| import type { Keymap } from '@/scripts/hotkey.js'; | ||||
| import { makeHotkey } from '@/utility/hotkey.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() { | ||||
| 	const { isClientUpdated } = await common(() => { | ||||
| @@ -34,7 +37,7 @@ export async function mainBoot() { | ||||
| 		if (!$i) uiStyle = 'visitor'; | ||||
|  | ||||
| 		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'); | ||||
|  | ||||
| @@ -73,9 +76,9 @@ export async function mainBoot() { | ||||
|  | ||||
| 	let reloadDialogShowing = false; | ||||
| 	stream.on('_disconnected_', async () => { | ||||
| 		if (defaultStore.state.serverDisconnectedBehavior === 'reload') { | ||||
| 		if (prefer.s.serverDisconnectedBehavior === 'reload') { | ||||
| 			location.reload(); | ||||
| 		} else if (defaultStore.state.serverDisconnectedBehavior === 'dialog') { | ||||
| 		} else if (prefer.s.serverDisconnectedBehavior === 'dialog') { | ||||
| 			if (reloadDialogShowing) return; | ||||
| 			reloadDialogShowing = true; | ||||
| 			const { canceled } = await confirm({ | ||||
| @@ -102,30 +105,24 @@ export async function mainBoot() { | ||||
| 		removeCustomEmojis(emojiData.emojis); | ||||
| 	}); | ||||
|  | ||||
| 	for (const plugin of ColdDeviceStorage.get('plugins').filter(p => p.active)) { | ||||
| 		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); | ||||
| 		}); | ||||
| 	} | ||||
| 	launchPlugins(); | ||||
|  | ||||
| 	try { | ||||
| 		if (defaultStore.state.enableSeasonalScreenEffect) { | ||||
| 		if (prefer.s.enableSeasonalScreenEffect) { | ||||
| 			const month = new Date().getMonth() + 1; | ||||
| 			if (defaultStore.state.hemisphere === 'S') { | ||||
| 			if (prefer.s.hemisphere === 'S') { | ||||
| 				// ▼南半球 | ||||
| 				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(); | ||||
| 				} | ||||
| 			} else { | ||||
| 				// ▼北半球 | ||||
| 				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(); | ||||
| 				} 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({ | ||||
| 						sakura: true, | ||||
| 					}).render(); | ||||
| @@ -138,8 +135,101 @@ export async function mainBoot() { | ||||
| 	} | ||||
|  | ||||
| 	if ($i) { | ||||
| 		defaultStore.loaded.then(() => { | ||||
| 			if (defaultStore.state.accountSetupWizard !== -1) { | ||||
| 		store.loaded.then(async () => { | ||||
| 			// prefereces migration | ||||
| 			// TODO: そのうち消す | ||||
| 			if (store.s.menu.length > 0) { | ||||
| 				const themes = await misskeyApi('i/registry/get', { scope: ['client'], key: 'themes' }).catch(() => []); | ||||
| 				if (themes.length > 0) { | ||||
| 					prefer.commit('themes', themes); | ||||
| 				} | ||||
| 				const plugins = ColdDeviceStorage.get('plugins'); | ||||
| 				prefer.commit('plugins', plugins.map(p => ({ | ||||
| 					...p, | ||||
| 					installId: (p as any).id, | ||||
| 					id: undefined, | ||||
| 				}))); | ||||
| 				prefer.commit('lightTheme', ColdDeviceStorage.get('lightTheme')); | ||||
| 				prefer.commit('darkTheme', ColdDeviceStorage.get('darkTheme')); | ||||
| 				prefer.commit('syncDeviceDarkMode', ColdDeviceStorage.get('syncDeviceDarkMode')); | ||||
| 				prefer.commit('overridedDeviceKind', store.s.overridedDeviceKind); | ||||
| 				prefer.commit('widgets', store.s.widgets); | ||||
| 				prefer.commit('keepCw', store.s.keepCw); | ||||
| 				prefer.commit('collapseRenotes', store.s.collapseRenotes); | ||||
| 				prefer.commit('rememberNoteVisibility', store.s.rememberNoteVisibility); | ||||
| 				prefer.commit('uploadFolder', store.s.uploadFolder); | ||||
| 				prefer.commit('keepOriginalUploading', store.s.keepOriginalUploading); | ||||
| 				prefer.commit('menu', store.s.menu); | ||||
| 				prefer.commit('statusbars', store.s.statusbars); | ||||
| 				prefer.commit('pinnedUserLists', store.s.pinnedUserLists); | ||||
| 				prefer.commit('serverDisconnectedBehavior', store.s.serverDisconnectedBehavior); | ||||
| 				prefer.commit('nsfw', store.s.nsfw); | ||||
| 				prefer.commit('highlightSensitiveMedia', store.s.highlightSensitiveMedia); | ||||
| 				prefer.commit('animation', store.s.animation); | ||||
| 				prefer.commit('animatedMfm', store.s.animatedMfm); | ||||
| 				prefer.commit('advancedMfm', store.s.advancedMfm); | ||||
| 				prefer.commit('showReactionsCount', store.s.showReactionsCount); | ||||
| 				prefer.commit('enableQuickAddMfmFunction', store.s.enableQuickAddMfmFunction); | ||||
| 				prefer.commit('loadRawImages', store.s.loadRawImages); | ||||
| 				prefer.commit('imageNewTab', store.s.imageNewTab); | ||||
| 				prefer.commit('disableShowingAnimatedImages', store.s.disableShowingAnimatedImages); | ||||
| 				prefer.commit('emojiStyle', store.s.emojiStyle); | ||||
| 				prefer.commit('menuStyle', store.s.menuStyle); | ||||
| 				prefer.commit('useBlurEffectForModal', store.s.useBlurEffectForModal); | ||||
| 				prefer.commit('useBlurEffect', store.s.useBlurEffect); | ||||
| 				prefer.commit('showFixedPostForm', store.s.showFixedPostForm); | ||||
| 				prefer.commit('showFixedPostFormInChannel', store.s.showFixedPostFormInChannel); | ||||
| 				prefer.commit('enableInfiniteScroll', store.s.enableInfiniteScroll); | ||||
| 				prefer.commit('useReactionPickerForContextMenu', store.s.useReactionPickerForContextMenu); | ||||
| 				prefer.commit('showGapBetweenNotesInTimeline', store.s.showGapBetweenNotesInTimeline); | ||||
| 				prefer.commit('instanceTicker', store.s.instanceTicker); | ||||
| 				prefer.commit('emojiPickerScale', store.s.emojiPickerScale); | ||||
| 				prefer.commit('emojiPickerWidth', store.s.emojiPickerWidth); | ||||
| 				prefer.commit('emojiPickerHeight', store.s.emojiPickerHeight); | ||||
| 				prefer.commit('emojiPickerStyle', store.s.emojiPickerStyle); | ||||
| 				prefer.commit('reportError', store.s.reportError); | ||||
| 				prefer.commit('squareAvatars', store.s.squareAvatars); | ||||
| 				prefer.commit('showAvatarDecorations', store.s.showAvatarDecorations); | ||||
| 				prefer.commit('numberOfPageCache', store.s.numberOfPageCache); | ||||
| 				prefer.commit('showNoteActionsOnlyHover', store.s.showNoteActionsOnlyHover); | ||||
| 				prefer.commit('showClipButtonInNoteFooter', store.s.showClipButtonInNoteFooter); | ||||
| 				prefer.commit('reactionsDisplaySize', store.s.reactionsDisplaySize); | ||||
| 				prefer.commit('limitWidthOfReaction', store.s.limitWidthOfReaction); | ||||
| 				prefer.commit('forceShowAds', store.s.forceShowAds); | ||||
| 				prefer.commit('aiChanMode', store.s.aiChanMode); | ||||
| 				prefer.commit('devMode', store.s.devMode); | ||||
| 				prefer.commit('mediaListWithOneImageAppearance', store.s.mediaListWithOneImageAppearance); | ||||
| 				prefer.commit('notificationPosition', store.s.notificationPosition); | ||||
| 				prefer.commit('notificationStackAxis', store.s.notificationStackAxis); | ||||
| 				prefer.commit('enableCondensedLine', store.s.enableCondensedLine); | ||||
| 				prefer.commit('keepScreenOn', store.s.keepScreenOn); | ||||
| 				prefer.commit('disableStreamingTimeline', store.s.disableStreamingTimeline); | ||||
| 				prefer.commit('useGroupedNotifications', store.s.useGroupedNotifications); | ||||
| 				prefer.commit('dataSaver', store.s.dataSaver); | ||||
| 				prefer.commit('enableSeasonalScreenEffect', store.s.enableSeasonalScreenEffect); | ||||
| 				prefer.commit('enableHorizontalSwipe', store.s.enableHorizontalSwipe); | ||||
| 				prefer.commit('useNativeUiForVideoAudioPlayer', store.s.useNativeUIForVideoAudioPlayer); | ||||
| 				prefer.commit('keepOriginalFilename', store.s.keepOriginalFilename); | ||||
| 				prefer.commit('alwaysConfirmFollow', store.s.alwaysConfirmFollow); | ||||
| 				prefer.commit('confirmWhenRevealingSensitiveMedia', store.s.confirmWhenRevealingSensitiveMedia); | ||||
| 				prefer.commit('contextMenu', store.s.contextMenu); | ||||
| 				prefer.commit('skipNoteRender', store.s.skipNoteRender); | ||||
| 				prefer.commit('showSoftWordMutedWord', store.s.showSoftWordMutedWord); | ||||
| 				prefer.commit('confirmOnReact', store.s.confirmOnReact); | ||||
| 				prefer.commit('sound.masterVolume', store.s.sound_masterVolume); | ||||
| 				prefer.commit('sound.notUseSound', store.s.sound_notUseSound); | ||||
| 				prefer.commit('sound.useSoundOnlyWhenActive', store.s.sound_useSoundOnlyWhenActive); | ||||
| 				prefer.commit('sound.on.note', store.s.sound_note as any); | ||||
| 				prefer.commit('sound.on.noteMy', store.s.sound_noteMy as any); | ||||
| 				prefer.commit('sound.on.notification', store.s.sound_notification as any); | ||||
| 				prefer.commit('sound.on.reaction', store.s.sound_reaction as any); | ||||
| 				store.set('deck.profile', deckStore.s.profile); | ||||
| 				store.set('deck.columns', deckStore.s.columns); | ||||
| 				store.set('deck.layout', deckStore.s.layout); | ||||
| 				store.set('menu', []); | ||||
| 			} | ||||
|  | ||||
| 			if (store.s.accountSetupWizard !== -1) { | ||||
| 				const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkUserSetupDialog.vue')), {}, { | ||||
| 					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; | ||||
| 			if (announcement.display === 'dialog') { | ||||
| 				const { dispose } = popup(defineAsyncComponent(() => import('@/components/MkAnnouncementDialog.vue')), { | ||||
| @@ -412,7 +502,7 @@ export async function mainBoot() { | ||||
| 			post(); | ||||
| 		}, | ||||
| 		'd': () => { | ||||
| 			defaultStore.set('darkMode', !defaultStore.state.darkMode); | ||||
| 			store.set('darkMode', !store.s.darkMode); | ||||
| 		}, | ||||
| 		's': () => { | ||||
| 			mainRouter.push('/search'); | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  | ||||
| import { createApp, defineAsyncComponent } from 'vue'; | ||||
| import { common } from './common.js'; | ||||
| import { emojiPicker } from '@/scripts/emoji-picker.js'; | ||||
| import { emojiPicker } from '@/utility/emoji-picker.js'; | ||||
|  | ||||
| export async function subBoot() { | ||||
| 	const { isClientUpdated } = await common(() => createApp( | ||||
|   | ||||
| @@ -4,8 +4,8 @@ | ||||
|  */ | ||||
|  | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { Cache } from '@/scripts/cache.js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { Cache } from '@/utility/cache.js'; | ||||
| import { misskeyApi } from '@/utility/misskey-api.js'; | ||||
|  | ||||
| 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')); | ||||
|   | ||||
| @@ -90,7 +90,7 @@ import MkFolder from '@/components/MkFolder.vue'; | ||||
| import RouterView from '@/components/global/RouterView.vue'; | ||||
| import { useRouterFactory } from '@/router/supplier'; | ||||
| 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<{ | ||||
| 	report: Misskey.entities.AdminAbuseUserReportsResponse[number]; | ||||
|   | ||||
| @@ -17,7 +17,7 @@ import * as Misskey from 'misskey-js'; | ||||
| import MkMention from './MkMention.vue'; | ||||
| import { i18n } from '@/i18n.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>(); | ||||
|  | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import { HttpResponse, http } from 'msw'; | ||||
| import { userDetailed } from '../../.storybook/fakes.js'; | ||||
| import { commonHandlers } from '../../.storybook/mocks.js'; | ||||
| import MkAchievements from './MkAchievements.vue'; | ||||
| import { ACHIEVEMENT_TYPES } from '@/scripts/achievements.js'; | ||||
| import { ACHIEVEMENT_TYPES } from '@/utility/achievements.js'; | ||||
| export const Empty = { | ||||
| 	render(args) { | ||||
| 		return { | ||||
|   | ||||
| @@ -55,9 +55,9 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { onMounted, ref, computed } from 'vue'; | ||||
| 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 { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/scripts/achievements.js'; | ||||
| import { ACHIEVEMENT_TYPES, ACHIEVEMENT_BADGES, claimAchievement } from '@/utility/achievements.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	user: Misskey.entities.User; | ||||
|   | ||||
| @@ -82,7 +82,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { computed, onMounted, onBeforeUnmount, ref } from 'vue'; | ||||
| import tinycolor from 'tinycolor2'; | ||||
| 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 | ||||
| const angleDiff = (a: number, b: number) => { | ||||
|   | ||||
| @@ -25,7 +25,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { onMounted, shallowRef } from 'vue'; | ||||
| import * as Misskey from 'misskey-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 MkButton from '@/components/MkButton.vue'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
|   | ||||
| @@ -59,10 +59,10 @@ import MkTextarea from '@/components/MkTextarea.vue'; | ||||
| import MkSelect from '@/components/MkSelect.vue'; | ||||
| import MkSwitch from '@/components/MkSwitch.vue'; | ||||
| 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 { deepMerge } from '@/scripts/merge.js'; | ||||
| import type { DeepPartial } from '@/scripts/merge.js'; | ||||
| import { deepMerge } from '@/utility/merge.js'; | ||||
| import type { DeepPartial } from '@/utility/merge.js'; | ||||
|  | ||||
| type PartialAllowedAntenna = Omit<Misskey.entities.Antenna, 'id' | 'createdAt' | 'updatedAt'> & { | ||||
| 	id?: string; | ||||
|   | ||||
| @@ -71,7 +71,7 @@ import MkInput from '@/components/MkInput.vue'; | ||||
| import MkSwitch from '@/components/MkSwitch.vue'; | ||||
| import MkTextarea from '@/components/MkTextarea.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 MkPostForm from '@/components/MkPostForm.vue'; | ||||
|  | ||||
|   | ||||
| @@ -123,8 +123,8 @@ import MkButton from '@/components/MkButton.vue'; | ||||
| import { $i, getAccounts, getAccountWithSigninDialog, getAccountWithSignupDialog } from '@/account.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { getProxiedImageUrl } from '@/scripts/media-proxy.js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { getProxiedImageUrl } from '@/utility/media-proxy.js'; | ||||
| import { misskeyApi } from '@/utility/misskey-api.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	name?: string; | ||||
|   | ||||
| @@ -12,7 +12,7 @@ import { userDetailed } from '../../.storybook/fakes.js'; | ||||
| import { commonHandlers } from '../../.storybook/mocks.js'; | ||||
| import MkAutocomplete from './MkAutocomplete.vue'; | ||||
| import MkInput from './MkInput.vue'; | ||||
| import { tick } from '@/scripts/test-utils.js'; | ||||
| import { tick } from '@/utility/test-utils.js'; | ||||
| const common = { | ||||
| 	render(args) { | ||||
| 		return { | ||||
|   | ||||
| @@ -49,22 +49,23 @@ import sanitizeHtml from 'sanitize-html'; | ||||
| import { emojilist, getEmojiName } from '@@/js/emojilist.js'; | ||||
| import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@@/js/emoji-base.js'; | ||||
| import { MFM_TAGS, MFM_PARAMS } from '@@/js/const.js'; | ||||
| import type { EmojiDef } from '@/scripts/search-emoji.js'; | ||||
| import contains from '@/scripts/contains.js'; | ||||
| import type { EmojiDef } from '@/utility/search-emoji.js'; | ||||
| import contains from '@/utility/contains.js'; | ||||
| import { acct } from '@/filters/user.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { misskeyApi } from '@/utility/misskey-api.js'; | ||||
| import { store } from '@/store.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { miLocalStorage } from '@/local-storage.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 emojiDb = computed(() => { | ||||
| 	//#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 => ({ | ||||
| 		emoji: x.char, | ||||
| @@ -72,7 +73,7 @@ const emojiDb = computed(() => { | ||||
| 		url: char2path(x.char), | ||||
| 	})); | ||||
|  | ||||
| 	for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { | ||||
| 	for (const index of Object.values(store.s.additionalUnicodeEmojiIndexes)) { | ||||
| 		for (const [emoji, keywords] of Object.entries(index)) { | ||||
| 			for (const k of keywords) { | ||||
| 				unicodeEmojiDB.push({ | ||||
| @@ -154,10 +155,10 @@ function complete(type: string, value: any) { | ||||
| 	emit('done', { type, value }); | ||||
| 	emit('closed'); | ||||
| 	if (type === 'emoji') { | ||||
| 		let recents = defaultStore.state.recentlyUsedEmojis; | ||||
| 		let recents = store.s.recentlyUsedEmojis; | ||||
| 		recents = recents.filter((emoji: any) => emoji !== 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') { | ||||
| 		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.s.recentlyUsedEmojis.map(emoji => emojiDb.value.find(dbEmoji => dbEmoji.emoji === emoji)).filter(x => x) as EmojiDef[]; | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <script lang="ts" setup> | ||||
| import { onMounted, ref } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { misskeyApi } from '@/utility/misskey-api.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	userIds: string[]; | ||||
|   | ||||
| @@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| 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 | ||||
| // see: https://docs.hcaptcha.com/configuration/#javascript-api | ||||
| @@ -154,7 +154,7 @@ async function requestRender() { | ||||
|  | ||||
| 		captchaWidgetId.value = captcha.value.render(elem, { | ||||
| 			sitekey: props.sitekey, | ||||
| 			theme: defaultStore.state.darkMode ? 'dark' : 'light', | ||||
| 			theme: store.s.darkMode ? 'dark' : 'light', | ||||
| 			callback: callback, | ||||
| 			'expired-callback': () => callback(undefined), | ||||
| 			'error-callback': () => callback(undefined), | ||||
|   | ||||
| @@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <script lang="ts" setup> | ||||
| import { ref } from 'vue'; | ||||
| 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'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
|   | ||||
| @@ -53,15 +53,15 @@ export type ChartSrc = | ||||
| import { onMounted, ref, shallowRef, watch } from 'vue'; | ||||
| import { Chart } from 'chart.js'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { misskeyApiGet } from '@/scripts/misskey-api.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { useChartTooltip } from '@/scripts/use-chart-tooltip.js'; | ||||
| import { chartVLine } from '@/scripts/chart-vline.js'; | ||||
| import { alpha } from '@/scripts/color.js'; | ||||
| import { misskeyApiGet } from '@/utility/misskey-api.js'; | ||||
| import { store } from '@/store.js'; | ||||
| import { useChartTooltip } from '@/utility/use-chart-tooltip.js'; | ||||
| import { chartVLine } from '@/utility/chart-vline.js'; | ||||
| import { alpha } from '@/utility/color.js'; | ||||
| import date from '@/filters/date.js'; | ||||
| import bytes from '@/filters/bytes.js'; | ||||
| import { initChart } from '@/scripts/init-chart.js'; | ||||
| import { chartLegend } from '@/scripts/chart-legend.js'; | ||||
| import { initChart } from '@/utility/init-chart.js'; | ||||
| import { chartLegend } from '@/utility/chart-legend.js'; | ||||
| import MkChartLegend from '@/components/MkChartLegend.vue'; | ||||
|  | ||||
| initChart(); | ||||
| @@ -161,7 +161,7 @@ const render = () => { | ||||
| 		chartInstance.destroy(); | ||||
| 	} | ||||
|  | ||||
| 	const vLineColor = defaultStore.state.darkMode ? 'rgba(255, 255, 255, 0.2)' : 'rgba(0, 0, 0, 0.2)'; | ||||
| 	const vLineColor = store.s.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))); | ||||
|  | ||||
|   | ||||
| @@ -23,9 +23,9 @@ import { computed, onMounted, onUnmounted, ref } from 'vue'; | ||||
| import MkPlusOneEffect from '@/components/MkPlusOneEffect.vue'; | ||||
| import * as os from '@/os.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 { claimAchievement } from '@/scripts/achievements.js'; | ||||
| import { claimAchievement } from '@/utility/achievements.js'; | ||||
|  | ||||
| const saveData = game.saveData; | ||||
| const cookies = computed(() => saveData.value?.cookies); | ||||
|   | ||||
| @@ -12,8 +12,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { computed, ref, watch } from 'vue'; | ||||
| import { bundledLanguagesInfo } from 'shiki/langs'; | ||||
| import type { BundledLanguage } from 'shiki/langs'; | ||||
| import { getHighlighter, getTheme } from '@/scripts/code-highlighter.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { getHighlighter, getTheme } from '@/utility/code-highlighter.js'; | ||||
| import { store } from '@/store.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	code: string; | ||||
| @@ -22,7 +22,7 @@ const props = defineProps<{ | ||||
| }>(); | ||||
|  | ||||
| const highlighter = await getHighlighter(); | ||||
| const darkMode = defaultStore.reactiveState.darkMode; | ||||
| const darkMode = store.r.darkMode; | ||||
| const codeLang = ref<BundledLanguage | 'aiscript'>('js'); | ||||
|  | ||||
| const [lightThemeName, darkThemeName] = await Promise.all([ | ||||
| @@ -74,10 +74,8 @@ watch(() => props.lang, (to) => { | ||||
| <style module lang="scss"> | ||||
| .codeBlockRoot :global(.shiki) { | ||||
| 	padding: 1em; | ||||
| 	margin: .5em 0; | ||||
| 	margin: 0; | ||||
| 	overflow: auto; | ||||
| 	border-radius: 8px; | ||||
| 	border: 1px solid var(--MI_THEME-divider); | ||||
| 	font-family: Consolas, Monaco, Andale Mono, Ubuntu Mono, monospace; | ||||
|  | ||||
| 	color: var(--shiki-fallback); | ||||
|   | ||||
| @@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	</button> | ||||
| 	<Suspense> | ||||
| 		<template #fallback> | ||||
| 			<MkLoading /> | ||||
| 			<MkLoading/> | ||||
| 		</template> | ||||
| 		<XCode v-if="show && lang" :code="code" :lang="lang"/> | ||||
| 		<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 * as os from '@/os.js'; | ||||
| import MkLoading from '@/components/global/MkLoading.vue'; | ||||
| import { defaultStore } from '@/store.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<{ | ||||
| 	code: string; | ||||
| @@ -42,7 +42,7 @@ const props = withDefaults(defineProps<{ | ||||
| 	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')); | ||||
|  | ||||
|   | ||||
| @@ -19,10 +19,10 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 		</div> | ||||
| 	</header> | ||||
| 	<Transition | ||||
| 		:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" | ||||
| 		:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" | ||||
| 		:enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" | ||||
| 		:leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" | ||||
| 		:enterActiveClass="prefer.s.animation ? $style.transition_toggle_enterActive : ''" | ||||
| 		:leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''" | ||||
| 		:enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''" | ||||
| 		:leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''" | ||||
| 		@enter="enter" | ||||
| 		@afterEnter="afterEnter" | ||||
| 		@leave="leave" | ||||
| @@ -40,7 +40,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { onMounted, onUnmounted, ref, shallowRef, watch } from 'vue'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
|   | ||||
| @@ -6,10 +6,10 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <template> | ||||
| <Transition | ||||
| 	appear | ||||
| 	:enterActiveClass="defaultStore.state.animation ? $style.transition_fade_enterActive : ''" | ||||
| 	:leaveActiveClass="defaultStore.state.animation ? $style.transition_fade_leaveActive : ''" | ||||
| 	:enterFromClass="defaultStore.state.animation ? $style.transition_fade_enterFrom : ''" | ||||
| 	:leaveToClass="defaultStore.state.animation ? $style.transition_fade_leaveTo : ''" | ||||
| 	:enterActiveClass="prefer.s.animation ? $style.transition_fade_enterActive : ''" | ||||
| 	:leaveActiveClass="prefer.s.animation ? $style.transition_fade_leaveActive : ''" | ||||
| 	:enterFromClass="prefer.s.animation ? $style.transition_fade_enterFrom : ''" | ||||
| 	:leaveToClass="prefer.s.animation ? $style.transition_fade_leaveTo : ''" | ||||
| > | ||||
| 	<div ref="rootEl" :class="$style.root" :style="{ zIndex }" @contextmenu.prevent.stop="() => {}"> | ||||
| 		<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 MkMenu from './MkMenu.vue'; | ||||
| import type { MenuItem } from '@/types/menu.js'; | ||||
| import contains from '@/scripts/contains.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import contains from '@/utility/contains.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
| import * as os from '@/os.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   | ||||
| @@ -35,13 +35,13 @@ import { onMounted, shallowRef, ref } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import Cropper from 'cropperjs'; | ||||
| import tinycolor from 'tinycolor2'; | ||||
| import { apiUrl } from '@@/js/config.js'; | ||||
| import MkModalWindow from '@/components/MkModalWindow.vue'; | ||||
| import * as os from '@/os.js'; | ||||
| import { $i } from '@/account.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { apiUrl } from '@@/js/config.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<{ | ||||
| 	(ev: 'ok', cropped: Misskey.entities.DriveFile): void; | ||||
| @@ -81,8 +81,8 @@ const ok = async () => { | ||||
| 			formData.append('i', $i!.token); | ||||
| 			if (props.uploadFolder) { | ||||
| 				formData.append('folderId', props.uploadFolder); | ||||
| 			} else if (props.uploadFolder !== null && defaultStore.state.uploadFolder) { | ||||
| 				formData.append('folderId', defaultStore.state.uploadFolder); | ||||
| 			} else if (props.uploadFolder !== null && prefer.s.uploadFolder) { | ||||
| 				formData.append('folderId', prefer.s.uploadFolder); | ||||
| 			} | ||||
|  | ||||
| 			window.fetch(apiUrl + '/drive/files/create', { | ||||
|   | ||||
| @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { computed } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| 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 MkButton from '@/components/MkButton.vue'; | ||||
|  | ||||
|   | ||||
| @@ -6,13 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <script lang="ts"> | ||||
| import { defineComponent, h, TransitionGroup, useCssModule } from 'vue'; | ||||
| import type { PropType } from 'vue'; | ||||
| import type { MisskeyEntity } from '@/types/date-separated-list.js'; | ||||
| import MkAd from '@/components/global/MkAd.vue'; | ||||
| import { isDebuggerEnabled, stackTraceInstances } from '@/debug.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { instance } from '@/instance.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import type { MisskeyEntity } from '@/types/date-separated-list.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| export default defineComponent({ | ||||
| 	props: { | ||||
| @@ -150,7 +150,7 @@ export default defineComponent({ | ||||
| 			[$style['direction-up']]: props.direction === 'up', | ||||
| 		}; | ||||
|  | ||||
| 		return () => defaultStore.state.animation ? h(TransitionGroup, { | ||||
| 		return () => prefer.s.animation ? h(TransitionGroup, { | ||||
| 			class: classes, | ||||
| 			name: 'list', | ||||
| 			tag: 'div', | ||||
|   | ||||
| @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| 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<{ | ||||
| 	showS?: boolean; | ||||
|   | ||||
| @@ -24,7 +24,8 @@ defineProps<{ | ||||
| } | ||||
|  | ||||
| .disabled { | ||||
| 	opacity: 0.7; | ||||
| 	opacity: 0.3; | ||||
| 	filter: saturate(0.5); | ||||
| } | ||||
|  | ||||
| .cover { | ||||
|   | ||||
| @@ -45,8 +45,8 @@ import bytes from '@/filters/bytes.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { $i } from '@/account.js'; | ||||
| import { getDriveFileMenu } from '@/scripts/get-drive-file-menu.js'; | ||||
| import { deviceKind } from '@/scripts/device-kind.js'; | ||||
| import { getDriveFileMenu } from '@/utility/get-drive-file-menu.js'; | ||||
| import { deviceKind } from '@/utility/device-kind.js'; | ||||
| import { useRouter } from '@/router/supplier.js'; | ||||
|  | ||||
| const router = useRouter(); | ||||
|   | ||||
| @@ -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> | ||||
| 		{{ folder.name }} | ||||
| 	</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 }} | ||||
| 	</p> | ||||
| 	<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 type { MenuItem } from '@/types/menu.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 { defaultStore } from '@/store.js'; | ||||
| import { claimAchievement } from '@/scripts/achievements.js'; | ||||
| import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; | ||||
| import { claimAchievement } from '@/utility/achievements.js'; | ||||
| import { copyToClipboard } from '@/utility/copy-to-clipboard.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	folder: Misskey.entities.DriveFolder; | ||||
| @@ -244,8 +244,8 @@ function deleteFolder() { | ||||
| 	misskeyApi('drive/folders/delete', { | ||||
| 		folderId: props.folder.id, | ||||
| 	}).then(() => { | ||||
| 		if (defaultStore.state.uploadFolder === props.folder.id) { | ||||
| 			defaultStore.set('uploadFolder', null); | ||||
| 		if (prefer.s.uploadFolder === props.folder.id) { | ||||
| 			prefer.commit('uploadFolder', null); | ||||
| 		} | ||||
| 	}).catch(err => { | ||||
| 		switch (err.id) { | ||||
| @@ -266,7 +266,7 @@ function deleteFolder() { | ||||
| } | ||||
|  | ||||
| function setAsUploadFolder() { | ||||
| 	defaultStore.set('uploadFolder', props.folder.id); | ||||
| 	prefer.commit('uploadFolder', props.folder.id); | ||||
| } | ||||
|  | ||||
| function onContextmenu(ev: MouseEvent) { | ||||
| @@ -295,7 +295,7 @@ function onContextmenu(ev: MouseEvent) { | ||||
| 		danger: true, | ||||
| 		action: deleteFolder, | ||||
| 	}]; | ||||
| 	if (defaultStore.state.devMode) { | ||||
| 	if (prefer.s.devMode) { | ||||
| 		menu = menu.concat([{ type: 'divider' }, { | ||||
| 			icon: 'ti ti-id', | ||||
| 			text: i18n.ts.copyFolderId, | ||||
|   | ||||
| @@ -20,7 +20,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <script lang="ts" setup> | ||||
| import { ref } from 'vue'; | ||||
| 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'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
|   | ||||
| @@ -104,12 +104,12 @@ import XNavFolder from '@/components/MkDrive.navFolder.vue'; | ||||
| import XFolder from '@/components/MkDrive.folder.vue'; | ||||
| import XFile from '@/components/MkDrive.file.vue'; | ||||
| 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 { defaultStore } from '@/store.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { uploadFile, uploads } from '@/scripts/upload.js'; | ||||
| import { claimAchievement } from '@/scripts/achievements.js'; | ||||
| import { uploadFile, uploads } from '@/utility/upload.js'; | ||||
| import { claimAchievement } from '@/utility/achievements.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	initialFolder?: Misskey.entities.DriveFolder; | ||||
| @@ -142,7 +142,7 @@ const selectedFiles = ref<Misskey.entities.DriveFile[]>([]); | ||||
| const selectedFolders = ref<Misskey.entities.DriveFolder[]>([]); | ||||
| const uploadings = uploads; | ||||
| 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); | ||||
| @@ -716,7 +716,7 @@ function onContextmenu(ev: MouseEvent) { | ||||
| } | ||||
|  | ||||
| onMounted(() => { | ||||
| 	if (defaultStore.state.enableInfiniteScroll && loadMoreFiles.value) { | ||||
| 	if (prefer.s.enableInfiniteScroll && loadMoreFiles.value) { | ||||
| 		nextTick(() => { | ||||
| 			ilFilesObserver.observe(loadMoreFiles.value?.$el); | ||||
| 		}); | ||||
| @@ -737,7 +737,7 @@ onMounted(() => { | ||||
| }); | ||||
|  | ||||
| onActivated(() => { | ||||
| 	if (defaultStore.state.enableInfiniteScroll) { | ||||
| 	if (prefer.s.enableInfiniteScroll) { | ||||
| 		nextTick(() => { | ||||
| 			ilFilesObserver.observe(loadMoreFiles.value?.$el); | ||||
| 		}); | ||||
|   | ||||
| @@ -105,8 +105,8 @@ import MkInfo from '@/components/MkInfo.vue'; | ||||
|  | ||||
| import * as os from '@/os.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; | ||||
| import { normalizeEmbedParams, getEmbedCode } from '@/scripts/get-embed-code.js'; | ||||
| import { copyToClipboard } from '@/utility/copy-to-clipboard.js'; | ||||
| import { normalizeEmbedParams, getEmbedCode } from '@/utility/get-embed-code.js'; | ||||
|  | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'ok'): void; | ||||
|   | ||||
| @@ -131,17 +131,18 @@ import type { | ||||
| import XSection from '@/components/MkEmojiPicker.section.vue'; | ||||
| import MkRippleEffect from '@/components/MkRippleEffect.vue'; | ||||
| import * as os from '@/os.js'; | ||||
| import { isTouchUsing } from '@/scripts/touch.js'; | ||||
| import { deviceKind } from '@/scripts/device-kind.js'; | ||||
| import { isTouchUsing } from '@/utility/touch.js'; | ||||
| import { deviceKind } from '@/utility/device-kind.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 { $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<{ | ||||
| 	showPinned?: boolean; | ||||
|   pinnedEmojis?: string[]; | ||||
| 	pinnedEmojis?: string[]; | ||||
| 	maxHeight?: number; | ||||
| 	asDrawer?: boolean; | ||||
| 	asWindow?: boolean; | ||||
| @@ -163,8 +164,9 @@ const { | ||||
| 	emojiPickerScale, | ||||
| 	emojiPickerWidth, | ||||
| 	emojiPickerHeight, | ||||
| 	recentlyUsedEmojis, | ||||
| } = defaultStore.reactiveState; | ||||
| } = prefer.r; | ||||
|  | ||||
| const recentlyUsedEmojis = store.r.recentlyUsedEmojis; | ||||
|  | ||||
| const recentlyUsedEmojisDef = computed(() => { | ||||
| 	return recentlyUsedEmojis.value.map(getDef); | ||||
| @@ -317,7 +319,7 @@ watch(q, () => { | ||||
| 			} | ||||
| 			if (matches.size >= max) return matches; | ||||
|  | ||||
| 			for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { | ||||
| 			for (const index of Object.values(store.s.additionalUnicodeEmojiIndexes)) { | ||||
| 				for (const emoji of emojis) { | ||||
| 					if (keywords.every(keyword => index[emoji.char].some(k => k.includes(keyword)))) { | ||||
| 						matches.add(emoji); | ||||
| @@ -334,7 +336,7 @@ watch(q, () => { | ||||
| 			} | ||||
| 			if (matches.size >= max) return matches; | ||||
|  | ||||
| 			for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { | ||||
| 			for (const index of Object.values(store.s.additionalUnicodeEmojiIndexes)) { | ||||
| 				for (const emoji of emojis) { | ||||
| 					if (index[emoji.char].some(k => k.startsWith(newQ))) { | ||||
| 						matches.add(emoji); | ||||
| @@ -351,7 +353,7 @@ watch(q, () => { | ||||
| 			} | ||||
| 			if (matches.size >= max) return matches; | ||||
|  | ||||
| 			for (const index of Object.values(defaultStore.state.additionalUnicodeEmojiIndexes)) { | ||||
| 			for (const index of Object.values(store.s.additionalUnicodeEmojiIndexes)) { | ||||
| 				for (const emoji of emojis) { | ||||
| 					if (index[emoji.char].some(k => k.includes(newQ))) { | ||||
| 						matches.add(emoji); | ||||
| @@ -413,7 +415,7 @@ function computeButtonTitle(ev: MouseEvent): void { | ||||
|  | ||||
| function chosen(emoji: string | Misskey.entities.EmojiSimple | UnicodeEmojiDef, ev?: MouseEvent) { | ||||
| 	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 x = rect.left + (el.offsetWidth / 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)) { | ||||
| 		let recents = defaultStore.state.recentlyUsedEmojis; | ||||
| 		let recents = store.s.recentlyUsedEmojis; | ||||
| 		recents = recents.filter((emoji) => emoji !== key); | ||||
| 		recents.unshift(key); | ||||
| 		defaultStore.set('recentlyUsedEmojis', recents.splice(0, 32)); | ||||
| 		store.set('recentlyUsedEmojis', recents.splice(0, 32)); | ||||
| 	} | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	ref="modal" | ||||
| 	v-slot="{ type, maxHeight }" | ||||
| 	:zPriority="'middle'" | ||||
| 	:preferType="defaultStore.state.emojiPickerStyle" | ||||
| 	:preferType="prefer.s.emojiPickerStyle" | ||||
| 	:hasInteractionWithOtherFocusTrappedEls="true" | ||||
| 	:transparentBg="true" | ||||
| 	:manualShowing="manualShowing" | ||||
| @@ -40,16 +40,16 @@ import * as Misskey from 'misskey-js'; | ||||
| import { shallowRef } from 'vue'; | ||||
| import MkModal from '@/components/MkModal.vue'; | ||||
| import MkEmojiPicker from '@/components/MkEmojiPicker.vue'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	manualShowing?: boolean | null; | ||||
| 	src?: HTMLElement; | ||||
| 	showPinned?: boolean; | ||||
|   pinnedEmojis?: string[], | ||||
| 	pinnedEmojis?: string[], | ||||
| 	asReactionPicker?: boolean; | ||||
| 	targetNote?: Misskey.entities.Note; | ||||
|   choseAndClose?: boolean; | ||||
| 	choseAndClose?: boolean; | ||||
| }>(), { | ||||
| 	manualShowing: null, | ||||
| 	showPinned: true, | ||||
|   | ||||
| @@ -14,10 +14,10 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 		</button> | ||||
| 	</header> | ||||
| 	<Transition | ||||
| 		:enterActiveClass="defaultStore.state.animation ? $style.folderToggleEnterActive : ''" | ||||
| 		:leaveActiveClass="defaultStore.state.animation ? $style.folderToggleLeaveActive : ''" | ||||
| 		:enterFromClass="defaultStore.state.animation ? $style.folderToggleEnterFrom : ''" | ||||
| 		:leaveToClass="defaultStore.state.animation ? $style.folderToggleLeaveTo : ''" | ||||
| 		:enterActiveClass="prefer.s.animation ? $style.folderToggleEnterActive : ''" | ||||
| 		:leaveActiveClass="prefer.s.animation ? $style.folderToggleLeaveActive : ''" | ||||
| 		:enterFromClass="prefer.s.animation ? $style.folderToggleEnterFrom : ''" | ||||
| 		:leaveToClass="prefer.s.animation ? $style.folderToggleLeaveTo : ''" | ||||
| 		@enter="enter" | ||||
| 		@afterEnter="afterEnter" | ||||
| 		@leave="leave" | ||||
| @@ -33,8 +33,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <script lang="ts" setup> | ||||
| import { onMounted, ref, shallowRef, watch } from 'vue'; | ||||
| import { miLocalStorage } from '@/local-storage.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { getBgColor } from '@/scripts/get-bg-color.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
| import { getBgColor } from '@/utility/get-bg-color.js'; | ||||
|  | ||||
| const miLocalStoragePrefix = 'ui:folder:' as const; | ||||
|  | ||||
|   | ||||
| @@ -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"> | ||||
| 			<Transition | ||||
| 				:enterActiveClass="defaultStore.state.animation ? $style.transition_toggle_enterActive : ''" | ||||
| 				:leaveActiveClass="defaultStore.state.animation ? $style.transition_toggle_leaveActive : ''" | ||||
| 				:enterFromClass="defaultStore.state.animation ? $style.transition_toggle_enterFrom : ''" | ||||
| 				:leaveToClass="defaultStore.state.animation ? $style.transition_toggle_leaveTo : ''" | ||||
| 				:enterActiveClass="prefer.s.animation ? $style.transition_toggle_enterActive : ''" | ||||
| 				:leaveActiveClass="prefer.s.animation ? $style.transition_toggle_leaveActive : ''" | ||||
| 				:enterFromClass="prefer.s.animation ? $style.transition_toggle_enterFrom : ''" | ||||
| 				:leaveToClass="prefer.s.animation ? $style.transition_toggle_leaveTo : ''" | ||||
| 				@enter="enter" | ||||
| 				@afterEnter="afterEnter" | ||||
| 				@leave="leave" | ||||
| @@ -57,8 +57,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { nextTick, onMounted, ref, shallowRef } from 'vue'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { getBgColor } from '@/scripts/get-bg-color.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
| import { getBgColor } from '@/utility/get-bg-color.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	defaultOpen?: boolean; | ||||
|   | ||||
| @@ -39,13 +39,14 @@ import { onBeforeUnmount, onMounted, ref } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { host } from '@@/js/config.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 { i18n } from '@/i18n.js'; | ||||
| import { claimAchievement } from '@/scripts/achievements.js'; | ||||
| import { pleaseLogin } from '@/scripts/please-login.js'; | ||||
| import { claimAchievement } from '@/utility/achievements.js'; | ||||
| import { pleaseLogin } from '@/utility/please-login.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<{ | ||||
| 	user: Misskey.entities.UserDetailed, | ||||
| @@ -100,7 +101,7 @@ async function onClick() { | ||||
| 				userId: props.user.id, | ||||
| 			}); | ||||
| 		} else { | ||||
| 			if (defaultStore.state.alwaysConfirmFollow) { | ||||
| 			if (prefer.s.alwaysConfirmFollow) { | ||||
| 				const { canceled } = await os.confirm({ | ||||
| 					type: 'question', | ||||
| 					text: i18n.tsx.followConfirm({ name: props.user.name || props.user.username }), | ||||
| @@ -120,11 +121,11 @@ async function onClick() { | ||||
| 			} else { | ||||
| 				await misskeyApi('following/create', { | ||||
| 					userId: props.user.id, | ||||
| 					withReplies: defaultStore.state.defaultWithReplies, | ||||
| 					withReplies: store.s.defaultWithReplies, | ||||
| 				}); | ||||
| 				emit('update:user', { | ||||
| 					...props.user, | ||||
| 					withReplies: defaultStore.state.defaultWithReplies, | ||||
| 					withReplies: store.s.defaultWithReplies, | ||||
| 				}); | ||||
| 				hasPendingFollowRequestFromYou.value = true; | ||||
|  | ||||
|   | ||||
| @@ -15,8 +15,8 @@ import * as Misskey from 'misskey-js'; | ||||
| import { computed, ref } from 'vue'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import { selectFile } from '@/scripts/select-file.js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { selectFile } from '@/utility/select-file.js'; | ||||
| import { misskeyApi } from '@/utility/misskey-api.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	fileId?: string | null; | ||||
|   | ||||
| @@ -80,7 +80,7 @@ import MkRange from './MkRange.vue'; | ||||
| import MkButton from './MkButton.vue'; | ||||
| import MkRadios from './MkRadios.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 { i18n } from '@/i18n.js'; | ||||
| import { infoImageUrl } from '@/instance.js'; | ||||
|   | ||||
| @@ -35,14 +35,14 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { computed, ref } from 'vue'; | ||||
| import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	post: Misskey.entities.GalleryPost; | ||||
| }>(); | ||||
|  | ||||
| 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); | ||||
|  | ||||
| function enterHover(): void { | ||||
|   | ||||
| @@ -16,11 +16,11 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { onMounted, nextTick, watch, shallowRef, ref } from 'vue'; | ||||
| import { Chart } from 'chart.js'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { useChartTooltip } from '@/scripts/use-chart-tooltip.js'; | ||||
| import { alpha } from '@/scripts/color.js'; | ||||
| import { initChart } from '@/scripts/init-chart.js'; | ||||
| import { misskeyApi } from '@/utility/misskey-api.js'; | ||||
| import { store } from '@/store.js'; | ||||
| import { useChartTooltip } from '@/utility/use-chart-tooltip.js'; | ||||
| import { alpha } from '@/utility/color.js'; | ||||
| import { initChart } from '@/utility/init-chart.js'; | ||||
|  | ||||
| initChart(); | ||||
|  | ||||
| @@ -106,7 +106,7 @@ async function renderChart() { | ||||
|  | ||||
| 	await nextTick(); | ||||
|  | ||||
| 	const color = defaultStore.state.darkMode ? '#b4e900' : '#86b300'; | ||||
| 	const color = store.s.darkMode ? '#b4e900' : '#86b300'; | ||||
|  | ||||
| 	// 視覚上の分かりやすさのため上から最も大きい3つの値の平均を最大値とする | ||||
| 	const max = values.slice().sort((a, b) => b - a).slice(0, 3).reduce((a, b) => a + b, 0) / 3; | ||||
|   | ||||
| @@ -28,12 +28,11 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <script lang="ts" setup> | ||||
| import { ref, shallowRef, computed, nextTick, watch } from 'vue'; | ||||
| import type { Tab } from '@/components/global/MkPageHeader.tabs.vue'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { isHorizontalSwipeSwiping as isSwiping } from '@/scripts/touch.js'; | ||||
| import { isHorizontalSwipeSwiping as isSwiping } from '@/utility/touch.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const rootEl = shallowRef<HTMLDivElement>(); | ||||
|  | ||||
| // eslint-disable-next-line no-undef | ||||
| const tabModel = defineModel<string>('tab'); | ||||
|  | ||||
| const props = defineProps<{ | ||||
| @@ -44,7 +43,7 @@ const emit = defineEmits<{ | ||||
| 	(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; | ||||
|  | ||||
| function touchStart(event: TouchEvent) { | ||||
| 	if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return; | ||||
| 	if (!prefer.r.enableHorizontalSwipe.value) return; | ||||
|  | ||||
| 	if (event.touches.length !== 1) return; | ||||
|  | ||||
| @@ -83,7 +82,7 @@ function touchStart(event: TouchEvent) { | ||||
| } | ||||
|  | ||||
| function touchMove(event: TouchEvent) { | ||||
| 	if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return; | ||||
| 	if (!prefer.r.enableHorizontalSwipe.value) return; | ||||
|  | ||||
| 	if (event.touches.length !== 1) return; | ||||
|  | ||||
| @@ -134,7 +133,7 @@ function touchEnd(event: TouchEvent) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (!defaultStore.reactiveState.enableHorizontalSwipe.value) return; | ||||
| 	if (!prefer.r.enableHorizontalSwipe.value) return; | ||||
|  | ||||
| 	if (event.touches.length !== 0) return; | ||||
|  | ||||
|   | ||||
| @@ -6,13 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <template> | ||||
| <div ref="root" :class="['chromatic-ignore', $style.root, { [$style.cover]: cover }]" :title="title ?? ''"> | ||||
| 	<TransitionGroup | ||||
| 		:duration="defaultStore.state.animation && props.transition?.duration || undefined" | ||||
| 		:enterActiveClass="defaultStore.state.animation && props.transition?.enterActiveClass || undefined" | ||||
| 		:leaveActiveClass="defaultStore.state.animation && (props.transition?.leaveActiveClass ?? $style.transition_leaveActive) || undefined" | ||||
| 		:enterFromClass="defaultStore.state.animation && props.transition?.enterFromClass || undefined" | ||||
| 		:leaveToClass="defaultStore.state.animation && props.transition?.leaveToClass || undefined" | ||||
| 		:enterToClass="defaultStore.state.animation && props.transition?.enterToClass || undefined" | ||||
| 		:leaveFromClass="defaultStore.state.animation && props.transition?.leaveFromClass || undefined" | ||||
| 		:duration="prefer.s.animation && props.transition?.duration || undefined" | ||||
| 		:enterActiveClass="prefer.s.animation && props.transition?.enterActiveClass || undefined" | ||||
| 		:leaveActiveClass="prefer.s.animation && (props.transition?.leaveActiveClass ?? $style.transition_leaveActive) || undefined" | ||||
| 		:enterFromClass="prefer.s.animation && props.transition?.enterFromClass || undefined" | ||||
| 		:leaveToClass="prefer.s.animation && props.transition?.leaveToClass || undefined" | ||||
| 		:enterToClass="prefer.s.animation && props.transition?.enterToClass || 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"/> | ||||
| 		<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 { v4 as uuid } from 'uuid'; | ||||
| import { render } from 'buraha'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	transition?: { | ||||
|   | ||||
| @@ -50,8 +50,8 @@ import { debounce } from 'throttle-debounce'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import { useInterval } from '@@/js/use-interval.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { Autocomplete } from '@/scripts/autocomplete.js'; | ||||
| import type { SuggestionType } from '@/scripts/autocomplete.js'; | ||||
| import { Autocomplete } from '@/utility/autocomplete.js'; | ||||
| import type { SuggestionType } from '@/utility/autocomplete.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	modelValue: string | number | null; | ||||
|   | ||||
| @@ -18,8 +18,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { ref } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import MkMiniChart from '@/components/MkMiniChart.vue'; | ||||
| import { misskeyApiGet } from '@/scripts/misskey-api.js'; | ||||
| import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js'; | ||||
| import { misskeyApiGet } from '@/utility/misskey-api.js'; | ||||
| import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	instance: Misskey.entities.FederationInstance; | ||||
|   | ||||
| @@ -88,10 +88,10 @@ import { onMounted, ref, computed, shallowRef } from 'vue'; | ||||
| import { Chart } from 'chart.js'; | ||||
| import MkSelect from '@/components/MkSelect.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 * 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 { i18n } from '@/i18n.js'; | ||||
| import MkHeatmap from '@/components/MkHeatmap.vue'; | ||||
| @@ -99,7 +99,7 @@ import type { HeatmapSource } from '@/components/MkHeatmap.vue'; | ||||
| import MkFoldableSection from '@/components/MkFoldableSection.vue'; | ||||
| import MkRetentionHeatmap from '@/components/MkRetentionHeatmap.vue'; | ||||
| import MkRetentionLineChart from '@/components/MkRetentionLineChart.vue'; | ||||
| import { initChart } from '@/scripts/init-chart.js'; | ||||
| import { initChart } from '@/utility/init-chart.js'; | ||||
|  | ||||
| initChart(); | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,7 @@ import { computed } from 'vue'; | ||||
| import type { CSSProperties } from 'vue'; | ||||
| import { instanceName as localInstanceName } from '@@/js/config.js'; | ||||
| import { instance as localInstance } from '@/instance.js'; | ||||
| import { getProxiedImageUrlNullable } from '@/scripts/media-proxy.js'; | ||||
| import { getProxiedImageUrlNullable } from '@/utility/media-proxy.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	host: string | null; | ||||
|   | ||||
| @@ -64,7 +64,7 @@ import { computed } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; | ||||
| import { copyToClipboard } from '@/utility/copy-to-clipboard.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import * as os from '@/os.js'; | ||||
|  | ||||
|   | ||||
| @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { } from 'vue'; | ||||
| import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; | ||||
| import { copyToClipboard } from '@/utility/copy-to-clipboard.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
|  | ||||
|   | ||||
| @@ -30,8 +30,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { shallowRef } from 'vue'; | ||||
| import MkModal from '@/components/MkModal.vue'; | ||||
| import { navbarItemDef } from '@/navbar.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { deviceKind } from '@/scripts/device-kind.js'; | ||||
| import { deviceKind } from '@/utility/device-kind.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	src?: HTMLElement; | ||||
| @@ -50,7 +50,7 @@ const preferedModalType = (deviceKind === 'desktop' && props.src != null) ? 'pop | ||||
|  | ||||
| const modal = shallowRef<InstanceType<typeof MkModal>>(); | ||||
|  | ||||
| const menu = defaultStore.state.menu; | ||||
| const menu = prefer.s.menu; | ||||
|  | ||||
| const items = Object.keys(navbarItemDef).filter(k => !menu.includes(k)).map(k => navbarItemDef[k]).filter(def => def.show == null ? true : def.show).map(def => ({ | ||||
| 	type: def.to ? 'link' : 'button', | ||||
|   | ||||
| @@ -17,7 +17,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <script lang="ts" setup> | ||||
| import { defineAsyncComponent, ref } from 'vue'; | ||||
| import { url as local } from '@@/js/config.js'; | ||||
| import { useTooltip } from '@/scripts/use-tooltip.js'; | ||||
| import { useTooltip } from '@/utility/use-tooltip.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { isEnabledUrlPreview } from '@/instance.js'; | ||||
| import type { MkABehavior } from '@/components/global/MkA.vue'; | ||||
|   | ||||
| @@ -10,20 +10,20 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	tabindex="0" | ||||
| 	:class="[ | ||||
| 		$style.audioContainer, | ||||
| 		(audio.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive, | ||||
| 		(audio.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive, | ||||
| 	]" | ||||
| 	@contextmenu.stop | ||||
| 	@keydown.stop | ||||
| > | ||||
| 	<button v-if="hide" :class="$style.hidden" @click="show"> | ||||
| 		<div :class="$style.hiddenTextWrapper"> | ||||
| 			<b v-if="audio.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.audio}${audio.size ? ' ' + bytes(audio.size) : ''})` : '' }}</b> | ||||
| 			<b v-else style="display: block;"><i class="ti ti-music"></i> {{ defaultStore.state.dataSaver.media && audio.size ? bytes(audio.size) : i18n.ts.audio }}</b> | ||||
| 			<b v-if="audio.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ prefer.s.dataSaver.media ? ` (${i18n.ts.audio}${audio.size ? ' ' + bytes(audio.size) : ''})` : '' }}</b> | ||||
| 			<b v-else style="display: block;"><i class="ti ti-music"></i> {{ prefer.s.dataSaver.media && audio.size ? bytes(audio.size) : i18n.ts.audio }}</b> | ||||
| 			<span style="display: block;">{{ i18n.ts.clickToShow }}</span> | ||||
| 		</div> | ||||
| 	</button> | ||||
|  | ||||
| 	<div v-else-if="defaultStore.reactiveState.useNativeUIForVideoAudioPlayer.value" :class="$style.nativeAudioContainer"> | ||||
| 	<div v-else-if="prefer.s.useNativeUiForVideoAudioPlayer" :class="$style.nativeAudioContainer"> | ||||
| 		<audio | ||||
| 			ref="audioEl" | ||||
| 			preload="metadata" | ||||
| @@ -91,15 +91,15 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { shallowRef, watch, computed, ref, onDeactivated, onActivated, onMounted } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import type { MenuItem } from '@/types/menu.js'; | ||||
| import type { Keymap } from '@/scripts/hotkey.js'; | ||||
| import { copyToClipboard } from '@/scripts/copy-to-clipboard'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import type { Keymap } from '@/utility/hotkey.js'; | ||||
| import { copyToClipboard } from '@/utility/copy-to-clipboard'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import bytes from '@/filters/bytes.js'; | ||||
| import { hms } from '@/filters/hms.js'; | ||||
| import MkMediaRange from '@/components/MkMediaRange.vue'; | ||||
| import { $i, iAmModerator } from '@/account.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	audio: Misskey.entities.DriveFile; | ||||
| @@ -155,10 +155,10 @@ const playerEl = shallowRef<HTMLDivElement>(); | ||||
| const audioEl = shallowRef<HTMLAudioElement>(); | ||||
|  | ||||
| // eslint-disable-next-line vue/no-setup-props-reactivity-loss | ||||
| const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore')); | ||||
| const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.audio.isSensitive && prefer.s.nsfw !== 'ignore')); | ||||
|  | ||||
| async function show() { | ||||
| 	if (props.audio.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 	if (props.audio.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) { | ||||
| 		const { canceled } = await os.confirm({ | ||||
| 			type: 'question', | ||||
| 			text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
| @@ -240,7 +240,7 @@ function showMenu(ev: MouseEvent) { | ||||
| 		menu.push({ type: 'divider' }, ...details); | ||||
| 	} | ||||
|  | ||||
| 	if (defaultStore.state.devMode) { | ||||
| 	if (prefer.s.devMode) { | ||||
| 		menu.push({ type: 'divider' }, { | ||||
| 			icon: 'ti ti-id', | ||||
| 			text: i18n.ts.copyFileId, | ||||
| @@ -407,7 +407,7 @@ onDeactivated(() => { | ||||
| 	elapsedTimeMs.value = 0; | ||||
| 	durationMs.value = 0; | ||||
| 	bufferedEnd.value = 0; | ||||
| 	hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore'); | ||||
| 	hide.value = (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.audio.isSensitive && prefer.s.nsfw !== 'ignore'); | ||||
| 	stopAudioElWatch(); | ||||
| 	onceInit = false; | ||||
| 	if (mediaTickFrameId) { | ||||
|   | ||||
| @@ -27,9 +27,9 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { ref } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import MkMediaAudio from '@/components/MkMediaAudio.vue'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	media: Misskey.entities.DriveFile; | ||||
| @@ -38,7 +38,7 @@ const props = defineProps<{ | ||||
| const hide = ref(true); | ||||
|  | ||||
| async function show() { | ||||
| 	if (props.media.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 	if (props.media.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) { | ||||
| 		const { canceled } = await os.confirm({ | ||||
| 			type: 'question', | ||||
| 			text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
|   | ||||
| @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| --> | ||||
|  | ||||
| <template> | ||||
| <div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive]" @click="onclick"> | ||||
| <div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive]" @click="onclick"> | ||||
| 	<component | ||||
| 		:is="disableImageLink ? 'div' : 'a'" | ||||
| 		v-bind="disableImageLink ? { | ||||
| @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	> | ||||
| 		<ImgWithBlurhash | ||||
| 			:hash="image.blurhash" | ||||
| 			:src="(defaultStore.state.dataSaver.media && hide) ? null : url" | ||||
| 			:src="(prefer.s.dataSaver.media && hide) ? null : url" | ||||
| 			:forceBlurhash="hide" | ||||
| 			:cover="hide || cover" | ||||
| 			:alt="image.comment || image.name" | ||||
| @@ -32,8 +32,8 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	<template v-if="hide"> | ||||
| 		<div :class="$style.hiddenText"> | ||||
| 			<div :class="$style.hiddenTextWrapper"> | ||||
| 				<b v-if="image.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }}</b> | ||||
| 				<b v-else style="display: block;"><i class="ti ti-photo"></i> {{ defaultStore.state.dataSaver.media && image.size ? bytes(image.size) : i18n.ts.image }}</b> | ||||
| 				<b v-if="image.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ prefer.s.dataSaver.media ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }}</b> | ||||
| 				<b v-else style="display: block;"><i class="ti ti-photo"></i> {{ prefer.s.dataSaver.media && image.size ? bytes(image.size) : i18n.ts.image }}</b> | ||||
| 				<span v-if="controls" style="display: block;">{{ i18n.ts.clickToShow }}</span> | ||||
| 			</div> | ||||
| 		</div> | ||||
| @@ -54,14 +54,14 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { watch, ref, computed } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import type { MenuItem } from '@/types/menu.js'; | ||||
| import { copyToClipboard } from '@/scripts/copy-to-clipboard'; | ||||
| import { getStaticImageUrl } from '@/scripts/media-proxy.js'; | ||||
| import { copyToClipboard } from '@/utility/copy-to-clipboard'; | ||||
| import { getStaticImageUrl } from '@/utility/media-proxy.js'; | ||||
| import bytes from '@/filters/bytes.js'; | ||||
| import ImgWithBlurhash from '@/components/MkImgWithBlurhash.vue'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { $i, iAmModerator } from '@/account.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| 	image: Misskey.entities.DriveFile; | ||||
| @@ -77,9 +77,9 @@ const props = withDefaults(defineProps<{ | ||||
|  | ||||
| const hide = ref(true); | ||||
|  | ||||
| const url = computed(() => (props.raw || defaultStore.state.loadRawImages) | ||||
| const url = computed(() => (props.raw || prefer.s.loadRawImages) | ||||
| 	? props.image.url | ||||
| 	: defaultStore.state.disableShowingAnimatedImages | ||||
| 	: prefer.s.disableShowingAnimatedImages | ||||
| 		? getStaticImageUrl(props.image.url) | ||||
| 		: props.image.thumbnailUrl, | ||||
| ); | ||||
| @@ -91,7 +91,7 @@ async function onclick(ev: MouseEvent) { | ||||
|  | ||||
| 	if (hide.value) { | ||||
| 		ev.stopPropagation(); | ||||
| 		if (props.image.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 		if (props.image.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) { | ||||
| 			const { canceled } = await os.confirm({ | ||||
| 				type: 'question', | ||||
| 				text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
| @@ -105,7 +105,7 @@ async function onclick(ev: MouseEvent) { | ||||
|  | ||||
| // Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする | ||||
| watch(() => props.image, () => { | ||||
| 	hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.image.isSensitive && defaultStore.state.nsfw !== 'ignore'); | ||||
| 	hide.value = (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.image.isSensitive && prefer.s.nsfw !== 'ignore'); | ||||
| }, { | ||||
| 	deep: true, | ||||
| 	immediate: true, | ||||
| @@ -166,7 +166,7 @@ function showMenu(ev: MouseEvent) { | ||||
| 		menuItems.push({ type: 'divider' }, ...details); | ||||
| 	} | ||||
|  | ||||
| 	if (defaultStore.state.devMode) { | ||||
| 	if (prefer.s.devMode) { | ||||
| 		menuItems.push({ type: 'divider' }, { | ||||
| 			icon: 'ti ti-id', | ||||
| 			text: i18n.ts.copyFileId, | ||||
|   | ||||
| @@ -12,9 +12,9 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 			:class="[ | ||||
| 				$style.medias, | ||||
| 				count === 1 ? [$style.n1, { | ||||
| 					[$style.n116_9]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '16_9', | ||||
| 					[$style.n11_1]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '1_1', | ||||
| 					[$style.n12_3]: defaultStore.reactiveState.mediaListWithOneImageAppearance.value === '2_3', | ||||
| 					[$style.n116_9]: prefer.s.mediaListWithOneImageAppearance === '16_9', | ||||
| 					[$style.n11_1]: prefer.s.mediaListWithOneImageAppearance === '1_1', | ||||
| 					[$style.n12_3]: prefer.s.mediaListWithOneImageAppearance === '2_3', | ||||
| 				}] : count === 2 ? $style.n2 : count === 3 ? $style.n3 : count === 4 ? $style.n4 : $style.nMany, | ||||
| 			]" | ||||
| 		> | ||||
| @@ -33,13 +33,13 @@ import * as Misskey from 'misskey-js'; | ||||
| import PhotoSwipeLightbox from 'photoswipe/lightbox'; | ||||
| import PhotoSwipe from 'photoswipe'; | ||||
| import 'photoswipe/style.css'; | ||||
| import { FILE_TYPE_BROWSERSAFE } from '@@/js/const.js'; | ||||
| import XBanner from '@/components/MkMediaBanner.vue'; | ||||
| import XImage from '@/components/MkMediaImage.vue'; | ||||
| import XVideo from '@/components/MkMediaVideo.vue'; | ||||
| import * as os from '@/os.js'; | ||||
| import { FILE_TYPE_BROWSERSAFE } from '@@/js/const.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { focusParent } from '@/scripts/focus.js'; | ||||
| import { focusParent } from '@/utility/focus.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	mediaList: Misskey.entities.DriveFile[]; | ||||
| @@ -75,7 +75,7 @@ async function calcAspectRatio() { | ||||
| 		return `${Math.max(ratio, img.properties.width / img.properties.height).toString()} / 1`; | ||||
| 	}; | ||||
|  | ||||
| 	switch (defaultStore.state.mediaListWithOneImageAppearance) { | ||||
| 	switch (prefer.s.mediaListWithOneImageAppearance) { | ||||
| 		case '16_9': | ||||
| 			gallery.value.style.aspectRatio = ratioMax(16 / 9); | ||||
| 			break; | ||||
|   | ||||
| @@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	:class="[ | ||||
| 		$style.videoContainer, | ||||
| 		controlsShowing && $style.active, | ||||
| 		(video.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive, | ||||
| 		(video.isSensitive && prefer.s.highlightSensitiveMedia) && $style.sensitive, | ||||
| 	]" | ||||
| 	@mouseover="onMouseOver" | ||||
| 	@mouseleave="onMouseLeave" | ||||
| @@ -20,13 +20,13 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| > | ||||
| 	<button v-if="hide" :class="$style.hidden" @click="show"> | ||||
| 		<div :class="$style.hiddenTextWrapper"> | ||||
| 			<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b> | ||||
| 			<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ defaultStore.state.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b> | ||||
| 			<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ prefer.s.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b> | ||||
| 			<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ prefer.s.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b> | ||||
| 			<span style="display: block;">{{ i18n.ts.clickToShow }}</span> | ||||
| 		</div> | ||||
| 	</button> | ||||
|  | ||||
| 	<div v-else-if="defaultStore.reactiveState.useNativeUIForVideoAudioPlayer.value" :class="$style.videoRoot"> | ||||
| 	<div v-else-if="prefer.s.useNativeUiForVideoAudioPlayer" :class="$style.videoRoot"> | ||||
| 		<video | ||||
| 			ref="videoEl" | ||||
| 			:class="$style.video" | ||||
| @@ -112,17 +112,17 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| import { ref, shallowRef, computed, watch, onDeactivated, onActivated, onMounted } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import type { MenuItem } from '@/types/menu.js'; | ||||
| import type { Keymap } from '@/scripts/hotkey.js'; | ||||
| import { copyToClipboard } from '@/scripts/copy-to-clipboard'; | ||||
| import type { Keymap } from '@/utility/hotkey.js'; | ||||
| import { copyToClipboard } from '@/utility/copy-to-clipboard'; | ||||
| import bytes from '@/filters/bytes.js'; | ||||
| import { hms } from '@/filters/hms.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { exitFullscreen, requestFullscreen } from '@/scripts/fullscreen.js'; | ||||
| import hasAudio from '@/scripts/media-has-audio.js'; | ||||
| import { exitFullscreen, requestFullscreen } from '@/utility/fullscreen.js'; | ||||
| import hasAudio from '@/utility/media-has-audio.js'; | ||||
| import MkMediaRange from '@/components/MkMediaRange.vue'; | ||||
| import { $i, iAmModerator } from '@/account.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	video: Misskey.entities.DriveFile; | ||||
| @@ -175,10 +175,10 @@ function hasFocus() { | ||||
| } | ||||
|  | ||||
| // eslint-disable-next-line vue/no-setup-props-reactivity-loss | ||||
| const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore')); | ||||
| const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.video.isSensitive && prefer.s.nsfw !== 'ignore')); | ||||
|  | ||||
| async function show() { | ||||
| 	if (props.video.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 	if (props.video.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) { | ||||
| 		const { canceled } = await os.confirm({ | ||||
| 			type: 'question', | ||||
| 			text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
| @@ -265,7 +265,7 @@ function showMenu(ev: MouseEvent) { | ||||
| 		menu.push({ type: 'divider' }, ...details); | ||||
| 	} | ||||
|  | ||||
| 	if (defaultStore.state.devMode) { | ||||
| 	if (prefer.s.devMode) { | ||||
| 		menu.push({ type: 'divider' }, { | ||||
| 			icon: 'ti ti-id', | ||||
| 			text: i18n.ts.copyFileId, | ||||
| @@ -502,7 +502,7 @@ onDeactivated(() => { | ||||
| 	elapsedTimeMs.value = 0; | ||||
| 	durationMs.value = 0; | ||||
| 	bufferedEnd.value = 0; | ||||
| 	hide.value = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore'); | ||||
| 	hide.value = (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.video.isSensitive && prefer.s.nsfw !== 'ignore'); | ||||
| 	stopVideoElWatch(); | ||||
| 	onceInit = false; | ||||
| 	if (mediaTickFrameId) { | ||||
|   | ||||
| @@ -19,8 +19,8 @@ import { computed } from 'vue'; | ||||
| import { host as localHost } from '@@/js/config.js'; | ||||
| import type { MkABehavior } from '@/components/global/MkA.vue'; | ||||
| import { $i } from '@/account.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import { getStaticImageUrl } from '@/scripts/media-proxy.js'; | ||||
| import { getStaticImageUrl } from '@/utility/media-proxy.js'; | ||||
| import { prefer } from '@/preferences.js'; | ||||
|  | ||||
| const props = defineProps<{ | ||||
| 	username: string; | ||||
| @@ -36,7 +36,7 @@ const isMe = $i && ( | ||||
| 	`@${props.username}@${toUnicode(props.host)}` === `@${$i.username}@${toUnicode(localHost)}`.toLowerCase() | ||||
| ); | ||||
|  | ||||
| const avatarUrl = computed(() => defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar | ||||
| const avatarUrl = computed(() => prefer.s.disableShowingAnimatedImages || prefer.s.dataSaver.avatar | ||||
| 	? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`) | ||||
| 	: `/avatar/@${props.username}@${props.host}`, | ||||
| ); | ||||
|   | ||||
| @@ -181,10 +181,10 @@ import MkSwitchButton from '@/components/MkSwitch.button.vue'; | ||||
| import type { MenuItem, InnerMenuItem, MenuPending, MenuAction, MenuSwitch, MenuRadio, MenuRadioOption, MenuParent } from '@/types/menu.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { isTouchUsing } from '@/scripts/touch.js'; | ||||
| import type { Keymap } from '@/scripts/hotkey.js'; | ||||
| import { isFocusable } from '@/scripts/focus.js'; | ||||
| import { getNodeOrNull } from '@/scripts/get-dom-node-or-null.js'; | ||||
| import { isTouchUsing } from '@/utility/touch.js'; | ||||
| import type { Keymap } from '@/utility/hotkey.js'; | ||||
| import { isFocusable } from '@/utility/focus.js'; | ||||
| import { getNodeOrNull } from '@/utility/get-dom-node-or-null.js'; | ||||
|  | ||||
| const childrenCache = new WeakMap<MenuParent, MenuItem[]>(); | ||||
| </script> | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user