Files
zeekay fe79d984ad Expose composer and Settings usage and expand live public activity coverage
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.
2026-10-27 14:55:30 -07:00

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>
)
}