mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
Testing: production export, typecheck, mobile/desktop composer and paid-Settings browser gates, historical activity/count unit tests and design lint pass. Risk: organization-scoped read-only usage, labelled estimates, public repository metadata only. How to revert: revert this commit and consume app 0.2.46.
111 lines
5.8 KiB
TypeScript
111 lines
5.8 KiB
TypeScript
'use client'
|
|
|
|
import { useI18n } from '@hanzo/i18n/react'
|
|
import { Text, View, XStack, YStack } from '@hanzo/ui'
|
|
import { Heatmap, More, Sparkline } from '@hanzo/ui/marketing'
|
|
import snapshotActivity from '@/lib/data/oss-activity.json'
|
|
import { usePublicActivity } from '@/lib/public-activity'
|
|
import snapshotStats from '@/lib/data/oss-stats.json'
|
|
import { Card, Caption, Mono } from '@/components/home/plate'
|
|
import { Onward } from '@/components/home/label'
|
|
import { figures, weekly, type Figure as Counted } from '@/lib/activity'
|
|
|
|
/**
|
|
* What the public repositories shipped, counted and not typed.
|
|
*
|
|
* Every figure and every cell is read by scripts/sync-oss.ts off GitHub's public
|
|
* API for the repositories we publish (forks left out, because a fork's history
|
|
* is the upstream's), and written to lib/data/oss-activity.json and
|
|
* oss-stats.json at each build, and `stats.read` is the moment it was read. A figure that file does not hold is not drawn,
|
|
* and with no activity at all the section is not drawn: there is no placeholder
|
|
* number and no fallback. The grid and the bars are @hanzo/ui's (`Heatmap`,
|
|
* `Sparkline`): this file hands them the data and the words.
|
|
*/
|
|
|
|
|
|
const fmt = (n: number) => n.toLocaleString('en-US')
|
|
const label = (k: string) => new Date(`${k}T00:00:00Z`).toLocaleDateString('en-US', { timeZone: 'UTC', month: 'short', day: 'numeric', year: 'numeric' })
|
|
const hour = (iso: string) => new Date(iso).toLocaleString('en-US', { timeZone: 'UTC', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', hour12: false })
|
|
|
|
function Figure({ id, title, value, caption, children }: { id: string; title: string; value: string; caption?: string; children?: React.ReactNode }) {
|
|
return (
|
|
<Card title={title}>
|
|
<Text fontFamily="$mono" fontSize="2rem" lineHeight="2.25rem" fontWeight="600" color="var(--foreground)" $platform-web={{ fontVariantNumeric: 'tabular-nums' }} data-figure={id}>
|
|
{value}
|
|
</Text>
|
|
{children}
|
|
{caption ? <Caption>{caption}</Caption> : null}
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
function Latest({ rows }: { rows: { repo: string; at: string; sha: string; message: string; url?: string }[] }) {
|
|
const { t } = useI18n()
|
|
if (!rows.length) return null
|
|
return (
|
|
<Card title={t('Latest commits')}>
|
|
<YStack render="ul" $platform-web={{ listStyle: 'none', margin: 0, padding: 0 }} data-slot="latest">
|
|
{rows.map((r) => (
|
|
<XStack key={`${r.repo}@${r.sha}`} render="li" items="baseline" gap={16} py={10} borderTopWidth={1} borderColor="var(--border)" flexWrap="wrap" $md={{ flexWrap: 'nowrap' }}>
|
|
<Mono color="var(--muted-foreground)" shrink={0} width={200} $platform-web={{ whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
|
|
{r.repo}
|
|
</Mono>
|
|
<Text render={<a href={r.url || `https://github.com/${r.repo}/commit/${r.sha}`} target="_blank" rel="noopener noreferrer" />} flex={1} minW={200} fontSize="$2" lineHeight="$2" color="var(--foreground)" $platform-web={{ textDecoration: 'none' }}>
|
|
{r.message}
|
|
</Text>
|
|
<Mono color="var(--muted-foreground)" shrink={0} data-i18n-ltr>
|
|
<time dateTime={r.at}>{hour(r.at)} UTC</time>
|
|
</Mono>
|
|
</XStack>
|
|
))}
|
|
</YStack>
|
|
</Card>
|
|
)
|
|
}
|
|
|
|
/** The panel: the counted figures the snapshot holds, the year as a grid, and the newest commits. Not drawn without activity. */
|
|
export default function Activity() {
|
|
const { t } = useI18n()
|
|
const live = usePublicActivity(snapshotStats.repos)
|
|
const activity = live ?? snapshotActivity
|
|
const stats = live ?? snapshotStats
|
|
const daily = activity.daily as Record<string, number>
|
|
const active = activity.active as Record<string, number>
|
|
if (!Object.keys(daily).length) return null
|
|
const titles = { year: t('Commits, past year'), week: t('Commits, past 7 days'), repos: t('Original public repositories'), active: t('Active this month') } as const
|
|
const notes = (f: Counted) => (f.id === 'repos' && f.of != null ? t('{n} organizations checked · non-fork repositories', { n: f.of }) : f.id === 'active' ? t('repositories with a commit in 30 days') : undefined)
|
|
const shown = figures(stats)
|
|
return (
|
|
<YStack gap={16} data-slot="activity">
|
|
{shown.length ? (
|
|
<View display="grid" gridTemplateColumns="repeat(2, minmax(0, 1fr))" gap={12} $md={{ gridTemplateColumns: `repeat(${shown.length}, minmax(0, 1fr))`, gap: 16 }}>
|
|
{shown.map((f) => (
|
|
<Figure key={f.id} id={f.id} title={titles[f.id]} value={fmt(f.value)} caption={notes(f)}>
|
|
{f.id === 'year' ? <Sparkline values={weekly(daily, activity.from, activity.to)} label={t('Commits a week over the past year')} height={28} /> : null}
|
|
</Figure>
|
|
))}
|
|
</View>
|
|
) : null}
|
|
<Card title={t('Commits a day')}>
|
|
<Heatmap
|
|
days={daily}
|
|
from={activity.from}
|
|
to={activity.to}
|
|
locale="en-US"
|
|
label={t('Commits a day over the past year across our public repositories: {n} in all.', { n: fmt(stats.commits.year) })}
|
|
line={(day, n) => t('{date} · {n} commits across {repos} repositories', { date: label(day), n: fmt(n), repos: fmt(active[day] ?? 0) })}
|
|
rest={t('Commits a day, from {from} to {to}', { from: label(activity.from), to: label(activity.to) })}
|
|
legend={{ less: t('Less'), more: t('More') }}
|
|
/>
|
|
</Card>
|
|
<Latest rows={activity.latest} />
|
|
<Caption>{live ? t('Live public Git history · updated {at}', { at: hour(live.read) }) : t('Public GitHub snapshot · read {at}', { at: hour(snapshotActivity.read) })}</Caption>
|
|
<XStack justify="flex-end">
|
|
<More href="https://github.com/hanzoai">
|
|
<Onward>{t('Read the source')}</Onward>
|
|
</More>
|
|
</XStack>
|
|
</YStack>
|
|
)
|
|
}
|