Style frontend
This commit is contained in:
parent
a11524516c
commit
220c9b917e
@ -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;
|
||||
|
@ -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`} /> React</a>, <a className="portal ~neutral active" href="https://tailwindcss.com"><FontAwesomeIcon icon={fab`css3-alt`} /> tailwind</a> and <a className="portal ~neutral active" href="https://a17t.miles.land/"><div className="select-none font-black">∴</div> 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`} /> Source</a>
|
||||
</div>
|
||||
<div>
|
||||
Backend: <a className="portal ~neutral active" href="https://fastapi.tiangolo.com/"><FontAwesomeIcon icon={fab`python`} /> 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">∴</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;
|
@ -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;
|
@ -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>
|
||||
}
|
@ -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>
|
||||
}
|
Loading…
Reference in New Issue
Block a user