JavaScript and React course Β· Module 7: Styling and Animations

Project: Cosmic Mission Control Panel

4 min read
In this lesson4

Congratulations, Navigator! You have reached the end of this module and it is time to combine all the styling techniques you have learned into one comprehensive project. Your task is to create a Cosmic Mission Control Panel - an interactive dashboard that utilizes knowledge from the entire module.

Project Goal

You will build a spaceship control panel that combines:

  • Styled Components with dynamic theming
  • CSS Animations with @keyframes
  • Responsive layout with CSS Grid and Flexbox
  • Theming (light/dark mode)
  • Interactive elements with hover effects and transitions

Project Architecture

The project consists of several key sections:

1. Theme System (Theming)

We use ThemeProvider from styled-components to manage colors and styles across the entire application:

1const darkTheme = {
2  bg: '#0a0a1a',
3  surface: '#12122a',
4  accent: '#00ff88',
5  text: '#e0e0e0',
6  danger: '#ff4444',
7  warning: '#ffaa00'
8};
9
10const lightTheme = {
11  bg: '#f0f4f8',
12  surface: '#ffffff',
13  accent: '#0066ff',
14  text: '#1a1a2e',
15  danger: '#cc0000',
16  warning: '#cc8800'
17};

2. CSS Animations

The panel uses several types of animations you learned in the module:

1/* Status pulsing */
2@keyframes pulse {
3  0%, 100% { opacity: 1; }
4  50% { opacity: 0.5; }
5}
6
7/* Slide in with offset */
8@keyframes slideIn {
9  from {
10    opacity: 0;
11    transform: translateY(20px);
12  }
13  to {
14    opacity: 1;
15    transform: translateY(0);
16  }
17}
18
19/* Radar rotation */
20@keyframes rotate {
21  from { transform: rotate(0deg); }
22  to { transform: rotate(360deg); }
23}

3. Styled Components with Props

Dynamic component styling based on passed props:

1const StatusBadge = styled.span`
2  padding: 4px 12px;
3  border-radius: 12px;
4  font-size: 12px;
5  font-weight: bold;
6  background: ${props => props.active ? '#00ff8833' : '#ff444433'};
7  color: ${props => props.active ? '#00ff88' : '#ff4444'};
8  animation: pulse 2s infinite;
9`;
10
11const Card = styled.div`
12  background: ${props => props.theme.surface};
13  border: 1px solid ${props => props.theme.accent}33;
14  border-radius: 12px;
15  padding: 20px;
16  transition: transform 0.3s ease, box-shadow 0.3s ease;
17
18  &:hover {
19    transform: translateY(-4px);
20    box-shadow: 0 8px 25px rgba(0, 255, 136, 0.15);
21  }
22`;

4. Responsive Layout with CSS Grid

The panel automatically adapts to the screen width:

1.dashboard-grid {
2  display: grid;
3  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
4  gap: 20px;
5  padding: 20px;
6}
7
8@media (max-width: 768px) {
9  .dashboard-grid {
10    grid-template-columns: 1fr;
11  }
12}

5. Complete Component Structure

The main App component brings all elements together:

1function App() {
2  const [isDark, setIsDark] = useState(true);
3
4  return (
5    <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
6      <GlobalStyle />
7      <Header>
8        <Title>Mission Control</Title>
9        <ThemeToggle onClick={() => setIsDark(!isDark)}>
10          {isDark ? 'Light' : 'Dark'}
11        </ThemeToggle>
12      </Header>
13      <DashboardGrid>
14        <StatusCard systems={systemsData} />
15        <RadarCard />
16        <MissionsCard missions={missionsData} />
17        <CrewCard crew={crewData} />
18      </DashboardGrid>
19    </ThemeProvider>
20  );
21}

Key Techniques Used in the Project

TechniqueUsage in Project
Styled ComponentsAll UI components
ThemeProviderSwitching dark/light mode
@keyframesStatus pulsing, radar rotation, card entry
CSS GridDashboard layout
FlexboxInternal card layout
transitionHover effects on cards and buttons
Dynamic propsStatus colors, conditional styles
Responsivenessauto-fit and minmax in grid

Module Summary

In this module, you learned the full spectrum of styling techniques in React:

  1. Classic CSS and CSS Modules - the foundation of styling with class isolation
  2. Styled Components - CSS-in-JS with dynamic props and theming
  3. SCSS - preprocessor with variables, mixins, and nesting
  4. Tailwind CSS - utility-first approach for fast prototyping
  5. UI Frameworks - ready component libraries (MUI, Ant Design, Chakra)
  6. Design Systems - building consistent design systems
  7. React Transition Group - animating component lifecycle
  8. CSS Animations - @keyframes, transition, and advanced effects

Each of these techniques has its place in the arsenal of a cosmic programmer. The best engineers know how to combine them into a coherent system - exactly as in this project.

Try the panel below and experiment with the code - change the theme colors, add new animations, or expand the dashboard sections!

Code for this lesson: App.jsx
1import React, { useState } from 'react';
2import styled, { keyframes, css, ThemeProvider, createGlobalStyle } from 'styled-components';
3
4// ===== THEMES =====
5const darkTheme = {
6  bg: '#0a0a1a',
7  surface: '#12122a',
8  surfaceHover: '#1a1a3a',
9  accent: '#00ff88',
10  accentDim: 'rgba(0,255,136,0.15)',
11  text: '#e0e0e0',
12  textSecondary: '#8888aa',
13  danger: '#ff4444',
14  warning: '#ffaa00',
15  border: 'rgba(0,255,136,0.2)',
16};
17
18const lightTheme = {
19  bg: '#f0f4f8',
20  surface: '#ffffff',
21  surfaceHover: '#e8ecf0',
22  accent: '#0066ff',
23  accentDim: 'rgba(0,102,255,0.1)',
24  text: '#1a1a2e',
25  textSecondary: '#666688',
26  danger: '#cc0000',
27  warning: '#cc8800',
28  border: 'rgba(0,102,255,0.2)',
29};
30
31// ===== GLOBAL STYLES =====
32const GlobalStyle = createGlobalStyle`
33  * { margin: 0; padding: 0; box-sizing: border-box; }
34  body {
35    font-family: 'Segoe UI', Tahoma, sans-serif;
36    background: ${props => props.theme.bg};
37    color: ${props => props.theme.text};
38    transition: background 0.3s ease, color 0.3s ease;
39  }
40`;
41
42// ===== ANIMATIONS =====
43const pulse = keyframes`
44  0%, 100% { opacity: 1; }
45  50% { opacity: 0.5; }
46`;
47
48const slideIn = keyframes`
49  from { opacity: 0; transform: translateY(20px); }
50  to { opacity: 1; transform: translateY(0); }
51`;
52
53const rotate = keyframes`
54  from { transform: rotate(0deg); }
55  to { transform: rotate(360deg); }
56`;
57
58const glow = keyframes`
59  0%, 100% { box-shadow: 0 0 5px ${() => 'rgba(0,255,136,0.3)'}; }
60  50% { box-shadow: 0 0 20px ${() => 'rgba(0,255,136,0.6)'}; }
61`;
62
63// ===== LAYOUT COMPONENTS =====
64const Header = styled.header`
65  display: flex;
66  justify-content: space-between;
67  align-items: center;
68  padding: 16px 24px;
69  background: ${p => p.theme.surface};
70  border-bottom: 1px solid ${p => p.theme.border};
71`;
72
73const Title = styled.h1`
74  font-size: 20px;
75  color: ${p => p.theme.accent};
76  letter-spacing: 2px;
77  text-transform: uppercase;
78`;
79
80const ThemeToggle = styled.button`
81  background: ${p => p.theme.accentDim};
82  border: 1px solid ${p => p.theme.accent};
83  color: ${p => p.theme.accent};
84  padding: 8px 16px;
85  border-radius: 8px;
86  cursor: pointer;
87  font-size: 14px;
88  transition: all 0.3s ease;
89  &:hover {
90    background: ${p => p.theme.accent};
91    color: ${p => p.theme.bg};
92  }
93`;
94
95const DashboardGrid = styled.div`
96  display: grid;
97  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
98  gap: 20px;
99  padding: 24px;
100`;
101
102const Card = styled.div`
103  background: ${p => p.theme.surface};
104  border: 1px solid ${p => p.theme.border};
105  border-radius: 12px;
106  padding: 20px;
107  animation: ${slideIn} 0.5s ease ${p => p.delay || '0s'} both;
108  transition: transform 0.3s ease, box-shadow 0.3s ease;
109  &:hover {
110    transform: translateY(-4px);
111    box-shadow: 0 8px 25px ${p => p.theme.accentDim};
112  }
113`;
114
115const CardTitle = styled.h3`
116  font-size: 14px;
117  text-transform: uppercase;
118  letter-spacing: 1px;
119  color: ${p => p.theme.accent};
120  margin-bottom: 16px;
121  display: flex;
122  align-items: center;
123  gap: 8px;
124`;
125
126// ===== STATUS COMPONENTS =====
127const StatusBadge = styled.span`
128  display: inline-block;
129  padding: 3px 10px;
130  border-radius: 12px;
131  font-size: 11px;
132  font-weight: bold;
133  background: ${p => p.active ? 'rgba(0,255,136,0.15)' : 'rgba(255,68,68,0.15)'};
134  color: ${p => p.active ? '#00ff88' : '#ff4444'};
135  animation: ${pulse} 2s infinite;
136`;
137
138const SystemRow = styled.div`
139  display: flex;
140  justify-content: space-between;
141  align-items: center;
142  padding: 8px 0;
143  border-bottom: 1px solid ${p => p.theme.border};
144  &:last-child { border-bottom: none; }
145`;
146
147// ===== RADAR COMPONENTS =====
148const RadarWrapper = styled.div`
149  width: 120px;
150  height: 120px;
151  border-radius: 50%;
152  border: 2px solid ${p => p.theme.accent};
153  position: relative;
154  margin: 0 auto 16px;
155  overflow: hidden;
156  background: radial-gradient(circle, ${p => p.theme.accentDim} 0%, transparent 70%);
157`;
158
159const RadarSweep = styled.div`
160  position: absolute;
161  top: 0; left: 50%;
162  width: 2px; height: 50%;
163  background: ${p => p.theme.accent};
164  transform-origin: bottom center;
165  animation: ${rotate} 3s linear infinite;
166`;
167
168const RadarDot = styled.div`
169  position: absolute;
170  width: 6px; height: 6px;
171  background: ${p => p.theme.accent};
172  border-radius: 50%;
173  top: ${p => p.y}%;
174  left: ${p => p.x}%;
175  animation: ${pulse} 1.5s infinite;
176`;
177
178// ===== PROGRESS BAR =====
179const ProgressOuter = styled.div`
180  width: 100%;
181  height: 6px;
182  background: ${p => p.theme.border};
183  border-radius: 3px;
184  margin-top: 6px;
185`;
186
187const ProgressInner = styled.div`
188  height: 100%;
189  width: ${p => p.value || 0}%;
190  background: ${p =>
191    p.value > 75 ? '#00ff88' :
192    p.value > 40 ? '#ffaa00' : '#ff4444'};
193  border-radius: 3px;
194  transition: width 0.5s ease;
195`;
196
197// ===== CREW AVATAR =====
198const AvatarCircle = styled.div`
199  width: 36px;
200  height: 36px;
201  border-radius: 50%;
202  background: ${p => p.color || p.theme.accent};
203  display: flex;
204  align-items: center;
205  justify-content: center;
206  font-size: 14px;
207  font-weight: bold;
208  color: #fff;
209`;
210
211const CrewRow = styled.div`
212  display: flex;
213  align-items: center;
214  gap: 12px;
215  padding: 8px 0;
216`;
217
218const CrewInfo = styled.div`
219  flex: 1;
220  & span { display: block; font-size: 12px; color: ${p => p.theme.textSecondary}; }
221`;
222
223// ===== DATA =====
224const systems = [
225  { name: 'Warp engines', active: true },
226  { name: 'Energy shields', active: true },
227  { name: 'Navigation systems', active: true },
228  { name: 'Long-range communications', active: false },
229  { name: 'Life support', active: true },
230];
231
232const missions = [
233  { name: 'X-7 Nebula Exploration', progress: 87 },
234  { name: 'Supply Transport', progress: 45 },
235  { name: 'Asteroid Mapping', progress: 62 },
236  { name: 'Relay Station Repair', progress: 15 },
237];
238
239const crew = [
240  { name: 'Cpt. Nova', role: 'Commander', color: '#e74c3c', initial: 'N' },
241  { name: 'Lt. Orion', role: 'Navigator', color: '#3498db', initial: 'O' },
242  { name: 'Dr. Stella', role: 'Medic', color: '#9b59b6', initial: 'S' },
243  { name: 'Ing. Vega', role: 'Engineer', color: '#2ecc71', initial: 'V' },
244];
245
246// ===== APP =====
247function App() {
248  const [isDark, setIsDark] = useState(true);
249  const theme = isDark ? darkTheme : lightTheme;
250
251  return (
252    <ThemeProvider theme={theme}>
253      <GlobalStyle />
254      <Header>
255        <Title>Mission Control</Title>
256        <ThemeToggle onClick={() => setIsDark(!isDark)}>
257          {isDark ? 'Light Mode' : 'Dark Mode'}
258        </ThemeToggle>
259      </Header>
260
261      <DashboardGrid>
262        {/* Systems Status */}
263        <Card delay="0s">
264          <CardTitle>Ship systems</CardTitle>
265          {systems.map((s, i) => (
266            <SystemRow key={i}>
267              <span>{s.name}</span>
268              <StatusBadge active={s.active}>
269                {s.active ? 'ONLINE' : 'OFFLINE'}
270              </StatusBadge>
271            </SystemRow>
272          ))}
273        </Card>
274
275        {/* Radar */}
276        <Card delay="0.1s">
277          <CardTitle>Radar</CardTitle>
278          <RadarWrapper>
279            <RadarSweep />
280            <RadarDot x={30} y={25} />
281            <RadarDot x={65} y={40} />
282            <RadarDot x={45} y={70} />
283          </RadarWrapper>
284          <p style={{ textAlign: 'center', fontSize: 13, opacity: 0.7 }}>
285            3 objects within scanner range
286          </p>
287        </Card>
288
289        {/* Missions Progress */}
290        <Card delay="0.2s">
291          <CardTitle>Missions</CardTitle>
292          {missions.map((m, i) => (
293            <div key={i} style={{ marginBottom: 12 }}>
294              <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13 }}>
295                <span>{m.name}</span>
296                <span style={{ fontWeight: 'bold' }}>{m.progress}%</span>
297              </div>
298              <ProgressOuter>
299                <ProgressInner value={m.progress} />
300              </ProgressOuter>
301            </div>
302          ))}
303        </Card>
304
305        {/* Crew */}
306        <Card delay="0.3s">
307          <CardTitle>Crew</CardTitle>
308          {crew.map((c, i) => (
309            <CrewRow key={i}>
310              <AvatarCircle color={c.color}>{c.initial}</AvatarCircle>
311              <CrewInfo>
312                <strong>{c.name}</strong>
313                <span>{c.role}</span>
314              </CrewInfo>
315              <StatusBadge active={true}>On duty</StatusBadge>
316            </CrewRow>
317          ))}
318        </Card>
319      </DashboardGrid>
320    </ThemeProvider>
321  );
322}
323
324export default App;

Spotted a mistake in this lesson?

Hands-on tasks in the game

  • Code editor

    Build a comprehensive Design System including: styled-components for component-level styling, CSS-in-JS patterns, theme provider with dark/light modes, responsive design with breakpoints, CSS Grid and Flexbox layouts, animations with @keyframes, typography system, color tokens, spacing system, and accessibility features (focus states, ARIA). Create a design system worthy of the most advanced Deep Space Nine interfaces!

Useful articles