From a3f24ea79b14394b24c4b60a010651eb29eeb872 Mon Sep 17 00:00:00 2001
From: polwex <polwex@sortug.com>
Date: Thu, 29 May 2025 12:10:22 +0700
Subject: glorious new db

---
 src/components/tones/ToneSelectorClient.tsx | 199 ++++++++++++++++++++++++++++
 1 file changed, 199 insertions(+)
 create mode 100644 src/components/tones/ToneSelectorClient.tsx

(limited to 'src/components/tones/ToneSelectorClient.tsx')

diff --git a/src/components/tones/ToneSelectorClient.tsx b/src/components/tones/ToneSelectorClient.tsx
new file mode 100644
index 0000000..0ee9433
--- /dev/null
+++ b/src/components/tones/ToneSelectorClient.tsx
@@ -0,0 +1,199 @@
+'use client';
+
+import { useState, useEffect, useTransition } from 'react';
+import { WordData } from '@/zoom/logic/types';
+import { fetchWordsByToneAndSyllables } from '@/actions/tones';
+import { Button } from '@/components/ui/button';
+import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
+import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
+import { Label } from '@/components/ui/label';
+import { Skeleton } from '@/components/ui/skeleton'; // For loading state
+
+// Helper to display tones prominently
+const ProminentToneDisplay = ({ wordData }: { wordData: WordData }) => {
+  if (!wordData.prosody || !Array.isArray(wordData.prosody)) {
+    return <p className="text-gray-500">No prosody data</p>;
+  }
+
+  return (
+    <div className="flex flex-col items-center mb-4">
+      <h1 className="text-6xl font-bold text-blue-600 mb-2">{wordData.spelling}</h1>
+      <div className="flex space-x-4">
+        {wordData.prosody.map((p, index) => (
+          <div key={index} className="text-center">
+            <p className="text-sm text-gray-500">Syllable {index + 1}</p>
+            <p className="text-5xl font-semibold text-indigo-500">{p.tone ?? '?'}</p>
+          </div>
+        ))}
+      </div>
+      {wordData.ipa && wordData.ipa.length > 0 && (
+        <p className="text-xl text-gray-700 mt-2">
+          {wordData.ipa.map(i => i.ipa).join(' / ')}
+        </p>
+      )}
+    </div>
+  );
+};
+
+
+export default function ToneSelectorClient({ initialWord }: { initialWord: WordData | null }) {
+  const [currentWord, setCurrentWord] = useState<WordData | null>(initialWord);
+  const [syllableCount, setSyllableCount] = useState<number>(initialWord?.syllables || 1);
+  const [selectedTones, setSelectedTones] = useState<(number | null)[]>(
+    initialWord?.prosody?.map(p => p.tone ?? null) || [null]
+  );
+  const [isLoading, startTransition] = useTransition();
+
+  useEffect(() => {
+    // Adjust selectedTones array length when syllableCount changes
+    setSelectedTones(prevTones => {
+      const newTones = Array(syllableCount).fill(null);
+      for (let i = 0; i < Math.min(prevTones.length, syllableCount); i++) {
+        newTones[i] = prevTones[i];
+      }
+      return newTones;
+    });
+  }, [syllableCount]);
+
+  const handleFetchWord = () => {
+    startTransition(async () => {
+      const word = await fetchWordsByToneAndSyllables(syllableCount, selectedTones);
+      setCurrentWord(word);
+    });
+  };
+
+  const handleSyllableCountChange = (value: string) => {
+    const count = parseInt(value, 10);
+    if (!isNaN(count) && count > 0 && count <= 5) { // Max 5 syllables for simplicity
+      setSyllableCount(count);
+    }
+  };
+
+  const handleToneChange = (syllableIndex: number, value: string) => {
+    const tone = value === 'any' ? null : parseInt(value, 10);
+    setSelectedTones(prevTones => {
+      const newTones = [...prevTones];
+      newTones[syllableIndex] = tone;
+      return newTones;
+    });
+  };
+  
+  const thaiTones = [
+    { value: '1', label: '1 (Mid)' },
+    { value: '2', label: '2 (Low)' },
+    { value: '3', label: '3 (Falling)' },
+    { value: '4', label: '4 (High)' },
+    { value: '5', label: '5 (Rising)' },
+  ];
+
+  return (
+    <div className="container mx-auto p-4 max-w-2xl">
+      <Card className="mb-6">
+        <CardHeader>
+          <CardTitle>Thai Tone Explorer</CardTitle>
+          <CardDescription>Select syllable count and tones to find Thai words.</CardDescription>
+        </CardHeader>
+        <CardContent className="space-y-6">
+          <div>
+            <Label htmlFor="syllable-count" className="text-lg font-medium">Number of Syllables</Label>
+            <Select
+              value={syllableCount.toString()}
+              onValueChange={handleSyllableCountChange}
+            >
+              <SelectTrigger id="syllable-count" className="w-full md:w-1/2 mt-1">
+                <SelectValue placeholder="Select number of syllables" />
+              </SelectTrigger>
+              <SelectContent>
+                {[1, 2, 3, 4, 5].map(num => (
+                  <SelectItem key={num} value={num.toString()}>
+                    {num} Syllable{num > 1 ? 's' : ''}
+                  </SelectItem>
+                ))}
+              </SelectContent>
+            </Select>
+          </div>
+
+          {Array.from({ length: syllableCount }).map((_, index) => (
+            <div key={index}>
+              <Label htmlFor={`tone-select-${index}`} className="text-lg font-medium">
+                Tone for Syllable {index + 1}
+              </Label>
+              <Select
+                value={selectedTones[index]?.toString() || 'any'}
+                onValueChange={(value) => handleToneChange(index, value)}
+              >
+                <SelectTrigger id={`tone-select-${index}`} className="w-full md:w-1/2 mt-1">
+                  <SelectValue placeholder={`Select tone for syllable ${index + 1}`} />
+                </SelectTrigger>
+                <SelectContent>
+                  <SelectItem value="any">Any Tone</SelectItem>
+                  {thaiTones.map(tone => (
+                    <SelectItem key={tone.value} value={tone.value}>
+                      {tone.label}
+                    </SelectItem>
+                  ))}
+                </SelectContent>
+              </Select>
+            </div>
+          ))}
+        </CardContent>
+        <CardFooter>
+          <Button onClick={handleFetchWord} disabled={isLoading} className="w-full md:w-auto">
+            {isLoading ? 'Searching...' : 'Find Word'}
+          </Button>
+        </CardFooter>
+      </Card>
+
+      {isLoading && !currentWord && (
+        <Card>
+          <CardHeader><Skeleton className="h-12 w-3/4" /></CardHeader>
+          <CardContent className="space-y-4">
+            <Skeleton className="h-8 w-1/2" />
+            <Skeleton className="h-20 w-full" />
+            <Skeleton className="h-6 w-full" />
+          </CardContent>
+        </Card>
+      )}
+
+      {!isLoading && currentWord && (
+        <Card>
+          <CardHeader>
+            <CardTitle className="text-center">Current Word</CardTitle>
+          </CardHeader>
+          <CardContent>
+            <ProminentToneDisplay wordData={currentWord} />
+            {/* You can add more details from WordData here if needed, like definitions */}
+            {currentWord.senses && currentWord.senses.length > 0 && (
+              <div className="mt-4 pt-4 border-t">
+                <h3 className="text-lg font-semibold mb-2">Meanings:</h3>
+                {currentWord.senses.map((sense, sIdx) => (
+                  <div key={sIdx} className="mb-2 p-2 border rounded bg-gray-50">
+                    <p className="font-medium text-indigo-600">{sense.pos}</p>
+                    {sense.senses && Array.isArray(sense.senses) && sense.senses.map((subSense, ssIdx) => (
+                       subSense.glosses && Array.isArray(subSense.glosses) && subSense.glosses.map((gloss: string, gIdx: number) => (
+                        <p key={`${ssIdx}-${gIdx}`} className="text-sm text-gray-700 ml-2">- {gloss}</p>
+                       ))
+                    ))}
+                  </div>
+                ))}
+              </div>
+            )}
+          </CardContent>
+        </Card>
+      )}
+
+      {!isLoading && !currentWord && (
+        <Card>
+          <CardHeader>
+            <CardTitle className="text-center">No Word Found</CardTitle>
+          </CardHeader>
+          <CardContent>
+            <p className="text-center text-gray-600">
+              Could not find a Thai word matching your criteria. Try different selections.
+            </p>
+          </CardContent>
+        </Card>
+      )}
+    </div>
+  );
+}
-- 
cgit v1.2.3

