Improve ui appearance

This commit is contained in:
sfigato 2023-03-07 23:08:22 +01:00
parent 8fa7247835
commit f6fb6f72f4
Signed by: blallo
GPG Key ID: C530464EEDCF489A
6 changed files with 160 additions and 99 deletions

View File

@ -16,6 +16,7 @@
"react-redux": "^8.0.1", "react-redux": "^8.0.1",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-use-websocket": "^4.3.1", "react-use-websocket": "^4.3.1",
"sass": "^1.58.3",
"typescript": "^4.6.0", "typescript": "^4.6.0",
"web-vitals": "^2.1.0" "web-vitals": "^2.1.0"
}, },

View File

@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import logo from './logo.svg';
import { RadioToggler } from './features/radio/Radio'; import { RadioToggler } from './features/radio/Radio';
import './App.css'; import './App.css';
@ -7,7 +6,6 @@ function App() {
return ( return (
<div className="App"> <div className="App">
<header className="App-header"> <header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<RadioToggler /> <RadioToggler />
</header> </header>
</div> </div>

View File

@ -1,79 +0,0 @@
.row {
display: flex;
align-items: center;
justify-content: center;
}
.row > button {
margin-left: 4px;
margin-right: 8px;
}
.row:not(:last-child) {
margin-bottom: 16px;
}
.value {
font-size: 78px;
padding-left: 16px;
padding-right: 16px;
margin-top: 2px;
font-family: 'Courier New', Courier, monospace;
}
.button {
appearance: none;
background: none;
font-size: 32px;
padding-left: 12px;
padding-right: 12px;
outline: none;
border: 2px solid transparent;
color: rgb(112, 76, 182);
padding-bottom: 4px;
cursor: pointer;
background-color: rgba(112, 76, 182, 0.1);
border-radius: 2px;
transition: all 0.15s;
}
.textbox {
font-size: 32px;
padding: 2px;
width: 64px;
text-align: center;
margin-right: 4px;
}
.button:hover,
.button:focus {
border: 2px solid rgba(112, 76, 182, 0.4);
}
.button:active {
background-color: rgba(112, 76, 182, 0.2);
}
.asyncButton {
composes: button;
position: relative;
}
.asyncButton:after {
content: '';
background-color: rgba(112, 76, 182, 0.15);
display: block;
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
opacity: 0;
transition: width 1s linear, opacity 0.5s ease 1s;
}
.asyncButton:active:after {
width: 0%;
opacity: 1;
transition: 0s;
}

View File

@ -0,0 +1,116 @@
@-webkit-keyframes rotor{
from{ -webkit-transform: rotate(0deg); }
to{ -webkit-transform: rotate(360deg); }
}
@-moz-keyframes rotor{
from{ -moz-transform: rotate(0deg); }
to{ -moz-transform: rotate(360deg); }
}
@-o-keyframes rotor{
from{ -o-transform: rotate(0deg); }
to{ -o-transform: rotate(360deg); }
}
@keyframes rotor{
from{ transform: rotate(0deg); }
to{ transform: rotate(360deg); }
}
$circle-size: 350px;
$inner-size: 310px;
$border-radius: 160px;
$margin: 20px;
$shadow-size: 20px;
$rotor-color-active: #6eeb34;
$rotor-color-stopped: #ff0000;
$rotor-color-loading: #fcc203;
$disconnected-color: #8a8987;
$hover-color: #fff7b0;
@mixin wedge($color) {
background-image: linear-gradient(45deg,
white 0%,
white 30%,
$color 30%,
$color 70%,
white 70%,
white 100%);
}
@mixin rotor-animation {
-webkit-animation: rotor 1.5s linear 0s infinite normal;
-mox-animation: rotor 1.5s linear 0s infinite normal;
-o-animation: rotor 1.5s linear 0s infinite normal;
animation: rotor 1.5s linear 0s infinite normal;
}
@mixin circle-shape {
width: $circle-size;
height: $circle-size;
border-radius: $border-radius;
/*** outer circle position: under */
z-index: 1;
position: absolute;
}
.buttonWrap {
width: $circle-size;
height: $circle-size;
margin: $margin 0;
display: inline-block;
position: relative;
/* Inner circle */
.clicker {
width: $inner-size;
height: $inner-size; /* 20px smaller b/c of margin below */
margin: $margin;
background-color: #fff;
border-radius: $border-radius;
/* Overlays this circle on the .circle */
z-index: 2;
position: absolute;
/* centers the text: adjust to desired size */
display: flex;
justify-content: center;
align-content: center;
flex-direction: column;
text-align: center;
font-size: 60px;
user-select: none;
/* shadow */
-webkit-box-shadow: 0px 0px $shadow-size 0px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 0px 0px $shadow-size 0px rgba(0, 0, 0, 0.5);
-o-box-shadow: 0px 0px $shadow-size 0px rgba(0, 0, 0, 0.5);
box-shadow: 0px 0px $shadow-size 0px rgba(0, 0, 0, 0.5);
&:hover {
background-color: $hover-color;
}
}
/** outer circle **/
.circleDisconnected {
@include circle-shape;
background-color: $disconnected-color;
}
.circleStarted {
@include circle-shape;
@include wedge($rotor-color-active);
@include rotor-animation;
}
.circleLoading {
@include circle-shape;
@include wedge($rotor-color-loading);
@include rotor-animation;
}
.circleStopped {
@include circle-shape;
background-color: $rotor-color-stopped;
}
}

View File

@ -4,12 +4,7 @@ import useWebSocket from 'react-use-websocket';
import { useAppSelector, useAppDispatch } from '../../app/hooks'; import { useAppSelector, useAppDispatch } from '../../app/hooks';
import { RadioState, ConnectionState } from '../../app/types'; import { RadioState, ConnectionState } from '../../app/types';
import { import {
setRadioStarted,
setRadioStopped,
toggleRadioState, toggleRadioState,
setConnected,
setDisconnected,
toggleConnection,
selectLoading, selectLoading,
selectRadio, selectRadio,
selectConnection, selectConnection,
@ -19,6 +14,7 @@ import {
getOnWSClose, getOnWSClose,
getOnWSMessage, getOnWSMessage,
} from './radioWS'; } from './radioWS';
import styles from './Radio.module.scss';
const getWSUrl = async () => { const getWSUrl = async () => {
const wsUrl = process.env.WS_ADDR ? process.env.WS_ADDR : "ws://localhost/liveness"; const wsUrl = process.env.WS_ADDR ? process.env.WS_ADDR : "ws://localhost/liveness";
@ -27,7 +23,7 @@ const getWSUrl = async () => {
}; };
export function RadioToggler() { export function RadioToggler() {
const loadingState = useAppSelector(selectLoading); const loading = useAppSelector(selectLoading);
const radioState = useAppSelector(selectRadio); const radioState = useAppSelector(selectRadio);
const connectionState = useAppSelector(selectConnection); const connectionState = useAppSelector(selectConnection);
@ -42,23 +38,38 @@ export function RadioToggler() {
const onWSMessage = getOnWSMessage(dispatch); const onWSMessage = getOnWSMessage(dispatch);
useEffect(() => { useEffect(() => {
if (lastJsonMessage != null) { if (lastJsonMessage != null) {
if (!loading) {
onWSMessage(lastJsonMessage); onWSMessage(lastJsonMessage);
} }
}
}); });
if (loadingState) { let buttonStatus = "";
return <div>Loading...</div>; let circleStyle = styles.circleDisconnected;
if (loading) {
buttonStatus = "Loading";
circleStyle = styles.circleLoading;
} else if (connectionState) {
switch (radioState) {
case RadioState.STARTED:
buttonStatus = "ON AIR";
circleStyle = styles.circleStarted;
break;
case RadioState.STOPPED:
buttonStatus = "OFFLINE";
circleStyle = styles.circleStopped;
break;
}
} }
return ( return (
<div> <div>
<div> <div className={styles.buttonWrap} aria-label="toggle-radio-state">
<button <div
aria-label="toggle-radio-state" className={styles.clicker}
onClick={() => dispatch(toggleRadioState())} onClick={() => dispatch(toggleRadioState())}
>TOGGLE</button> >{buttonStatus}</div>
<div>Radio: {radioState}</div> <div className={circleStyle}></div>
<div>Connection: {connectionState}</div>
</div> </div>
</div > </div >
); );

View File

@ -3053,7 +3053,7 @@ check-types@^11.1.1:
resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.2.tgz#7afc0b6a860d686885062f2dba888ba5710335b4" resolved "https://registry.yarnpkg.com/check-types/-/check-types-11.2.2.tgz#7afc0b6a860d686885062f2dba888ba5710335b4"
integrity sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA== integrity sha512-HBiYvXvn9Z70Z88XKjz3AEKd4HJhBXsa3j7xFnITAzoS8+q6eIGi8qDB8FKPBAjtuxjI/zFpwuiCb8oDtKOYrA==
chokidar@^3.4.2, chokidar@^3.5.3: "chokidar@>=3.0.0 <4.0.0", chokidar@^3.4.2, chokidar@^3.5.3:
version "3.5.3" version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
@ -4997,6 +4997,11 @@ immer@^9.0.16, immer@^9.0.7:
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b" resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b"
integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ== integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==
immutable@^4.0.0:
version "4.2.4"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.2.4.tgz#83260d50889526b4b531a5e293709a77f7c55a2a"
integrity sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==
import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1:
version "3.3.0" version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@ -7899,6 +7904,15 @@ sass-loader@^12.3.0:
klona "^2.0.4" klona "^2.0.4"
neo-async "^2.6.2" neo-async "^2.6.2"
sass@^1.58.3:
version "1.58.3"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.58.3.tgz#2348cc052061ba4f00243a208b09c40e031f270d"
integrity sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
sax@~1.2.4: sax@~1.2.4:
version "1.2.4" version "1.2.4"
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
@ -8105,7 +8119,7 @@ source-list-map@^2.0.0, source-list-map@^2.0.1:
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
source-map-js@^1.0.1, source-map-js@^1.0.2: "source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.1, source-map-js@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==