@@ -6,38 +6,45 @@ import { useBlueskyStore } from '../lib/bluesky/store';
6
6
import { BellIcon , HomeIcon , LogInIcon , MailIcon , SearchIcon , SettingsIcon , UserIcon } from 'lucide-react' ;
7
7
import { CreatePost } from './CreatePost' ;
8
8
import { cn } from '@/lib/utils' ;
9
- import { appName } from '@/config' ;
10
9
import { useQueryClient } from '@tanstack/react-query' ;
11
10
import { useUnreadCount } from '@/lib/bluesky/hooks/useUnreadCount' ;
12
11
import { useConversations } from '@/lib/bluesky/hooks/useConversations' ;
12
+ import { useScollVisible } from '@/hooks/useScrollVisible' ;
13
+ import { Avatar } from './ui/avatar' ;
14
+ import { useProfile } from '@/lib/bluesky/hooks/useProfile' ;
13
15
14
16
const HomeLink = ( ) => {
17
+ const { t } = useTranslation ( 'app' ) ;
15
18
const location = useLocation ( ) ;
16
19
const queryClient = useQueryClient ( ) ;
17
20
return (
18
21
< Link
19
22
to = "/"
20
- onClick = { ( ) => {
23
+ onClick = { async ( ) => {
21
24
// if we're on the homepage already we need to invalidate the associated query
22
25
if ( location . pathname === '/' ) {
23
26
// @TODO : we should really be invalidating the query for the current feed not all feeds
24
- queryClient . invalidateQueries ( {
27
+ await queryClient . invalidateQueries ( {
25
28
queryKey : [ 'feed' ] ,
26
29
} ) ;
27
30
}
28
31
} }
32
+ className = "flex flex-row items-center gap-2 p-3 rounded-sm hover:no-underline hover:bg-gray-200 dark:hover:bg-gray-700"
29
33
>
30
- < HomeIcon className = "size-7 xl:hidden " />
31
- < h1 className = "text-2xl font-bold hidden xl:block" > { appName } </ h1 >
34
+ < HomeIcon className = "size-7 xl:size-6 active:scale-90 " />
35
+ < span className = "hidden xl:block" > { t ( 'home' ) } </ span >
32
36
</ Link >
33
37
) ;
34
38
} ;
35
39
36
40
const SearchLink = ( ) => {
37
41
const { t } = useTranslation ( 'search' ) ;
38
42
return (
39
- < Link to = "/search" >
40
- < SearchIcon className = "size-7 xl:hidden" />
43
+ < Link
44
+ to = "/search"
45
+ className = "flex flex-row items-center gap-2 p-3 rounded-sm hover:no-underline hover:bg-gray-200 dark:hover:bg-gray-700"
46
+ >
47
+ < SearchIcon className = "size-7 xl:size-6 active:scale-90" />
41
48
< span className = "hidden xl:block" > { t ( 'search' ) } </ span >
42
49
</ Link >
43
50
) ;
@@ -48,9 +55,12 @@ const MessagesLink = () => {
48
55
const { data : convos } = useConversations ( ) ;
49
56
const unreadCount = convos ?. map ( ( convo ) => convo . unreadCount ) . reduce ( ( a , b ) => a + b , 0 ) ?? 0 ;
50
57
return (
51
- < Link to = "/messages" >
52
- < div className = "relative" >
53
- < MailIcon className = "size-7 xl:hidden" />
58
+ < Link
59
+ to = "/messages"
60
+ className = "flex flex-row items-center gap-2 p-3 rounded-sm hover:no-underline hover:bg-gray-200 dark:hover:bg-gray-700"
61
+ >
62
+ < div className = "relative active:scale-90" >
63
+ < MailIcon className = "size-7 xl:size-6" />
54
64
{ unreadCount > 0 && (
55
65
< span className = "absolute top-0 right-0 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-red-100 bg-blue-500 rounded-full transform translate-x-1/2 -translate-y-1/2" >
56
66
{ unreadCount }
@@ -66,9 +76,12 @@ const NotificationsLink = () => {
66
76
const { t } = useTranslation ( 'notifications' ) ;
67
77
const { data : unreadCount } = useUnreadCount ( ) ;
68
78
return (
69
- < Link to = "/notifications" >
79
+ < Link
80
+ to = "/notifications"
81
+ className = "flex flex-row items-center gap-2 p-3 rounded-sm hover:no-underline hover:bg-gray-200 dark:hover:bg-gray-700"
82
+ >
70
83
< div className = "relative" >
71
- < BellIcon className = "size-7 xl:hidden " />
84
+ < BellIcon className = "size-7 xl:size-6 active:scale-90 " />
72
85
{ unreadCount > 0 && (
73
86
< span className = "absolute top-0 right-0 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-red-100 bg-blue-500 rounded-full transform translate-x-1/2 -translate-y-1/2" >
74
87
{ unreadCount }
@@ -92,8 +105,9 @@ const ProfileLink = () => {
92
105
params = { {
93
106
handle : session ?. handle ,
94
107
} }
108
+ className = "flex flex-row items-center gap-2 p-3 rounded-sm hover:no-underline hover:bg-gray-200 dark:hover:bg-gray-700"
95
109
>
96
- < UserIcon className = "size-7 xl:hidden " />
110
+ < UserIcon className = "size-7 xl:size-6 active:scale-90 " />
97
111
< span className = "hidden xl:block" > { t ( 'profile' ) } </ span >
98
112
</ Link >
99
113
) ;
@@ -102,8 +116,11 @@ const ProfileLink = () => {
102
116
const SettingsLink = ( ) => {
103
117
const { t } = useTranslation ( 'app' ) ;
104
118
return (
105
- < Link to = "/settings" >
106
- < SettingsIcon className = "size-7 xl:hidden" />
119
+ < Link
120
+ to = "/settings"
121
+ className = "flex flex-row items-center gap-2 p-3 rounded-sm hover:no-underline hover:bg-gray-200 dark:hover:bg-gray-700"
122
+ >
123
+ < SettingsIcon className = "size-7 xl:size-6 active:scale-90" />
107
124
< span className = "hidden xl:block" > { t ( 'settings' ) } </ span >
108
125
</ Link >
109
126
) ;
@@ -113,7 +130,7 @@ const LoginButton = () => {
113
130
const { t } = useTranslation ( 'auth' ) ;
114
131
return (
115
132
< Link to = "/login" >
116
- < LogInIcon className = "size-7 xl:hidden" />
133
+ < LogInIcon className = "size-7 xl:hidden active:scale-90 " />
117
134
< span className = "hidden xl:block" > { t ( 'login.default' ) } </ span >
118
135
</ Link >
119
136
) ;
@@ -122,19 +139,26 @@ const LoginButton = () => {
122
139
export const Navbar = ( ) => {
123
140
const { isAuthenticated } = useAuth ( ) ;
124
141
const location = useLocation ( ) ;
142
+ const isVisible = useScollVisible ( ) ;
143
+ const handle = useBlueskyStore ( ( state ) => state . session ?. handle ) ;
144
+ const { data : profile } = useProfile ( { handle } ) ;
125
145
126
146
return (
127
147
< div
128
148
className = { cn (
129
- 'bg-background text-foreground' ,
149
+ 'bg-background text-foreground sticky ' ,
130
150
// base
131
- 'px-4 pt-1 z-50 ' ,
151
+ 'px-4 pt-1 z-40 ' ,
132
152
// mobile
133
153
'fixed bottom-0 left-0 right-0 pb-safe border-t border-gray-200 dark:border-gray-800' ,
134
154
// tablet
135
155
'md:top-0 md:right-auto md:border-r md:border-gray-200 md:dark:border-gray-800' ,
136
156
// desktop
137
157
'xl:bg-inherit xl:sticky xl:h-screen xl:border-none xl:top-0' ,
158
+ // transition
159
+ 'transform transition-transform duration-200 ease-in-out' ,
160
+ isVisible ? 'translate-y-0' : 'translate-y-full' ,
161
+ 'md:translate-y-0' ,
138
162
) }
139
163
>
140
164
< div
@@ -147,6 +171,9 @@ export const Navbar = () => {
147
171
'xl:space-y-0' ,
148
172
) }
149
173
>
174
+ < div className = "flex flex-row items-center gap-2 p-3" >
175
+ { handle && < Avatar handle = { handle } avatar = { profile ?. avatar } hover = { false } /> }
176
+ </ div >
150
177
< HomeLink />
151
178
< SearchLink />
152
179
{ isAuthenticated && < MessagesLink /> }
0 commit comments