1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-23 11:04:10 +02:00

feat(frontend): 自分のプロフィールページの二次元コード(QRコード)を表示し、他の人のコードを読み取りするページを追加 (#16456)

* wip (qr.show.vue)

* added to navbar

* qr.show.vue

* fix

* added to navbar

* fix size

* 🎨

* 🎨

* fix div warn

* fix

* use * 0.25

* fix??

* fix lint

* clean up

* ???

* ?

* fix

* 🎨

* 🎨

* refactor

* 🎨

* 🎨

* :ar:t

* 🎨

* iphone flip

* no lazy import

* 🎨

* 🎨

* 🎨

* ユーザー全部flipでいいや

* ✌️

* fix

* fix

* fix lint

* 🎨

* 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

* 🎨

* 🎨

* fix imports

* fix

* fix

* fix

* 🎨

* fix...

* set spacer-w

* ✌️

* 全画面でQRを読むように

* fix

* 🎨

* modify navbar.ts

* start/stop on vue activation

* display raw content read from qr

* 端末のQRをスキャンするボタンを追加

* chore

* やっぱりmfmを先に表示する

* 🎨

* 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 <anatawa12@icloud.com>
Co-authored-by: syuilo <4439005+syuilo@users.noreply.github.com>
This commit is contained in:
tamaina
2025-09-19 21:02:30 +09:00
committed by GitHub
parent 97adf6f2cc
commit 42b2aea533
23 changed files with 1122 additions and 62 deletions

View File

@@ -30,22 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only
</div>
<div :class="$style.controls">
<div class="_spacer _gaps">
<MkSelect v-model="type" :items="typeDef">
<template #label>{{ i18n.ts._watermarkEditor.type }}</template>
</MkSelect>
<div v-if="type === 'text' || type === 'image'">
<XLayer
v-for="(layer, i) in preset.layers"
:key="layer.id"
v-model:layer="preset.layers[i]"
></XLayer>
</div>
<div v-else-if="type === 'advanced'" class="_gaps_s">
<div class="_gaps_s">
<MkFolder v-for="(layer, i) in preset.layers" :key="layer.id" :defaultOpen="false" :canPage="false">
<template #label>
<div v-if="layer.type === 'text'">{{ i18n.ts._watermarkEditor.text }}</div>
<div v-if="layer.type === 'image'">{{ i18n.ts._watermarkEditor.image }}</div>
<div v-if="layer.type === 'qr'">{{ i18n.ts._watermarkEditor.qr }}</div>
<div v-if="layer.type === 'stripe'">{{ i18n.ts._watermarkEditor.stripe }}</div>
<div v-if="layer.type === 'polkadot'">{{ i18n.ts._watermarkEditor.polkadot }}</div>
<div v-if="layer.type === 'checker'">{{ i18n.ts._watermarkEditor.checker }}</div>
@@ -95,7 +85,7 @@ function createTextLayer(): WatermarkPreset['layers'][number] {
id: genId(),
type: 'text',
text: `(c) @${$i.username}`,
align: { x: 'right', y: 'bottom' },
align: { x: 'right', y: 'bottom', margin: 0 },
scale: 0.3,
angle: 0,
opacity: 0.75,
@@ -109,7 +99,7 @@ function createImageLayer(): WatermarkPreset['layers'][number] {
type: 'image',
imageId: null,
imageUrl: null,
align: { x: 'right', y: 'bottom' },
align: { x: 'right', y: 'bottom', margin: 0 },
scale: 0.3,
angle: 0,
opacity: 0.75,
@@ -118,6 +108,17 @@ function createImageLayer(): WatermarkPreset['layers'][number] {
};
}
function createQrLayer(): WatermarkPreset['layers'][number] {
return {
id: genId(),
type: 'qr',
data: '',
align: { x: 'right', y: 'bottom', margin: 0 },
scale: 0.3,
opacity: 1,
};
}
function createStripeLayer(): WatermarkPreset['layers'][number] {
return {
id: genId(),
@@ -165,7 +166,7 @@ const props = defineProps<{
const preset = reactive<WatermarkPreset>(deepClone(props.preset) ?? {
id: genId(),
name: '',
layers: [createTextLayer()],
layers: [],
});
const emit = defineEmits<{
@@ -187,28 +188,6 @@ async function cancel() {
dialog.value?.close();
}
const {
model: type,
def: typeDef,
} = useMkSelect({
items: [
{ label: i18n.ts._watermarkEditor.text, value: 'text' },
{ label: i18n.ts._watermarkEditor.image, value: 'image' },
{ label: i18n.ts._watermarkEditor.advanced, value: 'advanced' },
],
initialValue: preset.layers.length > 1 ? 'advanced' : preset.layers[0].type,
});
watch(type, () => {
if (type.value === 'text') {
preset.layers = [createTextLayer()];
} else if (type.value === 'image') {
preset.layers = [createImageLayer()];
} else if (type.value === 'advanced') {
// nop
}
});
watch(preset, async (newValue, oldValue) => {
if (renderer != null) {
renderer.setLayers(preset.layers);
@@ -338,6 +317,11 @@ function addLayer(ev: MouseEvent) {
action: () => {
preset.layers.push(createImageLayer());
},
}, {
text: i18n.ts._watermarkEditor.qr,
action: () => {
preset.layers.push(createQrLayer());
},
}, {
text: i18n.ts._watermarkEditor.stripe,
action: () => {