diff --git a/public/locales/en/components/existingtab.json b/public/locales/en/components/existingtab.json new file mode 100644 index 0000000..052818a --- /dev/null +++ b/public/locales/en/components/existingtab.json @@ -0,0 +1,5 @@ +{ + "company_name":"Company name", + "tier":"Gold-tier supporter", + "link_text":"Visit website" +} \ No newline at end of file diff --git a/public/locales/en/components/faq.json b/public/locales/en/components/faq.json new file mode 100644 index 0000000..c875992 --- /dev/null +++ b/public/locales/en/components/faq.json @@ -0,0 +1,24 @@ +{ + "heading": "Frequently asked", + "text_part_1": "Got questions? Hit us up", + "link_text": "on our Discord", + "text_part_2": "or check the most common ones below.", + "faqs": [ + { + "question": "What is the minimum monetary amount to start sponsoring you?", + "answer": "The bare minimum is one (1) USD per month. So with 12 dollars, you can contribute to this project for a whole year and get listed as a bronze-tier supporter." + }, + { + "question": "Why should our company sponsor your project?" + }, + { + "question": "Can I down- or upgrade sponsor tiers? How and when?" + }, + { + "question": "Do you have any kind of collaboration deals with educational orgs?" + }, + { + "question": "What if the project ends - will I be refunded somehow?" + } + ] +} \ No newline at end of file diff --git a/public/locales/en/components/monthlytab.json b/public/locales/en/components/monthlytab.json new file mode 100644 index 0000000..84492ab --- /dev/null +++ b/public/locales/en/components/monthlytab.json @@ -0,0 +1,41 @@ +{ + "buttonLabel": "Talk to us to get started", + "tiers": { + "bronze": { + "title": "Bronze", + "price": "Starting at $5 per month", + "description": "For individuals or small companies that wish contribute to our project.", + "checklist": [ + "Addition to our sponsors’ list", + "Discord badge" + ] + }, + "silver": { + "title": "Silver", + "price": "Starting at $20 per month", + "description": "Meant for small-to-medium sized companies.", + "checklist": [ + "Secondary level support via Discord", + "A second additional perk" + ] + }, + "gold": { + "title": "Gold", + "price": "Starting at $50 per month", + "description": "Meant for medium sized companies.", + "checklist": [ + "First level support via Discord", + "A second additional perk" + ] + }, + "platinum": { + "title": "Platinum", + "price": "Starting at $200 per month", + "description": "Meant for large companies that want this OSS project to shine.", + "checklist": [ + "Priority support via Discord", + "A second additional perk" + ] + } + } +} \ No newline at end of file diff --git a/public/locales/en/components/onetimetab.json b/public/locales/en/components/onetimetab.json new file mode 100644 index 0000000..6464103 --- /dev/null +++ b/public/locales/en/components/onetimetab.json @@ -0,0 +1,12 @@ +{ + "one_time": { + "title": "One-time sponsorship", + "description": "Want to support is with a singular support payment?", + "checklist": [ + "No monthly/yearly payments", + "Discord badge", + "Discord badge" + ] + }, + "buttonLabel": "Talk to us to get started" +} \ No newline at end of file diff --git a/public/locales/en/components/steps.json b/public/locales/en/components/steps.json new file mode 100644 index 0000000..e4f20e3 --- /dev/null +++ b/public/locales/en/components/steps.json @@ -0,0 +1,22 @@ +{ + "heading":"Steps to becoming a sponsor", + "description":"We prefer to talk directly with each of our potential sponsor as we hope that our core values align and that we are truly a fitting match.", + "steps":{ + "01":{ + "number":"01", + "step":"Send us a message on our Discord server", + "step_description":"We are active on our Discord and it’s the best way to stay in touch with us and follow our work.", + "link_text":"Join our Discord" + }, + "02":{ + "number":"02", + "step":"Apply as a sponsor by filling out a form", + "step_description":"If our preliminary chat goes well according to both you and us, we’ll give you a link to a form that you can fill out." + }, + "03":{ + "number":"03", + "step":"Wait for confirmation (and our huge thanks!)", + "step_description":"We will contact you via Discord or email and let you know if everything is in order for the sponsorship." + } + } +} \ No newline at end of file diff --git a/public/locales/en/pages/sponsors.json b/public/locales/en/pages/sponsors.json new file mode 100644 index 0000000..96be776 --- /dev/null +++ b/public/locales/en/pages/sponsors.json @@ -0,0 +1,11 @@ +{ + "sponsors":{ + "header":"Supported by awesome sponsors worldwide", + "description":"Our open source project is made possible with the support of awesome organizations and companies." + }, + "segments":{ + "monthly":"Monthly sponsorship", + "one_time":"One-time sponsorship", + "existing":"Existing sponsors" + } +} \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 5f04596..19c4f0f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,6 +16,7 @@ import LoginProcessPage from './pages/LoginProcess'; import OurTeamPage from './pages/OurTeam'; import PluginsPage from './pages/Plugins'; import PrivacyPolicy from './pages/PrivacyPolicy'; +import Sponsors from './pages/Sponsors'; import TermsOfService from './pages/TermsOfService'; import ThemesPage from './pages/Themes'; import UserProfilePage from './pages/UserProfile'; @@ -76,6 +77,7 @@ const App: React.FC = () => { { element: , path: '/plugins' }, { element: , path: '/privacy-policy' }, { element: , path: '/themes' }, + { element: , path: '/sponsors' }, { element: , path: '/our-team' }, { element: , path: '/terms-of-service' }, { diff --git a/src/assets/images/SponsorsPage/bronze_sponsor.jpg b/src/assets/images/SponsorsPage/bronze_sponsor.jpg new file mode 100644 index 0000000..4d66841 Binary files /dev/null and b/src/assets/images/SponsorsPage/bronze_sponsor.jpg differ diff --git a/src/assets/images/SponsorsPage/gold_sponsor.jpg b/src/assets/images/SponsorsPage/gold_sponsor.jpg new file mode 100644 index 0000000..0fb8f05 Binary files /dev/null and b/src/assets/images/SponsorsPage/gold_sponsor.jpg differ diff --git a/src/assets/images/SponsorsPage/one_time_sponsor.jpg b/src/assets/images/SponsorsPage/one_time_sponsor.jpg new file mode 100644 index 0000000..731121d Binary files /dev/null and b/src/assets/images/SponsorsPage/one_time_sponsor.jpg differ diff --git a/src/assets/images/SponsorsPage/platinum_sponsor.jpg b/src/assets/images/SponsorsPage/platinum_sponsor.jpg new file mode 100644 index 0000000..5708c9c Binary files /dev/null and b/src/assets/images/SponsorsPage/platinum_sponsor.jpg differ diff --git a/src/assets/images/SponsorsPage/silver_sponsor.jpg b/src/assets/images/SponsorsPage/silver_sponsor.jpg new file mode 100644 index 0000000..766b1fb Binary files /dev/null and b/src/assets/images/SponsorsPage/silver_sponsor.jpg differ diff --git a/src/components/Sponsors/ExistingTab.tsx b/src/components/Sponsors/ExistingTab.tsx new file mode 100644 index 0000000..87fb3b8 --- /dev/null +++ b/src/components/Sponsors/ExistingTab.tsx @@ -0,0 +1,51 @@ +import { Box, Grid, Grid2, Link, Typography } from '@mui/material'; +import { ArrowRight } from 'lucide-react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +const ExistingTab: React.FC = () => { + const { t } = useTranslation('components/existingtab'); + return ( + + + {Array.from({ length: 12 }).map(() => ( + + + + + + + + + + + {t('company_name')} + + + {t('tier')} + + + + + {t('link_text')} + + + + + + ))} + + + ); +}; + +export default ExistingTab; diff --git a/src/components/Sponsors/FAQ.tsx b/src/components/Sponsors/FAQ.tsx new file mode 100644 index 0000000..1de4e77 --- /dev/null +++ b/src/components/Sponsors/FAQ.tsx @@ -0,0 +1,52 @@ +import { Accordion, AccordionDetails, AccordionSummary, Box, Link, Typography } from '@mui/material'; +import { ChevronDown } from 'lucide-react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +type FAQ = { + question: string; + answer?: string; +}; +const FAQ: React.FC = () => { + const { t } = useTranslation('components/faq'); + const faqs = t('faqs', { returnObjects: true }) as FAQ[]; + return ( + + + {t('heading')} + + + {t('text_part_1')} {t('link_text')} {t('text_part_2')} + + + {faqs.map((faq) => ( + + }> + {faq.question} + + {faq.answer ? ( + + + The bare minimum is one (1) USD per month. So with 12 dollars, you can contribute to this project for + a whole year and get listed as a bronze-tier supporter. + + + ) : null} + + ))} + + + ); +}; + +export default FAQ; diff --git a/src/components/Sponsors/MonthlyTab.tsx b/src/components/Sponsors/MonthlyTab.tsx new file mode 100644 index 0000000..fd48cf6 --- /dev/null +++ b/src/components/Sponsors/MonthlyTab.tsx @@ -0,0 +1,130 @@ +import { + Box, + Button, + Card, + CardActions, + CardContent, + CardMedia, + Grid, + Grid2, + List, + ListItem, + ListItemIcon, + Typography, +} from '@mui/material'; +import { Check } from 'lucide-react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import bronzeSponsor from '../../assets/images/SponsorsPage/bronze_sponsor.jpg'; +import goldSponsor from '../../assets/images/SponsorsPage/gold_sponsor.jpg'; +import platinumSponsor from '../../assets/images/SponsorsPage/platinum_sponsor.jpg'; +import silverSponsor from '../../assets/images/SponsorsPage/silver_sponsor.jpg'; + +type TierItem = { + title: string; + price: string; + description: string; + checklist: string[]; +}; + +type MonthlyTabTranslation = { + [tier: string]: TierItem; +}; + +const MonthlyTab: React.FC = () => { + const { t } = useTranslation('components/monthlytab'); + + const monthlyTiers = t('tiers', { returnObjects: true }) as MonthlyTabTranslation; + + const getTierImage = (tier: string) => { + switch (tier) { + case 'bronze': + return bronzeSponsor; + case 'silver': + return silverSponsor; + case 'gold': + return goldSponsor; + case 'platinum': + return platinumSponsor; + default: + return bronzeSponsor; + } + }; + return ( + + + {Object.keys(monthlyTiers).map((tier) => ( + + + + + + {monthlyTiers[tier].title} + + + {monthlyTiers[tier].price} + + + {monthlyTiers[tier].description} + + + {monthlyTiers[tier].checklist.map((checkListItem, index) => ( + + + + + {checkListItem} + + ))} + + + + + + + + ))} + + + ); +}; + +export default MonthlyTab; diff --git a/src/components/Sponsors/OneTimeTab.tsx b/src/components/Sponsors/OneTimeTab.tsx new file mode 100644 index 0000000..11c4cb0 --- /dev/null +++ b/src/components/Sponsors/OneTimeTab.tsx @@ -0,0 +1,75 @@ +import { + Box, + Button, + Card, + CardActions, + CardContent, + CardMedia, + List, + ListItem, + ListItemIcon, + Typography, +} from '@mui/material'; +import { Check } from 'lucide-react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import oneTimeSponsor from '../../assets/images/SponsorsPage/one_time_sponsor.jpg'; + +const OneTimeTab: React.FC = () => { + const { t } = useTranslation('components/onetimetab'); + const checklist = t('one_time.checklist', { returnObjects: true }) as Array; + return ( + + + + + + {t('one_time.title')} + + + {t('one_time.description')} + + + {checklist.map((checkListItem, index) => ( + + + + + {checkListItem} + + ))} + + + + + + + + ); +}; + +export default OneTimeTab; diff --git a/src/components/Sponsors/Steps.tsx b/src/components/Sponsors/Steps.tsx new file mode 100644 index 0000000..cc1bffe --- /dev/null +++ b/src/components/Sponsors/Steps.tsx @@ -0,0 +1,118 @@ +import { Box, Grid, Grid2, Link, Typography } from '@mui/material'; +import { ArrowRight } from 'lucide-react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; + +import { Endpoints } from '@/constants/Endpoints'; + +type StepItem = { + number: string; + step: string; + step_description: string; + link_text?: string; +}; + +type Steps = { + [step: string]: StepItem; +}; + +const Steps: React.FC = () => { + const { t } = useTranslation('components/steps'); + + const steps = t('steps', { returnObjects: true }) as Steps; + + const sortedSteps = Object.keys(steps).sort((a, b) => a.localeCompare(b, undefined, { numeric: true })); + + return ( + + + {t('heading')} + + + {t('description')} + + + {sortedSteps.map((step) => ( + + + {steps[step].number} + + + {steps[step].step} + + + {steps[step].step_description} + + {steps[step].link_text ? ( + + {steps[step].link_text} + + + ) : null} + + ))} + + + ); +}; + +export default Steps; diff --git a/src/pages/Sponsors.tsx b/src/pages/Sponsors.tsx new file mode 100644 index 0000000..038c376 --- /dev/null +++ b/src/pages/Sponsors.tsx @@ -0,0 +1,124 @@ +import { Box, Skeleton, Tab, Tabs, Typography } from '@mui/material'; +import React, { lazy, Suspense, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import ExistingTab from '@/components/Sponsors/ExistingTab'; +import FAQ from '@/components/Sponsors/FAQ'; +import MonthlyTab from '@/components/Sponsors/MonthlyTab'; +import OneTimeTab from '@/components/Sponsors/OneTimeTab'; +import Steps from '@/components/Sponsors/Steps'; + +const Footer = lazy(() => import('@/components/Home/Footer')); + +const Sponsors: React.FC = () => { + const [currentSponsorCategory, setCurrentSponsoryCategory] = useState(0); + const { t } = useTranslation('pages/sponsors'); + + const handleCategoryChange = (event: React.SyntheticEvent, value: number) => { + setCurrentSponsoryCategory(value); + }; + + return ( + + + {t('sponsors.header')} + + + {t('sponsors.description')} + + + + + + + + + {currentSponsorCategory === 0 ? : null} + {currentSponsorCategory === 1 ? : null} + {currentSponsorCategory === 2 ? : null} + + + }> +