File size: 5,994 Bytes
b8cc2bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import { Component, For, Show, createEffect, onCleanup } from 'solid-js';
import { appStore } from '../stores/appStore';
import { getModelDisplayName, MODELS } from './ModelLoadingOverlay';

interface ContextPanelProps {
  isOpen: boolean;
  onClose: () => void;
  onLoadModel: () => void;
  onOpenDebug: () => void;
  onDeviceSelect?: (id: string) => void;
}

export const ContextPanel: Component<ContextPanelProps> = (props) => {
  createEffect(() => {
    if (!props.isOpen) return;
    const handler = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        e.preventDefault();
        props.onClose();
      }
    };
    document.addEventListener('keydown', handler);
    onCleanup(() => document.removeEventListener('keydown', handler));
  });

  return (
    <Show when={props.isOpen}>
      <div
        class="fixed inset-0 z-40 flex items-center justify-center bg-[var(--color-earthy-dark-brown)]/30 backdrop-blur-sm"
        role="dialog"
        aria-modal="true"
        aria-label="Context and settings"
        onClick={(e) => e.target === e.currentTarget && props.onClose()}
      >
        <div
          class="w-full max-w-md mx-4 bg-[var(--color-earthy-bg)] rounded-2xl border border-[var(--color-earthy-sage)] shadow-xl overflow-hidden"
          onClick={(e) => e.stopPropagation()}
        >
          <div class="px-6 py-4 border-b border-[var(--color-earthy-sage)]/30 flex items-center justify-between">
            <h2 class="text-lg font-semibold tracking-tight text-[var(--color-earthy-dark-brown)]">Context</h2>
            <button
              type="button"
              onClick={props.onClose}
              class="p-2 rounded-full text-[var(--color-earthy-muted-green)] hover:bg-[var(--color-earthy-sage)]/30 transition-colors"
              aria-label="Close"
            >
              <span class="material-symbols-outlined text-xl">close</span>
            </button>
          </div>

          <div class="p-6 space-y-6">
            <section>
              <h3 class="text-[10px] font-bold uppercase tracking-widest text-[var(--color-earthy-soft-brown)] mb-3">Model</h3>
              <div class="flex flex-col gap-2">
                <select
                  class="w-full text-sm bg-white border border-[var(--color-earthy-sage)] rounded-xl px-3 py-2 text-[var(--color-earthy-dark-brown)] focus:outline-none focus:ring-2 focus:ring-[var(--color-earthy-coral)]/30"
                  value={appStore.selectedModelId()}
                  onInput={(e) => appStore.setSelectedModelId((e.target as HTMLSelectElement).value)}
                  disabled={appStore.modelState() === 'loading'}
                >
                  <For each={MODELS}>
                    {(m) => <option value={m.id}>{m.name}</option>}
                  </For>
                </select>
                <p class="text-xs text-[var(--color-earthy-soft-brown)]">
                  {appStore.modelState() === 'ready' ? getModelDisplayName(appStore.selectedModelId()) : appStore.modelState()}
                </p>
                <button
                  type="button"
                  onClick={props.onLoadModel}
                  disabled={appStore.modelState() === 'ready' || appStore.modelState() === 'loading'}
                  class="flex items-center gap-2 px-4 py-2 rounded-full border border-[var(--color-earthy-sage)] text-[var(--color-earthy-muted-green)] hover:bg-[var(--color-earthy-muted-green)] hover:text-white transition-all text-sm font-medium disabled:opacity-50 disabled:cursor-not-allowed"
                >
                  <span class="material-symbols-outlined text-lg">power_settings_new</span>
                  {appStore.modelState() === 'ready' ? 'Model loaded' : appStore.modelState() === 'loading' ? 'Loading...' : 'Load model'}
                </button>
              </div>
            </section>

            <section>
              <h3 class="text-[10px] font-bold uppercase tracking-widest text-[var(--color-earthy-soft-brown)] mb-3">Audio input</h3>
              <select
                class="w-full text-sm bg-white border border-[var(--color-earthy-sage)] rounded-xl px-3 py-2 text-[var(--color-earthy-dark-brown)] focus:outline-none focus:ring-2 focus:ring-[var(--color-earthy-coral)]/30"
                value={appStore.selectedDeviceId()}
                onInput={(e) => {
                  const id = (e.target as HTMLSelectElement).value;
                  appStore.setSelectedDeviceId(id);
                  props.onDeviceSelect?.(id);
                }}
              >
                <For each={appStore.availableDevices()}>
                  {(device) => (
                    <option value={device.deviceId}>
                      {device.label || `Device ${device.deviceId.slice(0, 8)}`}
                    </option>
                  )}
                </For>
              </select>
            </section>

            <section>
              <h3 class="text-[10px] font-bold uppercase tracking-widest text-[var(--color-earthy-soft-brown)] mb-2">Backend</h3>
              <p class="text-sm text-[var(--color-earthy-dark-brown)] font-medium">{appStore.backend().toUpperCase()}</p>
            </section>

            <div class="pt-2 border-t border-[var(--color-earthy-sage)]/30 flex items-center justify-between">
              <span class="text-xs text-[var(--color-earthy-soft-brown)]">Developer</span>
              <button
                type="button"
                onClick={() => {
                  props.onOpenDebug();
                  props.onClose();
                }}
                class="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium text-[var(--color-earthy-muted-green)] hover:bg-[var(--color-earthy-sage)]/30 transition-colors"
              >
                <span class="material-symbols-outlined text-base">bug_report</span>
                Open Debug panel
              </button>
            </div>
          </div>
        </div>
      </div>
    </Show>
  );
};