upd
This commit is contained in:
parent
779fc69405
commit
15cbfeb0d6
23 changed files with 4679 additions and 204 deletions
7
.prettierrc.json5
Normal file
7
.prettierrc.json5
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
useTabs: false,
|
||||||
|
tabWidth: 2,
|
||||||
|
singleQuote: false,
|
||||||
|
trailingComma: "all",
|
||||||
|
printWidth: 100,
|
||||||
|
}
|
4481
package-lock.json
generated
4481
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -10,7 +10,13 @@
|
||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@chakra-ui/react": "^2.7.0",
|
||||||
|
"@emotion/react": "^11.11.1",
|
||||||
|
"@emotion/styled": "^11.11.0",
|
||||||
"@tauri-apps/api": "^1.3.0",
|
"@tauri-apps/api": "^1.3.0",
|
||||||
|
"classnames": "^2.3.2",
|
||||||
|
"flowbite": "^1.6.5",
|
||||||
|
"framer-motion": "^10.12.16",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router": "^6.11.2",
|
"react-router": "^6.11.2",
|
||||||
|
@ -23,7 +29,10 @@
|
||||||
"@types/react": "^18.0.15",
|
"@types/react": "^18.0.15",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.6",
|
||||||
"@vitejs/plugin-react": "^3.0.0",
|
"@vitejs/plugin-react": "^3.0.0",
|
||||||
|
"autoprefixer": "^10.4.14",
|
||||||
|
"postcss": "^8.4.24",
|
||||||
"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"
|
||||||
}
|
}
|
||||||
|
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
36
src-tauri/Cargo.lock
generated
36
src-tauri/Cargo.lock
generated
|
@ -1656,12 +1656,46 @@ version = "1.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libappindicator"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "db2d3cb96d092b4824cb306c9e544c856a4cb6210c1081945187f7f1924b47e8"
|
||||||
|
dependencies = [
|
||||||
|
"glib",
|
||||||
|
"gtk",
|
||||||
|
"gtk-sys",
|
||||||
|
"libappindicator-sys",
|
||||||
|
"log",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libappindicator-sys"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1b3b6681973cea8cc3bce7391e6d7d5502720b80a581c9a95c9cbaf592826aa"
|
||||||
|
dependencies = [
|
||||||
|
"gtk-sys",
|
||||||
|
"libloading",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.145"
|
version = "0.2.145"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc86cde3ff845662b8f4ef6cb50ea0e20c524eb3d29ae048287e06a1b3fa6a81"
|
checksum = "fc86cde3ff845662b8f4ef6cb50ea0e20c524eb3d29ae048287e06a1b3fa6a81"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libloading"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libsqlite3-sys"
|
name = "libsqlite3-sys"
|
||||||
version = "0.24.2"
|
version = "0.24.2"
|
||||||
|
@ -3048,6 +3082,7 @@ dependencies = [
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
"core-graphics",
|
"core-graphics",
|
||||||
"crossbeam-channel",
|
"crossbeam-channel",
|
||||||
|
"dirs-next",
|
||||||
"dispatch",
|
"dispatch",
|
||||||
"gdk",
|
"gdk",
|
||||||
"gdk-pixbuf",
|
"gdk-pixbuf",
|
||||||
|
@ -3062,6 +3097,7 @@ dependencies = [
|
||||||
"instant",
|
"instant",
|
||||||
"jni",
|
"jni",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
"libappindicator",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
|
|
|
@ -14,7 +14,7 @@ members = ["database-maker"]
|
||||||
tauri-build = { version = "1.3", features = [] }
|
tauri-build = { version = "1.3", features = [] }
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tauri = { version = "1.3", features = ["shell-open"] }
|
tauri = { version = "1.3", features = ["shell-open", "system-tray"] }
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
dirs = "5.0.1"
|
dirs = "5.0.1"
|
||||||
|
|
|
@ -6,14 +6,24 @@ 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
|
||||||
|
character: Option<String>,
|
||||||
|
|
||||||
#[derivative(Default(value = "10"))]
|
#[derivative(Default(value = "10"))]
|
||||||
how_many: u32,
|
how_many: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Kanji {
|
||||||
|
character: String,
|
||||||
|
meaning: String,
|
||||||
|
most_used_rank: u32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
pub struct GetKanjiResult {
|
pub struct GetKanjiResult {
|
||||||
count: u32,
|
count: u32,
|
||||||
kanji: Vec<String>,
|
kanji: Vec<Kanji>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
|
@ -24,18 +34,33 @@ pub async fn get_kanji(
|
||||||
let opts = options.unwrap_or_default();
|
let opts = options.unwrap_or_default();
|
||||||
|
|
||||||
let result = sqlx::query(
|
let result = sqlx::query(
|
||||||
r#"SELECT * FROM KanjiSet
|
r#"
|
||||||
|
SELECT * FROM KanjiSet
|
||||||
LEFT JOIN KanjiMeaningSet ON KanjiSet.ID = KanjiMeaningSet.Kanji_ID
|
LEFT JOIN KanjiMeaningSet ON KanjiSet.ID = KanjiMeaningSet.Kanji_ID
|
||||||
WHERE MostUsedRank IS NOT NULL
|
GROUP BY KanjiSet.ID
|
||||||
|
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(&state.0)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| ())?;
|
.map_err(|_| ())?;
|
||||||
|
|
||||||
let kanji = result.into_iter().map(|row| row.get("Character")).collect();
|
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 count = sqlx::query("SELECT COUNT(*) FROM KanjiSet")
|
let count = sqlx::query("SELECT COUNT(*) FROM KanjiSet")
|
||||||
.fetch_one(&state.0)
|
.fetch_one(&state.0)
|
||||||
|
|
|
@ -15,6 +15,7 @@ use sqlx::{
|
||||||
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
sqlite::{SqliteConnectOptions, SqlitePoolOptions},
|
||||||
SqlitePool,
|
SqlitePool,
|
||||||
};
|
};
|
||||||
|
use tauri::SystemTray;
|
||||||
|
|
||||||
use crate::kanji::KanjiDb;
|
use crate::kanji::KanjiDb;
|
||||||
|
|
||||||
|
@ -26,14 +27,20 @@ fn greet(name: &str) -> String {
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
|
// Open kanji db
|
||||||
let kanji_db_options =
|
let kanji_db_options =
|
||||||
SqliteConnectOptions::from_str("./KanjiDatabase.sqlite")?.read_only(true);
|
SqliteConnectOptions::from_str("./KanjiDatabase.sqlite")?.read_only(true);
|
||||||
let kanji_pool = SqlitePoolOptions::new()
|
let kanji_pool = SqlitePoolOptions::new()
|
||||||
.connect_with(kanji_db_options)
|
.connect_with(kanji_db_options)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
// System tray
|
||||||
|
let tray = SystemTray::new();
|
||||||
|
|
||||||
|
// Build tauri
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.manage(KanjiDb(kanji_pool))
|
.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])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.context("error while running tauri application")?;
|
.context("error while running tauri application")?;
|
||||||
|
|
|
@ -33,6 +33,10 @@
|
||||||
"security": {
|
"security": {
|
||||||
"csp": null
|
"csp": null
|
||||||
},
|
},
|
||||||
|
"systemTray": {
|
||||||
|
"iconPath": "icons/icon.ico",
|
||||||
|
"iconAsTemplate": true
|
||||||
|
},
|
||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
"fullscreen": false,
|
"fullscreen": false,
|
||||||
|
|
|
@ -1,11 +1,23 @@
|
||||||
|
main.main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
|
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
|
}
|
||||||
li {
|
|
||||||
padding-left: 0;
|
.link {
|
||||||
}
|
flex-grow: 1;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.link-active {
|
||||||
|
background-color: skyblue;
|
||||||
}
|
}
|
42
src/App.tsx
42
src/App.tsx
|
@ -1,23 +1,35 @@
|
||||||
import { Link, RouterProvider, createHashRouter } from "react-router-dom";
|
import { Link, RouterProvider, createHashRouter } from "react-router-dom";
|
||||||
import styles from "./App.module.scss";
|
|
||||||
import KanjiPane from "./panes/KanjiPane";
|
import KanjiPane from "./panes/KanjiPane";
|
||||||
|
import classNames from "classnames";
|
||||||
|
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 } from "react-router";
|
import { Outlet, Route, createRoutesFromElements, useLocation } from "react-router";
|
||||||
|
import SrsPane from "./panes/SrsPane";
|
||||||
|
import VocabPane from "./panes/VocabPane";
|
||||||
|
import SettingsPane from "./panes/SettingsPane";
|
||||||
|
import { StrictMode } from "react";
|
||||||
|
|
||||||
|
import styles from "./App.module.scss";
|
||||||
|
|
||||||
function Layout() {
|
function Layout() {
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<main className={styles.main}>
|
||||||
<ul className={styles.header}>
|
<ul className={styles.header}>
|
||||||
{routes.map((route) => (
|
{routes.map((route) => {
|
||||||
<li key={route.path}>
|
if (!route.title) return undefined;
|
||||||
<Link to={route.path}>{route.title}</Link>
|
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>
|
</li>
|
||||||
))}
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<Outlet />
|
<Outlet />
|
||||||
</>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,10 +49,18 @@ export default function App() {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
return <RouterProvider router={router} />;
|
return <StrictMode>
|
||||||
|
<ChakraProvider>
|
||||||
|
<RouterProvider router={router} />
|
||||||
|
</ChakraProvider>
|
||||||
|
</StrictMode>
|
||||||
}
|
}
|
||||||
|
|
||||||
const routes = [
|
const routes = [
|
||||||
{ path: "/", title: "Home", element: <HomePane /> },
|
{ key: "home", path: "/", title: "Home", element: <HomePane /> },
|
||||||
{ path: "/kanji", title: "Kanji", element: <KanjiPane /> },
|
{ key: "srs", path: "/srs", title: "SRS", element: <SrsPane /> },
|
||||||
|
{ key: "kanji", path: "/kanji", title: "Kanji", element: <KanjiPane /> },
|
||||||
|
{ key: "kanjiSelected", path: "/kanji/:selectedKanji", element: <KanjiPane /> },
|
||||||
|
{ key: "vocab", path: "/vocab", title: "Vocab", element: <VocabPane /> },
|
||||||
|
{ key: "settings", path: "/settings", title: "Settings", element: <SettingsPane /> },
|
||||||
];
|
];
|
||||||
|
|
10
src/components/KanjiDisplay.module.scss
Normal file
10
src/components/KanjiDisplay.module.scss
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
$kanjiDisplaySize: 80px;
|
||||||
|
|
||||||
|
.display {
|
||||||
|
border: 1px solid rgb(87, 87, 210);
|
||||||
|
width: $kanjiDisplaySize;
|
||||||
|
height: $kanjiDisplaySize;
|
||||||
|
font-size: $kanjiDisplaySize * 0.8;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
19
src/components/KanjiDisplay.tsx
Normal file
19
src/components/KanjiDisplay.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { invoke } from "@tauri-apps/api/tauri";
|
||||||
|
import { GetKanjiResult } from "../panes/KanjiPane";
|
||||||
|
import { Kanji } from "../types/Kanji"
|
||||||
|
import styles from "./KanjiDisplay.module.scss"
|
||||||
|
import useSWR from "swr";
|
||||||
|
|
||||||
|
interface KanjiDisplayProps {
|
||||||
|
kanjiCharacter: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function KanjiDisplay({ kanjiCharacter }: KanjiDisplayProps) {
|
||||||
|
const { data, error, isLoading } = useSWR(["get_kanji", kanjiCharacter], invoke<GetKanjiResult>);
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className={styles.display}>
|
||||||
|
{kanjiCharacter}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
|
@ -1,3 +0,0 @@
|
||||||
export default function KanjiSearch() {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from "react-dom/client";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
$kanjiDisplaySize: 80px;
|
.kanji-list {
|
||||||
|
display: flex;
|
||||||
.kanjiDisplay {
|
flex-direction: column;
|
||||||
border: 1px solid rgb(87, 87, 210);
|
gap: 2px;
|
||||||
width: $kanjiDisplaySize;
|
}
|
||||||
height: $kanjiDisplaySize;
|
|
||||||
font-size: $kanjiDisplaySize * 0.8;
|
.kanji-link {
|
||||||
text-align: center;
|
padding: 4px 8px;
|
||||||
vertical-align: middle;
|
border: 1px solid lightgray;
|
||||||
}
|
}
|
|
@ -1,36 +1,57 @@
|
||||||
import { useState } from "react";
|
|
||||||
import { Kanji } from "../types/Kanji";
|
|
||||||
import { invoke } from "@tauri-apps/api/tauri";
|
import { invoke } from "@tauri-apps/api/tauri";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
import styles from "./KanjiPane.module.scss";
|
import { Box, Grid, GridItem, LinkBox, Stack } from "@chakra-ui/layout";
|
||||||
|
|
||||||
interface GetKanjiResult {
|
import styles from "./KanjiPane.module.scss";
|
||||||
|
import { Link, useParams } from "react-router-dom";
|
||||||
|
import KanjiDisplay from "../components/KanjiDisplay";
|
||||||
|
import { Kanji } from "../types/Kanji";
|
||||||
|
|
||||||
|
export interface GetKanjiResult {
|
||||||
count: number;
|
count: number;
|
||||||
kanji: string[];
|
kanji: Kanji[];
|
||||||
}
|
}
|
||||||
|
|
||||||
function KanjiList({ data }: { data : GetKanjiResult}) {
|
interface KanjiListProps {
|
||||||
|
data: GetKanjiResult;
|
||||||
|
selectedCharacter: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function KanjiList({ data, selectedCharacter }: KanjiListProps) {
|
||||||
return <>
|
return <>
|
||||||
Displaying {data.kanji.length} of {data.count} results.
|
Displaying {data.kanji.length} of {data.count} results.
|
||||||
|
|
||||||
<ul>
|
{data.kanji.map(kanji => <Link key={kanji.character} className={styles['kanji-link']} to={`/kanji/${kanji.character}`}>
|
||||||
{data.kanji.map(kanji => <li key={kanji}>
|
<Grid
|
||||||
{kanji}
|
templateRows='repeat(2, 1fr)'
|
||||||
</li>)}
|
templateColumns='1fr 3fr'>
|
||||||
</ul>
|
<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() {
|
export default function KanjiPane() {
|
||||||
|
const { selectedKanji } = useParams();
|
||||||
const { data, error, isLoading } = useSWR("get_kanji", invoke<GetKanjiResult>);
|
const { data, error, isLoading } = useSWR("get_kanji", invoke<GetKanjiResult>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{JSON.stringify(error)}
|
{JSON.stringify(error)}
|
||||||
|
{JSON.stringify(selectedKanji)}
|
||||||
|
|
||||||
<div className={styles.kanjiDisplay}></div>
|
<Stack spacing={7} direction='row'>
|
||||||
|
<Box p={2} className={styles['kanji-list']}>
|
||||||
|
{data && <KanjiList data={data} selectedCharacter={selectedKanji} />}
|
||||||
|
</Box>
|
||||||
|
|
||||||
{data && <KanjiList data={data} />}
|
<Box p={5}>
|
||||||
|
{selectedKanji ? <KanjiDisplay kanjiCharacter={selectedKanji} /> : "nothing selected"}
|
||||||
|
</Box>
|
||||||
|
</Stack >
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
3
src/panes/SettingsPane.tsx
Normal file
3
src/panes/SettingsPane.tsx
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function SettingsPane() {
|
||||||
|
return <></>
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
export default function SrsPane() {
|
export default function SrsPane() {
|
||||||
|
return <></>
|
||||||
}
|
}
|
3
src/panes/VocabPane.tsx
Normal file
3
src/panes/VocabPane.tsx
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export default function VocabPane() {
|
||||||
|
return <></>
|
||||||
|
}
|
112
src/styles.css
112
src/styles.css
|
@ -1,109 +1,3 @@
|
||||||
:root {
|
@tailwind base;
|
||||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
@tailwind components;
|
||||||
font-size: 16px;
|
@tailwind utilities;
|
||||||
line-height: 24px;
|
|
||||||
font-weight: 400;
|
|
||||||
|
|
||||||
color: #0f0f0f;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
|
|
||||||
font-synthesis: none;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
-webkit-text-size-adjust: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
margin: 0;
|
|
||||||
padding-top: 10vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo {
|
|
||||||
height: 6em;
|
|
||||||
padding: 1.5em;
|
|
||||||
will-change: filter;
|
|
||||||
transition: 0.75s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logo.tauri:hover {
|
|
||||||
filter: drop-shadow(0 0 2em #24c8db);
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
font-weight: 500;
|
|
||||||
color: #646cff;
|
|
||||||
text-decoration: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #535bf2;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button {
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 0.6em 1.2em;
|
|
||||||
font-size: 1em;
|
|
||||||
font-weight: 500;
|
|
||||||
font-family: inherit;
|
|
||||||
color: #0f0f0f;
|
|
||||||
background-color: #ffffff;
|
|
||||||
transition: border-color 0.25s;
|
|
||||||
box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2);
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
button:hover {
|
|
||||||
border-color: #396cd8;
|
|
||||||
}
|
|
||||||
button:active {
|
|
||||||
border-color: #396cd8;
|
|
||||||
background-color: #e8e8e8;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#greet-input {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
color: #f6f6f6;
|
|
||||||
background-color: #2f2f2f;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #24c8db;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
|
||||||
button {
|
|
||||||
color: #ffffff;
|
|
||||||
background-color: #0f0f0f98;
|
|
||||||
}
|
|
||||||
button:active {
|
|
||||||
background-color: #0f0f0f69;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
export interface Kanji {
|
export interface Kanji {
|
||||||
character: string;
|
character: string;
|
||||||
translation: string;
|
meaning: string;
|
||||||
|
most_used_rank: number;
|
||||||
}
|
}
|
11
tailwind.config.js
Normal file
11
tailwind.config.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/** @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