Skip to content

Commit

Permalink
feat: ceremony address form
Browse files Browse the repository at this point in the history
  • Loading branch information
o-az committed Sep 13, 2024
1 parent d98e9a0 commit 4645d20
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 55 deletions.
1 change: 1 addition & 0 deletions ceremony/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ vite.config.ts.timestamp-*

# Stats directory
stats
_
7 changes: 6 additions & 1 deletion ceremony/ceremony.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
{
packages = {
ceremony = unstablePkgs.buildNpmPackage {
npmDepsHash = "sha256-iL4+qO73/tXPDPI7d6B8UywQN9vhchPzy91WiRLYXUI=";
npmDepsHash = "sha256-CEZJ8lBuOrOf65oInkexsrXOaU+rJeUpQ2SGmlTgYbI=";
src = ./.;
sourceRoot = "ceremony";
npmFlags = [ "--legacy-peer-deps" ];
Expand Down Expand Up @@ -39,6 +39,11 @@
${ensureAtRepositoryRoot}
cd ceremony/
export NODE_OPTIONS="--no-warnings"
export VITE_BUCKET_ID="contributions"
export VITE_SUPABASE_URL="https://otfaamdxmgnkjqsosxye.supabase.co/"
export VITE_SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6Im90ZmFhbWR4bWdua2pxc29zeHllIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MjEzMjA5NDMsImV4cCI6MjAzNjg5Njk0M30.q91NJPFFHKJXnbhbpUYwsB0NmimtD7pGPx6PkbB_A3w"
npm install
npm run dev
'';
Expand Down
58 changes: 49 additions & 9 deletions ceremony/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion ceremony/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
"devDependencies": {
"@sveltejs/adapter-static": "^3.0.4",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.6",
"@sveltejs/vite-plugin-svelte": "^4.0.0-next.7",
"@total-typescript/ts-reset": "^0.6.1",
"autoprefixer": "^10.4.20",
"clsx": "^2.1.1",
"postcss": "^8.4.44",
"svelte": "^5.0.0-next.1",
"svelte-check": "^3.6.0",
Expand All @@ -25,10 +26,12 @@
"vite": "^5.0.3"
},
"dependencies": {
"@scure/base": "^1.1.8",
"@splinetool/runtime": "^1.9.23",
"@supabase/supabase-js": "^2.45.3",
"@tanstack/svelte-query": "^5.54.1",
"neverthrow": "^7.1.0",
"runed": "^0.15.2",
"svelte-sonner": "^0.3.27"
}
}
73 changes: 73 additions & 0 deletions ceremony/src/lib/components/address/AddressForm.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script lang="ts">
import clsx from "clsx"
import { toast } from "svelte-sonner"
import { watch, Debounced } from "runed"
import type { ValidState } from "./index.ts"
import { isValidBech32Address } from "./validator.ts"
import type { HTMLInputAttributes } from "svelte/elements"
interface Props extends HTMLInputAttributes {
class?: string
onValidation: (valid: ValidState) => ValidState
}
let { onValidation, class: className = "", ...props }: Props = $props()
let inputText = $state("")
const debouncedInputText = new Debounced(
() => inputText,
/**
* TODO: change this to 1s and during debounce, show a loading state
*/
0
)
let validState: ValidState = $state("PENDING")
$effect(() => {
if (validState === "INVALID") toast.error(`Address is not valid`)
})
const onAddressSubmit = (event: Event) => {
event.preventDefault()
if (!debouncedInputText.current) return
const addressValidation = isValidBech32Address(debouncedInputText.current)
validState = addressValidation ? "VALID" : "INVALID"
onValidation(validState)
}
</script>

<form class="flex flex-col gap-2 min-w-[355px]">
<input
{...props}
type="text"
autocorrect="off"
autocomplete="off"
spellcheck="false"
autocapitalize="none"
bind:value={inputText}
placeholder="union1qp0wtsfltjk9rnvyu3fkdv0s0skp4y5y3py96f"
class={clsx([
className,
'text-md font-supermolot h-9 px-2 outline-none border-2',
validState === 'VALID'
? 'border-2 border-green-500'
: validState === 'INVALID'
? 'border-2 border-red-500'
: 'border-transparent',
])}
/>
<button
type="button"
onclick={onAddressSubmit}
disabled={inputText.length === 0}
class={clsx([
'hover:font-bold hover:bg-[#5FDFFC]',
'uppercase text-black w-full bg-[#A0ECFD] text-md font-supermolot h-9 px-2 font-semibold',
])}
>
submit
</button>
</form>

<style lang="postcss"></style>
5 changes: 5 additions & 0 deletions ceremony/src/lib/components/address/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import AddressForm from "./AddressForm.svelte"

export type ValidState = "PENDING" | "VALID" | "INVALID"

export { AddressForm }
15 changes: 15 additions & 0 deletions ceremony/src/lib/components/address/validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { bech32 } from "@scure/base"

type Bech32Address<T extends string = string> = `${T}1${string}`
export function isValidBech32Address(address: unknown): address is Bech32Address {
if (typeof address !== "string") return false

try {
const { prefix: _, words } = bech32.decode(address as Bech32Address)
const size = words.length
if ([20, 32].indexOf(size) === -1) return false
return true
} catch {
return false
}
}
85 changes: 41 additions & 44 deletions ceremony/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,66 +1,63 @@
<script lang="ts">
import H1 from "$lib/components/typography/H1.svelte"
import { onMount } from "svelte"
//
// let imageVisible = false
// onMount(() => {
// imageVisible = true
// })
import { AddressForm, type ValidState } from "$lib/components/address/index.ts"
let addressValidState: ValidState = $state("PENDING")
$effect(() => {
console.info(`ADDRESS VALIDITY STATE: ${addressValidState}`)
})
</script>

<section class="relative w-full h-full flex items-center justify-center overflow-hidden">
<AddressForm class="" onValidation={result => (addressValidState = result)} />
<div class="max-w-7xl sm:px-6 lg:px-8">
<div class="max-w-7xl sm:px-6 lg:px-8 fade-in-text">
<H1 class="text-center">
Welcome to<br>Union Ceremony
Welcome to<br />Union Ceremony
</H1>
</div>
</div>
<!-- <img-->
<!-- src="/images/whale.png"-->
<!-- alt=""-->
<!-- class="absolute -z-10 w-full h-full object-cover deep-sea-rise"-->
<!-- class:visible={imageVisible}/>-->
</section>

<style>
.deep-sea-rise {
opacity: 0;
transform: scale(0.5) translateY(140px);
filter: brightness(0.1);
animation: riseFromDepth 2.5s ease-out forwards;
}
.deep-sea-rise {
opacity: 0;
transform: scale(0.5) translateY(140px);
filter: brightness(0.1);
animation: riseFromDepth 2.5s ease-out forwards;
}
.deep-sea-rise.visible {
opacity: 1;
}
.deep-sea-rise.visible {
opacity: 1;
}
@keyframes riseFromDepth {
0% {
opacity: 0;
transform: scale(0.5) translateY(140px);
filter: brightness(0.1);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
filter: brightness(1);
}
@keyframes riseFromDepth {
0% {
opacity: 0;
transform: scale(0.5) translateY(140px);
filter: brightness(0.1);
}
.fade-in-text {
opacity: 0;
animation: fadeInText 1.5s ease-out forwards;
animation-delay: 2s;
100% {
opacity: 1;
transform: scale(1) translateY(0);
filter: brightness(1);
}
}
.fade-in-text {
opacity: 0;
animation: fadeInText 1.5s ease-out forwards;
animation-delay: 2s;
}
@keyframes fadeInText {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
@keyframes fadeInText {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>

0 comments on commit 4645d20

Please sign in to comment.