forked from cms/tibi-svelte-starter
- Introduced ContactFormBlock, FeaturesBlock, HeroBlock, and RichtextBlock components. - Implemented a scroll-reveal action for animations on element visibility. - Enhanced CSS styles for better theming and prose formatting. - Added localization support for new components and updated existing translations. - Created e2e tests for demo pages including contact form validation and navigation. - Added a video tour showcasing the demo pages and interactions.
78 lines
2.8 KiB
Svelte
78 lines
2.8 KiB
Svelte
<script lang="ts">
|
|
import { reveal } from "../lib/actions/reveal"
|
|
|
|
let { block }: { block: ContentBlockEntry } = $props()
|
|
|
|
const paddingTop = $derived(
|
|
block.padding?.top === "lg"
|
|
? "pt-20"
|
|
: block.padding?.top === "md"
|
|
? "pt-12"
|
|
: block.padding?.top === "sm"
|
|
? "pt-8"
|
|
: "pt-4"
|
|
)
|
|
const paddingBottom = $derived(
|
|
block.padding?.bottom === "lg"
|
|
? "pb-20"
|
|
: block.padding?.bottom === "md"
|
|
? "pb-12"
|
|
: block.padding?.bottom === "sm"
|
|
? "pb-8"
|
|
: "pb-4"
|
|
)
|
|
|
|
const hasImage = $derived(block.externalImageUrl || block.image)
|
|
const imageOnRight = $derived(block.imagePosition === "right")
|
|
const imageOnLeft = $derived(block.imagePosition === "left")
|
|
const showImage = $derived(hasImage && (imageOnRight || imageOnLeft))
|
|
</script>
|
|
|
|
<section data-block="richtext" class="richtext-section {paddingTop} {paddingBottom}" id={block.anchorId || undefined}>
|
|
<div class="max-w-6xl mx-auto px-6">
|
|
{#if block.tagline}
|
|
<div use:reveal>
|
|
<span class="inline-block text-brand-500 text-sm font-semibold tracking-widest uppercase mb-3">
|
|
{block.tagline}
|
|
</span>
|
|
</div>
|
|
{/if}
|
|
|
|
{#if block.headline}
|
|
<div use:reveal={{ delay: 100 }}>
|
|
<h2 class="text-3xl sm:text-4xl font-display font-bold text-gray-900 mb-8">
|
|
{block.headline}
|
|
</h2>
|
|
</div>
|
|
{/if}
|
|
|
|
{#if showImage}
|
|
<!-- Layout with image -->
|
|
<div class="grid md:grid-cols-2 gap-12 items-center" use:reveal={{ delay: 200 }}>
|
|
<div class:order-2={imageOnLeft} class="prose max-w-none">
|
|
{@html block.text || ""}
|
|
</div>
|
|
<div class:order-1={imageOnLeft} class="relative">
|
|
<div class="rounded-2xl overflow-hidden shadow-xl shadow-brand-900/10">
|
|
<img
|
|
src={block.externalImageUrl || ""}
|
|
alt={block.headline || ""}
|
|
class="w-full h-auto object-cover aspect-4/3"
|
|
loading="lazy"
|
|
/>
|
|
</div>
|
|
<!-- Decorative gradient behind image -->
|
|
<div
|
|
class="absolute -inset-4 -z-10 rounded-3xl bg-linear-to-br from-brand-100 to-brand-50 blur-sm"
|
|
></div>
|
|
</div>
|
|
</div>
|
|
{:else}
|
|
<!-- Text-only layout -->
|
|
<div class="prose max-w-3xl" use:reveal={{ delay: 200 }}>
|
|
{@html block.text || ""}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</section>
|