Merge pull request 'creates chatoverlay' (#30) from chatoverlay into main
All checks were successful
CI / deploy (push) Successful in 4m48s
All checks were successful
CI / deploy (push) Successful in 4m48s
Reviewed-on: #30
This commit is contained in:
commit
f3e8432452
2
pom.xml
2
pom.xml
@ -4,7 +4,7 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>de.arindy</groupId>
|
||||
<artifactId>dice-tower</artifactId>
|
||||
<version>1.0.8-SNAPSHOT</version>
|
||||
<version>1.1.0-SNAPSHOT</version>
|
||||
|
||||
<properties>
|
||||
<compiler-plugin.version>3.13.0</compiler-plugin.version>
|
||||
|
40
src/main/kotlin/de/arindy/dicetower/ChatOverlayResource.kt
Normal file
40
src/main/kotlin/de/arindy/dicetower/ChatOverlayResource.kt
Normal file
@ -0,0 +1,40 @@
|
||||
package de.arindy.dicetower
|
||||
|
||||
import io.quarkus.qute.TemplateInstance
|
||||
import jakarta.ws.rs.GET
|
||||
import jakarta.ws.rs.Path
|
||||
import jakarta.ws.rs.PathParam
|
||||
import jakarta.ws.rs.Produces
|
||||
import jakarta.ws.rs.QueryParam
|
||||
import jakarta.ws.rs.core.MediaType
|
||||
|
||||
@Path("chatoverlay")
|
||||
class ChatOverlayResource {
|
||||
|
||||
@GET
|
||||
@Path("/{channel}")
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
fun get(
|
||||
@PathParam("channel") channel: String,
|
||||
@QueryParam("scale") scale: Int? = 7,
|
||||
@QueryParam("maxDice") maxDice: Int? = 20,
|
||||
@QueryParam("modsAllowed") modsAllowed: Boolean = false,
|
||||
@QueryParam("vipAllowed") vipAllowed: Boolean = false,
|
||||
@QueryParam("subsAllowed") subsAllowed: Boolean = false,
|
||||
@QueryParam("cmd") cmd: String? = "roll",
|
||||
@QueryParam("theme") theme: String? = "default",
|
||||
@QueryParam("themeColor") themeColor: String? = "default",
|
||||
@QueryParam("clearAfter") clearAfter: Long? = -1,
|
||||
@QueryParam("timeout") timeout: Long? = -1
|
||||
): TemplateInstance {
|
||||
return Templates.chatoverlay(channel, scale ?: 7, maxDice ?: 20, modsAllowed, vipAllowed, subsAllowed, cmd ?: "roll", theme ?: "default", themeColor ?: "ff0202", clearAfter ?: 10, timeout ?: 60)
|
||||
}
|
||||
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_HTML)
|
||||
fun config(
|
||||
): TemplateInstance {
|
||||
return Templates.chatoverlayconfig()
|
||||
}
|
||||
|
||||
}
|
@ -7,8 +7,28 @@ import io.quarkus.qute.TemplateInstance
|
||||
object Templates {
|
||||
@JvmStatic
|
||||
external fun overlay(diceid: String, scale: Int?, clearAfter: Long?): TemplateInstance
|
||||
|
||||
@JvmStatic
|
||||
external fun results(room: String, name: String?, user: String?): TemplateInstance
|
||||
|
||||
@JvmStatic
|
||||
external fun index(version: String): TemplateInstance
|
||||
|
||||
@JvmStatic
|
||||
external fun chatoverlayconfig(): TemplateInstance
|
||||
|
||||
@JvmStatic
|
||||
external fun chatoverlay(
|
||||
channel: String,
|
||||
scale: Int?,
|
||||
maxDice: Int?,
|
||||
modsAllowed: Boolean,
|
||||
vipAllowed: Boolean,
|
||||
subsAllowed: Boolean,
|
||||
cmd: String?,
|
||||
theme: String?,
|
||||
themeColor: String?,
|
||||
clearAfter: Long?,
|
||||
timeout: Long?
|
||||
): TemplateInstance
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ function start(event = undefined) {
|
||||
document.getElementById('name').hidden = true;
|
||||
document.getElementById('room').hidden = true;
|
||||
document.getElementById('how-to').hidden = true;
|
||||
document.getElementById('chatOverlay').hidden = true;
|
||||
document.getElementById('results').hidden = false;
|
||||
document.getElementById('all-results').hidden = !document.getElementById('gm').checked;
|
||||
document.getElementById('all-results-urls').style.display = document.getElementById('gm').checked ? 'fles' : 'none';
|
||||
@ -178,6 +179,8 @@ document.addEventListener("DOMContentLoaded", async () => {
|
||||
}
|
||||
})
|
||||
|
||||
document.getElementById('chatOverlayLink').href = url() + '/chatoverlay'
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
if (!localStorage.getItem("userId")) {
|
||||
localStorage.setItem("userId", self.crypto.randomUUID());
|
||||
|
@ -24,3 +24,13 @@ body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: fixed;
|
||||
border-radius: 0.5rem;
|
||||
padding: 15px;
|
||||
max-width: 80%;
|
||||
font-size: 400%;
|
||||
color: #fff; !important;
|
||||
background-color: #333333dd; !important
|
||||
}
|
||||
|
1
src/main/resources/META-INF/resources/vendor/comfy.js/comfy.min.js
vendored
Normal file
1
src/main/resources/META-INF/resources/vendor/comfy.js/comfy.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
70
src/main/resources/templates/chatoverlay.html
Normal file
70
src/main/resources/templates/chatoverlay.html
Normal file
@ -0,0 +1,70 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Dice-Tower - Overlay</title>
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<link rel="stylesheet" href="/overlay/style.css">
|
||||
<script src="/vendor/comfy.js/comfy.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="dice-box"></div>
|
||||
<div popover id="results" class="tooltip">
|
||||
</div>
|
||||
<script type="module">
|
||||
import DiceBox from "/vendor/dice-box/dice-box.es.js";
|
||||
|
||||
const diceBox = new DiceBox("#dice-box", {
|
||||
assetPath: "/vendor/assets/",
|
||||
theme: '{theme}',
|
||||
themeColor: '{themeColor}',
|
||||
scale: {scale}
|
||||
});
|
||||
diceBox.init()
|
||||
ComfyJS.Init('{channel}');
|
||||
|
||||
//maxDice
|
||||
|
||||
ComfyJS.onCommand = async (user, command, message, flags) => {
|
||||
if ((
|
||||
flags.broadcaster || ({modsAllowed} && flags.mod) || ({vipAllowed} && flags.vip) || ({subsAllowed} && flags.subscriber
|
||||
)) && '{cmd}' === command && !shouldWait() && message.match(/^\d+d(4|6|8|10|12|20|100)$/) && (+message.split('d')[0] <= {maxDice})
|
||||
) {
|
||||
toggleWait(true);
|
||||
|
||||
diceBox.onRollComplete = (rollResult) => {
|
||||
rollResult.forEach(result => {
|
||||
let values = []
|
||||
result.rolls.forEach(roll => {
|
||||
values.push(roll.value);
|
||||
})
|
||||
document.getElementById('results').innerHTML = '<strong>' + message + '</strong>: [' + values.map(value => value === 1 ? '<strong style="text-shadow: 2px 2px 10px red">' + value + '</strong>' : value === result.sides ? '<strong style="text-shadow: 2px 2px 10px green">' + value + '</strong>' : value).join(' + ') + (result.modifier > 0 ? ' <a style="text-decoration: underline">+' + result.modifier + '</a>' : result.modifier < 0 ? ' <a style="text-decoration: underline">' + result.modifier + '</a>' : '') + '] = <strong>' + result.value + '</strong> '
|
||||
})
|
||||
document.getElementById('results').showPopover()
|
||||
setTimeout(() => {
|
||||
diceBox.clear();
|
||||
document.getElementById('results').hidePopover()
|
||||
}, {clearAfter} * 1000)
|
||||
}
|
||||
|
||||
diceBox.roll(message);
|
||||
setTimeout(() => {
|
||||
toggleWait(false);
|
||||
}, {clearAfter} * 1000 + {timeout} * 1000)
|
||||
} else {
|
||||
console.log('Not a valid command or not ready yet');
|
||||
}
|
||||
};
|
||||
|
||||
let wait;
|
||||
|
||||
function shouldWait() {
|
||||
return wait;
|
||||
}
|
||||
|
||||
function toggleWait(value) {
|
||||
wait = value;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
142
src/main/resources/templates/chatoverlayconfig.html
Normal file
142
src/main/resources/templates/chatoverlayconfig.html
Normal file
@ -0,0 +1,142 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Dice-Tower - Chatoverlay</title>
|
||||
<link rel="stylesheet" href="/vendor/w3css/4/w3.css">
|
||||
<link rel="stylesheet" href="/vendor/font-awesome/css/fontawesome.css">
|
||||
<link rel="stylesheet" href="/vendor/font-awesome/css/all.css">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<script src="/vendor/color-picker.js"></script>
|
||||
</head>
|
||||
<body class="w3-theme-l1">
|
||||
|
||||
<div class="w3-container w3-content"
|
||||
style="height: 95vh; display: flex; flex-direction: column; justify-content: space-between; padding: 25px">
|
||||
<h1 style="text-align: center"><i class="fa-solid fa-dice-d20"></i> Dice-Tower - Chatoverlay <i
|
||||
class="fa-solid fa-dice-d20"></i></h1>
|
||||
<div class="w3-panel w3-theme-l4 w3-card w3-display-container" style="padding: 25px; text-align: center;">
|
||||
<p>Allows Chat to roll a given amount of one dice</p>
|
||||
<p>Example: "!roll 5d20"</p>
|
||||
</div>
|
||||
<div class="w3-panel w3-theme-l4 w3-card w3-display-container"
|
||||
style="padding: 25px; text-align: center; margin-bottom: auto;">
|
||||
<label for="theme">Theme </label>
|
||||
<select name="theme" id="theme" style="margin: 25px">
|
||||
<option value="default">Default</option>
|
||||
<option value="blueGreenMetal">Blue-Green Metal</option>
|
||||
<option value="diceOfRolling">Dice of Rolling</option>
|
||||
<option value="gemstone">Gemstone</option>
|
||||
<option value="gemstoneMarble">Marble Gemstone</option>
|
||||
<option value="rock">Rock</option>
|
||||
<option value="rust">Rust</option>
|
||||
<option value="smooth">Smooth</option>
|
||||
<option value="wooden">Wooden</option>
|
||||
</select>
|
||||
<color-picker id="themeColor"></color-picker>
|
||||
<div>
|
||||
<label for="channel">Channel </label>
|
||||
<input type="text" id="channel" style="width: 400px; margin-top: 20px" value="arindy"/>
|
||||
<label for="cmd">Command </label>
|
||||
<input type="text" id="cmd" style="width: 100px; margin-top: 20px" value="roll"/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="checkbox" id="modsAllowed-container">Allow mods to roll
|
||||
<input type="checkbox" id="modsAllowed">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label class="checkbox" id="vipAllowed-container">Allow VIPs to roll
|
||||
<input type="checkbox" id="vipAllowed">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
<label class="checkbox" id="subsAllowed-container">Allow subs to roll
|
||||
<input type="checkbox" id="subsAllowed">
|
||||
<span class="checkmark"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="scale">Dice-Scale </label>
|
||||
<input type="number" id="scale" style="width: 50px; margin-top: 20px" value="7"/>
|
||||
<label for="maxDice">Max number of dice </label>
|
||||
<input type="number" id="maxDice" style="width: 50px; margin-top: 20px" value="20"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="clearAfter">Clear dice after (in seconds)</label>
|
||||
<input type="number" id="clearAfter" style="width: 50px; margin-top: 20px" value="10"/>
|
||||
<label for="timeout">Command-timeout (in seconds)</label>
|
||||
<input type="number" id="timeout" style="width: 50px; margin-top: 20px" value="10"/>
|
||||
</div>
|
||||
<div id="dice-box" style="height: 400px"></div>
|
||||
<button style="margin: 10px" id="preview">Preview <i class="fa-solid fa-magnifying-glass"></i></button>
|
||||
<button style="margin: 10px" id="generate">Generate overlay-link <i class="fa-solid fa-link"></i></button>
|
||||
<div>
|
||||
<input type="text" readonly id="link" style="width: 80%; margin-top: 20px"
|
||||
onclick="copyToClipboard(this.id)"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="snackbar-container">
|
||||
<div id="snackbar">.. they see them rolling</div>
|
||||
</div>
|
||||
<script>
|
||||
function copyToClipboard(id) {
|
||||
let copyText = document.getElementById(id)
|
||||
if (copyText.value.length > 0) {
|
||||
copyText.select();
|
||||
copyText.setSelectionRange(0, 99999);
|
||||
navigator.clipboard.writeText(copyText.value).then(() => {
|
||||
showSnackbar("<i class='fa-regular fa-copy'></i> Link copied to clipboard: <br/>" + copyText.value);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function showSnackbar(message) {
|
||||
let snackbar = document.getElementById("snackbar");
|
||||
let snackbarContainer = document.getElementById("snackbar-container");
|
||||
snackbar.innerHTML = message;
|
||||
snackbar.className = "show";
|
||||
snackbarContainer.className = "show";
|
||||
setTimeout(() => {
|
||||
snackbar.className = "";
|
||||
snackbarContainer.className = "";
|
||||
}, 3000)
|
||||
}
|
||||
</script>
|
||||
<script type="module">
|
||||
import DiceBox from "/vendor/dice-box/dice-box.es.js";
|
||||
|
||||
function url() {
|
||||
return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : '');
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
document.getElementById('preview').onclick = async () => {
|
||||
document.getElementById('dice-box').replaceChildren(...[])
|
||||
const diceBox = new DiceBox("#dice-box", {
|
||||
assetPath: "/vendor/assets/",
|
||||
theme: document.getElementById('theme').value,
|
||||
themeColor: document.getElementById('themeColor').value,
|
||||
scale: +document.getElementById('scale').value
|
||||
});
|
||||
await diceBox.init()
|
||||
diceBox.roll(['1d2', '1d4', '1d6', '1d8', '1d10', '1d12', '1d20', '1d100']);
|
||||
}
|
||||
document.getElementById('generate').onclick = async () => {
|
||||
document.getElementById('link').value = url() +
|
||||
"/chatoverlay/" + document.getElementById('channel').value +
|
||||
"?cmd=" + document.getElementById('cmd').value +
|
||||
"&theme=" + document.getElementById('theme').value +
|
||||
"&themeColor=" + encodeURIComponent(document.getElementById('themeColor').value) +
|
||||
"&scale=" + document.getElementById('scale').value +
|
||||
"&maxDice=" + document.getElementById('maxDice').value +
|
||||
"&clearAfter=" + document.getElementById('clearAfter').value +
|
||||
"&timeout=" + document.getElementById('timeout').value +
|
||||
"&modsAllowed=" + document.getElementById('modsAllowed').checked +
|
||||
"&vipAllowed=" + document.getElementById('vipAllowed').checked +
|
||||
"&subsAllowed=" + document.getElementById('subsAllowed').checked
|
||||
}
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -150,8 +150,8 @@
|
||||
<p>How is your character called?</p>
|
||||
</div>
|
||||
|
||||
<div style="margin-top: 20px; flex-grow: 1" id="how-to">
|
||||
<div class="w3-panel w3-theme-l4 w3-card w3-display-container" style="padding: 25px; margin-bottom: auto">
|
||||
<div style="margin-top: 20px" id="how-to">
|
||||
<div class="w3-panel w3-theme-l4 w3-card w3-display-container" style="padding: 25px;">
|
||||
<h2 style="text-align: center">How-To</h2>
|
||||
<ul>
|
||||
<li>
|
||||
@ -174,6 +174,11 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 20px; flex-grow: 1" id="chatOverlay">
|
||||
<div class="w3-panel w3-theme-l4 w3-card w3-display-container" style="padding: 25px; margin-bottom: auto">
|
||||
If you are looking for a way to let your twitch chat roll click <a href target="_blank" id="chatOverlayLink">here</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="snackbar-container">
|
||||
<div id="snackbar">.. they see them rolling</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user