Skip to content

Commit

Permalink
fix local contract deploy, add screenshot feature, update copy
Browse files Browse the repository at this point in the history
  • Loading branch information
auroter committed Jan 23, 2025
1 parent fa96c2e commit ce3289c
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 18 deletions.
133 changes: 128 additions & 5 deletions apps/bonding-curves/app/components/curve-visualizer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useCallback, useEffect, useRef, useState } from 'react'
import { Button, Input, Label, Text } from '@0xintuition/1ui'

import { generateCurvePoints } from '~/lib/curveUtils'
import html2canvas from 'html2canvas'
import { X } from 'lucide-react'
import {
createPublicClient,
Expand Down Expand Up @@ -1063,6 +1064,130 @@ export function CurveVisualizer() {
[selectedCurveId],
)

const handleScreenshot = useCallback(async () => {
const contentArea = document.querySelector<HTMLDivElement>(
'.flex.flex-col.gap-4 > .flex.flex-col.gap-4.rounded-lg.border.border-border.p-4',
)
if (!contentArea) return

try {
const rect = contentArea.getBoundingClientRect()
const appBg = window.getComputedStyle(document.body).backgroundColor

// Render at 8x scale
const scale = 8
const canvas = await html2canvas(contentArea, {
backgroundColor: 'transparent',
scale: scale,
logging: false,
useCORS: true,
allowTaint: true,
foreignObjectRendering: true,
width: rect.width + scale, // scale of 1 is off by 1 px
height: rect.height + scale,
x: -rect.left,
y: -rect.top,
onclone: (clonedDoc) => {
const clonedContent = clonedDoc.querySelector<HTMLElement>(
'.flex.flex-col.gap-4 > .flex.flex-col.gap-4.rounded-lg.border.border-border.p-4',
)
if (clonedContent) {
// Set the background color on the content area
clonedContent.style.backgroundColor = appBg
clonedContent.style.position = 'relative'
clonedContent.style.width = `${rect.width}px`
clonedContent.style.height = `${rect.height}px`

// Fix Browse button styling
const fileInput = clonedContent.querySelector('input[type="file"]')
if (fileInput instanceof HTMLElement) {
fileInput.style.opacity = '1'
fileInput.style.cursor = 'pointer'
}

// Ensure all child elements maintain their positions
clonedContent.querySelectorAll('*').forEach((el) => {
if (el instanceof HTMLElement) {
const originalEl = document.querySelector(
`[data-testid="${el.dataset.testid}"]`,
)
if (originalEl) {
const originalRect = originalEl.getBoundingClientRect()
const relativeTop = originalRect.top - rect.top
const relativeLeft = originalRect.left - rect.left
el.style.position = 'absolute'
el.style.top = `${relativeTop}px`
el.style.left = `${relativeLeft}px`
}
}
})

// Make tooltips visible
clonedContent
.querySelectorAll('[role="tooltip"]')
.forEach((tooltip) => {
if (tooltip instanceof HTMLElement) {
tooltip.style.visibility = 'visible'
tooltip.style.opacity = '1'
tooltip.style.display = 'block'
}
})

// Ensure SVG elements are visible
clonedContent.querySelectorAll('svg').forEach((svg) => {
if (svg instanceof SVGElement) {
svg.style.visibility = 'visible'
svg.style.opacity = '1'
}
})
}
},
})

// Create a new canvas at 2x scale for the final output
const finalScale = 2
const outputCanvas = document.createElement('canvas')
outputCanvas.width = rect.width * finalScale
outputCanvas.height = rect.height * finalScale
const ctx = outputCanvas.getContext('2d')

if (ctx) {
// Enable image smoothing for better antialiasing
ctx.imageSmoothingEnabled = true
ctx.imageSmoothingQuality = 'high'

// Draw the high-res canvas onto the smaller output canvas
ctx.drawImage(
canvas,
0,
0,
canvas.width,
canvas.height,
0,
0,
outputCanvas.width,
outputCanvas.height,
)
}

// Use the downscaled canvas for the blob
outputCanvas.toBlob(async (blob) => {
if (!blob) return
try {
await navigator.clipboard.write([
new ClipboardItem({
'image/png': blob,
}),
])
} catch (err) {
console.error('Error copying to clipboard:', err)
}
}, 'image/png')
} catch (err) {
console.error('Error creating screenshot:', err)
}
}, [])

// Cleanup on unmount
useEffect(() => {
return () => {
Expand All @@ -1074,11 +1199,9 @@ export function CurveVisualizer() {

return (
<div className="flex flex-col gap-4">
<div>
<Text variant="heading2">Bonding Curve Visualizer</Text>
<Text variant="body" className="text-muted-foreground">
Upload and compare multiple bonding curve implementations
</Text>
<div className="flex justify-between items-center">
<div></div>
<Button onClick={handleScreenshot}>Copy to Clipboard</Button>
</div>

<div className="flex flex-col gap-4 rounded-lg border border-border p-4">
Expand Down
2 changes: 2 additions & 0 deletions apps/bonding-curves/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import { CurveVisualizer } from './components/curve-visualizer'

// This may be unused

export default function Page() {
return (
<div className="min-h-screen bg-background">
Expand Down
7 changes: 5 additions & 2 deletions apps/bonding-curves/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ export default function Index() {
<div className="container mx-auto py-10">
<div className="flex flex-col gap-6">
<div className="flex flex-col gap-2">
<h1 className="text-4xl font-bold">Bonding Curves</h1>
<h1 className="text-4xl font-bold">
Intuition Bonding Curve Visualizer
</h1>
<p className="text-muted-foreground">
Upload and visualize your custom bonding curve implementations
Upload and visualize any bonding curve contract compatible with
Intuition Protocol.
</p>
</div>
<CurveVisualizer />
Expand Down
25 changes: 14 additions & 11 deletions apps/bonding-curves/app/routes/api.compile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ export const action: ActionFunction = async ({ request }) => {

try {
// Create directories if they don't exist and set permissions
await fs.mkdir(outDir, { recursive: true, mode: 0o777 }) // Full permissions for testing
await fs.mkdir(contractsDir, { recursive: true, mode: 0o755 })

// Set permissions on the contract file
if (isProduction) {
await fs.mkdir(outDir, { recursive: true, mode: 0o777 }) // Full permissions for testing
await fs.mkdir(contractsDir, { recursive: true, mode: 0o755 })

// Set permissions on the contract file
await fs.writeFile(contractPath, content)
await fs.chmod(contractPath, 0o644)

Expand All @@ -76,14 +76,15 @@ export const action: ActionFunction = async ({ request }) => {
// Log current working directory
const { stdout: pwdOutput } = await execAsync('pwd')
console.log('Current working directory:', pwdOutput)

// Log contract file contents and location before compilation
console.log('Contract path:', contractPath)
console.log('Contract directory contents:', await fs.readdir(contractsDir))
} else {
await execAsync(`docker exec bonding-curves-anvil-1 bash -c "echo '${escapedContent}' > ${contractPath}"`)
// In development, only create directories in Docker
await execAsync(`docker exec bonding-curves-anvil-1 bash -c "mkdir -p /app/contracts /app/out && echo '${escapedContent}' > /app/contracts/${fileName}"`)
}

// Log contract file contents and location before compilation
console.log('Contract path:', contractPath)
console.log('Contract directory contents:', await fs.readdir(contractsDir))

let compileResult: { stdout: string; stderr: string }
if (isProduction) {
console.log('Running forge build...')
Expand Down Expand Up @@ -117,8 +118,10 @@ export const action: ActionFunction = async ({ request }) => {
}

// Log directory contents and permissions for debugging
const { stdout: lsOutput } = await execAsync(`ls -la ${outDir}`)
console.log('Output directory permissions:', lsOutput)
if (isProduction) {
const { stdout: lsOutput } = await execAsync(`ls -la ${outDir}`)
console.log('Output directory permissions:', lsOutput)
}

console.log('Compilation output:', compileResult.stdout)
if (compileResult.stderr) {
Expand Down
1 change: 1 addition & 0 deletions apps/bonding-curves/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"clsx": "^2.1.1",
"d3": "^7.8.5",
"framer-motion": "^11.2.10",
"html2canvas": "^1.4.1",
"isbot": "^4",
"lucide-react": "^0.441.0",
"react": "^18.2.0",
Expand Down
39 changes: 39 additions & 0 deletions pnpm-lock.yaml

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

0 comments on commit ce3289c

Please sign in to comment.