feat: use swiper for post cover

This commit is contained in:
DIYgod 2023-07-19 17:24:48 +01:00
parent f7fdc1e3fc
commit 88c8c8d586
No known key found for this signature in database
11 changed files with 132 additions and 41 deletions

View File

@ -144,6 +144,7 @@
"serialize-javascript": "6.0.1",
"sharp": "0.32.3",
"sortablejs": "1.15.0",
"swiper": "^10.0.4",
"tailwind-merge": "1.14.0",
"tailwind-scrollbar-hide": "1.1.7",
"tailwindcss-animate": "1.0.6",

View File

@ -347,6 +347,9 @@ dependencies:
sortablejs:
specifier: 1.15.0
version: 1.15.0
swiper:
specifier: ^10.0.4
version: 10.0.4
tailwind-merge:
specifier: 1.14.0
version: 1.14.0
@ -12427,6 +12430,11 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
/swiper@10.0.4:
resolution: {integrity: sha512-DlNR3KiaVkPep6RraZ2tNr7lvyuzELuR+4NZr4wO42t0UworIO3DxDlz8b5Q3uUioh7cJad99EdRJLkPF+r8Ag==}
engines: {node: '>= 4.7.0'}
dev: false
/swr@2.2.0(react@18.2.0):
resolution: {integrity: sha512-AjqHOv2lAhkuUdIiBu9xbuettzAzWXmCEcLONNKJRba87WAefz8Ca9d6ds/SzrPc235n1IxWYdhJ2zF3MNUaoQ==}
peerDependencies:

View File

@ -16,7 +16,7 @@ export default async function HomeLayout({
}) {
return (
<>
<header className="py-5 fixed w-full top-0 bg-white z-[1]">
<header className="py-5 fixed w-full top-0 bg-white z-[2]">
<div className="max-w-screen-xl px-5 mx-auto flex justify-between items-center">
<div className="space-x-14 flex">
<UniLink

View File

@ -48,7 +48,10 @@ const Card = ({
)}
>
<PostCover
cover={post.metadata?.content.cover}
uniqueKey={`${post.characterId}-${post.noteId}`}
images={
post.metadata?.content.images || [post.metadata?.content.cover as any]
}
title={post.metadata?.content?.title}
/>
<div className="px-3 py-2 sm:px-5 sm:py-4 w-full min-w-0 h-[148px] sm:h-[166px] flex flex-col space-y-2 text-sm">

View File

@ -1,17 +1,23 @@
import "swiper/css"
import "swiper/css/effect-fade"
import "swiper/css/navigation"
import "swiper/css/pagination"
import { Autoplay, EffectFade, Navigation, Pagination } from "swiper/modules"
import { Swiper, SwiperSlide } from "swiper/react"
import uniqolor from "uniqolor"
import { Image } from "~/components/ui/Image"
export default function PostCover({
cover,
priority,
images,
title,
uniqueKey,
}: {
cover?: string
priority?: boolean
images?: string[]
title?: string
uniqueKey?: string
}) {
if (!cover) {
if (!images) {
if (title) {
const bgAccent = uniqolor(title, {
saturation: [30, 35],
@ -48,14 +54,62 @@ export default function PostCover({
return (
<>
<div className="xlog-post-cover rounded-t-2xl overflow-hidden flex items-center relative w-full aspect-video border-b">
<Image
className="object-cover w-full sm:group-hover:scale-105 sm:transition-transform sm:duration-400 sm:ease-in-out"
alt="cover"
src={cover}
width={624}
height={351}
priority={priority}
></Image>
{images.length > 1 ? (
<>
<Swiper
pagination={{
type: "progressbar",
}}
loop={true}
navigation={{
prevEl: `#swiper-button-prev-${uniqueKey}`,
nextEl: `#swiper-button-next-${uniqueKey}`,
}}
autoplay={{
delay: 5000,
disableOnInteraction: false,
pauseOnMouseEnter: true,
waitForTransition: false,
}}
effect={"fade"}
speed={1000}
modules={[EffectFade, Autoplay, Pagination, Navigation]}
className="w-full h-full"
>
{images.map((image) => (
<SwiperSlide key={image}>
<Image
className="object-cover w-full sm:group-hover:scale-105 sm:transition-transform sm:duration-400 sm:ease-in-out"
alt="cover"
src={image}
width={624}
height={351}
></Image>
</SwiperSlide>
))}
</Swiper>
<div
id={`swiper-button-prev-${uniqueKey}`}
className="swiper-button left-2"
>
<i className="icon-[mingcute--left-fill]" />
</div>
<div
id={`swiper-button-next-${uniqueKey}`}
className="swiper-button right-2"
>
<i className="icon-[mingcute--right-fill]" />
</div>
</>
) : (
<Image
className="object-cover w-full sm:group-hover:scale-105 sm:transition-transform sm:duration-400 sm:ease-in-out"
alt="cover"
src={images[0]}
width={624}
height={351}
></Image>
)}
</div>
</>
)

View File

@ -1,26 +0,0 @@
import { Image } from "~/components/ui/Image"
export default function PostCover({
cover,
priority,
}: {
cover?: string
priority?: boolean
}) {
if (!cover) return null
return (
<>
<div className="xlog-post-cover rounded-2xl overflow-hidden flex items-center relative w-full sm:w-36 sm:h-36 aspect-video mb-4 sm:mb-0 sm:mr-8">
<Image
className="object-cover w-full sm:w-36 sm:group-hover:scale-105 sm:transition-transform sm:duration-400 esm:ase-in-out"
alt="cover"
src={cover}
width={256}
height={256}
priority={priority}
></Image>
</div>
</>
)
}

View File

@ -529,3 +529,30 @@ textarea.input {
.right {
@apply flex justify-end;
}
.swiper-button {
@apply absolute top-1/2 -translate-y-1/2 bg-white rounded-full z-[1] w-6 h-6 flex items-center justify-center opacity-80;
}
.swiper .swiper-pagination-bullet {
@apply bg-zinc-100 opacity-50 w-[7px] h-[7px];
}
.swiper .swiper-pagination-bullet-active {
@apply opacity-100;
}
.swiper .swiper-pagination-bullets {
@apply leading-3;
}
.swiper .swiper-pagination-progressbar .swiper-pagination-progressbar-fill {
@apply bg-accent;
transition-duration: 5000ms !important;
transition-timing-function: linear;
transform: translate3d(0px, 0px, 0px) scaleX(0) scaleY(1);
}
.swiper .swiper-pagination-progressbar.swiper-pagination-horizontal {
@apply h-[2px] bg-transparent;
}

View File

@ -57,6 +57,25 @@ export const expandCrossbellNote = async ({
)?.address ||
rendered.cover ||
`${SITE_URL}/api/og?noteId=${expandedNote.noteId}&characterId=${expandedNote.characterId}`
expandedNote.metadata.content.images = []
const cover = expandedNote.metadata?.content?.attachments?.find(
(attachment) => attachment.name === "cover",
)?.address
if (cover) {
expandedNote.metadata.content.images.push(cover)
}
expandedNote.metadata.content.images =
expandedNote.metadata.content.images.concat(rendered.images)
if (!expandedNote.metadata.content.images.length) {
expandedNote.metadata.content.images.push(
`${SITE_URL}/api/og?noteId=${expandedNote.noteId}&characterId=${expandedNote.characterId}`,
)
}
expandedNote.metadata.content.images = [
...new Set(expandedNote.metadata.content.images),
]
expandedNote.metadata.content.audio = rendered.audio
expandedNote.metadata.content.frontMatter = rendered.frontMatter

View File

@ -78,6 +78,7 @@ export type ExpandedNote = NoteEntity & {
content: {
summary?: string
cover?: string
images?: string[]
frontMatter?: Record<string, any>
slug?: string
audio?: string

View File

@ -64,6 +64,7 @@ export type MarkdownEnv = {
frontMatter: Record<string, any>
__internal: Record<string, any>
cover: string
images: string[]
audio: string
toc: TocResult | null
tree: Root | null
@ -91,6 +92,7 @@ export const renderPageContent = (
__internal: {},
frontMatter: {},
cover: "",
images: [],
audio: "",
toc: null,
tree: null,
@ -251,6 +253,7 @@ export const renderPageContent = (
excerpt: result?.data.meta.description,
frontMatter: env.frontMatter,
cover: env.cover,
images: env.images,
audio: env.audio,
toc: env.toc,
tree: env.tree,

View File

@ -31,6 +31,7 @@ export const rehypeImage: Plugin<Array<{ env: MarkdownEnv }>, Root> = ({
env.cover = url
first = false
}
env.images.push(url)
if (isExternLink(url)) {
if (!url.startsWith("https:") && IS_PROD) {