aboutsummaryrefslogtreecommitdiff
path: root/components
diff options
context:
space:
mode:
authorFurkan Sahin <furkan-dev@proton.me>2022-05-30 21:11:40 -0500
committerFurkan Sahin <furkan-dev@proton.me>2026-02-20 15:13:00 -0500
commit16baa822cc897fa8764c14861f7869f46ca50e30 (patch)
treea970198a53dd4449ed8702d90433fda787075bcd /components
parent56a2f28565244127bb91ebabac731eaef950f3ec (diff)
Compress results gif
Diffstat (limited to 'components')
-rw-r--r--components/Box/index.tsx26
-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.tsx39
-rw-r--r--components/Code/index.tsx10
-rw-r--r--components/Input/index.tsx22
-rw-r--r--components/Link/index.tsx23
-rw-r--r--components/Link/link.module.scss11
-rw-r--r--components/List/index.tsx52
-rw-r--r--components/List/list.module.scss41
-rw-r--r--components/Markdown/index.tsx18
-rw-r--r--components/Markdown/markdown.module.scss111
-rw-r--r--components/Markdown/markdown.scss418
-rw-r--r--components/PathCrumbs/index.tsx61
-rw-r--r--components/TextArea/index.tsx22
-rw-r--r--components/Typ/index.tsx47
-rw-r--r--components/Typ/typo.module.scss3
-rw-r--r--components/ViewPort/index.tsx34
-rw-r--r--components/utils/inputElementStyle.tsx16
-rw-r--r--components/utils/systemProps.tsx107
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
+};