summaryrefslogtreecommitdiff
path: root/src/zoom/ServerSyllable.tsx
diff options
context:
space:
mode:
authorpolwex <polwex@sortug.com>2025-05-29 12:10:22 +0700
committerpolwex <polwex@sortug.com>2025-05-29 12:10:22 +0700
commita3f24ea79b14394b24c4b60a010651eb29eeb872 (patch)
treecb1c4937084116f66a59727ee752afd974714c8e /src/zoom/ServerSyllable.tsx
parent7abf2227438362ad30820ee236405ec1b57a40b6 (diff)
glorious new db
Diffstat (limited to 'src/zoom/ServerSyllable.tsx')
-rw-r--r--src/zoom/ServerSyllable.tsx84
1 files changed, 84 insertions, 0 deletions
diff --git a/src/zoom/ServerSyllable.tsx b/src/zoom/ServerSyllable.tsx
new file mode 100644
index 0000000..907b956
--- /dev/null
+++ b/src/zoom/ServerSyllable.tsx
@@ -0,0 +1,84 @@
+// This is a Server Component
+import React, { Suspense } from "react";
+import db from "@/lib/db";
+import {
+ Card,
+ CardHeader,
+ CardDescription,
+ CardContent,
+ CardFooter,
+ CardTitle,
+} from "@/components/ui/card";
+import { NLP } from "sortug-ai";
+import { Volume2, Link as LinkIcon } from "lucide-react";
+import { isTonal } from "@/lib/lang/utils";
+import { CardResponse, SyllableToken } from "@/lib/types/cards";
+import { deconstructSyllable } from "@/lib/calls/nlp";
+
+export default async function (props: { data: CardResponse }) {
+ const { expression } = props.data;
+ const { result } = await deconstructSyllable(expression.spelling);
+
+ return (
+ <div className="absolute w-full h-full bg-white dark:bg-slate-800 rounded-xl backface-hidden flex flex-col justify-center gap-8 items-center p-6">
+ <p className="text-5xl cursor-pointer hover:text-blue-700 font-semibold text-slate-800 dark:text-slate-100 text-center">
+ {expression.spelling}
+ </p>
+ <Suspense fallback={<IpaDisplay ipaEntries={expression.ipa} />}>
+ <Deconstructed syl={result} />
+ </Suspense>
+ </div>
+ );
+}
+
+function Deconstructed({ syl }: { syl: SyllableToken[] }) {
+ return (
+ <div>
+ {syl.map((tok) => (
+ <span></span>
+ ))}
+ </div>
+ );
+}
+
+// Helper component for IPA display
+const IpaDisplay = ({
+ ipaEntries,
+}: {
+ ipaEntries: Array<{ ipa: string; tags?: string[] }>;
+}) => {
+ if (!ipaEntries || ipaEntries.length === 0) return null;
+ return (
+ <div className="flex items-center space-x-2 flex-wrap">
+ {ipaEntries.map((entry, index) => {
+ const tags = entry.tags ? entry.tags : [];
+ return (
+ <span key={index} className="text-lg text-blue-600 font-serif">
+ {entry.ipa}{" "}
+ {tags.length > 0 && (
+ <span className="text-xs text-gray-500">({tags.join(", ")})</span>
+ )}
+ </span>
+ );
+ })}
+ <button
+ className="p-1 text-blue-500 hover:text-blue-700 transition-colors"
+ title="Pronounce"
+ // onClick={() => {
+ // /* Pronunciation logic would be client-side or a server roundtrip for audio file. */ alert(
+ // "Pronunciation feature not implemented for server component.",
+ // );
+ // }}
+ >
+ <Volume2 size={20} />
+ </button>
+ </div>
+ );
+};
+
+function Tones({ text, lang }: WordProps) {
+ return <div></div>;
+}
+function NotTones({ text, lang }: WordProps) {
+ return <div></div>;
+}