Fixes: JS error when no heading

Fixes: Reduce hover zone
Fixes: Add H1s into TOC
This commit is contained in:
Tom Moor
2017-10-24 08:43:35 -07:00
parent a2285c8fb7
commit 23c95f4d56
3 changed files with 31 additions and 18 deletions

View File

@ -26,9 +26,12 @@ type Props = {
} }
updateActiveHeading = () => { updateActiveHeading = () => {
let activeHeading = this.headingElements[0].id; const elements = this.headingElements;
if (!elements.length) return;
for (const element of this.headingElements) { let activeHeading = elements[0].id;
for (const element of elements) {
const bounds = element.getBoundingClientRect(); const bounds = element.getBoundingClientRect();
if (bounds.top <= 0) activeHeading = element.id; if (bounds.top <= 0) activeHeading = element.id;
} }
@ -38,7 +41,7 @@ type Props = {
get headingElements(): HTMLElement[] { get headingElements(): HTMLElement[] {
const elements = []; const elements = [];
const tagNames = ['h2', 'h3', 'h4', 'h5', 'h6']; const tagNames = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'];
for (const tagName of tagNames) { for (const tagName of tagNames) {
for (const ele of document.getElementsByTagName(tagName)) { for (const ele of document.getElementsByTagName(tagName)) {
@ -54,7 +57,6 @@ type Props = {
return state.document.nodes.filter((node: Block) => { return state.document.nodes.filter((node: Block) => {
if (!node.text) return false; if (!node.text) return false;
if (node.type === 'heading1') return false;
return node.type.match(/^heading/); return node.type.match(/^heading/);
}); });
} }
@ -67,7 +69,7 @@ type Props = {
<Wrapper> <Wrapper>
<Sections> <Sections>
{this.headings.map(heading => { {this.headings.map(heading => {
const slug = headingToSlug(heading.type, heading.text); const slug = headingToSlug(heading);
const active = this.activeHeading === slug; const active = this.activeHeading === slug;
return ( return (
@ -84,6 +86,13 @@ type Props = {
} }
} }
const Wrapper = styled.div`
position: fixed;
right: 0;
top: 150px;
z-index: 100;
`;
const Anchor = styled.a` const Anchor = styled.a`
color: ${props => (props.active ? color.slateDark : color.slate)}; color: ${props => (props.active ? color.slateDark : color.slate)};
font-weight: ${props => (props.active ? 500 : 400)}; font-weight: ${props => (props.active ? 500 : 400)};
@ -91,6 +100,8 @@ const Anchor = styled.a`
transition: all 100ms ease-in-out; transition: all 100ms ease-in-out;
margin-right: -5px; margin-right: -5px;
padding: 2px 0; padding: 2px 0;
pointer-events: none;
text-overflow: ellipsis;
&:hover { &:hover {
color: ${color.primary}; color: ${color.primary};
@ -99,14 +110,15 @@ const Anchor = styled.a`
const ListItem = styled.li` const ListItem = styled.li`
position: relative; position: relative;
margin-left: ${props => (props.type === 'heading2' ? '8px' : '16px')}; margin-left: ${props => (props.type.match(/heading[12]/) ? '8px' : '16px')};
text-align: right; text-align: right;
color: ${color.slate}; color: ${color.slate};
padding-right: 16px; padding-right: 16px;
white-space: nowrap;
&:after { &:after {
color: ${props => (props.active ? color.slateDark : color.slate)}; color: ${props => (props.active ? color.slateDark : color.slate)};
content: "${props => (props.type === 'heading2' ? '—' : '')}"; content: "${props => (props.type.match(/heading[12]/) ? '—' : '')}";
position: absolute; position: absolute;
right: 0; right: 0;
} }
@ -117,21 +129,21 @@ const Sections = styled.ol`
padding: 0; padding: 0;
list-style: none; list-style: none;
font-size: 13px; font-size: 13px;
width: 100px;
transition-delay: 1s;
transition: width 100ms ease-in-out;
&:hover { &:hover {
width: 300px;
transition-delay: 0s;
${Anchor} { ${Anchor} {
opacity: 1; opacity: 1;
margin-right: 0; margin-right: 0;
background: ${color.white}; background: ${color.white};
pointer-events: all;
} }
} }
`; `;
const Wrapper = styled.div`
position: fixed;
right: 0;
top: 160px;
z-index: 100;
`;
export default Contents; export default Contents;

View File

@ -30,7 +30,7 @@ function Heading(props: Props) {
const parentIsDocument = parent instanceof Document; const parentIsDocument = parent instanceof Document;
const firstHeading = parentIsDocument && parent.nodes.first() === node; const firstHeading = parentIsDocument && parent.nodes.first() === node;
const showPlaceholder = placeholder && firstHeading && !node.text; const showPlaceholder = placeholder && firstHeading && !node.text;
const slugish = headingToSlug(node.type, node.text); const slugish = headingToSlug(node);
const showHash = readOnly && !!slugish; const showHash = readOnly && !!slugish;
const Component = component; const Component = component;
const emoji = editor.props.emoji || ''; const emoji = editor.props.emoji || '';

View File

@ -1,8 +1,9 @@
// @flow // @flow
import { escape } from 'lodash'; import { escape } from 'lodash';
import type { Node } from './types';
import slug from 'slug'; import slug from 'slug';
export default function headingToSlug(heading: string, title: string) { export default function headingToSlug(node: Node) {
const level = heading.replace('heading', 'h'); const level = node.type.replace('heading', 'h');
return escape(`${level}-${slug(title)}`); return escape(`${level}-${slug(node.text)}-${node.key}`);
} }