webapp - ESLint + Prettier with pre-commit hooks (#54)
resolves #47 Co-authored-by: johba <johba@harb.eth> Reviewed-on: https://codeberg.org/johba/harb/pulls/54
This commit is contained in:
parent
2acb619a11
commit
f8927b426e
83 changed files with 7137 additions and 5113 deletions
|
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
msg: string
|
||||
}>()
|
||||
msg: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
|
|
|||
55
web-app/src/components/SocialButton.vue
Normal file
55
web-app/src/components/SocialButton.vue
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
<template>
|
||||
<a :href="props.href" target="_blank">
|
||||
<div class="social-badge" :style="{ color: color, 'border-color': color }" :class="{ 'social-badge--dark': props.dark }">
|
||||
<div class="social-badge-icon">
|
||||
<component :color="color" :is="img" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import IconDiscord from '@/components/icons/IconDiscord.vue';
|
||||
import IconTwitter from '@/components/icons/IconTwitter.vue';
|
||||
import IconTelegram from '@/components/icons/IconTelegram.vue';
|
||||
|
||||
interface Props {
|
||||
type?: string;
|
||||
dark?: boolean;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'discord',
|
||||
dark: false,
|
||||
href: '',
|
||||
});
|
||||
|
||||
const color = computed(() => (props.dark ? 'white' : 'black'));
|
||||
|
||||
const icons = {
|
||||
discord: IconDiscord,
|
||||
twitter: IconTwitter,
|
||||
telegram: IconTelegram,
|
||||
} as const;
|
||||
|
||||
const img = computed(() => icons[props.type as keyof typeof icons] ?? null);
|
||||
</script>
|
||||
<style lang="sass">
|
||||
.social-badge
|
||||
border-radius: 14px
|
||||
display: flex
|
||||
border: 1px solid var(--color-social-border)
|
||||
padding: 6px 20px
|
||||
align-items: center
|
||||
flex: 0 1 0
|
||||
color: black
|
||||
&:hover,&:active,&:focus
|
||||
background-color: var(--color-white-hovered)
|
||||
cursor: pointer
|
||||
&.social-badge--dark
|
||||
&:hover, &:active, &:focus
|
||||
background-color: var(--color-black-hovered)
|
||||
// font-size: 0
|
||||
</style>
|
||||
|
|
@ -1,241 +1,213 @@
|
|||
<template>
|
||||
<div class="hold-inner">
|
||||
<div class="stake-inner">
|
||||
<template v-if="!statCollection.initialized">
|
||||
<div>
|
||||
<f-loader></f-loader>
|
||||
</div>
|
||||
</template>
|
||||
<div class="hold-inner">
|
||||
<div class="stake-inner">
|
||||
<template v-if="!statCollection.initialized">
|
||||
<div>
|
||||
<FLoader></FLoader>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<div class="subheader2">Token Amount</div>
|
||||
<FSlider :min="minStakeAmount" :max="maxStakeAmount" v-model="stake.stakingAmountNumber"></FSlider>
|
||||
<div class="formular">
|
||||
<div class="row row-1">
|
||||
<f-input label="Staking Amount" class="staking-amount" v-model="stake.stakingAmountNumber">
|
||||
<template v-slot:details>
|
||||
<div class="balance">Balance: {{ maxStakeAmount.toFixed(2) }} $KRK</div>
|
||||
<div @click="setMaxAmount" class="staking-amount-max">
|
||||
<b>Max</b>
|
||||
</div>
|
||||
</template>
|
||||
</f-input>
|
||||
<Icon class="stake-arrow" icon="mdi:chevron-triple-right"></Icon>
|
||||
<f-input
|
||||
label="Owner Slots"
|
||||
class="staking-amount"
|
||||
disabled
|
||||
:modelValue="`${stakeSlots}(${supplyFreeze?.toFixed(4)})`"
|
||||
>
|
||||
<template #info>
|
||||
Slots correspond to a percentage of ownership in the protocol.<br /><br />1,000 Slots =
|
||||
1% Ownership<br /><br />When you unstake you get the exact percentage of the current
|
||||
$KRK total supply. When the total supply increased since you staked you get more tokens
|
||||
back than before.
|
||||
</template>
|
||||
</f-input>
|
||||
</div>
|
||||
<div class="row row-2">
|
||||
<f-select :items="adjustTaxRate.taxRates" label="Tax" v-model="taxRate">
|
||||
<template v-slot:info>
|
||||
The yearly tax you have to pay to keep your slots open. The tax is paid when unstaking
|
||||
or manually in the dashboard. If someone pays a higher tax they can buy you out.
|
||||
</template>
|
||||
</f-select>
|
||||
<f-input label="Floor Tax" disabled :modelValue="snatchSelection.floorTax">
|
||||
<template v-slot:info>
|
||||
This is the current minimum tax you have to pay to claim owner slots from other owners.
|
||||
</template>
|
||||
</f-input>
|
||||
<f-input label="Positions Buyout" disabled :modelValue="snatchSelection.snatchablePositions.length">
|
||||
<template v-slot:info>
|
||||
This shows you the numbers of staking positions you buy out from current owners by
|
||||
paying a higher tax. If you get bought out yourself by new owners you get paid out the
|
||||
current market value of your position incl. your profits.
|
||||
</template>
|
||||
</f-input>
|
||||
</div>
|
||||
</div>
|
||||
<f-button size="large" disabled block v-if="stake.state === 'NoBalance'">Insufficient Balance</f-button>
|
||||
<f-button size="large" disabled block v-else-if="stake.stakingAmountNumber < minStakeAmount"
|
||||
>Stake amount too low</f-button
|
||||
>
|
||||
<f-button
|
||||
size="large"
|
||||
disabled
|
||||
block
|
||||
v-else-if="
|
||||
!snatchSelection.openPositionsAvailable && stake.state === 'StakeAble' && snatchSelection.snatchablePositions.length === 0
|
||||
"
|
||||
>taxRate too low to snatch</f-button
|
||||
>
|
||||
<f-button
|
||||
size="large"
|
||||
block
|
||||
v-else-if="stake.state === 'StakeAble' && snatchSelection.snatchablePositions.length === 0"
|
||||
@click="stakeSnatch"
|
||||
>Stake</f-button
|
||||
>
|
||||
<f-button
|
||||
size="large"
|
||||
block
|
||||
v-else-if="stake.state === 'StakeAble' && snatchSelection.snatchablePositions.length > 0"
|
||||
@click="stakeSnatch"
|
||||
>Snatch and Stake</f-button
|
||||
>
|
||||
<f-button size="large" outlined block v-else-if="stake.state === 'SignTransaction'"
|
||||
>Sign Transaction ...</f-button
|
||||
>
|
||||
<f-button size="large" outlined block v-else-if="stake.state === 'Waiting'">Waiting ...</f-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="subheader2">Token Amount</div>
|
||||
<FSlider :min="minStakeAmount" :max="maxStakeAmount" v-model="stake.stakingAmountNumber"></FSlider>
|
||||
<div class="formular">
|
||||
<div class="row row-1">
|
||||
<FInput label="Staking Amount" class="staking-amount" v-model="stake.stakingAmountNumber">
|
||||
<template v-slot:details>
|
||||
<div class="balance">Balance: {{ maxStakeAmount.toFixed(2) }} $KRK</div>
|
||||
<div @click="setMaxAmount" class="staking-amount-max">
|
||||
<b>Max</b>
|
||||
</div>
|
||||
</template>
|
||||
</FInput>
|
||||
<Icon class="stake-arrow" icon="mdi:chevron-triple-right"></Icon>
|
||||
<FInput label="Owner Slots" class="staking-amount" disabled :modelValue="`${stakeSlots}(${supplyFreeze?.toFixed(4)})`">
|
||||
<template #info>
|
||||
Slots correspond to a percentage of ownership in the protocol.<br /><br />1,000 Slots = 1% Ownership<br /><br />When you
|
||||
unstake you get the exact percentage of the current $KRK total supply. When the total supply increased since you staked you
|
||||
get more tokens back than before.
|
||||
</template>
|
||||
</FInput>
|
||||
</div>
|
||||
<div class="row row-2">
|
||||
<FSelect :items="adjustTaxRate.taxRates" label="Tax" v-model="taxRate">
|
||||
<template v-slot:info>
|
||||
The yearly tax you have to pay to keep your slots open. The tax is paid when unstaking or manually in the dashboard. If
|
||||
someone pays a higher tax they can buy you out.
|
||||
</template>
|
||||
</FSelect>
|
||||
<FInput label="Floor Tax" disabled :modelValue="String(snatchSelection.floorTax)">
|
||||
<template v-slot:info> This is the current minimum tax you have to pay to claim owner slots from other owners. </template>
|
||||
</FInput>
|
||||
<FInput label="Positions Buyout" disabled :modelValue="String(snatchSelection.snatchablePositions.value.length)">
|
||||
<template v-slot:info>
|
||||
This shows you the numbers of staking positions you buy out from current owners by paying a higher tax. If you get bought
|
||||
out yourself by new owners you get paid out the current market value of your position incl. your profits.
|
||||
</template>
|
||||
</FInput>
|
||||
</div>
|
||||
</div>
|
||||
<FButton size="large" disabled block v-if="stake.state === 'NoBalance'">Insufficient Balance</FButton>
|
||||
<FButton size="large" disabled block v-else-if="stake.stakingAmountNumber < minStakeAmount">Stake amount too low</FButton>
|
||||
<FButton
|
||||
size="large"
|
||||
disabled
|
||||
block
|
||||
v-else-if="
|
||||
!snatchSelection.openPositionsAvailable && stake.state === 'StakeAble' && snatchSelection.snatchablePositions.value.length === 0
|
||||
"
|
||||
>taxRate too low to snatch</FButton
|
||||
>
|
||||
<FButton
|
||||
size="large"
|
||||
block
|
||||
v-else-if="stake.state === 'StakeAble' && snatchSelection.snatchablePositions.value.length === 0"
|
||||
@click="stakeSnatch"
|
||||
>Stake</FButton
|
||||
>
|
||||
<FButton
|
||||
size="large"
|
||||
block
|
||||
v-else-if="stake.state === 'StakeAble' && snatchSelection.snatchablePositions.value.length > 0"
|
||||
@click="stakeSnatch"
|
||||
>Snatch and Stake</FButton
|
||||
>
|
||||
<FButton size="large" outlined block v-else-if="stake.state === 'SignTransaction'">Sign Transaction ...</FButton>
|
||||
<FButton size="large" outlined block v-else-if="stake.state === 'Waiting'">Waiting ...</FButton>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FButton from "@/components/fcomponents/FButton.vue";
|
||||
import FInput from "@/components/fcomponents/FInput.vue";
|
||||
import FSelect from "@/components/fcomponents/FSelect.vue";
|
||||
import FLoader from "@/components/fcomponents/FLoader.vue";
|
||||
import FSlider from "@/components/fcomponents/FSlider.vue";
|
||||
import FOutput from "@/components/fcomponents/FOutput.vue";
|
||||
import { Icon } from "@iconify/vue";
|
||||
import { formatBigIntDivision, InsertCommaNumber, formatBigNumber, bigInt2Number } from "@/utils/helper";
|
||||
import { formatUnits } from "viem";
|
||||
import { loadPositions, usePositions } from "@/composables/usePositions";
|
||||
import { useStake } from "@/composables/useStake";
|
||||
import { useClaim } from "@/composables/useClaim";
|
||||
import { useAdjustTaxRate } from "@/composables/useAdjustTaxRates";
|
||||
import { useSnatchSelection } from "@/composables/useSnatchSelection";
|
||||
import { getMinStake } from "@/contracts/harb";
|
||||
import { useWallet } from "@/composables/useWallet";
|
||||
import { ref, onMounted, watch, computed, inject, watchEffect } from "vue";
|
||||
import { useStatCollection, loadStats } from "@/composables/useStatCollection";
|
||||
import { useRoute } from "vue-router";
|
||||
import FButton from '@/components/fcomponents/FButton.vue';
|
||||
import FInput from '@/components/fcomponents/FInput.vue';
|
||||
import FSelect from '@/components/fcomponents/FSelect.vue';
|
||||
import FLoader from '@/components/fcomponents/FLoader.vue';
|
||||
import FSlider from '@/components/fcomponents/FSlider.vue';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import { bigInt2Number } from '@/utils/helper';
|
||||
import { loadPositions, usePositions, type Position } from '@/composables/usePositions';
|
||||
import { useStake } from '@/composables/useStake';
|
||||
import { useClaim } from '@/composables/useClaim';
|
||||
import { useAdjustTaxRate } from '@/composables/useAdjustTaxRates';
|
||||
import { useSnatchSelection } from '@/composables/useSnatchSelection';
|
||||
import { assetsToShares } from '@/contracts/stake';
|
||||
import { getMinStake } from '@/contracts/harb';
|
||||
import { useWallet } from '@/composables/useWallet';
|
||||
import { ref, onMounted, watch, computed, watchEffect } from 'vue';
|
||||
import { useStatCollection, loadStats } from '@/composables/useStatCollection';
|
||||
import { useRoute } from 'vue-router';
|
||||
|
||||
const demo = sessionStorage.getItem("demo") === "true";
|
||||
const demo = sessionStorage.getItem('demo') === 'true';
|
||||
const route = useRoute();
|
||||
|
||||
const adjustTaxRate = useAdjustTaxRate();
|
||||
|
||||
const activeTab = ref("stake");
|
||||
const StakeMenuOpen = ref(false);
|
||||
const taxRate = ref<number>(1.0);
|
||||
const loading = ref<boolean>(true);
|
||||
const stakeSnatchLoading = ref<boolean>(false);
|
||||
const stake = useStake();
|
||||
const claim = useClaim();
|
||||
const _claim = useClaim();
|
||||
const wallet = useWallet();
|
||||
const statCollection = useStatCollection();
|
||||
|
||||
const { activePositions } = usePositions();
|
||||
const { activePositions: _activePositions } = usePositions();
|
||||
|
||||
const minStake = ref(0n);
|
||||
const stakeSlots = ref();
|
||||
const supplyFreeze = ref<number>(0);
|
||||
let debounceTimer: ReturnType<typeof setTimeout>;
|
||||
watchEffect(() => {
|
||||
console.log("supplyFreeze");
|
||||
if (!stake.stakingAmount) {
|
||||
supplyFreeze.value = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!stake.stakingAmount) {
|
||||
supplyFreeze.value = 0;
|
||||
return;
|
||||
}
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(async () => {
|
||||
stake.stakingAmountShares = await assetsToShares(stake.stakingAmount);
|
||||
const stakingAmountSharesNumber = bigInt2Number(stake.stakingAmountShares, 18);
|
||||
const stakeableSupplyNumber = bigInt2Number(statCollection.stakeableSupply, 18);
|
||||
minStake.value = await getMinStake();
|
||||
|
||||
clearTimeout(debounceTimer);
|
||||
debounceTimer = setTimeout(async () => {
|
||||
stake.stakingAmountShares = await assetsToShares(stake.stakingAmount);
|
||||
const stakingAmountSharesNumber = bigInt2Number(stake.stakingAmountShares, 18);
|
||||
const stakeableSupplyNumber = bigInt2Number(statCollection.stakeableSupply, 18);
|
||||
minStake.value = await getMinStake();
|
||||
|
||||
console.log(stakingAmountSharesNumber / stakeableSupplyNumber);
|
||||
supplyFreeze.value = stakingAmountSharesNumber / stakeableSupplyNumber;
|
||||
}, 500); // Verzögerung von 500ms
|
||||
supplyFreeze.value = stakingAmountSharesNumber / stakeableSupplyNumber;
|
||||
}, 500);
|
||||
});
|
||||
|
||||
watchEffect(() => {
|
||||
console.log("stakeSlots");
|
||||
stakeSlots.value = (supplyFreeze.value * 1000)?.toFixed(2);
|
||||
stakeSlots.value = (supplyFreeze.value * 1000)?.toFixed(2);
|
||||
});
|
||||
|
||||
const tokenIssuance = computed(() => {
|
||||
if (statCollection.kraikenTotalSupply === 0n) {
|
||||
return 0n;
|
||||
}
|
||||
const _tokenIssuance = computed(() => {
|
||||
if (statCollection.kraikenTotalSupply === 0n) {
|
||||
return 0n;
|
||||
}
|
||||
|
||||
return (statCollection.nettoToken7d / statCollection.kraikenTotalSupply) * 100n;
|
||||
return (statCollection.nettoToken7d / statCollection.kraikenTotalSupply) * 100n;
|
||||
});
|
||||
|
||||
async function stakeSnatch() {
|
||||
if (snatchSelection.snatchablePositions.value.length === 0) {
|
||||
await stake.snatch(stake.stakingAmount, taxRate.value);
|
||||
} else {
|
||||
const snatchAblePositionsIds = snatchSelection.snatchablePositions.value.map((p: Position) => p.positionId);
|
||||
await stake.snatch(stake.stakingAmount, taxRate.value, snatchAblePositionsIds);
|
||||
}
|
||||
stakeSnatchLoading.value = true;
|
||||
await new Promise((resolve) => setTimeout(resolve, 10000));
|
||||
await loadPositions();
|
||||
await loadStats();
|
||||
stakeSnatchLoading.value = false;
|
||||
if (snatchSelection.snatchablePositions.value.length === 0) {
|
||||
await stake.snatch(stake.stakingAmount, taxRate.value);
|
||||
} else {
|
||||
const snatchAblePositionsIds = snatchSelection.snatchablePositions.value.map((p: Position) => p.positionId);
|
||||
await stake.snatch(stake.stakingAmount, taxRate.value, snatchAblePositionsIds);
|
||||
}
|
||||
stakeSnatchLoading.value = true;
|
||||
await new Promise(resolve => setTimeout(resolve, 10000));
|
||||
await loadPositions();
|
||||
await loadStats();
|
||||
stakeSnatchLoading.value = false;
|
||||
}
|
||||
|
||||
watch(
|
||||
route,
|
||||
async (to) => {
|
||||
console.log("to", to.hash);
|
||||
if (to.hash === "#stake") {
|
||||
console.log("StakeMenuOpen", StakeMenuOpen.value);
|
||||
StakeMenuOpen.value = true;
|
||||
}
|
||||
},
|
||||
{ flush: "pre", immediate: true, deep: true }
|
||||
route,
|
||||
async to => {
|
||||
if (to.hash === '#stake') {
|
||||
StakeMenuOpen.value = true;
|
||||
}
|
||||
},
|
||||
{ flush: 'pre', immediate: true, deep: true }
|
||||
);
|
||||
|
||||
onMounted(async () => {
|
||||
try {
|
||||
minStake.value = await getMinStake();
|
||||
stake.stakingAmountNumber = minStakeAmount.value;
|
||||
} catch (error) {
|
||||
console.error("error", error);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
try {
|
||||
minStake.value = await getMinStake();
|
||||
stake.stakingAmountNumber = minStakeAmount.value;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
});
|
||||
|
||||
const minStakeAmount = computed(() => {
|
||||
console.log("minStake", minStake.value);
|
||||
return bigInt2Number(minStake.value, 18);
|
||||
return bigInt2Number(minStake.value, 18);
|
||||
});
|
||||
|
||||
const maxStakeAmount = computed(() => {
|
||||
if (wallet.balance?.value) {
|
||||
console.log("wallet.balance.value", wallet.balance);
|
||||
console.log("formatBigIntDivision(wallet.balance.value, 10n ** 18n)", bigInt2Number(wallet.balance.value, 18));
|
||||
return bigInt2Number(wallet.balance.value, 18);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
if (wallet.balance?.value) {
|
||||
return bigInt2Number(wallet.balance.value, 18);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
watch(
|
||||
minStakeAmount,
|
||||
async (newValue) => {
|
||||
console.log("newValue", newValue);
|
||||
if (newValue > stake.stakingAmountNumber && stake.stakingAmountNumber === 0) {
|
||||
stake.stakingAmountNumber = minStakeAmount.value;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
minStakeAmount,
|
||||
async newValue => {
|
||||
if (newValue > stake.stakingAmountNumber && stake.stakingAmountNumber === 0) {
|
||||
stake.stakingAmountNumber = minStakeAmount.value;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
function setMaxAmount() {
|
||||
console.log("maxStakeAmount.value", maxStakeAmount.value);
|
||||
stake.stakingAmountNumber = maxStakeAmount.value;
|
||||
stake.stakingAmountNumber = maxStakeAmount.value;
|
||||
}
|
||||
|
||||
const snatchSelection = useSnatchSelection(demo);
|
||||
const snatchSelection = useSnatchSelection(demo, taxRate);
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
@ -274,4 +246,4 @@ const snatchSelection = useSnatchSelection(demo);
|
|||
.stake-arrow
|
||||
align-self: center
|
||||
font-size: 30px
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,39 +1,42 @@
|
|||
<template>
|
||||
<div class="stats-output" :styles="styles">
|
||||
<f-card>
|
||||
<h6>{{ props.headline }}</h6>
|
||||
<f-output :name="props.name" :price="props.price">
|
||||
<template #price>
|
||||
<slot name="price"></slot>
|
||||
</template>
|
||||
</f-output>
|
||||
</f-card>
|
||||
</div>
|
||||
<div class="stats-output" :styles="styles">
|
||||
<FCard>
|
||||
<h6>{{ props.headline }}</h6>
|
||||
<FOutput :name="props.name" :price="props.price">
|
||||
<template #price>
|
||||
<slot name="price"></slot>
|
||||
</template>
|
||||
</FOutput>
|
||||
</FCard>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
import FCard from "@/components/fcomponents/FCard.vue"
|
||||
import FOutput from "@/components/fcomponents/FOutput.vue"
|
||||
import { computed } from 'vue';
|
||||
import FCard from '@/components/fcomponents/FCard.vue';
|
||||
import FOutput from '@/components/fcomponents/FOutput.vue';
|
||||
interface Props {
|
||||
name?: string;
|
||||
headline: string;
|
||||
price: string | number;
|
||||
width?: number;
|
||||
name?: string;
|
||||
headline: string;
|
||||
price: string | number;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
interface Styles {
|
||||
width?: string;
|
||||
width?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
name: '',
|
||||
width: undefined,
|
||||
});
|
||||
|
||||
const styles = computed(() => {
|
||||
const returnObject: Styles = {};
|
||||
if (props.width) {
|
||||
returnObject.width = `${props.width}px`;
|
||||
}
|
||||
return returnObject;
|
||||
const returnObject: Styles = {};
|
||||
if (props.width) {
|
||||
returnObject.width = `${props.width}px`;
|
||||
}
|
||||
return returnObject;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,121 +0,0 @@
|
|||
<template>
|
||||
<f-card :bg-color="bgcolor" :border-width="0" box-shadow="unset">
|
||||
<div class="info-popup">
|
||||
<div class="info-popup__header">
|
||||
<h6>{{ props.header }}</h6>
|
||||
</div>
|
||||
<div class="info-popup__body">
|
||||
<div>
|
||||
{{ props.subheader }}
|
||||
</div>
|
||||
<div v-if="props.value">
|
||||
<span class="number-big">{{ props.value }}</span
|
||||
> <span>{{ props.token }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!props.value">
|
||||
<hr />
|
||||
</div>
|
||||
<div class="info-popup__body2" v-if="props.info" v-html="props.info"></div>
|
||||
<div class="info-popup__footer">
|
||||
<f-button light block small @click="closeToast">Okay</f-button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="body">
|
||||
<h6 class="header">test{{ props.header }}</h6>
|
||||
<div class="subheader toast-header">test{{ props.subheader }}</div>
|
||||
<div class="amount-number">
|
||||
<div class="token-amount number-mobile">test{{ props.value }}</div>
|
||||
<div class="token-name">test{{ props.token }}</div>
|
||||
</div>
|
||||
<div class="info toast-body">test{{ props.info }}</div>
|
||||
</div> -->
|
||||
</f-card>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getCurrentInstance, computed } from "vue";
|
||||
import FButton from "@/components/fcomponents/FButton.vue";
|
||||
import FCard from "@/components/fcomponents/FCard.vue";
|
||||
import { useToast } from "vue-toastification";
|
||||
import type { ToastID } from "vue-toastification/dist/types/types";
|
||||
|
||||
const props = defineProps({
|
||||
value: String,
|
||||
header: String,
|
||||
subheader: String,
|
||||
info: String,
|
||||
token: String,
|
||||
type: String,
|
||||
});
|
||||
|
||||
const bgcolor = computed(() => {
|
||||
let color = "white";
|
||||
console.log("props.type");
|
||||
console.log(props.type);
|
||||
switch (props.type) {
|
||||
case "info":
|
||||
color = "#5f4884";
|
||||
break;
|
||||
case "error":
|
||||
color = "#8B0000";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return color;
|
||||
});
|
||||
|
||||
// element.classList.add("toast-open");
|
||||
const toast = useToast();
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
instance!.parent!.parent!.vnode!.el!.classList.add("toast-open");
|
||||
const id = instance!.attrs["toast-id"] as ToastID;
|
||||
|
||||
console.log("instance", instance!.attrs["toast-id"]);
|
||||
|
||||
function closeToast() {
|
||||
instance!.parent!.parent!.vnode!.el!.classList.remove("toast-open");
|
||||
toast.dismiss(id);
|
||||
}
|
||||
</script>
|
||||
<style lang="sass">
|
||||
.info-popup
|
||||
width: 342px
|
||||
display: flex
|
||||
color: var(--color-white)
|
||||
flex-direction: column
|
||||
gap: 16px
|
||||
font-size: var(--font-body1)
|
||||
text-align: center
|
||||
hr
|
||||
border: 1px solid var(--color-grey)
|
||||
.info-popup__header
|
||||
h6
|
||||
margin: 0
|
||||
color: var(--color-white)
|
||||
.info-popup__body
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 8px
|
||||
|
||||
.Vue-Toastification__container
|
||||
&.toast-open
|
||||
background-color: rgb(15, 15, 15, 0.7)
|
||||
height: 100vh
|
||||
width: 100vw
|
||||
position: fixed
|
||||
left: 0
|
||||
bottom: 0
|
||||
z-index: 10
|
||||
@media (min-width: 992px)
|
||||
background-color: unset
|
||||
&.top-center
|
||||
@media (min-width: 600px)
|
||||
left: unset
|
||||
margin-left: unset
|
||||
.Vue-Toastification__toast
|
||||
box-shadow: unset
|
||||
&.modal-overlay
|
||||
background-color: unset
|
||||
</style>
|
||||
118
web-app/src/components/ToastNotification.vue
Normal file
118
web-app/src/components/ToastNotification.vue
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
<template>
|
||||
<FCard :bg-color="bgcolor" :border-width="0" box-shadow="unset">
|
||||
<div class="info-popup">
|
||||
<div class="info-popup__header">
|
||||
<h6>{{ props.header }}</h6>
|
||||
</div>
|
||||
<div class="info-popup__body">
|
||||
<div>
|
||||
{{ props.subheader }}
|
||||
</div>
|
||||
<div v-if="props.value">
|
||||
<span class="number-big">{{ props.value }}</span
|
||||
> <span>{{ props.token }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!props.value">
|
||||
<hr />
|
||||
</div>
|
||||
<div class="info-popup__body2" v-if="props.info" v-html="props.info"></div>
|
||||
<div class="info-popup__footer">
|
||||
<FButton light block small @click="closeToast">Okay</FButton>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="body">
|
||||
<h6 class="header">test{{ props.header }}</h6>
|
||||
<div class="subheader toast-header">test{{ props.subheader }}</div>
|
||||
<div class="amount-number">
|
||||
<div class="token-amount number-mobile">test{{ props.value }}</div>
|
||||
<div class="token-name">test{{ props.token }}</div>
|
||||
</div>
|
||||
<div class="info toast-body">test{{ props.info }}</div>
|
||||
</div> -->
|
||||
</FCard>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { getCurrentInstance, computed } from 'vue';
|
||||
import FButton from '@/components/fcomponents/FButton.vue';
|
||||
import FCard from '@/components/fcomponents/FCard.vue';
|
||||
import { useToast } from 'vue-toastification';
|
||||
import type { ToastID } from 'vue-toastification/dist/types/types';
|
||||
|
||||
interface Props {
|
||||
value?: string;
|
||||
header?: string;
|
||||
subheader?: string;
|
||||
info?: string;
|
||||
token?: string;
|
||||
type?: string;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const bgcolor = computed(() => {
|
||||
let color = 'white';
|
||||
switch (props.type) {
|
||||
case 'info':
|
||||
color = '#5f4884';
|
||||
break;
|
||||
case 'error':
|
||||
color = '#8B0000';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return color;
|
||||
});
|
||||
|
||||
// element.classList.add("toast-open");
|
||||
const toast = useToast();
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
instance!.parent!.parent!.vnode!.el!.classList.add('toast-open');
|
||||
const id = instance!.attrs['toast-id'] as ToastID;
|
||||
|
||||
function closeToast() {
|
||||
instance!.parent!.parent!.vnode!.el!.classList.remove('toast-open');
|
||||
toast.dismiss(id);
|
||||
}
|
||||
</script>
|
||||
<style lang="sass">
|
||||
.info-popup
|
||||
width: 342px
|
||||
display: flex
|
||||
color: var(--color-white)
|
||||
flex-direction: column
|
||||
gap: 16px
|
||||
font-size: var(--font-body1)
|
||||
text-align: center
|
||||
hr
|
||||
border: 1px solid var(--color-grey)
|
||||
.info-popup__header
|
||||
h6
|
||||
margin: 0
|
||||
color: var(--color-white)
|
||||
.info-popup__body
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 8px
|
||||
|
||||
.Vue-Toastification__container
|
||||
&.toast-open
|
||||
background-color: rgb(15, 15, 15, 0.7)
|
||||
height: 100vh
|
||||
width: 100vw
|
||||
position: fixed
|
||||
left: 0
|
||||
bottom: 0
|
||||
z-index: 10
|
||||
@media (min-width: 992px)
|
||||
background-color: unset
|
||||
&.top-center
|
||||
@media (min-width: 600px)
|
||||
left: unset
|
||||
margin-left: unset
|
||||
.Vue-Toastification__toast
|
||||
box-shadow: unset
|
||||
&.modal-overlay
|
||||
background-color: unset
|
||||
</style>
|
||||
|
|
@ -1,30 +1,24 @@
|
|||
<template>
|
||||
<chart-js
|
||||
:snatchedPositions="snatchPositions.map((obj) => obj.id)"
|
||||
:positions="activePositions"
|
||||
:dark="darkTheme"
|
||||
></chart-js>
|
||||
<ChartJs :snatchedPositions="snatchPositions.map(obj => obj.id)" :positions="activePositions" :dark="darkTheme"></ChartJs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import ChartJs from "@/components/chart/ChartJs.vue";
|
||||
import {bigInt2Number, formatBigIntDivision} from "@/utils/helper";
|
||||
import { computed, ref } from "vue";
|
||||
import { useStatCollection } from "@/composables/useStatCollection";
|
||||
import { useStake } from "@/composables/useStake";
|
||||
import { usePositions, type Position } from "@/composables/usePositions";
|
||||
import { useDark } from "@/composables/useDark";
|
||||
import ChartJs from '@/components/chart/ChartJs.vue';
|
||||
import { bigInt2Number, formatBigIntDivision } from '@/utils/helper';
|
||||
import { computed, ref } from 'vue';
|
||||
import { useStatCollection } from '@/composables/useStatCollection';
|
||||
import { useStake } from '@/composables/useStake';
|
||||
import { usePositions, type Position } from '@/composables/usePositions';
|
||||
import { useDark } from '@/composables/useDark';
|
||||
const { darkTheme } = useDark();
|
||||
|
||||
const { activePositions, myActivePositions, tresholdValue, myClosedPositions, createRandomPosition } = usePositions();
|
||||
const { activePositions } = usePositions();
|
||||
const ignoreOwner = ref(false);
|
||||
|
||||
const taxRate = ref<number>(1.0);
|
||||
|
||||
const minStakeAmount = computed(() => {
|
||||
console.log("minStake", minStake.value);
|
||||
|
||||
return formatBigIntDivision(minStake.value, 10n ** 18n);
|
||||
return formatBigIntDivision(minStake.value, 10n ** 18n);
|
||||
});
|
||||
|
||||
const stakeAbleHarbAmount = computed(() => statCollection.kraikenTotalSupply / 5n);
|
||||
|
|
@ -34,35 +28,33 @@ const minStake = computed(() => stakeAbleHarbAmount.value / 600n);
|
|||
const stake = useStake();
|
||||
const statCollection = useStatCollection();
|
||||
const snatchPositions = computed(() => {
|
||||
if (
|
||||
if (
|
||||
bigInt2Number(statCollection.outstandingStake, 18) + stake.stakingAmountNumber <=
|
||||
bigInt2Number(statCollection.kraikenTotalSupply, 18) * 0.2
|
||||
) {
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
//Differenz aus outstandingSupply und totalSupply bestimmen, wie viel HARB kann zum Snatch verwendet werden
|
||||
const difference =
|
||||
}
|
||||
//Differenz aus outstandingSupply und totalSupply bestimmen, wie viel HARB kann zum Snatch verwendet werden
|
||||
const difference =
|
||||
bigInt2Number(statCollection.outstandingStake, 18) +
|
||||
stake.stakingAmountNumber -
|
||||
bigInt2Number(statCollection.kraikenTotalSupply, 18) * 0.2;
|
||||
console.log("difference", difference);
|
||||
|
||||
//Division ohne Rest, um zu schauen wie viele Positionen gesnatched werden könnten
|
||||
const snatchAblePositionsCount = Math.floor(difference / minStakeAmount.value);
|
||||
//Division ohne Rest, um zu schauen wie viele Positionen gesnatched werden könnten
|
||||
const snatchAblePositionsCount = Math.floor(difference / minStakeAmount.value);
|
||||
|
||||
//wenn mehr als 0 Positionen gesnatched werden könnten, wird geschaut wie viele Positionen in Frage kommen
|
||||
if (snatchAblePositionsCount > 0) {
|
||||
//wenn mehr als 0 Positionen gesnatched werden könnten, wird geschaut wie viele Positionen in Frage kommen
|
||||
if (snatchAblePositionsCount > 0) {
|
||||
const snatchAblePositions = activePositions.value.filter((obj: Position) => {
|
||||
if (ignoreOwner.value) {
|
||||
return obj.taxRatePercentage < taxRate.value;
|
||||
}
|
||||
return obj.taxRatePercentage < taxRate.value && !obj.iAmOwner;
|
||||
if (ignoreOwner.value) {
|
||||
return obj.taxRatePercentage < taxRate.value;
|
||||
}
|
||||
return obj.taxRatePercentage < taxRate.value && !obj.iAmOwner;
|
||||
});
|
||||
const slicedArray = snatchAblePositions.slice(0, snatchAblePositionsCount);
|
||||
return slicedArray;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
return [];
|
||||
});
|
||||
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,79 +1,68 @@
|
|||
<template>
|
||||
<div class="positions-graph">
|
||||
<div class="chart-modal" :class="{ 'chart--fullscreen': fullscreenOpen }" @click="toggleFullscreen">
|
||||
<div class="chart-inner" @click.stop>
|
||||
<div class="chart--header">
|
||||
<div class="chart--actions" v-if="props.positions?.length > 0">
|
||||
<reset-zoom-button @click="resetZoom"></reset-zoom-button>
|
||||
<fullscreen-button v-if="isMobile" @click="toggleFullscreen"></fullscreen-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="positions-graph">
|
||||
<div class="chart-modal" :class="{ 'chart--fullscreen': fullscreenOpen }" @click="toggleFullscreen">
|
||||
<div class="chart-inner" @click.stop>
|
||||
<div class="chart--header">
|
||||
<div class="chart--actions" v-if="props.positions?.length > 0">
|
||||
<ResetZoomButton @click="resetZoom"></ResetZoomButton>
|
||||
<FullscreenButton v-if="isMobile" @click="toggleFullscreen"></FullscreenButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="chart--body"
|
||||
:class="{ 'disable-actions': props.positions?.length === 0, dark: props.dark }"
|
||||
>
|
||||
<canvas ref="Chart1"></canvas>
|
||||
<template v-if="props.positions?.length === 0">
|
||||
<p class="chart--no-positions">No positions</p>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tooltipRef" ref="tooltipRef" :class="{ iAmOwner: activePosition?.iAmOwner }">
|
||||
<template v-if="activePosition?.iAmOwner">
|
||||
<p>Your staking position</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>Staking position</p>
|
||||
</template>
|
||||
<b>ID {{ activePosition?.id }}</b>
|
||||
<b>{{ activePosition?.amount }} $KRK</b>
|
||||
<b>Tax {{ activePosition?.taxRatePercentage }} %</b>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chart--body" :class="{ 'disable-actions': props.positions?.length === 0, dark: props.dark }">
|
||||
<canvas ref="Chart1"></canvas>
|
||||
<template v-if="props.positions?.length === 0">
|
||||
<p class="chart--no-positions">No positions</p>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tooltipRef" ref="tooltipRef" :class="{ iAmOwner: activePosition?.iAmOwner }">
|
||||
<template v-if="activePosition?.iAmOwner">
|
||||
<p>Your staking position</p>
|
||||
</template>
|
||||
<template v-else>
|
||||
<p>Staking position</p>
|
||||
</template>
|
||||
<b>ID {{ activePosition?.id }}</b>
|
||||
<b>{{ activePosition?.amount }} $KRK</b>
|
||||
<b>Tax {{ activePosition?.taxRatePercentage }} %</b>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, watch, shallowRef, computed } from "vue";
|
||||
import { onMounted, ref, watch, shallowRef } from 'vue';
|
||||
import {
|
||||
BarController,
|
||||
BarElement,
|
||||
CategoryScale,
|
||||
Chart,
|
||||
LineController,
|
||||
LineElement,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
Tooltip,
|
||||
} from "chart.js";
|
||||
BarController,
|
||||
BarElement,
|
||||
CategoryScale,
|
||||
Chart,
|
||||
LineController,
|
||||
LineElement,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
Tooltip,
|
||||
type TooltipModel,
|
||||
type ChartConfiguration,
|
||||
} from 'chart.js';
|
||||
// import { Chart } from "chart.js";
|
||||
import zoomPlugin from "chartjs-plugin-zoom";
|
||||
import { useAccount } from "@wagmi/vue";
|
||||
import { useMobile } from "@/composables/useMobile";
|
||||
import type { Position } from "@/composables/usePositions";
|
||||
import FullscreenButton from "@/components/chart/FullscreenButton.vue";
|
||||
import ResetZoomButton from "@/components/chart/ResetZoomButton.vue";
|
||||
Chart.register(
|
||||
zoomPlugin,
|
||||
LinearScale,
|
||||
CategoryScale,
|
||||
BarController,
|
||||
BarElement,
|
||||
LineController,
|
||||
LineElement,
|
||||
PointElement,
|
||||
Tooltip
|
||||
);
|
||||
import zoomPlugin from 'chartjs-plugin-zoom';
|
||||
import { useAccount } from '@wagmi/vue';
|
||||
import { useMobile } from '@/composables/useMobile';
|
||||
import type { Position } from '@/composables/usePositions';
|
||||
import FullscreenButton from '@/components/chart/FullscreenButton.vue';
|
||||
import ResetZoomButton from '@/components/chart/ResetZoomButton.vue';
|
||||
Chart.register(zoomPlugin, LinearScale, CategoryScale, BarController, BarElement, LineController, LineElement, PointElement, Tooltip);
|
||||
|
||||
interface Props {
|
||||
positions: Array<Position>;
|
||||
snatchedPositions: Array<string>;
|
||||
dark?: boolean;
|
||||
positions: Array<Position>;
|
||||
snatchedPositions: Array<string>;
|
||||
dark?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
dark: false,
|
||||
dark: false,
|
||||
});
|
||||
|
||||
const Chart1 = ref();
|
||||
|
|
@ -81,298 +70,290 @@ const fullscreenOpen = ref(false);
|
|||
const myChart = ref();
|
||||
const activePosition = ref();
|
||||
const tooltipRef = ref();
|
||||
const positionSnatched = ref();
|
||||
const _positionSnatched = ref();
|
||||
|
||||
const account = useAccount();
|
||||
const isMobile = useMobile();
|
||||
|
||||
function resetZoom() {
|
||||
console.log("resetZoom", { Chart1, myChart });
|
||||
myChart.value.value.resetZoom();
|
||||
myChart.value.value.resetZoom();
|
||||
}
|
||||
|
||||
function toggleFullscreen() {
|
||||
if (fullscreenOpen.value) {
|
||||
document.body.style.position = "unset";
|
||||
document.body.style.overflow = "unset";
|
||||
} else {
|
||||
document.body.style.overflow = "hidden";
|
||||
document.body.style.position = "relative";
|
||||
}
|
||||
fullscreenOpen.value = !fullscreenOpen.value;
|
||||
window.scrollTo(0, 0);
|
||||
if (fullscreenOpen.value) {
|
||||
document.body.style.position = 'unset';
|
||||
document.body.style.overflow = 'unset';
|
||||
} else {
|
||||
document.body.style.overflow = 'hidden';
|
||||
document.body.style.position = 'relative';
|
||||
}
|
||||
fullscreenOpen.value = !fullscreenOpen.value;
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.positions,
|
||||
(newData) => {
|
||||
console.log("props.positions", props.positions);
|
||||
() => props.positions,
|
||||
() => {
|
||||
myChart.value.value.destroy();
|
||||
renderChart(props.positions);
|
||||
|
||||
myChart.value.value.destroy();
|
||||
renderChart(props.positions);
|
||||
|
||||
// myChart.value.value.update();
|
||||
// myChart.value.datasets[0].bars[0].fillColor = "green"; //bar 1
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
// myChart.value.value.update();
|
||||
// myChart.value.datasets[0].bars[0].fillColor = "green"; //bar 1
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.dark,
|
||||
(newData) => {
|
||||
myChart.value.value.destroy();
|
||||
renderChart(props.positions);
|
||||
() => props.dark,
|
||||
() => {
|
||||
myChart.value.value.destroy();
|
||||
renderChart(props.positions);
|
||||
|
||||
// myChart.value.value.update();
|
||||
// myChart.value.datasets[0].bars[0].fillColor = "green"; //bar 1
|
||||
}
|
||||
// myChart.value.value.update();
|
||||
// myChart.value.datasets[0].bars[0].fillColor = "green"; //bar 1
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => props.snatchedPositions,
|
||||
(newData) => {
|
||||
// myChart.value.value.destroy();
|
||||
// renderChart(props.positions);
|
||||
let positionIndex = 0;
|
||||
if (myChart.value.value.data?.datasets[0]) {
|
||||
let backgroundColorArray = myChart.value.value.data.datasets[0].backgroundColor;
|
||||
() => props.snatchedPositions,
|
||||
() => {
|
||||
// myChart.value.value.destroy();
|
||||
// renderChart(props.positions);
|
||||
let positionIndex = 0;
|
||||
if (myChart.value.value.data?.datasets[0]) {
|
||||
const backgroundColorArray = myChart.value.value.data.datasets[0].backgroundColor;
|
||||
|
||||
for (let index = 0; index < backgroundColorArray.length; index++) {
|
||||
const position: Position = myChart.value.value.data.datasets[0].data[index];
|
||||
if (!position) {
|
||||
continue;
|
||||
}
|
||||
for (let index = 0; index < backgroundColorArray.length; index++) {
|
||||
const position: Position = myChart.value.value.data.datasets[0].data[index];
|
||||
if (!position) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!position.iAmOwner) {
|
||||
positionIndex++;
|
||||
}
|
||||
if (positionIndex <= props.snatchedPositions.length && props.snatchedPositions.includes(position.id)) {
|
||||
backgroundColorArray[index] = "##7550AE";
|
||||
} else {
|
||||
backgroundColorArray[index] = "##7550AE";
|
||||
// const position = myChart.value.value.data.datasets[0].data[index];
|
||||
if (position.iAmOwner) {
|
||||
backgroundColorArray[index] = "#7550AE";
|
||||
} else if (props.dark) {
|
||||
backgroundColorArray[index] = "white";
|
||||
} else {
|
||||
backgroundColorArray[index] = "black";
|
||||
}
|
||||
}
|
||||
}
|
||||
myChart.value.value.data.datasets[0].backgroundColor = backgroundColorArray;
|
||||
if (!position.iAmOwner) {
|
||||
positionIndex++;
|
||||
}
|
||||
if (positionIndex <= props.snatchedPositions.length && props.snatchedPositions.includes(position.id)) {
|
||||
backgroundColorArray[index] = '##7550AE';
|
||||
} else {
|
||||
backgroundColorArray[index] = '##7550AE';
|
||||
// const position = myChart.value.value.data.datasets[0].data[index];
|
||||
if (position.iAmOwner) {
|
||||
backgroundColorArray[index] = '#7550AE';
|
||||
} else if (props.dark) {
|
||||
backgroundColorArray[index] = 'white';
|
||||
} else {
|
||||
backgroundColorArray[index] = 'black';
|
||||
}
|
||||
}
|
||||
}
|
||||
myChart.value.value.data.datasets[0].backgroundColor = backgroundColorArray;
|
||||
|
||||
myChart.value.value.ctx.save();
|
||||
myChart.value.value?.update();
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
myChart.value.value.ctx.save();
|
||||
myChart.value.value?.update();
|
||||
}
|
||||
},
|
||||
{
|
||||
deep: true,
|
||||
}
|
||||
);
|
||||
|
||||
const externalTooltipHandler = (context: any) => {
|
||||
const { chart, tooltip } = context;
|
||||
const tooltipEl = tooltipRef.value;
|
||||
const externalTooltipHandler = (context: { chart: Chart; tooltip: TooltipModel<'bar'> }) => {
|
||||
const { chart, tooltip } = context;
|
||||
const tooltipEl = tooltipRef.value;
|
||||
|
||||
// Tooltip ausblenden, wenn keine Daten angezeigt werden sollen
|
||||
if (!tooltip.opacity) {
|
||||
tooltipEl.style.opacity = "0";
|
||||
tooltipEl.style.display = "none";
|
||||
return;
|
||||
}
|
||||
// Tooltip ausblenden, wenn keine Daten angezeigt werden sollen
|
||||
if (!tooltip.opacity) {
|
||||
tooltipEl.style.opacity = '0';
|
||||
tooltipEl.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
// Aktive Position setzen (Daten des angezeigten Punktes)
|
||||
activePosition.value = tooltip.dataPoints[0].element.$context.raw;
|
||||
// Aktive Position setzen (Daten des angezeigten Punktes)
|
||||
activePosition.value = (tooltip.dataPoints[0] as { element?: { $context?: { raw?: Position } } }).element?.$context?.raw;
|
||||
|
||||
// Positionierung des Tooltips
|
||||
const { offsetLeft: chartX, offsetTop: chartY } = chart.canvas;
|
||||
// Positionierung des Tooltips
|
||||
const { offsetLeft: chartX, offsetTop: chartY } = chart.canvas;
|
||||
|
||||
// Tooltip anpassen
|
||||
tooltipEl.style.opacity = "1";
|
||||
tooltipEl.style.display = "flex";
|
||||
tooltipEl.style.position = "absolute";
|
||||
// Tooltip anpassen
|
||||
tooltipEl.style.opacity = '1';
|
||||
tooltipEl.style.display = 'flex';
|
||||
tooltipEl.style.position = 'absolute';
|
||||
|
||||
// Tooltip mittig über dem Punkt platzieren
|
||||
tooltipEl.style.left = `${chartX + tooltip.caretX}px`;
|
||||
tooltipEl.style.top = `${chartY + tooltip.y}px`;
|
||||
// Tooltip mittig über dem Punkt platzieren
|
||||
tooltipEl.style.left = `${chartX + tooltip.caretX}px`;
|
||||
tooltipEl.style.top = `${chartY + tooltip.y}px`;
|
||||
|
||||
// Tooltip für saubere Mitte ausrichten
|
||||
tooltipEl.style.transform = "translateX(-50%)";
|
||||
tooltipEl.style.pointerEvents = "none";
|
||||
// Tooltip für saubere Mitte ausrichten
|
||||
tooltipEl.style.transform = 'translateX(-50%)';
|
||||
tooltipEl.style.pointerEvents = 'none';
|
||||
};
|
||||
|
||||
function renderChart(data: any) {
|
||||
console.log("renderChart");
|
||||
function renderChart(data: Position[]) {
|
||||
const backgroundColors = [];
|
||||
const data1 = data.map(obj => {
|
||||
return {
|
||||
...obj,
|
||||
// taxRatePercentage: obj.taxRate * 100,
|
||||
iAmOwner: obj.owner?.toLowerCase() === account.address.value?.toLowerCase(),
|
||||
};
|
||||
});
|
||||
|
||||
const backgroundColors = [];
|
||||
const data1 = data.map((obj: any) => {
|
||||
return {
|
||||
...obj,
|
||||
// taxRatePercentage: obj.taxRate * 100,
|
||||
iAmOwner: obj.owner?.toLowerCase() === account.address.value?.toLowerCase(),
|
||||
};
|
||||
});
|
||||
console.log("data1", data1);
|
||||
for (let index = 0; index < data1.length; index++) {
|
||||
const position = data1[index];
|
||||
|
||||
for (let index = 0; index < data1.length; index++) {
|
||||
const position = data1[index];
|
||||
// if(index < props.snatchedPositions){
|
||||
// backgroundColors.push("rgba(26,84,244, 0.5)");
|
||||
// positionSnatched.value = index;
|
||||
|
||||
// if(index < props.snatchedPositions){
|
||||
// backgroundColors.push("rgba(26,84,244, 0.5)");
|
||||
// positionSnatched.value = index;
|
||||
// }
|
||||
if (position.iAmOwner) {
|
||||
backgroundColors.push('rgba(117,80,174, 0.8)');
|
||||
} else if (props.dark) {
|
||||
backgroundColors[index] = 'white';
|
||||
} else {
|
||||
backgroundColors[index] = 'black';
|
||||
}
|
||||
}
|
||||
|
||||
// }
|
||||
if (position.iAmOwner) {
|
||||
backgroundColors.push("rgba(117,80,174, 0.8)");
|
||||
} else if (props.dark) {
|
||||
backgroundColors[index] = "white";
|
||||
} else {
|
||||
backgroundColors[index] = "black";
|
||||
}
|
||||
}
|
||||
|
||||
console.log("backgroundColors", backgroundColors);
|
||||
|
||||
myChart.value = shallowRef(
|
||||
new Chart(Chart1.value, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: data1.map((row: any) => row.id),
|
||||
datasets: [
|
||||
{
|
||||
type: "line",
|
||||
label: "TaxRate",
|
||||
data: data1,
|
||||
backgroundColor: ["#7550AE"],
|
||||
borderColor: ["#7550AE"],
|
||||
yAxisID: "y",
|
||||
parsing: {
|
||||
yAxisKey: "taxRatePercentage",
|
||||
xAxisKey: "id",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "bar",
|
||||
label: "Amount",
|
||||
data: data1,
|
||||
backgroundColor: backgroundColors,
|
||||
yAxisID: "y1",
|
||||
parsing: {
|
||||
yAxisKey: "amount",
|
||||
xAxisKey: "id",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
animation: {
|
||||
duration: 1,
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: "index",
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
position: "nearest",
|
||||
external: externalTooltipHandler,
|
||||
},
|
||||
zoom: {
|
||||
pan: {
|
||||
enabled: true,
|
||||
mode: "xy",
|
||||
},
|
||||
limits: {
|
||||
y: { min: 0 },
|
||||
},
|
||||
zoom: {
|
||||
wheel: {
|
||||
enabled: true,
|
||||
},
|
||||
pinch: {
|
||||
enabled: true,
|
||||
},
|
||||
mode: "xy",
|
||||
onZoomComplete(object: any) {
|
||||
// This update is needed to display up to date zoom level in the title.
|
||||
// Without this, previous zoom level is displayed.
|
||||
// The reason is: title uses the same beforeUpdate hook, and is evaluated before zoom.
|
||||
object.chart?.update("none");
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
// type: "linear",
|
||||
display: true,
|
||||
position: "left",
|
||||
max: Math.max(...data.map((o: any) => o.taxRate)) * 100 * 1.5,
|
||||
// min: 0,
|
||||
title: {
|
||||
display: true,
|
||||
text: "Tax",
|
||||
color: "#7550AE",
|
||||
font: {
|
||||
size: 16, // Hier die Schriftgröße ändern (z. B. 16px)
|
||||
weight: "bold", // Falls du den Text fett machen möchtest
|
||||
},
|
||||
},
|
||||
},
|
||||
y1: {
|
||||
// type: "linear",
|
||||
display: true,
|
||||
position: "right",
|
||||
max: Math.max(...data.map((o: any) => o.amount)) * 1.5,
|
||||
title: {
|
||||
display: true,
|
||||
text: "Slots",
|
||||
color: "white",
|
||||
font: {
|
||||
size: 16, // Hier die Schriftgröße ändern (z. B. 16px)
|
||||
weight: "bold", // Falls du den Text fett machen möchtest
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
// min: 0,
|
||||
},
|
||||
x: {
|
||||
display: true,
|
||||
ticks: {
|
||||
display: false,
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: "Positions",
|
||||
color: "white",
|
||||
font: {
|
||||
size: 16, // Hier die Schriftgröße ändern (z. B. 16px)
|
||||
weight: "bold", // Falls du den Text fett machen möchtest
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
} as any)
|
||||
);
|
||||
myChart.value = shallowRef(
|
||||
new Chart(Chart1.value, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: data1.map(row => row.id),
|
||||
datasets: [
|
||||
{
|
||||
type: 'line',
|
||||
label: 'TaxRate',
|
||||
data: data1,
|
||||
backgroundColor: ['#7550AE'],
|
||||
borderColor: ['#7550AE'],
|
||||
yAxisID: 'y',
|
||||
parsing: {
|
||||
yAxisKey: 'taxRatePercentage',
|
||||
xAxisKey: 'id',
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'bar',
|
||||
label: 'Amount',
|
||||
data: data1,
|
||||
backgroundColor: backgroundColors,
|
||||
yAxisID: 'y1',
|
||||
parsing: {
|
||||
yAxisKey: 'amount',
|
||||
xAxisKey: 'id',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
animation: {
|
||||
duration: 1,
|
||||
},
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'index',
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
},
|
||||
tooltip: {
|
||||
enabled: false,
|
||||
position: 'nearest',
|
||||
external: externalTooltipHandler,
|
||||
},
|
||||
zoom: {
|
||||
pan: {
|
||||
enabled: true,
|
||||
mode: 'xy',
|
||||
},
|
||||
limits: {
|
||||
y: { min: 0 },
|
||||
},
|
||||
zoom: {
|
||||
wheel: {
|
||||
enabled: true,
|
||||
},
|
||||
pinch: {
|
||||
enabled: true,
|
||||
},
|
||||
mode: 'xy',
|
||||
onZoomComplete(object: { chart?: Chart }) {
|
||||
// This update is needed to display up to date zoom level in the title.
|
||||
// Without this, previous zoom level is displayed.
|
||||
// The reason is: title uses the same beforeUpdate hook, and is evaluated before zoom.
|
||||
object.chart?.update('none');
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
// type: "linear",
|
||||
display: true,
|
||||
position: 'left',
|
||||
max: Math.max(...data.map(o => o.taxRate)) * 100 * 1.5,
|
||||
// min: 0,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Tax',
|
||||
color: '#7550AE',
|
||||
font: {
|
||||
size: 16, // Hier die Schriftgröße ändern (z. B. 16px)
|
||||
weight: 'bold', // Falls du den Text fett machen möchtest
|
||||
},
|
||||
},
|
||||
},
|
||||
y1: {
|
||||
// type: "linear",
|
||||
display: true,
|
||||
position: 'right',
|
||||
max: Math.max(...data.map(o => o.amount)) * 1.5,
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Slots',
|
||||
color: 'white',
|
||||
font: {
|
||||
size: 16, // Hier die Schriftgröße ändern (z. B. 16px)
|
||||
weight: 'bold', // Falls du den Text fett machen möchtest
|
||||
},
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
// min: 0,
|
||||
},
|
||||
x: {
|
||||
display: true,
|
||||
ticks: {
|
||||
display: false,
|
||||
},
|
||||
grid: {
|
||||
display: false,
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Positions',
|
||||
color: 'white',
|
||||
font: {
|
||||
size: 16, // Hier die Schriftgröße ändern (z. B. 16px)
|
||||
weight: 'bold', // Falls du den Text fett machen möchtest
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
} as unknown as ChartConfiguration)
|
||||
);
|
||||
}
|
||||
onMounted(() => {
|
||||
renderChart(props.positions);
|
||||
renderChart(props.positions);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,24 @@
|
|||
<template>
|
||||
<button class="chart-button">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
class="stroke"
|
||||
d="M10.8027 1.00195H16.002C16.3433 1.00195 16.6201 1.27869 16.6201 1.62006V6.81927"
|
||||
stroke-width="1.85431"
|
||||
/>
|
||||
<path
|
||||
class="stroke"
|
||||
d="M16.6191 10.5273L16.6191 15.7266C16.6191 16.0679 16.3424 16.3447 16.001 16.3447L10.8018 16.3447"
|
||||
stroke-width="1.85431"
|
||||
/>
|
||||
<path
|
||||
class="stroke"
|
||||
d="M7.0918 16.3457L1.89258 16.3457C1.55121 16.3457 1.27448 16.069 1.27448 15.7276L1.27448 10.5284"
|
||||
stroke-width="1.85431"
|
||||
/>
|
||||
<path
|
||||
class="stroke"
|
||||
d="M1.27539 6.81836L1.27539 1.61914C1.27539 1.27777 1.55213 1.00104 1.8935 1.00104L7.09271 1.00104"
|
||||
stroke-width="1.85431"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<button class="chart-button">
|
||||
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path class="stroke" d="M10.8027 1.00195H16.002C16.3433 1.00195 16.6201 1.27869 16.6201 1.62006V6.81927" stroke-width="1.85431" />
|
||||
<path
|
||||
class="stroke"
|
||||
d="M16.6191 10.5273L16.6191 15.7266C16.6191 16.0679 16.3424 16.3447 16.001 16.3447L10.8018 16.3447"
|
||||
stroke-width="1.85431"
|
||||
/>
|
||||
<path
|
||||
class="stroke"
|
||||
d="M7.0918 16.3457L1.89258 16.3457C1.55121 16.3457 1.27448 16.069 1.27448 15.7276L1.27448 10.5284"
|
||||
stroke-width="1.85431"
|
||||
/>
|
||||
<path
|
||||
class="stroke"
|
||||
d="M1.27539 6.81836L1.27539 1.61914C1.27539 1.27777 1.55213 1.00104 1.8935 1.00104L7.09271 1.00104"
|
||||
stroke-width="1.85431"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
<template>
|
||||
<button class="chart-button">
|
||||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1_3412_52485" fill="white">
|
||||
<path
|
||||
d="M12.9797 15.2305C11.7286 16.2335 10.2045 16.8366 8.60589 16.9613C7.00726 17.086 5.4081 16.7265 4.01664 15.9296C2.62518 15.1327 1.50588 13.9353 0.804464 12.4934C0.103046 11.0515 -0.14799 9.43173 0.0840395 7.84511C0.316069 6.2585 1.02041 4.77849 2.10537 3.59778C3.19033 2.41708 4.60564 1.59038 6.16702 1.22532C7.72841 0.860254 9.36354 0.973741 10.8595 1.551C12.3555 2.12826 13.643 3.14256 14.5545 4.46182L13.109 5.46048C12.3981 4.4315 11.3938 3.64038 10.227 3.19013C9.0602 2.73989 7.78485 2.65137 6.56702 2.93611C5.34918 3.22084 4.24529 3.86565 3.39905 4.78656C2.55282 5.70747 2.00345 6.86183 1.82248 8.09935C1.6415 9.33686 1.8373 10.6002 2.38439 11.7249C2.93147 12.8495 3.80449 13.7835 4.88979 14.405C5.97508 15.0266 7.22237 15.307 8.46926 15.2097C9.71615 15.1124 10.9049 14.642 11.8807 13.8597L12.9797 15.2305Z"
|
||||
/>
|
||||
</mask>
|
||||
<path
|
||||
d="M12.9797 15.2305C11.7286 16.2335 10.2045 16.8366 8.60589 16.9613C7.00726 17.086 5.4081 16.7265 4.01664 15.9296C2.62518 15.1327 1.50588 13.9353 0.804464 12.4934C0.103046 11.0515 -0.14799 9.43173 0.0840395 7.84511C0.316069 6.2585 1.02041 4.77849 2.10537 3.59778C3.19033 2.41708 4.60564 1.59038 6.16702 1.22532C7.72841 0.860254 9.36354 0.973741 10.8595 1.551C12.3555 2.12826 13.643 3.14256 14.5545 4.46182L13.109 5.46048C12.3981 4.4315 11.3938 3.64038 10.227 3.19013C9.0602 2.73989 7.78485 2.65137 6.56702 2.93611C5.34918 3.22084 4.24529 3.86565 3.39905 4.78656C2.55282 5.70747 2.00345 6.86183 1.82248 8.09935C1.6415 9.33686 1.8373 10.6002 2.38439 11.7249C2.93147 12.8495 3.80449 13.7835 4.88979 14.405C5.97508 15.0266 7.22237 15.307 8.46926 15.2097C9.71615 15.1124 10.9049 14.642 11.8807 13.8597L12.9797 15.2305Z"
|
||||
stroke="white"
|
||||
stroke-width="3.54886"
|
||||
mask="url(#path-1-inside-1_3412_52485)"
|
||||
/>
|
||||
<path d="M16.0005 6.89955L13.89 0.404049L9.32 5.47956L16.0005 6.89955Z" fill="white" />
|
||||
</svg>
|
||||
</button>
|
||||
<button class="chart-button">
|
||||
<svg width="16" height="17" viewBox="0 0 16 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<mask id="path-1-inside-1_3412_52485" fill="white">
|
||||
<path
|
||||
d="M12.9797 15.2305C11.7286 16.2335 10.2045 16.8366 8.60589 16.9613C7.00726 17.086 5.4081 16.7265 4.01664 15.9296C2.62518 15.1327 1.50588 13.9353 0.804464 12.4934C0.103046 11.0515 -0.14799 9.43173 0.0840395 7.84511C0.316069 6.2585 1.02041 4.77849 2.10537 3.59778C3.19033 2.41708 4.60564 1.59038 6.16702 1.22532C7.72841 0.860254 9.36354 0.973741 10.8595 1.551C12.3555 2.12826 13.643 3.14256 14.5545 4.46182L13.109 5.46048C12.3981 4.4315 11.3938 3.64038 10.227 3.19013C9.0602 2.73989 7.78485 2.65137 6.56702 2.93611C5.34918 3.22084 4.24529 3.86565 3.39905 4.78656C2.55282 5.70747 2.00345 6.86183 1.82248 8.09935C1.6415 9.33686 1.8373 10.6002 2.38439 11.7249C2.93147 12.8495 3.80449 13.7835 4.88979 14.405C5.97508 15.0266 7.22237 15.307 8.46926 15.2097C9.71615 15.1124 10.9049 14.642 11.8807 13.8597L12.9797 15.2305Z"
|
||||
/>
|
||||
</mask>
|
||||
<path
|
||||
d="M12.9797 15.2305C11.7286 16.2335 10.2045 16.8366 8.60589 16.9613C7.00726 17.086 5.4081 16.7265 4.01664 15.9296C2.62518 15.1327 1.50588 13.9353 0.804464 12.4934C0.103046 11.0515 -0.14799 9.43173 0.0840395 7.84511C0.316069 6.2585 1.02041 4.77849 2.10537 3.59778C3.19033 2.41708 4.60564 1.59038 6.16702 1.22532C7.72841 0.860254 9.36354 0.973741 10.8595 1.551C12.3555 2.12826 13.643 3.14256 14.5545 4.46182L13.109 5.46048C12.3981 4.4315 11.3938 3.64038 10.227 3.19013C9.0602 2.73989 7.78485 2.65137 6.56702 2.93611C5.34918 3.22084 4.24529 3.86565 3.39905 4.78656C2.55282 5.70747 2.00345 6.86183 1.82248 8.09935C1.6415 9.33686 1.8373 10.6002 2.38439 11.7249C2.93147 12.8495 3.80449 13.7835 4.88979 14.405C5.97508 15.0266 7.22237 15.307 8.46926 15.2097C9.71615 15.1124 10.9049 14.642 11.8807 13.8597L12.9797 15.2305Z"
|
||||
stroke="white"
|
||||
stroke-width="3.54886"
|
||||
mask="url(#path-1-inside-1_3412_52485)"
|
||||
/>
|
||||
<path d="M16.0005 6.89955L13.89 0.404049L9.32 5.47956L16.0005 6.89955Z" fill="white" />
|
||||
</svg>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
|||
|
|
@ -1,120 +1,101 @@
|
|||
<template>
|
||||
<f-collapse class="f-collapse-active" @collapse:opened="loadActivePositionData" :loading="loading">
|
||||
<template v-slot:header>
|
||||
<div class="collapse-header">
|
||||
<div class="collapse-header-row1">
|
||||
<div><span class="subheader2">Tax</span> {{ props.taxRate }} %</div>
|
||||
<f-button size="tiny" @click="payTax(props.id)">Pay Tax</f-button>
|
||||
<div class="position-id">
|
||||
<span class="subheader2">ID</span> <span class="number-small">{{ props.id }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse-header-row2">
|
||||
<div>
|
||||
<div class="profit-stats-item">
|
||||
<div><b>Initial Stake</b></div>
|
||||
<div>{{ compactNumber(props.amount) }} $KRK</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tags-list">
|
||||
<f-tag v-if="tag">{{ tag }}</f-tag>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="collapse-amount">
|
||||
<FCollapse class="f-collapse-active" @collapse:opened="loadActivePositionData" :loading="loading">
|
||||
<template v-slot:header>
|
||||
<div class="collapse-header">
|
||||
<div class="collapse-header-row1">
|
||||
<div><span class="subheader2">Tax</span> {{ props.taxRate }} %</div>
|
||||
<FButton size="tiny" @click="payTax(props.id)">Pay Tax</FButton>
|
||||
<div class="position-id">
|
||||
<span class="subheader2">ID</span> <span class="number-small">{{ props.id }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapse-header-row2">
|
||||
<div>
|
||||
<div class="profit-stats-item">
|
||||
<div><b>Initial Stake</b></div>
|
||||
<div>{{ compactNumber(props.amount) }} $KRK</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tags-list">
|
||||
<FTag v-if="tag">{{ tag }}</FTag>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="collapse-amount">
|
||||
<span class="number-small">{{ compactNumber(props.amount) }}</span>
|
||||
<span class="caption"> $KRK</span>
|
||||
</div> -->
|
||||
</div>
|
||||
</template>
|
||||
<div class="collapsed-body">
|
||||
<div class="profit-stats-wrapper">
|
||||
<div class="profit-stats-item">
|
||||
<div><b>Tax Paid</b></div>
|
||||
<div>{{ taxPaidGes }} $KRK</div>
|
||||
</div>
|
||||
<div class="profit-stats-item">
|
||||
<div><b>Issuance Earned</b></div>
|
||||
<div>{{ profit }} $KRK</div>
|
||||
</div>
|
||||
<div class="profit-stats-item profit-stats-total">
|
||||
<div><b>Total</b></div>
|
||||
<div>{{ total.toFixed(5) }} $KRK</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapsed-body--actions">
|
||||
<div :class="{ 'collapse-menu-open': showTaxMenu }">
|
||||
<f-button size="small" dense block outlined v-if="adjustTaxRate.state === 'SignTransaction'"
|
||||
>Sign Transaction ...</f-button
|
||||
>
|
||||
<f-button
|
||||
size="small"
|
||||
dense
|
||||
outlined
|
||||
block
|
||||
v-else-if="adjustTaxRate.state === 'Waiting'"
|
||||
@click="unstakePosition"
|
||||
>Waiting ...</f-button
|
||||
>
|
||||
<f-button
|
||||
size="small"
|
||||
dense
|
||||
block
|
||||
v-else-if="adjustTaxRate.state === 'Action' && !showTaxMenu"
|
||||
@click="showTaxMenu = true"
|
||||
>Adjust Tax Rate</f-button
|
||||
>
|
||||
<template v-else>
|
||||
<div class="collapse-menu-input">
|
||||
<f-select :items="filteredTaxRates" v-model="newTaxRate"> </f-select>
|
||||
</div>
|
||||
<div>
|
||||
<f-button size="small" dense @click="changeTax(props.id, newTaxRate)">Confirm</f-button>
|
||||
<f-button size="small" dense outlined @click="showTaxMenu = false">Cancel</f-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div></div>
|
||||
<div>
|
||||
<f-button size="small" dense block outlined v-if="unstake.state === 'SignTransaction'"
|
||||
>Sign Transaction ...</f-button
|
||||
>
|
||||
<f-button size="small" dense outlined block v-else-if="unstake.state === 'Waiting'"
|
||||
>Waiting ...</f-button
|
||||
>
|
||||
<f-button size="small" dense block v-else-if="unstake.state === 'Unstakeable'" @click="unstakePosition"
|
||||
>Unstake</f-button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</f-collapse>
|
||||
</div>
|
||||
</template>
|
||||
<div class="collapsed-body">
|
||||
<div class="profit-stats-wrapper">
|
||||
<div class="profit-stats-item">
|
||||
<div><b>Tax Paid</b></div>
|
||||
<div>{{ taxPaidGes }} $KRK</div>
|
||||
</div>
|
||||
<div class="profit-stats-item">
|
||||
<div><b>Issuance Earned</b></div>
|
||||
<div>{{ profit }} $KRK</div>
|
||||
</div>
|
||||
<div class="profit-stats-item profit-stats-total">
|
||||
<div><b>Total</b></div>
|
||||
<div>{{ total.toFixed(5) }} $KRK</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="collapsed-body--actions">
|
||||
<div :class="{ 'collapse-menu-open': showTaxMenu }">
|
||||
<FButton size="small" dense block outlined v-if="adjustTaxRate.state === 'SignTransaction'">Sign Transaction ...</FButton>
|
||||
<FButton size="small" dense outlined block v-else-if="adjustTaxRate.state === 'Waiting'" @click="unstakePosition"
|
||||
>Waiting ...</FButton
|
||||
>
|
||||
<FButton size="small" dense block v-else-if="adjustTaxRate.state === 'Action' && !showTaxMenu" @click="showTaxMenu = true"
|
||||
>Adjust Tax Rate</FButton
|
||||
>
|
||||
<template v-else>
|
||||
<div class="collapse-menu-input">
|
||||
<FSelect :items="filteredTaxRates" v-model="newTaxRate"> </FSelect>
|
||||
</div>
|
||||
<div>
|
||||
<FButton size="small" dense @click="changeTax(props.id, newTaxRate)">Confirm</FButton>
|
||||
<FButton size="small" dense outlined @click="showTaxMenu = false">Cancel</FButton>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
<div></div>
|
||||
<div>
|
||||
<FButton size="small" dense block outlined v-if="unstake.state === 'SignTransaction'">Sign Transaction ...</FButton>
|
||||
<FButton size="small" dense outlined block v-else-if="unstake.state === 'Waiting'">Waiting ...</FButton>
|
||||
<FButton size="small" dense block v-else-if="unstake.state === 'Unstakeable'" @click="unstakePosition">Unstake</FButton>
|
||||
</div>
|
||||
</div>
|
||||
</FCollapse>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FButton from "@/components/fcomponents/FButton.vue";
|
||||
import FTag from "@/components/fcomponents/FTag.vue";
|
||||
import FSelect from "@/components/fcomponents/FSelect.vue";
|
||||
import FCollapse from "@/components/fcomponents/FCollapse.vue";
|
||||
import { compactNumber, formatBigNumber } from "@/utils/helper";
|
||||
import { useUnstake } from "@/composables/useUnstake";
|
||||
import { useAdjustTaxRate } from "@/composables/useAdjustTaxRates";
|
||||
import { computed, ref, onMounted } from "vue";
|
||||
import { getTaxDue, payTax } from "@/contracts/stake";
|
||||
import { type Position, loadPositions } from "@/composables/usePositions";
|
||||
import { useStatCollection } from "@/composables/useStatCollection";
|
||||
import FButton from '@/components/fcomponents/FButton.vue';
|
||||
import FTag from '@/components/fcomponents/FTag.vue';
|
||||
import FSelect from '@/components/fcomponents/FSelect.vue';
|
||||
import FCollapse from '@/components/fcomponents/FCollapse.vue';
|
||||
import { compactNumber, formatBigNumber } from '@/utils/helper';
|
||||
import { useUnstake } from '@/composables/useUnstake';
|
||||
import { useAdjustTaxRate } from '@/composables/useAdjustTaxRates';
|
||||
import { computed, ref, onMounted } from 'vue';
|
||||
import { getTaxDue, payTax } from '@/contracts/stake';
|
||||
import { type Position, loadPositions } from '@/composables/usePositions';
|
||||
import { useStatCollection } from '@/composables/useStatCollection';
|
||||
|
||||
import { formatUnits } from "viem";
|
||||
import { formatUnits } from 'viem';
|
||||
|
||||
const unstake = useUnstake();
|
||||
const adjustTaxRate = useAdjustTaxRate();
|
||||
const statCollection = useStatCollection();
|
||||
|
||||
const props = defineProps<{
|
||||
taxRate: number;
|
||||
treshold: number;
|
||||
id: bigint;
|
||||
amount: number;
|
||||
position: Position;
|
||||
taxRate: number;
|
||||
treshold: number;
|
||||
id: bigint;
|
||||
amount: number;
|
||||
position: Position;
|
||||
}>();
|
||||
|
||||
const showTaxMenu = ref(false);
|
||||
|
|
@ -125,62 +106,51 @@ const profit = ref<number>();
|
|||
const loading = ref<boolean>(false);
|
||||
|
||||
const tag = computed(() => {
|
||||
if (props.taxRate < props.treshold) {
|
||||
return "Low Tax!";
|
||||
}
|
||||
return "";
|
||||
if (props.taxRate < props.treshold) {
|
||||
return 'Low Tax!';
|
||||
}
|
||||
return '';
|
||||
});
|
||||
|
||||
const total = computed(() => props.amount + profit.value! + -taxPaidGes.value!);
|
||||
|
||||
async function changeTax(id: bigint, newTaxRate: number) {
|
||||
await adjustTaxRate.changeTax(id, newTaxRate);
|
||||
showTaxMenu.value = false;
|
||||
await adjustTaxRate.changeTax(id, newTaxRate);
|
||||
showTaxMenu.value = false;
|
||||
}
|
||||
|
||||
async function unstakePosition() {
|
||||
console.log(props.id);
|
||||
await unstake.exitPosition(props.id);
|
||||
loading.value = true;
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
console.log("loadPositions begin");
|
||||
await loadPositions();
|
||||
console.log("loadPositions end");
|
||||
loading.value = false;
|
||||
await unstake.exitPosition(props.id);
|
||||
loading.value = true;
|
||||
await new Promise(resolve => setTimeout(resolve, 5000));
|
||||
await loadPositions();
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
async function loadActivePositionData() {
|
||||
console.log("loadActivePositionData", props.position);
|
||||
//loadTaxDue
|
||||
taxDue.value = await getTaxDue(props.id);
|
||||
taxPaidGes.value = formatBigNumber(taxDue.value + BigInt(props.position.taxPaid), 18);
|
||||
|
||||
//loadTaxDue
|
||||
taxDue.value = await getTaxDue(props.id);
|
||||
console.log("taxDue", taxDue.value);
|
||||
taxPaidGes.value = formatBigNumber(taxDue.value + BigInt(props.position.taxPaid), 18);
|
||||
console.log("loadActivePositionData", taxPaidGes.value);
|
||||
//loadTotalSupply
|
||||
|
||||
//loadTotalSupply
|
||||
const multiplier = Number(formatUnits(props.position.totalSupplyInit, 18)) / Number(formatUnits(statCollection.kraikenTotalSupply, 18));
|
||||
|
||||
const multiplier =
|
||||
Number(formatUnits(props.position.totalSupplyInit, 18)) /
|
||||
Number(formatUnits(statCollection.kraikenTotalSupply, 18));
|
||||
console.log("props.position.totalSupplyInit", props.position.totalSupplyInit);
|
||||
|
||||
console.log("multiplier", multiplier);
|
||||
|
||||
profit.value =
|
||||
Number(formatUnits(statCollection.kraikenTotalSupply, 18)) * multiplier -
|
||||
Number(formatUnits(statCollection.kraikenTotalSupply, 18));
|
||||
profit.value =
|
||||
Number(formatUnits(statCollection.kraikenTotalSupply, 18)) * multiplier - Number(formatUnits(statCollection.kraikenTotalSupply, 18));
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const taxRate = adjustTaxRate.taxRates.find((obj) => obj.index === props.position.taxRateIndex + 1);
|
||||
if (props.position.taxRateIndex !== undefined) {
|
||||
const taxRate = adjustTaxRate.taxRates.find(obj => obj.index === props.position.taxRateIndex! + 1);
|
||||
|
||||
if (taxRate) {
|
||||
newTaxRate.value = taxRate.year;
|
||||
}
|
||||
if (taxRate) {
|
||||
newTaxRate.value = taxRate.year;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const filteredTaxRates = computed(() => adjustTaxRate.taxRates.filter((obj) => obj.year > props.taxRate));
|
||||
const filteredTaxRates = computed(() => adjustTaxRate.taxRates.filter(obj => obj.year > props.taxRate));
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
|||
|
|
@ -1,56 +1,49 @@
|
|||
<template>
|
||||
<f-collapse class="f-collapse-history">
|
||||
<template v-slot:header>
|
||||
<div class="collapse-header">
|
||||
<div><span class="subheader2">Tax</span> {{ props.taxRate }} %</div>
|
||||
<div>
|
||||
<span class="subheader2">ID</span> <span class="number-small">{{ props.id }}</span>
|
||||
</div>
|
||||
<div class="collapse-amount">
|
||||
<span class="number-small">{{ compactNumber(props.amount) }}</span>
|
||||
<span class="caption"> $KRK</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="collapsed-body history">
|
||||
<div>
|
||||
<span class="subheader2">Tax paid</span><span class="number-small">{{ props.taxPaid }}</span
|
||||
><span class="caption"> $KRK</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="subheader2">Profit</span><span class="number-small">{{ profit }}</span
|
||||
><span class="caption"> $KRK</span>
|
||||
</div>
|
||||
</div>
|
||||
</f-collapse>
|
||||
<FCollapse class="f-collapse-history">
|
||||
<template v-slot:header>
|
||||
<div class="collapse-header">
|
||||
<div><span class="subheader2">Tax</span> {{ props.taxRate }} %</div>
|
||||
<div>
|
||||
<span class="subheader2">ID</span> <span class="number-small">{{ props.id }}</span>
|
||||
</div>
|
||||
<div class="collapse-amount">
|
||||
<span class="number-small">{{ compactNumber(props.amount) }}</span>
|
||||
<span class="caption"> $KRK</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="collapsed-body history">
|
||||
<div>
|
||||
<span class="subheader2">Tax paid</span><span class="number-small">{{ props.taxPaid }}</span
|
||||
><span class="caption"> $KRK</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="subheader2">Profit</span><span class="number-small">{{ profit }}</span
|
||||
><span class="caption"> $KRK</span>
|
||||
</div>
|
||||
</div>
|
||||
</FCollapse>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Position } from "@/composables/usePositions";
|
||||
import FCollapse from "@/components/fcomponents/FCollapse.vue";
|
||||
import { compactNumber } from "@/utils/helper";
|
||||
import { formatUnits } from "viem";
|
||||
import type { Position } from '@/composables/usePositions';
|
||||
import FCollapse from '@/components/fcomponents/FCollapse.vue';
|
||||
import { compactNumber } from '@/utils/helper';
|
||||
import { formatUnits } from 'viem';
|
||||
|
||||
import { computed } from "vue";
|
||||
import { computed } from 'vue';
|
||||
const props = defineProps<{
|
||||
taxRate: number;
|
||||
taxPaid: string;
|
||||
treshold: number;
|
||||
id: bigint;
|
||||
amount: number;
|
||||
position: Position;
|
||||
taxRate: number;
|
||||
taxPaid: string;
|
||||
treshold: number;
|
||||
id: bigint;
|
||||
amount: number;
|
||||
position: Position;
|
||||
}>();
|
||||
|
||||
const profit = computed(() => {
|
||||
const multiplier =
|
||||
Number(formatUnits(props.position.totalSupplyInit, 18)) /
|
||||
Number(formatUnits(props.position.totalSupplyEnd!, 18));
|
||||
console.log("multiplier", multiplier);
|
||||
console.log("props.position.amount", props.position.amount);
|
||||
return (
|
||||
Number(formatUnits(props.position.totalSupplyEnd!, 18)) * multiplier -
|
||||
Number(formatUnits(props.position.totalSupplyEnd!, 18))
|
||||
);
|
||||
const multiplier = Number(formatUnits(props.position.totalSupplyInit, 18)) / Number(formatUnits(props.position.totalSupplyEnd!, 18));
|
||||
return Number(formatUnits(props.position.totalSupplyEnd!, 18)) * multiplier - Number(formatUnits(props.position.totalSupplyEnd!, 18));
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,48 +1,49 @@
|
|||
<template>
|
||||
<button class="f-btn" :class="classObject" :style="styleObject">
|
||||
<slot></slot>
|
||||
</button>
|
||||
<button class="f-btn" :class="classObject" :style="styleObject">
|
||||
<slot></slot>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
interface Props {
|
||||
size?: string;
|
||||
dense?: boolean;
|
||||
disabled?: boolean;
|
||||
invert?: boolean;
|
||||
block?: boolean;
|
||||
outlined?: boolean;
|
||||
bgColor?: string;
|
||||
light?: boolean;
|
||||
dark?: boolean;
|
||||
size?: string;
|
||||
dense?: boolean;
|
||||
disabled?: boolean;
|
||||
invert?: boolean;
|
||||
block?: boolean;
|
||||
outlined?: boolean;
|
||||
bgColor?: string;
|
||||
light?: boolean;
|
||||
dark?: boolean;
|
||||
}
|
||||
|
||||
import { computed } from "vue";
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: "medium",
|
||||
size: 'medium',
|
||||
bgColor: '',
|
||||
});
|
||||
|
||||
const classObject = computed(() => ({
|
||||
"f-btn--tiny": props.size === "tiny",
|
||||
"f-btn--small": props.size === "small",
|
||||
"f-btn--medium": props.size === "medium",
|
||||
"f-btn--large": props.size === "large",
|
||||
"f-btn--dense": props.dense,
|
||||
"f-btn--disabled": props.disabled,
|
||||
"f-btn--invert": props.invert,
|
||||
"f-btn--block": props.block,
|
||||
"f-btn--outlined": props.outlined,
|
||||
"f-btn--light": props.light,
|
||||
"f-btn--dark": props.dark,
|
||||
'f-btn--tiny': props.size === 'tiny',
|
||||
'f-btn--small': props.size === 'small',
|
||||
'f-btn--medium': props.size === 'medium',
|
||||
'f-btn--large': props.size === 'large',
|
||||
'f-btn--dense': props.dense,
|
||||
'f-btn--disabled': props.disabled,
|
||||
'f-btn--invert': props.invert,
|
||||
'f-btn--block': props.block,
|
||||
'f-btn--outlined': props.outlined,
|
||||
'f-btn--light': props.light,
|
||||
'f-btn--dark': props.dark,
|
||||
}));
|
||||
|
||||
const styleObject = computed(() => {
|
||||
const returnObject: any = {};
|
||||
if (props.bgColor) {
|
||||
returnObject["background-color"] = props.bgColor;
|
||||
}
|
||||
return returnObject;
|
||||
const returnObject: Record<string, string> = {};
|
||||
if (props.bgColor) {
|
||||
returnObject['background-color'] = props.bgColor;
|
||||
}
|
||||
return returnObject;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,40 +1,45 @@
|
|||
<template>
|
||||
<div class="f-card" ref="fCard" :style="computedStyles">
|
||||
<div v-if="props.title" class="f-card__title">
|
||||
<h5>
|
||||
{{ props.title }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="f-card__body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-card" ref="fCard" :style="computedStyles">
|
||||
<div v-if="props.title" class="f-card__title">
|
||||
<h5>
|
||||
{{ props.title }}
|
||||
</h5>
|
||||
</div>
|
||||
<div class="f-card__body">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref, computed } from "vue";
|
||||
import { onMounted, ref, computed } from 'vue';
|
||||
|
||||
const fCard = ref();
|
||||
|
||||
interface Props {
|
||||
bgColor?: string;
|
||||
borderWidth?: number;
|
||||
boxShadow?: string;
|
||||
title?: string;
|
||||
bgColor?: string;
|
||||
borderWidth?: number;
|
||||
boxShadow?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
bgColor: '',
|
||||
borderWidth: undefined,
|
||||
boxShadow: '',
|
||||
title: '',
|
||||
});
|
||||
|
||||
const computedStyles = computed(() => ({
|
||||
"border-width": props.borderWidth,
|
||||
"background-color": props.bgColor,
|
||||
"box-shadow": props.boxShadow,
|
||||
'border-width': props.borderWidth,
|
||||
'background-color': props.bgColor,
|
||||
'box-shadow': props.boxShadow,
|
||||
}));
|
||||
|
||||
onMounted(() => {
|
||||
// if (props.bgcolor) {
|
||||
// fCard.value.style["background-color"] = props.bgcolor;
|
||||
// }
|
||||
// if (props.bgcolor) {
|
||||
// fCard.value.style["background-color"] = props.bgcolor;
|
||||
// }
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,50 +1,55 @@
|
|||
<template>
|
||||
<div class="f-collapse">
|
||||
<div class="f-collapse-wrapper" :class="{loading: props.loading}">
|
||||
<template v-if="loading">
|
||||
<f-loader></f-loader>
|
||||
</template>
|
||||
<div class="f-collapse-inner">
|
||||
<slot name="header"></slot>
|
||||
<!-- <img class="toggle-collapse" src="../assets/expand-less.svg?url" alt="expand less" /> -->
|
||||
<Icon v-if="isShow" class="toggle-collapse" icon="mdi:chevron-down" @click="openClose"></Icon>
|
||||
<Icon v-else icon="mdi:chevron-up" class="toggle-collapse" @click="openClose"></Icon>
|
||||
<!-- <img
|
||||
<div class="f-collapse">
|
||||
<div class="f-collapse-wrapper" :class="{ loading: props.loading }">
|
||||
<template v-if="loading">
|
||||
<FLoader></FLoader>
|
||||
</template>
|
||||
<div class="f-collapse-inner">
|
||||
<slot name="header"></slot>
|
||||
<!-- <img class="toggle-collapse" src="../assets/expand-less.svg?url" alt="expand less" /> -->
|
||||
<Icon v-if="isShow" class="toggle-collapse" icon="mdi:chevron-down" @click="openClose"></Icon>
|
||||
<Icon v-else icon="mdi:chevron-up" class="toggle-collapse" @click="openClose"></Icon>
|
||||
<!-- <img
|
||||
class="toggle-collapse"
|
||||
src="../assets/expand-more.svg?url"
|
||||
alt="expand more"
|
||||
v-else
|
||||
|
||||
/> -->
|
||||
</div>
|
||||
<Transition name="collapse">
|
||||
<div v-if="isShow" class="collapsableDiv">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<Transition name="collapse">
|
||||
<div v-if="isShow" class="collapsableDiv">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import FLoader from "@/components/fcomponents/FLoader.vue";
|
||||
import { ref } from 'vue';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import FLoader from '@/components/fcomponents/FLoader.vue';
|
||||
|
||||
const emit = defineEmits(["collapse:opened", "collapse:closed"]);
|
||||
interface Emits {
|
||||
(event: 'collapse:opened'): void;
|
||||
(event: 'collapse:closed'): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const props = defineProps<{
|
||||
loading?: boolean;
|
||||
loading?: boolean;
|
||||
}>();
|
||||
|
||||
const isShow = ref(false);
|
||||
const isShow = ref<boolean>(false);
|
||||
const openClose = () => {
|
||||
isShow.value = !isShow.value;
|
||||
if(isShow.value){
|
||||
emit("collapse:opened")
|
||||
} else{
|
||||
emit("collapse:closed")
|
||||
}
|
||||
isShow.value = !isShow.value;
|
||||
if (isShow.value) {
|
||||
emit('collapse:opened');
|
||||
} else {
|
||||
emit('collapse:closed');
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style lang="sass">
|
||||
|
|
@ -92,6 +97,4 @@ const openClose = () => {
|
|||
to
|
||||
max-height: 0px
|
||||
overflow: hidden
|
||||
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,48 +1,47 @@
|
|||
<template>
|
||||
<div class="f-input" :class="classObject">
|
||||
<div class="f-input-label subheader2">
|
||||
<label v-if="props.label" :for="name">{{ props.label }}</label>
|
||||
<icon>
|
||||
<template v-slot:text v-if="slots.info">
|
||||
<slot name="info"></slot>
|
||||
</template>
|
||||
</icon>
|
||||
</div>
|
||||
<div class="f-input__wrapper" ref="inputWrapper" @click="setFocus">
|
||||
<input
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
:type="props.type"
|
||||
:name="name"
|
||||
:id="name"
|
||||
@input="updateModelValue"
|
||||
:value="props.modelValue"
|
||||
/>
|
||||
<div class="f-input--suffix" v-if="slots.suffix">
|
||||
<slot name="suffix" >test </slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="f-input--details" v-if="slots.details">
|
||||
<slot name="details"> </slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-input" :class="classObject">
|
||||
<div class="f-input-label subheader2">
|
||||
<label v-if="props.label" :for="name">{{ props.label }}</label>
|
||||
<Icon>
|
||||
<template v-slot:text v-if="slots.info">
|
||||
<slot name="info"></slot>
|
||||
</template>
|
||||
</Icon>
|
||||
</div>
|
||||
<div class="f-input__wrapper" ref="inputWrapper" @click="setFocus">
|
||||
<input
|
||||
:disabled="props.disabled"
|
||||
:readonly="props.readonly"
|
||||
:type="props.type"
|
||||
:name="name"
|
||||
:id="name"
|
||||
@input="updateModelValue"
|
||||
:value="props.modelValue"
|
||||
/>
|
||||
<div class="f-input--suffix" v-if="slots.suffix">
|
||||
<slot name="suffix">test </slot>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="f-input--details" v-if="slots.details">
|
||||
<slot name="details"> </slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, getCurrentInstance, useSlots, ref } from "vue";
|
||||
import useClickOutside from "@/composables/useClickOutside"
|
||||
import { computed, getCurrentInstance, useSlots, ref } from 'vue';
|
||||
import useClickOutside from '@/composables/useClickOutside';
|
||||
|
||||
import Icon from "@/components/icons/IconInfo.vue";
|
||||
import Icon from '@/components/icons/IconInfo.vue';
|
||||
interface Props {
|
||||
size?: string;
|
||||
info?: string;
|
||||
label?: string;
|
||||
disabled?: boolean;
|
||||
modelValue?: any;
|
||||
type?: string;
|
||||
readonly?: boolean
|
||||
size?: string;
|
||||
info?: string;
|
||||
label?: string;
|
||||
disabled?: boolean;
|
||||
modelValue?: string | number;
|
||||
type?: string;
|
||||
readonly?: boolean;
|
||||
}
|
||||
|
||||
const slots = useSlots();
|
||||
|
|
@ -53,40 +52,47 @@ const instance = getCurrentInstance();
|
|||
const name = `f-input-${instance!.uid}`;
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: "normal",
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
type: "string",
|
||||
size: 'normal',
|
||||
disabled: false,
|
||||
readonly: false,
|
||||
type: 'string',
|
||||
info: '',
|
||||
label: '',
|
||||
modelValue: '',
|
||||
});
|
||||
|
||||
useClickOutside(inputWrapper, () => {
|
||||
removeFocus();
|
||||
})
|
||||
removeFocus();
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: string): void;
|
||||
}
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
function updateModelValue($event: any) {
|
||||
emit("update:modelValue", $event.target.value);
|
||||
function updateModelValue($event: Event) {
|
||||
const target = $event.target as HTMLInputElement;
|
||||
emit('update:modelValue', target.value);
|
||||
}
|
||||
|
||||
const classObject = computed(() => ({
|
||||
"f-input--normal": props.size === "normal",
|
||||
"f-input--big": props.size === "big",
|
||||
"f-input--disabled": props.disabled,
|
||||
'f-input--normal': props.size === 'normal',
|
||||
'f-input--big': props.size === 'big',
|
||||
'f-input--disabled': props.disabled,
|
||||
}));
|
||||
|
||||
function removeFocus(){
|
||||
const target = inputWrapper.value as HTMLElement
|
||||
target.classList.remove("f-input__wrapper--focused")
|
||||
function removeFocus() {
|
||||
const target = inputWrapper.value as HTMLElement;
|
||||
target.classList.remove('f-input__wrapper--focused');
|
||||
}
|
||||
|
||||
function setFocus(event:MouseEvent){
|
||||
console.log("setFocus");
|
||||
if(props.disabled){
|
||||
return
|
||||
}
|
||||
const target = inputWrapper.value as HTMLElement
|
||||
target.classList.add("f-input__wrapper--focused")
|
||||
function setFocus(_event: MouseEvent) {
|
||||
// console.log("setFocus");
|
||||
if (props.disabled) {
|
||||
return;
|
||||
}
|
||||
const target = inputWrapper.value as HTMLElement;
|
||||
target.classList.add('f-input__wrapper--focused');
|
||||
}
|
||||
</script>
|
||||
<style lang="sass">
|
||||
|
|
@ -109,7 +115,7 @@ function setFocus(event:MouseEvent){
|
|||
background-color: #2D2D2D
|
||||
&.f-input__wrapper--focused
|
||||
outline: none
|
||||
border: 1px solid #7550AE
|
||||
border: 1px solid #7550AE
|
||||
box-shadow: 0 0 5px #7550AE
|
||||
input
|
||||
border: 0
|
||||
|
|
@ -131,5 +137,4 @@ function setFocus(event:MouseEvent){
|
|||
display: flex
|
||||
align-items: center
|
||||
margin-right: 10px
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div class="cube">
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
</div>
|
||||
<div class="cube">
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
<div class="side"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
|||
|
|
@ -1,37 +1,38 @@
|
|||
<template>
|
||||
<div
|
||||
class="output-wrapper"
|
||||
:class="{
|
||||
'no-name': !props.name,
|
||||
'output--variant-1': props.variant === 1,
|
||||
'output--variant-2': props.variant === 2,
|
||||
'output--variant-3': props.variant === 3,
|
||||
}"
|
||||
>
|
||||
<div class="output-left">
|
||||
<div class="output-text">{{ props.name }}</div>
|
||||
<div class="output-price">
|
||||
<slot name="price">
|
||||
{{ props.price }}
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-right" v-if="slots.end">
|
||||
<slot name="end"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="output-wrapper"
|
||||
:class="{
|
||||
'no-name': !props.name,
|
||||
'output--variant-1': props.variant === 1,
|
||||
'output--variant-2': props.variant === 2,
|
||||
'output--variant-3': props.variant === 3,
|
||||
}"
|
||||
>
|
||||
<div class="output-left">
|
||||
<div class="output-text">{{ props.name }}</div>
|
||||
<div class="output-price">
|
||||
<slot name="price">
|
||||
{{ props.price }}
|
||||
</slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="output-right" v-if="slots.end">
|
||||
<slot name="end"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSlots } from "vue";
|
||||
const props = defineProps({
|
||||
name: String,
|
||||
price: [String, Number],
|
||||
variant: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: 1,
|
||||
},
|
||||
import { useSlots, withDefaults } from 'vue';
|
||||
interface Props {
|
||||
name?: string;
|
||||
price?: string | number;
|
||||
variant?: number;
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
variant: 1,
|
||||
name: '',
|
||||
price: '',
|
||||
});
|
||||
|
||||
const slots = useSlots();
|
||||
|
|
|
|||
|
|
@ -1,163 +1,141 @@
|
|||
<template>
|
||||
<div class="o-select" @click="clickSelect" ref="componentRef">
|
||||
<f-input hide-details :clearable="props.clearable" :label="props.label" :selectedable="false"
|
||||
:focus="showList" :modelValue="`${year} % yearly`" readonly>
|
||||
<template #info v-if="slots.info">
|
||||
<slot name="info"></slot>
|
||||
</template>
|
||||
<template #suffix>
|
||||
<Icon class="toggle-collapse" v-if="showList" icon="mdi:chevron-down"></Icon>
|
||||
<Icon class="toggle-collapse" v-else icon="mdi:chevron-up"></Icon>
|
||||
</template>
|
||||
</f-input>
|
||||
<div class="select-list-wrapper" v-show="showList" ref="selectList" >
|
||||
<div class="select-list-inner" @click.stop>
|
||||
<div class="select-list-item" v-for="(item, index) in props.items" :key="item.year" :class="{'active': year === item.year, 'hovered': activeIndex === index}"
|
||||
@click.stop="clickItem(item)" @mouseenter="mouseEnter($event, index)" @mouseleave="mouseLeave($event, index)">
|
||||
<div class="circle">
|
||||
<div class="active" v-if="year === item.year"></div>
|
||||
<div class="hovered" v-else-if="activeIndex === index"></div>
|
||||
</div>
|
||||
<div class="yearly">
|
||||
<div class="value">{{ item.year }} %</div>
|
||||
<div class="label">yearly</div>
|
||||
</div>
|
||||
<div class="daily">
|
||||
<div class="value">{{ item.daily.toFixed(4) }} %</div>
|
||||
<div class="label">daily</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="o-select" @click="clickSelect" ref="componentRef">
|
||||
<FInput
|
||||
hide-details
|
||||
:clearable="props.clearable"
|
||||
:label="props.label ?? undefined"
|
||||
:selectedable="false"
|
||||
:focus="showList"
|
||||
:modelValue="`${year} % yearly`"
|
||||
readonly
|
||||
>
|
||||
<template #info v-if="slots.info">
|
||||
<slot name="info"></slot>
|
||||
</template>
|
||||
<template #suffix>
|
||||
<Icon class="toggle-collapse" v-if="showList" icon="mdi:chevron-down"></Icon>
|
||||
<Icon class="toggle-collapse" v-else icon="mdi:chevron-up"></Icon>
|
||||
</template>
|
||||
</FInput>
|
||||
<div class="select-list-wrapper" v-show="showList" ref="selectList">
|
||||
<div class="select-list-inner" @click.stop>
|
||||
<div
|
||||
class="select-list-item"
|
||||
v-for="(item, index) in props.items"
|
||||
:key="item.year"
|
||||
:class="{ active: year === item.year, hovered: activeIndex === index }"
|
||||
@click.stop="clickItem(item)"
|
||||
@mouseenter="mouseEnter($event, index)"
|
||||
@mouseleave="mouseLeave($event, index)"
|
||||
>
|
||||
<div class="circle">
|
||||
<div class="active" v-if="year === item.year"></div>
|
||||
<div class="hovered" v-else-if="activeIndex === index"></div>
|
||||
</div>
|
||||
<div class="yearly">
|
||||
<div class="value">{{ item.year }} %</div>
|
||||
<div class="label">yearly</div>
|
||||
</div>
|
||||
<div class="daily">
|
||||
<div class="value">{{ item.daily.toFixed(4) }} %</div>
|
||||
<div class="label">daily</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<slot :style="[!props.editor ? {display: 'none'} : {}]"></slot>
|
||||
</div>
|
||||
<slot :style="[!props.editor ? { display: 'none' } : {}]"></slot>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, getCurrentInstance, type ComputedRef, useSlots } from "vue"
|
||||
import FInput from "@/components/fcomponents/FInput.vue"
|
||||
import useClickOutside from "@/composables/useClickOutside"
|
||||
import {Icon} from "@iconify/vue";
|
||||
|
||||
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const slots = useSlots();
|
||||
import { ref, computed, onMounted, useSlots, withDefaults } from 'vue';
|
||||
import FInput from '@/components/fcomponents/FInput.vue';
|
||||
import useClickOutside from '@/composables/useClickOutside';
|
||||
import { Icon } from '@iconify/vue';
|
||||
|
||||
interface Item {
|
||||
year: number;
|
||||
daily: number;
|
||||
year: number;
|
||||
daily: number;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
items: {
|
||||
type: [Array<Item>],
|
||||
required: false,
|
||||
default: []
|
||||
},
|
||||
clearable: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
itemTitle: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "label"
|
||||
},
|
||||
itemValue: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: "value"
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
modelValue: {
|
||||
type: Number,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
editor: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
}
|
||||
interface Props {
|
||||
items?: Item[];
|
||||
clearable?: boolean;
|
||||
itemTitle?: string;
|
||||
itemValue?: string;
|
||||
label?: string | null;
|
||||
modelValue?: number | null;
|
||||
value?: string | null;
|
||||
editor?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
clearable: false,
|
||||
itemTitle: 'label',
|
||||
itemValue: 'value',
|
||||
label: null,
|
||||
modelValue: null,
|
||||
value: null,
|
||||
editor: false,
|
||||
});
|
||||
|
||||
const showList = ref(<boolean>false);
|
||||
const slotElements = ref(<any[]>[])
|
||||
const componentRef = ref(<any>null);
|
||||
const selectList = ref();
|
||||
const activeIndex= ref();
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: number): void;
|
||||
}
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
const showList = ref<boolean>(false);
|
||||
const _slotElements = ref<unknown[]>([]);
|
||||
const componentRef = ref<HTMLElement | null>(null);
|
||||
const selectList = ref<HTMLElement | null>(null);
|
||||
const activeIndex = ref();
|
||||
|
||||
useClickOutside(componentRef, () => {
|
||||
|
||||
showList.value = false
|
||||
})
|
||||
showList.value = false;
|
||||
});
|
||||
|
||||
|
||||
const year= computed({
|
||||
const year = computed({
|
||||
// getter
|
||||
get() {
|
||||
return props.modelValue || props.items[0].year
|
||||
return props.modelValue || props.items[0].year;
|
||||
},
|
||||
// setter
|
||||
set(newValue: number) {
|
||||
|
||||
emit("update:modelValue", newValue)
|
||||
emit('update:modelValue', newValue);
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
function mouseEnter(event:MouseEvent , index:number){
|
||||
const target = event. target as HTMLElement;
|
||||
activeIndex.value = index;
|
||||
target.classList.add("active")
|
||||
function mouseEnter(event: MouseEvent, index: number) {
|
||||
const target = event.target as HTMLElement;
|
||||
activeIndex.value = index;
|
||||
target.classList.add('active');
|
||||
}
|
||||
|
||||
function mouseLeave(event:MouseEvent, index:number){
|
||||
const elements = selectList.value.querySelectorAll('.select-list-item');
|
||||
elements.forEach((element:HTMLElement) => {
|
||||
element.classList.remove("active")
|
||||
});
|
||||
|
||||
function mouseLeave(_event: MouseEvent, _index: number) {
|
||||
const elements = selectList.value?.querySelectorAll('.select-list-item');
|
||||
elements?.forEach(element => {
|
||||
(element as HTMLElement).classList.remove('active');
|
||||
});
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
|
||||
})
|
||||
onMounted(() => {});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function clickSelect(event: any) {
|
||||
showList.value = !showList.value;
|
||||
function clickSelect(_event: unknown) {
|
||||
showList.value = !showList.value;
|
||||
}
|
||||
|
||||
|
||||
function clickItem(item: any) {
|
||||
console.log("item", item);
|
||||
year.value = item.year
|
||||
showList.value = false;
|
||||
console.log("showList.value", showList.value);
|
||||
// emit('input', item)
|
||||
function clickItem(item: { year: number }) {
|
||||
// console.log("item", item);
|
||||
year.value = item.year;
|
||||
showList.value = false;
|
||||
// console.log("showList.value", showList.value);
|
||||
// emit('input', item)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
<style lang="sass">
|
||||
.o-select
|
||||
position: relative
|
||||
|
|
@ -228,7 +206,4 @@ function clickItem(item: any) {
|
|||
&::-webkit-scrollbar-thumb
|
||||
border-radius: 10px
|
||||
background-color: lightgrey
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,148 +1,158 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="slider-wrapper">
|
||||
<div class="disabled-slider" :style="{ 'flex-basis': minPercentage + '%' }">
|
||||
<div class="dot"></div>
|
||||
</div>
|
||||
<div class="range-slider">
|
||||
<input
|
||||
class="range-slider__range"
|
||||
type="range"
|
||||
ref="sliderInput"
|
||||
:style="{
|
||||
background: `linear-gradient(90deg, ${settings.fill} ${percentageDot}%, ${settings.background} ${percentageDot + 0.1}%)`,
|
||||
}"
|
||||
:value="props.modelValue"
|
||||
:min="props.min"
|
||||
:max="props.max"
|
||||
@input="updateModelValue"
|
||||
/>
|
||||
<div
|
||||
class="testbla"
|
||||
@mousemove="testMove"
|
||||
:style="{
|
||||
left: percentageDot + '%',
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div class="slider-wrapper">
|
||||
<div class="disabled-slider" :style="{ 'flex-basis': minPercentage + '%' }">
|
||||
<div class="dot"></div>
|
||||
</div>
|
||||
<div class="range-slider">
|
||||
<input
|
||||
class="range-slider__range"
|
||||
type="range"
|
||||
ref="sliderInput"
|
||||
:style="{
|
||||
background: `linear-gradient(90deg, ${settings.fill} ${percentageDot}%, ${settings.background} ${percentageDot + 0.1}%)`,
|
||||
}"
|
||||
:value="props.modelValue"
|
||||
:min="props.min"
|
||||
:max="props.max"
|
||||
@input="updateModelValue"
|
||||
/>
|
||||
<div
|
||||
class="testbla"
|
||||
@mousemove="testMove"
|
||||
:style="{
|
||||
left: percentageDot + '%',
|
||||
}"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onUnmounted, ref, computed } from "vue";
|
||||
import { onMounted, onUnmounted, ref, computed } from 'vue';
|
||||
|
||||
const sliderInput = ref();
|
||||
const sliderInput = ref<HTMLInputElement | null>(null);
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
interface Emits {
|
||||
(event: 'update:modelValue', value: number): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: number;
|
||||
min: number;
|
||||
max: number;
|
||||
modelValue: number;
|
||||
min: number;
|
||||
max: number;
|
||||
}>();
|
||||
|
||||
const minPercentage = computed(() => {
|
||||
if (!props.min || !props.max) {
|
||||
return 0n;
|
||||
}
|
||||
return (props.min * 100) / props.max;
|
||||
if (!props.min || !props.max) {
|
||||
return 0;
|
||||
}
|
||||
return (props.min * 100) / props.max;
|
||||
});
|
||||
|
||||
function updateModelValue(event: any) {
|
||||
emit("update:modelValue", event.target.valueAsNumber);
|
||||
function updateModelValue(event: Event) {
|
||||
emit('update:modelValue', (event.target as HTMLInputElement).valueAsNumber);
|
||||
}
|
||||
|
||||
|
||||
const sliderValue = computed({
|
||||
// getter
|
||||
get() {
|
||||
return props.modelValue || props.min;
|
||||
},
|
||||
// setter
|
||||
set(newValue) {
|
||||
emit("update:modelValue", newValue);
|
||||
},
|
||||
// getter
|
||||
get() {
|
||||
return Number.isFinite(props.modelValue) ? props.modelValue : props.min;
|
||||
},
|
||||
// setter
|
||||
set(newValue: number) {
|
||||
emit('update:modelValue', newValue);
|
||||
},
|
||||
});
|
||||
|
||||
const percentageDot = computed(() => {
|
||||
let percentage = (100 * (sliderValue.value - props.min)) / (props.max - props.min);
|
||||
|
||||
if(percentage < 20){
|
||||
percentage = percentage + 1;
|
||||
} else if(percentage > 50){
|
||||
percentage = percentage - 2;
|
||||
} else if(percentage > 80){
|
||||
percentage = percentage - 3;
|
||||
}
|
||||
|
||||
return percentage
|
||||
const range = props.max - props.min;
|
||||
if (range <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let percentage = (100 * (sliderValue.value - props.min)) / range;
|
||||
|
||||
if (percentage < 20) {
|
||||
percentage = percentage + 1;
|
||||
} else if (percentage > 50) {
|
||||
percentage = percentage - 2;
|
||||
} else if (percentage > 80) {
|
||||
percentage = percentage - 3;
|
||||
}
|
||||
|
||||
return percentage;
|
||||
});
|
||||
|
||||
const settings = {
|
||||
fill: "#7550AE",
|
||||
background: "#000000",
|
||||
fill: '#7550AE',
|
||||
background: '#000000',
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
sliderInput.value.addEventListener("input", setSliderValue);
|
||||
if (sliderInput.value) {
|
||||
sliderInput.value.addEventListener('input', setSliderValue);
|
||||
}
|
||||
});
|
||||
|
||||
function setSliderValue(event: any){
|
||||
sliderValue.value = event.target.value;
|
||||
function setSliderValue(event: Event) {
|
||||
const target = event.target as HTMLInputElement | null;
|
||||
if (target) {
|
||||
sliderValue.value = target.valueAsNumber;
|
||||
}
|
||||
}
|
||||
|
||||
function testMove(event: any) {
|
||||
}
|
||||
function testMove(_event: unknown) {}
|
||||
|
||||
onUnmounted(() => {
|
||||
console.log("sliderInput.value", sliderInput.value);
|
||||
if(sliderInput.value){
|
||||
sliderInput.value.removeEventListener("input", setSliderValue);
|
||||
}
|
||||
})
|
||||
if (sliderInput.value) {
|
||||
sliderInput.value.removeEventListener('input', setSliderValue);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.slider-wrapper {
|
||||
display: flex;
|
||||
display: flex;
|
||||
}
|
||||
.testbla {
|
||||
position: absolute;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
background-color: var(--color-based-blue);
|
||||
user-select: none;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
right: 50%;
|
||||
border-radius: 25px;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
position: absolute;
|
||||
height: 25px;
|
||||
width: 25px;
|
||||
background-color: var(--color-based-blue);
|
||||
user-select: none;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
right: 50%;
|
||||
border-radius: 25px;
|
||||
pointer-events: none;
|
||||
z-index: 10;
|
||||
}
|
||||
.disabled-slider {
|
||||
width: 60px;
|
||||
height: 7px;
|
||||
background-color: var(--color-border-main);
|
||||
/* margin-top: auto; */
|
||||
align-self: center;
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
width: 60px;
|
||||
height: 7px;
|
||||
background-color: var(--color-border-main);
|
||||
/* margin-top: auto; */
|
||||
align-self: center;
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
z-index: 3;
|
||||
pointer-events: none;
|
||||
}
|
||||
.dot {
|
||||
border-radius: 50px;
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
background-color: var(--color-border-main);
|
||||
position: absolute;
|
||||
right: -14px;
|
||||
/* bottom: 50%; */
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
border-radius: 50px;
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
background-color: var(--color-border-main);
|
||||
position: absolute;
|
||||
right: -14px;
|
||||
/* bottom: 50%; */
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
pointer-events: none;
|
||||
}
|
||||
// Base Colors
|
||||
$shade-10: #4682b4 !default;
|
||||
|
|
@ -164,96 +174,96 @@ $range-label-color: $shade-10 !default;
|
|||
$range-label-width: 60px !default;
|
||||
|
||||
.range-slider {
|
||||
width: $range-width;
|
||||
position: relative;
|
||||
accent-color: #7550AE;
|
||||
width: $range-width;
|
||||
position: relative;
|
||||
accent-color: #7550ae;
|
||||
}
|
||||
|
||||
.range-slider__range {
|
||||
// width: calc(100% - (#{$range-label-width + 13px}));
|
||||
width: 100%;
|
||||
height: $range-track-height;
|
||||
border-radius: 5px;
|
||||
background: $range-track-color;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
// width: calc(100% - (#{$range-label-width + 13px}));
|
||||
width: 100%;
|
||||
height: $range-track-height;
|
||||
border-radius: 5px;
|
||||
background: $range-track-color;
|
||||
outline: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
// Range Handle
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
opacity: 0;
|
||||
padding: 5px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
// Range Handle
|
||||
&::-webkit-slider-thumb {
|
||||
appearance: none;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
opacity: 0;
|
||||
padding: 5px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&:active::-webkit-slider-thumb {
|
||||
background: $range-handle-color-hover;
|
||||
}
|
||||
&:active::-webkit-slider-thumb {
|
||||
background: $range-handle-color-hover;
|
||||
}
|
||||
|
||||
&::-moz-range-thumb {
|
||||
width: $range-handle-size;
|
||||
height: $range-handle-size;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
background: $range-handle-color;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease-in-out;
|
||||
&::-moz-range-thumb {
|
||||
width: $range-handle-size;
|
||||
height: $range-handle-size;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
background: $range-handle-color;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background: $range-handle-color-hover;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background: $range-handle-color-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&:active::-moz-range-thumb {
|
||||
background: $range-handle-color-hover;
|
||||
}
|
||||
&:active::-moz-range-thumb {
|
||||
background: $range-handle-color-hover;
|
||||
}
|
||||
|
||||
// Focus state
|
||||
&:focus {
|
||||
&::-webkit-slider-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
// Focus state
|
||||
&:focus {
|
||||
&::-webkit-slider-thumb {
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Range Label
|
||||
.range-slider__value {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: $range-label-width;
|
||||
color: $shade-0;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
background: $range-label-color;
|
||||
padding: 5px 10px;
|
||||
margin-left: 8px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: $range-label-width;
|
||||
color: $shade-0;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
border-radius: 3px;
|
||||
background: $range-label-color;
|
||||
padding: 5px 10px;
|
||||
margin-left: 8px;
|
||||
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: -7px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 7px solid transparent;
|
||||
border-right: 7px solid $range-label-color;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: "";
|
||||
}
|
||||
&:after {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: -7px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 7px solid transparent;
|
||||
border-right: 7px solid $range-label-color;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: '';
|
||||
}
|
||||
}
|
||||
|
||||
// Firefox Overrides
|
||||
::-moz-range-track {
|
||||
background: $range-track-color;
|
||||
border: 0;
|
||||
background: $range-track-color;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
input::-moz-focus-inner,
|
||||
input::-moz-focus-outer {
|
||||
border: 0;
|
||||
border: 0;
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="f-tag">
|
||||
<slot></slot>
|
||||
</div>
|
||||
<div class="f-tag">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
|||
|
|
@ -1,34 +1,41 @@
|
|||
<template>
|
||||
<section v-show="value === props.name" ref="tab" role="tabpanel" tabindex="-1">
|
||||
<slot></slot>
|
||||
</section>
|
||||
<section v-show="value === props.name" ref="tab" role="tabpanel" tabindex="-1">
|
||||
<slot></slot>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, onBeforeMount, getCurrentInstance, ref, computed, watch, inject } from "vue";
|
||||
const instance = ref<any>();
|
||||
import { onMounted, onBeforeMount, getCurrentInstance, ref, watch, inject, type ComponentInternalInstance } from 'vue';
|
||||
|
||||
const isActive = ref<any>(null);
|
||||
interface Tab {
|
||||
uid: number;
|
||||
name: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
const value = inject("value");
|
||||
var updateTab: any = inject("updateTab");
|
||||
const instance = ref<ComponentInternalInstance | null>();
|
||||
|
||||
const isActive = ref<unknown>(null);
|
||||
|
||||
const value = inject('value');
|
||||
const updateTab: (tab: Tab) => void = inject('updateTab') as (tab: Tab) => void;
|
||||
|
||||
defineExpose({
|
||||
isActive,
|
||||
isActive,
|
||||
});
|
||||
|
||||
onBeforeMount(() => {});
|
||||
onMounted(() => {
|
||||
instance.value = getCurrentInstance();
|
||||
instance.value = getCurrentInstance();
|
||||
|
||||
var addTab: any = inject("addTab");
|
||||
addTab({
|
||||
uid: instance.value!.uid,
|
||||
name: props.name,
|
||||
label: props.label,
|
||||
});
|
||||
const addTab = inject('addTab') as (tab: Tab) => void;
|
||||
addTab({
|
||||
uid: instance.value?.uid ?? 0,
|
||||
name: props.name,
|
||||
label: props.label,
|
||||
});
|
||||
|
||||
// resolved = {"test123": 123, "blub": "abc"}
|
||||
// resolved = {"test123": 123, "blub": "abc"}
|
||||
});
|
||||
|
||||
// const test = computed(() => {
|
||||
|
|
@ -38,27 +45,20 @@ onMounted(() => {
|
|||
// })
|
||||
|
||||
//Props
|
||||
const props = defineProps({
|
||||
label: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: null,
|
||||
},
|
||||
name: {
|
||||
type: [String],
|
||||
required: true,
|
||||
default: null,
|
||||
},
|
||||
});
|
||||
interface Props {
|
||||
label: string;
|
||||
name: string;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
|
||||
watch(props, (newValue, oldValue) => {
|
||||
console.log("newValue", newValue);
|
||||
console.log("instance", instance.value);
|
||||
watch(props, (_newValue, _oldValue) => {
|
||||
// console.log("newValue", newValue);
|
||||
// console.log("instance", instance.value);
|
||||
|
||||
updateTab({
|
||||
uid: instance.value!.uid,
|
||||
name: props.name,
|
||||
label: props.label,
|
||||
});
|
||||
updateTab({
|
||||
uid: instance.value?.uid ?? 0,
|
||||
name: props.name,
|
||||
label: props.label,
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,89 +1,96 @@
|
|||
<template>
|
||||
<div class="f-tabs" ref="tabsRef">
|
||||
<div class="f-tabs__header" ref="headerRef">
|
||||
<div
|
||||
class="f-tab"
|
||||
ref="tabsRef1"
|
||||
:id="`f-tab-${tab.uid}`"
|
||||
v-for="tab in tabs"
|
||||
:key="tab.uid"
|
||||
@click="setActive(tab)"
|
||||
>
|
||||
<h5>{{ tab.label }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-tabs__content">
|
||||
<slot ref="tabsTest"></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-tabs" ref="tabsRef">
|
||||
<div class="f-tabs__header" ref="headerRef">
|
||||
<div class="f-tab" ref="tabsRef1" :id="`f-tab-${tab.uid}`" v-for="tab in tabs" :key="tab.uid" @click="setActive(tab)">
|
||||
<h5>{{ tab.label }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="f-tabs__content">
|
||||
<slot ref="tabsTest"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, nextTick, h, computed, useSlots, provide, getCurrentInstance } from "vue";
|
||||
import { ref, onMounted, nextTick, useSlots, provide, withDefaults } from 'vue';
|
||||
|
||||
interface Tab {
|
||||
uid: number;
|
||||
name: string;
|
||||
label: string;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
inheritAttrs: false,
|
||||
});
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
interface Props {
|
||||
modelValue?: string | null;
|
||||
}
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
modelValue: null,
|
||||
});
|
||||
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: string): void;
|
||||
}
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const slots1 = useSlots();
|
||||
const _slots1 = useSlots();
|
||||
|
||||
const tabsRef = ref<HTMLElement>();
|
||||
const tabsRef1 = ref<HTMLElement>();
|
||||
const headerRef = ref<HTMLElement>();
|
||||
const tabsArray = ref<Array<HTMLElement>>();
|
||||
const tabsComponents = ref<Array<any>>();
|
||||
const content = ref<any>();
|
||||
const target = ref<any>();
|
||||
const slots = ref<any>();
|
||||
const value = ref<any>();
|
||||
const tabsTest = ref<any>();
|
||||
const tabs = ref<Array<any>>([]);
|
||||
provide("value", value);
|
||||
provide("addTab", (tab: any) => {
|
||||
tabs.value.push(tab);
|
||||
const _tabsArray = ref<Array<HTMLElement>>();
|
||||
const _tabsComponents = ref<Array<unknown>>();
|
||||
const _content = ref<unknown>();
|
||||
const _target = ref<unknown>();
|
||||
const _slots = ref<unknown>();
|
||||
const value = ref<unknown>();
|
||||
const tabsTest = ref<unknown>();
|
||||
const tabs = ref<Array<Tab>>([]);
|
||||
provide('value', value);
|
||||
provide('addTab', (tab: Tab) => {
|
||||
tabs.value.push(tab);
|
||||
});
|
||||
|
||||
provide("updateTab", (tab: any) => {
|
||||
let changedTabIndex = tabs.value.findIndex((obj) => obj.uid === tab.uid);
|
||||
if (changedTabIndex > -1) {
|
||||
tabs.value[changedTabIndex] = tab;
|
||||
}
|
||||
provide('updateTab', (tab: Tab) => {
|
||||
const changedTabIndex = tabs.value.findIndex(obj => obj.uid === tab.uid);
|
||||
if (changedTabIndex > -1) {
|
||||
tabs.value[changedTabIndex] = tab;
|
||||
}
|
||||
});
|
||||
// provide('addTab', tabs.value)
|
||||
|
||||
onMounted(() => {
|
||||
nextTick(() => {
|
||||
if(props.modelValue){
|
||||
const tab = tabs.value.find((obj) => obj.name === props.modelValue)
|
||||
setActive(tab);
|
||||
|
||||
} else {
|
||||
setActive(tabs.value[0]);
|
||||
}
|
||||
});
|
||||
nextTick(() => {
|
||||
if (props.modelValue) {
|
||||
const tab = tabs.value.find(obj => obj.name === props.modelValue);
|
||||
if (tab) {
|
||||
setActive(tab);
|
||||
}
|
||||
} else {
|
||||
const firstTab = tabs.value[0];
|
||||
if (firstTab) {
|
||||
setActive(firstTab);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function setActive(tab: any) {
|
||||
function setActive(tab: Tab) {
|
||||
nextTick(() => {
|
||||
const tabElement = headerRef.value?.querySelector(`#f-tab-${tab.uid}`) as HTMLElement | null;
|
||||
const array = Array.prototype.slice.call(tabsRef.value?.children[0].children);
|
||||
|
||||
nextTick(() => {
|
||||
const tabElement: any = headerRef.value?.querySelector(`#f-tab-${tab.uid}`);
|
||||
var array = Array.prototype.slice.call(tabsRef.value?.children[0].children);
|
||||
|
||||
array.forEach((element: HTMLElement) => {
|
||||
element.classList.remove("f-tab--active");
|
||||
});
|
||||
tabElement.classList.add("f-tab--active");
|
||||
value.value = tab.name;
|
||||
emit("update:modelValue", tab.name);
|
||||
});
|
||||
array.forEach((element: HTMLElement) => {
|
||||
element.classList.remove('f-tab--active');
|
||||
});
|
||||
if (tabElement) {
|
||||
tabElement.classList.add('f-tab--active');
|
||||
}
|
||||
value.value = tab.name;
|
||||
emit('update:modelValue', tab.name);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -41,10 +41,9 @@ describe('FTabs.vue', () => {
|
|||
await wrapper.vm.$nextTick();
|
||||
|
||||
const sections = wrapper.findAll('section');
|
||||
|
||||
expect(sections[0].attributes('style')).not.toContain('display: none');
|
||||
|
||||
expect(sections[0].attributes('style')).not.toContain('display: none');
|
||||
expect(sections[1].attributes('style')).toContain('display: none');
|
||||
|
||||
});
|
||||
|
||||
it('switches to the correct tab on click', async () => {
|
||||
|
|
@ -66,7 +65,7 @@ describe('FTabs.vue', () => {
|
|||
await tabs[1].trigger('click');
|
||||
|
||||
const sections = wrapper.findAll('section');
|
||||
expect(sections[0].attributes('style')).toContain('display: none');
|
||||
expect(sections[0].attributes('style')).toContain('display: none');
|
||||
expect(sections[1].attributes('style')).not.toContain('display: none');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,29 +1,30 @@
|
|||
<template>
|
||||
<svg width="23" height="18" viewBox="0 0 23 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2590_494)">
|
||||
<path
|
||||
ref="svgPath"
|
||||
d="M19.419 3.40166C16.7691 1.45664 14.2483 1.51053 14.2483 1.51053L13.9906 1.79865C17.1188 2.73512 18.5723 4.08593 18.5723 4.08593C16.6585 3.05941 14.7817 2.55501 13.0336 2.35694C11.7088 2.21276 10.4391 2.24892 9.3167 2.39287C9.20634 2.39287 9.11433 2.41083 9.00397 2.42879C8.35994 2.48292 6.79584 2.71692 4.82702 3.56357C4.14628 3.86966 3.74131 4.08593 3.74131 4.08593C3.74131 4.08593 5.2687 2.66303 8.58065 1.72656L8.39664 1.51053C8.39664 1.51053 5.87579 1.4564 3.22598 3.40166C3.22598 3.40166 0.576172 8.10242 0.576172 13.9018C0.576172 13.9018 2.12191 16.5134 6.18851 16.6393C6.18851 16.6393 6.86925 15.8289 7.42129 15.1446C5.08444 14.4601 4.20109 13.0195 4.20109 13.0195C4.20109 13.0195 4.3851 13.1454 4.71642 13.3256C4.73477 13.3435 4.75313 13.3615 4.79007 13.3797C4.84537 13.4156 4.90043 13.4338 4.95573 13.4697C5.41576 13.7219 5.87579 13.92 6.29911 14.0821C7.05351 14.3703 7.95521 14.6584 9.00397 14.8565C10.3841 15.1087 12.0032 15.1987 13.7697 14.8744C14.6344 14.7303 15.5178 14.4783 16.4378 14.0999C17.0819 13.8656 17.7996 13.5236 18.554 13.0372C18.554 13.0372 17.6339 14.514 15.2234 15.1805C15.7754 15.865 16.4378 16.6393 16.4378 16.6393C20.5047 16.5131 22.0688 13.9018 22.0688 13.9018C22.0688 8.10242 19.419 3.40166 19.419 3.40166ZM7.8818 12.2267C6.85138 12.2267 6.00498 11.3262 6.00498 10.2276C6.00498 9.12894 6.83303 8.22841 7.8818 8.22841C8.93056 8.22841 9.77697 9.12894 9.75861 10.2276C9.75861 11.3262 8.93056 12.2267 7.8818 12.2267ZM14.598 12.2267C13.5675 12.2267 12.7211 11.3262 12.7211 10.2276C12.7211 9.12894 13.5492 8.22841 14.598 8.22841C15.6467 8.22841 16.4748 9.12894 16.4748 10.2276C16.4748 11.3262 15.647 12.2267 14.598 12.2267Z"
|
||||
:fill="props.color"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2590_494">
|
||||
<rect width="22" height="17" fill="white" transform="translate(0.333984 0.58667)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg width="23" height="18" viewBox="0 0 23 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2590_494)">
|
||||
<path
|
||||
ref="svgPath"
|
||||
d="M19.419 3.40166C16.7691 1.45664 14.2483 1.51053 14.2483 1.51053L13.9906 1.79865C17.1188 2.73512 18.5723 4.08593 18.5723 4.08593C16.6585 3.05941 14.7817 2.55501 13.0336 2.35694C11.7088 2.21276 10.4391 2.24892 9.3167 2.39287C9.20634 2.39287 9.11433 2.41083 9.00397 2.42879C8.35994 2.48292 6.79584 2.71692 4.82702 3.56357C4.14628 3.86966 3.74131 4.08593 3.74131 4.08593C3.74131 4.08593 5.2687 2.66303 8.58065 1.72656L8.39664 1.51053C8.39664 1.51053 5.87579 1.4564 3.22598 3.40166C3.22598 3.40166 0.576172 8.10242 0.576172 13.9018C0.576172 13.9018 2.12191 16.5134 6.18851 16.6393C6.18851 16.6393 6.86925 15.8289 7.42129 15.1446C5.08444 14.4601 4.20109 13.0195 4.20109 13.0195C4.20109 13.0195 4.3851 13.1454 4.71642 13.3256C4.73477 13.3435 4.75313 13.3615 4.79007 13.3797C4.84537 13.4156 4.90043 13.4338 4.95573 13.4697C5.41576 13.7219 5.87579 13.92 6.29911 14.0821C7.05351 14.3703 7.95521 14.6584 9.00397 14.8565C10.3841 15.1087 12.0032 15.1987 13.7697 14.8744C14.6344 14.7303 15.5178 14.4783 16.4378 14.0999C17.0819 13.8656 17.7996 13.5236 18.554 13.0372C18.554 13.0372 17.6339 14.514 15.2234 15.1805C15.7754 15.865 16.4378 16.6393 16.4378 16.6393C20.5047 16.5131 22.0688 13.9018 22.0688 13.9018C22.0688 8.10242 19.419 3.40166 19.419 3.40166ZM7.8818 12.2267C6.85138 12.2267 6.00498 11.3262 6.00498 10.2276C6.00498 9.12894 6.83303 8.22841 7.8818 8.22841C8.93056 8.22841 9.77697 9.12894 9.75861 10.2276C9.75861 11.3262 8.93056 12.2267 7.8818 12.2267ZM14.598 12.2267C13.5675 12.2267 12.7211 11.3262 12.7211 10.2276C12.7211 9.12894 13.5492 8.22841 14.598 8.22841C15.6467 8.22841 16.4748 9.12894 16.4748 10.2276C16.4748 11.3262 15.647 12.2267 14.598 12.2267Z"
|
||||
:fill="props.color"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2590_494">
|
||||
<rect width="22" height="17" fill="white" transform="translate(0.333984 0.58667)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { ref } from 'vue';
|
||||
|
||||
const svgPath = ref();
|
||||
|
||||
interface Props {
|
||||
color?: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'currentColor',
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. -->
|
||||
<path
|
||||
d="M96 0C43 0 0 43 0 96L0 416c0 53 43 96 96 96l288 0 32 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l0-64c17.7 0 32-14.3 32-32l0-320c0-17.7-14.3-32-32-32L384 0 96 0zm0 384l256 0 0 64L96 448c-17.7 0-32-14.3-32-32s14.3-32 32-32zm32-240c0-8.8 7.2-16 16-16l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16zm16 48l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16s7.2-16 16-16z"
|
||||
/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<!-- Font Awesome Free 6.6.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc. -->
|
||||
<path
|
||||
d="M96 0C43 0 0 43 0 96L0 416c0 53 43 96 96 96l288 0 32 0c17.7 0 32-14.3 32-32s-14.3-32-32-32l0-64c17.7 0 32-14.3 32-32l0-320c0-17.7-14.3-32-32-32L384 0 96 0zm0 384l256 0 0 64L96 448c-17.7 0-32-14.3-32-32s14.3-32 32-32zm32-240c0-8.8 7.2-16 16-16l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16zm16 48l192 0c8.8 0 16 7.2 16 16s-7.2 16-16 16l-192 0c-8.8 0-16-7.2-16-16s7.2-16 16-16z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
<path
|
||||
d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z"
|
||||
/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
<path
|
||||
d="M575.8 255.5c0 18-15 32.1-32 32.1h-32l.7 160.2c0 2.7-.2 5.4-.5 8.1V472c0 22.1-17.9 40-40 40H456c-1.1 0-2.2 0-3.3-.1c-1.4 .1-2.8 .1-4.2 .1H416 392c-22.1 0-40-17.9-40-40V448 384c0-17.7-14.3-32-32-32H256c-17.7 0-32 14.3-32 32v64 24c0 22.1-17.9 40-40 40H160 128.1c-1.5 0-3-.1-4.5-.2c-1.2 .1-2.4 .2-3.6 .2H104c-22.1 0-40-17.9-40-40V360c0-.9 0-1.9 .1-2.8V287.6H32c-18 0-32-14-32-32.1c0-9 3-17 10-24L266.4 8c7-7 15-8 22-8s15 2 21 7L564.8 231.5c8 7 12 15 11 24z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -1,42 +1,39 @@
|
|||
<template>
|
||||
<tippy v-if="slots.text" theme="my-theme" trigger="click">
|
||||
<div class="info-icon">
|
||||
<svg :width="props.size" :height="props.size" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.2 6.26416C6.2 5.84995 6.53579 5.51416 6.95 5.51416C7.36421 5.51416 7.7 5.84995 7.7 6.26416V9.76416C7.7 10.1784 7.36421 10.5142 6.95 10.5142C6.53579 10.5142 6.2 10.1784 6.2 9.76416V6.26416Z"
|
||||
/>
|
||||
<path
|
||||
d="M7 3.01416C7.55228 3.01416 8 3.46188 8 4.01416C8 4.56644 7.55228 5.01416 7 5.01416C6.44772 5.01416 6 4.56644 6 4.01416C6 3.46188 6.44772 3.01416 7 3.01416Z"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M14 7.01416C14 10.8802 10.866 14.0142 7 14.0142C3.13401 14.0142 0 10.8802 0 7.01416C0 3.14817 3.13401 0.0141602 7 0.0141602C10.866 0.0141602 14 3.14817 14 7.01416ZM1.5 7.01416C1.5 10.0517 3.96243 12.5142 7 12.5142C10.0376 12.5142 12.5 10.0517 12.5 7.01416C12.5 3.97659 10.0376 1.51416 7 1.51416C3.96243 1.51416 1.5 3.97659 1.5 7.01416Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<template #content>
|
||||
<slot name="text"></slot>
|
||||
|
||||
</template>
|
||||
</tippy>
|
||||
<Tippy v-if="slots.text" theme="my-theme" trigger="click">
|
||||
<div class="info-icon">
|
||||
<svg :width="props.size" :height="props.size" viewBox="0 0 14 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M6.2 6.26416C6.2 5.84995 6.53579 5.51416 6.95 5.51416C7.36421 5.51416 7.7 5.84995 7.7 6.26416V9.76416C7.7 10.1784 7.36421 10.5142 6.95 10.5142C6.53579 10.5142 6.2 10.1784 6.2 9.76416V6.26416Z"
|
||||
/>
|
||||
<path
|
||||
d="M7 3.01416C7.55228 3.01416 8 3.46188 8 4.01416C8 4.56644 7.55228 5.01416 7 5.01416C6.44772 5.01416 6 4.56644 6 4.01416C6 3.46188 6.44772 3.01416 7 3.01416Z"
|
||||
/>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M14 7.01416C14 10.8802 10.866 14.0142 7 14.0142C3.13401 14.0142 0 10.8802 0 7.01416C0 3.14817 3.13401 0.0141602 7 0.0141602C10.866 0.0141602 14 3.14817 14 7.01416ZM1.5 7.01416C1.5 10.0517 3.96243 12.5142 7 12.5142C10.0376 12.5142 12.5 10.0517 12.5 7.01416C12.5 3.97659 10.0376 1.51416 7 1.51416C3.96243 1.51416 1.5 3.97659 1.5 7.01416Z"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<template #content>
|
||||
<slot name="text"></slot>
|
||||
</template>
|
||||
</Tippy>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useSlots, ref, onMounted } from "vue";
|
||||
import { Tippy } from "vue-tippy";
|
||||
import "tippy.js/dist/tippy.css"; // optional for styling
|
||||
import { useSlots } from 'vue';
|
||||
import { Tippy } from 'vue-tippy';
|
||||
import 'tippy.js/dist/tippy.css'; // optional for styling
|
||||
const slots = useSlots();
|
||||
|
||||
interface Props {
|
||||
size?: string;
|
||||
size?: string;
|
||||
}
|
||||
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
size: "15px",
|
||||
size: '15px',
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
@ -49,8 +46,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
fill: var(--color-font)
|
||||
.tippy-arrow
|
||||
color: rgba(15, 15, 15, 0.9) !important
|
||||
.tippy-box[data-theme~='my-theme']
|
||||
background-color: rgba(15, 15, 15, 0.9)
|
||||
.tippy-box[data-theme~='my-theme']
|
||||
background-color: rgba(15, 15, 15, 0.9)
|
||||
height: fit-content
|
||||
color: white
|
||||
font-size: 12px
|
||||
|
|
@ -58,5 +55,4 @@ const props = withDefaults(defineProps<Props>(), {
|
|||
border-radius: var(--border-radius)
|
||||
// @media (min-width: 768px)
|
||||
// max-width: 400px
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="login-icon" viewBox="0 0 512 512">
|
||||
<path
|
||||
d="M352 96l64 0c17.7 0 32 14.3 32 32l0 256c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0c53 0 96-43 96-96l0-256c0-53-43-96-96-96l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32zm-9.4 182.6c12.5-12.5 12.5-32.8 0-45.3l-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L242.7 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l210.7 0-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l128-128z"
|
||||
/>
|
||||
</svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="login-icon" viewBox="0 0 512 512">
|
||||
<path
|
||||
d="M352 96l64 0c17.7 0 32 14.3 32 32l0 256c0 17.7-14.3 32-32 32l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32l64 0c53 0 96-43 96-96l0-256c0-53-43-96-96-96l-64 0c-17.7 0-32 14.3-32 32s14.3 32 32 32zm-9.4 182.6c12.5-12.5 12.5-32.8 0-45.3l-128-128c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L242.7 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l210.7 0-73.4 73.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l128-128z"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
|||
|
|
@ -1,33 +1,34 @@
|
|||
<template>
|
||||
<svg width="20" height="16" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2590_499)">
|
||||
<path
|
||||
ref="svgPath"
|
||||
d="M17.058 0.932576L1.74462 6.83727C0.699293 7.25659 0.705631 7.83977 1.55407 8.09947L5.48317 9.32593L6.83449 13.7733C7.01217 14.2637 6.92458 14.4583 7.43975 14.4583C7.83718 14.4583 8.01274 14.2765 8.2346 14.0608L10.1441 12.2041L14.1166 15.1392C14.8477 15.5426 15.3754 15.3336 15.5575 14.4606L18.1654 2.17133C18.4324 1.10065 17.7574 0.615059 17.058 0.932576Z"
|
||||
:fill="props.color"
|
||||
/>
|
||||
<path
|
||||
d="M7.45616 13.2757L6.16016 9.01067L16.1361 3.09253L8.76406 10.3509L7.45616 13.2757Z"
|
||||
:fill="(props.color === 'black' ? 'white' : 'black')"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2590_499">
|
||||
<rect width="18.125" height="14.5" fill="white" transform="translate(0.9375 0.83667)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
<svg width="20" height="16" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_2590_499)">
|
||||
<path
|
||||
ref="svgPath"
|
||||
d="M17.058 0.932576L1.74462 6.83727C0.699293 7.25659 0.705631 7.83977 1.55407 8.09947L5.48317 9.32593L6.83449 13.7733C7.01217 14.2637 6.92458 14.4583 7.43975 14.4583C7.83718 14.4583 8.01274 14.2765 8.2346 14.0608L10.1441 12.2041L14.1166 15.1392C14.8477 15.5426 15.3754 15.3336 15.5575 14.4606L18.1654 2.17133C18.4324 1.10065 17.7574 0.615059 17.058 0.932576Z"
|
||||
:fill="props.color"
|
||||
/>
|
||||
<path
|
||||
d="M7.45616 13.2757L6.16016 9.01067L16.1361 3.09253L8.76406 10.3509L7.45616 13.2757Z"
|
||||
:fill="props.color === 'black' ? 'white' : 'black'"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_2590_499">
|
||||
<rect width="18.125" height="14.5" fill="white" transform="translate(0.9375 0.83667)" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { ref } from 'vue';
|
||||
|
||||
const svgPath = ref();
|
||||
|
||||
interface Props {
|
||||
color?: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'currentColor',
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,30 +1,31 @@
|
|||
<template>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="20px"
|
||||
height="18px"
|
||||
viewBox="0 0 19 18"
|
||||
version="1.1"
|
||||
>
|
||||
<g id="surface1">
|
||||
<path
|
||||
ref="svgPath"
|
||||
d="M 14.945312 0 L 17.859375 0 L 11.464844 7.636719 L 18.9375 18 L 13.070312 18 L 8.480469 11.703125 L 3.222656 18 L 0.308594 18 L 7.085938 9.832031 L -0.0703125 0 L 5.941406 0 L 10.089844 5.753906 Z M 13.925781 16.207031 L 15.542969 16.207031 L 5.09375 1.726562 L 3.355469 1.726562 Z M 13.925781 16.207031 "
|
||||
:fill="props.color"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="20px"
|
||||
height="18px"
|
||||
viewBox="0 0 19 18"
|
||||
version="1.1"
|
||||
>
|
||||
<g id="surface1">
|
||||
<path
|
||||
ref="svgPath"
|
||||
d="M 14.945312 0 L 17.859375 0 L 11.464844 7.636719 L 18.9375 18 L 13.070312 18 L 8.480469 11.703125 L 3.222656 18 L 0.308594 18 L 7.085938 9.832031 L -0.0703125 0 L 5.941406 0 L 10.089844 5.753906 Z M 13.925781 16.207031 L 15.542969 16.207031 L 5.09375 1.726562 L 3.355469 1.726562 Z M 13.925781 16.207031 "
|
||||
:fill="props.color"
|
||||
/>
|
||||
</g>
|
||||
</svg>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import { ref } from 'vue';
|
||||
|
||||
const svgPath = ref();
|
||||
|
||||
interface Props {
|
||||
color?: string;
|
||||
color?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
color: 'currentColor',
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
<template>
|
||||
<template v-if="status === 'disconnected'">
|
||||
<f-button class="connect-button--disconnected">Connect</f-button>
|
||||
</template>
|
||||
<template v-else-if="status === 'connected'">
|
||||
<f-button class="connect-button connect-button--connected">
|
||||
<img :src="getBlocky(address!)" alt="avatar" />
|
||||
<div>{{ getAddressShortName(address!) }}</div>
|
||||
</f-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<f-button class="connect-button--loading">loading</f-button>
|
||||
</template>
|
||||
<template v-if="status === 'disconnected'">
|
||||
<FButton class="connect-button--disconnected">Connect</FButton>
|
||||
</template>
|
||||
<template v-else-if="status === 'connected'">
|
||||
<FButton class="connect-button connect-button--connected">
|
||||
<img :src="getBlocky(address!)" alt="avatar" />
|
||||
<div>{{ getAddressShortName(address!) }}</div>
|
||||
</FButton>
|
||||
</template>
|
||||
<template v-else>
|
||||
<FButton class="connect-button--loading">loading</FButton>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import FButton from "@/components/fcomponents/FButton.vue";
|
||||
import { getAddressShortName } from "@/utils/helper";
|
||||
import { useAccount } from "@wagmi/vue";
|
||||
import { getBlocky } from "@/utils/blockies";
|
||||
import FButton from '@/components/fcomponents/FButton.vue';
|
||||
import { getAddressShortName } from '@/utils/helper';
|
||||
import { useAccount } from '@wagmi/vue';
|
||||
import { getBlocky } from '@/utils/blockies';
|
||||
|
||||
const { address, status } = useAccount();
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,113 +1,103 @@
|
|||
<template>
|
||||
<div class="connect-wallet-wrapper">
|
||||
<template v-if="status === 'connected'">
|
||||
<div class="connected-header">
|
||||
<div class="connected-header-avatar">
|
||||
<img :src="getBlocky(address!)" alt="avatar" />
|
||||
</div>
|
||||
<div class="connected-header-address" :title="address">
|
||||
{{ getAddressShortName(address!) }}
|
||||
</div>
|
||||
<div class="connected-header-logout" @click="() => disconnect()">
|
||||
<img src="@/assets/logout.svg" alt="Logout" />
|
||||
</div>
|
||||
</div>
|
||||
<h6 class="connected-tokens-headline">Your Tokens</h6>
|
||||
<div class="connected-tokens">
|
||||
<f-output name="$KRK" :price="harbAmount" :variant="3">
|
||||
<template #end>
|
||||
<f-button size="small" dense
|
||||
><a :href="chain.chainData?.uniswap" target="_blank">Buy</a></f-button
|
||||
>
|
||||
</template>
|
||||
</f-output>
|
||||
<f-output name="Staked $KRK" :price="compactNumber(stakedAmount)" :variant="3">
|
||||
<template #end>
|
||||
<f-button size="small" dense @click="stakeLink">Stake</f-button>
|
||||
</template>
|
||||
</f-output>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="status === 'disconnected'">
|
||||
<h6 class="connect-wallet-headline low-mid-text">Connect your wallet</h6>
|
||||
<div class="connectors-wrapper">
|
||||
<div
|
||||
class="connectors-element card"
|
||||
:class="[[connector.id]]"
|
||||
v-for="connector in connectors"
|
||||
:key="connector.id"
|
||||
@click="connectWallet(connector, chainId)"
|
||||
>
|
||||
<div class="connector-icon">
|
||||
<img :src="loadConnectorImage(connector)" :alt="`${connector.name} Logo`" />
|
||||
</div>
|
||||
<div class="connector-name">
|
||||
{{ connector.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>Are you coming from Binance, Bybit, Kucoin or any other crypto exchange?</div>
|
||||
<div><u>Follow these instructions first.</u></div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div>loading</div>
|
||||
</template>
|
||||
</div>
|
||||
<div class="connect-wallet-wrapper">
|
||||
<template v-if="status === 'connected'">
|
||||
<div class="connected-header">
|
||||
<div class="connected-header-avatar">
|
||||
<img :src="getBlocky(address!)" alt="avatar" />
|
||||
</div>
|
||||
<div class="connected-header-address" :title="address">
|
||||
{{ getAddressShortName(address!) }}
|
||||
</div>
|
||||
<div class="connected-header-logout" @click="() => disconnect()">
|
||||
<img src="@/assets/logout.svg" alt="Logout" />
|
||||
</div>
|
||||
</div>
|
||||
<h6 class="connected-tokens-headline">Your Tokens</h6>
|
||||
<div class="connected-tokens">
|
||||
<FOutput name="$KRK" :price="harbAmount" :variant="3">
|
||||
<template #end>
|
||||
<FButton size="small" dense><a :href="chain.chainData?.uniswap" target="_blank">Buy</a></FButton>
|
||||
</template>
|
||||
</FOutput>
|
||||
<FOutput name="Staked $KRK" :price="compactNumber(stakedAmount)" :variant="3">
|
||||
<template #end>
|
||||
<FButton size="small" dense @click="stakeLink">Stake</FButton>
|
||||
</template>
|
||||
</FOutput>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="status === 'disconnected'">
|
||||
<h6 class="connect-wallet-headline low-mid-text">Connect your wallet</h6>
|
||||
<div class="connectors-wrapper">
|
||||
<div
|
||||
class="connectors-element card"
|
||||
:class="[[connector.id]]"
|
||||
v-for="connector in connectors"
|
||||
:key="connector.id"
|
||||
@click="connectWallet(connector, chainId)"
|
||||
>
|
||||
<div class="connector-icon">
|
||||
<img :src="loadConnectorImage(connector)" :alt="`${connector.name} Logo`" />
|
||||
</div>
|
||||
<div class="connector-name">
|
||||
{{ connector.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>Are you coming from Binance, Bybit, Kucoin or any other crypto exchange?</div>
|
||||
<div><u>Follow these instructions first.</u></div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div>loading</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getCurrentInstance, computed } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { getAddressShortName, compactNumber, formatBigIntDivision } from "@/utils/helper";
|
||||
import { getBlocky } from "@/utils/blockies";
|
||||
import FButton from "@/components/fcomponents/FButton.vue";
|
||||
import FOutput from "@/components/fcomponents/FOutput.vue";
|
||||
import { getCurrentInstance, computed } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { getAddressShortName, compactNumber, formatBigIntDivision } from '@/utils/helper';
|
||||
import { getBlocky } from '@/utils/blockies';
|
||||
import FButton from '@/components/fcomponents/FButton.vue';
|
||||
import FOutput from '@/components/fcomponents/FOutput.vue';
|
||||
|
||||
// import { usePositions } from "@/composables/usePositions";
|
||||
// import { useWallet } from "@/composables/useWallet";
|
||||
import { usePositions } from "@/composables/usePositions";
|
||||
import { useWallet } from "@/composables/useWallet";
|
||||
import { useChain } from "@/composables/useChain";
|
||||
import { usePositions } from '@/composables/usePositions';
|
||||
import { useWallet } from '@/composables/useWallet';
|
||||
import { useChain } from '@/composables/useChain';
|
||||
|
||||
import {
|
||||
useAccount,
|
||||
useDisconnect,
|
||||
useConnect,
|
||||
useChainId,
|
||||
useBalance,
|
||||
type CreateConnectorFn,
|
||||
type Connector,
|
||||
} from "@wagmi/vue";
|
||||
import { useAccount, useDisconnect, useConnect, useChainId, type CreateConnectorFn, type Connector } from '@wagmi/vue';
|
||||
|
||||
const { address, status } = useAccount();
|
||||
const { disconnect } = useDisconnect();
|
||||
const { connectors, connect, error } = useConnect();
|
||||
const { connectors, connect } = useConnect();
|
||||
const router = useRouter();
|
||||
const chainId = useChainId();
|
||||
const { myActivePositions } = usePositions();
|
||||
const wallet = useWallet();
|
||||
const chain = useChain();
|
||||
function loadConnectorImage(connector: Connector) {
|
||||
if (connector.icon) {
|
||||
return connector.icon;
|
||||
} else {
|
||||
return `./img/connectors/${connector.name}.svg`;
|
||||
}
|
||||
if (connector.icon) {
|
||||
return connector.icon;
|
||||
} else {
|
||||
return `./img/connectors/${connector.name}.svg`;
|
||||
}
|
||||
}
|
||||
// const goerliKey = import.meta.env.VITE_GOERLI_KEY;
|
||||
|
||||
const harbAmount = computed(() => {
|
||||
if (wallet.balance?.value) {
|
||||
return compactNumber(formatBigIntDivision(wallet.balance?.value, 10n ** BigInt(wallet.balance.decimals)));
|
||||
} else {
|
||||
return "0";
|
||||
}
|
||||
if (wallet.balance?.value) {
|
||||
return compactNumber(formatBigIntDivision(wallet.balance?.value, 10n ** BigInt(wallet.balance.decimals)));
|
||||
} else {
|
||||
return '0';
|
||||
}
|
||||
});
|
||||
|
||||
const stakedAmount = computed(() =>
|
||||
myActivePositions.value.reduce(function (a, b) {
|
||||
return a + b.amount;
|
||||
}, 0)
|
||||
myActivePositions.value.reduce(function (a, b) {
|
||||
return a + b.amount;
|
||||
}, 0)
|
||||
);
|
||||
|
||||
const instance = getCurrentInstance();
|
||||
|
|
@ -142,20 +132,20 @@ const instance = getCurrentInstance();
|
|||
// }
|
||||
|
||||
function closeModal() {
|
||||
instance!.parent!.emit("update:modelValue", false);
|
||||
instance!.parent!.emit('update:modelValue', false);
|
||||
}
|
||||
|
||||
// //special case for metaMask, but I think that is the most used wallet
|
||||
async function connectWallet(connector: CreateConnectorFn | Connector, chainId: any) {
|
||||
console.log("connector", connector);
|
||||
console.log("connector", connector.name);
|
||||
connect({ connector, chainId });
|
||||
closeModal();
|
||||
async function connectWallet(connector: CreateConnectorFn | Connector, chainId: number) {
|
||||
// console.log("connector", connector);
|
||||
// console.log("connector", connector.name);
|
||||
connect({ connector, chainId });
|
||||
closeModal();
|
||||
}
|
||||
|
||||
function stakeLink() {
|
||||
router.push("/dashboard#stake");
|
||||
closeModal();
|
||||
router.push('/dashboard#stake');
|
||||
closeModal();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
<template>
|
||||
<div class="footer" :style="{ color: (props.dark) ? 'white': 'black' }">
|
||||
<div class="footer-inner">
|
||||
<div class="footer-headline subheader2">Follow HARBERG Protocol</div>
|
||||
<div class="social-links">
|
||||
<social-button :dark="props.dark" type="discord" :href="discord"></social-button>
|
||||
<social-button :dark="props.dark" type="telegram" :href="telegram"></social-button>
|
||||
<social-button :dark="props.dark" type="twitter" :href="twitter"></social-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer" :style="{ color: props.dark ? 'white' : 'black' }">
|
||||
<div class="footer-inner">
|
||||
<div class="footer-headline subheader2">Follow HARBERG Protocol</div>
|
||||
<div class="social-links">
|
||||
<SocialButton :dark="props.dark" type="discord" :href="discord"></SocialButton>
|
||||
<SocialButton :dark="props.dark" type="telegram" :href="telegram"></SocialButton>
|
||||
<SocialButton :dark="props.dark" type="twitter" :href="twitter"></SocialButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import socialButton from '@/components/socialButton.vue';
|
||||
import SocialButton from '@/components/SocialButton.vue';
|
||||
|
||||
interface Props {
|
||||
dark?: boolean;
|
||||
dark?: boolean;
|
||||
}
|
||||
|
||||
const discord = import.meta.env.VITE_DISCORD
|
||||
const discord = import.meta.env.VITE_DISCORD;
|
||||
const telegram = import.meta.env.VITE_TELEGRAM;
|
||||
const twitter = import.meta.env.VITE_TWITTER;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,69 +1,63 @@
|
|||
<template>
|
||||
<header>
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner navigation-font">
|
||||
<div class="navbar-left" @click="router.push('/')">
|
||||
<div class="navbar-title">
|
||||
<span>K</span>
|
||||
<span class="big-spacing">r</span>
|
||||
<span class="small-spacing">A</span>
|
||||
<span class="big-spacing">I</span>
|
||||
<span>ken</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navbar-center"></div>
|
||||
<div class="navbar-end">
|
||||
<nav v-if="!isMobile">
|
||||
<RouterLink v-for="navbarRoute in navbarRoutes" :key="navbarRoute.name" :to="navbarRoute.path">
|
||||
{{ navbarRoute.title }}
|
||||
</RouterLink>
|
||||
<a href="/#/docs">Docs</a>
|
||||
</nav>
|
||||
<template v-if="!isMobile">
|
||||
<div class="vertical-line"></div>
|
||||
<network-changer></network-changer>
|
||||
<div class="vertical-line"></div>
|
||||
</template>
|
||||
<connect-button @click="showPanel = true" v-if="!isMobile"></connect-button>
|
||||
<icon-login @click="showPanel = true" v-else-if="isMobile && !address"></icon-login>
|
||||
<img
|
||||
@click="showPanel = true"
|
||||
v-else-if="isMobile && address"
|
||||
:src="getBlocky(address)"
|
||||
alt="avatar"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<header>
|
||||
<div class="navbar">
|
||||
<div class="navbar-inner navigation-font">
|
||||
<div class="navbar-left" @click="router.push('/')">
|
||||
<div class="navbar-title">
|
||||
<span>K</span>
|
||||
<span class="big-spacing">r</span>
|
||||
<span class="small-spacing">A</span>
|
||||
<span class="big-spacing">I</span>
|
||||
<span>ken</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="navbar-center"></div>
|
||||
<div class="navbar-end">
|
||||
<nav v-if="!isMobile">
|
||||
<RouterLink v-for="navbarRoute in navbarRoutes" :key="navbarRoute.name" :to="navbarRoute.path">
|
||||
{{ navbarRoute.title }}
|
||||
</RouterLink>
|
||||
<a href="/#/docs">Docs</a>
|
||||
</nav>
|
||||
<template v-if="!isMobile">
|
||||
<div class="vertical-line"></div>
|
||||
<NetworkChanger></NetworkChanger>
|
||||
<div class="vertical-line"></div>
|
||||
</template>
|
||||
<ConnectButton @click="showPanel = true" v-if="!isMobile"></ConnectButton>
|
||||
<IconLogin @click="showPanel = true" v-else-if="isMobile && !address"></IconLogin>
|
||||
<img @click="showPanel = true" v-else-if="isMobile && address" :src="getBlocky(address)" alt="avatar" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { getBlocky } from "@/utils/blockies";
|
||||
import { RouterLink, useRouter } from "vue-router";
|
||||
import IconLogin from "@/components/icons/IconLogin.vue";
|
||||
import ThemeToggle from "@/components/layouts/ThemeToggle.vue";
|
||||
import NetworkChanger from "@/components/layouts/NetworkChanger.vue";
|
||||
import ConnectButton from "@/components/layouts/ConnectButton.vue";
|
||||
import { computed, inject, ref } from "vue";
|
||||
import { useAccount } from "@wagmi/vue";
|
||||
import { useDark } from "@/composables/useDark";
|
||||
const {darkTheme} = useDark();
|
||||
const {address} = useAccount();
|
||||
import { getBlocky } from '@/utils/blockies';
|
||||
import { RouterLink, useRouter } from 'vue-router';
|
||||
import IconLogin from '@/components/icons/IconLogin.vue';
|
||||
// import ThemeToggle from "@/components/layouts/ThemeToggle.vue";
|
||||
import NetworkChanger from '@/components/layouts/NetworkChanger.vue';
|
||||
import ConnectButton from '@/components/layouts/ConnectButton.vue';
|
||||
import { inject, ref } from 'vue';
|
||||
import { useAccount } from '@wagmi/vue';
|
||||
import { useDark } from '@/composables/useDark';
|
||||
const { darkTheme: _darkTheme } = useDark();
|
||||
const { address } = useAccount();
|
||||
const router = useRouter();
|
||||
|
||||
const showPanel = inject<boolean>('showPanel', false);
|
||||
const isMobile = inject<boolean>('isMobile', false);
|
||||
|
||||
const showPanel = inject<boolean>("showPanel", false);
|
||||
const isMobile = inject<boolean>("isMobile", false);
|
||||
|
||||
const dark1 = ref(false)
|
||||
const _dark1 = ref(false);
|
||||
const routes = router.getRoutes();
|
||||
const navbarRoutes = routes.flatMap((obj) => {
|
||||
if (obj.meta.group === "navbar") {
|
||||
return { title: obj.meta.title, name: obj.name, path: obj.path };
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
const navbarRoutes = routes.flatMap(obj => {
|
||||
if (obj.meta.group === 'navbar') {
|
||||
return { title: obj.meta.title, name: obj.name, path: obj.path };
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
@ -1,38 +1,38 @@
|
|||
<template>
|
||||
<div class="network-changer" v-click-outside="closeMenu">
|
||||
<div class="network-changer-inner" @click="showMenu = !showMenu">
|
||||
<icon-base></icon-base>
|
||||
<Icon v-if="showMenu" class="toggle-icon" icon="mdi:chevron-down"></Icon>
|
||||
<Icon v-else class="toggle-icon" icon="mdi:chevron-up"></Icon>
|
||||
</div>
|
||||
<Transition name="collapse-network">
|
||||
<div v-show="showMenu" class="network-changer--list">
|
||||
<div class="list-inner" ref="listInner">
|
||||
<div class="list--element" v-for="chain in chains" :key="chain.id">
|
||||
<template v-if="chain.id === wallet.account.chainId">
|
||||
<icon-base></icon-base>
|
||||
<div>{{ chain.name }}</div>
|
||||
<div>Connected</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<icon-base></icon-base>
|
||||
<div>{{ chain.name }}</div>
|
||||
<f-button outlined dense @click="switchNetwork(chain)">Switch Network</f-button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<div class="network-changer" v-click-outside="closeMenu">
|
||||
<div class="network-changer-inner" @click="showMenu = !showMenu">
|
||||
<IconBase></IconBase>
|
||||
<Icon v-if="showMenu" class="toggle-icon" icon="mdi:chevron-down"></Icon>
|
||||
<Icon v-else class="toggle-icon" icon="mdi:chevron-up"></Icon>
|
||||
</div>
|
||||
<Transition name="collapse-network">
|
||||
<div v-show="showMenu" class="network-changer--list">
|
||||
<div class="list-inner" ref="listInner">
|
||||
<div class="list--element" v-for="chain in chains" :key="chain.id">
|
||||
<template v-if="chain.id === wallet.account.chainId">
|
||||
<IconBase></IconBase>
|
||||
<div>{{ chain.name }}</div>
|
||||
<div>Connected</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<IconBase></IconBase>
|
||||
<div>{{ chain.name }}</div>
|
||||
<FButton outlined dense @click="switchNetwork(chain)">Switch Network</FButton>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import IconBase from "@/components/icons/IconBase.vue";
|
||||
import { ref } from "vue";
|
||||
import { useChains, useChainId, useSwitchChain } from "@wagmi/vue";
|
||||
import {Icon} from "@iconify/vue";
|
||||
import FButton from "@/components/fcomponents/FButton.vue";
|
||||
import { useWallet } from "@/composables/useWallet";
|
||||
import IconBase from '@/components/icons/IconBase.vue';
|
||||
import { ref } from 'vue';
|
||||
import { useChains, useSwitchChain } from '@wagmi/vue';
|
||||
import { Icon } from '@iconify/vue';
|
||||
import FButton from '@/components/fcomponents/FButton.vue';
|
||||
import { useWallet } from '@/composables/useWallet';
|
||||
const chains = useChains();
|
||||
const wallet = useWallet();
|
||||
const { switchChain } = useSwitchChain();
|
||||
|
|
@ -41,15 +41,14 @@ const showMenu = ref<boolean>(false);
|
|||
const listInner = ref();
|
||||
|
||||
function closeMenu() {
|
||||
if (showMenu.value) {
|
||||
console.log("tesat");
|
||||
showMenu.value = false;
|
||||
}
|
||||
if (showMenu.value) {
|
||||
// console.log("tesat");
|
||||
showMenu.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function switchNetwork(chain: any) {
|
||||
console.log("chain", chain);
|
||||
switchChain({ chainId: chain.id });
|
||||
async function switchNetwork(chain: { id: number }) {
|
||||
switchChain({ chainId: chain.id });
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +1,26 @@
|
|||
<template>
|
||||
<div class="slideout-overlay" :class="{ open: props.modelValue }" @click="showPanel = false"></div>
|
||||
<div :class="{ 'slideout-wrapper': true, open: props.modelValue }">
|
||||
<div class="slideout-panel">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slideout-overlay" :class="{ open: props.modelValue }" @click="showPanel = false"></div>
|
||||
<div :class="{ 'slideout-wrapper': true, open: props.modelValue }">
|
||||
<div class="slideout-panel">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { inject, watchEffect } from "vue";
|
||||
import { inject } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Boolean,
|
||||
});
|
||||
interface Props {
|
||||
modelValue?: boolean;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
|
||||
defineEmits(["update:modelValue"]);
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: boolean): void;
|
||||
}
|
||||
defineEmits<Emits>();
|
||||
|
||||
const showPanel = inject("showPanel");
|
||||
const showPanel = inject('showPanel');
|
||||
</script>
|
||||
|
||||
<style lang="sass">
|
||||
|
|
|
|||
|
|
@ -1,150 +1,85 @@
|
|||
<template>
|
||||
<div class="toggle-dark-light">
|
||||
<input type="checkbox" id="darkmode-toggle" @click="toggleTheme" :checked="props.modelValue" />
|
||||
<label for="darkmode-toggle">
|
||||
<svg
|
||||
version="1.1"
|
||||
class="sun"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 496 496"
|
||||
style="enable-background: new 0 0 496 496"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<rect
|
||||
x="152.994"
|
||||
y="58.921"
|
||||
transform="matrix(0.3827 0.9239 -0.9239 0.3827 168.6176 -118.5145)"
|
||||
width="40.001"
|
||||
height="16"
|
||||
/>
|
||||
<rect
|
||||
x="46.9"
|
||||
y="164.979"
|
||||
transform="matrix(0.9239 0.3827 -0.3827 0.9239 71.29 -12.4346)"
|
||||
width="40.001"
|
||||
height="16"
|
||||
/>
|
||||
<rect
|
||||
x="46.947"
|
||||
y="315.048"
|
||||
transform="matrix(0.9239 -0.3827 0.3827 0.9239 -118.531 50.2116)"
|
||||
width="40.001"
|
||||
height="16"
|
||||
/>
|
||||
<div class="toggle-dark-light">
|
||||
<input type="checkbox" id="darkmode-toggle" @click="toggleTheme" :checked="props.modelValue" />
|
||||
<label for="darkmode-toggle">
|
||||
<svg
|
||||
version="1.1"
|
||||
class="sun"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 496 496"
|
||||
style="enable-background: new 0 0 496 496"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<rect x="152.994" y="58.921" transform="matrix(0.3827 0.9239 -0.9239 0.3827 168.6176 -118.5145)" width="40.001" height="16" />
|
||||
<rect x="46.9" y="164.979" transform="matrix(0.9239 0.3827 -0.3827 0.9239 71.29 -12.4346)" width="40.001" height="16" />
|
||||
<rect x="46.947" y="315.048" transform="matrix(0.9239 -0.3827 0.3827 0.9239 -118.531 50.2116)" width="40.001" height="16" />
|
||||
|
||||
<rect
|
||||
x="164.966"
|
||||
y="409.112"
|
||||
transform="matrix(-0.9238 -0.3828 0.3828 -0.9238 168.4872 891.7491)"
|
||||
width="16"
|
||||
height="39.999"
|
||||
/>
|
||||
<rect x="164.966" y="409.112" transform="matrix(-0.9238 -0.3828 0.3828 -0.9238 168.4872 891.7491)" width="16" height="39.999" />
|
||||
|
||||
<rect
|
||||
x="303.031"
|
||||
y="421.036"
|
||||
transform="matrix(-0.3827 -0.9239 0.9239 -0.3827 50.2758 891.6655)"
|
||||
width="40.001"
|
||||
height="16"
|
||||
/>
|
||||
<rect x="303.031" y="421.036" transform="matrix(-0.3827 -0.9239 0.9239 -0.3827 50.2758 891.6655)" width="40.001" height="16" />
|
||||
|
||||
<rect
|
||||
x="409.088"
|
||||
y="315.018"
|
||||
transform="matrix(-0.9239 -0.3827 0.3827 -0.9239 701.898 785.6559)"
|
||||
width="40.001"
|
||||
height="16"
|
||||
/>
|
||||
<rect x="409.088" y="315.018" transform="matrix(-0.9239 -0.3827 0.3827 -0.9239 701.898 785.6559)" width="40.001" height="16" />
|
||||
|
||||
<rect
|
||||
x="409.054"
|
||||
y="165.011"
|
||||
transform="matrix(-0.9239 0.3827 -0.3827 -0.9239 891.6585 168.6574)"
|
||||
width="40.001"
|
||||
height="16"
|
||||
/>
|
||||
<rect
|
||||
x="315.001"
|
||||
y="46.895"
|
||||
transform="matrix(0.9238 0.3828 -0.3828 0.9238 50.212 -118.5529)"
|
||||
width="16"
|
||||
height="39.999"
|
||||
/>
|
||||
<path
|
||||
d="M248,88c-88.224,0-160,71.776-160,160s71.776,160,160,160s160-71.776,160-160S336.224,88,248,88z M248,392
|
||||
<rect x="409.054" y="165.011" transform="matrix(-0.9239 0.3827 -0.3827 -0.9239 891.6585 168.6574)" width="40.001" height="16" />
|
||||
<rect x="315.001" y="46.895" transform="matrix(0.9238 0.3828 -0.3828 0.9238 50.212 -118.5529)" width="16" height="39.999" />
|
||||
<path
|
||||
d="M248,88c-88.224,0-160,71.776-160,160s71.776,160,160,160s160-71.776,160-160S336.224,88,248,88z M248,392
|
||||
c-79.4,0-144-64.6-144-144s64.6-144,144-144s144,64.6,144,144S327.4,392,248,392z"
|
||||
/>
|
||||
<rect x="240" width="16" height="72" />
|
||||
<rect
|
||||
x="62.097"
|
||||
y="90.096"
|
||||
transform="matrix(0.7071 0.7071 -0.7071 0.7071 98.0963 -40.6334)"
|
||||
width="71.999"
|
||||
height="16"
|
||||
/>
|
||||
<rect y="240" width="72" height="16" />
|
||||
/>
|
||||
<rect x="240" width="16" height="72" />
|
||||
<rect x="62.097" y="90.096" transform="matrix(0.7071 0.7071 -0.7071 0.7071 98.0963 -40.6334)" width="71.999" height="16" />
|
||||
<rect y="240" width="72" height="16" />
|
||||
|
||||
<rect
|
||||
x="90.091"
|
||||
y="361.915"
|
||||
transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 -113.9157 748.643)"
|
||||
width="16"
|
||||
height="71.999"
|
||||
/>
|
||||
<rect x="240" y="424" width="16" height="72" />
|
||||
<rect x="90.091" y="361.915" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 -113.9157 748.643)" width="16" height="71.999" />
|
||||
<rect x="240" y="424" width="16" height="72" />
|
||||
|
||||
<rect
|
||||
x="361.881"
|
||||
y="389.915"
|
||||
transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 397.8562 960.6281)"
|
||||
width="71.999"
|
||||
height="16"
|
||||
/>
|
||||
<rect x="424" y="240" width="72" height="16" />
|
||||
<rect
|
||||
x="389.911"
|
||||
y="62.091"
|
||||
transform="matrix(0.7071 0.7071 -0.7071 0.7071 185.9067 -252.6357)"
|
||||
width="16"
|
||||
height="71.999"
|
||||
/>
|
||||
</svg>
|
||||
<svg
|
||||
version="1.1"
|
||||
class="moon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 49.739 49.739"
|
||||
style="enable-background: new 0 0 49.739 49.739"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<path
|
||||
d="M25.068,48.889c-9.173,0-18.017-5.06-22.396-13.804C-3.373,23.008,1.164,8.467,13.003,1.979l2.061-1.129l-0.615,2.268
|
||||
<rect x="361.881" y="389.915" transform="matrix(-0.7071 -0.7071 0.7071 -0.7071 397.8562 960.6281)" width="71.999" height="16" />
|
||||
<rect x="424" y="240" width="72" height="16" />
|
||||
<rect x="389.911" y="62.091" transform="matrix(0.7071 0.7071 -0.7071 0.7071 185.9067 -252.6357)" width="16" height="71.999" />
|
||||
</svg>
|
||||
<svg
|
||||
version="1.1"
|
||||
class="moon"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 49.739 49.739"
|
||||
style="enable-background: new 0 0 49.739 49.739"
|
||||
xml:space="preserve"
|
||||
>
|
||||
<path
|
||||
d="M25.068,48.889c-9.173,0-18.017-5.06-22.396-13.804C-3.373,23.008,1.164,8.467,13.003,1.979l2.061-1.129l-0.615,2.268
|
||||
c-1.479,5.459-0.899,11.25,1.633,16.306c2.75,5.493,7.476,9.587,13.305,11.526c5.831,1.939,12.065,1.492,17.559-1.258v0
|
||||
c0.25-0.125,0.492-0.258,0.734-0.391l2.061-1.13l-0.585,2.252c-1.863,6.873-6.577,12.639-12.933,15.822
|
||||
C32.639,48.039,28.825,48.888,25.068,48.889z M12.002,4.936c-9.413,6.428-12.756,18.837-7.54,29.253
|
||||
c5.678,11.34,19.522,15.945,30.864,10.268c5.154-2.582,9.136-7.012,11.181-12.357c-5.632,2.427-11.882,2.702-17.752,0.748
|
||||
c-6.337-2.108-11.473-6.557-14.463-12.528C11.899,15.541,11.11,10.16,12.002,4.936z"
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
/>
|
||||
</svg>
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const emit = defineEmits(["update:modelValue"]);
|
||||
interface Emits {
|
||||
(event: 'update:modelValue', value: boolean): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: boolean;
|
||||
modelValue: boolean;
|
||||
}>();
|
||||
|
||||
function toggleTheme(event: any) {
|
||||
emit("update:modelValue", event.target.checked);
|
||||
function toggleTheme(event: Event) {
|
||||
const target = event.target as HTMLInputElement | null;
|
||||
if (target) {
|
||||
emit('update:modelValue', target.checked);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,97 +1,97 @@
|
|||
import { describe, it, expect, vi, beforeEach } from "vitest";
|
||||
import { defineAsyncComponent } from "vue";
|
||||
import { mount, flushPromises } from "@vue/test-utils";
|
||||
import SocialBadge from "./socialButton.vue";
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { mount } from '@vue/test-utils';
|
||||
import { defineComponent } from 'vue';
|
||||
import SocialBadge from './SocialButton.vue';
|
||||
|
||||
|
||||
const mockIconComponent = (name:string) => ({
|
||||
default: {
|
||||
function mockIconComponent(name: string) {
|
||||
return {
|
||||
__esModule: true,
|
||||
default: defineComponent({
|
||||
name,
|
||||
template: `<svg class='${name.toLowerCase()}'></svg>`,
|
||||
},
|
||||
});
|
||||
|
||||
vi.mock("../components/icons/IconDiscord.vue", () => mockIconComponent("IconDiscord"));
|
||||
vi.mock("../components/icons/IconTwitter.vue", () => mockIconComponent("IconTwitter"));
|
||||
vi.mock("../components/icons/IconTelegram.vue", () => mockIconComponent("IconTelegram"));
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
vi.mock('@/components/icons/IconDiscord.vue', () => mockIconComponent('IconDiscord'));
|
||||
vi.mock('@/components/icons/IconTwitter.vue', () => mockIconComponent('IconTwitter'));
|
||||
vi.mock('@/components/icons/IconTelegram.vue', () => mockIconComponent('IconTelegram'));
|
||||
|
||||
describe("SocialBadge.vue", () => {
|
||||
describe('SocialBadge.vue', () => {
|
||||
let wrapper;
|
||||
|
||||
beforeEach(() => {
|
||||
wrapper = null;
|
||||
});
|
||||
|
||||
it("renders the correct link", () => {
|
||||
it('renders the correct link', () => {
|
||||
wrapper = mount(SocialBadge, {
|
||||
props: {
|
||||
href: "https://example.com",
|
||||
href: 'https://example.com',
|
||||
},
|
||||
});
|
||||
|
||||
const link = wrapper.find("a");
|
||||
const link = wrapper.find('a');
|
||||
expect(link.exists()).toBe(true);
|
||||
expect(link.attributes("href")).toBe("https://example.com");
|
||||
expect(link.attributes("target")).toBe("_blank");
|
||||
expect(link.attributes('href')).toBe('https://example.com');
|
||||
expect(link.attributes('target')).toBe('_blank');
|
||||
});
|
||||
|
||||
it("applies the correct color for light mode", () => {
|
||||
it('applies the correct color for light mode', () => {
|
||||
wrapper = mount(SocialBadge, {
|
||||
props: {
|
||||
dark: false,
|
||||
},
|
||||
});
|
||||
|
||||
const badge = wrapper.find(".social-badge");
|
||||
expect(badge.attributes("style")).toContain("color: black");
|
||||
expect(badge.attributes("style")).toContain("border-color: black");
|
||||
const badge = wrapper.find('.social-badge');
|
||||
expect(badge.attributes('style')).toContain('color: black');
|
||||
expect(badge.attributes('style')).toContain('border-color: black');
|
||||
});
|
||||
|
||||
it("applies the correct color for dark mode", () => {
|
||||
it('applies the correct color for dark mode', () => {
|
||||
wrapper = mount(SocialBadge, {
|
||||
props: {
|
||||
dark: true,
|
||||
},
|
||||
});
|
||||
|
||||
const badge = wrapper.find(".social-badge");
|
||||
expect(badge.attributes("style")).toContain("color: white");
|
||||
expect(badge.attributes("style")).toContain("border-color: white");
|
||||
const badge = wrapper.find('.social-badge');
|
||||
expect(badge.attributes('style')).toContain('color: white');
|
||||
expect(badge.attributes('style')).toContain('border-color: white');
|
||||
});
|
||||
|
||||
// it("renders the correct icon based on the type prop", async () => {
|
||||
// wrapper = mount(SocialBadge, {
|
||||
// props: {
|
||||
// type: "discord",
|
||||
// },
|
||||
// });
|
||||
// await flushPromises();
|
||||
// const current = wrapper.getCurrentComponent()?.setupState?.img.__asyncResolved
|
||||
// console.log("current", current.default.name);
|
||||
|
||||
// expect(current.default.name).toBe("IconDiscord");
|
||||
// it("renders the correct icon based on the type prop", async () => {
|
||||
// wrapper = mount(SocialBadge, {
|
||||
// props: {
|
||||
// type: "discord",
|
||||
// },
|
||||
// });
|
||||
// await flushPromises();
|
||||
// const current = wrapper.getCurrentComponent()?.setupState?.img.__asyncResolved
|
||||
// console.log("current", current.default.name);
|
||||
|
||||
// // expect(icon.exists()).toBe(true);
|
||||
// });
|
||||
// expect(current.default.name).toBe("IconDiscord");
|
||||
|
||||
it("does not render an icon if the type is unsupported", async () => {
|
||||
// // expect(icon.exists()).toBe(true);
|
||||
// });
|
||||
|
||||
it('does not render an icon if the type is unsupported', async () => {
|
||||
wrapper = mount(SocialBadge, {
|
||||
props: {
|
||||
type: "unsupported",
|
||||
type: 'unsupported',
|
||||
},
|
||||
});
|
||||
|
||||
await wrapper.vm.$nextTick();
|
||||
|
||||
const icon = wrapper.find(".social-badge-icon").find("component");
|
||||
const icon = wrapper.find('.social-badge-icon').find('component');
|
||||
expect(icon.exists()).toBe(false);
|
||||
});
|
||||
|
||||
it("renders without crashing when no props are provided", () => {
|
||||
it('renders without crashing when no props are provided', () => {
|
||||
wrapper = mount(SocialBadge);
|
||||
|
||||
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
<template>
|
||||
<a :href="props.href" target="_blank">
|
||||
<div
|
||||
class="social-badge"
|
||||
:style="{ color: color, 'border-color': color }"
|
||||
:class="{ 'social-badge--dark': props.dark }"
|
||||
>
|
||||
<div class="social-badge-icon">
|
||||
<component :color="color" :is="img" />
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { defineAsyncComponent, computed } from "vue";
|
||||
|
||||
interface Props {
|
||||
type?: string;
|
||||
dark?: boolean;
|
||||
href?: string;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {});
|
||||
|
||||
const color = computed(() => (props.dark ? "white" : "black"));
|
||||
|
||||
const img = computed(() => {
|
||||
let img;
|
||||
switch (props.type) {
|
||||
case "discord":
|
||||
img = defineAsyncComponent(() => import(`../components/icons/IconDiscord.vue`));
|
||||
break;
|
||||
case "twitter":
|
||||
img = defineAsyncComponent(() => import(`../components/icons/IconTwitter.vue`));
|
||||
break;
|
||||
case "telegram":
|
||||
img = defineAsyncComponent(() => import(`../components/icons/IconTelegram.vue`));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return img;
|
||||
});
|
||||
</script>
|
||||
<style lang="sass">
|
||||
.social-badge
|
||||
border-radius: 14px
|
||||
display: flex
|
||||
border: 1px solid var(--color-social-border)
|
||||
padding: 6px 20px
|
||||
align-items: center
|
||||
flex: 0 1 0
|
||||
color: black
|
||||
&:hover,&:active,&:focus
|
||||
background-color: var(--color-white-hovered)
|
||||
cursor: pointer
|
||||
&.social-badge--dark
|
||||
&:hover, &:active, &:focus
|
||||
background-color: var(--color-black-hovered)
|
||||
// font-size: 0
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue