Skip to content

Commit b98ac9a

Browse files
committed
feat: introduce core UI components and simulation hooks for memory management.
1 parent c249c64 commit b98ac9a

16 files changed

Lines changed: 933 additions & 0 deletions
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
.header {
2+
background-color: #020617;
3+
border-bottom: 1px solid var(--color-border-subtle);
4+
padding: var(--space-4);
5+
display: flex;
6+
justify-content: space-between;
7+
align-items: center;
8+
box-shadow: var(--shadow-lg);
9+
z-index: 20;
10+
}
11+
12+
.leftSection {
13+
display: flex;
14+
align-items: center;
15+
gap: var(--space-4);
16+
}
17+
18+
.backButton {
19+
display: flex;
20+
align-items: center;
21+
gap: var(--space-2);
22+
color: var(--color-text-secondary);
23+
background: transparent;
24+
border: none;
25+
cursor: pointer;
26+
padding: var(--space-2) var(--space-3);
27+
border-radius: var(--radius-md);
28+
transition: all var(--transition-fast);
29+
font-size: var(--text-sm);
30+
font-weight: 600;
31+
}
32+
33+
.backButton:hover {
34+
color: var(--color-text-primary);
35+
background: var(--color-bg-secondary);
36+
}
37+
38+
.backButton:hover .backIcon {
39+
transform: translateX(-2px);
40+
}
41+
42+
.backIcon {
43+
width: 16px;
44+
height: 16px;
45+
transition: transform var(--transition-fast);
46+
}
47+
48+
.branding {
49+
display: flex;
50+
align-items: center;
51+
gap: var(--space-3);
52+
}
53+
54+
.logo {
55+
width: 40px;
56+
height: 40px;
57+
background: linear-gradient(135deg, #2563eb, #4f46e5);
58+
border-radius: var(--radius-lg);
59+
display: flex;
60+
align-items: center;
61+
justify-content: center;
62+
font-weight: 700;
63+
font-size: var(--text-xl);
64+
color: white;
65+
box-shadow: var(--shadow-md);
66+
}
67+
68+
.titleGroup {
69+
display: flex;
70+
flex-direction: column;
71+
}
72+
73+
.title {
74+
font-weight: 700;
75+
font-size: var(--text-lg);
76+
line-height: 1.2;
77+
color: var(--color-text-primary);
78+
margin: 0;
79+
}
80+
81+
.subtitle {
82+
font-size: var(--text-xs);
83+
color: var(--color-text-muted);
84+
margin: 0;
85+
}
86+
87+
.rightSection {
88+
display: flex;
89+
gap: var(--space-4);
90+
}

src/components/Layout/Header.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/**
2+
* Header Component
3+
* Main application header with navigation
4+
*/
5+
6+
import type { ReactNode } from 'react';
7+
import { useNavigation, isModuleView } from '../../contexts';
8+
import { MODULE_REGISTRY } from '../../types';
9+
import styles from './Header.module.css';
10+
11+
interface HeaderProps {
12+
moduleNav?: ReactNode;
13+
}
14+
15+
export function Header({ moduleNav }: HeaderProps) {
16+
const { currentView, goToHub } = useNavigation();
17+
const isInModule = isModuleView(currentView);
18+
const moduleConfig = isInModule ? MODULE_REGISTRY[currentView] : null;
19+
20+
return (
21+
<header className={styles.header}>
22+
<div className={styles.leftSection}>
23+
{/* Back Button */}
24+
{isInModule && (
25+
<button onClick={goToHub} className={styles.backButton}>
26+
<svg
27+
className={styles.backIcon}
28+
fill="none"
29+
stroke="currentColor"
30+
viewBox="0 0 24 24"
31+
>
32+
<path
33+
strokeLinecap="round"
34+
strokeLinejoin="round"
35+
strokeWidth={2}
36+
d="M15 19l-7-7 7-7"
37+
/>
38+
</svg>
39+
<span>Hub</span>
40+
</button>
41+
)}
42+
43+
{/* Logo & Title */}
44+
<div className={styles.branding}>
45+
<div className={styles.logo}>J</div>
46+
<div className={styles.titleGroup}>
47+
<h1 className={styles.title}>
48+
{moduleConfig?.title || 'Java Engineering Masterclass'}
49+
</h1>
50+
<p className={styles.subtitle}>
51+
{moduleConfig ? 'Module Active' : 'Interactive Advanced Concepts'}
52+
</p>
53+
</div>
54+
</div>
55+
</div>
56+
57+
{/* Module Navigation */}
58+
{isInModule && moduleNav && (
59+
<div className={styles.rightSection}>{moduleNav}</div>
60+
)}
61+
</header>
62+
);
63+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.appContainer {
2+
display: flex;
3+
flex-direction: column;
4+
height: 100vh;
5+
overflow: hidden;
6+
}
7+
8+
.mainContent {
9+
flex: 1;
10+
display: flex;
11+
overflow: hidden;
12+
position: relative;
13+
background-color: var(--color-bg-primary);
14+
}

src/components/Layout/Layout.tsx

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Layout Component
3+
* Main application layout wrapper
4+
*/
5+
6+
import type { ReactNode } from 'react';
7+
import { Header } from './Header';
8+
import styles from './Layout.module.css';
9+
10+
interface LayoutProps {
11+
children: ReactNode;
12+
moduleNav?: ReactNode;
13+
}
14+
15+
export function Layout({ children, moduleNav }: LayoutProps) {
16+
return (
17+
<div className={styles.appContainer}>
18+
<Header moduleNav={moduleNav} />
19+
<main className={styles.mainContent}>{children}</main>
20+
</div>
21+
);
22+
}

src/components/Layout/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { Header } from './Header';
2+
export { Layout } from './Layout';
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
.button {
2+
display: inline-flex;
3+
align-items: center;
4+
justify-content: center;
5+
gap: var(--space-2);
6+
border-radius: var(--radius-lg);
7+
font-weight: 600;
8+
transition: all var(--transition-fast);
9+
cursor: pointer;
10+
border: none;
11+
outline: none;
12+
}
13+
14+
.button:disabled {
15+
opacity: 0.5;
16+
cursor: not-allowed;
17+
}
18+
19+
/* Sizes */
20+
.sm {
21+
padding: var(--space-2) var(--space-3);
22+
font-size: var(--text-xs);
23+
}
24+
25+
.md {
26+
padding: var(--space-3) var(--space-4);
27+
font-size: var(--text-sm);
28+
}
29+
30+
.lg {
31+
padding: var(--space-4) var(--space-6);
32+
font-size: var(--text-base);
33+
}
34+
35+
/* Variants */
36+
.primary {
37+
background-color: #2563eb;
38+
color: white;
39+
}
40+
41+
.primary:hover:not(:disabled) {
42+
background-color: #3b82f6;
43+
}
44+
45+
.success {
46+
background-color: #059669;
47+
color: white;
48+
}
49+
50+
.success:hover:not(:disabled) {
51+
background-color: #10b981;
52+
}
53+
54+
.danger {
55+
background-color: #dc2626;
56+
color: white;
57+
}
58+
59+
.danger:hover:not(:disabled) {
60+
background-color: #ef4444;
61+
}
62+
63+
.warning {
64+
background-color: #d97706;
65+
color: white;
66+
}
67+
68+
.warning:hover:not(:disabled) {
69+
background-color: #f59e0b;
70+
}
71+
72+
.ghost {
73+
background-color: transparent;
74+
color: var(--color-text-secondary);
75+
border: 1px solid var(--color-border-default);
76+
}
77+
78+
.ghost:hover:not(:disabled) {
79+
color: var(--color-text-primary);
80+
border-color: var(--color-border-hover);
81+
}
82+
83+
.fullWidth {
84+
width: 100%;
85+
}

src/components/UI/Button.tsx

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Button Component
3+
* Reusable button with variants
4+
*/
5+
6+
import type { ButtonHTMLAttributes, ReactNode } from 'react';
7+
import styles from './Button.module.css';
8+
9+
type ButtonVariant = 'primary' | 'success' | 'danger' | 'ghost' | 'warning';
10+
type ButtonSize = 'sm' | 'md' | 'lg';
11+
12+
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
13+
variant?: ButtonVariant;
14+
size?: ButtonSize;
15+
fullWidth?: boolean;
16+
children: ReactNode;
17+
}
18+
19+
export function Button({
20+
variant = 'primary',
21+
size = 'md',
22+
fullWidth = false,
23+
children,
24+
className = '',
25+
...props
26+
}: ButtonProps) {
27+
const classes = [
28+
styles.button,
29+
styles[variant],
30+
styles[size],
31+
fullWidth ? styles.fullWidth : '',
32+
className,
33+
]
34+
.filter(Boolean)
35+
.join(' ');
36+
37+
return (
38+
<button className={classes} {...props}>
39+
{children}
40+
</button>
41+
);
42+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
.console {
2+
flex: 1;
3+
background: #000000;
4+
border-radius: var(--radius-md);
5+
padding: var(--space-3);
6+
font-family: var(--font-mono);
7+
font-size: var(--text-xs);
8+
overflow-y: auto;
9+
color: var(--color-text-secondary);
10+
min-height: 150px;
11+
}
12+
13+
.emptyState {
14+
color: var(--color-text-muted);
15+
font-style: italic;
16+
}
17+
18+
.line {
19+
border-left: 2px solid transparent;
20+
padding-left: var(--space-2);
21+
margin-bottom: var(--space-1);
22+
display: flex;
23+
gap: var(--space-2);
24+
line-height: 1.5;
25+
}
26+
27+
.info {
28+
border-color: var(--color-info);
29+
}
30+
31+
.warn {
32+
border-color: var(--color-warning);
33+
}
34+
35+
.error {
36+
border-color: var(--color-error);
37+
}
38+
39+
.success {
40+
border-color: var(--color-success);
41+
}
42+
43+
.timestamp {
44+
opacity: 0.5;
45+
font-size: 10px;
46+
flex-shrink: 0;
47+
}
48+
49+
.message {
50+
word-break: break-word;
51+
}

0 commit comments

Comments
 (0)