diff --git a/components/common/Footer.jsx b/components/common/Footer.jsx index 5bd9438..0d4327d 100644 --- a/components/common/Footer.jsx +++ b/components/common/Footer.jsx @@ -9,7 +9,6 @@ const FooterWrap = styled.footer` font-weight: 400; letter-spacing: -.01em; font-family: "SF Pro Text","SF Pro Icons","Helvetica Neue","Helvetica","Arial",sans-serif; - min-width: 1024px; overflow: hidden; position: relative; z-index: 1; diff --git a/components/common/Header.jsx b/components/common/Header.jsx index 4f930fe..7c3e428 100644 --- a/components/common/Header.jsx +++ b/components/common/Header.jsx @@ -5,6 +5,8 @@ import styled from 'styled-components' import { ExternalLink } from "react-feather" import Button from '@/components/common/Button'; import { Container } from '@/components/common/layout'; +import { mediaQueries } from '@/styles/breakpoints'; +import navigation from '@/data/navigation'; const Nav = styled.nav` position: relative; @@ -69,6 +71,9 @@ const MenuTray = styled.div` display: flex; align-items: center; gap: 24px; + @media ${mediaQueries.sm} { + display: none; + } `; const MenuItems = styled.ul``; const MenuItem = styled.li` @@ -92,6 +97,7 @@ const MenuItem = styled.li` && a { color: var(--foreground-color) !important; opacity: 0.5;import { Container } from '@/components/common/Container'; +import { mediaQueries } from '../../styles/mediaQueries'; } ` : ``} @@ -127,40 +133,18 @@ function Header() { - - - CodeEdit - - - - - What’s included - - - - - Resources - - - - - Developer - - - - - Extensions - - - - - GitHub - - - + {navigation.map(item => { + const isExternal = item.href.match(/(https?:\/\/[\w\d.-]+)/gi); + + return ( + + + {item.label} + + {isExternal && } + + ); + })} diff --git a/components/common/Site.jsx b/components/common/Site.jsx index 84b041a..b4a0dd2 100644 --- a/components/common/Site.jsx +++ b/components/common/Site.jsx @@ -2,6 +2,7 @@ import React, { useEffect, useContext } from "react"; import theme from "@/styles/theme"; import { ThemeProvider } from "styled-components"; import useColorScheme from "@/hooks/useColorScheme"; +import useWindowDimensions from '../../hooks/useWindowDimensions'; export const SiteContext = React.createContext({}); @@ -13,11 +14,10 @@ export const useSite = () => useContext(SiteContext); const Site = ({ children }) => { const { colorScheme, setColorScheme } = useColorScheme(); - - console.log({ colorScheme }) + const windowDimensions = useWindowDimensions(); return ( - + {children} diff --git a/components/common/Typography.jsx b/components/common/Typography.jsx index 29ad0e9..7182274 100644 --- a/components/common/Typography.jsx +++ b/components/common/Typography.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import styled from 'styled-components'; -import getTypographyStyles from '../../styles/getTypographyStyles'; +import getTypographyStyles from '@/styles/getTypographyStyles'; const TypographyWrap = styled.p` ${({ variant }) => getTypographyStyles(variant)} diff --git a/components/common/layout/Grid.jsx b/components/common/layout/Grid.jsx index ceed243..49b8096 100644 --- a/components/common/layout/Grid.jsx +++ b/components/common/layout/Grid.jsx @@ -7,7 +7,6 @@ const Grid = styled.div` ${({ columns }) => getResponsivePropStyles(columns, (val) => `grid-template-columns: repeat(${val}, 1fr);`)} ${({ rowHeight }) => getResponsivePropStyles(rowHeight, (val) => `grid-auto-rows: ${getSpacing(val)};`)} ${({ gap }) => getResponsivePropStyles(gap, (val) => `gap: ${getSpacing(val)};`)} - `; export default Grid; diff --git a/components/common/layout/GridItem.jsx b/components/common/layout/GridItem.jsx index b88e3d1..eaa1165 100644 --- a/components/common/layout/GridItem.jsx +++ b/components/common/layout/GridItem.jsx @@ -1,6 +1,7 @@ import React from "react"; import styled from "styled-components" import getResponsivePropStyles from '@/styles/getResponsivePropStyles'; +import useVisibilityProps from '../../../hooks/useVisibilityProps'; const GridItemWrap = styled.div` ${({ $width }) => getResponsivePropStyles($width, (val) => `grid-column-start: ${Number(val ?? 1)} span;`)} @@ -10,9 +11,11 @@ const GridItemWrap = styled.div` `; const GridItem = ({ children, width, height, as, ...props }) => { - return ( + const isVisible = useVisibilityProps(props); + + return isVisible ? ( {children} - ) + ) : null; } export default GridItem; diff --git a/components/common/layout/Section.jsx b/components/common/layout/Section.jsx index ad30e6a..7c53ddf 100644 --- a/components/common/layout/Section.jsx +++ b/components/common/layout/Section.jsx @@ -2,6 +2,7 @@ import styled from "styled-components"; import RestrictedContainer from "./Container" import getSpacing from '@/styles/spacing'; import getResponsivePropStyles from '@/styles/getResponsivePropStyles'; +import useVisibilityProps from "@/hooks/useVisibilityProps"; const SectionWrap = styled.section` ${({ gutter, gutterTop, gutterY }) => getResponsivePropStyles((gutterTop ?? gutterY ?? gutter ?? 8), (val) => ` @@ -24,6 +25,9 @@ const FullWidthContainer = styled.div` export default function Section (props) { let { children, className, contained, gutter, gutterTop, gutterBottom, gutterLeft, gutterRight, gutterX = true, gutterY } = props; const Container = contained ? RestrictedContainer : FullWidthContainer; + const isVisible = useVisibilityProps(props); + + if (!isVisible) return null; const defaultGutterX = 3; const defaultGutterY = 8; diff --git a/components/pages/home/sections/FeaturesSection.jsx b/components/pages/home/sections/FeaturesSection.jsx index 0249037..ff5a548 100644 --- a/components/pages/home/sections/FeaturesSection.jsx +++ b/components/pages/home/sections/FeaturesSection.jsx @@ -12,8 +12,8 @@ const FeaturesSection = () => { This is a description of the features section. - - + + Feature Title 1 @@ -22,7 +22,7 @@ const FeaturesSection = () => { - + Feature Title 2 @@ -31,7 +31,7 @@ const FeaturesSection = () => { - + Feature Title 4 @@ -40,7 +40,7 @@ const FeaturesSection = () => { - + Feature Title 2 @@ -49,7 +49,7 @@ const FeaturesSection = () => { - + Feature Title 3 diff --git a/components/pages/home/sections/IntroFeaturesSection.jsx b/components/pages/home/sections/IntroFeaturesSection.jsx index 8a8dc24..285b4a2 100644 --- a/components/pages/home/sections/IntroFeaturesSection.jsx +++ b/components/pages/home/sections/IntroFeaturesSection.jsx @@ -6,7 +6,7 @@ import { Grid, GridItem, Section, Stack } from '@/components/common/layout'; const IntroFeaturesSection = () => { return (
- + diff --git a/components/pages/home/sections/MoreFeaturesSection.jsx b/components/pages/home/sections/MoreFeaturesSection.jsx index 3c760f2..347a1b7 100644 --- a/components/pages/home/sections/MoreFeaturesSection.jsx +++ b/components/pages/home/sections/MoreFeaturesSection.jsx @@ -12,8 +12,8 @@ const MoreFeaturesSection = () => { This is a description of the features section. - - + + Feature Title 1 @@ -22,7 +22,7 @@ const MoreFeaturesSection = () => { - + Feature Title 4 @@ -31,7 +31,7 @@ const MoreFeaturesSection = () => { - + Feature Title 2 @@ -40,7 +40,7 @@ const MoreFeaturesSection = () => { - + Feature Title 3 @@ -49,7 +49,7 @@ const MoreFeaturesSection = () => { - + Feature Title 2 diff --git a/components/pages/home/sections/SocialSection.jsx b/components/pages/home/sections/SocialSection.jsx index bd6193f..188bfa4 100644 --- a/components/pages/home/sections/SocialSection.jsx +++ b/components/pages/home/sections/SocialSection.jsx @@ -6,7 +6,7 @@ import { Grid, GridItem, Section, Stack } from '@/components/common/layout'; const SocialSection = () => { return (
- + { This is a description of the why CodeEdit section. - + diff --git a/data/navigation.js b/data/navigation.js new file mode 100644 index 0000000..a4b4445 --- /dev/null +++ b/data/navigation.js @@ -0,0 +1,28 @@ +const navigation = [ + { + href: '/', + label: 'CodeEdit', + }, + { + href: 'whats-new', + label: 'What’s Included', + }, + { + href: 'resources', + label: 'Resources', + }, + { + href: 'developer', + label: 'Developer', + }, + { + href: 'extensions', + label: 'Extensions', + }, + { + href: 'https://github.com/CodeEditApp/CodeEdit', + label: 'GitHub', + }, +]; + +export default navigation; diff --git a/hooks/useVisibilityProps.js b/hooks/useVisibilityProps.js new file mode 100644 index 0000000..ec42a2b --- /dev/null +++ b/hooks/useVisibilityProps.js @@ -0,0 +1,52 @@ +import { useSite } from '@/components/common/Site'; + +const useVisibilityProps = (props) => { + const { + windowDimensions: { breakpoint }, + } = useSite(); + const { show, hide } = props; + + if (Object.hasOwnProperty.call(props, 'hide')) { + if (hide === true) { + return false; + } + if (typeof hide === 'string') { + if (hide === breakpoint) { + return false; + } + } + if (Array.isArray(hide)) { + if (hide.includes(breakpoint)) { + return false; + } + } else if (typeof hide === 'object') { + if (hide[breakpoint]) { + return false; + } + } + } + + if (Object.hasOwnProperty.call(props, 'show')) { + if (!show) { + return false; + } + if (typeof show === 'string') { + if (show !== breakpoint) { + return false; + } + } + if (Array.isArray(show)) { + if (!show.includes(breakpoint)) { + return false; + } + } else if (typeof show === 'object') { + if (!show[breakpoint]) { + return false; + } + } + } + + return true; +}; + +export default useVisibilityProps; diff --git a/hooks/useWindowDimensions.js b/hooks/useWindowDimensions.js new file mode 100644 index 0000000..33ec625 --- /dev/null +++ b/hooks/useWindowDimensions.js @@ -0,0 +1,26 @@ +import { getBreakpoint } from '@/styles/breakpoints'; +import { useState, useEffect } from 'react'; + +const useWindowDimensions = () => { + const [windowDimensions, setWindowDimensions] = useState({}); + + useEffect(() => { + const handleResize = () => { + setWindowDimensions({ + width: window.innerWidth, + height: window.innerHeight, + breakpoint: getBreakpoint(window.innerWidth), + }); + }; + + window.addEventListener('resize', handleResize); + + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return windowDimensions; +}; + +export default useWindowDimensions; diff --git a/jsconfig.json b/jsconfig.json index 46ced15..ae4d99a 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -3,9 +3,10 @@ "baseUrl": ".", "paths": { "@/components/*": ["./components/*"], + "@/data/*": ["./data/*"], "@/hooks/*": ["./hooks/*"], - "@/utils/*": ["./utils/*"], - "@/styles/*": ["./styles/*"] + "@/styles/*": ["./styles/*"], + "@/utils/*": ["./utils/*"] } } } diff --git a/styles/breakpoints.js b/styles/breakpoints.js new file mode 100644 index 0000000..76e3773 --- /dev/null +++ b/styles/breakpoints.js @@ -0,0 +1,75 @@ +export const breakpoints = { + xs: 500, + sm: 767, + md: 1068, + lg: 1440, + xl: 9999, +}; + +export const getBreakpoint = (width) => { + const { xs, sm, md, lg } = breakpoints; + + if (width <= xs) { + return 'xs'; + } + if (width > xs && width <= sm) { + return 'sm'; + } + if (width > sm && width <= md) { + return 'md'; + } + if (width > md && width <= lg) { + return 'lg'; + } + if (width > lg) { + return 'xl'; + } +}; + +export const mediaQueries = { + // small phones + xs: `only screen and (max-width: ${breakpoints.xs}px)`, + // most phones + sm: `only screen and (max-width: ${breakpoints.sm}px)`, + // tablets + md: `only screen and (max-width: ${breakpoints.md}px)`, + // large tablets and small desktops + lg: `only screen and (max-width: ${breakpoints.lg}px)`, + // large desktops + xl: `only screen and (min-width: ${breakpoints.lg + 1}px)`, +}; + +//////////////////////////////////// +// ... xs | sm | md | lg | xl ... // +// ============================== // +// min xs : 0 - Infinity // +// ...------------------------... // +// only xs : 0 - 499 // +// ...----| // +// max xs : 0 - 499 // +// ...----| // +// min sm : 500 - Infinity // +// |-------------------... // +// only sm : 500 - 733 // +// |----| // +// max sm : 0 - 734 // +// ...---------| // +// min md : 734 - Infinity // +// |--------------... // +// only md : 734 - 1068 // +// |----| // +// max md : 0 - 1068 // +// ...--------------| // +// min lg : 0 - 1440 // +// ...-------------------| // +// only lg : 0 - 1440 // +// |----| // +// max lg : 0 - 1440 // +// ...-------------------| // +// min xl : 1441 - Infinity // +// |----... // +// only xl : 1441 - Infinity // +// |----... // +// max xl : 0 - Infinity // +// ...------------------------... // +//////////////////////////////////// diff --git a/styles/getResponsivePropStyles.js b/styles/getResponsivePropStyles.js index cf83ba4..0e1b269 100644 --- a/styles/getResponsivePropStyles.js +++ b/styles/getResponsivePropStyles.js @@ -1,4 +1,4 @@ -import mediaQueries from './mediaQueries'; +import { mediaQueries } from './breakpoints'; const getMediaQueryStyle = (size, val, getStyle) => Object.keys(val).includes(size) diff --git a/styles/getTypographyStyles.js b/styles/getTypographyStyles.js index 07b3634..4025751 100644 --- a/styles/getTypographyStyles.js +++ b/styles/getTypographyStyles.js @@ -1,4 +1,4 @@ -import mediaQueries from './mediaQueries'; +import { mediaQueries } from './breakpoints'; const getTypographyStyles = (variant) => { switch (variant) { diff --git a/styles/mediaQueries.js b/styles/mediaQueries.js deleted file mode 100644 index 713f9ea..0000000 --- a/styles/mediaQueries.js +++ /dev/null @@ -1,14 +0,0 @@ -const mediaQueries = { - // small phones - xs: `only screen and (max-width: 500px)`, - // most phones - sm: `only screen and (max-width: 734px)`, - // tablets - md: `only screen and (max-width: 1068px)`, - // large tablets and small desktops - lg: `only screen and (max-width: 1440px)`, - // large desktops - xl: `only screen and (min-width: 1441px)`, -}; - -export default mediaQueries; diff --git a/styles/theme.js b/styles/theme.js index 35dd7b4..d31824f 100644 --- a/styles/theme.js +++ b/styles/theme.js @@ -1,4 +1,4 @@ -import mediaQueries from './mediaQueries'; +import { mediaQueries } from './breakpoints'; import getResponsivePropStyles from './getResponsivePropStyles'; const theme = {