diff --git a/.husky/pre-commit b/.husky/pre-commit index 5b9c373..ac7c128 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,14 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" -changedFiles="$(git diff --name-only --cached)" -npm run spell-check -- --files ${changedFiles} "!**/package-lock.json" "!**/*.svg" "!**/*.png" "!**/*.jppg" "!**/*.ico" +npm run clean-dictionary + +changedFiles="$(git diff --name-only --cached | grep -E '\.(html|txt|json|ts|tsx)$' | grep -E '^(public/|src/)' || true)" +if [ -n "$changedFiles" ]; then + npm run spell-check -- --files ${changedFiles} "!**/package-lock.json" "!**/*.svg" "!**/*.png" "!**/*.jppg" "!**/*.ico" +fi + +lintFiles="$(git diff --name-only --cached | grep -E '\.(ts|tsx)$' | grep -E '^src/' || true)" +if [ -n "$lintFiles" ]; then + npx eslint ${lintFiles} +fi diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..18fe9cd --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,7 @@ +# Agents + +## Merging Pull Requests + +- This repository only allows **rebase merges** (merge commits and squash merges are disabled). +- Branch protection rules require using the `--admin` flag to merge: `gh pr merge --rebase --admin` +- The **Cloudflare Pages** check is the build/deploy check. If it fails, the PR would break the website and should **not** be merged. diff --git a/dictionary.txt b/dictionary.txt index 25707ea..f6cfb4e 100644 --- a/dictionary.txt +++ b/dictionary.txt @@ -1,8 +1,6 @@ adopter&apos Ai AnimatedText -args -argTypes arrowLeft arrowPointer ArrowPointer @@ -19,17 +17,11 @@ card3 CardImage CardsWrapper centeredSlides -ChangeEvent charset ci className -clearInterval clior -codebase collateralization -ComponentMeta -ComponentStory -config const ContainerProps ContentWrapper @@ -42,7 +34,6 @@ descriptionText detectMobile diagramIcon DOCTYPE -DS_Store effect-coverflow EffectCoverflow eslint-disable @@ -59,21 +50,16 @@ FidaMarketplaceCardProps fidaMarketplaceTexts fidaOverlay Fida's -firefox fontFamily fontWeight FooterWrapper formattedText -gh-pages gradientLaptop gradientLaptopMobile gradientPhones grey greyWhite h1 -handleChange -handleDecrement -handleIncrement HeroCard hideBackdrop highlightIndex @@ -124,8 +110,6 @@ isScreen isSmallerCard isTablet iterableItems -javascript -javascript:openPaymentWindow JoinNetwork lang laptopCards @@ -165,7 +149,6 @@ minWidth640 MissionCard MissionCardProps missionCards -mkdir mobileCards MobileHeader mobilePadding @@ -174,12 +157,9 @@ MobilePhaseItemProps modalToggle motionConfig MoveIn -moz-appearance n2022 newDirection -newHeight newsletterTexts -newTop newWidth nft- NFT @@ -192,26 +172,21 @@ nft6 nft-cards NFTDetails nft-infos -NFT-MAKER nfts NFTs NFTSlider NFTSliderContainer ninefold nmeet -NMKR noTextWrap nowrap npm -onChange -onclick onClick onClickLeft onClickLink onClickRight onImageLoad onLoad -openPaymentWindow param paramArr params @@ -223,7 +198,6 @@ PhaseItemProps PhasesContainer phaseWidth png -.pnp PointerWrapper prevState px @@ -242,8 +216,6 @@ roadMapTexts roseDot roseReg rwd -screenX -screenY ScrollPage seamlessAI SeamlessAI @@ -253,7 +225,6 @@ seamlessAITexts setImageHeight setImageWidth setIntersecting -setInterval setIsExpanded setModalToggle setOne @@ -273,7 +244,6 @@ StickyWrapper StyledContainer StyledGenericWrapper StyledHeader -StyledLabel StyledLink styledParts StyledProps @@ -290,7 +260,6 @@ targetRef textAlign TextContainer textData -textfield textGradient textPlaceholder textPlacing @@ -301,15 +270,12 @@ textTertiary600 TextWrapper TitleContainer titleTexts -tj-actions toggleText TopSection TopWrapper transformOrigin transformVariant -typeof vw -webkit-appearance welcomeCards WelcomeCards welcomeHeroCard @@ -317,10 +283,7 @@ welcomeOverlay welcomeOverlayDesktop welcomeTexts whileInView -WithRoseText -wtop nft7 -SwiperCore cover1 nft-modal cover1mobile @@ -332,29 +295,13 @@ cover4 cover4mobile cover5 cover5mobile -activeIndex -setActiveIndex -swiperInstance -setSwiperInstance -activeIndex -handleNextSlide testnet -watchSlidesProgress -onSlideChange -onSwiper SliderContainer -SliderTitle -SliderDescription -translateX .nft-slider .swiper-slide -handleOpenLearnMoreModal FIDA DesktopLinesBg MobileLinesBg -handleOpenModal -isOpen -handleClose fetchpriority MenuButton MobileMenuButton @@ -367,22 +314,13 @@ menuMobileClose menuMobileOpen decodeURIComponent MenuWrapper -.github github -ubuntu-latest moveInAnimationValue -newValue -setValue ConquerRisk StyledConquerRisk conquerRiskTexts getQueryParams mui -renderBullet -bulletClass -NumberInput -spellchecker-cli-action-summary@main -backgroundCheck backgroundColor backgroundGradient greyBackgroundGradient @@ -391,34 +329,31 @@ backgroundImage NotFoundPage Founder&apos FounderContainer -FounderDesktopCard founderDesktopCard FounderHeroCard -fOunderMobileCard founderMobileCard -FounderModal -FounderModalContent -isFounderModalOpen -setIsFounderModalOpen -FounderSale +FounderCards +FounderBenefits +BenefitCard +BenefitContent +BenefitImage +BenefitsSection +handleLearnMore +BenefitStep +handleScrollToBenefits +StyledMenuModalButton +isSlg founderWelcomeHeroCard MobileHeaderFounders HeaderFounders FoundersHeaderMenuMobile StyledFoundersNavButtons -countAda -CounterContainer -popupHeight -popupWidth toUpperCase OurMission ourMissionOverlay ourMissionTexts -paymentUrl url grabCursor -PlusIcon -MinusIcon useCallback useEffect useMediaQuery @@ -432,24 +367,13 @@ useState PhasesCarousel user-scalable user-scalable=1 -userNavigate -austenstone CustomZoom learnAbout MoveOut -setTimeout -InputContainer -HTMLInputElement InputWrapper BrowserRouter -webkit-outer-spin-button -outerHeight utilityGray -GradientButton -NFTButton StyledButton -webkit-inner-spin-button -LearnButton .swiper-button-next .swiper-button-prev buttonLabel diff --git a/package.json b/package.json index 224924b..fe202b5 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "test": "react-scripts test", "eject": "react-scripts eject", "spell-check": "spellchecker --config .spellcheckerrc.json", + "clean-dictionary": "bash scripts/clean-dictionary.sh", "build-dictionary": "spellchecker --config .spellcheckerrc.json --generate-dictionary dictionary.txt", "prepare": "husky install" }, diff --git a/public/index.html b/public/index.html index c04dc4b..4ea3261 100644 --- a/public/index.html +++ b/public/index.html @@ -10,9 +10,6 @@ - - - diff --git a/scripts/clean-dictionary.sh b/scripts/clean-dictionary.sh new file mode 100755 index 0000000..26ba34f --- /dev/null +++ b/scripts/clean-dictionary.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Remove words from dictionary.txt that no longer appear in any source file. +# Scans the same file patterns as .spellcheckerrc.json. + +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)" +DICT="$REPO_ROOT/dictionary.txt" + +if [ ! -f "$DICT" ]; then + echo "dictionary.txt not found" >&2 + exit 1 +fi + +unused=() +while IFS= read -r word; do + [ -z "$word" ] && continue + if ! grep -rqF "$word" \ + --include='*.ts' --include='*.tsx' --include='*.html' --include='*.json' --include='*.css' \ + --exclude-dir=node_modules --exclude-dir=build --exclude-dir=reports \ + --exclude=dictionary.txt \ + "$REPO_ROOT/src" "$REPO_ROOT/public" "$REPO_ROOT/.github" 2>/dev/null; then + unused+=("$word") + fi +done < "$DICT" + +if [ ${#unused[@]} -eq 0 ]; then + exit 0 +fi + +echo "Removing ${#unused[@]} unused dictionary word(s):" +for w in "${unused[@]}"; do + echo " - $w" + grep -vxF "$w" "$DICT" > "$DICT.tmp" && mv "$DICT.tmp" "$DICT" +done + +# Stage the cleaned dictionary so the commit includes it +git add "$DICT" diff --git a/src/assets/icons/minus.svg b/src/assets/icons/minus.svg deleted file mode 100644 index 9989d9a..0000000 --- a/src/assets/icons/minus.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/assets/icons/plus.svg b/src/assets/icons/plus.svg deleted file mode 100644 index de301bb..0000000 --- a/src/assets/icons/plus.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/components/App.tsx b/src/components/App.tsx index 4640522..5830d46 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -2,7 +2,7 @@ import { lazy, Suspense } from 'react'; import { BrowserRouter as Router, Route, Routes } from 'react-router-dom'; const Index = lazy(() => import('../pages/Index')); -const FounderSale = lazy(() => import('../pages/FounderSale')); +const FounderCards = lazy(() => import('../pages/FounderCards')); const NotFoundPage = lazy(() => import('../pages/NotFoundPage')); const App = () => ( @@ -10,7 +10,7 @@ const App = () => ( Loading...}> } /> - } /> + } /> } /> diff --git a/src/components/HeaderFounders.tsx b/src/components/HeaderFounders.tsx index 10ec1dc..cb63a03 100644 --- a/src/components/HeaderFounders.tsx +++ b/src/components/HeaderFounders.tsx @@ -9,10 +9,10 @@ import { MobileHeaderFounders } from './rwd/MobileHeaderFounders'; import { StyledMenuMainButton, StyledMenuModalButton } from './StyledFoundersNavButtons'; interface Props { - handleOpenModal: () => void; + handleLearnMore: () => void; } -export const HeaderFounders = ({ handleOpenModal }: Props) => { +export const HeaderFounders = ({ handleLearnMore }: Props) => { const navigate = useNavigate(); const isTablet = useMediaQuery({ @@ -27,10 +27,10 @@ export const HeaderFounders = ({ handleOpenModal }: Props) => { {isTablet ? ( - + ) : (
- {isSlg ? 'Learn more' : 'Learn more about Fida NFT Collection'} + {isSlg ? 'Learn more' : 'Learn more about Fida NFT Collection'} navigate('/')}> Discover FIDA diff --git a/src/components/founder-sale/Counter.tsx b/src/components/founder-sale/Counter.tsx deleted file mode 100644 index d501808..0000000 --- a/src/components/founder-sale/Counter.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import { useMediaQuery } from '@mui/material'; -import { maxWidth840 } from 'components/rwd/detectMobile'; -import React, { ChangeEvent } from 'react'; -import styled from 'styled-components'; - -import { colors } from 'theme'; - -import { ReactComponent as PlusIcon } from '../../assets/icons/plus.svg'; -import { ReactComponent as MinusIcon } from '../../assets/icons/minus.svg'; - -interface Props { - value: number; - handleIncrement: () => void; - handleDecrement: () => void; - handleChange: (e: ChangeEvent) => void; -} - -export const Counter = React.memo(({ value, handleIncrement, handleDecrement, handleChange }: Props) => { - const isTablet = useMediaQuery(maxWidth840); - - return ( - - - Amount: - - - {isTablet && ( - - )} - - {!isTablet && ( - - )} - - - - ); -}); - -const CounterContainer = styled.div` - display: flex; - gap: 12px; - align-items: center; - - @media (max-width: 840px) { - flex-direction: column; - } -`; - -const StyledLabel = styled.span` - color: ${colors.textTertiary600}; - font-size: 1.5rem; - font-weight: 500; - - transition: 0.5s; - - @media (max-width: 640px) { - font-size: 1rem; - } -`; - -const NumberInput = styled.input` - width: 200px; - height: 56px; - text-align: center; - font-size: 16px; - border: 1px solid #fff; - border-radius: 24px; - background-color: white; - color: ${colors.textTertiary600}; - font-size: 24px; - outline: none; - -moz-appearance: textfield; /* Remove Firefox arrows */ - - ::-webkit-outer-spin-button, - ::-webkit-inner-spin-button { - -webkit-appearance: none; /* Remove Chrome arrows */ - margin: 0; - } - - @media (max-width: 640px) { - height: 42px; - font-size: 18px; - } -`; - -const InputContainer = styled.div` - display: flex; - align-items: center; - gap: 12px; -`; - -const Button = styled.button<{ disabled: boolean }>` - width: 56px; - height: 56px; - border-radius: 50%; - border: 1px solid #ccc; - background-color: ${props => (props.disabled ? 'rgba(255,255,255,0.7)' : 'white')}; - color: black; - opacity: ${props => (props.disabled ? '0.5' : '1')}; - font-size: 32px; - cursor: ${props => (props.disabled ? 'not-allowed' : 'pointer')}; - display: flex; - align-items: center; - justify-content: center; - - @media (max-width: 640px) { - height: 42px; - width: 42px; - } -`; diff --git a/src/components/founder-sale/FounderBenefits.tsx b/src/components/founder-sale/FounderBenefits.tsx new file mode 100644 index 0000000..7b88e54 --- /dev/null +++ b/src/components/founder-sale/FounderBenefits.tsx @@ -0,0 +1,177 @@ +import styled from 'styled-components'; +import { useMediaQuery } from 'react-responsive'; +import { motion } from 'framer-motion'; + +import { colors, radius } from 'theme'; +import { transition, transformVariant } from 'constants/motionConfig'; +import { maxWidth640, maxWidth840 } from 'components/rwd/detectMobile'; +import { AnimatedText } from 'components/_common/AnimatedText'; +import { ReadMore } from 'components/ReadMore'; + +import cover1 from '../../assets/images/nft-modal/cover-1.png'; +import cover1mobile from '../../assets/images/nft-modal/cover-1-mobile.png'; +import cover2 from '../../assets/images/nft-modal/cover-2.png'; +import cover2mobile from '../../assets/images/nft-modal/cover-2-mobile.png'; +import cover3 from '../../assets/images/nft-modal/cover-3.png'; +import cover3mobile from '../../assets/images/nft-modal/cover-3-mobile.png'; +import cover4 from '../../assets/images/nft-modal/cover-4.png'; +import cover4mobile from '../../assets/images/nft-modal/cover-4-mobile.png'; +import cover5 from '../../assets/images/nft-modal/cover-5.png'; +import cover5mobile from '../../assets/images/nft-modal/cover-5-mobile.png'; + +interface BenefitStep { + title: string; + description: string; + src: string; +} + +const MAX_DESCRIPTION_LENGTH = 150; + +const steps = (isMobile: boolean): BenefitStep[] => ([ + { + title: 'Benefits of the Fida Founders NFT Collection', + description: 'The Fida Founders NFT Collection offers a range of exclusive benefits that set it apart from other NFT collections. This collection is not just about digital art, or the historic introduction of global decentralized insurance, but a utility token within the Fida ecosystem. Here are the benefits we\'re currently planning for the token', + src: isMobile ? cover1mobile : cover1 + }, + { + title: 'Early Access to the Fida System', + description: 'As a holder of the Fida Founders NFT, you will be invited to the private testnet. This early access allows you to familiarize yourself with the platform, navigate its features, and most importantly influence its development through feature requests and user experience suggestions.', + src: isMobile ? cover2mobile : cover2 + }, + { + title: 'First Choice of Policies', + description: 'As an investor possessing a Fida Founders NFT will grant you access to an initial early commitment round to each policy brought onboard. This priority access means you can optimize your portfolio, with the risk profile and diversification that best suits your investment strategy. Early selection can be crucial in ensuring your proportion of the most desirable policies, especially those that might be limited in availability or have particularly favorable conditions.', + src: isMobile ? cover3mobile : cover3 + }, + { + title: 'Priority Listings', + description: 'As an insurer or broker holding a Fida Founders NFT your policies will be highlighted as founder\'s policy. In a competitive environment where other brokers are competing for investment a founding member\'s tag can significantly impact outcomes, raising the odds of getting your policy filled and offering a substantial edge.', + src: isMobile ? cover4mobile : cover4 + }, + { + title: 'Fee Discounts', + description: 'One of the certain advantages of the Fida Founders NFT is the entitlement to fee discounts. Listing fees, trading fees, and other charges within the Fida ecosystem will be discounted to holders of the Fida Founders Collection. As an NFT holder, you benefit from reduced fees, allowing you to trade effectively, and potentially increase your net gains. This financial incentive is designed to reward early supporters and encourage continued engagement with the platform.', + src: isMobile ? cover5mobile : cover5 + }, +]); + +export const FounderBenefits = () => { + const isMobile = useMediaQuery({ query: maxWidth640 }); + const isTablet = useMediaQuery({ query: maxWidth840 }); + + return ( + + {steps(isMobile).map((step, index) => { + const isReversed = index % 2 !== 0; + return ( + + + + + + {step.description.length >= MAX_DESCRIPTION_LENGTH && isTablet ? ( + + ) : ( + + )} + + + + ); + })} + + ); +}; + +const BenefitsSection = styled.div` + display: flex; + flex-direction: column; + gap: 16px; + width: 100%; + + @media (min-width: 1024px) { + gap: 0px; + } +`; + +const BenefitCard = styled.div` + background-color: ${colors.mainBlack}; + border-radius: ${radius['4xl']}; + + @media (min-width: 1024px) { + margin: 80px 0px; + } +`; + +const Card = styled.div<{ isReversed: boolean }>` + align-items: center; + background: ${colors.greyBackgroundGradient}; + border-radius: ${radius['4xl']}; + display: flex; + flex-direction: column; + padding: 16px; + position: relative; + + @media (min-width: 1024px) { + display: grid; + grid-template-columns: ${({ isReversed }) => (isReversed ? '60% 40%' : '40% 60%')}; + justify-content: space-between; + padding: 0px 32px; + } + + @media (min-width: 1440px) { + grid-template-columns: ${({ isReversed }) => (isReversed ? '60% 30%' : '30% 60%')}; + } +`; + +const BenefitImage = styled(motion.img)<{ isReversed: boolean }>` + width: 100%; + border-radius: ${radius['4xl']}; + + @media (min-width: 1024px) { + margin: ${({ isReversed }) => (isReversed ? '0px' : '24px 0px')}; + order: ${({ isReversed }) => (isReversed ? 1 : 0)}; + } +`; + +const BenefitContent = styled(motion.div)` + display: flex; + flex-direction: column; + gap: 16px; + justify-content: center; + margin-bottom: 32px; + margin-top: 14px; + + @media (min-width: 1024px) { + margin-left: 24px; + gap: 40px; + padding: 100px 0px; + } +`; diff --git a/src/components/founder-sale/NFTButton.tsx b/src/components/founder-sale/NFTButton.tsx deleted file mode 100644 index a7905cd..0000000 --- a/src/components/founder-sale/NFTButton.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { motion } from 'framer-motion'; -import styled from 'styled-components'; - -import { colors } from 'theme'; -import { transition, transformVariant } from 'constants/motionConfig'; - -interface Props { - value: number; -} - -export const NFTButton = ({ value }: Props) => ( - openPaymentWindow(value)} - > - {`Mint ${value} Fida Founder’s NFT${plural(value)} (${countAda(value)} ADA)`} - -); - -const GradientButton = styled(motion.button)` - margin-bottom: 40px; - border: 1px solid ${colors.blue}; - background: ${colors.backgroundGradient}; - color: white; - font-size: 18px; - font-weight: 700; - padding: 10px 20px; - cursor: pointer; - border-radius: 24px; - outline: none; - height: 60px; - width: 365px; - transition: 0.5s; - - &:hover { - opacity: 0.8; - } - - &:focus { - outline: none; - } - - &:active { - opacity: 0.8; - } - - @media (max-width: 840px) { - width: 90%; - font-size: 16px; - } -`; - -const plural = (count: number) => ((1 * count) === 1 ? '' : 's'); - -const countAda = (count: number) => (count * 300) - ((count - 1) * 30); - -const openPaymentWindow = (value: number) => { - const paymentUrl = `https://pay.nmkr.io/?p=1fe458e78a46451fb812b36ab3fa6f82&c=${value}`; - - const popupWidth = 500; - const popupHeight = 700; - - const wtop = window.top ?? { outerWidth: 400, outerHeight: 400, screenX: 800, screenY: 800 }; - const left = wtop.outerWidth / 2 + wtop.screenX - (popupWidth / 2); - const top = wtop.outerHeight / 2 + wtop.screenY - (popupHeight / 2); - - const popup = window.open(paymentUrl, 'NFT-MAKER PRO Payment Gateway', `popup=1, location=1, width=${popupWidth}, height=${popupHeight}, left=${left}, top=${top}`); - - document.body.style.cssText = 'background: rgba(0, 0, 0, 0.5)'; - - const backgroundCheck = setInterval(() => { - if (popup?.closed) { - clearInterval(backgroundCheck); - // eslint-disable-next-line no-console - console.log('Popup closed'); - - document.body.style.cssText = ''; - } - }, 1000); -}; diff --git a/src/components/founder-sale/modal/FounderModal.tsx b/src/components/founder-sale/modal/FounderModal.tsx deleted file mode 100644 index f8df626..0000000 --- a/src/components/founder-sale/modal/FounderModal.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import Backdrop from '@mui/material/Backdrop'; -import Modal from '@mui/material/Modal'; -import Fade from '@mui/material/Fade'; -import styled from 'styled-components'; -import { FounderModalContent } from './FounderModalContent'; - -interface Props { - isOpen: boolean; - handleClose: () => void; -} - -export const FounderModal = ({ isOpen, handleClose }: Props) => ( -
- { if (reason !== 'backdropClick') handleClose(); }} - closeAfterTransition - sx={{ - '.MuiBackdrop-root': { - backdropFilter: 'blur(4px)' - } - }} - slots={{ backdrop: Backdrop }} - slotProps={{ - backdrop: { - timeout: 500, - }, - }} - > - - - - X - - - -
-); - -const Container = styled.div` - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - max-width: 861px; - height: 70%; - min-height: 690px; - overflow: auto; - background-color: white; - border: 1px solid #000; - box-shadow: 24; - padding: 16px; - outline: none; - border-radius: 24px; - - @media (max-width: 1900px) and (max-height: 1037px) { - height: 90%; - } - - @media (min-height: 1037px) { - height: 70%; - } - - @media (min-height: 1400px) { - height: 40%; - } - - @media (max-width: 860px) { - max-width: 100%; - } - `; - -const CloseButton = styled.button` - position: absolute; - top: 30px; - right: 30px; - display: flex; - justify-content: center; - align-items: center; - width: 56px; - height: 56px; - border-radius: 100%; - border: none; - outline: none; - background-color: rgba(255,255,255,0.2); - color: white; - font-size: 18px; - z-index: 10; - cursor: pointer; - backdrop-filter: blur(8px); - - @media (max-width: 860px) { - width: 40px; - height: 40px; - } -`; diff --git a/src/components/founder-sale/modal/FounderModalContent.tsx b/src/components/founder-sale/modal/FounderModalContent.tsx deleted file mode 100644 index 8ce1fe1..0000000 --- a/src/components/founder-sale/modal/FounderModalContent.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import { Swiper, SwiperSlide } from 'swiper/react'; -import { useEffect, useState } from 'react'; - -import 'swiper/css'; -import 'swiper/css/pagination'; - -import './styles.css'; - -import { Pagination, Navigation } from 'swiper/modules'; -import styled from 'styled-components'; -import { Swiper as SwiperCore } from 'swiper/types'; - -import { useMediaQuery } from 'react-responsive'; -import { maxWidth640 } from 'components/rwd/detectMobile'; - -import cover1 from '../../../assets/images/nft-modal/cover-1.png'; -import cover1mobile from '../../../assets/images/nft-modal/cover-1-mobile.png'; -import cover2 from '../../../assets/images/nft-modal/cover-2.png'; -import cover2mobile from '../../../assets/images/nft-modal/cover-2-mobile.png'; -import cover3 from '../../../assets/images/nft-modal/cover-3.png'; -import cover3mobile from '../../../assets/images/nft-modal/cover-3-mobile.png'; -import cover4 from '../../../assets/images/nft-modal/cover-4.png'; -import cover4mobile from '../../../assets/images/nft-modal/cover-4-mobile.png'; -import cover5 from '../../../assets/images/nft-modal/cover-5.png'; -import cover5mobile from '../../../assets/images/nft-modal/cover-5-mobile.png'; - -interface Steps { - title: string; - description: string; - src: string; -} - -const steps = (isMobile: boolean): Steps[] => ([ - { - title: 'Benefits of the Fida Founders NFT Collection', - description: 'The Fida Founders NFT Collection offers a range of exclusive benefits that set it apart from other NFT collections. This collection is not just about digital art, or the historic introduction of global decentralized insurance, but a utility token within the Fida ecosystem. Here are the benefits we\'re currently planning for the token', - src: isMobile ? cover1mobile : cover1 - }, - { - title: 'Early Access to the Fida System', - description: 'As a holder of the Fida Founders NFT, you will be invited to the private testnet. This early access allows you to familiarize yourself with the platform, navigate its features, and most importantly influence its development through feature requests and user experience suggestions.', - src: isMobile ? cover2mobile : cover2 - }, - { - title: 'First Choice of Policies', - description: 'As an investor possessing a Fida Founders NFT will grant you access to an initial early commitment round to each policy brought onboard. This priority access means you can optimize your portfolio, with the risk profile and diversification that best suits your investment strategy. Early selection can be crucial in ensuring your proportion of the most desirable policies, especially those that might be limited in availability or have particularly favorable conditions.', - src: isMobile ? cover3mobile : cover3 - }, - { - title: 'Priority Listings', - description: 'As an insurer or broker holding a Fida Founders NFT your policies will be highlighted as founder\'s policy. In a competitive environment where other brokers are competing for investment a founding member\'s tag can significantly impact outcomes, raising the odds of getting your policy filled and offering a substantial edge.', - src: isMobile ? cover4mobile : cover4 - }, - { - title: 'Fee Discounts', - description: 'One of the certain advantages of the Fida Founders NFT is the entitlement to fee discounts. Listing fees, trading fees, and other charges within the Fida ecosystem will be discounted to holders of the Fida Founders Collection. As an NFT holder, you benefit from reduced fees, allowing you to trade effectively, and potentially increase your net gains. This financial incentive is designed to reward early supporters and encourage continued engagement with the platform.', - src: isMobile ? cover5mobile : cover5 - }, -]); - -export const FounderModalContent = () => { - const isMobile = useMediaQuery({ - query: maxWidth640, - }); - - const [activeIndex, setActiveIndex] = useState(0); - const [swiperInstance, setSwiperInstance] = useState(null); // Swiper instance state - - useEffect(() => { - const bullets = document.querySelectorAll('.swiper-pagination-bullet'); - bullets.forEach((bullet, index) => { - if (index < activeIndex) { - bullet.classList.add('swiper-pagination-bullet-past'); - } else { - bullet.classList.remove('swiper-pagination-bullet-past'); - } - }); - }, [activeIndex]); - - const pagination = { - clickable: true, - renderBullet(index: number, className: string) { - const bulletClass = index < activeIndex ? 'swiper-pagination-bullet-past' : ''; - return `${index + 1}`; - }, - }; - - const handleNextSlide = () => { - if (swiperInstance && activeIndex < steps(isMobile).length - 1) { - swiperInstance.slideNext(); - } else if (swiperInstance && activeIndex === steps(isMobile).length - 1) { - swiperInstance.slideTo(0); - } - }; - - return ( - setActiveIndex(swiper.activeIndex)} - onSwiper={setSwiperInstance} // Store the Swiper instance - > - {steps(isMobile).map(step => ( - - - {step.title} - - {step.title} - {step.description} - - - {`Learn more (${activeIndex + 1}/${steps(isMobile).length}) →`} - - - - ))} - - ); -}; - -const SliderContainer = styled.div` - display: flex; - flex-direction: column; - gap: 24px; -`; - -const TextContainer = styled.div` - display: flex; - flex-direction: column; - gap: 24px; -`; - -const SliderTitle = styled.p` - font-weight: 700; - font-size: 36px; - line-height: 44px; - color: black; - - @media (max-width: 640px) { - font-size: 24px; - line-height: 32px; - } -`; - -const SliderDescription = styled.p` - font-weight: 500; - font-size: 18px; - line-height: 28px; - color: black; - text-align: center; - padding: 0 68px; - - @media (max-width: 815px) { - font-size: 16px; - line-height: 24px; - padding: 0 24px; - }; - - @media (max-width: 640px) { - font-size: 14px; - line-height: 20px; - padding: 0 0; - }; - - @media (max-width: 375px) { - font-size: 12px; - line-height: 18px; - } -`; - -const LearnButton = styled.button` - position: absolute; - bottom: 52px; - left: 50%; - transform: translateX(-50%); - border: none; - outline: none; - background: none; - cursor: pointer; - font-weight: 500; - font-size: 18px; - line-height: 28px; - color: gray; - text-align: center; - - @media (max-width: 375px) { - font-size: 12px; - line-height: 18px; - bottom: 38px; - }; - - @media (max-width: 830px) { - font-size: 14px; - line-height: 20px; - bottom: 42px; - } -`; diff --git a/src/components/founder-sale/modal/styles.css b/src/components/founder-sale/modal/styles.css deleted file mode 100644 index c65c8d4..0000000 --- a/src/components/founder-sale/modal/styles.css +++ /dev/null @@ -1,132 +0,0 @@ -.modal-swiper.swiper { - width: 100%; - height: 100%; - border: none; - outline: none; - } - - .modal-swiper .swiper-slide { - text-align: center; - font-size: 18px; - background: #fff; - border: none; - outline: none; - - /* Center slide text vertically */ - display: flex; - justify-content: center; - align-items: start; - } - - .modal-swiper .swiper-slide img { - display: block; - width: 100%; - max-width: 829px; - height: 324px; - object-fit: cover; - border-radius: 24px; - } - - .modal-swiper .swiper-pagination-bullet { - width: 64px; - height: 16px; - text-align: center; - color: transparent; - opacity: 1; - border-radius: 99px; - background: #E6E6E6; - } - - .modal-swiper .swiper-pagination-bullet-active { - color: transparent; - background: #D33681; - } - - .modal-swiper .swiper-pagination-bullet-past { - color: transparent; - background: #D33681; - opacity: 0.3; - } - - .modal-swiper .swiper-button-next, .modal-swiper .swiper-button-prev { - border-radius: 100%; - background-color: transparent; - border: 1px solid rgba(0, 0, 0, 0.2); - color: #323232; - width: 42px; - height: 42px; - top: auto; - bottom: 0; - z-index: 30; - } - - .modal-swiper .swiper-button-next { - right: 22%; - } - - .modal-swiper .swiper-button-prev { - left: 22%; - } - - .modal-swiper .swiper-button-next::after, .modal-swiper .swiper-button-prev::after { - scale: 0.4; - } - - .modal-swiper .swiper-button-disabled { - visibility: hidden; - } - - @media (max-width: 830px) { - .modal-swiper .swiper-button-next { - right: 14%; - } - - .modal-swiper .swiper-button-prev { - left: 14%; - } -} - - @media (max-width: 640px) { - .modal-swiper .swiper-pagination-bullet { - width: 16px; - height: 16px; - } - - .modal-swiper .swiper-button-next, .modal-swiper .swiper-button-prev { - width: 26px; - height: 26px; - bottom: 8px; - } - - .modal-swiper .swiper-button-next::after, .modal-swiper .swiper-button-prev::after { - scale: 0.2; - } - - .modal-swiper .swiper-button-next { - right: 32%; - } - - .modal-swiper .swiper-button-prev { - left: 32%; - } -} - -@media (max-width: 560px) { - .modal-swiper .swiper-button-next { - right: 28%; - } - - .modal-swiper .swiper-button-prev { - left: 28%; - } -} - -@media (max-width: 450px) { - .modal-swiper .swiper-button-next { - right: 22%; - } - - .modal-swiper .swiper-button-prev { - left: 22%; - } -} diff --git a/src/components/rwd/FoundersHeaderMenuMobile.tsx b/src/components/rwd/FoundersHeaderMenuMobile.tsx index b330ff6..43a1ca3 100644 --- a/src/components/rwd/FoundersHeaderMenuMobile.tsx +++ b/src/components/rwd/FoundersHeaderMenuMobile.tsx @@ -12,11 +12,11 @@ import { useNavigate } from 'react-router-dom'; interface Props { modalToggle: boolean; setModalToggle: React.Dispatch>; - handleOpenLearnMoreModal: () => void + handleLearnMore: () => void; } export const FoundersHeaderMenuMobile = (props: Props) => { - const { modalToggle, setModalToggle, handleOpenLearnMoreModal } = props; + const { modalToggle, setModalToggle, handleLearnMore } = props; const navigate = useNavigate(); return ( @@ -38,7 +38,7 @@ export const FoundersHeaderMenuMobile = (props: Props) => { toUpperCase textPlacing="center" color={colors.buttonTertiaryColorFg} - onClick={handleOpenLearnMoreModal} + onClick={handleLearnMore} /> navigate('/')}> Discover FIDA diff --git a/src/components/rwd/MobileHeaderFounders.tsx b/src/components/rwd/MobileHeaderFounders.tsx index 42b13ba..963cc80 100644 --- a/src/components/rwd/MobileHeaderFounders.tsx +++ b/src/components/rwd/MobileHeaderFounders.tsx @@ -7,10 +7,10 @@ import menuMobileClose from 'assets/icons/menuMobileClose.svg'; import { FoundersHeaderMenuMobile } from './FoundersHeaderMenuMobile'; interface Props { - handleOpenLearnMoreModal: () => void; + handleLearnMore: () => void; } -export const MobileHeaderFounders = ({ handleOpenLearnMoreModal }: Props) => { +export const MobileHeaderFounders = ({ handleLearnMore }: Props) => { const [modalToggle, setModalToggle] = useState(false); return ( @@ -21,7 +21,7 @@ export const MobileHeaderFounders = ({ handleOpenLearnMoreModal }: Props) => { alt="open menu" loading="lazy" /> - + ); }; diff --git a/src/data/texts.ts b/src/data/texts.ts index e246e06..39cf305 100644 --- a/src/data/texts.ts +++ b/src/data/texts.ts @@ -20,11 +20,11 @@ const welcomeHeroCard = { }; const founderWelcomeHeroCard = { - description: 'Mint a Founder\'s NFT to gain early adopter\'s access to the decentralized insurance marketplace.', - title: 'Fida Founder\'s NFT Collection Mint', + description: 'Explore the Founder\'s NFT collection for early adopter\'s access to the decentralized insurance marketplace.', + title: 'Fida Founder\'s NFT Collection', button: { - label: 'Mint Now!', - link: 'founder-sale', + label: 'Learn More', + link: 'founders-card', } }; diff --git a/src/pages/FounderCards.tsx b/src/pages/FounderCards.tsx new file mode 100644 index 0000000..163d001 --- /dev/null +++ b/src/pages/FounderCards.tsx @@ -0,0 +1,95 @@ +import { lazy, Suspense } from 'react'; +import styled from 'styled-components'; +import { colors } from 'theme'; + +import { useMediaQuery } from 'react-responsive'; +import { Skeleton } from '@mui/material'; +import Footer from '../components/sections/Footer'; +import { Text } from '../components/_common/Text'; +import { Container } from '../components/_common/Container'; + +import backgroundImage from '../assets/images/background-pattern.png'; +import { NFTSlider } from '../components/founder-sale/NFTSlider'; +import { maxWidth840 } from '../components/rwd/detectMobile'; +import { HeaderFounders } from '../components/HeaderFounders'; +import { FounderBenefits } from '../components/founder-sale/FounderBenefits'; + +const NFTDetails = lazy(() => import('../components/founder-sale/NFTDetails')); + +const FounderCards = () => { + const isTablet = useMediaQuery({ + query: maxWidth840, + }); + + const handleScrollToBenefits = () => { + document.getElementById('benefits')?.scrollIntoView({ behavior: 'smooth' }); + }; + + return ( + + + + + {'Fida Founder\'s NFT Collection'.toUpperCase()} + + + + + }> + + + +