Skip to content

Commit 6bc8ca8

Browse files
authored
Merge branch 'main' into main
2 parents 5003123 + 6b60330 commit 6bc8ca8

File tree

7 files changed

+358
-119
lines changed

7 files changed

+358
-119
lines changed

next.config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@ import type { NextConfig } from "next";
22

33
const nextConfig: NextConfig = {
44
images: {
5-
domains: ['avatars.githubusercontent.com'],
5+
remotePatterns: [
6+
{
7+
protocol: 'https',
8+
hostname: 'avatars.githubusercontent.com',
9+
},
10+
{
11+
protocol: 'https',
12+
hostname: 'github.com',
13+
},
14+
],
615
},
716
};
817

src/app/api/search/route.ts

Whitespace-only changes.

src/app/api/user/[username]/route.ts

Whitespace-only changes.

src/app/search/page.tsx

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"use client";
22

33
import { useSearchParams } from "next/navigation";
4-
import { useEffect, useState, useRef } from "react";
4+
import { useEffect, useState, useCallback } from "react";
55
import { Card, CardContent } from "@/components/ui/card";
66
import { Button } from "@/components/ui/button";
7-
import { useCallback } from "react";
87
import Image from "next/image";
98
import { Badge } from "@/components/ui/badge";
109
import {
@@ -83,23 +82,13 @@ interface UserAnalytics {
8382

8483
export default function SearchPage() {
8584
const searchParams = useSearchParams();
86-
const userParam = searchParams.get("user");
87-
const repoParam = searchParams.get("repo");
85+
const userParam = searchParams?.get("user");
86+
const repoParam = searchParams?.get("repo");
8887
const { isLoading } = useRequireAuth();
8988
const { setCurrentQuery, setCurrentSearchType, setSearchModalOpen } =
9089
useSearchStore();
9190
const { setOpen } = useSidebarState();
9291

93-
// Refs for scroll sections
94-
const overviewRef = useRef<HTMLDivElement>(null);
95-
const behaviorRef = useRef<HTMLDivElement>(null);
96-
const starRef = useRef<HTMLDivElement>(null);
97-
const codeRef = useRef<HTMLDivElement>(null);
98-
const codeReviewRef = useRef<HTMLDivElement>(null);
99-
const issueRef = useRef<HTMLDivElement>(null);
100-
const monthlyStatsRef = useRef<HTMLDivElement>(null);
101-
const contributionActivitiesRef = useRef<HTMLDivElement>(null);
102-
10392
const [searchResults, setSearchResults] = useState<{
10493
repos: TrendingRepo[];
10594
users: TopContributor[];
@@ -147,47 +136,62 @@ export default function SearchPage() {
147136
[]
148137
);
149138

150-
// Scroll spy effect
139+
// Scroll spy effect - ONLY h2 titles matter
151140
useEffect(() => {
152141
const handleScroll = throttle(() => {
153-
const sections = [
154-
{ id: "overview", ref: overviewRef },
155-
{ id: "behavior", ref: behaviorRef },
156-
{ id: "star", ref: starRef },
157-
{ id: "code", ref: codeRef },
158-
{ id: "code-review", ref: codeReviewRef },
159-
{ id: "issue", ref: issueRef },
160-
{ id: "monthly-stats", ref: monthlyStatsRef },
161-
{ id: "contribution-activities", ref: contributionActivitiesRef },
162-
];
163-
const scrollPosition = window.scrollY + 200; // 200px offset
164-
let currentSection = sections[0].id;
165-
166-
// En alttaki section'ı bul
167-
for (let i = sections.length - 1; i >= 0; i--) {
168-
const element = sections[i].ref.current;
169-
if (element) {
170-
const elementTop = element.offsetTop;
171-
172-
if (scrollPosition >= elementTop) {
173-
currentSection = sections[i].id;
174-
break;
175-
}
142+
const sectionIds = ['overview', 'behavior', 'star', 'code', 'code-review', 'issue', 'monthly-stats', 'contribution-activities'];
143+
const headerOffset = 150; // Increased offset
144+
let currentActiveSection = 'overview';
145+
146+
// Check each section's h2 title position
147+
for (const sectionId of sectionIds) {
148+
const sectionElement = document.getElementById(sectionId);
149+
if (!sectionElement) continue;
150+
151+
const h2Element = sectionElement.querySelector('h2');
152+
if (!h2Element) continue;
153+
154+
const h2Rect = h2Element.getBoundingClientRect();
155+
156+
// If h2 title is at or above header offset, this section is active
157+
if (h2Rect.top <= headerOffset) {
158+
currentActiveSection = sectionId;
159+
} else {
160+
// First h2 that hasn't reached header yet - stop here
161+
break;
176162
}
177163
}
178164

179-
setActiveSection(currentSection);
165+
// Bottom of page special case
166+
if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 50) {
167+
currentActiveSection = 'contribution-activities';
168+
}
169+
170+
if (currentActiveSection !== activeSection) {
171+
setActiveSection(currentActiveSection);
172+
}
180173
}, 100);
181174

182175
window.addEventListener("scroll", handleScroll, { passive: true });
176+
handleScroll(); // Initial call
177+
183178
return () => window.removeEventListener("scroll", handleScroll);
184-
}, [throttle]);
179+
}, [activeSection, throttle]);
185180

186181
useEffect(() => {
187182
if (userParam || repoParam) {
188183
const query = userParam || repoParam || "";
189184
const type = userParam ? "users" : "repos";
190185

186+
// Clear previous state when switching users
187+
setUserAnalytics(null);
188+
setSearchResults({
189+
repos: [],
190+
users: [],
191+
loading: false,
192+
error: null,
193+
});
194+
191195
setCurrentQuery(query);
192196
setCurrentSearchType(type);
193197
performSearch(query, type);
@@ -236,11 +240,12 @@ export default function SearchPage() {
236240
};
237241

238242
const loadUserAnalytics = async () => {
243+
if (!userParam) return;
244+
239245
setLoadingAnalytics(true);
240246
try {
241-
// User analytics method was removed - no longer available
242-
console.log("User analytics feature temporarily disabled");
243-
setUserAnalytics(null);
247+
const analytics = await githubAPIClient.getUserAnalytics(userParam);
248+
setUserAnalytics(analytics);
244249
} catch (error) {
245250
console.error("Analytics error:", error);
246251
// Fallback to null if API fails
@@ -437,7 +442,7 @@ export default function SearchPage() {
437442
!loadingAnalytics && (
438443
<>
439444
{/* Overview Section */}
440-
<div id="overview" ref={overviewRef} className="scroll-mt-24">
445+
<div id="overview" className="scroll-mt-20">
441446
<div className="flex items-center mb-6">
442447
<Eye className="w-6 h-6 mr-2" />
443448
<h2 className="text-2xl font-bold">Overview</h2>
@@ -571,8 +576,7 @@ export default function SearchPage() {
571576
{/* Behavior Section */}
572577
<div
573578
id="behavior"
574-
ref={behaviorRef}
575-
className="scroll-mt-24"
579+
className="scroll-mt-20 mt-12"
576580
>
577581
<div className="flex items-center mb-6">
578582
<Activity className="w-6 h-6 mr-2" />
@@ -680,7 +684,7 @@ export default function SearchPage() {
680684
</div>
681685

682686
{/* Star Section */}
683-
<div id="star" ref={starRef} className="scroll-mt-24">
687+
<div id="star" className="scroll-mt-20 mt-12">
684688
<div className="flex items-center mb-6">
685689
<Star className="w-6 h-6 mr-2" />
686690
<h2 className="text-2xl font-bold">Star Activity</h2>
@@ -701,7 +705,7 @@ export default function SearchPage() {
701705
</ChartWrapper>
702706
</div>
703707
{/* Code Section */}
704-
<div id="code" ref={codeRef} className="scroll-mt-24">
708+
<div id="code" className="scroll-mt-20 mt-12">
705709
<div className="flex items-center mb-6">
706710
<Code className="w-6 h-6 mr-2" />
707711
<h2 className="text-2xl font-bold">
@@ -727,8 +731,7 @@ export default function SearchPage() {
727731
{/* Code Review Section */}
728732
<div
729733
id="code-review"
730-
ref={codeReviewRef}
731-
className="scroll-mt-24"
734+
className="scroll-mt-20 mt-12"
732735
>
733736
<div className="flex items-center mb-6">
734737
<GitPullRequest className="w-6 h-6 mr-2" />
@@ -751,7 +754,7 @@ export default function SearchPage() {
751754
</div>
752755

753756
{/* Issue Section */}
754-
<div id="issue" ref={issueRef} className="scroll-mt-24">
757+
<div id="issue" className="scroll-mt-20 mt-12">
755758
<div className="flex items-center mb-6">
756759
<AlertCircle className="w-6 h-6 mr-2" />
757760
<h2 className="text-2xl font-bold">Issues</h2>
@@ -775,8 +778,7 @@ export default function SearchPage() {
775778
{/* Monthly Statistics Section */}
776779
<div
777780
id="monthly-stats"
778-
ref={monthlyStatsRef}
779-
className="scroll-mt-24"
781+
className="scroll-mt-20 mt-12"
780782
>
781783
<div className="flex items-center mb-6">
782784
<Calendar className="w-6 h-6 mr-2" />
@@ -804,8 +806,7 @@ export default function SearchPage() {
804806
{/* Contribution Activities Section */}
805807
<div
806808
id="contribution-activities"
807-
ref={contributionActivitiesRef}
808-
className="scroll-mt-24"
809+
className="scroll-mt-20 mt-12"
809810
>
810811
<div className="flex items-center mb-6">
811812
<Activity className="w-6 h-6 mr-2" />

src/components/layout/Sidebar.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useState } from 'react'
66
import { Button } from '@/components/ui/button'
77
import { useSidebarState, useAuthStore, useStoreHydration, useActionItemsStore } from '@/stores'
88
import { useQuickWinsStore } from '@/stores/quickWins'
9-
import { ChevronRight, Clock, LogOut, MessageSquare, Sparkles, Star, Target, Zap, Home } from 'lucide-react'
9+
import { ChevronRight, Clock, LogOut, MessageSquare, Sparkles, Star, Target, Zap, Home, UserCheck, Lightbulb, Wrench } from 'lucide-react'
1010
import { Badge } from '../ui/badge'
1111
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '../ui/collapsible'
1212

@@ -19,7 +19,7 @@ export function Sidebar() {
1919
const { isConnected, logout } = useAuthStore()
2020

2121
const { getCountByType, loading } = useActionItemsStore()
22-
22+
2323
const { goodIssues, easyFixes, loading: quickWinsLoading } = useQuickWinsStore()
2424

2525
const [actionRequiredOpen, setActionRequiredOpen] = useState(true)
@@ -32,7 +32,7 @@ export function Sidebar() {
3232
if (type === 'easyFixes') return easyFixes.length
3333
return getCountByType(type)
3434
}
35-
35+
3636
const getActionRequiredTotal = () => getBadgeCount('assigned') + getBadgeCount('mentions') + getBadgeCount('stale')
3737
const getQuickWinsTotal = () => getBadgeCount('goodFirstIssues') + getBadgeCount('easyFixes')
3838

@@ -121,7 +121,7 @@ export function Sidebar() {
121121
{getActionRequiredTotal()}
122122
</Badge>
123123
)}
124-
<ChevronRight className={`w-4 h-4 transition-transform ${actionRequiredOpen ? 'rotate-90' : ''}`} />
124+
<ChevronRight className={`w-4 h-4 transition-transform ${actionRequiredOpen ? 'rotate-90' : ''}`} />
125125
</div>
126126
</CollapsibleTrigger>
127127

@@ -135,7 +135,7 @@ export function Sidebar() {
135135
: 'text-gray-600 hover:text-blue-600 hover:bg-gray-50 dark:hover:bg-gray-800'
136136
}`}
137137
>
138-
<Target className="w-4 h-4" />
138+
<UserCheck className="w-4 h-4" />
139139
Assigned
140140
<Badge
141141
variant="outline"
@@ -194,13 +194,13 @@ export function Sidebar() {
194194
<Target className="w-5 h-5" />
195195
<span>Quick Wins</span>
196196
</div>
197-
<div className="flex items-center gap-1">
197+
<div className="flex items-center gap-1">
198198
{getQuickWinsTotal() > 0 && (
199199
<Badge variant="outline" className="text-xs min-w-[1.25rem] h-5 bg-muted/30 border-muted-foreground/20">
200200
{getQuickWinsTotal()}
201201
</Badge>
202202
)}
203-
<ChevronRight className={`w-4 h-4 transition-transform ${quickWinsOpen ? 'rotate-90' : ''}`} />
203+
<ChevronRight className={`w-4 h-4 transition-transform ${quickWinsOpen ? 'rotate-90' : ''}`} />
204204
</div>
205205
</CollapsibleTrigger>
206206

@@ -213,7 +213,7 @@ export function Sidebar() {
213213
? 'bg-blue-50 text-blue-600 dark:bg-blue-900/20 dark:text-blue-400'
214214
: 'text-gray-600 hover:text-blue-600 hover:bg-gray-50 dark:hover:bg-gray-800'
215215
}`}>
216-
<Target className="w-4 h-4" />
216+
<Lightbulb className="w-4 h-4" />
217217
<span className="font-medium">Good First Issues</span>
218218
<Badge
219219
variant="outline"
@@ -228,7 +228,7 @@ export function Sidebar() {
228228
? 'bg-blue-50 text-blue-600 dark:bg-blue-900/20 dark:text-blue-400'
229229
: 'text-gray-600 hover:text-blue-600 hover:bg-gray-50 dark:hover:bg-gray-800'
230230
}`}>
231-
<Sparkles className="w-4 h-4" />
231+
<Wrench className="w-4 h-4" />
232232
<span className="font-medium">Easy Fixes</span>
233233
<Badge
234234
variant="outline"
@@ -279,7 +279,7 @@ export function Sidebar() {
279279
</div>
280280
</div>
281281

282-
{/* Footer - Logout Button */}
282+
{/* Footer - Logout Button */}
283283
{hasHydrated && isConnected && (
284284
<div className="p-4 border-t border-sidebar-border flex-shrink-0">
285285
<Button

src/components/layout/SidebarSearch.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
import { useState, useEffect } from 'react'
44
import Link from 'next/link'
55
import { usePathname } from 'next/navigation'
6-
7-
86
import { useSidebarState } from '@/stores'
97
import {
10-
118
Activity,
129
Star,
1310
Code,
@@ -47,15 +44,19 @@ export function SidebarSearch() {
4744
return () => window.removeEventListener('activeSectionChange', handleActiveSection as EventListener);
4845
}, []);
4946

50-
47+
5148

5249
const mainItems = navigationItems.filter(item => item.section === 'main')
5350
const analyticsItems = navigationItems.filter(item => item.section === 'analytics')
5451

5552
const scrollToSection = (sectionId: string) => {
5653
const element = document.getElementById(sectionId);
5754
if (element) {
58-
element.scrollIntoView({ behavior: 'smooth' });
55+
// Close sidebar on mobile after navigation
56+
if (window.innerWidth < 1024) { // lg breakpoint
57+
setOpen(false);
58+
}
59+
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
5960
}
6061
};
6162

@@ -124,12 +125,12 @@ export function SidebarSearch() {
124125
className={`
125126
w-full flex items-center space-x-3 px-3 py-2 rounded-lg transition-colors text-sm text-left
126127
${isActive
127-
? 'bg-sidebar-accent text-sidebar-primary font-medium'
128+
? 'bg-sidebar-accent text-sidebar-primary font-medium border-l-2 border-blue-500'
128129
: 'text-sidebar-foreground hover:bg-sidebar-accent/50'
129130
}
130131
`}
131132
>
132-
<Icon size={16} className="text-muted-foreground" />
133+
<Icon size={16} className={`${isActive ? 'text-blue-500' : 'text-muted-foreground'}`} />
133134
<span>{item.label}</span>
134135
</button>
135136
)

0 commit comments

Comments
 (0)