增加官方商城页面

This commit is contained in:
zhl 2022-01-21 19:35:35 +08:00
parent d1e867d3f2
commit f63ac1c666
10 changed files with 447 additions and 47 deletions

View File

@ -1,7 +1,7 @@
<template>
<div class="card-list">
<div class="grid">
<card v-for="c in cardList" :key="c"></card>
<nft-item v-for="c in cardList" :key="c.id" :data="c" class="item"></nft-item>
</div>
<pagination></pagination>
</div>
@ -9,17 +9,24 @@
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Pagination from '@/components/market/Pagination.vue'
import Card from '@/components/market/Card.vue'
import NftItem from '@/components/market/NftItem.vue'
import { ISpineData } from '@/utils/SpineRender'
@Component({
name: 'CardList',
components: {
Card,
NftItem,
Pagination
}
})
export default class extends Vue {
private cardList: number[] = [1, 2, 3, 4, 5, 6, 7, 8]
private cardList: ISpineData[] = []
created() {
for (let i = 0; i < 10; i++) {
this.cardList.push({ id: 'hero2_10' + i, type: 0, skelName: 'n_aoi', name: 'miffy', price: '10', class: 0, repeat: false })
}
}
}
</script>
<style lang="scss" scoped>
@ -47,6 +54,7 @@ export default class extends Vue {
.card-list .grid .item {
height: 21em;
width: 14.375em;
position: relative;
}
.spinner {

View File

@ -10,8 +10,8 @@
<img src="data:image/svg+xml,%3csvg width='28' height='20' viewBox='0 0 28 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3e %3cpath d='M0 3.33333V0H28V3.33333L0 3.33333Z' fill='white' /%3e %3cpath d='M0 11.6667H28V8.33333H0V11.6667Z' fill='white' /%3e %3cpath d='M0 20H28V16.6667H0V20Z' fill='white' /%3e %3c/svg%3e"></label>
</div>
<div class="nav overflow" :class="{'show': menuShow}">
<label class="navItem">Official Store</label>
<label class="navItem dash">Marketplace</label>
<a class="navItem" href="/official">Official Shop</a>
<a class="navItem dash" href="/market">Marketplace</a>
<button v-if="!walletCollected" class="general-btn connectButton mobile" @click="collectToWallet">
<span>Connect Wallet</span>
</button>
@ -80,7 +80,7 @@ export default class extends Vue {
background: rgba(20,16,59,.8);
box-shadow: 0 1em 1.5em rgba(0,0,0,0.15);
backdrop-filter: blur(5em);
z-index: 8;
z-index: 18;
height: 4.75em;
position: fixed;
padding: 0 5%;
@ -108,7 +108,7 @@ export default class extends Vue {
transform: translateX(100%);
display: flex;
z-index: 7;
z-index: 17;
opacity: 0;
transition: transform linear 0.2s, opacity linear 0.2s;
padding: 1.5em 1.5em;
@ -148,6 +148,7 @@ export default class extends Vue {
line-height: 1.5em;
color: #ffffff;
padding: 1.5em 0;
text-decoration: none;
&:not(:first-child) {
border-top: 1px solid #3d2a84;

View File

@ -0,0 +1,121 @@
<template>
<router-link class="card" to="/item">
<img class="bg-img" src="@/assets/main/card/card_border.png">
<div class="anim-border">
<img class="card-main-img" :src="require(`@/assets/main/card/${data.skelName}.png`)" />
<img class="name-img" :src="require('@/assets/main/card/'+data.name+'.png')">
<div class="info-div">
<img class='buy-icon' src="@/assets/main/card/icon_buy.png"/>
<div class="price-label"><span>{{data.price}}</span></div>
</div>
<div class="class-div">
<img :src="require('@/assets/main/card/class_'+data.class+'.png')">
</div>
</div>
</router-link>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import { ISpineData } from '@/utils/SpineRender'
declare module 'vue/types/vue' {
interface Vue {
data: ISpineData
}
}
@Component({
name: 'NftItem',
components: {
},
props: ['data']
})
export default class extends Vue {
}
</script>
<style lang="scss" scoped>
// rect: 297x389
$width: 14em;
$height: 18.33em;
.bg-img {
width: $width;
height: $height;
}
.anim-border {
width: $width;
height: $height;
position: absolute;
top: 0;
left: 0;
overflow: hidden;
}
.card-main-img {
position: absolute;
bottom: 0;
max-height: 100%;
top: 0;
left: 0;
right: 0;
margin: auto;
}
.info-div {
background-image: url('~@/assets/main/card/name_bg.png');
width: 100%;
height: $height * 0.29;
position: absolute;
bottom: $height * 0.025;
left: 0;
right: 0;
display: flex;
flex-direction: row;
align-items: center;
background-size: contain;
background-repeat: no-repeat;
justify-content: space-between;
}
.class-div{
position: absolute;
top: 8px;
right: 8px;
width: $width*42/297;
height: $height*42/389;
}
.class-div img {
width: 100%;
}
.name-img {
height: $height * 39 / 389;
width: auto;
position: absolute;
right: $width * 9 / 297;
bottom: $height * 100 / 389;
}
.price-label {
color: black;
height: $height * 29 / 389;
font-weight: bold;
width: $width * 145 / 297;
background-image: url('~@/assets/main/card/price_bg.png');
background-size: contain;
background-repeat: no-repeat;
display: flex;
align-items: center;
justify-content: center;
margin-right: $width * 40 / 297;
margin-bottom: $width * 10 / 297;
}
.price-label span {
font-size: $width * 20 / 297;
}
.buy-icon {
width: $width * 44 / 297;
height: $height * 52 / 389;
margin-left: $width * 40 / 297;
margin-bottom: $height * 12 / 389;
}
</style>

View File

@ -0,0 +1,98 @@
<template>
<div class="card-list">
<div class="grid">
<nft-item v-for="c in cardList" :key="c.id" :data="c"></nft-item>
</div>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import Pagination from '@/components/market/Pagination.vue'
import Card from '@/components/market/Card.vue'
import NftItem from '@/components/market/NftItem.vue'
import { ISpineData } from '@/utils/SpineRender'
@Component({
name: 'NftList',
components: {
NftItem,
Card,
Pagination
}
})
export default class extends Vue {
private cardList: ISpineData[] = []
created() {
for (let i = 0; i < 10; i++) {
this.cardList.push({ id: 'hero2_10' + i, type: 0, skelName: 'n_aoi', name: 'miffy', price: '10', class: 0, repeat: false })
}
}
}
</script>
<style lang="scss" scoped>
.card-list {
margin-top: 2.0265em;
width: 100%;
}
.card-list .grid {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
display: -ms-grid;
display: grid;
-ms-grid-columns: (1fr)[4];
grid-template-columns: repeat(4, 1fr);
-webkit-column-gap: 1.875em;
column-gap: 1.875em;
row-gap: 1.3125em;
}
.card-list .grid .card {
height: 18em;
width: 14em;
position: relative;
}
.spinner {
height: 100vh;
-webkit-box-flex: 0;
-ms-flex: none;
flex: none;
}
.empty {
padding-top: 7.375em;
}
.empty img {
width: 14.625em;
height: auto;
}
@media (max-width: 1023px) {
.card-list .grid {
-ms-grid-columns: (1fr)[2];
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 767px) {
.card-list{
margin-top: 76px;
padding: 26px 20px;
};
.card-list .grid {
-ms-grid-columns: (1fr)[2];
grid-template-columns: repeat(2, 1fr);
-webkit-column-gap: 1.79em;
column-gap: 1.79em;
row-gap: 1.8em;
}
}
</style>

View File

@ -1,8 +1,8 @@
<template>
<div class="searchResult">
<div class="wrapper">
<sort-select></sort-select>
<button class="general-btn btnFilter" @click="showFilter">
<sort-select v-if="showSort"></sort-select>
<button class="general-btn btnFilter" v-if="showSort" @click="showFilter">
<span>FILTERS</span>
</button>
</div>
@ -16,13 +16,19 @@ import SortSelect from '@/components/market/SortSelect.vue'
import CardList from '@/components/market/CardList.vue'
import ResultNo from '@/components/market/ResultNo.vue'
declare module 'vue/types/vue' {
interface Vue {
showSort?: boolean
}
}
@Component({
name: 'SearchResult',
components: {
ResultNo,
CardList,
SortSelect
}
},
props: ['showSort']
})
export default class extends Vue {
showFilter() {

View File

@ -10,14 +10,14 @@
</a>
</div>
<div class="header-menu">
<a class="menu-item" href="/">
<div class="item" :class="{'active': currentTab==='presell'}">
Official Store
<a class="menu-item" href="/official">
<div class="item" :class="{'active': currentTab==='official'}">
Official Shop
<div class="active-bottom" v-if="currentTab==='presell'"></div>
</div
>
</a>
<a class="menu-item" href="/">
<a class="menu-item" href="/market">
<div class="item " :class="{'active': currentTab==='market'}">
Marketplace
<div class="active-bottom" v-if="currentTab==='market'"></div>
@ -37,13 +37,17 @@
draggable="false"
v-if="walletCollected"
class="avatar"
ref="avatar"
src="https://assets.thetanarena.com/cosmetic/avatar/3.png"
alt="avatar"
@click="infoPanelShow=!infoPanelShow"
>
</div>
</div>
<top-user-info v-if="infoPanelShow && walletCollected"></top-user-info>
<top-user-info
v-show="infoPanelShow && walletCollected"
v-on:close-self="onClose"
></top-user-info>
</div>
</template>
@ -79,6 +83,10 @@ export default class extends Vue {
async disconnectWallet() {
return this.bc.disconnect()
}
onClose() {
this.infoPanelShow = false
}
}
</script>
@ -103,7 +111,7 @@ export default class extends Vue {
height: 100%;
position: relative;
z-index: 1;
width: 60vw;
flex: auto;
}
.top-header .header-menu .menu-item {

View File

@ -1,5 +1,6 @@
<template>
<div class="position dropdown anim">
<div class="info-bg" @click="close">
<div class="position dropdown anim" @click.stop="">
<span class="name">SEgGQ58HRlLd</span>
<div class="divCode">
<span class="address">{{showAccount}}</span>
@ -31,6 +32,7 @@
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
@ -46,6 +48,10 @@ import { Message } from 'element-ui'
})
export default class extends Vue {
bc = new BlockChain();
close(e: any) {
console.log(e)
this.$emit('close-self')
}
get walletCollected() {
return AppModule.walletConnected
@ -235,7 +241,13 @@ export default class extends Vue {
animation-name: overlay-anim;
opacity: 0;
}
.info-bg {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
}
@media (max-width: 767px) {
}

View File

@ -2,6 +2,7 @@ import Vue from 'vue'
import VueRouter, { RouteConfig } from 'vue-router'
import Main from '../views/Main.vue'
import Market from '../views/Market.vue'
import Official from '@/views/Official.vue'
import Item from '../views/Item.vue'
Vue.use(VueRouter)
@ -22,6 +23,11 @@ const routes: Array<RouteConfig> = [
name: 'Market',
component: Market
},
{
path: '/official',
name: 'Official',
component: Official
},
{
path: '/item',
name: 'Item',

View File

@ -5,7 +5,7 @@
<section class="root">
<div class="container">
<search-panel @filter-show="showFilter" :class="{'show': mobileFilterShow}"></search-panel>
<search-result @filter-show="showFilter"></search-result>
<search-result @filter-show="showFilter" :show-sort="true"></search-result>
</div>
</section>
</div>

140
src/views/Official.vue Normal file
View File

@ -0,0 +1,140 @@
<template>
<div>
<mobile-top class="mobile-top"></mobile-top>
<top-menu class="desk-top" :current-tab="currentTab"></top-menu>
<section class="root">
<div class="container">
<nft-list></nft-list>
</div>
</section>
</div>
</template>
<script lang="ts">
import { Component, Vue } from 'vue-property-decorator'
import SearchPanel from '@/components/market/SearchPanel.vue'
import SearchResult from '@/components/market/SearchResult.vue'
import TopMenu from '@/components/market/TopMenu.vue'
import MobileTop from '@/components/market/MoileTop.vue'
import NftList from '@/components/market/NftList.vue'
@Component({
components: {
NftList,
MobileTop,
SearchResult,
SearchPanel,
TopMenu
}
})
export default class Official extends Vue {
mobileFilterShow = false
currentTab = 'official'
showFilter(val: boolean) {
this.mobileFilterShow = val
}
}
</script>
<style lang="scss" scoped>
@import '../scss/breakpoints.scss';
.root {
display: flex;
flex-direction: column;
align-items: center;
}
.container {
display: flex;
flex-direction: row;
width: 1440px;
max-width: 100%;
box-sizing: border-box;
}
.mobile-top {
display: none;
}
@include media('<desktop') {
.container {
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
.searchPanel {
width: 100%;
}
.filterTablet {
padding-top: 40px;
width: 100%;
-webkit-transition: all 0.3s;
transition: all 0.3s;
height: auto;
}
.filterTablet.collapsed {
padding-top: 0;
opacity: 0;
height: 0;
z-index: -1;
overflow: hidden;
}
.searchResult {
padding: 2.5em 4em;
}
.searchResult .wrapper .btnFilter {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
text-transform: uppercase;
}
}
@media (min-width: 1024px) and (max-width: 1439px) {
.root {
font-size: 11px;
}
.root .container {
width: 1024px;
max-width: 100%;
}
}
@media (min-width: 768px) and (max-width: 1023px) {
.root {
font-size: 20px;
}
.container {
width: 768px;
}
}
@media (max-width: 767px) {
.root {
font-size: 11px;
}
}
@media (max-width: 767px) and (max-width: 320px) {
.root {
font-size: 9px;
}
}
@media (max-width: 767px) {
.container {
width: 375px;
}
.searchResult {
padding: 26px 20px;
}
.mobile-top {
display: block;
}
.desk-top {
display: none;
}
.show{
display: flex!important;
}
}
</style>