File: //var/www/quadcode.com/src/components/blocks/main/Plans.svelte
<script lang="ts">
import { t } from '$lib/translations';
import close from '../../../assets/images/main/plans/close.svg';
import stick from '../../../assets/images/main/plans/stick.svg';
import { popupForm } from '../../../store';
import manager1 from '../../../assets/images/main/webinars/daniel.webp';
import manager1x2 from '../../../assets/images/main/webinars/daniel_x2.webp';
import manager2 from '../../../assets/images/main/webinars/ivan.webp';
import manager2x2 from '../../../assets/images/main/webinars/ivan_x2.webp';
const items = [
{
title: $t('Lite'),
tagline: $t('Early-stage projects and MVPs'),
price: '$17,500',
popular: false,
features: {
marginCFD: false,
connectingPSP: false,
mobileApps: false,
salesModule: false,
marketingModule: false,
affiliateModule: false,
advancedCustomization: false,
},
instruments: {
count: '50+',
otcAssets: true,
realAssets: false,
cryptoPSPs: true,
psps: null,
},
coreStructure: {
crm: true,
billing: true,
dealingDesk: true,
servers: true,
},
platform: {
webTraderoom: true,
liquidity: true,
},
compliance: {
kyc: true,
antifraud: true,
},
summary: $t('Brokerage starter pack with limited assets and PSPs. Web version only.'),
},
{
title: $t('Advanced'),
tagline: $t('Growing brokerages, ready to scale'),
price: '$37,000',
popular: false,
features: {
marginCFD: true,
connectingPSP: true,
mobileApps: false,
salesModule: false,
marketingModule: false,
affiliateModule: false,
advancedCustomization: false,
},
instruments: {
count: '850+',
otcAssets: true,
realAssets: true,
cryptoPSPs: false,
psps: '170',
},
coreStructure: {
crm: true,
billing: true,
dealingDesk: true,
servers: true,
},
platform: {
webTraderoom: true,
liquidity: true,
},
compliance: {
kyc: true,
antifraud: true,
},
summary: $t('Advanced brokerage platform with 170 pre-connected PSP and wider range of available assets.'),
},
{
title: $t('Full'),
tagline: $t('Full-service brokerage'),
price: '$50,000',
popular: true,
features: {
marginCFD: true,
connectingPSP: true,
mobileApps: true,
salesModule: true,
marketingModule: true,
affiliateModule: false,
advancedCustomization: false,
},
instruments: {
count: '850+',
otcAssets: true,
realAssets: true,
cryptoPSPs: false,
psps: '170',
},
coreStructure: {
crm: true,
billing: true,
dealingDesk: true,
servers: true,
},
platform: {
webTraderoom: true,
liquidity: true,
},
compliance: {
kyc: true,
antifraud: true,
},
summary: $t(
'Full brokerage setup with mobile applications, wide range of assets and PSPs, sales and affiliate module.'
),
},
{
title: $t('Prime'),
tagline: $t('Established brands'),
price: '$90,000',
popular: false,
features: {
marginCFD: true,
connectingPSP: true,
mobileApps: true,
salesModule: true,
marketingModule: true,
affiliateModule: true,
advancedCustomization: true,
},
instruments: {
count: '850+',
otcAssets: true,
realAssets: true,
cryptoPSPs: false,
psps: '170',
},
coreStructure: {
crm: true,
billing: true,
dealingDesk: true,
servers: true,
},
platform: {
webTraderoom: true,
liquidity: true,
},
compliance: {
kyc: true,
antifraud: true,
},
summary: $t(
'All-in-one solution with mobile applications, sales & affiliate module, advanced customization and all available features.'
),
},
];
let optionActive: null | number = null;
const handleClick = (id: number) => {
optionActive = id === optionActive ? null : id;
};
</script>
<div id="pricing" class="block-plans">
<div class="container">
<h2 class="block-plans__title">{$t('Pricing')}</h2>
<div class="block-plans__all-plans">
<h3 class="block-plans__all-plans-title">{$t('All plans are supported')}</h3>
<div class="block-plans__all-plans-content">
<div class="block-plans__all-plans-section">
<div class="block-plans__section-title">{$t('Core structure')}</div>
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('CRM and Backoffice')}</span>
</div>
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Billing processing backend')}</span>
</div>
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Dealing desk')}</span>
</div>
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Servers')}</span>
</div>
</div>
</div>
<div class="block-plans__all-plans-section">
<div class="block-plans__section-title">{$t('Platform & Trading')}</div>
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Web traderoom')}</span>
</div>
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Liquidity & Quotes')}</span>
</div>
</div>
</div>
<div class="block-plans__all-plans-section">
<div class="block-plans__section-title">{$t('Compliance & Security')}</div>
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('KYC')}</span>
</div>
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Antifraud')}</span>
</div>
</div>
</div>
<div class="block-plans__all-plans-section">
<div class="block-plans__section-title">{$t('Other')}</div>
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('OTC Assets')}</span>
</div>
</div>
</div>
</div>
</div>
<div class="block-plans__list">
{#each items as item, index}
<div class="block-plans__plan-wrapper">
{#if item.popular}
<div class="block-plans__popular-badge">{$t('Most popular')}</div>
{/if}
<div class="block-plans__plan {item.popular ? 'popular' : ''}">
<div class="block-plans__planHeader">
<p class="block-plans__planName">{item.title}</p>
<p class="block-plans__planTagline">{item.tagline}</p>
<div class="block-plans__planPrice">
<p class="block-plans__planPriceNumber">{item.price}</p>
</div>
<div
class="block-plans__planButton"
on:click={() => popupForm.set(true)}
on:keydown={(event) => {
if (event.key === 'Escape') {
popupForm.set(false);
}
}}
role="button"
tabindex="0"
>
{$t('Get started')}
</div>
</div>
<div class="block-plans__planContent {index === optionActive ? 'active' : ''}">
<div class="block-plans__section">
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img
src={item.features.marginCFD ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.features.marginCFD
? 'block-plans__feature-name--disabled'
: ''}">{$t('Margin CFD')}</span
>
</div>
<div class="block-plans__feature-item">
<img
src={item.features.connectingPSP ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.features.connectingPSP
? 'block-plans__feature-name--disabled'
: ''}">{$t('Connecting new PSP')}</span
>
</div>
<div class="block-plans__feature-item">
<img
src={item.features.mobileApps ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.features.mobileApps
? 'block-plans__feature-name--disabled'
: ''}">{$t('iOS & Android Apps')}</span
>
</div>
<div class="block-plans__feature-item">
<img
src={item.features.salesModule ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.features.salesModule
? 'block-plans__feature-name--disabled'
: ''}">{$t('Sales module')}</span
>
</div>
<div class="block-plans__feature-item">
<img
src={item.features.marketingModule ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.features.marketingModule
? 'block-plans__feature-name--disabled'
: ''}">{$t('Marketing module')}</span
>
</div>
<div class="block-plans__feature-item">
<img
src={item.features.affiliateModule ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.features.affiliateModule
? 'block-plans__feature-name--disabled'
: ''}">{$t('Affiliate module')}</span
>
</div>
<div class="block-plans__feature-item">
<img
src={item.features.advancedCustomization ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.features.advancedCustomization
? 'block-plans__feature-name--disabled'
: ''}">{$t('Advanced customization')}</span
>
</div>
</div>
</div>
<div class="block-plans__section {index === 0 ? 'block-plans__section--instruments' : ''}">
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{item.instruments.count} {$t('instruments')}</span>
</div>
<div class="block-plans__feature-item block-plans__feature-item--hide-mobile">
<img
src={item.instruments.otcAssets ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span
class="block-plans__feature-name {!item.instruments.otcAssets
? 'block-plans__feature-name--disabled'
: ''}">{$t('OTC Assets')}</span
>
</div>
{#if item.instruments.realAssets}
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Real Assets')}</span>
</div>
{/if}
{#if item.instruments.cryptoPSPs}
<div class="block-plans__feature-item {index > 0 ? 'block-plans__feature-item--hide-mobile' : ''}">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{$t('Crypto PSPs')}</span>
</div>
{/if}
{#if item.instruments.psps !== null}
<div class="block-plans__feature-item">
<img src={stick} alt="" class="block-plans__feature-icon" loading="lazy" />
<span class="block-plans__feature-name">{item.instruments.psps || '170'} {$t('PSPs')}</span>
</div>
{/if}
</div>
</div>
<div class="block-plans__section block-plans__section--hide-mobile">
<div class="block-plans__section-title">Core structure</div>
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img
src={item.coreStructure.crm ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('CRM and Backoffice')}</span>
</div>
<div class="block-plans__feature-item">
<img
src={item.coreStructure.billing ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('Billing processing backend')}</span>
</div>
<div class="block-plans__feature-item">
<img
src={item.coreStructure.dealingDesk ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('Dealing desk')}</span>
</div>
<div class="block-plans__feature-item">
<img
src={item.coreStructure.servers ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('Servers')}</span>
</div>
</div>
</div>
<div class="block-plans__section block-plans__section--no-border block-plans__section--hide-mobile">
<div class="block-plans__section-title">Platform & Trading</div>
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img
src={item.platform.webTraderoom ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('Web traderoom')}</span>
</div>
<div class="block-plans__feature-item">
<img
src={item.platform.liquidity ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('Liquidity & Quotes')}</span>
</div>
</div>
</div>
<div class="block-plans__section block-plans__section--no-border block-plans__section--hide-mobile">
<div class="block-plans__section-title">Compliance & Security</div>
<div class="block-plans__feature-list">
<div class="block-plans__feature-item">
<img
src={item.compliance.kyc ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('KYC')}</span>
</div>
<div class="block-plans__feature-item">
<img
src={item.compliance.antifraud ? stick : close}
alt=""
class="block-plans__feature-icon"
loading="lazy"
/>
<span class="block-plans__feature-name">{$t('Antifraud')}</span>
</div>
</div>
</div>
<div class="block-plans__summary">
{item.summary}
</div>
</div>
<div
class="block-plans__planOptionsBtn {item.popular ? 'white' : ''} {index === optionActive ? 'active' : ''}"
role="button"
tabindex="0"
on:click={() => handleClick(index)}
on:keydown={() => false}
>
<span>{index === optionActive ? 'Hide' : 'Details'}</span>
<svg width="23" height="22" viewBox="0 0 23 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" width="22" height="22" rx="11" fill="#323232" fill-opacity="0.05" />
<path d="M7.5 9L11.5 13L15.5 9" stroke="#141414" stroke-width="2" />
</svg>
</div>
</div>
</div>
{/each}
</div>
<div class="block-plans__cta">
<div class="block-plans__cta-content">
<div class="block-plans__cta-avatars">
<div class="block-plans__cta-avatar-wrapper">
<img src={manager1} srcset={`${manager1} 1x, ${manager1x2} 2x`} alt="" class="block-plans__cta-avatar" />
</div>
<div class="block-plans__cta-avatar-wrapper">
<img src={manager2} srcset={`${manager2} 1x, ${manager2x2} 2x`} alt="" class="block-plans__cta-avatar" />
</div>
</div>
<div class="block-plans__cta-text">
<h3 class="block-plans__cta-title">{$t('Want to learn more about our plans?')}</h3>
<p class="block-plans__cta-subtitle">{$t('Submit the form and our managers will get in touch with you')}</p>
</div>
</div>
<button
class="block-plans__cta-button"
on:click={() => popupForm.set(true)}
on:keydown={(event) => {
if (event.key === 'Escape') {
popupForm.set(false);
}
}}
>
{$t('Contact our managers')}
</button>
</div>
</div>
</div>
<style lang="scss">
@import 'src/scss/variables';
@import 'src/scss/media';
@import 'src/scss/mixins';
.block-plans {
padding: 120px 0;
background: $techWhite;
@media (max-width: 720px) {
padding: 88px 0px;
}
.container {
@media (max-width: 1366px) {
max-width: 1290px;
}
@media (max-width: 720px) {
padding: 0 32px;
}
@media (max-width: 480px) {
padding: 0 24px;
}
}
&__title {
text-align: center;
font-weight: 400;
font-size: 64px;
line-height: 72px;
width: 100%;
margin-bottom: 104px;
color: #1b1c1d;
@media (max-width: 1024px) {
font-size: 56px;
line-height: 68px;
}
@media (max-width: 720px) {
font-size: 52px;
line-height: 64px;
margin-bottom: 56px;
}
@media (max-width: 393px) {
font-size: 36px;
line-height: 44px;
}
}
&__list {
display: flex;
align-items: stretch;
gap: 24px;
@media (max-width: 1024px) {
gap: 8px;
}
@media (max-width: 800px) {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 88px 24px;
}
@media (max-width: 480px) {
grid-template-columns: 1fr;
gap: 24px;
}
}
&__plan-wrapper {
flex: 1;
position: relative;
display: flex;
flex-direction: column;
&:has(.popular) {
@media (max-width: 480px) {
margin-top: 54px;
}
}
}
&__plan {
flex: 1;
height: 1192px;
border-radius: 32px;
border: 1px solid #d4d8db;
background: $techWhite;
padding: 24px;
position: relative;
display: flex;
flex-direction: column;
@media (max-width: 1024px) {
padding: 20px;
}
@media (max-width: 720px) {
padding: 24px 20px;
}
&.popular {
border: 2px solid #ff282b;
z-index: 2;
}
}
&__popular-badge {
position: absolute;
top: -40px;
left: 50%;
transform: translateX(-50%);
background: #fee7e4;
color: $redPrimary;
padding: 12px 16px 32px 16px;
border-radius: 24px 24px 0px 0px;
font-size: 16px;
line-height: 24px;
font-weight: 500;
letter-spacing: 0.5px;
width: 100%;
z-index: 1;
text-align: center;
}
&__planHeader {
margin-bottom: 24px;
@media (max-width: 1024px) {
margin-bottom: 28px;
}
@media (max-width: 720px) {
margin-bottom: 20px;
}
}
&__planName {
font-size: 32px;
line-height: 40px;
margin-bottom: 12px;
color: $fontPrimary;
@media (max-width: 1024px) {
font-size: 28px;
line-height: 36px;
}
@media (max-width: 720px) {
font-size: 24px;
line-height: 28px;
}
@media (max-width: 393px) {
font-size: 20px;
line-height: 26px;
}
}
&__planTagline {
font-size: 16px;
line-height: 20px;
color: #525659;
margin-bottom: 20px;
min-height: 60px;
@media (max-width: 720px) {
font-size: 14px;
}
}
&__planPriceNumber {
font-size: 24px;
line-height: 32px;
margin-bottom: 24px;
color: $fontPrimary;
@media (max-width: 1024px) {
margin-bottom: 28px;
}
@media (max-width: 720px) {
margin-bottom: 20px;
}
@media (max-width: 393px) {
font-size: 20px;
line-height: 26px;
}
}
&__planButton {
cursor: pointer;
border-radius: 64px;
font-size: 14px;
line-height: 20px;
background: #ff282b;
color: $techWhite;
border: none;
padding: 8px 16px;
width: fit-content;
transition: background 0.2s ease;
&:hover {
background: #e60019;
}
&:active {
background: #c70214;
}
}
&__planContent {
flex: 1;
display: block;
&.active {
display: block;
}
}
&__section {
margin-bottom: 24px;
@media (max-width: 1024px) {
margin-bottom: 30px;
}
@media (max-width: 720px) {
margin-bottom: 20px;
}
&:first-child {
margin-bottom: 24px;
@media (max-width: 720px) {
margin-bottom: 20px;
}
}
&:not(:first-child):not(&--no-border) {
padding-top: 24px;
border-top: 1px solid #d4d8db;
@media (max-width: 1024px) {
padding-top: 30px;
}
@media (max-width: 720px) {
padding-top: 20px;
}
}
&--no-border {
padding-top: 0;
border-top: none;
}
// Разобраться как сделать по другому
&--instruments {
margin-bottom: 54px;
@media (max-width: 1024px) {
margin-bottom: 64px;
}
@media (max-width: 480px) {
margin-bottom: 20px;
}
}
&--hide-mobile {
@media (max-width: 720px) {
display: none;
}
}
&:last-child {
margin-bottom: 0;
}
}
&__feature-item {
&--hide-mobile {
@media (max-width: 720px) {
display: none !important;
}
}
}
&__all-plans {
display: none;
background-color: #f2f5f7;
@media (max-width: 720px) {
display: block;
border-radius: 32px;
padding: 24px;
margin-bottom: 32px;
}
}
&__all-plans-title {
font-size: 24px;
line-height: 32px;
font-weight: 400;
color: $fontPrimary;
margin-bottom: 24px;
@media (max-width: 393px) {
font-size: 20px;
line-height: 26px;
}
}
&__all-plans-content {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 28px;
}
&__all-plans-section {
display: flex;
flex-direction: column;
}
&__section-title {
font-size: 16px;
line-height: 20px;
color: #7d8387;
margin-bottom: 16px;
@media (max-width: 720px) {
font-size: 14px;
}
}
&__feature-list {
display: flex;
flex-direction: column;
gap: 6px;
@media (max-width: 1024px) {
gap: 10px;
}
}
&__feature-item {
display: flex;
align-items: center;
gap: 8px;
position: relative;
padding-left: 26px;
}
&__feature-name {
font-size: 16px;
line-height: 24px;
color: $fontPrimary;
&--disabled {
color: #7d8387;
}
}
&__feature-icon {
position: absolute;
left: -2px;
width: 24px;
height: 24px;
flex-shrink: 0;
}
&__summary {
font-size: 16px;
line-height: 24px;
color: #525659;
padding-top: 24px;
color: #7d8387;
border-top: 1px solid #d4d8db;
@media (max-width: 720px) {
padding-top: 20px;
letter-spacing: -0.1px;
}
}
&__planOptionsBtn {
align-items: center;
gap: 10px;
width: max-content;
margin-inline: auto;
display: none;
cursor: pointer;
padding: 8px 0;
font-size: 14px;
line-height: 20px;
color: $fontPrimary;
&.white {
color: white;
svg {
path {
stroke: $techWhite;
}
}
}
&.active {
> svg {
transform: rotate(180deg);
}
}
}
&__cta {
display: flex;
align-items: center;
gap: 20px;
background: $techWhite;
border-radius: 32px;
padding: 24px;
margin-top: 56px;
background-color: #f9fbfc;
@media (max-width: 1366px) {
background-color: #f2f5f7;
}
@media (max-width: 720px) {
flex-direction: column;
align-items: flex-start;
gap: 32px;
}
@media (max-width: 480px) {
padding: 32px 24px;
margin-top: 24px;
}
}
&__cta-content {
display: flex;
align-items: center;
gap: 20px;
flex: 1;
@media (max-width: 720px) {
gap: 16px;
}
@media (max-width: 480px) {
flex-direction: column;
align-items: flex-start;
}
}
&__cta-avatars {
display: flex;
align-items: center;
}
&__cta-avatar-wrapper {
width: 64px;
height: 64px;
border-radius: 50%;
border: 2px solid $techWhite;
overflow: hidden;
position: relative;
flex-shrink: 0;
&:first-child {
z-index: 1;
}
&:last-child {
margin-left: -14px;
z-index: 2;
}
}
&__cta-avatar {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
&__cta-text {
flex: 1;
}
&__cta-title {
font-size: 20px;
line-height: 28px;
font-weight: 400;
color: #1b1c1d;
margin-bottom: 4px;
@media (max-width: 1024px) {
font-size: 18px;
line-height: 26px;
}
}
&__cta-subtitle {
font-size: 16px;
line-height: 24px;
color: #7d8387;
}
&__cta-button {
cursor: pointer;
border-radius: 48px;
font-size: 14px;
line-height: 20px;
color: $fontPrimary;
background: transparent;
border: 1px solid #d4d8db;
padding: 8px 14px;
transition: all 0.2s ease;
position: relative;
display: flex;
align-items: center;
gap: 8px;
&:hover {
background: #d4d8db;
border-color: transparent;
}
&:active {
background: #adb1b7;
border-color: transparent;
}
&::after {
content: '';
display: none;
width: 10px;
height: 10px;
background: url('../../../assets/icons/arrow-right.svg') center/contain no-repeat;
}
@media (max-width: 1366px) {
&::after {
display: block;
}
}
}
}
</style>