working qr scanner nice

This commit is contained in:
Paul Miller
2023-03-14 16:25:34 -05:00
parent 44cdbdcfcb
commit 1a08aca881
7 changed files with 134 additions and 9 deletions

14
package-lock.json generated
View File

@@ -12,6 +12,7 @@
"framer-motion": "^8.5.4",
"nostr-react": "^0.6.4",
"nostr-tools": "^1.3.2",
"qr-scanner": "^1.4.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-linkify": "1.0.0-alpha",
@@ -2433,6 +2434,11 @@
"integrity": "sha512-5EWrvLmglK+imbCJY0+INViFWUHg1AHel1sq4ZVSfdcNqGy9Edv3UB9IIzzg+xPaUcAgZYcfVs2fBcwDeZzU0A==",
"dev": true
},
"node_modules/@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
"integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
},
"node_modules/@types/prop-types": {
"version": "15.7.5",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
@@ -4609,6 +4615,14 @@
"node": ">=6"
}
},
"node_modules/qr-scanner": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/qr-scanner/-/qr-scanner-1.4.2.tgz",
"integrity": "sha512-kV1yQUe2FENvn59tMZW6mOVfpq9mGxGf8l6+EGaXUOd4RBOLg7tRC83OrirM5AtDvZRpdjdlXURsHreAOSPOUw==",
"dependencies": {
"@types/offscreencanvas": "^2019.6.4"
}
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",

View File

@@ -13,6 +13,7 @@
"framer-motion": "^8.5.4",
"nostr-react": "^0.6.4",
"nostr-tools": "^1.3.2",
"qr-scanner": "^1.4.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-linkify": "1.0.0-alpha",

View File

@@ -4,6 +4,7 @@ import Join from "@/routes/Join";
import Layout from "@/components/Layout";
import SecretWaitlistSkipper from "@/routes/SecretWaitlistSkipper";
import Home from "@/routes/Home";
import Scanner from "@/routes/Scanner";
function App() {
let active = localStorage.getItem('active') || "";
@@ -13,10 +14,10 @@ function App() {
{/* globals such as header will go here */}
<Routes>
{/* <Route path="/" element={<Home />} /> */}
<Route path="/" element={<Layout />}>
<Route index element={active === "true" ? <Home /> : <Join />} />
<Route path="secretwaitlistskipper" element={<SecretWaitlistSkipper />} />
<Route path="scanner" element={<Scanner />} />
</Route>
</Routes>
</div>

37
src/components/Reader.tsx Normal file
View File

@@ -0,0 +1,37 @@
import QrScanner from 'qr-scanner';
import { useEffect, useRef } from "react";
export default function Scanner({ onResult }: { onResult: (result: string) => void }) {
const container = useRef<HTMLVideoElement | null>(null);
useEffect(() => {
let scanner: QrScanner | null;
if (container.current) {
scanner = new QrScanner(
container.current,
(result) => {
onResult(result.data);
},
{
returnDetailedScanResult: true,
}
);
scanner.start();
}
return () => {
scanner?.destroy();
scanner = null;
}
}, [onResult]);
return (
<>
<div id="video-container">
<video ref={container} className="w-full h-full fixed object-cover bg-gray"></video>
</div>
</>
);
}

View File

@@ -3,12 +3,20 @@
@tailwind utilities;
body {
@apply text-white;
@apply bg-fixed bg-no-repeat bg-gradient-to-b from-black to-[#0b215b] bg-black;
@apply text-white bg-black;
@apply bg-fixed bg-no-repeat bg-gradient-to-b from-black to-[#0b215b];
overscroll-behavior-y: none;
min-height: 100.3%;
}
.bg-gradient {
@apply bg-fixed bg-no-repeat bg-gradient-to-b from-black to-[#0b215b];
}
.bg-gray {
@apply bg-fixed bg-no-repeat bg-gradient-to-b from-[hsl(224,5%,5%)] to-[hsl(224,5%,20%)];
}
.react-modal-sheet-container {
@apply !bg-[#262626];
}
@@ -16,3 +24,19 @@ body {
a {
@apply underline decoration-light-text hover:decoration-white;
}
#video-container {
position: relative;
width: max-content;
height: max-content;
overflow: hidden;
}
#video-container .scan-region-highlight {
border-radius: 30px;
outline: rgba(0, 0, 0, 0.25) solid 50vmax;
}
#video-container .scan-region-highlight-svg {
display: none;
}

View File

@@ -5,6 +5,7 @@ import mutiny_m from '@/assets/m.svg';
import scan from '@/assets/scan.svg';
import settings from '@/assets/settings.svg';
import send from '@/assets/send.svg';
import { Link } from 'react-router-dom';
function ActivityItem() {
return (
@@ -89,17 +90,16 @@ function App() {
<nav className='bg-black fixed bottom-0 shadow-lg z-40 w-full safe-bottom'>
<ul className='h-16 flex justify-between px-16 items-center'>
<li className='h-full border-t-2 border-b-2 border-b-black flex flex-col justify-center'>
<img src={mutiny_m} className="App-logo" alt="logo" />
<img src={mutiny_m} alt="home" />
</li>
<li>
<img src={scan} className="App-logo" alt="logo" />
<Link to="/scanner">
<img src={scan} alt="scan" />
</Link>
</li>
<li>
<img src={settings} className="App-logo" alt="logo" />
<img src={settings} alt="settings" />
</li>
{/* <li>home</li> */}
{/* <li>scan</li> */}
{/* <li>settings</li> */}
</ul>
</nav>

48
src/routes/Scanner.tsx Normal file
View File

@@ -0,0 +1,48 @@
import { useNavigate } from "react-router-dom";
import button from "@/styles/button";
import { useState } from "react";
import Reader from "@/components/Reader";
export default function Scanner() {
const navigate = useNavigate();
const [scanResult, setScanResult] = useState<string | null>(null);
function onResult(result: string) {
setScanResult(result);
}
function exit() {
navigate("/")
}
return (
<>
{scanResult ?
<div className="w-full p-8">
<div className="mt-[20vw] rounded-xl p-4 flex flex-col gap-2 bg-[rgba(0,0,0,0.5)]">
<header className='text-sm font-semibold uppercase'>
Scan Result
</header>
<code className="break-all">{scanResult}</code>
</div>
</div> : <Reader onResult={onResult} />
}
<div className="w-full flex flex-col fixed bottom-[2rem] gap-8 px-8">
{!scanResult &&
<>
<button className={button({ intent: "blue" })} onClick={exit}>Paste Something</button>
<button className={button()} onClick={exit}>Cancel</button>
</>
}
{scanResult &&
<>
<button className={button({ intent: "red" })} onClick={() => setScanResult(null)}>Try Again</button>
<button className={button()} onClick={exit}>Cancel</button>
</>
}
</div>
</>
);
}