|
1 | | -import React, { useContext, useState } from "react"; |
| 1 | +import React, { useContext, useMemo, useState } from "react"; |
2 | 2 | import { useNavigate } from "react-router-dom"; |
3 | 3 | import { styled } from "@linaria/react"; |
4 | 4 | import { ContentWrapper, ListItem, TextMessage } from "../layout/Content"; |
5 | 5 | import { LazyList, ScrollableList } from "../Lists"; |
6 | | -import { useFilteredData } from "./utils/filtering"; |
| 6 | +import { useFilteredData, useParsedSearch, doSearch } from "./utils/filtering"; |
7 | 7 | import { SchemaClassView } from "./SchemaClass"; |
8 | 8 | import { SchemaEnumView } from "./SchemaEnum"; |
9 | 9 | import { ClassTree } from "./ClassTree"; |
10 | 10 | import { Declaration } from "./api"; |
11 | | -import { DeclarationsContext, declarationKey } from "./DeclarationsContext"; |
12 | | -import { GAMES } from "../../games"; |
| 11 | +import { |
| 12 | + DeclarationsContext, |
| 13 | + DeclarationsContextType, |
| 14 | + declarationKey, |
| 15 | +} from "./DeclarationsContext"; |
| 16 | +import { GAMES, GameId } from "../../games"; |
13 | 17 |
|
14 | 18 | const CardBlock = styled.div` |
15 | 19 | max-width: 560px; |
@@ -159,6 +163,65 @@ const OffsetsNote = styled.div` |
159 | 163 | padding: 8px 4px; |
160 | 164 | `; |
161 | 165 |
|
| 166 | +const OtherGameHeader = styled.div` |
| 167 | + display: flex; |
| 168 | + align-items: center; |
| 169 | + gap: 6px; |
| 170 | + padding: 12px 0 4px; |
| 171 | + font-size: 15px; |
| 172 | + color: var(--text-dim); |
| 173 | +
|
| 174 | + svg { |
| 175 | + width: 18px; |
| 176 | + height: 18px; |
| 177 | + border-radius: 3px; |
| 178 | + } |
| 179 | +`; |
| 180 | + |
| 181 | +function OtherGamesResults() { |
| 182 | + const ctx = useContext(DeclarationsContext); |
| 183 | + const parsed = useParsedSearch(); |
| 184 | + |
| 185 | + const gameResults = useMemo(() => { |
| 186 | + const result: { gameId: GameId; declarations: Declaration[] }[] = []; |
| 187 | + for (const [gameId, lookup] of ctx.otherGamesLookup) { |
| 188 | + if (gameId === ctx.game) continue; |
| 189 | + const decls = Array.from(lookup.values()); |
| 190 | + const found = doSearch(decls, parsed); |
| 191 | + if (found.length > 0) { |
| 192 | + result.push({ gameId, declarations: found }); |
| 193 | + } |
| 194 | + } |
| 195 | + return result; |
| 196 | + }, [ctx.game, ctx.otherGamesLookup, parsed]); |
| 197 | + |
| 198 | + if (gameResults.length === 0) return null; |
| 199 | + |
| 200 | + return ( |
| 201 | + <> |
| 202 | + {gameResults.map(({ gameId, declarations }) => { |
| 203 | + const gameInfo = GAMES.find((g) => g.id === gameId); |
| 204 | + const overrideCtx: DeclarationsContextType = { |
| 205 | + ...ctx, |
| 206 | + game: gameId, |
| 207 | + root: `/${gameId}`, |
| 208 | + declarations, |
| 209 | + }; |
| 210 | + return ( |
| 211 | + <React.Fragment key={gameId}> |
| 212 | + <OtherGameHeader> |
| 213 | + {gameInfo?.icon} {gameInfo?.name} |
| 214 | + </OtherGameHeader> |
| 215 | + <DeclarationsContext.Provider value={overrideCtx}> |
| 216 | + <LazyList data={declarations} render={renderItem} /> |
| 217 | + </DeclarationsContext.Provider> |
| 218 | + </React.Fragment> |
| 219 | + ); |
| 220 | + })} |
| 221 | + </> |
| 222 | + ); |
| 223 | +} |
| 224 | + |
162 | 225 | function renderItem(declaration: Declaration) { |
163 | 226 | let children: React.JSX.Element; |
164 | 227 | switch (declaration.kind) { |
@@ -189,7 +252,10 @@ export function ContentList() { |
189 | 252 | <ScrollableList data={data} render={renderItem} /> |
190 | 253 | ) |
191 | 254 | ) : isSearching ? ( |
192 | | - <TextMessage>No results found</TextMessage> |
| 255 | + <> |
| 256 | + <TextMessage>No results found</TextMessage> |
| 257 | + <OtherGamesResults /> |
| 258 | + </> |
193 | 259 | ) : error ? ( |
194 | 260 | <TextMessage>{`Failed to load schemas: ${error}`}</TextMessage> |
195 | 261 | ) : loading ? ( |
|
0 commit comments