Implement instant photo website
This commit is contained in:
parent
e903ca7ff9
commit
571dff3598
2 changed files with 82 additions and 9 deletions
|
|
@ -169,7 +169,7 @@ impl Drawer {
|
||||||
.with_display(Display::Flex)
|
.with_display(Display::Flex)
|
||||||
.with_flex_direction(FlexDirection::Column)
|
.with_flex_direction(FlexDirection::Column)
|
||||||
.with_align_items(Some(AlignItems::Center))
|
.with_align_items(Some(AlignItems::Center))
|
||||||
.with_gap(length(16.0))
|
.with_gap(length(8.0))
|
||||||
.and_child(image)
|
.and_child(image)
|
||||||
.and_child(title)
|
.and_child(title)
|
||||||
.register(&mut tree)?;
|
.register(&mut tree)?;
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,88 @@
|
||||||
name="viewport"
|
name="viewport"
|
||||||
content="width=device-width, height=device-height, initial-scale=1, user-scalable=0"
|
content="width=device-width, height=device-height, initial-scale=1, user-scalable=0"
|
||||||
/>
|
/>
|
||||||
<title>TP: Photo</title>
|
<title>Instant Photo</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
background-color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1em;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
|
||||||
|
/* TODO Use px or vw instead of em */
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
|
||||||
|
border: 10px solid #f00;
|
||||||
|
border-radius: 100px;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active {
|
||||||
|
border-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
button .circle {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
border-radius: 60px;
|
||||||
|
margin: auto;
|
||||||
|
|
||||||
|
background-color: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:active .circle {
|
||||||
|
background-color: #a00;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<script type="module">
|
||||||
|
const video = document.getElementById("video");
|
||||||
|
const button = document.getElementById("button");
|
||||||
|
|
||||||
|
// Show camera feed full-screen
|
||||||
|
navigator.mediaDevices
|
||||||
|
.getUserMedia({ video: { facingMode: { ideal: "environment" } } })
|
||||||
|
.then((stream) => {
|
||||||
|
video.srcObject = stream;
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error("Error accessing the camera:", error);
|
||||||
|
});
|
||||||
|
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
canvas.width = video.videoWidth;
|
||||||
|
canvas.height = video.videoHeight;
|
||||||
|
canvas
|
||||||
|
.getContext("2d")
|
||||||
|
.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
canvas.toBlob((blob) => {
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("image", blob);
|
||||||
|
form.append("title", new Date().toLocaleString());
|
||||||
|
|
||||||
|
fetch("photo", { method: "POST", body: form }).catch((error) => {
|
||||||
|
console.error("Error uploading image:", error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<form method="post" enctype="multipart/form-data">
|
<video id="video" autoplay></video>
|
||||||
<ol>
|
<button id="button"><div class="circle"></div></button>
|
||||||
<li><input type="file" name="image" /></li>
|
|
||||||
<li><input type="text" name="title" /></li>
|
|
||||||
<li><button>Print!</button></li>
|
|
||||||
</ol>
|
|
||||||
</form>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue