your personal website on atproto - mirror
blento.app
1<script lang="ts" module>
2 export const settingsModalState = $state({
3 visible: false,
4 show: () => (settingsModalState.visible = true),
5 hide: () => (settingsModalState.visible = false)
6 });
7</script>
8
9<script lang="ts">
10 import type { WebsiteData } from '$lib/types';
11 import Modal from '$lib/components/modal/Modal.svelte';
12
13 let { data = $bindable() }: { data: WebsiteData } = $props();
14
15 type LayoutMode = NonNullable<WebsiteData['publication']['preferences']>['layoutMode'];
16
17 type LayoutOption = {
18 key: string;
19 value: LayoutMode;
20 label: string;
21 description: string;
22 };
23
24 const options: LayoutOption[] = [
25 {
26 key: 'automatic',
27 value: undefined,
28 label: 'Automatic',
29 description: 'Automatically syncs layouts until both are edited independently'
30 },
31 {
32 key: 'desktop-leads',
33 value: 'desktop-leads',
34 label: 'Desktop drives mobile',
35 description: 'Desktop edits update mobile, mobile edits are independent'
36 },
37 {
38 key: 'mobile-leads',
39 value: 'mobile-leads',
40 label: 'Mobile drives desktop',
41 description: 'Mobile edits update desktop, desktop edits are independent'
42 },
43 {
44 key: 'independent',
45 value: 'independent',
46 label: 'Independent',
47 description: 'Desktop and mobile layouts are fully independent'
48 }
49 ];
50
51 let selected = $derived(data.publication.preferences?.layoutMode ?? 'automatic');
52
53 function selectOption(option: LayoutOption) {
54 data.publication.preferences ??= {};
55 data.publication.preferences.layoutMode = option.value;
56 data = { ...data };
57 }
58</script>
59
60<Modal bind:open={settingsModalState.visible}>
61 <h3 class="text-base-900 dark:text-base-100 text-lg font-semibold">Settings</h3>
62
63 <div class="mt-4">
64 <h4 class="text-base-800 dark:text-base-200 text-sm font-medium">Layout Sync</h4>
65 <p class="text-base-500 dark:text-base-400 mt-1 text-xs">
66 Control how desktop and mobile layouts stay in sync.
67 </p>
68
69 <div class="mt-3 flex flex-col gap-2">
70 {#each options as option (option.key)}
71 {@const isSelected = option.key === (selected === undefined ? 'automatic' : selected)}
72 <button
73 type="button"
74 class="border-base-200 dark:border-base-700 hover:border-base-300 dark:hover:border-base-600 rounded-xl border-2 px-4 py-3 text-left transition-colors {isSelected
75 ? 'border-accent-500 bg-accent-50 dark:bg-accent-950/20'
76 : 'bg-base-50 dark:bg-base-800/50'}"
77 onclick={() => selectOption(option)}
78 >
79 <span
80 class="text-sm font-semibold {isSelected
81 ? 'text-accent-700 dark:text-accent-300'
82 : 'text-base-900 dark:text-base-100'}"
83 >
84 {option.label}
85 </span>
86 <p
87 class="mt-0.5 text-xs {isSelected
88 ? 'text-accent-600 dark:text-accent-400'
89 : 'text-base-500 dark:text-base-400'}"
90 >
91 {option.description}
92 </p>
93 </button>
94 {/each}
95 </div>
96 </div>
97</Modal>