Compare commits

...

3 Commits

Author SHA1 Message Date
Juan Di Toro 2a13d11e9d Merge branch 'master' of git.lumeweb.com:LumeWeb/web3browser.io into ditorodev 2023-11-09 13:41:15 +01:00
Juan Di Toro 2b5fbc8b36 feat: small improvements 2023-11-09 13:40:33 +01:00
Derrick Hammer 9836b5de26
fix: floors should be floor 2023-11-04 18:45:50 -04:00
4 changed files with 91 additions and 49 deletions

View File

@ -36,29 +36,36 @@ const App: React.FC = () => {
</div>
</div>
<Navigator />
{true || ethStatus?.syncState === "syncing" ||
{ethStatus?.syncState === "syncing" ||
handshakeStatus?.syncState === "syncing" ? (
<div className="py-4 -mb-4 flex flex-row gap-x-3">
{ethStatus?.syncState === "syncing" ? (
<span className="flex items-center gap-x-2 rounded-full bg-neutral-800 text-white p-1 px-4 bg">
<CircleProgressBar radius={5} strokeWidth={3} percentage={Math.floors(ethStatus.sync)} />
<CircleProgressBar radius={5} strokeWidth={3} percentage={Math.floor(ethStatus.sync)} />
<span className="font-bold font-mono text-orange-400 mr-2">{ethStatus.sync.toFixed(1)}%</span> Syncing Ethereum Network
</span>
) : ethStatus?.syncState === "done" ? (
<span className="flex items-center gap-x-2 rounded-full bg-neutral-800 text-white p-1 px-4 bg">
<CircleProgressBar radius={5} strokeWidth={3} percentage={100} />
{" "} Ethereum Synced
<CircleProgressBar radius={5} strokeWidth={3} percentage={100} />{" "}
Ethereum Synced
</span>
) : null}
{handshakeStatus?.syncState === "syncing" ? (
<span className="flex items-center gap-x-2 rounded-full bg-neutral-800 text-white p-1 px-4 bg">
<CircleProgressBar radius={5} strokeWidth={3} percentage={Math.floor(handshakeStatus.sync)} />
<span className="font-bold font-mono text-orange-400 mr-2">{handshakeStatus.sync.toFixed(1)}%</span> Syncing Handshake Network
<CircleProgressBar
radius={5}
strokeWidth={3}
percentage={Math.floor(handshakeStatus.sync)}
/>
<span className="font-bold font-mono text-orange-400 mr-2">
{handshakeStatus.sync.toFixed(1)}%
</span>{" "}
Syncing Handshake Network
</span>
) : handshakeStatus?.syncState === "done" ? (
<span className="flex items-center gap-x-2 rounded-full bg-neutral-800 text-white p-1 px-4 bg">
<CircleProgressBar radius={5} strokeWidth={3} percentage={100} />
{" "} Handshake Synced
<CircleProgressBar radius={5} strokeWidth={3} percentage={100} />{" "}
Handshake Synced
</span>
) : null}
</div>
@ -67,11 +74,21 @@ const App: React.FC = () => {
);
};
const CircleProgressBar = ({ radius, strokeWidth, textSize, percentage } : {radius: number, strokeWidth: number, textSize?: number, percentage: number}) => {
const CircleProgressBar = ({
radius,
strokeWidth,
textSize,
percentage,
}: {
radius: number;
strokeWidth: number;
textSize?: number;
percentage: number;
}) => {
const circumference = 2 * Math.PI * radius;
const offset = circumference - (percentage / 100) * circumference;
const color = Math.ceil(percentage) >= 100 ? "green-500" : "orange-400"
const color = Math.ceil(percentage) >= 100 ? "green-500" : "orange-400";
return (
<svg width={radius * 2 + strokeWidth} height={radius * 2 + strokeWidth}>
<circle
@ -93,16 +110,18 @@ const CircleProgressBar = ({ radius, strokeWidth, textSize, percentage } : {radi
strokeDashoffset={offset}
strokeLinecap="round"
/>
{textSize ? <text
x="50%"
className={`fill-${color}`}
y="50%"
textAnchor="middle"
dy=".3em"
fontSize={textSize}
>
{`${percentage}%`}
</text> : null }
{textSize ? (
<text
x="50%"
className={`fill-${color}`}
y="50%"
textAnchor="middle"
dy=".3em"
fontSize={textSize}
>
{`${percentage}%`}
</text>
) : null}
</svg>
);
};

View File

@ -38,6 +38,8 @@ interface BrowserContextType {
setUrl: React.Dispatch<React.SetStateAction<string>>;
isLoadingPage: boolean;
setIsLoadingPage: React.Dispatch<React.SetStateAction<boolean>>;
authStatus: LumeAuthStatus;
setAuthStatus: React.Dispatch<React.SetStateAction<LumeAuthStatus>>;
}
const BrowserStateContext = createContext<BrowserContextType | undefined>(
@ -51,10 +53,18 @@ export function BrowserStateProvider({
}) {
const [url, setUrl] = useState("");
const [isLoadingPage, setIsLoadingPage] = useState<boolean>(false);
const [authStatus, setAuthStatus] = useState<LumeAuthStatus>("idle");
return (
<BrowserStateContext.Provider
value={{ url, setUrl, isLoadingPage, setIsLoadingPage }}
value={{
url,
setUrl,
isLoadingPage,
setIsLoadingPage,
authStatus,
setAuthStatus,
}}
>
{children}
</BrowserStateContext.Provider>
@ -71,15 +81,18 @@ export function useBrowserState() {
return context;
}
type LumeAuthStatus = "idle" | "done" | "syncing";
async function boot({
onInit,
onAuth,
onBoot,
}: {
onInit: (inited: boolean) => Promise<void> | void;
onAuth: (authed: boolean) => Promise<void> | void;
onAuth: (authed: LumeAuthStatus) => Promise<void> | void;
onBoot: (booted: boolean) => Promise<void> | void;
}) {
await onAuth("idle");
let err = false;
const reg = await navigator.serviceWorker.register("/sw.js");
await reg.update();
@ -91,7 +104,8 @@ async function boot({
});
await onInit(true);
await kernelLoaded()
.then((result) => {
.then(async (result) => {
await onAuth("syncing");
if ("indexeddb_error" === (result as string)) {
alert(
"Error: Please ensure 3rd party cookies are enabled, and any security like brave shield is off, then reload the app",
@ -105,7 +119,7 @@ async function boot({
if (err) {
return;
}
await onAuth(true);
await onAuth("done");
BOOT_FUNCTIONS.push(
async () =>
@ -140,10 +154,11 @@ async function boot({
for (const resolver of resolvers) {
BOOT_FUNCTIONS.push(async () => dnsClient.registerResolver(resolver));
}
BOOT_FUNCTIONS.push(async () => onBoot(true));
await bootup();
await onBoot(true);
await Promise.all([
ethClient.ready(),
handshakeClient.ready(),
@ -152,7 +167,7 @@ async function boot({
}
async function bootup() {
for (const entry of Object.entries(BOOT_FUNCTIONS)) {
for await (const entry of Object.entries(BOOT_FUNCTIONS)) {
console.log(entry[1].toString());
await entry[1]();
}
@ -182,8 +197,8 @@ export function Navigator() {
const browse = (inputValue: string) => {
try {
if(inputValue === "") {
setUrl("about:blank")
if (inputValue === "") {
setUrl("about:blank");
}
// Try to parse it as a URL
const url = parseUrl(inputValue);
@ -235,7 +250,8 @@ export function Navigator() {
}
export function Browser() {
const { url, setUrl, isLoadingPage, setIsLoadingPage } = useBrowserState();
const { url, setUrl, isLoadingPage, setIsLoadingPage, setAuthStatus } =
useBrowserState();
const status = useLumeStatus();
const auth = useAuth();
const iframeRef = useRef<HTMLIFrameElement>(null);
@ -243,7 +259,11 @@ export function Browser() {
useEffect(() => {
boot({
onAuth(authed) {
auth.setIsLoggedIn(authed);
console.log({authed})
setAuthStatus(authed);
if (authed === "done") {
auth.setIsLoggedIn(true);
}
},
onBoot(booted) {
status.setReady(booted);
@ -256,7 +276,9 @@ export function Browser() {
);
}, []);
const handleIframeLoad = (event: React.SyntheticEvent<HTMLIFrameElement, Event>) => {
const handleIframeLoad = (
event: React.SyntheticEvent<HTMLIFrameElement, Event>,
) => {
try {
const newUrl = iframeRef?.current?.contentWindow?.location.href as string;
const urlObj = new URL(newUrl);
@ -267,8 +289,8 @@ export function Browser() {
setUrl(realUrl);
}
const readyState = event.currentTarget.contentDocument?.readyState;
console.log("[debug]",{readyState});
if(readyState === 'interactive') {
console.log("[debug]", { readyState });
if (readyState === "interactive") {
setIsLoadingPage(false);
}
} catch (e) {
@ -285,7 +307,7 @@ export function Browser() {
if (iframe) {
const observer = new MutationObserver((mutationsList, observer) => {
for (let mutation of mutationsList) {
console.log("[debug] Mutated ", {mutation})
console.log("[debug] Mutated ", { mutation });
if (
mutation.type === "attributes" &&
mutation.attributeName === "src"
@ -318,14 +340,14 @@ export function Browser() {
setUrl(_url.toString() || "about:blank");
}}
/>
) : null}
) : null}
<iframe
ref={iframeRef}
onLoad={handleIframeLoad}
src={url ? `/browse/${url}` : "about:blank"}
className={`${shouldRenderStartPage ? "hidden": ""} w-full h-full`}
></iframe>
<iframe
ref={iframeRef}
onLoad={handleIframeLoad}
src={url ? `/browse/${url}` : "about:blank"}
className={`${shouldRenderStartPage ? "hidden" : ""} w-full h-full`}
></iframe>
</>
);
}

View File

@ -4,10 +4,13 @@ import {
LumeIdentityTrigger,
useAuth,
useLumeStatus,
useNetworks,
} from "@lumeweb/sdk";
import { useBrowserState } from "./Browser";
const Lume: React.FC = () => {
const { isLoggedIn } = useAuth();
const { authStatus } = useBrowserState();
const { ready, inited } = useLumeStatus();
return (
@ -17,14 +20,14 @@ const Lume: React.FC = () => {
<LumeIdentityTrigger asChild>
<button
className="ml-2 w-full rounded-full bg-[hsl(113,49%,55%)] text-black disabled:pointer-events-none disabled:opacity-50"
disabled={!inited}
disabled={!inited || authStatus === 'syncing'}
>
Login
</button>
</LumeIdentityTrigger>
</LumeIdentity>
)}
{isLoggedIn && <LumeDashboard disabled={!ready} />}
{isLoggedIn && <LumeDashboard disabled={!inited} />}
</>
);
};

View File

@ -26,8 +26,6 @@ const StartPage = ({ setUrl }: Props) => {
from the Ethereum Name Service (ENS) and Handshake protocol, providing a
secure and decentralized browsing experience.
</p>
{/* TODO: Add the lume loading indicators for the networks. */}
{/* <CircleProgressBar radius={20} strokeWidth={4} textSize={12} percentage={75} /> */}
{inited && ready ? (
<div>
<hr className="my-3 border-neutral-700" />
@ -63,11 +61,11 @@ const StartPage = ({ setUrl }: Props) => {
) : null}
{inited && !ready && isLoggedIn ? (
<div
className="bg-yellow-800/40 rounded-md border border-yellow-500 text-yellow-500 p-4"
className="bg-green-800/40 rounded-md border border-green-500 text-green-500 p-4"
role="alert"
>
<p className="font-bold">Be patient</p>
<p>We are starting the engines.</p>
<p className="font-bold">You are logged in.</p>
<p>We are now starting to sync the networks.</p>
</div>
) : null}
{!isLoggedIn ? (