Compare commits
No commits in common. "156ad5c49952a1f0f79310be8a7af8e06ded6afa" and "db444adcc1e0b08e8c8c51c8d954ebebf1df34ea" have entirely different histories.
156ad5c499
...
db444adcc1
|
@ -60,8 +60,8 @@ pub mod content_type {
|
||||||
use serde::de::Error;
|
use serde::de::Error;
|
||||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||||
|
|
||||||
content_type!(pub ContentActivityStreams, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", "application/activity+json", "application/activity+json; charset=utf-8");
|
content_type!(pub ContentActivityStreams, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", "application/activity+json");
|
||||||
content_type!(pub ContentActivityJson, "application/activity+json", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", "application/activity+json; charset=utf-8");
|
content_type!(pub ContentActivityJson, "application/activity+json", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"");
|
||||||
content_type!(pub ContentHtml, "text/html");
|
content_type!(pub ContentHtml, "text/html");
|
||||||
content_type!(pub ContentJson, "application/json");
|
content_type!(pub ContentJson, "application/json");
|
||||||
content_type!(pub ContentXrdXml, "application/xrd+xml");
|
content_type!(pub ContentXrdXml, "application/xrd+xml");
|
||||||
|
|
|
@ -1,203 +0,0 @@
|
||||||
<template>
|
|
||||||
<component
|
|
||||||
:is="parentType"
|
|
||||||
:tag="tag"
|
|
||||||
:name="name"
|
|
||||||
class="sqadhkmv"
|
|
||||||
:class="{ noGap: noGap }"
|
|
||||||
:data-direction="direction"
|
|
||||||
:data-reversed="reversed ? 'true' : 'false'"
|
|
||||||
>
|
|
||||||
<template v-for="item in effectiveItems" :key="item.key">
|
|
||||||
<slot v-if="item.type === 'item'" :item="item.item"></slot>
|
|
||||||
<div v-else class="separator">
|
|
||||||
<p class="date">
|
|
||||||
<span>
|
|
||||||
<i class="ph-caret-up ph-bold ph-lg icon"></i>
|
|
||||||
{{ item.dateAfter }}
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
{{ item.dateBefore }}
|
|
||||||
<i class="ph-caret-down ph-bold ph-lg icon"></i>
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
</component>
|
|
||||||
</template>
|
|
||||||
<script lang="ts" setup generic="T">
|
|
||||||
import { computed, ref, shallowRef, TransitionGroup, watch } from "vue";
|
|
||||||
import { i18n } from "@/i18n";
|
|
||||||
import { defaultStore } from "@/store";
|
|
||||||
import { magTransProperty } from "@/scripts-mag/mag-util";
|
|
||||||
|
|
||||||
type Item = { id: string } & ({ createdAt: string } | { created_at: string });
|
|
||||||
const props = withDefaults(
|
|
||||||
defineProps<{
|
|
||||||
items: (T & Item)[];
|
|
||||||
direction?: "up" | "down";
|
|
||||||
reversed?: boolean;
|
|
||||||
noGap?: boolean;
|
|
||||||
}>(),
|
|
||||||
{
|
|
||||||
direction: "down",
|
|
||||||
reversed: false,
|
|
||||||
noGap: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
type ItemType =
|
|
||||||
| { type: "separator"; key: string; dateBefore: string; dateAfter: string }
|
|
||||||
| { type: "item"; key: string; item: T & Item };
|
|
||||||
|
|
||||||
const effectiveItems = shallowRef<ItemType[]>([]);
|
|
||||||
|
|
||||||
watch(
|
|
||||||
() => props.items,
|
|
||||||
(itemsNew) => {
|
|
||||||
const listItems: ItemType[] = [];
|
|
||||||
for (let i = 0; i < itemsNew.length; i++) {
|
|
||||||
listItems.push({
|
|
||||||
type: "item",
|
|
||||||
key: itemsNew[i].id,
|
|
||||||
item: itemsNew[i],
|
|
||||||
});
|
|
||||||
|
|
||||||
if (itemsNew.length > i + 1) {
|
|
||||||
const dateAfter = getDateText(itemsNew[i]);
|
|
||||||
const dateBefore = getDateText(itemsNew[i + 1]);
|
|
||||||
|
|
||||||
if (dateBefore === dateAfter) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
listItems.push({
|
|
||||||
type: "separator",
|
|
||||||
key: `${itemsNew[i].id}:separator`,
|
|
||||||
dateBefore,
|
|
||||||
dateAfter,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
effectiveItems.value = listItems;
|
|
||||||
},
|
|
||||||
{ deep: true, immediate: true }
|
|
||||||
);
|
|
||||||
|
|
||||||
function getDateText(item: { createdAt: string } | { created_at: string }) {
|
|
||||||
const dateTime = new Date(
|
|
||||||
magTransProperty(item, "createdAt", "created_at")
|
|
||||||
);
|
|
||||||
const date = dateTime.getDate();
|
|
||||||
const month = dateTime.getMonth() + 1;
|
|
||||||
return i18n.t("monthAndDay", {
|
|
||||||
month: month.toString(),
|
|
||||||
day: date.toString(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const animationEnabled = ref(defaultStore.state.animation);
|
|
||||||
watch(
|
|
||||||
() => defaultStore.state.animation,
|
|
||||||
(val) => (animationEnabled.value = val)
|
|
||||||
);
|
|
||||||
|
|
||||||
const parentType = computed(() =>
|
|
||||||
animationEnabled ? TransitionGroup : HTMLDivElement
|
|
||||||
);
|
|
||||||
const tag = computed(() => (animationEnabled ? "div" : null));
|
|
||||||
const name = computed(() => (animationEnabled ? "list" : null));
|
|
||||||
|
|
||||||
defineSlots<{
|
|
||||||
default(props: { item: T & Item }): any;
|
|
||||||
}>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.sqadhkmv {
|
|
||||||
> *:empty {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> *:not(:last-child) {
|
|
||||||
margin-bottom: var(--margin);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .list-move {
|
|
||||||
transition: transform 0.7s cubic-bezier(0.23, 1, 0.32, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
> .list-enter-active {
|
|
||||||
transition: transform 0.7s cubic-bezier(0.23, 1, 0.32, 1),
|
|
||||||
opacity 0.7s cubic-bezier(0.23, 1, 0.32, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-direction="up"] {
|
|
||||||
> .list-enter-from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(64px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[data-direction="down"] {
|
|
||||||
> .list-enter-from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-64px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> .separator {
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> .date {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 16px;
|
|
||||||
line-height: 32px;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
color: var(--dateLabelFg);
|
|
||||||
|
|
||||||
> span {
|
|
||||||
&:first-child {
|
|
||||||
margin-right: 8px;
|
|
||||||
|
|
||||||
> .icon {
|
|
||||||
margin-right: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-left: 8px;
|
|
||||||
|
|
||||||
> .icon {
|
|
||||||
margin-left: 8px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.noGap {
|
|
||||||
> * {
|
|
||||||
margin: 0 !important;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
&:first-child {
|
|
||||||
border-radius: var(--radius) var(--radius) 0 0;
|
|
||||||
}
|
|
||||||
&:last-child {
|
|
||||||
border-radius: 0 0 var(--radius) var(--radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(:last-child) {
|
|
||||||
border-bottom: solid 0.5px var(--divider);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
|
@ -23,11 +23,7 @@
|
||||||
<MagStreamStatus @reconnect="reload()" />
|
<MagStreamStatus @reconnect="reload()" />
|
||||||
|
|
||||||
<XList
|
<XList
|
||||||
v-slot="{
|
v-slot="{ item: notificationGroup }"
|
||||||
item: notificationGroup,
|
|
||||||
}: {
|
|
||||||
item: NotificationGroup,
|
|
||||||
}"
|
|
||||||
class="elsfgstc"
|
class="elsfgstc"
|
||||||
:items="items"
|
:items="items"
|
||||||
:no-gap="true"
|
:no-gap="true"
|
||||||
|
@ -95,7 +91,7 @@ import {
|
||||||
} from "vue";
|
} from "vue";
|
||||||
import XNotification from "@/components/MagNotification.vue";
|
import XNotification from "@/components/MagNotification.vue";
|
||||||
import XNotificationGroup from "@/components/MagNotificationGroup.vue";
|
import XNotificationGroup from "@/components/MagNotificationGroup.vue";
|
||||||
import XList from "@/components/MagDateSeparatedList.vue";
|
import XList from "@/components/MkDateSeparatedList.vue";
|
||||||
import XNote from "@/components/MagNote.vue";
|
import XNote from "@/components/MagNote.vue";
|
||||||
import MagStreamStatus from "@/components/MagStreamStatus.vue";
|
import MagStreamStatus from "@/components/MagStreamStatus.vue";
|
||||||
import { magStream, stream } from "@/stream";
|
import { magStream, stream } from "@/stream";
|
||||||
|
|
|
@ -0,0 +1,209 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { defineComponent, h, PropType, TransitionGroup } from "vue";
|
||||||
|
import { i18n } from "@/i18n";
|
||||||
|
import { defaultStore } from "@/store";
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
props: {
|
||||||
|
items: {
|
||||||
|
type: Array as PropType<
|
||||||
|
{
|
||||||
|
id: string;
|
||||||
|
createdAt?: string;
|
||||||
|
created_at?: string;
|
||||||
|
}[]
|
||||||
|
>,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
direction: {
|
||||||
|
type: String,
|
||||||
|
required: false,
|
||||||
|
default: "down",
|
||||||
|
},
|
||||||
|
reversed: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
noGap: {
|
||||||
|
type: Boolean,
|
||||||
|
required: false,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
setup(props, { slots, expose }) {
|
||||||
|
function getDateText(time: string) {
|
||||||
|
const date = new Date(time).getDate();
|
||||||
|
const month = new Date(time).getMonth() + 1;
|
||||||
|
return i18n.t("monthAndDay", {
|
||||||
|
month: month.toString(),
|
||||||
|
day: date.toString(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.items.length === 0) return;
|
||||||
|
|
||||||
|
const renderChildren = () =>
|
||||||
|
props.items.map((item, i) => {
|
||||||
|
if (!slots || !slots.default) return;
|
||||||
|
|
||||||
|
const el = slots.default({
|
||||||
|
item: item,
|
||||||
|
})[0];
|
||||||
|
if (el.key == null && item.id) el.key = item.id;
|
||||||
|
|
||||||
|
if (
|
||||||
|
i !== props.items.length - 1 &&
|
||||||
|
new Date(item.createdAt || item.created_at!).getDate() !==
|
||||||
|
new Date(
|
||||||
|
props.items[i + 1].createdAt ||
|
||||||
|
props.items[i + 1].created_at!
|
||||||
|
).getDate()
|
||||||
|
) {
|
||||||
|
const separator = h(
|
||||||
|
"div",
|
||||||
|
{
|
||||||
|
class: "separator",
|
||||||
|
key: item.id + ":separator",
|
||||||
|
},
|
||||||
|
h(
|
||||||
|
"p",
|
||||||
|
{
|
||||||
|
class: "date",
|
||||||
|
},
|
||||||
|
[
|
||||||
|
h("span", [
|
||||||
|
h("i", {
|
||||||
|
class: "ph-caret-up ph-bold ph-lg icon",
|
||||||
|
}),
|
||||||
|
getDateText(
|
||||||
|
item.createdAt || item.created_at!
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
h("span", [
|
||||||
|
getDateText(
|
||||||
|
props.items[i + 1].createdAt ||
|
||||||
|
props.items[i + 1].created_at!
|
||||||
|
),
|
||||||
|
h("i", {
|
||||||
|
class: "ph-caret-down ph-bold ph-lg icon",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return [el, separator];
|
||||||
|
}
|
||||||
|
|
||||||
|
return el;
|
||||||
|
});
|
||||||
|
|
||||||
|
return () =>
|
||||||
|
h(
|
||||||
|
defaultStore.state.animation ? TransitionGroup : "div",
|
||||||
|
defaultStore.state.animation
|
||||||
|
? {
|
||||||
|
class: "sqadhkmv" + (props.noGap ? " noGap" : ""),
|
||||||
|
name: "list",
|
||||||
|
tag: "div",
|
||||||
|
"data-direction": props.direction,
|
||||||
|
"data-reversed": props.reversed ? "true" : "false",
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
class: "sqadhkmv" + (props.noGap ? " noGap" : ""),
|
||||||
|
},
|
||||||
|
{ default: renderChildren }
|
||||||
|
);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.sqadhkmv {
|
||||||
|
> *:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
> *:not(:last-child) {
|
||||||
|
margin-bottom: var(--margin);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .list-move {
|
||||||
|
transition: transform 0.7s cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .list-enter-active {
|
||||||
|
transition: transform 0.7s cubic-bezier(0.23, 1, 0.32, 1),
|
||||||
|
opacity 0.7s cubic-bezier(0.23, 1, 0.32, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-direction="up"] {
|
||||||
|
> .list-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(64px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[data-direction="down"] {
|
||||||
|
> .list-enter-from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(-64px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .separator {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
> .date {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 16px;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--dateLabelFg);
|
||||||
|
|
||||||
|
> span {
|
||||||
|
&:first-child {
|
||||||
|
margin-right: 8px;
|
||||||
|
|
||||||
|
> .icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
> .icon {
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.noGap {
|
||||||
|
> * {
|
||||||
|
margin: 0 !important;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
&:first-child {
|
||||||
|
border-radius: var(--radius) var(--radius) 0 0;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
border-radius: 0 0 var(--radius) var(--radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
border-bottom: solid 0.5px var(--divider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -15,7 +15,7 @@
|
||||||
<div class="giivymft" :class="{ noGap }">
|
<div class="giivymft" :class="{ noGap }">
|
||||||
<XList
|
<XList
|
||||||
ref="notes"
|
ref="notes"
|
||||||
v-slot="{ item: note }: { item: Misskey.entities.Note }"
|
v-slot="{ item: note }"
|
||||||
:items="notes"
|
:items="notes"
|
||||||
:direction="pagination.reversed ? 'up' : 'down'"
|
:direction="pagination.reversed ? 'up' : 'down'"
|
||||||
:reversed="pagination.reversed"
|
:reversed="pagination.reversed"
|
||||||
|
@ -38,12 +38,11 @@ import { ref } from "vue";
|
||||||
import type { Paging } from "@/components/MkPagination.vue";
|
import type { Paging } from "@/components/MkPagination.vue";
|
||||||
import MkPagination from "@/components/MkPagination.vue";
|
import MkPagination from "@/components/MkPagination.vue";
|
||||||
import XNoteResolvingProxy from "@/components/MagNoteResolvingProxy.vue";
|
import XNoteResolvingProxy from "@/components/MagNoteResolvingProxy.vue";
|
||||||
import XList from "@/components/MagDateSeparatedList.vue";
|
import XList from "@/components/MkDateSeparatedList.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { noteIsMag } from "@/scripts-mag/mag-util";
|
import { noteIsMag } from "@/scripts-mag/mag-util";
|
||||||
import type * as Misskey from "calckey-js";
|
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{
|
||||||
pagination: Paging;
|
pagination: Paging;
|
||||||
noGap?: boolean;
|
noGap?: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
|
@ -16,18 +16,14 @@
|
||||||
|
|
||||||
<template #default="{ items }">
|
<template #default="{ items }">
|
||||||
<XList
|
<XList
|
||||||
v-slot="{
|
v-slot="{ item }"
|
||||||
item,
|
|
||||||
}: {
|
|
||||||
item: Misskey.entities.NoteFavorite,
|
|
||||||
}"
|
|
||||||
:items="items"
|
:items="items"
|
||||||
:direction="'down'"
|
:direction="'down'"
|
||||||
:no-gap="false"
|
:no-gap="false"
|
||||||
>
|
>
|
||||||
<XNoteResolvingProxy
|
<XNoteResolvingProxy
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:note="item.noteId"
|
:note="item.note"
|
||||||
:class="$style.note"
|
:class="$style.note"
|
||||||
/>
|
/>
|
||||||
</XList>
|
</XList>
|
||||||
|
@ -41,10 +37,9 @@
|
||||||
import { ref } from "vue";
|
import { ref } from "vue";
|
||||||
import MkPagination from "@/components/MkPagination.vue";
|
import MkPagination from "@/components/MkPagination.vue";
|
||||||
import XNoteResolvingProxy from "@/components/MagNoteResolvingProxy.vue";
|
import XNoteResolvingProxy from "@/components/MagNoteResolvingProxy.vue";
|
||||||
import XList from "@/components/MagDateSeparatedList.vue";
|
import XList from "@/components/MkDateSeparatedList.vue";
|
||||||
import { i18n } from "@/i18n";
|
import { i18n } from "@/i18n";
|
||||||
import { definePageMetadata } from "@/scripts/page-metadata";
|
import { definePageMetadata } from "@/scripts/page-metadata";
|
||||||
import type * as Misskey from "calckey-js";
|
|
||||||
|
|
||||||
const pagination = {
|
const pagination = {
|
||||||
endpoint: "i/favorites" as const,
|
endpoint: "i/favorites" as const,
|
||||||
|
|
Loading…
Reference in New Issue