still doesn't work
This commit is contained in:
parent
15cbfeb0d6
commit
4ecf26f4b2
19 changed files with 136 additions and 96 deletions
2
.prettierignore
Normal file
2
.prettierignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
src-tauri
|
|
@ -4,4 +4,4 @@
|
|||
singleQuote: false,
|
||||
trailingComma: "all",
|
||||
printWidth: 100,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,4 +3,4 @@ export default {
|
|||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use sqlx::{Row, SqlitePool};
|
||||
use sqlx::{sqlite::SqliteRow, Row, SqlitePool};
|
||||
use tauri::State;
|
||||
|
||||
pub struct KanjiDb(pub SqlitePool);
|
||||
|
@ -6,9 +6,7 @@ pub struct KanjiDb(pub SqlitePool);
|
|||
#[derive(Debug, Derivative, Serialize, Deserialize)]
|
||||
#[derivative(Default)]
|
||||
pub struct GetKanjiOptions {
|
||||
/// For looking up an existing one
|
||||
character: Option<String>,
|
||||
|
||||
#[serde(default)]
|
||||
#[derivative(Default(value = "10"))]
|
||||
how_many: u32,
|
||||
}
|
||||
|
@ -26,47 +24,68 @@ pub struct GetKanjiResult {
|
|||
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]
|
||||
pub async fn get_kanji(
|
||||
state: State<'_, KanjiDb>,
|
||||
db: State<'_, KanjiDb>,
|
||||
options: Option<GetKanjiOptions>,
|
||||
) -> Result<GetKanjiResult, ()> {
|
||||
let opts = options.unwrap_or_default();
|
||||
|
||||
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
|
||||
ORDER BY MostUsedRank
|
||||
LIMIT ?
|
||||
SELECT * FROM KanjiSet
|
||||
LEFT JOIN KanjiMeaningSet ON KanjiSet.ID = KanjiMeaningSet.Kanji_ID
|
||||
GROUP BY KanjiSet.ID
|
||||
HAVING MostUsedRank IS NOT NULL
|
||||
ORDER BY MostUsedRank
|
||||
LIMIT ?
|
||||
"#,
|
||||
)
|
||||
.bind(opts.how_many)
|
||||
.fetch_all(&state.0)
|
||||
.fetch_all(&db.0)
|
||||
.await
|
||||
.map_err(|_| ())?;
|
||||
|
||||
let kanji = result
|
||||
.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 kanji = result.into_iter().map(build_kanji).collect();
|
||||
|
||||
let count = sqlx::query("SELECT COUNT(*) FROM KanjiSet")
|
||||
.fetch_one(&state.0)
|
||||
.fetch_one(&db.0)
|
||||
.await
|
||||
.map_err(|_| ())?;
|
||||
let count = count.try_get(0).map_err(|_| ())?;
|
||||
|
||||
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)))
|
||||
}
|
||||
|
|
|
@ -41,7 +41,11 @@ async fn main() -> Result<()> {
|
|||
tauri::Builder::default()
|
||||
.manage(KanjiDb(kanji_pool))
|
||||
.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!())
|
||||
.context("error while running tauri application")?;
|
||||
|
||||
|
|
|
@ -15,9 +15,8 @@ main.main {
|
|||
flex-grow: 1;
|
||||
display: inline-block;
|
||||
padding: 12px;
|
||||
|
||||
}
|
||||
|
||||
.link-active {
|
||||
background-color: skyblue;
|
||||
}
|
||||
}
|
||||
|
|
41
src/App.tsx
41
src/App.tsx
|
@ -1,10 +1,10 @@
|
|||
import { Link, RouterProvider, createHashRouter } from "react-router-dom";
|
||||
import KanjiPane from "./panes/KanjiPane";
|
||||
import classNames from "classnames";
|
||||
import { ChakraProvider } from '@chakra-ui/react'
|
||||
import { ChakraProvider } from "@chakra-ui/react";
|
||||
import HomePane from "./panes/HomePane";
|
||||
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 VocabPane from "./panes/VocabPane";
|
||||
import SettingsPane from "./panes/SettingsPane";
|
||||
|
@ -20,11 +20,15 @@ function Layout() {
|
|||
<ul className={styles.header}>
|
||||
{routes.map((route) => {
|
||||
if (!route.title) return undefined;
|
||||
const active = route.path == location.pathname;
|
||||
const className = classNames(styles.link, active && styles['link-active']);
|
||||
return <li key={route.path}>
|
||||
<Link to={route.path} className={className}>{route.title}</Link>
|
||||
</li>
|
||||
const active = matchPath({ path: route.path }, location.pathname);
|
||||
const className = classNames(styles.link, active && styles["link-active"]);
|
||||
return (
|
||||
<li key={route.path}>
|
||||
<Link to={route.path} className={className}>
|
||||
{route.title}
|
||||
</Link>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
|
||||
|
@ -38,22 +42,19 @@ export default function App() {
|
|||
createRoutesFromElements(
|
||||
<Route path="/" element={<Layout />}>
|
||||
{routes.map((route, idx) => (
|
||||
<Route
|
||||
key={route.path}
|
||||
index={idx === 0}
|
||||
path={route.path}
|
||||
element={route.element}
|
||||
/>
|
||||
<Route key={route.path} index={idx === 0} path={route.path} element={route.element} />
|
||||
))}
|
||||
</Route>
|
||||
)
|
||||
</Route>,
|
||||
),
|
||||
);
|
||||
|
||||
return <StrictMode>
|
||||
<ChakraProvider>
|
||||
<RouterProvider router={router} />
|
||||
</ChakraProvider>
|
||||
</StrictMode>
|
||||
return (
|
||||
<StrictMode>
|
||||
<ChakraProvider>
|
||||
<RouterProvider router={router} />
|
||||
</ChakraProvider>
|
||||
</StrictMode>
|
||||
);
|
||||
}
|
||||
|
||||
const routes = [
|
||||
|
|
|
@ -7,4 +7,4 @@ $kanjiDisplaySize: 80px;
|
|||
font-size: $kanjiDisplaySize * 0.8;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { invoke } from "@tauri-apps/api/tauri";
|
||||
import { GetKanjiResult } from "../panes/KanjiPane";
|
||||
import { Kanji } from "../types/Kanji"
|
||||
import styles from "./KanjiDisplay.module.scss"
|
||||
import { Kanji } from "../types/Kanji";
|
||||
import styles from "./KanjiDisplay.module.scss";
|
||||
import useSWR from "swr";
|
||||
|
||||
interface KanjiDisplayProps {
|
||||
|
@ -9,11 +9,23 @@ interface 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 <>
|
||||
<div className={styles.display}>
|
||||
{kanjiCharacter}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<div className={styles.display}>{kanjiCharacter}</div>
|
||||
|
||||
{JSON.stringify(isLoading)}
|
||||
|
||||
<p>
|
||||
data:
|
||||
{JSON.stringify(data)}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
error:
|
||||
{JSON.stringify(error)}
|
||||
</p>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,5 +7,5 @@ import "./styles.css";
|
|||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
</React.StrictMode>,
|
||||
);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
export default function HomePane() {
|
||||
return <>
|
||||
hellosu
|
||||
</>
|
||||
}
|
||||
return <>hellosu</>;
|
||||
}
|
||||
|
|
|
@ -7,4 +7,4 @@
|
|||
.kanji-link {
|
||||
padding: 4px 8px;
|
||||
border: 1px solid lightgray;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,24 +14,30 @@ export interface GetKanjiResult {
|
|||
|
||||
interface KanjiListProps {
|
||||
data: GetKanjiResult;
|
||||
selectedCharacter: string;
|
||||
selectedCharacter?: string;
|
||||
}
|
||||
|
||||
function KanjiList({ data, selectedCharacter }: KanjiListProps) {
|
||||
return <>
|
||||
Displaying {data.kanji.length} of {data.count} results.
|
||||
|
||||
{data.kanji.map(kanji => <Link key={kanji.character} className={styles['kanji-link']} to={`/kanji/${kanji.character}`}>
|
||||
<Grid
|
||||
templateRows='repeat(2, 1fr)'
|
||||
templateColumns='1fr 3fr'>
|
||||
<GridItem rowSpan={2} style={{ fontSize: '24px', textAlign: 'center' }}>{kanji.character}</GridItem>
|
||||
<GridItem>{kanji.meaning}</GridItem>
|
||||
<GridItem>#{kanji.most_used_rank} most used</GridItem>
|
||||
</Grid>
|
||||
</Link>)}
|
||||
</>
|
||||
|
||||
return (
|
||||
<>
|
||||
Displaying {data.kanji.length} of {data.count} results.
|
||||
{data.kanji.map((kanji) => (
|
||||
<Link
|
||||
key={kanji.character}
|
||||
className={styles["kanji-link"]}
|
||||
to={`/kanji/${kanji.character}`}
|
||||
>
|
||||
<Grid templateRows="repeat(2, 1fr)" templateColumns="1fr 3fr">
|
||||
<GridItem rowSpan={2} style={{ fontSize: "24px", textAlign: "center" }}>
|
||||
{kanji.character}
|
||||
</GridItem>
|
||||
<GridItem>{kanji.meaning}</GridItem>
|
||||
<GridItem>#{kanji.most_used_rank} most used</GridItem>
|
||||
</Grid>
|
||||
</Link>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default function KanjiPane() {
|
||||
|
@ -43,15 +49,15 @@ export default function KanjiPane() {
|
|||
{JSON.stringify(error)}
|
||||
{JSON.stringify(selectedKanji)}
|
||||
|
||||
<Stack spacing={7} direction='row'>
|
||||
<Box p={2} className={styles['kanji-list']}>
|
||||
<Stack spacing={7} direction="row">
|
||||
<Box p={2} className={styles["kanji-list"]}>
|
||||
{data && <KanjiList data={data} selectedCharacter={selectedKanji} />}
|
||||
</Box>
|
||||
|
||||
<Box p={5}>
|
||||
{selectedKanji ? <KanjiDisplay kanjiCharacter={selectedKanji} /> : "nothing selected"}
|
||||
</Box>
|
||||
</Stack >
|
||||
</Stack>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export default function SettingsPane() {
|
||||
return <></>
|
||||
}
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export default function SrsPane() {
|
||||
return <></>
|
||||
}
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export default function VocabPane() {
|
||||
return <></>
|
||||
}
|
||||
return <></>;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities;
|
||||
|
|
|
@ -2,4 +2,4 @@ export interface Kanji {
|
|||
character: string;
|
||||
meaning: string;
|
||||
most_used_rank: number;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: ["./src/**/*.{html,js,jsx,ts,tsx}",
|
||||
"./node_modules/flowbite/**/*.js"],
|
||||
content: ["./src/**/*.{html,js,jsx,ts,tsx}", "./node_modules/flowbite/**/*.js"],
|
||||
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
|
||||
plugins: [require("flowbite/plugin")],
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue