Skip to content

Commit 2a980fb

Browse files
authored
Refactor/UI responsive (#132)
This PR improves the responsiveness of the app to ensure a seamless experience across different screen sizes.
1 parent 14cd7c5 commit 2a980fb

17 files changed

+789
-488
lines changed

src/index.ejs

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,47 @@
1212
<button id="print-button" class="load-button" title="Print">Print</button>
1313
<div id="app-title">GEduNet</div>
1414
</div>
15+
1516
<div id="bottom-screen" class="row container">
1617
<div id="left-bar" class="left-bar"></div>
18+
1719
<div class="canvas-container">
18-
<canvas id="canvas"></canvas>
19-
<button id="pause-button" class="pause-button" title="Pause"></button>
20-
<i id="undo-button" class="undo-button" title="Undo"></i>
21-
<i id="redo-button" class="redo-button" title="Redo"></i>
22-
<div class="wheel-container">
23-
<div class="wheel-label">Speed</div>
24-
<div class="circular-slider">
25-
<input
26-
type="range"
27-
id="speed-wheel"
28-
min="0.5"
29-
max="4"
30-
step="0.1"
31-
value="1"
32-
/>
20+
<div id="canvas-wrapper">
21+
<canvas id="canvas"></canvas>
22+
23+
<!-- Contenedor de controles en la izquierda -->
24+
<div id="left-controls">
25+
<button id="pause-button" class="pause-button" title="Pause"></button>
26+
<div class="undo-redo-container">
27+
<i id="undo-button" class="undo-button" title="Undo"></i>
28+
<i id="redo-button" class="redo-button" title="Redo"></i>
29+
</div>
30+
</div>
31+
32+
<!-- Contenedor de controles en la derecha -->
33+
<div id="right-controls">
34+
<div class="wheel-container">
35+
<div class="wheel-label">Speed</div>
36+
<div class="circular-slider">
37+
<input type="range" id="speed-wheel" min="0.5" max="4" step="0.1" value="1" />
38+
</div>
39+
<div class="value-display">1x</div>
40+
</div>
41+
42+
<div class="layer-container">
43+
<select id="layer-select" class="dropdown-menu">
44+
<option value="application">App Layer</option>
45+
<option value="transport">Transport Layer</option>
46+
<option value="network">Network Layer</option>
47+
<option value="link">Link Layer</option>
48+
</select>
49+
</div>
3350
</div>
34-
<div class="value-display">1x</div>
3551
</div>
36-
<select id="layer-select" class="dropdown-menu">
37-
<option value="application">App Layer</option>
38-
<option value="transport">Transport Layer</option>
39-
<option value="network">Network Layer</option>
40-
<option value="link">Link Layer</option>
41-
</select>
4252
</div>
53+
4354
<div id="right-bar" class="right-bar"></div>
4455
</div>
4556
</body>
4657
</html>
58+

src/index.ts

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Application, Assets } from "pixi.js";
2-
32
import {
43
deselectElement,
54
loadFromFile,
@@ -15,7 +14,6 @@ import { Viewport } from "./graphics/viewport";
1514
import { GlobalContext } from "./context";
1615

1716
// Assets
18-
// Doing this includes the file in the build
1917
import "./styles";
2018
import RouterSvg from "./assets/router.svg";
2119
import SwitchSvg from "./assets/switch.svg";
@@ -43,7 +41,11 @@ async function loadAssets(otherPromises: Promise<void>[]) {
4341

4442
// IIFE to avoid errors
4543
(async () => {
46-
// Initialization
44+
const canvasPlaceholder = document.getElementById("canvas");
45+
const lBar = document.getElementById("left-bar");
46+
const rBar = document.getElementById("right-bar");
47+
const tBar = document.getElementById("top-bar");
48+
4749
const app = new Application();
4850
const appInitPromise = app.init({
4951
width: window.innerWidth,
@@ -52,47 +54,61 @@ async function loadAssets(otherPromises: Promise<void>[]) {
5254
autoDensity: true,
5355
antialias: true,
5456
});
55-
await loadAssets([appInitPromise]);
5657

57-
const canvasPlaceholder = document.getElementById("canvas");
58+
await loadAssets([appInitPromise]);
5859
canvasPlaceholder.replaceWith(app.canvas);
5960

60-
// Background container initialization
6161
const viewport = new Viewport(app.renderer.events);
6262
app.stage.addChild(viewport);
6363

64-
// Context initialization
6564
const ctx = new GlobalContext(viewport);
6665

67-
// Get the layer’s menu
6866
const layerSelect = document.getElementById(
6967
"layer-select",
7068
) as HTMLSelectElement;
71-
7269
layerSelect.value = layerToName(ctx.getCurrentLayer());
7370

74-
// Initialize RightBar
7571
RightBar.getInstance();
7672

77-
// Left bar logic
7873
const leftBar = LeftBar.getFrom(document, ctx);
7974
leftBar.setButtonsByLayer(layerSelect.value);
8075

81-
const lBar = document.getElementById("left-bar");
82-
const rBar = document.getElementById("right-bar");
83-
const tBar = document.getElementById("top-bar");
84-
85-
// Resize logic
8676
function resize() {
87-
const newWidth = window.innerWidth - lBar.offsetWidth - rBar.offsetWidth;
88-
const newHeight = window.innerHeight - tBar.offsetHeight;
77+
// Check if the layout should be stacked (based on window width)
78+
const isStacked = window.innerWidth <= 768;
79+
80+
// Determine the size of the left bar (width if not stacked, height if stacked)
81+
const leftSize = isStacked
82+
? lBar?.offsetHeight || 0
83+
: lBar?.offsetWidth || 0;
84+
85+
// Determine the size of the right bar (width if not stacked, height if stacked)
86+
const rightSize = isStacked
87+
? rBar?.offsetHeight || 0
88+
: rBar?.offsetWidth || 0;
89+
90+
// Get the height of the top bar
91+
const topHeight = tBar?.offsetHeight || 0;
92+
93+
// Calculate the new width and height for the canvas
94+
// If stacked, reduce height by left and right sizes; otherwise, reduce width
95+
let newWidth = window.innerWidth - (isStacked ? 0 : leftSize + rightSize);
96+
let newHeight =
97+
window.innerHeight - (isStacked ? leftSize + rightSize : topHeight);
98+
99+
// Ensure minimum dimensions to prevent the canvas from becoming too small
100+
newWidth = Math.max(300, newWidth);
101+
newHeight = Math.max(200, newHeight);
89102

103+
// Log the new dimensions for debugging
104+
console.log("📏 Resizing canvas to:", newWidth, "x", newHeight);
105+
106+
// Resize the app renderer and viewport accordingly
90107
app.renderer.resize(newWidth, newHeight);
91108
viewport.resize(newWidth, newHeight);
92109
}
93110

94111
resize();
95-
96112
window.addEventListener("resize", resize);
97113

98114
const newButton = document.getElementById("new-button");
@@ -266,5 +282,21 @@ async function loadAssets(otherPromises: Promise<void>[]) {
266282
// Initialize with default value
267283
valueDisplay.textContent = `${(speedWheel as HTMLInputElement).value}x`;
268284

269-
console.log("initialized!");
285+
// Get the element with the ID "canvas-wrapper"
286+
const canvasWrapper = document.getElementById("canvas-wrapper");
287+
288+
// Check if the element exists before adding event listeners
289+
if (canvasWrapper) {
290+
// When the mouse enters the canvas wrapper, prevent scrolling
291+
canvasWrapper.addEventListener("mouseenter", () => {
292+
document.body.classList.add("no-scroll");
293+
});
294+
295+
// When the mouse leaves the canvas wrapper, allow scrolling again
296+
canvasWrapper.addEventListener("mouseleave", () => {
297+
document.body.classList.remove("no-scroll");
298+
});
299+
}
300+
301+
console.log("✅ Initialized!");
270302
})();

src/styles/buttons.css

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/styles/canvas.css

Lines changed: 23 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,29 @@
1-
/* canvas-container.css */
2-
3-
/* Styles for the main canvas container */
1+
/* 🔹 Canvas container */
42
.canvas-container {
5-
flex: 1; /* Fills the remaining space in the layout */
6-
display: flex; /* Uses flexbox to organize content */
7-
position: relative; /* Positions elements relative to the container */
8-
background-color: #a09f9f; /* Light gray background for the canvas area */
9-
}
10-
11-
/* Estilo del selector compacto y minimalista */
12-
#layer-select {
13-
position: absolute; /* Permite colocarlo sobre el canvas */
14-
top: 10px; /* Separación desde el borde superior */
15-
right: 10px; /* Separación desde el borde derecho */
16-
width: 160px; /* Reduce el ancho para un diseño más compacto */
17-
height: 30px; /* Altura más proporcional */
18-
padding: 0 15px; /* Espaciado horizontal más preciso */
19-
font-size: 14px; /* Tamaño del texto ajustado */
20-
font-family: "Arial", sans-serif; /* Fuente limpia y moderna */
21-
color: #ffffff; /* Texto blanco */
22-
background-color: #333333; /* Fondo oscuro elegante */
23-
border: 1px solid #666666; /* Borde gris */
24-
border-radius: 6px; /* Bordes ligeramente redondeados */
25-
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.2); /* Sombra suave */
26-
cursor: pointer; /* Cursor interactivo */
27-
transition: all 0.3s ease; /* Transiciones suaves */
28-
appearance: none; /* Oculta el estilo nativo */
29-
background-image: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAiIGhlaWdodD0iNSIgdmlld0JveD0iMCAwIDEwIDUiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTEgMUw1IDRMMTAgMUgxWiIgZmlsbD0iI0NDQ0NDQyIvPjwvc3ZnPg=="); /* Flecha personalizada en gris */
30-
background-repeat: no-repeat; /* Evita repetir la flecha */
31-
background-position: right 10px center; /* Coloca la flecha a la derecha */
32-
background-size: 10px; /* Tamaño proporcional de la flecha */
33-
}
34-
35-
/* Hover en el selector */
36-
#layer-select:hover {
37-
background-color: #444444; /* Fondo ligeramente más claro */
38-
border-color: #888888; /* Gris más claro */
39-
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.4); /* Sombra más pronunciada */
40-
}
41-
42-
/* Focus en el selector */
43-
#layer-select:focus {
44-
outline: none; /* Elimina el contorno predeterminado */
45-
box-shadow: 0 0 8px 2px rgba(136, 136, 136, 0.5); /* Resplandor gris */
3+
flex: 1; /* Allows the canvas to take up all available space */
4+
display: flex; /* Uses flexbox for layout */
5+
position: relative; /* Enables absolute positioning for child elements */
6+
background-color: #a09f9f; /* Neutral background color */
7+
overflow: hidden; /* Prevents overflow issues */
8+
min-height: 0; /* Ensures flexibility in height */
9+
width: 100%; /* Takes full width of the parent container */
4610
}
4711

48-
/* Opciones del desplegable */
49-
#layer-select option {
50-
font-size: 13px; /* Texto más compacto */
51-
color: #ffffff; /* Texto blanco */
52-
background-color: #292b2c; /* Fondo oscuro para las opciones */
53-
border: none; /* Sin bordes */
54-
padding: 5px; /* Espaciado interno ajustado */
55-
cursor: pointer; /* Interactividad */
12+
/* 🔹 Wrapper to ensure the canvas occupies all available space */
13+
#canvas-wrapper {
14+
position: absolute; /* Positions the wrapper to fill the container */
15+
top: 0;
16+
left: 0;
17+
width: 100%; /* Ensures full width */
18+
height: 100%; /* Ensures full height */
19+
display: flex; /* Uses flexbox for potential child alignment */
5620
}
5721

58-
/* Hover en las opciones del desplegable */
59-
#layer-select option:hover {
60-
background-color: #444444; /* Fondo más claro en hover */
61-
color: #ffffff; /* Mantiene el texto blanco */
22+
/* 🔹 Canvas occupying the entire space */
23+
#canvas {
24+
width: 100%; /* Full width */
25+
height: 100%; /* Full height */
26+
display: block; /* Ensures it behaves as a block element */
27+
min-width: 1px !important; /* 🔥 Prevents negative values */
28+
min-height: 1px !important; /* 🔥 Ensures a valid minimum size */
6229
}

src/styles/controls.css

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/* 🔹 Left controls container */
2+
#left-controls {
3+
display: flex; /* Uses flexbox for layout */
4+
align-items: center; /* Vertically aligns elements */
5+
gap: 1vw; /* Adds spacing between elements */
6+
flex-wrap: nowrap; /* Prevents wrapping into multiple lines */
7+
justify-content: flex-start; /* Keeps alignment to the left */
8+
position: absolute; /* Positions element absolutely */
9+
top: 1.5vh; /* Places it slightly below the top */
10+
left: 2vw; /* Positions it from the left */
11+
}
12+
13+
/* 🔹 Right controls container */
14+
#right-controls {
15+
display: flex; /* Uses flexbox */
16+
align-items: center; /* Centers elements vertically */
17+
gap: 6vw; /* Adds a large space between elements */
18+
flex-wrap: wrap; /* Allows wrapping to prevent overlapping */
19+
justify-content: flex-end; /* Aligns elements to the right */
20+
max-width: 90vw; /* Ensures controls do not exceed viewport width */
21+
position: absolute; /* Positions element absolutely */
22+
top: 1.5vh; /* Aligns it near the top */
23+
right: 2vw; /* Positions it from the right */
24+
}
25+
26+
/* 🔹 Adjustments for small screens */
27+
@media (max-width: 768px) {
28+
#left-controls {
29+
gap: 1vw; /* Keeps spacing compact */
30+
flex-wrap: wrap; /* Allows wrapping if space is limited */
31+
}
32+
33+
/* 🔹 Smaller pause button on small screens */
34+
.pause-button {
35+
width: 5vh;
36+
height: 5vh;
37+
}
38+
39+
/* 🔹 Smaller undo and redo buttons */
40+
.undo-button,
41+
.redo-button {
42+
width: 4.5vh;
43+
height: 4.5vh;
44+
}
45+
46+
/* 🔹 Undo/Redo container adjustments */
47+
.undo-redo-container {
48+
margin-left: 1vw; /* Adds slight left margin */
49+
flex-wrap: nowrap; /* Prevents elements from rearranging */
50+
}
51+
52+
/* 🔹 Right controls adjustments */
53+
#right-controls {
54+
gap: 3vw; /* Reduces spacing between controls */
55+
flex-wrap: wrap; /* Allows wrapping for better fit */
56+
}
57+
}

0 commit comments

Comments
 (0)