diff options
Diffstat (limited to 'packages/react-shared')
-rw-r--r-- | packages/react-shared/CHANGELOG.json | 12 | ||||
-rw-r--r-- | packages/react-shared/package.json | 4 | ||||
-rw-r--r-- | packages/react-shared/src/components/anchor_title.tsx | 76 | ||||
-rw-r--r-- | packages/react-shared/src/components/markdown_paragraph_block.tsx | 10 | ||||
-rw-r--r-- | packages/react-shared/src/components/markdown_section.tsx | 25 | ||||
-rw-r--r-- | packages/react-shared/src/components/nested_sidebar_menu.tsx | 144 | ||||
-rw-r--r-- | packages/react-shared/src/components/version_drop_down.tsx | 37 | ||||
-rw-r--r-- | packages/react-shared/src/utils/colors.ts | 1 |
8 files changed, 133 insertions, 176 deletions
diff --git a/packages/react-shared/CHANGELOG.json b/packages/react-shared/CHANGELOG.json index d1907e785..ee0352561 100644 --- a/packages/react-shared/CHANGELOG.json +++ b/packages/react-shared/CHANGELOG.json @@ -1,7 +1,6 @@ [ { - "timestamp": 1538693146, - "version": "1.0.15", + "version": "1.0.17", "changes": [ { "note": "Dependencies updated" @@ -9,6 +8,15 @@ ] }, { + "timestamp": 1538693146, + "version": "1.0.16", + "changes": [ + { + "note": "Unpublished package" + } + ] + }, + { "timestamp": 1538475601, "version": "1.0.14", "changes": [ diff --git a/packages/react-shared/package.json b/packages/react-shared/package.json index 178b6d76e..847946eb1 100644 --- a/packages/react-shared/package.json +++ b/packages/react-shared/package.json @@ -44,6 +44,7 @@ "@types/react-router-dom": "^4.0.4", "@types/react-scroll": "1.5.3", "@types/valid-url": "^1.0.2", + "@types/styled-components": "^4.0.0", "basscss": "^8.0.3", "change-case": "^3.0.2", "is-mobile": "^0.2.2", @@ -53,8 +54,9 @@ "react-dom": "^16.4.2", "react-highlight": "0xproject/react-highlight#2f40a42e0a3f0ad126f9f42d505b97b603fc7162", "react-markdown": "^3.2.2", - "react-scroll": "0xproject/react-scroll#similar-to-pr-330", + "react-scroll": "0xproject/react-scroll#similar-to-pr-330-but-with-replace-state", "react-router-dom": "^4.1.1", + "styled-components": "^3.3.0", "valid-url": "^1.0.9" }, "publishConfig": { diff --git a/packages/react-shared/src/components/anchor_title.tsx b/packages/react-shared/src/components/anchor_title.tsx index a83881b67..bd99edcab 100644 --- a/packages/react-shared/src/components/anchor_title.tsx +++ b/packages/react-shared/src/components/anchor_title.tsx @@ -1,7 +1,9 @@ import * as React from 'react'; import { Link as ScrollLink } from 'react-scroll'; +import styled from 'styled-components'; import { HeaderSizes, Styles } from '../types'; +import { colors } from '../utils/colors'; import { constants } from '../utils/constants'; const headerSizeToScrollOffset: { [headerSize: string]: number } = { @@ -14,20 +16,14 @@ export interface AnchorTitleProps { id: string; headerSize: HeaderSizes; shouldShowAnchor: boolean; + isDisabled: boolean; } -export interface AnchorTitleState { - isHovering: boolean; -} +export interface AnchorTitleState {} const styles: Styles = { - anchor: { - fontSize: 20, - transform: 'rotate(45deg)', - cursor: 'pointer', - }, h1: { - fontSize: '1.8em', + fontSize: '1.875em', }, h2: { fontSize: '1.5em', @@ -38,18 +34,28 @@ const styles: Styles = { }, }; +interface AnchorIconProps { + shouldShowAnchor: boolean; +} + +const AnchorIcon = + styled.i < + AnchorIconProps > + ` + opacity: ${props => (props.shouldShowAnchor ? 1 : 0)}; + &:hover { + opacity: ${props => (props.shouldShowAnchor ? 0.6 : 0)}; + } + font-size: 20px; + transform: rotate(45deg); + cursor: pointer; + `; + export class AnchorTitle extends React.Component<AnchorTitleProps, AnchorTitleState> { - constructor(props: AnchorTitleProps) { - super(props); - this.state = { - isHovering: false, - }; - } + public static defaultProps: Partial<AnchorTitleProps> = { + isDisabled: false, + }; public render(): React.ReactNode { - let opacity = 0; - if (this.props.shouldShowAnchor) { - opacity = this.state.isHovering ? 0.6 : 1; - } return ( <div className="relative flex" @@ -63,29 +69,21 @@ export class AnchorTitle extends React.Component<AnchorTitleProps, AnchorTitleSt } as any } > - <div className="inline-block" style={{ paddingRight: 4 }}> + <div className="inline-block" style={{ paddingRight: 4, color: colors.darkestGrey }}> {this.props.title} </div> - <ScrollLink - to={this.props.id} - hashSpy={true} - offset={headerSizeToScrollOffset[this.props.headerSize]} - duration={constants.DOCS_SCROLL_DURATION_MS} - containerId={constants.SCROLL_CONTAINER_ID} - > - <i - className="zmdi zmdi-link" - style={{ ...styles.anchor, opacity }} - onMouseOver={this._setHoverState.bind(this, true)} - onMouseOut={this._setHoverState.bind(this, false)} - /> - </ScrollLink> + {!this.props.isDisabled && ( + <ScrollLink + to={this.props.id} + hashSpy={true} + offset={headerSizeToScrollOffset[this.props.headerSize]} + duration={constants.DOCS_SCROLL_DURATION_MS} + containerId={constants.SCROLL_CONTAINER_ID} + > + <AnchorIcon className="zmdi zmdi-link" shouldShowAnchor={this.props.shouldShowAnchor} /> + </ScrollLink> + )} </div> ); } - private _setHoverState(isHovering: boolean): void { - this.setState({ - isHovering, - }); - } } diff --git a/packages/react-shared/src/components/markdown_paragraph_block.tsx b/packages/react-shared/src/components/markdown_paragraph_block.tsx new file mode 100644 index 000000000..eeaef8571 --- /dev/null +++ b/packages/react-shared/src/components/markdown_paragraph_block.tsx @@ -0,0 +1,10 @@ +import * as _ from 'lodash'; +import * as React from 'react'; + +import { colors } from '../utils/colors'; + +export interface MarkdownParagraphBlockProps {} + +export const MarkdownParagraphBlock: React.StatelessComponent<MarkdownParagraphBlockProps> = ({ children }) => { + return <span style={{ color: colors.greyTheme, lineHeight: '26px' }}>{children}</span>; +}; diff --git a/packages/react-shared/src/components/markdown_section.tsx b/packages/react-shared/src/components/markdown_section.tsx index e84d2b078..e6a7d80d5 100644 --- a/packages/react-shared/src/components/markdown_section.tsx +++ b/packages/react-shared/src/components/markdown_section.tsx @@ -11,12 +11,14 @@ import { AnchorTitle } from './anchor_title'; import { Link } from './link'; import { MarkdownCodeBlock } from './markdown_code_block'; import { MarkdownLinkBlock } from './markdown_link_block'; +import { MarkdownParagraphBlock } from './markdown_paragraph_block'; export interface MarkdownSectionProps { sectionName: string; markdownContent: string; headerSize?: HeaderSizes; githubLink?: string; + alternativeSectionTitle?: string; } interface DefaultMarkdownSectionProps { @@ -43,20 +45,23 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd const { sectionName, markdownContent, headerSize, githubLink } = this.props as PropsWithDefaults; const id = utils.getIdFromName(sectionName); - const finalSectionName = utils.convertCamelCaseToSpaces(sectionName); + const formattedSectionName = utils.convertCamelCaseToSpaces(sectionName); + const title = !_.isUndefined(this.props.alternativeSectionTitle) + ? this.props.alternativeSectionTitle + : formattedSectionName; return ( <div className="md-px1 sm-px2 overflow-hidden" onMouseOver={this._setAnchorVisibility.bind(this, true)} onMouseOut={this._setAnchorVisibility.bind(this, false)} > - <ScrollElement name={id}> - <div className="clearfix pt3"> + <ScrollElement name={id} style={{ paddingBottom: 20 }}> + <div className="clearfix" style={{ paddingTop: 30, paddingBottom: 20 }}> <div className="col lg-col-8 md-col-8 sm-col-12"> - <span style={{ textTransform: 'capitalize', color: colors.grey700 }}> + <span style={{ color: colors.grey700 }}> <AnchorTitle headerSize={headerSize} - title={finalSectionName} + title={_.capitalize(title)} id={id} shouldShowAnchor={this.state.shouldShowAnchor} /> @@ -72,13 +77,21 @@ export class MarkdownSection extends React.Component<MarkdownSectionProps, Markd )} </div> </div> - <hr style={{ border: `1px solid ${colors.lightestGrey}` }} /> <ReactMarkdown source={markdownContent} escapeHtml={false} renderers={{ code: MarkdownCodeBlock, link: MarkdownLinkBlock, + paragraph: MarkdownParagraphBlock, + }} + /> + <div + style={{ + width: '100%', + height: 1, + backgroundColor: colors.grey300, + marginTop: 32, }} /> </ScrollElement> diff --git a/packages/react-shared/src/components/nested_sidebar_menu.tsx b/packages/react-shared/src/components/nested_sidebar_menu.tsx index 5b6076df6..f734dc654 100644 --- a/packages/react-shared/src/components/nested_sidebar_menu.tsx +++ b/packages/react-shared/src/components/nested_sidebar_menu.tsx @@ -8,97 +8,100 @@ import { colors } from '../utils/colors'; import { utils } from '../utils/utils'; import { Link } from './link'; -import { VersionDropDown } from './version_drop_down'; export interface NestedSidebarMenuProps { sectionNameToLinks: ObjectMap<ALink[]>; - subsectionNameToLinks?: ObjectMap<ALink[]>; sidebarHeader?: React.ReactNode; - shouldDisplaySectionHeaders?: boolean; - onMenuItemClick?: () => void; - selectedVersion?: string; - versions?: string[]; - onVersionSelected?: (semver: string) => void; shouldReformatMenuItemNames?: boolean; } -export interface NestedSidebarMenuState {} +export interface NestedSidebarMenuState { + scrolledToId?: string; +} const styles: Styles = { - menuItemWithHeaders: { + menuItem: { minHeight: 0, + paddingLeft: 8, + borderRadius: 6, }, - menuItemWithoutHeaders: { - minHeight: 48, - }, - menuItemInnerDivWithHeaders: { + menuItemInnerDiv: { color: colors.grey800, fontSize: 14, lineHeight: 2, padding: 0, + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', }, }; export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, NestedSidebarMenuState> { public static defaultProps: Partial<NestedSidebarMenuProps> = { - shouldDisplaySectionHeaders: true, - onMenuItemClick: _.noop.bind(_), shouldReformatMenuItemNames: true, - subsectionNameToLinks: {}, }; + private _urlIntervalCheckId: number | undefined = undefined; + constructor(props: NestedSidebarMenuProps) { + super(props); + this.state = {}; + } + public componentDidMount(): void { + this._urlIntervalCheckId = window.setInterval(() => { + const scrollId = location.hash.slice(1); + if (scrollId !== this.state.scrolledToId) { + this.setState({ + scrolledToId: scrollId, + }); + } + }, 200); + } + public componentWillUnmount(): void { + window.clearInterval(this._urlIntervalCheckId); + } public render(): React.ReactNode { const navigation = _.map(this.props.sectionNameToLinks, (links: ALink[], sectionName: string) => { const finalSectionName = utils.convertCamelCaseToSpaces(sectionName); - if (this.props.shouldDisplaySectionHeaders) { - // tslint:disable-next-line:no-unused-variable - return ( - <div key={`section-${sectionName}`} className="py1" style={{ color: colors.linkSectionGrey }}> - <div style={{ fontWeight: 'bold', fontSize: 15, letterSpacing: 0.5 }} className="py1"> - {finalSectionName.toUpperCase()} - </div> - {this._renderMenuItems(links)} + // tslint:disable-next-line:no-unused-variable + return ( + <div key={`section-${sectionName}`} className="py1" style={{ color: colors.greyTheme }}> + <div style={{ fontSize: 14, letterSpacing: 0.5 }} className="py1 pl1"> + {finalSectionName.toUpperCase()} </div> - ); - } else { - return <div key={`section-${sectionName}`}>{this._renderMenuItems(links)}</div>; - } + {this._renderMenuItems(links)} + </div> + ); }); - const maxWidthWithScrollbar = 307; return ( <div> {this.props.sidebarHeader} - {!_.isUndefined(this.props.versions) && - !_.isUndefined(this.props.selectedVersion) && - !_.isUndefined(this.props.onVersionSelected) && ( - <div style={{ maxWidth: maxWidthWithScrollbar }}> - <VersionDropDown - selectedVersion={this.props.selectedVersion} - versions={this.props.versions} - onVersionSelected={this.props.onVersionSelected} - /> - </div> - )} - <div className="pl1">{navigation}</div> + <div>{navigation}</div> </div> ); } private _renderMenuItems(links: ALink[]): React.ReactNode[] { - const menuItemStyles = this.props.shouldDisplaySectionHeaders - ? styles.menuItemWithHeaders - : styles.menuItemWithoutHeaders; - const menuItemInnerDivStyles = this.props.shouldDisplaySectionHeaders ? styles.menuItemInnerDivWithHeaders : {}; + const scrolledToId = this.state.scrolledToId; const menuItems = _.map(links, link => { const finalMenuItemName = this.props.shouldReformatMenuItemNames ? utils.convertDashesToSpaces(link.title) : link.title; + let menuItemStyle = styles.menuItem; + let menuItemInnerDivStyle = styles.menuItemInnerDiv; + const isScrolledTo = link.to === scrolledToId; + if (isScrolledTo) { + menuItemStyle = { + ...menuItemStyle, + backgroundColor: colors.lightLinkBlue, + }; + menuItemInnerDivStyle = { + ...menuItemInnerDivStyle, + color: colors.white, + fontWeight: 'bold', + }; + } return ( <div key={`menuItem-${finalMenuItemName}`}> <Link to={link.to} shouldOpenInNewTab={link.shouldOpenInNewTab}> - <MenuItem - style={menuItemStyles} - innerDivStyle={menuItemInnerDivStyles} - onClick={this._onMenuItemClick.bind(this)} - > + <MenuItem style={menuItemStyle} innerDivStyle={menuItemInnerDivStyle}> <span style={{ textTransform: this.props.shouldReformatMenuItemNames ? 'capitalize' : 'none', @@ -108,50 +111,9 @@ export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, N </span> </MenuItem> </Link> - {this._renderMenuItemSubsections(link.title)} </div> ); }); return menuItems; } - private _renderMenuItemSubsections(menuItemName: string): React.ReactNode { - if ( - _.isUndefined(this.props.subsectionNameToLinks) || - _.isUndefined(this.props.subsectionNameToLinks[menuItemName]) - ) { - return null; - } - return this._renderSubsectionLinks(menuItemName, this.props.subsectionNameToLinks[menuItemName]); - } - private _renderSubsectionLinks(menuItemName: string, links: ALink[]): React.ReactNode { - return ( - <ul style={{ margin: 0, listStyleType: 'none', paddingLeft: 0 }} key={menuItemName}> - {_.map(links, link => { - const name = `${menuItemName}-${link.title}`; - return ( - <li key={`menuSubsectionItem-${name}`}> - <Link to={link.to} shouldOpenInNewTab={link.shouldOpenInNewTab}> - <MenuItem - style={{ minHeight: 35 }} - innerDivStyle={{ - paddingLeft: 16, - fontSize: 14, - lineHeight: '35px', - }} - onClick={this._onMenuItemClick.bind(this)} - > - {link.title} - </MenuItem> - </Link> - </li> - ); - })} - </ul> - ); - } - private _onMenuItemClick(): void { - if (!_.isUndefined(this.props.onMenuItemClick)) { - this.props.onMenuItemClick(); - } - } } diff --git a/packages/react-shared/src/components/version_drop_down.tsx b/packages/react-shared/src/components/version_drop_down.tsx deleted file mode 100644 index 5ff4bed54..000000000 --- a/packages/react-shared/src/components/version_drop_down.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import MenuItem from '@material-ui/core/MenuItem'; -import Select from '@material-ui/core/Select'; -import * as _ from 'lodash'; -import * as React from 'react'; - -export interface VersionDropDownProps { - selectedVersion: string; - versions: string[]; - onVersionSelected: (semver: string) => void; -} - -export interface VersionDropDownState {} - -export class VersionDropDown extends React.Component<VersionDropDownProps, VersionDropDownState> { - public render(): React.ReactNode { - return ( - <div className="mx-auto" style={{ width: 120 }}> - <Select value={this.props.selectedVersion} onChange={this._updateSelectedVersion.bind(this)}> - {this._renderDropDownItems()} - </Select> - </div> - ); - } - private _renderDropDownItems(): React.ReactNode[] { - const items = _.map(this.props.versions, version => { - return ( - <MenuItem key={version} value={version}> - v{version} - </MenuItem> - ); - }); - return items; - } - private _updateSelectedVersion(event: React.ChangeEvent<HTMLSelectElement>): void { - this.props.onVersionSelected(event.target.value); - } -} diff --git a/packages/react-shared/src/utils/colors.ts b/packages/react-shared/src/utils/colors.ts index 596c17e83..a4dd7fefa 100644 --- a/packages/react-shared/src/utils/colors.ts +++ b/packages/react-shared/src/utils/colors.ts @@ -18,6 +18,7 @@ const baseColors = { darkGrey: '#818181', landingLinkGrey: '#919191', linkSectionGrey: '#999999', + greyTheme: '#666666', grey700: '#616161', grey750: '#515151', grey800: '#424242', |