$blue: #027aff;
$width: 500px;
$height: $width * 1.1;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #A3BFFA;
color: white;
display: flex;
justify-content: center;
padding-top: 2rem;
}
.rounded {
border-radius: 1rem;
}
.module-bg {
background-color: rgba(#fff, 0.4);
}
.card-wrapper {
background-color: rgba(#fff, 0.2);
width: $width;
min-height: $height;
display: grid;
grid-template-rows: 2fr 3fr;
row-gap: 1rem;
padding: 0.8rem;
.half-modules-wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap: 1rem;
.other-connections {
display: grid;
grid-template-rows: 1fr 1fr;
row-gap: 1rem;
.keyboard-and-airplay {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap: 1rem;
}
}
}
.full-width-modules {
display: grid;
grid-template-rows: 1fr 1fr 1fr;
row-gap: 1rem;
}
}
button {
background-color: rgba(#000, 0.1);
border: none;
border-radius: 500px;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
outline: none;
transition: 0.2s;
svg {
width: 20px;
color: black;
}
}
.connection-controls {
display: grid;
box-sizing: border-box;
grid-template-rows: 1fr 1fr 1fr;
padding: 10px 20px;
.module-wrapper {
display: flex;
align-items: center;
.module {
flex: 1;
display: grid;
grid-template-columns: 0.4fr 1fr;
.icon-wrapper {
button.active {
background-color: $blue;
svg {
color: white;
}
}
}
.content-wrapper {
display: flex;
align-items: center;
.content {
p {
color: black;
}
.name {
font-weight: 400;
padding-bottom: 5px;
}
.status {
font-size: 13px;
opacity: 0.6;
}
}
}
}
}
}
.do-not-disturb {
display: grid;
grid-template-columns: 0.5fr 1fr;
color: black;
padding: 10px 20px;
.button-wrapper {
display: flex;
align-items: center;
button.active {
background-color: #685bdb;
svg {
fill: white;
color: white;
}
}
button {
transition: 0.2s;
svg {
fill: black;
color: black;
}
}
}
.content {
display: flex;
align-items: center;
p {
line-height: 1.4;
font-size: 16px;
letter-spacing: 1px;
}
}
}
.keyboard-and-airplay {
.module {
text-align: center;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
color: black;
font-size: 13px;
line-height: 1.4;
p {
padding-top: 10px;
}
}
}
.slider {
padding: 20px;
color: black;
p {
padding-bottom: 15px;
}
.slider-inner {
display: flex;
padding: 0 0;
border: 1px solid rgba(#111, 0.2);
border: 50px;
.icon {
background-color: #fff;
padding: 0 10px;
padding-right: 25px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50px 0 0 50px;
color: rgba(#000, 0.5);
}
svg {
width: 15px;
}
input {
width: 100%;
}
}
}
.range {
width: 100%;
height: 30px;
padding: 0;
margin: 0;
.rangeslider {
padding: 0;
margin: 0;
height: 30px;
background-color: rgba(#111, 0.1);
border-radius: 50px;
box-shadow: none;
.rangeslider__fill {
background-color: #fff;
box-shadow: none;
border-radius: 0px;
}
.rangeslider__handle {
background-color: #fff;
color: #fff;
box-shadow: -5px 0px 10px 0px rgba(#111, 0.2);
border: none;
outline: none;
&::after {
display: none;
}
}
}
}
.currently-playing {
display: grid;
grid-template-columns: 1fr 5fr 1fr;
padding: 5px 25px;
.image {
display: flex;
align-items: center;
img {
width: 70px;
height: 70px;
border-radius: 5px;
}
}
.content {
box-sizing: border-box;
padding: 0 25px;
display: flex;
align-items: center;
.text {
color: black;
h4 {
padding-bottom: 5px;
}
p {
opacity: 0.5;
}
}
}
.controls {
display: flex;
align-items: center;
justify-content: flex-end;
button {
background-color: transparent;
svg {
fill: black;
width: 30px;
}
}
}
}
View Compiled
const Slider = window.ReactRangeslider.default
const ConnectionModule = () => {
const [connections, setConnections] = React.useState([
{
icon: 'wifi',
name: 'Wi-Fi',
status: 'Home',
off: 'off',
active: true
},
{
icon: 'bluetooth',
name: 'Bluetooth',
active: false
},
{
icon: 'rss',
name: 'AirDrop',
status: 'Contacts Only',
off: 'off',
active: true
}
])
const toggleActive = (index) => {
const newConnections = [...connections]
newConnections[index].active = !newConnections[index].active
setConnections(newConnections)
}
return (
<div className='connection-controls rounded module-bg'>
{connections.map((connection, index) => (
<div className='module-wrapper'>
<div className='module'>
<div className='icon-wrapper'>
<button type='button' onClick={() => toggleActive(index)} className={connection.active && 'active'}><i data-feather={connection.icon}></i></button>
</div>
<div className='content-wrapper'>
<div className='content'>
<p className='name'>{connection.name}</p>
{connection.status && <p className='status'>{!connection.active && connection.off ? connection.off : connection.status}</p>}
</div>
</div>
</div>
</div>
))}
</div>
)
}
const DoNotDisturb = () => {
const [active, setActive] = React.useState(false)
return (
<div className='do-not-disturb rounded module-bg'>
<div className='button-wrapper'>
<button type='button' onClick={() => setActive(active => !active)} className={active && 'active'}><i data-feather='moon'></i></button>
</div>
<div className='content'><p>Do Not<br />Disturb</p></div>
</div>
)
}
const SliderComponent = () => {
const [value, setValue] = React.useState(0);
return (
<div className='range'>
<Slider
min={0}
max={100}
value={value}
tooltip={false}
orientation="horizontal"
onChange={value => setValue(value)}
/>
</div>
)
}
const FullWidthSlider = ({ text, icon }) => {
return (
<div className='slider rounded module-bg'>
<p>{text}</p>
<div className='slider-inner'>
<div className='icon'><i data-feather={icon}></i></div>
<SliderComponent />
</div>
</div>
)
}
const MusicModule = () => {
const [play, setPlay] = React.useState(true)
const togglePlay = () => {
setPlay(prevState => !prevState)
}
return (
<div className='currently-playing rounded module-bg'>
<div className='image'>
<img src="https://i1.sndcdn.com/artworks-000596249969-hovmmz-t500x500.jpg" width="80" alt="cover art " />
</div>
<div className='content'>
<div className='text'>
<h4>SAINt JHN</h4>
<p>Roses (Imanbek Remix)</p>
</div>
</div>
<div className='controls'>
<button type='button' onClick={() => togglePlay()}>
<div style={{ display: play ? 'inline-block' : 'none' }}>
<i data-feather='play'></i>
</div>
<div style={{ display: play ? 'none' : 'inline-block' }}>
<i data-feather='pause'></i>
</div>
</button>
</div>
</div>
)
}
const App = () => (
<div className='card-wrapper rounded'>
<div className='half-modules-wrapper'>
<ConnectionModule />
<div className='other-connections'>
<DoNotDisturb />
<div className='keyboard-and-airplay'>
<div className='module rounded module-bg'>
<i data-feather='sun'></i>
<p>Keyboard Brightness</p>
</div>
<div className='module rounded module-bg'>
<i data-feather='monitor'></i>
<p>Airplay Display</p>
</div>
</div>
</div>
</div>
<div className='full-width-modules'>
<FullWidthSlider text='Display' icon='sun' />
<FullWidthSlider text='Sound' icon='volume-2' />
<MusicModule />
</div>
</div>
)
ReactDOM.render(<App />, document.getElementById('app'))
feather.replace()
View Compiled