diff --git a/package-lock.json b/package-lock.json index cfa1cf1..a1a47a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,8 @@ "dependencies": { "next": "14.1.1", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "react-icons": "^5.1.0" }, "devDependencies": { "@babel/preset-env": "^7.24.0", @@ -8140,6 +8141,14 @@ "react": "^18.2.0" } }, + "node_modules/react-icons": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.1.0.tgz", + "integrity": "sha512-D3zug1270S4hbSlIRJ0CUS97QE1yNNKDjzQe3HqY0aefp2CBn9VgzgES27sRR2gOvFK+0CNx/BW0ggOESp6fqQ==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", diff --git a/package.json b/package.json index eb570d9..9ec1ee0 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "dependencies": { "next": "14.1.1", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "react-icons": "^5.1.0" }, "devDependencies": { "@babel/preset-env": "^7.24.0", diff --git a/src/app/components/socialSection/socialLinks.tsx b/src/app/components/socialSection/socialLinks.tsx new file mode 100644 index 0000000..deb7ef7 --- /dev/null +++ b/src/app/components/socialSection/socialLinks.tsx @@ -0,0 +1,25 @@ +import { IconContext } from 'react-icons'; +import { SocialLinkData } from './socialSection'; +import styles from './socialSection.module.css'; + +interface SocialLinksProps { + links: SocialLinkData[]; +} + +const SocialLinks = ({ links }: SocialLinksProps) => { + return ( + + + + ); +}; + +export default SocialLinks; diff --git a/src/app/components/socialSection/socialSection.module.css b/src/app/components/socialSection/socialSection.module.css new file mode 100644 index 0000000..96da769 --- /dev/null +++ b/src/app/components/socialSection/socialSection.module.css @@ -0,0 +1,35 @@ +.socialSection { + display: flex; + gap: 4rem; + align-items: center; + padding: 60px 60px 60px 0; +} + +.socialSection p { + font-family: 'Raleway', sans-serif; + font-size: 55px; +} + +.imageContainer { + display: flex; + align-items: center; + justify-content: start; + width: 50%; + height: 500px; + background-color: #0f1034; + border-radius: 0 30px 30px 0; +} + +.imageContainer img { + border-radius: 0 15px 15px 0; + width: 93%; + height: 90%; +} + +.socialLinks { + display: flex; + gap: 2.5rem; + justify-content: space-evenly; + list-style: none; + padding: 0; +} diff --git a/src/app/components/socialSection/socialSection.test.js b/src/app/components/socialSection/socialSection.test.js new file mode 100644 index 0000000..7344657 --- /dev/null +++ b/src/app/components/socialSection/socialSection.test.js @@ -0,0 +1,45 @@ +import { render, screen } from '@testing-library/react'; +import SocialSection from './socialSection'; + +describe('SocialSection', () => { + const mockData = [ + { + id: 'github', + imgSrc: '/assets/githubIcon.png', + alt: 'Github social icon', + link: 'https://github.com', + }, + { + id: 'discord', + imgSrc: '/assets/discordIcon.png', + alt: 'Discord social icon', + link: 'https://discord.com', + }, + { + id: 'meetup', + imgSrc: '/assets/meetupIcon.png', + alt: 'Meetup social icon', + link: '/', + }, + { + id: 'linkedin', + imgSrc: '/assets/linkedinIcon.png', + alt: 'LinkedIn social icon', + link: '/', + }, + ]; + + test('renders SocialSection component', () => { + render(); + + const socialSection = screen.getByTestId('socialSection'); + expect(socialSection).toBeInTheDocument(); + }); + + test('renders all social icons', () => { + render(); + + const linkList = screen.getAllByRole('listitem'); + expect(linkList).toHaveLength(4); + }); +}); diff --git a/src/app/components/socialSection/socialSection.tsx b/src/app/components/socialSection/socialSection.tsx new file mode 100644 index 0000000..8044ccf --- /dev/null +++ b/src/app/components/socialSection/socialSection.tsx @@ -0,0 +1,40 @@ +import Image from 'next/image'; +import SocialLinks from './socialLinks'; +import styles from './socialSection.module.css'; + +export interface SocialLinkData { + id: string; + icon: React.ReactNode; + imgSrc: string; + alt: string; + link: string; +} + +interface SocialSectionProps { + socialData: SocialLinkData[]; +} + +export default function SocialSection({ socialData }: SocialSectionProps) { + return ( +
+
+ +
+
+

+ Join our Discord and
other social links! +

+

+ This is YOUR community, +
be a part of it! +

+ +
+
+ ); +} diff --git a/src/app/hooks/useMediaQuery/README.md b/src/app/hooks/useMediaQuery/README.md new file mode 100644 index 0000000..45df5f3 --- /dev/null +++ b/src/app/hooks/useMediaQuery/README.md @@ -0,0 +1,7 @@ +This is a slimmer version of the `useMediaQuery` hook from [useHooks-ts](https://usehooks-ts.com/react-hook/use-media-query) + +This hook uses the [`matchMedia()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) method of the `Window` object to check for matching conditions against a media query passed into the hook. + +`useMediaQuery` takes a media query argument passed as a string: + +`useMediaQuery('(max-width: 750px)')` diff --git a/src/app/hooks/useMediaQuery/index.tsx b/src/app/hooks/useMediaQuery/index.tsx new file mode 100644 index 0000000..a3b27f4 --- /dev/null +++ b/src/app/hooks/useMediaQuery/index.tsx @@ -0,0 +1,18 @@ +import { useState, useEffect } from 'react'; + +const useMediaQuery = (query: string): boolean => { + const [isMatch, setIsMatch] = useState(false); + + useEffect(() => { + const mediaQueryList = window.matchMedia(query); + setIsMatch(mediaQueryList.matches); + + mediaQueryList.onchange = (event) => { + setIsMatch(event.matches); + }; + }, [query]); + + return isMatch; +}; + +export default useMediaQuery; diff --git a/src/app/page.tsx b/src/app/page.tsx index 4961c35..1db7719 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,7 +1,11 @@ +'use client'; +import { FaDiscord, FaGithub, FaLinkedin, FaMeetup } from 'react-icons/fa'; +import useMediaQuery from './hooks/useMediaQuery'; import CardsSection from './components/cardsSection/cardsSection'; import BannerSection from './components/bannerSection/bannerSection'; import HeroSection from './components/heroSection/heroSection'; import Navbar from './components/navbar/navbar'; +import SocialSection from './components/socialSection/socialSection'; import styles from './page.module.css'; import GroupPhotoSection from './components/groupPhotoSection/groupPhotoSection'; import BentoSection from './components/bentoSection/bentoSection'; @@ -35,14 +39,51 @@ export default function Home() { meetupUrl: 'https://www.meetup.com/dallas-software-developers-meetup/', communityUrl: '/', cohortUrl: '/', + githubUrl: 'https://github.com/dallassoftwaredevelopers', + discordUrl: '/', + linkedinUrl: 'https://www.linkedin.com/company/dallas-software-developers', }; + const socialData = [ + { + id: 'github', + icon: , + imgSrc: '/assets/githubIcon.png', + alt: 'Github social icon', + link: labelMap.githubUrl, + }, + { + id: 'discord', + icon: , + imgSrc: '/assets/discordIcon.png', + alt: 'Discord social icon', + link: labelMap.discordUrl, + }, + { + id: 'meetup', + icon: , + imgSrc: '/assets/meetupIcon.png', + alt: 'Meetup social icon', + link: labelMap.meetupUrl, + }, + { + id: 'linkedin', + icon: , + imgSrc: '/assets/linkedinIcon.png', + alt: 'LinkedIn social icon', + link: labelMap.linkedinUrl, + }, + ]; + + const isDesktop = useMediaQuery('(min-width: 1024px)'); + return (
+ {isDesktop && }