main
html 396 lines 14 KB
Raw
1 <html>
2 <head>
3 <title>Plugin Info</title>
4 <script type="module">
5 import { store } from "/components/plugins/list/pluginListStore.js";
6 </script>
7 </head>
8 <body>
9 <div x-data>
10 <template x-if="$store.pluginListStore && $store.pluginListStore.selectedPlugin">
11 <div class="plugin-info-view">
12 <div class="plugin-info-header">
13 <template x-if="$store.pluginListStore.selectedPlugin.thumbnail_url">
14 <div class="plugin-info-thumb">
15 <img :src="$store.pluginListStore.selectedPlugin.thumbnail_url"
16 :alt="$store.pluginListStore.selectedPlugin.display_name || $store.pluginListStore.selectedPlugin.name">
17 </div>
18 </template>
19 <div class="plugin-info-header-main">
20 <div class="plugin-info-heading">
21 <h2 class="plugin-info-title"
22 x-text="$store.pluginListStore.selectedPlugin.display_name || $store.pluginListStore.selectedPlugin.name"></h2>
23 <div class="plugin-info-source"
24 x-text="$store.pluginListStore.selectedPlugin.is_custom ? 'Custom plugin' : 'Builtin plugin'"></div>
25 </div>
26
27 <div class="plugin-info-description"
28 x-text="$store.pluginListStore.selectedPlugin.description || 'No description provided.'"></div>
29 </div>
30 </div>
31
32 <div class="plugin-info-grid">
33 <div class="plugin-info-label">Plugin ID:</div>
34 <div class="plugin-info-value">
35 <code x-text="$store.pluginListStore.selectedPlugin.name"></code>
36 </div>
37
38 <div class="plugin-info-label">Version:</div>
39 <div class="plugin-info-value"
40 x-text="$store.pluginListStore.selectedPlugin.version || 'n/a'"></div>
41
42 <template x-if="$store.pluginListStore.selectedPlugin.author && $store.pluginListStore.selectedPlugin.repo">
43 <div class="plugin-info-grid-pair">
44 <div class="plugin-info-label">Repository:</div>
45 <div class="plugin-info-value">
46 <code x-text="`${$store.pluginListStore.selectedPlugin.author}/${$store.pluginListStore.selectedPlugin.repo}`"></code>
47 </div>
48 </div>
49 </template>
50
51 <div class="plugin-info-label">Path:</div>
52 <div class="plugin-info-value">
53 <code x-text="$store.pluginListStore.selectedPlugin.path"></code>
54 </div>
55
56 <div class="plugin-info-label">Settings sections:</div>
57 <div class="plugin-info-value"
58 x-text="($store.pluginListStore.selectedPlugin.settings_sections || []).length ? $store.pluginListStore.selectedPlugin.settings_sections.join(', ') : 'None'"></div>
59
60 <div class="plugin-info-label">Per-project config:</div>
61 <div class="plugin-info-value"
62 x-text="$store.pluginListStore.selectedPlugin.per_project_config ? 'Yes' : 'No'"></div>
63
64 <div class="plugin-info-label">Per-agent config:</div>
65 <div class="plugin-info-value"
66 x-text="$store.pluginListStore.selectedPlugin.per_agent_config ? 'Yes' : 'No'"></div>
67
68 <div class="plugin-info-label">Main screen:</div>
69 <div class="plugin-info-value"
70 x-text="$store.pluginListStore.selectedPlugin.has_main_screen ? 'Available' : 'Not available'"></div>
71
72 <div class="plugin-info-label">Config screen:</div>
73 <div class="plugin-info-value"
74 x-text="$store.pluginListStore.selectedPlugin.has_config_screen ? 'Available' : 'Not available'"></div>
75 </div>
76
77 <div class="plugin-info-readme-section"
78 x-show="$store.pluginListStore.selectedPlugin.has_readme || $store.pluginListStore.readmeLoading || $store.pluginListStore.readmeError || $store.pluginListStore.readmeContent">
79 <button type="button"
80 class="plugin-info-readme-toggle"
81 data-bs-toggle="collapse"
82 data-bs-target="#plugin-info-readme-collapse"
83 aria-expanded="false"
84 aria-controls="plugin-info-readme-collapse">
85 <span>README</span>
86 <x-icon class="plugin-info-readme-toggle-icon" name="expand_more"></x-icon>
87 </button>
88 <div class="collapse" id="plugin-info-readme-collapse">
89 <div class="plugin-info-readme-body">
90 <div x-show="$store.pluginListStore.readmeLoading" class="plugin-info-loading-text">
91 Loading readme...
92 </div>
93 <div x-show="$store.pluginListStore.readmeError && !$store.pluginListStore.readmeLoading"
94 class="plugin-info-readme-error"
95 x-text="$store.pluginListStore.readmeError"></div>
96 <div x-show="$store.pluginListStore.readmeContent && !$store.pluginListStore.readmeLoading"
97 class="plugin-info-readme-content"
98 x-html="$store.pluginListStore.readmeContent"></div>
99 </div>
100 </div>
101 </div>
102 </div>
103 </template>
104
105 <template x-if="$store.pluginListStore?.selectedPlugin">
106 <div class="modal-footer plugin-info-footer" data-modal-footer>
107 <div class="plugin-info-footer-row">
108 <div class="plugin-info-footer-left">
109 <button type="button"
110 class="button"
111 title="Open plugin files"
112 @click="$store.pluginListStore.openPluginFolder($store.pluginListStore.selectedPlugin)">
113 <x-icon class="icon" name="folder_open"></x-icon> Files
114 </button>
115 <template x-if="$store.pluginListStore.selectedPlugin.pluginHub?.key">
116 <button type="button"
117 class="button"
118 title="Open in Plugin Hub"
119 @click="$store.pluginListStore.openPluginHub($store.pluginListStore.selectedPlugin)">
120 <x-icon class="icon" name="storefront"></x-icon> Hub
121 </button>
122 </template>
123 </div>
124 <div class="plugin-info-footer-right">
125 <button class="btn btn-cancel" @click="window.closeModal?.()">Close</button>
126 </div>
127 </div>
128 </div>
129 </template>
130 </div>
131
132 <style>
133 .plugin-info-view {
134 padding: 1rem;
135 }
136
137 .plugin-info-header {
138 display: flex;
139 align-items: flex-start;
140 gap: 1rem;
141 margin-bottom: 1rem;
142 }
143
144 .plugin-info-thumb {
145 width: 96px;
146 height: 96px;
147 flex-shrink: 0;
148 display: flex;
149 align-items: center;
150 justify-content: center;
151 overflow: hidden;
152 border: 1px solid var(--color-border);
153 border-radius: 12px;
154 background: var(--color-panel);
155 }
156
157 .plugin-info-thumb img {
158 width: 100%;
159 height: 100%;
160 object-fit: contain;
161 padding: 0.5rem;
162 }
163
164 .plugin-info-header-main {
165 flex: 1;
166 min-width: 0;
167 }
168
169 .plugin-info-heading {
170 display: flex;
171 flex-wrap: wrap;
172 align-items: baseline;
173 justify-content: space-between;
174 gap: 0.75rem;
175 margin-bottom: 0.5rem;
176 }
177
178 .plugin-info-title {
179 margin: 0;
180 font-size: 1.1rem;
181 }
182
183 .plugin-info-source {
184 color: var(--color-text-secondary);
185 font-size: var(--font-size-small);
186 }
187
188 .plugin-info-description {
189 margin-bottom: 1rem;
190 color: var(--color-text-secondary);
191 }
192
193 .plugin-info-grid {
194 display: grid;
195 grid-template-columns: 12rem 1fr;
196 gap: 0.5rem 0.75rem;
197 }
198
199 .plugin-info-readme-section {
200 margin-top: 1.5rem;
201 padding-top: 1rem;
202 border-top: 1px solid var(--color-border);
203 }
204
205 .plugin-info-readme-toggle {
206 width: 100%;
207 display: flex;
208 align-items: center;
209 justify-content: space-between;
210 gap: 0.75rem;
211 padding: 0;
212 border: 0;
213 background: transparent;
214 color: var(--color-text-primary);
215 font-size: 0.95rem;
216 font-weight: 600;
217 text-align: left;
218 cursor: pointer;
219 }
220
221 .plugin-info-readme-toggle-icon {
222 transition: transform 0.2s ease;
223 }
224
225 .plugin-info-readme-toggle[aria-expanded="true"] .plugin-info-readme-toggle-icon {
226 transform: rotate(180deg);
227 }
228
229 .plugin-info-readme-body {
230 padding-top: 0.85rem;
231 }
232
233 .plugin-info-loading-text,
234 .plugin-info-readme-error {
235 color: var(--color-text-secondary);
236 }
237
238 .plugin-info-readme-content {
239 font-size: 0.95rem;
240 line-height: 1.6;
241 color: var(--color-text-primary);
242 overflow-x: auto;
243 scrollbar-width: none;
244 -ms-overflow-style: none;
245 }
246
247 .plugin-info-readme-content::-webkit-scrollbar {
248 display: none;
249 }
250
251 .plugin-info-readme-content h1,
252 .plugin-info-readme-content h2,
253 .plugin-info-readme-content h3,
254 .plugin-info-readme-content h4 {
255 margin-top: 1rem;
256 margin-bottom: 0.5rem;
257 color: var(--color-text-primary);
258 }
259
260 .plugin-info-readme-content h1 { font-size: 1.5rem; }
261 .plugin-info-readme-content h2 { font-size: 1.25rem; }
262 .plugin-info-readme-content h3 { font-size: 1.1rem; }
263 .plugin-info-readme-content h4 { font-size: 1rem; }
264
265 .plugin-info-readme-content p {
266 margin-bottom: 0.75rem;
267 }
268
269 .plugin-info-readme-content code {
270 background: var(--color-panel);
271 padding: 0.15rem 0.35rem;
272 border-radius: 4px;
273 font-family: var(--font-family-mono);
274 font-size: 0.85em;
275 }
276
277 .plugin-info-readme-content pre {
278 background: var(--color-panel);
279 padding: 1rem;
280 border-radius: 8px;
281 overflow-x: auto;
282 margin-bottom: 1rem;
283 }
284
285 .plugin-info-readme-content pre code {
286 background: none;
287 padding: 0;
288 }
289
290 .plugin-info-readme-content ul,
291 .plugin-info-readme-content ol {
292 margin-bottom: 0.75rem;
293 padding-left: 1.5rem;
294 }
295
296 .plugin-info-readme-content li {
297 margin-bottom: 0.25rem;
298 }
299
300 .plugin-info-readme-content a {
301 color: var(--color-highlight);
302 text-decoration: none;
303 }
304
305 .plugin-info-readme-content a:hover {
306 text-decoration: underline;
307 }
308
309 .plugin-info-readme-content img {
310 max-width: 100%;
311 border-radius: 8px;
312 margin: 0.5rem 0;
313 }
314
315 .plugin-info-readme-content blockquote {
316 border-left: 3px solid var(--color-border);
317 padding-left: 1rem;
318 margin-left: 0;
319 color: var(--color-text-secondary);
320 }
321
322 .plugin-info-readme-content table {
323 width: 100%;
324 border-collapse: collapse;
325 margin-bottom: 1rem;
326 }
327
328 .plugin-info-readme-content th,
329 .plugin-info-readme-content td {
330 border: 1px solid var(--color-border);
331 padding: 0.5rem;
332 text-align: left;
333 }
334
335 .plugin-info-readme-content th {
336 background: var(--color-panel);
337 }
338
339 .plugin-info-grid-pair {
340 display: contents;
341 }
342
343 .plugin-info-label {
344 font-weight: 600;
345 color: var(--color-text-secondary);
346 }
347
348 .plugin-info-value {
349 min-width: 0;
350 word-break: break-word;
351 overflow-wrap: anywhere;
352 }
353
354 .plugin-info-footer-row {
355 width: 100%;
356 display: flex;
357 align-items: center;
358 justify-content: space-between;
359 gap: 0.75rem;
360 flex-wrap: wrap;
361 }
362
363 .plugin-info-footer-left,
364 .plugin-info-footer-right {
365 display: flex;
366 gap: 0.5rem;
367 flex-wrap: wrap;
368 }
369
370 @media (max-width: 640px) {
371 .plugin-info-header {
372 flex-direction: column;
373 }
374
375 .plugin-info-grid {
376 grid-template-columns: 1fr;
377 gap: 0.25rem;
378 }
379
380 .plugin-info-label {
381 margin-top: 0.5rem;
382 }
383
384 .plugin-info-footer-row {
385 flex-direction: column;
386 align-items: stretch;
387 }
388
389 .plugin-info-footer-left,
390 .plugin-info-footer-right {
391 width: 100%;
392 }
393 }
394 </style>
395 </body>
396 </html>