Retour au catalogue

Careers Culture

Section culture d'entreprise avec valeurs en cards et photos placeholder en grille asymetrique.

careersmedium Both Responsive a11y
minimalcorporateelegantsaasuniversalagencygrid
Theme
"use client";

import { motion } from "framer-motion";
import { Heart, Users, Sparkles, Target } from "lucide-react";
import type { LucideIcon } from "lucide-react";

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

interface CareersCultureProps {
  title?: string;
  titleAccent?: string;
  description?: string;
  values?: Value[];
  photoColors?: string[];
}

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

const ICON_MAP: Record<string, LucideIcon> = {
  heart: Heart,
  users: Users,
  sparkles: Sparkles,
  target: Target,
};

export default function CareersCulture({
  title = "Notre culture",
  titleAccent = "d'entreprise",
  description = "Ce qui nous rassemble et nous fait avancer chaque jour.",
  values = [],
  photoColors = [],
}: CareersCultureProps) {
  const defaultValues: Value[] = values.length
    ? values
    : [
        { icon: "heart", title: "Bienveillance", description: "Un environnement ou chacun se sent ecoute et respecte." },
        { icon: "sparkles", title: "Innovation", description: "Nous encourageons les idees nouvelles et l'experimentation." },
        { icon: "users", title: "Collaboration", description: "Le travail d'equipe est au coeur de chaque projet." },
        { icon: "target", title: "Impact", description: "Chaque contribution compte et fait avancer notre mission." },
      ];

  const defaultColors = photoColors.length
    ? photoColors
    : ["var(--color-accent-subtle)", "var(--color-background-alt)", "var(--color-accent-subtle)"];

  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)",
        }}
      >
        {/* Header */}
        <div style={{ textAlign: "center", maxWidth: "600px", margin: "0 auto 3rem" }}>
          <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(2rem, 4vw, 3rem)",
              fontWeight: 700,
              lineHeight: 1.1,
              letterSpacing: "-0.02em",
              color: "var(--color-foreground)",
              marginBottom: "1rem",
            }}
          >
            {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.08, ease: EASE }}
            style={{ fontSize: "1.0625rem", lineHeight: 1.7, color: "var(--color-foreground-muted)" }}
          >
            {description}
          </motion.p>
        </div>

        {/* Photo placeholders */}
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ duration: 0.6, delay: 0.12, ease: EASE }}
          style={{
            display: "grid",
            gridTemplateColumns: "2fr 1fr 1fr",
            gap: "1rem",
            marginBottom: "3rem",
            height: 240,
          }}
        >
          {defaultColors.map((color, i) => (
            <div
              key={i}
              style={{
                borderRadius: "var(--radius-lg)",
                background: color,
                border: "1px solid var(--color-border)",
              }}
            />
          ))}
        </motion.div>

        {/* Values grid */}
        <div
          style={{
            display: "grid",
            gridTemplateColumns: "repeat(auto-fill, minmax(240px, 1fr))",
            gap: "1.25rem",
          }}
        >
          {defaultValues.map((val, i) => {
            const Icon = ICON_MAP[val.icon] ?? Heart;
            return (
              <motion.div
                key={val.title}
                initial={{ opacity: 0, y: 16 }}
                animate={{ opacity: 1, y: 0 }}
                transition={{ duration: 0.45, delay: 0.2 + i * 0.06, ease: EASE }}
                style={{
                  padding: "1.5rem",
                  borderRadius: "var(--radius-lg)",
                  border: "1px solid var(--color-border)",
                  background: "var(--color-background-card)",
                }}
              >
                <div
                  style={{
                    width: 40,
                    height: 40,
                    borderRadius: "var(--radius-md)",
                    background: "var(--color-accent-subtle)",
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    marginBottom: "1rem",
                  }}
                >
                  <Icon style={{ width: 20, height: 20, color: "var(--color-accent)" }} />
                </div>
                <h3
                  style={{
                    fontFamily: "var(--font-sans)",
                    fontSize: "1rem",
                    fontWeight: 600,
                    color: "var(--color-foreground)",
                    marginBottom: "0.5rem",
                  }}
                >
                  {val.title}
                </h3>
                <p style={{ fontSize: "0.875rem", lineHeight: 1.6, color: "var(--color-foreground-muted)" }}>
                  {val.description}
                </p>
              </motion.div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

Avis

Careers Culture — React Careers Section — Incubator