feat(search): add global search across wiki entities
Implement /api/search endpoint for cross-entity querying Add GlobalSearch component to top navigation bar with categorized results
This commit is contained in:
@@ -159,6 +159,190 @@ svg {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.site-topbar__search {
|
||||
flex: 0 1 520px;
|
||||
}
|
||||
|
||||
.global-search {
|
||||
position: relative;
|
||||
min-width: 220px;
|
||||
}
|
||||
|
||||
.global-search__toggle {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.global-search__form {
|
||||
min-height: 44px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
border: 2px solid var(--line);
|
||||
border-radius: var(--radius-control);
|
||||
background: var(--surface);
|
||||
box-shadow: 0 3px 0 var(--line-strong);
|
||||
padding: 0 10px;
|
||||
transition:
|
||||
border-color 0.14s ease,
|
||||
box-shadow 0.14s ease;
|
||||
}
|
||||
|
||||
.global-search__form:focus-within {
|
||||
border-color: var(--pokemon-blue);
|
||||
box-shadow: 0 3px 0 var(--pokemon-blue-deep);
|
||||
}
|
||||
|
||||
.global-search__form-icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.global-search__input {
|
||||
min-width: 0;
|
||||
width: 100%;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background: transparent;
|
||||
color: var(--ink);
|
||||
font-size: 0.94rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.global-search__input::placeholder {
|
||||
color: var(--muted);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.global-search__clear {
|
||||
width: 30px;
|
||||
min-width: 30px;
|
||||
min-height: 30px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
border-radius: var(--radius-small);
|
||||
background: transparent;
|
||||
color: var(--muted);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.global-search__clear:hover {
|
||||
background: var(--surface-soft);
|
||||
color: var(--ink-soft);
|
||||
}
|
||||
|
||||
.global-search__panel {
|
||||
position: absolute;
|
||||
inset: calc(100% + 8px) 0 auto 0;
|
||||
z-index: 80;
|
||||
max-height: min(70dvh, 620px);
|
||||
overflow: auto;
|
||||
border: 2px solid var(--line-strong);
|
||||
border-radius: var(--radius-card);
|
||||
background: var(--surface-raised);
|
||||
box-shadow: var(--shadow-raised);
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.global-search__group + .global-search__group {
|
||||
margin-top: 10px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.global-search__group-title {
|
||||
margin: 0 0 6px;
|
||||
color: var(--muted);
|
||||
font-size: 0.72rem;
|
||||
font-weight: 900;
|
||||
letter-spacing: 0;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.global-search__result {
|
||||
min-height: 58px;
|
||||
display: grid;
|
||||
grid-template-columns: 40px minmax(0, 1fr);
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 8px;
|
||||
border-radius: var(--radius-control);
|
||||
color: var(--ink);
|
||||
}
|
||||
|
||||
.global-search__result:hover {
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.global-search__result-image,
|
||||
.global-search__result-mark {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: var(--radius-small);
|
||||
background: var(--surface-soft);
|
||||
}
|
||||
|
||||
.global-search__result-image {
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.global-search__result-mark {
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.global-search__result-copy {
|
||||
min-width: 0;
|
||||
display: grid;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.global-search__result-title,
|
||||
.global-search__result-meta {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.global-search__result-title {
|
||||
color: var(--ink);
|
||||
font-size: 0.94rem;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
.global-search__result-meta {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
color: var(--muted);
|
||||
font-size: 0.78rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.global-search__message {
|
||||
margin: 0;
|
||||
padding: 14px 10px;
|
||||
color: var(--muted);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.global-search__skeleton {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.global-search__skeleton span {
|
||||
height: 48px;
|
||||
border-radius: var(--radius-control);
|
||||
background: linear-gradient(90deg, var(--surface-soft), var(--line), var(--surface-soft));
|
||||
background-size: 220% 100%;
|
||||
animation: shimmer 1.4s linear infinite;
|
||||
}
|
||||
|
||||
.topbar-actions {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
@@ -6864,6 +7048,53 @@ button:disabled,
|
||||
display: none;
|
||||
}
|
||||
|
||||
.site-topbar__search {
|
||||
flex: 0 0 auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.global-search {
|
||||
position: static;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.global-search__toggle {
|
||||
width: 44px;
|
||||
min-width: 44px;
|
||||
min-height: 44px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
border: 2px solid var(--line);
|
||||
border-radius: var(--radius-control);
|
||||
background: var(--surface);
|
||||
color: var(--ink-soft);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.global-search__toggle:hover {
|
||||
border-color: var(--pokemon-blue);
|
||||
color: var(--pokemon-blue-deep);
|
||||
}
|
||||
|
||||
.global-search__form {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.global-search--mobile-open .global-search__form {
|
||||
position: fixed;
|
||||
top: 68px;
|
||||
right: 12px;
|
||||
left: 12px;
|
||||
z-index: 80;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.global-search__panel {
|
||||
position: fixed;
|
||||
inset: 122px 12px auto 12px;
|
||||
max-height: calc(100dvh - 138px);
|
||||
}
|
||||
|
||||
.topbar-actions {
|
||||
flex: 0 0 auto;
|
||||
gap: 6px;
|
||||
|
||||
Reference in New Issue
Block a user