Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 122 additions & 4 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"use client"
"use client"

const safeBase64Encode = (str: string) =>
btoa(unescape(encodeURIComponent(str)));
Expand All @@ -14,10 +14,30 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@
import { Badge } from "@/components/ui/badge"
import { CopyButton } from "@/components/ui/copy-button"
import { CommandPalette, type Command } from "@/components/ui/command-palette"

import {
Code2, Play, Download, Upload, Layout, Maximize2, Minimize2,
FileText, Palette, Zap, Sun, Moon, Search, Link as LinkIcon,
Undo2, Redo2, Timer, MoreHorizontal, X, LogIn, UserPlus,
Code2,
Play,
Download,
Layout,
FileText,
Palette,
Zap,
Sun,
Moon,
Link as LinkIcon,
Timer,
Camera,
LogIn,
UserPlus,
Undo2,
Redo2,
Upload,
Minimize2,
Maximize2,
MoreHorizontal,
X,
Search,
} from "lucide-react"
import { toast } from "sonner"
import * as prettier from 'prettier'
Expand Down Expand Up @@ -351,6 +371,7 @@ export default function CodeEditor() {
}
}, [handleDragMove])


useEffect(() => {
window.addEventListener("mousemove", handleMouseMove)
window.addEventListener("mouseup", handleDragEnd)
Expand Down Expand Up @@ -430,6 +451,92 @@ export default function CodeEditor() {
setCurrentTemplateId(template.id)
toast("Template loaded", { description: `${template.name} template loaded.` })
}
const exportImage = async () => {
const previewIframe = previewRef.current
if (!previewIframe) {
toast.error("No preview to capture")
return
}

const loadingToast = toast.loading("Capturing preview…")

try {
const { default: html2canvas } = await import("html2canvas")
Comment on lines +463 to +464

const width = previewIframe.clientWidth || 800
const height = previewIframe.clientHeight || 600
const currentCode = codeRef.current

const combinedHtml = `<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><style>
*{box-sizing:border-box}
html,body{margin:0!important;padding:0!important;width:${width}px!important;min-height:${height}px!important;}
${currentCode.css}
</style></head><body>${currentCode.html}<script>(function(){try{${currentCode.javascript}}catch(e){}})()</script></body></html>`
// Off-screen but NOT visibility:hidden — hidden iframes don't paint,
// so html2canvas captures a blank canvas
const tempIframe = document.createElement("iframe")
tempIframe.style.cssText = `position:fixed;left:-9999px;top:0;width:${width}px;height:${height}px;border:none;`
document.body.appendChild(tempIframe)
tempIframe.srcdoc = combinedHtml
Comment on lines +477 to +480

// Wait for iframe to load
await new Promise<void>((resolve) => {
tempIframe.addEventListener("load", () => resolve(), { once: true })
setTimeout(resolve, 4000)
Comment on lines +484 to +485
})

// Extra time for JS inside the iframe to paint
await new Promise((r) => setTimeout(r, 500))

const tempDoc = tempIframe.contentDocument
if (!tempDoc?.body) {
document.body.removeChild(tempIframe)
toast.dismiss(loadingToast)
toast.error("Export failed", { description: "Preview not accessible." })
return
}

const canvas = await html2canvas(tempDoc.documentElement, {
useCORS: true,
allowTaint: true,
backgroundColor: "#ffffff",
width,
height,
logging: false,
scale: 1,
})

document.body.removeChild(tempIframe)
toast.dismiss(loadingToast)
Comment on lines +509 to +510

// Wrap toBlob in a Promise — plain callback silently swallows failures
const blob = await new Promise<Blob | null>((resolve) => {
canvas.toBlob(resolve, "image/png")
})

if (!blob) {
toast.error("Export failed", { description: "Canvas was empty or tainted." })
return
}

const url = URL.createObjectURL(blob)
const a = document.createElement("a")
a.href = url
a.download = "webify-preview.png"
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
URL.revokeObjectURL(url)
toast.success("Image exported!", { description: "Saved as webify-preview.png" })

} catch (err) {
console.error("Export image error:", err)
toast.dismiss(loadingToast)
toast.error("Export failed", {
description: err instanceof Error ? err.message : "Unknown error",
})
}
Comment on lines +532 to +538
}

const downloadCode = async () => {
const zip = new JSZip()
Expand Down Expand Up @@ -611,6 +718,7 @@ if (layout === "preview") setLayout("split")
{ label: "Share link", icon: <LinkIcon className="w-5 h-5" />, action: copyShareLink },
{ label: "Open in tab", icon: <Maximize2 className="w-5 h-5" />, action: () => { if (previewRef.current?.src) window.open(previewRef.current.src, "_blank") } },
{ label: isFullscreen ? "Exit fullscreen" : "Fullscreen", icon: isFullscreen ? <Minimize2 className="w-5 h-5" /> : <Maximize2 className="w-5 h-5" />, action: () => { setIsFullscreen(v => !v); setMoreSheetOpen(false) } },
{ label: "Export Image", icon: <Camera className="w-5 h-5" />, action: exportImage },
{ label: "Command palette", icon: <Search className="w-5 h-5" />, action: () => { setMoreSheetOpen(false); setPaletteOpen(true) } },
{ label: theme === "light" ? "Dark mode" : "Light mode", icon: theme === "light" ? <Moon className="w-5 h-5" /> : <Sun className="w-5 h-5" />, action: () => { toggleTheme(); setMoreSheetOpen(false) } },
].map((item) => (
Expand Down Expand Up @@ -779,6 +887,16 @@ if (layout === "preview") setLayout("split")
{!autoRun && (
<Button size="sm" onClick={runCodeManually} className="shrink-0">Run</Button>
)}
<Button
variant="outline"
size="sm"
onClick={exportImage}
className="ml-auto shrink-0 hidden md:flex h-8 text-xs"
title="Export preview as PNG"
>
<Camera className="w-3.5 h-3.5 mr-1.5" />
Export Image
</Button>
</div>
<div className={`flex-1 bg-white dark:bg-gray-900 relative ${isResizing ? "pointer-events-none" : ""}`}>
<iframe
Expand Down
50 changes: 50 additions & 0 deletions fix_syntax.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
with open(r'c:\Users\lishi\webify\Webify\app\page.tsx', 'r', encoding='utf-8') as f:
lines = f.readlines()

# Find the problematic area - lines around 1123-1134 (0-indexed: 1122-1133)
# Looking for the pattern: "} catch {}" followed by "} catch {"
i = 0
fixes = 0
while i < len(lines):
# Find " } catch {}" followed by empty line and " } catch {"
stripped = lines[i].rstrip()
if stripped == ' } catch {}' and i + 2 < len(lines):
next_non_empty = i + 1
while next_non_empty < len(lines) and lines[next_non_empty].strip() == '':
next_non_empty += 1
if next_non_empty < len(lines) and '} catch {' in lines[next_non_empty]:
# Found duplicate - remove from i+1 to end of duplicate catch block
# Find the closing } of the duplicate catch
end = next_non_empty + 1
brace_count = 1 if '{' in lines[next_non_empty] and '}' not in lines[next_non_empty].split('{', 1)[1] else 0
if lines[next_non_empty].rstrip().endswith('{'):
# Multi-line catch block
while end < len(lines) and brace_count > 0:
if '{' in lines[end]:
brace_count += lines[end].count('{')
if '}' in lines[end]:
brace_count -= lines[end].count('}')
end += 1
else:
# Single line like "} catch {\n }\n"
end = next_non_empty + 1
while end < len(lines) and lines[end].strip() != '':
if lines[end].strip() == '}':
end += 1
break
end += 1

print(f"Removing duplicate catch at lines {i+2}-{end} (1-indexed)")
print(f" Content: {''.join(lines[i+1:end])}")
# Remove the blank line(s) and duplicate catch block
del lines[i+1:end]
fixes += 1
continue
i += 1

if fixes > 0:
with open(r'c:\Users\lishi\webify\Webify\app\page.tsx', 'w', encoding='utf-8') as f:
f.writelines(lines)
print(f'\nFixed {fixes} duplicate catch blocks')
else:
print('No fixes needed')
Comment on lines +1 to +50
24 changes: 24 additions & 0 deletions fix_syntax2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
with open(r'c:\Users\lishi\webify\Webify\app\page.tsx', 'r', encoding='utf-8') as f:
lines = f.readlines()

# Remove lines 1123-1125 (0-indexed: 1122-1124) - the duplicate "} catch { }"
# And lines 1132-1135 (0-indexed: 1131-1134) - the duplicate "} catch { // corrupted... }"

# Work backwards to avoid index shifting
# Second duplicate: lines 1133-1135 (1-indexed), 0-indexed 1132-1134
del lines[1132:1135]

# First duplicate: lines 1123-1125 (1-indexed), 0-indexed 1122-1124
del lines[1122:1125]

with open(r'c:\Users\lishi\webify\Webify\app\page.tsx', 'w', encoding='utf-8') as f:
f.writelines(lines)

print('Fixed')

# Verify
with open(r'c:\Users\lishi\webify\Webify\app\page.tsx', 'r', encoding='utf-8') as f:
lines = f.readlines()
print('Lines 1115-1135:')
for i in range(1114, 1135):
print(f'{i+1}: {lines[i]}', end='')
Comment on lines +1 to +24
Comment on lines +1 to +24
36 changes: 36 additions & 0 deletions fix_syntax3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
with open(r'c:\Users\lishi\webify\Webify\app\page.tsx', 'r', encoding='utf-8') as f:
lines = f.readlines()

# Find ALL remaining "} catch {" duplicates that follow a "} catch {}"
to_delete = []
i = 0
while i < len(lines):
if lines[i].strip() == '} catch {}':
# Check if next non-empty line starts another catch
j = i + 1
while j < len(lines) and lines[j].strip() == '':
j += 1
if j < len(lines) and lines[j].strip().startswith('} catch {'):
# Find end of this duplicate catch block
end = j + 1
if lines[j].strip() == '} catch {':
# Multi-line - find closing }
while end < len(lines):
if lines[end].strip() == '}':
end += 1
break
end += 1
# Mark lines i+1 to end for deletion (keep the first } catch {})
for k in range(i+1, end):
to_delete.append(k)
print(f"Found duplicate catch at lines {i+2}-{end} (1-indexed)")
i += 1

# Delete in reverse order
for idx in sorted(to_delete, reverse=True):
del lines[idx]

with open(r'c:\Users\lishi\webify\Webify\app\page.tsx', 'w', encoding='utf-8') as f:
f.writelines(lines)

print(f"Deleted {len(to_delete)} lines")
Comment thread
Lishhhh07 marked this conversation as resolved.
19 changes: 5 additions & 14 deletions next.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,15 @@ const nextConfig: NextConfig = {
async headers() {
return [
{
source: "/(.*)",
source: "/((?!_next).*)",
headers: [
{
key: "X-Frame-Options",
value: "SAMEORIGIN",
},
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
{ key: "X-Frame-Options", value: "SAMEORIGIN" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
],
},
];
},
};

export default nextConfig;
export default nextConfig;
Loading
Loading