astro-accelerator 4.0.9 → 4.0.12
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 +15 -1
- package/package.json +9 -9
- package/public/css/main.css +236 -21
- package/public/css/vars.css +20 -4
- package/public/js/search.js +167 -44
- package/src/config.ts +1 -1
- package/src/layouts/Search.astro +11 -5
- package/src/pages/articles/[page].astro +67 -0
- package/src/pages/authors/[author]/[page].astro +120 -0
- package/src/pages/category/[category]/[page].astro +124 -0
- package/src/pages/category/[category]/index.astro +20 -0
- package/src/pages/tag/[tag]/[page].astro +123 -0
- package/src/themes/accelerator/components/Search.astro +99 -0
package/README.md
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
# Astro Accelerator
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
[](https://github.com/Steve-Fenton/astro-accelerator/actions/workflows/build-astro.yml)
|
|
5
4
|
|
|
6
5
|
Review the documentation at [astro.stevefenton.co.uk](https://astro.stevefenton.co.uk/)
|
|
@@ -8,6 +7,21 @@ Review the documentation at [astro.stevefenton.co.uk](https://astro.stevefenton.
|
|
|
8
7
|
[](https://www.npmjs.com/package/astro-accelerator/)
|
|
9
8
|
[](https://www.npmjs.com/package/astro-accelerator/)
|
|
10
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
|
+
|
|
19
|
+
## Publish to NPM
|
|
20
|
+
|
|
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".
|
|
22
|
+
|
|
23
|
+
The NPM token expires periodically and must be updated in GitHub settings -> Secrets -> Actions.
|
|
24
|
+
|
|
11
25
|
## Upgrades
|
|
12
26
|
|
|
13
27
|
- [Upgrading from v3 to v4 of Astro and Astro Accelerator.](https://www.stevefenton.co.uk/blog/2023/12/upgrade-astro-v4/)
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.0.
|
|
2
|
+
"version": "4.0.12",
|
|
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
|
},
|
|
@@ -55,14 +56,13 @@
|
|
|
55
56
|
"src/config.ts",
|
|
56
57
|
"src/pages/index.md",
|
|
57
58
|
"src/pages/search.md",
|
|
58
|
-
"src/pages/
|
|
59
|
-
"src/pages/articles
|
|
60
|
-
"src/pages/
|
|
61
|
-
"src/pages/
|
|
62
|
-
"src/pages/category
|
|
63
|
-
"src/pages/
|
|
64
|
-
"src/pages/tag
|
|
65
|
-
"src/pages/tag/[[]tag[]]/index.astro",
|
|
59
|
+
"src/pages/articles/*.astro",
|
|
60
|
+
"src/pages/articles/*.ts",
|
|
61
|
+
"src/pages/authors/**/*.astro",
|
|
62
|
+
"src/pages/category/**/*.astro",
|
|
63
|
+
"src/pages/category/**/*.astro",
|
|
64
|
+
"src/pages/tag/**/*.astro",
|
|
65
|
+
"src/pages/tag/**/*.astro",
|
|
66
66
|
"src/pages/search.json.ts",
|
|
67
67
|
"src/pages/sitemap.xml.ts",
|
|
68
68
|
"src/pages/report/*",
|
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,79 @@ 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
|
+
function activateInput() {
|
|
116
|
+
siteSearchWrapper.classList.add('is-active');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function deactivateInput() {
|
|
120
|
+
siteSearchWrapper.classList.remove('is-active');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function openDropdown() {
|
|
124
|
+
siteSearchElement.classList.add('is-active');
|
|
125
|
+
|
|
126
|
+
requestAnimationFrame(() => {
|
|
127
|
+
const dropdownHeightPercentage = parseFloat(getComputedStyle(siteSearchWrapper).getPropertyValue('--search-dropdown-height'));
|
|
128
|
+
// Convert vh to pixels
|
|
129
|
+
const dropdownHeight = window.innerHeight * (dropdownHeightPercentage / 100) + 32;
|
|
130
|
+
const siteSearchElementRect = siteSearchElement.getBoundingClientRect();
|
|
131
|
+
const offsetFromBottomToElement = window.innerHeight - siteSearchElementRect.bottom;
|
|
132
|
+
|
|
133
|
+
if (offsetFromBottomToElement < dropdownHeight) {
|
|
134
|
+
// Scroll to the siteSearchElement
|
|
135
|
+
siteSearchElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
136
|
+
|
|
137
|
+
// Delay the overflow to allow for smooth scrolling
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
document.body.style.overflow = 'hidden';
|
|
140
|
+
}, 300);
|
|
141
|
+
} else {
|
|
142
|
+
// If dropdown is fully visible, no need to adjust scroll but prevent further scrolling
|
|
143
|
+
document.body.style.overflow = 'hidden';
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function closeDropdown() {
|
|
149
|
+
siteSearchElement.classList.remove('is-active');
|
|
150
|
+
document.body.style.overflow = '';
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function clearInput() {
|
|
154
|
+
closeDropdown();
|
|
155
|
+
siteSearchInput.value = '';
|
|
156
|
+
siteSearchInput.focus();
|
|
157
|
+
}
|
|
158
|
+
|
|
80
159
|
/** @type{Synonyms | null} */
|
|
81
160
|
var _synonyms = null;
|
|
82
161
|
|
|
@@ -91,7 +170,7 @@ async function getSynonyms() {
|
|
|
91
170
|
|
|
92
171
|
try {
|
|
93
172
|
const synonymsModule = await import('./synonyms.js');
|
|
94
|
-
_synonyms =synonymsModule.synonyms;
|
|
173
|
+
_synonyms = synonymsModule.synonyms;
|
|
95
174
|
} catch {
|
|
96
175
|
_synonyms = {};
|
|
97
176
|
}
|
|
@@ -105,7 +184,7 @@ async function getSynonyms() {
|
|
|
105
184
|
*/
|
|
106
185
|
async function replaceSynonyms(queryTerms) {
|
|
107
186
|
const synonyms = await getSynonyms();
|
|
108
|
-
|
|
187
|
+
|
|
109
188
|
for (let i = 0; i < queryTerms.length; i++) {
|
|
110
189
|
const term = queryTerms[i];
|
|
111
190
|
if (synonyms[term] != null) {
|
|
@@ -125,8 +204,17 @@ async function replaceSynonyms(queryTerms) {
|
|
|
125
204
|
async function search(s, r) {
|
|
126
205
|
const numberOfResults = r ?? 12;
|
|
127
206
|
|
|
207
|
+
// Add 'is-active' class when search is performed
|
|
208
|
+
if (s && s.trim().length > 0) {
|
|
209
|
+
activateInput();
|
|
210
|
+
openDropdown();
|
|
211
|
+
} else {
|
|
212
|
+
// Remove 'is-active' class when search is cleared
|
|
213
|
+
closeDropdown();
|
|
214
|
+
}
|
|
215
|
+
|
|
128
216
|
/** @type {SearchEntry[]} */
|
|
129
|
-
const needles =
|
|
217
|
+
const needles = [];
|
|
130
218
|
|
|
131
219
|
// Clean the input
|
|
132
220
|
const cleanQuery = sanitise(s);
|
|
@@ -149,7 +237,7 @@ async function search(s, r) {
|
|
|
149
237
|
|
|
150
238
|
const allTerms = queryTerms.concat(stemmedTerms);
|
|
151
239
|
|
|
152
|
-
cleanQuery.length > 0 && haystack.forEach(
|
|
240
|
+
cleanQuery.length > 0 && haystack.forEach((item) => {
|
|
153
241
|
|
|
154
242
|
item.foundWords = 0;
|
|
155
243
|
item.score = 0;
|
|
@@ -163,7 +251,7 @@ async function search(s, r) {
|
|
|
163
251
|
if (item.safeTitle === currentQuery) {
|
|
164
252
|
item.foundWords += 2;
|
|
165
253
|
}
|
|
166
|
-
|
|
254
|
+
|
|
167
255
|
if (contains(item.safeTitle, currentQuery)) {
|
|
168
256
|
item.score = item.score + scoring.phraseTitle;
|
|
169
257
|
item.foundWords += 2;
|
|
@@ -187,7 +275,7 @@ async function search(s, r) {
|
|
|
187
275
|
// Part 2 - Term Matches, i.e. "Kitchen" or "Sink"
|
|
188
276
|
|
|
189
277
|
let foundWords = 0;
|
|
190
|
-
|
|
278
|
+
|
|
191
279
|
allTerms.forEach(term => {
|
|
192
280
|
let isTermFound = false;
|
|
193
281
|
|
|
@@ -255,7 +343,7 @@ async function search(s, r) {
|
|
|
255
343
|
}
|
|
256
344
|
});
|
|
257
345
|
|
|
258
|
-
needles.sort(function (a, b){
|
|
346
|
+
needles.sort(function (a, b) {
|
|
259
347
|
if (b.foundWords === a.foundWords) {
|
|
260
348
|
return b.score - a.score;
|
|
261
349
|
}
|
|
@@ -265,12 +353,12 @@ async function search(s, r) {
|
|
|
265
353
|
|
|
266
354
|
const total = needles.reduce(function (accumulator, needle) {
|
|
267
355
|
return accumulator + needle.score;
|
|
268
|
-
|
|
356
|
+
}, 0);
|
|
269
357
|
|
|
270
|
-
const results =
|
|
358
|
+
const results = siteSearchResults;
|
|
271
359
|
|
|
272
|
-
const
|
|
273
|
-
|
|
360
|
+
const ul = document.createElement('ul');
|
|
361
|
+
ul.className = 'site-search-results__list';
|
|
274
362
|
|
|
275
363
|
const limit = Math.min(needles.length, numberOfResults);
|
|
276
364
|
|
|
@@ -282,28 +370,59 @@ async function search(s, r) {
|
|
|
282
370
|
|
|
283
371
|
const address = new URL(needle.url);
|
|
284
372
|
const isSameHost = siteUrl.host == address.host;
|
|
285
|
-
const url =
|
|
373
|
+
const url = isSameHost ? address.pathname : needle.url;
|
|
374
|
+
|
|
375
|
+
const listElementWrapper = document.createElement('a');
|
|
376
|
+
listElementWrapper.href = url;
|
|
377
|
+
listElementWrapper.className = 'result-wrapper';
|
|
286
378
|
|
|
287
|
-
const
|
|
379
|
+
const listElementTitle = document.createElement('span');
|
|
288
380
|
// Only highlight user query terms, not stemmed terms
|
|
289
|
-
|
|
290
|
-
|
|
381
|
+
listElementTitle.innerHTML = highlight(needle.title, queryTerms);
|
|
382
|
+
listElementTitle.className = 'result-title';
|
|
291
383
|
|
|
292
384
|
const path = document.createElement('div');
|
|
293
385
|
path.className = 'result-path';
|
|
294
|
-
path.innerHTML = address.pathname;
|
|
295
386
|
|
|
296
|
-
|
|
297
|
-
|
|
387
|
+
// Split the path into segments, filter out empty segments (in case of leading slash)
|
|
388
|
+
const segments = address.pathname.split('/').filter(Boolean);
|
|
389
|
+
|
|
390
|
+
segments.forEach((segment, index) => {
|
|
391
|
+
const words = segment.replace(/-/g, ' ').split(' ');
|
|
392
|
+
const processedSegment = words.map((word, index) =>
|
|
393
|
+
index === 0 ? word.charAt(0).toUpperCase() + word.slice(1).toLowerCase() : word.toLowerCase()
|
|
394
|
+
).join(' ');
|
|
395
|
+
|
|
396
|
+
const segmentSpan = document.createElement('span');
|
|
397
|
+
segmentSpan.className = 'result-path__segment';
|
|
398
|
+
segmentSpan.textContent = processedSegment;
|
|
399
|
+
path.appendChild(segmentSpan);
|
|
400
|
+
|
|
401
|
+
if (index < segments.length - 1) {
|
|
402
|
+
const svgIcon = document.createElement('span');
|
|
403
|
+
svgIcon.className = 'result-path__icon';
|
|
404
|
+
svgIcon.innerHTML = `
|
|
405
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="6" height="10" viewBox="0 0 6 10" fill="none">
|
|
406
|
+
<path d="M1 9L5 5L1 1" stroke="#7C98B4" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
|
|
407
|
+
</svg>
|
|
408
|
+
`;
|
|
409
|
+
path.appendChild(svgIcon);
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
const listElementDescription = document.createElement('p');
|
|
414
|
+
listElementDescription.className = 'result-description';
|
|
298
415
|
// Only highlight user query terms, not stemmed terms
|
|
299
|
-
|
|
416
|
+
listElementDescription.innerHTML = highlight(needle.description, queryTerms);
|
|
300
417
|
|
|
301
418
|
const li = document.createElement('li');
|
|
419
|
+
li.classList.add('site-search-results__item');
|
|
302
420
|
li.dataset.words = needle.foundWords.toString();
|
|
303
|
-
li.dataset.score = (Math.round((needle.score/ total) * 1000) / 1000).toString();
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
421
|
+
li.dataset.score = (Math.round((needle.score / total) * 1000) / 1000).toString();
|
|
422
|
+
listElementWrapper.appendChild(path);
|
|
423
|
+
listElementWrapper.appendChild(listElementTitle);
|
|
424
|
+
listElementWrapper.appendChild(listElementDescription);
|
|
425
|
+
li.appendChild(listElementWrapper);
|
|
307
426
|
|
|
308
427
|
if (enabled(f.search, 'headings') && needle.matchedHeadings.length > 0) {
|
|
309
428
|
const headings = document.createElement('ul');
|
|
@@ -325,28 +444,30 @@ async function search(s, r) {
|
|
|
325
444
|
li.appendChild(headings);
|
|
326
445
|
}
|
|
327
446
|
|
|
328
|
-
|
|
447
|
+
ul.appendChild(li);
|
|
329
448
|
}
|
|
330
449
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
450
|
+
let h2;
|
|
451
|
+
if (needles.length === 0) {
|
|
452
|
+
h2 = document.createElement('h2');
|
|
453
|
+
h2.classList.add('search-results__heading');
|
|
454
|
+
h2.innerHTML = results.dataset.emptytitle || 'No Results';
|
|
455
|
+
}
|
|
335
456
|
|
|
336
457
|
const more = document.createElement('button');
|
|
337
458
|
more.className = 'show-more';
|
|
338
459
|
more.type = 'button';
|
|
339
460
|
more.innerHTML = 'See more';
|
|
340
|
-
more.addEventListener('click', function() {
|
|
461
|
+
more.addEventListener('click', function (e) {
|
|
462
|
+
e.stopPropagation(); // Prevent the click from closing the dropdown
|
|
341
463
|
currentQuery = '';
|
|
342
464
|
const newTotal = numberOfResults + 12;
|
|
343
|
-
|
|
344
465
|
search(s, newTotal);
|
|
345
|
-
})
|
|
466
|
+
});
|
|
346
467
|
|
|
347
468
|
results.innerHTML = '';
|
|
348
|
-
results.appendChild(
|
|
349
|
-
results.appendChild(
|
|
469
|
+
results.appendChild(ul);
|
|
470
|
+
h2 && results.appendChild(h2);
|
|
350
471
|
|
|
351
472
|
if (needles.length > numberOfResults) {
|
|
352
473
|
results.appendChild(more);
|
|
@@ -361,10 +482,12 @@ async function search(s, r) {
|
|
|
361
482
|
var debounceTimer;
|
|
362
483
|
|
|
363
484
|
function debounceSearch() {
|
|
364
|
-
var input =
|
|
485
|
+
var input = siteSearchInput;
|
|
486
|
+
|
|
487
|
+
document.body.style.overflow = 'hidden'; // Prevent scrolling when active
|
|
365
488
|
|
|
366
489
|
if (input == null) {
|
|
367
|
-
throw new Error('Cannot find
|
|
490
|
+
throw new Error('Cannot find data-site-search-query');
|
|
368
491
|
}
|
|
369
492
|
|
|
370
493
|
// Words chained with . are combined, i.e. System.Text is "systemtext"
|
|
@@ -379,10 +502,10 @@ function debounceSearch() {
|
|
|
379
502
|
}
|
|
380
503
|
|
|
381
504
|
fetch(dataUrl)
|
|
382
|
-
.then(function (response) {
|
|
505
|
+
.then(function (response) {
|
|
383
506
|
return response.json();
|
|
384
507
|
})
|
|
385
|
-
.then(function (data) {
|
|
508
|
+
.then(function (data) {
|
|
386
509
|
haystack = data;
|
|
387
510
|
ready = true;
|
|
388
511
|
|
|
@@ -397,21 +520,21 @@ fetch(dataUrl)
|
|
|
397
520
|
}
|
|
398
521
|
|
|
399
522
|
/** @type {HTMLFormElement} */
|
|
400
|
-
const siteSearch =
|
|
523
|
+
const siteSearch = siteSearchElement;
|
|
401
524
|
|
|
402
525
|
/** @type {HTMLInputElement} */
|
|
403
|
-
const siteSearchQuery =
|
|
526
|
+
const siteSearchQuery = siteSearchInput;
|
|
404
527
|
|
|
405
528
|
if (siteSearch == null || siteSearchQuery == null) {
|
|
406
|
-
throw new Error('Cannot find #site-search or
|
|
529
|
+
throw new Error('Cannot find #site-search or data-site-search-query');
|
|
407
530
|
}
|
|
408
|
-
|
|
531
|
+
|
|
409
532
|
siteSearch.addEventListener('submit', function (e) {
|
|
410
533
|
e.preventDefault();
|
|
411
534
|
debounceSearch();
|
|
412
535
|
return false;
|
|
413
536
|
});
|
|
414
|
-
|
|
537
|
+
|
|
415
538
|
siteSearchQuery.addEventListener('keyup', function (e) {
|
|
416
539
|
e.preventDefault();
|
|
417
540
|
if (!scrolled) {
|
|
@@ -429,7 +552,7 @@ fetch(dataUrl)
|
|
|
429
552
|
|
|
430
553
|
for (let key of Object.keys(scoring)) {
|
|
431
554
|
if (params.has(`s_${key}`)) {
|
|
432
|
-
scoring[key] = parseInt(params.get(`s_${key}`) ?? scoring[key].toString(), 10)
|
|
555
|
+
scoring[key] = parseInt(params.get(`s_${key}`) ?? scoring[key].toString(), 10);
|
|
433
556
|
}
|
|
434
557
|
}
|
|
435
558
|
|
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,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
// warning: This file is overwritten by Astro Accelerator
|
|
3
|
+
|
|
4
|
+
// For listing all articles in this folder
|
|
5
|
+
import { PostFiltering, PostOrdering, Accelerator } from 'astro-accelerator-utils';
|
|
6
|
+
import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
|
|
7
|
+
import type { MarkdownInstance } from 'astro-accelerator-utils/types/Astro';
|
|
8
|
+
import type { Page } from 'astro';
|
|
9
|
+
import { SITE } from '@config';
|
|
10
|
+
import { Translations, Lang } from '@util/Languages';
|
|
11
|
+
import Default from 'src/layouts/Default.astro';
|
|
12
|
+
import ArticleList from '@components/ArticleList.astro';
|
|
13
|
+
import PagingLinks from '@components/PagingLinks.astro';
|
|
14
|
+
|
|
15
|
+
const accelerator = new Accelerator(SITE);
|
|
16
|
+
const stats = new accelerator.statistics('pages/articles/[page].astro');
|
|
17
|
+
stats.start();
|
|
18
|
+
|
|
19
|
+
const lang = SITE.default.lang;
|
|
20
|
+
|
|
21
|
+
// Props
|
|
22
|
+
type Props = {
|
|
23
|
+
page: Page<MarkdownInstance>;
|
|
24
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
25
|
+
pubDate: Date;
|
|
26
|
+
};
|
|
27
|
+
const { page, headings, pubDate } = Astro.props satisfies Props;
|
|
28
|
+
|
|
29
|
+
const frontmatter: Frontmatter = {
|
|
30
|
+
layout: 'src/layouts/Default.astro',
|
|
31
|
+
title: 'Articles',
|
|
32
|
+
keywords: `articles`,
|
|
33
|
+
description: `${SITE.title} articles.`,
|
|
34
|
+
pubDate: pubDate
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
// Language
|
|
38
|
+
const _ = Lang(lang);
|
|
39
|
+
|
|
40
|
+
// Logic
|
|
41
|
+
export async function getData() {
|
|
42
|
+
const sourcePosts = await Astro.glob('./**/*.md', './**/*.mdx') as MarkdownInstance[];
|
|
43
|
+
const posts = sourcePosts
|
|
44
|
+
.filter(PostFiltering.isListable)
|
|
45
|
+
.sort(PostOrdering.sortByPubDateDesc);
|
|
46
|
+
|
|
47
|
+
return posts;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function getStaticPaths({ paginate }: any) {
|
|
51
|
+
let data = await getData();
|
|
52
|
+
return paginate(data, {
|
|
53
|
+
props: { pubDate: data[0].frontmatter.pubDate },
|
|
54
|
+
pageSize: SITE.pageSize
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Page Links
|
|
59
|
+
const pageLinks = accelerator.paging.links(SITE.pageLinks, page.lastPage, page.currentPage, page.url.current);
|
|
60
|
+
|
|
61
|
+
stats.stop();
|
|
62
|
+
---
|
|
63
|
+
<Default frontmatter={ frontmatter } headings={ headings }>
|
|
64
|
+
<h2>{ _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()) }</h2>
|
|
65
|
+
<ArticleList lang={ lang } posts={ page.data } />
|
|
66
|
+
<PagingLinks lang={ lang } page={ page } pageLinks={ pageLinks } />
|
|
67
|
+
</Default>
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
// warning: This file is overwritten by Astro Accelerator
|
|
3
|
+
|
|
4
|
+
// For listing all articles in this folder
|
|
5
|
+
import { PostFiltering, PostOrdering, Accelerator } from 'astro-accelerator-utils';
|
|
6
|
+
import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
|
|
7
|
+
import type { MarkdownInstance } from 'astro-accelerator-utils/types/Astro';
|
|
8
|
+
import type { Page } from 'astro';
|
|
9
|
+
import { Translations, Lang } from '@util/Languages';
|
|
10
|
+
import { SITE } from '@config';
|
|
11
|
+
import Default from 'src/layouts/Default.astro';
|
|
12
|
+
import ArticleList from '@components/ArticleList.astro';
|
|
13
|
+
import PagingLinks from '@components/PagingLinks.astro';
|
|
14
|
+
|
|
15
|
+
const accelerator = new Accelerator(SITE);
|
|
16
|
+
const stats = new accelerator.statistics('pages/authors/[author]/[page].astro');
|
|
17
|
+
stats.start();
|
|
18
|
+
|
|
19
|
+
const lang = SITE.default.lang;
|
|
20
|
+
const currentUrl = new URL(Astro.request.url);
|
|
21
|
+
const slug = accelerator.urlFormatter.getAuthorId(currentUrl);
|
|
22
|
+
|
|
23
|
+
const author = accelerator.posts.all()
|
|
24
|
+
.filter(PostFiltering.isAuthor)
|
|
25
|
+
.filter(x => {
|
|
26
|
+
if (!x.url) {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const url = new URL(x.url, SITE.url);
|
|
31
|
+
return accelerator.urlFormatter.getAuthorId(url) == slug;
|
|
32
|
+
})[0];
|
|
33
|
+
|
|
34
|
+
// Language
|
|
35
|
+
const _ = Lang(lang);
|
|
36
|
+
|
|
37
|
+
// Props
|
|
38
|
+
type Props = {
|
|
39
|
+
page: Page<MarkdownInstance>;
|
|
40
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
41
|
+
pubDate: Date;
|
|
42
|
+
};
|
|
43
|
+
const { title, page, headings, pubDate } = Astro.props satisfies Props;
|
|
44
|
+
|
|
45
|
+
const authorFrontmatter = {
|
|
46
|
+
...author.frontmatter,
|
|
47
|
+
titleAdditional: `(${ _(Translations.articles.author) }) ` + _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()),
|
|
48
|
+
pubDate: pubDate
|
|
49
|
+
} as Frontmatter;
|
|
50
|
+
|
|
51
|
+
const text = (author.frontmatter.summary ?? '').replace('\n', '\n\n');
|
|
52
|
+
const authorText = accelerator.markdown.getHtmlFrom(text);
|
|
53
|
+
|
|
54
|
+
// Logic
|
|
55
|
+
type AuthorData = {
|
|
56
|
+
posts: MarkdownInstance[];
|
|
57
|
+
authors: string[];
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function getData() {
|
|
61
|
+
const sourcePosts = await Astro.glob(['../../**/*.md', '../../**/*.mdx']) satisfies MarkdownInstance[];
|
|
62
|
+
const data: AuthorData = { posts: [], authors: []};
|
|
63
|
+
|
|
64
|
+
data.posts = sourcePosts
|
|
65
|
+
.filter(PostFiltering.isListable)
|
|
66
|
+
.sort(PostOrdering.sortByPubDateDesc);
|
|
67
|
+
|
|
68
|
+
data.posts.forEach(p => {
|
|
69
|
+
const auths: string[] = p.frontmatter.authors ?? [];
|
|
70
|
+
if (auths.length == 0) {
|
|
71
|
+
console.log('No authors found', p.url);
|
|
72
|
+
}
|
|
73
|
+
auths.forEach(a => {
|
|
74
|
+
if (!data.authors.includes(a)) {
|
|
75
|
+
data.authors.push(a);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return data;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export async function getStaticPaths({ paginate }: any) {
|
|
84
|
+
let data = await getData();
|
|
85
|
+
|
|
86
|
+
return data.authors.map(a => {
|
|
87
|
+
const filtered = data.posts.filter(p => {
|
|
88
|
+
const auths: string[] = p.frontmatter.authors ?? [];
|
|
89
|
+
return auths.includes(a);
|
|
90
|
+
});
|
|
91
|
+
return paginate(filtered, {
|
|
92
|
+
params: { author: a.toLowerCase() },
|
|
93
|
+
props: { pubDate: filtered[0].frontmatter.pubDate },
|
|
94
|
+
pageSize: SITE.pageSize
|
|
95
|
+
});
|
|
96
|
+
}).flat();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Page Links
|
|
100
|
+
const pageLinks = accelerator.paging.links(SITE.pageLinks, page.lastPage, page.currentPage, page.url.current);
|
|
101
|
+
|
|
102
|
+
// Breadcrumbs
|
|
103
|
+
const breadcrumbs: { url: string; title: string; ariaCurrent?: string; }[] = []
|
|
104
|
+
|
|
105
|
+
if (page.url.current != pageLinks[0].url) {
|
|
106
|
+
breadcrumbs.push({
|
|
107
|
+
url: page.url.current,
|
|
108
|
+
title: _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()),
|
|
109
|
+
ariaCurrent: 'page',
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
stats.stop();
|
|
114
|
+
---
|
|
115
|
+
<Default frontmatter={ authorFrontmatter } headings={ headings } breadcrumbs={ breadcrumbs }>
|
|
116
|
+
<Fragment set:html={ authorText } />
|
|
117
|
+
<h2>{ _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()) }</h2>
|
|
118
|
+
<ArticleList lang={ lang } posts={ page.data } />
|
|
119
|
+
<PagingLinks lang={ lang } page={ page } pageLinks={ pageLinks } />
|
|
120
|
+
</Default>
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
---
|
|
2
|
+
// warning: This file is overwritten by Astro Accelerator
|
|
3
|
+
|
|
4
|
+
// For listing by frontmatter.categories
|
|
5
|
+
import { PostFiltering, PostOrdering, Accelerator } from 'astro-accelerator-utils';
|
|
6
|
+
import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
|
|
7
|
+
import type { MarkdownInstance } from 'astro-accelerator-utils/types/Astro';
|
|
8
|
+
import type { Page } from 'astro';
|
|
9
|
+
import { Translations, Lang } from '@util/Languages';
|
|
10
|
+
import { SITE } from '@config';
|
|
11
|
+
import Default from 'src/layouts/Default.astro';
|
|
12
|
+
import ArticleList from '@components/ArticleList.astro';
|
|
13
|
+
import PagingLinks from '@components/PagingLinks.astro';
|
|
14
|
+
|
|
15
|
+
const accelerator = new Accelerator(SITE);
|
|
16
|
+
const stats = new accelerator.statistics('pages/authors/[category]/[page].astro');
|
|
17
|
+
stats.start();
|
|
18
|
+
|
|
19
|
+
const lang = SITE.default.lang;
|
|
20
|
+
const currentUrl = new URL(Astro.request.url);
|
|
21
|
+
const slug = currentUrl.pathname.split('/')[3];
|
|
22
|
+
|
|
23
|
+
// Language
|
|
24
|
+
const _ = Lang(lang);
|
|
25
|
+
|
|
26
|
+
// Props
|
|
27
|
+
type Props = {
|
|
28
|
+
title: string;
|
|
29
|
+
page: Page<MarkdownInstance>;
|
|
30
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
31
|
+
pubDate: Date;
|
|
32
|
+
};
|
|
33
|
+
const { title, page, headings, pubDate } = Astro.props satisfies Props;
|
|
34
|
+
|
|
35
|
+
const frontmatter: Frontmatter = {
|
|
36
|
+
layout: 'src/layouts/Default.astro',
|
|
37
|
+
title: title,
|
|
38
|
+
titleAdditional: `(${ _(Translations.articles.category) }) ` + _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()),
|
|
39
|
+
keywords: `${slug},articles`,
|
|
40
|
+
description: `${SITE.title} ${slug} articles.`,
|
|
41
|
+
pubDate: pubDate
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Logic
|
|
45
|
+
type CategoryData = {
|
|
46
|
+
posts: MarkdownInstance[];
|
|
47
|
+
categories: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function getData() {
|
|
51
|
+
// TODO: Replace with call to Posts.all()
|
|
52
|
+
const sourcePosts = await Astro.glob(['../../**/*.md', '../../**/*.mdx']) as MarkdownInstance[];
|
|
53
|
+
|
|
54
|
+
const data: CategoryData = { posts: [], categories: []};
|
|
55
|
+
|
|
56
|
+
data.posts = sourcePosts
|
|
57
|
+
.filter(PostFiltering.isListable)
|
|
58
|
+
.sort(PostOrdering.sortByPubDateDesc);
|
|
59
|
+
|
|
60
|
+
data.posts.forEach(p => {
|
|
61
|
+
const auths: string[] = p.frontmatter.categories ?? [];
|
|
62
|
+
if (auths.length == 0) {
|
|
63
|
+
console.log('No categories found', p.url);
|
|
64
|
+
}
|
|
65
|
+
auths.forEach(a => {
|
|
66
|
+
if (!data.categories.includes(a)) {
|
|
67
|
+
data.categories.push(a);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return data;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function getStaticPaths({ paginate }: any) {
|
|
76
|
+
let data = await getData();
|
|
77
|
+
|
|
78
|
+
return data.categories.map(c => {
|
|
79
|
+
const filtered = data.posts.filter(p => {
|
|
80
|
+
const cats: string[] = p.frontmatter.categories ?? [];
|
|
81
|
+
return cats.includes(c);
|
|
82
|
+
});
|
|
83
|
+
return paginate(filtered, {
|
|
84
|
+
params: { category: c.toLowerCase().replace(/ /g, '-') },
|
|
85
|
+
props: { title: c, pubDate: filtered[0].frontmatter.pubDate },
|
|
86
|
+
pageSize: SITE.pageSize
|
|
87
|
+
});
|
|
88
|
+
}).flat();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Page Links
|
|
92
|
+
const pageLinks = accelerator.paging.links(SITE.pageLinks, page.lastPage, page.currentPage, page.url.current);
|
|
93
|
+
|
|
94
|
+
// Breadcrumbs
|
|
95
|
+
const breadcrumbs: { url: string; title: string; ariaCurrent?: string; }[] = []
|
|
96
|
+
|
|
97
|
+
if (page.url.current == pageLinks[0].url) {
|
|
98
|
+
breadcrumbs.push({
|
|
99
|
+
url: pageLinks[0].url as string,
|
|
100
|
+
title: title,
|
|
101
|
+
ariaCurrent: 'page'
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (page.url.current != pageLinks[0].url) {
|
|
106
|
+
breadcrumbs.push({
|
|
107
|
+
url: pageLinks[0].url as string,
|
|
108
|
+
title: title,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
breadcrumbs.push({
|
|
112
|
+
url: page.url.current,
|
|
113
|
+
title: _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()),
|
|
114
|
+
ariaCurrent: 'page',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
stats.stop();
|
|
119
|
+
---
|
|
120
|
+
<Default frontmatter={ frontmatter } headings={ headings } breadcrumbs={ breadcrumbs }>
|
|
121
|
+
<h2>{ _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()) }</h2>
|
|
122
|
+
<ArticleList lang={ lang } posts={ page.data } />
|
|
123
|
+
<PagingLinks lang={ lang } page={ page } pageLinks={ pageLinks } />
|
|
124
|
+
</Default>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
// warning: This file is overwritten by Astro Accelerator
|
|
3
|
+
|
|
4
|
+
import { getData } from './[page].astro';
|
|
5
|
+
import Redirect from 'src/layouts/Redirect.astro'
|
|
6
|
+
|
|
7
|
+
export async function getStaticPaths() {
|
|
8
|
+
let data = await getData();
|
|
9
|
+
|
|
10
|
+
return data.categories.map(item => {
|
|
11
|
+
return { params: { category: item.toLowerCase().replace(' ', '-') }}
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const frontmatter = {
|
|
16
|
+
redirect: './1/'
|
|
17
|
+
} as any;
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<Redirect frontmatter={ frontmatter } headings={ [] } />
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
// warning: This file is overwritten by Astro Accelerator
|
|
3
|
+
|
|
4
|
+
// For listing by frontmatter.tags
|
|
5
|
+
import { PostFiltering, PostOrdering, Accelerator } from 'astro-accelerator-utils';
|
|
6
|
+
import type { Frontmatter } from 'astro-accelerator-utils/types/Frontmatter';
|
|
7
|
+
import type { MarkdownInstance } from 'astro-accelerator-utils/types/Astro';
|
|
8
|
+
import type { Page } from 'astro';
|
|
9
|
+
import { Translations, Lang } from '@util/Languages';
|
|
10
|
+
import { SITE } from '@config';
|
|
11
|
+
import Default from 'src/layouts/Default.astro';
|
|
12
|
+
import ArticleList from '@components/ArticleList.astro';
|
|
13
|
+
import PagingLinks from '@components/PagingLinks.astro';
|
|
14
|
+
|
|
15
|
+
const accelerator = new Accelerator(SITE);
|
|
16
|
+
const stats = new accelerator.statistics('pages/authors/[tag]/[page].astro');
|
|
17
|
+
stats.start();
|
|
18
|
+
|
|
19
|
+
const lang = SITE.default.lang;
|
|
20
|
+
const currentUrl = new URL(Astro.request.url);
|
|
21
|
+
const slug = currentUrl.pathname.split('/')[3];
|
|
22
|
+
|
|
23
|
+
// Language
|
|
24
|
+
const _ = Lang(lang);
|
|
25
|
+
|
|
26
|
+
// Props
|
|
27
|
+
type Props = {
|
|
28
|
+
title: string;
|
|
29
|
+
page: Page<MarkdownInstance>;
|
|
30
|
+
headings: { depth: number; slug: string; text: string; }[];
|
|
31
|
+
pubDate: Date;
|
|
32
|
+
};
|
|
33
|
+
const { title, page, headings, pubDate } = Astro.props satisfies Props;
|
|
34
|
+
|
|
35
|
+
const frontmatter: Frontmatter = {
|
|
36
|
+
layout: 'src/layouts/Default.astro',
|
|
37
|
+
title: title,
|
|
38
|
+
titleAdditional: `(${ _(Translations.articles.tag) }) ` + _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()),
|
|
39
|
+
keywords: `${slug},articles`,
|
|
40
|
+
description: `${SITE.title} ${slug} articles.`,
|
|
41
|
+
pubDate: pubDate
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Logic
|
|
45
|
+
type CacheData = {
|
|
46
|
+
posts: MarkdownInstance[];
|
|
47
|
+
tags: string[];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export async function getData() {
|
|
51
|
+
const sourcePosts = await Astro.glob(['../../**/*.md', '../../**/*.mdx']) satisfies MarkdownInstance[];
|
|
52
|
+
|
|
53
|
+
const data: CacheData = { posts: [], tags: []};
|
|
54
|
+
|
|
55
|
+
data.posts = sourcePosts
|
|
56
|
+
.filter(PostFiltering.isListable)
|
|
57
|
+
.sort(PostOrdering.sortByPubDateDesc);
|
|
58
|
+
|
|
59
|
+
data.posts.forEach(p => {
|
|
60
|
+
const auths: string[] = p.frontmatter.tags ?? [];
|
|
61
|
+
if (auths.length == 0) {
|
|
62
|
+
console.log('No categories found', p.url);
|
|
63
|
+
}
|
|
64
|
+
auths.forEach(a => {
|
|
65
|
+
if (!data.tags.includes(a)) {
|
|
66
|
+
data.tags.push(a);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
return data;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export async function getStaticPaths({ paginate }: any) {
|
|
75
|
+
let data = await getData();
|
|
76
|
+
|
|
77
|
+
return data.tags.map(t => {
|
|
78
|
+
const filtered = data.posts.filter(p => {
|
|
79
|
+
const tags: string[] = p.frontmatter.tags ?? [];
|
|
80
|
+
return tags.includes(t);
|
|
81
|
+
});
|
|
82
|
+
return paginate(filtered, {
|
|
83
|
+
params: { tag: t.toLowerCase().replace(/ /g, '-') },
|
|
84
|
+
props: { title: t, pubDate: filtered[0].frontmatter.pubDate },
|
|
85
|
+
pageSize: SITE.pageSize
|
|
86
|
+
});
|
|
87
|
+
}).flat();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Page Links
|
|
91
|
+
const pageLinks = accelerator.paging.links(SITE.pageLinks, page.lastPage, page.currentPage, page.url.current);
|
|
92
|
+
|
|
93
|
+
// Breadcrumbs
|
|
94
|
+
const breadcrumbs: { url: string; title: string; ariaCurrent?: string; }[] = []
|
|
95
|
+
|
|
96
|
+
if (page.url.current == pageLinks[0].url) {
|
|
97
|
+
breadcrumbs.push({
|
|
98
|
+
url: pageLinks[0].url as string,
|
|
99
|
+
title: title,
|
|
100
|
+
ariaCurrent: 'page'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (page.url.current != pageLinks[0].url) {
|
|
105
|
+
breadcrumbs.push({
|
|
106
|
+
url: pageLinks[0].url as string,
|
|
107
|
+
title: title,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
breadcrumbs.push({
|
|
111
|
+
url: page.url.current,
|
|
112
|
+
title: _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()),
|
|
113
|
+
ariaCurrent: 'page',
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
stats.stop();
|
|
118
|
+
---
|
|
119
|
+
<Default frontmatter={ frontmatter } headings={ headings } breadcrumbs={ breadcrumbs }>
|
|
120
|
+
<h2>{ _(Translations.articles.page_title).replace('{n}', page.currentPage.toString()) }</h2>
|
|
121
|
+
<ArticleList lang={ lang } posts={ page.data } />
|
|
122
|
+
<PagingLinks lang={ lang } page={ page } pageLinks={ pageLinks } />
|
|
123
|
+
</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>
|