astro-accelerator 4.0.10 → 4.0.13
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/README.md +9 -0
- package/package.json +2 -1
- package/public/css/main.css +236 -21
- package/public/css/vars.css +20 -4
- package/public/js/search.js +194 -44
- package/src/config.ts +1 -1
- package/src/layouts/Search.astro +11 -5
- package/src/themes/accelerator/components/Search.astro +99 -0
package/README.md
CHANGED
|
@@ -7,6 +7,15 @@ Review the documentation at [astro.stevefenton.co.uk](https://astro.stevefenton.
|
|
|
7
7
|
[](https://www.npmjs.com/package/astro-accelerator/)
|
|
8
8
|
[](https://www.npmjs.com/package/astro-accelerator/)
|
|
9
9
|
|
|
10
|
+
## Image optimization on Linux
|
|
11
|
+
|
|
12
|
+
Currently, to run the image optimization on Linux, you need to force a compatible version of Sharp to be installed. Any suggestions for a better approach would be appreciated:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm install --include=optional sharp
|
|
16
|
+
pnpm install --force @img/sharp-linux-x64
|
|
17
|
+
```
|
|
18
|
+
|
|
10
19
|
## Publish to NPM
|
|
11
20
|
|
|
12
21
|
Update the `package.json` with the new version number, and commit the change with the message "Release n.n.n", for example, if the new version is `4.0.9` commit with: "Release 4.0.9".
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.
|
|
2
|
+
"version": "4.0.13",
|
|
3
3
|
"author": "Steve Fenton",
|
|
4
4
|
"name": "astro-accelerator",
|
|
5
5
|
"description": "A super-lightweight, accessible, SEO-friendly starter project for Astro",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"hast-util-from-selector": "^3.0.0",
|
|
40
40
|
"html-to-text": "^9.0.5",
|
|
41
41
|
"keyword-extractor": "^0.0.28",
|
|
42
|
+
"optional": "^0.1.4",
|
|
42
43
|
"remark-directive": "^3.0.0",
|
|
43
44
|
"sharp": "^0.33.2"
|
|
44
45
|
},
|
package/public/css/main.css
CHANGED
|
@@ -604,44 +604,259 @@ nav.site-nav h2 {
|
|
|
604
604
|
|
|
605
605
|
/* Site Search */
|
|
606
606
|
|
|
607
|
-
|
|
608
|
-
|
|
607
|
+
.site-search__wrapper {
|
|
608
|
+
position: relative;
|
|
609
|
+
width: 100%;
|
|
610
|
+
max-width: 34.75rem;
|
|
611
|
+
transition: max-width var(--search-dropdown-duration) ease-in-out;
|
|
609
612
|
}
|
|
610
613
|
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
grid-template-columns: fit-content(400px) auto 30px;
|
|
614
|
-
gap: 1em;
|
|
614
|
+
.site-search__wrapper.is-active {
|
|
615
|
+
max-width: 57.8rem;
|
|
615
616
|
}
|
|
616
617
|
|
|
617
|
-
|
|
618
|
-
|
|
618
|
+
.site-search {
|
|
619
|
+
height: var(--search-height);
|
|
620
|
+
border-radius: var(--search-border-radius);
|
|
621
|
+
border: var(--search-border);
|
|
622
|
+
background-color: var(--white);
|
|
623
|
+
position: relative;
|
|
624
|
+
z-index: 1
|
|
619
625
|
}
|
|
620
626
|
|
|
621
|
-
|
|
622
|
-
|
|
627
|
+
.site-search-results {
|
|
628
|
+
background-color: var(--white);
|
|
629
|
+
position: absolute;
|
|
630
|
+
top: var(--search-height);
|
|
631
|
+
width: 100%;
|
|
632
|
+
padding: 0;
|
|
633
|
+
border-radius: var(--search-border-radius);
|
|
634
|
+
border-radius: 0.9375rem;
|
|
635
|
+
list-style-type: none;
|
|
636
|
+
overflow-y: scroll;
|
|
637
|
+
transition-property: padding, transform, visibility;
|
|
638
|
+
transition-duration: var(--search-dropdown-duration);
|
|
639
|
+
transition-timing-function: ease-in-out;
|
|
640
|
+
visibility: hidden;
|
|
641
|
+
transform: translateY(0) scaleY(0);
|
|
642
|
+
z-index: 1;
|
|
643
|
+
max-height: var(--search-dropdown-height);
|
|
644
|
+
transform-origin: top;
|
|
645
|
+
will-change: transform;
|
|
623
646
|
}
|
|
624
647
|
|
|
625
|
-
|
|
626
|
-
padding
|
|
648
|
+
.site-search.is-active+.site-search-results {
|
|
649
|
+
padding: 1rem 0;
|
|
650
|
+
transform: translateY(1.37rem) scaleY(1);
|
|
651
|
+
visibility: visible;
|
|
627
652
|
}
|
|
628
653
|
|
|
629
|
-
.site-search-results {
|
|
630
|
-
|
|
654
|
+
.site-search-results ul {
|
|
655
|
+
list-style-type: none;
|
|
656
|
+
margin-inline-start: 0;
|
|
631
657
|
}
|
|
632
658
|
|
|
633
|
-
.site-search-results
|
|
659
|
+
.site-search-results ul:not(.post-list) {
|
|
660
|
+
margin: 0;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
.site-search-results .show-more {
|
|
664
|
+
border-radius: 4.0625rem;
|
|
665
|
+
background: #00FFA3;
|
|
666
|
+
padding: 0.5rem 0.75rem;
|
|
634
667
|
display: block;
|
|
635
|
-
|
|
668
|
+
margin: 1rem auto 0;
|
|
669
|
+
cursor: pointer;
|
|
636
670
|
}
|
|
637
671
|
|
|
638
|
-
.site-
|
|
639
|
-
|
|
672
|
+
.site-search__overlay {
|
|
673
|
+
opacity: 0;
|
|
674
|
+
visibility: hidden;
|
|
675
|
+
background: rgba(12, 26, 36, 0.30);
|
|
676
|
+
position: fixed;
|
|
677
|
+
top: 0;
|
|
678
|
+
left: 0;
|
|
679
|
+
right: 0;
|
|
680
|
+
bottom: 0;
|
|
681
|
+
transition: opacity var(--search-dropdown-duration) ease-in-out;
|
|
682
|
+
z-index: 1;
|
|
640
683
|
}
|
|
641
684
|
|
|
642
|
-
.site-
|
|
643
|
-
|
|
644
|
-
|
|
685
|
+
.site-search__wrapper.is-active .site-search__overlay {
|
|
686
|
+
opacity: 1;
|
|
687
|
+
visibility: visible;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.site-search-query {
|
|
691
|
+
width: 100%;
|
|
692
|
+
background: transparent;
|
|
693
|
+
height: 100%;
|
|
694
|
+
padding: 0 1rem;
|
|
695
|
+
width: calc(100% - 2rem);
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.search-results__heading {
|
|
699
|
+
visibility: hidden;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
.site-search.is-active+.site-search-results>.search-results__heading {
|
|
703
|
+
visibility: visible;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
.site-search-results__item {
|
|
707
|
+
background-color: transparent;
|
|
708
|
+
transition-property: background-color, border-color;
|
|
709
|
+
transition-duration: var(--search-dropdown-duration);
|
|
710
|
+
transition-timing-function: ease-in-out;
|
|
711
|
+
border-bottom: 0.0625rem solid;
|
|
712
|
+
border-color: var(--search-item-border-color);
|
|
713
|
+
position: relative;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
.site-search-results__item:hover {
|
|
717
|
+
--hover-color: rgba(13, 128, 216, 0.07);
|
|
718
|
+
background-color: var(--hover-color);
|
|
719
|
+
border-color: var(--hover-color);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
.site-search-results__item::after {
|
|
723
|
+
content: "";
|
|
724
|
+
display: inline-block;
|
|
725
|
+
width: 0.75rem;
|
|
726
|
+
height: 1.25rem;
|
|
727
|
+
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='20' viewBox='0 0 12 20' fill='none'%3E%3Cpath d='M2 18L10 10L2 2' stroke='%230D80D8' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
|
|
728
|
+
background-size: 0.75rem 1.25rem;
|
|
729
|
+
background-repeat: no-repeat;
|
|
730
|
+
position: absolute;
|
|
731
|
+
right: 2rem;
|
|
732
|
+
top: 50%;
|
|
733
|
+
transform: translateY(-50%) translateX(-1rem);
|
|
734
|
+
opacity: 0;
|
|
735
|
+
transition-property: opacity, transform;
|
|
736
|
+
transition-duration: var(--search-dropdown-duration);
|
|
737
|
+
transition-timing-function: ease-in-out;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.site-search-results__item:hover::after {
|
|
741
|
+
opacity: 1;
|
|
742
|
+
transform: translateY(-50%) translateX(0);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
@media (max-width: 930px) {
|
|
746
|
+
.site-search-results__item {
|
|
747
|
+
padding: 1rem;
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
.result-wrapper {
|
|
752
|
+
display: flex;
|
|
753
|
+
padding: 1.5rem 3.6rem 1.75rem;
|
|
754
|
+
text-decoration: none;
|
|
755
|
+
flex-direction: column;
|
|
756
|
+
gap: 0.56rem;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
.result-wrapper:hover {
|
|
760
|
+
background-color: initial;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
@media (max-width: 930px) {
|
|
764
|
+
.result-wrapper {
|
|
765
|
+
padding: 1rem;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.site-search-results__item:hover .result-wrapper {
|
|
770
|
+
color: initial;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.result-wrapper mark {
|
|
774
|
+
color: var(--blue-500);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.result-path {
|
|
778
|
+
color: var(--blue-grey-lighter);
|
|
779
|
+
font-size: var(--font-size-small);
|
|
780
|
+
font-weight: 400;
|
|
781
|
+
display: flex;
|
|
782
|
+
gap: 0.5rem;
|
|
783
|
+
flex-wrap: wrap;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.result-path__segment:last-child {
|
|
787
|
+
color: var(--blue-grey);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.result-title {
|
|
791
|
+
color: var(--blue-midnight);
|
|
792
|
+
font-size: var(--font-size-large);
|
|
793
|
+
font-weight: 700;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.result-description {
|
|
797
|
+
color: var(--blue-grey-dark);
|
|
798
|
+
font-size: var(--font-size-medium);
|
|
799
|
+
font-weight: 400;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.site-search>fieldset {
|
|
803
|
+
height: 100%;
|
|
804
|
+
display: flex;
|
|
805
|
+
align-items: center;
|
|
806
|
+
padding: 0 1rem;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
.site-search__remove-btn {
|
|
810
|
+
margin-left: auto;
|
|
811
|
+
background-color: transparent;
|
|
812
|
+
padding: 0.5rem;
|
|
813
|
+
cursor: pointer;
|
|
814
|
+
visibility: hidden;
|
|
815
|
+
transition: transform var(--search-dropdown-duration) ease-in-out;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
.site-search__remove-btn:hover {
|
|
819
|
+
transform: scale(1.2);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
.site-search.is-active .site-search__remove-btn {
|
|
823
|
+
visibility: visible;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
.site-search__mobile {
|
|
827
|
+
display: none;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
@media (max-width: 930px) {
|
|
831
|
+
.site-header .site-search__wrapper {
|
|
832
|
+
max-width: fit-content;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
.site-header .site-search {
|
|
836
|
+
display: none;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.site-header .site-search__mobile {
|
|
840
|
+
--search-mobile-size: 3rem;
|
|
841
|
+
display: flex;
|
|
842
|
+
width: var(--search-mobile-size);
|
|
843
|
+
height: var(--search-mobile-size);
|
|
844
|
+
border-radius: calc(var(--search-mobile-size) / 2);
|
|
845
|
+
justify-content: center;
|
|
846
|
+
align-items: center;
|
|
847
|
+
border: var(--search-border);
|
|
848
|
+
}
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
.site-search .show-more {
|
|
852
|
+
display: inline-block;
|
|
853
|
+
font-size: var(--font-size-small);
|
|
854
|
+
border-radius: 100px;
|
|
855
|
+
text-decoration: none;
|
|
856
|
+
text-align: center;
|
|
857
|
+
padding: 0.2em 0.6em 0.3em 0.6em;
|
|
858
|
+
color: var(--color-hint);
|
|
859
|
+
background-color: var(--bg-color-hint);
|
|
645
860
|
}
|
|
646
861
|
|
|
647
862
|
.result-headings li {
|
package/public/css/vars.css
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
--fore-block: #333;
|
|
25
25
|
--aft-block: #F3F5FF;
|
|
26
26
|
--icon-block: #4D71FF;
|
|
27
|
-
|
|
27
|
+
|
|
28
28
|
--fore-table-head: #FDFDFE;
|
|
29
29
|
--aft-table-head: #2F3141;
|
|
30
30
|
--fore-table-row-odd: #333;
|
|
@@ -54,6 +54,16 @@
|
|
|
54
54
|
|
|
55
55
|
/* Calculate the mobile width by removing l/r columns and grid gap */
|
|
56
56
|
--content-width-mobile: calc(100vw - (1rem * 2));
|
|
57
|
+
|
|
58
|
+
/* Search variables */
|
|
59
|
+
--white: #fff;
|
|
60
|
+
--search-height: 3rem;
|
|
61
|
+
--search-border-radius: calc(var(--search-height)/2);
|
|
62
|
+
--search-results-padding: 1rem;
|
|
63
|
+
--search-border: 0.0625rem solid #76A1C2;
|
|
64
|
+
--search-dropdown-height: 65vh;
|
|
65
|
+
--search-dropdown-duration: 0.3s;
|
|
66
|
+
--search-item-border-color: #DAE2E9;
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
@media (prefers-color-scheme: dark) {
|
|
@@ -61,11 +71,11 @@
|
|
|
61
71
|
--fore: #CCC;
|
|
62
72
|
--fore-headings: #CCE;
|
|
63
73
|
--aft: #333;
|
|
64
|
-
|
|
74
|
+
|
|
65
75
|
--fore-link: #abb9ef;
|
|
66
76
|
--fore-link-alt: #abb9ef;
|
|
67
77
|
--aft-link-alt: #232323;
|
|
68
|
-
|
|
78
|
+
|
|
69
79
|
--fore-head: #CCC;
|
|
70
80
|
--aft-head: #222;
|
|
71
81
|
|
|
@@ -80,10 +90,16 @@
|
|
|
80
90
|
--icon-block: #abb9ef;
|
|
81
91
|
|
|
82
92
|
--fore-table-head: #CCC;
|
|
83
|
-
--aft-table-head: #222;
|
|
93
|
+
--aft-table-head: #222;
|
|
84
94
|
--fore-table-row-odd: #CCC;
|
|
85
95
|
--aft-table-row-odd: #333;
|
|
86
96
|
--fore-table-row-even: #CCC;
|
|
87
97
|
--aft-table-row-even: #444;
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
/* Search variables */
|
|
101
|
+
--white: var(--aft);
|
|
102
|
+
--search-border: 0.0625rem solid var(--link-alt-head);
|
|
103
|
+
--search-item-border-color: var(--link-head);
|
|
88
104
|
}
|
|
89
105
|
}
|
package/public/js/search.js
CHANGED
|
@@ -57,10 +57,16 @@ function enabled(settings, option) {
|
|
|
57
57
|
} Synonyms
|
|
58
58
|
*/
|
|
59
59
|
|
|
60
|
+
const siteSearchInput = qs('[data-site-search-query]');
|
|
61
|
+
const siteSearchWrapper = qs('[data-site-search-wrapper]');
|
|
62
|
+
const siteSearchElement = qs('[data-site-search]');
|
|
63
|
+
const siteSearchResults = qs('[data-site-search-results');
|
|
64
|
+
const removeSearchButton = qs('[data-site-search-remove]');
|
|
65
|
+
|
|
60
66
|
/** @type {SearchEntry[]} */
|
|
61
67
|
var haystack = [];
|
|
62
68
|
var currentQuery = '';
|
|
63
|
-
var dataUrl =
|
|
69
|
+
var dataUrl = siteSearchElement.dataset.sourcedata;
|
|
64
70
|
|
|
65
71
|
var scoring = {
|
|
66
72
|
depth: 5,
|
|
@@ -77,6 +83,106 @@ var scoring = {
|
|
|
77
83
|
var ready = false;
|
|
78
84
|
var scrolled = false;
|
|
79
85
|
|
|
86
|
+
siteSearchInput.addEventListener('focus', () => activateInput());
|
|
87
|
+
|
|
88
|
+
// Close the dropdown upon clicking outside the search
|
|
89
|
+
document.addEventListener('click', function (e) {
|
|
90
|
+
if (!siteSearchElement.contains(e.target) && !siteSearchResults.contains(e.target)) {
|
|
91
|
+
closeDropdown();
|
|
92
|
+
|
|
93
|
+
const duration = getComputedStyle(siteSearchWrapper).getPropertyValue('--search-dropdown-duration');
|
|
94
|
+
|
|
95
|
+
// Convert duration to milliseconds for setTimeout
|
|
96
|
+
const durationMs = parseFloat(duration) * (duration.endsWith('ms') ? 1 : 1000);
|
|
97
|
+
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
deactivateInput();
|
|
100
|
+
}, durationMs);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// Reopen the dropdown upon clicking the input after it has been closed
|
|
105
|
+
siteSearchInput.addEventListener('click', () => {
|
|
106
|
+
if (siteSearchInput.value.trim() !== '') {
|
|
107
|
+
activateInput();
|
|
108
|
+
openDropdown();
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
// Clear the search input
|
|
113
|
+
removeSearchButton.addEventListener('click', () => clearInput());
|
|
114
|
+
|
|
115
|
+
// Dropdown accessibility controls
|
|
116
|
+
document.addEventListener('keydown', function (e) {
|
|
117
|
+
if (e.key === 'Escape' && siteSearchWrapper.classList.contains('is-active')) {
|
|
118
|
+
closeDropdown();
|
|
119
|
+
deactivateInput();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Only proceed if search is active
|
|
123
|
+
if (!siteSearchWrapper.classList.contains('is-active')) return;
|
|
124
|
+
|
|
125
|
+
const firstElement = siteSearchInput;
|
|
126
|
+
const lastElement = siteSearchResults.querySelector('button');
|
|
127
|
+
|
|
128
|
+
if (e.key === 'Tab') {
|
|
129
|
+
if (e.shiftKey && document.activeElement === firstElement) {
|
|
130
|
+
// If shift+tab is pressed on the first focusable element, move to the last
|
|
131
|
+
e.preventDefault();
|
|
132
|
+
if (lastElement) lastElement.focus();
|
|
133
|
+
} else if (!e.shiftKey && document.activeElement === lastElement) {
|
|
134
|
+
// If tab is pressed on the last focusable element, move to the first
|
|
135
|
+
e.preventDefault();
|
|
136
|
+
firstElement.focus();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
function activateInput() {
|
|
142
|
+
siteSearchWrapper.classList.add('is-active');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function deactivateInput() {
|
|
146
|
+
siteSearchWrapper.classList.remove('is-active');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function openDropdown() {
|
|
150
|
+
siteSearchElement.classList.add('is-active');
|
|
151
|
+
|
|
152
|
+
requestAnimationFrame(() => {
|
|
153
|
+
const dropdownHeightPercentage = parseFloat(getComputedStyle(siteSearchWrapper).getPropertyValue('--search-dropdown-height'));
|
|
154
|
+
// Convert vh to pixels
|
|
155
|
+
const dropdownHeight = window.innerHeight * (dropdownHeightPercentage / 100) + 32;
|
|
156
|
+
const siteSearchElementRect = siteSearchElement.getBoundingClientRect();
|
|
157
|
+
const offsetFromBottomToElement = window.innerHeight - siteSearchElementRect.bottom;
|
|
158
|
+
|
|
159
|
+
if (offsetFromBottomToElement < dropdownHeight) {
|
|
160
|
+
// Scroll to the siteSearchElement
|
|
161
|
+
siteSearchElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
162
|
+
|
|
163
|
+
// Delay the overflow to allow for smooth scrolling
|
|
164
|
+
setTimeout(() => {
|
|
165
|
+
document.body.style.overflow = 'hidden';
|
|
166
|
+
}, 300);
|
|
167
|
+
} else {
|
|
168
|
+
// If dropdown is fully visible, no need to adjust scroll but prevent further scrolling
|
|
169
|
+
document.body.style.overflow = 'hidden';
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function closeDropdown() {
|
|
175
|
+
siteSearchElement.classList.remove('is-active');
|
|
176
|
+
document.body.style.overflow = '';
|
|
177
|
+
siteSearchInput.blur();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function clearInput() {
|
|
181
|
+
closeDropdown();
|
|
182
|
+
siteSearchInput.value = '';
|
|
183
|
+
siteSearchInput.focus();
|
|
184
|
+
}
|
|
185
|
+
|
|
80
186
|
/** @type{Synonyms | null} */
|
|
81
187
|
var _synonyms = null;
|
|
82
188
|
|
|
@@ -91,7 +197,7 @@ async function getSynonyms() {
|
|
|
91
197
|
|
|
92
198
|
try {
|
|
93
199
|
const synonymsModule = await import('./synonyms.js');
|
|
94
|
-
_synonyms =synonymsModule.synonyms;
|
|
200
|
+
_synonyms = synonymsModule.synonyms;
|
|
95
201
|
} catch {
|
|
96
202
|
_synonyms = {};
|
|
97
203
|
}
|
|
@@ -105,7 +211,7 @@ async function getSynonyms() {
|
|
|
105
211
|
*/
|
|
106
212
|
async function replaceSynonyms(queryTerms) {
|
|
107
213
|
const synonyms = await getSynonyms();
|
|
108
|
-
|
|
214
|
+
|
|
109
215
|
for (let i = 0; i < queryTerms.length; i++) {
|
|
110
216
|
const term = queryTerms[i];
|
|
111
217
|
if (synonyms[term] != null) {
|
|
@@ -125,8 +231,17 @@ async function replaceSynonyms(queryTerms) {
|
|
|
125
231
|
async function search(s, r) {
|
|
126
232
|
const numberOfResults = r ?? 12;
|
|
127
233
|
|
|
234
|
+
// Add 'is-active' class when search is performed
|
|
235
|
+
if (s && s.trim().length > 0) {
|
|
236
|
+
activateInput();
|
|
237
|
+
openDropdown();
|
|
238
|
+
} else {
|
|
239
|
+
// Remove 'is-active' class when search is cleared
|
|
240
|
+
closeDropdown();
|
|
241
|
+
}
|
|
242
|
+
|
|
128
243
|
/** @type {SearchEntry[]} */
|
|
129
|
-
const needles =
|
|
244
|
+
const needles = [];
|
|
130
245
|
|
|
131
246
|
// Clean the input
|
|
132
247
|
const cleanQuery = sanitise(s);
|
|
@@ -149,7 +264,7 @@ async function search(s, r) {
|
|
|
149
264
|
|
|
150
265
|
const allTerms = queryTerms.concat(stemmedTerms);
|
|
151
266
|
|
|
152
|
-
cleanQuery.length > 0 && haystack.forEach(
|
|
267
|
+
cleanQuery.length > 0 && haystack.forEach((item) => {
|
|
153
268
|
|
|
154
269
|
item.foundWords = 0;
|
|
155
270
|
item.score = 0;
|
|
@@ -163,7 +278,7 @@ async function search(s, r) {
|
|
|
163
278
|
if (item.safeTitle === currentQuery) {
|
|
164
279
|
item.foundWords += 2;
|
|
165
280
|
}
|
|
166
|
-
|
|
281
|
+
|
|
167
282
|
if (contains(item.safeTitle, currentQuery)) {
|
|
168
283
|
item.score = item.score + scoring.phraseTitle;
|
|
169
284
|
item.foundWords += 2;
|
|
@@ -187,7 +302,7 @@ async function search(s, r) {
|
|
|
187
302
|
// Part 2 - Term Matches, i.e. "Kitchen" or "Sink"
|
|
188
303
|
|
|
189
304
|
let foundWords = 0;
|
|
190
|
-
|
|
305
|
+
|
|
191
306
|
allTerms.forEach(term => {
|
|
192
307
|
let isTermFound = false;
|
|
193
308
|
|
|
@@ -255,7 +370,7 @@ async function search(s, r) {
|
|
|
255
370
|
}
|
|
256
371
|
});
|
|
257
372
|
|
|
258
|
-
needles.sort(function (a, b){
|
|
373
|
+
needles.sort(function (a, b) {
|
|
259
374
|
if (b.foundWords === a.foundWords) {
|
|
260
375
|
return b.score - a.score;
|
|
261
376
|
}
|
|
@@ -265,12 +380,12 @@ async function search(s, r) {
|
|
|
265
380
|
|
|
266
381
|
const total = needles.reduce(function (accumulator, needle) {
|
|
267
382
|
return accumulator + needle.score;
|
|
268
|
-
|
|
383
|
+
}, 0);
|
|
269
384
|
|
|
270
|
-
const results =
|
|
385
|
+
const results = siteSearchResults;
|
|
271
386
|
|
|
272
|
-
const
|
|
273
|
-
|
|
387
|
+
const ul = document.createElement('ul');
|
|
388
|
+
ul.className = 'site-search-results__list';
|
|
274
389
|
|
|
275
390
|
const limit = Math.min(needles.length, numberOfResults);
|
|
276
391
|
|
|
@@ -282,28 +397,59 @@ async function search(s, r) {
|
|
|
282
397
|
|
|
283
398
|
const address = new URL(needle.url);
|
|
284
399
|
const isSameHost = siteUrl.host == address.host;
|
|
285
|
-
const url =
|
|
400
|
+
const url = isSameHost ? address.pathname : needle.url;
|
|
401
|
+
|
|
402
|
+
const listElementWrapper = document.createElement('a');
|
|
403
|
+
listElementWrapper.href = url;
|
|
404
|
+
listElementWrapper.className = 'result-wrapper';
|
|
286
405
|
|
|
287
|
-
const
|
|
406
|
+
const listElementTitle = document.createElement('span');
|
|
288
407
|
// Only highlight user query terms, not stemmed terms
|
|
289
|
-
|
|
290
|
-
|
|
408
|
+
listElementTitle.innerHTML = highlight(needle.title, queryTerms);
|
|
409
|
+
listElementTitle.className = 'result-title';
|
|
291
410
|
|
|
292
411
|
const path = document.createElement('div');
|
|
293
412
|
path.className = 'result-path';
|
|
294
|
-
path.innerHTML = address.pathname;
|
|
295
413
|
|
|
296
|
-
|
|
297
|
-
|
|
414
|
+
// Split the path into segments, filter out empty segments (in case of leading slash)
|
|
415
|
+
const segments = address.pathname.split('/').filter(Boolean);
|
|
416
|
+
|
|
417
|
+
segments.forEach((segment, index) => {
|
|
418
|
+
const words = segment.replace(/-/g, ' ').split(' ');
|
|
419
|
+
const processedSegment = words.map((word, index) =>
|
|
420
|
+
index === 0 ? word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() : word.toLowerCase()
|
|
421
|
+
).join(' ');
|
|
422
|
+
|
|
423
|
+
const segmentSpan = document.createElement('span');
|
|
424
|
+
segmentSpan.className = 'result-path__segment';
|
|
425
|
+
segmentSpan.textContent = processedSegment;
|
|
426
|
+
path.appendChild(segmentSpan);
|
|
427
|
+
|
|
428
|
+
if (index < segments.length - 1) {
|
|
429
|
+
const svgIcon = document.createElement('span');
|
|
430
|
+
svgIcon.className = 'result-path__icon';
|
|
431
|
+
svgIcon.innerHTML = `
|
|
432
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="10" viewBox="0 0 6 10" fill="none">
|
|
433
|
+
<path d="M1 9L5 5L1 1" stroke="#7C98B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
434
|
+
</svg>
|
|
435
|
+
`;
|
|
436
|
+
path.appendChild(svgIcon);
|
|
437
|
+
}
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
const listElementDescription = document.createElement('p');
|
|
441
|
+
listElementDescription.className = 'result-description';
|
|
298
442
|
// Only highlight user query terms, not stemmed terms
|
|
299
|
-
|
|
443
|
+
listElementDescription.innerHTML = highlight(needle.description, queryTerms);
|
|
300
444
|
|
|
301
445
|
const li = document.createElement('li');
|
|
446
|
+
li.classList.add('site-search-results__item');
|
|
302
447
|
li.dataset.words = needle.foundWords.toString();
|
|
303
|
-
li.dataset.score = (Math.round((needle.score/ total) * 1000) / 1000).toString();
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
448
|
+
li.dataset.score = (Math.round((needle.score / total) * 1000) / 1000).toString();
|
|
449
|
+
listElementWrapper.appendChild(path);
|
|
450
|
+
listElementWrapper.appendChild(listElementTitle);
|
|
451
|
+
listElementWrapper.appendChild(listElementDescription);
|
|
452
|
+
li.appendChild(listElementWrapper);
|
|
307
453
|
|
|
308
454
|
if (enabled(f.search, 'headings') && needle.matchedHeadings.length > 0) {
|
|
309
455
|
const headings = document.createElement('ul');
|
|
@@ -325,28 +471,30 @@ async function search(s, r) {
|
|
|
325
471
|
li.appendChild(headings);
|
|
326
472
|
}
|
|
327
473
|
|
|
328
|
-
|
|
474
|
+
ul.appendChild(li);
|
|
329
475
|
}
|
|
330
476
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
477
|
+
let h2;
|
|
478
|
+
if (needles.length === 0) {
|
|
479
|
+
h2 = document.createElement('h2');
|
|
480
|
+
h2.classList.add('search-results__heading');
|
|
481
|
+
h2.innerHTML = results.dataset.emptytitle || 'No Results';
|
|
482
|
+
}
|
|
335
483
|
|
|
336
484
|
const more = document.createElement('button');
|
|
337
485
|
more.className = 'show-more';
|
|
338
486
|
more.type = 'button';
|
|
339
487
|
more.innerHTML = 'See more';
|
|
340
|
-
more.addEventListener('click', function() {
|
|
488
|
+
more.addEventListener('click', function (e) {
|
|
489
|
+
e.stopPropagation(); // Prevent the click from closing the dropdown
|
|
341
490
|
currentQuery = '';
|
|
342
491
|
const newTotal = numberOfResults + 12;
|
|
343
|
-
|
|
344
492
|
search(s, newTotal);
|
|
345
|
-
})
|
|
493
|
+
});
|
|
346
494
|
|
|
347
495
|
results.innerHTML = '';
|
|
348
|
-
results.appendChild(
|
|
349
|
-
results.appendChild(
|
|
496
|
+
results.appendChild(ul);
|
|
497
|
+
h2 && results.appendChild(h2);
|
|
350
498
|
|
|
351
499
|
if (needles.length > numberOfResults) {
|
|
352
500
|
results.appendChild(more);
|
|
@@ -361,10 +509,12 @@ async function search(s, r) {
|
|
|
361
509
|
var debounceTimer;
|
|
362
510
|
|
|
363
511
|
function debounceSearch() {
|
|
364
|
-
var input =
|
|
512
|
+
var input = siteSearchInput;
|
|
513
|
+
|
|
514
|
+
document.body.style.overflow = 'hidden'; // Prevent scrolling when active
|
|
365
515
|
|
|
366
516
|
if (input == null) {
|
|
367
|
-
throw new Error('Cannot find
|
|
517
|
+
throw new Error('Cannot find data-site-search-query');
|
|
368
518
|
}
|
|
369
519
|
|
|
370
520
|
// Words chained with . are combined, i.e. System.Text is "systemtext"
|
|
@@ -379,10 +529,10 @@ function debounceSearch() {
|
|
|
379
529
|
}
|
|
380
530
|
|
|
381
531
|
fetch(dataUrl)
|
|
382
|
-
.then(function (response) {
|
|
532
|
+
.then(function (response) {
|
|
383
533
|
return response.json();
|
|
384
534
|
})
|
|
385
|
-
.then(function (data) {
|
|
535
|
+
.then(function (data) {
|
|
386
536
|
haystack = data;
|
|
387
537
|
ready = true;
|
|
388
538
|
|
|
@@ -397,21 +547,21 @@ fetch(dataUrl)
|
|
|
397
547
|
}
|
|
398
548
|
|
|
399
549
|
/** @type {HTMLFormElement} */
|
|
400
|
-
const siteSearch =
|
|
550
|
+
const siteSearch = siteSearchElement;
|
|
401
551
|
|
|
402
552
|
/** @type {HTMLInputElement} */
|
|
403
|
-
const siteSearchQuery =
|
|
553
|
+
const siteSearchQuery = siteSearchInput;
|
|
404
554
|
|
|
405
555
|
if (siteSearch == null || siteSearchQuery == null) {
|
|
406
|
-
throw new Error('Cannot find #site-search or
|
|
556
|
+
throw new Error('Cannot find #site-search or data-site-search-query');
|
|
407
557
|
}
|
|
408
|
-
|
|
558
|
+
|
|
409
559
|
siteSearch.addEventListener('submit', function (e) {
|
|
410
560
|
e.preventDefault();
|
|
411
561
|
debounceSearch();
|
|
412
562
|
return false;
|
|
413
563
|
});
|
|
414
|
-
|
|
564
|
+
|
|
415
565
|
siteSearchQuery.addEventListener('keyup', function (e) {
|
|
416
566
|
e.preventDefault();
|
|
417
567
|
if (!scrolled) {
|
|
@@ -429,7 +579,7 @@ fetch(dataUrl)
|
|
|
429
579
|
|
|
430
580
|
for (let key of Object.keys(scoring)) {
|
|
431
581
|
if (params.has(`s_${key}`)) {
|
|
432
|
-
scoring[key] = parseInt(params.get(`s_${key}`) ?? scoring[key].toString(), 10)
|
|
582
|
+
scoring[key] = parseInt(params.get(`s_${key}`) ?? scoring[key].toString(), 10);
|
|
433
583
|
}
|
|
434
584
|
}
|
|
435
585
|
|
package/src/config.ts
CHANGED
package/src/layouts/Search.astro
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
// warning: This file is overwritten by Astro Accelerator
|
|
3
|
-
|
|
4
2
|
import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
|
|
5
|
-
import
|
|
3
|
+
import { SITE } from '@config';
|
|
4
|
+
import { Lang } from '@util/Languages';
|
|
5
|
+
import Default from './Default.astro';
|
|
6
|
+
import Search from '../themes/accelerator/components/Search.astro';
|
|
6
7
|
|
|
7
8
|
// Properties
|
|
8
9
|
type Props = {
|
|
@@ -10,7 +11,12 @@ type Props = {
|
|
|
10
11
|
headings: { depth: number; slug: string; text: string; }[];
|
|
11
12
|
}
|
|
12
13
|
const { frontmatter, headings } = Astro.props satisfies Props;
|
|
14
|
+
const lang = frontmatter.lang ?? SITE.default.lang;
|
|
15
|
+
|
|
16
|
+
// Language
|
|
17
|
+
const _ = Lang(lang);
|
|
13
18
|
---
|
|
14
|
-
<
|
|
19
|
+
<Default frontmatter={ frontmatter } headings={ headings }>
|
|
15
20
|
<slot />
|
|
16
|
-
|
|
21
|
+
<Search lang={ lang }/>
|
|
22
|
+
</Default>
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { Accelerator, PostFiltering } from "astro-accelerator-utils";
|
|
3
|
+
import { Translations, Lang } from "@util/Languages";
|
|
4
|
+
import { SITE } from "@config";
|
|
5
|
+
|
|
6
|
+
// Properties
|
|
7
|
+
type Props = {
|
|
8
|
+
lang: string;
|
|
9
|
+
};
|
|
10
|
+
const { lang } = Astro.props satisfies Props;
|
|
11
|
+
|
|
12
|
+
// Language
|
|
13
|
+
const _ = Lang(lang);
|
|
14
|
+
|
|
15
|
+
// Logic
|
|
16
|
+
const siteUrl = Astro.site ? Astro.site.href : "";
|
|
17
|
+
const accelerator = new Accelerator(SITE);
|
|
18
|
+
const search =
|
|
19
|
+
accelerator.posts.all().filter(PostFiltering.isSearch).shift() ?? null;
|
|
20
|
+
const searchUrl =
|
|
21
|
+
(search && accelerator.urlFormatter.formatAddress(search.url)) ||
|
|
22
|
+
SITE.search.fallbackUrl;
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
<div class="site-search__wrapper" data-site-search-wrapper>
|
|
26
|
+
<div class="site-search__overlay"></div>
|
|
27
|
+
<form
|
|
28
|
+
method="GET"
|
|
29
|
+
action={SITE.search.fallbackUrl ?? "https://www.google.com/search"}
|
|
30
|
+
role="search"
|
|
31
|
+
class="site-search"
|
|
32
|
+
autocomplete="off"
|
|
33
|
+
data-sourcedata={SITE.subfolder + "/search.json"}
|
|
34
|
+
data-site-search
|
|
35
|
+
>
|
|
36
|
+
<fieldset>
|
|
37
|
+
<input
|
|
38
|
+
type="hidden"
|
|
39
|
+
name={SITE.search.fallbackSite ?? "q"}
|
|
40
|
+
value={"site:" + siteUrl}
|
|
41
|
+
/>
|
|
42
|
+
<svg
|
|
43
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
44
|
+
width="20"
|
|
45
|
+
height="19"
|
|
46
|
+
viewBox="0 0 20 19"
|
|
47
|
+
fill="none"
|
|
48
|
+
>
|
|
49
|
+
<path
|
|
50
|
+
d="M19.0524 16.4267L15.3727 12.7273C15.2067 12.5603 14.9815 12.4675 14.7453 12.4675H14.1437C15.1624 11.1577 15.7676 9.5102 15.7676 7.718C15.7676 3.45455 12.3316 0 8.09097 0C3.85035 0 0.414307 3.45455 0.414307 7.718C0.414307 11.9814 3.85035 15.436 8.09097 15.436C9.87358 15.436 11.5123 14.8275 12.8151 13.8033V14.4082C12.8151 14.6456 12.9073 14.872 13.0734 15.039L16.7531 18.7384C17.1 19.0872 17.661 19.0872 18.0042 18.7384L19.0487 17.6883C19.3956 17.3395 19.3956 16.7755 19.0524 16.4267ZM8.09097 12.4675C5.48164 12.4675 3.36687 10.3451 3.36687 7.718C3.36687 5.09462 5.47795 2.96846 8.09097 2.96846C10.7003 2.96846 12.8151 5.09091 12.8151 7.718C12.8151 10.3414 10.704 12.4675 8.09097 12.4675Z"
|
|
51
|
+
fill="#274B66"></path>
|
|
52
|
+
</svg>
|
|
53
|
+
<input
|
|
54
|
+
type="text"
|
|
55
|
+
name={SITE.search.fallbackSite ?? "q"}
|
|
56
|
+
class="site-search-query"
|
|
57
|
+
placeholder={_(Translations.search.search_for)}
|
|
58
|
+
spellcheck="true"
|
|
59
|
+
autocomplete="off"
|
|
60
|
+
data-site-search-query
|
|
61
|
+
/>
|
|
62
|
+
<button class="site-search__remove-btn" data-site-search-remove>
|
|
63
|
+
<svg
|
|
64
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
65
|
+
width="11"
|
|
66
|
+
height="11"
|
|
67
|
+
viewBox="0 0 11 11"
|
|
68
|
+
fill="none"
|
|
69
|
+
>
|
|
70
|
+
<path
|
|
71
|
+
d="M7.585 5.5L10.7122 2.37281C11.0959 1.98906 11.0959 1.36687 10.7122 0.982812L10.0172 0.287813C9.63344 -0.0959375 9.01125 -0.0959375 8.62719 0.287813L5.5 3.415L2.37281 0.287813C1.98906 -0.0959375 1.36688 -0.0959375 0.982813 0.287813L0.287813 0.982812C-0.0959375 1.36656 -0.0959375 1.98875 0.287813 2.37281L3.415 5.5L0.287813 8.62719C-0.0959375 9.01094 -0.0959375 9.63312 0.287813 10.0172L0.982813 10.7122C1.36656 11.0959 1.98906 11.0959 2.37281 10.7122L5.5 7.585L8.62719 10.7122C9.01094 11.0959 9.63344 11.0959 10.0172 10.7122L10.7122 10.0172C11.0959 9.63344 11.0959 9.01125 10.7122 8.62719L7.585 5.5Z"
|
|
72
|
+
fill="#355670"></path>
|
|
73
|
+
</svg>
|
|
74
|
+
</button>
|
|
75
|
+
</fieldset>
|
|
76
|
+
</form>
|
|
77
|
+
<div
|
|
78
|
+
class="site-search-results"
|
|
79
|
+
data-title={_(Translations.search.results_title)}
|
|
80
|
+
data-emptytitle={_(Translations.search.no_results_title)}
|
|
81
|
+
data-site-search-results
|
|
82
|
+
>
|
|
83
|
+
</div>
|
|
84
|
+
<a href={searchUrl} class="site-search__mobile">
|
|
85
|
+
<svg
|
|
86
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
87
|
+
width="20"
|
|
88
|
+
height="19"
|
|
89
|
+
viewBox="0 0 20 19"
|
|
90
|
+
fill="none"
|
|
91
|
+
>
|
|
92
|
+
<path
|
|
93
|
+
d="M19.0524 16.4267L15.3727 12.7273C15.2067 12.5603 14.9815 12.4675 14.7453 12.4675H14.1437C15.1624 11.1577 15.7676 9.5102 15.7676 7.718C15.7676 3.45455 12.3316 0 8.09097 0C3.85035 0 0.414307 3.45455 0.414307 7.718C0.414307 11.9814 3.85035 15.436 8.09097 15.436C9.87358 15.436 11.5123 14.8275 12.8151 13.8033V14.4082C12.8151 14.6456 12.9073 14.872 13.0734 15.039L16.7531 18.7384C17.1 19.0872 17.661 19.0872 18.0042 18.7384L19.0487 17.6883C19.3956 17.3395 19.3956 16.7755 19.0524 16.4267ZM8.09097 12.4675C5.48164 12.4675 3.36687 10.3451 3.36687 7.718C3.36687 5.09462 5.47795 2.96846 8.09097 2.96846C10.7003 2.96846 12.8151 5.09091 12.8151 7.718C12.8151 10.3414 10.704 12.4675 8.09097 12.4675Z"
|
|
94
|
+
fill="#274B66"></path>
|
|
95
|
+
</svg>
|
|
96
|
+
</a>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<script src={SITE.subfolder + "/js/search.js"} type="module" async></script>
|