diff --git a/package.json b/package.json index cc74716..f3c3c7e 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "pull:dev": "instant-cli pull --env .env.development" }, "dependencies": { - "@instantdb/admin": "branch-suspense-debug", - "@instantdb/react": "branch-suspense-debug", + "@instantdb/admin": "latest", + "@instantdb/react": "latest", "next": "16.1.6", "react": "19.2.4", "react-dom": "19.2.4" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 13e171f..c9a269f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,11 +13,11 @@ importers: .: dependencies: '@instantdb/admin': - specifier: branch-suspense-debug - version: 0.22.155-branch-suspense-debug.22922116303.1 + specifier: latest + version: 0.22.156 '@instantdb/react': - specifier: branch-suspense-debug - version: 0.22.155-branch-suspense-debug.22922116303.1(react@19.2.4) + specifier: latest + version: 0.22.156(react@19.2.4) next: specifier: 16.1.6 version: 16.1.6(@babel/core@7.29.0)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) @@ -658,33 +658,33 @@ packages: cpu: [x64] os: [win32] - '@instantdb/admin@0.22.155-branch-suspense-debug.22922116303.1': - resolution: {integrity: sha512-WAko3ySExG4Mnz9hUUeYbW7CuNLTV+308jIsoPMAiFNx0sliwrUuWnDQtQZkHTcehS2gvve3sKomlQ1+Oh7Gnw==} + '@instantdb/admin@0.22.156': + resolution: {integrity: sha512-hZtK2mZBZ9emY3ICIBmgVMeOssS+CIBLmcorPtWQTqELYYogIyX5TsAOKtCEThQXG0DrnQ/tjuBdGjAaeBXZmA==} '@instantdb/core@0.22.155': resolution: {integrity: sha512-YpP6t6nK7dSKr23So78pEXq28aNDygXe7StihtxzxJDVT8sDA+tRGLo77QGIUgdyG62VHP1iuIWG1xnaBPPdMQ==} - '@instantdb/core@0.22.155-branch-suspense-debug.22922116303.1': - resolution: {integrity: sha512-6z3aebqFYXrGzllZ6rvE+cU6+oVQcqG4n0uL6fN/MFbIda7A6WcXf1DgR+U6gS8i9cwfDRC9/DoZ4scauHBaAg==} + '@instantdb/core@0.22.156': + resolution: {integrity: sha512-mAUG5+fsfHo+0ih1UoEggcSLR3PNJeg9pf2YBhVVHLx8uvP/p9q5SCTGE10/L1blImJ2x9V2DHRLoqnbMAFYBw==} '@instantdb/platform@0.22.155': resolution: {integrity: sha512-0UsSE+cqvhXGeJD1NsP+sFlLD9ZOX4pvvZyf+FnP9e2p6L7mCRXPblu+SPn9dGX0Hq6sjlPH3kEcSM3ZnzNWuQ==} - '@instantdb/react-common@0.22.155-branch-suspense-debug.22922116303.1': - resolution: {integrity: sha512-WrO6vREKnolh7mC7LatKcBWJt2NWKXDJDC8iRrXtnp1GbNKvmtXbLYU1StTv1AAvbCruL2tH+iepxGtM37O3lQ==} + '@instantdb/react-common@0.22.156': + resolution: {integrity: sha512-8QAQ9FReJ0SPzjiVZJzv1a8KtbaZsHNgDCESQ6EanU0jLng3pxmOY7mV7SGh1m1e9a5Bu0yaSyOlYj4V0j4HzA==} peerDependencies: react: '>=16' - '@instantdb/react@0.22.155-branch-suspense-debug.22922116303.1': - resolution: {integrity: sha512-ug6wavKsf5i3uRSt4D/LdZRnXldS1cAYfv/LolmkTY6X6iaDmoGnYduwZJ771edXrbZH9+O0CdEY4lU0k2bPEw==} + '@instantdb/react@0.22.156': + resolution: {integrity: sha512-EgH86+KxlwCc1v4vjNZqVJUYJtOIAbceqZIQrAJRENlJIcnZqoj0fbdKluS8CDZkvVsrG6MJsx5T62Z2UvfD9w==} peerDependencies: react: '>=16' '@instantdb/version@0.22.155': resolution: {integrity: sha512-S4kF3Cj5NKWMnHdhDnhe5jSBIWtMi7AEQeaqgQW59gm1XXk80/R0M9OZ0p1L9RWbgV/o4U/LHdSYtoWdw+MZPQ==} - '@instantdb/version@0.22.155-branch-suspense-debug.22922116303.1': - resolution: {integrity: sha512-tr1b8dmRbYqEdzO0skAttwial83UUxEsRklh7W4f0avwFiF0kbhhDbPnyxPW7+eF3Mh7DBtXIpskC1UVA6XqiQ==} + '@instantdb/version@0.22.156': + resolution: {integrity: sha512-DIKte2HMBUbnTXWlTGIES+b0mzibMGhjOx//PAh2CFztJZXUzdiQvKQ6joxUz6dS+dRYfwaMrUEIZksRMHMxXw==} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -3062,10 +3062,10 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@instantdb/admin@0.22.155-branch-suspense-debug.22922116303.1': + '@instantdb/admin@0.22.156': dependencies: - '@instantdb/core': 0.22.155-branch-suspense-debug.22922116303.1 - '@instantdb/version': 0.22.155-branch-suspense-debug.22922116303.1 + '@instantdb/core': 0.22.156 + '@instantdb/version': 0.22.156 cookie: 1.1.1 eventsource: 4.1.0 uuid: 11.1.0 @@ -3076,9 +3076,9 @@ snapshots: mutative: 1.3.0 uuid: 11.1.0 - '@instantdb/core@0.22.155-branch-suspense-debug.22922116303.1': + '@instantdb/core@0.22.156': dependencies: - '@instantdb/version': 0.22.155-branch-suspense-debug.22922116303.1 + '@instantdb/version': 0.22.156 mutative: 1.3.0 uuid: 11.1.0 @@ -3089,23 +3089,23 @@ snapshots: '@instantdb/core': 0.22.155 '@instantdb/version': 0.22.155 - '@instantdb/react-common@0.22.155-branch-suspense-debug.22922116303.1(react@19.2.4)': + '@instantdb/react-common@0.22.156(react@19.2.4)': dependencies: - '@instantdb/core': 0.22.155-branch-suspense-debug.22922116303.1 - '@instantdb/version': 0.22.155-branch-suspense-debug.22922116303.1 + '@instantdb/core': 0.22.156 + '@instantdb/version': 0.22.156 react: 19.2.4 - '@instantdb/react@0.22.155-branch-suspense-debug.22922116303.1(react@19.2.4)': + '@instantdb/react@0.22.156(react@19.2.4)': dependencies: - '@instantdb/core': 0.22.155-branch-suspense-debug.22922116303.1 - '@instantdb/react-common': 0.22.155-branch-suspense-debug.22922116303.1(react@19.2.4) - '@instantdb/version': 0.22.155-branch-suspense-debug.22922116303.1 + '@instantdb/core': 0.22.156 + '@instantdb/react-common': 0.22.156(react@19.2.4) + '@instantdb/version': 0.22.156 eventsource: 4.1.0 react: 19.2.4 '@instantdb/version@0.22.155': {} - '@instantdb/version@0.22.155-branch-suspense-debug.22922116303.1': {} + '@instantdb/version@0.22.156': {} '@jridgewell/gen-mapping@0.3.13': dependencies: diff --git a/src/app/components.tsx b/src/app/components.tsx index 39d7ca9..5aef487 100644 --- a/src/app/components.tsx +++ b/src/app/components.tsx @@ -2,6 +2,7 @@ import { db } from '@/lib/db'; import { useCallback, useEffect, useRef, useState } from 'react'; +import { createPortal } from 'react-dom'; import Link from 'next/link'; import { useTheme } from './ThemeProvider'; import { useRouter } from 'next/navigation'; @@ -875,7 +876,13 @@ function CodeInput({ onComplete }: { onComplete: (code: string) => void }) { // -- Upgrade Modal -- -export function UpgradeModal({ onClose }: { onClose: () => void }) { +export function UpgradeModal({ + onClose, + reason, +}: { + onClose: () => void; + reason?: string; +}) { const [sentEmail, setSentEmail] = useState(''); const inputRef = useRef(null); @@ -908,7 +915,7 @@ export function UpgradeModal({ onClose }: { onClose: () => void }) { Save your account

- Link an email to keep your sketches. + {reason || 'Link an email to keep your sketches.'}

{!sentEmail ? (
= 1000 + ? `${(inkRemaining / 1000).toFixed(1)}k` + : Math.round(inkRemaining).toString(); + + return ( +
+ + + + + + {label} + +
+ ); +} + +export function InkBudgetPreview({ budget }: { budget: number }) { + const passes = budget / CANVAS_W; + const svgW = 80; + const svgH = 60; + const pad = 6; + const innerW = svgW - pad * 2; + const innerH = svgH - pad * 2; + // 15 passes (12k) fills the mini canvas + const spacing = innerH / 15; + + let d = ''; + let y = pad; + let goingRight = true; + let left = passes; + + for (let i = 0; i < Math.ceil(passes) && y <= svgH - pad; i++) { + const frac = Math.min(left, 1); + const len = innerW * frac; + + if (i === 0) d += `M ${pad} ${y}`; + + const endX = goingRight ? pad + len : pad + innerW - len; + d += ` L ${endX} ${y}`; + left -= frac; + + if (left > 0) { + const nextY = y + spacing; + d += ` L ${endX} ${nextY}`; + y = nextY; + } + goingRight = !goingRight; + } + + return ( + + + + + ); +} + // -- Drawing Helpers -- export let lastX = 0; @@ -2408,6 +2537,7 @@ export function UpvoteButton({ score: number; } | null>(null); const [showLogin, setShowLogin] = useState(false); + const [showUpgrade, setShowUpgrade] = useState(false); const [pending, setPending] = useState(false); const displayVoted = optimistic ? optimistic.voted : voted; @@ -2427,10 +2557,14 @@ export function UpvoteButton({ if (isOwnSketch) return; - if (!user || !user.email) { + if (!user) { setShowLogin(true); return; } + if (!user.email) { + setShowUpgrade(true); + return; + } if (pending) return; setPending(true); @@ -2543,7 +2677,19 @@ export function UpvoteButton({ if (compact) { return ( <> - {showLogin && setShowLogin(false)} />} + {showLogin && + createPortal( + setShowLogin(false)} />, + document.body, + )} + {showUpgrade && + createPortal( + setShowUpgrade(false)} + reason="Link an email to vote on sketches." + />, + document.body, + )} + {/* Mode toggle */}
- {[15, 30, 60].map((d, i) => ( + {(['time', 'ink'] as const).map((mode, i) => ( ))}
+ {/* Budget picker */} +
+ {budgetMode === 'time' + ? [15, 30, 60].map((d, i) => ( + + )) + : [3000, 6000, 12000].map((b, i) => ( + + ))} +
+ {budgetMode === 'ink' && } {remixLoading ? 'Loading remix...' : 'Draw to start!'} @@ -610,11 +681,15 @@ function DrawCanvas({ )} - + {budgetMode === 'ink' ? ( + + ) : ( + + )} @@ -659,8 +734,18 @@ function DrawCanvas({ )}
diff --git a/src/instant.schema.ts b/src/instant.schema.ts index 7c8f961..cec97cc 100644 --- a/src/instant.schema.ts +++ b/src/instant.schema.ts @@ -28,6 +28,7 @@ const _schema = i.schema({ trimEnd: i.number().optional(), flagged: i.boolean().optional(), score: i.number().indexed().optional(), + inkBudget: i.number().optional(), }), votes: i.entity({ createdAt: i.number().indexed(),