Merge pull request #360 from alisaweb3/v3-single
Improved Governance List Style
This commit is contained in:
commit
8d14f342d6
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,2 +1,3 @@
|
||||
node_modules/
|
||||
**/.vscode
|
||||
**/.vscode
|
||||
yarn-error.log
|
@ -4,6 +4,7 @@
|
||||
"private": true,
|
||||
"target": "",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"serve": "vite",
|
||||
"build": "run-p type-check build-only",
|
||||
"preview": "vite preview",
|
||||
@ -28,6 +29,7 @@
|
||||
"@vueuse/core": "^9.12.0",
|
||||
"@vueuse/math": "^9.12.0",
|
||||
"apexcharts": "^3.37.1",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"axios": "^1.3.2",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"dayjs": "^1.11.7",
|
||||
@ -36,11 +38,16 @@
|
||||
"numeral": "^2.0.6",
|
||||
"osmojs": "^14.0.0-rc.0",
|
||||
"pinia": "^2.0.28",
|
||||
"postcss": "^8.4.23",
|
||||
"prismjs": "^1.29.0",
|
||||
"tailwindcss": "^3.3.1",
|
||||
"vite-plugin-vue-layouts": "^0.7.0",
|
||||
"vite-plugin-vuetify": "^1.0.2",
|
||||
"vue": "^3.2.45",
|
||||
"vue-flatpickr-component": "^11.0.3",
|
||||
"vue-i18n": "^9.2.2",
|
||||
"vue-json-pretty": "^2.2.4",
|
||||
"vue-prism-component": "^2.0.0",
|
||||
"vue-router": "^4.1.6",
|
||||
"vue3-apexcharts": "^1.4.1",
|
||||
"vue3-flip-countdown": "^0.1.6",
|
||||
@ -69,7 +76,7 @@
|
||||
"unplugin-auto-import": "^0.13.0",
|
||||
"unplugin-vue-components": "^0.23.0",
|
||||
"unplugin-vue-define-options": "1.1.4",
|
||||
"vite": "^4.0.0",
|
||||
"vite": "^4.3.1",
|
||||
"vite-plugin-pages": "^0.28.0",
|
||||
"vue-tsc": "^1.0.12"
|
||||
}
|
||||
|
@ -1,58 +1,67 @@
|
||||
<script lang="ts" setup>
|
||||
import { useFormatter } from '@/stores';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { ref, type PropType } from 'vue';
|
||||
|
||||
import { useFormatter } from "@/stores";
|
||||
import { computed } from "@vue/reactivity";
|
||||
import { ref, type PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
tally: { type: Object as PropType<{
|
||||
yes: string,
|
||||
no: string,
|
||||
noWithVeto: string,
|
||||
abstain: string
|
||||
}>},
|
||||
pool: {
|
||||
tally: {
|
||||
type: Object as PropType<{
|
||||
notBondedTokens: string;
|
||||
bondedTokens: string;
|
||||
yes: string;
|
||||
no: string;
|
||||
noWithVeto: string;
|
||||
abstain: string;
|
||||
}>,
|
||||
},
|
||||
})
|
||||
const format = useFormatter()
|
||||
const yes = computed(() => (format.calculatePercent(props.tally?.yes, props.pool?.bondedTokens)))
|
||||
const no = computed(() => ref(format.calculatePercent(props.tally?.no, props.pool?.bondedTokens)))
|
||||
const abstain = computed(() => (format.calculatePercent(props.tally?.abstain, props.pool?.bondedTokens)))
|
||||
const veto = computed(() => (format.calculatePercent(props.tally?.noWithVeto, props.pool?.bondedTokens)))
|
||||
|
||||
|
||||
console.log(yes.value, no.value, abstain.value, veto.value)
|
||||
pool: {
|
||||
type: Object as PropType<{
|
||||
notBondedTokens: string;
|
||||
bondedTokens: string;
|
||||
}>,
|
||||
},
|
||||
});
|
||||
const format = useFormatter();
|
||||
const yes = computed(() =>
|
||||
format.calculatePercent(props.tally?.yes, props.pool?.bondedTokens)
|
||||
);
|
||||
const no = computed(() =>
|
||||
ref(format.calculatePercent(props.tally?.no, props.pool?.bondedTokens))
|
||||
);
|
||||
const abstain = computed(() =>
|
||||
format.calculatePercent(props.tally?.abstain, props.pool?.bondedTokens)
|
||||
);
|
||||
const veto = computed(() =>
|
||||
format.calculatePercent(props.tally?.noWithVeto, props.pool?.bondedTokens)
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-success" :style="`width: ${yes}`"></div>
|
||||
<div class="progress-bar bg-error" :style="`width: ${no}`"></div>
|
||||
<div class="progress-bar " :style="`width: ${veto}; background-color: #B71C1C;`"></div>
|
||||
<div class="progress-bar bg-secondary" :style="`width: ${abstain}`"></div>
|
||||
</div>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-success" :style="`width: ${yes}`"></div>
|
||||
<div class="progress-bar bg-error" :style="`width: ${no}`"></div>
|
||||
<div
|
||||
class="progress-bar"
|
||||
:style="`width: ${veto}; background-color: #B71C1C;`"
|
||||
></div>
|
||||
<div class="progress-bar bg-secondary" :style="`width: ${abstain}`"></div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.progress {
|
||||
height: 0.8rem;
|
||||
overflow: hidden;
|
||||
background-color: rgba(128, 128, 128, 0.178);
|
||||
height: 0.8rem;
|
||||
overflow: hidden;
|
||||
background-color: rgba(128, 128, 128, 0.178);
|
||||
}
|
||||
.progress-bar {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
}
|
||||
.progress :first-child {
|
||||
border-radius: 0px !important;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
border-radius: 0px !important;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
.progress :last-child {
|
||||
border-radius: 0px !important;
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -124,7 +124,7 @@ function shortName(name: string, id: string) {
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VDivider />
|
||||
<VCardText style="max-height: 250px; overflow:scroll;"><MdEditor :model-value="coinInfo.description?.en" previewOnly></MdEditor></VCardText>
|
||||
<VCardText class="" style="max-height: 250px; overflow:auto;"><MdEditor :model-value="coinInfo.description?.en" previewOnly></MdEditor></VCardText>
|
||||
<VCardItem>
|
||||
<VChip v-for="tag in coinInfo.categories" size="x-small" class="mr-2">{{ tag }}</VChip>
|
||||
</VCardItem>
|
||||
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
@ -6,57 +6,60 @@ import ProposalProcess from './ProposalProcess.vue';
|
||||
import type { PropType } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
proposals: { type: Object as PropType<PaginatedProposals>},
|
||||
})
|
||||
proposals: { type: Object as PropType<PaginatedProposals> },
|
||||
});
|
||||
// const list = computed(()=> proposl)
|
||||
const format = useFormatter()
|
||||
const staking = useStakingStore()
|
||||
const chain = useBlockchain()
|
||||
function showType(v: string){
|
||||
if(v) {
|
||||
return v.substring(v.lastIndexOf('.')+1)
|
||||
}
|
||||
return v
|
||||
const format = useFormatter();
|
||||
const staking = useStakingStore();
|
||||
const chain = useBlockchain();
|
||||
function showType(v: string) {
|
||||
if (v) {
|
||||
return v.substring(v.lastIndexOf('.') + 1);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
const statusMap: Record<string, string> = {
|
||||
PROPOSAL_STATUS_VOTING_PERIOD: 'VOTING',
|
||||
PROPOSAL_STATUS_PASSED: 'PASSED',
|
||||
PROPOSAL_STATUS_REJECTED: 'REJECTED',
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<VExpansionPanels variant="accordion">
|
||||
<VExpansionPanel v-for="(x, i) in proposals?.proposals">
|
||||
<VExpansionPanelTitle disable-icon-rotate>
|
||||
<VChip label color="primary" class="mr-2">{{x.proposal_id}}</VChip>
|
||||
<div class="w-100"><VChip label>{{ showType(x.content['@type']) }}</VChip> {{ x.content?.title }}
|
||||
<div class="d-flex mt-1">
|
||||
<small class="text-secondary me-auto"> {{ format.toDay(x.voting_end_time, 'from') }}</small>
|
||||
<ProposalProcess style="width:300px;" :pool="staking.pool" :tally="x.final_tally_result"></ProposalProcess>
|
||||
<span></span>
|
||||
</div>
|
||||
</div>
|
||||
<template #actions>
|
||||
<VIcon
|
||||
v-if="x.status === 'PROPOSAL_STATUS_PASSED'"
|
||||
icon="mdi-check"
|
||||
color="success"
|
||||
class="ml-2"
|
||||
/>
|
||||
<VIcon
|
||||
v-if="x.status === 'PROPOSAL_STATUS_REJECTED'"
|
||||
icon="mdi-multiply"
|
||||
color="error"
|
||||
class="ml-2"
|
||||
/>
|
||||
</template>
|
||||
</VExpansionPanelTitle>
|
||||
<VExpansionPanelText>
|
||||
<VCard class="card-box">
|
||||
<VCardText>
|
||||
<MdEditor :model-value="format.multiLine(x.content?.description)" previewOnly></MdEditor>
|
||||
</VCardText>
|
||||
<div class="text-center w-100 my-2">
|
||||
<VBtn :to="`/${chain.chainName}/gov/${x.proposal_id}`" color="primary" variant="flat" size="small">Detail</VBtn>
|
||||
<VBtn color="primary" variant="flat" class="ml-2" size="small">Vote</VBtn>
|
||||
</div>
|
||||
</VCard>
|
||||
</VExpansionPanelText>
|
||||
</VExpansionPanel>
|
||||
</VExpansionPanels>
|
||||
</template>
|
||||
<div class="bg-white dark:bg-[#28334e] rounded text-sm">
|
||||
<RouterLink
|
||||
:to="`/${chain.chainName}/gov/${item?.proposal_id}`"
|
||||
v-for="(item, index) in proposals?.proposals"
|
||||
:key="index"
|
||||
class="py-4 px-4 hover:bg-gray-100 dark:hover:bg-[#353f5a] block rounded cursor-pointer"
|
||||
>
|
||||
<div class="grid grid-cols-6 md:grid-cols-11 flex-1">
|
||||
<div class="text-textMain dark:text-white mb-3">#{{ item?.proposal_id }}</div>
|
||||
|
||||
<div class="col-span-5 md:pr-10 text-textMain dark:text-white truncate">
|
||||
{{ item?.content?.title }}
|
||||
</div>
|
||||
|
||||
<div class="col-span-3 mb-3 truncate">
|
||||
<div
|
||||
class="bg-[#f6f2ff] text-[#9c6cff] dark:bg-gray-600 dark:text-gray-300 inline-block rounded-full px-2 py-[1px] text-xs"
|
||||
>
|
||||
{{ showType(item.content['@type']) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-yes flex items-center mb-3">
|
||||
<div class="w-1 h-1 bg-yes rounded-full mr-2"></div>
|
||||
<div class="text-xs">{{ statusMap?.[item?.status] || item?.status }}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="truncate mb-3 col-span-2 md:col-span-1 text-xs text-gray-500 dark:text-gray-400 text-right md:flex md:justify-start"
|
||||
>
|
||||
{{ format.toDay(item.voting_end_time, 'from') }}
|
||||
</div>
|
||||
</div>
|
||||
<ProposalProcess :pool="staking.pool" :tally="item.final_tally_result"></ProposalProcess>
|
||||
</RouterLink>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -2,52 +2,36 @@
|
||||
import { useFormatter } from '@/stores';
|
||||
import type { Tally } from '@/types';
|
||||
import { computed } from '@vue/reactivity';
|
||||
import { ref, type PropType } from 'vue';
|
||||
|
||||
import type { PropType } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
tally: { type: Object as PropType<Tally>},
|
||||
tally: { type: Object as PropType<Tally> },
|
||||
pool: {
|
||||
type: Object as PropType<{
|
||||
not_bonded_tokens: string;
|
||||
bonded_tokens: string;
|
||||
not_bonded_tokens: string;
|
||||
bonded_tokens: string;
|
||||
}>,
|
||||
},
|
||||
})
|
||||
const total = computed(() => props.pool?.bonded_tokens)
|
||||
const format = useFormatter()
|
||||
const yes = computed(() => (format.calculatePercent(props.tally?.yes, total.value)))
|
||||
const no = computed(() => ref(format.calculatePercent(props.tally?.no, total.value)))
|
||||
const abstain = computed(() => (format.calculatePercent(props.tally?.abstain, total.value)))
|
||||
const veto = computed(() => (format.calculatePercent(props.tally?.no_with_veto, total.value)))
|
||||
|
||||
});
|
||||
const total = computed(() => props.pool?.bonded_tokens);
|
||||
const format = useFormatter();
|
||||
const yes = computed(() => format.calculatePercent(props.tally?.yes, total.value));
|
||||
const no = computed(() => format.calculatePercent(props.tally?.no, total.value));
|
||||
const abstain = computed(() => format.calculatePercent(props.tally?.abstain, total.value));
|
||||
const veto = computed(() => format.calculatePercent(props.tally?.no_with_veto, total.value));
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="progress">
|
||||
<div class="progress-bar bg-success" :style="`width: ${yes}`"> {{ yes }}</div>
|
||||
<div class="progress-bar bg-error" :style="`width: ${no}`">{{ no }} </div>
|
||||
<div class="progress-bar " :style="`width: ${veto}; background-color: #B71C1C;`"> {{ veto }} </div>
|
||||
<div class="progress-bar bg-secondary" :style="`width: ${abstain}`"> </div>
|
||||
</div>
|
||||
<div class="progress rounded-full h-1 text-xs flex items-center">
|
||||
<div class="h-1 bg-yes" :style="`width: ${yes}`"></div>
|
||||
<div class="h-1 bg-no" :style="`width: ${no}`"></div>
|
||||
<div class="h-1" :style="`width: ${veto}; background-color: #B71C1C;`"></div>
|
||||
<div class="h-1 bg-secondary" :style="`width: ${abstain}`"></div>
|
||||
</div>
|
||||
</template>
|
||||
<style scoped>
|
||||
.progress {
|
||||
height: 0.8rem;
|
||||
overflow: hidden;
|
||||
background-color: rgba(128, 128, 128, 0.178);
|
||||
overflow: hidden;
|
||||
background-color: rgba(128, 128, 128, 0.178);
|
||||
}
|
||||
.progress-bar {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
}
|
||||
.progress :first-child {
|
||||
border-radius: 0px !important;
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
.progress :last-child {
|
||||
border-radius: 0px !important;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
@ -1,41 +1,42 @@
|
||||
<script lang="ts" setup>
|
||||
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig'
|
||||
import { useThemeConfig } from '@/plugins/vuetify/@core/composable/useThemeConfig';
|
||||
|
||||
// Components
|
||||
import Footer from '@/layouts/components/Footer.vue'
|
||||
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue'
|
||||
import UserProfile from '@/layouts/components/ChainProfile.vue'
|
||||
import Footer from '@/layouts/components/Footer.vue';
|
||||
import NavbarThemeSwitcher from '@/layouts/components/NavbarThemeSwitcher.vue';
|
||||
import UserProfile from '@/layouts/components/ChainProfile.vue';
|
||||
|
||||
import { useDashboard } from '@/stores/useDashboard'
|
||||
import { useDashboard } from '@/stores/useDashboard';
|
||||
|
||||
// @layouts plugin
|
||||
import { VerticalNavLayout } from '@layouts'
|
||||
import NavBarI18n from './NavBarI18n.vue'
|
||||
import NavSearchBar from './NavSearchBar.vue'
|
||||
import NavBarNotifications from './NavBarNotifications.vue'
|
||||
import TheCustomizer from '@/plugins/vuetify/@core/components/TheCustomizer.vue'
|
||||
import Breadcrumbs from './Breadcrumbs.vue'
|
||||
import { useBlockchain } from '@/stores'
|
||||
import { VerticalNavLayout } from '@layouts';
|
||||
import NavBarI18n from './NavBarI18n.vue';
|
||||
import NavSearchBar from './NavSearchBar.vue';
|
||||
import NavBarNotifications from './NavBarNotifications.vue';
|
||||
import TheCustomizer from '@/plugins/vuetify/@core/components/TheCustomizer.vue';
|
||||
import Breadcrumbs from './Breadcrumbs.vue';
|
||||
import { useBlockchain } from '@/stores';
|
||||
|
||||
const { appRouteTransition, isLessThanOverlayNavBreakpoint, isVerticalNavCollapsed } = useThemeConfig()
|
||||
const { width: windowWidth } = useWindowSize()
|
||||
const { appRouteTransition, isLessThanOverlayNavBreakpoint, isVerticalNavCollapsed } =
|
||||
useThemeConfig();
|
||||
const { width: windowWidth } = useWindowSize();
|
||||
|
||||
// ℹ️ Provide animation name for vertical nav collapse icon.
|
||||
const verticalNavHeaderActionAnimationName = ref<null | 'rotate-180' | 'rotate-back-180'>(null)
|
||||
const verticalNavHeaderActionAnimationName = ref<null | 'rotate-180' | 'rotate-back-180'>(null);
|
||||
|
||||
watch(isVerticalNavCollapsed, val => {
|
||||
verticalNavHeaderActionAnimationName.value = val ? 'rotate-180' : 'rotate-back-180'
|
||||
})
|
||||
verticalNavHeaderActionAnimationName.value = val ? 'rotate-180' : 'rotate-back-180';
|
||||
});
|
||||
|
||||
const dashboard = useDashboard()
|
||||
dashboard.initial()
|
||||
const blockchain = useBlockchain()
|
||||
const dashboard = useDashboard();
|
||||
dashboard.initial();
|
||||
const blockchain = useBlockchain();
|
||||
// blockchain.initial()
|
||||
blockchain.$subscribe((m, s) => {
|
||||
if(!Array.isArray(m.events) && m.events.key === 'chainName') {
|
||||
blockchain.initial()
|
||||
if (!Array.isArray(m.events) && m.events.key === 'chainName') {
|
||||
blockchain.initial();
|
||||
}
|
||||
})
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -43,8 +44,11 @@ blockchain.$subscribe((m, s) => {
|
||||
<!-- 👉 navbar -->
|
||||
<template #navbar="{ toggleVerticalOverlayNavActive }">
|
||||
<div class="d-flex h-100 align-center">
|
||||
<IconBtn v-if="isLessThanOverlayNavBreakpoint(windowWidth)" class="ms-n3"
|
||||
@click="toggleVerticalOverlayNavActive(true)">
|
||||
<IconBtn
|
||||
v-if="isLessThanOverlayNavBreakpoint(windowWidth)"
|
||||
class="ms-n3"
|
||||
@click="toggleVerticalOverlayNavActive(true)"
|
||||
>
|
||||
<VIcon icon="mdi-menu" />
|
||||
</IconBtn>
|
||||
|
||||
@ -52,9 +56,9 @@ blockchain.$subscribe((m, s) => {
|
||||
|
||||
<VSpacer />
|
||||
<!-- <NavSearchBar />-->
|
||||
<NavBarNotifications />
|
||||
<NavBarI18n />
|
||||
<NavbarThemeSwitcher />
|
||||
<NavBarNotifications class="hidden md:inline-block" />
|
||||
<NavBarI18n class="hidden md:inline-block" />
|
||||
<NavbarThemeSwitcher class="hidden md:inline-block" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
30
src/main.ts
30
src/main.ts
@ -1,32 +1,32 @@
|
||||
/* eslint-disable import/order */
|
||||
import "@/plugins/vuetify/@iconify/icons-bundle";
|
||||
import App from "@/App.vue";
|
||||
import layoutsPlugin from "@/plugins/vuetify/layouts";
|
||||
import vuetify from "@/plugins/vuetify";
|
||||
import i18n from "@/plugins/i18n";
|
||||
import { loadFonts } from "@/plugins/vuetify/webfontloader";
|
||||
import "@/plugins/vuetify/@core/scss/template/index.scss";
|
||||
import "@/plugins/vuetify/styles/styles.scss";
|
||||
import { createApp } from "vue";
|
||||
import { createPinia } from "pinia";
|
||||
import '@/plugins/vuetify/@iconify/icons-bundle';
|
||||
import App from '@/App.vue';
|
||||
import layoutsPlugin from '@/plugins/vuetify/layouts';
|
||||
import vuetify from '@/plugins/vuetify';
|
||||
import i18n from '@/plugins/i18n';
|
||||
import { loadFonts } from '@/plugins/vuetify/webfontloader';
|
||||
import '@/plugins/vuetify/@core/scss/template/index.scss';
|
||||
import '@/plugins/vuetify/styles/styles.scss';
|
||||
import '@/style.css';
|
||||
import { createApp } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
// import router from "@/plugins/vuetify/router";
|
||||
import router from "./router";
|
||||
import { useBaseStore } from "./stores/useBaseStore";
|
||||
import router from './router';
|
||||
import { useBaseStore } from './stores/useBaseStore';
|
||||
|
||||
loadFonts();
|
||||
|
||||
// Create vue app
|
||||
const app = createApp(App);
|
||||
// Use plugins
|
||||
app.use(i18n)
|
||||
app.use(i18n);
|
||||
app.use(vuetify);
|
||||
app.use(createPinia());
|
||||
app.use(layoutsPlugin);
|
||||
app.use(router);
|
||||
|
||||
|
||||
// Mount vue app
|
||||
app.mount("#app");
|
||||
app.mount('#app');
|
||||
|
||||
// fetch latest block every 6s
|
||||
// const blockStore = useBaseStore()
|
||||
|
@ -124,7 +124,7 @@ function shortName(name: string, id: string) {
|
||||
</VCol>
|
||||
</VRow>
|
||||
<VDivider />
|
||||
<VCardText style="max-height: 250px; overflow:scroll;"><MdEditor :model-value="coinInfo.description?.en" previewOnly></MdEditor></VCardText>
|
||||
<VCardText style="max-height: 250px; overflow:auto;"><MdEditor :model-value="coinInfo.description?.en" previewOnly></MdEditor></VCardText>
|
||||
<VCardItem>
|
||||
<VChip v-for="tag in coinInfo.categories" size="x-small" class="mr-2">{{ tag }}</VChip>
|
||||
</VCardItem>
|
||||
|
@ -1,31 +1,52 @@
|
||||
<script setup lang="ts">
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig'
|
||||
import type { ThemeSwitcherTheme } from '@layouts/types'
|
||||
import { useThemeConfig } from '@core/composable/useThemeConfig';
|
||||
import type { ThemeSwitcherTheme } from '@layouts/types';
|
||||
import { onMounted } from 'vue';
|
||||
|
||||
const props = defineProps<{
|
||||
themes: ThemeSwitcherTheme[]
|
||||
}>()
|
||||
themes: ThemeSwitcherTheme[];
|
||||
}>();
|
||||
|
||||
const { theme } = useThemeConfig()
|
||||
const { state: currentThemeName, next: getNextThemeName, index: currentThemeIndex } = useCycleList(props.themes.map(t => t.name), { initialValue: theme.value })
|
||||
const { theme } = useThemeConfig();
|
||||
const {
|
||||
state: currentThemeName,
|
||||
next: getNextThemeName,
|
||||
index: currentThemeIndex,
|
||||
} = useCycleList(
|
||||
props.themes.map(t => t.name),
|
||||
{ initialValue: theme.value }
|
||||
);
|
||||
|
||||
const changeTheme = () => {
|
||||
theme.value = getNextThemeName()
|
||||
}
|
||||
theme.value = getNextThemeName();
|
||||
};
|
||||
|
||||
const changeMode = (val: 'dark' | 'light') => {
|
||||
if (val === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
document.documentElement.classList.remove('light');
|
||||
} else {
|
||||
document.documentElement.classList.add('light');
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
};
|
||||
// Update icon if theme is changed from other sources
|
||||
watch(theme, val => {
|
||||
currentThemeName.value = val
|
||||
})
|
||||
watch(theme, (val: 'dark' | 'light') => {
|
||||
currentThemeName.value = val;
|
||||
changeMode(val);
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (currentThemeName.value) {
|
||||
changeMode(currentThemeName.value);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<IconBtn @click="changeTheme">
|
||||
<VIcon :icon="props.themes[currentThemeIndex].icon" />
|
||||
<VTooltip
|
||||
activator="parent"
|
||||
open-delay="1000"
|
||||
>
|
||||
<VTooltip activator="parent" open-delay="1000">
|
||||
<span class="text-capitalize">{{ currentThemeName }}</span>
|
||||
</VTooltip>
|
||||
</IconBtn>
|
||||
|
3
src/style.css
Normal file
3
src/style.css
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
17
tailwind.config.js
Normal file
17
tailwind.config.js
Normal file
@ -0,0 +1,17 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
darkMode: ['class'],
|
||||
content: ['./index.html', './src/**/*.{vue,js,ts,jsx,tsx}'],
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
main: '#5973fe',
|
||||
yes: '#3fb68b',
|
||||
no: '#ff5353',
|
||||
info: '#00b2ff',
|
||||
textMain: '#333',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
};
|
8192
yarn-error.log
8192
yarn-error.log
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user