mirror of
https://github.com/Instadapp/assembly.git
synced 2024-07-29 22:37:06 +00:00
wip
This commit is contained in:
parent
5d00313260
commit
e22a0cc177
29
components/Backdrop.vue
Normal file
29
components/Backdrop.vue
Normal file
|
@ -0,0 +1,29 @@
|
|||
<template>
|
||||
<transition
|
||||
enter-active-class="duration-300 ease-out"
|
||||
enter-class="opacity-0"
|
||||
enter-to-class="opacity-100"
|
||||
leave-active-class="duration-200 ease-in"
|
||||
leave-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<div
|
||||
v-if="show"
|
||||
class="fixed inset-0 z-10 bg-primary-black bg-opacity-20"
|
||||
v-on="$listeners"
|
||||
></div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from '@nuxtjs/composition-api'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
show: { type: Boolean, default: false },
|
||||
},
|
||||
setup() {
|
||||
return {}
|
||||
},
|
||||
})
|
||||
</script>
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="relative flex items-center w-full">
|
||||
<input
|
||||
class="w-full pr-4 form-input"
|
||||
class="w-full pr-4 rounded-[6px] border border-grey-dark border-opacity-[0.15]"
|
||||
type="text"
|
||||
v-bind="$attrs"
|
||||
:class="{ 'pl-9 py-1': dense, 'pl-12': !dense }"
|
||||
|
|
59
components/common/input/InputNumeric.vue
Normal file
59
components/common/input/InputNumeric.vue
Normal file
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div class="flex flex-col flex-shrink-0 w-full">
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="w-full pl-8 pr-8 rounded-[6px] border border-grey-dark border-opacity-[0.15]"
|
||||
type="text"
|
||||
inputmode="decimal"
|
||||
:value="value"
|
||||
v-bind="$attrs"
|
||||
v-on="inputListeners"
|
||||
/>
|
||||
|
||||
<div class="h-0">
|
||||
<transition
|
||||
enter-active-class="duration-75 ease-out"
|
||||
enter-class="opacity-0"
|
||||
enter-to-class="opacity-100"
|
||||
leave-active-class="duration-75 ease-in"
|
||||
leave-class="opacity-100"
|
||||
leave-to-class="opacity-0"
|
||||
>
|
||||
<p v-if="touched && showError && error" class="mt-1 text-red-600 text-11">{{ error }}</p>
|
||||
</transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, watch, ref } from '@nuxtjs/composition-api'
|
||||
import { useInputListeners } from '@/composables/useInputListeners'
|
||||
import { usePattern } from '@/composables/usePattern'
|
||||
|
||||
export default defineComponent({
|
||||
inheritAttrs: false,
|
||||
props: {
|
||||
value: { type: String, default: '' },
|
||||
showError: { type: Boolean, default: false },
|
||||
error: { type: String, default: null },
|
||||
},
|
||||
|
||||
setup(props, context) {
|
||||
const { amountPattern } = usePattern()
|
||||
const amountFilter = (value) => amountPattern.test(value)
|
||||
|
||||
const { inputListeners } = useInputListeners(props, context, amountFilter)
|
||||
|
||||
const touched = ref(false)
|
||||
const stopTouchedWatcher = watch(
|
||||
() => props.value,
|
||||
() => {
|
||||
touched.value = true
|
||||
stopTouchedWatcher()
|
||||
}
|
||||
)
|
||||
|
||||
return { inputListeners, touched }
|
||||
},
|
||||
})
|
||||
</script>
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div
|
||||
class="absolute inset-y-0 right-0 z-10 flex flex-col w-full overflow-hidden transform shadow-xs xxl:translate-x-0 dark:shadow-none xxl-transform-none xxl:relative dark:bg-dark-500 bg-background"
|
||||
class="absolute inset-y-0 right-0 z-10 flex flex-col w-full overflow-hidden transform shadow bg-white"
|
||||
style="max-width: clamp(var(--min-width-app), var(--width-sidebar-context), 100%)"
|
||||
:class="{
|
||||
'translate-x-0 duration-300': isOpen,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="flex flex-col dark:bg-dark-500 bg-background">
|
||||
<div class="flex flex-col bg-white">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
<template>
|
||||
<div
|
||||
class="flex flex-shrink-0 w-full border-b items border-grey-light dark:border-dark-600 h-navbar"
|
||||
style="min-height: var(--height-navbar)"
|
||||
>
|
||||
<div class="flex items-center w-full mx-auto" style="max-width: 296px">
|
||||
<div class="flex-shrink-0 w-full mx-auto max-w-[385px] p-4">
|
||||
<div class="flex justify-between items-center w-full">
|
||||
<button
|
||||
class="flex items-center justify-center py-2 mt-1 mr-5 text-opacity-50 group hover:text-opacity-100 focus:hover:text-opacity-100 text-grey-pure focus:outline-none dark:text-light dark:text-opacity-84"
|
||||
class="flex items-center justify-center text-opacity-50 group hover:text-opacity-100 focus:hover:text-opacity-100 text-grey-pure focus:outline-none"
|
||||
@click="back"
|
||||
>
|
||||
<SVGArrowLeft
|
||||
class="transition-transform duration-75 ease-out transform group-hover:-translate-x-1"
|
||||
/>
|
||||
</button>
|
||||
<div class="w-full mt-1 font-semibold text-14"><slot /></div>
|
||||
|
||||
<button
|
||||
class="flex items-center justify-center text-opacity-50 group hover:text-opacity-100 focus:hover:text-opacity-100 text-grey-pure focus:outline-none"
|
||||
@click="close"
|
||||
>
|
||||
<SVGClose class="w-3 h-3" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="w-full my-5 text-center text-primary-gray font-semibold text-lg"><slot /></div>
|
||||
</div>
|
||||
<!-- <button
|
||||
v-if="!!close"
|
||||
class="flex items-center justify-center p-2 mt-1 text-opacity-50 group hover:text-opacity-100 focus:hover:text-opacity-100 text-grey-pure focus:outline-none"
|
||||
@click="close"
|
||||
>
|
||||
<SVGClose />
|
||||
</button> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -36,8 +36,8 @@ export default defineComponent({
|
|||
SVGArrowLeft,
|
||||
},
|
||||
setup() {
|
||||
const { back } = useSidebar()
|
||||
return { back }
|
||||
const { back, close } = useSidebar()
|
||||
return { back, close }
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<SidebarContextHeader><slot name="title" /></SidebarContextHeader>
|
||||
|
||||
<div class="overflow-y-scroll scrollbar-hover">
|
||||
<div class="mx-auto" style="max-width: 296px">
|
||||
<div class="mx-auto max-w-[385px]">
|
||||
<div class="py-2 sm:py-4">
|
||||
<slot />
|
||||
</div>
|
||||
|
|
|
@ -1,83 +1,55 @@
|
|||
<template>
|
||||
<SidebarContextRootContainer>
|
||||
<template #title>Supply SYMBOL</template>
|
||||
<template #title>Supply {{ symbol }}</template>
|
||||
|
||||
<SidebarSectionValueWithIcon class="mt-6" label="Token Balance">
|
||||
<template #icon><IconCurrency :currency="rootTokenKey"/></template>
|
||||
<template #value>BALANCE</template>
|
||||
<SidebarSectionValueWithIcon class="mt-2" label="Token Balance">
|
||||
<template #icon
|
||||
><IconCurrency :currency="rootTokenKey" class="w-20 h-20" noHeight
|
||||
/></template>
|
||||
<template #value>{{ balance }} {{ symbol }}</template>
|
||||
</SidebarSectionValueWithIcon>
|
||||
|
||||
<hr />
|
||||
|
||||
<InputNumeric
|
||||
v-model="amount"
|
||||
:disabled="pending"
|
||||
class="mt-6"
|
||||
placeholder="Amount to supply"
|
||||
:error="'ERROR'"
|
||||
/>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="flex items-center justify-between mt-6">
|
||||
<div class="font-semibold">Set Max</div>
|
||||
|
||||
<ToggleButton :checked="isMaxAmount" @change="toggle" />
|
||||
<div class="bg-background mt-6 p-8">
|
||||
<input-numeric v-model="amount" placeholder="Amount to supply" />
|
||||
</div>
|
||||
|
||||
<SidebarContextHeading class="mt-6"
|
||||
>Projected Debt Position
|
||||
</SidebarContextHeading>
|
||||
|
||||
<hr />
|
||||
|
||||
<SidebarSectionStatus
|
||||
class="mt-6"
|
||||
:liquidation="maxLiquidation"
|
||||
:status="status"
|
||||
/>
|
||||
|
||||
<hr />
|
||||
|
||||
<!-- prettier-ignore -->
|
||||
<SidebarSectionValueWithIcon class="mt-6" label="Liquidation Price (ETH)">
|
||||
<template #value>{{ formatUsdMax(liquidationPrice, liquidationMaxPrice) }} / {{ formatUsd(liquidationMaxPrice) }}</template>
|
||||
</SidebarSectionValueWithIcon>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="flex flex-shrink-0 mt-6">
|
||||
<ButtonCTA
|
||||
class="w-full"
|
||||
:disabled="!isValid || pending"
|
||||
:loading="pending"
|
||||
@click="cast"
|
||||
>Supply</ButtonCTA
|
||||
>
|
||||
</div>
|
||||
|
||||
<ValidationErrors :error-messages="errorMessages" class="mt-6" />
|
||||
</SidebarContextRootContainer>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from '@nuxtjs/composition-api'
|
||||
import { computed, defineComponent, ref } from '@nuxtjs/composition-api'
|
||||
import InputNumeric from '~/components/common/input/InputNumeric.vue'
|
||||
import { useAaveV2Position } from '~/composables/useAaveV2Position'
|
||||
import { useFormatting } from '~/composables/useFormatting'
|
||||
import { useToken } from '~/composables/useToken'
|
||||
|
||||
export default defineComponent({
|
||||
components: { InputNumeric },
|
||||
props: {
|
||||
tokenKey: { type: String, required: true },
|
||||
},
|
||||
setup(props) {
|
||||
const { status } = useAaveV2Position()
|
||||
const { formatUsd, formatUsdMax, formatNumber, formatDecimal } = useFormatting()
|
||||
const { status, displayPositions } = useAaveV2Position()
|
||||
// const { formatUsd, formatUsdMax, formatNumber, formatDecimal } = useFormatting()
|
||||
|
||||
const amount = ref('')
|
||||
|
||||
const rootTokenKey = computed(() => 'eth')
|
||||
|
||||
const { getTokenByKey } = useToken()
|
||||
|
||||
const token = computed(() => getTokenByKey(props.tokenKey))
|
||||
const symbol = computed(() => token.value?.symbol)
|
||||
|
||||
|
||||
const balance = computed(() => "0")
|
||||
|
||||
return {
|
||||
amount,
|
||||
status,
|
||||
|
||||
formatUsd, formatUsdMax, formatNumber, formatDecimal,
|
||||
rootTokenKey,
|
||||
token,
|
||||
symbol,
|
||||
balance,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
<template>
|
||||
<div class="flex items-center justify-between flex-shrink-0">
|
||||
<ValueDisplay class="mr-3" :label="label">
|
||||
<slot name="value" />
|
||||
</ValueDisplay>
|
||||
|
||||
<div class="flex flex-col items-center justify-center text-center flex-shrink-0">
|
||||
<slot name="icon" />
|
||||
|
||||
<value-display class="mt-4" :label="label">
|
||||
<slot name="value" />
|
||||
</value-display>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from '@nuxtjs/composition-api'
|
||||
import ValueDisplay from './ValueDisplay.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { ValueDisplay },
|
||||
props: {
|
||||
label: { type: String, required: true },
|
||||
},
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<template>
|
||||
<div class="flex flex-col items-start">
|
||||
<ValueDisplayLabel class="flex mb-2"
|
||||
>{{ label }} <Info v-if="tooltip" :text="tooltip" class="ml-1" />
|
||||
</ValueDisplayLabel>
|
||||
<div class="h-6 font-medium text-19">
|
||||
<div class="flex flex-col items-center">
|
||||
<div class="h-6 font-medium text-24">
|
||||
<Spinner v-if="loading" class="w-5 h-5" />
|
||||
<slot v-else name="default" />
|
||||
</div>
|
||||
|
||||
<value-display-label class="flex mb-2 mt-3"
|
||||
>{{ label }} <Info v-if="tooltip" :text="tooltip" class="ml-1" />
|
||||
</value-display-label>
|
||||
|
||||
<transition
|
||||
enter-active-class="duration-200 ease-out"
|
||||
enter-class="opacity-0"
|
||||
|
@ -27,8 +28,10 @@
|
|||
|
||||
<script>
|
||||
import { defineComponent } from '@nuxtjs/composition-api'
|
||||
import ValueDisplayLabel from './ValueDisplayLabel.vue'
|
||||
|
||||
export default defineComponent({
|
||||
components: { ValueDisplayLabel },
|
||||
props: {
|
||||
label: { type: String, default: null },
|
||||
loading: { type: Boolean, default: false },
|
||||
|
|
16
composables/useBackdrop.ts
Normal file
16
composables/useBackdrop.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { computed } from "@nuxtjs/composition-api";
|
||||
import { useSidebar } from "./useSidebar";
|
||||
|
||||
export function useBackdrop() {
|
||||
const { isOpen: isSidbarOpen, close: closeSidbar } = useSidebar();
|
||||
|
||||
const isShown = computed(() => isSidbarOpen.value);
|
||||
|
||||
function close() {
|
||||
if (isSidbarOpen.value) {
|
||||
closeSidbar();
|
||||
}
|
||||
}
|
||||
|
||||
return { isShown, close };
|
||||
}
|
57
composables/useInputListeners.ts
Normal file
57
composables/useInputListeners.ts
Normal file
|
@ -0,0 +1,57 @@
|
|||
import { computed } from '@vue/composition-api'
|
||||
import { useBigNumber } from './useBigNumber'
|
||||
const { gt } = useBigNumber()
|
||||
|
||||
function createEventListener(context, eventName, filter, params) {
|
||||
return function (event) {
|
||||
const input = event.target
|
||||
|
||||
if (filter) {
|
||||
// filter input with input filter
|
||||
if (filter(input.value)) {
|
||||
input.oldValue = input.value
|
||||
input.oldSelectionStart = input.selectionStart
|
||||
input.oldSelectionEnd = input.selectionEnd
|
||||
|
||||
if (params?.max && gt(input.value, params.max)) {
|
||||
input.value = params.max
|
||||
}
|
||||
|
||||
context.emit(eventName, input.value)
|
||||
} else if (Object.prototype.hasOwnProperty.call(input, 'oldValue')) {
|
||||
input.value = input.oldValue
|
||||
// FIXME: Jumps back to old value after moving cursor
|
||||
if (input.oldSelectionStart !== null && input.oldSelectionEnd !== null) {
|
||||
input.setSelectionRange(input.oldSelectionStart, input.oldSelectionEnd)
|
||||
}
|
||||
} else {
|
||||
input.value = ''
|
||||
}
|
||||
} else {
|
||||
context.emit(eventName, input.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function useInputListeners(props, context, filter, params) {
|
||||
if (!props || typeof props.value === 'undefined') {
|
||||
throw new Error(
|
||||
"No prop 'value' found. Make sure to define and add it to the input.\nAdd the prop like this:\nvalue: { type: String, required: false, default: '' }\n\nAnd the binding on the input like this:\n:value=\"value\""
|
||||
)
|
||||
}
|
||||
const inputListeners = computed(() =>
|
||||
Object.assign({}, context.listeners, {
|
||||
change: createEventListener(context, 'change', filter, params),
|
||||
input: createEventListener(context, 'input', filter, params),
|
||||
keydown: createEventListener(context, 'keydown', filter, params),
|
||||
keyup: createEventListener(context, 'keyup', filter, params),
|
||||
mousedown: createEventListener(context, 'mousedown', filter, params),
|
||||
mouseup: createEventListener(context, 'mouseup', filter, params),
|
||||
select: createEventListener(context, 'select', filter, params),
|
||||
contextmenu: createEventListener(context, 'contextmenu', filter, params),
|
||||
dro: createEventListener(context, 'dro', filter, params),
|
||||
})
|
||||
)
|
||||
|
||||
return { inputListeners }
|
||||
}
|
7
composables/usePattern.ts
Normal file
7
composables/usePattern.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const amountPattern = /^\d*([,\\.]\d*)?$/;
|
||||
|
||||
const notAlphaNumPattern = /[^A-Za-z0-9\s]+/gi;
|
||||
|
||||
export function usePattern() {
|
||||
return { amountPattern, notAlphaNumPattern };
|
||||
}
|
|
@ -15,6 +15,7 @@ import { useWeb3 } from "./useWeb3";
|
|||
// import SidebarAaveV2Withdraw from '~/components/sidebar/context/aaveV2/SidebarAaveV2Withdraw.vue'
|
||||
|
||||
const sidebars = {
|
||||
"/polygon/aave-v2": { component: null },
|
||||
"/polygon/aave-v2#overview": { component: null },
|
||||
"/polygon/aave-v2#supply": { component: SidebarAaveV2Supply },
|
||||
"/polygon/aave-v2#borrow": { component: null },
|
||||
|
@ -45,7 +46,7 @@ export function init() {
|
|||
const hasDsaChanged = dsa !== oldDsa;
|
||||
|
||||
const [hash, params] = route.hash.split("?");
|
||||
|
||||
|
||||
if (hasPathChanged){
|
||||
router.push({ hash: null })
|
||||
return
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
<template>
|
||||
<div class="min-h-screen overflow-hidden font-sans antialiased text-primary-black">
|
||||
<div
|
||||
class="min-h-screen overflow-hidden font-sans antialiased text-primary-black"
|
||||
>
|
||||
<Navbar />
|
||||
<div class="max-w-6xl mx-auto py-12 overflow-x-hidden ">
|
||||
<div>
|
||||
<Nuxt />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Backdrop :show="isBackdropShown" @click="closeBackdrop" />
|
||||
|
||||
<SidebarContext class="grid-sidebar-context" />
|
||||
|
||||
<NotificationBar />
|
||||
|
@ -13,12 +18,14 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from "@nuxtjs/composition-api";
|
||||
import { defineComponent, watch } from "@nuxtjs/composition-api";
|
||||
import MakerDAOIcon from '~/assets/icons/makerdao.svg?inline'
|
||||
import CompoundIcon from '~/assets/icons/compound.svg?inline'
|
||||
import AaveIcon from '~/assets/icons/aave.svg?inline'
|
||||
import { useWeb3 } from '~/composables/useWeb3'
|
||||
import { init as initSidebars } from '~/composables/useSidebar'
|
||||
import { useBackdrop } from '@/composables/useBackdrop'
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
MakerDAOIcon,
|
||||
|
@ -27,6 +34,15 @@ export default defineComponent({
|
|||
},
|
||||
setup() {
|
||||
const { active, activate, deactivate } = useWeb3();
|
||||
const { isShown: isBackdropShown, close: closeBackdrop } = useBackdrop()
|
||||
|
||||
watch(isBackdropShown, () => {
|
||||
if (isBackdropShown.value) {
|
||||
document.body.classList.add('overflow-hidden')
|
||||
} else {
|
||||
document.body.classList.remove('overflow-hidden')
|
||||
}
|
||||
})
|
||||
|
||||
initSidebars();
|
||||
|
||||
|
@ -34,6 +50,8 @@ export default defineComponent({
|
|||
active,
|
||||
activate,
|
||||
deactivate,
|
||||
isBackdropShown,
|
||||
closeBackdrop,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user