Skip to content

Commit

Permalink
start onlyframes
Browse files Browse the repository at this point in the history
  • Loading branch information
backmeupplz committed Feb 28, 2024
1 parent 2992d31 commit a09e37e
Show file tree
Hide file tree
Showing 18 changed files with 4,437 additions and 239 deletions.
2 changes: 2 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
VITE_BACKEND_URL=http://localhost:1337
VITE_WALLET_CONNECT_PROJECT_ID=123
11 changes: 10 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,14 @@
"editor.quickSuggestions": {
"strings": true
},
"cSpell.words": ["Onlyframes"]
"cSpell.words": [
"daisyui",
"Onlyframes",
"rainbowkit",
"synthwave",
"tailwindcss",
"tanstack",
"viem",
"wagmi"
]
}
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@
"preview": "yarn build && yarn vite preview"
},
"dependencies": {
"@rainbow-me/rainbowkit": "^2.0.1",
"@tanstack/react-query": "^5.24.1",
"envalid": "^8.0.0",
"jotai": "^2.6.5",
"preact": "^10.19.6"
"preact": "^10.19.6",
"viem": "2.x",
"wagmi": "^2.5.7"
},
"devDependencies": {
"@preact/preset-vite": "^2.8.1",
Expand Down
33 changes: 27 additions & 6 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,34 @@
import { Suspense } from 'preact/compat'
import UserCount from 'components/UserCount'
import { ConnectButton } from '@rainbow-me/rainbowkit'
import FileUpload from 'components/FileUpload'
import SignMessage from 'components/SignMessage'

export default function () {
return (
<div className="container mx-auto max-w-prose p-10 prose">
<h1>Onlyframes</h1>
<Suspense fallback={<p>Loading...</p>}>
<UserCount />
</Suspense>
<h1>OnlyFrames</h1>
<p>
G'day, user! Welcome to OnlyFrames where you can upload images as
token-gated frames.
</p>
<p>
Connect a wallet that is connected to a Farcaster account, select an
image, specify the token chain, address, and (optionally) token ID (for
ERC1155), hit the "Upload!" button and get a shareable URL that you can
paste anywhere on Warpcast! Only the users holding the token you've
specified will be able to see it.
</p>
<div className="my-2">
<ConnectButton />
</div>
<SignMessage />
<FileUpload />
<p>
Made with love by{' '}
<a href="https://warpcast.com/borodutch" target="_blank">
@borodutch
</a>
, consider a follow!
</p>
</div>
)
}
7 changes: 7 additions & 0 deletions src/atoms/signature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { atom } from 'jotai'

export default atom({
signature: '',
message: '',
address: '',
})
4 changes: 0 additions & 4 deletions src/atoms/userCount.ts

This file was deleted.

109 changes: 109 additions & 0 deletions src/components/FileUpload.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { useAccount } from 'wagmi'
import { useAtomValue } from 'jotai'
import { useState } from 'preact/compat'
import env from 'helpers/env'
import signatureAtom from 'atoms/signature'

export default function FileUpload() {
const { isConnected } = useAccount()
if (!isConnected) {
return null
}

const { signature, message, address } = useAtomValue(signatureAtom)
if (!signature || !message || !address) {
return null
}

const [file, setFile] = useState<File | undefined>()
const [loading, setLoading] = useState(false)
const [success, setSuccess] = useState(false)
const [errorMessage, setErrorMessage] = useState<string>('')

async function uploadFile() {
if (!file) {
return
}
setLoading(true)
setSuccess(false)
setErrorMessage('')

try {
const formData = new FormData()
formData.append('file', file)
const response = await fetch(`${env.VITE_BACKEND_URL}/upload`, {
method: 'POST',
body: formData,
})

if (response.ok) {
setSuccess(true)
} else {
setErrorMessage(
`${response.statusText}: ${(await response.json()).message}`
)
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : `${error}`
setErrorMessage(errorMessage)
console.error(errorMessage)
} finally {
setLoading(false)
}
}

return (
<div className="flex flex-col gap-2">
<input
type="file"
className="file-input file-input-bordered file-input-primary"
onChange={(event) => {
setFile(event.currentTarget?.files?.[0])
}}
/>
<button
class="btn btn-active btn-primary"
onClick={uploadFile}
disabled={loading}
>
{loading && '🤔 '}Upload!
</button>
{success && (
<div role="alert" class="alert alert-success">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>Success!</span>
</div>
)}
{errorMessage && (
<div role="alert" class="alert alert-error">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>Error! {errorMessage}</span>
</div>
)}
</div>
)
}
81 changes: 81 additions & 0 deletions src/components/SignMessage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { signMessage } from '@wagmi/core'
import { useAccount } from 'wagmi'
import { useAtom } from 'jotai'
import { useState } from 'preact/hooks'
import signatureAtom from 'atoms/signature'
import wagmiConfig from 'helpers/wagmiConfig'

export default function () {
const { address: currentlyConnectedAccount, isConnected } = useAccount()
if (!isConnected) {
return null
}

const [{ signature, message, address }, setSignature] = useAtom(signatureAtom)
if (signature && message && address === currentlyConnectedAccount) {
return (
<p>
Thank you for providing a signature for{' '}
<code className="break-all">{address}</code>!
</p>
)
}

const [loading, setLoading] = useState(false)
const [errorMessage, setErrorMessage] = useState('')

return (
<div className="flex flex-col gap-2">
<button
className="btn btn-secondary"
disabled={loading}
onClick={async () => {
console.log(address)
if (!currentlyConnectedAccount) {
return
}
const message = `Sign this message to prove ownership of ${currentlyConnectedAccount}`
setLoading(true)
setErrorMessage('')
try {
const signature = await signMessage(wagmiConfig, {
message,
})
setSignature({
signature,
message,
address: currentlyConnectedAccount,
})
} catch (error) {
const newErrorMessage =
error instanceof Error ? error.message : `${error}`
setErrorMessage(newErrorMessage)
console.error(newErrorMessage)
} finally {
setLoading(false)
}
}}
>
Sign message
</button>
{errorMessage && (
<div role="alert" class="alert alert-error">
<svg
xmlns="http://www.w3.org/2000/svg"
class="stroke-current shrink-0 h-6 w-6"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span>Error! {errorMessage}</span>
</div>
)}
</div>
)
}
8 changes: 0 additions & 8 deletions src/components/UserCount.tsx

This file was deleted.

20 changes: 20 additions & 0 deletions src/components/Wallet.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import '@rainbow-me/rainbowkit/styles.css'
import { PropsWithChildren } from 'preact/compat'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { RainbowKitProvider, darkTheme } from '@rainbow-me/rainbowkit'
import { WagmiProvider } from 'wagmi'
import wagmiConfig from 'helpers/wagmiConfig'

const queryClient = new QueryClient()

export default function ({ children }: PropsWithChildren) {
return (
<WagmiProvider config={wagmiConfig}>
<QueryClientProvider client={queryClient}>
<RainbowKitProvider coolMode theme={darkTheme()}>
{children}
</RainbowKitProvider>
</QueryClientProvider>
</WagmiProvider>
)
}
6 changes: 6 additions & 0 deletions src/helpers/env.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { cleanEnv, str } from 'envalid'

export default cleanEnv(import.meta.env, {
VITE_BACKEND_URL: str(),
VITE_WALLET_CONNECT_PROJECT_ID: str(),
})
3 changes: 0 additions & 3 deletions src/helpers/formatNumber.ts

This file was deleted.

4 changes: 0 additions & 4 deletions src/helpers/getUserCount.ts

This file was deleted.

7 changes: 7 additions & 0 deletions src/helpers/polyfills.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Buffer } from 'buffer'

window.global = window.global ?? window
window.Buffer = window.Buffer ?? Buffer
window.process = window.process ?? { env: {} } // Minimal process polyfill

export {}
9 changes: 9 additions & 0 deletions src/helpers/wagmiConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getDefaultConfig } from '@rainbow-me/rainbowkit'
import { mainnet } from 'wagmi/chains'
import env from 'helpers/env'

export default getDefaultConfig({
appName: 'OnlyFrames',
projectId: env.VITE_WALLET_CONNECT_PROJECT_ID,
chains: [mainnet],
})
9 changes: 8 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import 'helpers/polyfills'
import 'index.css'
import { render } from 'preact'
import App from 'App'
import Wallet from 'components/Wallet'

render(<App />, document.getElementById('root') as Element)
render(
<Wallet>
<App />
</Wallet>,
document.getElementById('root') as Element
)
3 changes: 3 additions & 0 deletions tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
module.exports = {
content: ['./index.html', './src/**/!(tailwind).{ts,tsx}'],
plugins: [require('@tailwindcss/typography'), require('daisyui')],
daisyui: {
themes: ['synthwave'],
},
}
Loading

0 comments on commit a09e37e

Please sign in to comment.