mirror of
https://github.com/nuttylmao/nutty.gg.git
synced 2026-09-18 19:50:58 -04:00
Complete overhaul of Printer Bot dock
First stage of widget-dock-core
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 2000 1556" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(30.772,0,0,30.772,323.017,878.74)">
|
||||
<path d="M32.927,8.977L22,22L11.073,8.977C14.134,6.408 18.003,5 22,5C25.997,5 29.866,6.408 32.927,8.977ZM-5.271,-10.5L-10.497,-16.729C-1.392,-24.369 10.114,-28.557 22,-28.557C33.886,-28.557 45.392,-24.369 54.497,-16.729L49.271,-10.5C41.63,-16.912 31.974,-20.426 22,-20.426C12.026,-20.426 2.37,-16.912 -5.271,-10.5ZM4.373,0.993L0.145,-4.046C6.269,-9.184 14.007,-12 22,-12C29.993,-12 37.731,-9.184 43.855,-4.046L39.627,0.993C34.688,-3.151 28.447,-5.422 22,-5.422C15.553,-5.422 9.312,-3.151 4.373,0.993Z" style="fill:rgb(0,230,118);"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg width="100%" height="100%" viewBox="0 0 1865 1556" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;">
|
||||
<g transform="matrix(86.4291,0,0,86.4291,-901.44,-432.146)">
|
||||
<path d="M32,9L32,15L30,15L30,9L32,9ZM32,17L32,19L30,19L30,17L32,17ZM28.048,9.158C26.155,8.331 24.097,7.895 22,7.895C18.449,7.895 15.011,9.146 12.291,11.429L10.43,9.211C13.672,6.491 17.768,5 22,5C24.923,5 27.782,5.712 30.339,7.048L30,7.048C28.922,7.048 28.048,7.922 28.048,9L28.048,9.158ZM28.082,15.362C26.355,13.988 24.212,13.237 22,13.237C19.705,13.237 17.483,14.045 15.724,15.521L14.219,13.727C16.399,11.897 19.154,10.895 22,10.895C24.135,10.895 26.22,11.459 28.048,12.514L28.048,15C28.048,15.124 28.06,15.245 28.082,15.362ZM25.891,18.363L22,23L18.109,18.363C19.2,17.449 20.577,16.947 22,16.947C23.423,16.947 24.8,17.449 25.891,18.363Z" style="fill:rgb(221,44,0);"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,86 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="shortcut icon" href="#" />
|
||||
<link rel="stylesheet" href="../../styles/global.css" />
|
||||
<link rel="stylesheet" href="./style.css" />
|
||||
<script type="text/javascript" src="https://unpkg.com/@streamerbot/client/dist/streamerbot-client.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/luxon@3/build/global/luxon.min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<!-- Header -->
|
||||
<div id="header">
|
||||
<img src="../../resources/logo.png" style="height: 40px;" />
|
||||
<label id="title" class="title"></label>
|
||||
<div id="header-end">
|
||||
<button id="sb-actions-button" onclick="OpenRequiredActionsDialog()">
|
||||
</button>
|
||||
<button id="sb-status-button" onclick="OpenConnectDialog()">
|
||||
<img id="sb-status-icon" style="height: 1em;" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Page Contents -->
|
||||
<iframe id="content">
|
||||
</iframe>
|
||||
|
||||
<!-- Blur Layer -->
|
||||
<div id="blur-layer"></div>
|
||||
|
||||
<!-- Streamer.bot Required Actions Dialog -->
|
||||
<div id="sb-required-actions-dialog" class="dialog">
|
||||
|
||||
<button class="dialog-nav-button" onclick="CloseRequiredActionsDialog()">×</button>
|
||||
|
||||
<label id="sb-required-actions-success">✅ All actions found</label>
|
||||
|
||||
<label id="sb-required-actions-failure">⚠️ You are missing Streamer.bot actions</label>
|
||||
<label id="sb-required-actions-failure-subtext" class="setting-description">The following actions were not found in Streamer.bot:</label>
|
||||
|
||||
<div id="sb-required-actions-list" class="callout">
|
||||
</div>
|
||||
|
||||
<label class="setting-description">Please import the following </label>
|
||||
|
||||
<div id="sb-import-wrapper">
|
||||
<label id="sb-import-code" class="callout"></label>
|
||||
<button id="sb-import-copy-button" onclick="CopyImportCode()">Copy</button>
|
||||
</div>
|
||||
|
||||
<button onclick="CheckRequiredActions()">Check Again</button>
|
||||
</div>
|
||||
|
||||
<!-- Streamer.bot Connect Dialog -->
|
||||
<div id="sb-connect-dialog" class="dialog">
|
||||
|
||||
<hr class="divider">
|
||||
|
||||
<div style="display: flex; flex-direction: row; gap: 1em">
|
||||
<div class="field">
|
||||
<label for="sb-address">Address *</label>
|
||||
<input type="text" id="sb-address" name="sb-address" placeholder="127.0.0.1" value="127.0.0.1">
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="sb-port">Port *</label>
|
||||
<input type="text" id="sb-port" name="sb-port" placeholder="8080" value="8080">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="sb-password">Password</label>
|
||||
<label class="setting-description" for="sb-password">(Optional)</label>
|
||||
<input type="password" id="sb-password" name="sb-password">
|
||||
</div>
|
||||
|
||||
<hr class="divider">
|
||||
|
||||
<label id="sb-error-label"></label>
|
||||
|
||||
<button id="sb-connect-button" onclick="Connect()">Connect</button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script src="./script.js"></script>
|
||||
@@ -0,0 +1,271 @@
|
||||
////////////////
|
||||
// PARAMETERS //
|
||||
////////////////
|
||||
|
||||
const queryString = window.location.search;
|
||||
const urlParams = new URLSearchParams(queryString);
|
||||
|
||||
const configJson = urlParams.get("config") || "";
|
||||
|
||||
///////////////////
|
||||
// PAGE ELEMENTS //
|
||||
///////////////////
|
||||
|
||||
const sbConnectDialog = document.getElementById('sb-connect-dialog');
|
||||
const sbAddressInput = document.getElementById('sb-address');
|
||||
const sbPortInput = document.getElementById('sb-port');
|
||||
const sbPasswordInput = document.getElementById('sb-password');
|
||||
const sbErrorLabel = document.getElementById('sb-error-label');
|
||||
|
||||
const sbRequiredActionsDialog = document.getElementById('sb-required-actions-dialog');
|
||||
const sbRequiredActionsSuccessLabel = document.getElementById('sb-required-actions-success');
|
||||
const sbRequiredActionsFailureLabel = document.getElementById('sb-required-actions-failure');
|
||||
const sbRequiredActionsFailureSubtext = document.getElementById('sb-required-actions-failure-subtext');
|
||||
|
||||
|
||||
const sbRequiredActionsList = document.getElementById('sb-required-actions-list');
|
||||
const sbImportCodeLabel = document.getElementById('sb-import-code');
|
||||
const sbImportCopyButton = document.getElementById('sb-import-copy-button');
|
||||
|
||||
|
||||
const sbActionsButton = document.getElementById('sb-actions-button');
|
||||
const sbStatusButton = document.getElementById('sb-status-button');
|
||||
const sbStatusIcon = document.getElementById('sb-status-icon');
|
||||
|
||||
const blurLayer = document.getElementById('blur-layer');
|
||||
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// STREAMER.BOT CLIENT //
|
||||
/////////////////////////
|
||||
|
||||
// Check local storage
|
||||
if (localStorage.getItem('sbServerAddress') === null)
|
||||
localStorage.setItem('sbServerAddress', '127.0.0.1');
|
||||
if (localStorage.getItem('sbServerPort') === null)
|
||||
localStorage.setItem('sbServerPort', '8080');
|
||||
|
||||
sbAddressInput.value = localStorage.getItem('sbServerAddress');
|
||||
sbPortInput.value = localStorage.getItem('sbServerPort');
|
||||
sbPasswordInput.value = localStorage.getItem('sbServerPassword');
|
||||
|
||||
const sbServerAddress = sbAddressInput.value;
|
||||
const sbServerPort = sbPortInput.value;
|
||||
const sbServerPassword = sbPasswordInput.value;
|
||||
|
||||
window.sbClient = new StreamerbotClient({
|
||||
host: sbServerAddress,
|
||||
port: sbServerPort,
|
||||
password: sbServerPassword,
|
||||
immediate: true,
|
||||
|
||||
onConnect: (data) => {
|
||||
console.log(`Streamer.bot successfully connected to ${sbServerAddress}:${sbServerPort}`)
|
||||
console.debug(data);
|
||||
|
||||
SetConnectionState(true);
|
||||
},
|
||||
|
||||
onDisconnect: () => {
|
||||
console.error(`Streamer.bot disconnected from ${sbServerAddress}:${sbServerPort}`)
|
||||
SetConnectionState(false);
|
||||
},
|
||||
|
||||
onError: (err) => {
|
||||
console.error(`Streamer.bot disconnected from ${sbServerAddress}:${sbServerPort}`)
|
||||
SetErrorMessage(err);
|
||||
}
|
||||
});
|
||||
|
||||
function SetConnectionState(isConnected) {
|
||||
if (isConnected) {
|
||||
localStorage.setItem('sbServerAddress', sbAddressInput.value);
|
||||
localStorage.setItem('sbServerPort', sbPortInput.value);
|
||||
localStorage.setItem('sbServerPassword', sbPasswordInput.value);
|
||||
|
||||
sbConnectDialog.style.display = "none";
|
||||
blurLayer.style.display = "none";
|
||||
sbErrorLabel.style.display = 'none';
|
||||
sbStatusIcon.src = 'icons/connected.svg';
|
||||
|
||||
sbStatusButton.title = `Connected to ${window.sbClient.info.name} (${window.sbClient.info.version})`;
|
||||
|
||||
// Check required actions
|
||||
CheckRequiredActions();
|
||||
}
|
||||
else {
|
||||
sbConnectDialog.style.display = "flex";
|
||||
blurLayer.style.display = "block";
|
||||
sbStatusIcon.src = 'icons/disconnected.svg';
|
||||
|
||||
SetErrorMessage('Disconnected from Streamer.bot');
|
||||
}
|
||||
}
|
||||
|
||||
function SetErrorMessage(error) {
|
||||
sbErrorLabel.textContent = error;
|
||||
sbErrorLabel.style.display = 'block';
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////
|
||||
// CONFIG //
|
||||
////////////
|
||||
|
||||
if (configJson) {
|
||||
// Set the header/title of the page
|
||||
fetch(configJson)
|
||||
.then(res => res.json())
|
||||
.then(config => {
|
||||
const root = document.documentElement;
|
||||
const domain = getComputedStyle(root).getPropertyValue('--domain').trim();
|
||||
|
||||
// Set the page title
|
||||
parent.document.title = `${domain} • ${config.title}`;
|
||||
|
||||
// Set the title label
|
||||
title.textContent = config.title;
|
||||
})
|
||||
.catch(err => console.error('Failed to load config:', err));
|
||||
}
|
||||
|
||||
async function CheckRequiredActions() {
|
||||
if (configJson) {
|
||||
console.debug('Checking required actions...')
|
||||
|
||||
// Set the header/title of the page
|
||||
fetch(configJson)
|
||||
.then(res => res.json())
|
||||
.then(async config => {
|
||||
// Clear the required actions list
|
||||
const sbRequiredActionsList = document.getElementById('sb-required-actions-list');
|
||||
sbRequiredActionsList.innerHTML = '';
|
||||
|
||||
// Set the import code
|
||||
sbImportCodeLabel.textContent = config.sbImportCode;
|
||||
|
||||
// Assume all actions are found
|
||||
SetRequiredActionState(true);
|
||||
|
||||
// Check each required action
|
||||
if (config.requiredSbActions) {
|
||||
// Get a full list of actions currently installed in Streamer.bot
|
||||
const response = await sbClient.getActions();
|
||||
|
||||
// Iterate over required SB actions and check if they're present
|
||||
config.requiredSbActions.forEach(req => {
|
||||
const exists = response.actions.some(act => act.id === req.id);
|
||||
|
||||
console.debug(`${req.name}: ${exists ? 'Found' : 'Missing'}`)
|
||||
|
||||
// As soon as one is found that doesn't exist, throw up warning
|
||||
if (!exists)
|
||||
SetRequiredActionState(false);
|
||||
|
||||
// container div
|
||||
const item = document.createElement('div');
|
||||
item.className = 'sb-required-action';
|
||||
|
||||
// name label
|
||||
const nameLabel = document.createElement('label');
|
||||
nameLabel.textContent = req.name;
|
||||
|
||||
// status label
|
||||
const statusLabel = document.createElement('label');
|
||||
statusLabel.className = 'sb-required-action-found';
|
||||
//statusLabel.textContent = exists ? '✅' : '❌';
|
||||
statusLabel.textContent = exists ? 'Found' : 'Missing';
|
||||
statusLabel.style.color = exists ? '#00d26a' : '#f92f60';
|
||||
statusLabel.style.fontWeight = 500;
|
||||
|
||||
// append labels to div
|
||||
item.appendChild(nameLabel);
|
||||
item.appendChild(statusLabel);
|
||||
|
||||
// append div to list
|
||||
sbRequiredActionsList.appendChild(item);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are no required actions, so hide the button
|
||||
sbActionsButton.style.display = 'none';
|
||||
}
|
||||
})
|
||||
.catch(err => console.error('Failed to load config:', err));
|
||||
}
|
||||
}
|
||||
|
||||
function SetRequiredActionState(isSuccess) {
|
||||
if (isSuccess)
|
||||
{
|
||||
sbRequiredActionsSuccessLabel.style.display = 'block';
|
||||
sbRequiredActionsFailureLabel.style.display = 'none';
|
||||
sbRequiredActionsFailureSubtext.style.display = 'none';
|
||||
|
||||
sbActionsButton.title = `All actions found`;
|
||||
|
||||
sbActionsButton.textContent = '✅';
|
||||
}
|
||||
else
|
||||
{
|
||||
sbRequiredActionsSuccessLabel.style.display = 'none';
|
||||
sbRequiredActionsFailureLabel.style.display = 'block';
|
||||
sbRequiredActionsFailureSubtext.style.display = 'block';
|
||||
|
||||
sbActionsButton.title = `You are missing Streamer.bot actions`;
|
||||
|
||||
sbActionsButton.textContent = '⚠️';
|
||||
|
||||
OpenRequiredActionsDialog();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////
|
||||
// PAGE INTERACTIONS //
|
||||
///////////////////////
|
||||
|
||||
function Connect() {
|
||||
sbClient.options.host = sbAddressInput.value;
|
||||
sbClient.options.port = sbPortInput.value;
|
||||
sbClient.options.password = sbPasswordInput.value;
|
||||
sbClient.connect();
|
||||
}
|
||||
|
||||
function CopyImportCode() {
|
||||
const textToCopy = sbImportCodeLabel.textContent;
|
||||
navigator.clipboard.writeText(textToCopy)
|
||||
.then(() => {
|
||||
console.debug('Copied to clipboard!');
|
||||
|
||||
// Click feedback
|
||||
const root = document.documentElement;
|
||||
const successColor = getComputedStyle(root).getPropertyValue('--success-color').trim();
|
||||
const buttonColor = getComputedStyle(root).getPropertyValue('--button-color').trim();
|
||||
sbImportCopyButton.textContent = 'Copied!';
|
||||
sbImportCopyButton.style.background = successColor;
|
||||
setTimeout(() => {
|
||||
sbImportCopyButton.textContent = 'Copy';
|
||||
sbImportCopyButton.style.background = buttonColor;
|
||||
}, 1500);
|
||||
})
|
||||
.catch(err => console.error('Failed to copy text: ', err));
|
||||
}
|
||||
|
||||
function OpenConnectDialog() {
|
||||
sbConnectDialog.style.display = "flex";
|
||||
blurLayer.style.display = "block";
|
||||
}
|
||||
|
||||
function OpenRequiredActionsDialog() {
|
||||
sbRequiredActionsDialog.style.display = "flex";
|
||||
blurLayer.style.display = "block";
|
||||
}
|
||||
|
||||
function CloseRequiredActionsDialog() {
|
||||
sbRequiredActionsDialog.style.display = "none";
|
||||
blurLayer.style.display = "none";
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************/
|
||||
/*** HEADER ***/
|
||||
/**************/
|
||||
|
||||
#header {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
padding: 1em;
|
||||
gap: 1em;
|
||||
box-shadow: 0px 0px 10px rgba(0, 0, 0, 1);
|
||||
}
|
||||
|
||||
#header-end {
|
||||
margin-left: auto;
|
||||
align-items: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 1em;
|
||||
}
|
||||
|
||||
#header-end button {
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*********************/
|
||||
/*** PAGE CONTENTS ***/
|
||||
/*********************/
|
||||
|
||||
#content {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************/
|
||||
/*** BLUR LAYER ***/
|
||||
/******************/
|
||||
|
||||
#blur-layer {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
/* top:0; left:0; bottom:0; right:0 */
|
||||
backdrop-filter: blur(5px);
|
||||
/* blur the content behind */
|
||||
-webkit-backdrop-filter: blur(5px);
|
||||
/* Safari support */
|
||||
z-index: 1;
|
||||
/* behind the modal */
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************/
|
||||
/*** STREAMER.BOT CONNECT BOX ***/
|
||||
/********************************/
|
||||
|
||||
#sb-required-actions-dialog {
|
||||
max-width: 30em;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#sb-connect-button:enabled:hover {
|
||||
background-color: #3be477;
|
||||
}
|
||||
|
||||
#sb-error-label {
|
||||
background: #a82d2e33;
|
||||
border-radius: 0.5em;
|
||||
padding: 1em;
|
||||
color: #c65e5e;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/******************************************/
|
||||
/*** STREAMER.BOT REQUIRED ACTIONS LIST ***/
|
||||
/******************************************/
|
||||
|
||||
.sb-required-action {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sb-required-action-found {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
#sb-import-code {
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
max-width: 100%;
|
||||
padding: 0.5em;
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
#sb-import-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5em;
|
||||
}
|
||||
Reference in New Issue
Block a user