Archived
style/ui changes
This commit is contained in:
1 parent
a44056c590
commit
749652163b
14 files changed
+188
-27
No files matched your search
+3
-1
@@ -27,7 +27,9 @@
|
|||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="app">
|
<div id="app">
|
||||||
<img src="%PUBLIC_URL%/logo192.png" alt="Trash Recognizer logo" />
|
<div id="loading-cont" style="text-align: center; display: flex; flex-direction: column; column-gap: 10px; justify-content: center; align-items: center">
|
||||||
|
<img src="%PUBLIC_URL%/logo192.png" alt="Trash Recognizer logo" />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script>
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
@media screen and (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
flex-direction: column !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import { Box } from "../Box";
|
||||||
|
import { CreditTile } from "../CreditTile";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
|
||||||
|
export const About: FC<{ cfn: (d: any) => void }> = (props) => {
|
||||||
|
return (
|
||||||
|
<Box direction="column" gap={10} horizontalAlignment="center" verticalAlignment="center">
|
||||||
|
<h1>Trash helper</h1>
|
||||||
|
<Box className={style.container} direction="row" gap={5} horizontalAlignment={"center"} verticalAlignment="center">
|
||||||
|
<CreditTile title="GRZ4NA" imageUrl="https://avatars.githubusercontent.com/u/74425958?v=4" gh="grz4na" delay={0} />
|
||||||
|
<CreditTile title="makoteq" imageUrl="https://avatars.githubusercontent.com/u/42750440?v=4" gh="makoteq" delay={100} />
|
||||||
|
<CreditTile title="drgoodcat" imageUrl="https://avatars.githubusercontent.com/u/60068941?v=4" gh="drgoodcat" delay={200} />
|
||||||
|
</Box>
|
||||||
|
<button style={{ width: "100%" }} onClick={props.cfn} className="btn-inverse">
|
||||||
|
Zamknij
|
||||||
|
</button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@import "../index.scss";
|
@import "../../index.scss";
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -18,4 +18,6 @@
|
|||||||
padding: 10px;
|
padding: 10px;
|
||||||
clip-path: inset(0 0 0 0);
|
clip-path: inset(0 0 0 0);
|
||||||
position: relative;
|
position: relative;
|
||||||
|
border: 1.5px solid lighten($background, 10%);
|
||||||
|
box-shadow: 0 0 0.5px black;
|
||||||
}
|
}
|
||||||
File renamed without changes.
@@ -5,7 +5,7 @@ import { AlertDialog } from "./index";
|
|||||||
export const spawnDialog = async (elements: (close: (data: any) => void) => ReactNode, windowStyles?: CSSProperties) => {
|
export const spawnDialog = async (elements: (close: (data: any) => void) => ReactNode, windowStyles?: CSSProperties) => {
|
||||||
const container = document.createElement("div");
|
const container = document.createElement("div");
|
||||||
const backgroundColor = "rgba(0,0,0,0.75)";
|
const backgroundColor = "rgba(0,0,0,0.75)";
|
||||||
const animationDuration = 300;
|
const animationDuration = 250;
|
||||||
|
|
||||||
(container.style as any) = "display: block; overflow: hidden; width: 100vw; height: 100vh; z-index: 20; position: fixed; top: 0; left: 0";
|
(container.style as any) = "display: block; overflow: hidden; width: 100vw; height: 100vh; z-index: 20; position: fixed; top: 0; left: 0";
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
@import "../../index.scss";
|
||||||
|
|
||||||
|
.container {
|
||||||
|
text-decoration: none;
|
||||||
|
animation: in-anim 0.3s ease-out both;
|
||||||
|
transform: translateY(15px);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
background-color: transparent;
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 10px;
|
||||||
|
border: solid 1px transparent;
|
||||||
|
display: block;
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba(200, 200, 200, 0.2);
|
||||||
|
border: solid 1px lighten(rgba(200, 200, 200, 0.2), 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.img {
|
||||||
|
border-radius: 50%;
|
||||||
|
padding: 10px;
|
||||||
|
transition: transform 0.2s ease-out;
|
||||||
|
width: 10vh;
|
||||||
|
height: 10vh;
|
||||||
|
.container:hover & {
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 20px;
|
||||||
|
color: $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes in-anim {
|
||||||
|
from {
|
||||||
|
transform: translateY(15px);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import { Box } from "../Box";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
|
||||||
|
export const CreditTile: FC<{ title: string; imageUrl?: string; gh?: string; delay?: number }> = (props) => {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
target={"_blank"}
|
||||||
|
style={{ animationDelay: `${props.delay ? props.delay + 300 : 300}ms` }}
|
||||||
|
className={style.container}
|
||||||
|
rel="noreferrer"
|
||||||
|
href={`https://github.com/${props.gh}`}
|
||||||
|
>
|
||||||
|
<Box gap={5} direction="column" verticalAlignment="center" horizontalAlignment="center">
|
||||||
|
<img className={style.img} src={props.imageUrl} alt={props.title} />
|
||||||
|
<div className={style.title}>{props.title}</div>
|
||||||
|
</Box>
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,39 +1,29 @@
|
|||||||
import { FC, useContext } from "react";
|
import { FC, useContext } from "react";
|
||||||
import { spawnDialog } from "../../AlertDialog/spawnDialog";
|
import { spawnDialog } from "../AlertDialog/spawnDialog";
|
||||||
import { modelCtx } from "../../constants";
|
import { modelCtx } from "../../constants";
|
||||||
import { getVideoFrame } from "../../utils/getVideoFrame";
|
import { About } from "../About";
|
||||||
import { Icon } from "../Icon";
|
import { Icon } from "../Icon";
|
||||||
|
import { Results } from "../Results";
|
||||||
import style from "./index.module.scss";
|
import style from "./index.module.scss";
|
||||||
|
|
||||||
export const Overlay: FC = () => {
|
export const Overlay: FC = () => {
|
||||||
const model = useContext(modelCtx);
|
const model = useContext(modelCtx);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={style.container}>
|
<div className={style.container}>
|
||||||
<button
|
<button className={style.aboutBtn} onClick={() => spawnDialog((c) => <About cfn={c} />)}>
|
||||||
className={style.aboutBtn}
|
|
||||||
onClick={() =>
|
|
||||||
spawnDialog((close) => {
|
|
||||||
return <></>;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Icon type="info-circle-fill" size={30} />
|
<Icon type="info-circle-fill" size={30} />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className={style.captureBtn}
|
className={style.captureBtn}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const can = getVideoFrame(document.querySelector("#video-feed") as HTMLVideoElement);
|
|
||||||
const r = await model?.classify(can);
|
|
||||||
console.log(r);
|
|
||||||
spawnDialog((c) => {
|
spawnDialog((c) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<modelCtx.Provider value={model}>
|
||||||
<img width={500} alt={r?.[0].className} src={can.toDataURL("image/png")} />
|
<Results />
|
||||||
<p>{r?.[0].className}</p>
|
<button style={{ width: "100%" }} onClick={c} className="btn-inverse">
|
||||||
<p>{r?.[0].probability}</p>
|
Zamknij
|
||||||
<button onClick={c}>close</button>
|
</button>
|
||||||
</>
|
</modelCtx.Provider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
.loadingLbl {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.loadingCircle {
|
||||||
|
animation: spin 1s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { FC, useContext, useEffect, useState } from "react";
|
||||||
|
import { modelCtx } from "../../constants";
|
||||||
|
import { getVideoFrame } from "../../utils/getVideoFrame";
|
||||||
|
import style from "./index.module.scss";
|
||||||
|
import loadingCircle from "../../assets/loadingCircle.png";
|
||||||
|
import { Box } from "../Box";
|
||||||
|
|
||||||
|
export const Results: FC<{}> = (_) => {
|
||||||
|
const [el, uel] = useState(
|
||||||
|
<Box direction="column" gap={10} verticalAlignment="center" horizontalAlignment="center">
|
||||||
|
<img className={style.loadingCircle} src={loadingCircle} width={100} height={100} />
|
||||||
|
<h1 className={style.loadingLbl}>Trwa analizowanie zdjęcia...</h1>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
const model = useContext(modelCtx);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const can = getVideoFrame(document.querySelector("#video-feed") as HTMLVideoElement);
|
||||||
|
model?.classify(can).then((r) => {
|
||||||
|
console.log(r);
|
||||||
|
uel(
|
||||||
|
<>
|
||||||
|
<img height={500} alt={r?.[0].className} src={can.toDataURL("image/png")} />
|
||||||
|
<p>{r?.[0].className}</p>
|
||||||
|
<p>{r?.[0].probability}</p>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, [model]);
|
||||||
|
|
||||||
|
return el;
|
||||||
|
};
|
||||||
+24
-1
@@ -40,6 +40,29 @@ button {
|
|||||||
&:hover {
|
&:hover {
|
||||||
background-color: $text;
|
background-color: $text;
|
||||||
color: black;
|
color: black;
|
||||||
border-color: darken($text, 10%);
|
border-color: darken($text, 30%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn-inverse {
|
||||||
|
border: none;
|
||||||
|
padding: 10px;
|
||||||
|
box-shadow: none;
|
||||||
|
border-radius: $borderRadius;
|
||||||
|
background-color: $text;
|
||||||
|
color: black;
|
||||||
|
transition: all $transitionDuration ease;
|
||||||
|
border: 1.5px solid darken($text, 30%);
|
||||||
|
box-shadow: 0 0 0.5px black;
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background-color: $background;
|
||||||
|
color: $text;
|
||||||
|
border-color: lighten($background, 10%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
background-color: darken($text, 20%);
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
+10
-3
@@ -7,7 +7,14 @@ import { modelCtx, videoStreamCtx } from "./constants";
|
|||||||
import { load as loadModel } from "@tensorflow-models/mobilenet";
|
import { load as loadModel } from "@tensorflow-models/mobilenet";
|
||||||
|
|
||||||
const main = async () => {
|
const main = async () => {
|
||||||
console.log("Requesting camera access...");
|
const appContainer = document.querySelector("#app");
|
||||||
|
const infoLabel = document.createElement("p");
|
||||||
|
infoLabel.style.color = "white";
|
||||||
|
infoLabel.style.fontSize = "25px";
|
||||||
|
infoLabel.style.fontFamily = "Arial, sans-serif";
|
||||||
|
infoLabel.style.fontWeight = "100";
|
||||||
|
infoLabel.innerHTML = "Oczekiwanie na uprawnienia dostępu do kamery...";
|
||||||
|
appContainer?.children[0].appendChild(infoLabel);
|
||||||
const videoStream =
|
const videoStream =
|
||||||
(await window.navigator.mediaDevices?.getUserMedia({ video: { facingMode: "environment" } }).catch((e) => {
|
(await window.navigator.mediaDevices?.getUserMedia({ video: { facingMode: "environment" } }).catch((e) => {
|
||||||
if (e instanceof DOMException) {
|
if (e instanceof DOMException) {
|
||||||
@@ -15,7 +22,7 @@ const main = async () => {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
})) ?? null;
|
})) ?? null;
|
||||||
console.log("Loading AI model...");
|
infoLabel.innerHTML = "Wczytywanie aplikacji...";
|
||||||
const model = await loadModel();
|
const model = await loadModel();
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
@@ -25,7 +32,7 @@ const main = async () => {
|
|||||||
</videoStreamCtx.Provider>
|
</videoStreamCtx.Provider>
|
||||||
</modelCtx.Provider>
|
</modelCtx.Provider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
document.querySelector("#app")
|
appContainer
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user