Skip to content

Commit

Permalink
Rework Bingus frontend
Browse files Browse the repository at this point in the history
  • Loading branch information
ButterscotchV committed Dec 11, 2024
1 parent e8b04d8 commit ca6ac42
Show file tree
Hide file tree
Showing 8 changed files with 1,727 additions and 1,072 deletions.
4 changes: 2 additions & 2 deletions bingus-frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta
name="description"
content="A site for searching SlimeVR FAQ using AI."
content="A site for searching the SlimeVR FAQ."
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<title>Bingus Search</title>
<title>Bingus</title>
</head>
<body>
<div id="root"></div>
Expand Down
25 changes: 13 additions & 12 deletions bingus-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,css,md,json}\" --config ../.prettierrc"
},
"dependencies": {
"@emotion/react": "^11.13.3",
"@emotion/styled": "^11.13.0",
"@mui/material": "^6.1.0",
"mui-markdown": "^1.2.2",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"@emotion/react": "^11.14.0",
"@emotion/styled": "^11.14.0",
"@mui/icons-material": "^6.2.0",
"@mui/material": "^6.2.0",
"mui-markdown": "^1.2.3",
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"devDependencies": {
"@types/react": "^18.3.7",
"@types/react-dom": "^18.3.0",
"@vitejs/plugin-react": "^4.3.1",
"eslint-plugin-react": "^7.36.1",
"eslint-plugin-react-hooks": "^4.6.2",
"vite": "^5.4.6"
"@types/react": "^19.0.1",
"@types/react-dom": "^19.0.2",
"@vitejs/plugin-react": "^4.3.4",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.1.0",
"vite": "^6.0.3"
}
}
20 changes: 0 additions & 20 deletions bingus-frontend/src/App.css

This file was deleted.

213 changes: 115 additions & 98 deletions bingus-frontend/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { ThemeProvider } from "@emotion/react";
import {
Alert,
Button,
Card,
CardContent,
CardHeader,
CircularProgress,
Container,
createTheme,
CssBaseline,
IconButton,
Link,
Skeleton,
Stack,
TextField,
Typography,
} from "@mui/material";
import { useMemo, useRef, useState } from "react";
import "./App.css";
import MuiMarkdown from "mui-markdown";
import SearchIcon from "@mui/icons-material/Search";
import LightModeIcon from "@mui/icons-material/LightMode";
import DarkModeIcon from "@mui/icons-material/DarkMode";

export type Result = {
relevance: number;
Expand All @@ -25,6 +27,37 @@ export type Result = {
text: string;
};

function relevanceToElevation(relevance: number, scale = 24): number {
return Math.round((relevance / 100) * scale);
}

interface ResultCardProps {
readonly relevance: number;
readonly title: string;
readonly text: string;
}

function ResultCard(props: ResultCardProps) {
return (
<Card
key={props.title}
variant="elevation"
elevation={1 + relevanceToElevation(props.relevance, 5)}
sx={{ width: "100%" }}
>
<CardHeader
title={props.title}
subheader={`${props.relevance.toFixed()}% relevant`}
sx={{ pb: 1 }}
titleTypographyProps={{ sx: { typography: { sm: "h5", xs: "h6" } } }}
/>
<CardContent sx={{ pt: 0 }}>
<MuiMarkdown>{props.text}</MuiMarkdown>
</CardContent>
</Card>
);
}

function App() {
const localTheme = localStorage.getItem("user-theme");
const systemDarkMode = matchMedia("(prefers-color-scheme: dark)");
Expand Down Expand Up @@ -54,9 +87,12 @@ function App() {

const urlInputSearched = useRef(false);
const [input, setInput] = useState(urlInput);
const [lastResults, setLastResults] = useState<Result[] | null>(null);
const [lastSearchInput, setLastSearchInput] = useState("");
const [lastSearch, setLastSearch] = useState("");

const [loadingResults, setLoadingResults] = useState(false);
const [searchResults, setSearchResults] = useState<Result[] | undefined>(
undefined,
);

const updateUrl = function () {
window.history.replaceState({}, window.name, url.toString());
Expand All @@ -78,16 +114,16 @@ function App() {
};

const search = async () => {
if (input === lastSearchInput) {
if (input === lastSearch) {
return;
}

// Clear last search results
setLastResults(null);
setSearchResults(undefined);

if (!input || !/\S/.test(input)) {
setLastResults(null);
setLastSearchInput(input);
setSearchResults(undefined);
setLastSearch(input);

url.searchParams.delete("q");
updateUrl();
Expand All @@ -98,9 +134,8 @@ function App() {
url.searchParams.set("q", input);
updateUrl();

const results = await queryBingus(input);
setLastResults(results);
setLastSearchInput(input);
setSearchResults(await queryBingus(input));
setLastSearch(input);
};

if (!urlInputSearched.current) {
Expand All @@ -116,106 +151,88 @@ function App() {
});
};

const relevanceToElevation = function (
relevance: number,
scale = 24,
): number {
return Math.round((relevance / 100) * scale);
};

const resultCard = function (relevance: number, title: string, text: string) {
const relevanceElevation = relevanceToElevation(relevance, 5);

return (
<Card
key={title}
variant="elevation"
elevation={1 + relevanceElevation}
sx={{ width: "100%" }}
>
<CardHeader
title={title}
subheader={`${relevance.toFixed()}% relevant`}
sx={{ pb: 1 }}
titleTypographyProps={{ sx: { typography: { sm: "h5", xs: "h6" } } }}
/>
<CardContent sx={{ pt: 0 }}>
<MuiMarkdown>{text}</MuiMarkdown>
</CardContent>
</Card>
);
};

const results = function () {
return lastResults?.length ? (
lastResults
.sort((a, b) => (a.relevance <= b.relevance ? 1 : -1))
.map((result) =>
resultCard(result.relevance, result.title, result.text),
)
) : (
<Typography color="text.secondary" padding={1}>
No results...
</Typography>
);
};

return (
<ThemeProvider theme={theme}>
<CssBaseline />

<Container className={prefersDarkMode ? "dark" : ""}>
<Stack spacing={1} direction="row" sx={{ my: 2 }}>
<Alert variant="outlined" severity="info" sx={{ flexGrow: 1 }}>
<Typography>
Information may not be up-to-date. If you need further help, join
the <Link href="https://discord.gg/SlimeVR">SlimeVR Discord</Link>
.
</Typography>
</Alert>
<Button
variant="contained"
<Container>
<Stack useFlexGap direction="column" py={2} spacing={2}>
<IconButton
onClick={toggleTheme}
sx={{ width: "fit-content", height: "fit-content" }}
sx={{
width: "fit-content",
height: "fit-content",
alignSelf: "end",
}}
>
{prefersDarkMode ? "Dark" : "Light"}
</Button>
</Stack>
{prefersDarkMode ? (
<DarkModeIcon fontSize="inherit" />
) : (
<LightModeIcon fontSize="inherit" />
)}
</IconButton>

<Container disableGutters>
<Typography
noWrap
align="center"
sx={{ typography: { md: "h2", sm: "h3", xs: "h4" } }}
variant="h2"
sx={{ typography: { md: "h2", sm: "h3", xs: "h3" } }}
>
Bingus Search
<b>Bingus</b>
</Typography>
<Typography align="center" variant="subtitle2" color="textSecondary">
Information may not be up-to-date. If you need further help, join
the <Link href="https://discord.gg/SlimeVR">SlimeVR Discord</Link>.
</Typography>

<Stack spacing={1} direction="row" sx={{ my: 2 }}>
<TextField
fullWidth
label="Ask a question..."
autoFocus
value={input}
variant="filled"
onChange={(e) => setInput(e.target.value)}
onKeyUp={(e) => {
if (e.key === "Enter") search();
}}
/>
<Button onClick={search} variant="contained">
Search
</Button>
</Stack>

<Stack spacing={2} alignItems="center" direction="column" my={3}>
{loadingResults ? (
<CircularProgress thickness={5.5} size={64} sx={{ padding: 1 }} />
) : (
results()
)}
<TextField
fullWidth
label="Ask a question..."
autoFocus
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyUp={(e) => {
if (e.key === "Enter") search();
}}
slotProps={{
input: {
endAdornment: loadingResults ? (
<CircularProgress />
) : (
<IconButton onClick={search}>
<SearchIcon fontSize="inherit" />
</IconButton>
),
},
}}
/>

<Stack spacing={2} alignItems="center" direction="column">
{loadingResults
? [...Array(30)].map((_, i) => (
<Skeleton
key={i}
variant="rounded"
width="100%"
height={128}
/>
))
: searchResults
?.sort((a, b) => (a.relevance <= b.relevance ? 1 : -1))
?.map((result) => (
<ResultCard
key={result.title}
relevance={result.relevance}
title={result.title}
text={result.text}
/>
)) || (
<Typography color="text.secondary" padding={1}>
No results...
</Typography>
)}
</Stack>
</Container>
</Stack>
</Container>
</ThemeProvider>
);
Expand Down
Binary file removed bingus-frontend/src/fonts/Ubuntu-Regular.ttf
Binary file not shown.
17 changes: 1 addition & 16 deletions bingus-frontend/src/index.css
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
:root {
font-family: Ubuntu, Inter, Avenir, Helvetica, Arial, sans-serif;

background-color: #000000;

font-synthesis: none;
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-text-size-adjust: 100%;
}

body {
margin: 0;
display: flex;
min-width: 320px;
min-height: 100vh;
color-scheme: light dark;
}
Loading

0 comments on commit ca6ac42

Please sign in to comment.