From 3c7a652e98f2c9d3feb596c8ad444bf67f41db59 Mon Sep 17 00:00:00 2001 From: michalspeckle Date: Thu, 15 May 2025 09:49:36 +0200 Subject: [PATCH] feat(fe): improvements to empty states (#4696) * feat(fe): render different CardImportFileArea variants based on context * feat(fe): remove default emptyStateVariant * refactor(fe): use container classes * feat(fe): remove click from full card upload area. Only on buttons * chore(fe): updates to empty states, clean up. * feat(fe): new empty state illustrations refactor * chore(fe): removing nested selectors and clean up * chore(fe): removed default variant * feat(fe): empty state illustration slot added and styling changes * feat(fe): new empty state illustrations and styling changes * chore(fe): copy change * chore(fe): refactor --------- Co-authored-by: andrewwallacespeckle --- .../illustration/emptystate/DiscussionTab.vue | 125 +++++++++++++++ .../illustration/emptystate/Project.vue | 76 +++++++++ .../illustration/emptystate/ProjectTab.vue | 144 ++++++++++++++++++ .../illustration/emptystate/Workspace.vue} | 26 +++- .../components/project/CardImportFileArea.vue | 117 ++++++++++++-- .../components/project/EmptyState.vue | 23 +-- .../page/latest-items/comments/EmptyState.vue | 3 + .../components/project/page/models/Card.vue | 1 + .../project/page/models/ListView.vue | 1 + .../project/page/models/StructureItem.vue | 5 + .../projects/ProjectDashboardCard.vue | 1 + .../workspace/dashboard/ProjectList.vue | 6 +- 12 files changed, 502 insertions(+), 26 deletions(-) create mode 100644 packages/frontend-2/components/global/illustration/emptystate/DiscussionTab.vue create mode 100644 packages/frontend-2/components/global/illustration/emptystate/Project.vue create mode 100644 packages/frontend-2/components/global/illustration/emptystate/ProjectTab.vue rename packages/frontend-2/components/{workspace/EmptyStateIllustration.vue => global/illustration/emptystate/Workspace.vue} (93%) diff --git a/packages/frontend-2/components/global/illustration/emptystate/DiscussionTab.vue b/packages/frontend-2/components/global/illustration/emptystate/DiscussionTab.vue new file mode 100644 index 000000000..3eba4b150 --- /dev/null +++ b/packages/frontend-2/components/global/illustration/emptystate/DiscussionTab.vue @@ -0,0 +1,125 @@ + + diff --git a/packages/frontend-2/components/global/illustration/emptystate/Project.vue b/packages/frontend-2/components/global/illustration/emptystate/Project.vue new file mode 100644 index 000000000..a66c93666 --- /dev/null +++ b/packages/frontend-2/components/global/illustration/emptystate/Project.vue @@ -0,0 +1,76 @@ + diff --git a/packages/frontend-2/components/global/illustration/emptystate/ProjectTab.vue b/packages/frontend-2/components/global/illustration/emptystate/ProjectTab.vue new file mode 100644 index 000000000..ecd14d5a6 --- /dev/null +++ b/packages/frontend-2/components/global/illustration/emptystate/ProjectTab.vue @@ -0,0 +1,144 @@ + + diff --git a/packages/frontend-2/components/workspace/EmptyStateIllustration.vue b/packages/frontend-2/components/global/illustration/emptystate/Workspace.vue similarity index 93% rename from packages/frontend-2/components/workspace/EmptyStateIllustration.vue rename to packages/frontend-2/components/global/illustration/emptystate/Workspace.vue index b481f1cfa..d9164de99 100644 --- a/packages/frontend-2/components/workspace/EmptyStateIllustration.vue +++ b/packages/frontend-2/components/global/illustration/emptystate/Workspace.vue @@ -9,7 +9,7 @@ + diff --git a/packages/frontend-2/components/project/CardImportFileArea.vue b/packages/frontend-2/components/project/CardImportFileArea.vue index 63479d61b..3a86d84f1 100644 --- a/packages/frontend-2/components/project/CardImportFileArea.vue +++ b/packages/frontend-2/components/project/CardImportFileArea.vue @@ -11,9 +11,8 @@ @files-selected="onFilesSelected" >
- - Use our - - connectors - - to publish a {{ modelName ? '' : 'new model' }} version to - {{ modelName ? 'this model' : 'this project' }}, or drag and drop a IFC/OBJ/STL - file here. - +
+
+ + +
+ +
+

+ {{ + emptyStateVariant === 'modelsSection' + ? 'The project has no models, yet.' + : 'No models, yet.' + }} +

+

+ Use + + connectors + + to publish a {{ modelName ? '' : 'new model' }} version to + {{ modelName ? 'this model' : 'this project' }}, or drag and drop a + IFC/OBJ/STL file here. +

+
+ + Install connectors + + + Upload a file + +
+
+
@@ -54,10 +77,13 @@ import { ExclamationTriangleIcon } from '@heroicons/vue/24/solid' import { connectorsRoute } from '~/lib/common/helpers/route' import type { Nullable } from '@speckle/shared' +type EmptyStateVariants = 'modelGrid' | 'modelList' | 'modelsSection' + const props = defineProps<{ projectId: string modelName?: string disabled?: boolean + emptyStateVariant?: EmptyStateVariants }>() const { @@ -79,6 +105,75 @@ const uploadZone = ref( }> ) +const showEmptyState = computed( + () => + props.emptyStateVariant !== 'modelGrid' && props.emptyStateVariant !== 'modelList' +) + +const containerClasses = computed(() => { + const classParts = ['w-full flex justify-center items-center'] + + if (props.emptyStateVariant === 'modelGrid') { + classParts.push('p-4 gap-4') + } else if (props.emptyStateVariant === 'modelList') { + classParts.push('p-4 gap-4 text-center') + } else if (props.emptyStateVariant === 'modelsSection') { + classParts.push('p-4 gap-4 text-balance') + } else { + classParts.push('p-20 gap-8 text-balance flex-col text-center') + } + + return classParts.join(' ') +}) + +const illustrationClasses = computed(() => { + const classParts = ['max-w-lg'] + + if (props.emptyStateVariant === 'modelGrid') { + classParts.push('hidden') + } else if (props.emptyStateVariant === 'modelList') { + classParts.push('hidden') + } else if (props.emptyStateVariant === 'modelsSection') { + classParts.push('hidden min-[1350px]:block') + } else { + classParts.push('') + } + + return classParts.join(' ') +}) + +const paragraphClasses = computed(() => { + const classParts = ['text-body-xs text-foreground-2 mt-2 p-0'] + + if (props.emptyStateVariant === 'modelGrid') { + classParts.push('') + } else if (props.emptyStateVariant === 'modelList') { + classParts.push('') + } else if (props.emptyStateVariant === 'modelsSection') { + classParts.push('max-w-sm') + } else { + classParts.push('max-w-sm') + } + + return classParts.join(' ') +}) + +const buttonsClasses = computed(() => { + const classParts = ['w-full flex flex-row gap-2 flex-wrap'] + + if (props.emptyStateVariant === 'modelGrid') { + classParts.push('mt-3') + } else if (props.emptyStateVariant === 'modelList') { + classParts.push('mt-3') + } else if (props.emptyStateVariant === 'modelsSection') { + classParts.push('mt-3') + } else { + classParts.push('justify-center mt-6') + } + + return classParts.join(' ') +}) + const getDashedBorderClasses = (isDraggingFiles: boolean) => { if (isDraggingFiles) return 'border-primary' if (errorMessage.value) return 'border-danger' diff --git a/packages/frontend-2/components/project/EmptyState.vue b/packages/frontend-2/components/project/EmptyState.vue index a7ef34086..9484d69e8 100644 --- a/packages/frontend-2/components/project/EmptyState.vue +++ b/packages/frontend-2/components/project/EmptyState.vue @@ -1,13 +1,18 @@ diff --git a/packages/frontend-2/components/project/page/latest-items/comments/EmptyState.vue b/packages/frontend-2/components/project/page/latest-items/comments/EmptyState.vue index 4306b3189..a668cfbb5 100644 --- a/packages/frontend-2/components/project/page/latest-items/comments/EmptyState.vue +++ b/packages/frontend-2/components/project/page/latest-items/comments/EmptyState.vue @@ -1,5 +1,8 @@