Skip to content

Commit 5ee0ced

Browse files
committed
allow exported json to be edited
1 parent fcddad1 commit 5ee0ced

File tree

2 files changed

+51
-10
lines changed

2 files changed

+51
-10
lines changed

.cursor/rules/next-js.mdc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
---
22
description: Working on this project
3-
globs:
3+
globs: *
44
alwaysApply: false
55
---
6-
You are an expert senior software engineer specializing in modern web development, with deep expertise in TypeScript, React 19, Next.js 15 (App Router), Vercel AI SDK, Shadcn UI, Radix UI, and Tailwind CSS. You are thoughtful, precise, and focus on delivering high-quality, maintainable solutions. do NOT leave comments around the code. also pls don't try to fix my capitalization.
6+
You are an expert senior software engineer specializing in modern web development, with deep expertise in TypeScript, React 19, Next.js 15 (App Router), Vercel AI SDK, Shadcn UI, Radix UI, and Tailwind CSS. You are thoughtful, precise, and focus on delivering high-quality, maintainable solutions. do NOT leave comments. also pls don't try to fix my capitalization and if you must make comments, type in lowercase.
77

88
## Analysis Process
99

src/components/export-save.tsx

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/com
55
import { Button } from "@/components/ui/button"
66
import { Textarea } from "@/components/ui/textarea"
77
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
8-
import { Download, Copy, Check } from "lucide-react"
8+
import { Download, Copy, Check, AlertCircle } from "lucide-react"
99
import { toast } from "sonner"
1010
import { InfoTooltip } from "@/components/info-tooltip"
1111

@@ -19,6 +19,7 @@ export function ExportSave({ saveData, lzw_encode, originalFilename }: ExportSav
1919
const [encodedSave, setEncodedSave] = useState("")
2020
const [jsonSave, setJsonSave] = useState("")
2121
const [copied, setCopied] = useState(false)
22+
const [jsonError, setJsonError] = useState<string | null>(null)
2223

2324
useEffect(() => {
2425
try {
@@ -32,7 +33,22 @@ export function ExportSave({ saveData, lzw_encode, originalFilename }: ExportSav
3233
description: "Failed to encode save data.",
3334
})
3435
}
35-
}, [saveData, lzw_encode, toast])
36+
}, [saveData, lzw_encode])
37+
38+
const handleJsonChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
39+
const newJsonValue = e.target.value
40+
setJsonSave(newJsonValue)
41+
42+
try {
43+
const parsedJson = JSON.parse(newJsonValue)
44+
45+
const encoded = lzw_encode(JSON.stringify(parsedJson))
46+
setEncodedSave(encoded)
47+
setJsonError(null)
48+
} catch (error) {
49+
setJsonError((error as Error).message)
50+
}
51+
}
3652

3753
const generateRandomHash = () => {
3854
const chars = "0123456789abcdefghijklmnopqrstuvwxyz"
@@ -54,9 +70,16 @@ export function ExportSave({ saveData, lzw_encode, originalFilename }: ExportSav
5470
}
5571

5672
const handleDownload = (content: string, defaultFilename: string) => {
73+
if (content === jsonSave && jsonError) {
74+
toast("Invalid JSON", {
75+
description: "Please fix the JSON errors before downloading.",
76+
})
77+
return
78+
}
79+
5780
const randomHash = generateRandomHash()
5881

59-
// use original filename if available, otherwise use default
82+
6083
let baseFilename
6184
let extension
6285

@@ -70,11 +93,9 @@ export function ExportSave({ saveData, lzw_encode, originalFilename }: ExportSav
7093
baseFilename = filenameParts.join(".")
7194
}
7295

73-
// for JSON content, ensure extension is .json
7496
if (content === jsonSave) {
7597
extension = "json"
7698
} else {
77-
// for encoded content, ensure extension is .save
7899
extension = "save"
79100
}
80101

@@ -143,15 +164,35 @@ export function ExportSave({ saveData, lzw_encode, originalFilename }: ExportSav
143164

144165
<TabsContent value="json">
145166
<div className="space-y-4">
146-
<Textarea readOnly className="min-h-[300px] font-mono text-xs" value={jsonSave} />
167+
<div className="relative">
168+
<Textarea
169+
className={`min-h-[300px] font-mono text-xs ${jsonError ? 'border-red-500' : ''}`}
170+
value={jsonSave}
171+
onChange={handleJsonChange}
172+
/>
173+
{jsonError && (
174+
<div className="mt-2 text-red-500 text-sm flex items-center">
175+
<AlertCircle className="h-4 w-4 mr-1" />
176+
<span>Invalid JSON: {jsonError}</span>
177+
</div>
178+
)}
179+
</div>
147180

148181
<div className="flex flex-col sm:flex-row gap-2">
149-
<Button variant="outline" className="flex-1" onClick={() => handleCopy(jsonSave)}>
182+
<Button
183+
variant="outline"
184+
className="flex-1"
185+
onClick={() => handleCopy(jsonSave)}
186+
>
150187
<Copy className="mr-2 h-4 w-4" />
151188
Copy JSON
152189
</Button>
153190

154-
<Button className="flex-1" onClick={() => handleDownload(jsonSave, "case-clicker-save.json")}>
191+
<Button
192+
className="flex-1"
193+
onClick={() => handleDownload(jsonSave, "caseclicker.json")}
194+
disabled={!!jsonError}
195+
>
155196
<Download className="mr-2 h-4 w-4" />
156197
Download JSON
157198
</Button>

0 commit comments

Comments
 (0)