diff --git a/docusaurus.config.ts b/docusaurus.config.ts index dd9e2a7..9896d9f 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -69,34 +69,6 @@ export default async function createConfigAsync() { es: '/es/', pt: '/pt/' }, - legal: { - fr: '/legal', - en: '/en/legal', - de: '/de/legal', - es: '/es/legal', - pt: '/pt/legal' - }, - terms: { - fr: '/terms', - en: '/en/terms', - de: '/de/terms', - es: '/es/terms', - pt: '/pt/terms' - }, - privacy: { - fr: '/privacy', - en: '/en/privacy', - de: '/de/privacy', - es: '/es/privacy', - pt: '/pt/privacy' - }, - cookies: { - fr: '/cookies', - en: '/en/cookies', - de: '/de/cookies', - es: '/es/cookies', - pt: '/pt/cookies' - }, geranium: { fr: 'https://i.dfr.gg/geranium.webm', en: 'https://i.dfr.gg/en-geranium.webm', @@ -356,7 +328,7 @@ export default async function createConfigAsync() { }, { label: 'Documentation', - to: '/', + to: '/docs', target: '_self' }, { @@ -376,22 +348,22 @@ export default async function createConfigAsync() { items: [ { label: 'Mentions légales', - to: 'legal', + to: '/legal', target: '_self' }, { label: 'Conditions d\'utilisation', - to: 'terms', + to: '/terms', target: '_self' }, { label: 'Politique de confidentialité', - to: 'privacy', + to: '/privacy', target: '_self' }, { label: 'Politique des cookies', - to: 'cookies', + to: '/cookies', target: '_self' } ], diff --git a/src/components/landing/Hero/index.tsx b/src/components/landing/Hero/index.tsx new file mode 100644 index 0000000..912654b --- /dev/null +++ b/src/components/landing/Hero/index.tsx @@ -0,0 +1,58 @@ +import React, {type ReactNode} from 'react'; +import clsx from 'clsx'; +import shared from '../styles/shared.module.css'; +import styles from './styles.module.css'; + +type HeroProps = { + /** Nombre brut de serveurs, arrondi à la dizaine de milliers inférieure + * (pallier 50 000) pour produire un chiffre stable façon checkpoint. */ + serverCount?: number; +}; + +const PRE_TITLE_FALLBACK = 350_000; +const PRE_TITLE_STEP = 50_000; + +function roundedServerCount(raw: number | undefined): number { + if (raw == null || !Number.isFinite(raw)) return PRE_TITLE_FALLBACK; + return Math.floor(raw / PRE_TITLE_STEP) * PRE_TITLE_STEP; +} + +export default function Hero({serverCount}: HeroProps): ReactNode { + const formatted = roundedServerCount(serverCount).toLocaleString('fr-FR'); + return ( +
+
+
+
+
+ Utilisé par plus de {formatted} serveurs +
+
+

+ Le meilleur bot Discord de{' '} + sécurité +

+

+ Empêchez les utilisateurs malintentionnés de nuire à votre serveur + Discord. +

+
+ + Ajouter à Discord + + + Voir les fonctionnalités + +
+
+
+
+ ); +} diff --git a/src/components/landing/Hero/styles.module.css b/src/components/landing/Hero/styles.module.css new file mode 100644 index 0000000..3015b24 --- /dev/null +++ b/src/components/landing/Hero/styles.module.css @@ -0,0 +1,85 @@ +.section { + padding-top: 90px; + padding-bottom: 150px; + position: relative; + overflow-x: clip; +} + +.content { + z-index: 2; + text-align: center; + display: flex; + flex-flow: column; + justify-content: space-between; + align-items: center; + position: relative; +} + +.preTitleWrap { + border-radius: 50px; + background-color: #1b1a25; + background-image: linear-gradient(180deg, #d35f5f 40%, #a561a3); + margin-bottom: 20px; + padding: 1px; + display: inline-block; + overflow: hidden; +} + +.preTitleText { + border-radius: 50px; + background-color: #1b1a25; + padding: 7px 14px 5px; + font-size: 16px; + font-weight: 400; + line-height: 1.5em; + color: #fff; + text-align: center; +} + +.title { + margin: 0 0 10px 0; + font-family: var(--ifm-heading-font-family); + color: #fff; + font-size: 68px; + font-weight: 600; + line-height: 1.2em; +} + +.description { + width: 75%; + font-family: var(--ifm-font-family-base); + margin-top: 0; + margin-bottom: 50px; + color: #e1e0e9; + font-size: 18px; +} + +.buttonList { + display: flex; + flex-flow: wrap; + justify-content: center; + align-items: center; + column-gap: 30px; + row-gap: 15px; +} + +@media screen and (max-width: 991px) { + .section { + padding-top: 50px; + padding-bottom: 100px; + } + .description { + width: 100%; + margin-bottom: 30px; + } +} + +@media screen and (max-width: 767px) { + .section { + padding-top: 30px; + padding-bottom: 80px; + } + .title { + font-size: 48px; + } +} diff --git a/src/components/landing/Servers/index.tsx b/src/components/landing/Servers/index.tsx new file mode 100644 index 0000000..4d8090a --- /dev/null +++ b/src/components/landing/Servers/index.tsx @@ -0,0 +1,210 @@ +import React, {type ReactNode} from 'react'; +import clsx from 'clsx'; +import shared from '../styles/shared.module.css'; +import styles from './styles.module.css'; + +type Badge = 'verified' | 'partner' | null; + +type Server = { + name: string; + icon: string; + alt: string; + href: string; + members: string; + badge: Badge; +}; + +const SERVERS: Server[] = [ + { + name: 'Wankil Studio', + icon: '/img/landing/iconWankilStudio.webp', + alt: 'Wankil Studio Discord server icon', + href: 'https://discord.com/invite/wankilstudio', + members: '40 000 membres', + badge: 'verified', + }, + { + name: 'Rocket League France', + icon: '/img/landing/iconRocketLeagueFrance.webp', + alt: 'Rocket League France Discord server icon', + href: 'https://discord.com/invite/rlfr', + members: '196 500 membres', + badge: 'partner', + }, + { + name: 'Slash FR', + icon: '/img/landing/iconSlashFR.webp', + alt: 'Slash FR Discord server icon', + href: 'https://discord.com/invite/fr', + members: '48 500 membres', + badge: null, + }, + { + name: "ZetFar's Family", + icon: '/img/landing/iconZetFar.webp', + alt: 'ZetFar Discord server icon', + href: 'https://discord.com/invite/zetfar', + members: '135 000 membres', + badge: 'verified', + }, + { + name: 'Ligue 1 McDonald’s', + icon: '/img/landing/iconLigue1.webp', + alt: 'Ligue 1 Discord server icon', + href: 'https://discord.com/invite/ligue1', + members: '15 000 membres', + badge: 'verified', + }, + { + name: 'Jobless', + icon: '/img/landing/iconJobless.webp', + alt: 'Jobless Discord server icon', + href: 'https://discord.com/invite/jobless', + members: '56 500 membres', + badge: 'partner', + }, + { + name: 'Blox Fruits FR', + icon: '/img/landing/iconBloxFruitsFR.webp', + alt: 'Blox Fruits FR Discord server icon', + href: 'https://discord.com/invite/bloxfruitsfr', + members: '124 000 membres', + badge: null, + }, + { + name: 'CYRILmp4', + icon: '/img/landing/iconCyrilmp4.webp', + alt: 'CYRILmp4 Discord server icon', + href: 'https://discord.com/invite/cyrilmp4', + members: '22 500 membres', + badge: 'partner', + }, + { + name: 'Fortnite House', + icon: '/img/landing/iconFortniteHouse.webp', + alt: 'Fortnite House Discord server icon', + href: 'https://discord.com/invite/officiel', + members: '66 500 membres', + badge: 'partner', + }, + { + name: 'PUBG MOBILE FRANCE', + icon: '/img/landing/iconPUBGMobileFrance.webp', + alt: 'PUBG MOBILE FRANCE Discord server icon', + href: 'https://discord.com/invite/pubgmfr', + members: '18 000 membres', + badge: 'verified', + }, + { + name: 'NationGlory', + icon: '/img/landing/iconNationsGlory.webp', + alt: 'NationsGlory server icon', + href: 'https://discord.com/invite/nationsglory', + members: '51 000 membres', + badge: 'partner', + }, + { + name: 'MASTU', + icon: '/img/landing/iconMastu.webp', + alt: 'MASTU Discord server icon', + href: 'https://discord.com/invite/mastu', + members: '17 000 membres', + badge: 'partner', + }, + { + name: 'Clash Royale FR', + icon: '/img/landing/iconClashRoyaleFR.webp', + alt: 'Clash Royale FR Discord server icon', + href: 'https://discord.com/invite/clashfr', + members: '34 000 membres', + badge: 'partner', + }, + { + name: 'TEAM VITALITY', + icon: '/img/landing/iconTeamVitality.webp', + alt: 'TEAM VITALITY Discord server icon', + href: 'https://discord.com/invite/teamvitality', + members: '19 500 membres', + badge: null, + }, + { + name: 'Genshin Impact FR', + icon: '/img/landing/iconGenshinImpactFR.webp', + alt: 'Genshin Impact FR Discord server icon', + href: 'https://discord.com/invite/genshinimpactfr', + members: '55 000 membres', + badge: 'partner', + }, +]; + +function BadgeImg({badge}: {badge: Badge}) { + if (!badge) return null; + const src = + badge === 'verified' + ? '/img/landing/serverBadgeVerified.svg' + : '/img/landing/serverBadgePartner.svg'; + const alt = + badge === 'verified' + ? 'Discord server badge verified' + : 'Discord server badge partner'; + return ( + {alt} + ); +} + +function ServerCard({server}: {server: Server}) { + return ( + +
+ {server.alt} +
+
+
{server.name}
+ +
+
{server.members}
+
+
+
+ ); +} + +export default function Servers(): ReactNode { + return ( +
+
+

Nous protégeons les plus grands

+
+
+
+ {SERVERS.map((server) => ( + + ))} +
+ +
+
+
+
+ ); +} diff --git a/src/components/landing/Servers/styles.module.css b/src/components/landing/Servers/styles.module.css new file mode 100644 index 0000000..b3be400 --- /dev/null +++ b/src/components/landing/Servers/styles.module.css @@ -0,0 +1,145 @@ +.section { + z-index: 3; + position: relative; +} + +.title { + text-align: center; + margin: 0 0 20px 0; + color: #e1e0e9; + font-family: var(--ifm-font-family-base); + font-size: 18px; + font-weight: 400; +} + +.marqueeWrap { + position: relative; + width: 100%; + overflow: hidden; + display: flex; + align-items: center; + --marquee-fade-width: 80px; + -webkit-mask-image: linear-gradient( + 90deg, + transparent, + #000 var(--marquee-fade-width), + #000 calc(100% - var(--marquee-fade-width)), + transparent + ); + mask-image: linear-gradient( + 90deg, + transparent, + #000 var(--marquee-fade-width), + #000 calc(100% - var(--marquee-fade-width)), + transparent + ); +} + +.track { + display: flex; + flex: none; + align-items: center; + width: max-content; + color: #fff; + opacity: 0.85; + animation: marquee 60s linear infinite; +} + +.marqueeWrap:hover .track { + animation-play-state: paused; +} + +.group { + display: flex; + align-items: center; +} + +.server { + display: flex; + flex-flow: column; + align-items: flex-start; + justify-content: flex-start; + min-width: 275px; + margin-right: 30px; + padding: 30px; + border: 1px solid #444950; + border-radius: 0.8rem; + background-color: #242328; + color: #fff; + text-decoration: none; + transition: border-color 0.2s ease-in-out; +} + +.server:hover { + border-color: #d35f5f; + text-decoration: none; + color: #fff; +} + +.avatarInfo { + display: flex; + align-items: center; + column-gap: 15px; + row-gap: 15px; + font-size: 14px; + line-height: 1.5em; +} + +.avatar { + flex: none; + width: 50px; + height: 50px; + object-fit: cover; + border-radius: 50%; +} + +.infos { + display: flex; + flex-flow: column; + align-items: flex-start; + justify-content: center; + row-gap: 6px; +} + +.nameRow { + display: flex; + align-items: center; +} + +.name { + color: #fff; + font-size: 18px; + font-weight: 600; + font-family: var(--ifm-font-family-base); +} + +.badge { + margin-left: 10px; +} + +.memberCount { + color: #e1e0e9; + font-size: 14px; +} + +@keyframes marquee { + from { + transform: translate3d(0, 0, 0); + } + to { + transform: translate3d(-50%, 0, 0); + } +} + +@media (prefers-reduced-motion: reduce) { + .track { + animation: none; + } +} + +@media screen and (max-width: 767px) { + .server { + min-width: 240px; + padding: 20px; + } +} diff --git a/src/components/landing/styles/shared.module.css b/src/components/landing/styles/shared.module.css new file mode 100644 index 0000000..0a2a1cf --- /dev/null +++ b/src/components/landing/styles/shared.module.css @@ -0,0 +1,164 @@ +/* Shared landing-page tokens & utilities, mirroring the Webflow source */ + +.landing { + /* Colors from raidprotectbot.webflow.css */ + --color-black: #040114; + --color-gray-1: #070417; + --color-gray-2: #1b1a25; + --color-gray-3: #242328; + --color-gray-4: #e1e0e9; + --color-white: #ffffff; + --color-primary-1: #726cb3; + --color-primary-4: #a561a3; + --color-primary-rp: #d35f5f; + --color-darker-primary: #bd5454; + --color-border-doc: #444950; + --color-founder: #ffab22; + --color-enterprise: #5f6fd3; + + --radius-sm: 10px; + --radius-md: 20px; + --radius-lg: 50px; + --radius-doc: 0.8rem; + + --gradient-1: linear-gradient(180deg, var(--color-primary-rp) 40%, var(--color-primary-4)); + --gradient-feature-icon: linear-gradient( + 135deg, + var(--color-primary-1), + var(--color-primary-rp) 60%, + var(--color-primary-4) + ); + + color: var(--color-gray-4); + font-size: 18px; + line-height: 1.5em; + background-color: var(--color-black); +} + +.container { + max-width: 1360px; + margin-left: auto; + margin-right: auto; + padding-left: 30px; + padding-right: 30px; +} + +.sectionSpacing { + padding-top: 150px; + padding-bottom: 150px; +} + +.sectionSpacingTop { + padding-top: 150px; +} + +.sectionSpacingBottom { + padding-bottom: 150px; +} + +.textGradient { + background-image: var(--gradient-1); + -webkit-text-fill-color: transparent; + -webkit-background-clip: text; + background-clip: text; +} + +.btnPrimary { + display: inline-block; + border: 1px solid var(--color-darker-primary); + border-radius: var(--radius-lg); + background-color: var(--color-darker-primary); + color: #fff; + text-align: center; + padding: 20px 28px 18px; + font-size: 18px; + font-weight: 500; + line-height: 1.1em; + text-decoration: none; + transition: border-color 0.3s, background-color 0.3s, transform 0.3s, color 0.3s; +} + +.btnPrimary:hover { + text-decoration: none; + color: #fff; + border-color: var(--color-darker-primary); + background-color: var(--color-darker-primary); + transform: translate3d(0, -3px, 0.01px); +} + +.btnPrimaryFounder { + border-color: var(--color-founder); + background-color: var(--color-founder); + color: #fff; +} + +.btnPrimaryFounder:hover { + border-color: var(--color-founder); + background-color: var(--color-founder); +} + +.btnSecondary { + display: inline-block; + border: 1px solid var(--color-darker-primary); + border-radius: var(--radius-lg); + background-color: transparent; + color: var(--color-white); + text-align: center; + padding: 20px 28px 18px; + font-size: 18px; + line-height: 1.1em; + text-decoration: none; + transition: border-color 0.3s, transform 0.3s, background-color 0.3s, color 0.3s; +} + +.btnSecondary:hover { + text-decoration: none; + color: #fff; + border-color: var(--color-darker-primary); + background-color: var(--color-darker-primary); + transform: translate3d(0, -3px, 0.01px); +} + +.btnSecondaryEnterprise { + border-color: var(--color-enterprise); +} + +.btnSecondaryEnterprise:hover { + border-color: var(--color-enterprise); + background-color: var(--color-enterprise); +} + +@media screen and (max-width: 991px) { + .sectionSpacing { + padding-top: 100px; + padding-bottom: 100px; + } + .sectionSpacingTop { + padding-top: 100px; + } + .sectionSpacingBottom { + padding-bottom: 100px; + } +} + +@media screen and (max-width: 767px) { + .container { + padding-left: 20px; + padding-right: 20px; + } + .sectionSpacing { + padding-top: 80px; + padding-bottom: 80px; + } + .sectionSpacingTop { + padding-top: 80px; + } + .sectionSpacingBottom { + padding-bottom: 80px; + } + .btnPrimary, + .btnSecondary { + padding: 20px 26px 16px; + font-size: 16px; + } +} diff --git a/src/css/custom.css b/src/css/custom.css index 21f433d..9b3423f 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -4,6 +4,12 @@ * work well for content-centric websites. */ +@media (prefers-reduced-motion: no-preference) { + html { + scroll-behavior: smooth; + } +} + /* You can override the default Infima variables here. */ html[data-theme='dark'] { --ifm-background-color: #040114; diff --git a/src/pages/index.module.css b/src/pages/index.module.css new file mode 100644 index 0000000..bec9b26 --- /dev/null +++ b/src/pages/index.module.css @@ -0,0 +1,509 @@ +/* ===== About section ===== */ + +.aboutSection { + overflow-x: clip; +} + +.aboutTitleGrid { + display: grid; + grid-template-rows: auto; + grid-template-columns: 1.25fr 1fr; + grid-column-gap: 100px; + grid-row-gap: 100px; + margin-bottom: 30px; +} + +.aboutTitle { + font-family: var(--ifm-heading-font-family); + color: #fff; + font-size: 50px; + font-weight: 600; + line-height: 1.2em; + margin: 0; +} + +.counterGrid { + display: grid; + grid-template-rows: auto; + grid-template-columns: 1fr 1fr; + grid-column-gap: 100px; + grid-row-gap: 100px; + align-items: center; +} + +.imageWrap { + position: relative; +} + +.curve { + width: 100%; + height: auto; + display: block; +} + +.curveLine { + stroke-dasharray: 1400; + stroke-dashoffset: 1400; + animation: rpDraw 1.5s cubic-bezier(0.4, 0, 0.2, 1) forwards; +} + +@keyframes rpDraw { + to { + stroke-dashoffset: 0; + } +} + +.curvePulse { + transform-origin: 860px 28px; + animation: rpPulse 1.8s ease-out infinite; +} + +@keyframes rpPulse { + 0% { + transform: scale(1); + opacity: 0.9; + } + 70% { + transform: scale(2.8); + opacity: 0; + } + 100% { + transform: scale(2.8); + opacity: 0; + } +} + +@media (prefers-reduced-motion: reduce) { + .curveLine, + .curvePulse { + animation: none !important; + } + .curveLine { + stroke-dashoffset: 0; + } +} + +.stats { + display: grid; + grid-template-rows: auto auto; + grid-template-columns: 1fr 1fr; + grid-column-gap: 60px; + grid-row-gap: 60px; + align-items: start; +} + +.counterItem { + display: flex; + flex-flow: column; +} + +.counterTitle { + font-family: var(--ifm-heading-font-family); + margin-bottom: 0; + font-size: 44px; + font-weight: 600; + line-height: 1.3em; + color: #fff; +} + +.counterLabel { + color: #e1e0e9; + font-size: 18px; + margin-top: 4px; +} + +@media screen and (max-width: 991px) { + .aboutTitleGrid { + grid-template-columns: 1fr; + grid-column-gap: 10px; + grid-row-gap: 10px; + } + .counterGrid { + grid-template-columns: 1fr; + } + .stats { + grid-column-gap: 50px; + grid-row-gap: 50px; + } +} + +@media screen and (max-width: 767px) { + .aboutTitle { + font-size: 42px; + } + .counterTitle { + font-size: 30px; + } + .stats { + grid-column-gap: 30px; + grid-row-gap: 30px; + } +} + +/* ===== Features section ===== */ + +.featuresSection { + position: relative; +} + +.featuresTitleWrap { + z-index: 2; + position: relative; + margin: 0 auto 70px auto; + width: 50%; + text-align: center; + display: flex; + flex-flow: column; +} + +.featuresTitle { + margin: 0 0 10px 0; + font-family: var(--ifm-heading-font-family); + color: #fff; + font-size: 50px; + font-weight: 600; + line-height: 1.2em; +} + +.featuresSubtitle { + margin: 0; + color: #e1e0e9; + font-size: 18px; + font-weight: 400; +} + +.featuresGrid { + position: relative; + display: grid; + grid-template-rows: auto; + grid-template-columns: 1fr 1fr 1fr; + grid-column-gap: 50px; + grid-row-gap: 50px; +} + +.featuresDecoration { + background-image: linear-gradient(180deg, #d35f5f 40%, #a561a3); + opacity: 0.5; + filter: blur(140px); + width: 450px; + height: 100px; + margin: auto; + position: absolute; + inset: 0; + z-index: 0; + pointer-events: none; +} + +.featuresItem { + z-index: 2; + position: relative; + display: flex; + flex-flow: column; + align-items: center; + text-align: center; + text-decoration: none; + transition: transform 0.3s; + column-gap: 20px; + row-gap: 20px; + color: inherit; +} + +.featuresItem:hover { + transform: scale(1.04); + text-decoration: none; + color: inherit; +} + +.featuresIconWrap { + flex: none; + display: flex; + align-items: center; + justify-content: center; + width: 80px; + height: 80px; + padding: 1px; + border-radius: 50%; + background-image: linear-gradient( + 135deg, + #726cb3, + #d35f5f 60%, + #a561a3 + ); +} + +.featuresIconBg { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + border-radius: 50%; + background-color: #1b1a25; +} + +.featuresIcon { + width: 32px; + height: 32px; +} + +.featuresItemTitle { + margin: 0 0 10px 0; + font-family: var(--ifm-heading-font-family); + color: #fff; + font-size: 26px; + font-weight: 600; + line-height: 1.3em; +} + +.featuresItemDescription { + margin: 0; + color: #e1e0e9; + font-size: 18px; +} + +@media screen and (max-width: 1279px) { + .featuresGrid { + grid-column-gap: 50px; + grid-row-gap: 50px; + } +} + +@media screen and (min-width: 1280px) { + .featuresGrid { + grid-column-gap: 90px; + grid-row-gap: 100px; + } + .featuresTitleWrap { + width: 95%; + } +} + +@media screen and (max-width: 991px) { + .featuresTitleWrap { + width: 100%; + } + .featuresGrid { + grid-template-columns: 1fr 1fr; + } + .featuresIconWrap { + width: 70px; + height: 70px; + } +} + +@media screen and (max-width: 767px) { + .featuresTitle { + font-size: 42px; + } + .featuresItemTitle { + font-size: 22px; + } + .featuresGrid { + grid-column-gap: 30px; + } +} + +/* ===== Pricing section ===== */ + +.pricingSection { + overflow-x: clip; + padding-top: 150px; + padding-bottom: 150px; +} + +.pricingTitleWrap { + text-align: center; + width: 60%; + margin: 0 auto 40px auto; + position: relative; +} + +.pricingTitleInner { + z-index: 2; + position: relative; +} + +.pricingTitle { + margin: 0 0 10px 0; + font-family: var(--ifm-heading-font-family); + color: #fff; + font-size: 50px; + font-weight: 600; + line-height: 1.2em; +} + +.pricingDescription { + margin: 0 0 40px 0; + color: #e1e0e9; + font-size: 18px; +} + +.pricingDecoration { + background-image: linear-gradient(180deg, #d35f5f 40%, #a561a3); + filter: blur(110px); + width: 50%; + height: 90px; + margin: 179px auto auto auto; + position: absolute; + inset: 0; + z-index: 0; + pointer-events: none; +} + +.pricingGrid { + z-index: 2; + position: relative; + display: grid; + grid-template-rows: auto; + grid-template-columns: 1fr 1fr 1fr; + grid-column-gap: 30px; + grid-row-gap: 30px; + margin-bottom: 30px; +} + +.pricingItem { + display: flex; + flex-flow: column; + justify-content: flex-start; + align-items: flex-start; + border: 1px solid #242328; + border-radius: 20px; + background-color: #070417; + padding: 30px; +} + +.pricingItemCenter { + border-color: #d35f5f; + background-color: #1b1a25; +} + +.preTitle { + border: 1px solid #d35f5f; + border-radius: 50px; + background-color: #242328; + color: #fff; + text-align: center; + margin-bottom: 20px; + padding: 8px 20px; + font-size: 16px; + line-height: 1.3em; + font-family: var(--ifm-font-family-base); +} + +.preTitleFounder { + border-color: #ffab22; + background-color: #1b1a25; +} + +.preTitleEnterprise { + border-color: #5f6fd3; +} + +.priceWrap { + display: flex; + flex-flow: wrap; + justify-content: flex-start; + align-items: baseline; + width: 100%; + column-gap: 10px; + row-gap: 5px; + margin-bottom: 20px; +} + +.price { + margin: 0; + font-family: var(--ifm-heading-font-family); + color: #fff; + font-size: 30px; + font-weight: 600; + line-height: 1.2em; +} + +.priceCenter { + text-align: right; + background-image: linear-gradient(180deg, #d35f5f 40%, #a561a3); + -webkit-text-fill-color: transparent; + -webkit-background-clip: text; + background-clip: text; +} + +.itemTagline { + margin: 0; + color: #e1e0e9; + font-size: 18px; + line-height: 1.5em; +} + +.featureList { + display: flex; + flex-flow: column; + width: 100%; + margin-top: 50px; + margin-bottom: 50px; + column-gap: 15px; + row-gap: 15px; +} + +.featureItem { + display: flex; + align-items: flex-start; + justify-content: flex-start; + column-gap: 8px; + row-gap: 8px; + color: #e1e0e9; +} + +.featureIcon { + flex: none; + width: 18px; + height: 18px; + margin-top: 5px; +} + +.buttonList { + display: flex; + flex-flow: column; + align-items: stretch; + justify-content: flex-start; + width: 100%; + margin-top: auto; + text-align: center; + column-gap: 15px; + row-gap: 15px; +} + +@media screen and (max-width: 991px) { + .pricingSection { + padding-top: 100px; + padding-bottom: 100px; + } + .pricingTitleWrap { + width: 100%; + } + .pricingGrid { + grid-template-columns: 1fr 1fr; + } + .featureList { + margin-top: 30px; + margin-bottom: 30px; + } +} + +@media screen and (max-width: 767px) { + .pricingSection { + padding-top: 80px; + padding-bottom: 80px; + } + .pricingTitle { + font-size: 42px; + } + .pricingGrid { + grid-template-columns: 1fr; + grid-column-gap: 20px; + grid-row-gap: 20px; + margin-bottom: 20px; + } + .pricingItem { + padding: 20px; + } +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 64dc99a..69d2115 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -1,30 +1,433 @@ -import React, {type ReactNode} from 'react'; +import React, {type ReactNode, useEffect, useState} from 'react'; +import clsx from 'clsx'; import Layout from '@theme/Layout'; import Link from '@docusaurus/Link'; -import Translate, {translate} from '@docusaurus/Translate'; +import Hero from '@site/src/components/landing/Hero'; +import Servers from '@site/src/components/landing/Servers'; +import shared from '@site/src/components/landing/styles/shared.module.css'; +import styles from './index.module.css'; + +type Counts = { + servers: number; + users: number; + captcha: number; + antispam: number; +}; + +type FormattedValue = { + value: string; + unit: string; +}; + +function formatValue(value: number): FormattedValue { + if (value >= 1_000_000) { + return {value: (value / 1_000_000).toFixed(1), unit: 'M'}; + } + return {value: (value / 1_000).toFixed(1), unit: 'k'}; +} + +function StatCounter({ + rawValue, + label, + fallback, +}: { + rawValue?: number; + label: string; + fallback: string; +}) { + if (rawValue == null) { + return ( +
+
+ {fallback} +
+
{label}
+
+ ); + } + const formatted = formatValue(rawValue); + return ( +
+
+ {formatted.value} + {formatted.unit} +
+
{label}
+
+ ); +} + +const CHECK_ICON = '/img/landing/icon-02.svg'; + +function FeatureItem({children}: {children: ReactNode}) { + return ( +
+ +
{children}
+
+ ); +} + +type Feature = { + to: string; + icon: string; + iconAlt: string; + title: string; + description: string; +}; + +const FEATURES: Feature[] = [ + { + to: '/docs/features/anti-spam', + icon: '/img/landing/iconAntispamWhite.svg', + iconAlt: 'RaidProtect icon Antispam', + title: 'Protection anti-spam', + description: + 'Sanctionnez instantanément les tentatives de spam, sans aucune intervention de votre part.', + }, + { + to: '/docs/features/raid-mode', + icon: '/img/landing/iconAntiraidWhite.svg', + iconAlt: 'RaidProtect icon Antiraid', + title: 'Blocage des raids', + description: + "Vous craignez un raid ? Notre bot est capable de le détecter et de le bloquer avant même qu'il impacte votre serveur.", + }, + { + to: '/docs/features/captcha', + icon: '/img/landing/iconCaptchaWhite.svg', + iconAlt: 'RaidProtect icon Captcha', + title: 'Protection contre les robots', + description: + "Grâce au captcha, vos membres doivent prouver qu'ils sont humains. Dites adieu aux comptes automatisés.", + }, + { + to: '/docs/features/utilities', + icon: '/img/landing/iconReportWhite.svg', + iconAlt: 'RaidProtect icon Report', + title: 'Modération & administration', + description: + "Gérez votre serveur comme un pro avec nos diverses fonctionalités de modération et d'administration.", + }, + { + to: '/docs/features/tag-role', + icon: '/img/landing/iconTagWhite.svg', + iconAlt: 'RaidProtect icon Tag', + title: 'Rôle de Tag', + description: + 'Le Rôle de Tag permet d’attribuer automatiquement un rôle aux membres qui ajoutent le tag de votre serveur.', + }, + { + to: '/docs/features/dm-lock', + icon: '/img/landing/iconDmlockWhite.svg', + iconAlt: 'RaidProtect icon DM Lock', + title: 'Fermeture des MP', + description: + 'Un bouclier inédit contre le spam, le scam et les arnaques par message privé.', + }, +]; export default function Home(): ReactNode { + const [counts, setCounts] = useState(null); + + useEffect(() => { + let cancelled = false; + fetch('https://docs.raidprotect.bot/counts.json') + .then((res) => { + if (!res.ok) throw new Error('Erreur lors de la récupération des données'); + return res.json(); + }) + .then((data: Counts) => { + if (!cancelled) setCounts(data); + }) + .catch((err) => { + // Stats are best-effort; failure is non-blocking + // eslint-disable-next-line no-console + console.error('Erreur de mise à jour des statistiques :', err); + }); + return () => { + cancelled = true; + }; + }, []); + return ( -
-

- RaidProtect -

-

- - La nouvelle page d'accueil arrive bientôt. En attendant, retrouvez toute la documentation ci-dessous. - -

-
- - Accéder à la documentation - -
+ title="RaidProtect • Sécurisez votre serveur Discord" + description="RaidProtect est un bot Discord français ayant pour mission de protéger simplement votre serveur des utilisateurs malintentionnés."> +
+ + + + {/* About */} +
+
+
+

+ Nos résultats ont un{' '} + impact +

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
+
+
+
+ + {/* Features */} +
+
+
+

+ Nos fonctionnalités +

+

+ Découvrez ce qui fait de nous l'un des meilleurs bots pour protéger + votre serveur Discord des utilisateurs malintentionnés. +

+
+
+ +
+
+ + {/* Pricing */} +
+
+
+
+

+ Garder une longueur{' '} + d'avance +

+

+ Ajoutez RaidProtect et commencez à protéger votre serveur dès + aujourd'hui. +

+
+ +
+ {/* Basic */} +
+
Basic
+
+

Gratuit

+
+

+ La sécurité essentielle assurée pour toujours +

+
+ Protections anti-spam + Blocage automatique des raids + Filtrage des bots malveillants + Modération & administration + + Et bien plus encore... + +
+ +
+ + {/* Founder */} +
+
+ Founder +
+
+

Abonnement

+

+ 2,99 $ +

+
+

+ Offre de lancement réservée aux premiers abonnés +

+
+ Profil du bot personnalisable + Noms de sanctions custom + Accès avancé à l'Auth Manager + Accès étendu au Display Public + Accès à la Bêta publique + Rôle exclusif sur notre serveur +
+ +
+ + {/* Business */} +
+
+ Business +
+
+

Sur demande

+
+

+ Pour les projets aux exigences de sécurité élevées +

+
+ Les fonctionnalités Founder + Instance dédiée et isolée + Audit initial de votre serveur + Intégration avec vos outils + Fonctionnalités sur mesure + Suivi régulier avec un expert + Support prioritaire +
+ +
+
+
+
); diff --git a/static/img/landing/411d8a698dd15ddf.webp b/static/img/landing/411d8a698dd15ddf.webp new file mode 100644 index 0000000..db9fa67 Binary files /dev/null and b/static/img/landing/411d8a698dd15ddf.webp differ diff --git a/static/img/landing/RP-embed-p-1080.webp b/static/img/landing/RP-embed-p-1080.webp new file mode 100644 index 0000000..79efe3e Binary files /dev/null and b/static/img/landing/RP-embed-p-1080.webp differ diff --git a/static/img/landing/RP-embed-p-500.webp b/static/img/landing/RP-embed-p-500.webp new file mode 100644 index 0000000..e535087 Binary files /dev/null and b/static/img/landing/RP-embed-p-500.webp differ diff --git a/static/img/landing/RP-embed-p-800.webp b/static/img/landing/RP-embed-p-800.webp new file mode 100644 index 0000000..0b19aae Binary files /dev/null and b/static/img/landing/RP-embed-p-800.webp differ diff --git a/static/img/landing/RP-embed.webp b/static/img/landing/RP-embed.webp new file mode 100644 index 0000000..88c8559 Binary files /dev/null and b/static/img/landing/RP-embed.webp differ diff --git a/static/img/landing/favicon.png b/static/img/landing/favicon.png new file mode 100644 index 0000000..6ab3afd Binary files /dev/null and b/static/img/landing/favicon.png differ diff --git a/static/img/landing/icon-02.svg b/static/img/landing/icon-02.svg new file mode 100644 index 0000000..2746652 --- /dev/null +++ b/static/img/landing/icon-02.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/landing/icon-geranium.svg b/static/img/landing/icon-geranium.svg new file mode 100644 index 0000000..e1a5ad8 --- /dev/null +++ b/static/img/landing/icon-geranium.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/img/landing/iconAntiraidWhite.svg b/static/img/landing/iconAntiraidWhite.svg new file mode 100644 index 0000000..df1d271 --- /dev/null +++ b/static/img/landing/iconAntiraidWhite.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/landing/iconAntispamWhite.svg b/static/img/landing/iconAntispamWhite.svg new file mode 100644 index 0000000..4b3f4f4 --- /dev/null +++ b/static/img/landing/iconAntispamWhite.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/landing/iconArtofWar3.webp b/static/img/landing/iconArtofWar3.webp new file mode 100644 index 0000000..12bb9f7 Binary files /dev/null and b/static/img/landing/iconArtofWar3.webp differ diff --git a/static/img/landing/iconBloxFruitsFR.webp b/static/img/landing/iconBloxFruitsFR.webp new file mode 100644 index 0000000..55d3cec Binary files /dev/null and b/static/img/landing/iconBloxFruitsFR.webp differ diff --git a/static/img/landing/iconCaptchaWhite.svg b/static/img/landing/iconCaptchaWhite.svg new file mode 100644 index 0000000..2b52714 --- /dev/null +++ b/static/img/landing/iconCaptchaWhite.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/img/landing/iconChatzone.webp b/static/img/landing/iconChatzone.webp new file mode 100644 index 0000000..62d5fa5 Binary files /dev/null and b/static/img/landing/iconChatzone.webp differ diff --git a/static/img/landing/iconClashGG.webp b/static/img/landing/iconClashGG.webp new file mode 100644 index 0000000..c58a383 Binary files /dev/null and b/static/img/landing/iconClashGG.webp differ diff --git a/static/img/landing/iconClashRoyaleFR.webp b/static/img/landing/iconClashRoyaleFR.webp new file mode 100644 index 0000000..ade9f1e Binary files /dev/null and b/static/img/landing/iconClashRoyaleFR.webp differ diff --git a/static/img/landing/iconCyrilmp4.webp b/static/img/landing/iconCyrilmp4.webp new file mode 100644 index 0000000..a31c0c4 Binary files /dev/null and b/static/img/landing/iconCyrilmp4.webp differ diff --git a/static/img/landing/iconDiscord.svg b/static/img/landing/iconDiscord.svg new file mode 100644 index 0000000..8a937d5 --- /dev/null +++ b/static/img/landing/iconDiscord.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/landing/iconDistrict10.webp b/static/img/landing/iconDistrict10.webp new file mode 100644 index 0000000..d945426 Binary files /dev/null and b/static/img/landing/iconDistrict10.webp differ diff --git a/static/img/landing/iconDmlockWhite.svg b/static/img/landing/iconDmlockWhite.svg new file mode 100644 index 0000000..eaa8a8e --- /dev/null +++ b/static/img/landing/iconDmlockWhite.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/static/img/landing/iconEclipse.webp b/static/img/landing/iconEclipse.webp new file mode 100644 index 0000000..b5ced10 Binary files /dev/null and b/static/img/landing/iconEclipse.webp differ diff --git a/static/img/landing/iconFlexingSeal.webp b/static/img/landing/iconFlexingSeal.webp new file mode 100644 index 0000000..72aa067 Binary files /dev/null and b/static/img/landing/iconFlexingSeal.webp differ diff --git a/static/img/landing/iconFortniteHouse.webp b/static/img/landing/iconFortniteHouse.webp new file mode 100644 index 0000000..5f79842 Binary files /dev/null and b/static/img/landing/iconFortniteHouse.webp differ diff --git a/static/img/landing/iconGenshinImpactFR.webp b/static/img/landing/iconGenshinImpactFR.webp new file mode 100644 index 0000000..fdf60b9 Binary files /dev/null and b/static/img/landing/iconGenshinImpactFR.webp differ diff --git a/static/img/landing/iconGitHub.svg b/static/img/landing/iconGitHub.svg new file mode 100644 index 0000000..80ac1a0 --- /dev/null +++ b/static/img/landing/iconGitHub.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/static/img/landing/iconJobless.webp b/static/img/landing/iconJobless.webp new file mode 100644 index 0000000..b9b660d Binary files /dev/null and b/static/img/landing/iconJobless.webp differ diff --git a/static/img/landing/iconLigue1.webp b/static/img/landing/iconLigue1.webp new file mode 100644 index 0000000..3aeef05 Binary files /dev/null and b/static/img/landing/iconLigue1.webp differ diff --git a/static/img/landing/iconLinkedIn.svg b/static/img/landing/iconLinkedIn.svg new file mode 100644 index 0000000..d730c0b --- /dev/null +++ b/static/img/landing/iconLinkedIn.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/static/img/landing/iconMastu.webp b/static/img/landing/iconMastu.webp new file mode 100644 index 0000000..2152f05 Binary files /dev/null and b/static/img/landing/iconMastu.webp differ diff --git a/static/img/landing/iconMetaLock.webp b/static/img/landing/iconMetaLock.webp new file mode 100644 index 0000000..ab75bb5 Binary files /dev/null and b/static/img/landing/iconMetaLock.webp differ diff --git a/static/img/landing/iconNationsGlory.webp b/static/img/landing/iconNationsGlory.webp new file mode 100644 index 0000000..2cde6d0 Binary files /dev/null and b/static/img/landing/iconNationsGlory.webp differ diff --git a/static/img/landing/iconPUBGMobileFrance.webp b/static/img/landing/iconPUBGMobileFrance.webp new file mode 100644 index 0000000..832c71c Binary files /dev/null and b/static/img/landing/iconPUBGMobileFrance.webp differ diff --git a/static/img/landing/iconPUBGMobileUK.webp b/static/img/landing/iconPUBGMobileUK.webp new file mode 100644 index 0000000..7712f12 Binary files /dev/null and b/static/img/landing/iconPUBGMobileUK.webp differ diff --git a/static/img/landing/iconReportWhite.svg b/static/img/landing/iconReportWhite.svg new file mode 100644 index 0000000..825b4bc --- /dev/null +++ b/static/img/landing/iconReportWhite.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/landing/iconRocketBaguette.webp b/static/img/landing/iconRocketBaguette.webp new file mode 100644 index 0000000..56df15f Binary files /dev/null and b/static/img/landing/iconRocketBaguette.webp differ diff --git a/static/img/landing/iconRocketLeagueFrance.webp b/static/img/landing/iconRocketLeagueFrance.webp new file mode 100644 index 0000000..2d44604 Binary files /dev/null and b/static/img/landing/iconRocketLeagueFrance.webp differ diff --git a/static/img/landing/iconSlashFR.webp b/static/img/landing/iconSlashFR.webp new file mode 100644 index 0000000..88f56ac Binary files /dev/null and b/static/img/landing/iconSlashFR.webp differ diff --git a/static/img/landing/iconTagWhite.svg b/static/img/landing/iconTagWhite.svg new file mode 100644 index 0000000..44e1c07 --- /dev/null +++ b/static/img/landing/iconTagWhite.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/img/landing/iconTeamVitality.webp b/static/img/landing/iconTeamVitality.webp new file mode 100644 index 0000000..fc58127 Binary files /dev/null and b/static/img/landing/iconTeamVitality.webp differ diff --git a/static/img/landing/iconTheForge.webp b/static/img/landing/iconTheForge.webp new file mode 100644 index 0000000..4f0e196 Binary files /dev/null and b/static/img/landing/iconTheForge.webp differ diff --git a/static/img/landing/iconWankilStudio.webp b/static/img/landing/iconWankilStudio.webp new file mode 100644 index 0000000..59b21eb Binary files /dev/null and b/static/img/landing/iconWankilStudio.webp differ diff --git a/static/img/landing/iconWeWard.webp b/static/img/landing/iconWeWard.webp new file mode 100644 index 0000000..dd4c769 Binary files /dev/null and b/static/img/landing/iconWeWard.webp differ diff --git a/static/img/landing/iconX.svg b/static/img/landing/iconX.svg new file mode 100644 index 0000000..9acfb6b --- /dev/null +++ b/static/img/landing/iconX.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/landing/iconYouTube.svg b/static/img/landing/iconYouTube.svg new file mode 100644 index 0000000..fcf1429 --- /dev/null +++ b/static/img/landing/iconYouTube.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/landing/iconZetFar.webp b/static/img/landing/iconZetFar.webp new file mode 100644 index 0000000..81694ec Binary files /dev/null and b/static/img/landing/iconZetFar.webp differ diff --git a/static/img/landing/logoRaidProtect.svg b/static/img/landing/logoRaidProtect.svg new file mode 100644 index 0000000..174d47b --- /dev/null +++ b/static/img/landing/logoRaidProtect.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/static/img/landing/pattern-01.svg b/static/img/landing/pattern-01.svg new file mode 100644 index 0000000..75e229c --- /dev/null +++ b/static/img/landing/pattern-01.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/static/img/landing/serverBadgePartner.svg b/static/img/landing/serverBadgePartner.svg new file mode 100644 index 0000000..9960d7b --- /dev/null +++ b/static/img/landing/serverBadgePartner.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/static/img/landing/serverBadgeVerified.svg b/static/img/landing/serverBadgeVerified.svg new file mode 100644 index 0000000..f677182 --- /dev/null +++ b/static/img/landing/serverBadgeVerified.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/static/img/landing/webclip.png b/static/img/landing/webclip.png new file mode 100644 index 0000000..8eb16d3 Binary files /dev/null and b/static/img/landing/webclip.png differ