diff --git a/.gitignore b/.gitignore
index 233d6bc..cbe529b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,9 @@
-/.idea
-/DistributionTool.exe
+.DS_Store
+.idea/**
+/DistributionTool*
+.vscode/**
+package.json
+package-lock.json
+.history
+__exclude
+.editorconfig
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..aa0f75f
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "warudo.streamdeck.sdPlugin/libs"]
+ path = warudo.streamdeck.sdPlugin/libs
+ url = git@github.com:elgatosf/streamdeck-javascript-sdk.git
diff --git a/Release/warudo.streamdeck.streamDeckPlugin b/Release/warudo.streamdeck.streamDeckPlugin
index 2f9d5ad..7d54819 100644
Binary files a/Release/warudo.streamdeck.streamDeckPlugin and b/Release/warudo.streamdeck.streamDeckPlugin differ
diff --git a/warudo.streamdeck.sdPlugin/en.json b/warudo.streamdeck.sdPlugin/en.json
index 09fdcd4..ba954bb 100644
--- a/warudo.streamdeck.sdPlugin/en.json
+++ b/warudo.streamdeck.sdPlugin/en.json
@@ -1,15 +1,20 @@
{
- "Description": "Use this to create your own plugin",
- "Name": "Stream Deck Template",
- "Category": "Templates",
- "com.elgato.template.action": {
- "Name": "Action",
- "Tooltip": "This is the only action in this plugin"
- },
- "Localization": {
- "More info": "More info",
- "Message": "Message",
- "Click Me": "Click Me",
- "Button": "Button"
- }
+ "Description": "Integration with Warudo, a 3D livestreaming software for VTubers.",
+ "Name": "Warudo",
+ "Category": "Warudo",
+ "warudo.trigger": {
+ "Name": "Trigger",
+ "Tooltip": "Invoke a trigger in Warudo"
+ },
+ "warudo.toggle": {
+ "Name": "Toggle",
+ "Tooltip": "Activate a toggle in Warudo"
+ },
+ "warudo.message": {
+ "Name": "Message",
+ "Tooltip": "Send a message to Warudo"
+ },
+ "Localization": {
+ "Receiver name": "Receiver name"
+ }
}
diff --git a/warudo.streamdeck.sdPlugin/index.html b/warudo.streamdeck.sdPlugin/index.html
index 288d31f..3341200 100644
--- a/warudo.streamdeck.sdPlugin/index.html
+++ b/warudo.streamdeck.sdPlugin/index.html
@@ -2,25 +2,28 @@
- warudo.streamdeck
-
+ warudo.streamdeck
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/warudo.streamdeck.sdPlugin/js/index.js b/warudo.streamdeck.sdPlugin/index.js
similarity index 52%
rename from warudo.streamdeck.sdPlugin/js/index.js
rename to warudo.streamdeck.sdPlugin/index.js
index f210c4f..4e0a783 100644
--- a/warudo.streamdeck.sdPlugin/js/index.js
+++ b/warudo.streamdeck.sdPlugin/index.js
@@ -1,6 +1,5 @@
///
///
-///
/* GLOBALS */
@@ -26,14 +25,8 @@ let messages = {}; // context -> message
let toggleStates = {}; // receiver name -> state
const warudoEndpoint = 'ws://localhost:19069';
-// Always try to keep the websocket connection open
let ws = null;
-// Always try to keep the websocket connection open
-setInterval(() => {
- if (ws.readyState !== WebSocket.OPEN && ws.readyState !== WebSocket.CONNECTING) {
- setupWebsocket();
- }
-}, 1000);
+let _tryconnect = undefined;
const setupWebsocket = () => {
toggleStates = {};
@@ -44,7 +37,9 @@ const setupWebsocket = () => {
}
ws.onclose = function() {
console.log('Disconnected from Warudo');
- setupWebsocket();
+ if (_tryconnect) {
+ try_connect();
+ }
}
ws.onmessage = function(msg) {
console.log('Message from Warudo', msg);
@@ -67,7 +62,25 @@ const setupWebsocket = () => {
}
}
}
-setupWebsocket();
+
+const try_connect = () => {
+ _tryconnect = window.setTimeout(() => {
+ setupWebsocket();
+ }, 1000);
+}
+
+const cancel_try_connect = () => {
+ window.clearTimeout(_tryconnect);
+ _tryconnect = undefined;
+}
+
+const connecting = () => {
+ return (ws) && (ws.readyState == WebSocket.CONNECTING);
+}
+
+const connected = () => {
+ return (!connecting()) && (ws && (ws.readyState === WebSocket.OPEN));
+}
const updateToggleStates = () => {
// Find all toggle actions and update their state
@@ -129,15 +142,26 @@ actions.forEach(action => {
action.onKeyDown(async jsn => {
console.log('onKeyDown', jsn.context);
getSettingsAndRun(jsn.context, () => {
- const data = {
- receiverName: receiverNames[jsn.context],
- };
- if (action === messageAction) {
- data.message = messages[jsn.context] || '';
+ try {
+ const data = {
+ receiverName: receiverNames[jsn.context],
+ };
+ if (action === messageAction) {
+ data.message = messages[jsn.context] || '';
+ }
+
+ if (!connected()) {
+ $SD.showAlert(jsn.context);
+ return;
+ }
+
+ const payload = { action: actionType, data }
+ console.log('Sending payload', payload);
+ ws.send(JSON.stringify(payload));
+ $SD.showOk(jsn.context);
+ } catch (e) {
+ $SD.showAlert(jsn.context);
}
- const payload = { action: actionType, data }
- console.log('Sending payload', payload)
- ws.send(JSON.stringify(payload));
});
});
@@ -179,119 +203,15 @@ actions.forEach(action => {
});
-/* STREAMDECK RELATED */
-
-// In this example, we're monitoring a couple of apps
-// that we've added to the manifest.json file
-// under the "monitoredApps" key
-// if one of the monitored apps is launched or terminated,
-// we'll update the key images and send the running apps list
-// to the property inspector
-
$SD.onApplicationDidLaunch((jsn) => {
const {event, payload} = jsn;
- console.log('onApplicationDidLaunch', jsn, event, payload);
- // our monitored app settings (in manifest.json) are case-sensitive
- // so we need to capitalize the app name to match
- const app = Utils.capitalize(Utils.getApplicationName(payload));
- // there should be a corresponding image in the images folder
- const img = `images/${payload.application}.png`;
- // try to load it
- Utils.loadImagePromise(img).then(results => {
- MCONTEXTS.forEach(c => updateKeyImages(c, img));
- });
- // add the monitored app to our running apps list
- if(!MPLUGINDATA.runningApps.includes(app)) {MPLUGINDATA.runningApps.push(app);};
- // send the running apps list to the property inspector
- MCONTEXTS.forEach(updateRunningApps);
+ console.log('Warudo is open, attempting to connect...', jsn, event, payload);
+ if (!connected()) {
+ try_connect();
+ }
});
$SD.onApplicationDidTerminate(({context,payload}) => {
- console.log('onApplicationDidTerminate', payload, payload.application);
- // our monitored app settings (in manifest.json) are case-sensitive
- // so we need to capitalize the app name to match
- const app = Utils.capitalize(Utils.getApplicationName(payload));
- // remove the terminated app from our running apps list
- MPLUGINDATA.runningApps = MPLUGINDATA.runningApps.filter(item => item !== app);
- // there should be a corresponding image in the images folder
- const img = `images/${payload.application}.png`;
- // overlay our terminated image on top of the terminated app image
- const arrImages = [img, 'images/terminated.png'];
- // try to load them
- Utils.loadImages(arrImages).then(images => {
- // if successfully loaded, merge them
- Utils.mergeImages(images).then(b64 => {
- // and update the key images
- MCONTEXTS.forEach(c => updateKeyImages(c, b64));
- setTimeout(() => {
- // after 1.5 seconds, reset the key images
- MCONTEXTS.forEach(c => updateKeyImages(c, `images/default.png`));
- }, 1500);
- });
- });
- // update the running apps list in the property inspector
- MCONTEXTS.forEach(updateRunningApps);
+ console.log('Warudo has quit, stopping any attempts at connecting...', payload, payload.application);
+ cancel_try_connect();
});
-
-/** HELPERS */
-
-const updateRunningApps = (context) => {
- console.log('updateRunningApps', MPLUGINDATA.runningApps);
- // $SD.sendToPropertyInspector(context, {runningApps: MPLUGINDATA.runningApps});
- sendToPropertyInspector(context, {runningApps: MPLUGINDATA.runningApps});
-};
-
-const updateKeyImages = (context, url) => {
- // console.log('updateKeyImages', context);
- $SD.setImage(context, url);
-};
-
-
-/** UTILITIES USED IN THIS DEMO */
-
-Utils.loadImagePromise = url =>
- new Promise(resolve => {
- const img = new Image();
- img.onload = () => resolve({url, img, status: 'ok'});
- img.onerror = () => resolve({url, img, status: 'error'});
- img.src = url;
- });
-
-Utils.loadImages = arrayOfUrls => Promise.all(arrayOfUrls.map(Utils.loadImagePromise));
-
-Utils.capitalize = str => {
- return str.charAt(0).toUpperCase() + str.slice(1);
-};
-
-Utils.getApplicationName = (payload) => {
- const isMac = $SD.appInfo.application.platform === 'mac';
- if(payload && payload.application) {
- return isMac ? payload.application.split('.').pop() : payload.application.split('.')[0];
- }
- return '';
-};
-
-Utils.mergeImages = (images = [], options = {width: 144, height: 144, format: 'image/png', quality: 1}, inCanvas) => new Promise(resolve => {
- const canvas = inCanvas && inCanvas instanceof HTMLCanvasElement
- ? inCanvas
- : document.createElement('canvas');
-
- const ctx = canvas.getContext('2d');
- ctx.globalCompositeOperation = 'source-over';
-
- resolve(Promise.all(images).then(images => {
- canvas.width = options.width || 144;
- canvas.height = options.height || 144;
-
- // Draw images to canvas
- images.forEach(image => {
- ctx.globalAlpha = image.opacity ? image.opacity : 1;
- return ctx.drawImage(image.img, image.x || 0, image.y || 0);
- });
-
- // Resolve all other data URIs sync
- return canvas.toDataURL(options.format, options.quality);
- }));
-});
-
-
diff --git a/warudo.streamdeck.sdPlugin/index_pi.html b/warudo.streamdeck.sdPlugin/index_pi.html
deleted file mode 100644
index 49f945d..0000000
--- a/warudo.streamdeck.sdPlugin/index_pi.html
+++ /dev/null
@@ -1,735 +0,0 @@
-
-
-
-
-
-
-
-
- Property Inspector Samples PI
-
-
-
-
-
-
-
-
-
-
-
-
-
Inputs
-
Text
-
Buttons
-
Selects
-
-
-
-
-
-
TEXTAREAS
-
-
-
Message with info-box
-
-
- 0/50
-
-
-
-
-
-
-
-
BUTTONS
-
-
-
-
-
-
- Button full width
-
-
-
-
-
-
-
-
-
SELECTS
-
-
-
Select
-
-
- Jane Doe
- Some Girl
- Yoko Hama
-
-
- John Doe
- Some Man
- Another Chap
-
-
-
-
-
-
-
Combo
-
- Jane Doe
- Some Guy
-
-
Click Me
-
-
-
-
-
MONITORED APPS
-
-
-
CANVAS
-
-
-
-
- Info
- To draw with the mouse, press/hold the alt key.
- To refresh the canvas, press shift and click.
-
-
-
-
CHECKBOXES & RADIO
-
-
-
-
-
-
-
-
-
COLOR
-
-
-
-
RANGE
-
-
-
-
-
Range (with label)
-
- 0
-
- 100
-
-
-
-
-
Range (with datalist)
-
- 0
-
-
- 25
- 50
- 75
-
- 100
-
-
-
-
-
-
-
Brightness
-
-
-
-
- 60
-
-
-
-
-
-
-
Meters
-
-
-
-
-
-
-
-
-
-
-
Meter (full)
-
-
-
-
-
-
-
-
-
-
-
Meter (with labels)
-
-
- 0
-
- 100
-
-
- -17
-
- 37.2
-
-
- Min
-
- Max
-
-
-
-
-
Progress
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Progress (with labels)
-
-
-
-
LISTS
-
-
-
List (unordered)
-
- Milk
- Bread
- Chocolate
- More chocolate
-
-
-
-
-
List (flex)
-
- Milk 1 liter
- Bread 1 slice
- Chocolate lots of
- More things...
-
-
-
-
-
-
-
List (single select)
-
- Milk
- Bread
- Chocolate
- More chocolate
-
-
-
-
-
-
-
List (multi select)
-
- Coke
- Sprite
- Juice
- Water
- Mocktail
- Smoothies
- Milk
- Tea
- Coffee
-
-
-
-
TABLES
-
-
-
Table (no-select)
-
- Table without selection
-
- One
- Two
- Three
-
-
- 1.00
- 2.00
- 3.00
-
-
- west
- east
- south
-
-
-
-
-
-
Table (single-select)
-
- Table with single selection
-
- Four
- Five
- Six
-
-
- 4.00
- 5.00
- 6.50
-
-
- west
- east
- south
-
-
-
-
-
-
Table (multi-select)
-
- Table with multi selection
-
- Seven
- Eight
- Nine
-
-
- 7.00
- 8.00
- 9.99
-
-
- west
- east
- south
-
-
-
-
-
DATE/TIME
-
-
-
-
-
-
-
-
-
Month (with list)
-
-
- 1967-07
- 2000-01
- 1999-12
- 2019-12
-
-
-
-
-
Week
-
-
- 2019-W01
- 2019-W02
- 2019-W05
- 2019-W24
- 2019-W52
-
-
-
-
-
-
-
-
-
-
FILE
-
-
-
Select File
-
-
- no file...
- Choose file...
-
-
-
-
GROUPS
-
-
-
Send A Message
-
-
-
Account ID
-
- Jane Doe
- Some Guy
- Another Chap
-
-
-
-
Message
-
-
- 123/456
-
-
-
-
-
-
-
-
-
-
-
Message
-
-
-
- This is some message
- Information:
- In this area you can type some information to your user.
- Click here
-
-
-
-
-
DETAILS
-
-
-
Details
-
- Wrapped Details
- If you like to show details aligned with other controls, you can simply wrap the details-item into a regular 'sdpi-item-value'
- In this case, details are auto-aligned with the sdpi-item-value controls above.
- ....
-
-
-
-
- More Info
- These samples are provided by Elgato Systems 'as is'.
- You are encouraged to use these samples (or this plugin) as a starter for your own ideas. (Just keep in mind to read the SDK-documentation and/or - at least - change the UUID in the manifest.json 😉 )
- To find out how things are working, just open the 'index_pi.html' included in this plugin and compare to what's shown in StreamDeck
- Scripts
- There's an index_pi.js file, which makes this sample interactive and sends changes to the Stream Deck plugin.
- This is a very convenient (although not optimized) way to communicate from Property Inspector to your plugin.
- If you think you have a better solution, please feel free to reach out and send your ideas.
- Other
- We hope you enjoy extending your Stream Deck and are pretty curious what you will do with it.
- Enjoy
- Your Elgato Gaming chaps
-
-
-
-
CAROUSEL
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
CONTEXT MENU
-
-
-
-
Button
-
Click to show the menu
-
-
-
-
-
Right click in this input field
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/warudo.streamdeck.sdPlugin/js/contextmenu.js b/warudo.streamdeck.sdPlugin/js/contextmenu.js
deleted file mode 100644
index 33fde9e..0000000
--- a/warudo.streamdeck.sdPlugin/js/contextmenu.js
+++ /dev/null
@@ -1,56 +0,0 @@
-var contextMenuClassName = "context-menu";
-var contextMenuItemClassName = "context-menu__item";
-var contextMenuLinkClassName = "context-menu__link";
-var contextMenuActive = "context-menu--active";
-
-var triggerItemClassName = "context-menu__trigger";
-/**
-* Turns the custom context menu on.
-*/
-function toggleMenuOn(contextMenu) {
- if( !contextMenu.classList.contains(contextMenuActive)){
- contextMenu.classList.add( contextMenuActive );
- }
-}
-
-/**
-* Turns the custom context menu off.
-*/
-function toggleMenuOff(contextMenu) {
- if (contextMenu.classList.contains(contextMenuActive)){
- contextMenu.classList.remove( contextMenuActive );
- }
-}
-
-
-function positionMenu(menu, xPos, yPos){
- menuWidth = menu.offsetWidth + 4;
- menuHeight = menu.offsetHeight + 4;
-
- windowWidth = window.innerWidth;
- windowHeight = window.innerHeight;
-
- if ( (windowWidth - xPos) < menuWidth ) {
- menu.style.left = windowWidth - menuWidth + "px";
- } else {
- menu.style.left = xPos + "px";
- }
-
- if ( (windowHeight - yPos) < menuHeight ) {
- menu.style.top = windowHeight - menuHeight + "px";
- } else {
- menu.style.top = yPos + "px";
- }
-}
-
-function openContextMenu(contextMenuId, xPos, yPos){
- console.log("openContextMenu called");
- var contextMenu = document.getElementById(contextMenuId);
-
- toggleMenuOn(contextMenu);
- positionMenu(contextMenu, xPos, yPos);
-
- document.addEventListener('click', function(){
- toggleMenuOff(contextMenu);
- }, true);
-}
diff --git a/warudo.streamdeck.sdPlugin/js/index_pi.js b/warudo.streamdeck.sdPlugin/js/index_pi.js
deleted file mode 100644
index 4a32bf0..0000000
--- a/warudo.streamdeck.sdPlugin/js/index_pi.js
+++ /dev/null
@@ -1,663 +0,0 @@
-///
-///
-///
-
-console.log('Property Inspector loaded', $PI);
-
-// register a callback for the 'connected' event
-// this is all you need to communicate with the plugin and the StreamDeck software
-$PI.onConnected(jsn => {
- console.log('Property Inspector connected', jsn);
- initPropertyInspector();
- console.log(jsn.actionInfo.payload.settings);
- Object.entries(jsn.actionInfo.payload.settings).forEach(([key, value]) => {
- console.log('setting', key, value);
- const el = document.getElementById(key);
- if(el) {
- el.value = value;
- }
- });
-
- let actionUUID = $PI.actionInfo.action;
- // register a callback for the 'sendToPropertyInspector' event
- $PI.onSendToPropertyInspector(actionUUID, jsn => {
- console.log('onSendToPropertyInspector', jsn);
- sdpiCreateList(document.querySelector('#runningAppsContainer'), {
- id: 'runningAppsID',
- label: 'Running Apps',
- value: jsn.payload.runningApps,
- type: 'list',
- selectionType: 'no-select'
- });
- });
-});
-
-
-/**
-this sample plugin activates all of its controls in code
-so we need to wait for the DOM to be ready
-and then we can initialize the controls
-You can also simply add the controls to the HTML and then
-use the 'sendToPlugin' callback to send the desired values to the plugin
-example:
-
-*
-To try that, simply remove the 'initPropertyInspector' call above (or put a comment in front of it) and
-type something into the 'Name' field. You should see the 'changed' message in the console of the plugin.
-*/
-
-
-// this is called by the 'Name' input field
-const changed = () => {
- console.log('changed', event, event.target, event.target.value);
- // the value of the input field is saved to settings
- $PI.setSettings({[event.target.id]: event.target.value});
- // the value of the input field is also sent to the plugin
- // which is not needed, because the plugin already received
- // the value via the 'setSettings' call
- // This is mostly used to send values to the plugin
- // that are not saved in the settings
- $PI.sendToPlugin({key: event.target.id, value: event.target.value});
-};
-
-// this is called by some buttons in the HTML
-const clicked = () => {
- console.log('clicked', event?.target?.id, event?.target?.value);
-};
-
-
-/**
- * TABS
- * ----
- *
- * This will make the tabs interactive:
- * - clicking on a tab will make it active
- * - clicking on a tab will show the corresponding content
- * - clicking on a tab will hide the content of all other tabs
- * - a tab must have the class "tab"
- * - a tab must have a data-target attribute that points to the id of the content
- * - the content must have the class "tab-content"
- * - the content must have an id that matches the data-target attribute of the tab
- * - the content must have a data-tab attribute that matches the data-target attribute of the tab
- * Inputs
- * Text
- * a complete tab-example can be found in the index.html
-
-
- * You can use the code below to activate the tabs (`activateTabs` and `clickTab` are required)
- */
-
-function activateTabs(activeTab) {
- const allTabs = Array.from(document.querySelectorAll('.tab'));
- let activeTabEl = null;
- allTabs.forEach((el, i) => {
- el.onclick = () => clickTab(el);
- if(el.dataset?.target === activeTab) {
- activeTabEl = el;
- }
- });
- if(activeTabEl) {
- clickTab(activeTabEl);
- } else if(allTabs.length) {
- clickTab(allTabs[0]);
- }
-}
-
-function clickTab(clickedTab) {
- const allTabs = Array.from(document.querySelectorAll('.tab'));
- allTabs.forEach((el, i) => el.classList.remove('selected'));
- clickedTab.classList.add('selected');
- activeTab = clickedTab.dataset?.target;
- allTabs.forEach((el, i) => {
- if(el.dataset.target) {
- const t = document.querySelector(el.dataset.target);
- if(t) {
- t.style.display = el == clickedTab ? 'block' : 'none';
- }
- }
- });
-}
-
-/**
- * DEMO
- * ----
- *
- * This initializes all elements found in the PI and makes them
- * interactive. It will also send the values to the plugin.
- *
- * */
-
-function initPropertyInspector(initDelay) {
- prepareDOMElements(document);
- demoCanvas();
- /** expermimental carousel is not part of the DOM
- * so let the DOM get constructed first and then
- * inject the carousel */
- setTimeout(function() {
- initCarousel();
- initToolTips();
- dragTest();
-
- }, initDelay || 100);
-}
-
-// our method to pass values to the plugin
-function sendValueToPlugin(value, param) {
- $PI.sendToPlugin({[param]: value});
-}
-
-/** CREATE INTERACTIVE HTML-DOM
- * where elements can be clicked or act on their 'change' event.
- * Messages are then processed using the 'handleSdpiItemChange' method below.
- */
-function prepareDOMElements(baseElement) {
- const onchangeevt = 'onchange'; // 'oninput'; // change this, if you want interactive elements act on any change, or while they're modified
-
- baseElement = baseElement || document;
- Array.from(baseElement.querySelectorAll('.sdpi-item-value')).forEach(
- (el, i) => {
- const elementsToClick = [
- 'BUTTON',
- 'OL',
- 'UL',
- 'TABLE',
- 'METER',
- 'PROGRESS',
- 'CANVAS'
- ].includes(el.tagName);
- const evt = elementsToClick ? 'onclick' : onchangeevt || 'onchange';
-
- /** Look for combinations, where we consider the span as label for the input
- * we don't use `labels` for that, because a range could have 2 labels.
- */
- const inputGroup = el.querySelectorAll('input + span');
- if(inputGroup.length === 2) {
- const offs = inputGroup[0].tagName === 'INPUT' ? 1 : 0;
- inputGroup[offs].innerText = inputGroup[1 - offs].value;
- inputGroup[1 - offs]['oninput'] = function() {
- inputGroup[offs].innerText = inputGroup[1 - offs].value;
- };
- }
- /** We look for elements which have an 'clickable' attribute
- * we use these e.g. on an 'inputGroup' () to adjust the value of
- * the corresponding range-control
- */
- Array.from(el.querySelectorAll('.clickable')).forEach(
- (subel, subi) => {
- subel['onclick'] = function(e) {
- handleSdpiItemChange(e.target, subi);
- };
- }
- );
- /** Just in case the found HTML element already has an input or change - event attached,
- * we clone it, and call it in the callback, right before the freshly attached event
- */
- const cloneEvt = el[evt];
- el[evt] = function(e) {
- if(cloneEvt) cloneEvt();
- handleSdpiItemChange(e.target, i);
- };
- }
- );
-
- /**
- * You could add a 'label' to a textares, e.g. to show the number of charactes already typed
- * or contained in the textarea. This helper updates this label for you.
- */
- baseElement.querySelectorAll('textarea').forEach((e) => {
- const maxl = e.getAttribute('maxlength');
- e.targets = baseElement.querySelectorAll(`[for='${e.id}']`);
- if(e.targets.length) {
- let fn = () => {
- for(let x of e.targets) {
- x.textContent = maxl ? `${e.value.length}/${maxl}` : `${e.value.length}`;
- }
- };
- fn();
- e.onkeyup = fn;
- }
- });
-
- baseElement.querySelectorAll('[data-open-url]').forEach(e => {
- const value = e.getAttribute('data-open-url');
- if(value) {
- e.onclick = () => {
- let path;
- if(value.indexOf('http') !== 0) {
- path = document.location.href.split('/');
- path.pop();
- path.push(value.split('/').pop());
- path = path.join('/');
- } else {
- path = value;
- }
- $SD.api.openUrl($SD.uuid, path);
- };
- } else {
- console.log(`${value} is not a supported url`);
- }
- });
-}
-
-function handleSdpiItemChange(e, idx) {
-
- /** Following items are containers, so we won't handle clicks on them */
-
- if(['OL', 'UL', 'TABLE'].includes(e.tagName)) {
- return;
- }
-
- /** SPANS are used inside a control as 'labels'
- * If a SPAN element calls this function, it has a class of 'clickable' set and is thereby handled as
- * clickable label.
- */
-
- if(e.tagName === 'SPAN') {
- const inp = e.parentNode.querySelector('input');
- var tmpValue;
-
- // if there's no attribute set for the span, try to see, if there's a value in the textContent
- // and use it as value
- if(!e.hasAttribute('value')) {
- tmpValue = Number(e.textContent);
- if(typeof tmpValue === 'number' && tmpValue !== null) {
- e.setAttribute('value', 0 + tmpValue); // this is ugly, but setting a value of 0 on a span doesn't do anything
- e.value = tmpValue;
- }
- } else {
- tmpValue = Number(e.getAttribute('value'));
- }
-
- if(inp && tmpValue !== undefined) {
- inp.value = tmpValue;
- } else return;
- }
-
- const selectedElements = [];
- const isList = ['LI', 'OL', 'UL', 'DL', 'TD'].includes(e.tagName);
- const sdpiItem = e.closest('.sdpi-item');
- const sdpiItemGroup = e.closest('.sdpi-item-group');
- let sdpiItemChildren = isList
- ? sdpiItem.querySelectorAll(e.tagName === 'LI' ? 'li' : 'td')
- : sdpiItem.querySelectorAll('.sdpi-item-child > input');
-
- if(isList) {
- const siv = e.closest('.sdpi-item-value');
- if(!siv.classList.contains('multi-select')) {
- for(let x of sdpiItemChildren) x.classList.remove('selected');
- }
- if(!siv.classList.contains('no-select')) {
- e.classList.toggle('selected');
- }
- }
-
- if(sdpiItemChildren.length && ['radio', 'checkbox'].includes(sdpiItemChildren[0].type)) {
- e.setAttribute('_value', e.checked); //'_value' has priority over .value
- }
- if(sdpiItemGroup && !sdpiItemChildren.length) {
- for(let x of ['input', 'meter', 'progress']) {
- sdpiItemChildren = sdpiItemGroup.querySelectorAll(x);
- if(sdpiItemChildren.length) break;
- }
- }
-
- if(e.selectedIndex !== undefined) {
- if(e.tagName === 'SELECT') {
- sdpiItemChildren.forEach((ec, i) => {
- selectedElements.push({[ec.id]: ec.value});
- });
- }
- idx = e.selectedIndex;
- } else {
- sdpiItemChildren.forEach((ec, i) => {
- if(ec.classList.contains('selected')) {
- selectedElements.push(ec.textContent);
- }
- if(ec === e) {
- idx = i;
- selectedElements.push(ec.value);
- }
- });
- }
-
- const returnValue = {
- key: e.id && e.id.charAt(0) !== '_' ? e.id : sdpiItem.id,
- value: isList
- ? e.textContent
- : e.hasAttribute('_value')
- ? e.getAttribute('_value')
- : e.value
- ? e.type === 'file'
- ? decodeURIComponent(e.value.replace(/^C:\\fakepath\\/, ''))
- : e.value
- : e.getAttribute('value'),
- group: sdpiItemGroup ? sdpiItemGroup.id : false,
- index: idx,
- selection: selectedElements,
- checked: e.checked
- };
-
- /** Just simulate the original file-selector:
- * If there's an element of class '.sdpi-file-info'
- * show the filename there
- */
- if(e.type === 'file') {
- const info = sdpiItem.querySelector('.sdpi-file-info');
- if(info) {
- const s = returnValue.value.split('/').pop();
- info.textContent = s.length > 28
- ? s.substr(0, 10)
- + '...'
- + s.substr(s.length - 10, s.length)
- : s;
- }
- }
-
- sendValueToPlugin(returnValue, 'sdpi_collection');
-}
-
-function updateKeyForDemoCanvas(cnv) {
- sendValueToPlugin({
- key: 'your_canvas',
- value: cnv.toDataURL()
- }, 'sdpi_collection');
-}
-
-/** UTILITIES */
-/** Helper function to construct a list of running apps
- * from a template string.
- * -> information about running apps is received from the plugin
- */
-
-function sdpiCreateList(el, obj, cb) {
- if(el) {
- el.style.display = obj.value.length ? 'block' : 'none';
- Array.from(document.querySelectorAll(`.${el.id}`)).forEach((subel, i) => {
- subel.style.display = obj.value.length ? 'flex' : 'none';
- });
- if(obj.value.length) {
- el.innerHTML = `
-
${obj.label || ''}
-
- ${obj.value.map(e => `${e} `).join('')}
-
-
`;
- setTimeout(function() {
- prepareDOMElements(el);
- if(cb) cb();
- }, 10);
- return;
- }
- }
- if(cb) cb();
-};
-
-/** Quick utility to return a random color.
- * If the randomly generated string is less than 6 characters
- * pad it with '0'
- */
-function randomColor(prefix) {
- return (prefix || '') + (((1 << 24) * Math.random()) | 0).toString(16).padStart(6, 0); // just a random color padded to 6 characters
-}
-
-/** CANVAS DEMO */
-
-function demoCanvas() {
- const touchDevice = (('ontouchstart' in document.documentElement) && (navigator.platform != 'Win32'));
- const evtDown = touchDevice ? 'touchstart' : 'mousedown';
- const evtMove = touchDevice ? 'touchmove' : 'mousemove';
- const evtEnd = touchDevice ? 'touchend' : 'mouseup';
- const evtX = touchDevice ? 'pageX' : 'clientX';
- const evtY = touchDevice ? 'pageY' : 'clientY';
-
- const cnv = document.querySelector('canvas');
- if(!cnv) return;
- const ctx = cnv.getContext('2d');
- if(!ctx) return;
- function drawRandomCanvas() {
- const rad = cnv.height / 4;
- const cX = Math.random() * cnv.width;
- const cY = Math.random() * cnv.height;
-
- const grad = ctx.createLinearGradient(0, 0, 0, 170);
- const clr = randomColor();
- grad.addColorStop(0, fadeColor(clr, -100));
- grad.addColorStop(0.5, '#' + clr);
- grad.addColorStop(1, fadeColor(clr, 100));
- ctx.fillStyle = grad;
-
- // ctx.fillStyle = randomColor();
- ctx.fillRect(0, 0, cnv.width, cnv.height);
- ctx.beginPath();
- ctx.arc(cX, cY, rad, 0, 2 * Math.PI, false);
- ctx.fillStyle = '#' + randomColor();
- ctx.fill();
- ctx.lineWidth = 5;
- ctx.strokeStyle = '#' + randomColor();
- ctx.stroke();
- }
-
- drawRandomCanvas();
-
- const pos = {x: 0, y: 0};
-
- var el = document.querySelector('.sdpi-wrapper');
- cnv.addEventListener(evtDown, function(e) {
- if(e.shiftKey) {
- drawRandomCanvas();
- return;
- }
- pos.x = e[evtX] - cnv.offsetLeft + el.scrollLeft;
- pos.y = e[evtY] - cnv.offsetTop + el.scrollTop;
- });
-
- cnv.addEventListener(evtEnd, function(e) {
- e.target.value = cnv.toDataURL();
- });
-
- cnv.addEventListener(evtMove, function(e) {
- if(!touchDevice) {
- if(!e.altKey || e.buttons !== 1) return;
- }
- e.preventDefault();
-
- ctx.beginPath();
- ctx.lineWidth = 5;
- ctx.lineCap = 'round';
- ctx.strokeStyle = '#061261';
- ctx.moveTo(pos.x, pos.y); // from
- pos.x = e[evtX] - cnv.offsetLeft + el.scrollLeft;
- pos.y = e[evtY] - cnv.offsetTop + el.scrollTop;
- ctx.lineTo(pos.x, pos.y); // to
- ctx.stroke();
- });
-
- // updateKeyForDemoCanvas(cnv, cnv);
-}
-
-/** EXPERIMENTAL CAROUSEL */
-
-function initCarousel() {
- document.querySelectorAll('.sdpi-item [type=carousel]').forEach((e, i, a) => {
- var m = e.querySelector('img');
- e.data = {
- currentOffset: 0,
- visibleCards: 3,
- scrollDistance: m ? m.clientWidth + 10 : 70,
- numCards: e.querySelectorAll('.card-carousel--card').length,
- leftNav: e.querySelectorAll('.card-carousel--nav__left'),
- rightNav: e.querySelectorAll('.card-carousel--nav__right'),
- atStart: true,
- atEnd: false
- };
-
- e.end = function() {
- return e.data.currentOffset <= (e.data.scrollDistance * -1) * (e.data.numCards - e.data.visibleCards);
- };
-
- const cards = e.querySelector('.card-carousel-cards');
-
- e.move = function(direction) {
- if(direction === 1 && !this.data.atEnd) {
- this.data.currentOffset -= this.data.scrollDistance;
- } else if(direction === -1 && !this.data.atStart) {
- this.data.currentOffset += this.data.scrollDistance;
- }
-
- if(cards) {
- cards.setAttribute('style', `transform:translateX(${this.data.currentOffset}px)`);
- this.data.atStart = this.data.currentOffset === 0;
- this.data.atEnd = this.end();
- this.data.leftNav.forEach((ctl) => {
- if(!this.data.atStart) ctl.removeAttribute('disabled');
- else ctl.setAttribute('disabled', this.data.atStart);
- });
- this.data.rightNav.forEach((ctl) => {
- if(!this.data.atEnd) ctl.removeAttribute('disabled');
- else ctl.setAttribute('disabled', this.data.atEnd);
- });
- }
- };
-
- e.data.leftNav.forEach((nl) => {
- nl.onclick = function() {
- e.move(-1);
- };
- });
-
- e.data.rightNav.forEach((nl) => {
- nl.onclick = function() {
- e.move(1);
- };
- });
-
- e.querySelectorAll('.card-carousel--card').forEach((crd, idx) => {
- crd.onclick = function(evt) {
- handleSdpiItemChange(crd, idx);
- };
- });
- });
-};
-
-
-function drag_start(event) {
- /**
- * In PI Samples the title-attribute is extracted to css and set
- * to an absolute position (at the bottom of the PI).
- * Since it is still part of the HTML-node, we just remove the title
- * attribute (otherwise the node will get extended so it includes the title
- * node too.)
- */
-
- const t = event.target.getAttribute('title');
- // event.target.removeAttribute('title');
- // temporarily remove draggable attribute before copying
- event.target.removeAttribute('draggable');
- event.dataTransfer.effectAllowed = "all";
- var dataList = event.dataTransfer.items;
- /**
- * the following helper just formats the HTML, so the output
- * looks a bit nicer.
- */
- const prettifiedHTMLString = prettifyHTML(event.target.outerHTML);
-
- // add draggable attribute after copying
- event.target.setAttribute('draggable', "true");
- if(t) event.target.setAttribute('title', t);
-
- /**
- * Finally add the prettified string to the dragObjs data-container:
- */
- dataList.add(prettifiedHTMLString, "text/plain");
-
-}
-
-
-function dragTest() {
- const els = document.querySelectorAll('.sdpi-item');
- Array.from(els).forEach((e, i) => {
- //subel.style.display = obj.value.length ? 'flex' : 'none';
- e.addEventListener("dragstart", drag_start, false);
- e.setAttribute('draggable', "true");
- // e.ondragstart="drag_start(event)";
-
- });
-}
-
-function prettifyHTML(htmlStr) {
- const div = document.createElement('div');
- div.innerHTML = htmlStr.trim();
- return prettify(div, 0).innerHTML;
-}
-
-function prettify(node, level) {
-
- const spacesBefore = new Array(level++ + 1).join(' ');
- const spacesAfter = new Array(level - 1).join(' ');
- let textNode;
-
- Object.values(node.children).map(e => {
- textNode = document.createTextNode('\n' + spacesBefore);
- node.insertBefore(textNode, e);
- prettify(e, level);
- if(node.lastElementChild == e) {
- textNode = document.createTextNode('\n' + spacesAfter);
- node.appendChild(textNode);
- }
- });
-
- return node;
-}
-
-function rangeToPercent(value, min, max) {
- return (value / (max - min));
-};
-function initToolTips() {
- const tooltip = document.querySelector('.sdpi-info-label');
- const arrElements = document.querySelectorAll('.floating-tooltip');
- arrElements.forEach((e, i) => {
- initToolTip(e, tooltip);
- });
-}
-
-function initToolTip(element, tooltip) {
-
- const tw = tooltip.getBoundingClientRect().width;
- const suffix = element.getAttribute('data-suffix') || '';
-
- const fn = () => {
- const elementRect = element.getBoundingClientRect();
- const w = elementRect.width - tw / 2;
- const percnt = rangeToPercent(element.value, element.min, element.max);
- tooltip.textContent = suffix != "" ? `${element.value} ${suffix}` : String(element.value);
- tooltip.style.left = `${elementRect.left + Math.round(w * percnt) - tw / 4}px`;
- tooltip.style.top = `${elementRect.top - 32}px`;
- };
-
- if(element) {
- element.addEventListener('mouseenter', function() {
- tooltip.classList.remove('hidden');
- tooltip.classList.add('shown');
- fn();
- }, false);
-
- element.addEventListener('mouseout', function() {
- tooltip.classList.remove('shown');
- tooltip.classList.add('hidden');
- fn();
- }, false);
- element.addEventListener('input', fn, false);
- }
-}
-
-
-activateTabs();
diff --git a/warudo.streamdeck.sdPlugin/libs b/warudo.streamdeck.sdPlugin/libs
new file mode 160000
index 0000000..7d2ba3c
--- /dev/null
+++ b/warudo.streamdeck.sdPlugin/libs
@@ -0,0 +1 @@
+Subproject commit 7d2ba3ce41620dbb6c2f2a69a158224f6d95ef22
diff --git a/warudo.streamdeck.sdPlugin/libs/.prettierrc b/warudo.streamdeck.sdPlugin/libs/.prettierrc
deleted file mode 100644
index b00520f..0000000
--- a/warudo.streamdeck.sdPlugin/libs/.prettierrc
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "useTabs": true,
- "singleQuote": true,
- "printWidth": 100
-}
diff --git a/warudo.streamdeck.sdPlugin/libs/assets/caret.svg b/warudo.streamdeck.sdPlugin/libs/assets/caret.svg
deleted file mode 100644
index 932fff4..0000000
--- a/warudo.streamdeck.sdPlugin/libs/assets/caret.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/warudo.streamdeck.sdPlugin/libs/assets/caret_closed.svg b/warudo.streamdeck.sdPlugin/libs/assets/caret_closed.svg
deleted file mode 100644
index 2678e69..0000000
--- a/warudo.streamdeck.sdPlugin/libs/assets/caret_closed.svg
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/warudo.streamdeck.sdPlugin/libs/assets/check.png b/warudo.streamdeck.sdPlugin/libs/assets/check.png
deleted file mode 100644
index b5e9e62..0000000
Binary files a/warudo.streamdeck.sdPlugin/libs/assets/check.png and /dev/null differ
diff --git a/warudo.streamdeck.sdPlugin/libs/assets/check.svg b/warudo.streamdeck.sdPlugin/libs/assets/check.svg
deleted file mode 100644
index bbfec96..0000000
--- a/warudo.streamdeck.sdPlugin/libs/assets/check.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/warudo.streamdeck.sdPlugin/libs/assets/elg_calendar.svg b/warudo.streamdeck.sdPlugin/libs/assets/elg_calendar.svg
deleted file mode 100644
index 851cc91..0000000
--- a/warudo.streamdeck.sdPlugin/libs/assets/elg_calendar.svg
+++ /dev/null
@@ -1,25 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/warudo.streamdeck.sdPlugin/libs/assets/elg_calendar_inv.svg b/warudo.streamdeck.sdPlugin/libs/assets/elg_calendar_inv.svg
deleted file mode 100644
index 4e47b6e..0000000
--- a/warudo.streamdeck.sdPlugin/libs/assets/elg_calendar_inv.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
diff --git a/warudo.streamdeck.sdPlugin/libs/assets/rcheck.svg b/warudo.streamdeck.sdPlugin/libs/assets/rcheck.svg
deleted file mode 100644
index c01a443..0000000
--- a/warudo.streamdeck.sdPlugin/libs/assets/rcheck.svg
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/warudo.streamdeck.sdPlugin/libs/css/sdpi.css b/warudo.streamdeck.sdPlugin/libs/css/sdpi.css
deleted file mode 100644
index 8b79294..0000000
--- a/warudo.streamdeck.sdPlugin/libs/css/sdpi.css
+++ /dev/null
@@ -1,1726 +0,0 @@
-:root {
- --sdpi-bgcolor: #2D2D2D;
- --sdpi-background: #3D3D3D;
- --sdpi-color: #d8d8d8;
- --sdpi-bordercolor: #3a3a3a;
- --sdpi-linecolor: #454545;
- --sdpi-buttonbordercolor: #969696;
- --sdpi-borderradius: 0px;
- --sdpi-width: 224px;
- --sdpi-fontweight: 600;
- --sdpi-letterspacing: -0.25pt;
- --sdpi-tab-color: #969696;
- --sdpi-tab-font-size: 9pt;
-}
-
-html {
- --sdpi-bgcolor: #2D2D2D;
- --sdpi-background: #3D3D3D;
- --sdpi-color: #d8d8d8;
- --sdpi-bordercolor: #3a3a3a;
- --sdpi-buttonbordercolor: #969696;
- --sdpi-borderradius: 0px;
- --sdpi-width: 224px;
- --sdpi-fontweight: 600;
- --sdpi-letterspacing: -0.25pt;
- height: 100%;
- width: 100%;
- overflow: hidden;
- touch-action: none;
-}
-
-html,
-body {
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
- font-size: 9pt;
- background-color: var(--sdpi-bgcolor);
- color: #9a9a9a;
-}
-
-body {
- height: 100%;
- padding: 0;
- overflow-x: hidden;
- overflow-y: auto;
- margin: 0;
- -webkit-overflow-scrolling: touch;
- -webkit-text-size-adjust: 100%;
- -webkit-font-smoothing: antialiased;
-}
-
-mark {
- background-color: var(--sdpi-bgcolor);
- color: var(--sdpi-color);
-}
-
-hr,
-hr2 {
- -webkit-margin-before: 1em;
- -webkit-margin-after: 1em;
- border-style: none;
- background: var(--sdpi-background);
- height: 1px;
-}
-
-hr2,
-.sdpi-heading {
- display: flex;
- flex-basis: 100%;
- align-items: center;
- color: inherit;
- font-size: 9pt;
- margin: 8px 0px;
-}
-
-.sdpi-heading::before,
-.sdpi-heading::after {
- content: "";
- flex-grow: 1;
- background: var(--sdpi-background);
- height: 1px;
- font-size: 0px;
- line-height: 0px;
- margin: 0px 16px;
-}
-
-hr2 {
- height: 2px;
-}
-
-hr,
-hr2 {
- margin-left: 16px;
- margin-right: 16px;
-}
-
-.sdpi-item-value,
-option,
-input,
-select,
-button {
- font-size: 10pt;
- font-weight: var(--sdpi-fontweight);
- letter-spacing: var(--sdpi-letterspacing);
-}
-
-.sdpi-item-value> :last-of-type,
-.sdpi-item-value:last-child {
- margin-bottom: 4px;
-}
-
-.win .sdpi-item-value,
-.win option,
-.win input,
-.win select,
-.win button {
- font-size: 11px;
- font-style: normal;
- letter-spacing: inherit;
- font-weight: 100;
-}
-
-.win button {
- font-size: 12px;
-}
-
-::-webkit-progress-value,
-meter::-webkit-meter-optimum-value {
- border-radius: 2px;
- /* background: linear-gradient(#ccf, #99f 20%, #77f 45%, #77f 55%, #cdf); */
-}
-
-::-webkit-progress-bar,
-meter::-webkit-meter-bar {
- border-radius: 3px;
- background: var(--sdpi-background);
-}
-
-::-webkit-progress-bar:active,
-meter::-webkit-meter-bar:active {
- border-radius: 3px;
- background: #222222;
-}
-
-::-webkit-progress-value:active,
-meter::-webkit-meter-optimum-value:active {
- background: #99f;
-}
-
-progress,
-progress.sdpi-item-value {
- min-height: 5px !important;
- height: 5px;
- background-color: #303030;
-}
-
-progress {
- margin-top: 8px !important;
- margin-bottom: 8px !important;
-}
-
-.full progress,
-progress.full {
- margin-top: 3px !important;
-}
-
-::-webkit-progress-inner-element {
- background-color: transparent;
-}
-
-
-.sdpi-item[type="progress"] {
- margin-top: 4px !important;
- margin-bottom: 12px;
- min-height: 15px;
-}
-
-.sdpi-item-child.full:last-child {
- margin-bottom: 4px;
-}
-
-
-/* TABS */
-
-.tabs {
- /**
- * Setting display to flex makes this container lay
- * out its children using flexbox, the exact same
- * as in the above "Stepper input" example.
- */
- display: flex;
- border-bottom: 1px solid rgba(255, 255, 255, 0.0);
- flex-wrap: nowrap;
- white-space: nowrap;
- overflow-x: auto;
- text-transform: capitalize;
- background-color: transparent;
-}
-
-.tabs::-webkit-scrollbar {
- height: 4px;
- display: none;
-}
-
-.tabs::-webkit-scrollbar-track {
- -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
- box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
- border-radius: 8px;
-}
-
-.tabs::-webkit-scrollbar-thumb {
- background-color: #444;
- outline: 1px solid #444;
- border-radius: 8px;
-}
-
-.tab-separator {
- margin-left: 100px;
- max-width: 234px;
- margin-bottom: 20px;
- margin-top: -3px;
-}
-
-.tab {
- cursor: pointer;
- padding: 6px 16px;
- color: var(--sdpi-tab-color);
- font-size: var(--sdpi-tab-font-size);
- font-weight: var(--title-font-weight);
- background-color: rgba(0, 0, 0, 0.1);
- margin: 1px;
- border-top-left-radius: 5px;
- border-top-right-radius: 5px;
- border: 1px solid rgba(255, 255, 255, 0.1);
- border-bottom: 1px solid var(--sdpi-linecolor);
- -webkit-user-select: none;
- user-select: none;
-}
-
-.tab-container {
- margin-top: -14px;
-}
-
-.tab-container>hr {
- margin-left: 100px;
- max-width: 234px;
-}
-
-.tabs+hr {
- margin-left: 0px;
- max-width: 234px;
- margin-top: -6px;
-}
-
-.tab.selected {
- color: white;
- background-color: var(--sdpi-bgcolor);
- border-bottom: 1px solid rgba(255, 255, 255, 0.0);
-}
-
-.sdpi-item.tabgroup {
- margin-top: 0px;
-}
-
-.istab {
- background-color: rgba(0, 0, 0, 0.2);
- margin-bottom: 20px;
- padding: 4px;
-}
-
-select {
- -webkit-appearance: none;
- -moz-appearance: none;
- -o-appearance: none;
- appearance: none;
- background: url(../assets/caret.svg) no-repeat 97% center;
-}
-
-label.sdpi-file-label,
-input[type="button"],
-input[type="submit"],
-input[type="reset"],
-input[type="file"],
-input[type=file]::-webkit-file-upload-button,
-button,
-select {
- color: var(--sdpi-color);
- border: 1pt solid #303030;
- font-size: 8pt;
- background-color: var(--sdpi-background);
- border-radius: var(--sdpi-borderradius);
-}
-
-label.sdpi-file-label,
-input[type="button"],
-input[type="submit"],
-input[type="reset"],
-input[type="file"],
-input[type=file]::-webkit-file-upload-button,
-button {
- border: 1pt solid var(--sdpi-buttonbordercolor);
- border-radius: var(--sdpi-borderradius);
- border-color: var(--sdpi-buttonbordercolor);
- min-height: 23px !important;
- height: 23px !important;
- margin-right: 8px;
-}
-
-input[type=number]::-webkit-inner-spin-button,
-input[type=number]::-webkit-outer-spin-button {
- -webkit-appearance: none;
- margin: 0;
-}
-
-input[type="file"] {
- border-radius: var(--sdpi-borderradius);
- max-width: 220px;
-}
-
-option {
- height: 1.5em;
- padding: 4px;
-}
-
-/* SDPI */
-
-.sdpi-wrapper {
- overflow-x: hidden;
- height: 100%;
-}
-
-.sdpi-item {
- display: flex;
- flex-direction: row;
- min-height: 32px;
- align-items: center;
- margin-top: 2px;
- max-width: 344px;
- -webkit-user-drag: none;
-}
-
-.sdpi-item:first-child {
- margin-top: -1px;
-}
-
-.sdpi-item:first-of-type {
- margin-top: 2px;
-}
-
-.sdpi-item[type="radio"]:first-of-type,
-.sdpi-item[type="checkbox"]:first-of-type {
- margin-top: -4px;
-}
-
-.sdpi-item:last-child {
- margin-bottom: 0px;
-}
-
-.sdpi-item>*:not(.sdpi-item-label):not(meter):not(details):not(canvas) {
- min-height: 26px;
-}
-
-.sdpi-item>*:not(.sdpi-item-label.empty):not(meter) {
- min-height: 26px;
-}
-
-.sdpi-item>input {
- padding: 0px 4px;
-}
-
-.sdpi-item-group {
- padding: 0 !important;
-}
-
-meter.sdpi-item-value {
- margin-left: 6px;
-}
-
-.sdpi-item[type="group"] {
- display: block;
- margin-top: 12px;
- margin-bottom: 12px;
- /* border: 1px solid white; */
- flex-direction: unset;
- text-align: left;
-}
-
-.sdpi-item[type="group"]>.sdpi-item-label,
-.sdpi-item[type="group"].sdpi-item-label {
- width: 96%;
- text-align: left;
- font-weight: 700;
- margin-bottom: 4px;
- padding-left: 4px;
-}
-
-dl,
-ul,
-ol {
- -webkit-margin-before: 0px;
- -webkit-margin-after: 4px;
- -webkit-padding-start: 1em;
- max-height: 90px;
- overflow-y: scroll;
- cursor: pointer;
- user-select: none;
-}
-
-table.sdpi-item-value,
-dl.sdpi-item-value,
-ul.sdpi-item-value,
-ol.sdpi-item-value {
- -webkit-margin-before: 4px;
- -webkit-margin-after: 8px;
- -webkit-padding-start: 1em;
- width: var(--sdpi-width);
- text-align: center;
-}
-
-table>caption {
- margin: 2px;
-}
-
-.list,
-.sdpi-item[type="list"] {
- align-items: baseline;
-}
-
-.sdpi-item-label {
- text-align: right;
- flex: none;
- width: 94px;
- padding-right: 5px;
- font-weight: 600;
- -webkit-user-select: none;
- line-height: 24px;
- margin-left: -1px;
-}
-
-.win .sdpi-item-label,
-.sdpi-item-label>small {
- font-weight: normal;
-}
-
-.sdpi-item-label:after {
- content: ": ";
-}
-
-.sdpi-item-label.empty:after {
- content: "";
-}
-
-.sdpi-test,
-.sdpi-item-value {
- flex: 1 0 0;
- /* flex-grow: 1;
- flex-shrink: 0; */
- margin-right: 14px;
- margin-left: 4px;
- justify-content: space-evenly;
-}
-
-canvas.sdpi-item-value {
- max-width: 144px;
- max-height: 144px;
- width: 144px;
- height: 144px;
- margin: 0 auto;
- cursor: pointer;
-}
-
-input.sdpi-item-value {
- margin-left: 5px;
-}
-
-.sdpi-item-value button,
-button.sdpi-item-value {
- margin-left: 6px;
- margin-right: 14px;
-}
-
-.sdpi-item-value.range {
- margin-left: 0px;
-}
-
-table,
-dl.sdpi-item-value,
-ul.sdpi-item-value,
-ol.sdpi-item-value,
-.sdpi-item-value>dl,
-.sdpi-item-value>ul,
-.sdpi-item-value>ol {
- list-style-type: none;
- list-style-position: outside;
- margin-left: -4px;
- margin-right: -4px;
- padding: 4px;
- border: 1px solid var(--sdpi-bordercolor);
-}
-
-dl.sdpi-item-value,
-ul.sdpi-item-value,
-ol.sdpi-item-value,
-.sdpi-item-value>ol {
- list-style-type: none;
- list-style-position: inside;
- margin-left: 5px;
- margin-right: 12px;
- padding: 4px !important;
- display: flex;
- flex-direction: column;
-}
-
-.two-items li {
- display: flex;
-}
-
-.two-items li>*:first-child {
- flex: 0 0 50%;
- text-align: left;
-}
-
-.two-items.thirtyseventy li>*:first-child {
- flex: 0 0 30%;
-}
-
-ol.sdpi-item-value,
-.sdpi-item-value>ol[listtype="none"] {
- list-style-type: none;
-}
-
-ol.sdpi-item-value[type="decimal"],
-.sdpi-item-value>ol[type="decimal"] {
- list-style-type: decimal;
-}
-
-ol.sdpi-item-value[type="decimal-leading-zero"],
-.sdpi-item-value>ol[type="decimal-leading-zero"] {
- list-style-type: decimal-leading-zero;
-}
-
-ol.sdpi-item-value[type="lower-alpha"],
-.sdpi-item-value>ol[type="lower-alpha"] {
- list-style-type: lower-alpha;
-}
-
-ol.sdpi-item-value[type="upper-alpha"],
-.sdpi-item-value>ol[type="upper-alpha"] {
- list-style-type: upper-alpha;
-}
-
-ol.sdpi-item-value[type="upper-roman"],
-.sdpi-item-value>ol[type="upper-roman"] {
- list-style-type: upper-roman;
-}
-
-ol.sdpi-item-value[type="lower-roman"],
-.sdpi-item-value>ol[type="lower-roman"] {
- list-style-type: upper-roman;
-}
-
-tr:nth-child(even),
-.sdpi-item-value>ul>li:nth-child(even),
-.sdpi-item-value>ol>li:nth-child(even),
-li:nth-child(even) {
- background-color: rgba(0, 0, 0, .2)
-}
-
-td:hover,
-.sdpi-item-value>ul>li:hover:nth-child(even),
-.sdpi-item-value>ol>li:hover:nth-child(even),
-li:hover:nth-child(even),
-li:hover {
- background-color: rgba(255, 255, 255, .1);
-}
-
-td.selected,
-td.selected:hover,
-li.selected:hover,
-li.selected {
- color: white;
- background-color: #77f;
-}
-
-tr {
- border: 1px solid var(--sdpi-bordercolor);
-}
-
-td {
- border-right: 1px solid var(--sdpi-bordercolor);
- -webkit-user-select: none;
-}
-
-tr:last-child,
-td:last-child {
- border: none;
-}
-
-.sdpi-item-value.select,
-.sdpi-item-value>select {
- margin-right: 13px;
- margin-left: 4px;
- padding: 0px 4px;
-}
-
-.sdpi-item-child,
-.sdpi-item-group>.sdpi-item>input[type="color"] {
- margin-top: 0.4em;
- margin-right: 4px;
- margin-left: 4px;
-}
-
-.full,
-.full *,
-.sdpi-item-value.full,
-.sdpi-item-child>full>*,
-.sdpi-item-child.full,
-.sdpi-item-child.full>*,
-.full>.sdpi-item-child,
-.full>.sdpi-item-child>* {
- display: flex;
- flex: 1 1 0;
- margin-bottom: 4px;
- margin-left: 0px;
- width: 100%;
-
- justify-content: space-evenly;
-}
-
-.sdpi-item-group>.sdpi-item>input[type="color"] {
- margin-top: 0px;
-}
-
-::-webkit-calendar-picker-indicator:focus,
-input[type=file]::-webkit-file-upload-button:focus,
-button:focus,
-textarea:focus,
-input:focus,
-select:focus,
-option:focus,
-details:focus,
-summary:focus,
-.custom-select select {
- outline: none;
-}
-
-summary {
- cursor: default;
- -webkit-user-select: none;
-}
-
-.pointer,
-summary .pointer {
- cursor: pointer;
-}
-
-details * {
- font-size: 12px;
- font-weight: normal;
-}
-
-details.message {
- padding: 4px 18px 4px 12px;
-}
-
-details.message summary {
- font-size: 10pt;
- font-weight: 600;
- min-height: 18px;
-}
-
-details.message:first-child {
- margin-top: 4px;
- margin-left: 0;
- padding-left: 102px !important;
-}
-
-details.message>summary:first-of-type {
- line-height: 20px;
-}
-
-details.message h1 {
- text-align: left;
-}
-
-details:not(.pointer)>summary {
- list-style: none;
-}
-
-details>summary::-webkit-details-marker .message>summary::-webkit-details-marker {
- display: none;
-}
-
-.info20,
-.question,
-.caution,
-.info {
- background-repeat: no-repeat;
- background-position: 72px center;
-}
-
-.info20 {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' d='M10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 C15.5228475,0 20,4.4771525 20,10 C20,15.5228475 15.5228475,20 10,20 Z M10,8 C8.8954305,8 8,8.84275812 8,9.88235294 L8,16.1176471 C8,17.1572419 8.8954305,18 10,18 C11.1045695,18 12,17.1572419 12,16.1176471 L12,9.88235294 C12,8.84275812 11.1045695,8 10,8 Z M10,3 C8.8954305,3 8,3.88165465 8,4.96923077 L8,5.03076923 C8,6.11834535 8.8954305,7 10,7 C11.1045695,7 12,6.11834535 12,5.03076923 L12,4.96923077 C12,3.88165465 11.1045695,3 10,3 Z'/%3E%3C/svg%3E%0A");
-}
-
-.info {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' d='M10,18 C5.581722,18 2,14.418278 2,10 C2,5.581722 5.581722,2 10,2 C14.418278,2 18,5.581722 18,10 C18,14.418278 14.418278,18 10,18 Z M10,8 C9.44771525,8 9,8.42137906 9,8.94117647 L9,14.0588235 C9,14.5786209 9.44771525,15 10,15 C10.5522847,15 11,14.5786209 11,14.0588235 L11,8.94117647 C11,8.42137906 10.5522847,8 10,8 Z M10,5 C9.44771525,5 9,5.44082732 9,5.98461538 L9,6.01538462 C9,6.55917268 9.44771525,7 10,7 C10.5522847,7 11,6.55917268 11,6.01538462 L11,5.98461538 C11,5.44082732 10.5522847,5 10,5 Z'/%3E%3C/svg%3E%0A");
-}
-
-.info2 {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='15' height='15' viewBox='0 0 15 15'%3E%3Cpath fill='%23999' d='M7.5,15 C3.35786438,15 0,11.6421356 0,7.5 C0,3.35786438 3.35786438,0 7.5,0 C11.6421356,0 15,3.35786438 15,7.5 C15,11.6421356 11.6421356,15 7.5,15 Z M7.5,2 C6.67157287,2 6,2.66124098 6,3.47692307 L6,3.52307693 C6,4.33875902 6.67157287,5 7.5,5 C8.32842705,5 9,4.33875902 9,3.52307693 L9,3.47692307 C9,2.66124098 8.32842705,2 7.5,2 Z M5,6 L5,7.02155172 L6,7 L6,12 L5,12.0076778 L5,13 L10,13 L10,12 L9,12.0076778 L9,6 L5,6 Z'/%3E%3C/svg%3E%0A");
-}
-
-.sdpi-more-info {
- background-image: linear-gradient(to right, #00000000 0%, #00000040 80%), url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpolygon fill='%23999' points='4 7 8 7 8 5 12 8 8 11 8 9 4 9'/%3E%3C/svg%3E%0A");
-}
-
-.caution {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' fill-rule='evenodd' d='M9.03952676,0.746646542 C9.57068894,-0.245797319 10.4285735,-0.25196227 10.9630352,0.746646542 L19.7705903,17.2030214 C20.3017525,18.1954653 19.8777595,19 18.8371387,19 L1.16542323,19 C0.118729947,19 -0.302490098,18.2016302 0.231971607,17.2030214 L9.03952676,0.746646542 Z M10,2.25584053 L1.9601405,17.3478261 L18.04099,17.3478261 L10,2.25584053 Z M10,5.9375 C10.531043,5.9375 10.9615385,6.37373537 10.9615385,6.91185897 L10.9615385,11.6923077 C10.9615385,12.2304313 10.531043,12.6666667 10,12.6666667 C9.46895697,12.6666667 9.03846154,12.2304313 9.03846154,11.6923077 L9.03846154,6.91185897 C9.03846154,6.37373537 9.46895697,5.9375 10,5.9375 Z M10,13.4583333 C10.6372516,13.4583333 11.1538462,13.9818158 11.1538462,14.6275641 L11.1538462,14.6641026 C11.1538462,15.3098509 10.6372516,15.8333333 10,15.8333333 C9.36274837,15.8333333 8.84615385,15.3098509 8.84615385,14.6641026 L8.84615385,14.6275641 C8.84615385,13.9818158 9.36274837,13.4583333 10,13.4583333 Z'/%3E%3C/svg%3E%0A");
-}
-
-.question {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cpath fill='%23999' d='M10,18 C5.581722,18 2,14.418278 2,10 C2,5.581722 5.581722,2 10,2 C14.418278,2 18,5.581722 18,10 C18,14.418278 14.418278,18 10,18 Z M6.77783203,7.65332031 C6.77783203,7.84798274 6.85929281,8.02888914 7.0222168,8.19604492 C7.18514079,8.36320071 7.38508996,8.44677734 7.62207031,8.44677734 C8.02409055,8.44677734 8.29703704,8.20768468 8.44091797,7.72949219 C8.59326248,7.27245865 8.77945854,6.92651485 8.99951172,6.69165039 C9.2195649,6.45678594 9.56233491,6.33935547 10.027832,6.33935547 C10.4256205,6.33935547 10.7006836,6.37695313 11.0021973,6.68847656 C11.652832,7.53271484 10.942627,8.472229 10.3750916,9.1321106 C9.80755615,9.79199219 8.29492188,11.9897461 10.027832,12.1347656 C10.4498423,12.1700818 10.7027991,11.9147157 10.7832031,11.4746094 C11.0021973,9.59857178 13.1254883,8.82415771 13.1254883,7.53271484 C13.1254883,7.07568131 12.9974785,6.65250846 12.7414551,6.26318359 C12.4854317,5.87385873 12.1225609,5.56600048 11.652832,5.33959961 C11.1831031,5.11319874 10.6414419,5 10.027832,5 C9.36767248,5 8.79004154,5.13541531 8.29492187,5.40625 C7.79980221,5.67708469 7.42317837,6.01879677 7.16503906,6.43139648 C6.90689975,6.8439962 6.77783203,7.25130007 6.77783203,7.65332031 Z M10.0099668,15 C10.2713191,15 10.5016601,14.9108147 10.7009967,14.7324415 C10.9003332,14.5540682 11,14.3088087 11,13.9966555 C11,13.7157177 10.9047629,13.4793767 10.7142857,13.2876254 C10.5238086,13.0958742 10.2890379,13 10.0099668,13 C9.72646591,13 9.48726565,13.0958742 9.2923588,13.2876254 C9.09745196,13.4793767 9,13.7157177 9,13.9966555 C9,14.313268 9.10077419,14.5596424 9.30232558,14.735786 C9.50387698,14.9119295 9.73975502,15 10.0099668,15 Z'/%3E%3C/svg%3E%0A");
-}
-
-
-.sdpi-more-info {
- position: fixed;
- left: 0px;
- right: 0px;
- bottom: 0px;
- min-height: 16px;
- padding-right: 16px;
- text-align: right;
- -webkit-touch-callout: none;
- cursor: pointer;
- user-select: none;
- background-position: right center;
- background-repeat: no-repeat;
- border-radius: var(--sdpi-borderradius);
- text-decoration: none;
- color: var(--sdpi-color);
-}
-
-.sdpi-more-info-button {
- display: flex;
- align-self: right;
- margin-left: auto;
- position: fixed;
- right: 17px;
- bottom: 0px;
- user-select: none;
-}
-
-
-.sdpi-bottom-bar {
- display: flex;
- align-self: right;
- margin-left: auto;
- position: fixed;
- right: 17px;
- bottom: 0px;
- user-select: none;
-}
-
-.sdpi-bottom-bar.right {
- right: 0px;
-}
-
-.sdpi-bottom-bar button {
- min-height: 20px !important;
- height: 20px !important;
-}
-
-details a {
- background-position: right !important;
- min-height: 24px;
- display: inline-block;
- line-height: 24px;
- padding-right: 28px;
-}
-
-
-input:not([type="range"]),
-textarea {
- -webkit-appearance: none;
- background: var(--sdpi-background);
- color: var(--sdpi-color);
- font-weight: normal;
- font-size: 9pt;
- border: none;
- margin-top: 2px;
- margin-bottom: 2px;
- min-width: 219px;
-}
-
-textarea+label {
- display: flex;
- justify-content: flex-end
-}
-
-input[type="radio"],
-input[type="checkbox"] {
- display: none;
-}
-
-input[type="radio"]+label,
-input[type="checkbox"]+label {
- font-size: 9pt;
- color: var(--sdpi-color);
- font-weight: normal;
- margin-right: 8px;
- -webkit-user-select: none;
-}
-
-input[type="radio"]+label:after,
-input[type="checkbox"]+label:after {
- content: " " !important;
-}
-
-.sdpi-item[type="radio"]>.sdpi-item-value,
-.sdpi-item[type="checkbox"]>.sdpi-item-value {
- padding-top: 2px;
-}
-
-.sdpi-item[type="checkbox"]>.sdpi-item-value>* {
- margin-top: 4px;
-}
-
-.sdpi-item[type="checkbox"] .sdpi-item-child,
-.sdpi-item[type="radio"] .sdpi-item-child {
- display: inline-block;
-}
-
-.sdpi-item[type="range"] .sdpi-item-value,
-.sdpi-item[type="meter"] .sdpi-item-child,
-.sdpi-item[type="progress"] .sdpi-item-child {
- display: flex;
-}
-
-.sdpi-item[type="range"] .sdpi-item-value {
- min-height: 26px;
-}
-
-.sdpi-item[type="range"] .sdpi-item-value span,
-.sdpi-item[type="meter"] .sdpi-item-child span,
-.sdpi-item[type="progress"] .sdpi-item-child span {
- margin-top: -2px;
- min-width: 8px;
- text-align: right;
- user-select: none;
- cursor: pointer;
- -webkit-user-select: none;
- user-select: none;
-}
-
-.sdpi-item[type="range"] .sdpi-item-value span {
- margin-top: 7px;
- text-align: right;
-}
-
-span+input[type="range"] {
- display: flex;
- max-width: 168px;
-
-}
-
-.sdpi-item[type="range"] .sdpi-item-value span:first-child,
-.sdpi-item[type="meter"] .sdpi-item-child span:first-child,
-.sdpi-item[type="progress"] .sdpi-item-child span:first-child {
- margin-right: 4px;
-}
-
-.sdpi-item[type="range"] .sdpi-item-value span:last-child,
-.sdpi-item[type="meter"] .sdpi-item-child span:last-child,
-.sdpi-item[type="progress"] .sdpi-item-child span:last-child {
- margin-left: 4px;
-}
-
-.reverse {
- transform: rotate(180deg);
-}
-
-.sdpi-item[type="meter"] .sdpi-item-child meter+span:last-child {
- margin-left: -10px;
-}
-
-.sdpi-item[type="progress"] .sdpi-item-child meter+span:last-child {
- margin-left: -14px;
-}
-
-.sdpi-item[type="radio"]>.sdpi-item-value>* {
- margin-top: 2px;
-}
-
-details {
- padding: 8px 18px 8px 12px;
- min-width: 86px;
-}
-
-details>h4 {
- border-bottom: 1px solid var(--sdpi-bordercolor);
-}
-
-legend {
- display: none;
-}
-
-.sdpi-item-value>textarea {
- padding: 0px;
- width: 219px;
- margin-left: 1px;
- margin-top: 3px;
- padding: 4px;
-}
-
-input[type="radio"]+label span,
-input[type="checkbox"]+label span {
- display: inline-block;
- width: 16px;
- height: 16px;
- margin: 2px 4px 2px 0;
- border-radius: 3px;
- vertical-align: middle;
- background: var(--sdpi-background);
- cursor: pointer;
- border: 1px solid rgb(0, 0, 0, .2);
-}
-
-input[type="radio"]+label span {
- border-radius: 100%;
-}
-
-input[type="radio"]:checked+label span,
-input[type="checkbox"]:checked+label span {
- background-color: #77f;
- background-image: url(../assets/check.svg);
- background-repeat: no-repeat;
- background-position: center center;
- border: 1px solid rgb(0, 0, 0, .4);
-}
-
-input[type="radio"]:active:checked+label span,
-input[type="radio"]:active+label span,
-input[type="checkbox"]:active:checked+label span,
-input[type="checkbox"]:active+label span {
- background-color: #303030;
-}
-
-input[type="radio"]:checked+label span {
- background-image: url(../assets/rcheck.svg);
-}
-
-input[type="range"] {
- width: var(--sdpi-width);
- height: 30px;
- overflow: hidden;
- cursor: pointer;
- background: transparent !important;
-}
-
-.sdpi-item>input[type="range"] {
- margin-left: 2px;
- max-width: var(--sdpi-width);
- width: var(--sdpi-width);
- padding: 0px;
- margin-top: 2px;
-}
-
-/*
-input[type="range"],
-input[type="range"]::-webkit-slider-runnable-track,
-input[type="range"]::-webkit-slider-thumb {
- -webkit-appearance: none;
-}
-*/
-
-input[type="range"]::-webkit-slider-runnable-track {
- height: 5px;
- background: #979797;
- border-radius: 3px;
- padding: 0px !important;
- border: 1px solid var(--sdpi-background);
-}
-
-input[type="range"]::-webkit-slider-thumb {
- position: relative;
- -webkit-appearance: none;
- background-color: var(--sdpi-color);
- width: 12px;
- height: 12px;
- border-radius: 20px;
- margin-top: -5px;
- border: none;
-}
-
-input[type="range" i] {
- margin: 0;
-}
-
-input[type="range"]::-webkit-slider-thumb::before {
- position: absolute;
- content: "";
- height: 5px;
- /* equal to height of runnable track or 1 less */
- width: 500px;
- /* make this bigger than the widest range input element */
- left: -502px;
- /* this should be -2px - width */
- top: 8px;
- /* don't change this */
- background: #77f;
-}
-
-input[type="color"] {
- min-width: 32px;
- min-height: 32px;
- width: 32px;
- height: 32px;
- padding: 0;
- background-color: var(--sdpi-bgcolor);
- flex: none;
-}
-
-::-webkit-color-swatch {
- min-width: 24px;
-}
-
-textarea {
- height: 3em;
- word-break: break-word;
- line-height: 1.5em;
-}
-
-.textarea {
- padding: 0px !important;
-}
-
-textarea {
- width: 219px;
- /*98%;*/
- height: 96%;
- min-height: 6em;
- resize: none;
- border-radius: var(--sdpi-borderradius);
-}
-
-/* CAROUSEL */
-
-.sdpi-item[type="carousel"] {}
-
-.sdpi-item.card-carousel-wrapper,
-.sdpi-item>.card-carousel-wrapper {
- padding: 0;
-}
-
-
-.card-carousel-wrapper {
- display: flex;
- align-items: center;
- justify-content: center;
- margin: 12px auto;
- color: #666a73;
-}
-
-.card-carousel {
- display: flex;
- justify-content: center;
- width: 278px;
-}
-
-.card-carousel--overflow-container {
- overflow: hidden;
-}
-
-.card-carousel--nav__left,
-.card-carousel--nav__right {
- /* display: inline-block; */
- width: 12px;
- height: 12px;
- border-top: 2px solid #42b883;
- border-right: 2px solid #42b883;
- cursor: pointer;
- margin: 0 4px;
- transition: transform 150ms linear;
-}
-
-.card-carousel--nav__left[disabled],
-.card-carousel--nav__right[disabled] {
- opacity: 0.2;
- border-color: black;
-}
-
-.card-carousel--nav__left {
- transform: rotate(-135deg);
-}
-
-.card-carousel--nav__left:active {
- transform: rotate(-135deg) scale(0.85);
-}
-
-.card-carousel--nav__right {
- transform: rotate(45deg);
-}
-
-.card-carousel--nav__right:active {
- transform: rotate(45deg) scale(0.85);
-}
-
-.card-carousel-cards {
- display: flex;
- transition: transform 150ms ease-out;
- transform: translatex(0px);
-}
-
-.card-carousel-cards .card-carousel--card {
- margin: 0 5px;
- cursor: pointer;
- /* box-shadow: 0 4px 15px 0 rgba(40, 44, 53, 0.06), 0 2px 2px 0 rgba(40, 44, 53, 0.08); */
- background-color: #fff;
- border-radius: 4px;
- z-index: 3;
-}
-
-.xxcard-carousel-cards .card-carousel--card:first-child {
- margin-left: 0;
-}
-
-.xxcard-carousel-cards .card-carousel--card:last-child {
- margin-right: 0;
-}
-
-.card-carousel-cards .card-carousel--card img {
- vertical-align: bottom;
- border-top-left-radius: 4px;
- border-top-right-radius: 4px;
- transition: opacity 150ms linear;
- width: 60px;
-}
-
-.card-carousel-cards .card-carousel--card img:hover {
- opacity: 0.5;
-}
-
-.card-carousel-cards .card-carousel--card--footer {
- border-top: 0;
- max-width: 80px;
- overflow: hidden;
- display: flex;
- height: 100%;
- flex-direction: column;
-}
-
-.card-carousel-cards .card-carousel--card--footer p {
- padding: 3px 0;
- margin: 0;
- margin-bottom: 2px;
- font-size: 15px;
- font-weight: 500;
- color: #2c3e50;
-}
-
-.card-carousel-cards .card-carousel--card--footer p:nth-of-type(2) {
- font-size: 12px;
- font-weight: 300;
- padding: 6px;
- color: #666a73;
-}
-
-
-h1 {
- font-size: 1.3em;
- font-weight: 500;
- text-align: center;
- margin-bottom: 12px;
-}
-
-::-webkit-datetime-edit {
- font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
- background: url(../assets/elg_calendar_inv.svg) no-repeat left center;
- padding-right: 1em;
- padding-left: 25px;
- background-position: 4px 0px;
-}
-
-::-webkit-datetime-edit-fields-wrapper {}
-
-::-webkit-datetime-edit-text {
- padding: 0 0.3em;
-}
-
-::-webkit-datetime-edit-month-field {}
-
-::-webkit-datetime-edit-day-field {}
-
-::-webkit-datetime-edit-year-field {}
-
-::-webkit-inner-spin-button {
-
- /* display: none; */
-}
-
-::-webkit-calendar-picker-indicator {
- background: transparent;
- font-size: 17px;
-}
-
-::-webkit-calendar-picker-indicator:focus {
- background-color: rgba(0, 0, 0, 0.2);
-}
-
-input[type="date"] {
- -webkit-align-items: center;
- display: -webkit-inline-flex;
- font-family: monospace;
- overflow: hidden;
- padding: 0;
- -webkit-padding-start: 1px;
-}
-
-input::-webkit-datetime-edit {
- -webkit-flex: 1;
- -webkit-user-modify: read-only !important;
- display: inline-block;
- min-width: 0;
- overflow: hidden;
-}
-
-/*
-input::-webkit-datetime-edit-fields-wrapper {
- -webkit-user-modify: read-only !important;
- display: inline-block;
- padding: 1px 0;
- white-space: pre;
-
-}
-*/
-
-/*
-input[type="date"] {
- background-color: red;
- outline: none;
-}
-
-input[type="date"]::-webkit-clear-button {
- font-size: 18px;
- height: 30px;
- position: relative;
-}
-
-input[type="date"]::-webkit-inner-spin-button {
- height: 28px;
-}
-
-input[type="date"]::-webkit-calendar-picker-indicator {
- font-size: 15px;
-} */
-
-input[type="file"] {
- opacity: 0;
- display: none;
-}
-
-.sdpi-item>input[type="file"] {
- opacity: 1;
- display: flex;
-}
-
-input[type="file"]+span {
- display: flex;
- flex: 0 1 auto;
- background-color: #0000ff50;
-}
-
-label.sdpi-file-label {
- cursor: pointer;
- user-select: none;
- display: inline-block;
- min-height: 21px !important;
- height: 21px !important;
- line-height: 20px;
- padding: 0px 4px;
- margin: auto;
- margin-right: 0px;
- float: right;
-}
-
-.sdpi-file-label>label:active,
-.sdpi-file-label.file:active,
-label.sdpi-file-label:active,
-label.sdpi-file-info:active,
-input[type="file"]::-webkit-file-upload-button:active,
-button:active {
- background-color: var(--sdpi-color);
- color: #303030;
-}
-
-input:required:invalid,
-input:focus:invalid {
- background: var(--sdpi-background) url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5IiBoZWlnaHQ9IjkiIHZpZXdCb3g9IjAgMCA5IDkiPgogICAgPHBhdGggZmlsbD0iI0Q4RDhEOCIgZD0iTTQuNSwwIEM2Ljk4NTI4MTM3LC00LjU2NTM4NzgyZS0xNiA5LDIuMDE0NzE4NjMgOSw0LjUgQzksNi45ODUyODEzNyA2Ljk4NTI4MTM3LDkgNC41LDkgQzIuMDE0NzE4NjMsOSAzLjA0MzU5MTg4ZS0xNiw2Ljk4NTI4MTM3IDAsNC41IEMtMy4wNDM1OTE4OGUtMTYsMi4wMTQ3MTg2MyAyLjAxNDcxODYzLDQuNTY1Mzg3ODJlLTE2IDQuNSwwIFogTTQsMSBMNCw2IEw1LDYgTDUsMSBMNCwxIFogTTQuNSw4IEM0Ljc3NjE0MjM3LDggNSw3Ljc3NjE0MjM3IDUsNy41IEM1LDcuMjIzODU3NjMgNC43NzYxNDIzNyw3IDQuNSw3IEM0LjIyMzg1NzYzLDcgNCw3LjIyMzg1NzYzIDQsNy41IEM0LDcuNzc2MTQyMzcgNC4yMjM4NTc2Myw4IDQuNSw4IFoiLz4KICA8L3N2Zz4) no-repeat 98% center;
-}
-
-input:required:valid {
- background: var(--sdpi-background) url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5IiBoZWlnaHQ9IjkiIHZpZXdCb3g9IjAgMCA5IDkiPjxwb2x5Z29uIGZpbGw9IiNEOEQ4RDgiIHBvaW50cz0iNS4yIDEgNi4yIDEgNi4yIDcgMy4yIDcgMy4yIDYgNS4yIDYiIHRyYW5zZm9ybT0icm90YXRlKDQwIDQuNjc3IDQpIi8+PC9zdmc+) no-repeat 98% center;
-}
-
-.tooltip,
-:tooltip,
-:title {
- color: yellow;
-}
-
-.sdpi-item-group.file {
- width: 232px;
- display: flex;
- align-items: center;
-}
-
-.sdpi-file-info {
- overflow-wrap: break-word;
- word-wrap: break-word;
- hyphens: auto;
-
- min-width: 132px;
- max-width: 144px;
- max-height: 32px;
- margin-top: 0px;
- margin-left: 5px;
- display: inline-block;
- overflow: hidden;
- padding: 6px 4px;
- background-color: var(--sdpi-background);
-}
-
-
-::-webkit-scrollbar {
- width: 8px;
-}
-
-::-webkit-scrollbar-track {
- -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
- box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
- margin: 4px;
- border-radius: 8px;
-}
-
-::-webkit-scrollbar-thumb {
- background-color: #999999;
- outline: 1px solid slategrey;
- border-radius: 8px;
-}
-
-a {
- color: #7397d2;
-}
-
-.testcontainer {
- display: flex;
- background-color: #0000ff20;
- max-width: 400px;
- height: 200px;
- align-content: space-evenly;
-}
-
-input[type=range] {
- -webkit-appearance: none;
- /* background-color: green; */
- height: 6px;
- margin-top: 12px;
- z-index: 0;
- overflow: visible;
-}
-
-/*
-input[type="range"]::-webkit-slider-thumb {
- -webkit-appearance: none;
- background-color: var(--sdpi-color);
- width: 12px;
- height: 12px;
- border-radius: 20px;
- margin-top: -6px;
- border: none;
-} */
-
-:-webkit-slider-thumb {
- -webkit-appearance: none;
- background-color: var(--sdpi-color);
- width: 16px;
- height: 16px;
- border-radius: 20px;
- margin-top: -6px;
- border: 1px solid #999999;
-}
-
-.sdpi-item[type="range"] .sdpi-item-group {
- display: flex;
- flex-direction: column;
-}
-
-.xxsdpi-item[type="range"] .sdpi-item-group input {
- max-width: 204px;
-}
-
-.sdpi-item[type="range"] .sdpi-item-group span {
- margin-left: 0px !important;
-}
-
-.sdpi-item[type="range"] .sdpi-item-group>.sdpi-item-child {
- display: flex;
- flex-direction: row;
-}
-
-.rangeLabel {
- position: absolute;
- font-weight: normal;
- margin-top: 24px;
-}
-
-:disabled {
- color: #993333;
-}
-
-select,
-select option {
- color: var(--sdpi-color);
-}
-
-select.disabled,
-select option:disabled {
- color: #fd9494;
- font-style: italic;
-}
-
-.runningAppsContainer {
- display: none;
-}
-
-.one-line {
- min-height: 1.5em;
-}
-
-.two-lines {
- min-height: 3em;
-}
-
-.three-lines {
- min-height: 4.5em;
-}
-
-.four-lines {
- min-height: 6em;
-}
-
-.min80>.sdpi-item-child {
- min-width: 80px;
-}
-
-.min100>.sdpi-item-child {
- min-width: 100px;
-}
-
-.min120>.sdpi-item-child {
- min-width: 120px;
-}
-
-.min140>.sdpi-item-child {
- min-width: 140px;
-}
-
-.min160>.sdpi-item-child {
- min-width: 160px;
-}
-
-.min200>.sdpi-item-child {
- min-width: 200px;
-}
-
-.max40 {
- flex-basis: 40%;
- flex-grow: 0;
-}
-
-.max30 {
- flex-basis: 30%;
- flex-grow: 0;
-}
-
-.max20 {
- flex-basis: 20%;
- flex-grow: 0;
-}
-
-.up20 {
- margin-top: -20px;
-}
-
-.alignCenter {
- align-items: center;
-}
-
-.alignTop {
- align-items: flex-start;
-}
-
-.alignBaseline {
- align-items: baseline;
-}
-
-.noMargins,
-.noMargins *,
-.noInnerMargins * {
- margin: 0;
- padding: 0;
-}
-
-.hidden {
- display: none !important;
-}
-
-.icon-help,
-.icon-help-line,
-.icon-help-fill,
-.icon-help-inv,
-.icon-brighter,
-.icon-darker,
-.icon-warmer,
-.icon-cooler {
- min-width: 20px;
- width: 20px;
- background-repeat: no-repeat;
- opacity: 1;
-}
-
-.icon-help:active,
-.icon-help-line:active,
-.icon-help-fill:active,
-.icon-help-inv:active,
-.icon-brighter:active,
-.icon-darker:active,
-.icon-warmer:active,
-.icon-cooler:active {
- opacity: 0.5;
-}
-
-.icon-brighter,
-.icon-darker,
-.icon-warmer,
-.icon-cooler {
- margin-top: 5px !important;
-}
-
-.icon-help,
-.icon-help-line,
-.icon-help-fill,
-.icon-help-inv {
- cursor: pointer;
- margin: 0px;
- margin-left: 4px;
-}
-
-.icon-brighter {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Ccircle cx='10' cy='10' r='4'/%3E%3Cpath d='M14.8532861,7.77530426 C14.7173255,7.4682615 14.5540843,7.17599221 14.3666368,6.90157083 L16.6782032,5.5669873 L17.1782032,6.4330127 L14.8532861,7.77530426 Z M10.5,4.5414007 C10.2777625,4.51407201 10.051423,4.5 9.82179677,4.5 C9.71377555,4.5 9.60648167,4.50311409 9.5,4.50925739 L9.5,2 L10.5,2 L10.5,4.5414007 Z M5.38028092,6.75545367 C5.18389364,7.02383457 5.01124349,7.31068015 4.86542112,7.61289977 L2.82179677,6.4330127 L3.32179677,5.5669873 L5.38028092,6.75545367 Z M4.86542112,12.3871002 C5.01124349,12.6893198 5.18389364,12.9761654 5.38028092,13.2445463 L3.32179677,14.4330127 L2.82179677,13.5669873 L4.86542112,12.3871002 Z M9.5,15.4907426 C9.60648167,15.4968859 9.71377555,15.5 9.82179677,15.5 C10.051423,15.5 10.2777625,15.485928 10.5,15.4585993 L10.5,18 L9.5,18 L9.5,15.4907426 Z M14.3666368,13.0984292 C14.5540843,12.8240078 14.7173255,12.5317385 14.8532861,12.2246957 L17.1782032,13.5669873 L16.6782032,14.4330127 L14.3666368,13.0984292 Z'/%3E%3C/g%3E%3C/svg%3E");
-}
-
-.icon-darker {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M10 14C7.790861 14 6 12.209139 6 10 6 7.790861 7.790861 6 10 6 12.209139 6 14 7.790861 14 10 14 12.209139 12.209139 14 10 14zM10 13C11.6568542 13 13 11.6568542 13 10 13 8.34314575 11.6568542 7 10 7 8.34314575 7 7 8.34314575 7 10 7 11.6568542 8.34314575 13 10 13zM14.8532861 7.77530426C14.7173255 7.4682615 14.5540843 7.17599221 14.3666368 6.90157083L16.6782032 5.5669873 17.1782032 6.4330127 14.8532861 7.77530426zM10.5 4.5414007C10.2777625 4.51407201 10.051423 4.5 9.82179677 4.5 9.71377555 4.5 9.60648167 4.50311409 9.5 4.50925739L9.5 2 10.5 2 10.5 4.5414007zM5.38028092 6.75545367C5.18389364 7.02383457 5.01124349 7.31068015 4.86542112 7.61289977L2.82179677 6.4330127 3.32179677 5.5669873 5.38028092 6.75545367zM4.86542112 12.3871002C5.01124349 12.6893198 5.18389364 12.9761654 5.38028092 13.2445463L3.32179677 14.4330127 2.82179677 13.5669873 4.86542112 12.3871002zM9.5 15.4907426C9.60648167 15.4968859 9.71377555 15.5 9.82179677 15.5 10.051423 15.5 10.2777625 15.485928 10.5 15.4585993L10.5 18 9.5 18 9.5 15.4907426zM14.3666368 13.0984292C14.5540843 12.8240078 14.7173255 12.5317385 14.8532861 12.2246957L17.1782032 13.5669873 16.6782032 14.4330127 14.3666368 13.0984292z'/%3E%3C/g%3E%3C/svg%3E");
-}
-
-.icon-warmer {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M12.3247275 11.4890349C12.0406216 11.0007637 11.6761954 10.5649925 11.2495475 10.1998198 11.0890394 9.83238991 11 9.42659309 11 9 11 7.34314575 12.3431458 6 14 6 15.6568542 6 17 7.34314575 17 9 17 10.6568542 15.6568542 12 14 12 13.3795687 12 12.8031265 11.8116603 12.3247275 11.4890349zM17.6232392 11.6692284C17.8205899 11.4017892 17.9890383 11.1117186 18.123974 10.8036272L20.3121778 12.0669873 19.8121778 12.9330127 17.6232392 11.6692284zM18.123974 7.19637279C17.9890383 6.88828142 17.8205899 6.5982108 17.6232392 6.33077158L19.8121778 5.0669873 20.3121778 5.9330127 18.123974 7.19637279zM14.5 4.52746439C14.3358331 4.50931666 14.1690045 4.5 14 4.5 13.8309955 4.5 13.6641669 4.50931666 13.5 4.52746439L13.5 2 14.5 2 14.5 4.52746439zM13.5 13.4725356C13.6641669 13.4906833 13.8309955 13.5 14 13.5 14.1690045 13.5 14.3358331 13.4906833 14.5 13.4725356L14.5 16 13.5 16 13.5 13.4725356zM14 11C15.1045695 11 16 10.1045695 16 9 16 7.8954305 15.1045695 7 14 7 12.8954305 7 12 7.8954305 12 9 12 10.1045695 12.8954305 11 14 11zM9.5 11C10.6651924 11.4118364 11.5 12.5 11.5 14 11.5 16 10 17.5 8 17.5 6 17.5 4.5 16 4.5 14 4.5 12.6937812 5 11.5 6.5 11L6.5 7 9.5 7 9.5 11z'/%3E%3Cpath d='M12,14 C12,16.209139 10.209139,18 8,18 C5.790861,18 4,16.209139 4,14 C4,12.5194353 4.80439726,11.2267476 6,10.5351288 L6,4 C6,2.8954305 6.8954305,2 8,2 C9.1045695,2 10,2.8954305 10,4 L10,10.5351288 C11.1956027,11.2267476 12,12.5194353 12,14 Z M11,14 C11,12.6937812 10.1651924,11.5825421 9,11.1707057 L9,4 C9,3.44771525 8.55228475,3 8,3 C7.44771525,3 7,3.44771525 7,4 L7,11.1707057 C5.83480763,11.5825421 5,12.6937812 5,14 C5,15.6568542 6.34314575,17 8,17 C9.65685425,17 11,15.6568542 11,14 Z'/%3E%3C/g%3E%3C/svg%3E");
-}
-
-.icon-cooler {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 20 20'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M10.4004569 11.6239517C10.0554735 10.9863849 9.57597206 10.4322632 9 9.99963381L9 9.7450467 9.53471338 9.7450467 10.8155381 8.46422201C10.7766941 8.39376637 10.7419749 8.32071759 10.7117062 8.2454012L9 8.2454012 9 6.96057868 10.6417702 6.96057868C10.6677696 6.86753378 10.7003289 6.77722682 10.7389179 6.69018783L9.44918707 5.40045694 9 5.40045694 9 4.34532219 9.32816127 4.34532219 9.34532219 2.91912025 10.4004569 2.91912025 10.4004569 4.53471338 11.6098599 5.74411634C11.7208059 5.68343597 11.8381332 5.63296451 11.9605787 5.59396526L11.9605787 3.8884898 10.8181818 2.74609294 11.5642748 2 12.5727518 3.00847706 13.5812289 2 14.3273218 2.74609294 13.2454012 3.82801356 13.2454012 5.61756719C13.3449693 5.65339299 13.4408747 5.69689391 13.5324038 5.74735625L14.7450467 4.53471338 14.7450467 2.91912025 15.8001815 2.91912025 15.8001815 4.34532219 17.2263834 4.34532219 17.2263834 5.40045694 15.6963166 5.40045694 14.4002441 6.69652946C14.437611 6.78161093 14.4692249 6.86979146 14.4945934 6.96057868L16.2570138 6.96057868 17.3994107 5.81818182 18.1455036 6.56427476 17.1370266 7.57275182 18.1455036 8.58122888 17.3994107 9.32732182 16.3174901 8.2454012 14.4246574 8.2454012C14.3952328 8.31861737 14.3616024 8.38969062 14.3240655 8.45832192L15.6107903 9.7450467 17.2263834 9.7450467 17.2263834 10.8001815 15.8001815 10.8001815 15.8001815 12.2263834 14.7450467 12.2263834 14.7450467 10.6963166 13.377994 9.32926387C13.3345872 9.34850842 13.2903677 9.36625331 13.2454012 9.38243281L13.2454012 11.3174901 14.3273218 12.3994107 13.5812289 13.1455036 12.5848864 12.1491612 11.5642748 13.1455036 10.8181818 12.3994107 11.9605787 11.2570138 11.9605787 9.40603474C11.8936938 9.38473169 11.828336 9.36000556 11.7647113 9.33206224L10.4004569 10.6963166 10.4004569 11.6239517zM12.75 8.5C13.3022847 8.5 13.75 8.05228475 13.75 7.5 13.75 6.94771525 13.3022847 6.5 12.75 6.5 12.1977153 6.5 11.75 6.94771525 11.75 7.5 11.75 8.05228475 12.1977153 8.5 12.75 8.5zM9.5 14C8.5 16.3333333 7.33333333 17.5 6 17.5 4.66666667 17.5 3.5 16.3333333 2.5 14L9.5 14z'/%3E%3Cpath d='M10,14 C10,16.209139 8.209139,18 6,18 C3.790861,18 2,16.209139 2,14 C2,12.5194353 2.80439726,11.2267476 4,10.5351288 L4,4 C4,2.8954305 4.8954305,2 6,2 C7.1045695,2 8,2.8954305 8,4 L8,10.5351288 C9.19560274,11.2267476 10,12.5194353 10,14 Z M9,14 C9,12.6937812 8.16519237,11.5825421 7,11.1707057 L7,4 C7,3.44771525 6.55228475,3 6,3 C5.44771525,3 5,3.44771525 5,4 L5,11.1707057 C3.83480763,11.5825421 3,12.6937812 3,14 C3,15.6568542 4.34314575,17 6,17 C7.65685425,17 9,15.6568542 9,14 Z'/%3E%3C/g%3E%3C/svg%3E");
-}
-
-.icon-help {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Cpath fill='%23999' d='M11.292 12.516l.022 1.782H9.07v-1.804c0-1.98 1.276-2.574 2.662-3.278h-.022c.814-.44 1.65-.88 1.694-2.2.044-1.386-1.122-2.728-3.234-2.728-1.518 0-2.662.902-3.366 2.354L5 5.608C5.946 3.584 7.662 2 10.17 2c3.564 0 5.632 2.442 5.588 5.06-.066 2.618-1.716 3.41-3.102 4.158-.704.374-1.364.682-1.364 1.298zm-1.122 2.442c.858 0 1.452.594 1.452 1.452 0 .682-.594 1.408-1.452 1.408-.77 0-1.386-.726-1.386-1.408 0-.858.616-1.452 1.386-1.452z'/%3E%3C/svg%3E");
-}
-
-.icon-help-line {
- background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23999' fill-rule='evenodd'%3E%3Cpath d='M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zm0-1a9 9 0 1 0 0-18 9 9 0 0 0 0 18z'/%3E%3Cpath d='M10.848 12.307l.02 1.578H8.784v-1.597c0-1.753 1.186-2.278 2.474-2.901h-.02c.756-.39 1.533-.78 1.574-1.948.041-1.226-1.043-2.414-3.006-2.414-1.41 0-2.474.798-3.128 2.083L5 6.193C5.88 4.402 7.474 3 9.805 3 13.118 3 15.04 5.161 15 7.478c-.061 2.318-1.595 3.019-2.883 3.68-.654.332-1.268.604-1.268 1.15zM9.805 14.47c.798 0 1.35.525 1.35 1.285 0 .603-.552 1.246-1.35 1.246-.715 0-1.288-.643-1.288-1.246 0-.76.573-1.285 1.288-1.285z' fill-rule='nonzero'/%3E%3C/g%3E%3C/svg%3E");
-}
-
-.icon-help-fill {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Ccircle cx='10' cy='10' r='10' fill='%23999'/%3E%3Cpath fill='%23FFF' fill-rule='nonzero' d='M8.368 7.189H5C5 3.5 7.668 2 10.292 2 13.966 2 16 4.076 16 7.012c0 3.754-3.849 3.136-3.849 5.211v1.656H8.455v-1.832c0-2.164 1.4-2.893 2.778-3.6.437-.242 1.006-.574 1.006-1.236 0-2.208-3.871-2.142-3.871-.022zM10.25 18a1.75 1.75 0 1 1 0-3.5 1.75 1.75 0 0 1 0 3.5z'/%3E%3C/g%3E%3C/svg%3E");
-}
-
-.icon-help-inv {
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Cpath fill='%23999' fill-rule='evenodd' d='M10 20C4.477 20 0 15.523 0 10S4.477 0 10 0s10 4.477 10 10-4.477 10-10 10zM8.368 7.189c0-2.12 3.87-2.186 3.87.022 0 .662-.568.994-1.005 1.236-1.378.707-2.778 1.436-2.778 3.6v1.832h3.696v-1.656c0-2.075 3.849-1.457 3.849-5.21C16 4.075 13.966 2 10.292 2 7.668 2 5 3.501 5 7.189h3.368zM10.25 18a1.75 1.75 0 1 0 0-3.5 1.75 1.75 0 0 0 0 3.5z'/%3E%3C/svg%3E");
-}
-
-.kelvin::after {
- content: "K";
-}
-
-.mired::after {
- content: " Mired";
-}
-
-.percent::after {
- content: "%";
-}
-
-.sdpi-item-value+.icon-cooler,
-.sdpi-item-value+.icon-warmer {
- margin-left: 0px !important;
- margin-top: 15px !important;
-}
-
-/**
- CONTROL-CENTER STYLES
-*/
-input[type="range"].colorbrightness::-webkit-slider-runnable-track,
-input[type="range"].colortemperature::-webkit-slider-runnable-track {
- height: 8px;
- background: #979797;
- border-radius: 4px;
- background-image: linear-gradient(to right, #94d0ec, #ffb165);
-}
-
-input[type="range"].colorbrightness::-webkit-slider-runnable-track {
- background-color: #efefef;
- background-image: linear-gradient(to right, black, rgba(0, 0, 0, 0));
-}
-
-
-input[type="range"].colorbrightness::-webkit-slider-thumb,
-input[type="range"].colortemperature::-webkit-slider-thumb {
- width: 16px;
- height: 16px;
- border-radius: 20px;
- margin-top: -5px;
- background-color: #86c6e8;
- box-shadow: 0px 0px 1px #000000;
- border: 1px solid #d8d8d8;
-}
-
-.sdpi-info-label {
- display: inline-block;
- user-select: none;
- position: absolute;
- height: 15px;
- width: auto;
- text-align: center;
- border-radius: 4px;
- min-width: 44px;
- max-width: 80px;
- background: white;
- font-size: 11px;
- color: black;
- z-index: 1000;
- box-shadow: 0px 0px 12px rgba(0, 0, 0, .8);
- padding: 2px;
-
-}
-
-.sdpi-info-label.hidden {
- opacity: 0;
- transition: opacity 0.25s linear;
-}
-
-.sdpi-info-label.shown {
- position: absolute;
- opacity: 1;
- transition: opacity 0.25s ease-out;
-}
-
-/* adding some styles here that override sdpi things so we can use this as notes for sdpi updates*/
-select {
- min-width: 0px;
-
- /* this is a clunky fix for using background image as select arrow with long text options */
- -webkit-appearance: media-slider;
- text-overflow: ellipsis;
-}
-
-/*--------- context menu ----------*/
-
-.context-menu {
- display: none;
- position: absolute;
- z-index: 10;
- padding: 12px 0;
- width: 120px;
- background-color: #3D3D3D;
- border: solid 1px #dfdfdf;
- box-shadow: 1px 1px 2px #cfcfcf;
-}
-
-.context-menu--active {
- display: block;
-}
-
-.context-menu__items {
- list-style: none;
- margin: 0;
- padding: 0;
- overflow-y: auto;
-}
-
-.context-menu__item {
- display: block;
- margin-bottom: 4px;
- background-color: #3D3D3D !important;
-}
-
-.context-menu__item:last-child {
- margin-bottom: 0;
-}
-
-.context-menu__link {
- display: block;
- padding: 4px 12px;
- color: #ffff;
- text-decoration: none;
- white-space: nowrap;
-}
-
-.context-menu__link:hover {
- color: #fff;
- background-color: #0066aa;
-}
-
-.context-menu_message {
- cursor: default;
-}
diff --git a/warudo.streamdeck.sdPlugin/libs/js/action.js b/warudo.streamdeck.sdPlugin/libs/js/action.js
deleted file mode 100644
index 1f49591..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/action.js
+++ /dev/null
@@ -1,188 +0,0 @@
-///
-
-/**
- * @class Action
- * A Stream Deck plugin action, where you can register callback functions for different events
- */
-class ELGSDAction {
- UUID;
- on = EventEmitter.on;
- emit = EventEmitter.emit;
-
- constructor(UUID) {
- if (!UUID) {
- console.error(
- 'An action UUID matching the action UUID in your manifest is required when creating Actions.'
- );
- }
-
- this.UUID = UUID;
- }
-
- /**
- * Registers a callback function for the didReceiveSettings event, which fires when calling getSettings
- * @param {function} fn
- */
- onDidReceiveSettings(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the didReceiveSettings event is required for onDidReceiveSettings.'
- );
- }
-
- this.on(`${this.UUID}.${Events.didReceiveSettings}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the keyDown event, which fires when pressing a key down
- * @param {function} fn
- */
- onKeyDown(fn) {
- if (!fn) {
- console.error('A callback function for the keyDown event is required for onKeyDown.');
- }
-
- this.on(`${this.UUID}.${Events.keyDown}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the keyUp event, which fires when releasing a key
- * @param {function} fn
- */
- onKeyUp(fn) {
- if (!fn) {
- console.error('A callback function for the keyUp event is required for onKeyUp.');
- }
-
- this.on(`${this.UUID}.${Events.keyUp}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the willAppear event, which fires when an action appears on the canvas
- * @param {function} fn
- */
- onWillAppear(fn) {
- if (!fn) {
- console.error('A callback function for the willAppear event is required for onWillAppear.');
- }
-
- this.on(`${this.UUID}.${Events.willAppear}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the willAppear event, which fires when an action disappears on the canvas
- * @param {function} fn
- */
- onWillDisappear(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the willDisappear event is required for onWillDisappear.'
- );
- }
-
- this.on(`${this.UUID}.${Events.willDisappear}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the titleParametersDidChange event, which fires when a user changes the key title
- * @param {function} fn
- */
- onTitleParametersDidChange(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the titleParametersDidChange event is required for onTitleParametersDidChange.'
- );
- }
-
- this.on(`${this.UUID}.${Events.titleParametersDidChange}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the propertyInspectorDidAppear event, which fires when the property inspector is displayed
- * @param {function} fn
- */
- onPropertyInspectorDidAppear(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the propertyInspectorDidAppear event is required for onPropertyInspectorDidAppear.'
- );
- }
-
- this.on(`${this.UUID}.${Events.propertyInspectorDidAppear}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the propertyInspectorDidDisappear event, which fires when the property inspector is closed
- * @param {function} fn
- */
- onPropertyInspectorDidDisappear(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the propertyInspectorDidDisappear event is required for onPropertyInspectorDidDisappear.'
- );
- }
-
- this.on(`${this.UUID}.${Events.propertyInspectorDidDisappear}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the sendToPlugin event, which fires when the property inspector uses the sendToPlugin api
- * @param {function} fn
- */
- onSendToPlugin(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the sendToPlugin event is required for onSendToPlugin.'
- );
- }
-
- this.on(`${this.UUID}.${Events.sendToPlugin}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the onDialRotate event, which fires when a SD+ dial was rotated
- * @param {function} fn
- */
- onDialRotate(fn) {
- if (!fn) {
- console.error('A callback function for the onDialRotate event is required for onDialRotate.');
- }
- this.on(`${this.UUID}.${Events.dialRotate}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the onDialPress event, which fires when a SD+ dial was pressed or released
- * @param {function} fn
- */
- onDialPress(fn) {
- if (!fn) {
- console.error('A callback function for the onDialPress event is required for onDialPress.');
- }
- this.on(`${this.UUID}.${Events.dialPress}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the touchTap event, which fires when a SD+ touch panel was touched quickly
- * @param {function} fn
- */
- onTouchTap(fn) {
- if (!fn) {
- console.error('A callback function for the onTouchTap event is required for onTouchTap.');
- }
- this.on(`${this.UUID}.${Events.touchTap}`, (jsn) => fn(jsn));
- return this;
- }
-}
-
-const Action = ELGSDAction;
diff --git a/warudo.streamdeck.sdPlugin/libs/js/api.js b/warudo.streamdeck.sdPlugin/libs/js/api.js
deleted file mode 100644
index b85f63f..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/api.js
+++ /dev/null
@@ -1,240 +0,0 @@
-///
-
-class ELGSDApi {
- port;
- uuid;
- messageType;
- actionInfo;
- websocket;
- language;
- localization;
- appInfo;
- on = EventEmitter.on;
- emit = EventEmitter.emit;
-
- /**
- * Connect to Stream Deck
- * @param {string} port
- * @param {string} uuid
- * @param {string} messageType
- * @param {string} appInfoString
- * @param {string} actionString
- */
- connect(port, uuid, messageType, appInfoString, actionString) {
- this.port = port;
- this.uuid = uuid;
- this.messageType = messageType;
- this.actionInfo = actionString ? JSON.parse(actionString) : null;
- this.appInfo = JSON.parse(appInfoString);
- this.language = this.appInfo?.application?.language ?? null;
-
- if (this.websocket) {
- this.websocket.close();
- this.websocket = null;
- }
-
- this.websocket = new WebSocket('ws://127.0.0.1:' + this.port);
-
- this.websocket.onopen = () => {
- const json = {
- event: this.messageType,
- uuid: this.uuid,
- };
-
- this.websocket.send(JSON.stringify(json));
-
- this.emit(Events.connected, {
- connection: this.websocket,
- port: this.port,
- uuid: this.uuid,
- actionInfo: this.actionInfo,
- appInfo: this.appInfo,
- messageType: this.messageType,
- });
- };
-
- this.websocket.onerror = (evt) => {
- const error = `WEBSOCKET ERROR: ${evt}, ${evt.data}, ${SocketErrors[evt?.code]}`;
- console.warn(error);
- this.logMessage(error);
- };
-
- this.websocket.onclose = (evt) => {
- console.warn('WEBSOCKET CLOSED:', SocketErrors[evt?.code]);
- };
-
- this.websocket.onmessage = (evt) => {
- const data = evt?.data ? JSON.parse(evt.data) : null;
-
- const { action, event } = data;
- const message = action ? `${action}.${event}` : event;
- if (message && message !== '') this.emit(message, data);
- };
- }
-
- /**
- * Write to log file
- * @param {string} message
- */
- logMessage(message) {
- if (!message) {
- console.error('A message is required for logMessage.');
- }
-
- try {
- if (this.websocket) {
- const json = {
- event: Events.logMessage,
- payload: {
- message: message,
- },
- };
- this.websocket.send(JSON.stringify(json));
- } else {
- console.error('Websocket not defined');
- }
- } catch (e) {
- console.error('Websocket not defined');
- }
- }
-
- /**
- * Fetches the specified language json file
- * @param {string} pathPrefix
- * @returns {Promise}
- */
- async loadLocalization(pathPrefix) {
- try {
- if (!pathPrefix) {
- console.error('A path to localization json is required for loadLocalization.');
- }
- const manifest = await this.readJson(`${pathPrefix}${this.language}.json`);
- this.localization = manifest['Localization'] ?? null;
- window.$localizedStrings = this.localization;
-
- this.emit('localizationLoaded', this.localization);
-
- return this.localization;
- } catch (e) {
- console.error('Error loading localization', e);
- }
- }
-
- /**
- *
- * @param {string} path
- * @returns {Promise} json
- */
- async readJson(path) {
- if (!path) {
- console.error('A path is required to readJson.');
- }
-
- return new Promise((resolve, reject) => {
- const req = new XMLHttpRequest();
- req.onerror = reject;
- req.overrideMimeType('application/json');
- req.open('GET', path, true);
- req.onreadystatechange = (response) => {
- if (req.readyState === 4) {
- const jsonString = response?.target?.response;
- if (jsonString) {
- resolve(JSON.parse(response?.target?.response));
- } else {
- reject();
- }
- }
- };
-
- req.send();
- });
- }
-
- /**
- * Send JSON payload to StreamDeck
- * @param {string} context
- * @param {string} event
- * @param {object} [payload]
- */
- send(context, event, payload = {}) {
- this.websocket && this.websocket.send(JSON.stringify({ context, event, ...payload }));
- }
-
- /**
- * Save the plugin's persistent data
- * @param {object} payload
- */
- setGlobalSettings(payload) {
- this.send(this.uuid, Events.setGlobalSettings, {
- payload: payload,
- });
- }
-
- /**
- * Request the plugin's persistent data. StreamDeck does not return the data, but trigger the plugin/property inspectors didReceiveGlobalSettings event
- */
- getGlobalSettings() {
- this.send(this.uuid, Events.getGlobalSettings);
- }
-
- /**
- * Opens a URL in the default web browser
- * @param {string} url
- */
- openUrl(url) {
- if (!url) {
- console.error('A url is required for openUrl.');
- }
-
- this.send(this.uuid, Events.openUrl, {
- payload: {
- url,
- },
- });
- }
-
- /**
- * Registers a callback function for when Stream Deck is connected
- * @param {function} fn
- * @returns ELGSDStreamDeck
- */
- onConnected(fn) {
- if (!fn) {
- console.error('A callback function for the connected event is required for onConnected.');
- }
-
- this.on(Events.connected, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the didReceiveGlobalSettings event, which fires when calling getGlobalSettings
- * @param {function} fn
- */
- onDidReceiveGlobalSettings(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the didReceiveGlobalSettings event is required for onDidReceiveGlobalSettings.'
- );
- }
-
- this.on(Events.didReceiveGlobalSettings, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the didReceiveSettings event, which fires when calling getSettings
- * @param {string} action
- * @param {function} fn
- */
- onDidReceiveSettings(action, fn) {
- if (!fn) {
- console.error(
- 'A callback function for the didReceiveSettings event is required for onDidReceiveSettings.'
- );
- }
-
- this.on(`${action}.${Events.didReceiveSettings}`, (jsn) => fn(jsn));
- return this;
- }
-}
diff --git a/warudo.streamdeck.sdPlugin/libs/js/constants.js b/warudo.streamdeck.sdPlugin/libs/js/constants.js
deleted file mode 100644
index 48d10db..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/constants.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/**
- * Errors received from WebSocket
- */
-const SocketErrors = {
- 0: 'The connection has not yet been established',
- 1: 'The connection is established and communication is possible',
- 2: 'The connection is going through the closing handshake',
- 3: 'The connection has been closed or could not be opened',
- 1000: 'Normal Closure. The purpose for which the connection was established has been fulfilled.',
- 1001: 'Going Away. An endpoint is "going away", such as a server going down or a browser having navigated away from a page.',
- 1002: 'Protocol error. An endpoint is terminating the connection due to a protocol error',
- 1003: "Unsupported Data. An endpoint received a type of data it doesn't support.",
- 1004: '--Reserved--. The specific meaning might be defined in the future.',
- 1005: 'No Status. No status code was actually present.',
- 1006: 'Abnormal Closure. The connection was closed abnormally, e.g., without sending or receiving a Close control frame',
- 1007: 'Invalid frame payload data. The connection was closed, because the received data was not consistent with the type of the message (e.g., non-UTF-8 [http://tools.ietf.org/html/rfc3629]).',
- 1008: 'Policy Violation. The connection was closed, because current message data "violates its policy". This reason is given either if there is no other suitable reason, or if there is a need to hide specific details about the policy.',
- 1009: 'Message Too Big. Connection closed because the message is too big for it to process.',
- 1010: "Mandatory Extension. Connection is terminated the connection because the server didn't negotiate one or more extensions in the WebSocket handshake.",
- 1011: 'Internl Server Error. Connection closed because it encountered an unexpected condition that prevented it from fulfilling the request.',
- 1015: "TLS Handshake. The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified).",
-};
-
-/**
- * Events used for communicating with Stream Deck
- */
-const Events = {
- didReceiveSettings: 'didReceiveSettings',
- didReceiveGlobalSettings: 'didReceiveGlobalSettings',
- keyDown: 'keyDown',
- keyUp: 'keyUp',
- willAppear: 'willAppear',
- willDisappear: 'willDisappear',
- titleParametersDidChange: 'titleParametersDidChange',
- deviceDidConnect: 'deviceDidConnect',
- deviceDidDisconnect: 'deviceDidDisconnect',
- applicationDidLaunch: 'applicationDidLaunch',
- applicationDidTerminate: 'applicationDidTerminate',
- systemDidWakeUp: 'systemDidWakeUp',
- propertyInspectorDidAppear: 'propertyInspectorDidAppear',
- propertyInspectorDidDisappear: 'propertyInspectorDidDisappear',
- sendToPlugin: 'sendToPlugin',
- sendToPropertyInspector: 'sendToPropertyInspector',
- connected: 'connected',
- setImage: 'setImage',
- setXYWHImage: 'setXYWHImage',
- setTitle: 'setTitle',
- setState: 'setState',
- showOk: 'showOk',
- showAlert: 'showAlert',
- openUrl: 'openUrl',
- setGlobalSettings: 'setGlobalSettings',
- getGlobalSettings: 'getGlobalSettings',
- setSettings: 'setSettings',
- getSettings: 'getSettings',
- registerPropertyInspector: 'registerPropertyInspector',
- registerPlugin: 'registerPlugin',
- logMessage: 'logMessage',
- switchToProfile: 'switchToProfile',
- dialRotate: 'dialRotate',
- dialPress: 'dialPress',
- touchTap: 'touchTap',
- setFeedback: 'setFeedback',
- setFeedbackLayout: 'setFeedbackLayout',
-};
-
-/**
- * Constants used for Stream Deck
- */
-const Constants = {
- dataLocalize: '[data-localize]',
- hardwareAndSoftware: 0,
- hardwareOnly: 1,
- softwareOnly: 2,
-};
-
-const DestinationEnum = {
- HARDWARE_AND_SOFTWARE: 0,
- HARDWARE_ONLY: 1,
- SOFTWARE_ONLY: 2,
-};
diff --git a/warudo.streamdeck.sdPlugin/libs/js/dynamic-styles.js b/warudo.streamdeck.sdPlugin/libs/js/dynamic-styles.js
deleted file mode 100644
index 901c4ce..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/dynamic-styles.js
+++ /dev/null
@@ -1,70 +0,0 @@
-const fadeColor = function (col, amt) {
- const min = Math.min,
- max = Math.max;
- const num = parseInt(col.replace(/#/g, ''), 16);
- const r = min(255, max((num >> 16) + amt, 0));
- const g = min(255, max((num & 0x0000ff) + amt, 0));
- const b = min(255, max(((num >> 8) & 0x00ff) + amt, 0));
- return '#' + (g | (b << 8) | (r << 16)).toString(16).padStart(6, 0);
-};
-
-$PI.onConnected(({appInfo}) => {
- if (!appInfo?.colors) return;
- const clrs = appInfo.colors;
- const node = document.getElementById('#sdpi-dynamic-styles') || document.createElement('style');
- if (!clrs.mouseDownColor) clrs.mouseDownColor = fadeColor(clrs.highlightColor, -100);
- const clr = clrs.highlightColor.slice(0, 7);
- const clr1 = fadeColor(clr, 100);
- const clr2 = fadeColor(clr, 60);
- const metersActiveColor = fadeColor(clr, -60);
-
- node.setAttribute('id', 'sdpi-dynamic-styles');
- node.innerHTML = `
-
- input[type="radio"]:checked + label span,
- input[type="checkbox"]:checked + label span {
- background-color: ${clrs.highlightColor};
- }
-
- input[type="radio"]:active:checked + label span,
- input[type="checkbox"]:active:checked + label span {
- background-color: ${clrs.mouseDownColor};
- }
-
- input[type="radio"]:active + label span,
- input[type="checkbox"]:active + label span {
- background-color: ${clrs.buttonPressedBorderColor};
- }
-
- td.selected,
- td.selected:hover,
- li.selected:hover,
- li.selected {
- color: white;
- background-color: ${clrs.highlightColor};
- }
-
- .sdpi-file-label > label:active,
- .sdpi-file-label.file:active,
- label.sdpi-file-label:active,
- label.sdpi-file-info:active,
- input[type="file"]::-webkit-file-upload-button:active,
- button:active {
- border: 1pt solid ${clrs.buttonPressedBorderColor};
- background-color: ${clrs.buttonPressedBackgroundColor};
- color: ${clrs.buttonPressedTextColor};
- border-color: ${clrs.buttonPressedBorderColor};
- }
-
- ::-webkit-progress-value,
- meter::-webkit-meter-optimum-value {
- background: linear-gradient(${clr2}, ${clr1} 20%, ${clr} 45%, ${clr} 55%, ${clr2})
- }
-
- ::-webkit-progress-value:active,
- meter::-webkit-meter-optimum-value:active {
- background: linear-gradient(${clr}, ${clr2} 20%, ${metersActiveColor} 45%, ${metersActiveColor} 55%, ${clr})
- }
- `;
- document.body.appendChild(node);
-});
diff --git a/warudo.streamdeck.sdPlugin/libs/js/events.js b/warudo.streamdeck.sdPlugin/libs/js/events.js
deleted file mode 100644
index cc18825..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/events.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/** ELGEvents
- * Publish/Subscribe pattern to quickly signal events to
- * the plugin, property inspector and data.
- */
-
-const ELGEvents = {
- eventEmitter: function (name, fn) {
- const eventList = new Map();
-
- const on = (name, fn) => {
- if (!eventList.has(name)) eventList.set(name, ELGEvents.pubSub());
-
- return eventList.get(name).sub(fn);
- };
-
- const has = name => eventList.has(name);
-
- const emit = (name, data) => eventList.has(name) && eventList.get(name).pub(data);
-
- return Object.freeze({on, has, emit, eventList});
- },
-
- pubSub: function pubSub() {
- const subscribers = new Set();
-
- const sub = fn => {
- subscribers.add(fn);
- return () => {
- subscribers.delete(fn);
- };
- };
-
- const pub = data => subscribers.forEach(fn => fn(data));
- return Object.freeze({pub, sub});
- }
-};
-
-const EventEmitter = ELGEvents.eventEmitter();
\ No newline at end of file
diff --git a/warudo.streamdeck.sdPlugin/libs/js/property-inspector.js b/warudo.streamdeck.sdPlugin/libs/js/property-inspector.js
deleted file mode 100644
index d8b6705..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/property-inspector.js
+++ /dev/null
@@ -1,82 +0,0 @@
-///
-///
-
-class ELGSDPropertyInspector extends ELGSDApi {
- constructor() {
- super();
- if (ELGSDPropertyInspector.__instance) {
- return ELGSDPropertyInspector.__instance;
- }
-
- ELGSDPropertyInspector.__instance = this;
- }
-
- /**
- * Registers a callback function for when Stream Deck sends data to the property inspector
- * @param {string} actionUUID
- * @param {function} fn
- * @returns ELGSDStreamDeck
- */
- onSendToPropertyInspector(actionUUID, fn) {
- if (typeof actionUUID != 'string') {
- console.error('An action UUID string is required for onSendToPropertyInspector.');
- }
-
- if (!fn) {
- console.error(
- 'A callback function for the sendToPropertyInspector event is required for onSendToPropertyInspector.'
- );
- }
-
- this.on(`${actionUUID}.${Events.sendToPropertyInspector}`, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Send payload from the property inspector to the plugin
- * @param {object} payload
- */
- sendToPlugin(payload) {
- this.send(this.uuid, Events.sendToPlugin, {
- action: this?.actionInfo?.action,
- payload: payload || null,
- });
- }
-
- /**
- * Save the actions's persistent data.
- * @param {object} payload
- */
- setSettings(payload) {
- this.send(this.uuid, Events.setSettings, {
- action: this?.actionInfo?.action,
- payload: payload || null,
- });
- }
-
- /**
- * Request the actions's persistent data. StreamDeck does not return the data, but trigger the actions's didReceiveSettings event
- */
- getSettings() {
- this.send(this.uuid, Events.getSettings);
- }
-}
-
-const $PI = new ELGSDPropertyInspector();
-
-/**
- * connectElgatoStreamDeckSocket
- * This is the first function StreamDeck Software calls, when
- * establishing the connection to the plugin or the Property Inspector
- * @param {string} port - The socket's port to communicate with StreamDeck software.
- * @param {string} uuid - A unique identifier, which StreamDeck uses to communicate with the plugin
- * @param {string} messageType - Identifies, if the event is meant for the property inspector or the plugin.
- * @param {string} appInfoString - Information about the host (StreamDeck) application
- * @param {string} actionInfo - Context is an internal identifier used to communicate to the host application.
- */
-function connectElgatoStreamDeckSocket(port, uuid, messageType, appInfoString, actionInfo) {
- const delay = window?.initialConnectionDelay || 0;
- setTimeout(() => {
- $PI.connect(port, uuid, messageType, appInfoString, actionInfo);
- }, delay);
-}
diff --git a/warudo.streamdeck.sdPlugin/libs/js/prototypes.js b/warudo.streamdeck.sdPlugin/libs/js/prototypes.js
deleted file mode 100644
index e3b84fe..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/prototypes.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/** reaches out for a magical global localization object, hopefully loaded by $SD and swaps the string **/
-String.prototype.lox = function () {
- var a = String(this);
- try {
- a = $localizedStrings[a] || a;
- } catch (b) {
- }
- return a;
-};
-
-String.prototype.sprintf = function (inArr) {
- let i = 0;
- const args = inArr && Array.isArray(inArr) ? inArr : arguments;
- return this.replace(/%s/g, function () {
- return args[i++];
- });
-};
-
-WebSocket.prototype.sendJSON = function (jsn, log) {
- if (log) {
- console.log('SendJSON', this, jsn);
- }
- // if (this.readyState) {
- this.send(JSON.stringify(jsn));
- // }
-};
diff --git a/warudo.streamdeck.sdPlugin/libs/js/stream-deck.js b/warudo.streamdeck.sdPlugin/libs/js/stream-deck.js
deleted file mode 100644
index 7b24d7d..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/stream-deck.js
+++ /dev/null
@@ -1,299 +0,0 @@
-///
-///
-
-var $localizedStrings = $localizedStrings || {};
-
-/**
- * @class StreamDeck
- * StreamDeck object containing all required code to establish
- * communication with SD-Software and the Property Inspector
- */
-class ELGSDStreamDeck extends ELGSDApi {
- constructor() {
- super();
- if (ELGSDStreamDeck.__instance) {
- return ELGSDStreamDeck.__instance;
- }
-
- ELGSDStreamDeck.__instance = this;
- }
-
- /**
- * Display alert triangle on actions key
- * @param {string} context
- */
- showAlert(context) {
- if (!context) {
- console.error('A context is required to showAlert on the key.');
- }
-
- this.send(context, Events.showAlert);
- }
-
- /**
- * Display ok check mark on actions key
- * @param {string} context
- */
- showOk(context) {
- if (!context) {
- console.error('A context is required to showOk on the key.');
- }
-
- this.send(context, Events.showOk);
- }
-
- /**
- * Save the actions's persistent data.
- * @param context
- * @param {object} payload
- */
- setSettings(context, payload) {
- this.send(context, Events.setSettings, {
- action: this?.actionInfo?.action,
- payload: payload || null,
- targetContext: context,
- });
- }
-
- /**
- * Request the actions's persistent data. StreamDeck does not return the data, but trigger the actions's didReceiveSettings event
- * @param {string} [context]
- */
- getSettings(context) {
- this.send(context, Events.getSettings);
- }
-
- /**
- * Set the state of the actions
- * @param {string} context
- * @param {number} [state]
- */
- setState(context, state) {
- if (!context) {
- console.error('A context is required when using setState.');
- }
-
- this.send(context, Events.setState, {
- payload: {
- state: 1 - Number(state === 0),
- },
- });
- }
-
- /**
- * Set the title of the action's key
- * @param {string} context
- * @param {string} title
- * @param [target]
- */
- setTitle(context, title = '', target = Constants.hardwareAndSoftware) {
- if (!context) {
- console.error('A key context is required for setTitle.');
- }
-
- this.send(context, Events.setTitle, {
- payload: {
- title: title ? `${title}` : '',
- target,
- },
- });
- }
-
- /**
- *
- * @param {string} context
- * @param {number} [target]
- */
- clearTitle(context, target) {
- if (!context) {
- console.error('A key context is required to clearTitle.');
- }
-
- this.setTitle(context, null, target);
- }
-
- /**
- * Send payload to property inspector
- * @param {string} context
- * @param {string} action
- * @param {object} payload
- */
- sendToPropertyInspector(context, action, payload = null) {
- if (typeof action != 'string') {
- console.error('An action UUID is required to sendToPropertyInspector.');
- }
-
- if (typeof context != 'string') {
- console.error('A key context is required to sendToPropertyInspector.');
- }
-
- this.send(context, Events.sendToPropertyInspector, {
- action,
- payload,
- });
- }
-
- /**
- * Set the actions key image
- * @param {string} context
- * @param {string} [image]
- * @param {number} [state]
- * @param {number} [target]
- */
- setImage(context, image, state, target = Constants.hardwareAndSoftware) {
- if (!context) {
- console.error('A key context is required for setImage.');
- }
-
- this.send(context, Events.setImage, {
- payload: {
- image,
- target,
- state,
- },
- });
- }
-
- /**
- * Set the properties of the layout on the Stream Deck + touch display
- * @param {*} context
- * @param {*} payload
- */
- setFeedback(context, payload) {
- if (!context) {
- console.error('A context is required for setFeedback.');
- }
-
- this.send(context, Events.setFeedback, {
- payload,
- });
- }
-
- /**
- * Set the active layout by ID or path for the Stream Deck + touch display
- * @param {*} context
- * @param {*} layout
- */
- setFeedbackLayout(context, layout) {
- if (!context) {
- console.error('A context is required for setFeedbackLayout.');
- }
-
- this.send(context, Events.setFeedbackLayout, {
- payload: { layout },
- });
- }
-
- /**
- * Registers a callback function for the deviceDidConnect event, which fires when a device is plugged in
- * @param {function} fn
- * @returns ELGSDStreamDeck
- */
- onDeviceDidConnect(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the deviceDidConnect event is required for onDeviceDidConnect.'
- );
- }
-
- this.on(Events.deviceDidConnect, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the deviceDidDisconnect event, which fires when a device is unplugged
- * @param {function} fn
- * @returns ELGSDStreamDeck
- */
- onDeviceDidDisconnect(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the deviceDidDisconnect event is required for onDeviceDidDisconnect.'
- );
- }
-
- this.on(Events.deviceDidDisconnect, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the applicationDidLaunch event, which fires when the application starts
- * @param {function} fn
- * @returns ELGSDStreamDeck
- */
- onApplicationDidLaunch(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the applicationDidLaunch event is required for onApplicationDidLaunch.'
- );
- }
-
- this.on(Events.applicationDidLaunch, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the applicationDidTerminate event, which fires when the application exits
- * @param {function} fn
- * @returns ELGSDStreamDeck
- */
- onApplicationDidTerminate(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the applicationDidTerminate event is required for onApplicationDidTerminate.'
- );
- }
-
- this.on(Events.applicationDidTerminate, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Registers a callback function for the systemDidWakeUp event, which fires when the computer wakes
- * @param {function} fn
- * @returns ELGSDStreamDeck
- */
- onSystemDidWakeUp(fn) {
- if (!fn) {
- console.error(
- 'A callback function for the systemDidWakeUp event is required for onSystemDidWakeUp.'
- );
- }
-
- this.on(Events.systemDidWakeUp, (jsn) => fn(jsn));
- return this;
- }
-
- /**
- * Switches to a readonly profile or returns to previous profile
- * @param {string} device
- * @param {string} [profile]
- */
- switchToProfile(device, profile) {
- if (!device) {
- console.error('A device id is required for switchToProfile.');
- }
-
- this.send(this.uuid, Events.switchToProfile, { device, payload: { profile } });
- }
-}
-
-const $SD = new ELGSDStreamDeck();
-
-/**
- * connectElgatoStreamDeckSocket
- * This is the first function StreamDeck Software calls, when
- * establishing the connection to the plugin or the Property Inspector
- * @param {string} port - The socket's port to communicate with StreamDeck software.
- * @param {string} uuid - A unique identifier, which StreamDeck uses to communicate with the plugin
- * @param {string} messageType - Identifies, if the event is meant for the property inspector or the plugin.
- * @param {string} appInfoString - Information about the host (StreamDeck) application
- * @param {string} actionInfo - Context is an internal identifier used to communicate to the host application.
- */
-function connectElgatoStreamDeckSocket(port, uuid, messageType, appInfoString, actionInfo) {
- const delay = window?.initialConnectionDelay || 0;
-
- setTimeout(() => {
- $SD.connect(port, uuid, messageType, appInfoString, actionInfo);
- }, delay);
-}
diff --git a/warudo.streamdeck.sdPlugin/libs/js/timers.js b/warudo.streamdeck.sdPlugin/libs/js/timers.js
deleted file mode 100644
index 5d74e36..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/timers.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/* global ESDTimerWorker */
-/*eslint no-unused-vars: "off"*/
-/*eslint-env es6*/
-
-let ESDTimerWorker = new Worker(URL.createObjectURL(
- new Blob([timerFn.toString().replace(/^[^{]*{\s*/, '').replace(/\s*}[^}]*$/, '')], {type: 'text/javascript'})
-));
-ESDTimerWorker.timerId = 1;
-ESDTimerWorker.timers = {};
-const ESDDefaultTimeouts = {
- timeout: 0,
- interval: 10
-};
-
-Object.freeze(ESDDefaultTimeouts);
-
-function _setTimer(callback, delay, type, params) {
- const id = ESDTimerWorker.timerId++;
- ESDTimerWorker.timers[id] = {callback, params};
- ESDTimerWorker.onmessage = (e) => {
- if (ESDTimerWorker.timers[e.data.id]) {
- if (e.data.type === 'clearTimer') {
- delete ESDTimerWorker.timers[e.data.id];
- } else {
- const cb = ESDTimerWorker.timers[e.data.id].callback;
- if (cb && typeof cb === 'function') cb(...ESDTimerWorker.timers[e.data.id].params);
- }
- }
- };
- ESDTimerWorker.postMessage({type, id, delay});
- return id;
-}
-
-function _setTimeoutESD(...args) {
- let [callback, delay = 0, ...params] = [...args];
- return _setTimer(callback, delay, 'setTimeout', params);
-}
-
-function _setIntervalESD(...args) {
- let [callback, delay = 0, ...params] = [...args];
- return _setTimer(callback, delay, 'setInterval', params);
-}
-
-function _clearTimeoutESD(id) {
- ESDTimerWorker.postMessage({type: 'clearTimeout', id}); // ESDTimerWorker.postMessage({type: 'clearInterval', id}); = same thing
- delete ESDTimerWorker.timers[id];
-}
-
-window.setTimeout = _setTimeoutESD;
-window.setInterval = _setIntervalESD;
-window.clearTimeout = _clearTimeoutESD; //timeout and interval share the same timer-pool
-window.clearInterval = _clearTimeoutESD;
-
-/** This is our worker-code
- * It is executed in it's own (global) scope
- * which is wrapped above @ `let ESDTimerWorker`
- */
-
-function timerFn() {
- /*eslint indent: ["error", 4, { "SwitchCase": 1 }]*/
-
- let timers = {};
- let debug = false;
- let supportedCommands = ['setTimeout', 'setInterval', 'clearTimeout', 'clearInterval'];
-
- function log(e) {
- console.log('Worker-Info::Timers', timers);
- }
-
- function clearTimerAndRemove(id) {
- if (timers[id]) {
- if (debug) console.log('clearTimerAndRemove', id, timers[id], timers);
- clearTimeout(timers[id]);
- delete timers[id];
- postMessage({type: 'clearTimer', id: id});
- if (debug) log();
- }
- }
-
- onmessage = function (e) {
- // first see, if we have a timer with this id and remove it
- // this automatically fulfils clearTimeout and clearInterval
- supportedCommands.includes(e.data.type) && timers[e.data.id] && clearTimerAndRemove(e.data.id);
- if (e.data.type === 'setTimeout') {
- timers[e.data.id] = setTimeout(() => {
- postMessage({id: e.data.id});
- clearTimerAndRemove(e.data.id); //cleaning up
- }, Math.max(e.data.delay || 0));
- } else if (e.data.type === 'setInterval') {
- timers[e.data.id] = setInterval(() => {
- postMessage({id: e.data.id});
- }, Math.max(e.data.delay || ESDDefaultTimeouts.interval));
- }
- };
-}
diff --git a/warudo.streamdeck.sdPlugin/libs/js/utils.js b/warudo.streamdeck.sdPlugin/libs/js/utils.js
deleted file mode 100644
index a7b84cc..0000000
--- a/warudo.streamdeck.sdPlugin/libs/js/utils.js
+++ /dev/null
@@ -1,94 +0,0 @@
-class Utils {
- /**
- * Returns the value from a form using the form controls name property
- * @param {Element | string} form
- * @returns
- */
- static getFormValue(form) {
- if (typeof form === 'string') {
- form = document.querySelector(form);
- }
-
- const elements = form?.elements;
-
- if (!elements) {
- console.error('Could not find form!');
- }
-
- const formData = new FormData(form);
- let formValue = {};
-
- formData.forEach((value, key) => {
- if (!Reflect.has(formValue, key)) {
- formValue[key] = value;
- return;
- }
- if (!Array.isArray(formValue[key])) {
- formValue[key] = [formValue[key]];
- }
- formValue[key].push(value);
- });
-
- return formValue;
- }
-
- /**
- * Sets the value of form controls using their name attribute and the jsn object key
- * @param {*} jsn
- * @param {Element | string} form
- */
- static setFormValue(jsn, form) {
- if (!jsn) {
- return;
- }
-
- if (typeof form === 'string') {
- form = document.querySelector(form);
- }
-
- const elements = form?.elements;
-
- if (!elements) {
- console.error('Could not find form!');
- }
-
- Array.from(elements)
- .filter((element) => element?.name)
- .forEach((element) => {
- const { name, type } = element;
- const value = name in jsn ? jsn[name] : null;
- const isCheckOrRadio = type === 'checkbox' || type === 'radio';
-
- if (value === null) return;
-
- if (isCheckOrRadio) {
- const isSingle = value === element.value;
- if (isSingle || (Array.isArray(value) && value.includes(element.value))) {
- element.checked = true;
- }
- } else {
- element.value = value ?? '';
- }
- });
- }
-
- /**
- * This provides a slight delay before processing rapid events
- * @param {number} wait - delay before processing function (recommended time 150ms)
- * @param {function} fn
- * @returns
- */
- static debounce(wait, fn) {
- let timeoutId = null;
- return (...args) => {
- window.clearTimeout(timeoutId);
- timeoutId = window.setTimeout(() => {
- fn.apply(null, args);
- }, wait);
- };
- }
-
- static delay(wait) {
- return new Promise((fn) => setTimeout(fn, wait));
- }
-}
diff --git a/warudo.streamdeck.sdPlugin/libs/package.json b/warudo.streamdeck.sdPlugin/libs/package.json
deleted file mode 100644
index 0b7a603..0000000
--- a/warudo.streamdeck.sdPlugin/libs/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "name": "streamdeck-sdk",
- "version": "1.0.0",
- "description": "An API for connecting to Stream Deck WebSockets.",
- "repository": {
- "type": "git",
- "url": "git+https://github.com/elgatosf/streamdeck-javascript-sdk.git"
- },
- "author": "Elgato",
- "bugs": {
- "url": "https://github.com/elgatosf/streamdeck-javascript-sdk/issues"
- },
- "homepage": "https://github.com/elgatosf/streamdeck-javascript-sdk#readme"
-}
diff --git a/warudo.streamdeck.sdPlugin/manifest.json b/warudo.streamdeck.sdPlugin/manifest.json
index 2d02eb5..10c03c6 100644
--- a/warudo.streamdeck.sdPlugin/manifest.json
+++ b/warudo.streamdeck.sdPlugin/manifest.json
@@ -6,7 +6,7 @@
"Name": "Warudo",
"Icon": "action/images/icon",
"URL": "https://warudo.app",
- "Version": "1.1.0",
+ "Version": "1.2.0",
"Software": {
"MinimumVersion": "5.0"
},
@@ -16,6 +16,11 @@
"MinimumVersion": "10"
}
],
+ "ApplicationsToMonitor": {
+ "windows": [
+ "Warudo.exe"
+ ]
+ },
"Category": "Warudo",
"CategoryIcon": "action/images/icon",
"Actions": [
diff --git a/warudo.streamdeck.sdPlugin/message.html b/warudo.streamdeck.sdPlugin/message.html
index 6a16129..ce9103d 100644
--- a/warudo.streamdeck.sdPlugin/message.html
+++ b/warudo.streamdeck.sdPlugin/message.html
@@ -2,46 +2,41 @@
-
-
-
-
- Warudo Message
-
-
-
-
-
+
+
+
+
+ Warudo Message
+
-
-
-
Receiver name
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/warudo.streamdeck.sdPlugin/js/pi.js b/warudo.streamdeck.sdPlugin/pi.js
similarity index 99%
rename from warudo.streamdeck.sdPlugin/js/pi.js
rename to warudo.streamdeck.sdPlugin/pi.js
index 367819f..ce6fab2 100644
--- a/warudo.streamdeck.sdPlugin/js/pi.js
+++ b/warudo.streamdeck.sdPlugin/pi.js
@@ -1,6 +1,5 @@
-///
-///
-///
+///
+///
console.log('Property Inspector loaded', $PI);
diff --git a/warudo.streamdeck.sdPlugin/toggle.html b/warudo.streamdeck.sdPlugin/toggle.html
index cc7759f..57ffbe9 100644
--- a/warudo.streamdeck.sdPlugin/toggle.html
+++ b/warudo.streamdeck.sdPlugin/toggle.html
@@ -2,42 +2,36 @@
-
-
-
-
-
Warudo Toggle
-
-
-
-
-
+
+
+
+
+
Warudo Toggle
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/warudo.streamdeck.sdPlugin/trigger.html b/warudo.streamdeck.sdPlugin/trigger.html
index 4c4b221..1324587 100644
--- a/warudo.streamdeck.sdPlugin/trigger.html
+++ b/warudo.streamdeck.sdPlugin/trigger.html
@@ -2,42 +2,35 @@
-
-
-
-
-
Warudo Trigger
-
-
-
-
-
+
+
+
+
+
Warudo Trigger
+
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+