{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"sitemap-editor","type":"registry:ui","title":"SitemapEditor","description":"sitemap.xml editor \u2014 a flat list of URL entries with lastmod \/ changefreq \/ priority.","package":"fancy-x-files-ui","dependencies":["@particle-academy\/react-fancy"],"registryDependencies":["model.js","validate.js"],"files":[{"path":"components\/fancy\/sitemap-editor\/SitemapEditor.tsx","content":"import { Button, Input, Select } from \"@particle-academy\/react-fancy\";\r\nimport type {\r\n  SitemapChangeFreq,\r\n  SitemapModel,\r\n  SitemapUrl,\r\n} from \"..\/model.js\";\r\nimport { validateSitemap } from \"..\/validate.js\";\r\nimport { IssueList, Section } from \".\/internal.js\";\r\n\r\nexport interface SitemapEditorProps {\r\n  value: SitemapModel;\r\n  onChange: (next: SitemapModel) => void;\r\n  hideIssues?: boolean;\r\n  className?: string;\r\n}\r\n\r\nconst CHANGE_FREQS: SitemapChangeFreq[] = [\r\n  \"always\",\r\n  \"hourly\",\r\n  \"daily\",\r\n  \"weekly\",\r\n  \"monthly\",\r\n  \"yearly\",\r\n  \"never\",\r\n];\r\n\r\n\/** Controlled sitemap.xml editor: a flat list of URL entries. *\/\r\nexport function SitemapEditor({\r\n  value,\r\n  onChange,\r\n  hideIssues,\r\n  className,\r\n}: SitemapEditorProps) {\r\n  const issues = validateSitemap(value);\r\n  const patch = (next: Partial<SitemapModel>) => onChange({ ...value, ...next });\r\n\r\n  const updateUrl = (index: number, next: Partial<SitemapUrl>) =>\r\n    patch({\r\n      urls: value.urls.map((u, i) => (i === index ? { ...u, ...next } : u)),\r\n    });\r\n\r\n  const addUrl = () => patch({ urls: [...value.urls, { loc: \"\" }] });\r\n\r\n  const removeUrl = (index: number) =>\r\n    patch({ urls: value.urls.filter((_, i) => i !== index) });\r\n\r\n  return (\r\n    <div className={className} data-x-editor=\"sitemap\">\r\n      <Section\r\n        title=\"URLs\"\r\n        handle=\"sitemap-urls\"\r\n        action={\r\n          <Button\r\n            type=\"button\"\r\n            variant=\"ghost\"\r\n            onClick={addUrl}\r\n            data-x-add=\"sitemap-url\"\r\n          >\r\n            Add URL\r\n          <\/Button>\r\n        }\r\n      >\r\n        {value.urls.map((url, i) => (\r\n          <div\r\n            key={i}\r\n            data-x-url={i}\r\n            style={{\r\n              border: \"1px solid var(--rf-border, #e5e7eb)\",\r\n              borderRadius: \"0.5rem\",\r\n              padding: \"0.6rem\",\r\n              display: \"flex\",\r\n              flexDirection: \"column\",\r\n              gap: \"0.4rem\",\r\n            }}\r\n          >\r\n            <div style={{ display: \"flex\", gap: \"0.4rem\", alignItems: \"end\" }}>\r\n              <div style={{ flex: 1 }}>\r\n                <Input\r\n                  label=\"loc\"\r\n                  value={url.loc}\r\n                  onValueChange={(loc) => updateUrl(i, { loc })}\r\n                  placeholder=\"https:\/\/example.com\/page\"\r\n                  data-x-input={`sitemap-loc:${i}`}\r\n                \/>\r\n              <\/div>\r\n              <Button\r\n                type=\"button\"\r\n                variant=\"ghost\"\r\n                color=\"red\"\r\n                onClick={() => removeUrl(i)}\r\n                data-x-remove={`sitemap-url:${i}`}\r\n              >\r\n                \u00d7\r\n              <\/Button>\r\n            <\/div>\r\n            <div\r\n              style={{\r\n                display: \"flex\",\r\n                gap: \"0.4rem\",\r\n                flexWrap: \"wrap\",\r\n              }}\r\n            >\r\n              <div style={{ flex: \"1 1 9rem\" }}>\r\n                <Input\r\n                  label=\"lastmod\"\r\n                  type=\"text\"\r\n                  value={url.lastmod ?? \"\"}\r\n                  onValueChange={(v) =>\r\n                    updateUrl(i, { lastmod: v || undefined })\r\n                  }\r\n                  placeholder=\"2026-01-01\"\r\n                  data-x-input={`sitemap-lastmod:${i}`}\r\n                \/>\r\n              <\/div>\r\n              <div style={{ flex: \"1 1 9rem\" }}>\r\n                <Select\r\n                  label=\"changefreq\"\r\n                  value={url.changefreq ?? \"\"}\r\n                  list={[\"\", ...CHANGE_FREQS]}\r\n                  onValueChange={(v) =>\r\n                    updateUrl(i, {\r\n                      changefreq: (v || undefined) as\r\n                        | SitemapChangeFreq\r\n                        | undefined,\r\n                    })\r\n                  }\r\n                  data-x-input={`sitemap-changefreq:${i}`}\r\n                \/>\r\n              <\/div>\r\n              <div style={{ flex: \"1 1 6rem\" }}>\r\n                <Input\r\n                  label=\"priority\"\r\n                  type=\"number\"\r\n                  value={url.priority != null ? String(url.priority) : \"\"}\r\n                  onValueChange={(v) =>\r\n                    updateUrl(i, {\r\n                      priority: v === \"\" ? undefined : Number(v),\r\n                    })\r\n                  }\r\n                  placeholder=\"0.5\"\r\n                  data-x-input={`sitemap-priority:${i}`}\r\n                \/>\r\n              <\/div>\r\n            <\/div>\r\n          <\/div>\r\n        ))}\r\n      <\/Section>\r\n\r\n      {hideIssues ? null : <IssueList issues={issues} testid=\"sitemap\" \/>}\r\n    <\/div>\r\n  );\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/sitemap-editor\/SitemapEditor.tsx"}]}