From fbbfd024f489f9694286b59c92e35f5e6a39a2b7 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Tue, 1 Oct 2024 19:37:55 +0200 Subject: [PATCH] Init --- .eslintrc.json | 20 + .github/workflows/node.js.yml | 30 + .gitignore | 40 + LICENSE | 21 + Procfile | 1 + README.md | 15 + app/componets/center.tsx | 11 + app/componets/footer.tsx | 18 + app/componets/github_ribbon.tsx | 38 + app/globals.css | 62 + app/kanji/[level]/page.tsx | 136 + app/layout.tsx | 34 + app/page.tsx | 73 + app/wanikani/WaniKani.ts | 50 + next.config.mjs | 4 + package-lock.json | 8844 +++++++++++++++++++++++++++++++ package.json | 35 + postcss.config.mjs | 8 + providers.tsx | 17 + tailwind.config.ts | 22 + tsconfig.json | 26 + 21 files changed, 9505 insertions(+) create mode 100644 .eslintrc.json create mode 100644 .github/workflows/node.js.yml create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Procfile create mode 100644 README.md create mode 100644 app/componets/center.tsx create mode 100644 app/componets/footer.tsx create mode 100644 app/componets/github_ribbon.tsx create mode 100644 app/globals.css create mode 100644 app/kanji/[level]/page.tsx create mode 100644 app/layout.tsx create mode 100644 app/page.tsx create mode 100644 app/wanikani/WaniKani.ts create mode 100644 next.config.mjs create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 postcss.config.mjs create mode 100644 providers.tsx create mode 100644 tailwind.config.ts create mode 100644 tsconfig.json diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..afa0a3b --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,20 @@ +{ + "extends": [ + "next/core-web-vitals", + "next/typescript" + ], + "rules": { + "semi": [ + 2, + "never" + ], + "quotes": [ + 2, + "single", + { + "avoidEscape": true + } + ], + "@typescript-eslint/no-explicit-any": "off" + } +} \ No newline at end of file diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000..484a8ab --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,30 @@ +# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs + +name: Node.js CI + +on: + push: + branches: [ "master" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [22.x] + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + cache: 'npm' + - run: npm install + - run: npm run lint + - run: npm run build diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..35b6a77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts + + +# WS +.idea diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b6653fc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Ilya Kirillov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..e8f79ea --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: npm start \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0064879 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# 🈷️ Wani Fast Cards + +[🔗 wani-fast-cards.darthorimar.me](https://wani-fast-cards.darthorimar.me/) + +I created this app to briefly review the [WaniKani](https://wanikani.com) kanji at a level where I have unlocked (almost) all of them. It helps me retain kanji better in my memory and stop confusing them with each other :) + +# 🏗️ Building + +The app is hosted at [wani-fast-cards.darthorimar.me](https://wani-fast-cards.darthorimar.me), but it can also be built and run locally. + +The app is written with Next.js and React. + +- Use `npm run dev` to run a development version of the app. +- Use `npm run start` to run a production version of the site. +- Use `npm run build` to create a production build of the site. diff --git a/app/componets/center.tsx b/app/componets/center.tsx new file mode 100644 index 0000000..e8ddfc2 --- /dev/null +++ b/app/componets/center.tsx @@ -0,0 +1,11 @@ +import { ReactNode } from 'react' + +export function Center( + { children }: { children: ReactNode } +) { + return
+
+ {children} +
+
+} \ No newline at end of file diff --git a/app/componets/footer.tsx b/app/componets/footer.tsx new file mode 100644 index 0000000..1d4e3d8 --- /dev/null +++ b/app/componets/footer.tsx @@ -0,0 +1,18 @@ +import { FaGithub, FaGlobe, FaLinkedin } from 'react-icons/fa' + +export function Footer() { + return +} \ No newline at end of file diff --git a/app/componets/github_ribbon.tsx b/app/componets/github_ribbon.tsx new file mode 100644 index 0000000..42b7f15 --- /dev/null +++ b/app/componets/github_ribbon.tsx @@ -0,0 +1,38 @@ +export function GitHubRibbon() { + return + + + + +} diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..e5185c2 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,62 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + color: var(--foreground); + background: var(--background); + font-family: Arial, Helvetica, sans-serif; +} + +@layer utilities { + .text-balance { + text-wrap: balance; + } +} + + +/* */ +.github-corner:hover .octo-arm { + animation: octocat-wave 560ms ease-in-out +} + +@keyframes octocat-wave { + + 0%, + 100% { + transform: rotate(0) + } + + 20%, + 60% { + transform: rotate(-25deg) + } + + 40%, + 80% { + transform: rotate(10deg) + } +} + +@media (max-width:500px) { + .github-corner:hover .octo-arm { + animation: none + } + + .github-corner .octo-arm { + animation: octocat-wave 560ms ease-in-out + } +} +/* */ diff --git a/app/kanji/[level]/page.tsx b/app/kanji/[level]/page.tsx new file mode 100644 index 0000000..af06c4f --- /dev/null +++ b/app/kanji/[level]/page.tsx @@ -0,0 +1,136 @@ +'use client' + +import { Center } from '@/app/componets/center' +import { getKanjiForLevel, getWanikaniStatus, Kanji, WanikaniStatus } from '@/app/wanikani/WaniKani' +import { Button, Card, CardBody } from '@nextui-org/react' +import { useRouter } from 'next/navigation' +import React from 'react' +import { useEffect, useState } from 'react' +import { MdArrowBack } from 'react-icons/md' +import { MdRestartAlt } from 'react-icons/md' + +export default function Page( + { params }: { params: { level: number } } +) { + const [rerenderCount, setRerenderCount] = useState(0) + + function rerender() { + setRerenderCount(c => c + 1) + } + + return <> + +
+ +
+ +} + +function Navigation({ rerender }: { rerender: () => void }) { + const router = useRouter() + return
+ } onPress={() => router.push('/')} /> + } onPress={() => rerender()} /> +
+} + +function ActionButton( + { icon, onPress }: { icon: React.ReactNode, onPress: () => void } +) { + return + + } + + if (status === '3lvl' && level > 3) { + return
+ + Level {level} is inaccessible + +
+ } + + if (status === 'loading') { + return
Loading...
+ } + + return
+

Kanji for level {level}

+ +
+} + +function ErrorCard({ children }: { children: React.ReactNode }) { + return + +

{children}

+
+
+} + +function LearnKanji( + { kanjis, rerender }: { kanjis: Kanji[], rerender: () => void } +) { + const [notShowKanjis, setNotShowKanjis] = useState(kanjis) + const [revealAnswer, setRevealAnswer] = useState(false) + + const router = useRouter() + + if (notShowKanjis.length === 0) { + return
+
Done!
+
+ + +
+
+ } + + return
{ + if (revealAnswer) { + setNotShowKanjis(notShowKanjis.slice(1)) + } + setRevealAnswer(!revealAnswer) + }}> +
{notShowKanjis[0].kanji}
+ {revealAnswer && <> +
{notShowKanjis[0].reading}
+
{notShowKanjis[0].meaning}
+ } + +
+} + +function shuffled(array: T[]): T[] { + const result = [...array] + for (let i = result.length - 1; i >= 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [result[i], result[j]] = [result[j], result[i]] + } + return result +} \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..2f16bb2 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from 'next' +import './globals.css' +import { ReactNode } from 'react' +import { Inter as FontSans } from 'next/font/google' +import clsx from 'clsx' +import { Providers } from '@/providers' + +const fontSans = FontSans({ + subsets: ['latin'], + variable: '--font-sans', +}) + + +export const metadata: Metadata = { + title: 'Wani Fast Kanji' +} + +export default function RootLayout( + { children }: { children: ReactNode } +) { + return ( + + + + {children} + + + + ) +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..766f8bb --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,73 @@ +'use client' + +import { Center } from '@/app/componets/center' +import { Footer } from '@/app/componets/footer' +import { GitHubRibbon } from '@/app/componets/github_ribbon' +import { getWanikaniStatus, useApiKey, WanikaniStatus } from '@/app/wanikani/WaniKani' +import { Button, CircularProgress, Input, Link } from '@nextui-org/react' +import React, { useCallback, useEffect, useRef, useState } from 'react' + +export default function Page() { + const [wanikaniStatus, setWanikaniStatus] = useState('no_key') + return <> + +
+ +
+

Chose Kanji Level

+
+ { + Array.from({ length: 60 }, (_, i) => i + 1) + .map((i) => + + ) + } +
+
+
+