@shohojdhara/atomix 0.2.1 → 0.2.3
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/README.md +1 -28
- package/dist/atomix.css +1500 -241
- package/dist/atomix.min.css +6 -6
- package/dist/index.d.ts +1052 -194
- package/dist/index.esm.js +12201 -6066
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +5481 -2827
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/dist/themes/boomdevs.css +1500 -301
- package/dist/themes/boomdevs.min.css +60 -8
- package/dist/themes/esrar.css +1500 -241
- package/dist/themes/esrar.min.css +6 -6
- package/dist/themes/mashroom.css +1496 -237
- package/dist/themes/mashroom.min.css +8 -8
- package/dist/themes/shaj-default.css +1451 -192
- package/dist/themes/shaj-default.min.css +6 -6
- package/package.json +66 -15
- package/src/components/Accordion/Accordion.stories.tsx +137 -0
- package/src/components/Accordion/Accordion.tsx +33 -3
- package/src/components/AtomixGlass/AtomixGlass.stories.tsx +3011 -0
- package/src/components/AtomixGlass/AtomixGlass.test.tsx +199 -0
- package/src/components/AtomixGlass/AtomixGlass.tsx +1281 -0
- package/src/components/AtomixGlass/AtomixGlassComprehensivePreview.stories.tsx +1369 -0
- package/src/components/AtomixGlass/README.md +134 -0
- package/src/components/AtomixGlass/index.ts +10 -0
- package/src/components/AtomixGlass/shader-utils.ts +140 -0
- package/src/components/AtomixGlass/utils.ts +8 -0
- package/src/components/Badge/Badge.stories.tsx +169 -0
- package/src/components/Badge/Badge.tsx +27 -2
- package/src/components/Button/Button.stories.tsx +345 -0
- package/src/components/Button/Button.tsx +35 -3
- package/src/components/Button/README.md +216 -0
- package/src/components/Callout/Callout.stories.tsx +813 -78
- package/src/components/Callout/Callout.test.tsx +368 -0
- package/src/components/Callout/Callout.tsx +26 -7
- package/src/components/Callout/README.md +409 -0
- package/src/components/Card/Card.stories.tsx +140 -0
- package/src/components/Card/Card.tsx +19 -3
- package/src/components/DatePicker/DatePicker copy.tsx +551 -0
- package/src/components/DatePicker/DatePicker.stories.tsx +188 -0
- package/src/components/DatePicker/DatePicker.tsx +379 -332
- package/src/components/DatePicker/readme.md +110 -1
- package/src/components/DatePicker/types.ts +8 -0
- package/src/components/Dropdown/Dropdown.stories.tsx +145 -0
- package/src/components/Dropdown/Dropdown.tsx +34 -5
- package/src/components/Footer/Footer.stories.tsx +388 -0
- package/src/components/Footer/Footer.tsx +197 -0
- package/src/components/Footer/FooterLink.tsx +72 -0
- package/src/components/Footer/FooterSection.tsx +87 -0
- package/src/components/Footer/FooterSocialLink.tsx +117 -0
- package/src/components/Footer/README.md +261 -0
- package/src/components/Footer/index.ts +13 -0
- package/src/components/Form/Checkbox.stories.tsx +101 -0
- package/src/components/Form/Checkbox.tsx +26 -2
- package/src/components/Form/Input.stories.tsx +124 -0
- package/src/components/Form/Input.tsx +36 -7
- package/src/components/Form/Radio.stories.tsx +139 -0
- package/src/components/Form/Radio.tsx +26 -2
- package/src/components/Form/Select.stories.tsx +110 -0
- package/src/components/Form/Select.tsx +26 -2
- package/src/components/Form/Textarea.stories.tsx +104 -0
- package/src/components/Form/Textarea.tsx +36 -7
- package/src/components/Hero/Hero.stories.tsx +54 -1
- package/src/components/Hero/Hero.tsx +70 -11
- package/src/components/Modal/Modal.stories.tsx +235 -0
- package/src/components/Modal/Modal.tsx +64 -35
- package/src/components/Pagination/Pagination.stories.tsx +101 -0
- package/src/components/Pagination/Pagination.tsx +25 -1
- package/src/components/Popover/Popover.stories.tsx +94 -0
- package/src/components/Popover/Popover.tsx +30 -4
- package/src/components/Rating/Rating.stories.tsx +112 -0
- package/src/components/Rating/Rating.tsx +25 -1
- package/src/components/SectionIntro/SectionIntro.tsx +9 -11
- package/src/components/Slider/Slider.stories.tsx +634 -50
- package/src/components/Slider/Slider.tsx +5 -3
- package/src/components/Steps/Steps.stories.tsx +119 -0
- package/src/components/Steps/Steps.tsx +32 -1
- package/src/components/Tab/Tab.stories.tsx +88 -0
- package/src/components/Tab/Tab.tsx +32 -1
- package/src/components/Toggle/Toggle.stories.tsx +92 -0
- package/src/components/Toggle/Toggle.tsx +32 -1
- package/src/components/Tooltip/Tooltip.stories.tsx +131 -0
- package/src/components/Tooltip/Tooltip.tsx +43 -7
- package/src/components/VideoPlayer/VideoPlayer.stories.tsx +1002 -196
- package/src/components/VideoPlayer/VideoPlayer.tsx +161 -4
- package/src/components/index.ts +14 -0
- package/src/layouts/Grid/Grid.stories.tsx +226 -159
- package/src/lib/composables/index.ts +4 -0
- package/src/lib/composables/useAtomixGlass.ts +71 -0
- package/src/lib/composables/useButton.ts +3 -1
- package/src/lib/composables/useCallout.ts +4 -1
- package/src/lib/composables/useFooter.ts +85 -0
- package/src/lib/composables/useGlassContainer.ts +168 -0
- package/src/lib/composables/useSlider.ts +191 -4
- package/src/lib/constants/components.ts +173 -0
- package/src/lib/types/components.ts +622 -0
- package/src/lib/utils/displacement-generator.ts +86 -0
- package/src/styles/01-settings/_index.scss +1 -0
- package/src/styles/01-settings/_settings.accordion.scss +20 -19
- package/src/styles/01-settings/_settings.animations.scss +5 -5
- package/src/styles/01-settings/_settings.avatar-group.scss +1 -1
- package/src/styles/01-settings/_settings.avatar.scss +17 -18
- package/src/styles/01-settings/_settings.background.scss +10 -0
- package/src/styles/01-settings/_settings.badge.scss +1 -1
- package/src/styles/01-settings/_settings.breadcrumb.scss +8 -2
- package/src/styles/01-settings/_settings.callout.scss +7 -7
- package/src/styles/01-settings/_settings.card.scss +2 -2
- package/src/styles/01-settings/_settings.chart.scss +7 -7
- package/src/styles/01-settings/_settings.checkbox-group.scss +5 -2
- package/src/styles/01-settings/_settings.checkbox.scss +10 -4
- package/src/styles/01-settings/_settings.countdown.scss +6 -4
- package/src/styles/01-settings/_settings.dropdown.scss +9 -7
- package/src/styles/01-settings/_settings.edge-panel.scss +3 -2
- package/src/styles/01-settings/_settings.footer.scss +125 -0
- package/src/styles/01-settings/_settings.form-group.scss +3 -1
- package/src/styles/01-settings/_settings.form.scss +4 -2
- package/src/styles/01-settings/_settings.hero.scss +9 -7
- package/src/styles/01-settings/_settings.input.scss +9 -7
- package/src/styles/01-settings/_settings.list-group.scss +4 -2
- package/src/styles/01-settings/_settings.list.scss +4 -2
- package/src/styles/01-settings/_settings.menu.scss +10 -8
- package/src/styles/01-settings/_settings.messages.scss +19 -17
- package/src/styles/01-settings/_settings.modal.scss +6 -4
- package/src/styles/01-settings/_settings.nav.scss +6 -4
- package/src/styles/01-settings/_settings.navbar.scss +8 -5
- package/src/styles/01-settings/_settings.pagination.scss +5 -3
- package/src/styles/01-settings/_settings.popover.scss +6 -4
- package/src/styles/01-settings/_settings.rating.scss +5 -3
- package/src/styles/01-settings/_settings.river.scss +8 -6
- package/src/styles/01-settings/_settings.sectionintro.scss +8 -6
- package/src/styles/01-settings/_settings.select.scss +7 -5
- package/src/styles/01-settings/_settings.side-menu.scss +15 -13
- package/src/styles/01-settings/_settings.spacing.scss +4 -0
- package/src/styles/01-settings/_settings.steps.scss +7 -5
- package/src/styles/01-settings/_settings.tabs.scss +7 -5
- package/src/styles/01-settings/_settings.testimonials.scss +6 -4
- package/src/styles/01-settings/_settings.toggle.scss +3 -1
- package/src/styles/01-settings/_settings.tooltip.scss +5 -3
- package/src/styles/01-settings/_settings.upload.scss +22 -20
- package/src/styles/02-tools/_tools.animations.scss +19 -0
- package/src/styles/02-tools/_tools.background.scss +87 -0
- package/src/styles/02-tools/_tools.glass.scss +1 -0
- package/src/styles/02-tools/_tools.rem.scss +18 -5
- package/src/styles/02-tools/_tools.utility-api.scss +32 -26
- package/src/styles/03-generic/_generic.root.scss +15 -2
- package/src/styles/04-elements/_elements.body.scss +6 -0
- package/src/styles/06-components/_components.accordion.scss +24 -4
- package/src/styles/06-components/_components.atomix-glass.scss +0 -0
- package/src/styles/06-components/_components.avatar-group.scss +2 -1
- package/src/styles/06-components/_components.avatar.scss +2 -1
- package/src/styles/06-components/_components.badge.scss +36 -1
- package/src/styles/06-components/_components.breadcrumb.scss +2 -1
- package/src/styles/06-components/_components.button.scss +14 -3
- package/src/styles/06-components/_components.callout.scss +44 -4
- package/src/styles/06-components/_components.card.scss +21 -2
- package/src/styles/06-components/_components.chart.scss +3 -2
- package/src/styles/06-components/_components.checkbox.scss +2 -1
- package/src/styles/06-components/_components.color-mode-toggle.scss +3 -2
- package/src/styles/06-components/_components.countdown.scss +2 -1
- package/src/styles/06-components/_components.data-table.scss +7 -6
- package/src/styles/06-components/_components.datepicker.scss +20 -1
- package/src/styles/06-components/_components.dropdown.scss +11 -4
- package/src/styles/06-components/_components.edge-panel.scss +4 -3
- package/src/styles/06-components/_components.footer.scss +825 -0
- package/src/styles/06-components/_components.form-group.scss +1 -0
- package/src/styles/06-components/_components.hero.scss +4 -4
- package/src/styles/06-components/_components.image-gallery.scss +1 -0
- package/src/styles/06-components/_components.input.scss +33 -2
- package/src/styles/06-components/_components.list-group.scss +3 -2
- package/src/styles/06-components/_components.list.scss +2 -1
- package/src/styles/06-components/_components.menu.scss +5 -4
- package/src/styles/06-components/_components.messages.scss +8 -7
- package/src/styles/06-components/_components.modal.scss +3 -2
- package/src/styles/06-components/_components.nav.scss +6 -5
- package/src/styles/06-components/_components.navbar.scss +4 -3
- package/src/styles/06-components/_components.pagination.scss +2 -1
- package/src/styles/06-components/_components.photoviewer.scss +4 -3
- package/src/styles/06-components/_components.popover.scss +3 -2
- package/src/styles/06-components/_components.product-review.scss +3 -2
- package/src/styles/06-components/_components.progress.scss +3 -2
- package/src/styles/06-components/_components.river.scss +3 -2
- package/src/styles/06-components/_components.sectionintro.scss +2 -1
- package/src/styles/06-components/_components.select.scss +5 -4
- package/src/styles/06-components/_components.side-menu.scss +8 -7
- package/src/styles/06-components/_components.skeleton.scss +3 -2
- package/src/styles/06-components/_components.slider.scss +7 -6
- package/src/styles/06-components/_components.spinner.scss +1 -0
- package/src/styles/06-components/_components.steps.scss +3 -2
- package/src/styles/06-components/_components.tabs.scss +4 -3
- package/src/styles/06-components/_components.testimonials.scss +2 -1
- package/src/styles/06-components/_components.todo.scss +3 -2
- package/src/styles/06-components/_components.toggle.scss +5 -4
- package/src/styles/06-components/_components.tooltip.scss +3 -2
- package/src/styles/06-components/_components.upload.scss +4 -3
- package/src/styles/06-components/_components.video-player.scss +50 -27
- package/src/styles/06-components/_index.scss +2 -0
- package/src/styles/99-utilities/_utilities.glass-fixes.scss +48 -0
- package/dist/themes/yabai.css +0 -13711
- package/dist/themes/yabai.min.css +0 -189
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
2
|
+
import { Footer } from './Footer';
|
|
3
|
+
import { FooterSection } from './FooterSection';
|
|
4
|
+
import { FooterLink } from './FooterLink';
|
|
5
|
+
|
|
6
|
+
const meta: Meta<typeof Footer> = {
|
|
7
|
+
title: 'Components/Footer',
|
|
8
|
+
component: Footer,
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'fullscreen',
|
|
11
|
+
docs: {
|
|
12
|
+
description: {
|
|
13
|
+
component: 'A modern, comprehensive footer component with enhanced visual effects, accessibility features, responsive design, and multiple layout variants following Atomix design patterns.',
|
|
14
|
+
},
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
argTypes: {
|
|
18
|
+
layout: {
|
|
19
|
+
control: 'select',
|
|
20
|
+
options: ['columns', 'centered', 'minimal', 'stacked'],
|
|
21
|
+
description: 'Footer layout variant',
|
|
22
|
+
},
|
|
23
|
+
variant: {
|
|
24
|
+
control: 'select',
|
|
25
|
+
options: ['primary', 'secondary', 'success', 'info', 'warning', 'error', 'light', 'dark'],
|
|
26
|
+
description: 'Color variant',
|
|
27
|
+
},
|
|
28
|
+
size: {
|
|
29
|
+
control: 'select',
|
|
30
|
+
options: ['sm', 'md', 'lg'],
|
|
31
|
+
description: 'Size variant',
|
|
32
|
+
},
|
|
33
|
+
showNewsletter: {
|
|
34
|
+
control: 'boolean',
|
|
35
|
+
description: 'Whether to show newsletter signup',
|
|
36
|
+
},
|
|
37
|
+
showBackToTop: {
|
|
38
|
+
control: 'boolean',
|
|
39
|
+
description: 'Whether to show back to top button',
|
|
40
|
+
},
|
|
41
|
+
showDivider: {
|
|
42
|
+
control: 'boolean',
|
|
43
|
+
description: 'Whether to show divider above bottom section',
|
|
44
|
+
},
|
|
45
|
+
sticky: {
|
|
46
|
+
control: 'boolean',
|
|
47
|
+
description: 'Whether footer should be sticky',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default meta;
|
|
53
|
+
type Story = StoryObj<typeof Footer>;
|
|
54
|
+
|
|
55
|
+
// Sample social links
|
|
56
|
+
const sampleSocialLinks = [
|
|
57
|
+
{ platform: 'facebook' as const, url: 'https://facebook.com/company' },
|
|
58
|
+
{ platform: 'twitter' as const, url: 'https://twitter.com/company' },
|
|
59
|
+
{ platform: 'instagram' as const, url: 'https://instagram.com/company' },
|
|
60
|
+
{ platform: 'linkedin' as const, url: 'https://linkedin.com/company' },
|
|
61
|
+
{ platform: 'github' as const, url: 'https://github.com/company' },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
// Sample footer content
|
|
65
|
+
const SampleFooterContent = () => (
|
|
66
|
+
<>
|
|
67
|
+
<FooterSection title="Products">
|
|
68
|
+
<FooterLink href="/product1">Web Development</FooterLink>
|
|
69
|
+
<FooterLink href="/product2">Mobile Apps</FooterLink>
|
|
70
|
+
<FooterLink href="/product3">UI/UX Design</FooterLink>
|
|
71
|
+
<FooterLink href="/product4">Consulting</FooterLink>
|
|
72
|
+
</FooterSection>
|
|
73
|
+
|
|
74
|
+
<FooterSection title="Company">
|
|
75
|
+
<FooterLink href="/about">About Us</FooterLink>
|
|
76
|
+
<FooterLink href="/careers">Careers</FooterLink>
|
|
77
|
+
<FooterLink href="/blog">Blog</FooterLink>
|
|
78
|
+
<FooterLink href="/contact">Contact</FooterLink>
|
|
79
|
+
</FooterSection>
|
|
80
|
+
|
|
81
|
+
<FooterSection title="Support">
|
|
82
|
+
<FooterLink href="/help">Help Center</FooterLink>
|
|
83
|
+
<FooterLink href="/docs">Documentation</FooterLink>
|
|
84
|
+
<FooterLink href="/community">Community</FooterLink>
|
|
85
|
+
<FooterLink href="/status">Status</FooterLink>
|
|
86
|
+
</FooterSection>
|
|
87
|
+
|
|
88
|
+
<FooterSection title="Legal">
|
|
89
|
+
<FooterLink href="/privacy">Privacy Policy</FooterLink>
|
|
90
|
+
<FooterLink href="/terms">Terms of Service</FooterLink>
|
|
91
|
+
<FooterLink href="/cookies">Cookie Policy</FooterLink>
|
|
92
|
+
<FooterLink href="/licenses">Licenses</FooterLink>
|
|
93
|
+
</FooterSection>
|
|
94
|
+
</>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
export const Default: Story = {
|
|
98
|
+
args: {
|
|
99
|
+
brand: 'Atomix',
|
|
100
|
+
brandDescription: 'A modern, accessible design system and component library for building beautiful user interfaces.',
|
|
101
|
+
copyright: '© 2024 Atomix. All rights reserved.',
|
|
102
|
+
layout: 'columns',
|
|
103
|
+
variant: 'primary',
|
|
104
|
+
size: 'md',
|
|
105
|
+
socialLinks: sampleSocialLinks,
|
|
106
|
+
showNewsletter: false,
|
|
107
|
+
showBackToTop: false,
|
|
108
|
+
showDivider: true,
|
|
109
|
+
sticky: false,
|
|
110
|
+
},
|
|
111
|
+
render: (args) => (
|
|
112
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
113
|
+
<div style={{ flex: 1, padding: '2rem', backgroundColor: 'var(--atomix-surface)' }}>
|
|
114
|
+
<h1>Page Content</h1>
|
|
115
|
+
<p>This is sample page content to demonstrate the footer component.</p>
|
|
116
|
+
</div>
|
|
117
|
+
<Footer {...args}>
|
|
118
|
+
<SampleFooterContent />
|
|
119
|
+
</Footer>
|
|
120
|
+
</div>
|
|
121
|
+
),
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
export const WithNewsletter: Story = {
|
|
125
|
+
args: {
|
|
126
|
+
...Default.args,
|
|
127
|
+
showNewsletter: true,
|
|
128
|
+
newsletterTitle: 'Stay in the Loop',
|
|
129
|
+
newsletterDescription: 'Get the latest updates, articles, and resources delivered to your inbox.',
|
|
130
|
+
onNewsletterSubmit: (email: string) => {
|
|
131
|
+
console.log('Newsletter signup:', email);
|
|
132
|
+
alert(`Thank you for subscribing with ${email}!`);
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
render: Default.render,
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
export const WithBackToTop: Story = {
|
|
139
|
+
args: {
|
|
140
|
+
...Default.args,
|
|
141
|
+
showBackToTop: true,
|
|
142
|
+
backToTopText: 'Back to Top',
|
|
143
|
+
onBackToTop: () => {
|
|
144
|
+
console.log('Back to top clicked');
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
render: Default.render,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
export const Centered: Story = {
|
|
151
|
+
args: {
|
|
152
|
+
...Default.args,
|
|
153
|
+
layout: 'centered',
|
|
154
|
+
showNewsletter: true,
|
|
155
|
+
showBackToTop: true,
|
|
156
|
+
},
|
|
157
|
+
render: Default.render,
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
export const Minimal: Story = {
|
|
161
|
+
args: {
|
|
162
|
+
brand: 'Atomix',
|
|
163
|
+
copyright: '© 2024 Atomix. All rights reserved.',
|
|
164
|
+
layout: 'minimal',
|
|
165
|
+
variant: 'light',
|
|
166
|
+
size: 'sm',
|
|
167
|
+
socialLinks: sampleSocialLinks.slice(0, 3),
|
|
168
|
+
showDivider: false,
|
|
169
|
+
},
|
|
170
|
+
render: (args) => (
|
|
171
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
172
|
+
<div style={{ flex: 1, padding: '2rem', backgroundColor: 'var(--atomix-surface)' }}>
|
|
173
|
+
<h1>Page Content</h1>
|
|
174
|
+
<p>This is sample page content with a minimal footer.</p>
|
|
175
|
+
</div>
|
|
176
|
+
<Footer {...args}>
|
|
177
|
+
<FooterSection title="Quick Links">
|
|
178
|
+
<FooterLink href="/about">About</FooterLink>
|
|
179
|
+
<FooterLink href="/contact">Contact</FooterLink>
|
|
180
|
+
<FooterLink href="/privacy">Privacy</FooterLink>
|
|
181
|
+
</FooterSection>
|
|
182
|
+
</Footer>
|
|
183
|
+
</div>
|
|
184
|
+
),
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
export const Stacked: Story = {
|
|
188
|
+
args: {
|
|
189
|
+
...Default.args,
|
|
190
|
+
layout: 'stacked',
|
|
191
|
+
showNewsletter: true,
|
|
192
|
+
showBackToTop: true,
|
|
193
|
+
},
|
|
194
|
+
render: Default.render,
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
export const DarkVariant: Story = {
|
|
198
|
+
args: {
|
|
199
|
+
...Default.args,
|
|
200
|
+
variant: 'dark',
|
|
201
|
+
showNewsletter: true,
|
|
202
|
+
showBackToTop: true,
|
|
203
|
+
},
|
|
204
|
+
render: Default.render,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const LargeSize: Story = {
|
|
208
|
+
args: {
|
|
209
|
+
...Default.args,
|
|
210
|
+
size: 'lg',
|
|
211
|
+
showNewsletter: true,
|
|
212
|
+
showBackToTop: true,
|
|
213
|
+
},
|
|
214
|
+
render: Default.render,
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
export const SmallSize: Story = {
|
|
218
|
+
args: {
|
|
219
|
+
...Default.args,
|
|
220
|
+
size: 'sm',
|
|
221
|
+
layout: 'minimal',
|
|
222
|
+
},
|
|
223
|
+
render: Default.render,
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
export const WithBrandLogo: Story = {
|
|
227
|
+
args: {
|
|
228
|
+
...Default.args,
|
|
229
|
+
brandLogo: 'https://via.placeholder.com/150x50/007bff/ffffff?text=LOGO',
|
|
230
|
+
showNewsletter: true,
|
|
231
|
+
},
|
|
232
|
+
render: Default.render,
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
export const Sticky: Story = {
|
|
236
|
+
args: {
|
|
237
|
+
...Default.args,
|
|
238
|
+
sticky: true,
|
|
239
|
+
size: 'sm',
|
|
240
|
+
layout: 'minimal',
|
|
241
|
+
},
|
|
242
|
+
render: (args) => (
|
|
243
|
+
<div style={{ height: '200vh', backgroundColor: 'var(--atomix-surface)' }}>
|
|
244
|
+
<div style={{ padding: '2rem' }}>
|
|
245
|
+
<h1>Scroll down to see sticky footer</h1>
|
|
246
|
+
<p>This page is tall enough to demonstrate the sticky footer behavior.</p>
|
|
247
|
+
{Array.from({ length: 20 }, (_, i) => (
|
|
248
|
+
<p key={i}>
|
|
249
|
+
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor
|
|
250
|
+
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis
|
|
251
|
+
nostrud exercitation ullamco laboris.
|
|
252
|
+
</p>
|
|
253
|
+
))}
|
|
254
|
+
</div>
|
|
255
|
+
<Footer {...args}>
|
|
256
|
+
<SampleFooterContent />
|
|
257
|
+
</Footer>
|
|
258
|
+
</div>
|
|
259
|
+
),
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
export const CollapsibleSections: Story = {
|
|
263
|
+
args: {
|
|
264
|
+
...Default.args,
|
|
265
|
+
showNewsletter: true,
|
|
266
|
+
},
|
|
267
|
+
render: (args) => (
|
|
268
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
269
|
+
<div style={{ flex: 1, padding: '2rem', backgroundColor: 'var(--atomix-surface)' }}>
|
|
270
|
+
<h1>Collapsible Footer Sections</h1>
|
|
271
|
+
<p>Resize the window to mobile size to see collapsible sections.</p>
|
|
272
|
+
</div>
|
|
273
|
+
<Footer {...args}>
|
|
274
|
+
<FooterSection title="Products" collapsible defaultCollapsed>
|
|
275
|
+
<FooterLink href="/product1">Web Development</FooterLink>
|
|
276
|
+
<FooterLink href="/product2">Mobile Apps</FooterLink>
|
|
277
|
+
<FooterLink href="/product3">UI/UX Design</FooterLink>
|
|
278
|
+
</FooterSection>
|
|
279
|
+
|
|
280
|
+
<FooterSection title="Company" collapsible>
|
|
281
|
+
<FooterLink href="/about">About Us</FooterLink>
|
|
282
|
+
<FooterLink href="/careers">Careers</FooterLink>
|
|
283
|
+
<FooterLink href="/blog">Blog</FooterLink>
|
|
284
|
+
</FooterSection>
|
|
285
|
+
|
|
286
|
+
<FooterSection title="Support" collapsible>
|
|
287
|
+
<FooterLink href="/help">Help Center</FooterLink>
|
|
288
|
+
<FooterLink href="/docs">Documentation</FooterLink>
|
|
289
|
+
<FooterLink href="/community">Community</FooterLink>
|
|
290
|
+
</FooterSection>
|
|
291
|
+
</Footer>
|
|
292
|
+
</div>
|
|
293
|
+
),
|
|
294
|
+
};
|
|
295
|
+
|
|
296
|
+
export const WithExternalLinks: Story = {
|
|
297
|
+
args: {
|
|
298
|
+
...Default.args,
|
|
299
|
+
socialLinks: [
|
|
300
|
+
...sampleSocialLinks,
|
|
301
|
+
{ platform: 'tiktok' as const, url: 'https://tiktok.com/@company' },
|
|
302
|
+
{ platform: 'whatsapp' as const, url: 'https://wa.me/1234567890' },
|
|
303
|
+
{ platform: 'discord' as const, url: 'https://discord.gg/company' },
|
|
304
|
+
],
|
|
305
|
+
},
|
|
306
|
+
render: (args) => (
|
|
307
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
308
|
+
<div style={{ flex: 1, padding: '2rem', backgroundColor: 'var(--atomix-surface)' }}>
|
|
309
|
+
<h1>Modern Social Links</h1>
|
|
310
|
+
<p>Footer with enhanced social platforms and modern styling.</p>
|
|
311
|
+
</div>
|
|
312
|
+
<Footer {...args}>
|
|
313
|
+
<FooterSection title="External Resources">
|
|
314
|
+
<FooterLink href="https://github.com" external>GitHub</FooterLink>
|
|
315
|
+
<FooterLink href="https://stackoverflow.com" external>Stack Overflow</FooterLink>
|
|
316
|
+
<FooterLink href="https://developer.mozilla.org" external>MDN Docs</FooterLink>
|
|
317
|
+
</FooterSection>
|
|
318
|
+
|
|
319
|
+
<FooterSection title="Internal Links">
|
|
320
|
+
<FooterLink href="/about">About Us</FooterLink>
|
|
321
|
+
<FooterLink href="/contact">Contact</FooterLink>
|
|
322
|
+
<FooterLink href="/blog" active>Blog</FooterLink>
|
|
323
|
+
<FooterLink href="/disabled" disabled>Disabled Link</FooterLink>
|
|
324
|
+
</FooterSection>
|
|
325
|
+
</Footer>
|
|
326
|
+
</div>
|
|
327
|
+
),
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
export const ModernGradients: Story = {
|
|
331
|
+
args: {
|
|
332
|
+
...Default.args,
|
|
333
|
+
variant: 'primary',
|
|
334
|
+
showNewsletter: true,
|
|
335
|
+
showBackToTop: true,
|
|
336
|
+
socialLinks: sampleSocialLinks,
|
|
337
|
+
},
|
|
338
|
+
render: (args) => (
|
|
339
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
340
|
+
<div style={{ flex: 1, padding: '2rem', background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)' }}>
|
|
341
|
+
<h1 style={{ color: 'white' }}>Modern Design</h1>
|
|
342
|
+
<p style={{ color: 'white' }}>Showcasing modern gradients and enhanced visual effects.</p>
|
|
343
|
+
</div>
|
|
344
|
+
<Footer {...args}>
|
|
345
|
+
<SampleFooterContent />
|
|
346
|
+
</Footer>
|
|
347
|
+
</div>
|
|
348
|
+
),
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
export const AccessibilityFocused: Story = {
|
|
352
|
+
args: {
|
|
353
|
+
...Default.args,
|
|
354
|
+
showNewsletter: true,
|
|
355
|
+
showBackToTop: true,
|
|
356
|
+
},
|
|
357
|
+
render: (args) => (
|
|
358
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
359
|
+
<div style={{ flex: 1, padding: '2rem', backgroundColor: 'var(--atomix-surface)' }}>
|
|
360
|
+
<h1>Accessibility Features</h1>
|
|
361
|
+
<p>Tab through the footer elements to see enhanced focus states and keyboard navigation.</p>
|
|
362
|
+
</div>
|
|
363
|
+
<Footer {...args}>
|
|
364
|
+
<SampleFooterContent />
|
|
365
|
+
</Footer>
|
|
366
|
+
</div>
|
|
367
|
+
),
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
export const ResponsiveShowcase: Story = {
|
|
371
|
+
args: {
|
|
372
|
+
...Default.args,
|
|
373
|
+
layout: 'columns',
|
|
374
|
+
showNewsletter: true,
|
|
375
|
+
showBackToTop: true,
|
|
376
|
+
},
|
|
377
|
+
render: (args) => (
|
|
378
|
+
<div style={{ minHeight: '100vh', display: 'flex', flexDirection: 'column' }}>
|
|
379
|
+
<div style={{ flex: 1, padding: '2rem', backgroundColor: 'var(--atomix-surface)' }}>
|
|
380
|
+
<h1>Responsive Design</h1>
|
|
381
|
+
<p>Resize the viewport to see responsive grid layouts and collapsible sections.</p>
|
|
382
|
+
</div>
|
|
383
|
+
<Footer {...args}>
|
|
384
|
+
<SampleFooterContent />
|
|
385
|
+
</Footer>
|
|
386
|
+
</div>
|
|
387
|
+
),
|
|
388
|
+
};
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { FooterProps } from '../../lib/types/components';
|
|
3
|
+
import { useFooter } from '../../lib/composables/useFooter';
|
|
4
|
+
import { Button } from '../Button';
|
|
5
|
+
import { Input, Form } from '../Form';
|
|
6
|
+
import { FooterSocialLink } from './FooterSocialLink';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Footer component provides a comprehensive footer section with multiple layout options,
|
|
10
|
+
* social links, newsletter signup, and responsive design.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <Footer
|
|
15
|
+
* brand="My Company"
|
|
16
|
+
* copyright="© 2024 My Company. All rights reserved."
|
|
17
|
+
* layout="columns"
|
|
18
|
+
* showNewsletter
|
|
19
|
+
* socialLinks={[
|
|
20
|
+
* { platform: 'twitter', url: 'https://twitter.com/company' },
|
|
21
|
+
* { platform: 'facebook', url: 'https://facebook.com/company' }
|
|
22
|
+
* ]}
|
|
23
|
+
* >
|
|
24
|
+
* <FooterSection title="Products">
|
|
25
|
+
* <FooterLink href="/product1">Product 1</FooterLink>
|
|
26
|
+
* <FooterLink href="/product2">Product 2</FooterLink>
|
|
27
|
+
* </FooterSection>
|
|
28
|
+
* </Footer>
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export const Footer = forwardRef<HTMLElement, FooterProps>(
|
|
32
|
+
(
|
|
33
|
+
{
|
|
34
|
+
brand,
|
|
35
|
+
brandLogo,
|
|
36
|
+
brandDescription,
|
|
37
|
+
copyright,
|
|
38
|
+
layout = 'columns',
|
|
39
|
+
variant = 'primary',
|
|
40
|
+
size = 'md',
|
|
41
|
+
showNewsletter = false,
|
|
42
|
+
newsletterTitle = 'Stay Updated',
|
|
43
|
+
newsletterDescription = 'Subscribe to our newsletter for the latest updates.',
|
|
44
|
+
newsletterPlaceholder = 'Enter your email',
|
|
45
|
+
newsletterButtonText = 'Subscribe',
|
|
46
|
+
onNewsletterSubmit,
|
|
47
|
+
socialLinks = [],
|
|
48
|
+
showBackToTop = false,
|
|
49
|
+
backToTopText = 'Back to Top',
|
|
50
|
+
onBackToTop,
|
|
51
|
+
showDivider = true,
|
|
52
|
+
sticky = false,
|
|
53
|
+
children,
|
|
54
|
+
className = '',
|
|
55
|
+
disabled = false,
|
|
56
|
+
...props
|
|
57
|
+
},
|
|
58
|
+
ref
|
|
59
|
+
) => {
|
|
60
|
+
const {
|
|
61
|
+
footerClass,
|
|
62
|
+
containerClass,
|
|
63
|
+
brandClass,
|
|
64
|
+
sectionsClass,
|
|
65
|
+
bottomClass,
|
|
66
|
+
handleNewsletterSubmit,
|
|
67
|
+
handleBackToTop,
|
|
68
|
+
socialLinks: footerSocialLinks,
|
|
69
|
+
} = useFooter({
|
|
70
|
+
layout,
|
|
71
|
+
variant,
|
|
72
|
+
size,
|
|
73
|
+
sticky,
|
|
74
|
+
showNewsletter,
|
|
75
|
+
showBackToTop,
|
|
76
|
+
socialLinks,
|
|
77
|
+
onNewsletterSubmit,
|
|
78
|
+
onBackToTop,
|
|
79
|
+
className,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<footer ref={ref} className={footerClass} {...props}>
|
|
84
|
+
<div className={containerClass}>
|
|
85
|
+
{/* Main Footer Content */}
|
|
86
|
+
<div className={sectionsClass}>
|
|
87
|
+
{/* Brand Section */}
|
|
88
|
+
{(brand || brandLogo || brandDescription) && (
|
|
89
|
+
<div className={brandClass}>
|
|
90
|
+
{brandLogo && (
|
|
91
|
+
<div className="c-footer__brand-logo">
|
|
92
|
+
{typeof brandLogo === 'string' ? (
|
|
93
|
+
<img src={brandLogo} alt={'Brand Logo'} />
|
|
94
|
+
) : (
|
|
95
|
+
brandLogo
|
|
96
|
+
)}
|
|
97
|
+
</div>
|
|
98
|
+
)}
|
|
99
|
+
{brand && (
|
|
100
|
+
<div className="c-footer__brand-name">
|
|
101
|
+
{typeof brand === 'string' ? <h3>{brand}</h3> : brand}
|
|
102
|
+
</div>
|
|
103
|
+
)}
|
|
104
|
+
{brandDescription && (
|
|
105
|
+
<div className="c-footer__brand-description">
|
|
106
|
+
{brandDescription}
|
|
107
|
+
</div>
|
|
108
|
+
)}
|
|
109
|
+
{socialLinks.length > 0 && (
|
|
110
|
+
<div className="c-footer__social">
|
|
111
|
+
{socialLinks.map((link, index) => (
|
|
112
|
+
<FooterSocialLink
|
|
113
|
+
key={`${link.platform}-${index}`}
|
|
114
|
+
platform={link.platform}
|
|
115
|
+
url={link.url}
|
|
116
|
+
icon={link.icon}
|
|
117
|
+
label={link.label}
|
|
118
|
+
size={size}
|
|
119
|
+
/>
|
|
120
|
+
))}
|
|
121
|
+
</div>
|
|
122
|
+
)}
|
|
123
|
+
</div>
|
|
124
|
+
)}
|
|
125
|
+
|
|
126
|
+
{/* Footer Sections */}
|
|
127
|
+
{children && (
|
|
128
|
+
<div className="c-footer__sections">
|
|
129
|
+
{children}
|
|
130
|
+
</div>
|
|
131
|
+
)}
|
|
132
|
+
|
|
133
|
+
{/* Newsletter Section */}
|
|
134
|
+
{showNewsletter && (
|
|
135
|
+
<div className="c-footer__newsletter">
|
|
136
|
+
<h4 className="c-footer__newsletter-title">{newsletterTitle}</h4>
|
|
137
|
+
{newsletterDescription && (
|
|
138
|
+
<p className="c-footer__newsletter-description">{newsletterDescription}</p>
|
|
139
|
+
)}
|
|
140
|
+
<Form className="c-footer__newsletter-form" onSubmit={(e) => {
|
|
141
|
+
e.preventDefault();
|
|
142
|
+
const formData = new FormData(e.currentTarget);
|
|
143
|
+
const email = formData.get('email') as string;
|
|
144
|
+
if (email) handleNewsletterSubmit(email);
|
|
145
|
+
}}>
|
|
146
|
+
<div className="c-footer__newsletter-input-group">
|
|
147
|
+
<Input
|
|
148
|
+
type="email"
|
|
149
|
+
name="email"
|
|
150
|
+
className="c-footer__newsletter-input"
|
|
151
|
+
placeholder={newsletterPlaceholder}
|
|
152
|
+
required
|
|
153
|
+
/>
|
|
154
|
+
<Button type="submit" className="c-footer__newsletter-button">
|
|
155
|
+
{newsletterButtonText}
|
|
156
|
+
</Button>
|
|
157
|
+
</div>
|
|
158
|
+
</Form>
|
|
159
|
+
</div>
|
|
160
|
+
)}
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
{/* Footer Bottom */}
|
|
164
|
+
{(copyright || showBackToTop) && showDivider && (
|
|
165
|
+
<hr className="c-footer__divider" />
|
|
166
|
+
)}
|
|
167
|
+
|
|
168
|
+
{(copyright || showBackToTop) && (
|
|
169
|
+
<div className={bottomClass}>
|
|
170
|
+
{copyright && (
|
|
171
|
+
<div className="c-footer__copyright">
|
|
172
|
+
{copyright}
|
|
173
|
+
</div>
|
|
174
|
+
)}
|
|
175
|
+
{showBackToTop && (
|
|
176
|
+
<Button
|
|
177
|
+
variant="ghost"
|
|
178
|
+
className="c-footer__back-to-top"
|
|
179
|
+
onClick={handleBackToTop}
|
|
180
|
+
disabled={disabled}
|
|
181
|
+
aria-label={backToTopText}
|
|
182
|
+
>
|
|
183
|
+
<span className="c-footer__back-to-top-icon">↑</span>
|
|
184
|
+
<span className="c-footer__back-to-top-text">{backToTopText}</span>
|
|
185
|
+
</Button>
|
|
186
|
+
)}
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
</div>
|
|
190
|
+
</footer>
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
Footer.displayName = 'Footer';
|
|
196
|
+
|
|
197
|
+
export default Footer;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import React, { forwardRef } from 'react';
|
|
2
|
+
import { FooterLinkProps } from '../../lib/types/components';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* FooterLink component provides styled links for use within footer sections.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* <FooterLink href="/about" icon={<InfoIcon />} external>
|
|
10
|
+
* About Us
|
|
11
|
+
* </FooterLink>
|
|
12
|
+
* ```
|
|
13
|
+
*/
|
|
14
|
+
export const FooterLink = forwardRef<HTMLAnchorElement, FooterLinkProps>(
|
|
15
|
+
(
|
|
16
|
+
{
|
|
17
|
+
href,
|
|
18
|
+
icon,
|
|
19
|
+
external = false,
|
|
20
|
+
active = false,
|
|
21
|
+
disabled = false,
|
|
22
|
+
onClick,
|
|
23
|
+
children,
|
|
24
|
+
className = '',
|
|
25
|
+
LinkComponent,
|
|
26
|
+
...props
|
|
27
|
+
},
|
|
28
|
+
ref
|
|
29
|
+
) => {
|
|
30
|
+
const linkClass = [
|
|
31
|
+
'c-footer__link',
|
|
32
|
+
active && 'c-footer__link--active',
|
|
33
|
+
disabled && 'c-footer__link--disabled',
|
|
34
|
+
className,
|
|
35
|
+
]
|
|
36
|
+
.filter(Boolean)
|
|
37
|
+
.join(' ');
|
|
38
|
+
|
|
39
|
+
const linkProps = {
|
|
40
|
+
className: linkClass,
|
|
41
|
+
onClick: disabled ? undefined : onClick,
|
|
42
|
+
'aria-disabled': disabled,
|
|
43
|
+
...(external && {
|
|
44
|
+
target: '_blank',
|
|
45
|
+
rel: 'noopener noreferrer',
|
|
46
|
+
}),
|
|
47
|
+
...props,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
if (LinkComponent) {
|
|
51
|
+
return (
|
|
52
|
+
<LinkComponent ref={ref} to={href} {...linkProps}>
|
|
53
|
+
{icon && <span className="c-footer__link-icon">{icon}</span>}
|
|
54
|
+
<span className="c-footer__link-text">{children}</span>
|
|
55
|
+
{external && <span className="c-footer__link-external">↗</span>}
|
|
56
|
+
</LinkComponent>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<a ref={ref} href={disabled ? undefined : href} {...linkProps}>
|
|
62
|
+
{icon && <span className="c-footer__link-icon">{icon}</span>}
|
|
63
|
+
<span className="c-footer__link-text">{children}</span>
|
|
64
|
+
{external && <span className="c-footer__link-external">↗</span>}
|
|
65
|
+
</a>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
FooterLink.displayName = 'FooterLink';
|
|
71
|
+
|
|
72
|
+
export default FooterLink;
|