58 lines
1.3 KiB
Svelte
58 lines
1.3 KiB
Svelte
<script lang="ts">
|
||
import type { HTMLAttributes } from "svelte/elements";
|
||
|
||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||
id?: string | undefined;
|
||
label?: string;
|
||
expanded?: boolean;
|
||
children?: () => any;
|
||
}
|
||
|
||
let {
|
||
id,
|
||
label = "",
|
||
expanded = $bindable(false),
|
||
class: className = "",
|
||
children,
|
||
...restProps
|
||
}: Props = $props();
|
||
</script>
|
||
|
||
<div {id} class="spoiler-group {className}" {...restProps}>
|
||
<button
|
||
class="btn btn-link p-0 d-flex align-items-center w-100 text-decoration-none spoiler-header"
|
||
onclick={() => (expanded = !expanded)}
|
||
aria-expanded={expanded}>
|
||
<span class="font-monospace fs-5 ms-1 fw-bold text-muted spoiler-icon" class:expanded>
|
||
{expanded ? "−" : "+"}
|
||
</span>
|
||
<span class="small text-nowrap ms-1">{label}</span>
|
||
<div class="flex-fill border-top ms-1"></div>
|
||
</button>
|
||
|
||
{#if expanded}
|
||
<div class="p-2 border border-top-0 spoiler-content">
|
||
{@render children?.()}
|
||
</div>
|
||
{:else}
|
||
<div style="padding-top: 0.75em;" class={className}></div>
|
||
{/if}
|
||
</div>
|
||
|
||
<style>
|
||
.spoiler-header {
|
||
margin-bottom: -0.75em;
|
||
}
|
||
.spoiler-content {
|
||
padding-top: 0.75em !important;
|
||
}
|
||
|
||
.spoiler-icon {
|
||
line-height: 1;
|
||
padding-bottom: 0.1em;
|
||
}
|
||
|
||
.btn:hover .spoiler-icon {
|
||
color: var(--bs-dark) !important;
|
||
}
|
||
</style>
|