| 1 | <script lang="ts"> |
| 2 | import { createEventDispatcher } from 'svelte'; |
| 3 | import { |
| 4 | LINE_HEIGHT_DEFAULT, |
| 5 | LINE_HEIGHT_MAX, |
| 6 | LINE_HEIGHT_MIN, |
| 7 | MESSAGE_SPACING_DEFAULT, |
| 8 | MESSAGE_SPACING_MAX, |
| 9 | MESSAGE_SPACING_MIN, |
| 10 | lineHeight, |
| 11 | messageSpacing |
| 12 | } from './appearance'; |
| 13 | import { DEFAULT_QUICK_REACTIONS } from './quick-reactions'; |
| 14 | import ReactionPicker from './ReactionPicker.svelte'; |
| 15 | import ThemeSettings from './ThemeSettings.svelte'; |
| 16 | import KeywordSettings from './KeywordSettings.svelte'; |
| 17 | import NotificationSettings from './NotificationSettings.svelte'; |
| 18 | import type { ImagePack, QuickReaction } from './types'; |
| 19 | |
| 20 | export let quick: QuickReaction[]; |
| 21 | export let packs: ImagePack[] = []; |
| 22 | export let onQuickChange: (list: QuickReaction[]) => void; |
| 23 | |
| 24 | const dispatch = createEventDispatcher<{ close: void; packs: void }>(); |
| 25 | |
| 26 | $: quickIsDefault = |
| 27 | quick.length === DEFAULT_QUICK_REACTIONS.length && quick.every((r, i) => r.key === DEFAULT_QUICK_REACTIONS[i].key); |
| 28 | |
| 29 | </script> |
| 30 | |
| 31 | <div class="modal settings" role="dialog" aria-modal="true" aria-label="Settings"> |
| 32 | <div class="modal-tabs" role="tablist" aria-label="Settings"> |
| 33 | <button type="button" role="tab" aria-selected="true" class="active">Settings</button> |
| 34 | <button type="button" class="icon-btn modal-x" aria-label="Close settings" on:click={() => dispatch('close')}> |
| 35 | <span aria-hidden="true">✕</span> |
| 36 | </button> |
| 37 | </div> |
| 38 | |
| 39 | <ThemeSettings /> |
| 40 | |
| 41 | <section aria-label="Message spacing"> |
| 42 | <h3 class="sec-h">Space between messages</h3> |
| 43 | <div class="range"> |
| 44 | <input |
| 45 | type="range" |
| 46 | min={MESSAGE_SPACING_MIN} |
| 47 | max={MESSAGE_SPACING_MAX} |
| 48 | step="1" |
| 49 | bind:value={$messageSpacing} |
| 50 | aria-label="Space between messages in pixels" |
| 51 | /> |
| 52 | <span class="value">{$messageSpacing}px</span> |
| 53 | <button |
| 54 | type="button" |
| 55 | class="ghost-btn" |
| 56 | disabled={$messageSpacing === MESSAGE_SPACING_DEFAULT} |
| 57 | on:click={() => messageSpacing.set(MESSAGE_SPACING_DEFAULT)} |
| 58 | > |
| 59 | Reset |
| 60 | </button> |
| 61 | </div> |
| 62 | <h3 class="sec-h">Line height</h3> |
| 63 | <div class="range"> |
| 64 | <input |
| 65 | type="range" |
| 66 | min={LINE_HEIGHT_MIN} |
| 67 | max={LINE_HEIGHT_MAX} |
| 68 | step="0.05" |
| 69 | bind:value={$lineHeight} |
| 70 | aria-label="Line height within messages" |
| 71 | /> |
| 72 | <span class="value">{$lineHeight.toFixed(2)}</span> |
| 73 | <button |
| 74 | type="button" |
| 75 | class="ghost-btn" |
| 76 | disabled={$lineHeight === LINE_HEIGHT_DEFAULT} |
| 77 | on:click={() => lineHeight.set(LINE_HEIGHT_DEFAULT)} |
| 78 | > |
| 79 | Reset |
| 80 | </button> |
| 81 | </div> |
| 82 | </section> |
| 83 | |
| 84 | <NotificationSettings /> |
| 85 | |
| 86 | <KeywordSettings /> |
| 87 | |
| 88 | <section aria-label="Quick reactions"> |
| 89 | <div class="sec-head"> |
| 90 | <h3 class="sec-h">Quick reactions</h3> |
| 91 | <button type="button" class="ghost-btn" disabled={quickIsDefault} on:click={() => onQuickChange(DEFAULT_QUICK_REACTIONS)}> |
| 92 | Reset |
| 93 | </button> |
| 94 | </div> |
| 95 | <ReactionPicker embedded {quick} {packs} {onQuickChange} onPick={() => {}} onClose={() => dispatch('close')} /> |
| 96 | </section> |
| 97 | |
| 98 | <section aria-label="Packs"> |
| 99 | <div class="sec-head"> |
| 100 | <h3 class="sec-h">Sticker and emoji packs</h3> |
| 101 | <button type="button" class="ghost-btn" on:click={() => dispatch('packs')}>Manage</button> |
| 102 | </div> |
| 103 | </section> |
| 104 | </div> |
| 105 | |
| 106 | <style> |
| 107 | .settings { max-height: calc(100dvh - 32px); overflow-y: auto; } |
| 108 | section { margin-top: 18px; } |
| 109 | .sec-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; } |
| 110 | .sec-head .sec-h { margin: 0; } |
| 111 | .sec-h { font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin: 0 0 6px; } |
| 112 | .range + .sec-h { margin-top: 12px; } |
| 113 | .range { display: flex; align-items: center; gap: 10px; } |
| 114 | .range input[type='range'] { flex: 1; accent-color: var(--accent); } |
| 115 | .value { font-size: 13px; min-width: 4ch; text-align: right; font-variant-numeric: tabular-nums; } |
| 116 | </style> |