main
html 265 lines 10.2 KB
Raw
1 <html>
2 <head>
3 <script type="module">
4 import { store } from "/plugins/_commands/webui/commands-slash-store.js";
5 </script>
6 </head>
7 <body>
8 <div x-data>
9 <template x-if="$store.commandsSlash">
10 <div class="commands-slash-menu-root" x-create="$store.commandsSlash.onMount()" x-destroy="$store.commandsSlash.cleanup()">
11 <div class="commands-slash-menu" x-show="$store.commandsSlash.menuVisible" x-transition.opacity.duration.120ms>
12 <template x-if="$store.commandsSlash.loading">
13 <div class="commands-slash-loading">
14 <x-icon class="spinning" name="progress_activity"></x-icon>
15 <span x-text="$store.commandsSlash.loadingLabel"></span>
16 </div>
17 </template>
18
19 <template x-if="!$store.commandsSlash.loading && $store.commandsSlash.filteredItems.length > 0">
20 <div class="commands-slash-results">
21 <template x-for="(item, index) in $store.commandsSlash.filteredItems" :key="item.id || item.path">
22 <button type="button"
23 class="commands-slash-item"
24 :class="{ active: index === $store.commandsSlash.selectedIndex }"
25 @mouseenter="$store.commandsSlash.selectedIndex = index"
26 @mousedown.prevent
27 @click.prevent="$store.commandsSlash.applySelectedItem(item)">
28 <div class="commands-slash-item-header">
29 <div class="commands-slash-item-name"
30 :class="$store.commandsSlash.mode === 'reference' ? ['is-reference', `is-${item.tone}`] : ''">
31 <template x-if="$store.commandsSlash.mode === 'reference'">
32 <x-icon class="commands-reference-icon" :name="item.icon"></x-icon>
33 </template>
34 <span class="commands-slash-prefix" x-text="$store.commandsSlash.mode === 'reference' ? '@' : '/'"></span><span x-text="$store.commandsSlash.mode === 'reference' ? item.label : item.name"></span>
35 </div>
36 <span class="commands-slash-scope"
37 :class="$store.commandsSlash.mode === 'reference' ? ['is-reference', `is-${item.tone}`] : ''"
38 x-text="$store.commandsSlash.mode === 'reference' ? item.kind : item.source_scope_label"></span>
39 </div>
40 <div class="commands-slash-item-description" x-text="item.description"></div>
41 <template x-if="$store.commandsSlash.mode !== 'reference' && item.argument_hint">
42 <div class="commands-slash-item-hint" x-text="item.argument_hint"></div>
43 </template>
44 </button>
45 </template>
46 </div>
47 </template>
48
49 <template x-if="!$store.commandsSlash.loading && $store.commandsSlash.filteredItems.length === 0">
50 <div class="commands-slash-empty">
51 <div class="commands-slash-empty-copy">
52 <span x-text="$store.commandsSlash.emptyLabel"></span>
53 </div>
54 <template x-if="$store.commandsSlash.mode !== 'reference'">
55 <button type="button"
56 class="commands-slash-create"
57 @mousedown.prevent
58 @click.prevent="$store.commandsSlash.openCreateCommand()">
59 <x-icon name="add"></x-icon>
60 <span x-text="$store.commandsSlash.emptyStateLabel"></span>
61 </button>
62 </template>
63 </div>
64 </template>
65 </div>
66 </div>
67 </template>
68 </div>
69
70 <style>
71 .commands-slash-menu-root {
72 position: relative;
73 z-index: 30;
74 }
75
76 .commands-slash-menu {
77 margin-bottom: 0.55rem;
78 border: 1px solid var(--color-border);
79 border-radius: 8px;
80 background: color-mix(in srgb, var(--color-panel) 96%, var(--color-background));
81 box-shadow: 0 14px 32px rgba(0, 0, 0, 0.14);
82 overflow: hidden;
83 }
84
85 .commands-slash-results {
86 max-height: 18rem;
87 overflow-y: auto;
88 }
89
90 .commands-slash-item {
91 display: flex;
92 flex-direction: column;
93 gap: 0.32rem;
94 width: 100%;
95 padding: var(--spacing-sm) 0.8rem;
96 border: 0;
97 border-bottom: 1px solid color-mix(in srgb, var(--color-border) 60%, transparent);
98 background: transparent;
99 color: inherit;
100 text-align: left;
101 cursor: pointer;
102 }
103
104 .commands-slash-item:last-child {
105 border-bottom: 0;
106 }
107
108 .commands-slash-item.active,
109 .commands-slash-item:hover {
110 background: color-mix(in srgb, var(--color-highlight) 10%, transparent);
111 }
112
113 .commands-slash-item-header {
114 display: flex;
115 justify-content: space-between;
116 gap: 0.75rem;
117 align-items: center;
118 }
119
120 .commands-slash-item-name {
121 font-weight: 600;
122 }
123
124 .commands-slash-item-name.is-reference {
125 display: inline-flex;
126 align-items: center;
127 }
128
129 .commands-reference-icon {
130 margin-right: 0.38rem;
131 font-size: 1.08rem;
132 color: var(--color-highlight);
133 font-variation-settings: 'FILL' 0, 'wght' 450, 'GRAD' 0, 'opsz' 20;
134 }
135
136 .commands-slash-prefix {
137 color: var(--color-highlight);
138 }
139
140 .commands-slash-item-name.is-reference .commands-slash-prefix {
141 color: inherit;
142 }
143
144 .commands-slash-scope {
145 padding: 0.18rem 0.45rem;
146 border-radius: 999px;
147 background: color-mix(in srgb, var(--color-highlight) 12%, transparent);
148 font-size: 0.72rem;
149 font-weight: 600;
150 white-space: nowrap;
151 }
152
153 .commands-slash-scope.is-reference {
154 padding: 0;
155 background: transparent;
156 }
157
158 .commands-slash-item-name.is-reference,
159 #chat-input .composer-reference {
160 color: var(--color-text);
161 }
162
163 #chat-input .composer-reference {
164 display: inline;
165 font-size: 0;
166 font-weight: 600;
167 line-height: inherit;
168 white-space: nowrap;
169 vertical-align: baseline;
170 }
171
172 #chat-input .composer-reference::before {
173 display: inline-block;
174 color: var(--color-highlight);
175 font-family: 'Material Symbols Outlined';
176 margin-right: 0.22rem;
177 font-size: 1rem;
178 font-weight: normal;
179 line-height: 1;
180 vertical-align: -0.1em;
181 font-variation-settings: 'FILL' 0, 'wght' 450, 'GRAD' 0, 'opsz' 20;
182 }
183
184 #chat-input .composer-reference::after {
185 content: attr(data-label);
186 font-family: var(--font-family-main, "Rubik", Arial, Helvetica, sans-serif);
187 font-size: 1rem;
188 line-height: inherit;
189 vertical-align: baseline;
190 }
191
192 #chat-input .composer-reference.is-folder::before { content: 'folder'; }
193 #chat-input .composer-reference.is-file::before { content: 'draft'; }
194 #chat-input .composer-reference.is-agent::before { content: 'person'; }
195 #chat-input .composer-reference.is-skill::before { content: 'auto_awesome'; }
196 #chat-input .composer-reference.is-mcp::before { content: 'hub'; }
197
198 html:not(.material-icons-ready) #chat-input .composer-reference::before {
199 visibility: hidden;
200 }
201
202 .commands-slash-item-description {
203 color: var(--color-text-secondary);
204 font-size: 0.86rem;
205 line-height: 1.4;
206 }
207
208 .commands-slash-item-hint {
209 color: var(--color-text-secondary);
210 font-family: "Roboto Mono", monospace;
211 font-size: 0.77rem;
212 opacity: 0.85;
213 }
214
215 .commands-slash-empty,
216 .commands-slash-loading {
217 display: flex;
218 align-items: center;
219 justify-content: space-between;
220 gap: 0.75rem;
221 padding: 0.9rem 1rem;
222 }
223
224 .commands-slash-empty-copy,
225 .commands-slash-loading {
226 color: var(--color-text-secondary);
227 }
228
229 .commands-slash-create {
230 display: inline-flex;
231 align-items: center;
232 gap: 0.35rem;
233 padding: 0.5rem 0.75rem;
234 border: 1px solid var(--color-border);
235 border-radius: 999px;
236 background: transparent;
237 color: var(--color-text);
238 cursor: pointer;
239 font-weight: 600;
240 white-space: nowrap;
241 }
242
243 .spinning {
244 animation: commands-slash-spin 1s linear infinite;
245 }
246
247 @keyframes commands-slash-spin {
248 from { transform: rotate(0deg); }
249 to { transform: rotate(360deg); }
250 }
251
252 @media (max-width: 640px) {
253 .commands-slash-empty,
254 .commands-slash-loading {
255 flex-direction: column;
256 align-items: stretch;
257 }
258
259 .commands-slash-create {
260 justify-content: center;
261 }
262 }
263 </style>
264 </body>
265 </html>