Merge pull request #57 from devandres-tech/storybook-init

Storybook init
This commit is contained in:
Andres Alcocer
2022-12-17 14:11:37 -05:00
committed by GitHub
27 changed files with 29219 additions and 1927 deletions

13
.gitignore vendored
View File

@@ -4,6 +4,9 @@ node_modules
# Build files # Build files
dist/ dist/
# tests
coverage/
# Environment varialbes # Environment varialbes
.env .env
@@ -18,3 +21,13 @@ npm-debug.log*
.firebase.json .firebase.json
.vercel .vercel
# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

1
.npmrc Normal file
View File

@@ -0,0 +1 @@
legacy-peer-deps=true

35
.storybook/main.js Normal file
View File

@@ -0,0 +1,35 @@
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const custom = require('../webpack.config.js')()
module.exports = {
stories: ['../src/**/*.stories.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/preset-create-react-app',
],
framework: '@storybook/react',
core: {
builder: '@storybook/builder-webpack5',
},
webpackFinal: (config) => {
return {
...config,
module: {
...config.module,
rules: custom.module.rules, // babel, sass, fonts and images loaders
},
resolve: {
...config.resolve,
...custom.resolve, // custom imports resolvers
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
...config.plugins,
],
}
},
}

22
.storybook/preview.js Normal file
View File

@@ -0,0 +1,22 @@
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
backgrounds: {
default: 'dark',
values: [
{
name: 'dark',
value: '#141414',
},
{
name: 'light',
value: '#fff',
},
],
},
}

View File

@@ -14,7 +14,9 @@ This project is a simplified front end clone of Netflix. It was created with Rea
- [ ] Create user account page - [ ] Create user account page
- [x] Migrate to Typescript - [x] Migrate to Typescript
- [ ] Implement dynamic code splitting with dynamic imports - [ ] Implement dynamic code splitting with dynamic imports
- [ ] Setup storybook - [x] Setup storybook
- [ ] Implement internationalization with react-i18next
- [ ] Exclude storybook files from test coverage
### Tools used ### Tools used

30387
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,12 +8,16 @@
"build:prod": "webpack --mode development", "build:prod": "webpack --mode development",
"start:dev": "webpack serve --mode development --config webpack.config.js --open", "start:dev": "webpack serve --mode development --config webpack.config.js --open",
"start:prod": "webpack serve --mode production --open", "start:prod": "webpack serve --mode production --open",
"lint": "eslint --fix . && echo 'Lint complete.'" "lint": "eslint --fix . && echo 'Lint complete.'",
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook",
"test": "react-scripts test"
}, },
"author": "Andres Alcocer", "author": "Andres Alcocer",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@reduxjs/toolkit": "^1.9.0", "@reduxjs/toolkit": "^1.9.0",
"@testing-library/jest-dom": "^5.16.5",
"@types/jest": "^29.2.3", "@types/jest": "^29.2.3",
"@types/node": "^18.11.9", "@types/node": "^18.11.9",
"@types/react": "^18.0.25", "@types/react": "^18.0.25",
@@ -45,7 +49,19 @@
"@babel/polyfill": "^7.0.0-beta.51", "@babel/polyfill": "^7.0.0-beta.51",
"@babel/preset-env": "^7.20.2", "@babel/preset-env": "^7.20.2",
"@babel/preset-react": "^7.18.6", "@babel/preset-react": "^7.18.6",
"@storybook/addon-actions": "^6.5.13",
"@storybook/addon-essentials": "^6.5.13",
"@storybook/addon-interactions": "^6.5.13",
"@storybook/addon-links": "^6.5.13",
"@storybook/builder-webpack5": "^6.5.13",
"@storybook/manager-webpack5": "^6.5.13",
"@storybook/node-logger": "^6.5.13",
"@storybook/preset-create-react-app": "^4.1.2",
"@storybook/react": "^6.5.13",
"@storybook/testing-library": "^0.0.13",
"@testing-library/react": "^13.4.0",
"babel-loader": "^9.1.0", "babel-loader": "^9.1.0",
"babel-plugin-named-exports-order": "^0.0.2",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^11.0.0", "copy-webpack-plugin": "^11.0.0",
"css-loader": "^6.7.2", "css-loader": "^6.7.2",
@@ -62,7 +78,7 @@
"html-loader": "^4.2.0", "html-loader": "^4.2.0",
"html-webpack-plugin": "^5.5.0", "html-webpack-plugin": "^5.5.0",
"image-webpack-loader": "^8.1.0", "image-webpack-loader": "^8.1.0",
"mini-css-extract-plugin": "^2.7.0", "mini-css-extract-plugin": "^1.3.6",
"node-sass": "^8.0.0", "node-sass": "^8.0.0",
"prettier": "^2.8.0", "prettier": "^2.8.0",
"sass-loader": "^13.2.0", "sass-loader": "^13.2.0",
@@ -75,5 +91,17 @@
"webpack": "^5.75.0", "webpack": "^5.75.0",
"webpack-cli": "^5.0.0", "webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1" "webpack-dev-server": "^4.11.1"
},
"eslintConfig": {
"overrides": [
{
"files": [
"**/*.stories.*"
],
"rules": {
"import/no-anonymous-default-export": "off"
}
}
]
} }
} }

View File

@@ -0,0 +1,42 @@
import './button.scss'
export enum ButtonType {
Primary,
Secondary,
IconRound,
IconRoundSecondary,
Alternate,
}
interface IButton {
label?: string
onClick?: () => void
buttonType: ButtonType
Icon?: JSX.Element
}
const Button = ({ label, onClick, buttonType, Icon }: IButton) => {
const getIconClassName = (): '' | ' with-icon' => {
return Icon ? ' with-icon' : ''
}
const getLabelClassName = (): '' | ' with-label' => {
return label ? ' with-label' : ''
}
const getPrimaryClassName = (): string => {
return ButtonType[buttonType ? buttonType : ButtonType.Primary]
}
return (
<button
className={`n-button${getIconClassName()}${getLabelClassName()} ${getPrimaryClassName()}`}
onClick={onClick}
>
{Icon && Icon}
{label && <span>{label}</span>}
</button>
)
}
export default Button

View File

@@ -0,0 +1,73 @@
import React from 'react'
import { ComponentStory, ComponentMeta } from '@storybook/react'
import Button from '../Button'
import { ButtonType } from '../Button'
import PlayLogo from '../../../static/images/play-button.svg'
export default {
title: 'Button',
component: Button,
parameters: {
parameters: {
backgrounds: {
default: '#141414',
values: [
{ name: 'dark', value: '#141414' },
{ name: 'light', value: '#fff' },
],
},
},
docs: {
description: {
component: 'Primary and secondary styles for all buttons',
},
},
},
} as ComponentMeta<typeof Button>
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />
export const Primary = Template.bind({})
Primary.args = {
label: 'Primary',
buttonType: ButtonType.Primary,
}
export const Secondary = Template.bind({})
Secondary.args = {
label: 'Secondary',
buttonType: ButtonType.Secondary,
}
export const Alternate = Template.bind({})
Alternate.args = {
label: 'Alternate',
buttonType: ButtonType.Alternate,
}
export const IconRound = Template.bind({})
IconRound.args = {
Icon: <PlayLogo />,
buttonType: ButtonType.IconRound,
}
export const IconRoundSecondary = Template.bind({})
IconRoundSecondary.args = {
Icon: <PlayLogo />,
buttonType: ButtonType.IconRoundSecondary,
}
export const PrimaryWithIcon = Template.bind({})
PrimaryWithIcon.args = {
label: 'Primary Ic',
buttonType: ButtonType.Primary,
Icon: <PlayLogo />,
}
export const SecondaryWithIcon = Template.bind({})
SecondaryWithIcon.args = {
label: 'Secondary Ic',
buttonType: ButtonType.Secondary,
Icon: <PlayLogo />,
}

View File

@@ -0,0 +1,51 @@
import {
Primary,
Secondary,
IconRound,
PrimaryWithIcon,
SecondaryWithIcon,
Alternate,
IconRoundSecondary,
} from './Button.stories'
import { render } from '@testing-library/react'
describe('Button constructor', (): void => {
test('should render primary button', (): void => {
const { container } = render(<Primary {...Primary.args} />)
expect(container).toMatchSnapshot()
})
test('should render primary button with icon', (): void => {
const { container } = render(<PrimaryWithIcon {...PrimaryWithIcon.args} />)
expect(container).toMatchSnapshot()
})
test('should render secondary button', (): void => {
const { container } = render(<Secondary {...Secondary.args} />)
expect(container).toMatchSnapshot()
})
test('should render secondary button with icon', (): void => {
const { container } = render(
<SecondaryWithIcon {...SecondaryWithIcon.args} />
)
expect(container).toMatchSnapshot()
})
test('should render icon round button', (): void => {
const { container } = render(<IconRound {...IconRound.args} />)
expect(container).toMatchSnapshot()
})
test('should render secondary icon round button', (): void => {
const { container } = render(
<IconRoundSecondary {...IconRoundSecondary.args} />
)
expect(container).toMatchSnapshot()
})
test('should render alternate button', (): void => {
const { container } = render(<Alternate {...Alternate.args} />)
expect(container).toMatchSnapshot()
})
})

View File

@@ -0,0 +1,83 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Button constructor should render alternate button 1`] = `
<div>
<button
class="n-button with-label Alternate"
>
<span>
Alternate
</span>
</button>
</div>
`;
exports[`Button constructor should render icon round button 1`] = `
<div>
<button
class="n-button with-icon IconRound"
>
<play-button.svg />
</button>
</div>
`;
exports[`Button constructor should render primary button 1`] = `
<div>
<button
class="n-button with-label Primary"
>
<span>
Primary
</span>
</button>
</div>
`;
exports[`Button constructor should render primary button with icon 1`] = `
<div>
<button
class="n-button with-icon with-label Primary"
>
<play-button.svg />
<span>
Primary Ic
</span>
</button>
</div>
`;
exports[`Button constructor should render secondary button 1`] = `
<div>
<button
class="n-button with-label Secondary"
>
<span>
Secondary
</span>
</button>
</div>
`;
exports[`Button constructor should render secondary button with icon 1`] = `
<div>
<button
class="n-button with-icon with-label Secondary"
>
<play-button.svg />
<span>
Secondary Ic
</span>
</button>
</div>
`;
exports[`Button constructor should render secondary icon round button 1`] = `
<div>
<button
class="n-button with-icon IconRoundSecondary"
>
<play-button.svg />
</button>
</div>
`;

View File

@@ -0,0 +1,167 @@
@import '../../static/sass/abstracts/functions';
.n-button {
cursor: pointer;
outline: none;
appearance: none;
border: 0;
border-radius: 4px;
padding: 0.8rem;
opacity: 1;
user-select: none;
will-change: background-color, color;
word-break: break-word;
white-space: nowrap;
font-size: 17px;
font-weight: 500;
line-height: 2.4rem;
font-family: 'Netflix Sans', 'Helvetica Neue', 'Segoe UI', 'Roboto', 'Ubuntu',
'sans-serif';
@include responsive(phone) {
top: 24rem;
}
&.with-icon {
display: flex;
align-items: center;
& > * {
height: 24px;
fill: #fff;
}
}
&.with-label {
padding-left: 2.4rem;
padding-right: 2.8rem;
& > span {
margin-left: 1rem;
font-weight: 500;
}
}
&.Primary {
color: #000;
background-color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
& > * {
fill: #000;
}
&:not(:disabled):hover {
background-color: rgba(255, 255, 255, 0.75);
}
&:not(:disabled):active {
background-color: rgba(255, 255, 255, 0.5);
color: rgba(0, 0, 0, 0.7);
}
&:not(:disabled):focus::before {
box-sizing: content-box;
content: '';
display: block;
height: 100%;
width: 100%;
border: 2px solid white;
border-radius: 8px;
padding: 2px;
position: absolute;
left: -4px;
top: -4px;
}
}
&.Secondary {
background-color: rgba(109, 109, 110, 0.7);
color: #fff;
&:not(:disabled):hover {
background-color: rgba(109, 109, 110, 0.4);
}
&:not(:disabled):active {
background-color: rgba(109, 109, 110, 0.4);
color: rgba(255, 255, 255, 0.7);
}
&:not(:disabled):focus::before {
box-sizing: content-box;
content: '';
display: block;
height: 100%;
width: 100%;
border: 2px solid white;
border-radius: 8px;
padding: 2px;
position: absolute;
left: -4px;
top: -4px;
}
}
&.Alternate {
background-color: #d22f27;
color: #fff;
}
&.IconRound,
&.IconRoundSecondary {
border-radius: 50%;
display: flex;
height: 42px;
width: 42px;
border: 2px solid rgba(255, 255, 255, 0.7);
color: white;
background-color: rgba(42, 42, 42, 0.6);
border-color: hsla(0, 0%, 100%, 0.5);
border-width: 2px;
& > * {
fill: #fff;
height: 100%;
width: 100%;
}
&:not(.with-label):hover {
background-color: #2a2a2a;
border-color: #fff;
border-width: 2px;
}
&:not(.with-label):focus {
background-color: #2a2a2a;
border: 2px solid white;
color: white;
}
&:not(:disabled):focus::before {
box-sizing: content-box;
content: '';
display: block;
height: 100%;
width: 100%;
border: 2px solid white;
border-radius: 8px;
padding: 2px;
position: absolute;
left: -4px;
top: -4px;
border-radius: 50%;
}
}
&.IconRoundSecondary {
background-color: #fff;
& > * {
fill: #000;
}
&:not(.with-label):hover {
background-color: #e3e3e3;
}
}
}

View File

@@ -8,7 +8,6 @@ const footer = () => (
className='footer__copyright--link' className='footer__copyright--link'
href='https://github.com/devandres-tech' href='https://github.com/devandres-tech'
> >
{' '}
Dev Andres Dev Andres
</a> </a>
</div> </div>

View File

@@ -1,7 +1,9 @@
import React, { useState } from 'react' import React, { useState } from 'react'
import PlayLogo from '../static/images/play-button.svg' import PlayLogo from '../static/images/play-button.svg'
import AddLogo from '../static/images/add.svg' import { ButtonType } from './Button/Button'
import Button from './Button/Button'
import MoreInfo from '../static/images/more-info.svg'
import MuteIcon from '../static/images/mute.svg' import MuteIcon from '../static/images/mute.svg'
import UnmuteIcon from '../static/images/unmute.svg' import UnmuteIcon from '../static/images/unmute.svg'
import ReactPlayer from 'react-player' import ReactPlayer from 'react-player'
@@ -27,17 +29,18 @@ const Header = ({ name, overview }: IHeader) => {
url='https://vimeo.com/384025132' url='https://vimeo.com/384025132'
/> />
<h1 className='header__container-heading'>{name}</h1> <h1 className='header__container-heading'>{name}</h1>
<button <Button
Icon={<PlayLogo />}
buttonType={ButtonType.Primary}
onClick={() => alert('not a movie!')} onClick={() => alert('not a movie!')}
className='header__container-btnPlay' label={'Play'}
> />
<PlayLogo className='header__container-btnMyList-play' /> <Button
Play Icon={<MoreInfo />}
</button> buttonType={ButtonType.Secondary}
<button className='header__container-btnMyList'> label={'More Info'}
<AddLogo className='header__container-btnMyList-add' /> />
My List
</button>
{isMuted ? ( {isMuted ? (
<MuteIcon <MuteIcon
onClick={() => setIsMuted(false)} onClick={() => setIsMuted(false)}

View File

@@ -3,8 +3,9 @@ import { NavLink } from 'react-router-dom'
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useScroll } from '../hooks/useScroll' import { useScroll } from '../hooks/useScroll'
import SearchLogo from '../static/images/search-icon.svg' import Search from '../static/images/search-icon.svg'
import NetflixLogo from '../static/images/Netflix_Logo_RGB.png' import NetflixLogo from '../static/images/Netflix_Logo_RGB.png'
import AddLogo from '../static/images/add.svg'
import BellLogo from '../static/images/bell-logo.svg' import BellLogo from '../static/images/bell-logo.svg'
import DropdownArrow from '../static/images/drop-down-arrow.svg' import DropdownArrow from '../static/images/drop-down-arrow.svg'
import DropdownContent from './DropdownContent' import DropdownContent from './DropdownContent'
@@ -52,9 +53,8 @@ const Navbar = () => {
Recently Added Recently Added
</div> </div>
<div className='navigation__container-link pseudo-link'>My List</div> <div className='navigation__container-link pseudo-link'>My List</div>
<div className='navigation__container--left'> <div className='navigation__container--left'>
<SearchLogo className='logo' /> <Search className='logo' />
<input <input
ref={searchInput} ref={searchInput}
value={userInput} value={userInput}
@@ -64,7 +64,6 @@ const Navbar = () => {
placeholder='Title, genres, people' placeholder='Title, genres, people'
/> />
</div> </div>
<div className='navigation__container-link pseudo-link'>KIDS</div> <div className='navigation__container-link pseudo-link'>KIDS</div>
<div className='navigation__container-link pseudo-link'>DVD</div> <div className='navigation__container-link pseudo-link'>DVD</div>
<BellLogo className='navigation__container--bellLogo' /> <BellLogo className='navigation__container--bellLogo' />

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="Hawkins-Icon Hawkins-Icon-Standard"><path fill-rule="evenodd" clip-rule="evenodd" d="M11 2V11H2V13H11V22H13V13H22V11H13V2H11Z" fill="currentColor"></path></svg>

After

Width:  |  Height:  |  Size: 263 B

View File

@@ -0,0 +1 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="Hawkins-Icon Hawkins-Icon-Standard"><path fill-rule="evenodd" clip-rule="evenodd" d="M12 3C7.02944 3 3 7.02944 3 12C3 16.9706 7.02944 21 12 21C16.9706 21 21 16.9706 21 12C21 7.02944 16.9706 3 12 3ZM1 12C1 5.92487 5.92487 1 12 1C18.0751 1 23 5.92487 23 12C23 18.0751 18.0751 23 12 23C5.92487 23 1 18.0751 1 12ZM13 10V18H11V10H13ZM12 8.5C12.8284 8.5 13.5 7.82843 13.5 7C13.5 6.17157 12.8284 5.5 12 5.5C11.1716 5.5 10.5 6.17157 10.5 7C10.5 7.82843 11.1716 8.5 12 8.5Z" fill="currentColor"></path></svg>

After

Width:  |  Height:  |  Size: 602 B

View File

@@ -1,38 +1 @@
<?xml version="1.0" encoding="iso-8859-1"?> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="Hawkins-Icon Hawkins-Icon-Standard"><path d="M4 2.69127C4 1.93067 4.81547 1.44851 5.48192 1.81506L22.4069 11.1238C23.0977 11.5037 23.0977 12.4963 22.4069 12.8762L5.48192 22.1849C4.81546 22.5515 4 22.0693 4 21.3087V2.69127Z" fill="currentColor"></path></svg>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 41.999 41.999" style="enable-background:new 0 0 41.999 41.999;" xml:space="preserve">
<path d="M36.068,20.176l-29-20C6.761-0.035,6.363-0.057,6.035,0.114C5.706,0.287,5.5,0.627,5.5,0.999v40
c0,0.372,0.206,0.713,0.535,0.886c0.146,0.076,0.306,0.114,0.465,0.114c0.199,0,0.397-0.06,0.568-0.177l29-20
c0.271-0.187,0.432-0.494,0.432-0.823S36.338,20.363,36.068,20.176z"/>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 824 B

After

Width:  |  Height:  |  Size: 361 B

View File

@@ -1,12 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<svg width="251px" height="251px" viewBox="0 0 251 251" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="search-icon"><path fill-rule="evenodd" clip-rule="evenodd" d="M14 11C14 14.3137 11.3137 17 8 17C4.68629 17 2 14.3137 2 11C2 7.68629 4.68629 5 8 5C11.3137 5 14 7.68629 14 11ZM14.3623 15.8506C12.9006 17.7649 10.5945 19 8 19C3.58172 19 0 15.4183 0 11C0 6.58172 3.58172 3 8 3C12.4183 3 16 6.58172 16 11C16 12.1076 15.7749 13.1626 15.368 14.1218L24.0022 19.1352L22.9979 20.8648L14.3623 15.8506Z" fill="currentColor"></path></svg>
<!-- Generator: Sketch 49.3 (51167) - http://www.bohemiancoding.com/sketch -->
<title>Slice 1</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="musica-searcher" fill="#FFFFFF" fill-rule="nonzero">
<path d="M244.186,214.604 L189.807,160.226 C189.518,159.937 189.179,159.735 188.877,159.466 C199.577,143.235 205.822,123.806 205.822,102.912 C205.822,46.075 159.747,0 102.911,0 C46.075,0 0,46.075 0,102.911 C0,159.746 46.074,205.822 102.91,205.822 C123.805,205.822 143.233,199.577 159.464,188.877 C159.733,189.178 159.934,189.517 160.223,189.806 L214.603,244.186 C222.772,252.354 236.016,252.354 244.186,244.186 C252.354,236.017 252.354,222.773 244.186,214.604 Z M102.911,170.146 C65.777,170.146 35.675,140.044 35.675,102.911 C35.675,65.777 65.778,35.675 102.911,35.675 C140.043,35.675 170.146,65.778 170.146,102.911 C170.146,140.044 140.043,170.146 102.911,170.146 Z" id="Shape"></path>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 566 B

View File

@@ -123,9 +123,15 @@
border-collapse: collapse; border-collapse: collapse;
border-spacing: 0; border-spacing: 0;
} }
// prettier-ignore
@font-face {
font-family: 'Netflix Sans';
src: url('../../../fonts/NetflixSans_W_Rg.woff2') format('woff2'), url('../../../fonts/NetflixSans_W_Md.woff2') format('woff2'), url('../../../fonts/NetflixSans_W_Bd.woff2') format('woff2');
}
body { body {
font-family: 'Hind', sans-serif; font-family: 'Netflix Sans', 'Helvetica Neue', 'Segoe UI', 'Roboto', 'Ubuntu',
'sans-serif';
box-sizing: border-box; box-sizing: border-box;
background-color: $color-background; background-color: $color-background;
} }
@@ -133,6 +139,7 @@ body {
html { html {
// this defines what 1rem is --> font root size // this defines what 1rem is --> font root size
font-size: 62.5%; // 10/16, 1rem = 10px; font-size: 62.5%; // 10/16, 1rem = 10px;
// font-weight: bold;
@include responsive(tab_port) { @include responsive(tab_port) {
font-size: 50%; font-size: 50%;

View File

@@ -3,6 +3,28 @@
position: relative; position: relative;
padding-top: 56.25%; padding-top: 56.25%;
& > button.Primary,
button.Secondary {
top: 40rem;
position: absolute;
@include responsive(phone) {
top: 24rem;
}
}
& > button.Primary {
left: 4rem;
}
& > button.Secondary {
left: 17rem;
@include responsive(tab_port) {
left: 18.5rem;
}
}
@include responsive(phone) { @include responsive(phone) {
padding-top: 0; padding-top: 0;
height: 32rem; height: 32rem;
@@ -34,64 +56,6 @@
} }
} }
&-btnPlay,
&-btnMyList {
top: 40rem;
cursor: pointer;
font-size: 1.6rem;
color: #fff;
outline: none;
border: none;
font-weight: 700;
border-radius: 5px;
padding-left: 3.5rem;
padding-right: 3.5rem;
margin-right: 1rem;
padding-top: 1rem;
background-color: rgba(112, 111, 111, 0.5);
padding-bottom: 1rem;
@include responsive(phone) {
top: 24rem;
}
&-add {
width: 15px;
height: 15px;
fill: #fff;
margin-right: 1rem;
}
&-play {
width: 15px;
height: 15px;
fill: #fff;
margin-right: 1rem;
}
}
&-btnPlay {
color: #000;
background-color: #e6e6e6;
transition: all 0.2s;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
& > * {
fill: #000;
}
left: 4rem;
position: absolute;
}
&-btnMyList {
left: 18.5rem;
position: absolute;
&:hover {
background-color: rgb(37, 37, 37);
}
}
&-btnVolume { &-btnVolume {
position: absolute; position: absolute;
height: 3rem; height: 3rem;

View File

@@ -35,7 +35,6 @@
&--bellLogo { &--bellLogo {
cursor: pointer; cursor: pointer;
height: 2.2rem; height: 2.2rem;
fill: red;
width: 2.2rem; width: 2.2rem;
padding-right: 2.5rem; padding-right: 2.5rem;
@@ -109,13 +108,18 @@
} }
&-link { &-link {
font-weight: 500;
font-size: 1.4rem; font-size: 1.4rem;
color: rgb(221, 221, 221); color: rgb(221, 221, 221);
text-decoration: none; text-decoration: none;
margin-right: 2rem; margin-right: 2rem;
transition: all 0.2s; transition: all 0.2s;
@media screen and (min-width: 1200px) {
.pinning-header .main-header {
font-size: 14px;
}
}
&:last-child { &:last-child {
padding-right: 2.6rem; padding-right: 2.6rem;
} }
@@ -162,8 +166,9 @@
} }
.logo { .logo {
width: 1.8rem; position: relative;
height: 1.8rem; left: 10px;
bottom: 4px;
transform: translateX(2.4rem) translateY(1rem); transform: translateX(2.4rem) translateY(1rem);
cursor: pointer; cursor: pointer;
} }
@@ -171,7 +176,6 @@
.dropdownContent { .dropdownContent {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
// align-items: center;
opacity: 0; opacity: 0;
color: #fff; color: #fff;
@@ -196,7 +200,6 @@
&:hover { &:hover {
border-bottom: 1px solid #fff; border-bottom: 1px solid #fff;
// border-width: 2%;
} }
} }

View File

@@ -4,7 +4,7 @@
"noImplicitAny": true, "noImplicitAny": true,
"module": "es6", "module": "es6",
"target": "es5", "target": "es5",
"jsx": "react", "jsx": "react-jsx",
"sourceMap": true, "sourceMap": true,
"allowJs": true, "allowJs": true,
"moduleResolution": "node", "moduleResolution": "node",

View File

@@ -2,14 +2,13 @@ const HtmlWebPackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin') const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const dotenv = require('dotenv') const dotenv = require('dotenv')
const webpack = require('webpack') const webpack = require('webpack')
const path = require('path')
const prod = const prod =
(process.env.NODE_ENV ? process.env.NODE_ENV : '').trim() === 'production' (process.env.NODE_ENV ? process.env.NODE_ENV : '').trim() === 'production'
const path = require('path')
module.exports = () => { module.exports = () => {
dotenv.config({ dotenv.config({
@@ -21,10 +20,11 @@ module.exports = () => {
output: { output: {
filename: '[name].[contenthash].js', filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'), path: path.resolve(__dirname, 'dist'),
assetModuleFilename: 'assets/[name][ext]',
clean: true, clean: true,
}, },
resolve: { resolve: {
extensions: ['.tsx', '.ts', '.js'], extensions: ['.js', '.ts', '.tsx'],
}, },
optimization: { optimization: {
runtimeChunk: 'single', runtimeChunk: 'single',
@@ -67,7 +67,15 @@ module.exports = () => {
patterns: [ patterns: [
{ {
from: 'src/static/images', from: 'src/static/images',
to: 'static/images', to: 'resources/',
},
],
}),
new CopyWebpackPlugin({
patterns: [
{
from: 'src/fonts',
to: 'fonts/',
}, },
], ],
}), }),
@@ -93,24 +101,17 @@ module.exports = () => {
{ {
test: /\.svg$/, test: /\.svg$/,
exclude: /node_modules/, exclude: /node_modules/,
use: { use: ['@svgr/webpack'],
loader: 'svg-react-loader',
},
}, },
{ {
test: /\.css$/i, test: /\.(sass|less|css|scss)$/,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
{
test: /\.scss$/,
use: [ use: [
{ // fallback to style-loader in development
loader: MiniCssExtractPlugin.loader, process.env.NODE_ENV !== 'production'
options: { ? 'style-loader'
publicPath: '../', : MiniCssExtractPlugin.loader,
},
},
'css-loader', 'css-loader',
'resolve-url-loader',
'sass-loader', 'sass-loader',
], ],
}, },
@@ -127,6 +128,13 @@ module.exports = () => {
}, },
], ],
}, },
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: 'asset/resource',
generator: {
filename: './fonts/[name][ext]',
},
},
], ],
}, },
} }