From 32b21b1186fad6489d832ed1721cde7685c04fa5 Mon Sep 17 00:00:00 2001 From: tamaina Date: Mon, 25 Aug 2025 07:23:43 +0900 Subject: [PATCH 01/85] wip (qr.show.vue) --- locales/index.d.ts | 14 ++ locales/ja-JP.yml | 5 + packages/frontend/package.json | 1 + .../directives/flip-on-device-orientation.ts | 44 +++++ packages/frontend/src/directives/index.ts | 2 + packages/frontend/src/pages/qr.read.vue | 21 ++ packages/frontend/src/pages/qr.show.vue | 179 ++++++++++++++++++ packages/frontend/src/pages/qr.vue | 44 +++++ packages/frontend/src/router.definition.ts | 4 + pnpm-lock.yaml | 16 ++ 10 files changed, 330 insertions(+) create mode 100644 packages/frontend/src/directives/flip-on-device-orientation.ts 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/locales/index.d.ts b/locales/index.d.ts index c31a3f4e83..2040d55628 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12548,6 +12548,20 @@ export interface Locale extends ILocale { */ "listDrafts": string; }; + /** + * 二次元コード + */ + "qr": string; + "_qr": { + /** + * 表示 + */ + "showTabTitle": string; + /** + * 読み取る + */ + "readTabTitle": string; + }; } declare const locales: { [lang: string]: Locale; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 522f53ce4d..cf26446a4d 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -3359,3 +3359,8 @@ _drafts: restoreFromDraft: "下書きから復元" restore: "復元" listDrafts: "下書き一覧" + +qr: 二次元コード +_qr: + showTabTitle: "表示" + readTabTitle: "読み取る" diff --git a/packages/frontend/package.json b/packages/frontend/package.json index 952af75d97..682429baad 100644 --- a/packages/frontend/package.json +++ b/packages/frontend/package.json @@ -63,6 +63,7 @@ "misskey-reversi": "workspace:*", "photoswipe": "5.4.4", "punycode.js": "2.3.1", + "qr-code-styling": "1.9.2", "rollup": "4.48.0", "sanitize-html": "2.17.0", "sass": "1.90.0", diff --git a/packages/frontend/src/directives/flip-on-device-orientation.ts b/packages/frontend/src/directives/flip-on-device-orientation.ts new file mode 100644 index 0000000000..767d42a480 --- /dev/null +++ b/packages/frontend/src/directives/flip-on-device-orientation.ts @@ -0,0 +1,44 @@ +import type { Directive } from 'vue'; + +let initialized = false; +let styleEl: HTMLStyleElement | null = null; +const elements = new Set(); +const className = '_flipOnDeviceOrientation'; +const variableName = `--flip_on_device_orientation_transform`; + +function handleOrientationChange() { + const isUpsideDown = window.screen.orientation.type === 'landscape-secondary'; + const transform = isUpsideDown ? 'scale(-1, -1)' : ''; + window.document.body.style.setProperty(variableName, transform); +} + +function registerListener() { + if (!initialized) { + screen.orientation.addEventListener('change', handleOrientationChange); + if (!styleEl) { + styleEl = window.document.createElement('style'); + styleEl.textContent = `.${className} { transform: var(${variableName}); }`; + window.document.head.appendChild(styleEl); + } + initialized = true; + } else if (window.document.getElementsByClassName(className).length === 0) { + screen.orientation.removeEventListener('change', handleOrientationChange); + if (styleEl) { + window.document.head.removeChild(styleEl); + styleEl = null; + } + initialized = false; + } +} + +export default { + mounted(el) { + registerListener(); + el.classList.add(className); + handleOrientationChange(); + }, + unmounted(el) { + el.classList.remove(className); + registerListener(); + }, +} as Directive; diff --git a/packages/frontend/src/directives/index.ts b/packages/frontend/src/directives/index.ts index 9555045afe..c6948d8c06 100644 --- a/packages/frontend/src/directives/index.ts +++ b/packages/frontend/src/directives/index.ts @@ -16,6 +16,7 @@ import clickAnime from './click-anime.js'; import panel from './panel.js'; import adaptiveBorder from './adaptive-border.js'; import adaptiveBg from './adaptive-bg.js'; +import flipOnDeviceOrientation from './flip-on-device-orientation.js'; export default function(app: App) { for (const [key, value] of Object.entries(directives)) { @@ -36,4 +37,5 @@ export const directives = { 'panel': panel, 'adaptive-border': adaptiveBorder, 'adaptive-bg': adaptiveBg, + 'flip-on-device-orientation': flipOnDeviceOrientation, }; diff --git a/packages/frontend/src/pages/qr.read.vue b/packages/frontend/src/pages/qr.read.vue new file mode 100644 index 0000000000..5cf8c6dee1 --- /dev/null +++ b/packages/frontend/src/pages/qr.read.vue @@ -0,0 +1,21 @@ + + + + + + + diff --git a/packages/frontend/src/pages/qr.show.vue b/packages/frontend/src/pages/qr.show.vue new file mode 100644 index 0000000000..75544c0ce1 --- /dev/null +++ b/packages/frontend/src/pages/qr.show.vue @@ -0,0 +1,179 @@ + + + + + + + diff --git a/packages/frontend/src/pages/qr.vue b/packages/frontend/src/pages/qr.vue new file mode 100644 index 0000000000..123534ac2b --- /dev/null +++ b/packages/frontend/src/pages/qr.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/packages/frontend/src/router.definition.ts b/packages/frontend/src/router.definition.ts index e25e0fe161..d59c9d1c6f 100644 --- a/packages/frontend/src/router.definition.ts +++ b/packages/frontend/src/router.definition.ts @@ -590,6 +590,10 @@ export const ROUTE_DEF = [{ path: '/reversi/g/:gameId', component: page(() => import('@/pages/reversi/game.vue')), loginRequired: false, +}, { + path: '/qr', + component: page(() => import('@/pages/qr.vue')), + loginRequired: true, }, { path: '/debug', component: page(() => import('@/pages/debug.vue')), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 66f42b70e3..40c660ce0a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -844,6 +844,9 @@ importers: punycode.js: specifier: 2.3.1 version: 2.3.1 + qr-code-styling: + specifier: 1.9.2 + version: 1.9.2 rollup: specifier: 4.48.0 version: 4.48.0 @@ -9508,6 +9511,13 @@ packages: resolution: {integrity: sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==} engines: {node: '>=6.0.0'} + qr-code-styling@1.9.2: + resolution: {integrity: sha512-RgJaZJ1/RrXJ6N0j7a+pdw3zMBmzZU4VN2dtAZf8ZggCfRB5stEQ3IoDNGaNhYY3nnZKYlYSLl5YkfWN5dPutg==} + engines: {node: '>=18.18.0'} + + qrcode-generator@1.5.2: + resolution: {integrity: sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw==} + qrcode@1.5.4: resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} engines: {node: '>=10.13.0'} @@ -21080,6 +21090,12 @@ snapshots: pvutils@1.1.3: {} + qr-code-styling@1.9.2: + dependencies: + qrcode-generator: 1.5.2 + + qrcode-generator@1.5.2: {} + qrcode@1.5.4: dependencies: dijkstrajs: 1.0.2 From 926cd832c6de92f45c58b18b4695d9ae6b70c40d Mon Sep 17 00:00:00 2001 From: tamaina Date: Mon, 25 Aug 2025 07:28:02 +0900 Subject: [PATCH 02/85] added to navbar --- packages/frontend/src/navbar.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/frontend/src/navbar.ts b/packages/frontend/src/navbar.ts index c0fe0f2b85..1cd7f0a3e0 100644 --- a/packages/frontend/src/navbar.ts +++ b/packages/frontend/src/navbar.ts @@ -15,6 +15,12 @@ import { i18n } from '@/i18n.js'; import { unisonReload } from '@/utility/unison-reload.js'; export const navbarItemDef = reactive({ + qr: { + title: i18n.ts.qr, + icon: 'ti ti-qrcode', + show: computed(() => $i != null), + to: '/qr', + }, notifications: { title: i18n.ts.notifications, icon: 'ti ti-bell', From 9c9e6c9ca9090cf8461b0e1320074115d751e5ed Mon Sep 17 00:00:00 2001 From: tamaina Date: Mon, 25 Aug 2025 08:09:08 +0900 Subject: [PATCH 03/85] qr.show.vue --- locales/index.d.ts | 8 +++ locales/ja-JP.yml | 2 + packages/frontend/src/pages/qr.read.vue | 1 + packages/frontend/src/pages/qr.show.vue | 71 ++++++++++++++++++------- 4 files changed, 63 insertions(+), 19 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 2040d55628..20735c9e66 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12561,6 +12561,14 @@ export interface Locale extends ILocale { * 読み取る */ "readTabTitle": string; + /** + * {name} {acct} + */ + "shareTitle": ParameterizedString<"name" | "acct">; + /** + * Fediverseで私をフォローしてください! + */ + "shareText": string; }; } declare const locales: { diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index cf26446a4d..6b591227f0 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -3364,3 +3364,5 @@ qr: 二次元コード _qr: showTabTitle: "表示" readTabTitle: "読み取る" + shareTitle: "{name} {acct}" + shareText: "Fediverseで私をフォローしてください!" diff --git a/packages/frontend/src/pages/qr.read.vue b/packages/frontend/src/pages/qr.read.vue index 5cf8c6dee1..a4b8aaad1c 100644 --- a/packages/frontend/src/pages/qr.read.vue +++ b/packages/frontend/src/pages/qr.read.vue @@ -17,5 +17,6 @@ const $i = ensureSignin(); diff --git a/packages/frontend/src/pages/qr.show.vue b/packages/frontend/src/pages/qr.show.vue index 75544c0ce1..94874717d9 100644 --- a/packages/frontend/src/pages/qr.show.vue +++ b/packages/frontend/src/pages/qr.show.vue @@ -5,35 +5,51 @@ SPDX-License-Identifier: AGPL-3.0-only diff --git a/packages/frontend/src/pages/qr.vue b/packages/frontend/src/pages/qr.vue index 3db767f494..558f25a761 100644 --- a/packages/frontend/src/pages/qr.vue +++ b/packages/frontend/src/pages/qr.vue @@ -4,7 +4,7 @@ SPDX-License-Identifier: AGPL-3.0-only --> -
+
+
-
- -
@@ -48,5 +44,5 @@ const props = defineProps<{ const parsed = computed(() => mfm.parse(props.data)); const urls = computed(() => extractUrlFromMfm(parsed.value)); -const tab = ref<'urls' | 'mfm' | 'raw'>(urls.value.length > 0 ? 'urls' : 'mfm'); +const tab = ref<'mfm' | 'raw'>('mfm'); From 09d39d1fcffe545755d0d03aabf711f1fd366ff8 Mon Sep 17 00:00:00 2001 From: tamaina Date: Sun, 31 Aug 2025 21:00:21 +0900 Subject: [PATCH 60/85] :art: --- packages/frontend/src/pages/qr.read.raw-viewer.vue | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/frontend/src/pages/qr.read.raw-viewer.vue b/packages/frontend/src/pages/qr.read.raw-viewer.vue index 3628092db4..551c9bbc74 100644 --- a/packages/frontend/src/pages/qr.read.raw-viewer.vue +++ b/packages/frontend/src/pages/qr.read.raw-viewer.vue @@ -19,11 +19,11 @@ /> -
+
-
+
From bcb36d8b6fcbdfeb8a1cd19031df9cbd2c9537f9 Mon Sep 17 00:00:00 2001 From: tamaina Date: Sun, 31 Aug 2025 21:52:17 +0900 Subject: [PATCH 61/85] fix 18n --- locales/index.d.ts | 8 ++++++++ locales/ja-JP.yml | 3 +-- packages/frontend/src/pages/qr.read.raw-viewer.vue | 5 +++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/locales/index.d.ts b/locales/index.d.ts index 4b38d9a515..9ca156c9de 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12601,6 +12601,14 @@ export interface Locale extends ILocale { * 端末の画像をスキャン */ "scanFile": string; + /** + * テキスト + */ + "raw": string; + /** + * MFM + */ + "mfm": string; }; } declare const locales: { diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index aef53448c0..9a26206947 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -3374,6 +3374,5 @@ _qr: stopQr: "コードリーダーを停止" noQrCodeFound: "QRコードが見つかりません" scanFile: "端末の画像をスキャン" - urls: "URL" - raw: "生データ" + raw: "テキスト" mfm: "MFM" diff --git a/packages/frontend/src/pages/qr.read.raw-viewer.vue b/packages/frontend/src/pages/qr.read.raw-viewer.vue index 551c9bbc74..f8b9cfeeff 100644 --- a/packages/frontend/src/pages/qr.read.raw-viewer.vue +++ b/packages/frontend/src/pages/qr.read.raw-viewer.vue @@ -7,12 +7,12 @@ :tabs="[ { key: 'mfm', - title: 'MFM', + title: i18n.ts._qr.mfm, icon: 'ti ti-align-left', }, { key: 'raw', - title: 'Raw', + title: i18n.ts._qr.raw, icon: 'ti ti-code', }, ]" @@ -37,6 +37,7 @@ import MkTabs from '@/components/MkTabs.vue'; import { extractUrlFromMfm } from '@/utility/extract-url-from-mfm'; import MkCode from '@/components/MkCode.vue'; import MkUrlPreview from '@/components/MkUrlPreview.vue'; +import { i18n } from '@/i18n.js'; const props = defineProps<{ data: string; From 21f4dd1d7a7b53548e8cc222e57aeeae9122e35f Mon Sep 17 00:00:00 2001 From: tamaina Date: Wed, 3 Sep 2025 00:52:15 +0900 Subject: [PATCH 62/85] =?UTF-8?q?QR=E3=81=AE=E5=86=85=E5=AE=B9=E3=81=AF/us?= =?UTF-8?q?ers/:userId=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/frontend/src/pages/qr.show.vue | 42 +++++++++++++------------ 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/packages/frontend/src/pages/qr.show.vue b/packages/frontend/src/pages/qr.show.vue index 5cb4770506..de3e94b80d 100644 --- a/packages/frontend/src/pages/qr.show.vue +++ b/packages/frontend/src/pages/qr.show.vue @@ -4,11 +4,13 @@ SPDX-License-Identifier: AGPL-3.0-only -->