Skip to content

Commit

Permalink
Update demo walrus site
Browse files Browse the repository at this point in the history
  • Loading branch information
mario4tier committed Sep 2, 2024
1 parent d9e3c50 commit e907393
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 90 deletions.
3 changes: 2 additions & 1 deletion dapps/suiftly.walrus.site/packages/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-hot-toast": "^2.4.1",
"react-use": "^17.5.1"
"react-use": "^17.5.1",
"react-router-dom": "^6.22.0"
},
"devDependencies": {
"@types/node": "^20.14.15",
Expand Down
168 changes: 82 additions & 86 deletions dapps/suiftly.walrus.site/packages/frontend/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,118 +1,114 @@
import { FC, useEffect, useRef } from 'react'
import { FC, useState } from 'react'
import Layout from '~~/components/layout/Layout'
{
/*import GreetingForm from '~~/components/GreetingForm'*/
/*import NetworkSupportChecker from './NetworkSupportChecker'*/
}
import Layout from '~~/components/layout/Layout'
import NetworkSupportChecker from './NetworkSupportChecker'
import { fetchBlob } from '@suiftly/core'

// A fetchBlob() async function that take a single "blobID" string argument.
// It should return a promise that resolves to the blob data (a standard JS
// Blob interface).
//
// The blob data is first retreived with a CDN URL like this:
// https://cdn.suiftly.io/blobs/{blobID}
//
// The function should extract the Content-Type header and use it
// to build the JS Blob object.
//
// The function should throw an error if the response status is not 200.
//
// Example usage:
// const blob = await fetchBlob('some-blob-id')
import DemoImage from './DemoImage'
import { Link, Text, Flex } from '@radix-ui/themes'
import LabeledLinkSuiftly from './LabeledLinkSuiftly'
import BlobIdInput from './BlobIdInput'
import LabeledLink from './LabeledLink'

const App: FC = () => {
// TODO Just proof-of-concept... need to design this way better!!!!
const fetchInitiated1 = useRef(false)
const fetchInitiated2 = useRef(false)

useEffect(() => {
const blobID = 'fK7v0bft1JqVbxQaM_KJAYkejbY9FgU9doqZwg7smw8'
const imageContainer1 = document.getElementById('image-container-walrus')
const imageContainer2 = document.getElementById('image-container-suiftly')
const defaultBlobId = 'fK7v0bft1JqVbxQaM_KJAYkejbY9FgU9doqZwg7smw8'
const [blobId, setBlobId] = useState(defaultBlobId)

if (imageContainer1 && !fetchInitiated1.current) {
fetchInitiated1.current = true
fetchBlob(blobID, { allowSuiftly: false })
const handleRunCode = () => {
const imageContainer = document.getElementById('image-container')
if (imageContainer) {
fetchBlob(blobId)
.then((blob) => {
const url = URL.createObjectURL(blob)
const img = document.createElement('img')
img.src = url
img.alt = 'Fetched Blob'

// Clear the loading message and append the image
if (imageContainer1) {
imageContainer1.innerHTML = ''
imageContainer1.appendChild(img)
}
imageContainer.innerHTML = ''
imageContainer.appendChild(img)
})
.catch((error) => {
console.error('Error fetching walrus blob:', error)
if (imageContainer1) {
imageContainer1.innerHTML = '<p>Error loading walrus image</p>'
console.error('Error fetching walrus blob:', blobId, error)
if (imageContainer) {
imageContainer.innerHTML = '<p>Error loading walrus image</p>'
}
})
}
}

if (imageContainer2 && !fetchInitiated2.current) {
fetchInitiated2.current = true
fetchBlob(blobID, { allowSuiftly: true })
const codeSnippet = `
const imageContainer = document.getElementById('image-container')
if (imageContainer) {
const blobId = '${blobId}'
fetchBlob(blobId)
.then((blob) => {
const url = URL.createObjectURL(blob)
const img = document.createElement('img')
img.src = url
img.src = URL.createObjectURL(blob)
img.alt = 'Fetched Blob'

// Clear the loading message and append the image
if (imageContainer2) {
imageContainer2.innerHTML = ''
imageContainer2.appendChild(img)
}
imageContainer.appendChild(img)
})
.catch((error) => {
console.error('Error fetching suiftly blob:', error)
if (imageContainer2) {
imageContainer2.innerHTML = '<p>Error loading suiftly image</p>'
}
console.error('Error fetching:', blobId, error)
})
}

// Cleanup URL object when component unmounts
return () => {
if (imageContainer1) {
const img = imageContainer1.querySelector('img')
if (img) {
URL.revokeObjectURL(img.src)
}
}
if (imageContainer2) {
const img = imageContainer2.querySelector('img')
if (img) {
URL.revokeObjectURL(img.src)
}
}
}
})
`

return (
<Layout>
<NetworkSupportChecker />
<div className="justify-content flex flex-grow flex-col items-center justify-center rounded-md p-3">
{/*<GreetingForm />*/}

<div
id="image-container-suiftly"
style={{ width: '128px', height: '128px' }}
>
<p>Loading image...</p>
</div>

<div
id="image-container-walrus"
style={{ width: '128px', height: '128px' }}
>
<p>Loading image...</p>
{/*<NetworkSupportChecker />*/}
<div className="justify-content flex flex-grow flex-col rounded-md p-3">
<div className="align-center flex flex-row items-center justify-center">
<h1 className="text-3xl font-bold">
<Text>Suiftly Demo</Text>
</h1>
</div>
<br />
<Text>Optionally customize this demo with any image blob ID:</Text>
<BlobIdInput
blobId={blobId}
defaultBlobId={defaultBlobId}
setBlobId={setBlobId}
/>
<br />
<br />
<h2 className="text-xl font-semibold">
<Text>Direct Links (Trust your CDN)</Text>
</h2>
<LabeledLinkSuiftly label="blob" blobId={blobId} />
<LabeledLinkSuiftly label="metrics" blobId={blobId} />
<LabeledLinkSuiftly label="view" blobId={blobId} />
<br />
<h2 className="text-xl font-semibold">
<Text>NPM Package (Trust your CDN... but verify)</Text>
</h2>
<Text>
Install
<Link href="https://www.npmjs.com/package/@suiftly/core">
@suiftly/core
</Link>{' '}
to fetch blobs with Suiftly to Walrus failover and blob integrity
checks.
</Text>
<DemoImage code={codeSnippet} onRunCode={handleRunCode} />
<Text style={{ fontSize: 20 }}>
<br />
Coming soon: Simpler react components like{' '}
<b>&lt;ImageBlob blobId="..."&gt;</b>
</Text>
<br />
<LabeledLink label="More info" url="https://suiftly.io" />
<LabeledLink
label="NPM Package"
url="https://www.npmjs.com/package/@suiftly/core"
/>
<LabeledLink
label="GitHub"
url="https://github.com/chainmovers/suiftly"
/>
<LabeledLink
label="Discord"
url="https://discord.com/invite/Erb6SwsVbH"
/>
</div>
</Layout>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import React from 'react'
import { TextField, Button, Flex } from '@radix-ui/themes'

interface BlobIdInputProps {
blobId: string
defaultBlobId: string
setBlobId: (blobId: string) => void
}

const BlobIdInput: React.FC<BlobIdInputProps> = ({
blobId,
defaultBlobId,
setBlobId,
}) => {
const handleReset = () => {
setBlobId(defaultBlobId)
}

return (
<Flex direction="row" gap="2" width="400" align="center">
{/*<label htmlFor="blobIdInput">
<Text>Blob ID:</Text>
</label>*/}
<TextField.Root
size="2"
color="green"
radius="large"
value={blobId}
variant="soft"
onChange={(e) => setBlobId(e.target.value)}
placeholder={defaultBlobId}
style={{ width: '400px' }} // Set the width here
/>
{blobId !== defaultBlobId && (
<Button onClick={handleReset}>Reset to default</Button>
)}
</Flex>
)
}

export default BlobIdInput
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React, { useState } from 'react'
import { Button, Flex, Text } from '@radix-ui/themes'

interface DemoImageProps {
code: string
onRunCode: () => void
}

const DemoImage: React.FC<DemoImageProps> = ({ code, onRunCode }) => {
const [imageDisplayed, setImageDisplayed] = useState(false)

const handleRunCode = () => {
setImageDisplayed(true)
onRunCode()
}

const handleClearImage = () => {
const imageContainer = document.getElementById('image-container')
if (imageContainer) {
const existing_img = imageContainer.querySelector('img')
if (existing_img) {
imageContainer.removeChild(existing_img)
}
}
setImageDisplayed(false)
}

return (
<Flex
className="demo-image-container"
direction="row"
gap="2"
align="center"
>
<Flex className="code-section" direction="column" gap="1" p="3">
<pre
className="code-block"
style={{
backgroundColor: '#f3f4f6',
padding: '3px',
borderRadius: '10px',
}}
>
<code>{code}</code>
</pre>
</Flex>
<Flex direction="column" gap="2" align="center">
<Flex
id="image-container"
className="image-container"
style={{
width: '128px',
height: '128px',
border: '1px solid #ccc',
flex: 'none',
}}
align="center"
justify="center"
>
<Text>image-container</Text>
</Flex>

<Flex>
{imageDisplayed ? (
<Button
className="clear-image-button"
variant="solid"
color="red"
onClick={handleClearImage}
>
Clear Image
</Button>
) : (
<Button
className="run-code-button"
variant="solid"
color="blue"
onClick={handleRunCode}
>
Run Code
</Button>
)}
</Flex>
</Flex>
</Flex>
)
}

export default DemoImage
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react'
import { Flex, Text, Link } from '@radix-ui/themes'

interface LabeledLinkProps {
label: string
url: string
minWidthLabel?: string
}

const LabeledLink: React.FC<LabeledLinkProps> = ({
label,
url,
minWidthLabel = '110px',
}) => {
return (
<Flex direction="row" align="center" gap="1">
<Text style={{ minWidth: minWidthLabel }}>{label} : </Text>
<Link href={url} underline="hover">
{url}
</Link>
</Flex>
)
}

export default LabeledLink
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react'
import { Flex, Text, Link } from '@radix-ui/themes'

interface LabeledLinkProps {
label: string
blobId: string
}

const LabeledLinkSuiftly: React.FC<LabeledLinkProps> = ({ label, blobId }) => {
const url = `https://cdn.suiftly.io/${label}/${blobId}`
return (
<Flex direction="row" align="center" gap="1">
<Text>{label} : </Text>
<Link href={url} underline="hover">
https://cdn.suiftly.io/<b>{label}</b>/{blobId}
</Link>
</Flex>
)
}

export default LabeledLinkSuiftly
Loading

0 comments on commit e907393

Please sign in to comment.