chore(i18n): update language files with new "load more" translations
This commit is contained in:
+2
-1
@@ -119,7 +119,8 @@
|
||||
"privatePrompts": "الأوامر الخاصة",
|
||||
"noPrompts": "لم يتم العثور على أوامر",
|
||||
"noPromptsDescription": "حاول تعديل معايير البحث أو التصفية للعثور على ما تبحث عنه.",
|
||||
"noMorePrompts": "وصلت إلى النهاية",
|
||||
"noMorePrompts": "لقد وصلت إلى النهاية",
|
||||
"loadMore": "تحميل المزيد",
|
||||
"loading": "جاري التحميل...",
|
||||
"promptTitle": "العنوان",
|
||||
"promptContent": "المحتوى",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "Keine Prompts gefunden",
|
||||
"noPromptsDescription": "Versuchen Sie, Ihre Such- oder Filterkriterien anzupassen, um das Gesuchte zu finden.",
|
||||
"noMorePrompts": "Sie haben das Ende erreicht",
|
||||
"loadMore": "Mehr laden",
|
||||
"loading": "Laden...",
|
||||
"promptTitle": "Titel",
|
||||
"promptContent": "Inhalt",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "Δεν βρέθηκαν prompts",
|
||||
"noPromptsDescription": "Δοκιμάστε να προσαρμόσετε την αναζήτηση ή τα φίλτρα σας.",
|
||||
"noMorePrompts": "Φτάσατε στο τέλος",
|
||||
"loadMore": "Φόρτωση περισσότερων",
|
||||
"loading": "Φόρτωση...",
|
||||
"promptTitle": "Τίτλος",
|
||||
"promptContent": "Περιεχόμενο",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "No prompts found",
|
||||
"noPromptsDescription": "Try adjusting your search or filter criteria to find what you're looking for.",
|
||||
"noMorePrompts": "You've reached the end",
|
||||
"loadMore": "Load More",
|
||||
"loading": "Loading...",
|
||||
"promptTitle": "Title",
|
||||
"promptContent": "Content",
|
||||
|
||||
@@ -151,6 +151,7 @@
|
||||
"deletePromptDescription": "Esta acción no se puede deshacer. El prompt será eliminado permanentemente.",
|
||||
"deleteError": "Error al eliminar el prompt",
|
||||
"noMorePrompts": "Has llegado al final",
|
||||
"loadMore": "Cargar más",
|
||||
"loading": "Cargando...",
|
||||
"types": {
|
||||
"text": "Texto",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "Aucun prompt trouvé",
|
||||
"noPromptsDescription": "Essayez d'ajuster votre recherche ou vos critères de filtre pour trouver ce que vous cherchez.",
|
||||
"noMorePrompts": "Vous avez atteint la fin",
|
||||
"loadMore": "Charger plus",
|
||||
"loading": "Chargement...",
|
||||
"promptTitle": "Titre",
|
||||
"promptContent": "Contenu",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "לא נמצאו פרומפטים",
|
||||
"noPromptsDescription": "נסה להתאים את החיפוש או הסינון שלך.",
|
||||
"noMorePrompts": "הגעת לסוף",
|
||||
"loadMore": "טען עוד",
|
||||
"loading": "טוען...",
|
||||
"promptTitle": "כותרת",
|
||||
"promptContent": "תוכן",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "Nessun prompt trovato",
|
||||
"noPromptsDescription": "Prova a modificare i criteri di ricerca o filtro per trovare quello che cerchi.",
|
||||
"noMorePrompts": "Hai raggiunto la fine",
|
||||
"loadMore": "Carica altro",
|
||||
"loading": "Caricamento...",
|
||||
"promptTitle": "Titolo",
|
||||
"promptContent": "Contenuto",
|
||||
|
||||
+2
-1
@@ -150,7 +150,8 @@
|
||||
"deletePromptTitle": "このプロンプトを削除しますか?",
|
||||
"deletePromptDescription": "この操作は取り消せません。プロンプトは完全に削除されます。",
|
||||
"deleteError": "プロンプトの削除に失敗しました",
|
||||
"noMorePrompts": "最後まで表示しました",
|
||||
"noMorePrompts": "すべて表示しました",
|
||||
"loadMore": "もっと読み込む",
|
||||
"loading": "読み込み中...",
|
||||
"types": {
|
||||
"text": "テキスト",
|
||||
|
||||
+2
-1
@@ -119,7 +119,8 @@
|
||||
"privatePrompts": "비공개 프롬프트",
|
||||
"noPrompts": "프롬프트가 없습니다",
|
||||
"noPromptsDescription": "원하는 것을 찾으려면 검색 또는 필터 조건을 조정해 보세요.",
|
||||
"noMorePrompts": "마지막까지 확인했습니다",
|
||||
"noMorePrompts": "끝에 도달했습니다",
|
||||
"loadMore": "더 보기",
|
||||
"loading": "로딩 중...",
|
||||
"promptTitle": "제목",
|
||||
"promptContent": "내용",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "Nenhum prompt encontrado",
|
||||
"noPromptsDescription": "Tente ajustar sua busca ou critérios de filtro para encontrar o que procura.",
|
||||
"noMorePrompts": "Você chegou ao fim",
|
||||
"loadMore": "Carregar mais",
|
||||
"loading": "Carregando...",
|
||||
"promptTitle": "Título",
|
||||
"promptContent": "Conteúdo",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "Промпты не найдены",
|
||||
"noPromptsDescription": "Попробуйте изменить параметры поиска или фильтры.",
|
||||
"noMorePrompts": "Вы достигли конца",
|
||||
"loadMore": "Загрузить ещё",
|
||||
"loading": "Загрузка...",
|
||||
"promptTitle": "Заголовок",
|
||||
"promptContent": "Содержимое",
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
"noPrompts": "Prompt bulunamadı",
|
||||
"noPromptsDescription": "Aradığınızı bulmak için arama veya filtre kriterlerinizi değiştirmeyi deneyin.",
|
||||
"noMorePrompts": "Sona ulaştınız",
|
||||
"loadMore": "Daha Fazla Yükle",
|
||||
"loading": "Yükleniyor...",
|
||||
"promptTitle": "Başlık",
|
||||
"promptContent": "İçerik",
|
||||
|
||||
+2
-1
@@ -150,7 +150,8 @@
|
||||
"deletePromptTitle": "删除此提示词?",
|
||||
"deletePromptDescription": "此操作无法撤销。提示词将被永久删除。",
|
||||
"deleteError": "删除提示词失败",
|
||||
"noMorePrompts": "已到达末尾",
|
||||
"noMorePrompts": "已经到底了",
|
||||
"loadMore": "加载更多",
|
||||
"loading": "加载中...",
|
||||
"types": {
|
||||
"text": "文本",
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
import { useEffect, useRef, useState, useCallback } from "react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { Loader2, SearchX } from "lucide-react";
|
||||
import { Loader2, SearchX, RefreshCw } from "lucide-react";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useFilterContext } from "./filter-context";
|
||||
import { PromptCard, type PromptCardProps } from "./prompt-card";
|
||||
|
||||
@@ -54,6 +55,7 @@ export function InfinitePromptList({
|
||||
const [page, setPage] = useState(1);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [hasMore, setHasMore] = useState(initialPrompts.length < initialTotal);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const loaderRef = useRef<HTMLDivElement>(null);
|
||||
const abortControllerRef = useRef<AbortController | null>(null);
|
||||
|
||||
@@ -67,6 +69,7 @@ export function InfinitePromptList({
|
||||
setPrompts(initialPrompts);
|
||||
setPage(1);
|
||||
setHasMore(initialPrompts.length < initialTotal);
|
||||
setHasError(false);
|
||||
setFilterPending(false);
|
||||
}, [initialPrompts, initialTotal, setFilterPending]);
|
||||
|
||||
@@ -82,6 +85,7 @@ export function InfinitePromptList({
|
||||
abortControllerRef.current = controller;
|
||||
|
||||
setIsLoading(true);
|
||||
setHasError(false);
|
||||
try {
|
||||
const nextPage = page + 1;
|
||||
const params = new URLSearchParams();
|
||||
@@ -115,6 +119,7 @@ export function InfinitePromptList({
|
||||
return;
|
||||
}
|
||||
console.error("Failed to load more prompts:", error);
|
||||
setHasError(true);
|
||||
} finally {
|
||||
// Only clear loading if this controller is still active
|
||||
if (abortControllerRef.current === controller) {
|
||||
@@ -123,8 +128,10 @@ export function InfinitePromptList({
|
||||
}
|
||||
}, [isLoading, hasMore, page, filters]);
|
||||
|
||||
// Intersection Observer for infinite scroll
|
||||
// Intersection Observer for infinite scroll (disabled if there was an error)
|
||||
useEffect(() => {
|
||||
if (hasError) return;
|
||||
|
||||
const observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
if (entries[0].isIntersecting && hasMore && !isLoading) {
|
||||
@@ -139,7 +146,7 @@ export function InfinitePromptList({
|
||||
}
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, [loadMore, hasMore, isLoading]);
|
||||
}, [loadMore, hasMore, isLoading, hasError]);
|
||||
|
||||
// Cleanup abort controller on unmount
|
||||
useEffect(() => {
|
||||
@@ -183,7 +190,7 @@ export function InfinitePromptList({
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Loader / End indicator */}
|
||||
{/* Loader / End indicator / Error state */}
|
||||
<div ref={loaderRef} className="flex items-center justify-center py-4">
|
||||
{isLoading && (
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
@@ -191,6 +198,12 @@ export function InfinitePromptList({
|
||||
{t("loading")}
|
||||
</div>
|
||||
)}
|
||||
{!isLoading && hasError && hasMore && (
|
||||
<Button variant="outline" size="sm" onClick={loadMore}>
|
||||
<RefreshCw className="h-4 w-4 mr-2" />
|
||||
{t("loadMore")}
|
||||
</Button>
|
||||
)}
|
||||
{!hasMore && prompts.length > 0 && (
|
||||
<p className="text-xs text-muted-foreground">{t("noMorePrompts")}</p>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user