Add show more button to notifications + make show more button into its own component

This commit is contained in:
Freeplay 2023-04-28 18:18:09 -04:00
parent e4d995406c
commit 3cc7979aad
5 changed files with 143 additions and 78 deletions

View file

@ -66,5 +66,41 @@ const toggle = () => {
background: var(--cwFg) !important;
color: var(--cwBg) !important;
}
&.fade {
display: block;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
> span {
display: inline-block;
background: var(--panel);
padding: 0.4em 1em;
font-size: 0.8em;
border-radius: 999px;
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
}
&:hover {
> span {
background: var(--panelHighlight);
}
}
}
&.showLess {
width: 100%;
margin-top: 1em;
position: sticky;
bottom: var(--stickyBottom);
> span {
display: inline-block;
background: var(--panel);
padding: 6px 10px;
font-size: 0.8em;
border-radius: 999px;
box-shadow: 0 0 7px 7px var(--bg);
}
}
}
</style>

View file

@ -89,7 +89,7 @@
/>
</div>
</div>
<div class="tail">
<div class="tail" :class="{ collapsed }">
<header>
<span v-if="notification.type === 'pollEnded'">{{
i18n.ts._notification.pollEnded
@ -112,11 +112,11 @@
v-if="notification.type === 'reaction'"
class="text"
:to="notePage(notification.note)"
:title="getNoteSummary(notification.note)"
:title="summary"
>
<i class="ph-quotes ph-fill ph-lg"></i>
<Mfm
:text="getNoteSummary(notification.note)"
:text="summary"
:plain="true"
:nowrap="!full"
:custom-emojis="notification.note.emojis"
@ -142,10 +142,10 @@
v-if="notification.type === 'reply'"
class="text"
:to="notePage(notification.note)"
:title="getNoteSummary(notification.note)"
:title="summary"
>
<Mfm
:text="getNoteSummary(notification.note)"
:text="summary"
:plain="true"
:nowrap="!full"
:custom-emojis="notification.note.emojis"
@ -155,10 +155,10 @@
v-if="notification.type === 'mention'"
class="text"
:to="notePage(notification.note)"
:title="getNoteSummary(notification.note)"
:title="summary"
>
<Mfm
:text="getNoteSummary(notification.note)"
:text="summary"
:plain="true"
:nowrap="!full"
:custom-emojis="notification.note.emojis"
@ -168,10 +168,10 @@
v-if="notification.type === 'quote'"
class="text"
:to="notePage(notification.note)"
:title="getNoteSummary(notification.note)"
:title="summary"
>
<Mfm
:text="getNoteSummary(notification.note)"
:text="summary"
:plain="true"
:nowrap="!full"
:custom-emojis="notification.note.emojis"
@ -181,11 +181,11 @@
v-if="notification.type === 'pollVote'"
class="text"
:to="notePage(notification.note)"
:title="getNoteSummary(notification.note)"
:title="summary"
>
<i class="ph-quotes ph-fill ph-lg"></i>
<Mfm
:text="getNoteSummary(notification.note)"
:text="summary"
:plain="true"
:nowrap="!full"
:custom-emojis="notification.note.emojis"
@ -196,11 +196,11 @@
v-if="notification.type === 'pollEnded'"
class="text"
:to="notePage(notification.note)"
:title="getNoteSummary(notification.note)"
:title="summary"
>
<i class="ph-quotes ph-fill ph-lg"></i>
<Mfm
:text="getNoteSummary(notification.note)"
:text="summary"
:plain="true"
:nowrap="!full"
:custom-emojis="notification.note.emojis"
@ -264,6 +264,7 @@
<span v-if="notification.type === 'app'" class="text">
<Mfm :text="notification.body" :nowrap="!full" />
</span>
<xShowMoreButton v-if="isLong" v-model="collapsed"></xShowMoreButton>
</div>
</div>
</template>
@ -274,6 +275,7 @@ import * as misskey from "calckey-js";
import XReactionIcon from "@/components/MkReactionIcon.vue";
import MkFollowButton from "@/components/MkFollowButton.vue";
import XReactionTooltip from "@/components/MkReactionTooltip.vue";
import XShowMoreButton from "./MkShowMoreButton.vue";
import { getNoteSummary } from "@/scripts/get-note-summary";
import { notePage } from "@/filters/note";
import { userPage } from "@/filters/user";
@ -299,12 +301,19 @@ const props = withDefaults(
const elRef = ref<HTMLElement>(null);
const reactionRef = ref(null);
const summary = getNoteSummary(props.notification.note);
const showEmojiReactions =
defaultStore.state.enableEmojiReactions ||
defaultStore.state.showEmojisInReactionNotifications;
const defaultReaction = ["⭐", "👍", "❤️"].includes(instance.defaultReaction)
? instance.defaultReaction
: "⭐";
const isLong = (summary.split("\n").length > 3 || summary.length > 200);
const collapsed = $ref(isLong);
let readObserver: IntersectionObserver | undefined;
let connection;
@ -486,6 +495,7 @@ useTooltip(reactionRef, (showing) => {
}
> .tail {
position: relative;
flex: 1;
min-width: 0;
@ -526,6 +536,17 @@ useTooltip(reactionRef, (showing) => {
margin-left: 4px;
}
}
&.collapsed > .text {
display: block;
position: relative;
max-height: calc(4em + 50px);
overflow: hidden;
mask: linear-gradient(black calc(100% - 64px), transparent);
-webkit-mask: linear-gradient(
black calc(100% - 64px),
transparent
);
}
}
}
</style>

View file

@ -0,0 +1,68 @@
<template>
<button
v-if="modelValue"
class="fade _button"
@click.stop="toggle"
>
<span>{{ i18n.ts.showMore }}</span>
</button>
<button
v-if="!modelValue"
class="showLess _button"
@click.stop="toggle"
>
<span>{{ i18n.ts.showLess }}</span>
</button>
</template>
<script lang="ts" setup>
import { i18n } from "@/i18n";
const props = defineProps<{
modelValue: boolean;
}>();
const emit = defineEmits<{
(ev: "update:modelValue", v: boolean): void;
}>();
const toggle = () => {
emit("update:modelValue", !props.modelValue);
};
</script>
<style lang="scss" scoped>
.fade {
display: block;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
> span {
display: inline-block;
background: var(--panel);
padding: 0.4em 1em;
font-size: 0.8em;
border-radius: 999px;
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
}
&:hover {
> span {
background: var(--panelHighlight);
}
}
}
.showLess {
width: 100%;
margin-top: 1em;
position: sticky;
bottom: var(--stickyBottom);
> span {
display: inline-block;
background: var(--panel);
padding: 6px 10px;
font-size: 0.8em;
border-radius: 999px;
box-shadow: 0 0 7px 7px var(--bg);
}
}
</style>

View file

@ -97,20 +97,7 @@
</div>
</template>
</div>
<button
v-if="isLong && collapsed"
class="fade _button"
@click.stop="collapsed = false"
>
<span>{{ i18n.ts.showMore }}</span>
</button>
<button
v-if="isLong && !collapsed"
class="showLess _button"
@click.stop="collapsed = true"
>
<span>{{ i18n.ts.showLess }}</span>
</button>
<XShowMoreButton v-if="isLong" v-model="collapsed"></XShowMoreButton>
<XCwButton v-if="note.cw" v-model="showContent" :note="note" />
</div>
</div>
@ -124,6 +111,7 @@ import XNoteSimple from "@/components/MkNoteSimple.vue";
import XMediaList from "@/components/MkMediaList.vue";
import XPoll from "@/components/MkPoll.vue";
import MkUrlPreview from "@/components/MkUrlPreview.vue";
import XShowMoreButton from "./MkShowMoreButton.vue";
import XCwButton from "@/components/MkCwButton.vue";
import { extractUrlFromMfm } from "@/scripts/extract-url-from-mfm";
import { i18n } from "@/i18n";
@ -146,6 +134,7 @@ const isLong =
props.note.text != null &&
(props.note.text.split("\n").length > 9 || props.note.text.length > 500);
const collapsed = $ref(props.note.cw == null && isLong);
const urls = props.note.text
? extractUrlFromMfm(mfm.parse(props.note.text)).slice(0, 5)
: null;
@ -264,43 +253,6 @@ let showContent = $ref(false);
top: 40px;
}
}
:deep(.fade) {
display: block;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
> span {
display: inline-block;
background: var(--panel);
padding: 0.4em 1em;
font-size: 0.8em;
border-radius: 999px;
box-shadow: 0 2px 6px rgb(0 0 0 / 20%);
}
&:hover {
> span {
background: var(--panelHighlight);
}
}
}
}
:deep(.showLess) {
width: 100%;
margin-top: 1em;
position: sticky;
bottom: var(--stickyBottom);
> span {
display: inline-block;
background: var(--panel);
padding: 6px 10px;
font-size: 0.8em;
border-radius: 999px;
box-shadow: 0 0 7px 7px var(--bg);
}
}
}
}

View file

@ -55,20 +55,7 @@
:custom-emojis="user.emojis"
/>
</div>
<button
v-if="isLong && collapsed"
class="fade _button"
@click.stop="collapsed = false"
>
<span>{{ i18n.ts.showMore }}</span>
</button>
<button
v-if="isLong && !collapsed"
class="showLess _button"
@click.stop="collapsed = true"
>
<span>{{ i18n.ts.showLess }}</span>
</button>
<XShowMoreButton v-if="isLong" v-model="collapsed"></XShowMoreButton>
<div v-if="user.fields.length > 0" class="fields">
<dl
v-for="(field, i) in user.fields"
@ -128,6 +115,7 @@ import * as Acct from "calckey-js/built/acct";
import type * as misskey from "calckey-js";
import MkFollowButton from "@/components/MkFollowButton.vue";
import { userPage } from "@/filters/user";
import XShowMoreButton from "./MkShowMoreButton.vue";
import * as os from "@/os";
import { $i } from "@/account";
import { i18n } from "@/i18n";