mirror of
https://github.com/Kong/insomnia.git
synced 2026-10-24 07:39:10 -04:00
Reduce AppBar sizing and add Project Name to breadcrumbs (#4159)
This commit is contained in:
1 parent
6c34d9088e
commit
5c02273757
12 files changed
+165
-128
No files matched your search
@@ -6,7 +6,6 @@ export interface StringInfo {
|
||||
type StringId =
|
||||
| 'collection'
|
||||
| 'document'
|
||||
| 'home'
|
||||
| 'project'
|
||||
| 'workspace'
|
||||
| 'defaultProject'
|
||||
@@ -23,10 +22,6 @@ export const strings: Record<StringId, StringInfo> = {
|
||||
singular: 'Document',
|
||||
plural: 'Documents',
|
||||
},
|
||||
home: {
|
||||
singular: 'Dashboard',
|
||||
plural: 'Dashboards',
|
||||
},
|
||||
project: {
|
||||
singular: 'Project',
|
||||
plural: 'Projects',
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { Breadcrumb, BreadcrumbProps, Header as _Header } from 'insomnia-components';
|
||||
import React, { FC, Fragment, ReactNode } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import coreLogo from '../images/insomnia-core-logo.png';
|
||||
import { SettingsButton } from './buttons/settings-button';
|
||||
import { AccountDropdownButton } from './dropdowns/account-dropdown';
|
||||
|
||||
const Header = styled(_Header)({
|
||||
whiteSpace: 'nowrap',
|
||||
});
|
||||
|
||||
const RightWrapper = styled.div({
|
||||
transformOrigin: 'right',
|
||||
transform: 'scale(0.85)',
|
||||
display: 'flex',
|
||||
justifySelf: 'flex-end',
|
||||
alignItems: 'center',
|
||||
'& .tooltip': {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
export interface AppHeaderProps {
|
||||
breadcrumbProps: BreadcrumbProps;
|
||||
gridCenter?: ReactNode;
|
||||
gridRight?: ReactNode;
|
||||
}
|
||||
|
||||
export const AppHeader: FC<AppHeaderProps> = ({
|
||||
breadcrumbProps,
|
||||
gridCenter,
|
||||
gridRight,
|
||||
}) => {
|
||||
return (
|
||||
<Header
|
||||
gridLeft={(
|
||||
<Fragment>
|
||||
<img src={coreLogo} alt="Insomnia" width="28" height="28" />
|
||||
<Breadcrumb {...breadcrumbProps} />
|
||||
</Fragment>
|
||||
)}
|
||||
gridCenter={gridCenter}
|
||||
gridRight={(
|
||||
<RightWrapper>
|
||||
{gridRight}
|
||||
<SettingsButton />
|
||||
<AccountDropdownButton />
|
||||
</RightWrapper>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -1,36 +1,35 @@
|
||||
import { CircleButton, SvgIcon, Tooltip } from 'insomnia-components';
|
||||
import React, { FunctionComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { useSelector } from 'react-redux';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import { hotKeyRefs } from '../../../common/hotkeys';
|
||||
import type { Settings } from '../../../models/settings';
|
||||
import { selectSettings } from '../../redux/selectors';
|
||||
import { Hotkey } from '../hotkey';
|
||||
import { showSettingsModal } from '../modals/settings-modal';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
settings: Settings;
|
||||
}
|
||||
const Wrapper = styled.div({
|
||||
marginLeft: 'var(--padding-md)',
|
||||
});
|
||||
|
||||
const SettingsButton: FunctionComponent<Props> = ({ className, settings }) => (
|
||||
<Tooltip
|
||||
delay={1000}
|
||||
position="bottom"
|
||||
message={
|
||||
<>
|
||||
Preferences (
|
||||
<Hotkey keyBindings={settings.hotKeyRegistry[hotKeyRefs.PREFERENCES_SHOW_GENERAL.id]} />)
|
||||
</>
|
||||
}
|
||||
>
|
||||
<CircleButton className={className} onClick={showSettingsModal}>
|
||||
<SvgIcon icon="gear" />
|
||||
</CircleButton>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
export default connect((state, props) => ({
|
||||
// @ts-expect-error -- TSCONVERSION
|
||||
settings: selectSettings(state, props),
|
||||
}))(SettingsButton);
|
||||
export const SettingsButton: FunctionComponent = () => {
|
||||
const { hotKeyRegistry } = useSelector(selectSettings);
|
||||
return (
|
||||
<Wrapper>
|
||||
<Tooltip
|
||||
delay={1000}
|
||||
position="bottom"
|
||||
message={
|
||||
<>
|
||||
Preferences (
|
||||
<Hotkey keyBindings={hotKeyRegistry[hotKeyRefs.PREFERENCES_SHOW_GENERAL.id]} />)
|
||||
</>
|
||||
}
|
||||
>
|
||||
<CircleButton onClick={showSettingsModal}>
|
||||
<SvgIcon icon="gear" />
|
||||
</CircleButton>
|
||||
</Tooltip>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
@@ -1,3 +1,4 @@
|
||||
import classNames from 'classnames';
|
||||
import { CircleButton, SvgIcon, Tooltip } from 'insomnia-components';
|
||||
import React, { Fragment, FunctionComponent } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
@@ -12,24 +13,30 @@ import { Link } from '../base/link';
|
||||
import { PromptButton } from '../base/prompt-button';
|
||||
import { showLoginModal } from '../modals/login-modal';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
const Wrapper = styled.div({
|
||||
display: 'flex',
|
||||
marginLeft: 'var(--padding-md)',
|
||||
});
|
||||
|
||||
interface StyledIconProps {
|
||||
faIcon: string;
|
||||
}
|
||||
|
||||
const StyledIconContainer = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: var(--padding-xs);
|
||||
padding-right: var(--padding-md);
|
||||
i {
|
||||
width: unset !important;
|
||||
}
|
||||
`;
|
||||
const StyledIcon = styled.i.attrs<StyledIconProps>(props => ({
|
||||
className: classNames('fa', props.faIcon),
|
||||
}))<StyledIconProps>({
|
||||
marginleft: 'var(--padding-md)',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
paddingLeft: 'var(--padding-xs)',
|
||||
paddingRight: 'var(--padding-md)',
|
||||
width: 'unset !important',
|
||||
});
|
||||
|
||||
export const AccountDropdown: FunctionComponent<Props> = ({ className }) => {
|
||||
export const AccountDropdownButton: FunctionComponent = () => {
|
||||
const { disablePaidFeatureAds } = useSelector(selectSettings);
|
||||
return (
|
||||
<div className={className}>
|
||||
<Wrapper>
|
||||
<Dropdown>
|
||||
<DropdownButton noWrap>
|
||||
<Tooltip delay={1000} position="bottom" message="Account">
|
||||
@@ -45,18 +52,12 @@ export const AccountDropdown: FunctionComponent<Props> = ({ className }) => {
|
||||
buttonClass={PromptButton}
|
||||
onClick={session.logout}
|
||||
>
|
||||
<StyledIconContainer>
|
||||
<i className="fa fa-sign-out" />
|
||||
</StyledIconContainer>
|
||||
Logout
|
||||
<StyledIcon faIcon="fa-sign-out" />Logout
|
||||
</DropdownItem>
|
||||
) : (
|
||||
<Fragment>
|
||||
<DropdownItem key="login" onClick={showLoginModal}>
|
||||
<StyledIconContainer>
|
||||
<i className="fa fa-sign-in" />
|
||||
</StyledIconContainer>
|
||||
Log In
|
||||
<StyledIcon faIcon="fa-sign-in" />Log In
|
||||
</DropdownItem>
|
||||
{!disablePaidFeatureAds && (
|
||||
<DropdownItem
|
||||
@@ -66,16 +67,13 @@ export const AccountDropdown: FunctionComponent<Props> = ({ className }) => {
|
||||
href="https://insomnia.rest/pricing"
|
||||
button
|
||||
>
|
||||
<StyledIconContainer>
|
||||
<i className="fa fa-users" />
|
||||
</StyledIconContainer>{' '}
|
||||
Upgrade to Plus
|
||||
<StyledIcon faIcon="fa-users" />{' '}Upgrade to Plus
|
||||
<i className="fa fa-star surprise fa-outline" />
|
||||
</DropdownItem>
|
||||
)}
|
||||
</Fragment>
|
||||
)}
|
||||
</Dropdown>
|
||||
</div>
|
||||
</Wrapper>
|
||||
);
|
||||
};
|
||||
@@ -437,7 +437,7 @@ class UnconnectedSyncDropdown extends PureComponent<Props, State> {
|
||||
<i className="fa fa-code-fork space-right" />{' '}
|
||||
{initializing ? 'Initializing...' : currentBranch}
|
||||
</div>
|
||||
<div className="space-left">
|
||||
<div className="flex space-left">
|
||||
<Tooltip message={snapshotToolTipMsg} delay={800} position="bottom">
|
||||
<i
|
||||
className={classnames('fa fa-cube fa--fixed-width', {
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import { Breadcrumb, Header } from 'insomnia-components';
|
||||
import React, { Fragment, FunctionComponent, ReactNode, useCallback } from 'react';
|
||||
import React, { FunctionComponent, ReactNode, useCallback } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { ACTIVITY_HOME, GlobalActivity } from '../../common/constants';
|
||||
import { strings } from '../../common/strings';
|
||||
import { isDesign } from '../../models/workspace';
|
||||
import coreLogo from '../images/insomnia-core-logo.png';
|
||||
import { selectActiveProjectName } from '../redux/selectors';
|
||||
import { ActivityToggle } from './activity-toggle';
|
||||
import SettingsButton from './buttons/settings-button';
|
||||
import { AccountDropdown } from './dropdowns/account-dropdown';
|
||||
import { AppHeader } from './app-header';
|
||||
import { WorkspaceDropdown } from './dropdowns/workspace-dropdown';
|
||||
import type { WrapperProps } from './wrapper';
|
||||
|
||||
@@ -35,6 +33,7 @@ export const WorkspacePageHeader: FunctionComponent<Props> = ({
|
||||
() => handleActivityChange({ workspaceId: activeWorkspace?._id, nextActivity: ACTIVITY_HOME }),
|
||||
[activeWorkspace, handleActivityChange],
|
||||
);
|
||||
const activeProjectName = useSelector(selectActiveProjectName);
|
||||
|
||||
if (!activeWorkspace || !activeWorkspaceName || !activeApiSpec || !activity) {
|
||||
return null;
|
||||
@@ -42,6 +41,7 @@ export const WorkspacePageHeader: FunctionComponent<Props> = ({
|
||||
|
||||
const workspace = (
|
||||
<WorkspaceDropdown
|
||||
key="workspace-dd"
|
||||
activeEnvironment={activeEnvironment}
|
||||
activeWorkspace={activeWorkspace}
|
||||
activeWorkspaceName={activeWorkspaceName}
|
||||
@@ -53,19 +53,13 @@ export const WorkspacePageHeader: FunctionComponent<Props> = ({
|
||||
);
|
||||
|
||||
const crumbs = [
|
||||
{ id: 'home', node: strings.home.singular, onClick: homeCallback },
|
||||
{ id: 'workspace', node: <Fragment key="workspace-dd">{workspace}</Fragment> },
|
||||
{ id: 'project', node: activeProjectName, onClick: homeCallback },
|
||||
{ id: 'workspace', node: workspace },
|
||||
];
|
||||
|
||||
return (
|
||||
<Header
|
||||
className="app-header theme--app-header"
|
||||
gridLeft={
|
||||
<Fragment>
|
||||
<img src={coreLogo} alt="Insomnia" width="24" height="24" />
|
||||
<Breadcrumb crumbs={crumbs}/>
|
||||
</Fragment>
|
||||
}
|
||||
<AppHeader
|
||||
breadcrumbProps={{ crumbs }}
|
||||
gridCenter={
|
||||
isDesign(activeWorkspace) && (
|
||||
<ActivityToggle
|
||||
@@ -75,13 +69,7 @@ export const WorkspacePageHeader: FunctionComponent<Props> = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
gridRight={
|
||||
<>
|
||||
{gridRight}
|
||||
<SettingsButton className="margin-left" />
|
||||
<AccountDropdown className="margin-left" />
|
||||
</>
|
||||
}
|
||||
gridRight={gridRight}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -2,15 +2,13 @@ import 'swagger-ui-react/swagger-ui.css';
|
||||
|
||||
import { autoBindMethodsForReact } from 'class-autobind-decorator';
|
||||
import {
|
||||
Breadcrumb,
|
||||
Button,
|
||||
CardContainer,
|
||||
Dropdown,
|
||||
DropdownDivider,
|
||||
DropdownItem,
|
||||
Header,
|
||||
} from 'insomnia-components';
|
||||
import React, { Fragment, PureComponent } from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { unreachableCase } from 'ts-assert-unreachable';
|
||||
@@ -31,15 +29,13 @@ import { isDesign, Workspace, WorkspaceScopeKeys } from '../../models/workspace'
|
||||
import { WorkspaceMeta } from '../../models/workspace-meta';
|
||||
import { MemClient } from '../../sync/git/mem-client';
|
||||
import { initializeLocalBackendProjectAndMarkForSync } from '../../sync/vcs/initialize-backend-project';
|
||||
import coreLogo from '../images/insomnia-core-logo.png';
|
||||
import { cloneGitRepository } from '../redux/modules/git';
|
||||
import { setDashboardSortOrder } from '../redux/modules/global';
|
||||
import { ForceToWorkspace } from '../redux/modules/helpers';
|
||||
import { importClipBoard, importFile, importUri } from '../redux/modules/import';
|
||||
import { activateWorkspace, createWorkspace } from '../redux/modules/workspace';
|
||||
import { selectDashboardSortOrder } from '../redux/selectors';
|
||||
import SettingsButton from './buttons/settings-button';
|
||||
import { AccountDropdown } from './dropdowns/account-dropdown';
|
||||
import { AppHeader } from './app-header';
|
||||
import { DashboardSortDropdown } from './dropdowns/dashboard-sort-dropdown';
|
||||
import { ProjectDropdown } from './dropdowns/project-dropdown';
|
||||
import { RemoteWorkspacesDropdown } from './dropdowns/remote-workspaces-dropdown';
|
||||
@@ -352,30 +348,16 @@ class WrapperHome extends PureComponent<Props, State> {
|
||||
<PageLayout
|
||||
wrapperProps={this.props.wrapperProps}
|
||||
renderPageHeader={() => (
|
||||
<Header
|
||||
className="app-header theme--app-header"
|
||||
gridLeft={
|
||||
<Fragment>
|
||||
<img src={coreLogo} alt="Insomnia" width="24" height="24" />
|
||||
<Breadcrumb
|
||||
crumbs={[
|
||||
{
|
||||
id: 'project',
|
||||
node: <ProjectDropdown vcs={vcs || undefined} />,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
{isLoading ? (
|
||||
<i className="fa fa-refresh fa-spin space-left" />
|
||||
) : null}
|
||||
</Fragment>
|
||||
}
|
||||
gridRight={
|
||||
<>
|
||||
<SettingsButton className="margin-left" />
|
||||
<AccountDropdown className="margin-left" />
|
||||
</>
|
||||
}
|
||||
<AppHeader
|
||||
breadcrumbProps={{
|
||||
crumbs: [
|
||||
{
|
||||
id: 'project',
|
||||
node: <ProjectDropdown vcs={vcs || undefined} />,
|
||||
},
|
||||
],
|
||||
isLoading,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
renderPageBody={() => (
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
&:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
& button {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown__backdrop {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { FC, ReactNode } from 'react';
|
||||
import React, { FC, Fragment, ReactNode } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
interface CrumbProps {
|
||||
export interface CrumbProps {
|
||||
id: string;
|
||||
node: ReactNode;
|
||||
onClick?: React.MouseEventHandler<HTMLAnchorElement>;
|
||||
@@ -10,11 +10,11 @@ interface CrumbProps {
|
||||
export interface BreadcrumbProps {
|
||||
crumbs: CrumbProps[];
|
||||
className?: string;
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
const StyledBreadcrumb = styled.ul`
|
||||
font-size: var(--font-size-lg);
|
||||
font-weight: 600;
|
||||
font-size: var(--font-size-md);
|
||||
color: var(--color-font);
|
||||
grid-area: breadcrumbs;
|
||||
display: flex;
|
||||
@@ -24,7 +24,7 @@ const StyledBreadcrumb = styled.ul`
|
||||
a,
|
||||
a::before,
|
||||
li > ::before {
|
||||
color: var(--color-font);
|
||||
color: var(--color-font) !important;
|
||||
}
|
||||
|
||||
li {
|
||||
@@ -32,11 +32,20 @@ const StyledBreadcrumb = styled.ul`
|
||||
flex-direction: row;
|
||||
|
||||
a {
|
||||
font-weight: 400 !important;
|
||||
cursor: pointer;
|
||||
opacity: 0.5;
|
||||
&:hover {
|
||||
color: var(--color-font);
|
||||
opacity: 1;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
&::before {
|
||||
margin: 0 var(--padding-xs);
|
||||
font-weight: 300;
|
||||
opacity: 0.5;
|
||||
content: '/';
|
||||
}
|
||||
|
||||
@@ -50,8 +59,13 @@ const Crumb: FC<CrumbProps> = ({ id, node, onClick }) => <li key={id}>
|
||||
{onClick ? <a href="#" onClick={onClick}>{node}</a> : node}
|
||||
</li>;
|
||||
|
||||
export const Breadcrumb: FC<BreadcrumbProps> = ({ crumbs, className }) => (
|
||||
<StyledBreadcrumb className={className}>
|
||||
{crumbs.map(Crumb)}
|
||||
</StyledBreadcrumb>
|
||||
export const Breadcrumb: FC<BreadcrumbProps> = ({ crumbs, className, isLoading }) => (
|
||||
<Fragment>
|
||||
<StyledBreadcrumb className={className}>
|
||||
{crumbs.map(Crumb)}
|
||||
</StyledBreadcrumb>
|
||||
{isLoading ? (
|
||||
<i className="fa fa-refresh fa-spin space-left" />
|
||||
) : null}
|
||||
</Fragment>
|
||||
);
|
||||
@@ -1,3 +1,4 @@
|
||||
import classNames from 'classnames';
|
||||
import React, { FC, memo, ReactNode } from 'react';
|
||||
import styled from 'styled-components';
|
||||
|
||||
@@ -10,7 +11,7 @@ export interface HeaderProps {
|
||||
|
||||
const StyledHeader = styled.div`
|
||||
border-bottom: 1px solid var(--hl-md);
|
||||
padding: var(--padding-md);
|
||||
padding: var(--padding-xxs) var(--padding-sm);
|
||||
display: grid;
|
||||
grid-template-columns: 2fr 1.5fr 2fr;
|
||||
grid-template-rows: 1fr;
|
||||
@@ -37,7 +38,7 @@ const StyledHeader = styled.div`
|
||||
`;
|
||||
|
||||
export const Header: FC<HeaderProps> = memo(({ className, gridLeft, gridCenter, gridRight }) => (
|
||||
<StyledHeader className={className}>
|
||||
<StyledHeader className={classNames('app-header theme--app-header', className)}>
|
||||
<div className="header_left">{gridLeft}</div>
|
||||
<div className="header_center">{gridCenter}</div>
|
||||
<div className="header_right">{gridRight}</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ export * from './dropdown';
|
||||
export * from './sidebar';
|
||||
export * from './list-group';
|
||||
|
||||
export { Breadcrumb, BreadcrumbProps } from './breadcrumb';
|
||||
export { Breadcrumb, BreadcrumbProps, CrumbProps } from './breadcrumb';
|
||||
export { CardContainer } from './card-container';
|
||||
export { Card, CardProps } from './card';
|
||||
export { Header, HeaderProps } from './header';
|
||||
|
||||
@@ -5,12 +5,15 @@ import type { RadioButtonGroupProps } from './radio-button-group';
|
||||
import { RadioButtonGroup } from './radio-button-group';
|
||||
|
||||
const ThemedButtonGroup = styled(RadioButtonGroup)<RadioButtonGroupProps>`
|
||||
font-weight: bold;
|
||||
font-weight: 500;
|
||||
background: var(--hl-xs);
|
||||
color: var(--color-font);
|
||||
border: 0;
|
||||
border-radius: 100px;
|
||||
align-content: space-evenly;
|
||||
padding: var(--padding-xxs);
|
||||
transform: scale(0.9);
|
||||
transformOrigin: 'center';
|
||||
|
||||
label {
|
||||
padding: 0;
|
||||
@@ -18,17 +21,16 @@ const ThemedButtonGroup = styled(RadioButtonGroup)<RadioButtonGroupProps>`
|
||||
|
||||
span {
|
||||
text-transform: uppercase;
|
||||
padding: var(--padding-xxs) var(--padding-md);
|
||||
padding: var(--padding-xs) var(--padding-xxs);
|
||||
color: var(--hl);
|
||||
background: transparent;
|
||||
font-size: var(--font-size-sm);
|
||||
font-size: var(--font-size-xs);
|
||||
margin: 0 auto;
|
||||
min-width: 4rem;
|
||||
}
|
||||
|
||||
input:checked + span {
|
||||
color: var(--color-font);
|
||||
text-shadow: 0 1px rgba(255, 255, 255, 0.25);
|
||||
background: var(--color-bg);
|
||||
}
|
||||
`;
|
||||
|
||||
Reference in new issue
Block a user