@feedlog-ai/webcomponents 0.0.25 → 0.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/feedlog-badge.cjs.entry.js +1 -1
- package/dist/cjs/feedlog-button_3.cjs.entry.js +65 -10
- package/dist/cjs/feedlog-card.cjs.entry.js +1 -1
- package/dist/cjs/feedlog-issues-client.cjs.entry.js +2 -2
- package/dist/cjs/feedlog-issues.cjs.entry.js +4 -4
- package/dist/cjs/feedlog-toolkit.cjs.js +2 -2
- package/dist/cjs/{index-SWDeFUqw.js → index-Bk1-M_w_.js} +48 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/collection/components/feedlog-issue/feedlog-issue.css +180 -33
- package/dist/collection/components/feedlog-issue/feedlog-issue.js +6 -4
- package/dist/collection/components/feedlog-issues/feedlog-issues.css +3 -1
- package/dist/collection/components/feedlog-issues/feedlog-issues.js +21 -2
- package/dist/collection/components/feedlog-issues/feedlog-issues.stories.js +28 -0
- package/dist/collection/components/feedlog-issues-client/feedlog-issues-client.js +1 -1
- package/dist/collection/components/feedlog-issues-list/feedlog-issues-list.css +58 -0
- package/dist/collection/components/feedlog-issues-list/feedlog-issues-list.js +80 -2
- package/dist/collection/test/mocks/feedlog-core.js +10 -0
- package/dist/components/feedlog-issue.js +1 -1
- package/dist/components/feedlog-issues-client.js +1 -1
- package/dist/components/feedlog-issues-list.js +1 -1
- package/dist/components/feedlog-issues.js +1 -1
- package/dist/components/index.js +1 -1
- package/dist/components/{p-BBPFf6g7.js → p-BuX7UXwe.js} +2 -2
- package/dist/components/p-DMKFbFjj.js +1 -0
- package/dist/components/p-GzOCQT_k.js +1 -0
- package/dist/esm/feedlog-badge.entry.js +1 -1
- package/dist/esm/feedlog-button_3.entry.js +65 -10
- package/dist/esm/feedlog-card.entry.js +1 -1
- package/dist/esm/feedlog-issues-client.entry.js +2 -2
- package/dist/esm/feedlog-issues.entry.js +4 -4
- package/dist/esm/feedlog-toolkit.js +3 -3
- package/dist/esm/{index-B0OkcXfW.js → index-CHawAwGP.js} +48 -1
- package/dist/esm/loader.js +3 -3
- package/dist/feedlog-toolkit/feedlog-toolkit.esm.js +1 -1
- package/dist/feedlog-toolkit/{p-6576aefa.entry.js → p-13089dc5.entry.js} +1 -1
- package/dist/feedlog-toolkit/p-7f8133b3.entry.js +1 -0
- package/dist/feedlog-toolkit/{p-B0OkcXfW.js → p-CHawAwGP.js} +2 -2
- package/dist/feedlog-toolkit/{p-1e3dd1c6.entry.js → p-bc48ec0d.entry.js} +1 -1
- package/dist/feedlog-toolkit/{p-25d89169.entry.js → p-c974a35e.entry.js} +1 -1
- package/dist/feedlog-toolkit/p-f868da29.entry.js +3 -0
- package/dist/types/components/feedlog-issue/feedlog-issue.d.ts +2 -1
- package/dist/types/components/feedlog-issues/feedlog-issues.d.ts +4 -0
- package/dist/types/components/feedlog-issues/feedlog-issues.stories.d.ts +1 -0
- package/dist/types/components/feedlog-issues-list/feedlog-issues-list.d.ts +10 -0
- package/dist/types/components.d.ts +16 -0
- package/dist/types/test/mocks/feedlog-core.d.ts +5 -0
- package/package.json +2 -2
- package/dist/components/p-BR3ookRG.js +0 -1
- package/dist/components/p-DKGIKLzX.js +0 -1
- package/dist/feedlog-toolkit/p-0733934f.entry.js +0 -3
- package/dist/feedlog-toolkit/p-191fc966.entry.js +0 -1
|
@@ -149,14 +149,15 @@
|
|
|
149
149
|
|
|
150
150
|
.issue-main {
|
|
151
151
|
display: flex;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
gap: 1rem;
|
|
152
|
+
flex-direction: column;
|
|
153
|
+
gap: 0;
|
|
155
154
|
}
|
|
156
155
|
|
|
157
|
-
.issue-
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
.issue-footer {
|
|
157
|
+
display: flex;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: flex-end;
|
|
160
|
+
margin-top: 0.75rem;
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
.issue-title {
|
|
@@ -294,62 +295,208 @@
|
|
|
294
295
|
}
|
|
295
296
|
|
|
296
297
|
.upvote-button {
|
|
297
|
-
display: flex;
|
|
298
|
-
flex-direction:
|
|
298
|
+
display: inline-flex;
|
|
299
|
+
flex-direction: row;
|
|
299
300
|
align-items: center;
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
border
|
|
303
|
-
background-color: var(--feedlog-muted);
|
|
304
|
-
border: 1px solid transparent;
|
|
301
|
+
border-radius: 0.375rem; /* 6px */
|
|
302
|
+
background-color: #ffffff;
|
|
303
|
+
border: 1px solid #e2e8f0;
|
|
305
304
|
cursor: pointer;
|
|
306
|
-
transition: all 0.2s
|
|
305
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
307
306
|
flex-shrink: 0;
|
|
308
|
-
|
|
309
|
-
|
|
307
|
+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
308
|
+
overflow: hidden;
|
|
309
|
+
padding: 0.375rem 0.75rem;
|
|
310
|
+
gap: 0.5rem;
|
|
311
|
+
font-family: inherit;
|
|
312
|
+
line-height: 1;
|
|
310
313
|
}
|
|
311
314
|
|
|
312
315
|
.upvote-button:hover {
|
|
313
|
-
background-color:
|
|
314
|
-
border-color:
|
|
316
|
+
background-color: #f8fafc;
|
|
317
|
+
border-color: #cbd5e1;
|
|
318
|
+
transform: translateY(-1px);
|
|
319
|
+
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.08), 0 2px 4px -2px rgba(0, 0, 0, 0.04);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
.upvote-button:active {
|
|
323
|
+
transform: translateY(0);
|
|
324
|
+
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
315
325
|
}
|
|
316
326
|
|
|
317
327
|
.upvote-button.upvoted {
|
|
318
|
-
background-color:
|
|
319
|
-
border-color:
|
|
328
|
+
background-color: #eff6ff;
|
|
329
|
+
border-color: #bfdbfe;
|
|
320
330
|
}
|
|
321
331
|
|
|
322
332
|
.upvote-button.upvoted:hover {
|
|
323
|
-
background-color:
|
|
324
|
-
border-color:
|
|
333
|
+
background-color: #dbeafe;
|
|
334
|
+
border-color: #93c5fd;
|
|
325
335
|
}
|
|
326
336
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
337
|
+
.upvote-action {
|
|
338
|
+
display: flex;
|
|
339
|
+
flex-direction: row;
|
|
340
|
+
align-items: center;
|
|
341
|
+
gap: 0.375rem;
|
|
342
|
+
color: #475569;
|
|
343
|
+
font-size: 0.875rem;
|
|
344
|
+
font-weight: 600;
|
|
345
|
+
transition: color 0.2s ease;
|
|
330
346
|
}
|
|
331
347
|
|
|
332
|
-
:
|
|
333
|
-
|
|
334
|
-
|
|
348
|
+
.upvote-button:hover .upvote-action {
|
|
349
|
+
color: #0f172a;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
.upvote-button.upvoted .upvote-action {
|
|
353
|
+
color: #2563eb;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
.upvote-button.upvoted:hover .upvote-action {
|
|
357
|
+
color: #1d4ed8;
|
|
335
358
|
}
|
|
336
359
|
|
|
337
360
|
.upvote-icon {
|
|
338
|
-
width:
|
|
339
|
-
height:
|
|
361
|
+
width: 1.125rem;
|
|
362
|
+
height: 1.125rem;
|
|
363
|
+
min-width: 1.125rem;
|
|
364
|
+
min-height: 1.125rem;
|
|
340
365
|
color: inherit;
|
|
366
|
+
flex-shrink: 0;
|
|
367
|
+
display: block;
|
|
368
|
+
vertical-align: middle;
|
|
369
|
+
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.upvote-button:hover .upvote-icon {
|
|
373
|
+
transform: translateY(-2px);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.upvote-button:active .upvote-icon {
|
|
377
|
+
transform: translateY(0) scale(0.9);
|
|
341
378
|
}
|
|
342
379
|
|
|
343
380
|
.upvote-icon.filled {
|
|
344
|
-
color:
|
|
381
|
+
color: inherit;
|
|
345
382
|
}
|
|
346
383
|
|
|
347
384
|
.upvote-icon.outline {
|
|
348
|
-
color:
|
|
385
|
+
color: inherit;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.reel-container {
|
|
389
|
+
position: relative;
|
|
390
|
+
display: inline-flex;
|
|
391
|
+
align-items: center;
|
|
392
|
+
height: 1.25rem;
|
|
393
|
+
overflow: hidden;
|
|
394
|
+
border-left: 1px solid #e2e8f0;
|
|
395
|
+
padding-left: 0.5rem;
|
|
396
|
+
transition: border-color 0.2s ease;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.upvote-button:hover .reel-container {
|
|
400
|
+
border-color: #cbd5e1;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
.upvote-button.upvoted .reel-container {
|
|
404
|
+
border-color: #bfdbfe;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
.upvote-button.upvoted:hover .reel-container {
|
|
408
|
+
border-color: #93c5fd;
|
|
349
409
|
}
|
|
350
410
|
|
|
351
411
|
.upvote-count {
|
|
352
|
-
font-size: 0.
|
|
412
|
+
font-size: 0.875rem;
|
|
353
413
|
font-weight: 600;
|
|
414
|
+
color: #475569;
|
|
415
|
+
transition: color 0.2s ease;
|
|
416
|
+
line-height: 1.25rem;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.upvote-button:hover .upvote-count {
|
|
420
|
+
color: #0f172a;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.upvote-button.upvoted .upvote-count {
|
|
424
|
+
color: #2563eb;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.upvote-button.upvoted:hover .upvote-count {
|
|
428
|
+
color: #1d4ed8;
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.reel-number {
|
|
432
|
+
display: inline-block;
|
|
433
|
+
animation: reelIn 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
@keyframes reelIn {
|
|
437
|
+
0% {
|
|
438
|
+
transform: translateY(100%);
|
|
439
|
+
opacity: 0;
|
|
440
|
+
}
|
|
441
|
+
100% {
|
|
442
|
+
transform: translateY(0);
|
|
443
|
+
opacity: 1;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/* Dark theme overrides */
|
|
448
|
+
:host(.dark) .upvote-button {
|
|
449
|
+
background-color: var(--feedlog-card);
|
|
450
|
+
border-color: var(--feedlog-border);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
:host(.dark) .upvote-button:hover {
|
|
454
|
+
background-color: var(--feedlog-muted);
|
|
455
|
+
border-color: var(--feedlog-muted-foreground);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
:host(.dark) .upvote-button.upvoted {
|
|
459
|
+
background-color: rgba(37, 99, 235, 0.15);
|
|
460
|
+
border-color: rgba(37, 99, 235, 0.3);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
:host(.dark) .upvote-button.upvoted:hover {
|
|
464
|
+
background-color: rgba(37, 99, 235, 0.25);
|
|
465
|
+
border-color: rgba(37, 99, 235, 0.4);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
:host(.dark) .upvote-action,
|
|
469
|
+
:host(.dark) .upvote-count {
|
|
470
|
+
color: var(--feedlog-muted-foreground);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
:host(.dark) .upvote-button:hover .upvote-action,
|
|
474
|
+
:host(.dark) .upvote-button:hover .upvote-count {
|
|
354
475
|
color: var(--feedlog-card-foreground);
|
|
355
476
|
}
|
|
477
|
+
|
|
478
|
+
:host(.dark) .upvote-button.upvoted .upvote-action,
|
|
479
|
+
:host(.dark) .upvote-button.upvoted .upvote-count {
|
|
480
|
+
color: var(--feedlog-blue-400);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
:host(.dark) .upvote-button.upvoted:hover .upvote-action,
|
|
484
|
+
:host(.dark) .upvote-button.upvoted:hover .upvote-count {
|
|
485
|
+
color: var(--feedlog-blue-300);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
:host(.dark) .reel-container {
|
|
489
|
+
border-color: var(--feedlog-border);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
:host(.dark) .upvote-button:hover .reel-container {
|
|
493
|
+
border-color: var(--feedlog-muted-foreground);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
:host(.dark) .upvote-button.upvoted .reel-container {
|
|
497
|
+
border-color: rgba(37, 99, 235, 0.3);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
:host(.dark) .upvote-button.upvoted:hover .reel-container {
|
|
501
|
+
border-color: rgba(37, 99, 235, 0.4);
|
|
502
|
+
}
|
|
@@ -27,13 +27,15 @@ export class FeedlogIssueComponent {
|
|
|
27
27
|
return (h("svg", { class: "pin-icon", xmlns: "http://www.w3.org/2000/svg", width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: "M12 17v5" }), h("path", { d: "M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16h1v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-2h1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z" })));
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
|
-
* Renders the upvote (
|
|
30
|
+
* Renders the upvote (caret-up / arrow) icon SVG
|
|
31
|
+
* Path centered in 24x24 viewBox for proper vertical alignment
|
|
31
32
|
*/
|
|
32
33
|
renderUpvoteIcon(filled) {
|
|
34
|
+
const path = 'M12 7l7 10H5l7-10z';
|
|
33
35
|
if (filled) {
|
|
34
|
-
return (h("svg", { class: "upvote-icon filled", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor" }, h("path", { d:
|
|
36
|
+
return (h("svg", { class: "upvote-icon filled", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "currentColor" }, h("path", { d: path })));
|
|
35
37
|
}
|
|
36
|
-
return (h("svg", { class: "upvote-icon outline", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d:
|
|
38
|
+
return (h("svg", { class: "upvote-icon outline", xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }, h("path", { d: path })));
|
|
37
39
|
}
|
|
38
40
|
/**
|
|
39
41
|
* Format an ISO date string to a relative time string
|
|
@@ -102,7 +104,7 @@ export class FeedlogIssueComponent {
|
|
|
102
104
|
const statusBadgeLabel = this.getStatusBadgeLabel();
|
|
103
105
|
const githubUrl = (_b = issue.githubIssueLink) !== null && _b !== void 0 ? _b : issueUrl;
|
|
104
106
|
const showGithubButton = githubUrl != null && githubUrl !== '';
|
|
105
|
-
return (h(Host, { class: this.theme === 'dark' ? 'dark' : '', "data-upvoted": issue.hasUpvoted ? 'true' : 'false' }, h("div", { class: `issue-card issue-type-${issue.type}` }, h("div", { class: "issue-content" }, h("div", { class: "issue-header" }, h("div", { class: "issue-header-left" }, h("div", { class: "issue-type-badge" }, issue.type === 'bug' ? (h("feedlog-badge", { variant: "destructive" }, "Bug")) : (h("feedlog-badge", { variant: "enhancement" }, "Enhancement"))), statusBadgeLabel && (h("feedlog-badge", { variant: "secondary" }, statusBadgeLabel)), issue.pinnedAt && (h("div", { class: "pinned-indicator", title: "Pinned issue" }, this.renderPinIcon()))), h("span", { class: "issue-timestamp", title: timestampTitle }, timestampLabel, " ", this.formatDate(timestampDate))), h("div", { class: "issue-main" }, h("
|
|
107
|
+
return (h(Host, { class: this.theme === 'dark' ? 'dark' : '', "data-upvoted": issue.hasUpvoted ? 'true' : 'false' }, h("div", { class: `issue-card issue-type-${issue.type}` }, h("div", { class: "issue-content" }, h("div", { class: "issue-header" }, h("div", { class: "issue-header-left" }, h("div", { class: "issue-type-badge" }, issue.type === 'bug' ? (h("feedlog-badge", { variant: "destructive" }, "Bug")) : (h("feedlog-badge", { variant: "enhancement" }, "Enhancement"))), statusBadgeLabel && (h("feedlog-badge", { variant: "secondary" }, statusBadgeLabel)), issue.pinnedAt && (h("div", { class: "pinned-indicator", title: "Pinned issue" }, this.renderPinIcon()))), h("span", { class: "issue-timestamp", title: timestampTitle }, timestampLabel, " ", this.formatDate(timestampDate))), h("div", { class: "issue-main" }, h("h3", { class: "issue-title" }, displayTitle), issue.body != null && issue.body !== '' && (h("div", { class: "issue-body", innerHTML: parseMarkdown(issue.body) })), h("div", { class: "issue-repository" }, repoName != null && (h("span", { class: "repo-name", title: repoTooltip }, repoName)), showGithubButton && (h("a", { part: "github-link", class: "github-link", href: githubUrl, target: "_blank", rel: "noopener noreferrer", title: "View on GitHub" }, this.renderExternalLinkIcon(), h("span", { class: "github-link-text" }, "View on GitHub")))), issue.type !== 'bug' && (h("div", { class: "issue-footer" }, h("button", { part: "upvote-button", class: `upvote-button ${issue.hasUpvoted ? 'upvoted' : ''}`, onClick: (e) => this.handleUpvote(e), title: issue.hasUpvoted ? 'Remove upvote' : 'Upvote this issue' }, h("div", { class: "upvote-action" }, h("slot", { name: "upvote-icon" }, this.renderUpvoteIcon(issue.hasUpvoted)), h("span", { class: "upvote-label" }, "Upvote")), h("div", { class: "reel-container" }, h("span", { class: "upvote-count reel-number", key: issue.upvoteCount }, issue.upvoteCount))))))))));
|
|
106
108
|
}
|
|
107
109
|
static get is() { return "feedlog-issue"; }
|
|
108
110
|
static get encapsulation() { return "shadow"; }
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
--feedlog-radius: 0.625rem;
|
|
23
23
|
--feedlog-gap: 0.5rem;
|
|
24
24
|
--feedlog-padding: 2rem;
|
|
25
|
+
--feedlog-min-height: 100%;
|
|
25
26
|
--feedlog-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.08), 0 1px 2px -1px rgba(0, 0, 0, 0.08);
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -45,11 +46,12 @@
|
|
|
45
46
|
|
|
46
47
|
|
|
47
48
|
.issues-container {
|
|
48
|
-
min-height:
|
|
49
|
+
min-height: var(--feedlog-min-height);
|
|
49
50
|
/* Parent can override via --feedlog-background (e.g. transparent); fallback to theme default */
|
|
50
51
|
background-color: var(--feedlog-background, var(--feedlog-theme-bg, #ffffff));
|
|
51
52
|
padding: var(--feedlog-padding);
|
|
52
53
|
margin: 0 auto;
|
|
54
|
+
border-radius: var(--feedlog-radius);
|
|
53
55
|
}
|
|
54
56
|
|
|
55
57
|
.issues-header {
|
|
@@ -55,13 +55,13 @@ export class FeedlogIssues {
|
|
|
55
55
|
}
|
|
56
56
|
renderIssuesList() {
|
|
57
57
|
var _a, _b;
|
|
58
|
-
return (h("feedlog-issues-list", { issues: this.issues, theme: this.currentTheme, getIssueUrl: this.getIssueUrl, emptyStateTitle: (_a = this.emptyStateTitle) !== null && _a !== void 0 ? _a : 'No updates yet', emptyStateMessage: (_b = this.emptyStateMessage) !== null && _b !== void 0 ? _b : 'Check back later for new updates.', onFeedlogUpvote: (e) => this.handleUpvote(e) }));
|
|
58
|
+
return (h("feedlog-issues-list", { issues: this.issues, limit: this.limit, theme: this.currentTheme, getIssueUrl: this.getIssueUrl, emptyStateTitle: (_a = this.emptyStateTitle) !== null && _a !== void 0 ? _a : 'No updates yet', emptyStateMessage: (_b = this.emptyStateMessage) !== null && _b !== void 0 ? _b : 'Check back later for new updates.', onFeedlogUpvote: (e) => this.handleUpvote(e) }));
|
|
59
59
|
}
|
|
60
60
|
render() {
|
|
61
61
|
const containerStyle = {
|
|
62
62
|
maxWidth: this.maxWidth,
|
|
63
63
|
};
|
|
64
|
-
return (h(Host, { key: '
|
|
64
|
+
return (h(Host, { key: '96686863c5eb831e64993c681c7780e035c0e2b2', class: this.currentTheme === 'dark' ? 'dark' : '' }, h("div", { key: '54d01678053f4fe58eb547f9954f497402495a83', class: "issues-container", style: containerStyle }, (this.heading || this.subtitle) && (h("header", { key: '889aa47cb4ceea60ca4a5615f512793d726059d9', class: "issues-header" }, h("div", { key: '8b4ac6a9ed0c6120ec838a1329416f3471cd2751', class: "header-content" }, this.heading && h("h1", { key: 'cfc52f28bc5131715a5c7a0b9231e440b4c0b67c', class: "issues-title" }, this.heading), this.subtitle && h("p", { key: '8b4488546ceb6e807d689b8fca2b2fd85722f824', class: "issues-subtitle" }, this.subtitle)))), this.loading && (h("div", { key: '35c382f4417893c17951b73dedb12452e805668c', class: "loading-state", role: "status", "aria-label": "Loading issues" }, h("div", { key: '2d83dd9d40bf7b2a14744ee4a715108a9cdebd60', class: "loading-skeletons" }, [1, 2, 3].map(i => (h("div", { key: i, class: "skeleton-card" }, h("div", { class: "skeleton-content" }, h("div", { class: "skeleton-header" }, h("div", { class: "skeleton-badge" }), h("div", { class: "skeleton-timestamp" })), h("div", { class: "skeleton-main" }, h("div", { class: "skeleton-title" }), h("div", { class: "skeleton-body" }, h("div", { class: "skeleton-line" }), h("div", { class: "skeleton-line short" })), h("div", { class: "skeleton-repo" })), h("div", { class: "skeleton-footer" }, h("div", { class: "skeleton-upvote" }))))))))), this.error && (h("div", { key: '43efd42ce0d213131ba97d42d1f98c52515ea9fd', class: "error-state", role: "alert" }, h("div", { key: 'ad22b0378e290556c896c628dadabf6091bbf972', class: "error-state-content" }, this.renderErrorIcon(), h("h2", { key: '9a9779f52de12aa2241ba9ddda6cf8297a4af84d', class: "error-state-title" }, "Something went wrong"), h("p", { key: 'c697040d37909d882730e5d9ab3a3b147061fc51', class: "error-state-message" }, this.error)))), !this.loading && !this.error && (h("div", { key: 'afc12552ff7ccc808c7191c1dd1e26d3b95bf2fd' }, this.renderIssuesList(), this.hasMore && (h("div", { key: '0f6c84bdeda386e4eec439fb80f4ee1606b9b559', class: "load-more-container" }, h("feedlog-button", { key: 'e6983bd889a6cdfd4a4b8a06f3a6a97c2d276243', onFeedlogClick: this.handleLoadMore, disabled: this.isLoadingMore, variant: "outline" }, this.isLoadingMore ? 'Loading...' : 'Load More Issues'))))))));
|
|
65
65
|
}
|
|
66
66
|
static get is() { return "feedlog-issues"; }
|
|
67
67
|
static get encapsulation() { return "shadow"; }
|
|
@@ -121,6 +121,25 @@ export class FeedlogIssues {
|
|
|
121
121
|
"attribute": "max-width",
|
|
122
122
|
"defaultValue": "'42rem'"
|
|
123
123
|
},
|
|
124
|
+
"limit": {
|
|
125
|
+
"type": "number",
|
|
126
|
+
"mutable": false,
|
|
127
|
+
"complexType": {
|
|
128
|
+
"original": "number",
|
|
129
|
+
"resolved": "number | undefined",
|
|
130
|
+
"references": {}
|
|
131
|
+
},
|
|
132
|
+
"required": false,
|
|
133
|
+
"optional": true,
|
|
134
|
+
"docs": {
|
|
135
|
+
"tags": [],
|
|
136
|
+
"text": "Page size for issues list pagination. When set, enables pagination when issues exceed this limit."
|
|
137
|
+
},
|
|
138
|
+
"getter": false,
|
|
139
|
+
"setter": false,
|
|
140
|
+
"reflect": false,
|
|
141
|
+
"attribute": "limit"
|
|
142
|
+
},
|
|
124
143
|
"theme": {
|
|
125
144
|
"type": "string",
|
|
126
145
|
"mutable": true,
|
|
@@ -96,6 +96,7 @@ const sampleIssues = [
|
|
|
96
96
|
hasUpvoted: false,
|
|
97
97
|
},
|
|
98
98
|
];
|
|
99
|
+
const manyIssues = Array.from({ length: 200 }, (_, i) => (Object.assign(Object.assign({}, sampleIssues[0]), { id: `issue-${i + 1}`, title: `Issue ${i + 1}` })));
|
|
99
100
|
const meta = {
|
|
100
101
|
title: 'Components/Issues',
|
|
101
102
|
component: 'feedlog-issues',
|
|
@@ -132,6 +133,10 @@ const meta = {
|
|
|
132
133
|
control: 'text',
|
|
133
134
|
description: 'Empty state message',
|
|
134
135
|
},
|
|
136
|
+
limit: {
|
|
137
|
+
control: 'number',
|
|
138
|
+
description: 'Page size for pagination',
|
|
139
|
+
},
|
|
135
140
|
},
|
|
136
141
|
args: {
|
|
137
142
|
issues: sampleIssues,
|
|
@@ -250,6 +255,29 @@ export const TransparentBackground = {
|
|
|
250
255
|
}
|
|
251
256
|
},
|
|
252
257
|
};
|
|
258
|
+
export const Paginated = {
|
|
259
|
+
args: {
|
|
260
|
+
issues: manyIssues,
|
|
261
|
+
limit: 10,
|
|
262
|
+
heading: 'Community feedback',
|
|
263
|
+
subtitle: 'Upvote issues you care about',
|
|
264
|
+
},
|
|
265
|
+
parameters: {
|
|
266
|
+
docs: {
|
|
267
|
+
description: {
|
|
268
|
+
story: 'Pagination with 200 issues, 10 per page. Shows first/last pages, 3 pages around current, and prev/next arrows.',
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
render: props => h("feedlog-issues", Object.assign({}, props)),
|
|
273
|
+
play: async ({ canvasElement, args }) => {
|
|
274
|
+
const element = canvasElement.querySelector('feedlog-issues');
|
|
275
|
+
if (element && args.issues) {
|
|
276
|
+
element.issues = args.issues;
|
|
277
|
+
element.limit = args.limit;
|
|
278
|
+
}
|
|
279
|
+
},
|
|
280
|
+
};
|
|
253
281
|
export const CustomCSSVars = {
|
|
254
282
|
args: {
|
|
255
283
|
issues: sampleIssues,
|
|
@@ -219,7 +219,7 @@ export class FeedlogIssuesClient {
|
|
|
219
219
|
const style = hostBg
|
|
220
220
|
? { '--feedlog-background': hostBg }
|
|
221
221
|
: undefined;
|
|
222
|
-
return (h("feedlog-issues", { key: '
|
|
222
|
+
return (h("feedlog-issues", { key: '15ae96d7d7b51964026f873f8b97e10530ed02b4', style: style, issues: this.issues, limit: this.limit, maxWidth: this.maxWidth, theme: this.theme, heading: this.heading, subtitle: this.subtitle, emptyStateTitle: this.emptyStateTitle, emptyStateMessage: this.emptyStateMessage, getIssueUrl: this.getIssueUrl, loading: this.loading, error: this.error, hasMore: this.hasMore, isLoadingMore: this.isLoadingMore, onFeedlogUpvote: this.handleUpvote, onFeedlogLoadMore: async () => this.loadMore() }));
|
|
223
223
|
}
|
|
224
224
|
static get is() { return "feedlog-issues-client"; }
|
|
225
225
|
static get encapsulation() { return "shadow"; }
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
align-items: center;
|
|
35
35
|
text-align: center;
|
|
36
36
|
max-width: 20rem;
|
|
37
|
+
margin-inline: auto;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
.empty-state-illustration {
|
|
@@ -55,3 +56,60 @@
|
|
|
55
56
|
color: var(--feedlog-muted-foreground);
|
|
56
57
|
line-height: 1.5;
|
|
57
58
|
}
|
|
59
|
+
|
|
60
|
+
.pagination {
|
|
61
|
+
display: flex;
|
|
62
|
+
align-items: center;
|
|
63
|
+
justify-content: center;
|
|
64
|
+
gap: 0.25rem;
|
|
65
|
+
margin-top: 1.5rem;
|
|
66
|
+
flex-wrap: wrap;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.pagination-btn {
|
|
70
|
+
min-width: 2rem;
|
|
71
|
+
height: 2rem;
|
|
72
|
+
padding: 0 0.5rem;
|
|
73
|
+
color: var(--feedlog-foreground);
|
|
74
|
+
background: transparent;
|
|
75
|
+
border: 1px solid var(--feedlog-border, oklch(0.9 0 0));
|
|
76
|
+
border-radius: var(--feedlog-radius, 0.375rem);
|
|
77
|
+
font-size: 0.875rem;
|
|
78
|
+
font-weight: 500;
|
|
79
|
+
cursor: pointer;
|
|
80
|
+
transition: background-color 0.15s, border-color 0.15s;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.pagination-btn:hover:not(:disabled) {
|
|
84
|
+
background: var(--feedlog-muted, oklch(0.96 0 0));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.pagination-btn[aria-current='page'] {
|
|
88
|
+
background: var(--feedlog-accent-color, oklch(0.55 0.2 250));
|
|
89
|
+
color: white;
|
|
90
|
+
border-color: var(--feedlog-accent-color, oklch(0.55 0.2 250));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.pagination-btn:disabled {
|
|
94
|
+
opacity: 0.5;
|
|
95
|
+
cursor: not-allowed;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.pagination-arrow {
|
|
99
|
+
font-size: 1.25rem;
|
|
100
|
+
line-height: 1;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.pagination-ellipsis {
|
|
104
|
+
padding: 0 0.25rem;
|
|
105
|
+
color: var(--feedlog-muted-foreground);
|
|
106
|
+
font-size: 0.875rem;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
:host(.dark) .pagination-btn {
|
|
110
|
+
border-color: oklch(0.4 0.02 260);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
:host(.dark) .pagination-btn:hover:not(:disabled) {
|
|
114
|
+
background: oklch(0.35 0.02 260);
|
|
115
|
+
}
|
|
@@ -14,19 +14,64 @@ export class FeedlogIssuesList {
|
|
|
14
14
|
* Theme variant: 'light' or 'dark'
|
|
15
15
|
*/
|
|
16
16
|
this.theme = 'light';
|
|
17
|
+
this.currentPage = 1;
|
|
17
18
|
this.handleUpvote = (event) => {
|
|
18
19
|
event.stopPropagation();
|
|
19
20
|
this.feedlogUpvote.emit(event.detail);
|
|
20
21
|
};
|
|
21
22
|
}
|
|
23
|
+
resetPage() {
|
|
24
|
+
this.currentPage = 1;
|
|
25
|
+
}
|
|
22
26
|
renderEmptyStateIllustration() {
|
|
23
27
|
return (h("svg", { class: "empty-state-illustration", xmlns: "http://www.w3.org/2000/svg", width: "120", height: "96", viewBox: "0 0 120 96", fill: "none", "aria-hidden": "true" }, h("path", { d: "M20 36h80v44c0 4.4-3.6 8-8 8H28c-4.4 0-8-3.6-8-8V36z", fill: "var(--feedlog-empty-illustration-bg)", stroke: "var(--feedlog-empty-illustration-stroke)", "stroke-width": "1.5", "stroke-linejoin": "round" }), h("path", { d: "M20 36l20-24h40l20 24", fill: "none", stroke: "var(--feedlog-empty-illustration-stroke)", "stroke-width": "1.5", "stroke-linecap": "round", "stroke-linejoin": "round" }), h("path", { d: "M44 52h32M44 60h24M44 68h28", stroke: "var(--feedlog-empty-illustration-muted)", "stroke-width": "1.25", "stroke-linecap": "round" })));
|
|
24
28
|
}
|
|
29
|
+
getVisibleIssues() {
|
|
30
|
+
if (this.issues.length === 0)
|
|
31
|
+
return [];
|
|
32
|
+
if (this.limit == null || this.issues.length <= this.limit) {
|
|
33
|
+
return this.issues;
|
|
34
|
+
}
|
|
35
|
+
const offset = (this.currentPage - 1) * this.limit;
|
|
36
|
+
return this.issues.slice(offset, offset + this.limit);
|
|
37
|
+
}
|
|
38
|
+
getPageNumbers() {
|
|
39
|
+
if (this.limit == null)
|
|
40
|
+
return [];
|
|
41
|
+
const totalPages = Math.ceil(this.issues.length / this.limit);
|
|
42
|
+
if (totalPages <= 1)
|
|
43
|
+
return [];
|
|
44
|
+
const toShow = new Set([1, totalPages]);
|
|
45
|
+
const start = Math.max(1, this.currentPage - 1);
|
|
46
|
+
const end = Math.min(totalPages, this.currentPage + 1);
|
|
47
|
+
for (let i = start; i <= end; i++)
|
|
48
|
+
toShow.add(i);
|
|
49
|
+
const sorted = Array.from(toShow).sort((a, b) => a - b);
|
|
50
|
+
const result = [];
|
|
51
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
52
|
+
if (i > 0 && sorted[i] - sorted[i - 1] > 1)
|
|
53
|
+
result.push('ellipsis');
|
|
54
|
+
result.push(sorted[i]);
|
|
55
|
+
}
|
|
56
|
+
return result;
|
|
57
|
+
}
|
|
58
|
+
goToPage(page) {
|
|
59
|
+
const totalPages = this.limit != null ? Math.ceil(this.issues.length / this.limit) : 1;
|
|
60
|
+
this.currentPage = Math.max(1, Math.min(page, totalPages));
|
|
61
|
+
}
|
|
62
|
+
renderPagination() {
|
|
63
|
+
if (this.limit == null || this.issues.length <= this.limit)
|
|
64
|
+
return null;
|
|
65
|
+
const totalPages = Math.ceil(this.issues.length / this.limit);
|
|
66
|
+
const pageNumbers = this.getPageNumbers();
|
|
67
|
+
return (h("nav", { class: "pagination", "aria-label": "Issues pagination" }, h("button", { type: "button", class: "pagination-btn pagination-arrow", "aria-label": "Previous page", disabled: this.currentPage <= 1, onClick: () => this.goToPage(this.currentPage - 1) }, "\u2039"), pageNumbers.map((p, i) => p === 'ellipsis' ? (h("span", { key: i, class: "pagination-ellipsis", "aria-hidden": "true" }, "\u2026")) : (h("button", { key: i, type: "button", class: "pagination-btn", "aria-current": p === this.currentPage ? 'page' : undefined, onClick: () => this.goToPage(p) }, p))), h("button", { type: "button", class: "pagination-btn pagination-arrow", "aria-label": "Next page", disabled: this.currentPage >= totalPages, onClick: () => this.goToPage(this.currentPage + 1) }, "\u203A")));
|
|
68
|
+
}
|
|
25
69
|
render() {
|
|
26
|
-
|
|
70
|
+
const visibleIssues = this.getVisibleIssues();
|
|
71
|
+
return (h(Host, { key: '474f5ca0d8edc94a8e9a03d83c6a977270391d65', class: this.theme === 'dark' ? 'dark' : '' }, h("div", { key: '8f2f8125653ec5f80b167945a33cefe483c1a001', class: "issues-list" }, visibleIssues.length === 0 ? (h("div", { class: "empty-state" }, this.emptyStateTitle && this.emptyStateMessage ? (h("div", { class: "empty-state-content" }, this.renderEmptyStateIllustration(), h("h2", { class: "empty-state-title" }, this.emptyStateTitle), h("p", { class: "empty-state-message" }, this.emptyStateMessage))) : (h("p", null, "No issues found")))) : (visibleIssues.map(issue => {
|
|
27
72
|
var _a, _b;
|
|
28
73
|
return (h("feedlog-issue", { key: issue.id, issue: issue, issueUrl: (_b = (_a = this.getIssueUrl) === null || _a === void 0 ? void 0 : _a.call(this, issue)) !== null && _b !== void 0 ? _b : undefined, theme: this.theme, onFeedlogUpvote: (e) => this.handleUpvote(e) }));
|
|
29
|
-
})))));
|
|
74
|
+
}))), this.renderPagination()));
|
|
30
75
|
}
|
|
31
76
|
static get is() { return "feedlog-issues-list"; }
|
|
32
77
|
static get encapsulation() { return "shadow"; }
|
|
@@ -66,6 +111,25 @@ export class FeedlogIssuesList {
|
|
|
66
111
|
"setter": false,
|
|
67
112
|
"defaultValue": "[]"
|
|
68
113
|
},
|
|
114
|
+
"limit": {
|
|
115
|
+
"type": "number",
|
|
116
|
+
"mutable": false,
|
|
117
|
+
"complexType": {
|
|
118
|
+
"original": "number",
|
|
119
|
+
"resolved": "number | undefined",
|
|
120
|
+
"references": {}
|
|
121
|
+
},
|
|
122
|
+
"required": false,
|
|
123
|
+
"optional": true,
|
|
124
|
+
"docs": {
|
|
125
|
+
"tags": [],
|
|
126
|
+
"text": "Page size (items per page). When set, enables pagination when issues exceed this limit."
|
|
127
|
+
},
|
|
128
|
+
"getter": false,
|
|
129
|
+
"setter": false,
|
|
130
|
+
"reflect": false,
|
|
131
|
+
"attribute": "limit"
|
|
132
|
+
},
|
|
69
133
|
"theme": {
|
|
70
134
|
"type": "string",
|
|
71
135
|
"mutable": false,
|
|
@@ -149,6 +213,11 @@ export class FeedlogIssuesList {
|
|
|
149
213
|
}
|
|
150
214
|
};
|
|
151
215
|
}
|
|
216
|
+
static get states() {
|
|
217
|
+
return {
|
|
218
|
+
"currentPage": {}
|
|
219
|
+
};
|
|
220
|
+
}
|
|
152
221
|
static get events() {
|
|
153
222
|
return [{
|
|
154
223
|
"method": "feedlogUpvote",
|
|
@@ -167,4 +236,13 @@ export class FeedlogIssuesList {
|
|
|
167
236
|
}
|
|
168
237
|
}];
|
|
169
238
|
}
|
|
239
|
+
static get watchers() {
|
|
240
|
+
return [{
|
|
241
|
+
"propName": "issues",
|
|
242
|
+
"methodName": "resetPage"
|
|
243
|
+
}, {
|
|
244
|
+
"propName": "limit",
|
|
245
|
+
"methodName": "resetPage"
|
|
246
|
+
}];
|
|
247
|
+
}
|
|
170
248
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock for @feedlog-ai/core used in tests.
|
|
3
|
+
* Mapped via Stencil testing config moduleNameMapper to avoid CI resolution issues.
|
|
4
|
+
*/
|
|
5
|
+
export const FeedlogSDK = jest.fn().mockImplementation(() => ({
|
|
6
|
+
fetchIssues: jest
|
|
7
|
+
.fn()
|
|
8
|
+
.mockResolvedValue({ issues: [], pagination: { cursor: null, hasMore: false } }),
|
|
9
|
+
toggleUpvote: jest.fn(),
|
|
10
|
+
}));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{F as o,d as s}from"./p-
|
|
1
|
+
import{F as o,d as s}from"./p-BuX7UXwe.js";const p=o,r=s;export{p as FeedlogIssue,r as defineCustomElement}
|