Feat/icon tooltip (#2812)

* comp-rename Tooltip to InfoTip (fbu)

* fix: additional func InfoTip

* ToolHint component

* toolhint intg collectiontoolbar

* toolhint intg notifications

* toolhint intg sidebar

* chore: update infotip for path params

* chore: update infotip for path params
This commit is contained in:
Pragadesh-45 2024-08-27 18:36:59 +05:30 committed by GitHub
parent ee7f886c03
commit 600940226c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 136 additions and 70 deletions

View File

@ -1,6 +1,6 @@
import React, { useEffect } from 'react';
import { useFormik } from 'formik';
import Tooltip from 'components/Tooltip';
import InfoTip from 'components/InfoTip';
import StyledWrapper from './StyledWrapper';
import * as Yup from 'yup';
import toast from 'react-hot-toast';
@ -104,7 +104,7 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
<div className="mb-3 flex items-center">
<label className="settings-label flex items-center" htmlFor="enabled">
Config
<Tooltip
<InfoTip
text={`
<div>
<ul>
@ -114,7 +114,7 @@ const ProxySettings = ({ proxyConfig, onUpdate }) => {
</ul>
</div>
`}
tooltipId="request-var"
infotipId="request-var"
/>
</label>
<div className="flex items-center">

View File

@ -5,7 +5,7 @@ import { useDispatch } from 'react-redux';
import { useTheme } from 'providers/Theme';
import { saveFolderRoot } from 'providers/ReduxStore/slices/collections/actions';
import SingleLineEditor from 'components/SingleLineEditor';
import Tooltip from 'components/Tooltip';
import InfoTip from 'components/InfoTip';
import StyledWrapper from './StyledWrapper';
import toast from 'react-hot-toast';
import { variableNameRegex } from 'utils/common/regex';
@ -82,14 +82,14 @@ const VarsTable = ({ folder, collection, vars, varType }) => {
<td>
<div className="flex items-center">
<span>Value</span>
<Tooltip text="You can write any valid JS Template Literal here" tooltipId="request-var" />
<InfoTip text="You can write any valid JS Template Literal here" infotipId="request-var" />
</div>
</td>
) : (
<td>
<div className="flex items-center">
<span>Expr</span>
<Tooltip text="You can write any valid JS expression here" tooltipId="response-var" />
<InfoTip text="You can write any valid JS expression here" infotipId="response-var" />
</div>
</td>
)}

View File

@ -1,12 +1,12 @@
import React from 'react';
import { Tooltip as ReactTooltip } from 'react-tooltip';
import { Tooltip as ReactInfoTip } from 'react-tooltip';
const Tooltip = ({ text, tooltipId }) => {
const InfoTip = ({ text, infotipId }) => {
return (
<>
<svg
tabIndex="-1"
id={tooltipId}
id={infotipId}
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
@ -17,9 +17,9 @@ const Tooltip = ({ text, tooltipId }) => {
<path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z" />
<path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z" />
</svg>
<ReactTooltip anchorId={tooltipId} html={text} />
<ReactInfoTip anchorId={infotipId} html={text} />
</>
);
};
export default Tooltip;
export default InfoTip;

View File

@ -10,6 +10,8 @@ import {
} from 'providers/ReduxStore/slices/notifications';
import { useDispatch, useSelector } from 'react-redux';
import { humanizeDate, relativeDate } from 'utils/common';
import ToolHint from 'components/ToolHint';
import { useTheme } from 'providers/Theme';
const PAGE_SIZE = 5;
@ -20,6 +22,7 @@ const Notifications = () => {
const [showNotificationsModal, setShowNotificationsModal] = useState(false);
const [selectedNotification, setSelectedNotification] = useState(null);
const [pageNumber, setPageNumber] = useState(1);
const { storedTheme } = useTheme();
const notificationsStartIndex = (pageNumber - 1) * PAGE_SIZE;
const notificationsEndIndex = pageNumber * PAGE_SIZE;
@ -85,21 +88,22 @@ const Notifications = () => {
return (
<StyledWrapper>
<a
title="Notifications"
className="relative cursor-pointer"
onClick={() => {
dispatch(fetchNotifications());
setShowNotificationsModal(true);
}}
>
<IconBell
size={18}
strokeWidth={1.5}
className={`mr-2 hover:text-gray-700 ${unreadNotifications?.length > 0 ? 'bell' : ''}`}
/>
{unreadNotifications.length > 0 && (
<span className="notification-count text-xs">{unreadNotifications.length}</span>
)}
<ToolHint text="Notifications" toolhintId="Notifications" offset={8} >
<IconBell
size={18}
strokeWidth={1.5}
className={`mr-2 ${unreadNotifications?.length > 0 ? 'bell' : ''}`}
/>
{unreadNotifications.length > 0 && (
<span className="notification-count text-xs">{unreadNotifications.length}</span>
)}
</ToolHint>
</a>
{showNotificationsModal && (
@ -129,9 +133,8 @@ const Notifications = () => {
{notifications?.slice(notificationsStartIndex, notificationsEndIndex)?.map((notification) => (
<li
key={notification.id}
className={`p-4 flex flex-col justify-center ${
selectedNotification?.id == notification.id ? 'active' : notification.read ? 'read' : ''
}`}
className={`p-4 flex flex-col justify-center ${selectedNotification?.id == notification.id ? 'active' : notification.read ? 'read' : ''
}`}
onClick={handleNotificationItemClick(notification)}
>
<div className="notification-title w-full">{notification?.title}</div>
@ -141,9 +144,8 @@ const Notifications = () => {
</ul>
<div className="w-full pagination flex flex-row gap-4 justify-center p-2 items-center text-xs">
<button
className={`pl-2 pr-2 py-3 select-none ${
pageNumber <= 1 ? 'opacity-50' : 'text-link cursor-pointer hover:underline'
}`}
className={`pl-2 pr-2 py-3 select-none ${pageNumber <= 1 ? 'opacity-50' : 'text-link cursor-pointer hover:underline'
}`}
onClick={handlePrev}
>
{'Prev'}
@ -159,9 +161,8 @@ const Notifications = () => {
</div>
</div>
<button
className={`pl-2 pr-2 py-3 select-none ${
pageNumber == totalPages ? 'opacity-50' : 'text-link cursor-pointer hover:underline'
}`}
className={`pl-2 pr-2 py-3 select-none ${pageNumber == totalPages ? 'opacity-50' : 'text-link cursor-pointer hover:underline'
}`}
onClick={handleNext}
>
{'Next'}

View File

@ -1,7 +1,7 @@
import React from 'react';
import get from 'lodash/get';
import cloneDeep from 'lodash/cloneDeep';
import Tooltip from 'components/Tooltip';
import InfoTip from 'components/InfoTip';
import { IconTrash } from '@tabler/icons';
import { useDispatch } from 'react-redux';
import { useTheme } from 'providers/Theme';
@ -175,7 +175,7 @@ const QueryParams = ({ item, collection }) => {
</button>
<div className="mb-2 title text-xs flex items-stretch">
<span>Path</span>
<Tooltip
<InfoTip
text={`
<div>
Path variables are automatically added whenever the
@ -186,7 +186,7 @@ const QueryParams = ({ item, collection }) => {
</code>
</div>
`}
tooltipId="path-param-tooltip"
infotipId="path-param-InfoTip"
/>
</div>
<table>

View File

@ -33,18 +33,18 @@ const Wrapper = styled.div`
top: 1px;
}
.tooltip {
.infotip {
position: relative;
display: inline-block;
cursor: pointer;
}
.tooltip:hover .tooltiptext {
.infotip:hover .infotiptext {
visibility: visible;
opacity: 1;
}
.tooltiptext {
.infotiptext {
visibility: hidden;
width: auto;
background-color: ${(props) => props.theme.requestTabs.active.bg};
@ -62,7 +62,7 @@ const Wrapper = styled.div`
white-space: nowrap;
}
.tooltiptext::after {
.infotiptext::after {
content: '';
position: absolute;
top: 100%;

View File

@ -74,7 +74,7 @@ const QueryUrl = ({ item, collection, handleRun }) => {
/>
<div className="flex items-center h-full mr-2 cursor-pointer" id="send-request" onClick={handleRun}>
<div
className="tooltip mx-3"
className="infotip mr-3"
onClick={(e) => {
e.stopPropagation();
if (!item.draft) return;
@ -87,7 +87,7 @@ const QueryUrl = ({ item, collection, handleRun }) => {
size={22}
className={`${item.draft ? 'cursor-pointer' : 'cursor-default'}`}
/>
<span className="tooltiptext text-xs">
<span className="infotiptext text-xs">
Save <span className="shortcut">({saveShortcut})</span>
</span>
</div>

View File

@ -6,7 +6,7 @@ import { useTheme } from 'providers/Theme';
import { addVar, updateVar, deleteVar } from 'providers/ReduxStore/slices/collections';
import { sendRequest, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
import SingleLineEditor from 'components/SingleLineEditor';
import Tooltip from 'components/Tooltip';
import InfoTip from 'components/InfoTip';
import StyledWrapper from './StyledWrapper';
import toast from 'react-hot-toast';
import { variableNameRegex } from 'utils/common/regex';
@ -83,14 +83,14 @@ const VarsTable = ({ item, collection, vars, varType }) => {
<td>
<div className="flex items-center">
<span>Value</span>
<Tooltip text="You can write any valid JS Template Literal here" tooltipId="request-var" />
<InfoTip text="You can write any valid JS Template Literal here" infotipId="request-var" />
</div>
</td>
) : (
<td>
<div className="flex items-center">
<span>Expr</span>
<Tooltip text="You can write any valid JS expression here" tooltipId="response-var" />
<InfoTip text="You can write any valid JS expression here" infotipId="response-var" />
</div>
</td>
)}

View File

@ -2,4 +2,4 @@ import styled from 'styled-components';
const StyledWrapper = styled.div``;
export default StyledWrapper;
export default StyledWrapper;

View File

@ -4,6 +4,7 @@ import { IconFiles, IconRun, IconEye, IconSettings } from '@tabler/icons';
import EnvironmentSelector from 'components/Environments/EnvironmentSelector';
import { addTab } from 'providers/ReduxStore/slices/tabs';
import { useDispatch } from 'react-redux';
import ToolHint from 'components/ToolHint';
import StyledWrapper from './StyledWrapper';
import JsSandboxMode from 'components/SecuritySettings/JsSandboxMode';
@ -51,14 +52,20 @@ const CollectionToolBar = ({ collection }) => {
<span className="mr-2">
<JsSandboxMode collection={collection} />
</span>
<span className="mr-2">
<IconRun className="cursor-pointer" size={20} strokeWidth={1.5} onClick={handleRun} />
<span className="mr-3">
<ToolHint text="Runner" toolhintId="RunnnerToolhintId" place='bottom'>
<IconRun className="cursor-pointer" size={18} strokeWidth={1.5} onClick={handleRun} />
</ToolHint>
</span>
<span className="mr-3">
<IconEye className="cursor-pointer" size={18} strokeWidth={1.5} onClick={viewVariables} />
<ToolHint text="Variables" toolhintId="VariablesToolhintId">
<IconEye className="cursor-pointer" size={18} strokeWidth={1.5} onClick={viewVariables} />
</ToolHint>
</span>
<span className="mr-3">
<IconSettings className="cursor-pointer" size={18} strokeWidth={1.5} onClick={viewCollectionSettings} />
<ToolHint text="Collection Settings" toolhintId="CollectionSettingsToolhintId">
<IconSettings className="cursor-pointer" size={18} strokeWidth={1.5} onClick={viewCollectionSettings} />
</ToolHint>
</span>
<EnvironmentSelector collection={collection} />
</div>

View File

@ -2,7 +2,7 @@ import { IconFilter, IconX } from '@tabler/icons';
import React, { useMemo } from 'react';
import { useRef } from 'react';
import { useState } from 'react';
import { Tooltip as ReactTooltip } from 'react-tooltip';
import { Tooltip as ReactInfotip } from 'react-tooltip';
const QueryResultFilter = ({ filter, onChange, mode }) => {
const inputRef = useRef(null);
@ -19,7 +19,7 @@ const QueryResultFilter = ({ filter, onChange, mode }) => {
}
};
const tooltipText = useMemo(() => {
const infotipText = useMemo(() => {
if (mode.includes('json')) {
return 'Filter with JSONPath';
}
@ -49,7 +49,7 @@ const QueryResultFilter = ({ filter, onChange, mode }) => {
'response-filter absolute bottom-2 w-full justify-end right-0 flex flex-row items-center gap-2 py-4 px-2 pointer-events-none'
}
>
{tooltipText && !isExpanded && <ReactTooltip anchorId={'request-filter-icon'} html={tooltipText} />}
{infotipText && !isExpanded && <ReactInfotip anchorId={'request-filter-icon'} html={infotipText} />}
<input
ref={inputRef}
type="text"

View File

@ -5,7 +5,7 @@ import * as Yup from 'yup';
import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions';
import { cloneCollection } from 'providers/ReduxStore/slices/collections/actions';
import toast from 'react-hot-toast';
import Tooltip from 'components/Tooltip';
import InfoTip from 'components/InfoTip';
import Modal from 'components/Modal';
const CloneCollection = ({ onClose, collection }) => {
@ -126,9 +126,9 @@ const CloneCollection = ({ onClose, collection }) => {
<label htmlFor="collection-folder-name" className="flex items-center mt-3">
<span className="font-semibold">Folder Name</span>
<Tooltip
<InfoTip
text="This folder will be created under the selected location"
tooltipId="collection-folder-name-tooltip"
infotipId="collection-folder-name-infotip"
/>
</label>
<input

View File

@ -5,7 +5,7 @@ import * as Yup from 'yup';
import { browseDirectory } from 'providers/ReduxStore/slices/collections/actions';
import { createCollection } from 'providers/ReduxStore/slices/collections/actions';
import toast from 'react-hot-toast';
import Tooltip from 'components/Tooltip';
import InfoTip from 'components/InfoTip';
import Modal from 'components/Modal';
const CreateCollection = ({ onClose }) => {
@ -119,9 +119,9 @@ const CreateCollection = ({ onClose }) => {
<label htmlFor="collection-folder-name" className="flex items-center mt-3">
<span className="font-semibold">Folder Name</span>
<Tooltip
<InfoTip
text="This folder will be created under the selected location"
tooltipId="collection-folder-name-tooltip"
infotipId="collection-folder-name-infotip"
/>
</label>
<input

View File

@ -4,6 +4,7 @@ import StyledWrapper from './StyledWrapper';
import GitHubButton from 'react-github-btn';
import Preferences from 'components/Preferences';
import Cookies from 'components/Cookies';
import ToolHint from 'components/ToolHint';
import GoldenEdition from './GoldenEdition';
import { useState, useEffect } from 'react';
@ -95,28 +96,30 @@ const Sidebar = () => {
<div className="footer flex px-1 py-2 absolute bottom-0 left-0 right-0 items-center select-none">
<div className="flex items-center ml-1 text-xs ">
<a
title="Preferences"
className="mr-2 cursor-pointer hover:text-gray-700"
onClick={() => dispatch(showPreferences(true))}
>
<IconSettings size={18} strokeWidth={1.5} />
<a className="mr-2 cursor-pointer" onClick={() => dispatch(showPreferences(true))}>
<ToolHint text="Preferences" toolhintId="Preferences" effect='float' place='top-start' offset={8}>
<IconSettings size={18} strokeWidth={1.5} />
</ToolHint>
</a>
<a
title="Cookies"
className="mr-2 cursor-pointer hover:text-gray-700"
className="mr-2 cursor-pointer"
onClick={() => setCookiesOpen(true)}
>
<IconCookie size={18} strokeWidth={1.5} />
<ToolHint text="Cookies" toolhintId="Cookies" offset={8}>
<IconCookie size={18} strokeWidth={1.5} />
</ToolHint>
</a>
<a
title="Golden Edition"
className="mr-2 cursor-pointer hover:text-gray-700"
className="mr-2 cursor-pointer"
onClick={() => setGoldenEditonOpen(true)}
>
<IconHeart size={18} strokeWidth={1.5} />
<ToolHint text="Golden Edition" toolhintId="Golden Edition" offset={8} >
<IconHeart size={18} strokeWidth={1.5} />
</ToolHint>
</a>
<a>
<Notifications />
</a>
<Notifications />
</div>
<div className="pl-1" style={{ position: 'relative', top: '3px' }}>
{/* This will get moved to home page */}
@ -126,7 +129,7 @@ const Sidebar = () => {
data-show-count="true"
aria-label="Star usebruno/bruno on GitHub"
>
Star
Star
</GitHubButton> */}
</div>
<div className="flex flex-grow items-center justify-end text-xs mr-2">v1.26.2</div>
@ -137,7 +140,7 @@ const Sidebar = () => {
<div className="absolute drag-sidebar h-full" onMouseDown={handleDragbarMouseDown}>
<div className="drag-request-border" />
</div>
</StyledWrapper>
</StyledWrapper >
);
};

View File

@ -0,0 +1,8 @@
import styled from 'styled-components';
const Wrapper = styled.div`
background-color: ${(props) => props.theme.sidebar.badge};
color: ${(props) => props.theme.text};
`;
export default Wrapper;

View File

@ -0,0 +1,47 @@
import React from 'react';
import { Tooltip as ReactToolHint } from 'react-tooltip';
import StyledWrapper from './StyledWrapper';
import { useTheme } from 'providers/Theme';
const ToolHint = ({
text,
toolhintId,
children,
tooltipStyle = {},
place = 'top',
offset,
theme = null
}) => {
const { theme: contextTheme } = useTheme();
const appliedTheme = theme || contextTheme;
const toolhintBackgroundColor = appliedTheme?.sidebar.badge.bg || 'black';
const toolhintTextColor = appliedTheme?.text || 'white';
const combinedToolhintStyle = {
...tooltipStyle,
fontSize: '0.75rem',
padding: '0.25rem 0.5rem',
backgroundColor: toolhintBackgroundColor,
color: toolhintTextColor
};
return (
<>
<span id={toolhintId}>{children}</span>
<StyledWrapper theme={appliedTheme}>
<ReactToolHint
anchorId={toolhintId}
html={text}
className="toolhint"
offset={offset}
place={place}
noArrow={true}
style={combinedToolhintStyle}
/>
</StyledWrapper>
</>
);
};
export default ToolHint;