@chassis-ui/docs 0.3.4 → 0.3.5
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 +1 -1
- package/package.json +1 -1
- package/src/js/search.js +109 -1
- package/src/layouts/header/SearchDialog.astro +4 -0
- package/src/scss/_search.scss +360 -344
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Shared Astro layouts, components, and utilities for Chassis documentation sites.
|
|
4
4
|
|
|
5
|
-
[](https://opensource.org/licenses/MIT) [](https://opensource.org/licenses/MIT) [](https://www.npmjs.com/package/@chassis-ui/docs) [](https://www.npmjs.com/package/@chassis-ui/docs)
|
|
6
6
|
|
|
7
7
|
## Overview
|
|
8
8
|
|
package/package.json
CHANGED
package/src/js/search.js
CHANGED
|
@@ -22,7 +22,74 @@ const LOADING_SKELETON_DELAY_MS = 200
|
|
|
22
22
|
const RECENT_STORAGE_KEY = 'cxd:search:recent'
|
|
23
23
|
const RECENT_LIMIT = 5
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
// ─── Multi-site search ────────────────────────────────────────────────────────
|
|
26
|
+
// Every Chassis project deploys its own Pagefind index under its own path
|
|
27
|
+
// prefix (e.g. `/tokens/pagefind/`), matching the prefix chassis-ui.com's
|
|
28
|
+
// Vercel rewrites proxy that project under (see `ref/VERCEL_CONFIG.md`).
|
|
29
|
+
// This lets one shared instance merge every project's index into a single,
|
|
30
|
+
// site-filterable search — no cross-origin requests required, since
|
|
31
|
+
// `chassis-ui.com/<slug>/...` and `<slug>.vercel.app/<slug>/...` both resolve
|
|
32
|
+
// the same root-relative bundle path.
|
|
33
|
+
|
|
34
|
+
/** All Chassis projects with their own Pagefind index, in nav order. `website` is the hub (root-level index, no path prefix). */
|
|
35
|
+
const CHASSIS_SITES = [
|
|
36
|
+
{ slug: 'website', label: 'Website' },
|
|
37
|
+
{ slug: 'tokens', label: 'Tokens' },
|
|
38
|
+
{ slug: 'css', label: 'CSS' },
|
|
39
|
+
{ slug: 'assets', label: 'Assets' },
|
|
40
|
+
{ slug: 'icons', label: 'Icons' },
|
|
41
|
+
{ slug: 'figma', label: 'Figma' }
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
// Hosts where every project's index is reachable at its root-relative bundle
|
|
45
|
+
// path via Vercel's proxy rewrites. Everywhere else (local dev, direct
|
|
46
|
+
// `*.vercel.app` preview deployments) only this site's own pages exist, so
|
|
47
|
+
// merging would 404. Pagefind has no built-in resilience for a failed
|
|
48
|
+
// `mergeIndex` call — it throws and takes the whole search down with it — so
|
|
49
|
+
// merging is only attempted on these hosts.
|
|
50
|
+
const CANONICAL_HOSTS = new Set(['chassis-ui.com', 'staging.chassis-ui.com'])
|
|
51
|
+
|
|
52
|
+
const getBundlePath = (slug) => (slug === 'website' ? '/pagefind/' : `/${slug}/pagefind/`)
|
|
53
|
+
|
|
54
|
+
const getCurrentSite = () => {
|
|
55
|
+
const [, firstSegment] = typeof location === 'undefined' ? [] : location.pathname.split('/')
|
|
56
|
+
return CHASSIS_SITES.find((site) => site.slug === firstSegment) ?? CHASSIS_SITES[0]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const isCanonicalHost = () =>
|
|
60
|
+
typeof location !== 'undefined' && CANONICAL_HOSTS.has(location.hostname)
|
|
61
|
+
|
|
62
|
+
const currentSite = getCurrentSite()
|
|
63
|
+
|
|
64
|
+
// Pagefind derives `baseUrl` from `bundlePath` by stripping the trailing
|
|
65
|
+
// `pagefind` segment (e.g. `/tokens/pagefind/` -> `/tokens/`), then prepends
|
|
66
|
+
// that to every result's raw URL. Those raw URLs are already site-root-relative
|
|
67
|
+
// (e.g. `tokens/docs/...`, because that's where the page actually lives inside
|
|
68
|
+
// `_site`), so the auto-derived baseUrl would double up the prefix into
|
|
69
|
+
// `/tokens/tokens/docs/...`. Force it back to `/` for every index.
|
|
70
|
+
const BASE_URL = '/'
|
|
71
|
+
|
|
72
|
+
const mergeIndex = isCanonicalHost()
|
|
73
|
+
? CHASSIS_SITES.filter((site) => site.slug !== currentSite.slug).map((site) => ({
|
|
74
|
+
bundlePath: getBundlePath(site.slug),
|
|
75
|
+
baseUrl: BASE_URL,
|
|
76
|
+
mergeFilter: { site: site.slug }
|
|
77
|
+
}))
|
|
78
|
+
: []
|
|
79
|
+
|
|
80
|
+
const instance = getInstanceManager().getInstance('default', {
|
|
81
|
+
bundlePath: getBundlePath(currentSite.slug),
|
|
82
|
+
baseUrl: BASE_URL,
|
|
83
|
+
mergeFilter: { site: currentSite.slug },
|
|
84
|
+
mergeIndex
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
// Default filter scope: the website (hub) defaults to searching everywhere;
|
|
88
|
+
// every project site defaults to its own results, but can still be widened
|
|
89
|
+
// or switched via the `cxd-search-filter` control.
|
|
90
|
+
if (currentSite.slug !== 'website') {
|
|
91
|
+
instance.searchFilters = { site: currentSite.slug }
|
|
92
|
+
}
|
|
26
93
|
|
|
27
94
|
// ─── Recent visits ────────────────────────────────────────────────────────────
|
|
28
95
|
// Opt-out via Do Not Track; silently no-op when storage is unavailable.
|
|
@@ -368,6 +435,44 @@ class CxdSearchResults extends HTMLElement {
|
|
|
368
435
|
}
|
|
369
436
|
}
|
|
370
437
|
|
|
438
|
+
// ─── Site filter ──────────────────────────────────────────────────────────────
|
|
439
|
+
// Dropdown letting the visitor scope results to a single project, or back out
|
|
440
|
+
// to "Everywhere". Only rendered when other sites were actually merged in
|
|
441
|
+
// (see `mergeIndex` above) — with a single, un-merged index there's nothing
|
|
442
|
+
// meaningful to filter.
|
|
443
|
+
|
|
444
|
+
const FILTER_OPTIONS = [{ slug: '', label: 'Everywhere' }, ...CHASSIS_SITES]
|
|
445
|
+
|
|
446
|
+
class CxdSearchFilter extends HTMLElement {
|
|
447
|
+
connectedCallback() {
|
|
448
|
+
this.select = this.querySelector('select')
|
|
449
|
+
if (!this.select) return
|
|
450
|
+
|
|
451
|
+
// Always rendered — even outside merging (local dev, direct preview
|
|
452
|
+
// deployments) the current site's own results are tagged with `site`, so
|
|
453
|
+
// "Everywhere" and the current site both work; switching to a *different*
|
|
454
|
+
// site just yields no results until it's actually merged in.
|
|
455
|
+
this.hidden = false
|
|
456
|
+
|
|
457
|
+
this.select.innerHTML = FILTER_OPTIONS.map(
|
|
458
|
+
(option) => `<option value="${option.slug}">${escapeHtml(option.label)}</option>`
|
|
459
|
+
).join('')
|
|
460
|
+
this.select.value = currentSite.slug === 'website' ? '' : currentSite.slug
|
|
461
|
+
|
|
462
|
+
this._onChange = this._onChange.bind(this)
|
|
463
|
+
this.select.addEventListener('change', this._onChange)
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
disconnectedCallback() {
|
|
467
|
+
this.select?.removeEventListener('change', this._onChange)
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
_onChange() {
|
|
471
|
+
const value = this.select.value
|
|
472
|
+
instance.triggerSearchWithFilters(instance.searchTerm, value ? { site: value } : {})
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
371
476
|
// ─── Registration ─────────────────────────────────────────────────────────────
|
|
372
477
|
|
|
373
478
|
const defineSearchCustomElements = () => {
|
|
@@ -377,6 +482,9 @@ const defineSearchCustomElements = () => {
|
|
|
377
482
|
if (!customElements.get('cxd-search-results')) {
|
|
378
483
|
customElements.define('cxd-search-results', CxdSearchResults)
|
|
379
484
|
}
|
|
485
|
+
if (!customElements.get('cxd-search-filter')) {
|
|
486
|
+
customElements.define('cxd-search-filter', CxdSearchFilter)
|
|
487
|
+
}
|
|
380
488
|
}
|
|
381
489
|
|
|
382
490
|
// ─── Trigger shortcut hints ───────────────────────────────────────────────────
|
|
@@ -44,6 +44,10 @@ const { id = 'cxdSearchDialog', placeholder = 'Search docs…' } = Astro.props
|
|
|
44
44
|
/>
|
|
45
45
|
</div>
|
|
46
46
|
</cxd-search-input>
|
|
47
|
+
<cxd-search-filter class="cxd-search-filter" hidden>
|
|
48
|
+
<label class="visually-hidden" for={`${id}-filter`}>Search in</label>
|
|
49
|
+
<select id={`${id}-filter`} class="form-input cxd-search-filter-select"></select>
|
|
50
|
+
</cxd-search-filter>
|
|
47
51
|
<button
|
|
48
52
|
type="button"
|
|
49
53
|
class="close-button"
|
package/src/scss/_search.scss
CHANGED
|
@@ -1,418 +1,434 @@
|
|
|
1
1
|
@use "@chassis-ui/css/scss/mixins" as *;
|
|
2
2
|
@use "@chassis-ui/css/scss/placeholders" as *;
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
@layer custom {
|
|
5
|
+
//
|
|
6
|
+
// Pagefind search UI
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
.cxd-search {
|
|
10
|
+
position: relative;
|
|
11
|
+
|
|
12
|
+
@include media-breakpoint-up(large) {
|
|
13
|
+
position: absolute;
|
|
14
|
+
top: 20%;
|
|
15
|
+
right: 13rem;
|
|
16
|
+
width: 200px;
|
|
17
|
+
|
|
18
|
+
[dir="rtl"] & {
|
|
19
|
+
right: auto;
|
|
20
|
+
left: 13rem;
|
|
21
|
+
}
|
|
20
22
|
}
|
|
23
|
+
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
}
|
|
24
26
|
|
|
27
|
+
// Trigger button
|
|
28
|
+
//
|
|
29
|
+
// Mobile (< md): icon-only, no chrome.
|
|
30
|
+
// md+: expands to a faux input with label and ⌘K shortcut hint.
|
|
25
31
|
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
cursor: pointer;
|
|
47
|
-
background-color: transparent;
|
|
48
|
-
border: 0;
|
|
49
|
-
@include border-radius(var(--cx-border-radius-medium));
|
|
50
|
-
@include transition(color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out);
|
|
51
|
-
|
|
52
|
-
&:focus-visible {
|
|
53
|
-
@include focus-ring(true);
|
|
54
|
-
}
|
|
32
|
+
.cxd-search-trigger {
|
|
33
|
+
// @extend %form-input;
|
|
34
|
+
--cx-padding-x: var(--cx-space-xsmall);
|
|
35
|
+
--cx-padding-y: .375rem;
|
|
36
|
+
--cx-icon-color: var(--cx-fg-color);
|
|
37
|
+
display: inline-flex;
|
|
38
|
+
gap: .5rem;
|
|
39
|
+
align-items: center;
|
|
40
|
+
margin-block: .125rem;
|
|
41
|
+
// padding-inline-end: .5rem;
|
|
42
|
+
// padding: .25rem .5rem;
|
|
43
|
+
@include exclude-strokes(form-input);
|
|
44
|
+
@include font-size(var(--cx-font-size-small));
|
|
45
|
+
color: var(--cx-fg-subtle);
|
|
46
|
+
text-align: start;
|
|
47
|
+
cursor: pointer;
|
|
48
|
+
background-color: transparent;
|
|
49
|
+
border: 0;
|
|
50
|
+
@include border-radius(var(--cx-border-radius-medium));
|
|
51
|
+
@include transition(color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out);
|
|
55
52
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
--cx-icon-color: var(--cx-fg-subtle);
|
|
60
|
-
width: 100%;
|
|
61
|
-
background-color: var(--cx-bg-main);
|
|
62
|
-
@include border();
|
|
53
|
+
&:focus-visible {
|
|
54
|
+
@include focus-ring(true);
|
|
55
|
+
}
|
|
63
56
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
--cx-icon-
|
|
67
|
-
--cx-
|
|
57
|
+
@include media-breakpoint-up(large) {
|
|
58
|
+
--cx-border-color: var(--cx-border-subtle);
|
|
59
|
+
--cx-icon-size: var(--cx-icon-small);
|
|
60
|
+
--cx-icon-color: var(--cx-fg-subtle);
|
|
61
|
+
width: 100%;
|
|
62
|
+
background-color: var(--cx-bg-main);
|
|
63
|
+
@include border();
|
|
64
|
+
|
|
65
|
+
&:hover {
|
|
66
|
+
// --fg-color: var(--cx-fg-main);
|
|
67
|
+
--cx-icon-color: var(--cx-fg-color);
|
|
68
|
+
--cx-border-color: var(--cx-border-main);
|
|
69
|
+
}
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
|
-
}
|
|
71
72
|
|
|
72
|
-
.cxd-search-trigger-icon {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
73
|
+
.cxd-search-trigger-icon {
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
color: var(--cx-fg-subtle);
|
|
76
|
+
}
|
|
76
77
|
|
|
77
|
-
.cxd-search-trigger-label,
|
|
78
|
-
.cxd-search-trigger-shortcut {
|
|
79
|
-
|
|
78
|
+
.cxd-search-trigger-label,
|
|
79
|
+
.cxd-search-trigger-shortcut {
|
|
80
|
+
display: none;
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
82
|
+
@include media-breakpoint-up(large) {
|
|
83
|
+
display: inline-flex;
|
|
84
|
+
}
|
|
83
85
|
}
|
|
84
|
-
}
|
|
85
86
|
|
|
86
|
-
.cxd-search-trigger-label {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
87
|
+
.cxd-search-trigger-label {
|
|
88
|
+
flex: 1;
|
|
89
|
+
overflow: hidden;
|
|
90
|
+
text-overflow: ellipsis;
|
|
91
|
+
white-space: nowrap;
|
|
92
|
+
}
|
|
92
93
|
|
|
93
|
-
.cxd-search-trigger-shortcut {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
94
|
+
.cxd-search-trigger-shortcut {
|
|
95
|
+
flex-shrink: 0;
|
|
96
|
+
gap: .125rem;
|
|
97
|
+
}
|
|
97
98
|
|
|
98
|
-
.cxd-search-trigger-key {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
99
|
+
.cxd-search-trigger-key {
|
|
100
|
+
display: inline-flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
min-width: 1.25rem;
|
|
104
|
+
padding: .125rem .375rem;
|
|
105
|
+
font-family: var(--cx-font-family-code);
|
|
106
|
+
@include font-size(var(--cx-font-size-small));
|
|
107
|
+
@include line-height(var(--cx-line-height-small));
|
|
108
|
+
color: var(--cx-fg-subtle);
|
|
109
|
+
background-color: var(--cx-bg-evident);
|
|
110
|
+
// border: var(--cx-border-width) solid var(--cx-border-color);
|
|
111
|
+
@include border-radius(var(--cx-border-radius-small));
|
|
112
|
+
}
|
|
112
113
|
|
|
113
|
-
// Search dialog shell
|
|
114
|
-
//
|
|
115
|
-
// Top-aligned overlay using the existing `.dialog` surface.
|
|
116
|
-
// Sizing and position make it feel like a command palette.
|
|
114
|
+
// Search dialog shell
|
|
115
|
+
//
|
|
116
|
+
// Top-aligned overlay using the existing `.dialog` surface.
|
|
117
|
+
// Sizing and position make it feel like a command palette.
|
|
118
|
+
|
|
119
|
+
.cxd-search-dialog {
|
|
120
|
+
--cx-dialog-margin: 1.5rem;
|
|
121
|
+
--cx-dialog-padding: .75rem;
|
|
122
|
+
--cx-dialog-header-padding: .75rem;
|
|
123
|
+
--cx-dialog-footer-padding: .5rem .75rem;
|
|
124
|
+
--cx-dialog-border-radius: var(--cx-border-radius-large);
|
|
125
|
+
|
|
126
|
+
align-self: flex-start;
|
|
127
|
+
width: 640px;
|
|
128
|
+
max-height: min(80dvh, 720px);
|
|
129
|
+
margin-block-start: 3rem;
|
|
130
|
+
overflow: hidden;
|
|
131
|
+
background-color: var(--cx-bg-even);
|
|
132
|
+
|
|
133
|
+
@include media-breakpoint-down(small) {
|
|
134
|
+
max-height: calc(100dvh - 4rem);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
117
137
|
|
|
118
|
-
|
|
119
|
-
--cx-dialog-margin: 1.5rem;
|
|
120
|
-
--cx-dialog-padding: .75rem;
|
|
121
|
-
--cx-dialog-header-padding: .75rem;
|
|
122
|
-
--cx-dialog-footer-padding: .5rem .75rem;
|
|
123
|
-
--cx-dialog-border-radius: var(--cx-border-radius-large);
|
|
138
|
+
// Header / search form
|
|
124
139
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
140
|
+
.cxd-search-form {
|
|
141
|
+
display: flex;
|
|
142
|
+
flex-wrap: nowrap;
|
|
143
|
+
gap: .75rem;
|
|
144
|
+
align-items: center;
|
|
145
|
+
padding: var(--cx-space-medium);
|
|
146
|
+
border-bottom: 0;
|
|
147
|
+
}
|
|
131
148
|
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
cxd-search-input {
|
|
150
|
+
flex-grow: 1;
|
|
134
151
|
}
|
|
135
|
-
}
|
|
136
152
|
|
|
137
|
-
//
|
|
153
|
+
// Site filter dropdown — only shown when other project indexes were merged
|
|
154
|
+
// in (see `search.js`), letting the visitor scope results to one project or
|
|
155
|
+
// back out to "Everywhere".
|
|
156
|
+
.cxd-search-filter {
|
|
157
|
+
flex-shrink: 0;
|
|
158
|
+
}
|
|
138
159
|
|
|
139
|
-
.cxd-search-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
160
|
+
// .cxd-search-filter-select {
|
|
161
|
+
// --cx-padding-y: .375rem;
|
|
162
|
+
// --cx-padding-x: .5rem;
|
|
163
|
+
// width: auto;
|
|
164
|
+
// @include font-size(var(--cx-font-size-small));
|
|
165
|
+
// }
|
|
166
|
+
// .cxd-search-input {
|
|
167
|
+
// flex: 1;
|
|
168
|
+
// width: 100%;
|
|
169
|
+
// min-width: 0;
|
|
170
|
+
// background-color: transparent;
|
|
171
|
+
// border-color: transparent;
|
|
172
|
+
// box-shadow: none;
|
|
173
|
+
|
|
174
|
+
// &:focus {
|
|
175
|
+
// background-color: transparent;
|
|
176
|
+
// border-color: transparent;
|
|
177
|
+
// box-shadow: none;
|
|
178
|
+
// }
|
|
179
|
+
// }
|
|
147
180
|
|
|
148
|
-
cxd-search-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
//
|
|
152
|
-
// flex: 1;
|
|
153
|
-
// width: 100%;
|
|
154
|
-
// min-width: 0;
|
|
155
|
-
// background-color: transparent;
|
|
156
|
-
// border-color: transparent;
|
|
157
|
-
// box-shadow: none;
|
|
158
|
-
|
|
159
|
-
// &:focus {
|
|
160
|
-
// background-color: transparent;
|
|
161
|
-
// border-color: transparent;
|
|
162
|
-
// box-shadow: none;
|
|
163
|
-
// }
|
|
164
|
-
// }
|
|
165
|
-
|
|
166
|
-
// .cxd-search-close {
|
|
167
|
-
// flex-shrink: 0;
|
|
168
|
-
// margin-inline-start: 0;
|
|
169
|
-
// }
|
|
170
|
-
|
|
171
|
-
// Body / results
|
|
172
|
-
|
|
173
|
-
.cxd-search-body {
|
|
174
|
-
padding: 0 var(--cx-space-medium) var(--cx-space-medium);
|
|
175
|
-
}
|
|
181
|
+
// .cxd-search-close {
|
|
182
|
+
// flex-shrink: 0;
|
|
183
|
+
// margin-inline-start: 0;
|
|
184
|
+
// }
|
|
176
185
|
|
|
177
|
-
|
|
178
|
-
display: block;
|
|
179
|
-
min-height: 6rem;
|
|
180
|
-
border: 0;
|
|
181
|
-
}
|
|
186
|
+
// Body / results
|
|
182
187
|
|
|
183
|
-
.cxd-search-
|
|
184
|
-
|
|
185
|
-
|
|
188
|
+
.cxd-search-body {
|
|
189
|
+
padding: 0 var(--cx-space-medium) var(--cx-space-medium);
|
|
190
|
+
}
|
|
186
191
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
.list-item {
|
|
191
|
-
padding: 0;
|
|
192
|
+
.cxd-search-results {
|
|
193
|
+
display: block;
|
|
194
|
+
min-height: 6rem;
|
|
192
195
|
border: 0;
|
|
193
196
|
}
|
|
194
|
-
}
|
|
195
197
|
|
|
196
|
-
.cxd-search-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// gap: var(--cx-space-xsmall);
|
|
200
|
-
gap: 0;
|
|
201
|
-
padding: 0;
|
|
202
|
-
}
|
|
198
|
+
.cxd-search-results-list {
|
|
199
|
+
// --cx-list-border-width: 0;
|
|
200
|
+
// --cx-list-border-radius: 0;
|
|
203
201
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
// Single row template: top-level results, sub-results, and recent visits.
|
|
214
|
-
.cxd-search-item {
|
|
215
|
-
--cx-icon-size: var(--cx-icon-medium);
|
|
216
|
-
--cx-icon-color: var(--cx-fg-subtle);
|
|
217
|
-
position: relative;
|
|
218
|
-
display: grid;
|
|
219
|
-
grid-template-columns: auto 1fr;
|
|
220
|
-
column-gap: .5rem;
|
|
221
|
-
align-items: center;
|
|
222
|
-
padding: var(--cx-space-xsmall);
|
|
223
|
-
text-decoration: none;
|
|
224
|
-
background-color: var(--cx-bg-main);
|
|
225
|
-
@include border();
|
|
226
|
-
@include border-radius(var(--cx-border-radius-medium));
|
|
227
|
-
|
|
228
|
-
mark {
|
|
229
|
-
background: none;
|
|
202
|
+
gap: var(--cx-space-small);
|
|
203
|
+
padding-block-start: var(--cx-space-xsmall);
|
|
204
|
+
list-style: none;
|
|
205
|
+
.list-item {
|
|
206
|
+
padding: 0;
|
|
207
|
+
border: 0;
|
|
208
|
+
}
|
|
230
209
|
}
|
|
231
210
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
211
|
+
.cxd-search-result {
|
|
212
|
+
display: flex;
|
|
213
|
+
flex-direction: column;
|
|
214
|
+
// gap: var(--cx-space-xsmall);
|
|
215
|
+
gap: 0;
|
|
216
|
+
padding: 0;
|
|
235
217
|
}
|
|
236
218
|
|
|
237
|
-
|
|
219
|
+
// Default-active state: while focus is in the search input, the first result
|
|
220
|
+
// is highlighted as the Enter target. Once the user arrows into the list,
|
|
221
|
+
// :focus-within takes over.
|
|
222
|
+
.cxd-search-results:not(:focus-within) .cxd-search-result:first-child > .cxd-search-item {
|
|
223
|
+
@include focus-ring(true);
|
|
224
|
+
--cx-focus-ring-offset: -2px;
|
|
238
225
|
background-color: var(--cx-bg-main);
|
|
239
226
|
}
|
|
240
227
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
228
|
+
// Single row template: top-level results, sub-results, and recent visits.
|
|
229
|
+
.cxd-search-item {
|
|
230
|
+
--cx-icon-size: var(--cx-icon-medium);
|
|
231
|
+
--cx-icon-color: var(--cx-fg-subtle);
|
|
232
|
+
position: relative;
|
|
233
|
+
display: grid;
|
|
234
|
+
grid-template-columns: auto 1fr;
|
|
235
|
+
column-gap: .5rem;
|
|
236
|
+
align-items: center;
|
|
237
|
+
padding: var(--cx-space-xsmall);
|
|
238
|
+
text-decoration: none;
|
|
239
|
+
background-color: var(--cx-bg-main);
|
|
240
|
+
@include border();
|
|
241
|
+
@include border-radius(var(--cx-border-radius-medium));
|
|
246
242
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
}
|
|
243
|
+
mark {
|
|
244
|
+
background: none;
|
|
245
|
+
}
|
|
251
246
|
|
|
252
|
-
.cxd-search-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
}
|
|
247
|
+
&:has(+ .cxd-search-subresults) {
|
|
248
|
+
border-block-end-width: 0;
|
|
249
|
+
@include border-bottom-radius(0);
|
|
250
|
+
}
|
|
256
251
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
252
|
+
&:hover {
|
|
253
|
+
background-color: var(--cx-bg-main);
|
|
254
|
+
}
|
|
261
255
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
256
|
+
&:focus-visible {
|
|
257
|
+
--cx-focus-ring-offset: -2px;
|
|
258
|
+
z-index: 1;
|
|
259
|
+
@include focus-ring(true);
|
|
260
|
+
}
|
|
266
261
|
|
|
267
|
-
.cxd-search-item-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
262
|
+
// &:not(.cxd-search-item-sub) {
|
|
263
|
+
// border: var(--cx-border-width) solid var(--cx-border-color);
|
|
264
|
+
// }
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.cxd-search-item-icon {
|
|
268
|
+
// margin-block-start: .15rem;
|
|
269
|
+
color: var(--cx-fg-subtle);
|
|
270
|
+
}
|
|
275
271
|
|
|
276
|
-
.cxd-search-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
align-items: center;
|
|
280
|
-
padding-inline-start: var(--cx-space-4xlarge);
|
|
281
|
-
// padding-inline-start: var(--cx-space-medium);
|
|
282
|
-
|
|
283
|
-
&::before {
|
|
284
|
-
position: absolute;
|
|
285
|
-
inset-block: 15%;
|
|
286
|
-
inset-inline: 0;
|
|
287
|
-
width: var(--cx-border-width);
|
|
288
|
-
height: 70%;
|
|
289
|
-
margin-inline-start: 1.25rem;
|
|
290
|
-
content: " ";
|
|
291
|
-
background-color: var(--cx-fg-subtle);
|
|
292
|
-
}
|
|
293
|
-
&::after {
|
|
294
|
-
position: absolute;
|
|
295
|
-
inset: 0;
|
|
296
|
-
width: .75rem;
|
|
297
|
-
height: var(--cx-border-width);
|
|
298
|
-
margin-block: auto;
|
|
299
|
-
margin-inline-start: 1.25rem;
|
|
300
|
-
content: " ";
|
|
301
|
-
background-color: var(--cx-fg-subtle);
|
|
272
|
+
.cxd-search-item-body {
|
|
273
|
+
grid-column: 2;
|
|
274
|
+
min-width: 0;
|
|
302
275
|
}
|
|
276
|
+
|
|
303
277
|
.cxd-search-item-title {
|
|
278
|
+
font-weight: var(--cx-font-weight-strong);
|
|
279
|
+
color: var(--cx-fg-main);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.cxd-search-item-excerpt {
|
|
283
|
+
overflow: hidden;
|
|
284
|
+
color: var(--cx-fg-subtle);
|
|
285
|
+
text-overflow: ellipsis;
|
|
286
|
+
white-space: nowrap;
|
|
304
287
|
@include font-size(var(--cx-font-size-small));
|
|
305
288
|
@include line-height(var(--cx-line-height-small));
|
|
306
289
|
}
|
|
307
290
|
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
.cxd-search-subresults {
|
|
311
|
-
display: flex;
|
|
312
|
-
flex-direction: column;
|
|
313
|
-
// gap: var(--cx-space-xsmall);
|
|
314
|
-
gap: 0;
|
|
315
|
-
// padding-inline-start: var(--cx-space-large);
|
|
316
291
|
.cxd-search-subitem {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
292
|
+
--cx-icon-size: var(--cx-icon-small);
|
|
293
|
+
--cx-icon-color: var(--cx-fg-subtle);
|
|
294
|
+
align-items: center;
|
|
295
|
+
padding-inline-start: var(--cx-space-4xlarge);
|
|
296
|
+
// padding-inline-start: var(--cx-space-medium);
|
|
297
|
+
|
|
298
|
+
&::before {
|
|
299
|
+
position: absolute;
|
|
300
|
+
inset-block: 15%;
|
|
301
|
+
inset-inline: 0;
|
|
302
|
+
width: var(--cx-border-width);
|
|
303
|
+
height: 70%;
|
|
304
|
+
margin-inline-start: 1.25rem;
|
|
305
|
+
content: " ";
|
|
306
|
+
background-color: var(--cx-fg-subtle);
|
|
307
|
+
}
|
|
308
|
+
&::after {
|
|
309
|
+
position: absolute;
|
|
310
|
+
inset: 0;
|
|
311
|
+
width: .75rem;
|
|
312
|
+
height: var(--cx-border-width);
|
|
313
|
+
margin-block: auto;
|
|
314
|
+
margin-inline-start: 1.25rem;
|
|
315
|
+
content: " ";
|
|
316
|
+
background-color: var(--cx-fg-subtle);
|
|
317
|
+
}
|
|
318
|
+
.cxd-search-item-title {
|
|
319
|
+
@include font-size(var(--cx-font-size-small));
|
|
320
|
+
@include line-height(var(--cx-line-height-small));
|
|
325
321
|
}
|
|
326
322
|
|
|
327
323
|
}
|
|
328
|
-
}
|
|
329
324
|
|
|
330
|
-
|
|
325
|
+
.cxd-search-subresults {
|
|
326
|
+
display: flex;
|
|
327
|
+
flex-direction: column;
|
|
328
|
+
// gap: var(--cx-space-xsmall);
|
|
329
|
+
gap: 0;
|
|
330
|
+
// padding-inline-start: var(--cx-space-large);
|
|
331
|
+
.cxd-search-subitem {
|
|
332
|
+
border-block-end-width: 0;
|
|
333
|
+
@include border-radius(0);
|
|
334
|
+
&:is(:last-child > .cxd-search-subitem) {
|
|
335
|
+
border-block-end-width: var(--cx-border-width);
|
|
336
|
+
@include border-bottom-radius(var(--cx-border-radius));
|
|
337
|
+
&::before {
|
|
338
|
+
height: 35%;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
331
341
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
gap: .5rem;
|
|
335
|
-
align-items: center;
|
|
336
|
-
justify-content: space-between;
|
|
337
|
-
padding-block: .5rem;
|
|
338
|
-
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
339
344
|
|
|
340
|
-
|
|
341
|
-
@include font-size(var(--cx-font-size-xsmall));
|
|
342
|
-
font-weight: 600;
|
|
343
|
-
color: var(--cx-fg-subtle);
|
|
344
|
-
text-transform: uppercase;
|
|
345
|
-
letter-spacing: .04em;
|
|
346
|
-
}
|
|
345
|
+
// Recently visited
|
|
347
346
|
|
|
348
|
-
.cxd-search-recent-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
border: 0;
|
|
355
|
-
@include border-radius(var(--cx-border-radius-medium));
|
|
356
|
-
@include transition(color .15s ease-in-out, background-color .15s ease-in-out);
|
|
357
|
-
|
|
358
|
-
&:hover {
|
|
359
|
-
color: var(--cx-fg-main);
|
|
360
|
-
background-color: var(--cx-bg-main);
|
|
347
|
+
.cxd-search-recent-header {
|
|
348
|
+
display: flex;
|
|
349
|
+
gap: .5rem;
|
|
350
|
+
align-items: center;
|
|
351
|
+
justify-content: space-between;
|
|
352
|
+
padding-block: .5rem;
|
|
361
353
|
}
|
|
362
354
|
|
|
363
|
-
|
|
364
|
-
@include
|
|
355
|
+
.cxd-search-recent-label {
|
|
356
|
+
@include font-size(var(--cx-font-size-xsmall));
|
|
357
|
+
font-weight: 600;
|
|
358
|
+
color: var(--cx-fg-subtle);
|
|
359
|
+
text-transform: uppercase;
|
|
360
|
+
letter-spacing: .04em;
|
|
365
361
|
}
|
|
366
|
-
}
|
|
367
362
|
|
|
368
|
-
|
|
363
|
+
.cxd-search-recent-clear {
|
|
364
|
+
padding: .125rem .375rem;
|
|
365
|
+
@include font-size(var(--cx-font-size-xsmall));
|
|
366
|
+
color: var(--cx-fg-subtle);
|
|
367
|
+
cursor: pointer;
|
|
368
|
+
background-color: transparent;
|
|
369
|
+
border: 0;
|
|
370
|
+
@include border-radius(var(--cx-border-radius-medium));
|
|
371
|
+
@include transition(color .15s ease-in-out, background-color .15s ease-in-out);
|
|
369
372
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
color: var(--cx-fg-subtle);
|
|
375
|
-
text-align: center;
|
|
376
|
-
}
|
|
373
|
+
&:hover {
|
|
374
|
+
color: var(--cx-fg-main);
|
|
375
|
+
background-color: var(--cx-bg-main);
|
|
376
|
+
}
|
|
377
377
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
378
|
+
&:focus-visible {
|
|
379
|
+
@include focus-ring(true);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
381
382
|
|
|
382
|
-
|
|
383
|
-
display: flex;
|
|
384
|
-
flex-direction: column;
|
|
385
|
-
gap: var(--cx-space-small);
|
|
386
|
-
}
|
|
383
|
+
// Empty / loading / error states
|
|
387
384
|
|
|
385
|
+
.cxd-search-empty,
|
|
386
|
+
.cxd-search-error {
|
|
387
|
+
padding: 2rem 1rem;
|
|
388
|
+
@include font-size(var(--cx-font-size-small));
|
|
389
|
+
color: var(--cx-fg-subtle);
|
|
390
|
+
text-align: center;
|
|
391
|
+
}
|
|
388
392
|
|
|
389
|
-
.cxd-search-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
}
|
|
393
|
+
.cxd-search-error {
|
|
394
|
+
color: var(--cx-danger-fg-main);
|
|
395
|
+
}
|
|
393
396
|
|
|
394
|
-
.cxd-search-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
color: var(--cx-fg-subtle);
|
|
400
|
-
background: none;
|
|
401
|
-
border: 0;
|
|
402
|
-
}
|
|
397
|
+
.cxd-search-loading {
|
|
398
|
+
display: flex;
|
|
399
|
+
flex-direction: column;
|
|
400
|
+
gap: var(--cx-space-small);
|
|
401
|
+
}
|
|
403
402
|
|
|
404
|
-
.cxd-search-shortcut-key {
|
|
405
|
-
display: inline-flex;
|
|
406
|
-
align-items: center;
|
|
407
|
-
justify-content: center;
|
|
408
|
-
min-width: 1.25rem;
|
|
409
|
-
min-height: 1.25rem;
|
|
410
|
-
padding: 0 .25rem;
|
|
411
|
-
background-color: var(--cx-bg-main);
|
|
412
|
-
}
|
|
413
403
|
|
|
414
|
-
.cxd-search-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
404
|
+
.cxd-search-footer {
|
|
405
|
+
padding-block: var(--cx-space-small);
|
|
406
|
+
background-color: var(--cx-bg-evident);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.cxd-search-shortcuts-list > .list-item {
|
|
410
|
+
display: inline-flex;
|
|
411
|
+
gap: .25rem;
|
|
412
|
+
align-items: center;
|
|
413
|
+
padding: 0 .5rem;
|
|
414
|
+
color: var(--cx-fg-subtle);
|
|
415
|
+
background: none;
|
|
416
|
+
border: 0;
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.cxd-search-shortcut-key {
|
|
420
|
+
display: inline-flex;
|
|
421
|
+
align-items: center;
|
|
422
|
+
justify-content: center;
|
|
423
|
+
min-width: 1.25rem;
|
|
424
|
+
min-height: 1.25rem;
|
|
425
|
+
padding: 0 .25rem;
|
|
426
|
+
background-color: var(--cx-bg-main);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.cxd-search-shortcut-label {
|
|
430
|
+
padding-inline-start: .25rem;
|
|
431
|
+
@include font-size(var(--cx-font-size-small));
|
|
432
|
+
@include line-height(var(--cx-line-height-small));
|
|
433
|
+
}
|
|
418
434
|
}
|