@moontra/moonui-pro 2.20.1 → 2.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +691 -261
- package/dist/index.mjs +7418 -4934
- package/package.json +11 -5
- package/plugin/index.d.ts +86 -0
- package/plugin/index.js +308 -0
- package/scripts/postbuild.js +27 -0
- package/scripts/postinstall.js +176 -23
- package/src/__tests__/use-intersection-observer.test.tsx +0 -216
- package/src/__tests__/use-local-storage.test.tsx +0 -174
- package/src/__tests__/use-pro-access.test.tsx +0 -183
- package/src/components/advanced-chart/advanced-chart.test.tsx +0 -281
- package/src/components/advanced-chart/index.tsx +0 -1242
- package/src/components/advanced-forms/index.tsx +0 -426
- package/src/components/animated-button/index.tsx +0 -385
- package/src/components/calendar/event-dialog.tsx +0 -372
- package/src/components/calendar/index.tsx +0 -1073
- package/src/components/calendar-pro/index.tsx +0 -1697
- package/src/components/color-picker/index.tsx +0 -432
- package/src/components/credit-card-input/index.tsx +0 -406
- package/src/components/dashboard/dashboard-grid.tsx +0 -462
- package/src/components/dashboard/demo.tsx +0 -425
- package/src/components/dashboard/index.tsx +0 -1046
- package/src/components/dashboard/time-range-picker.tsx +0 -336
- package/src/components/dashboard/types.ts +0 -222
- package/src/components/dashboard/widgets/activity-feed.tsx +0 -344
- package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
- package/src/components/dashboard/widgets/metric-card.tsx +0 -343
- package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
- package/src/components/data-table/data-table-column-toggle.tsx +0 -169
- package/src/components/data-table/data-table-export.ts +0 -156
- package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
- package/src/components/data-table/data-table.test.tsx +0 -187
- package/src/components/data-table/index.tsx +0 -845
- package/src/components/draggable-list/index.tsx +0 -100
- package/src/components/enhanced/badge.tsx +0 -191
- package/src/components/enhanced/button.tsx +0 -362
- package/src/components/enhanced/card.tsx +0 -266
- package/src/components/enhanced/dialog.tsx +0 -246
- package/src/components/enhanced/index.ts +0 -4
- package/src/components/error-boundary/index.tsx +0 -109
- package/src/components/file-upload/file-upload.test.tsx +0 -243
- package/src/components/file-upload/index.tsx +0 -1660
- package/src/components/floating-action-button/index.tsx +0 -206
- package/src/components/form-wizard/form-wizard-context.tsx +0 -307
- package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
- package/src/components/form-wizard/form-wizard-progress.tsx +0 -298
- package/src/components/form-wizard/form-wizard-step.tsx +0 -111
- package/src/components/form-wizard/index.tsx +0 -102
- package/src/components/form-wizard/types.ts +0 -76
- package/src/components/gesture-drawer/index.tsx +0 -551
- package/src/components/github-stars/github-api.ts +0 -426
- package/src/components/github-stars/hooks.ts +0 -516
- package/src/components/github-stars/index.tsx +0 -375
- package/src/components/github-stars/types.ts +0 -148
- package/src/components/github-stars/variants.tsx +0 -513
- package/src/components/health-check/index.tsx +0 -439
- package/src/components/hover-card-3d/index.tsx +0 -530
- package/src/components/index.ts +0 -128
- package/src/components/internal/index.ts +0 -78
- package/src/components/kanban/add-card-modal.tsx +0 -502
- package/src/components/kanban/card-detail-modal.tsx +0 -761
- package/src/components/kanban/index.ts +0 -13
- package/src/components/kanban/kanban.tsx +0 -1684
- package/src/components/kanban/types.ts +0 -168
- package/src/components/lazy-component/index.tsx +0 -823
- package/src/components/license-error/index.tsx +0 -29
- package/src/components/magnetic-button/index.tsx +0 -167
- package/src/components/memory-efficient-data/index.tsx +0 -1016
- package/src/components/moonui-quiz-form/index.tsx +0 -817
- package/src/components/optimized-image/index.tsx +0 -425
- package/src/components/performance-debugger/index.tsx +0 -589
- package/src/components/performance-monitor/index.tsx +0 -794
- package/src/components/phone-number-input/index.tsx +0 -338
- package/src/components/pinch-zoom/index.tsx +0 -566
- package/src/components/quiz-form/index.tsx +0 -479
- package/src/components/rich-text-editor/index-old-backup.tsx +0 -437
- package/src/components/rich-text-editor/index.tsx +0 -2324
- package/src/components/rich-text-editor/slash-commands-extension.ts +0 -220
- package/src/components/rich-text-editor/slash-commands.css +0 -35
- package/src/components/rich-text-editor/table-styles.css +0 -65
- package/src/components/sidebar/index.tsx +0 -865
- package/src/components/spotlight-card/index.tsx +0 -191
- package/src/components/swipeable-card/index.tsx +0 -100
- package/src/components/timeline/index.tsx +0 -1148
- package/src/components/ui/accordion.tsx +0 -73
- package/src/components/ui/alert-dialog.tsx +0 -141
- package/src/components/ui/alert.tsx +0 -141
- package/src/components/ui/aspect-ratio.tsx +0 -245
- package/src/components/ui/avatar.tsx +0 -153
- package/src/components/ui/badge.tsx +0 -228
- package/src/components/ui/breadcrumb.tsx +0 -214
- package/src/components/ui/button.tsx +0 -222
- package/src/components/ui/calendar.tsx +0 -387
- package/src/components/ui/card.tsx +0 -214
- package/src/components/ui/checkbox.tsx +0 -259
- package/src/components/ui/collapsible.tsx +0 -135
- package/src/components/ui/color-picker.tsx +0 -97
- package/src/components/ui/command.tsx +0 -225
- package/src/components/ui/dialog.tsx +0 -334
- package/src/components/ui/dropdown-menu.tsx +0 -218
- package/src/components/ui/gesture-drawer.tsx +0 -11
- package/src/components/ui/hover-card.tsx +0 -29
- package/src/components/ui/index.ts +0 -190
- package/src/components/ui/input.tsx +0 -222
- package/src/components/ui/label.tsx +0 -29
- package/src/components/ui/lightbox.tsx +0 -606
- package/src/components/ui/magnetic-button.tsx +0 -129
- package/src/components/ui/media-gallery.tsx +0 -612
- package/src/components/ui/pagination.tsx +0 -123
- package/src/components/ui/popover.tsx +0 -185
- package/src/components/ui/progress.tsx +0 -30
- package/src/components/ui/radio-group.tsx +0 -257
- package/src/components/ui/scroll-area.tsx +0 -47
- package/src/components/ui/select.tsx +0 -374
- package/src/components/ui/separator.tsx +0 -145
- package/src/components/ui/sheet.tsx +0 -139
- package/src/components/ui/skeleton.tsx +0 -20
- package/src/components/ui/slider.tsx +0 -354
- package/src/components/ui/spotlight-card.tsx +0 -119
- package/src/components/ui/switch.tsx +0 -86
- package/src/components/ui/table.tsx +0 -329
- package/src/components/ui/tabs.tsx +0 -198
- package/src/components/ui/textarea.tsx +0 -28
- package/src/components/ui/toast.tsx +0 -317
- package/src/components/ui/toggle.tsx +0 -119
- package/src/components/ui/tooltip.tsx +0 -151
- package/src/components/virtual-list/index.tsx +0 -668
- package/src/hooks/use-chart.ts +0 -205
- package/src/hooks/use-data-table.ts +0 -182
- package/src/hooks/use-docs-pro-access.ts +0 -13
- package/src/hooks/use-license-check.ts +0 -65
- package/src/hooks/use-subscription.ts +0 -19
- package/src/hooks/use-toast.ts +0 -15
- package/src/index.ts +0 -14
- package/src/lib/ai-providers.ts +0 -377
- package/src/lib/component-metadata.ts +0 -18
- package/src/lib/micro-interactions.ts +0 -255
- package/src/lib/paddle.ts +0 -17
- package/src/lib/utils.ts +0 -6
- package/src/patterns/login-form/index.tsx +0 -276
- package/src/patterns/login-form/types.ts +0 -67
- package/src/setupTests.ts +0 -41
- package/src/styles/advanced-chart.css +0 -239
- package/src/styles/calendar.css +0 -35
- package/src/styles/design-system.css +0 -363
- package/src/styles/index.css +0 -85
- package/src/styles/tailwind.css +0 -7
- package/src/styles/tokens.css +0 -455
- package/src/types/moonui.d.ts +0 -22
- package/src/types/next-auth.d.ts +0 -21
- package/src/use-intersection-observer.tsx +0 -154
- package/src/use-local-storage.tsx +0 -71
- package/src/use-paddle.ts +0 -138
- package/src/use-performance-optimizer.ts +0 -389
- package/src/use-pro-access.ts +0 -141
- package/src/use-scroll-animation.ts +0 -219
- package/src/use-subscription.ts +0 -37
- package/src/use-toast.ts +0 -32
- package/src/utils/chart-helpers.ts +0 -357
- package/src/utils/cn.ts +0 -6
- package/src/utils/data-processing.ts +0 -151
- package/src/utils/license-validator.tsx +0 -183
|
@@ -1,516 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback, useRef } from "react"
|
|
2
|
-
import {
|
|
3
|
-
GitHubRepository,
|
|
4
|
-
GitHubStats,
|
|
5
|
-
RateLimitInfo,
|
|
6
|
-
StarHistory,
|
|
7
|
-
Milestone,
|
|
8
|
-
} from "./types"
|
|
9
|
-
import {
|
|
10
|
-
fetchUserRepositories,
|
|
11
|
-
fetchRepository,
|
|
12
|
-
fetchContributorsCount,
|
|
13
|
-
fetchStarHistory,
|
|
14
|
-
calculateStats,
|
|
15
|
-
getRateLimitInfo,
|
|
16
|
-
clearCache,
|
|
17
|
-
} from "./github-api"
|
|
18
|
-
|
|
19
|
-
interface UseGitHubDataOptions {
|
|
20
|
-
username?: string
|
|
21
|
-
repository?: string
|
|
22
|
-
repositories?: string[]
|
|
23
|
-
token?: string
|
|
24
|
-
autoRefresh?: boolean
|
|
25
|
-
refreshInterval?: number
|
|
26
|
-
sortBy?: string
|
|
27
|
-
maxItems?: number
|
|
28
|
-
onError?: (error: Error) => void
|
|
29
|
-
onDataUpdate?: (stats: GitHubStats) => void
|
|
30
|
-
onMilestoneReached?: (milestone: Milestone) => void
|
|
31
|
-
milestones?: number[]
|
|
32
|
-
// For docs mode optimizations
|
|
33
|
-
docsMode?: boolean
|
|
34
|
-
mockDataFallback?: boolean
|
|
35
|
-
forceMockData?: boolean // Force mock data instead of API
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function useGitHubData({
|
|
39
|
-
username,
|
|
40
|
-
repository,
|
|
41
|
-
repositories,
|
|
42
|
-
token,
|
|
43
|
-
autoRefresh = false,
|
|
44
|
-
refreshInterval = 300000,
|
|
45
|
-
sortBy = "stars",
|
|
46
|
-
maxItems,
|
|
47
|
-
onError,
|
|
48
|
-
onDataUpdate,
|
|
49
|
-
onMilestoneReached,
|
|
50
|
-
milestones = [10, 50, 100, 500, 1000, 5000, 10000],
|
|
51
|
-
docsMode = false,
|
|
52
|
-
mockDataFallback = true,
|
|
53
|
-
forceMockData = false,
|
|
54
|
-
}: UseGitHubDataOptions) {
|
|
55
|
-
// Docs mode detection
|
|
56
|
-
const isDocsMode = docsMode || (typeof window !== "undefined" &&
|
|
57
|
-
(window.location.pathname.includes("/docs/") ||
|
|
58
|
-
window.location.pathname.includes("/components/")))
|
|
59
|
-
|
|
60
|
-
// Disable autoRefresh in docs mode
|
|
61
|
-
const effectiveAutoRefresh = isDocsMode ? false : autoRefresh
|
|
62
|
-
const [repos, setRepos] = useState<GitHubRepository[]>([])
|
|
63
|
-
const [stats, setStats] = useState<GitHubStats | null>(null)
|
|
64
|
-
const [loading, setLoading] = useState(true)
|
|
65
|
-
const [error, setError] = useState<string | null>(null)
|
|
66
|
-
const [rateLimitInfo, setRateLimitInfo] = useState<RateLimitInfo | null>(null)
|
|
67
|
-
const [lastUpdated, setLastUpdated] = useState<Date | null>(null)
|
|
68
|
-
|
|
69
|
-
const refreshTimeoutRef = useRef<NodeJS.Timeout | undefined>(undefined)
|
|
70
|
-
const previousStarsRef = useRef<Map<string, number>>(new Map())
|
|
71
|
-
const errorCountRef = useRef<number>(0) // Hata sayısını takip et
|
|
72
|
-
const maxErrorCount = isDocsMode ? 1 : 2 // Fewer retries in docs mode
|
|
73
|
-
const hasInitialFetchedRef = useRef(false) // İlk fetch yapıldı mı?
|
|
74
|
-
const docsDataCacheRef = useRef<GitHubRepository[] | null>(null) // Docs mode cache
|
|
75
|
-
|
|
76
|
-
// Store checkMilestones function as ref - this way it won't be recreated on every render
|
|
77
|
-
const milestonesRef = useRef(milestones)
|
|
78
|
-
const onMilestoneReachedRef = useRef(onMilestoneReached)
|
|
79
|
-
|
|
80
|
-
// Ref'leri güncelle
|
|
81
|
-
useEffect(() => {
|
|
82
|
-
milestonesRef.current = milestones
|
|
83
|
-
}, [milestones])
|
|
84
|
-
|
|
85
|
-
useEffect(() => {
|
|
86
|
-
onMilestoneReachedRef.current = onMilestoneReached
|
|
87
|
-
}, [onMilestoneReached])
|
|
88
|
-
|
|
89
|
-
const checkMilestones = useCallback((repos: GitHubRepository[]) => {
|
|
90
|
-
if (!onMilestoneReachedRef.current) return
|
|
91
|
-
|
|
92
|
-
repos.forEach(repo => {
|
|
93
|
-
const previousStars = previousStarsRef.current.get(repo.full_name) || 0
|
|
94
|
-
const currentStars = repo.stargazers_count
|
|
95
|
-
|
|
96
|
-
milestonesRef.current.forEach(milestone => {
|
|
97
|
-
if (previousStars < milestone && currentStars >= milestone) {
|
|
98
|
-
onMilestoneReachedRef.current?.({
|
|
99
|
-
count: milestone,
|
|
100
|
-
reached: true,
|
|
101
|
-
date: new Date().toISOString(),
|
|
102
|
-
celebration: true,
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
previousStarsRef.current.set(repo.full_name, currentStars)
|
|
108
|
-
})
|
|
109
|
-
}, []) // Boş dependency array - fonksiyon asla yeniden oluşturulmaz
|
|
110
|
-
|
|
111
|
-
const fetchData = useCallback(async () => {
|
|
112
|
-
// If forceMockData is true, always return mock data
|
|
113
|
-
if (forceMockData) {
|
|
114
|
-
console.log("[Mock Mode] Using mock data")
|
|
115
|
-
const mockData = getMockGitHubData(username, repository, repositories)
|
|
116
|
-
setRepos(mockData)
|
|
117
|
-
const calculatedStats = calculateStats(mockData)
|
|
118
|
-
setStats(calculatedStats)
|
|
119
|
-
setError(null)
|
|
120
|
-
setLoading(false)
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Docs modunda ve daha önce fetch yapıldıysa, cache'den döndür
|
|
125
|
-
if (isDocsMode && hasInitialFetchedRef.current && docsDataCacheRef.current) {
|
|
126
|
-
console.log("[Docs Mode] Returning cached data, skipping API request")
|
|
127
|
-
setRepos(docsDataCacheRef.current)
|
|
128
|
-
const calculatedStats = calculateStats(docsDataCacheRef.current)
|
|
129
|
-
setStats(calculatedStats)
|
|
130
|
-
setLoading(false)
|
|
131
|
-
return
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Hata limiti aşıldıysa istek yapma
|
|
135
|
-
if (errorCountRef.current >= maxErrorCount) {
|
|
136
|
-
console.warn("Maximum error count reached. Stopping requests.")
|
|
137
|
-
|
|
138
|
-
// Show mock data if in docs mode and mockDataFallback is active
|
|
139
|
-
if (isDocsMode && mockDataFallback) {
|
|
140
|
-
const mockData = getMockGitHubData(username, repository, repositories)
|
|
141
|
-
setRepos(mockData)
|
|
142
|
-
const calculatedStats = calculateStats(mockData)
|
|
143
|
-
setStats(calculatedStats)
|
|
144
|
-
setError(null)
|
|
145
|
-
} else {
|
|
146
|
-
setError("Maximum retry limit exceeded. Please check your configuration.")
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
setLoading(false)
|
|
150
|
-
return
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Don't make requests if required info is missing
|
|
154
|
-
const hasValidInput =
|
|
155
|
-
(username && repository) || // Tek repository modu
|
|
156
|
-
(username && repositories && repositories.length > 0) || // Çoklu repository modu
|
|
157
|
-
(repositories && repositories.length > 0 && repositories.every(r => r.includes('/'))) || // Full path repositories
|
|
158
|
-
username // Kullanıcının tüm repositoryleri
|
|
159
|
-
|
|
160
|
-
if (!hasValidInput) {
|
|
161
|
-
console.warn("No valid input provided. Skipping API request.")
|
|
162
|
-
setLoading(false)
|
|
163
|
-
setError(null)
|
|
164
|
-
setRepos([])
|
|
165
|
-
setStats(null)
|
|
166
|
-
return
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
try {
|
|
170
|
-
setLoading(true)
|
|
171
|
-
setError(null)
|
|
172
|
-
|
|
173
|
-
// Check rate limit first
|
|
174
|
-
try {
|
|
175
|
-
const rateLimit = await getRateLimitInfo(token)
|
|
176
|
-
setRateLimitInfo(rateLimit)
|
|
177
|
-
|
|
178
|
-
if (rateLimit.remaining < 10) {
|
|
179
|
-
console.warn(`Low GitHub API rate limit: ${rateLimit.remaining} requests remaining`)
|
|
180
|
-
}
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.error("Failed to fetch rate limit:", error)
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
let fetchedRepos: GitHubRepository[] = []
|
|
186
|
-
|
|
187
|
-
// Single repository mode
|
|
188
|
-
if (repository && username) {
|
|
189
|
-
const repo = await fetchRepository(username, repository, token)
|
|
190
|
-
fetchedRepos = [repo]
|
|
191
|
-
}
|
|
192
|
-
// Multiple specific repositories with full paths
|
|
193
|
-
else if (repositories && repositories.length > 0 && repositories.every(r => r.includes('/'))) {
|
|
194
|
-
const repoPromises = repositories.map(fullPath => {
|
|
195
|
-
const [owner, name] = fullPath.split('/')
|
|
196
|
-
return fetchRepository(owner, name, token)
|
|
197
|
-
})
|
|
198
|
-
fetchedRepos = await Promise.all(repoPromises)
|
|
199
|
-
}
|
|
200
|
-
// Multiple specific repositories with username
|
|
201
|
-
else if (repositories && repositories.length > 0 && username) {
|
|
202
|
-
const repoPromises = repositories.map(repoName =>
|
|
203
|
-
fetchRepository(username, repoName, token)
|
|
204
|
-
)
|
|
205
|
-
fetchedRepos = await Promise.all(repoPromises)
|
|
206
|
-
}
|
|
207
|
-
// All user repositories
|
|
208
|
-
else if (username) {
|
|
209
|
-
fetchedRepos = await fetchUserRepositories(username, token, {
|
|
210
|
-
sort: sortBy,
|
|
211
|
-
per_page: 100,
|
|
212
|
-
})
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Sort repositories
|
|
216
|
-
fetchedRepos.sort((a, b) => {
|
|
217
|
-
switch (sortBy) {
|
|
218
|
-
case "stars":
|
|
219
|
-
return b.stargazers_count - a.stargazers_count
|
|
220
|
-
case "forks":
|
|
221
|
-
return b.forks_count - a.forks_count
|
|
222
|
-
case "updated":
|
|
223
|
-
return new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
|
|
224
|
-
case "created":
|
|
225
|
-
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
226
|
-
case "name":
|
|
227
|
-
return a.name.localeCompare(b.name)
|
|
228
|
-
case "issues":
|
|
229
|
-
return b.open_issues_count - a.open_issues_count
|
|
230
|
-
default:
|
|
231
|
-
return 0
|
|
232
|
-
}
|
|
233
|
-
})
|
|
234
|
-
|
|
235
|
-
// Limit results
|
|
236
|
-
if (maxItems && maxItems > 0) {
|
|
237
|
-
fetchedRepos = fetchedRepos.slice(0, maxItems)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Fetch additional data for detailed view
|
|
241
|
-
const enhancedRepos = await Promise.all(
|
|
242
|
-
fetchedRepos.map(async repo => {
|
|
243
|
-
try {
|
|
244
|
-
const contributorsCount = await fetchContributorsCount(
|
|
245
|
-
repo.owner.login,
|
|
246
|
-
repo.name,
|
|
247
|
-
token
|
|
248
|
-
)
|
|
249
|
-
return { ...repo, contributors_count: contributorsCount }
|
|
250
|
-
} catch (error) {
|
|
251
|
-
console.error(`Failed to fetch contributors for ${repo.full_name}:`, error)
|
|
252
|
-
return repo
|
|
253
|
-
}
|
|
254
|
-
})
|
|
255
|
-
)
|
|
256
|
-
|
|
257
|
-
setRepos(enhancedRepos)
|
|
258
|
-
|
|
259
|
-
// Calculate statistics
|
|
260
|
-
const calculatedStats = calculateStats(enhancedRepos)
|
|
261
|
-
setStats(calculatedStats)
|
|
262
|
-
|
|
263
|
-
// Check milestones
|
|
264
|
-
checkMilestones(enhancedRepos)
|
|
265
|
-
|
|
266
|
-
// Notify data update
|
|
267
|
-
if (onDataUpdate) {
|
|
268
|
-
onDataUpdate(calculatedStats)
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
setLastUpdated(new Date())
|
|
272
|
-
// Reset error counter on success
|
|
273
|
-
errorCountRef.current = 0
|
|
274
|
-
|
|
275
|
-
// Cache successful data in docs mode
|
|
276
|
-
if (isDocsMode) {
|
|
277
|
-
hasInitialFetchedRef.current = true
|
|
278
|
-
docsDataCacheRef.current = enhancedRepos
|
|
279
|
-
}
|
|
280
|
-
} catch (err) {
|
|
281
|
-
const errorMessage = err instanceof Error ? err.message : "Failed to fetch data"
|
|
282
|
-
setError(errorMessage)
|
|
283
|
-
|
|
284
|
-
// Hata sayacını artır
|
|
285
|
-
errorCountRef.current += 1
|
|
286
|
-
console.error(`GitHub API error (${errorCountRef.current}/${maxErrorCount}):`, errorMessage)
|
|
287
|
-
|
|
288
|
-
// Show mock data if in docs mode and mockDataFallback is active
|
|
289
|
-
if (isDocsMode && mockDataFallback && !hasInitialFetchedRef.current) {
|
|
290
|
-
console.warn("[Docs Mode] API failed, using mock data")
|
|
291
|
-
const mockData = getMockGitHubData(username, repository, repositories)
|
|
292
|
-
setRepos(mockData)
|
|
293
|
-
const calculatedStats = calculateStats(mockData)
|
|
294
|
-
setStats(calculatedStats)
|
|
295
|
-
setError(null)
|
|
296
|
-
hasInitialFetchedRef.current = true
|
|
297
|
-
docsDataCacheRef.current = mockData
|
|
298
|
-
} else if (onError) {
|
|
299
|
-
onError(err instanceof Error ? err : new Error(errorMessage))
|
|
300
|
-
}
|
|
301
|
-
} finally {
|
|
302
|
-
setLoading(false)
|
|
303
|
-
}
|
|
304
|
-
}, [
|
|
305
|
-
username,
|
|
306
|
-
repository,
|
|
307
|
-
repositories?.join(','), // Convert array to string to keep reference stable
|
|
308
|
-
token,
|
|
309
|
-
sortBy,
|
|
310
|
-
maxItems,
|
|
311
|
-
checkMilestones, // Now stable
|
|
312
|
-
onDataUpdate,
|
|
313
|
-
onError,
|
|
314
|
-
isDocsMode,
|
|
315
|
-
mockDataFallback,
|
|
316
|
-
forceMockData,
|
|
317
|
-
])
|
|
318
|
-
|
|
319
|
-
// Initial fetch
|
|
320
|
-
useEffect(() => {
|
|
321
|
-
// Only fetch if there's valid input
|
|
322
|
-
const hasValidInput =
|
|
323
|
-
(username && repository) ||
|
|
324
|
-
(username && repositories && repositories.length > 0) ||
|
|
325
|
-
(repositories && repositories.length > 0 && repositories.every(r => r.includes('/'))) ||
|
|
326
|
-
username
|
|
327
|
-
|
|
328
|
-
if (hasValidInput) {
|
|
329
|
-
fetchData()
|
|
330
|
-
} else {
|
|
331
|
-
setLoading(false)
|
|
332
|
-
}
|
|
333
|
-
}, [fetchData])
|
|
334
|
-
|
|
335
|
-
// Auto-refresh
|
|
336
|
-
useEffect(() => {
|
|
337
|
-
// Completely disable auto-refresh in docs mode
|
|
338
|
-
if (!effectiveAutoRefresh) return
|
|
339
|
-
|
|
340
|
-
const scheduleRefresh = () => {
|
|
341
|
-
refreshTimeoutRef.current = setTimeout(() => {
|
|
342
|
-
fetchData()
|
|
343
|
-
scheduleRefresh()
|
|
344
|
-
}, refreshInterval)
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
scheduleRefresh()
|
|
348
|
-
|
|
349
|
-
return () => {
|
|
350
|
-
if (refreshTimeoutRef.current) {
|
|
351
|
-
clearTimeout(refreshTimeoutRef.current)
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
}, [effectiveAutoRefresh, refreshInterval, fetchData])
|
|
355
|
-
|
|
356
|
-
const refresh = useCallback(() => {
|
|
357
|
-
// Limit refresh in docs mode
|
|
358
|
-
if (isDocsMode && hasInitialFetchedRef.current) {
|
|
359
|
-
console.warn("[Docs Mode] Refresh disabled after initial fetch")
|
|
360
|
-
return Promise.resolve()
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
// Hata limiti aşıldıysa refresh yapma
|
|
364
|
-
if (errorCountRef.current >= maxErrorCount) {
|
|
365
|
-
console.warn("Cannot refresh: maximum error count reached")
|
|
366
|
-
return Promise.resolve()
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
clearCache()
|
|
370
|
-
return fetchData()
|
|
371
|
-
}, [fetchData, isDocsMode])
|
|
372
|
-
|
|
373
|
-
return {
|
|
374
|
-
repos,
|
|
375
|
-
stats,
|
|
376
|
-
loading,
|
|
377
|
-
error,
|
|
378
|
-
rateLimitInfo,
|
|
379
|
-
lastUpdated,
|
|
380
|
-
refresh,
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Hook for star history
|
|
385
|
-
export function useStarHistory(
|
|
386
|
-
owner: string,
|
|
387
|
-
repo: string,
|
|
388
|
-
token?: string
|
|
389
|
-
) {
|
|
390
|
-
const [history, setHistory] = useState<StarHistory[]>([])
|
|
391
|
-
const [loading, setLoading] = useState(true)
|
|
392
|
-
const [error, setError] = useState<string | null>(null)
|
|
393
|
-
|
|
394
|
-
useEffect(() => {
|
|
395
|
-
const fetchHistory = async () => {
|
|
396
|
-
try {
|
|
397
|
-
setLoading(true)
|
|
398
|
-
setError(null)
|
|
399
|
-
const data = await fetchStarHistory(owner, repo, token)
|
|
400
|
-
setHistory(data)
|
|
401
|
-
} catch (err) {
|
|
402
|
-
setError(err instanceof Error ? err.message : "Failed to fetch star history")
|
|
403
|
-
} finally {
|
|
404
|
-
setLoading(false)
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (owner && repo) {
|
|
409
|
-
fetchHistory()
|
|
410
|
-
}
|
|
411
|
-
}, [owner, repo, token])
|
|
412
|
-
|
|
413
|
-
return { history, loading, error }
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
// Hook for notifications
|
|
417
|
-
export function useGitHubNotifications(enabled: boolean = true) {
|
|
418
|
-
const [permission, setPermission] = useState<NotificationPermission>("default")
|
|
419
|
-
|
|
420
|
-
useEffect(() => {
|
|
421
|
-
if (!enabled || typeof window === "undefined" || !("Notification" in window)) {
|
|
422
|
-
return
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
setPermission(Notification.permission)
|
|
426
|
-
|
|
427
|
-
if (Notification.permission === "default") {
|
|
428
|
-
Notification.requestPermission().then(setPermission)
|
|
429
|
-
}
|
|
430
|
-
}, [enabled])
|
|
431
|
-
|
|
432
|
-
const notify = useCallback(
|
|
433
|
-
(title: string, options?: NotificationOptions) => {
|
|
434
|
-
if (!enabled || permission !== "granted") return
|
|
435
|
-
|
|
436
|
-
try {
|
|
437
|
-
new Notification(title, {
|
|
438
|
-
icon: "/icon-192x192.png",
|
|
439
|
-
badge: "/icon-192x192.png",
|
|
440
|
-
...options,
|
|
441
|
-
})
|
|
442
|
-
} catch (error) {
|
|
443
|
-
console.error("Failed to show notification:", error)
|
|
444
|
-
}
|
|
445
|
-
},
|
|
446
|
-
[enabled, permission]
|
|
447
|
-
)
|
|
448
|
-
|
|
449
|
-
return { permission, notify }
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
// Mock data generator for docs mode
|
|
453
|
-
function getMockGitHubData(
|
|
454
|
-
username?: string,
|
|
455
|
-
repository?: string,
|
|
456
|
-
repositories?: string[]
|
|
457
|
-
): GitHubRepository[] {
|
|
458
|
-
const defaultRepos: GitHubRepository[] = [
|
|
459
|
-
{
|
|
460
|
-
id: 1,
|
|
461
|
-
name: repository || "awesome-project",
|
|
462
|
-
full_name: `${username || "moonui"}/${repository || "awesome-project"}`,
|
|
463
|
-
description: "An amazing open source project with great features",
|
|
464
|
-
html_url: `https://github.com/${username || "moonui"}/${repository || "awesome-project"}`,
|
|
465
|
-
homepage: "https://awesome-project.dev",
|
|
466
|
-
stargazers_count: 12453,
|
|
467
|
-
watchers_count: 543,
|
|
468
|
-
forks_count: 2341,
|
|
469
|
-
language: "TypeScript",
|
|
470
|
-
topics: ["react", "ui", "components", "typescript"],
|
|
471
|
-
created_at: "2022-01-15T10:30:00Z",
|
|
472
|
-
updated_at: new Date().toISOString(),
|
|
473
|
-
pushed_at: new Date().toISOString(),
|
|
474
|
-
size: 4567,
|
|
475
|
-
open_issues_count: 23,
|
|
476
|
-
license: {
|
|
477
|
-
key: "mit",
|
|
478
|
-
name: "MIT License",
|
|
479
|
-
spdx_id: "MIT",
|
|
480
|
-
url: "https://api.github.com/licenses/mit",
|
|
481
|
-
},
|
|
482
|
-
owner: {
|
|
483
|
-
login: username || "moonui",
|
|
484
|
-
avatar_url: `https://github.com/${username || "moonui"}.png`,
|
|
485
|
-
html_url: `https://github.com/${username || "moonui"}`,
|
|
486
|
-
type: "Organization",
|
|
487
|
-
},
|
|
488
|
-
contributors_count: 89,
|
|
489
|
-
},
|
|
490
|
-
]
|
|
491
|
-
|
|
492
|
-
if (repositories && repositories.length > 0) {
|
|
493
|
-
return repositories.map((repo, index) => {
|
|
494
|
-
const [owner, name] = repo.includes('/') ? repo.split('/') : [username || "moonui", repo]
|
|
495
|
-
return {
|
|
496
|
-
...defaultRepos[0],
|
|
497
|
-
id: index + 1,
|
|
498
|
-
name: name,
|
|
499
|
-
full_name: `${owner}/${name}`,
|
|
500
|
-
html_url: `https://github.com/${owner}/${name}`,
|
|
501
|
-
stargazers_count: Math.floor(Math.random() * 20000) + 1000,
|
|
502
|
-
forks_count: Math.floor(Math.random() * 3000) + 100,
|
|
503
|
-
watchers_count: Math.floor(Math.random() * 1000) + 50,
|
|
504
|
-
language: ["TypeScript", "JavaScript", "Python", "Go", "Rust"][index % 5],
|
|
505
|
-
owner: {
|
|
506
|
-
login: owner,
|
|
507
|
-
avatar_url: `https://github.com/${owner}.png`,
|
|
508
|
-
html_url: `https://github.com/${owner}`,
|
|
509
|
-
type: "Organization",
|
|
510
|
-
},
|
|
511
|
-
}
|
|
512
|
-
})
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
return defaultRepos
|
|
516
|
-
}
|