Skip to content

Instantly share code, notes, and snippets.

@YuraKolesnikov
Created March 2, 2021 14:40
Show Gist options
  • Save YuraKolesnikov/0855ffb16588428c48e5e853ed646a01 to your computer and use it in GitHub Desktop.
Save YuraKolesnikov/0855ffb16588428c48e5e853ed646a01 to your computer and use it in GitHub Desktop.
import { withDesign } from 'storybook-addon-designs'
import { withPadding, withContainer } from '../../.storybook/helpers'
import VDomainCard from './VDomainCard'
import { domains } from './domains'
export default {
title: 'Simple Components / VDomainCard',
decorators: [withContainer, withPadding, withDesign]
}
export const Standard = args => ({
props: Object.keys(args),
components: { VDomainCard },
data () {
return {
domains
}
},
template: `
<div style="max-width: 1200px; display: grid; grid-template-columns: repeat(auto-fill, minmax(288px, 328px)); grid-column-gap: 24px">
<VDomainCard view="box" v-for="domain in domains" :key="domain.id" :product="domain" v-bind="$props" />
</div>
`
})
Standard.args = {
domain: 'kekis'
}
export const List = args => ({
props: Object.keys(args),
components: { VDomainCard },
data () {
return {
domains
}
},
template: `
<div style="max-width: 1200px;">
<VDomainCard view="list" v-for="domain in domains" :key="domain.id" :product="domain" domain="kekis" />
</div>
`
})
Standard.parameters = {
design: {
type: 'figma',
url: 'https://www.figma.com/file/3F0xMdYWmdcxVCpCRSh7lo/Components-Library-(Jino-%E2%80%A2-Shop)-(Beta)?node-id=3387%3A46430'
}
}
<template>
<component
:is="selectedView"
:product="product"
:domain="domain"
:domainAvailabilityStatuses="domainAvailabilityStatuses"
/>
</template>
<script>
import { narrowViewportMatch, touchDeviceMatch } from '../../lib/env'
import VDomainCardBox from './components/VDomainCardBox'
import VDomainCardList from './components/VDomainCardList'
export default {
props: {
view: {
type: String,
default: 'box'
},
product: {
type: Object,
default: () => ({})
},
domain: {
type: String,
default: null
},
domainAvailabilityStatuses: {
type: Object,
default: () => ({})
}
},
data () {
return {
debounce: null,
showBox: false
}
},
computed: {
selectedView () {
return this.view === 'box' || this.showBox ? VDomainCardBox : VDomainCardList
}
},
mounted () {
window.addEventListener('resize', this.debounceGetViewportWidth)
},
beforeDestroy () {
window.removeEventListener('resize', this.debounceGetViewportWidth)
},
methods: {
setSelectedView () {
this.showBox = narrowViewportMatch().matches || touchDeviceMatch().matches
},
debounceGetViewportWidth () {
clearTimeout(this.debounce)
this.debounce = setTimeout(() => this.setSelectedView(), 500)
}
}
}
</script>
<template>
<div :class="$style.DomainCardBox">
<div :class="$style.DomainCardBox__badges">
<div
v-if="product.discount"
:class="discountBadgeClassList"
>
&minus;{{ product.discount }}%
</div>
<div
v-if="product.isCp"
:class="jinoDomainsBadgeClassList"
>
Джино • Домены
</div>
<div
v-if="product.promocodeDiscountPercent"
:class="promocodeDiscountBadgeClassList"
>
&minus;{{ product.promocodeDiscountPercent }}%
</div>
</div>
<div :class="$style.DomainCardBox__prices">
<div
:class="$style.DomainCardBox__mobilePrice"
v-if="isMobile && product.checked"
>
<span>{{ price }} ₽</span>
<VIcon
:class="$style.DomainCardBox__mobilePriceIcon"
name="arrow-right"
size="s"
/>
</div>
<template v-else>
<span
:class="$style.DomainCardBox__oldPrice"
v-if="product.price"
>
{{ product.basePrice }} ₽
</span>
<span
:class="$style.DomainCardBox__newPrice"
>
{{ price }} ₽
</span>
</template>
</div>
<div :class="$style.DomainCardBox__status">
<div
:class="circleClassList"
v-if="status"
/>
<VIcon
:class="$style.DomainCardBox__favorite"
:size="isMobile ? 'm' : 's'"
:name="product.favorite ? 'heart-filled' : 'heart'"
:data-name="product.favorite ? 'heart-filled' : 'heart'"
v-else
@click.native="toggleFavorite(product.id)"
/>
<span
:class="$style.DomainCardBox__textTaken"
v-if="status === 'failed'"
>
Домен занят
</span>
</div>
<VUniLink
v-bind="linkProps"
:class="[
$style.DomainCardBox__domain,
{ [$style.DomainCardBox__domain_size_s]: domain }
]"
target="_blank"
>
<span
:class="$style.DomainCardBox__website"
v-if="domain"
>
{{ domain }}
</span>
<span :class="$style.DomainCardBox__dot">.</span>
<span :class="$style.DomainCardBox__name">{{ displayZone }}</span>
</VUniLink>
<button :class="$style.DomainCardBox__buy">
Купить
</button>
</div>
</template>
<script>
import { narrowViewportMatch, touchDeviceMatch } from '../../../lib/env'
import VIcon from '../../VIcon'
import VUniLink from '../../VUniLink'
export default {
components: {
VIcon,
VUniLink
},
props: {
product: {
type: Object,
default: () => ({})
},
domain: {
type: String,
default: null
},
checked: {
type: Boolean,
default: false
},
domainAvailabilityStatuses: {
type: Object,
default: () => ({})
}
},
computed: {
discountBadgeClassList () {
return [
this.$style.DomainCardBox__badge,
this.$style.DomainCardBox__badge_color_green,
this.$style.DomainCardBox__badge_position_left
]
},
jinoDomainsBadgeClassList () {
return [
this.$style.DomainCardBox__badge,
this.$style.DomainCardBox__badge_color_red,
this.$style.DomainCardBox__badge_position_left
]
},
promocodeDiscountBadgeClassList () {
return [
this.$style.DomainCardBox__badge,
this.$style.DomainCardBox__badge_color_red,
this.$style.DomainCardBox__badge_position_right
]
},
circleClassList () {
return [
this.$style.DomainCardBox__circle,
{ [this.$style.DomainCardBox__circle_color_red]: this.status === 'failed' }
]
},
isMobile () {
return narrowViewportMatch().matches || touchDeviceMatch().matches
},
shouldShowBadge () {
return (this.product.discount && this.product.basePrice) || this.product.isCp
},
displayZone () {
return this.product.zone.substr(1)
},
status () {
const info = this.domainAvailabilityStatuses[this.domain]
if (!info) { return }
return info.status
},
isUnavailable () {
return this.status === 'failed'
},
buyButtonLabel () {
if (this.status === 'succeed') { return 'Купить' }
if (this.status === 'failed') { return 'Недоступен' }
return 'Подробнее'
},
price () {
const { price, promocodePrice, basePrice } = this.product
return price || promocodePrice || basePrice
},
linkProps () {
let postfix = ''
if (this.displayDomain) {
postfix = `?domain=${this.displayDomain}`
}
const link = {}
if (this.product.isCp) {
link.href = 'https://google.com'
} else {
link.to = `/catalog/domains/${this.product.zone}/${postfix}`
}
/* if (this.product.isCp) {
link.href = `${this.$env.JINOSITE_URL}/domains/price/.${this.displayZone}/${postfix}`
} else {
link.to = `/catalog/domains/${this.product.zone}/${postfix}`
} */
return link
}
},
methods: {
toggleFavorite (id) {
this.$emit('toggleFavorite', id)
}
}
}
</script>
<style lang="scss" module>
@import "~/assets/scss/variables";
.DomainCardBox {
box-sizing: border-box;
background: #fff;
box-shadow: 0 2px 20px rgba(0, 0, 0, 0.08);
border-radius: 12px;
position: relative;
overflow: hidden;
max-width: 320px;
min-width: 250px;
display: grid;
padding: 12px 12px 12px 16px;
grid-template-rows: 28px 22px 28px;
height: 96px;
margin-bottom: 24px;
}
.DomainCardBox__badges {
position: absolute;
top: 0;
left: 0;
display: flex;
}
.DomainCardBox__badge {
padding: 4px 8px;
font-size: $text-12;
line-height: $text-16;
text-align: center;
font-weight: 400;
}
.DomainCardBox__badge_color_green {
color: $secondary-green;
background-color: $tertiary-green-light;
}
.DomainCardBox__badge_color_red {
color: $primary;
background-color: $tertiary-red-light;
}
.DomainCardBox__badge_position_left {
border-radius: 12px 0;
margin-right: 2px;
}
.DomainCardBox__badge_position_right {
border-radius: 0 0 12px 12px;
}
.DomainCardBox__circle {
--bg-color: #{$secondary-green};
width: 10px;
height: 10px;
border-radius: 50%;
background-color: var(--bg-color);
}
.DomainCardBox__circle_color_red {
--bg-color: #{$text-negative};
}
.DomainCardBox__prices {
justify-self: end;
display: flex;
align-items: flex-start;
transition: opacity 0.3s $animation-timing;
}
.DomainCardBox__oldPrice {
text-decoration-line: line-through;
font-size: $text-18;
font-weight: 700;
color: $text-03;
line-height: $text-24;
margin-right: 4px;
}
.DomainCardBox__newPrice {
font-size: $text-24;
line-height: $text-28;
font-weight: 700;
font-family: 'PT Sans Caption', sans-serif;
color: $text-01;
}
.DomainCardBox__status {
font-size: $text-12;
height: 13px;
display: flex;
align-items: center;
}
.DomainCardBox__textTaken {
color: $text-negative;
font-size: $text-12;
line-height: 16px;
text-transform: uppercase;
margin-left: 4px;
}
.DomainCardBox__domain {
display: flex;
align-items: flex-end;
font-weight: bold;
font-size: $text-20;
line-height: 28px;
position: relative;
text-decoration: none;
max-width: 100%;
overflow: hidden;
&::before {
content: "";
position: absolute;
width: calc(100% + 24px);
height: 96px;
bottom: -8px;
left: -16px;
}
}
.DomainCardBox__website {
color: $text-02;
}
.DomainCardBox__dot {
color: $primary;
font-size: $text-24;
}
.DomainCardBox__name {
color: $text-01;
}
.DomainCardBox__favorite {
--fill: #{$base-04};
cursor: pointer;
position: relative;
z-index: 10;
&[data-name="heart-filled"] {
--fill: #{$base-05};
}
&:hover {
--fill: #{$base-05};
}
}
.DomainCardBox__buy {
box-sizing: border-box;
position: absolute;
border: 0;
padding: 0;
z-index: 10;
right: 0;
top: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
width: 96px;
height: 96px;
background-color: $secondary-green;
color: #fff;
cursor: pointer;
transform: translate3d(100px, 0, 0);
transition: transform 0.3s $animation-timing;
&:focus,
&:active {
outline: 0;
}
}
.DomainCardBox:hover {
.DomainCardBox__buy {
transform: translate3d(0, 0, 0);
}
.DomainCardBox__prices {
opacity: 0;
}
}
@media (max-width: 878px) {
.DomainCardBox {
padding: 8px 8px 8px 16px;
height: 80px;
grid-template-rows: 30px 10px 28px;
&:hover {
.DomainCardBox__buy {
transform: translate3d(100px, 0, 0);
}
.DomainCardBox__prices {
opacity: 1;
}
}
}
.DomainCardBox__domain {
font-size: $text-24;
&::before {
height: 80px;
}
}
.DomainCardBox__newPrice {
font-size: $text-20;
}
.DomainCardBox__domain_size_s {
font-size: $text-16;
}
.DomainCardBox__dot {
transform: translateY(-1px);
}
.DomainCardBox__favorite {
position: absolute;
bottom: 6px;
right: 8px;
z-index: 5;
}
.DomainCardBox__mobilePrice {
display: flex;
align-items: center;
font-size: $text-14;
line-height: 20px;
background: $secondary-green;
border-radius: 12px;
color: #fff;
padding: 6px 14px 6px 16px;
&Icon {
--fill: #fff;
margin-left: 6px;
}
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment