{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "desktop-6",
  "title": "Desktop 6: About window",
  "author": "Ballmac <https://ui.ballmac.com>",
  "description": "The About window of a desktop app: icon, name, version and build with a copy button, links, open-source acknowledgements and Check for updates. Small and centered on macOS, a dialog with OK on Windows.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://ui.ballmac.com/r/app-window.json",
    "https://ui.ballmac.com/r/button.json",
    "https://ui.ballmac.com/r/feel-presets.json"
  ],
  "files": [
    {
      "path": "registry/ballmac/components/blocks/desktop-6/desktop-6.tsx",
      "content": "// Ballmac UI: Desktop 6. https://ui.ballmac.com/blocks/desktop-6\n\"use client\"\n\nimport * as React from \"react\"\nimport { Check, ChevronLeft, Copy, Info, Sparkles } from \"lucide-react\"\n\nimport { AppWindow, AppWindowContent, AppWindowTitleBar } from \"@/components/ballmac/app-window\"\nimport { Button, buttonVariants } from \"@/components/ballmac/button\"\nimport { useFeel, type FeelId } from \"@/lib/ballmac/feel\"\nimport { cn } from \"@/lib/utils\"\n\ntype Desktop6Acknowledgement = { name: string; license: string; href?: string }\n\ntype Desktop6Props = Omit<React.ComponentProps<\"div\">, \"children\"> & {\n  /** Which platform the window handles like. Defaults to the page's feel. */\n  feel?: FeelId\n  /** Draw the window frame. Turn off inside a real Tauri or Electron window that already has one. */\n  frame?: boolean\n  appName?: string\n  version?: string\n  /** The build number, shown in brackets after the version as macOS does. */\n  build?: string\n  /** The app icon. A generated one is drawn when you leave it out. */\n  icon?: React.ReactNode\n  /** One line about the app. */\n  tagline?: string\n  copyright?: string\n  /** Links under the version: website, privacy policy, support. */\n  links?: { label: string; href: string }[]\n  /** Open-source software the app includes, listed under Acknowledgements. */\n  acknowledgements?: Desktop6Acknowledgement[]\n  /** Called by \"Check for updates\". Leave it out to hide the button. */\n  onCheckForUpdates?: () => void\n  /** Called by OK (Windows) and the close button. */\n  onClose?: () => void\n}\n\nconst sampleAck: Desktop6Acknowledgement[] = [\n  { name: \"Tauri\", license: \"MIT or Apache-2.0\", href: \"https://github.com/tauri-apps/tauri\" },\n  { name: \"React\", license: \"MIT\", href: \"https://github.com/facebook/react\" },\n  { name: \"Radix UI\", license: \"MIT\", href: \"https://github.com/radix-ui/primitives\" },\n  { name: \"Lucide\", license: \"ISC\", href: \"https://github.com/lucide-icons/lucide\" },\n  { name: \"Ballmac UI\", license: \"MIT\", href: \"https://ui.ballmac.com\" },\n]\n\nfunction AppIcon({ icon, className }: { icon?: React.ReactNode; className?: string }) {\n  return (\n    <span\n      aria-hidden=\"true\"\n      className={cn(\n        \"from-primary to-primary/70 text-primary-foreground flex shrink-0 items-center justify-center rounded-[22%] bg-linear-to-b shadow-[0_2px_6px_rgb(0_0_0/0.18),inset_0_1px_0_rgb(255_255_255/0.25)] [&_svg]:size-1/2\",\n        className\n      )}\n    >\n      {icon ?? <Sparkles />}\n    </span>\n  )\n}\n\n/**\n * The About window: icon, name, version and build (with a button that copies them for a support email), copyright, links,\n * acknowledgements for the open-source software inside, and Check for updates. Small and centered on macOS, a dialog with OK on Windows.\n */\nfunction Desktop6({\n  feel: feelProp,\n  frame = true,\n  appName = \"Acme\",\n  version = \"2.4.1\",\n  build = \"241\",\n  icon,\n  tagline = \"Notes that stay out of your way.\",\n  copyright = \"© 2026 Acme, Inc. All rights reserved.\",\n  links = [\n    { label: \"Website\", href: \"#\" },\n    { label: \"Privacy\", href: \"#\" },\n    { label: \"Support\", href: \"#\" },\n  ],\n  acknowledgements = sampleAck,\n  onCheckForUpdates,\n  onClose,\n  className,\n  ...props\n}: Desktop6Props) {\n  const page = useFeel().feel\n  const feel = feelProp ?? page\n  const win = feel === \"windows\"\n  const mac = feel === \"macos\"\n  const id = React.useId()\n  const [view, setView] = React.useState<\"about\" | \"acknowledgements\">(\"about\")\n  const [copied, setCopied] = React.useState(false)\n  const versionText = build ? `Version ${version} (${build})` : `Version ${version}`\n  React.useEffect(() => {\n    if (!copied) return\n    const t = setTimeout(() => setCopied(false), 1600)\n    return () => clearTimeout(t)\n  }, [copied])\n\n  const copy = async () => {\n    try {\n      await navigator.clipboard?.writeText(`${appName} ${versionText}`)\n      setCopied(true)\n    } catch {}\n  }\n  const t = (macText: string, other: string) => (mac ? macText : other)\n\n  const about = (\n    <div className={cn(\"flex flex-1 flex-col gap-4 p-6\", mac ? \"items-center text-center\" : \"\")}>\n      <div className={cn(\"flex gap-4\", mac ? \"flex-col items-center\" : \"items-center\")}>\n        <AppIcon icon={icon} className={mac ? \"size-20\" : \"size-14\"} />\n        <div>\n          <h2 id={`${id}-title`} className={cn(\"font-semibold\", mac ? \"text-base\" : \"text-lg\")}>\n            {appName}\n          </h2>\n          <div className={cn(\"mt-0.5 flex items-center gap-1\", mac && \"justify-center\")}>\n            <p className=\"text-muted-foreground text-xs tabular-nums select-text\">{versionText}</p>\n            <Button variant=\"ghost\" size=\"icon-sm\" className=\"size-6 [&_svg]:size-3\" onClick={copy} aria-label={copied ? \"Version copied\" : \"Copy version\"}>\n              {copied ? <Check aria-hidden=\"true\" /> : <Copy aria-hidden=\"true\" />}\n            </Button>\n          </div>\n        </div>\n      </div>\n      {tagline ? <p className=\"text-[13px] text-pretty\">{tagline}</p> : null}\n      {links.length ? (\n        <nav aria-label={`About ${appName}`} className={cn(\"flex flex-wrap gap-x-4 gap-y-1\", mac && \"justify-center\")}>\n          {links.map((l) => (\n            <a key={l.label} href={l.href} target=\"_blank\" rel=\"noreferrer\" className=\"text-primary rounded-sm text-[13px] underline-offset-4 outline-none hover:underline focus-visible:ring-[3px] focus-visible:ring-ring/50\">\n              {l.label}\n            </a>\n          ))}\n        </nav>\n      ) : null}\n      <div className=\"flex-1\" />\n      <div className={cn(\"flex flex-wrap items-center gap-2\", mac ? \"justify-center\" : \"\")}>\n        {acknowledgements.length ? (\n          <Button variant=\"outline\" size=\"sm\" onClick={() => setView(\"acknowledgements\")}>\n            {t(\"Acknowledgements\", \"Third-party notices\")}\n          </Button>\n        ) : null}\n        {onCheckForUpdates ? (\n          <Button variant=\"outline\" size=\"sm\" onClick={onCheckForUpdates}>\n            {t(\"Check for Updates…\", \"Check for updates\")}\n          </Button>\n        ) : null}\n        {win ? (\n          <Button size=\"sm\" className=\"ms-auto min-w-20\" onClick={onClose}>\n            OK\n          </Button>\n        ) : null}\n      </div>\n      {copyright ? <p className=\"text-muted-foreground text-[11px]\">{copyright}</p> : null}\n      <p aria-live=\"polite\" className=\"sr-only\">\n        {copied ? \"Version copied\" : \"\"}\n      </p>\n    </div>\n  )\n\n  const acks = (\n    <div className=\"flex min-h-0 flex-1 flex-col gap-3 p-4\">\n      <div className=\"flex items-center gap-2\">\n        <Button variant=\"ghost\" size=\"sm\" onClick={() => setView(\"about\")} className=\"ps-1.5\">\n          <ChevronLeft aria-hidden=\"true\" className=\"rtl:rotate-180\" />\n          Back\n        </Button>\n        <h2 id={`${id}-title`} className=\"text-sm font-semibold\">\n          {t(\"Acknowledgements\", \"Third-party notices\")}\n        </h2>\n      </div>\n      <p className=\"text-muted-foreground px-1 text-xs text-pretty\">{appName} is built with open-source software. Thank you to everyone who works on it.</p>\n      <ul tabIndex={0} aria-label={t(\"Acknowledgements\", \"Third-party notices\")} className=\"bg-background min-h-0 flex-1 divide-y overflow-y-auto rounded-md border outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50\">\n        {acknowledgements.map((a) => (\n          <li key={a.name} className=\"flex items-center justify-between gap-3 px-3 py-2 text-[13px]\">\n            {a.href ? (\n              <a href={a.href} target=\"_blank\" rel=\"noreferrer\" className={cn(buttonVariants({ variant: \"link\" }), \"h-auto px-0 text-[13px] font-medium\")}>\n                {a.name}\n              </a>\n            ) : (\n              <span className=\"font-medium\">{a.name}</span>\n            )}\n            <span className=\"text-muted-foreground text-xs\">{a.license}</span>\n          </li>\n        ))}\n      </ul>\n    </div>\n  )\n\n  const content = view === \"about\" ? about : acks\n  if (!frame)\n    return (\n      <div data-slot=\"desktop-6\" data-feel={feelProp} role=\"region\" aria-labelledby={`${id}-title`} className={cn(\"flex flex-col\", className)} {...props}>\n        {content}\n      </div>\n    )\n  return (\n    <AppWindow\n      data-slot=\"desktop-6\"\n      feel={feel}\n      onClose={onClose}\n      role=\"region\"\n      aria-labelledby={`${id}-title`}\n      className={cn(mac ? \"h-[24rem] w-full max-w-[19rem]\" : \"h-[22rem] w-full max-w-md\", className)}\n      {...props}\n    >\n      <AppWindowTitleBar title={win ? `About ${appName}` : \"\"} icon={<Info />} className=\"border-b-0\" />\n      <AppWindowContent className=\"flex flex-col\">{content}</AppWindowContent>\n    </AppWindow>\n  )\n}\n\nexport { Desktop6, type Desktop6Props, type Desktop6Acknowledgement }\n",
      "type": "registry:component",
      "target": "@components/ballmac/blocks/desktop-6/desktop-6.tsx"
    }
  ],
  "meta": {
    "schema": 1,
    "tier": "free",
    "tags": [
      "desktop",
      "about",
      "version",
      "acknowledgements",
      "credits",
      "licenses",
      "tauri",
      "electron",
      "macos",
      "windows",
      "feel"
    ],
    "version": "1.0.0",
    "updated": "2026-10-17",
    "tests": true,
    "ai": {
      "summary": "An About window. <Desktop6 appName version build tagline copyright links={[{ label, href }]} acknowledgements={[{ name, license, href }]} onCheckForUpdates onClose />. Acknowledgements open in the same window with a Back button; the copy button puts \"Acme Version 2.4.1 (241)\" on the clipboard.",
      "whenToUse": [
        "The About item in a Tauri or Electron app's app menu",
        "Crediting the open-source licences a desktop app ships with"
      ],
      "whenNotToUse": [
        "A company About page on a website (use team-1 or a marketing block)"
      ],
      "composesWith": [
        "desktop-1",
        "desktop-3",
        "app-window",
        "feel-auto"
      ],
      "a11y": [
        {
          "keys": "Tab",
          "action": "The copy button is named \"Copy version\" and announces \"Version copied\""
        },
        {
          "keys": "Acknowledgements",
          "action": "The list is a focusable scroll region; Back returns to the About view"
        }
      ],
      "customization": [
        "feel: 'macos' | 'windows' (defaults to the page's feel); frame={false} inside a real native window",
        "Tauri: version from getVersion() in @tauri-apps/api/app; Electron: app.getVersion()",
        "Generate acknowledgements from your lockfile with a licence checker at build time"
      ]
    },
    "statesNone": "Static content: nothing to load, submit or fail.",
    "examples": [
      "desktop-6-demo",
      "desktop-6-windows"
    ],
    "url": "https://ui.ballmac.com/components/desktop-6"
  },
  "categories": [
    "blocks",
    "desktop"
  ],
  "type": "registry:block"
}