From 9a1e8af707acec9bfabd4c5be9ba6595d7f14c3e Mon Sep 17 00:00:00 2001 From: polwex Date: Sat, 16 Aug 2025 13:18:51 +0700 Subject: pretty fast gotta say --- src/components/Main.tsx | 6 ++- src/components/tones/ToneSelectorClient.tsx | 65 +++++++++++++++++++++++------ src/pages/tones.tsx | 1 + src/picker/App.tsx | 5 ++- src/styles/globals.css | 32 ++++++++++++++ src/zoom/App.tsx | 4 +- src/zoom/zoom.css | 32 -------------- 7 files changed, 95 insertions(+), 50 deletions(-) diff --git a/src/components/Main.tsx b/src/components/Main.tsx index 3e6f3e7..6be61a3 100644 --- a/src/components/Main.tsx +++ b/src/components/Main.tsx @@ -18,8 +18,9 @@ import { CardHeader, CardTitle, } from "@/components/ui/card"; -import { Loader2 } from "lucide-react"; // Loading spinner import { useRouter } from "waku"; +import { Spinner } from "./ui/spinner"; +import { Loader2 } from "lucide-react"; const SorlangPage: React.FC = () => { const [textValue, setTextValue] = useState(""); @@ -192,7 +193,8 @@ const SorlangPage: React.FC = () => { > {isExtracting ? ( <> - + {/**/} + Extracting... ) : ( diff --git a/src/components/tones/ToneSelectorClient.tsx b/src/components/tones/ToneSelectorClient.tsx index 8a0327c..48580a4 100644 --- a/src/components/tones/ToneSelectorClient.tsx +++ b/src/components/tones/ToneSelectorClient.tsx @@ -1,6 +1,7 @@ "use client"; -import { useState, useEffect, useTransition, useRef } from "react"; +import { Spinner } from "@/components/ui/spinner"; +import { useState, useEffect, useTransition, useRef, useCallback } from "react"; import { WordData } from "@/zoom/logic/types"; import { fetchWordsByToneAndSyllables, @@ -26,7 +27,7 @@ import { Label } from "@/components/ui/label"; import { Skeleton } from "@/components/ui/skeleton"; // For loading state import { MutationOrder, ToneQuery } from "@/lib/types/phonetics"; import { ProsodySyllable } from "@/lib/types/cards"; -import { ArrowLeft, ArrowRight, Loader2, Volume2 } from "lucide-react"; +import { ArrowLeft, ArrowRight, Volume2 } from "lucide-react"; function getColorByTone(tone: string): string { if (tone === "mid") return "blue"; @@ -38,6 +39,7 @@ function getColorByTone(tone: string): string { } // Helper to display tones prominently const ProminentToneDisplay = ({ word }: { word: any }) => { + const [isLoading, setLoading] = useState(false); const tones: string[] = word.tone_sequence.split(","); const syls: string[] = word.syl_seq.split(","); const [isPending, startTransition] = useTransition(); @@ -59,7 +61,7 @@ const ProminentToneDisplay = ({ word }: { word: any }) => { const audioRef = useRef(null); async function playAudio() { - // setLoading(true); + setLoading(true); // const audioContext = new (window.AudioContext || // (window as any).webkitAudioContext)(); // const response = await fetch(audioUrl); @@ -76,11 +78,22 @@ const ProminentToneDisplay = ({ word }: { word: any }) => { const res = await fetch(`/api/tts?word=${word.spelling}&lang=thai`); const audioBlob = await res.blob(); const audioURL = URL.createObjectURL(audioBlob); + setLoading(false); if (audioRef.current) { audioRef.current.src = audioURL; audioRef.current.play(); } } + useEffect(() => { + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === " ") { + e.preventDefault(); + playAudio(); + } + }; + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); + }, [playAudio]); return (
@@ -105,7 +118,7 @@ const ProminentToneDisplay = ({ word }: { word: any }) => { > - {isPending && } + {(isPending || isLoading) && }
diff --git a/src/styles/globals.css b/src/styles/globals.css index 4bc2c75..d22c133 100644 --- a/src/styles/globals.css +++ b/src/styles/globals.css @@ -121,4 +121,36 @@ body { @apply bg-background text-foreground; } +} + +/* Loaders */ +.spinner { + border: 4px solid rgba(0, 0, 0, 0.1); + width: 24px; + height: 24px; + border-radius: 50%; + border-left-color: #09f; + margin: 5px auto; + animation: spin 1s ease infinite; +} + +.mini-spinner { + display: inline-block; + border: 2px solid rgba(0, 0, 0, 0.1); + width: 12px; + height: 12px; + border-radius: 50%; + border-left-color: #09f; + margin: 0 3px; + animation: spin 1s ease infinite; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } } \ No newline at end of file diff --git a/src/zoom/App.tsx b/src/zoom/App.tsx index d41dd7f..8ea3007 100644 --- a/src/zoom/App.tsx +++ b/src/zoom/App.tsx @@ -5,7 +5,7 @@ import FullText from "./FullText"; import "./zoom.css"; import { useZoom, ZoomProvider } from "./hooks/useZoom"; import { NLP } from "sortug-ai"; -import { Loader2 } from "lucide-react"; +import { Spinner } from "@/components/ui/spinner"; const App: React.FC = () => { const { viewState } = useZoom(); @@ -70,7 +70,7 @@ const App: React.FC = () => {
{isLoading ? ( - + ) : spacy ? ( ) : ( diff --git a/src/zoom/zoom.css b/src/zoom/zoom.css index 2c743bd..2887ca2 100644 --- a/src/zoom/zoom.css +++ b/src/zoom/zoom.css @@ -409,38 +409,6 @@ main { background-color: #e0e0e0; } -/* Loaders */ -.spinner { - border: 4px solid rgba(0, 0, 0, 0.1); - width: 24px; - height: 24px; - border-radius: 50%; - border-left-color: #09f; - margin: 5px auto; - animation: spin 1s ease infinite; -} - -.mini-spinner { - display: inline-block; - border: 2px solid rgba(0, 0, 0, 0.1); - width: 12px; - height: 12px; - border-radius: 50%; - border-left-color: #09f; - margin: 0 3px; - animation: spin 1s ease infinite; -} - -@keyframes spin { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } -} - /* Responsive adjustments */ @media (max-width: 768px) { -- cgit v1.2.3