mirror of
https://github.com/DerTyp7/teamspeak-obs-overlay.git
synced 2025-10-29 12:52:09 +01:00
clean up
This commit is contained in:
@@ -1,9 +1,10 @@
|
|||||||
import React, { ChangeEvent, useRef, useState } from "react";
|
import React, { ChangeEvent, useRef, useState, useEffect } from "react";
|
||||||
import "@styles/Generator.scss";
|
import "@styles/Generator.scss";
|
||||||
import Viewer from "./Viewer";
|
import Viewer from "./Viewer";
|
||||||
|
|
||||||
export default function Generator() {
|
export default function Generator() {
|
||||||
const [outputUrl, setOutputUrl] = useState(new URL(window.location.href).toString());
|
// State variables
|
||||||
|
const [outputUrl, setOutputUrl] = useState(() => new URL(window.location.href).toString());
|
||||||
const copiedTooltipRef = useRef<HTMLDivElement>(null);
|
const copiedTooltipRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const [remoteAppPort, setRemoteAppPort] = useState(5899);
|
const [remoteAppPort, setRemoteAppPort] = useState(5899);
|
||||||
@@ -11,10 +12,12 @@ export default function Generator() {
|
|||||||
const [hideNonTalking, setHideNonTalking] = useState(false);
|
const [hideNonTalking, setHideNonTalking] = useState(false);
|
||||||
const [clientLimit, setClientLimit] = useState(0);
|
const [clientLimit, setClientLimit] = useState(0);
|
||||||
|
|
||||||
React.useEffect(() => {
|
// Effect to generate URL when dependencies change
|
||||||
|
useEffect(() => {
|
||||||
generateUrl();
|
generateUrl();
|
||||||
}, [remoteAppPort, showChannelName, hideNonTalking, clientLimit]);
|
}, [remoteAppPort, showChannelName, hideNonTalking, clientLimit]);
|
||||||
|
|
||||||
|
// Function to generate the output URL
|
||||||
function generateUrl() {
|
function generateUrl() {
|
||||||
const url = new URL(window.location.href.replace("/generate", ""));
|
const url = new URL(window.location.href.replace("/generate", ""));
|
||||||
url.searchParams.set("remoteAppPort", remoteAppPort.toString());
|
url.searchParams.set("remoteAppPort", remoteAppPort.toString());
|
||||||
@@ -25,6 +28,7 @@ export default function Generator() {
|
|||||||
setOutputUrl(url.toString());
|
setOutputUrl(url.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to copy URL to clipboard
|
||||||
function copy() {
|
function copy() {
|
||||||
navigator.clipboard.writeText(outputUrl);
|
navigator.clipboard.writeText(outputUrl);
|
||||||
|
|
||||||
@@ -43,16 +47,21 @@ export default function Generator() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="generator">
|
<div className="generator">
|
||||||
|
{/* Header */}
|
||||||
<div className="headline">
|
<div className="headline">
|
||||||
<h1>TS5-OBS-Overlay Generator</h1>
|
<h1>TS5-OBS-Overlay Generator</h1>
|
||||||
<h4>by DerTyp7</h4>
|
<h4>by DerTyp7</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Instructions */}
|
||||||
<div className="instructions">
|
<div className="instructions">
|
||||||
<p>1. Customize your settings</p>
|
<p>1. Customize your settings</p>
|
||||||
<p>2. Copy the generated URL</p>
|
<p>2. Copy the generated URL</p>
|
||||||
<p>3. Paste the URL into the BrowserSource URL field in OBS</p>
|
<p>3. Paste the URL into the BrowserSource URL field in OBS</p>
|
||||||
<a href="#">Click here for detailed instructions</a>
|
<a href="#">Click here for detailed instructions</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Output Section */}
|
||||||
<div className="output">
|
<div className="output">
|
||||||
<p className="url">
|
<p className="url">
|
||||||
<code>{outputUrl}</code>
|
<code>{outputUrl}</code>
|
||||||
@@ -64,61 +73,46 @@ export default function Generator() {
|
|||||||
Copied!
|
Copied!
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Generator Content */}
|
||||||
<div className="generatorContent">
|
<div className="generatorContent">
|
||||||
|
{/* Configurations */}
|
||||||
<div className="configurations">
|
<div className="configurations">
|
||||||
<h2>Configurations</h2>
|
<h2>Configurations</h2>
|
||||||
|
|
||||||
<div className="options">
|
<div className="options">
|
||||||
|
{/* Option Sections */}
|
||||||
<section>
|
<section>
|
||||||
<div
|
{/* Show Channel Name Option */}
|
||||||
className="option"
|
<div className="option" onClick={() => setShowChannelName(!showChannelName)}>
|
||||||
onClick={() => {
|
|
||||||
setShowChannelName(!showChannelName);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input type="checkbox" checked={showChannelName} />
|
<input type="checkbox" checked={showChannelName} />
|
||||||
<label>Show channelname</label>
|
<label>Show channel name</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
{/* Hide Non-Talking Clients Option */}
|
||||||
className="option"
|
<div className="option" onClick={() => setHideNonTalking(!hideNonTalking)}>
|
||||||
onClick={() => {
|
|
||||||
setHideNonTalking(!hideNonTalking);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<input type="checkbox" checked={hideNonTalking} />
|
<input type="checkbox" checked={hideNonTalking} />
|
||||||
<label>Hide non talking clients</label>
|
<label>Hide non talking clients</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
{/* Client Limit Option */}
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<input
|
<input type="number" value={clientLimit} min={0} onChange={(e: ChangeEvent<HTMLInputElement>) => setClientLimit(parseInt(e.target.value))} />
|
||||||
type="number"
|
|
||||||
value={20}
|
|
||||||
min={0}
|
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setClientLimit(parseInt(e.target.value));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<label>Client Limit</label>
|
<label>Client Limit</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* RemoteApp-Port Option */}
|
||||||
<div className="option">
|
<div className="option">
|
||||||
<input
|
<input type="number" value={remoteAppPort} min={0} onChange={(e: ChangeEvent<HTMLInputElement>) => setRemoteAppPort(parseInt(e.target.value))} />
|
||||||
type="number"
|
|
||||||
value={5899}
|
|
||||||
min={0}
|
|
||||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
|
||||||
setRemoteAppPort(parseInt(e.target.value));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<label>RemoteApp-Port</label>
|
<label>RemoteApp-Port</label>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Preview */}
|
||||||
<div className="preview">
|
<div className="preview">
|
||||||
<Viewer remoteAppPort={remoteAppPort} showChannelName={showChannelName} hideNonTalking={hideNonTalking} clientLimit={clientLimit} />
|
<Viewer remoteAppPort={remoteAppPort} showChannelName={showChannelName} hideNonTalking={hideNonTalking} clientLimit={clientLimit} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ $breakpoint-1: 1200px;
|
|||||||
$breakpoint-2: 790px;
|
$breakpoint-2: 790px;
|
||||||
$breakpoint-3: 600px;
|
$breakpoint-3: 600px;
|
||||||
|
|
||||||
|
// Tooltip animation keyframes
|
||||||
@keyframes tooltipAnimation {
|
@keyframes tooltipAnimation {
|
||||||
0% {
|
0% {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -16,7 +17,7 @@ $breakpoint-3: 600px;
|
|||||||
|
|
||||||
.generator {
|
.generator {
|
||||||
background-color: #232528;
|
background-color: #232528;
|
||||||
color: white;
|
color: #fff;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@@ -39,25 +40,17 @@ $breakpoint-3: 600px;
|
|||||||
gap: 10px 50px;
|
gap: 10px 50px;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
|
|
||||||
p,
|
p,
|
||||||
a {
|
a {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
color: #b4b4b4;
|
color: #b4b4b4;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
|
||||||
color: #3abe78;
|
|
||||||
font-weight: bold;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: all 100ms ease-in-out;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #31f399;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.output {
|
.output {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@@ -142,6 +135,7 @@ $breakpoint-3: 600px;
|
|||||||
justify-content: left;
|
justify-content: left;
|
||||||
column-gap: 10px;
|
column-gap: 10px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
-moz-appearance: none;
|
-moz-appearance: none;
|
||||||
@@ -154,7 +148,7 @@ $breakpoint-3: 600px;
|
|||||||
outline: none;
|
outline: none;
|
||||||
transition: all 200ms ease-in-out;
|
transition: all 200ms ease-in-out;
|
||||||
position: relative;
|
position: relative;
|
||||||
color: white;
|
color: #fff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|
||||||
&::-webkit-outer-spin-button,
|
&::-webkit-outer-spin-button,
|
||||||
@@ -163,7 +157,7 @@ $breakpoint-3: 600px;
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make it a cross when checked
|
// Cross when checked styles
|
||||||
&:checked {
|
&:checked {
|
||||||
&:after {
|
&:after {
|
||||||
content: "";
|
content: "";
|
||||||
@@ -193,7 +187,10 @@ $breakpoint-3: 600px;
|
|||||||
|
|
||||||
input[type="number"] {
|
input[type="number"] {
|
||||||
width: 50px;
|
width: 50px;
|
||||||
|
height: 25px;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
appearance: textfield;
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
@@ -202,9 +199,13 @@ $breakpoint-3: 600px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Preview styles
|
||||||
.preview {
|
.preview {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
border: 2px solid #31f39973;
|
border: 2px solid #31f39973;
|
||||||
|
|
||||||
|
// Viewer styles (see src/styles/Viewer.scss)
|
||||||
.viewer {
|
.viewer {
|
||||||
background-image: url("/images/viewer_example_background.png");
|
background-image: url("/images/viewer_example_background.png");
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
@@ -214,6 +215,7 @@ $breakpoint-3: 600px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Responsive styles
|
||||||
@media screen and (max-width: $breakpoint-1) {
|
@media screen and (max-width: $breakpoint-1) {
|
||||||
.generatorContent {
|
.generatorContent {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@@ -243,13 +245,13 @@ $breakpoint-3: 600px;
|
|||||||
.url {
|
.url {
|
||||||
width: 200px;
|
width: 200px;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.generatorContent {
|
.generatorContent {
|
||||||
.configurations {
|
.configurations {
|
||||||
.options {
|
.options {
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 30px;
|
gap: 30px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
|
//* Viewer styles
|
||||||
|
// this file contains styles for the viewer component
|
||||||
|
// styles for the viewer component should not be modified somewhere else
|
||||||
|
|
||||||
.viewer {
|
.viewer {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0 0;
|
padding: 0.5rem;
|
||||||
font-size: 3rem;
|
|
||||||
color: white;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
h1,
|
h1,
|
||||||
p {
|
p {
|
||||||
margin: 0;
|
|
||||||
background-color: #2f313680;
|
background-color: #2f313680;
|
||||||
padding: 0.25rem 0.5rem;
|
padding: 0.25rem 0.5rem;
|
||||||
border-radius: 0.25rem;
|
border-radius: 0.25rem;
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
max-width: 20ch;
|
max-width: 20ch;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.channelNameContainer {
|
.channelNameContainer {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -31,12 +32,14 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
|
|
||||||
|
// icon styles
|
||||||
svg {
|
svg {
|
||||||
width: 2.1rem;
|
width: 2.1rem;
|
||||||
aspect-ratio: 1/1;
|
aspect-ratio: 1/1;
|
||||||
margin-right: 0.5rem;
|
margin-right: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// client name styles
|
||||||
p {
|
p {
|
||||||
font-size: 1.4rem;
|
font-size: 1.4rem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// Reset styles for all elements
|
||||||
* {
|
* {
|
||||||
font-family: Arial, Helvetica, sans-serif;
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
@@ -7,19 +8,23 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set up basic styles for the entire page
|
||||||
body,
|
body,
|
||||||
html {
|
html {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure the root element takes up the full viewport
|
||||||
#root {
|
#root {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
min-width: 100%;
|
min-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Headline styles
|
||||||
h1 {
|
h1 {
|
||||||
font-size: 1.8rem;
|
font-size: 1.8rem;
|
||||||
}
|
}
|
||||||
@@ -36,6 +41,7 @@ h4 {
|
|||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common styles for heading elements
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
@@ -45,6 +51,19 @@ h6 {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text styles
|
||||||
|
a {
|
||||||
|
color: #3abe78;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all 100ms ease-in-out;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #31f399;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Button styles
|
||||||
button {
|
button {
|
||||||
background-color: #202024;
|
background-color: #202024;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -54,13 +73,14 @@ button {
|
|||||||
padding: 10px 20px;
|
padding: 10px 20px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition: all 300ms ease-in-out;
|
transition: all 300ms ease-in-out;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: #42d486;
|
background-color: #42d486;
|
||||||
color: #202024;
|
color: #202024;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// custom dark themed scrollbar
|
// Custom dark-themed scrollbar
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 5px;
|
width: 5px;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
@@ -74,8 +94,8 @@ button {
|
|||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background: #31f39973;
|
background: #31f39973;
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb:hover {
|
&:hover {
|
||||||
background: #48ee95;
|
background: #48ee95;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user