diff options
Diffstat (limited to 'src/app')
| -rw-r--r-- | src/app/(payload)/admin/[[...segments]]/not-found.tsx | 23 | ||||
| -rw-r--r-- | src/app/(payload)/admin/[[...segments]]/page.tsx | 23 | ||||
| -rw-r--r-- | src/app/(payload)/admin/importMap.js | 3 | ||||
| -rw-r--r-- | src/app/(payload)/api/[...slug]/route.ts | 19 | ||||
| -rw-r--r-- | src/app/(payload)/custom.scss | 1 | ||||
| -rw-r--r-- | src/app/(payload)/layout.tsx | 31 | ||||
| -rw-r--r-- | src/app/(public)/about/page.tsx | 153 | ||||
| -rw-r--r-- | src/app/(public)/articles/page.tsx | 38 | ||||
| -rw-r--r-- | src/app/(public)/demos/page.tsx | 94 | ||||
| -rw-r--r-- | src/app/(public)/layout.tsx | 16 | ||||
| -rw-r--r-- | src/app/(public)/page.tsx | 174 | ||||
| -rw-r--r-- | src/app/(public)/services/page.tsx | 148 | ||||
| -rw-r--r-- | src/app/globals.css | 102 | ||||
| -rw-r--r-- | src/app/layout.tsx | 31 |
14 files changed, 856 insertions, 0 deletions
diff --git a/src/app/(payload)/admin/[[...segments]]/not-found.tsx b/src/app/(payload)/admin/[[...segments]]/not-found.tsx new file mode 100644 index 0000000..62ffef8 --- /dev/null +++ b/src/app/(payload)/admin/[[...segments]]/not-found.tsx @@ -0,0 +1,23 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import type { Metadata } from "next"; + +import config from "@payload-config"; +import { NotFoundPage, generatePageMetadata } from "@payloadcms/next/views"; +import { importMap } from "../importMap"; + +type Args = { + params: Promise<{ segments: string[] }>; + searchParams: Promise<{ [key: string]: string | string[] }>; +}; + +export const generateMetadata = ({ + params, + searchParams, +}: Args): Promise<Metadata> => + generatePageMetadata({ config, params, searchParams }); + +const NotFound = ({ params, searchParams }: Args) => + NotFoundPage({ config, importMap, params, searchParams }); + +export default NotFound; diff --git a/src/app/(payload)/admin/[[...segments]]/page.tsx b/src/app/(payload)/admin/[[...segments]]/page.tsx new file mode 100644 index 0000000..3132b87 --- /dev/null +++ b/src/app/(payload)/admin/[[...segments]]/page.tsx @@ -0,0 +1,23 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import type { Metadata } from "next"; + +import config from "@payload-config"; +import { RootPage, generatePageMetadata } from "@payloadcms/next/views"; +import { importMap } from "../importMap"; + +type Args = { + params: Promise<{ segments: string[] }>; + searchParams: Promise<{ [key: string]: string | string[] }>; +}; + +export const generateMetadata = ({ + params, + searchParams, +}: Args): Promise<Metadata> => + generatePageMetadata({ config, params, searchParams }); + +const Page = ({ params, searchParams }: Args) => + RootPage({ config, params, searchParams, importMap }); + +export default Page; diff --git a/src/app/(payload)/admin/importMap.js b/src/app/(payload)/admin/importMap.js new file mode 100644 index 0000000..6b29107 --- /dev/null +++ b/src/app/(payload)/admin/importMap.js @@ -0,0 +1,3 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +export const importMap = {}; diff --git a/src/app/(payload)/api/[...slug]/route.ts b/src/app/(payload)/api/[...slug]/route.ts new file mode 100644 index 0000000..dc8ba37 --- /dev/null +++ b/src/app/(payload)/api/[...slug]/route.ts @@ -0,0 +1,19 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import config from "@payload-config"; +import "@payloadcms/next/css"; +import { + REST_DELETE, + REST_GET, + REST_OPTIONS, + REST_PATCH, + REST_POST, + REST_PUT, +} from "@payloadcms/next/routes"; + +export const GET = REST_GET(config); +export const POST = REST_POST(config); +export const DELETE = REST_DELETE(config); +export const PATCH = REST_PATCH(config); +export const PUT = REST_PUT(config); +export const OPTIONS = REST_OPTIONS(config); diff --git a/src/app/(payload)/custom.scss b/src/app/(payload)/custom.scss new file mode 100644 index 0000000..a8d95bd --- /dev/null +++ b/src/app/(payload)/custom.scss @@ -0,0 +1 @@ +/* Custom styles for the Payload admin panel - can be extended later */ diff --git a/src/app/(payload)/layout.tsx b/src/app/(payload)/layout.tsx new file mode 100644 index 0000000..3c6b6e4 --- /dev/null +++ b/src/app/(payload)/layout.tsx @@ -0,0 +1,31 @@ +/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */ +/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */ +import config from "@payload-config"; +import "@payloadcms/next/css"; +import type { ServerFunctionClient } from "payload"; +import { handleServerFunctions, RootLayout } from "@payloadcms/next/layouts"; +import React from "react"; + +import { importMap } from "./admin/importMap.js"; +import "./custom.scss"; + +type Args = { + children: React.ReactNode; +}; + +const serverFunction: ServerFunctionClient = async function (args) { + "use server"; + return handleServerFunctions({ + ...args, + config, + importMap, + }); +}; + +const Layout = ({ children }: Args) => ( + <RootLayout config={config} importMap={importMap} serverFunction={serverFunction}> + {children} + </RootLayout> +); + +export default Layout; diff --git a/src/app/(public)/about/page.tsx b/src/app/(public)/about/page.tsx new file mode 100644 index 0000000..7e76cbe --- /dev/null +++ b/src/app/(public)/about/page.tsx @@ -0,0 +1,153 @@ +import { Code, Server, Shield, Award } from "lucide-react"; + +const timeline = [ + { + icon: Code, + period: "Début de carrière", + title: "Développeur", + description: + "Développement logiciel, compréhension profonde du code et des architectures applicatives. Base solide pour comprendre les enjeux de sécurité au niveau applicatif.", + }, + { + icon: Server, + period: "Évolution", + title: "Administrateur Systèmes", + description: + "Administration Linux et Windows Server. Gestion d'infrastructures, scripting, automatisation. Vision complète de la chaîne technique.", + }, + { + icon: Shield, + period: "Spécialisation", + title: "Expert IAM & Sécurité", + description: + "Spécialisation en Identity & Access Management. Administration AD et Entra ID, implémentation OIDC/OAuth, stratégies Zero Trust.", + }, +]; + +const skills = { + "Identity & Access Management": [ + "OIDC / OAuth 2.0 / SAML", + "Keycloak", + "Active Directory", + "Microsoft Entra ID (Azure AD)", + "PIM / PAM", + "RBAC / ABAC", + "Conditional Access", + "SSO / Federation", + ], + "Sécurité": [ + "Zero Trust Architecture", + "Durcissement AD (Tiering Model)", + "Sécurité des endpoints", + "PKI & Certificats", + "Audit de sécurité", + "Conformité & Gouvernance", + ], + "Systèmes & Infra": [ + "Windows Server / AD DS", + "Linux (Debian, RHEL, Ubuntu)", + "Docker & Conteneurisation", + "PowerShell / Bash", + "Automatisation & CI/CD", + "Monitoring & Logging", + ], +}; + +export default function AboutPage() { + return ( + <> + <section className="bg-cosmos-900 py-16 sm:py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-2xl text-center"> + <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl"> + À propos + </h1> + <p className="mt-6 text-lg text-cosmos-300"> + Un parcours du développement à la sécurité, pour une vision + complète et pragmatique de l'IAM. + </p> + </div> + </div> + </section> + + {/* Timeline */} + <section className="py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <h2 className="text-2xl font-bold text-cosmos-900 text-center mb-16"> + Parcours professionnel + </h2> + <div className="relative"> + <div className="absolute left-1/2 -translate-x-px h-full w-0.5 bg-border hidden lg:block" /> + <div className="space-y-12 lg:space-y-16"> + {timeline.map((item, index) => { + const Icon = item.icon; + const isLeft = index % 2 === 0; + return ( + <div + key={item.title} + className={`relative flex flex-col lg:flex-row items-center gap-8 ${ + isLeft ? "lg:flex-row" : "lg:flex-row-reverse" + }`} + > + <div + className={`flex-1 ${isLeft ? "lg:text-right" : "lg:text-left"}`} + > + <p className="text-sm font-semibold text-araucaria-600 uppercase tracking-wider"> + {item.period} + </p> + <h3 className="mt-2 text-xl font-bold text-cosmos-900"> + {item.title} + </h3> + <p className="mt-3 text-muted leading-relaxed"> + {item.description} + </p> + </div> + <div className="relative z-10 w-14 h-14 rounded-full bg-cosmos-900 flex items-center justify-center border-4 border-nieve shadow-lg shrink-0"> + <Icon className="w-6 h-6 text-araucaria-400" /> + </div> + <div className="flex-1 hidden lg:block" /> + </div> + ); + })} + </div> + </div> + </div> + </section> + + {/* Compétences */} + <section className="py-20 bg-pewma border-t border-border"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <h2 className="text-2xl font-bold text-cosmos-900 text-center mb-16"> + Compétences techniques + </h2> + <div className="grid grid-cols-1 md:grid-cols-3 gap-8"> + {Object.entries(skills).map(([category, items]) => ( + <div + key={category} + className="rounded-xl border border-border bg-nieve p-8" + > + <div className="flex items-center gap-3 mb-6"> + <Award className="w-5 h-5 text-kultrun-700" /> + <h3 className="text-lg font-semibold text-cosmos-900"> + {category} + </h3> + </div> + <ul className="space-y-2"> + {items.map((skill) => ( + <li + key={skill} + className="text-sm text-muted flex items-center gap-2" + > + <span className="w-1.5 h-1.5 rounded-full bg-araucaria-500 shrink-0" /> + {skill} + </li> + ))} + </ul> + </div> + ))} + </div> + </div> + </section> + </> + ); +} diff --git a/src/app/(public)/articles/page.tsx b/src/app/(public)/articles/page.tsx new file mode 100644 index 0000000..5dd7a01 --- /dev/null +++ b/src/app/(public)/articles/page.tsx @@ -0,0 +1,38 @@ +import { FileText } from "lucide-react"; + +export default function ArticlesPage() { + return ( + <> + <section className="bg-cosmos-900 py-16 sm:py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-2xl text-center"> + <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl"> + Articles & Guides + </h1> + <p className="mt-6 text-lg text-cosmos-300"> + Concepts de sécurité, guides d'implémentation OIDC/OAuth, + best practices Zero Trust. + </p> + </div> + </div> + </section> + + <section className="py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-2xl text-center"> + <div className="w-16 h-16 mx-auto rounded-2xl bg-pewma flex items-center justify-center mb-6"> + <FileText className="w-8 h-8 text-cosmos-500" /> + </div> + <h2 className="text-xl font-semibold text-cosmos-900"> + Articles à venir + </h2> + <p className="mt-4 text-muted"> + Les premiers articles techniques sur OIDC, OAuth2 et le Zero Trust + sont en cours de rédaction. Revenez bientôt ! + </p> + </div> + </div> + </section> + </> + ); +} diff --git a/src/app/(public)/demos/page.tsx b/src/app/(public)/demos/page.tsx new file mode 100644 index 0000000..7afee2a --- /dev/null +++ b/src/app/(public)/demos/page.tsx @@ -0,0 +1,94 @@ +import Link from "next/link"; +import { Workflow, Terminal, KeyRound, ShieldCheck } from "lucide-react"; + +const demos = [ + { + icon: Workflow, + title: "Visualiseur OIDC", + description: + "Animation pas-à-pas des flux OIDC : Authorization Code, PKCE, Client Credentials. Comprenez chaque échange entre le client, l'IdP et le resource server.", + href: "/demos/oidc-flow", + status: "Bientôt disponible", + }, + { + icon: Terminal, + title: "Playground OAuth2", + description: + "Testez interactivement les requêtes OAuth2. Explorez les scopes, tokens, refresh tokens. Connecté à un vrai serveur Keycloak.", + href: "/demos/oauth-playground", + status: "Bientôt disponible", + }, + { + icon: KeyRound, + title: "Décodeur JWT", + description: + "Décodez et inspectez vos tokens JWT en temps réel. Visualisez le header, le payload et validez la signature.", + href: "/demos/token-decoder", + status: "Bientôt disponible", + }, + { + icon: ShieldCheck, + title: "Simulateur Zero Trust", + description: + "Visualisation interactive des couches de sécurité Zero Trust. Explorez les différentes stratégies d'implémentation.", + href: "/demos/zero-trust", + status: "Bientôt disponible", + }, +]; + +export default function DemosPage() { + return ( + <> + <section className="bg-cosmos-900 py-16 sm:py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-2xl text-center"> + <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl"> + Démos interactives + </h1> + <p className="mt-6 text-lg text-cosmos-300"> + Explorez les concepts de sécurité et d'IAM à travers des + outils interactifs. Apprenez en pratiquant. + </p> + </div> + </div> + </section> + + <section className="py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="grid grid-cols-1 md:grid-cols-2 gap-8"> + {demos.map((demo) => { + const Icon = demo.icon; + return ( + <div + key={demo.title} + className="group relative rounded-xl border border-border bg-nieve p-8 hover:border-cosmos-300 hover:shadow-lg transition-all duration-300" + > + <div className="flex items-start justify-between mb-6"> + <div className="w-12 h-12 rounded-lg bg-cosmos-900 flex items-center justify-center"> + <Icon className="w-6 h-6 text-araucaria-400" /> + </div> + <span className="px-3 py-1 text-xs font-medium bg-araucaria-50 text-araucaria-700 rounded-full border border-araucaria-200"> + {demo.status} + </span> + </div> + <h3 className="text-xl font-semibold text-cosmos-900"> + {demo.title} + </h3> + <p className="mt-3 text-sm text-muted leading-relaxed"> + {demo.description} + </p> + <Link + href={demo.href} + className="mt-6 inline-flex items-center text-sm font-semibold text-cosmos-700 hover:text-kultrun-700 transition-colors" + > + Explorer la démo → + </Link> + </div> + ); + })} + </div> + </div> + </section> + </> + ); +} diff --git a/src/app/(public)/layout.tsx b/src/app/(public)/layout.tsx new file mode 100644 index 0000000..5b71246 --- /dev/null +++ b/src/app/(public)/layout.tsx @@ -0,0 +1,16 @@ +import { Header } from "@/components/layout/Header"; +import { Footer } from "@/components/layout/Footer"; + +export default function PublicLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + <> + <Header /> + <main className="min-h-[calc(100vh-4rem)]">{children}</main> + <Footer /> + </> + ); +} diff --git a/src/app/(public)/page.tsx b/src/app/(public)/page.tsx new file mode 100644 index 0000000..36ecee7 --- /dev/null +++ b/src/app/(public)/page.tsx @@ -0,0 +1,174 @@ +import Link from "next/link"; +import { + Shield, + Key, + Lock, + Network, + Server, + ArrowRight, + CheckCircle, +} from "lucide-react"; + +const expertises = [ + { + icon: Key, + title: "OIDC & OAuth2", + description: + "Intégration et sécurisation des flux d'authentification. Authorization Code, PKCE, Client Credentials.", + }, + { + icon: Shield, + title: "Zero Trust", + description: + "Architecture Zero Trust de bout en bout. Never trust, always verify. Micro-segmentation et contrôle d'accès continu.", + }, + { + icon: Lock, + title: "Active Directory & Entra ID", + description: + "Administration, durcissement et migration AD. Configuration Entra ID, Conditional Access, PIM.", + }, + { + icon: Network, + title: "IAM & Gouvernance", + description: + "Stratégie IAM complète. Gestion des identités, provisioning, RBAC/ABAC, audit et conformité.", + }, + { + icon: Server, + title: "Infrastructure & DevSecOps", + description: + "Sécurisation Linux & Windows. Automatisation, durcissement, monitoring sécurité.", + }, +]; + +const highlights = [ + "Expert senior avec expérience en développement, systèmes et sécurité", + "Maîtrise des environnements Open Source et Windows", + "Approche pragmatique orientée résultats", + "Accompagnement de la stratégie à l'implémentation", +]; + +export default function HomePage() { + return ( + <> + {/* Hero */} + <section className="relative overflow-hidden bg-cosmos-900 py-24 sm:py-32"> + <div className="absolute inset-0 opacity-10"> + <div + className="absolute inset-0" + style={{ + backgroundImage: `radial-gradient(circle at 25% 25%, var(--color-araucaria-500) 1px, transparent 1px), + radial-gradient(circle at 75% 75%, var(--color-kultrun-700) 1px, transparent 1px)`, + backgroundSize: "60px 60px", + }} + /> + </div> + <div className="relative mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-3xl text-center"> + <p className="text-sm font-semibold text-araucaria-400 uppercase tracking-widest"> + Consulting IAM & Sécurité + </p> + <h1 className="mt-4 text-4xl font-bold tracking-tight text-nieve sm:text-6xl"> + Sécurisez vos identités, + <br /> + <span className="text-araucaria-400">protégez vos accès</span> + </h1> + <p className="mt-6 text-lg leading-8 text-cosmos-300"> + Expert senior en Identity & Access Management. J'accompagne + les organisations dans leur stratégie de sécurité des identités, + de l'audit à l'implémentation. + </p> + <div className="mt-10 flex items-center justify-center gap-4 flex-wrap"> + <Link + href="/services" + className="inline-flex items-center gap-2 rounded-lg bg-kultrun-700 px-6 py-3 text-sm font-semibold text-nieve hover:bg-kultrun-600 transition-colors" + > + Mes services + <ArrowRight className="w-4 h-4" /> + </Link> + <Link + href="/demos" + className="inline-flex items-center gap-2 rounded-lg border border-cosmos-600 px-6 py-3 text-sm font-semibold text-cosmos-200 hover:bg-cosmos-800 hover:text-nieve transition-colors" + > + Voir les démos + </Link> + </div> + </div> + </div> + </section> + + {/* Highlights */} + <section className="py-12 bg-pewma border-b border-border"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6"> + {highlights.map((text) => ( + <div key={text} className="flex items-start gap-3"> + <CheckCircle className="w-5 h-5 text-ngunechen-700 mt-0.5 shrink-0" /> + <p className="text-sm text-tierra-700 font-medium">{text}</p> + </div> + ))} + </div> + </div> + </section> + + {/* Expertises */} + <section className="py-20 sm:py-28"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-2xl text-center"> + <h2 className="text-3xl font-bold tracking-tight text-cosmos-900 sm:text-4xl"> + Domaines d'expertise + </h2> + <p className="mt-4 text-lg text-muted"> + Une expertise transversale, du développement à + l'infrastructure, centrée sur la sécurité des identités. + </p> + </div> + + <div className="mx-auto mt-16 grid grid-cols-1 gap-8 sm:grid-cols-2 lg:grid-cols-3"> + {expertises.map((item) => { + const Icon = item.icon; + return ( + <div + key={item.title} + className="group relative rounded-xl border border-border bg-nieve p-8 hover:border-cosmos-300 hover:shadow-lg transition-all duration-300" + > + <div className="w-12 h-12 rounded-lg bg-cosmos-900 flex items-center justify-center group-hover:bg-cosmos-800 transition-colors"> + <Icon className="w-6 h-6 text-araucaria-400" /> + </div> + <h3 className="mt-6 text-lg font-semibold text-cosmos-900"> + {item.title} + </h3> + <p className="mt-2 text-sm text-muted leading-relaxed"> + {item.description} + </p> + </div> + ); + })} + </div> + </div> + </section> + + {/* CTA */} + <section className="bg-cosmos-900 py-16"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-2xl text-center"> + <h2 className="text-2xl font-bold text-nieve sm:text-3xl"> + Un projet de sécurisation ? + </h2> + <p className="mt-4 text-cosmos-300"> + Discutons de vos besoins en IAM et sécurité informatique. + </p> + <Link + href="/contact" + className="mt-8 inline-flex items-center gap-2 rounded-lg bg-araucaria-500 px-8 py-3 text-sm font-semibold text-cosmos-950 hover:bg-araucaria-400 transition-colors" + > + Prendre contact + <ArrowRight className="w-4 h-4" /> + </Link> + </div> + </div> + </section> + </> + ); +} diff --git a/src/app/(public)/services/page.tsx b/src/app/(public)/services/page.tsx new file mode 100644 index 0000000..424e939 --- /dev/null +++ b/src/app/(public)/services/page.tsx @@ -0,0 +1,148 @@ +import { + Search, + Key, + ShieldCheck, + Server, + ArrowRight, +} from "lucide-react"; +import Link from "next/link"; + +const services = [ + { + id: "audit", + icon: Search, + title: "Audit IAM & Sécurité", + description: + "Évaluation complète de votre posture de sécurité des identités. Analyse des configurations AD, Entra ID, politiques d'accès, et recommandations priorisées.", + deliverables: [ + "Rapport d'audit détaillé", + "Matrice de risques priorisée", + "Plan de remédiation", + ], + }, + { + id: "oidc", + icon: Key, + title: "Intégration OIDC / OAuth2", + description: + "Conception et implémentation de flux d'authentification modernes. Intégration d'applications existantes avec OIDC, migration depuis SAML, mise en place de SSO.", + deliverables: [ + "Architecture d'authentification", + "Implémentation et tests", + "Documentation technique", + ], + }, + { + id: "zero-trust", + icon: ShieldCheck, + title: "Stratégie Zero Trust", + description: + "Définition et déploiement d'une architecture Zero Trust adaptée à votre contexte. Conditional Access, micro-segmentation, vérification continue.", + deliverables: [ + "Feuille de route Zero Trust", + "Configuration Conditional Access", + "Formation des équipes", + ], + }, + { + id: "ad-entra", + icon: Server, + title: "AD & Entra ID", + description: + "Administration avancée, durcissement et migration Active Directory. Configuration Entra ID, synchronisation hybride, PIM/PAM.", + deliverables: [ + "Durcissement AD (tiering model)", + "Configuration Entra ID", + "Migration et synchronisation", + ], + }, +]; + +export default function ServicesPage() { + return ( + <> + <section className="bg-cosmos-900 py-16 sm:py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="mx-auto max-w-2xl text-center"> + <h1 className="text-3xl font-bold tracking-tight text-nieve sm:text-5xl"> + Services de consulting + </h1> + <p className="mt-6 text-lg text-cosmos-300"> + Des mandats ciblés pour sécuriser vos identités et vos accès, + de l'audit stratégique à l'implémentation technique. + </p> + </div> + </div> + </section> + + <section className="py-20"> + <div className="mx-auto max-w-7xl px-6 lg:px-8"> + <div className="space-y-16"> + {services.map((service, index) => { + const Icon = service.icon; + const isEven = index % 2 === 0; + return ( + <div + key={service.id} + id={service.id} + className={`flex flex-col lg:flex-row gap-8 lg:gap-16 items-start ${ + isEven ? "" : "lg:flex-row-reverse" + }`} + > + <div className="flex-1"> + <div className="flex items-center gap-4 mb-4"> + <div className="w-12 h-12 rounded-lg bg-cosmos-900 flex items-center justify-center"> + <Icon className="w-6 h-6 text-araucaria-400" /> + </div> + <h2 className="text-2xl font-bold text-cosmos-900"> + {service.title} + </h2> + </div> + <p className="text-muted leading-relaxed"> + {service.description} + </p> + </div> + <div className="flex-1 w-full lg:max-w-sm"> + <div className="rounded-xl border border-border bg-pewma p-6"> + <h3 className="text-sm font-semibold text-cosmos-700 uppercase tracking-wider mb-4"> + Livrables + </h3> + <ul className="space-y-3"> + {service.deliverables.map((item) => ( + <li + key={item} + className="flex items-start gap-3 text-sm text-tierra-700" + > + <ArrowRight className="w-4 h-4 text-kultrun-700 mt-0.5 shrink-0" /> + {item} + </li> + ))} + </ul> + </div> + </div> + </div> + ); + })} + </div> + </div> + </section> + + <section className="bg-pewma py-16 border-t border-border"> + <div className="mx-auto max-w-7xl px-6 lg:px-8 text-center"> + <h2 className="text-2xl font-bold text-cosmos-900"> + Besoin d'un mandat sur mesure ? + </h2> + <p className="mt-4 text-muted"> + Chaque organisation est unique. Discutons de vos besoins spécifiques. + </p> + <Link + href="/contact" + className="mt-8 inline-flex items-center gap-2 rounded-lg bg-kultrun-700 px-8 py-3 text-sm font-semibold text-nieve hover:bg-kultrun-600 transition-colors" + > + Discuter de mon projet + </Link> + </div> + </section> + </> + ); +} diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 0000000..9fa0a21 --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,102 @@ +@import "tailwindcss"; + +@theme { + /* === Palette Mapuche Corporate === */ + + /* Primary - Cosmos (bleu-nuit profond) */ + --color-cosmos-50: #e8ecf3; + --color-cosmos-100: #c5cfe0; + --color-cosmos-200: #9fafc9; + --color-cosmos-300: #7990b2; + --color-cosmos-400: #5c79a1; + --color-cosmos-500: #3f6290; + --color-cosmos-600: #355585; + --color-cosmos-700: #294576; + --color-cosmos-800: #1f3664; + --color-cosmos-900: #1b2a4a; + --color-cosmos-950: #0f1829; + + /* Accent - Kultrun Red */ + --color-kultrun-50: #fce8e8; + --color-kultrun-100: #f8c5c6; + --color-kultrun-200: #f09ea0; + --color-kultrun-300: #e8777a; + --color-kultrun-400: #e1595d; + --color-kultrun-500: #d93c40; + --color-kultrun-600: #c4343a; + --color-kultrun-700: #b8282e; + --color-kultrun-800: #9a2026; + --color-kultrun-900: #7a181d; + --color-kultrun-950: #4a0e11; + + /* Secondary - Araucaria Gold */ + --color-araucaria-50: #fbf5e6; + --color-araucaria-100: #f5e6c0; + --color-araucaria-200: #eed596; + --color-araucaria-300: #e7c46c; + --color-araucaria-400: #e1b84d; + --color-araucaria-500: #d4a843; + --color-araucaria-600: #c99a30; + --color-araucaria-700: #b28527; + --color-araucaria-800: #9a6f1f; + --color-araucaria-900: #7a5616; + --color-araucaria-950: #4a340d; + + /* Earth - Tierra */ + --color-tierra-50: #f3ede8; + --color-tierra-100: #e0d3c8; + --color-tierra-200: #ccb7a5; + --color-tierra-300: #b79b82; + --color-tierra-400: #a78568; + --color-tierra-500: #97704f; + --color-tierra-600: #886347; + --color-tierra-700: #6b4c3b; + --color-tierra-800: #573d30; + --color-tierra-900: #3e2b22; + --color-tierra-950: #241913; + + /* Success - Ngünechen Green */ + --color-ngunechen-50: #e8f2eb; + --color-ngunechen-100: #c5dece; + --color-ngunechen-200: #9ec9ae; + --color-ngunechen-300: #77b38e; + --color-ngunechen-400: #5aa375; + --color-ngunechen-500: #3d935c; + --color-ngunechen-600: #358352; + --color-ngunechen-700: #2d5a3d; + --color-ngunechen-800: #244a32; + --color-ngunechen-900: #1a3624; + --color-ngunechen-950: #0f2015; + + /* Semantic surface colors */ + --color-nieve: #faf7f2; + --color-pewma: #ede8df; + --color-border: #d4cfc6; + --color-muted: #7a746b; + --color-text: #1a1614; + + /* Font families */ + --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif; + --font-mono: "JetBrains Mono", ui-monospace, monospace; + + /* Border radius */ + --radius-sm: 0.375rem; + --radius-md: 0.5rem; + --radius-lg: 0.75rem; + --radius-xl: 1rem; +} + +@layer base { + body { + background-color: var(--color-nieve); + color: var(--color-text); + font-family: var(--font-sans); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + + ::selection { + background-color: var(--color-cosmos-900); + color: var(--color-nieve); + } +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000..857dbf9 --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,31 @@ +import type { Metadata } from "next"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "Der-topogo | Consulting IAM & Sécurité", + description: + "Expert senior en Identity & Access Management, sécurité informatique, OIDC/OAuth, Zero Trust. Active Directory, Microsoft Entra ID, Open Source.", + keywords: [ + "IAM", + "sécurité informatique", + "OIDC", + "OAuth", + "Zero Trust", + "Active Directory", + "Entra ID", + "consulting", + "cybersécurité", + ], +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + <html lang="fr"> + <body>{children}</body> + </html> + ); +} |
