Skip to content

Commit 69eb4d5

Browse files
authored
Feat/config menu & shortcuts (#156)
![image](https://github.com/user-attachments/assets/23f926e0-bba7-471c-a9ea-cc1099af258f) TODO: refactor index.ts
1 parent 20786c2 commit 69eb4d5

File tree

17 files changed

+664
-59
lines changed

17 files changed

+664
-59
lines changed

src/config.ts

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
import { GlobalContext } from "./context";
2+
import { Colors } from "./utils";
3+
4+
export class ConfigModal {
5+
private ctx: GlobalContext;
6+
private modalOverlay: HTMLDivElement | null;
7+
private modalContent: HTMLDivElement | null;
8+
private closeBtn: HTMLSpanElement | null;
9+
private saveSettingsButton: HTMLButtonElement | null;
10+
private colorPicker: HTMLInputElement | null;
11+
private selectedColor: number; // Stores the actual selected color as a number
12+
private tempColor: number; // Temporary color for selection
13+
14+
constructor(ctx: GlobalContext) {
15+
this.ctx = ctx;
16+
this.modalOverlay = null;
17+
this.modalContent = null;
18+
this.closeBtn = null;
19+
this.saveSettingsButton = null;
20+
this.colorPicker = null;
21+
this.selectedColor = Colors.Violet; // Default saved color
22+
this.tempColor = this.selectedColor; // Temporary color for selection
23+
24+
this.createModal();
25+
this.setupEventListeners();
26+
}
27+
28+
private createModal() {
29+
const modalContainer = document.getElementById("settingsModal");
30+
31+
if (!modalContainer) {
32+
console.error("Modal container not found.");
33+
return;
34+
}
35+
36+
modalContainer.innerHTML = `
37+
<div class="modal-overlay">
38+
<div class="modal-content">
39+
<span class="close">&times;</span>
40+
<h2>Settings & Shortcuts</h2>
41+
42+
<div class="modal-body">
43+
<!-- Bloque de Shortcuts -->
44+
<div class="shortcuts-container">
45+
<h3>Keyboard Shortcuts</h3>
46+
<div class="scrollable-content">
47+
<ul class="shortcuts-list">
48+
<li><strong>[C]</strong> - Connect devices</li>
49+
<li><strong>[H]</strong> - Open Help</li>
50+
<li><strong>[Delete] / [Backspace]</strong> - Delete selected element</li>
51+
<li><strong>[Space]</strong> - Pause/resume simulation</li>
52+
<li><strong>[Ctrl + Z]</strong> - Undo</li>
53+
<li><strong>[Ctrl + Y]</strong> - Redo</li>
54+
<li><strong>[N]</strong> - Create a new network</li>
55+
<li><strong>[S]</strong> - Save your network</li>
56+
<li><strong>[L]</strong> - Load a saved network</li>
57+
<li><strong>[P]</strong> - Print the current network</li>
58+
</ul>
59+
</div>
60+
</div>
61+
62+
<!-- Bloque de Settings -->
63+
<div class="settings-container">
64+
<h3>General Settings</h3>
65+
<div class="scrollable-content">
66+
<ul class="settings-list">
67+
<li class="setting-item">
68+
<label for="colorPicker">Highlighter Color</label>
69+
<input type="color" id="colorPicker">
70+
</li>
71+
<li class="setting-item">
72+
<label for="autoConnections">Auto Connections</label>
73+
<input type="checkbox" id="autoConnections" class="switch-input">
74+
</li>
75+
<li class="setting-item">
76+
<label for="autoConnections">Config_1</label>
77+
<input type="checkbox" id="Config_1" class="switch-input">
78+
</li>
79+
<li class="setting-item">
80+
<label for="autoConnections">Config_2</label>
81+
<input type="checkbox" id="Config_2" class="switch-input">
82+
</li>
83+
<li class="setting-item">
84+
<label for="autoConnections">Config_3</label>
85+
<input type="checkbox" id="Config_3" class="switch-input">
86+
</li>
87+
<li class="setting-item">
88+
<label for="autoConnections">Config_4</label>
89+
<input type="checkbox" id="Config_4" class="switch-input">
90+
</li>
91+
<li class="setting-item">
92+
<label for="autoConnections">Config_5</label>
93+
<input type="checkbox" id="Config_5" class="switch-input">
94+
</li>
95+
</ul>
96+
</div>
97+
</div>
98+
</div>
99+
100+
<!-- Botón Guardar -->
101+
<button id="saveSettings" class="save-button">Save Settings</button>
102+
</div>
103+
</div>
104+
`;
105+
106+
// Capture element references
107+
this.modalOverlay = document.querySelector(
108+
".modal-overlay",
109+
) as HTMLDivElement;
110+
this.modalContent = document.querySelector(
111+
".modal-content",
112+
) as HTMLDivElement;
113+
this.closeBtn = document.querySelector(".close") as HTMLSpanElement;
114+
this.saveSettingsButton = document.getElementById(
115+
"saveSettings",
116+
) as HTMLButtonElement;
117+
this.colorPicker = document.getElementById(
118+
"colorPicker",
119+
) as HTMLInputElement;
120+
}
121+
122+
private setupEventListeners() {
123+
if (
124+
!this.modalOverlay ||
125+
!this.modalContent ||
126+
!this.closeBtn ||
127+
!this.saveSettingsButton ||
128+
!this.colorPicker
129+
) {
130+
console.error("Some modal elements were not found.");
131+
return;
132+
}
133+
134+
// Event to close the modal when clicking the "X" button
135+
this.closeBtn.onclick = () => this.close();
136+
137+
// Event to close the modal when clicking outside of it
138+
this.modalOverlay.onclick = (event) => {
139+
if (event.target === this.modalOverlay) this.close();
140+
};
141+
142+
// Event to save settings and apply selected color
143+
this.saveSettingsButton.onclick = () => {
144+
this.saveSettings();
145+
this.close();
146+
};
147+
148+
// Event to update temp color without saving it
149+
this.colorPicker.oninput = () => {
150+
if (this.colorPicker) {
151+
this.tempColor = this.hexToNumber(this.colorPicker.value);
152+
}
153+
};
154+
}
155+
156+
public open() {
157+
if (this.modalOverlay && this.modalContent) {
158+
// Reset tempColor to the last saved color when opening
159+
this.tempColor = this.selectedColor;
160+
161+
// Update color picker to reflect the saved color
162+
if (this.colorPicker) {
163+
this.colorPicker.value = this.toHex(this.selectedColor);
164+
}
165+
166+
this.modalOverlay.style.display = "flex"; // Make it visible first
167+
setTimeout(() => {
168+
this.modalOverlay?.classList.add("show");
169+
this.modalContent?.classList.add("show");
170+
}, 10); // Small delay for the animation to work properly
171+
}
172+
}
173+
174+
public close() {
175+
// Reset tempColor and revert picker to saved color
176+
this.tempColor = this.selectedColor;
177+
if (this.colorPicker) {
178+
this.colorPicker.value = this.toHex(this.selectedColor);
179+
}
180+
181+
if (this.modalOverlay && this.modalContent) {
182+
this.modalOverlay.classList.remove("show");
183+
this.modalContent.classList.remove("show");
184+
185+
setTimeout(() => {
186+
if (this.modalOverlay) {
187+
this.modalOverlay.style.display = "none"; // Hide after animation
188+
}
189+
}, 300);
190+
}
191+
}
192+
193+
private saveSettings() {
194+
// Save the temp color as the actual selected color
195+
if (this.tempColor != this.selectedColor) {
196+
this.selectedColor = this.tempColor;
197+
this.ctx.change_select_color(this.selectedColor);
198+
}
199+
200+
console.log("Settings saved. Applied color:", this.selectedColor);
201+
}
202+
203+
// Convert a number (0xRRGGBB) to a hex string ("#RRGGBB")
204+
private toHex(color: number): string {
205+
return `#${color.toString(16).padStart(6, "0")}`;
206+
}
207+
208+
// Convert a hex string ("#RRGGBB") to a number (0xRRGGBB)
209+
private hexToNumber(hex: string): number {
210+
return parseInt(hex.replace("#", ""), 16);
211+
}
212+
213+
// Method to retrieve the selected color (if needed externally)
214+
public getSelectedColor(): number {
215+
return this.selectedColor;
216+
}
217+
}

src/context.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { IpAddress, IpAddressGenerator } from "./packets/ip";
1111
import { layerFromName } from "./types/devices/layer";
1212
import { SpeedMultiplier } from "./types/devices/speedMultiplier";
1313
import { MacAddress, MacAddressGenerator } from "./packets/ethernet";
14+
import { Colors } from "./utils";
1415

1516
export class GlobalContext {
1617
private viewport: Viewport = null;
@@ -20,8 +21,10 @@ export class GlobalContext {
2021
private saveIntervalId: NodeJS.Timeout | null = null;
2122
private ipGenerator: IpAddressGenerator;
2223
private macGenerator: MacAddressGenerator;
24+
private selectColor: number;
2325

2426
constructor(viewport: Viewport) {
27+
this.selectColor = Colors.Violet;
2528
this.viewport = viewport;
2629

2730
// Sets the initial datagraph and viewgraph
@@ -168,4 +171,12 @@ export class GlobalContext {
168171
console.log("DataGraph");
169172
console.log(this.datagraph);
170173
}
174+
175+
public change_select_color(color: number) {
176+
this.selectColor = color;
177+
}
178+
179+
public get_select_color() {
180+
return this.selectColor;
181+
}
171182
}

src/index.ejs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
<body>
88
<div id="top-bar">
99
<button id="new-button" class="new-button" title="New">New</button>
10-
<button id="save-button" class="save-button" title="Save">Save</button>
10+
<button id="save-button" class="save-button" title="Save">Save</button>
1111
<button id="load-button" class="load-button" title="Load">Load</button>
1212
<button id="print-button" class="load-button" title="Print">Print</button>
1313
<div id="app-title">GEduNet</div>
14+
<button id="help-button" class="help-button" title="Help">?</button>
1415
</div>
1516

17+
<div id="settingsModal"></div>
18+
1619
<div id="bottom-screen" class="row container">
1720
<div id="left-bar" class="left-bar"></div>
1821

0 commit comments

Comments
 (0)