Skip to content

Commit

Permalink
feat: Create Footer Component
Browse files Browse the repository at this point in the history
  • Loading branch information
fa-901 committed Oct 14, 2023
1 parent 4dc0089 commit a1d4a3c
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 9 deletions.
49 changes: 49 additions & 0 deletions components/sections/Footer/index.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
.footer {
@apply flex
flex-col
items-center
gap-6
px-8
py-4
md:flex-row
md:justify-between
md:py-5;

.sectionPrimary {
@apply flex
flex-wrap
content-start
items-center
justify-center
gap-1
self-stretch;

a {
@apply whitespace-nowrap;
}
}

.sectionSecondary {
@apply flex
flex-col
items-center
gap-1
md:flex-row;

.social {
@apply flex
items-center
gap-1;
}
}

.darkImage {
@apply hidden
dark:block;
}

.lightImage {
@apply block
dark:hidden;
}
}
10 changes: 10 additions & 0 deletions components/sections/Footer/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { Meta as MetaObj, StoryObj } from '@storybook/react';

import Footer from './index';

type Story = StoryObj<typeof Footer>;
type Meta = MetaObj<typeof Footer>;

export const Default: Story = {};

export default { component: Footer } as Meta;
58 changes: 58 additions & 0 deletions components/sections/Footer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import classNames from 'classnames';
import Image from 'next/image';
import type { FC } from 'react';
import { FormattedMessage } from 'react-intl';

import NavItem from '@/components/sections/NavItem';
import { useSiteConfig } from '@/hooks/useSiteConfig';

import styles from './index.module.css';

const Footer: FC = () => {
const { footerLinks, socialLinks } = useSiteConfig();

const openJSlink = footerLinks.at(-1)!;

return (
<footer className={styles.footer}>
<div className={styles.sectionPrimary}>
{footerLinks.slice(0, -1).map(item => (
<NavItem type="footer" href={item.link} key={item.link}>
<FormattedMessage id={item.text} />
</NavItem>
))}
</div>
<div className={styles.sectionSecondary}>
<NavItem type="footer" href={openJSlink.link}>
&copy; <FormattedMessage id={openJSlink.text} />
</NavItem>
<div className={styles.social}>
{socialLinks.map(link => {
const navClass = classNames({
[styles.darkImage]: link.kind === 'dark',
[styles.lightImage]: link.kind === 'light',
});

return (
<NavItem
className={navClass}
key={link.icon}
href={link.link}
type="footer"
>
<Image
src={link.icon}
alt={link.alt || 'social'}
width={20}
height={20}
/>
</NavItem>
);
})}
</div>
</div>
</footer>
);
};

export default Footer;
13 changes: 10 additions & 3 deletions components/sections/NavItem/index.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,28 @@ type Meta = MetaObj<typeof NavItem>;
export const Default: Story = {
args: {
href: '/learn',
label: 'Learn',
children: 'Learn',
},
};

export const WithExternalLink: Story = {
args: {
href: 'https://nodejs.org/en',
label: 'Learn',
children: 'Learn',
},
};

export const WithChildren: Story = {
args: {
href: 'https://nodejs.org/en',
children: <b>Learn</b>,
},
};

export const FooterItem: Story = {
args: {
href: '/about',
label: 'Trademark Policy',
children: 'Trademark Policy',
type: 'footer',
},
};
Expand Down
15 changes: 10 additions & 5 deletions components/sections/NavItem/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ArrowUpRightIcon } from '@heroicons/react/24/solid';
import classNames from 'classnames';
import type { FC } from 'react';
import type { FC, PropsWithChildren } from 'react';
import { useMemo } from 'react';

import LocalizedLink from '@/components/LocalizedLink';
Expand All @@ -11,11 +11,16 @@ type NavItemType = 'nav' | 'footer';

type NavItemProps = {
href: string;
label?: string;
type?: NavItemType;
className?: string;
};

const NavItem: FC<NavItemProps> = ({ href, label, type = 'nav' }) => {
const NavItem: FC<PropsWithChildren<NavItemProps>> = ({
href,
type = 'nav',
children,
className,
}) => {
const showIcon = useMemo(
() => type === 'nav' && /^https?:\/\//.test(href),
[href, type]
Expand All @@ -24,9 +29,9 @@ const NavItem: FC<NavItemProps> = ({ href, label, type = 'nav' }) => {
return (
<LocalizedLink
href={href}
className={classNames(styles.navItem, styles[type])}
className={classNames(styles.navItem, styles[type], className)}
>
<span className={styles.label}>{label}</span>
<span className={styles.label}>{children}</span>
{showIcon && <ArrowUpRightIcon className={styles.icon} />}
</LocalizedLink>
);
Expand Down
5 changes: 5 additions & 0 deletions i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
"components.header.links.security": "Security",
"components.header.links.certification": "Certification",
"components.header.links.blog": "News",
"components.footer.links.trademarkPolicy": "Trademark Policy",
"components.footer.links.privacyPolicy": "Privacy Policy",
"components.footer.links.codeOfConduct": "Code of Conduct",
"components.footer.links.security": "Security",
"components.footer.links.openJS": "OpenJS Foundation",
"components.navigation.about.links.governance": "Governance",
"components.navigation.docs.links.es6": "ES6 and beyond",
"components.navigation.docs.links.apiLts": "{fullLtsNodeVersion} API {spanLts}",
Expand Down
62 changes: 61 additions & 1 deletion site.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,65 @@
"text": "Security releases now available",
"link": "https://nodejs.org/en/blog/vulnerability/october-2023-security-releases/"
}
}
},
"footerLinks": [
{
"link": "https://openjsf.org/wp-content/uploads/sites/84/2021/01/OpenJS-Foundation-Trademark-Policy-2021-01-12.docx.pdf",
"text": "components.footer.links.trademarkPolicy"
},
{
"link": "https://openjsf.org/wp-content/uploads/sites/84/2021/04/OpenJS-Foundation-Privacy-Policy-2019-11-15.pdf",
"text": "components.footer.links.privacyPolicy"
},
{
"link": "https://github.com/openjs-foundation/cross-project-council/blob/main/CODE_OF_CONDUCT.md",
"text": "components.footer.links.codeOfConduct"
},
{
"link": "https://github.com/nodejs/node/blob/HEAD/SECURITY.md#security",
"text": "components.footer.links.security"
},
{
"link": "https://openjsf.org/",
"text": "components.footer.links.openJS"
}
],
"socialLinks": [
{
"icon": "/static/images/logos/social-github.svg",
"link": "https://github.com/nodejs/node",
"kind": "dark",
"alt": "GitHub"
},
{
"icon": "/static/images/logos/social-github-dark.svg",
"link": "https://github.com/nodejs/node",
"kind": "light",
"alt": "GitHub"
},
{
"icon": "/static/images/logos/social-mastodon.svg",
"link": "https://social.lfx.dev/@nodejs",
"kind": "neutral",
"alt": "Mastodon"
},
{
"icon": "/static/images/logos/social-twitter.svg",
"link": "https://twitter.com/nodejs",
"kind": "neutral",
"alt": "Twitter"
},
{
"icon": "/static/images/logos/social-slack.svg",
"link": "https://openjs-foundation.slack.com/join/shared_invite/zt-238w9sb83-Qk9NcsrEMomq94Y~3gW8EQ#/shared-invite/email",
"kind": "neutral",
"alt": "Slack"
},
{
"icon": "/static/images/logos/social-linkedin.svg",
"link": "https://www.linkedin.com/company/node-js",
"kind": "neutral",
"alt": "LinkedIn"
}
]
}
14 changes: 14 additions & 0 deletions types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ export interface OGConfig {
imgHeight: string;
}

export interface FooterConfig {
text: string;
link: string;
}

export interface SocialConfig {
icon: string;
link: string;
kind: 'dark' | 'light' | 'neutral';
alt?: string;
}

export interface SiteConfig {
title: string;
description: string;
Expand All @@ -23,4 +35,6 @@ export interface SiteConfig {
twitter: TwitterConfig;
rssFeeds: Array<RSSFeed>;
websiteBanners: Record<string, WebsiteBanner>;
footerLinks: Array<FooterConfig>;
socialLinks: Array<SocialConfig>;
}

0 comments on commit a1d4a3c

Please sign in to comment.