Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions notes.txt
Original file line number Diff line number Diff line change
@@ -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!
26 changes: 16 additions & 10 deletions src/App/App.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="App">
<DeleteMe>
Implement the menu instead of me
<span role="img" aria-label="unicorn icon">
🦄
</span>
</DeleteMe>
<GlobalStyle bgImage={bgImage} />
<Navigation items={navItems} title={`Hjem`} />
</div>
);
}
};

export default App;
36 changes: 28 additions & 8 deletions src/App/styled.ts
Original file line number Diff line number Diff line change
@@ -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<GlobalStyleProps>`
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;
}
`;
52 changes: 52 additions & 0 deletions src/components/Icon/Icon.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<IconWrap onClick={handleClick} large={large || false}>
<IconImg
src={require(`../../assets/icons/${type.toUpperCase()}.svg`)}
alt=""
rotate={rotate || 0}
fill={fill || ''}
/>
</IconWrap>
);
};

export default Icon;
1 change: 1 addition & 0 deletions src/components/Icon/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Icon';
41 changes: 41 additions & 0 deletions src/components/Icon/styled.ts
Original file line number Diff line number Diff line change
@@ -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<IconWrapperProps>`
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<IconImgProps>`
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;
`;
67 changes: 67 additions & 0 deletions src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -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<NavigationItemProps>,
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 => (<NavigationItem key={item.url} {...item} />));

const handleMenuClick = () => {
setIsOpen(!isOpen);
};

return (
<NavWrapper open={isOpen}>
{ isOpen && (
<NavButtonClose onClick={handleMenuClick}>
<Icon type="CLOSE" fill="white" />
</NavButtonClose>
)}
<NavDesktopButton onClick={handleMenuClick}>
<Icon type={iconTypeHome} large />
<NavTitle>{ title }</NavTitle>
<Icon type="ARROW_DOWN" rotate={isOpen ? 180 : 0} fill="white" />
</NavDesktopButton>
<NavMobileButton onClick={handleMenuClick}>
{ isOpen ? (
<React.Fragment>
<Icon type={iconTypeHome} large />
<NavTitle>{ title }</NavTitle>
<Icon type="ARROW_DOWN" rotate={270} fill="white" />
</React.Fragment>
) : (
<Icon type={iconTypeHomeMobile} large />
)}
</NavMobileButton>
<NavItemList open={isOpen}>
<ul>{ navItems }</ul>
</NavItemList>
</NavWrapper>
);
};

export default Navigation;
29 changes: 29 additions & 0 deletions src/components/Navigation/NavigationItem.tsx
Original file line number Diff line number Diff line change
@@ -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 ) => (
<NavItem>
<NavItemLink href={url}>
<Icon type={iconType} fill="teal" />
<NavItemTitle>{ label }</NavItemTitle>
<Icon type="ARROW_DOWN" rotate={270} fill="white" bp={'mobile'} />
</NavItemLink>
</NavItem>
);

export default NavigationItem;
1 change: 1 addition & 0 deletions src/components/Navigation/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './Navigation';
Loading