@netlify/spark-ui 1.5.0-alpha.9 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/SearchHeading.css +1 -1
- package/dist/assets/SearchLink.css +1 -1
- package/dist/assets/SearchModal.css +1 -1
- package/dist/chunks/compat.module.DJD78v1z.js +175 -0
- package/dist/chunks/hooks.module.D9IrxdEh.js +138 -0
- package/dist/chunks/{useTimeout.Cq4aqnDe.js → useTimeout.YR4eKwj7.js} +1 -1
- package/dist/components/index.d.ts +0 -1
- package/dist/components/preact/Icon/index.d.ts +2 -2
- package/dist/components/preact/Icon/index.js +75 -87
- package/dist/components/preact/Modal/Modal.js +1 -1
- package/dist/components/preact/SearchModal/components/SearchInput.d.ts +0 -2
- package/dist/components/preact/SearchModal/components/SearchInput.js +2 -2
- package/dist/components/preact/SearchModal/components/SearchLink/SearchLink.d.ts +1 -1
- package/dist/components/preact/SearchModal/components/SearchLink/SearchLink.js +17 -35
- package/dist/components/preact/SearchModal/components/SearchModal/SearchModal.js +49 -72
- package/dist/components/preact/SearchModal/components/SearchToggle/SearchToggle.js +1 -1
- package/dist/components/preact/SearchModal/components/SearchWindow.d.ts +1 -1
- package/dist/components/preact/SearchModal/components/SearchWindow.js +30 -49
- package/dist/components/preact/SearchModal/hooks/useKeyboardNav.js +6 -6
- package/dist/components/preact/SearchModal/hooks/useSearch.js +2 -2
- package/dist/components/preact/SearchModal/hooks/useSearchHotkeys.js +1 -1
- package/dist/components/preact/SearchModal/hooks/useSearchLogger.js +1 -1
- package/dist/components/preact/SearchModal/hooks/useSearchParams.js +1 -1
- package/dist/components/preact/SearchModal/hooks/useSearchToggles.d.ts +1 -3
- package/dist/components/preact/SearchModal/hooks/useSearchToggles.js +10 -13
- package/dist/components/preact/SearchModal/types/search.types.d.ts +1 -6
- package/dist/components/preact/index.d.ts +0 -1
- package/dist/components/preact/index.js +5 -7
- package/package.json +3 -5
- package/packages/assets/icons/ai.svg +22 -0
- package/packages/assets/icons/dev.svg +8 -0
- package/packages/assets/icons/ecommerce.svg +16 -0
- package/packages/assets/icons/marketing.svg +20 -0
- package/packages/components/CodeBlock.astro +4 -1
- package/packages/components/SectionTabbedContent.astro +185 -0
- package/packages/components/Switchback.astro +129 -0
- package/packages/components/Tab.astro +12 -0
- package/packages/components/TabList.astro +7 -0
- package/packages/components/TabPanel.astro +13 -0
- package/packages/components/TabPanelGroup.astro +45 -0
- package/packages/components/TabbedContent.astro +72 -0
- package/packages/components/Tabs.astro +0 -2
- package/packages/components/Testimonial.astro +0 -0
- package/packages/components/index.ts +0 -1
- package/packages/components/preact/Icon/index.tsx +55 -56
- package/packages/components/preact/SearchModal/components/SearchHeading/SearchHeading.css +4 -5
- package/packages/components/preact/SearchModal/components/SearchInput.tsx +7 -9
- package/packages/components/preact/SearchModal/components/SearchLink/SearchLink.css +9 -14
- package/packages/components/preact/SearchModal/components/SearchLink/SearchLink.tsx +7 -27
- package/packages/components/preact/SearchModal/components/SearchModal/SearchModal.css +29 -67
- package/packages/components/preact/SearchModal/components/SearchModal/SearchModal.tsx +30 -60
- package/packages/components/preact/SearchModal/components/SearchWindow.tsx +18 -32
- package/packages/components/preact/SearchModal/hooks/useKeyboardNav.ts +2 -2
- package/packages/components/preact/SearchModal/hooks/useSearchToggles.ts +3 -11
- package/packages/components/preact/SearchModal/types/search.types.tsx +2 -5
- package/packages/components/preact/index.ts +0 -1
- package/packages/styles/code-block.css +22 -23
- package/packages/styles/fonts.css +31 -2
- package/packages/styles/layout.css +33 -0
- package/packages/styles/tokens.css +22 -36
- package/packages/themes/poimandres.json +6 -19
- package/dist/assets/AskNetlify.css +0 -1
- package/dist/assets/Orb.css +0 -1
- package/dist/chunks/compat.module.BNbXPLVY.js +0 -298
- package/dist/chunks/hooks.module.DGkdD5n9.js +0 -177
- package/dist/components/preact/AskNetlify/AskNetlify.d.ts +0 -7
- package/dist/components/preact/AskNetlify/AskNetlify.js +0 -5774
- package/dist/components/preact/Orb/Orb.d.ts +0 -2
- package/dist/components/preact/Orb/Orb.js +0 -5
- package/dist/components/preact/SpriteIcon/index.d.ts +0 -7
- package/dist/components/preact/SpriteIcon/index.js +0 -7
- package/dist/components/preact/icons/AskNetlify.d.ts +0 -5
- package/dist/components/preact/icons/AskNetlify.js +0 -69
- package/dist/components/preact/icons/Book.d.ts +0 -5
- package/dist/components/preact/icons/Book.js +0 -23
- package/dist/components/preact/icons/CircleQuestion.d.ts +0 -5
- package/dist/components/preact/icons/CircleQuestion.js +0 -25
- package/dist/components/preact/icons/Comment.d.ts +0 -5
- package/dist/components/preact/icons/Comment.js +0 -23
- package/dist/components/preact/icons/Lightbulb.d.ts +0 -5
- package/dist/components/preact/icons/Lightbulb.js +0 -34
- package/dist/components/preact/icons/MagnifyingGlass.d.ts +0 -5
- package/dist/components/preact/icons/MagnifyingGlass.js +0 -23
- package/dist/utils/theme.d.ts +0 -3
- package/packages/assets/icons/AskNetlify.svg +0 -23
- package/packages/assets/icons/icons.svg +0 -10
- package/packages/assets/icons/lightbulb.svg +0 -4
- package/packages/components/preact/AskNetlify/AskNetlify.css +0 -224
- package/packages/components/preact/AskNetlify/AskNetlify.tsx +0 -156
- package/packages/components/preact/Orb/Orb.css +0 -94
- package/packages/components/preact/Orb/Orb.tsx +0 -7
- package/packages/components/preact/SpriteIcon/index.tsx +0 -13
- package/packages/components/preact/icons/AskNetlify.tsx +0 -46
- package/packages/components/preact/icons/Book.tsx +0 -20
- package/packages/components/preact/icons/CircleQuestion.tsx +0 -22
- package/packages/components/preact/icons/Comment.tsx +0 -20
- package/packages/components/preact/icons/Lightbulb.tsx +0 -26
- package/packages/components/preact/icons/MagnifyingGlass.tsx +0 -20
- package/packages/utils/theme.ts +0 -12
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.n-search-link {
|
|
2
|
-
--n-search-icon-size:
|
|
3
|
-
|
|
2
|
+
--n-search-icon-size: 1em;
|
|
3
|
+
all: unset;
|
|
4
4
|
display: flex;
|
|
5
5
|
justify-content: space-between;
|
|
6
6
|
flex-wrap: wrap;
|
|
@@ -11,11 +11,6 @@
|
|
|
11
11
|
font-weight: var(--font-weight-regular);
|
|
12
12
|
text-decoration: none;
|
|
13
13
|
cursor: pointer;
|
|
14
|
-
width: 100%;
|
|
15
|
-
border: none;
|
|
16
|
-
text-align: left;
|
|
17
|
-
outline: none;
|
|
18
|
-
border-radius: var(--radius-l);
|
|
19
14
|
}
|
|
20
15
|
|
|
21
16
|
.n-search-link-body {
|
|
@@ -25,17 +20,17 @@
|
|
|
25
20
|
text-wrap: pretty;
|
|
26
21
|
}
|
|
27
22
|
|
|
28
|
-
.n-search-link:is(:hover, :focus-
|
|
23
|
+
.n-search-link:is(:hover, :focus-within) {
|
|
29
24
|
background: var(--n-search-color-bg-2);
|
|
30
25
|
|
|
31
26
|
& .n-search-link-icon [data-icon='caretRight'] {
|
|
32
|
-
|
|
27
|
+
display: block;
|
|
33
28
|
}
|
|
34
29
|
}
|
|
35
30
|
|
|
36
31
|
.n-search-link-title {
|
|
37
32
|
font-weight: var(--font-weight-medium);
|
|
38
|
-
color: var(--color-text
|
|
33
|
+
color: var(--color-text);
|
|
39
34
|
line-height: 1.5;
|
|
40
35
|
}
|
|
41
36
|
|
|
@@ -54,8 +49,7 @@
|
|
|
54
49
|
background-color: var(--mark-bg, var(--color-highlight));
|
|
55
50
|
}
|
|
56
51
|
|
|
57
|
-
.n-search-link-icon
|
|
58
|
-
.n-search-link-icon svg {
|
|
52
|
+
.n-search-link-icon {
|
|
59
53
|
display: flex;
|
|
60
54
|
width: var(--n-search-icon-size);
|
|
61
55
|
height: var(--n-search-icon-size);
|
|
@@ -63,8 +57,9 @@
|
|
|
63
57
|
}
|
|
64
58
|
|
|
65
59
|
.n-search-link-icon [data-icon='caretRight'] {
|
|
66
|
-
|
|
67
|
-
|
|
60
|
+
display: none;
|
|
61
|
+
width: 0.8em;
|
|
62
|
+
opacity: 0.3;
|
|
68
63
|
}
|
|
69
64
|
|
|
70
65
|
.n-search-link-label {
|
|
@@ -4,40 +4,20 @@ import './SearchLink.css';
|
|
|
4
4
|
|
|
5
5
|
import Icon from '../../../Icon';
|
|
6
6
|
|
|
7
|
-
const SearchLink = ({
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
label,
|
|
11
|
-
url,
|
|
12
|
-
excerpt,
|
|
13
|
-
resource,
|
|
14
|
-
onClick,
|
|
15
|
-
}: SearchLinkProps) => {
|
|
16
|
-
const { handleClick: log } = useSearchLogger();
|
|
17
|
-
|
|
7
|
+
const SearchLink = ({ icon, label, url, excerpt, resource }: SearchLinkProps) => {
|
|
8
|
+
const { handleClick } = useSearchLogger()
|
|
9
|
+
|
|
18
10
|
return (
|
|
19
|
-
<
|
|
20
|
-
className="n-search-link"
|
|
21
|
-
href={url}
|
|
22
|
-
onClick={(e: Event) => {
|
|
23
|
-
onClick && onClick();
|
|
24
|
-
log(e);
|
|
25
|
-
}}
|
|
26
|
-
>
|
|
11
|
+
<a className="n-search-link" href={url} onClick={handleClick}>
|
|
27
12
|
{icon && (
|
|
28
13
|
<span className="n-search-link-icon">
|
|
29
14
|
<Icon name={icon} />
|
|
30
15
|
</span>
|
|
31
16
|
)}
|
|
32
17
|
<div className="n-search-link-body">
|
|
18
|
+
|
|
33
19
|
<p className="n-search-link-title">
|
|
34
|
-
|
|
35
|
-
{resource && (
|
|
36
|
-
<span className="n-search-link-badge" data-resource={resource}>
|
|
37
|
-
{resource}
|
|
38
|
-
</span>
|
|
39
|
-
)}
|
|
40
|
-
</p>
|
|
20
|
+
<span className="n-search-link-label">{label}</span> {resource && <span className="n-search-link-badge" data-resource={resource}>{resource}</span>}</p>
|
|
41
21
|
{excerpt && (
|
|
42
22
|
<p className="n-search-link-excerpt" dangerouslySetInnerHTML={{ __html: excerpt }} />
|
|
43
23
|
)}
|
|
@@ -45,7 +25,7 @@ const SearchLink = ({
|
|
|
45
25
|
<div className="n-search-link-icon">
|
|
46
26
|
<Icon name="caretRight" />
|
|
47
27
|
</div>
|
|
48
|
-
</
|
|
28
|
+
</a>
|
|
49
29
|
);
|
|
50
30
|
};
|
|
51
31
|
|
|
@@ -4,18 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
/* Root Variables */
|
|
6
6
|
.n-search-modal {
|
|
7
|
-
--n-search-padding-inline:
|
|
8
|
-
--n-search-color-text: var(--color-text
|
|
9
|
-
--n-search-color-text-secondary: var(--color-text-
|
|
7
|
+
--n-search-padding-inline: 0.5em;
|
|
8
|
+
--n-search-color-text: var(--color-text, currentColor);
|
|
9
|
+
--n-search-color-text-secondary: var(--color-text-weak, currentColor);
|
|
10
10
|
--n-search-color-bg: var(--search-bg-color);
|
|
11
|
-
--n-search-color-bg-2: var(--color-bg-
|
|
11
|
+
--n-search-color-bg-2: var(--color-bg-2);
|
|
12
12
|
--n-search-color-border: var(--color-bg-3);
|
|
13
|
-
--n-search-border-radius:
|
|
13
|
+
--n-search-border-radius: 8px;
|
|
14
14
|
--n-search-max-w: 600px;
|
|
15
15
|
--n-search-text-highlight: var(--search-highlight-color);
|
|
16
|
-
--n-search-input-height: 50px;
|
|
17
|
-
--n-search-footer-height: 40px;
|
|
18
|
-
--n-search-container-height: 400px;
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
.n-search-modal {
|
|
@@ -24,17 +21,13 @@
|
|
|
24
21
|
border-radius: var(--n-search-border-radius);
|
|
25
22
|
width: min(var(--n-search-max-w), 100%);
|
|
26
23
|
margin: auto;
|
|
27
|
-
background: var(--n-search-color-bg);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.n-search-modal-ask {
|
|
31
|
-
--n-search-max-w: 800px;
|
|
32
24
|
}
|
|
33
25
|
|
|
34
26
|
.n-search-container {
|
|
35
27
|
--mark-bg: var(--n-search-text-highlight);
|
|
36
28
|
display: grid;
|
|
37
29
|
width: min(var(--n-search-max-w), 100%);
|
|
30
|
+
min-height: 470px;
|
|
38
31
|
background-color: var(--n-search-color-bg);
|
|
39
32
|
border-radius: var(--n-search-border-radius);
|
|
40
33
|
overflow: hidden;
|
|
@@ -50,14 +43,13 @@
|
|
|
50
43
|
}
|
|
51
44
|
|
|
52
45
|
.n-search-input-wrapper {
|
|
53
|
-
|
|
46
|
+
all: unset;
|
|
54
47
|
display: flex;
|
|
55
48
|
width: 100%;
|
|
56
|
-
|
|
49
|
+
border-bottom: 1px solid var(--n-search-color-border);
|
|
57
50
|
}
|
|
58
51
|
|
|
59
52
|
.n-search-input {
|
|
60
|
-
position: relative;
|
|
61
53
|
display: inline-flex;
|
|
62
54
|
box-sizing: border-box;
|
|
63
55
|
background: var(--n-search-color-bg);
|
|
@@ -68,32 +60,16 @@
|
|
|
68
60
|
border: none;
|
|
69
61
|
outline: none;
|
|
70
62
|
font-size: 1rem;
|
|
71
|
-
color: var(--color-text
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
.n-search-input-wrapper::after,
|
|
75
|
-
.n-search-footer::after {
|
|
76
|
-
content: '';
|
|
77
|
-
display: block;
|
|
78
|
-
width: 200%;
|
|
79
|
-
height: 1px;
|
|
80
|
-
background: var(--n-search-color-border);
|
|
81
|
-
position: absolute;
|
|
82
|
-
bottom: 0;
|
|
83
|
-
left: 0;
|
|
63
|
+
color: var(--color-text);
|
|
84
64
|
}
|
|
85
65
|
|
|
86
66
|
.n-search-input::placeholder {
|
|
87
|
-
color: var(--n-search-color-text
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.n-search-links {
|
|
91
|
-
padding: var(--space-2xs);
|
|
67
|
+
color: var(--n-search-color-text);
|
|
92
68
|
}
|
|
93
69
|
|
|
94
70
|
.n-search-label {
|
|
95
71
|
display: flex;
|
|
96
|
-
padding-inline
|
|
72
|
+
padding-inline: var(--n-search-padding-inline);
|
|
97
73
|
align-items: center;
|
|
98
74
|
}
|
|
99
75
|
|
|
@@ -104,8 +80,8 @@
|
|
|
104
80
|
|
|
105
81
|
.n-search-icon {
|
|
106
82
|
display: flex;
|
|
107
|
-
width: var(--n-search-icon-size,
|
|
108
|
-
height: var(--n-search-icon-size,
|
|
83
|
+
width: var(--n-search-icon-size, 0.8em);
|
|
84
|
+
height: var(--n-search-icon-size, 0.8em);
|
|
109
85
|
color: var(--n-search-color-text-secondary);
|
|
110
86
|
}
|
|
111
87
|
|
|
@@ -116,26 +92,28 @@
|
|
|
116
92
|
|
|
117
93
|
/* Search Results */
|
|
118
94
|
.n-search-window {
|
|
119
|
-
height:
|
|
95
|
+
height: 400px;
|
|
120
96
|
overflow-x: hidden;
|
|
121
97
|
overflow-y: auto;
|
|
122
98
|
overscroll-behavior: contain;
|
|
123
|
-
scroll-padding-block: var(--space-s);
|
|
124
99
|
margin-block: 0;
|
|
125
100
|
background: var(--n-search-color-bg);
|
|
126
101
|
}
|
|
127
102
|
|
|
103
|
+
.n-results-list-item {
|
|
104
|
+
border-bottom: 1px solid var(--color-bg-3);
|
|
105
|
+
}
|
|
106
|
+
.n-results-list-item:first-of-type {
|
|
107
|
+
border-top: 1px solid var(--color-bg-3);
|
|
108
|
+
}
|
|
109
|
+
|
|
128
110
|
/* Footer */
|
|
129
111
|
.n-search-footer {
|
|
130
|
-
|
|
112
|
+
border-top: 1px solid var(--n-search-color-border);
|
|
113
|
+
padding: var(--space-2xs) var(--space-s);
|
|
114
|
+
background: var(--color-bg-2);
|
|
131
115
|
display: flex;
|
|
132
116
|
gap: var(--space-m);
|
|
133
|
-
padding: var(--space-2xs) var(--space-s);
|
|
134
|
-
height: var(--n-search-footer-height);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
.n-search-footer::after {
|
|
138
|
-
top: 0;
|
|
139
117
|
}
|
|
140
118
|
|
|
141
119
|
.n-search-footer-tip {
|
|
@@ -150,8 +128,7 @@
|
|
|
150
128
|
.n-search-modal {
|
|
151
129
|
transition:
|
|
152
130
|
display 0.2s allow-discrete,
|
|
153
|
-
overlay 0.2s allow-discrete
|
|
154
|
-
width 0.15s ease-in-out;
|
|
131
|
+
overlay 0.2s allow-discrete;
|
|
155
132
|
animation: closeSearch 0.2s forwards;
|
|
156
133
|
}
|
|
157
134
|
|
|
@@ -159,43 +136,28 @@
|
|
|
159
136
|
animation: openSearch 0.2s forwards;
|
|
160
137
|
}
|
|
161
138
|
|
|
162
|
-
.n-search-modal[data-state='search'] > * {
|
|
163
|
-
opacity: 0;
|
|
164
|
-
animation: appearContainer 120ms ease-in-out forwards;
|
|
165
|
-
animation-delay: 140ms;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
@keyframes appearContainer {
|
|
169
|
-
0% {
|
|
170
|
-
opacity: 0;
|
|
171
|
-
}
|
|
172
|
-
100% {
|
|
173
|
-
opacity: 1;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
139
|
@keyframes openSearch {
|
|
178
140
|
from {
|
|
179
141
|
opacity: 0;
|
|
180
|
-
transform: scale(0.9);
|
|
142
|
+
transform: translateY(20px) scale(0.9);
|
|
181
143
|
}
|
|
182
144
|
to {
|
|
183
145
|
opacity: 1;
|
|
184
|
-
transform: scale(1);
|
|
146
|
+
transform: translateY(0px) scale(1);
|
|
185
147
|
}
|
|
186
148
|
}
|
|
187
149
|
|
|
188
150
|
@keyframes closeSearch {
|
|
189
151
|
from {
|
|
190
152
|
opacity: 1;
|
|
191
|
-
transform: scale(1);
|
|
153
|
+
transform: translateY(0px) scale(1);
|
|
192
154
|
}
|
|
193
155
|
50% {
|
|
194
156
|
opacity: 0.3;
|
|
195
157
|
}
|
|
196
158
|
to {
|
|
197
159
|
opacity: 0;
|
|
198
|
-
transform: scale(0.9);
|
|
160
|
+
transform: translateY(20px) scale(0.9);
|
|
199
161
|
}
|
|
200
162
|
}
|
|
201
163
|
|
|
@@ -15,24 +15,20 @@ import {
|
|
|
15
15
|
useSearchLogger,
|
|
16
16
|
} from '../../hooks';
|
|
17
17
|
|
|
18
|
-
import AskNetlify from '../../../../preact/AskNetlify/AskNetlify';
|
|
19
|
-
|
|
20
18
|
import './SearchModal.css';
|
|
21
19
|
|
|
22
20
|
interface Props {
|
|
23
21
|
children: ComponentChildren;
|
|
24
22
|
className?: string;
|
|
25
|
-
debug?: boolean
|
|
23
|
+
debug?: boolean
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
function SearchModal(props: Props = {
|
|
26
|
+
function SearchModal(props: Props = {className: '', children: null, debug: false }) {
|
|
29
27
|
const [isPagefindLoaded, setIsPagefindLoaded] = useState(false);
|
|
30
|
-
const [modalState, setModalState] = useState({ current: 'search' });
|
|
31
|
-
const [askNetlifyQuery, setAskNetlifyQuery] = useState('');
|
|
32
28
|
|
|
33
29
|
// Poll for the existence of window.pagefind.
|
|
34
30
|
useEffect(() => {
|
|
35
|
-
let intervalId:
|
|
31
|
+
let intervalId:number;
|
|
36
32
|
|
|
37
33
|
const checkForPagefind = () => {
|
|
38
34
|
if (window.pagefind) {
|
|
@@ -49,18 +45,19 @@ function SearchModal(props: Props = { className: '', children: null, debug: fals
|
|
|
49
45
|
return () => clearInterval(intervalId);
|
|
50
46
|
}, []);
|
|
51
47
|
|
|
48
|
+
|
|
52
49
|
const { children, className, debug, ...rest } = props;
|
|
53
50
|
const { state, actions } = useSearch();
|
|
54
|
-
|
|
55
51
|
const [searchOpen, setSearchOpen] = useState(false);
|
|
52
|
+
|
|
56
53
|
const openSearch = () => setSearchOpen(true);
|
|
57
54
|
const closeSearch = () => setSearchOpen(false);
|
|
58
55
|
|
|
59
56
|
const modalRef = useRef<HTMLDialogElement>(null);
|
|
60
57
|
const containerRef = useClickOutside<HTMLDivElement>(closeSearch);
|
|
61
58
|
|
|
62
|
-
useSearchLogger(state, debug)
|
|
63
|
-
useSearchToggles(isPagefindLoaded,
|
|
59
|
+
useSearchLogger(state, debug)
|
|
60
|
+
useSearchToggles(isPagefindLoaded, openSearch);
|
|
64
61
|
useSearchParams(isPagefindLoaded, actions.setSearchTerm, openSearch);
|
|
65
62
|
useSearchHotkeys(isPagefindLoaded, searchOpen, openSearch, closeSearch);
|
|
66
63
|
useKeyboardNav(isPagefindLoaded, modalRef, searchOpen, closeSearch);
|
|
@@ -70,58 +67,31 @@ function SearchModal(props: Props = { className: '', children: null, debug: fals
|
|
|
70
67
|
searchOpen ? modalRef.current.showModal() : modalRef.current.close();
|
|
71
68
|
}, [searchOpen]);
|
|
72
69
|
|
|
73
|
-
useEffect(() => {
|
|
74
|
-
const input = modalRef.current?.querySelector('input');
|
|
75
|
-
|
|
76
|
-
if (input) input.focus();
|
|
77
|
-
|
|
78
|
-
if (modalState.current === 'ask') {
|
|
79
|
-
setTimeout(() => {
|
|
80
|
-
modalRef.current.classList.add('n-search-modal-ask');
|
|
81
|
-
}, 150);
|
|
82
|
-
} else if (modalState.current === 'search') {
|
|
83
|
-
setTimeout(() => {
|
|
84
|
-
modalRef.current.classList.remove('n-search-modal-ask');
|
|
85
|
-
}, 150);
|
|
86
|
-
}
|
|
87
|
-
}, [modalState.current]);
|
|
88
|
-
|
|
89
70
|
return (
|
|
90
|
-
<Modal
|
|
91
|
-
ref={modalRef}
|
|
92
|
-
className={`n-search-modal ${className ? className : ''}`}
|
|
93
|
-
data-state={modalState.current}
|
|
94
|
-
{...rest}
|
|
95
|
-
>
|
|
71
|
+
<Modal ref={modalRef} className={`n-search-modal ${className ? className : ''}`} {...rest}>
|
|
96
72
|
<div ref={containerRef} className="n-search-container">
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<KeyboardKey keyNames={['↑', '↓']} />
|
|
120
|
-
to navigate
|
|
121
|
-
</p>
|
|
122
|
-
</div>
|
|
123
|
-
</>
|
|
124
|
-
)}
|
|
73
|
+
<SearchInput setSearchTerm={actions.setSearchTerm} initialValue={state.searchTerm} />
|
|
74
|
+
|
|
75
|
+
<SearchWindow
|
|
76
|
+
searchLoading={state.isLoading}
|
|
77
|
+
searchTerm={state.searchTerm}
|
|
78
|
+
results={state.results}
|
|
79
|
+
>
|
|
80
|
+
{children}
|
|
81
|
+
</SearchWindow>
|
|
82
|
+
|
|
83
|
+
<div className="n-search-footer">
|
|
84
|
+
<p className="n-search-footer-tip">
|
|
85
|
+
<KeyboardKey keyNames={['Esc']} />
|
|
86
|
+
to close
|
|
87
|
+
</p>
|
|
88
|
+
<p className="n-search-footer-tip">
|
|
89
|
+
<KeyboardKey keyNames={['Tab']} />
|
|
90
|
+
<span>or</span>
|
|
91
|
+
<KeyboardKey keyNames={['↑', '↓']} />
|
|
92
|
+
to navigate
|
|
93
|
+
</p>
|
|
94
|
+
</div>
|
|
125
95
|
</div>
|
|
126
96
|
</Modal>
|
|
127
97
|
);
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import type { FunctionComponent } from 'preact';
|
|
2
|
-
import type { SearchResultsProps, SearchWindowProps } from '../types/search.types';
|
|
2
|
+
import type { SearchLinkProps, SearchResultsProps, SearchWindowProps } from '../types/search.types';
|
|
3
3
|
import { useMemo } from 'preact/hooks';
|
|
4
4
|
import SearchHeading from './SearchHeading/SearchHeading';
|
|
5
5
|
import SearchLink from './SearchLink/SearchLink';
|
|
6
6
|
|
|
7
|
-
import { handleThemeChange, ThemeMap, Theme } from '../../../../utils/theme';
|
|
8
|
-
|
|
9
7
|
/* --- Search Results Window (for active searches) --- */
|
|
10
8
|
const SearchResults: FunctionComponent<SearchResultsProps> = ({
|
|
11
9
|
searchLoading,
|
|
@@ -22,9 +20,9 @@ const SearchResults: FunctionComponent<SearchResultsProps> = ({
|
|
|
22
20
|
|
|
23
21
|
if (!results || results.length === 0) {
|
|
24
22
|
return (
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
<SearchHeading>
|
|
24
|
+
0 results for <span className="n-search-term">{searchTerm}</span>
|
|
25
|
+
</SearchHeading>
|
|
28
26
|
);
|
|
29
27
|
}
|
|
30
28
|
|
|
@@ -45,41 +43,29 @@ const SearchResults: FunctionComponent<SearchResultsProps> = ({
|
|
|
45
43
|
|
|
46
44
|
/* --- Main Search Results Component --- */
|
|
47
45
|
export default function SearchWindow({
|
|
48
|
-
setModalState,
|
|
49
46
|
searchLoading,
|
|
50
47
|
searchTerm,
|
|
51
48
|
results,
|
|
52
49
|
children: DefaultWindow,
|
|
53
50
|
}: SearchWindowProps) {
|
|
51
|
+
const askNetlify: SearchLinkProps = {
|
|
52
|
+
icon: 'sparkles',
|
|
53
|
+
label: 'Ask Netlify AI',
|
|
54
|
+
url: 'https://docs.netlify.com/ask-netlify/',
|
|
55
|
+
};
|
|
56
|
+
|
|
54
57
|
return (
|
|
55
58
|
<div className="n-search-window">
|
|
56
|
-
<div className="
|
|
59
|
+
<div className="search-links">
|
|
60
|
+
<SearchLink {...askNetlify} />
|
|
57
61
|
{searchTerm && searchTerm.length > 1 ? (
|
|
58
|
-
<SearchResults
|
|
62
|
+
<SearchResults
|
|
63
|
+
searchLoading={searchLoading}
|
|
64
|
+
searchTerm={searchTerm}
|
|
65
|
+
results={results}
|
|
66
|
+
/>
|
|
59
67
|
) : DefaultWindow ? (
|
|
60
|
-
|
|
61
|
-
<SearchLink
|
|
62
|
-
as="button"
|
|
63
|
-
icon="askNetlify"
|
|
64
|
-
label="Ask Netlify AI"
|
|
65
|
-
onClick={() => {
|
|
66
|
-
setModalState({ current: 'ask' });
|
|
67
|
-
}}
|
|
68
|
-
/>
|
|
69
|
-
|
|
70
|
-
{DefaultWindow}
|
|
71
|
-
|
|
72
|
-
<SearchHeading>Actions</SearchHeading>
|
|
73
|
-
<SearchLink
|
|
74
|
-
as="button"
|
|
75
|
-
icon="lightbulb"
|
|
76
|
-
label="Toggle theme"
|
|
77
|
-
onClick={() => {
|
|
78
|
-
const theme = document.documentElement.getAttribute('data-theme') as Theme;
|
|
79
|
-
theme && handleThemeChange(ThemeMap[theme]);
|
|
80
|
-
}}
|
|
81
|
-
/>
|
|
82
|
-
</>
|
|
68
|
+
DefaultWindow
|
|
83
69
|
) : null}
|
|
84
70
|
</div>
|
|
85
71
|
</div>
|
|
@@ -21,7 +21,7 @@ export function useKeyboardNav(
|
|
|
21
21
|
onClose: () => void
|
|
22
22
|
) {
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
if (!isPagefindLoaded) return
|
|
24
|
+
if (!isPagefindLoaded) return
|
|
25
25
|
const handleKeydown = (e: KeyboardEvent) => {
|
|
26
26
|
if (!isOpen) return;
|
|
27
27
|
|
|
@@ -35,7 +35,7 @@ export function useKeyboardNav(
|
|
|
35
35
|
const container = containerRef.current;
|
|
36
36
|
if (!container) return;
|
|
37
37
|
|
|
38
|
-
const links = Array.from(container.querySelectorAll('
|
|
38
|
+
const links = Array.from(container.querySelectorAll('a'));
|
|
39
39
|
const currentIndex = links.findIndex(link => link === document.activeElement);
|
|
40
40
|
const nextIndex =
|
|
41
41
|
e.key === 'ArrowDown'
|
|
@@ -12,24 +12,16 @@ import { useEffect } from 'preact/hooks';
|
|
|
12
12
|
* @param onOpen - A function to be called when a toggle element is clicked.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
export function useSearchToggles(
|
|
16
|
-
isPagefindLoaded: boolean,
|
|
17
|
-
onOpen: () => void,
|
|
18
|
-
setState: (state: { current: string }) => void
|
|
19
|
-
) {
|
|
15
|
+
export function useSearchToggles(isPagefindLoaded: boolean, onOpen: () => void) {
|
|
20
16
|
useEffect(() => {
|
|
21
|
-
if (!isPagefindLoaded) return
|
|
17
|
+
if (!isPagefindLoaded) return
|
|
22
18
|
const toggles = document.querySelectorAll('[data-ntl-search-toggle]');
|
|
23
19
|
|
|
24
20
|
if (!toggles.length) return;
|
|
25
21
|
|
|
26
22
|
toggles.forEach(t => {
|
|
27
|
-
const current = t.dataset.ntlSearchToggle ? t.dataset.ntlSearchToggle : 'search';
|
|
28
23
|
t.removeAttribute('disabled');
|
|
29
|
-
t.addEventListener('click',
|
|
30
|
-
onOpen();
|
|
31
|
-
setState({ current });
|
|
32
|
-
});
|
|
24
|
+
t.addEventListener('click', onOpen);
|
|
33
25
|
});
|
|
34
26
|
|
|
35
27
|
return () => {
|
|
@@ -2,17 +2,14 @@ import type { ComponentChildren } from 'preact';
|
|
|
2
2
|
import type { IconName } from '../../Icon';
|
|
3
3
|
|
|
4
4
|
export interface SearchLinkProps {
|
|
5
|
-
as?: any;
|
|
6
5
|
icon: IconName;
|
|
7
6
|
label: string;
|
|
8
7
|
resource?: 'blog' | 'changelog' | 'docs' | 'guide';
|
|
9
|
-
url
|
|
8
|
+
url: string;
|
|
10
9
|
excerpt?: string;
|
|
11
|
-
onClick?: () => void;
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export interface SearchWindowProps {
|
|
15
|
-
setModalState: (e: { current: string }) => void;
|
|
16
13
|
searchLoading: boolean;
|
|
17
14
|
searchTerm?: string;
|
|
18
15
|
results?: SearchLinkProps[];
|
|
@@ -36,4 +33,4 @@ export interface SearchGTMObjectProps {
|
|
|
36
33
|
resultUrl?: string;
|
|
37
34
|
query?: string;
|
|
38
35
|
debug_mode?: boolean;
|
|
39
|
-
}
|
|
36
|
+
}
|
|
@@ -4,7 +4,6 @@ export { default as Icon } from './Icon';
|
|
|
4
4
|
export { default as SearchLink } from './SearchModal/components/SearchLink/SearchLink';
|
|
5
5
|
export { default as SearchHeading } from './SearchModal/components/SearchHeading/SearchHeading';
|
|
6
6
|
export { default as SearchToggle } from './SearchModal/components/SearchToggle/SearchToggle';
|
|
7
|
-
export { default as AskNetlify } from "./AskNetlify/AskNetlify"
|
|
8
7
|
export { SearchModal } from './SearchModal';
|
|
9
8
|
|
|
10
9
|
export { type IconName } from './Icon';
|