Created UI for showing and adding skins
This commit is contained in:
@ -66,6 +66,8 @@ public class Skin implements JSON {
|
||||
|
||||
public static Skin loadFromImage(InputStream is, String label) throws SkinException, IOException, NoSuchAlgorithmException {
|
||||
BufferedImage image = ImageIO.read(is);
|
||||
if (image == null)
|
||||
throw new SkinException("Failed to load the image");
|
||||
int width = image.getWidth();
|
||||
int height = image.getHeight();
|
||||
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
api = {
|
||||
getSkins: async function() {
|
||||
return fetch("api/skins").then(res=>res.json());
|
||||
return (await fetch("api/skins").then(res=>res.json())).map(skin=>{return {
|
||||
hash: skin.hash,
|
||||
label: skin.label,
|
||||
png: `${location.protocol}//${location.host}${skin.png}`,
|
||||
png_old: `${location.protocol}//${location.host}${skin.png_old}`,
|
||||
}});
|
||||
},
|
||||
addSkin: async function(skin, label) {
|
||||
let data = new FormData();
|
||||
data.append("skin", skin);
|
||||
data.append("label", label);
|
||||
await fetch("api/skin", {"method": "POST", body: data});
|
||||
},
|
||||
};
|
||||
@ -5,21 +5,98 @@
|
||||
<script src="api.js"></script>
|
||||
<script src="thirdparty/skinview3d.js.gz"></script>
|
||||
<script src="thirdparty/alpine.js.gz" defer></script>
|
||||
<script>
|
||||
const skinViewer = new skinview3d.SkinViewer({
|
||||
width: 200,
|
||||
height: 300,
|
||||
renderPaused: true,
|
||||
});
|
||||
skinViewer.camera.rotation.x = -0.62;
|
||||
skinViewer.camera.rotation.y = 0.534;
|
||||
skinViewer.camera.rotation.z = 0.348;
|
||||
skinViewer.camera.position.x = 17.0;
|
||||
skinViewer.camera.position.y = 19.0;
|
||||
skinViewer.camera.position.z = 23.0;
|
||||
async function renderSkin(url)
|
||||
{
|
||||
await skinViewer.loadSkin(url),
|
||||
skinViewer.render();
|
||||
const image = skinViewer.canvas.toDataURL();
|
||||
|
||||
return image;
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
dialog
|
||||
{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
background-color: var(--bg);
|
||||
transform: translate(50%, 50%);
|
||||
min-width: 50vw;
|
||||
aspect-ratio: 1.5/1;
|
||||
}
|
||||
.screenblock
|
||||
{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
min-width: 100vw;
|
||||
min-height: 100vh;
|
||||
}
|
||||
.flex-container
|
||||
{
|
||||
display: flex;
|
||||
}
|
||||
.flex
|
||||
{
|
||||
flex: 1;
|
||||
}
|
||||
#skin-cards
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.skin-card
|
||||
{
|
||||
min-width: 30%;
|
||||
max-width: 30%;
|
||||
margin: 0.5em;
|
||||
margin-left: 1.666%;
|
||||
margin-right: 1.666%;
|
||||
}
|
||||
</style>
|
||||
<title>Skinner</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Skinner</h1>
|
||||
<article>
|
||||
<form method="POST" action="api/skin" enctype="multipart/form-data">
|
||||
<input name="label" type="text" placeholder="Skin name">
|
||||
<input name="skin" type="file" required>
|
||||
<input type="submit" value="Add new skin">
|
||||
<body x-data="{add_dialog: false, blur: false, skins: api.getSkins()}">
|
||||
<main x-bind:style="blur ? 'filter: blur(10px);' : ''">
|
||||
<h1>Skinner</h1>
|
||||
<div class="flex-container">
|
||||
<input class="flex" type="search" placeholder="Search skins..." disabled title="Not implemented">
|
||||
<button @click="add_dialog = true; blur = true;">Add new</button>
|
||||
</div>
|
||||
<div id="skin-cards"">
|
||||
<template x-for="skin in skins">
|
||||
<article class="skin-card" x-data="{}">
|
||||
<img x-bind:src="await renderSkin(skin.png)">
|
||||
<big x-text="skin.label || 'Unnamed'"></big>
|
||||
</article>
|
||||
</template>
|
||||
</div>
|
||||
</main>
|
||||
<div class="screenblock" x-show="blur"><!-- Block to prevent mouse clicks --></div>
|
||||
<dialog x-bind:open="add_dialog">
|
||||
<form method="POST" action="api/skin" enctype="multipart/form-data" x-data="{files: null, label: '', processing: false}" @submit.prevent="processing = true; api.addSkin(files, label).then(async ()=>{skins = await api.getSkins(); blur = false; add_dialog = false; processing = false;})">
|
||||
<h1>Add Skin</h1><br>
|
||||
<input type="text" placeholder="Skin name" x-model="label">
|
||||
<input type="file" accept="image/png" @change="files = $el.files[0]" required><br><br><br>
|
||||
<input type="submit" value="Add new skin" x-bind:disabled="processing">
|
||||
<button @click="blur = false; add_dialog = false;" x-bind:disabled="processing">Cancel</button>
|
||||
</form>
|
||||
</article>
|
||||
<div x-data="{skins: api.getSkins()}">
|
||||
<template x-for="skin in skins">
|
||||
<p x-text="skin.label + ' <<>> ' + skin.hash"></p>
|
||||
</template>
|
||||
</div>
|
||||
</dialog>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user