@crombolo/cli 0.13.2 → 0.14.4
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/bin/crombolo.ts +689 -23
- package/package.json +7 -7
- package/src/operations/commands.ts +108 -4
- package/src/remote/client.ts +288 -0
- package/src/remote/remotes-file.ts +80 -0
- package/src/remote/transfer.ts +337 -0
- package/templates/basic/bundle/package.json +1 -1
- package/templates/demo/harbourstone/bundle/content/bundle.json +11 -4
- package/templates/demo/harbourstone/bundle/content/nodes/40107d59-f3e9-4592-aee8-5b03d4586cbd.json +7 -0
- package/templates/demo/harbourstone/bundle/content/nodes/6ad8f0f3-9334-47f1-b805-80c4b4b4fa88.json +7 -0
- package/templates/demo/harbourstone/bundle/content/nodes/9468d1b4-f521-48ef-b044-2ab07b461b96.json +42 -0
- package/templates/demo/harbourstone/bundle/content/nodes/a562f0a2-cb6e-4ead-a1ce-4d180632419f.json +7 -0
- package/templates/demo/harbourstone/bundle/content/nodes/cd681b4b-9c4e-4624-9c13-450aa6a9c135.json +7 -0
- package/templates/demo/harbourstone/bundle/package.json +1 -1
- package/templates/demo/harbourstone/files/components/pages/searchPage.tsx +76 -0
- package/templates/demo/harbourstone/files/components/shared/site-header.tsx +13 -1
- package/templates/demo/harbourstone/files/css/site.css +113 -0
- package/templates/demo/harbourstone/files/schema/content-types/contact-page.toml +2 -0
- package/templates/demo/harbourstone/files/schema/content-types/content-page.toml +2 -0
- package/templates/demo/harbourstone/files/schema/content-types/expression.toml +8 -0
- package/templates/demo/harbourstone/files/schema/content-types/home-page.toml +5 -1
- package/templates/demo/harbourstone/files/schema/content-types/search-page.toml +33 -0
- package/templates/demo/harbourstone/files/schema/content-types/whisky-list.toml +2 -0
- package/templates/starter/bundle/content/bundle.json +12 -5
- package/templates/starter/bundle/content/nodes/c720ef2a-b5c8-48ec-a504-065e8188d4aa.json +28 -0
- package/templates/starter/bundle/package.json +1 -1
- package/templates/starter/files/components/pages/searchPage.tsx +57 -0
- package/templates/starter/files/components/shared/site-header.tsx +11 -2
- package/templates/starter/files/css/site.css +66 -0
- package/templates/starter/files/schema/content-types/content-page.toml +4 -1
- package/templates/starter/files/schema/content-types/search-page.toml +21 -0
|
@@ -162,6 +162,27 @@ main > article,
|
|
|
162
162
|
color: var(--brass-deep);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
+
/* The search box sits after the links, as small and quiet as they are. */
|
|
166
|
+
.masthead__search input {
|
|
167
|
+
width: 9rem;
|
|
168
|
+
padding: 0.35rem 0.6rem;
|
|
169
|
+
border: 1px solid var(--line);
|
|
170
|
+
border-radius: 0;
|
|
171
|
+
background: var(--card);
|
|
172
|
+
color: var(--ink);
|
|
173
|
+
font: inherit;
|
|
174
|
+
font-size: 0.875rem;
|
|
175
|
+
transition:
|
|
176
|
+
border-color var(--ease),
|
|
177
|
+
width var(--ease);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.masthead__search input:focus-visible {
|
|
181
|
+
outline: none;
|
|
182
|
+
width: 13rem;
|
|
183
|
+
border-color: var(--brass);
|
|
184
|
+
}
|
|
185
|
+
|
|
165
186
|
.site-footer {
|
|
166
187
|
margin-top: 5rem;
|
|
167
188
|
border-top: 1px solid var(--line);
|
|
@@ -718,3 +739,95 @@ main > article,
|
|
|
718
739
|
padding-block: 0;
|
|
719
740
|
}
|
|
720
741
|
}
|
|
742
|
+
|
|
743
|
+
/* -------------------------------------------------------------- search */
|
|
744
|
+
|
|
745
|
+
.search-form {
|
|
746
|
+
display: flex;
|
|
747
|
+
flex-wrap: wrap;
|
|
748
|
+
gap: 0.75rem;
|
|
749
|
+
align-items: stretch;
|
|
750
|
+
margin-top: 2rem;
|
|
751
|
+
max-width: 36rem;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
.search-form input {
|
|
755
|
+
flex: 1;
|
|
756
|
+
min-width: 12rem;
|
|
757
|
+
padding: 0.75rem;
|
|
758
|
+
border: 1px solid var(--line);
|
|
759
|
+
border-radius: 0;
|
|
760
|
+
background: var(--card);
|
|
761
|
+
color: var(--ink);
|
|
762
|
+
font: inherit;
|
|
763
|
+
font-size: 1rem;
|
|
764
|
+
transition: border-color var(--ease);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.search-form input:focus-visible {
|
|
768
|
+
outline: none;
|
|
769
|
+
border-color: var(--brass);
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.search-form .button {
|
|
773
|
+
margin-top: 0;
|
|
774
|
+
background: none;
|
|
775
|
+
cursor: pointer;
|
|
776
|
+
font-family: inherit;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.search-results {
|
|
780
|
+
margin: 0;
|
|
781
|
+
padding: 0;
|
|
782
|
+
max-width: 44rem;
|
|
783
|
+
list-style: none;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.search-results li {
|
|
787
|
+
padding-block: 1.75rem;
|
|
788
|
+
border-top: 1px solid var(--line);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
.search-results h2 {
|
|
792
|
+
margin: 0.5rem 0 0;
|
|
793
|
+
font-size: 1.5rem;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
.search-results h2 a {
|
|
797
|
+
text-decoration: none;
|
|
798
|
+
transition: color var(--ease);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
.search-results h2 a:hover {
|
|
802
|
+
color: var(--brass-deep);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.search-results p {
|
|
806
|
+
margin: 0.75rem 0 0;
|
|
807
|
+
color: var(--muted);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.search-results mark {
|
|
811
|
+
background: none;
|
|
812
|
+
color: var(--ink);
|
|
813
|
+
font-weight: 500;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
.search-pages {
|
|
817
|
+
display: flex;
|
|
818
|
+
justify-content: space-between;
|
|
819
|
+
align-items: baseline;
|
|
820
|
+
max-width: 44rem;
|
|
821
|
+
padding-top: 1.75rem;
|
|
822
|
+
border-top: 1px solid var(--line);
|
|
823
|
+
font-size: 0.75rem;
|
|
824
|
+
font-weight: 500;
|
|
825
|
+
letter-spacing: 0.18em;
|
|
826
|
+
text-transform: uppercase;
|
|
827
|
+
color: var(--muted);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
nav.search-pages a {
|
|
831
|
+
color: var(--brass-deep);
|
|
832
|
+
text-decoration: none;
|
|
833
|
+
}
|
|
@@ -19,6 +19,7 @@ key = "753d8c52-4949-4e92-a76a-fa02da0fd199"
|
|
|
19
19
|
alias = "eyebrow"
|
|
20
20
|
name = "Eyebrow"
|
|
21
21
|
type = "textstring"
|
|
22
|
+
site-search = "low"
|
|
22
23
|
|
|
23
24
|
[[tab.property]]
|
|
24
25
|
key = "1e8f3a9d-5bdf-4a01-a6c7-cc4a055fae22"
|
|
@@ -26,6 +27,7 @@ alias = "title"
|
|
|
26
27
|
name = "Title"
|
|
27
28
|
type = "textstring"
|
|
28
29
|
mandatory = true
|
|
30
|
+
site-search = "high"
|
|
29
31
|
|
|
30
32
|
[[tab.property]]
|
|
31
33
|
key = "cf4561c0-82bb-4ad5-9f88-bd3fbd210b7c"
|
|
@@ -17,6 +17,7 @@ alias = "eyebrow"
|
|
|
17
17
|
name = "Eyebrow"
|
|
18
18
|
description = "The small line above the heading"
|
|
19
19
|
type = "textstring"
|
|
20
|
+
site-search = "low"
|
|
20
21
|
|
|
21
22
|
[[tab.property]]
|
|
22
23
|
key = "4501d20d-3b78-40a4-97e4-dd25b2d8535a"
|
|
@@ -24,6 +25,7 @@ alias = "title"
|
|
|
24
25
|
name = "Title"
|
|
25
26
|
type = "textstring"
|
|
26
27
|
mandatory = true
|
|
28
|
+
site-search = "high"
|
|
27
29
|
|
|
28
30
|
[[tab.property]]
|
|
29
31
|
key = "33199ac7-8128-4dc4-bae1-554b2a622447"
|
|
@@ -16,6 +16,7 @@ alias = "title"
|
|
|
16
16
|
name = "Title"
|
|
17
17
|
type = "textstring"
|
|
18
18
|
mandatory = true
|
|
19
|
+
site-search = "high"
|
|
19
20
|
|
|
20
21
|
[[tab.property]]
|
|
21
22
|
key = "25738367-ed14-4985-9843-04716417c88a"
|
|
@@ -24,6 +25,13 @@ name = "Kind"
|
|
|
24
25
|
description = "House malt, Lightly peated, Sherry matured, Cask strength"
|
|
25
26
|
type = "textstring"
|
|
26
27
|
|
|
28
|
+
[[tab.property]]
|
|
29
|
+
key = "96f868bf-a368-4457-843a-1f38accf6cc1"
|
|
30
|
+
alias = "productType"
|
|
31
|
+
name = "Product type"
|
|
32
|
+
description = "What the bottling is, e.g. Whisky"
|
|
33
|
+
type = "textstring"
|
|
34
|
+
|
|
27
35
|
[[tab.property]]
|
|
28
36
|
key = "f4238bf1-3d9d-4dbc-b6f4-9800e1dfdc79"
|
|
29
37
|
alias = "summary"
|
|
@@ -5,7 +5,7 @@ name = "Home Page"
|
|
|
5
5
|
description = "The site's landing page"
|
|
6
6
|
icon = "icon-home"
|
|
7
7
|
allow-at-root = true
|
|
8
|
-
allow-children = ["contentPage", "whiskyList", "contactPage"]
|
|
8
|
+
allow-children = ["contentPage", "whiskyList", "contactPage", "searchPage"]
|
|
9
9
|
components = ["pages/homePage"]
|
|
10
10
|
default-component = "pages/homePage"
|
|
11
11
|
|
|
@@ -18,6 +18,7 @@ alias = "eyebrow"
|
|
|
18
18
|
name = "Eyebrow"
|
|
19
19
|
description = "The small line above the heading"
|
|
20
20
|
type = "textstring"
|
|
21
|
+
site-search = "low"
|
|
21
22
|
|
|
22
23
|
[[tab.property]]
|
|
23
24
|
key = "be74a0df-3e9d-47f3-b60e-778a89682a80"
|
|
@@ -26,6 +27,7 @@ name = "Title"
|
|
|
26
27
|
description = "Shown as the page heading"
|
|
27
28
|
type = "textstring"
|
|
28
29
|
mandatory = true
|
|
30
|
+
site-search = "high"
|
|
29
31
|
|
|
30
32
|
[[tab.property]]
|
|
31
33
|
key = "a540c93a-228b-49f6-931a-be1b986bedd1"
|
|
@@ -46,6 +48,7 @@ alias = "heroCtaLabel"
|
|
|
46
48
|
name = "Hero button"
|
|
47
49
|
description = "Links to the range. Leave empty for no button."
|
|
48
50
|
type = "textstring"
|
|
51
|
+
site-search = false
|
|
49
52
|
|
|
50
53
|
[[tab]]
|
|
51
54
|
name = "House style"
|
|
@@ -102,3 +105,4 @@ alias = "rangeCtaLabel"
|
|
|
102
105
|
name = "Button"
|
|
103
106
|
description = "Links to the range. Leave empty for no button."
|
|
104
107
|
type = "textstring"
|
|
108
|
+
site-search = false
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[content-type]
|
|
2
|
+
key = "4308082e-5024-47fc-950d-1ee93a3e304f"
|
|
3
|
+
alias = "searchPage"
|
|
4
|
+
name = "Search Page"
|
|
5
|
+
description = "Lists the pages matching what a visitor searched for"
|
|
6
|
+
icon = "icon-search"
|
|
7
|
+
components = ["pages/searchPage"]
|
|
8
|
+
default-component = "pages/searchPage"
|
|
9
|
+
site-search = false
|
|
10
|
+
|
|
11
|
+
[[tab]]
|
|
12
|
+
name = "Header"
|
|
13
|
+
|
|
14
|
+
[[tab.property]]
|
|
15
|
+
key = "3a5d2f03-8bf6-41e2-9971-3848df983f0a"
|
|
16
|
+
alias = "eyebrow"
|
|
17
|
+
name = "Eyebrow"
|
|
18
|
+
description = "The small line above the heading"
|
|
19
|
+
type = "textstring"
|
|
20
|
+
|
|
21
|
+
[[tab.property]]
|
|
22
|
+
key = "e5be09c2-12bd-4647-a6c9-2549459d97b4"
|
|
23
|
+
alias = "title"
|
|
24
|
+
name = "Title"
|
|
25
|
+
type = "textstring"
|
|
26
|
+
mandatory = true
|
|
27
|
+
|
|
28
|
+
[[tab.property]]
|
|
29
|
+
key = "16eab79f-e753-48ca-a3f8-7e326a3f513f"
|
|
30
|
+
alias = "standfirst"
|
|
31
|
+
name = "Standfirst"
|
|
32
|
+
description = "A sentence under the heading, shown before anyone has searched"
|
|
33
|
+
type = "textarea"
|
|
@@ -19,6 +19,7 @@ key = "13785a42-6d0a-4152-89ec-c765db766547"
|
|
|
19
19
|
alias = "eyebrow"
|
|
20
20
|
name = "Eyebrow"
|
|
21
21
|
type = "textstring"
|
|
22
|
+
site-search = "low"
|
|
22
23
|
|
|
23
24
|
[[tab.property]]
|
|
24
25
|
key = "727804c0-7d4a-43d9-a473-71c9e27397c0"
|
|
@@ -26,6 +27,7 @@ alias = "title"
|
|
|
26
27
|
name = "Title"
|
|
27
28
|
type = "textstring"
|
|
28
29
|
mandatory = true
|
|
30
|
+
site-search = "high"
|
|
29
31
|
|
|
30
32
|
[[tab.property]]
|
|
31
33
|
key = "9c83bcea-a70e-4a3f-8185-ad04ddec55f1"
|
|
@@ -3,19 +3,20 @@
|
|
|
3
3
|
"id": "da9fd74e-b964-44b4-8d61-afa7f65a28d2",
|
|
4
4
|
"createdAt": "2026-10-01T00:00:00.000Z",
|
|
5
5
|
"createdBy": "bun run build:template",
|
|
6
|
-
"integrity": "sha256-
|
|
6
|
+
"integrity": "sha256-c8b50fa21bb3bed8ecf30380427ef65894dafb97734e9bf17ed465080cba7866",
|
|
7
7
|
"snapshot": "published",
|
|
8
8
|
"provenance": {
|
|
9
9
|
"siteName": "Starter",
|
|
10
10
|
"schemaVersion": "1.0.0",
|
|
11
11
|
"schemaRevision": "0",
|
|
12
|
-
"schemaHash": "
|
|
12
|
+
"schemaHash": "1d47f00fd4feb3085e530673fceb33320ddb1c604fbb385c73e631eaace62a73"
|
|
13
13
|
},
|
|
14
14
|
"selector": {
|
|
15
15
|
"roots": [
|
|
16
16
|
"64d95359-d91a-4050-b440-3e5124a74999",
|
|
17
17
|
"634dd948-cf83-4cad-9b7b-7c938b33da76",
|
|
18
|
-
"d2997ebb-36ca-47cb-bbc8-31fefca787c0"
|
|
18
|
+
"d2997ebb-36ca-47cb-bbc8-31fefca787c0",
|
|
19
|
+
"c720ef2a-b5c8-48ec-a504-065e8188d4aa"
|
|
19
20
|
],
|
|
20
21
|
"descendants": true,
|
|
21
22
|
"asGiven": [
|
|
@@ -23,12 +24,13 @@
|
|
|
23
24
|
]
|
|
24
25
|
},
|
|
25
26
|
"counts": {
|
|
26
|
-
"document":
|
|
27
|
+
"document": 4
|
|
27
28
|
},
|
|
28
29
|
"dependencies": {
|
|
29
30
|
"carried": [
|
|
30
31
|
"634dd948-cf83-4cad-9b7b-7c938b33da76",
|
|
31
32
|
"64d95359-d91a-4050-b440-3e5124a74999",
|
|
33
|
+
"c720ef2a-b5c8-48ec-a504-065e8188d4aa",
|
|
32
34
|
"d2997ebb-36ca-47cb-bbc8-31fefca787c0"
|
|
33
35
|
],
|
|
34
36
|
"expected": [],
|
|
@@ -37,10 +39,15 @@
|
|
|
37
39
|
{
|
|
38
40
|
"key": "8491ffa4-9b2f-48b0-a3c0-f40c1034216e",
|
|
39
41
|
"alias": "contentPage"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"key": "938c7f88-8df2-45d2-a4a2-49ecb3e68db7",
|
|
45
|
+
"alias": "searchPage"
|
|
40
46
|
}
|
|
41
47
|
],
|
|
42
48
|
"components": [
|
|
43
|
-
"pages/contentPage"
|
|
49
|
+
"pages/contentPage",
|
|
50
|
+
"pages/searchPage"
|
|
44
51
|
],
|
|
45
52
|
"languages": []
|
|
46
53
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"key": "c720ef2a-b5c8-48ec-a504-065e8188d4aa",
|
|
3
|
+
"kind": "document",
|
|
4
|
+
"contentType": {
|
|
5
|
+
"key": "938c7f88-8df2-45d2-a4a2-49ecb3e68db7",
|
|
6
|
+
"alias": "searchPage"
|
|
7
|
+
},
|
|
8
|
+
"parent": "64d95359-d91a-4050-b440-3e5124a74999",
|
|
9
|
+
"sortOrder": 2,
|
|
10
|
+
"template": "pages/searchPage",
|
|
11
|
+
"variants": [
|
|
12
|
+
{
|
|
13
|
+
"culture": null,
|
|
14
|
+
"segment": null,
|
|
15
|
+
"name": "Search",
|
|
16
|
+
"published": true
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"values": [
|
|
20
|
+
{
|
|
21
|
+
"property": "title",
|
|
22
|
+
"culture": null,
|
|
23
|
+
"segment": null,
|
|
24
|
+
"editor": "Umbraco.TextBox",
|
|
25
|
+
"value": "Search"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type PageProps, search } from '@crombolo/crombolo'
|
|
2
|
+
import { Layout } from '../shared/layout.tsx'
|
|
3
|
+
|
|
4
|
+
const PER_PAGE = 10
|
|
5
|
+
|
|
6
|
+
/** The pages matching `?q=`, best first, ten at a time, each with the text around the match. */
|
|
7
|
+
export default async function SearchPage(props: PageProps) {
|
|
8
|
+
const { model, request } = props
|
|
9
|
+
const url = new URL(request.url)
|
|
10
|
+
const query = url.searchParams.get('q')?.trim() ?? ''
|
|
11
|
+
const page = Math.max(1, Number.parseInt(url.searchParams.get('page') ?? '1', 10) || 1)
|
|
12
|
+
const results = query
|
|
13
|
+
? await search(query, { skip: (page - 1) * PER_PAGE, take: PER_PAGE })
|
|
14
|
+
: { total: 0, items: [] }
|
|
15
|
+
const pages = Math.ceil(results.total / PER_PAGE)
|
|
16
|
+
const link = (n: number) => `${model.url}?q=${encodeURIComponent(query)}&page=${n}`
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Layout {...props}>
|
|
20
|
+
<h1>{model.text('title') || model.name}</h1>
|
|
21
|
+
<search>
|
|
22
|
+
<form class="search-form" action={model.url} method="get">
|
|
23
|
+
<input type="search" name="q" value={query} aria-label="Search the site" />
|
|
24
|
+
<button type="submit">Search</button>
|
|
25
|
+
</form>
|
|
26
|
+
</search>
|
|
27
|
+
{query ? (
|
|
28
|
+
<p class="search-summary">
|
|
29
|
+
{results.total === 0
|
|
30
|
+
? `Nothing matches “${query}”.`
|
|
31
|
+
: `${results.total} ${results.total === 1 ? 'page matches' : 'pages match'} “${query}”.`}
|
|
32
|
+
</p>
|
|
33
|
+
) : null}
|
|
34
|
+
<ol class="search-results">
|
|
35
|
+
{results.items.map((item) => (
|
|
36
|
+
<li>
|
|
37
|
+
<a href={item.url}>{item.content.text('title') || item.name}</a>
|
|
38
|
+
<p>
|
|
39
|
+
{item.excerpt.map((segment) =>
|
|
40
|
+
segment.match ? <mark>{segment.text}</mark> : segment.text,
|
|
41
|
+
)}
|
|
42
|
+
</p>
|
|
43
|
+
</li>
|
|
44
|
+
))}
|
|
45
|
+
</ol>
|
|
46
|
+
{pages > 1 ? (
|
|
47
|
+
<nav class="search-pages" aria-label="Search results pages">
|
|
48
|
+
{page > 1 ? <a href={link(page - 1)}>Previous</a> : null}
|
|
49
|
+
<span>
|
|
50
|
+
Page {page} of {pages}
|
|
51
|
+
</span>
|
|
52
|
+
{page < pages ? <a href={link(page + 1)}>Next</a> : null}
|
|
53
|
+
</nav>
|
|
54
|
+
) : null}
|
|
55
|
+
</Layout>
|
|
56
|
+
)
|
|
57
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { Navigation, PublishedContent } from '@crombolo/crombolo'
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The site name, from the config, and the primary nav: the home page followed by its children, so
|
|
5
|
-
* adding a page in the backoffice adds it here.
|
|
5
|
+
* adding a page in the backoffice adds it here. A Search Page among them is the search box instead.
|
|
6
6
|
*/
|
|
7
7
|
export function SiteHeader({
|
|
8
8
|
model,
|
|
@@ -16,7 +16,9 @@ export function SiteHeader({
|
|
|
16
16
|
const home = nav.root()[0]
|
|
17
17
|
if (!home) return null
|
|
18
18
|
const ancestry = model.path.split(',')
|
|
19
|
-
const
|
|
19
|
+
const children = nav.children(home, { visibleOnly: true })
|
|
20
|
+
const searchPage = children.find((child) => child.contentType.alias === 'searchPage')
|
|
21
|
+
const links = [home, ...children.filter((child) => child !== searchPage)]
|
|
20
22
|
return (
|
|
21
23
|
<header class="site-header">
|
|
22
24
|
<div class="container site-header__inner">
|
|
@@ -34,6 +36,13 @@ export function SiteHeader({
|
|
|
34
36
|
)
|
|
35
37
|
})}
|
|
36
38
|
</nav>
|
|
39
|
+
{searchPage ? (
|
|
40
|
+
<search>
|
|
41
|
+
<form class="site-search" action={searchPage.url} method="get">
|
|
42
|
+
<input type="search" name="q" placeholder="Search" aria-label="Search the site" />
|
|
43
|
+
</form>
|
|
44
|
+
</search>
|
|
45
|
+
) : null}
|
|
37
46
|
</div>
|
|
38
47
|
</header>
|
|
39
48
|
)
|
|
@@ -75,6 +75,72 @@ main {
|
|
|
75
75
|
font-weight: 600;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
.site-search input,
|
|
79
|
+
.search-form input {
|
|
80
|
+
font: inherit;
|
|
81
|
+
padding: 0.4rem 0.75rem;
|
|
82
|
+
border: 1px solid var(--border);
|
|
83
|
+
border-radius: 0.375rem;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.search-form {
|
|
87
|
+
display: flex;
|
|
88
|
+
gap: 0.5rem;
|
|
89
|
+
margin-bottom: 1.5rem;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.search-form input {
|
|
93
|
+
flex: 1;
|
|
94
|
+
max-width: 32rem;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.search-form button {
|
|
98
|
+
font: inherit;
|
|
99
|
+
padding: 0.4rem 1rem;
|
|
100
|
+
border: 0;
|
|
101
|
+
border-radius: 0.375rem;
|
|
102
|
+
background: var(--accent);
|
|
103
|
+
color: #fff;
|
|
104
|
+
cursor: pointer;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.search-summary {
|
|
108
|
+
color: var(--muted);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.search-results {
|
|
112
|
+
list-style: none;
|
|
113
|
+
padding: 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.search-results li {
|
|
117
|
+
padding: 1rem 0;
|
|
118
|
+
border-bottom: 1px solid var(--border);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.search-results li > a {
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
font-size: 1.1rem;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.search-results p {
|
|
127
|
+
margin: 0.25rem 0 0;
|
|
128
|
+
color: var(--muted);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.search-results mark {
|
|
132
|
+
background: none;
|
|
133
|
+
color: var(--text);
|
|
134
|
+
font-weight: 600;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.search-pages {
|
|
138
|
+
display: flex;
|
|
139
|
+
gap: 1.5rem;
|
|
140
|
+
align-items: center;
|
|
141
|
+
margin-top: 1.5rem;
|
|
142
|
+
}
|
|
143
|
+
|
|
78
144
|
h1 {
|
|
79
145
|
font-size: 2.25rem;
|
|
80
146
|
line-height: 1.2;
|
|
@@ -5,7 +5,7 @@ name = "Content Page"
|
|
|
5
5
|
description = "A page with a main column and a sidebar"
|
|
6
6
|
icon = "icon-document"
|
|
7
7
|
allow-at-root = true
|
|
8
|
-
allow-children = ["contentPage"]
|
|
8
|
+
allow-children = ["contentPage", "searchPage"]
|
|
9
9
|
compositions = ["seoFields"]
|
|
10
10
|
components = ["pages/contentPage"]
|
|
11
11
|
default-component = "pages/contentPage"
|
|
@@ -20,6 +20,7 @@ name = "Title"
|
|
|
20
20
|
description = "Shown as the page heading"
|
|
21
21
|
type = "textstring"
|
|
22
22
|
mandatory = true
|
|
23
|
+
site-search = "high"
|
|
23
24
|
|
|
24
25
|
[[tab.property]]
|
|
25
26
|
key = "7028eeb8-9739-4cc9-b3e1-8b424dd1e929"
|
|
@@ -42,6 +43,7 @@ key = "d049eba5-ae38-4fe9-9b05-64d1fa50b35e"
|
|
|
42
43
|
alias = "sidebarHeading"
|
|
43
44
|
name = "Heading"
|
|
44
45
|
type = "textstring"
|
|
46
|
+
site-search = "low"
|
|
45
47
|
|
|
46
48
|
[[tab.property]]
|
|
47
49
|
key = "fff4d170-e192-419a-9490-59affd2f6148"
|
|
@@ -49,3 +51,4 @@ alias = "sidebarText"
|
|
|
49
51
|
name = "Text"
|
|
50
52
|
description = "Leave empty for a single-column page"
|
|
51
53
|
type = "richtext"
|
|
54
|
+
site-search = "low"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[content-type]
|
|
2
|
+
key = "938c7f88-8df2-45d2-a4a2-49ecb3e68db7"
|
|
3
|
+
alias = "searchPage"
|
|
4
|
+
name = "Search Page"
|
|
5
|
+
description = "Lists the pages matching what a visitor searched for"
|
|
6
|
+
icon = "icon-search"
|
|
7
|
+
compositions = ["seoFields"]
|
|
8
|
+
components = ["pages/searchPage"]
|
|
9
|
+
default-component = "pages/searchPage"
|
|
10
|
+
site-search = false
|
|
11
|
+
|
|
12
|
+
[[tab]]
|
|
13
|
+
name = "Content"
|
|
14
|
+
|
|
15
|
+
[[tab.property]]
|
|
16
|
+
key = "324e2bbc-2c0e-4984-a5d0-37032a5bec74"
|
|
17
|
+
alias = "title"
|
|
18
|
+
name = "Title"
|
|
19
|
+
description = "Shown as the page heading"
|
|
20
|
+
type = "textstring"
|
|
21
|
+
mandatory = true
|