display raw content read from qr
This commit is contained in:
parent
83016acd3e
commit
f72e3f61e9
|
@ -0,0 +1,43 @@
|
||||||
|
<template>
|
||||||
|
<MkFolder defaultOpen :withSpacer="false">
|
||||||
|
<template #label>{{ data.split('\n')[0] }}</template>
|
||||||
|
<template #header>
|
||||||
|
<MkTabs
|
||||||
|
v-model:tab="tab"
|
||||||
|
:tabs="[{
|
||||||
|
key: 'raw',
|
||||||
|
title: 'Raw',
|
||||||
|
}, {
|
||||||
|
key: 'mfm',
|
||||||
|
title: 'MFM',
|
||||||
|
}]"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div v-show="tab === 'raw'" class="_spacer" style="--MI_SPACER-min: 14px; --MI_SPACER-max: 22px;">
|
||||||
|
<MkCode :code="data" lang="text"/>
|
||||||
|
</div>
|
||||||
|
<div v-show="tab === 'mfm'" class="_gaps _spacer">
|
||||||
|
<Mfm :text="data" :nyaize="false"/>
|
||||||
|
<MkUrlPreview v-for="url in urls" :key="url" :url="url" :compact="true" :detail="false"/>
|
||||||
|
</div>
|
||||||
|
</MkFolder>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { defineProps, ref, computed } from 'vue';
|
||||||
|
import * as mfm from 'mfm-js';
|
||||||
|
import MkFolder from '@/components/MkFolder.vue';
|
||||||
|
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';
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
data: string;
|
||||||
|
}>();
|
||||||
|
|
||||||
|
const tab = ref<'mfm' | 'raw'>('raw');
|
||||||
|
const parsed = computed(() => mfm.parse(props.data));
|
||||||
|
const urls = computed(() => extractUrlFromMfm(parsed.value));
|
||||||
|
</script>
|
|
@ -41,6 +41,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<MkTab v-model="tab" :class="$style.tab">
|
<MkTab v-model="tab" :class="$style.tab">
|
||||||
<option value="users">{{ i18n.ts.users }}</option>
|
<option value="users">{{ i18n.ts.users }}</option>
|
||||||
<option value="notes">{{ i18n.ts.notes }}</option>
|
<option value="notes">{{ i18n.ts.notes }}</option>
|
||||||
|
<option value="all">{{ i18n.ts.all }}</option>
|
||||||
</MkTab>
|
</MkTab>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="tab === 'users'" :class="[$style.users, '_margin']" style="padding-bottom: var(--MI-margin);">
|
<div v-if="tab === 'users'" :class="[$style.users, '_margin']" style="padding-bottom: var(--MI-margin);">
|
||||||
|
@ -49,6 +50,9 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<div v-else-if="tab === 'notes'" class="_margin _gaps" style="padding-bottom: var(--MI-margin);">
|
<div v-else-if="tab === 'notes'" class="_margin _gaps" style="padding-bottom: var(--MI-margin);">
|
||||||
<MkNote v-for="note in notes" :key="note.id" :note="note" :class="$style.note"/>
|
<MkNote v-for="note in notes" :key="note.id" :note="note" :class="$style.note"/>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-else-if="tab === 'all'" class="_margin _gaps" style="padding-bottom: var(--MI-margin);">
|
||||||
|
<MkQrReadRawViewer v-for="result in Array.from(results).reverse()" :key="result" :data="result"/>
|
||||||
|
</div>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
</div>
|
</div>
|
||||||
</MkStickyContainer>
|
</MkStickyContainer>
|
||||||
|
@ -68,6 +72,7 @@ import { misskeyApi } from '@/utility/misskey-api.js';
|
||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkTab from '@/components/MkTab.vue';
|
import MkTab from '@/components/MkTab.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
import MkQrReadRawViewer from '@/pages/qr.read.raw-viewer.vue';
|
||||||
|
|
||||||
const LIST_RERENDER_INTERVAL = 1500;
|
const LIST_RERENDER_INTERVAL = 1500;
|
||||||
|
|
||||||
|
@ -80,8 +85,11 @@ const scrollHeight = ref(window.innerHeight);
|
||||||
|
|
||||||
const scannerInstance = shallowRef<QrScanner | null>(null);
|
const scannerInstance = shallowRef<QrScanner | null>(null);
|
||||||
|
|
||||||
const tab = ref<'users' | 'notes'>('users');
|
const tab = ref<'users' | 'notes' | 'all'>('users');
|
||||||
|
|
||||||
|
// higher is recent
|
||||||
|
const results = ref(new Set<string>());
|
||||||
|
// lower is recent
|
||||||
const uris = ref<string[]>([]);
|
const uris = ref<string[]>([]);
|
||||||
const sources = new Map<string, ApShowResponse | null>();
|
const sources = new Map<string, ApShowResponse | null>();
|
||||||
const users = ref<(misskey.entities.UserDetailed)[]>([]);
|
const users = ref<(misskey.entities.UserDetailed)[]>([]);
|
||||||
|
@ -92,10 +100,10 @@ const notesCount = ref(0);
|
||||||
const timer = ref<number | null>(null);
|
const timer = ref<number | null>(null);
|
||||||
|
|
||||||
function updateLists() {
|
function updateLists() {
|
||||||
const results = uris.value.map(uri => sources.get(uri)).filter((r): r is ApShowResponse => !!r);
|
const responses = uris.value.map(uri => sources.get(uri)).filter((r): r is ApShowResponse => !!r);
|
||||||
users.value = results.filter(r => r.type === 'User').map(r => r.object).filter((u): u is misskey.entities.UserDetailed => !!u);
|
users.value = responses.filter(r => r.type === 'User').map(r => r.object).filter((u): u is misskey.entities.UserDetailed => !!u);
|
||||||
usersCount.value = users.value.length;
|
usersCount.value = users.value.length;
|
||||||
notes.value = results.filter(r => r.type === 'Note').map(r => r.object).filter((n): n is misskey.entities.Note => !!n);
|
notes.value = responses.filter(r => r.type === 'Note').map(r => r.object).filter((n): n is misskey.entities.Note => !!n);
|
||||||
notesCount.value = notes.value.length;
|
notesCount.value = notes.value.length;
|
||||||
updateRequired.value = false;
|
updateRequired.value = false;
|
||||||
}
|
}
|
||||||
|
@ -128,29 +136,38 @@ watch(tab, () => {
|
||||||
|
|
||||||
async function processResult(result: QrScanner.ScanResult) {
|
async function processResult(result: QrScanner.ScanResult) {
|
||||||
if (!result) return;
|
if (!result) return;
|
||||||
const uri = result.data.trim();
|
const trimmed = result.data.trim();
|
||||||
|
|
||||||
|
if (!trimmed) return;
|
||||||
|
|
||||||
|
const haveExisted = results.value.has(trimmed);
|
||||||
|
results.value.add(trimmed);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new URL(uri);
|
new URL(trimmed);
|
||||||
} catch {
|
} catch {
|
||||||
|
if (!haveExisted) {
|
||||||
|
tab.value = 'all';
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uris.value[0] !== uri) {
|
if (uris.value[0] !== trimmed) {
|
||||||
// 並べ替え
|
// 並べ替え
|
||||||
uris.value = [uri, ...uris.value.slice(0, 29).filter(u => u !== uri)];
|
uris.value = [trimmed, ...uris.value.slice(0, 29).filter(u => u !== trimmed)];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sources.has(uri)) return;
|
if (sources.has(trimmed)) return;
|
||||||
// Start fetching user info
|
// Start fetching user info
|
||||||
sources.set(uri, null);
|
sources.set(trimmed, null);
|
||||||
|
|
||||||
await misskeyApi('ap/show', { uri })
|
await misskeyApi('ap/show', { uri: trimmed })
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.type === 'User') {
|
if (data.type === 'User') {
|
||||||
sources.set(uri, data);
|
sources.set(trimmed, data);
|
||||||
tab.value = 'users';
|
tab.value = 'users';
|
||||||
} else if (data.type === 'Note') {
|
} else if (data.type === 'Note') {
|
||||||
sources.set(uri, data);
|
sources.set(trimmed, data);
|
||||||
tab.value = 'notes';
|
tab.value = 'notes';
|
||||||
}
|
}
|
||||||
updateLists();
|
updateLists();
|
||||||
|
|
Loading…
Reference in New Issue