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 <andrew@speckle.systems>
This commit is contained in:
michalspeckle
2025-05-15 09:49:36 +02:00
committed by GitHub
parent 77101832bf
commit 3c7a652e98
12 changed files with 502 additions and 26 deletions
@@ -0,0 +1,125 @@
<template>
<svg
width="194"
height="141"
viewBox="0 0 194 141"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
x="0.585984"
y="0.177422"
width="136.5"
height="102.75"
rx="5.625"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 -0.0788556 58.8926)"
stroke="currentColor"
class="stroke-outline-5 fill-foundation-2"
stroke-width="1"
/>
<g clip-path="url(#clip0_3199_61388)">
<g clip-path="url(#clip1_3199_61388)">
<path
d="M90.747 90.6301L83.1931 93.148C81.1897 93.8158 78.7533 93.7941 76.4199 93.0876C74.0865 92.3811 72.0472 91.0477 70.7507 89.3808L57.7147 72.6202C56.4182 70.9532 55.9706 69.0893 56.4705 67.4384C56.9703 65.7874 58.3766 64.4848 60.3801 63.817L90.5956 53.7451C92.5991 53.0773 95.0355 53.0991 97.3689 53.8056C99.7023 54.5121 101.742 55.8454 103.038 57.5124L116.074 74.273C117.371 75.9399 117.818 77.8039 117.318 79.4548C116.818 81.1057 115.412 82.4084 113.409 83.0762L105.855 85.5941L103.189 94.3973L90.747 90.6301Z"
fill="currentColor"
class="stroke-outline-5 fill-foundation-page"
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M73.9053 72.7725L91.0969 67.0419"
stroke="currentColor"
class="stroke-outline-5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M80.0811 80.9941L95.1888 75.9582"
stroke="currentColor"
class="stroke-outline-5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<g clip-path="url(#clip2_3199_61388)">
<path
d="M110.958 60.9562L104.483 63.1145C102.766 63.6869 100.677 63.6682 98.6773 63.0627C96.6772 62.4571 94.9293 61.3142 93.818 59.8854L82.6442 45.5192C81.533 44.0904 81.1493 42.4927 81.5778 41.0776C82.0062 39.6625 83.2117 38.546 84.9289 37.9736L110.828 29.3406C112.545 28.7682 114.633 28.7868 116.634 29.3924C118.634 29.9979 120.382 31.1408 121.493 32.5696L132.667 46.9358C133.778 48.3647 134.161 49.9623 133.733 51.3774C133.305 52.7925 132.099 53.909 130.382 54.4814L123.907 56.6397L121.623 64.1853L110.958 60.9562Z"
stroke="currentColor"
class="stroke-outline-5 fill-foundation"
fill="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M96.2295 45.5137L113.496 39.7583"
stroke="currentColor"
class="stroke-outline-5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M101.816 52.6968L114.766 48.3803"
stroke="currentColor"
class="stroke-outline-5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
</g>
<rect
x="0.585984"
y="0.177422"
width="136.5"
height="102.75"
rx="5.625"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 -0.0788556 43.8926)"
stroke="currentColor"
class="dash-moving stroke-outline-5"
stroke-dashoffset="25"
stroke-width="1"
stroke-dasharray="3 4"
/>
<defs>
<clipPath id="clip0_3199_61388">
<rect
width="137.25"
height="103.5"
rx="6"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 0 43.6699)"
fill="currentColor"
class="fill-foundation"
/>
</clipPath>
<clipPath id="clip1_3199_61388">
<rect
width="63.7"
height="63.7"
fill="currentColor"
class="fill-foundation"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 38.7539 60.4727)"
/>
</clipPath>
<clipPath id="clip2_3199_61388">
<rect
width="54.6"
height="54.6"
fill="currentColor"
class="fill-foundation"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 66.3926 35.1069)"
/>
</clipPath>
</defs>
</svg>
</template>
<style scoped>
.dash-moving {
animation: dash 2s ease-in-out 0s 1 normal forwards running;
}
@keyframes dash {
100% {
stroke-dashoffset: 0;
}
}
</style>
@@ -0,0 +1,76 @@
<template>
<svg
width="175"
height="134"
viewBox="0 0 175 134"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<mask id="path-1-inside-1_3194_60474" fill="currentColor" class="fill-foundation">
<path
d="M108.32 6.47994L49.55 0.719944C47.18 0.489944 44.91 0.919944 42.83 1.88994C40.75 2.85994 38.84 4.40994 37.24 6.39994C35.64 8.38994 34.32 10.8199 33.42 13.5799C32.52 16.3399 32 19.4199 32 22.6899V111.8C32 115.07 32.5 118.15 33.41 120.91C34.32 123.67 35.62 126.1 37.23 128.09C38.84 130.08 40.73 131.61 42.82 132.6C44.91 133.59 47.17 134.01 49.54 133.77L108.31 128.01C110.27 127.82 112.13 127.05 113.82 125.83C115.51 124.61 116.99 122.95 118.24 120.96C119.49 118.97 120.49 116.66 121.19 114.13C121.89 111.6 122.26 108.87 122.26 106.02V28.4699C122.26 25.6199 121.88 22.8799 121.19 20.3599C120.5 17.8399 119.49 15.5199 118.24 13.5299C116.99 11.5399 115.49 9.86994 113.82 8.65994C112.15 7.44994 110.28 6.66994 108.31 6.47994"
/>
</mask>
<path
d="M108.32 6.47994L49.55 0.719944C47.18 0.489944 44.91 0.919944 42.83 1.88994C40.75 2.85994 38.84 4.40994 37.24 6.39994C35.64 8.38994 34.32 10.8199 33.42 13.5799C32.52 16.3399 32 19.4199 32 22.6899V111.8C32 115.07 32.5 118.15 33.41 120.91C34.32 123.67 35.62 126.1 37.23 128.09C38.84 130.08 40.73 131.61 42.82 132.6C44.91 133.59 47.17 134.01 49.54 133.77L108.31 128.01C110.27 127.82 112.13 127.05 113.82 125.83C115.51 124.61 116.99 122.95 118.24 120.96C119.49 118.97 120.49 116.66 121.19 114.13C121.89 111.6 122.26 108.87 122.26 106.02V28.4699C122.26 25.6199 121.88 22.8799 121.19 20.3599C120.5 17.8399 119.49 15.5199 118.24 13.5299C116.99 11.5399 115.49 9.86994 113.82 8.65994C112.15 7.44994 110.28 6.66994 108.31 6.47994"
fill="transparent"
class="stroke-outline-3 opacity-75"
stroke="currentColor"
/>
<path
d="M60.9609 2.34277C62.9638 1.40878 65.1444 0.995973 67.4209 1.2168V1.21777L126.19 6.97754H126.191C128.06 7.15771 129.847 7.89848 131.456 9.06445C133.065 10.2305 134.524 11.8502 135.746 13.7959C136.968 15.7412 137.96 18.0158 138.638 20.4922C139.316 22.9685 139.689 25.664 139.689 28.4697V106.02C139.689 108.826 139.325 111.512 138.638 113.997C137.949 116.485 136.968 118.75 135.746 120.694C134.523 122.641 133.085 124.249 131.457 125.425C129.929 126.528 128.272 127.239 126.539 127.472L126.191 127.513H126.19L67.4209 133.272H67.4189C65.1429 133.503 62.9742 133.101 60.9639 132.148C58.9494 131.194 57.1173 129.714 55.5488 127.775C53.9809 125.837 52.7077 123.462 51.8145 120.753C50.922 118.046 50.4297 115.019 50.4297 111.8V22.6904C50.4297 19.4722 50.9321 16.4444 51.8154 13.7354C52.6978 11.0296 53.9898 8.65311 55.5498 6.71289C57.1082 4.77471 58.9592 3.27626 60.9609 2.34277Z"
stroke="currentColor"
stroke-width="1"
stroke-linecap="round"
stroke-dasharray="3 4"
stroke-dashoffset="25"
fill="transparent"
class="stroke-outline-5"
/>
<mask id="path-4-inside-2_3194_60474" fill="currentColor" class="fill-foundation">
<path
d="M144.47 6.47994L85.7001 0.719944C83.3301 0.489944 81.0602 0.919944 78.9802 1.88994C76.9002 2.85994 74.9902 4.40994 73.3902 6.39994C71.7902 8.38994 70.4702 10.8199 69.5702 13.5799C68.6702 16.3399 68.1602 19.4199 68.1602 22.6899V111.8C68.1602 115.07 68.6602 118.15 69.5702 120.91C70.4802 123.67 71.7802 126.1 73.3902 128.09C75.0002 130.08 76.8902 131.61 78.9802 132.6C81.0702 133.59 83.3301 134.01 85.7001 133.77L144.46 128.01C146.42 127.82 148.28 127.05 149.97 125.83C151.66 124.61 153.14 122.95 154.39 120.96C155.64 118.97 156.64 116.66 157.34 114.13C158.04 111.6 158.41 108.87 158.41 106.02V28.4699C158.41 25.6199 158.03 22.8799 157.34 20.3599C156.65 17.8399 155.64 15.5199 154.39 13.5299C153.14 11.5399 151.64 9.86994 149.97 8.65994C148.3 7.44994 146.43 6.66994 144.46 6.47994"
/>
</mask>
<path
d="M144.47 6.47994L85.7001 0.719944C83.3301 0.489944 81.0602 0.919944 78.9802 1.88994C76.9002 2.85994 74.9902 4.40994 73.3902 6.39994C71.7902 8.38994 70.4702 10.8199 69.5702 13.5799C68.6702 16.3399 68.1602 19.4199 68.1602 22.6899V111.8C68.1602 115.07 68.6602 118.15 69.5702 120.91C70.4802 123.67 71.7802 126.1 73.3902 128.09C75.0002 130.08 76.8902 131.61 78.9802 132.6C81.0702 133.59 83.3301 134.01 85.7001 133.77L144.46 128.01C146.42 127.82 148.28 127.05 149.97 125.83C151.66 124.61 153.14 122.95 154.39 120.96C155.64 118.97 156.64 116.66 157.34 114.13C158.04 111.6 158.41 108.87 158.41 106.02V28.4699C158.41 25.6199 158.03 22.8799 157.34 20.3599C156.65 17.8399 155.64 15.5199 154.39 13.5299C153.14 11.5399 151.64 9.86994 149.97 8.65994C148.3 7.44994 146.43 6.66994 144.46 6.47994"
stroke="currentColor"
stroke-width="1"
fill="currentColor"
class="fill-foundation-2 stroke-outline-5"
/>
<path
d="M123.219 31.1665L100.475 41.2781V66.5779L114.281 62.9002V67.1559V62.9002L123.219 64.5086V31.1665Z"
fill="currentColor"
class="fill-foundation stroke-outline-5"
stroke="currentColor"
stroke-linejoin="round"
/>
<path
d="M92.0309 78.4568L109.816 74.9969V86.9096L92.0309 88.9704V78.4568ZM114.281 62.8999L100.475 66.5776L89.4004 69.5264V78.9594L92.0309 78.4568V88.9704L89.4004 89.272V100.004L114.281 99.1658V67.1556V62.8999Z"
fill="currentColor"
class="fill-foundation"
/>
<path
d="M92.0309 78.4568L109.816 74.9969V86.9096L92.0309 88.9704M92.0309 78.4568V88.9704M92.0309 78.4568L89.4004 78.9594V69.5264L100.475 66.5776L114.281 62.8999V67.1556V99.1658L89.4004 100.004V89.272L92.0309 88.9704"
class="stroke-outline-5"
stroke="currentColor"
stroke-linejoin="round"
/>
<path
d="M114.281 62.8999V67.1556V99.1658L140 97.0547V67.5326L123.22 64.5084L114.281 62.8999Z"
fill="currentColor"
class="fill-foundation stroke-outline-5"
stroke="currentColor"
stroke-linejoin="round"
/>
<path
d="M123.304 31.1743V64.5248L140 67.5323V38.4878L123.304 31.1743Z"
fill="currentColor"
class="fill-foundation stroke-outline-5"
stroke="currentColor"
stroke-linejoin="round"
/>
</svg>
</template>
@@ -0,0 +1,144 @@
<template>
<svg
width="194"
height="141"
viewBox="0 0 194 141"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect
x="0.585984"
y="0.177422"
width="136.5"
height="102.75"
rx="5.625"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 -0.0788556 59.0923)"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-2"
fill="currentClass"
stroke-width="1"
/>
<g clip-path="url(#clip0_3199_61296)">
<g clip-path="url(#clip1_3199_61296)">
<path
d="M70.2824 95.2933L109.853 89.7539L91.3457 65.9593L57.4464 78.7897L70.2824 95.2933Z"
fill="currentClass"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-page"
stroke-linejoin="round"
/>
<path
d="M152.677 64.5974L109.853 89.7541L91.3457 65.9595L142.236 51.1733L152.677 64.5974Z"
fill="currentClass"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-2"
stroke-linejoin="round"
/>
<path
d="M73.3722 50.6422L102.838 32.4529L118.925 53.1364L85.5759 66.3327L73.3722 50.6422Z"
fill="currentClass"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-page"
stroke-linejoin="round"
/>
<path
d="M147.845 62.3604L109.583 81.6142L100.721 70.2205L142.424 55.3906L147.845 62.3604Z"
ffill="currentClass"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-page"
stroke-linejoin="round"
/>
<path
d="M62.457 76.8955L76.129 94.4738"
stroke="currentClass"
class="stroke-outline-5"
stroke-miterlimit="10"
/>
<path
d="M68.167 74.7349L82.7952 93.5425"
stroke="currentClass"
class="stroke-outline-5"
stroke-miterlimit="10"
/>
<path
d="M74.7324 72.25L90.4587 92.4694"
stroke="currentClass"
class="stroke-outline-5"
stroke-miterlimit="10"
/>
<path
d="M82.3652 69.3608L99.3684 91.2221"
stroke="currentClass"
class="stroke-outline-5"
stroke-miterlimit="10"
/>
<path
d="M93.3637 68.5535L144.205 52.373L140.505 47.6161L86.7197 60.0112L93.3637 68.5535Z"
fill="currentClass"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-2"
stroke-linejoin="round"
/>
<path
d="M93.3634 68.5533L57.7386 80.975L53.1967 75.1355L86.7195 60.011L93.3634 68.5533Z"
fill="currentClass"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-page"
stroke-linejoin="round"
/>
<path
d="M137.005 48.4229L118.564 52.6721L102.838 32.4526L124.516 32.3656L137.005 48.4229Z"
fill="currentClass"
stroke="currentClass"
class="stroke-outline-5 fill-foundation-2"
stroke-linejoin="round"
/>
</g>
</g>
<rect
x="0.585984"
y="0.177422"
width="136.5"
height="102.75"
rx="5.625"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 -0.0788556 44.0923)"
stroke="currentClass"
class="stroke-outline-5 dash-moving"
stroke-width="1"
stroke-dashoffset="25"
stroke-dasharray="3 4"
/>
<defs>
<clipPath id="clip0_3199_61296">
<rect
width="137.25"
height="103.5"
rx="6"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 0 43.8696)"
fill="currentColor"
class="fill-foundation"
/>
</clipPath>
<clipPath id="clip1_3199_61296">
<rect
width="91"
height="60"
fill="currentColor"
class="fill-foundation"
transform="matrix(0.948683 -0.316228 0.613941 0.789352 37.0537 54.3804)"
/>
</clipPath>
</defs>
</svg>
</template>
<style scoped>
.dash-moving {
animation: dash 2s ease-in-out 0s 1 normal forwards running;
}
@keyframes dash {
100% {
stroke-dashoffset: 0;
}
}
</style>
@@ -9,7 +9,7 @@
<path
d="M7.49495 103.869L166.728 50.7911C170.436 49.5552 175.387 51.0542 177.786 54.1393L253.207 151.108C255.606 154.193 254.546 157.696 250.838 158.932L91.6048 212.01C87.897 213.246 82.946 211.747 80.5464 208.662L5.12605 111.693C2.72652 108.608 3.78711 105.105 7.49495 103.869Z"
stroke="currentColor"
class="stroke-outline-3"
class="stroke-outline-3 fade-in-y fade-in-y-delay"
/>
<path
d="M7.49495 79.8688L166.728 26.7911C170.436 25.5552 175.387 27.0542 177.786 30.1393L253.207 127.108C255.606 130.193 254.546 133.696 250.838 134.932L91.6048 188.01C87.897 189.246 82.946 187.747 80.5464 184.662L5.12605 87.6928C2.72652 84.6077 3.78711 81.1047 7.49495 79.8688Z"
@@ -19,7 +19,7 @@
<path
d="M7.49495 79.8688L166.728 26.7911C170.436 25.5552 175.387 27.0542 177.786 30.1393L253.207 127.108C255.606 130.193 254.546 133.696 250.838 134.932L91.6048 188.01C87.897 189.246 82.946 187.747 80.5464 184.662L5.12605 87.6928C2.72652 84.6077 3.78711 81.1047 7.49495 79.8688Z"
stroke="currentColor"
class="stroke-outline-2"
class="stroke-outline-2 fade-in-y"
/>
<path
d="M5.12605 63.6928C2.72652 60.6077 3.78711 57.1047 7.49495 55.8688L166.728 2.7911C170.436 1.55516 175.387 3.0542 177.786 6.1393L253.207 103.108C255.606 106.193 254.546 109.696 250.838 110.932L91.6048 164.01C87.897 165.246 82.946 163.747 80.5464 160.662L5.12605 63.6928Z"
@@ -149,3 +149,25 @@
</defs>
</svg>
</template>
<style scoped>
.fade-in-y {
opacity: 0;
animation: fade-in-y 1s ease-in-out forwards;
}
.fade-in-y-delay {
animation-delay: 0.25s;
}
@keyframes fade-in-y {
0% {
opacity: 0;
transform: translateY(-20px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
</style>
@@ -11,9 +11,8 @@
@files-selected="onFilesSelected"
>
<div
class="w-full h-full border-dashed border rounded-md p-4 flex items-center justify-center text-sm cursor-pointer"
class="w-full h-full border-dashed border rounded-md p-4 flex items-center justify-center text-sm"
:class="[getDashedBorderClasses(isDraggingFiles)]"
@click="openFilePicker"
>
<div
v-if="fileUpload"
@@ -35,15 +34,39 @@
:style="progressBarStyle"
/>
</div>
<span v-else class="text-body-xs text-foreground-2 text-center select-none">
Use our
<NuxtLink target="_blank" :to="connectorsRoute" class="font-medium" @click.stop>
<span class="underline">connectors</span>
</NuxtLink>
to publish a {{ modelName ? '' : 'new model' }} version to
{{ modelName ? 'this model' : 'this project' }}, or drag and drop a IFC/OBJ/STL
file here.
</span>
<div v-else :class="containerClasses">
<div :class="illustrationClasses">
<IllustrationEmptystateProject v-if="emptyStateVariant === 'modelsSection'" />
<IllustrationEmptystateProjectTab v-else />
</div>
<div>
<p v-if="showEmptyState" class="text-foreground-2 text-heading-sm p-0 m-0">
{{
emptyStateVariant === 'modelsSection'
? 'The project has no models, yet.'
: 'No models, yet.'
}}
</p>
<p :class="paragraphClasses">
Use
<NuxtLink :to="connectorsRoute" class="font-medium">
<span class="underline">connectors</span>
</NuxtLink>
to publish a {{ modelName ? '' : 'new model' }} version to
{{ modelName ? 'this model' : 'this project' }}, or drag and drop a
IFC/OBJ/STL file here.
</p>
<div v-if="showEmptyState" :class="buttonsClasses">
<FormButton :to="connectorsRoute" size="sm" color="outline">
Install connectors
</FormButton>
<FormButton size="sm" color="outline" @click="openFilePicker">
Upload a file
</FormButton>
</div>
</div>
</div>
</div>
</FormFileUploadZone>
</template>
@@ -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'
@@ -1,13 +1,18 @@
<template>
<div class="flex justify-center flex-col text-center my-12">
<h3 class="text-heading mt-2 text-foreground">
{{ title }}
</h3>
<h4 v-if="text" class="text-body-xs mb-4 mt-2 max-w-xs mx-auto text-foreground-2">
{{ text }}
</h4>
<div class="flex flex-col items-center gap-2">
<slot name="cta"></slot>
<div
class="w-full flex justify-center items-center p-20 gap-8 text-balance flex-col text-center"
>
<slot name="illustration"></slot>
<div>
<p class="text-foreground-2 text-heading-sm p-0 m-0">
{{ title }}
</p>
<p v-if="text" class="text-body-xs max-w-xs mx-auto text-foreground-2 mt-2 p-0">
{{ text }}
</p>
<div class="w-full flex flex-row justify-center max-w-xs mx-auto mt-3 flex-wrap">
<slot name="cta"></slot>
</div>
</div>
</div>
</template>
@@ -1,5 +1,8 @@
<template>
<ProjectEmptyState :small="small" title="No discussions, yet." :text="text">
<template #illustration>
<IllustrationEmptystateDiscussionTab />
</template>
<template #cta>
<div v-if="showButton" class="mt-3">
<FormButton :icon-left="PlusIcon" @click="() => $emit('new-discussion')">
@@ -84,6 +84,7 @@
>
<ProjectCardImportFileArea
ref="importArea"
empty-state-variant="modelGrid"
:project-id="projectId"
:model-name="model.name"
class="w-full h-full"
@@ -80,6 +80,7 @@ const logger = useLogger()
const infiniteLoadCacheBuster = ref(0)
const newSubmodelParent = ref('')
const showNewDialog = computed({
get: () => !!newSubmodelParent.value,
set: (newVal) => {
@@ -75,6 +75,9 @@
/>
<ProjectCardImportFileArea
v-else
:empty-state-variant="
props.gridOrList === GridListToggleValue.Grid ? 'modelGrid' : 'modelList'
"
:project-id="project.id"
:model-name="item.fullName"
:disabled="!canCreateModel.authorized"
@@ -238,6 +241,7 @@ import type { Nullable } from '@speckle/shared'
import { useMixpanel } from '~~/lib/core/composables/mp'
import { useIsModelExpanded } from '~~/lib/projects/composables/models'
import { HorizontalDirection } from '~~/lib/common/composables/window'
import { GridListToggleValue } from '~~/lib/layout/helpers/components'
/**
* TODO: The template in this file is a complete mess, needs refactoring
@@ -289,6 +293,7 @@ const props = defineProps<{
item: SingleLevelModelTreeItemFragment | PendingFileUploadFragment
project: ProjectPageModelsStructureItem_ProjectFragment
isSearchResult?: boolean
gridOrList?: GridListToggleValue
}>()
const router = useRouter()
@@ -108,6 +108,7 @@
/>
<ProjectCardImportFileArea
v-if="hasNoModels"
empty-state-variant="modelsSection"
:project-id="project.id"
:disabled="project?.workspace?.readOnly"
class="h-28 col-span-4"
@@ -22,10 +22,8 @@
v-if="showEmptyState"
class="bg-foundation-page h-96 flex flex-col items-center justify-center gap-4"
>
<WorkspaceEmptyStateIllustration />
<span class="text-body-2xs text-foreground-2 text-center">
Workspace is empty
</span>
<IllustrationEmptystateWorkspace />
<h2 class="text-heading-sm text-foreground-2 text-center">Workspace is empty</h2>
<WorkspaceAddProjectMenu
:workspace="workspace"
:workspace-slug="workspaceSlug"