]> OzVa Git service - delta-velorum/commitdiff
Bulk commit corry ):
authorMax Value <greenwoodw50@gmail.com>
Wed, 13 May 2026 20:13:58 +0000 (21:13 +0100)
committerMax Value <greenwoodw50@gmail.com>
Wed, 13 May 2026 20:13:58 +0000 (21:13 +0100)
33 files changed:
argo/__init__.py
argo/admin.py
argo/src/admin.ts
argo/src/image.ts [new file with mode: 0644]
argo/src/marquee.ts [new file with mode: 0644]
argo/src/time.ts
argo/src/update.ts
argo/src/utils.ts
argo/static/admin.css
argo/static/media/assets/strap1.svg [new file with mode: 0644]
argo/static/style.css
argo/static/style/bottom_box.css [new file with mode: 0644]
argo/static/style/bottom_graphic.css [new file with mode: 0644]
argo/static/style/box.css
argo/static/style/crawler_marquee.css [new file with mode: 0644]
argo/static/style/crawler_outer_box.css [new file with mode: 0644]
argo/static/style/crawler_timer_box.css [new file with mode: 0644]
argo/static/style/crawler_top.css [new file with mode: 0644]
argo/static/style/discount_box.css
argo/static/style/item_box.css
argo/static/style/logo_box.css
argo/static/style/monthly_box.css [new file with mode: 0644]
argo/static/style/pricing_box.css
argo/static/style/side_box.css
argo/static/style/side_timer_box.css
argo/static/style/spin_box.css [new file with mode: 0644]
argo/templates/admin.html
argo/templates/admin/timer.html [new file with mode: 0644]
argo/templates/admin/toggle.html [new file with mode: 0644]
argo/templates/index.html
argo/templates/info/c.html
argo/templates/table.html
requirements.txt

index 2b0c68570542350b09ad269382319096e42fe41d..f3e03d624b31091ff7592d297290d3d7360e1248 100644 (file)
@@ -42,6 +42,10 @@ def index():
 def connecting():
        emit("update", database_read_views(), json=True, namespace="/", broadcast=True)
 
+@app.route("/data", methods=["get"])
+def data():
+       return database_read_views()
+
 # info screen pages
 
 @app.route("/info/<string:screen>", methods=["get"])
index dac3bb51c28c9c8b6700f315f58711bf2c3a65b0..65e4cb57f6ed1754dde5dae7343c39ecaf8abd3b 100644 (file)
@@ -1,6 +1,8 @@
 from flask import render_template, request
 from flask_socketio import emit
+from glob import glob
 import time
+import os
 
 from argo.database.read import read_indexes as database_read_indexes
 from argo.database.read import read_views as database_read_views
@@ -10,9 +12,14 @@ from argo.database.read import read as database_read
 from argo import STAR
 
 def admin_main():
+       from argo import app
+       assets = glob(os.path.join(app.root_path, "static", "media", "assets", "*"))
+       assets = [path.split("argo")[-1] for path in assets]
+
        return render_template(
                "admin.html",
                indexes=database_read_indexes(),
+               assets=assets,
                star=STAR
                )
 
index 22e72e368fadd66651bbe7e1a3879e44aeb1c93d..fdc2e656e04cef663c436358ece9d64b94993399 100644 (file)
@@ -38,3 +38,50 @@ export function setupTrigger() {
                })
        }
 }
+
+export function setupTimerButtons() {
+       // setup all timer control buttons
+       const el: HTMLCollectionOf<Element> =
+               document.getElementsByClassName("timer");
+
+       for (let e of el) {
+               e.addEventListener("click", (event) => {
+                       if (event.target instanceof HTMLElement) {
+                               let delay = document.getElementById(`${event.target.getAttribute('name')}+delay`);
+
+                               if (delay instanceof HTMLInputElement) {
+                                       delay.value = eval(`${delay.value}${event.target.getAttribute('value')}`);
+                               }
+                       }
+               })
+       }
+}
+
+export function setupClipboard() {
+       // copy previous links href to the clipboard
+       const el: HTMLCollectionOf<Element> =
+               document.getElementsByClassName("clipboard");
+
+       for (let e of el) {
+               const button = document.createElement("button");
+               button.innerHTML = "Copy Link";
+
+               button.addEventListener("click", (event) => {
+                       const button = event.target;
+                       if (button instanceof HTMLElement) {
+                               const link = button.previousElementSibling;
+                               if (link instanceof HTMLAnchorElement) {
+                                       navigator.clipboard.writeText(link["href"]);
+                                       button.innerHTML = "Copied!";
+                                       setTimeout(function () {
+                                               button.innerHTML = "Copy Link";
+                                       }, 1000)
+                               }
+                       }
+               })
+
+               if (e.parentNode instanceof HTMLElement) {
+                       e.parentNode.insertBefore(button, e.nextSibling);
+               }
+       }
+}
diff --git a/argo/src/image.ts b/argo/src/image.ts
new file mode 100644 (file)
index 0000000..f26cef0
--- /dev/null
@@ -0,0 +1,12 @@
+export default function renderImage(): void {
+       const el: HTMLCollectionOf<Element> =
+               document.getElementsByClassName("image");
+
+       for (let e of el) {
+               if (e instanceof HTMLImageElement) {
+                       if (typeof e.dataset.raw === "string") {
+                               e.src = `${e.dataset.raw}?${new Date().getTime()}` // cachebreaker!
+                       }
+               }
+       }
+}
diff --git a/argo/src/marquee.ts b/argo/src/marquee.ts
new file mode 100644 (file)
index 0000000..91a7d32
--- /dev/null
@@ -0,0 +1,56 @@
+const marqueeInterval: number = 20; //ms
+
+export default function setupMarquee(): void {
+       const el: HTMLCollectionOf<Element> =
+               document.getElementsByClassName("marquee");
+
+       for (let e of el) {
+               if (e instanceof HTMLElement) {
+                       e.dataset.current = "0";
+                       setInterval(function() {
+                               const box = e.parentNode;
+                               if (box instanceof HTMLElement) {
+                                       let inner = e.getBoundingClientRect().right;
+                                       let outer = box.getBoundingClientRect().left;
+                                       let width = box.getBoundingClientRect().width;
+
+                                       if (inner - outer < 0) {
+                                               randomPopulate(e);
+
+                                               e.style = `transform: translateX(${width}px);`
+                                               e.dataset.current = width as unknown as string;
+                                       }
+
+                                       let position = e.dataset.current as unknown as number - 1;
+                                       e.style = `transform: translateX(${position}px);`
+                                       e.dataset.current = position as unknown as string;
+                               }
+                       }, marqueeInterval);
+               }
+       }
+}
+
+function randomPopulate(e: HTMLElement) {
+       if (typeof e.dataset.raw === "string") {
+               let data = eval(e.dataset.raw);
+               if (data instanceof Array) {
+                       if (data.length == 0) { return }
+                       else {
+                               let index = randomInt(0, data.length);
+
+                               while (index as unknown as string == e.dataset.index) {
+                                       index = randomInt(0, data.length);
+                               }
+
+                               e.innerHTML = data[index];
+                               e.dataset.index = index as unknown as string;
+                       }
+               } else if (typeof data == "string") { // UNTESTED
+                       e.innerHTML = data;
+               }
+       }
+}
+
+function randomInt(min: number, max: number): number {
+       return Math.floor(Math.random() * (max - min) + min)
+}
index 84b69f3166b65d0134bacf24ab88dc3a53e7f235..6ab52c08f0815b8cc3888a1d9ef72716e7ea6317 100644 (file)
@@ -1,4 +1,10 @@
-import { timeSince, timeUntil, timeFormatBroadcast } from "./utils.js";
+import {
+       timeSince,
+       timeUntil,
+       timeFormatBroadcast,
+       timeFormatStandard,
+       timeFormatState
+} from "./utils.js";
 
 const timeUpdate: number = 1000; // ms
 
@@ -34,13 +40,33 @@ export function setupTimeUntil(): void {
                setInterval(
                        function () {
                                const el: HTMLCollectionOf<Element> =
-                               document.getElementsByClassName("until");
+                                       document.getElementsByClassName("until");
 
                                for (let e of el) {
                                        if (e instanceof HTMLElement) {
                                                if (typeof e.dataset.raw === "string") {
-                                                       let [hours, minutes, seconds] = timeUntil(eval(e.dataset.raw))
-                                                       e.innerHTML = timeFormatBroadcast(hours, minutes, seconds);
+                                                       let [hours, minutes, seconds, totalSeconds] = timeUntil(eval(e.dataset.raw))
+
+                                                       let length = e.dataset.raw.split("+")[1] as unknown as number;
+                                                       let percent = (totalSeconds / length) * 100
+                                                       e.style = `--percent: ${percent}%;`
+
+                                                       // populate
+                                                       if (e.classList.contains("until-broadcast")) {          // broadcast timer
+                                                               e.innerHTML = timeFormatBroadcast(hours, minutes, seconds);
+                                                       } else if (e.classList.contains("until-timeout")) {     // state changes when run down
+                                                               e.dataset.timeout = timeFormatState(hours, minutes, seconds);
+                                                       } else if (e.classList.contains("until-sound")) {       // play sounds when run down
+                                                               let timeout: string = timeFormatState(hours, minutes, seconds);
+                                                               if (timeout == "true" && e.dataset.last == "false") {
+                                                                       if (e instanceof HTMLMediaElement) {
+                                                                               e.play();
+                                                                       }
+                                                               }
+                                                               e.dataset.last = timeout;
+                                                       } else {                                                                                        // standard timer (MM:SS)
+                                                               e.innerHTML = timeFormatStandard(hours, minutes, seconds);
+                                                       }
                                                }
                                        }
                                }
index f122da31bc1bf1267deba374f1189be8d22a5e85..6a984d5e50869fa7f4bf25efc14b05b30ffe4a3b 100644 (file)
@@ -5,13 +5,16 @@ import { setupTimeSince, setupTimeUntil } from "./time.js";
 import { setupSounds, playSounds } from "./sound.js";
 import { setupStyle, renderStyle } from "./style.js";
 import renderShowUntil from "./show_until.js";
+import setupMarquee from "./marquee.js";
 import renderState from "./state.js";
-import renderPrice from "./price.js"
+import renderPrice from "./price.js";
+import renderImage from "./image.js";
 import renderText from "./text.js";
 
 export default function setupUpdate(): void {
        setupTimeSince();
        setupTimeUntil();
+       setupMarquee();
        setupSounds();
        setupStyle();
 
@@ -35,6 +38,7 @@ export default function setupUpdate(): void {
                renderState();
                renderPrice();
                renderStyle();
+               renderImage();
                renderText();
                playSounds();
 
index 684ee85ab361c8d5e82cccfdd9c32b8a311db22a..b2cadb1f32a2780dc8174406d7b62f1694dcb486 100644 (file)
@@ -9,7 +9,7 @@ export function timeUntil(end: number): number[] {
        let minutes: number = Math.floor(time / 60);
        let seconds: number = Math.floor(time % 60);
 
-       return [hours, minutes, seconds]
+       return [hours, minutes, seconds, time]
 }
 
 export function timeSince(end: number): number[] {
@@ -26,6 +26,14 @@ export function timeSince(end: number): number[] {
        return [hours, minutes, seconds]
 }
 
+export function timeFormatStandard(hours: number, minutes: number, seconds: number): string {
+       var hoursString = hours.toString().padStart(2, "0");
+       var minutesString = minutes.toString().padStart(2, "0");
+       var secondsString = seconds.toString().padStart(2, "0");
+
+       return `${minutesString}:${secondsString}`
+}
+
 export function timeFormatBroadcast(hours: number, minutes: number, seconds: number): string {
        var hoursString = hours.toString().padStart(2, "0");
        var minutesString = minutes.toString().padStart(2, "0");
@@ -33,3 +41,8 @@ export function timeFormatBroadcast(hours: number, minutes: number, seconds: num
 
        return `${hoursString}h ${minutesString}' ${secondsString}"`
 }
+
+export function timeFormatState(hours: number, minutes: number, seconds: number): string {
+       if (hours + minutes + seconds == 0) { return "true" }
+       else { return "false" }
+}
index aee1ec6231748afa54bc361beee4fff44528583e..9857c03256e367bdcc43d0b50f2b89b516da0353 100644 (file)
@@ -30,6 +30,7 @@ main {
 input[type="submit"]:first-of-type {
        outline: 15px solid white;
        position: sticky; top: 0px;
+       z-index: 2;
 }
 
 /* THE OPTIONS GRID */
@@ -52,7 +53,6 @@ input[type="submit"]:first-of-type {
        z-index: 1;
 }
 .currentValue { color: red; }
-.currentValue[type="radio"] { background-color: red; }
 
 i {
        font-style: normal;
@@ -68,6 +68,21 @@ i {
                -1px 0px 0 black;
 }
 
+.clipboard ~ button {
+       margin-left: 0.5em;
+}
+
+/* timer button text colors */
+.timer[value^="+"] { color: green; }
+.timer[value^="-"] { color: red; }
+
+#assetGrid {
+       display: grid; grid-template-columns: 30% 70%;
+       column-gap: 10px; row-gap: 10px;
+       margin-bottom: 10px;
+}
+#assetGrid > img { border: 1px solid black; }
+
 /* PRINT MODE
                need to work on this a little bit, currently just hides things that
                shouldnt be printed and thats all. Should be able to potentially display
diff --git a/argo/static/media/assets/strap1.svg b/argo/static/media/assets/strap1.svg
new file mode 100644 (file)
index 0000000..054ce95
--- /dev/null
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   width="1920"
+   height="480"
+   viewBox="0 0 1920 480"
+   version="1.1"
+   id="svg1"
+   inkscape:version="1.4.3 (0d15f75042, 2025-12-25)"
+   sodipodi:docname="strap1.svg"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:svg="http://www.w3.org/2000/svg">
+  <sodipodi:namedview
+     id="namedview1"
+     pagecolor="#ffffff"
+     bordercolor="#000000"
+     borderopacity="0.25"
+     inkscape:showpageshadow="2"
+     inkscape:pageopacity="0.0"
+     inkscape:pagecheckerboard="0"
+     inkscape:deskcolor="#d1d1d1"
+     inkscape:document-units="px"
+     inkscape:zoom="0.22239583"
+     inkscape:cx="960.00001"
+     inkscape:cy="541.82671"
+     inkscape:window-width="1366"
+     inkscape:window-height="710"
+     inkscape:window-x="0"
+     inkscape:window-y="0"
+     inkscape:window-maximized="1"
+     inkscape:current-layer="layer1" />
+  <defs
+     id="defs1" />
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1">
+    <g
+       id="g3"
+       transform="translate(0,-51.224152)"
+       style="fill:#000000;fill-opacity:0.99000001">
+      <text
+         xml:space="preserve"
+         style="font-size:192px;line-height:1.35;font-family:'EB Garamond';-inkscape-font-specification:'EB Garamond';text-align:end;letter-spacing:0.06px;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#000000;fill-opacity:0.99000001;stroke-width:6.4;stroke-linejoin:bevel"
+         x="1257.3059"
+         y="236.73596"
+         id="text1"><tspan
+           sodipodi:role="line"
+           x="1257.3658"
+           y="236.73596"
+           id="tspan2"
+           style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:192px;font-family:'EB Garamond';-inkscape-font-specification:'EB Garamond Bold';fill:#000000;fill-opacity:0.99000001">XMDV</tspan></text>
+      <text
+         xml:space="preserve"
+         style="font-size:192px;line-height:1.35;font-family:'EB Garamond';-inkscape-font-specification:'EB Garamond';text-align:end;letter-spacing:0.06px;writing-mode:lr-tb;direction:ltr;text-anchor:end;fill:#000000;fill-opacity:0.99000001;stroke-width:6.4;stroke-linejoin:bevel"
+         x="1445.7065"
+         y="416.56024"
+         id="text3"><tspan
+           sodipodi:role="line"
+           id="tspan3"
+           x="1445.7665"
+           y="416.56024"
+           style="font-style:italic;font-variant:normal;font-weight:600;font-stretch:normal;font-size:192px;font-family:'EB Garamond';-inkscape-font-specification:'EB Garamond Semi-Bold Italic';fill:#000000;fill-opacity:0.99000001">Teleshopping</tspan></text>
+    </g>
+  </g>
+</svg>
index 3295c95621966d4c3038944e54b1842e2c522f68..d8f95a7fd1438e67cbc2ed74f6d0d49539940377 100644 (file)
@@ -3,3 +3,4 @@
        font-weight: 600;
 }
 .title { text-transform: capitalize; }
+.style { display: none; }
diff --git a/argo/static/style/bottom_box.css b/argo/static/style/bottom_box.css
new file mode 100644 (file)
index 0000000..2a3d472
--- /dev/null
@@ -0,0 +1,5 @@
+.styleBottomBox {
+       position: fixed;
+       bottom: var(--safeVertical); left: var(--safeHorizontal);
+       width: calc(100vw - (var(--safeHorizontal) * 2)) !important;
+}
diff --git a/argo/static/style/bottom_graphic.css b/argo/static/style/bottom_graphic.css
new file mode 100644 (file)
index 0000000..26c747d
--- /dev/null
@@ -0,0 +1,28 @@
+.styleBottomGraphic {
+       margin-left: calc(100% - var(--bottomGraphicWidth)) !important;
+       margin-bottom: 0 !important;
+       box-sizing: border-box;
+       width: var(--bottomGraphicWidth) !important;
+}
+
+.state-false .styleBottomGraphic {
+       padding: 0; margin: 0;
+}
+.styleBottomGraphic {
+       opacity: 0; max-height: 0;
+       transform: translateY(20px);
+       /* should do some tweeking for the below */
+       transition:
+       opacity var(--baseAnimationLength),
+       max-height var(--baseAnimationLength) cubic-bezier(1,0,0,1),
+       padding var(--baseAnimationLength),
+       margin var(--baseAnimationLength),
+       transform var(--baseAnimationLength);
+       overflow: hidden;
+}
+.state-true .styleBottomGraphic {
+       opacity: 1; max-height: 50vh;
+       transform: translateY(0px);
+}
+
+.styleBottomGraphic { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
index 35a7a24f597ca4fbce1fbc6ccbba88ddf0ee1ca5..40274d05d74fcf5ecfdec5a0d1300ad09a76fee5 100644 (file)
@@ -11,7 +11,7 @@
        text-shadow: var(--textAShadow);
 
        background: var(--backgroundA);
-       box-shadow: inset 0 0 var(--innerGlowSize) var(--innerGlowColor);
+       box-shadow: inset 0 0 var(--innerGlowASize) var(--innerGlowAColor);
        border: var(--borderASize) solid var(--borderAColor);
 
        border-radius: var(--borderARadius);
@@ -29,7 +29,7 @@
        text-shadow: var(--textBShadow);
 
        background: var(--backgroundB);
-       box-shadow: inset 0 0 var(--innerGlowSize) var(--innerGlowColor);
+       box-shadow: inset 0 0 var(--innerGlowBSize) var(--innerGlowBColor);
        border: var(--borderBSize) solid var(--borderBColor);
 
        border-radius: var(--borderBRadius);
@@ -47,7 +47,7 @@
        text-shadow: var(--textCShadow);
 
        background: var(--backgroundC);
-       box-shadow: inset 0 0 var(--innerGlowSize) var(--innerGlowColor);
+       box-shadow: inset 0 0 var(--innerGlowCSize) var(--innerGlowCColor);
        border: var(--borderCSize) solid var(--borderCColor);
 
        border-radius: var(--borderCRadius);
diff --git a/argo/static/style/crawler_marquee.css b/argo/static/style/crawler_marquee.css
new file mode 100644 (file)
index 0000000..5733928
--- /dev/null
@@ -0,0 +1,7 @@
+.styleCrawlerMarquee {
+       font-size: 1.5em;
+       display: inline-block;
+}
+.styleCrawlerInnerBox {
+       overflow: clip;
+}
diff --git a/argo/static/style/crawler_outer_box.css b/argo/static/style/crawler_outer_box.css
new file mode 100644 (file)
index 0000000..2b2b760
--- /dev/null
@@ -0,0 +1,27 @@
+body.state-blank .styleCrawlerOuterBox {
+       padding: 0; margin: 0;
+}
+.styleCrawlerOuterBox {
+       opacity: 0; max-height: 0;
+       transform: translateX(-20px);
+       /* should do some tweeking for the below */
+       transition:
+       opacity var(--baseAnimationLength),
+       max-height var(--baseAnimationLength) cubic-bezier(1,0,0,1),
+       padding var(--baseAnimationLength),
+       margin var(--baseAnimationLength),
+       transform var(--baseAnimationLength);
+       overflow: hidden;
+}
+body:not(.state-blank) .styleCrawlerOuterBox {
+       opacity: 1; max-height: 50vh;
+       transform: translateX(0px);
+}
+
+/* BEGIN GRID LAYOUT */
+
+.styleCrawlerOuterBox { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
+.styleCrawlerOuterBox:has(*[data-timeout="false"]) { column-gap: var(--boxHPad); }
+.styleCrawlerOuterBox > *:first-child { grid-column-start: 1; grid-column-end: 3; }
+
+/* END GRID LAYOUT */
diff --git a/argo/static/style/crawler_timer_box.css b/argo/static/style/crawler_timer_box.css
new file mode 100644 (file)
index 0000000..036eaf2
--- /dev/null
@@ -0,0 +1,32 @@
+.styleCrawlerTimerBox {
+       font-size: 1.5em;
+       background:
+               linear-gradient(
+                       color-mix(in srgb, var(--borderBColor), transparent 100%),
+                       color-mix(in srgb, var(--borderBColor), transparent 100%) var(--percent),
+                       color-mix(in srgb, var(--borderBColor), transparent 0%) calc(var(--percent) + 1px),
+                       color-mix(in srgb, var(--borderBColor), transparent 0%)
+               ),
+               var(--backgroundC)
+               !important;
+}
+
+.styleCrawlerTimerBox[data-timeout="true"] {
+       padding: 0; margin: 0;
+}
+.styleCrawlerTimerBox {
+       opacity: 0; max-width: 0;
+       transform: translateX(20px);
+       /* should do some tweeking for the below */
+       transition:
+       opacity var(--baseAnimationLength),
+       max-width var(--baseAnimationLength) cubic-bezier(1,0,0,1),
+       padding var(--baseAnimationLength),
+       margin var(--baseAnimationLength),
+       transform var(--baseAnimationLength);
+       overflow: hidden;
+}
+.styleCrawlerTimerBox[data-timeout="false"] {
+       opacity: 1; max-width: 50vh;
+       transform: translateX(0px);
+}
diff --git a/argo/static/style/crawler_top.css b/argo/static/style/crawler_top.css
new file mode 100644 (file)
index 0000000..04b06f7
--- /dev/null
@@ -0,0 +1,21 @@
+.state-false .styleCrawlerTop {
+       padding: 0; margin: 0;
+}
+.styleCrawlerTop {
+       opacity: 0; max-height: 0;
+       transform: translateY(20px);
+       /* should do some tweeking for the below */
+       transition:
+       opacity var(--baseAnimationLength),
+       max-height var(--baseAnimationLength) cubic-bezier(1,0,0,1),
+       padding var(--baseAnimationLength),
+       margin var(--baseAnimationLength),
+       transform var(--baseAnimationLength);
+       overflow: hidden;
+}
+.state-true .styleCrawlerTop {
+       opacity: 1; max-height: 50vh;
+       transform: translateY(0px);
+}
+
+.styleCrawlerTop { display: grid; grid-template-columns: minmax(0, 1fr) auto; }
index 2c846612fb3fe71bada38e2b2239a0e19fb370d7..c70a1449afd399acde5e47b91d774c6517fb2456 100644 (file)
@@ -1,5 +1,4 @@
-.styleDiscountBox > em {
-       display: block;
+.styleDiscountBox em {
        font-size: 0.7em;
        line-height: 1.4em;
 }
index f40ef48c08b10adf0362d54c89733b8323dcd542..3a849a3ac6bd86dbf7b14b8893a96d5e7b7ad743 100644 (file)
@@ -27,3 +27,16 @@ body.state-sold .styleItemBox {
        opacity: 1; max-height: 50vh;
        transform: translateX(0px);
 }
+
+/* text styling in item box */
+.styleItemId {}
+.styleItemTitle {
+       font-size: 1.1em;
+       line-height: 1.3;
+}
+.styleItemDescription {
+       display: block;
+       font-size: 0.8em;
+       line-height: 1.3;
+       font-weight: 400;
+}
index c070292863e2c4ef3ba492f1461bbe064493e8d3..b17bf33a1188b13463ba3dc253b4167bd3f80e34 100644 (file)
@@ -15,9 +15,16 @@ body:not(
        margin var(--baseAnimationLength),
        transform var(--baseAnimationLength);
        overflow: hidden;
+
+       color: white;
+
+       width: fit-content;
+       text-align: center;
+       font-size: 1.5em;
+       font-weight: 800;
 }
 body.state-product .styleLogoBox,
 body.state-crawler .styleLogoBox {
-       opacity: 1; max-height: 50vh;
+       opacity: .4; max-height: 50vh;
        transform: translateX(0px);
 }
diff --git a/argo/static/style/monthly_box.css b/argo/static/style/monthly_box.css
new file mode 100644 (file)
index 0000000..92e025d
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+body:not(
+       .state-discount,
+       .state-move
+) .styleMonthlyBox {
+        padding: 0; margin: 0;
+}
+*/
+.styleMonthlyBox {
+       /*
+       opacity: 0; max-height: 0;
+       transform: translateX(-20px);
+       /* should do some tweeking for the below *//*
+       transition:
+       opacity var(--baseAnimationLength),
+       max-height var(--baseAnimationLength) cubic-bezier(1,0,0,1),
+       padding var(--baseAnimationLength),
+       margin var(--baseAnimationLength),
+       transform var(--baseAnimationLength);
+       overflow: hidden;
+       */
+
+       font-size: calc(0.75 * var(--baseFontSize));
+       line-height: 1;
+}
+/*
+body.state-discount .styleMonthlyBox,
+body.state-move .styleMonthlyBox {
+       opacity: 1; max-height: 50vh;
+       transform: translateX(0px);
+       padding: 5px;
+}
+*/
index 57d2fffbc771536dfc8f0365c8c7d7a5ddddecd6..0a89d62fc7042fe720705e301c096b2e31776731 100644 (file)
@@ -12,6 +12,10 @@ body:not(.state-price, .state-discount, .state-move) .stylePricingBox {
        margin var(--baseAnimationLength),
        transform var(--baseAnimationLength);
        overflow: hidden;
+
+       font-size: 0.8em;
+       line-height: 1;
+       font-weight: 400;
 }
 body.state-price .stylePricingBox,
 body.state-discount .stylePricingBox,
@@ -19,3 +23,11 @@ body.state-move .stylePricingBox {
        opacity: 1; max-height: 50vh;
        transform: translateX(0px);
 }
+
+body.state-discount .stylePricingBox .styleStrikeDependant,
+body.state-move .stylePricingBox .styleStrikeDependant {
+       text-decoration: line-through var(--textBColor) solid 3px;
+}
+
+.styleStartPrice { font-size: 1.5em; font-weight: 600; }
+.stylePhoneNumber { font-size: 1.5em; }
index 066842e5141edcc5af7ef12fbc802a713dee79f6..b5591c18bec3396736de8c37bc3abd420a976fef 100644 (file)
@@ -4,7 +4,8 @@
        display: flex;
        flex-direction: column;
 
-       margin: 50px;
+       /* standard HD safe margins */
+       margin: var(--safeVertical) 0 0 var(--safeHorizontal);
 }
 .styleSideBox > * {
        margin-bottom: 5px;
index dfd48d4e3527d63db9c4a0e01a2a0ef377440ba9..259464725b53acdf77189446a10c1e8aa69ec36b 100644 (file)
@@ -1,4 +1,39 @@
 .styleSideTimerBox {
        display: inline;
        width: fit-content !important;
+
+       text-shadow:
+               1px 1px 3px white, -1px 1px 3px white, 1px -1px 3px white, -1px -1px 3px white,
+               0 1px 3px white, 0 -1px 3px white, 1px 0 3px white, -1px 0 3px white
+               !important;
+       background:
+               linear-gradient(
+                       -0.25turn,
+                       color-mix(in srgb, var(--borderBColor), transparent 100%),
+                       color-mix(in srgb, var(--borderBColor), transparent 100%) var(--percent),
+                       color-mix(in srgb, var(--borderBColor), transparent 0%) calc(var(--percent) + 1px),
+                       color-mix(in srgb, var(--borderBColor), transparent 0%)
+               ),
+               var(--backgroundA)
+               !important;
+}
+
+.styleSideTimerBox[data-timeout="true"] {
+       padding: 0; margin: 0;
+}
+.styleSideTimerBox {
+       opacity: 0; max-height: 0;
+       transform: translateX(-20px);
+       /* should do some tweeking for the below */
+       transition:
+       opacity var(--baseAnimationLength),
+       max-height var(--baseAnimationLength) cubic-bezier(1,0,0,1),
+       padding var(--baseAnimationLength),
+       margin var(--baseAnimationLength),
+       transform var(--baseAnimationLength);
+       overflow: hidden;
+}
+.styleSideTimerBox[data-timeout="false"] {
+       opacity: 1; max-height: 50vh;
+       transform: translateX(0px);
 }
diff --git a/argo/static/style/spin_box.css b/argo/static/style/spin_box.css
new file mode 100644 (file)
index 0000000..fb6b244
--- /dev/null
@@ -0,0 +1,8 @@
+@keyframes spin {
+       from { transform: rotateY(-90deg); }
+       to { transform: rotateY(90deg); }
+}
+
+.styleSpinBox {
+       animation: 6s linear 0s spin infinite;
+}
index 40fae547762f0bf3bad627cfa47c73ec4899a6dd..fa9ebf62cd390ea68825e17f3c57dac9e764d7c2 100644 (file)
@@ -12,8 +12,8 @@
 
                <script type="module" defer>
 
-import { setupTrigger } from "/script/admin.js";
-setupTrigger();
+import { setupClipboard } from "/script/admin.js";
+setupClipboard();
 
                </script>
        </head>
@@ -49,10 +49,21 @@ setupTrigger();
                                <li><a href="/info/c">Info page C</a> <em>(Gallery screen, timing and state)</em></li>
                        </ul>
 
-                       <img
-                               src="/static/media/velo.jpg"
-                               attributionsrc="https://commons.wikimedia.org/w/index.php?curid=4075468"
-                               style="width: min(100%, 700px);" />
+                       <h2>Assets</h2>
+
+                       <div id="assetGrid">
+                               {% for path in assets %}
+                                       <img style="width: 100%;" src="{{ path }}" />
+                                       <span><a href="{{ path }}" class="clipboard">Link</a></span>
+                               {% endfor %}
+                       </div>
+
+                       {#
+                               <img
+                                       src="/static/media/velo.jpg"
+                                       attributionsrc="https://commons.wikimedia.org/w/index.php?curid=4075468"
+                                       style="width: min(100%, 700px);" />
+                       #}
 
                        <br>
                        <code><a href="https://delta-aa.ozva.co.uk/admin">Delta Aa</a> - <a href="https://delta-ab.ozva.co.uk/admin">Delta Ab</a> - <a href="https://git.ozva.co.uk/?p=delta-velorum;a=summary">Nomenclature</a></code>
diff --git a/argo/templates/admin/timer.html b/argo/templates/admin/timer.html
new file mode 100644 (file)
index 0000000..9f1364a
--- /dev/null
@@ -0,0 +1,13 @@
+<span id="{{ name }}" style="grid-column: 2 / span 3;">
+       <noscript style="color: red;">Timer will not function without JS<br></noscript>
+       <button type="button" name="{{ name }}" value="{{ label }}" class="trigger">
+               Start {{ label }}
+       </button>
+       <input type="number" id="{{ name }}+delay" value="{{ value.split('+')[1] }}"/><span> seconds</span>
+       <button type="button" name="{{ name }}" value="-60" class="timer">-60s</button>
+       <button type="button" name="{{ name }}" value="-30" class="timer">-30s</button>
+       <button type="button" name="{{ name }}" value="-10" class="timer">-10s</button>
+       <button type="button" name="{{ name }}" value="+10" class="timer">+10s</button>
+       <button type="button" name="{{ name }}" value="+30" class="timer">+30s</button>
+       <button type="button" name="{{ name }}" value="+60" class="timer">+60s</button>
+</span>
diff --git a/argo/templates/admin/toggle.html b/argo/templates/admin/toggle.html
new file mode 100644 (file)
index 0000000..66bbdde
--- /dev/null
@@ -0,0 +1,13 @@
+<label>{{ label }}</label>
+<span>
+       {% if value == "true" %}
+               <input id="{{ name }}" type="radio" name="{{ name }}" value="true" checked="checked" />
+               <label>on &harr; off</label>
+               <input id="{{ name }}" type="radio" name="{{ name }}" value="false" />
+       {% else %}
+               <input id="{{ name }}" type="radio" name="{{ name }}" value="true" />
+               <label>on &harr; off</label>
+               <input id="{{ name }}" type="radio" name="{{ name }}" value="false" checked="checked" />
+       {% endif %}
+</span>
+<span class="currentValue">{{ value }}</span>
index fb924194437b29c59f95ec185a93726034720715..1bfab8f0d4153884e129e2f4c0c106f08cb18bb3 100644 (file)
 
                {# ELEMENT STYLING IMPORTS #}
                <link rel="stylesheet" href="/static/style/side_box.css">
+               <link rel="stylesheet" href="/static/style/bottom_box.css">
                <link rel="stylesheet" href="/static/style/qty_box.css">
                <link rel="stylesheet" href="/static/style/side_timer_box.css">
                <link rel="stylesheet" href="/static/style/center_shout.css">
                <link rel="stylesheet" href="/static/style/discount_box.css">
                <link rel="stylesheet" href="/static/style/banner_box.css">
+               <link rel="stylesheet" href="/static/style/monthly_box.css">
                <link rel="stylesheet" href="/static/style/pricing_box.css">
                <link rel="stylesheet" href="/static/style/item_box.css">
                <link rel="stylesheet" href="/static/style/logo_box.css">
+               <link rel="stylesheet" href="/static/style/spin_box.css">
+               <link rel="stylesheet" href="/static/style/crawler_outer_box.css">
+               <link rel="stylesheet" href="/static/style/crawler_timer_box.css">
+               <link rel="stylesheet" href="/static/style/crawler_marquee.css">
+               <link rel="stylesheet" href="/static/style/crawler_top.css">
+               <link rel="stylesheet" href="/static/style/bottom_graphic.css">
 
                {# HELPER IMPORTS #}
                <link rel="stylesheet" href="/static/style/box.css">
                <link rel="stylesheet" href="/static/style/show_until.css">
-               <link rel="stylesheet" href="/static/style/background.css">
 
                <script type="importmap">
                {
@@ -45,6 +52,11 @@ setupUpdate();
                <span class="update style~~text--sideBoxWidth style"></span>
                <span class="update style~~text--baseFontSize style"></span>
 
+               <span class="update style~~text--safeHorizontal style"></span>
+               <span class="update style~~text--safeVertical style"></span>
+
+               <span class="update style~~text--bottomGraphicWidth style"></span>
+
                {# DYNAMIC STYLING ELEMENTS #}
 
                <span class="update style__colorscheme~~text--borderASize style"></span>
@@ -69,8 +81,12 @@ setupUpdate();
                <span class="update style__colorscheme__backgroundB~~text--backgroundB style"></span>
                <span class="update style__colorscheme__backgroundC~~text--backgroundC style"></span>
 
-               <span class="update style__colorscheme~~color--innerGlowColor style"></span>
-               <span class="update style__colorscheme~~text--innerGlowSize style"></span>
+               <span class="update style__colorscheme~~color--innerGlowAColor style"></span>
+               <span class="update style__colorscheme~~text--innerGlowASize style"></span>
+               <span class="update style__colorscheme~~color--innerGlowBColor style"></span>
+               <span class="update style__colorscheme~~text--innerGlowBSize style"></span>
+               <span class="update style__colorscheme~~color--innerGlowCColor style"></span>
+               <span class="update style__colorscheme~~text--innerGlowCSize style"></span>
 
                {# SFX ELEMENTS #}
                <audio src="/static/media/sfx/banner_shout.wav" class="update data~~trigger--bannerShoutTrigger sound"></audio>
@@ -78,6 +94,18 @@ setupUpdate();
                <audio src="/static/media/sfx/state_change.wav" class="update data__state~~text--state sound"></audio>
                <audio src="/static/media/sfx/shout.wav" class="update data~~trigger--centerShoutTrigger sound"></audio>
 
+               {# TIMER SFX ELEMENTS #}
+               <audio src="/static/media/sfx/clock.wav" class="update data__timer~~timer--timerSide1 until until-sound"></audio>
+               <audio src="/static/media/sfx/clock.wav" class="update data__timer~~timer--timerSide2 until until-sound"></audio>
+               <audio src="/static/media/sfx/clock.wav" class="update data__timer~~timer--timerCrawler until until-sound"></audio>
+
+               {#
+
+               ------------------------------------------------------------------------
+               PAGE BEGINS
+
+               #}
+
                {# CENTER SHOUT #}
                <div class="styleCenterShout update data~~trigger--centerShoutTrigger showUntil">
                        <div>
@@ -100,36 +128,45 @@ setupUpdate();
                                these are switched on and off using the state class from the
                                body tag.
                #}
+
                <div class="styleSideBox">
 
                        {# LOGO BOX #}
-                       <div class="styleLogoBox">
-                               LOGO BOX
+                       <div class="styleLogoBox styleSpinBox .styleOutline">
+                               XMDV
                        </div>
 
                        {# BANNER BOX #}
                        <div class="styleBannerBox boxC">
-                               BANNER BOX
+                               <span class="update data__text~~text--bannerText title"></span>
                        </div>
 
                        {# ITEM BOX #}
                        <div class="styleItemBox boxB">
+                               Item Code <span class="update data__product~~text--id title styleItemId"></span>
                                <div class="boxA">
-                                       ITEM BOX
+                                       <span class="update data__product~~text--title title styleItemTitle"></span><br>
+                                       <span class="update data__product~~text--description text styleItemDescription"></span>
                                </div>
-                       </div>
 
-                       {# PRICING BOX #}
-                       <div class="stylePricingBox boxA">
-                               PRICING BOX
+                               {# PRICING BOX #}
+                               <div class="stylePricingBox boxA">
+                                       <span class="styleStrikeDependant">ONLY <span class="update data__product__originalPriceString~~text--originalPriceString text styleStartPrice "></span></span><br>
+                                       <span class="stylePhoneNumber">#### ### ####</span> Call Us Now!
+                               </div>
                        </div>
 
                        {# DISOUNT BOX #}
                        <div class="styleDiscountBox boxB">
-                               <em>Now only...</em>
+                               <b><span class="update data__product~~number--discount discount"></span></b>
+                               OFF! CHEAP! <em>SAVE
+                               <b><span class="update data__product__savePriceString~~text--savePriceString text"></span></b></em>
                                <div class="boxA">
-                                       <b><span class="update data__product~~number--discount discount"></span></b>
-                                       OFF!
+                                       <em>NOW...</em>
+                                       <span class="update data__product__currentPriceString~~text--currentPriceString text"></span>
+                                       <div class="boxC styleMonthlyBox">
+                                               ...Or <b><span class="update data__product~~float--monthlyPayments text"></span></b> Monthly Payments of <b><span class="update data__product__multibuyPriceString~~text--multibuyPriceString text"></span></b>
+                                       </div>
                                </div>
                        </div>
 
@@ -148,11 +185,44 @@ setupUpdate();
                        </div>
 
                        {# TIMER BOX #}
-                       <div class="styleSideTimerBox boxA">
-                               TIMER 1!
+                       <div class="styleSideTimerBox boxA update data__timer~~timer--timerSide1 until until-timeout">
+                               <span class="update data__timer~~timer--timerSide1 until"></span>
+                       </div>
+                       <div class="styleSideTimerBox boxA update data__timer~~timer--timerSide2 until until-timeout">
+                               <span class="update data__timer~~timer--timerSide2 until"></span>
                        </div>
-                       <div class="styleSideTimerBox boxA">
-                               TIMER 2!
+               </div>
+
+               {# CRAWLER
+
+                       GRAPHIC BOX
+
+                       OUTER CRAWLER
+                       includes:
+                       - CRAWLER TOP BANNER (STATIC) (show on OuterBox state change)
+                       - CRAWLER MARQUEE
+                       - CRAWLER TIMER (show only when running)
+
+                       (crawler show during: all except blank)
+               #}
+
+               <div class="styleBottomBox">
+
+                       <div class="update data~~toggle--showBottomGraphic state">
+                               <img class="styleBottomGraphic boxA update data~~text--bottomGraphic image" />
+                       </div>
+
+                       <div class="styleCrawlerOuterBox boxA update data__text~~toggle--showCrawlerTop state">
+                               <span class="styleCrawlerTop">
+                                       <span class="update data__text~~text--crawlerTop title"></span>
+                                       <span style="color: var(--borderBColor); margin-right: 0.2em;"><em>XMDV Teleshopping</em></span>
+                               </span>
+                               <div class="styleCrawlerInnerBox boxC">
+                                       <span class="styleCrawlerMarquee update data__text__crawlerMarqueeList~~text--crawlerMarqueeList marquee"></span>
+                               </div>
+                               <div class="styleCrawlerTimerBox boxC update data__timer~~timer--timerCrawler until until-timeout">
+                                       <span class="update data__timer~~timer--timerCrawler until"></span>
+                               </div>
                        </div>
                </div>
        </body>
index a5d1a7dc52b6b51b6740c26e1ca7d861cabbc03a..515822d03682d7c3674185e5273eeb3d53903c2e 100644 (file)
@@ -32,7 +32,7 @@ setupUpdate();
                        <span>Next state: <span class="update data__state~~text--nextState title"></span></span>
 
                        <span style="grid-column: 1 / span 3; font-size: 2em; font-size: 2em;">
-                               <span class="update data~~trigger--startTrigger since"></span> <span style="background-color: red;">T-<span class="update data__endTime~~text--endTime until"></span></span>
+                               <span class="update data~~trigger--startTrigger since"></span> <span style="background-color: red;">T-<span class="update data__endTime~~text--endTime until until-broadcast"></span></span>
                        </span>
                </div>
        </body>
index e712803019e99e00da26cd7e14af35c21e083b50..6801f4a5b6ea8d3172b89374d7bfea1092923617 100644 (file)
@@ -13,8 +13,9 @@
 
                <script type="module" defer>
 
-import { setupTrigger } from "/script/admin.js";
+import { setupTrigger, setupTimerButtons } from "/script/admin.js";
 setupTrigger();
+setupTimerButtons();
 
                </script>
        </head>
@@ -22,6 +23,7 @@ setupTrigger();
                <nav>
                        <p><a href="/admin">.. back</a></p>
                        <p><b>{{ table_name }}</b></p>
+                       <p><a href="/admin/{{ table_name }}#current">current</a></p>
                        <ol>
                        {% for row in table %}
                                <li style="border: 1px solid gray; margin-top: -1px;"><ul>
@@ -37,7 +39,7 @@ setupTrigger();
                </nav>
                <main>
                        <h1><i>&delta; Velorum {{ star }}</i> Table: {{ table_name }}</h1>
-                       <form class="optionsGrid" method="post">
+                       <form class="optionsGrid" method="post" action="/admin/{{ table_name }}#current">
                                <input type="submit" value="Submit table" style="grid-column: 1 / span 4;">
                                <span class="optionsGridSpacer" style="grid-column: 1 / span 4;"></span>
                                {% for row in table %}
@@ -49,10 +51,12 @@ setupTrigger();
                                                        display: flex;
                                                        justify-content: center;
                                                        align-items: center;
-                                                       ">
+                                                       "
                                                        {% if loop.index0 == indexes["int--" ~ table_name] %}
-                                                               <input type="radio" name="{{ "indexes~~0~~int--" ~ table_name }}" value="{{ loop.index0 }}" checked="checked" class="currentValue">
+                                                               id="current">
+                                                               <input type="radio" name="{{ "indexes~~0~~int--" ~ table_name }}" value="{{ loop.index0 }}" checked="checked">
                                                        {% else %}
+                                                               >
                                                                <input type="radio" name="{{ "indexes~~0~~int--" ~ table_name }}" value="{{ loop.index0 }}" >
                                                        {% endif %}
                                                </span>
@@ -68,19 +72,7 @@ setupTrigger();
                                                {% set value = row[feild] %}
                                                {% set name = table_name ~ "~~" ~ group ~ "~~" ~ feild %}
 
-                                               {% if type == "textarea" %}
-                                                       {% include "admin/textarea.html" %}
-                                               {% elif type == "text" %}
-                                                       {% include "admin/text.html" %}
-                                               {% elif type == "number" %}
-                                                       {% include "admin/number.html" %}
-                                               {% elif type == "float" %}
-                                                       {% include "admin/float.html" %}
-                                               {% elif type == "trigger" %}
-                                                       {% include "admin/trigger.html" %}
-                                               {% elif type == "color" %}
-                                                       {% include "admin/color.html" %}
-                                               {% endif %}
+                                               {% include "admin/" ~ type ~ ".html" %}
                                        {% endfor %}
                                        <span class="optionsGridSpacer" style="grid-column: 1 / span 4;"></span>
 
index 797b57058702f676ba7a8fe10dd64f395d545e51..c1a15191b747b27633604e0b16c965eba26f929a 100644 (file)
@@ -1,3 +1,4 @@
+prometheus-flask-exporter
 flask_socketio
 flask_httpauth
 flask_cors