Skip to content

Commit 4953caf

Browse files
committed
feat(header): re-design share header
- Introduced enhanced scroll state management to adjust header elevation and compactness based on scroll position. - Updated the layout of the header and container components for better responsiveness and visual appeal. - Improved logo and social media links sections with animations and transitions for a more dynamic user experience. These changes aim to provide a more intuitive and visually appealing header that adapts to user interactions. Signed-off-by: Innei <[email protected]>
1 parent 072f503 commit 4953caf

File tree

2 files changed

+91
-53
lines changed

2 files changed

+91
-53
lines changed

apps/ssr/client/components/layout/header/index.tsx

Lines changed: 90 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
1-
import { siteConfig } from "@client/configs"
2-
import { openInFollowApp } from "@client/lib/helper"
31
import { Folo } from "@follow/components/icons/folo.js"
42
import { Logo } from "@follow/components/icons/logo.jsx"
53
import { SocialMediaLinks } from "@follow/constants"
64
import { cn } from "@follow/utils/utils"
75
import type { MotionValue } from "motion/react"
8-
import { useMotionValueEvent, useScroll } from "motion/react"
6+
import { m, useMotionValueEvent, useScroll } from "motion/react"
97
import * as React from "react"
108
import { useState } from "react"
11-
import { useHotkeys } from "react-hotkeys-hook"
129

1310
const useMotionValueToState = (value: MotionValue<number>) => {
1411
const [state, setState] = useState(value.get())
@@ -19,10 +16,7 @@ const useMotionValueToState = (value: MotionValue<number>) => {
1916
function Container({ className, ...props }: React.ComponentPropsWithoutRef<"div">) {
2017
return (
2118
<div
22-
className={cn(
23-
"mx-auto w-full max-w-[var(--container-max-width)] px-4 sm:px-6 lg:px-8",
24-
className,
25-
)}
19+
className={cn("mx-auto w-full max-w-[var(--container-max-width)]", className)}
2620
{...props}
2721
/>
2822
)
@@ -31,64 +25,107 @@ function Container({ className, ...props }: React.ComponentPropsWithoutRef<"div"
3125
const HeaderWrapper: Component = (props) => {
3226
const { scrollY } = useScroll()
3327
const scrollYState = useMotionValueToState(scrollY)
34-
const showOverlay = scrollYState > 100
28+
29+
// Enhanced scroll state management
30+
const isHeaderElevated = scrollYState > 20
31+
const isCompact = scrollYState > 60
3532

3633
return (
37-
<header
38-
className={cn(
39-
"fixed inset-x-0 top-0 z-50 flex h-[80px] w-full items-center px-4 duration-200 lg:px-10",
40-
showOverlay && "h-[60px]",
41-
)}
42-
>
34+
<header className={"fixed inset-x-0 top-0 z-50 transition-all duration-300 ease-out"}>
4335
<div
4436
className={cn(
45-
"absolute inset-0 transform-gpu [-webkit-backdrop-filter:saturate(180%)_blur(20px)] [backdrop-filter:saturate(180%)_blur(20px)] [backface-visibility:hidden]",
46-
"bg-[var(--bg-opacity)] duration-200 [border-bottom:1px_solid_rgb(187_187_187_/_20%)]",
37+
"mx-4 mt-4 transition-all duration-300 ease-out",
38+
isCompact ? "mt-2" : "mt-4",
39+
isHeaderElevated ? "mx-0 md:mx-4" : "px-4 sm:px-6 lg:px-8",
4740
)}
48-
style={{
49-
opacity: showOverlay ? 1 : 0,
50-
}}
51-
/>
52-
53-
{props.children}
41+
>
42+
<m.div
43+
className={cn(
44+
"rounded-xl border border-transparent px-4 transition-all duration-300 ease-out",
45+
"relative flex items-center",
46+
isCompact ? "py-2" : "py-3",
47+
isHeaderElevated && [
48+
"border-border/50 bg-background/80 px-4 shadow-lg backdrop-blur-xl md:px-0",
49+
"supports-[backdrop-filter]:bg-background/60",
50+
],
51+
)}
52+
>
53+
{props.children}
54+
</m.div>
55+
</div>
5456
</header>
5557
)
5658
}
59+
5760
export const Header = () => {
58-
const handleToApp = () => {
59-
openInFollowApp({
60-
deeplink: "",
61-
fallback: () => {
62-
return siteConfig.appUrl
63-
},
64-
fallbackUrl: siteConfig.appUrl,
65-
})
66-
}
67-
useHotkeys("l", handleToApp)
61+
const { scrollY } = useScroll()
62+
const scrollYState = useMotionValueToState(scrollY)
63+
const isCompact = scrollYState > 60
6864

6965
return (
7066
<HeaderWrapper>
71-
<Container>
72-
<nav className="relative flex justify-between">
73-
<div className="flex items-center md:gap-x-12">
74-
<a className="flex items-center gap-4" href="/">
75-
<Logo className="h-8 w-auto" />
76-
{/* <p className="font-default text-xl font-semibold">{APP_NAME}</p> */}
77-
<Folo className="size-10" />
67+
<Container className="w-full">
68+
<nav className="relative flex w-full items-center justify-between">
69+
{/* Enhanced Logo Section */}
70+
<m.div
71+
whileHover={{ scale: 1.02 }}
72+
whileTap={{ scale: 0.98 }}
73+
className="flex shrink-0 items-center"
74+
>
75+
<a
76+
className={cn(
77+
"group flex items-center gap-3 rounded-lg px-2 py-1.5 transition-all duration-200",
78+
"hover:bg-fill/30",
79+
)}
80+
href="/"
81+
>
82+
<Logo
83+
className={cn(
84+
"transition-all duration-300",
85+
isCompact ? "h-6 w-auto" : "h-8 w-auto",
86+
)}
87+
/>
88+
<Folo
89+
className={cn("transition-all duration-300", isCompact ? "size-7" : "size-10")}
90+
/>
7891
</a>
79-
</div>
80-
<div className="flex flex-wrap items-center gap-6 text-2xl">
81-
{SocialMediaLinks.map((link) => (
82-
<a
83-
href={link.url}
84-
key={link.url}
85-
target="_blank"
86-
rel="noreferrer"
87-
className="flex items-center"
88-
>
89-
<i className={link.iconClassName} />
90-
</a>
91-
))}
92+
</m.div>
93+
94+
{/* Enhanced Social Links Section */}
95+
<div className="flex shrink-0 items-center">
96+
<div
97+
className={cn(
98+
"flex items-center gap-2 transition-all duration-300",
99+
isCompact ? "gap-1 text-xl" : "gap-2 text-2xl",
100+
)}
101+
>
102+
{SocialMediaLinks.map((link) => (
103+
<m.a
104+
key={link.url}
105+
href={link.url}
106+
target="_blank"
107+
rel="noreferrer"
108+
whileHover={{ scale: 1.1, y: -1 }}
109+
whileTap={{ scale: 0.95 }}
110+
className={cn(
111+
"group relative flex items-center justify-center rounded-lg",
112+
"text-text-secondary hover:text-text",
113+
"hover:bg-fill/40 active:bg-fill/60",
114+
isCompact ? "size-8" : "size-10",
115+
)}
116+
>
117+
<i
118+
className={cn(
119+
link.iconClassName,
120+
"transition-transform duration-200 group-hover:scale-110",
121+
)}
122+
/>
123+
124+
{/* Subtle hover effect */}
125+
<div className="from-blue/10 to-purple/10 absolute inset-0 rounded-lg bg-gradient-to-r opacity-0 transition-opacity duration-200 group-hover:opacity-100" />
126+
</m.a>
127+
))}
128+
</div>
92129
</div>
93130
</nav>
94131
</Container>

apps/ssr/client/query/list.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ const fetchListById = async (id: string) => {
66
const res = await apiClient.lists.$get({ query: { listId: id } })
77
return res.data
88
}
9+
910
export const useList = ({ id }: { id?: string }) =>
1011
useQuery({
1112
queryKey: ["lists", id],

0 commit comments

Comments
 (0)