diff options
| author | Furkan Sahin <furkan-dev@proton.me> | 2022-05-30 21:11:40 -0500 |
|---|---|---|
| committer | Furkan Sahin <furkan-dev@proton.me> | 2026-02-20 15:13:00 -0500 |
| commit | 16baa822cc897fa8764c14861f7869f46ca50e30 (patch) | |
| tree | a970198a53dd4449ed8702d90433fda787075bcd /components | |
| parent | 56a2f28565244127bb91ebabac731eaef950f3ec (diff) | |
Compress results gif
Diffstat (limited to 'components')
| -rw-r--r-- | components/Box/index.tsx | 26 | ||||
| -rw-r--r-- | components/BreadCrumbs/breadcrumbs.module.scss (renamed from components/Breadcrumbs/breadcrumbs.module.scss) | 0 | ||||
| -rw-r--r-- | components/BreadCrumbs/index.tsx (renamed from components/Breadcrumbs/index.tsx) | 22 | ||||
| -rw-r--r-- | components/Button/index.tsx | 39 | ||||
| -rw-r--r-- | components/Code/index.tsx | 10 | ||||
| -rw-r--r-- | components/Input/index.tsx | 22 | ||||
| -rw-r--r-- | components/Link/index.tsx | 23 | ||||
| -rw-r--r-- | components/Link/link.module.scss | 11 | ||||
| -rw-r--r-- | components/List/index.tsx | 52 | ||||
| -rw-r--r-- | components/List/list.module.scss | 41 | ||||
| -rw-r--r-- | components/Markdown/index.tsx | 18 | ||||
| -rw-r--r-- | components/Markdown/markdown.module.scss | 111 | ||||
| -rw-r--r-- | components/Markdown/markdown.scss | 418 | ||||
| -rw-r--r-- | components/PathCrumbs/index.tsx | 61 | ||||
| -rw-r--r-- | components/TextArea/index.tsx | 22 | ||||
| -rw-r--r-- | components/Typ/index.tsx | 47 | ||||
| -rw-r--r-- | components/Typ/typo.module.scss | 3 | ||||
| -rw-r--r-- | components/ViewPort/index.tsx | 34 | ||||
| -rw-r--r-- | components/utils/inputElementStyle.tsx | 16 | ||||
| -rw-r--r-- | components/utils/systemProps.tsx | 107 |
20 files changed, 941 insertions, 142 deletions
diff --git a/components/Box/index.tsx b/components/Box/index.tsx new file mode 100644 index 0000000..f81fa5b --- /dev/null +++ b/components/Box/index.tsx @@ -0,0 +1,26 @@ +import { getSystemStyle, SystemProps } from '../utils/systemProps'; + +interface BoxProps extends SystemProps { + style?: React.CSSProperties; + children?: React.ReactNode; + el?: keyof React.ReactHTML; +}; + +const Box: React.FC<BoxProps> = ({ el, style, children, ...props}) => { + const systemStyle = getSystemStyle(props, style); + + let Tag = el; + + if(!el) { + Tag = 'div' as keyof React.ReactHTML; + } + + return ( + // @ts-ignore + <Tag style={systemStyle}> + { children } + </Tag> + ); +}; + +export default Box; diff --git a/components/Breadcrumbs/breadcrumbs.module.scss b/components/BreadCrumbs/breadcrumbs.module.scss index 6facea4..6facea4 100644 --- a/components/Breadcrumbs/breadcrumbs.module.scss +++ b/components/BreadCrumbs/breadcrumbs.module.scss diff --git a/components/Breadcrumbs/index.tsx b/components/BreadCrumbs/index.tsx index c5a17b8..98b20b4 100644 --- a/components/Breadcrumbs/index.tsx +++ b/components/BreadCrumbs/index.tsx @@ -1,15 +1,16 @@ import React, { Children, FC } from "react"; -import Link from "next/link"; +import Link from '../Link'; import styles from './breadcrumbs.module.scss'; import clsx from 'clsx'; -export type BreadcrumbsProps = { +export type BreadCrumbsProps = { className?: string; style?: object; + children: React.ReactNode; }; -const Breadcrumbs : FC<BreadcrumbsProps> = ({children, className, ...props}) => ( - <span className={clsx(styles.breadcrumbs, className)} {...props}> +const BreadCrumbs : FC<BreadCrumbsProps> = ({children, className, style, ...props}) => ( + <span style={{ whiteSpace: 'nowrap', ...style }} className={clsx(styles.breadcrumbs, className)} {...props}> {Children.map(children, (child, index) => { return ( <> @@ -25,7 +26,11 @@ const Breadcrumbs : FC<BreadcrumbsProps> = ({children, className, ...props}) => </span> ); -const Crumb : FC = ({children, ...props}) => ( +export type CrumbProps = { + children: React.ReactNode; +}; + +const Crumb : FC<CrumbProps> = ({children, ...props}) => ( <span className={styles.crumb} {...props}> {children} </span> @@ -33,18 +38,19 @@ const Crumb : FC = ({children, ...props}) => ( export type LinkCrumbProps = { href: string; + children: React.ReactNode; } const LinkCrumb : FC<LinkCrumbProps> = ({children, href, ...props}) => ( <Crumb> <Link href={href}> - <a>{children}</a> + {children} </Link> </Crumb> ); export { Crumb, - Breadcrumbs, + BreadCrumbs, LinkCrumb -};
\ No newline at end of file +}; diff --git a/components/Button/index.tsx b/components/Button/index.tsx new file mode 100644 index 0000000..9eb2e95 --- /dev/null +++ b/components/Button/index.tsx @@ -0,0 +1,39 @@ +import React, { TextareaHTMLAttributes } from 'react'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; + +interface ButtonProps + extends React.ButtonHTMLAttributes<HTMLButtonElement>, + SystemProps +{ } + +const Button: React.FC<ButtonProps> = ({ style, ...props }) => { + style = { + margin: '0.25rem 0.125rem', + cursor: 'pointer', + padding: '0.375rem 0.75rem', + borderRadius: '0.25rem', + textAlign: 'center', + verticalAlign: 'middle', + display: 'inline-block', + userSelect: 'none', + + fontFamily: 'inherit', + fontSize: '.95rem', + lineHeight: '1.15', + + // Color + color: '#fff', + backgroundColor: '#1473ff', + border: '1px solid #1473ff', + boxSizing: 'border-box', + + transition: 'color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out', + ...style, + }; + + const systemStyle = getSystemStyle(props, style); + + return (<button style={systemStyle} {...props} />); +}; + +export default Button; diff --git a/components/Code/index.tsx b/components/Code/index.tsx new file mode 100644 index 0000000..23e7a8b --- /dev/null +++ b/components/Code/index.tsx @@ -0,0 +1,10 @@ +import React, { FC, CSSProperties } from 'react'; + +interface CodeProps extends React.HTMLProps<HTMLSpanElement> { + style?: CSSProperties; +} +const Code: FC<CodeProps> = ({ children, style }) => { + return <code className='md-codespan' style={style}>{children}</code>; +}; + +export default Code; diff --git a/components/Input/index.tsx b/components/Input/index.tsx new file mode 100644 index 0000000..69f64fa --- /dev/null +++ b/components/Input/index.tsx @@ -0,0 +1,22 @@ +import React, { TextareaHTMLAttributes, ForwardRefRenderFunction } from 'react'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; +import inputElStyle from '../utils/inputElementStyle'; + +interface InputProps + extends React.InputHTMLAttributes<HTMLInputElement>, + SystemProps +{ } + +const Input: ForwardRefRenderFunction<HTMLInputElement, InputProps> = + ({ style, ...props }, ref) => { + style = { + ...inputElStyle, + ...style, + }; + + const systemStyle = getSystemStyle(props, style); + + return <input ref={ref} style={systemStyle} {...props} />; + }; + +export default React.forwardRef(Input); diff --git a/components/Link/index.tsx b/components/Link/index.tsx new file mode 100644 index 0000000..e6477c2 --- /dev/null +++ b/components/Link/index.tsx @@ -0,0 +1,23 @@ +import React, { ReactNode } from 'react'; +import NextLink from 'next/link'; +import styles from './link.module.scss'; +import clsx from 'clsx'; + +interface LinkProps { + href: string; + children: ReactNode; + className?: string; +} + +const Link: React.FC<LinkProps> = ({ href, className, children }) => { + return ( + <NextLink + href={href} + className={clsx('md-a', className)} + > + {children} + </NextLink> + ); +}; + +export default Link; diff --git a/components/Link/link.module.scss b/components/Link/link.module.scss new file mode 100644 index 0000000..b6ef943 --- /dev/null +++ b/components/Link/link.module.scss @@ -0,0 +1,11 @@ +.link { + text-decoration: none; +} + +.link:hover { + text-decoration: underline; +} + +.link, .link:visited, .link:active, .link:hover { + color: #0716ea; +} diff --git a/components/List/index.tsx b/components/List/index.tsx new file mode 100644 index 0000000..ae5c190 --- /dev/null +++ b/components/List/index.tsx @@ -0,0 +1,52 @@ +import React, { FC } from 'react'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; +import clsx from 'clsx'; + +interface ListProps extends SystemProps { + style?: React.CSSProperties; + variant : 'ordered' | 'unordered'; + children?: React.ReactNode; + className?: string; +}; + +const List : FC<ListProps> = ({ style, className, variant, children, ...props }) => { + + const systemStyle = getSystemStyle(props, style); + + const Tag = { + 'ordered': 'ol', + 'unordered': 'ul' + }[variant] as keyof React.ReactHTML; + + const styleClass = 'md-' + Tag; + + return ( + <Tag + className={clsx(styleClass, 'md-list', className)} + children={children} + style={systemStyle} + /> + ); +}; + +interface ListItemProps extends SystemProps { + style?: React.CSSProperties; + children?: React.ReactNode; + className?: string; +}; + +const ListItem : FC<ListItemProps> = ({ style, className, children, ...props }) => { + const systemStyle = getSystemStyle(props, style); + + return ( + <li + className={clsx('md-li', className)} + style={systemStyle} + >{children}</li> + ); +} + +export { + List, + ListItem +}; diff --git a/components/List/list.module.scss b/components/List/list.module.scss new file mode 100644 index 0000000..87ec3a3 --- /dev/null +++ b/components/List/list.module.scss @@ -0,0 +1,41 @@ +.list-li { + font-size: 1rem; + letter-spacing: 0.00938em; + + line-height: 1.4; + margin-left: 1em; + + list-style-image: none; + list-style-position: inside; + list-style-type: none; + + box-sizing: border-box; + + font-size: 1rem; +} + +.list-unordered li:not(:first-child) { + margin-top: 0.15rem; +} + +.list { + .list li:first-child { + margin-top: 0.15rem !important; + } +} + +.list-unordered li { + list-style-type: disc; +} + +.list .list-unordered li { + list-style-type: circle; +} + +.list .list .list-unordered li { + list-style-type: square; +} + +.list-ordered li { + list-style-type: decimal; +} diff --git a/components/Markdown/index.tsx b/components/Markdown/index.tsx index 4bb6c79..b6def4f 100644 --- a/components/Markdown/index.tsx +++ b/components/Markdown/index.tsx @@ -1,27 +1,27 @@ import React, { FC } from 'react'; -import styles from './markdown.module.scss'; + import clsx from 'clsx'; interface MarkdownProps { md: string; className?: string; - props?: object; } -const Markdown : FC<MarkdownProps> = ({md, className, ...props}) => ( +const Markdown : FC<MarkdownProps> = ({md, className}) => { + + const prerendered = ( <div - className={clsx(styles.markdownContainer, className)} - dangerouslySetInnerHTML={{ __html: md }} - - {...props} /> -); + ); + + return prerendered; +}; export type { MarkdownProps }; -export default Markdown;
\ No newline at end of file +export default Markdown; diff --git a/components/Markdown/markdown.module.scss b/components/Markdown/markdown.module.scss deleted file mode 100644 index e1debd1..0000000 --- a/components/Markdown/markdown.module.scss +++ /dev/null @@ -1,111 +0,0 @@ -.markdownContainer { - strong { - font-weight: 600; - } - - h1 { - font-size: 2.8rem; - font-weight: 300; - line-height: 1.167; - letter-spacing: -0.01562em; - margin-top: 1.0rem; - margin-bottom: 1rem; - - padding-bottom: 0.4rem; - border-bottom: 0.12rem solid rgb(53, 53, 53); - } - - h2 { - font-size: 2.3rem; - font-weight: 300; - line-height: 1.2; - letter-spacing: -0.00833em; - - margin-top: 1.6rem; - margin-bottom: 0.8rem; - } - - h3 { - font-size: 1.3rem; - font-weight: 400; - line-height: 1.167; - letter-spacing: 0em; - - margin-top: 1.3rem; - margin-bottom: 0.5rem; - } - - h4 { - font-size: 1.25rem; - } - - h5 { - font-size: 1.15rem; - } - - h6 { - font-size: 1.10rem; - } - - h4, h5, h6 { - margin-top: 0.8rem; - margin-bottom: 0.6rem; - } - - p, li { - font-size: 1rem; - letter-spacing: 0.00938em; - font-weight: 300; - } - - p { - font-size: 1rem; - line-height: 1.5; - margin-bottom: 1em; - } - - code { - font-size: 1rem; - line-height: 1.5; - padding: 0.05rem 0.2rem; - } - - pre { - padding: 0.5rem 1.0rem; - margin: 0.5rem 0; - box-sizing: border-box; - } - pre > code { - padding: 0; - } - - code, pre { - background-color: #f2f4f7; - border-radius: 5px; - } - - pre { - overflow: auto; - box-sizing: border-box; - } - - @media screen and (max-width: 700px) { - pre { - padding-bottom: 0.7rem; - } - } - - li { - line-height: 1.15; - margin-left: 1em; - margin-top: 0.3em; - list-style-image: none; - list-style-position: outside; - list-style-type: circle; - } - - img { - max-width: 95%; - margin: 2em 2.5%; - } -} diff --git a/components/Markdown/markdown.scss b/components/Markdown/markdown.scss new file mode 100644 index 0000000..e529e66 --- /dev/null +++ b/components/Markdown/markdown.scss @@ -0,0 +1,418 @@ +/* AUTOMATIC MARGIN APPLIED WHEN md-dl */ + +.md-dl.md-h1, .md-dl.md-h2, .md-dl.md-h3, .md-dl.md-h4, .md-dl.md-h5, .md-dl.md-h6 { + margin-top: 20px; + margin-bottom: 14px; +} + +.md-dl.md-list, .md-dl.md-pre, .md-dl.md-p, .md-dl.md-table, .md-dl.md-blockquote { + margin-bottom: 14px; +} + +.md-dl.md-list .md-list { + margin-bottom: 0; +} + +.md-dl.md-blockquote > :last-child { + margin-bottom: 0; +} + +.md-dl.md-wrapper > :first-child { + margin-top: 0; +} + +/* LINKS */ + +.md-a { + text-decoration: none; +} + +.md-a:hover { + text-decoration: underline; +} + +.md-a, .md-a:visited, .md-a:active, .md-a:hover { + color: #0716ea; +} + +/* TEXT */ + +.md-blockquote, .md-p, .md-li { + font-size: 1rem; + letter-spacing: 0.00938em; + line-height: 1.5; +} + +.md-code { + font-size: 1rem; + line-height: 1.25; +} + +.md-strong { + font-weight: bold; +} + +.md-em { + font-style: italic; +} + +/* LISTS */ + +.md-li { + line-height: 1.25; + margin-left: 1em; + + list-style-image: none; + list-style-position: inside; + list-style-type: none; +} + +// allow wrapping with inside list-style-position elements +.md-li > p { + display: inline; +} + +.md-dl.md-li > p { + margin-bottom: 0; + + &::after { + content: ""; + display: block; + margin-bottom: 14px; + } +} + +.md-li-checkbox { + list-style-type: none !important; +} + +.md-checkbox { + margin: 0; + margin-right: 0.5em; +} + +// UP TO FOUR LEVELS OF DECORATORS + +.md-ol > li { + list-style-type: decimal; +} + +.md-ul > li { + list-style-type: disc; +} + +.md-list .md-ul > li { + list-style-type: circle; +} + +.md-list .md-list .md-ul > li { + list-style-type: square; +} + +.md-list .md-list .md-list .md-ul > li { + list-style-type: disc; +} + +// ADD SLIGHT MARGIN TO SPACE ELEMENTS EXCEPT THE FIRST + +.md-list > li:not(:first-child) { + margin-top: 0.15rem; +} + +.md-list .md-list > li:first-child { + margin-top: 0.15rem; +} + +/* HEADINGS */ + +.md-h1 { + font-size: 3rem; + font-weight: 300; + line-height: 1.167; + letter-spacing: -0.01562em; + + padding-bottom: 0.4rem; + border-bottom: 0.12rem solid rgb(53, 53, 53); +} + +.md-h2 { + font-size: 2.5rem; + font-weight: 300; + line-height: 1.2; + letter-spacing: -0.00833em; +} + +.md-h3 { + font-size: 1.4rem; + font-weight: 400; + line-height: 1.167; + letter-spacing: 0em; +} + +.md-h4 { + font-size: 1.38rem; +} + +.md-h5 { + font-size: 1.26rem; +} + +.md-h6 { + font-size: 1.2rem; +} + + +/* CODE */ + +.md-codespan { + background-color: #f2f4f7; + border-radius: 5px; + padding: 0.05rem 0.2rem; +} + +/* BLOCKQUOTE */ + +.md-blockquote { + box-sizing: border-box; + + position: relative; + padding-left: 1.2rem; + padding-top: 0.05rem; + padding-bottom: 0.05rem; + + &::before { + content: ""; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 3px; + background-color: grey; + } +} + +/* CODE */ + +.md-pre { + background-color: #f2f4f7; + border-radius: 5px; + padding: 12px; + overflow: scroll; +} + +/* MD LINE / SEP */ + +.md-hr { + font-size: 300; +} + +/* TABLES */ + +.md-table { + width: 100%; + border-collapse: collapse; + margin: 1rem 0; +} + +.md-thead { + background-color: #f2f4f7; + font-size: 1.10rem; + + .md-th { + padding: 0.5rem 0.75rem; + text-align: left; + border-bottom: 2px solid #545454; + } +} + + +.md-tbody { + .md-tr { + &:nth-child(even) { + background-color: #f8f8f8; + } + + &:nth-child(odd) { + background-color: #ffffff; + } + } + + .md-td { + padding: 0.5rem 0.75rem; + border-bottom: 1px solid #ddd; + } +} + +/* IMAGE */ + +.md-img { + max-width: 95%; + margin: 2em 2.5%; +} + +/* DEL */ + +.md-del { } + +.markdownContainer { + /* Strong */ + + strong { + font-weight: 600; + } + + /* Headings */ + + h1 { + font-size: 2.8rem; + font-weight: 300; + line-height: 1.167; + letter-spacing: -0.01562em; + margin-top: 1.0rem; + margin-bottom: 1rem; + + padding-bottom: 0.4rem; + border-bottom: 0.12rem solid rgb(53, 53, 53); + } + + h2 { + font-size: 2.3rem; + font-weight: 300; + line-height: 1.2; + letter-spacing: -0.00833em; + + margin-top: 1.6rem; + margin-bottom: 0.8rem; + } + + h3 { + font-size: 1.3rem; + font-weight: 400; + line-height: 1.167; + letter-spacing: 0em; + + margin-top: 1.3rem; + margin-bottom: 0.5rem; + } + + h4 { + font-size: 1.25rem; + } + + h5 { + font-size: 1.15rem; + } + + h6 { + font-size: 1.10rem; + } + + h4, h5, h6 { + margin-top: 0.8rem; + margin-bottom: 0.6rem; + } + + p, li { + font-size: 1rem; + letter-spacing: 0.00938em; + } + + p { + font-size: 1rem; + line-height: 1.5; + margin-bottom: 1em; + } + + code { + font-size: 1rem; + line-height: 1.5; + padding: 0.05rem 0.2rem; + } + + pre { + padding: 0.5rem 1.0rem; + margin: 0.5rem 0; + box-sizing: border-box; + } + pre > code { + padding: 0; + } + + code, pre { + background-color: #f2f4f7; + border-radius: 5px; + } + + pre { + overflow: auto; + box-sizing: border-box; + } + + @media screen and (max-width: 700px) { + pre { + padding-bottom: 0.7rem; + } + } + + /* LISTS */ + + // li { + // font-size: 1rem; + // letter-spacing: 0.00938em; + + // line-height: 1.4; + // margin-left: 1em; + + // list-style-image: none; + // list-style-position: inside; + // list-style-type: none; + + // box-sizing: border-box; + + // font-size: 1rem; + // } + + // ul, ol { + // li:not(:first-child) { + // margin-top: 0.15rem; + // } + // } + + // ul ol li, ol li { + // list-style-type: decimal; + // } + + // ul li { + // list-style-type: disc; + // } + + // ul, ol { + // ul li:first-child, ol li:first-child { + // margin-top: 0.15rem !important; + // } + + // ul li { + // list-style-type: circle; + // } + + // ul, ol { + // ul li { + // list-style-type: square; + // } + // } + // } + + // li { + // line-height: 1.15; + // margin-left: 1em; + // margin-bottom: 0.3em; + // list-style-image: none; + // list-style-position: outside; + // list-style-type: circle; + // } + + img { + max-width: 95%; + margin: 2em 2.5%; + } +} diff --git a/components/PathCrumbs/index.tsx b/components/PathCrumbs/index.tsx new file mode 100644 index 0000000..41875ec --- /dev/null +++ b/components/PathCrumbs/index.tsx @@ -0,0 +1,61 @@ +import React, { FC } from 'react'; + +import assert from '../../utils/assert'; +import { DISPLAY_DOMAIN } from '../../utils/env'; + +const urlPathComponents = (path : string): string[] => { + assert(path.length > 0, "empty path"); + + let canonicalizedPath = path[path.length - 1] === '/' ? + path.substr(0, path.length - 1) : path; + + if(canonicalizedPath.length === 0) { + return []; + } else { + canonicalizedPath = canonicalizedPath[0] == '/' ? + path.substr(1, path.length - 1) : path; + } + + return canonicalizedPath.split('/') +} + +const urlPathComponentsToFullPath = (urlPathComponents : string[]): string[] => { + const fullPaths = new Array<string>(urlPathComponents.length + 1); + + fullPaths[0] = ''; + + for(let i = 0; i < urlPathComponents.length; i++) { + fullPaths[i + 1] = fullPaths[i] + '/' + urlPathComponents[i]; + } + + fullPaths[0] = '/'; + + return fullPaths; +}; + +export type PathCrumbsProps = { + path: string; + style?: React.CSSProperties; +}; + +import { BreadCrumbs , LinkCrumb } from '../../components/BreadCrumbs'; + +const PathCrumbs: FC<PathCrumbsProps> = ({ path, style }) => { + + const pathComponents = urlPathComponents(path); + const fullPaths = urlPathComponentsToFullPath(pathComponents); + + const linksComponents = fullPaths.map((fullPath, i) => ( + <LinkCrumb href={fullPath} key={fullPath}> + { i === 0 ? DISPLAY_DOMAIN : pathComponents[i - 1] } + </LinkCrumb> + )); + + return ( + <BreadCrumbs style={style}> + {linksComponents} + </BreadCrumbs> + ); +}; + +export default PathCrumbs; diff --git a/components/TextArea/index.tsx b/components/TextArea/index.tsx new file mode 100644 index 0000000..c40efed --- /dev/null +++ b/components/TextArea/index.tsx @@ -0,0 +1,22 @@ +import React, { TextareaHTMLAttributes, ForwardRefRenderFunction } from 'react'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; +import inputElStyle from '../utils/inputElementStyle'; + +interface TextAreaProps + extends TextareaHTMLAttributes<HTMLTextAreaElement>, + SystemProps +{ } + +const TextArea: ForwardRefRenderFunction<HTMLTextAreaElement, TextAreaProps> = + ({ style, ...props }, ref) => { + style = { + ...inputElStyle, + ...style, + }; + + const systemStyle = getSystemStyle(props, style); + + return <textarea ref={ref} style={systemStyle} {...props} />; + }; + +export default React.forwardRef(TextArea); diff --git a/components/Typ/index.tsx b/components/Typ/index.tsx new file mode 100644 index 0000000..43d7673 --- /dev/null +++ b/components/Typ/index.tsx @@ -0,0 +1,47 @@ +import React from 'react'; +import styles from './typo.module.scss'; +import clsx from 'clsx'; + + +type Variant = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'body'; +type Align = 'inherit' | 'left' | 'center' | 'right'; + +interface TypProps extends React.HTMLAttributes<HTMLElement> { + variant?: Variant; + align?: Align; + gutter?: boolean; +} + +const variantTagMap: Record<Variant, keyof JSX.IntrinsicElements> = { + h1: 'h1', + h2: 'h2', + h3: 'h3', + h4: 'h4', + h5: 'h5', + h6: 'h6', + body: 'p' +}; + +const Typ: React.FC<TypProps> = ({ + variant = 'body', + align = 'inherit', + gutter = false, + className, + ...props +}) => { + const Tag = variantTagMap[variant] as keyof React.ReactHTML; + + const typographyClassName = clsx( + `md-${variantTagMap[variant]}`, + { + [`align-${align}`]: align !== 'inherit', + [styles['typo-gutter']]: gutter + }, + className + ); + + return <Tag className={typographyClassName} {...props} />; +}; + +export default Typ; + diff --git a/components/Typ/typo.module.scss b/components/Typ/typo.module.scss new file mode 100644 index 0000000..48a5b10 --- /dev/null +++ b/components/Typ/typo.module.scss @@ -0,0 +1,3 @@ +.typo-gutter { + margin-bottom: 0.35em; +} diff --git a/components/ViewPort/index.tsx b/components/ViewPort/index.tsx index 665ee00..08b4c7e 100644 --- a/components/ViewPort/index.tsx +++ b/components/ViewPort/index.tsx @@ -1,23 +1,29 @@ import React, { FC } from "react" import styles from './index.module.scss'; +import { getSystemStyle, SystemProps } from '../utils/systemProps'; import clsx from 'clsx'; -export type Props = { - size?: "sm" | "md" | "lg"; - className?: string; +interface Props extends SystemProps { + size?: "sm" | "md" | "lg"; + className?: string; + children?: React.ReactNode; + style?: React.CSSProperties; }; -const Viewport : FC<Props> = ({children, className, size}) => { - const _size : string = size || "md"; - const sizeClass : string = styles['viewport-' + _size]; +const Viewport : FC<Props> = ({children, className, style, size, ...systemProps}) => { + style = getSystemStyle(systemProps, style); - return ( - <div - className={clsx(sizeClass, className)} - > - {children} - </div> - ) + const _size : string = size || "md"; + const sizeClass : string = styles['viewport-' + _size]; + + return ( + <div + className={clsx(sizeClass, className)} + style={style} + > + {children} + </div> + ) }; -export default Viewport;
\ No newline at end of file +export default Viewport; diff --git a/components/utils/inputElementStyle.tsx b/components/utils/inputElementStyle.tsx new file mode 100644 index 0000000..c784e85 --- /dev/null +++ b/components/utils/inputElementStyle.tsx @@ -0,0 +1,16 @@ +import React from 'react'; + +export default { + backgroundColor: '#fff', + border: '1px solid #ced4da', + padding: '0.375rem 0.75rem', + width: '100%', + borderRadius: '0.25rem', + resize: 'vertical', + fontFamily: 'inherit', + margin: '0', + display: 'block', + fontSize: '1em', + boxSizing: 'border-box', + lineHeight: '1.5rem', +} as React.CSSProperties; diff --git a/components/utils/systemProps.tsx b/components/utils/systemProps.tsx new file mode 100644 index 0000000..8fc0317 --- /dev/null +++ b/components/utils/systemProps.tsx @@ -0,0 +1,107 @@ +import React from 'react'; + +export type SystemProps = { + // Margin + mt?: number; + mb?: number; + ml?: number; + mr?: number; + mx?: number; + my?: number; + m?: number; + + // Padding + pt?: number; + pb?: number; + pl?: number; + pr?: number; + px?: number; + py?: number; + p?: number; + + // Arbitrary style + sx?: React.CSSProperties; +}; + +const calculateStyleValue = (multiplier: number, spacer: number = 1): string => { + return `${multiplier * spacer}em`; +}; + +const getSystemStyle = ( + systemProps: SystemProps, + userStyle: React.CSSProperties = {} +): React.CSSProperties => { + const spacer = 1; // 1em + + let style: React.CSSProperties = {}; + + // Margin + const { mt, mb, ml, mr, mx, my, m } = systemProps; + + if (m !== undefined) { + const value = calculateStyleValue(m, spacer); + style.marginTop = value; + style.marginBottom = value; + style.marginLeft = value; + style.marginRight = value; + } + + if (mx !== undefined) { + const value = calculateStyleValue(mx, spacer); + style.marginLeft = value; + style.marginRight = value; + } + + if (my !== undefined) { + const value = calculateStyleValue(my, spacer); + style.marginTop = value; + style.marginBottom = value; + } + + if (mt !== undefined) style.marginTop = calculateStyleValue(mt, spacer); + if (mb !== undefined) style.marginBottom = calculateStyleValue(mb, spacer); + if (ml !== undefined) style.marginLeft = calculateStyleValue(ml, spacer); + if (mr !== undefined) style.marginRight = calculateStyleValue(mr, spacer); + + // Padding + const { pt, pb, pl, pr, px, py, p } = systemProps; + + if (p !== undefined) { + const value = calculateStyleValue(p, spacer); + style.paddingTop = value; + style.paddingBottom = value; + style.paddingLeft = value; + style.paddingRight = value; + } + + if (px !== undefined) { + const value = calculateStyleValue(px, spacer); + style.paddingLeft = value; + style.paddingRight = value; + } + + if (py !== undefined) { + const value = calculateStyleValue(py, spacer); + style.paddingTop = value; + style.paddingBottom = value; + } + + if (pt !== undefined) style.paddingTop = calculateStyleValue(pt, spacer); + if (pb !== undefined) style.paddingBottom = calculateStyleValue(pb, spacer); + if (pl !== undefined) style.paddingLeft = calculateStyleValue(pl, spacer); + if (pr !== undefined) style.paddingRight = calculateStyleValue(pr, spacer); + + // Merge with arbitrary styles (sx) + if (systemProps.sx) { + style = { ...style, ...systemProps.sx }; + } + + // Override with user-defined style + style = { ...style, ...userStyle }; + + return style; +}; + +export { + getSystemStyle +}; |
