@internetarchive/collection-browser 4.4.1 → 4.5.1-alpha-webdev8221.0
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/.editorconfig +29 -29
- package/.github/workflows/ci.yml +27 -27
- package/.github/workflows/gh-pages-main.yml +39 -39
- package/.github/workflows/npm-publish.yml +39 -39
- package/.github/workflows/pr-preview.yml +38 -38
- package/.husky/pre-commit +1 -1
- package/.prettierignore +1 -1
- package/LICENSE +661 -661
- package/README.md +83 -83
- package/dist/index.d.ts +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/app-root.d.ts +8 -0
- package/dist/src/app-root.js +26 -0
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/collection-browser.d.ts +8 -4
- package/dist/src/collection-browser.js +20 -11
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets/facet-row.d.ts +6 -0
- package/dist/src/collection-facets/facet-row.js +19 -1
- package/dist/src/collection-facets/facet-row.js.map +1 -1
- package/dist/src/collection-facets/facets-template.js +2 -0
- package/dist/src/collection-facets/facets-template.js.map +1 -1
- package/dist/src/data-source/collection-browser-data-source-interface.d.ts +5 -0
- package/dist/src/data-source/collection-browser-data-source-interface.js.map +1 -1
- package/dist/src/data-source/collection-browser-data-source.d.ts +1 -1
- package/dist/src/data-source/collection-browser-data-source.js +8 -6
- package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
- package/dist/src/restoration-state-handler.js +2 -4
- package/dist/src/restoration-state-handler.js.map +1 -1
- package/dist/src/styles/tile-action-styles.d.ts +14 -0
- package/dist/src/styles/tile-action-styles.js +59 -0
- package/dist/src/styles/tile-action-styles.js.map +1 -0
- package/dist/src/tiles/base-tile-component.d.ts +17 -1
- package/dist/src/tiles/base-tile-component.js +50 -1
- package/dist/src/tiles/base-tile-component.js.map +1 -1
- package/dist/src/tiles/grid/item-tile.js +1 -0
- package/dist/src/tiles/grid/item-tile.js.map +1 -1
- package/dist/src/tiles/list/tile-list-compact-header.js +27 -2
- package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
- package/dist/src/tiles/list/tile-list-compact.d.ts +1 -1
- package/dist/src/tiles/list/tile-list-compact.js +113 -75
- package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
- package/dist/src/tiles/list/tile-list.d.ts +1 -1
- package/dist/src/tiles/list/tile-list.js +164 -146
- package/dist/src/tiles/list/tile-list.js.map +1 -1
- package/dist/src/tiles/models.d.ts +11 -0
- package/dist/src/tiles/models.js.map +1 -1
- package/dist/src/tiles/tile-dispatcher.d.ts +14 -0
- package/dist/src/tiles/tile-dispatcher.js +107 -4
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/src/utils/date-filter-field.d.ts +6 -0
- package/dist/src/utils/date-filter-field.js +9 -0
- package/dist/src/utils/date-filter-field.js.map +1 -0
- package/dist/test/collection-browser.test.js +81 -0
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/collection-facets/facet-row.test.js +32 -0
- package/dist/test/collection-facets/facet-row.test.js.map +1 -1
- package/eslint.config.mjs +53 -53
- package/index.html +24 -24
- package/index.ts +1 -0
- package/local.archive.org.cert +86 -86
- package/local.archive.org.key +27 -27
- package/package.json +120 -120
- package/renovate.json +6 -6
- package/src/app-root.ts +30 -0
- package/src/collection-browser.ts +17 -13
- package/src/collection-facets/facet-row.ts +11 -1
- package/src/collection-facets/facets-template.ts +2 -0
- package/src/data-source/collection-browser-data-source-interface.ts +6 -0
- package/src/data-source/collection-browser-data-source.ts +16 -7
- package/src/restoration-state-handler.ts +5 -5
- package/src/styles/tile-action-styles.ts +59 -0
- package/src/tiles/base-tile-component.ts +60 -1
- package/src/tiles/grid/item-tile.ts +1 -0
- package/src/tiles/list/tile-list-compact-header.ts +28 -2
- package/src/tiles/list/tile-list-compact.ts +114 -75
- package/src/tiles/list/tile-list.ts +190 -172
- package/src/tiles/models.ts +13 -0
- package/src/tiles/tile-dispatcher.ts +114 -4
- package/src/utils/date-filter-field.ts +11 -0
- package/test/collection-browser.test.ts +132 -0
- package/test/collection-facets/facet-row.test.ts +46 -0
- package/tsconfig.json +25 -25
- package/web-dev-server.config.mjs +30 -30
- package/web-test-runner.config.mjs +52 -52
|
@@ -15,6 +15,7 @@ import { BaseTileComponent } from '../base-tile-component';
|
|
|
15
15
|
import { formatCount, NumberFormat } from '../../utils/format-count';
|
|
16
16
|
import type { DateFormat } from '../../utils/format-date';
|
|
17
17
|
import { isFirstMillisecondOfUTCYear } from '../../utils/local-date-from-utc';
|
|
18
|
+
import { tileActionStyles } from '../../styles/tile-action-styles';
|
|
18
19
|
|
|
19
20
|
import '../image-block';
|
|
20
21
|
import '../review-block';
|
|
@@ -26,6 +27,7 @@ export class TileList extends BaseTileComponent {
|
|
|
26
27
|
/*
|
|
27
28
|
* Reactive properties inherited from BaseTileComponent:
|
|
28
29
|
* - model?: TileModel;
|
|
30
|
+
* - tileActions: TileAction[] = [];
|
|
29
31
|
* - currentWidth?: number;
|
|
30
32
|
* - currentHeight?: number;
|
|
31
33
|
* - baseNavigationUrl?: string;
|
|
@@ -61,7 +63,9 @@ export class TileList extends BaseTileComponent {
|
|
|
61
63
|
private get mobileTemplate() {
|
|
62
64
|
return html`
|
|
63
65
|
<div id="list-line-top">
|
|
64
|
-
<div id="list-line-left"
|
|
66
|
+
<div id="list-line-left">
|
|
67
|
+
${this.imageBlockTemplate} ${this.renderTileActions('list-detail')}
|
|
68
|
+
</div>
|
|
65
69
|
<div id="list-line-right">
|
|
66
70
|
<div id="title-line">
|
|
67
71
|
<div id="title">${this.titleTemplate}</div>
|
|
@@ -75,7 +79,9 @@ export class TileList extends BaseTileComponent {
|
|
|
75
79
|
|
|
76
80
|
private get desktopTemplate() {
|
|
77
81
|
return html`
|
|
78
|
-
<div id="list-line-left"
|
|
82
|
+
<div id="list-line-left">
|
|
83
|
+
${this.imageBlockTemplate} ${this.renderTileActions('list-detail')}
|
|
84
|
+
</div>
|
|
79
85
|
<div id="list-line-right">
|
|
80
86
|
<div id="title-line">
|
|
81
87
|
<div id="title">${this.titleTemplate}</div>
|
|
@@ -511,190 +517,202 @@ export class TileList extends BaseTileComponent {
|
|
|
511
517
|
}
|
|
512
518
|
|
|
513
519
|
static get styles() {
|
|
514
|
-
return
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
520
|
+
return [
|
|
521
|
+
tileActionStyles,
|
|
522
|
+
css`
|
|
523
|
+
html {
|
|
524
|
+
font-size: unset;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
div {
|
|
528
|
+
font-size: 14px;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
div a {
|
|
532
|
+
text-decoration: none;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
div a:link {
|
|
536
|
+
color: var(--ia-theme-link-color, #4b64ff);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
.label {
|
|
540
|
+
font-weight: bold;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
#list-line.mobile {
|
|
544
|
+
--infiniteScrollerRowGap: 20px;
|
|
545
|
+
--infiniteScrollerRowHeight: auto;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
#list-line.desktop {
|
|
549
|
+
--infiniteScrollerRowGap: 30px;
|
|
550
|
+
--infiniteScrollerRowHeight: auto;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/* fields */
|
|
554
|
+
#icon-right {
|
|
555
|
+
width: 20px;
|
|
556
|
+
padding-top: 5px;
|
|
557
|
+
--iconHeight: 20px;
|
|
558
|
+
--iconWidth: 20px;
|
|
559
|
+
--iconTextAlign: right;
|
|
560
|
+
margin-top: -8px;
|
|
561
|
+
text-align: right;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
#title {
|
|
565
|
+
color: #4b64ff;
|
|
566
|
+
text-decoration: none;
|
|
567
|
+
font-size: 22px;
|
|
568
|
+
font-weight: bold;
|
|
569
|
+
/* align top of text with image */
|
|
570
|
+
line-height: 25px;
|
|
571
|
+
margin-top: -4px;
|
|
572
|
+
padding-bottom: 2px;
|
|
573
|
+
flex-grow: 1;
|
|
574
|
+
|
|
575
|
+
display: -webkit-box;
|
|
576
|
+
-webkit-box-orient: vertical;
|
|
577
|
+
-webkit-line-clamp: 3;
|
|
578
|
+
overflow: hidden;
|
|
579
|
+
overflow-wrap: anywhere;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.metadata {
|
|
583
|
+
line-height: 20px;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
#description,
|
|
587
|
+
#creator,
|
|
588
|
+
#topics,
|
|
589
|
+
#source {
|
|
590
|
+
text-align: left;
|
|
591
|
+
overflow: hidden;
|
|
592
|
+
text-overflow: ellipsis;
|
|
593
|
+
-webkit-box-orient: vertical;
|
|
594
|
+
display: -webkit-box;
|
|
595
|
+
word-break: break-word;
|
|
596
|
+
-webkit-line-clamp: 3; /* number of lines to show */
|
|
597
|
+
line-clamp: 3;
|
|
598
|
+
|
|
599
|
+
/*
|
|
592
600
|
* Safari doesn't always respect the line-clamping rules above,
|
|
593
601
|
* so we add this to ensure these fields still get truncated
|
|
594
602
|
*/
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
603
|
+
max-height: 60px;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
#collections {
|
|
607
|
+
display: -webkit-box;
|
|
608
|
+
-webkit-box-orient: vertical;
|
|
609
|
+
-webkit-line-clamp: 3;
|
|
610
|
+
overflow: hidden;
|
|
611
|
+
overflow-wrap: anywhere;
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
#collections > a {
|
|
615
|
+
display: inline-block;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
#icon {
|
|
619
|
+
padding-top: 5px;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
#description {
|
|
623
|
+
padding-top: 10px;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
/* Top level container */
|
|
627
|
+
#list-line {
|
|
628
|
+
display: flex;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
#list-line.mobile {
|
|
632
|
+
flex-direction: column;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
#list-line.desktop {
|
|
636
|
+
column-gap: 10px;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
#list-line-top {
|
|
640
|
+
display: flex;
|
|
641
|
+
column-gap: 7px;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
#list-line-bottom {
|
|
645
|
+
padding-top: 4px;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
#list-line-right,
|
|
649
|
+
#list-line-top,
|
|
650
|
+
#list-line-bottom {
|
|
651
|
+
width: 100%;
|
|
652
|
+
}
|
|
613
653
|
|
|
614
|
-
|
|
615
|
-
padding-top: 10px;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
/* Top level container */
|
|
619
|
-
#list-line {
|
|
620
|
-
display: flex;
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
#list-line.mobile {
|
|
624
|
-
flex-direction: column;
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
#list-line.desktop {
|
|
628
|
-
column-gap: 10px;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
#list-line-top {
|
|
632
|
-
display: flex;
|
|
633
|
-
column-gap: 7px;
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
#list-line-bottom {
|
|
637
|
-
padding-top: 4px;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
#list-line-right,
|
|
641
|
-
#list-line-top,
|
|
642
|
-
#list-line-bottom {
|
|
643
|
-
width: 100%;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/*
|
|
654
|
+
/*
|
|
647
655
|
* If the container becomes very tiny, don't let the thumbnail side take
|
|
648
656
|
* up too much space. Shouldn't make a difference on ordinary viewport sizes.
|
|
649
657
|
*/
|
|
650
|
-
|
|
651
|
-
|
|
658
|
+
#list-line-left {
|
|
659
|
+
max-width: 25%;
|
|
660
|
+
|
|
661
|
+
display: flex;
|
|
662
|
+
flex-direction: column;
|
|
663
|
+
row-gap: 5px;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
div a:hover {
|
|
667
|
+
text-decoration: underline;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/* Lines containing multiple div as row */
|
|
671
|
+
#item-line,
|
|
672
|
+
#dates-line,
|
|
673
|
+
#views-line,
|
|
674
|
+
#title-line {
|
|
675
|
+
display: flex;
|
|
676
|
+
flex-direction: row;
|
|
677
|
+
column-gap: 10px;
|
|
678
|
+
}
|
|
652
679
|
|
|
653
|
-
|
|
654
|
-
flex-direction: column;
|
|
655
|
-
row-gap: 5px;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
div a:hover {
|
|
659
|
-
text-decoration: underline;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
/* Lines containing multiple div as row */
|
|
663
|
-
#item-line,
|
|
664
|
-
#dates-line,
|
|
665
|
-
#views-line,
|
|
666
|
-
#title-line {
|
|
667
|
-
display: flex;
|
|
668
|
-
flex-direction: row;
|
|
669
|
-
column-gap: 10px;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/*
|
|
680
|
+
/*
|
|
673
681
|
* With the exception of the title line, allow these to wrap if
|
|
674
682
|
* the space becomes too small to accommodate them together.
|
|
675
683
|
*
|
|
676
684
|
* The title line is excluded because it contains the mediatype icon
|
|
677
685
|
* which we don't want to wrap.
|
|
678
686
|
*/
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
687
|
+
#item-line,
|
|
688
|
+
#dates-line,
|
|
689
|
+
#views-line {
|
|
690
|
+
flex-wrap: wrap;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.capture-dates {
|
|
694
|
+
margin: 0;
|
|
695
|
+
padding: 0;
|
|
696
|
+
list-style-type: none;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.capture-dates a:link {
|
|
700
|
+
text-decoration: none;
|
|
701
|
+
color: var(--ia-theme-link-color, #4b64ff);
|
|
702
|
+
}
|
|
703
|
+
.capture-dates a:hover {
|
|
704
|
+
text-decoration: underline;
|
|
705
|
+
}
|
|
684
706
|
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
.capture-dates a:hover {
|
|
696
|
-
text-decoration: underline;
|
|
697
|
-
}
|
|
698
|
-
`;
|
|
707
|
+
/*
|
|
708
|
+
* Tile-list (extended) action row sits under the thumbnail in the left
|
|
709
|
+
* column. The image-block above already has its own bottom padding via
|
|
710
|
+
* the parent's row-gap, so we don't need extra spacing here.
|
|
711
|
+
*/
|
|
712
|
+
.tile-actions.list-detail {
|
|
713
|
+
width: 100%;
|
|
714
|
+
}
|
|
715
|
+
`,
|
|
716
|
+
];
|
|
699
717
|
}
|
|
700
718
|
}
|
package/src/tiles/models.ts
CHANGED
|
@@ -6,3 +6,16 @@
|
|
|
6
6
|
* - `minimal`: Show neither tile stats nor the text snippets.
|
|
7
7
|
*/
|
|
8
8
|
export type LayoutType = 'default' | 'stats-only' | 'snippets-only' | 'minimal';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Describes an action button to render on a tile.
|
|
12
|
+
* Styling is controlled via the CSS custom properties documented in
|
|
13
|
+
* `src/styles/tile-action-styles.ts`.
|
|
14
|
+
*/
|
|
15
|
+
export interface TileAction {
|
|
16
|
+
/** Unique identifier for this action, included in the `tileActionClicked` event */
|
|
17
|
+
id: string;
|
|
18
|
+
|
|
19
|
+
/** Visible label text displayed on the button */
|
|
20
|
+
label: string;
|
|
21
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { css, html, nothing, PropertyValues } from 'lit';
|
|
2
2
|
import { customElement, property, query } from 'lit/decorators.js';
|
|
3
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
3
4
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
4
5
|
import { msg } from '@lit/localize';
|
|
5
6
|
import type {
|
|
@@ -26,6 +27,7 @@ import {
|
|
|
26
27
|
HoverPaneProviderInterface,
|
|
27
28
|
} from './hover/hover-pane-controller';
|
|
28
29
|
import { srOnlyStyle } from '../styles/sr-only';
|
|
30
|
+
import { tileActionStyles } from '../styles/tile-action-styles';
|
|
29
31
|
|
|
30
32
|
@customElement('tile-dispatcher')
|
|
31
33
|
export class TileDispatcher
|
|
@@ -37,6 +39,7 @@ export class TileDispatcher
|
|
|
37
39
|
/*
|
|
38
40
|
* Reactive properties inherited from BaseTileComponent:
|
|
39
41
|
* - model?: TileModel;
|
|
42
|
+
* - tileActions: TileAction[] = [];
|
|
40
43
|
* - currentWidth?: number;
|
|
41
44
|
* - currentHeight?: number;
|
|
42
45
|
* - baseNavigationUrl?: string;
|
|
@@ -104,14 +107,20 @@ export class TileDispatcher
|
|
|
104
107
|
|
|
105
108
|
render() {
|
|
106
109
|
const isGridMode = this.tileDisplayMode === 'grid';
|
|
110
|
+
const hasTileActions = isGridMode && this.showGridTileActions;
|
|
107
111
|
const hoverPaneTemplate =
|
|
108
112
|
this.hoverPaneController?.getTemplate() ?? nothing;
|
|
113
|
+
const containerClasses = classMap({
|
|
114
|
+
hoverable: isGridMode,
|
|
115
|
+
'has-tile-actions': hasTileActions,
|
|
116
|
+
});
|
|
109
117
|
return html`
|
|
110
|
-
<div id="container" class=${
|
|
118
|
+
<div id="container" class=${containerClasses}>
|
|
111
119
|
${this.tileDisplayMode === 'list-header'
|
|
112
120
|
? this.headerTemplate
|
|
113
121
|
: this.tileTemplate}
|
|
114
|
-
${this.
|
|
122
|
+
${this.gridTileActionsTemplate} ${this.manageCheckTemplate}
|
|
123
|
+
${hoverPaneTemplate}
|
|
115
124
|
</div>
|
|
116
125
|
`;
|
|
117
126
|
}
|
|
@@ -134,6 +143,7 @@ export class TileDispatcher
|
|
|
134
143
|
.currentWidth=${currentWidth}
|
|
135
144
|
.sortParam=${sortParam ?? defaultSortParam}
|
|
136
145
|
.mobileBreakpoint=${mobileBreakpoint}
|
|
146
|
+
.tileActions=${this.tileActions}
|
|
137
147
|
>
|
|
138
148
|
</tile-list-compact-header>
|
|
139
149
|
`;
|
|
@@ -306,6 +316,52 @@ export class TileDispatcher
|
|
|
306
316
|
});
|
|
307
317
|
}
|
|
308
318
|
|
|
319
|
+
/** Whether tile action buttons should be rendered in grid mode */
|
|
320
|
+
private get showGridTileActions(): boolean {
|
|
321
|
+
return (
|
|
322
|
+
this.tileActions.length > 0 &&
|
|
323
|
+
!this.isManageView &&
|
|
324
|
+
this.tileDisplayMode === 'grid'
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Template for the grid-mode action buttons. Rendered alongside the inner
|
|
330
|
+
* tile link inside the dispatcher's shadow root so the action buttons can
|
|
331
|
+
* suppress the hover pane on hover.
|
|
332
|
+
*/
|
|
333
|
+
private get gridTileActionsTemplate() {
|
|
334
|
+
if (!this.showGridTileActions) return nothing;
|
|
335
|
+
|
|
336
|
+
return html`
|
|
337
|
+
<div
|
|
338
|
+
class="tile-actions grid-tile-actions"
|
|
339
|
+
@mouseenter=${this.handleGridActionsMouseEnter}
|
|
340
|
+
@mousemove=${(e: Event) => e.stopPropagation()}
|
|
341
|
+
>
|
|
342
|
+
${this.tileActions.map(
|
|
343
|
+
action => html`
|
|
344
|
+
<button
|
|
345
|
+
class="tile-action-btn"
|
|
346
|
+
@click=${(e: Event) => this.handleTileActionClick(e, action)}
|
|
347
|
+
>
|
|
348
|
+
${action.label}
|
|
349
|
+
</button>
|
|
350
|
+
`,
|
|
351
|
+
)}
|
|
352
|
+
</div>
|
|
353
|
+
`;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* When the mouse enters the grid-mode tile actions area, dispatch a
|
|
358
|
+
* synthetic mouseleave on the host to cancel the hover pane's show timer
|
|
359
|
+
* and hide any visible pane.
|
|
360
|
+
*/
|
|
361
|
+
private handleGridActionsMouseEnter = (): void => {
|
|
362
|
+
this.dispatchEvent(new MouseEvent('mouseleave', { bubbles: false }));
|
|
363
|
+
};
|
|
364
|
+
|
|
309
365
|
private get tile() {
|
|
310
366
|
const {
|
|
311
367
|
model,
|
|
@@ -402,6 +458,7 @@ export class TileDispatcher
|
|
|
402
458
|
.baseImageUrl=${this.baseImageUrl}
|
|
403
459
|
.loggedIn=${this.loggedIn}
|
|
404
460
|
.suppressBlurring=${this.suppressBlurring}
|
|
461
|
+
.tileActions=${this.isManageView ? [] : this.tileActions}
|
|
405
462
|
?useLocalTime=${this.useLocalTime}
|
|
406
463
|
>
|
|
407
464
|
</tile-list-compact>`;
|
|
@@ -420,6 +477,7 @@ export class TileDispatcher
|
|
|
420
477
|
.baseImageUrl=${this.baseImageUrl}
|
|
421
478
|
.loggedIn=${this.loggedIn}
|
|
422
479
|
.suppressBlurring=${this.suppressBlurring}
|
|
480
|
+
.tileActions=${this.isManageView ? [] : this.tileActions}
|
|
423
481
|
?useLocalTime=${this.useLocalTime}
|
|
424
482
|
>
|
|
425
483
|
</tile-list>`;
|
|
@@ -431,6 +489,7 @@ export class TileDispatcher
|
|
|
431
489
|
static get styles() {
|
|
432
490
|
return [
|
|
433
491
|
srOnlyStyle,
|
|
492
|
+
tileActionStyles,
|
|
434
493
|
css`
|
|
435
494
|
:host {
|
|
436
495
|
display: block;
|
|
@@ -466,8 +525,45 @@ export class TileDispatcher
|
|
|
466
525
|
border-radius: 4px;
|
|
467
526
|
}
|
|
468
527
|
|
|
469
|
-
|
|
470
|
-
|
|
528
|
+
/*
|
|
529
|
+
* When tile actions are present, the container takes on the role of
|
|
530
|
+
* the tile's visual card so the tile content and action row appear
|
|
531
|
+
* as a single unified element. The inner tile's own shadow/radius
|
|
532
|
+
* are disabled via CSS variable overrides to avoid visual
|
|
533
|
+
* duplication, and the action row sits as a footer inside the same
|
|
534
|
+
* card.
|
|
535
|
+
*/
|
|
536
|
+
#container.has-tile-actions {
|
|
537
|
+
display: flex;
|
|
538
|
+
flex-direction: column;
|
|
539
|
+
overflow: hidden;
|
|
540
|
+
box-shadow: var(--tileShadow, 1px 1px 2px 0);
|
|
541
|
+
--tileBoxShadow: none;
|
|
542
|
+
--tileCornerRadius: 0;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
#container.has-tile-actions .tile-link {
|
|
546
|
+
flex: 1;
|
|
547
|
+
min-height: 0;
|
|
548
|
+
overflow: hidden;
|
|
549
|
+
border-radius: 0;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* Normal hover shadow lives on the inner anchor for plain tiles */
|
|
553
|
+
#container.hoverable:not(.has-tile-actions) a:focus,
|
|
554
|
+
#container.hoverable:not(.has-tile-actions) a:hover {
|
|
555
|
+
box-shadow: var(
|
|
556
|
+
--tileHoverBoxShadow,
|
|
557
|
+
0 0 6px 2px rgba(8, 8, 32, 0.8)
|
|
558
|
+
);
|
|
559
|
+
transition: box-shadow 0.1s ease;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
/*
|
|
563
|
+
* When the container owns the card visuals, the hover shadow needs
|
|
564
|
+
* to move up to the container so it wraps the action row too.
|
|
565
|
+
*/
|
|
566
|
+
#container.hoverable.has-tile-actions:hover {
|
|
471
567
|
box-shadow: var(
|
|
472
568
|
--tileHoverBoxShadow,
|
|
473
569
|
0 0 6px 2px rgba(8, 8, 32, 0.8)
|
|
@@ -521,6 +617,20 @@ export class TileDispatcher
|
|
|
521
617
|
left: -9999px;
|
|
522
618
|
z-index: 2;
|
|
523
619
|
}
|
|
620
|
+
|
|
621
|
+
/*
|
|
622
|
+
* Grid-mode action row sits flush against the bottom of the card —
|
|
623
|
+
* the buttons' own borders form the visible bottom edge. The outer
|
|
624
|
+
* buttons get rounded bottom corners to match the container so the
|
|
625
|
+
* red border traces cleanly around the card's bottom corners.
|
|
626
|
+
*/
|
|
627
|
+
.grid-tile-actions .tile-action-btn:first-child {
|
|
628
|
+
border-bottom-left-radius: 4px;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
.grid-tile-actions .tile-action-btn:last-child {
|
|
632
|
+
border-bottom-right-radius: 4px;
|
|
633
|
+
}
|
|
524
634
|
`,
|
|
525
635
|
];
|
|
526
636
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Determines the appropriate search filter field name based on date format.
|
|
3
|
+
* Dates in YYYY-MM format (containing a hyphen) use the `date` field;
|
|
4
|
+
* dates in YYYY format use the `year` field.
|
|
5
|
+
*/
|
|
6
|
+
export function dateFilterField(
|
|
7
|
+
minDate?: string,
|
|
8
|
+
maxDate?: string,
|
|
9
|
+
): 'date' | 'year' {
|
|
10
|
+
return minDate?.includes('-') || maxDate?.includes('-') ? 'date' : 'year';
|
|
11
|
+
}
|