27 Commits

Author SHA1 Message Date
gitea
c8cd05f035 [no ci] prepare new Version 2025-02-11 21:56:44 +00:00
gitea
3e35dfb9ba [no ci] release 1.0.1 2025-02-11 21:56:38 +00:00
f465e1c101 fix SNAPSHOTS
All checks were successful
CI / deploy (push) Successful in 5m5s
2025-02-11 22:51:33 +01:00
gitea
2f4cc2de8b [no ci] release 1.0.1 2025-02-11 21:40:20 +00:00
b977996689 uses mvn:versions instead of jgitver
All checks were successful
CI / deploy (push) Successful in 4m46s
2025-02-11 22:35:30 +01:00
1544776ecc fix tag
Some checks failed
CI / deploy (push) Failing after 4m59s
2025-02-11 22:00:44 +01:00
468d9660c4 Merge pull request 'jgitver' (#23) from jgitver into main
Some checks failed
CI / deploy (push) Failing after 4m48s
Reviewed-on: #23
2025-02-11 21:42:15 +01:00
a43f5b30f7 remove SNAPSHOT
All checks were successful
CI / deploy (push) Successful in 4m53s
CI / deploy (pull_request) Successful in 4m50s
2025-02-11 21:31:28 +01:00
4ebd9a7262 fetch tags
All checks were successful
CI / deploy (push) Successful in 6m58s
2025-02-11 20:42:22 +01:00
ad4179a517 Merge pull request 'adds jgitver' (#22) from jgitver into main
All checks were successful
CI / deploy (push) Successful in 4m35s
Reviewed-on: #22
2025-02-11 20:36:32 +01:00
Arindy
f7705e15e5 adds jgitver
All checks were successful
CI / deploy (push) Successful in 4m30s
CI / deploy (pull_request) Successful in 4m27s
2025-02-11 20:24:09 +01:00
0299f89901 Merge pull request 'copies links to clipboard' (#20) from copy-to-clipboard into main
All checks were successful
CI / deploy (push) Successful in 4m28s
Reviewed-on: #20
2025-02-11 11:24:44 +01:00
Arindy
7f7a27a178 copies links to clipboard
All checks were successful
CI / deploy (push) Successful in 4m22s
CI / deploy (pull_request) Successful in 4m18s
2025-02-11 11:15:37 +01:00
d9caee420a Merge pull request 'overwrites dice-overlay sse, so that only the last instance rolls the dice' (#19) from remove-sse-on-close into main
All checks were successful
CI / deploy (push) Successful in 4m21s
Reviewed-on: #19
2025-02-10 21:39:03 +01:00
Arindy
f9893e2a17 overwrites dice-overlay sse, so that only the last instance rolls the dice
All checks were successful
CI / deploy (push) Successful in 4m18s
CI / deploy (pull_request) Successful in 4m20s
2025-02-10 21:30:11 +01:00
fdd06978d8 Merge pull request 'show-all-overlays' (#18) from show-all-overlays into main
All checks were successful
CI / deploy (push) Successful in 4m24s
Reviewed-on: #18
2025-02-10 20:21:20 +01:00
Arindy
13f206ae97 splits gm-view from normal-view
All checks were successful
CI / deploy (push) Successful in 4m16s
CI / deploy (pull_request) Successful in 4m20s
2025-02-10 20:08:29 +01:00
Arindy
827b74ebf1 moves overlay notice 2025-02-10 18:41:13 +01:00
80d331cdd3 Merge pull request 'adds buttons for simple commands' (#16) from adds-easy-way-to-roll into main
All checks were successful
CI / deploy (push) Successful in 4m18s
Reviewed-on: #16
2025-02-10 18:39:00 +01:00
Arindy
0e3d88cd4a fixes overlay tooltip
All checks were successful
CI / deploy (push) Successful in 4m14s
CI / deploy (pull_request) Successful in 4m17s
2025-02-10 18:26:44 +01:00
Arindy
cb077b50de adds how-to
All checks were successful
CI / deploy (push) Successful in 4m21s
CI / deploy (pull_request) Successful in 4m19s
2025-02-10 18:19:54 +01:00
Arindy
9def3240b2 styles buttons
All checks were successful
CI / deploy (push) Successful in 4m29s
CI / deploy (pull_request) Successful in 4m22s
2025-02-10 18:01:57 +01:00
Arindy
13eacc886d adds buttons for simple commands
All checks were successful
CI / deploy (push) Successful in 4m18s
CI / deploy (pull_request) Successful in 4m17s
2025-02-10 17:46:10 +01:00
af41ff5d78 Merge pull request 'adds a dice preview' (#15) from fix-color-picker into main
All checks were successful
CI / deploy (push) Successful in 4m24s
Reviewed-on: #15
2025-02-10 17:20:26 +01:00
Arindy
153b25e53f rounds elements
All checks were successful
CI / deploy (push) Successful in 4m23s
CI / deploy (pull_request) Successful in 4m13s
2025-02-10 17:04:57 +01:00
Arindy
2e6267e7b4 adds button icons
Some checks failed
CI / deploy (push) Has been cancelled
CI / deploy (pull_request) Successful in 6m22s
2025-02-10 16:58:26 +01:00
7ee16d5f3e Merge pull request 'enter in color picker now sets the color' (#14) from fix-color-picker into main
All checks were successful
CI / deploy (push) Successful in 4m22s
Reviewed-on: #14
2025-02-10 16:05:24 +01:00
6 changed files with 460 additions and 70 deletions

View File

@@ -11,6 +11,8 @@ jobs:
steps:
- name: Check out repository code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup JDK
uses: actions/setup-java@v4
@@ -18,8 +20,14 @@ jobs:
distribution: 'zulu'
java-version: '21'
- name: new Version
if: github.ref_name == 'main'
run: |
./mvnw -B --no-transfer-progress versions:set -DremoveSnapshot
- name: Build Runner
run: ./mvnw --no-transfer-progress clean verify -Pnative -Dquarkus.native.remote-container-build=true
run: |
./mvnw -B --no-transfer-progress clean verify -Pnative -Dquarkus.native.remote-container-build=true -Djgitver.skip=true
- name: Add coverage to PR
id: jacoco
@@ -31,6 +39,10 @@ jobs:
min-coverage-changed-files: 60
title: ${{ env.REPO }} Coverage
- id: version
name: Version
run: echo "VERSION=$(./mvnw help:evaluate -Dexpression=project.version -q -DforceStdout)" >> ${GITHUB_OUTPUT}
- name: Build Container
if: github.ref_name == 'main'
run: docker build -f src/main/docker/Dockerfile.native-micro -t ${{ env.REPO }} .
@@ -38,3 +50,17 @@ jobs:
- name: Deploy
if: github.ref_name == 'main'
run: "docker compose up -d"
- name: create tag
if: github.ref_name == 'main'
run: |
git config user.email "ci@git.arindy.de"
git config user.name "gitea"
git add ./pom.xml
git commit -m "[no ci] release ${{ steps.version.outputs.VERSION }}"
./mvnw -B --no-transfer-progress clean validate -Pnew-snapshot
git add ./pom.xml
git commit -m "[no ci] prepare new Version"
git tag ${{ steps.version.outputs.VERSION }} -m "release ${{ steps.version.outputs.VERSION }}"
git push origin main
git push origin ${{ steps.version.outputs.VERSION }}

46
pom.xml
View File

@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>de.arindy</groupId>
<artifactId>dice-tower</artifactId>
<version>1.0.0-SNAPSHOT</version>
<version>1.0.2-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.13.0</compiler-plugin.version>
@@ -21,6 +21,13 @@
<rxjava-version>2.2.8</rxjava-version>
</properties>
<scm>
<connection>scm:git:https://git.arindy.de/arindy/dice-tower.git</connection>
<developerConnection>scm:git:https://git.arindy.de/arindy/dice-tower.git</developerConnection>
<url>https://git.arindy.de/arindy/dice-tower</url>
<tag>HEAD</tag>
</scm>
<dependencyManagement>
<dependencies>
<dependency>
@@ -267,5 +274,42 @@
<quarkus.native.enabled>true</quarkus.native.enabled>
</properties>
</profile>
<profile>
<id>new-snapshot</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>next-version</id>
<goals>
<goal>parse-version</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.18.0</version>
<executions>
<execution>
<id>release-version</id>
<phase>validate</phase>
<goals>
<goal>set</goal>
</goals>
<configuration>
<newVersion>${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.nextIncrementalVersion}-SNAPSHOT</newVersion>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@@ -26,9 +26,6 @@ final class DiceResource(@Context val sse: Sse) {
@POST
@Consumes(MediaType.APPLICATION_JSON)
fun parseCommand(@PathParam("id") id: String, data: RollPayload) {
if (!sseBroadcasters.containsKey(id)) {
sseBroadcasters[id] = sse.newBroadcaster()
}
data.roll = data.command.split(" ", "&", "and").filter { it.isNotEmpty() }.map { it.trim() }.toTypedArray<String>()
data.room = id.split(":")[0]
data.user = id.split(":")[1]
@@ -41,6 +38,17 @@ final class DiceResource(@Context val sse: Sse) {
}
}
@POST
@Path("/register")
@Consumes(MediaType.APPLICATION_JSON)
fun register(@PathParam("id") id: String, data: Any) {
println("id = [${id}], data = [${data}]")
sseBroadcasters["register:$id"]?.broadcast(
eventBuilder.id((UUID.randomUUID()).toString())
.mediaType(MediaType.APPLICATION_JSON_TYPE).data(data).build())
}
@POST
@Path("/results")
@Consumes(MediaType.APPLICATION_JSON)
@@ -55,9 +63,7 @@ final class DiceResource(@Context val sse: Sse) {
@Path("/stream")
@Produces(MediaType.SERVER_SENT_EVENTS)
fun stream(@PathParam("id") id: String, @Context sseEventSink: SseEventSink) {
if (!sseBroadcasters.containsKey(id)) {
sseBroadcasters[id] = sse.newBroadcaster()
}
sseBroadcasters[id] = sse.newBroadcaster()
sseBroadcasters[id]?.register(sseEventSink)
}
@@ -71,7 +77,17 @@ final class DiceResource(@Context val sse: Sse) {
sseBroadcasters[id]?.register(sseEventSink)
}
@GET
@Path("/users")
@Produces(MediaType.SERVER_SENT_EVENTS)
fun users(@PathParam("id") id: String, @Context sseEventSink: SseEventSink) {
if (!sseBroadcasters.containsKey("register:$id")) {
sseBroadcasters["register:$id"] = sse.newBroadcaster()
}
sseBroadcasters["register:$id"]?.register(sseEventSink)
}
@RegisterForReflection
data class Result(val name: String, val user: String, val themeColor: String) {}
data class Result(val name: String, val user: String, val themeColor: String)
}

View File

@@ -61,7 +61,9 @@
document.addEventListener("DOMContentLoaded", async() => {
await diceBox.init()
let timeout = 0;
evtSource.addEventListener("message", function (event) {
clearInterval(timeout);
let data = JSON.parse(event.data);
diceBox.onRollComplete = (rollResult) => {
let httpRequest = new XMLHttpRequest();
@@ -74,7 +76,7 @@
results: rollResult,
} ))
if ({clearAfter} > 0) {
setTimeout(() => diceBox.clear(), {clearAfter} * 1000)
timeout = setTimeout(() => diceBox.clear(), {clearAfter} * 1000)
}
}

View File

@@ -7,13 +7,27 @@
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script src="/vendor/color-picker.js"></script>
<style>
.w3-theme-l6 { color:#000 !important; background-color:#999999 !important}
.w3-theme-l4 { color:#fff !important; background-color:#666666 !important}
.w3-theme-l1 { color:#fff !important; background-color:#333333 !important}
.w3-theme-l6 {
color: #000 !important;
background-color: #999999 !important;
border-radius: 10px;
}
.w3-theme-l4 {
color: #fff !important;
background-color: #666666 !important;
border-radius: 10px;
}
.w3-theme-l1 {
color: #fff !important;
background-color: #333333 !important;
border-radius: 10px;
}
.collapsible {
background-color: #333333;
color: black;
cursor: pointer;
margin-top: 10px;
padding: 18px;
width: 100%;
@@ -28,12 +42,26 @@
display: none;
overflow: hidden;
background-color: #999999;
color: #000
color: #000;
border-radius: 10px;
}
button {
padding: 10px;
border: #333333 3px solid;
border-radius: 10px;
background: #333333;
color: #fff
}
button:hover {
background: #444444;
}
button:active {
background: #222222;
}
input {
margin: 10px;
}
@@ -98,14 +126,20 @@
width: 5px;
height: 5px;
font-size: large;
color: #000
}
.overlayButton:hover {
background: transparent;
}
.tooltip {
position: fixed;
border-radius: 0.5rem;
padding: 15px;
color:#fff !important;
background-color:#333333dd !important
color: #fff !important;
background-color: #333333dd !important
}
#dice-box {
@@ -122,33 +156,150 @@
height: 100%;
margin: 20px
}
.checkbox {
position: relative;
padding-left: 100px;
margin-bottom: 12px;
margin-left: 10px;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.checkbox input {
position: absolute;
opacity: 0;
cursor: pointer;
height: 0;
width: 0;
}
.checkmark {
margin-left: 75px;
position: absolute;
top: 0;
left: 0;
height: 15px;
width: 15px;
background-color: #eee;
}
.checkbox:hover input ~ .checkmark {
background-color: #ccc;
}
/* When the checkbox is checked, add a blue background */
.checkbox input:checked ~ .checkmark {
background-color: #333333;
}
/* Create the checkmark/indicator (hidden when not checked) */
.checkmark:after {
content: "";
position: absolute;
display: none;
}
/* Show the checkmark when checked */
.checkbox input:checked ~ .checkmark:after {
display: block;
}
/* Style the checkmark/indicator */
.checkbox .checkmark:after {
left: 5px;
top: 2px;
width: 5px;
height: 10px;
border: solid white;
border-width: 0 3px 3px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg);
}
#snackbar-container {
visibility: hidden;
position: fixed;
width: 100%;
z-index: 1;
bottom: 200px;
display: flex;
justify-content: center;
align-items: center;
}
#snackbar {
visibility: hidden;
text-align: center;
border-radius: 0.5rem;
padding: 15px;
color: #fff !important;
border: #fff 5px solid;
background-color: #333333dd !important
}
#snackbar-container.show {
visibility: visible;
}
#snackbar.show {
visibility: visible;
-webkit-animation: fadein 0.5s, fadeout 0.5s 2.5s;
animation: fadein 0.5s, fadeout 0.5s 2.5s;
}
</style>
</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">
<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">Dice-Tower</h1>
<div class="w3-panel w3-theme-l4 w3-card w3-display-container" style="padding: 25px; text-align: center; margin-bottom: auto">
<label for="name" id="nameLabel">Name </label><input type="text" id="name" style="width: 75%" required onkeyup="start(event)"/><br/>
<label for="room" id="roomLabel">Room </label><input type="text" id="room" style="width: 75%" required onkeyup="start(event)"/><br/>
<button id="start" onclick="start()" style="align-self: center">Start</button>
<div class="w3-panel w3-theme-l4 w3-card w3-display-container"
style="padding: 25px; text-align: center; margin-bottom: auto;">
<label for="name" id="nameLabel">Name </label><input type="text" id="name" style="width: 50%; margin-top: 20px"
required onkeyup="start(event)"/><br/>
<label for="room" id="roomLabel">Room </label><input type="text" id="room" style="width: 50%" required
onkeyup="start(event)"/><br/>
<div>
<button id="start" onclick="start()" style="align-self: center; margin-top: 20px">Start 🞂</button>
<label class="checkbox" id="gm-container">Join as GM
<input type="checkbox" id="gm" style="margin-left: 50px">
<span class="checkmark"></span>
</label>
</div>
</div>
<div id="dice-tower" hidden class="w3-panel w3-theme-l4 w3-card w3-display-container" style="padding: 25px; margin-bottom: auto">
<button type="button" class="collapsible" style="color: white; font-weight: bold">Overlay URLs <a>🞃</a></button>
<div id="dice-tower" hidden class="w3-panel w3-theme-l4 w3-card w3-display-container"
style="padding: 25px; margin-bottom: auto">
<button type="button" class="collapsible" style="color: white; font-weight: bold">Overlay URLs <a>🞃</a></button>
<div class="content">
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline;">
<label for="overlayId">Dice-Overlay <a style="color: red"> (Only open once) </a> </label>
<input type="text" readonly id="overlayId" style="flex-grow: 1"/>
<button popovertarget="overlay-hint" data-trigger="hover" class="overlayButton">?</button>
<div id="overlay-urls">
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline;">
<label for="overlayId" id="overlayLabel">Dice-Overlay </label>
<input type="text" readonly id="overlayId" style="flex-grow: 1" onclick="copyToClipboard(this.id)"/>
<button id="overlay-hint-button" popovertarget="overlay-hint" data-trigger="hover"
class="overlayButton">🛈
</button>
</div>
</div>
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline;"
hidden id="all-results-urls">
<label for="resultsId">All-Results-Overlay </label>
<input type="text" readonly id="resultsId" style="flex-grow: 1" onclick="copyToClipboard(this.id)"/>
<button popovertarget="all-results-hint" data-trigger="hover" class="overlayButton">🛈</button>
</div>
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline;">
<label for="resultsId">All-Results-Overlay </label><input type="text" readonly id="resultsId" style="flex-grow: 1"/><button popovertarget="all-results-hint" data-trigger="hover" class="overlayButton">?</button>
</div>
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline;">
<label for="myResultsId">My-Results-Overlay </label><input type="text" readonly id="myResultsId" style="flex-grow: 1"/><button popovertarget="my-results-hint" data-trigger="hover" class="overlayButton">?</button>
<label for="myResultsId">My-Results-Overlay </label>
<input type="text" readonly id="myResultsId" style="flex-grow: 1" onclick="copyToClipboard(this.id)"/>
<button popovertarget="my-results-hint" data-trigger="hover" class="overlayButton">🛈</button>
</div>
</div>
<button type="button" class="collapsible" style="color: white; font-weight: bold">Customize Dice <a>🞃</a></button>
<button type="button" class="collapsible" style="color: white; font-weight: bold">Customize Dice <a>🞃</a>
</button>
<div class="content">
<label for="theme">Theme </label>
<select name="theme" id="theme" style="margin: 25px">
@@ -162,33 +313,59 @@
<option value="smooth">Smooth</option>
<option value="wooden">Wooden</option>
</select>
<br/>
<color-picker id="themeColor"></color-picker><br/>
<color-picker id="themeColor"></color-picker>
<div id="dice-box"></div>
<button style="margin-bottom: 20px" id="preview">Preview</button>
<button style="margin-bottom: 20px" onclick="saveDice()">Save</button>
<button popovertarget="save-dice-hint" data-trigger="hover" class="overlayButton">?</button>
</div><br/>
<p>Example Commands: "1d6", "2d8 1d100", "1d4 and 1d6", "2d20 & 1d2, "5d6+10"</p>
<label for="command">Command </label><input type="text" id="command" onkeyup="roll(event)"/>
<button hidden id="roll" onclick="roll()">Roll</button><br/><br/>
<label for="resultSwitch">Show all results </label>
<label class="switch">
<input type="checkbox" id="resultSwitch">
<span class="slider"></span>
</label>
<button style="margin: 10px" id="preview">Preview 🔎</button>
<button style="margin: 10px" onclick="saveDice()">Save 💾</button>
<button popovertarget="save-dice-hint" data-trigger="hover" class="overlayButton">🛈</button>
</div>
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: center; margin: 20px 25px;">
<label style="font-size: x-large; font-weight: bold;">Roll </label>
<button style="border: transparent; border-radius: 100%; font-size: x-large; font-weight: bold; height: 50px; width: 50px"
onclick="removeDice()">-
</button>
<label style="font-size: x-large; font-weight: bold;" id="dice-amount">1</label>
<button style="border: transparent; border-radius: 100%; font-size: x-large; font-weight: bold; height: 50px; width: 50px"
onclick="addDice()">+
</button>
<button style="font-size: x-large; font-weight: bold;" onclick="rollEasy('d4')">D4</button>
<button style="font-size: x-large; font-weight: bold;" onclick="rollEasy('d6')">D6</button>
<button style="font-size: x-large; font-weight: bold;" onclick="rollEasy('d8')">D8</button>
<button style="font-size: x-large; font-weight: bold;" onclick="rollEasy('d10')">D10</button>
<button style="font-size: x-large; font-weight: bold;" onclick="rollEasy('d12')">D12</button>
<button style="font-size: x-large; font-weight: bold;" onclick="rollEasy('d20')">D20</button>
<button style="font-size: x-large; font-weight: bold;" onclick="rollEasy('d100')">D100</button>
</div>
<div style="display: flex; flex-direction: row; justify-content: space-between; align-items: baseline; margin: 20px 25px;">
<label for="command">Command </label>
<input type="text" id="command" style="flex-grow: 1" onkeyup="roll(event)"/>
<button hidden id="roll" onclick="roll()">Roll 🎲</button>
<button popovertarget="command-hint" data-trigger="hover" class="overlayButton">🛈</button>
</div>
<div style="margin: 20px 25px" id="all-results">
<label for="resultSwitch">Show all results </label>
<label class="switch">
<input type="checkbox" id="resultSwitch">
<span class="slider"></span>
</label>
</div>
</div>
<div id="results" hidden class="w3-panel w3-theme-l6 w3-card w3-display-container" style="padding: 25px; flex-grow: 1; margin-bottom: auto">
<iframe id="resultFrame" title="results" style="width: 100%; height: 85%; overflow: hidden; border: 0" onload="this.height=this.contentWindow.document.body.scrollHeight;" ></iframe>
<div id="results" hidden class="w3-panel w3-theme-l6 w3-card w3-display-container"
style="padding: 25px; flex-grow: 1; margin-bottom: auto">
<iframe id="resultFrame" title="results" style="width: 100%; height: 85%; overflow: hidden; border: 0"
onload="this.height=this.contentWindow.document.body.scrollHeight;"></iframe>
</div>
<div popover id="overlay-hint" class="tooltip">
<p style="color: red; font-weight: bold">Only open Overlay once, unless you want multiple results</p>
<p style="color: red; font-weight: bold">Only the last loaded instance of that overlay rolls the dice!</p>
<p>Query Params you can Change:</p>
<ul>
<li><strong>scale</strong> changes the size of the dice (any value over 1; remove param or set -1 to keep the dice)</li>
<li><strong>clearAfter</strong> time until dice are cleared (in seconds)</li>
<li><strong>scale</strong> changes the size of the dice (any value over 1)</li>
<li><strong>clearAfter</strong> time until dice are cleared (in seconds; remove param or set -1 to keep the
dice)
</li>
</ul>
</div>
<div popover id="all-results-hint" class="tooltip">
@@ -200,13 +377,60 @@
<div popover id="save-dice-hint" class="tooltip">
This saves your current theme and theme color for current Name
</div>
<div popover id="command-hint" class="tooltip">
Example Commands: "1d6", "2d8 1d100", "1d4 and 1d6", "2d20 & 1d2, "5d6+10"
</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">
<h2 style="text-align: center">How-To</h2>
<ul>
<li>
Join a room by entering your character name and the name of the room.<br/>
<strong>If you are a GM, make sure to join the room first or let all other players rejoin to get all
Overlay-URLs.</strong>
</li>
<li>Open your Dice-Overlay either in a new Tab or as a browser source in OBS</li>
<ul>
<li style="color: red; font-weight: bold">Only the last loaded instance of that overlay rolls the
dice!
</li>
<li>You can configure your Overlay with query parameters (more information at the info element next
to the link)
</li>
</ul>
<li>Configure your dice</li>
<li>Save your dice configuration</li>
<li>Start rolling</li>
</ul>
</div>
</div>
</div>
<div id="snackbar-container">
<div id="snackbar">.. they see them rolling</div>
</div>
<script>
function addDice() {
let amount = +document.getElementById('dice-amount').innerText
document.getElementById('dice-amount').innerText = amount + 1
}
function removeDice() {
let amount = +document.getElementById('dice-amount').innerText
if (amount > 1) {
document.getElementById('dice-amount').innerText = amount - 1
}
}
function url() {
return window.location.protocol + '//' + window.location.hostname + (window.location.port?.length > 0 ? ':' + window.location.port : '');
}
function start(event) {
if((!event || event.keyCode === 13) && document.getElementById('name').value.length > 0 && document.getElementById('room').value.length > 0) {
console.log(document.getElementById('gm').checked)
if ((!event || event.keyCode === 13) && document.getElementById('name').value.length > 0 && document.getElementById('room').value.length > 0) {
document.getElementById('overlayId').value = url() + '/overlay/' + document.getElementById('room').value + ':' + localStorage.getItem('userId') + '?scale=7&clearAfter=30';
document.getElementById('resultsId').value = url() + '/overlay/' + document.getElementById('room').value + '/results';
document.getElementById('myResultsId').value = document.getElementById('resultsId').value + '?name=' + encodeURIComponent(document.getElementById('name').value) + '&user=' + localStorage.getItem('userId');
@@ -216,9 +440,14 @@
document.getElementById('dice-tower').hidden = false;
document.getElementById('name').hidden = true;
document.getElementById('room').hidden = true;
document.getElementById('gm-container').hidden = true;
document.getElementById('how-to').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';
document.getElementById('nameLabel').innerHTML = '<strong style="font-size:x-large;">' + document.getElementById('name').value + '</strong>';
document.getElementById('roomLabel').innerHTML = '<strong style="font-size:medium;">' + document.getElementById('room').value + '</strong>';
document.getElementById('overlayLabel').innerHTML = 'Dice-Overlay for <strong>' + document.getElementById('name').value + '</strong>';
document.title = document.getElementById('name').value + ' - Dice-Tower';
if (localStorage.getItem(document.getElementById('name').value + "-theme")) {
@@ -227,11 +456,58 @@
if (localStorage.getItem(document.getElementById('name').value + "-themeColor")) {
document.getElementById('themeColor').setColor(localStorage.getItem(document.getElementById('name').value + "-themeColor"));
}
let httpRequest = new XMLHttpRequest();
httpRequest.open('POST', url() + '/dice/' + document.getElementById('room').value + '/register')
httpRequest.setRequestHeader('Content-Type', 'application/json')
httpRequest.send(JSON.stringify({
name: document.getElementById('name').value,
overlay: document.getElementById('overlayId').value,
id: document.getElementById('room').value + ':' + localStorage.getItem('userId')
}))
if (document.getElementById('gm').checked) {
document.getElementById('resultSwitch').checked = true;
document.getElementById('resultFrame').src = document.getElementById('resultsId').value;
const evtSource = new EventSource(url() + '/dice/' + document.getElementById('room').value + '/users');
evtSource.addEventListener('message', function (event) {
let data = JSON.parse(event.data);
if (data.id !== document.getElementById('room').value + ':' + localStorage.getItem('userId')) {
let overlays = document.getElementById('overlay-urls');
let newOverlay = document.getElementById(data.id) ?? document.createElement('div');
newOverlay.replaceChildren(...[]);
newOverlay.id = data.id;
newOverlay.style.display = "flex";
newOverlay.style.flexDirection = "row";
newOverlay.style.justifyContent = "space-between";
newOverlay.style.alignItems = "baseline";
let newLabel = document.createElement('label');
newLabel.for = data.id + 'url';
newLabel.innerHTML = "Dice-Overlay for <strong>" + data.name + "</strong>";
let newInput = document.createElement('input');
newInput.type = "text";
newInput.readOnly = true;
newInput.id = data.id + 'url';
newInput.style.flexGrow = '1';
newInput.value = data.overlay;
newInput.onclick = () => copyToClipboard(newInput.id)
let hint = document.getElementById('overlay-hint-button').cloneNode(true);
newOverlay.appendChild(newLabel);
newOverlay.appendChild(newInput);
newOverlay.appendChild(hint);
overlays.appendChild(newOverlay);
}
showPopover();
});
}
}
}
function rollEasy(dice) {
document.getElementById('command').value = document.getElementById('dice-amount').innerText + dice;
roll();
}
function roll(event) {
if((!event || event.keyCode === 13) && document.getElementById('command').value?.length > 0) {
if ((!event || event.keyCode === 13) && document.getElementById('command').value?.length > 0) {
let httpRequest = new XMLHttpRequest();
httpRequest.open('POST', url() + '/dice/' + document.getElementById('room').value + ':' + localStorage.getItem(`userId`))
httpRequest.setRequestHeader('Content-Type', 'application/json')
@@ -240,7 +516,7 @@
command: document.getElementById('command').value,
themeColor: document.getElementById('themeColor').value,
theme: document.getElementById('theme').value
} ))
}))
}
}
@@ -264,20 +540,24 @@
});
}
const popover = document.querySelectorAll("[popovertarget][data-trigger='hover']");
function showPopover() {
const popover = document.querySelectorAll("[popovertarget][data-trigger='hover']");
popover.forEach((e) => {
const target = document.querySelector("#" + e.getAttribute("popovertarget"));
e.addEventListener("mouseover",()=>{
target.showPopover();
popover.forEach((e) => {
const target = document.querySelector("#" + e.getAttribute("popovertarget"));
e.addEventListener("mouseover", () => {
target.showPopover();
});
e.addEventListener("mouseout", () => {
target.hidePopover();
});
});
}
e.addEventListener("mouseout",()=>{
target.hidePopover();
});
});
showPopover();
document.getElementById('resultSwitch').addEventListener('change', function() {
document.getElementById('resultSwitch').addEventListener('change', function () {
if (!this.checked) {
document.getElementById('resultFrame').src = document.getElementById('myResultsId').value;
} else {
@@ -285,15 +565,36 @@
}
})
document.addEventListener("DOMContentLoaded", async() => {
document.addEventListener("DOMContentLoaded", async () => {
if (!localStorage.getItem("userId")) {
localStorage.setItem("userId", self.crypto.randomUUID());
}
})
function copyToClipboard(id) {
let copyText = document.getElementById(id);
copyText.select();
copyText.setSelectionRange(0, 99999);
navigator.clipboard.writeText(copyText.value);
showSnackbar("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(function () {
snackbar.className = snackbar.className.replace("show", "");
snackbarContainer.className = snackbarContainer.className.replace("show", "");
}, 5000);
}
</script>
<script type="module">
import DiceBox from "/vendor/dice-box/dice-box.es.js";
document.addEventListener("DOMContentLoaded", async() => {
document.addEventListener("DOMContentLoaded", async () => {
document.getElementById('preview').onclick = async () => {
document.getElementById('dice-box').replaceChildren(...[])
const diceBox = new DiceBox("#dice-box", {
@@ -303,13 +604,14 @@
scale: 14
});
await diceBox.init()
diceBox.roll(['1d2','1d4','1d6','1d8','1d10','1d12','1d20','1d100']);
diceBox.roll(['1d2', '1d4', '1d6', '1d8', '1d10', '1d12', '1d20', '1d100']);
}
})
</script>
</body>
<footer class="w3-theme-l1 w3-center w3-padding-16">
<a href="https://git.arindy.de/arindy/dice-tower" target="_blank" class="w3-hover-text-black">Dice-Tower on my GitTea</a>
<a href="https://git.arindy.de/arindy/dice-tower" target="_blank" class="w3-hover-text-black">Dice-Tower on my
GitTea</a>
</footer>
</html>

View File

@@ -31,7 +31,7 @@
resultText += '<br/>&ensp; D' + result.sides + ': [' + values.map(value => value === 1 ? '<strong style="color: red">' + value + '</strong>' : value === result.sides ? '<strong style="color: 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 style="font-size: x-large">' + result.value + '</strong> '
})
}
node.innerHTML = '<strong style="text-shadow: 2px 2px 10px ' + data.themeColor + ';">' + data.name + ':</strong> &#127922; ' + resultText
node.innerHTML = '<strong style="text-shadow: 2px 2px 10px ' + data.themeColor + ';">' + data.name + ':</strong> 🎲 ' + resultText
name.appendChild(node)
document.getElementById('results').insertBefore(name, document.getElementById('results').firstChild);
}