Skip to content

Commit b011ad1

Browse files
committed
feat: Add Servlet and Streams modules, including a Servlet request-response flow simulator.
1 parent 0fa4d1f commit b011ad1

File tree

12 files changed

+1629
-2
lines changed

12 files changed

+1629
-2
lines changed

src/components/Layout/Header.tsx

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,30 @@ export function Header({ moduleNav }: HeaderProps) {
5454

5555
{/* Logo & Title */}
5656
<div className={styles.branding}>
57-
<div className={styles.logo}>J</div>
57+
<div className={styles.logo}>
58+
<svg viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
59+
{/* Coffee cup body */}
60+
<rect x="8" y="18" width="24" height="22" rx="3" fill="url(#coffeeGrad)" />
61+
{/* Cup handle */}
62+
<path d="M32 22 C38 22 38 36 32 36" stroke="url(#coffeeGrad)" strokeWidth="3" fill="none" />
63+
{/* Steam lines */}
64+
<path d="M14 14 Q16 10 14 6" stroke="#94a3b8" strokeWidth="2" strokeLinecap="round" opacity="0.7">
65+
<animate attributeName="d" values="M14 14 Q16 10 14 6;M14 14 Q12 10 14 6;M14 14 Q16 10 14 6" dur="2s" repeatCount="indefinite" />
66+
</path>
67+
<path d="M20 12 Q22 8 20 4" stroke="#94a3b8" strokeWidth="2" strokeLinecap="round" opacity="0.7">
68+
<animate attributeName="d" values="M20 12 Q22 8 20 4;M20 12 Q18 8 20 4;M20 12 Q22 8 20 4" dur="2s" repeatCount="indefinite" begin="0.3s" />
69+
</path>
70+
<path d="M26 14 Q28 10 26 6" stroke="#94a3b8" strokeWidth="2" strokeLinecap="round" opacity="0.7">
71+
<animate attributeName="d" values="M26 14 Q28 10 26 6;M26 14 Q24 10 26 6;M26 14 Q28 10 26 6" dur="2s" repeatCount="indefinite" begin="0.6s" />
72+
</path>
73+
<defs>
74+
<linearGradient id="coffeeGrad" x1="0%" y1="0%" x2="100%" y2="100%">
75+
<stop offset="0%" stopColor="#f97316" />
76+
<stop offset="100%" stopColor="#ea580c" />
77+
</linearGradient>
78+
</defs>
79+
</svg>
80+
</div>
5881
<div className={styles.titleGroup}>
5982
<h1 className={styles.title}>
6083
{moduleConfig?.title || 'Java Engineering Masterclass'}

src/contexts/ConsoleContext.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ const createInitialState = (): ModuleConsoleState => ({
2323
architecture: [],
2424
platform: [],
2525
jdbc: [],
26+
servlet: [],
27+
streams: [],
2628
});
2729

2830
interface ConsoleProviderProps {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* Servlet Module Container
3+
* Main entry point for JSP & Servlets module
4+
*/
5+
6+
import { useNavigation } from '../../contexts';
7+
import { ServletSimulator } from './ServletSimulator';
8+
import { ServletTheory } from './ServletTheory';
9+
10+
export function ServletModule() {
11+
const { activeTab } = useNavigation();
12+
13+
return activeTab === 'simulator' ? <ServletSimulator /> : <ServletTheory />;
14+
}
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
/* Servlet Simulator Styles */
2+
3+
.container {
4+
width: 100%;
5+
height: 100%;
6+
padding: var(--space-6);
7+
overflow-y: auto;
8+
background-color: var(--color-bg-primary);
9+
}
10+
11+
.grid {
12+
display: grid;
13+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
14+
gap: var(--space-6);
15+
max-width: 1200px;
16+
margin: 0 auto;
17+
}
18+
19+
.panel {
20+
background-color: var(--color-bg-secondary);
21+
border: 1px solid var(--color-border-default);
22+
border-radius: var(--radius-xl);
23+
padding: var(--space-6);
24+
}
25+
26+
.panelTitle {
27+
font-size: var(--text-xl);
28+
font-weight: 700;
29+
color: var(--color-text-primary);
30+
margin: 0 0 var(--space-1) 0;
31+
}
32+
33+
.panelSubtitle {
34+
font-size: var(--text-sm);
35+
color: var(--color-text-muted);
36+
margin: 0 0 var(--space-4) 0;
37+
}
38+
39+
/* Steps */
40+
.stepsContainer {
41+
display: flex;
42+
flex-direction: column;
43+
gap: var(--space-2);
44+
}
45+
46+
.step {
47+
display: flex;
48+
align-items: center;
49+
gap: var(--space-3);
50+
padding: var(--space-3);
51+
background-color: rgba(255, 255, 255, 0.03);
52+
border: 1px solid var(--color-border-default);
53+
border-radius: var(--radius-md);
54+
transition: all 0.3s ease;
55+
}
56+
57+
.step.active {
58+
background-color: rgba(251, 113, 133, 0.1);
59+
border-color: #fb7185;
60+
}
61+
62+
.step.complete {
63+
background-color: rgba(134, 239, 172, 0.1);
64+
border-color: #86efac;
65+
}
66+
67+
.stepMarker {
68+
width: 28px;
69+
height: 28px;
70+
background-color: var(--color-border-default);
71+
border-radius: 50%;
72+
display: flex;
73+
align-items: center;
74+
justify-content: center;
75+
font-size: var(--text-sm);
76+
font-weight: 700;
77+
color: var(--color-text-muted);
78+
flex-shrink: 0;
79+
}
80+
81+
.step.active .stepMarker {
82+
background-color: #fb7185;
83+
color: white;
84+
}
85+
86+
.step.complete .stepMarker {
87+
background-color: #86efac;
88+
color: #0f172a;
89+
}
90+
91+
.stepContent {
92+
display: flex;
93+
flex-direction: column;
94+
}
95+
96+
.stepContent strong {
97+
font-size: var(--text-sm);
98+
color: var(--color-text-primary);
99+
}
100+
101+
.stepContent small {
102+
font-size: var(--text-xs);
103+
color: var(--color-text-muted);
104+
}
105+
106+
/* Method Selector */
107+
.methodSelector {
108+
display: flex;
109+
gap: var(--space-2);
110+
margin-bottom: var(--space-4);
111+
}
112+
113+
.methodBtn {
114+
flex: 1;
115+
padding: var(--space-2);
116+
background-color: rgba(255, 255, 255, 0.05);
117+
border: 2px solid var(--color-border-default);
118+
border-radius: var(--radius-md);
119+
color: var(--color-text-secondary);
120+
font-weight: 700;
121+
cursor: pointer;
122+
transition: all 0.2s;
123+
}
124+
125+
.methodBtn.selected {
126+
background-color: rgba(251, 113, 133, 0.1);
127+
border-color: #fb7185;
128+
color: #fb7185;
129+
}
130+
131+
/* URL Display */
132+
.urlDisplay {
133+
background-color: #0a0a0a;
134+
border: 1px solid var(--color-border-default);
135+
border-radius: var(--radius-md);
136+
padding: var(--space-3);
137+
margin-bottom: var(--space-4);
138+
}
139+
140+
.urlDisplay code {
141+
font-family: var(--font-mono);
142+
font-size: var(--text-sm);
143+
color: #fb7185;
144+
}
145+
146+
/* Send Button */
147+
.sendBtn {
148+
width: 100%;
149+
padding: var(--space-3);
150+
background-color: #fb7185;
151+
color: white;
152+
border: none;
153+
border-radius: var(--radius-md);
154+
font-weight: 700;
155+
cursor: pointer;
156+
transition: background-color 0.2s;
157+
}
158+
159+
.sendBtn:hover:not(:disabled) {
160+
background-color: #e11d48;
161+
}
162+
163+
.sendBtn:disabled {
164+
opacity: 0.5;
165+
cursor: not-allowed;
166+
}
167+
168+
/* Session */
169+
.sessionStatus {
170+
display: flex;
171+
align-items: center;
172+
gap: var(--space-3);
173+
margin-bottom: var(--space-4);
174+
padding: var(--space-3);
175+
background-color: rgba(255, 255, 255, 0.03);
176+
border-radius: var(--radius-md);
177+
}
178+
179+
.sessionLabel {
180+
color: var(--color-text-muted);
181+
font-size: var(--text-sm);
182+
}
183+
184+
.sessionOn {
185+
color: #86efac;
186+
font-weight: 700;
187+
}
188+
189+
.sessionOff {
190+
color: var(--color-text-muted);
191+
font-weight: 700;
192+
}
193+
194+
.sessionInfo {
195+
background-color: #0a0a0a;
196+
border: 1px solid var(--color-border-default);
197+
border-radius: var(--radius-md);
198+
padding: var(--space-3);
199+
margin-bottom: var(--space-4);
200+
}
201+
202+
.sessionItem {
203+
display: flex;
204+
justify-content: space-between;
205+
padding: var(--space-1) 0;
206+
font-size: var(--text-sm);
207+
}
208+
209+
.sessionItem span {
210+
color: var(--color-text-muted);
211+
}
212+
213+
.sessionItem code {
214+
color: #fb7185;
215+
}
216+
217+
.invalidateBtn {
218+
width: 100%;
219+
padding: var(--space-2);
220+
background-color: transparent;
221+
border: 2px solid #f87171;
222+
border-radius: var(--radius-md);
223+
color: #f87171;
224+
font-weight: 700;
225+
font-size: var(--text-sm);
226+
cursor: pointer;
227+
transition: all 0.2s;
228+
}
229+
230+
.invalidateBtn:hover:not(:disabled) {
231+
background-color: rgba(248, 113, 113, 0.1);
232+
}
233+
234+
.invalidateBtn:disabled {
235+
opacity: 0.4;
236+
cursor: not-allowed;
237+
}

0 commit comments

Comments
 (0)