main
html 188 lines 7.47 KB
Raw
1 <html class="settings-modal">
2 <head>
3 <title>Settings</title>
4 </head>
5
6 <body>
7 <script type="module">
8 import { store as settingsStore } from "/components/settings/settings-store.js";
9 </script>
10
11 <div x-data>
12 <template x-if="$store.settings">
13 <div x-init="$store.settings.onOpen()" x-destroy="$store.settings.cleanup()">
14
15 <!-- Loading state -->
16 <div x-show="$store.settings.isLoading && !$store.settings.settings" class="settings-loading">
17 <x-icon class="spinning" name="progress_activity"></x-icon>
18 <span>Loading settings...</span>
19 </div>
20
21 <!-- Error state -->
22 <div x-show="$store.settings.error && !$store.settings.settings" class="settings-error">
23 <x-icon name="error"></x-icon>
24 <span x-text="$store.settings.error"></span>
25 <button class="btn btn-retry" @click="$store.settings.onOpen()">Retry</button>
26 </div>
27
28 <!-- Settings content -->
29 <div x-show="$store.settings.settings" class="settings-content">
30 <!-- Tab Navigation -->
31 <aside class="settings-tabs-container" aria-label="Settings categories">
32 <div class="settings-search" role="search">
33 <x-icon aria-hidden="true" name="search"></x-icon>
34 <input
35 type="search"
36 x-model.debounce.100ms="$store.settings.searchQuery"
37 @keydown.enter.prevent="$store.settings.openFirstSearchResult()"
38 placeholder="Search"
39 aria-label="Search settings"
40 autocomplete="off"
41 />
42 <button
43 type="button"
44 class="settings-search-clear"
45 x-show="$store.settings.hasSearchQuery"
46 @click="$store.settings.clearSearch()"
47 aria-label="Clear search"
48 >
49 <x-icon aria-hidden="true" name="close"></x-icon>
50 </button>
51 </div>
52
53 <div class="settings-tabs no-scrollbar" role="tablist" aria-orientation="vertical">
54 <template x-for="item in $store.settings.filteredNavItems" :key="item.id">
55 <div class="settings-nav-group"
56 :class="{
57 'settings-nav-group-active': $store.settings.activeTab === item.id,
58 'settings-nav-group-open': $store.settings.isNavGroupExpanded(item.id)
59 }">
60 <button type="button"
61 class="settings-tab settings-parent-tab"
62 role="tab"
63 :aria-selected="$store.settings.activeTab === item.id"
64 :aria-expanded="$store.settings.isNavGroupExpanded(item.id)"
65 :class="{
66 'active': $store.settings.activeTab === item.id,
67 'settings-tab-attention': $store.settings.navItemHasAttention(item)
68 }"
69 @click="$store.settings.toggleNavGroup(item.id)">
70 <x-icon aria-hidden="true" :name="item.icon"></x-icon>
71 <span class="settings-tab-label" x-text="item.label"></span>
72 <span class="settings-tab-meta">
73 <span class="settings-attention-dot"
74 x-show="$store.settings.navItemHasAttention(item)"
75 aria-hidden="true"></span>
76 <x-icon class="settings-tab-chevron"
77 aria-hidden="true" name="expand_more"></x-icon>
78 </span>
79 </button>
80
81 <div class="settings-section-list"
82 x-show="$store.settings.isNavGroupExpanded(item.id)"
83 x-transition.opacity.duration.120ms>
84 <template x-for="section in item.sections" :key="section.id">
85 <a class="settings-section-link"
86 :class="{
87 'active': $store.settings.activeSection === section.id,
88 'settings-tab-attention': $store.settings.sectionItemHasAttention(section)
89 }"
90 :aria-current="$store.settings.activeSection === section.id ? 'true' : null"
91 :href="`#${section.id}`"
92 @click="$store.settings.scrollToSection(section.id, $event)">
93 <x-icon aria-hidden="true" :name="section.icon"></x-icon>
94 <span class="settings-tab-label" x-text="section.label"></span>
95 <span class="settings-attention-dot"
96 x-show="$store.settings.sectionItemHasAttention(section)"
97 aria-hidden="true"></span>
98 </a>
99 </template>
100 </div>
101 </div>
102 </template>
103 <div class="settings-search-empty" x-show="$store.settings.hasSearchQuery && !$store.settings.filteredNavItems.length">
104 No settings found
105 </div>
106 </div>
107 </aside>
108
109 <!-- Settings sections for agent, external, developer, mcp, backup tabs -->
110 <main id="settings-sections" class="settings-pane">
111 <div class="settings-tab-panel" data-settings-tab="agent" x-show="$store.settings.activeTab === 'agent'">
112 <x-component path="settings/agent/agent-settings.html"></x-component>
113 </div>
114 <div class="settings-tab-panel" data-settings-tab="external" x-show="$store.settings.activeTab === 'external'">
115 <x-component path="settings/external/external-settings.html"></x-component>
116 </div>
117 <div class="settings-tab-panel" data-settings-tab="mcp" x-show="$store.settings.activeTab === 'mcp'">
118 <x-component path="settings/mcp/mcp-settings.html"></x-component>
119 </div>
120 <div class="settings-tab-panel" data-settings-tab="developer" x-show="$store.settings.activeTab === 'developer'">
121 <x-component path="settings/developer/developer-settings.html"></x-component>
122 </div>
123 <div class="settings-tab-panel" data-settings-tab="backup" x-show="$store.settings.activeTab === 'backup'">
124 <x-component path="settings/backup/backup-settings.html"></x-component>
125 </div>
126 <div class="settings-tab-panel" data-settings-tab="skills" x-show="$store.settings.activeTab === 'skills'">
127 <x-component path="settings/skills/skills-settings.html"></x-component>
128 </div>
129 </main>
130 </div>
131
132 <!-- Footer -->
133 <div class="modal-footer" data-modal-footer x-show="$store.settings.settings">
134 <button class="btn btn-ok"
135 @click="$store.settings.saveAndClose()"
136 :disabled="$store.settings?.isLoading">
137 Save
138 </button>
139 <button class="btn btn-cancel"
140 @click="$store.settings.closeSettings()">
141 Cancel
142 </button>
143 </div>
144
145 </div>
146 </template>
147 </div>
148 </body>
149 </html>
150
151 <style>
152 .settings-loading,
153 .settings-error {
154 display: flex;
155 flex: 1 1 auto;
156 align-items: center;
157 justify-content: center;
158 align-self: stretch;
159 gap: 0.75rem;
160 width: 100%;
161 min-height: 0;
162 padding: 2rem;
163 color: var(--color-text-secondary, #999);
164 font-size: 1rem;
165 }
166
167 .settings-error {
168 flex-direction: column;
169 color: var(--color-error, #e74c3c);
170 }
171
172 .settings-error .material-symbols-outlined {
173 font-size: 2rem;
174 }
175
176 .settings-error .btn-retry {
177 margin-top: 1rem;
178 }
179
180 .spinning {
181 animation: spin 1s linear infinite;
182 }
183
184 @keyframes spin {
185 from { transform: rotate(0deg); }
186 to { transform: rotate(360deg); }
187 }
188 </style>