Skip to content

Commit

Permalink
Merge pull request #305 from Mavrin/master
Browse files Browse the repository at this point in the history
#299 add toolbar for markdown formatting
  • Loading branch information
umputun committed Apr 15, 2019
2 parents 2a53a54 + c7824e6 commit 0585c32
Show file tree
Hide file tree
Showing 24 changed files with 329 additions and 36 deletions.
17 changes: 17 additions & 0 deletions web/app/@types/markdown-toolbar-element/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
declare namespace JSX {
interface IntrinsicElements {
'markdown-toolbar': {
for: string;
children?: any;
className: string;
};
'md-bold': any;
'md-header': any;
'md-italic': any;
'md-quote': any;
'md-code': any;
'md-link': any;
'md-unordered-list': any;
'md-ordered-list': any;
}
}
15 changes: 15 additions & 0 deletions web/app/common/closest-polyfill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector;
}

if (!Element.prototype.closest) {
Element.prototype.closest = function(s) {
let el = this;

do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
return null;
};
}
2 changes: 2 additions & 0 deletions web/app/common/polyfills.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'core-js/es/promise';
import 'focus-visible';
import '@webcomponents/custom-elements';
import './closest-polyfill';

export default async function loadPolyfills() {
const fillCoreJs = async () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.input__control-panel {
height: 30px;
background-color: #eee;
}
2 changes: 1 addition & 1 deletion web/app/components/input/__field/input__field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
$lineHeight: 1.4;
$fontSize: 16px;
$paddingVrt: 10px;
$lines: 3;
$lines: 4;
$height: calc($fontSize * $lineHeight * $lines + $paddingVrt * 2);

box-sizing: border-box;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.input__toolbar {
display: block;
float: right;
}

.input__toolbar-item {
background: none;
border: 0;
color: #586069;
display: block;
float: left;
padding: 4px 5px;

&:hover {
color: #0aa;
}
}

.input__toolbar-icon {
display: inline-block;
fill: currentColor;
}

.input__toolbar-group {
display: inline-block;
margin-left: 20px;
}

.input__toolbar-group:first-child {
margin-left: 0;
}
11 changes: 11 additions & 0 deletions web/app/components/input/_theme/_dark/input_theme_dark.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,15 @@
.input__preview-wrapper {
background: #eee;
}

.input__toolbar-item {
color: #ddd;
&:hover {
color: #0aa;
}
}

.input__control-panel {
background-color: #333;
}
}
3 changes: 2 additions & 1 deletion web/app/components/input/input.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
position: relative;
display: block;
font-size: 0;
border: 12px solid;
border-style: solid;
border-width: 6px 12px 12px 12px;
border-radius: 2px;
}
12 changes: 10 additions & 2 deletions web/app/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import { StaticStore } from '@app/common/static_store';
import { siteId, url, pageTitle } from '@app/common/settings';
import { extractErrorMessageFromResponse } from '@app/utils/errorUtils';

import MarkdownToolbar from './markdown-toolbar';
import TextareaAutosize from './textarea-autosize';

const RSS_THREAD_URL = `${BASE_URL}${API_BASE}/rss/post?site=${siteId}&url=${url}`;
const RSS_SITE_URL = `${BASE_URL}${API_BASE}/rss/site?site=${siteId}`;
const RSS_REPLIES_URL = `${BASE_URL}${API_BASE}/rss/reply?site=${siteId}&user=`;

let textareaId = 0;

interface Props {
/** user id for rss link generation */
userId?: User['id'];
Expand Down Expand Up @@ -52,10 +55,11 @@ const Labels = {

export class Input extends Component<Props, State> {
textAreaRef?: TextareaAutosize;

textareaId: string;
constructor(props: Props) {
super(props);

textareaId = textareaId + 1;
this.textareaId = `textarea_${textareaId}`;
this.state = {
preview: null,
isErrorShown: false,
Expand Down Expand Up @@ -165,8 +169,12 @@ export class Input extends Component<Props, State> {
onSubmit={this.send}
aria-label="New comment"
>
<div className="input__control-panel">
<MarkdownToolbar textareaId={this.textareaId} />
</div>
<div className="input__field-wrapper">
<TextareaAutosize
id={this.textareaId}
ref={ref => (this.textAreaRef = ref)}
className="input__field"
placeholder="Your comment here"
Expand Down
13 changes: 13 additions & 0 deletions web/app/components/input/markdown-toolbar-icons/bold-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function BoldIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 10 16" version="1.1" width="10" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M1 2h3.83c2.48 0 4.3.75 4.3 2.95 0 1.14-.63 2.23-1.67 2.61v.06c1.33.3 2.3 1.23 2.3 2.86 0 2.39-1.97 3.52-4.61 3.52H1V2zm3.66 4.95c1.67 0 2.38-.66 2.38-1.69 0-1.17-.78-1.61-2.34-1.61H3.13v3.3h1.53zm.27 5.39c1.77 0 2.75-.64 2.75-1.98 0-1.27-.95-1.81-2.75-1.81h-1.8v3.8h1.8v-.01z"
/>
</svg>
);
}
13 changes: 13 additions & 0 deletions web/app/components/input/markdown-toolbar-icons/code-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function CodeIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M9.5 3L8 4.5 11.5 8 8 11.5 9.5 13 14 8 9.5 3zm-5 0L0 8l4.5 5L6 11.5 2.5 8 6 4.5 4.5 3z"
/>
</svg>
);
}
13 changes: 13 additions & 0 deletions web/app/components/input/markdown-toolbar-icons/header-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function HeaderIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 18 16" version="1.1" width="18" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M13.62 9.08L12.1 3.66h-.06l-1.5 5.42h3.08zM5.7 10.13S4.68 6.52 4.53 6.02h-.08l-1.13 4.11H5.7zM17.31 14h-2.25l-.95-3.25h-4.07L9.09 14H6.84l-.69-2.33H2.87L2.17 14H0l3.3-9.59h2.5l2.17 6.34L10.86 2h2.52l3.94 12h-.01z"
/>
</svg>
);
}
13 changes: 13 additions & 0 deletions web/app/components/input/markdown-toolbar-icons/italic-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function ItalicIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 6 16" version="1.1" width="6" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M2.81 5h1.98L3 14H1l1.81-9zm.36-2.7c0-.7.58-1.3 1.33-1.3.56 0 1.13.38 1.13 1.03 0 .75-.59 1.3-1.33 1.3-.58 0-1.13-.38-1.13-1.03z"
/>
</svg>
);
}
13 changes: 13 additions & 0 deletions web/app/components/input/markdown-toolbar-icons/link-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function LinkIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z"
/>
</svg>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function OrderedListIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M12.01 13c0 .59 0 1-.59 1H4.6c-.59 0-.59-.41-.59-1 0-.59 0-1 .59-1h6.81c.59 0 .59.41.59 1h.01zM4.6 4h6.81C12 4 12 3.59 12 3c0-.59 0-1-.59-1H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1zm6.81 3H4.6c-.59 0-.59.41-.59 1 0 .59 0 1 .59 1h6.81C12 9 12 8.59 12 8c0-.59 0-1-.59-1zm-9.4-6h-.72c-.3.19-.58.25-1.03.34V2h.75v2.14H.17V5h2.84v-.86h-1V1zm.392 8.12c-.129 0-.592.04-.802.07.53-.56 1.14-1.25 1.14-1.89C2.72 6.52 2.18 6 1.38 6c-.59 0-.97.2-1.38.64l.58.58c.19-.19.38-.38.64-.38.28 0 .48.16.48.52 0 .53-.77 1.2-1.7 2.06V10h3v-.88h-.598zm-.222 3.79v-.03c.44-.19.64-.47.64-.86 0-.7-.56-1.11-1.44-1.11-.48 0-.89.19-1.28.52l.55.64c.25-.2.44-.31.69-.31.27 0 .42.13.42.36 0 .27-.2.44-.86.44v.75c.83 0 .98.17.98.47 0 .25-.23.38-.58.38-.28 0-.56-.14-.81-.38l-.48.66c.3.36.77.56 1.41.56.83 0 1.53-.41 1.53-1.16 0-.5-.31-.81-.77-.94v.01z"
/>
</svg>
);
}
13 changes: 13 additions & 0 deletions web/app/components/input/markdown-toolbar-icons/quote-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function QuoteIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 14 16" version="1.1" width="14" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M6.16 3.5C3.73 5.06 2.55 6.67 2.55 9.36c.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.9 0-2.99-1.52-2.99-4.25 0-3.8 1.75-6.53 5.02-8.42L6.16 3.5zm7 0c-2.43 1.56-3.61 3.17-3.61 5.86.16-.05.3-.05.44-.05 1.27 0 2.5.86 2.5 2.41 0 1.61-1.03 2.61-2.5 2.61-1.89 0-2.98-1.52-2.98-4.25 0-3.8 1.75-6.53 5.02-8.42l1.14 1.84h-.01z"
/>
</svg>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @jsx h */
import { h } from 'preact';

export default function UnorderedListIcon() {
return (
<svg className="input__toolbar-icon" viewBox="0 0 12 16" version="1.1" width="12" height="16" aria-hidden="true">
<path
fill-rule="evenodd"
d="M2 13c0 .59 0 1-.59 1H.59C0 14 0 13.59 0 13c0-.59 0-1 .59-1h.81c.59 0 .59.41.59 1H2zm2.59-9h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1H4.59C4 2 4 2.41 4 3c0 .59 0 1 .59 1zM1.41 7H.59C0 7 0 7.41 0 8c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0-5H.59C0 2 0 2.41 0 3c0 .59 0 1 .59 1h.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm10 5H4.59C4 7 4 7.41 4 8c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01zm0 5H4.59C4 12 4 12.41 4 13c0 .59 0 1 .59 1h6.81c.59 0 .59-.41.59-1 0-.59 0-1-.59-1h.01z"
/>
</svg>
);
}
63 changes: 63 additions & 0 deletions web/app/components/input/markdown-toolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/** @jsx h */
import { h, Component, RenderableProps } from 'preact';
import '@github/markdown-toolbar-element';
import BoldIcon from './markdown-toolbar-icons/bold-icon';
import HeaderIcon from './markdown-toolbar-icons/header-icon';
import ItalicIcon from './markdown-toolbar-icons/italic-icon';
import QuoteIcon from './markdown-toolbar-icons/quote-icon';
import CodeIcon from './markdown-toolbar-icons/code-icon';
import LinkIcon from './markdown-toolbar-icons/link-icon';
import UnorderedListIcon from './markdown-toolbar-icons/unordered-list-icon';
import OrderedListIcon from './markdown-toolbar-icons/ordered-list-icon';

interface Props {
textareaId: string;
}

const boldLabel = 'Add bold text <cmd-b>';
const headerLabel = 'Add header text';
const italicLabel = 'Add italic text <cmd-i>';
const quoteLabel = 'Insert a quote';
const codeLabel = 'Insert a code';
const linkLabel = 'Add a link <cmd-k>';
const unorderedListLabel = 'Add a bulleted list';
const orderedListLabel = 'Add a numbered list';

export default class MarkdownToolbar extends Component<Props> {
render(props: RenderableProps<Props>) {
return (
<markdown-toolbar className="input__toolbar" for={props.textareaId}>
<div className="input__toolbar-group">
<md-header className="input__toolbar-item" title={headerLabel} aria-label={headerLabel}>
<HeaderIcon />
</md-header>
<md-bold className="input__toolbar-item" title={boldLabel} aria-label={boldLabel}>
<BoldIcon />
</md-bold>
<md-italic className="input__toolbar-item" title={italicLabel} aria-label={italicLabel}>
<ItalicIcon />
</md-italic>
</div>
<div className="input__toolbar-group">
<md-quote className="input__toolbar-item" title={quoteLabel} aria-label={quoteLabel}>
<QuoteIcon />
</md-quote>
<md-code className="input__toolbar-item" title={codeLabel} aria-label={codeLabel}>
<CodeIcon />
</md-code>
<md-link className="input__toolbar-item" title={linkLabel} aria-label={linkLabel}>
<LinkIcon />
</md-link>
</div>
<div className="input__toolbar-group">
<md-unordered-list className="input__toolbar-item" title={unorderedListLabel} aria-label={unorderedListLabel}>
<UnorderedListIcon />
</md-unordered-list>
<md-ordered-list className="input__toolbar-item" title={orderedListLabel} aria-label={orderedListLabel}>
<OrderedListIcon />
</md-ordered-list>
</div>
</markdown-toolbar>
);
}
}
2 changes: 2 additions & 0 deletions web/app/components/input/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require('./__button/input__button.scss');
require('./__button/_type/_preview/input__button_type_preview.scss');
require('./__button/_type/_send/input__button_type_send.scss');

require('./__control-panel/input__control-panel.scss');
require('./__counter/input__counter.scss');
require('./__error/input__error.scss');
require('./__field/input__field.scss');
Expand All @@ -18,6 +19,7 @@ require('./__rss/input__rss.scss');
require('./__rss-link/input__rss-link.scss');
require('./__markdown/input__markdown.scss');
require('./__markdown-link/input__markdown-link.scss');
require('./__markdown-toolbar/input__markdown-toolbar.scss');

require('./_theme/_dark/input_theme_dark.scss');
require('./_theme/_light/input_theme_light.scss');
1 change: 1 addition & 0 deletions web/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ module.exports = {
'\\.scss$': '<rootDir>/app/testUtils/mockStyles.js',
'@app/(.*)': '<rootDir>/app/$1',
},
setupFilesAfterEnv: ['<rootDir>/setup-jest-env.js'],
};

0 comments on commit 0585c32

Please sign in to comment.