diff --git a/examples/app_hub/hub.css b/examples/app_hub/hub.css index 0ae17b1..a542d38 100644 --- a/examples/app_hub/hub.css +++ b/examples/app_hub/hub.css @@ -8,6 +8,8 @@ font-display: swap; } +/* Clockopia kept for legacy only; hub clock uses DSEG14 (see .hub-clock-widget rules). */ + @font-face { font-family: "DSEG14 Classic"; src: url("assets/fonts/DSEG14Classic-Regular.ttf") format("truetype"); @@ -339,7 +341,11 @@ overflow: visible; background: rgba(18, 24, 34, 0.88); backdrop-filter: blur(1.5px); - transition: transform 0.2s ease, box-shadow 0.2s ease, filter 0.2s ease; + transition: + transform 0.22s ease, + box-shadow 0.28s ease, + border-color 0.28s ease, + filter 0.22s ease; cursor: move; user-select: none; touch-action: none; @@ -347,7 +353,7 @@ box-sizing: border-box; display: flex; flex-direction: column; - font-family: "DSEG14 Classic", "Consolas", monospace; + font-family: "Clockopia", "Consolas", monospace; } .cw-clock-inner { @@ -379,8 +385,23 @@ .hub-clock-widget:hover { transform: scale(1.035); - box-shadow: 0 16px 42px rgba(0, 0, 0, 0.62), 0 0 26px rgba(155, 205, 255, 0.22); - filter: saturate(1.04); + border-color: rgba(165, 225, 255, 0.98); + box-shadow: + 0 16px 42px rgba(0, 0, 0, 0.62), + 0 0 0 1px rgba(140, 210, 255, 0.55), + 0 0 22px rgba(120, 200, 255, 0.52), + 0 0 44px rgba(90, 175, 255, 0.32), + inset 0 0 14px rgba(120, 200, 255, 0.07); + filter: saturate(1.06); +} + +.hub-clock-widget.is-dragging { + opacity: 0.25; + transition: opacity 0.12s ease; +} + +.hub-clock-widget.is-dragging:hover { + transform: none; } .cw-primary-block { @@ -393,6 +414,14 @@ background: transparent; } +.cw-row-tz { + margin-top: 15px; /* 15dip between line 1 and line 2 */ +} + +.cw-row-date { + margin-top: 5px; /* 5dip between line 2 and line 3 */ +} + .cw-row { width: 100%; min-height: 0; @@ -569,7 +598,7 @@ letter-spacing: 0.16em; font-weight: 400; text-transform: uppercase; - font-family: "DSEG14 Classic", "Consolas", monospace; + font-family: "Digital-7 Mono Italic", "Consolas", monospace; } .cw-line-date { @@ -578,7 +607,7 @@ letter-spacing: 0.12em; font-weight: 400; text-transform: uppercase; - font-family: "DSEG14 Classic", "Consolas", monospace; + font-family: "Digital-7 Mono Italic", "Consolas", monospace; } .cw-separator { @@ -607,13 +636,12 @@ .cw-world-cell { min-width: 0; width: 100%; - min-height: 178px; + min-height: 200px; display: flex; flex-direction: column; align-items: center; justify-content: center; - gap: 5px; - padding: 20px 4px; + padding: 16px 4px; background: rgba(20, 28, 40, 0.62); border-left: 1px solid rgba(255, 255, 255, 0.22); } @@ -622,88 +650,109 @@ border-left: 0; } +.cw-world-stack { + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; +} + .cw-world-label { - color: #a6b0c2; - font-size: 9.5px; + color: #c5d0e2; + font-size: clamp(0.95rem, 1.6vw, 1.15rem); letter-spacing: 0.12em; - margin-top: 0; - margin-bottom: 8px; - font-family: "DSEG14 Classic", "Consolas", monospace; + font-weight: 400; + text-transform: uppercase; + margin: 0; + line-height: 1; + flex: 0 0 auto; + font-family: "Digital-7 Mono Italic", "Consolas", monospace; } .cw-dial { - width: 100%; - max-width: 70px; - aspect-ratio: 1; - height: auto; - margin-inline: auto; + --cw-dial-size: 90px; + --cw-roman-orbit: 28px; + width: var(--cw-dial-size); + max-width: var(--cw-dial-size); + height: var(--cw-dial-size); + flex: 0 0 auto; + margin: 0; border-radius: 50%; position: relative; - border: 2px solid rgba(239, 243, 252, 0.8); - background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.36), rgba(255, 255, 255, 0) 36%), #edf2fb; - box-shadow: inset -5px -5px 10px rgba(0, 0, 0, 0.14), inset 6px 7px 9px rgba(255, 255, 255, 0.42); + border: none; + background: + radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.36), rgba(255, 255, 255, 0) 36%), + #edf2fb; + box-shadow: + 0 0 0 4px #b8c6d8, + 0 0 0 5px rgba(244, 248, 253, 0.94), + 0 0 0 6px #7f94aa, + 0 2px 8px rgba(0, 0, 0, 0.38), + inset 0 1px 2px rgba(255, 255, 255, 0.55), + inset 0 -2px 4px rgba(70, 86, 108, 0.22), + inset -4px -4px 8px rgba(0, 0, 0, 0.12), + inset 5px 6px 8px rgba(255, 255, 255, 0.38); } .cw-roman { position: absolute; left: 50%; top: 50%; - width: 15px; - height: 15px; - margin: -7.5px; - transform: rotate(calc(var(--i) * 30deg)) translateY(-30px) rotate(calc(var(--i) * -30deg)); - font-family: "Times New Roman", serif; + width: 14px; + height: 14px; + margin: -7px; + transform: rotate(calc(var(--i) * 30deg)) translateY(calc(-1 * var(--cw-roman-orbit))) rotate(calc(var(--i) * -30deg)); + font-family: "Clockopia", "Consolas", monospace; font-size: 9px; font-weight: 700; color: #223147; text-align: center; + line-height: 1; } .cw-roman-major { - font-size: 11.5px; + font-size: 11px; opacity: 1; } .cw-roman-minor { - font-size: 3.2px; + font-size: 3px; opacity: 0.25; } -html[data-clock-font="dseg14-modern"] .hub-clock-widget, -html[data-clock-font="dseg14-modern"] .cw-lcd-text { - font-family: "DSEG14 Modern", "Consolas", monospace; -} - -html[data-clock-font="ds-digital"] .hub-clock-widget, -html[data-clock-font="ds-digital"] .cw-lcd-text { - font-family: "DS-Digital", "Consolas", monospace; -} - -html[data-clock-font="digital-7-mono-italic"] .hub-clock-widget, -html[data-clock-font="digital-7-mono-italic"] .cw-lcd-text { - font-family: "Digital-7 Mono Italic", "Consolas", monospace; -} - -.cw-lcd-text { - font-family: "DSEG14 Classic", "Consolas", monospace; +/* Mixed clock typography: line 1 DSEG14, lines 2–3 Digital-7, rest Clockopia */ +.hub-clock-widget .cw-line-time, +.hub-clock-widget .cw-line-time .cw-lcd-text, +.hub-clock-widget .cw-time-main, +.hub-clock-widget .cw-time-main .cw-lcd-text { + font-family: "DSEG14 Classic", "Consolas", monospace !important; font-variant-numeric: tabular-nums; } +.hub-clock-widget .cw-line-region, +.hub-clock-widget .cw-line-region.cw-lcd-text, +.hub-clock-widget .cw-line-date, +.hub-clock-widget .cw-line-date.cw-lcd-text, +.hub-clock-widget .cw-world-label { + font-family: "Digital-7 Mono Italic", "Consolas", monospace !important; + font-variant-numeric: tabular-nums; +} + +.hub-clock-widget .cw-world-section, +.hub-clock-widget .cw-roman { + font-family: "Clockopia", "Consolas", monospace !important; +} + .cw-resize-handle { - position: absolute; - width: 50px; - height: 50px; - min-width: 50px; - min-height: 50px; - z-index: 6; - display: flex; - align-items: center; - justify-content: center; - color: rgba(220, 236, 255, 0.9); - filter: drop-shadow(0 0 4px rgba(150, 200, 255, 0.35)); - pointer-events: auto; - background: transparent; - box-sizing: border-box; + display: none !important; + background: none !important; + border: 0 !important; + box-shadow: none !important; +} + +.hub-clock-widget:hover .cw-resize-handle { + display: flex !important; + background: transparent !important; } .cw-resize-handle-visual { diff --git a/examples/app_hub/index.html b/examples/app_hub/index.html index 3a63a4d..157306c 100644 --- a/examples/app_hub/index.html +++ b/examples/app_hub/index.html @@ -1,5 +1,5 @@ - + @@ -11,7 +11,7 @@ })(); - + @@ -158,7 +158,7 @@ var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover')); var logoEnabled = !!(stage && supportsSvg && supportsLayout); - var logoBuild = '20260530k'; + var logoBuild = '20260530t'; function hubAsset(rel) { var link = document.querySelector('link[href*="hub.css"]'); @@ -193,8 +193,8 @@ }; var clockFontParams = new URLSearchParams(window.location.search); - var clockFontKey = (clockFontParams.get('clockFont') || 'dseg14-classic').toLowerCase(); - if (!LCD_FONT_CATALOG[clockFontKey]) clockFontKey = 'dseg14-classic'; + var clockFontKey = (clockFontParams.get('clockFont') || 'digital-7-mono-italic').toLowerCase(); + if (!LCD_FONT_CATALOG[clockFontKey]) clockFontKey = 'digital-7-mono-italic'; var lcdFontReady = false; var lcdSymbolIds = {}; var lcdFontPrefix = LCD_FONT_CATALOG[clockFontKey].prefix; @@ -550,10 +550,13 @@ function buildWorldClock(tz) { var cell = document.createElement('div'); cell.className = 'cw-cell cw-world-cell'; + var stack = document.createElement('div'); + stack.className = 'cw-world-stack'; + var label = document.createElement('div'); label.className = 'cw-world-label'; label.textContent = cityLabels[tz] || tz.toUpperCase(); - cell.appendChild(label); + stack.appendChild(label); var dial = document.createElement('div'); dial.className = 'cw-dial'; @@ -579,7 +582,8 @@ dial.appendChild(minute); dial.appendChild(second); dial.appendChild(pin); - cell.appendChild(dial); + stack.appendChild(dial); + cell.appendChild(stack); return { tz: tz, hour: hour, minute: minute, second: second, root: cell }; } @@ -664,7 +668,7 @@ if (sym.id) lcdSymbolIds[sym.id] = sym; }); lcdFontReady = Object.keys(lcdSymbolIds).length > 0; - document.documentElement.setAttribute('data-clock-font', clockFontKey); + document.documentElement.setAttribute('data-clock-font', 'mixed'); var widget = document.getElementById('hub-clock-widget'); if (widget) widget.setAttribute('data-lcd-mode', lcdFontReady ? 'svg' : 'text'); done(lcdFontReady); @@ -687,51 +691,9 @@ function renderLcdText(el, text, opts) { opts = opts || {}; if (!el) return; - el.innerHTML = ''; + el.textContent = text; el.classList.add('cw-lcd-text'); - var fontCss = LCD_FONT_CATALOG[clockFontKey].css; - if (!lcdFontReady) { - el.textContent = text; - el.style.fontFamily = fontCss; - return; - } - var renderedSvg = false; - String(text).split('').forEach(function (ch) { - var up = ch.toUpperCase(); - var sid = lcdSymbolId(up === ch ? ch : up); - if (!sid || !lcdSymbolIds[sid]) { - var fb = document.createElement('span'); - fb.className = 'ot-fallback-char' + (opts.bold ? ' ot-fallback-char--bold' : ''); - fb.style.fontFamily = fontCss; - fb.textContent = ch === ' ' ? '\u00A0' : ch; - el.appendChild(fb); - return; - } - var sym = lcdSymbolIds[sid]; - if (!sym.childNodes.length) { - var emptyFb = document.createElement('span'); - emptyFb.className = 'ot-fallback-char'; - emptyFb.style.fontFamily = fontCss; - emptyFb.textContent = ch === ' ' ? '\u00A0' : ch; - el.appendChild(emptyFb); - return; - } - renderedSvg = true; - var wrap = document.createElement('span'); - wrap.className = 'ot-glyph-wrap' + (opts.bold ? ' ot-glyph-wrap--bold' : ''); - if (opts.blinkColon && ch === ':') wrap.className += ' ot-colon-blink'; - var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - svg.setAttribute('viewBox', sym.getAttribute('viewBox') || '0 0 20 32'); - svg.setAttribute('class', 'ot-glyph'); - svg.setAttribute('aria-hidden', 'true'); - cloneLcdSymbolContent(svg, sym); - wrap.appendChild(svg); - el.appendChild(wrap); - }); - if (!renderedSvg) { - el.textContent = text; - el.style.fontFamily = fontCss; - } + if (opts.blinkColon) el.classList.add('ot-colon-blink'); } function loadQuartzAlphabet(done) { @@ -990,28 +952,15 @@ }); } + loadLcdAlphabet(function () { + updateClockWidget(); + setInterval(updateClockWidget, 1000); + }); + + /* Resize handles: hidden by default (CSS). Skip red debug boxes entirely. */ (function makeClockWidgetInteractive() { var widget = document.getElementById('hub-clock-widget'); if (!widget) return; - var arrowPath = 'M44.106,42.943H3.987L44.933,1.995c0.456-0.455,0.456-1.196,0-1.651c-0.452-0.455-1.195-0.455-1.651,0L2.336,41.292V1.168C2.336,0.524,1.81,0,1.168,0C0.523,0,0,0.524,0,1.168v44.111h44.111c0.644,0,1.168-0.522,1.168-1.168C45.279,43.469,44.755,42.943,44.106,42.943z'; - var handles = ['nw', 'ne', 'sw', 'se']; - handles.forEach(function (pos) { - var h = document.createElement('span'); - h.className = 'cw-resize-handle cw-resize-' + pos; - h.dataset.resize = pos; - h.setAttribute('aria-hidden', 'true'); - var visual = document.createElement('span'); - visual.className = 'cw-resize-handle-visual'; - var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); - svg.setAttribute('viewBox', '0 0 45.279 45.279'); - var path = document.createElementNS('http://www.w3.org/2000/svg', 'path'); - path.setAttribute('d', arrowPath); - svg.appendChild(path); - visual.appendChild(svg); - h.appendChild(visual); - widget.appendChild(h); - }); - var drag = null; widget.addEventListener('pointerdown', function (ev) { var target = ev.target; @@ -1030,6 +979,7 @@ drag = { mode: 'move', dx: ev.clientX - box.left, dy: ev.clientY - box.top }; } widget.setPointerCapture(ev.pointerId); + widget.classList.add('is-dragging'); ev.preventDefault(); }); @@ -1061,16 +1011,16 @@ } }); - widget.addEventListener('pointerup', function (ev) { + function endDrag(ev) { if (!drag) return; drag = null; + widget.classList.remove('is-dragging'); widget.releasePointerCapture(ev.pointerId); - }); + } + + widget.addEventListener('pointerup', endDrag); + widget.addEventListener('pointercancel', endDrag); })(); - loadLcdAlphabet(function () { - updateClockWidget(); - setInterval(updateClockWidget, 1000); - }); })();