@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.
- package/dist/components/index.d.mts +74 -1
- package/dist/components/index.d.ts +74 -1
- package/dist/components/index.js +208 -0
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +206 -0
- package/dist/components/index.mjs.map +1 -1
- package/dist/index.d.mts +113 -2
- package/dist/index.d.ts +113 -2
- package/dist/index.js +196 -16
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +187 -16
- package/dist/index.mjs.map +1 -1
- package/docs/BLOG.md +1005 -0
- package/package.json +1 -1
|
@@ -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
|
-
|
|
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
|
-
|
|
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 };
|
package/dist/components/index.js
CHANGED
|
@@ -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,
|