First Commit

This commit is contained in:
cesnimda
2026-03-21 11:55:27 +01:00
commit 2e8a29b4d0
1757 changed files with 166084 additions and 0 deletions
@@ -0,0 +1,22 @@
// @project
import { Clientele3 } from '@/blocks/clientele';
import { DynamicComponentType } from '@/enum';
/*************************** CLIENTELE 3 - DATA ***************************/
const data = {
title: '4,000+ companies already growing',
clienteleList: [
{ image: { component: 'clientele/Techlify', type: DynamicComponentType.IMAGE } },
{ image: { component: 'clientele/Marketly', type: DynamicComponentType.IMAGE } },
{ image: { component: 'clientele/Realtor', type: DynamicComponentType.IMAGE } },
{ image: { component: 'clientele/Financely', type: DynamicComponentType.IMAGE } },
{ image: { component: 'clientele/Realtor', type: DynamicComponentType.IMAGE } }
]
};
/*************************** BLOCK - CLIENTELE 3 ***************************/
export default function BlockClientele3() {
return <Clientele3 {...data} />;
}
@@ -0,0 +1,35 @@
// @project
import { ContactUs4 } from '@/blocks/contact-us';
/*************************** CONTACT US 4 - DATA ***************************/
const data = {
heading: 'Wed love to hear from you',
caption: 'Explore key statistics and trends shaping our understanding of the current landscape.',
list: [
{
icon: 'tabler-phone',
title: 'Contact Sale',
content: 'Speak to someone from our sales team.',
link: { children: 'Contact Sales' }
},
{
icon: 'tabler-help-circle',
title: 'Have a Question',
content: 'See our frequently asked question',
link: { children: 'Get Answers' }
},
{
icon: 'tabler-folder-check',
title: 'Press & Media',
content: 'Get in touch with our PR team',
link: { children: 'Press Contact' }
}
]
};
/*************************** BLOCK - CONTACT US 4 ***************************/
export default function BlockContactUs4() {
return <ContactUs4 {...data} />;
}
@@ -0,0 +1,45 @@
// @mui
import Typography from '@mui/material/Typography';
// @project
import branding from '@/branding.json';
import { Cta4 } from '@/blocks/cta';
/*************************** CALL TO ACTION 4 - HEADLINE ***************************/
function HeadlineText() {
return (
<Typography variant="h2">
Enhance performance{' '}
<Typography variant="h2" component="span" sx={{ color: 'text.secondary' }}>
and efficiency. Dive into {branding.brandName} for a{' '}
</Typography>
better cloud experience.
</Typography>
);
}
/*************************** CALL TO ACTION 4 - DATA ***************************/
const data = {
headLine: <HeadlineText />,
primaryBtn: { children: 'Get Started' },
profileGroups: {
avatarGroups: [
{ avatar: '/assets/images/user/avatar1.png' },
{ avatar: '/assets/images/user/avatar2.png' },
{ avatar: '/assets/images/user/avatar3.png' },
{ avatar: '/assets/images/user/avatar4.png' },
{ avatar: '/assets/images/user/avatar5.png' }
],
review: '10k+ Reviews (4.5 out of 5)'
},
list: [{ primary: `Automated Scaling for Efficiency` }, { primary: 'Real-time Performance Insights' }],
clientContent: '300+ Client Trust Us'
};
/*************************** BLOCK - CALL TO ACTION 4 ***************************/
export default function BlockCta4() {
return <Cta4 {...data} />;
}
@@ -0,0 +1,32 @@
// @project
import branding from '@/branding.json';
import { Cta5 } from '@/blocks/cta';
/*************************** CALL TO ACTION 5 - DATA ***************************/
const data = {
heading: `${branding.brandName} Community`,
caption: 'Collaborate confidently with granular access controls and regulatory compliance. ',
label: 'Join Community',
input: {
adornmentBtn: { children: 'Get Started' },
helpertext: '1 email per week. No spam. Ever. Unsubscribe anytime'
},
saleData: { count: 10, defaultUnit: 'X', caption: 'Achieving faster sales through streamlined' },
profileGroups: {
avatarGroups: [
{ avatar: '/assets/images/user/avatar1.png' },
{ avatar: '/assets/images/user/avatar2.png' },
{ avatar: '/assets/images/user/avatar3.png' },
{ avatar: '/assets/images/user/avatar4.png' },
{ avatar: '/assets/images/user/avatar5.png' }
],
review: '10k+ Reviews (4.5 out of 5)'
}
};
/*************************** BLOCK - CALL TO ACTION 5 ***************************/
export default function BlockCta5() {
return <Cta5 {...data} />;
}
@@ -0,0 +1,20 @@
// @project
import { Error404Page } from '@/blocks/maintenance';
import { SEO_CONTENT } from '@/metadata';
/*************************** METADATA - ERROR 404 ***************************/
export const metadata = { ...SEO_CONTENT.error404Page };
/*************************** ERROR 404 - DATA ***************************/
const data = {
primaryBtn: { children: 'Back to Home Page', href: '/' },
heading: `Looks like you've taken a wrong turn. Lets get you back on track!`
};
/*************************** BLOCK - ERROR 404 ***************************/
export default function BlockError404Page() {
return <Error404Page {...data} />;
}
@@ -0,0 +1,20 @@
// @project
import { Error500Page } from '@/blocks/maintenance';
import { SEO_CONTENT } from '@/metadata';
/*************************** METADATA - ERROR 500 ***************************/
export const metadata = { ...SEO_CONTENT.error500Page };
/*************************** ERROR 500 - DATA ***************************/
const data = {
primaryBtn: { children: 'Back to Home Page', href: '/' },
heading: 'Please try again later or feel free to contact us if the problem persists.'
};
/*************************** BLOCK - ERROR 500 ***************************/
export default function BlockError500Page() {
return <Error500Page {...data} />;
}
@@ -0,0 +1,110 @@
// @project
import branding from '@/branding.json';
import { Faq6 } from '@/blocks/faq';
/*************************** FAQ 6 - DATA ***************************/
const data = {
heading: 'Frequently Asked Questions',
caption: `Answers to common queries about ${branding.brandName}.`,
defaultExpanded: 'Fees & Charges',
faqList: [
{
question: `Is ${branding.brandName} only for SaaS web apps?`,
answer: `While ${branding.brandName} is designed with SaaS applications in mind, its not limited to SaaS products. ${branding.brandName} is multipurpose and can be used for a variety of websites and applications, whether its for an agency, digital product, CRM, blog, AI platform, or any other system. ${branding.brandName} is versatile and adaptable to fit any use case, SaaS or not. Its built for all types of projects!`,
category: 'General'
},
{
question: `What makes ${branding.brandName} different from other UI Kits?`,
answer: `${branding.brandName} offers industry-specific templates, a React Material UI Kit, Figma UI Kit, and flexible customization options that cater to both front-end marketing and admin interfaces.`,
category: 'General'
},
{
question: `Is ${branding.brandName} suitable for both developers and designers?`,
answer: {
content: `Yes, ${branding.brandName} is built for both, with a Figma UI kit for designers and React code for developers.`,
type: 'list',
data: [
{ primary: 'Figma UI Kit for Designers.' },
{ primary: 'React Material UI Code for Developers.' },
{ primary: 'Seamless Collaboration.' }
]
},
category: 'General'
},
{
question: `What is the difference between the Figma and codebase versions?`,
answer:
'The Figma version is for design and prototyping, while the codebase version provides ready-to-use React components for development.',
category: 'General'
},
{
question: 'How can I download the template after purchase?',
answer: 'You will receive the template in a .zip format immediately after successfully purchasing the template.',
category: 'General'
},
{
question: `What's included in the ${branding.brandName} license?`,
answer: {
content: 'It includes the Figma UI kit, React Material UI codebase, regular updates, and customer support.',
type: 'list',
data: [
{ primary: `One License = One End Product` },
{ primary: `Separate License for Each Product` },
{ primary: `Comply with License Terms` }
]
},
category: 'Pricing & Licenses'
},
{
question: `Can I use ${branding.brandName} for multiple projects?`,
answer: {
content:
'No, one license allows usage in a single end product. For each new product or project, you are required to purchase a separate license. This ensures compliance with the licensing terms and provides ongoing support for each individual product. Make sure to obtain the appropriate license for every new project you work on.',
type: 'list',
data: [
{ primary: `One License = One End Product` },
{ primary: `Separate License for Each Product` },
{ primary: `Comply with License Terms` }
]
},
category: 'Pricing & Licenses'
},
{
question: 'Do you offer refunds?',
answer:
'Yes, we offer refunds, but only if you provide a valid reason to support your claim. For more details, please review our MUI Store Refund Policy.',
category: 'Pricing'
},
{
question: 'Do I get access to future updates?',
answer: {
content:
'Yes, you will receive future updates for 1 year from the date of purchase. If you need updates after 1 year, you will need to purchase the license again. However, this is not a renewal—your license is valid for a lifetime, but updates are limited to the 1-year period.',
type: 'list',
data: [{ primary: `1 Year Free Updates` }, { primary: `License validity is lifetime` }]
},
category: 'Support & Updates'
},
{
question: 'Is support included with the template purchase?',
answer: {
content:
'Support is included for 6 months, but it is limited to resolving issues within the template itself. We do not provide support for installation, customization queries, or troubleshooting unrelated issues. For ongoing support beyond 6 months, you will need to extend the support period with an additional purchase.',
type: 'list',
data: [{ primary: `6 Months Support` }, { primary: `No Installation Support` }, { primary: `No Customization Support` }]
},
category: 'Support & Updates'
}
],
getInTouch: { link: { children: 'Get in Touch' } },
categories: ['General', 'Pricing & Licenses', 'Support & Updates'],
activeCategory: 'General'
};
/*************************** FAQ - 6 ***************************/
export default function BlockFaq6() {
return <Faq6 {...data} />;
}
@@ -0,0 +1,62 @@
// @project
import { Feature18 } from '@/blocks/feature';
/*************************** FEATURE 18 - DATA ***************************/
const data = {
heading: 'Dynamic Task Automation',
caption: 'Gain insights into performance metrics and proactively address issues for uninterrupted operations.',
topics: [
{
icon: 'tabler-sparkles',
title: 'AI Assistant',
title2: 'Advanced AI Integration',
description: 'Leverage cutting-edge AI to enhance decision-making and streamline operations.',
image: '/assets/images/graphics/ai/graphics12-light.svg',
list: [
{ primary: 'Intelligent Decision Support' },
{ primary: 'Predictive Analytics' },
{ primary: 'Natural Language Processing' },
{ primary: 'Real-time Insights' }
],
actionBtn: { children: 'Explore all Features' },
actionBtn2: { children: 'Customize' }
},
{
icon: 'tabler-chart-histogram',
title: 'Simple Analysis',
title2: 'Data Lifecycle Management',
description: 'Process data in parallel, significantly boosting data processing speed.',
image: '/assets/images/graphics/ai/graphics7-light.svg',
list: [{ primary: 'Fortress for Your Data' }, { primary: 'Granular Access Controls' }, { primary: 'Automated Backup Solutions' }],
actionBtn: { children: 'Explore all Features' },
actionBtn2: { children: 'Customize' }
},
{
icon: 'tabler-users',
title: 'Easy Collaboration',
title2: 'Seamless Teamwork',
description: 'Foster collaboration with intuitive tools designed for team success.',
image: '/assets/images/graphics/ai/graphics4-light.svg',
list: [{ primary: 'Shared Workspaces' }, { primary: 'Real-time Collaboration' }, { primary: 'Task Assignment and Tracking' }],
actionBtn: { children: 'Explore all Features' },
actionBtn2: { children: 'Customize' }
},
{
icon: 'tabler-settings-up',
title: 'Smart Automation',
title2: 'Intelligent Task Management',
description: 'Automate repetitive tasks and focus on what truly matters with smart solutions.',
image: '/assets/images/graphics/ai/graphics9-light.svg',
list: [{ primary: 'Workflow Automation' }, { primary: 'Trigger-based Actions' }, { primary: 'Scalable Solutions' }],
actionBtn: { children: 'Explore all Features' },
actionBtn2: { children: 'Customize' }
}
]
};
/*************************** BLOCK - FEATURE 18 ***************************/
export default function BlockFeature18() {
return <Feature18 {...data} />;
}
@@ -0,0 +1,49 @@
// @project
import { Feature20 } from '@/blocks/feature';
/*************************** FEATURE 20 - DATA ***************************/
const data = {
heading: 'Intelligent Data Compression',
caption: 'Process data faster, enhance system, and gain quicker insights.',
image: '/assets/images/graphics/ai/graphics4-light.svg',
actionBtn: { children: 'Explore all Features' },
features: [
{
icon: 'tabler-chart-histogram',
title: 'Parallel Processing',
content: 'Process data in parallel, significantly boosting data processing speed.'
},
{
icon: 'tabler-artboard',
title: 'Scalable Data Pipelines',
content: 'Build and manage scalable and efficient data processing pipelines.'
},
{
icon: 'tabler-database',
title: 'Data Quality Assurance',
content: 'Tools to ensure and maintain high data quality and integrity.'
},
{
icon: 'tabler-settings-up',
title: 'Dynamic Task Automation',
content: 'Automate dynamic tasks to enhance workflow efficiency.'
},
{
icon: 'tabler-devices-code',
title: 'Cross-Platform ',
content: 'Compatibility with various platforms for versatile data processing.'
},
{
icon: 'tabler-route',
title: 'Workflow Optimization',
content: 'Optimize workflows for increased productivity and efficiency.'
}
]
};
/*************************** BLOCK - FEATURE 20 ***************************/
export default function BlockFeature20() {
return <Feature20 {...data} />;
}
@@ -0,0 +1,53 @@
// @project
import branding from '@/branding.json';
import { Feature21 } from '@/blocks/feature';
/*************************** FEATURE 21 - DATA ***************************/
const data = {
heading: `Unlock the Power of ${branding.brandName}`,
caption: 'Discover the myriad benefits that come with our innovative platform.',
image: '/assets/images/graphics/ai/desktop1-light.svg',
primaryBtn: { children: 'Buy Now' },
secondaryBtn: { children: 'Get free figma' },
features: [
{
icon: 'tabler-app-window',
title: 'Tested in multiple browsers'
},
{
icon: 'tabler-box-model',
title: 'Ready to use template'
},
{
icon: 'tabler-folder-check',
title: 'Always updated package'
},
{
icon: 'tabler-code',
title: 'Optimised code structure'
},
{
icon: 'tabler-lock',
title: 'Pre Define Authentication'
},
{
icon: 'tabler-git-branch',
title: 'Clean folder structure to adapt'
},
{
icon: 'tabler-toggle-right',
title: 'Easy to switch themes'
},
{
icon: 'tabler-components',
title: 'Pluggable components'
}
]
};
/*************************** BLOCK - FEATURE 21 ***************************/
export default function BlockFeature21() {
return <Feature21 {...data} />;
}
@@ -0,0 +1,8 @@
// @project
import { Footer7 } from '@/blocks/footer';
/*************************** BLOCK - FOOTER 7 ***************************/
export default function BlockFooter7() {
return <Footer7 />;
}
@@ -0,0 +1,58 @@
// @mui
import CardMedia from '@mui/material/CardMedia';
import Chip from '@mui/material/Chip';
import Typography from '@mui/material/Typography';
// @project
import { Hero17 } from '@/blocks/hero';
/*************************** HERO 17 - DATA ***************************/
const data = {
chip: {
label: (
<>
<Typography variant="caption" sx={{ color: 'text.secondary' }}>
Over 200+
</Typography>
<Chip
label={
<Typography variant="caption" sx={{ color: 'primary.main' }}>
Design Blocks
</Typography>
}
sx={{ height: 24, bgcolor: 'primary.lighter', mr: -1, ml: 0.75, '& .MuiChip-label': { px: 1.25 } }}
icon={
<CardMedia
component="img"
image="/assets/images/shared/celebration.svg"
sx={{ width: 16, height: 16 }}
alt="celebration"
loading="lazy"
/>
}
/>
</>
)
},
headLine: 'Real-time Performance Monitoring',
captionLine: 'Identify and resolve issues proactively for uninterrupted operations.',
primaryBtn: { children: 'Try Predictive Cost Analytics' },
videoSrc: 'https://d2elhhoq00m1pj.cloudfront.net/saasable-intro.mp4',
videoThumbnail: '/assets/videos/thumbnails/intro-thumbnail.png',
listData: [
{ image: '/assets/images/shared/react.svg', title: 'React 19' },
{ image: '/assets/images/shared/next-js.svg', title: 'Next.js' },
{ image: '/assets/images/shared/material-ui.svg', title: 'Material UI v7' },
{ image: '/assets/images/shared/typescript.svg', title: 'TypeScript' },
{ image: '/assets/images/shared/javascript.svg', title: 'JavaScript' },
{ image: '/assets/images/shared/m3.svg', title: 'Material 3' },
{ image: '/assets/images/shared/figma.svg', title: 'Figma' }
]
};
/*************************** BLOCK - HERO 17 ***************************/
export default function BlockHero17() {
return <Hero17 {...data} />;
}
@@ -0,0 +1,29 @@
// @project
import { Integration2 } from '@/blocks/integration';
/*************************** INTEGRATION 2 - DATA ***************************/
const data = {
headLine: 'Connect with top-tier tools available Interface',
captionLine: 'Discover the features that will transform your customer relationships',
primaryBtn: { children: 'See All Integration' },
tagList: [
{ label: 'Slack', icon: 'tabler-brand-slack' },
{ label: 'Abstract', icon: 'tabler-brand-abstract' },
{ label: 'Asana', icon: 'tabler-brand-asana' },
{ label: 'Back Bone', icon: 'tabler-brand-backbone' },
{ label: 'Intercom', icon: 'tabler-brand-intercom' },
{ label: 'Master Card', icon: 'tabler-brand-mastercard' },
{ label: 'Skype', icon: 'tabler-brand-skype' },
{ label: 'Google Drive', icon: 'tabler-brand-google-drive' },
{ label: 'Tripadvisor', icon: 'tabler-brand-tripadvisor' },
{ label: 'Facebook Messenger', icon: 'tabler-brand-messenger' },
{ label: 'Paypal', icon: 'tabler-brand-paypal' }
]
};
/*************************** BLOCK - INTEGRATION 2 ***************************/
export default function BlockIntegration2() {
return <Integration2 {...data} />;
}
@@ -0,0 +1,14 @@
'use client';
import PropTypes from 'prop-types';
// @mui
import Box from '@mui/material/Box';
/*************************** LAYOUT - BLOCKS ***************************/
export default function Blocks({ children }) {
return <Box sx={{ '& :focus-visible': { outline: 'none' } }}>{children}</Box>;
}
Blocks.propTypes = { children: PropTypes.any };
@@ -0,0 +1,80 @@
// @mui
import Button from '@mui/material/Button';
import CardMedia from '@mui/material/CardMedia';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @project
import branding from '@/branding.json';
import { MegaMenu4 } from '@/blocks/mega-menu';
import { MenuPopper } from '@/components/navbar';
import { landings } from '@/data/landings';
import { BUY_NOW_URL } from '@/path';
/*************************** MEGAMENU 4 - FOOTER ***************************/
function footerData() {
return (
<Stack direction={{ sm: 'row' }} sx={{ gap: 1.5, justifyContent: 'space-between', alignItems: { xs: 'flex-start', sm: 'center' } }}>
<Stack sx={{ gap: 1 }}>
<Stack direction="row" sx={{ alignItems: 'center', gap: 1 }}>
<Typography variant="h5">Explore our range of landing demos tailored to suit your needs</Typography>
<Chip
label={<Typography variant="caption">Featured</Typography>}
size="small"
sx={{
bgcolor: 'background.default',
'& .MuiChip-label': { px: 1.5, py: 0.5 },
display: { xs: 'none', sm: 'inline-flex' }
}}
icon={
<CardMedia
component="img"
image="/assets/images/shared/celebration.svg"
sx={{ width: 16, height: 16 }}
alt="celebration"
loading="lazy"
/>
}
/>
</Stack>
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
{branding.brandName} offers 200+ customizable blocks, empowering you to effortlessly design and build landing pages tailored to
your product or service needs.
</Typography>
</Stack>
<Button
variant="contained"
sx={{ display: { xs: 'none', sm: 'inline-flex' }, minWidth: 100, px: { xs: 2 }, py: 1.25 }}
href={BUY_NOW_URL}
target="_blank"
rel="noopener noreferrer"
>
Buy Now
</Button>
</Stack>
);
}
/*************************** MEGAMENU 4 - DATA ***************************/
const data = {
menuItems: landings,
footerData: footerData()
};
/*************************** BLOCK - MEGAMENU 4 ***************************/
export default function BlockMegamenu4() {
return (
<Stack sx={{ alignItems: 'center' }}>
<Box sx={{ my: 4 }}>
<MenuPopper toggleProps={{ children: 'Mega Menu 4' }} defaultOpen popperWidth={936} offset={8}>
<MegaMenu4 {...data} />
</MenuPopper>
</Box>
</Stack>
);
}
@@ -0,0 +1,99 @@
// @mui
import Button from '@mui/material/Button';
import CardMedia from '@mui/material/CardMedia';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @project
import { MegaMenu5 } from '@/blocks/mega-menu';
import { MenuPopper } from '@/components/navbar';
import { BUY_NOW_URL, DOCS_URL } from '@/path';
/*************************** MEGAMENU 5 - BANNER ***************************/
function bannerData() {
return (
<Stack sx={{ alignItems: 'flex-start', gap: 3, height: 1, justifyContent: 'center' }}>
<Stack sx={{ gap: 1 }}>
<Stack sx={{ alignItems: 'flex-start', gap: 1.5 }}>
<Chip
label={<Typography variant="subtitle2">Coming Soon</Typography>}
icon={
<CardMedia
component="img"
image="/assets/images/shared/celebration.svg"
sx={{ width: 16, height: 16 }}
alt="celebration"
loading="lazy"
/>
}
size="small"
sx={{ bgcolor: 'background.default', '& .MuiChip-label': { px: 1.5, py: 0.5 }, '& .MuiChip-icon': { ml: 1.25 } }}
/>
<Typography variant="h5">We are coming with many more landings</Typography>
</Stack>
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
Discover tailored solutions to elevate your business. Stay ahead with our latest updates and insights.
</Typography>
</Stack>
<Button
variant="contained"
sx={{ minWidth: 92, px: { xs: 2 }, py: 1.25 }}
href={BUY_NOW_URL}
target="_blank"
rel="noopener noreferrer"
>
Buy Now
</Button>
</Stack>
);
}
/*************************** MEGAMENU 5 - DATA ***************************/
const data = {
menuItems: [
{
title: 'General',
itemsList: [
{ title: 'About', status: 'Pro' },
{ title: 'Career', status: 'Pro' },
{ title: 'FAQs', status: 'Pro' },
{ title: 'Privacy Policy', link: { href: '/privacy-policy', target: '_blank' } },
{ title: 'Contact Us', link: { href: '/contact', target: '_blank' } },
{ title: 'Coming Soon', status: 'Pro' },
{ title: 'Error 404', link: { href: '/blocks/error404', target: '_blank' } }
]
},
{
title: 'External',
itemsList: [
{ title: 'Blog', link: { href: 'https://blog.saasable.io/', target: '_blank' } },
{ title: 'Documentation', link: { href: DOCS_URL, target: '_blank' } },
{ title: 'Support', link: { href: 'https://codedthemes.support-hub.io/', target: '_blank' } },
{
title: 'Discord',
link: { href: 'https://discord.com/invite/2WpeGsQH98', target: '_blank' }
},
{ title: 'Terms & Conditions', link: { href: 'https://mui.com/store/terms/', target: '_blank' } }
]
}
],
bannerData: bannerData()
};
/*************************** BLOCK - MEGAMENU 5 ***************************/
export default function BlockMegamenu5() {
return (
<Stack sx={{ alignItems: 'center' }}>
<Box sx={{ my: 4 }}>
<MenuPopper toggleProps={{ children: 'Mega Menu 5' }} defaultOpen popperWidth={750} offset={8}>
<MegaMenu5 {...data} />
</MenuPopper>
</Box>
</Stack>
);
}
@@ -0,0 +1,22 @@
// @project
import branding from '@/branding.json';
import { Metrics5 } from '@/blocks/metrics';
/*************************** BENEFIT 5 - DATA ***************************/
const data = {
heading: 'Data Processing at its Peak',
caption: `See the success stories of organizations scaling with ${branding.brandName}`,
blockDetail: [
{ counter: 99, defaultUnit: '%', caption: 'Compression Efficiency Achieved' },
{ counter: 40, defaultUnit: '%', caption: 'Reduction in Storage Costs' },
{ counter: 80, defaultUnit: '%', caption: 'Reduction in Over-Provisioning' },
{ counter: 4.5, defaultUnit: '/5', caption: 'Average User Satisfaction Rating' }
]
};
/*************************** BLOCK - METRICS 5 ***************************/
export default function BlockMetrics5() {
return <Metrics5 {...data} />;
}
@@ -0,0 +1,66 @@
// @project
import { Other2 } from '@/blocks/other';
import { Navbar10 } from '@/blocks/navbar';
import { NavbarContent10 } from '@/blocks/navbar/navbar-content';
import { MegaMenuType } from '@/enum';
/*************************** NAVBAR 10 - DATA ***************************/
const navbar = {
primaryBtn: { children: 'Get Started' },
secondaryBtn: { children: 'Sign in' },
navItems: [
{ id: 'overview', title: 'Overview' },
{ id: 'products', title: 'Products' },
{ id: 'pricing', title: 'Pricing' },
{
id: 'resource',
title: 'Resource',
megaMenu: {
type: MegaMenuType.MEGAMENU2,
toggleBtn: { children: 'Resource', size: 'small', sx: { color: 'text.primary', py: 1.5 } },
menuItems: [
{
title: 'Blog',
content: 'Explore our latest articles and insights.'
},
{
title: 'Help Center',
content: 'Find answers to common questions and support topics.',
selected: true
},
{
title: 'Guides',
content: 'Follow our comprehensive guides to get started.'
},
{
title: 'Events',
content: 'Stay informed about upcoming events and webinars.'
},
{
title: 'Security',
content: 'Learn about our security measures to protect your data.'
},
{
title: 'Payments',
content: 'Get help with billing and payment options.'
}
]
}
},
{ id: 'help', title: 'Help', icon: 'tabler-help' }
]
};
/*************************** BLOCK - NAVBAR 10 ***************************/
export default function BlockNavbar10() {
return (
<>
<Navbar10>
<NavbarContent10 {...navbar} />
</Navbar10>
<Other2 />
</>
);
}
@@ -0,0 +1,58 @@
// @project
import Other1 from '@/blocks/other/Other1';
import { PAGE_PATH, SECTION_PATH } from '@/path';
// @asssets
const imagePrefix = '/assets/images/presentation';
/*************************** OTHER 1 - DATA ***************************/
const data = {
heading: 'Customizable Building Blocks',
description: 'Kickstart your SaaS landing page design with pre-designed templates featuring versatile components.',
primaryBtn: { children: 'Explore all Blocks', href: SECTION_PATH },
sections: [
{
title: 'Hero',
subTitle: '17 Different Variants',
image: `${imagePrefix}/hero-light.svg`,
link: PAGE_PATH.hero
},
{
title: 'Call to Action',
subTitle: '12 Different Variants',
image: `${imagePrefix}/cta-light.svg`,
link: PAGE_PATH.cta
},
{
title: 'Feature',
subTitle: '23 Different Variants',
image: `${imagePrefix}/feature-light.svg`,
link: PAGE_PATH.feature
},
{
title: 'Metrics',
subTitle: '9 Different Variants',
image: `${imagePrefix}/metrics-light.svg`,
link: PAGE_PATH.metrics
},
{
title: 'Process',
subTitle: '7 Different Variants',
image: `${imagePrefix}/process-light.svg`,
link: PAGE_PATH.process
},
{
title: 'Integration',
subTitle: '8 Different Variants',
image: `${imagePrefix}/integration-light.svg`,
link: PAGE_PATH.integration
}
]
};
/*************************** BLOCK - OTHER 1 ***************************/
export default function BlockOther1() {
return <Other1 {...data} />;
}
@@ -0,0 +1,8 @@
// @project
import Other2 from '@/blocks/other/Other2';
/*************************** BLOCK - OTHER 2 ***************************/
export default function BlockOther2() {
return <Other2 />;
}
@@ -0,0 +1,45 @@
// @project
import { Pricing9 } from '@/blocks/pricing';
/*************************** PRICING 9 - DATA ***************************/
const data = {
heading: 'The Affordable Unfair Advantage',
caption: 'Choose the plan that aligns with your cloud management requirements.',
features: [
{ id: 1, label: '1 Demo Landing' },
{ id: 2, label: '7 Demo Landing' },
{ id: 3, label: '25 Components Blocks' },
{ id: 4, label: '193+ Component Blocks' },
{ id: 5, label: 'Dark/Light Mode' },
{ id: 6, label: 'Typescript Version' },
{ id: 7, label: 'Design File (Figma)' },
{ id: 8, label: 'Multiple Color Options' },
{ id: 9, label: 'RTL' },
{ id: 10, label: 'Supbase Authentication' }
],
plans: [
{
title: 'Free',
price: 0,
active: false,
featureTitle: 'Features',
exploreLink: { children: 'Get Started With Free' },
featuresID: [1, 3]
},
{
title: 'Pro',
active: false,
price: 69,
featureTitle: 'Features',
exploreLink: { children: 'Get Started With Pro' },
featuresID: [2, 4, 5, 6, 7, 8, 9, 10]
}
]
};
/*************************** BLOCK - PRICING 9 ***************************/
export default function BlockPricing9() {
return <Pricing9 {...data} />;
}
@@ -0,0 +1,8 @@
// @project
import { PrivacyPolicy1 } from '@/blocks/privacy-policy';
/*************************** BLOCK - PRIVACY POLICY 1 ***************************/
export default function BlockPrivacyPolicy1() {
return <PrivacyPolicy1 />;
}
@@ -0,0 +1,14 @@
//@project
import { ProPage } from '@/blocks/pro-page';
/*************************** PRO PAGE - DATA ***************************/
const data = {
image: '/assets/images/pro-page/Lock.svg'
};
/*************************** BLOCK - PRO PAGE ***************************/
export default function BlockProPage() {
return <ProPage {...data} />;
}
@@ -0,0 +1,46 @@
// @mui
import Typography from '@mui/material/Typography';
// @project
import { SmallHero3 } from '@/blocks/small-hero';
import GraphicsImage from '@/components/GraphicsImage';
/*************************** SMALL HERO 3 - HEADLINE ***************************/
function HeadlineText() {
return (
<Typography variant="h1" sx={{ width: { lg: '90%' } }}>
Effortless CRM Management, Seamless Business
<GraphicsImage
sx={{
display: 'inline-block',
height: { xs: 32, sm: 45, md: 57 },
width: { xs: 61, sm: 86, md: 109 },
backgroundSize: 'contain',
mx: { xs: 0.5, sm: 1, md: 1.5 },
verticalAlign: 'sub'
}}
image="/assets/images/graphics/ai/rocket.svg"
/>
Growth
</Typography>
);
}
/*************************** SMALL HERO 3 - DATA ***************************/
const data = {
chip: {
label: 'New Beta Version is Release ',
link: { children: 'explore now', href: '#' }
},
captionLine: 'Empowering Businesses with a Customizable, Data-Driven CRM Solution.',
headLine: <HeadlineText />,
exploreBtn: { children: 'Explore More' }
};
/*************************** BLOCK - SMALL HERO 3 ***************************/
export default function BlockSmallHero3() {
return <SmallHero3 {...data} />;
}
@@ -0,0 +1,71 @@
// @project
import { Testimonial10 } from '@/blocks/testimonial';
/*************************** TESTIMONIAL 10 - DATA ***************************/
const data = {
heading: 'Hear From Our Satisfied Users',
caption: `Discover why users love our platform and how it's making a positive impact on their work and businesses.`,
testimonials: [
{
title: 'Strongly endorsed!',
ratings: 5,
review: 'This platform exceeded my expectations! The features are robust, and the user interface is incredibly intuitive.',
profile: { avatar: '', name: 'Sarah T.', role: 'Business Owner' }
},
{
title: 'Top pick!',
ratings: 4,
review: `I've tried several platforms, and this one stands out for its reliability and user-friendly.`,
profile: { avatar: '', name: 'Alex M.', role: 'Project Manager' }
},
{
title: 'Widely praised!',
ratings: 2,
review: `Outstanding customer support! They're responsive and go above and beyond to ensure a smooth experience. Highly satisfied.`,
profile: { avatar: '', name: 'Emily P.', role: 'Freelancer' }
},
{
title: 'Hugely endorsed!',
ratings: 5,
review: `I've recommended this platform to colleagues, and they've all been impressed. It's versatile, efficient, and simply fantastic.`,
profile: { avatar: '', name: 'Maria S', role: 'Marketing Specialist' }
},
{
title: 'Outstanding choice!',
ratings: 2,
review: `This platform transformed the way we work. It's flexible, scalable, and adapts seamlessly to our evolving needs.`,
profile: { avatar: '', name: 'James L.', role: 'IT Professional' }
},
{
title: 'A must-consider!',
ratings: 3,
review: `As a tech enthusiast, I appreciate the innovation behind this platform. It's modern, sleek, and delivers on its promises.`,
profile: { avatar: '', name: 'Kevin R.', role: 'Software Developer' }
},
{
title: 'Highly recommended!',
ratings: 5,
review: `I've used many platforms in my career, and this one is a standout. The functionality is unmatched, making it a joy to work with.`,
profile: { avatar: '', name: 'Jessica W.', role: 'UX/UI Designer' }
},
{
title: 'Exceptional suggestion!',
ratings: 1,
review: `Our team's productivity soared after adopting this platform. It's a reliable solution that brings tangible results.`,
profile: { avatar: '', name: 'Eric H.', role: 'Operations Manager' }
},
{
title: 'Superbly recommended!',
ratings: 3,
review: 'What I love most is the seamless integration with other tools. It streamlines our workflow and saves us valuable time.',
profile: { avatar: '', name: 'Brian C.', role: 'Content Creator' }
}
]
};
/*************************** BLOCK - TESTIMONIAL 10 ***************************/
export default function BlockTestimonial10() {
return <Testimonial10 {...data} />;
}
@@ -0,0 +1,13 @@
'use client';
import PropTypes from 'prop-types';
// @project
import ThemeProviders from '@/components/ThemeProvider';
/*************************** LAYOUT - COMMON ***************************/
export default function CommonLayout({ children }) {
return <ThemeProviders>{children}</ThemeProviders>;
}
CommonLayout.propTypes = { children: PropTypes.any };
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const About = dynamic(() => import('@/views/sections/About'));
/*************************** METADATA - ABOUT ***************************/
export const metadata = { ...SEO_CONTENT.about, openGraph: { ...SEO_CONTENT.about, url: PAGE_PATH.about } };
/*************************** PAGE - ABOUT ***************************/
export default function AboutPage() {
return <About />;
}
@@ -0,0 +1,20 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const ForgotPassword = dynamic(() => import('@/views/sections/ForgotPassword'));
/*************************** METADATA - FORGOT PASSWORD ***************************/
export const metadata = {
...SEO_CONTENT.forgotPassword,
openGraph: { ...SEO_CONTENT.forgotPassword, url: PAGE_PATH.forgotPassword }
};
/*************************** PAGE - FORGOT PASSWORD ***************************/
export default function ForgotPasswordPage() {
return <ForgotPassword />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Login = dynamic(() => import('@/views/sections/Login'));
/*************************** METADATA - LOGIN ***************************/
export const metadata = { ...SEO_CONTENT.login, openGraph: { ...SEO_CONTENT.login, url: PAGE_PATH.login } };
/*************************** PAGE - LOGIN ***************************/
export default function LoginPage() {
return <Login />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const NewPassword = dynamic(() => import('@/views/sections/NewPassword'));
/*************************** METADATA - NEW PASSWORD ***************************/
export const metadata = { ...SEO_CONTENT.newPassword, openGraph: { ...SEO_CONTENT.newPassword, url: PAGE_PATH.newPassword } };
/*************************** PAGE - NEW PASSWORD ***************************/
export default function NewPasswordPage() {
return <NewPassword />;
}
@@ -0,0 +1,20 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const OtpVerification = dynamic(() => import('@/views/sections/OtpVerification'));
/*************************** METADATA - OTP VERIFICATION ***************************/
export const metadata = {
...SEO_CONTENT.otpVerification,
openGraph: { ...SEO_CONTENT.otpVerification, url: PAGE_PATH.otpVerification }
};
/*************************** PAGE - OTP VERIFICATION ***************************/
export default function OtpVerificationPage() {
return <OtpVerification />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Register = dynamic(() => import('@/views/sections/Register'));
/*************************** METADATA - REGISTER ***************************/
export const metadata = { ...SEO_CONTENT.register, openGraph: { ...SEO_CONTENT.register, url: PAGE_PATH.register } };
/*************************** PAGE - REGISTER ***************************/
export default function RegisterPage() {
return <Register />;
}
@@ -0,0 +1,18 @@
// @next
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const BlogDetails = dynamic(() => import('@/views/sections/BlogDetails'));
/*************************** METADATA - BLOG DETAILS ***************************/
export const metadata = { ...SEO_CONTENT.blogDetails, openGraph: { ...SEO_CONTENT.blogDetails, url: PAGE_PATH.blogDetails } };
/*************************** PAGE - BLOG DETAILS ***************************/
export default function BlogDetailsPage() {
return <BlogDetails />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Blog = dynamic(() => import('@/views/sections/Blog'));
/*************************** METADATA - BLOG ***************************/
export const metadata = { ...SEO_CONTENT.blog, openGraph: { ...SEO_CONTENT.blog, url: PAGE_PATH.blog } };
/*************************** PAGE - BLOG ***************************/
export default function BlogPage() {
return <Blog />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Clientele = dynamic(() => import('@/views/sections/Clientele'));
/*************************** METADATA - CLIENTELE ***************************/
export const metadata = { ...SEO_CONTENT.clientele, openGraph: { ...SEO_CONTENT.clientele, url: PAGE_PATH.clientele } };
/*************************** PAGE - CLIENTELE ***************************/
export default function ClientelePage() {
return <Clientele />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Color = dynamic(() => import('@/views/sections/Color'));
/*************************** METADATA - COLOR ***************************/
export const metadata = { ...SEO_CONTENT.color, openGraph: { ...SEO_CONTENT.color, url: PAGE_PATH.color } };
/*************************** PAGE - COLOR ***************************/
export default function ColorPage() {
return <Color />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const ComingSoon = dynamic(() => import('@/views/sections/ComingSoon'));
/*************************** METADATA - COMING SOON ***************************/
export const metadata = { ...SEO_CONTENT.comingSoon, openGraph: { ...SEO_CONTENT.comingSoon, url: PAGE_PATH.comingSoon } };
/*************************** PAGE - COMING SOON ***************************/
export default function ComingSoonPage() {
return <ComingSoon />;
}
@@ -0,0 +1,16 @@
import dynamic from 'next/dynamic';
// @project
import { SEO_CONTENT } from '@/metadata';
const ContactUs = dynamic(() => import('@/views/sections/ContactUs'));
/*************************** METADATA - CONTACT US ***************************/
export const metadata = { ...SEO_CONTENT.contactUs };
/*************************** PAGE - CONTACT US ***************************/
export default function ContactUsPage() {
return <ContactUs />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Cookie = dynamic(() => import('@/views/sections/Cookie'));
/*************************** METADATA - COOKIE ***************************/
export const metadata = { ...SEO_CONTENT.cookie, openGraph: { ...SEO_CONTENT.cookie, url: PAGE_PATH.cookie } };
/*************************** PAGE - COOKIE ***************************/
export default function CookiePage() {
return <Cookie />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Cta = dynamic(() => import('@/views/sections/Cta'));
/*************************** METADATA - CALL TO ACTION ***************************/
export const metadata = { ...SEO_CONTENT.cta, openGraph: { ...SEO_CONTENT.cta, url: PAGE_PATH.cta } };
/*************************** PAGE - CALL TO ACTION ***************************/
export default function CtaPage() {
return <Cta />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const EarlyAccess = dynamic(() => import('@/views/sections/EarlyAccess'));
/*************************** METADATA - EARLY ACCCESS ***************************/
export const metadata = { ...SEO_CONTENT.earlyAccess, openGraph: { ...SEO_CONTENT.earlyAccess, url: PAGE_PATH.earlyAccess } };
/*************************** PAGE - EARLY ACCCESS ***************************/
export default function EarlyAccessPage() {
return <EarlyAccess />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Error404 = dynamic(() => import('@/views/sections/Error404'));
/*************************** METADATA - ERROR 404 ***************************/
export const metadata = { ...SEO_CONTENT.error404, openGraph: { ...SEO_CONTENT.error404, url: PAGE_PATH.error404 } };
/*************************** PAGE - ERROR 404 ***************************/
export default function Error404Page() {
return <Error404 />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Error500 = dynamic(() => import('@/views/sections/Error500'));
/*************************** METADATA - ERROR 500 ***************************/
export const metadata = { ...SEO_CONTENT.error500, openGraph: { ...SEO_CONTENT.error500, url: PAGE_PATH.error500 } };
/*************************** PAGE - ERROR 500 ***************************/
export default function Error500Page() {
return <Error500 />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Faq = dynamic(() => import('@/views/sections/Faq'));
/*************************** METADATA - FAQ ***************************/
export const metadata = { ...SEO_CONTENT.faq, openGraph: { ...SEO_CONTENT.faq, url: PAGE_PATH.faq } };
/*************************** PAGE - FAQ ***************************/
export default function FaqPage() {
return <Faq />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Feature = dynamic(() => import('@/views/sections/Feature'));
/*************************** METADATA - FEATURE ***************************/
export const metadata = { ...SEO_CONTENT.feature, openGraph: { ...SEO_CONTENT.feature, url: PAGE_PATH.feature } };
/*************************** PAGE - FEATURE ***************************/
export default function FeaturePage() {
return <Feature />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Footer = dynamic(() => import('@/views/sections/Footer'));
/*************************** METADATA - FOOTER ***************************/
export const metadata = { ...SEO_CONTENT.footer, openGraph: { ...SEO_CONTENT.footer, url: PAGE_PATH.footer } };
/*************************** PAGE - FOOTER ***************************/
export default function FooterPage() {
return <Footer />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Gallery = dynamic(() => import('@/views/sections/Gallery'));
/*************************** METADATA - GALLERY ***************************/
export const metadata = { ...SEO_CONTENT.gallery, openGraph: { ...SEO_CONTENT.gallery, url: PAGE_PATH.gallery } };
/*************************** PAGE - GALLERY ***************************/
export default function GalleryPage() {
return <Gallery />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Hero = dynamic(() => import('@/views/sections/Hero'));
/*************************** METADATA - HERO ***************************/
export const metadata = { ...SEO_CONTENT.hero, openGraph: { ...SEO_CONTENT.hero, url: PAGE_PATH.hero } };
/*************************** PAGE - HERO ***************************/
export default function HeroPage() {
return <Hero />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Icon = dynamic(() => import('@/views/sections/Icon'));
/*************************** METADATA - ICON ***************************/
export const metadata = { ...SEO_CONTENT.icon, openGraph: { ...SEO_CONTENT.icon, url: PAGE_PATH.icon } };
/*************************** PAGE - ICON ***************************/
export default function IconPage() {
return <Icon />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Integration = dynamic(() => import('@/views/sections/Integration'));
/*************************** METADATA - INTEGRATION ***************************/
export const metadata = { ...SEO_CONTENT.integration, openGraph: { ...SEO_CONTENT.integration, url: PAGE_PATH.integration } };
/*************************** PAGE - INTEGRATION ***************************/
export default function IntegrationPage() {
return <Integration />;
}
@@ -0,0 +1,26 @@
'use client';
import PropTypes from 'prop-types';
// @next
import dynamic from 'next/dynamic';
const ScrollFab = dynamic(() => import('@/components/ScrollFab'));
const SectionsLayout = dynamic(() => import('@/views/sections/layout'));
/*************************** LAYOUT - SECTIONS ***************************/
export default function Sections({ children }) {
return (
<SectionsLayout>
<>
{children}
{/* scroll to top section */}
<ScrollFab />
</>
</SectionsLayout>
);
}
Sections.propTypes = { children: PropTypes.any };
@@ -0,0 +1,8 @@
// @project
import Loader from '@/components/Loader';
/*************************** LOADER ***************************/
export default function Loading() {
return <Loader />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const MegaMenu = dynamic(() => import('@/views/sections/MegaMenu'));
/*************************** METADATA - MEGA MENU ***************************/
export const metadata = { ...SEO_CONTENT.megaMenu, openGraph: { ...SEO_CONTENT.megaMenu, url: PAGE_PATH.megaMenu } };
/*************************** PAGE - MEGA MENU ***************************/
export default function MegaMenuPage() {
return <MegaMenu />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Metrics = dynamic(() => import('@/views/sections/metrics'));
/*************************** METADATA - METRICS ***************************/
export const metadata = { ...SEO_CONTENT.metrics, openGraph: { ...SEO_CONTENT.metrics, url: PAGE_PATH.metrics } };
/*************************** PAGE - METRICS ***************************/
export default function MetricsPage() {
return <Metrics />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Navbar = dynamic(() => import('@/views/sections/Navbar'));
/*************************** METADATA - NAVBAR ***************************/
export const metadata = { ...SEO_CONTENT.navbar, openGraph: { ...SEO_CONTENT.navbar, url: PAGE_PATH.navbar } };
/*************************** PAGE - NAVBAR ***************************/
export default function NavbarPage() {
return <Navbar />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const OnBoard = dynamic(() => import('@/views/sections/OnBoard'));
/*************************** METADATA - ONBOARD ***************************/
export const metadata = { ...SEO_CONTENT.onBoard, openGraph: { ...SEO_CONTENT.onBoard, url: PAGE_PATH.onboard } };
/*************************** PAGE - ONBOARD ***************************/
export default function OnBoardPage() {
return <OnBoard />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Other = dynamic(() => import('@/views/sections/Other'));
/*************************** METADATA - OTHER ***************************/
export const metadata = { ...SEO_CONTENT.other, openGraph: { ...SEO_CONTENT.other, url: PAGE_PATH.other } };
/*************************** PAGE - OTHER ***************************/
export default function OtherPage() {
return <Other />;
}
@@ -0,0 +1,16 @@
import dynamic from 'next/dynamic';
// @project
import { SEO_CONTENT } from '@/metadata';
const Sections = dynamic(() => import('@/views/sections'));
/*************************** METADATA - SECTIONS ***************************/
export const metadata = { ...SEO_CONTENT.section };
/*************************** PAGE - SECTIONS ***************************/
export default function SectionsPage() {
return <Sections />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Pricing = dynamic(() => import('@/views/sections/Pricing'));
/*************************** METADATA - PRICING ***************************/
export const metadata = { ...SEO_CONTENT.pricing, openGraph: { ...SEO_CONTENT.pricing, url: PAGE_PATH.pricing } };
/*************************** PAGE - PRICING ***************************/
export default function PricingPage() {
return <Pricing />;
}
@@ -0,0 +1,16 @@
import dynamic from 'next/dynamic';
// @project
import { SEO_CONTENT } from '@/metadata';
const PrivacyPolicy = dynamic(() => import('@/views/sections/PrivacyPolicy'));
/*************************** METADATA - PRIVACY POLICY ***************************/
export const metadata = { ...SEO_CONTENT.privacyPolicy };
/*************************** PAGE - PRIVACY POLICY ***************************/
export default function PrivacyPolicyPage() {
return <PrivacyPolicy />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const ProPages = dynamic(() => import('@/views/sections/ProPage'));
/*************************** METADATA - PRO PAGE ***************************/
export const metadata = { ...SEO_CONTENT.pricing, openGraph: { ...SEO_CONTENT.pricing, url: PAGE_PATH.pricing } };
/*************************** PAGE - PRICING ***************************/
export default function ProPage() {
return <ProPages />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Process = dynamic(() => import('@/views/sections/Process'));
/*************************** METADATA - PROCESS ***************************/
export const metadata = { ...SEO_CONTENT.process, openGraph: { ...SEO_CONTENT.process, url: PAGE_PATH.process } };
/*************************** PAGE - PROCESS ***************************/
export default function ProcessPage() {
return <Process />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const SmallHero = dynamic(() => import('@/views/sections/SmallHero'));
/*************************** METADATA - SMALL HERO ***************************/
export const metadata = { ...SEO_CONTENT.smallHero, openGraph: { ...SEO_CONTENT.smallHero, url: PAGE_PATH.smallHero } };
/*************************** PAGE - SMALL HERO ***************************/
export default function SmallHeroPage() {
return <SmallHero />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Team = dynamic(() => import('@/views/sections/Team'));
/*************************** METADATA - TEAM ***************************/
export const metadata = { ...SEO_CONTENT.team, openGraph: { ...SEO_CONTENT.team, url: PAGE_PATH.team } };
/*************************** PAGE - TEAM ***************************/
export default function TeamPage() {
return <Team />;
}
@@ -0,0 +1,20 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const TermsCondition = dynamic(() => import('@/views/sections/TermsCondition'));
/*************************** METADATA - TERMS CONDITION ***************************/
export const metadata = {
...SEO_CONTENT.termsCondition,
openGraph: { ...SEO_CONTENT.termsCondition, url: PAGE_PATH.termsCondition }
};
/*************************** PAGE - TERMS CONDITION ***************************/
export default function TermsConditionPage() {
return <TermsCondition />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Testimonial = dynamic(() => import('@/views/sections/Testimonial'));
/*************************** METADATA - TESTIMONIAL ***************************/
export const metadata = { ...SEO_CONTENT.testimonial, openGraph: { ...SEO_CONTENT.testimonial, url: PAGE_PATH.testimonial } };
/*************************** PAGE - TESTIMONIAL ***************************/
export default function TestimonialPage() {
return <Testimonial />;
}
@@ -0,0 +1,15 @@
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
import TopOffer from '@/views/sections/TopOffer';
/*************************** METADATA - TOP OFFER ***************************/
export const metadata = { ...SEO_CONTENT.topOffer, openGraph: { ...SEO_CONTENT.topOffer, url: PAGE_PATH.topOffer } };
/*************************** PAGE - TOP OFFER ***************************/
export default function TopOfferPage() {
return <TopOffer />;
}
@@ -0,0 +1,17 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const Typography = dynamic(() => import('@/views/sections/Typography'));
/*************************** METADATA - TYPOGRAPHY ***************************/
export const metadata = { ...SEO_CONTENT.typography, openGraph: { ...SEO_CONTENT.typography, url: PAGE_PATH.typography } };
/*************************** PAGE - TYPOGRAPHY ***************************/
export default function TypographyPage() {
return <Typography />;
}
@@ -0,0 +1,16 @@
import dynamic from 'next/dynamic';
// @project
import { SEO_CONTENT } from '@/metadata';
const UnderMaintenance = dynamic(() => import('@/views/sections/UnderMaintenance'));
/*************************** METADATA - UNDER MAINTENANCE ***************************/
export const metadata = { ...SEO_CONTENT.underMaintenance };
/*************************** PAGE - UNDER MAINTENANCE ***************************/
export default function UnderMaintenancePage() {
return <UnderMaintenance />;
}
@@ -0,0 +1,16 @@
import dynamic from 'next/dynamic';
// @project
import { SEO_CONTENT } from '@/metadata';
const Contact = dynamic(() => import('@/views/landings/default/contact'));
/*************************** METADATA - CONTACT ***************************/
export const metadata = { ...SEO_CONTENT.contactUs };
/*************************** PAGE - CONTACT ***************************/
export default function ContactPage() {
return <Contact />;
}
@@ -0,0 +1,27 @@
import PropTypes from 'prop-types';
// @next
import dynamic from 'next/dynamic';
// @project
const ScrollFab = dynamic(() => import('@/components/ScrollFab'));
// const ThemeAI = dynamic(() => import('@/views/landings/ai/theme'));
const MainLayout = dynamic(() => import('@/views/landings/default/layout'));
/*************************** LAYOUT - AI ***************************/
export default function AI({ children }) {
return (
// <ThemeAI>
<MainLayout>
<>
{children}
{/* scroll to top section */}
<ScrollFab />
</>
</MainLayout>
// </ThemeAI>
);
}
AI.propTypes = { children: PropTypes.any };
@@ -0,0 +1,19 @@
// @next
import dynamic from 'next/dynamic';
// @project
const ScrollFab = dynamic(() => import('@/components/ScrollFab'));
const Main = dynamic(() => import('@/views/landings/default'));
/*************************** PAGE - ROOT ***************************/
export default function HomePage() {
return (
<>
<Main />
{/* scroll to top section */}
<ScrollFab />
</>
);
}
@@ -0,0 +1,16 @@
import dynamic from 'next/dynamic';
// @project
import { SEO_CONTENT } from '@/metadata';
const PrivacyPolicy = dynamic(() => import('@/views/landings/default/privacy-policy'));
/*************************** METADATA - PRIVACY POLICY ***************************/
export const metadata = { ...SEO_CONTENT.privacyPolicy };
/*************************** PAGE - PRIVACY POLICY ***************************/
export default function PrivacyPolicyPage() {
return <PrivacyPolicy />;
}
@@ -0,0 +1,20 @@
import dynamic from 'next/dynamic';
// @project
import { PAGE_PATH } from '@/path';
import { SEO_CONTENT } from '@/metadata';
const TermsCondition = dynamic(() => import('@/views/landings/default/terms-condition'));
/*************************** METADATA - TERMS CONDITION ***************************/
export const metadata = {
...SEO_CONTENT.termsCondition,
openGraph: { ...SEO_CONTENT.termsCondition, url: PAGE_PATH.termsConditionPage }
};
/*************************** PAGE - TERMS CONDITION ***************************/
export default function TermsConditionPage() {
return <TermsCondition />;
}
@@ -0,0 +1,36 @@
'use client';
import PropTypes from 'prop-types';
import { useEffect, useState } from 'react';
// @project
import Loader from '@/components/Loader';
import ThemeProvider from '@/components/ThemeProvider';
import { ConfigProvider } from '@/contexts/ConfigContext';
/*************************** COMMON - CONFIG, THEME ***************************/
export default function ProviderWrapper({ children }) {
const [loader, setLoader] = useState(true);
useEffect(() => {
setLoader(false);
}, []);
/**
* A loader is needed here to initialize the configuration from localStorage and set the default theme.
* Without a loader,
* the theme palette and fontFamily don't match, resulting in an error like:
* "Warning: Prop className did not match".
*/
return (
<ConfigProvider>
<ThemeProvider>
<main>{loader ? <Loader /> : children}</main>
</ThemeProvider>
</ConfigProvider>
);
}
ProviderWrapper.propTypes = { children: PropTypes.any };
@@ -0,0 +1,38 @@
// @next
import { NextResponse } from 'next/server';
// @third-party
import axios from 'axios';
/*************************** API - MAILERLITE SUBSCRIBE ***************************/
// POST handler for /api/subscribe
export async function POST(request) {
try {
const { email } = await request.json();
if (!email) {
return NextResponse.json({ error: 'Email is required' }, { status: 400 });
}
// Example: MailerLite API endpoint (replace with your actual MailerLite API URL)
const mailerLiteUrl = `${process.env.MAILERLITE_API_ENDPOINT}/subscribers`;
// Make the Axios POST request to MailerLite (replace 'YOUR_API_KEY' with your actual API key)
await axios.post(
mailerLiteUrl,
{ email, groups: process.env.MAILERLITE_GROUP?.trim().replaceAll(' ', '').split(',') },
{
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${process.env.MAILERLITE_API_KEY}` // Authorization header with MailerLite API key
}
}
);
// Handle successful response
return NextResponse.json({ message: 'Subscribed successfully!' }, { status: 200 });
} catch (error) {
// Handle failure response
console.error('Error subscribing:', error);
return NextResponse.json({ error }, { status: 500 });
}
}
+22
View File
@@ -0,0 +1,22 @@
'use client';
// @project
import { Error500Page } from '@/blocks/maintenance';
import ThemeProviders from '@/components/ThemeProvider';
/*************************** ERROR 500 - DATA ***************************/
const data = {
primaryBtn: { children: 'Back to Home Page' },
heading: 'Please try again later or feel free to contact us if the problem persists.'
};
/*************************** ERROR - 500 ***************************/
export default function InternalServerError() {
return (
<ThemeProviders>
<Error500Page {...data} />
</ThemeProviders>
);
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

+18
View File
@@ -0,0 +1,18 @@
/* slick-carousel slider */
@import 'slick-carousel/slick/slick.css';
@import 'slick-carousel/slick/slick-theme.css';
/* scrollbar */
@import '../styles/scrollbar.css';
/* to remove default browser focus-visible */
body * {
&:focus-visible,
&:focus {
outline: none;
}
}
html {
scroll-behavior: smooth;
}
+42
View File
@@ -0,0 +1,42 @@
import PropTypes from 'prop-types';
import Script from 'next/script';
// @style
import './globals.css';
// @mui
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
// @project
import ProviderWrapper from './ProviderWrapper';
import { mainMetadata } from '@/metadata';
const gaId = process.env.NEXT_PUBLIC_ANALYTICS_ID || '';
/*************************** METADATA - MAIN ***************************/
export const metadata = { ...mainMetadata };
/*************************** LAYOUT - MAIN ***************************/
// Root layout component that wraps the entire application
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<head>
{/* Preconnect and DNS Prefetch */}
<link rel="preconnect" href="https://www.googletagmanager.com" />
<link rel="dns-prefetch" href="https://www.googletagmanager.com" />
<script src="https://fomo.codedthemes.com/pixel/gkPddwTcjNYydfr7v3FcZuToUb9ZAevo" defer data-nscript="lazyOnload"></script>
</head>
<body>
<AppRouterCacheProvider options={{ enableCssLayer: true }}>
<ProviderWrapper>{children}</ProviderWrapper>
</AppRouterCacheProvider>
{gaId && <Script strategy="lazyOnload" src={`https://www.googletagmanager.com/gtag/js?id=${gaId}`} />}
</body>
</html>
);
}
RootLayout.propTypes = { children: PropTypes.any };
+13
View File
@@ -0,0 +1,13 @@
// @project
import Loader from '@/components/Loader';
import ThemeProviders from '@/components/ThemeProvider';
/*************************** LOADER ***************************/
export default function Loading() {
return (
<ThemeProviders>
<Loader />
</ThemeProviders>
);
}
@@ -0,0 +1,22 @@
'use client';
// @project
import { Error404Page } from '@/blocks/maintenance';
import ThemeProviders from '@/components/ThemeProvider';
/*************************** ERROR 404 - DATA ***************************/
const data = {
primaryBtn: { children: 'Back to Home Page', onClick: () => window.history.back() },
heading: `Looks like you've taken a wrong turn. Lets get you back on track!`
};
/*************************** ERROR - 404 ***************************/
export default function notfound() {
return (
<ThemeProviders>
<Error404Page {...data} />
</ThemeProviders>
);
}
@@ -0,0 +1,181 @@
'use client';
import { useEffect, useState } from 'react';
// @mui
import Divider from '@mui/material/Divider';
import Grid from '@mui/material/Grid';
import List from '@mui/material/List';
import ListItemButton from '@mui/material/ListItemButton';
import ListItemText from '@mui/material/ListItemText';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
// @project
import ContainerWrapper from '@/components/ContainerWrapper';
import { SECTION_COMMON_PY } from '@/utils/constant';
// Helper functions for scrollspy
const clamp = (value) => Math.max(0, value);
const isBetween = (value, floor, ceil) => value >= floor && value <= ceil;
/*************************** HOOKS - SCROLLSPY ***************************/
function useScrollspy(ids, offset = 0) {
const [activeId, setActiveId] = useState('');
useEffect(() => {
const listener = () => {
const scroll = window.scrollY;
const position = ids
.map((id) => {
const element = document.getElementById(id);
if (!element) return { id, top: -1, bottom: -1 };
const rect = element.getBoundingClientRect();
const top = clamp(rect.top + scroll - offset);
const bottom = clamp(rect.bottom + scroll - offset);
return { id, top, bottom };
})
.find(({ top, bottom }) => isBetween(scroll, top, bottom));
setActiveId(position?.id || '');
};
window.addEventListener('scroll', listener);
window.addEventListener('resize', listener);
listener(); // Initial call to set the activeId
return () => {
window.removeEventListener('scroll', listener);
window.removeEventListener('resize', listener);
};
}, [ids, offset]);
return activeId;
}
/*************************** TERMS CONDITION - DATA ***************************/
const menuItems = [
{
id: 'acceptance-of-terms',
heading: 'Acceptance of terms',
caption:
'By accessing and using this website, you agree to be bound by these Terms and Conditions of Use. If you do not agree with any part of these terms, you must not use the website. shares information about you when you use our website or services. By accessing or using our website, you consent to the practices described in this policy.'
},
{
id: 'changes-to-terms',
heading: 'Changes to terms',
caption:
'We reserve the right to modify or replace these terms at our sole discretion. It is your responsibility to check these terms periodically for changes. Your continued use of the website after the posting of any changes constitutes acceptance of those changes.'
},
{
id: 'user-conduct',
heading: 'User conduct',
caption:
'You agree to use this website only for lawful purposes and in a manner consistent with all applicable local, national, and international laws and regulations.'
},
{
id: 'intellectual-property',
heading: 'Intellectual property',
caption:
'All content on this website, including but not limited to text, graphics, logos, images, audio clips, video clips, digital downloads, and data compilations, is the property of [Your Company Name] or its content suppliers and protected by international copyright laws.'
},
{
id: 'privacy-policy',
heading: 'Privacy policy',
caption:
'We do not sell, trade, or otherwise transfer your personal information to third parties. We may share information with trusted service providers who assist us in operating our website, conducting our business, or servicing you.'
},
{
id: 'user-generated-content',
heading: 'User-generated content',
caption:
'If you submit any material to this website, you grant [Your Company Name] a perpetual, royalty-free, worldwide license to use, reproduce, modify, adapt, publish, translate, create derivative works from, distribute, and display such material.'
},
{
id: 'limitation-of-liability',
heading: 'Limitation of liability',
caption:
'In no event shall [Your Company Name] or its affiliates be liable for any direct, indirect, incidental, special, or consequential damages resulting from the use or inability to use this website.'
},
{
id: 'indemnity',
heading: 'Indemnity',
caption:
"You agree to indemnify and hold harmless [Your Company Name] and its affiliates from any claims, actions, demands, damages, liabilities, costs, or expenses, including reasonable attorneys' fees, arising out of or related to your use of the website or any violation of these terms."
},
{
id: 'governing-law',
heading: 'Governing law',
caption:
'These terms are governed by and construed in accordance with the laws of [Your Country/State], without regard to its conflict of law principles.'
}
];
/*************************** SECTIONS - TERMS CONDITION ***************************/
/**
*
* Demos:
* - [Terms Condition](https://www.saasable.io/sections/terms-condition)
*/
export default function TermsConditionPage() {
const ids = menuItems.map((item) => item.id);
// Adjust offset as per header height
const activeId = useScrollspy(ids, 60);
const [selectedID, setSelectedID] = useState(activeId);
useEffect(() => {
if (activeId) {
setSelectedID(activeId);
}
}, [activeId]);
return (
<ContainerWrapper sx={{ pb: SECTION_COMMON_PY }}>
<Grid container spacing={{ xs: 2, md: 3 }}>
<Grid size={{ xs: 12, sm: 4, md: 3 }}>
<List component="div" sx={{ position: 'sticky', top: 20 }} disablePadding>
{menuItems.map((item, index) => (
<ListItemButton
key={index}
href={`#${item.id}`}
sx={{
py: 1.25,
px: 1.5,
borderRadius: 3,
mb: 0.75,
...(selectedID === item.id && { color: 'primary.main', bgcolor: 'grey.100' }),
'&:hover': { bgcolor: 'grey.50' }
}}
onClick={() => setSelectedID(item.id)}
>
<ListItemText primary={item.heading} sx={{ my: 0 }} slotProps={{ primary: { variant: 'subtitle1' } }} />
</ListItemButton>
))}
</List>
<Divider sx={{ display: { xs: 'block', sm: 'none' } }} />
</Grid>
<Grid size={{ xs: 12, sm: 8, md: 9 }}>
{menuItems.map((item, index) => (
<Stack
key={index}
id={item.id}
sx={{ py: { xs: 1, sm: 1.5, md: 3 }, px: { md: 3 }, gap: 1, '&:first-of-type': { pt: { sm: 0 } } }}
>
<Typography variant="h4">{item.heading}</Typography>
<Typography variant="body1" sx={{ color: 'text.secondary' }}>
{item.caption}
</Typography>
</Stack>
))}
</Grid>
</Grid>
</ContainerWrapper>
);
}
@@ -0,0 +1,246 @@
import PropTypes from 'prop-types';
// @mui
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @project
import { GraphicsCard } from '@/components/cards';
import Typeset from '@/components/Typeset';
/*************************** TYPOGRAPHY - DATA ***************************/
const typographyData = [
{
heading: 'Headings',
items: [
{
title: 'Heading 01',
sizeValue: { desktop: '57px', tablet: '45px', mobile: '36px' },
lineHeight: { desktop: '64px', tablet: '52px', mobile: '44px' },
letterSpacing: { desktop: '-0.25px', tablet: '0px', mobile: '0px' },
variant: 'h1',
label: 'h1 - Heading Large',
fontWeight: 'Regular (400)'
},
{
title: 'Heading 02',
sizeValue: { desktop: '45px', tablet: '36px', mobile: '24px' },
lineHeight: { desktop: '52px', tablet: '44px', mobile: '32px' },
letterSpacing: { desktop: '0px', tablet: '0px', mobile: '0px' },
variant: 'h2',
label: 'h2 - Heading Medium',
fontWeight: 'Regular (400)'
},
{
title: 'Heading 03',
sizeValue: { desktop: '28px', tablet: '24px', mobile: '20px' },
lineHeight: { desktop: '36px', tablet: '32px', mobile: '28px' },
letterSpacing: { desktop: '0px', tablet: '0px', mobile: '0px' },
variant: 'h3',
label: 'h3 - Display Medium',
fontWeight: 'Regular (400)'
},
{
title: 'Heading 04',
sizeValue: { desktop: '24px', tablet: '20px', mobile: '16px' },
lineHeight: { desktop: '32px', tablet: '28px', mobile: '24px' },
letterSpacing: { desktop: '0px', tablet: '0px', mobile: '0px' },
variant: 'h4',
label: 'h4 - Display Small',
fontWeight: 'Regular (400)'
},
{
title: 'Heading 05',
sizeValue: { desktop: '22px', tablet: '16px', mobile: '16px' },
lineHeight: { desktop: '28px', tablet: '24px', mobile: '24px' },
letterSpacing: { desktop: '0px', tablet: '0.15px', mobile: '0.15px' },
variant: 'h5',
label: 'h5 - Label Large',
fontWeight: 'Medium (500)'
},
{
title: 'Heading 06',
sizeValue: { desktop: '22px', tablet: '16px', mobile: '16px' },
lineHeight: { desktop: '30px', tablet: '24px', mobile: '24px' },
letterSpacing: { desktop: '0px', tablet: '0.5px', mobile: '0.5px' },
variant: 'h6',
label: 'h6 - Paragraph Large',
fontWeight: 'Regular (400)'
}
]
},
{
heading: 'Body / Paragraph',
items: [
{
title: 'Body 01',
sizeValue: { desktop: '16px', tablet: '14px', mobile: '14px' },
lineHeight: { desktop: '24px', tablet: '20px', mobile: '20px' },
letterSpacing: { desktop: '0.5px', tablet: '0.25px', mobile: '0.25px' },
variant: 'body1',
label: 'body1 - Paragraph Medium',
fontWeight: 'Regular (400)'
},
{
title: 'Body 02',
sizeValue: { desktop: '14px', tablet: '12px', mobile: '12px' },
lineHeight: { desktop: '20px', tablet: '18px', mobile: '18px' },
letterSpacing: { desktop: '0.25px', tablet: '0.25px', mobile: '0.25px' },
variant: 'body2',
label: 'body2 - Paragraph Small',
fontWeight: 'Regular (400)'
}
]
},
{
heading: 'Subtitle',
items: [
{
title: 'Subtitle 01',
sizeValue: { desktop: '16px', tablet: '14px', mobile: '14px' },
lineHeight: { desktop: '24px', tablet: '20px', mobile: '20px' },
letterSpacing: { desktop: '0.15px', tablet: '0.1px', mobile: '0.1px' },
variant: 'subtitle1',
label: 'subtitle1 - Label Medium',
fontWeight: 'Medium (500)'
},
{
title: 'Subtitle 02',
sizeValue: { desktop: '14px', tablet: '12px', mobile: '12px' },
lineHeight: { desktop: '20px', tablet: '18px', mobile: '18px' },
letterSpacing: { desktop: '0.1px', tablet: '0.1px', mobile: '0.1 px' },
variant: 'subtitle2',
label: 'subtitle2 - Label Small',
fontWeight: 'Semibold (600)'
}
]
},
{
heading: 'Caption',
items: [
{
title: 'Caption',
sizeValue: { desktop: '12px', tablet: '12px', mobile: '12px' },
lineHeight: { desktop: '16px', tablet: '16px', mobile: '16px' },
letterSpacing: { desktop: '0px', tablet: '0px', mobile: '0 px' },
variant: 'caption',
label: 'caption - Hyperlink Small',
fontWeight: 'Semibold (600)'
},
{
title: 'Caption 01',
sizeValue: { desktop: '16px', tablet: '16px', mobile: '16px' },
lineHeight: { desktop: '24px', tablet: '24px', mobile: '24px' },
letterSpacing: { desktop: '0.5px', tablet: '0.5px', mobile: '0.5px' },
variant: 'caption1',
label: 'caption1 - Hyperlink Large',
fontWeight: 'Regular (400)'
},
{
title: 'Caption 02',
sizeValue: { desktop: '14px', tablet: '14px', mobile: '14px' },
lineHeight: { desktop: '20px', tablet: '20px', mobile: '20px' },
letterSpacing: { desktop: '0.1px', tablet: '0.1 px', mobile: '0.1px' },
variant: 'caption2',
label: 'caption2 - Hyperlink Medium',
fontWeight: 'Medium (500)'
}
]
}
];
/*************************** TYPOGRAPHY - BLOCK ***************************/
function FontSizeBlock({ desktop, tablet, mobile, type }) {
let label1 = 'Desktop';
let label2 = 'Tablet';
let label3 = 'Mobile';
if (type === 'letter-spacing') {
label1 = label2 = label3 = 'Letter Spacing';
}
if (type === 'line-height') {
label1 = label2 = label3 = 'Line Height';
}
return (
<Grid container spacing={1}>
<Grid size={4}>
<Stack sx={{ gap: 0.5 }}>
<Typography variant="body2" sx={{ color: 'grey.700' }}>
{label1}
</Typography>
<Typography variant="subtitle1">{desktop}</Typography>
</Stack>
</Grid>
<Grid size={4}>
<Stack sx={{ gap: 0.5 }}>
<Typography variant="body2" sx={{ color: 'grey.700' }}>
{label2}
</Typography>
<Typography variant="subtitle1">{tablet}</Typography>
</Stack>
</Grid>
<Grid size={4}>
<Stack sx={{ gap: 0.5 }}>
<Typography variant="body2" sx={{ color: 'grey.700' }}>
{label3}
</Typography>
<Typography variant="subtitle1">{mobile}</Typography>
</Stack>
</Grid>
</Grid>
);
}
/*************************** SECTIONS - TYPOGRAPHY ***************************/
/**
*
* Demos:
* - [Typography](https://www.saasable.io/sections/typography)
*/
export default function TypographyPage() {
return (
<Grid container spacing={{ xs: 2.5, sm: 3, md: 4 }}>
{typographyData.map((item, index) => (
<Grid key={index} size={12}>
<Stack sx={{ gap: { xs: 1.5 } }}>
<Typeset {...{ heading: item.heading, stackProps: { sx: { mb: 1 } } }} />
{item.items.map((block, index) => (
<GraphicsCard key={index}>
<Box sx={{ p: { xs: 3, sm: 4, md: 5 } }}>
<Grid container spacing={2.5}>
<Grid size={{ xs: 12, sm: 3, md: 2 }}>
<Typography variant="h4">{block.title}</Typography>
<Typography variant="body2" sx={{ color: 'grey.700' }}>
{block.label}
</Typography>
</Grid>
<Grid size={{ xs: 11, sm: 6, md: 4 }}>
<Stack sx={{ gap: 2.5 }}>
<Typography variant="subtitle1">{block.fontWeight}</Typography>
<FontSizeBlock {...block.sizeValue} type="font-size" />
<FontSizeBlock {...block.lineHeight} type="line-height" />
<FontSizeBlock {...block.letterSpacing} type="letter-spacing" />
</Stack>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<Typography variant={block.variant}>Quick brown fox jumps!</Typography>
</Grid>
</Grid>
</Box>
</GraphicsCard>
))}
</Stack>
</Grid>
))}
</Grid>
);
}
FontSizeBlock.propTypes = { desktop: PropTypes.string, tablet: PropTypes.string, mobile: PropTypes.string, type: PropTypes.string };
@@ -0,0 +1,125 @@
'use client';
import PropTypes from 'prop-types';
// @mui
import { useTheme } from '@mui/material/styles';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @third-party
import { motion } from 'motion/react';
import Slider from 'react-slick';
// @project
import ContainerWrapper from '@/components/ContainerWrapper';
import GraphicsImage from '@/components/GraphicsImage';
import { withAlpha } from '@/utils/colorUtils';
import { SECTION_COMMON_PY } from '@/utils/constant';
/*************************** CLIENTELE - 3 ***************************/
/**
*
* Demos:
* - [Clientele3](https://www.saasable.io/blocks/clientele/clientele3)
*
* API:
* - [Clientele3 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/clientele/clientele3#props-details)
*/
export default function Clientele3({ title, clienteleList }) {
const theme = useTheme();
const settings = {
autoplay: true,
arrows: false,
dots: false,
infinite: true,
speed: 500,
slidesToShow: 5,
swipeToSlide: true,
initialSlide: 0,
responsive: [
{
breakpoint: theme.breakpoints.values.md,
settings: { slidesToShow: 4 }
},
{
breakpoint: theme.breakpoints.values.sm,
settings: { slidesToShow: 2, centerMode: true }
}
]
};
const shade = {
content: `' '`,
zIndex: 1,
position: 'absolute',
width: { sm: 60, xs: 40 },
height: 1,
top: 0,
background: `linear-gradient(90deg, ${theme.vars.palette.background.default} -8.54%, ${withAlpha(theme.vars.palette.background.default, 0)} 100%)`,
transform: null
};
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<Stack sx={{ gap: 2.5 }}>
{title && (
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.3 }}
>
<Typography variant="subtitle2" align="center" sx={{ color: 'text.secondary' }}>
{title}
</Typography>
</motion.div>
)}
<Box sx={{ position: 'relative', '&:before': { ...shade, left: 0 }, '&:after': { ...shade, right: 0, rotate: '180deg' } }}>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.4
}}
>
<Slider {...settings}>
{clienteleList.map((item, index) => (
<motion.div
key={index}
initial={{ opacity: 0, scale: 0.5 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.6, ease: 'easeOut', delay: index * 0.2 }}
>
<Box
sx={{
px: { xs: 0.25, sm: 0.5, md: 0.75 },
'& svg': { opacity: 0.4, transition: ' all 0.5s ease-in-out' },
'&:hover svg': { opacity: 1, transition: ' all 0.5s ease-in-out' }
}}
>
<Chip
label={<GraphicsImage {...item} />}
slotProps={{ label: { sx: { p: 0 } } }}
sx={{ bgcolor: 'grey.100', height: { xs: 40, sm: 46, md: 60 }, width: 1 }}
/>
</Box>
</motion.div>
))}
</Slider>
</motion.div>
</Box>
</Stack>
</ContainerWrapper>
);
}
Clientele3.propTypes = { title: PropTypes.string, clienteleList: PropTypes.array };
@@ -0,0 +1 @@
export { default as Clientele3 } from './Clientele3';
@@ -0,0 +1,131 @@
'use client';
import PropTypes from 'prop-types';
// @mui
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box';
// @third-party
import { motion } from 'framer-motion';
// @project
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import { GraphicsCard } from '@/components/cards';
import { ContactUsForm2 } from '@/components/contact-us';
import ContainerWrapper from '@/components/ContainerWrapper';
import SvgIcon from '@/components/SvgIcon';
import Typeset from '@/components/Typeset';
import { SECTION_COMMON_PY } from '@/utils/constant';
/*************************** CONTACT US - CARD ***************************/
function ContactCard({ icon, title, content, link }) {
return (
<GraphicsCard sx={{ height: 1 }}>
<Stack direction={{ xs: 'row', sm: 'column' }} sx={{ gap: { xs: 2, sm: 4, md: 5 }, height: 1, p: { xs: 2, sm: 3, md: 4 } }}>
<Avatar sx={{ width: 60, height: 60, bgcolor: 'grey.300' }}>
<SvgIcon {...(typeof icon === 'string' ? { name: icon } : { ...icon })} />
</Avatar>
<Stack sx={{ gap: { xs: 2, md: 3 }, height: 1, alignItems: 'flex-start', justifyContent: 'space-between' }}>
<Typeset
{...{
heading: title,
caption: content,
stackProps: { sx: { gap: 1 } },
headingProps: { variant: 'h4' },
captionProps: { variant: 'body1' }
}}
/>
{link && (
<ButtonAnimationWrapper>
<Button color="primary" variant="outlined" {...link} />
</ButtonAnimationWrapper>
)}
</Stack>
</Stack>
</GraphicsCard>
);
}
/*************************** CONTACT US - 4 ***************************/
/**
*
* Demos:
* - [ContactUs4](https://www.saasable.io/blocks/contact-us/contact-us4)
*
* API:
* - [ContactUs4 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/contact-us/contactus4#props-details)
*/
export default function ContactUs4({ heading, caption, list, showForm = true }) {
const sectionPadding = { xs: 2, sm: 3, md: 5 };
const cardRadius = { xs: 6, sm: 8 };
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<Stack sx={{ gap: { xs: 3, sm: 4 } }}>
<Grid container spacing={1.5}>
{showForm && (
<Grid size={12}>
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.4,
delay: 0.4
}}
style={{ height: '100%' }}
>
<GraphicsCard sx={{ height: 1, borderRadius: cardRadius }}>
<GraphicsCard sx={{ bgcolor: 'grey.200', borderRadius: cardRadius }}>
<Box sx={{ p: { xs: 2, sm: 4, md: 5 } }}>
{heading && (
<Typeset
{...{
heading,
caption,
stackProps: { sx: { alignItems: 'center', textAlign: 'center' } },
headingProps: { sx: { maxWidth: { xs: '85%', sm: '80%' } } },
captionProps: { sx: { maxWidth: { sm: '60%' } } }
}}
/>
)}
</Box>
</GraphicsCard>
<Box sx={{ p: sectionPadding, px: { md: 24 } }}>
<ContactUsForm2 />
</Box>
</GraphicsCard>
</motion.div>
</Grid>
)}
{list?.map((item, index) => (
<Grid key={index} size={{ xs: 12, sm: 4 }}>
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.4,
delay: item.animationDelay
}}
style={{ height: '100%' }}
>
<ContactCard {...{ ...item }} />
</motion.div>
</Grid>
))}
</Grid>
</Stack>
</ContainerWrapper>
);
}
ContactCard.propTypes = { icon: PropTypes.any, title: PropTypes.any, content: PropTypes.any, link: PropTypes.any };
ContactUs4.propTypes = { heading: PropTypes.any, caption: PropTypes.any, list: PropTypes.any, showForm: PropTypes.bool };
@@ -0,0 +1 @@
export { default as ContactUs4 } from './ContactUs4';
@@ -0,0 +1,122 @@
'use client';
import PropTypes from 'prop-types';
// @mui
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @third-party
import { motion } from 'motion/react';
// @project
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import ContainerWrapper from '@/components/ContainerWrapper';
import { GraphicsCard } from '@/components/cards';
import { ProfileGroup } from '@/components/cards/profile-card';
import SvgIcon from '@/components/SvgIcon';
import { SECTION_COMMON_PY } from '@/utils/constant';
// @assets
import Arrow from '@/images/graphics/Arrow';
/*************************** CALL TO ACTION - 4 ***************************/
/**
*
* Demos:
* - [CTA4](https://www.saasable.io/blocks/cta/cta4)
*
* API:
* - [CTA4 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/cta/cta4#props-details)
*/
export default function Cta4({ headLine, primaryBtn, profileGroups, list, clientContent }) {
const transformValues = { xs: 'rotate(45deg)', sm: 'rotate(320deg)', md: 'unset' };
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<GraphicsCard>
<Box sx={{ p: { xs: 3, sm: 4, md: 5 } }}>
<Grid container spacing={{ xs: 5, sm: 0, md: 3 }} sx={{ alignItems: 'flex-end' }}>
<Grid size={{ xs: 12, sm: 9, md: 8 }}>
<Stack sx={{ gap: 5 }}>
<ProfileGroup {...profileGroups} />
<Stack sx={{ gap: { xs: 2, sm: 5 } }}>
{typeof headLine === 'string' ? <Typography variant="h2">{headLine}</Typography> : headLine}
{list && (
<Stack direction={{ sm: 'row' }} sx={{ columnGap: { xs: 1, sm: 3 }, rowGap: 1, flexWrap: 'wrap' }}>
{list.map((item, index) => (
<motion.div
key={index}
initial={{ opacity: 0, x: -30 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.2, ease: 'easeInOut', delay: index * 0.6 }}
>
<Stack direction="row" sx={{ gap: 1, alignItems: 'center' }}>
<SvgIcon name="tabler-rosette-discount-check" color="text.secondary" stroke={1} />
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
{item.primary}
</Typography>
</Stack>
</motion.div>
))}
</Stack>
)}
</Stack>
</Stack>
</Grid>
<Grid sx={{ position: 'relative', pl: { md: 3 }, pt: { md: 3 } }} size={{ sm: 3, md: 4 }}>
<Box
sx={{
position: 'absolute',
top: { xs: -36, sm: -98, md: -68 },
right: { xs: -70, sm: 40, md: 100 },
transform: transformValues
}}
>
<Arrow />
</Box>
<Typography
variant="subtitle1"
sx={{
color: 'primary.main',
width: 94,
position: 'absolute',
top: { xs: 6, sm: -160, md: -82 },
right: { xs: -160, sm: 0 }
}}
>
{clientContent}
</Typography>
<Box sx={{ textAlign: 'right' }}>
<motion.div
initial={{ scale: 0.9 }}
animate={{ opacity: 1, y: 0, scale: [1, 1.05, 1] }}
transition={{ duration: 1.1, delay: 0.1, ease: 'easeInOut', repeat: Infinity }}
whileHover={{ scale: 1, transition: { duration: 0.3 } }}
whileTap={{ scale: 0.95 }}
>
<ButtonAnimationWrapper>
<Button color="primary" size="large" variant="contained" sx={{ minWidth: { md: 263 } }} {...primaryBtn} />
</ButtonAnimationWrapper>
</motion.div>
</Box>
</Grid>
</Grid>
</Box>
</GraphicsCard>
</ContainerWrapper>
);
}
Cta4.propTypes = {
headLine: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
primaryBtn: PropTypes.any,
profileGroups: PropTypes.object,
list: PropTypes.array,
clientContent: PropTypes.string
};
@@ -0,0 +1,200 @@
'use client';
import PropTypes from 'prop-types';
// @mui
import Button from '@mui/material/Button';
import Chip from '@mui/material/Chip';
import Divider from '@mui/material/Divider';
import Grid from '@mui/material/Grid';
import OutlinedInput from '@mui/material/OutlinedInput';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @third-party
import { motion } from 'motion/react';
// @project
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import ContainerWrapper from '@/components/ContainerWrapper';
import { GraphicsCard } from '@/components/cards';
import { ProfileGroup } from '@/components/cards/profile-card';
import LogoWatermark from '@/components/logo/LogoWatermark';
import Typeset from '@/components/Typeset';
import { SECTION_COMMON_PY } from '@/utils/constant';
// @assets
import Wave from '@/images/graphics/Wave';
/*************************** CALL TO ACTION - 5 ***************************/
/**
*
* Demos:
* - [CTA5](https://www.saasable.io/blocks/cta/cta5)
*
* API:
* - [CTA5 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/cta/cta5#props-details)
*/
export default function Cta5({ heading, caption, label, input = false, primaryBtn, secondaryBtn, description, saleData, profileGroups }) {
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.4
}}
>
<Grid container spacing={1.5}>
<Grid size={{ xs: 12, sm: 8, md: 9 }}>
<motion.div initial={{ opacity: 0, y: -100 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.8, delay: 0.6 }}>
<GraphicsCard sx={{ position: 'relative' }}>
<Stack
sx={{ alignItems: 'flex-start', gap: { xs: 5.75, sm: 10 }, p: { xs: 3, sm: 4, md: 8 }, position: 'relative', zIndex: 1 }}
>
<Stack sx={{ gap: 5 }}>
<Stack direction="row" sx={{ alignItems: 'center', gap: 1 }}>
<Chip
label={label}
variant="outlined"
slotProps={{ label: { sx: { py: 0.75, px: 2, typography: 'caption', color: 'secondary.main' } } }}
sx={{ borderColor: 'grey.600' }}
/>
<Divider sx={{ width: 63, borderBottomWidth: 2 }} />
</Stack>
<Typeset {...{ heading, caption, captionProps: { sx: { maxWidth: 478 } } }} />
</Stack>
{input && typeof input === 'object' && (
<Stack sx={{ gap: 0.75, width: { sm: '100%', md: 'unset' } }}>
<OutlinedInput
placeholder={input.placeholder || 'Enter your email address'}
endAdornment={
<Button
color="primary"
variant="contained"
sx={{ px: 4, minWidth: { xs: 110, md: 120 } }}
{...input.adornmentBtn}
/>
}
slotProps={{
input: { 'aria-label': 'Email address', sx: { px: 2.5, py: 0.75 } },
notchedOutline: { sx: { borderRadius: 25 } }
}}
sx={{ typography: 'caption2', color: 'secondary.main', p: 0.5, whiteSpace: 'nowrap' }}
/>
{input.helpertext && (
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
{input.helpertext}
</Typography>
)}
</Stack>
)}
{(primaryBtn || secondaryBtn || description) && (
<Stack sx={{ alignItems: 'flex-start', gap: 1.5, width: { sm: '100%', md: '60%' }, ...(input && { mt: -6 }) }}>
{(primaryBtn || secondaryBtn) && (
<Stack direction="row" spacing={1.5} sx={{ alignItems: 'flex-start', justifyContent: 'center' }}>
{secondaryBtn && (
<ButtonAnimationWrapper>
<Button variant="outlined" sx={{ minWidth: { sm: 170 } }} {...secondaryBtn} />
</ButtonAnimationWrapper>
)}
{primaryBtn && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button variant="contained" sx={{ minWidth: { sm: 170 } }} {...primaryBtn} />
</ButtonAnimationWrapper>
</motion.div>
)}
</Stack>
)}
{description && typeof description === 'string' ? (
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
{description}
</Typography>
) : (
description
)}
</Stack>
)}
</Stack>
<Box
sx={{ position: 'absolute', right: -160, bottom: -160, display: { xs: 'none', md: 'block' }, transform: 'scaleX(-1)' }}
>
<LogoWatermark />
</Box>
</GraphicsCard>
</motion.div>
</Grid>
<Grid size={{ xs: 12, sm: 4, md: 3 }}>
<Grid container sx={{ height: 1, position: 'relative' }}>
<Grid size={{ xs: 6, sm: 12 }} sx={{ minHeight: { sm: '50%' } }}>
<GraphicsCard sx={{ height: 1 }}>
<Stack sx={{ alignItems: 'center', gap: 1, py: { xs: 2, sm: 6, md: 7.5 }, px: { xs: 2, sm: 3.5 }, textAlign: 'center' }}>
<Typography component="div" variant="h1">
{saleData.count}
<Typography variant="h2" component="span" sx={{ color: 'text.secondary' }}>
{saleData.defaultUnit}
</Typography>
</Typography>
<Typography sx={{ color: 'text.secondary' }}>{saleData.caption}</Typography>
</Stack>
</GraphicsCard>
</Grid>
<Box
sx={{
position: 'absolute',
left: '50%',
top: '50%',
transform: { xs: 'translate(-50%,-50%) rotate(90deg)', sm: 'translate(-50%,-50%)' },
'& .wave svg': { width: { xs: 70, sm: 122 } }
}}
>
<Wave />
</Box>
<Grid size={{ xs: 6, sm: 12 }} sx={{ minHeight: { sm: '50%' } }}>
<GraphicsCard sx={{ height: 1 }}>
<ProfileGroup
{...profileGroups}
sx={{
py: { xs: 2, sm: 4, md: 6.75 },
px: { xs: 2, sm: 1.5 },
height: 1,
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center',
'& .MuiAvatarGroup-root': { mb: 0.5 },
'& .MuiAvatar-root': { width: { xs: 40, sm: 58 }, height: { xs: 40, sm: 58 } },
'& .wave': { display: 'none' }
}}
/>
</GraphicsCard>
</Grid>
</Grid>
</Grid>
</Grid>
</motion.div>
</ContainerWrapper>
);
}
Cta5.propTypes = {
heading: PropTypes.string,
caption: PropTypes.string,
label: PropTypes.string,
input: PropTypes.oneOfType([PropTypes.bool, PropTypes.any]),
primaryBtn: PropTypes.any,
secondaryBtn: PropTypes.any,
description: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),
saleData: PropTypes.any,
profileGroups: PropTypes.object
};
@@ -0,0 +1,2 @@
export { default as Cta4 } from './Cta4';
export { default as Cta5 } from './Cta5';
@@ -0,0 +1,211 @@
'use client';
import PropTypes from 'prop-types';
import { useState } from 'react';
// @next
import NextLink from 'next/link';
// @mui
import { useTheme } from '@mui/material/styles';
import Accordion from '@mui/material/Accordion';
import AccordionDetails from '@mui/material/AccordionDetails';
import AccordionSummary from '@mui/material/AccordionSummary';
import Button from '@mui/material/Button';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
// @third-party
import { motion } from 'motion/react';
import Slider from 'react-slick';
// @project
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import ContainerWrapper from '@/components/ContainerWrapper';
import FaqDetails from '@/components/faq/FaqDetails';
import SvgIcon from '@/components/SvgIcon';
import Typeset from '@/components/Typeset';
import useFocusWithin from '@/hooks/useFocusWithin';
import { generateFocusVisibleStyles } from '@/utils/CommonFocusStyle';
import { SECTION_COMMON_PY } from '@/utils/constant';
/*************************** FAQ - 6 ***************************/
/**
*
* Demos:
* - [FAQ6](https://www.saasable.io/blocks/faq/faq6)
*
* API:
* - [FAQ6 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/faq/faq6#props-details)
*/
export default function Faq6({ heading, caption, defaultExpanded, faqList, getInTouch, categories, activeCategory }) {
const theme = useTheme();
const isFocusWithin = useFocusWithin();
const [expanded, setExpanded] = useState(defaultExpanded || false);
const [activeTopic, setActiveTopic] = useState(activeCategory || '');
const [filterFaqList, setFilterFaqList] = useState(activeCategory ? faqList.filter((item) => item.category === activeCategory) : faqList);
const cardRadius = { xs: 4, sm: 6 };
const accordionRadius = { xs: cardRadius.xs * 4, sm: cardRadius.sm * 4 };
const accordionPX = { xs: 2, sm: 3 };
const iconProps = { color: 'text.primary' };
// Handles the expansion of accordion panels
const handleChange = (panel) => (event, isExpanded) => setExpanded(isExpanded ? panel : false);
const slickStyle = { '& .slick-slide': { ' > div': { px: { xs: 0.5, md: 0.75 } } } };
const settings = {
arrows: false,
dots: false,
infinite: false,
speed: 500,
swipeToSlide: true,
initialSlide: 0,
variableWidth: true
};
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<Stack sx={{ gap: { xs: 3, sm: 4 } }}>
{heading && (
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
>
<Stack direction={{ sm: 'row' }} sx={{ gap: 4, justifyContent: 'space-between', alignItems: { xs: 'flex-start', sm: 'end' } }}>
<Typeset {...{ heading, caption }} />
{getInTouch?.link && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button
variant="contained"
size="large"
{...getInTouch.link}
{...(getInTouch.link && getInTouch.link.href && { component: NextLink })}
sx={{ minWidth: 215, ...getInTouch.link.sx }}
/>
</ButtonAnimationWrapper>
</motion.div>
)}
</Stack>
</motion.div>
)}
<Stack sx={{ gap: 2 }}>
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.4
}}
>
<Stack sx={slickStyle}>
<Slider {...settings}>
<Button
sx={{
minHeight: { xs: 40, sm: 48 },
color: 'text.primary',
borderColor: 'divider',
bgcolor: activeTopic === '' ? 'grey.100' : 'inherit',
'&.MuiButton-root:hover': { bgcolor: 'grey.100', borderColor: 'divider' }
}}
variant="outlined"
onClick={() => {
setActiveTopic('');
setFilterFaqList(faqList);
}}
>
All
</Button>
{categories.map((item, index) => (
<Button
key={index}
sx={{
minHeight: { xs: 40, sm: 48 },
color: 'text.primary',
borderColor: 'divider',
bgcolor: activeTopic === item ? 'grey.100' : 'inherit',
'&.MuiButton-root:hover': { bgcolor: 'grey.100', borderColor: 'divider' }
}}
variant="outlined"
onClick={() => {
setActiveTopic(item);
setFilterFaqList(faqList.filter((list) => list.category === item));
}}
>
{item}
</Button>
))}
</Slider>
</Stack>
</motion.div>
<Stack
sx={{
gap: 1.5,
'& .MuiAccordion-root:first-of-type': { borderTopLeftRadius: accordionRadius, borderTopRightRadius: accordionRadius },
'& .MuiAccordion-root:last-of-type': { borderBottomLeftRadius: accordionRadius, borderBottomRightRadius: accordionRadius }
}}
>
{filterFaqList.map((item, index) => (
<motion.div
key={index}
initial={{ y: 20, opacity: 0 }}
whileInView={{ y: 0, opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.2, delay: index * 0.2 }}
>
<Accordion
key={index}
expanded={expanded === `panel${index}`}
onChange={handleChange(`panel${index}`)}
sx={{
borderRadius: cardRadius,
backgroundColor: 'grey.100',
...(isFocusWithin && { '&:focus-within': generateFocusVisibleStyles(theme.vars.palette.primary.main) })
}}
>
<AccordionSummary
expandIcon={<SvgIcon name={expanded === `panel${index}` ? 'tabler-minus' : 'tabler-plus'} {...iconProps} size={20} />}
sx={{
p: accordionPX,
'&.Mui-focusVisible': { bgcolor: 'transparent' },
'&:hover, &:hover svg': { color: 'primary.dark' }
}}
slotProps={{ content: { sx: { my: 0 } } }}
>
<Typography variant="h4">{item.question}</Typography>
</AccordionSummary>
<AccordionDetails sx={{ px: accordionPX, pt: 0, pb: accordionPX }} key={index}>
<FaqDetails answer={item.answer} />
</AccordionDetails>
</Accordion>
</motion.div>
))}
</Stack>
</Stack>
</Stack>
</ContainerWrapper>
);
}
Faq6.propTypes = {
heading: PropTypes.any,
caption: PropTypes.any,
defaultExpanded: PropTypes.any,
faqList: PropTypes.any,
getInTouch: PropTypes.any,
categories: PropTypes.array,
activeCategory: PropTypes.string
};
@@ -0,0 +1 @@
export { default as Faq6 } from './Faq6';
@@ -0,0 +1,268 @@
'use client';
import PropTypes from 'prop-types';
import { useState } from 'react';
// @mui
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Tab from '@mui/material/Tab';
import TabContext from '@mui/lab/TabContext';
import TabList from '@mui/lab/TabList';
import TabPanel from '@mui/lab/TabPanel';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @third-party
import { motion } from 'motion/react';
// @project
import ContainerWrapper from '@/components/ContainerWrapper';
import { GraphicsCard } from '@/components/cards';
import SvgIcon from '@/components/SvgIcon';
import Typeset from '@/components/Typeset';
import { SECTION_COMMON_PY } from '@/utils/constant';
// @assets
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import GraphicsImage from '@/components/GraphicsImage';
/*************************** FEATURE - 18 ***************************/
/**
*
* Demos:
* - [Feature18](https://www.saasable.io/blocks/feature/feature18)
*
* API
* - [Feature18 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/feature/feature18#props-details)
*/
export default function Feature18({ heading, caption, topics }) {
const boxPadding = { xs: 3, md: 5 };
const imagePadding = { xs: 3, sm: 4, md: 5 };
const [value, setValue] = useState('1');
// Handle tab change
const handleChange = (event, newValue) => {
setValue(newValue);
};
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<Stack sx={{ gap: { xs: 3, sm: 4 } }}>
<Typeset
{...{
heading,
caption,
stackProps: { sx: { alignItems: 'center', textAlign: 'center', maxWidth: { sm: 470, md: 615 }, mx: 'auto' } }
}}
/>
<Stack sx={{ gap: 1.5, alignItems: 'center' }}>
<TabContext value={value}>
<GraphicsCard sx={{ width: { xs: 1, sm: 'unset' } }}>
<Box sx={{ p: 0.25 }}>
<TabList
onChange={handleChange}
sx={{ minHeight: 'unset', p: 0.25 }}
slotProps={{ indicator: { sx: { display: 'none' } } }}
variant="scrollable"
>
{topics.map((item, index) => (
<Tab
label={item.title}
disableFocusRipple
{...(item.icon && {
icon: (
<SvgIcon
{...(typeof item.icon === 'string' ? { name: item.icon } : { ...item.icon })}
size={16}
stroke={2}
color="text.secondary"
/>
)
})}
value={String(index + 1)}
key={index}
iconPosition="start"
tabIndex={0}
sx={{
minHeight: 44,
minWidth: { xs: 112, md: 160, sm: 156 },
borderRadius: 10,
borderWidth: 1,
borderStyle: 'solid',
borderColor: 'transparent',
'& svg ': { mr: 1 },
'&.Mui-selected': {
bgcolor: 'grey.200',
borderColor: 'grey.400',
minWidth: { xs: 112, md: 160, sm: 156 },
color: 'text.primary',
'& svg': { stroke: 'text.primary' }
},
'&.Mui-focusVisible': { bgcolor: 'grey.300' },
'&:hover': { bgcolor: 'grey.200' }
}}
/>
))}
</TabList>
</Box>
</GraphicsCard>
{topics.map((item, index) => (
<TabPanel value={String(index + 1)} key={index} sx={{ p: 0, width: 1 }}>
<Grid container spacing={1.5}>
<Grid size={{ xs: 12, sm: 5 }}>
<GraphicsCard>
<motion.div
initial={{ opacity: 0, x: 100, y: 100 }}
whileInView={{ opacity: 1, x: 0, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: 0.1 }}
>
<Box
sx={{
pl: item.isCoverImage ? 0 : imagePadding,
pt: item.isCoverImage ? 0 : imagePadding,
height: { xs: 260, sm: 396, md: 434 }
}}
>
<GraphicsImage
sx={{
height: 1,
backgroundPositionX: 'left',
backgroundPositionY: 'top',
...(item.isImageBorder && { borderTop: '5px solid', borderLeft: '5px solid', borderColor: 'grey.200' }),
...(item.isCoverImage && { backgroundSize: 'cover', border: 'none' }),
borderTopLeftRadius: { xs: 12 },
borderBottomRightRadius: { xs: 20, sm: 32, md: 40 }
}}
image={item.image}
/>
</Box>
</motion.div>
</GraphicsCard>
</Grid>
<Grid size={{ xs: 12, sm: 7 }} sx={{ display: 'flex' }}>
<GraphicsCard>
<Stack
sx={{
justifyContent: 'space-between',
gap: 5,
height: item.actionBtn || item.actionBtn2 ? { sm: 'calc(100% - 98px)', md: 'calc(100% - 114px)' } : 1,
pt: boxPadding,
px: boxPadding
}}
>
<motion.div
key={index}
initial={{ opacity: 0, x: -30 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -30 }}
transition={{ duration: 0.2, ease: 'linear', delay: index * 0.1 }}
>
<Stack direction="row" sx={{ gap: 1 }}>
{item.icon && (
<SvgIcon
{...(typeof item.icon === 'string' ? { name: item.icon } : { ...item.icon })}
size={16}
stroke={2}
color="text.primary"
/>
)}
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
{item.title}
</Typography>
</Stack>
</motion.div>
<Stack sx={{ gap: { xs: 2, md: 3 }, pb: boxPadding }}>
<Stack sx={{ gap: 0.5 }}>
<Typography variant="h4">{item.title2}</Typography>
{item.description && <Typography sx={{ color: 'text.secondary' }}>{item.description}</Typography>}
</Stack>
{item.list && (
<Grid container spacing={{ xs: 0.75, md: 1 }}>
{item.list.map((list, index) => (
<Grid key={index} size={{ xs: 12, md: 6 }}>
<motion.div
key={index}
initial={{ opacity: 0, x: -30 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -30 }}
transition={{ duration: 0.2, ease: 'linear', delay: index * 0.1 }}
>
<Stack
direction="row"
sx={{
gap: 0.5,
alignItems: 'center',
'& svg.tabler-rosette-discount-check': { width: { xs: 16, md: 24 }, height: { xs: 16, md: 24 } }
}}
>
<SvgIcon name="tabler-rosette-discount-check" stroke={1} color="text.secondary" />
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
{list.primary}
</Typography>
</Stack>
</motion.div>
</Grid>
))}
</Grid>
)}
</Stack>
</Stack>
{(item.actionBtn || item.actionBtn2) && (
<GraphicsCard sx={{ bgcolor: 'grey.200' }}>
<Stack direction="row" sx={{ alignItems: 'flex-start', gap: 1.5, p: { xs: 2, sm: 3, md: 4 } }}>
{item.actionBtn2 && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button
variant="outlined"
color="primary"
startIcon={<SvgIcon name="tabler-help" size={16} stroke={3} />}
{...item.actionBtn2}
/>
</ButtonAnimationWrapper>
</motion.div>
)}
{item.actionBtn && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button
variant="contained"
color="primary"
startIcon={<SvgIcon name="tabler-link" size={16} stroke={3} color="background.default" />}
{...item.actionBtn}
/>
</ButtonAnimationWrapper>
</motion.div>
)}
</Stack>
</GraphicsCard>
)}
</GraphicsCard>
</Grid>
</Grid>
</TabPanel>
))}
</TabContext>
</Stack>
</Stack>
</ContainerWrapper>
);
}
Feature18.propTypes = { heading: PropTypes.string, caption: PropTypes.string, topics: PropTypes.array };
@@ -0,0 +1,248 @@
'use client';
import PropTypes from 'prop-types';
// @mui
import { useTheme } from '@mui/material/styles';
import useMediaQuery from '@mui/material/useMediaQuery';
import Avatar from '@mui/material/Avatar';
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @third-party
import { motion } from 'motion/react';
// @project
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import ContainerWrapper from '@/components/ContainerWrapper';
import { GraphicsCard } from '@/components/cards';
import GraphicsImage from '@/components/GraphicsImage';
import SvgIcon from '@/components/SvgIcon';
import Typeset from '@/components/Typeset';
import { withAlpha } from '@/utils/colorUtils';
import { SECTION_COMMON_PY } from '@/utils/constant';
// @assets
import Star from '@/images/graphics/Star';
/*************************** FEATURE - 20 ***************************/
/**
*
* Demos:
* - [Feature20](https://www.saasable.io/blocks/feature/feature20)
*
* API
* - [Feature20 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/feature/feature20#props-details)
*/
export default function Feature20({ heading, caption, image, features, actionBtn, secondaryBtn }) {
const theme = useTheme();
const downSM = useMediaQuery(theme.breakpoints.down('sm'));
const downMD = useMediaQuery(theme.breakpoints.down('md'));
const partitionInExtraSmall = 1;
const partitionInSmall = 2;
const partitionInLarge = 3;
const columns = downSM ? partitionInExtraSmall : downMD ? partitionInSmall : partitionInLarge;
const calculateElementsInLastRow = (dataArray, columns) => {
const totalItems = dataArray.length;
const elementsInLastRow = totalItems % columns || columns;
return elementsInLastRow;
};
const calculateIndexOfFirstElementInLastRow = (dataArray, elementsInLastRow) => {
const totalItems = dataArray.length;
const indexOfFirstElementInLastRow = totalItems - elementsInLastRow;
return indexOfFirstElementInLastRow;
};
const elementsInLastRow = calculateElementsInLastRow(features, columns);
const indexOfFirstElementInLastRow = calculateIndexOfFirstElementInLastRow(features, elementsInLastRow);
const calculateIndexOfLastElementOfEachRow = (dataArray, columns) => {
const indices = [];
const totalItems = dataArray.length;
const rows = Math.ceil(totalItems / columns);
for (let i = 1; i <= rows; i++) {
const lastIndexInRow = i * columns - 1;
indices.push(lastIndexInRow < totalItems ? lastIndexInRow : totalItems - 1);
}
return indices;
};
const indicesOfLastElements = calculateIndexOfLastElementOfEachRow(features, columns);
const gc = theme.vars.palette.background.default;
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<Stack sx={{ gap: { xs: 3, sm: 4, md: 5 } }}>
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.3
}}
>
<Typeset {...{ heading, stackProps: { sx: { maxWidth: { md: 500 }, ...(!image && { maxWidth: 1, textAlign: 'center' }) } } }} />
</motion.div>
<motion.div
initial={{ opacity: 0, y: 25 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.4
}}
>
<GraphicsCard sx={{ position: 'relative', overflow: 'visible' }}>
{image && (
<GraphicsCard
sx={{
height: { md: 267 },
width: { md: 456 },
bgcolor: 'transparent',
position: 'absolute',
top: -190,
right: 45,
zIndex: -1,
display: { xs: 'none', md: 'block' }
}}
>
<GraphicsImage sx={{ height: 1, backgroundPositionX: 'right', backgroundPositionY: 'top' }} image={image}>
<Box
sx={{ width: 1, height: 1, background: `linear-gradient(180deg, ${withAlpha(gc, 0)} 0%, ${withAlpha(gc, 0.6)} 100%)` }}
/>
</GraphicsImage>
</GraphicsCard>
)}
<Box sx={{ p: 3 }}>
<Grid container>
{features.map((item, index) => (
<Grid
key={index}
size={{ xs: 12 / partitionInExtraSmall, sm: 12 / partitionInSmall, md: 12 / partitionInLarge }}
sx={{
position: 'relative',
...(index < indexOfFirstElementInLastRow && { borderBottom: `1px solid ${theme.vars.palette.grey[300]}` }),
...(!indicesOfLastElements.includes(index) && { borderRight: `1px solid ${theme.vars.palette.grey[300]}` })
}}
>
<Stack sx={{ gap: { xs: 3, sm: 4 }, height: 1, py: { xs: 1.5, sm: 3, md: 4 }, px: { xs: 0, sm: 3, md: 4 } }}>
<Avatar sx={{ width: 60, height: 60, bgcolor: 'grey.300' }}>
<motion.div
initial={{ opacity: 0, scale: 0.6 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 2, delay: index * 0.1 }}
>
<SvgIcon {...(typeof item.icon === 'string' ? { name: item.icon } : { ...item.icon })} />
</motion.div>
</Avatar>
<Stack sx={{ gap: { xs: 0.5, md: 1 } }}>
<motion.div
initial={{ opacity: 0, y: 25 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.2 }}
>
{item.title && <Typography variant="h4">{item.title}</Typography>}
</motion.div>
<motion.div
initial={{ opacity: 0, y: 25 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.5, delay: index * 0.3 }}
>
{item.content && <Typography sx={{ color: 'text.secondary' }}>{item.content}</Typography>}
</motion.div>
</Stack>
</Stack>
{index < indexOfFirstElementInLastRow && !indicesOfLastElements.includes(index) && (
<Stack sx={{ position: 'absolute', bottom: -9, right: -9 }}>
<Star />
</Stack>
)}
</Grid>
))}
</Grid>
</Box>
</GraphicsCard>
</motion.div>
<Stack sx={{ alignItems: 'center', gap: 3 }}>
<Typography variant="h6" sx={{ color: 'text.secondary', maxWidth: { xs: '75%', sm: '45%' }, textAlign: 'center' }}>
<motion.div
initial={{ opacity: 0, y: 15 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.4
}}
>
{caption}
</motion.div>
</Typography>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.5
}}
>
<Stack direction="row" sx={{ alignItems: 'center', justifyContent: 'center', gap: 1.5 }}>
{secondaryBtn && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button variant="outlined" {...secondaryBtn} />
</ButtonAnimationWrapper>
</motion.div>
)}
{actionBtn && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button
variant="contained"
color="primary"
startIcon={<SvgIcon name="tabler-sparkles" size={16} stroke={3} color="background.default" />}
{...actionBtn}
/>
</ButtonAnimationWrapper>
</motion.div>
)}
</Stack>
</motion.div>
</Stack>
</Stack>
</ContainerWrapper>
);
}
Feature20.propTypes = {
heading: PropTypes.string,
caption: PropTypes.string,
image: PropTypes.any,
features: PropTypes.array,
actionBtn: PropTypes.any,
secondaryBtn: PropTypes.any
};
@@ -0,0 +1,153 @@
'use client';
import PropTypes from 'prop-types';
// @mui
import Button from '@mui/material/Button';
import Grid from '@mui/material/Grid';
import Stack from '@mui/material/Stack';
import Box from '@mui/material/Box';
// @third-party
import { motion } from 'motion/react';
// @project
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import { GraphicsCard, IconCard } from '@/components/cards';
import ContainerWrapper from '@/components/ContainerWrapper';
import GraphicsImage from '@/components/GraphicsImage';
import Typeset from '@/components/Typeset';
import SvgIcon from '@/components/SvgIcon';
import { SECTION_COMMON_PY } from '@/utils/constant';
/*************************** FEATURE - 21 ***************************/
/**
*
* Demos:
* - [Feature21](https://www.saasable.io/blocks/feature/feature21)
*
* API
* - [Feature21 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/feature/feature21#props-details)
*/
export default function Feature21({ heading, caption, image, features, primaryBtn, secondaryBtn }) {
const imagePadding = { xs: 3, sm: 4, md: 5 };
const iconProps = { color: 'text.primary', stroke: 1 };
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<Stack sx={{ gap: { xs: 3, sm: 4 } }}>
{(heading || caption) && (
<motion.div
initial={{ opacity: 0, y: 5 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: 0.3 }}
>
<Typeset {...{ heading, caption, stackProps: { sx: { textAlign: 'center' } } }} />
</motion.div>
)}
<Stack sx={{ gap: 1.5 }}>
{image && (
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.3,
delay: 0.3
}}
>
<GraphicsCard>
<Box sx={{ pl: imagePadding, pt: imagePadding, height: { xs: 204, sm: 300, md: 360 } }}>
<GraphicsImage
image={image}
sx={{
height: 1,
backgroundPositionX: 'left',
backgroundPositionY: 'top',
borderTopLeftRadius: { xs: 12 },
borderBottomRightRadius: { xs: 20, sm: 32, md: 40 },
border: '5px solid',
borderColor: 'grey.200',
borderBottom: 'none',
borderRight: 'none'
}}
/>
</Box>
</GraphicsCard>
</motion.div>
)}
<Grid container spacing={1.5}>
{features.map((item, index) => (
<Grid key={index} size={{ xs: 12, sm: 6, md: 3 }}>
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: index * 0.2 }}
style={{ height: '100%' }}
>
<IconCard
icon={{ ...(typeof item.icon === 'string' ? { name: item.icon, ...iconProps } : { ...iconProps, ...item.icon }) }}
title={item.title}
stackProps={{ sx: { gap: 2, height: 1 } }}
cardPadding={{ xs: 2, sm: 3 }}
/>
</motion.div>
</Grid>
))}
</Grid>
</Stack>
{(primaryBtn || secondaryBtn) && (
<motion.div
initial={{ opacity: 0, y: 10 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.3, delay: 0.4 }}
>
<Stack direction="row" sx={{ alignItems: 'center', justifyContent: 'center', gap: 1.5 }}>
{secondaryBtn && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button variant="outlined" startIcon={<SvgIcon name="tabler-eye" size={16} stroke={3} />} {...secondaryBtn} />
</ButtonAnimationWrapper>
</motion.div>
)}
{primaryBtn && (
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button
variant="contained"
startIcon={<SvgIcon name="tabler-download" size={16} stroke={3} color="background.default" />}
{...primaryBtn}
/>
</ButtonAnimationWrapper>
</motion.div>
)}
</Stack>
</motion.div>
)}
</Stack>
</ContainerWrapper>
);
}
Feature21.propTypes = {
heading: PropTypes.string,
caption: PropTypes.string,
image: PropTypes.any,
features: PropTypes.array,
primaryBtn: PropTypes.any,
secondaryBtn: PropTypes.any
};
@@ -0,0 +1,3 @@
export { default as Feature18 } from './Feature18';
export { default as Feature20 } from './Feature20';
export { default as Feature21 } from './Feature21';
@@ -0,0 +1,205 @@
'use client';
// @next
import NextLink from 'next/link';
// @mui
import Grid from '@mui/material/Grid';
import Link from '@mui/material/Link';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
// @third-party
import { motion } from 'framer-motion';
// @project
import branding from '@/branding.json';
import { GraphicsCard } from '@/components/cards';
import ContainerWrapper from '@/components/ContainerWrapper';
import { Copyright, FollowUS, Sitemap } from '@/components/footer';
import LogoSection from '@/components/logo';
import SvgIcon from '@/components/SvgIcon';
import { CopyrightType } from '@/enum';
import { DOCS_URL, FREEBIES_URL } from '@/path';
import { SECTION_COMMON_PY } from '@/utils/constant';
/*************************** FOOTER - 7 DATA ***************************/
/**
*
* Demos:
* - [Footer7](https://www.saasable.io/blocks/footer/footer7)
*/
const linkProps = { target: '_blank', rel: 'noopener noreferrer' };
const data = [
{
id: 'resources',
grid: { size: { xs: 12, sm: 'auto' } },
title: 'Resources',
menu: [
{
label: 'Freebies',
link: { href: FREEBIES_URL, ...linkProps }
},
{
label: 'Documentation',
link: { href: DOCS_URL, ...linkProps }
},
{
label: 'Blog',
link: { href: 'https://blog.saasable.io/', ...linkProps }
},
{
label: 'Refund Policy',
link: { href: 'https://mui.com/store/customer-refund-policy/', ...linkProps }
}
]
},
{
id: 'support',
grid: { size: { xs: 6, sm: 'auto' } },
title: 'Support',
menu: [
{
label: 'Pricing',
link: { href: 'https://mui.com/store/items/saasable-multipurpose-ui-kit-and-dashboard/', ...linkProps }
},
{
label: 'FAQs',
link: { href: 'https://phoenixcoded.gitbook.io/saasable/faq', ...linkProps }
},
{
label: 'Support',
link: { href: branding.company.socialLink.support, ...linkProps }
},
{
label: 'License Terms',
link: { href: 'https://mui.com/store/license/', ...linkProps }
},
{
label: 'Discord',
link: { href: branding.company.socialLink.discord, ...linkProps }
}
]
},
{
id: 'company',
grid: { size: { xs: 6, sm: 'auto' } },
title: 'Company',
menu: [
{
label: 'Why Phoenixcoded?',
link: {
href: 'https://blog.saasable.io/a-decade-of-expertise-the-phoenixcoded-story-and-why-you-should-trust-us',
...linkProps
}
},
{
label: 'About',
link: { href: 'https://saasable.io/about', ...linkProps }
},
{
label: 'Contact Us',
link: { href: '/contact', ...linkProps }
}
]
}
];
const iconProps = { color: 'text.secondary' };
const usefullLinks = [
{
icon: <SvgIcon name="tabler-brand-figma" {...iconProps} />,
title: 'Figma Version 1.1.0',
href: 'https://www.figma.com/community/file/1425095061180549847'
},
{
icon: <SvgIcon name="tabler-route" {...iconProps} />,
title: 'React Material UI v7',
href: 'https://mui.com/material-ui/getting-started'
},
{
icon: <SvgIcon name="tabler-sparkles" {...iconProps} />,
title: 'Documentation',
href: DOCS_URL
}
];
/*************************** FOOTER - 7 ***************************/
export default function Footer7() {
const logoFollowContent = (
<Stack sx={{ alignItems: 'flex-start', gap: { xs: 1.5, sm: 3 } }}>
<LogoSection />
<Typography variant="h6" sx={{ maxWidth: { sm: 280 }, mb: { xs: -1, sm: -2.5 } }}>
{process.env.NEXT_PUBLIC_VERSION}
</Typography>
<Typography variant="body2" sx={{ maxWidth: { sm: 280 } }}>
Explore the different versions of our {branding.brandName} template.
</Typography>
</Stack>
);
return (
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{
duration: 0.5,
delay: 0.4
}}
>
<Stack id="footer-7" role="contentinfo" rel="noopener noreferrer" aria-label="Footer 7" sx={{ gap: { xs: 3, sm: 4, md: 5 } }}>
<Grid container spacing={{ xs: 4, md: 3 }}>
<Grid size={{ xs: 12, md: 6 }}>
<Stack direction={{ sm: 'row', md: 'column' }} sx={{ gap: 3, justifyContent: 'space-between', height: 1 }}>
{logoFollowContent}
<Stack sx={{ gap: { xs: 2, sm: 2.5, md: 3 } }}>
{usefullLinks.map((item, index) => (
<Stack direction="row" sx={{ gap: 1, alignItems: 'center' }} key={index}>
{item.icon}
<Link
component={NextLink}
variant="body2"
color="text.secondary"
href={item.href}
target="_blank"
rel="noopener noreferrer"
aria-label="Usefull Links"
>
{item.title}
</Link>
</Stack>
))}
</Stack>
</Stack>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<Sitemap list={data} isMenuDesign />
</Grid>
</Grid>
<GraphicsCard sx={{ borderRadius: { xs: 6, sm: 8 } }}>
<Stack
direction={{ sm: 'row' }}
sx={{
alignItems: 'center',
justifyContent: { xs: 'center', sm: 'space-between' },
gap: 1.5,
py: { xs: 2, sm: 1.5 },
px: { xs: 2, sm: 3 }
}}
>
<Copyright type={CopyrightType.TYPE3} />
<FollowUS heading={false} color="grey.100" />
</Stack>
</GraphicsCard>
</Stack>
</motion.div>
</ContainerWrapper>
);
}
@@ -0,0 +1 @@
export { default as Footer7 } from './Footer7';
@@ -0,0 +1,250 @@
'use client';
import PropTypes from 'prop-types';
import { useEffect, useRef, useState } from 'react';
// @mui
import { useTheme } from '@mui/material/styles';
import Button from '@mui/material/Button';
import Chip from '@mui/material/Chip';
import Stack from '@mui/material/Stack';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
// @third-party
import { motion, useScroll, useTransform } from 'motion/react';
// @project
import ButtonAnimationWrapper from '@/components/ButtonAnimationWrapper';
import { GraphicsCard } from '@/components/cards';
import ContainerWrapper from '@/components/ContainerWrapper';
import GraphicsImage from '@/components/GraphicsImage';
import SvgIcon from '@/components/SvgIcon';
import { SECTION_COMMON_PY } from '@/utils/constant';
import { getBackgroundDots } from '@/utils/getBackgroundDots';
import { withAlpha } from '@/utils/colorUtils';
// @assets
import Wave from '@/images/graphics/Wave';
// threshold - adjust threshold as needed
const options = { root: null, rootMargin: '0px', threshold: 0.6 };
/*************************** HERO - 17 ***************************/
/**
*
* Demos:
* - [Hero17](https://www.saasable.io/blocks/hero/hero17)
*
* API:
* - [Hero17 API](https://phoenixcoded.gitbook.io/saasable/ui-kit/development/components/hero/hero17#props-details)
*/
export default function Hero17({ chip, headLine, captionLine, primaryBtn, videoSrc, videoThumbnail, listData }) {
const theme = useTheme();
const boxRadius = { xs: 24, sm: 32, md: 40 };
const containerRef = useRef(null);
const { scrollYProgress } = useScroll({
target: containerRef,
offset: ['start start', 'end start']
});
const scale = useTransform(scrollYProgress, [0, 0.1, 0.2, 0.4, 0.6], [0.9, 0.92, 0.94, 0.96, 1]);
const videoRef = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
// Handle video play/pause based on intersection with the viewport
useEffect(() => {
const handleIntersection = (entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
if (videoRef.current && !isPlaying) {
videoRef.current
.play()
.then(() => {
setIsPlaying(true);
})
.catch((error) => {
console.error('Autoplay was prevented:', error);
});
}
} else {
if (videoRef.current && isPlaying) {
videoRef.current.pause();
setIsPlaying(false);
}
}
});
};
const observer = new IntersectionObserver(handleIntersection, options);
const videoElement = videoRef.current;
if (videoElement) {
observer.observe(videoElement);
}
return () => {
if (videoElement) {
observer.unobserve(videoElement);
}
};
}, [isPlaying]);
return (
<>
<Box
sx={{
height: { xs: 592, sm: 738, md: 878 },
position: 'absolute',
top: 0,
left: 0,
width: 1,
zIndex: -1,
borderBottomLeftRadius: boxRadius,
borderBottomRightRadius: boxRadius,
...getBackgroundDots(theme.vars.palette.grey[300], 2, 35),
bgcolor: 'grey.100'
}}
/>
<ContainerWrapper sx={{ py: SECTION_COMMON_PY }}>
<Box ref={containerRef}>
<Box sx={{ pb: { xs: 3, sm: 4, md: 5 } }}>
<Stack sx={{ alignItems: 'center', gap: 1.5 }}>
<motion.div
initial={{ opacity: 0, scale: 0.6 }}
whileInView={{ opacity: 1, scale: [0.6, 1.15, 0.95, 1] }}
animate={{
boxShadow: [
`0 0 0px ${withAlpha(theme.vars.palette.primary.dark, 0)}`,
`0 0 20px ${withAlpha(theme.vars.palette.primary.main, 0.8)}`,
`0 0 0px ${withAlpha(theme.vars.palette.primary.dark, 0)}`
],
borderRadius: '74px'
}}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.8, ease: 'linear' }}
>
<Chip
variant="outlined"
label={chip.label}
slotProps={{
label: {
sx: { py: 0.5, px: 1.5, ...(typeof chip.label === 'string' && { typography: 'caption', color: 'text.secondary' }) }
}
}}
sx={{ bgcolor: 'grey.100' }}
/>
</motion.div>
<motion.div
initial={{ opacity: 0, scale: 0.6 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.6, delay: 0.2, ease: 'linear' }}
>
<Typography variant="h1" align="center" sx={{ maxWidth: 800 }}>
{headLine}
</Typography>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 1, delay: 0.2, ease: [0.215, 0.61, 0.355, 1] }}
>
<Box sx={{ pt: 0.5, pb: 0.75 }}>
<Wave />
</Box>
</motion.div>
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 1, delay: 0.3, ease: [0.215, 0.61, 0.355, 1] }}
>
<Typography variant="h6" align="center" sx={{ color: 'text.secondary', maxWidth: 650 }}>
{captionLine}
</Typography>
</motion.div>
</Stack>
<Stack sx={{ alignItems: 'center', gap: 2, mt: { xs: 3, sm: 4, md: 5 } }}>
<motion.div
initial={{ opacity: 0, y: 30 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
whileHover={{ scale: 1.06 }}
>
<ButtonAnimationWrapper>
<Button
color="primary"
variant="contained"
startIcon={<SvgIcon name="tabler-sparkles" size={16} stroke={3} color="background.default" />}
{...primaryBtn}
/>
</ButtonAnimationWrapper>
</motion.div>
<Stack direction="row" sx={{ gap: 1, flexWrap: 'wrap', justifyContent: 'center' }}>
{listData.map((item, index) => (
<motion.div
key={index}
initial={{ opacity: 0, scale: 0.6 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.9, delay: index * 0.08, ease: 'linear' }}
>
<Chip
label={item.title}
variant="outlined"
icon={<GraphicsImage image={item.image} sx={{ width: 16, height: 16 }} />}
slotProps={{ label: { sx: { py: 0.75, px: 1, typography: 'caption2' } } }}
sx={{ height: 32, px: 1, bgcolor: 'grey.100' }}
/>
</motion.div>
))}
</Stack>
</Stack>
</Box>
<motion.div
initial={{ opacity: 0, scale: 0.6 }}
whileInView={{ opacity: 1, scale: 0.9 }}
viewport={{ once: true }}
transition={{ duration: 0.9, delay: 0.3 }}
style={{ scale }}
>
<GraphicsCard sx={{ border: '5px solid', borderColor: 'grey.300' }}>
<video
playsInline
ref={videoRef}
width="100%"
height="100%"
style={{ display: 'flex', objectFit: 'cover' }}
preload="metadata"
autoPlay={false}
loop={true}
muted={true}
poster={videoThumbnail}
>
<source src={videoSrc} type="video/mp4" />
</video>
</GraphicsCard>
</motion.div>
</Box>
</ContainerWrapper>
</>
);
}
Hero17.propTypes = {
chip: PropTypes.object,
headLine: PropTypes.string,
captionLine: PropTypes.string,
primaryBtn: PropTypes.any,
videoSrc: PropTypes.string,
videoThumbnail: PropTypes.string,
listData: PropTypes.array
};

Some files were not shown because too many files have changed in this diff Show More