Vue
by joplomacedo
HTML
<link href="https://fonts.googleapis.com/css?family=Fira+Sans:200,300,400,500,600,700,800,900" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.3.1/css/all.css" integrity="sha384-mzrmE5qonljUremFsqc01SB46JvROS7bZs3IO2EmfFsd15uHvIt+Y8vEf7N7fWAU" crossorigin="anonymous">
<div id="app">
<div class="page_header">
<div class="page_header__logo_block">
<img class="page_header__logo" src="https://static.holdonsam.com/site/2_0/img/reoodle_logos/white.svg" alt="">
<div class="page_header__logo_block_divider"></div>
<div class="page_header__pricing_page_label">Pagamentos</div>
</div>
<div class="page_header__nav">
<div class="page_header__nav_link">
Back to App
</div>
</div>
</div>
<div class="page_body">
<div class="tabs__nav">
<div @click="() => changeView('plans')" class="tabs__nav_link" :class="currentView === 'plans'? 'is-selected' : null">Planos</div>
<div @click="() => changeView('receipts')" class="tabs__nav_link" :class="currentView === 'receipts'? 'is-selected' : null">Recibos</div>
</div>
<div class="tabs__body">
<div v-if="currentView === 'plans'">
<div>
<p class="t-h--3">
Plano corrente
</p>
<div class="active_plan_card" v-if="currentPlan !== null">
<div>
<div class="t-label">Plano</div>
<div>{{currentPlan.name}}</div>
</div>
<div>
<div class="t-label">Data de compra</div>
<div>{{purchaseDate}}</div>
</div>
<div>
<div class="t-label">Data de renovação</div>
<div>{{renewalDate}}</div>
</div>
...
CSS
*,
*:after,
*:before {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
font: inherit;
border: 0;
padding: 0;
margin: 0;
color: inherit;
text-decoration: none;
}
html {
font-size: 100%;
font-family: helveticaneue, helvetica, arial, sans-serif;
-webkit-font-smoothing: antialiased;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
html {
line-height: 1.7;
font-size: 17px;
height: 100%;
background: #fffaf3;
color: hsla(259, 13%, 49%, 1);
font-weight: 400;
font-family: fira sans, sans-serif;
--color-brand: #5e2bcc;
}
body {
background: transparent;
}
.t-h--2 {
font-weight: 600;
color: var(--color-brand);
font-size: 1.25em;
}
.t-h--3 {
font-weight: 800;
color: var(--color-brand);
font-size: 1.25em;
line-height: 1.2;
margin-bottom: .6em;
}
.app-btn {}
.app-btn_group {
display: flex;
}
.app-btn_group .app-btn:first-child {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.app-btn_group .app-btn:last-child {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.app-radio {
display: inline-flex;
align-items: center;
margin-right: 1em;
cursor: pointer;
--transition: .12s;
}
.app-radio__label {}
.app-radio__input {
display: none;
}
.app-radio__box {
position: relative;
display: inline-flex;
height: 1.1em;
width: 1.1em;
border-radius: 50px;
border: 1px solid grey;
margin-right: .3em;
align-items: center;
justify-content: center;
transition: var(--transition);
}
.app-radio__check {
position: absolute;
height: .5em;
width: .5em;
border-radius: 50px;
background-color: var(--color-brand);
opacity: 0;
transform: scale(0);
transition: var(--transition);
}
.app-radio__input:checked~.app-radio__box {
border-color: var(--color-brand);
}
.app-radio__input:checked~.app-radio__box>.app-radio__check {
opacity: 1;
transform: scale(1);
}
.app-divider {
height: 1px;
...
Vue
Vue.component('app-divider', {
template: `
<div class="app-divider"></div>
`
});
Vue.component('app-radio', {
template: `
<label class="app-radio">
<input
type="radio"
class="app-radio__input"
:value="value"
:checked="isChecked"
@change="$emit('change', value)"
/>
<span class="app-radio__box">
<span class="app-radio__check"></span>
</span>
<span class="app-radio__label">
{{label}}
</span>
</label>
`,
model: {
prop: 'modelValue',
event: 'change'
},
props: {
label:{
type: String,
required: true
},
value: {
type: [String, Number],
required: true
},
modelValue: {
default: ""
}
},
computed: {
isChecked() {
return this.modelValue == this.value
}
}
})
Vue.component('app-btn-group', {
template: `
<div class="app-btn_group">
<slot />
</div>
`,
})
Vue.component('app-btn', {
template: `
<component :is="tag" class="app-btn">
<span class="app-btn__content">
<span class="app-btn__icon" :class="icon" v-if="icon"></span>
<span class="app-btn__text">
<slot />
</span>
</span>
</component>
`,
props: {
tag: {
default: 'button'
},
icon: {
default: null
}
}
})
new Vue({
el: "#app",
data: {
plans: [
{ id:"basic_monthly", name: 'Básico', monthlySms: 200, price: 19, billingInterval: 1},
{ id:"basic_yearly", name: 'Básico', monthlySms: 200, price: 14, billingInterval: 12},
{ id:"standard_monthly", name: 'Standard', monthlySms: 400, price: 39, billingInterval: 1},
{ id:"standard_yearly", name: 'Standard', monthlySms: 400, price: 29, billingInterval: 12},
{ id:"pro_monthly", name: 'Pro', monthlySms: 800, price: 69, billingInterval: 1},
{ id:"pro_yearly", name: 'Pro', monthlySms: 800, price: 59, billingInterval: 12},
].map( plan...