Initial commit

Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com>
Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com>
Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com>
Co-Authored-By: Michael Cartner <32543275+michaelcartner@users.noreply.github.com>
This commit is contained in:
Eric Tuvesson
2023-09-05 12:08:55 +02:00
commit 53f0d6320e
2704 changed files with 76354 additions and 0 deletions

View File

@@ -0,0 +1,105 @@
@use '../../../css/utils/mixins.scss';
.Root {
display: flex;
&.is-horisontal {
flex-direction: row;
}
&.is-vertical {
flex-direction: column;
}
}
.ImageContainer {
flex-grow: 0;
flex-shrink: 0;
position: relative;
background-color: #ffffff;
.Root.is-horisontal & {
@include mixins.aspect-ratio(1, 1);
width: 156px;
}
.Root.is-vertical & {
@include mixins.aspect-ratio(354, 200);
}
}
.Image {
background-position: center;
position: absolute;
background-repeat: no-repeat;
background-size: cover;
top: 0;
bottom: 0;
left: 0;
right: 0;
.Root.is-vertical &:not(.has-no-padding) {
background-size: contain;
top: 12px;
bottom: 12px;
left: 12px;
right: 12px;
}
.Root.is-horisontal & {
background-size: cover;
}
}
.Content {
background-color: var(--doc-color-noodl-black-light);
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.Root.is-horisontal & {
padding: 25px 32px;
}
.Root.is-vertical & {
padding: 16px 24px;
}
}
.PrimaryAction {
font-weight: 600;
cursor: pointer;
display: inline-block;
margin-right: 24px;
border-bottom: none !important;
font-family: var(--doc-font-title);
span {
color: var(--doc-color-noodl-orange);
transition: color var(--ifm-transition-fast)
var(--ifm-transition-timing-default);
&:hover {
color: var(--doc-color-noodl-orange-140);
}
}
}
.SecondaryAction {
font-weight: 600;
cursor: pointer;
display: inline-block;
border-bottom: none !important;
font-family: var(--doc-font-title);
span {
color: var(--doc-color-text);
transition: color var(--ifm-transition-fast)
var(--ifm-transition-timing-default);
&:hover {
color: var(--doc-color-noodl-orange);
}
}
}

View File

@@ -0,0 +1,105 @@
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
import useIsBrowser from '@docusaurus/useIsBrowser'
import clsx from 'clsx'
import React, { useMemo } from 'react'
import { TextSize, Text } from '../../typography/Text/Text'
import { Title, TitleSize } from '../../typography/Title/Title'
import css from './ArticleCard.module.scss'
export enum ArticleCardLayout {
Horisontal = 'is-horisontal',
Vertical = 'is-vertical',
}
interface IActionSlot {
label: string
onClick?: () => void
href?: string
}
export interface ArticleCardProps {
layout?: ArticleCardLayout
title: string
description: string
hasNoPaddingInThumb?: boolean
primaryAction: IActionSlot
secondaryAction?: IActionSlot
imageUrl?: string
}
export function ArticleCard({
layout = ArticleCardLayout.Vertical,
title,
description,
hasNoPaddingInThumb,
primaryAction,
secondaryAction,
imageUrl,
}: ArticleCardProps) {
const { siteConfig } = useDocusaurusContext()
const isBrowser = useIsBrowser()
const thumbUrl = useMemo(() => {
return !isBrowser
? null
: location.protocol +
'//' +
location.host +
siteConfig.baseUrl.slice(0, -1) +
(imageUrl[0]==='/'?imageUrl:('/'+imageUrl))
}, [isBrowser])
return (
<article className={clsx(css['Root'], css[layout])}>
<div className={css['ImageContainer']}>
{thumbUrl && (
<div
className={clsx(
css['Image'],
hasNoPaddingInThumb && css['has-no-padding']
)}
style={{ backgroundImage: `url(${thumbUrl})` }}
/>
)}
</div>
<div className={css['Content']}>
<div>
<header>
<Title size={TitleSize.Smaller} headingLevel={1}>
{title}
</Title>
</header>
<Text size={TextSize.Small}>{description}</Text>
</div>
<footer className={css['Footer']}>
{Boolean(primaryAction) && (
<a
className={css['PrimaryAction']}
href={primaryAction.href}
onClick={primaryAction.onClick}
>
<Text size={TextSize.Small} isSpan>
{primaryAction.label}
</Text>
</a>
)}
{Boolean(secondaryAction) && (
<a
className={css['SecondaryAction']}
href={secondaryAction.href}
onClick={secondaryAction.onClick}
>
<Text size={TextSize.Small} isSpan>
{secondaryAction.label}
</Text>
</a>
)}
</footer>
</div>
</article>
)
}

View File

@@ -0,0 +1,20 @@
@use '../../../css/utils/typography.scss';
.Root {
@include typography.h2;
font-size: 26px;
line-height: 1.1;
display: flex;
justify-content: center;
align-items: center;
padding: 32px 24px 24px;
height: 100%;
min-height: 180px;
border-bottom: none !important;
background-color: var(--doc-color-noodl-green);
text-align: center;
&:hover {
background-color: var(--doc-color-noodl-green-180);
}
}

View File

@@ -0,0 +1,19 @@
import Link from '@docusaurus/Link'
import React from 'react'
import css from './ButtonCard.module.scss'
export interface ButtonCardProps {
title: string
href?: string
onClick?: () => void
}
export function ButtonCard({ title, href, onClick }: ButtonCardProps) {
const Tag = href ? Link : 'button'
return (
<Tag className={css['Root']} to={href} onClick={onClick}>
{title}
</Tag>
)
}

View File

@@ -0,0 +1 @@
export { default } from './ButtonCard'

View File

@@ -0,0 +1,32 @@
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
import React from 'react'
import { ArticleCard, ArticleCardLayout } from '../ArticleCard/ArticleCard'
interface GuideCardProps {
title: string
description: string
href: string
imageUrl?: string
}
export function GuideCard({
title,
description,
href,
imageUrl,
}: GuideCardProps) {
const { siteConfig } = useDocusaurusContext()
return (
<ArticleCard
layout={ArticleCardLayout.Horisontal}
primaryAction={{
label: 'Read guide',
href: siteConfig.baseUrl.slice(0, -1) + href,
}}
title={title}
description={description}
imageUrl={imageUrl}
/>
)
}

View File

@@ -0,0 +1,42 @@
@use '../../../css/utils/typography.scss';
.Root {
display: flex;
flex-direction: column;
padding: 24px;
justify-content: space-between;
position: relative;
background-size: cover;
background-position: center;
&:before {
content: '';
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
pointer-events: none;
opacity: 0;
transition: opacity var(--ifm-transition-fast)
var(--ifm-transition-timing-default);
background-color: var(--doc-color-noodl-white);
}
&:hover:before {
opacity: 0.5;
}
}
.IconContainer {
position: relative;
}
.Label {
@include typography.h3;
color: var(--doc-color-noodl-black) !important;
max-width: 131px;
display: block;
position: relative;
padding-bottom: 20px;
}

View File

@@ -0,0 +1,52 @@
import Link from '@docusaurus/Link'
import React, { useMemo } from 'react'
import css from './LinkCard.module.scss'
import PlayIcon from '../../../../static/img/icons/play-black.svg'
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
import useIsBrowser from '@docusaurus/useIsBrowser'
export interface LinkCardProps {
href: string
colorVariable: string
backgroundImage: string
label: string
playIcon?: boolean
}
export function LinkCard({
href,
colorVariable,
backgroundImage,
label,
playIcon
}: LinkCardProps) {
const { siteConfig } = useDocusaurusContext()
const isBrowser = useIsBrowser()
const bgUrl = useMemo(() => {
return isBrowser && backgroundImage
? location.protocol +
'//' +
location.host +
siteConfig.baseUrl.slice(0, -1) +
backgroundImage
: null
}, [isBrowser])
return (
<Link
className={css['Root']}
style={{
backgroundColor: `var(${colorVariable})`,
backgroundImage: bgUrl ? `url(${bgUrl})` : null,
}}
to={href}
>
<span className={css['Label']}>{label}</span>
{(playIcon===undefined || playIcon === true) && (<div className={css['IconContainer']}>
<PlayIcon />
</div>)}
</Link>
)
}

View File

@@ -0,0 +1 @@
export { default } from './LinkCard'

View File

@@ -0,0 +1,41 @@
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
import useIsBrowser from '@docusaurus/useIsBrowser'
import React from 'react'
import { useMemo } from 'react'
import {
importIntoNoodl,
ImportIntoNoodlArgs,
} from '../../../utils/importIntoNoodl'
import { ArticleCard, ArticleCardLayout } from '../ArticleCard/ArticleCard'
interface ModuleCardProps {
thumbUrl: string
title: string
description: string
readMoreUrl: string
importArgs: ImportIntoNoodlArgs
}
export function ModuleCard({
thumbUrl,
title,
description,
readMoreUrl,
importArgs,
}: ModuleCardProps) {
const { siteConfig } = useDocusaurusContext()
return (
<ArticleCard
title={title}
description={description}
hasNoPaddingInThumb
imageUrl={thumbUrl}
layout={ArticleCardLayout.Vertical}
primaryAction={{
label: 'Read more',
href: siteConfig.baseUrl.slice(0, -1) + readMoreUrl,
}}
/>
)
}

View File

@@ -0,0 +1,51 @@
.Root {
display: block;
padding: 13px 18px;
font-weight: 600;
color: var(--doc-color-noodl-white) !important;
border: 2px solid transparent !important;
position: relative;
line-height: 1;
height: 100%;
font-size: 14px;
&:after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--doc-color-noodl-white);
opacity: 0;
pointer-events: none;
}
&.has-hoverstate:hover {
border: 2px solid var(--doc-color-noodl-white) !important;
&:after {
opacity: 0.3;
}
}
&.is-visual {
background-color: var(--doc-color-visual-node);
}
&.is-data {
background-color: var(--doc-color-data-node);
}
&.is-custom {
background-color: var(--doc-color-custom-node);
}
&.is-logic {
background-color: var(--doc-color-logic-node);
}
&.is-connection {
background-color: var(--doc-color-connection-node);
}
}

View File

@@ -0,0 +1,35 @@
import Link from '@docusaurus/Link'
import clsx from 'clsx'
import React from 'react'
import css from './NodeCard.module.scss'
export enum NodeType {
Visual = 'is-visual',
Data = 'is-data',
Custom = 'is-custom',
Logic = 'is-logic',
Connection = 'is-connection',
}
export interface NodeCardProps {
nodeType: NodeType
label: string
docUrl?: string
}
export function NodeCard({ nodeType, label, docUrl }: NodeCardProps) {
const Tag = docUrl ? Link : 'div'
return (
<Tag
className={clsx(
css['Root'],
css[nodeType],
Boolean(docUrl) && css['has-hoverstate']
)}
to={docUrl}
>
{label}
</Tag>
)
}

View File

@@ -0,0 +1 @@
export { default } from './NodeCard'

View File

@@ -0,0 +1,46 @@
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'
import React from 'react'
import { importIntoNoodl } from '../../../utils/importIntoNoodl'
import { ArticleCard, ArticleCardLayout } from '../ArticleCard/ArticleCard'
interface ProjectCardProps {
title: string
description: string
href: string
imageUrl: string
project: string
backend: string
}
export function ProjectCard({
title,
description,
href,
imageUrl,
project,
backend,
}: ProjectCardProps) {
const { siteConfig } = useDocusaurusContext()
return (
<ArticleCard
layout={ArticleCardLayout.Vertical}
title={title}
description={description}
imageUrl={imageUrl}
primaryAction={{
label: 'Download project',
onClick: () =>
importIntoNoodl(project, {
name: title,
cf: backend,
thumb: imageUrl,
}),
}}
secondaryAction={{
label: 'Read more',
href: siteConfig.baseUrl.slice(0, -1) + href,
}}
/>
)
}

View File

@@ -0,0 +1,75 @@
@use '../../../css/utils/mixins.scss';
@use '../../../css/utils/typography.scss';
$_hover-background: var(--doc-color-noodl-black-light);
.Root {
display: flex;
align-items: stretch;
position: relative;
outline: 10px solid transparent;
transition: outline var(--ifm-transition-fast)
var(--ifm-transition-timing-default);
&:hover {
outline: 10px solid $_hover-background;
}
}
.Thumb {
@include mixins.aspect-ratio(560, 315);
position: relative;
overflow: hidden;
width: calc(50% - 24px);
background-size: cover;
background-position: center;
}
.Details {
display: flex;
flex-direction: column;
justify-content: space-between;
width: calc(50% + 24px);
padding-left: 24px;
transition: background-color var(--ifm-transition-fast)
var(--ifm-transition-timing-default);
.Root:hover & {
background-color: $_hover-background;
}
}
.Title {
@include typography.h4;
padding-bottom: 10px;
}
.Description {
@include typography.body-small;
}
.VideoLength {
font-size: 12px;
padding-top: 10px;
display: flex;
align-items: center;
svg {
width: 18px;
height: 18px;
}
span {
margin-left: 5px;
line-height: 1;
}
}
.Link {
font-size: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}

View File

@@ -0,0 +1,47 @@
import React from 'react'
import css from './VideoLinkCard.module.scss'
import PlayIcon from '../../../../static/img/icons/play-white.svg'
export interface VideoLinkCardProps {
videoId: string
title: string
description: string
videoLength: string
}
export function VideoLinkCard({
videoId,
title,
description,
videoLength,
}: VideoLinkCardProps) {
return (
<article className={css['Root']}>
<div
className={css['Thumb']}
style={{
backgroundImage: `url(http://img.youtube.com/vi/${videoId}/0.jpg)`,
}}
/>
<div className={css['Details']}>
<div>
<h1 className={css['Title']}>{title}</h1>
<p className={css['Description']}>{description}</p>
</div>
<p className={css['VideoLength']}>
<PlayIcon />
<span>{videoLength}</span>
</p>
</div>
<a
className={css['Link']}
href={`https://www.youtube.com/watch?v=${videoId}`}
target="_blank"
rel="noopener noreferrer"
>
Watch video
</a>
</article>
)
}

View File

@@ -0,0 +1 @@
export { default } from './VideoLinkCard'

View File

@@ -0,0 +1,15 @@
@use '../../../css/utils/mixins.scss';
.Root {
@include mixins.aspect-ratio(560, 315);
position: relative;
overflow: hidden;
iframe {
left: 0;
top: 0;
height: 100%;
width: 100%;
position: absolute;
}
}

View File

@@ -0,0 +1,22 @@
import React from 'react'
import css from './YouTubeEmbed.module.scss'
export interface YouTubeEmbedProps {
videoId: string
}
export function YouTubeEmbed({ videoId }: YouTubeEmbedProps) {
return (
<div className={css['Root']}>
<iframe
width="840"
height="472"
src={`https://www.youtube.com/embed/${videoId}`}
title="YouTube video player"
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
></iframe>
</div>
)
}

View File

@@ -0,0 +1,49 @@
import React from 'react'
function fallbackCopyTextToClipboard(text) {
var textArea = document.createElement('textarea');
textArea.value = text;
// Avoid scrolling to bottom
textArea.style.top = '0';
textArea.style.left = '0';
textArea.style.position = 'fixed';
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
var successful = document.execCommand('copy');
var msg = successful ? 'successful' : 'unsuccessful';
console.log('Fallback: Copying text command was ' + msg);
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
}
document.body.removeChild(textArea);
}
function copyTextToClipboard(text) {
if (!navigator.clipboard) {
fallbackCopyTextToClipboard(text);
return;
}
navigator.clipboard.writeText(text).then(
function () {
console.log('Async: Copying to clipboard was successful!');
},
function (err) {
console.error('Async: Could not copy text: ', err);
}
);
}
function copyJsonToClipboard(json) {
copyTextToClipboard(JSON.stringify(json));
}
export default function CopyToClipboardButton(props) {
return (
<button className="ndl-copy-nodes-button" onClick={() => copyJsonToClipboard(props.json)}></button>
)
}

View File

@@ -0,0 +1,29 @@
import React from 'react'
import { importIntoNoodl } from '../utils/importIntoNoodl'
interface ImportButtonProps {
zip: string
name: string
thumb: string
cf: string
}
export default function ImportButton({
zip,
name,
thumb,
cf,
}: ImportButtonProps) {
return (
<button
className="ndl-import-button"
onClick={() =>
importIntoNoodl(zip, {
name,
thumb,
cf,
})
}
/>
)
}

View File

@@ -0,0 +1,6 @@
.Root {
max-width: var(--ifm-container-width-xl);
padding: var(--doc-size-page-top-spacing-l)
var(--ifm-navbar-padding-horizontal);
margin: 0 auto;
}

View File

@@ -0,0 +1,10 @@
import React, { ReactNode } from 'react'
import css from './Container.module.scss'
export interface ContainerProps {
children: ReactNode
}
export function Container({ children }: ContainerProps) {
return <div className={css['Root']}>{children}</div>
}

View File

@@ -0,0 +1,103 @@
$_gutter: 24px;
.Root {
display: flex;
box-sizing: border-box;
flex-wrap: wrap;
margin-top: $_gutter * -1;
margin-left: $_gutter * -1;
&.has-equal-height-items {
align-items: stretch;
}
}
.GridItem {
flex-grow: 0;
flex-shrink: 0;
padding-top: $_gutter;
padding-left: $_gutter;
pointer-events: none;
> * {
pointer-events: all;
}
.Root.has-equal-height-items & > * {
height: 100%;
}
.Root.is-grid-half > & {
width: 100%;
@media (min-width: 850px) {
width: 50%;
}
}
.Root.is-grid-thirds > & {
width: 100%;
@media (min-width: 600px) {
width: 50%;
}
@media (min-width: 900px) {
width: 33.333%;
}
}
.Root.is-grid-fifths > & {
width: 100%;
@media (min-width: 350px) {
width: 50%;
}
@media (min-width: 520px) {
width: 33.333%;
}
@media (min-width: 800px) {
width: 25%;
}
@media (min-width: 1250px) {
width: 20%;
}
}
.Root.is-grid-2-1-1 > & {
width: 100%;
@media (min-width: 400px) {
&:nth-child(3n-2) {
width: 100%;
}
&:not(:nth-child(3n-2)) {
width: 50%;
}
}
@media (min-width: 800px) {
&:nth-child(3n-2) {
width: 50%;
}
&:not(:nth-child(3n-2)) {
width: 25%;
}
}
}
.Root.is-grid-2-3 > & {
&:nth-child(odd) {
width: 40%;
}
&:nth-child(even) {
width: 60%;
}
}
}

View File

@@ -0,0 +1,46 @@
import clsx from 'clsx'
import React, { ReactNode, useMemo } from 'react'
import css from './Grid.module.scss'
export enum GridLayout {
Half = 'is-grid-half',
Thirds = 'is-grid-thirds',
Fifths = 'is-grid-fifths',
Grid_2_1_1 = 'is-grid-2-1-1',
Grid_2_3 = 'is-grid-2-3',
}
export interface GridProps {
layout: GridLayout
children: ReactNode
hasEqualHeightItems?: boolean
}
export function Grid({ layout, children, hasEqualHeightItems }: GridProps) {
const childArray = useMemo(
() => (Array.isArray(children) ? children : [children]),
[children]
)
return (
<div
className={clsx(
css['Root'],
css[layout],
hasEqualHeightItems && css['has-equal-height-items']
)}
>
{/* using i is not the best, but not all items will have ids.
if items orders or rendering get all weird or buggy this is the cause */}
{childArray.map((child, i) => {
if (child === null) return null
return (
<div key={i} className={css['GridItem']}>
{child}
</div>
)
})}
</div>
)
}

View File

@@ -0,0 +1,22 @@
@use '../../../css/utils/typography.scss';
.Root {
padding-bottom: 120px;
}
.Header {
display: flex;
justify-content: space-between;
align-items: baseline;
}
.Link {
@include typography.h3;
color: var(--doc-color-noodl-white-65) !important; // ajajaj
&:hover {
color: var(--doc-color-noodl-white) !important;
border-bottom-color: transparent !important;
}
}

View File

@@ -0,0 +1,42 @@
import Link from '@docusaurus/Link'
import React, { ReactNode } from 'react'
import { Title, TitleProps, TitleSize } from '../../typography/Title/Title'
import css from './Section.module.scss'
export interface SectionProps {
title?: TitleProps['children']
titleSize?: TitleProps['size']
linkLabel?: string | false
linkHref?: string
children: ReactNode
hasNoHeader?: boolean
}
export function Section({
title,
titleSize,
linkLabel = 'View all',
linkHref,
children,
hasNoHeader,
}: SectionProps) {
return (
<section className={css['Root']}>
{!hasNoHeader && (
<div className={css['Header']}>
<Title size={titleSize}>{title}</Title>
{Boolean(linkLabel) && (
<Link className={css['Link']} href={linkHref}>
{linkLabel}
</Link>
)}
</div>
)}
<div className={css['Content']}>{children}</div>
</section>
)
}

View File

@@ -0,0 +1 @@
export { default } from './Section'

View File

@@ -0,0 +1,36 @@
@use '../../../css/utils/typography.scss';
.Root {
font-family: var(--doc-font-text);
margin-block-start: 0;
margin-block-end: 0;
max-width: 860px;
[data-theme='dark'] & {
@extend %font-smoothing;
}
&.is-size-default {
@include typography.body;
&.has-bottom-spacing {
@include typography.body-bottom-spacing;
}
}
&.is-size-small {
@include typography.body-small;
&.has-bottom-spacing {
@include typography.body-small-bottom-spacing;
}
}
&.is-inline {
display: inline;
}
&.is-centered {
text-align: center;
}
}

View File

@@ -0,0 +1,47 @@
import clsx from 'clsx'
import React, { CSSProperties, ReactNode } from 'react'
import css from './Text.module.scss'
export enum TextSize {
Default = 'default',
Small = 'small',
}
export interface TextProps {
children?: ReactNode
className?: string
size?: TextSize
style?: CSSProperties
hasBottomSpacing?: boolean
isSpan?: boolean
isCentered?: boolean
}
export function Text({
children,
size = TextSize.Default,
style,
className,
hasBottomSpacing = true,
isSpan,
isCentered,
}: TextProps) {
const Tag = isSpan ? 'span' : 'p'
return (
<Tag
className={clsx(
css['Root'],
css[`is-size-${size}`],
isSpan && css['is-inline'],
isCentered && css['is-centered'],
hasBottomSpacing && css['has-bottom-spacing'],
className
)}
style={style}
>
{children}
</Tag>
)
}

View File

@@ -0,0 +1 @@
export { default } from './Text'

View File

@@ -0,0 +1,42 @@
@use '../../../css/utils/typography.scss';
.Root {
margin-bottom: 0;
margin-top: 0;
&.is-size-default {
@include typography.h2;
&.has-bottom-spacing {
@include typography.h2-bottom-spacing;
}
}
&.is-size-large {
@include typography.h1;
&.has-bottom-spacing {
@include typography.h1-bottom-spacing;
}
}
&.is-size-small {
@include typography.h3;
&.has-bottom-spacing {
@include typography.h3-bottom-spacing;
}
}
&.is-size-smaller {
@include typography.h4;
&.has-bottom-spacing {
@include typography.h4-bottom-spacing;
}
}
&.is-centered {
text-align: center;
}
}

View File

@@ -0,0 +1,43 @@
import clsx from 'clsx'
import React, { ReactNode } from 'react'
import css from './Title.module.scss'
export enum TitleSize {
Default = 'default',
Large = 'large',
Small = 'small',
Smaller = 'smaller',
}
export interface TitleProps {
children?: ReactNode
size?: TitleSize
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6
hasBottomSpacing?: boolean
isCentered?: boolean
}
export function Title({
children,
size = TitleSize.Default,
headingLevel = 2,
hasBottomSpacing = true,
isCentered,
}: TitleProps) {
// hahahaha wtf
const Tag: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' = `h${headingLevel}`
return (
<Tag
className={clsx(
css['Root'],
css[`is-size-${size}`],
isCentered && css['is-centered'],
hasBottomSpacing && css['has-bottom-spacing']
)}
>
{children}
</Tag>
)
}

View File

@@ -0,0 +1 @@
export { default } from './Title'