Teapack1 commited on
Commit
2004aa8
1 Parent(s): deeb85c
Files changed (8) hide show
  1. Dockerfile +2 -0
  2. database.db +0 -0
  3. main.py +16 -7
  4. models.py +1 -0
  5. static/app.js +105 -14
  6. static/styles.css +148 -78
  7. templates/edit_cables.html +2 -2
  8. templates/index.html +36 -21
Dockerfile CHANGED
@@ -6,4 +6,6 @@ COPY . .
6
 
7
  RUN pip install --no-cache-dir -r requirements.txt
8
 
 
 
9
  CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
 
6
 
7
  RUN pip install --no-cache-dir -r requirements.txt
8
 
9
+ EXPOSE 7860
10
+
11
  CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
database.db CHANGED
Binary files a/database.db and b/database.db differ
 
main.py CHANGED
@@ -4,6 +4,7 @@ from fastapi.staticfiles import StaticFiles
4
  from fastapi.templating import Jinja2Templates
5
  from sqlalchemy.orm import Session
6
  from pydantic import BaseModel
 
7
  from models import Base, Cable, SessionLocal, init_db
8
 
9
  app = FastAPI()
@@ -22,6 +23,9 @@ class VoltageDropRequest(BaseModel):
22
  length: float
23
  cable_type: str
24
 
 
 
 
25
  def get_db():
26
  db = SessionLocal()
27
  try:
@@ -30,7 +34,9 @@ def get_db():
30
  db.close()
31
 
32
  def calculate_voltage_drop(voltage, load, length, resistance):
33
- return voltage - (load * length * resistance)
 
 
34
 
35
  @app.get("/", response_class=HTMLResponse)
36
  async def read_root(request: Request, db: Session = Depends(get_db)):
@@ -38,12 +44,15 @@ async def read_root(request: Request, db: Session = Depends(get_db)):
38
  return templates.TemplateResponse("index.html", {"request": request, "cables": cables})
39
 
40
  @app.post("/calculate")
41
- async def calculate(request: VoltageDropRequest, db: Session = Depends(get_db)):
42
- cable = db.query(Cable).filter(Cable.type == request.cable_type).first()
43
- if not cable:
44
- raise HTTPException(status_code=400, detail="Invalid cable type")
45
- result = calculate_voltage_drop(request.voltage, request.load, request.length, cable.resistance)
46
- return {"voltage_drop": result}
 
 
 
47
 
48
  @app.get("/edit_cables", response_class=HTMLResponse)
49
  async def edit_cables(request: Request, db: Session = Depends(get_db)):
 
4
  from fastapi.templating import Jinja2Templates
5
  from sqlalchemy.orm import Session
6
  from pydantic import BaseModel
7
+ from typing import List
8
  from models import Base, Cable, SessionLocal, init_db
9
 
10
  app = FastAPI()
 
23
  length: float
24
  cable_type: str
25
 
26
+ class MultipleCablesRequest(BaseModel):
27
+ cables: List[VoltageDropRequest]
28
+
29
  def get_db():
30
  db = SessionLocal()
31
  try:
 
34
  db.close()
35
 
36
  def calculate_voltage_drop(voltage, load, length, resistance):
37
+ voltage_drop = load * length * resistance
38
+ final_voltage = voltage - voltage_drop
39
+ return final_voltage
40
 
41
  @app.get("/", response_class=HTMLResponse)
42
  async def read_root(request: Request, db: Session = Depends(get_db)):
 
44
  return templates.TemplateResponse("index.html", {"request": request, "cables": cables})
45
 
46
  @app.post("/calculate")
47
+ async def calculate(request: MultipleCablesRequest, db: Session = Depends(get_db)):
48
+ results = []
49
+ for cable_request in request.cables:
50
+ cable = db.query(Cable).filter(Cable.type == cable_request.cable_type).first()
51
+ if not cable:
52
+ raise HTTPException(status_code=400, detail="Invalid cable type")
53
+ voltage_drop = calculate_voltage_drop(cable_request.voltage, cable_request.load, cable_request.length, cable.resistance)
54
+ results.append({"voltage_drop": voltage_drop})
55
+ return results
56
 
57
  @app.get("/edit_cables", response_class=HTMLResponse)
58
  async def edit_cables(request: Request, db: Session = Depends(get_db)):
models.py CHANGED
@@ -2,6 +2,7 @@ from sqlalchemy import Column, Integer, String, Float, create_engine
2
  from sqlalchemy.ext.declarative import declarative_base
3
  from sqlalchemy.orm import sessionmaker
4
 
 
5
  DATABASE_URL = "sqlite:///./database.db"
6
 
7
  Base = declarative_base()
 
2
  from sqlalchemy.ext.declarative import declarative_base
3
  from sqlalchemy.orm import sessionmaker
4
 
5
+ #DATABASE_URL = "sqlite:///:memory:?check_same_thread=False" # Use this for in-memory database
6
  DATABASE_URL = "sqlite:///./database.db"
7
 
8
  Base = declarative_base()
static/app.js CHANGED
@@ -1,6 +1,10 @@
1
  document.addEventListener('DOMContentLoaded', function() {
2
  const form = document.getElementById('calculator-form');
 
 
3
  const calculateButton = document.querySelector('.btn-calculate');
 
 
4
 
5
  // Function to check if all form fields are filled
6
  function checkFormValidity() {
@@ -14,33 +18,120 @@ document.addEventListener('DOMContentLoaded', function() {
14
  }
15
  }
16
 
17
- // Listen for input events on the form to trigger validation
18
- form.addEventListener('input', checkFormValidity);
 
 
 
 
 
 
 
 
 
 
19
 
20
- // Initially check the form validity on page load
21
- checkFormValidity();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
 
23
  // Handle form submission
24
  form.addEventListener('submit', async function(event) {
25
  event.preventDefault();
26
 
27
- const formData = new FormData(event.target);
28
- const data = {
29
- voltage: parseFloat(formData.get('voltage')),
30
- load: parseFloat(formData.get('load')),
31
- length: parseFloat(formData.get('length')),
32
- cable_type: formData.get('cable_type')
33
- };
 
 
 
 
 
 
 
34
 
 
35
  const response = await fetch('/calculate', {
36
  method: 'POST',
37
  headers: {
38
  'Content-Type': 'application/json'
39
  },
40
- body: JSON.stringify(data)
41
  });
42
 
43
- const result = await response.json();
44
- document.getElementById('result').innerText = `Result Voltage: ${result.voltage_drop} V`;
 
 
 
 
 
 
 
 
 
 
45
  });
 
 
 
 
 
46
  });
 
1
  document.addEventListener('DOMContentLoaded', function() {
2
  const form = document.getElementById('calculator-form');
3
+ const cableContainer = document.getElementById('cable-container');
4
+ const addCableButton = document.getElementById('add-cable');
5
  const calculateButton = document.querySelector('.btn-calculate');
6
+ let cableCount = 1;
7
+ const maxCables = 3;
8
 
9
  // Function to check if all form fields are filled
10
  function checkFormValidity() {
 
18
  }
19
  }
20
 
21
+ // Function to update the IDs and names of the inputs in each cable group
22
+ function updateCableGroupInputs() {
23
+ const cableGroups = document.querySelectorAll('.cable-group');
24
+ cableGroups.forEach((group, index) => {
25
+ group.querySelectorAll('input, select').forEach(input => {
26
+ // Update the id and name attributes to include the index
27
+ const baseName = input.name.split('[')[0]; // Get the base name without the index
28
+ input.name = `${baseName}[${index}]`;
29
+ input.id = `${baseName}-${index}`; // Update the id as well for accessibility
30
+ });
31
+ });
32
+ }
33
 
34
+ // Function to copy values from the first cable group
35
+ function copyInitialCableValues(newCableGroup) {
36
+ const initialCableGroup = document.querySelector('.cable-group');
37
+
38
+ // Copy values from the initial cable group to the new cable group
39
+ initialCableGroup.querySelectorAll('input, select').forEach((input, index) => {
40
+ const correspondingInput = newCableGroup.querySelectorAll('input, select')[index];
41
+ correspondingInput.value = input.value;
42
+ });
43
+ }
44
+
45
+ // Function to update the visibility of the remove buttons
46
+ function updateRemoveButtons() {
47
+ const removeButtons = document.querySelectorAll('.btn-remove-cable');
48
+ removeButtons.forEach(button => {
49
+ if (cableCount > 1) {
50
+ button.style.display = 'inline-block';
51
+ } else {
52
+ button.style.display = 'none';
53
+ }
54
+ });
55
+ }
56
+
57
+ // Add a new cable section
58
+ addCableButton.addEventListener('click', function() {
59
+ if (cableCount < maxCables) {
60
+ const newCableGroup = document.querySelector('.cable-group').cloneNode(true);
61
+
62
+ // Copy values from the initial cable group
63
+ copyInitialCableValues(newCableGroup);
64
+
65
+ // Append the new cable group to the container
66
+ cableContainer.appendChild(newCableGroup);
67
+ cableCount++;
68
+ updateCableGroupInputs();
69
+ updateRemoveButtons();
70
+ checkFormValidity();
71
+ }
72
+ if (cableCount >= maxCables) {
73
+ addCableButton.disabled = true;
74
+ }
75
+ });
76
+
77
+ // Remove a cable section
78
+ cableContainer.addEventListener('click', function(event) {
79
+ if (event.target.classList.contains('btn-remove-cable')) {
80
+ if (cableCount > 1) {
81
+ event.target.closest('.cable-group').remove();
82
+ cableCount--;
83
+ updateCableGroupInputs();
84
+ addCableButton.disabled = false;
85
+ updateRemoveButtons();
86
+ checkFormValidity();
87
+ }
88
+ }
89
+ });
90
 
91
  // Handle form submission
92
  form.addEventListener('submit', async function(event) {
93
  event.preventDefault();
94
 
95
+ const formData = new FormData(form);
96
+ const cablesData = [];
97
+
98
+ // Iterate over the form data and collect all cables
99
+ for (let i = 0; i < cableCount; i++) {
100
+ const voltage = parseFloat(formData.get(`voltage[${i}]`));
101
+ const load = parseFloat(formData.get(`load[${i}]`));
102
+ const length = parseFloat(formData.get(`length[${i}]`));
103
+ const cable_type = formData.get(`cable_type[${i}]`);
104
+
105
+ cablesData.push({ voltage, load, length, cable_type });
106
+ }
107
+
108
+ console.log("Sending cables data:", cablesData); // Debugging line
109
 
110
+ // Send the cables data to the backend
111
  const response = await fetch('/calculate', {
112
  method: 'POST',
113
  headers: {
114
  'Content-Type': 'application/json'
115
  },
116
+ body: JSON.stringify({ cables: cablesData })
117
  });
118
 
119
+ if (response.ok) {
120
+ const results = await response.json();
121
+
122
+ // Display the results
123
+ let resultsHtml = '';
124
+ results.forEach((result, index) => {
125
+ resultsHtml += `<p>Cable ${index + 1}: Voltage Drop: ${result.voltage_drop.toFixed(2)} V</p>`;
126
+ });
127
+ document.getElementById('result').innerHTML = resultsHtml;
128
+ } else {
129
+ console.error("Error:", response.statusText);
130
+ }
131
  });
132
+
133
+ // Initially check the form validity and update buttons on page load
134
+ form.addEventListener('input', checkFormValidity);
135
+ checkFormValidity();
136
+ updateRemoveButtons();
137
  });
static/styles.css CHANGED
@@ -1,11 +1,9 @@
 
1
  body {
2
  font-family: Arial, sans-serif;
3
- display: flex;
4
- flex-direction: column;
5
- align-items: center;
6
  margin: 0;
7
  padding: 0;
8
- background-color: #f8f9fa;
9
  }
10
 
11
  header {
@@ -18,68 +16,94 @@ header {
18
  padding: 20px 0;
19
  }
20
 
21
- .calculator-form {
22
- width: 100%;
23
- display: flex;
24
- flex-direction: column;
25
- }
26
-
27
  #logo {
28
  height: 50px;
29
  margin-right: 20px;
30
  }
31
 
32
- main {
 
 
 
 
33
  display: flex;
34
  flex-direction: column;
35
  align-items: center;
36
- margin-top: 30px;
37
  width: 100%;
38
- max-width: 600px;
39
  padding: 20px;
40
- background-color: white;
41
- box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
42
- border-radius: 8px;
43
  }
44
 
45
- .add-cable-section,
46
- .existing-cables-section {
 
 
47
  width: 100%;
48
- margin-bottom: 30px;
 
49
  }
50
 
51
- .add-cable-section h2,
52
- .existing-cables-section h2 {
53
- margin-bottom: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
54
  color: #343a40;
55
  }
56
 
57
  .form-row {
58
  display: flex;
59
- align-items: center;
60
  justify-content: space-between;
 
61
  margin-bottom: 15px;
 
62
  }
63
 
64
  .form-row label {
65
- flex-basis: 30%;
66
  font-weight: bold;
 
67
  }
68
 
69
- .form-row input {
70
- flex-basis: 65%;
 
71
  padding: 8px;
72
  font-size: 16px;
73
  border: 1px solid #ccc;
74
- border-radius: 8px;
 
 
75
  }
76
 
 
77
  .form-row select {
78
- flex-basis: 65%;
 
79
  padding: 8px;
80
  font-size: 16px;
81
  border: 1px solid #ccc;
82
- border-radius: 8px;
 
 
 
 
 
 
 
 
83
  }
84
 
85
  .btn {
@@ -89,88 +113,134 @@ main {
89
  border: none;
90
  color: white;
91
  border-radius: 4px;
 
92
  }
93
 
94
- .btn-add {
95
- background-color: #28a745;
96
- width: 100%;
97
  }
98
 
99
- .btn-save {
 
100
  background-color: #007bff;
101
- margin-right: 5px;
102
  }
103
 
104
- .btn-delete {
105
- background-color: #dc3545;
 
106
  }
107
 
108
- .btn-group {
109
- display: flex;
110
- justify-content: flex-end;
111
- margin-top: 10px;
112
  }
113
 
114
- .section-divider {
115
- margin: 40px 0;
116
- border: 0;
117
- border-top: 2px solid #dee2e6;
118
- width: 100%;
119
  }
120
 
121
- .cable-divider {
122
- margin: 20px 0;
123
- border: 0;
124
- border-top: 1px solid #dee2e6;
 
 
 
 
 
 
 
 
 
125
  width: 100%;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  }
127
 
128
  .btn-back {
129
  background-color: #007bff;
130
  color: white;
131
- padding: 10px 20px;
132
- font-size: 16px;
133
  text-align: center;
134
  text-decoration: none;
135
- margin-top: 30px;
136
- display: inline-block;
137
- border-radius: 5px;
138
- width: 100%;
139
  }
140
 
141
  .btn-back:hover {
142
  background-color: #0056b3;
143
  }
144
- .btn-calculate {
145
- background-color: #6c757d; /* Disabled state */
146
- color: white;
147
- padding: 10px 20px;
148
- font-size: 18px;
149
- border: none;
150
- cursor: not-allowed;
151
- border-radius: 4px;
152
- margin-top: 20px;
153
- width: 100%;
154
- text-align: center;
155
- transition: background-color 0.3s ease;
156
  }
157
 
158
- .btn-calculate.enabled {
159
- background-color: #28a745; /* Enabled state */
160
- cursor: pointer;
 
 
 
 
 
 
 
 
 
 
 
161
  }
162
 
163
- .btn-calculate:hover.enabled {
164
- background-color: #218838;
165
  }
166
 
167
- .result-display {
168
- margin-top: 30px;
169
- font-size: 24px;
170
- color: #28a745;
171
- text-align: center;
 
 
 
 
 
 
 
172
  padding: 20px;
173
- border-top: 2px solid #dee2e6;
 
 
 
 
 
 
174
  width: 100%;
 
175
  }
176
 
 
 
 
 
 
1
+ /* General Styles */
2
  body {
3
  font-family: Arial, sans-serif;
4
+ background-color: #f8f9fa;
 
 
5
  margin: 0;
6
  padding: 0;
 
7
  }
8
 
9
  header {
 
16
  padding: 20px 0;
17
  }
18
 
 
 
 
 
 
 
19
  #logo {
20
  height: 50px;
21
  margin-right: 20px;
22
  }
23
 
24
+ h1 {
25
+ margin: 0;
26
+ }
27
+
28
+ .calculator-main {
29
  display: flex;
30
  flex-direction: column;
31
  align-items: center;
32
+ margin: 30px auto;
33
  width: 100%;
34
+ max-width: 1200px;
35
  padding: 20px;
36
+ box-sizing: border-box;
 
 
37
  }
38
 
39
+ #cable-container {
40
+ display: flex;
41
+ gap: 20px;
42
+ justify-content: center;
43
  width: 100%;
44
+ margin-bottom: 20px;
45
+ flex-wrap: wrap; /* Allow wrapping for better responsiveness */
46
  }
47
 
48
+ .cable-group {
49
+ background-color: white;
50
+ padding: 20px;
51
+ border-radius: 8px;
52
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
53
+ box-sizing: border-box;
54
+ position: relative;
55
+ flex: auto; /* Let the items grow and shrink based on space */
56
+ max-width: 800px; /* Optional maximum width */
57
+ min-width: 500px; /* Optional minimum width */
58
+ }
59
+
60
+ .cable-group h2 {
61
+ text-align: center;
62
+ margin-top: 0;
63
  color: #343a40;
64
  }
65
 
66
  .form-row {
67
  display: flex;
 
68
  justify-content: space-between;
69
+ align-items: center;
70
  margin-bottom: 15px;
71
+ width: 100%;
72
  }
73
 
74
  .form-row label {
75
+ flex: 0 0 40%; /* Label takes up 40% of the row */
76
  font-weight: bold;
77
+ color: #343a40;
78
  }
79
 
80
+ .form-row input,
81
+ .form-row select {
82
+ flex: 1; /* Input takes up the remaining space */
83
  padding: 8px;
84
  font-size: 16px;
85
  border: 1px solid #ccc;
86
+ border-radius: 4px;
87
+ width: 100%;
88
+ box-sizing: border-box;
89
  }
90
 
91
+ /* Dropdown styling */
92
  .form-row select {
93
+ appearance: none;
94
+ background-color: #f8f9fa;
95
  padding: 8px;
96
  font-size: 16px;
97
  border: 1px solid #ccc;
98
+ border-radius: 4px;
99
+ width: 100%;
100
+ box-sizing: border-box;
101
+ }
102
+
103
+ .btn-group, .form-group {
104
+ display: flex;
105
+ justify-content: space-between;
106
+ width: 100%; /* Ensure buttons are aligned in one row */
107
  }
108
 
109
  .btn {
 
113
  border: none;
114
  color: white;
115
  border-radius: 4px;
116
+ transition: background-color 0.3s ease;
117
  }
118
 
119
+ .btn:hover {
120
+ opacity: 0.9;
 
121
  }
122
 
123
+ .btn-add,
124
+ .btn-add-cable {
125
  background-color: #007bff;
126
+ margin-right: 10px;
127
  }
128
 
129
+ .btn-add-cable:disabled {
130
+ background-color: #6c757d;
131
+ cursor: not-allowed;
132
  }
133
 
134
+ .btn-calculate {
135
+ background-color: #6c757d; /* Disabled state */
136
+ cursor: not-allowed;
 
137
  }
138
 
139
+ .btn-calculate.enabled {
140
+ background-color: #28a745; /* Enabled state */
141
+ cursor: pointer;
 
 
142
  }
143
 
144
+ .btn-remove-cable {
145
+ background-color: #dc3545;
146
+ padding: 3px 8px;
147
+ font-size: 12px;
148
+ position: absolute;
149
+ bottom: 10px;
150
+ right: 10px;
151
+ }
152
+
153
+ .action-buttons {
154
+ display: flex;
155
+ justify-content: center;
156
+ gap: 10px;
157
  width: 100%;
158
+ margin-bottom: 20px;
159
+ }
160
+
161
+ .result-display {
162
+ margin-top: 20px;
163
+ font-size: 20px;
164
+ color: #28a745;
165
+ text-align: center;
166
+ padding: 20px;
167
+ border-top: 2px solid #dee2e6;
168
+ width: 50%;
169
+ background-color: white;
170
+ border-radius: 8px;
171
+ box-sizing: border-box;
172
  }
173
 
174
  .btn-back {
175
  background-color: #007bff;
176
  color: white;
177
+ padding: 8px 16px;
178
+ font-size: 10px;
179
  text-align: center;
180
  text-decoration: none;
181
+ margin-top: 16px;
 
 
 
182
  }
183
 
184
  .btn-back:hover {
185
  background-color: #0056b3;
186
  }
187
+
188
+ /* Media Queries for Responsiveness */
189
+ @media (max-width: 992px) {
190
+ #cable-container .cable-group {
191
+ flex: 1 1 48%; /* Two cables per row on medium screens */
192
+ }
193
+
194
+ #cable-container .cable-group:nth-child(3) {
195
+ flex: 1 1 100%; /* Stack the third cable below on medium screens */
196
+ }
 
 
197
  }
198
 
199
+ @media (max-width: 768px) {
200
+ #cable-container .cable-group {
201
+ flex: 1 1 100%; /* Full width for all cables on small screens */
202
+ }
203
+
204
+ .btn-add-cable,
205
+ .btn-calculate {
206
+ width: 100%;
207
+ margin-right: 0;
208
+ }
209
+
210
+ .action-buttons {
211
+ flex-direction: column;
212
+ }
213
  }
214
 
215
+ .btn-save {
216
+ background-color: #007bff;
217
  }
218
 
219
+ .btn-delete {
220
+ background-color: #dc3545;
221
+ }
222
+
223
+ /* Adjusted Specific Styles for the Edit Cables Page */
224
+ .edit-cables-main {
225
+ display: flex;
226
+ flex-direction: column;
227
+ align-items: center;
228
+ margin: 30px auto;
229
+ width: 100%;
230
+ max-width: 500px; /* Adjusted width to make it more compact */
231
  padding: 20px;
232
+ box-sizing: border-box;
233
+ background-color: white;
234
+ box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
235
+ border-radius: 8px;
236
+ }
237
+
238
+ .add-cable-section, .existing-cables-section {
239
  width: 100%;
240
+ margin-bottom: 30px;
241
  }
242
 
243
+ .add-cable-section h2, .existing-cables-section h2 {
244
+ margin-bottom: 20px;
245
+ color: #343a40;
246
+ }
templates/edit_cables.html CHANGED
@@ -10,7 +10,7 @@
10
  <header>
11
  <h1>Edit Cables</h1>
12
  </header>
13
- <main>
14
  <section class="add-cable-section">
15
  <h2>Add Cable</h2>
16
  <form action="/add_cable" method="post" class="cable-form">
@@ -43,7 +43,7 @@
43
  <label for="resistance">Resistance:</label>
44
  <input type="number" step="0.01" id="resistance" name="resistance" value="{{ cable.resistance }}" required>
45
  </div>
46
- <div class="form-row btn-group">
47
  <button type="submit" class="btn btn-save">Save</button>
48
  <button formaction="/delete_cable/{{ cable.id }}" formmethod="post" class="btn btn-delete">Delete</button>
49
  </div>
 
10
  <header>
11
  <h1>Edit Cables</h1>
12
  </header>
13
+ <main class="edit-cables-main">
14
  <section class="add-cable-section">
15
  <h2>Add Cable</h2>
16
  <form action="/add_cable" method="post" class="cable-form">
 
43
  <label for="resistance">Resistance:</label>
44
  <input type="number" step="0.01" id="resistance" name="resistance" value="{{ cable.resistance }}" required>
45
  </div>
46
+ <div class="btn-group">
47
  <button type="submit" class="btn btn-save">Save</button>
48
  <button formaction="/delete_cable/{{ cable.id }}" formmethod="post" class="btn btn-delete">Delete</button>
49
  </div>
templates/index.html CHANGED
@@ -12,36 +12,51 @@
12
  <h1>Voltage Drop Calculator</h1>
13
  </header>
14
  <main class="calculator-main">
15
- <form id="calculator-form" class="calculator-form">
16
- <div class="form-row">
17
- <label for="cable_type">Cable Type:</label>
18
- <select id="cable_type" name="cable_type" required>
19
- {% for cable in cables %}
20
- <option value="{{ cable.type }}">{{ cable.type }}</option>
21
- {% endfor %}
22
- </select>
23
- </div>
 
 
 
 
24
 
25
- <div class="form-row">
26
- <label for="voltage">Voltage:</label>
27
- <input type="number" id="voltage" name="voltage" required>
28
- </div>
29
 
30
- <div class="form-row">
31
- <label for="load">Load (A):</label>
32
- <input type="number" id="load" name="load" required>
33
- </div>
34
 
35
- <div class="form-row">
36
- <label for="length">Length (m):</label>
37
- <input type="number" id="length" name="length" required>
 
 
 
 
 
38
  </div>
39
 
40
- <button type="submit" class="btn btn-calculate">Calculate</button>
 
 
 
 
41
  </form>
42
 
 
43
  <div id="result" class="result-display"></div>
44
 
 
45
  <a href="/edit_cables" class="btn btn-back">Edit Cables</a>
46
  </main>
47
  <script src="/static/app.js"></script>
 
12
  <h1>Voltage Drop Calculator</h1>
13
  </header>
14
  <main class="calculator-main">
15
+ <!-- Form wraps all cable groups -->
16
+ <form id="calculator-form">
17
+ <div id="cable-container">
18
+ <div class="cable-group">
19
+ <h2>Cable 1</h2>
20
+ <div class="form-row">
21
+ <label for="cable_type-0">Cable Type:</label>
22
+ <select id="cable_type-0" name="cable_type[0]" required>
23
+ {% for cable in cables %}
24
+ <option value="{{ cable.type }}">{{ cable.type }}</option>
25
+ {% endfor %}
26
+ </select>
27
+ </div>
28
 
29
+ <div class="form-row">
30
+ <label for="voltage-0">Voltage:</label>
31
+ <input type="number" id="voltage-0" name="voltage[0]" required>
32
+ </div>
33
 
34
+ <div class="form-row">
35
+ <label for="load-0">Load (A):</label>
36
+ <input type="number" id="load-0" name="load[0]" required>
37
+ </div>
38
 
39
+ <div class="form-row">
40
+ <label for="length-0">Length (m):</label>
41
+ <input type="number" id="length-0" name="length[0]" required>
42
+ </div>
43
+
44
+ <!-- Remove Cable Button -->
45
+ <button type="button" class="btn btn-remove-cable" style="display: none;">- Remove Cable</button>
46
+ </div>
47
  </div>
48
 
49
+ <!-- Action Buttons -->
50
+ <div class="action-buttons">
51
+ <button id="add-cable" type="button" class="btn btn-add-cable">+ Add Cable</button>
52
+ <button type="submit" class="btn btn-calculate">Calculate</button>
53
+ </div>
54
  </form>
55
 
56
+ <!-- Results Display -->
57
  <div id="result" class="result-display"></div>
58
 
59
+ <!-- Edit Cables Link -->
60
  <a href="/edit_cables" class="btn btn-back">Edit Cables</a>
61
  </main>
62
  <script src="/static/app.js"></script>