diff --git a/src/pages/authors/[authorSlug].astro b/src/pages/authors/[authorSlug].astro new file mode 100644 index 000000000..0e628c610 --- /dev/null +++ b/src/pages/authors/[authorSlug].astro @@ -0,0 +1,194 @@ +--- +import BaseLayout from '../../layouts/BaseLayout.astro'; +import SimplePageHeader from '../../components/SimplePageHeader.astro'; +import { httpGet } from '../../lib/http'; + +export async function getStaticPaths() { + // For now, return an empty array for static generation + // In production, you'd fetch all authors here + return []; +} + +const { authorSlug } = Astro.params; +const apiUrl = import.meta.env.PUBLIC_API_URL || 'http://localhost:8080'; + +// Fetch author details +const { response: author, error: authorError } = await httpGet( + `${apiUrl}/v1-get-author/${authorSlug}` +); + +if (authorError || !author) { + return Astro.redirect('/404'); +} + +// Fetch author's guides +const { response: guidesData, error: guidesError } = await httpGet( + `${apiUrl}/v1-list-guides`, + { + authorId: author._id, + perPage: 100, + sortBy: '-publishedAt', + } +); + +const guides = guidesData?.data || []; + +// Check if guide is within the last 15 days +const isNew = (publishedAt: string) => { + if (!publishedAt) return false; + const daysDiff = Math.floor((Date.now() - new Date(publishedAt).getTime()) / (1000 * 60 * 60 * 24)); + return daysDiff < 15; +}; +--- + + +
+
+
+ +
+
+ {author.avatar && ( + {author.name} + )} +
+

+ {author.name} +

+ + {author.bio && ( +

+ {author.bio} +

+ )} + +
+ + {author.guideCount} {author.guideCount === 1 ? 'guide' : 'guides'} published + + + {author.socialLinks && ( +
+ {author.socialLinks.twitter && ( + + Twitter + + )} + {author.socialLinks.github && ( + + GitHub + + )} + {author.socialLinks.linkedin && ( + + LinkedIn + + )} + {author.socialLinks.website && ( + + Website + + )} +
+ )} +
+
+
+
+ + +
+

+ Guides by {author.name} +

+ + {guides.length === 0 ? ( +

No guides published yet.

+ ) : ( + + )} +
+
+
+
+
+
\ No newline at end of file diff --git a/src/pages/guides-v2.astro b/src/pages/guides-v2.astro new file mode 100644 index 000000000..d887cb1b7 --- /dev/null +++ b/src/pages/guides-v2.astro @@ -0,0 +1,81 @@ +--- +import SimplePageHeader from '../components/SimplePageHeader.astro'; +import BaseLayout from '../layouts/BaseLayout.astro'; +import { httpGet } from '../lib/http'; + +const apiUrl = import.meta.env.PUBLIC_API_URL || 'http://localhost:8080'; + +// Fetch guides from the new v2 API +const { response: guidesData, error } = await httpGet( + `${apiUrl}/v1-list-guides`, + { + perPage: 100, + sortBy: '-publishedAt', + } +); + +const guides = guidesData?.data || []; +const sortedGuides = guides.sort((a: any, b: any) => { + const aDate = new Date(a.publishedAt as string); + const bDate = new Date(b.publishedAt as string); + return bDate.getTime() - aDate.getTime(); +}); + +const getGuideType = (guide: any) => { + if (guide.roadmapId) { + return 'Roadmap Guide'; + } + return 'Guide'; +}; + +// Check if guide is within the last 15 days +const isNew = (publishedAt: string) => { + if (!publishedAt) return false; + const daysDiff = Math.floor((Date.now() - new Date(publishedAt).getTime()) / (1000 * 60 * 60 * 24)); + return daysDiff < 15; +}; +--- + + + + + +
+
\ No newline at end of file diff --git a/src/pages/guides/[guideSlug].astro b/src/pages/guides/[guideSlug].astro new file mode 100644 index 000000000..9c836b9f4 --- /dev/null +++ b/src/pages/guides/[guideSlug].astro @@ -0,0 +1,198 @@ +--- +import BaseLayout from '../../layouts/BaseLayout.astro'; +import { httpGet } from '../../lib/http'; + +export async function getStaticPaths() { + const apiUrl = import.meta.env.PUBLIC_API_URL || 'http://localhost:8080'; + + const { response: guidesData } = await httpGet( + `${apiUrl}/v1-list-guides`, + { + perPage: 100, + sortBy: '-publishedAt', + } + ); + + const guides = guidesData?.data || []; + + return guides.map((guide: any) => ({ + params: { guideSlug: guide.slug }, + props: { guideSlug: guide.slug }, + })); +} + +const { guideSlug } = Astro.params; +const apiUrl = import.meta.env.PUBLIC_API_URL || 'http://localhost:8080'; + +const { response: guide, error } = await httpGet( + `${apiUrl}/v1-get-guide/${guideSlug}` +); + +if (error || !guide) { + return Astro.redirect('/404'); +} + +// Convert content to HTML if needed +const renderContent = (content: any) => { + if (typeof content === 'string') { + return content; + } + // If content is JSON from tiptap editor, we'll need to convert it + // For now, return a placeholder + return '
Guide content will be rendered here
'; +}; +--- + + +
+
+
+ +
+

+ {guide.title} +

+ + {guide.description && ( +

+ {guide.description} +

+ )} + +
+ {guide.author && ( + + {guide.author.avatar && ( + {guide.author.name} + )} + By {guide.author.name} + + )} + + {guide.publishedAt && ( + + {new Date(guide.publishedAt).toLocaleDateString('en-US', { + year: 'numeric', + month: 'long', + day: 'numeric' + })} + + )} + + {guide.viewCount && ( + {guide.viewCount.toLocaleString()} views + )} +
+ + {guide.tags && guide.tags.length > 0 && ( +
+ {guide.tags.map((tag: string) => ( + + {tag} + + ))} +
+ )} +
+ + + {guide.featuredImage && ( +
+ {guide.title} +
+ )} + + +
+ +
+ + + {guide.author && guide.author.bio && ( +
+

About the Author

+
+ {guide.author.avatar && ( + {guide.author.name} + )} +
+ + {guide.author.name} + +

{guide.author.bio}

+ + {guide.author.socialLinks && ( +
+ {guide.author.socialLinks.twitter && ( + + Twitter + + )} + {guide.author.socialLinks.github && ( + + GitHub + + )} + {guide.author.socialLinks.linkedin && ( + + LinkedIn + + )} + {guide.author.socialLinks.website && ( + + Website + + )} +
+ )} +
+
+
+ )} +
+
+
+
+
\ No newline at end of file