{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"llms-txt-editor","type":"registry:ui","title":"LlmsTxtEditor","description":"llms.txt editor \u2014 title \/ summary \/ details + repeatable link sections.","package":"fancy-x-files-ui","dependencies":["@particle-academy\/react-fancy"],"registryDependencies":["model.js","validate.js"],"files":[{"path":"components\/fancy\/llms-txt-editor\/LlmsTxtEditor.tsx","content":"import { Button, Input, Textarea } from \"@particle-academy\/react-fancy\";\r\nimport type { LlmsLink, LlmsSection, LlmsTxtModel } from \"..\/model.js\";\r\nimport { validateLlmsTxt } from \"..\/validate.js\";\r\nimport { IssueList, Section } from \".\/internal.js\";\r\n\r\nexport interface LlmsTxtEditorProps {\r\n  value: LlmsTxtModel;\r\n  onChange: (next: LlmsTxtModel) => void;\r\n  hideIssues?: boolean;\r\n  className?: string;\r\n}\r\n\r\n\/** Controlled llms.txt editor: title\/summary\/details + repeatable sections. *\/\r\nexport function LlmsTxtEditor({\r\n  value,\r\n  onChange,\r\n  hideIssues,\r\n  className,\r\n}: LlmsTxtEditorProps) {\r\n  const issues = validateLlmsTxt(value);\r\n  const patch = (next: Partial<LlmsTxtModel>) => onChange({ ...value, ...next });\r\n\r\n  const updateSection = (index: number, next: Partial<LlmsSection>) => {\r\n    const sections = value.sections.map((s, i) =>\r\n      i === index ? { ...s, ...next } : s,\r\n    );\r\n    patch({ sections });\r\n  };\r\n\r\n  const addSection = () =>\r\n    patch({ sections: [...value.sections, { name: \"\", links: [] }] });\r\n\r\n  const removeSection = (index: number) =>\r\n    patch({ sections: value.sections.filter((_, i) => i !== index) });\r\n\r\n  const updateLink = (\r\n    si: number,\r\n    li: number,\r\n    next: Partial<LlmsLink>,\r\n  ) => {\r\n    const links = value.sections[si].links.map((l, i) =>\r\n      i === li ? { ...l, ...next } : l,\r\n    );\r\n    updateSection(si, { links });\r\n  };\r\n\r\n  const addLink = (si: number) =>\r\n    updateSection(si, {\r\n      links: [...value.sections[si].links, { title: \"\", url: \"\" }],\r\n    });\r\n\r\n  const removeLink = (si: number, li: number) =>\r\n    updateSection(si, {\r\n      links: value.sections[si].links.filter((_, i) => i !== li),\r\n    });\r\n\r\n  return (\r\n    <div className={className} data-x-editor=\"llmsTxt\">\r\n      <Section title=\"Header\" handle=\"llms-header\">\r\n        <Input\r\n          label=\"Title\"\r\n          value={value.title}\r\n          onValueChange={(title) => patch({ title })}\r\n          placeholder=\"Example Corp\"\r\n          data-x-input=\"llms-title\"\r\n        \/>\r\n        <Textarea\r\n          label=\"Summary\"\r\n          value={value.summary ?? \"\"}\r\n          onValueChange={(v) => patch({ summary: v || undefined })}\r\n          placeholder=\"One-line blockquote summary.\"\r\n          data-x-input=\"llms-summary\"\r\n        \/>\r\n        <Textarea\r\n          label=\"Details\"\r\n          value={value.details ?? \"\"}\r\n          onValueChange={(v) => patch({ details: v || undefined })}\r\n          placeholder=\"Free-form Markdown paragraph(s).\"\r\n          data-x-input=\"llms-details\"\r\n        \/>\r\n      <\/Section>\r\n\r\n      <Section\r\n        title=\"Sections\"\r\n        handle=\"llms-sections\"\r\n        action={\r\n          <Button\r\n            type=\"button\"\r\n            variant=\"ghost\"\r\n            onClick={addSection}\r\n            data-x-add=\"llms-section\"\r\n          >\r\n            Add section\r\n          <\/Button>\r\n        }\r\n      >\r\n        {value.sections.map((section, si) => (\r\n          <div\r\n            key={si}\r\n            data-x-section-row={si}\r\n            style={{\r\n              border: \"1px solid var(--rf-border, #e5e7eb)\",\r\n              borderRadius: \"0.5rem\",\r\n              padding: \"0.75rem\",\r\n              display: \"flex\",\r\n              flexDirection: \"column\",\r\n              gap: \"0.5rem\",\r\n            }}\r\n          >\r\n            <div style={{ display: \"flex\", gap: \"0.5rem\", alignItems: \"end\" }}>\r\n              <div style={{ flex: 1 }}>\r\n                <Input\r\n                  label=\"Section name\"\r\n                  value={section.name}\r\n                  onValueChange={(name) => updateSection(si, { name })}\r\n                  placeholder=\"Docs\"\r\n                  data-x-input={`llms-section-name:${si}`}\r\n                \/>\r\n              <\/div>\r\n              <Button\r\n                type=\"button\"\r\n                variant=\"ghost\"\r\n                color=\"red\"\r\n                onClick={() => removeSection(si)}\r\n                data-x-remove={`llms-section:${si}`}\r\n              >\r\n                Remove\r\n              <\/Button>\r\n            <\/div>\r\n\r\n            {section.links.map((link, li) => (\r\n              <div\r\n                key={li}\r\n                data-x-link-row={`${si}:${li}`}\r\n                style={{\r\n                  display: \"flex\",\r\n                  gap: \"0.4rem\",\r\n                  alignItems: \"end\",\r\n                  flexWrap: \"wrap\",\r\n                }}\r\n              >\r\n                <div style={{ flex: \"1 1 8rem\" }}>\r\n                  <Input\r\n                    label={li === 0 ? \"Title\" : undefined}\r\n                    value={link.title}\r\n                    onValueChange={(title) => updateLink(si, li, { title })}\r\n                    placeholder=\"Getting started\"\r\n                    data-x-input={`llms-link-title:${si}:${li}`}\r\n                  \/>\r\n                <\/div>\r\n                <div style={{ flex: \"1 1 10rem\" }}>\r\n                  <Input\r\n                    label={li === 0 ? \"URL\" : undefined}\r\n                    value={link.url}\r\n                    onValueChange={(url) => updateLink(si, li, { url })}\r\n                    placeholder=\"https:\/\/example.com\/docs\"\r\n                    data-x-input={`llms-link-url:${si}:${li}`}\r\n                  \/>\r\n                <\/div>\r\n                <div style={{ flex: \"1 1 8rem\" }}>\r\n                  <Input\r\n                    label={li === 0 ? \"Notes\" : undefined}\r\n                    value={link.notes ?? \"\"}\r\n                    onValueChange={(v) =>\r\n                      updateLink(si, li, { notes: v || undefined })\r\n                    }\r\n                    placeholder=\"optional\"\r\n                    data-x-input={`llms-link-notes:${si}:${li}`}\r\n                  \/>\r\n                <\/div>\r\n                <Button\r\n                  type=\"button\"\r\n                  variant=\"ghost\"\r\n                  color=\"red\"\r\n                  onClick={() => removeLink(si, li)}\r\n                  data-x-remove={`llms-link:${si}:${li}`}\r\n                >\r\n                  \u00d7\r\n                <\/Button>\r\n              <\/div>\r\n            ))}\r\n            <Button\r\n              type=\"button\"\r\n              variant=\"ghost\"\r\n              onClick={() => addLink(si)}\r\n              data-x-add={`llms-link:${si}`}\r\n            >\r\n              Add link\r\n            <\/Button>\r\n          <\/div>\r\n        ))}\r\n      <\/Section>\r\n\r\n      {hideIssues ? null : <IssueList issues={issues} testid=\"llmsTxt\" \/>}\r\n    <\/div>\r\n  );\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/llms-txt-editor\/LlmsTxtEditor.tsx"}]}