Last active
March 5, 2023 11:30
-
-
Save mike-at-redspace/7cb1a23b7c3ed64319e48c641dda7035 to your computer and use it in GitHub Desktop.
VotingApp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
async function getWebGLContext(canvas) { | |
try { | |
return canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); | |
} catch (e) { | |
return null; | |
} | |
} | |
async function getCanvasFingerprint() { | |
const canvas = document.createElement('canvas'); | |
canvas.width = 200; | |
canvas.height = 200; | |
let hash = ''; | |
const signals = { | |
pixelRatio: window.devicePixelRatio || 1, | |
userAgent: window.navigator.userAgent, | |
// Add more signals here | |
}; | |
const gl = await getWebGLContext(canvas); | |
if (gl) { | |
const regl = Regl(canvas); | |
const drawCircle = regl({ | |
frag: ` | |
precision mediump float; | |
varying vec4 color; | |
void main() { | |
gl_FragColor = color; | |
} | |
`, | |
vert: ` | |
precision mediump float; | |
attribute vec2 position; | |
attribute vec4 color; | |
varying vec4 vColor; | |
void main() { | |
gl_Position = vec4(position, 0.0, 1.0); | |
vColor = color; | |
} | |
`, | |
attributes: { | |
position: [ | |
[-1, -1], | |
[1, -1], | |
[1, 1], | |
[-1, 1], | |
], | |
color: [ | |
[1, 0, 0, 1], | |
[0, 1, 0, 1], | |
[0, 0, 1, 1], | |
[1, 1, 1, 1], | |
], | |
}, | |
elements: [ | |
[0, 1, 2], | |
[0, 2, 3], | |
], | |
}); | |
drawCircle(); | |
const drawGradient = regl({ | |
frag: ` | |
precision mediump float; | |
varying vec2 uv; | |
void main() { | |
gl_FragColor = vec4(uv, 0.0, 1.0); | |
} | |
`, | |
vert: ` | |
precision mediump float; | |
attribute vec2 position; | |
varying vec2 uv; | |
void main() { | |
gl_Position = vec4(position, 0.0, 1.0); | |
uv = position * 0.5 + 0.5; | |
} | |
`, | |
attributes: { | |
position: [ | |
[-1, -1], | |
[1, -1], | |
[1, 1], | |
[-1, 1], | |
], | |
}, | |
elements: [ | |
[0, 1, 2], | |
[0, 2, 3], | |
], | |
}); | |
drawGradient(); | |
const dataURL = canvas.toDataURL(); | |
hash = sha256(dataURL).toString(); | |
} else { | |
const ctx = canvas.getContext('2d'); | |
ctx.fillStyle = 'white'; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
ctx.fillStyle = 'black'; | |
ctx.font = '20px sans-serif'; | |
ctx.fillText('Hello, world!', 50, 50); | |
const gradient = ctx.createLinearGradient(0, 0, canvas.width, canvas.height); | |
gradient.addColorStop(0, 'red'); | |
gradient.addColorStop(1, 'blue'); | |
ctx.fillStyle = gradient; | |
const dataURL = canvas.toDataURL(); | |
hash = sha256(dataURL).toString(); | |
} | |
return hash; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function ResultsChart({ votes }) { | |
// Use a charting library or create your own chart component | |
return ( | |
<div> | |
<h2>Results:</h2> | |
<p>Option 1: {votes.option1}</p> | |
<p>Option 2: {votes.option2}</p> | |
<p>Option 3: {votes.option3}</p> | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { useState } from 'react'; | |
import getCanvasFingerprint from './getCanvasFingerprint'; | |
function useVote() { | |
const [isLoading, setIsLoading] = useState(false); | |
const [error, setError] = useState(null); | |
async function sendVote(vote) { | |
setIsLoading(true); | |
setError(null); | |
const fingerprint = getCanvasFingerprint(); | |
try { | |
const response = await fetch('/votes', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ vote, fingerprint }), | |
}); | |
if (!response.ok) { | |
throw new Error('Failed to send vote'); | |
} | |
setIsLoading(false); | |
} catch (err) { | |
setError(err.message); | |
setIsLoading(false); | |
} | |
} | |
return { | |
isLoading, | |
error, | |
sendVote, | |
}; | |
} | |
export default useVote; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function VotingApp() { | |
const [hasVoted, setHasVoted] = useState(false); | |
const [votes, setVotes] = useState({ | |
option1: 0, | |
option2: 0, | |
option3: 0, | |
}); | |
const { isLoading, error, sendVote } = useVote(); | |
async function handleVote(option) { | |
setVotes((prevVotes) => ({ | |
...prevVotes, | |
[option]: prevVotes[option] + 1, | |
})); | |
try { | |
await sendVote(option); | |
setHasVoted(true); | |
} catch (err) { | |
console.error(err); | |
} | |
} | |
return ( | |
<div> | |
{isLoading && <p>Loading...</p>} | |
{error && <p>Error: {error}</p>} | |
{hasVoted ? ( | |
<ResultsChart votes={votes} /> | |
) : ( | |
<VotingOptions onVote={handleVote} /> | |
)} | |
</div> | |
); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function VotingOptions({ onVote }) { | |
return ( | |
<div> | |
<h2>Vote for your favorite option:</h2> | |
<button onClick={() => onVote('option1')}>Option 1</button> | |
<button onClick={() => onVote('option2')}>Option 2</button> | |
<button onClick={() => onVote('option3')}>Option 3</button> | |
</div> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment