update r2 config for enchunCMS email adapter
This commit is contained in:
195
apps/frontend/src/components/videoHero.astro
Normal file
195
apps/frontend/src/components/videoHero.astro
Normal file
@@ -0,0 +1,195 @@
|
||||
---
|
||||
import { Image } from "astro:assets";
|
||||
interface Props {
|
||||
desktopVideo: string;
|
||||
mobileVideo: string;
|
||||
hideOnDesktop?: boolean;
|
||||
hideOnMobile?: boolean;
|
||||
logo?: string;
|
||||
header: string;
|
||||
subheader: string;
|
||||
useWebmFallback?: boolean;
|
||||
focalPoint?: string;
|
||||
}
|
||||
|
||||
const {
|
||||
desktopVideo,
|
||||
mobileVideo,
|
||||
hideOnDesktop = false,
|
||||
hideOnMobile = false,
|
||||
logo,
|
||||
header,
|
||||
subheader,
|
||||
useWebmFallback = true,
|
||||
focalPoint = "object-right",
|
||||
} = Astro.props;
|
||||
|
||||
// Helper to get base path without extension
|
||||
const getBasePath = (path: string) => path.replace(/\.(mp4|webm)$/i, "");
|
||||
|
||||
// Generate sources based on useWebmFallback
|
||||
const getSources = (inputPath: string) => {
|
||||
const basePath = getBasePath(inputPath);
|
||||
|
||||
if (useWebmFallback) {
|
||||
return [
|
||||
{ src: `${basePath}.webm`, type: "video/webm" },
|
||||
{ src: `${basePath}.mp4`, type: "video/mp4" },
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
src: inputPath,
|
||||
type: inputPath.endsWith(".webm") ? "video/webm" : "video/mp4",
|
||||
},
|
||||
];
|
||||
};
|
||||
---
|
||||
|
||||
<!-- Desktop Video -->
|
||||
<video
|
||||
id="desktop-video"
|
||||
class={`absolute top-0 left-0 w-full h-[100dvh] object-cover z-0 hidden md:block ${focalPoint}`}
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
preload="metadata"
|
||||
>
|
||||
{
|
||||
getSources(desktopVideo).map((source) => (
|
||||
<source src={source.src} type={source.type} />
|
||||
))
|
||||
}
|
||||
</video>
|
||||
|
||||
<!-- Mobile Video -->
|
||||
<video
|
||||
id="mobile-video"
|
||||
class={`absolute top-0 left-0 w-full h-[100dvh] object-cover z-0 md:hidden block`}
|
||||
autoplay
|
||||
muted
|
||||
loop
|
||||
playsinline
|
||||
preload="metadata"
|
||||
>
|
||||
{
|
||||
getSources(mobileVideo).map((source) => (
|
||||
<source src={source.src} type={source.type} />
|
||||
))
|
||||
}
|
||||
</video>
|
||||
|
||||
<!-- Hero Content Overlay -->
|
||||
<section
|
||||
class={`h-[100dvh] -mt-[5rem] flex items-center justify-center relative ${hideOnDesktop ? "hidden md:block" : ""} ${hideOnMobile ? "md:hidden" : ""} z-10 overflow-hidden`}
|
||||
>
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full bg-gradient-to-r from-black/80 to-black/0 flex items-center justify-center"
|
||||
>
|
||||
<div class="text-white max-w-6xl w-full p-8">
|
||||
{
|
||||
logo && (
|
||||
<div class="flex items-center justify-start mb-6">
|
||||
<Image
|
||||
height={182}
|
||||
width={237}
|
||||
src={logo}
|
||||
alt="enchun-ogo"
|
||||
class="hidden md:block w-32 h-auto mr-8"
|
||||
/>
|
||||
<div class="flex flex-col items-start justify-start ">
|
||||
<h1 class="text-2xl md:text-6xl text-start leading-tight font-extrabold mb-3 whitespace-break-spaces">
|
||||
{header}
|
||||
</h1>
|
||||
<p class="text-xs md:text-3xl font-light mb-4 leading-relaxed whitespace-nowrap">
|
||||
{subheader}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!logo && (
|
||||
<div class="flex flex-col items-start">
|
||||
<h1 class="text-2xl md:text-6xl text-start leading-tight font-extrabold mb-3 whitespace-break-spaces">
|
||||
{header}
|
||||
</h1>
|
||||
<p class="text-xs md:text-3xl font-light mb-4 leading-relaxed whitespace-nowrap">
|
||||
{subheader}
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
// Enhanced mobile/desktop detection and video loading
|
||||
function initVideoHero() {
|
||||
const desktopVideo = document.getElementById(
|
||||
"desktop-video",
|
||||
) as HTMLVideoElement;
|
||||
const mobileVideo = document.getElementById(
|
||||
"mobile-video",
|
||||
) as HTMLVideoElement;
|
||||
|
||||
if (!desktopVideo || !mobileVideo) return;
|
||||
|
||||
// Function to check if we're on mobile
|
||||
const isMobile = () => window.innerWidth < 768;
|
||||
|
||||
// Function to switch videos based on device
|
||||
const switchVideos = () => {
|
||||
const mobile = isMobile();
|
||||
|
||||
if (mobile) {
|
||||
// On mobile, hide desktop video, show mobile video
|
||||
desktopVideo.style.display = "none";
|
||||
mobileVideo.style.display = "block";
|
||||
} else {
|
||||
// On desktop, show desktop video, hide mobile video
|
||||
desktopVideo.style.display = "block";
|
||||
mobileVideo.style.display = "none";
|
||||
}
|
||||
};
|
||||
|
||||
// Initial switch
|
||||
switchVideos();
|
||||
|
||||
// Listen for resize events
|
||||
window.addEventListener("resize", () => {
|
||||
switchVideos();
|
||||
});
|
||||
|
||||
// Handle video loading errors
|
||||
[desktopVideo, mobileVideo].forEach((video) => {
|
||||
video.addEventListener("error", (e) => {
|
||||
console.warn("Video failed to load:", video.src);
|
||||
// Could fallback to static image here
|
||||
});
|
||||
});
|
||||
|
||||
// Preload videos when they're hidden to improve switching
|
||||
const preloadVideos = () => {
|
||||
[desktopVideo, mobileVideo].forEach((video) => {
|
||||
if (video.style.display === "none") {
|
||||
video.load();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Preload on load
|
||||
window.addEventListener("load", preloadVideos);
|
||||
}
|
||||
|
||||
// Initialize when DOM is ready
|
||||
document.addEventListener("DOMContentLoaded", initVideoHero);
|
||||
// Also initialize immediately if DOM is already ready
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", initVideoHero);
|
||||
} else {
|
||||
initVideoHero();
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user