From 37bffe6b9b4595caeb146c1df14a016b32601495 Mon Sep 17 00:00:00 2001 From: Fred Emmott Date: Wed, 9 Jan 2019 20:08:35 -0800 Subject: [PATCH] Add a streamdeck plugin Requires the jslib from the web UI copying in as 'StreamingRemote.js' --- .../app.html | 309 ++++ .../caret.svg | 3 + .../common.js | 1124 ++++++++++++ .../keys/recording-active.png | Bin 0 -> 6569 bytes .../keys/recording-changing.png | Bin 0 -> 6725 bytes .../keys/recording-stopped.png | Bin 0 -> 6437 bytes .../keys/streaming-active.png | Bin 0 -> 6939 bytes .../keys/streaming-changing.png | Bin 0 -> 7225 bytes .../keys/streaming-stopped.png | Bin 0 -> 6809 bytes .../manifest.json | 36 + .../pi.html | 96 + .../sdpi.css | 1605 +++++++++++++++++ 12 files changed, 3173 insertions(+) create mode 100644 com.fredemmott.streamingremote.sdPlugin/app.html create mode 100644 com.fredemmott.streamingremote.sdPlugin/caret.svg create mode 100644 com.fredemmott.streamingremote.sdPlugin/common.js create mode 100644 com.fredemmott.streamingremote.sdPlugin/keys/recording-active.png create mode 100644 com.fredemmott.streamingremote.sdPlugin/keys/recording-changing.png create mode 100644 com.fredemmott.streamingremote.sdPlugin/keys/recording-stopped.png create mode 100644 com.fredemmott.streamingremote.sdPlugin/keys/streaming-active.png create mode 100644 com.fredemmott.streamingremote.sdPlugin/keys/streaming-changing.png create mode 100644 com.fredemmott.streamingremote.sdPlugin/keys/streaming-stopped.png create mode 100644 com.fredemmott.streamingremote.sdPlugin/manifest.json create mode 100644 com.fredemmott.streamingremote.sdPlugin/pi.html create mode 100644 com.fredemmott.streamingremote.sdPlugin/sdpi.css diff --git a/com.fredemmott.streamingremote.sdPlugin/app.html b/com.fredemmott.streamingremote.sdPlugin/app.html new file mode 100644 index 0000000..c6417e1 --- /dev/null +++ b/com.fredemmott.streamingremote.sdPlugin/app.html @@ -0,0 +1,309 @@ + + + + + com.fredemmott.streamingRemote + + + + + + + + + + diff --git a/com.fredemmott.streamingremote.sdPlugin/caret.svg b/com.fredemmott.streamingremote.sdPlugin/caret.svg new file mode 100644 index 0000000..b69162a --- /dev/null +++ b/com.fredemmott.streamingremote.sdPlugin/caret.svg @@ -0,0 +1,3 @@ + + + diff --git a/com.fredemmott.streamingremote.sdPlugin/common.js b/com.fredemmott.streamingremote.sdPlugin/common.js new file mode 100644 index 0000000..e4807c4 --- /dev/null +++ b/com.fredemmott.streamingremote.sdPlugin/common.js @@ -0,0 +1,1124 @@ +/* global $SD, ControlCenterClient, REMOTESETTINGS, initializeControlCenterClient, $localizedStrings */ +/* exported initializeControlCenterClient, $localizedStrings, REMOTESETTINGS */ +/* eslint no-undef: "error", + curly: 0, + no-caller: 0 +*/ + +// eslint-disable-next-line no-use-before-define +var $localizedStrings = $localizedStrings || {}, + REMOTESETTINGS = REMOTESETTINGS || {}, + DestinationEnum = Object.freeze({ + HARDWARE_AND_SOFTWARE: 0, + HARDWARE_ONLY: 1, + SOFTWARE_ONLY: 2 + }), + // eslint-disable-next-line no-unused-vars + isQT = navigator.appVersion.includes('QtWebEngine'), + debug = debug || false, + debugLog = function () {}; + +const setDebugOutput = (debug) => (debug === true) ? console.log.bind(window.console) : function () {}; +debugLog = setDebugOutput(debug); + +// Create a wrapper to allow passing JSON to the socket +WebSocket.prototype.sendJSON = function (jsn, log) { + if (log) { + console.log('SendJSON', this, jsn); + } + // if (this.readyState) { + this.send(JSON.stringify(jsn)); + // } +}; + +/* eslint no-extend-native: ["error", { "exceptions": ["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++]; + }); +}; + +// eslint-disable-next-line no-unused-vars +const sprintf = (s, ...args) => { + let i = 0; + return s.replace(/%s/g, function () { + return args[i++]; + }); +}; + +const loadLocalization = (lang, pathPrefix) => { + Utils.readJson(`${pathPrefix}${lang}.json`, function (jsn) { + const manifest = Utils.parseJson(jsn); + $localizedStrings = manifest && manifest.hasOwnProperty('Localization') ? manifest['Localization'] : {}; + debugLog($localizedStrings); + }); +} + +var Utils = { + isUndefined: function (value) { + return typeof value === 'undefined'; + }, + isObject: function (o) { + return ( + typeof o === 'object' && + o !== null && + o.constructor && + o.constructor === Object + ); + }, + isPlainObject: function (o) { + return ( + typeof o === 'object' && + o !== null && + o.constructor && + o.constructor === Object + ); + }, + isArray: function (value) { + return Array.isArray(value); + }, + isNumber: function (value) { + return typeof value === 'number' && value !== null; + }, + isInteger (value) { + return typeof value === 'number' && value === Number(value); + }, + isString (value) { + return typeof value === 'string'; + }, + isImage (value) { + return value instanceof HTMLImageElement; + }, + isCanvas (value) { + return value instanceof HTMLCanvasElement; + }, + isValue: function (value) { + return !this.isObject(value) && !this.isArray(value); + }, + isNull: function (value) { + return value === null; + }, + toInteger: function (value) { + var INFINITY = 1 / 0, + MAX_INTEGER = 1.7976931348623157e308; + if (!value) { + return value === 0 ? value : 0; + } + value = Number(value); + if (value === INFINITY || value === -INFINITY) { + var sign = value < 0 ? -1 : 1; + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } +}; +Utils.minmax = function (v, min = 0, max = 100) { + return Math.min(max, Math.max(min, v)); +}; + +Utils.setDebugOutput = (debug) => { + return (debug === true) ? console.log.bind(window.console) : function () {}; +}; + +Utils.randomComponentName = function (len = 6) { + return `${Utils.randomLowerString(len)}-${Utils.randomLowerString(len)}`; +}; + +Utils.randomString = function (len = 8) { + return Array.apply(0, Array(len)) + .map(function () { + return (function (charset) { + return charset.charAt( + Math.floor(Math.random() * charset.length) + ); + })( + 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + ); + }) + .join(''); +}; + +Utils.rs = function (len = 8) { + return [...Array(len)].map(i => (~~(Math.random() * 36)).toString(36)).join(''); +}; + +Utils.randomLowerString = function (len = 8) { + return Array.apply(0, Array(len)) + .map(function () { + return (function (charset) { + return charset.charAt( + Math.floor(Math.random() * charset.length) + ); + })('abcdefghijklmnopqrstuvwxyz'); + }) + .join(''); +}; + +Utils.capitalize = function (str) { + return str.charAt(0).toUpperCase() + str.slice(1); +}; + +Utils.measureText = (text, font) => { + const canvas = Utils.measureText.canvas || (Utils.measureText.canvas = document.createElement("canvas")); + const ctx = canvas.getContext("2d"); + ctx.font = font || 'bold 10pt system-ui'; + return ctx.measureText(text).width; +}; + +Utils.fixName = (d, dName) => { + let i = 1; + const base = dName; + while (d[dName]) { + dName = `${base} (${i})` + i++; + } + return dName; +}; + +Utils.isEmptyString = (str) => { + return (!str || str.length === 0); +}; + +Utils.isBlankString = (str) => { + return (!str || /^\s*$/.test(str)); +}; + +Utils.log = function () {}; +Utils.count = 0; +Utils.counter = function () { + return (this.count += 1); +}; +Utils.getPrefix = function () { + return this.prefix + this.counter(); +}; + +Utils.prefix = Utils.randomString() + '_'; + +Utils.getUrlParameter = function (name) { + const nameA = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]'); + var regex = new RegExp('[\\?&]' + nameA + '=([^&#]*)'); + var results = regex.exec(location.search.replace(/\/$/, '')); + return results === null + ? null + : decodeURIComponent(results[1].replace(/\+/g, ' ')); +}; + +Utils.debounce = function (func, wait = 100) { + let timeout; + return function (...args) { + clearTimeout(timeout); + timeout = setTimeout(() => { + func.apply(this, args); + }, wait); + }; +}; + +Utils.getRandomColor = function () { + return '#' + (((1 << 24) * Math.random()) | 0).toString(16).padStart(6, 0); // just a random color padded to 6 characters +}; + +/* + Quick utility to lighten or darken a color (doesn't take color-drifting, etc. into account) + Usage: + fadeColor('#061261', 100); // will lighten the color + fadeColor('#200867'), -100); // will darken the color +*/ + +Utils.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); +} + +Utils.lerpColor = function (startColor, targetColor, amount) { + const ah = parseInt(startColor.replace(/#/g, ''), 16); + const ar = ah >> 16; + const ag = (ah >> 8) & 0xff; + const ab = ah & 0xff; + const bh = parseInt(targetColor.replace(/#/g, ''), 16); + const br = bh >> 16; + var bg = (bh >> 8) & 0xff; + var bb = bh & 0xff; + const rr = ar + amount * (br - ar); + const rg = ag + amount * (bg - ag); + const rb = ab + amount * (bb - ab); + + return ( + '#' + + (((1 << 24) + (rr << 16) + (rg << 8) + rb) | 0) + .toString(16) + .slice(1) + .toUpperCase() + ); +}; + +Utils.hexToRgb = function (hex) { + const match = hex.replace(/#/, '').match(/.{1,2}/g); + return { + r: parseInt(match[0], 16), + g: parseInt(match[1], 16), + b: parseInt(match[2], 16) + }; +}; + +Utils.rgbToHex = (r, g, b) => '#' + [r, g, b].map(x => { + return x.toString(16).padStart(2,0) +}).join('') + + +Utils.nscolorToRgb = function (rP, gP, bP) { + return { + r : Math.round(rP * 255), + g : Math.round(gP * 255), + b : Math.round(bP * 255) + } +}; + +Utils.nsColorToHex = function (rP, gP, bP) { + const c = Utils.nscolorToRgb(rP, gP, bP); + return Utils.rgbToHex(c.r, c.g, c.b); +}; + +Utils.miredToKelvin = function (mired) { + return 1e6 / mired; +}; + +Utils.kelvinToMired = function (kelvin) { + return 1e6 / kelvin; +}; + +Utils.getBrightness = function (hexColor) { + // http://www.w3.org/TR/AERT#color-contrast + if (typeof hexColor === 'string' && hexColor.charAt(0) === '#') { + var rgb = Utils.hexToRgb(hexColor); + return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; + } + return 0; +}; + +Utils.readJson = function (file, callback) { + var req = new XMLHttpRequest(); + req.onerror = function (e) { + // Utils.log(`[Utils][readJson] Error while trying to read ${file}`, e); + }; + req.overrideMimeType('application/json'); + req.open('GET', file, true); + req.onreadystatechange = function () { + if (req.readyState === 4) { + // && req.status == "200") { + if (callback) callback(req.responseText); + } + }; + req.send(null); +}; + +Utils.loadScript = function (url, callback) { + var el = document.createElement('script'); + el.src = url; + el.onload = function () { + callback(url, true); + }; + el.onerror = function () { + console.error('Failed to load file: ' + url); + callback(url, false); + }; + document.body.appendChild(el); +}; + +Utils.parseJson = function (jsonString) { + if (typeof jsonString === 'object') return jsonString; + try { + var o = JSON.parse(jsonString); + + // Handle non-exception-throwing cases: + // Neither JSON.parse(false) or JSON.parse(1234) throw errors, hence the type-checking, + // but... JSON.parse(null) returns null, and typeof null === "object", + // so we must check for that, too. Thankfully, null is falsey, so this suffices: + if (o && typeof o === 'object') { + return o; + } + } catch (e) {} + + return false; +}; + +Utils.parseJSONPromise = function (jsonString) { + // fetch('/my-json-doc-as-string') + // .then(Utils.parseJSONPromise) + // .then(heresYourValidJSON) + // .catch(error - or return default JSON) + + return new Promise((resolve, reject) => { + try { + resolve(JSON.parse(jsonString)); + } catch (e) { + reject(e); + } + }); +}; + +/* eslint-disable import/prefer-default-export */ +Utils.getProperty = function (obj, dotSeparatedKeys, defaultValue) { + if (arguments.length > 1 && typeof dotSeparatedKeys !== 'string') + return undefined; + if (typeof obj !== 'undefined' && typeof dotSeparatedKeys === 'string') { + const pathArr = dotSeparatedKeys.split('.'); + pathArr.forEach((key, idx, arr) => { + if (typeof key === 'string' && key.includes('[')) { + try { + // extract the array index as string + const pos = /\[([^)]+)\]/.exec(key)[1]; + // get the index string length (i.e. '21'.length === 2) + const posLen = pos.length; + arr.splice(idx + 1, 0, Number(pos)); + + // keep the key (array name) without the index comprehension: + // (i.e. key without [] (string of length 2) + // and the length of the index (posLen)) + arr[idx] = key.slice(0, -2 - posLen); // eslint-disable-line no-param-reassign + } catch (e) { + // do nothing + } + } + }); + // eslint-disable-next-line no-param-reassign, no-confusing-arrow + obj = pathArr.reduce( + (o, key) => (o && o[key] !== 'undefined' ? o[key] : undefined), + obj + ); + } + return obj === undefined ? defaultValue : obj; +}; + +Utils.getProp = (jsn, str, defaultValue = {}, sep = '.') => { + const arr = str.split(sep); + return arr.reduce((obj, key) => + (obj && obj.hasOwnProperty(key)) ? obj[key] : defaultValue, jsn); +}; + +Utils.setProp = function (jsonObj, path, value) { + const names = path.split('.'); + let jsn = jsonObj; + + // createNestedObject(jsn, names, values); + // If a value is given, remove the last name and keep it for later: + var targetProperty = arguments.length === 3 ? names.pop() : false; + + // Walk the hierarchy, creating new objects where needed. + // If the lastName was removed, then the last object is not set yet: + for (var i = 0; i < names.length; i++) { + jsn = jsn[names[i]] = jsn[names[i]] || {}; + } + + // If a value was given, set it to the target property (the last one): + if (targetProperty) jsn = jsn[targetProperty] = value; + + // Return the last object in the hierarchy: + return jsn; +}; + +Utils.getDataUri = function (url, callback, inCanvas, inFillcolor) { + var image = new Image(); + + image.onload = function () { + var canvas = + inCanvas && Utils.isCanvas(inCanvas) + ? inCanvas + : document.createElement('canvas'); + + canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size + canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size + + var ctx = canvas.getContext('2d'); + if (inFillcolor) { + ctx.fillStyle = inFillcolor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + ctx.drawImage(this, 0, 0); + // Get raw image data + // callback && callback(canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, '')); + + // ... or get as Data URI + callback(canvas.toDataURL('image/png')); + }; + + image.src = url; +}; + +/** Quick utility to inject a style to the DOM +* e.g. injectStyle('.localbody { background-color: green;}') +*/ +Utils.injectStyle = function (styles, styleId) { + const node = document.createElement('style'); + const tempID = styleId || Utils.randomString(8); + node.setAttribute('id', tempID); + node.innerHTML = styles; + document.body.appendChild(node); + return node; +}; + + +Utils.loadImage = function (inUrl, callback, inCanvas, inFillcolor) { + /** Convert to array, so we may load multiple images at once */ + const aUrl = !Array.isArray(inUrl) ? [inUrl] : inUrl; + const canvas = inCanvas && inCanvas instanceof HTMLCanvasElement + ? inCanvas + : document.createElement('canvas'); + var imgCount = aUrl.length - 1; + const imgCache = {}; + + var ctx = canvas.getContext('2d'); + ctx.globalCompositeOperation = 'source-over'; + + for (let url of aUrl) { + let image = new Image(); + let cnt = imgCount; + let w = 144, h = 144; + + image.onload = function () { + imgCache[url] = this; + // look at the size of the first image + if (url === aUrl[0]) { + canvas.width = this.naturalWidth; // or 'width' if you want a special/scaled size + canvas.height = this.naturalHeight; // or 'height' if you want a special/scaled size + } + // if (Object.keys(imgCache).length == aUrl.length) { + if (cnt < 1) { + if (inFillcolor) { + ctx.fillStyle = inFillcolor; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + // draw in the proper sequence FIFO + aUrl.forEach(e => { + if (!imgCache[e]) { + console.warn(imgCache[e], imgCache); + } + + if (imgCache[e]) { + ctx.drawImage(imgCache[e], 0, 0); + ctx.save(); + } + }); + + callback(canvas.toDataURL('image/png')); + // or to get raw image data + // callback && callback(canvas.toDataURL('image/png').replace(/^data:image\/(png|jpg);base64,/, '')); + } + }; + + imgCount--; + image.src = url; + } +}; + +Utils.getData = function (url) { + // Return a new promise. + return new Promise(function (resolve, reject) { + // Do the usual XHR stuff + var req = new XMLHttpRequest(); + // Make sure to call .open asynchronously + req.open('GET', url, true); + + req.onload = function () { + // This is called even on 404 etc + // so check the status + if (req.status === 200) { + // Resolve the promise with the response text + resolve(req.response); + } else { + // Otherwise reject with the status text + // which will hopefully be a meaningful error + reject(Error(req.statusText)); + } + }; + + // Handle network errors + req.onerror = function () { + reject(Error('Network Error')); + }; + + // Make the request + req.send(); + }); +}; + +Utils.negArray = function (arr) { + /** http://h3manth.com/new/blog/2013/negative-array-index-in-javascript/ */ + return Proxy.create({ + set: function (proxy, index, value) { + index = parseInt(index); + return index < 0 ? (arr[arr.length + index] = value) : (arr[index] = value); + }, + get: function (proxy, index) { + index = parseInt(index); + return index < 0 ? arr[arr.length + index] : arr[index]; + } + }); +}; + +Utils.onChange = function (object, callback) { + /** https://github.com/sindresorhus/on-change */ + 'use strict'; + const handler = { + get (target, property, receiver) { + try { + console.log('get via Proxy: ', property, target, receiver); + return new Proxy(target[property], handler); + } catch (err) { + console.log('get via Reflect: ', err, property, target, receiver); + return Reflect.get(target, property, receiver); + } + }, + set (target, property, value, receiver) { + console.log('Utils.onChange:set1:', target, property, value, receiver); + // target[property] = value; + const b = Reflect.set(target, property, value); + console.log('Utils.onChange:set2:', target, property, value, receiver); + return b; + }, + defineProperty (target, property, descriptor) { + console.log('Utils.onChange:defineProperty:', target, property, descriptor); + callback(target, property, descriptor); + return Reflect.defineProperty(target, property, descriptor); + }, + deleteProperty (target, property) { + console.log('Utils.onChange:deleteProperty:', target, property); + callback(target, property); + return Reflect.deleteProperty(target, property); + } + }; + + return new Proxy(object, handler); +}; + +Utils.observeArray = function (object, callback) { + 'use strict'; + const array = []; + const handler = { + get (target, property, receiver) { + try { + return new Proxy(target[property], handler); + } catch (err) { + return Reflect.get(target, property, receiver); + } + }, + set (target, property, value, receiver) { + console.log('XXXUtils.observeArray:set1:', target, property, value, array); + target[property] = value; + console.log('XXXUtils.observeArray:set2:', target, property, value, array); + }, + defineProperty (target, property, descriptor) { + callback(target, property, descriptor); + return Reflect.defineProperty(target, property, descriptor); + }, + deleteProperty (target, property) { + callback(target, property, descriptor); + return Reflect.deleteProperty(target, property); + } + }; + + return new Proxy(object, handler); +}; + +window['_'] = Utils; + +/** + * connectSocket + * This is the first function StreamDeck Software calls, when + * establishing the connection to the plugin or the Property Inspector + * @param {string} inPort - The socket's port to communicate with StreamDeck software. + * @param {string} inUUID - A unique identifier, which StreamDeck uses to communicate with the plugin + * @param {string} inMessageType - Identifies, if the event is meant for the property inspector or the plugin. + * @param {string} inApplicationInfo - Information about the host (StreamDeck) application + * @param {string} inActionInfo - Context is an internal identifier used to communicate to the host application. + **/ + +// eslint-disable-next-line no-unused-vars +function connectSocket ( + inPort, + inUUID, + inMessageType, + inApplicationInfo, + inActionInfo +) { + StreamDeck.getInstance().connect(arguments); + window.$SD.api = Object.assign({ send: SDApi.send }, SDApi.common, SDApi[inMessageType]); +} + +/** + * StreamDeck object containing all required code to establish + * communication with SD-Software and the Property Inspector + */ + +const StreamDeck = (function () { + // Hello it's me + var instance; + /* + Populate and initialize internally used properties + */ + + function init () { + // *** PRIVATE *** + + var inPort, + inUUID, + inMessageType, + inApplicationInfo, + inActionInfo, + websocket = null; + + var events = ELGEvents.eventEmitter(); + var logger = SDDebug.logger(); + + function showVars () { + debugLog('---- showVars'); + debugLog('- port', inPort); + debugLog('- uuid', inUUID); + debugLog('- messagetype', inMessageType); + debugLog('- info', inApplicationInfo); + debugLog('- inActionInfo', inActionInfo); + debugLog('----< showVars'); + } + + function connect (args) { + inPort = args[0]; + inUUID = args[1]; + inMessageType = args[2]; + inApplicationInfo = Utils.parseJson(args[3]); + inActionInfo = + args[4] !== 'undefined' ? Utils.parseJson(args[4]) : args[4]; + + /** Debug variables */ + if (debug) { + showVars(); + } + + const lang = Utils.getProp(inApplicationInfo,'application.language', false); + if (lang) loadLocalization(lang, inMessageType === 'registerPropertyInspector' ? '../' : './'); + + /** restrict the API to what's possible + * within Plugin or Property Inspector + * + */ + // $SD.api = SDApi[inMessageType]; + + if (websocket) { + websocket.close(); + websocket = null; + }; + + websocket = new WebSocket('ws://localhost:' + inPort); + + websocket.onopen = function () { + var json = { + event: inMessageType, + uuid: inUUID + }; + + // console.log('***************', inMessageType + " websocket:onopen", inUUID, json); + + websocket.sendJSON(json); + $SD.uuid = inUUID; + $SD.actionInfo = inActionInfo; + $SD.applicationInfo = inApplicationInfo; + $SD.messageType = inMessageType; + $SD.connection = websocket; + + instance.emit('connected', { + connection: websocket, + port: inPort, + uuid: inUUID, + actionInfo: inActionInfo, + applicationInfo: inApplicationInfo, + messageType: inMessageType + }); + }; + + websocket.onerror = function (evt) { + console.warn('WEBOCKET ERROR', evt, evt.data); + }; + + websocket.onclose = function (evt) { + // Websocket is closed + var reason = WEBSOCKETERROR(evt); + console.warn( + '[STREAMDECK]***** WEBOCKET CLOSED **** reason:', + reason + ); + }; + + websocket.onmessage = function (evt) { + var jsonObj = Utils.parseJson(evt.data), + m; + + // console.log('[STREAMDECK] websocket.onmessage ... ', jsonObj); + + if (!jsonObj.hasOwnProperty('action')) { + m = jsonObj.event; + // console.log('%c%s', 'color: white; background: red; font-size: 12px;', '[common.js]onmessage:', m); + } else { + switch (inMessageType) { + case 'registerPlugin': + m = jsonObj['action'] + '.' + jsonObj['event']; + break; + case 'registerPropertyInspector': + m = 'sendToPropertyInspector'; + break; + default: + console.log('%c%s', 'color: white; background: red; font-size: 12px;', '[STREAMDECK] websocket.onmessage +++++++++ PROBLEM ++++++++'); + console.warn('UNREGISTERED MESSAGETYPE:', inMessageType); + } + } + + if (m && m !== '') + events.emit(m, jsonObj); + }; + + instance.connection = websocket; + } + + return { + // *** PUBLIC *** + + uuid: inUUID, + on: events.on, + emit: events.emit, + connection: websocket, + connect: connect, + api: null, + logger: logger + }; + } + + return { + getInstance: function () { + if (!instance) { + instance = init(); + } + return instance; + } + }; +})(); + +// eslint-disable-next-line no-unused-vars +function initializeControlCenterClient () { + const settings = Object.assign(REMOTESETTINGS || {}, { debug: false }); + var $CC = new ControlCenterClient(settings); + window['$CC'] = $CC; + return $CC; +} + +/** 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 }); + } +}; + +/** SDApi + * This ist the main API to communicate between plugin, property inspector and + * application host. + * Internal functions: + * - setContext: sets the context of the current plugin + * - exec: prepare the correct JSON structure and send + * + * Methods exposed in the $SD.api alias + * Messages send from the plugin + * ----------------------------- + * - showAlert + * - showOK + * - setSettings + * - setTitle + * - setImage + * - sendToPropertyInspector + * + * Messages send from Property Inspector + * ------------------------------------- + * - sendToPlugin + * + * Messages received in the plugin + * ------------------------------- + * willAppear + * willDisappear + * keyDown + * keyUp + */ + +const SDApi = { + send: function (context, fn, payload, debug) { + /** Combine the passed JSON with the name of the event and it's context + * If the payload contains 'event' or 'context' keys, it will overwrite existing 'event' or 'context'. + * This function is non-mutating and thereby creates a new object containing + * all keys of the original JSON objects. + */ + // console.log("SEND...........", payload) + const pl = Object.assign({}, { event: fn, context: context }, payload); + + /** Check, if we have a connection, and if, send the JSON payload */ + if (debug) { + console.log('-----SDApi.send-----'); + console.log('context', context); + console.log(pl); + console.log(payload.payload); + console.log(JSON.stringify(payload.payload)); + console.log('-------'); + } + $SD.connection && $SD.connection.sendJSON(pl); + + /** + * DEBUG-Utility to quickly show the current payload in the Property Inspector. + */ + + if ( + $SD.connection && + [ + 'sendToPropertyInspector', + 'showOK', + 'showAlert', + 'setSettings' + ].indexOf(fn) === -1 + ) { + // console.log("send.sendToPropertyInspector", payload); + // this.sendToPropertyInspector(context, typeof payload.payload==='object' ? JSON.stringify(payload.payload) : JSON.stringify({'payload':payload.payload}), pl['action']); + } + }, + + registerPlugin: { + + /** Messages send from the plugin */ + showAlert: function (context) { + SDApi.send(context, 'showAlert', {}); + }, + + showOk: function (context) { + SDApi.send(context, 'showOk', {}); + }, + + setSettings: function (context, payload) { + SDApi.send(context, 'setSettings', { + payload: payload + }); + }, + + setState: function (context, payload) { + SDApi.send(context, 'setState', { + payload: { + 'state': 1 - Number(payload === 0) + } + }); + }, + + setTitle: function (context, title, target) { + SDApi.send(context, 'setTitle', { + payload: { + title: '' + title || '', + target: target || DestinationEnum.HARDWARE_AND_SOFTWARE + } + }); + }, + + setImage: function (context, img, target) { + SDApi.send(context, 'setImage', { + payload: { + image: img || '', + target: target || DestinationEnum.HARDWARE_AND_SOFTWARE + } + }); + }, + + sendToPropertyInspector: function (context, payload, action) { + SDApi.send(context, 'sendToPropertyInspector', { + action: action, + payload: payload + }); + }, + + showUrl2: function (context, urlToOpen) { + SDApi.send(context, 'openUrl', { + payload: { + url: urlToOpen + } + }); + } + }, + + /** Messages send from Property Inspector */ + + registerPropertyInspector: { + + sendToPlugin: function (piUUID, action, payload) { + SDApi.send( + piUUID, + 'sendToPlugin', + { + action: action, + payload: payload || {} + }, + false + ); + } + }, + + /** COMMON */ + + common: { + openUrl: function (context, urlToOpen) { + SDApi.send(context, 'openUrl', { + payload: { + url: urlToOpen + } + }); + }, + + test: function () { + console.log(this); + console.log(SDApi); + }, + + debugPrint: function (context, inString) { + // console.log("------------ DEBUGPRINT"); + // console.log([].slice.apply(arguments).join()); + // console.log("------------ DEBUGPRINT"); + SDApi.send(context, 'debugPrint', { + payload: [].slice.apply(arguments).join('.') || '' + }); + }, + + dbgSend: function (fn, context) { + /** lookup if an appropriate function exists */ + if ($SD.connection && this[fn] && typeof this[fn] === 'function') { + /** verify if type of payload is an object/json */ + const payload = this[fn](); + if (typeof payload === 'object') { + Object.assign({ event: fn, context: context }, payload); + $SD.connection && $SD.connection.sendJSON(payload); + } + } + console.log(this, fn, typeof this[fn], this[fn]()); + } + + } +}; + +/** SDDebug + * Utility to log the JSON structure of an incoming object + */ + +const SDDebug = { + logger: function (name, fn) { + const logEvent = jsn => { + console.log('____SDDebug.logger.logEvent'); + console.log(jsn); + debugLog('-->> Received Obj:', jsn); + debugLog('jsonObj', jsn); + debugLog('event', jsn['event']); + debugLog('actionType', jsn['actionType']); + debugLog('settings', jsn['settings']); + debugLog('coordinates', jsn['coordinates']); + debugLog('---'); + }; + + const logSomething = jsn => + console.log('____SDDebug.logger.logSomething'); + + return { logEvent, logSomething }; + } +}; + +/** + * This is the instance of the StreamDeck object. + * There's only one StreamDeck object, which carries + * connection parameters and handles communication + * to/from the software's PluginManager. + */ + +window.$SD = StreamDeck.getInstance(); +window.$SD.api = SDApi; + +function WEBSOCKETERROR (evt) { + // Websocket is closed + var reason = ''; + if (evt.code === 1000) { + reason = 'Normal Closure. The purpose for which the connection was established has been fulfilled.'; + } else if (evt.code === 1001) { + reason = 'Going Away. An endpoint is "going away", such as a server going down or a browser having navigated away from a page.'; + } else if (evt.code === 1002) { + reason = 'Protocol error. An endpoint is terminating the connection due to a protocol error'; + } else if (evt.code === 1003) { + reason = "Unsupported Data. An endpoint received a type of data it doesn't support."; + } else if (evt.code === 1004) { + reason = '--Reserved--. The specific meaning might be defined in the future.'; + } else if (evt.code === 1005) { + reason = 'No Status. No status code was actually present.'; + } else if (evt.code === 1006) { + reason = 'Abnormal Closure. The connection was closed abnormally, e.g., without sending or receiving a Close control frame'; + } else if (evt.code === 1007) { + reason = '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]).'; + } else if (evt.code === 1008) { + reason = '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.'; + } else if (evt.code === 1009) { + reason = 'Message Too Big. Connection closed because the message is too big for it to process.'; + } else if (evt.code === 1010) { // Note that this status code is not used by the server, because it can fail the WebSocket handshake instead. + reason = "Mandatory Ext. Connection is terminated the connection because the server didn't negotiate one or more extensions in the WebSocket handshake.
Mandatory extensions were: " + evt.reason; + } else if (evt.code === 1011) { + reason = 'Internl Server Error. Connection closed because it encountered an unexpected condition that prevented it from fulfilling the request.'; + } else if (evt.code === 1015) { + reason = "TLS Handshake. The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified)."; + } else { + reason = 'Unknown reason'; + } + + return reason; +} + +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' +}; diff --git a/com.fredemmott.streamingremote.sdPlugin/keys/recording-active.png b/com.fredemmott.streamingremote.sdPlugin/keys/recording-active.png new file mode 100644 index 0000000000000000000000000000000000000000..410e0898fd8381db672b273bcfd851b33ac8041d GIT binary patch literal 6569 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 UJpE+ketqsyQPfnZkuwkb7oniXVgLXD literal 0 HcmV?d00001 diff --git a/com.fredemmott.streamingremote.sdPlugin/keys/recording-changing.png b/com.fredemmott.streamingremote.sdPlugin/keys/recording-changing.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e15f7c25528fbca9d8e99b9b87d4bcf5ccc1c8 GIT binary patch literal 6725 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 E0MQ2-MF0Q* literal 0 HcmV?d00001 diff --git a/com.fredemmott.streamingremote.sdPlugin/keys/recording-stopped.png b/com.fredemmott.streamingremote.sdPlugin/keys/recording-stopped.png new file mode 100644 index 0000000000000000000000000000000000000000..2b56299ab3989f84b07c7ed6815f6041baec676a GIT binary patch literal 6437 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 literal 0 HcmV?d00001 diff --git a/com.fredemmott.streamingremote.sdPlugin/keys/streaming-active.png b/com.fredemmott.streamingremote.sdPlugin/keys/streaming-active.png new file mode 100644 index 0000000000000000000000000000000000000000..8dc1cbae6e9f487dbd3461fb9d6b281cc07405ad GIT binary patch literal 6939 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 JN8f!E@_z>kd*=WE literal 0 HcmV?d00001 diff --git a/com.fredemmott.streamingremote.sdPlugin/keys/streaming-changing.png b/com.fredemmott.streamingremote.sdPlugin/keys/streaming-changing.png new file mode 100644 index 0000000000000000000000000000000000000000..4ef4f031e517cb22bc3a8053f43128c81e9a75e5 GIT binary patch literal 7225 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 S=Uu$|&Qnv;RxFpd4EaCKbU~N^ literal 0 HcmV?d00001 diff --git a/com.fredemmott.streamingremote.sdPlugin/manifest.json b/com.fredemmott.streamingremote.sdPlugin/manifest.json new file mode 100644 index 0000000..69ed59b --- /dev/null +++ b/com.fredemmott.streamingremote.sdPlugin/manifest.json @@ -0,0 +1,36 @@ +{ + "Actions": [ + { + "Icon": "keys/streaming-changing", + "Name": "Streaming Remote", + "States": [ + { + "Image": "keys/streaming-changing", + "TitleAlignment": "middle", + "FontSize": "16" + } + ], + "SupportedInMultiActions": false, + "Tooltip": "Remotely control OBS and XSplit", + "UUID": "com.fredemmott.streamingremote.action" + } + ], + "Author": "Fred Emmott", + "CodePath": "app.html", + "Description": "Remotely control OBS and XSplit", + "Name": "Streaming Remote", + "Icon": "keys/streaming-changing", + "URL": "https://github.com/fredemmott/streaming-remote/", + "Version": "1.0", + "PropertyInspectorPath": "pi.html", + "OS": [ + { + "Platform": "mac", + "MinimumVersion": "10.11" + }, + { + "Platform": "windows", + "MinimumVersion": "10" + } + ] +} diff --git a/com.fredemmott.streamingremote.sdPlugin/pi.html b/com.fredemmott.streamingremote.sdPlugin/pi.html new file mode 100644 index 0000000..14d661b --- /dev/null +++ b/com.fredemmott.streamingremote.sdPlugin/pi.html @@ -0,0 +1,96 @@ + + + + + + com.fredemmott.streamingremote PI + + + + + + + + + + + + diff --git a/com.fredemmott.streamingremote.sdPlugin/sdpi.css b/com.fredemmott.streamingremote.sdPlugin/sdpi.css new file mode 100644 index 0000000..e768899 --- /dev/null +++ b/com.fredemmott.streamingremote.sdPlugin/sdpi.css @@ -0,0 +1,1605 @@ +html { + --sdpi-bgcolor: #2D2D2D; + --sdpi-background: #3D3D3D; + --sdpi-color: #d8d8d8; + --sdpi-bordercolor: #3a3a3a; + --sdpi-borderradius: 0px; + --sdpi-width: 224px; + --sdpi-fontweight: 600; + --sdpi-letterspacing: -0.25pt; + height: 100%; + width: 100%; + overflow: hidden; +} + +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); +} + +.hidden { + display: none; +} + +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); +} + + + +.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 { + /** + * 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 #D7DBDD; +} + +.tab { + cursor: pointer; + padding: 5px 30px; + color: #16a2d7; + font-size: 9pt; + border-bottom: 2px solid transparent; +} + +.tab.is-tab-selected { + border-bottom-color: #4ebbe4; +} + +select { + -webkit-appearance: none; + -moz-appearance: none; + -o-appearance: none; + appearance: none; + background: url(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-color); + border-radius: var(--sdpi-borderradius); + 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; +} + +.sdpi-item { + display: flex; + flex-direction: row; + min-height: 32px; + align-items: center; + margin-top: 2px; + max-width: 344px; +} + +.sdpi-item:first-child { + margin-top:1px; +} + +.sdpi-item:last-child { + margin-bottom: 0px; +} + +.sdpi-item > *:not(.sdpi-item-label):not(meter):not(details) { + min-height: 26px; + padding: 0px 4px 0px 4px; +} + +.sdpi-item > *:not(.sdpi-item-label.empty):not(meter) { + min-height: 26px; + padding: 0px 4px 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: 4px; + font-weight: 600; + -webkit-user-select: none; +} + +.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: 7px; + margin-right: 19px; +} + +.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; +} + +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; +} + +.sdpi-item-child, +.sdpi-item-group > .sdpi-item > input[type="color"] { + margin-top: 0.4em; + margin-right: 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.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: 106px; +} + +details.message h1 { + text-align: left; +} + +.message > summary::-webkit-details-marker { + display: none; +} + +.info20, +.question, +.caution, +.info { + background-repeat: no-repeat; + background-position: 70px 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; +} + +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; +} + +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; +} + +.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: 227px; + margin-left: 1px; +} + +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(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(rcheck.svg); +} + + +/* +input[type="radio"] + label span { + background: url(buttons.png) -38px top no-repeat; +} + +input[type="radio"]:checked + label span { + background: url(buttons.png) -57px top no-repeat; +} +*/ + +input[type="range"] { + width: var(--sdpi-width); + height: 30px; + overflow: hidden; + cursor: pointer; + background: transparent !important; +} + +.sdpi-item > input[type="range"] { + margin-left: 8px; + max-width: var(--sdpi-width); + width: var(--sdpi-width); + padding: 0px; +} + +/* +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: 221px; /*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(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; +} + +[title]:hover { + display: flex; + align-items: center; + justify-content: center; +} + +[title]:hover::after { + content: ''; + position: absolute; + bottom: -1000px; + left: 8px; + display: none; + color: #fff; + border: 8px solid transparent; + border-bottom: 8px solid #000; +} +[title]:hover::before { +content: attr(title); + display: flex; + justify-content: center; + align-self: center; + padding: 6px 12px; + border-radius: 5px; + background: rgba(0,0,0,0.8); + color: var(--sdpi-color); + font-size: 9pt; + font-family: sans-serif; + opacity: 1; + position: absolute; + height: auto; + /* width: 50%; + left: 35%; */ + text-align: center; + bottom: 2px; + z-index: 100; + box-shadow: 0px 3px 6px rgba(0, 0, 0, .5); + /* box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); */ +} + +.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); +} + +::-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; +} + +:disabled { + color: #993333; +} + +select, +select option { + color: var(--sdpi-color); +} + +select.disabled, +select option:disabled { + color: #fd9494; + font-style: italic; +} + +.runningAppsContainer { + display: none; +} + +/* debug +div { + background-color: rgba(64,128,255,0.2); +} +*/ + +.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; +} + + +/** +input[type=range].vVertical { + -webkit-appearance: none; + background-color: green; + margin-left: -60px; + width: 100px; + height:6px; + margin-top: 0px; + transform:rotate(90deg); + z-index: 0; + overflow: visible; +} + +input[type=range].vHorizon { + -webkit-appearance: none; + background-color: pink; + height: 10px; + width:200px; + +} + +.test2 { + background-color: #00ff0020; + display: flex; +} + + +.vertical.sdpi-item[type="range"] .sdpi-item-value { + display: block; +} + + +.vertical.sdpi-item:first-child, +.vertical { + margin-top: 12px; + margin-bottom: 16px; +} +.vertical > .sdpi-item-value { + margin-right: 16px; +} + +.vertical .sdpi-item-group { + width: 100%; + display: flex; + justify-content: space-evenly; +} + +.vertical input[type=range] { + height: 100px; + width: 21px; + -webkit-appearance: slider-vertical; + display: flex; + flex-flow: column; +} + +.vertical input[type="range"]::-webkit-slider-runnable-track { + height: auto; + width: 5px; +} + +.vertical input[type="range"]::-webkit-slider-thumb { + margin-top: 0px; + margin-left: -6px; +} + +.vertical .sdpi-item-value { + flex-flow: column; + align-items: flex-start; +} + +.vertical.sdpi-item[type="range"] .sdpi-item-value { + align-items: center; + margin-right: 16px; + text-align: center; +} + +.vertical.sdpi-item[type="range"] .sdpi-item-value span, +.vertical input[type="range"] .sdpi-item-value span { + text-align: center; + margin: 4px 0px; +} +*/ + +/* +.file { + box-sizing: border-box; + display: block; + overflow: hidden; + padding: 10px; + position: relative; + text-indent: 100%; + white-space: nowrap; + height: 190px; + width: 160px; +} +.file::before { + content: ""; + display: block; + position: absolute; + top: 10px; + left: 10px; + height: 170px; + width: 140px; +} +.file::after { + content: ""; + height: 90px; + width: 90px; + position: absolute; + right: 0; + bottom: 0; + overflow: visible; +} + +.list--files { + display: flex; + flex-wrap: wrap; + justify-content: center; + margin: auto; + padding: 30px 0; + width: 630px; +} +.list--files > li { + margin: 0; + padding: 15px; +} + +.type-document::before { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxNDBweCIgaGVpZ2h0PSIxNzBweCIgdmlld0JveD0iMCAwIDE0MCAxNzAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0E3QTlBQyIgZD0iTTAsMHYxNzBoMTQwVjBIMHogTTEzMCwxNjBIMTBWMTBoMTIwVjE2MHogTTExMCw0MEgzMFYzMGg4MFY0MHogTTExMCw2MEgzMFY1MGg4MFY2MHogTTExMCw4MEgzMFY3MGg4MFY4MHoNCiAgIE0xMTAsMTAwSDMwVjkwaDgwVjEwMHogTTExMCwxMjBIMzB2LTEwaDgwVjEyMHogTTkwLDE0MEgzMHYtMTBoNjBWMTQweiIvPg0KPC9zdmc+); +} + +.type-image { + height: 160px; +} +.type-image::before { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxNDBweCIgaGVpZ2h0PSIxNDBweCIgdmlld0JveD0iMCAwIDE0MCAxNDAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDE0MCAxNDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxwYXRoIGZpbGw9IiNBN0E5QUMiIGQ9Ik0wLDB2MTQwaDE0MFYwSDB6IE0xMzAsMTMwSDEwVjEwaDEyMFYxMzB6Ii8+DQogIDxwb2x5Z29uIGZpbGw9IiNFNkU3RTgiIHBvaW50cz0iOTAsMTEwIDQwLDQwIDEwLDgwIDEwLDEzMCA5MCwxMzAgICIvPg0KICA8cG9seWdvbiBmaWxsPSIjRDFEM0Q0IiBwb2ludHM9IjEwLDEzMCA1MCw5MCA2MCwxMDAgMTAwLDYwIDEzMCwxMzAgICIvPg0KPC9nPg0KPC9zdmc+); + height: 140px; +} + +.state-synced::after { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5MHB4IiBoZWlnaHQ9IjkwcHgiIHZpZXdCb3g9IjAgMCA5MCA5MCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTAgOTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxjaXJjbGUgZmlsbD0iIzAwQTY1MSIgY3g9IjQ1IiBjeT0iNDUiIHI9IjQ1Ii8+DQogIDxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0yMCw0NUwyMCw0NWMtMi44LDIuOC0yLjgsNy4yLDAsMTBsMTAuMSwxMC4xYzIuNywyLjcsNy4yLDIuNyw5LjksMEw3MCwzNWMyLjgtMi44LDIuOC03LjIsMC0xMGwwLDANCiAgICBjLTIuOC0yLjgtNy4yLTIuOC0xMCwwTDM1LDUwbC01LTVDMjcuMiw0Mi4yLDIyLjgsNDIuMiwyMCw0NXoiLz4NCjwvZz4NCjwvc3ZnPg==); +} + +.state-deleted::after { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5MHB4IiBoZWlnaHQ9IjkwcHgiIHZpZXdCb3g9IjAgMCA5MCA5MCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTAgOTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxjaXJjbGUgZmlsbD0iI0VEMUMyNCIgY3g9IjQ1IiBjeT0iNDUiIHI9IjQ1Ii8+DQogIDxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik02NSwyNUw2NSwyNWMtMi44LTIuOC03LjItMi44LTEwLDBMNDUsMzVMMzUsMjVjLTIuOC0yLjgtNy4yLTIuOC0xMCwwbDAsMGMtMi44LDIuOC0yLjgsNy4yLDAsMTBsMTAsMTANCiAgICBMMjUsNTVjLTIuOCwyLjgtMi44LDcuMiwwLDEwbDAsMGMyLjgsMi44LDcuMiwyLjgsMTAsMGwxMC0xMGwxMCwxMGMyLjgsMi44LDcuMiwyLjgsMTAsMGwwLDBjMi44LTIuOCwyLjgtNy4yLDAtMTBMNTUsNDVsMTAtMTANCiAgICBDNjcuOCwzMi4yLDY3LjgsMjcuOCw2NSwyNXoiLz4NCjwvZz4NCjwvc3ZnPg==); +} +.state-deleted::before { + opacity: .25; +} + +.state-locked::after { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5MHB4IiBoZWlnaHQ9IjkwcHgiIHZpZXdCb3g9IjAgMCA5MCA5MCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTAgOTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxjaXJjbGUgZmlsbD0iIzU4NTk1QiIgY3g9IjQ1IiBjeT0iNDUiIHI9IjQ1Ii8+DQogIDxyZWN0IHg9IjIwIiB5PSI0MCIgZmlsbD0iI0ZGRkZGRiIgd2lkdGg9IjUwIiBoZWlnaHQ9IjMwIi8+DQogIDxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0zMi41LDQ2LjVjLTIuOCwwLTUtMi4yLTUtNVYyOWMwLTkuNiw3LjktMTcuNSwxNy41LTE3LjVTNjIuNSwxOS40LDYyLjUsMjljMCwyLjgtMi4yLDUtNSw1cy01LTIuMi01LTUNCiAgICBjMC00LjEtMy40LTcuNS03LjUtNy41cy03LjUsMy40LTcuNSw3LjV2MTIuNUMzNy41LDQ0LjMsMzUuMyw0Ni41LDMyLjUsNDYuNXoiLz4NCjwvZz4NCjwvc3ZnPg==); +} + + + +html { + --fheight: 95px; + --fwidth: 80px; + --fspacing: 5px; + --ftotalwidth: 315px; + --bgsize: 50%; + --bgsize2: cover; + --bgsize3: contain; +} + +ul { + list-style: none; +} + + +.file { + height: var(--fheight); + width: var(--fwidth); +} +.file::before { + content: ""; + display: block; + position: absolute; + top: var(--fspacing); + left: var(--fspacing); + height: calc(var(--fheight) - var(--fspacing)*2); + width: calc(var(--fwidth) - var(--fspacing)*2); +} +.file::after { + content: ""; + height: calc(var(--fheight)/2); + width: calc(var(--fheight)/2); + position: absolute; + right: 0; + bottom: 0; + overflow: visible; +} + +.list--files { + display: flex; + flex-wrap: wrap; + justify-content: center; + margin: auto; + padding: calc(var(--fspacing)*3) 0; + width: var(--ftotalwidth); +} +.list--files > li { + margin: 0; + padding: var(--fspacing); +} + +.type-document::before { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxNDBweCIgaGVpZ2h0PSIxNzBweCIgdmlld0JveD0iMCAwIDE0MCAxNzAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPHBhdGggZmlsbD0iI0E3QTlBQyIgZD0iTTAsMHYxNzBoMTQwVjBIMHogTTEzMCwxNjBIMTBWMTBoMTIwVjE2MHogTTExMCw0MEgzMFYzMGg4MFY0MHogTTExMCw2MEgzMFY1MGg4MFY2MHogTTExMCw4MEgzMFY3MGg4MFY4MHoNCiAgIE0xMTAsMTAwSDMwVjkwaDgwVjEwMHogTTExMCwxMjBIMzB2LTEwaDgwVjEyMHogTTkwLDE0MEgzMHYtMTBoNjBWMTQweiIvPg0KPC9zdmc+); + height: calc(var(--fheight) - var(--fspacing)*2); + background-size: var(--bgsize2); + background-repeat: no-repeat; +} + +.type-image { + height: var(--fwidth); + height: calc(var(--fheight) - var(--fspacing)*2); +} +.type-image::before { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIxNDBweCIgaGVpZ2h0PSIxNDBweCIgdmlld0JveD0iMCAwIDE0MCAxNDAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDE0MCAxNDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxwYXRoIGZpbGw9IiNBN0E5QUMiIGQ9Ik0wLDB2MTQwaDE0MFYwSDB6IE0xMzAsMTMwSDEwVjEwaDEyMFYxMzB6Ii8+DQogIDxwb2x5Z29uIGZpbGw9IiNFNkU3RTgiIHBvaW50cz0iOTAsMTEwIDQwLDQwIDEwLDgwIDEwLDEzMCA5MCwxMzAgICIvPg0KICA8cG9seWdvbiBmaWxsPSIjRDFEM0Q0IiBwb2ludHM9IjEwLDEzMCA1MCw5MCA2MCwxMDAgMTAwLDYwIDEzMCwxMzAgICIvPg0KPC9nPg0KPC9zdmc+); + height: calc(var(--fheight) - var(--fspacing)*2); + background-size: var(--bgsize3); + background-repeat: no-repeat; +} + +.state-synced::after { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5MHB4IiBoZWlnaHQ9IjkwcHgiIHZpZXdCb3g9IjAgMCA5MCA5MCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTAgOTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxjaXJjbGUgZmlsbD0iIzAwQTY1MSIgY3g9IjQ1IiBjeT0iNDUiIHI9IjQ1Ii8+DQogIDxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0yMCw0NUwyMCw0NWMtMi44LDIuOC0yLjgsNy4yLDAsMTBsMTAuMSwxMC4xYzIuNywyLjcsNy4yLDIuNyw5LjksMEw3MCwzNWMyLjgtMi44LDIuOC03LjIsMC0xMGwwLDANCiAgICBjLTIuOC0yLjgtNy4yLTIuOC0xMCwwTDM1LDUwbC01LTVDMjcuMiw0Mi4yLDIyLjgsNDIuMiwyMCw0NXoiLz4NCjwvZz4NCjwvc3ZnPg==); + background-size: var(--bgsize); + background-repeat: no-repeat; + background-position: bottom right; +} + +.state-deleted::after { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5MHB4IiBoZWlnaHQ9IjkwcHgiIHZpZXdCb3g9IjAgMCA5MCA5MCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTAgOTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxjaXJjbGUgZmlsbD0iI0VEMUMyNCIgY3g9IjQ1IiBjeT0iNDUiIHI9IjQ1Ii8+DQogIDxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik02NSwyNUw2NSwyNWMtMi44LTIuOC03LjItMi44LTEwLDBMNDUsMzVMMzUsMjVjLTIuOC0yLjgtNy4yLTIuOC0xMCwwbDAsMGMtMi44LDIuOC0yLjgsNy4yLDAsMTBsMTAsMTANCiAgICBMMjUsNTVjLTIuOCwyLjgtMi44LDcuMiwwLDEwbDAsMGMyLjgsMi44LDcuMiwyLjgsMTAsMGwxMC0xMGwxMCwxMGMyLjgsMi44LDcuMiwyLjgsMTAsMGwwLDBjMi44LTIuOCwyLjgtNy4yLDAtMTBMNTUsNDVsMTAtMTANCiAgICBDNjcuOCwzMi4yLDY3LjgsMjcuOCw2NSwyNXoiLz4NCjwvZz4NCjwvc3ZnPg==); + background-size: var(--bgsize); + background-repeat: no-repeat; + background-position: bottom right; +} +.state-deleted::before { + opacity: .25; +} + +.state-locked::after { + background-image: url(data:image/svg+xml;charset=utf-8;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiDQogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczphPSJodHRwOi8vbnMuYWRvYmUuY29tL0Fkb2JlU1ZHVmlld2VyRXh0ZW5zaW9ucy8zLjAvIg0KICAgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSI5MHB4IiBoZWlnaHQ9IjkwcHgiIHZpZXdCb3g9IjAgMCA5MCA5MCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgOTAgOTAiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQogIDxjaXJjbGUgZmlsbD0iIzU4NTk1QiIgY3g9IjQ1IiBjeT0iNDUiIHI9IjQ1Ii8+DQogIDxyZWN0IHg9IjIwIiB5PSI0MCIgZmlsbD0iI0ZGRkZGRiIgd2lkdGg9IjUwIiBoZWlnaHQ9IjMwIi8+DQogIDxwYXRoIGZpbGw9IiNGRkZGRkYiIGQ9Ik0zMi41LDQ2LjVjLTIuOCwwLTUtMi4yLTUtNVYyOWMwLTkuNiw3LjktMTcuNSwxNy41LTE3LjVTNjIuNSwxOS40LDYyLjUsMjljMCwyLjgtMi4yLDUtNSw1cy01LTIuMi01LTUNCiAgICBjMC00LjEtMy40LTcuNS03LjUtNy41cy03LjUsMy40LTcuNSw3LjV2MTIuNUMzNy41LDQ0LjMsMzUuMyw0Ni41LDMyLjUsNDYuNXoiLz4NCjwvZz4NCjwvc3ZnPg==); + background-size: var(--bgsize); + background-repeat: no-repeat; + background-position: bottom right; +} +*/