Files
my-notes-viewer/frontend/src/blocks/RichtextBlock.svelte
Sebastian Frank 40ffa8207e feat: add new contact form, hero, features, and richtext blocks; implement scroll-reveal action and update styles
- 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.
2026-02-26 03:54:07 +00:00

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>