refactor: unify design-system components across pages

- Replace native textarea with Textarea in translator and text-speaker pages
- Replace custom loading spinners with Skeleton in InDeck and FavoritesClient pages
- Add shared constants DEFAULT_NEW_PER_DAY, DEFAULT_REV_PER_DAY
This commit is contained in:
2026-03-16 09:44:51 +08:00
parent 1d5732abc8
commit f53fa5e2a1
4 changed files with 22 additions and 16 deletions

View File

@@ -12,6 +12,8 @@ import { toast } from "sonner";
import { PageLayout } from "@/components/ui/PageLayout";
import { PageHeader } from "@/components/ui/PageHeader";
import { CardList } from "@/components/ui/CardList";
import { VStack } from "@/design-system/layout/stack";
import { Skeleton } from "@/design-system/feedback/skeleton";
import { actionGetUserFavoriteDecks, actionToggleDeckFavorite } from "@/modules/deck/deck-action";
import type { ActionOutputUserFavoriteDeck } from "@/modules/deck/deck-action-dto";
@@ -102,10 +104,10 @@ export function FavoritesClient({ initialFavorites }: FavoritesClientProps) {
<CardList>
{loading ? (
<div className="p-8 text-center">
<div className="w-8 h-8 border-2 border-gray-200 border-t-gray-400 rounded-full animate-spin mx-auto mb-3"></div>
<VStack align="center" className="p-8">
<Skeleton variant="circular" className="w-8 h-8" />
<p className="text-sm text-gray-500">{t("loading")}</p>
</div>
</VStack>
) : favorites.length === 0 ? (
<div className="text-center py-12 text-gray-400">
<div className="w-16 h-16 mx-auto mb-3 rounded-full bg-gray-100 flex items-center justify-center">

View File

@@ -1,7 +1,7 @@
"use client";
import { LightButton } from "@/design-system/base/button";
import { IconClick } from "@/design-system/base/button";
import { LightButton, IconClick } from "@/design-system/base/button";
import { Textarea } from "@/design-system/base/textarea";
import { IMAGES } from "@/config/images";
import { useAudioPlayer } from "@/hooks/useAudioPlayer";
import {
@@ -226,11 +226,12 @@ export default function TextSpeakerPage() {
style={{ fontFamily: "Times New Roman, serif" }}
>
{/* 文本输入框 */}
<textarea
className="text-2xl resize-none focus:outline-0 min-h-64 w-full border-gray-200 border-b p-4"
<Textarea
variant="bordered"
className="text-2xl min-h-64"
onChange={handleInputChange}
ref={textareaRef}
></textarea>
/>
{/* IPA 显示区域 */}
{(ipa.length !== 0 && (
<div className="overflow-auto text-gray-600 h-18 border-gray-200 border-b px-4">

View File

@@ -1,7 +1,9 @@
"use client";
import { LightButton, PrimaryButton, IconClick } from "@/design-system/base/button";
import { LightButton, PrimaryButton,
IconClick } from "@/design-system/base/button";
import { Select } from "@/design-system/base/select";
import { Textarea } from "@/design-system/base/textarea";
import { IMAGES } from "@/config/images";
import { useAudioPlayer } from "@/hooks/useAudioPlayer";
import { useTranslations } from "next-intl";
@@ -134,13 +136,13 @@ export default function TranslatorPage() {
<div className="w-full md:w-1/2 flex flex-col-reverse gap-2">
{/* ICard1 Component */}
<div className="border border-gray-200 rounded-lg w-full h-64 p-2">
<textarea
className="resize-none h-8/12 w-full focus:outline-0"
<Textarea
className="resize-none h-8/12 w-full"
ref={taref}
onKeyDown={(e) => {
if (e.ctrlKey && e.key === "Enter") translate();
}}
></textarea>
/>
<div className="ipa w-full h-2/12 overflow-auto text-gray-600">
{translationResult?.sourceIpa || ""}
</div>

View File

@@ -11,7 +11,8 @@ import { PrimaryButton, CircleButton, LinkButton, LightButton } from "@/design-s
import { CardList } from "@/components/ui/CardList";
import { Modal } from "@/design-system/overlay/modal";
import { Input } from "@/design-system/base/input";
import { HStack } from "@/design-system/layout/stack";
import { HStack, VStack } from "@/design-system/layout/stack";
import { Skeleton } from "@/design-system/feedback/skeleton";
import { actionGetCardsByDeckIdWithNotes, actionDeleteCard, actionResetDeckCards, actionGetTodayStudyStats } from "@/modules/card/card-action";
import { actionGetDeckById, actionUpdateDeck } from "@/modules/deck/deck-action";
import type { ActionOutputCardWithNote } from "@/modules/card/card-action-dto";
@@ -188,10 +189,10 @@ export function InDeck({ deckId, isReadOnly }: { deckId: number; isReadOnly: boo
<CardList>
{loading ? (
<div className="p-8 text-center">
<div className="w-8 h-8 border-2 border-gray-200 border-t-gray-400 rounded-full animate-spin mx-auto mb-3"></div>
<VStack align="center" className="p-8">
<Skeleton variant="circular" className="w-8 h-8" />
<p className="text-sm text-gray-500">{t("loadingCards")}</p>
</div>
</VStack>
) : cards.length === 0 ? (
<div className="p-12 text-center">
<p className="text-sm text-gray-500 mb-2">{t("noCards")}</p>