diff --git a/index.html b/index.html index 3e3c259..7195422 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - Half Counter + Code Snippets diff --git a/spark.meta.json b/spark.meta.json index 599b9f8..fd74d91 100644 --- a/spark.meta.json +++ b/spark.meta.json @@ -1,3 +1,4 @@ -{ - "templateVersion": 0, - +{ + "templateVersion": 0, + "dbType": null +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index e287fb2..6e790a5 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,151 +1,179 @@ +import { useState } from 'react' import { useKV } from '@github/spark/hooks' import { Button } from '@/components/ui/button' -import { Card } from '@/components/ui/card' -import { Separator } from '@/components/ui/separator' -import { Plus, Minus, ArrowCounterClockwise, Warning } from '@phosphor-icons/react' -import { motion, AnimatePresence } from 'framer-motion' +import { Input } from '@/components/ui/input' +import { Plus, MagnifyingGlass, Code } from '@phosphor-icons/react' +import { Snippet } from '@/lib/types' +import { SnippetCard } from '@/components/SnippetCard' +import { SnippetDialog } from '@/components/SnippetDialog' +import { SnippetViewer } from '@/components/SnippetViewer' +import { EmptyState } from '@/components/EmptyState' import { toast } from 'sonner' function App() { - const [count, setCount] = useKV('counter-value', 0) - const [maxReached, setMaxReached] = useKV('max-reached', 0) + const [snippets, setSnippets] = useKV('snippets', []) + const [searchQuery, setSearchQuery] = useState('') + const [dialogOpen, setDialogOpen] = useState(false) + const [viewerOpen, setViewerOpen] = useState(false) + const [editingSnippet, setEditingSnippet] = useState(null) + const [viewingSnippet, setViewingSnippet] = useState(null) - const currentCount = count ?? 0 - const currentMax = maxReached ?? 0 - const limit = Math.floor(currentMax / 2) - const isLimited = currentMax > 0 - const isAtLimit = isLimited && currentCount >= limit + const currentSnippets = snippets ?? [] - const increment = () => { - const newCount = currentCount + 1 - - if (isLimited && newCount > limit) { - toast.error('Half the app is gone!', { - description: `You can only count to ${limit} now (half of ${currentMax})` - }) - return - } - - setCount(newCount) - - if (newCount > currentMax) { - setMaxReached(newCount) + const filteredSnippets = currentSnippets.filter((snippet) => { + const query = searchQuery.toLowerCase() + return ( + snippet.title.toLowerCase().includes(query) || + snippet.description.toLowerCase().includes(query) || + snippet.language.toLowerCase().includes(query) || + snippet.code.toLowerCase().includes(query) + ) + }) + + const handleSaveSnippet = (snippetData: Omit) => { + if (editingSnippet) { + setSnippets((current) => + (current ?? []).map((s) => + s.id === editingSnippet.id + ? { ...s, ...snippetData, updatedAt: Date.now() } + : s + ) + ) + toast.success('Snippet updated successfully') + } else { + const newSnippet: Snippet = { + ...snippetData, + id: crypto.randomUUID(), + createdAt: Date.now(), + updatedAt: Date.now(), + } + setSnippets((current) => [...(current ?? []), newSnippet]) + toast.success('Snippet created successfully') } + setEditingSnippet(null) } - const decrement = () => { - setCount((current) => (current ?? 0) - 1) + const handleEditSnippet = (snippet: Snippet) => { + setEditingSnippet(snippet) + setDialogOpen(true) } - const reset = () => { - setCount(0) - setMaxReached(0) - toast.success('Counter reset - full power restored!') + const handleDeleteSnippet = (id: string) => { + setSnippets((current) => (current ?? []).filter((s) => s.id !== id)) + toast.success('Snippet deleted') } - const formattedCount = currentCount.toLocaleString() + const handleCopySnippet = (code: string) => { + navigator.clipboard.writeText(code) + toast.success('Code copied to clipboard') + } + + const handleViewSnippet = (snippet: Snippet) => { + setViewingSnippet(snippet) + setViewerOpen(true) + } + + const handleCreateNew = () => { + setEditingSnippet(null) + setDialogOpen(true) + } return ( -
-
-
+
+
+
- -
-
-

Half Counter

-

- {isLimited ? `Once you reach a number, you can only count to half of it` : 'Count up... if you dare'} -

-
- - - -
- -
- {formattedCount} +
+
+
+
+
+
+ +
+
+

+ Code Snippets +

+

+ {currentSnippets.length} {currentSnippets.length === 1 ? 'snippet' : 'snippets'} saved +

+
- + +
- - {isLimited && ( - -
-
limit
-
{limit}
-
-
- )} -
-
- - {isLimited && ( - - -
- Half the app is gone! Your max was {currentMax}, now you can only reach {limit}. + {currentSnippets.length > 0 && ( +
+
+ + setSearchQuery(e.target.value)} + className="pl-10 h-11" + /> +
- + )} +
+
+ +
+ {currentSnippets.length === 0 ? ( + + ) : filteredSnippets.length === 0 ? ( +
+ +

No snippets found

+

+ Try adjusting your search query +

+
+ ) : ( +
+ {filteredSnippets.map((snippet) => ( + + ))} +
)} +
+
- + -
- - -
- - -
- +
) }