fix: card thumbnails, search/sort sizing, link styling, management buttons

- install-index.html: contain thumbnails instead of cropping, add title overlay on cards, fix search bar min-width, constrain sort dropdown - install-detail.html: fix link colors for both themes, prevent icon underline on hover, replace "Already Installed" with management buttons (Open, Config, README, License, Info, Delete) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

TerminallyLazy committed Mar 3, 2026 at 23:43 UTC e7f9456b071021667c31ded563575865894b0e4e
2 files changed +141 -26
plugins/plugin_installer/webui/install-detail.html
+100 -5
@@ -50,9 +50,55 @@
50
51 <div class="pi-detail-actions">
52 <template x-if="$store.pluginInstallStore.selectedPlugin.installed">
53 - <button class="button" disabled>
54 - <span class="icon material-symbols-outlined">check</span> Already Installed
55 - </button>
53 + <div>
54 + <div class="pi-installed-badge-row">
55 + <span class="material-symbols-outlined pi-installed-check">check_circle</span>
56 + <span class="pi-installed-label">Installed</span>
57 + </div>
58 +
59 + <div x-show="$store.pluginInstallStore.installedPluginInfoLoading" class="pi-loading-inline">
60 + Loading plugin info...
61 + </div>
62 +
63 + <template x-if="$store.pluginInstallStore.installedPluginInfo">
64 + <div class="pi-manage-actions">
65 + <template x-if="$store.pluginInstallStore.installedPluginInfo.has_main_screen">
66 + <button type="button" class="button"
67 + @click="$store.pluginInstallStore.manageOpenPlugin()">
68 + <span class="icon material-symbols-outlined">dashboard</span> Open
69 + </button>
70 + </template>
71 + <template x-if="$store.pluginInstallStore.installedPluginInfo.has_config_screen">
72 + <button type="button" class="button"
73 + @click="$store.pluginInstallStore.manageOpenConfig()">
74 + <span class="icon material-symbols-outlined">settings</span> Config
75 + </button>
76 + </template>
77 + <template x-if="$store.pluginInstallStore.installedPluginInfo.has_readme">
78 + <button type="button" class="button"
79 + @click="$store.pluginInstallStore.manageOpenDoc('readme')">
80 + <span class="icon material-symbols-outlined">description</span> README
81 + </button>
82 + </template>
83 + <template x-if="$store.pluginInstallStore.installedPluginInfo.has_license">
84 + <button type="button" class="button"
85 + @click="$store.pluginInstallStore.manageOpenDoc('license')">
86 + <span class="icon material-symbols-outlined">gavel</span> License
87 + </button>
88 + </template>
89 + <button type="button" class="button"
90 + @click="$store.pluginInstallStore.manageOpenInfo()">
91 + <span class="icon material-symbols-outlined">info</span> Info
92 + </button>
93 + <template x-if="$store.pluginInstallStore.installedPluginInfo.is_custom">
94 + <button type="button" class="button cancel"
95 + @click="$confirmClick($event, () => $store.pluginInstallStore.manageDeletePlugin())">
96 + <span class="icon material-symbols-outlined">delete</span> Delete
97 + </button>
98 + </template>
99 + </div>
100 + </template>
101 + </div>
102 </template>
103 <template x-if="!$store.pluginInstallStore.selectedPlugin.installed">
104 <button class="button confirm"
@@ -112,11 +158,11 @@
158 .pi-detail-thumb img {
159 width: 100%;
160 height: 100%;
115 - object-fit: cover;
161 + object-fit: contain;
162 }
163
164 .pi-detail-placeholder {
119 - font-size: 3rem;
165 + font-size: 4rem;
166 color: var(--color-text-muted);
167 }
168
@@ -177,6 +223,16 @@
223
224 .pi-link:hover {
225 text-decoration: underline;
226 + text-underline-offset: 2px;
227 + }
228 +
229 + .pi-link .material-symbols-outlined {
230 + text-decoration: none;
231 + color: var(--color-highlight);
232 + }
233 +
234 + .pi-link:hover .material-symbols-outlined {
235 + text-decoration: none;
236 }
237
238 .pi-detail-actions {
@@ -220,6 +276,45 @@
276 font-family: var(--font-family-code);
277 }
278
279 + .pi-installed-badge-row {
280 + display: flex;
281 + align-items: center;
282 + gap: 0.4rem;
283 + margin-bottom: 0.75rem;
284 + }
285 +
286 + .pi-installed-check {
287 + font-size: 1.3rem;
288 + color: #22c55e;
289 + }
290 +
291 + .pi-installed-label {
292 + font-weight: 600;
293 + font-size: 0.95rem;
294 + color: #22c55e;
295 + }
296 +
297 + .pi-manage-actions {
298 + display: flex;
299 + flex-wrap: wrap;
300 + gap: 0.5rem;
301 + }
302 +
303 + .pi-manage-actions .button {
304 + padding: 0.3rem 0.6rem;
305 + font-size: 0.9rem;
306 + }
307 +
308 + .pi-manage-actions .button .icon {
309 + font-size: 1.1rem;
310 + }
311 +
312 + .pi-loading-inline {
313 + font-size: 0.85rem;
314 + color: var(--color-text-secondary);
315 + padding: 0.5rem 0;
316 + }
317 +
318 @media (max-width: 500px) {
319 .pi-detail-header {
320 flex-direction: column;
plugins/plugin_installer/webui/install-index.html
+41 -21
@@ -18,8 +18,8 @@
18 placeholder="Search plugins...">
19 <select class="pi-sort-select"
20 x-model="$store.pluginInstallStore.sortBy">
21 - <option value="stars">Sort by Stars</option>
22 - <option value="name">Sort by Name</option>
21 + <option value="stars">Stars</option>
22 + <option value="name">Name</option>
23 </select>
24 </div>
25
@@ -44,14 +44,14 @@
44 <template x-if="!plugin.thumbnail">
45 <span class="material-symbols-outlined pi-card-placeholder">extension</span>
46 </template>
47 - </div>
48 - <div class="pi-card-body">
49 - <div class="pi-card-title">
50 - <span x-text="plugin.title || plugin.key"></span>
47 + <div class="pi-card-thumb-overlay">
48 + <span class="pi-card-thumb-title" x-text="plugin.title || plugin.key"></span>
49 <template x-if="plugin.installed">
50 <span class="pi-badge-installed">Installed</span>
51 </template>
52 </div>
53 + </div>
54 + <div class="pi-card-body">
55 <div class="pi-card-desc" x-text="$store.pluginInstallStore.truncate(plugin.description, 100)"></div>
56 </div>
57 <div class="pi-card-footer">
@@ -100,6 +100,7 @@
100
101 .pi-search-input {
102 flex: 1;
103 + min-width: 0;
104 padding: 0.5rem 0.75rem;
105 border: 1px solid var(--color-border);
106 border-radius: 4px;
@@ -109,6 +110,8 @@
110 }
111
112 .pi-sort-select {
113 + max-width: 140px;
114 + flex-shrink: 0;
115 padding: 0.5rem;
116 border: 1px solid var(--color-border);
117 border-radius: 4px;
@@ -141,46 +144,63 @@
144
145 .pi-card-thumb {
146 width: 100%;
144 - height: 120px;
147 + height: 140px;
148 overflow: hidden;
149 display: flex;
150 align-items: center;
151 justify-content: center;
152 background: var(--color-panel);
153 + position: relative;
154 }
155
156 .pi-card-thumb img {
157 width: 100%;
158 height: 100%;
155 - object-fit: cover;
159 + object-fit: contain;
160 + padding: 0.5rem;
161 }
162
163 .pi-card-placeholder {
159 - font-size: 3rem;
164 + font-size: 4.5rem;
165 color: var(--color-text-muted);
166 }
167
163 - .pi-card-body {
164 - padding: 0.6rem 0.75rem;
165 - flex: 1;
166 - }
167 -
168 - .pi-card-title {
169 - font-weight: 600;
170 - font-size: 0.95rem;
168 + .pi-card-thumb-overlay {
169 + position: absolute;
170 + bottom: 0;
171 + left: 0;
172 + right: 0;
173 + padding: 0.4rem 0.6rem;
174 + background: rgba(0, 0, 0, 0.55);
175 display: flex;
176 align-items: center;
177 gap: 0.4rem;
174 - flex-wrap: wrap;
178 + }
179 +
180 + .pi-card-thumb-title {
181 + font-weight: 600;
182 + font-size: 0.85rem;
183 + color: #fff;
184 + white-space: nowrap;
185 + overflow: hidden;
186 + text-overflow: ellipsis;
187 + flex: 1;
188 + min-width: 0;
189 }
190
191 .pi-badge-installed {
178 - font-size: 0.7rem;
192 + font-size: 0.65rem;
193 font-weight: 600;
194 padding: 0.1rem 0.4rem;
195 border-radius: 3px;
182 - background: rgba(34,197,94,0.2);
183 - color: #22c55e;
196 + background: rgba(34,197,94,0.3);
197 + color: #4ade80;
198 + flex-shrink: 0;
199 + }
200 +
201 + .pi-card-body {
202 + padding: 0.5rem 0.75rem;
203 + flex: 1;
204 }
205
206 .pi-card-desc {