Browse Source

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

Co-authored-by: Andrew Bastin <andrewbastin.k@gmail.com>
Anwarul Islam 1 year ago
parent
commit
fc3e3aeaec

+ 42 - 0
.github/workflows/ui.yml

@@ -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 }}

+ 2 - 0
packages/hoppscotch-common/src/components.d.ts

@@ -86,6 +86,7 @@ declare module '@vue/runtime-core' {
     HoppSmartLink: typeof import('@hoppscotch/ui')['HoppSmartLink']
     HoppSmartModal: typeof import('@hoppscotch/ui')['HoppSmartModal']
     HoppSmartPicture: typeof import('@hoppscotch/ui')['HoppSmartPicture']
+    HoppSmartPlaceholder: typeof import('@hoppscotch/ui')['HoppSmartPlaceholder']
     HoppSmartProgressRing: typeof import('@hoppscotch/ui')['HoppSmartProgressRing']
     HoppSmartRadioGroup: typeof import('@hoppscotch/ui')['HoppSmartRadioGroup']
     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']
     SmartModal: typeof import('./../../hoppscotch-ui/src/components/smart/Modal.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']
     SmartRadio: typeof import('./../../hoppscotch-ui/src/components/smart/Radio.vue')['default']
     SmartRadioGroup: typeof import('./../../hoppscotch-ui/src/components/smart/RadioGroup.vue')['default']

+ 6 - 7
packages/hoppscotch-common/src/components/app/Fuse.vue

@@ -10,15 +10,14 @@
         @mouseover="selectedEntry = shortcutIndex"
       />
     </div>
-    <div
+    <HoppSmartPlaceholder
       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" />
-      <span class="my-2 text-center">
-        {{ t("state.nothing_found") }} "{{ search }}"
-      </span>
-    </div>
+      <template #icon>
+        <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
+      </template>
+    </HoppSmartPlaceholder>
   </div>
 </template>
 

+ 6 - 7
packages/hoppscotch-common/src/components/app/Shortcuts.vue

@@ -39,15 +39,14 @@
             />
           </div>
         </details>
-        <div
+        <HoppSmartPlaceholder
           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" />
-          <span class="my-2 text-center">
-            {{ t("state.nothing_found") }} "{{ filterText }}"
-          </span>
-        </div>
+          <template #icon>
+            <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
+          </template>
+        </HoppSmartPlaceholder>
       </div>
       <div v-else class="flex flex-col divide-y divide-dividerLight">
         <details

+ 29 - 52
packages/hoppscotch-common/src/components/collections/MyCollections.vue

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

+ 32 - 46
packages/hoppscotch-common/src/components/collections/TeamCollections.vue

@@ -262,67 +262,53 @@
         </template>
         <template #emptyNode="{ node }">
           <div v-if="node === null">
-            <div
-              class="flex flex-col items-center justify-center p-4 text-secondaryLight"
-              @drop="(e) => e.stopPropagation()"
-            >
-              <img
+            <div @drop="(e) => e.stopPropagation()">
+              <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.collection')}`"
-              />
-              <span class="pb-4 text-center">
-                {{ t("empty.collections") }}
-              </span>
-              <HoppButtonSecondary
-                v-if="hasNoTeamAccess"
-                v-tippy="{ theme: 'tooltip' }"
-                disabled
-                filled
-                outline
-                :title="t('team.no_access')"
-                :label="t('action.new')"
-              />
-              <HoppButtonSecondary
-                v-else
-                :icon="IconPlus"
-                :label="t('action.new')"
-                filled
-                outline
-                @click="emit('display-modal-add')"
-              />
+                :alt="`${t('empty.collections')}`"
+                :text="t('empty.collections')"
+              >
+                <HoppButtonSecondary
+                  v-if="hasNoTeamAccess"
+                  v-tippy="{ theme: 'tooltip' }"
+                  disabled
+                  filled
+                  outline
+                  :title="t('team.no_access')"
+                  :label="t('action.new')"
+                />
+                <HoppButtonSecondary
+                  v-else
+                  :icon="IconPlus"
+                  :label="t('action.new')"
+                  filled
+                  outline
+                  @click="emit('display-modal-add')"
+                />
+              </HoppSmartPlaceholder>
             </div>
           </div>
           <div
             v-else-if="node.data.type === 'collections'"
-            class="flex flex-col items-center justify-center p-4 text-secondaryLight"
             @drop="(e) => e.stopPropagation()"
           >
-            <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.collection')}`"
-            />
-            <span class="pb-4 text-center">
-              {{ t("empty.collections") }}
-            </span>
+              :alt="`${t('empty.collections')}`"
+              :text="t('empty.collections')"
+            >
+            </HoppSmartPlaceholder>
           </div>
           <div
             v-else-if="node.data.type === 'folders'"
-            class="flex flex-col items-center justify-center p-4 text-secondaryLight"
             @drop="(e) => e.stopPropagation()"
           >
-            <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>
+              :text="t('empty.folder')"
+            >
+            </HoppSmartPlaceholder>
           </div>
         </template>
       </SmartTree>

+ 5 - 12
packages/hoppscotch-common/src/components/collections/graphql/Collection.vue

@@ -171,21 +171,14 @@
           @duplicate-request="$emit('duplicate-request', $event)"
           @select="$emit('select', $event)"
         />
-        <div
+        <HoppSmartPlaceholder
           v-if="
             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
             :label="t('add.new')"
             filled
@@ -196,7 +189,7 @@
               })
             "
           />
-        </div>
+        </HoppSmartPlaceholder>
       </div>
     </div>
     <HoppSmartConfirmModal

+ 6 - 12
packages/hoppscotch-common/src/components/collections/graphql/Folder.vue

@@ -160,25 +160,19 @@
           @duplicate-request="emit('duplicate-request', $event)"
           @select="emit('select', $event)"
         />
-        <div
+
+        <HoppSmartPlaceholder
           v-if="
             folder.folders &&
             folder.folders.length === 0 &&
             folder.requests &&
             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
-            :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>
+        </HoppSmartPlaceholder>
       </div>
     </div>
     <HoppSmartConfirmModal

+ 11 - 19
packages/hoppscotch-common/src/components/collections/graphql/index.vue

@@ -60,35 +60,27 @@
         @select="$emit('select', $event)"
       />
     </div>
-    <div
+    <HoppSmartPlaceholder
       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
         :label="t('add.new')"
         filled
         outline
         @click="displayModalAdd(true)"
       />
-    </div>
-    <div
+    </HoppSmartPlaceholder>
+    <HoppSmartPlaceholder
       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" />
-      <span class="my-2 text-center">
-        {{ t("state.nothing_found") }} "{{ filterText }}"
-      </span>
-    </div>
+      <template #icon>
+        <icon-lucide-search class="pb-2 opacity-75 svg-icons" />
+      </template>
+    </HoppSmartPlaceholder>
     <CollectionsGraphqlAdd
       :show="showModalAdd"
       @hide-modal="displayModalAdd(false)"

+ 11 - 24
packages/hoppscotch-common/src/components/environments/Selector.vue

@@ -70,20 +70,13 @@
                 }
               "
             />
-            <div
+            <HoppSmartPlaceholder
               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
-                :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>
+            </HoppSmartPlaceholder>
           </HoppSmartTab>
           <HoppSmartTab
             :id="'team-environments'"
@@ -119,20 +112,14 @@
                   }
                 "
               />
-              <div
+
+              <HoppSmartPlaceholder
                 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
-                  :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>
+              </HoppSmartPlaceholder>
             </div>
             <div
               v-if="!teamListLoading && teamAdapterError"

Some files were not shown because too many files changed in this diff