mirror of
git://f0xx.org/android_cast
synced 2026-07-29 03:38:52 +03:00
snap
This commit is contained in:
BIN
examples/app_hub/assets/fonts/Clockopia.ttf
Normal file
BIN
examples/app_hub/assets/fonts/Clockopia.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1920" height="1080" viewBox="0 0 1920 1080" preserveAspectRatio="xMidYMid slice" role="img" aria-label="Internal snapshot globe 20260530b">
|
||||
<!-- Internal snapshot pointer for build 20260530b vertical nav dock + Clockopia clock -->
|
||||
<image href="hub-logo-fragment-globe.svg?v=20260530b" x="0" y="0" width="1920" height="1080"/>
|
||||
</svg>
|
||||
@@ -1,5 +1,13 @@
|
||||
/* Project hub — matches crash console tokens (app.css) */
|
||||
|
||||
@font-face {
|
||||
font-family: "Clockopia";
|
||||
src: url("assets/fonts/Clockopia.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
|
||||
.hub-page {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
@@ -21,7 +29,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
justify-content: flex-start;
|
||||
min-height: calc(100vh - 40px);
|
||||
padding: 32px 28px 48px;
|
||||
box-sizing: border-box;
|
||||
@@ -87,6 +95,84 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.hub-nav-dock,
|
||||
#hub-nav-dock {
|
||||
position: fixed;
|
||||
z-index: 2;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
justify-content: flex-end;
|
||||
align-items: stretch;
|
||||
gap: 5px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
pointer-events: none;
|
||||
grid-template-columns: none !important;
|
||||
grid-auto-flow: row !important;
|
||||
max-width: none;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* app.css .cards { display:grid } must not flatten the dock if classes linger */
|
||||
#hub-nav-dock.cards,
|
||||
#hub-nav-dock.hub-cards,
|
||||
.hub-nav-dock.cards,
|
||||
.hub-nav-dock.hub-cards {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
grid-template-columns: none !important;
|
||||
}
|
||||
|
||||
.hub-nav-dock .hub-card,
|
||||
#hub-nav-dock .hub-card,
|
||||
#hub-nav-dock > a {
|
||||
display: flex !important;
|
||||
flex-direction: row !important;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 14px 16px;
|
||||
width: 100% !important;
|
||||
max-width: 100%;
|
||||
flex: 0 0 auto !important;
|
||||
margin: 0 !important;
|
||||
opacity: 0.85;
|
||||
pointer-events: auto;
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease, filter 0.22s ease;
|
||||
}
|
||||
|
||||
#hub-nav-dock > .hub-card + .hub-card,
|
||||
.hub-nav-dock > .hub-card + .hub-card {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
.hub-nav-dock .hub-card:hover,
|
||||
.hub-nav-dock .hub-card:focus-visible {
|
||||
opacity: 1;
|
||||
color: var(--text);
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
transform: translateY(-2px);
|
||||
border-color: rgba(160, 220, 255, 0.95);
|
||||
box-shadow:
|
||||
0 0 18px rgba(120, 200, 255, 0.55),
|
||||
0 0 36px rgba(90, 170, 255, 0.35),
|
||||
0 10px 28px rgba(0, 0, 0, 0.42);
|
||||
filter: drop-shadow(0 0 10px rgba(140, 210, 255, 0.45));
|
||||
}
|
||||
|
||||
[data-theme="light"] .hub-nav-dock .hub-card:hover,
|
||||
[data-theme="light"] .hub-nav-dock .hub-card:focus-visible {
|
||||
box-shadow:
|
||||
0 0 16px rgba(70, 130, 210, 0.45),
|
||||
0 0 30px rgba(60, 120, 200, 0.28),
|
||||
0 10px 24px rgba(26, 35, 50, 0.22);
|
||||
}
|
||||
|
||||
.hub-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, minmax(200px, 1fr));
|
||||
@@ -182,6 +268,26 @@
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.nav-icon--builder {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border: 2px solid currentColor;
|
||||
border-radius: 3px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.nav-icon--builder::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
top: 7px;
|
||||
width: 10px;
|
||||
height: 2px;
|
||||
background: currentColor;
|
||||
box-shadow: 0 -4px 0 currentColor, 0 4px 0 currentColor;
|
||||
}
|
||||
|
||||
.hub-page .bottom-bar {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
@@ -199,16 +305,17 @@
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.48);
|
||||
border-radius: 18px;
|
||||
overflow: visible;
|
||||
background: rgba(226, 34, 34, 0.5);
|
||||
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;
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
touch-action: none;
|
||||
padding: 40px;
|
||||
padding: 28px 32px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
font-family: "Clockopia", "DS-Digital", "Consolas", monospace;
|
||||
}
|
||||
|
||||
.cw-clock-inner {
|
||||
@@ -251,7 +358,7 @@
|
||||
align-content: start;
|
||||
row-gap: 0;
|
||||
overflow: hidden;
|
||||
background: rgba(0, 180, 80, 0.35);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.cw-row {
|
||||
@@ -284,26 +391,43 @@
|
||||
}
|
||||
|
||||
.cw-time-main {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto auto;
|
||||
align-items: end;
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
column-gap: 6px;
|
||||
column-gap: 4px;
|
||||
line-height: 1;
|
||||
font-weight: 700;
|
||||
font-weight: 400;
|
||||
width: fit-content;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(170, 255, 200, 0.95);
|
||||
border-radius: 8px;
|
||||
padding: 4px 6px;
|
||||
border: 0;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
font-family: "Clockopia", "DS-Digital", "Consolas", monospace;
|
||||
font-variant-numeric: tabular-nums;
|
||||
color: #d8f6b8;
|
||||
text-shadow: 0 0 10px rgba(190, 240, 150, 0.42);
|
||||
}
|
||||
|
||||
#cw-hm-lcd {
|
||||
font-size: clamp(2.4rem, 4.8vw, 3.6rem);
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
#cw-colon-lcd,
|
||||
#cw-ss-lcd {
|
||||
font-size: clamp(1.6rem, 3.2vw, 2.4rem);
|
||||
}
|
||||
|
||||
#cw-tz-text {
|
||||
font-size: clamp(0.95rem, 1.6vw, 1.15rem);
|
||||
margin-left: 10px;
|
||||
opacity: 0.92;
|
||||
}
|
||||
|
||||
.ot-lcd-line {
|
||||
display: inline-flex;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#cw-hm-lcd .ot-glyph {
|
||||
@@ -404,18 +528,20 @@
|
||||
|
||||
.cw-line-region {
|
||||
color: #b8c2d4;
|
||||
font-size: 12px;
|
||||
font-size: clamp(0.62rem, 1vw, 0.75rem);
|
||||
letter-spacing: 0.16em;
|
||||
font-weight: 300;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
font-family: "Clockopia", "Consolas", monospace;
|
||||
}
|
||||
|
||||
.cw-line-date {
|
||||
color: #c5d0e2;
|
||||
font-size: 24px;
|
||||
font-size: clamp(0.95rem, 1.6vw, 1.15rem);
|
||||
letter-spacing: 0.12em;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
font-family: "Clockopia", "Consolas", monospace;
|
||||
}
|
||||
|
||||
.cw-separator {
|
||||
@@ -438,7 +564,7 @@
|
||||
max-width: 100%;
|
||||
border-top: 0;
|
||||
justify-items: center;
|
||||
background: rgba(40, 110, 255, 0.35);
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.cw-world-cell {
|
||||
@@ -465,6 +591,7 @@
|
||||
letter-spacing: 0.12em;
|
||||
margin-top: 0;
|
||||
margin-bottom: 8px;
|
||||
font-family: "Clockopia", "Consolas", monospace;
|
||||
}
|
||||
|
||||
.cw-dial {
|
||||
@@ -782,13 +909,19 @@
|
||||
width: min(94vw, 567px);
|
||||
min-width: 0;
|
||||
}
|
||||
.hub-cards {
|
||||
grid-template-columns: 1fr;
|
||||
max-width: 420px;
|
||||
.hub-nav-dock .hub-card {
|
||||
padding: 14px 16px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.hub-nav-dock .hub-card {
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
.hub-nav-dock .hub-card:hover,
|
||||
.hub-nav-dock .hub-card:focus-visible {
|
||||
transform: none;
|
||||
}
|
||||
.hub-cards .hub-card {
|
||||
transition: border-color 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
})();
|
||||
</script>
|
||||
<link rel="stylesheet" href="/app/androidcast_project/crashes/assets/css/app.css">
|
||||
<link rel="stylesheet" href="hub.css?v=20260529a">
|
||||
<link rel="stylesheet" href="hub.css?v=20260530h">
|
||||
<link rel="stylesheet" href="hub-logo-layers.css">
|
||||
<script src="assets/analytics.config.js"></script>
|
||||
<script src="/app/androidcast_project/crashes/assets/js/analytics.js" defer></script>
|
||||
@@ -72,29 +72,72 @@
|
||||
</select>
|
||||
</label>
|
||||
</header>
|
||||
<nav class="hub-cards cards cards--lift" aria-label="Android Cast apps">
|
||||
<a class="hub-card card card--lift" href="crashes/?view=reports">
|
||||
<span class="hub-card-icon" aria-hidden="true">
|
||||
<span class="nav-icon nav-icon--reports"></span>
|
||||
</span>
|
||||
<span class="hub-card-label">AndroidCast reports</span>
|
||||
</a>
|
||||
<a class="hub-card card card--lift" href="git/">
|
||||
<span class="hub-card-icon" aria-hidden="true">
|
||||
<span class="nav-icon nav-icon--git"></span>
|
||||
</span>
|
||||
<span class="hub-card-label">AndroidCast git</span>
|
||||
</a>
|
||||
<a class="hub-card card card--lift" href="crashes/?view=tickets">
|
||||
<span class="hub-card-icon" aria-hidden="true">
|
||||
<span class="nav-icon nav-icon--tickets"></span>
|
||||
</span>
|
||||
<span class="hub-card-label">AndroidCast tickets</span>
|
||||
</a>
|
||||
</nav>
|
||||
</main>
|
||||
</div>
|
||||
<nav class="hub-nav-dock" id="hub-nav-dock" aria-label="Android Cast apps">
|
||||
<a class="hub-card card card--lift" href="git/">
|
||||
<span class="hub-card-icon" aria-hidden="true">
|
||||
<span class="nav-icon nav-icon--git"></span>
|
||||
</span>
|
||||
<span class="hub-card-label">AndroidCast git</span>
|
||||
</a>
|
||||
<a class="hub-card card card--lift" href="crashes/?view=tickets">
|
||||
<span class="hub-card-icon" aria-hidden="true">
|
||||
<span class="nav-icon nav-icon--tickets"></span>
|
||||
</span>
|
||||
<span class="hub-card-label">AndroidCast tickets</span>
|
||||
</a>
|
||||
<a class="hub-card card card--lift" href="crashes/?view=reports">
|
||||
<span class="hub-card-icon" aria-hidden="true">
|
||||
<span class="nav-icon nav-icon--reports"></span>
|
||||
</span>
|
||||
<span class="hub-card-label">AndroidCast crashes</span>
|
||||
</a>
|
||||
<a class="hub-card card card--lift" href="build/">
|
||||
<span class="hub-card-icon" aria-hidden="true">
|
||||
<span class="nav-icon nav-icon--builder"></span>
|
||||
</span>
|
||||
<span class="hub-card-label">AndroidCast builder</span>
|
||||
</a>
|
||||
</nav>
|
||||
<footer class="bottom-bar">(c) Anton Afanaasyeu</footer>
|
||||
<script>
|
||||
(function () {
|
||||
var GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 330 };
|
||||
function globeCoverRect() {
|
||||
var vw = window.innerWidth;
|
||||
var vh = window.innerHeight;
|
||||
var scale = Math.max(vw / GLOBE_VIEW.imgW, vh / GLOBE_VIEW.imgH);
|
||||
var drawW = GLOBE_VIEW.imgW * scale;
|
||||
var drawH = GLOBE_VIEW.imgH * scale;
|
||||
var offX = (vw - drawW) / 2;
|
||||
var offY = (vh - drawH) / 2;
|
||||
var left = offX + (GLOBE_VIEW.cx - GLOBE_VIEW.r) * scale;
|
||||
var top = offY + (GLOBE_VIEW.cy - GLOBE_VIEW.r) * scale;
|
||||
var bottom = offY + (GLOBE_VIEW.cy + GLOBE_VIEW.r) * scale;
|
||||
var right = offX + (GLOBE_VIEW.cx + GLOBE_VIEW.r) * scale;
|
||||
return { left: left, top: top, bottom: bottom, right: right, width: right - left, height: bottom - top };
|
||||
}
|
||||
function layoutHubNavDock() {
|
||||
var dock = document.getElementById('hub-nav-dock');
|
||||
if (!dock) return;
|
||||
var globe = globeCoverRect();
|
||||
var insetX = Math.max(16, globe.width * 0.06);
|
||||
var dockW = Math.min(300, Math.max(210, globe.width * 0.38));
|
||||
dock.style.width = dockW + 'px';
|
||||
dock.style.left = (globe.left + insetX) + 'px';
|
||||
dock.style.top = globe.top + 'px';
|
||||
dock.style.height = globe.height + 'px';
|
||||
dock.style.display = 'flex';
|
||||
dock.style.flexDirection = 'column';
|
||||
dock.style.flexWrap = 'nowrap';
|
||||
dock.style.gap = '5px';
|
||||
dock.style.justifyContent = 'flex-end';
|
||||
}
|
||||
layoutHubNavDock();
|
||||
window.addEventListener('resize', layoutHubNavDock);
|
||||
})();
|
||||
</script>
|
||||
<script>
|
||||
(function () {
|
||||
var sel = document.getElementById('theme-select');
|
||||
@@ -116,7 +159,7 @@
|
||||
var supportsLayout = !!(window.CSS && CSS.supports && CSS.supports('object-fit', 'cover'));
|
||||
if (!supportsSvg || !supportsLayout) return;
|
||||
|
||||
var logoBuild = '20260529a';
|
||||
var logoBuild = '20260530h';
|
||||
var fragments = {
|
||||
space: 'assets/hub-logo-fragment-space.svg',
|
||||
globe: 'assets/hub-logo-fragment-globe.svg',
|
||||
@@ -167,6 +210,44 @@
|
||||
stage.hidden = false;
|
||||
stage.setAttribute('aria-hidden', 'true');
|
||||
|
||||
/* Nav dock overlaps globe left hemisphere; stack top → bottom. */
|
||||
var GLOBE_VIEW = { imgW: 1920, imgH: 1080, cx: 720, cy: 560, r: 330 };
|
||||
function globeCoverRect() {
|
||||
var vw = window.innerWidth;
|
||||
var vh = window.innerHeight;
|
||||
var scale = Math.max(vw / GLOBE_VIEW.imgW, vh / GLOBE_VIEW.imgH);
|
||||
var drawW = GLOBE_VIEW.imgW * scale;
|
||||
var drawH = GLOBE_VIEW.imgH * scale;
|
||||
var offX = (vw - drawW) / 2;
|
||||
var offY = (vh - drawH) / 2;
|
||||
var left = offX + (GLOBE_VIEW.cx - GLOBE_VIEW.r) * scale;
|
||||
var top = offY + (GLOBE_VIEW.cy - GLOBE_VIEW.r) * scale;
|
||||
var bottom = offY + (GLOBE_VIEW.cy + GLOBE_VIEW.r) * scale;
|
||||
var right = offX + (GLOBE_VIEW.cx + GLOBE_VIEW.r) * scale;
|
||||
return { left: left, top: top, bottom: bottom, right: right, width: right - left, height: bottom - top };
|
||||
}
|
||||
function layoutHubNavDock() {
|
||||
var dock = document.getElementById('hub-nav-dock');
|
||||
if (!dock) return;
|
||||
var globe = globeCoverRect();
|
||||
var insetX = Math.max(16, globe.width * 0.06);
|
||||
var dockW = Math.min(300, Math.max(210, globe.width * 0.38));
|
||||
dock.style.width = dockW + 'px';
|
||||
dock.style.left = (globe.left + insetX) + 'px';
|
||||
dock.style.top = globe.top + 'px';
|
||||
dock.style.height = globe.height + 'px';
|
||||
dock.style.right = 'auto';
|
||||
dock.style.bottom = 'auto';
|
||||
dock.style.display = 'flex';
|
||||
dock.style.flexDirection = 'column';
|
||||
dock.style.flexWrap = 'nowrap';
|
||||
dock.style.alignItems = 'stretch';
|
||||
dock.style.gap = '5px';
|
||||
dock.style.justifyContent = 'flex-end';
|
||||
}
|
||||
layoutHubNavDock();
|
||||
window.addEventListener('resize', layoutHubNavDock);
|
||||
|
||||
var docsModal = document.getElementById('hub-docs-modal');
|
||||
var docsToc = document.getElementById('hub-docs-toc');
|
||||
var docsPanels = document.getElementById('hub-docs-panels');
|
||||
@@ -737,15 +818,20 @@
|
||||
return model;
|
||||
});
|
||||
|
||||
function setClockopiaText(el, text) {
|
||||
if (!el) return;
|
||||
el.textContent = text;
|
||||
}
|
||||
|
||||
function updateClockWidget() {
|
||||
var now = new Date();
|
||||
var p = timeParts(now, primaryTz);
|
||||
renderOvertimeDigits(document.getElementById('cw-hm-lcd'), p.hh + p.mm, false, false);
|
||||
renderOvertimeDigits(document.getElementById('cw-colon-lcd'), ':', false, false);
|
||||
renderOvertimeDigits(document.getElementById('cw-ss-lcd'), p.ss, false, false);
|
||||
renderOvertimeText(document.getElementById('cw-tz-text'), gmtOffsetLabel(now, primaryTz), { bold: false });
|
||||
renderOvertimeText(document.getElementById('cw-region'), regionLabel(primaryTz), { bold: false });
|
||||
renderOvertimeText(document.getElementById('cw-date-line'), formatDateLine(now, primaryTz), { bold: false });
|
||||
setClockopiaText(document.getElementById('cw-hm-lcd'), p.hh + ':' + p.mm);
|
||||
setClockopiaText(document.getElementById('cw-colon-lcd'), ':');
|
||||
setClockopiaText(document.getElementById('cw-ss-lcd'), p.ss);
|
||||
setClockopiaText(document.getElementById('cw-tz-text'), gmtOffsetLabel(now, primaryTz));
|
||||
setClockopiaText(document.getElementById('cw-region'), regionLabel(primaryTz));
|
||||
setClockopiaText(document.getElementById('cw-date-line'), formatDateLine(now, primaryTz));
|
||||
|
||||
secondary.forEach(function (clock) {
|
||||
var t = timeParts(now, clock.tz);
|
||||
@@ -836,10 +922,8 @@
|
||||
widget.releasePointerCapture(ev.pointerId);
|
||||
});
|
||||
})();
|
||||
loadOvertimeAlphabet(function () {
|
||||
updateClockWidget();
|
||||
setInterval(updateClockWidget, 1000);
|
||||
});
|
||||
updateClockWidget();
|
||||
setInterval(updateClockWidget, 1000);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user