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
107 changes: 103 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 @@ -24,6 +24,7 @@ import {
Moon,
Link as LinkIcon,
Timer,
Camera,
} from "lucide-react"
import { toast } from "sonner"

Expand Down Expand Up @@ -1102,6 +1103,7 @@ export default function CodeEditor() {
const [activeTab, setActiveTab] = useState<keyof CodeContent>("html")
const [theme, setTheme] = useState<"light" | "dark">("light")
const previewRef = useRef<HTMLIFrameElement>(null)
const codeRef = useRef<CodeContent>(code)

useEffect(() => {
const savedTheme = localStorage.getItem("theme") as "light" | "dark" | null
Expand All @@ -1116,6 +1118,7 @@ export default function CodeEditor() {
}, [])

useEffect(() => {
codeRef.current = code
const timer = setTimeout(() => {
try {
localStorage.setItem("webify_code", JSON.stringify(code))
Expand Down Expand Up @@ -1149,6 +1152,92 @@ export default function CodeEditor() {
setCode(template.content)
toast.success(`${template.name} 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 +1164 to +1165

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 +1178 to +1181

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

// 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 +1210 to +1211

// 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 +1233 to +1239
}

const downloadCode = async () => {
const zip = new JSZip()
Expand Down Expand Up @@ -1239,9 +1328,19 @@ export default function CodeEditor() {
<PreviewErrorBoundary>
<div className="flex flex-col border-t lg:border-t-0 lg:border-l border-gray-200 dark:border-gray-700">
<div className="bg-white dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700 px-3 py-2 flex items-center gap-2">
<Play className="w-4 h-4 text-green-600" />
<span className="text-sm font-medium text-gray-900 dark:text-white">Live Preview</span>
</div>
<Play className="w-4 h-4 text-green-600" />
<span className="text-sm font-medium text-gray-900 dark:text-white">Live Preview</span>
<Button
variant="outline"
size="sm"
onClick={exportImage}
className="ml-auto h-7 text-xs"
title="Export preview as PNG"
>
<Camera className="w-3.5 h-3.5 mr-1.5" />
Export Image
</Button>
</div>
<iframe ref={previewRef} className="flex-1 w-full border-0 bg-white" title="Live Preview" sandbox="allow-scripts allow-forms allow-popups allow-modals" />
</div>
</PreviewErrorBoundary>
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 on lines +1 to +36
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;
50 changes: 50 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@radix-ui/react-tabs": "^1.1.12",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"html2canvas": "^1.4.1",
"jszip": "^3.10.1",
"lucide-react": "^0.516.0",
"monaco-editor": "^0.52.2",
Expand Down