feat: vertical tabs for right sidebars
This commit is contained in:
1
packages/hoppscotch-app/assets/icons/box.svg
Normal file
1
packages/hoppscotch-app/assets/icons/box.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line></svg>
|
||||
|
After Width: | Height: | Size: 435 B |
1
packages/hoppscotch-app/assets/icons/clock.svg
Normal file
1
packages/hoppscotch-app/assets/icons/clock.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg>
|
||||
|
After Width: | Height: | Size: 275 B |
@@ -8,7 +8,7 @@
|
||||
divide-y divide-dividerLight
|
||||
border-b border-dividerLight
|
||||
flex flex-col
|
||||
top-sidebarPrimaryStickyFold
|
||||
top-0
|
||||
z-10
|
||||
sticky
|
||||
"
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
z-10
|
||||
sticky
|
||||
"
|
||||
:class="{ '!top-sidebarPrimaryStickyFold': !saveRequest && !doc }"
|
||||
>
|
||||
<div v-if="!saveRequest" class="search-wrappe">
|
||||
<input
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
<template>
|
||||
<AppSection :label="`${$t('environment.title')}`">
|
||||
<div
|
||||
class="
|
||||
bg-primary
|
||||
rounded-t
|
||||
flex flex-col
|
||||
top-sidebarPrimaryStickyFold
|
||||
z-10
|
||||
sticky
|
||||
"
|
||||
>
|
||||
<div class="bg-primary rounded-t flex flex-col top-0 z-10 sticky">
|
||||
<tippy ref="options" interactive trigger="click" theme="popover" arrow>
|
||||
<template #trigger>
|
||||
<span
|
||||
|
||||
@@ -1,9 +1,54 @@
|
||||
<template>
|
||||
<aside>
|
||||
<SmartTabs styles="sticky bg-primary z-10 top-0">
|
||||
<SmartTab :id="'docs'" :label="`Docs`" :selected="true">
|
||||
<AppSection label="docs">
|
||||
<div class="bg-primary flex top-sidebarPrimaryStickyFold z-10 sticky">
|
||||
<SmartTabs styles="sticky bg-primary z-10 top-0" vertical>
|
||||
<SmartTab
|
||||
:id="'history'"
|
||||
icon="clock"
|
||||
:label="`${$t('tab.history')}`"
|
||||
:selected="true"
|
||||
>
|
||||
<History
|
||||
ref="graphqlHistoryComponent"
|
||||
:page="'graphql'"
|
||||
@useHistory="handleUseHistory"
|
||||
/>
|
||||
</SmartTab>
|
||||
|
||||
<SmartTab
|
||||
:id="'collections'"
|
||||
icon="folder"
|
||||
:label="`${$t('tab.collections')}`"
|
||||
>
|
||||
<CollectionsGraphql />
|
||||
</SmartTab>
|
||||
|
||||
<SmartTab
|
||||
:id="'docs'"
|
||||
icon="book-open"
|
||||
:label="`${$t('tab.documentation')}`"
|
||||
>
|
||||
<AppSection label="docs">
|
||||
<div
|
||||
v-if="
|
||||
queryFields.length === 0 &&
|
||||
mutationFields.length === 0 &&
|
||||
subscriptionFields.length === 0 &&
|
||||
graphqlTypes.length === 0
|
||||
"
|
||||
class="
|
||||
flex flex-col
|
||||
text-secondaryLight
|
||||
p-4
|
||||
items-center
|
||||
justify-center
|
||||
"
|
||||
>
|
||||
<i class="opacity-75 pb-2 material-icons">link</i>
|
||||
<span class="text-center">
|
||||
{{ $t("empty.schema") }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div class="bg-primary flex top-0 z-10 sticky">
|
||||
<input
|
||||
v-model="graphqlFieldsFilterText"
|
||||
type="search"
|
||||
@@ -23,7 +68,7 @@
|
||||
</div>
|
||||
<SmartTabs
|
||||
ref="gqlTabs"
|
||||
styles="border-t border-dividerLight bg-primary sticky z-10 top-sidebarSecondaryStickyFold"
|
||||
styles="border-t border-b border-dividerLight bg-primary sticky z-10 top-sidebarPrimaryStickyFold"
|
||||
>
|
||||
<div class="gqlTabs">
|
||||
<SmartTab
|
||||
@@ -88,110 +133,79 @@
|
||||
</SmartTab>
|
||||
</div>
|
||||
</SmartTabs>
|
||||
<div
|
||||
v-if="
|
||||
queryFields.length === 0 &&
|
||||
mutationFields.length === 0 &&
|
||||
subscriptionFields.length === 0 &&
|
||||
graphqlTypes.length === 0
|
||||
"
|
||||
class="
|
||||
flex flex-col
|
||||
text-secondaryLight
|
||||
p-4
|
||||
items-center
|
||||
justify-center
|
||||
"
|
||||
>
|
||||
<i class="opacity-75 pb-2 material-icons">link</i>
|
||||
<span class="text-center">
|
||||
{{ $t("empty.schema") }}
|
||||
</span>
|
||||
</div>
|
||||
</AppSection>
|
||||
</SmartTab>
|
||||
</div>
|
||||
</AppSection>
|
||||
</SmartTab>
|
||||
|
||||
<SmartTab :id="'history'" :label="`${$t('tab.history')}`">
|
||||
<History
|
||||
ref="graphqlHistoryComponent"
|
||||
:page="'graphql'"
|
||||
@useHistory="handleUseHistory"
|
||||
/>
|
||||
</SmartTab>
|
||||
|
||||
<SmartTab :id="'collections'" :label="`${$t('tab.collections')}`">
|
||||
<CollectionsGraphql />
|
||||
</SmartTab>
|
||||
|
||||
<SmartTab :id="'schema'" :label="`Schema`">
|
||||
<AppSection ref="schema" label="schema">
|
||||
<div
|
||||
v-if="schemaString"
|
||||
class="
|
||||
bg-primary
|
||||
flex flex-1
|
||||
top-sidebarPrimaryStickyFold
|
||||
pl-4
|
||||
z-10
|
||||
sticky
|
||||
items-center
|
||||
justify-between
|
||||
"
|
||||
>
|
||||
<label class="font-semibold text-secondaryLight">
|
||||
{{ $t("graphql.schema") }}
|
||||
</label>
|
||||
<div class="flex">
|
||||
<ButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
to="https://docs.hoppscotch.io/quickstart/graphql"
|
||||
blank
|
||||
:title="$t('app.wiki')"
|
||||
svg="help-circle"
|
||||
/>
|
||||
<ButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="$t('state.linewrap')"
|
||||
:class="{ '!text-accent': linewrapEnabled }"
|
||||
svg="corner-down-left"
|
||||
@click.native.prevent="linewrapEnabled = !linewrapEnabled"
|
||||
/>
|
||||
<ButtonSecondary
|
||||
ref="downloadSchema"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="$t('action.download_file')"
|
||||
:svg="downloadSchemaIcon"
|
||||
@click.native="downloadSchema"
|
||||
/>
|
||||
<ButtonSecondary
|
||||
ref="copySchemaCode"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="$t('action.copy')"
|
||||
:svg="copySchemaIcon"
|
||||
@click.native="copySchema"
|
||||
/>
|
||||
</div>
|
||||
<SmartTab :id="'schema'" icon="box" :label="`${$t('tab.schema')}`">
|
||||
<AppSection ref="schema" label="schema">
|
||||
<div
|
||||
v-if="schemaString"
|
||||
class="
|
||||
bg-primary
|
||||
flex flex-1
|
||||
top-0
|
||||
pl-4
|
||||
z-10
|
||||
sticky
|
||||
items-center
|
||||
justify-between
|
||||
border-b border-dividerLight
|
||||
"
|
||||
>
|
||||
<label class="font-semibold text-secondaryLight">
|
||||
{{ $t("graphql.schema") }}
|
||||
</label>
|
||||
<div class="flex">
|
||||
<ButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
to="https://docs.hoppscotch.io/quickstart/graphql"
|
||||
blank
|
||||
:title="$t('app.wiki')"
|
||||
svg="help-circle"
|
||||
/>
|
||||
<ButtonSecondary
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="$t('state.linewrap')"
|
||||
:class="{ '!text-accent': linewrapEnabled }"
|
||||
svg="corner-down-left"
|
||||
@click.native.prevent="linewrapEnabled = !linewrapEnabled"
|
||||
/>
|
||||
<ButtonSecondary
|
||||
ref="downloadSchema"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="$t('action.download_file')"
|
||||
:svg="downloadSchemaIcon"
|
||||
@click.native="downloadSchema"
|
||||
/>
|
||||
<ButtonSecondary
|
||||
ref="copySchemaCode"
|
||||
v-tippy="{ theme: 'tooltip' }"
|
||||
:title="$t('action.copy')"
|
||||
:svg="copySchemaIcon"
|
||||
@click.native="copySchema"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="schemaString" ref="schemaEditor"></div>
|
||||
<div
|
||||
v-else
|
||||
class="
|
||||
flex flex-col
|
||||
text-secondaryLight
|
||||
p-4
|
||||
items-center
|
||||
justify-center
|
||||
"
|
||||
>
|
||||
<i class="opacity-75 pb-2 material-icons">link</i>
|
||||
<span class="text-center">
|
||||
{{ $t("empty.schema") }}
|
||||
</span>
|
||||
</div>
|
||||
</AppSection>
|
||||
</SmartTab>
|
||||
</SmartTabs>
|
||||
</aside>
|
||||
</div>
|
||||
<div v-if="schemaString" ref="schemaEditor"></div>
|
||||
<div
|
||||
v-else
|
||||
class="
|
||||
flex flex-col
|
||||
text-secondaryLight
|
||||
p-4
|
||||
items-center
|
||||
justify-center
|
||||
"
|
||||
>
|
||||
<i class="opacity-75 pb-2 material-icons">link</i>
|
||||
<span class="text-center">
|
||||
{{ $t("empty.schema") }}
|
||||
</span>
|
||||
</div>
|
||||
</AppSection>
|
||||
</SmartTab>
|
||||
</SmartTabs>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
<template>
|
||||
<AppSection label="history">
|
||||
<div
|
||||
class="
|
||||
bg-primary
|
||||
border-b border-dividerLight
|
||||
flex
|
||||
top-sidebarPrimaryStickyFold
|
||||
z-10
|
||||
sticky
|
||||
"
|
||||
>
|
||||
<div class="bg-primary border-b border-dividerLight flex top-0 z-10 sticky">
|
||||
<input
|
||||
v-model="filterText"
|
||||
type="search"
|
||||
|
||||
@@ -1,34 +1,53 @@
|
||||
<template>
|
||||
<div class="flex flex-col flex-nowrap flex-1">
|
||||
<div class="tabs hide-scrollbar relative" :class="styles">
|
||||
<div
|
||||
class="flex flex-nowrap flex-1 h-full"
|
||||
:class="{ 'flex-col': !vertical }"
|
||||
>
|
||||
<div
|
||||
class="tabs hide-scrollbar relative"
|
||||
:class="[{ 'border-r border-dividerLight': vertical }, styles]"
|
||||
>
|
||||
<div class="flex flex-1">
|
||||
<div class="flex flex-1 justify-between">
|
||||
<div class="flex">
|
||||
<div
|
||||
class="flex flex-1 justify-between"
|
||||
:class="{ 'flex-col': vertical }"
|
||||
>
|
||||
<div class="flex" :class="{ 'flex-col space-y-2 p-2': vertical }">
|
||||
<button
|
||||
v-for="(tab, index) in tabs"
|
||||
:key="`tab-${index}`"
|
||||
class="tab"
|
||||
:class="{ active: tab.active }"
|
||||
:class="[{ active: tab.active }, { vertical: vertical }]"
|
||||
tabindex="0"
|
||||
@keyup.enter="selectTab(tab)"
|
||||
@click="selectTab(tab)"
|
||||
>
|
||||
<i v-if="tab.icon" class="material-icons">
|
||||
{{ tab.icon }}
|
||||
</i>
|
||||
<span v-if="tab.label">{{ tab.label }}</span>
|
||||
<SmartIcon v-if="tab.icon" class="svg-icons" :name="tab.icon" />
|
||||
<tippy
|
||||
v-if="vertical && tab.label"
|
||||
placement="left"
|
||||
theme="tooltip"
|
||||
:content="tab.label"
|
||||
/>
|
||||
<span v-else-if="tab.label">{{ tab.label }}</span>
|
||||
<span v-if="tab.info && tab.info !== 'null'" class="tab-info">
|
||||
{{ tab.info }}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="flex justify-center items-center">
|
||||
<slot name="actions"></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<slot></slot>
|
||||
<div
|
||||
:class="{
|
||||
'flex flex-col flex-1 overflow-y-auto hide-scrollbar': vertical,
|
||||
}"
|
||||
>
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -41,6 +60,10 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
vertical: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
@@ -49,8 +72,10 @@ export default defineComponent({
|
||||
}
|
||||
},
|
||||
|
||||
created() {
|
||||
this.tabs = this.$children
|
||||
mounted() {
|
||||
this.tabs = this.$children.filter(
|
||||
(child) => child.$options.name === "SmartTab"
|
||||
)
|
||||
},
|
||||
|
||||
methods: {
|
||||
@@ -69,6 +94,7 @@ export default defineComponent({
|
||||
@apply flex;
|
||||
@apply whitespace-nowrap;
|
||||
@apply overflow-auto;
|
||||
@apply flex-shrink-0;
|
||||
|
||||
// &::after {
|
||||
// @apply absolute;
|
||||
@@ -84,6 +110,7 @@ export default defineComponent({
|
||||
.tab {
|
||||
@apply relative;
|
||||
@apply flex;
|
||||
@apply flex-shrink-0;
|
||||
@apply items-center;
|
||||
@apply justify-center;
|
||||
@apply px-4 py-2;
|
||||
@@ -120,10 +147,6 @@ export default defineComponent({
|
||||
content: "";
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
@apply mr-4;
|
||||
}
|
||||
|
||||
&:focus::after {
|
||||
@apply bg-divider;
|
||||
}
|
||||
@@ -140,6 +163,28 @@ export default defineComponent({
|
||||
@apply bg-accent;
|
||||
}
|
||||
}
|
||||
|
||||
&.vertical {
|
||||
@apply p-2;
|
||||
@apply rounded;
|
||||
|
||||
&:focus::after {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
&.active {
|
||||
@apply text-accent;
|
||||
|
||||
.tab-info {
|
||||
@apply text-secondary;
|
||||
@apply border-dividerDark;
|
||||
}
|
||||
|
||||
&::after {
|
||||
@apply hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -442,6 +442,7 @@
|
||||
"authorization": "Authorization",
|
||||
"body": "Body",
|
||||
"collections": "Collections",
|
||||
"documentation": "Documentation",
|
||||
"headers": "Headers",
|
||||
"history": "History",
|
||||
"mqtt": "MQTT",
|
||||
@@ -449,6 +450,7 @@
|
||||
"pre_request_script": "Pre-request Script",
|
||||
"queries": "Queries",
|
||||
"query": "Query",
|
||||
"schema": "Schema",
|
||||
"socketio": "Socket.IO",
|
||||
"sse": "SSE",
|
||||
"tests": "Tests",
|
||||
|
||||
@@ -71,7 +71,7 @@ export const defaultSettings: SettingsType = {
|
||||
bearerToken: true,
|
||||
oauth2Token: true,
|
||||
},
|
||||
THEME_COLOR: "blue",
|
||||
THEME_COLOR: "indigo",
|
||||
BG_COLOR: "system",
|
||||
TELEMETRY_ENABLED: true,
|
||||
LEFT_SIDEBAR: true,
|
||||
|
||||
@@ -61,25 +61,32 @@
|
||||
min-size="20"
|
||||
class="hide-scrollbar !overflow-auto"
|
||||
>
|
||||
<aside>
|
||||
<SmartTabs styles="sticky bg-primary z-10 top-0">
|
||||
<SmartTab
|
||||
:id="'history'"
|
||||
:label="`${$t('tab.history')}`"
|
||||
:selected="true"
|
||||
>
|
||||
<History ref="historyComponent" :page="'rest'" />
|
||||
</SmartTab>
|
||||
<SmartTabs styles="sticky bg-primary z-10 top-0" vertical>
|
||||
<SmartTab
|
||||
:id="'history'"
|
||||
icon="clock"
|
||||
:label="`${$t('tab.history')}`"
|
||||
:selected="true"
|
||||
>
|
||||
<History ref="historyComponent" :page="'rest'" />
|
||||
</SmartTab>
|
||||
|
||||
<SmartTab :id="'collections'" :label="`${$t('tab.collections')}`">
|
||||
<Collections />
|
||||
</SmartTab>
|
||||
<SmartTab
|
||||
:id="'collections'"
|
||||
icon="folder"
|
||||
:label="`${$t('tab.collections')}`"
|
||||
>
|
||||
<Collections />
|
||||
</SmartTab>
|
||||
|
||||
<SmartTab :id="'env'" :label="`${$t('environment.title')}`">
|
||||
<Environments />
|
||||
</SmartTab>
|
||||
</SmartTabs>
|
||||
</aside>
|
||||
<SmartTab
|
||||
:id="'env'"
|
||||
icon="layers"
|
||||
:label="`${$t('environment.title')}`"
|
||||
>
|
||||
<Environments />
|
||||
</SmartTab>
|
||||
</SmartTabs>
|
||||
</Pane>
|
||||
<SmartConfirmModal
|
||||
:show="confirmSync"
|
||||
|
||||
@@ -397,7 +397,7 @@ export default defineComponent({
|
||||
|
||||
showLogin: false,
|
||||
|
||||
active: getLocalConfig("THEME_COLOR") || "blue",
|
||||
active: getLocalConfig("THEME_COLOR") || "indigo",
|
||||
confirmRemove: false,
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user