From d9258ba2bc6794eea9cd0e7a01d1749a8136d40f Mon Sep 17 00:00:00 2001 From: fbering Date: Wed, 26 Feb 2020 23:41:01 +0100 Subject: [PATCH] Hep. Har smidt notes.txt med. --- notes.txt | 3 + src/App/App.tsx | 26 ++-- src/App/styled.ts | 36 ++++-- src/components/Icon/Icon.tsx | 52 ++++++++ src/components/Icon/index.tsx | 1 + src/components/Icon/styled.ts | 41 ++++++ src/components/Navigation/Navigation.tsx | 67 ++++++++++ src/components/Navigation/NavigationItem.tsx | 29 +++++ src/components/Navigation/index.tsx | 1 + src/components/Navigation/styled.ts | 128 +++++++++++++++++++ 10 files changed, 366 insertions(+), 18 deletions(-) create mode 100644 notes.txt create mode 100644 src/components/Icon/Icon.tsx create mode 100644 src/components/Icon/index.tsx create mode 100644 src/components/Icon/styled.ts create mode 100644 src/components/Navigation/Navigation.tsx create mode 100644 src/components/Navigation/NavigationItem.tsx create mode 100644 src/components/Navigation/index.tsx create mode 100644 src/components/Navigation/styled.ts diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000..8d4f9eb --- /dev/null +++ b/notes.txt @@ -0,0 +1,3 @@ +Har ikke arbejdet med styled components før så min brug af det er måske helt forkert. Men synes det er et super spændende værktøj og et skønt fix til det BEM helvede jeg arbejder med nogengange. Muligheden for genbrug virker også fed. + +Er også typescript rookie. Men er stor fan af det! diff --git a/src/App/App.tsx b/src/App/App.tsx index 04ab6f5..37a8ee0 100644 --- a/src/App/App.tsx +++ b/src/App/App.tsx @@ -1,17 +1,23 @@ -import React from "react"; -import { DeleteMe } from "./styled"; +import React from 'react'; +import { GlobalStyle } from './styled'; +import Navigation from '../components/Navigation'; +import bgImage from '../assets/background.png'; -function App() { +const navItems = [ + { label: 'Kanaler', iconType: 'channels', url: '#kanaler' }, + { label: 'Film', iconType: 'movies', url: '#film' }, + { label: 'Serier', iconType: 'series', url: '#serier' }, + { label: 'Børn', iconType: 'parental', url: '#boern' }, + { label: 'Min Samling', iconType: 'favorites', url: '#min-samling' } +]; + +const App = () => { return (
- - Implement the menu instead of me - - 🦄 - - + +
); -} +}; export default App; diff --git a/src/App/styled.ts b/src/App/styled.ts index 807101d..0a283ef 100644 --- a/src/App/styled.ts +++ b/src/App/styled.ts @@ -1,9 +1,29 @@ -import styled from "styled-components"; - -export const DeleteMe = styled.div` - display: flex; - justify-content: center; - align-items: center; - height: 100vh; - font-size: 5rem; +import { createGlobalStyle } from 'styled-components' + +interface GlobalStyleProps { + readonly bgImage?: string; +}; + +export const GlobalStyle = createGlobalStyle` + html, + body { + height: 100%; + position: relative; + } + + body { + background-color: #eee; + background-image: ${props => (props.bgImage ? `url(${props.bgImage})` : 'none')}; + background-position: right top; + background-repeat: no-repeat; + background-size: cover; + color: #fff; + font-size: 16px; + margin: 0; + padding: 0; + } + + * { + outline: none; + } `; diff --git a/src/components/Icon/Icon.tsx b/src/components/Icon/Icon.tsx new file mode 100644 index 0000000..0785c51 --- /dev/null +++ b/src/components/Icon/Icon.tsx @@ -0,0 +1,52 @@ +import React from 'react'; +import { + IconImg, + IconWrapper, + IconWrapperDesktop, + IconWrapperMobile +} from './styled'; + +const wrapComponents: { [key: string]: Function } = { + base: IconWrapper, + desktop: IconWrapperDesktop, + mobile: IconWrapperMobile +}; + +type IconProps = { + bp?: string, + clickCallback?: Function, + fill?: string, + large?: boolean, + rotate?: number, + type: string +}; + +const Icon = ({ + bp, + clickCallback, + fill, + large, + rotate, + type +}: IconProps ) => { + const IconWrap = wrapComponents[bp || 'base'] || IconWrapper; + + const handleClick = () => { + if (clickCallback) { + clickCallback(); + } + } + + return ( + + + + ); +}; + +export default Icon; diff --git a/src/components/Icon/index.tsx b/src/components/Icon/index.tsx new file mode 100644 index 0000000..dc6b45c --- /dev/null +++ b/src/components/Icon/index.tsx @@ -0,0 +1 @@ +export { default } from './Icon'; diff --git a/src/components/Icon/styled.ts b/src/components/Icon/styled.ts new file mode 100644 index 0000000..8c42049 --- /dev/null +++ b/src/components/Icon/styled.ts @@ -0,0 +1,41 @@ +import styled from "styled-components"; + +interface IconWrapperProps { + readonly large: boolean; +}; + +interface IconImgProps { + readonly rotate: number; + readonly fill: string; +}; + + +export const IconWrapper = styled.span` + display: inline-block; + width: ${props => props.large ? '41px' : '28px' }; +`; + +export const IconWrapperDesktop = styled(IconWrapper)` + @media(max-width: 767px) { + display: none; + } +`; + +export const IconWrapperMobile = styled(IconWrapper)` + @media(min-width: 768px) { + display: none; + } +`; + +export const IconImg = styled.img` + display: block; + max-width: 100%; + ${props => props.fill === 'white' && ( + 'filter: invert(100%) sepia(0%) saturate(348%) hue-rotate(61deg) brightness(114%) contrast(87%);' + )} + ${props => props.fill === 'teal' && ( + 'filter: invert(76%) sepia(6%) saturate(1108%) hue-rotate(154deg) brightness(90%) contrast(94%);' + )} + transform: rotate(${props => props.rotate ? `${props.rotate}deg` : '0deg'}); + transition: transform 500ms; +`; diff --git a/src/components/Navigation/Navigation.tsx b/src/components/Navigation/Navigation.tsx new file mode 100644 index 0000000..d15b804 --- /dev/null +++ b/src/components/Navigation/Navigation.tsx @@ -0,0 +1,67 @@ +import React, { useState } from 'react'; +import { + NavWrapper, + NavDesktopButton, + NavMobileButton, + NavButtonClose, + NavTitle, + NavItemList +} from './styled'; +import Icon from '../Icon'; +import NavigationItem, { NavigationItemProps } from './NavigationItem'; + +type NavigationProps = { + items: Array, + title: string, + iconHome?: string, + iconHomeMobile?: string +}; + +const Navigation = ({ + items, + title, + iconHome, + iconHomeMobile +}: NavigationProps ) => { + const [isOpen, setIsOpen] = useState(false); + + const iconTypeHome = iconHome || 'HOME_ACTIVE'; + const iconTypeHomeMobile = iconHomeMobile || 'HOME_ACTIVE_RESPONSIVE'; + + const navItems = items.map(item => ()); + + const handleMenuClick = () => { + setIsOpen(!isOpen); + }; + + return ( + + { isOpen && ( + + + + )} + + + { title } + + + + { isOpen ? ( + + + { title } + + + ) : ( + + )} + + +
    { navItems }
+
+
+ ); +}; + +export default Navigation; diff --git a/src/components/Navigation/NavigationItem.tsx b/src/components/Navigation/NavigationItem.tsx new file mode 100644 index 0000000..1f745f6 --- /dev/null +++ b/src/components/Navigation/NavigationItem.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { + NavItem, + NavItemLink, + NavItemTitle +} from './styled'; +import Icon from '../Icon'; + +export type NavigationItemProps = { + label: string, + iconType: string, + url: string +}; + +const NavigationItem = ({ + label, + iconType, + url +}: NavigationItemProps ) => ( + + + + { label } + + + +); + +export default NavigationItem; diff --git a/src/components/Navigation/index.tsx b/src/components/Navigation/index.tsx new file mode 100644 index 0000000..7bc6dc0 --- /dev/null +++ b/src/components/Navigation/index.tsx @@ -0,0 +1 @@ +export { default } from './Navigation'; diff --git a/src/components/Navigation/styled.ts b/src/components/Navigation/styled.ts new file mode 100644 index 0000000..8d92238 --- /dev/null +++ b/src/components/Navigation/styled.ts @@ -0,0 +1,128 @@ +import styled from "styled-components"; + +interface NavProps { + readonly open: boolean; +} + +export const NavWrapper = styled.div` + @media(max-width: 767px) { + height: 100%; + max-width: 300px; + position: fixed; + width: 80vw; + + &:before { + background-color: #03021e; + content: ''; + display: block; + height: 100%; + position: absolute; + right: ${props => props.open ? '0' : '100%' }; + transition: right 500ms; + width: 100%; + } + } + + @media(min-width: 768px) { + padding: 20px 0 0 60px; + } +`; + +export const NavButtonClose = styled.button` + background: transparent; + border: none; + cursor: pointer; + left: 20px; + position: absolute; + top: 30px; + z-index: 10; + + @media(min-width: 768px) { + display: none; + } +`; + +export const NavButton = styled.button` + align-items: center; + background: transparent; + border: none; + color: #eee; + cursor: pointer; + display: flex; + justify-content: left; + position: relative; +`; + +export const NavDesktopButton = styled(NavButton)` + @media(max-width: 767px) { + display: none; + } +`; + +export const NavMobileButton = styled(NavButton)` + margin: 100px 0 0; + padding: 0 20px; + width: 100%; + + @media(min-width: 768px) { + display: none; + } +`; + +export const NavTitle = styled.h3` + flex: 1 0 auto; + font-size: 1rem; + font-weight: 400; + margin: 0 0 0 10px; + padding: 0; + text-align: left; +`; + +export const NavItemList = styled.nav` + margin-top: 10px; + + @media(max-width: 767px) { + margin-left: ${props => props.open ? '0' : '-100%' }; + transition: margin-left 500ms; + width: 100%; + } + + @media(min-width: 768px) { + background-color: #03021e; + border-radius: 10px; + display: ${props => props.open ? 'block' : 'none' }; + overflow: hidden; + padding: 10px 0; + width: 200px; + } + + ul { + list-style: none; + margin: 0; + padding: 0; + } +`; + +export const NavItem = styled.li` + position: relative; +`; + +export const NavItemLink = styled.a` + align-items: center; + color: #95b3c1; + display: flex; + padding: 10px 20px 10px 25px; + text-align: left; + text-decoration: none; + transition: padding-left 500ms; + + &:hover { + background-color: #18223a; + padding-left: 30px; + } +`; + +export const NavItemTitle = styled.span` + flex: 1 0 auto; + margin: 0 0 0 20px; +`;