diff --git a/src/components/App.tsx b/src/components/App.tsx index 2786b2e..d2dc835 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -25,26 +25,40 @@ const App: React.FC = () => { return (
-
- -

Web3 Browser

-
+ +
+ +

Web3 Browser

+
+
- {ethStatus?.syncState === "syncing" || + {true || ethStatus?.syncState === "syncing" || handshakeStatus?.syncState === "syncing" ? (
{ethStatus?.syncState === "syncing" ? ( - - {ethStatus.sync.toFixed(0)}% Syncing Ethereum Network + + + {ethStatus.sync.toFixed(1)}% Syncing Ethereum Network + + ) : ethStatus?.syncState === "done" ? ( + + + {" "} Ethereum Synced ) : null} {handshakeStatus?.syncState === "syncing" ? ( - - {handshakeStatus.sync.toFixed(1)}% Syncing Handshake Network + + + {handshakeStatus.sync.toFixed(1)}% Syncing Ethereum Network + + ) : handshakeStatus?.syncState === "done" ? ( + + + {" "} Handshake Synced ) : null}
@@ -53,6 +67,46 @@ const App: React.FC = () => { ); }; +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" + + return ( + + + + {textSize ? + {`${percentage}%`} + : null } + + ); +}; + const Root = () => { return ( diff --git a/src/components/Browser.tsx b/src/components/Browser.tsx index 1c5fcf0..f96bfc9 100644 --- a/src/components/Browser.tsx +++ b/src/components/Browser.tsx @@ -29,6 +29,7 @@ import { useAuth, useLumeStatus, } from "@lumeweb/sdk"; +import StartPage from "./StartPage"; let BOOT_FUNCTIONS: (() => Promise)[] = []; @@ -163,22 +164,29 @@ const NavInput = forwardRef( }, ); +function parseUrl(url: string) { + let input = url.trim(); + + // If the input doesn't contain a protocol, assume it's http + if (!input?.match(/^https?:\/\//)) { + input = `http://${input}`; + } + + return new URL(input); +} + export function Navigator() { const { url: contextUrl, setUrl } = useBrowserState(); const { ready } = useLumeStatus(); const inputEl = useRef(); const browse = (inputValue: string) => { - let input = inputValue.trim(); - - // If the input doesn't contain a protocol, assume it's http - if (!input?.match(/^https?:\/\//)) { - input = `http://${input}`; - } - try { + if(inputValue === "") { + setUrl("about:blank") + } // Try to parse it as a URL - const url = new URL(input); + const url = parseUrl(inputValue); setUrl(url.toString() || "about:blank"); } catch (e) { @@ -248,7 +256,7 @@ export function Browser() { ); }, []); - const handleIframeLoad = () => { + const handleIframeLoad = (event: React.SyntheticEvent) => { try { const newUrl = iframeRef?.current?.contentWindow?.location.href as string; const urlObj = new URL(newUrl); @@ -258,7 +266,11 @@ export function Browser() { if (url !== realUrl) { setUrl(realUrl); } - setIsLoadingPage(false); + const readyState = event.currentTarget.contentDocument?.readyState; + console.log("[debug]",{readyState}); + if(readyState === 'interactive') { + setIsLoadingPage(false); + } } catch (e) { // This will catch errors related to cross-origin requests, in which case we can't access the iframe's contentWindow.location console.warn( @@ -273,6 +285,7 @@ export function Browser() { if (iframe) { const observer = new MutationObserver((mutationsList, observer) => { for (let mutation of mutationsList) { + console.log("[debug] Mutated ", {mutation}) if ( mutation.type === "attributes" && mutation.attributeName === "src" @@ -287,6 +300,8 @@ export function Browser() { } }, []); + const shouldRenderStartPage = !url || url === "about:blank"; + return ( <> {isLoadingPage ? ( @@ -296,12 +311,21 @@ export function Browser() { ) : null} - + {shouldRenderStartPage ? ( + { + const _url = parseUrl(url); + setUrl(_url.toString() || "about:blank"); + }} + /> + ) : null} + + ); } diff --git a/src/components/Lume.tsx b/src/components/Lume.tsx index d08629a..f4fc2f1 100644 --- a/src/components/Lume.tsx +++ b/src/components/Lume.tsx @@ -6,7 +6,7 @@ import { useLumeStatus, } from "@lumeweb/sdk"; -const Lume: React.FC = () => { +const Lume: React.FC = () => { const { isLoggedIn } = useAuth(); const { ready, inited } = useLumeStatus(); @@ -14,21 +14,19 @@ const Lume: React.FC = () => { <> {!isLoggedIn && ( - - { + - } )} {isLoggedIn && } ); -} +}; -export default Lume; \ No newline at end of file +export default Lume; diff --git a/src/components/StartPage.tsx b/src/components/StartPage.tsx new file mode 100644 index 0000000..8556712 --- /dev/null +++ b/src/components/StartPage.tsx @@ -0,0 +1,135 @@ +import { useAuth, useLumeStatus } from "@lumeweb/sdk"; +import React from "react"; + +type Props = { + setUrl: (url: string) => void; +}; + +const AVAILABLE_PAGES = [ + "blockranger.eth", + "esteroids.eth", + "ens.eth", + "sogola.eth", + "vitalik.eth", +]; + +const StartPage = ({ setUrl }: Props) => { + const { ready, inited } = useLumeStatus(); + const { isLoggedIn } = useAuth(); + return ( +
+

+ Welcome to the Lume Browser +

+

+ This browser will let you trustessly access websites with domain names + from the Ethereum Name Service (ENS) and Handshake protocol, providing a + secure and decentralized browsing experience. +

+ {/* TODO: Add the lume loading indicators for the networks. */} + {/* */} + {inited && ready ? ( +
+
+

+ Currently Accessible Websites: +

+

+ To come back to the roots of the web, we have to change a lot of + behavior on how browsers resolve assets and make them safe by + checking their hashes in a trustlessly way. The sites listed here + are the ones we've successfully integrated with our technology. + We're working on complex tasks to ensure that file serving is + trustless and decentralized, which involves reimplementing many + functionalities that current DNSs and CDNs already provide. +

+
    + {AVAILABLE_PAGES.map((url, index) => ( + + ))} +
+
+ ) : null} + {inited && !ready && isLoggedIn ? ( +
+

Be patient

+

We are starting the engines.

+
+ ): null} + {!isLoggedIn ? ( +
+

Attention

+

Please click login to start using the browser.

+
+ ) : null} +
+ ); +}; + +export default StartPage; + +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; + + return ( + + + + + {`${percentage}%`} + + + ); +}; diff --git a/tailwind.config.js b/tailwind.config.js index b5bfccc..be11b37 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -1,6 +1,7 @@ /** @type {import('tailwindcss').Config} */ module.exports = { darkMode: ["class"], + safelist: ["fill-green-500", "stroke-green-500", "fill-orange-400", "stroke-orange-400"], content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], theme: { container: {