Retour au catalogue

Careers Day In Life

Timeline 'Une journee type' montrant l'emploi du temps quotidien d'un employe.

careersmedium Both Responsive a11y
playfulelegantsaasuniversalagencystacked
Theme
"use client";

import { motion } from "framer-motion";
import { Coffee, Focus, PenTool, Utensils, Users, GitMerge, BookOpen } from "lucide-react";
import type { LucideIcon } from "lucide-react";

interface ScheduleItem {
  time: string;
  title: string;
  description: string;
  icon: string;
}

interface Persona {
  name: string;
  role: string;
  avatar: string;
}

interface CareersDayInLifeProps {
  title?: string;
  subtitle?: string;
  persona?: Persona;
  schedule?: ScheduleItem[];
}

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

const ICON_MAP: Record<string, LucideIcon> = {
  coffee: Coffee,
  focus: Focus,
  "pen-tool": PenTool,
  utensils: Utensils,
  users: Users,
  "git-merge": GitMerge,
  book: BookOpen,
};

export default function CareersDayInLife({
  title = "Une journee chez nous",
  subtitle = "Decouvrez le quotidien d'un membre de l'equipe.",
  persona,
  schedule = [],
}: CareersDayInLifeProps) {
  return (
    <section style={{ paddingTop: "var(--section-padding-y-lg)", paddingBottom: "var(--section-padding-y-lg)", background: "var(--color-background)" }}>
      <div style={{ maxWidth: 720, margin: "0 auto", padding: "0 var(--container-padding-x)" }}>
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          whileInView={{ opacity: 1, y: 0 }}
          viewport={{ once: true }}
          transition={{ duration: 0.6, ease: EASE }}
          style={{ textAlign: "center", marginBottom: "2rem" }}
        >
          <h2 style={{ fontFamily: "var(--font-sans)", fontSize: "clamp(1.75rem, 3vw, 2.5rem)", fontWeight: 700, color: "var(--color-foreground)", marginBottom: "0.5rem" }}>{title}</h2>
          <p style={{ fontSize: "1.0625rem", color: "var(--color-foreground-muted)", lineHeight: 1.7 }}>{subtitle}</p>
        </motion.div>

        {persona && (
          <motion.div
            initial={{ opacity: 0, y: 12 }}
            whileInView={{ opacity: 1, y: 0 }}
            viewport={{ once: true }}
            transition={{ duration: 0.5, delay: 0.05, ease: EASE }}
            style={{ display: "flex", alignItems: "center", gap: "0.75rem", justifyContent: "center", marginBottom: "2.5rem" }}
          >
            <div style={{ width: 44, height: 44, borderRadius: "var(--radius-full)", background: "var(--color-accent-subtle)", overflow: "hidden" }}>
              <img src={persona.avatar} alt="" style={{ width: "100%", height: "100%", objectFit: "cover" }} />
            </div>
            <div>
              <p style={{ fontSize: "0.9375rem", fontWeight: 600, color: "var(--color-foreground)" }}>{persona.name}</p>
              <p style={{ fontSize: "0.8125rem", color: "var(--color-foreground-muted)" }}>{persona.role}</p>
            </div>
          </motion.div>
        )}

        <div style={{ position: "relative" }}>
          {/* Timeline line */}
          <div aria-hidden style={{ position: "absolute", left: 56, top: 0, bottom: 0, width: 2, background: "var(--color-border)" }} />

          {schedule.map((item, i) => {
            const Icon = ICON_MAP[item.icon] ?? Coffee;
            return (
              <motion.div
                key={item.time}
                initial={{ opacity: 0, x: -12 }}
                whileInView={{ opacity: 1, x: 0 }}
                viewport={{ once: true, margin: "-30px" }}
                transition={{ duration: 0.45, delay: i * 0.06, ease: EASE }}
                style={{ display: "flex", gap: "1.25rem", marginBottom: "1.5rem", position: "relative" }}
              >
                {/* Time */}
                <div style={{ width: 44, textAlign: "right", flexShrink: 0, paddingTop: "0.75rem" }}>
                  <span style={{ fontSize: "0.8125rem", fontWeight: 700, fontFamily: "var(--font-sans)", color: "var(--color-foreground)" }}>{item.time}</span>
                </div>

                {/* Dot */}
                <div style={{ width: 24, display: "flex", justifyContent: "center", paddingTop: "0.85rem", flexShrink: 0 }}>
                  <div style={{ width: 12, height: 12, borderRadius: "var(--radius-full)", background: "var(--color-accent)", border: "3px solid var(--color-background)", zIndex: 1 }} />
                </div>

                {/* Card */}
                <div style={{ flex: 1, padding: "1rem 1.25rem", borderRadius: "var(--radius-lg)", border: "1px solid var(--color-border)", background: "var(--color-background-card)" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: "0.5rem", marginBottom: "0.35rem" }}>
                    <Icon style={{ width: 15, height: 15, color: "var(--color-accent)" }} />
                    <h3 style={{ fontFamily: "var(--font-sans)", fontSize: "0.9375rem", fontWeight: 600, color: "var(--color-foreground)" }}>{item.title}</h3>
                  </div>
                  <p style={{ fontSize: "0.8125rem", lineHeight: 1.6, color: "var(--color-foreground-muted)" }}>{item.description}</p>
                </div>
              </motion.div>
            );
          })}
        </div>
      </div>
    </section>
  );
}

Avis

Careers Day In Life — React Careers Section — Incubator