diff --git a/locales/en-US.yml b/locales/en-US.yml
index 7ccda1426c..cb96caa823 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -1157,6 +1157,7 @@ addRe: "Add \"re:\" at the beginning of comment in reply to a post with a conten
confirm: "Confirm"
importZip: "Import ZIP"
exportZip: "Export ZIP"
+getQrCode: "Get QR code"
emojiPackCreator: "Emoji pack creator"
indexable: "Indexable"
indexableDescription: "Allow built-in search to show your public posts"
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 6367dda9f4..5d7a1ecef8 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -928,6 +928,8 @@ colored: "Coloré"
label: "Étiquette"
localOnly: "Local seulement"
account: "Comptes"
+getQrCode: "Obtenir le code QR"
+
_emailUnavailable:
used: "Adresse non disponible"
format: "Le format de cette adresse de courriel est invalide"
diff --git a/packages/client/package.json b/packages/client/package.json
index 97a5f83ef7..8b9184ad38 100644
--- a/packages/client/package.json
+++ b/packages/client/package.json
@@ -28,6 +28,7 @@
"@types/matter-js": "0.19.6",
"@types/prismjs": "^1.26.3",
"@types/punycode": "2.1.4",
+ "@types/qrcode": "1.5.1",
"@types/seedrandom": "3.0.8",
"@types/textarea-caret": "^3.0.3",
"@types/throttle-debounce": "5.0.2",
@@ -60,13 +61,17 @@
"insert-text-at-cursor": "0.3.0",
"json5": "2.2.3",
"katex": "0.16.10",
+ "long": "^5.2.3",
"libopenmpt-wasm": "github:TheEssem/libopenmpt-packaging#build",
"matter-js": "0.19.0",
"mfm-js": "0.24.0",
+ "multer": "1.4.4-lts.1",
"moment": "2.30.1",
"photoswipe": "5.4.3",
"prismjs": "1.29.0",
"punycode": "2.3.1",
+ "qrcode": "1.5.3",
+ "qrcode-vue3": "^1.6.8",
"rollup": "4.14.2",
"s-age": "1.1.2",
"sass": "1.75.0",
diff --git a/packages/client/src/components/FfQrCode.vue b/packages/client/src/components/FfQrCode.vue
new file mode 100644
index 0000000000..9dca107406
--- /dev/null
+++ b/packages/client/src/components/FfQrCode.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
{{
+ i18n.ts.gotIt
+ }}
+
+
+
+
+
+
+
diff --git a/packages/client/src/os.ts b/packages/client/src/os.ts
index c7c62852de..61629863ba 100644
--- a/packages/client/src/os.ts
+++ b/packages/client/src/os.ts
@@ -7,6 +7,7 @@ import type { Component, MaybeRef, Ref } from "vue";
import { defineAsyncComponent, markRaw, ref } from "vue";
import { i18n } from "./i18n";
import MkDialog from "@/components/MkDialog.vue";
+import FfQrCode from "@/components/FfQrCode.vue";
import MkPostFormDialog from "@/components/MkPostFormDialog.vue";
import MkToast from "@/components/MkToast.vue";
import MkWaitingDialog from "@/components/MkWaitingDialog.vue";
@@ -1003,6 +1004,19 @@ export function post(
});
}
+export async function displayQrCode(qrCode: string) {
+ (await new Promise<(() => void) | undefined>((resolve) => {
+ let dispose: (() => void) | undefined;
+ popup(FfQrCode, { qrCode }, {
+ closed: () => {
+ resolve(dispose);
+ }
+ }).then((res) => {
+ dispose = res.dispose
+ })
+ }))?.();
+}
+
export const deckGlobalEvents = new EventEmitter();
/*
diff --git a/packages/client/src/scripts/get-user-menu.ts b/packages/client/src/scripts/get-user-menu.ts
index 880ce481c7..713023eada 100644
--- a/packages/client/src/scripts/get-user-menu.ts
+++ b/packages/client/src/scripts/get-user-menu.ts
@@ -290,6 +290,13 @@ export function getUserMenu(user, router: Router = mainRouter) {
os.post({ specified: user });
},
},
+ {
+ icon: "ph-qr-code ph-bold ph-lg",
+ text: i18n.ts.getQrCode,
+ action: () => {
+ os.displayQrCode(window.location.href)
+ }
+ },
isSignedIn(me) && me.id !== user.id
? {
type: "link",