(frontend) add onboarding modal with help menu button

integrate onboarding feature accessible from left panel help menu

(frontend) add docs onboarding and help memu

Introduce an onboarding to guide users through core features.
This commit is contained in:
Cyril
2026-02-05 13:38:57 +01:00
committed by Anthony LC
parent c3acfe45d2
commit 6c493c24d5
24 changed files with 483 additions and 67 deletions
+1
View File
@@ -9,6 +9,7 @@ and this project adheres to
### Added
- ✨(backend) add a is_first_connection flag to the User model #1938
- ✨(frontend) add onboarding modal with help menu button #1868
### Changed
@@ -158,5 +158,9 @@
"href": "/assets/favicon-dark.png",
"type": "image/png"
}
},
"onboarding": {
"enabled": true,
"learn_more_url": ""
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@@ -16,6 +16,10 @@ interface ThemeCustomization {
light: LinkHTMLAttributes<HTMLLinkElement>;
dark: LinkHTMLAttributes<HTMLLinkElement>;
};
onboarding?: {
enabled: true;
learn_more_url?: string;
};
footer?: FooterType;
home: {
'with-proconnect'?: boolean;
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9 20C8.45 20 7.97917 19.8042 7.5875 19.4125C7.19583 19.0208 7 18.55 7 18C7 17.45 7.19583 16.9792 7.5875 16.5875C7.97917 16.1958 8.45 16 9 16C9.55 16 10.0208 16.1958 10.4125 16.5875C10.8042 16.9792 11 17.45 11 18C11 18.55 10.8042 19.0208 10.4125 19.4125C10.0208 19.8042 9.55 20 9 20ZM15 20C14.45 20 13.9792 19.8042 13.5875 19.4125C13.1958 19.0208 13 18.55 13 18C13 17.45 13.1958 16.9792 13.5875 16.5875C13.9792 16.1958 14.45 16 15 16C15.55 16 16.0208 16.1958 16.4125 16.5875C16.8042 16.9792 17 17.45 17 18C17 18.55 16.8042 19.0208 16.4125 19.4125C16.0208 19.8042 15.55 20 15 20ZM9 14C8.45 14 7.97917 13.8042 7.5875 13.4125C7.19583 13.0208 7 12.55 7 12C7 11.45 7.19583 10.9792 7.5875 10.5875C7.97917 10.1958 8.45 10 9 10C9.55 10 10.0208 10.1958 10.4125 10.5875C10.8042 10.9792 11 11.45 11 12C11 12.55 10.8042 13.0208 10.4125 13.4125C10.0208 13.8042 9.55 14 9 14ZM15 14C14.45 14 13.9792 13.8042 13.5875 13.4125C13.1958 13.0208 13 12.55 13 12C13 11.45 13.1958 10.9792 13.5875 10.5875C13.9792 10.1958 14.45 10 15 10C15.55 10 16.0208 10.1958 16.4125 10.5875C16.8042 10.9792 17 11.45 17 12C17 12.55 16.8042 13.0208 16.4125 13.4125C16.0208 13.8042 15.55 14 15 14ZM9 8C8.45 8 7.97917 7.80417 7.5875 7.4125C7.19583 7.02083 7 6.55 7 6C7 5.45 7.19583 4.97917 7.5875 4.5875C7.97917 4.19583 8.45 4 9 4C9.55 4 10.0208 4.19583 10.4125 4.5875C10.8042 4.97917 11 5.45 11 6C11 6.55 10.8042 7.02083 10.4125 7.4125C10.0208 7.80417 9.55 8 9 8ZM15 8C14.45 8 13.9792 7.80417 13.5875 7.4125C13.1958 7.02083 13 6.55 13 6C13 5.45 13.1958 4.97917 13.5875 4.5875C13.9792 4.19583 14.45 4 15 4C15.55 4 16.0208 4.19583 16.4125 4.5875C16.8042 4.97917 17 5.45 17 6C17 6.55 16.8042 7.02083 16.4125 7.4125C16.0208 7.80417 15.55 8 15 8Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.032 11.8745C12.1434 11.8745 12.2462 11.8962 12.339 11.9395C12.4317 11.9828 12.5307 12.054 12.6358 12.153L15.1415 14.4452C15.2219 14.5195 15.2842 14.6005 15.3275 14.6871C15.3707 14.7736 15.3916 14.8727 15.3916 14.9839C15.3916 15.188 15.3204 15.3552 15.1782 15.4851C15.0421 15.6148 14.8749 15.6802 14.677 15.6802C14.5782 15.6801 14.479 15.6584 14.3802 15.6152C14.2874 15.5719 14.2073 15.5126 14.1392 15.4383L13.4613 14.7329L12.7393 13.9761L12.8209 15.42V18.3994C12.8208 18.6096 12.7407 18.7858 12.5799 18.928C12.4252 19.0765 12.2424 19.1506 12.032 19.1506C11.8157 19.1506 11.6305 19.0763 11.4759 18.928C11.3213 18.7858 11.2433 18.6096 11.2432 18.3994V15.42L11.3303 13.9688L10.6129 14.7329L9.91663 15.4383C9.85475 15.5126 9.77375 15.5719 9.67476 15.6152C9.57593 15.6583 9.47974 15.6802 9.38708 15.6802C9.1769 15.6801 9.00365 15.6149 8.86762 15.4851C8.73772 15.3552 8.67251 15.188 8.67247 14.9839C8.67247 14.8727 8.69433 14.7736 8.73752 14.6871C8.78083 14.6005 8.84604 14.5195 8.93266 14.4452L11.4384 12.153C11.5373 12.054 11.6333 11.9828 11.7261 11.9395C11.8187 11.8962 11.9208 11.8745 12.032 11.8745Z" fill="currentColor"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.5309 1.95331C11.9207 1.95331 12.2616 1.98191 12.5524 2.0376C12.8431 2.08711 13.1122 2.18302 13.3596 2.32527C13.607 2.46139 13.8611 2.6621 14.1209 2.92811L18.9839 7.87448C19.256 8.14658 19.4598 8.40975 19.5959 8.6633C19.7382 8.91078 19.8341 9.18651 19.8836 9.48968C19.9331 9.7866 19.9578 10.1515 19.9578 10.5845V19.0022C19.9578 19.9983 19.7047 20.7535 19.1974 21.267C18.69 21.7867 17.9379 22.0466 16.9418 22.0466H7.05819C6.06207 22.0466 5.30993 21.7897 4.80259 21.2761C4.29529 20.7626 4.04218 20.0045 4.04218 19.0022V4.99772C4.04219 4.00165 4.29527 3.24648 4.80259 2.73296C5.30993 2.21329 6.06211 1.95331 7.05819 1.95331H11.5309ZM7.21577 3.77281C6.76413 3.77282 6.42705 3.89043 6.20432 4.12554C5.98159 4.36064 5.86992 4.69175 5.86992 5.11866V18.8905C5.86992 19.3173 5.98163 19.6455 6.20432 19.8744C6.42706 20.1033 6.76114 20.218 7.20661 20.218H16.7934C17.245 20.218 17.5821 20.1033 17.8048 19.8744C18.0275 19.6455 18.1392 19.3173 18.1392 18.8905V10.8355H13.1369C12.4749 10.8355 11.9798 10.6715 11.6518 10.3435C11.3301 10.0156 11.169 9.52046 11.169 8.85844V3.77281H7.21577ZM12.7751 8.68254C12.7751 8.87416 12.8156 9.01282 12.896 9.0994C12.9826 9.18597 13.1212 9.22944 13.3128 9.22949H17.8882L12.7751 4.02292V8.68254Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.8544 19.4045C2.51806 19.4045 2.25096 19.3121 2.05312 19.1275C1.86186 18.9428 1.76624 18.6889 1.76624 18.3658C1.76624 18.1415 1.8091 17.9173 1.89484 17.6931L6.28708 5.85183C6.57726 5.03405 7.14772 4.62517 7.99847 4.62517C8.44693 4.62517 8.81295 4.72739 9.09653 4.93183C9.38012 5.12968 9.59775 5.43964 9.74944 5.86172L14.112 17.6436C14.2043 17.9008 14.2505 18.1349 14.2505 18.346C14.2505 18.6691 14.1483 18.9263 13.9438 19.1176C13.7394 19.3088 13.4624 19.4045 13.1129 19.4045C12.7831 19.4045 12.5259 19.3286 12.3413 19.1769C12.1566 19.0319 12.0115 18.7878 11.906 18.4449L10.798 15.3783H5.17913L4.08107 18.4449C3.96895 18.7878 3.82057 19.0319 3.63591 19.1769C3.45125 19.3286 3.19075 19.4045 2.8544 19.4045ZM5.743 13.5383H10.2638L8.02815 7.12795H7.9688L5.743 13.5383ZM15.6552 22.5206C15.1078 22.5206 14.8342 22.2898 14.8342 21.8281C14.8342 21.3665 15.1078 21.1357 15.6552 21.1357H17.7524V2.85442H15.6552C15.1078 2.85442 14.8342 2.6236 14.8342 2.16195C14.8342 1.7069 15.1078 1.47937 15.6552 1.47937H21.4027C21.9567 1.47937 22.2337 1.7069 22.2337 2.16195C22.2337 2.6236 21.9567 2.85442 21.4027 2.85442H19.3451V21.1357H21.4027C21.9567 21.1357 22.2337 21.3665 22.2337 21.8281C22.2337 22.2898 21.9567 22.5206 21.4027 22.5206H15.6552Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 381 B

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.78842 23.2081C3.72004 23.2081 2.91216 22.9377 2.36477 22.397C1.81739 21.8562 1.5437 21.0549 1.5437 19.9931V9.82367C1.5437 8.76188 1.81739 7.96059 2.36477 7.41981C2.91216 6.87902 3.72004 6.60863 4.78842 6.60863H19.2017C20.2701 6.60863 21.078 6.88232 21.6254 7.4297C22.1793 7.97049 22.4563 8.76848 22.4563 9.82367V19.9931C22.4563 21.0483 22.1793 21.8463 21.6254 22.3871C21.078 22.9345 20.2701 23.2081 19.2017 23.2081H4.78842ZM4.90713 21.2692H19.083C19.5381 21.2692 19.8876 21.1472 20.1316 20.9032C20.3822 20.6658 20.5075 20.3064 20.5075 19.8249V9.99184C20.5075 9.51041 20.3822 9.15098 20.1316 8.91356C19.8876 8.66955 19.5381 8.54754 19.083 8.54754H4.90713C4.44548 8.54754 4.09265 8.66955 3.84864 8.91356C3.61122 9.15098 3.49251 9.51041 3.49251 9.99184V19.8249C3.49251 20.3064 3.61122 20.6658 3.84864 20.9032C4.09265 21.1472 4.44548 21.2692 4.90713 21.2692ZM3.72004 4.99616C3.79258 4.52792 3.95416 4.16519 4.20477 3.90799C4.46197 3.65079 4.85437 3.52218 5.38197 3.52218H18.6181C19.1457 3.52218 19.5348 3.65079 19.7854 3.90799C20.0426 4.16519 20.2074 4.52792 20.28 4.99616H3.72004ZM5.7381 2.13724C5.76448 1.69538 5.90627 1.36233 6.16347 1.13811C6.42727 0.907282 6.79659 0.79187 7.27142 0.79187H16.7286C17.2034 0.79187 17.5695 0.907282 17.8267 1.13811C18.0839 1.36233 18.2323 1.69538 18.2718 2.13724H5.7381Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.3136 21.6055L17.2529 8.63648C17.5035 8.38587 17.6288 8.0858 17.6288 7.73626C17.6288 7.38673 17.5068 7.08666 17.2628 6.83605C17.0254 6.58544 16.7286 6.46014 16.3725 6.46014C16.0098 6.46014 15.7031 6.58544 15.4525 6.83605L2.51318 19.805C2.26257 20.0622 2.13726 20.3623 2.13726 20.7053C2.13726 21.0548 2.25927 21.3549 2.50328 21.6055C2.7407 21.8561 3.04078 21.9814 3.4035 21.9814C3.75963 21.988 4.06299 21.8627 4.3136 21.6055ZM12.9101 11.7526L12.3463 11.1986L15.9471 7.58788C16.0263 7.50874 16.1219 7.46917 16.234 7.46917C16.3395 7.46917 16.4318 7.50874 16.511 7.58788C16.5901 7.66702 16.6297 7.76264 16.6297 7.87476C16.6297 7.98028 16.5901 8.06931 16.511 8.14185L12.9101 11.7526ZM7.49897 9.71475C7.59789 9.71475 7.67703 9.68837 7.73639 9.63561C7.79574 9.58285 7.82872 9.51031 7.83531 9.41798C7.93424 8.82443 8.04635 8.3397 8.17165 7.96379C8.29036 7.58128 8.46183 7.27791 8.68606 7.05369C8.90369 6.82286 9.20047 6.6481 9.57638 6.52939C9.95229 6.40408 10.4436 6.29197 11.0504 6.19304C11.2548 6.16007 11.357 6.05455 11.357 5.87648C11.357 5.67864 11.2548 5.56652 11.0504 5.54014C10.437 5.45441 9.9457 5.34889 9.57638 5.22358C9.20047 5.09168 8.90369 4.91362 8.68606 4.68939C8.46843 4.46516 8.30026 4.16509 8.18155 3.78918C8.06284 3.40667 7.94742 2.91535 7.83531 2.31521C7.80234 2.11736 7.69022 2.01843 7.49897 2.01843C7.3275 2.01843 7.22198 2.12065 7.18241 2.3251C7.09008 2.91205 6.98126 3.39678 6.85596 3.77929C6.73066 4.1552 6.55919 4.45857 6.34155 4.68939C6.12392 4.91362 5.82715 5.09168 5.45123 5.22358C5.06873 5.34889 4.5708 5.45441 3.95747 5.54014C3.75962 5.56652 3.6607 5.67864 3.6607 5.87648C3.6607 6.06114 3.75962 6.16666 3.95747 6.19304C4.5774 6.28537 5.07532 6.39419 5.45123 6.51949C5.82715 6.6448 6.12392 6.81956 6.34155 7.04379C6.55259 7.26802 6.71747 7.57469 6.83617 7.96379C6.95488 8.3463 7.0703 8.83432 7.18241 9.42787C7.1956 9.51361 7.23517 9.58285 7.30112 9.63561C7.36047 9.68837 7.42642 9.71475 7.49897 9.71475ZM19.0138 17.8463C19.1786 17.8463 19.2743 17.7573 19.3007 17.5792C19.3732 17.111 19.4424 16.7417 19.5084 16.4713C19.5677 16.2009 19.6667 15.9965 19.8052 15.858C19.9371 15.7129 20.1448 15.6008 20.4284 15.5216C20.7054 15.4425 21.0978 15.3633 21.6056 15.2842C21.7771 15.2512 21.8628 15.1556 21.8628 14.9973C21.8628 14.8324 21.7738 14.7368 21.5957 14.7104C21.0945 14.6313 20.7054 14.5555 20.4284 14.4829C20.1448 14.4038 19.9371 14.2917 19.8052 14.1466C19.6667 14.0015 19.5677 13.7937 19.5084 13.5233C19.4424 13.2464 19.3732 12.877 19.3007 12.4154C19.2743 12.2373 19.1786 12.1483 19.0138 12.1483C18.8489 12.1483 18.7533 12.2373 18.7269 12.4154C18.6543 12.877 18.5851 13.2431 18.5191 13.5134C18.4532 13.7838 18.3543 13.9916 18.2224 14.1367C18.0905 14.2818 17.886 14.3939 17.609 14.473C17.3255 14.5522 16.9298 14.6313 16.422 14.7104C16.2505 14.7368 16.1647 14.8324 16.1647 14.9973C16.1647 15.1556 16.2505 15.2512 16.422 15.2842C16.9298 15.3633 17.3222 15.4425 17.5992 15.5216C17.8761 15.5942 18.0839 15.703 18.2224 15.8481C18.3543 15.9866 18.4532 16.1943 18.5191 16.4713C18.5851 16.7417 18.6543 17.111 18.7269 17.5792C18.7533 17.7573 18.8489 17.8463 19.0138 17.8463ZM15.6701 20.6954C15.7888 20.6954 15.868 20.6228 15.9075 20.4777C15.9801 20.115 16.046 19.8512 16.1054 19.6863C16.1582 19.5149 16.267 19.3962 16.4318 19.3302C16.5901 19.2643 16.877 19.1884 17.2925 19.1027C17.4244 19.0763 17.4903 19.0005 17.4903 18.8752C17.4903 18.7498 17.4211 18.6707 17.2826 18.6377C16.8737 18.5718 16.5868 18.5058 16.422 18.4399C16.2571 18.3673 16.1483 18.2486 16.0955 18.0838C16.0427 17.9123 15.9801 17.6419 15.9075 17.2726C15.868 17.1275 15.7888 17.0549 15.6701 17.0549C15.5382 17.0549 15.4591 17.1242 15.4327 17.2627C15.3668 17.6386 15.3074 17.909 15.2546 18.0739C15.2019 18.2387 15.0931 18.3542 14.9282 18.4201C14.7567 18.4861 14.4632 18.5586 14.0478 18.6377C13.9159 18.6641 13.8499 18.7433 13.8499 18.8752C13.8499 19.0005 13.9192 19.0763 14.0577 19.1027C14.4665 19.1884 14.7567 19.2643 14.9282 19.3302C15.0997 19.3962 15.2118 19.5149 15.2645 19.6863C15.3173 19.8512 15.3734 20.115 15.4327 20.4777C15.4591 20.6228 15.5382 20.6954 15.6701 20.6954Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

@@ -0,0 +1,72 @@
import { Button, useModal } from '@gouvfr-lasuite/cunningham-react';
import { DropdownMenu } from '@gouvfr-lasuite/ui-kit';
import { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { css } from 'styled-components';
import { Box, DropdownMenuOption } from '@/components';
import { useConfig } from '@/core';
import HelpOutlineIcon from '../assets/help-outline.svg';
import WandAndStarsIcon from '../assets/wand-and-stars.svg';
import { OnBoarding } from './OnBoarding';
export const HelpMenu = () => {
const { t } = useTranslation();
const [isMenuOpen, setIsMenuOpen] = useState(false);
const modalOnbording = useModal();
const { data: config } = useConfig();
const onboardingEnabled = config?.theme_customization?.onboarding?.enabled;
const toggleMenu = useCallback(() => {
setIsMenuOpen((open) => !open);
}, []);
const options = useMemo<DropdownMenuOption[]>(
() => [
{
label: t('Onboarding'),
icon: <WandAndStarsIcon aria-hidden="true" />,
callback: modalOnbording.open,
show: onboardingEnabled,
},
],
[modalOnbording.open, t, onboardingEnabled],
);
return (
<>
<Box
$css={css`
.c__dropdown-menu-trigger {
width: fit-content;
justify-content: flex-start;
}
`}
>
<DropdownMenu
options={options}
isOpen={isMenuOpen}
onOpenChange={setIsMenuOpen}
>
<Box $direction="row" $align="center">
<Button
aria-label={t('Open onboarding menu')}
color="neutral"
variant="tertiary"
iconPosition="left"
icon={<HelpOutlineIcon aria-hidden="true" />}
onClick={toggleMenu}
/>
</Box>
</DropdownMenu>
</Box>
<OnBoarding
isOpen={modalOnbording.isOpen}
onClose={modalOnbording.close}
/>
</>
);
};
@@ -0,0 +1,89 @@
import {
ModalSize,
OnboardingModal,
type OnboardingModalProps,
} from '@gouvfr-lasuite/ui-kit';
import { useTranslation } from 'react-i18next';
import { createGlobalStyle } from 'styled-components';
import { useConfig } from '@/core/config/api/useConfig';
import { useOnboardingSteps } from '../hooks/useOnboardingSteps';
const OnBoardingStyle = createGlobalStyle`
.c__onboarding-modal__steps{
height: auto;
}
.c__onboarding-modal__content {
height: 350px;
}
.c__onboarding-modal__steps {
gap: var(--c--globals--spacings--sm);
}
.c__modal__scroller {
overflow-x: hidden;
}
/* Uniform font for onboarding modal */
.c__modal:has(.c__onboarding-modal__steps),
.c__modal:has(.c__onboarding-modal__steps)
*:not(.material-icons):not(.material-icons-filled):not(
.material-symbols-outlined
) {
font-family: Marianne, Inter, Roboto Flex Variable, sans-serif;
}
/* Separator between content and footer actions/link */
.c__modal__footer {
position: relative;
border-top: 0;
padding-top: var(--c--globals--spacings--md);
}
.c__modal__footer::before {
content: '';
position: absolute;
inset: 0 calc(-1 * var(--c--globals--spacings--xl)) auto;
height: 1px;
background-color: var(--c--contextuals--border--surface--primary);
}
`;
type OnBoardingProps = {
isOpen: boolean;
onClose: () => void;
} & Partial<OnboardingModalProps>;
export const OnBoarding = (props: OnBoardingProps) => {
const { t } = useTranslation();
const { steps } = useOnboardingSteps();
const { data: config } = useConfig();
const learnMoreUrl =
config?.theme_customization?.onboarding?.learn_more_url?.trim();
return (
<>
{props.isOpen ? <OnBoardingStyle /> : null}
<OnboardingModal
size={ModalSize.LARGE}
appName={t('Discover Docs')}
mainTitle={t('Learn the core principles')}
steps={steps}
footerLink={
learnMoreUrl
? {
label: t('Learn more docs features'),
href: learnMoreUrl,
}
: undefined
}
onSkip={props.onClose}
onComplete={props.onClose}
{...props}
/>
</>
);
};
@@ -0,0 +1,49 @@
import { CSSProperties, PropsWithChildren } from 'react';
import { css } from 'styled-components';
import { Box } from '@/components';
import { tokens, useCunninghamTheme } from '@/cunningham';
type ColorToken = keyof typeof tokens.themes.default.globals.colors;
export interface OnboardingStepIconProps {
size?: string;
colorToken?: ColorToken;
color?: CSSProperties['color'];
}
export const OnboardingStepIcon = ({
size = '32px',
colorToken = 'gray-550',
color: colorCss,
children,
}: PropsWithChildren<OnboardingStepIconProps>) => {
const { colorsTokens } = useCunninghamTheme();
const color =
colorCss ??
colorsTokens[colorToken] ??
colorsTokens['gray-550'] ??
'currentColor';
return (
<Box
$css={css`
width: ${size};
height: ${size};
flex: 0 0 ${size};
display: flex;
align-items: center;
justify-content: center;
color: ${color};
svg {
width: 24px;
height: 24px;
display: block;
}
`}
>
{children}
</Box>
);
};
@@ -0,0 +1,144 @@
import { type OnboardingStep } from '@gouvfr-lasuite/ui-kit';
import Image from 'next/image';
import { useTranslation } from 'react-i18next';
import { useCunninghamTheme } from '@/cunningham';
import DragIndicatorIcon from '../assets/drag_indicator.svg';
import FileShareIcon from '../assets/file-share.svg';
import FormatTextIcon from '../assets/format-text.svg';
import StackTemplateIcon from '../assets/stack-template.svg';
import { OnboardingStepIcon } from '../components/OnboardingStepIcon';
export interface OnboardingStepsData {
steps: OnboardingStep[];
}
export const useOnboardingSteps = () => {
const { t } = useTranslation();
const { contextualTokens, colorsTokens } = useCunninghamTheme();
const activeColor =
contextualTokens.content.semantic.brand.tertiary ??
colorsTokens['brand-600'];
return {
steps: [
{
icon: (
<OnboardingStepIcon>
<DragIndicatorIcon aria-hidden="true" />
</OnboardingStepIcon>
),
activeIcon: (
<OnboardingStepIcon color={activeColor}>
<DragIndicatorIcon aria-hidden="true" />
</OnboardingStepIcon>
),
title: t('Compose your doc easily'),
description: t(
'Move, duplicate, and transform your texts, headings, lists, images without breaking your layout.',
),
content: (
<Image
src={t('src_img_onboarding_step_1', {
desc: 'URL of onboarding step 1 preview image',
defaultValue: '/assets/on-boarding/step_1_EN.gif',
})}
alt={t('Compose your doc easily')}
width={350}
height={350}
priority
unoptimized
/>
),
},
{
icon: (
<OnboardingStepIcon>
<FormatTextIcon aria-hidden="true" />
</OnboardingStepIcon>
),
activeIcon: (
<OnboardingStepIcon color={activeColor}>
<FormatTextIcon aria-hidden="true" />
</OnboardingStepIcon>
),
title: t('Format your content with the toolbar'),
description: t(
'Apply styles, structure, and emphasis in one click—keep documents clean, consistent, and easy to scan.',
),
content: (
<Image
src={t('src_img_onboarding_step_2', {
desc: 'URL of onboarding step 2 preview image',
defaultValue: '/assets/on-boarding/step_2_EN.gif',
})}
alt={t('Format your content with the toolbar')}
width={350}
height={350}
priority
unoptimized
/>
),
},
{
icon: (
<OnboardingStepIcon>
<FileShareIcon aria-hidden="true" />
</OnboardingStepIcon>
),
activeIcon: (
<OnboardingStepIcon color={activeColor}>
<FileShareIcon aria-hidden="true" />
</OnboardingStepIcon>
),
title: t('Share and collaborate with ease'),
description: t(
'Decide exactly who can view, comment, edit—or simply use shareable links.',
),
content: (
<Image
src={t('src_img_onboarding_step_3', {
desc: 'URL of onboarding step 3 preview image',
defaultValue: '/assets/on-boarding/step_3_EN.png',
})}
alt={t('Share and collaborate with ease')}
width={350}
height={350}
priority
unoptimized
/>
),
},
{
icon: (
<OnboardingStepIcon>
<StackTemplateIcon aria-hidden="true" />
</OnboardingStepIcon>
),
activeIcon: (
<OnboardingStepIcon color={activeColor}>
<StackTemplateIcon aria-hidden="true" />
</OnboardingStepIcon>
),
title: t('Draw inspiration from the content library'),
description: t(
'Start from ready-made templates for common use cases, then customize them to match your workflow in minutes.',
),
content: (
<Image
src={t('src_img_onboarding_step_4', {
desc: 'URL of onboarding step 4 preview image',
defaultValue: '/assets/on-boarding/step_4_EN.png',
})}
alt={t('Draw inspiration from the content library')}
width={350}
height={350}
priority
unoptimized
/>
),
},
],
};
};
@@ -0,0 +1,2 @@
export * from './components/HelpMenu';
export * from './components/OnBoarding';
@@ -2,9 +2,11 @@ import { useTranslation } from 'react-i18next';
import { createGlobalStyle, css } from 'styled-components';
import { Box, SeparatedSection } from '@/components';
import { useConfig } from '@/core/config/api/useConfig';
import { useCunninghamTheme } from '@/cunningham';
import { ButtonLogin } from '@/features/auth';
import { HEADER_HEIGHT } from '@/features/header/conf';
import { HelpMenu } from '@/features/help';
import { LanguagePicker } from '@/features/language';
import { useResponsiveStore } from '@/stores';
@@ -26,82 +28,96 @@ export const LeftPanel = () => {
const { spacingsTokens } = useCunninghamTheme();
const { isPanelOpen, isPanelOpenMobile } = useLeftPanelStore();
const isPanelOpenState = isDesktop ? isPanelOpen : isPanelOpenMobile;
const { data: config } = useConfig();
/**
* The onboarding can be disable, so we need to check if it's enabled before displaying the help menu.
* TODO: As soon as we get more than one fixed element in the help menu,
* we should remove this condition and display the help menu even if the onboarding is disabled
*/
const showHelpMenu = config?.theme_customization?.onboarding?.enabled;
if (isDesktop) {
return (
<Box
data-testid="left-panel-desktop"
$css={css`
height: calc(100vh - ${HEADER_HEIGHT}px);
width: 100%;
overflow: hidden;
background-color: var(--c--contextuals--background--surface--primary);
`}
className="--docs--left-panel-desktop"
as="nav"
aria-label={t('Document sections')}
>
<Box
$css={css`
flex: 0 0 auto;
`}
>
<LeftPanelHeader />
</Box>
<LeftPanelContent />
{showHelpMenu && (
<SeparatedSection showSeparator={false}>
<Box $padding={{ horizontal: 'sm' }} $justify="flex-start">
<HelpMenu />
</Box>
</SeparatedSection>
)}
</Box>
);
}
return (
<>
{isDesktop && (
{isPanelOpenState && <MobileLeftPanelStyle />}
<Box
$hasTransition
$css={css`
z-index: 999;
width: 100dvw;
height: calc(100dvh - 52px);
border-right: 1px solid var(--c--globals--colors--gray-200);
position: fixed;
transform: translateX(${isPanelOpenState ? '0' : '-100dvw'});
background-color: var(--c--contextuals--background--surface--primary);
overflow-y: auto;
overflow-x: hidden;
`}
className="--docs--left-panel-mobile"
>
<Box
data-testid="left-panel-desktop"
$css={css`
height: calc(100vh - ${HEADER_HEIGHT}px);
width: 100%;
overflow: hidden;
background-color: var(
--c--contextuals--background--surface--primary
);
`}
className="--docs--left-panel-desktop"
data-testid="left-panel-mobile"
as="nav"
aria-label={t('Document sections')}
$css={css`
width: 100%;
justify-content: center;
align-items: center;
gap: ${spacingsTokens['base']};
`}
>
<Box
$css={css`
flex: 0 0 auto;
`}
>
<LeftPanelHeader />
</Box>
<LeftPanelHeader />
<LeftPanelContent />
</Box>
)}
{!isDesktop && (
<>
{isPanelOpenState && <MobileLeftPanelStyle />}
<Box
$hasTransition
$css={css`
z-index: 999;
width: 100dvw;
height: calc(100dvh - 52px);
border-right: 1px solid var(--c--globals--colors--gray-200);
position: fixed;
transform: translateX(${isPanelOpenState ? '0' : '-100dvw'});
background-color: var(
--c--contextuals--background--surface--primary
);
overflow-y: auto;
overflow-x: hidden;
`}
className="--docs--left-panel-mobile"
>
<Box
data-testid="left-panel-mobile"
as="nav"
aria-label={t('Document sections')}
$css={css`
width: 100%;
justify-content: center;
align-items: center;
gap: ${spacingsTokens['base']};
`}
>
<LeftPanelHeader />
<LeftPanelContent />
<SeparatedSection showSeparator={false}>
<Box
$justify="center"
$align="center"
$gap={spacingsTokens['sm']}
>
<ButtonLogin />
<LanguagePicker />
</Box>
</SeparatedSection>
{showHelpMenu && (
<SeparatedSection showSeparator={false}>
<Box
$padding={{ horizontal: 'sm', vertical: 'xs' }}
$justify="flex-start"
>
<HelpMenu />
</Box>
</SeparatedSection>
)}
<SeparatedSection showSeparator={false}>
<Box $justify="center" $align="center" $gap={spacingsTokens['sm']}>
<ButtonLogin />
<LanguagePicker />
</Box>
</Box>
</>
)}
</SeparatedSection>
</Box>
</Box>
</>
);
};
@@ -768,6 +768,17 @@
"Content modal to explain why the user cannot edit": "Contenu modal pour expliquer pourquoi l'utilisateur ne peut pas modifier",
"Content modal to export the document": "Contenu modal pour exporter le document",
"Convert Markdown": "Convertir le Markdown",
"Compose your doc easily": "Rédigez votre document facilement",
"Discover Docs": "Découvrez Docs",
"Learn more docs features": "Découvrez les fonctionnalités de Docs",
"Learn the core principles": "Apprenez les principes fondamentaux",
"Move, duplicate, and transform your texts, headings, lists, images without breaking your layout.": "Déplacez, dupliquez et transformez vos textes, titres, listes, images sans casser votre mise en page.",
"Format your content with the toolbar": "Formatez votre contenu avec la barre d'outils",
"Apply styles, structure, and emphasis in one click—keep documents clean, consistent, and easy to scan.": "Appliquez styles, structure et emphase en un clic — gardez des documents propres, cohérents et faciles à parcourir",
"Share and collaborate with ease": "Partagez et collaborez en toute simplicité",
"Decide exactly who can view, comment, edit—or simply use shareable links.": "Décidez exactement qui peut voir, commenter, éditer — ou simplement utiliser des liens partageables.",
"Draw inspiration from the content library": "Tirez parti de la bibliothèque de contenu",
"Start from ready-made templates for common use cases, then customize them to match your workflow in minutes.": "Commencez à partir de modèles prêts à l'emploi pour les cas d'utilisation courants, puis personnalisez-les pour correspondre à votre flux de travail en quelques minutes.",
"Copied to clipboard": "Copié dans le presse-papier",
"Copy as {{format}}": "Copier en {{format}}",
"Copy link": "Copier le lien",
@@ -1013,6 +1024,10 @@
"Your access request for this document is pending.": "Votre demande d'accès à ce document est en attente.",
"Your current document will revert to this version.": "Votre document actuel va revenir à cette version.",
"Your {{format}} was downloaded succesfully": "Votre {{format}} a été téléchargé avec succès",
"src_img_onboarding_step_1": "/assets/on-boarding/step_1_FR.gif",
"src_img_onboarding_step_2": "/assets/on-boarding/step_2_FR.gif",
"src_img_onboarding_step_3": "/assets/on-boarding/step_3_FR.png",
"src_img_onboarding_step_4": "/assets/on-boarding/step_4_FR.png",
"days_many": "jours",
"days_one": "jour",
"days_other": "jours",