Add vibrant color into media card title

This commit is contained in:
2026-01-16 08:15:19 +05:00
parent 1d56d8ed5d
commit 3289a71e8b
7 changed files with 235 additions and 6 deletions

View File

@ -0,0 +1,60 @@
<script setup lang="ts">
import type { VNodeRef } from "vue";
import tinycolor from "tinycolor2"
const imageElement = shallowRef<VNodeRef | null>(null);
const palette = useVibrantPalette(imageElement);
const paletteVibrantHsl = ref<string>('');
watch(palette, () => {
if (!palette.value?.Vibrant) return;
const [hue, saturation, lightness] = palette.value.Vibrant.hsl;
const lighterColor = tinycolor({ h: hue * 360, s: saturation, l: lightness }).brighten().desaturate().toHslString()
paletteVibrantHsl.value = lighterColor;
});
interface Props {
image_url: string;
image_alt?: string;
title: string;
type: 'anime' | 'manga' | 'character' | 'voice_actor';
subtitle?: string;
description?: string;
tooltipEnabled?: boolean;
tooltipMetadata?: {
studio: string;
type: string;
episodes: number;
rating: number;
tags?: string[];
};
dynamicColor?: boolean;
onClick?: () => void;
onHover?: (isHovering: boolean) => void;
}
const props = defineProps<Props>();
</script>
<template>
<div class="rounded-lg h-full overflow-hidden max-w-64">
<div class="flex flex-col gap-2 cursor-pointer text-muted-foreground vibrant-color">
<NuxtImg ref="imageElement" :src="props.image_url" sizes="128px md:256px" quality="100" />
<p class="text-lg line-clamp-2 font-semibold">
{{ props.title }}
</p>
</div>
</div>
</template>
<style scoped>
.vibrant-color:hover {
color: v-bind(paletteVibrantHsl);
}
</style>

View File

@ -0,0 +1,18 @@
<script setup lang="ts">
import { cn } from '~/lib/utils';
interface Props {
class?: string;
}
const props = defineProps<Props>();
</script>
<template>
<div :class="cn('rounded-lg h-full overflow-hidden w-full max-w-64', props.class)">
<div class="flex flex-col gap-2 h-full pb-6">
<Skeleton class="h-full w-full" />
<Skeleton class="h-6 w-3/4" />
</div>
</div>
</template>

View File

@ -0,0 +1,15 @@
import type { Palette } from "@vibrant/color";
import { Vibrant } from "node-vibrant/browser";
export const useVibrantPalette = (imageRef: Ref) => {
if (import.meta.server) {
return ref<Palette | null>(null);
}
return computedAsync(async () => {
if (!imageRef.value?.$el) return null;
const vibrant = Vibrant.from(imageRef.value.$el);
const palette = await vibrant.getPalette();
return palette || null;
}, null);
};

View File

@ -1,6 +1,8 @@
<script setup lang="ts">
import { Search, SlidersHorizontal } from 'lucide-vue-next';
import HeroSection from '@/components/ui/internal/HeroSection.vue';
import MediaImageCard from '~/components/ui/internal/MediaImageCard.vue';
import SkeletonMediaImageCard from '~/components/ui/internal/SkeletonMediaImageCard.vue';
</script>
@ -19,7 +21,7 @@ import HeroSection from '@/components/ui/internal/HeroSection.vue';
<SlidersHorizontal />
</Button>
</div>
<div class="w-full">
<div class="w-full flex flex-col items-center gap-4 max-w-full xl:max-w-3/4">
<div class="flex w-full justify-between">
<Button variant="ghost" class="text-2xl font-bold tracking-tight">
TRENDING NOW
@ -28,8 +30,29 @@ import HeroSection from '@/components/ui/internal/HeroSection.vue';
View all
</Button>
</div>
<div>
Test
<div
class="grid grid-cols-3 md:grid-cols-4 lg:grid-cols-5 2xl:grid-cols-6 gap-4 gap-y-12 justify-items-center w-full">
<MediaImageCard image_url="example/jigokuraku.jpg" title="Jigokuraku 2nd Season" type="anime" />
<MediaImageCard image_url="example/jujutsukaisen.jpg"
title="Jujutsu Kaisen: Shimetsu Kaiyuu - Zenpen" type="anime" />
<MediaImageCard image_url="example/okiraku.jpg" title="Okiraku Ryoushu no Tanoshii Ryouchi Bouei"
type="anime" />
<MediaImageCard image_url="example/oshi no ko.jpg" title="[Oshi no Ko] 3rd Season" type="anime" />
<MediaImageCard image_url="example/shibou.jpg" title="Shibou Yuugi de Meshi wo Kuu." type="anime" />
<MediaImageCard image_url="example/sousounofrieren.jpg" title="Sousou no Frieren 2nd Season"
type="anime" />
<MediaImageCard image_url="example/tamonkun.jpg" title="Tamon-kun Ima Docchi!?" type="anime" />
<MediaImageCard image_url="example/yuusha party.jpg" title="Yuusha Party wo Oidasareta Kiyou Binbou"
type="anime" />
<MediaImageCard image_url="example/jujutsukaisen.jpg"
title="Jujutsu Kaisen: Shimetsu Kaiyuu - Zenpen soetjsot giwjiagjwiag wgi wajig wig gwi"
type="anime" />
<MediaImageCard image_url="example/okiraku.jpg"
title="Okiraku Ryoushu no Tanoshii Ryouchi Bouei teisotsoeitj wgjiwag wgj wigwji"
type="anime" />
<MediaImageCard image_url="example/oshi no ko.jpg"
title="[Oshi no Ko] 3rd Season iaowjegiogjoiawgio waiogjawiog wag" type="anime" />
<SkeletonMediaImageCard />
</div>
</div>
</div>