Retour au catalogue

Mobile App Features

Features list avec mockup phone a cote, style split layout.

mobile-appmedium Both Responsive a11y
minimalcorporatesaasuniversalsplit
Theme
"use client";

import { motion } from "framer-motion";
import { Zap, Shield, Bell, CloudOff, RefreshCw, Lock } from "lucide-react";
import type { LucideIcon } from "lucide-react";

interface Feature {
  icon: string;
  title: string;
  description: string;
}

interface MobileAppFeaturesProps {
  title?: string;
  titleAccent?: string;
  description?: string;
  features?: Feature[];
  screenColor?: string;
}

const EASE = [0.16, 1, 0.3, 1] as const;

const ICON_MAP: Record<string, LucideIcon> = {
  zap: Zap,
  shield: Shield,
  bell: Bell,
  cloud: CloudOff,
  refresh: RefreshCw,
  lock: Lock,
};

export default function MobileAppFeatures({
  title = "Tout ce dont vous avez besoin",
  titleAccent = "au bout des doigts",
  description = "Des fonctionnalites pensees pour simplifier votre quotidien.",
  features = [],
  screenColor = "var(--color-accent-subtle)",
}: MobileAppFeaturesProps) {
  const defaultFeatures: Feature[] = features.length
    ? features
    : [
        { icon: "zap", title: "Ultra rapide", description: "Temps de chargement inferieur a une seconde." },
        { icon: "shield", title: "Securise", description: "Chiffrement de bout en bout pour vos donnees." },
        { icon: "bell", title: "Notifications", description: "Restez informe en temps reel." },
        { icon: "cloud", title: "Mode hors-ligne", description: "Fonctionne meme sans connexion." },
        { icon: "refresh", title: "Sync automatique", description: "Vos donnees toujours a jour." },
        { icon: "lock", title: "Vie privee", description: "Aucune donnee revendue a des tiers." },
      ];

  return (
    <section
      style={{
        position: "relative",
        overflow: "hidden",
        paddingTop: "var(--section-padding-y-lg)",
        paddingBottom: "var(--section-padding-y-lg)",
        background: "var(--color-background)",
      }}
    >
      <div
        style={{
          width: "100%",
          maxWidth: "var(--container-max-width)",
          margin: "0 auto",
          padding: "0 var(--container-padding-x)",
          display: "grid",
          gridTemplateColumns: "1fr 1fr",
          gap: "4rem",
          alignItems: "center",
        }}
      >
        {/* Phone mockup */}
        <motion.div
          initial={{ opacity: 0, x: -40 }}
          animate={{ opacity: 1, x: 0 }}
          transition={{ duration: 0.7, ease: EASE }}
          style={{ display: "flex", justifyContent: "center" }}
        >
          <div
            style={{
              width: 260,
              height: 520,
              borderRadius: 36,
              border: "3px solid var(--color-border)",
              background: "var(--color-background-card)",
              padding: 10,
              boxShadow: "0 20px 50px rgba(0,0,0,0.12)",
            }}
          >
            <div
              style={{
                width: "100%",
                height: "100%",
                borderRadius: 26,
                background: screenColor,
              }}
            />
          </div>
        </motion.div>

        {/* Features list */}
        <div>
          <motion.h2
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.6, ease: EASE }}
            style={{
              fontFamily: "var(--font-sans)",
              fontSize: "clamp(1.75rem, 3.5vw, 2.75rem)",
              fontWeight: 700,
              lineHeight: 1.15,
              letterSpacing: "-0.02em",
              color: "var(--color-foreground)",
              marginBottom: "0.75rem",
            }}
          >
            {title}{" "}
            <em style={{ fontFamily: "var(--font-serif)", fontStyle: "italic", fontWeight: 400, color: "var(--color-accent)" }}>
              {titleAccent}
            </em>
          </motion.h2>

          <motion.p
            initial={{ opacity: 0, y: 12 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.5, delay: 0.06, ease: EASE }}
            style={{
              fontSize: "1.0625rem",
              lineHeight: 1.7,
              color: "var(--color-foreground-muted)",
              marginBottom: "2rem",
            }}
          >
            {description}
          </motion.p>

          <div style={{ display: "grid", gap: "1.25rem" }}>
            {defaultFeatures.map((feat, i) => {
              const Icon = ICON_MAP[feat.icon] ?? Zap;
              return (
                <motion.div
                  key={feat.title}
                  initial={{ opacity: 0, x: 20 }}
                  animate={{ opacity: 1, x: 0 }}
                  transition={{ duration: 0.45, delay: 0.12 + i * 0.06, ease: EASE }}
                  style={{ display: "flex", gap: "1rem", alignItems: "flex-start" }}
                >
                  <div
                    style={{
                      width: 40,
                      height: 40,
                      borderRadius: "var(--radius-md)",
                      background: "var(--color-accent-subtle)",
                      display: "flex",
                      alignItems: "center",
                      justifyContent: "center",
                      flexShrink: 0,
                    }}
                  >
                    <Icon style={{ width: 20, height: 20, color: "var(--color-accent)" }} />
                  </div>
                  <div>
                    <h3
                      style={{
                        fontFamily: "var(--font-sans)",
                        fontSize: "0.9375rem",
                        fontWeight: 600,
                        color: "var(--color-foreground)",
                        marginBottom: "0.25rem",
                      }}
                    >
                      {feat.title}
                    </h3>
                    <p style={{ fontSize: "0.875rem", lineHeight: 1.6, color: "var(--color-foreground-muted)" }}>
                      {feat.description}
                    </p>
                  </div>
                </motion.div>
              );
            })}
          </div>
        </div>
      </div>
    </section>
  );
}

Avis

Mobile App Features — React Mobile-app Section — Incubator