feat: placeholder component in hoppscotch-ui (#3123)

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
This commit is contained in:
Anwarul Islam
2023-06-21 00:39:16 +06:00
committed by GitHub
parent 331d482b22
commit fc3e3aeaec
43 changed files with 378 additions and 577 deletions

42
.github/workflows/ui.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Deploy to Netlify (ui)
on:
push:
branches: [main]
# run this workflow only if an update is made to the ui package
paths:
- "packages/hoppscotch-ui/**"
workflow_dispatch:
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup environment
run: mv .env.example .env
- name: Setup pnpm
uses: pnpm/action-setup@v2.2.4
with:
version: 8
run_install: true
- name: Setup node
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node }}
cache: pnpm
- name: Build site
run: pnpm run generate-ui
# Deploy the ui site with netlify-cli
- name: Deploy to Netlify (ui)
run: npx netlify-cli deploy --dir=packages/hoppscotch-ui/.histoire/dist --prod
env:
NETLIFY_SITE_ID: ${{ secrets.NETLIFY_UI_SITE_ID }}
NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}

View File

@@ -86,6 +86,7 @@ declare module '@vue/runtime-core' {
HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink'] HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal'] HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture'] HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder']
HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing'] HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing']
HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup'] HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup']
HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver'] HoppSmartSlideOver: typeof import('@hoppscotch/ui')['HoppSmartSlideOver']
@@ -167,6 +168,7 @@ declare module '@vue/runtime-core' {
SmartLink: typeof import('./../../hoppscotch-ui/src/components/smart/Link.vue')['default'] SmartLink: typeof import('./../../hoppscotch-ui/src/components/smart/Link.vue')['default']
SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.vue')['default'] SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.vue')['default']
SmartPicture: typeof import('./../../hoppscotch-ui/src/components/smart/Picture.vue')['default'] SmartPicture: typeof import('./../../hoppscotch-ui/src/components/smart/Picture.vue')['default']
SmartPlaceholder: typeof import('./../../hoppscotch-ui/src/components/smart/Placeholder.vue')['default']
SmartProgressRing: typeof import('./../../hoppscotch-ui/src/components/smart/ProgressRing.vue')['default'] SmartProgressRing: typeof import('./../../hoppscotch-ui/src/components/smart/ProgressRing.vue')['default']
SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default'] SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default']
SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default'] SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default']

View File

@@ -10,15 +10,14 @@
@mouseover="selectedEntry = shortcutIndex" @mouseover="selectedEntry = shortcutIndex"
/> />
</div> </div>
<div <HoppSmartPlaceholder
v-if="searchResults.length === 0" v-if="searchResults.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="`${t('state.nothing_found')} ‟${search}”`"
> >
<icon-lucide-search class="pb-2 opacity-75 svg-icons" /> <template #icon>
<span class="my-2 text-center"> <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
{{ t("state.nothing_found") }} "{{ search }}" </template>
</span> </HoppSmartPlaceholder>
</div>
</div> </div>
</template> </template>

View File

@@ -39,15 +39,14 @@
/> />
</div> </div>
</details> </details>
<div <HoppSmartPlaceholder
v-if="searchResults.length === 0" v-if="searchResults.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="`${t('state.nothing_found')} ‟${filterText}”`"
> >
<icon-lucide-search class="pb-2 opacity-75 svg-icons" /> <template #icon>
<span class="my-2 text-center"> <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
{{ t("state.nothing_found") }} "{{ filterText }}" </template>
</span> </HoppSmartPlaceholder>
</div>
</div> </div>
<div v-else class="flex flex-col divide-y divide-dividerLight"> <div v-else class="flex flex-col divide-y divide-dividerLight">
<details <details

View File

@@ -243,49 +243,33 @@
/> />
</template> </template>
<template #emptyNode="{ node }"> <template #emptyNode="{ node }">
<div <HoppSmartPlaceholder
v-if="filterText.length !== 0 && filteredCollections.length === 0" v-if="filterText.length !== 0 && filteredCollections.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="`${t('state.nothing_found')}${filterText}`"
> >
<icon-lucide-search class="pb-2 opacity-75 svg-icons" /> <template #icon>
<span class="my-2 text-center"> <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
{{ t("state.nothing_found") }} "{{ filterText }}" </template>
</span> </HoppSmartPlaceholder>
</div> <HoppSmartPlaceholder
<div v-else-if="node === null"> v-else-if="node === null"
<div :src="`/images/states/${colorMode.value}/pack.svg`"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :alt="`${t('empty.collections')}`"
> :text="t('empty.collections')"
<img
:src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
:alt="`${t('empty.collections')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.collections") }}
</span>
<HoppButtonSecondary
:label="t('add.new')"
filled
outline
@click="emit('display-modal-add')"
/>
</div>
</div>
<div
v-else-if="node.data.type === 'collections'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
> >
<img <HoppButtonSecondary
:src="`/images/states/${colorMode.value}/pack.svg`" :label="t('add.new')"
loading="lazy" filled
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4" outline
:alt="`${t('empty.collection')}`" @click="emit('display-modal-add')"
/> />
<span class="pb-4 text-center"> </HoppSmartPlaceholder>
{{ t("empty.collection") }} <HoppSmartPlaceholder
</span> v-else-if="node.data.type === 'collections'"
:src="`/images/states/${colorMode.value}/pack.svg`"
:alt="`${t('empty.collections')}`"
:text="t('empty.collections')"
>
<HoppButtonSecondary <HoppButtonSecondary
:label="t('add.new')" :label="t('add.new')"
filled filled
@@ -298,21 +282,14 @@
}) })
" "
/> />
</div> </HoppSmartPlaceholder>
<div <HoppSmartPlaceholder
v-else-if="node.data.type === 'folders'" v-else-if="node.data.type === 'folders'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/pack.svg`"
:alt="`${t('empty.folder')}`"
:text="t('empty.folder')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
:alt="`${t('empty.folder')}`"
/>
<span class="text-center">
{{ t("empty.folder") }}
</span>
</div>
</template> </template>
</SmartTree> </SmartTree>
</div> </div>

View File

@@ -262,67 +262,53 @@
</template> </template>
<template #emptyNode="{ node }"> <template #emptyNode="{ node }">
<div v-if="node === null"> <div v-if="node === null">
<div <div @drop="(e) => e.stopPropagation()">
class="flex flex-col items-center justify-center p-4 text-secondaryLight" <HoppSmartPlaceholder
@drop="(e) => e.stopPropagation()"
>
<img
:src="`/images/states/${colorMode.value}/pack.svg`" :src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy" :alt="`${t('empty.collections')}`"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4" :text="t('empty.collections')"
:alt="`${t('empty.collection')}`" >
/> <HoppButtonSecondary
<span class="pb-4 text-center"> v-if="hasNoTeamAccess"
{{ t("empty.collections") }} v-tippy="{ theme: 'tooltip' }"
</span> disabled
<HoppButtonSecondary filled
v-if="hasNoTeamAccess" outline
v-tippy="{ theme: 'tooltip' }" :title="t('team.no_access')"
disabled :label="t('action.new')"
filled />
outline <HoppButtonSecondary
:title="t('team.no_access')" v-else
:label="t('action.new')" :icon="IconPlus"
/> :label="t('action.new')"
<HoppButtonSecondary filled
v-else outline
:icon="IconPlus" @click="emit('display-modal-add')"
:label="t('action.new')" />
filled </HoppSmartPlaceholder>
outline
@click="emit('display-modal-add')"
/>
</div> </div>
</div> </div>
<div <div
v-else-if="node.data.type === 'collections'" v-else-if="node.data.type === 'collections'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
@drop="(e) => e.stopPropagation()" @drop="(e) => e.stopPropagation()"
> >
<img <HoppSmartPlaceholder
:src="`/images/states/${colorMode.value}/pack.svg`" :src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy" :alt="`${t('empty.collections')}`"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4" :text="t('empty.collections')"
:alt="`${t('empty.collection')}`" >
/> </HoppSmartPlaceholder>
<span class="pb-4 text-center">
{{ t("empty.collections") }}
</span>
</div> </div>
<div <div
v-else-if="node.data.type === 'folders'" v-else-if="node.data.type === 'folders'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight"
@drop="(e) => e.stopPropagation()" @drop="(e) => e.stopPropagation()"
> >
<img <HoppSmartPlaceholder
:src="`/images/states/${colorMode.value}/pack.svg`" :src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
:alt="`${t('empty.folder')}`" :alt="`${t('empty.folder')}`"
/> :text="t('empty.folder')"
<span class="text-center"> >
{{ t("empty.folder") }} </HoppSmartPlaceholder>
</span>
</div> </div>
</template> </template>
</SmartTree> </SmartTree>

View File

@@ -171,21 +171,14 @@
@duplicate-request="$emit('duplicate-request', $event)" @duplicate-request="$emit('duplicate-request', $event)"
@select="$emit('select', $event)" @select="$emit('select', $event)"
/> />
<div <HoppSmartPlaceholder
v-if=" v-if="
collection.folders.length === 0 && collection.requests.length === 0 collection.folders.length === 0 && collection.requests.length === 0
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/pack.svg`"
:alt="`${t('empty.collection')}`"
:text="t('empty.collection')"
> >
<img
:src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
:alt="`${t('empty.collection')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.collection") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="t('add.new')" :label="t('add.new')"
filled filled
@@ -196,7 +189,7 @@
}) })
" "
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</div> </div>
<HoppSmartConfirmModal <HoppSmartConfirmModal

View File

@@ -160,25 +160,19 @@
@duplicate-request="emit('duplicate-request', $event)" @duplicate-request="emit('duplicate-request', $event)"
@select="emit('select', $event)" @select="emit('select', $event)"
/> />
<div
<HoppSmartPlaceholder
v-if=" v-if="
folder.folders && folder.folders &&
folder.folders.length === 0 && folder.folders.length === 0 &&
folder.requests && folder.requests &&
folder.requests.length === 0 folder.requests.length === 0
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/pack.svg`"
:alt="`${t('empty.folder')}`"
:text="t('empty.folder')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
:alt="`${t('empty.folder')}`"
/>
<span class="text-center">
{{ t("empty.folder") }}
</span>
</div>
</div> </div>
</div> </div>
<HoppSmartConfirmModal <HoppSmartConfirmModal

View File

@@ -60,35 +60,27 @@
@select="$emit('select', $event)" @select="$emit('select', $event)"
/> />
</div> </div>
<div <HoppSmartPlaceholder
v-if="collections.length === 0" v-if="collections.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/pack.svg`"
:alt="`${t('empty.collections')}`"
:text="t('empty.collections')"
> >
<img
:src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="t('empty.collections')"
/>
<span class="pb-4 text-center">
{{ t("empty.collections") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="t('add.new')" :label="t('add.new')"
filled filled
outline outline
@click="displayModalAdd(true)" @click="displayModalAdd(true)"
/> />
</div> </HoppSmartPlaceholder>
<div <HoppSmartPlaceholder
v-if="!(filteredCollections.length !== 0 || collections.length === 0)" v-if="!(filteredCollections.length !== 0 || collections.length === 0)"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="`${t('state.nothing_found')}${filterText}`"
> >
<icon-lucide-search class="pb-2 opacity-75 svg-icons" /> <template #icon>
<span class="my-2 text-center"> <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
{{ t("state.nothing_found") }} "{{ filterText }}" </template>
</span> </HoppSmartPlaceholder>
</div>
<CollectionsGraphqlAdd <CollectionsGraphqlAdd
:show="showModalAdd" :show="showModalAdd"
@hide-modal="displayModalAdd(false)" @hide-modal="displayModalAdd(false)"

View File

@@ -70,20 +70,13 @@
} }
" "
/> />
<div <HoppSmartPlaceholder
v-if="myEnvironments.length === 0" v-if="myEnvironments.length === 0"
class="flex flex-col items-center justify-center text-secondaryLight" :src="`/images/states/${colorMode.value}/blockchain.svg`"
:alt="`${t('empty.environments')}`"
:text="t('empty.environments')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-2"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-2 text-center">
{{ t("empty.environments") }}
</span>
</div>
</HoppSmartTab> </HoppSmartTab>
<HoppSmartTab <HoppSmartTab
:id="'team-environments'" :id="'team-environments'"
@@ -119,20 +112,14 @@
} }
" "
/> />
<div
<HoppSmartPlaceholder
v-if="teamEnvironmentList.length === 0" v-if="teamEnvironmentList.length === 0"
class="flex flex-col items-center justify-center text-secondaryLight" :src="`/images/states/${colorMode.value}/blockchain.svg`"
:alt="`${t('empty.environments')}`"
:text="t('empty.environments')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-2"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-2 text-center">
{{ t("empty.environments") }}
</span>
</div>
</div> </div>
<div <div
v-if="!teamListLoading && teamAdapterError" v-if="!teamListLoading && teamAdapterError"

View File

@@ -79,26 +79,19 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="vars.length === 0" v-if="vars.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/blockchain.svg`"
:alt="`${t('empty.environments')}`"
:text="t('empty.environments')"
> >
<img
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.environments") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="`${t('add.new')}`" :label="`${t('add.new')}`"
filled filled
class="mb-4" class="mb-4"
@click="addEnvironmentVariable" @click="addEnvironmentVariable"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -32,19 +32,12 @@
:environment="environment" :environment="environment"
@edit-environment="editEnvironment(index)" @edit-environment="editEnvironment(index)"
/> />
<div <HoppSmartPlaceholder
v-if="environments.length === 0" v-if="environments.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/blockchain.svg`"
:alt="`${t('empty.environments')}`"
:text="t('empty.environments')"
> >
<img
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.environments") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="`${t('add.new')}`" :label="`${t('add.new')}`"
filled filled
@@ -52,7 +45,7 @@
class="mb-4" class="mb-4"
@click="displayModalAdd(true)" @click="displayModalAdd(true)"
/> />
</div> </HoppSmartPlaceholder>
<EnvironmentsMyDetails <EnvironmentsMyDetails
:show="showModalDetails" :show="showModalDetails"
:action="action" :action="action"

View File

@@ -83,19 +83,12 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="vars.length === 0" v-if="vars.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/blockchain.svg`"
:alt="`${t('empty.environments')}`"
:text="t('empty.environments')"
> >
<img
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.environments") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
v-if="isViewer" v-if="isViewer"
disabled disabled
@@ -110,7 +103,7 @@
class="mb-4" class="mb-4"
@click="addEnvironmentVariable" @click="addEnvironmentVariable"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -43,19 +43,12 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="!loading && teamEnvironments.length === 0 && !adapterError" v-if="!loading && teamEnvironments.length === 0 && !adapterError"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/blockchain.svg`"
:alt="`${t('empty.environments')}`"
:text="t('empty.environments')"
> >
<img
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.environments')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.environments") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
v-if="team === undefined || team.myRole === 'VIEWER'" v-if="team === undefined || team.myRole === 'VIEWER'"
v-tippy="{ theme: 'tooltip' }" v-tippy="{ theme: 'tooltip' }"
@@ -74,7 +67,7 @@
class="mb-4" class="mb-4"
@click="displayModalAdd(true)" @click="displayModalAdd(true)"
/> />
</div> </HoppSmartPlaceholder>
<div v-else-if="!loading"> <div v-else-if="!loading">
<EnvironmentsTeamsEnvironment <EnvironmentsTeamsEnvironment
v-for="(environment, index) in JSON.parse( v-for="(environment, index) in JSON.parse(

View File

@@ -114,19 +114,12 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="authType === 'none'" v-if="authType === 'none'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/login.svg`"
:alt="`${t('empty.authorization')}`"
:text="t('empty.authorization')"
> >
<img
:src="`/images/states/${colorMode.value}/login.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.authorization')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.authorization") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
outline outline
:label="t('app.documentation')" :label="t('app.documentation')"
@@ -136,7 +129,7 @@
reverse reverse
class="mb-4" class="mb-4"
/> />
</div> </HoppSmartPlaceholder>
<div v-else class="flex flex-1 border-b border-dividerLight"> <div v-else class="flex flex-1 border-b border-dividerLight">
<div class="w-2/3 border-r border-dividerLight"> <div class="w-2/3 border-r border-dividerLight">
<div v-if="authType === 'basic'"> <div v-if="authType === 'basic'">

View File

@@ -289,19 +289,12 @@
</div> </div>
</template> </template>
</draggable> </draggable>
<div <HoppSmartPlaceholder
v-if="workingHeaders.length === 0" v-if="workingHeaders.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_category.svg`"
:alt="`${t('empty.headers')}`"
:text="t('empty.headers')"
> >
<img
:src="`/images/states/${colorMode.value}/add_category.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.headers')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.headers") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="`${t('add.new')}`" :label="`${t('add.new')}`"
filled filled
@@ -309,7 +302,7 @@
class="mb-4" class="mb-4"
@click="addHeader" @click="addHeader"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</HoppSmartTab> </HoppSmartTab>
<HoppSmartTab :id="'authorization'" :label="`${t('tab.authorization')}`"> <HoppSmartTab :id="'authorization'" :label="`${t('tab.authorization')}`">

View File

@@ -1,12 +1,13 @@
<template> <template>
<div class="flex flex-col flex-1 overflow-auto whitespace-nowrap"> <div class="flex flex-col flex-1 overflow-auto whitespace-nowrap">
<div <HoppSmartPlaceholder
v-if="responseString === 'loading'" v-if="responseString === 'loading'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="t('state.loading')"
> >
<HoppSmartSpinner class="my-4" /> <template #icon>
<span class="text-secondaryLight">{{ t("state.loading") }}</span> <HoppSmartSpinner class="my-4" />
</div> </template>
</HoppSmartPlaceholder>
<div v-else-if="responseString" class="flex flex-col flex-1"> <div v-else-if="responseString" class="flex flex-col flex-1">
<div <div
class="sticky top-0 z-10 flex items-center justify-between flex-shrink-0 pl-4 overflow-x-auto border-b bg-primary border-dividerLight" class="sticky top-0 z-10 flex items-center justify-between flex-shrink-0 pl-4 overflow-x-auto border-b bg-primary border-dividerLight"

View File

@@ -24,25 +24,18 @@
:icon="IconBookOpen" :icon="IconBookOpen"
:label="`${t('tab.documentation')}`" :label="`${t('tab.documentation')}`"
> >
<div <HoppSmartPlaceholder
v-if=" v-if="
queryFields.length === 0 && queryFields.length === 0 &&
mutationFields.length === 0 && mutationFields.length === 0 &&
subscriptionFields.length === 0 && subscriptionFields.length === 0 &&
graphqlTypes.length === 0 graphqlTypes.length === 0
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_comment.svg`"
:alt="`${t('empty.documentation')}`"
:text="t('empty.documentation')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/add_comment.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.documentation')}`"
/>
<span class="mb-4 text-center">
{{ t("empty.documentation") }}
</span>
</div>
<div v-else> <div v-else>
<div <div
class="sticky top-0 z-10 flex flex-shrink-0 overflow-x-auto bg-primary" class="sticky top-0 z-10 flex flex-shrink-0 overflow-x-auto bg-primary"
@@ -172,20 +165,13 @@
ref="schemaEditor" ref="schemaEditor"
class="flex flex-col flex-1" class="flex flex-col flex-1"
></div> ></div>
<div <HoppSmartPlaceholder
v-else v-else
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/blockchain.svg`"
:alt="`${t('empty.schema')}`"
:text="t('empty.schema')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/blockchain.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.schema')}`"
/>
<span class="mb-4 text-center">
{{ t("empty.schema") }}
</span>
</div>
</HoppSmartTab> </HoppSmartTab>
</HoppSmartTabs> </HoppSmartTabs>
</template> </template>

View File

@@ -106,31 +106,23 @@
/> />
</details> </details>
</div> </div>
<div <HoppSmartPlaceholder
v-if="history.length === 0" v-if="history.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/history.svg`"
:alt="`${t('empty.history')}`"
:text="t('empty.history')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/history.svg`" <HoppSmartPlaceholder
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.history')}`"
/>
<span class="mb-4 text-center">
{{ t("empty.history") }}
</span>
</div>
<div
v-else-if=" v-else-if="
Object.keys(filteredHistoryGroups).length === 0 || Object.keys(filteredHistoryGroups).length === 0 ||
filteredHistory.length === 0 filteredHistory.length === 0
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="`${t('state.nothing_found')} ‟${filterText || filterSelection}”`"
> >
<icon-lucide-search class="pb-2 opacity-75 svg-icons" /> <template #icon>
<span class="mt-2 mb-4 text-center"> <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
{{ t("state.nothing_found") }} "{{ filterText || filterSelection }}" </template>
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="t('action.clear')" :label="t('action.clear')"
outline outline
@@ -141,7 +133,7 @@
} }
" "
/> />
</div> </HoppSmartPlaceholder>
<HoppSmartConfirmModal <HoppSmartConfirmModal
:show="confirmRemove" :show="confirmRemove"
:title="`${t('confirm.remove_history')}`" :title="`${t('confirm.remove_history')}`"

View File

@@ -113,17 +113,12 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="auth.authType === 'none'" v-if="auth.authType === 'none'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/login.svg`"
:alt="`${t('empty.authorization')}`"
:text="t('empty.authorization')"
> >
<img
:src="`/images/states/${colorMode.value}/login.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.authorization')}`"
/>
<span class="pb-4 text-center">{{ t("empty.authorization") }}</span>
<HoppButtonSecondary <HoppButtonSecondary
outline outline
:label="t('app.documentation')" :label="t('app.documentation')"
@@ -133,7 +128,7 @@
reverse reverse
class="mb-4" class="mb-4"
/> />
</div> </HoppSmartPlaceholder>
<div v-else class="flex flex-1 border-b border-dividerLight"> <div v-else class="flex flex-1 border-b border-dividerLight">
<div class="w-2/3 border-r border-dividerLight"> <div class="w-2/3 border-r border-dividerLight">
<div v-if="auth.authType === 'basic'"> <div v-if="auth.authType === 'basic'">

View File

@@ -102,17 +102,12 @@
v-model="body" v-model="body"
/> />
<HttpRawBody v-else-if="body.contentType !== null" v-model="body" /> <HttpRawBody v-else-if="body.contentType !== null" v-model="body" />
<div <HoppSmartPlaceholder
v-if="body.contentType == null" v-if="body.contentType == null"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/upload_single_file.svg`"
:alt="`${t('empty.body')}`"
:text="t('empty.body')"
> >
<img
:src="`/images/states/${colorMode.value}/upload_single_file.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.body')}`"
/>
<span class="pb-4 text-center">{{ t("empty.body") }}</span>
<HoppButtonSecondary <HoppButtonSecondary
outline outline
:label="`${t('app.documentation')}`" :label="`${t('app.documentation')}`"
@@ -122,7 +117,7 @@
reverse reverse
class="mb-4" class="mb-4"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</template> </template>

View File

@@ -152,17 +152,12 @@
</template> </template>
</draggable> </draggable>
<div <HoppSmartPlaceholder
v-if="workingParams.length === 0" v-if="workingParams.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/upload_single_file.svg`"
:alt="`${t('empty.body')}`"
:text="t('empty.body')"
> >
<img
:src="`/images/states/${colorMode.value}/upload_single_file.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.body')}`"
/>
<span class="pb-4 text-center">{{ t("empty.body") }}</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="`${t('add.new')}`" :label="`${t('add.new')}`"
filled filled
@@ -170,7 +165,7 @@
class="mb-4" class="mb-4"
@click="addBodyParam" @click="addBodyParam"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</template> </template>

View File

@@ -56,20 +56,19 @@
} }
" "
/> />
<div <HoppSmartPlaceholder
v-if=" v-if="
!( !(
filteredCodegenDefinitions.length !== 0 || filteredCodegenDefinitions.length !== 0 ||
CodegenDefinitions.length === 0 CodegenDefinitions.length === 0
) )
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="`${t('state.nothing_found')}${searchQuery}`"
> >
<icon-lucide-search class="pb-2 opacity-75 svg-icons" /> <template #icon>
<span class="my-2 text-center"> <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
{{ t("state.nothing_found") }} "{{ searchQuery }}" </template>
</span> </HoppSmartPlaceholder>
</div>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -202,17 +202,12 @@
</div> </div>
</template> </template>
</draggable> </draggable>
<div <HoppSmartPlaceholder
v-if="workingHeaders.length === 0" v-if="workingHeaders.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_category.svg`"
:alt="`${t('empty.headers')}`"
:text="t('empty.headers')"
> >
<img
:src="`/images/states/${colorMode.value}/add_category.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.headers')}`"
/>
<span class="pb-4 text-center">{{ t("empty.headers") }}</span>
<HoppButtonSecondary <HoppButtonSecondary
filled filled
:label="`${t('add.new')}`" :label="`${t('add.new')}`"
@@ -220,7 +215,7 @@
class="mb-4" class="mb-4"
@click="addHeader" @click="addHeader"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -145,18 +145,12 @@
</div> </div>
</template> </template>
</draggable> </draggable>
<HoppSmartPlaceholder
<div
v-if="workingParams.length === 0" v-if="workingParams.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_files.svg`"
:alt="`${t('empty.parameters')}`"
:text="t('empty.parameters')"
> >
<img
:src="`/images/states/${colorMode.value}/add_files.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.parameters')}`"
/>
<span class="pb-4 text-center">{{ t("empty.parameters") }}</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="`${t('add.new')}`" :label="`${t('add.new')}`"
:icon="IconPlus" :icon="IconPlus"
@@ -164,7 +158,7 @@
class="mb-4" class="mb-4"
@click="addParam" @click="addParam"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -11,51 +11,29 @@
<HoppSmartSpinner class="my-4" /> <HoppSmartSpinner class="my-4" />
<span class="text-secondaryLight">{{ t("state.loading") }}</span> <span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div> </div>
<div <HoppSmartPlaceholder
v-if="response.type === 'network_fail'" v-if="response.type === 'network_fail'"
class="flex flex-col items-center justify-center flex-1 p-4" :src="`/images/states/${colorMode.value}/youre_lost.svg`"
:alt="`${t('error.network_fail')}`"
:heading="t('error.network_fail')"
:text="t('helpers.network_fail')"
> >
<img
:src="`/images/states/${colorMode.value}/youre_lost.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-32 h-32 my-4"
:alt="`${t('error.network_fail')}`"
/>
<span class="mb-2 font-semibold text-center">
{{ t("error.network_fail") }}
</span>
<span
class="max-w-sm mb-6 text-center whitespace-normal text-secondaryLight"
>
{{ t("helpers.network_fail") }}
</span>
<AppInterceptor class="p-2 border rounded border-dividerLight" /> <AppInterceptor class="p-2 border rounded border-dividerLight" />
</div> </HoppSmartPlaceholder>
<div <HoppSmartPlaceholder
v-if="response.type === 'script_fail'" v-if="response.type === 'script_fail'"
class="flex flex-col items-center justify-center flex-1 p-4" :src="`/images/states/${colorMode.value}/youre_lost.svg`"
:alt="`${t('error.script_fail')}`"
:label="t('error.script_fail')"
:text="t('helpers.script_fail')"
> >
<img
:src="`/images/states/${colorMode.value}/youre_lost.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-32 h-32 my-4"
:alt="`${t('error.script_fail')}`"
/>
<span class="mb-2 font-semibold text-center">
{{ t("error.script_fail") }}
</span>
<span
class="max-w-sm mb-6 text-center whitespace-normal text-secondaryLight"
>
{{ t("helpers.script_fail") }}
</span>
<div <div
class="w-full px-4 py-2 overflow-auto font-mono text-red-400 whitespace-normal rounded bg-primaryLight" class="mt-2 w-full px-4 py-2 overflow-auto font-mono text-red-400 whitespace-normal rounded bg-primaryLight"
> >
{{ response.error.name }}: {{ response.error.message }}<br /> {{ response.error.name }}: {{ response.error.message }}<br />
{{ response.error.stack }} {{ response.error.stack }}
</div> </div>
</div> </HoppSmartPlaceholder>
<div <div
v-if="response.type === 'success' || response.type === 'fail'" v-if="response.type === 'success' || response.type === 'fail'"
class="flex items-center font-semibold text-tiny" class="flex items-center font-semibold text-tiny"

View File

@@ -151,41 +151,21 @@
</div> </div>
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-else-if="testResults && testResults.scriptError" v-else-if="testResults && testResults.scriptError"
class="flex flex-col items-center justify-center flex-1 p-4" :src="`/images/states/${colorMode.value}/youre_lost.svg`"
:alt="`${t('error.test_script_fail')}`"
:heading="t('error.test_script_fail')"
:text="t('helpers.test_script_fail')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/youre_lost.svg`" <HoppSmartPlaceholder
loading="lazy"
class="inline-flex flex-col object-contain object-center w-32 h-32 my-4"
:alt="`${t('error.test_script_fail')}`"
/>
<span class="mb-2 font-semibold text-center">
{{ t("error.test_script_fail") }}
</span>
<span
class="max-w-sm mb-6 text-center whitespace-normal text-secondaryLight"
>
{{ t("helpers.test_script_fail") }}
</span>
</div>
<div
v-else v-else
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/validation.svg`"
:alt="`${t('empty.tests')}`"
:heading="t('empty.tests')"
:text="t('helpers.tests')"
> >
<img
:src="`/images/states/${colorMode.value}/validation.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.tests')}`"
/>
<span class="pb-2 text-center">
{{ t("empty.tests") }}
</span>
<span class="pb-4 text-center">
{{ t("helpers.tests") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
outline outline
:label="`${t('action.learn_more')}`" :label="`${t('action.learn_more')}`"
@@ -195,7 +175,7 @@
reverse reverse
class="my-4" class="my-4"
/> />
</div> </HoppSmartPlaceholder>
<EnvironmentsMyDetails <EnvironmentsMyDetails
:show="showMyEnvironmentDetailsModal" :show="showMyEnvironmentDetailsModal"
action="new" action="new"

View File

@@ -143,19 +143,12 @@
</div> </div>
</template> </template>
</draggable> </draggable>
<div <HoppSmartPlaceholder
v-if="workingUrlEncodedParams.length === 0" v-if="workingUrlEncodedParams.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_category.svg`"
:alt="`${t('empty.body')}`"
:text="t('empty.body')"
> >
<img
:src="`/images/states/${colorMode.value}/add_category.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.body')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.body") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
filled filled
:label="`${t('add.new')}`" :label="`${t('add.new')}`"
@@ -163,7 +156,7 @@
class="mb-4" class="mb-4"
@click="addUrlEncodedParam" @click="addUrlEncodedParam"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -11,20 +11,13 @@
<HoppSmartSpinner class="mb-4" /> <HoppSmartSpinner class="mb-4" />
<span class="text-secondaryLight">{{ t("state.loading") }}</span> <span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div> </div>
<div <HoppSmartPlaceholder
v-if="!loading && myShortcodes.length === 0" v-if="!loading && myShortcodes.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_files.svg`"
:alt="`${t('empty.shortcodes')}`"
:text="t('empty.shortcodes')"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/add_files.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-8"
:alt="`${t('empty.shortcodes')}`"
/>
<span class="mb-4 text-center">
{{ t("empty.shortcodes") }}
</span>
</div>
<div v-else-if="!loading"> <div v-else-if="!loading">
<div <div
class="hidden w-full border-t rounded-t bg-primaryLight lg:flex border-x border-dividerLight" class="hidden w-full border-t rounded-t bg-primaryLight lg:flex border-x border-dividerLight"

View File

@@ -52,20 +52,19 @@
" "
/> />
</HoppSmartLink> </HoppSmartLink>
<div <HoppSmartPlaceholder
v-if=" v-if="
!( !(
filteredAppLanguages.length !== 0 || filteredAppLanguages.length !== 0 ||
APP_LANGUAGES.length === 0 APP_LANGUAGES.length === 0
) )
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="`${t('state.nothing_found')}${searchQuery}`"
> >
<icon-lucide-search class="pb-2 opacity-75 svg-icons" /> <template #icon>
<span class="my-2 text-center"> <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
{{ t("state.nothing_found") }} "{{ searchQuery }}" </template>
</span> </HoppSmartPlaceholder>
</div>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -47,19 +47,12 @@
" "
class="border rounded border-divider" class="border rounded border-divider"
> >
<div <HoppSmartPlaceholder
v-if="teamDetails.data.right.team.teamMembers === 0" v-if="teamDetails.data.right.team.teamMembers === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_group.svg`"
:alt="`${t('empty.members')}`"
:text="t('empty.members')"
> >
<img
:src="`/images/states/${colorMode.value}/add_group.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.members')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.members") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:icon="IconUserPlus" :icon="IconUserPlus"
:label="t('team.invite')" :label="t('team.invite')"
@@ -69,7 +62,7 @@
} }
" "
/> />
</div> </HoppSmartPlaceholder>
<div v-else class="divide-y divide-dividerLight"> <div v-else class="divide-y divide-dividerLight">
<div <div
v-for="(member, index) in membersList" v-for="(member, index) in membersList"

View File

@@ -98,17 +98,14 @@
</div> </div>
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if=" v-if="
E.isRight(pendingInvites.data) && E.isRight(pendingInvites.data) &&
pendingInvites.data.right.team.teamInvitations.length === 0 pendingInvites.data.right.team.teamInvitations.length === 0
" "
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :text="t('empty.pending_invites')"
> >
<span class="text-center"> </HoppSmartPlaceholder>
{{ t("empty.pending_invites") }}
</span>
</div>
<div <div
v-if="!pendingInvites.loading && E.isLeft(pendingInvites.data)" v-if="!pendingInvites.loading && E.isLeft(pendingInvites.data)"
class="flex flex-col items-center p-4" class="flex flex-col items-center p-4"
@@ -221,25 +218,18 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="newInvites.length === 0" v-if="newInvites.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_group.svg`"
:alt="`${t('empty.invites')}`"
:text="`${t('empty.invites')}`"
> >
<img
:src="`/images/states/${colorMode.value}/add_group.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
:alt="`${t('empty.invites')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.invites") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="t('add.new')" :label="t('add.new')"
filled filled
@click="addNewInvitee" @click="addNewInvitee"
/> />
</div> </HoppSmartPlaceholder>
</div> </div>
<div <div
v-if="newInvites.length" v-if="newInvites.length"

View File

@@ -10,25 +10,18 @@
<HoppSmartSpinner class="mb-4" /> <HoppSmartSpinner class="mb-4" />
<span class="text-secondaryLight">{{ t("state.loading") }}</span> <span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div> </div>
<div <HoppSmartPlaceholder
v-if="!loading && myTeams.length === 0" v-if="!loading && myTeams.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_group.svg`"
:alt="`${t('empty.teams')}`"
:text="`${t('empty.teams')}`"
> >
<img
:src="`/images/states/${colorMode.value}/add_group.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-8"
:alt="`${t('empty.teams')}`"
/>
<span class="mb-4 text-center">
{{ t("empty.teams") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="`${t('team.create_new')}`" :label="`${t('team.create_new')}`"
filled filled
@click="displayModalAdd(true)" @click="displayModalAdd(true)"
/> />
</div> </HoppSmartPlaceholder>
<div <div
v-else-if="!loading" v-else-if="!loading"
class="grid gap-4" class="grid gap-4"

View File

@@ -15,19 +15,12 @@
<HoppSmartSpinner class="mb-4" /> <HoppSmartSpinner class="mb-4" />
<span class="text-secondaryLight">{{ t("state.loading") }}</span> <span class="text-secondaryLight">{{ t("state.loading") }}</span>
</div> </div>
<div <HoppSmartPlaceholder
v-if="!loading && myTeams.length === 0" v-if="!loading && myTeams.length === 0"
class="flex flex-col items-center justify-center flex-1 p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_group.svg`"
:alt="`${t('empty.teams')}`"
:text="`${t('empty.teams')}`"
> >
<img
:src="`/images/states/${colorMode.value}/add_group.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-8"
:alt="`${t('empty.teams')}`"
/>
<span class="mb-4 text-center">
{{ t("empty.teams") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="t('team.create_new')" :label="t('team.create_new')"
filled filled
@@ -35,7 +28,7 @@
:icon="IconPlus" :icon="IconPlus"
@click="displayModalAdd(true)" @click="displayModalAdd(true)"
/> />
</div> </HoppSmartPlaceholder>
<div v-else-if="!loading" class="flex flex-col"> <div v-else-if="!loading" class="flex flex-col">
<div <div
class="sticky top-0 z-10 flex items-center justify-between py-2 pl-2 mb-2 -top-2 bg-popover" class="sticky top-0 z-10 flex items-center justify-between py-2 pl-2 mb-2 -top-2 bg-popover"

View File

@@ -8,25 +8,18 @@
> >
<HoppSmartSpinner class="mb-4" /> <HoppSmartSpinner class="mb-4" />
</div> </div>
<div <HoppSmartPlaceholder
v-else-if="currentUser === null" v-else-if="currentUser === null"
class="flex flex-col items-center justify-center" :src="`/images/states/${colorMode.value}/login.svg`"
:alt="`${t('empty.profile')}`"
:text="`${t('empty.profile')}`"
> >
<img
:src="`/images/states/${colorMode.value}/login.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-24 h-24 my-4"
:alt="`${t('empty.parameters')}`"
/>
<p class="pb-4 text-center text-secondaryLight">
{{ t("empty.profile") }}
</p>
<HoppButtonPrimary <HoppButtonPrimary
:label="t('auth.login')" :label="t('auth.login')"
class="mb-4" class="mb-4"
@click="invokeAction('modals.login.toggle')" @click="invokeAction('modals.login.toggle')"
/> />
</div> </HoppSmartPlaceholder>
<div v-else class="space-y-8"> <div v-else class="space-y-8">
<div <div
class="h-24 rounded bg-primaryLight -mb-11 md:h-32" class="h-24 rounded bg-primaryLight -mb-11 md:h-32"

View File

@@ -136,28 +136,19 @@
</span> </span>
</div> </div>
</div> </div>
<HoppSmartPlaceholder
<div
v-if="topics.length === 0" v-if="topics.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/pack.svg`"
:alt="`${t('empty.subscription')}`"
:text="`${t('empty.subscription')}`"
> >
<img
:src="`/images/states/${colorMode.value}/pack.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.subscription')}`"
/>
<span class="pb-4 text-center">
{{ t("empty.subscription") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:label="t('mqtt.new')" :label="t('mqtt.new')"
filled filled
outline outline
@click="showSubscriptionModal(true)" @click="showSubscriptionModal(true)"
/> />
</div> </HoppSmartPlaceholder>
<div v-else> <div v-else>
<div <div
v-for="(topic, index) in topics" v-for="(topic, index) in topics"

View File

@@ -190,19 +190,12 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="authType === 'None'" v-if="authType === 'None'"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/login.svg`"
:alt="`${t('socketio.connection_not_authorized')}`"
:text="`${t('socketio.connection_not_authorized')}`"
> >
<img
:src="`/images/states/${colorMode.value}/login.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.authorization')}`"
/>
<span class="pb-4 text-center">
{{ t("socketio.connection_not_authorized") }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
outline outline
:label="t('app.documentation')" :label="t('app.documentation')"
@@ -212,7 +205,7 @@
reverse reverse
class="mb-4" class="mb-4"
/> />
</div> </HoppSmartPlaceholder>
<div <div
v-if="authType === 'Bearer'" v-if="authType === 'Bearer'"
class="flex flex-1 border-b border-dividerLight" class="flex flex-1 border-b border-dividerLight"

View File

@@ -159,20 +159,13 @@
</div> </div>
</template> </template>
</draggable> </draggable>
<div <HoppSmartPlaceholder
v-if="protocols.length === 0" v-if="protocols.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/${colorMode.value}/add_category.svg`"
:alt="`${t('empty.protocols')}`"
:text="`${t('empty.protocols')}`"
> >
<img </HoppSmartPlaceholder>
:src="`/images/states/${colorMode.value}/add_category.svg`"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 my-4"
:alt="`${t('empty.protocols')}`"
/>
<span class="mb-4 text-center">
{{ t("empty.protocols") }}
</span>
</div>
</HoppSmartTab> </HoppSmartTab>
</HoppSmartTabs> </HoppSmartTabs>
</template> </template>

View File

@@ -111,13 +111,14 @@
/> />
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="newMembersList.length === 0" v-if="newMembersList.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" :src="`/images/states/dark/add_group.svg`"
alt="No invites"
text="No invites"
> >
<span class="pb-4 text-center"> No invites </span>
<HoppButtonSecondary label="Add new" filled @click="addNewMember" /> <HoppButtonSecondary label="Add new" filled @click="addNewMember" />
</div> </HoppSmartPlaceholder>
</div> </div>
<div <div
v-if="newMembersList.length" v-if="newMembersList.length"

View File

@@ -11,13 +11,10 @@
</div> </div>
<div class="border rounded border-divider my-8"> <div class="border rounded border-divider my-8">
<div <HoppSmartPlaceholder
v-if="team?.teamMembers?.length === 0" v-if="team?.teamMembers?.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" text="No members in this team. Add members to this team to collaborate"
> >
<span class="pb-4 text-center">
{{ t('teams.no_members') }}
</span>
<HoppButtonSecondary <HoppButtonSecondary
:icon="IconUserPlus" :icon="IconUserPlus"
:label="t('teams.add_members')" :label="t('teams.add_members')"
@@ -27,7 +24,7 @@
} }
" "
/> />
</div> </HoppSmartPlaceholder>
<div v-else class="divide-y divide-dividerLight"> <div v-else class="divide-y divide-dividerLight">
<div <div
v-for="(member, index) in membersList" v-for="(member, index) in membersList"

View File

@@ -37,16 +37,15 @@
</div> </div>
</div> </div>
</div> </div>
<div <HoppSmartPlaceholder
v-if="team && pendingInvites?.length === 0" v-if="team && pendingInvites?.length === 0"
class="flex flex-col items-center justify-center p-4 text-secondaryLight" text="No pending invites"
> >
<span class="text-center">{{ t('teams.no_pending_invites') }} </span> <div v-if="!fetching && error" class="flex flex-col items-center p-4">
</div> <icon-lucide-help-circle class="mb-4 svg-icons" />
<div v-if="!fetching && error" class="flex flex-col items-center p-4"> Something went wrong. Please try again later.
<icon-lucide-help-circle class="mb-4 svg-icons" /> </div>
{{ t('teams.error') }} </HoppSmartPlaceholder>
</div>
</div> </div>
</div> </div>
</template> </template>

View File

@@ -0,0 +1,40 @@
<template>
<div class="flex flex-col items-center justify-center p-4">
<img
v-if="src"
:src="src"
loading="lazy"
class="inline-flex flex-col object-contain object-center w-16 h-16 mb-4"
:alt="alt"
/>
<slot name="icon"></slot>
<span v-if="heading" class="mb-2 font-semibold text-center">
{{ heading }}
</span>
<span
class="max-w-sm mb-4 text-center whitespace-normal text-secondaryLight"
>
{{ text }}
</span>
<slot></slot>
</div>
</template>
<script setup lang="ts">
withDefaults(
defineProps<{
src?: string
alt?: string
heading?: string
text?: string
}>(),
{
alt: "",
text: "",
}
)
</script>

View File

@@ -19,3 +19,4 @@ export { default as HoppSmartToggle } from "./Toggle.vue"
export { default as HoppSmartWindow } from "./Window.vue" export { default as HoppSmartWindow } from "./Window.vue"
export { default as HoppSmartWindows } from "./Windows.vue" export { default as HoppSmartWindows } from "./Windows.vue"
export { default as HoppSmartPicture } from "./Picture.vue" export { default as HoppSmartPicture } from "./Picture.vue"
export { default as HoppSmartPlaceholder } from "./Placeholder.vue"