new guida
This commit is contained in:
parent
d26acf9b60
commit
d303c189a9
2 changed files with 310 additions and 5 deletions
261
apps/infoalloggi/src/components/how-it-works.tsx
Normal file
261
apps/infoalloggi/src/components/how-it-works.tsx
Normal file
|
|
@ -0,0 +1,261 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { domAnimation, LazyMotion, m } from "framer-motion";
|
||||||
|
import type React from "react";
|
||||||
|
import { cn } from "~/lib/utils";
|
||||||
|
|
||||||
|
interface CardProps {
|
||||||
|
number: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
colorTheme?: "orange" | "blue" | "purple";
|
||||||
|
className?: string;
|
||||||
|
rotate?: string;
|
||||||
|
colors?: {
|
||||||
|
bg: string;
|
||||||
|
text: string;
|
||||||
|
border: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Card = ({
|
||||||
|
number,
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
colorTheme = "blue",
|
||||||
|
className,
|
||||||
|
colors: customColors,
|
||||||
|
}: CardProps) => {
|
||||||
|
const defaultBgColors = {
|
||||||
|
orange: "bg-orange-50 dark:bg-orange-500/10",
|
||||||
|
blue: "bg-blue-50 dark:bg-blue-500/10",
|
||||||
|
purple: "bg-purple-50 dark:bg-purple-500/10",
|
||||||
|
};
|
||||||
|
const defaultTextColors = {
|
||||||
|
orange: "text-orange-500 dark:text-orange-400",
|
||||||
|
blue: "text-blue-600 dark:text-blue-400",
|
||||||
|
purple: "text-purple-600 dark:text-purple-400",
|
||||||
|
};
|
||||||
|
const defaultBorderColors = {
|
||||||
|
orange: "border-orange-100 dark:border-orange-500/20",
|
||||||
|
blue: "border-blue-100 dark:border-blue-500/20",
|
||||||
|
purple: "border-purple-100 dark:border-purple-500/20",
|
||||||
|
};
|
||||||
|
|
||||||
|
const bgColor = customColors?.bg || defaultBgColors[colorTheme];
|
||||||
|
const textColor = customColors?.text || defaultTextColors[colorTheme];
|
||||||
|
const borderColor = customColors?.border || defaultBorderColors[colorTheme];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
`relative w-full transition-transform duration-300 hover:z-30 hover:scale-105 md:w-[400px]`,
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div className="rounded-[25px] border border-neutral-100 bg-card p-2 shadow-[0px_10px_20px_0px_#D3D3D3] dark:border-neutral-800 dark:shadow-none">
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
`relative flex h-full flex-col overflow-hidden rounded-[15px] border p-[15px]`,
|
||||||
|
bgColor,
|
||||||
|
borderColor,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<span className={cn(`mb-5 text-4xl`, textColor)}>{number}</span>
|
||||||
|
<h3 className="mb-[10px] font-semibold text-2xl text-neutral-800 leading-none dark:text-neutral-100">
|
||||||
|
{title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-neutral-500 tracking-tight dark:text-neutral-400">
|
||||||
|
{description}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface Step {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
colorTheme?: "orange" | "blue" | "purple";
|
||||||
|
colors?: {
|
||||||
|
bg: string;
|
||||||
|
text: string;
|
||||||
|
border: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StepPosition {
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HowItWorksProps {
|
||||||
|
features?: Step[];
|
||||||
|
className?: string;
|
||||||
|
stepPositions?: StepPosition[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_CARD_POSITIONS: StepPosition[] = [
|
||||||
|
{
|
||||||
|
className: "md:absolute md:top-0 md:left-[15%] lg:left-[10%]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: "md:absolute md:top-[210px] md:right-[15%] lg:right-[10%]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: "md:absolute md:top-[450px] md:left-[15%] lg:left-[10%]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: "md:absolute md:top-[680px] md:right-[10%] lg:right-[10%]",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
className: "md:absolute md:top-[910px] md:left-[15%] lg:left-[10%]",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function HowItWorks({
|
||||||
|
features,
|
||||||
|
className,
|
||||||
|
stepPositions,
|
||||||
|
}: HowItWorksProps) {
|
||||||
|
const defaultFeatures: Step[] = [
|
||||||
|
{
|
||||||
|
title: "Create Account",
|
||||||
|
description:
|
||||||
|
"Sign up in minutes. Enter your details and verify your email to get started.",
|
||||||
|
colorTheme: "orange",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Verify Identity",
|
||||||
|
description:
|
||||||
|
"Complete your profile verification to ensure secure transactions and compliance.",
|
||||||
|
colorTheme: "blue",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Select Plan",
|
||||||
|
description:
|
||||||
|
"Choose from a variety of investment plans tailored to your financial goals.",
|
||||||
|
colorTheme: "purple",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Analyze & Invest",
|
||||||
|
description:
|
||||||
|
"Review returns and make your first investment with confidence.",
|
||||||
|
colorTheme: "orange",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Track Growth",
|
||||||
|
description:
|
||||||
|
"Monitor your portfolio in real-time and watch your wealth grow over time.",
|
||||||
|
colorTheme: "blue",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const data = features && features.length > 0 ? features : defaultFeatures;
|
||||||
|
const positions = stepPositions || DEFAULT_CARD_POSITIONS;
|
||||||
|
|
||||||
|
let height = 1130;
|
||||||
|
if (data.length === 1) height = 400;
|
||||||
|
else if (data.length === 2) height = 450;
|
||||||
|
else if (data.length === 3) height = 800;
|
||||||
|
else if (data.length === 4) height = 900;
|
||||||
|
else height = 1130;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<LazyMotion features={domAnimation}>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
`relative mt-5 bg-background max-md:pt-5 max-md:pb-5 md:pt-10`,
|
||||||
|
className,
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="pointer-events-none absolute inset-0 opacity-[0.08] dark:opacity-[0.15]"
|
||||||
|
style={{
|
||||||
|
backgroundImage: "linear-gradient(#000 1px, transparent 1px)",
|
||||||
|
backgroundSize: "100% 32px",
|
||||||
|
marginTop: "4px",
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div
|
||||||
|
className="pointer-events-none absolute inset-0 opacity-0 dark:opacity-[0.1]"
|
||||||
|
style={{
|
||||||
|
backgroundImage: "linear-gradient(#fff 1px, transparent 1px)",
|
||||||
|
backgroundSize: "100% 32px",
|
||||||
|
marginTop: "4px",
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<div className="pointer-events-none absolute inset-y-0 left-0 w-1/2 bg-linear-to-r from-background"></div>
|
||||||
|
<div className="pointer-events-none absolute inset-y-0 right-0 w-1/2 bg-linear-to-l from-background"></div>
|
||||||
|
|
||||||
|
<div className="relative z-10 mx-auto max-w-6xl">
|
||||||
|
<div
|
||||||
|
className="relative mx-auto flex h-auto w-full max-w-[1400px] flex-col space-y-6 sm:space-y-8 md:block md:h-(--md-height) md:space-y-0"
|
||||||
|
style={{ "--md-height": `${height}px` } as React.CSSProperties}
|
||||||
|
>
|
||||||
|
{data.length > 1 && (
|
||||||
|
<svg
|
||||||
|
className="pointer-events-none absolute top-0 left-0 z-0 hidden h-full w-full md:block"
|
||||||
|
preserveAspectRatio="none"
|
||||||
|
viewBox={`0 0 1000 ${height}`}
|
||||||
|
>
|
||||||
|
<title>stroke</title>
|
||||||
|
{(() => {
|
||||||
|
const pathD = data.reduce((acc, _, index) => {
|
||||||
|
if (index >= data.length - 1) return acc;
|
||||||
|
if (index === 0)
|
||||||
|
return "M 290 150 C 500 150, 550 270, 710 270"; // 1 -> 2
|
||||||
|
if (index === 1)
|
||||||
|
return `${acc} C 850 270, 500 350, 290 450`; // 2 -> 3
|
||||||
|
if (index === 2)
|
||||||
|
return `${acc} C 290 600, 550 720, 750 720`; // 3 -> 4
|
||||||
|
if (index === 3)
|
||||||
|
return `${acc} C 950 720, 500 800, 290 850`; // 4 -> 5
|
||||||
|
return acc;
|
||||||
|
}, "");
|
||||||
|
return (
|
||||||
|
<m.path
|
||||||
|
animate={{
|
||||||
|
strokeDashoffset: -140, // Multiple of 14 (8+6) for seamless loop
|
||||||
|
}}
|
||||||
|
className="text-neutral-300 dark:text-neutral-700"
|
||||||
|
d={pathD}
|
||||||
|
fill="none"
|
||||||
|
initial={{ strokeDashoffset: 0 }}
|
||||||
|
stroke="currentColor"
|
||||||
|
strokeDasharray="8 6"
|
||||||
|
strokeLinecap="round"
|
||||||
|
strokeWidth="2"
|
||||||
|
transition={{
|
||||||
|
duration: 3,
|
||||||
|
repeat: Infinity,
|
||||||
|
ease: "linear",
|
||||||
|
}}
|
||||||
|
vectorEffect="non-scaling-stroke"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})()}
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{data.map((step, index) => {
|
||||||
|
const position = positions[index % positions.length];
|
||||||
|
if (!position) return null;
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
className={position.className}
|
||||||
|
colors={step.colors}
|
||||||
|
colorTheme={step.colorTheme || "blue"}
|
||||||
|
description={step.description}
|
||||||
|
key={step.title}
|
||||||
|
number={`0${index + 1}`}
|
||||||
|
title={step.title}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LazyMotion>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { NextPage } from "next";
|
import type { NextPage } from "next";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { ComeFunziona } from "~/components/come_funziona";
|
import HowItWorks from "~/components/how-it-works";
|
||||||
import {
|
import {
|
||||||
Accordion,
|
Accordion,
|
||||||
AccordionContent,
|
AccordionContent,
|
||||||
|
|
@ -16,6 +16,49 @@ import { useTranslation } from "~/providers/I18nProvider";
|
||||||
*/
|
*/
|
||||||
const Guida: NextPage = () => {
|
const Guida: NextPage = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
//todo translation
|
||||||
|
const features = [
|
||||||
|
{
|
||||||
|
title: "Esplora gli annunci",
|
||||||
|
description:
|
||||||
|
"In base a località, tipologia, prezzo, data di disponibilità e molte altre caratteristiche.",
|
||||||
|
colors: {
|
||||||
|
bg: "bg-orange-50 dark:bg-orange-500/10",
|
||||||
|
text: "text-orange-500 dark:text-orange-400",
|
||||||
|
border: "border-orange-100 dark:border-orange-500/20",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Attiva il servizio",
|
||||||
|
description:
|
||||||
|
"Richiedi il servizio, ti invieremo un collegamento per completare la ricerca che abbiamo creato per te e acquistare il servizio.",
|
||||||
|
colors: {
|
||||||
|
bg: "bg-blue-50 dark:bg-blue-500/10",
|
||||||
|
text: "text-blue-600 dark:text-blue-400",
|
||||||
|
border: "border-blue-100 dark:border-blue-500/20",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Visita le case",
|
||||||
|
description:
|
||||||
|
"Fissa appuntamenti direttamente con i proprietari per una visita. La trattativa è tra voi privati. Non c'è mediazione.",
|
||||||
|
colors: {
|
||||||
|
bg: "bg-purple-50 dark:bg-purple-500/10",
|
||||||
|
text: "text-purple-600 dark:text-purple-400",
|
||||||
|
border: "border-purple-100 dark:border-purple-500/20",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "Contratto di affitto",
|
||||||
|
description:
|
||||||
|
"Procederemo alla stesura del contratto di locazione in base agli accordi che hai trovato con il propritario.",
|
||||||
|
colors: {
|
||||||
|
bg: "bg-green-50 dark:bg-green-500/10",
|
||||||
|
text: "text-green-500 dark:text-green-400",
|
||||||
|
border: "border-green-100 dark:border-green-500/20",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|
@ -23,12 +66,13 @@ const Guida: NextPage = () => {
|
||||||
<title>{t.heads.guida_titolo}</title>
|
<title>{t.heads.guida_titolo}</title>
|
||||||
<meta content={t.heads.main_description} name="description" />
|
<meta content={t.heads.main_description} name="description" />
|
||||||
</Head>
|
</Head>
|
||||||
<main className="mx-auto w-full max-w-8xl px-2 py-5 md:px-8">
|
<main className="mx-auto flex w-full max-w-8xl flex-col px-2 py-5 md:px-8">
|
||||||
<Badge className="bg-muted py-1 text-foreground text-sm outline outline-muted-foreground">
|
<Badge className="bg-muted py-1 text-foreground text-sm outline outline-muted-foreground">
|
||||||
{t.guida}
|
{t.guida}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
|
||||||
<ComeFunziona />
|
{/* <ComeFunziona /> */}
|
||||||
|
<HowItWorks features={features} />
|
||||||
<FAQSection />
|
<FAQSection />
|
||||||
</main>
|
</main>
|
||||||
</>
|
</>
|
||||||
|
|
@ -51,8 +95,8 @@ const FAQSection = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="px-4 py-12 md:px-6" id="faq">
|
<section className="px-4 py-8 sm:py-12 md:px-6" id="faq">
|
||||||
<div className="mx-auto grid max-w-5xl items-center gap-6 py-12">
|
<div className="mx-auto grid max-w-5xl items-center gap-6">
|
||||||
<div className="flex flex-col justify-center space-y-4">
|
<div className="flex flex-col justify-center space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<h2 className="font-bold text-3xl tracking-tighter md:text-4xl">
|
<h2 className="font-bold text-3xl tracking-tighter md:text-4xl">
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue