Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

MINOR: feat: add meta-buiding components #4

Merged
merged 1 commit into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export { default as BIMDataBuildingMaker } from "./src/BIMDataBuildingMaker/BIMDataBuildingMaker.vue";
export { default as BIMDataFileManager } from "./src/BIMDataFileManager/BIMDataFileManager.vue";
export { default as BIMDataGuidedTour } from "./src/BIMDataGuidedTour/BIMDataGuidedTour.vue";
export { default as BIMDataMetaBuildingStructure } from "./src/BIMDataMetaBuildingStructure/BIMDataMetaBuildingStructure.vue";
export { default as BIMDataModelPreview } from "./src/BIMDataModelPreview/BIMDataModelPreview.vue";
export { default as BIMDataPDFViewer } from "./src/BIMDataPDFViewer/BIMDataPDFViewer.vue";
export { default as BIMDataSafeZoneModal } from "./src/BIMDataSafeZoneModal/BIMDataSafeZoneModal.vue";
45 changes: 45 additions & 0 deletions src/BIMDataBuildingMaker/BIMDataBuildingMaker.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.bimdata-building-maker {
position: relative;
height: 100%;
background-color: var(--color-white);

&__header {
height: 44px;
padding: calc(var(--spacing-unit) / 2) 0;

display: flex;
justify-content: center;
align-items: center;
gap: var(--spacing-unit);

box-shadow: var(--box-shadow);

&__btn-back {
position: absolute;
left: var(--spacing-unit);
}
}

&__body {
height: calc(100% - 44px);
padding: calc(2 * var(--spacing-unit));
}

&__loader {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;

display: flex;
justify-content: center;
align-items: center;

background-color: rgba(255, 255, 255, 0.75);

.bimdata-spinner {
transform: scale(2);
}
}
}
183 changes: 183 additions & 0 deletions src/BIMDataBuildingMaker/BIMDataBuildingMaker.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
<template>
<div class="bimdata-building-maker">
<div
class="bimdata-building-maker__header"
:style="{ visibility: currentView === VIEWS.LIST ? 'hidden' : 'visible' }"
>
<BIMDataButton
class="bimdata-building-maker__header__btn-back"
ghost
radius
:disabled="loading.value"
@click="back"
>
<BIMDataIconArrow
size="xxs"
margin="0 6px 0 0"
/>
<span>{{ $t("BuildingMaker.back") }}</span>
</BIMDataButton>
<img :src="icon" />
<span>{{ $t("BuildingMaker.title") }}</span>
</div>

<div class="bimdata-building-maker__body">
<transition
name="fade"
mode="out-in"
>
<template v-if="currentView === VIEWS.FORM">
<BuildingForm
:metaBuilding="currentMetaBuilding"
@metaBuilding-created="onMetaBuildingCreated"
@metaBuilding-updated="onMetaBuildingUpdated"
/>
</template>

<template v-else-if="currentView === VIEWS.STOREYS && currentMetaBuilding">
<BuildingStoreys
:apiClient="apiClient"
:space="space"
:project="project"
:metaBuilding="currentMetaBuilding"
@close="back"
/>
</template>

<template v-else>
<BuildingsList
:metaBuildings="metaBuildings"
@create-metaBuilding="openForm"
@update-metaBuilding="openForm"
@delete-metaBuilding="deleteMetaBuilding"
@manage-storeys="openStoreys"
/>
</template>
</transition>
</div>

<transition name="fade">
<div
class="bimdata-building-maker__loader"
v-show="loading.value"
>
<BIMDataSpinner />
</div>
</transition>
</div>
</template>

<script>
import { onMounted, provide, ref } from "vue";
import icon from "./icon.svg";
import { createService } from "./service.js";
// Components
import BuildingForm from "./BuildingForm/BuildingForm.vue";
import BuildingsList from "./BuildingsList/BuildingsList.vue";
import BuildingStoreys from "./BuildingStoreys/BuildingStoreys.vue";

const VIEWS = Object.freeze({
FORM: "form",
LIST: "list",
STOREYS: "storeys",
});

export default {
components: {
BuildingForm,
BuildingsList,
BuildingStoreys,
},
props: {
apiClient: {
type: Object,
required: true,
},
space: {
type: Object,
required: true,
},
project: {
type: Object,
required: true,
},
model: {
type: Object,
default: null,
},
},
emits: [
"metaBuilding-created",
"metaBuilding-updated",
"metaBuilding-deleted",
],
setup(props, { emit }) {
const service = createService(props.apiClient, props.space, props.project);
const loading = ref(false);

provide("service", service);
provide("loading", loading);

const currentView = ref(VIEWS.LIST);
const metaBuildings = ref([]);
const currentMetaBuilding = ref(null);

const loadMetaBuildings = async () => {
loading.value = true;
metaBuildings.value = await service.fetchMetaBuildings();
loading.value = false;
};
const deleteMetaBuilding = async (metaBuilding) => {
await service.deleteMetaBuilding(metaBuilding);
loadMetaBuildings();
emit("metaBuilding-deleted");
};
const openForm = (metaBuilding) => {
currentMetaBuilding.value = metaBuilding || null;
currentView.value = VIEWS.FORM;
};
const openStoreys = (metaBuilding) => {
currentMetaBuilding.value = metaBuilding;
currentView.value = VIEWS.STOREYS;
};
const onMetaBuildingCreated = async (metaBuilding) => {
await loadMetaBuildings();
openStoreys(metaBuilding);
emit("metaBuilding-created");
};
const onMetaBuildingUpdated = () => {
loadMetaBuildings();
currentView.value = VIEWS.LIST;
emit("metaBuilding-updated");
};
const back = () => {
currentView.value = VIEWS.LIST;
};

onMounted(() => {
loadMetaBuildings();
if (props.model) openStoreys(props.model);
});

return {
// References
currentMetaBuilding,
currentView,
icon,
loading,
metaBuildings,
VIEWS,
// Methods
back,
deleteMetaBuilding,
loadMetaBuildings,
onMetaBuildingCreated,
onMetaBuildingUpdated,
openForm,
openStoreys,
};
},
};
</script>

<style scoped lang="scss" src="./BIMDataBuildingMaker.scss"></style>
33 changes: 33 additions & 0 deletions src/BIMDataBuildingMaker/BuildingForm/BuildingForm.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.building-form {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
gap: calc(2 * var(--spacing-unit));

&__icon {
width: 36px;
}

&__title {
margin: 0;
}

&__text {
text-align: center;
color: var(--color-granite);
}

&__controls {
width: 100%;
padding: 0 20%;

.bimdata-input {
width: 100%;
}

.bimdata-btn {
margin-left: auto;
}
}
}
88 changes: 88 additions & 0 deletions src/BIMDataBuildingMaker/BuildingForm/BuildingForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<template>
<div class="building-form">
<img class="building-form__icon" :src="icon" />
<h2 class="building-form__title">
{{ $t("BuildingMaker.title") }}
</h2>
<div class="building-form__text">
{{ $t("BuildingMaker.form.text") }}
</div>
<div class="building-form__controls">
<BIMDataInput
ref="nameInput"
:placeholder="$t('BuildingMaker.form.input')"
v-model="metaBuildingName"
:error="hasError"
:errorMessage="$t('BuildingMaker.form.error')"
@keyup.enter.stop="submit"
/>
<BIMDataButton width="120px" color="primary" fill radius @click="submit">
{{ $t(`BuildingMaker.form.${metaBuilding ? 'updateButton' : 'createButton'}`) }}
</BIMDataButton>
</div>
</div>
</template>

<script>
import { inject, onMounted, ref, watch } from "vue";
import icon from "../icon.svg";

export default {
props: {
metaBuilding: {
type: Object,
},
},
emits: [
"metaBuilding-created",
"metaBuilding-updated"
],
setup(props, { emit }) {
const service = inject("service");

const nameInput = ref(null);
const hasError = ref(false);
const metaBuildingName = ref("");

// Reset error state when meta building name changes
watch(metaBuildingName, () => hasError.value = false);

onMounted(() => {
nameInput.value.focus();
metaBuildingName.value = props.metaBuilding?.name ?? "";
});

const submit = async () => {
if (!metaBuildingName.value) {
hasError.value = true;
return;
}
if (metaBuildingName.value === props.metaBuilding?.name) {
return;
}

let newBuilding = { name: metaBuildingName.value };
if (props.metaBuilding) {
newBuilding.id = props.metaBuilding.id;
newBuilding = await service.updateMetaBuilding(newBuilding);
emit("metaBuilding-updated", newBuilding);
} else {
newBuilding = await service.createMetaBuilding(newBuilding);
emit("metaBuilding-created", newBuilding);
}
};

return {
// References
hasError,
icon,
metaBuildingName,
nameInput,
// Methods
submit,
};
},
};
</script>

<style scoped lang="scss" src="./BuildingForm.scss"></style>
35 changes: 35 additions & 0 deletions src/BIMDataBuildingMaker/BuildingStoreys/BuildingStoreys.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
.building-storeys {
height: 100%;

.content {
position: relative;
height: 100%;
display: flex;
flex-direction: column;
}

&__tree,
&__dms {
flex-grow: 1;
overflow-y: auto;
}

&__form {
position: absolute;
top: calc(var(--spacing-unit) * 2);
left: 0;
width: 100%;
}

&:deep(.bimdata-file-manager) {
position: static;

.bimdata-file-manager__pdf-page-selector {
position: absolute;
top: -12px;
left: -12px;
width: calc(100% + 24px);
height: calc(100% + 24px);
}
}
}
Loading