diff --git a/app/components/@settings/tabs/connections/components/RepositoryList.tsx b/app/components/@settings/tabs/connections/components/RepositoryList.tsx index d6f0abda..7f90a98e 100644 --- a/app/components/@settings/tabs/connections/components/RepositoryList.tsx +++ b/app/components/@settings/tabs/connections/components/RepositoryList.tsx @@ -1,6 +1,7 @@ import React, { useContext } from 'react'; import type { GitHubRepoInfo } from '~/types/GitHub'; import { EmptyState, StatusIndicator } from '~/components/ui'; +import { useI18n } from '~/hooks/useI18n'; import { RepositoryCard } from './RepositoryCard'; import { RepositoryDialogContext } from './RepositoryDialogContext'; @@ -12,15 +13,16 @@ interface RepositoryListProps { } export function RepositoryList({ repos, isLoading, onSelect, activeTab }: RepositoryListProps) { + const { t } = useI18n(); // Access the parent component's setShowAuthDialog function const { setShowAuthDialog } = useContext(RepositoryDialogContext); if (isLoading) { return (
- +

- This may take a moment + {t('This may take a moment')}

); @@ -31,9 +33,9 @@ export function RepositoryList({ repos, isLoading, onSelect, activeTab }: Reposi return ( setShowAuthDialog(true)} /> ); @@ -41,8 +43,8 @@ export function RepositoryList({ repos, isLoading, onSelect, activeTab }: Reposi return ( ); } diff --git a/app/components/I18nProvider.tsx b/app/components/I18nProvider.tsx new file mode 100644 index 00000000..76fa8cbe --- /dev/null +++ b/app/components/I18nProvider.tsx @@ -0,0 +1,51 @@ +import React, { useState, useCallback } from 'react'; +import { I18nContext, I18nContextType } from '../context/i18n'; + +interface I18nProviderProps { + children: React.ReactNode; +} + +// Basic translations (replace with a proper i18n library later) +const translations: Record> = { + en: { + greeting: 'Hello', + welcome: 'Welcome to our application!', + 'Loading repositories...': 'Loading repositories...', + 'This may take a moment': 'This may take a moment', + 'No repositories found': 'No repositories found', + 'Connect your GitHub account or create a new repository to get started': 'Connect your GitHub account or create a new repository to get started', + 'Connect GitHub Account': 'Connect GitHub Account', + 'Try searching with different keywords or filters': 'Try searching with different keywords or filters', + }, + es: { + greeting: 'Hola', + welcome: '¡Bienvenido a nuestra aplicación!', + 'Loading repositories...': 'Cargando repositorios...', + 'This may take a moment': 'Esto puede tomar un momento', + 'No repositories found': 'No se encontraron repositorios', + 'Connect your GitHub account or create a new repository to get started': 'Conecta tu cuenta de GitHub o crea un nuevo repositorio para comenzar', + 'Connect GitHub Account': 'Conectar cuenta de GitHub', + 'Try searching with different keywords or filters': 'Intenta buscar con diferentes palabras clave o filtros', + }, +}; + +export const I18nProvider: React.FC = ({ children }) => { + const [locale, setLocale] = useState('en'); + + const t = useCallback( + (key: string): string => { + return translations[locale]?.[key] || key; + }, + [locale] + ); + + const contextValue: I18nContextType = { + locale, + setLocale, + t, + }; + + return ( + {children} + ); +}; diff --git a/app/components/LanguageSelector.tsx b/app/components/LanguageSelector.tsx new file mode 100644 index 00000000..62400210 --- /dev/null +++ b/app/components/LanguageSelector.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { useI18n } from '../hooks/useI18n'; +import { Button } from './ui/Button'; // Assuming a Button component exists + +export const LanguageSelector: React.FC = () => { + const { locale, setLocale } = useI18n(); + + return ( +
+ + +
+ ); +}; diff --git a/app/components/chat/ChatSkeleton.tsx b/app/components/chat/ChatSkeleton.tsx new file mode 100644 index 00000000..cc40d0f8 --- /dev/null +++ b/app/components/chat/ChatSkeleton.tsx @@ -0,0 +1,27 @@ +// app/components/chat/ChatSkeleton.tsx +export function ChatSkeleton() { + return ( +
+
+
+
+
+
+ {/* Placeholder for a few messages */} + {[1, 2, 3].map((i) => ( +
+
+
+
+
+
+
+ ))} + {/* Placeholder for chat input box */} +
+
+
+
+
+ ); +} diff --git a/app/context/i18n.tsx b/app/context/i18n.tsx new file mode 100644 index 00000000..b61d8fb4 --- /dev/null +++ b/app/context/i18n.tsx @@ -0,0 +1,9 @@ +import { createContext } from 'react'; + +export interface I18nContextType { + locale: string; + setLocale: (locale: string) => void; + t: (key: string) => string; +} + +export const I18nContext = createContext(undefined); diff --git a/app/hooks/useI18n.ts b/app/hooks/useI18n.ts new file mode 100644 index 00000000..77233afb --- /dev/null +++ b/app/hooks/useI18n.ts @@ -0,0 +1,10 @@ +import { useContext } from 'react'; +import { I18nContext, I18nContextType } from '../context/i18n'; + +export const useI18n = (): I18nContextType => { + const context = useContext(I18nContext); + if (context === undefined) { + throw new Error('useI18n must be used within an I18nProvider'); + } + return context; +}; diff --git a/app/root.tsx b/app/root.tsx index a7ccb285..ff1587f0 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,6 +1,8 @@ import { useStore } from '@nanostores/react'; import type { LinksFunction } from '@remix-run/cloudflare'; import { Links, Meta, Outlet, Scripts, ScrollRestoration } from '@remix-run/react'; +import { I18nProvider } from './components/I18nProvider'; +import { LanguageSelector } from './components/LanguageSelector'; import tailwindReset from '@unocss/reset/tailwind-compat.css?url'; import { themeStore } from './lib/stores/theme'; import { stripIndents } from './utils/stripIndent'; diff --git a/app/routes/_index.tsx b/app/routes/_index.tsx index 65df404a..0207af8a 100644 --- a/app/routes/_index.tsx +++ b/app/routes/_index.tsx @@ -1,9 +1,10 @@ import { json, type MetaFunction } from '@remix-run/cloudflare'; import { ClientOnly } from 'remix-utils/client-only'; -import { BaseChat } from '~/components/chat/BaseChat'; +import { BaseChat } from '~/components/chat/BaseChat'; // Keep BaseChat import if Chat.client still needs it, or remove if ChatSkeleton replaces all BaseChat SSR usage import { Chat } from '~/components/chat/Chat.client'; import { Header } from '~/components/header/Header'; import BackgroundRays from '~/components/ui/BackgroundRays'; +import { ChatSkeleton } from '~/components/chat/ChatSkeleton'; // Import the new skeleton export const meta: MetaFunction = () => { return [{ title: 'Bolt' }, { name: 'description', content: 'Talk with Bolt, an AI assistant from StackBlitz' }]; @@ -22,7 +23,7 @@ export default function Index() {
- }>{() => } + }>{() => }
); }