Refactor onboarding welcome screen to v2 design (#5262)

* refactor onboarding home page to v2 design

* fixc typography and buttons

* refactor useTheme to return isLight variable | call useTheme from inside SVG component | apply light mode background gradient | polish styles to match designs

* add welcome i18n

* simplify isLight variable

* add new welcome translation key to locales

* delete unused images

* move OnboardingLogoSVG into module | compute isLight directly in component

* add type button | add border-none | add hover state

* update hook with doc

---------

Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
This commit is contained in:
Marcello Fitton 2026-03-24 22:06:58 -07:00 committed by GitHub
parent 7e9737dd86
commit e9883f4d09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 165 additions and 52 deletions

View File

@ -7,10 +7,22 @@ const availableThemes = {
dark: "Dark",
};
/**
* @typedef {'system' | 'light' | 'dark'} ThemeOption
*/
/**
* @typedef {Object} UseThemeResult
* @property {ThemeOption} theme - The current theme preference stored in localStorage.
* @property {(newTheme: ThemeOption) => void} setTheme - Sets the theme preference.
* @property {{system: string, light: string, dark: string}} availableThemes - Map of theme keys to display names.
* @property {boolean} isLight - Whether the resolved theme is light (explicitly or via system preference).
*/
/**
* Determines the current theme of the application.
* "system" follows the OS preference, "light" and "dark" force that mode.
* @returns {{theme: ('system' | 'light' | 'dark'), setTheme: function, availableThemes: object}}
* @returns {UseThemeResult}
*/
export function useTheme() {
const [theme, _setTheme] = useState(() => {
@ -59,11 +71,16 @@ export function useTheme() {
/**
* Sets the theme of the application and runs any
* other necessary side effects
* @param {string} newTheme The new theme to set
* @param {ThemeOption} newTheme The new theme to set
*/
function setTheme(newTheme) {
_setTheme(newTheme);
}
return { theme, setTheme, availableThemes };
return {
theme,
setTheme,
availableThemes,
isLight: resolvedTheme === "light",
};
}

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "مرحبا في",
getStarted: "بسم الله",
welcome: null,
},
llm: {
title: "إعدادات نموذج التعلم العميق المفضّلة",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Vítejte v",
getStarted: "Začít",
welcome: null,
},
llm: {
title: "Preferovaný LLM",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Velkommen til",
getStarted: "Kom godt i gang",
welcome: null,
},
llm: {
title: "LLM-præference",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Willkommen bei",
getStarted: "Jetzt starten",
welcome: null,
},
llm: {
title: "LLM-Einstellung",

View File

@ -2,6 +2,7 @@ const TRANSLATIONS = {
onboarding: {
home: {
title: "Welcome to",
welcome: "Welcome",
getStarted: "Get Started",
},
llm: {

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Bienvenido a",
getStarted: "Comenzar",
welcome: null,
},
llm: {
title: "Preferencia de LLM",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Tere tulemast",
getStarted: "Alusta",
welcome: null,
},
llm: {
title: "LLM-i eelistus",

View File

@ -19,6 +19,7 @@ const TRANSLATIONS = {
home: {
title: "به",
getStarted: "شروع کنید",
welcome: null,
},
llm: {
title: "ترجیحات مدل‌های زبان بزرگ",

View File

@ -18,6 +18,7 @@ const TRANSLATIONS = {
home: {
title: "Bienvenue",
getStarted: "Commencer",
welcome: null,
},
llm: {
title: "Préférence LLM",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "ברוכים הבאים ל",
getStarted: "להתחלה",
welcome: null,
},
llm: {
title: "העדפות מודל שפה (LLM)",

View File

@ -19,6 +19,7 @@ const TRANSLATIONS = {
home: {
title: "Benvenuti a",
getStarted: "Inizia",
welcome: null,
},
llm: {
title: "Preferenza per i modelli LLM",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "ようこそ",
getStarted: "はじめる",
welcome: null,
},
llm: {
title: "LLMの設定",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "방문을 환영합니다",
getStarted: "시작하기",
welcome: null,
},
llm: {
title: "LLM 기본 설정",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Sveiki atvykę į",
getStarted: "Pradėti",
welcome: null,
},
llm: {
title: "LLM pasirinkimas",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Laipni lūgti",
getStarted: "Sākt darbu",
welcome: null,
},
llm: {
title: "LLM preferences",

View File

@ -19,6 +19,7 @@ const TRANSLATIONS = {
home: {
title: "Welkom bij",
getStarted: "Aan de slag",
welcome: null,
},
llm: {
title: "LLM-voorkeuren",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Witamy w",
getStarted: "Rozpocznij",
welcome: null,
},
llm: {
title: "Preferencje modeli językowych",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Bem-vindo ao",
getStarted: "Começar",
welcome: null,
},
llm: {
title: "Preferência de LLM",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Bine ai venit la",
getStarted: "Începe",
welcome: null,
},
llm: {
title: "Preferința LLM",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "Добро пожаловать в",
getStarted: "Начать",
welcome: null,
},
llm: {
title: "Предпочитаемые LLM",

View File

@ -19,6 +19,7 @@ const TRANSLATIONS = {
home: {
title: "Hoş Geldiniz",
getStarted: "Başla",
welcome: null,
},
llm: {
title: "LLM Tercihi",

View File

@ -19,6 +19,7 @@ const TRANSLATIONS = {
home: {
title: "Chào mừng đến",
getStarted: "Bắt đầu",
welcome: null,
},
llm: {
title: "Tùy chọn LLM",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "欢迎使用",
getStarted: "开始",
welcome: null,
},
llm: {
title: "LLM 偏好",

View File

@ -4,6 +4,7 @@ const TRANSLATIONS = {
home: {
title: "歡迎使用",
getStarted: "開始使用",
welcome: null,
},
llm: {
title: "LLM 偏好",

View File

@ -0,0 +1,80 @@
import { useTheme } from "@/hooks/useTheme";
export function OnboardingLogoSVG() {
const { isLight } = useTheme();
return (
<svg
viewBox="0 0 818 514"
fill="none"
xmlns="http://www.w3.org/2000/svg"
className="w-full h-auto"
>
<g filter="url(#filter0_i_onboarding)">
<path
d="M817.643 77.9966V435.862C817.643 478.86 782.656 513.847 739.646 513.847H598.7C575.046 513.847 552.952 503.3 538.072 484.907L478.122 410.756C470.908 401.84 470.837 389.328 477.943 380.329L499.609 352.901C504.264 347.009 511.228 343.628 518.739 343.628C526.251 343.628 533.143 346.973 537.798 352.818L595.593 425.47C598.391 428.969 602.557 430.981 607.033 430.981H715.243C726.004 430.981 734.766 422.22 734.766 411.458V102.4C734.766 91.627 726.004 82.8773 715.243 82.8773H606.938C602.462 82.8773 598.295 84.8773 595.498 88.3771L279.643 484.479C264.75 503.145 242.525 513.847 218.657 513.847H77.9847C34.9866 513.847 0 478.86 0 435.862V77.9966C0 34.9866 34.9866 0 77.9847 0H219.681C243.716 0 266.036 10.8329 280.928 29.7249L338.426 103.115C345.437 112.019 345.425 124.435 338.39 133.328L316.57 160.898C311.927 166.767 304.963 170.147 297.463 170.147C289.964 170.147 283.059 166.802 278.405 160.957L220.764 88.3771C217.979 84.8773 213.812 82.8773 209.336 82.8773H102.388C91.627 82.8773 82.8654 91.627 82.8654 102.4V411.458C82.8654 422.22 91.627 430.981 102.388 430.981H209.289C213.765 430.981 217.931 428.969 220.717 425.482L536.727 29.3559C551.607 10.7019 573.832 0 597.7 0H739.646C782.656 0 817.643 34.9866 817.643 77.9966Z"
fill="url(#paint0_linear_onboarding)"
fillOpacity={isLight ? 0.5 : 0.28}
/>
</g>
<defs>
<filter
id="filter0_i_onboarding"
x="0"
y="0"
width="817.643"
height="525.847"
filterUnits="userSpaceOnUse"
colorInterpolationFilters="sRGB"
>
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend
mode="normal"
in="SourceGraphic"
in2="BackgroundImageFix"
result="shape"
/>
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha"
/>
<feOffset dy="12" />
<feGaussianBlur stdDeviation="6" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0"
/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow" />
</filter>
<linearGradient
id="paint0_linear_onboarding"
x1="15.9568"
y1="-4.97115"
x2="720.527"
y2="514.346"
gradientUnits="userSpaceOnUse"
>
{isLight ? (
<>
<stop stopColor="#B0BAC5" />
<stop offset="0.538462" stopColor="#FFFFFF" stopOpacity="0.4" />
<stop offset="1" stopColor="#A8B0BE" />
</>
) : (
<>
<stop stopColor="#3C5769" />
<stop
offset="0.538462"
stopColor="#9FA5C2"
stopOpacity="0.253846"
/>
<stop offset="1" stopColor="#40435E" />
</>
)}
</linearGradient>
</defs>
</svg>
);
}

View File

@ -1,64 +1,56 @@
import paths from "@/utils/paths";
import LGroupImg from "./l_group.png";
import RGroupImg from "./r_group.png";
import LGroupImgLight from "./l_group-light.png";
import RGroupImgLight from "./r_group-light.png";
import AnythingLLMLogo from "@/media/logo/anything-llm.png";
import { useNavigate } from "react-router-dom";
import { useTheme } from "@/hooks/useTheme";
import { useTranslation } from "react-i18next";
import useRedirectToHomeOnOnboardingComplete from "@/hooks/useOnboardingComplete";
const IMG_SRCSET = {
light: {
l: LGroupImgLight,
r: RGroupImgLight,
},
default: {
l: LGroupImg,
r: RGroupImg,
},
};
import { OnboardingLogoSVG } from "./components/OnboardingLogoSVG";
export default function OnboardingHome() {
const navigate = useNavigate();
useRedirectToHomeOnOnboardingComplete();
const { theme } = useTheme();
const { t } = useTranslation();
const srcSet = IMG_SRCSET?.[theme] || IMG_SRCSET.default;
return (
<>
<div className="relative w-screen h-screen flex overflow-hidden bg-theme-bg-primary">
<div
className="hidden md:block fixed bottom-10 left-10 w-[320px] h-[320px] bg-no-repeat bg-contain"
style={{ backgroundImage: `url(${srcSet.l})` }}
></div>
<div className="relative w-screen h-screen flex flex-col overflow-hidden bg-zinc-950 light:bg-slate-50">
{/* Dark mode background gradient */}
<div
className="absolute inset-0 light:hidden"
style={{
background:
"radial-gradient(ellipse 160% 100% at 50% 0%, rgba(130, 152, 178, 0.45) 0%, rgba(60, 87, 105, 0.25) 45%, transparent 90%)",
}}
/>
{/* Light mode background gradient */}
<div
className="absolute inset-0 hidden light:block"
style={{
background:
"radial-gradient(ellipse 160% 100% at 50% 0%, rgba(176, 200, 224, 0.7) 0%, rgba(195, 213, 230, 0.45) 50%, transparent 90%)",
}}
/>
<div
className="hidden md:block fixed top-10 right-10 w-[320px] h-[320px] bg-no-repeat bg-contain"
style={{ backgroundImage: `url(${srcSet.r})` }}
></div>
<div className="relative flex justify-center items-center m-auto">
<div className="flex flex-col justify-center items-center">
<p className="text-theme-text-primary font-thin text-[24px]">
{t("onboarding.home.title")}
</p>
<img
src={AnythingLLMLogo}
alt="AnythingLLM"
className="md:h-[50px] flex-shrink-0 max-w-[300px] light:invert"
/>
<button
onClick={() => navigate(paths.onboarding.llmPreference())}
className="border-[2px] border-theme-text-primary animate-pulse light:animate-none w-full md:max-w-[350px] md:min-w-[300px] text-center py-3 bg-theme-button-primary hover:bg-theme-bg-secondary text-theme-text-primary font-semibold text-sm my-10 rounded-md "
>
{t("onboarding.home.getStarted")}
</button>
</div>
</div>
<div className="relative z-10 flex justify-center pt-[58px]">
<p className="text-white/80 light:text-slate-600 text-3xl font-semibold">
AnythingLLM
</p>
</div>
</>
<div className="relative z-10 flex-1 flex flex-col items-center justify-center -mt-8">
<div className="absolute flex items-center justify-center w-full px-4 md:px-0 md:max-w-[852px] md:w-[56%]">
<OnboardingLogoSVG />
</div>
<h1 className="relative font-medium text-white light:text-slate-700 text-[64px] md:text-[96px] lg:text-[160px] leading-none tracking-[-0.06em] select-none">
{t("onboarding.home.welcome")}
</h1>
<button
type="button"
onClick={() => navigate(paths.onboarding.llmPreference())}
className="relative border-none z-10 h-[36px] w-[300px] py-2.5 px-5 rounded-lg bg-slate-50 hover:bg-slate-300 font-medium text-sm mt-[42px] text-zinc-900 light:text-white light:bg-slate-900 light:hover:bg-slate-800 text-center flex justify-center items-center transition-colors duration-200"
>
{t("onboarding.home.getStarted")}
</button>
</div>
</div>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB