refactor: update hopp-ui to be independent (#2927)
Co-authored-by: Anwarul Islam <anwaarulislaam@gmail.com>
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<SmartLink
|
||||
:to="to"
|
||||
:blank="blank"
|
||||
<HoppSmartLink :to="to" :blank="blank"
|
||||
class="relative inline-flex items-center justify-center py-2 font-bold transition focus:outline-none focus-visible:bg-accentDark"
|
||||
:class="[
|
||||
color
|
||||
@@ -21,45 +19,29 @@
|
||||
'border border-accent hover:border-accentDark focus-visible:border-accentDark':
|
||||
outline,
|
||||
},
|
||||
]"
|
||||
:disabled="disabled"
|
||||
:tabindex="loading ? '-1' : '0'"
|
||||
role="button"
|
||||
>
|
||||
<span
|
||||
class="inline-flex items-center justify-center whitespace-nowrap"
|
||||
:class="[{ 'flex-row-reverse': reverse }, { 'opacity-50': loading }]"
|
||||
>
|
||||
<component
|
||||
:is="icon"
|
||||
v-if="icon"
|
||||
class="svg-icons"
|
||||
:class="[
|
||||
{ '!text-2xl': large },
|
||||
label ? (reverse ? 'ml-2' : 'mr-2') : '',
|
||||
]"
|
||||
/>
|
||||
]" :disabled="disabled" :tabindex="loading ? '-1' : '0'" role="button">
|
||||
<span class="inline-flex items-center justify-center whitespace-nowrap"
|
||||
:class="[{ 'flex-row-reverse': reverse }, { 'opacity-50': loading }]">
|
||||
<component :is="icon" v-if="icon" class="svg-icons" :class="[
|
||||
{ '!text-2xl': large },
|
||||
label ? (reverse ? 'ml-2' : 'mr-2') : '',
|
||||
]" />
|
||||
{{ label }}
|
||||
<div v-if="shortcut.length" class="<sm:hidden">
|
||||
<kbd
|
||||
v-for="(key, index) in shortcut"
|
||||
:key="`key-${index}`"
|
||||
class="shortcut-key !bg-accentDark !border-accentLight"
|
||||
>
|
||||
<kbd v-for="(key, index) in shortcut" :key="`key-${index}`"
|
||||
class="shortcut-key !bg-accentDark !border-accentLight">
|
||||
{{ key }}
|
||||
</kbd>
|
||||
</div>
|
||||
</span>
|
||||
<span
|
||||
v-if="loading"
|
||||
class="absolute inset-0 flex items-center justify-center"
|
||||
>
|
||||
<SmartSpinner />
|
||||
<span v-if="loading" class="absolute inset-0 flex items-center justify-center">
|
||||
<HoppSmartSpinner />
|
||||
</span>
|
||||
</SmartLink>
|
||||
</HoppSmartLink>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppSmartLink, HoppSmartSpinner } from "../smart"
|
||||
import type { Component } from "vue"
|
||||
|
||||
interface Props {
|
||||
@@ -80,6 +62,7 @@ interface Props {
|
||||
outline?: boolean
|
||||
shortcut?: string[]
|
||||
}
|
||||
|
||||
withDefaults(defineProps<Props>(), {
|
||||
to: "",
|
||||
exact: true,
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<SmartLink
|
||||
:to="to"
|
||||
:exact="exact"
|
||||
:blank="blank"
|
||||
<HoppSmartLink :to="to" :exact="exact" :blank="blank"
|
||||
class="inline-flex items-center justify-center py-2 font-semibold transition whitespace-nowrap focus:outline-none"
|
||||
:class="[
|
||||
color
|
||||
@@ -22,41 +19,26 @@
|
||||
'bg-primaryLight hover:bg-primaryDark focus-visible:bg-primaryDark':
|
||||
filled,
|
||||
},
|
||||
]"
|
||||
:disabled="disabled"
|
||||
:tabindex="loading ? '-1' : '0'"
|
||||
role="button"
|
||||
>
|
||||
<span
|
||||
v-if="!loading"
|
||||
class="inline-flex items-center justify-center whitespace-nowrap"
|
||||
:class="{ 'flex-row-reverse': reverse }"
|
||||
>
|
||||
<component
|
||||
:is="icon"
|
||||
v-if="icon"
|
||||
class="svg-icons"
|
||||
:class="[
|
||||
{ '!text-2xl': large },
|
||||
label ? (reverse ? 'ml-2' : 'mr-2') : '',
|
||||
]"
|
||||
/>
|
||||
]" :disabled="disabled" :tabindex="loading ? '-1' : '0'" role="button">
|
||||
<span v-if="!loading" class="inline-flex items-center justify-center whitespace-nowrap"
|
||||
:class="{ 'flex-row-reverse': reverse }">
|
||||
<component :is="icon" v-if="icon" class="svg-icons" :class="[
|
||||
{ '!text-2xl': large },
|
||||
label ? (reverse ? 'ml-2' : 'mr-2') : '',
|
||||
]" />
|
||||
{{ label }}
|
||||
<div v-if="shortcut.length" class="<sm:hidden">
|
||||
<kbd
|
||||
v-for="(key, index) in shortcut"
|
||||
:key="`key-${index}`"
|
||||
class="shortcut-key !bg-inherit"
|
||||
>
|
||||
<kbd v-for="(key, index) in shortcut" :key="`key-${index}`" class="shortcut-key !bg-inherit">
|
||||
{{ key }}
|
||||
</kbd>
|
||||
</div>
|
||||
</span>
|
||||
<SmartSpinner v-else />
|
||||
</SmartLink>
|
||||
<HoppSmartSpinner v-else />
|
||||
</HoppSmartLink>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppSmartLink, HoppSmartSpinner } from "../smart";
|
||||
import type { Component } from "vue"
|
||||
|
||||
interface Props {
|
||||
|
||||
2
packages/hoppscotch-ui/src/components/button/index.ts
Normal file
2
packages/hoppscotch-ui/src/components/button/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export { default as HoppButtonPrimary } from "./Primary.vue"
|
||||
export { default as HoppButtonSecondary } from "./Secondary.vue"
|
||||
@@ -1,47 +1,2 @@
|
||||
import Primary from "./button/Primary.vue"
|
||||
import Secondary from "./button/Secondary.vue"
|
||||
import Anchor from "./smart/Anchor.vue"
|
||||
import AutoComplete from "./smart/AutoComplete.vue"
|
||||
import Checkbox from "./smart/Checkbox.vue"
|
||||
import ConfirmModal from "./smart/ConfirmModal.vue"
|
||||
import Expand from "./smart/Expand.vue"
|
||||
import FileChip from "./smart/FileChip.vue"
|
||||
import Intersection from "./smart/Intersection.vue"
|
||||
import Item from "./smart/Item.vue"
|
||||
import Link from "./smart/Link.vue"
|
||||
import Modal from "./smart/Modal.vue"
|
||||
import ProgressRing from "./smart/ProgressRing.vue"
|
||||
import Radio from "./smart/Radio.vue"
|
||||
import RadioGroup from "./smart/RadioGroup.vue"
|
||||
import SlideOver from "./smart/SlideOver.vue"
|
||||
import Spinner from "./smart/Spinner.vue"
|
||||
import Tab from "./smart/Tab.vue"
|
||||
import Tabs from "./smart/Tabs.vue"
|
||||
import Toggle from "./smart/Toggle.vue"
|
||||
import Window from "./smart/Window.vue"
|
||||
import Windows from "./smart/Windows.vue"
|
||||
|
||||
export default {
|
||||
Primary,
|
||||
Secondary,
|
||||
Anchor,
|
||||
AutoComplete,
|
||||
Checkbox,
|
||||
ConfirmModal,
|
||||
Expand,
|
||||
FileChip,
|
||||
Intersection,
|
||||
Item,
|
||||
Link,
|
||||
Modal,
|
||||
ProgressRing,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
SlideOver,
|
||||
Spinner,
|
||||
Tab,
|
||||
Tabs,
|
||||
Toggle,
|
||||
Window,
|
||||
Windows,
|
||||
}
|
||||
export * from "./button"
|
||||
export * from "./smart"
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
<template>
|
||||
<SmartLink
|
||||
:to="to"
|
||||
:exact="exact"
|
||||
:blank="blank"
|
||||
class="inline-flex items-center justify-center focus:outline-none"
|
||||
<HoppSmartLink :to="to" :exact="exact" :blank="blank" class="inline-flex items-center justify-center focus:outline-none"
|
||||
:class="[
|
||||
color
|
||||
? `text-${color}-500 hover:text-${color}-600 focus-visible:text-${color}-600`
|
||||
: 'hover:text-secondaryDark focus-visible:text-secondaryDark',
|
||||
{ 'opacity-75 cursor-not-allowed': disabled },
|
||||
{ 'flex-row-reverse': reverse },
|
||||
]"
|
||||
:disabled="disabled"
|
||||
tabindex="0"
|
||||
>
|
||||
<component
|
||||
:is="icon"
|
||||
v-if="icon"
|
||||
class="svg-icons"
|
||||
:class="label ? (reverse ? 'ml-2' : 'mr-2') : ''"
|
||||
/>
|
||||
]" :disabled="disabled" tabindex="0">
|
||||
<component :is="icon" v-if="icon" class="svg-icons" :class="label ? (reverse ? 'ml-2' : 'mr-2') : ''" />
|
||||
{{ label }}
|
||||
</SmartLink>
|
||||
</HoppSmartLink>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import HoppSmartLink from "./Link.vue";
|
||||
import { Component, defineComponent, PropType } from "vue"
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
HoppSmartLink
|
||||
},
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
|
||||
@@ -1,36 +1,17 @@
|
||||
<template>
|
||||
<div class="autocomplete-wrapper">
|
||||
<input
|
||||
ref="acInput"
|
||||
:value="text"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:placeholder="placeholder"
|
||||
:spellcheck="spellcheck"
|
||||
:autocapitalize="autocapitalize"
|
||||
:class="styles"
|
||||
@input.stop="
|
||||
<input ref="acInput" :value="text" type="text" autocomplete="off" :placeholder="placeholder" :spellcheck="spellcheck"
|
||||
:autocapitalize="autocapitalize" :class="styles" @input.stop="
|
||||
(e) => {
|
||||
$emit('input', e.target.value)
|
||||
updateSuggestions(e)
|
||||
}
|
||||
"
|
||||
@keyup="updateSuggestions"
|
||||
@click="updateSuggestions"
|
||||
@keydown="handleKeystroke"
|
||||
@change="$emit('change', $event)"
|
||||
/>
|
||||
<ul
|
||||
v-if="suggestions.length > 0 && suggestionsVisible"
|
||||
class="suggestions"
|
||||
:style="{ transform: `translate(${suggestionsOffsetLeft}px, 0)` }"
|
||||
>
|
||||
<li
|
||||
v-for="(suggestion, index) in suggestions"
|
||||
:key="`suggestion-${index}`"
|
||||
:class="{ active: currentSuggestionIndex === index }"
|
||||
@click.prevent="forceSuggestion(suggestion)"
|
||||
>
|
||||
" @keyup="updateSuggestions" @click="updateSuggestions" @keydown="handleKeystroke"
|
||||
@change="$emit('change', $event)" />
|
||||
<ul v-if="suggestions.length > 0 && suggestionsVisible" class="suggestions"
|
||||
:style="{ transform: `translate(${suggestionsOffsetLeft}px, 0)` }">
|
||||
<li v-for="(suggestion, index) in suggestions" :key="`suggestion-${index}`"
|
||||
:class="{ active: currentSuggestionIndex === index }" @click.prevent="forceSuggestion(suggestion)">
|
||||
{{ suggestion }}
|
||||
</li>
|
||||
</ul>
|
||||
@@ -182,7 +163,7 @@ export default defineComponent({
|
||||
case "Tab": {
|
||||
const activeSuggestion =
|
||||
this.suggestions[
|
||||
this.currentSuggestionIndex >= 0 ? this.currentSuggestionIndex : 0
|
||||
this.currentSuggestionIndex >= 0 ? this.currentSuggestionIndex : 0
|
||||
]
|
||||
|
||||
if (!activeSuggestion) {
|
||||
@@ -205,7 +186,7 @@ export default defineComponent({
|
||||
@apply relative;
|
||||
@apply contents;
|
||||
|
||||
input:focus + ul.suggestions,
|
||||
input:focus+ul.suggestions,
|
||||
ul.suggestions:hover {
|
||||
@apply block;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
<template>
|
||||
<SmartModal
|
||||
v-if="show"
|
||||
dialog
|
||||
:title="confirm ?? t?.('modal.confirm') ?? 'Confirm'"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
@close="hideModal"
|
||||
>
|
||||
<HoppSmartModal v-if="show" dialog :title="confirm ?? t?.('modal.confirm') ?? 'Confirm'" role="dialog" aria-modal="true"
|
||||
@close="hideModal">
|
||||
<template #body>
|
||||
<div class="flex flex-col items-center justify-center">
|
||||
{{ title }}
|
||||
@@ -14,27 +8,19 @@
|
||||
</template>
|
||||
<template #footer>
|
||||
<span class="flex space-x-2">
|
||||
<ButtonPrimary
|
||||
v-focus
|
||||
:label="yes ?? t?.('action.yes') ?? 'Yes'"
|
||||
:loading="!!loadingState"
|
||||
outline
|
||||
@click="resolve"
|
||||
/>
|
||||
<ButtonSecondary
|
||||
:label="no ?? t?.('action.no') ?? 'No'"
|
||||
filled
|
||||
outline
|
||||
@click="hideModal"
|
||||
/>
|
||||
<HoppButtonPrimary v-focus :label="yes ?? t?.('action.yes') ?? 'Yes'" :loading="!!loadingState" outline
|
||||
@click="resolve" />
|
||||
<HoppButtonSecondary :label="no ?? t?.('action.no') ?? 'No'" filled outline @click="hideModal" />
|
||||
</span>
|
||||
</template>
|
||||
</SmartModal>
|
||||
</HoppSmartModal>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { inject } from "vue"
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../index"
|
||||
import { HoppButtonPrimary, HoppButtonSecondary } from "../button"
|
||||
import { HoppSmartModal } from "."
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../plugin"
|
||||
|
||||
const { t } = inject<HoppUIPluginOptions>(HOPP_UI_OPTIONS) ?? {}
|
||||
|
||||
|
||||
@@ -1,32 +1,22 @@
|
||||
<template>
|
||||
<div
|
||||
class="relative flex flex-col space-y-2 overflow-hidden"
|
||||
:class="expand ? 'h-full' : 'max-h-32'"
|
||||
>
|
||||
<div class="relative flex flex-col space-y-2 overflow-hidden" :class="expand ? 'h-full' : 'max-h-32'">
|
||||
<slot name="body"></slot>
|
||||
<div
|
||||
class="sticky inset-x-0 bottom-0 flex items-center justify-center flex-shrink-0 overflow-x-auto"
|
||||
>
|
||||
<ButtonSecondary
|
||||
:icon="expand ? IconChevronUp : IconChevronDown"
|
||||
:label="
|
||||
expand
|
||||
? less ?? t?.('action.less') ?? 'Less'
|
||||
: more ?? t?.('action.more') ?? 'More'
|
||||
"
|
||||
filled
|
||||
rounded
|
||||
@click="expand = !expand"
|
||||
/>
|
||||
<div class="sticky inset-x-0 bottom-0 flex items-center justify-center flex-shrink-0 overflow-x-auto">
|
||||
<HoppButtonSecondary :icon="expand ? IconChevronUp : IconChevronDown" :label="
|
||||
expand
|
||||
? less ?? t?.('action.less') ?? 'Less'
|
||||
: more ?? t?.('action.more') ?? 'More'
|
||||
" filled rounded @click="expand = !expand" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppButtonSecondary } from "../button"
|
||||
import IconChevronUp from "~icons/lucide/chevron-up"
|
||||
import IconChevronDown from "~icons/lucide/chevron-down"
|
||||
import { inject, ref } from "vue"
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../index"
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../plugin"
|
||||
|
||||
const { t } = inject<HoppUIPluginOptions>(HOPP_UI_OPTIONS) ?? {}
|
||||
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
<template>
|
||||
<SmartLink
|
||||
:to="to"
|
||||
:exact="exact"
|
||||
:blank="blank"
|
||||
<HoppSmartLink :to="to" :exact="exact" :blank="blank"
|
||||
class="inline-flex items-center flex-shrink-0 px-4 py-2 rounded transition hover:bg-primaryDark hover:text-secondaryDark focus:outline-none focus-visible:bg-primaryDark focus-visible:text-secondaryDark"
|
||||
:class="[
|
||||
{ 'opacity-75 cursor-not-allowed': disabled },
|
||||
@@ -13,31 +10,15 @@
|
||||
'border border-divider hover:border-dividerDark focus-visible:border-dividerDark':
|
||||
outline,
|
||||
},
|
||||
]"
|
||||
:disabled="disabled"
|
||||
:tabindex="loading ? '-1' : '0'"
|
||||
role="menuitem"
|
||||
>
|
||||
<span
|
||||
v-if="!loading"
|
||||
class="inline-flex items-center"
|
||||
:class="{ 'self-start': !!infoIcon }"
|
||||
>
|
||||
<component
|
||||
:is="icon"
|
||||
v-if="icon"
|
||||
class="opacity-75 svg-icons"
|
||||
:class="[
|
||||
label ? (reverse ? 'ml-4' : 'mr-4') : '',
|
||||
{ 'text-accent': active },
|
||||
]"
|
||||
/>
|
||||
]" :disabled="disabled" :tabindex="loading ? '-1' : '0'" role="menuitem">
|
||||
<span v-if="!loading" class="inline-flex items-center" :class="{ 'self-start': !!infoIcon }">
|
||||
<component :is="icon" v-if="icon" class="opacity-75 svg-icons" :class="[
|
||||
label ? (reverse ? 'ml-4' : 'mr-4') : '',
|
||||
{ 'text-accent': active },
|
||||
]" />
|
||||
</span>
|
||||
<SmartSpinner v-else class="mr-4 text-secondaryDark" />
|
||||
<div
|
||||
class="inline-flex items-start flex-1 truncate"
|
||||
:class="{ 'flex-col': description }"
|
||||
>
|
||||
<HoppSmartSpinner v-else class="mr-4 text-secondaryDark" />
|
||||
<div class="inline-flex items-start flex-1 truncate" :class="{ 'flex-col': description }">
|
||||
<div class="font-semibold truncate">
|
||||
{{ label }}
|
||||
</div>
|
||||
@@ -45,28 +26,26 @@
|
||||
{{ description }}
|
||||
</p>
|
||||
</div>
|
||||
<component
|
||||
:is="infoIcon"
|
||||
v-if="infoIcon"
|
||||
class="items-center self-center ml-4 svg-icons"
|
||||
:class="{ 'text-accent': activeInfoIcon }"
|
||||
/>
|
||||
<component :is="infoIcon" v-if="infoIcon" class="items-center self-center ml-4 svg-icons"
|
||||
:class="{ 'text-accent': activeInfoIcon }" />
|
||||
<div v-if="shortcut.length" class="ml-4 <sm:hidden font-medium">
|
||||
<kbd
|
||||
v-for="(key, index) in shortcut"
|
||||
:key="`key-${index}`"
|
||||
class="-mr-2 shortcut-key"
|
||||
>
|
||||
<kbd v-for="(key, index) in shortcut" :key="`key-${index}`" class="-mr-2 shortcut-key">
|
||||
{{ key }}
|
||||
</kbd>
|
||||
</div>
|
||||
</SmartLink>
|
||||
</HoppSmartLink>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import HoppSmartLink from "./Link.vue"
|
||||
import HoppSmartSpinner from "./Spinner.vue"
|
||||
import { defineComponent } from "vue"
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
HoppSmartLink,
|
||||
HoppSmartSpinner
|
||||
},
|
||||
props: {
|
||||
to: {
|
||||
type: String,
|
||||
|
||||
@@ -1,30 +1,12 @@
|
||||
<template>
|
||||
<button
|
||||
v-if="renderedTag === 'BUTTON'"
|
||||
aria-label="button"
|
||||
role="button"
|
||||
v-bind="$attrs"
|
||||
>
|
||||
<button v-if="renderedTag === 'BUTTON'" aria-label="button" role="button" v-bind="$attrs">
|
||||
<slot></slot>
|
||||
</button>
|
||||
<a
|
||||
v-else-if="renderedTag === 'ANCHOR' && !blank"
|
||||
aria-label="Link"
|
||||
:href="to"
|
||||
role="link"
|
||||
v-bind="updatedAttrs"
|
||||
>
|
||||
<a v-else-if="renderedTag === 'ANCHOR' && !blank" aria-label="Link" :href="to" role="link" v-bind="updatedAttrs">
|
||||
<slot></slot>
|
||||
</a>
|
||||
<a
|
||||
v-else-if="renderedTag === 'ANCHOR' && blank"
|
||||
aria-label="Link"
|
||||
:href="to"
|
||||
role="link"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
v-bind="updatedAttrs"
|
||||
>
|
||||
<a v-else-if="renderedTag === 'ANCHOR' && blank" aria-label="Link" :href="to" role="link" target="_blank" rel="noopener"
|
||||
v-bind="updatedAttrs">
|
||||
<slot></slot>
|
||||
</a>
|
||||
<RouterLink v-else :to="to" v-bind="updatedAttrs">
|
||||
@@ -33,6 +15,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { RouterLink } from "vue-router"
|
||||
/**
|
||||
* for preventing the automatic binding of $attrs.
|
||||
* we are manually binding $attrs or updatedAttrs.
|
||||
|
||||
@@ -101,7 +101,7 @@ import {
|
||||
onBeforeUnmount,
|
||||
inject,
|
||||
} from "vue"
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../index"
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../plugin"
|
||||
|
||||
const { t, onModalOpen, onModalClose } =
|
||||
inject<HoppUIPluginOptions>(HOPP_UI_OPTIONS) ?? {}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
<template>
|
||||
<SmartItem
|
||||
:label="label"
|
||||
:icon="selected ? IconCircleDot : IconCircle"
|
||||
:active="selected"
|
||||
role="radio"
|
||||
:aria-checked="selected"
|
||||
@click="emit('change', value)"
|
||||
/>
|
||||
<HoppSmartItem :label="label" :icon="selected ? IconCircleDot : IconCircle" :active="selected" role="radio"
|
||||
:aria-checked="selected" @click="emit('change', value)" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppSmartItem } from "."
|
||||
import IconCircleDot from "~icons/lucide/circle-dot"
|
||||
import IconCircle from "~icons/lucide/circle"
|
||||
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<SmartRadio
|
||||
v-for="(radio, index) in radios"
|
||||
:key="`radio-${index}`"
|
||||
:value="radio.value"
|
||||
:label="radio.label"
|
||||
:selected="modelValue === radio.value"
|
||||
@change="emit('update:modelValue', radio.value)"
|
||||
/>
|
||||
<HoppSmartRadio v-for="(radio, index) in radios" :key="`radio-${index}`" :value="radio.value" :label="radio.label"
|
||||
:selected="modelValue === radio.value" @change="emit('update:modelValue', radio.value)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppSmartRadio } from '.';
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: "update:modelValue", value: string): void
|
||||
}>()
|
||||
|
||||
@@ -1,30 +1,18 @@
|
||||
<template>
|
||||
<div>
|
||||
<Transition name="fade" appear>
|
||||
<div
|
||||
v-if="show"
|
||||
class="fixed inset-0 z-20 transition-opacity"
|
||||
@keydown.esc="close()"
|
||||
>
|
||||
<div
|
||||
class="absolute inset-0 bg-primaryLight opacity-90 focus:outline-none"
|
||||
tabindex="0"
|
||||
@click="close()"
|
||||
></div>
|
||||
<div v-if="show" class="fixed inset-0 z-20 transition-opacity" @keydown.esc="close()">
|
||||
<div class="absolute inset-0 bg-primaryLight opacity-90 focus:outline-none" tabindex="0" @click="close()"></div>
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition name="slide" appear>
|
||||
<aside
|
||||
v-if="show"
|
||||
class="fixed top-0 right-0 z-30 flex flex-col h-full max-w-full overflow-auto border-l shadow-xl border-dividerDark bg-primary w-96"
|
||||
>
|
||||
<div
|
||||
class="flex items-center justify-between p-2 border-b border-dividerLight"
|
||||
>
|
||||
<aside v-if="show"
|
||||
class="fixed top-0 right-0 z-30 flex flex-col h-full max-w-full overflow-auto border-l shadow-xl border-dividerDark bg-primary w-96">
|
||||
<div class="flex items-center justify-between p-2 border-b border-dividerLight">
|
||||
<h3 class="ml-4 heading">{{ title }}</h3>
|
||||
<span class="flex items-center">
|
||||
<kbd class="mr-2 shortcut-key">ESC</kbd>
|
||||
<ButtonSecondary :icon="IconX" @click="close()" />
|
||||
<HoppButtonSecondary :icon="IconX" @click="close()" />
|
||||
</span>
|
||||
</div>
|
||||
<slot name="content"></slot>
|
||||
@@ -34,6 +22,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppButtonSecondary } from "../button"
|
||||
import { onMounted, watch } from "vue"
|
||||
import IconX from "~icons/lucide/x"
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
<template>
|
||||
<icon-lucide-loader class="animate-spin svg-icons" />
|
||||
<IconLucideLoader class="animate-spin svg-icons" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue"
|
||||
|
||||
export default defineComponent({})
|
||||
<script setup lang="ts">
|
||||
import IconLucideLoader from "~icons/lucide/loader"
|
||||
</script>
|
||||
|
||||
@@ -1,71 +1,37 @@
|
||||
<template>
|
||||
<div class="flex flex-col flex-1 h-auto overflow-y-hidden flex-nowrap">
|
||||
<div
|
||||
class="relative sticky top-0 z-10 flex-shrink-0 overflow-x-auto tabs bg-primaryLight"
|
||||
>
|
||||
<div class="relative sticky top-0 z-10 flex-shrink-0 overflow-x-auto tabs bg-primaryLight">
|
||||
<div class="flex flex-1 flex-shrink-0 w-0 overflow-x-auto">
|
||||
<div class="flex justify-between divide-x divide-dividerLight">
|
||||
<div class="flex">
|
||||
<draggable
|
||||
v-bind="dragOptions"
|
||||
:list="tabEntries"
|
||||
:style="tabStyles"
|
||||
:item-key="'window-'"
|
||||
class="flex flex-shrink-0 overflow-x-auto transition divide-x divide-dividerLight"
|
||||
@sort="sortTabs"
|
||||
>
|
||||
<draggable v-bind="dragOptions" :list="tabEntries" :style="tabStyles" :item-key="'window-'"
|
||||
class="flex flex-shrink-0 overflow-x-auto transition divide-x divide-dividerLight" @sort="sortTabs">
|
||||
<template #item="{ element: [tabID, tabMeta] }">
|
||||
<button
|
||||
:key="`removable-tab-${tabID}`"
|
||||
class="tab"
|
||||
:class="[{ active: modelValue === tabID }]"
|
||||
:aria-label="tabMeta.label || ''"
|
||||
role="button"
|
||||
@keyup.enter="selectTab(tabID)"
|
||||
@click="selectTab(tabID)"
|
||||
>
|
||||
<button :key="`removable-tab-${tabID}`" class="tab" :class="[{ active: modelValue === tabID }]"
|
||||
:aria-label="tabMeta.label || ''" role="button" @keyup.enter="selectTab(tabID)"
|
||||
@click="selectTab(tabID)">
|
||||
<div class="flex items-stretch truncate">
|
||||
<span
|
||||
v-if="tabMeta.icon"
|
||||
class="flex items-center justify-center mx-4 cursor-pointer"
|
||||
>
|
||||
<span v-if="tabMeta.icon" class="flex items-center justify-center mx-4 cursor-pointer">
|
||||
<component :is="tabMeta.icon" class="w-4 h-4 svg-icons" />
|
||||
</span>
|
||||
<span class="truncate">
|
||||
{{ tabMeta.label }}
|
||||
</span>
|
||||
</div>
|
||||
<ButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip', delay: [500, 20] }"
|
||||
:icon="IconX"
|
||||
:style="{
|
||||
visibility: tabMeta.isRemovable ? 'visible' : 'hidden',
|
||||
}"
|
||||
:title="closeText ?? t?.('action.close') ?? 'Close'"
|
||||
:class="[{ active: modelValue === tabID }, 'close']"
|
||||
class="mx-2 !p-0.5"
|
||||
@click.stop="emit('removeTab', tabID)"
|
||||
/>
|
||||
<HoppButtonSecondary v-tippy="{ theme: 'tooltip', delay: [500, 20] }" :icon="IconX" :style="{
|
||||
visibility: tabMeta.isRemovable ? 'visible' : 'hidden',
|
||||
}" :title="closeText ?? t?.('action.close') ?? 'Close'"
|
||||
:class="[{ active: modelValue === tabID }, 'close']" class="mx-2 !p-0.5"
|
||||
@click.stop="emit('removeTab', tabID)" />
|
||||
</button>
|
||||
</template>
|
||||
</draggable>
|
||||
</div>
|
||||
<div
|
||||
class="sticky right-0 flex items-center justify-center flex-shrink-0 overflow-x-auto z-8"
|
||||
>
|
||||
<div class="sticky right-0 flex items-center justify-center flex-shrink-0 overflow-x-auto z-8">
|
||||
<slot name="actions">
|
||||
<span
|
||||
v-if="canAddNewTab"
|
||||
class="flex items-center justify-center px-2 py-1.5 bg-primaryLight z-8"
|
||||
>
|
||||
<ButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="newText ?? t?.('action.new') ?? 'New'"
|
||||
:icon="IconPlus"
|
||||
class="rounded !p-1"
|
||||
filled
|
||||
@click="addTab"
|
||||
/>
|
||||
<span v-if="canAddNewTab" class="flex items-center justify-center px-2 py-1.5 bg-primaryLight z-8">
|
||||
<ButtonSecondary v-tippy="{ theme: 'tooltip' }" :title="newText ?? t?.('action.new') ?? 'New'"
|
||||
:icon="IconPlus" class="rounded !p-1" filled @click="addTab" />
|
||||
</span>
|
||||
</slot>
|
||||
</div>
|
||||
@@ -79,15 +45,15 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { HoppButtonSecondary } from "../button"
|
||||
import IconPlus from "~icons/lucide/plus"
|
||||
import IconX from "~icons/lucide/x"
|
||||
import { pipe } from "fp-ts/function"
|
||||
import { not } from "fp-ts/Predicate"
|
||||
import * as A from "fp-ts/Array"
|
||||
import * as O from "fp-ts/Option"
|
||||
import { ref, ComputedRef, computed, provide, inject } from "vue"
|
||||
import type { Slot } from "vue"
|
||||
import draggable from "vuedraggable"
|
||||
import { ref, ComputedRef, computed, provide, inject, Slot } from "vue"
|
||||
import draggable from "vuedraggable-es"
|
||||
import { HoppUIPluginOptions, HOPP_UI_OPTIONS } from "./../../index"
|
||||
|
||||
export type TabMeta = {
|
||||
@@ -213,13 +179,13 @@ const addTab = () => {
|
||||
@apply whitespace-nowrap;
|
||||
@apply overflow-auto;
|
||||
@apply flex-shrink-0;
|
||||
@apply after:absolute;
|
||||
@apply after:inset-x-0;
|
||||
@apply after:bottom-0;
|
||||
@apply after:bg-dividerLight;
|
||||
@apply after:z-10;
|
||||
@apply after:h-0.25;
|
||||
@apply after:content-DEFAULT;
|
||||
@apply after: absolute;
|
||||
@apply after: inset-x-0;
|
||||
@apply after: bottom-0;
|
||||
@apply after: bg-dividerLight;
|
||||
@apply after: z-10;
|
||||
@apply after: h-0.25;
|
||||
@apply after: content-DEFAULT;
|
||||
|
||||
.tab {
|
||||
@apply relative;
|
||||
@@ -232,23 +198,23 @@ const addTab = () => {
|
||||
@apply items-center;
|
||||
@apply justify-between;
|
||||
@apply text-secondaryLight;
|
||||
@apply hover:bg-primaryDark;
|
||||
@apply hover:text-secondary;
|
||||
@apply focus-visible:text-secondaryDark;
|
||||
@apply before:absolute;
|
||||
@apply before:left-0;
|
||||
@apply before:right-0;
|
||||
@apply before:top-0;
|
||||
@apply before:bg-transparent;
|
||||
@apply before:z-2;
|
||||
@apply before:h-0.5;
|
||||
@apply before:content-DEFAULT;
|
||||
@apply hover: bg-primaryDark;
|
||||
@apply hover: text-secondary;
|
||||
@apply focus-visible: text-secondaryDark;
|
||||
@apply before: absolute;
|
||||
@apply before: left-0;
|
||||
@apply before: right-0;
|
||||
@apply before: top-0;
|
||||
@apply before: bg-transparent;
|
||||
@apply before: z-2;
|
||||
@apply before: h-0.5;
|
||||
@apply before: content-DEFAULT;
|
||||
@apply focus: before: bg-divider;
|
||||
|
||||
&.active {
|
||||
@apply text-secondaryDark;
|
||||
@apply bg-primary;
|
||||
@apply before:bg-accent;
|
||||
@apply before: bg-accent;
|
||||
}
|
||||
|
||||
.close {
|
||||
|
||||
20
packages/hoppscotch-ui/src/components/smart/index.ts
Normal file
20
packages/hoppscotch-ui/src/components/smart/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
export { default as HoppSmartAnchor } from "./Anchor.vue"
|
||||
export { default as HoppSmartAutoComplete } from "./AutoComplete.vue"
|
||||
export { default as HoppSmartCheckbox } from "./Checkbox.vue"
|
||||
export { default as HoppSmartConfirmModal } from "./ConfirmModal.vue"
|
||||
export { default as HoppSmartExpand } from "./Expand.vue"
|
||||
export { default as HoppSmartFileChip } from "./FileChip.vue"
|
||||
export { default as HoppSmartIntersection } from "./Intersection.vue"
|
||||
export { default as HoppSmartItem } from "./Item.vue"
|
||||
export { default as HoppSmartLink } from "./Link.vue"
|
||||
export { default as HoppSmartModal } from "./Modal.vue"
|
||||
export { default as HoppSmartProgressRing } from "./ProgressRing.vue"
|
||||
export { default as HoppSmartRadio } from "./Radio.vue"
|
||||
export { default as HoppSmartRadioGroup } from "./RadioGroup.vue"
|
||||
export { default as HoppSmartSlideOver } from "./SlideOver.vue"
|
||||
export { default as HoppSmartSpinner } from "./Spinner.vue"
|
||||
export { default as HoppSmartTab } from "./Tab.vue"
|
||||
export { default as HoppSmartTabs } from "./Tabs.vue"
|
||||
export { default as HoppSmartToggle } from "./Toggle.vue"
|
||||
export { default as HoppSmartWindow } from "./Window.vue"
|
||||
export { default as HoppSmartWindows } from "./Windows.vue"
|
||||
Reference in New Issue
Block a user