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 Head from "next/head";
|
||||
import { ComeFunziona } from "~/components/come_funziona";
|
||||
import HowItWorks from "~/components/how-it-works";
|
||||
import {
|
||||
Accordion,
|
||||
AccordionContent,
|
||||
|
|
@ -16,6 +16,49 @@ import { useTranslation } from "~/providers/I18nProvider";
|
|||
*/
|
||||
const Guida: NextPage = () => {
|
||||
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 (
|
||||
<>
|
||||
|
|
@ -23,12 +66,13 @@ const Guida: NextPage = () => {
|
|||
<title>{t.heads.guida_titolo}</title>
|
||||
<meta content={t.heads.main_description} name="description" />
|
||||
</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">
|
||||
{t.guida}
|
||||
</Badge>
|
||||
|
||||
<ComeFunziona />
|
||||
{/* <ComeFunziona /> */}
|
||||
<HowItWorks features={features} />
|
||||
<FAQSection />
|
||||
</main>
|
||||
</>
|
||||
|
|
@ -51,8 +95,8 @@ const FAQSection = () => {
|
|||
}
|
||||
|
||||
return (
|
||||
<section className="px-4 py-12 md:px-6" id="faq">
|
||||
<div className="mx-auto grid max-w-5xl items-center gap-6 py-12">
|
||||
<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">
|
||||
<div className="flex flex-col justify-center space-y-4">
|
||||
<div className="space-y-2">
|
||||
<h2 className="font-bold text-3xl tracking-tighter md:text-4xl">
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue