-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
21 changed files
with
542 additions
and
181 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
app/src/lib/components/TransferFrom/components/AssetDialog.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
<script lang="ts"> | ||
import type {IntentStore} from "$lib/components/TransferFrom/transfer/intents.ts"; | ||
import type {Readable} from "svelte/store"; | ||
import type {ContextStore} from "$lib/components/TransferFrom/transfer/context.ts"; | ||
import {Button} from "$lib/components/ui/button"; | ||
interface Props { | ||
intents: IntentStore | ||
context: Readable<ContextStore> | ||
onSelectAsset: () => void | ||
} | ||
export let intents: Props["intents"] | ||
export let context: Props["context"] | ||
export let onSelectAsset: Props["onSelectAsset"] | ||
</script> | ||
|
||
<Button | ||
type="button" | ||
size="sm" | ||
variant="outline" | ||
class="border-2 border-white min-w-[150px]" | ||
on:click={onSelectAsset} | ||
> | ||
{$context?.assetInfo ?? "Select asset"} | ||
</Button> |
83 changes: 83 additions & 0 deletions
83
app/src/lib/components/TransferFrom/components/ChainDialog.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<script lang="ts"> | ||
import type {Readable} from "svelte/store"; | ||
import type {ContextStore} from "$lib/components/TransferFrom/transfer/context.ts"; | ||
interface Props { | ||
context: Readable<ContextStore> | ||
kind: "source" | "destination" | ||
dialogOpen: boolean | ||
onChainSelect: (type: 'source' | 'destination', chain: string) => void | ||
onClose: () => void | ||
} | ||
export let context: Props["context"] | ||
export let kind: Props["kind"] | ||
export let dialogOpen: Props["dialogOpen"] | ||
export let onChainSelect: Props["onChainSelect"] | ||
export let onClose: Props["onClose"] | ||
</script> | ||
|
||
{#if dialogOpen && $context?.chains} | ||
<dialog | ||
open | ||
aria-label={`Select ${kind} chain`} | ||
class="absolute z-50 inset-0 overflow-y-scroll p-0 bg-transparent m-0 w-full h-full animate-fade-in backdrop-blur-md" | ||
> | ||
<button | ||
type="button" | ||
class="fixed inset-0 w-full h-full bg-gradient-to-t from-black to-black/10 animate-fade-in" | ||
on:click|self={onClose} | ||
aria-label="Close dialog" | ||
/> | ||
|
||
<div class="relative z-10"> | ||
<div class="flex justify-center"> | ||
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4 md:gap-8 max-w-4xl py-8 px-4"> | ||
{#each $context.chains as chain, i} | ||
<button | ||
style="animation-delay: {i * 100}ms" | ||
on:click={() => onChainSelect(kind, chain.chain_id)} | ||
type="button" | ||
class="h-72 flex items-end border p-4 bg-secondary group hover:bg-accent transition-colors animate-slide-up" | ||
> | ||
<span class="font-supermolot uppercase font-bold text-xl text-start text-secondary-foreground group-hover:text-secondary"> | ||
{chain.display_name} | ||
</span> | ||
</button> | ||
{/each} | ||
</div> | ||
</div> | ||
</div> | ||
</dialog> | ||
{/if} | ||
|
||
<style> | ||
@keyframes fade-in { | ||
from { | ||
opacity: 0; | ||
} | ||
to { | ||
opacity: 1; | ||
} | ||
} | ||
@keyframes slide-up { | ||
from { | ||
transform: translateY(30px); | ||
opacity: 0; | ||
} | ||
to { | ||
transform: translateY(0); | ||
opacity: 1; | ||
} | ||
} | ||
:global(.animate-fade-in) { | ||
animation: fade-in 0.3s ease-out forwards; | ||
} | ||
:global(.animate-slide-up) { | ||
animation: slide-up 0.4s ease-out forwards; | ||
opacity: 0; | ||
} | ||
</style> |
14 changes: 14 additions & 0 deletions
14
app/src/lib/components/TransferFrom/components/Cube/FaceWrapper.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<script> | ||
export let visible = true | ||
export let width = 0; // Pixel value | ||
export let height = 0; // Pixel value | ||
export let translateZ = 0; | ||
export let rotateY = "0deg"; | ||
</script> | ||
|
||
<div | ||
class="absolute bg-neutral-900 flex flex-col items-center p-4 border-2 {visible ? 'opacity-100' : 'opacity-0 pointer-events-none'}}" | ||
style={`width: ${width}px; height: ${height}px; transform: rotateY(${rotateY}) translateZ(${translateZ}px);;`} | ||
> | ||
<slot /> | ||
</div> |
23 changes: 23 additions & 0 deletions
23
app/src/lib/components/TransferFrom/components/Cube/faces/Assets.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<script lang="ts"> | ||
import type {IntentStore} from "$lib/components/TransferFrom/transfer/intents.ts"; | ||
import type {ValidationStoreAndMethods} from "$lib/components/TransferFrom/transfer/validation.ts"; | ||
import type {Readable} from "svelte/store"; | ||
import type {ContextStore} from "$lib/components/TransferFrom/transfer/context.ts"; | ||
import type {CubeFaces} from "$lib/components/TransferFrom/types.ts"; | ||
interface Props { | ||
stores: { | ||
intents: IntentStore | ||
validation: ValidationStoreAndMethods | ||
context: Readable<ContextStore> | ||
} | ||
rotateTo: (face: CubeFaces) => void | ||
} | ||
export let stores: Props["stores"] | ||
export let rotateTo: Props["rotateTo"] | ||
$: ({intents, validation, context} = stores) | ||
</script> | ||
|
||
<button class="font-supermolot font-bold text-lg mb-4" on:click={() => rotateTo("intentFace")}>Select asset</button> |
28 changes: 28 additions & 0 deletions
28
app/src/lib/components/TransferFrom/components/Cube/faces/Chains.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
<script lang="ts"> | ||
import type {IntentStore} from "$lib/components/TransferFrom/transfer/intents.ts"; | ||
import type {ValidationStoreAndMethods} from "$lib/components/TransferFrom/transfer/validation.ts"; | ||
import type {Readable} from "svelte/store"; | ||
import type {ContextStore} from "$lib/components/TransferFrom/transfer/context.ts"; | ||
import type {CubeFaces} from "$lib/components/TransferFrom/types.ts"; | ||
interface Props { | ||
stores: { | ||
intents: IntentStore | ||
validation: ValidationStoreAndMethods | ||
context: Readable<ContextStore> | ||
} | ||
rotateTo: (face: CubeFaces) => void | ||
select: "source" | "destination" | ||
} | ||
export let stores: Props["stores"] | ||
export let rotateTo: Props["rotateTo"] | ||
export let select: Props["select"] | ||
$: ({intents, validation, context} = stores) | ||
</script> | ||
|
||
<h2 class="font-supermolot font-bold text-lg mb-4">Select chain</h2> | ||
{#each $context.chains as chain} | ||
<button on:click={() => rotateTo("intentFace")}>{chain.display_name}</button> | ||
{/each} |
87 changes: 87 additions & 0 deletions
87
app/src/lib/components/TransferFrom/components/Cube/faces/Intent.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
<script lang="ts"> | ||
import Direction from "$lib/components/TransferFrom/components/Direction.svelte"; | ||
import AssetDialog from "$lib/components/TransferFrom/components/AssetDialog.svelte"; | ||
import type {Readable} from "svelte/store"; | ||
import type {IntentStore} from "$lib/components/TransferFrom/transfer/intents.ts"; | ||
import type {ValidationStoreAndMethods} from "$lib/components/TransferFrom/transfer/validation.ts"; | ||
import type {ContextStore} from "$lib/components/TransferFrom/transfer/context.ts"; | ||
import type {CubeFaces} from "$lib/components/TransferFrom/types.ts"; | ||
import {Button} from "$lib/components/ui/button"; | ||
interface Props { | ||
stores: { | ||
intents: IntentStore | ||
validation: ValidationStoreAndMethods | ||
context: Readable<ContextStore> | ||
} | ||
rotateTo: (face: CubeFaces) => void | ||
} | ||
export let stores: Props["stores"] | ||
export let rotateTo: Props["rotateTo"] | ||
$: ({intents, validation, context} = stores) | ||
</script> | ||
|
||
<div class="flex flex-col justify-between w-full h-full"> | ||
<div class="flex flex-col gap-4"> | ||
<Direction | ||
{context} | ||
{intents} | ||
getSourceChain={() => rotateTo("sourceFace")} | ||
getDestinationChain={() => rotateTo("destinationFace")} | ||
/> | ||
<AssetDialog | ||
{context} | ||
{intents} | ||
onSelectAsset={() => rotateTo("assetsFace")} | ||
/> | ||
<div class="flex flex-col gap-1"> | ||
<input | ||
id="amount" | ||
type="number" | ||
name="amount" | ||
minlength={1} | ||
maxlength={64} | ||
required={true} | ||
disabled={false} | ||
autocorrect="off" | ||
placeholder="0.00" | ||
spellcheck="false" | ||
autocomplete="off" | ||
inputmode="decimal" | ||
data-field="amount" | ||
autocapitalize="none" | ||
pattern="^[0-9]*[.,]?[0-9]*$" | ||
class="p-1 {$validation.errors.amount ? 'border-red-500' : ''}" | ||
value={$intents.amount} | ||
on:input={event => intents.updateField('amount', event)} | ||
/> | ||
{#if $validation.errors.amount} | ||
<span class="text-red-500 text-sm">{$validation.errors.amount}</span> | ||
{/if} | ||
</div> | ||
|
||
<div class="flex flex-col gap-1"> | ||
<input | ||
type="text" | ||
id="receiver" | ||
name="receiver" | ||
required={true} | ||
disabled={false} | ||
autocorrect="off" | ||
spellcheck="false" | ||
autocomplete="off" | ||
data-field="receiver" | ||
class="p-1 disabled:bg-black/30 {$validation.errors.receiver ? 'border-red-500' : ''}" | ||
placeholder="Enter destination address" | ||
value={$intents.receiver} | ||
on:input={event => intents.updateField('receiver', event)} | ||
/> | ||
{#if $validation.errors.receiver} | ||
<span class="text-red-500 text-sm">{$validation.errors.receiver}</span> | ||
{/if} | ||
</div> | ||
</div> | ||
<Button on:click={() => rotateTo("verifyFace")}>Transfer</Button> | ||
</div> |
23 changes: 23 additions & 0 deletions
23
app/src/lib/components/TransferFrom/components/Cube/faces/Transfer.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<script lang="ts"> | ||
import type {IntentStore} from "$lib/components/TransferFrom/transfer/intents.ts"; | ||
import type {ValidationStoreAndMethods} from "$lib/components/TransferFrom/transfer/validation.ts"; | ||
import type {Readable} from "svelte/store"; | ||
import type {ContextStore} from "$lib/components/TransferFrom/transfer/context.ts"; | ||
import type {CubeFaces} from "$lib/components/TransferFrom/types.ts"; | ||
interface Props { | ||
stores: { | ||
intents: IntentStore | ||
validation: ValidationStoreAndMethods | ||
context: Readable<ContextStore> | ||
} | ||
rotateTo: (face: CubeFaces) => void | ||
} | ||
export let stores: Props["stores"] | ||
export let rotateTo: Props["rotateTo"] | ||
$: ({intents, validation, context} = stores) | ||
</script> | ||
|
||
<button on:click={() => rotateTo("intentFace")}>Transfer</button> |
98 changes: 98 additions & 0 deletions
98
app/src/lib/components/TransferFrom/components/Cube/index.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
<script lang="ts"> | ||
import type {CubeFaces} from "$lib/components/TransferFrom/types.ts"; | ||
import FaceWrapper from "$lib/components/TransferFrom/components/Cube/FaceWrapper.svelte"; | ||
import {deviceWidth} from "$lib/utilities/device.ts"; | ||
let currentRotation = {x: 0, y: 0}; | ||
const facePositions = { | ||
intentFace: 0, | ||
chainsFace: -90, | ||
verifyFace: -180, | ||
assetsFace: -270, | ||
sourceFace: -90, | ||
destinationFace: -90, | ||
} as const; | ||
let currentVisibleFace: "source" | "destination" = "source"; | ||
$: currentVisibleFace = "source"; | ||
function findShortestRotation(current: number, target: number): number { | ||
const revolution = Math.floor(current / 360) * 360; | ||
const normalizedTarget = target + revolution; | ||
let diff = normalizedTarget - current; | ||
if (Math.abs(diff) > 180) { | ||
diff = diff > 0 ? diff - 360 : diff + 360; | ||
} | ||
return current + diff; | ||
} | ||
function rotateTo(face: CubeFaces) { | ||
console.log('rotate to: ', face) | ||
const targetRotation = facePositions[face]; | ||
// Calculate the new Y rotation | ||
const newY = findShortestRotation(currentRotation.y, targetRotation); | ||
currentRotation = {x: 0, y: newY}; | ||
// Update visibility state | ||
if (face === "sourceFace") { | ||
currentVisibleFace = "source"; | ||
} else if (face === "destinationFace") { | ||
currentVisibleFace = "destination"; | ||
} | ||
} | ||
//If we want to be specific we can set each w | ||
$: width = | ||
$deviceWidth >= 1536 ? 400 : // 2xl breakpoint | ||
$deviceWidth >= 1280 ? 400 : // xl breakpoint | ||
$deviceWidth >= 1024 ? 400 : // lg breakpoint | ||
$deviceWidth >= 768 ? 400 : // md breakpoint | ||
$deviceWidth >= 640 ? 400 : // sm breakpoint | ||
300; // Default for smaller screens | ||
$: height = width * 1.5; | ||
$: translateZ = width / 2; | ||
</script> | ||
|
||
<div class="h-screen w-full flex items-center justify-center bg-black perspective-[2000px]"> | ||
<div | ||
class="relative transform-style-preserve-3d transition-transform duration-1000" | ||
style={`width: ${width}px; height: ${height}px; transform: rotateX(${currentRotation.x}deg) rotateY(${currentRotation.y}deg)`} | ||
> | ||
<FaceWrapper {width} {height} {translateZ} visible rotateY={"0deg"}> | ||
<slot name="intent" {rotateTo}/> | ||
</FaceWrapper> | ||
|
||
<!--Source and destination is on the same degree, we just hide one depending on clicked intent.--> | ||
<!--By doing this we can "layer" faces and reuse the rotation--> | ||
<FaceWrapper {width} {height} {translateZ} visible={currentVisibleFace === 'source'} rotateY={"90deg"}> | ||
<slot name="source" {rotateTo}/> | ||
</FaceWrapper> | ||
|
||
<FaceWrapper {width} {height} {translateZ} visible={currentVisibleFace === 'destination'} rotateY={"90deg"}> | ||
<slot name="destination" {rotateTo}/> | ||
</FaceWrapper> | ||
|
||
<FaceWrapper {width} {height} {translateZ} visible rotateY={"270deg"}> | ||
<slot name="assets" {rotateTo}/> | ||
</FaceWrapper> | ||
|
||
<FaceWrapper {width} {height} {translateZ} visible rotateY={"180deg"}> | ||
<slot name="transfer" {rotateTo}/> | ||
</FaceWrapper> | ||
</div> | ||
</div> | ||
|
||
<style> | ||
.perspective-\[2000px\] { | ||
perspective: 2000px; | ||
} | ||
.transform-style-preserve-3d { | ||
transform-style: preserve-3d; | ||
} | ||
</style> |
Oops, something went wrong.