fix(common): improve responsive layout and overflow in realtime pages (#5843)

Co-authored-by: nivedin <nivedinp@gmail.com>
Co-authored-by: James George <25279263+jamesgeorge007@users.noreply.github.com>
This commit is contained in:
Chandraprakash Pandey 2026-02-18 14:28:43 +05:30 committed by GitHub
parent 28a6569f42
commit 680439a1b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 182 additions and 171 deletions

View file

@ -17,114 +17,117 @@
/>
</div>
<div
class="sticky z-10 flex flex-shrink-0 items-center justify-between overflow-x-auto border-b border-dividerLight bg-primary pl-4"
class="sticky z-10 w-0 min-w-full flex-shrink-0 overflow-x-auto border-b border-dividerLight bg-primary"
:class="stickyHeaderStyles"
>
<span class="flex items-center">
<label class="truncate font-semibold text-secondaryLight">
{{ t("websocket.message") }}
</label>
<tippy
interactive
trigger="click"
theme="popover"
:on-shown="() => tippyActions.focus()"
>
<HoppSmartSelectWrapper>
<HoppButtonSecondary
:label="contentType || t('state.none').toLowerCase()"
class="ml-2 rounded-none pr-8"
/>
</HoppSmartSelectWrapper>
<template #content="{ hide }">
<div
ref="tippyActions"
class="flex flex-col focus:outline-none"
tabindex="0"
@keyup.escape="hide()"
>
<HoppSmartItem
v-for="(contentTypeItem, index) in validContentTypes"
:key="`contentTypeItem-${index}`"
:label="contentTypeItem"
:info-icon="
contentTypeItem === contentType ? IconDone : undefined
"
:active-info-icon="contentTypeItem === contentType"
@click="
() => {
contentType = contentTypeItem
hide()
}
"
<div class="flex items-center justify-between pl-4">
<span class="flex items-center">
<label class="truncate font-semibold text-secondaryLight">
{{ t("websocket.message") }}
</label>
<tippy
interactive
trigger="click"
theme="popover"
:on-shown="() => tippyActions.focus()"
>
<HoppSmartSelectWrapper>
<HoppButtonSecondary
:label="contentType || t('state.none').toLowerCase()"
class="ml-2 rounded-none pr-8"
/>
</div>
</template>
</tippy>
</span>
<div class="flex">
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip', delay: [500, 20], allowHTML: true }"
:title="`${t(
'request.run'
)} <kbd>${getSpecialKey()}</kbd><kbd></kbd>`"
:label="`${t('action.send')}`"
:disabled="!communicationBody || !isConnected"
:icon="IconSend"
class="!hover:text-accentDark rounded-none !text-accent"
@click="sendMessage()"
/>
<HoppSmartCheckbox
v-tippy="{ theme: 'tooltip' }"
:on="clearInputOnSend"
class="px-2"
:title="`${t('mqtt.clear_input_on_send')}`"
@change="clearInputOnSend = !clearInputOnSend"
>
{{ t("mqtt.clear_input") }}
</HoppSmartCheckbox>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
to="https://docs.hoppscotch.io/documentation/features/realtime-api-testing"
blank
:title="t('app.wiki')"
:icon="IconHelpCircle"
/>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:title="t('action.clear')"
:icon="IconTrash2"
@click="clearContent"
/>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }"
:icon="IconWrapText"
@click.prevent="linewrapEnabled = !linewrapEnabled"
/>
<HoppButtonSecondary
v-if="contentType && contentType == 'JSON'"
v-tippy="{ theme: 'tooltip' }"
:title="t('action.prettify')"
:icon="prettifyIcon"
@click="prettifyRequestBody"
/>
<label for="payload">
</HoppSmartSelectWrapper>
<template #content="{ hide }">
<div
ref="tippyActions"
class="flex flex-col focus:outline-none"
tabindex="0"
@keyup.escape="hide()"
>
<HoppSmartItem
v-for="(contentTypeItem, index) in validContentTypes"
:key="`contentTypeItem-${index}`"
:label="contentTypeItem"
:info-icon="
contentTypeItem === contentType ? IconDone : undefined
"
:active-info-icon="contentTypeItem === contentType"
@click="
() => {
contentType = contentTypeItem
hide()
}
"
/>
</div>
</template>
</tippy>
</span>
<div class="flex">
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip', delay: [500, 20], allowHTML: true }"
:title="`${t(
'request.run'
)} <kbd>${getSpecialKey()}</kbd><kbd></kbd>`"
:label="`${t('action.send')}`"
:disabled="!communicationBody || !isConnected"
:icon="IconSend"
class="!hover:text-accentDark rounded-none !text-accent"
@click="sendMessage()"
/>
<HoppSmartCheckbox
v-tippy="{ theme: 'tooltip' }"
:on="clearInputOnSend"
class="px-2"
:title="`${t('mqtt.clear_input_on_send')}`"
@change="clearInputOnSend = !clearInputOnSend"
>
{{ t("mqtt.clear_input") }}
</HoppSmartCheckbox>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:title="t('import.title')"
:icon="IconFilePlus"
@click="payload!.click()"
to="https://docs.hoppscotch.io/documentation/features/realtime-api-testing"
blank
:title="t('app.wiki')"
:icon="IconHelpCircle"
/>
</label>
<input
ref="payload"
class="input"
name="payload"
type="file"
@change="uploadPayload"
/>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:title="t('action.clear')"
:icon="IconTrash2"
@click="clearContent"
/>
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:title="t('state.linewrap')"
:class="{ '!text-accent': linewrapEnabled }"
:icon="IconWrapText"
@click.prevent="linewrapEnabled = !linewrapEnabled"
/>
<HoppButtonSecondary
v-if="contentType && contentType == 'JSON'"
v-tippy="{ theme: 'tooltip' }"
:title="t('action.prettify')"
:icon="prettifyIcon"
@click="prettifyRequestBody"
/>
<label for="payload">
<HoppButtonSecondary
v-tippy="{ theme: 'tooltip' }"
:title="t('import.title')"
:icon="IconFilePlus"
@click="payload!.click()"
/>
</label>
<input
id="payload"
ref="payload"
class="input"
name="payload"
type="file"
@change="uploadPayload"
/>
</div>
</div>
</div>
<div class="h-full relative overflow-auto flex flex-col flex-1">

View file

@ -4,8 +4,8 @@
<div
class="sticky top-0 z-10 flex flex-shrink-0 space-x-2 overflow-x-auto bg-primary p-4"
>
<div class="inline-flex flex-1 space-x-2">
<div class="flex flex-1">
<div class="sm:inline-flex flex-1 sm:space-x-2 sm:space-y-0 space-y-2">
<div class="flex flex-1 sm:flex-row flex-col sm:space-y-0 space-y-2">
<input
id="mqtt-url"
v-model="url"
@ -20,28 +20,30 @@
"
@keyup.enter="isUrlValid ? toggleConnection() : null"
/>
<label
for="client-id"
class="truncate border-b border-t border-divider bg-primaryLight px-4 py-2 font-semibold text-secondaryLight"
>
{{ t("mqtt.client_id") }}
</label>
<input
id="client-id"
v-model="clientID"
class="flex w-full flex-1 rounded-r border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
spellcheck="false"
:disabled="
connectionState === 'CONNECTED' ||
connectionState === 'CONNECTING'
"
@keyup.enter="isUrlValid ? toggleConnection() : null"
/>
<div class="flex">
<label
for="client-id"
class="truncate border-b border-t border-divider bg-primaryLight px-4 py-2 font-semibold text-secondaryLight"
>
{{ t("mqtt.client_id") }}
</label>
<input
id="client-id"
v-model="clientID"
class="flex w-full flex-1 rounded-r border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
spellcheck="false"
:disabled="
connectionState === 'CONNECTED' ||
connectionState === 'CONNECTING'
"
@keyup.enter="isUrlValid ? toggleConnection() : null"
/>
</div>
</div>
<HoppButtonPrimary
id="connect"
:disabled="!isUrlValid"
class="w-32"
class="sm:w-32 w-full"
:label="
connectionState === 'CONNECTING'
? t('action.connecting')

View file

@ -4,21 +4,22 @@
<div
class="sticky top-0 z-10 flex flex-shrink-0 space-x-2 overflow-x-auto bg-primary p-4"
>
<div class="inline-flex flex-1 space-x-2">
<div class="flex flex-1">
<div class="sm:inline-flex flex-1 sm:space-x-2 sm:space-y-0 space-y-2">
<div class="flex flex-1 sm:flex-row flex-col sm:space-y-0 space-y-2">
<label for="client-version">
<tippy
interactive
trigger="click"
theme="popover"
:on-shown="() => tippyActions.focus()"
class="sm:bg-primaryLight"
>
<HoppSmartSelectWrapper>
<input
id="client-version"
v-tippy="{ theme: 'tooltip' }"
title="socket.io-client version"
class="flex w-26 cursor-pointer rounded-l border border-divider bg-primaryLight px-4 py-2 font-semibold text-secondaryDark"
class="flex sm:w-26 flex-1 cursor-pointer rounded-l border border-divider bg-primaryLight px-4 py-2 font-semibold text-secondaryDark"
:value="`Client ${clientVersion}`"
readonly
:disabled="
@ -49,38 +50,40 @@
</template>
</tippy>
</label>
<input
id="socketio-url"
v-model="url"
type="url"
autocomplete="off"
spellcheck="false"
:class="{ error: !isUrlValid }"
class="flex w-full flex-1 border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
:placeholder="`${t('socketio.url')}`"
:disabled="
connectionState === 'CONNECTED' ||
connectionState === 'CONNECTING'
"
@keyup.enter="isUrlValid ? toggleConnection() : null"
/>
<input
id="socketio-path"
v-model="path"
class="flex w-full flex-1 rounded-r border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
spellcheck="false"
:disabled="
connectionState === 'CONNECTED' ||
connectionState === 'CONNECTING'
"
@keyup.enter="isUrlValid ? toggleConnection() : null"
/>
<div class="flex flex-1">
<input
id="socketio-url"
v-model="url"
type="url"
autocomplete="off"
spellcheck="false"
:class="{ error: !isUrlValid }"
class="flex w-full flex-1 border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
:placeholder="`${t('socketio.url')}`"
:disabled="
connectionState === 'CONNECTED' ||
connectionState === 'CONNECTING'
"
@keyup.enter="isUrlValid ? toggleConnection() : null"
/>
<input
id="socketio-path"
v-model="path"
class="flex w-full flex-1 rounded-r border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
spellcheck="false"
:disabled="
connectionState === 'CONNECTED' ||
connectionState === 'CONNECTING'
"
@keyup.enter="isUrlValid ? toggleConnection() : null"
/>
</div>
</div>
<HoppButtonPrimary
id="connect"
:disabled="!isUrlValid"
name="connect"
class="w-32"
class="sm:w-32 w-full"
:label="
connectionState === 'CONNECTING'
? t('action.connecting')

View file

@ -4,8 +4,8 @@
<div
class="sticky top-0 z-10 flex flex-shrink-0 space-x-2 overflow-x-auto bg-primary p-4"
>
<div class="inline-flex flex-1 space-x-2">
<div class="flex flex-1">
<div class="sm:inline-flex flex-1 sm:space-x-2 sm:space-y-0 space-y-2">
<div class="flex flex-1 flex-col space-y-1 sm:space-y-0 sm:flex-row">
<input
id="server"
v-model="server"
@ -19,28 +19,31 @@
"
@keyup.enter="isUrlValid ? toggleSSEConnection() : null"
/>
<label
for="event-type"
class="truncate border-b border-t border-divider bg-primaryLight px-4 py-2 font-semibold text-secondaryLight"
>
{{ t("sse.event_type") }}
</label>
<input
id="event-type"
v-model="eventType"
class="flex w-full flex-1 rounded-r border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
spellcheck="false"
:disabled="
connectionState === 'STARTED' || connectionState === 'STARTING'
"
@keyup.enter="isUrlValid ? toggleSSEConnection() : null"
/>
<div class="flex flex-1">
<label
for="event-type"
class="truncate border-b border-t border-divider bg-primaryLight px-4 py-2 font-semibold text-secondaryLight"
>
{{ t("sse.event_type") }}
</label>
<input
id="event-type"
v-model="eventType"
class="flex w-full flex-1 rounded-r border border-divider bg-primaryLight px-4 py-2 text-secondaryDark"
spellcheck="false"
:disabled="
connectionState === 'STARTED' ||
connectionState === 'STARTING'
"
@keyup.enter="isUrlValid ? toggleSSEConnection() : null"
/>
</div>
</div>
<HoppButtonPrimary
id="start"
:disabled="!isUrlValid"
name="start"
class="w-32"
class="sm:w-32 w-full"
:label="
connectionState === 'STARTING'
? t('action.starting')