From 42b2aea53364c57c39ebb953359ece4b7b0017a5 Mon Sep 17 00:00:00 2001 From: tamaina Date: Fri, 19 Sep 2025 21:02:30 +0900 Subject: [PATCH] =?UTF-8?q?feat(frontend):=20=E8=87=AA=E5=88=86=E3=81=AE?= =?UTF-8?q?=E3=83=97=E3=83=AD=E3=83=95=E3=82=A3=E3=83=BC=E3=83=AB=E3=83=9A?= =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=81=AE=E4=BA=8C=E6=AC=A1=E5=85=83=E3=82=B3?= =?UTF-8?q?=E3=83=BC=E3=83=89(QR=E3=82=B3=E3=83=BC=E3=83=89)=E3=82=92?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=97=E3=80=81=E4=BB=96=E3=81=AE=E4=BA=BA?= =?UTF-8?q?=E3=81=AE=E3=82=B3=E3=83=BC=E3=83=89=E3=82=92=E8=AA=AD=E3=81=BF?= =?UTF-8?q?=E5=8F=96=E3=82=8A=E3=81=99=E3=82=8B=E3=83=9A=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=82=92=E8=BF=BD=E5=8A=A0=20(#16456)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip (qr.show.vue) * added to navbar * qr.show.vue * fix * added to navbar * fix size * :art: * :art: * fix div warn * fix * use * 0.25 * fix?? * fix lint * clean up * ??? * ? * fix * :art: * :art: * refactor * :art: * :art: * :ar:t * :art: * iphone flip * no lazy import * :art: * :art: * :art: * ユーザー全部flipでいいや * :v: * fix * fix * fix lint * :art: * fix type * fix: local user profile url cannot be resolved with ap/show * fix: local user url with hostname could not be resolved * chore: use common utility for checking self host * wip * :art: * :art: * fix imports * fix * fix * fix * :art: * fix... * set spacer-w * :v: * 全画面でQRを読むように * fix * :art: * modify navbar.ts * start/stop on vue activation * display raw content read from qr * 端末のQRをスキャンするボタンを追加 * chore * やっぱりmfmを先に表示する * :art: * fix 18n * QRの内容は/users/:userIdにする * add spdx * use cqh * `defineProps` is a compiler macro and no longer needs to be imported. * use MkUserName * 🎨 * 🎨 * refactor * clean up * refactor * 🎨 * Update qr.show.vue * Misskeyロゴにdrop-shadowを追加 * clean up: do not use empty css * fix os.select usage * Update qr.vue * Update qr.show.vue * Update qr.show.vue * Update get-user-menu.ts * ✌️ * Update show.ts * Update ja-JP.yml * watermark * Update CHANGELOG.md * Update qr.read.vue * Update qr.read.vue * wip * Update MkWatermarkEditorDialog.Layer.vue --------- Co-authored-by: anatawa12 Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com> --- CHANGELOG.md | 2 + locales/index.d.ts | 74 ++++ locales/ja-JP.yml | 20 + .../src/server/api/endpoints/ap/show.ts | 2 +- packages/frontend/package.json | 2 + .../frontend/src/components/MkPolkadots.vue | 15 +- .../src/components/MkPositionSelector.vue | 18 +- .../MkWatermarkEditorDialog.Layer.vue | 73 ++++ .../components/MkWatermarkEditorDialog.vue | 58 +-- packages/frontend/src/navbar.ts | 6 + packages/frontend/src/pages/chat/home.vue | 2 +- .../frontend/src/pages/qr.read.raw-viewer.vue | 54 +++ packages/frontend/src/pages/qr.read.vue | 397 ++++++++++++++++++ packages/frontend/src/pages/qr.show.vue | 234 +++++++++++ packages/frontend/src/pages/qr.vue | 57 +++ .../frontend/src/pages/settings/drive.vue | 2 +- .../frontend/src/pages/settings/profile.vue | 10 + packages/frontend/src/router.definition.ts | 4 + .../frontend/src/utility/get-user-menu.ts | 10 + .../utility/image-effector/ImageEffector.ts | 75 +++- .../image-effector/fxs/watermarkPlacement.ts | 9 +- packages/frontend/src/utility/watermark.ts | 34 +- pnpm-lock.yaml | 26 ++ 23 files changed, 1122 insertions(+), 62 deletions(-) create mode 100644 packages/frontend/src/pages/qr.read.raw-viewer.vue create mode 100644 packages/frontend/src/pages/qr.read.vue create mode 100644 packages/frontend/src/pages/qr.show.vue create mode 100644 packages/frontend/src/pages/qr.vue diff --git a/CHANGELOG.md b/CHANGELOG.md index adeb453795..e841ea2791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,10 @@ - Enhance: 広告ごとにセンシティブフラグを設定できるようになりました ### Client +- Feat: アカウントのQRコードを表示・読み取りできるようになりました - Enhance: チャットの日本語名称がダイレクトメッセージに戻るとともに、ベータ版機能ではなくなりました - Enhance: 画像編集にマスクエフェクトを追加 +- Enhance: ウォーターマークにアカウントのQRコードを追加できるように - Enhance: 時刻計算のための基準値を一か所で管理するようにし、パフォーマンスを向上 - Fix: iOSで、デバイスがダークモードだと初回読み込み時にエラーになる問題を修正 diff --git a/locales/index.d.ts b/locales/index.d.ts index ee808bfa77..95886125ff 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12235,10 +12235,18 @@ export interface Locale extends ILocale { * テキスト */ "text": string; + /** + * 二次元コード + */ + "qr": string; /** * 位置 */ "position": string; + /** + * マージン + */ + "margin": string; /** * タイプ */ @@ -12295,6 +12303,10 @@ export interface Locale extends ILocale { * サブドットの数 */ "polkadotSubDotDivisions": string; + /** + * 空欄にするとアカウントのURLになります + */ + "leaveBlankToAccountUrl": string; }; "_imageEffector": { /** @@ -12572,6 +12584,68 @@ export interface Locale extends ILocale { */ "listDrafts": string; }; + /** + * 二次元コード + */ + "qr": string; + "_qr": { + /** + * 表示 + */ + "showTabTitle": string; + /** + * 読み取る + */ + "readTabTitle": string; + /** + * {name} {acct} + */ + "shareTitle": ParameterizedString<"name" | "acct">; + /** + * Fediverseで私をフォローしてください! + */ + "shareText": string; + /** + * カメラを選択 + */ + "chooseCamera": string; + /** + * ライト選択不可 + */ + "cannotToggleFlash": string; + /** + * ライトをオンにする + */ + "turnOnFlash": string; + /** + * ライトをオフにする + */ + "turnOffFlash": string; + /** + * コードリーダーを再開 + */ + "startQr": string; + /** + * コードリーダーを停止 + */ + "stopQr": string; + /** + * QRコードが見つかりません + */ + "noQrCodeFound": string; + /** + * 端末の画像をスキャン + */ + "scanFile": string; + /** + * テキスト + */ + "raw": string; + /** + * MFM + */ + "mfm": string; + }; } declare const locales: { [lang: string]: Locale; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 322ff3ab2f..4ae52990e5 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -3275,7 +3275,9 @@ _watermarkEditor: opacity: "不透明度" scale: "サイズ" text: "テキスト" + qr: "二次元コード" position: "位置" + margin: "マージン" type: "タイプ" image: "画像" advanced: "高度" @@ -3290,6 +3292,7 @@ _watermarkEditor: polkadotSubDotOpacity: "サブドットの不透明度" polkadotSubDotRadius: "サブドットの大きさ" polkadotSubDotDivisions: "サブドットの数" + leaveBlankToAccountUrl: "空欄にするとアカウントのURLになります" _imageEffector: title: "エフェクト" @@ -3365,3 +3368,20 @@ _drafts: restoreFromDraft: "下書きから復元" restore: "復元" listDrafts: "下書き一覧" + +qr: "二次元コード" +_qr: + showTabTitle: "表示" + readTabTitle: "読み取る" + shareTitle: "{name} {acct}" + shareText: "Fediverseで私をフォローしてください!" + chooseCamera: "カメラを選択" + cannotToggleFlash: "ライト選択不可" + turnOnFlash: "ライトをオンにする" + turnOffFlash: "ライトをオフにする" + startQr: "コードリーダーを再開" + stopQr: "コードリーダーを停止" + noQrCodeFound: "QRコードが見つかりません" + scanFile: "端末の画像をスキャン" + raw: "テキスト" + mfm: "MFM" diff --git a/packages/backend/src/server/api/endpoints/ap/show.ts b/packages/backend/src/server/api/endpoints/ap/show.ts index 4afed7dc5c..fe48e7497a 100644 --- a/packages/backend/src/server/api/endpoints/ap/show.ts +++ b/packages/backend/src/server/api/endpoints/ap/show.ts @@ -18,9 +18,9 @@ import { UserEntityService } from '@/core/entities/UserEntityService.js'; import { NoteEntityService } from '@/core/entities/NoteEntityService.js'; import { UtilityService } from '@/core/UtilityService.js'; import { bindThis } from '@/decorators.js'; -import { ApiError } from '../../error.js'; import { IdentifiableError } from '@/misc/identifiable-error.js'; import { FetchAllowSoftFailMask } from '@/core/activitypub/misc/check-against-url.js'; +import { ApiError } from '../../error.js'; export const meta = { tags: ['federation'], diff --git a/packages/frontend/package.json b/packages/frontend/package.json index f207d04b96..bacdc7b133 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -63,6 +63,8 @@ "misskey-reversi": "workspace:*", "photoswipe": "5.4.4", "punycode.js": "2.3.1", + "qr-code-styling": "1.9.2", + "qr-scanner": "1.4.2", "rollup": "4.50.1", "sanitize-html": "2.17.0", "sass": "1.92.1", diff --git a/packages/frontend/src/components/MkPolkadots.vue b/packages/frontend/src/components/MkPolkadots.vue index 285c4d0b79..4f1346b685 100644 --- a/packages/frontend/src/components/MkPolkadots.vue +++ b/packages/frontend/src/components/MkPolkadots.vue @@ -4,14 +4,18 @@ SPDX-License-Identifier: AGPL-3.0-only --> @@ -27,14 +31,17 @@ const props = withDefaults(defineProps<{ --dot-size: 2px; --gap-size: 40px; --offset: calc(var(--gap-size) / 2); + --height: v-bind('props.height + "px"'); - height: 200px; - margin-bottom: -200px; - + height: var(--height); background-image: linear-gradient(transparent 60%, transparent 100%), radial-gradient(var(--c) var(--dot-size), transparent var(--dot-size)), radial-gradient(var(--c) var(--dot-size), transparent var(--dot-size)); background-position: 0 0, 0 0, var(--offset) var(--offset); background-size: 100% 100%, var(--gap-size) var(--gap-size), var(--gap-size) var(--gap-size); mask-image: linear-gradient(to bottom, black 0%, transparent 100%); pointer-events: none; + + &.revered { + mask-image: linear-gradient(to top, black 0%, transparent 100%); + } } diff --git a/packages/frontend/src/components/MkPositionSelector.vue b/packages/frontend/src/components/MkPositionSelector.vue index 739f55125b..6f12aada30 100644 --- a/packages/frontend/src/components/MkPositionSelector.vue +++ b/packages/frontend/src/components/MkPositionSelector.vue @@ -6,15 +6,15 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue b/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue index 11ae091d90..288293db3f 100644 --- a/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue +++ b/packages/frontend/src/components/MkWatermarkEditorDialog.Layer.vue @@ -18,6 +18,18 @@ SPDX-License-Identifier: AGPL-3.0-only > + + + + + + + + + +