diff --git a/app/components/DocsCards.tsx b/app/components/DocsCards.tsx index 6abb8ce..cf3ef15 100644 --- a/app/components/DocsCards.tsx +++ b/app/components/DocsCards.tsx @@ -13,28 +13,89 @@ interface DocFile { excerpt: string; content: string; firstImage?: string; + tags?: string[]; + stability?: 'stable' | 'in-dev' | 'experimental'; } -function parseFileContent(content: string): DocFile { - const [, frontMatter, markdownContent] = content.split('---'); - const metadata = Object.fromEntries( - frontMatter.trim().split('\n').map(line => line.split(': ')) - ); +// function parseFileContent(content: string): { parsedDoc: DocFile; rawMetadata: any } { +// const [, frontMatter, markdownContent] = content.split('---'); +// const metadata = Object.fromEntries( +// frontMatter.trim().split('\n').map(line => { +// const [key, ...value] = line.split(': '); +// return [key, value.join(': ').trim()]; +// }) +// ); +// +// console.log('Raw parsed metadata:', metadata); +// +// const parsedDoc: DocFile = { +// slug: '', // You'll need to set this elsewhere +// title: metadata.title || '', +// excerpt: metadata.excerpt || '', +// content: markdownContent.trim(), +// firstImage: metadata.image || undefined, +// tags: metadata.tags ? JSON.parse(metadata.tags.replace(/'/g, '"')) : undefined, +// stability: metadata.stability as 'stable' | 'in-dev' | 'experimental' | undefined +// }; +// +// console.log('Parsed document:', parsedDoc); +// +// return { parsedDoc, rawMetadata: metadata }; +// } - const firstParagraph = markdownContent.trim().split('\n\n')[0]; +const stabilityEmoji: { [key: string]: string } = { + stable: '✅ Stable - ', + 'in-dev': '🚧 InDev - ', + experimental: '🧪 Experimental - ' +}; - return { - slug: '', // You'll need to set this elsewhere - title: metadata.title || '', - excerpt: metadata.excerpt || '', - content: markdownContent.trim(), - firstImage: metadata.image || undefined - }; +interface TagsProps { + tags: string[]; + selectedTags: string[]; + setSelectedTags: React.Dispatch>; } +const Tags: React.FC = ({ tags, selectedTags, setSelectedTags }) => ( +
+ {tags.map(tag => ( + + ))} +
+); + +interface StabilityFilterProps { + selectedStability: string; + setSelectedStability: React.Dispatch>; +} + +const StabilityFilter: React.FC = ({ selectedStability, setSelectedStability }) => ( + +); + export function DocsCards({ docs }: { docs: DocFile[] }) { const [active, setActive] = useState(null); const [searchTerm, setSearchTerm] = useState(""); + const [selectedTags, setSelectedTags] = useState([]); + const [selectedStability, setSelectedStability] = useState('all'); const ref = useRef(null); const id = useId(); @@ -58,18 +119,40 @@ export function DocsCards({ docs }: { docs: DocFile[] }) { useOutsideClick(ref, () => setActive(null)); const filteredDocs = docs.filter((doc) => - doc.title.toLowerCase().includes(searchTerm.toLowerCase()) || - doc.excerpt.toLowerCase().includes(searchTerm.toLowerCase()) + (doc.title.toLowerCase().includes(searchTerm.toLowerCase()) || + doc.excerpt.toLowerCase().includes(searchTerm.toLowerCase())) && + (selectedTags.length === 0 || (doc.tags && selectedTags.every(tag => doc.tags.includes(tag)))) && + (selectedStability === 'all' || (doc.stability && doc.stability === selectedStability)) ); + const allTags = Array.from(new Set(docs.flatMap(doc => doc.tags || []))); + const renderExcerpt = (content: string) => { const firstParagraph = content.split('\n\n')[0]; return marked(firstParagraph); }; + const renderTags = (tags: string[] | undefined) => { + if (!tags || tags.length === 0) return null; + return ( +
+ {tags.map(tag => ( + + {tag} + + ))} +
+ ); + }; + + const renderStabilityEmoji = (stability: string | undefined) => { + if (!stability || !stabilityEmoji[stability]) return null; + return {stabilityEmoji[stability]}; + }; + return ( <> -
+
setSearchTerm(e.target.value)} className="w-full p-2 border border-gray-300 text-black rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" /> + +
{active && ( @@ -122,7 +207,7 @@ export function DocsCards({ docs }: { docs: DocFile[] }) { layoutId={`title-${active.slug}-${id}`} className="text-2xl font-bold text-neutral-800 dark:text-neutral-100 mb-4" > - {active.title} + {renderStabilityEmoji(active.stability)}{active.title} + {renderTags(active.tags)} - doc.title.toLowerCase().includes(searchTerm.toLowerCase()) - ); - - return ( - <> - setSearchTerm(e.target.value)} - /> -
    - {filteredDocs.map((doc) => ( -
  • - - {doc.title} - -
  • - ))} -
- - ); -} \ No newline at end of file diff --git a/app/docs/[slug]/page.tsx b/app/docs/[slug]/page.tsx index ae56c81..bf0ab4c 100644 --- a/app/docs/[slug]/page.tsx +++ b/app/docs/[slug]/page.tsx @@ -31,7 +31,7 @@ async function getDocContent(slug: string) { export default async function DocPage({ params }: { params: { slug: string } }) { const { content } = await getDocContent(params.slug); return ( -
+
{ const { data, content } = matter(fileContents); - if (!data.title) { console.warn(`Document ${slug} does not have a valid title and will be skipped.`); return null; } - + const excerpt = data.excerpt || content.slice(0, 150) + '...'; const htmlContent = await marked(content); - + return { slug, title: data.title, excerpt, content, firstImage: data.image || undefined, - htmlContent + htmlContent, + tags: data.tags || [], + stability: data.stability as 'stable' | 'in-dev' | 'experimental' | undefined }; } async function getDocs(): Promise { const docsDirectory = path.join(process.cwd(), 'docs'); const filenames = fs.readdirSync(docsDirectory); - const docsPromises = filenames.map(async (filename) => { const filePath = path.join(docsDirectory, filename); const fileContents = fs.readFileSync(filePath, 'utf8'); @@ -45,7 +47,6 @@ async function getDocs(): Promise { return await parseFileContent(fileContents, slug); }); - const docs = await Promise.all(docsPromises); return docs.filter((doc): doc is DocFile => doc !== null); } diff --git a/docs/about-horizon.md b/docs/about-horizon.md index fe3266d..13259b7 100644 --- a/docs/about-horizon.md +++ b/docs/about-horizon.md @@ -1,6 +1,8 @@ --- title: About Horizon image: +tags: [] +stability: stable excerpt: A brief introduction to Horizon --- diff --git a/docs/api-experimental.md b/docs/api-experimental.md index c0737e7..e51687c 100644 --- a/docs/api-experimental.md +++ b/docs/api-experimental.md @@ -1,6 +1,8 @@ --- -title: 🧪 Experimental Plugin API +title: Plugin API image: +tags: [] +stability: experimental excerpt: The Plugin API is an experimental feature of Horizon and is not recommended for use in production environments yet. --- diff --git a/docs/development.md b/docs/development.md index 148955c..47bac82 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,7 +1,9 @@ --- -title: Development - Getting started +title: Getting started with Development image: excerpt: A starting point to learn about developing for Horizon +tags: [] +stability: stable --- # Developer Documentation - Overview