parent
b031e22003
commit
4bf257d136
|
@ -1,25 +1,41 @@
|
||||||
@import "src/style/modules";
|
@import "src/style/modules";
|
||||||
|
|
||||||
.note-editor {
|
.note-editor {
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.note-editor-text, .note-editor-preview {
|
.note-editor--body {
|
||||||
flex: 1 1 0;
|
flex: 1 1 40vh;
|
||||||
border-width: $ix-border;
|
position: relative;
|
||||||
border-style: solid;
|
}
|
||||||
border-radius: $ix-radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-editor-text {
|
.note-editor--body .react-codemirror2,
|
||||||
border-color: $g5-pepper;
|
.note-editor--preview {
|
||||||
}
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.note-editor-preview {
|
.note-editor--body .react-codemirror2 {
|
||||||
border-color: $g4-onyx;
|
z-index: 1;
|
||||||
padding: $ix-marg-b * 2;
|
}
|
||||||
}
|
|
||||||
|
.note-editor--preview {
|
||||||
|
background-color: $g3-castle;
|
||||||
|
z-index: 2;
|
||||||
|
border-width: $ix-border;
|
||||||
|
border-style: solid;
|
||||||
|
border-radius: $ix-radius;
|
||||||
|
border-color: $g4-onyx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-editor--preview-scroll {
|
||||||
|
position: absolute !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.note-editor--markdown-container {
|
||||||
|
padding: $ix-marg-c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-editor--controls {
|
.note-editor--controls {
|
||||||
|
@ -33,14 +49,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-editor--toggle {
|
.note-editor--radio {
|
||||||
display: flex;
|
width: 220px;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.note-editor--footer {
|
.note-editor--footer {
|
||||||
font-size: 13px;
|
font-size: $form-sm-font;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
color: $g11-sidewalk;
|
color: $g11-sidewalk;
|
||||||
margin-top: $ix-marg-b;
|
margin-top: $ix-marg-b;
|
||||||
|
|
|
@ -1,9 +1,18 @@
|
||||||
// Libraries
|
// Libraries
|
||||||
import React, {SFC} from 'react'
|
import React, {PureComponent} from 'react'
|
||||||
import {connect} from 'react-redux'
|
import {connect} from 'react-redux'
|
||||||
|
import classnames from 'classnames'
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import {Radio, SlideToggle, ComponentSize} from 'src/clockface'
|
import {
|
||||||
|
Radio,
|
||||||
|
SlideToggle,
|
||||||
|
ComponentSize,
|
||||||
|
ComponentSpacer,
|
||||||
|
ButtonShape,
|
||||||
|
Stack,
|
||||||
|
Alignment,
|
||||||
|
} from 'src/clockface'
|
||||||
import NoteEditorText from 'src/dashboards/components/NoteEditorText'
|
import NoteEditorText from 'src/dashboards/components/NoteEditorText'
|
||||||
import NoteEditorPreview from 'src/dashboards/components/NoteEditorPreview'
|
import NoteEditorPreview from 'src/dashboards/components/NoteEditorPreview'
|
||||||
|
|
||||||
|
@ -37,65 +46,84 @@ interface OwnProps {}
|
||||||
|
|
||||||
type Props = StateProps & DispatchProps & OwnProps
|
type Props = StateProps & DispatchProps & OwnProps
|
||||||
|
|
||||||
const NoteEditor: SFC<Props> = props => {
|
class NoteEditor extends PureComponent<Props> {
|
||||||
const {
|
public render() {
|
||||||
note,
|
const {note, isPreviewing, onSetIsPreviewing, onSetNote} = this.props
|
||||||
isPreviewing,
|
|
||||||
toggleVisible,
|
|
||||||
showNoteWhenEmpty,
|
|
||||||
onSetIsPreviewing,
|
|
||||||
onToggleShowNoteWhenEmpty,
|
|
||||||
onSetNote,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-editor">
|
<div className="note-editor">
|
||||||
<div
|
<div className={this.controlsClassName}>
|
||||||
className={`note-editor--controls ${toggleVisible ? '' : 'centered'}`}
|
<div className="note-editor--radio">
|
||||||
>
|
<Radio shape={ButtonShape.StretchToFit}>
|
||||||
<Radio>
|
<Radio.Button
|
||||||
<Radio.Button
|
value={false}
|
||||||
value={false}
|
active={!isPreviewing}
|
||||||
active={!isPreviewing}
|
onClick={onSetIsPreviewing}
|
||||||
onClick={onSetIsPreviewing}
|
>
|
||||||
>
|
Compose
|
||||||
Compose
|
</Radio.Button>
|
||||||
</Radio.Button>
|
<Radio.Button
|
||||||
<Radio.Button
|
value={true}
|
||||||
value={true}
|
active={isPreviewing}
|
||||||
active={isPreviewing}
|
onClick={onSetIsPreviewing}
|
||||||
onClick={onSetIsPreviewing}
|
>
|
||||||
>
|
Preview
|
||||||
Preview
|
</Radio.Button>
|
||||||
</Radio.Button>
|
</Radio>
|
||||||
</Radio>
|
|
||||||
{toggleVisible && (
|
|
||||||
<div className="note-editor--toggle">
|
|
||||||
<SlideToggle.Label text="Show note when query returns no data" />
|
|
||||||
<SlideToggle
|
|
||||||
active={showNoteWhenEmpty}
|
|
||||||
size={ComponentSize.ExtraSmall}
|
|
||||||
onChange={onToggleShowNoteWhenEmpty}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
{this.visibilityToggle}
|
||||||
|
</div>
|
||||||
|
<div className="note-editor--body">
|
||||||
|
{this.noteEditorPreview}
|
||||||
|
<NoteEditorText note={note} onChangeNote={onSetNote} />
|
||||||
|
</div>
|
||||||
|
<div className="note-editor--footer">
|
||||||
|
Need help using Markdown? Check out{' '}
|
||||||
|
<a
|
||||||
|
href="https://daringfireball.net/projects/markdown/syntax"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
this handy guide
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{isPreviewing ? (
|
)
|
||||||
<NoteEditorPreview note={note} />
|
}
|
||||||
) : (
|
|
||||||
<NoteEditorText note={note} onChangeNote={onSetNote} />
|
private get controlsClassName(): string {
|
||||||
)}
|
const {toggleVisible} = this.props
|
||||||
<div className="note-editor--footer">
|
|
||||||
Need help using Markdown? Check out{' '}
|
return classnames('note-editor--controls', {centered: toggleVisible})
|
||||||
<a
|
}
|
||||||
href="https://daringfireball.net/projects/markdown/syntax"
|
|
||||||
target="_blank"
|
private get noteEditorPreview(): JSX.Element {
|
||||||
>
|
const {isPreviewing, note} = this.props
|
||||||
this handy guide
|
|
||||||
</a>
|
if (isPreviewing) {
|
||||||
</div>
|
return <NoteEditorPreview note={note} />
|
||||||
</div>
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
private visibilityToggle(): JSX.Element {
|
||||||
|
const {
|
||||||
|
toggleVisible,
|
||||||
|
showNoteWhenEmpty,
|
||||||
|
onToggleShowNoteWhenEmpty,
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
if (toggleVisible) {
|
||||||
|
return (
|
||||||
|
<ComponentSpacer stackChildren={Stack.Columns} align={Alignment.Right}>
|
||||||
|
<SlideToggle.Label text="Show note when query returns no data" />
|
||||||
|
<SlideToggle
|
||||||
|
active={showNoteWhenEmpty}
|
||||||
|
size={ComponentSize.ExtraSmall}
|
||||||
|
onChange={onToggleShowNoteWhenEmpty}
|
||||||
|
/>
|
||||||
|
</ComponentSpacer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mstp = (state: AppState) => {
|
const mstp = (state: AppState) => {
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
.note-editor-container .overlay--container {
|
|
||||||
height: 80%;
|
|
||||||
max-height: 600px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-editor-container .overlay--body {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
OverlayHeading,
|
OverlayHeading,
|
||||||
OverlayTechnology,
|
OverlayTechnology,
|
||||||
OverlayContainer,
|
OverlayContainer,
|
||||||
|
OverlayFooter,
|
||||||
Button,
|
Button,
|
||||||
ComponentColor,
|
ComponentColor,
|
||||||
ComponentStatus,
|
ComponentStatus,
|
||||||
|
@ -26,9 +27,6 @@ import {notify} from 'src/shared/actions/notifications'
|
||||||
// Utils
|
// Utils
|
||||||
import {savingNoteFailed} from 'src/shared/copy/v2/notifications'
|
import {savingNoteFailed} from 'src/shared/copy/v2/notifications'
|
||||||
|
|
||||||
// Styles
|
|
||||||
import 'src/dashboards/components/NoteEditorContainer.scss'
|
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import {RemoteDataState} from 'src/types'
|
import {RemoteDataState} from 'src/types'
|
||||||
import {AppState} from 'src/types/v2'
|
import {AppState} from 'src/types/v2'
|
||||||
|
@ -65,20 +63,19 @@ class NoteEditorContainer extends PureComponent<Props, State> {
|
||||||
<div className="note-editor-container">
|
<div className="note-editor-container">
|
||||||
<OverlayTechnology visible={overlayVisible}>
|
<OverlayTechnology visible={overlayVisible}>
|
||||||
<OverlayContainer>
|
<OverlayContainer>
|
||||||
<OverlayHeading title={this.overlayTitle}>
|
<OverlayHeading title={this.overlayTitle} onDismiss={onHide} />
|
||||||
<div className="create-source-overlay--heading-buttons">
|
|
||||||
<Button text="Cancel" onClick={onHide} />
|
|
||||||
<Button
|
|
||||||
text="Save"
|
|
||||||
color={ComponentColor.Success}
|
|
||||||
status={this.saveButtonStatus}
|
|
||||||
onClick={this.handleSave}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</OverlayHeading>
|
|
||||||
<OverlayBody>
|
<OverlayBody>
|
||||||
<NoteEditor />
|
<NoteEditor />
|
||||||
</OverlayBody>
|
</OverlayBody>
|
||||||
|
<OverlayFooter>
|
||||||
|
<Button text="Cancel" onClick={onHide} />
|
||||||
|
<Button
|
||||||
|
text="Save"
|
||||||
|
color={ComponentColor.Success}
|
||||||
|
status={this.saveButtonStatus}
|
||||||
|
onClick={this.handleSave}
|
||||||
|
/>
|
||||||
|
</OverlayFooter>
|
||||||
</OverlayContainer>
|
</OverlayContainer>
|
||||||
</OverlayTechnology>
|
</OverlayTechnology>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -9,9 +9,15 @@ interface Props {
|
||||||
|
|
||||||
const NoteEditorPreview: SFC<Props> = props => {
|
const NoteEditorPreview: SFC<Props> = props => {
|
||||||
return (
|
return (
|
||||||
<div className="note-editor-preview markdown-format">
|
<div className="note-editor--preview">
|
||||||
<FancyScrollbar>
|
<FancyScrollbar className="note-editor--preview-scroll">
|
||||||
<ReactMarkdown source={props.note} escapeHtml={true} />
|
<div className="note-editor--markdown-container">
|
||||||
|
<ReactMarkdown
|
||||||
|
source={props.note}
|
||||||
|
escapeHtml={true}
|
||||||
|
className="markdown-format"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</FancyScrollbar>
|
</FancyScrollbar>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
@import "src/style/modules";
|
|
||||||
|
|
||||||
.note-editor-text {
|
|
||||||
background-color: $g2-kevlar;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.react-codemirror2 {
|
|
||||||
padding: $ix-marg-b + $ix-marg-a;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -5,9 +5,6 @@ import {Controlled as ReactCodeMirror} from 'react-codemirror2'
|
||||||
// Utils
|
// Utils
|
||||||
import {humanizeNote} from 'src/dashboards/utils/notes'
|
import {humanizeNote} from 'src/dashboards/utils/notes'
|
||||||
|
|
||||||
// Styles
|
|
||||||
import 'src/dashboards/components/NoteEditorText.scss'
|
|
||||||
|
|
||||||
const OPTIONS = {
|
const OPTIONS = {
|
||||||
mode: 'markdown',
|
mode: 'markdown',
|
||||||
theme: 'markdown',
|
theme: 'markdown',
|
||||||
|
@ -32,15 +29,13 @@ class NoteEditorText extends PureComponent<Props, {}> {
|
||||||
const {note} = this.props
|
const {note} = this.props
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="note-editor-text">
|
<ReactCodeMirror
|
||||||
<ReactCodeMirror
|
autoCursor={true}
|
||||||
autoCursor={true}
|
value={humanizeNote(note)}
|
||||||
value={humanizeNote(note)}
|
options={OPTIONS}
|
||||||
options={OPTIONS}
|
onBeforeChange={this.handleChange}
|
||||||
onBeforeChange={this.handleChange}
|
onTouchStart={noOp}
|
||||||
onTouchStart={noOp}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,11 +7,20 @@
|
||||||
.cm-s-markdown {
|
.cm-s-markdown {
|
||||||
background-color: $g2-kevlar;
|
background-color: $g2-kevlar;
|
||||||
color: $g15-platinum;
|
color: $g15-platinum;
|
||||||
|
padding: 12px;
|
||||||
|
border: 2px solid $g5-pepper;
|
||||||
|
transition: border-color 0.25s ease, box-shadow 0.25s ease;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
|
border-color: $g7-graphite;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.CodeMirror-focused {
|
||||||
|
border-color: $c-pool;
|
||||||
|
box-shadow: 0 0 6px 0 $c-pool;
|
||||||
|
}
|
||||||
|
|
||||||
.cm-italic {
|
.cm-italic {
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,3 @@
|
||||||
.create-source-overlay--heading-buttons {
|
|
||||||
button {
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.create-source-overlay {
|
.create-source-overlay {
|
||||||
.form--element {
|
.form--element {
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
|
|
Loading…
Reference in New Issue