Skip to content

Instantly share code, notes, and snippets.

@MarcWoodyard
Created September 12, 2022 23:16
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save MarcWoodyard/4697962fcba9f8a6dda1eb1223756be4 to your computer and use it in GitHub Desktop.
Futuristic UI - Control Console
<div id="main-app"></div>
<!--
Inspired by this FUI design:
https://www.behance.net/gallery/14374555/2RISE-FUTURISTIC-MEDICAL-INTERFACE
-->
const sc = styled.default;
const colors = {
orange: '#fc8503',
darkOrange: '#b56917',
};
const Wrapper = sc.section`
border: 1px solid #ccc;
color: #ddd;
width: 100%; min-width: 10rem; max-width: 30rem;
min-height: 15rem;
padding: 1rem;
position: fixed;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
&:after,
&:before {
content: '';
color: #ccc;
position: absolute;
width: 0.5rem; height: 0.5rem;
}
&:before {
bottom: -0.5rem;
right: -0.5rem;
border-bottom: 1px solid #ccc;
border-right: 1px solid #ccc;
}
&:after {
top: -0.5rem;
left: -0.5rem;
border-top: 1px solid #ccc;
border-left: 1px solid #ccc;
}
`;
const Header = sc.h2`
border-top: 1px solid #ccc;
border-bottom: 1px solid #ccc;
line-height: 2rem;
font-size: 1.875rem;
position: relative;
&:before {
content: '';
position: absolute;
left: -0.5rem;
background-color: ${colors.orange};
width: 0.25rem; height: 0.25rem;
margin: 0.875rem 0 0 0;
border-radius: 50%;
}
`;
const ControlWrapper = sc.div`
width: 11rem;
`;
const Body = sc.div`
padding: 1rem;
display: flex;
justify-content: space-between;
`;
const Subheader = sc.h5`
margin: 0 0 0.5rem;
strong {
font-weight: bold;
letter-spacing: 0.025rem;
}
`;
const ButtonGroup = sc.div`
display: flex;
flex-wrap: wrap;
`;
const Button = sc.button`
background: none;
border: 3px solid #ccc;
cursor: pointer;
width: 5rem; height: 5rem;
color: #ccc;
display: flex;
line-height: 1;
flex-direction: column;
outline: none;
margin: 0 1rem 0.5rem 0;
padding: 0.25rem;
position: relative;
transition:
border-color 250ms ease-in-out,
color 250ms ease-in-out;
&:last-of-type {
margin-right: 0;
}
&:after {
content: '';
border-top: 1rem solid transparent;
border-bottom: 1rem solid transparent;
border-left: 1rem solid #ccc;
transform: rotate(45deg);
position: absolute;
bottom: -0.4rem; right: 0.075rem;
transition: border-color 250ms ease-in-out;
}
&:hover {
color: ${colors.darkOrange};
border-color: ${colors.darkOrange};
&:after {
border-left-color: ${colors.darkOrange};
}
}
&:active {
color: ${colors.orange};
border-color: ${colors.orange};
&:after {
border-left-color: ${colors.orange};
}
}
`;
const ButtonHeader = sc.span`
font-size: 24px;
`;
const ButtonSubheader = sc.span`
font-size: 18px;
`;
const HR = sc.div`
border-top: 1px solid #ccc;
margin: ${({ last }) => last ? '0 -0.5rem 0.5rem' : '0 -0.5rem 0.25rem'};
`;
const VisualizerWrapper = sc.div`
margin: 0 1rem;
`;
const Radar = sc.div`
display: flex;
position: relative;
flex: 1 1 auto;
height: 12rem;
width: 12rem;
`;
const RadarGrid = sc.div`
background-color: ${({ active }) => active
? 'rgba(255, 255, 255, 0.1)'
: 'rgba(255, 255, 255, 0)'
};
cursor: pointer;
position: absolute;
width: ${({ diameter }) => diameter || '50%'};
height: ${({ diameter }) => diameter || '50%'};
border: 1px solid ${({ active }) => active ? colors.orange : '#666'};
border-radius: 50%;
overflow: visible;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
z-index: ${({ index }) => index || '0'};
transition:
background-color 300ms ease-in-out,
border 600ms ease-in-out;
&:hover {
background-color: ${({ active }) => active
? 'rgba(255, 255, 255, 0.125)'
: 'rgba(255, 255, 255, 0.05)'
};
transition: background-color 100ms ease-in-out;
}
&:active {
background-color: rgba(255, 255, 255, 0.15);
}
`;
const Blip = sc.div`
cursor: pointer;
font-size: 0.75rem;
top: ${({ y }) => `calc(${y} - 1rem)` || '50%'};
left: ${({ x }) => `calc(${x} + 0.25rem)` || '50%'};
position: absolute;
text-transform: uppercase;
width: 5rem;
user-select: none;
z-index: 10;
font-smoothing: antialiased;
&:after {
background-color: #fff;
bottom: -0.5rem; left: -0.25rem;
content: '';
color: #fff;
position: absolute;
transform: translate(-50%, -50%);
width: 0.25rem; height: 0.25rem;
}
`;
// App Component
class App extends React.Component {
state = {
distance: "10"
};
changeDistance = (e) => {
this.setState({ distance: e.currentTarget.dataset.range });
};
render = () => (
<Wrapper>
<Header>REMOTE STATION</Header>
<Body>
<ControlWrapper>
<Subheader>CONTROL CONSOLE</Subheader>
<ButtonGroup>
<Button>
<ButtonHeader>L5</ButtonHeader>
<ButtonSubheader>CPU</ButtonSubheader>
</Button>
<Button>
<ButtonHeader>H1</ButtonHeader>
<ButtonSubheader>MEMORY</ButtonSubheader>
</Button>
</ButtonGroup>
<HR />
<HR last />
<ButtonGroup>
<Button>
<ButtonHeader>G2</ButtonHeader>
<ButtonSubheader>DRIVE</ButtonSubheader>
</Button>
<Button>
<ButtonHeader>B8</ButtonHeader>
<ButtonSubheader>NETWORK</ButtonSubheader>
</Button>
</ButtonGroup>
</ControlWrapper>
<VisualizerWrapper>
<Subheader>RADAR DISTANCE:
<strong> {this.state.distance} KM</strong>
</Subheader>
<Radar>
<Blip x="50%" y="50%">&nbsp;</Blip>
<Blip x="65%" y="50%">10 KM</Blip>
<Blip x="83%" y="50%">50 KM</Blip>
<Blip x="100%" y="50%">100 KM</Blip>
<RadarGrid
active={this.state.distance === '10'}
data-range="10"
diameter="30%"
index={3}
onClick={this.changeDistance}
/>
<RadarGrid
active={this.state.distance === '50'}
data-range="50"
diameter="65%"
index={2}
onClick={this.changeDistance}
/>
<RadarGrid
active={this.state.distance === '100'}
data-range="100"
diameter="100%"
index={1}
onClick={this.changeDistance}
/>
</Radar>
</VisualizerWrapper>
</Body>
</Wrapper>
);
}
// Render app
ReactDOM.render(<App />, document.getElementById('main-app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/styled-components/2.2.1/styled-components.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.9.1/d3.min.js"></script>
html {
background: #191919;
background-image:
linear-gradient(90deg, #111 1rem, transparent 1rem),
linear-gradient(#111 1rem, transparent 1rem);
background-size: 1.2rem 1.2rem;
}
html,
body,
* {
font-family: 'Saira Extra Condensed', sans-serif;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment