Skip to content

Commit

Permalink
Implement MDX-specific components
Browse files Browse the repository at this point in the history
This commit initially includes the `Image` (wraps `GatsbyImage`) and
`ShinkWidth` component placed in the new atom core package
`mdx-elements`.

GH-129
  • Loading branch information
arcticicestudio committed Mar 9, 2019
1 parent 6b861a1 commit 405016f
Show file tree
Hide file tree
Showing 8 changed files with 299 additions and 4 deletions.
83 changes: 83 additions & 0 deletions src/components/atoms/core/mdx-elements/Image.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import React from "react";
import PropTypes from "prop-types";
import GatsbyImage from "gatsby-image";
import styled, { css } from "styled-components";
import { rgba } from "polished";

import { Figure } from "atoms/core/html-elements";
import { contentMdxImageFluidPropTypes } from "data/graphql/fragmentPropTypes";
import { colors, motion, themedMode, MODE_BRIGHT_SNOW_FLURRY, MODE_DARK_NIGHT_FROST } from "styles/theme";

const boxShadow = themedMode({
[MODE_BRIGHT_SNOW_FLURRY]: css`0px 10px 20px 2px ${rgba(colors.shadow.decent[MODE_BRIGHT_SNOW_FLURRY], 0.35)}`,
[MODE_DARK_NIGHT_FROST]: css`0px 10px 20px 2px ${rgba(colors.shadow.decent[MODE_DARK_NIGHT_FROST], 0.2)}`
});

const figcaptionFontColor = themedMode({
[MODE_BRIGHT_SNOW_FLURRY]: colors.font.faded[MODE_BRIGHT_SNOW_FLURRY],
[MODE_DARK_NIGHT_FROST]: colors.font.faded[MODE_DARK_NIGHT_FROST]
});

const Img = styled(GatsbyImage)`
border-radius: ${({ rounded }) => rounded && "8px"};
max-width: ${({ fluid, fillSize }) => (fillSize < 100 ? `${fillSize}%` : `${fluid.presentationWidth}px`)};
margin: ${({ hasCaption }) => `0 auto ${hasCaption ? "2em" : "6em"} auto`};
box-shadow: ${({ dropShadow }) => dropShadow && boxShadow};
transition: box-shadow ${motion.speed.duration.transition.base.themeModeSwitch}ms ease-in-out;
`;

const FigCaption = styled.figcaption`
color: ${figcaptionFontColor};
margin-bottom: 6em;
margin-left: 1em;
font-size: 0.875em;
`;

/**
* An Gatsby image wrapped in a `<figure>` element with an optional caption.
*
* @author Arctic Ice Studio <[email protected]>
* @author Sven Greb <[email protected]>
* @since 0.10.0
* @see https://www.gatsbyjs.org/docs/working-with-images
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/figure
*/
const Image = ({ children, dropShadow, rounded, fillSize, src, ...passProps }) => (
<Figure>
<Img
dropShadow={dropShadow}
fillSize={fillSize}
fluid={src.fluid && src.fluid}
hasCaption={!!children}
rounded={rounded}
{...passProps}
/>
{children && <FigCaption>{children}</FigCaption>}
</Figure>
);

Image.propTypes = {
children: PropTypes.node,
dropShadow: PropTypes.bool,
fillSize: PropTypes.number,
rounded: PropTypes.bool,
...contentMdxImageFluidPropTypes
};

Image.defaultProps = {
children: null,
dropShadow: false,
fillSize: 100,
rounded: false
};

export default Image;
34 changes: 34 additions & 0 deletions src/components/atoms/core/mdx-elements/ShrinkedWidth.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import styled from "styled-components";
import PropTypes from "prop-types";

/**
* An container component that shrinks the maxiumum width for a better visual style and more readable text.
* The maximum width in percent can be customized using the `value` prop.
*
* @author Arctic Ice Studio <[email protected]>
* @author Sven Greb <[email protected]>
* @since 0.10.0
*/
const ShrinkedWidth = styled.div`
max-width: ${({ value }) => `${value}%`};
margin: 0 auto;
`;

ShrinkedWidth.propTypes = {
value: PropTypes.number
};

ShrinkedWidth.defaultProps = {
value: 60
};

export default ShrinkedWidth;
126 changes: 126 additions & 0 deletions src/components/atoms/core/mdx-elements/Video.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import React, { useRef, useState } from "react";
import PropTypes from "prop-types";
import styled, { css } from "styled-components";

import { Figure } from "atoms/core/html-elements";
import { contentMdxImageFluidPropTypes, contentMdxMediaFilePropTypes } from "data/graphql/fragmentPropTypes";
import { mixinDropShadowAmbientLight, mixinDropShadowDirectLight, transitionThemedModeSwitch } from "styles/shared";

import FigCaption from "./shared/FigCaption";
import Image from "./Image";

const Vid = styled.video`
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
display: block;
max-width: ${({ fillSize }) => fillSize}%;
margin: ${({ hasCaption }) => `0 auto ${hasCaption ? "2em" : "6em"} auto`};
border-radius: ${({ rounded }) => rounded && "8px"};
box-shadow: ${({ dropShadow }) =>
dropShadow &&
css`
${mixinDropShadowDirectLight()}, ${mixinDropShadowAmbientLight()}
`};
`;

const Container = styled(Figure)`
position: relative;
`;

const PosterImage = styled(Image)`
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
opacity: ${({ videoLoaded }) => (videoLoaded ? 0 : 1)};
transition: ${transitionThemedModeSwitch("opacity", 0, "ease")};
`;

/**
* An video wrapped in a `<figure>` element with an optional caption.
* Note that the video is muted and blocked for autoplay (deconstructed `autoPlay` prop) by default to prevent problems
* with browser-specific autoplay blocking mechanisms. The autoplay logic is handled by the component to allow to make
* use of "Gatsby Sharp" for a responsive poster image.
*
* @author Arctic Ice Studio <[email protected]>
* @author Sven Greb <[email protected]>
* @since 0.10.0
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video
* @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/canplaythrough_event
* @see https://developers.google.com/web/updates/2016/03/play-returns-promise
*/
const Video = ({ autoPlay, children, dropShadow, fillSize, poster, rounded, sources, ...passProps }) => {
const videoRef = useRef(null);
const [videoLoaded, setVideoLoaded] = useState(false);

function playVideo() {
return videoRef.current.play();
}

function handleOnVideoLoaded() {
setVideoLoaded(true);
playVideo();
}

return (
<Container>
<Vid
ref={videoRef}
dropShadow={dropShadow}
fillSize={fillSize}
hasCaption={!!children}
muted
onCanPlayThrough={handleOnVideoLoaded}
onTouchStart={playVideo}
playsInline
rounded={rounded}
{...passProps}
>
{sources.map(src => (
<source key={src.publicURL} src={src?.publicURL} type={`video/${src.extension}`} />
))}
</Vid>
<PosterImage
dropShadow={dropShadow}
fillSize={fillSize}
fluid={poster}
rounded={rounded}
videoLoaded={videoLoaded}
/>
{children && <FigCaption>{children}</FigCaption>}
</Container>
);
};

Video.propTypes = {
autoPlay: PropTypes.bool,
children: PropTypes.node,
dropShadow: PropTypes.bool,
fillSize: PropTypes.number,
poster: PropTypes.shape({ ...contentMdxImageFluidPropTypes }).isRequired,
rounded: PropTypes.bool,
sources: PropTypes.arrayOf(PropTypes.shape({ ...contentMdxMediaFilePropTypes })).isRequired
};

Video.defaultProps = {
autoPlay: false,
children: null,
dropShadow: false,
fillSize: 100,
rounded: false
};

export default Video;
14 changes: 14 additions & 0 deletions src/components/atoms/core/mdx-elements/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import Image from "./Image";
import ShrinkedWidth from "./ShrinkedWidth";
import Video from "./Video";

export { Image, ShrinkedWidth, Video };
13 changes: 12 additions & 1 deletion src/data/graphql/fragmentPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ const contentMdxImageFluidPropTypes = {
})
};

/**
* GraphQL fragment prop types for a media file of a MDX content document.
*/
const contentMdxMediaFilePropTypes = {
extension: PropTypes.string,
name: PropTypes.string,
publicURL: PropTypes.string,
relativePath: PropTypes.string
};

/**
* GraphQL fragment prop types for the frontmatter of a MDX content document.
*/
Expand Down Expand Up @@ -123,5 +133,6 @@ export {
contentBlogPostFrontmatterPropTypes,
contentDocsPagePropTypes,
contentDocsPageFrontmatterPropTypes,
contentMdxImageFluidPropTypes
contentMdxImageFluidPropTypes,
contentMdxMediaFilePropTypes
};
26 changes: 26 additions & 0 deletions src/styles/theme/motion/easings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <[email protected]>
* Copyright (C) 2018-present Sven Greb <[email protected]>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

/**
* @file Provides motion easing values.
* @author Arctic Ice Studio <[email protected]>
* @author Sven Greb <[email protected]>
* @since 0.10.0
* @see https://material.io/design/motion/speed.html#easing
* @see https://easings.net
*/

const easings = {
easeInQuad: [0.55, 0.085, 0.68, 0.53],
easeInOutQuad: [0.455, 0.03, 0.515, 0.955],
easeOutCubic: [0.215, 0.61, 0.355, 1],
easeOutQuart: [0.165, 0.84, 0.44, 1]
};

export default easings;
6 changes: 3 additions & 3 deletions src/styles/theme/motion/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
* @file Provides motion related values like animations inspired by Material Design Guidelines.
* @author Arctic Ice Studio <[email protected]>
* @author Sven Greb <[email protected]>
* @see https://material.io/design/motion/speed.html
* @since 0.2.0
*/

import easings from "./easings";
import speed, { duration } from "./speed";

const motion = { speed };
const motion = { easings, speed };

export { speed, duration };
export { easings, speed, duration };
export default motion;
1 change: 1 addition & 0 deletions src/styles/theme/motion/speed.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const duration = {
transition: {
base: { themeModeSwitch: 400 },
area: {
fullscreen: 400,
large: 300,
medium: 250,
small: 100
Expand Down

0 comments on commit 405016f

Please sign in to comment.