mirror of
https://github.com/liyunze-coding/RythonDev.git
synced 2026-11-06 10:53:33 +00:00
177 lines
4.2 KiB
Svelte
177 lines
4.2 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from "svelte";
|
|
|
|
interface Props {
|
|
position?: "left" | "right";
|
|
image_src: string;
|
|
image_alt: string;
|
|
video_src: string;
|
|
title: string;
|
|
description: string;
|
|
tags?: Array<string>;
|
|
}
|
|
|
|
let {
|
|
position = "left",
|
|
image_src,
|
|
image_alt,
|
|
video_src,
|
|
title,
|
|
description,
|
|
tags = [],
|
|
}: Props = $props();
|
|
|
|
const positionLeft = $derived(position === "left");
|
|
const side = $derived(positionLeft ? "left" : "right");
|
|
|
|
onMount(() => {
|
|
const videos = document.querySelectorAll<HTMLVideoElement>(".playable");
|
|
|
|
videos.forEach((video) => {
|
|
// Ensure the video element supports play and pause methods
|
|
if (
|
|
typeof video.play === "function" &&
|
|
typeof video.pause === "function"
|
|
) {
|
|
video.addEventListener("mouseenter", () => {
|
|
video.volume = 0;
|
|
video.muted = true;
|
|
video.play();
|
|
});
|
|
|
|
video.addEventListener("mouseleave", () => {
|
|
video.pause();
|
|
video.currentTime = 0;
|
|
});
|
|
|
|
// Check if the screen width is less than or equal to 768px (mobile screen size)
|
|
if (window.innerWidth <= 768) {
|
|
video.muted = true;
|
|
video.autoplay = true;
|
|
video.loop = true;
|
|
video.play();
|
|
}
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<div
|
|
class="mb-10 flex h-fit w-full flex-col justify-center px-10 lg:flex-row lg:px-20"
|
|
class:lg:flex-row={positionLeft}
|
|
class:lg:flex-row-reverse={!positionLeft}
|
|
>
|
|
<div
|
|
class="image-container relative mb-5 flex aspect-video w-full [perspective:200px] lg:mr-5 lg:mb-0 lg:ml-auto lg:w-1/2"
|
|
>
|
|
{#snippet renderLayer(
|
|
kind: "image" | "video",
|
|
layerClass: string,
|
|
extraClass: string,
|
|
)}
|
|
{#if kind === "image"}
|
|
<img
|
|
src={image_src}
|
|
alt={image_alt}
|
|
class="project-media absolute top-1/2 left-1/2 max-w-full rounded-xl border-2 border-solid border-gray-800 {layerClass} {extraClass} {side}"
|
|
width="700"
|
|
/>
|
|
{:else}
|
|
<!-- svelte-ignore a11y_media_has_caption -->
|
|
<video
|
|
width="700"
|
|
class="project-media playable absolute top-1/2 left-1/2 max-w-full rounded-xl border-2 border-solid border-gray-800 {layerClass} {extraClass} {side}"
|
|
>
|
|
<source src={video_src} type="video/webm" />
|
|
</video>
|
|
{/if}
|
|
{/snippet}
|
|
|
|
{@render renderLayer(
|
|
"image",
|
|
"background-img",
|
|
"opacity-40 brightness-75",
|
|
)}
|
|
{@render renderLayer("video", "frontfacing-vid", "opacity-100")}
|
|
</div>
|
|
<div
|
|
class="flex h-fit w-full flex-col items-center justify-center lg:h-[340px] lg:w-1/2 lg:px-10
|
|
{positionLeft ? 'lg:items-start' : 'lg:items-end'}"
|
|
>
|
|
<h2
|
|
class="mb-5 text-center text-3xl font-bold
|
|
{positionLeft ? 'lg:text-left' : 'lg:text-right'}"
|
|
>
|
|
{title}
|
|
</h2>
|
|
<p
|
|
class="max-w-lg text-center text-xl text-balance lg:max-w-none
|
|
{positionLeft ? 'lg:text-left' : 'lg:text-right'}"
|
|
>
|
|
{description}
|
|
</p>
|
|
<div
|
|
class="mt-5 flex w-full flex-row flex-wrap justify-center
|
|
{positionLeft ? 'lg:justify-start' : 'lg:justify-end'}"
|
|
>
|
|
{#each tags as tag}
|
|
<div
|
|
class="bg-accent my-1 mr-1
|
|
w-fit rounded-full px-3
|
|
py-1 text-black transition-colors duration-300"
|
|
>
|
|
{tag}
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
:global(html[data-theme="light"]) .project-media {
|
|
border-color: #cbd5e1;
|
|
}
|
|
|
|
.background-img.left {
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
.background-img.right {
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
.frontfacing-vid.left {
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
.frontfacing-vid.right {
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
|
|
@media (min-width: 426px) {
|
|
.background-img.left {
|
|
transform: translateX(calc(-50% + 25px))
|
|
translateY(calc(-50% + 5px)) translateZ(-50px) rotateY(5deg);
|
|
}
|
|
|
|
.background-img.right {
|
|
transform: translateX(calc(-50%)) translateY(calc(-50% + 5px))
|
|
translateZ(-50px) rotateY(-3deg);
|
|
}
|
|
|
|
.frontfacing-vid.left {
|
|
transform: translateX(calc(-50% + 35px)) translateY(calc(-50%))
|
|
translateZ(-50px) rotateY(5deg);
|
|
}
|
|
|
|
.frontfacing-vid.right {
|
|
transform: translateX(calc(-50% - 10px)) translateY(-50%)
|
|
translateZ(-50px) rotateY(-3deg);
|
|
}
|
|
|
|
.image-container:hover .frontfacing-vid,
|
|
.image-container:hover .background-img {
|
|
transform: translate(-50%, -50%);
|
|
}
|
|
}
|
|
</style>
|