atagen

malice

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