note-improvements (#9734)
Not sure if this is the best way to jump to the post This also lets you select text w/out clicking to the post (and clicking normally on top of the text opens the post) Co-authored-by: Freeplay <Freeplay@duck.com> Reviewed-on: https://codeberg.org/calckey/calckey/pulls/9734 Co-authored-by: Free <freeplay@duck.com> Co-committed-by: Free <freeplay@duck.com>
This commit is contained in:
parent
d75a4e56e3
commit
c2df136dda
|
@ -33,7 +33,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<article class="article" @contextmenu.stop="onContextmenu" @click="router.push(notePage(appearNote))">
|
<article class="article" @contextmenu.stop="onContextmenu" @click="noteClick">
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="header-container">
|
<div class="header-container">
|
||||||
<MkAvatar class="avatar" :user="appearNote.user"/>
|
<MkAvatar class="avatar" :user="appearNote.user"/>
|
||||||
|
@ -41,16 +41,16 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<p v-if="appearNote.cw != null" class="cw">
|
<p v-if="appearNote.cw != null" class="cw">
|
||||||
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis" @click.stop/>
|
<Mfm v-if="appearNote.cw != ''" class="text" :text="appearNote.cw" :author="appearNote.user" :custom-emojis="appearNote.emojis" :i="$i"/>
|
||||||
<XCwButton v-model="showContent" :note="appearNote"/>
|
<XCwButton v-model="showContent" :note="appearNote"/>
|
||||||
</p>
|
</p>
|
||||||
<div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed, isLong }">
|
<div v-show="appearNote.cw == null || showContent" class="content" :class="{ collapsed, isLong }">
|
||||||
<div class="text">
|
<div class="text">
|
||||||
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis" @click.stop/>
|
<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
|
||||||
<!-- <a v-if="appearNote.renote != null" class="rp">RN:</a> -->
|
<!-- <a v-if="appearNote.renote != null" class="rp">RN:</a> -->
|
||||||
<div v-if="translating || translation" class="translation">
|
<div v-if="translating || translation" class="translation">
|
||||||
<MkLoading v-if="translating" mini/>
|
<MkLoading v-if="translating" mini/>
|
||||||
<div v-else class="translated" @click.stop>
|
<div v-else class="translated">
|
||||||
<b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
|
<b>{{ i18n.t('translatedFrom', { x: translation.sourceLang }) }}: </b>
|
||||||
<Mfm :text="translation.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
|
<Mfm :text="translation.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -264,6 +264,14 @@ function focusAfter() {
|
||||||
focusNext(el.value);
|
focusNext(el.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function noteClick(e) {
|
||||||
|
if (document.getSelection().type === 'Range') {
|
||||||
|
e.stopPropagation();
|
||||||
|
} else {
|
||||||
|
router.push(notePage(appearNote))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function readPromo() {
|
function readPromo() {
|
||||||
os.api('promo/read', {
|
os.api('promo/read', {
|
||||||
noteId: appearNote.id,
|
noteId: appearNote.id,
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
:tabindex="!isDeleted ? '-1' : null"
|
:tabindex="!isDeleted ? '-1' : null"
|
||||||
:class="{ renote: isRenote }"
|
:class="{ renote: isRenote }"
|
||||||
>
|
>
|
||||||
<MkNoteSub v-for="note in conversation" :key="note.id" class="reply-to-more" :note="note" @click.self="router.push(notePage(note))"/>
|
<MkNoteSub v-for="note in conversation" :key="note.id" class="reply-to-more" :note="note"/>
|
||||||
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to" @click.self="router.push(notePage(appearNote))"/>
|
<MkNoteSub v-if="appearNote.reply" :note="appearNote.reply" class="reply-to"/>
|
||||||
<div v-if="isRenote" class="renote">
|
<div v-if="isRenote" class="renote">
|
||||||
<MkAvatar class="avatar" :user="note.user"/>
|
<MkAvatar class="avatar" :user="note.user"/>
|
||||||
<i class="ph-repeat ph-bold ph-lg"></i>
|
<i class="ph-repeat ph-bold ph-lg"></i>
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
<MkVisibility :note="note"/>
|
<MkVisibility :note="note"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<article class="article" @contextmenu.stop="onContextmenu">
|
<article ref="noteEl" class="article" @contextmenu.stop="onContextmenu" tabindex="-1">
|
||||||
<header class="header">
|
<header class="header">
|
||||||
<MkAvatar class="avatar" :user="appearNote.user" :show-indicator="true"/>
|
<MkAvatar class="avatar" :user="appearNote.user" :show-indicator="true"/>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
|
@ -99,7 +99,7 @@
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
<MkNoteSub v-for="note in directReplies" :key="note.id" :note="note" class="reply" :conversation="replies" @click.self="router.push(notePage(note))"/>
|
<MkNoteSub v-for="note in directReplies" :key="note.id" :note="note" class="reply" :conversation="replies"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_panel muted" @click="muted = false">
|
<div v-else class="_panel muted" @click="muted = false">
|
||||||
<I18n :src="i18n.ts.userSaysSomething" tag="small">
|
<I18n :src="i18n.ts.userSaysSomething" tag="small">
|
||||||
|
@ -113,7 +113,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, inject, onMounted, onUnmounted, reactive, ref } from 'vue';
|
import { computed, inject, onMounted, onUnmounted, onUpdated, reactive, ref } from 'vue';
|
||||||
import * as mfm from 'mfm-js';
|
import * as mfm from 'mfm-js';
|
||||||
import type * as misskey from 'calckey-js';
|
import type * as misskey from 'calckey-js';
|
||||||
import MkNoteSub from '@/components/MkNoteSub.vue';
|
import MkNoteSub from '@/components/MkNoteSub.vue';
|
||||||
|
@ -175,6 +175,7 @@ const isRenote = (
|
||||||
);
|
);
|
||||||
|
|
||||||
const el = ref<HTMLElement>();
|
const el = ref<HTMLElement>();
|
||||||
|
const noteEl = $ref();
|
||||||
const menuButton = ref<HTMLElement>();
|
const menuButton = ref<HTMLElement>();
|
||||||
const starButton = ref<InstanceType<typeof XStarButton>>();
|
const starButton = ref<InstanceType<typeof XStarButton>>();
|
||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
|
@ -192,6 +193,8 @@ const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultS
|
||||||
const conversation = ref<misskey.entities.Note[]>([]);
|
const conversation = ref<misskey.entities.Note[]>([]);
|
||||||
const replies = ref<misskey.entities.Note[]>([]);
|
const replies = ref<misskey.entities.Note[]>([]);
|
||||||
const directReplies = ref<misskey.entities.Note[]>([]);
|
const directReplies = ref<misskey.entities.Note[]>([]);
|
||||||
|
let isScrolling;
|
||||||
|
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
'r': () => reply(true),
|
'r': () => reply(true),
|
||||||
|
@ -281,11 +284,11 @@ function showRenoteMenu(viaKeyboard = false): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
el.value.focus();
|
noteEl.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function blur() {
|
function blur() {
|
||||||
el.value.blur();
|
noteEl.blur();
|
||||||
}
|
}
|
||||||
|
|
||||||
os.api('notes/children', {
|
os.api('notes/children', {
|
||||||
|
@ -302,6 +305,7 @@ if (appearNote.replyId) {
|
||||||
noteId: appearNote.replyId,
|
noteId: appearNote.replyId,
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
conversation.value = res.reverse();
|
conversation.value = res.reverse();
|
||||||
|
focus();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,13 +326,26 @@ function onNoteReplied(noteData: NoteUpdatedEvent): void {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.addEventListener("wheel", () => {
|
||||||
|
isScrolling = true;
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
stream.on("noteUpdated", onNoteReplied);
|
stream.on("noteUpdated", onNoteReplied);
|
||||||
|
isScrolling = false;
|
||||||
|
noteEl.scrollIntoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUpdated(() => {
|
||||||
|
if (!isScrolling) {
|
||||||
|
noteEl.scrollIntoView()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
stream.off("noteUpdated", onNoteReplied);
|
stream.off("noteUpdated", onNoteReplied);
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -434,7 +451,8 @@ onUnmounted(() => {
|
||||||
}
|
}
|
||||||
font-size: 1.2em;
|
font-size: 1.2em;
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
|
outline: none;
|
||||||
|
scroll-margin-top: calc(var(--stickyTop) + 20vh);
|
||||||
> .header {
|
> .header {
|
||||||
display: flex;
|
display: flex;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div v-size="{ max: [450, 500] }" class="wrpstxzv" :class="{ children: depth > 1, singleStart: replies.length == 1, firstColumn: depth == 1 && conversation }">
|
<div v-size="{ max: [450, 500] }" class="wrpstxzv" :class="{ children: depth > 1, singleStart: replies.length == 1, firstColumn: depth == 1 && conversation }">
|
||||||
<div v-if="conversation && depth > 1" class="line"></div>
|
<div v-if="conversation && depth > 1" class="line"></div>
|
||||||
<div class="main" @click="router.push(notePage(note))">
|
<div class="main" @click="noteClick">
|
||||||
<div class="avatar-container">
|
<div class="avatar-container">
|
||||||
<MkAvatar class="avatar" :user="note.user"/>
|
<MkAvatar class="avatar" :user="note.user"/>
|
||||||
<div v-if="(!conversation) || replies.length > 0" class="line"></div>
|
<div v-if="(!conversation) || replies.length > 0" class="line"></div>
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
<Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
|
<Mfm v-if="note.cw != ''" class="text" :text="note.cw" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
|
||||||
<XCwButton v-model="showContent" :note="note"/>
|
<XCwButton v-model="showContent" :note="note"/>
|
||||||
</p>
|
</p>
|
||||||
<div v-show="note.cw == null || showContent" class="content" @click="router.push(notePage(note))">
|
<div v-show="note.cw == null || showContent" class="content">
|
||||||
<MkSubNoteContent class="text" :note="note" :detailed="true" :parentId="note.parentId" :conversation="conversation"/>
|
<MkSubNoteContent class="text" :note="note" :detailed="true" :parentId="note.parentId" :conversation="conversation"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -68,6 +68,14 @@ const props = withDefaults(defineProps<{
|
||||||
|
|
||||||
let showContent = $ref(false);
|
let showContent = $ref(false);
|
||||||
const replies: misskey.entities.Note[] = props.conversation?.filter(item => item.replyId === props.note.id || item.renoteId === props.note.id).reverse() ?? [];
|
const replies: misskey.entities.Note[] = props.conversation?.filter(item => item.replyId === props.note.id || item.renoteId === props.note.id).reverse() ?? [];
|
||||||
|
|
||||||
|
function noteClick(e) {
|
||||||
|
if (document.getSelection().type === 'Range') {
|
||||||
|
e.stopPropagation();
|
||||||
|
} else {
|
||||||
|
router.push(notePage(props.note))
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|
|
@ -88,7 +88,6 @@ html._themeChanging_ {
|
||||||
html, body {
|
html, body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|
Loading…
Reference in New Issue