setSearchQuery(e.target.value)}
className="pl-10 h-11"
@@ -138,9 +139,9 @@ function App() {
) : filteredSnippets.length === 0 ? (
-
No snippets found
+
{strings.noResults.title}
- Try adjusting your search query
+ {strings.noResults.description}
) : (
diff --git a/src/ErrorFallback.tsx b/src/ErrorFallback.tsx
index 5550b44..c256851 100644
--- a/src/ErrorFallback.tsx
+++ b/src/ErrorFallback.tsx
@@ -1,110 +1,99 @@
-import { useState } from "react";
-import { Alert, AlertTitle, AlertDescription } from "./components/ui/alert";
-import { AIErrorHelper } from "./components/AIEr
-import { AlertTriangleIcon, RefreshCwIcon, ChevronDownIcon,
-import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./components/ui/collapsible";
-import { AlertTriangleIcon, RefreshCwIcon, ChevronDownIcon, ChevronUpIcon, CopyIcon, CheckIcon } from "lucide-react";
-
-interface ErrorFallbackProps {
-
- if (import.meta.env.DEV) throw
-
-
-
- navigator.clipboard.writeText(error
-
-
- const [copied, setCopied] = useState(false);
-
- const errorDetails = `Error: ${error.message}\n\nStack Trace:\n${error.stack || 'No stack trace available'}`;
-
- const handleCopy = () => {
- navigator.clipboard.writeText(errorDetails);
- setCopied(true);
- setTimeout(() => setCopied(false), 2000);
- };
-
- return (
-
-
-
-
- This spark has encountered a runtime error
- onClick={handl
- >
- <>
-
-
-
- >
-
-
- {error.message}
-
-
- <>
-
- )}
-
- {error.s
-
- Tr
-
-
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+import { useState } from "react";
+import { Alert, AlertTitle, AlertDescription } from "./components/ui/alert";
+import { AIErrorHelper } from "./components/AIErrorHelper";
+import { Button } from "./components/ui/button";
+import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "./components/ui/collapsible";
+import { AlertTriangleIcon, RefreshCwIcon, ChevronDownIcon, ChevronUpIcon, CopyIcon, CheckIcon } from "lucide-react";
+
+interface ErrorFallbackProps {
+ error: Error;
+}
+
+export function ErrorFallback({ error }: ErrorFallbackProps) {
+ if (import.meta.env.DEV) throw error;
+
+ const [isStackOpen, setIsStackOpen] = useState(false);
+ const [copied, setCopied] = useState(false);
+
+ const errorDetails = `Error: ${error.message}\n\nStack Trace:\n${error.stack || 'No stack trace available'}`;
+
+ const handleCopy = () => {
+ navigator.clipboard.writeText(errorDetails);
+ setCopied(true);
+ setTimeout(() => setCopied(false), 2000);
+ };
+
+ return (
+
+
+
+
+ This spark has encountered a runtime error
+
+
+
+ {error.message}
+
+
+
+
+
+
+
+
+
+
+
+ {error.stack || 'No stack trace available'}
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/EmptyState.tsx b/src/components/EmptyState.tsx
index ecd9107..5e3144e 100644
--- a/src/components/EmptyState.tsx
+++ b/src/components/EmptyState.tsx
@@ -1,5 +1,6 @@
import { Code } from '@phosphor-icons/react'
import { Button } from '@/components/ui/button'
+import { strings } from '@/lib/config'
interface EmptyStateProps {
onCreateClick: () => void
@@ -11,13 +12,13 @@ export function EmptyState({ onCreateClick }: EmptyStateProps) {
-
No snippets yet
+
{strings.emptyState.title}
- Start building your code snippet library. Save reusable code for quick access anytime.
+ {strings.emptyState.description}
)
diff --git a/src/components/SnippetCard.tsx b/src/components/SnippetCard.tsx
index 3bb8efa..6cb0609 100644
--- a/src/components/SnippetCard.tsx
+++ b/src/components/SnippetCard.tsx
@@ -4,6 +4,7 @@ import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import { Copy, Pencil, Trash, Eye } from '@phosphor-icons/react'
import { Snippet, LANGUAGE_COLORS } from '@/lib/types'
+import { strings, appConfig } from '@/lib/config'
interface SnippetCardProps {
snippet: Snippet
@@ -20,7 +21,7 @@ export function SnippetCard({ snippet, onEdit, onDelete, onCopy, onView }: Snipp
try {
const code = snippet?.code || ''
const description = snippet?.description || ''
- const maxLength = 150
+ const maxLength = appConfig.codePreviewMaxLength
const isTruncated = code.length > maxLength
const displayCode = isTruncated ? code.slice(0, maxLength) + '...' : code
@@ -46,7 +47,7 @@ export function SnippetCard({ snippet, onEdit, onDelete, onCopy, onView }: Snipp
e.stopPropagation()
onCopy(snippetData.fullCode)
setIsCopied(true)
- setTimeout(() => setIsCopied(false), 2000)
+ setTimeout(() => setIsCopied(false), appConfig.copiedTimeout)
}
const handleEdit = (e: React.MouseEvent) => {
@@ -66,7 +67,7 @@ export function SnippetCard({ snippet, onEdit, onDelete, onCopy, onView }: Snipp
if (!snippet) {
return (
- Click to view full code...
+ {strings.snippetCard.viewFullCode}
)}
@@ -115,7 +116,7 @@ export function SnippetCard({ snippet, onEdit, onDelete, onCopy, onView }: Snipp
className="gap-2"
>
@@ -124,16 +125,16 @@ export function SnippetCard({ snippet, onEdit, onDelete, onCopy, onView }: Snipp
size="sm"
onClick={handleCopy}
className="gap-2"
- aria-label="Copy code"
+ aria-label={strings.snippetCard.ariaLabels.copy}
>
- {isCopied ? 'Copied!' : 'Copy'}
+ {isCopied ? strings.snippetCard.copiedButton : strings.snippetCard.copyButton}
@@ -142,7 +143,7 @@ export function SnippetCard({ snippet, onEdit, onDelete, onCopy, onView }: Snipp
size="sm"
onClick={handleDelete}
className="text-destructive hover:text-destructive hover:bg-destructive/10"
- aria-label="Delete snippet"
+ aria-label={strings.snippetCard.ariaLabels.delete}
>
diff --git a/src/components/SnippetDialog.tsx b/src/components/SnippetDialog.tsx
index 2975d88..80b1ae7 100644
--- a/src/components/SnippetDialog.tsx
+++ b/src/components/SnippetDialog.tsx
@@ -21,6 +21,7 @@ import {
} from '@/components/ui/select'
import { Snippet, LANGUAGES } from '@/lib/types'
import { MonacoEditor } from '@/components/MonacoEditor'
+import { strings, appConfig } from '@/lib/config'
interface SnippetDialogProps {
open: boolean
@@ -32,7 +33,7 @@ interface SnippetDialogProps {
export function SnippetDialog({ open, onOpenChange, onSave, editingSnippet }: SnippetDialogProps) {
const [title, setTitle] = useState('')
const [description, setDescription] = useState('')
- const [language, setLanguage] = useState('JavaScript')
+ const [language, setLanguage] = useState(appConfig.defaultLanguage)
const [code, setCode] = useState('')
const [hasPreview, setHasPreview] = useState(false)
const [errors, setErrors] = useState<{ title?: string; code?: string }>({})
@@ -47,7 +48,7 @@ export function SnippetDialog({ open, onOpenChange, onSave, editingSnippet }: Sn
} else {
setTitle('')
setDescription('')
- setLanguage('JavaScript')
+ setLanguage(appConfig.defaultLanguage)
setCode('')
setHasPreview(false)
}
@@ -58,10 +59,10 @@ export function SnippetDialog({ open, onOpenChange, onSave, editingSnippet }: Sn
const newErrors: { title?: string; code?: string } = {}
if (!title.trim()) {
- newErrors.title = 'Title is required'
+ newErrors.title = strings.snippetDialog.fields.title.errorMessage
}
if (!code.trim()) {
- newErrors.code = 'Code is required'
+ newErrors.code = strings.snippetDialog.fields.code.errorMessage
}
if (Object.keys(newErrors).length > 0) {
@@ -79,7 +80,7 @@ export function SnippetDialog({ open, onOpenChange, onSave, editingSnippet }: Sn
setTitle('')
setDescription('')
- setLanguage('JavaScript')
+ setLanguage(appConfig.defaultLanguage)
setCode('')
setHasPreview(false)
setErrors({})
@@ -91,21 +92,23 @@ export function SnippetDialog({ open, onOpenChange, onSave, editingSnippet }: Sn
- {editingSnippet ? 'Edit Snippet' : 'Create New Snippet'}
+ {editingSnippet ? strings.snippetDialog.edit.title : strings.snippetDialog.create.title}
{editingSnippet
- ? 'Update your code snippet details below.'
- : 'Save a reusable code snippet for quick access later.'}
+ ? strings.snippetDialog.edit.description
+ : strings.snippetDialog.create.description}
-
+
setTitle(e.target.value)}
className={errors.title ? 'border-destructive ring-destructive' : ''}
@@ -116,7 +119,7 @@ export function SnippetDialog({ open, onOpenChange, onSave, editingSnippet }: Sn
-
+
- {['JSX', 'TSX', 'JavaScript', 'TypeScript'].includes(language) && (
+ {appConfig.previewEnabledLanguages.includes(language) && (
- Enable split-screen preview for this snippet
+ {strings.snippetDialog.fields.preview.label}
)}
-
+
-
+
diff --git a/src/components/SnippetViewer.tsx b/src/components/SnippetViewer.tsx
index 649e661..4b4ca14 100644
--- a/src/components/SnippetViewer.tsx
+++ b/src/components/SnippetViewer.tsx
@@ -12,6 +12,7 @@ import { MonacoEditor } from '@/components/MonacoEditor'
import { ReactPreview } from '@/components/ReactPreview'
import { cn } from '@/lib/utils'
import { useState } from 'react'
+import { strings, appConfig } from '@/lib/config'
interface SnippetViewerProps {
snippet: Snippet | null
@@ -30,7 +31,7 @@ export function SnippetViewer({ snippet, open, onOpenChange, onEdit, onCopy }: S
const handleCopy = () => {
onCopy(snippet.code)
setIsCopied(true)
- setTimeout(() => setIsCopied(false), 2000)
+ setTimeout(() => setIsCopied(false), appConfig.copiedTimeout)
}
const handleEdit = () => {
@@ -38,7 +39,7 @@ export function SnippetViewer({ snippet, open, onOpenChange, onEdit, onCopy }: S
onEdit(snippet)
}
- const canPreview = snippet.hasPreview && ['JSX', 'TSX', 'JavaScript', 'TypeScript'].includes(snippet.language)
+ const canPreview = snippet.hasPreview && appConfig.previewEnabledLanguages.includes(snippet.language)
return (
@@ -78,7 +79,7 @@ export function SnippetViewer({ snippet, open, onOpenChange, onEdit, onCopy }: S
className="gap-2"
>
- {showPreview ? 'Hide' : 'Show'} Preview
+ {showPreview ? strings.snippetViewer.buttons.hidePreview : strings.snippetViewer.buttons.showPreview}
)}
@@ -106,7 +107,7 @@ export function SnippetViewer({ snippet, open, onOpenChange, onEdit, onCopy }: S
className="gap-2"
>
- Edit
+ {strings.snippetViewer.buttons.edit}