Files
plspace/src/components/common/Module.svelte
T

56 lines
1.6 KiB
Svelte

<script lang="ts">
/**
* A bordered box with a caption bar — the unit every page is assembled from.
*
* `variant` picks the era-correct chrome:
* panel blue caption bar (left rail)
* band peach caption bar (main column)
* plain no chrome, just the heading
*/
import type { Snippet } from 'svelte'
import type { CustomEmoji } from '$lib/api/types'
import EmojiText from './EmojiText.svelte'
interface Props {
title?: string
/** Custom emoji available to user-derived titles. */
titleEmojis?: CustomEmoji[]
variant?: 'panel' | 'band' | 'plain'
/** Right-aligned link in the caption bar, e.g. "[view all]". */
action?: Snippet
/** Remove body padding, for tables that should meet the border. */
flush?: boolean
/** Extra classes, so callers can add their own styling hook. */
class?: string
children: Snippet
}
let {
title,
titleEmojis,
variant = 'panel',
action,
flush = false,
class: extraClass = '',
children,
}: Props = $props()
const variantClass = $derived(
variant === 'band' ? 'module--band' : variant === 'plain' ? 'module--plain' : '',
)
</script>
<section class="module {variantClass} {extraClass}" data-variant={variant}>
{#if title}
<h2 class="module-header">
<EmojiText class="module-header-title" text={title} emojis={titleEmojis} />
{#if action}
<span class="module-header-action">{@render action()}</span>
{/if}
</h2>
{/if}
<div class="module-body" class:module-body--flush={flush}>
{@render children()}
</div>
</section>