Style frontend

This commit is contained in:
Kai Vogelgesang 2022-01-11 21:59:53 +01:00
parent a11524516c
commit 220c9b917e
Signed by: kai
GPG Key ID: 0A95D3B6E62C0879
5 changed files with 140 additions and 50 deletions

View File

@ -1,14 +1,32 @@
import React from 'react';
import Layout from './Layout';
import MainView from './MainView';
import { TokenProvider } from './tokenStorage';
import { TokenProvider, TokenContext } from './tokenStorage';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Login from './Login';
import Index from './pages/Index';
import Page404 from './pages/Page404';
const App: React.FC = () => {
return <Layout>
<TokenProvider>
<MainView />
</TokenProvider>
</Layout>
return <TokenProvider>
<Router>
<Layout>
<Content />
</Layout>
</Router>
</TokenProvider>
}
const Content: React.FC = () => {
const tokenStorage = React.useContext(TokenContext);
if (!tokenStorage.token) {
return <Login />
}
return <Routes>
<Route index element={<Index />} />
<Route path="*" element={<Page404 />} />
</Routes>
}
export default App;

View File

@ -1,21 +1,85 @@
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { fab } from "fontawesome.macro";
import { fas, fab } from "fontawesome.macro";
import React from "react";
import { Link } from "react-router-dom";
import { TokenContext } from "./tokenStorage";
export const Layout: React.FC = (props) => {
return <div className="max-w-screen-lg px-6 py-4 mx-auto lg:mx-auto md:py-8 min-h-screen flex flex-col justify-between">
<main className="mb-auto">{props.children}</main>
<footer className="text-xs md:flex justify-between">
<div>
Frontend: <a className="portal ~neutral active" href="https://reactjs.org/"><FontAwesomeIcon icon={fab`react`} />&nbsp;React</a>, <a className="portal ~neutral active" href="https://tailwindcss.com"><FontAwesomeIcon icon={fab`css3-alt`} />&nbsp;tailwind</a> and <a className="portal ~neutral active" href="https://a17t.miles.land/"><div className="select-none font-black">&there4;</div>&nbsp;a17t</a>
return <div className="min-h-screen flex flex-col justify-between">
<Header />
<div className="mb-auto flex flex-row justify-center">
<div className="w-full max-w-screen-lg py-2">
{props.children}
</div>
<div>
<a className="portal ~neutral active" href="https://git.leafbla.de/turtles-1.18.1/controlpanel"><FontAwesomeIcon icon={fab`git-alt`} />&nbsp;Source</a>
</div>
<div>
Backend: <a className="portal ~neutral active" href="https://fastapi.tiangolo.com/"><FontAwesomeIcon icon={fab`python`} />&nbsp;FastAPI</a>
</div>
</footer>
</div>
<Footer />
</div>
}
const Header: React.FC = () => {
const tokenStorage = React.useContext(TokenContext);
return <header className="px-3 py-3 flex flex-row justify-between">
<Link to="/">
<span className="shield ~info shadow">
<FontAwesomeIcon icon={fas`satellite-dish`} />
</span>
<span className="heading ml-2 inline-block h-full align-middle leading-normal">Panel of Controlness</span>
</Link>
<span>
<a className="button ~neutral mr-1" href="docs">
<FontAwesomeIcon icon={fas`book-skull`} />
<span className="ml-1">API Docs</span>
</a>
<button className="button ~neutral @high" onClick={tokenStorage.reset} disabled={tokenStorage.token ? false : true}>
<FontAwesomeIcon icon={fas`arrow-right-from-bracket`} />
<span className="ml-1">Logout</span>
</button>
</span>
</header>
}
const Footer: React.FC = () => {
return <footer className="text-xs px-6 py-6 sm:grid grid-cols-3">
<div className="text-left">
<span className="mr-1">Frontend:</span>
<FooterBadge href="https://reactjs.org" text="React">
<FontAwesomeIcon icon={fab`react`} />
</FooterBadge>
<span className="mr-1">,</span>
<FooterBadge href="https://tailwindcss.com" text="tailwind">
<FontAwesomeIcon icon={fab`css3-alt`} />
</FooterBadge>
<span className="mx-1">and</span>
<FooterBadge href="https://a17t.miles.land" text="a17t">
<span className="select-none font-black">&there4;</span>
</FooterBadge>
</div>
<div className="sm:text-center">
<FooterBadge href="https://git.leafbla.de/turtles-1.18.1/controlpanel" text="Source">
<FontAwesomeIcon icon={fab`git-alt`} />
</FooterBadge>
</div>
<div className="sm:text-right">
<span className="mr-1">Backend:</span>
<FooterBadge href="https://fastapi.tiangolo.com" text="FastAPI">
<FontAwesomeIcon icon={fab`python`} />
</FooterBadge>
</div>
</footer>
}
const FooterBadge: React.FC<{
text: string,
href: string,
}> = ({ text, href, children }) => {
return <a className="portal ~neutral active" href={href}>
<span className="inline-block align-middle mr-1">
{children}
</span>
{text}
</a>
}
export default Layout;

View File

@ -1,14 +0,0 @@
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import Index from "./pages/Index";
import Page404 from './pages/Page404';
export const MainView: React.FC = () => {
return <Router>
<Routes>
<Route index element={<Index />} />
<Route path="*" element={<Page404 />} />
</Routes>
</Router >
}
export default MainView;

View File

@ -1,5 +1,8 @@
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { fas } from "fontawesome.macro";
import React, { useEffect, useState } from "react";
import { Computer, State } from "../proto";
import { Computer, ComputerType, State } from "../proto";
import { TokenContext } from "../tokenStorage";
export const Index: React.FC = () => {
@ -24,8 +27,6 @@ export const Index: React.FC = () => {
}, [tokenStorage.token]);
return <>
<button onClick={tokenStorage.reset}>Logout</button>
<p>State:</p>
{
state
? <Groups computers={state.computers} />
@ -46,17 +47,17 @@ const Groups: React.FC<{ computers: Array<Computer> }> = ({ computers }) => {
groupMap.get(computer.group)!.push(computer);
}
return <>
return <div>
{
Array.from(groupMap.entries()).map((entry) => {
const [group, computers] = entry;
return <div key={group}>
<p>{group}:</p>
<CardList computers={computers}/>
return <div key={group} className="mt-5 first:mt-0">
<h2 className="supra">{group}:</h2>
<CardList computers={computers} />
</div>
})
}
</>
</div>
}
@ -69,7 +70,33 @@ const CardList: React.FC<{ computers: Array<Computer> }> = ({ computers }) => {
}
const ComputerCard: React.FC<{ computer: Computer }> = ({ computer }) => {
return <div>
{computer.is_advanced ? "advanced " : ""}{computer.type} {computer.label || "(no label)"}
const typeIcon: Map<ComputerType, IconProp> = new Map([
["computer", fas`desktop`],
["turtle", fas`pager`],
["pocket", fas`mobile-screen-button`],
]);
return <div className="card mt-2">
<div className="flex flex-row justify-between">
<div>
<p>
<span className="inline-block align-middle">
<FontAwesomeIcon icon={typeIcon.get(computer.type) || fas`question`} />
</span>
<span className={`heading mx-2 text-lg ${computer.label ? "" : "font-extralight"}`}>
{computer.label || "(no label)"}
</span>
{computer.is_advanced && <span className="badge ~yellow @low">advanced</span>}
</p>
<p className="support">
{computer.uuid}
</p>
</div>
<div>
Offline
<span className="icon m-1 text-red-900"><FontAwesomeIcon icon={fas`ban`} /></span>
</div>
</div>
</div>
}

View File

@ -1,5 +1,4 @@
import React, { useEffect, useMemo, useState } from "react";
import Login from "./Login";
const LOCAL_STORAGE_KEY = "token";
@ -48,10 +47,6 @@ export const TokenProvider: React.FC = (props) => {
}, [tokenStorage]);
return <TokenContext.Provider value={tokenStorage}>
{
tokenStorage.token
? props.children
: <Login />
}
{ props.children }
</TokenContext.Provider>
}