feat(marketing): intègre pipeline 4 étapes + réseau hub d'intégrations depuis dictia.ca/solutions/dictai
- Pipeline (entre Solution & Bento) : Upload → GPU WhisperX → IA Mistral → Export Auto-advance Alpine 2400ms, sweep ring SVG CSS, dot glow, prefers-reduced-motion - Hub (entre Bento & Pricing) : DictIA → 3 hubs → 9 outils SVG natif <animateMotion> sur bezier paths, zéro lib JS, fallback liste 3-col WCAG - Texte 100% canonique extrait de Website-Sanity dictai-pipeline.tsx + dictai-hub.tsx - OQLF NBSP : "1 heure d'audio → 2 minutes", "5 000+ apps", "100 % en local" - WCAG : aria-labelledby sections, role=tab/list, focus-visible, prefers-reduced-motion - +397 lignes, npm run build:css exécuté pour utilities cyan/purple/opacity Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,7 @@
|
||||
--color-teal-400: oklch(77.7% 0.152 181.912);
|
||||
--color-teal-500: oklch(70.4% 0.14 182.503);
|
||||
--color-teal-600: oklch(60% 0.118 184.704);
|
||||
--color-cyan-300: oklch(86.5% 0.127 207.078);
|
||||
--color-blue-50: oklch(97% 0.014 254.604);
|
||||
--color-blue-100: oklch(93.2% 0.032 255.585);
|
||||
--color-blue-200: oklch(88.2% 0.059 254.128);
|
||||
@@ -137,6 +138,7 @@
|
||||
--radius-md: 0.375rem;
|
||||
--radius-lg: 0.5rem;
|
||||
--radius-xl: 0.75rem;
|
||||
--ease-in: cubic-bezier(0.4, 0, 1, 1);
|
||||
--ease-out: cubic-bezier(0, 0, 0.2, 1);
|
||||
--ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
|
||||
--animate-spin: spin 1s linear infinite;
|
||||
@@ -378,6 +380,9 @@
|
||||
.-top-1 {
|
||||
top: calc(var(--spacing) * -1);
|
||||
}
|
||||
.-top-1\.5 {
|
||||
top: calc(var(--spacing) * -1.5);
|
||||
}
|
||||
.-top-3 {
|
||||
top: calc(var(--spacing) * -3);
|
||||
}
|
||||
@@ -423,6 +428,9 @@
|
||||
.top-full {
|
||||
top: 100%;
|
||||
}
|
||||
.-right-1\.5 {
|
||||
right: calc(var(--spacing) * -1.5);
|
||||
}
|
||||
.-right-6 {
|
||||
right: calc(var(--spacing) * -6);
|
||||
}
|
||||
@@ -654,6 +662,9 @@
|
||||
.-mb-px {
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
.mb-0\.5 {
|
||||
margin-bottom: calc(var(--spacing) * 0.5);
|
||||
}
|
||||
.mb-1 {
|
||||
margin-bottom: calc(var(--spacing) * 1);
|
||||
}
|
||||
@@ -810,9 +821,18 @@
|
||||
.h-72 {
|
||||
height: calc(var(--spacing) * 72);
|
||||
}
|
||||
.h-\[2px\] {
|
||||
height: 2px;
|
||||
}
|
||||
.h-\[62px\] {
|
||||
height: 62px;
|
||||
}
|
||||
.h-\[68px\] {
|
||||
height: 68px;
|
||||
}
|
||||
.h-\[88px\] {
|
||||
height: 88px;
|
||||
}
|
||||
.h-\[95vh\] {
|
||||
height: 95vh;
|
||||
}
|
||||
@@ -831,6 +851,12 @@
|
||||
.h-\[600px\] {
|
||||
height: 600px;
|
||||
}
|
||||
.h-\[700px\] {
|
||||
height: 700px;
|
||||
}
|
||||
.h-auto {
|
||||
height: auto;
|
||||
}
|
||||
.h-full {
|
||||
height: 100%;
|
||||
}
|
||||
@@ -882,6 +908,9 @@
|
||||
.min-h-\[8rem\] {
|
||||
min-height: 8rem;
|
||||
}
|
||||
.min-h-\[110px\] {
|
||||
min-height: 110px;
|
||||
}
|
||||
.min-h-\[calc\(100vh-62px\)\] {
|
||||
min-height: calc(100vh - 62px);
|
||||
}
|
||||
@@ -963,6 +992,12 @@
|
||||
.w-80 {
|
||||
width: calc(var(--spacing) * 80);
|
||||
}
|
||||
.w-\[68px\] {
|
||||
width: 68px;
|
||||
}
|
||||
.w-\[88px\] {
|
||||
width: 88px;
|
||||
}
|
||||
.w-\[400px\] {
|
||||
width: 400px;
|
||||
}
|
||||
@@ -975,6 +1010,9 @@
|
||||
.w-\[600px\] {
|
||||
width: 600px;
|
||||
}
|
||||
.w-\[700px\] {
|
||||
width: 700px;
|
||||
}
|
||||
.w-full {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -1097,6 +1135,14 @@
|
||||
--tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.translate-y-0 {
|
||||
--tw-translate-y: calc(var(--spacing) * 0);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.translate-y-2 {
|
||||
--tw-translate-y: calc(var(--spacing) * 2);
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
}
|
||||
.translate-y-full {
|
||||
--tw-translate-y: 100%;
|
||||
translate: var(--tw-translate-x) var(--tw-translate-y);
|
||||
@@ -1113,6 +1159,15 @@
|
||||
--tw-scale-z: 100%;
|
||||
scale: var(--tw-scale-x) var(--tw-scale-y);
|
||||
}
|
||||
.scale-105 {
|
||||
--tw-scale-x: 105%;
|
||||
--tw-scale-y: 105%;
|
||||
--tw-scale-z: 105%;
|
||||
scale: var(--tw-scale-x) var(--tw-scale-y);
|
||||
}
|
||||
.-rotate-90 {
|
||||
rotate: calc(90deg * -1);
|
||||
}
|
||||
.rotate-45 {
|
||||
rotate: 45deg;
|
||||
}
|
||||
@@ -1190,6 +1245,9 @@
|
||||
.grid-cols-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
.grid-cols-4 {
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
}
|
||||
.grid-cols-7 {
|
||||
grid-template-columns: repeat(7, minmax(0, 1fr));
|
||||
}
|
||||
@@ -1564,6 +1622,12 @@
|
||||
.border-brand-b1 {
|
||||
border-color: #0062ff;
|
||||
}
|
||||
.border-brand-b2\/40 {
|
||||
border-color: color-mix(in oklab, #00bdd8 40%, transparent);
|
||||
}
|
||||
.border-brand-b3\/60 {
|
||||
border-color: color-mix(in oklab, #00c896 60%, transparent);
|
||||
}
|
||||
.border-brand-border {
|
||||
border-color: #e6ebf2;
|
||||
}
|
||||
@@ -1831,6 +1895,9 @@
|
||||
.bg-blue-600 {
|
||||
background-color: var(--color-blue-600);
|
||||
}
|
||||
.bg-brand-b1 {
|
||||
background-color: #0062ff;
|
||||
}
|
||||
.bg-brand-b1\/10 {
|
||||
background-color: color-mix(in oklab, #0062ff 10%, transparent);
|
||||
}
|
||||
@@ -1840,6 +1907,9 @@
|
||||
.bg-brand-b3\/10 {
|
||||
background-color: color-mix(in oklab, #00c896 10%, transparent);
|
||||
}
|
||||
.bg-brand-b3\/60 {
|
||||
background-color: color-mix(in oklab, #00c896 60%, transparent);
|
||||
}
|
||||
.bg-brand-bg {
|
||||
background-color: #f7f9fc;
|
||||
}
|
||||
@@ -2231,6 +2301,9 @@
|
||||
.px-6 {
|
||||
padding-inline: calc(var(--spacing) * 6);
|
||||
}
|
||||
.px-7 {
|
||||
padding-inline: calc(var(--spacing) * 7);
|
||||
}
|
||||
.px-8 {
|
||||
padding-inline: calc(var(--spacing) * 8);
|
||||
}
|
||||
@@ -2657,12 +2730,18 @@
|
||||
.text-brand-b1 {
|
||||
color: #0062ff;
|
||||
}
|
||||
.text-brand-b2 {
|
||||
color: #00bdd8;
|
||||
}
|
||||
.text-brand-b3 {
|
||||
color: #00c896;
|
||||
}
|
||||
.text-brand-navy {
|
||||
color: #060d1a;
|
||||
}
|
||||
.text-brand-navy\/30 {
|
||||
color: color-mix(in oklab, #060d1a 30%, transparent);
|
||||
}
|
||||
.text-brand-navy\/40 {
|
||||
color: color-mix(in oklab, #060d1a 40%, transparent);
|
||||
}
|
||||
@@ -2681,6 +2760,9 @@
|
||||
.text-brand-navy\/90 {
|
||||
color: color-mix(in oklab, #060d1a 90%, transparent);
|
||||
}
|
||||
.text-cyan-300 {
|
||||
color: var(--color-cyan-300);
|
||||
}
|
||||
.text-emerald-300 {
|
||||
color: var(--color-emerald-300);
|
||||
}
|
||||
@@ -2729,6 +2811,9 @@
|
||||
.text-purple-300 {
|
||||
color: var(--color-purple-300);
|
||||
}
|
||||
.text-purple-400 {
|
||||
color: var(--color-purple-400);
|
||||
}
|
||||
.text-purple-500 {
|
||||
color: var(--color-purple-500);
|
||||
}
|
||||
@@ -2913,6 +2998,9 @@
|
||||
.opacity-75 {
|
||||
opacity: 75%;
|
||||
}
|
||||
.opacity-80 {
|
||||
opacity: 80%;
|
||||
}
|
||||
.opacity-90 {
|
||||
opacity: 90%;
|
||||
}
|
||||
@@ -2927,6 +3015,10 @@
|
||||
--tw-shadow: 0 25px 50px -12px var(--tw-shadow-color, rgb(0 0 0 / 0.25));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.shadow-\[0_0_28px_rgba\(0\,98\,255\,0\.35\)\] {
|
||||
--tw-shadow: 0 0 28px var(--tw-shadow-color, rgba(0,98,255,0.35));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.shadow-cta {
|
||||
--tw-shadow: 0 4px 20px var(--tw-shadow-color, rgba(0, 98, 255, 0.28));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
@@ -2947,6 +3039,10 @@
|
||||
--tw-shadow: 0 20px 25px -5px var(--tw-shadow-color, rgb(0 0 0 / 0.1)), 0 8px 10px -6px var(--tw-shadow-color, rgb(0 0 0 / 0.1));
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.ring {
|
||||
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
}
|
||||
.ring-1 {
|
||||
--tw-ring-shadow: var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color, currentcolor);
|
||||
box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);
|
||||
@@ -3060,6 +3156,10 @@
|
||||
--tw-duration: 500ms;
|
||||
transition-duration: 500ms;
|
||||
}
|
||||
.ease-in {
|
||||
--tw-ease: var(--ease-in);
|
||||
transition-timing-function: var(--ease-in);
|
||||
}
|
||||
.ease-in-out {
|
||||
--tw-ease: var(--ease-in-out);
|
||||
transition-timing-function: var(--ease-in-out);
|
||||
@@ -4110,6 +4210,11 @@
|
||||
outline-offset: 2px;
|
||||
}
|
||||
}
|
||||
.focus-visible\:outline-offset-4 {
|
||||
&:focus-visible {
|
||||
outline-offset: 4px;
|
||||
}
|
||||
}
|
||||
.focus-visible\:outline-brand-b1 {
|
||||
&:focus-visible {
|
||||
outline-color: #0062ff;
|
||||
|
||||
@@ -455,6 +455,212 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ===== PIPELINE — Comment ça marche : 4 étapes ===== #}
|
||||
{# Source canonique : InnovA-AI/Website-Sanity/components/sections/dictai-pipeline.tsx
|
||||
Animation traduite : Framer Motion auto-advance + sweep ring → Alpine.js setInterval + CSS keyframes #}
|
||||
<style>
|
||||
/* Sweep ring on the active pipeline node — restarts via :key (DOM swap) */
|
||||
@keyframes pipeline-sweep {
|
||||
from { stroke-dashoffset: 257.6; }
|
||||
to { stroke-dashoffset: 0; }
|
||||
}
|
||||
.pipeline-sweep-ring {
|
||||
stroke-dasharray: 257.6; /* 2π × 41 */
|
||||
animation: pipeline-sweep 2400ms linear forwards;
|
||||
}
|
||||
/* Underline sweep on the description card — restart on Alpine swap */
|
||||
@keyframes pipeline-underline {
|
||||
from { transform: scaleX(0); }
|
||||
to { transform: scaleX(1); }
|
||||
}
|
||||
.pipeline-underline {
|
||||
transform-origin: left;
|
||||
animation: pipeline-underline 2400ms linear forwards;
|
||||
}
|
||||
/* Glowing dot trailing the active step on the track */
|
||||
.pipeline-dot {
|
||||
transition: left 450ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
/* Filled track from start to active step */
|
||||
.pipeline-track-fill {
|
||||
transition: transform 450ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||
transform-origin: left;
|
||||
}
|
||||
/* Reduced motion : freeze auto-advance + remove all animations */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.pipeline-sweep-ring, .pipeline-underline, .pipeline-dot, .pipeline-track-fill {
|
||||
animation: none !important;
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
/* Hide Alpine x-show elements until Alpine hydrates (avoids FOUC flash of all 4 cards) */
|
||||
[x-cloak] { display: none !important; }
|
||||
</style>
|
||||
<section class="bg-white py-20 border-y border-brand-border" aria-labelledby="pipeline-title">
|
||||
<div class="max-w-[1100px] mx-auto px-6">
|
||||
<div class="text-center max-w-2xl mx-auto mb-14">
|
||||
<p class="eyebrow grad-text mb-4">COMMENT ÇA MARCHE</p>
|
||||
<h2 id="pipeline-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-4 text-brand-navy">
|
||||
Du fichier au résumé <span class="grad-text">en 4 étapes</span>.
|
||||
</h2>
|
||||
<p class="text-lg text-brand-navy/70">
|
||||
Aucune installation côté utilisateur, aucune conversion préalable. DictIA orchestre l'ensemble du pipeline — du téléversement à l'export — en moins de deux minutes pour une heure d'audio.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Pipeline track + 4 nodes — Alpine state drives all visuals.
|
||||
active = 0..3 (current step), prefers-reduced-motion stops the autoplay (handled in x-init). #}
|
||||
<div
|
||||
class="relative max-w-4xl mx-auto"
|
||||
x-data="{
|
||||
active: 0,
|
||||
timer: null,
|
||||
steps: [
|
||||
{ positionPct: 12.5, fillPct: 0 },
|
||||
{ positionPct: 37.5, fillPct: 33.33 },
|
||||
{ positionPct: 62.5, fillPct: 66.66 },
|
||||
{ positionPct: 87.5, fillPct: 100 }
|
||||
],
|
||||
startTimer() {
|
||||
if (this.timer) clearInterval(this.timer);
|
||||
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
||||
this.timer = setInterval(() => { this.active = (this.active + 1) % 4; }, 2400);
|
||||
},
|
||||
select(i) { this.active = i; this.startTimer(); }
|
||||
}"
|
||||
x-init="startTimer()"
|
||||
>
|
||||
{# Background + filled track (top: 44px = node center 88px / 2) #}
|
||||
<div class="absolute h-px bg-brand-border" style="top: 44px; left: 12.5%; right: 12.5%;" aria-hidden="true"></div>
|
||||
<div
|
||||
class="pipeline-track-fill absolute h-[2px]"
|
||||
style="top: 43px; left: 12.5%; width: 75%; background: linear-gradient(90deg, #0062ff 0%, #00bdd8 100%);"
|
||||
:style="`transform: scaleX(${steps[active].fillPct / 100})`"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
|
||||
{# Moving glowing dot — left transitions via CSS #}
|
||||
<div
|
||||
class="pipeline-dot absolute w-3.5 h-3.5 rounded-full bg-white pointer-events-none z-10"
|
||||
style="top: 44px; transform: translate(-50%, -50%); box-shadow: 0 0 18px rgba(0,189,216,0.55), 0 0 36px rgba(0,98,255,0.35);"
|
||||
:style="`left: ${steps[active].positionPct}%`"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
|
||||
{# Nodes grid — 4 cols #}
|
||||
<div class="grid grid-cols-4 gap-2">
|
||||
{# Each step rendered statically; active state computed via :class. #}
|
||||
{% set steps = [
|
||||
('Uploader', 'Audio ou vidéo', '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-7 h-7" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>',
|
||||
"Glissez n'importe quel format — MP3, WAV, MP4, MKV. Aucune conversion nécessaire. DictIA accepte tout sans préparation."),
|
||||
('GPU transcrit', 'WhisperX Large-v3', '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-7 h-7" aria-hidden="true"><rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3"/></svg>',
|
||||
"Votre GPU traite le fichier 60× plus vite qu'un humain. 1 heure d'audio → 2 minutes. Précision 95 %+ en français canadien. 100 % en local — zéro cloud étranger."),
|
||||
('IA structure', 'Mistral 7B / Nemo 12B', '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-7 h-7" aria-hidden="true"><path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24 2.5 2.5 0 0 1 1.98-3A2.5 2.5 0 0 1 9.5 2z"/><path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24 2.5 2.5 0 0 0-1.98-3A2.5 2.5 0 0 0 14.5 2z"/></svg>',
|
||||
"L'IA identifie automatiquement chaque locuteur, génère un résumé structuré, extrait les points d'action et répond à vos questions sur le contenu transcrit."),
|
||||
('Exporter', 'Dans votre écosystème', '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-7 h-7" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>',
|
||||
"DOCX, SRT, VTT, JSON, Obsidian, Logseq. Connectez avec n8n, Zapier ou Make pour automatiser vos workflows — zéro copier-coller.")
|
||||
] %}
|
||||
{% for label, sublabel, icon, desc in steps %}
|
||||
<button
|
||||
type="button"
|
||||
@click="select({{ loop.index0 }})"
|
||||
class="group flex flex-col items-center gap-4 cursor-pointer select-none focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-4 rounded-none p-2"
|
||||
:aria-current="active === {{ loop.index0 }} ? 'step' : 'false'"
|
||||
aria-label="Étape {{ loop.index }} sur 4 : {{ label }} — {{ sublabel }}"
|
||||
>
|
||||
{# Circle node — visual state driven by :class (active / completed / pending) #}
|
||||
<span
|
||||
class="relative w-[88px] h-[88px] rounded-full border-2 flex items-center justify-center transition-all duration-300"
|
||||
:class="{
|
||||
'border-brand-b1 bg-brand-b1/10 scale-105 shadow-[0_0_28px_rgba(0,98,255,0.35)]': active === {{ loop.index0 }},
|
||||
'border-brand-b3/60 bg-brand-b3/10': active > {{ loop.index0 }},
|
||||
'border-brand-border bg-white': active < {{ loop.index0 }}
|
||||
}"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<span
|
||||
class="transition-opacity duration-300"
|
||||
:class="active >= {{ loop.index0 }} ? 'opacity-100 text-brand-b1' : 'opacity-30 text-brand-navy/30'"
|
||||
>{{ icon | safe }}</span>
|
||||
|
||||
{# Step badge — top-right corner with index #}
|
||||
<span
|
||||
class="absolute -top-1.5 -right-1.5 w-6 h-6 rounded-full flex items-center justify-center text-[11px] font-bold transition-colors duration-300"
|
||||
:class="active >= {{ loop.index0 }} ? 'bg-brand-b1 text-white' : 'bg-brand-border text-brand-navy/40'"
|
||||
>{{ loop.index }}</span>
|
||||
|
||||
{# Sweep progress ring — only visible on active step. Re-keyed via :key when active changes. #}
|
||||
<template x-if="active === {{ loop.index0 }}">
|
||||
<svg
|
||||
:key="active"
|
||||
class="absolute inset-0 w-full h-full -rotate-90 pointer-events-none"
|
||||
viewBox="0 0 88 88"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle class="pipeline-sweep-ring" cx="44" cy="44" r="41" fill="none" stroke="#0062ff" stroke-width="2" stroke-linecap="round"></circle>
|
||||
</svg>
|
||||
</template>
|
||||
</span>
|
||||
|
||||
{# Label + sublabel — opacity dimmed on pending steps #}
|
||||
<span
|
||||
class="text-center px-1 transition-opacity duration-300 block"
|
||||
:class="active >= {{ loop.index0 }} ? 'opacity-100' : 'opacity-40'"
|
||||
>
|
||||
<span class="block font-bold text-sm leading-tight mb-0.5 text-brand-navy">{{ label }}</span>
|
||||
<span class="block text-xs text-brand-navy/70 leading-tight">{{ sublabel }}</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Step description card — swaps with x-show + x-transition. Underline sweep restarts via :key on active. #}
|
||||
<div class="mt-12 max-w-2xl mx-auto min-h-[110px] flex items-center justify-center">
|
||||
{% for label, sublabel, icon, desc in steps %}
|
||||
<div
|
||||
x-show="active === {{ loop.index0 }}"
|
||||
x-transition:enter="transition ease-out duration-300"
|
||||
x-transition:enter-start="opacity-0 translate-y-2"
|
||||
x-transition:enter-end="opacity-100 translate-y-0"
|
||||
x-transition:leave="transition ease-in duration-150"
|
||||
x-transition:leave-start="opacity-100"
|
||||
x-transition:leave-end="opacity-0"
|
||||
class="relative w-full bg-brand-bg border border-brand-border px-7 py-6 text-center rounded overflow-hidden"
|
||||
x-cloak
|
||||
>
|
||||
<p class="text-sm text-brand-navy/80 leading-relaxed">{{ desc | safe }}</p>
|
||||
<span
|
||||
:key="active"
|
||||
class="pipeline-underline absolute bottom-0 left-0 h-[2px] w-full"
|
||||
style="background: linear-gradient(90deg, #0062ff, #00bdd8);"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Progress dots (mobile-friendly + click target redundancy) #}
|
||||
<div class="flex justify-center gap-2 mt-8" role="tablist" aria-label="Sélectionner une étape">
|
||||
{% for label, sublabel, icon, desc in steps %}
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
@click="select({{ loop.index0 }})"
|
||||
class="h-1 rounded-full transition-all duration-300 focus-visible:outline-2 focus-visible:outline-brand-b1 focus-visible:outline-offset-2"
|
||||
:class="{
|
||||
'w-8 bg-brand-b1': active === {{ loop.index0 }},
|
||||
'w-8 bg-brand-b3/60': active > {{ loop.index0 }},
|
||||
'w-2 bg-brand-border': active < {{ loop.index0 }}
|
||||
}"
|
||||
:aria-selected="active === {{ loop.index0 }} ? 'true' : 'false'"
|
||||
aria-label="Aller à l'étape {{ loop.index }} : {{ label }}"
|
||||
></button>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ===== BENTO FEATURES ===== #}
|
||||
<section class="bg-white py-20" aria-labelledby="bento-title">
|
||||
<div class="max-w-[1060px] mx-auto px-6">
|
||||
@@ -486,6 +692,197 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ===== HUB — Réseau d'intégrations ===== #}
|
||||
{# Source canonique : InnovA-AI/Website-Sanity/components/sections/dictai-hub.tsx
|
||||
Animation : SVG pur avec <animateMotion> sur bezier paths — aucune lib JS, aucune config.
|
||||
Particules cyan circulent en continu de DictIA → Hubs → Outils. #}
|
||||
<style>
|
||||
/* DictIA central node — pulsing rings (decorative, native CSS) */
|
||||
@keyframes hub-ring-pulse {
|
||||
0% { transform: scale(1); opacity: 0.55; }
|
||||
70% { transform: scale(2.6); opacity: 0; }
|
||||
100% { transform: scale(2.6); opacity: 0; }
|
||||
}
|
||||
.hub-ring { animation: hub-ring-pulse 3s ease-out infinite; }
|
||||
.hub-ring-2 { animation-delay: 1s; }
|
||||
.hub-ring-3 { animation-delay: 2s; }
|
||||
/* DictIA core breathing glow */
|
||||
@keyframes hub-core-breathe {
|
||||
0%, 100% { box-shadow: 0 0 26px rgba(0,189,216,0.55), 0 0 56px rgba(0,189,216,0.18); }
|
||||
50% { box-shadow: 0 0 38px rgba(0,189,216,0.75), 0 0 72px rgba(0,189,216,0.28); }
|
||||
}
|
||||
.hub-core { animation: hub-core-breathe 3.5s ease-in-out infinite; }
|
||||
/* Reduced motion : freeze everything */
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.hub-ring, .hub-core { animation: none !important; }
|
||||
/* Disable SVG animateMotion via display:none on the animateMotion elements (browser respects this). */
|
||||
.hub-network-svg animateMotion { display: none !important; }
|
||||
}
|
||||
</style>
|
||||
<section class="bg-brand-navy text-white py-20 overflow-hidden relative" aria-labelledby="hub-title">
|
||||
{# Decorative cosmic orb — cyan, mid-section #}
|
||||
<div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[700px] h-[700px] rounded-full pointer-events-none" aria-hidden="true"
|
||||
style="background: radial-gradient(circle, rgba(0,189,216,0.10) 0%, transparent 60%); filter: blur(60px);"></div>
|
||||
|
||||
<div class="relative max-w-[1200px] mx-auto px-6">
|
||||
<div class="text-center max-w-2xl mx-auto mb-12">
|
||||
<p class="eyebrow grad-text mb-4">INTÉGRATIONS — RÉSEAU OUVERT</p>
|
||||
<h2 id="hub-title" class="text-[clamp(2rem,3vw,2.75rem)] font-black mb-4">
|
||||
DictIA <span class="grad-text">se connecte à tout</span>.
|
||||
</h2>
|
||||
<p class="text-lg text-white/70">
|
||||
Transcriptions et résumés acheminés automatiquement vers vos outils de travail. Trois familles d'intégrations couvrent l'essentiel des flux documentaires, communication et automatisation.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{# Network diagram — SVG with native <animateMotion> for particle flow.
|
||||
Layout : DictIA center-top, 3 hubs (Documents | Communication | Automatisation), 9 tools below. #}
|
||||
<div class="relative max-w-4xl mx-auto">
|
||||
<svg
|
||||
viewBox="0 0 900 460"
|
||||
preserveAspectRatio="xMidYMid meet"
|
||||
class="hub-network-svg w-full h-auto"
|
||||
role="img"
|
||||
aria-labelledby="hub-svg-title hub-svg-desc"
|
||||
>
|
||||
<title id="hub-svg-title">Diagramme du réseau d'intégrations DictIA</title>
|
||||
<desc id="hub-svg-desc">DictIA au centre, connecté à trois familles : Documents (Word, Google Docs, Obsidian), Communication (Outlook, Teams, Notion) et Automatisation (Zapier, Make, n8n).</desc>
|
||||
|
||||
<defs>
|
||||
{# Bezier path definitions — DictIA top → 3 hubs (mid) #}
|
||||
<path id="hub-path-docs" d="M450,54 C450,127 168,127 168,200" />
|
||||
<path id="hub-path-comm" d="M450,54 C450,127 450,127 450,200" />
|
||||
<path id="hub-path-auto" d="M450,54 C450,127 732,127 732,200" />
|
||||
|
||||
{# Bezier paths — Hub → Tool #}
|
||||
{# Documents hub (168, 200) → Word(62,390), Google(175,390), Obsidian(282,390) #}
|
||||
<path id="hub-path-word" d="M168,216 C168,303 62,303 62,390" />
|
||||
<path id="hub-path-google" d="M168,216 C168,303 175,303 175,390" />
|
||||
<path id="hub-path-obsidian" d="M168,216 C168,303 282,303 282,390" />
|
||||
{# Communication hub (450, 200) → Outlook(358,390), Teams(450,390), Notion(542,390) #}
|
||||
<path id="hub-path-outlook" d="M450,216 C450,303 358,303 358,390" />
|
||||
<path id="hub-path-teams" d="M450,216 C450,303 450,303 450,390" />
|
||||
<path id="hub-path-notion" d="M450,216 C450,303 542,303 542,390" />
|
||||
{# Automatisation hub (732, 200) → Zapier(618,390), Make(722,390), n8n(828,390) #}
|
||||
<path id="hub-path-zapier" d="M732,216 C732,303 618,303 618,390" />
|
||||
<path id="hub-path-make" d="M732,216 C732,303 722,303 722,390" />
|
||||
<path id="hub-path-n8n" d="M732,216 C732,303 828,303 828,390" />
|
||||
</defs>
|
||||
|
||||
{# Render bezier connections (visible strokes) — DictIA → Hubs (thick), Hub → Tools (thin) #}
|
||||
{# DictIA → Hubs #}
|
||||
<use href="#hub-path-docs" fill="none" stroke="#0062ff" stroke-width="1.5" opacity="0.55" />
|
||||
<use href="#hub-path-comm" fill="none" stroke="#00bdd8" stroke-width="1.5" opacity="0.55" />
|
||||
<use href="#hub-path-auto" fill="none" stroke="#8b5cf6" stroke-width="1.5" opacity="0.55" />
|
||||
|
||||
{# Hub → Tool (lighter) #}
|
||||
<use href="#hub-path-word" fill="none" stroke="#0062ff" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-google" fill="none" stroke="#0062ff" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-obsidian" fill="none" stroke="#0062ff" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-outlook" fill="none" stroke="#00bdd8" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-teams" fill="none" stroke="#00bdd8" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-notion" fill="none" stroke="#00bdd8" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-zapier" fill="none" stroke="#8b5cf6" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-make" fill="none" stroke="#8b5cf6" stroke-width="1" opacity="0.30" />
|
||||
<use href="#hub-path-n8n" fill="none" stroke="#8b5cf6" stroke-width="1" opacity="0.30" />
|
||||
|
||||
{# Animated particles — DictIA → Hubs (bigger, dual particles) #}
|
||||
{% for hub in [
|
||||
('docs', '#0062ff', '0s', '2.4s'),
|
||||
('comm', '#00bdd8', '0.8s', '2.4s'),
|
||||
('auto', '#8b5cf6', '1.6s', '2.4s')
|
||||
] %}
|
||||
<circle r="3.2" fill="{{ hub[1] }}" opacity="0.95">
|
||||
<animateMotion dur="{{ hub[3] }}" repeatCount="indefinite" begin="{{ hub[2] }}">
|
||||
<mpath href="#hub-path-{{ hub[0] }}" />
|
||||
</animateMotion>
|
||||
</circle>
|
||||
<circle r="1.8" fill="{{ hub[1] }}" opacity="0.6">
|
||||
<animateMotion dur="{{ hub[3] }}" repeatCount="indefinite" begin="{{ hub[2] }}s + 1.2s">
|
||||
<mpath href="#hub-path-{{ hub[0] }}" />
|
||||
</animateMotion>
|
||||
</circle>
|
||||
{% endfor %}
|
||||
|
||||
{# Animated particles — Hub → Tool (smaller, fast) #}
|
||||
{% for tool in [
|
||||
('word', '#0062ff', '0s'),
|
||||
('google', '#0062ff', '0.4s'),
|
||||
('obsidian', '#0062ff', '0.8s'),
|
||||
('outlook', '#00bdd8', '0.2s'),
|
||||
('teams', '#00bdd8', '0.6s'),
|
||||
('notion', '#00bdd8', '1.0s'),
|
||||
('zapier', '#8b5cf6', '0.1s'),
|
||||
('make', '#8b5cf6', '0.5s'),
|
||||
('n8n', '#8b5cf6', '0.9s')
|
||||
] %}
|
||||
<circle r="2.2" fill="{{ tool[1] }}" opacity="0.75">
|
||||
<animateMotion dur="2s" repeatCount="indefinite" begin="{{ tool[2] }}">
|
||||
<mpath href="#hub-path-{{ tool[0] }}" />
|
||||
</animateMotion>
|
||||
</circle>
|
||||
{% endfor %}
|
||||
</svg>
|
||||
|
||||
{# DictIA central node — absolute positioned over the SVG (z-10) #}
|
||||
<div class="absolute pointer-events-none" style="left: 50%; top: 11.7%; transform: translate(-50%, -50%); z-index: 10;" aria-hidden="true">
|
||||
<div class="relative w-[68px] h-[68px]">
|
||||
{# Pulsing rings #}
|
||||
<span class="hub-ring absolute inset-0 rounded-full border-2 border-brand-b2/40"></span>
|
||||
<span class="hub-ring hub-ring-2 absolute inset-0 rounded-full border-2 border-brand-b2/40"></span>
|
||||
<span class="hub-ring hub-ring-3 absolute inset-0 rounded-full border-2 border-brand-b2/40"></span>
|
||||
{# Core orb #}
|
||||
<span class="hub-core absolute inset-0 rounded-full grad-bg flex items-center justify-center">
|
||||
<span class="font-black text-white text-[13px] tracking-tight">DictIA</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{# Hub labels overlay — positioned to match SVG hub coords (200/460 = 43.5% top, 168/900=18.7% / 450/900=50% / 732/900=81.3% left) #}
|
||||
{% set hub_data = [
|
||||
('Documents', 'Word · Google Docs · Obsidian', '18.7%', 'rgba(0,98,255,0.10)', 'rgba(0,98,255,0.30)', 'text-blue-300'),
|
||||
('Communication', 'Outlook · Teams · Notion', '50%', 'rgba(0,189,216,0.10)', 'rgba(0,189,216,0.30)', 'text-cyan-300'),
|
||||
('Automatisation', 'Zapier · Make · n8n', '81.3%', 'rgba(139,92,246,0.10)', 'rgba(139,92,246,0.30)', 'text-purple-300')
|
||||
] %}
|
||||
{% for name, sub, leftpos, bgcol, brdcol, txtcol in hub_data %}
|
||||
<div
|
||||
class="absolute pointer-events-none px-3 py-2 rounded-full backdrop-blur-sm whitespace-nowrap"
|
||||
style="left: {{ leftpos }}; top: 43.5%; transform: translate(-50%, -50%); background: {{ bgcol }}; border: 1px solid {{ brdcol }};"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<p class="text-[11px] font-bold text-white leading-none">{{ name }}</p>
|
||||
<p class="text-[9px] {{ txtcol }} leading-none mt-0.5 opacity-80">{{ sub }}</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
{# Tool list — text fallback below the diagram (covers screen readers + reduces visual noise on mobile) #}
|
||||
<div class="mt-12 grid sm:grid-cols-3 gap-6 max-w-3xl mx-auto" role="list" aria-label="Outils intégrés à DictIA">
|
||||
{% for col_label, tools, accent in [
|
||||
('Documents', [('Word', 'Export .docx instantané'), ('Google Docs', 'Sync Google Workspace'), ('Obsidian', 'Notes Markdown locales')], 'text-brand-b1'),
|
||||
('Communication', [('Outlook', 'Envoi email automatique'), ('Teams', 'Canal Teams dédié'), ('Notion', 'Page Notion structurée')], 'text-brand-b2'),
|
||||
('Automatisation', [('Zapier', '5 000+ apps connectées'), ('Make', 'Scénarios visuels no-code'), ('n8n', 'Workflows open-source')], 'text-purple-400')
|
||||
] %}
|
||||
<div role="listitem" class="bg-white/[0.03] border border-white/[0.06] p-5 rounded">
|
||||
<p class="eyebrow {{ accent }} mb-3">{{ col_label | upper }}</p>
|
||||
<ul class="space-y-2">
|
||||
{% for tool_name, tool_desc in tools %}
|
||||
<li class="text-sm">
|
||||
<span class="font-semibold text-white">{{ tool_name }}</span>
|
||||
<span class="text-white/70"> — {{ tool_desc | safe }}</span>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<p class="text-center text-sm text-white/70 mt-8 max-w-2xl mx-auto">
|
||||
Architecture ouverte. Tout export est aussi disponible en DOCX, SRT, VTT, JSON, TXT et MD — formats standards consommables par n'importe quel logiciel métier (gestion de dossiers, paie, CRM).
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{# ===== PRICING ===== #}
|
||||
<section class="bg-brand-bg py-20" id="tarifs" aria-labelledby="pricing-title">
|
||||
<div class="max-w-[1200px] mx-auto px-6">
|
||||
|
||||
Reference in New Issue
Block a user