mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-10 09:48:32 +00:00
loading multiple cost schedules in the web ui is now more responsive, clean up and organise css code #5369
This commit is contained in:
@@ -2,15 +2,7 @@
|
||||
th {
|
||||
position: relative;
|
||||
}
|
||||
.resizer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
cursor: col-resize;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.context-menu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
.floating-form {
|
||||
width: 50vw;
|
||||
max-height: 80vh;
|
||||
position: absolute;
|
||||
background-color: var(--background-color);
|
||||
border: 1px solid black;
|
||||
z-index: 9999;
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
padding-bottom: var(--padding-medium);
|
||||
}
|
||||
|
||||
[id^="enable-editing-quantities"].floating-form {
|
||||
height: 70vh;
|
||||
}
|
||||
|
||||
.form-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #323936;
|
||||
padding: var(--padding-medium);
|
||||
font-size: large;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 6px 6px 0 0;
|
||||
height: 5%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
height: 95%;
|
||||
padding-left: var(--padding-medium);
|
||||
padding-right: var(--padding-medium);
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 1em;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.form-section h3 {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.summary-section {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.summary-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.floating-form tr {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.floating-form td {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 5px;
|
||||
overflow: auto;
|
||||
max-height: 400px;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
|
||||
.selected {
|
||||
border-color: #28a745;
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px #28a745;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
|
||||
.classificationView {
|
||||
border-left: 5px solid #28a745;
|
||||
min-height: 200px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 5px;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.selectedClassificationText {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.back-button:disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.classification-cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.classification {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
|
||||
.message {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.message span {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.message .icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.message .close-button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.message .close-button:hover {
|
||||
background-color: #ffcccc;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
background-color: #ffe6e6;
|
||||
}
|
||||
|
||||
.error .close-button {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.error .close-button:hover {
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: green;
|
||||
border: 1px solid green;
|
||||
background-color: #e6ffe6;
|
||||
}
|
||||
|
||||
.success .close-button {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.success .close-button:hover {
|
||||
background-color: #ccffcc;
|
||||
color: darkgreen;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 10px;
|
||||
}
|
||||
.card-body {
|
||||
height: 10vh;
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
.cost-tables {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(700px, 2fr));
|
||||
grid-auto-rows: minmax(350px, auto);
|
||||
gap: 10px;
|
||||
font-size: var(--fontSize);
|
||||
}
|
||||
|
||||
.schedule {
|
||||
border: 1px solid #ccc;
|
||||
position: relative;
|
||||
overflow: hidden; /* Ensure content doesn't overflow */
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
flex: 1;
|
||||
overflow-y: auto; /* Enables vertical scrolling */
|
||||
}
|
||||
|
||||
thead .resizer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
width: 5px;
|
||||
height: 100%;
|
||||
cursor: col-resize;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
table {
|
||||
table-layout: auto;
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 1px solid #ccc; /* Optional: adds a border around the table */
|
||||
}
|
||||
|
||||
thead {
|
||||
background-color: #727272;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
tbody {
|
||||
width: 100%; /* Ensure full width for alignment */
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 5px;
|
||||
border-right: 1px solid #ccc;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
word-wrap: break-word;
|
||||
border-right: 1px solid #ddd;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
width: auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
td {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.actions-column {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
opacity: 0;
|
||||
width: fit-content;
|
||||
min-width: fit-content;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
[id^="cost-items"] tr:hover .actions-column {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.selected-cell,
|
||||
.clickable-cell:hover {
|
||||
border: 2px solid var(--highlight-over);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
td {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.cost-tables {
|
||||
grid-template-columns: 2fr; /* One column on smaller screens */
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.cost-tables {
|
||||
grid-template-columns: 1fr; /* One column on smaller screens */
|
||||
}
|
||||
}
|
||||
|
||||
.table-wrapper.collapsed {
|
||||
max-height: 40px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.table-wrapper .form-header {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
@import url("./components/card.css");
|
||||
@import url("./components/contextMenu.css");
|
||||
@import url("./components/headerBar.css");
|
||||
@import url("./components/table.css");
|
||||
@import url("./components/floatingForm.css");
|
||||
@import url("./components/message.css");
|
||||
@import url("./components/layeredViewPanel.css");
|
||||
|
||||
:root {
|
||||
--fontSize: 14px;
|
||||
@@ -15,74 +19,32 @@
|
||||
--padding-small: 5px;
|
||||
--padding-medium: 10px;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
height: 100vh;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.floating-form {
|
||||
width: 50vw;
|
||||
max-height: 80vh;
|
||||
position: absolute;
|
||||
background-color: var(--background-color);
|
||||
border: 1px solid black;
|
||||
z-index: 9999;
|
||||
cursor: move;
|
||||
user-select: none;
|
||||
padding-bottom: var(--padding-medium);
|
||||
.floating-form .table-container {
|
||||
max-height: 80%;
|
||||
box-shadow: 0 5px 5px 0 #254e3c;
|
||||
}
|
||||
|
||||
[id^="enable-editing-quantities"].floating-form {
|
||||
height: 70vh;
|
||||
#cost-items {
|
||||
max-height: calc(100vh - var(--margin-small));
|
||||
}
|
||||
|
||||
.form-header {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #323936;
|
||||
padding: var(--padding-medium);
|
||||
font-size: large;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 6px 6px 0 0;
|
||||
height: 5%;
|
||||
position: relative;
|
||||
[id^="cost-values-form"] table {
|
||||
max-height: 50%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
height: 95%;
|
||||
padding-left: var(--padding-medium);
|
||||
padding-right: var(--padding-medium);
|
||||
}
|
||||
|
||||
.form-section {
|
||||
margin-bottom: 1em;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.form-section h3 {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.summary-section {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.summary-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.floating-form tr {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.floating-form td {
|
||||
padding: 3px;
|
||||
[id^="selected-products"] .form-container {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
@@ -168,84 +130,6 @@ body {
|
||||
background: var(--scrollbar-thumb-hover-color);
|
||||
}
|
||||
|
||||
body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin-top: 1em;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.table-wrapper {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
border: 2px solid #254e3c;
|
||||
}
|
||||
|
||||
.floating-form .table-container {
|
||||
max-height: 80%;
|
||||
overflow: auto;
|
||||
box-shadow: 0 5px 5px 0 #254e3c;
|
||||
}
|
||||
|
||||
#cost-items {
|
||||
max-height: calc(100vh - var(--margin-small));
|
||||
}
|
||||
|
||||
[id^="cost-values-form"] table {
|
||||
max-height: 50%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
[id^="selected-products"] .form-container {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
tr,
|
||||
td,
|
||||
th {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: var(--fontSize);
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
thead {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background-color: #727272;
|
||||
}
|
||||
|
||||
tbody {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
border-right: 1px solid #ddd;
|
||||
text-align: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
td {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
@@ -329,39 +213,6 @@ form select {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
table {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 2px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
table {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 1px;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
form table {
|
||||
max-height: 50%;
|
||||
}
|
||||
@@ -371,36 +222,6 @@ form table {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
[id^="cost-items"] th:nth-child(1),
|
||||
[id^="cost-items"] td:nth-child(1) {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
[id^="cost-items"] th:last-child,
|
||||
[id^="cost-items"] td:last-child {
|
||||
width: fit-content;
|
||||
min-width: fit-content;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
.actions-column {
|
||||
transition: opacity 0.3s ease-in-out;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
[id^="cost-items"] tr:hover .actions-column {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.selected-cell, .clickable-cell:hover {
|
||||
border: 2px solid var(--highlight-over);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
td {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.append-right {
|
||||
right: 0;
|
||||
top: 50%;
|
||||
@@ -412,46 +233,6 @@ i {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.classificationView {
|
||||
border-left: 5px solid #28a745;
|
||||
min-height: 200px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
padding: 5px;
|
||||
max-height: 400px;
|
||||
}
|
||||
|
||||
.selected {
|
||||
border-color: #28a745;
|
||||
outline: none;
|
||||
box-shadow: 0 0 0 3px #28a745;
|
||||
color: #ddd;
|
||||
}
|
||||
|
||||
.selectedClassificationText {
|
||||
color: #28a745;
|
||||
}
|
||||
|
||||
.back-button {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.back-button:disabled {
|
||||
cursor: not-allowed;
|
||||
background-color: #ccc;
|
||||
}
|
||||
|
||||
.classification-cell {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.classification {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#column-selector {
|
||||
display: flex;
|
||||
@@ -501,69 +282,8 @@ i {
|
||||
margin-left: -5px;
|
||||
}
|
||||
|
||||
.message {
|
||||
position: relative;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
margin: 10px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.message span {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.message .icon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.message .close-button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
transition: background-color 0.3s, color 0.3s;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.message .close-button:hover {
|
||||
background-color: #ffcccc;
|
||||
}
|
||||
|
||||
.error {
|
||||
color: red;
|
||||
border: 1px solid red;
|
||||
background-color: #ffe6e6;
|
||||
}
|
||||
|
||||
.error .close-button {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.error .close-button:hover {
|
||||
color: darkred;
|
||||
}
|
||||
|
||||
.success {
|
||||
color: green;
|
||||
border: 1px solid green;
|
||||
background-color: #e6ffe6;
|
||||
}
|
||||
|
||||
.success .close-button {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.success .close-button:hover {
|
||||
background-color: #ccffcc;
|
||||
color: darkgreen;
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 10px;
|
||||
}
|
||||
.card-body {
|
||||
height: 10vh;
|
||||
}
|
||||
@@ -420,13 +420,15 @@ export class CostUI {
|
||||
}
|
||||
|
||||
static isCostScheduleLoaded(id) {
|
||||
const existingTable = document.getElementById("cost-items-" + id);
|
||||
const existingTable = document.getElementById(
|
||||
"cost-schedule-container-" + id
|
||||
);
|
||||
return existingTable !== null;
|
||||
}
|
||||
|
||||
static removeCostSchedule(id) {
|
||||
const table = document.getElementById("cost-items-" + id);
|
||||
table ? table.parentElement.remove() : null;
|
||||
const container = document.getElementById("cost-schedule-container-" + id);
|
||||
container.remove();
|
||||
}
|
||||
|
||||
static createCostTree({
|
||||
@@ -531,25 +533,35 @@ export class CostUI {
|
||||
tableWrapper = table.parentElement;
|
||||
table.remove();
|
||||
} else {
|
||||
tableWrapper = document.createElement("div");
|
||||
tableWrapper.classList.add("table-wrapper");
|
||||
document.getElementById("cost-items").appendChild(tableWrapper);
|
||||
const tableHeader = document.createElement("div");
|
||||
tableHeader.classList.add("form-header");
|
||||
const text = CostUI.Text(
|
||||
const scheduleDiv = document.createElement("div");
|
||||
scheduleDiv.classList.add("schedule");
|
||||
scheduleDiv.id = "cost-schedule-container-" + id;
|
||||
|
||||
const scheduleHeader = document.createElement("div");
|
||||
scheduleHeader.classList.add("form-header");
|
||||
|
||||
const scheduleName = CostUI.Text(
|
||||
costSchedule.Name,
|
||||
"fa-solid fa-money-bill-wave",
|
||||
"x-large"
|
||||
);
|
||||
|
||||
tableWrapper = document.createElement("div");
|
||||
tableWrapper.classList.add("table-wrapper");
|
||||
|
||||
const callback = () => {
|
||||
tableWrapper.remove();
|
||||
scheduleDiv.remove();
|
||||
};
|
||||
let closeButton = CostUI.createCloseButton(callback);
|
||||
tableHeader.appendChild(text);
|
||||
tableHeader.appendChild(closeButton);
|
||||
tableWrapper.appendChild(tableHeader);
|
||||
|
||||
scheduleHeader.appendChild(scheduleName);
|
||||
scheduleHeader.appendChild(closeButton);
|
||||
|
||||
scheduleDiv.appendChild(scheduleHeader);
|
||||
scheduleDiv.appendChild(tableWrapper);
|
||||
document.getElementById("cost-items").appendChild(scheduleDiv);
|
||||
}
|
||||
|
||||
const table = document.createElement("table");
|
||||
table.id = "cost-items-" + id;
|
||||
const tbody = document.createElement("tbody");
|
||||
@@ -573,9 +585,9 @@ export class CostUI {
|
||||
(header) => header.name !== "Linked Rate"
|
||||
);
|
||||
columnHeaders = columnHeaders.map((header) => {
|
||||
if (header.name === "Unit") {
|
||||
if (header.name === "Cost") {
|
||||
return { name: "Rate (" + currency + ")", visible: preferences.Cost };
|
||||
} else if (header.name === "Cost (" + currency + ")") {
|
||||
} else if (header.name === "Total Cost (" + currency + ")") {
|
||||
return {
|
||||
name: "Total Rate (" + currency + ")",
|
||||
visible: preferences.TotalCost,
|
||||
@@ -2735,14 +2747,14 @@ export class CostUI {
|
||||
|
||||
addButton.addEventListener("click", function (e) {
|
||||
e.preventDefault();
|
||||
let type = CostUI.getQuantityTypeAttribute(quantityType);
|
||||
let type = CostUI.getQuantityTypeAttribute(costItemId, quantityType);
|
||||
callbacks.addQuantity(costItemId, type);
|
||||
});
|
||||
|
||||
return addButton;
|
||||
}
|
||||
|
||||
static getQuantityTypeAttribute(quantityType) {
|
||||
static getQuantityTypeAttribute(costItemId, quantityType) {
|
||||
let type = quantityType;
|
||||
if (!type) {
|
||||
const qtoSection = document.getElementById(
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="cost-schedules" class="row-container"></div>
|
||||
<div id="cost-items" class="table-container"></div>
|
||||
<div id="cost-items" class="cost-tables"></div>
|
||||
<footer>
|
||||
<p>BlenderBIM Version: {{version}}</p>
|
||||
</footer>
|
||||
|
||||
Reference in New Issue
Block a user