@timmbr/ui 1.3.1 → 1.4.1
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/NavFooter/NavFooter.d.ts +9 -0
- package/dist/components/NavFooter/NavFooter.d.ts.map +1 -0
- package/dist/components/NavFooter/NavFooter.helpers.d.ts +27 -0
- package/dist/components/NavFooter/NavFooter.helpers.d.ts.map +1 -0
- package/dist/components/NavFooter/NavFooter.helpers.js +78 -0
- package/dist/components/NavFooter/NavFooter.js +251 -0
- package/dist/components/NavFooter/NavFooter.styles.d.ts +37 -0
- package/dist/components/NavFooter/NavFooter.styles.d.ts.map +1 -0
- package/dist/components/NavFooter/NavFooter.styles.js +54 -0
- package/dist/components/NavFooter/NavFooter.types.d.ts +414 -0
- package/dist/components/NavFooter/NavFooter.types.d.ts.map +1 -0
- package/dist/components/NavFooter/index.d.ts +5 -0
- package/dist/components/NavFooter/index.d.ts.map +1 -0
- package/dist/components/NavFooter/subcomponents/FooterBrand.d.ts +16 -0
- package/dist/components/NavFooter/subcomponents/FooterBrand.d.ts.map +1 -0
- package/dist/components/NavFooter/subcomponents/FooterBrand.js +99 -0
- package/dist/components/NavFooter/subcomponents/FooterLegalBar.d.ts +10 -0
- package/dist/components/NavFooter/subcomponents/FooterLegalBar.d.ts.map +1 -0
- package/dist/components/NavFooter/subcomponents/FooterLegalBar.js +60 -0
- package/dist/components/NavFooter/subcomponents/FooterNavSection.d.ts +15 -0
- package/dist/components/NavFooter/subcomponents/FooterNavSection.d.ts.map +1 -0
- package/dist/components/NavFooter/subcomponents/FooterNavSection.js +123 -0
- package/dist/components/NavFooter/subcomponents/FooterNewsletter.d.ts +9 -0
- package/dist/components/NavFooter/subcomponents/FooterNewsletter.d.ts.map +1 -0
- package/dist/components/NavFooter/subcomponents/FooterNewsletter.js +95 -0
- package/dist/components/NavFooter/subcomponents/FooterOffice.d.ts +9 -0
- package/dist/components/NavFooter/subcomponents/FooterOffice.d.ts.map +1 -0
- package/dist/components/NavFooter/subcomponents/FooterOffice.js +63 -0
- package/dist/components/NavFooter/subcomponents/FooterSocial.d.ts +12 -0
- package/dist/components/NavFooter/subcomponents/FooterSocial.d.ts.map +1 -0
- package/dist/components/NavFooter/subcomponents/FooterSocial.js +50 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/test-mocks/next-headers.d.ts +1 -0
- package/dist/test-mocks/next-headers.d.ts.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NavFooterProps } from './NavFooter.types';
|
|
3
|
+
export declare const NavFooter: React.ForwardRefExoticComponent<NavFooterProps & React.RefAttributes<HTMLElement>>;
|
|
4
|
+
/**
|
|
5
|
+
* Convenience alias for `NavFooter`.
|
|
6
|
+
*/
|
|
7
|
+
export declare const Footer: React.ForwardRefExoticComponent<NavFooterProps & React.RefAttributes<HTMLElement>>;
|
|
8
|
+
export default NavFooter;
|
|
9
|
+
//# sourceMappingURL=NavFooter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavFooter.d.ts","sourceRoot":"","sources":["../../../src/components/NavFooter/NavFooter.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,OAAO,KAAK,EACV,cAAc,EAOf,MAAM,mBAAmB,CAAC;AAc3B,eAAO,MAAM,SAAS,oFAuRrB,CAAC;AAIF;;GAEG;AACH,eAAO,MAAM,MAAM,oFAAY,CAAC;AAEhC,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { NavFooterSection, NavFooterLinkItem, NavFooterSocialLink } from './NavFooter.types';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves full destination URL across micro-frontends and zones.
|
|
5
|
+
*/
|
|
6
|
+
export declare function resolveNavDestination(href?: string, zone?: string, zones?: Record<string, string>): string | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Checks if link requires cross-origin / cross-zone full page load.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isCrossZoneNavigation(zone?: string, currentZone?: string, explicitCrossZone?: boolean): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Built-in Social Icon SVGs matching Figma design system specifications.
|
|
13
|
+
*/
|
|
14
|
+
export declare const DefaultSocialIcons: Record<string, React.ReactNode>;
|
|
15
|
+
/**
|
|
16
|
+
* Default sample sections from Figma design for out-of-the-box usage.
|
|
17
|
+
*/
|
|
18
|
+
export declare const DEFAULT_FOOTER_SECTIONS: NavFooterSection[];
|
|
19
|
+
/**
|
|
20
|
+
* Default sample social links from Figma design.
|
|
21
|
+
*/
|
|
22
|
+
export declare const DEFAULT_FOOTER_SOCIAL_LINKS: NavFooterSocialLink[];
|
|
23
|
+
/**
|
|
24
|
+
* Default sample legal links.
|
|
25
|
+
*/
|
|
26
|
+
export declare const DEFAULT_FOOTER_LEGAL_LINKS: NavFooterLinkItem[];
|
|
27
|
+
//# sourceMappingURL=NavFooter.helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavFooter.helpers.d.ts","sourceRoot":"","sources":["../../../src/components/NavFooter/NavFooter.helpers.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAElG;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,CAAC,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,MAAM,EACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC7B,MAAM,GAAG,SAAS,CAGpB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,CAAC,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,EACpB,iBAAiB,CAAC,EAAE,OAAO,GAC1B,OAAO,CAKT;AAED;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,SAAS,CAyC9D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,EAAE,gBAAgB,EAgCrD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,2BAA2B,EAAE,mBAAmB,EAK5D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,iBAAiB,EAGzD,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
2
|
+
import { resolveZoneHref } from '../../providers/TimmbrConfigProvider.js';
|
|
3
|
+
|
|
4
|
+
function resolveNavDestination(href, zone, zones) {
|
|
5
|
+
if (!href) return void 0;
|
|
6
|
+
return resolveZoneHref(href, zone, zones);
|
|
7
|
+
}
|
|
8
|
+
function isCrossZoneNavigation(zone, currentZone, explicitCrossZone) {
|
|
9
|
+
if (explicitCrossZone) return true;
|
|
10
|
+
if (!zone) return false;
|
|
11
|
+
if (!currentZone) return true;
|
|
12
|
+
return zone !== currentZone;
|
|
13
|
+
}
|
|
14
|
+
const DefaultSocialIcons = {
|
|
15
|
+
instagram: /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: [
|
|
16
|
+
/* @__PURE__ */ jsx("rect", { width: "20", height: "20", x: "2", y: "2", rx: "5", ry: "5" }),
|
|
17
|
+
/* @__PURE__ */ jsx("path", { d: "M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z" }),
|
|
18
|
+
/* @__PURE__ */ jsx("line", { x1: "17.5", x2: "17.51", y1: "6.5", y2: "6.5" })
|
|
19
|
+
] }),
|
|
20
|
+
facebook: /* @__PURE__ */ jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: /* @__PURE__ */ jsx("path", { d: "M18 2h-3a5 5 0 0 0-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 0 1 1-1h3z" }) }),
|
|
21
|
+
linkedin: /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: [
|
|
22
|
+
/* @__PURE__ */ jsx("path", { d: "M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z" }),
|
|
23
|
+
/* @__PURE__ */ jsx("rect", { width: "4", height: "12", x: "2", y: "9" }),
|
|
24
|
+
/* @__PURE__ */ jsx("circle", { cx: "4", cy: "4", r: "2" })
|
|
25
|
+
] }),
|
|
26
|
+
x: /* @__PURE__ */ jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", className: "shrink-0", children: /* @__PURE__ */ jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) }),
|
|
27
|
+
twitter: /* @__PURE__ */ jsx("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "currentColor", className: "shrink-0", children: /* @__PURE__ */ jsx("path", { d: "M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" }) }),
|
|
28
|
+
youtube: /* @__PURE__ */ jsxs("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: [
|
|
29
|
+
/* @__PURE__ */ jsx("path", { d: "M2.5 17a24.12 24.12 0 0 1 0-10 2 2 0 0 1 1.4-1.4 49.56 49.56 0 0 1 16.2 0A2 2 0 0 1 21.5 7a24.12 24.12 0 0 1 0 10 2 2 0 0 1-1.4 1.4 49.55 49.55 0 0 1-16.2 0A2 2 0 0 1 2.5 17" }),
|
|
30
|
+
/* @__PURE__ */ jsx("polygon", { points: "10 15 15 12 10 9 10 15", fill: "currentColor" })
|
|
31
|
+
] }),
|
|
32
|
+
pinterest: /* @__PURE__ */ jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", className: "shrink-0", children: /* @__PURE__ */ jsx("path", { d: "M12 0C5.373 0 0 5.372 0 12c0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738a.36.36 0 0 1 .083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146C9.57 23.812 10.763 24 12 24c6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z" }) })
|
|
33
|
+
};
|
|
34
|
+
const DEFAULT_FOOTER_SECTIONS = [
|
|
35
|
+
{
|
|
36
|
+
id: "shop",
|
|
37
|
+
title: "Shop",
|
|
38
|
+
items: [
|
|
39
|
+
{ id: "sofas", label: "Sofa's", href: "/shop/sofas" },
|
|
40
|
+
{ id: "living", label: "Living", href: "/shop/living" },
|
|
41
|
+
{ id: "bedroom", label: "Bedroom", href: "/shop/bedroom" },
|
|
42
|
+
{ id: "office", label: "Office", href: "/shop/office" },
|
|
43
|
+
{ id: "dining", label: "Dining", href: "/shop/dining" }
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: "craft",
|
|
48
|
+
title: "Craft",
|
|
49
|
+
items: [
|
|
50
|
+
{ id: "materials", label: "Our materials", href: "/craft/materials" },
|
|
51
|
+
{ id: "workshop", label: "The workshop", href: "/craft/workshop" },
|
|
52
|
+
{ id: "sustainability", label: "Sustainability", href: "/craft/sustainability" },
|
|
53
|
+
{ id: "care", label: "Care guide", href: "/craft/care-guide" }
|
|
54
|
+
]
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "help",
|
|
58
|
+
title: "Help",
|
|
59
|
+
items: [
|
|
60
|
+
{ id: "contact", label: "Contact Us", href: "/help/contact" },
|
|
61
|
+
{ id: "delivery", label: "Delivery", href: "/help/delivery" },
|
|
62
|
+
{ id: "returns", label: "Returns", href: "/help/returns" },
|
|
63
|
+
{ id: "warranty", label: "Warranty", href: "/help/warranty" }
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
];
|
|
67
|
+
const DEFAULT_FOOTER_SOCIAL_LINKS = [
|
|
68
|
+
{ name: "instagram", href: "https://instagram.com/timmbr", ariaLabel: "Follow us on Instagram" },
|
|
69
|
+
{ name: "facebook", href: "https://facebook.com/timmbr", ariaLabel: "Follow us on Facebook" },
|
|
70
|
+
{ name: "linkedin", href: "https://linkedin.com/company/timmbr", ariaLabel: "Connect on LinkedIn" },
|
|
71
|
+
{ name: "x", href: "https://x.com/timmbr", ariaLabel: "Follow us on X" }
|
|
72
|
+
];
|
|
73
|
+
const DEFAULT_FOOTER_LEGAL_LINKS = [
|
|
74
|
+
{ id: "privacy", label: "Privacy", href: "/privacy" },
|
|
75
|
+
{ id: "terms", label: "Terms", href: "/terms" }
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
export { DEFAULT_FOOTER_LEGAL_LINKS, DEFAULT_FOOTER_SECTIONS, DEFAULT_FOOTER_SOCIAL_LINKS, DefaultSocialIcons, isCrossZoneNavigation, resolveNavDestination };
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '@timmbr/utils';
|
|
5
|
+
import { resolveMotion } from '../../types/motion.js';
|
|
6
|
+
import { navFooterContainerVariants, navFooterRootVariants } from './NavFooter.styles.js';
|
|
7
|
+
import { DEFAULT_FOOTER_SECTIONS, DEFAULT_FOOTER_SOCIAL_LINKS, DEFAULT_FOOTER_LEGAL_LINKS } from './NavFooter.helpers.js';
|
|
8
|
+
import { FooterBrand } from './subcomponents/FooterBrand.js';
|
|
9
|
+
import { FooterNavSection } from './subcomponents/FooterNavSection.js';
|
|
10
|
+
import { FooterSocial } from './subcomponents/FooterSocial.js';
|
|
11
|
+
import { FooterOffice } from './subcomponents/FooterOffice.js';
|
|
12
|
+
import { FooterNewsletter } from './subcomponents/FooterNewsletter.js';
|
|
13
|
+
import { FooterLegalBar } from './subcomponents/FooterLegalBar.js';
|
|
14
|
+
import { useGlobalAnimation } from '../../providers/AnimationProvider.js';
|
|
15
|
+
|
|
16
|
+
const NavFooter = React.forwardRef(
|
|
17
|
+
(props, ref) => {
|
|
18
|
+
const {
|
|
19
|
+
// 1. Modular Configuration Objects
|
|
20
|
+
branding: brandingProp,
|
|
21
|
+
navigation: navigationProp,
|
|
22
|
+
social: socialProp,
|
|
23
|
+
office: officeProp,
|
|
24
|
+
newsletter: newsletterProp,
|
|
25
|
+
legal: legalProp,
|
|
26
|
+
mobile: mobileProp,
|
|
27
|
+
// 2. Flat Shorthands
|
|
28
|
+
logo,
|
|
29
|
+
description,
|
|
30
|
+
sections: sectionsProp,
|
|
31
|
+
socialLinks: socialLinksProp,
|
|
32
|
+
address,
|
|
33
|
+
officeTitle,
|
|
34
|
+
copyright,
|
|
35
|
+
legalLinks,
|
|
36
|
+
// 3. Section Visibility Toggles
|
|
37
|
+
showNavigation: showNavProp,
|
|
38
|
+
showSocial: showSocialProp,
|
|
39
|
+
showOffice: showOfficeProp,
|
|
40
|
+
showLegal: showLegalProp,
|
|
41
|
+
showNewsletter: showNewsletterProp,
|
|
42
|
+
// 4. Container & Customization
|
|
43
|
+
containerMaxWidth = "2xl",
|
|
44
|
+
linkComponent,
|
|
45
|
+
motion: motionProp,
|
|
46
|
+
className,
|
|
47
|
+
children,
|
|
48
|
+
...rest
|
|
49
|
+
} = props;
|
|
50
|
+
const globalMotion = useGlobalAnimation();
|
|
51
|
+
const { shouldAnimate, motionClass, dataAttributes } = resolveMotion(motionProp, globalMotion);
|
|
52
|
+
const resolvedBranding = React.useMemo(() => {
|
|
53
|
+
return {
|
|
54
|
+
logo: brandingProp?.logo ?? logo,
|
|
55
|
+
description: brandingProp?.description ?? description,
|
|
56
|
+
href: brandingProp?.href ?? "/",
|
|
57
|
+
zone: brandingProp?.zone,
|
|
58
|
+
alt: brandingProp?.alt ?? "Timmbr Home",
|
|
59
|
+
className: brandingProp?.className,
|
|
60
|
+
onClick: brandingProp?.onClick
|
|
61
|
+
};
|
|
62
|
+
}, [brandingProp, logo, description]);
|
|
63
|
+
const { resolvedSections, isNavigationVisible } = React.useMemo(() => {
|
|
64
|
+
let sections = DEFAULT_FOOTER_SECTIONS;
|
|
65
|
+
let isVisible = true;
|
|
66
|
+
if (Array.isArray(navigationProp)) {
|
|
67
|
+
sections = navigationProp;
|
|
68
|
+
} else if (navigationProp && typeof navigationProp === "object") {
|
|
69
|
+
sections = navigationProp.sections ?? DEFAULT_FOOTER_SECTIONS;
|
|
70
|
+
if (typeof navigationProp.show === "boolean") isVisible = navigationProp.show;
|
|
71
|
+
} else if (sectionsProp) {
|
|
72
|
+
sections = sectionsProp;
|
|
73
|
+
}
|
|
74
|
+
if (typeof showNavProp === "boolean") {
|
|
75
|
+
isVisible = showNavProp;
|
|
76
|
+
}
|
|
77
|
+
return { resolvedSections: sections, isNavigationVisible: isVisible };
|
|
78
|
+
}, [navigationProp, sectionsProp, showNavProp]);
|
|
79
|
+
const { resolvedSocialLinks, socialTitle, isSocialVisible } = React.useMemo(() => {
|
|
80
|
+
let links = DEFAULT_FOOTER_SOCIAL_LINKS;
|
|
81
|
+
let title = void 0;
|
|
82
|
+
let isVisible = true;
|
|
83
|
+
if (Array.isArray(socialProp)) {
|
|
84
|
+
links = socialProp;
|
|
85
|
+
} else if (socialProp && typeof socialProp === "object") {
|
|
86
|
+
links = socialProp.links ?? DEFAULT_FOOTER_SOCIAL_LINKS;
|
|
87
|
+
title = socialProp.title;
|
|
88
|
+
if (typeof socialProp.show === "boolean") isVisible = socialProp.show;
|
|
89
|
+
} else if (socialLinksProp) {
|
|
90
|
+
links = socialLinksProp;
|
|
91
|
+
}
|
|
92
|
+
if (typeof showSocialProp === "boolean") {
|
|
93
|
+
isVisible = showSocialProp;
|
|
94
|
+
}
|
|
95
|
+
return { resolvedSocialLinks: links, socialTitle: title, isSocialVisible: isVisible };
|
|
96
|
+
}, [socialProp, socialLinksProp, showSocialProp]);
|
|
97
|
+
const { resolvedOffice, isOfficeVisible } = React.useMemo(() => {
|
|
98
|
+
const office = {
|
|
99
|
+
title: officeProp?.title ?? officeTitle ?? "Registered Office:",
|
|
100
|
+
address: officeProp?.address ?? address ?? "Timmbr Furnitures SABN Kallappa Layout, Ashwini Extenstion, Chintamani Karnataka 563125",
|
|
101
|
+
email: officeProp?.email,
|
|
102
|
+
phone: officeProp?.phone,
|
|
103
|
+
extraContent: officeProp?.extraContent,
|
|
104
|
+
className: officeProp?.className
|
|
105
|
+
};
|
|
106
|
+
let isVisible = true;
|
|
107
|
+
if (officeProp && typeof officeProp === "object" && typeof officeProp.show === "boolean") {
|
|
108
|
+
isVisible = officeProp.show;
|
|
109
|
+
}
|
|
110
|
+
if (typeof showOfficeProp === "boolean") {
|
|
111
|
+
isVisible = showOfficeProp;
|
|
112
|
+
}
|
|
113
|
+
return { resolvedOffice: office, isOfficeVisible: isVisible };
|
|
114
|
+
}, [officeProp, officeTitle, address, showOfficeProp]);
|
|
115
|
+
const { resolvedNewsletter, isNewsletterVisible } = React.useMemo(() => {
|
|
116
|
+
const newsletter = {
|
|
117
|
+
title: newsletterProp?.title ?? "Stay in the loop",
|
|
118
|
+
description: newsletterProp?.description ?? "Sign up for our newsletter to receive updates and exclusive offers.",
|
|
119
|
+
placeholder: newsletterProp?.placeholder ?? "Enter your email...",
|
|
120
|
+
buttonText: newsletterProp?.buttonText ?? "Subscribe",
|
|
121
|
+
onSubmit: newsletterProp?.onSubmit,
|
|
122
|
+
status: newsletterProp?.status,
|
|
123
|
+
errorMessage: newsletterProp?.errorMessage,
|
|
124
|
+
successMessage: newsletterProp?.successMessage,
|
|
125
|
+
className: newsletterProp?.className
|
|
126
|
+
};
|
|
127
|
+
let isVisible = Boolean(newsletterProp?.show);
|
|
128
|
+
if (typeof showNewsletterProp === "boolean") {
|
|
129
|
+
isVisible = showNewsletterProp;
|
|
130
|
+
}
|
|
131
|
+
return { resolvedNewsletter: newsletter, isNewsletterVisible: isVisible };
|
|
132
|
+
}, [newsletterProp, showNewsletterProp]);
|
|
133
|
+
const { resolvedLegal, isLegalVisible } = React.useMemo(() => {
|
|
134
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
135
|
+
const legal = {
|
|
136
|
+
copyright: legalProp?.copyright ?? copyright ?? `© ${currentYear} Timmbr Furniture Co.`,
|
|
137
|
+
links: legalProp?.links ?? legalLinks ?? DEFAULT_FOOTER_LEGAL_LINKS,
|
|
138
|
+
extra: legalProp?.extra,
|
|
139
|
+
className: legalProp?.className
|
|
140
|
+
};
|
|
141
|
+
let isVisible = true;
|
|
142
|
+
if (legalProp && typeof legalProp === "object" && typeof legalProp.show === "boolean") {
|
|
143
|
+
isVisible = legalProp.show;
|
|
144
|
+
}
|
|
145
|
+
if (typeof showLegalProp === "boolean") {
|
|
146
|
+
isVisible = showLegalProp;
|
|
147
|
+
}
|
|
148
|
+
return { resolvedLegal: legal, isLegalVisible: isVisible };
|
|
149
|
+
}, [legalProp, copyright, legalLinks, showLegalProp]);
|
|
150
|
+
const isAccordionEnabled = mobileProp?.accordion ?? true;
|
|
151
|
+
const allowMultipleOpen = mobileProp?.allowMultipleOpen ?? true;
|
|
152
|
+
const [openSectionIds, setOpenSectionIds] = React.useState(() => {
|
|
153
|
+
const initial = /* @__PURE__ */ new Set();
|
|
154
|
+
resolvedSections.forEach((sec) => {
|
|
155
|
+
if (sec.defaultOpen) initial.add(sec.id);
|
|
156
|
+
});
|
|
157
|
+
return initial;
|
|
158
|
+
});
|
|
159
|
+
const handleSectionToggle = (sectionId) => {
|
|
160
|
+
setOpenSectionIds((prev) => {
|
|
161
|
+
const next = new Set(prev);
|
|
162
|
+
if (next.has(sectionId)) {
|
|
163
|
+
next.delete(sectionId);
|
|
164
|
+
} else {
|
|
165
|
+
if (!allowMultipleOpen) {
|
|
166
|
+
next.clear();
|
|
167
|
+
}
|
|
168
|
+
next.add(sectionId);
|
|
169
|
+
}
|
|
170
|
+
return next;
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
return /* @__PURE__ */ jsx(
|
|
174
|
+
"footer",
|
|
175
|
+
{
|
|
176
|
+
ref,
|
|
177
|
+
role: "contentinfo",
|
|
178
|
+
"data-slot": "nav-footer",
|
|
179
|
+
className: cn(navFooterRootVariants(), className),
|
|
180
|
+
...dataAttributes,
|
|
181
|
+
...rest,
|
|
182
|
+
children: /* @__PURE__ */ jsxs(
|
|
183
|
+
"div",
|
|
184
|
+
{
|
|
185
|
+
className: cn(
|
|
186
|
+
navFooterContainerVariants({ maxWidth: containerMaxWidth }),
|
|
187
|
+
"pt-12 sm:pt-14 md:pt-16 pb-6"
|
|
188
|
+
),
|
|
189
|
+
"data-slot": "nav-footer-inner",
|
|
190
|
+
children: [
|
|
191
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col lg:flex-row items-start justify-between gap-10 sm:gap-12 lg:gap-14 xl:gap-20", children: [
|
|
192
|
+
/* @__PURE__ */ jsx("div", { className: "shrink-0", children: /* @__PURE__ */ jsx(
|
|
193
|
+
FooterBrand,
|
|
194
|
+
{
|
|
195
|
+
branding: resolvedBranding,
|
|
196
|
+
linkComponent
|
|
197
|
+
}
|
|
198
|
+
) }),
|
|
199
|
+
isNavigationVisible && resolvedSections.length > 0 && /* @__PURE__ */ jsx(
|
|
200
|
+
"div",
|
|
201
|
+
{
|
|
202
|
+
className: "w-full lg:flex-1 grid grid-cols-1 md:grid-cols-3 gap-0 md:gap-8 lg:gap-12 xl:gap-16",
|
|
203
|
+
"data-slot": "footer-nav-grid",
|
|
204
|
+
children: resolvedSections.map((sec) => /* @__PURE__ */ jsx(
|
|
205
|
+
FooterNavSection,
|
|
206
|
+
{
|
|
207
|
+
section: sec,
|
|
208
|
+
isMobileAccordion: isAccordionEnabled,
|
|
209
|
+
isOpen: openSectionIds.has(sec.id),
|
|
210
|
+
onToggle: () => handleSectionToggle(sec.id),
|
|
211
|
+
shouldAnimate,
|
|
212
|
+
motionClass,
|
|
213
|
+
linkComponent
|
|
214
|
+
},
|
|
215
|
+
sec.id
|
|
216
|
+
))
|
|
217
|
+
}
|
|
218
|
+
),
|
|
219
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-8 shrink-0 max-w-[320px] w-full", children: [
|
|
220
|
+
isSocialVisible && resolvedSocialLinks.length > 0 && /* @__PURE__ */ jsx(
|
|
221
|
+
FooterSocial,
|
|
222
|
+
{
|
|
223
|
+
links: resolvedSocialLinks,
|
|
224
|
+
title: socialTitle,
|
|
225
|
+
shouldAnimate,
|
|
226
|
+
motionClass
|
|
227
|
+
}
|
|
228
|
+
),
|
|
229
|
+
isOfficeVisible && /* @__PURE__ */ jsx(FooterOffice, { office: resolvedOffice }),
|
|
230
|
+
isNewsletterVisible && /* @__PURE__ */ jsx(FooterNewsletter, { newsletter: resolvedNewsletter })
|
|
231
|
+
] })
|
|
232
|
+
] }),
|
|
233
|
+
children && /* @__PURE__ */ jsx("div", { className: "mt-8 mb-4", children }),
|
|
234
|
+
isLegalVisible && /* @__PURE__ */ jsx("div", { className: "mt-12 sm:mt-14 md:mt-16", children: /* @__PURE__ */ jsx(
|
|
235
|
+
FooterLegalBar,
|
|
236
|
+
{
|
|
237
|
+
legal: resolvedLegal,
|
|
238
|
+
linkComponent
|
|
239
|
+
}
|
|
240
|
+
) })
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
}
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
NavFooter.displayName = "NavFooter";
|
|
249
|
+
const Footer = NavFooter;
|
|
250
|
+
|
|
251
|
+
export { Footer, NavFooter };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Root footer container styles adhering to Timmbr dark luxury aesthetic.
|
|
3
|
+
*/
|
|
4
|
+
export declare const navFooterRootVariants: (props?: ({
|
|
5
|
+
tone?: "dark" | "light" | null | undefined;
|
|
6
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
|
+
/**
|
|
8
|
+
* Inner container width and responsive padding variants.
|
|
9
|
+
*/
|
|
10
|
+
export declare const navFooterContainerVariants: (props?: ({
|
|
11
|
+
maxWidth?: "sm" | "lg" | "md" | "xl" | "2xl" | "full" | null | undefined;
|
|
12
|
+
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
13
|
+
/**
|
|
14
|
+
* Navigation column title styles.
|
|
15
|
+
*/
|
|
16
|
+
export declare const footerSectionTitleVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
17
|
+
/**
|
|
18
|
+
* Navigation link item styles.
|
|
19
|
+
*/
|
|
20
|
+
export declare const footerNavLinkVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
21
|
+
/**
|
|
22
|
+
* Social media icon button styles.
|
|
23
|
+
*/
|
|
24
|
+
export declare const footerSocialButtonVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Registered office block styles.
|
|
27
|
+
*/
|
|
28
|
+
export declare const footerOfficeBlockVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
29
|
+
/**
|
|
30
|
+
* Legal sub-bar styles.
|
|
31
|
+
*/
|
|
32
|
+
export declare const footerLegalBarVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
33
|
+
/**
|
|
34
|
+
* Legal policy link styles.
|
|
35
|
+
*/
|
|
36
|
+
export declare const footerLegalLinkVariants: (props?: import("class-variance-authority/types").ClassProp | undefined) => string;
|
|
37
|
+
//# sourceMappingURL=NavFooter.styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NavFooter.styles.d.ts","sourceRoot":"","sources":["../../../src/components/NavFooter/NavFooter.styles.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,eAAO,MAAM,qBAAqB;;8EAajC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B;;8EAiBtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,oFAEtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,oFAEjC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,oFAEtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,oFAErC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,sBAAsB,oFAElC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,oFAEnC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { cva } from 'class-variance-authority';
|
|
2
|
+
|
|
3
|
+
const navFooterRootVariants = cva(
|
|
4
|
+
"w-full bg-[#1A1714] text-[#F7F1E6] relative border-t border-black/20 transition-colors select-text",
|
|
5
|
+
{
|
|
6
|
+
variants: {
|
|
7
|
+
tone: {
|
|
8
|
+
dark: "bg-[#1A1714] text-[#F7F1E6]",
|
|
9
|
+
light: "bg-[var(--color-bg-2,#F7F1E6)] text-[var(--color-grey-800,#3C3C3C)] border-t border-[#E7DFD3]"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
defaultVariants: {
|
|
13
|
+
tone: "dark"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
);
|
|
17
|
+
const navFooterContainerVariants = cva(
|
|
18
|
+
"mx-auto px-5 sm:px-8 lg:px-12 xl:px-16 transition-all",
|
|
19
|
+
{
|
|
20
|
+
variants: {
|
|
21
|
+
maxWidth: {
|
|
22
|
+
sm: "max-w-screen-sm",
|
|
23
|
+
md: "max-w-screen-md",
|
|
24
|
+
lg: "max-w-screen-lg",
|
|
25
|
+
xl: "max-w-[1280px]",
|
|
26
|
+
"2xl": "max-w-[1440px]",
|
|
27
|
+
full: "max-w-full"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
maxWidth: "2xl"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
);
|
|
35
|
+
const footerSectionTitleVariants = cva(
|
|
36
|
+
"font-title text-xs font-semibold text-[#D39375] uppercase tracking-[0.14em] select-none flex items-center justify-between w-full"
|
|
37
|
+
);
|
|
38
|
+
const footerNavLinkVariants = cva(
|
|
39
|
+
"font-sans text-sm text-[#F7F1E6]/85 hover:text-[#D39375] hover:opacity-100 transition-colors inline-flex items-center gap-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#D39375]/60 rounded py-0.5 select-none"
|
|
40
|
+
);
|
|
41
|
+
const footerSocialButtonVariants = cva(
|
|
42
|
+
"inline-flex items-center justify-center text-[#D39375] hover:text-[#F7F1E6] hover:bg-white/5 p-2 rounded-full transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#D39375]/60 active:scale-95"
|
|
43
|
+
);
|
|
44
|
+
const footerOfficeBlockVariants = cva(
|
|
45
|
+
"flex flex-col gap-1.5 text-sm text-[#F7F1E6]/85 font-sans leading-relaxed"
|
|
46
|
+
);
|
|
47
|
+
const footerLegalBarVariants = cva(
|
|
48
|
+
"border-t border-white/10 py-5 sm:py-6 flex flex-col sm:flex-row items-center justify-between gap-4 text-xs font-sans text-[#B7AEA2]"
|
|
49
|
+
);
|
|
50
|
+
const footerLegalLinkVariants = cva(
|
|
51
|
+
"text-xs font-sans text-[#B7AEA2] hover:text-white transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-[#D39375]/60 rounded px-1"
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export { footerLegalBarVariants, footerLegalLinkVariants, footerNavLinkVariants, footerOfficeBlockVariants, footerSectionTitleVariants, footerSocialButtonVariants, navFooterContainerVariants, navFooterRootVariants };
|