mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
The commits section read numbers that were typed into scripts/sync-oss.ts (5,420 repositories, 214 orgs, 784 pushes a day, 245,417 commits, each contributor's count), a day's count scaled by a made-up factor, and a star count that began at 1,420. The forge's database holds 1,150 repositories and 46 orgs; none of that was read. Its panels were tinted rgba over a stylesheet, DualStarButton showed its guess before GitHub answered, and BulkStarModal said "successfully starred" over a forge PUT. scripts/sync-oss.ts (was .mjs) now counts GitHub's public activity for the orgs we publish: commits a day, the year, the week, active repositories and the newest commits, written at each build with the moment it was read. A figure the snapshot does not hold is not drawn. The grid, bars and repository card are @hanzo/ui/marketing (8.29.19); the showcase stylesheet and DayActivityModal are deleted. The org and repo pages lose their typed "velocity" banners. Design lint is zero in components/oss, home/OpenSource and ForgeBetaBanner. e2e/gates/activity.spec.ts holds each figure to the snapshot, the cards to one fill and edge in both schemes, a card's name, line and foot to their own rows, and the phone to no sideways scroll. Claude-Session: https://claude.ai/code/session_017vrVus6PPBgP5YRzKV1iqW
178 lines
5.1 KiB
TypeScript
178 lines
5.1 KiB
TypeScript
'use client'
|
|
|
|
import React, { useState } from 'react'
|
|
import { Star, Check } from 'lucide-react'
|
|
import { Text, XStack, YStack } from '@hanzo/ui'
|
|
import { useI18n } from '@hanzo/i18n/react'
|
|
import starred_ from '@/lib/data/oss-stars.json'
|
|
|
|
/** The stars each public repository holds, counted by scripts/sync-oss.ts; a repository with none is not listed. */
|
|
const STARS = starred_.stars as Record<string, number>
|
|
|
|
export interface DualStarButtonProps {
|
|
owner: string
|
|
repo: string
|
|
githubUrl?: string
|
|
size?: 'sm' | 'md'
|
|
}
|
|
|
|
export default function DualStarButton({
|
|
owner,
|
|
repo,
|
|
githubUrl,
|
|
size = 'md',
|
|
}: DualStarButtonProps) {
|
|
const { t } = useI18n()
|
|
const [starred, setStarred] = useState(false)
|
|
// Only what GitHub holds: pressing the button opens GitHub's own star, and a count is never raised on a guess.
|
|
const count = STARS[`${owner}/${repo}`] ?? 0
|
|
const [activeTooltip, setActiveTooltip] = useState(false)
|
|
|
|
const gh = githubUrl || `https://github.com/${owner}/${repo}`
|
|
|
|
const handleDualStar = (e: React.MouseEvent) => {
|
|
e.preventDefault()
|
|
e.stopPropagation()
|
|
|
|
if (!starred) {
|
|
setStarred(true)
|
|
setActiveTooltip(true)
|
|
setTimeout(() => setActiveTooltip(false), 3000)
|
|
|
|
// Open GitHub star tab so user stars on GitHub simultaneously
|
|
try {
|
|
const ghWin = window.open(gh, '_blank', 'noopener,noreferrer')
|
|
if (ghWin) ghWin.blur()
|
|
window.focus()
|
|
} catch {
|
|
/* a blocked popup leaves the star where it is */
|
|
}
|
|
|
|
// Call Hanzo Forge star API
|
|
try {
|
|
fetch(`https://forge.hanzo.ai/api/v1/user/starred/${owner}/${repo}`, {
|
|
method: 'PUT',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
credentials: 'include',
|
|
}).catch(() => {})
|
|
} catch {
|
|
/* the forge star is a courtesy: GitHub's tab is the one that counts */
|
|
}
|
|
} else {
|
|
setStarred(false)
|
|
}
|
|
}
|
|
|
|
const isSm = size === 'sm'
|
|
|
|
return (
|
|
<XStack items="center" gap={6} position="relative">
|
|
<XStack
|
|
render={
|
|
<button
|
|
type="button"
|
|
onClick={handleDualStar}
|
|
title={t('Dual-Star on Hanzo Forge and GitHub')}
|
|
/>
|
|
}
|
|
items="center"
|
|
gap={6}
|
|
px={isSm ? 10 : 13}
|
|
py={isSm ? 5 : 7}
|
|
rounded={8}
|
|
borderWidth={1}
|
|
borderColor={starred ? 'var(--foreground)' : 'var(--border)'}
|
|
bg={starred ? 'var(--secondary)' : 'transparent'}
|
|
hoverStyle={{ borderColor: 'var(--border-strong)', bg: 'var(--secondary)' }}
|
|
cursor="pointer"
|
|
$platform-web={{ borderRadius: '8px', borderStyle: 'solid', transition: 'all 0.18s ease-in-out' }}
|
|
>
|
|
<Star
|
|
width={isSm ? 13 : 15}
|
|
height={isSm ? 13 : 15}
|
|
color={starred ? 'var(--foreground)' : 'var(--muted-foreground)'}
|
|
fill={starred ? 'var(--foreground)' : 'none'}
|
|
/>
|
|
<Text
|
|
fontSize={isSm ? 11 : 12}
|
|
fontWeight="600"
|
|
color="var(--foreground)"
|
|
>
|
|
{starred ? t('Starred') : t('Star')}
|
|
</Text>
|
|
{count > 0 ? (
|
|
<XStack
|
|
items="center"
|
|
px={6}
|
|
py={1}
|
|
rounded={4}
|
|
bg="var(--secondary)"
|
|
$platform-web={{ borderRadius: '4px' }}
|
|
>
|
|
<Text
|
|
fontFamily="$mono"
|
|
fontSize={isSm ? 10 : 11}
|
|
fontWeight="600"
|
|
color="var(--muted-foreground)"
|
|
>
|
|
{count.toLocaleString('en-US')}
|
|
</Text>
|
|
</XStack>
|
|
) : null}
|
|
</XStack>
|
|
|
|
{/* Dual Badge indicating Forge + GitHub sync */}
|
|
<XStack
|
|
items="center"
|
|
gap={4}
|
|
px={6}
|
|
py={3}
|
|
rounded={6}
|
|
borderWidth={1}
|
|
borderColor="var(--border)"
|
|
bg="var(--background)"
|
|
$platform-web={{ borderRadius: '6px' }}
|
|
>
|
|
<Text fontSize={10} fontFamily="$mono" color="var(--foreground)" fontWeight="700">
|
|
{t('Forge')}
|
|
</Text>
|
|
<Text fontSize={9} color="var(--muted-foreground)">
|
|
+
|
|
</Text>
|
|
<Text fontSize={10} fontFamily="$mono" color="var(--muted-foreground)" fontWeight="600">
|
|
GH
|
|
</Text>
|
|
</XStack>
|
|
|
|
{/* Instant Notification Tooltip */}
|
|
{activeTooltip && (
|
|
<YStack
|
|
position="absolute"
|
|
b="100%"
|
|
mb={8}
|
|
l="50%"
|
|
p={8}
|
|
rounded={6}
|
|
bg="var(--background)"
|
|
borderWidth={1}
|
|
borderColor="var(--foreground)"
|
|
$platform-web={{
|
|
borderRadius: '6px',
|
|
transform: 'translateX(-50%)',
|
|
boxShadow: 'var(--shadow-floating)',
|
|
whiteSpace: 'nowrap',
|
|
zIndex: 'var(--z-tooltip)',
|
|
}}
|
|
>
|
|
<XStack items="center" gap={6}>
|
|
<Check width={12} height={12} color="var(--foreground)" />
|
|
<Text fontSize={11} fontWeight="600" color="var(--foreground)">
|
|
{t('Starred on Hanzo Forge & GitHub!')}
|
|
</Text>
|
|
</XStack>
|
|
</YStack>
|
|
)}
|
|
</XStack>
|
|
)
|
|
}
|