Tabbed content in detailed notes page
This commit is contained in:
parent
e921e2dce3
commit
d013b351e2
|
@ -5,7 +5,7 @@
|
||||||
ref="el"
|
ref="el"
|
||||||
v-hotkey="keymap"
|
v-hotkey="keymap"
|
||||||
v-size="{ max: [500, 450, 350, 300] }"
|
v-size="{ max: [500, 450, 350, 300] }"
|
||||||
class="tkcbzcuz"
|
class="tkcbzcuz note-container"
|
||||||
:tabindex="!isDeleted ? '-1' : null"
|
:tabindex="!isDeleted ? '-1' : null"
|
||||||
:class="{ renote: isRenote }"
|
:class="{ renote: isRenote }"
|
||||||
>
|
>
|
||||||
|
@ -104,6 +104,11 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div v-if="detailedView" class="info">
|
||||||
|
<MkA class="created-at" :to="notePage(appearNote)">
|
||||||
|
<MkTime :time="appearNote.createdAt" mode="absolute" />
|
||||||
|
</MkA>
|
||||||
<MkA
|
<MkA
|
||||||
v-if="appearNote.channel && !inChannel"
|
v-if="appearNote.channel && !inChannel"
|
||||||
class="channel"
|
class="channel"
|
||||||
|
@ -113,11 +118,6 @@
|
||||||
{{ appearNote.channel.name }}</MkA
|
{{ appearNote.channel.name }}</MkA
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="detailedView" class="info">
|
|
||||||
<MkA class="created-at" :to="notePage(appearNote)">
|
|
||||||
<MkTime :time="appearNote.createdAt" mode="absolute" />
|
|
||||||
</MkA>
|
|
||||||
</div>
|
|
||||||
<footer ref="footerEl" class="footer" @click.stop tabindex="-1">
|
<footer ref="footerEl" class="footer" @click.stop tabindex="-1">
|
||||||
<XReactionsViewer
|
<XReactionsViewer
|
||||||
v-if="enableEmojiReactions"
|
v-if="enableEmojiReactions"
|
||||||
|
@ -130,7 +130,7 @@
|
||||||
@click="reply()"
|
@click="reply()"
|
||||||
>
|
>
|
||||||
<i class="ph-arrow-u-up-left ph-bold ph-lg"></i>
|
<i class="ph-arrow-u-up-left ph-bold ph-lg"></i>
|
||||||
<template v-if="appearNote.repliesCount > 0">
|
<template v-if="appearNote.repliesCount > 0 && !detailedView">
|
||||||
<p class="count">{{ appearNote.repliesCount }}</p>
|
<p class="count">{{ appearNote.repliesCount }}</p>
|
||||||
</template>
|
</template>
|
||||||
</button>
|
</button>
|
||||||
|
@ -139,6 +139,7 @@
|
||||||
class="button"
|
class="button"
|
||||||
:note="appearNote"
|
:note="appearNote"
|
||||||
:count="appearNote.renoteCount"
|
:count="appearNote.renoteCount"
|
||||||
|
:detailedView="detailedView"
|
||||||
/>
|
/>
|
||||||
<XStarButtonNoEmoji
|
<XStarButtonNoEmoji
|
||||||
v-if="!enableEmojiReactions"
|
v-if="!enableEmojiReactions"
|
||||||
|
@ -450,6 +451,10 @@ function focusAfter() {
|
||||||
focusNext(el.value);
|
focusNext(el.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scrollIntoView() {
|
||||||
|
el.value.scrollIntoView();
|
||||||
|
}
|
||||||
|
|
||||||
function noteClick(e) {
|
function noteClick(e) {
|
||||||
if (document.getSelection().type === "Range" || props.detailedView) {
|
if (document.getSelection().type === "Range" || props.detailedView) {
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
@ -464,6 +469,12 @@ function readPromo() {
|
||||||
});
|
});
|
||||||
isDeleted.value = true;
|
isDeleted.value = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
focus,
|
||||||
|
blur,
|
||||||
|
scrollIntoView,
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -656,14 +667,13 @@ function readPromo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .channel {
|
|
||||||
opacity: 0.7;
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
> .info {
|
> .info {
|
||||||
margin-block: 16px;
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: .7em;
|
||||||
|
margin-top: 16px;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
font-size: 0.9em;
|
font-size: 0.9em;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,17 +25,51 @@
|
||||||
:detailedView="true"
|
:detailedView="true"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div ref="noteEl" class="article" tabindex="-1" :id="appearNote.id">
|
<MkNote
|
||||||
<MkNote
|
ref="noteEl"
|
||||||
@contextmenu.stop="onContextmenu"
|
@contextmenu.stop="onContextmenu"
|
||||||
tabindex="-1"
|
tabindex="-1"
|
||||||
:note="appearNote"
|
:note="appearNote"
|
||||||
detailedView
|
detailedView
|
||||||
></MkNote>
|
></MkNote>
|
||||||
</div>
|
|
||||||
|
<MkTab
|
||||||
|
v-model="tab"
|
||||||
|
:style="'chips'"
|
||||||
|
@update:modelValue="loadTab"
|
||||||
|
>
|
||||||
|
<option value="replies">
|
||||||
|
<i class="ph-arrow-u-up-left ph-bold ph-lg"></i>
|
||||||
|
<template v-if="appearNote.repliesCount > 0">
|
||||||
|
<span class="count">{{ appearNote.repliesCount }}</span>
|
||||||
|
</template>
|
||||||
|
{{ i18n.ts._notification._types.reply }}
|
||||||
|
</option>
|
||||||
|
<option value="renotes">
|
||||||
|
<i class="ph-repeat ph-bold ph-lg"></i>
|
||||||
|
<template v-if="appearNote.renoteCount > 0">
|
||||||
|
<span class="count">{{ appearNote.renoteCount }}</span>
|
||||||
|
</template>
|
||||||
|
{{ i18n.ts._notification._types.renote }}
|
||||||
|
</option>
|
||||||
|
<option value="quotes">
|
||||||
|
<i class="ph-quotes ph-bold ph-lg"></i>
|
||||||
|
<template v-if="directQuotes?.length > 0">
|
||||||
|
<span class="count">{{ directQuotes.length }}</span>
|
||||||
|
</template>
|
||||||
|
{{ i18n.ts._notification._types.quote }}
|
||||||
|
</option>
|
||||||
|
<option value="clips">
|
||||||
|
<i class="ph-paperclip ph-bold ph-lg"></i>
|
||||||
|
<template v-if="clips.length > 0">
|
||||||
|
<span class="count">{{ clips.length }}</span>
|
||||||
|
</template>
|
||||||
|
{{ i18n.ts.clips }}
|
||||||
|
</option>
|
||||||
|
</MkTab>
|
||||||
|
|
||||||
<MkNoteSub
|
<MkNoteSub
|
||||||
v-if="directReplies"
|
v-if="directReplies && tab === 'replies'"
|
||||||
v-for="note in directReplies"
|
v-for="note in directReplies"
|
||||||
:key="note.id"
|
:key="note.id"
|
||||||
:note="note"
|
:note="note"
|
||||||
|
@ -43,7 +77,66 @@
|
||||||
:conversation="replies"
|
:conversation="replies"
|
||||||
:detailedView="true"
|
:detailedView="true"
|
||||||
/>
|
/>
|
||||||
<MkLoading v-else-if="appearNote.repliesCount > 0" />
|
<MkLoading v-else-if="tab === 'replies' && appearNote.repliesCount > 0" />
|
||||||
|
|
||||||
|
<MkNoteSub
|
||||||
|
v-if="directQuotes && tab === 'quotes'"
|
||||||
|
v-for="note in directQuotes"
|
||||||
|
:key="note.id"
|
||||||
|
:note="note"
|
||||||
|
class="reply"
|
||||||
|
:conversation="directQuotes"
|
||||||
|
:detailedView="true"
|
||||||
|
/>
|
||||||
|
<MkLoading v-else-if="tab === 'quotes' && directQuotes.length > 0" />
|
||||||
|
|
||||||
|
<!-- <MkPagination
|
||||||
|
v-if="tab === 'renotes'"
|
||||||
|
v-slot="{ items }"
|
||||||
|
ref="pagingComponent"
|
||||||
|
:pagination="pagination"
|
||||||
|
> -->
|
||||||
|
<MkUserCardMini
|
||||||
|
v-if="tab === 'renotes' && appearNote.renoteCount > 0"
|
||||||
|
v-for="item in renotes"
|
||||||
|
:key="item.user.id"
|
||||||
|
:user="item.user"
|
||||||
|
:with-chart="false"
|
||||||
|
/>
|
||||||
|
<!-- </MkPagination> -->
|
||||||
|
<MkLoading v-else-if="tab === 'renotes' && appearNote.renoteCount > 0" />
|
||||||
|
|
||||||
|
<div
|
||||||
|
v-if="tab === 'clips' && clips.length > 0"
|
||||||
|
class="_content clips"
|
||||||
|
>
|
||||||
|
<MkA
|
||||||
|
v-for="item in clips"
|
||||||
|
:key="item.id"
|
||||||
|
:to="`/clips/${item.id}`"
|
||||||
|
class="item _panel"
|
||||||
|
>
|
||||||
|
<b>{{ item.name }}</b>
|
||||||
|
<div
|
||||||
|
v-if="item.description"
|
||||||
|
class="description"
|
||||||
|
>
|
||||||
|
{{ item.description }}
|
||||||
|
</div>
|
||||||
|
<div class="user">
|
||||||
|
<MkAvatar
|
||||||
|
:user="item.user"
|
||||||
|
class="avatar"
|
||||||
|
:show-indicator="true"
|
||||||
|
/>
|
||||||
|
<MkUserName
|
||||||
|
:user="item.user"
|
||||||
|
:nowrap="false"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</MkA>
|
||||||
|
</div>
|
||||||
|
<MkLoading v-else-if="tab === 'clips' && clips.length > 0" />
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="_panel muted" @click="muted.muted = false">
|
<div v-else class="_panel muted" @click="muted.muted = false">
|
||||||
<I18n :src="softMuteReasonI18nSrc(muted.what)" tag="small">
|
<I18n :src="softMuteReasonI18nSrc(muted.what)" tag="small">
|
||||||
|
@ -73,15 +166,17 @@ import {
|
||||||
reactive,
|
reactive,
|
||||||
ref,
|
ref,
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import type * as misskey from "calckey-js";
|
import * as misskey from "calckey-js";
|
||||||
|
import MkTab from "@/components/MkTab.vue";
|
||||||
import MkNote from "@/components/MkNote.vue";
|
import MkNote from "@/components/MkNote.vue";
|
||||||
import MkNoteSub from "@/components/MkNoteSub.vue";
|
import MkNoteSub from "@/components/MkNoteSub.vue";
|
||||||
import XStarButton from "@/components/MkStarButton.vue";
|
import XStarButton from "@/components/MkStarButton.vue";
|
||||||
import XRenoteButton from "@/components/MkRenoteButton.vue";
|
import XRenoteButton from "@/components/MkRenoteButton.vue";
|
||||||
|
import MkPagination from "@/components/MkPagination.vue";
|
||||||
|
import MkUserCardMini from "@/components/MkUserCardMini.vue";
|
||||||
import { pleaseLogin } from "@/scripts/please-login";
|
import { pleaseLogin } from "@/scripts/please-login";
|
||||||
import { getWordSoftMute } from "@/scripts/check-word-mute";
|
import { getWordSoftMute } from "@/scripts/check-word-mute";
|
||||||
import { userPage } from "@/filters/user";
|
import { userPage } from "@/filters/user";
|
||||||
import { useRouter } from "@/router";
|
|
||||||
import * as os from "@/os";
|
import * as os from "@/os";
|
||||||
import { defaultStore, noteViewInterruptors } from "@/store";
|
import { defaultStore, noteViewInterruptors } from "@/store";
|
||||||
import { reactionPicker } from "@/scripts/reaction-picker";
|
import { reactionPicker } from "@/scripts/reaction-picker";
|
||||||
|
@ -92,12 +187,15 @@ import { useNoteCapture } from "@/scripts/use-note-capture";
|
||||||
import { deepClone } from "@/scripts/clone";
|
import { deepClone } from "@/scripts/clone";
|
||||||
import { stream } from "@/stream";
|
import { stream } from "@/stream";
|
||||||
import { NoteUpdatedEvent } from "calckey-js/built/streaming.types";
|
import { NoteUpdatedEvent } from "calckey-js/built/streaming.types";
|
||||||
|
import appear from "@/directives/appear";
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
note: misskey.entities.Note;
|
note: misskey.entities.Note;
|
||||||
pinned?: boolean;
|
pinned?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
let tab = $ref("replies");
|
||||||
|
|
||||||
let note = $ref(deepClone(props.note));
|
let note = $ref(deepClone(props.note));
|
||||||
|
|
||||||
const softMuteReasonI18nSrc = (what?: string) => {
|
const softMuteReasonI18nSrc = (what?: string) => {
|
||||||
|
@ -146,6 +244,9 @@ const translating = ref(false);
|
||||||
let conversation = $ref<null | misskey.entities.Note[]>([]);
|
let conversation = $ref<null | misskey.entities.Note[]>([]);
|
||||||
const replies = ref<misskey.entities.Note[]>([]);
|
const replies = ref<misskey.entities.Note[]>([]);
|
||||||
let directReplies = $ref<null | misskey.entities.Note[]>([]);
|
let directReplies = $ref<null | misskey.entities.Note[]>([]);
|
||||||
|
let directQuotes = $ref<null | misskey.entities.Note[]>([]);
|
||||||
|
let clips = $ref();
|
||||||
|
let renotes = $ref();
|
||||||
let isScrolling;
|
let isScrolling;
|
||||||
|
|
||||||
const keymap = {
|
const keymap = {
|
||||||
|
@ -259,10 +360,14 @@ os.api("notes/children", {
|
||||||
directReplies = res
|
directReplies = res
|
||||||
.filter(
|
.filter(
|
||||||
(note) =>
|
(note) =>
|
||||||
note.replyId === appearNote.id ||
|
note.replyId === appearNote.id
|
||||||
note.renoteId === appearNote.id
|
|
||||||
)
|
)
|
||||||
.reverse();
|
.reverse();
|
||||||
|
directQuotes = res
|
||||||
|
.filter(
|
||||||
|
(note) =>
|
||||||
|
note.renoteId === appearNote.id
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
conversation = null;
|
conversation = null;
|
||||||
|
@ -276,6 +381,33 @@ if (appearNote.replyId) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clips = null;
|
||||||
|
os.api("notes/clips", {
|
||||||
|
noteId: appearNote.id,
|
||||||
|
}).then((res) => {
|
||||||
|
clips = res;
|
||||||
|
});
|
||||||
|
|
||||||
|
// const pagination = {
|
||||||
|
// endpoint: "notes/renotes",
|
||||||
|
// noteId: appearNote.id,
|
||||||
|
// limit: 10,
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const pagingComponent = $ref<InstanceType<typeof MkPagination>>();
|
||||||
|
|
||||||
|
renotes = null;
|
||||||
|
function loadTab() {
|
||||||
|
if (tab === "renotes" && !renotes) {
|
||||||
|
os.api("notes/renotes", {
|
||||||
|
noteId: appearNote.id,
|
||||||
|
limit: 100,
|
||||||
|
}).then((res) => {
|
||||||
|
renotes = res;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function onNoteUpdated(noteData: NoteUpdatedEvent): Promise<void> {
|
async function onNoteUpdated(noteData: NoteUpdatedEvent): Promise<void> {
|
||||||
const { type, id, body } = noteData;
|
const { type, id, body } = noteData;
|
||||||
|
|
||||||
|
@ -326,12 +458,12 @@ document.addEventListener("wheel", () => {
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
stream.on("noteUpdated", onNoteUpdated);
|
stream.on("noteUpdated", onNoteUpdated);
|
||||||
isScrolling = false;
|
isScrolling = false;
|
||||||
noteEl?.scrollIntoView();
|
noteEl.scrollIntoView();
|
||||||
});
|
});
|
||||||
|
|
||||||
onUpdated(() => {
|
onUpdated(() => {
|
||||||
if (!isScrolling) {
|
if (!isScrolling) {
|
||||||
noteEl?.scrollIntoView();
|
noteEl.scrollIntoView();
|
||||||
if (location.hash) {
|
if (location.hash) {
|
||||||
location.replace(location.hash); // Jump to highlighted reply
|
location.replace(location.hash); // Jump to highlighted reply
|
||||||
}
|
}
|
||||||
|
@ -372,80 +504,36 @@ onUnmounted(() => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover > .article > .main > .footer > .button {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
> .reply-to {
|
> .reply-to {
|
||||||
margin-bottom: -16px;
|
margin-bottom: -16px;
|
||||||
padding-bottom: 16px;
|
padding-bottom: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .renote {
|
> :deep(.note-container) {
|
||||||
display: flex;
|
padding-block: 28px 0;
|
||||||
align-items: center;
|
|
||||||
padding: 16px 32px 8px 32px;
|
|
||||||
line-height: 28px;
|
|
||||||
white-space: pre;
|
|
||||||
color: var(--renote);
|
|
||||||
|
|
||||||
> .avatar {
|
|
||||||
flex-shrink: 0;
|
|
||||||
display: inline-block;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
margin: 0 8px 0 0;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> i {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> span {
|
|
||||||
overflow: hidden;
|
|
||||||
flex-shrink: 1;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
> .name {
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .info {
|
|
||||||
margin-left: auto;
|
|
||||||
font-size: 0.9em;
|
|
||||||
|
|
||||||
> .time {
|
|
||||||
flex-shrink: 0;
|
|
||||||
color: inherit;
|
|
||||||
|
|
||||||
> .dropdownIcon {
|
|
||||||
margin-right: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .renote + .article {
|
|
||||||
padding-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .article {
|
|
||||||
padding-block: 28px 6px;
|
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
overflow: clip;
|
overflow: clip;
|
||||||
outline: none;
|
outline: none;
|
||||||
scroll-margin-top: calc(var(--stickyTop) + 20vh);
|
scroll-margin-top: calc(var(--stickyTop) + 20vh);
|
||||||
:deep(.article) {
|
.article {
|
||||||
cursor: unset;
|
cursor: unset;
|
||||||
|
padding-bottom: 0;
|
||||||
}
|
}
|
||||||
&:first-of-type {
|
&:first-of-type {
|
||||||
padding-top: 28px;
|
padding-top: 28px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> :deep(.chips) {
|
||||||
|
padding: 6px 32px 12px;
|
||||||
|
}
|
||||||
|
> :deep(.user-card-mini) {
|
||||||
|
padding-inline: 32px;
|
||||||
|
border-top: 1px solid var(--divider);
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
> .reply {
|
> .reply {
|
||||||
border-top: solid 0.5px var(--divider);
|
border-top: solid 0.5px var(--divider);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -532,46 +620,20 @@ onUnmounted(() => {
|
||||||
> .reply-to:first-child {
|
> .reply-to:first-child {
|
||||||
padding-top: 14px;
|
padding-top: 14px;
|
||||||
}
|
}
|
||||||
> .renote {
|
|
||||||
padding: 8px 16px 0 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .article {
|
> :deep(.note-container) {
|
||||||
padding: 6px 0 0 0;
|
padding: 6px 0 0 0;
|
||||||
> .header > .body {
|
> .header > .body {
|
||||||
padding-left: 10px;
|
padding-left: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
> .clips, > .chips, > :deep(.user-card-mini) {
|
||||||
|
padding-inline: 16px !important;
|
||||||
&.max-width_350px {
|
|
||||||
> .article {
|
|
||||||
> .main {
|
|
||||||
> .footer {
|
|
||||||
> .button {
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.max-width_300px {
|
&.max-width_300px {
|
||||||
font-size: 0.825em;
|
font-size: 0.825em;
|
||||||
|
|
||||||
> .article {
|
|
||||||
> .main {
|
|
||||||
> .footer {
|
|
||||||
> .button {
|
|
||||||
&:not(:last-child) {
|
|
||||||
margin-right: 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,4 +642,36 @@ onUnmounted(() => {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clips { // want to redesign at some point
|
||||||
|
padding: 24px 32px;
|
||||||
|
padding-top: 0;
|
||||||
|
> .item {
|
||||||
|
display: block;
|
||||||
|
padding: 16px;
|
||||||
|
// background: var(--buttonBg);
|
||||||
|
border: 1px solid var(--divider);
|
||||||
|
margin-bottom: var(--margin);
|
||||||
|
transition: background .2s;
|
||||||
|
&:hover, &:focus-within {
|
||||||
|
background: var(--panelHighlight);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .description {
|
||||||
|
padding: 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> .user {
|
||||||
|
$height: 32px;
|
||||||
|
padding-top: 16px;
|
||||||
|
border-top: solid 0.5px var(--divider);
|
||||||
|
line-height: $height;
|
||||||
|
|
||||||
|
> .avatar {
|
||||||
|
width: $height;
|
||||||
|
height: $height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
@click="renote(false, $event)"
|
@click="renote(false, $event)"
|
||||||
>
|
>
|
||||||
<i class="ph-repeat ph-bold ph-lg"></i>
|
<i class="ph-repeat ph-bold ph-lg"></i>
|
||||||
<p v-if="count > 0" class="count">{{ count }}</p>
|
<p v-if="count > 0 && !detailedView" class="count">{{ count }}</p>
|
||||||
</button>
|
</button>
|
||||||
<button v-else class="eddddedb _button">
|
<button v-else class="eddddedb _button">
|
||||||
<i class="ph-prohibit ph-bold ph-lg"></i>
|
<i class="ph-prohibit ph-bold ph-lg"></i>
|
||||||
|
@ -30,6 +30,7 @@ import { MenuItem } from "@/types/menu";
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
note: misskey.entities.Note;
|
note: misskey.entities.Note;
|
||||||
count: number;
|
count: number;
|
||||||
|
detailedView?;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const buttonRef = ref<HTMLElement>();
|
const buttonRef = ref<HTMLElement>();
|
||||||
|
|
|
@ -6,6 +6,9 @@ export default defineComponent({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
style: {
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const options = this.$slots.default();
|
const options = this.$slots.default();
|
||||||
|
@ -13,7 +16,10 @@ export default defineComponent({
|
||||||
return h(
|
return h(
|
||||||
"div",
|
"div",
|
||||||
{
|
{
|
||||||
class: "pxhvhrfw",
|
class: [
|
||||||
|
"pxhvhrfw",
|
||||||
|
{ chips: this.style === "chips" },
|
||||||
|
],
|
||||||
},
|
},
|
||||||
options.map((option) =>
|
options.map((option) =>
|
||||||
withDirectives(
|
withDirectives(
|
||||||
|
@ -66,7 +72,7 @@ export default defineComponent({
|
||||||
|
|
||||||
&.active {
|
&.active {
|
||||||
color: var(--accent);
|
color: var(--accent);
|
||||||
background: var(--accentedBg);
|
background: var(--accentedBg) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.active):hover {
|
&:not(.active):hover {
|
||||||
|
@ -83,6 +89,26 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.chips {
|
||||||
|
padding: 12px 32px;
|
||||||
|
font-size: .85em;
|
||||||
|
overflow-x: auto;
|
||||||
|
> button {
|
||||||
|
display: flex;
|
||||||
|
gap: 6px;
|
||||||
|
align-items: center;
|
||||||
|
flex: unset;
|
||||||
|
margin: 0;
|
||||||
|
margin-right: 8px;
|
||||||
|
padding: .5em 1em;
|
||||||
|
border-radius: 100px;
|
||||||
|
background: var(--buttonBg);
|
||||||
|
> i {
|
||||||
|
margin-top: -.1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&.max-width_500px {
|
&.max-width_500px {
|
||||||
font-size: 80%;
|
font-size: 80%;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
class="user-card-mini"
|
||||||
:class="[
|
:class="[
|
||||||
$style.root,
|
$style.root,
|
||||||
{ yellow: user.isSilenced, red: user.isSuspended, gray: false },
|
{ yellow: user.isSilenced, red: user.isSuspended, gray: false },
|
||||||
|
|
|
@ -41,37 +41,6 @@
|
||||||
class="note"
|
class="note"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
v-if="clips && clips.length > 0"
|
|
||||||
class="_content clips _gap"
|
|
||||||
>
|
|
||||||
<div class="title">{{ i18n.ts.clip }}</div>
|
|
||||||
<MkA
|
|
||||||
v-for="item in clips"
|
|
||||||
:key="item.id"
|
|
||||||
:to="`/clips/${item.id}`"
|
|
||||||
class="item _panel _gap"
|
|
||||||
>
|
|
||||||
<b>{{ item.name }}</b>
|
|
||||||
<div
|
|
||||||
v-if="item.description"
|
|
||||||
class="description"
|
|
||||||
>
|
|
||||||
{{ item.description }}
|
|
||||||
</div>
|
|
||||||
<div class="user">
|
|
||||||
<MkAvatar
|
|
||||||
:user="item.user"
|
|
||||||
class="avatar"
|
|
||||||
:show-indicator="true"
|
|
||||||
/>
|
|
||||||
<MkUserName
|
|
||||||
:user="item.user"
|
|
||||||
:nowrap="false"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</MkA>
|
|
||||||
</div>
|
|
||||||
<MkButton
|
<MkButton
|
||||||
v-if="!showPrev && hasPrev"
|
v-if="!showPrev && hasPrev"
|
||||||
class="load prev"
|
class="load prev"
|
||||||
|
@ -114,7 +83,6 @@ const props = defineProps<{
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
let note = $ref<null | misskey.entities.Note>();
|
let note = $ref<null | misskey.entities.Note>();
|
||||||
let clips = $ref();
|
|
||||||
let hasPrev = $ref(false);
|
let hasPrev = $ref(false);
|
||||||
let hasNext = $ref(false);
|
let hasNext = $ref(false);
|
||||||
let showPrev = $ref(false);
|
let showPrev = $ref(false);
|
||||||
|
@ -160,9 +128,6 @@ function fetchNote() {
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
note = res;
|
note = res;
|
||||||
Promise.all([
|
Promise.all([
|
||||||
os.api("notes/clips", {
|
|
||||||
noteId: note.id,
|
|
||||||
}),
|
|
||||||
os.api("users/notes", {
|
os.api("users/notes", {
|
||||||
userId: note.userId,
|
userId: note.userId,
|
||||||
untilId: note.id,
|
untilId: note.id,
|
||||||
|
@ -173,8 +138,7 @@ function fetchNote() {
|
||||||
sinceId: note.id,
|
sinceId: note.id,
|
||||||
limit: 1,
|
limit: 1,
|
||||||
}),
|
}),
|
||||||
]).then(([_clips, prev, next]) => {
|
]).then(([prev, next]) => {
|
||||||
clips = _clips;
|
|
||||||
hasPrev = prev.length !== 0;
|
hasPrev = prev.length !== 0;
|
||||||
hasNext = next.length !== 0;
|
hasNext = next.length !== 0;
|
||||||
});
|
});
|
||||||
|
@ -220,10 +184,6 @@ definePageMetadata(
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
:global(html, body) {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
|
|
||||||
.fcuexfpr {
|
.fcuexfpr {
|
||||||
#calckey_app > :not(.wallpaper) & {
|
#calckey_app > :not(.wallpaper) & {
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
|
@ -251,34 +211,6 @@ definePageMetadata(
|
||||||
background: var(--panel);
|
background: var(--panel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .clips {
|
|
||||||
> .title {
|
|
||||||
font-weight: bold;
|
|
||||||
padding: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .item {
|
|
||||||
display: block;
|
|
||||||
padding: 16px;
|
|
||||||
|
|
||||||
> .description {
|
|
||||||
padding: 8px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .user {
|
|
||||||
$height: 32px;
|
|
||||||
padding-top: 16px;
|
|
||||||
border-top: solid 0.5px var(--divider);
|
|
||||||
line-height: $height;
|
|
||||||
|
|
||||||
> .avatar {
|
|
||||||
width: $height;
|
|
||||||
height: $height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue