1
+<script type="module">
2
+ import { store } from "/plugins/_discovery/webui/discovery-store.js";
3
+</script>
4
+
5
+<div x-data>
6
+ <template x-if="$store.discoveryStore">
7
+ <div class="discovery-slot"
8
+ @modal-closed.window="$store.discoveryStore.refreshCards()"
9
+ x-create="$store.discoveryStore.refreshCards()"
10
+ x-show="!($store.welcomeStore?.banners || []).some(b => b.id === 'missing-api-key') && ($store.discoveryStore.cards.length > 0 || $store.discoveryStore.hasDismissedCards)">
11
+
12
+ <div class="discovery-section">
13
+ <template x-for="card in $store.discoveryStore.heroCards" :key="card.id">
14
+ <article class="discovery-hero"
15
+ role="button"
16
+ tabindex="0"
17
+ @click="$store.discoveryStore.executeCta(card.cta_action)"
18
+ @keydown.enter.prevent="$store.discoveryStore.executeCta(card.cta_action)"
19
+ @keydown.space.prevent="$store.discoveryStore.executeCta(card.cta_action)">
20
+ <button class="discovery-dismiss"
21
+ type="button"
22
+ x-show="card.dismissible"
23
+ @click.stop="$store.discoveryStore.dismissCard(card.id)"
24
+ :aria-label="`Dismiss ${card.title}`"
25
+ title="Dismiss">
26
+ <span class="material-symbols-outlined">close</span>
27
+ </button>
28
+
29
+ <div class="discovery-hero-content">
30
+ <h3 class="discovery-hero-title" x-text="card.title"></h3>
31
+ <p class="discovery-hero-desc" x-text="card.description"></p>
32
+ <button class="btn btn-ok"
33
+ type="button"
34
+ @click.stop="$store.discoveryStore.executeCta(card.cta_action)">
35
+ <span x-text="card.cta_text"></span>
36
+ <span class="material-symbols-outlined">arrow_forward</span>
37
+ </button>
38
+ </div>
39
+
40
+ <div class="discovery-hero-thumb">
41
+ <template x-if="card.thumbnail">
42
+ <img :src="card.thumbnail" :alt="card.title" loading="lazy">
43
+ </template>
44
+ <template x-if="!card.thumbnail && card.icon">
45
+ <span class="material-symbols-outlined discovery-hero-icon" x-text="card.icon"></span>
46
+ </template>
47
+ </div>
48
+ </article>
49
+ </template>
50
+
51
+ <div class="discovery-features" x-show="$store.discoveryStore.featureCards.length > 0">
52
+ <template x-for="card in $store.discoveryStore.featureCards" :key="card.id">
53
+ <article class="discovery-feature-card"
54
+ role="button"
55
+ tabindex="0"
56
+ @click="$store.discoveryStore.executeCta(card.cta_action)"
57
+ @keydown.enter.prevent="$store.discoveryStore.executeCta(card.cta_action)"
58
+ @keydown.space.prevent="$store.discoveryStore.executeCta(card.cta_action)">
59
+ <button class="discovery-dismiss discovery-dismiss-small"
60
+ type="button"
61
+ x-show="card.dismissible"
62
+ @click.stop="$store.discoveryStore.dismissCard(card.id)"
63
+ :aria-label="`Dismiss ${card.title}`"
64
+ title="Dismiss">
65
+ <span class="material-symbols-outlined">close</span>
66
+ </button>
67
+
68
+ <div class="discovery-feature-head">
69
+ <div class="discovery-feature-thumb">
70
+ <template x-if="card.thumbnail">
71
+ <img :src="card.thumbnail" :alt="card.title" loading="lazy">
72
+ </template>
73
+ <template x-if="!card.thumbnail && card.icon">
74
+ <span class="material-symbols-outlined discovery-feature-icon" x-text="card.icon"></span>
75
+ </template>
76
+ </div>
77
+ <h4 class="discovery-feature-title" x-text="card.title"></h4>
78
+ </div>
79
+
80
+ <p class="discovery-feature-desc" x-text="card.description"></p>
81
+
82
+ <button class="btn btn primary"
83
+ type="button"
84
+ @click.stop="$store.discoveryStore.executeCta(card.cta_action)">
85
+ <span x-text="card.cta_text"></span>
86
+ <span class="material-symbols-outlined">arrow_forward</span>
87
+ </button>
88
+ </article>
89
+ </template>
90
+ </div>
91
+
92
+ <div class="discovery-undismiss" x-show="$store.discoveryStore.hasDismissedCards">
93
+ <button type="button"
94
+ class="discovery-undismiss-btn"
95
+ @click="$store.discoveryStore.undismissCards()">
96
+ <span class="material-symbols-outlined">undo</span>
97
+ <span>Show dismissed suggestions</span>
98
+ </button>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </template>
103
+
104
+ <style>
105
+ .discovery-slot {
106
+ grid-column: 1 / -1;
107
+ width: 100%;
108
+ }
109
+
110
+ .discovery-section {
111
+ display: flex;
112
+ flex-direction: column;
113
+ gap: 1rem;
114
+ width: 100%;
115
+ margin-top: 0.1rem;
116
+ }
117
+
118
+ .discovery-hero,
119
+ .discovery-feature-card {
120
+ position: relative;
121
+ border: 1px solid var(--color-border);
122
+ border-radius: 12px;
123
+ background: var(--color-panel);
124
+ text-align: left;
125
+ transition:
126
+ border-color 0.2s ease,
127
+ background-color 0.2s ease,
128
+ box-shadow 0.2s ease,
129
+ transform 0.2s ease;
130
+ }
131
+
132
+ .discovery-hero:hover,
133
+ .discovery-feature-card:hover,
134
+ .discovery-hero:focus-visible,
135
+ .discovery-feature-card:focus-visible {
136
+ border-color: color-mix(in srgb, var(--color-primary) 72%, white 6%);
137
+ box-shadow: 0 10px 28px rgba(0, 0, 0, 0.16);
138
+ outline: none;
139
+ }
140
+
141
+ .discovery-hero {
142
+ display: flex;
143
+ align-items: center;
144
+ gap: 1rem;
145
+ min-height: 152px;
146
+ overflow: hidden;
147
+ padding: 1.25rem 1.25rem 1.25rem 1.5rem;
148
+ background:
149
+ linear-gradient(
150
+ 135deg,
151
+ color-mix(in srgb, var(--color-primary) 10%, transparent),
152
+ transparent 58%
153
+ ),
154
+ radial-gradient(
155
+ circle at 92% 24%,
156
+ color-mix(in srgb, var(--color-primary) 12%, transparent),
157
+ transparent 42%
158
+ ),
159
+ var(--color-panel);
160
+ }
161
+
162
+ .discovery-hero-content,
163
+ .discovery-hero-thumb {
164
+ position: relative;
165
+ z-index: 1;
166
+ }
167
+
168
+ .discovery-hero-content {
169
+ flex: 1 1 auto;
170
+ min-width: 0;
171
+ }
172
+
173
+ .discovery-hero-title {
174
+ margin: 0 0 0.4rem;
175
+ color: var(--color-text);
176
+ font-size: 1.08rem;
177
+ font-weight: 600;
178
+ letter-spacing: 0.01em;
179
+ }
180
+
181
+ .discovery-hero-desc {
182
+ margin: 0 0 1rem;
183
+ color: var(--color-text);
184
+ font-size: 0.86rem;
185
+ line-height: 1.5;
186
+ max-width: 38ch;
187
+ }
188
+
189
+ .discovery-cta-link,
190
+ .discovery-undismiss-btn {
191
+ display: inline-flex;
192
+ align-items: center;
193
+ justify-content: center;
194
+ gap: 0.35rem;
195
+ cursor: pointer;
196
+ transition:
197
+ background-color 0.2s ease,
198
+ border-color 0.2s ease,
199
+ color 0.2s ease,
200
+ transform 0.2s ease;
201
+ }
202
+
203
+ .discovery-hero-thumb {
204
+ flex: 0 0 132px;
205
+ width: 132px;
206
+ height: 108px;
207
+ display: flex;
208
+ align-items: center;
209
+ justify-content: center;
210
+ }
211
+
212
+ .discovery-hero-thumb img {
213
+ width: 100%;
214
+ height: 100%;
215
+ object-fit: contain;
216
+ filter: drop-shadow(0 12px 18px rgba(0, 0, 0, 0.12));
217
+ }
218
+
219
+ .discovery-hero-icon {
220
+ font-size: 3rem;
221
+ color: var(--color-highlight-dark);
222
+ }
223
+
224
+ .discovery-features {
225
+ display: grid;
226
+ grid-template-columns: repeat(3, minmax(0, 1fr));
227
+ gap: 1rem;
228
+ }
229
+
230
+ .discovery-feature-card {
231
+ display: flex;
232
+ flex-direction: column;
233
+ align-items: flex-start;
234
+ min-height: 188px;
235
+ padding: 1rem;
236
+ background:
237
+ linear-gradient(
238
+ 180deg,
239
+ color-mix(in srgb, var(--color-primary) 4%, transparent),
240
+ transparent 38%
241
+ ),
242
+ var(--color-panel);
243
+ }
244
+
245
+ .discovery-feature-head {
246
+ display: flex;
247
+ flex-direction: row;
248
+ align-items: center;
249
+ gap: 0.75rem;
250
+ width: 100%;
251
+ min-width: 0;
252
+ }
253
+
254
+ .discovery-feature-thumb {
255
+ flex: 0 0 auto;
256
+ width: 52px;
257
+ height: 52px;
258
+ display: flex;
259
+ align-items: center;
260
+ justify-content: center;
261
+ border-radius: 14px;
262
+ overflow: hidden;
263
+ background: color-mix(in srgb, var(--color-primary) 10%, transparent);
264
+ box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--color-primary) 10%, transparent);
265
+ }
266
+
267
+ .discovery-feature-thumb img {
268
+ width: 100%;
269
+ height: 100%;
270
+ object-fit: cover;
271
+ }
272
+
273
+ .discovery-feature-icon {
274
+ font-size: 1.45rem;
275
+ color: var(--color-highlight-dark);
276
+ }
277
+
278
+ .discovery-feature-title {
279
+ margin: 0;
280
+ flex: 1 1 auto;
281
+ min-width: 0;
282
+ color: var(--color-text);
283
+ font-size: 0.92rem;
284
+ font-weight: 600;
285
+ line-height: 1.25;
286
+ }
287
+
288
+ .discovery-feature-desc {
289
+ margin: 0.55rem 0 0;
290
+ padding-bottom: var(--spacing-md);
291
+ color: var(--color-text);
292
+ font-size: 0.8rem;
293
+ line-height: 1.45;
294
+ }
295
+
296
+ .discovery-feature-card > .btn {
297
+ margin-top: auto;
298
+ }
299
+
300
+ .discovery-cta-link {
301
+ margin-top: 0.95rem;
302
+ border: 1px solid color-mix(in srgb, var(--color-primary) 34%, var(--color-border));
303
+ border-radius: 8px;
304
+ background: transparent;
305
+ color: var(--color-primary);
306
+ padding: 0.42rem 0.72rem;
307
+ font-size: 0.79rem;
308
+ font-weight: 600;
309
+ }
310
+
311
+ .discovery-cta-link:hover,
312
+ .discovery-cta-link:focus-visible {
313
+ background: var(--color-primary);
314
+ border-color: var(--color-primary);
315
+ color: #fff;
316
+ outline: none;
317
+ }
318
+
319
+ .discovery-dismiss {
320
+ position: absolute;
321
+ top: 0.65rem;
322
+ right: 0.65rem;
323
+ display: flex;
324
+ align-items: center;
325
+ justify-content: center;
326
+ width: 28px;
327
+ height: 28px;
328
+ border: none;
329
+ border-radius: 8px;
330
+ background: transparent;
331
+ color: var(--color-secondary);
332
+ cursor: pointer;
333
+ opacity: 0;
334
+ transition:
335
+ opacity 0.2s ease,
336
+ background-color 0.2s ease,
337
+ color 0.2s ease;
338
+ z-index: 2;
339
+ }
340
+
341
+ .discovery-dismiss-small {
342
+ top: 0.55rem;
343
+ right: 0.55rem;
344
+ width: 26px;
345
+ height: 26px;
346
+ }
347
+
348
+ .discovery-hero:hover .discovery-dismiss,
349
+ .discovery-hero:focus-visible .discovery-dismiss,
350
+ .discovery-feature-card:hover .discovery-dismiss,
351
+ .discovery-feature-card:focus-visible .discovery-dismiss {
352
+ opacity: 0.68;
353
+ }
354
+
355
+ .discovery-dismiss:hover,
356
+ .discovery-dismiss:focus-visible {
357
+ opacity: 1;
358
+ color: var(--color-text);
359
+ background: color-mix(in srgb, var(--color-border) 84%, transparent);
360
+ outline: none;
361
+ }
362
+
363
+ .discovery-dismiss .material-symbols-outlined {
364
+ font-size: 1rem;
365
+ }
366
+
367
+ .discovery-undismiss {
368
+ display: flex;
369
+ justify-content: flex-start;
370
+ }
371
+
372
+ .discovery-undismiss-btn {
373
+ border: none;
374
+ background: transparent;
375
+ padding: 0;
376
+ color: var(--color-secondary);
377
+ font-size: 0.8rem;
378
+ font-weight: 500;
379
+ }
380
+
381
+ .discovery-undismiss-btn:hover,
382
+ .discovery-undismiss-btn:focus-visible {
383
+ color: var(--color-primary);
384
+ outline: none;
385
+ }
386
+
387
+ .discovery-cta-link .material-symbols-outlined,
388
+ .discovery-undismiss-btn .material-symbols-outlined {
389
+ font-size: 1rem;
390
+ }
391
+
392
+ @media (hover: none) {
393
+ .discovery-dismiss {
394
+ opacity: 0.68;
395
+ }
396
+ }
397
+
398
+ @media (max-width: 768px) {
399
+ .discovery-section {
400
+ gap: 0.85rem;
401
+ }
402
+
403
+ .discovery-hero {
404
+ min-height: 0;
405
+ padding: 1rem;
406
+ }
407
+
408
+ .discovery-hero-thumb {
409
+ flex-basis: 92px;
410
+ width: 92px;
411
+ height: 76px;
412
+ }
413
+
414
+ .discovery-features {
415
+ grid-template-columns: 1fr;
416
+ gap: 0.75rem;
417
+ }
418
+
419
+ .discovery-feature-card {
420
+ display: grid;
421
+ grid-template-columns: minmax(0, 1fr) auto;
422
+ gap: 0.75rem;
423
+ min-height: 0;
424
+ align-items: center;
425
+ padding: 0.85rem 1rem;
426
+ }
427
+
428
+ .discovery-feature-head {
429
+ grid-column: 1;
430
+ min-width: 0;
431
+ }
432
+
433
+ .discovery-feature-thumb {
434
+ width: 46px;
435
+ height: 46px;
436
+ }
437
+
438
+ .discovery-feature-desc {
439
+ display: none;
440
+ }
441
+
442
+ .discovery-feature-card > .btn {
443
+ grid-column: 2;
444
+ grid-row: 1;
445
+ align-self: center;
446
+ margin-top: 0;
447
+ }
448
+
449
+ .discovery-cta-link {
450
+ margin-top: 0;
451
+ }
452
+ }
453
+
454
+ @media (max-width: 520px) {
455
+ .discovery-slot {
456
+ margin-top: 0.15rem;
457
+ }
458
+
459
+ .discovery-hero {
460
+ padding-right: 0.95rem;
461
+ }
462
+
463
+ .discovery-hero-thumb {
464
+ display: none;
465
+ }
466
+
467
+ .discovery-hero-title {
468
+ font-size: 1rem;
469
+ }
470
+
471
+ .discovery-feature-card {
472
+ grid-template-columns: minmax(0, 1fr) auto;
473
+ padding-right: 3rem;
474
+ }
475
+
476
+ .discovery-feature-card > .btn {
477
+ justify-self: end;
478
+ }
479
+ }
480
+ </style>
481
+</div>