@zoyth/simple-site-framework 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3933,4 +3933,77 @@ interface CTASectionProps {
3933
3933
  */
3934
3934
  declare function CTASection({ heading, description, primaryCTA, secondaryCTA, locale, variant, buttonLayout, backgroundColor, align, maxWidth, className, }: CTASectionProps): react_jsx_runtime.JSX.Element;
3935
3935
 
3936
- export { AboutSection, AddressLink, type AddressLinkProps, AnimatedCounter, type AnimatedCounterProps, AnimatedItem, AnimatedSection, type AnimatedSectionProps, type AnimationType, type Badge, type BadgeType, type BillingPeriod, BlogCard, type BlogCardProps, BodyEndScripts, type BodyEndScriptsProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, type CTAButtonConfig, CTASection, type CTASectionProps, Card, type CardProps, CaseStudySection, Checkbox, CheckboxGroup, CheckboxGroupARIA, type CheckboxGroupARIAOption, type CheckboxGroupARIAProps, type CheckboxGroupOption, type CheckboxGroupProps, type CheckboxProps, CodeBlock, type CodeBlockProps, type ComparisonFeature, type ComparisonOption, ComparisonTable, type ComparisonTableProps, ComponentDemo, type ComponentDemoProps, ContactForm, type ContactFormData, type ContactFormField, type ContactFormProps, type ContactFormResponse, ContactSection, CountdownTimer, type CountdownTimerProps, type CustomBadge, EmailLink, type EmailLinkProps, ExitIntentModal, type ExitIntentModalProps, type FAQ, FAQAccordion, type FAQAccordionProps, type Feature, type FeatureCategory, FeatureSection, FeaturesGrid, FileUpload, type FileUploadProps, Footer, type FooterProps, FormField, FormFieldARIA, type FormFieldARIAProps, type FormFieldProps, FormGroup, HeadScripts, type HeadScriptsProps, Header, type HeaderProps, type Heading, HeroSection, I18nMetaTags, type I18nMetaTagsProps, Icon, type IconName, type IconProps, Icons, InlineCode, Input, type InputProps, LanguageSelector, type LanguageSelectorProps, LanguageSwitcher, type LanguageSwitcherProps, LazySection, type LazySectionProps, LiveProof, type LiveProofNotification, type LiveProofProps, LoadingOverlay, type LoadingOverlayProps, LoadingSpinner, type LoadingSpinnerProps, LogosSection, MobileCTA, type MobileCTAProps, Modal, ModalContent, ModalFooter, type ModalProps, ModalRoot, type ModalSize, ModalTrigger, MultiStepForm, type MultiStepFormProps, type NotificationPosition, type OpenGraphMetadata, PersonalTaxesSection, PhoneLink, type PhoneLinkProps, PolicyLayout, type PolicyLayoutProps, type PricingFeature, PricingTable, type PricingTableProps, type PricingTier, Radio, RadioGroup, RadioGroupARIA, type RadioGroupARIAOption, type RadioGroupARIAProps, type RadioGroupOption, type RadioGroupProps, type RadioProps, RecruitingSection, SEOMetaTags, type SEOMetaTagsProps, SecurePortalSection, Select, type SelectOption, type SelectOptionGroup, type SelectProps, ServicePageLayout, ServicesSection, Skeleton, type SkeletonAnimation, SkeletonAvatar, SkeletonButton, SkeletonCard, SkeletonImage, type SkeletonProps, SkeletonText, type SpinnerSize, type SpinnerStyle, type Stat, StatsSection, type StatsSectionProps, type StepProps, StickyBar, type StickyBarProps, StructuredData, type StructuredDataProps, StyleGuide, type StyleGuideProps, type Tab, TableOfContents, type TableOfContentsProps, Tabs, type TabsProps, type Testimonial, TestimonialCarousel, type TestimonialCarouselProps, TestimonialSection, Textarea, type TextareaProps, Timeline, type TimelineItem, type TimelineProps, type Toast, type ToastPosition, ToastProvider, type ToastProviderProps, type ToastType, TrustBadges, type TrustBadgesProps, type TwitterMetadata, WhyChooseUsSection, generateMockNotifications, toast, useMultiStepForm, useToast, withLazyLoad };
3936
+ interface BlogLayoutProps {
3937
+ /** Blog post title */
3938
+ title: string;
3939
+ /** Short description for SEO */
3940
+ excerpt: string;
3941
+ /** Author name */
3942
+ author: string;
3943
+ /** Author avatar URL */
3944
+ authorAvatar?: string;
3945
+ /** Publication date (ISO string YYYY-MM-DD) */
3946
+ date: string;
3947
+ /** Reading time in minutes */
3948
+ readTime: number;
3949
+ /** Post tags */
3950
+ tags: string[];
3951
+ /** Featured image URL */
3952
+ image?: string;
3953
+ /** Featured image alt text */
3954
+ imageAlt?: string;
3955
+ /** Current locale */
3956
+ locale: string;
3957
+ /** Blog post content (from MDX) */
3958
+ children: ReactNode;
3959
+ /** Show table of contents sidebar @default true */
3960
+ showToc?: boolean;
3961
+ /** Link to blog index */
3962
+ backHref?: string;
3963
+ /** Label for back link */
3964
+ backLabel?: string;
3965
+ /** Additional CSS classes */
3966
+ className?: string;
3967
+ }
3968
+ declare function BlogLayout({ title, excerpt, author, authorAvatar, date, readTime, tags, image, imageAlt, locale, children, showToc, backHref, backLabel, className, }: BlogLayoutProps): react_jsx_runtime.JSX.Element;
3969
+
3970
+ interface BlogPostMetadata {
3971
+ title: string;
3972
+ excerpt: string;
3973
+ author: string;
3974
+ /** ISO date (YYYY-MM-DD) */
3975
+ date: string;
3976
+ /** Reading time in minutes */
3977
+ readTime: number;
3978
+ tags: string[];
3979
+ featured?: boolean;
3980
+ /** Featured image URL */
3981
+ image?: string;
3982
+ imageAlt?: string;
3983
+ [key: string]: unknown;
3984
+ }
3985
+
3986
+ interface BlogIndexProps {
3987
+ /** Current locale */
3988
+ locale: string;
3989
+ /** Blog posts to display */
3990
+ posts: Array<{
3991
+ slug: string;
3992
+ metadata: BlogPostMetadata;
3993
+ }>;
3994
+ /** Page title */
3995
+ title?: LocalizedString$2 | string;
3996
+ /** Page description */
3997
+ description?: LocalizedString$2 | string;
3998
+ /** Show tag filter bar @default true */
3999
+ showTagFilter?: boolean;
4000
+ /** BlogCard variant @default 'default' */
4001
+ cardVariant?: 'default' | 'horizontal' | 'minimal';
4002
+ /** Show featured posts prominently @default true */
4003
+ featuredFirst?: boolean;
4004
+ /** Additional CSS classes */
4005
+ className?: string;
4006
+ }
4007
+ declare function BlogIndex({ locale, posts, title, description, showTagFilter, cardVariant, featuredFirst, className, }: BlogIndexProps): react_jsx_runtime.JSX.Element;
4008
+
4009
+ export { AboutSection, AddressLink, type AddressLinkProps, AnimatedCounter, type AnimatedCounterProps, AnimatedItem, AnimatedSection, type AnimatedSectionProps, type AnimationType, type Badge, type BadgeType, type BillingPeriod, BlogCard, type BlogCardProps, BlogIndex, type BlogIndexProps, BlogLayout, type BlogLayoutProps, BodyEndScripts, type BodyEndScriptsProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, type CTAButtonConfig, CTASection, type CTASectionProps, Card, type CardProps, CaseStudySection, Checkbox, CheckboxGroup, CheckboxGroupARIA, type CheckboxGroupARIAOption, type CheckboxGroupARIAProps, type CheckboxGroupOption, type CheckboxGroupProps, type CheckboxProps, CodeBlock, type CodeBlockProps, type ComparisonFeature, type ComparisonOption, ComparisonTable, type ComparisonTableProps, ComponentDemo, type ComponentDemoProps, ContactForm, type ContactFormData, type ContactFormField, type ContactFormProps, type ContactFormResponse, ContactSection, CountdownTimer, type CountdownTimerProps, type CustomBadge, EmailLink, type EmailLinkProps, ExitIntentModal, type ExitIntentModalProps, type FAQ, FAQAccordion, type FAQAccordionProps, type Feature, type FeatureCategory, FeatureSection, FeaturesGrid, FileUpload, type FileUploadProps, Footer, type FooterProps, FormField, FormFieldARIA, type FormFieldARIAProps, type FormFieldProps, FormGroup, HeadScripts, type HeadScriptsProps, Header, type HeaderProps, type Heading, HeroSection, I18nMetaTags, type I18nMetaTagsProps, Icon, type IconName, type IconProps, Icons, InlineCode, Input, type InputProps, LanguageSelector, type LanguageSelectorProps, LanguageSwitcher, type LanguageSwitcherProps, LazySection, type LazySectionProps, LiveProof, type LiveProofNotification, type LiveProofProps, LoadingOverlay, type LoadingOverlayProps, LoadingSpinner, type LoadingSpinnerProps, LogosSection, MobileCTA, type MobileCTAProps, Modal, ModalContent, ModalFooter, type ModalProps, ModalRoot, type ModalSize, ModalTrigger, MultiStepForm, type MultiStepFormProps, type NotificationPosition, type OpenGraphMetadata, PersonalTaxesSection, PhoneLink, type PhoneLinkProps, PolicyLayout, type PolicyLayoutProps, type PricingFeature, PricingTable, type PricingTableProps, type PricingTier, Radio, RadioGroup, RadioGroupARIA, type RadioGroupARIAOption, type RadioGroupARIAProps, type RadioGroupOption, type RadioGroupProps, type RadioProps, RecruitingSection, SEOMetaTags, type SEOMetaTagsProps, SecurePortalSection, Select, type SelectOption, type SelectOptionGroup, type SelectProps, ServicePageLayout, ServicesSection, Skeleton, type SkeletonAnimation, SkeletonAvatar, SkeletonButton, SkeletonCard, SkeletonImage, type SkeletonProps, SkeletonText, type SpinnerSize, type SpinnerStyle, type Stat, StatsSection, type StatsSectionProps, type StepProps, StickyBar, type StickyBarProps, StructuredData, type StructuredDataProps, StyleGuide, type StyleGuideProps, type Tab, TableOfContents, type TableOfContentsProps, Tabs, type TabsProps, type Testimonial, TestimonialCarousel, type TestimonialCarouselProps, TestimonialSection, Textarea, type TextareaProps, Timeline, type TimelineItem, type TimelineProps, type Toast, type ToastPosition, ToastProvider, type ToastProviderProps, type ToastType, TrustBadges, type TrustBadgesProps, type TwitterMetadata, WhyChooseUsSection, generateMockNotifications, toast, useMultiStepForm, useToast, withLazyLoad };
@@ -3933,4 +3933,77 @@ interface CTASectionProps {
3933
3933
  */
3934
3934
  declare function CTASection({ heading, description, primaryCTA, secondaryCTA, locale, variant, buttonLayout, backgroundColor, align, maxWidth, className, }: CTASectionProps): react_jsx_runtime.JSX.Element;
3935
3935
 
3936
- export { AboutSection, AddressLink, type AddressLinkProps, AnimatedCounter, type AnimatedCounterProps, AnimatedItem, AnimatedSection, type AnimatedSectionProps, type AnimationType, type Badge, type BadgeType, type BillingPeriod, BlogCard, type BlogCardProps, BodyEndScripts, type BodyEndScriptsProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, type CTAButtonConfig, CTASection, type CTASectionProps, Card, type CardProps, CaseStudySection, Checkbox, CheckboxGroup, CheckboxGroupARIA, type CheckboxGroupARIAOption, type CheckboxGroupARIAProps, type CheckboxGroupOption, type CheckboxGroupProps, type CheckboxProps, CodeBlock, type CodeBlockProps, type ComparisonFeature, type ComparisonOption, ComparisonTable, type ComparisonTableProps, ComponentDemo, type ComponentDemoProps, ContactForm, type ContactFormData, type ContactFormField, type ContactFormProps, type ContactFormResponse, ContactSection, CountdownTimer, type CountdownTimerProps, type CustomBadge, EmailLink, type EmailLinkProps, ExitIntentModal, type ExitIntentModalProps, type FAQ, FAQAccordion, type FAQAccordionProps, type Feature, type FeatureCategory, FeatureSection, FeaturesGrid, FileUpload, type FileUploadProps, Footer, type FooterProps, FormField, FormFieldARIA, type FormFieldARIAProps, type FormFieldProps, FormGroup, HeadScripts, type HeadScriptsProps, Header, type HeaderProps, type Heading, HeroSection, I18nMetaTags, type I18nMetaTagsProps, Icon, type IconName, type IconProps, Icons, InlineCode, Input, type InputProps, LanguageSelector, type LanguageSelectorProps, LanguageSwitcher, type LanguageSwitcherProps, LazySection, type LazySectionProps, LiveProof, type LiveProofNotification, type LiveProofProps, LoadingOverlay, type LoadingOverlayProps, LoadingSpinner, type LoadingSpinnerProps, LogosSection, MobileCTA, type MobileCTAProps, Modal, ModalContent, ModalFooter, type ModalProps, ModalRoot, type ModalSize, ModalTrigger, MultiStepForm, type MultiStepFormProps, type NotificationPosition, type OpenGraphMetadata, PersonalTaxesSection, PhoneLink, type PhoneLinkProps, PolicyLayout, type PolicyLayoutProps, type PricingFeature, PricingTable, type PricingTableProps, type PricingTier, Radio, RadioGroup, RadioGroupARIA, type RadioGroupARIAOption, type RadioGroupARIAProps, type RadioGroupOption, type RadioGroupProps, type RadioProps, RecruitingSection, SEOMetaTags, type SEOMetaTagsProps, SecurePortalSection, Select, type SelectOption, type SelectOptionGroup, type SelectProps, ServicePageLayout, ServicesSection, Skeleton, type SkeletonAnimation, SkeletonAvatar, SkeletonButton, SkeletonCard, SkeletonImage, type SkeletonProps, SkeletonText, type SpinnerSize, type SpinnerStyle, type Stat, StatsSection, type StatsSectionProps, type StepProps, StickyBar, type StickyBarProps, StructuredData, type StructuredDataProps, StyleGuide, type StyleGuideProps, type Tab, TableOfContents, type TableOfContentsProps, Tabs, type TabsProps, type Testimonial, TestimonialCarousel, type TestimonialCarouselProps, TestimonialSection, Textarea, type TextareaProps, Timeline, type TimelineItem, type TimelineProps, type Toast, type ToastPosition, ToastProvider, type ToastProviderProps, type ToastType, TrustBadges, type TrustBadgesProps, type TwitterMetadata, WhyChooseUsSection, generateMockNotifications, toast, useMultiStepForm, useToast, withLazyLoad };
3936
+ interface BlogLayoutProps {
3937
+ /** Blog post title */
3938
+ title: string;
3939
+ /** Short description for SEO */
3940
+ excerpt: string;
3941
+ /** Author name */
3942
+ author: string;
3943
+ /** Author avatar URL */
3944
+ authorAvatar?: string;
3945
+ /** Publication date (ISO string YYYY-MM-DD) */
3946
+ date: string;
3947
+ /** Reading time in minutes */
3948
+ readTime: number;
3949
+ /** Post tags */
3950
+ tags: string[];
3951
+ /** Featured image URL */
3952
+ image?: string;
3953
+ /** Featured image alt text */
3954
+ imageAlt?: string;
3955
+ /** Current locale */
3956
+ locale: string;
3957
+ /** Blog post content (from MDX) */
3958
+ children: ReactNode;
3959
+ /** Show table of contents sidebar @default true */
3960
+ showToc?: boolean;
3961
+ /** Link to blog index */
3962
+ backHref?: string;
3963
+ /** Label for back link */
3964
+ backLabel?: string;
3965
+ /** Additional CSS classes */
3966
+ className?: string;
3967
+ }
3968
+ declare function BlogLayout({ title, excerpt, author, authorAvatar, date, readTime, tags, image, imageAlt, locale, children, showToc, backHref, backLabel, className, }: BlogLayoutProps): react_jsx_runtime.JSX.Element;
3969
+
3970
+ interface BlogPostMetadata {
3971
+ title: string;
3972
+ excerpt: string;
3973
+ author: string;
3974
+ /** ISO date (YYYY-MM-DD) */
3975
+ date: string;
3976
+ /** Reading time in minutes */
3977
+ readTime: number;
3978
+ tags: string[];
3979
+ featured?: boolean;
3980
+ /** Featured image URL */
3981
+ image?: string;
3982
+ imageAlt?: string;
3983
+ [key: string]: unknown;
3984
+ }
3985
+
3986
+ interface BlogIndexProps {
3987
+ /** Current locale */
3988
+ locale: string;
3989
+ /** Blog posts to display */
3990
+ posts: Array<{
3991
+ slug: string;
3992
+ metadata: BlogPostMetadata;
3993
+ }>;
3994
+ /** Page title */
3995
+ title?: LocalizedString$2 | string;
3996
+ /** Page description */
3997
+ description?: LocalizedString$2 | string;
3998
+ /** Show tag filter bar @default true */
3999
+ showTagFilter?: boolean;
4000
+ /** BlogCard variant @default 'default' */
4001
+ cardVariant?: 'default' | 'horizontal' | 'minimal';
4002
+ /** Show featured posts prominently @default true */
4003
+ featuredFirst?: boolean;
4004
+ /** Additional CSS classes */
4005
+ className?: string;
4006
+ }
4007
+ declare function BlogIndex({ locale, posts, title, description, showTagFilter, cardVariant, featuredFirst, className, }: BlogIndexProps): react_jsx_runtime.JSX.Element;
4008
+
4009
+ export { AboutSection, AddressLink, type AddressLinkProps, AnimatedCounter, type AnimatedCounterProps, AnimatedItem, AnimatedSection, type AnimatedSectionProps, type AnimationType, type Badge, type BadgeType, type BillingPeriod, BlogCard, type BlogCardProps, BlogIndex, type BlogIndexProps, BlogLayout, type BlogLayoutProps, BodyEndScripts, type BodyEndScriptsProps, Breadcrumb, type BreadcrumbItem, type BreadcrumbProps, Button, type ButtonProps, type CTAButtonConfig, CTASection, type CTASectionProps, Card, type CardProps, CaseStudySection, Checkbox, CheckboxGroup, CheckboxGroupARIA, type CheckboxGroupARIAOption, type CheckboxGroupARIAProps, type CheckboxGroupOption, type CheckboxGroupProps, type CheckboxProps, CodeBlock, type CodeBlockProps, type ComparisonFeature, type ComparisonOption, ComparisonTable, type ComparisonTableProps, ComponentDemo, type ComponentDemoProps, ContactForm, type ContactFormData, type ContactFormField, type ContactFormProps, type ContactFormResponse, ContactSection, CountdownTimer, type CountdownTimerProps, type CustomBadge, EmailLink, type EmailLinkProps, ExitIntentModal, type ExitIntentModalProps, type FAQ, FAQAccordion, type FAQAccordionProps, type Feature, type FeatureCategory, FeatureSection, FeaturesGrid, FileUpload, type FileUploadProps, Footer, type FooterProps, FormField, FormFieldARIA, type FormFieldARIAProps, type FormFieldProps, FormGroup, HeadScripts, type HeadScriptsProps, Header, type HeaderProps, type Heading, HeroSection, I18nMetaTags, type I18nMetaTagsProps, Icon, type IconName, type IconProps, Icons, InlineCode, Input, type InputProps, LanguageSelector, type LanguageSelectorProps, LanguageSwitcher, type LanguageSwitcherProps, LazySection, type LazySectionProps, LiveProof, type LiveProofNotification, type LiveProofProps, LoadingOverlay, type LoadingOverlayProps, LoadingSpinner, type LoadingSpinnerProps, LogosSection, MobileCTA, type MobileCTAProps, Modal, ModalContent, ModalFooter, type ModalProps, ModalRoot, type ModalSize, ModalTrigger, MultiStepForm, type MultiStepFormProps, type NotificationPosition, type OpenGraphMetadata, PersonalTaxesSection, PhoneLink, type PhoneLinkProps, PolicyLayout, type PolicyLayoutProps, type PricingFeature, PricingTable, type PricingTableProps, type PricingTier, Radio, RadioGroup, RadioGroupARIA, type RadioGroupARIAOption, type RadioGroupARIAProps, type RadioGroupOption, type RadioGroupProps, type RadioProps, RecruitingSection, SEOMetaTags, type SEOMetaTagsProps, SecurePortalSection, Select, type SelectOption, type SelectOptionGroup, type SelectProps, ServicePageLayout, ServicesSection, Skeleton, type SkeletonAnimation, SkeletonAvatar, SkeletonButton, SkeletonCard, SkeletonImage, type SkeletonProps, SkeletonText, type SpinnerSize, type SpinnerStyle, type Stat, StatsSection, type StatsSectionProps, type StepProps, StickyBar, type StickyBarProps, StructuredData, type StructuredDataProps, StyleGuide, type StyleGuideProps, type Tab, TableOfContents, type TableOfContentsProps, Tabs, type TabsProps, type Testimonial, TestimonialCarousel, type TestimonialCarouselProps, TestimonialSection, Textarea, type TextareaProps, Timeline, type TimelineItem, type TimelineProps, type Toast, type ToastPosition, ToastProvider, type ToastProviderProps, type ToastType, TrustBadges, type TrustBadgesProps, type TwitterMetadata, WhyChooseUsSection, generateMockNotifications, toast, useMultiStepForm, useToast, withLazyLoad };
@@ -28812,6 +28812,8 @@ __export(components_exports, {
28812
28812
  AnimatedItem: () => AnimatedItem,
28813
28813
  AnimatedSection: () => AnimatedSection,
28814
28814
  BlogCard: () => BlogCard,
28815
+ BlogIndex: () => BlogIndex,
28816
+ BlogLayout: () => BlogLayout,
28815
28817
  BodyEndScripts: () => BodyEndScripts,
28816
28818
  Breadcrumb: () => Breadcrumb,
28817
28819
  Button: () => Button,
@@ -34301,6 +34303,10 @@ var import_react24 = require("react");
34301
34303
  var import_rsc = require("next-mdx-remote/rsc");
34302
34304
  var import_rehype_slug = __toESM(require("rehype-slug"));
34303
34305
 
34306
+ // src/lib/content/blog.ts
34307
+ var import_rsc2 = require("next-mdx-remote/rsc");
34308
+ var import_rehype_slug2 = __toESM(require("rehype-slug"));
34309
+
34304
34310
  // src/components/sections/HeroSection.tsx
34305
34311
  var import_image4 = __toESM(require("next/image"));
34306
34312
  var import_jsx_runtime35 = require("react/jsx-runtime");
@@ -38200,6 +38206,206 @@ function CTASection({
38200
38206
  }
38201
38207
  );
38202
38208
  }
38209
+
38210
+ // src/components/BlogLayout.tsx
38211
+ var import_jsx_runtime69 = require("react/jsx-runtime");
38212
+ function BlogLayout({
38213
+ title,
38214
+ excerpt,
38215
+ author,
38216
+ authorAvatar,
38217
+ date,
38218
+ readTime,
38219
+ tags,
38220
+ image,
38221
+ imageAlt,
38222
+ locale,
38223
+ children,
38224
+ showToc = true,
38225
+ backHref,
38226
+ backLabel,
38227
+ className
38228
+ }) {
38229
+ const formattedDate = formatDate2(date, locale);
38230
+ const isFr = locale === "fr";
38231
+ return /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("article", { className: cn("max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 sm:py-12", className), children: [
38232
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
38233
+ "a",
38234
+ {
38235
+ href: backHref || `/${locale}/blog`,
38236
+ className: "inline-flex items-center text-sm text-gray-600 hover:text-primary mb-6",
38237
+ children: [
38238
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { "aria-hidden": "true", children: "\u2190" }),
38239
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { className: "ml-2", children: backLabel || (isFr ? "Retour au blog" : "Back to blog") })
38240
+ ]
38241
+ }
38242
+ ),
38243
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("header", { className: "mb-8 sm:mb-12", children: [
38244
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("h1", { className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-4", children: title }),
38245
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "flex flex-wrap items-center gap-4 text-sm text-gray-600 mb-4", children: [
38246
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "flex items-center gap-2", children: [
38247
+ authorAvatar && /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
38248
+ "img",
38249
+ {
38250
+ src: authorAvatar,
38251
+ alt: author,
38252
+ className: "w-8 h-8 rounded-full object-cover"
38253
+ }
38254
+ ),
38255
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { children: author })
38256
+ ] }),
38257
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { "aria-hidden": "true", children: "\xB7" }),
38258
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("time", { dateTime: date, children: formattedDate }),
38259
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("span", { "aria-hidden": "true", children: "\xB7" }),
38260
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("span", { children: [
38261
+ readTime,
38262
+ " ",
38263
+ isFr ? "min de lecture" : "min read"
38264
+ ] })
38265
+ ] }),
38266
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "flex flex-wrap gap-2", children: tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
38267
+ "span",
38268
+ {
38269
+ className: "inline-block px-3 py-1 text-xs font-medium bg-gray-100 text-gray-700 rounded-full",
38270
+ children: tag
38271
+ },
38272
+ tag
38273
+ )) })
38274
+ ] }),
38275
+ image && /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "mb-8 sm:mb-12 rounded-lg overflow-hidden", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
38276
+ "img",
38277
+ {
38278
+ src: image,
38279
+ alt: imageAlt || title,
38280
+ className: "w-full h-auto object-cover"
38281
+ }
38282
+ ) }),
38283
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)("div", { className: "flex flex-col lg:flex-row gap-8 lg:gap-12", children: [
38284
+ showToc && /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("aside", { className: "hidden lg:block w-64 flex-shrink-0", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "sticky top-24", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(TableOfContents, { title: isFr ? "Table des mati\xE8res" : "Table of Contents" }) }) }),
38285
+ /* @__PURE__ */ (0, import_jsx_runtime69.jsx)("div", { className: "flex-1 min-w-0", children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
38286
+ "div",
38287
+ {
38288
+ className: cn(
38289
+ "prose prose-gray prose-lg max-w-none",
38290
+ "prose-headings:scroll-mt-24",
38291
+ "prose-h2:text-2xl prose-h2:font-bold prose-h2:mt-12 prose-h2:mb-4",
38292
+ "prose-h3:text-xl prose-h3:font-semibold prose-h3:mt-8 prose-h3:mb-3",
38293
+ "prose-h4:text-lg prose-h4:font-semibold prose-h4:mt-6 prose-h4:mb-2",
38294
+ "prose-p:text-gray-700 prose-p:leading-relaxed",
38295
+ "prose-a:text-primary prose-a:no-underline hover:prose-a:underline",
38296
+ "prose-strong:text-gray-900 prose-strong:font-semibold",
38297
+ "prose-ul:my-6 prose-li:my-2",
38298
+ "prose-code:text-primary prose-code:bg-gray-100 prose-code:px-1.5 prose-code:py-0.5 prose-code:rounded",
38299
+ "prose-pre:bg-gray-900 prose-pre:text-gray-100",
38300
+ "prose-blockquote:border-l-primary prose-blockquote:bg-gray-50 prose-blockquote:py-2",
38301
+ "prose-table:text-sm",
38302
+ "sm:prose-lg",
38303
+ "prose-headings:break-words",
38304
+ "prose-p:break-words"
38305
+ ),
38306
+ children
38307
+ }
38308
+ ) })
38309
+ ] })
38310
+ ] });
38311
+ }
38312
+ function formatDate2(dateString, locale) {
38313
+ try {
38314
+ const isoDateMatch = dateString.match(/^(\d{4})-(\d{2})-(\d{2})$/);
38315
+ const date = isoDateMatch ? /* @__PURE__ */ new Date(`${dateString}T12:00:00`) : new Date(dateString);
38316
+ return date.toLocaleDateString(locale, {
38317
+ year: "numeric",
38318
+ month: "long",
38319
+ day: "numeric"
38320
+ });
38321
+ } catch {
38322
+ return dateString;
38323
+ }
38324
+ }
38325
+
38326
+ // src/components/BlogIndex.tsx
38327
+ var import_react35 = require("react");
38328
+ var import_jsx_runtime70 = require("react/jsx-runtime");
38329
+ function BlogIndex({
38330
+ locale,
38331
+ posts,
38332
+ title,
38333
+ description,
38334
+ showTagFilter = true,
38335
+ cardVariant = "default",
38336
+ featuredFirst = true,
38337
+ className
38338
+ }) {
38339
+ const [activeTag, setActiveTag] = (0, import_react35.useState)(null);
38340
+ const resolvedTitle = title ? typeof title === "string" ? title : getLocalizedString(title, locale) : void 0;
38341
+ const resolvedDescription = description ? typeof description === "string" ? description : getLocalizedString(description, locale) : void 0;
38342
+ const allTags = (0, import_react35.useMemo)(() => {
38343
+ const tagSet = /* @__PURE__ */ new Set();
38344
+ for (const post of posts) {
38345
+ for (const tag of post.metadata.tags) {
38346
+ tagSet.add(tag);
38347
+ }
38348
+ }
38349
+ return Array.from(tagSet).sort();
38350
+ }, [posts]);
38351
+ const filteredPosts = activeTag ? posts.filter((p) => p.metadata.tags.includes(activeTag)) : posts;
38352
+ const featuredPosts = featuredFirst ? filteredPosts.filter((p) => p.metadata.featured) : [];
38353
+ const regularPosts = featuredFirst ? filteredPosts.filter((p) => !p.metadata.featured) : filteredPosts;
38354
+ const isFr = locale === "fr";
38355
+ return /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: cn("max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8 sm:py-12", className), children: [
38356
+ (resolvedTitle || resolvedDescription) && /* @__PURE__ */ (0, import_jsx_runtime70.jsxs)("div", { className: "mb-8 sm:mb-12", children: [
38357
+ resolvedTitle && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("h1", { className: "text-3xl sm:text-4xl lg:text-5xl font-bold text-gray-900 mb-3", children: resolvedTitle }),
38358
+ resolvedDescription && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("p", { className: "text-lg text-gray-600", children: resolvedDescription })
38359
+ ] }),
38360
+ showTagFilter && allTags.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "flex flex-wrap gap-2 mb-8", role: "group", "aria-label": isFr ? "Filtrer par tag" : "Filter by tag", children: allTags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
38361
+ "button",
38362
+ {
38363
+ onClick: () => setActiveTag(activeTag === tag ? null : tag),
38364
+ className: cn(
38365
+ "px-3 py-1.5 text-sm font-medium rounded-full transition-colors",
38366
+ activeTag === tag ? "bg-primary text-white" : "bg-gray-100 text-gray-700 hover:bg-gray-200"
38367
+ ),
38368
+ children: tag
38369
+ },
38370
+ tag
38371
+ )) }),
38372
+ filteredPosts.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "text-center py-16", children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("p", { className: "text-gray-500 text-lg", children: isFr ? "Aucun article trouv\xE9." : "No posts found." }) }),
38373
+ featuredPosts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "mb-12", children: /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-6", children: featuredPosts.map((post) => /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
38374
+ BlogCard,
38375
+ {
38376
+ locale,
38377
+ title: post.metadata.title,
38378
+ excerpt: post.metadata.excerpt,
38379
+ image: post.metadata.image,
38380
+ imageAlt: post.metadata.imageAlt,
38381
+ href: `/${locale}/blog/${post.slug}`,
38382
+ author: post.metadata.author,
38383
+ date: post.metadata.date,
38384
+ readTime: post.metadata.readTime,
38385
+ tags: post.metadata.tags,
38386
+ variant: cardVariant
38387
+ },
38388
+ post.slug
38389
+ )) }) }),
38390
+ regularPosts.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime70.jsx)("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6", children: regularPosts.map((post) => /* @__PURE__ */ (0, import_jsx_runtime70.jsx)(
38391
+ BlogCard,
38392
+ {
38393
+ locale,
38394
+ title: post.metadata.title,
38395
+ excerpt: post.metadata.excerpt,
38396
+ image: post.metadata.image,
38397
+ imageAlt: post.metadata.imageAlt,
38398
+ href: `/${locale}/blog/${post.slug}`,
38399
+ author: post.metadata.author,
38400
+ date: post.metadata.date,
38401
+ readTime: post.metadata.readTime,
38402
+ tags: post.metadata.tags,
38403
+ variant: cardVariant
38404
+ },
38405
+ post.slug
38406
+ )) })
38407
+ ] });
38408
+ }
38203
38409
  // Annotate the CommonJS export names for ESM import in node:
38204
38410
  0 && (module.exports = {
38205
38411
  AboutSection,
@@ -38208,6 +38414,8 @@ function CTASection({
38208
38414
  AnimatedItem,
38209
38415
  AnimatedSection,
38210
38416
  BlogCard,
38417
+ BlogIndex,
38418
+ BlogLayout,
38211
38419
  BodyEndScripts,
38212
38420
  Breadcrumb,
38213
38421
  Button,