~james/core

core/web/src/lib/components/settings/SettingsRow.svelte -rw-r--r-- 2.6 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
<script lang="ts">
	import type { Component, Snippet } from "svelte";
	import type { SvelteHTMLElements } from "svelte/elements";
	import { resolve } from "$app/paths";
	import Link from "#lib/components/ui/Link.svelte";
	import { tv } from "tailwind-variants";
	import { toLines } from "#lib/components/settings/descriptionLines.ts";

	interface Props {
		icon?: Component<SvelteHTMLElements["svg"]>;
		title?: string;
		href?: string;
		description?: string | string[];
		tags?: Snippet;
		meta?: Snippet;
		label?: Snippet;
		children?: Snippet;
		align?: "center" | "start";
		stack?: boolean;
	}

	let {
		icon,
		title,
		href,
		description,
		tags,
		meta,
		label,
		children,
		align = "center",
		stack = false
	}: Props = $props();

	const row = tv({
		slots: {
			base: "flex min-h-2xl w-full justify-between",
			actions: "flex items-center gap-xs empty:hidden"
		},
		variants: {
			stack: {
				true: {
					base: "flex-col justify-center gap-xs sm:flex-row sm:justify-between sm:gap-md",
					actions: "w-full justify-end sm:w-auto sm:shrink-0"
				},
				false: {
					base: "gap-md",
					actions: "shrink-0"
				}
			},
			align: {
				start: {},
				center: {}
			}
		},
		compoundVariants: [
			{ align: "start", stack: false, class: { base: "items-start" } },
			{ align: "start", stack: true, class: { base: "sm:items-start" } },
			{ align: "center", stack: false, class: { base: "items-center" } },
			{ align: "center", stack: true, class: { base: "sm:items-center" } }
		]
	});

	const classes = $derived(row({ stack, align }));

	const Glyph = $derived(icon);
	const lines = $derived(toLines(description));
</script>

<div class={classes.base()}>
	{#if label}
		{@render label()}
	{:else}
		<span class="flex min-w-0 flex-col gap-2xs">
			<span class="flex min-w-0 flex-wrap items-center gap-xs">
				{#if Glyph}
					<Glyph class="size-3.5 shrink-0 text-foreground-default" aria-hidden="true" />
				{/if}
				{#if href}
					<Link
						href={resolve(href as "/")}
						variant="inherit"
						class="min-w-0 wrap-anywhere">{title}</Link
					>
				{:else}
					<span
						data-testid="settingsRowTitle"
						class="min-w-0 typography-paragraph-regular wrap-anywhere text-foreground-default"
						>{title}</span
					>
				{/if}
				{#if tags}
					{@render tags()}
				{/if}
			</span>
			{#if meta}
				{@render meta()}
			{:else}
				{#each lines as line (line)}
					<span class="typography-paragraph-regular wrap-anywhere text-foreground-muted"
						>{line}</span
					>
				{/each}
			{/if}
		</span>
	{/if}
	{#if children}
		<div class={classes.actions()}>
			{@render children()}
		</div>
	{/if}
</div>