Browse Source

feat(components): add tabs components

Ahmad Kholid 3 years ago
parent
commit
d1eb91a3b5

+ 0 - 21
LICENSE

@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2019 Michael Xieyang Liu
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 39 - 29
src/components/newtab/workflow/WorkflowDetailsCard.vue

@@ -19,39 +19,45 @@
         <v-remixicon name="riDeleteBin7Line" />
         <v-remixicon name="riDeleteBin7Line" />
       </ui-button>
       </ui-button>
     </div>
     </div>
-    <div class="flex mb-4 mt-5 mx-4 items-center space-x-2 border-b">
-      <div class="border-b-2 pb-1 flex-1 border-accent">
-        <button class="p-2 hoverable w-full rounded-lg transition">
-          Tasks
-        </button>
-      </div>
-      <div class="border-b-2 pb-1 flex-1 border-transparent">
-        <button class="p-2 hoverable w-full rounded-lg transition">
-          Data Schema
-        </button>
-      </div>
-    </div>
-    <!-- <hr class="mb-4 mt-5 mx-4" />
-    <p class="mb-1 px-4 text-gray-600">Tasks</p> -->
-    <div
-      class="px-4 grid grid-cols-2 gap-2 pb-4 overflow-auto pt-1"
-      style="max-height: calc(100vh - 200px)"
-    >
-      <div
-        v-for="task in taskList"
-        :key="task.id"
-        :title="task.name"
-        class="cursor-move select-none group p-4 rounded-lg bg-input transition"
+    <ui-tabs v-model="state.activeTab" fill class="mx-4 mt-5 mb-4">
+      <ui-tab value="tasks">Tasks</ui-tab>
+      <ui-tab value="data-schema">Data Schema</ui-tab>
+    </ui-tabs>
+    <ui-tab-panels v-model="state.activeTab">
+      <ui-tab-panel
+        value="tasks"
+        class="px-4 grid grid-cols-2 gap-2 pb-4 overflow-auto pt-1"
+        style="max-height: calc(100vh - 200px)"
       >
       >
-        <v-remixicon :name="task.icon" size="24" class="mb-2" />
-        <p class="leading-tight text-overflow">
-          {{ task.name }}
-        </p>
-      </div>
-    </div>
+        <div
+          v-for="task in taskList"
+          :key="task.id"
+          :title="task.name"
+          class="
+            cursor-move
+            select-none
+            group
+            p-4
+            rounded-lg
+            bg-input
+            transition
+          "
+        >
+          <v-remixicon :name="task.icon" size="24" class="mb-3" />
+          <p class="leading-tight text-overflow">
+            {{ task.name }}
+          </p>
+        </div>
+      </ui-tab-panel>
+      <ui-tab-panel value="data-schema">
+        <p>sss</p>
+      </ui-tab-panel>
+    </ui-tab-panels>
   </ui-card>
   </ui-card>
 </template>
 </template>
 <script setup>
 <script setup>
+import { shallowReactive } from 'vue';
+
 const taskList = [
 const taskList = [
   {
   {
     id: 'event-click',
     id: 'event-click',
@@ -94,4 +100,8 @@ const taskList = [
     icon: 'riEqualizerLine',
     icon: 'riEqualizerLine',
   },
   },
 ].sort((a, b) => (a.name > b.name ? 1 : -1));
 ].sort((a, b) => (a.name > b.name ? 1 : -1));
+
+const state = shallowReactive({
+  activeTab: 'tasks',
+});
 </script>
 </script>

+ 31 - 0
src/components/ui/UiTab.vue

@@ -0,0 +1,31 @@
+<template>
+  <button
+    :aria-selected="uiTabs.modelValue.value === value"
+    :class="[
+      uiTabs.modelValue.value === value
+        ? 'border-accent'
+        : 'border-transparent',
+      { 'flex-1': uiTabs.fill.value },
+    ]"
+    :tabIndex="uiTabs.modelValue.value === value ? 0 : -1"
+    aria-role="tab"
+    class="border-b-2 px-2 z-[1] py-3 ui-tab focus:ring-0"
+    @mouseenter="uiTabs.hoverHandler"
+    @click="uiTabs.updateActive(value)"
+  >
+    <slot></slot>
+  </button>
+</template>
+<script setup>
+import { inject } from 'vue';
+
+/* eslint-disable-next-line */
+const props = defineProps({
+  value: {
+    type: [String, Number],
+    default: '',
+  },
+});
+
+const uiTabs = inject('ui-tabs', {});
+</script>

+ 26 - 0
src/components/ui/UiTabPanel.vue

@@ -0,0 +1,26 @@
+<template>
+  <div
+    v-if="value === uiTabPanels.modelValue.value"
+    class="ui-tab-panel"
+    :class="activeClass"
+  >
+    <slot></slot>
+  </div>
+</template>
+<script setup>
+import { inject } from 'vue';
+
+/* eslint-disable-next-line */
+defineProps({
+  value: {
+    type: [String, Number],
+    default: '',
+  },
+  activeClass: {
+    type: String,
+    default: 'ui-tab-panel--active',
+  },
+});
+
+const uiTabPanels = inject('ui-tab-panels', {});
+</script>

+ 16 - 0
src/components/ui/UiTabPanels.vue

@@ -0,0 +1,16 @@
+<template>
+  <slot></slot>
+</template>
+<script setup>
+import { toRefs, provide } from 'vue';
+
+/* eslint-disable-next-line */
+const props = defineProps({
+  modelValue: {
+    type: [String, Number],
+    default: '',
+  },
+});
+
+provide('ui-tab-panels', toRefs(props));
+</script>

+ 71 - 0
src/components/ui/UiTabs.vue

@@ -0,0 +1,71 @@
+<template>
+  <div
+    aria-role="tablist"
+    class="ui-tabs border-b flex items-center relative"
+    @mouseleave="showHoverIndicator = false"
+  >
+    <div
+      v-show="showHoverIndicator"
+      ref="hoverIndicator"
+      class="
+        ui-tabs__indicator
+        z-0
+        top-[5px]
+        absolute
+        left-0
+        rounded-lg
+        bg-box-transparent
+      "
+    ></div>
+    <slot></slot>
+  </div>
+</template>
+<script>
+import { provide, toRefs, ref } from 'vue';
+
+export default {
+  props: {
+    modelValue: {
+      type: [String, Number],
+      default: '',
+    },
+    fill: Boolean,
+  },
+  emits: ['update:modelValue'],
+  setup(props, { emit }) {
+    const hoverIndicator = ref(null);
+    const showHoverIndicator = ref(false);
+
+    function updateActive(id) {
+      emit('update:modelValue', id);
+    }
+    function hoverHandler({ target }) {
+      showHoverIndicator.value = true;
+      hoverIndicator.value.style.width = `${
+        target.getBoundingClientRect().width
+      }px`;
+      hoverIndicator.value.style.transform = `translateX(${target.offsetLeft}px)`;
+    }
+
+    provide('ui-tabs', {
+      updateActive,
+      hoverHandler,
+      ...toRefs(props),
+    });
+
+    return {
+      hoverIndicator,
+      showHoverIndicator,
+    };
+  },
+};
+</script>
+<style>
+.ui-tabs__indicator {
+  min-height: 38px;
+  min-width: 50px;
+  transition-duration: 200ms;
+  transition-property: transform, width;
+  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
+}
+</style>