Skip to content

Commit 59e67bd

Browse files
committed
animated banner
1 parent 9008005 commit 59e67bd

3 files changed

Lines changed: 119 additions & 66 deletions

File tree

src/components/AILibraryHero.tsx

Lines changed: 84 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ import {
3636
SERVICE_Y_OFFSET,
3737
SERVICE_Y_CENTER,
3838
SERVICE_HEIGHT,
39+
LIBRARY_CARD_WIDTH,
40+
LIBRARY_CARD_HEIGHT,
41+
LIBRARY_CARD_LOCATIONS,
42+
SERVER_CARD_Y_OFFSET,
43+
SERVER_CARD_LOCATIONS,
44+
SERVER_CARD_WIDTH,
45+
SERVER_CARD_HEIGHT,
3946
} from '~/stores/aiLibraryHeroAnimation'
4047

4148
// Get the store instance for accessing getState in closures
@@ -507,7 +514,7 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) {
507514
<div className="relative flex flex-col items-center gap-8 text-center px-4 overflow-visible">
508515
{/* Diagram and Chat Panel Container */}
509516
<div
510-
className="relative z-10 w-full max-w-7xl mx-auto mt-16 flex flex-row flex-wrap gap-8 lg:gap-12"
517+
className="relative z-10 w-full max-w-7xl mx-auto flex flex-row flex-wrap gap-8 lg:gap-12"
511518
style={{ height: SVG_HEIGHT }}
512519
>
513520
{/* SVG Diagram */}
@@ -775,67 +782,83 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) {
775782

776783
{/* Top layer: Frameworks */}
777784
<AILibraryHeroCard
778-
x={0}
785+
x={LIBRARY_CARD_LOCATIONS[0]}
779786
y={0}
780-
width={120}
781-
height={60}
787+
width={LIBRARY_CARD_WIDTH}
788+
height={LIBRARY_CARD_HEIGHT}
782789
label="Vanilla"
783790
opacity={getOpacity(0, selectedFramework, rotatingFramework)}
784791
textColor={textColor}
785792
strokeColor={strokeColor}
786793
fontSize={BOX_FONT_SIZE}
787794
fontWeight={BOX_FONT_WEIGHT}
788795
logo={tsLogo}
789-
transform={
790-
selectedFramework === 0
791-
? 'translate(60, 30) scale(1.1) translate(-60, -30)'
792-
: ''
793-
}
796+
transform={getScaleTransform(
797+
0,
798+
selectedFramework,
799+
LIBRARY_CARD_LOCATIONS[0] + LIBRARY_CARD_WIDTH / 2,
800+
LIBRARY_CARD_HEIGHT / 2
801+
)}
794802
/>
795803

796804
<AILibraryHeroCard
797-
x={160}
805+
x={LIBRARY_CARD_LOCATIONS[1]}
798806
y={0}
799-
width={120}
800-
height={60}
807+
width={LIBRARY_CARD_WIDTH}
808+
height={LIBRARY_CARD_HEIGHT}
801809
label="React"
802810
opacity={getOpacity(1, selectedFramework, rotatingFramework)}
803811
textColor={textColor}
804812
strokeColor={strokeColor}
805813
fontSize={BOX_FONT_SIZE}
806814
fontWeight={BOX_FONT_WEIGHT}
807815
logo={reactLogo}
808-
transform={getScaleTransform(1, selectedFramework, 220, 30)}
816+
transform={getScaleTransform(
817+
1,
818+
selectedFramework,
819+
LIBRARY_CARD_LOCATIONS[1] + LIBRARY_CARD_WIDTH / 2,
820+
LIBRARY_CARD_HEIGHT / 2
821+
)}
809822
/>
810823

811824
<AILibraryHeroCard
812-
x={320}
825+
x={LIBRARY_CARD_LOCATIONS[2]}
813826
y={0}
814-
width={120}
815-
height={60}
827+
width={LIBRARY_CARD_WIDTH}
828+
height={LIBRARY_CARD_HEIGHT}
816829
label="Solid"
817830
opacity={getOpacity(2, selectedFramework, rotatingFramework)}
818831
textColor={textColor}
819832
strokeColor={strokeColor}
820833
fontSize={BOX_FONT_SIZE}
821834
fontWeight={BOX_FONT_WEIGHT}
822835
logo={solidLogo}
823-
transform={getScaleTransform(2, selectedFramework, 380, 30)}
836+
transform={getScaleTransform(
837+
2,
838+
selectedFramework,
839+
LIBRARY_CARD_LOCATIONS[2] + LIBRARY_CARD_WIDTH / 2,
840+
LIBRARY_CARD_HEIGHT / 2
841+
)}
824842
/>
825843

826844
<AILibraryHeroCard
827-
x={480}
845+
x={LIBRARY_CARD_LOCATIONS[3]}
828846
y={0}
829-
width={120}
830-
height={60}
847+
width={LIBRARY_CARD_WIDTH}
848+
height={LIBRARY_CARD_HEIGHT}
831849
label="?"
832850
opacity={getOpacity(3, selectedFramework, rotatingFramework)}
833851
textColor={textColor}
834852
strokeColor={strokeColor}
835853
fontSize={BOX_FONT_SIZE}
836854
fontWeight={BOX_FONT_WEIGHT}
837855
isDashed={true}
838-
transform={getScaleTransform(3, selectedFramework, 540, 30)}
856+
transform={getScaleTransform(
857+
3,
858+
selectedFramework,
859+
LIBRARY_CARD_LOCATIONS[3] + LIBRARY_CARD_WIDTH / 2,
860+
LIBRARY_CARD_HEIGHT / 2
861+
)}
839862
/>
840863

841864
{/* @tanstack/ai-client box */}
@@ -1012,25 +1035,30 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) {
10121035

10131036
{/* Server layer */}
10141037
<AILibraryHeroCard
1015-
x={0}
1016-
y={370}
1017-
width={120}
1018-
height={60}
1038+
x={SERVER_CARD_LOCATIONS[0]}
1039+
y={SERVER_CARD_Y_OFFSET}
1040+
width={SERVER_CARD_WIDTH}
1041+
height={SERVER_CARD_HEIGHT}
10191042
label="TypeScript"
10201043
opacity={getOpacity(0, selectedServer, rotatingServer)}
10211044
textColor={textColor}
10221045
strokeColor={strokeColor}
10231046
fontSize={16}
10241047
fontWeight={BOX_FONT_WEIGHT}
10251048
logo={tsLogo}
1026-
transform={getScaleTransform(0, selectedServer, 60, 400)}
1049+
transform={getScaleTransform(
1050+
0,
1051+
selectedServer,
1052+
SERVER_CARD_LOCATIONS[0] + SERVER_CARD_WIDTH / 2,
1053+
SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2
1054+
)}
10271055
/>
10281056

10291057
<AILibraryHeroCard
1030-
x={160}
1031-
y={370}
1032-
width={120}
1033-
height={60}
1058+
x={SERVER_CARD_LOCATIONS[1]}
1059+
y={SERVER_CARD_Y_OFFSET}
1060+
width={SERVER_CARD_WIDTH}
1061+
height={SERVER_CARD_HEIGHT}
10341062
label="PHP"
10351063
opacity={getOpacity(1, selectedServer, rotatingServer)}
10361064
textColor={textColor}
@@ -1039,37 +1067,52 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) {
10391067
fontWeight={BOX_FONT_WEIGHT}
10401068
logoLight={phpLightLogo}
10411069
logoDark={phpDarkLogo}
1042-
transform={getScaleTransform(1, selectedServer, 220, 400)}
1070+
transform={getScaleTransform(
1071+
1,
1072+
selectedServer,
1073+
SERVER_CARD_LOCATIONS[1] + SERVER_CARD_WIDTH / 2,
1074+
SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2
1075+
)}
10431076
/>
10441077

10451078
<AILibraryHeroCard
1046-
x={320}
1047-
y={370}
1048-
width={120}
1049-
height={60}
1079+
x={SERVER_CARD_LOCATIONS[2]}
1080+
y={SERVER_CARD_Y_OFFSET}
1081+
width={SERVER_CARD_WIDTH}
1082+
height={SERVER_CARD_HEIGHT}
10501083
label="Python"
10511084
opacity={getOpacity(2, selectedServer, rotatingServer)}
10521085
textColor={textColor}
10531086
strokeColor={strokeColor}
10541087
fontSize={BOX_FONT_SIZE}
10551088
fontWeight={BOX_FONT_WEIGHT}
10561089
logo={pythonLogo}
1057-
transform={getScaleTransform(2, selectedServer, 380, 400)}
1090+
transform={getScaleTransform(
1091+
2,
1092+
selectedServer,
1093+
SERVER_CARD_LOCATIONS[2] + SERVER_CARD_WIDTH / 2,
1094+
SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2
1095+
)}
10581096
/>
10591097

10601098
<AILibraryHeroCard
1061-
x={480}
1062-
y={370}
1063-
width={120}
1064-
height={60}
1099+
x={SERVER_CARD_LOCATIONS[3]}
1100+
y={SERVER_CARD_Y_OFFSET}
1101+
width={SERVER_CARD_WIDTH}
1102+
height={SERVER_CARD_HEIGHT}
10651103
label="?"
10661104
opacity={getOpacity(3, selectedServer, rotatingServer)}
10671105
textColor={textColor}
10681106
strokeColor={strokeColor}
10691107
fontSize={BOX_FONT_SIZE}
10701108
fontWeight={BOX_FONT_WEIGHT}
10711109
isDashed={true}
1072-
transform={getScaleTransform(3, selectedServer, 540, 400)}
1110+
transform={getScaleTransform(
1111+
3,
1112+
selectedServer,
1113+
SERVER_CARD_LOCATIONS[3] + SERVER_CARD_WIDTH / 2,
1114+
SERVER_CARD_Y_OFFSET + SERVER_CARD_HEIGHT / 2
1115+
)}
10731116
/>
10741117
</svg>
10751118
</div>
@@ -1082,31 +1125,6 @@ export function AILibraryHero({ project, cta, actions }: AILibraryHeroProps) {
10821125
/>
10831126
</div>
10841127
</div>
1085-
1086-
{/* Content overlay */}
1087-
<div className="relative z-10 flex flex-col items-center gap-6 mt-8">
1088-
<h2 className="font-bold text-2xl md:text-4xl max-w-xl xl:max-w-4xl text-balance [letter-spacing:-0.03em]">
1089-
{project.tagline}
1090-
</h2>
1091-
{project.description ? (
1092-
<p className="text opacity-90 max-w-lg xl:max-w-2xl lg:text-base text-balance">
1093-
{project.description}
1094-
</p>
1095-
) : null}
1096-
{actions ? (
1097-
<div>{actions}</div>
1098-
) : cta ? (
1099-
<Link
1100-
{...cta.linkProps}
1101-
className={twMerge(
1102-
'inline-block py-2 px-4 rounded uppercase font-extrabold transition-colors',
1103-
cta.className
1104-
)}
1105-
>
1106-
{cta.label}
1107-
</Link>
1108-
) : null}
1109-
</div>
11101128
</div>
11111129
</>
11121130
)

src/routes/_libraries/ai.$version.index.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { getLibrary } from '~/libraries'
1010
import { LibraryFeatureHighlights } from '~/components/LibraryFeatureHighlights'
1111
import LandingPageGad from '~/components/LandingPageGad'
1212
import OpenSourceStats, { ossStatsQuery } from '~/components/OpenSourceStats'
13+
import { LibraryHero } from '~/components/LibraryHero'
1314

1415
const library = getLibrary('ai')
1516

@@ -33,6 +34,17 @@ function AIVersionIndex() {
3334
return (
3435
<>
3536
<div className="flex flex-col gap-20 md:gap-32 max-w-full pt-32">
37+
<LibraryHero
38+
project={aiProject}
39+
cta={{
40+
linkProps: {
41+
to: '/$libraryId/$version/docs',
42+
params: { libraryId: library.id, version },
43+
},
44+
label: 'Get Started',
45+
className: 'bg-pink-500 text-white',
46+
}}
47+
/>
3648
<AILibraryHero
3749
project={aiProject}
3850
cta={{

src/stores/aiLibraryHeroAnimation.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,29 @@ export const SERVICE_Y_OFFSET = 265
2828
export const SERVICE_HEIGHT = 40
2929
export const SERVICE_Y_CENTER = SERVICE_Y_OFFSET + SERVICE_HEIGHT / 2
3030

31+
export const LIBRARY_CARD_WIDTH = 140
32+
export const LIBRARY_CARD_HEIGHT = 60
33+
export const LIBRARY_CARD_GUTTER = 20
34+
const LIBRARY_CARD_START_X = -20
35+
export const LIBRARY_CARD_LOCATIONS = [0, 1, 2, 3].map(
36+
(index) =>
37+
LIBRARY_CARD_START_X +
38+
index * (LIBRARY_CARD_WIDTH + LIBRARY_CARD_GUTTER) +
39+
LIBRARY_CARD_GUTTER / 2
40+
)
41+
42+
export const SERVER_CARD_WIDTH = 140
43+
export const SERVER_CARD_HEIGHT = 60
44+
export const SERVER_CARD_GUTTER = 20
45+
const SERVER_CARD_START_X = -20
46+
export const SERVER_CARD_LOCATIONS = [0, 1, 2, 3].map(
47+
(index) =>
48+
SERVER_CARD_START_X +
49+
index * (SERVER_CARD_WIDTH + SERVER_CARD_GUTTER) +
50+
SERVER_CARD_GUTTER / 2
51+
)
52+
export const SERVER_CARD_Y_OFFSET = 370
53+
3154
export type ChatMessage = {
3255
id: string
3356
user: string

0 commit comments

Comments
 (0)