still doesn't work

This commit is contained in:
Michael Zhang 2023-06-07 18:03:50 -05:00
parent db3ef039c7
commit 4cbdc7c142
19 changed files with 136 additions and 96 deletions

2
.prettierignore Normal file
View file

@ -0,0 +1,2 @@
node_modules
src-tauri

View file

@ -4,4 +4,4 @@
singleQuote: false, singleQuote: false,
trailingComma: "all", trailingComma: "all",
printWidth: 100, printWidth: 100,
} }

View file

@ -3,4 +3,4 @@ export default {
tailwindcss: {}, tailwindcss: {},
autoprefixer: {}, autoprefixer: {},
}, },
} };

View file

@ -1,4 +1,4 @@
use sqlx::{Row, SqlitePool}; use sqlx::{sqlite::SqliteRow, Row, SqlitePool};
use tauri::State; use tauri::State;
pub struct KanjiDb(pub SqlitePool); pub struct KanjiDb(pub SqlitePool);
@ -6,9 +6,7 @@ pub struct KanjiDb(pub SqlitePool);
#[derive(Debug, Derivative, Serialize, Deserialize)] #[derive(Debug, Derivative, Serialize, Deserialize)]
#[derivative(Default)] #[derivative(Default)]
pub struct GetKanjiOptions { pub struct GetKanjiOptions {
/// For looking up an existing one #[serde(default)]
character: Option<String>,
#[derivative(Default(value = "10"))] #[derivative(Default(value = "10"))]
how_many: u32, how_many: u32,
} }
@ -26,47 +24,68 @@ pub struct GetKanjiResult {
kanji: Vec<Kanji>, kanji: Vec<Kanji>,
} }
fn build_kanji(row: SqliteRow) -> Kanji {
let character = row.get("Character");
let meaning = row.get("Meaning");
let most_used_rank = row.get("MostUsedRank");
Kanji {
character,
meaning,
most_used_rank,
}
}
#[tauri::command] #[tauri::command]
pub async fn get_kanji( pub async fn get_kanji(
state: State<'_, KanjiDb>, db: State<'_, KanjiDb>,
options: Option<GetKanjiOptions>, options: Option<GetKanjiOptions>,
) -> Result<GetKanjiResult, ()> { ) -> Result<GetKanjiResult, ()> {
let opts = options.unwrap_or_default(); let opts = options.unwrap_or_default();
let result = sqlx::query( let result = sqlx::query(
r#" r#"
SELECT * FROM KanjiSet SELECT * FROM KanjiSet
LEFT JOIN KanjiMeaningSet ON KanjiSet.ID = KanjiMeaningSet.Kanji_ID LEFT JOIN KanjiMeaningSet ON KanjiSet.ID = KanjiMeaningSet.Kanji_ID
GROUP BY KanjiSet.ID GROUP BY KanjiSet.ID
HAVING MostUsedRank IS NOT NULL HAVING MostUsedRank IS NOT NULL
ORDER BY MostUsedRank ORDER BY MostUsedRank
LIMIT ? LIMIT ?
"#, "#,
) )
.bind(opts.how_many) .bind(opts.how_many)
.fetch_all(&state.0) .fetch_all(&db.0)
.await .await
.map_err(|_| ())?; .map_err(|_| ())?;
let kanji = result let kanji = result.into_iter().map(build_kanji).collect();
.into_iter()
.map(|row| {
let character = row.get("Character");
let meaning = row.get("Meaning");
let most_used_rank = row.get("MostUsedRank");
Kanji {
character,
meaning,
most_used_rank,
}
})
.collect();
let count = sqlx::query("SELECT COUNT(*) FROM KanjiSet") let count = sqlx::query("SELECT COUNT(*) FROM KanjiSet")
.fetch_one(&state.0) .fetch_one(&db.0)
.await .await
.map_err(|_| ())?; .map_err(|_| ())?;
let count = count.try_get(0).map_err(|_| ())?; let count = count.try_get(0).map_err(|_| ())?;
Ok(GetKanjiResult { kanji, count }) Ok(GetKanjiResult { kanji, count })
} }
#[tauri::command]
pub async fn get_single_kanji(
db: State<'_, KanjiDb>,
character: String,
) -> Result<Option<Kanji>, ()> {
let result = sqlx::query(
r#"
SELECT * FROM KanjiSet
LEFT JOIN KanjiMeaningSet ON KanjiSet.ID = KanjiMeaningSet.Kanji_ID
GROUP BY KanjiSet.ID
HAVING MostUsedRank IS NOT NULL
AND Kanji.Character = ?
"#,
)
.bind(character)
.fetch_one(&db.0)
.await
.map_err(|_| ())?;
Ok(Some(build_kanji(result)))
}

View file

@ -41,7 +41,11 @@ async fn main() -> Result<()> {
tauri::Builder::default() tauri::Builder::default()
.manage(KanjiDb(kanji_pool)) .manage(KanjiDb(kanji_pool))
.system_tray(tray) .system_tray(tray)
.invoke_handler(tauri::generate_handler![greet, kanji::get_kanji]) .invoke_handler(tauri::generate_handler![
greet,
kanji::get_kanji,
kanji::get_single_kanji
])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.context("error while running tauri application")?; .context("error while running tauri application")?;

View file

@ -15,9 +15,8 @@ main.main {
flex-grow: 1; flex-grow: 1;
display: inline-block; display: inline-block;
padding: 12px; padding: 12px;
} }
.link-active { .link-active {
background-color: skyblue; background-color: skyblue;
} }

View file

@ -1,10 +1,10 @@
import { Link, RouterProvider, createHashRouter } from "react-router-dom"; import { Link, RouterProvider, createHashRouter } from "react-router-dom";
import KanjiPane from "./panes/KanjiPane"; import KanjiPane from "./panes/KanjiPane";
import classNames from "classnames"; import classNames from "classnames";
import { ChakraProvider } from '@chakra-ui/react' import { ChakraProvider } from "@chakra-ui/react";
import HomePane from "./panes/HomePane"; import HomePane from "./panes/HomePane";
import { createBrowserRouter } from "react-router-dom"; import { createBrowserRouter } from "react-router-dom";
import { Outlet, Route, createRoutesFromElements, useLocation } from "react-router"; import { Outlet, Route, createRoutesFromElements, matchPath, useLocation } from "react-router";
import SrsPane from "./panes/SrsPane"; import SrsPane from "./panes/SrsPane";
import VocabPane from "./panes/VocabPane"; import VocabPane from "./panes/VocabPane";
import SettingsPane from "./panes/SettingsPane"; import SettingsPane from "./panes/SettingsPane";
@ -20,11 +20,15 @@ function Layout() {
<ul className={styles.header}> <ul className={styles.header}>
{routes.map((route) => { {routes.map((route) => {
if (!route.title) return undefined; if (!route.title) return undefined;
const active = route.path == location.pathname; const active = matchPath({ path: route.path }, location.pathname);
const className = classNames(styles.link, active && styles['link-active']); const className = classNames(styles.link, active && styles["link-active"]);
return <li key={route.path}> return (
<Link to={route.path} className={className}>{route.title}</Link> <li key={route.path}>
</li> <Link to={route.path} className={className}>
{route.title}
</Link>
</li>
);
})} })}
</ul> </ul>
@ -38,22 +42,19 @@ export default function App() {
createRoutesFromElements( createRoutesFromElements(
<Route path="/" element={<Layout />}> <Route path="/" element={<Layout />}>
{routes.map((route, idx) => ( {routes.map((route, idx) => (
<Route <Route key={route.path} index={idx === 0} path={route.path} element={route.element} />
key={route.path}
index={idx === 0}
path={route.path}
element={route.element}
/>
))} ))}
</Route> </Route>,
) ),
); );
return <StrictMode> return (
<ChakraProvider> <StrictMode>
<RouterProvider router={router} /> <ChakraProvider>
</ChakraProvider> <RouterProvider router={router} />
</StrictMode> </ChakraProvider>
</StrictMode>
);
} }
const routes = [ const routes = [

View file

@ -7,4 +7,4 @@ $kanjiDisplaySize: 80px;
font-size: $kanjiDisplaySize * 0.8; font-size: $kanjiDisplaySize * 0.8;
text-align: center; text-align: center;
vertical-align: middle; vertical-align: middle;
} }

View file

@ -1,7 +1,7 @@
import { invoke } from "@tauri-apps/api/tauri"; import { invoke } from "@tauri-apps/api/tauri";
import { GetKanjiResult } from "../panes/KanjiPane"; import { GetKanjiResult } from "../panes/KanjiPane";
import { Kanji } from "../types/Kanji" import { Kanji } from "../types/Kanji";
import styles from "./KanjiDisplay.module.scss" import styles from "./KanjiDisplay.module.scss";
import useSWR from "swr"; import useSWR from "swr";
interface KanjiDisplayProps { interface KanjiDisplayProps {
@ -9,11 +9,23 @@ interface KanjiDisplayProps {
} }
export default function KanjiDisplay({ kanjiCharacter }: KanjiDisplayProps) { export default function KanjiDisplay({ kanjiCharacter }: KanjiDisplayProps) {
const { data, error, isLoading } = useSWR(["get_kanji", kanjiCharacter], invoke<GetKanjiResult>); const { data, error, isLoading } = useSWR(["get_single_kanji", kanjiCharacter], ([command, character]) => invoke<GetKanjiResult>(command, { character }));
return <> return (
<div className={styles.display}> <>
{kanjiCharacter} <div className={styles.display}>{kanjiCharacter}</div>
</div>
</> {JSON.stringify(isLoading)}
}
<p>
data:
{JSON.stringify(data)}
</p>
<p>
error:
{JSON.stringify(error)}
</p>
</>
);
}

View file

@ -7,5 +7,5 @@ import "./styles.css";
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render( ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode> <React.StrictMode>
<App /> <App />
</React.StrictMode> </React.StrictMode>,
); );

View file

@ -1,5 +1,3 @@
export default function HomePane() { export default function HomePane() {
return <> return <>hellosu</>;
hellosu }
</>
}

View file

@ -7,4 +7,4 @@
.kanji-link { .kanji-link {
padding: 4px 8px; padding: 4px 8px;
border: 1px solid lightgray; border: 1px solid lightgray;
} }

View file

@ -14,24 +14,30 @@ export interface GetKanjiResult {
interface KanjiListProps { interface KanjiListProps {
data: GetKanjiResult; data: GetKanjiResult;
selectedCharacter: string; selectedCharacter?: string;
} }
function KanjiList({ data, selectedCharacter }: KanjiListProps) { function KanjiList({ data, selectedCharacter }: KanjiListProps) {
return <> return (
Displaying {data.kanji.length} of {data.count} results. <>
Displaying {data.kanji.length} of {data.count} results.
{data.kanji.map(kanji => <Link key={kanji.character} className={styles['kanji-link']} to={`/kanji/${kanji.character}`}> {data.kanji.map((kanji) => (
<Grid <Link
templateRows='repeat(2, 1fr)' key={kanji.character}
templateColumns='1fr 3fr'> className={styles["kanji-link"]}
<GridItem rowSpan={2} style={{ fontSize: '24px', textAlign: 'center' }}>{kanji.character}</GridItem> to={`/kanji/${kanji.character}`}
<GridItem>{kanji.meaning}</GridItem> >
<GridItem>#{kanji.most_used_rank} most used</GridItem> <Grid templateRows="repeat(2, 1fr)" templateColumns="1fr 3fr">
</Grid> <GridItem rowSpan={2} style={{ fontSize: "24px", textAlign: "center" }}>
</Link>)} {kanji.character}
</> </GridItem>
<GridItem>{kanji.meaning}</GridItem>
<GridItem>#{kanji.most_used_rank} most used</GridItem>
</Grid>
</Link>
))}
</>
);
} }
export default function KanjiPane() { export default function KanjiPane() {
@ -43,15 +49,15 @@ export default function KanjiPane() {
{JSON.stringify(error)} {JSON.stringify(error)}
{JSON.stringify(selectedKanji)} {JSON.stringify(selectedKanji)}
<Stack spacing={7} direction='row'> <Stack spacing={7} direction="row">
<Box p={2} className={styles['kanji-list']}> <Box p={2} className={styles["kanji-list"]}>
{data && <KanjiList data={data} selectedCharacter={selectedKanji} />} {data && <KanjiList data={data} selectedCharacter={selectedKanji} />}
</Box> </Box>
<Box p={5}> <Box p={5}>
{selectedKanji ? <KanjiDisplay kanjiCharacter={selectedKanji} /> : "nothing selected"} {selectedKanji ? <KanjiDisplay kanjiCharacter={selectedKanji} /> : "nothing selected"}
</Box> </Box>
</Stack > </Stack>
</> </>
); );
} }

View file

@ -1,3 +1,3 @@
export default function SettingsPane() { export default function SettingsPane() {
return <></> return <></>;
} }

View file

@ -1,3 +1,3 @@
export default function SrsPane() { export default function SrsPane() {
return <></> return <></>;
} }

View file

@ -1,3 +1,3 @@
export default function VocabPane() { export default function VocabPane() {
return <></> return <></>;
} }

View file

@ -1,3 +1,3 @@
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;

View file

@ -2,4 +2,4 @@ export interface Kanji {
character: string; character: string;
meaning: string; meaning: string;
most_used_rank: number; most_used_rank: number;
} }

View file

@ -1,11 +1,10 @@
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
export default { export default {
content: ["./src/**/*.{html,js,jsx,ts,tsx}", content: ["./src/**/*.{html,js,jsx,ts,tsx}", "./node_modules/flowbite/**/*.js"],
"./node_modules/flowbite/**/*.js"],
theme: { theme: {
extend: {}, extend: {},
}, },
plugins: [require("flowbite/plugin")], plugins: [require("flowbite/plugin")],
}; };