diff --git a/package-lock.json b/package-lock.json index 81a9e2d1a..5972ebeaf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16499,6 +16499,39 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.522.tgz", "integrity": "sha512-KGKjcafTpOxda0kqwQ72M0tDmX6RsGhUJTy0Hr7slt0+CgHh9Oex8JdjY9Og68dUkTLUlBOJC0A5W5Mw3QSGCg==" }, + "node_modules/embla-carousel": { + "version": "8.0.0-rc14", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.0.0-rc14.tgz", + "integrity": "sha512-/NLkMFZ7xKryRVYeUjmhbfV63Vr07saPBDwAX2TPMbcaiWwfQfU5Xsc2AiCMZANtwmzsjRK6gSBa7hOy/VXu6g==" + }, + "node_modules/embla-carousel-autoplay": { + "version": "8.0.0-rc14", + "resolved": "https://registry.npmjs.org/embla-carousel-autoplay/-/embla-carousel-autoplay-8.0.0-rc14.tgz", + "integrity": "sha512-ey3MFD6Lti8sAO/bHLvdl+LO19U77SpYVIZP5rsPqFpnRac7bjZt9cSZ5udw9adniN0ckeRe+0y5wy+AYmzQsw==", + "peerDependencies": { + "embla-carousel": "8.0.0-rc14" + } + }, + "node_modules/embla-carousel-react": { + "version": "8.0.0-rc14", + "resolved": "https://registry.npmjs.org/embla-carousel-react/-/embla-carousel-react-8.0.0-rc14.tgz", + "integrity": "sha512-2b9vXACEcn0qja4QyaFMfCgFbFhumV3krOCGr9+jlQiuXt5z/EyfiYYziDsm70DhTtxtg/uKEGflIqZSfWRYKg==", + "dependencies": { + "embla-carousel": "8.0.0-rc14", + "embla-carousel-reactive-utils": "8.0.0-rc14" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.1 || ^18.0.0" + } + }, + "node_modules/embla-carousel-reactive-utils": { + "version": "8.0.0-rc14", + "resolved": "https://registry.npmjs.org/embla-carousel-reactive-utils/-/embla-carousel-reactive-utils-8.0.0-rc14.tgz", + "integrity": "sha512-r153bynAo9eTBuWWggPWLYnE9xqVOYmkkeMbAuGX8pkUisJN8aTLMW9b7CYOzjURRB7z85EmYRbeBg+axQzc9g==", + "peerDependencies": { + "embla-carousel": "8.0.0-rc14" + } + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -36399,6 +36432,8 @@ "classnames": "^2.3.2", "clsx": "^1.2.1", "cmdk": "^0.2.0", + "embla-carousel-autoplay": "^8.0.0-rc14", + "embla-carousel-react": "^8.0.0-rc14", "lucide-react": "^0.276.0", "react-hook-form": "^7.46.1", "tailwindcss-animate": "^1.0.7", diff --git a/shared/locales/de/website-our-work.json b/shared/locales/de/website-our-work.json index ac12ee272..5af648e36 100644 --- a/shared/locales/de/website-our-work.json +++ b/shared/locales/de/website-our-work.json @@ -1,6 +1,11 @@ { - "section-1": { + "section-our-work": { "title-1": "Wir bauen das Fundament für echte Veränderung. ", - "title-2": "Zeitgemäss. Digital. Gemeinsam." + "title-2": "Zeitgemäss. Digital. Gemeinsam.", + "vimeo-video-id": "488184818" + }, + "section-how-it-works": { + "title": "Ein solidarischer Beitrag, von Mensch zu Mensch. So einfach.", + "subtitle": "Mach einen Unterschied in weniger als 1 Minute." } } diff --git a/shared/locales/en/website-common.json b/shared/locales/en/website-common.json index ded44c0cc..c4a1d6174 100644 --- a/shared/locales/en/website-common.json +++ b/shared/locales/en/website-common.json @@ -6,8 +6,10 @@ "team": "Team", "how-it-works": "How It Works", "how-it-works-description": "Subtitle...", - "contributors": "Spender:innen", + "contributors": "Contributors", "contributors-description": "Subtitle...", + "recipients": "Recipients", + "recipients-description": "Subtitle...", "transparency": "Transparency", "finances": "Finanzen", diff --git a/shared/locales/en/website-our-work.json b/shared/locales/en/website-our-work.json index fe00edbdc..0aae689a3 100644 --- a/shared/locales/en/website-our-work.json +++ b/shared/locales/en/website-our-work.json @@ -1,6 +1,24 @@ { - "section-1": { + "section-our-work": { "title-1": "Our work is made possible by you. Make a ", - "title-2": "change with us." + "title-2": "change with us.", + "vimeo-video-id": "433937157" + }, + "section-how-it-works": { + "title": "From you to someone in need. This is solidarity.", + "subtitle": "Make a difference in under a minute.", + "item-1": "100% of individual contributions are paid out to recipients", + "item-2": "Flexible payment schedules. Adjust or cancel anytime", + "item-3": "Social Income payments are sent directly to recipients’ mobile phones.", + "item-4": "The amount disbursed is determined by the average salary where recipients live." + }, + "section-contributors": { + "header-1": "Contributors", + "title-1": "People from all walks of life contribute.", + "text-1": "We receive, amongst others, regular individual contributions from employees at the following organisations and companies:", + + "header-2": "Why contribute?", + "title-2": "One goal. Greater social justice.", + "text-2": "Our contributors want to help people for a variety of reasons. Here are just a few driving forces behind the humanitarians who contribute their 1% to Social Income:" } } diff --git a/ui/package.json b/ui/package.json index 3c6988c48..f7ad18816 100644 --- a/ui/package.json +++ b/ui/package.json @@ -61,6 +61,8 @@ "classnames": "^2.3.2", "clsx": "^1.2.1", "cmdk": "^0.2.0", + "embla-carousel-autoplay": "^8.0.0-rc14", + "embla-carousel-react": "^8.0.0-rc14", "lucide-react": "^0.276.0", "react-hook-form": "^7.46.1", "tailwindcss-animate": "^1.0.7", diff --git a/ui/src/components/carousel.tsx b/ui/src/components/carousel.tsx new file mode 100644 index 000000000..68f5e5b08 --- /dev/null +++ b/ui/src/components/carousel.tsx @@ -0,0 +1,156 @@ +'use client'; + +import Autoplay, { AutoplayOptionsType } from 'embla-carousel-autoplay'; +import useEmblaCarousel, { EmblaOptionsType } from 'embla-carousel-react'; +import React, { useContext, useEffect } from 'react'; +import { cn } from '../lib/utils'; + +export const CarouselContext = React.createContext({}); + +type CarouselProps = { + options?: EmblaOptionsType & { autoPlay?: { enabled: boolean } & AutoplayOptionsType }; + showDots?: boolean; +} & React.HTMLAttributes; + +export const Carousel = ({ children, className, options = {}, showDots = true, ...props }: CarouselProps) => { + const [emblaRef, emblaApi] = useEmblaCarousel( + options, + options?.autoPlay?.enabled ? [Autoplay(options.autoPlay)] : [], + ); + const [emblaOptions, setEmblaOptions] = React.useState(options); + const [selectedIndex, setSelectedIndex] = React.useState(0); + const slidesCount = React.Children.count(children); + + useEffect(() => { + function selectHandler() { + const index = emblaApi?.selectedScrollSnap(); + setSelectedIndex(index || 0); + } + emblaApi?.on('select', selectHandler); + + return () => { + emblaApi?.off('select', selectHandler); + }; + }, [emblaApi]); + + useEffect(() => { + setEmblaOptions(options); + }, [options]); + + return ( + +
+
{children}
+
+ {showDots && ( + emblaApi?.scrollTo(index)} + /> + )} + + emblaApi?.scrollNext()} + onPrev={() => emblaApi?.scrollPrev()} + /> +
+ ); +}; + +export const CarouselContent = React.forwardRef>( + ({ children, className, ...props }, ref) => { + const options = useContext(CarouselContext); + return ( +
+ {children} +
+ ); + }, +); + +type CarouselDots = { + itemsLength: number; + selectedIndex: number; + onClick?: (index: number) => void; +}; + +const CarouselDots = ({ itemsLength, selectedIndex, onClick }: CarouselDots) => { + const arr = new Array(itemsLength).fill(0); + return ( +
+ {arr.map((_, index) => { + const selected = index === selectedIndex; + return ( +
onClick?.(index)} + >
+ ); + })} +
+ ); +}; + +type Props = { + canScrollPrev: boolean; + canScrollNext: boolean; + onPrev(): void; + onNext(): void; +}; +const CarouselControls = (props: Props) => { + return ( +
+ + +
+ ); +}; +export default CarouselControls; diff --git a/ui/src/components/containers/base-container.tsx b/ui/src/components/containers/base-container.tsx index b273790e6..ba4f1b77d 100644 --- a/ui/src/components/containers/base-container.tsx +++ b/ui/src/components/containers/base-container.tsx @@ -1,14 +1,21 @@ -import classNames from 'classnames'; -import { PropsWithChildren } from 'react'; +import React from 'react'; +import { twMerge } from 'tailwind-merge'; +import { BackgroundColor } from '../../interfaces/color'; -interface BaseContainerProps { - className?: string; -} +type BaseContainerProps = { + backgroundColor?: BackgroundColor; +} & React.HTMLAttributes; -export function BaseContainer({ children, className }: PropsWithChildren) { - return ( -
-
{children}
-
- ); -} +export const BaseContainer = React.forwardRef( + ({ children, className, backgroundColor, ...props }, ref) => { + return ( +
+
+
+ {children} +
+
+
+ ); + }, +); diff --git a/ui/src/components/dialog.tsx b/ui/src/components/dialog.tsx index 9606ab96b..f12127c7a 100644 --- a/ui/src/components/dialog.tsx +++ b/ui/src/components/dialog.tsx @@ -39,7 +39,7 @@ const DialogContent = React.forwardRef< ; - const FONT_COLOR_MAP: { [key in FontColor]: string } = { - 'base-content': 'text-base-content', - primary: 'text-primary', - 'primary-content': 'text-primary-content', - secondary: 'text-secondary', - 'secondary-focus': 'text-secondary-focus', - 'secondary-content': 'text-secondary-content', - accent: 'text-accent', - 'accent-focus': 'text-accent-focus', - 'accent-content': 'text-accent-content', - neutral: 'text-neutral', - 'neutral-focus': 'text-neutral-focus', - 'neutral-content': 'text-neutral-content', - info: 'text-info', - 'info-content': 'text-info-content', - success: 'text-success', - 'success-content': 'text-success-content', - warning: 'text-warning', - 'warning-content': 'text-warning-content', - error: 'text-error', - 'error-content': 'text-error-content', + foreground: 'text-foreground', + 'primary-foreground': 'text-primary-foreground', + 'secondary-foreground': 'text-secondary-foreground', + 'accent-foreground': 'text-accent-foreground', + 'destructive-foreground': 'text-destructive-foreground', + 'muted-foreground': 'text-muted-foreground', + 'popover-foreground': 'text-popover-foreground', + 'card-foreground': 'text-card-foreground', }; const LINE_HEIGHTS = ['none', 'tight', 'snug', 'normal', 'relaxed', 'loose'] as const; @@ -98,7 +62,7 @@ export function Typography({ as, size = 'md', weight = 'normal', - color = 'base-content', + color = 'foreground', lineHeight = 'normal', className, children, diff --git a/ui/src/globals.css b/ui/src/globals.css index 87349fef9..a9caa295b 100644 --- a/ui/src/globals.css +++ b/ui/src/globals.css @@ -3,6 +3,7 @@ @tailwind utilities; @layer base { + :root, .theme-default { --si-yellow: hsl(48, 100%, 49%); --background: hsl(0 0% 100%); @@ -36,7 +37,11 @@ --radius: 0.5rem; } - .theme-blue { + .theme-light-blue { + --background: hsl(216, 54%, 95%); + } + + .theme-dark-blue { --si-yellow: hsl(48, 100%, 49%); --background: hsl(216, 54%, 55%); --foreground: hsl(60 9.1% 97.8%); @@ -73,7 +78,7 @@ @layer base { body, .theme-default, - .theme-blue { + .theme-dark-blue { @apply bg-background text-foreground; } } diff --git a/ui/src/index.ts b/ui/src/index.ts index acc09d906..1968606cf 100644 --- a/ui/src/index.ts +++ b/ui/src/index.ts @@ -4,6 +4,7 @@ export * from './components/accordion'; export * from './components/badge'; export * from './components/button'; export * from './components/card'; +export * from './components/carousel'; export * from './components/collapsible'; export * from './components/containers'; export * from './components/dialog'; diff --git a/ui/src/interfaces/color.ts b/ui/src/interfaces/color.ts index 5028b4d62..5c4d373a6 100644 --- a/ui/src/interfaces/color.ts +++ b/ui/src/interfaces/color.ts @@ -1,31 +1,55 @@ export const COLORS = [ + 'foreground', + 'background', + 'border', + 'input', + 'ring', + 'si-yellow', 'primary', - 'primary-focus', - 'primary-content', + 'primary-foreground', 'secondary', - 'secondary-focus', - 'secondary-content', + 'secondary-foreground', + 'destructive', + 'destructive-foreground', + 'muted', + 'muted-foreground', 'accent', - 'accent-focus', - 'accent-content', - 'neutral', - 'neutral-focus', - 'neutral-content', - 'base-100', - 'base-200', - 'base-300', - 'base-content', - 'info', - 'info-focus', - 'info-content', - 'success', - 'success-focus', - 'success-content', - 'warning', - 'warning-focus', - 'warning-content', - 'error', - 'error-focus', - 'error-content', + 'accent-foreground', + 'popover', + 'popover-foreground', + 'card', + 'card-foreground', + 'bg-red-50', + 'bg-yellow-50', + 'bg-green-50', + 'bg-blue-50', + 'bg-indigo-50', + 'bg-purple-50', + 'bg-pink-50', + 'bg-muted', ] as const; export type Color = (typeof COLORS)[number]; + +export type FontColor = Extract< + Color, + | 'foreground' + | 'primary-foreground' + | 'secondary-foreground' + | 'accent-foreground' + | 'destructive-foreground' + | 'muted-foreground' + | 'popover-foreground' + | 'card-foreground' +>; + +export type BackgroundColor = Extract< + Color, + | 'bg-red-50' + | 'bg-yellow-50' + | 'bg-green-50' + | 'bg-blue-50' + | 'bg-indigo-50' + | 'bg-purple-50' + | 'bg-pink-50' + | 'bg-muted' +>; diff --git a/website/src/app/[lang]/[country]/(website)/(home)/page.tsx b/website/src/app/[lang]/[country]/(website)/(home)/page.tsx index c5c85420d..0d3a4c4e1 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/page.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/page.tsx @@ -22,7 +22,7 @@ export default async function Page(props: DefaultPageProps) { videoButton: translator.t('section-2.video-button'), }} /> - + {props.params.country === 'ch' && } diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx index bcac57b5f..7043c87c2 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx @@ -15,7 +15,7 @@ export default async function Section1({ params }: DefaultPageProps) {
{translator.t('section-1.title-1')} - + {translator.t('section-1.title-2')} {translator.t('section-1.title-3')} diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx index 48714e654..268eb1d48 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx @@ -1,10 +1,9 @@ 'use client'; +import { VimeoVideoComponent } from '@/components/VimeoVideoComponent'; import { PlayCircleIcon } from '@heroicons/react/24/outline'; import { BaseContainer, Dialog, DialogContent, DialogTrigger, Typography } from '@socialincome/ui'; -import Player from '@vimeo/player'; import Image from 'next/image'; -import { useEffect, useRef, useState } from 'react'; import houseGif from './house.gif'; type Section2Props = { @@ -18,34 +17,14 @@ type Section2Props = { }; export default function Section2({ vimeoVideoId, translations }: Section2Props) { - const playerRef = useRef(null); - const [player, setPlayer] = useState(null); - const [showModal, setShowModal] = useState(false); - - useEffect(() => { - if (playerRef.current) { - setPlayer( - new Player(playerRef.current, { - id: vimeoVideoId, - controls: true, - responsive: true, - }), - ); - } - }, [playerRef, vimeoVideoId]); - - useEffect(() => { - void player?.pause(); - }, [player, showModal]); - return ( - +
{translations.title1} - + {translations.title2} @@ -53,22 +32,23 @@ export default function Section2({ vimeoVideoId, translations }: Section2Props)
-
setShowModal((prevState) => !prevState)}> - House Animation for Video Preview - - -
- - - {translations.videoButton} - -
-
- -
- -
-
+ + + House Animation for Video Preview + + + {translations.videoButton} + + + + + +
diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-3.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-3.tsx index 5358b3bdb..36334f39a 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-3.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-3.tsx @@ -2,15 +2,13 @@ import { DefaultPageProps } from '@/app/[lang]/[country]'; import { BaseContainer, Typography } from '@socialincome/ui'; export default function Section3({ params }: DefaultPageProps) { - if (params.country === 'ch') { - return ( - -
-
- Who should, if not us here in Switzerland? -
+ return ( + +
+
+ Who should, if not us here in Switzerland?
- - ); - } +
+
+ ); } diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-4.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-4.tsx index 4e7d2dae5..0a8176203 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-4.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-4.tsx @@ -9,13 +9,13 @@ export default async function Section4({ params }: DefaultPageProps) { }); return ( - +

{translator.t('section-4.title-1')} - + {translator.t('section-4.title-2')}

diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-5-card.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-5-card.tsx index 1ffdabeac..a94309383 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-5-card.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-5-card.tsx @@ -1,9 +1,17 @@ 'use client'; import { CheckCircleIcon } from '@heroicons/react/24/outline'; -import { Dialog, DialogContent, DialogTrigger, Typography } from '@socialincome/ui'; +import { + Card, + CardContent, + CardHeader, + CardTitle, + Dialog, + DialogContent, + DialogTrigger, + Typography, +} from '@socialincome/ui'; import Link from 'next/link'; -import { useCallback, useRef } from 'react'; type SectionCardProps = { titles: { @@ -18,31 +26,28 @@ type SectionCardProps = { }; export function SectionCard({ titles, items = [], paragraphs = [], articles = [], faqs = [] }: SectionCardProps) { - const ref = useRef(null); - const handleShow = useCallback(() => ref.current?.showModal(), [ref]); - return ( -
- - {titles.main} - -
- {items.map((item, index) => ( -
- - - {item} - -
- ))} -
-
+ + + {titles.main} + + +
    + {items.map((item, index) => ( +
  • + + {item} +
  • + ))} +
+
+
- -
+ +
{titles.main} @@ -62,7 +67,7 @@ export function SectionCard({ titles, items = [], paragraphs = [], articles = []
{article.author} - {article.title} + {article.title}
))} @@ -78,7 +83,7 @@ export function SectionCard({ titles, items = [], paragraphs = [], articles = [] {faqs.map((faq, index) => (
- {faq.question} + {faq.question}
))} diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-5.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-5.tsx index ebb56577c..77e8c7c0f 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-5.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-5.tsx @@ -11,11 +11,11 @@ export default async function Section5({ params }: DefaultPageProps) { return ( -
- +
+ {translator?.t('section-5.title')} -
+
- + - + {title} diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-6.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-6.tsx index b0709acb9..e363a1d72 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-6.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-6.tsx @@ -10,13 +10,13 @@ export default async function Section6({ params }: DefaultPageProps) { }); return ( - +

{translator.t('section-6.title-1')} - + {translator.t('section-6.title-2')}

@@ -26,7 +26,6 @@ export default async function Section6({ params }: DefaultPageProps) { description={translator.t('section-6.card-1.description')} paragraphs={[translator.t('section-6.card-2.paragraph-1')]} /> - -
+
Change animation -
+
{translator?.t('section-1.title-1')} - + {translator?.t('section-1.title-2')}
diff --git a/website/src/app/[lang]/[country]/(website)/donate/individual/page.tsx b/website/src/app/[lang]/[country]/(website)/donate/individual/page.tsx index 51968b5b7..feff77d89 100644 --- a/website/src/app/[lang]/[country]/(website)/donate/individual/page.tsx +++ b/website/src/app/[lang]/[country]/(website)/donate/individual/page.tsx @@ -97,7 +97,7 @@ export default function Page({ params, searchParams }: DefaultPageProps) { return ( - + How would you like to pay?
@@ -146,7 +146,7 @@ export default function Page({ params, searchParams }: DefaultPageProps) { name="amount" render={({ field }) => ( - + Amount diff --git a/website/src/app/[lang]/[country]/(website)/donate/success/page.tsx b/website/src/app/[lang]/[country]/(website)/donate/success/page.tsx index c0b00891b..c272fc439 100644 --- a/website/src/app/[lang]/[country]/(website)/donate/success/page.tsx +++ b/website/src/app/[lang]/[country]/(website)/donate/success/page.tsx @@ -11,7 +11,7 @@ export default async function Page({ searchParams }: DefaultPageProps) { return (
- + Thank you )} /> - diff --git a/website/src/app/[lang]/[country]/(website)/me/contributions/billing-portal-button.tsx b/website/src/app/[lang]/[country]/(website)/me/contributions/billing-portal-button.tsx index 499a7e345..d0e241f70 100644 --- a/website/src/app/[lang]/[country]/(website)/me/contributions/billing-portal-button.tsx +++ b/website/src/app/[lang]/[country]/(website)/me/contributions/billing-portal-button.tsx @@ -23,7 +23,7 @@ export function BillingPortalButton() { }, [authUser]); return ( - ); diff --git a/website/src/app/[lang]/[country]/(website)/me/layout.tsx b/website/src/app/[lang]/[country]/(website)/me/layout.tsx index 12c6b482b..7fd1f08bd 100644 --- a/website/src/app/[lang]/[country]/(website)/me/layout.tsx +++ b/website/src/app/[lang]/[country]/(website)/me/layout.tsx @@ -20,7 +20,7 @@ export default async function Layout({ children, params }: PropsWithChildren - +
{tabs.map((tab, index) => ( diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/epfl.svg b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/epfl.svg new file mode 100644 index 000000000..cf5b0352a --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/epfl.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/gov.svg b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/gov.svg new file mode 100644 index 000000000..1f270d61a --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/gov.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/mckinsey.svg b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/mckinsey.svg new file mode 100644 index 000000000..348a8ff0b --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/mckinsey.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/microsoft.svg b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/microsoft.svg new file mode 100644 index 000000000..e9ff7da60 --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/microsoft.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/website/src/app/[lang]/[country]/(website)/our-work/phones.gif b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/phones-1.gif similarity index 100% rename from website/src/app/[lang]/[country]/(website)/our-work/phones.gif rename to website/src/app/[lang]/[country]/(website)/our-work/(assets)/phones-1.gif diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/phones-2.gif b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/phones-2.gif new file mode 100644 index 000000000..c49de1c80 Binary files /dev/null and b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/phones-2.gif differ diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/r17.svg b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/r17.svg new file mode 100644 index 000000000..dac9130c4 --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/r17.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/srg.svg b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/srg.svg new file mode 100644 index 000000000..70de0a2a8 --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/srg.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/website/src/app/[lang]/[country]/(website)/our-work/(assets)/un.svg b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/un.svg new file mode 100644 index 000000000..9198b0c89 --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/(assets)/un.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/website/src/app/[lang]/[country]/(website)/our-work/page.tsx b/website/src/app/[lang]/[country]/(website)/our-work/page.tsx index 656f189ca..914526110 100644 --- a/website/src/app/[lang]/[country]/(website)/our-work/page.tsx +++ b/website/src/app/[lang]/[country]/(website)/our-work/page.tsx @@ -1,10 +1,14 @@ import { DefaultPageProps } from '@/app/[lang]/[country]'; -import Section1 from './section-1'; +import { SectionContributors } from './section-contributors'; +import { SectionHowItWorks } from './section-how-it-works'; +import { SectionOurWork } from './section-our-work'; export default async function Page(props: DefaultPageProps) { return ( <> - + + + ); } diff --git a/website/src/app/[lang]/[country]/(website)/our-work/section-1.tsx b/website/src/app/[lang]/[country]/(website)/our-work/section-1.tsx deleted file mode 100644 index 5d368c01f..000000000 --- a/website/src/app/[lang]/[country]/(website)/our-work/section-1.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { DefaultPageProps } from '@/app/[lang]/[country]'; -import { Translator } from '@socialincome/shared/src/utils/i18n'; -import { BaseContainer, Typography } from '@socialincome/ui'; -import Image from 'next/image'; -import phonesGif from './phones.gif'; - -export default async function Section1({ params }: DefaultPageProps) { - const translator = await Translator.getInstance({ - language: params.lang, - namespaces: ['website-our-work'], - }); - - return ( - -
- Change animation -
- - {translator?.t('section-1.title-1')} - - - {translator?.t('section-1.title-2')} - -
-
-
- ); -} diff --git a/website/src/app/[lang]/[country]/(website)/our-work/section-contributors-carousel.tsx b/website/src/app/[lang]/[country]/(website)/our-work/section-contributors-carousel.tsx new file mode 100644 index 000000000..28036ef70 --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/section-contributors-carousel.tsx @@ -0,0 +1,56 @@ +'use client'; + +import { useScreenSize } from '@/hooks/useScreenSize'; +import { Carousel, CarouselContent } from '@socialincome/ui'; +import Image from 'next/image'; +import epflSVG from './(assets)/epfl.svg'; +import govSVG from './(assets)/gov.svg'; +import mckinseySVG from './(assets)/mckinsey.svg'; +import microsoftSVG from './(assets)/microsoft.svg'; +import r17SVG from './(assets)/r17.svg'; +import srgSVG from './(assets)/srg.svg'; +import unSVG from './(assets)/un.svg'; + +export function SectionContributorsCarousel() { + const screenSize = useScreenSize(); + + const companyLogos = [ + { logo: govSVG, name: 'FDFA' }, + { logo: microsoftSVG, name: 'Microsoft' }, + { logo: mckinseySVG, name: 'McKinsey' }, + { logo: unSVG, name: 'UN' }, + { logo: srgSVG, name: 'SRG' }, + { logo: epflSVG, name: 'EPFL' }, + { logo: r17SVG, name: 'R17' }, + ]; + + let slidesToScroll; + switch (screenSize) { + case 'xs': + case 'sm': + slidesToScroll = 2; + break; + case 'md': + slidesToScroll = 3; + break; + default: + slidesToScroll = 4; + break; + } + + return ( + + {companyLogos.map((entry, index) => ( + + {`${entry.name} + + ))} + + ); +} diff --git a/website/src/app/[lang]/[country]/(website)/our-work/section-contributors.tsx b/website/src/app/[lang]/[country]/(website)/our-work/section-contributors.tsx new file mode 100644 index 000000000..541d0f45a --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/section-contributors.tsx @@ -0,0 +1,44 @@ +import { DefaultPageProps } from '@/app/[lang]/[country]'; +import { SectionContributorsCarousel } from '@/app/[lang]/[country]/(website)/our-work/section-contributors-carousel'; +import { Translator } from '@socialincome/shared/src/utils/i18n'; +import { BaseContainer, Typography } from '@socialincome/ui'; + +export async function SectionContributors({ params }: DefaultPageProps) { + const translator = await Translator.getInstance({ + language: params.lang, + namespaces: ['website-our-work'], + }); + + return ( + +
+ + {translator.t('section-contributors.header-1')} + + + {translator.t('section-contributors.title-1')} + + + {translator.t('section-contributors.text-1')} + + +
+ +
+ + {translator.t('section-contributors.header-2')} + + + {translator.t('section-contributors.title-2')} + + + {translator.t('section-contributors.text-2')} + +
+
+ ); +} diff --git a/website/src/app/[lang]/[country]/(website)/our-work/section-how-it-works.tsx b/website/src/app/[lang]/[country]/(website)/our-work/section-how-it-works.tsx new file mode 100644 index 000000000..77ceadceb --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/section-how-it-works.tsx @@ -0,0 +1,40 @@ +import { DefaultPageProps } from '@/app/[lang]/[country]'; +import { CheckCircleIcon } from '@heroicons/react/24/outline'; +import { Translator } from '@socialincome/shared/src/utils/i18n'; +import { BaseContainer, Typography } from '@socialincome/ui'; +import _ from 'lodash'; +import Image from 'next/image'; +import phonesGif from './(assets)/phones-2.gif'; + +export async function SectionHowItWorks({ params }: DefaultPageProps) { + const translator = await Translator.getInstance({ + language: params.lang, + namespaces: ['website-our-work'], + }); + + return ( + +
+ + {translator.t('section-how-it-works.title')} + +
+ Change animation +
+ + {translator.t('section-how-it-works.subtitle')} + +
    + {_.range(1, 5).map((i) => ( +
  • + + {translator.t(`section-how-it-works.item-${i}`)} +
  • + ))} +
+
+
+
+
+ ); +} diff --git a/website/src/app/[lang]/[country]/(website)/our-work/section-our-work.tsx b/website/src/app/[lang]/[country]/(website)/our-work/section-our-work.tsx new file mode 100644 index 000000000..850eefe38 --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/our-work/section-our-work.tsx @@ -0,0 +1,34 @@ +import { DefaultPageProps } from '@/app/[lang]/[country]'; +import { VimeoVideoComponent } from '@/components/VimeoVideoComponent'; +import { Translator } from '@socialincome/shared/src/utils/i18n'; +import { BaseContainer, Dialog, DialogContent, DialogTrigger, Typography } from '@socialincome/ui'; +import Image from 'next/image'; +import phonesGif from './(assets)/phones-1.gif'; + +export async function SectionOurWork({ params }: DefaultPageProps) { + const translator = await Translator.getInstance({ + language: params.lang, + namespaces: ['website-our-work'], + }); + + return ( + + + + Change animation +

+ + {translator?.t('section-our-work.title-1')} + + + {translator?.t('section-our-work.title-2')} + +

+
+ + + +
+
+ ); +} diff --git a/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-1.tsx b/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-1.tsx index 5c8a4a514..a434af963 100644 --- a/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-1.tsx +++ b/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-1.tsx @@ -34,7 +34,7 @@ export async function Section1({ params, paymentStats, contributionStats }: Sect {translator.t('section-1.title-2')}
- {translator.t('section-1.since-march-2020')} + {translator.t('section-1.since-march-2020')} {cards.map((card, index) => (
diff --git a/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-2.tsx b/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-2.tsx index b1cbca4b3..5a31decd8 100644 --- a/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-2.tsx +++ b/website/src/app/[lang]/[country]/(website)/transparency/finances/[currency]/section-2.tsx @@ -31,7 +31,7 @@ export async function Section2({ params, contributionStats, paymentStats }: Sect {translator.t('section-2.contributions-from', { context: { value: contributionStats.totalIndividualContributionsAmount, currency: params.currency }, })} - + {translator.t('section-2.individuals', { context: { count: contributionStats.totalIndividualContributorsCount }, })} @@ -67,7 +67,7 @@ export async function Section2({ params, contributionStats, paymentStats }: Sect currency: params.currency, }, })} - + {translator.t('section-2.institutions', { context: { count: contributionStats.totalInstitutionalContributorsCount }, })} diff --git a/website/src/app/providers.tsx b/website/src/app/providers.tsx index 61a20a344..13a17b4aa 100644 --- a/website/src/app/providers.tsx +++ b/website/src/app/providers.tsx @@ -101,7 +101,7 @@ export function ThemeProvider({ children }: PropsWithChildren) { let theme; switch (baseSegment) { case 'donate': - theme = 'theme-blue'; + theme = 'theme-dark-blue'; break; default: theme = 'theme-default'; diff --git a/website/src/components/VimeoVideoComponent.tsx b/website/src/components/VimeoVideoComponent.tsx new file mode 100644 index 000000000..58448313f --- /dev/null +++ b/website/src/components/VimeoVideoComponent.tsx @@ -0,0 +1,20 @@ +'use client'; + +import Player from '@vimeo/player'; +import { useEffect, useRef } from 'react'; + +export function VimeoVideoComponent({ vimeoVideoId }: { vimeoVideoId: number }) { + const playerRef = useRef(null); + + useEffect(() => { + if (playerRef.current) { + new Player(playerRef.current, { + id: vimeoVideoId, + controls: true, + responsive: true, + }); + } + }, [vimeoVideoId]); + + return
; +} diff --git a/website/src/components/footer/footer-client.tsx b/website/src/components/footer/footer-client.tsx index e1a4d9bc4..d6b3c2c7c 100644 --- a/website/src/components/footer/footer-client.tsx +++ b/website/src/components/footer/footer-client.tsx @@ -16,6 +16,7 @@ import { } from '@socialincome/ui'; import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context'; import { ReadonlyURLSearchParams, useRouter, useSearchParams } from 'next/navigation'; +import { Suspense } from 'react'; type FooterClientProps = { supportedTranslatedLanguages: { code: LanguageCode; translation: string }[]; @@ -30,11 +31,7 @@ function onCountryChange(country: ValidCountry, router: AppRouterInstance, searc } // TODO: i18n -export function FooterClient({ - params, - supportedTranslatedLanguages, - supportedTranslatedCountries, -}: FooterClientProps) { +function FooterComponent({ params, supportedTranslatedLanguages, supportedTranslatedCountries }: FooterClientProps) { const router = useRouter(); const searchParams = useSearchParams(); @@ -48,7 +45,7 @@ export function FooterClient({ return (