{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"analytics-block","type":"registry:block","title":"Analytics workspace","description":"A date window, a chart and sortable readings driven by the same sample dataset, with CSV export.","registryDependencies":["https://mizu.user64bit.world/r/data-table.json","https://mizu.user64bit.world/r/date-range-field.json","https://mizu.user64bit.world/r/segmented-control.json","https://mizu.user64bit.world/r/stat.json","https://mizu.user64bit.world/r/trend-chart.json"],"meta":{"client":true},"files":[{"path":"registry/blocks/AnalyticsBlock.tsx","type":"registry:component","target":"@ui/mizu/blocks/AnalyticsBlock.tsx","content":"\"use client\";\n\nimport { useState } from \"react\";\nimport { DataTable } from \"../data-table\";\nimport { DateRangeField, type DateRange } from \"../date-range-field\";\nimport { SegmentedControl } from \"../segmented-control\";\nimport { Stat } from \"../stat\";\nimport { TrendChart } from \"../trend-chart\";\nimport \"./blocks.css\";\n\nconst readings = Array.from({ length: 21 }, (_, index) => ({\n  date: `2026-10-${String(index + 1).padStart(2, \"0\")}`,\n  visits: 1180 + index * 47 + ((index * 173) % 420),\n  signups: 42 + index * 3 + ((index * 11) % 24),\n}));\nconst initialWindow = { start: \"2026-10-15\", end: \"2026-10-21\" };\nconst number = new Intl.NumberFormat(\"en-US\");\nconst day = new Intl.DateTimeFormat(\"en\", {\n  month: \"short\",\n  day: \"numeric\",\n  timeZone: \"UTC\",\n});\n\nexport function AnalyticsBlock() {\n  const [window, setWindow] = useState<DateRange>(initialWindow);\n  const [metric, setMetric] = useState(\"visits\");\n  const filtered = readings.filter(\n    (reading) =>\n      (!window.start || reading.date >= window.start) &&\n      (!window.end || reading.date <= window.end),\n  );\n  const visits = filtered.reduce((sum, reading) => sum + reading.visits, 0);\n  const signups = filtered.reduce((sum, reading) => sum + reading.signups, 0);\n  const csv = [\n    \"date,visits,signups\",\n    ...filtered.map(\n      (reading) => `${reading.date},${reading.visits},${reading.signups}`,\n    ),\n  ].join(\"\\n\");\n  return (\n    <section\n      className=\"mizu-block mizu-block-analytics\"\n      aria-label=\"Sample analytics workspace\"\n    >\n      <div className=\"mizu-block-analytics-controls\">\n        <DateRangeField\n          label=\"Reporting window\"\n          value={window}\n          onValueChange={setWindow}\n          defaultValue={initialWindow}\n          min=\"2026-10-01\"\n          max=\"2026-10-21\"\n          hint=\"Illustrative data, October 1–21, 2026.\"\n          presets={[\n            { label: \"Sample week\", value: initialWindow },\n            {\n              label: \"All sample dates\",\n              value: { start: \"2026-10-01\", end: \"2026-10-21\" },\n            },\n          ]}\n        />\n        <div className=\"mizu-block-analytics-summary\">\n          <Stat\n            label=\"Visits\"\n            value={number.format(visits)}\n            detail={`${filtered.length} days in view`}\n          />\n          <Stat\n            label=\"Signups\"\n            value={number.format(signups)}\n            detail={`${visits ? ((signups / visits) * 100).toFixed(1) : \"0.0\"}% of visits`}\n          />\n        </div>\n      </div>\n      <div className=\"mizu-block-toolbar\">\n        <SegmentedControl\n          label=\"Plot metric\"\n          value={metric}\n          onValueChange={setMetric}\n          options={[\n            { value: \"visits\", label: \"Visits\" },\n            { value: \"signups\", label: \"Signups\" },\n          ]}\n        />\n        <a\n          className=\"mizu-block-download\"\n          href={`data:text/csv;charset=utf-8,${encodeURIComponent(csv)}`}\n          download=\"mizu-sample-analytics.csv\"\n        >\n          Export current CSV\n        </a>\n      </div>\n      <TrendChart\n        label={metric === \"visits\" ? \"Sample visits\" : \"Sample signups\"}\n        series={[\n          {\n            id: metric,\n            label: metric === \"visits\" ? \"Visits\" : \"Signups\",\n            data: filtered.map((reading) => ({\n              x: Date.parse(`${reading.date}T00:00:00Z`),\n              y: metric === \"visits\" ? reading.visits : reading.signups,\n            })),\n            area: true,\n          },\n        ]}\n        utc\n        height={240}\n        formatX={(timestamp) => day.format(timestamp)}\n        format={(value) => number.format(value)}\n        zero\n        empty=\"No sample readings in this date window. Adjust the dates or choose a preset.\"\n      />\n      <DataTable\n        label=\"Daily sample readings\"\n        rows={filtered}\n        getRowId={(reading) => reading.date}\n        empty=\"No readings match the date window.\"\n        columns={[\n          {\n            id: \"date\",\n            header: \"Date\",\n            sortValue: (reading) => reading.date,\n            render: (reading) => (\n              <time dateTime={reading.date}>{reading.date}</time>\n            ),\n          },\n          {\n            id: \"visits\",\n            header: \"Visits\",\n            align: \"right\",\n            sortValue: (reading) => reading.visits,\n            render: (reading) => number.format(reading.visits),\n          },\n          {\n            id: \"signups\",\n            header: \"Signups\",\n            align: \"right\",\n            sortValue: (reading) => reading.signups,\n            render: (reading) => number.format(reading.signups),\n          },\n        ]}\n      />\n    </section>\n  );\n}\n"},{"path":"registry/blocks/blocks.css","type":"registry:file","target":"@ui/mizu/blocks/blocks.css","content":".mizu-block {\n  min-width: 0;\n  color: var(--mizu-paper);\n  background: var(--mizu-ink);\n}\n.mizu-block h3 {\n  margin: 0 0 12px;\n  font: 600 24px / 1.2 var(--mizu-font-display);\n  letter-spacing: -0.025em;\n}\n.mizu-block p {\n  max-width: 65ch;\n}\n.mizu-block-settings {\n  display: grid;\n  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);\n  gap: 48px;\n}\n.mizu-block-settings-intro > p:first-of-type {\n  margin: 0 0 24px;\n  color: var(--mizu-muted);\n  line-height: 1.6;\n}\n.mizu-block-settings-intro > .mizu-field-hint {\n  margin-top: 24px;\n}\n.mizu-block-settings-form {\n  display: grid;\n  gap: 24px;\n}\n.mizu-block-settings-form > p {\n  margin: 0;\n}\n.mizu-block-settings-form > p:empty {\n  position: absolute;\n}\n.mizu-block-actions,\n.mizu-block-toolbar {\n  display: flex;\n  align-items: end;\n  justify-content: space-between;\n  gap: 16px;\n  flex-wrap: wrap;\n}\n.mizu-block-actions {\n  align-items: stretch;\n  justify-content: flex-start;\n}\n.mizu-block-text-action,\n.mizu-block-download {\n  display: inline-flex;\n  align-items: center;\n  min-height: 44px;\n  padding: 8px 0;\n  border: 0;\n  background: transparent;\n  color: var(--mizu-accent);\n  font: 11px var(--mizu-font-mono);\n  text-decoration: underline;\n  text-underline-offset: 4px;\n  cursor: pointer;\n}\n.mizu-block-text-action:hover,\n.mizu-block-download:hover {\n  color: var(--mizu-paper);\n}\n.mizu-block-text-action:focus-visible,\n.mizu-block-download:focus-visible,\n.mizu-block-file-name:focus-visible,\n.mizu-block-file-detail pre:focus-visible {\n  outline: 2px solid var(--mizu-accent);\n  outline-offset: 4px;\n}\n.mizu-block-toolbar > .mizu-search {\n  flex: 1 1 240px;\n}\n.mizu-block-toolbar > .mizu-field {\n  flex: 0 1 200px;\n}\n.mizu-block-readout {\n  margin: 16px 0;\n  color: var(--mizu-muted);\n  font: 11px var(--mizu-font-mono);\n  font-variant-numeric: tabular-nums;\n}\n.mizu-block-file-workspace {\n  display: grid;\n  grid-template-columns: minmax(0, 1.5fr) minmax(240px, 1fr);\n  gap: 32px;\n  align-items: start;\n}\n.mizu-block-file-name {\n  min-height: 44px;\n  padding: 0;\n  border: 0;\n  background: none;\n  color: var(--mizu-paper);\n  font: inherit;\n  text-align: left;\n  text-decoration: underline;\n  text-decoration-color: transparent;\n  text-underline-offset: 4px;\n  overflow-wrap: anywhere;\n  cursor: pointer;\n  transition: text-decoration-color var(--mizu-duration-fast);\n}\n.mizu-block-file-name:hover {\n  text-decoration-color: var(--mizu-line-bright);\n}\n.mizu-block-file-name[aria-pressed=\"true\"] {\n  color: var(--mizu-accent);\n}\n.mizu-block-file-detail {\n  min-width: 0;\n  padding: 24px;\n  border: 1px solid var(--mizu-line);\n  background: var(--mizu-ink-2);\n}\n.mizu-block-file-detail h3 {\n  font-size: 20px;\n  overflow-wrap: anywhere;\n}\n.mizu-block-file-detail pre {\n  max-height: 240px;\n  margin: 20px 0 8px;\n  overflow: auto;\n  white-space: pre-wrap;\n  overflow-wrap: anywhere;\n  color: var(--mizu-paper);\n  font: 11px / 1.7 var(--mizu-font-mono);\n  tab-size: 2;\n}\n.mizu-block-analytics {\n  display: grid;\n  gap: 32px;\n}\n.mizu-block-analytics-controls {\n  display: grid;\n  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);\n  gap: 48px;\n  align-items: start;\n}\n.mizu-block-analytics-summary {\n  display: grid;\n  grid-template-columns: repeat(2, minmax(0, 1fr));\n  gap: 24px;\n  padding-top: 28px;\n}\n@media (max-width: 800px) {\n  .mizu-block-settings,\n  .mizu-block-file-workspace,\n  .mizu-block-analytics-controls {\n    grid-template-columns: minmax(0, 1fr);\n    gap: 28px;\n  }\n  .mizu-block-analytics-summary {\n    padding-top: 0;\n  }\n}\n@media (max-width: 420px) {\n  .mizu-block-analytics-summary {\n    grid-template-columns: minmax(0, 1fr);\n  }\n}\n"}]}