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
|
divide-y divide-dividerLight
|
||||||
border-b border-dividerLight
|
border-b border-dividerLight
|
||||||
flex flex-col
|
flex flex-col
|
||||||
top-sidebarPrimaryStickyFold
|
top-0
|
||||||
z-10
|
z-10
|
||||||
sticky
|
sticky
|
||||||
"
|
"
|
||||||
|
|||||||
@@ -14,7 +14,6 @@
|
|||||||
z-10
|
z-10
|
||||||
sticky
|
sticky
|
||||||
"
|
"
|
||||||
:class="{ '!top-sidebarPrimaryStickyFold': !saveRequest && !doc }"
|
|
||||||
>
|
>
|
||||||
<div v-if="!saveRequest" class="search-wrappe">
|
<div v-if="!saveRequest" class="search-wrappe">
|
||||||
<input
|
<input
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppSection :label="`${$t('environment.title')}`">
|
<AppSection :label="`${$t('environment.title')}`">
|
||||||
<div
|
<div class="bg-primary rounded-t flex flex-col top-0 z-10 sticky">
|
||||||
class="
|
|
||||||
bg-primary
|
|
||||||
rounded-t
|
|
||||||
flex flex-col
|
|
||||||
top-sidebarPrimaryStickyFold
|
|
||||||
z-10
|
|
||||||
sticky
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<tippy ref="options" interactive trigger="click" theme="popover" arrow>
|
<tippy ref="options" interactive trigger="click" theme="popover" arrow>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<span
|
<span
|
||||||
|
|||||||
@@ -1,9 +1,54 @@
|
|||||||
<template>
|
<template>
|
||||||
<aside>
|
<SmartTabs styles="sticky bg-primary z-10 top-0" vertical>
|
||||||
<SmartTabs styles="sticky bg-primary z-10 top-0">
|
<SmartTab
|
||||||
<SmartTab :id="'docs'" :label="`Docs`" :selected="true">
|
:id="'history'"
|
||||||
<AppSection label="docs">
|
icon="clock"
|
||||||
<div class="bg-primary flex top-sidebarPrimaryStickyFold z-10 sticky">
|
: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
|
<input
|
||||||
v-model="graphqlFieldsFilterText"
|
v-model="graphqlFieldsFilterText"
|
||||||
type="search"
|
type="search"
|
||||||
@@ -23,7 +68,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<SmartTabs
|
<SmartTabs
|
||||||
ref="gqlTabs"
|
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">
|
<div class="gqlTabs">
|
||||||
<SmartTab
|
<SmartTab
|
||||||
@@ -88,110 +133,79 @@
|
|||||||
</SmartTab>
|
</SmartTab>
|
||||||
</div>
|
</div>
|
||||||
</SmartTabs>
|
</SmartTabs>
|
||||||
<div
|
</div>
|
||||||
v-if="
|
</AppSection>
|
||||||
queryFields.length === 0 &&
|
</SmartTab>
|
||||||
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>
|
|
||||||
|
|
||||||
<SmartTab :id="'history'" :label="`${$t('tab.history')}`">
|
<SmartTab :id="'schema'" icon="box" :label="`${$t('tab.schema')}`">
|
||||||
<History
|
<AppSection ref="schema" label="schema">
|
||||||
ref="graphqlHistoryComponent"
|
<div
|
||||||
:page="'graphql'"
|
v-if="schemaString"
|
||||||
@useHistory="handleUseHistory"
|
class="
|
||||||
/>
|
bg-primary
|
||||||
</SmartTab>
|
flex flex-1
|
||||||
|
top-0
|
||||||
<SmartTab :id="'collections'" :label="`${$t('tab.collections')}`">
|
pl-4
|
||||||
<CollectionsGraphql />
|
z-10
|
||||||
</SmartTab>
|
sticky
|
||||||
|
items-center
|
||||||
<SmartTab :id="'schema'" :label="`Schema`">
|
justify-between
|
||||||
<AppSection ref="schema" label="schema">
|
border-b border-dividerLight
|
||||||
<div
|
"
|
||||||
v-if="schemaString"
|
>
|
||||||
class="
|
<label class="font-semibold text-secondaryLight">
|
||||||
bg-primary
|
{{ $t("graphql.schema") }}
|
||||||
flex flex-1
|
</label>
|
||||||
top-sidebarPrimaryStickyFold
|
<div class="flex">
|
||||||
pl-4
|
<ButtonSecondary
|
||||||
z-10
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
sticky
|
to="https://docs.hoppscotch.io/quickstart/graphql"
|
||||||
items-center
|
blank
|
||||||
justify-between
|
:title="$t('app.wiki')"
|
||||||
"
|
svg="help-circle"
|
||||||
>
|
/>
|
||||||
<label class="font-semibold text-secondaryLight">
|
<ButtonSecondary
|
||||||
{{ $t("graphql.schema") }}
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
</label>
|
:title="$t('state.linewrap')"
|
||||||
<div class="flex">
|
:class="{ '!text-accent': linewrapEnabled }"
|
||||||
<ButtonSecondary
|
svg="corner-down-left"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
@click.native.prevent="linewrapEnabled = !linewrapEnabled"
|
||||||
to="https://docs.hoppscotch.io/quickstart/graphql"
|
/>
|
||||||
blank
|
<ButtonSecondary
|
||||||
:title="$t('app.wiki')"
|
ref="downloadSchema"
|
||||||
svg="help-circle"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
/>
|
:title="$t('action.download_file')"
|
||||||
<ButtonSecondary
|
:svg="downloadSchemaIcon"
|
||||||
v-tippy="{ theme: 'tooltip' }"
|
@click.native="downloadSchema"
|
||||||
:title="$t('state.linewrap')"
|
/>
|
||||||
:class="{ '!text-accent': linewrapEnabled }"
|
<ButtonSecondary
|
||||||
svg="corner-down-left"
|
ref="copySchemaCode"
|
||||||
@click.native.prevent="linewrapEnabled = !linewrapEnabled"
|
v-tippy="{ theme: 'tooltip' }"
|
||||||
/>
|
:title="$t('action.copy')"
|
||||||
<ButtonSecondary
|
:svg="copySchemaIcon"
|
||||||
ref="downloadSchema"
|
@click.native="copySchema"
|
||||||
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>
|
</div>
|
||||||
<div v-if="schemaString" ref="schemaEditor"></div>
|
</div>
|
||||||
<div
|
<div v-if="schemaString" ref="schemaEditor"></div>
|
||||||
v-else
|
<div
|
||||||
class="
|
v-else
|
||||||
flex flex-col
|
class="
|
||||||
text-secondaryLight
|
flex flex-col
|
||||||
p-4
|
text-secondaryLight
|
||||||
items-center
|
p-4
|
||||||
justify-center
|
items-center
|
||||||
"
|
justify-center
|
||||||
>
|
"
|
||||||
<i class="opacity-75 pb-2 material-icons">link</i>
|
>
|
||||||
<span class="text-center">
|
<i class="opacity-75 pb-2 material-icons">link</i>
|
||||||
{{ $t("empty.schema") }}
|
<span class="text-center">
|
||||||
</span>
|
{{ $t("empty.schema") }}
|
||||||
</div>
|
</span>
|
||||||
</AppSection>
|
</div>
|
||||||
</SmartTab>
|
</AppSection>
|
||||||
</SmartTabs>
|
</SmartTab>
|
||||||
</aside>
|
</SmartTabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<AppSection label="history">
|
<AppSection label="history">
|
||||||
<div
|
<div class="bg-primary border-b border-dividerLight flex top-0 z-10 sticky">
|
||||||
class="
|
|
||||||
bg-primary
|
|
||||||
border-b border-dividerLight
|
|
||||||
flex
|
|
||||||
top-sidebarPrimaryStickyFold
|
|
||||||
z-10
|
|
||||||
sticky
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
v-model="filterText"
|
v-model="filterText"
|
||||||
type="search"
|
type="search"
|
||||||
|
|||||||
@@ -1,34 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex flex-col flex-nowrap flex-1">
|
<div
|
||||||
<div class="tabs hide-scrollbar relative" :class="styles">
|
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">
|
||||||
<div class="flex flex-1 justify-between">
|
<div
|
||||||
<div class="flex">
|
class="flex flex-1 justify-between"
|
||||||
|
:class="{ 'flex-col': vertical }"
|
||||||
|
>
|
||||||
|
<div class="flex" :class="{ 'flex-col space-y-2 p-2': vertical }">
|
||||||
<button
|
<button
|
||||||
v-for="(tab, index) in tabs"
|
v-for="(tab, index) in tabs"
|
||||||
:key="`tab-${index}`"
|
:key="`tab-${index}`"
|
||||||
class="tab"
|
class="tab"
|
||||||
:class="{ active: tab.active }"
|
:class="[{ active: tab.active }, { vertical: vertical }]"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
@keyup.enter="selectTab(tab)"
|
@keyup.enter="selectTab(tab)"
|
||||||
@click="selectTab(tab)"
|
@click="selectTab(tab)"
|
||||||
>
|
>
|
||||||
<i v-if="tab.icon" class="material-icons">
|
<SmartIcon v-if="tab.icon" class="svg-icons" :name="tab.icon" />
|
||||||
{{ tab.icon }}
|
<tippy
|
||||||
</i>
|
v-if="vertical && tab.label"
|
||||||
<span v-if="tab.label">{{ tab.label }}</span>
|
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">
|
<span v-if="tab.info && tab.info !== 'null'" class="tab-info">
|
||||||
{{ tab.info }}
|
{{ tab.info }}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex">
|
<div class="flex justify-center items-center">
|
||||||
<slot name="actions"></slot>
|
<slot name="actions"></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<slot></slot>
|
<div
|
||||||
|
:class="{
|
||||||
|
'flex flex-col flex-1 overflow-y-auto hide-scrollbar': vertical,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -41,6 +60,10 @@ export default defineComponent({
|
|||||||
type: String,
|
type: String,
|
||||||
default: "",
|
default: "",
|
||||||
},
|
},
|
||||||
|
vertical: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
@@ -49,8 +72,10 @@ export default defineComponent({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
mounted() {
|
||||||
this.tabs = this.$children
|
this.tabs = this.$children.filter(
|
||||||
|
(child) => child.$options.name === "SmartTab"
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
@@ -69,6 +94,7 @@ export default defineComponent({
|
|||||||
@apply flex;
|
@apply flex;
|
||||||
@apply whitespace-nowrap;
|
@apply whitespace-nowrap;
|
||||||
@apply overflow-auto;
|
@apply overflow-auto;
|
||||||
|
@apply flex-shrink-0;
|
||||||
|
|
||||||
// &::after {
|
// &::after {
|
||||||
// @apply absolute;
|
// @apply absolute;
|
||||||
@@ -84,6 +110,7 @@ export default defineComponent({
|
|||||||
.tab {
|
.tab {
|
||||||
@apply relative;
|
@apply relative;
|
||||||
@apply flex;
|
@apply flex;
|
||||||
|
@apply flex-shrink-0;
|
||||||
@apply items-center;
|
@apply items-center;
|
||||||
@apply justify-center;
|
@apply justify-center;
|
||||||
@apply px-4 py-2;
|
@apply px-4 py-2;
|
||||||
@@ -120,10 +147,6 @@ export default defineComponent({
|
|||||||
content: "";
|
content: "";
|
||||||
}
|
}
|
||||||
|
|
||||||
.material-icons {
|
|
||||||
@apply mr-4;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus::after {
|
&:focus::after {
|
||||||
@apply bg-divider;
|
@apply bg-divider;
|
||||||
}
|
}
|
||||||
@@ -140,6 +163,28 @@ export default defineComponent({
|
|||||||
@apply bg-accent;
|
@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>
|
</style>
|
||||||
|
|||||||
@@ -442,6 +442,7 @@
|
|||||||
"authorization": "Authorization",
|
"authorization": "Authorization",
|
||||||
"body": "Body",
|
"body": "Body",
|
||||||
"collections": "Collections",
|
"collections": "Collections",
|
||||||
|
"documentation": "Documentation",
|
||||||
"headers": "Headers",
|
"headers": "Headers",
|
||||||
"history": "History",
|
"history": "History",
|
||||||
"mqtt": "MQTT",
|
"mqtt": "MQTT",
|
||||||
@@ -449,6 +450,7 @@
|
|||||||
"pre_request_script": "Pre-request Script",
|
"pre_request_script": "Pre-request Script",
|
||||||
"queries": "Queries",
|
"queries": "Queries",
|
||||||
"query": "Query",
|
"query": "Query",
|
||||||
|
"schema": "Schema",
|
||||||
"socketio": "Socket.IO",
|
"socketio": "Socket.IO",
|
||||||
"sse": "SSE",
|
"sse": "SSE",
|
||||||
"tests": "Tests",
|
"tests": "Tests",
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ export const defaultSettings: SettingsType = {
|
|||||||
bearerToken: true,
|
bearerToken: true,
|
||||||
oauth2Token: true,
|
oauth2Token: true,
|
||||||
},
|
},
|
||||||
THEME_COLOR: "blue",
|
THEME_COLOR: "indigo",
|
||||||
BG_COLOR: "system",
|
BG_COLOR: "system",
|
||||||
TELEMETRY_ENABLED: true,
|
TELEMETRY_ENABLED: true,
|
||||||
LEFT_SIDEBAR: true,
|
LEFT_SIDEBAR: true,
|
||||||
|
|||||||
@@ -61,25 +61,32 @@
|
|||||||
min-size="20"
|
min-size="20"
|
||||||
class="hide-scrollbar !overflow-auto"
|
class="hide-scrollbar !overflow-auto"
|
||||||
>
|
>
|
||||||
<aside>
|
<SmartTabs styles="sticky bg-primary z-10 top-0" vertical>
|
||||||
<SmartTabs styles="sticky bg-primary z-10 top-0">
|
<SmartTab
|
||||||
<SmartTab
|
:id="'history'"
|
||||||
:id="'history'"
|
icon="clock"
|
||||||
:label="`${$t('tab.history')}`"
|
:label="`${$t('tab.history')}`"
|
||||||
:selected="true"
|
:selected="true"
|
||||||
>
|
>
|
||||||
<History ref="historyComponent" :page="'rest'" />
|
<History ref="historyComponent" :page="'rest'" />
|
||||||
</SmartTab>
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab :id="'collections'" :label="`${$t('tab.collections')}`">
|
<SmartTab
|
||||||
<Collections />
|
:id="'collections'"
|
||||||
</SmartTab>
|
icon="folder"
|
||||||
|
:label="`${$t('tab.collections')}`"
|
||||||
|
>
|
||||||
|
<Collections />
|
||||||
|
</SmartTab>
|
||||||
|
|
||||||
<SmartTab :id="'env'" :label="`${$t('environment.title')}`">
|
<SmartTab
|
||||||
<Environments />
|
:id="'env'"
|
||||||
</SmartTab>
|
icon="layers"
|
||||||
</SmartTabs>
|
:label="`${$t('environment.title')}`"
|
||||||
</aside>
|
>
|
||||||
|
<Environments />
|
||||||
|
</SmartTab>
|
||||||
|
</SmartTabs>
|
||||||
</Pane>
|
</Pane>
|
||||||
<SmartConfirmModal
|
<SmartConfirmModal
|
||||||
:show="confirmSync"
|
:show="confirmSync"
|
||||||
|
|||||||
@@ -397,7 +397,7 @@ export default defineComponent({
|
|||||||
|
|
||||||
showLogin: false,
|
showLogin: false,
|
||||||
|
|
||||||
active: getLocalConfig("THEME_COLOR") || "blue",
|
active: getLocalConfig("THEME_COLOR") || "indigo",
|
||||||
confirmRemove: false,
|
confirmRemove: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user