mirror of
https://codeberg.org/vlw/big-black-coffee-button.git
synced 2025-09-14 00:33:42 +02:00
initial commit
This commit is contained in:
commit
a2fcc6ba95
9 changed files with 192 additions and 0 deletions
1
assets/media/coffee.svg
Normal file
1
assets/media/coffee.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 120.2 129.7"><g style="display:block;overflow:hidden"><path d="M26.3 67.3s-2.8-1.2 2.8-1c2.3.2 4.5.1 7 .2a974.8 974.8 0 0 0 15.8.4 599.2 599.2 0 0 0 28.8 0c2.1 0 4.2 0 6.2-.2 2 0 4.3.7 6 .4a13 13 0 0 1 4.8-.1c1.6.2 2.5 1 2.8 2.4.2 1.4.2 2.8-.2 4.3a213.5 213.5 0 0 1-4.7 21.6 32.5 32.5 0 0 1-4.4 10.4c-.7 1.1-1.6 2.6-3 4.4a24.1 24.1 0 0 1-9.6 8c-1.4.5-2.9.9-4.5 1.1a79 79 0 0 1-9 .7 58.2 58.2 0 0 1-10.3-1 46.4 46.4 0 0 1-10.5-3.6 39.7 39.7 0 0 1-8.8-5.4 24.8 24.8 0 0 1-8.4-11.6 46.6 46.6 0 0 1-4.4-16.6 69.6 69.6 0 0 1-.6-12 4 4 0 0 1 3.4-3.3 4 4 0 0 1 4.2 2.4 4 4 0 0 1 .1 2.6c-1.3 4.9-8 3-7.8-1.3a4 4 0 0 1 3.1-3.7 4 4 0 0 1 4.4 2l.4 1.3.1.6v2a164.3 164.3 0 0 0 .2 8.5 81.1 81.1 0 0 0 2.2 11.6 41.2 41.2 0 0 0 5.5 10.2c1 1.5 2.5 2.8 4.2 4a30.1 30.1 0 0 0 8.8 4.2 33.3 33.3 0 0 0 9.6 1.8 63.2 63.2 0 0 0 9.8-.3c2.5-.3 4.5-.8 6.1-1.6a16 16 0 0 0 4.3-2.7 36.1 36.1 0 0 0 6.2-9 35 35 0 0 0 1.8-5.4A368.6 368.6 0 0 0 92.1 80c.5-2 1.3-3.9 2.4-5.7 1-1.8.7-2.6-1.2-2.5-1.8 0-4.2-.8-6.2-.8a978.3 978.3 0 0 1-12.8.2 564.8 564.8 0 0 0-22.4-.1 305.4 305.4 0 0 0-15.8.2h-7c-5.4 1.7-7.6-4.5-3.6-5h1.3z"/><path d="m98.5 72.7 2.5.2a38.3 38.3 0 0 1 15.8 4.8c.9.8 1.6 2 2.2 3.3.6 1.4 1 3.3 1.2 5.8a13 13 0 0 1-.5 5.6c-.5 1.2-1.3 2.3-2.4 3.4a16 16 0 0 1-3.3 2.6 37.2 37.2 0 0 1-7.5 3.2l-4.8 1.3c-1.8.5-3.1 1-3.9 1.6-1.6 1.1-2.1 1.4-3 1.5a4 4 0 0 1-4.2-2.2 4 4 0 0 1 1-4.7c3.7-3.2 9.7 2.9 4.9 6.3a4 4 0 0 1-4.8-.3 4 4 0 0 1-1.1-4.6c.2-.4.4-.8.7-1l.5-.6L93 98a66.8 66.8 0 0 1 9.3-3.4 24 24 0 0 0 5.7-2c1.8-.7 3-1.7 3.8-3 .9-1.3 1-2.8.6-4.5-.5-1.7-1.3-2.8-2.6-3.3s-2.8-.9-4.4-1.1a26 26 0 0 0-4.8-.4 33.4 33.4 0 0 1-3.7-.4 3.7 3.7 0 0 1-1.3-6 3.7 3.7 0 0 1 2.4-1.1h.4zm-77.7 34-2.3-.2a13.5 13.5 0 0 0-9 3c-1 .8-1 1.8-.1 2.6.9 1 2.6 2 5 3.1a180.7 180.7 0 0 0 14.4 5.6 57.8 57.8 0 0 0 12.3 2.3 331.1 331.1 0 0 0 50.3 1.4 143.8 143.8 0 0 0 9.6-1.2c1.6-.3 3.2-.7 4.8-1.4 1.6-.6 1.7-1.3.3-2-1.4-.9-3-1.3-5-1.5a83 83 0 0 0-5-.3c-2.7 0-3.2-.2-4-.6a3.8 3.8 0 0 1-1.9-4.3 3.8 3.8 0 0 1 3.7-3c4.8 0 5.5 8.3-.3 7.8a3.8 3.8 0 0 1-3.4-3.2 3.8 3.8 0 0 1 2-4.1c.4-.2.8-.4 1.3-.4h.6a132770.8 132770.8 0 0 0 8.3.6 20.5 20.5 0 0 1 9.8 2.8c1.8 1 3 2.5 3.7 4.5.7 2 .5 3.8-.7 5.2a8.8 8.8 0 0 1-3.7 3 39.7 39.7 0 0 1-9.8 2.3 96 96 0 0 1-20.2.8 1801.6 1801.6 0 0 0-20.4-.2 353.5 353.5 0 0 1-20.7-.6 138.9 138.9 0 0 1-27.5-5.3 35 35 0 0 1-6-2.6c-2.3-1.2-4-2.5-5.2-4a6.7 6.7 0 0 1-1.7-4.3c0-1.6.3-3 .8-4.4.5-1.3 1.3-2.6 2.5-3.8a18.4 18.4 0 0 1 10.2-5 35.4 35.4 0 0 1 9 0 3.8 3.8 0 0 1 1.2 6.2 3.8 3.8 0 0 1-2.4 1.2h-.5zm15.5-90.6 2.4.9c1.6.6 3 1.2 4.3 2a16 16 0 0 1 3.8 3.2 8.7 8.7 0 0 1 2.4 5 10 10 0 0 1-1.4 5.8 19.8 19.8 0 0 1-3.8 5.1 17.6 17.6 0 0 0-3.1 3.8c-.7 1.1-.5 2.4.6 3.7a62.6 62.6 0 0 0 2.9 3.3 4.2 4.2 0 0 1 .4 5 4.2 4.2 0 0 1-4.8 1.8c-.4 0-.8-.3-1.2-.6-6-4.2 3-10.8 6.1-5.5a4.2 4.2 0 0 1-.7 5 4.2 4.2 0 0 1-3.7 1.3c-.7-.2-1.3-.5-2-.9a39587 39587 0 0 0-4.9-5.8c-.8-1-1.4-2.5-1.7-4.3-.4-1.8-.4-3.5 0-5a8.6 8.6 0 0 1 2.7-4 151 151 0 0 1 3.6-3.2c1-.9 2-2 2.7-3.3.8-1.3.7-2.3-.5-3.2-1-1-2.5-1.6-4-2l-3-1a3.8 3.8 0 0 1-1-6.2 3.8 3.8 0 0 1 3.4-1l.5.1zM58.4 0l3 .5 5.2 1c1.4.4 3 1.2 4.7 2.3a8.5 8.5 0 0 1 3.5 4.6c.6 1.9 1 3.5 1 4.7a14 14 0 0 1-.7 4.9c-.6 2-1.5 3.6-2.7 5a71.6 71.6 0 0 1-3.5 3.5c-1.2 1-1.5 2.3-1.1 4a41 41 0 0 0 1.4 5c.5 1.8.8 3.4.7 5a12 12 0 0 1-1 4.7 35.5 35.5 0 0 1-2.6 5.1 4.3 4.3 0 0 1-5 1.5 4.3 4.3 0 0 1-2.9-4.4c.7-7.6 11.3-3 8.1 2.5a4.3 4.3 0 0 1-4.8 2 4.3 4.3 0 0 1-3.3-4c0-.5 0-1 .2-1.4l.2-.7L60 44a9 9 0 0 0 1.4-3.6c.1-1.3-.1-2.7-.8-4.4-.6-1.6-1-3.3-1.3-5.2-.2-2 0-3.7.8-5.5a13 13 0 0 1 3.3-4.6l3.6-3.6c1-1.1 1.5-2.7 1.5-4.8 0-2-.9-3.2-2.4-3.7a38 38 0 0 0-5.4-.9 40.2 40.2 0 0 1-4.4-.6 3.7 3.7 0 0 1-.7-6.1A3.7 3.7 0 0 1 58 0h.5zM88 17.6l2.2.5c1.3.4 3 1.2 4.8 2.2a8 8 0 0 1 3.6 4c.7 1.4.6 3.2-.3 5.2a14 14 0 0 1-4 5A96.6 96.6 0 0 1 89 38c-1.7 1-2.3 2.3-1.8 3.8.4 1.5 1 3 2 4.6.8 1.6 1.3 2.7 1.3 3.1a4.3 4.3 0 0 1-2.2 4.7 4.3 4.3 0 0 1-5.2-1c-5-5.5 5.5-10 7.3-4.1a4.3 4.3 0 0 1-1.7 4.9 4.3 4.3 0 0 1-5.2-.4 891 891 0 0 0-1.2-1.7l-.7-1.2a73 73 0 0 1-3.2-7.4c-.6-1.4-.6-3-.2-4.8a8.6 8.6 0 0 1 2.2-4.2c1-1 2.4-2.1 4.1-3.2 1.8-1 3.2-2.2 4.2-3.3 1-1.2.9-1.9-.5-2.2l-2.5-.7a3.8 3.8 0 0 1-1.4-6.2 3.8 3.8 0 0 1 3.3-1.2h.5z"/></g></svg>
|
After Width: | Height: | Size: 4.1 KiB |
BIN
assets/media/icon.png
Normal file
BIN
assets/media/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
assets/media/icon512_maskable.png
Normal file
BIN
assets/media/icon512_maskable.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
BIN
assets/media/icon512_rounded.png
Normal file
BIN
assets/media/icon512_rounded.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
BIN
assets/media/sfx.m4a
Normal file
BIN
assets/media/sfx.m4a
Normal file
Binary file not shown.
70
assets/script.mjs
Normal file
70
assets/script.mjs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import { default as API } from "https://cdn.jsdelivr.net/npm/reflect-client@2.0.1/build/Reflect.js";
|
||||||
|
|
||||||
|
const STORAGE_KEY = "key";
|
||||||
|
const STORAGE_URL = "url";
|
||||||
|
|
||||||
|
function error(message) {
|
||||||
|
// Create wrapper for error messages
|
||||||
|
if (!document.querySelector("div#error")) {
|
||||||
|
const wrapper = document.createElement("div");
|
||||||
|
wrapper.id = "error";
|
||||||
|
|
||||||
|
// Remove wrapper element button
|
||||||
|
const closeButton = document.createElement("button");
|
||||||
|
closeButton.innerText = "Close error messages";
|
||||||
|
closeButton.addEventListener("click", () => wrapper.remove());
|
||||||
|
|
||||||
|
wrapper.appendChild(closeButton);
|
||||||
|
document.body.insertAdjacentElement("afterbegin", wrapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
const element = document.createElement("pre");
|
||||||
|
element.innerText = message;
|
||||||
|
|
||||||
|
document.querySelector("div#error").insertAdjacentElement("afterbegin", element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set logged in state on load if credentials exist
|
||||||
|
if (localStorage.getItem(STORAGE_URL) && localStorage.getItem(STORAGE_KEY)) {
|
||||||
|
document.body.classList.add("loggedin");
|
||||||
|
|
||||||
|
// Set login form credentials with values from storage
|
||||||
|
document.querySelector(`[name="${STORAGE_URL}"]`).value = localStorage.getItem(STORAGE_URL);
|
||||||
|
document.querySelector(`[name="${STORAGE_KEY}"]`).value = localStorage.getItem(STORAGE_KEY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Login form
|
||||||
|
document.querySelector("form").addEventListener("submit", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
// Set credentials in localStroage
|
||||||
|
const form = new FormData(event.target);
|
||||||
|
localStorage.setItem(STORAGE_URL, form.get(STORAGE_URL));
|
||||||
|
localStorage.setItem(STORAGE_KEY, form.get(STORAGE_KEY));
|
||||||
|
|
||||||
|
document.body.classList.add("loggedin");
|
||||||
|
});
|
||||||
|
|
||||||
|
// The Big Black Coffee Button
|
||||||
|
document.querySelector("button#coffee").addEventListener("click", async () => {
|
||||||
|
try {
|
||||||
|
// Attempt to pour some coffee
|
||||||
|
const url = new URL(localStorage.getItem(STORAGE_URL));
|
||||||
|
const resp = await new API(url.origin, localStorage.getItem(STORAGE_KEY)).call(url.pathname).post();
|
||||||
|
|
||||||
|
// Bail out and show error error if we didn't get a 2xx response code
|
||||||
|
if (!resp.ok) {
|
||||||
|
return error(await resp.text());
|
||||||
|
}
|
||||||
|
} catch (message) {
|
||||||
|
// Bail out if something went wrong with the API client
|
||||||
|
return error(message.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Play a fun little effect on success
|
||||||
|
const sfx = document.querySelector("audio");
|
||||||
|
sfx.addEventListener("playing", () => document.body.classList.add("coffeup"), { once: true });
|
||||||
|
sfx.addEventListener("ended", () => document.body.classList.remove("coffeup"), { once: true });
|
||||||
|
|
||||||
|
return sfx.play();
|
||||||
|
});
|
54
assets/style.css
Normal file
54
assets/style.css
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
body {
|
||||||
|
font-family: monospace;
|
||||||
|
max-width: 1000px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
body:not(.loggedin) div:not(#login),
|
||||||
|
body.loggedin div#login {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
form fieldset {
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#error {
|
||||||
|
padding: 1em;
|
||||||
|
background-color: mistyrose;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
div#error pre {
|
||||||
|
padding: 1em;
|
||||||
|
background-color: salmon;
|
||||||
|
}
|
||||||
|
|
||||||
|
button#coffee {
|
||||||
|
display: block;
|
||||||
|
margin: auto;
|
||||||
|
width: 20em;
|
||||||
|
height: 20em;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: solid 1em black;
|
||||||
|
background-color: transparent;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 3em;
|
||||||
|
}
|
||||||
|
|
||||||
|
button#coffee * {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.coffeup button#coffee {
|
||||||
|
pointer-events: none;
|
||||||
|
border-color: burlywood;
|
||||||
|
animation: coffeup 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes coffeup {
|
||||||
|
0% { transform: rotate(0); }
|
||||||
|
25% { transform: rotate(-10deg); }
|
||||||
|
75% { transform: rotate(10deg); }
|
||||||
|
100% { transform: rotate(0); }
|
||||||
|
}
|
39
index.html
Normal file
39
index.html
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Big Black Coffee Button</title>
|
||||||
|
<link rel="stylesheet" href="assets/style.css">
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
<link rel="icon" href="assets/media/icon512_maskable.png">
|
||||||
|
</head>
|
||||||
|
<body class="">
|
||||||
|
<div id="login">
|
||||||
|
<h1>Big Black Coffee Button</h1>
|
||||||
|
<form>
|
||||||
|
<fieldset>
|
||||||
|
<legend>Credentials</legend>
|
||||||
|
|
||||||
|
<label for="endpoint">Endpoint URL</label>
|
||||||
|
<input id="endpoint" type="text" name="url" placeholder="https://api.vlw.se/coffee">
|
||||||
|
|
||||||
|
<label for="key">API Key</label>
|
||||||
|
<input id="key" type="password" name="key" placeholder="Pvdv6WqbDyVcJx38FjDpQtiq0teBQLGtBLDTkNG4XYHpvxWkCXcyW1uAWVLXxS947M">
|
||||||
|
|
||||||
|
<p>Credentials will be saved in <samp>localStorage</samp> until cleared</p>
|
||||||
|
|
||||||
|
<input type="submit" value="Save">
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button onclick="document.body.classList.remove('loggedin')">Show credentials</button>
|
||||||
|
<button id="coffee">
|
||||||
|
<img src="assets/media/coffee.svg">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<audio src="assets/media/sfx.m4a"></audio>
|
||||||
|
<script src="assets/script.mjs" type="module"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
28
manifest.json
Normal file
28
manifest.json
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"theme_color": "#deb887",
|
||||||
|
"background_color": "#ffffff",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"purpose": "maskable",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"src": "assets/media/icon512_maskable.png",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"purpose": "any",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"src": "assets/media/icon512_rounded.png",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"orientation": "portrait",
|
||||||
|
"display": "standalone",
|
||||||
|
"dir": "auto",
|
||||||
|
"lang": "en-US",
|
||||||
|
"name": "Big Black Coffee Button",
|
||||||
|
"short_name": "BBCB",
|
||||||
|
"start_url": "https://bbcb.srv.vlw.se",
|
||||||
|
"scope": "https://bbcb.srv.vlw.se",
|
||||||
|
"id": "https://bbcb.srv.vlw.se",
|
||||||
|
"description": "One big button for updating api.vlw.se/coffee"
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue