diff --git a/www/src/components/TableCells.tsx b/www/src/components/TableCells.tsx new file mode 100644 index 0000000000..2dd00c84a2 --- /dev/null +++ b/www/src/components/TableCells.tsx @@ -0,0 +1,76 @@ +import React from 'react'; +import MeasuredItem from './MeasuredItem'; +import measuredTypeProps from './typography-page/measuredTypeProps'; + +export type CodeCellType = { + value: string | number | undefined, +}; + +export type DataTableRowType = { + row: { + original: { + name?: string, + size?: string, + className?: string, + text?: string, + } + }, +}; + +export function ClassNameCell({ value }: CodeCellType) { + if (!value) { + return null; + } + + return ( + + .{value} + + ); +} + +export function TextCell({ value }: CodeCellType) { + return ( +

+ {value} +

+ ); +} + +export function CodeCell({ value }: CodeCellType) { + return ( + + {value} + + ); +} + +export function DesktopMeasuredCell({ row } : DataTableRowType) { + return ( + +

+ {row.original.text} +

+
+ ); +} + +export function MobileMeasuredCell({ row } : DataTableRowType) { + return ( +
+ +

+ {row.original.text} +

+
+
+ ); +} + +export function StyleCell({ row } : DataTableRowType) { + return ( +

+ {row.original.text} +

+ ); +} diff --git a/www/src/components/typography-page/Alignment.tsx b/www/src/components/typography-page/Alignment.tsx new file mode 100644 index 0000000000..bc70f9698d --- /dev/null +++ b/www/src/components/typography-page/Alignment.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +// @ts-ignore +import { DataTable } from '~paragon-react'; +import { ClassNameCell, StyleCell } from '../TableCells'; + +const alignmentClassesAndDescriptions = [ + { className: 'text-left', text: 'left text.' }, + { className: 'text-right', text: 'right text.' }, + { className: 'text-center', text: 'center text.' }, + { + className: 'text-justify', + text: 'The text-justify class specifies the justification method of text. ' + + 'This text-justify class spreads the words into the complete line with equal spaces.', + }, + { + className: 'text-wrap', + text: 'Use text-wrap to cause text to wrap normally within an element. Newlines and spaces will be collapsed.', + }, + { + className: 'text-nowrap', + text: 'Use text-nowrap to prevent text from wrapping within an element. Newlines and spaces will be collapsed. ' + + 'You can prevent line breaks and text wrapping for specific elements', + }, +]; + +export default function Alignment() { + return ( + <> +

Alignment

+
+ + + +
+ + ); +} diff --git a/www/src/components/typography-page/Body.tsx b/www/src/components/typography-page/Body.tsx new file mode 100644 index 0000000000..89e33d113b --- /dev/null +++ b/www/src/components/typography-page/Body.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import MeasuredItem from '../MeasuredItem'; +import measuredTypeProps from './measuredTypeProps'; +// @ts-ignore +import { DataTable } from '~paragon-react'; + +import { DesktopMeasuredCell, ClassNameCell } from '../TableCells'; + +const bodyClassesAndDescriptions = [ + { className: 'lead', text: 'Large Body' }, + { className: '', text: 'Body' }, + { className: 'small', text: 'Small Body' }, + { className: 'x-small', text: 'Extra Small Body' }, + { className: 'micro', text: 'Micro Body' }, +]; + +export default function Body() { + return ( + <> +

Body

+
+ + + +
+ + ); +} diff --git a/www/src/components/typography-page/DecorationAndEmphasis.tsx b/www/src/components/typography-page/DecorationAndEmphasis.tsx new file mode 100644 index 0000000000..b1bea15ef2 --- /dev/null +++ b/www/src/components/typography-page/DecorationAndEmphasis.tsx @@ -0,0 +1,41 @@ +import React from 'react'; +// @ts-ignore +import { DataTable } from '~paragon-react'; +import { ClassNameCell, StyleCell } from '../TableCells'; + +const decorationAndEmphasisClassesAndDescriptions = [ + { className: 'text-lowercase', text: 'Lowercase text.' }, + { className: 'text-uppercase', text: 'uppercase text.' }, + { className: 'text-capitalize', text: 'capitalize text.' }, + { className: 'text-decoration-none', text: 'No decorations.' }, + { className: 'font-italic', text: 'Italic text.' }, + { className: 'font-weight-bold', text: 'Bold text.' }, + { className: 'font-weight-normal', text: 'Regular text.' }, +]; + +export default function DecorationAndEmphasis() { + return ( + <> +

Decoration and Emphasis

+
+ + + +
+ + ); +} diff --git a/www/src/components/typography-page/Display.tsx b/www/src/components/typography-page/Display.tsx new file mode 100644 index 0000000000..9fc3a6bfe1 --- /dev/null +++ b/www/src/components/typography-page/Display.tsx @@ -0,0 +1,39 @@ +import React from 'react'; +// @ts-ignore +import { DataTable } from '~paragon-react'; + +import { ClassNameCell, DesktopMeasuredCell, MobileMeasuredCell } from '../TableCells'; + +const displaySizes = [1, 2, 3, 4]; + +export default function Display() { + return ( + <> +

Display

+
+ ({ text: `Display ${size}`, className: `display-${size}` }))} + columns={[ + { + Header: 'Desktop', + Cell: DesktopMeasuredCell, + }, + { + Header: 'Mobile', + Cell: MobileMeasuredCell, + }, + { + id: 'css-class', + Header: 'CSS Class', + accessor: 'className', + Cell: ClassNameCell, + }, + ]} + > + + +
+ + ); +} diff --git a/www/src/components/typography-page/Headings.tsx b/www/src/components/typography-page/Headings.tsx new file mode 100644 index 0000000000..4b2e11b94c --- /dev/null +++ b/www/src/components/typography-page/Headings.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +// @ts-ignore +import { DataTable } from '~paragon-react'; + +import { MobileMeasuredCell, ClassNameCell, DesktopMeasuredCell } from '../TableCells'; + +const headingSizes = [1, 2, 3, 4, 5, 6]; + +export default function Headings() { + return ( + <> +

Headings

+
+ ({ text: `Heading ${size}`, className: `h${size}` }))} + columns={[ + { + Header: 'Desktop', + Cell: DesktopMeasuredCell, + }, + { + Header: 'Mobile', + Cell: MobileMeasuredCell, + }, + { + Header: 'CSS Class', + accessor: 'className', + Cell: ClassNameCell, + }, + ]} + > + + +
+ + ); +} diff --git a/www/src/components/typography-page/Links.tsx b/www/src/components/typography-page/Links.tsx new file mode 100644 index 0000000000..3adc083b64 --- /dev/null +++ b/www/src/components/typography-page/Links.tsx @@ -0,0 +1,51 @@ +import React from 'react'; +// @ts-ignore +import { DataTable } from '~paragon-react'; +import { TextCell } from '../TableCells'; + +const linksClassesAndDescriptions = [ + { + example: Standalone Link, + description: The default style for a tags that don`t appear in a p tag., + }, + { + example: An inline link in a sentence., + description: For links inside a p or with the .inline-link class name., + }, + { + example: Muted, Standalone Link, + description: .muted-link not in a p tag., + }, + { + example: ( + + An muted, inline link in a sentence. + + ), + description: ( + + For .muted-link links inside a p or with the .inline-link class name. + + ), + }, +]; + +export default function Links() { + return ( + <> +

Links

+
+ + + +
+ + ); +} diff --git a/www/src/components/typography-page/index.tsx b/www/src/components/typography-page/index.tsx new file mode 100644 index 0000000000..4ce784ed33 --- /dev/null +++ b/www/src/components/typography-page/index.tsx @@ -0,0 +1,6 @@ +export { default as AlignmentTable } from './Alignment'; +export { default as BodyTable } from './Body'; +export { default as DecorationAndEmphasisTable } from './DecorationAndEmphasis'; +export { default as DisplayTable } from './Display'; +export { default as HeadingsTable } from './Headings'; +export { default as LinksTable } from './Links'; diff --git a/www/src/components/typography-page/measuredTypeProps.tsx b/www/src/components/typography-page/measuredTypeProps.tsx new file mode 100644 index 0000000000..82e5075cd7 --- /dev/null +++ b/www/src/components/typography-page/measuredTypeProps.tsx @@ -0,0 +1,35 @@ +import React from 'react'; + +const weightLabels: Record = { + 200: 'Light', + 300: 'Light', + 400: 'Regular', + 500: 'Medium', + 600: 'Medium', + 700: 'Bold', + 800: 'Black', +}; + +const measuredTypeProps = { + properties: ['font-size', 'line-height', 'font-family', 'font-weight'], + renderAfter: (measurements: { [x: string]: string; }) => { + const fontFamily = measurements['font-family'] + ? measurements['font-family'].split(',')[0] + : null; + const weight = weightLabels[measurements['font-weight']]; + // only one significant digit if needed + const fontSize = Math.round(Number.parseFloat(measurements['font-size']) * 10) / 10; + const lineHeight = Math.round(Number.parseFloat(measurements['line-height']) * 10) / 10; + + return ( +

+ + {fontFamily} {weight} + + {fontSize}px / {lineHeight}px +

+ ); + }, +}; + +export default measuredTypeProps; diff --git a/www/src/pages/foundations/colors.tsx b/www/src/pages/foundations/colors.tsx index dcb15659a8..61c584ba77 100644 --- a/www/src/pages/foundations/colors.tsx +++ b/www/src/pages/foundations/colors.tsx @@ -2,11 +2,14 @@ import React from 'react'; import { graphql } from 'gatsby'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { Container } from '~paragon-react'; +// @ts-ignore import Color from 'color'; import SEO from '../../components/SEO'; import MeasuredItem from '../../components/MeasuredItem'; import Layout from '../../components/PageLayout'; +import { Container, DataTable } from '~paragon-react'; + +import { CodeCell } from '../../components/TableCells'; const utilityClasses = { bg: (color: string, level: number) => (level ? `bg-${color}-${level}` : `bg-${color}`), @@ -34,11 +37,7 @@ const colors: IColors[] = [ const levels = [100, 200, 300, 400, 500, 600, 700, 800, 900]; -export type ParseColorTypes = { - [key: string]: string | null; -}; - -const selectorColors: ParseColorTypes = {}; +const selectorColors: Record = {}; function parseColors(cssSelectors: { selector: string; declarations: string; }[]) { const colorsAreParsed = Object.keys(selectorColors).length !== 0; @@ -181,29 +180,33 @@ export default function ColorsPage({ data }: IColorsPage) { for theming and attempt to eliminate mixins from the public api.

- +
- - - - @@ -245,7 +250,7 @@ export default function ColorsPage({ data }: IColorsPage) { theme-color(“gray”, 300); -

CSS Class Utilties

+

CSS Class Utilities

Utility classes for backgrounds, borders, and text colors follow the format below: @@ -253,37 +258,23 @@ export default function ColorsPage({ data }: IColorsPage) {

{'.{use}-{color}-{level}'}

-
+ Color Name
A theme color
+ {colors.map(({ themeName }) => ( - {themeName} + + {themeName} + ))}
+ Variant

A number level or element type

+ Levels - {levels.map(level => ( - {level} + {levels.map((level) => ( + + {level} + ))}
Element types @@ -221,8 +224,10 @@ export default function ColorsPage({ data }: IColorsPage) { 'text', 'active', 'dark-text', - ].map(element => ( - {element} + ].map((element) => ( + + {element} + ))}
- - - - - - - - - - - - - - -
UseColorLevel
- bg- -
- border- -
- text- -
-
- {colors.map(({ themeName }) => ( - {themeName}- - ))} - - {levels.map(level => ( - {level} - ))} -
+
+ ({ + use: Object.keys(utilityClasses)[index], + color: themeName, + level: levels[index], + }))} + columns={[ + { Header: 'Use', accessor: 'use', Cell: CodeCell }, + { Header: 'Color', accessor: 'color', Cell: CodeCell }, + { Header: 'Level', accessor: 'level', Cell: CodeCell }, + ]} + > + + +

Background Fills

diff --git a/www/src/pages/foundations/elevation.jsx b/www/src/pages/foundations/elevation.tsx similarity index 90% rename from www/src/pages/foundations/elevation.jsx rename to www/src/pages/foundations/elevation.tsx index ec138987ee..3d03d56f28 100644 --- a/www/src/pages/foundations/elevation.jsx +++ b/www/src/pages/foundations/elevation.tsx @@ -23,7 +23,7 @@ const controlsProps = [ function BoxShadowNode() { const [showToast, setShowToast] = useState(false); - const isBoxShadowCopied = (level, side) => { + const isBoxShadowCopied = (level: number, side: string) => { navigator.clipboard.writeText(`@include pgn-box-shadow(${level}, "${side}");`); setShowToast(true); }; @@ -61,6 +61,25 @@ function BoxShadowNode() { ); } +export interface IBoxShadowToolkit { + id: number, + updateBoxShadow: (shadow: IBoxShadowModel, id: number) => void, + removeBoxShadowLayer: (id: number) => void, + disableBoxShadowLayer: (id: number) => void, + enableBoxShadowLayer: (id: number) => void, + isDisabled: boolean, + canDelete: boolean, +} + +export interface IBoxShadowModel { + x: number, + y: number, + blur: number, + spread: number, + color: string, + inset: boolean, +} + function BoxShadowToolkit({ id, updateBoxShadow, @@ -69,8 +88,8 @@ function BoxShadowToolkit({ enableBoxShadowLayer, isDisabled, canDelete, -}) { - const [boxShadowModel, setBoxShadowModel] = useState({ +}: IBoxShadowToolkit) { + const [boxShadowModel, setBoxShadowModel] = useState({ x: 0, y: 0, blur: 0, @@ -79,7 +98,7 @@ function BoxShadowToolkit({ inset: false, }); - const updateBoxShadowModel = (property, value) => { + const updateBoxShadowModel = (property: string, value: boolean | string) => { global.analytics.track('openedx.paragon.docs.elevation.generator.updated', { property, value }); const newBoxShadowModel = { @@ -107,7 +126,7 @@ function BoxShadowToolkit({ max="100" type={key === 'color' ? 'color' : 'range'} defaultValue="0" - onChange={(e) => updateBoxShadowModel(key, e.target.value)} + onChange={(e: React.ChangeEvent) => updateBoxShadowModel(key, e.target.value)} disabled={isDisabled} /> @@ -175,7 +194,7 @@ BoxShadowToolkit.propTypes = { function BoxShadowGenerator() { const [boxShadows, setBoxShadows] = useState([{ id: 1, enabled: true, style: DEFAULT_BOX_SHADOW }]); - const updateBoxShadow = (shadow, id) => { + const updateBoxShadow = (shadow: IBoxShadowModel, id: number) => { setBoxShadows(boxShadows.map(item => { if (id === item.id) { return { @@ -197,12 +216,12 @@ function BoxShadowGenerator() { ]); }; - const removeBoxShadowLayer = (toolkitId) => { + const removeBoxShadowLayer = (toolkitId: number) => { global.analytics.track('openedx.paragon.elevation.shadow-generator.layer.removed'); setBoxShadows(boxShadows.filter((shadow) => shadow.id !== toolkitId)); }; - const disableBoxShadowLayer = (toolkitId) => { + const disableBoxShadowLayer = (toolkitId: number) => { global.analytics.track('openedx.paragon.elevation.shadow-generator.layer.disabled'); const updatedBoxShadows = boxShadows .map((shadow) => { @@ -214,7 +233,7 @@ function BoxShadowGenerator() { setBoxShadows(updatedBoxShadows); }; - const enableBoxShadowLayer = (toolkitId) => { + const enableBoxShadowLayer = (toolkitId: string | number) => { global.analytics.track('openedx.paragon.elevation.shadow-generator.layer.enabled'); const updatedBoxShadows = boxShadows .map((shadow) => { @@ -305,28 +324,29 @@ export default function ElevationPage() {

Mixin

- pgn-box-shadow($level, $side) + pgn-box-shadow($level, $direction) +
- +
- - - -
+ Direction name + {boxShadowSides.map(side => ( {side} ))}
+ Levels

Box-shadows elevation levels

+ {boxShadowLevels.map(level => ( {level} ))} diff --git a/www/src/pages/foundations/typography.tsx b/www/src/pages/foundations/typography.tsx index 06c6e09966..8e9cb1f2b6 100644 --- a/www/src/pages/foundations/typography.tsx +++ b/www/src/pages/foundations/typography.tsx @@ -1,45 +1,15 @@ -/* eslint-disable jsx-a11y/anchor-is-valid */ import React from 'react'; -import { Container } from '~paragon-react'; -import SEO from '../../components/SEO'; -import MeasuredItem from '../../components/MeasuredItem'; import Layout from '../../components/PageLayout'; - -export type WeightLabelsTypes = { - [key: string]: string, -}; - -const weightLabels: WeightLabelsTypes = { - 200: 'Light', - 300: 'Light', - 400: 'Regular', - 500: 'Medium', - 600: 'Medium', - 700: 'Bold', - 800: 'Black', -}; - -const measuredTypeProps = { - properties: ['font-size', 'line-height', 'font-family', 'font-weight'], - renderAfter: (measurements: { [x: string]: string; }) => { - const fontFamily = measurements['font-family'] - ? measurements['font-family'].split(',')[0] - : null; - const weight = weightLabels[measurements['font-weight']]; - // only one significant digit if needed - const fontSize = Math.round(Number.parseFloat(measurements['font-size']) * 10) / 10; - const lineHeight = Math.round(Number.parseFloat(measurements['line-height']) * 10) / 10; - - return ( -

- - {fontFamily} {weight} - - {fontSize}px / {lineHeight}px -

- ); - }, -}; +import SEO from '../../components/SEO'; +import { Container } from '~paragon-react'; +import { + HeadingsTable, + BodyTable, + DisplayTable, + DecorationAndEmphasisTable, + LinksTable, + AlignmentTable, +} from '../../components/typography-page'; export default function TypographyPage() { return ( @@ -48,349 +18,13 @@ export default function TypographyPage() { {/* eslint-disable-next-line react/jsx-pascal-case */}

Typography

- - - - - - - - - - - {[1, 2, 3, 4, 5, 6].map(headingSize => ( - - - - - - ))} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {[1, 2, 3, 4].map(displaySize => ( - - - - - - ))} - - - - - - - - - - - - - - - - - - - - - - -
-

Headings

-
DesktopMobileCSS Class
- -

- Heading {headingSize} -

-
-
- -

- Heading {headingSize} -

-
-
- .h{headingSize} -
- -

Heading Label

-
- A heading label is usually paired with and proceeds a Heading. -
- .heading-label -
-

Body

-
Desktop & MobileCSS Class
- -

Large Body

-
-
- .lead -
- -

Body

-
-
- -

Small Body

-
-
- .small -
- -

Extra Small Body

-
-
- .x-small -
- -

Micro Body

-
-
- .micro -
-

Display

-
DesktopMobileCSS Class
- -

- Display {displaySize} -

-
-
- -

- Display {displaySize} -

-
-
- .display-{displaySize} -
-

Links

-
- Standalone Link - - - The default style for a tags that don't appear in - a p tag. - -
-

- An{' '} - - inline link - {' '} - in a sentence. -

-
- - For links inside a p or with the{' '} - .inline-link class name. - -
- - Muted, Standalone Link - - - - .muted-link not in a p tag. - -
-

- An{' '} - - muted, inline link - {' '} - in a sentence. -

-
- - For .muted-link links inside a p or - with the .inline-link class name. - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Decoration and Emphasis

-
StyleCSS Class
-

Lowercase text.

-
- .text-lowercase -
-

uppercase text.

-
- .text-uppercase -
-

capitalize text.

-
- .text-capitalize -
-

No decorations.

-
- .text-decoration-none -
-

Italic text.

-
- .text-italic -
-

Bold text.

-
- .font-weight-bold -
-

Regular text.

-
- .font-weight-normal -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Alignment

-
StyleCSS Class
-

left text.

-
- .text-left -
-

right text.

-
- .text-right -
-

center text.

-
- .text-center -
-

justify text.

-

- At the edge of forever tendrils of gossamer clouds corpus - callosum culture Vangelis dispassionate extraterrestrial - observer. -

-
- .text-justify -
-

wrap text.

-
- .text-wrap -
-

nowrap text.

-
- .text-nowrap -
+
+ + + + + + ); diff --git a/www/src/scss/base.scss b/www/src/scss/base.scss index b7ee26249c..85e385a2ab 100644 --- a/www/src/scss/base.scss +++ b/www/src/scss/base.scss @@ -25,3 +25,7 @@ body { .container-fluid { max-width: none; } + +.fs-16 { + font-size: 16px; +}