UI/UX and tweaks to Markdown Descriptions (#279)

* Styles and editor done for requests

* Add description markdown to WOrkspace settings

* Show file icon beside request with description

* Add tracking
This commit is contained in:
Gregory Schier
2017-06-01 15:58:09 -07:00
committed by GitHub
parent eb94f430f0
commit e7bc8bb860
17 changed files with 534 additions and 175 deletions

View File

@@ -1,7 +1,8 @@
import uuid from 'uuid';
import {parse as urlParse, format as urlFormat} from 'url';
import {DEBOUNCE_MILLIS} from './constants';
import {DEBOUNCE_MILLIS, getAppVersion, isDevelopment} from './constants';
import * as querystring from './querystring';
import {shell} from 'electron';
const URL_PATH_CHARACTER_WHITELIST = '+,;@=:';
@@ -257,3 +258,15 @@ export function preventDefault (e) {
export function stopPropagation (e) {
e.stopPropagation();
}
export function clickLink (href) {
if (href.match(/^http/i)) {
const appName = isDevelopment() ? 'Insomnia Dev' : 'Insomnia';
const qs = `utm_source=${appName}&utm_medium=app&utm_campaign=v${getAppVersion()}`;
const attributedHref = querystring.joinUrl(href, qs);
shell.openExternal(attributedHref);
} else {
// Don't modify non-http urls
shell.openExternal(href);
}
}

View File

@@ -1,9 +1,7 @@
import React, {PureComponent, PropTypes} from 'react';
import React, {PropTypes, PureComponent} from 'react';
import autobind from 'autobind-decorator';
import {shell} from 'electron';
import {trackEvent} from '../../../analytics/index';
import {getAppVersion, isDevelopment} from '../../../common/constants';
import * as querystring from '../../../common/querystring';
import * as misc from '../../../common/misc';
@autobind
class Link extends PureComponent {
@@ -13,17 +11,7 @@ class Link extends PureComponent {
// Also call onClick that was passed to us if there was one
onClick && onClick(e);
if (href.match(/^http/i)) {
const appName = isDevelopment() ? 'Insomnia Dev' : 'Insomnia';
const qs = `utm_source=${appName}&utm_medium=app&utm_campaign=v${getAppVersion()}`;
const attributedHref = querystring.joinUrl(href, qs);
shell.openExternal(attributedHref);
} else {
// Don't modify non-http urls
shell.openExternal(href);
}
misc.clickLink(href);
trackEvent('Link', 'Click', href);
}

View File

@@ -339,7 +339,8 @@ class CodeEditor extends PureComponent {
hideScrollbars,
noStyleActiveLine,
noLint,
indentSize
indentSize,
dynamicHeight
} = this.props;
let mode;
@@ -410,6 +411,10 @@ class CodeEditor extends PureComponent {
};
}
if (dynamicHeight) {
options.viewportMargin = Infinity;
}
// Strip of charset if there is one
const cm = this.codeMirror;
Object.keys(options).map(key => {
@@ -558,11 +563,13 @@ class CodeEditor extends PureComponent {
onMouseLeave,
onClick,
className,
dynamicHeight,
style
} = this.props;
const classes = classnames(className, {
'editor': true,
'editor--dynamic-height': dynamicHeight,
'editor--readonly': readOnly
});
@@ -673,7 +680,8 @@ CodeEditor.propTypes = {
readOnly: PropTypes.bool,
filter: PropTypes.string,
singleLine: PropTypes.bool,
debounceMillis: PropTypes.number
debounceMillis: PropTypes.number,
dynamicHeight: PropTypes.bool
};
export default CodeEditor;

View File

@@ -2,9 +2,7 @@ import React, {PropTypes, PureComponent} from 'react';
import autobind from 'autobind-decorator';
import PromptButton from '../base/prompt-button';
import {Dropdown, DropdownButton, DropdownHint, DropdownItem} from '../base/dropdown';
import RequestSettingsModal from '../modals/request-settings-modal';
import * as models from '../../../models';
import {showModal} from '../modals/index';
import {trackEvent} from '../../../analytics/index';
import {DropdownDivider} from '../base/dropdown/index';
@@ -25,10 +23,6 @@ class RequestActionsDropdown extends PureComponent {
trackEvent('Request', 'Generate Code', 'Request Action');
}
_handleShowRequestSettings () {
showModal(RequestSettingsModal, this.props.request);
}
_handleRemove () {
const {request} = this.props;
models.request.remove(request);
@@ -42,6 +36,7 @@ class RequestActionsDropdown extends PureComponent {
render () {
const {
request, // eslint-disable-line no-unused-vars
handleShowSettings,
...other
} = this.props;
@@ -63,7 +58,7 @@ class RequestActionsDropdown extends PureComponent {
<DropdownDivider/>
<DropdownItem onClick={this._handleShowRequestSettings}>
<DropdownItem onClick={handleShowSettings}>
<i className="fa fa-wrench"/> Settings
<DropdownHint alt shift char=","/>
</DropdownItem>
@@ -75,6 +70,7 @@ class RequestActionsDropdown extends PureComponent {
RequestActionsDropdown.propTypes = {
handleDuplicateRequest: PropTypes.func.isRequired,
handleGenerateCode: PropTypes.func.isRequired,
handleShowSettings: PropTypes.func.isRequired,
request: PropTypes.object.isRequired
};

View File

@@ -0,0 +1,165 @@
import React, {PropTypes, PureComponent} from 'react';
import ReactDOM from 'react-dom';
import autobind from 'autobind-decorator';
import classnames from 'classnames';
import marked from 'marked';
import highlight from 'highlight.js';
import {Tab, TabList, TabPanel, Tabs} from 'react-tabs';
import {trackEvent} from '../../analytics';
import Button from './base/button';
import CodeEditor from './codemirror/code-editor';
import * as misc from '../../common/misc';
@autobind
class MarkdownEditor extends PureComponent {
constructor (props) {
super(props);
this.state = {
markdown: props.defaultValue,
compiled: ''
};
}
_trackTab (name) {
trackEvent('Request', 'Markdown Editor Tab', name);
}
_handleChange (markdown) {
this.props.onChange(markdown);
this._compileMarkdown(markdown);
}
async _compileMarkdown (markdown) {
const compiled = marked(await this.props.handleRender(markdown));
this.setState({markdown, compiled});
}
_setPreviewRef (n) {
this._preview = n;
}
_highlightCodeBlocks () {
if (!this._preview) {
return;
}
const el = ReactDOM.findDOMNode(this._preview);
for (const block of el.querySelectorAll('pre > code')) {
highlight.highlightBlock(block);
}
for (const a of el.querySelectorAll('a')) {
a.addEventListener('click', e => {
e.preventDefault();
misc.clickLink(e.target.getAttribute('href'));
});
}
}
componentWillMount () {
this._compileMarkdown(this.state.markdown);
}
componentDidUpdate () {
this._highlightCodeBlocks();
}
componentDidMount () {
marked.setOptions({
renderer: new marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
smartLists: true,
smartypants: false
});
this._highlightCodeBlocks();
}
render () {
const {
fontSize,
lineWrapping,
indentSize,
keyMap,
placeholder,
defaultPreviewMode,
className,
handleRender,
handleGetRenderContext
} = this.props;
const {markdown, compiled} = this.state;
return (
<Tabs className={classnames('markdown-editor', 'outlined', className)}
forceRenderTabPanel
selectedIndex={defaultPreviewMode ? 1 : 0}>
<TabList>
<Tab>
<Button onClick={this._trackTab} value="Write">
Write
</Button>
</Tab>
<Tab>
<Button onClick={this._trackTab} value="Preview">
Preview
</Button>
</Tab>
</TabList>
<TabPanel className="markdown-editor__edit">
<div className="form-control form-control--outlined">
<CodeEditor
hideGutters
hideLineNumbers
dynamicHeight
manualPrettify
noStyleActiveLine
mode="text/plain"
placeholder={placeholder}
debounceMillis={300}
keyMap={keyMap}
fontSize={fontSize}
lineWrapping={lineWrapping}
indentSize={indentSize}
defaultValue={markdown}
render={handleRender}
getRenderContext={handleGetRenderContext}
onChange={this._handleChange}
/>
</div>
<div className="txt-sm italic faint">
Styling with Markdown is supported
</div>
</TabPanel>
<TabPanel>
<div className="markdown-editor__preview" ref={this._setPreviewRef}
dangerouslySetInnerHTML={{__html: compiled}}>
{/* Set from above */}
</div>
</TabPanel>
</Tabs>
);
}
}
MarkdownEditor.propTypes = {
// Required
onChange: PropTypes.func.isRequired,
defaultValue: PropTypes.string.isRequired,
fontSize: PropTypes.number.isRequired,
indentSize: PropTypes.number.isRequired,
keyMap: PropTypes.string.isRequired,
lineWrapping: PropTypes.bool.isRequired,
handleRender: PropTypes.func.isRequired,
handleGetRenderContext: PropTypes.func.isRequired,
// Optional
placeholder: PropTypes.string,
defaultPreviewMode: PropTypes.bool,
className: PropTypes.string
};
export default MarkdownEditor;

View File

@@ -1,74 +0,0 @@
import React, {PropTypes, PureComponent} from 'react';
import autobind from 'autobind-decorator';
import {Tab, TabList, TabPanel, Tabs} from 'react-tabs';
import {trackEvent} from '../../analytics';
import Button from './base/button';
import CodeEditor from './codemirror/code-editor';
import marked from 'marked';
marked.setOptions({
renderer: new marked.Renderer(),
gfm: true,
tables: true,
breaks: false,
pedantic: false,
smartLists: true,
smartypants: false
});
@autobind
class Markdown extends PureComponent {
constructor (props) {
super(props);
this._defaultValue = props.defaultValue;
this._compiled = marked(this._defaultValue);
}
_trackTab (name) {
trackEvent('Request', 'Markdown Editor Tab', name);
}
_handleChange (value) {
this._compiled = marked(value);
this.props.onChange(value);
}
render () {
return (
<Tabs>
<TabList>
<Tab>
<Button onClick={this._trackTab} value="Write">
Write
</Button>
</Tab>
<Tab>
<Button onClick={this._trackTab} value="Preview">
Preview
</Button>
</Tab>
</TabList>
<TabPanel>
<CodeEditor
manualPrettify
mode="text/x-markdown"
placeholder="..."
defaultValue={this._defaultValue}
onChange={this._handleChange}
/>
</TabPanel>
<TabPanel>
<div className="pad" dangerouslySetInnerHTML={{__html: this._compiled}}></div>
</TabPanel>
</Tabs>
);
}
}
Markdown.propTypes = {
// Required
onChange: PropTypes.func.isRequired,
defaultValue: PropTypes.string.isRequired
};
export default Markdown;

View File

@@ -1,6 +1,5 @@
import React, {PureComponent} from 'react';
import React, {PropTypes, PureComponent} from 'react';
import autobind from 'autobind-decorator';
import Link from '../base/link';
import Modal from '../base/modal';
import ModalBody from '../base/modal-body';
import ModalHeader from '../base/modal-header';
@@ -8,14 +7,16 @@ import HelpTooltip from '../help-tooltip';
import * as models from '../../../models';
import {trackEvent} from '../../../analytics/index';
import DebouncedInput from '../base/debounced-input';
import Markdown from '../markdown';
import MarkdownEditor from '../markdown-editor';
@autobind
class RequestSettingsModal extends PureComponent {
constructor (props) {
super(props);
this.state = {
request: null
request: null,
showDescription: false,
defaultPreviewMode: false
};
}
@@ -38,12 +39,22 @@ class RequestSettingsModal extends PureComponent {
async _handleDescriptionChange (description) {
const request = await models.request.update(this.state.request, {description});
this.setState({request});
this.setState({request, defaultPreviewMode: false});
}
_handleAddDescription () {
trackEvent('Request', 'Add Description');
this.setState({showDescription: true});
}
show (request) {
this.modal.show();
this.setState({request});
const hasDescription = !!request.description;
this.setState({
request,
showDescription: hasDescription,
defaultPreviewMode: hasDescription
});
}
hide () {
@@ -62,10 +73,21 @@ class RequestSettingsModal extends PureComponent {
}
renderModalBody (request) {
const {
editorLineWrapping,
editorFontSize,
editorIndentSize,
editorKeyMap,
handleRender,
handleGetRenderContext
} = this.props;
const {showDescription, defaultPreviewMode} = this.state;
return (
<div>
<div className="form-control form-control--outlined">
<label>Request Name
<label>Name
{' '}
<span className="txt-sm faint italic">
(also rename by double-clicking in sidebar)
@@ -79,22 +101,27 @@ class RequestSettingsModal extends PureComponent {
/>
</label>
</div>
<div className="form-control form-control--outlined">
<label>Description
{' '}
<span className="txt-sm faint italic">
(supports <Link href="https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet"> markdown </Link>)
</span>
<div className="input input--area">
<Markdown className="input"
defaultValue={request.description}
onChange={this._handleDescriptionChange}
/>
</div>
</label>
</div>
<div className="pad-top-sm">
<h2 className="txt-lg">Cookie Handling</h2>
{showDescription ? (
<MarkdownEditor
className="margin-top"
defaultPreviewMode={defaultPreviewMode}
fontSize={editorFontSize}
indentSize={editorIndentSize}
keyMap={editorKeyMap}
placeholder="Write a description"
lineWrapping={editorLineWrapping}
handleRender={handleRender}
handleGetRenderContext={handleGetRenderContext}
defaultValue={request.description}
onChange={this._handleDescriptionChange}
/>
) : (
<button onClick={this._handleAddDescription}
className="btn btn--outlined btn--super-duper-compact">
Add Description
</button>
)}
<div className="pad-top">
<div className="form-control form-control--thin">
<label>Send cookies automatically
{this.renderCheckboxInput('settingSendCookies')}
@@ -105,9 +132,6 @@ class RequestSettingsModal extends PureComponent {
{this.renderCheckboxInput('settingStoreCookies')}
</label>
</div>
</div>
<div className="pad-top-sm">
<h2 className="txt-lg">Advanced Settings</h2>
<div className="form-control form-control--thin">
<label>Automatically encode special characters in URL
{this.renderCheckboxInput('settingEncodeUrl')}
@@ -147,6 +171,13 @@ class RequestSettingsModal extends PureComponent {
}
}
RequestSettingsModal.propTypes = {};
RequestSettingsModal.propTypes = {
editorFontSize: PropTypes.number.isRequired,
editorIndentSize: PropTypes.number.isRequired,
editorKeyMap: PropTypes.string.isRequired,
editorLineWrapping: PropTypes.bool.isRequired,
handleRender: PropTypes.func.isRequired,
handleGetRenderContext: PropTypes.func.isRequired
};
export default RequestSettingsModal;

View File

@@ -9,6 +9,7 @@ import ModalHeader from '../base/modal-header';
import PromptButton from '../base/prompt-button';
import * as models from '../../../models/index';
import {trackEvent} from '../../../analytics/index';
import MarkdownEditor from '../markdown-editor';
@autobind
class WorkspaceSettingsModal extends PureComponent {
@@ -21,7 +22,9 @@ class WorkspaceSettingsModal extends PureComponent {
keyPath: '',
pfxPath: '',
host: '',
passphrase: ''
passphrase: '',
showDescription: false,
defaultPreviewMode: false
};
}
@@ -29,6 +32,11 @@ class WorkspaceSettingsModal extends PureComponent {
models.workspace.update(this.props.workspace, patch);
}
_handleAddDescription () {
this.setState({showDescription: true});
trackEvent('Workspace', 'Add Description');
}
_handleSetModalRef (n) {
this.modal = n;
}
@@ -48,6 +56,10 @@ class WorkspaceSettingsModal extends PureComponent {
_handleDescriptionChange (description) {
this._workspaceUpdate({description});
if (this.state.defaultPreviewMode !== false) {
this.setState({defaultPreviewMode: false});
}
}
_handleCreateHostChange (e) {
@@ -126,13 +138,16 @@ class WorkspaceSettingsModal extends PureComponent {
show () {
this.modal.show();
const hasDescription = !!this.props.workspace.description;
this.setState({
showAddCertificateForm: false,
crtPath: '',
keyPath: '',
pfxPath: '',
host: '',
passphrase: ''
passphrase: '',
showDescription: hasDescription,
defaultPreviewMode: hasDescription
});
}
@@ -154,8 +169,25 @@ class WorkspaceSettingsModal extends PureComponent {
}
renderModalBody () {
const {workspace} = this.props;
const {pfxPath, crtPath, keyPath, showAddCertificateForm} = this.state;
const {
workspace,
editorLineWrapping,
editorFontSize,
editorIndentSize,
editorKeyMap,
handleRender,
handleGetRenderContext
} = this.props;
const {
pfxPath,
crtPath,
keyPath,
showAddCertificateForm,
showDescription,
defaultPreviewMode
} = this.state;
return (
<ModalBody key={`body::${workspace._id}`} noScroll>
<Tabs forceRenderTabPanel>
@@ -167,40 +199,47 @@ class WorkspaceSettingsModal extends PureComponent {
<button>Client Certificates</button>
</Tab>
</TabList>
<TabPanel className="pad scrollable">
<div className="row-fill">
<div className="form-control form-control--outlined">
<label>Workspace Name
<DebouncedInput
type="text"
delay={500}
placeholder="Awesome API"
defaultValue={workspace.name}
onChange={this._handleRename}
/>
</label>
</div>
</div>
<TabPanel className="pad scrollable pad-top-sm">
<div className="form-control form-control--outlined">
<label>Description
<label>Name
<DebouncedInput
textarea
type="text"
delay={500}
rows="4"
placeholder="This workspace is for testing the Awesome API!"
defaultValue={workspace.description}
onChange={this._handleDescriptionChange}
placeholder="Awesome API"
defaultValue={workspace.name}
onChange={this._handleRename}
/>
</label>
</div>
<div>
{showDescription ? (
<MarkdownEditor
className="margin-top"
defaultPreviewMode={defaultPreviewMode}
fontSize={editorFontSize}
indentSize={editorIndentSize}
keyMap={editorKeyMap}
placeholder="Write a description"
lineWrapping={editorLineWrapping}
handleRender={handleRender}
handleGetRenderContext={handleGetRenderContext}
defaultValue={workspace.description}
onChange={this._handleDescriptionChange}
/>
) : (
<button onClick={this._handleAddDescription}
className="btn btn--outlined btn--super-duper-compact">
Add Description
</button>
)}
</div>
<div className="form-control form-control--padded">
<label htmlFor="nothing">Danger Zone
<PromptButton onClick={this._handleRemoveWorkspace}
addIcon
className="width-auto btn btn--clicky">
<i className="fa fa-trash-o"/> Delete Workspace
</PromptButton>
</label>
<h2>Danger Zone</h2>
<PromptButton onClick={this._handleRemoveWorkspace}
addIcon
className="width-auto btn btn--clicky">
<i className="fa fa-trash-o"/> Delete Workspace
</PromptButton>
</div>
</TabPanel>
<TabPanel className="pad scrollable">
@@ -376,7 +415,13 @@ class WorkspaceSettingsModal extends PureComponent {
WorkspaceSettingsModal.propTypes = {
handleRemoveWorkspace: PropTypes.func.isRequired,
workspace: PropTypes.object.isRequired
workspace: PropTypes.object.isRequired,
editorFontSize: PropTypes.number.isRequired,
editorIndentSize: PropTypes.number.isRequired,
editorKeyMap: PropTypes.string.isRequired,
editorLineWrapping: PropTypes.bool.isRequired,
handleRender: PropTypes.func.isRequired,
handleGetRenderContext: PropTypes.func.isRequired
};
export default WorkspaceSettingsModal;

View File

@@ -8,6 +8,8 @@ import Editable from '../base/editable';
import MethodTag from '../tags/method-tag';
import * as models from '../../../models';
import {trackEvent} from '../../../analytics/index';
import {showModal} from '../modals/index';
import RequestSettingsModal from '../modals/request-settings-modal';
@autobind
class SidebarRequestRow extends PureComponent {
@@ -55,6 +57,15 @@ class SidebarRequestRow extends PureComponent {
trackEvent('Request', 'Activate', 'Sidebar');
}
_handleShowRequestSettings () {
showModal(RequestSettingsModal, this.props.request);
}
_handleClickDescription () {
trackEvent('Request', 'Click Description Icon');
this._handleShowRequestSettings();
}
setDragDirection (dragDirection) {
if (dragDirection !== this.state.dragDirection) {
this.setState({dragDirection});
@@ -106,17 +117,28 @@ class SidebarRequestRow extends PureComponent {
onContextMenu={this._handleShowRequestActions}>
<div className="sidebar__clickable">
<MethodTag method={request.method}/>
<Editable value={request.name}
onEditStart={this._handleEditStart}
onSubmit={this._handleRequestUpdateName}/>
<div>
<Editable value={request.name}
className="inline-block"
onEditStart={this._handleEditStart}
onSubmit={this._handleRequestUpdateName}/>
{request.description && (
<button title="View description"
onClick={this._handleClickDescription}
className="icon space-left txt-sm super-faint">
<i className="fa fa-file-text-o"/>
</button>
)}
</div>
</div>
</button>
<div className="sidebar__actions">
<RequestActionsDropdown
right
ref={this._setRequestActionsDropdownRef}
handleDuplicateRequest={handleDuplicateRequest}
handleGenerateCode={handleGenerateCode}
right
handleShowSettings={this._handleShowRequestSettings}
request={request}
requestGroup={requestGroup}
/>

View File

@@ -375,8 +375,18 @@ class Wrapper extends PureComponent {
<RequestCreateModal ref={registerModal}/>
<PaymentNotificationModal ref={registerModal}/>
<FilterHelpModal ref={registerModal}/>
<RequestSettingsModal ref={registerModal}/>
<RequestRenderErrorModal ref={registerModal}/>
<RequestSettingsModal
ref={registerModal}
editorFontSize={settings.editorFontSize}
editorIndentSize={settings.editorIndentSize}
editorKeyMap={settings.editorKeyMap}
editorLineWrapping={settings.editorLineWrapping}
handleRender={handleRender}
handleGetRenderContext={handleGetRenderContext}
/>
<CookiesModal
ref={registerModal}
workspace={activeWorkspace}
@@ -391,6 +401,12 @@ class Wrapper extends PureComponent {
<WorkspaceSettingsModal
ref={registerModal}
workspace={activeWorkspace}
editorFontSize={settings.editorFontSize}
editorIndentSize={settings.editorIndentSize}
editorKeyMap={settings.editorKeyMap}
editorLineWrapping={settings.editorLineWrapping}
handleRender={handleRender}
handleGetRenderContext={handleGetRenderContext}
handleRemoveWorkspace={this._handleRemoveActiveWorkspace}/>
<WorkspaceShareSettingsModal
ref={registerModal}

View File

@@ -71,19 +71,12 @@
padding: @padding-sm;
border-radius: @radius-md;
background-color: @hl-xxs;
&.input--area {
background-color: transparent;
padding:0;
}
}
.input,
input,
select {
height: @line-height-xs;
&.input--area {
height: auto;
}
}
.input[data-focused="on"],
@@ -164,13 +157,25 @@
}
}
.icon {
text-align: center;
color: var(--hl);
&:hover {
color: var(--color-font);
}
}
.btn {
text-align: center;
padding: 0 (@padding-md * 1.5);
height: @line-height-md;
border: 1px solid transparent;
background: var(--color-bg);
&:not(.btn--plain) {
padding: 0 (@padding-md * 1.5);
height: @line-height-md;
border: 1px solid transparent;
}
&.btn--compact {
padding: 0 @padding-md;
height: @line-height-sm;

View File

@@ -0,0 +1,124 @@
@import '../constants/dimensions';
@import '../constants/colors';
.markdown-editor {
border: 1px solid var(--hl-md);
border-radius: @radius-md;
.markdown-editor__edit {
padding: @padding-xs @padding-sm;
// Not sure why this style doesn't work on .CodeMirror...
.CodeMirror-scroll {
max-height: 30vh;
}
.input {
height: auto;
}
}
.markdown-editor__preview {
max-height: 30vh;
padding: @padding-sm;
overflow: auto;
h1 {
font-size: @font-size-xxl;
}
& > * {
margin: @padding-sm 0 @padding-md 0;
padding: 0;
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
p > code {
padding: 0 @padding-xs;
}
ul {
list-style: circle;
padding-left: @padding-md;
}
.hljs {
width: 100%;
box-sizing: border-box;
.hljs-meta,
.hljs-comment,
.hljs-quote {
color: var(--hl);
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: var(--color-font);
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-built_in,
.hljs-builtin-name,
.hljs-type,
.hljs-class .hljs-title,
.hljs-tag .hljs-attr {
color: var(--color-surprise);
}
.hljs-symbol,
.hljs-bullet,
.hljs-title,
.hljs-section,
.hljs-selector-id,
.hljs-doctag {
color: var(--color-danger);
}
.hljs-string {
color: var(--color-notice);
}
.hljs-subst {
font-weight: normal;
}
.hljs-tag,
.hljs-name,
.hljs-attr,
.hljs-regexp,
.hljs-link,
.hljs-attribute {
color: var(--color-success);
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}
}
}
}

View File

@@ -72,7 +72,6 @@
padding-right: @padding-md;
}
}
}
.ReactTabs__Tab--selected {
@@ -89,6 +88,10 @@
background: transparent;
}
.ReactTabs__Tab > button > a {
color: inherit;
}
.ReactTabs__TabPanel {
width: 100%;
height: 100%;

View File

@@ -115,4 +115,14 @@
&.editor--readonly .CodeMirror-cursors {
visibility: hidden;
}
&.editor--dynamic-height {
.CodeMirror {
position: static;
}
.CodeMirror-lines {
padding-bottom: 0.5em;
}
}
}

View File

@@ -27,6 +27,7 @@
@import 'components/environment-editor';
@import 'components/header-editor';
@import 'components/key-value-editor';
@import 'components/markdown-editor';
@import 'components/method-dropdown';
@import 'components/modal';
@import 'components/pane';

5
package-lock.json generated
View File

@@ -3580,6 +3580,11 @@
"resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
"integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ="
},
"highlight.js": {
"version": "9.12.0",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
"integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
},
"hkdf": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/hkdf/-/hkdf-0.0.2.tgz",

View File

@@ -114,6 +114,7 @@
"codemirror": "5.24.2",
"electron-context-menu": "0.9.0",
"electron-squirrel-startup": "1.0.0",
"highlight.js": "9.12.0",
"hkdf": "0.0.2",
"html-entities": "1.2.0",
"httpsnippet": "1.16.5",
@@ -121,7 +122,7 @@
"insomnia-importers": "1.3.3",
"jsonlint": "1.6.2",
"jsonpath": "0.2.11",
"marked": "^0.3.6",
"marked": "0.3.6",
"mime-types": "2.1.14",
"mkdirp": "0.5.1",
"moment": "2.18.1",