Skip to content

Commit 9e00b24

Browse files
committed
Fixes
1 parent 2423557 commit 9e00b24

19 files changed

+1492
-44
lines changed

src/components/FeedbackModerationList.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react'
2+
import { Link } from '@tanstack/react-router'
23
import { twMerge } from 'tailwind-merge'
34
import {
45
Table,
@@ -164,10 +165,22 @@ export function FeedbackModerationList({
164165
onClick={() => toggleExpanded(feedback.id)}
165166
>
166167
<TableCell className="font-mono text-xs">
167-
{(page - 1) * pageSize + index + 1}
168+
<Link
169+
to="/admin/feedback_/$id"
170+
params={{ id: feedback.id }}
171+
className="hover:text-blue-600 dark:hover:text-blue-400"
172+
onClick={(e) => e.stopPropagation()}
173+
>
174+
{(page - 1) * pageSize + index + 1}
175+
</Link>
168176
</TableCell>
169177
<TableCell>
170-
<div className="flex items-center gap-2">
178+
<Link
179+
to="/admin/feedback_/$id"
180+
params={{ id: feedback.id }}
181+
className="flex items-center gap-2 hover:opacity-80"
182+
onClick={(e) => e.stopPropagation()}
183+
>
171184
{feedback.type === 'note' ? (
172185
<MessageSquare className="text-blue-500" />
173186
) : (
@@ -176,7 +189,7 @@ export function FeedbackModerationList({
176189
<span className="text-xs">
177190
{feedback.type === 'note' ? 'Note' : 'Improvement'}
178191
</span>
179-
</div>
192+
</Link>
180193
</TableCell>
181194
<TableCell>
182195
<span

src/components/OpenSourceStats.tsx

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,13 @@ const NpmDownloadCounter = ({
1818
}
1919
}) => {
2020
const ref = useNpmDownloadCounter(npmData)
21-
return <span ref={ref} style={{ fontVariantNumeric: 'tabular-nums' }} />
21+
// Provide initial SSR value, hook will update it on client
22+
const initialCount = npmData.totalDownloads ?? 0
23+
return (
24+
<span ref={ref} style={{ fontVariantNumeric: 'tabular-nums' }}>
25+
{initialCount.toLocaleString()}
26+
</span>
27+
)
2228
}
2329

2430
function isValidMetric(value: number | undefined | null): boolean {
@@ -144,9 +150,55 @@ function OssStatsContent({ library }: { library?: Library }) {
144150
)
145151
}
146152

153+
function OssStatsSkeleton() {
154+
return (
155+
<Card
156+
className="relative p-8 grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-8 items-center
157+
justify-center xl:place-items-center rounded-[2rem]"
158+
>
159+
<div className="flex gap-4 items-center">
160+
<Download className="text-2xl" />
161+
<div>
162+
<div className="text-2xl font-bold opacity-80 h-7 w-24 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
163+
<div className="text-sm opacity-60 font-medium italic">
164+
NPM Downloads
165+
</div>
166+
</div>
167+
</div>
168+
<div className="flex gap-4 items-center">
169+
<Star className="text-2xl" />
170+
<div>
171+
<div className="text-2xl font-bold opacity-80 h-7 w-20 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
172+
<div className="text-sm opacity-60 font-medium italic -mt-1">
173+
Stars on Github
174+
</div>
175+
</div>
176+
</div>
177+
<div className="flex gap-4 items-center">
178+
<Users className="text-2xl" />
179+
<div>
180+
<div className="text-2xl font-bold opacity-80 h-7 w-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
181+
<div className="text-sm opacity-60 font-medium italic -mt-1">
182+
Contributors on GitHub
183+
</div>
184+
</div>
185+
</div>
186+
<div className="flex gap-4 items-center">
187+
<Box className="text-2xl" />
188+
<div>
189+
<div className="text-2xl font-bold opacity-80 h-7 w-16 bg-gray-200 dark:bg-gray-700 rounded animate-pulse" />
190+
<div className="text-sm opacity-60 font-medium italic -mt-1">
191+
Dependents on GitHub
192+
</div>
193+
</div>
194+
</div>
195+
</Card>
196+
)
197+
}
198+
147199
export default function OssStats({ library }: { library?: Library }) {
148200
return (
149-
<Suspense fallback={<></>}>
201+
<Suspense fallback={<OssStatsSkeleton />}>
150202
<BlankErrorBoundary>
151203
<OssStatsContent library={library} />
152204
</BlankErrorBoundary>

src/components/ShowcaseModerationList.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from 'react'
2+
import { Link } from '@tanstack/react-router'
23
import { twMerge } from 'tailwind-merge'
34
import {
45
Table,
@@ -168,7 +169,12 @@ export function ShowcaseModerationList({
168169
{(page - 1) * pageSize + index + 1}
169170
</TableCell>
170171
<TableCell>
171-
<div className="flex items-center gap-3">
172+
<Link
173+
to="/admin/showcases_/$id"
174+
params={{ id: showcase.id }}
175+
className="flex items-center gap-3 hover:opacity-80"
176+
onClick={(e) => e.stopPropagation()}
177+
>
172178
{showcase.logoUrl && (
173179
<img
174180
src={showcase.logoUrl}
@@ -184,7 +190,7 @@ export function ShowcaseModerationList({
184190
{showcase.tagline}
185191
</div>
186192
</div>
187-
</div>
193+
</Link>
188194
</TableCell>
189195
<TableCell>
190196
<span

src/components/icons/CogsIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function CogsIcon({
1010
<svg
1111
stroke="currentColor"
1212
fill="currentColor"
13-
stroke-width="0"
13+
strokeWidth="0"
1414
viewBox="0 0 640 512"
1515
aria-hidden={props['aria-label'] ? undefined : true}
1616
className={className}

src/components/icons/NpmIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export function NpmIcon({
99
return (
1010
<svg
1111
viewBox="0 0 576 512"
12-
stroke-width="0"
12+
strokeWidth="0"
1313
fill="currentColor"
1414
stroke="currentColor"
1515
width={width}

src/components/icons/YinYangIcon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function YinYangIcon({
1010
<svg
1111
stroke="currentColor"
1212
fill="currentColor"
13-
stroke-width="0"
13+
strokeWidth="0"
1414
viewBox="0 0 496 512"
1515
width={width}
1616
height={height}

src/db/client.ts

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,37 @@ import { drizzle } from 'drizzle-orm/postgres-js'
22
import postgres from 'postgres'
33
import * as schema from './schema'
44

5-
// Create the connection string from environment variable
6-
const connectionString = process.env.DATABASE_URL
5+
// Lazy initialization to avoid throwing at module load time
6+
let _client: ReturnType<typeof postgres> | null = null
7+
let _db: ReturnType<typeof drizzle<typeof schema>> | null = null
78

8-
if (!connectionString) {
9-
throw new Error('DATABASE_URL environment variable is not set')
9+
function getDb() {
10+
if (!_db) {
11+
const connectionString = process.env.DATABASE_URL
12+
if (!connectionString) {
13+
throw new Error('DATABASE_URL environment variable is not set')
14+
}
15+
_client = postgres(connectionString, {
16+
max: 1,
17+
idle_timeout: 20,
18+
connect_timeout: 10,
19+
})
20+
_db = drizzle(_client, { schema })
21+
}
22+
return _db
1023
}
1124

12-
// Create postgres client
13-
// For serverless environments, use connection pooling
14-
const client = postgres(connectionString, {
15-
max: 1, // For serverless, limit connections
16-
idle_timeout: 20,
17-
connect_timeout: 10,
25+
// Use a getter to lazily initialize db on first access
26+
export const db = new Proxy({} as ReturnType<typeof drizzle<typeof schema>>, {
27+
get(target, prop, receiver) {
28+
const realDb = getDb()
29+
const value = Reflect.get(realDb, prop, realDb)
30+
if (typeof value === 'function') {
31+
return value.bind(realDb)
32+
}
33+
return value
34+
},
1835
})
1936

20-
// Create drizzle instance with schema
21-
export const db = drizzle(client, { schema })
22-
2337
// Export schema for use in migrations and queries
2438
export { schema }

0 commit comments

Comments
 (0)