feat: add banner (#12258)

* feat: add banner

* fix: type error
This commit is contained in:
René Wang 2026-02-12 21:22:21 +08:00 committed by GitHub
parent e51fbba881
commit bbbe3a8d09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
71 changed files with 864 additions and 174 deletions

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "مجموعة",
"groupAgents.underReview": "قيد المراجعة",
"home.communityAgents": "وكلاء المجتمع",
"home.creatorReward.action": "قدّم الآن",
"home.creatorReward.subtitle": "برنامج مكافآت المبدعين لعام 2026 أصبح متاحًا رسميًا.",
"home.creatorReward.title": "أنشئ. شارك. واحصل على مقابل.",
"home.featuredAssistants": "وكلاء مميزون",
"home.featuredModels": "نماذج مميزة",
"home.featuredPlugins": "مهارات مميزة",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "أدوات مساعدة",
"mcp.categories.travel-transport.description": "تخطيط السفر والمواصلات",
"mcp.categories.travel-transport.name": "السفر والمواصلات",
"mcp.categories.utility.description": "خدمات التنبؤ بالطقس والأرصاد الجوية",
"mcp.categories.utility.name": "الخدمات",
"mcp.categories.weather.description": "توقعات الطقس وخدمات الأرصاد الجوية",
"mcp.categories.weather.name": "الطقس",
"mcp.categories.web-search.description": "البحث على الويب واسترجاع المعلومات",
@ -478,6 +483,10 @@
"tab.plugin": "المهارة",
"tab.provider": "المزود",
"tab.user": "المستخدم",
"time.formatOtherYear": "D MMM، YYYY",
"time.formatThisYear": "D MMM",
"time.today": "اليوم",
"time.yesterday": "أمس",
"user.agents": "الوكلاء",
"user.downloads": "التنزيلات",
"user.editProfile": "تعديل الملف الشخصي",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "إضافة إلى المكتبة",
"addToKnowledgeBase.totalFiles": "{{count}} ملف/ملفات محددة",
"createNew.confirm": "إنشاء جديد",
"createNew.description.placeholder": "وصف المكتبة (اختياري)",
"createNew.description.label": "وصف المكتبة (اختياري)",
"createNew.description.placeholder": "يساعد الوصف نموذج اللغة الكبير على فهم مكتبتك بشكل أفضل",
"createNew.edit.confirm": "حفظ التغييرات",
"createNew.edit.title": "تعديل المكتبة",
"createNew.formTitle": "المعلومات الأساسية",
"createNew.name.placeholder": "اسم المكتبة",
"createNew.name.required": "يرجى إدخال اسم المكتبة",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Група",
"groupAgents.underReview": "В процес на преглед",
"home.communityAgents": "Агенти от общността",
"home.creatorReward.action": "Кандидатствай сега",
"home.creatorReward.subtitle": "Програмата за възнаграждение на създатели за 2026 г. е официално стартирана.",
"home.creatorReward.title": "Създавай. Споделяй. Получавай възнаграждение.",
"home.featuredAssistants": "Препоръчани агенти",
"home.featuredModels": "Препоръчани модели",
"home.featuredPlugins": "Препоръчани умения",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Помощни инструменти",
"mcp.categories.travel-transport.description": "Планиране на пътувания и транспорт",
"mcp.categories.travel-transport.name": "Пътуване и транспорт",
"mcp.categories.utility.description": "Прогноза за времето и метеорологични услуги",
"mcp.categories.utility.name": "Услуги",
"mcp.categories.weather.description": "Прогноза за времето и метеорологични услуги",
"mcp.categories.weather.name": "Времето",
"mcp.categories.web-search.description": "Уеб търсене и извличане на информация",
@ -478,6 +483,10 @@
"tab.plugin": "Умение",
"tab.provider": "Доставчик",
"tab.user": "Потребител",
"time.formatOtherYear": "D MMM, YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Днес",
"time.yesterday": "Вчера",
"user.agents": "Агенти",
"user.downloads": "Изтегляния",
"user.editProfile": "Редактирай профил",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Добавяне към библиотека",
"addToKnowledgeBase.totalFiles": "{{count}} избрани файла",
"createNew.confirm": "Създай нова",
"createNew.description.placeholder": "Описание на библиотеката (по избор)",
"createNew.description.label": "Описание на библиотеката (по избор)",
"createNew.description.placeholder": "Описанието помага на LLM да разбере по-добре вашата библиотека",
"createNew.edit.confirm": "Запази промените",
"createNew.edit.title": "Редактиране на библиотека",
"createNew.formTitle": "Основна информация",
"createNew.name.placeholder": "Име на библиотеката",
"createNew.name.required": "Моля, въведете име на библиотеката",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Gruppe",
"groupAgents.underReview": "Wird überprüft",
"home.communityAgents": "Community-Agenten",
"home.creatorReward.action": "Jetzt bewerben",
"home.creatorReward.subtitle": "Das Creator-Belohnungsprogramm 2026 ist offiziell gestartet.",
"home.creatorReward.title": "Kreieren. Teilen. Geld verdienen.",
"home.featuredAssistants": "Empfohlene Agenten",
"home.featuredModels": "Empfohlene Modelle",
"home.featuredPlugins": "Empfohlene Fähigkeiten",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Hilfsprogramme",
"mcp.categories.travel-transport.description": "Reiseplanung und Transport",
"mcp.categories.travel-transport.name": "Reise & Transport",
"mcp.categories.utility.description": "Wettervorhersage und meteorologische Dienste",
"mcp.categories.utility.name": "Dienstprogramme",
"mcp.categories.weather.description": "Wettervorhersage und meteorologische Dienste",
"mcp.categories.weather.name": "Wetter",
"mcp.categories.web-search.description": "Websuche und Informationsabruf",
@ -478,6 +483,10 @@
"tab.plugin": "Fähigkeit",
"tab.provider": "Anbieter",
"tab.user": "Benutzer",
"time.formatOtherYear": "D. MMM YYYY",
"time.formatThisYear": "D. MMM",
"time.today": "Heute",
"time.yesterday": "Gestern",
"user.agents": "Agenten",
"user.downloads": "Downloads",
"user.editProfile": "Profil bearbeiten",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Zur Bibliothek hinzufügen",
"addToKnowledgeBase.totalFiles": "{{count}} Dateien ausgewählt",
"createNew.confirm": "Neu erstellen",
"createNew.description.placeholder": "Bibliotheksbeschreibung (optional)",
"createNew.description.label": "Bibliotheksbeschreibung (optional)",
"createNew.description.placeholder": "Die Beschreibung hilft dem LLM, Ihre Bibliothek besser zu verstehen",
"createNew.edit.confirm": "Änderungen speichern",
"createNew.edit.title": "Bibliothek bearbeiten",
"createNew.formTitle": "Grundinformationen",
"createNew.name.placeholder": "Name der Bibliothek",
"createNew.name.required": "Bitte geben Sie einen Namen für die Bibliothek ein",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Group",
"groupAgents.underReview": "Under Review",
"home.communityAgents": "Community Agents",
"home.creatorReward.action": "Apply Now",
"home.creatorReward.subtitle": "2026 Creator Reward Program is officially live.",
"home.creatorReward.title": "Create. Share. Get Paid.",
"home.featuredAssistants": "Featured Agents",
"home.featuredModels": "Featured Models",
"home.featuredPlugins": "Featured Skills",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Utility Tools",
"mcp.categories.travel-transport.description": "Travel Planning and Transportation",
"mcp.categories.travel-transport.name": "Travel & Transport",
"mcp.categories.utility.description": "Weather Forecasting and Meteorological Services",
"mcp.categories.utility.name": "Utility",
"mcp.categories.weather.description": "Weather Forecasting and Meteorological Services",
"mcp.categories.weather.name": "Weather",
"mcp.categories.web-search.description": "Web Search and Information Retrieval",
@ -478,6 +483,10 @@
"tab.plugin": "Skill",
"tab.provider": "Provider",
"tab.user": "User",
"time.formatOtherYear": "MMM D, YYYY",
"time.formatThisYear": "MMM D",
"time.today": "Today",
"time.yesterday": "Yesterday",
"user.agents": "Agents",
"user.downloads": "Downloads",
"user.editProfile": "Edit Profile",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Add to Library",
"addToKnowledgeBase.totalFiles": "{{count}} files selected",
"createNew.confirm": "Create New",
"createNew.description.placeholder": "Library description (optional)",
"createNew.description.label": "Library Description (Optional)",
"createNew.description.placeholder": "Description helps LLM understand your library better",
"createNew.edit.confirm": "Save Changes",
"createNew.edit.title": "Edit Library",
"createNew.formTitle": "Basic Information",
"createNew.name.placeholder": "Library name",
"createNew.name.required": "Please enter a library name",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Grupo",
"groupAgents.underReview": "En revisión",
"home.communityAgents": "Agentes de la Comunidad",
"home.creatorReward.action": "Aplica ahora",
"home.creatorReward.subtitle": "El Programa de Recompensas para Creadores 2026 ya está disponible.",
"home.creatorReward.title": "Crea. Comparte. Gana dinero.",
"home.featuredAssistants": "Agentes Destacados",
"home.featuredModels": "Modelos Destacados",
"home.featuredPlugins": "Habilidades Destacadas",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Herramientas utilitarias",
"mcp.categories.travel-transport.description": "Planificación de viajes y transporte",
"mcp.categories.travel-transport.name": "Viajes y transporte",
"mcp.categories.utility.description": "Pronóstico del tiempo y servicios meteorológicos",
"mcp.categories.utility.name": "Utilidad",
"mcp.categories.weather.description": "Pronóstico del tiempo y servicios meteorológicos",
"mcp.categories.weather.name": "Clima",
"mcp.categories.web-search.description": "Búsqueda web y recuperación de información",
@ -478,6 +483,10 @@
"tab.plugin": "Habilidad",
"tab.provider": "Proveedor",
"tab.user": "Usuario",
"time.formatOtherYear": "D MMM, YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Hoy",
"time.yesterday": "Ayer",
"user.agents": "Agentes",
"user.downloads": "Descargas",
"user.editProfile": "Editar Perfil",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Añadir a la biblioteca",
"addToKnowledgeBase.totalFiles": "{{count}} archivos seleccionados",
"createNew.confirm": "Crear nueva",
"createNew.description.placeholder": "Descripción de la biblioteca (opcional)",
"createNew.description.label": "Descripción de la biblioteca (opcional)",
"createNew.description.placeholder": "La descripción ayuda al LLM a comprender mejor tu biblioteca",
"createNew.edit.confirm": "Guardar cambios",
"createNew.edit.title": "Editar biblioteca",
"createNew.formTitle": "Información básica",
"createNew.name.placeholder": "Nombre de la biblioteca",
"createNew.name.required": "Por favor, introduce un nombre para la biblioteca",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "گروه",
"groupAgents.underReview": "در حال بررسی",
"home.communityAgents": "عوامل جامعه",
"home.creatorReward.action": "هم‌اکنون درخواست دهید",
"home.creatorReward.subtitle": "برنامه پاداش سازندگان ۲۰۲۶ رسماً آغاز شد.",
"home.creatorReward.title": "بسازید. به اشتراک بگذارید. درآمد کسب کنید.",
"home.featuredAssistants": "عوامل ویژه",
"home.featuredModels": "مدل‌های ویژه",
"home.featuredPlugins": "مهارت‌های ویژه",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "ابزارهای کاربردی",
"mcp.categories.travel-transport.description": "برنامه‌ریزی سفر و حمل‌ونقل",
"mcp.categories.travel-transport.name": "سفر و حمل‌ونقل",
"mcp.categories.utility.description": "پیش‌بینی وضعیت هوا و خدمات هواشناسی",
"mcp.categories.utility.name": "کاربردی",
"mcp.categories.weather.description": "پیش‌بینی وضعیت هوا و خدمات هواشناسی",
"mcp.categories.weather.name": "آب‌وهوا",
"mcp.categories.web-search.description": "جستجوی وب و بازیابی اطلاعات",
@ -478,6 +483,10 @@
"tab.plugin": "مهارت",
"tab.provider": "ارائه‌دهنده",
"tab.user": "کاربر",
"time.formatOtherYear": "D MMM، YYYY",
"time.formatThisYear": "D MMM",
"time.today": "امروز",
"time.yesterday": "دیروز",
"user.agents": "عوامل",
"user.downloads": "دانلودها",
"user.editProfile": "ویرایش پروفایل",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "افزودن به کتابخانه",
"addToKnowledgeBase.totalFiles": "{{count}} فایل انتخاب شده",
"createNew.confirm": "ایجاد جدید",
"createNew.description.placeholder": "توضیحات کتابخانه (اختیاری)",
"createNew.description.label": "توضیحات کتابخانه (اختیاری)",
"createNew.description.placeholder": "توضیحات به مدل زبانی کمک می‌کند کتابخانه شما را بهتر درک کند",
"createNew.edit.confirm": "ذخیره تغییرات",
"createNew.edit.title": "ویرایش کتابخانه",
"createNew.formTitle": "اطلاعات پایه",
"createNew.name.placeholder": "نام کتابخانه",
"createNew.name.required": "لطفاً نام کتابخانه را وارد کنید",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Groupe",
"groupAgents.underReview": "En cours d'examen",
"home.communityAgents": "Agents de la communauté",
"home.creatorReward.action": "Postulez maintenant",
"home.creatorReward.subtitle": "Le programme de récompenses des créateurs 2026 est officiellement lancé.",
"home.creatorReward.title": "Créez. Partagez. Soyez rémunéré.",
"home.featuredAssistants": "Agents en vedette",
"home.featuredModels": "Modèles en vedette",
"home.featuredPlugins": "Compétences en vedette",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Outils utilitaires",
"mcp.categories.travel-transport.description": "Planification de voyages et transports",
"mcp.categories.travel-transport.name": "Voyage & Transport",
"mcp.categories.utility.description": "Prévisions météorologiques et services météorologiques",
"mcp.categories.utility.name": "Utilitaire",
"mcp.categories.weather.description": "Prévisions météorologiques et services météorologiques",
"mcp.categories.weather.name": "Météo",
"mcp.categories.web-search.description": "Recherche web et récupération d'informations",
@ -478,6 +483,10 @@
"tab.plugin": "Compétence",
"tab.provider": "Fournisseur",
"tab.user": "Utilisateur",
"time.formatOtherYear": "D MMM YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Aujourdhui",
"time.yesterday": "Hier",
"user.agents": "Agents",
"user.downloads": "Téléchargements",
"user.editProfile": "Modifier le profil",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Ajouter à la bibliothèque",
"addToKnowledgeBase.totalFiles": "{{count}} fichiers sélectionnés",
"createNew.confirm": "Créer",
"createNew.description.placeholder": "Description de la bibliothèque (facultatif)",
"createNew.description.label": "Description de la bibliothèque (facultatif)",
"createNew.description.placeholder": "La description aide le LLM à mieux comprendre votre bibliothèque",
"createNew.edit.confirm": "Enregistrer les modifications",
"createNew.edit.title": "Modifier la bibliothèque",
"createNew.formTitle": "Informations de base",
"createNew.name.placeholder": "Nom de la bibliothèque",
"createNew.name.required": "Veuillez entrer un nom de bibliothèque",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Gruppo",
"groupAgents.underReview": "In fase di revisione",
"home.communityAgents": "Agenti della Community",
"home.creatorReward.action": "Candidati ora",
"home.creatorReward.subtitle": "Il Programma di Ricompensa per i Creatori 2026 è ufficialmente attivo.",
"home.creatorReward.title": "Crea. Condividi. Vieni ricompensato.",
"home.featuredAssistants": "Agenti in Evidenza",
"home.featuredModels": "Modelli in Evidenza",
"home.featuredPlugins": "Abilità in Evidenza",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Strumenti utili",
"mcp.categories.travel-transport.description": "Pianificazione viaggi e trasporti",
"mcp.categories.travel-transport.name": "Viaggi e trasporti",
"mcp.categories.utility.description": "Previsioni del tempo e servizi meteorologici",
"mcp.categories.utility.name": "Utilità",
"mcp.categories.weather.description": "Previsioni meteo e servizi meteorologici",
"mcp.categories.weather.name": "Meteo",
"mcp.categories.web-search.description": "Ricerca web e recupero di informazioni",
@ -478,6 +483,10 @@
"tab.plugin": "Abilità",
"tab.provider": "Provider",
"tab.user": "Utente",
"time.formatOtherYear": "D MMM YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Oggi",
"time.yesterday": "Ieri",
"user.agents": "Agenti",
"user.downloads": "Download",
"user.editProfile": "Modifica Profilo",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Aggiungi alla Libreria",
"addToKnowledgeBase.totalFiles": "{{count}} file selezionati",
"createNew.confirm": "Crea nuova",
"createNew.description.placeholder": "Descrizione della libreria (facoltativa)",
"createNew.description.label": "Descrizione della Libreria (Opzionale)",
"createNew.description.placeholder": "La descrizione aiuta il LLM a comprendere meglio la tua libreria",
"createNew.edit.confirm": "Salva Modifiche",
"createNew.edit.title": "Modifica Libreria",
"createNew.formTitle": "Informazioni di base",
"createNew.name.placeholder": "Nome della libreria",
"createNew.name.required": "Inserisci un nome per la libreria",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "グループ",
"groupAgents.underReview": "審査中",
"home.communityAgents": "コミュニティアシスタント",
"home.creatorReward.action": "今すぐ申し込む",
"home.creatorReward.subtitle": "2026年クリエイター報酬プログラムが正式に開始されました。",
"home.creatorReward.title": "創造する。共有する。報酬を得る。",
"home.featuredAssistants": "おすすめアシスタント",
"home.featuredModels": "おすすめモデル",
"home.featuredPlugins": "おすすめプラグイン",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "実用ツール",
"mcp.categories.travel-transport.description": "旅行計画と交通手段",
"mcp.categories.travel-transport.name": "旅行・交通",
"mcp.categories.utility.description": "天気予報および気象サービス",
"mcp.categories.utility.name": "ユーティリティ",
"mcp.categories.weather.description": "天気予報と気象サービス",
"mcp.categories.weather.name": "気象・天気",
"mcp.categories.web-search.description": "ウェブ検索と情報検索",
@ -478,6 +483,10 @@
"tab.plugin": "プラグイン",
"tab.provider": "モデルサービスプロバイダー",
"tab.user": "ユーザー",
"time.formatOtherYear": "YYYY年M月D日",
"time.formatThisYear": "M月D日",
"time.today": "今日",
"time.yesterday": "昨日",
"user.agents": "アシスタント",
"user.downloads": "ダウンロード",
"user.editProfile": "プロフィールを編集",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "ナレッジベースに追加",
"addToKnowledgeBase.totalFiles": "選択されたファイルは {{count}} 件です",
"createNew.confirm": "新規作成",
"createNew.description.placeholder": "ナレッジベースの説明(任意)",
"createNew.description.label": "ライブラリの説明(任意)",
"createNew.description.placeholder": "説明を追加すると、LLM がライブラリをより正確に理解できます",
"createNew.edit.confirm": "変更を保存",
"createNew.edit.title": "ライブラリの編集",
"createNew.formTitle": "基本情報",
"createNew.name.placeholder": "ナレッジベース名",
"createNew.name.required": "ナレッジベース名を入力してください",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "그룹",
"groupAgents.underReview": "검토 중",
"home.communityAgents": "커뮤니티 도우미",
"home.creatorReward.action": "지금 신청하기",
"home.creatorReward.subtitle": "2026 크리에이터 리워드 프로그램이 공식적으로 시작되었습니다.",
"home.creatorReward.title": "창작하고, 공유하고, 보상받으세요.",
"home.featuredAssistants": "추천 도우미",
"home.featuredModels": "추천 모델",
"home.featuredPlugins": "추천 기능",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "유틸리티 도구",
"mcp.categories.travel-transport.description": "여행 계획 및 교통 수단",
"mcp.categories.travel-transport.name": "여행 & 교통",
"mcp.categories.utility.description": "기상 예보 및 기상 서비스",
"mcp.categories.utility.name": "유틸리티",
"mcp.categories.weather.description": "일기예보 및 기상 서비스",
"mcp.categories.weather.name": "날씨 & 기상",
"mcp.categories.web-search.description": "웹 검색 및 정보 검색",
@ -478,6 +483,10 @@
"tab.plugin": "기능",
"tab.provider": "모델 서비스 제공자",
"tab.user": "사용자",
"time.formatOtherYear": "YYYY년 M월 D일",
"time.formatThisYear": "M월 D일",
"time.today": "오늘",
"time.yesterday": "어제",
"user.agents": "도우미",
"user.downloads": "다운로드",
"user.editProfile": "프로필 편집",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "지식 베이스에 추가",
"addToKnowledgeBase.totalFiles": "{{count}}개의 파일이 선택되었습니다",
"createNew.confirm": "새로 만들기",
"createNew.description.placeholder": "지식 베이스 설명 (선택 사항)",
"createNew.description.label": "라이브러리 설명 (선택 사항)",
"createNew.description.placeholder": "설명은 LLM이 라이브러리를 더 잘 이해하는 데 도움이 됩니다",
"createNew.edit.confirm": "변경 사항 저장",
"createNew.edit.title": "라이브러리 편집",
"createNew.formTitle": "기본 정보",
"createNew.name.placeholder": "지식 베이스 이름",
"createNew.name.required": "지식 베이스 이름을 입력하세요",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Groep",
"groupAgents.underReview": "In beoordeling",
"home.communityAgents": "Community Agents",
"home.creatorReward.action": "Nu Aanmelden",
"home.creatorReward.subtitle": "Het Creator Beloningsprogramma 2026 is officieel van start gegaan.",
"home.creatorReward.title": "Creëer. Deel. Verdien Geld.",
"home.featuredAssistants": "Uitgelichte Agents",
"home.featuredModels": "Uitgelichte Modellen",
"home.featuredPlugins": "Uitgelichte Vaardigheden",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Hulpprogramma's",
"mcp.categories.travel-transport.description": "Reisplanning en vervoer",
"mcp.categories.travel-transport.name": "Reizen & Vervoer",
"mcp.categories.utility.description": "Weersvoorspellingen en meteorologische diensten",
"mcp.categories.utility.name": "Nutsvoorziening",
"mcp.categories.weather.description": "Weersvoorspellingen en meteorologische diensten",
"mcp.categories.weather.name": "Weer",
"mcp.categories.web-search.description": "Webzoekopdrachten en informatieopvraging",
@ -478,6 +483,10 @@
"tab.plugin": "Vaardigheid",
"tab.provider": "Aanbieder",
"tab.user": "Gebruiker",
"time.formatOtherYear": "D MMM YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Vandaag",
"time.yesterday": "Gisteren",
"user.agents": "Agents",
"user.downloads": "Downloads",
"user.editProfile": "Profiel bewerken",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Toevoegen aan bibliotheek",
"addToKnowledgeBase.totalFiles": "{{count}} bestanden geselecteerd",
"createNew.confirm": "Nieuw aanmaken",
"createNew.description.placeholder": "Beschrijving van de bibliotheek (optioneel)",
"createNew.description.label": "Bibliotheekbeschrijving (optioneel)",
"createNew.description.placeholder": "Een beschrijving helpt het LLM je bibliotheek beter te begrijpen",
"createNew.edit.confirm": "Wijzigingen opslaan",
"createNew.edit.title": "Bibliotheek bewerken",
"createNew.formTitle": "Basisinformatie",
"createNew.name.placeholder": "Naam van de bibliotheek",
"createNew.name.required": "Voer een naam voor de bibliotheek in",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Grupa",
"groupAgents.underReview": "W trakcie przeglądu",
"home.communityAgents": "Agenci Społeczności",
"home.creatorReward.action": "Aplikuj teraz",
"home.creatorReward.subtitle": "Program Nagród dla Twórców 2026 jest już dostępny.",
"home.creatorReward.title": "Twórz. Udostępniaj. Zarabiaj.",
"home.featuredAssistants": "Polecani Agenci",
"home.featuredModels": "Polecane Modele",
"home.featuredPlugins": "Polecane Umiejętności",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Narzędzia użytkowe",
"mcp.categories.travel-transport.description": "Planowanie podróży i transport",
"mcp.categories.travel-transport.name": "Podróże i transport",
"mcp.categories.utility.description": "Prognozowanie pogody i usługi meteorologiczne",
"mcp.categories.utility.name": "Użyteczność",
"mcp.categories.weather.description": "Prognozy pogody i usługi meteorologiczne",
"mcp.categories.weather.name": "Pogoda",
"mcp.categories.web-search.description": "Wyszukiwanie w sieci i pozyskiwanie informacji",
@ -478,6 +483,10 @@
"tab.plugin": "Umiejętność",
"tab.provider": "Dostawca",
"tab.user": "Użytkownik",
"time.formatOtherYear": "D MMM, YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Dzisiaj",
"time.yesterday": "Wczoraj",
"user.agents": "Agenci",
"user.downloads": "Pobrane",
"user.editProfile": "Edytuj Profil",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Dodaj do biblioteki",
"addToKnowledgeBase.totalFiles": "Wybrano {{count}} plików",
"createNew.confirm": "Utwórz nową",
"createNew.description.placeholder": "Opis biblioteki (opcjonalnie)",
"createNew.description.label": "Opis biblioteki (opcjonalnie)",
"createNew.description.placeholder": "Opis pomaga modelowi LLM lepiej zrozumieć Twoją bibliotekę",
"createNew.edit.confirm": "Zapisz zmiany",
"createNew.edit.title": "Edytuj bibliotekę",
"createNew.formTitle": "Informacje podstawowe",
"createNew.name.placeholder": "Nazwa biblioteki",
"createNew.name.required": "Wprowadź nazwę biblioteki",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Grupo",
"groupAgents.underReview": "Em análise",
"home.communityAgents": "Agentes da Comunidade",
"home.creatorReward.action": "Inscreva-se agora",
"home.creatorReward.subtitle": "O Programa de Recompensas para Criadores de 2026 está oficialmente no ar.",
"home.creatorReward.title": "Crie. Compartilhe. Seja pago.",
"home.featuredAssistants": "Agentes em Destaque",
"home.featuredModels": "Modelos em Destaque",
"home.featuredPlugins": "Habilidades em Destaque",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Ferramentas Utilitárias",
"mcp.categories.travel-transport.description": "Planejamento de Viagens e Transporte",
"mcp.categories.travel-transport.name": "Viagem e Transporte",
"mcp.categories.utility.description": "Previsão do tempo e serviços meteorológicos",
"mcp.categories.utility.name": "Utilidade",
"mcp.categories.weather.description": "Previsão do Tempo e Serviços Meteorológicos",
"mcp.categories.weather.name": "Clima",
"mcp.categories.web-search.description": "Busca na Web e Recuperação de Informações",
@ -478,6 +483,10 @@
"tab.plugin": "Habilidade",
"tab.provider": "Provedor",
"tab.user": "Usuário",
"time.formatOtherYear": "D 'de' MMM 'de' YYYY",
"time.formatThisYear": "D 'de' MMM",
"time.today": "Hoje",
"time.yesterday": "Ontem",
"user.agents": "Agentes",
"user.downloads": "Downloads",
"user.editProfile": "Editar Perfil",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Adicionar à Biblioteca",
"addToKnowledgeBase.totalFiles": "{{count}} arquivos selecionados",
"createNew.confirm": "Criar Nova",
"createNew.description.placeholder": "Descrição da biblioteca (opcional)",
"createNew.description.label": "Descrição da Biblioteca (Opcional)",
"createNew.description.placeholder": "A descrição ajuda o LLM a entender melhor sua biblioteca",
"createNew.edit.confirm": "Salvar Alterações",
"createNew.edit.title": "Editar Biblioteca",
"createNew.formTitle": "Informações Básicas",
"createNew.name.placeholder": "Nome da biblioteca",
"createNew.name.required": "Por favor, insira um nome para a biblioteca",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Группа",
"groupAgents.underReview": "На рассмотрении",
"home.communityAgents": "Агенты сообщества",
"home.creatorReward.action": "Подать заявку",
"home.creatorReward.subtitle": "Программа вознаграждений для создателей 2026 официально запущена.",
"home.creatorReward.title": "Создавай. Делись. Получай вознаграждение.",
"home.featuredAssistants": "Избранные агенты",
"home.featuredModels": "Избранные модели",
"home.featuredPlugins": "Избранные навыки",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Утилиты",
"mcp.categories.travel-transport.description": "Планирование путешествий и транспорт",
"mcp.categories.travel-transport.name": "Путешествия и транспорт",
"mcp.categories.utility.description": "Прогноз погоды и метеорологические услуги",
"mcp.categories.utility.name": "Утилиты",
"mcp.categories.weather.description": "Прогноз погоды и метеорологические сервисы",
"mcp.categories.weather.name": "Погода",
"mcp.categories.web-search.description": "Поиск в интернете и извлечение информации",
@ -478,6 +483,10 @@
"tab.plugin": "Навык",
"tab.provider": "Провайдер",
"tab.user": "Пользователь",
"time.formatOtherYear": "D MMM YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Сегодня",
"time.yesterday": "Вчера",
"user.agents": "Агенты",
"user.downloads": "Загрузки",
"user.editProfile": "Редактировать профиль",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Добавить в библиотеку",
"addToKnowledgeBase.totalFiles": "Выбрано файлов: {{count}}",
"createNew.confirm": "Создать",
"createNew.description.placeholder": "Описание библиотеки (необязательно)",
"createNew.description.label": "Описание библиотеки (необязательно)",
"createNew.description.placeholder": "Описание помогает LLM лучше понять вашу библиотеку",
"createNew.edit.confirm": "Сохранить изменения",
"createNew.edit.title": "Редактировать библиотеку",
"createNew.formTitle": "Основная информация",
"createNew.name.placeholder": "Название библиотеки",
"createNew.name.required": "Пожалуйста, введите название библиотеки",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Grup",
"groupAgents.underReview": "İncelemede",
"home.communityAgents": "Topluluk Ajansları",
"home.creatorReward.action": "Hemen Başvur",
"home.creatorReward.subtitle": "2026 Yaratıcı Ödül Programı resmen başladı.",
"home.creatorReward.title": "Üret. Paylaş. Kazan.",
"home.featuredAssistants": "Öne Çıkan Ajanslar",
"home.featuredModels": "Öne Çıkan Modeller",
"home.featuredPlugins": "Öne Çıkan Beceriler",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Yardımcı Araçlar",
"mcp.categories.travel-transport.description": "Seyahat Planlama ve Ulaşım",
"mcp.categories.travel-transport.name": "Seyahat & Ulaşım",
"mcp.categories.utility.description": "Hava Tahmini ve Meteorolojik Hizmetler",
"mcp.categories.utility.name": "Kamu Hizmeti",
"mcp.categories.weather.description": "Hava Tahmini ve Meteorolojik Hizmetler",
"mcp.categories.weather.name": "Hava Durumu",
"mcp.categories.web-search.description": "Web Arama ve Bilgi Erişimi",
@ -478,6 +483,10 @@
"tab.plugin": "Yetenek",
"tab.provider": "Sağlayıcı",
"tab.user": "Kullanıcı",
"time.formatOtherYear": "D MMM YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Bugün",
"time.yesterday": "Dün",
"user.agents": "Ajanslar",
"user.downloads": "İndirmeler",
"user.editProfile": "Profili Düzenle",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Kütüphaneye Ekle",
"addToKnowledgeBase.totalFiles": "{{count}} dosya seçildi",
"createNew.confirm": "Yeni Oluştur",
"createNew.description.placeholder": "Kütüphane açıklaması (isteğe bağlı)",
"createNew.description.label": "Kütüphane Açıklaması (İsteğe Bağlı)",
"createNew.description.placeholder": "Açıklama, LLM'nin kütüphanenizi daha iyi anlamasına yardımcı olur",
"createNew.edit.confirm": "Değişiklikleri Kaydet",
"createNew.edit.title": "Kütüphaneyi Düzenle",
"createNew.formTitle": "Temel Bilgiler",
"createNew.name.placeholder": "Kütüphane adı",
"createNew.name.required": "Lütfen bir kütüphane adı girin",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "Nhóm",
"groupAgents.underReview": "Đang xem xét",
"home.communityAgents": "Tác nhân cộng đồng",
"home.creatorReward.action": "Đăng ký ngay",
"home.creatorReward.subtitle": "Chương trình Phần thưởng Nhà sáng tạo 2026 đã chính thức bắt đầu.",
"home.creatorReward.title": "Sáng tạo. Chia sẻ. Nhận thưởng.",
"home.featuredAssistants": "Tác nhân nổi bật",
"home.featuredModels": "Mô hình nổi bật",
"home.featuredPlugins": "Kỹ năng nổi bật",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "Công cụ Tiện ích",
"mcp.categories.travel-transport.description": "Lập kế hoạch du lịch và phương tiện di chuyển",
"mcp.categories.travel-transport.name": "Du lịch & Vận chuyển",
"mcp.categories.utility.description": "Dự báo thời tiết và Dịch vụ khí tượng",
"mcp.categories.utility.name": "Tiện ích",
"mcp.categories.weather.description": "Dự báo thời tiết và dịch vụ khí tượng",
"mcp.categories.weather.name": "Thời tiết",
"mcp.categories.web-search.description": "Tìm kiếm web và truy xuất thông tin",
@ -478,6 +483,10 @@
"tab.plugin": "Kỹ năng",
"tab.provider": "Nhà cung cấp",
"tab.user": "Người dùng",
"time.formatOtherYear": "D MMM, YYYY",
"time.formatThisYear": "D MMM",
"time.today": "Hôm nay",
"time.yesterday": "Hôm qua",
"user.agents": "Tác vụ",
"user.downloads": "Tải xuống",
"user.editProfile": "Chỉnh sửa hồ sơ",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "Thêm vào Thư viện",
"addToKnowledgeBase.totalFiles": "{{count}} tệp đã được chọn",
"createNew.confirm": "Tạo mới",
"createNew.description.placeholder": "Mô tả thư viện (không bắt buộc)",
"createNew.description.label": "Mô tả Thư viện (Không bắt buộc)",
"createNew.description.placeholder": "Mô tả giúp Mô hình Ngôn ngữ Lớn (LLM) hiểu rõ hơn về thư viện của bạn",
"createNew.edit.confirm": "Lưu Thay đổi",
"createNew.edit.title": "Chỉnh sửa Thư viện",
"createNew.formTitle": "Thông tin cơ bản",
"createNew.name.placeholder": "Tên thư viện",
"createNew.name.required": "Vui lòng nhập tên thư viện",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "群组",
"groupAgents.underReview": "审核中",
"home.communityAgents": "社区助理",
"home.creatorReward.action": "立即申请",
"home.creatorReward.subtitle": "2026 创作者奖励计划已正式上线。",
"home.creatorReward.title": "创作、分享、获得回报",
"home.featuredAssistants": "推荐助理",
"home.featuredModels": "推荐模型",
"home.featuredPlugins": "精选技能",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "实用工具",
"mcp.categories.travel-transport.description": "旅行规划与交通出行",
"mcp.categories.travel-transport.name": "旅行交通",
"mcp.categories.utility.description": "天气预报与气象服务",
"mcp.categories.utility.name": "实用工具",
"mcp.categories.weather.description": "天气预报与气象服务",
"mcp.categories.weather.name": "气象天气",
"mcp.categories.web-search.description": "网页搜索与信息检索",
@ -478,6 +483,10 @@
"tab.plugin": "技能",
"tab.provider": "模型服务商",
"tab.user": "用户",
"time.formatOtherYear": "YYYY年M月D日",
"time.formatThisYear": "M月D日",
"time.today": "今天",
"time.yesterday": "昨天",
"user.agents": "助理",
"user.downloads": "下载",
"user.editProfile": "编辑个人资料",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "添加到资源库",
"addToKnowledgeBase.totalFiles": "已选择 {{count}} 个文件",
"createNew.confirm": "新建",
"createNew.description.placeholder": "资源库简介(选填)",
"createNew.description.label": "库描述(可选)",
"createNew.description.placeholder": "描述有助于大语言模型更好地理解您的库",
"createNew.edit.confirm": "保存修改",
"createNew.edit.title": "编辑资源库",
"createNew.formTitle": "基本信息",
"createNew.name.placeholder": "资源库名称",
"createNew.name.required": "请填写资源库名称",

View file

@ -150,6 +150,9 @@
"groupAgents.tag": "群組",
"groupAgents.underReview": "審核中",
"home.communityAgents": "社群助手",
"home.creatorReward.action": "立即申請",
"home.creatorReward.subtitle": "2026 創作者獎勵計畫正式啟動。",
"home.creatorReward.title": "創作.分享.獲得報酬。",
"home.featuredAssistants": "推薦助手",
"home.featuredModels": "推薦模型",
"home.featuredPlugins": "精選外掛",
@ -194,6 +197,8 @@
"mcp.categories.tools.name": "實用工具",
"mcp.categories.travel-transport.description": "旅行規劃與交通出行",
"mcp.categories.travel-transport.name": "旅行交通",
"mcp.categories.utility.description": "天氣預報與氣象服務",
"mcp.categories.utility.name": "實用工具",
"mcp.categories.weather.description": "天氣預報與氣象服務",
"mcp.categories.weather.name": "氣象天氣",
"mcp.categories.web-search.description": "網頁搜尋與資訊檢索",
@ -478,6 +483,10 @@
"tab.plugin": "外掛",
"tab.provider": "模型服務商",
"tab.user": "使用者",
"time.formatOtherYear": "YYYY 年 M 月 D 日",
"time.formatThisYear": "M 月 D 日",
"time.today": "今天",
"time.yesterday": "昨天",
"user.agents": "助理",
"user.downloads": "下載",
"user.editProfile": "編輯個人資料",

View file

@ -9,7 +9,10 @@
"addToKnowledgeBase.title": "新增至知識庫",
"addToKnowledgeBase.totalFiles": "已選擇 {{count}} 個文件",
"createNew.confirm": "新建",
"createNew.description.placeholder": "知識庫簡介(選填)",
"createNew.description.label": "資料庫描述(選填)",
"createNew.description.placeholder": "描述有助於大型語言模型更好地理解您的資料庫",
"createNew.edit.confirm": "儲存變更",
"createNew.edit.title": "編輯資料庫",
"createNew.formTitle": "基本信息",
"createNew.name.placeholder": "知識庫名稱",
"createNew.name.required": "請填寫知識庫名稱",

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

View file

@ -119,7 +119,7 @@ const Versions = memo(() => {
align: 'end',
dataIndex: 'createdAt',
render: (_: any, record: any) => (
<PublishedTime date={record.createdAt} showPrefix={false} />
<PublishedTime date={record.createdAt} />
),
title: t('assistants.details.version.table.publishAt'),
},

View file

@ -182,7 +182,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
<PublishedTime
className={styles.time}
date={createdAt as string}
template={'MMM DD, YYYY'}
/>
<AgentForkTag />
{!!forkCount && forkCount > 0 && (

View file

@ -101,7 +101,7 @@ const Versions = memo(() => {
align: 'end',
dataIndex: 'createdAt',
render: (_: any, record: any) => (
<PublishedTime date={record.createdAt} showPrefix={false} />
<PublishedTime date={record.createdAt} />
),
title: t('groupAgents.details.version.table.publishAt', {
defaultValue: 'Published At',

View file

@ -185,7 +185,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
<PublishedTime
className={styles.time}
date={createdAt as string}
template={'MMM DD, YYYY'}
/>
<GroupAgentForkTag />
{!!forkCount && forkCount > 0 && (

View file

@ -61,7 +61,7 @@ const Versions = memo(() => {
{
align: 'end',
dataIndex: 'createdAt',
render: (_, record) => <PublishedTime date={record.createdAt} showPrefix={false} />,
render: (_, record) => <PublishedTime date={record.createdAt} />,
title: t('mcp.details.versions.table.publishAt'),
},
]}

View file

@ -91,7 +91,7 @@ const Header = memo<{ mobile?: boolean }>(({ mobile: isMobile }) => {
<PublishedTime
className={styles.time}
date={releasedAt as string}
template={'MMM DD, YYYY'}
/>
</Flexbox>
</Flexbox>

View file

@ -378,7 +378,7 @@ const UserAgentCard = memo<UserAgentCardProps>(
<PublishedTime
className={styles.secondaryDesc}
date={createdAt}
template={'MMM DD, YYYY'}
/>
</Flexbox>
{category && t(`category.assistant.${category}` as any)}

View file

@ -218,7 +218,7 @@ const FavoriteAgentCard = memo<FavoriteAgentCardProps>(
<PublishedTime
className={styles.secondaryDesc}
date={createdAt}
template={'MMM DD, YYYY'}
/>
</Flexbox>
{category && t(`category.assistant.${category}` as any)}

View file

@ -193,7 +193,7 @@ const FavoritePluginCard = memo<FavoritePluginCardProps>(
<PublishedTime
className={styles.secondaryDesc}
date={createdAt}
template={'MMM DD, YYYY'}
/>
</Flexbox>
{category && t(`category.plugin.${category}` as any)}

View file

@ -321,7 +321,7 @@ const UserGroupCard = memo<UserGroupCardProps>(
<PublishedTime
className={styles.secondaryDesc}
date={createdAt}
template={'MMM DD, YYYY'}
/>
</Flexbox>
{category && t(`category.groupAgent.${category}` as any, { defaultValue: category })}

View file

@ -0,0 +1,103 @@
'use client';
import { Button, Flexbox } from '@lobehub/ui';
import { createStaticStyles, cx, responsive } from 'antd-style';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { useIsDark } from '@/hooks/useIsDark';
const styles = createStaticStyles(({ css }) => ({
banner: css`
position: relative;
width: 100%;
padding: 24px 32px;
border-radius: 12px;
${responsive.sm} {
padding: 16px 20px;
}
`,
banner_dark: css`
background: linear-gradient(135deg, #5c3d0e 0%, #7a4f10 50%, #6b3a08 100%);
`,
banner_light: css`
background: linear-gradient(135deg, #fceabb 0%, #f8b500 50%, #e88a20 100%);
`,
subtitle: css`
margin: 0;
font-size: 14px;
font-weight: 400;
line-height: 1.5;
${responsive.sm} {
font-size: 12px;
}
`,
subtitle_dark: css`
color: rgba(255, 255, 255, 0.65);
`,
subtitle_light: css`
color: rgba(0, 0, 0, 0.65);
`,
symbols: css`
position: absolute;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
width: 50%;
border-radius: 0 12px 12px 0;
background: url('/images/banner_creator.png') right center / auto 100% no-repeat;
pointer-events: none;
${responsive.sm} {
display: none;
}
`,
title: css`
margin: 0;
font-size: 22px;
font-weight: 700;
line-height: 1.3;
${responsive.sm} {
font-size: 18px;
}
`,
title_dark: css`
color: rgba(255, 255, 255, 0.88);
`,
title_light: css`
color: rgba(0, 0, 0, 0.88);
`,
}));
const CreatorRewardBanner = memo(() => {
const { t } = useTranslation('discover');
const isDark = useIsDark();
return (
<Flexbox
className={cx(styles.banner, isDark ? styles.banner_dark : styles.banner_light)}
width={'100%'}
>
<Flexbox gap={8} style={{ position: 'relative', zIndex: 1 }}>
<h2 className={cx(styles.title, isDark ? styles.title_dark : styles.title_light)}>
{t('home.creatorReward.title')}
</h2>
<p className={cx(styles.subtitle, isDark ? styles.subtitle_dark : styles.subtitle_light)}>
{t('home.creatorReward.subtitle')}
</p>
<div style={{ marginBlockStart: 4 }}>
<a href={'#'} rel={'noopener noreferrer'} target={'_blank'}>
<Button type={'primary'}>{t('home.creatorReward.action')}</Button>
</a>
</div>
</Flexbox>
<div className={styles.symbols} />
</Flexbox>
);
});
export default CreatorRewardBanner;

View file

@ -9,6 +9,7 @@ import { AssistantSorts, McpSorts } from '@/types/discover';
import Title from '../../components/Title';
import AssistantList from '../agent/features/List';
import McpList from '../mcp/features/List';
import CreatorRewardBanner from './features/CreatorRewardBanner';
import Loading from './loading';
const HomePage = memo(() => {
@ -32,6 +33,7 @@ const HomePage = memo(() => {
return (
<>
<CreatorRewardBanner />
<Title more={t('home.more')} moreLink={'/community/agent'}>
{t('home.featuredAssistants')}
</Title>

View file

@ -3,12 +3,14 @@ import { useTranslation } from 'react-i18next';
import ListLoading from '@/app/[variants]/(main)/community/components/ListLoading';
import Title from '@/app/[variants]/(main)/community/components/Title';
import CreatorRewardBanner from './features/CreatorRewardBanner';
const Loading = memo(() => {
const { t } = useTranslation('discover');
return (
<>
<CreatorRewardBanner />
<Title more={t('home.more')} moreLink={'/community/agent'}>
{t('home.featuredAssistants')}
</Title>

View file

@ -208,7 +208,7 @@ const McpItem = memo<DiscoverMcpItem>(
<PublishedTime
className={styles.secondaryDesc}
date={updatedAt}
template={'MMM DD, YYYY'}
/>
</Flexbox>
<Flexbox horizontal align={'center'} gap={8}>

View file

@ -150,7 +150,7 @@ const ModelItem = memo<DiscoverModelItem>(
<PublishedTime
className={styles.secondaryDesc}
date={releasedAt || dayjs().toISOString()}
template={'MMM DD, YYYY'}
/>
</Flexbox>
<Popover

View file

@ -17,12 +17,13 @@ import { useDropdownMenu } from './useDropdownMenu';
interface KnowledgeBaseItemProps {
active?: boolean;
className?: string;
description?: string | null;
id: string;
name: string;
style?: CSSProperties;
}
const KnowledgeBaseItem = memo<KnowledgeBaseItemProps>(({ id, name, active, style, className }) => {
const KnowledgeBaseItem = memo<KnowledgeBaseItemProps>(({ id, name, description, active, style, className }) => {
const setLibraryId = useResourceManagerStore((s) => s.setLibraryId);
const navigate = useNavigate();
@ -67,7 +68,9 @@ const KnowledgeBaseItem = memo<KnowledgeBaseItemProps>(({ id, name, active, styl
}, [isLoading]);
const dropdownMenu = useDropdownMenu({
description,
id,
name,
toggleEditing,
});

View file

@ -1,21 +1,25 @@
import { type MenuProps } from '@lobehub/ui';
import { Icon } from '@lobehub/ui';
import { App } from 'antd';
import { PencilLine, Trash } from 'lucide-react';
import { FileText, PencilLine, Trash } from 'lucide-react';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { useCreateNewModal } from '@/features/LibraryModal';
import { useKnowledgeBaseStore } from '@/store/library';
interface ActionProps {
description?: string | null;
id: string;
name: string;
toggleEditing: (visible?: boolean) => void;
}
export const useDropdownMenu = ({ id, toggleEditing }: ActionProps): (() => MenuProps['items']) => {
export const useDropdownMenu = ({ id, name, description, toggleEditing }: ActionProps): (() => MenuProps['items']) => {
const { t } = useTranslation(['file', 'common']);
const { modal } = App.useApp();
const removeKnowledgeBase = useKnowledgeBaseStore((s) => s.removeKnowledgeBase);
const { open } = useCreateNewModal();
const handleDelete = () => {
if (!id) return;
@ -30,6 +34,13 @@ export const useDropdownMenu = ({ id, toggleEditing }: ActionProps): (() => Menu
});
};
const handleEditDescription = () => {
open({
id,
initialValues: { description: description || '', name },
});
};
return useCallback(
() =>
[
@ -42,6 +53,15 @@ export const useDropdownMenu = ({ id, toggleEditing }: ActionProps): (() => Menu
toggleEditing(true);
},
},
{
icon: <Icon icon={FileText} />,
key: 'editDescription',
label: t('edit', { ns: 'common' }),
onClick: (info: any) => {
info.domEvent?.stopPropagation();
handleEditDescription();
},
},
{ type: 'divider' },
{
danger: true,
@ -51,6 +71,6 @@ export const useDropdownMenu = ({ id, toggleEditing }: ActionProps): (() => Menu
onClick: handleDelete,
},
].filter(Boolean) as MenuProps['items'],
[t, id, modal, removeKnowledgeBase, toggleEditing, handleDelete],
[t, id, name, description, modal, removeKnowledgeBase, toggleEditing, handleDelete, handleEditDescription, open],
);
};

View file

@ -39,7 +39,7 @@ const LibraryList = memo(() => {
return (
<Flexbox gap={1} paddingInline={4}>
{data?.map((item) => (
<Item id={item.id} key={item.id} name={item.name} />
<Item description={item.description} id={item.id} key={item.id} name={item.name} />
))}
</Flexbox>
);

View file

@ -11,27 +11,22 @@ import { SortType } from '@/types/files';
export const useResourceManagerUrlSync = () => {
const [searchParams, setSearchParams] = useSearchParams();
const [searchQuery, sorter, sortType, viewMode, setSearchQuery, setSorter, setSortType] =
useResourceManagerStore((s) => [
s.searchQuery,
s.sorter,
s.sortType,
s.viewMode,
s.setSearchQuery,
s.setSorter,
s.setSortType,
]);
const [sorter, sortType, viewMode, setSorter, setSortType] = useResourceManagerStore((s) => [
s.sorter,
s.sortType,
s.viewMode,
s.setSorter,
s.setSortType,
]);
// Initialize store from URL on mount (URL → Store)
useEffect(() => {
const q = searchParams.get('q');
const sorterParam = (searchParams.get('sorter') || 'createdAt') as
| 'name'
| 'createdAt'
| 'size';
const sortTypeParam = (searchParams.get('sortType') || SortType.Desc) as SortType;
setSearchQuery(q);
setSorter(sorterParam);
setSortType(sortTypeParam);
// eslint-disable-next-line react-hooks/exhaustive-deps
@ -43,13 +38,6 @@ export const useResourceManagerUrlSync = () => {
(prev) => {
const newParams = new URLSearchParams(prev);
// Search query
if (searchQuery) {
newParams.set('q', searchQuery);
} else {
newParams.delete('q');
}
// Sorter (clear if default)
if (sorter === 'createdAt') {
newParams.delete('sorter');
@ -75,5 +63,5 @@ export const useResourceManagerUrlSync = () => {
},
{ replace: true },
); // Use replace to avoid polluting history
}, [searchQuery, sorter, sortType, viewMode, setSearchParams]);
}, [sorter, sortType, viewMode, setSearchParams]);
};

View file

@ -1,7 +1,5 @@
'use client';
import 'dayjs/locale/zh.js';
import { createStaticStyles, cssVar, cx } from 'antd-style';
import dayjs from 'dayjs';
import { type CSSProperties, type FC } from 'react';
@ -18,6 +16,17 @@ const formatTime = (time?: string) => {
}
};
const formatDate = (date: string, t: (key: string) => string, template?: string) => {
if (template) return dayjs(date).format(template);
const d = dayjs(date);
const now = dayjs();
if (d.isSame(now, 'day')) return t('time.today');
if (d.isSame(now.subtract(1, 'day'), 'day')) return t('time.yesterday');
if (d.isSame(now, 'year')) return d.format(t('time.formatThisYear'));
return d.format(t('time.formatOtherYear'));
};
const styles = createStaticStyles(({ css }) => {
return {
time: css`
@ -28,44 +37,26 @@ const styles = createStaticStyles(({ css }) => {
};
});
interface PrivacyUpdatedProps {
interface PublishedTimeProps {
className?: string;
date: string;
showPrefix?: boolean;
style?: CSSProperties;
template?: string;
}
const PublishedTime: FC<PrivacyUpdatedProps> = ({
date,
style,
className,
template = 'dddd, MMMM D YYYY',
showPrefix = true,
}) => {
const { t, i18n } = useTranslation('discover');
const time = dayjs(date).locale(i18n.language).format(template);
const PublishedTime: FC<PublishedTimeProps> = ({ date, style, className, template }) => {
const { t } = useTranslation('discover');
const time = formatDate(date, t as (key: string) => string, template);
if (showPrefix) {
return (
<div className={cx(styles.time, className)} style={style}>
{t('publishedTime')}{' '}
<time aria-label={'published-date'} dateTime={formatTime(date)}>
{time}
</time>
</div>
);
} else {
return (
<time
aria-label={'published-date'}
className={cx(styles.time, className)}
dateTime={formatTime(date)}
style={style}
>
{time}
</time>
);
}
return (
<time
aria-label={'published-date'}
className={cx(styles.time, className)}
dateTime={formatTime(date)}
style={style}
>
{time}
</time>
);
};
export default PublishedTime;

View file

@ -269,6 +269,7 @@ const SearchResults = memo<SearchResultsProps>(
return (
<CommandItem
description={subtitle}
forceMount
icon={getIcon(result.type)}
key={result.id}
title={titleWithPrefix}

View file

@ -1,4 +1,4 @@
import { Button, Form, Input, TextArea } from '@lobehub/ui';
import { Button, Flexbox, Input, TextArea } from '@lobehub/ui';
import { memo, useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -6,28 +6,43 @@ import { useKnowledgeBaseStore } from '@/store/library';
import { type CreateKnowledgeBaseParams } from '@/types/knowledgeBase';
interface CreateFormProps {
id?: string;
initialValues?: { name?: string; description?: string };
onClose?: () => void;
onSuccess?: (id: string) => void;
}
const CreateForm = memo<CreateFormProps>(({ onClose, onSuccess }) => {
const CreateForm = memo<CreateFormProps>(({ id, initialValues, onClose, onSuccess }) => {
const { t } = useTranslation('knowledgeBase');
const [loading, setLoading] = useState(false);
const [name, setName] = useState(initialValues?.name || '');
const [description, setDescription] = useState(initialValues?.description || '');
const createNewKnowledgeBase = useKnowledgeBaseStore((s) => s.createNewKnowledgeBase);
const updateKnowledgeBase = useKnowledgeBaseStore((s) => s.updateKnowledgeBase);
const isEditMode = !!id;
const handleSubmit = async () => {
if (!name.trim()) return;
const onFinish = async (values: CreateKnowledgeBaseParams) => {
setLoading(true);
const values = { name: name.trim(), description: description.trim() };
try {
const id = await createNewKnowledgeBase(values);
setLoading(false);
// Call onSuccess callback if provided, otherwise navigate directly
if (onSuccess) {
onSuccess(id);
if (isEditMode) {
await updateKnowledgeBase(id, values);
setLoading(false);
onClose?.();
} else {
window.location.href = `/resource/library/${id}`;
const newId = await createNewKnowledgeBase(values);
setLoading(false);
if (onSuccess) {
onSuccess(newId);
onClose?.();
} else {
window.location.href = `/resource/library/${newId}`;
}
}
} catch (e) {
console.error(e);
@ -36,35 +51,26 @@ const CreateForm = memo<CreateFormProps>(({ onClose, onSuccess }) => {
};
return (
<Form
gap={16}
itemsType={'flat'}
layout={'vertical'}
footer={
<Button block htmlType={'submit'} loading={loading} type={'primary'}>
{t('createNew.confirm')}
</Button>
}
items={[
{
children: <Input autoFocus placeholder={t('createNew.name.placeholder')} />,
label: t('createNew.name.placeholder'),
name: 'name',
rules: [{ message: t('createNew.name.required'), required: true }],
},
{
children: (
<TextArea
placeholder={t('createNew.description.placeholder')}
style={{ minHeight: 120 }}
/>
),
label: t('createNew.description.placeholder'),
name: 'description',
},
]}
onFinish={onFinish}
/>
<Flexbox gap={16}>
<Input
autoFocus
placeholder={t('createNew.name.placeholder')}
value={name}
onChange={(e) => setName(e.target.value)}
/>
<Flexbox gap={8}>
<label style={{ fontSize: 14 }}>{t('createNew.description.label')}</label>
<TextArea
placeholder={t('createNew.description.placeholder')}
style={{ minHeight: 120 }}
value={description}
onChange={(e) => setDescription(e.target.value)}
/>
</Flexbox>
<Button block loading={loading} onClick={handleSubmit} type={'primary'}>
{isEditMode ? t('createNew.edit.confirm') : t('createNew.confirm')}
</Button>
</Flexbox>
);
});

View file

@ -1,37 +1,58 @@
import { createModal, Flexbox, useModalContext } from '@lobehub/ui';
import { memo, Suspense, useCallback } from 'react';
import { Flexbox, createModal, useModalContext } from '@lobehub/ui';
import { Suspense, memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import CreateForm from './CreateForm';
interface ModalContentProps {
id?: string;
initialValues?: { name?: string; description?: string };
onSuccess?: (id: string) => void;
}
const ModalContent = memo<ModalContentProps>(({ onSuccess }) => {
const ModalContent = memo<ModalContentProps>(({ id, initialValues, onSuccess }) => {
const { close } = useModalContext();
return (
<Flexbox paddingInline={16} style={{ paddingBottom: 16 }}>
<CreateForm onClose={close} onSuccess={onSuccess} />
<Flexbox paddingInline={8} style={{ paddingBottom: 8 }}>
<CreateForm id={id} initialValues={initialValues} onClose={close} onSuccess={onSuccess} />
</Flexbox>
);
});
ModalContent.displayName = 'KnowledgeBaseCreateModalContent';
interface OpenParams {
id?: string;
initialValues?: { name?: string; description?: string };
onSuccess?: (id: string) => void;
}
export const useCreateNewModal = () => {
const open = useCallback((props?: { onSuccess?: (id: string) => void }) => {
createModal({
children: (
<Suspense fallback={<div style={{ minHeight: 200 }} />}>
<ModalContent onSuccess={props?.onSuccess} />
</Suspense>
),
focusTriggerAfterClose: true,
footer: null,
title: null,
});
}, []);
const { t } = useTranslation('knowledgeBase');
const open = useCallback(
(props?: OpenParams) => {
const isEditMode = !!props?.id;
createModal({
children: (
<Suspense fallback={<div style={{ minHeight: 200 }} />}>
<ModalContent
id={props?.id}
initialValues={props?.initialValues}
onSuccess={props?.onSuccess}
/>
</Suspense>
),
width: 420,
focusTriggerAfterClose: true,
footer: null,
title: isEditMode ? t('createNew.edit.title') : t('createNew.title'),
});
},
[t],
);
return { open };
};

View file

@ -234,7 +234,7 @@ const Header = memo<{ inModal?: boolean; mobile?: boolean }>(({ mobile: isMobile
<PublishedTime
className={styles.time}
date={(updatedAt || createdAt) as string}
template={'MMM DD, YYYY'}
/>
</Flexbox>
</Flexbox>

View file

@ -0,0 +1,93 @@
'use client';
import { ActionIcon } from '@lobehub/ui';
import { Input } from 'antd';
import { useDebounce } from 'ahooks';
import { SearchIcon, XIcon } from 'lucide-react';
import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
const SearchInput = memo(() => {
const { t } = useTranslation('components');
const [expanded, setExpanded] = useState(false);
const [showIcon, setShowIcon] = useState(true);
const [localQuery, setLocalQuery] = useState('');
const inputRef = useRef<any>(null);
const setSearchQuery = useResourceManagerStore((s) => s.setSearchQuery);
const debouncedQuery = useDebounce(localQuery, { wait: 350 });
useEffect(() => {
if (!expanded) return;
setSearchQuery(debouncedQuery || null);
}, [debouncedQuery, expanded, setSearchQuery]);
const handleExpand = useCallback(() => {
setShowIcon(false);
setExpanded(true);
setTimeout(() => inputRef.current?.focus(), 0);
}, []);
const handleCollapse = useCallback(() => {
setExpanded(false);
setLocalQuery('');
setSearchQuery(null);
}, [setSearchQuery]);
const handleBlur = useCallback(() => {
if (!localQuery) {
handleCollapse();
}
}, [localQuery, handleCollapse]);
const handleTransitionEnd = useCallback(() => {
if (!expanded) {
setShowIcon(true);
}
}, [expanded]);
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === 'Escape') {
handleCollapse();
}
},
[handleCollapse],
);
return (
<>
<div
onTransitionEnd={handleTransitionEnd}
style={{
opacity: expanded ? 1 : 0,
overflow: 'hidden',
transition: 'width 240ms ease-out, opacity 200ms ease-out',
width: expanded ? 200 : 0,
}}
>
<Input
onBlur={handleBlur}
onChange={(e) => setLocalQuery(e.target.value)}
onKeyDown={handleKeyDown}
placeholder={t('FileManager.search.placeholder')}
prefix={<SearchIcon size={14} />}
ref={inputRef}
size="small"
style={{ width: 200 }}
suffix={localQuery ? <XIcon onClick={handleCollapse} size={14} style={{ cursor: 'pointer' }} /> : undefined}
value={localQuery}
/>
</div>
{showIcon && (
<ActionIcon icon={SearchIcon} onClick={handleExpand} style={{ marginRight: 4 }} />
)}
</>
);
});
SearchInput.displayName = 'SearchInput';
export default SearchInput;

View file

@ -3,13 +3,12 @@
import { ActionIcon, Flexbox } from '@lobehub/ui';
import { App } from 'antd';
import { cssVar } from 'antd-style';
import { BookMinusIcon, FileBoxIcon, SearchIcon, Trash2Icon } from 'lucide-react';
import { BookMinusIcon, FileBoxIcon, Trash2Icon } from 'lucide-react';
import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
import NavHeader from '@/features/NavHeader';
import { useGlobalStore } from '@/store/global';
import { FilesTabs } from '@/types/files';
import AddButton from '../../Header/AddButton';
@ -17,6 +16,7 @@ import BatchActionsDropdown from '../ToolBar/BatchActionsDropdown';
import SortDropdown from '../ToolBar/SortDropdown';
import ViewSwitcher from '../ToolBar/ViewSwitcher';
import Breadcrumb from './Breadcrumb';
import SearchInput from './SearchInput';
/**
* Toolbar for the resource explorer
@ -32,8 +32,6 @@ const Header = memo(() => {
s.onActionClick,
s.selectedFileIds,
]);
const toggleCommandMenu = useGlobalStore((s) => s.toggleCommandMenu);
const selectCount = selectFileIds.length;
const isMultiSelected = selectCount > 1;
@ -103,7 +101,7 @@ const Header = memo(() => {
left={leftContent}
right={
<>
<ActionIcon icon={SearchIcon} onClick={() => toggleCommandMenu(true)} />
<SearchInput />
<SortDropdown />
<BatchActionsDropdown selectCount={selectCount} onActionClick={onActionClick} />
<ViewSwitcher />

View file

@ -404,6 +404,7 @@ const FileListItem = memo<FileListItemProps>(
onDragOver={handleDragOver}
onDragStart={handleDragStart}
onDrop={handleDrop}
onClick={handleItemClick}
onMouseEnter={() => onHoverChange(true)}
onMouseLeave={() => onHoverChange(false)}
>
@ -437,7 +438,6 @@ const FileListItem = memo<FileListItemProps>(
paddingInline: 8,
width: columnWidths.name,
}}
onClick={handleItemClick}
>
<Flexbox horizontal align={'center'} className={styles.nameContainer}>
<Flexbox

View file

@ -60,7 +60,6 @@ const ListView = memo(function ListView() {
const [
libraryId,
category,
searchQuery,
selectFileIds,
setSelectedFileIds,
pendingRenameItemId,
@ -70,7 +69,6 @@ const ListView = memo(function ListView() {
] = useResourceManagerStore((s) => [
s.libraryId,
s.category,
s.searchQuery,
s.selectedFileIds,
s.setSelectedFileIds,
s.pendingRenameItemId,
@ -107,12 +105,11 @@ const ListView = memo(function ListView() {
category: libraryId ? undefined : category,
libraryId,
parentId: currentFolderSlug || null,
q: searchQuery ?? undefined,
showFilesInKnowledgeBase: false,
sortType,
sorter,
}),
[category, currentFolderSlug, libraryId, searchQuery, sorter, sortType],
[category, currentFolderSlug, libraryId, sorter, sortType],
);
const { isLoading, isValidating } = useFetchResources(queryParams);
@ -124,8 +121,7 @@ const ListView = memo(function ListView() {
return (
currentQueryParams.libraryId !== queryParams.libraryId ||
currentQueryParams.parentId !== queryParams.parentId ||
currentQueryParams.category !== queryParams.category ||
currentQueryParams.q !== queryParams.q
currentQueryParams.category !== queryParams.category
);
}, [currentQueryParams, queryParams]);

View file

@ -22,7 +22,6 @@ const MasonryView = memo(function MasonryView() {
const [
libraryId,
category,
searchQuery,
selectedFileIds,
setSelectedFileIds,
storeIsMasonryReady,
@ -32,7 +31,6 @@ const MasonryView = memo(function MasonryView() {
] = useResourceManagerStore((s) => [
s.libraryId,
s.category,
s.searchQuery,
s.selectedFileIds,
s.setSelectedFileIds,
s.isMasonryReady,
@ -53,12 +51,11 @@ const MasonryView = memo(function MasonryView() {
category: libraryId ? undefined : category,
libraryId,
parentId: null,
q: searchQuery ?? undefined,
showFilesInKnowledgeBase: false,
sortType,
sorter,
}),
[category, libraryId, searchQuery, sorter, sortType],
[category, libraryId, sorter, sortType],
);
const { isLoading, isValidating } = useFetchResources(queryParams);
@ -70,8 +67,7 @@ const MasonryView = memo(function MasonryView() {
return (
currentQueryParams.libraryId !== queryParams.libraryId ||
currentQueryParams.parentId !== queryParams.parentId ||
currentQueryParams.category !== queryParams.category ||
currentQueryParams.q !== queryParams.q
currentQueryParams.category !== queryParams.category
);
}, [currentQueryParams, queryParams]);

View file

@ -0,0 +1,231 @@
'use client';
import { Center, Checkbox, Flexbox } from '@lobehub/ui';
import { VirtuosoMasonry } from '@virtuoso.dev/masonry';
import { cssVar } from 'antd-style';
import { SearchIcon } from 'lucide-react';
import { memo, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Virtuoso } from 'react-virtuoso';
import { useResourceManagerStore } from '@/app/[variants]/(main)/resource/features/store';
import NeuralNetworkLoading from '@/components/NeuralNetworkLoading';
import { useClientDataSWR } from '@/libs/swr';
import { resourceService } from '@/services/resource';
import { useGlobalStore } from '@/store/global';
import { INITIAL_STATUS } from '@/store/global/initialState';
import type { AsyncTaskStatus } from '@/types/asyncTask';
import type { FileListItem } from '@/types/files';
import FileListItemComponent from './ListView/ListItem';
import MasonryItemWrapper from './MasonryView/MasonryItem/MasonryItemWrapper';
import { useMasonryColumnCount } from './useMasonryColumnCount';
const SWR_RESOURCE_SEARCH = 'SWR_RESOURCE_SEARCH';
const SearchResultsOverlay = memo(() => {
const { t } = useTranslation('components');
const [searchQuery, libraryId, category, viewMode] = useResourceManagerStore((s) => [
s.searchQuery,
s.libraryId,
s.category,
s.viewMode,
]);
const [selectedFileIds, setSelectedFileIds] = useState<string[]>([]);
const columnWidths = useGlobalStore(
(s) => s.status.resourceManagerColumnWidths || INITIAL_STATUS.resourceManagerColumnWidths,
);
const columnCount = useMasonryColumnCount();
const isActive = !!searchQuery && searchQuery.length > 0;
const { data: rawData, isLoading } = useClientDataSWR(
isActive
? [
SWR_RESOURCE_SEARCH,
{ category: libraryId ? undefined : category, libraryId, q: searchQuery },
]
: null,
async ([, params]: [string, { category?: string; libraryId?: string; q: string }]) => {
const response = await resourceService.queryResources({
...params,
limit: 50,
offset: 0,
showFilesInKnowledgeBase: false,
} as any);
return response.items;
},
);
const data: FileListItem[] | undefined = useMemo(
() =>
rawData?.map((item) => ({
...item,
chunkCount: item.chunkCount ?? null,
chunkingError: item.chunkingError ?? null,
chunkingStatus: (item.chunkingStatus ?? null) as AsyncTaskStatus | null,
embeddingError: item.embeddingError ?? null,
embeddingStatus: (item.embeddingStatus ?? null) as AsyncTaskStatus | null,
finishEmbedding: item.finishEmbedding ?? false,
url: item.url ?? '',
})),
[rawData],
);
const masonryContext = useMemo(
() => ({
knowledgeBaseId: libraryId ?? undefined,
selectFileIds: selectedFileIds,
setSelectedFileIds,
}),
[libraryId, selectedFileIds],
);
if (!isActive) return null;
return (
<div
style={{
background: cssVar.colorBgContainer as string,
bottom: 0,
display: 'flex',
flexDirection: 'column',
left: 0,
position: 'absolute',
right: 0,
top: 0,
zIndex: 10,
}}
>
{isLoading ? (
<Center height="100%">
<NeuralNetworkLoading size={48} />
</Center>
) : !data || data.length === 0 ? (
<Center height="100%">
<Flexbox align="center" gap={8}>
<SearchIcon size={32} style={{ color: cssVar.colorTextQuaternary as string }} />
<span style={{ color: cssVar.colorTextDescription as string, fontSize: 14 }}>
{t('FileManager.search.noResults')}
</span>
</Flexbox>
</Center>
) : viewMode === 'list' ? (
<Flexbox height={'100%'}>
<div style={{ flex: 1, overflow: 'auto hidden' }}>
<Flexbox
align="center"
horizontal
paddingInline={8}
style={{
borderBlockEnd: `1px solid ${cssVar.colorBorderSecondary}`,
color: cssVar.colorTextDescription as string,
fontSize: 12,
height: 40,
minHeight: 40,
minWidth: 800,
}}
>
<Center height={40} style={{ paddingInline: 4 }}>
<Checkbox checked={false} disabled />
</Center>
<Flexbox
justify="center"
style={{
flexShrink: 0,
height: '100%',
maxWidth: columnWidths.name,
minWidth: columnWidths.name,
paddingBlock: 6,
paddingInline: '20px 16px',
width: columnWidths.name,
}}
>
{t('FileManager.title.title')}
</Flexbox>
<Flexbox
justify="center"
style={{
flexShrink: 0,
height: '100%',
paddingBlock: 6,
paddingInlineEnd: 16,
width: columnWidths.date,
}}
>
{t('FileManager.title.createdAt')}
</Flexbox>
<Flexbox
justify="center"
style={{
flexShrink: 0,
height: '100%',
paddingBlock: 6,
paddingInlineEnd: 16,
width: columnWidths.size,
}}
>
{t('FileManager.title.size')}
</Flexbox>
</Flexbox>
<div style={{ height: 'calc(100% - 40px)', overflow: 'hidden', position: 'relative' }}>
<Virtuoso
data={data}
defaultItemHeight={48}
itemContent={(index, item) => {
if (!item) return null;
return (
<FileListItemComponent
columnWidths={columnWidths}
index={index}
isAnyRowHovered={false}
key={item.id}
selected={selectedFileIds.includes(item.id)}
onHoverChange={() => {}}
onSelectedChange={(id, checked) => {
if (checked) {
setSelectedFileIds((prev) => [...prev, id]);
} else {
setSelectedFileIds((prev) => prev.filter((fid) => fid !== id));
}
}}
{...item}
/>
);
}}
style={{ height: '100%' }}
/>
</div>
</div>
</Flexbox>
) : (
<div
style={{
flex: 1,
height: '100%',
overflowY: 'auto',
}}
>
<div style={{ paddingBlockEnd: 24, paddingBlockStart: 12, paddingInline: 24 }}>
<VirtuosoMasonry
ItemContent={MasonryItemWrapper}
columnCount={columnCount}
context={masonryContext}
data={data}
style={{
gap: '16px',
overflow: 'hidden',
}}
/>
</div>
</div>
)}
</div>
);
});
SearchResultsOverlay.displayName = 'SearchResultsOverlay';
export default SearchResultsOverlay;

View file

@ -13,6 +13,7 @@ import EmptyPlaceholder from './EmptyPlaceholder';
import Header from './Header';
import ListView from './ListView';
import MasonryView from './MasonryView';
import SearchResultsOverlay from './SearchResultsOverlay';
import { useCheckTaskStatus } from './useCheckTaskStatus';
import { useResourceExplorer } from './useResourceExplorer';
@ -40,6 +41,8 @@ const ResourceExplorer = memo(() => {
s.sortType,
]);
// searchQuery is still subscribed above for selection-clearing effect below
// Get folder path for empty state check
const { currentFolderSlug } = useFolderPath();
@ -51,12 +54,11 @@ const ResourceExplorer = memo(() => {
category: libraryId ? undefined : category,
libraryId,
parentId: currentFolderSlug || null,
q: searchQuery ?? undefined,
showFilesInKnowledgeBase: false,
sortType,
sorter,
}),
[category, libraryId, currentFolderSlug, searchQuery, sortType, sorter],
[category, libraryId, currentFolderSlug, sortType, sorter],
);
// Use SWR for data fetching with automatic caching and revalidation
@ -98,13 +100,16 @@ const ResourceExplorer = memo(() => {
return (
<Flexbox height={'100%'}>
<Header />
{showEmptyStatus ? (
<EmptyPlaceholder />
) : viewMode === 'list' ? (
<ListView />
) : (
<MasonryView />
)}
<div style={{ flex: 1, overflow: 'hidden', position: 'relative' }}>
{showEmptyStatus ? (
<EmptyPlaceholder />
) : viewMode === 'list' ? (
<ListView />
) : (
<MasonryView />
)}
<SearchResultsOverlay />
</div>
</Flexbox>
);
});

View file

@ -49,6 +49,8 @@ export default {
'FileManager.emptyStatus.or': 'or',
'FileManager.emptyStatus.title': 'Drag files or folders here',
'FileManager.noFolders': 'No folders available',
'FileManager.search.noResults': 'No files found',
'FileManager.search.placeholder': 'Search files...',
'FileManager.sort.dateAdded': 'Date Added',
'FileManager.sort.name': 'Name',
'FileManager.sort.size': 'Size',

View file

@ -171,6 +171,10 @@ export default {
'groupAgents.underReview': 'Under Review',
'home.creatorReward.action': 'Apply Now',
'home.creatorReward.subtitle': '2026 Creator Reward Program is officially live.',
'home.creatorReward.title': 'Create. Share. Get Paid.',
'home.communityAgents': 'Community Agents',
'home.featuredAssistants': 'Featured Agents',
@ -262,6 +266,10 @@ export default {
'mcp.categories.travel-transport.name': 'Travel & Transport',
'mcp.categories.utility.name': 'Utility',
'mcp.categories.utility.description': 'Weather Forecasting and Meteorological Services',
'mcp.categories.weather.description': 'Weather Forecasting and Meteorological Services',
'mcp.categories.weather.name': 'Weather',
@ -846,6 +854,11 @@ export default {
'publishedTime': 'Published',
'time.formatOtherYear': 'MMM D, YYYY',
'time.formatThisYear': 'MMM D',
'time.today': 'Today',
'time.yesterday': 'Yesterday',
'search.placeholder': 'Search by name, description, or keywords...',
'search.result': '{{count}} results about <highlight>{{keyword}}</highlight>',

View file

@ -11,7 +11,10 @@ export default {
'moveToKnowledgeBase.error': 'Failed to move file to Library',
'moveToKnowledgeBase.success': 'File moved successfully',
'createNew.confirm': 'Create New',
'createNew.description.placeholder': 'Library description (optional)',
'createNew.edit.confirm': 'Save Changes',
'createNew.edit.title': 'Edit Library',
'createNew.description.label': 'Library Description (Optional)',
'createNew.description.placeholder': 'Description helps LLM understand your library better',
'createNew.formTitle': 'Basic Information',
'createNew.name.placeholder': 'Library name',
'createNew.name.required': 'Please enter a library name',