eslint + more vocab
This commit is contained in:
parent
5987e746db
commit
00ec52a9a4
30 changed files with 3846 additions and 660 deletions
14
eslint.config.js
Normal file
14
eslint.config.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import js from "@eslint/js";
|
||||||
|
import reactRecommended from "eslint-plugin-react/configs/recommended.js";
|
||||||
|
import reactJsxRuntime from "eslint-plugin-react/configs/jsx-runtime.js";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{ ignores: ["src-tauri/**/*", "dist/**/*"] },
|
||||||
|
{ settings: { react: { version: "detect" } } },
|
||||||
|
{
|
||||||
|
files: ["**/*.js"],
|
||||||
|
rules: js.configs.recommended.rules,
|
||||||
|
},
|
||||||
|
reactRecommended,
|
||||||
|
reactJsxRuntime,
|
||||||
|
];
|
4218
package-lock.json
generated
4218
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -18,7 +18,6 @@
|
||||||
"chakra-react-select": "^4.6.0",
|
"chakra-react-select": "^4.6.0",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"date-fns": "^2.30.0",
|
"date-fns": "^2.30.0",
|
||||||
"flowbite": "^1.6.5",
|
|
||||||
"framer-motion": "^10.12.16",
|
"framer-motion": "^10.12.16",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
@ -29,19 +28,23 @@
|
||||||
"swr": "^2.1.5"
|
"swr": "^2.1.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^8.42.0",
|
||||||
"@tauri-apps/cli": "^1.4.0",
|
"@tauri-apps/cli": "^1.4.0",
|
||||||
"@types/lodash-es": "^4.17.7",
|
"@types/lodash-es": "^4.17.7",
|
||||||
"@types/node": "^18.7.10",
|
"@types/node": "^18.7.10",
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@types/react-timeago": "^4.1.3",
|
"@types/react-timeago": "^4.1.3",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
||||||
|
"@typescript-eslint/parser": "^5.59.11",
|
||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.0.0",
|
||||||
"@vitejs/plugin-react-swc": "^3.3.2",
|
"@vitejs/plugin-react-swc": "^3.3.2",
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
|
"eslint": "^8.42.0",
|
||||||
|
"eslint-plugin-react": "^7.32.2",
|
||||||
"postcss": "^8.4.24",
|
"postcss": "^8.4.24",
|
||||||
"prettier": "^2.8.8",
|
"prettier": "^2.8.8",
|
||||||
"sass": "^1.62.1",
|
"sass": "^1.62.1",
|
||||||
"tailwindcss": "^3.3.2",
|
|
||||||
"typescript": "^4.9.5",
|
"typescript": "^4.9.5",
|
||||||
"vite": "^4.2.1"
|
"vite": "^4.2.1"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
export default {
|
|
||||||
plugins: {
|
|
||||||
tailwindcss: {},
|
|
||||||
autoprefixer: {},
|
|
||||||
},
|
|
||||||
};
|
|
1
src-tauri/Cargo.lock
generated
1
src-tauri/Cargo.lock
generated
|
@ -1643,6 +1643,7 @@ dependencies = [
|
||||||
"derivative",
|
"derivative",
|
||||||
"dirs",
|
"dirs",
|
||||||
"flate2",
|
"flate2",
|
||||||
|
"itertools",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sqlx",
|
"sqlx",
|
||||||
|
|
|
@ -26,6 +26,7 @@ derivative = "2.2.0"
|
||||||
flate2 = "1.0.26"
|
flate2 = "1.0.26"
|
||||||
base64 = "0.21.2"
|
base64 = "0.21.2"
|
||||||
tantivy = { version = "0.20.2", default-features = false, features = ["memmap2"] }
|
tantivy = { version = "0.20.2", default-features = false, features = ["memmap2"] }
|
||||||
|
itertools = "0.10.5"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# this feature is used for production builds or when `devPath` points to the filesystem
|
# this feature is used for production builds or when `devPath` points to the filesystem
|
||||||
|
|
|
@ -50,6 +50,7 @@ fn default_how_many() -> u32 {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Kanji {
|
pub struct Kanji {
|
||||||
|
id: u32,
|
||||||
character: String,
|
character: String,
|
||||||
meanings: Vec<KanjiMeaning>,
|
meanings: Vec<KanjiMeaning>,
|
||||||
srs_info: Option<KanjiSrsInfo>,
|
srs_info: Option<KanjiSrsInfo>,
|
||||||
|
@ -270,6 +271,7 @@ pub async fn get_kanji(
|
||||||
}
|
}
|
||||||
|
|
||||||
new_vec.push(Kanji {
|
new_vec.push(Kanji {
|
||||||
|
id,
|
||||||
character,
|
character,
|
||||||
meanings: vec![meaning],
|
meanings: vec![meaning],
|
||||||
|
|
||||||
|
|
|
@ -12,13 +12,12 @@ pub mod utils;
|
||||||
pub mod vocab;
|
pub mod vocab;
|
||||||
|
|
||||||
use std::process;
|
use std::process;
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
use sqlx::sqlite::{SqliteConnectOptions, SqlitePoolOptions};
|
||||||
use tauri::{
|
use tauri::{
|
||||||
CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu,
|
CustomMenuItem, Manager, SystemTray, SystemTrayEvent, SystemTrayMenu,
|
||||||
SystemTrayMenuItem, WindowEvent,
|
WindowEvent,
|
||||||
};
|
};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
|
|
||||||
|
@ -78,6 +77,7 @@ async fn main() -> Result<()> {
|
||||||
srs::generate_review_batch,
|
srs::generate_review_batch,
|
||||||
srs::update_srs_item,
|
srs::update_srs_item,
|
||||||
kanji::get_kanji,
|
kanji::get_kanji,
|
||||||
|
vocab::get_vocab,
|
||||||
utils::application_info,
|
utils::application_info,
|
||||||
])
|
])
|
||||||
.on_window_event(|event| match event.event() {
|
.on_window_event(|event| match event.event() {
|
||||||
|
|
|
@ -1,14 +1,8 @@
|
||||||
|
use sqlx::Row;
|
||||||
use tauri::State;
|
use tauri::State;
|
||||||
|
|
||||||
use crate::kanji::KanjiDb;
|
use crate::kanji::KanjiDb;
|
||||||
|
|
||||||
#[derive(Debug, Derivative, Serialize, Deserialize)]
|
|
||||||
#[derivative(Default)]
|
|
||||||
pub struct GetVocabOptions {
|
|
||||||
#[serde(default)]
|
|
||||||
kanji_id: Option<u32>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct Vocab {
|
pub struct Vocab {
|
||||||
kanji_writing: String,
|
kanji_writing: String,
|
||||||
|
@ -21,8 +15,16 @@ pub struct Vocab {
|
||||||
frequency_rank: u32,
|
frequency_rank: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Derivative, Serialize, Deserialize)]
|
||||||
|
#[derivative(Default)]
|
||||||
|
pub struct GetVocabOptions {
|
||||||
|
#[serde(default)]
|
||||||
|
kanji_id: Option<u32>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct GetVocabResult {
|
pub struct GetVocabResult {
|
||||||
|
count: u32,
|
||||||
vocab: Vec<Vocab>,
|
vocab: Vec<Vocab>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,5 +35,46 @@ pub async fn get_vocab(
|
||||||
) -> Result<GetVocabResult, String> {
|
) -> Result<GetVocabResult, String> {
|
||||||
let opts = options.unwrap_or_default();
|
let opts = options.unwrap_or_default();
|
||||||
|
|
||||||
Ok(GetVocabResult { vocab: vec![] })
|
let query_string = format!(
|
||||||
|
r#"
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
|
// Count query
|
||||||
|
let count = {
|
||||||
|
let kanji_filter_clause = match opts.kanji_id {
|
||||||
|
Some(_) => format!(
|
||||||
|
r#"
|
||||||
|
JOIN KanjiEntityVocabEntity ON KanjiEntityVocabEntity.Vocabs_ID = VocabSet.ID
|
||||||
|
WHERE KanjiEntityVocabEntity.Kanji_ID = ?
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
None => String::new(),
|
||||||
|
};
|
||||||
|
let count_query_string = format!(
|
||||||
|
r#"
|
||||||
|
SELECT COUNT(*) AS Count
|
||||||
|
FROM VocabSet
|
||||||
|
{kanji_filter_clause}
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"count query: {count_query_string}\n bind {:?}",
|
||||||
|
opts.kanji_id
|
||||||
|
);
|
||||||
|
let mut count_query = sqlx::query(&count_query_string);
|
||||||
|
if let Some(kanji_id) = opts.kanji_id {
|
||||||
|
count_query = count_query.bind(kanji_id);
|
||||||
|
}
|
||||||
|
let row = count_query
|
||||||
|
.fetch_one(&kanji_db.0)
|
||||||
|
.await
|
||||||
|
.map_err(|err| err.to_string())?;
|
||||||
|
row.get("Count")
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(GetVocabResult {
|
||||||
|
count,
|
||||||
|
vocab: vec![],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Link, RouterProvider, createHashRouter } from "react-router-dom";
|
import { Link, RouterProvider } from "react-router-dom";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { ChakraProvider, Flex } from "@chakra-ui/react";
|
import { ChakraProvider, Flex } from "@chakra-ui/react";
|
||||||
import { createBrowserRouter } from "react-router-dom";
|
import { createBrowserRouter } from "react-router-dom";
|
||||||
|
|
|
@ -1,12 +1,8 @@
|
||||||
import { Button, Grid, GridItem, Stat, StatLabel, StatNumber, Tooltip } from "@chakra-ui/react";
|
import { Button, Grid, GridItem, Stat, StatLabel, StatNumber, Tooltip } from "@chakra-ui/react";
|
||||||
import { ArrowRightIcon } from "@chakra-ui/icons";
|
import { ArrowRightIcon } from "@chakra-ui/icons";
|
||||||
import styles from "./DashboardReviewStats.module.scss";
|
|
||||||
import useSWR from "swr";
|
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import ConditionalWrapper from "./utils/ConditionalWrapper";
|
import ConditionalWrapper from "./utils/ConditionalWrapper";
|
||||||
import ReactTimeago, { Formatter } from "react-timeago";
|
import ReactTimeago, { Formatter } from "react-timeago";
|
||||||
import { isValid } from "date-fns";
|
|
||||||
import { SrsStats } from "../panes/SrsPane";
|
import { SrsStats } from "../panes/SrsPane";
|
||||||
|
|
||||||
export interface DashboardReviewStatsProps {
|
export interface DashboardReviewStatsProps {
|
||||||
|
@ -15,7 +11,7 @@ export interface DashboardReviewStatsProps {
|
||||||
|
|
||||||
interface Stat {
|
interface Stat {
|
||||||
label: string;
|
label: string;
|
||||||
value: any;
|
value: string | number | JSX.Element;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function DashboardReviewStats({ srsStats }: DashboardReviewStatsProps) {
|
export default function DashboardReviewStats({ srsStats }: DashboardReviewStatsProps) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
$kanjiDisplaySize: 120px;
|
$kanjiDisplaySize: 120px;
|
||||||
|
|
||||||
.main {
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
|
@ -79,8 +82,15 @@ $kanjiDisplaySize: 120px;
|
||||||
|
|
||||||
.vocabSection {
|
.vocabSection {
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
font-size: 1.5em;
|
font-size: 1.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vocabList {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import SelectOnClick from "./utils/SelectOnClick";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import Strokes from "./Strokes";
|
import Strokes from "./Strokes";
|
||||||
import SrsPart from "./SrsPart";
|
import SrsPart from "./SrsPart";
|
||||||
|
import VocabList from "./VocabList";
|
||||||
|
|
||||||
interface KanjiDisplayProps {
|
interface KanjiDisplayProps {
|
||||||
kanjiCharacter: string;
|
kanjiCharacter: string;
|
||||||
|
@ -44,11 +45,6 @@ export default function KanjiDisplay({ kanjiCharacter }: KanjiDisplayProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<details>
|
|
||||||
<summary>Debug</summary>
|
|
||||||
<pre>{JSON.stringify(kanji, null, 2)}</pre>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<main className={styles.main}>
|
<main className={styles.main}>
|
||||||
<div className={styles.topRow}>
|
<div className={styles.topRow}>
|
||||||
<SelectOnClick className={styles.display}>{kanji.character}</SelectOnClick>
|
<SelectOnClick className={styles.display}>{kanji.character}</SelectOnClick>
|
||||||
|
@ -89,6 +85,8 @@ export default function KanjiDisplay({ kanjiCharacter }: KanjiDisplayProps) {
|
||||||
|
|
||||||
<div className={styles.vocabSection}>
|
<div className={styles.vocabSection}>
|
||||||
<h2>Related Vocab</h2>
|
<h2>Related Vocab</h2>
|
||||||
|
|
||||||
|
<VocabList kanjiId={kanji.id} className={styles.vocabList} />
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
import { GetKanjiResult } from "../panes/KanjiPane";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { Badge, Grid, GridItem } from "@chakra-ui/layout";
|
import { Badge, Grid, GridItem } from "@chakra-ui/layout";
|
||||||
import styles from "./KanjiList.module.scss";
|
import styles from "./KanjiList.module.scss";
|
||||||
import { Kanji } from "../lib/kanji";
|
import { Kanji } from "../lib/kanji";
|
||||||
import { Input, Spinner } from "@chakra-ui/react";
|
import { Spinner } from "@chakra-ui/react";
|
||||||
import { useCallback, useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import SearchBar from "./SearchBar";
|
|
||||||
import LevelBadge from "./utils/LevelBadge";
|
import LevelBadge from "./utils/LevelBadge";
|
||||||
|
|
||||||
export interface KanjiListProps {
|
export interface KanjiListProps {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { SearchIcon } from "@chakra-ui/icons";
|
import { SearchIcon } from "@chakra-ui/icons";
|
||||||
import { Input, InputGroup, InputRightElement, Spinner } from "@chakra-ui/react";
|
import { Input, InputGroup, InputRightElement, Spinner } from "@chakra-ui/react";
|
||||||
import { FormEvent, useEffect, useState } from "react";
|
import { FormEvent, useState } from "react";
|
||||||
|
|
||||||
export interface SearchBarProps {
|
export interface SearchBarProps {
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
|
|
15
src/components/VocabList.module.scss
Normal file
15
src/components/VocabList.module.scss
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vocabList {
|
||||||
|
flex-grow: 1;
|
||||||
|
border: 1px solid lightgray;
|
||||||
|
padding: 12px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
36
src/components/VocabList.tsx
Normal file
36
src/components/VocabList.tsx
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
import { Input, StylesProvider } from "@chakra-ui/react";
|
||||||
|
import { GetVocabResult } from "../lib/vocab";
|
||||||
|
import { invoke } from "@tauri-apps/api";
|
||||||
|
import useSWR from "swr";
|
||||||
|
import styles from "./VocabList.module.scss";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
export interface VocabListProps {
|
||||||
|
kanjiId?: number;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function VocabList({ className, kanjiId }: VocabListProps) {
|
||||||
|
const { data, isLoading, error } = useSWR(["get_vocab", kanjiId], () =>
|
||||||
|
invoke<GetVocabResult>("get_vocab", {
|
||||||
|
options: { kanji_id: kanjiId },
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
console.error(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main className={classNames(styles.main, className)}>
|
||||||
|
<Input placeholder="Filter..." autoFocus />
|
||||||
|
|
||||||
|
<div>
|
||||||
|
Displaying {data.vocab.length} of {data.count} results. ({kanjiId})
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.vocabList}></div>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
3
src/components/utils/LevelBadge.module.scss
Normal file
3
src/components/utils/LevelBadge.module.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.badge {
|
||||||
|
user-select: none;
|
||||||
|
}
|
|
@ -1,11 +1,14 @@
|
||||||
import { Badge, BadgeProps } from "@chakra-ui/react";
|
import { Badge, BadgeProps } from "@chakra-ui/react";
|
||||||
import { srsLevels } from "../../lib/srs";
|
import { srsLevels } from "../../lib/srs";
|
||||||
|
import classNames from "classnames";
|
||||||
|
|
||||||
|
import styles from "./LevelBadge.module.scss";
|
||||||
|
|
||||||
export interface LevelBadgeProps extends BadgeProps {
|
export interface LevelBadgeProps extends BadgeProps {
|
||||||
grade?: number;
|
grade?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function LevelBadge({ grade, ...props }: LevelBadgeProps) {
|
export default function LevelBadge({ grade, className, ...props }: LevelBadgeProps) {
|
||||||
if (grade == undefined) return null;
|
if (grade == undefined) return null;
|
||||||
|
|
||||||
const levelInfo = srsLevels.get(grade);
|
const levelInfo = srsLevels.get(grade);
|
||||||
|
@ -14,7 +17,12 @@ export default function LevelBadge({ grade, ...props }: LevelBadgeProps) {
|
||||||
const { color, name } = levelInfo;
|
const { color, name } = levelInfo;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Badge backgroundColor={color} color="white" {...props}>
|
<Badge
|
||||||
|
backgroundColor={color}
|
||||||
|
color="white"
|
||||||
|
className={classNames(styles.badge, className)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
{name}
|
{name}
|
||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
export interface Kanji {
|
export interface Kanji {
|
||||||
|
id: number;
|
||||||
character: string;
|
character: string;
|
||||||
meanings: KanjiMeaning[];
|
meanings: KanjiMeaning[];
|
||||||
|
|
||||||
|
|
6
src/lib/vocab.ts
Normal file
6
src/lib/vocab.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export interface GetVocabResult {
|
||||||
|
count: number;
|
||||||
|
vocab: Vocab[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Vocab {}
|
|
@ -8,9 +8,10 @@
|
||||||
gap: 16px;
|
gap: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.kanji-pane-list {
|
.kanjiPaneList {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
min-width: 280px;
|
min-width: 280px;
|
||||||
|
@ -19,3 +20,13 @@
|
||||||
.right-side {
|
.right-side {
|
||||||
flex-grow: 5;
|
flex-grow: 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.searchContainer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.advancedSearch {
|
||||||
|
font-size: 0.8em;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from "@tauri-apps/api/tauri";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import { Box, Flex, Grid, GridItem, LinkBox, Stack } from "@chakra-ui/layout";
|
import { Box, Flex } from "@chakra-ui/layout";
|
||||||
|
|
||||||
import styles from "./KanjiPane.module.scss";
|
import styles from "./KanjiPane.module.scss";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
|
@ -9,6 +9,7 @@ import { Kanji } from "../lib/kanji";
|
||||||
import { KanjiList } from "../components/KanjiList";
|
import { KanjiList } from "../components/KanjiList";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import SearchBar from "../components/SearchBar";
|
import SearchBar from "../components/SearchBar";
|
||||||
|
import { QuestionIcon, UpDownIcon } from "@chakra-ui/icons";
|
||||||
|
|
||||||
export interface GetKanjiResult {
|
export interface GetKanjiResult {
|
||||||
count: number;
|
count: number;
|
||||||
|
@ -55,9 +56,17 @@ export function Component() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex className={styles["kanji-pane-container"]}>
|
<Flex className={styles["kanji-pane-container"]}>
|
||||||
<Box className={styles["kanji-pane-list"]}>
|
<Box className={styles.kanjiPaneList}>
|
||||||
<div className={styles["search-container"]}>
|
<div className={styles.searchContainer}>
|
||||||
<SearchBar isLoading={isLoading} setSearchQuery={setSearchQuery} />
|
<SearchBar isLoading={isLoading} setSearchQuery={setSearchQuery} />
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary className={styles.advancedSearch}>Advanced</summary>
|
||||||
|
|
||||||
|
<a href="">
|
||||||
|
Help <QuestionIcon />
|
||||||
|
</a>
|
||||||
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{kanjiList && (
|
{kanjiList && (
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from "@tauri-apps/api/tauri";
|
||||||
import useSWR, { useSWRConfig } from "swr";
|
import useSWR from "swr";
|
||||||
import SelectOnClick from "../components/utils/SelectOnClick";
|
import SelectOnClick from "../components/utils/SelectOnClick";
|
||||||
|
|
||||||
interface ApplicationInfo {
|
interface ApplicationInfo {
|
||||||
|
|
|
@ -20,11 +20,11 @@ export interface SrsStats {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Component() {
|
export function Component() {
|
||||||
const {
|
const { data: srsStats, error } = useSWR(["get_srs_stats"], ([command]) =>
|
||||||
data: srsStats,
|
invoke<SrsStats>(command),
|
||||||
error,
|
);
|
||||||
isLoading,
|
|
||||||
} = useSWR(["get_srs_stats"], ([command]) => invoke<SrsStats>(command));
|
if (error) console.error(error);
|
||||||
|
|
||||||
if (!srsStats) return <>Loading...</>;
|
if (!srsStats) return <>Loading...</>;
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,11 @@
|
||||||
import {
|
import { Button, Container, Progress, Spinner, useDisclosure } from "@chakra-ui/react";
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Input,
|
|
||||||
InputGroup,
|
|
||||||
InputLeftElement,
|
|
||||||
InputRightElement,
|
|
||||||
Progress,
|
|
||||||
Spinner,
|
|
||||||
useDisclosure,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import styles from "./SrsReviewPane.module.scss";
|
import styles from "./SrsReviewPane.module.scss";
|
||||||
import { ChangeEvent, FormEvent, useEffect, useState } from "react";
|
import { FormEvent, useEffect, useState } from "react";
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from "@tauri-apps/api/tauri";
|
||||||
import { Link, ScrollRestoration, useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import { ArrowBackIcon } from "@chakra-ui/icons";
|
import { ArrowBackIcon } from "@chakra-ui/icons";
|
||||||
import ConfirmQuitModal from "../components/utils/ConfirmQuitModal";
|
import ConfirmQuitModal from "../components/utils/ConfirmQuitModal";
|
||||||
import * as _ from "lodash-es";
|
import * as _ from "lodash-es";
|
||||||
import { romajiToKana } from "../lib/kanaHelper";
|
|
||||||
import {
|
import {
|
||||||
ReviewItem,
|
ReviewItem,
|
||||||
ReviewItemType,
|
ReviewItemType,
|
||||||
|
@ -26,12 +15,9 @@ import {
|
||||||
groupUpdatedLevel,
|
groupUpdatedLevel,
|
||||||
isGroupCorrect,
|
isGroupCorrect,
|
||||||
} from "../lib/srs";
|
} from "../lib/srs";
|
||||||
import classNames from "classnames";
|
|
||||||
import InputBox from "../components/srsReview/InputBox";
|
import InputBox from "../components/srsReview/InputBox";
|
||||||
import SelectOnClick from "../components/utils/SelectOnClick";
|
import SelectOnClick from "../components/utils/SelectOnClick";
|
||||||
|
|
||||||
const batchSize = 10;
|
|
||||||
|
|
||||||
export function Component() {
|
export function Component() {
|
||||||
// null = has not started, (.length == 0) = finished
|
// null = has not started, (.length == 0) = finished
|
||||||
const [reviewQueue, setReviewQueue] = useState<ReviewItem[] | null>(null);
|
const [reviewQueue, setReviewQueue] = useState<ReviewItem[] | null>(null);
|
||||||
|
@ -124,7 +110,7 @@ export function Component() {
|
||||||
delay: newLevel.delay,
|
delay: newLevel.delay,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = await invoke("update_srs_item", params);
|
await invoke("update_srs_item", params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it's wrong this time
|
// If it's wrong this time
|
||||||
|
|
4
src/panes/VocabPane.module.scss
Normal file
4
src/panes/VocabPane.module.scss
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.main {
|
||||||
|
width: 100%;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
|
@ -1,5 +1,12 @@
|
||||||
|
import VocabList from "../components/VocabList";
|
||||||
|
import styles from "./VocabPane.module.scss";
|
||||||
|
|
||||||
export function Component() {
|
export function Component() {
|
||||||
return <></>;
|
return (
|
||||||
|
<main className={styles.main}>
|
||||||
|
<VocabList />
|
||||||
|
</main>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.displayName = "VocabPane";
|
Component.displayName = "VocabPane";
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
|
||||||
export default {
|
|
||||||
content: ["./src/**/*.{html,js,jsx,ts,tsx}", "./node_modules/flowbite/**/*.js"],
|
|
||||||
|
|
||||||
theme: {
|
|
||||||
extend: {},
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [require("flowbite/plugin")],
|
|
||||||
};
|
|
Loading…
Reference in a new issue