start getting dashboard working

Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
Sean Cross 2023-12-02 13:13:19 +08:00
parent ceb2d55543
commit 81ec574f41
3 changed files with 443 additions and 93 deletions

View File

@ -1,16 +1,116 @@
import { FarpatchWidget, makeNavView as makeNavItem } from "../interfaces"; import { FarpatchWidget, makeNavView as makeNavItem } from "../interfaces";
class DashboardItem {
id: string;
name: string;
value: string;
constructor(id: string, name: string, value: string) {
this.id = id;
this.name = name;
this.value = value;
}
render(): HTMLElement {
var field: HTMLElement = document.createElement("div");
field.classList.add("fieldset-item");
var navViewIcon = document.createElement("span");
navViewIcon.setAttribute("aria-hidden", "true");
navViewIcon.classList.add("las");
navViewIcon.classList.add("la-3x");
navViewIcon.classList.add("la-" + this.id);
navViewIcon.classList.add("icon");
var inputStack: HTMLElement = document.createElement("div");
inputStack.classList.add("input-stack");
var label: HTMLElement = document.createElement("label");
label.setAttribute("for", this.id);
label.setAttribute("id", this.id);
label.setAttribute("aria-hidden", "true");
label.innerText = this.name;
var input: HTMLElement = document.createElement("input");
input.setAttribute("name", this.id);
input.setAttribute("aria-labelledby", this.id);
input.setAttribute("type", "range");
input.setAttribute("value", this.value);
input.setAttribute("max", "10");
input.setAttribute("style", "--track-fill: 30%");
inputStack.appendChild(label);
inputStack.appendChild(input);
field.appendChild(navViewIcon);
field.appendChild(inputStack);
return field;
}
}
class DashboardSection {
id: string;
name: string;
items: DashboardItem[];
constructor(id: string, name: string, items: DashboardItem[]) {
this.id = id;
this.name = name;
this.items = items;
}
render(): HTMLElement {
var root: HTMLElement = document.createElement("section");
var header: HTMLElement = document.createElement("header");
var h2: HTMLElement = document.createElement("h2");
h2.innerText = this.name;
header.appendChild(h2);
root.appendChild(header);
var fieldset: HTMLElement = document.createElement("fieldset");
for (var i = 0; i < this.items.length; i++) {
fieldset.appendChild(this.items[i].render());
}
root.appendChild(fieldset);
return root;
}
}
export class DashboardWidget implements FarpatchWidget { export class DashboardWidget implements FarpatchWidget {
index: number = 0; index: number = 0;
view: HTMLElement = document.createElement("div"); view: HTMLElement = document.createElement("form");
navItem: HTMLElement; navItem: HTMLElement;
name: string; name: string;
icon: string = "home"; icon: string = "home";
title: string = "Dashboard"; title: string = "Dashboard";
sections: DashboardSection[];
constructor(name: string) { constructor(name: string) {
this.name = name; this.name = name;
this.navItem = makeNavItem(name, this.icon, this.title); this.navItem = makeNavItem(name, this.icon, this.title);
this.sections = [
new DashboardSection("voltages", "Voltages", [
new DashboardItem("system-voltage", "System", "3.3V"),
new DashboardItem("target-voltage", "Target", "1.8V"),
new DashboardItem("usb-voltage", "USB", "5.0V"),
new DashboardItem("extra-voltage", "Extra", "3.8V"),
]),
new DashboardSection("network", "Network", [
new DashboardItem("ip-address", "IP Address", "10.0.0.5"),
new DashboardItem("gdb-port", "GDB Port", "2022"),
new DashboardItem("uart-port", "UART Port", "2023"),
]),
new DashboardSection("target", "Target", [
new DashboardItem("detected-devices", "Detected Devices", "STM32F4"),
new DashboardItem("flash-size", "Flash Size", "512k"),
new DashboardItem("ram-size", "RAM Size", "32k"),
]),
new DashboardSection("about", "About", [
new DashboardItem("farpatch-version", "Farpatch Version", "5555239293"),
new DashboardItem("bmp-version", "Blackmagic Version", "1.10.0"),
]),
];
} }
updateIndex(index: number): void { updateIndex(index: number): void {
@ -18,32 +118,10 @@ export class DashboardWidget implements FarpatchWidget {
} }
onInit(): void { onInit(): void {
this.view.innerHTML = ` for (var i = 0; i < this.sections.length; i++) {
<div class="fieldset-item"> this.view.appendChild(this.sections[i].render());
<picture aria-hidden="true"> }
<svg viewBox="0 0 24 24">
<title>A note icon</title>
<path d="M12 3v10.55c-.59-.34-1.27-.55-2-.55-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z"/>
</svg>
</picture>
<div class="input-stack">
<label
for="media-volume"
id="media-volume"
aria-hidden="true">
Media volume
</label>
<input
name="media-volume"
aria-labelledby="media-volume"
type="range"
value="3"
max="10"
style="--track-fill: 30%"
>
</div>
</div>
`;
console.log("Initialized Dashboard Widget"); console.log("Initialized Dashboard Widget");
} }
onFocus(element: HTMLElement): void { onFocus(element: HTMLElement): void {

334
static/css/fancy.css Normal file
View File

@ -0,0 +1,334 @@
@custom-media --motionOK (prefers-reduced-motion: no-preference);
:root {
--surface1: lch(10 0 0);
--surface2: lch(15 0 0);
--surface3: lch(20 0 0);
--surface4: lch(25 0 0);
--text1: lch(95 0 0);
--text2: lch(75 0 0);
--brand: lch(64 20 237);
--brand-bg1: lch(70 64 349);
--brand-bg2: lch(60 84 300);
--brand-bg-gradient: linear-gradient(
to bottom,
var(--brand-bg1),
var(--brand-bg2)
);
--thumb-highlight-color: lch(100 0 0 / 20%);
--space-xxs: .25rem;
--space-xs: .5rem;
--space-sm: 1rem;
--space-md: 1.5rem;
--space-lg: 2rem;
--space-xl: 3rem;
--space-xxl: 6rem;
--isLTR: 1;
--isRTL: -1;
&:dir(rtl) {
--isLTR: -1;
--isRTL: 1;
}
@media (prefers-color-scheme: light) {
& {
--surface1: lch(90 0 0);
--surface2: lch(100 0 0);
--surface3: lch(98 0 0);
--surface4: lch(85 0 0);
--text1: lch(20 0 0);
--text2: lch(40 0 0);
--brand: lch(64 40 237);
--brand-bg1: lch(50 64 349);
--brand-bg2: lch(40 84 300);
--thumb-highlight-color: lch(0 0 0 / 20%);
}
}
}
form {
max-width: 89vw;
display: grid;
gap: var(--space-xl) var(--space-xxl);
--repeat: auto-fit;
grid-template-columns:
repeat(var(--repeat), minmax(min(10ch, 100%), 35ch));
align-items: flex-start;
@media (orientation: landscape) and (width >= 640px) { & {
--repeat: 2;
}}
}
section {
display: grid;
gap: var(--space-md);
}
header {
display: grid;
gap: var(--space-xxs);
}
fieldset {
border: 1px solid var(--surface4);
background: var(--surface4);
padding: 0;
margin: 0;
display: grid;
gap: 1px;
border-radius: var(--space-sm);
overflow: hidden;
transition: box-shadow .3s ease;
&:focus-within {
box-shadow: 0 5px 20px -10px hsl(0 0% 0% / 50%);
}
}
input[type="range"] {
--track-height: .5ex;
--track-fill: 0%;
--thumb-size: 3ex;
--thumb-offset: -1.25ex;
--thumb-highlight-size: 0px;
display: block;
inline-size: 100%;
margin: 1ex 0;
appearance: none;
background: transparent;
outline-offset: 5px;
@media (hover: none) {
& {
--thumb-size: 30px;
--thumb-offset: -14px;
}
}
&::-webkit-slider-runnable-track {
appearance: none;
block-size: var(--track-height);
border-radius: 5ex;
background:
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
var(--brand-bg-gradient) fixed;
}
&::-moz-range-track {
appearance: none;
block-size: var(--track-height);
border-radius: 5ex;
background:
linear-gradient(
to right,
transparent var(--track-fill),
var(--surface1) 0%
),
var(--brand-bg-gradient) fixed;
}
&::-webkit-slider-thumb {
appearance: none;
cursor: ew-resize;
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-block-start: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
@nest .fieldset-item:focus-within & {
border-color: var(--surface2);
}
}
&::-moz-range-thumb {
appearance: none;
cursor: ew-resize;
border: 3px solid var(--surface3);
block-size: var(--thumb-size);
inline-size: var(--thumb-size);
margin-block-start: var(--thumb-offset);
border-radius: 50%;
background: var(--brand-bg-gradient) fixed;
box-shadow: 0 0 0 var(--thumb-highlight-size) var(--thumb-highlight-color);
@media (--motionOK) {
& {
transition: box-shadow .1s ease;
}
}
@nest .fieldset-item:focus-within & {
border-color: var(--surface2);
}
}
&:is(:hover,:active) {
--thumb-highlight-size: 10px;
}
}
input[type="checkbox"] {
inline-size: var(--space-sm);
block-size: var(--space-sm);
margin: 0;
outline-offset: 5px;
accent-color: var(--brand);
position: relative;
transform-style: preserve-3d;
cursor: pointer;
&:hover::before {
--thumb-scale: 1;
}
@media (hover: none) {
& {
inline-size: var(--space-md);
block-size: var(--space-md);
}
}
&::before {
--thumb-scale: .01;
--thumb-highlight-size: var(--space-xl);
content: "";
inline-size: var(--thumb-highlight-size);
block-size: var(--thumb-highlight-size);
clip-path: circle(50%);
position: absolute;
inset-block-start: 50%;
inset-inline-start: 50%;
background: var(--thumb-highlight-color);
transform-origin: center center;
transform:
translateX(calc(var(--isRTL) * 50%))
translateY(-50%)
translateZ(-1px)
scale(var(--thumb-scale))
;
will-change: transform;
@media (--motionOK) {
& {
transition: transform .2s ease;
}
}
}
}
.fieldset-item {
background: var(--surface3);
transition: background .2s ease;
display: grid;
grid-template-columns: var(--space-lg) 1fr;
gap: var(--space-md);
padding-block: var(--space-sm);
padding-inline: var(--space-md);
@media (width >= 540px) {
grid-template-columns: var(--space-xxl) 1fr;
gap: var(--space-xs);
padding-block: var(--space-md);
padding-inline: 0 var(--space-xl);
}
&:focus-within {
background: var(--surface2);
& svg {
fill: white;
}
& picture {
clip-path: circle(50%);
background: var(--brand-bg-gradient) fixed;
}
}
& > :is(.input-stack, label) {
display: grid;
gap: var(--space-xs);
}
& > .input-stack > label {
display: contents;
}
& > picture {
block-size: var(--space-xl);
inline-size: var(--space-xl);
clip-path: circle(40%);
display: inline-grid;
place-content: center;
background: var(--surface3) fixed;
@media (--motionOK) {
& {
transition: clip-path .3s ease;
}
}
}
& svg {
fill: var(--text2);
block-size: var(--space-md);
}
& > :is(picture, input[type="checkbox"]) {
place-self: center;
}
}
small {
color: var(--text2);
line-height: 1.5;
}
.github-corner {
color: var(--surface1);
fill: var(--surface3);
&:hover .octo-arm {
animation: octocat-wave 560ms ease-in-out
}
}
@keyframes octocat-wave{
0%,100% {
transform: rotate(0)
}
20%,60% {
transform: rotate(-25deg)
}
40%,80% {
transform: rotate(10deg)
}
}

View File

@ -7,75 +7,13 @@
<link rel="stylesheet" href="css/desktop.css"> <link rel="stylesheet" href="css/desktop.css">
<link rel="stylesheet" href="css/mobile.css"> <link rel="stylesheet" href="css/mobile.css">
<link rel="stylesheet" href="css/xterm.css" /> <link rel="stylesheet" href="css/xterm.css" />
<link rel="stylesheet" href="css/fancy.css" />
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width">
<title>Farpatch</title>
<script src="main.js"></script> <script src="main.js"></script>
</head> </head>
<body> <body></body>
<!-- <nav class="sidenav">
<ul class="sidenav-nav">
<li class="sidenav-item" id="dashboard-button">
<a class="sidenav-link">
<span class="las la-3x la-home icon"></span>
<span class="link-text">Dashboard</span>
</a>
</li>
<li class="sidenav-item" id="uart-button">
<a class="sidenav-link">
<span class="las la-3x la-keyboard icon">*</span>
<span class="link-text">UART</span>
</a>
</li>
<li class="sidenav-item" id="rtt-button">
<a class="sidenav-link">
<span class="las la-3x la-microchip icon"></span>
<span class="link-text">RTT</span>
</a>
</li>
<li class="sidenav-item" id="debug-button">
<a class="sidenav-link">
<span class="las la-3x la-scroll icon"></span>
<span class="link-text">Debug</span>
</a>
</li>
<li class="sidenav-item" id="settings-button">
<a class="sidenav-link">
<span class="las la-3x la-sliders-h icon"></span>
<span class="link-text">Settings</span>
</a>
</li>
<li class="sidenav-item-filler"></li>
<li class="sidenav-item sidenav-item-toggle" id="rail-toggle-button">
<a class="sidenav-link">
<span class="las la-3x la-bars icon"></span>
<span class="link-text">Hide</span>
</a>
</li>
</ul>
</nav>
<main>
<div class="main-content" id="dashboard-view">
<div>Version: 1.0</div>
</div>
<div class="main-content" id="uart-view"></div>
<div class="main-content" id="rtt-view">
<div>[RTT goes here]</div>
</div>
<div class="main-content" id="debug-view">
<div>[Debug goes here]</div>
</div>
<div class="main-content" id="settings-view">
<div>[Settings goes here]</div>
</div>
</main> -->
</body>
</html> </html>