diff --git a/src/components/DrumMachine/DrumMachine.jsx b/src/components/DrumMachine/DrumMachine.jsx index eea40a0..3e7bdb7 100644 --- a/src/components/DrumMachine/DrumMachine.jsx +++ b/src/components/DrumMachine/DrumMachine.jsx @@ -1,7 +1,30 @@ +'use client'; import React from 'react'; +import useSound from 'use-sound'; + +import styles from './DrumMachine.module.css'; + +const SOUND_SRC = '/909-drums.mp3'; function DrumMachine() { - return
; + const [play] = useSound(SOUND_SRC, { + sprite: { + kick: [0, 350], + hihat: [374, 160], + snare: [666, 290], + cowbell: [968, 200], + }, + soundEnabled: true, + }); + + return ( +
+ + + + +
+ ); } export default DrumMachine; diff --git a/src/components/DrumMachine/DrumMachine.module.css b/src/components/DrumMachine/DrumMachine.module.css new file mode 100644 index 0000000..e536138 --- /dev/null +++ b/src/components/DrumMachine/DrumMachine.module.css @@ -0,0 +1,28 @@ +.wrapper { + display: flex; + gap: 8px; +} + +.wrapper button { + background: hsl(234deg 54% 53%); + color: white; + font-size: 1.5rem; + font-weight: 900; + flex: 1; + padding-block: 8px; + border: 4px solid; + border-top-color: hsl(234deg 54% 72%); + border-left-color: hsl(234deg 54% 65%); + border-right-color: hsl(234deg 54% 60%); + border-bottom-color: hsl(234deg 54% 30%); + border-radius: 2px; + cursor: pointer; +} + +.wrapper button:active { + background: hsl(234deg 54% 45%); + border-top-color: hsl(234deg 54% 30%); + border-left-color: hsl(234deg 54% 40%); + border-right-color: hsl(234deg 54% 45%); + border-bottom-color: hsl(234deg 54% 60%); +} diff --git a/src/components/Header/Header.jsx b/src/components/Header/Header.jsx index 6731459..1dba373 100644 --- a/src/components/Header/Header.jsx +++ b/src/components/Header/Header.jsx @@ -1,7 +1,36 @@ +'use client'; import React from 'react'; +import { Volume2, VolumeX } from 'react-feather'; +import Link from 'next/link'; + +import VisuallyHidden from '../VisuallyHidden'; +import MaxWidthWrapper from '../MaxWidthWrapper'; +import styles from './Header.module.css'; function Header() { - return
; + const id = React.useId(); + + // TODO: Global state? + const soundEnabled = true; + + return ( +
+ + Kool Website + + + +
+ ); } export default Header; diff --git a/src/components/Header/Header.module.css b/src/components/Header/Header.module.css new file mode 100644 index 0000000..fcbe5a0 --- /dev/null +++ b/src/components/Header/Header.module.css @@ -0,0 +1,47 @@ +.wrapper { + padding: 16px; + margin-bottom: 6rem; + background: hsl(234deg 70% 85% / 0.9); + backdrop-filter: blur(4px); + border-bottom: 8px dashed hsl(234deg 54% 53%); + outline: 4px solid hsl(234deg 70% 85% / 0.9); + /* prettier-ignore */ + box-shadow: + 0px 2px 4px hsl(234deg 40% 30% / 0.2), + 0px 4px 8px hsl(234deg 40% 30% / 0.2), + 0px 8px 16px hsl(234deg 40% 30% / 0.2), + 0px 16px 32px hsl(234deg 40% 30% / 0.2); +} + +.innerWrapper { + display: flex; + justify-content: space-between; + align-items: center; +} + +.innerWrapper a { + font-size: 1.5rem; + color: inherit; + text-decoration: none; + font-weight: bold; +} + +.innerWrapper button { + display: flex; + justify-content: center; + align-items: center; + width: 48px; + height: 48px; + border: 3px solid hsl(0deg 0% 85%); + border-top-color: hsl(0deg 0% 100%); + border-bottom-color: hsl(0deg 0% 70%); + background: hsl(0deg 0% 93%); +} + +.innerWrapper button:active { + border-top-color: hsl(0deg 0% 60%); + border-left-color: hsl(0deg 0% 75%); + border-right-color: hsl(0deg 0% 75%); + border-bottom-color: hsl(0deg 0% 92%); + background: hsl(0deg 0% 85%); +} diff --git a/src/components/MaxWidthWrapper/MaxWidthWrapper.jsx b/src/components/MaxWidthWrapper/MaxWidthWrapper.jsx index 620a063..f3d3f9f 100644 --- a/src/components/MaxWidthWrapper/MaxWidthWrapper.jsx +++ b/src/components/MaxWidthWrapper/MaxWidthWrapper.jsx @@ -1,7 +1,17 @@ import React from 'react'; +import styles from './MaxWidthWrapper.module.css'; -function MaxWidthWrapper() { - return
; +function MaxWidthWrapper({ + children, + as: Tag = 'div', + className = '', + ...delegated +}) { + return ( + + {children} + + ); } export default MaxWidthWrapper; diff --git a/src/components/MaxWidthWrapper/MaxWidthWrapper.module.css b/src/components/MaxWidthWrapper/MaxWidthWrapper.module.css new file mode 100644 index 0000000..a08e97d --- /dev/null +++ b/src/components/MaxWidthWrapper/MaxWidthWrapper.module.css @@ -0,0 +1,5 @@ +.wrapper { + max-width: 700px; + margin-inline: auto; + padding-inline: 16px; +} diff --git a/src/components/VisuallyHidden/VisuallyHidden.jsx b/src/components/VisuallyHidden/VisuallyHidden.jsx index 8c2d072..cc0b70d 100644 --- a/src/components/VisuallyHidden/VisuallyHidden.jsx +++ b/src/components/VisuallyHidden/VisuallyHidden.jsx @@ -1,7 +1,24 @@ -import React from 'react'; +// These styles will make sure the component +// is not visible, but will still be announced +// by screen readers. +// +// Adding “display: none” would hide the +// element from ALL users, including those +// using screen-readers. +const hiddenStyles = { + display: 'inline-block', + position: 'absolute', + overflow: 'hidden', + clip: 'rect(0 0 0 0)', + height: 1, + width: 1, + margin: -1, + padding: 0, + border: 0, +}; -function VisuallyHidden() { - return
; -} +const VisuallyHidden = ({ children }) => { + return {children}; +}; export default VisuallyHidden;