From 9b4047cd32f64ac32d68b2ff4154969e5d8f9879 Mon Sep 17 00:00:00 2001 From: Stephen Handley Date: Mon, 17 Feb 2025 16:22:08 -0800 Subject: [PATCH 01/11] convert scss to tailwind --- app/page.tsx | 2 +- components/Accordion.module.scss | 31 ---- components/Accordion.tsx | 15 +- components/ActionBar.module.scss | 4 - components/ActionBar.tsx | 8 +- components/ActionButton.module.scss | 59 ------ components/ActionButton.tsx | 15 +- components/ActionListItem.module.scss | 52 ------ components/ActionListItem.tsx | 8 +- components/AlertBanner.module.scss | 7 - components/AlertBanner.tsx | 9 +- components/Avatar.module.scss | 119 ------------ components/Avatar.tsx | 23 ++- components/Badge.module.scss | 15 -- components/Badge.tsx | 7 +- components/BarLoader.module.scss | 15 -- components/BarLoader.tsx | 6 +- components/BarProgress.module.scss | 15 -- components/BarProgress.tsx | 7 +- components/Block.module.scss | 8 - components/Block.tsx | 7 +- components/BlockLoader.module.scss | 7 - components/BlockLoader.tsx | 9 +- components/BreadCrumbs.module.scss | 36 ---- components/BreadCrumbs.tsx | 12 +- components/Button.module.scss | 55 ------ components/Button.tsx | 20 ++- components/ButtonGroup.module.scss | 12 -- components/ButtonGroup.tsx | 10 +- components/CanvasPlatformer.module.scss | 16 -- components/CanvasPlatformer.tsx | 8 +- components/CanvasSnake.module.scss | 16 -- components/CanvasSnake.tsx | 8 +- components/Card.module.scss | 76 -------- components/Card.tsx | 15 +- components/CardDouble.module.scss | 86 --------- components/CardDouble.tsx | 17 +- components/Checkbox.module.scss | 59 ------ components/Checkbox.tsx | 13 +- components/Chessboard.module.scss | 37 ---- components/Chessboard.tsx | 12 +- components/CodeBlock.module.scss | 37 ---- components/CodeBlock.tsx | 9 +- components/ComboBox.module.scss | 3 - components/ComboBox.tsx | 6 +- components/ContentFluid.module.scss | 6 - components/ContentFluid.tsx | 6 +- components/DOMSnake.module.scss | 27 --- components/DOMSnake.tsx | 9 +- components/DataTable.module.scss | 43 ----- components/DataTable.tsx | 24 ++- components/DatePicker.module.scss | 62 ------- components/DatePicker.tsx | 13 +- components/Dialog.module.scss | 35 ---- components/Dialog.tsx | 9 +- components/Divider.module.scss | 25 --- components/Divider.tsx | 8 +- components/Drawer.module.scss | 56 ------ components/Drawer.tsx | 21 ++- components/DropdownMenu.module.scss | 10 -- components/DropdownMenu.tsx | 7 +- components/DropdownMenuTrigger.module.scss | 4 - components/DropdownMenuTrigger.tsx | 6 +- components/Grid.module.scss | 4 - components/Grid.tsx | 6 +- components/HoverComponentTrigger.module.scss | 4 - components/HoverComponentTrigger.tsx | 6 +- components/Indent.module.scss | 4 - components/Indent.tsx | 6 +- components/Input.module.scss | 79 -------- components/Input.tsx | 31 +++- components/ListItem.module.scss | 8 - components/ListItem.tsx | 9 +- components/MatrixLoader.module.scss | 11 -- components/MatrixLoader.tsx | 7 +- components/Message.module.scss | 41 ----- components/Message.tsx | 10 +- components/MessageViewer.module.scss | 35 ---- components/MessageViewer.tsx | 10 +- components/ModalStack.module.scss | 20 --- components/ModalStack.tsx | 12 +- components/Navigation.module.scss | 50 ------ components/Navigation.tsx | 10 +- components/NumberRangeSlider.module.scss | 103 ----------- components/NumberRangeSlider.tsx | 20 ++- components/Popover.module.scss | 7 - components/Popover.tsx | 6 +- components/RadioButton.module.scss | 74 -------- components/RadioButton.tsx | 24 ++- components/Row.module.scss | 10 -- components/Row.tsx | 6 +- components/RowEllipsis.module.scss | 13 -- components/RowEllipsis.tsx | 6 +- components/RowSpaceBetween.module.scss | 11 -- components/RowSpaceBetween.tsx | 6 +- components/Select.module.scss | 77 -------- components/Select.tsx | 17 +- components/SidebarLayout.module.scss | 55 ------ components/SidebarLayout.tsx | 14 +- components/Table.module.scss | 13 -- components/Table.tsx | 7 +- components/TableColumn.module.scss | 15 -- components/TableColumn.tsx | 6 +- components/TableRow.module.scss | 15 -- components/TableRow.tsx | 6 +- components/Text.module.scss | 4 - components/Text.tsx | 6 +- components/TextArea.module.scss | 74 -------- components/TextArea.tsx | 29 ++- components/Tooltip.module.scss | 7 - components/Tooltip.tsx | 6 +- components/TreeView.module.scss | 18 -- components/TreeView.tsx | 17 +- components/examples/AS400.module.scss | 2 - components/examples/AS400.tsx | 2 - .../examples/DashboardRadar.module.scss | 64 ------- components/examples/DashboardRadar.tsx | 16 +- components/examples/Denabase.module.scss | 108 ----------- components/examples/Denabase.tsx | 17 +- components/modals/ModalAlert.module.scss | 23 --- components/modals/ModalAlert.tsx | 12 +- .../modals/ModalCanvasPlatformer.module.scss | 23 --- components/modals/ModalCanvasPlatformer.tsx | 9 +- .../modals/ModalCanvasSnake.module.scss | 23 --- components/modals/ModalCanvasSnake.tsx | 14 +- components/modals/ModalChess.module.scss | 23 --- components/modals/ModalChess.tsx | 9 +- .../modals/ModalCreateAccount.module.scss | 23 --- components/modals/ModalCreateAccount.tsx | 10 +- components/modals/ModalDOMSnake.tsx | 9 +- components/modals/ModalError.module.scss | 23 --- components/modals/ModalError.tsx | 9 +- .../modals/ModalMatrixModes.module.scss | 23 --- components/modals/ModalMatrixModes.tsx | 9 +- components/page/DefaultActionBar.module.scss | 6 - components/page/DefaultActionBar.tsx | 7 +- components/page/DefaultLayout.module.scss | 11 -- components/page/DefaultLayout.tsx | 7 +- global.scss => global.css | 170 +++++------------- package.json | 12 +- pages/_app.tsx | 2 +- postcss.config.mjs | 6 + tailwind.config.js | 26 +++ 143 files changed, 656 insertions(+), 2459 deletions(-) delete mode 100644 components/Accordion.module.scss delete mode 100644 components/ActionBar.module.scss delete mode 100644 components/ActionButton.module.scss delete mode 100644 components/ActionListItem.module.scss delete mode 100644 components/AlertBanner.module.scss delete mode 100644 components/Avatar.module.scss delete mode 100644 components/Badge.module.scss delete mode 100644 components/BarLoader.module.scss delete mode 100644 components/BarProgress.module.scss delete mode 100644 components/Block.module.scss delete mode 100644 components/BlockLoader.module.scss delete mode 100644 components/BreadCrumbs.module.scss delete mode 100644 components/Button.module.scss delete mode 100644 components/ButtonGroup.module.scss delete mode 100644 components/CanvasPlatformer.module.scss delete mode 100644 components/CanvasSnake.module.scss delete mode 100644 components/Card.module.scss delete mode 100644 components/CardDouble.module.scss delete mode 100644 components/Checkbox.module.scss delete mode 100644 components/Chessboard.module.scss delete mode 100644 components/CodeBlock.module.scss delete mode 100644 components/ComboBox.module.scss delete mode 100644 components/ContentFluid.module.scss delete mode 100644 components/DOMSnake.module.scss delete mode 100644 components/DataTable.module.scss delete mode 100644 components/DatePicker.module.scss delete mode 100644 components/Dialog.module.scss delete mode 100644 components/Divider.module.scss delete mode 100644 components/Drawer.module.scss delete mode 100644 components/DropdownMenu.module.scss delete mode 100644 components/DropdownMenuTrigger.module.scss delete mode 100644 components/Grid.module.scss delete mode 100644 components/HoverComponentTrigger.module.scss delete mode 100644 components/Indent.module.scss delete mode 100644 components/Input.module.scss delete mode 100644 components/ListItem.module.scss delete mode 100644 components/MatrixLoader.module.scss delete mode 100644 components/Message.module.scss delete mode 100644 components/MessageViewer.module.scss delete mode 100644 components/ModalStack.module.scss delete mode 100644 components/Navigation.module.scss delete mode 100644 components/NumberRangeSlider.module.scss delete mode 100644 components/Popover.module.scss delete mode 100644 components/RadioButton.module.scss delete mode 100644 components/Row.module.scss delete mode 100644 components/RowEllipsis.module.scss delete mode 100644 components/RowSpaceBetween.module.scss delete mode 100644 components/Select.module.scss delete mode 100644 components/SidebarLayout.module.scss delete mode 100644 components/Table.module.scss delete mode 100644 components/TableColumn.module.scss delete mode 100644 components/TableRow.module.scss delete mode 100644 components/Text.module.scss delete mode 100644 components/TextArea.module.scss delete mode 100644 components/Tooltip.module.scss delete mode 100644 components/TreeView.module.scss delete mode 100644 components/examples/AS400.module.scss delete mode 100644 components/examples/DashboardRadar.module.scss delete mode 100644 components/examples/Denabase.module.scss delete mode 100644 components/modals/ModalAlert.module.scss delete mode 100644 components/modals/ModalCanvasPlatformer.module.scss delete mode 100644 components/modals/ModalCanvasSnake.module.scss delete mode 100644 components/modals/ModalChess.module.scss delete mode 100644 components/modals/ModalCreateAccount.module.scss delete mode 100644 components/modals/ModalError.module.scss delete mode 100644 components/modals/ModalMatrixModes.module.scss delete mode 100644 components/page/DefaultActionBar.module.scss delete mode 100755 components/page/DefaultLayout.module.scss rename global.scss => global.css (93%) mode change 100755 => 100644 create mode 100644 postcss.config.mjs create mode 100644 tailwind.config.js diff --git a/app/page.tsx b/app/page.tsx index 5ca7423..3803e55 100755 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,4 +1,4 @@ -import '@root/global.scss'; +import '@root/global.css'; import * as Constants from '@common/constants'; import * as Utilities from '@common/utilities'; diff --git a/components/Accordion.module.scss b/components/Accordion.module.scss deleted file mode 100644 index 773dffa..0000000 --- a/components/Accordion.module.scss +++ /dev/null @@ -1,31 +0,0 @@ -.flex { - display: flex; - align-items: center; - justify-content: space-between; - - &:hover { - background: var(--theme-focused-foreground); - } -} - -.icon { - flex-shrink: 0; - user-select: none; - cursor: pointer; -} - -.content { - min-width: 10%; - width: 100%; - user-select: none; - cursor: pointer; - transition: 200ms ease all; - transition-property: padding; - padding-left: 0ch; -} - -.active { - .content { - padding-left: 1ch; - } -} diff --git a/components/Accordion.tsx b/components/Accordion.tsx index e3c4c8e..fbecd51 100644 --- a/components/Accordion.tsx +++ b/components/Accordion.tsx @@ -1,12 +1,17 @@ 'use client'; -import styles from '@components/Accordion.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; import Row from '@components/Row'; +const styles = { + flex: "flex items-center justify-between hover:bg-[var(--theme-focused-foreground)]", + icon: "flex-shrink-0 select-none cursor-pointer", + content: "min-w-[10%] w-full select-none cursor-pointer transition-[padding] duration-200 ease", + active: "pl-[1ch]" +}; + interface AccordionProps { defaultValue?: boolean; title: string; @@ -24,9 +29,9 @@ const Accordion: React.FC = ({ defaultValue = false, title, chil return ( <> -
+
{show ? '▾' : '▸'} - {title} + {title}
{show && {children}} diff --git a/components/ActionBar.module.scss b/components/ActionBar.module.scss deleted file mode 100644 index 37dd948..0000000 --- a/components/ActionBar.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.root { - background: var(--theme-background); - box-shadow: inset 0 0 0 1px var(--theme-border); -} \ No newline at end of file diff --git a/components/ActionBar.tsx b/components/ActionBar.tsx index bbd296f..fd24c20 100644 --- a/components/ActionBar.tsx +++ b/components/ActionBar.tsx @@ -1,7 +1,5 @@ -import styles from '@components/ActionBar.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; import ButtonGroup from '@components/ButtonGroup'; @@ -18,6 +16,10 @@ interface ActionBarProps { items: ActionBarItem[]; } +const styles = { + root: "bg-[var(--theme-background)] shadow-[inset_0_0_0_1px_var(--theme-border)]" +}; + const ActionBar: React.FC = ({ items }) => { return (
diff --git a/components/ActionButton.module.scss b/components/ActionButton.module.scss deleted file mode 100644 index 756581b..0000000 --- a/components/ActionButton.module.scss +++ /dev/null @@ -1,59 +0,0 @@ -.hotkey { - background: var(--theme-button-foreground); - color: var(--theme-text); - cursor: pointer; - flex-shrink: 0; - font-weight: 400; - padding: 0 1ch 0 1ch; - text-indent: 0ch; - user-select: none; -} - -.content { - background: var(--theme-button-background); - box-shadow: inset 0 0 0 2px var(--theme-button-foreground); - cursor: pointer; - flex-shrink: 0; - font-weight: 400; - padding: 0 1ch 0 1ch; - text-indent: 0ch; - text-transform: uppercase; - user-select: none; -} - -.root { - display: inline-flex; - align-items: center; - justify-content: space-between; - cursor: pointer; - outline: 0; - border: 0; - margin: 0; - padding: 0; - box-sizing: border-box; - font-family: var(--font-family-mono); - font-size: var(--font-size); - flex-shrink: 0; - - &:hover .hotkey { - background: var(--theme-focused-foreground); - } - - &:hover .content { - box-shadow: inset 0 0 0 2px var(--theme-focused-foreground); - } - - &:focus .hotkey { - background: var(--theme-focused-foreground); - } - - &:focus .content { - box-shadow: inset 0 0 0 2px var(--theme-focused-foreground); - } -} - -.selected { - .content { - background: var(--theme-focused-foreground); - } -} diff --git a/components/ActionButton.tsx b/components/ActionButton.tsx index 84a6018..1abf0b9 100644 --- a/components/ActionButton.tsx +++ b/components/ActionButton.tsx @@ -1,6 +1,6 @@ -import styles from '@components/ActionButton.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; + import * as Utilities from '@common/utilities'; interface ActionButtonProps { @@ -12,11 +12,18 @@ interface ActionButtonProps { isSelected?: boolean; } +const styles = { + root: "inline-flex items-center justify-between cursor-pointer outline-0 border-0 m-0 p-0 box-border font-[var(--font-family-mono)] text-[var(--font-size)] flex-shrink-0", + hotkey: "bg-[var(--theme-button-foreground)] text-[var(--theme-text)] cursor-pointer flex-shrink-0 font-normal px-[1ch] text-indent-0 select-none group-hover:bg-[var(--theme-focused-foreground)] group-focus:bg-[var(--theme-focused-foreground)]", + content: "bg-[var(--theme-button-background)] shadow-[inset_0_0_0_2px_var(--theme-button-foreground)] cursor-pointer flex-shrink-0 font-normal px-[1ch] text-indent-0 uppercase select-none group-hover:shadow-[inset_0_0_0_2px_var(--theme-focused-foreground)] group-focus:shadow-[inset_0_0_0_2px_var(--theme-focused-foreground)]", + selected: "bg-[var(--theme-focused-foreground)]" +}; + const ActionButton = React.forwardRef(({ onClick, hotkey, children, style, rootStyle, isSelected }, ref) => { return ( -
+
{Utilities.isEmpty(hotkey) ? null : {hotkey}} - + {children}
diff --git a/components/ActionListItem.module.scss b/components/ActionListItem.module.scss deleted file mode 100644 index fd183a0..0000000 --- a/components/ActionListItem.module.scss +++ /dev/null @@ -1,52 +0,0 @@ -.item { - align-items: flex-start; - background: transparent; - color: var(--theme-text); - cursor: pointer; - display: flex; - justify-content: space-between; - outline: 0; - border: 0; - text-decoration: none; - - &:visited { - background: transparent; - color: var(--theme-text); - } - - &:hover { - background: transparent; - color: var(--theme-text); - } - - &:hover .icon { - background: var(--theme-focused-foreground); - } - - &:focus .icon { - background: var(--theme-focused-foreground); - } -} - -.icon { - align-items: center; - background: var(--theme-button-foreground); - display: inline-flex; - flex-shrink: 0; - height: calc(var(--font-size) * var(--theme-line-height-base)); - justify-content: center; - width: 3ch; - user-select: none; -} - -.text { - align-items: center; - align-self: stretch; - background: var(--theme-button-background); - display: inline-flex; - justify-content: flex-start; - min-width: 10%; - padding: 0 1ch 0 1ch; - user-select: none; - width: 100%; -} diff --git a/components/ActionListItem.tsx b/components/ActionListItem.tsx index 6bee1f8..78b6250 100644 --- a/components/ActionListItem.tsx +++ b/components/ActionListItem.tsx @@ -1,7 +1,11 @@ -import styles from '@components/ActionListItem.module.scss'; - import * as React from 'react'; +const styles = { + item: "flex items-start justify-between bg-transparent text-[var(--theme-text)] cursor-pointer outline-0 border-0 no-underline group !no-underline", + icon: "!flex items-center justify-center bg-[var(--theme-button-foreground)] flex-shrink-0 w-[3ch] h-[calc(var(--font-size)*var(--theme-line-height-base))] select-none group-hover:bg-[var(--theme-focused-foreground)] group-focus:bg-[var(--theme-focused-foreground)]", + text: "inline-flex items-center justify-start self-stretch bg-[var(--theme-button-background)] min-w-[10%] w-full px-[1ch] select-none" +}; + interface ActionListItemProps { style?: React.CSSProperties; icon?: React.ReactNode; diff --git a/components/AlertBanner.module.scss b/components/AlertBanner.module.scss deleted file mode 100644 index 228be57..0000000 --- a/components/AlertBanner.module.scss +++ /dev/null @@ -1,7 +0,0 @@ -.root { - display: block; - background: var(--theme-border); - box-shadow: 1ch 1ch 0 0 var(--theme-border-subdued); - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - font-weight: 400; -} diff --git a/components/AlertBanner.tsx b/components/AlertBanner.tsx index fd46436..4753c29 100644 --- a/components/AlertBanner.tsx +++ b/components/AlertBanner.tsx @@ -1,6 +1,9 @@ -import styles from '@components/AlertBanner.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; + +const styles = { + root: "block bg-[var(--theme-border)] shadow-[1ch_1ch_0_0_var(--theme-border-subdued)] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] font-normal" +}; interface AlertBannerProps { style?: any; @@ -10,7 +13,7 @@ interface AlertBannerProps { const AlertBanner: React.FC = ({ style: propStyle, ...rest }) => { let style: React.CSSProperties = { ...propStyle }; - return
; + return
; }; export default AlertBanner; diff --git a/components/Avatar.module.scss b/components/Avatar.module.scss deleted file mode 100644 index 29ffc8d..0000000 --- a/components/Avatar.module.scss +++ /dev/null @@ -1,119 +0,0 @@ -.parent { - display: flex; - align-items: flex-start; - justify-content: space-between; -} - -.placeholder { - background: var(--theme-border); - display: inline-block; - width: 4ch; - height: calc(var(--font-size) * var(--theme-line-height-base) * 2); - vertical-align: bottom; - flex-shrink: 0; - position: relative; - - &:hover { - &::before { - content: ''; - top: 0; - left: 0; - right: 0; - bottom: 0; - position: absolute; - pointer-events: none; - opacity: 0.5; - background: var(--theme-focused-foreground); - } - } -} - -.root { - background: unset; - background-size: cover; - background-position: 50% 50%; - background-repeat: no-repeat; - display: inline-block; - width: 4ch; - height: calc(var(--font-size) * var(--theme-line-height-base) * 2); - vertical-align: bottom; - flex-shrink: 0; - position: relative; - - &:hover { - background: unset; - background-size: cover; - background-position: 50% 50%; - background-repeat: no-repeat; - &::before { - content: ''; - top: 0; - left: 0; - right: 0; - bottom: 0; - position: absolute; - pointer-events: none; - opacity: 0.5; - background: var(--theme-focused-foreground); - } - } -} - -a { - &.root { - background: unset; - background-size: cover; - background-position: 50% 50%; - background-repeat: no-repeat; - display: inline-block; - width: 4ch; - height: calc(var(--font-size) * var(--theme-line-height-base) * 2); - vertical-align: bottom; - flex-shrink: 0; - position: relative; - - &:hover { - background: unset; - background-size: cover; - background-position: 50% 50%; - background-repeat: no-repeat; - &::before { - content: ''; - top: 0; - left: 0; - right: 0; - bottom: 0; - position: absolute; - pointer-events: none; - opacity: 0.5; - background: var(--theme-focused-foreground); - } - } - - &:focus { - background: unset; - background-size: cover; - background-position: 50% 50%; - background-repeat: no-repeat; - outline: 0; - - &::before { - content: ''; - top: 0; - left: 0; - right: 0; - bottom: 0; - position: absolute; - pointer-events: none; - opacity: 0.5; - background: var(--theme-focused-foreground); - } - } - } -} - -.right { - min-width: 10%; - width: 100%; - background: var(--theme-foreground); -} diff --git a/components/Avatar.tsx b/components/Avatar.tsx index ad03d2f..b613ea1 100644 --- a/components/Avatar.tsx +++ b/components/Avatar.tsx @@ -1,7 +1,13 @@ -import styles from '@components/Avatar.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; + +const styles = { + parent: "flex items-start justify-between", + placeholder: "bg-[var(--theme-border)] inline-block w-[4ch] h-[calc(var(--font-size)*var(--theme-line-height-base)*2)] align-bottom flex-shrink-0 relative hover:before:content-[''] hover:before:absolute hover:before:inset-0 hover:before:pointer-events-none hover:before:opacity-50 hover:before:bg-[var(--theme-focused-foreground)]", + root: "inline-block w-[4ch] h-[calc(var(--font-size)*var(--theme-line-height-base)*2)] align-bottom flex-shrink-0 relative hover:before:content-[''] hover:before:absolute hover:before:inset-0 hover:before:pointer-events-none hover:before:opacity-50 hover:before:bg-[var(--theme-focused-foreground)]", + link: "inline-block w-[4ch] h-[calc(var(--font-size)*var(--theme-line-height-base)*2)] align-bottom flex-shrink-0 relative hover:before:content-[''] hover:before:absolute hover:before:inset-0 hover:before:pointer-events-none hover:before:opacity-50 hover:before:bg-[var(--theme-focused-foreground)] focus:outline-0", + right: "min-w-[10%] w-full bg-[var(--theme-foreground)]" +}; interface AvatarProps extends Omit, 'style' | 'className' | 'children'> { src?: string; @@ -14,16 +20,21 @@ interface AvatarProps extends Omit, 'style' const Avatar: React.FC = (props) => { const { src, style: propStyle, href, target, children, ...rest } = props; - const backgroundStyle = src ? { backgroundImage: `url(${src})` } : {}; + const backgroundStyle = src ? { + backgroundImage: `url(${src})`, + backgroundSize: '100% 100%', + backgroundPosition: '0 0', + backgroundRepeat: 'no-repeat' + } : {}; const combinedStyle = { ...propStyle, ...backgroundStyle }; let avatarElement: React.ReactElement; if (href) { - avatarElement = ; + avatarElement = ; } else { - avatarElement =
; + avatarElement =
; } if (!children) { diff --git a/components/Badge.module.scss b/components/Badge.module.scss deleted file mode 100644 index 605c33c..0000000 --- a/components/Badge.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -.root { - display: inline-block; - vertical-align: top; - text-align: center; - font-weight: 400; - margin: 0; - outline: 0; - border: 0; - font-family: var(--font-family-mono); - min-height: calc(var(--theme-line-height-base) * var(--font-size)); - text-transform: uppercase; - transition: 200ms ease all; - background: var(--theme-border); - padding: 0 1ch 0 1ch; -} diff --git a/components/Badge.tsx b/components/Badge.tsx index a8e078c..4113d08 100644 --- a/components/Badge.tsx +++ b/components/Badge.tsx @@ -1,8 +1,11 @@ 'use client'; -import styles from '@components/Badge.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; + +const styles = { + root: clsx("inline-block align-top text-center font-normal m-0 outline-0 border-0 font-[var(--font-family-mono)] min-h-[calc(var(--theme-line-height-base)*var(--font-size))] uppercase transition-all duration-200 ease bg-[var(--theme-border)] px-[1ch] py-0") +}; interface BadgeProps extends React.HTMLAttributes { children?: React.ReactNode; diff --git a/components/BarLoader.module.scss b/components/BarLoader.module.scss deleted file mode 100644 index c32eec0..0000000 --- a/components/BarLoader.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -.root { - background: var(--theme-border); - height: calc(var(--font-size) * var(--theme-line-height-base)); - white-space: nowrap; - text-align: left; - vertical-align: bottom; - display: block; -} - -.bar { - background: linear-gradient(to right, transparent, var(--theme-text)); - height: 100%; - width: 0%; - transition: width 0.1s linear; -} diff --git a/components/BarLoader.tsx b/components/BarLoader.tsx index 007599c..3e1184f 100644 --- a/components/BarLoader.tsx +++ b/components/BarLoader.tsx @@ -1,8 +1,12 @@ 'use client'; import * as React from 'react'; +import clsx from 'clsx'; -import styles from '@components/BarLoader.module.scss'; +const styles = { + root: clsx("bg-[var(--theme-border)] h-[calc(var(--font-size)*var(--theme-line-height-base))] whitespace-nowrap text-left align-bottom block"), + bar: clsx("bg-[linear-gradient(to_right,transparent,var(--theme-text))] h-full w-0 transition-[width] duration-100 linear") +}; interface BarLoaderProps { intervalRate?: number; diff --git a/components/BarProgress.module.scss b/components/BarProgress.module.scss deleted file mode 100644 index bbb659e..0000000 --- a/components/BarProgress.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -.root { - display: block; - background: var(--theme-border-subdued); - white-space: nowrap; - text-align: left; - vertical-align: bottom; - overflow: hidden; - position: relative; -} - -.measure { - visibility: hidden; - position: absolute; - pointer-events: none; -} diff --git a/components/BarProgress.tsx b/components/BarProgress.tsx index b79ab0c..7ef3dde 100644 --- a/components/BarProgress.tsx +++ b/components/BarProgress.tsx @@ -1,9 +1,14 @@ 'use client'; -import styles from '@components/BarProgress.module.scss'; +import clsx from 'clsx'; import * as React from 'react'; +const styles = { + root: clsx("block bg-[var(--theme-border-subdued)] whitespace-nowrap text-left align-bottom overflow-hidden relative"), + measure: clsx("invisible absolute pointer-events-none") +}; + interface BarProgressProps { intervalRate?: number; progress?: number; diff --git a/components/Block.module.scss b/components/Block.module.scss deleted file mode 100644 index f5c3988..0000000 --- a/components/Block.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.block { - display: inline-block; - width: 1ch; - background: var(--theme-text); - height: calc(var(--font-size) * var(--theme-line-height-base)); - vertical-align: bottom; - flex-shrink: 0; -} diff --git a/components/Block.tsx b/components/Block.tsx index 380fd34..f71e96f 100644 --- a/components/Block.tsx +++ b/components/Block.tsx @@ -1,6 +1,9 @@ -import styles from '@components/Block.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; + +const styles = { + block: clsx("inline-block w-[1ch] bg-[var(--theme-text)] h-[calc(var(--font-size)*var(--theme-line-height-base))] align-bottom flex-shrink-0") +}; interface BlockProps extends React.HTMLAttributes { children?: React.ReactNode; diff --git a/components/BlockLoader.module.scss b/components/BlockLoader.module.scss deleted file mode 100644 index 354762d..0000000 --- a/components/BlockLoader.module.scss +++ /dev/null @@ -1,7 +0,0 @@ -.root { - display: inline-block; - width: 1ch; - color: inherit; - height: calc(var(--font-size) * var(--theme-line-height-base)); - vertical-align: bottom; -} diff --git a/components/BlockLoader.tsx b/components/BlockLoader.tsx index f167422..4970a81 100644 --- a/components/BlockLoader.tsx +++ b/components/BlockLoader.tsx @@ -1,8 +1,11 @@ 'use client'; -import styles from '@components/BlockLoader.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; + +const styles = { + root: clsx("inline-block w-[1ch] text-inherit h-[calc(var(--font-size)*var(--theme-line-height-base))] align-bottom") +}; const SEQUENCES = [ ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'], @@ -24,7 +27,7 @@ interface BlockLoaderProps extends Omit, ' const BlockLoader: React.FC = ({ mode = 0 }) => { if (!SEQUENCES[mode]) { - return ; + return ; } const [index, setIndex] = React.useState(0); diff --git a/components/BreadCrumbs.module.scss b/components/BreadCrumbs.module.scss deleted file mode 100644 index 90fb1b7..0000000 --- a/components/BreadCrumbs.module.scss +++ /dev/null @@ -1,36 +0,0 @@ -.root { - display: inline-block; -} - -.line { - display: inline-block; - line-height: calc(var(--theme-line-height-base) * 1rem); -} - -.link { - display: inline-block; - color: var(--theme-text); - outline: 0; - border: 0; - text-decoration: none; - background: var(--theme-border); - - &:hover { - color: var(--theme-text); - background: var(--theme-focused-foreground); - } - - &:visited { - color: var(--theme-text); - } - - &:focus { - background: var(--theme-focused-foreground); - } -} - -.symbol { - min-width: 1ch; - display: inline-block; - margin: 0 1ch 0 1ch; -} \ No newline at end of file diff --git a/components/BreadCrumbs.tsx b/components/BreadCrumbs.tsx index 68f7c93..5fa1b86 100644 --- a/components/BreadCrumbs.tsx +++ b/components/BreadCrumbs.tsx @@ -1,6 +1,12 @@ -import styles from '@components/BreadCrumbs.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; + +const styles = { + root: clsx("inline-block"), + line: clsx("inline-block leading-[calc(var(--theme-line-height-base)*1rem)]"), + link: clsx("inline-block text-[var(--theme-text)] outline-0 border-0 !no-underline bg-[var(--theme-border)] hover:text-[var(--theme-text)] hover:bg-[var(--theme-focused-foreground)] visited:text-[var(--theme-text)] focus:bg-[var(--theme-focused-foreground)]"), + symbol: clsx("inline-block mx-[9px] my-0") +}; interface BreadCrumbsItem { url?: string; @@ -24,7 +30,7 @@ const BreadCrumbs: React.FC = ({ items }) => { return ( {index === items.length - 1 ? {linkElement} : linkElement} - {index < items.length - 1 && } + {index < items.length - 1 && } ); })} diff --git a/components/Button.module.scss b/components/Button.module.scss deleted file mode 100644 index a47ca89..0000000 --- a/components/Button.module.scss +++ /dev/null @@ -1,55 +0,0 @@ -.root { - vertical-align: top; - display: inline-block; - font-weight: 400; - text-align: center; - margin: 0; - outline: 0; - border: 0; - font-family: var(--font-family-mono); - width: 100%; - font-size: var(--font-size); - line-height: calc(var(--theme-line-height-base) * 2em); - min-height: calc(var(--theme-line-height-base) * (var(--font-size) * 2)); - padding: 0 2ch 0 2ch; - text-transform: uppercase; - letter-spacing: 1px; - transition: 200ms ease all; -} - -.primary { - background: var(--theme-button); - color: var(--theme-button-text); - cursor: pointer; - - &:hover { - background: var(--theme-focused-foreground); - } - - &:focus { - background: var(--theme-focused-foreground); - } -} - -.secondary { - background: var(--theme-background); - color: var(--theme-text); - box-shadow: inset 0 0 0 1px var(--theme-border); - cursor: pointer; - - &:hover { - background: var(--theme-focused-foreground); - box-shadow: inset 0 0 0 1px transparent; - } - - &:focus { - background: var(--theme-focused-foreground); - box-shadow: inset 0 0 0 1px transparent; - } -} - -.disabled { - background: var(--theme-button-background); - color: var(--theme-button-foreground); - cursor: not-allowed; -} diff --git a/components/Button.tsx b/components/Button.tsx index 7d04b62..3fb8a92 100644 --- a/components/Button.tsx +++ b/components/Button.tsx @@ -1,9 +1,15 @@ 'use client'; -import styles from '@components/Button.module.scss'; +import clsx from 'clsx'; import * as React from 'react'; -import * as Utilities from '@common/utilities'; + +const styles = { + root: clsx("align-top inline-block font-normal text-center m-0 outline-0 border-0 font-[var(--font-family-mono)] w-full text-[var(--font-size)] leading-[calc(var(--theme-line-height-base)*2em)] min-h-[calc(var(--theme-line-height-base)*(var(--font-size)*2))] px-[2ch] py-0 uppercase tracking-[1px] transition-all duration-200 ease"), + primary: clsx("bg-[var(--theme-button)] text-[var(--theme-button-text)] cursor-pointer hover:bg-[var(--theme-focused-foreground)] focus:bg-[var(--theme-focused-foreground)]"), + secondary: clsx("bg-[var(--theme-background)] text-[var(--theme-text)] shadow-[inset_0_0_0_1px_var(--theme-border)] cursor-pointer hover:bg-[var(--theme-focused-foreground)] hover:shadow-[inset_0_0_0_1px_transparent] focus:bg-[var(--theme-focused-foreground)] focus:shadow-[inset_0_0_0_1px_transparent]"), + disabled: clsx("bg-[var(--theme-button-background)] text-[var(--theme-button-foreground)] cursor-not-allowed") +}; interface ButtonProps extends React.ButtonHTMLAttributes { theme?: 'PRIMARY' | 'SECONDARY'; @@ -12,20 +18,20 @@ interface ButtonProps extends React.ButtonHTMLAttributes { } const Button: React.FC = ({ theme = 'PRIMARY', isDisabled, children, ...rest }) => { - let classNames = Utilities.classNames(styles.root, styles.primary); + let buttonClasses = clsx(styles.root, styles.primary); if (theme === 'SECONDARY') { - classNames = Utilities.classNames(styles.root, styles.secondary); + buttonClasses = clsx(styles.root, styles.secondary); } if (isDisabled) { - classNames = Utilities.classNames(styles.root, styles.disabled); + buttonClasses = clsx(styles.root, styles.disabled); - return
{children}
; + return
{children}
; } return ( - ); diff --git a/components/ButtonGroup.module.scss b/components/ButtonGroup.module.scss deleted file mode 100644 index 6cafda3..0000000 --- a/components/ButtonGroup.module.scss +++ /dev/null @@ -1,12 +0,0 @@ -.root { -} - -.full { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(60px, 1fr)); - white-space: nowrap; -} - -.full > * > * { - width: 100%; -} diff --git a/components/ButtonGroup.tsx b/components/ButtonGroup.tsx index ae75ea0..c6fa135 100644 --- a/components/ButtonGroup.tsx +++ b/components/ButtonGroup.tsx @@ -1,20 +1,24 @@ 'use client'; -import styles from '@components/ButtonGroup.module.scss'; +import clsx from 'clsx'; import * as React from 'react'; -import * as Utilities from '@common/utilities'; import ActionButton from '@components/ActionButton'; import DropdownMenuTrigger from '@components/DropdownMenuTrigger'; +const styles = { + root: clsx(""), + full: clsx("grid grid-cols-[repeat(auto-fit,minmax(60px,1fr))] whitespace-nowrap [&>*>*]:w-full") +}; + const ButtonGroup = (props) => { if (!props.items) { return null; } return ( -
+
{props.items.map((each) => { if (each.items) { return ( diff --git a/components/CanvasPlatformer.module.scss b/components/CanvasPlatformer.module.scss deleted file mode 100644 index 0527e03..0000000 --- a/components/CanvasPlatformer.module.scss +++ /dev/null @@ -1,16 +0,0 @@ -.container { - width: 100%; - height: auto; - position: relative; -} - -.root { - display: block; - width: 100%; - background: transparent; - - &:focus { - outline: 0; - box-shadow: inset 0 0 0 1px var(--theme-focused-foreground); - } -} \ No newline at end of file diff --git a/components/CanvasPlatformer.tsx b/components/CanvasPlatformer.tsx index 49431cb..f82c321 100644 --- a/components/CanvasPlatformer.tsx +++ b/components/CanvasPlatformer.tsx @@ -1,11 +1,15 @@ 'use client'; -import styles from '@components/CanvasPlatformer.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import ActionButton from '@components/ActionButton'; +const styles = { + container: clsx("w-full h-auto relative"), + root: clsx("block w-full bg-transparent focus:outline-0 focus:shadow-[inset_0_0_0_1px_var(--theme-focused-foreground)]") +}; + interface PlatformerProps { rows?: number; } diff --git a/components/CanvasSnake.module.scss b/components/CanvasSnake.module.scss deleted file mode 100644 index 64679df..0000000 --- a/components/CanvasSnake.module.scss +++ /dev/null @@ -1,16 +0,0 @@ -.container { - width: 100%; - height: auto; - position: relative; -} - -.root { - display: block; - width: 100%; - background: transparent; - - &:focus { - outline: 0; - box-shadow: inset 0 0 0 1px var(--theme-focused-foreground); - } -} diff --git a/components/CanvasSnake.tsx b/components/CanvasSnake.tsx index 6cc569a..1659940 100644 --- a/components/CanvasSnake.tsx +++ b/components/CanvasSnake.tsx @@ -1,11 +1,15 @@ 'use client'; -import styles from '@components/CanvasSnake.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import ActionButton from '@components/ActionButton'; +const styles = { + container: clsx("w-full h-auto relative"), + root: clsx("block w-full bg-transparent focus:outline-0 focus:shadow-[inset_0_0_0_1px_var(--theme-focused-foreground)]") +}; + interface SnakeProps { rows?: number; } diff --git a/components/Card.module.scss b/components/Card.module.scss deleted file mode 100644 index 3ad4af6..0000000 --- a/components/Card.module.scss +++ /dev/null @@ -1,76 +0,0 @@ -.card { - position: relative; - display: block; - padding-top: 0; - padding-left: 0; - padding-right: 0; - padding-bottom: 0; - white-space: prewrap; -} - -.children { - box-shadow: - inset 2px 0 0 0 var(--theme-text), - inset -2px 0 0 0 var(--theme-text), - inset 0 -2px 0 0 var(--theme-text); - display: block; - padding-top: calc(var(--theme-line-height-base) * 0.5rem); - padding-left: 2ch; - padding-right: 2ch; - padding-bottom: calc(var(--theme-line-height-base) * 1rem); - overflow-x: auto; - overflow-y: hidden; - - &::-webkit-scrollbar { - display: none; - } - - scrollbar-width: none; -} - -.action { - display: flex; - align-items: flex-end; - justify-content: space-between; -} - -.left { - min-width: 10%; - width: 100%; - box-shadow: - inset 2px 0 0 0 var(--theme-text), - inset 0 2px 0 0 var(--theme-text); - padding: calc((var(--font-size) * 0.5) * var(--theme-line-height-base)) 2ch 0px 1ch; -} - -.leftCorner { - flex-shrink: 0; - box-shadow: - inset 2px 0 0 0 var(--theme-text), - inset 0 2px 0 0 var(--theme-text); - padding: calc((var(--font-size) * 0.5) * var(--theme-line-height-base)) 1ch 0px 1ch; -} - -.right { - min-width: 10%; - width: 100%; - box-shadow: - inset -2px 0 0 0 var(--theme-text), - inset 0 2px 0 0 var(--theme-text); - padding: calc((var(--font-size) * 0.5) * var(--theme-line-height-base)) 2ch 0px 1ch; -} - -.rightCorner { - flex-shrink: 0; - box-shadow: - inset -2px 0 0 0 var(--theme-text), - inset 0 2px 0 0 var(--theme-text); - padding: calc((var(--font-size) * 0.5) * var(--theme-line-height-base)) 1ch 0px 1ch; -} - -.title { - flex-shrink: 0; - padding: 0 1ch 0 1ch; - font-size: var(--font-size); - font-weight: 400; -} diff --git a/components/Card.tsx b/components/Card.tsx index b7c15c7..f14957d 100644 --- a/components/Card.tsx +++ b/components/Card.tsx @@ -1,7 +1,16 @@ -import styles from '@components/Card.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; + +const styles = { + card: clsx("relative block p-0 whitespace-pre-wrap"), + children: clsx("shadow-[inset_2px_0_0_0_var(--theme-text),inset_-2px_0_0_0_var(--theme-text),inset_0_-2px_0_0_var(--theme-text)] block pt-[calc(var(--theme-line-height-base)*0.5rem)] px-[2ch] pb-[calc(var(--theme-line-height-base)*1rem)] overflow-x-auto overflow-y-hidden scrollbar-none"), + action: clsx("flex items-end justify-between"), + left: clsx("min-w-[10%] w-full shadow-[inset_2px_0_0_0_var(--theme-text),inset_0_2px_0_0_var(--theme-text)] pt-[calc((var(--font-size)*0.5)*var(--theme-line-height-base))] pr-[2ch] pb-0 pl-[1ch]"), + leftCorner: clsx("flex-shrink-0 shadow-[inset_2px_0_0_0_var(--theme-text),inset_0_2px_0_0_var(--theme-text)] pt-[calc((var(--font-size)*0.5)*var(--theme-line-height-base))] px-[1ch] pb-0"), + right: clsx("min-w-[10%] w-full shadow-[inset_-2px_0_0_0_var(--theme-text),inset_0_2px_0_0_var(--theme-text)] pt-[calc((var(--font-size)*0.5)*var(--theme-line-height-base))] pr-[2ch] pb-0 pl-[1ch]"), + rightCorner: clsx("flex-shrink-0 shadow-[inset_-2px_0_0_0_var(--theme-text),inset_0_2px_0_0_var(--theme-text)] pt-[calc((var(--font-size)*0.5)*var(--theme-line-height-base))] px-[1ch] pb-0"), + title: clsx("flex-shrink-0 px-[1ch] text-[var(--font-size)] font-normal") +}; interface CardProps extends React.HTMLAttributes { children?: React.ReactNode; diff --git a/components/CardDouble.module.scss b/components/CardDouble.module.scss deleted file mode 100644 index 4127ff5..0000000 --- a/components/CardDouble.module.scss +++ /dev/null @@ -1,86 +0,0 @@ -.card { - --card-double-border-width: 6px; - --card-double-half-gutter: (var(--font-size) * 0.5); - --card-double-top-gutter: 6px; - - position: relative; - display: block; - padding-top: 0; - padding-right: 0; - padding-left: 0; - padding-bottom: 0; -} - -.children { - border-left: var(--card-double-border-width) solid var(--theme-text); - border-left-style: double; - border-bottom: var(--card-double-border-width) solid var(--theme-text); - border-bottom-style: double; - border-right: var(--card-double-border-width) solid var(--theme-text); - border-right-style: double; - display: block; - padding-top: calc(var(--theme-line-height-base) * 0.5rem); - padding-left: calc(2ch - var(--card-double-border-width)); - padding-right: calc(2ch - var(--card-double-border-width)); - padding-bottom: calc(var(--theme-line-height-base) * 1rem - var(--card-double-border-width)); - - overflow-x: auto; - overflow-y: hidden; - - &::-webkit-scrollbar { - display: none; - } - - scrollbar-width: none; -} - -.action { - display: flex; - align-items: flex-end; - justify-content: space-between; -} - -.left { - min-width: 10%; - width: 100%; - border-top: var(--card-double-border-width) solid var(--theme-text); - border-top-style: double; - border-left: var(--card-double-border-width) solid var(--theme-text); - border-left-style: double; - padding: calc(var(--card-double-top-gutter) * var(--theme-line-height-base)) 2ch 0px 1ch; -} - -.leftCorner { - flex-shrink: 0; - border-top: var(--card-double-border-width) solid var(--theme-text); - border-top-style: double; - border-left: var(--card-double-border-width) solid var(--theme-text); - border-left-style: double; - padding: calc(var(--card-double-top-gutter) * var(--theme-line-height-base)) calc(1ch - 6px) 0px 1ch; -} - -.right { - min-width: 10%; - width: 100%; - border-top: var(--card-double-border-width) solid var(--theme-text); - border-top-style: double; - border-right: var(--card-double-border-width) solid var(--theme-text); - border-right-style: double; - padding: calc(var(--card-double-top-gutter) * var(--theme-line-height-base)) 2ch 0px 1ch; -} - -.rightCorner { - flex-shrink: 0; - border-top: var(--card-double-border-width) solid var(--theme-text); - border-top-style: double; - border-right: var(--card-double-border-width) solid var(--theme-text); - border-right-style: double; - padding: calc(var(--card-double-top-gutter) * var(--theme-line-height-base)) 1ch 0px calc(1ch - 6px); -} - -.title { - flex-shrink: 0; - padding: 0 1ch 0 1ch; - font-size: var(--font-size); - font-weight: 400; -} diff --git a/components/CardDouble.tsx b/components/CardDouble.tsx index 89bf5bc..72881f7 100644 --- a/components/CardDouble.tsx +++ b/components/CardDouble.tsx @@ -1,7 +1,4 @@ -import styles from '@components/CardDouble.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; interface CardProps extends React.HTMLAttributes { children?: React.ReactNode; @@ -10,6 +7,18 @@ interface CardProps extends React.HTMLAttributes { style?: any; } +const styles = { + card: "relative flex p-0", + action: "flex items-end justify-between", + left: "min-w-[10%] w-full border-t-[6px] border-l-[6px] border-solid border-[var(--theme-text)] [border-top-style:double] [border-left-style:double] pt-[calc(var(--card-double-top-gutter)*var(--theme-line-height-base))] pr-[2ch] pb-0 pl-[1ch]", + right: "min-w-[10%] w-full border-t-[6px] border-r-[6px] border-solid border-[var(--theme-text)] [border-top-style:double] [border-right-style:double] pt-[calc(var(--card-double-top-gutter)*var(--theme-line-height-base))] pr-[2ch] pb-0 pl-[1ch]", + leftCorner: "flex-shrink-0 border-t-[6px] border-l-[6px] border-solid border-[var(--theme-text)] [border-top-style:double] [border-left-style:double] pt-[calc(var(--card-double-top-gutter)*var(--theme-line-height-base))] pr-[calc(1ch-6px)] pb-0 pl-[1ch]", + rightCorner: "flex-shrink-0 border-t-[6px] border-r-[6px] border-solid border-[var(--theme-text)] [border-top-style:double] [border-right-style:double] pt-[calc(var(--card-double-top-gutter)*var(--theme-line-height-base))] pr-[1ch] pb-0 pl-[calc(1ch-6px)]", + title: "flex-shrink-0 px-[1ch] text-[var(--font-size)] font-normal", + children: "block border-l-[6px] border-r-[6px] border-b-[6px] border-solid border-[var(--theme-text)] [border-left-style:double] [border-right-style:double] [border-bottom-style:double] overflow-x-auto overflow-y-hidden scrollbar-none pt-[calc(var(--theme-line-height-base)*0.5rem)] pl-[calc(2ch-6px)] pr-[calc(2ch-6px)] pb-[calc(var(--theme-line-height-base)*1rem-6px)]", + borderChildren: "block" +}; + const CardDouble: React.FC = ({ children, mode, title, style, ...rest }) => { let titleElement = (
@@ -40,7 +49,7 @@ const CardDouble: React.FC = ({ children, mode, title, style, ...rest } return ( -
+
{titleElement}
diff --git a/components/Checkbox.module.scss b/components/Checkbox.module.scss deleted file mode 100644 index 9985dcb..0000000 --- a/components/Checkbox.module.scss +++ /dev/null @@ -1,59 +0,0 @@ -.section { - display: flex; - align-items: flex-start; - justify-content: space-between; - - .right { - padding-bottom: calc(8px * var(--theme-line-height-base)); - box-shadow: inset 0 1px 0 0 var(--theme-border-subdued); - } - - &:last-child { - .right { - padding-bottom: 0; - } - } -} - -.checked { -} - -.focused { - .figure { - background: var(--theme-focused-foreground); - } -} - -.relative { - position: relative; - flex-shrink: 0; - display: inline-block; - vertical-align: baseline; -} - -.figure { - width: 100%; - height: 100%; - cursor: pointer; - color: var(--theme-text); - background: var(--theme-button-foreground); - align-self: stretch; - display: inline-block; - padding: 0 1ch 0 1ch; -} - -.right { - background: var(--theme-button-background); - min-width: 10%; - width: 100%; - align-self: stretch; -} - -.input { - top: 0; - left: 0; - opacity: 0; - position: absolute; - width: 1px; - height: 1px; -} diff --git a/components/Checkbox.tsx b/components/Checkbox.tsx index cdabcbe..80ca0b1 100644 --- a/components/Checkbox.tsx +++ b/components/Checkbox.tsx @@ -1,6 +1,5 @@ 'use client'; -import styles from '@components/Checkbox.module.scss'; import * as React from 'react'; import * as Utilities from '@common/utilities'; @@ -14,6 +13,16 @@ interface CheckboxProps { children?: React.ReactNode; } +const styles = { + section: "flex items-start justify-between", + right: "min-w-[10%] w-full bg-[var(--theme-button-background)] pb-[calc(8px*var(--theme-line-height-base))] shadow-[inset_0_1px_0_0_var(--theme-border-subdued)] last:pb-0", + checked: "", + focused: "", + relative: "relative flex-shrink-0 inline-block align-baseline", + figure: "w-full h-full cursor-pointer text-[var(--theme-text)] bg-[var(--theme-button-foreground)] self-stretch inline-block px-[1ch] group-[.focused]:bg-[var(--theme-focused-foreground)]", + input: "absolute top-0 left-0 opacity-0 w-[1px] h-[1px]" +}; + const Checkbox: React.FC = ({ style, name, defaultChecked = false, onChange, children }) => { const checkboxId = `${name}-checkbox`; const inputRef = React.useRef(null); @@ -61,7 +70,7 @@ const Checkbox: React.FC = ({ style, name, defaultChecked = false
diff --git a/components/Chessboard.module.scss b/components/Chessboard.module.scss deleted file mode 100644 index 9de89e0..0000000 --- a/components/Chessboard.module.scss +++ /dev/null @@ -1,37 +0,0 @@ -.board { - display: inline-table; - border-collapse: collapse; -} - -.corner { - width: 1ch; - height: calc(var(--theme-line-height-base) * 1rem); -} - -.cell { - width: 1ch; - height: calc(var(--theme-line-height-base) * 1rem); - background-color: var(--theme-border-subdued); - text-align: center; - vertical-align: middle; -} - -.square { - height: calc(var(--theme-line-height-base) * 2rem); - text-align: center; - vertical-align: middle; - width: 3ch; -} - -.dark { - background-color: var(--theme-focused-foreground); -} - -.light { - background-color: var(--theme-focused-foreground-subdued); -} - -.symbol { - font-size: 40px; - line-height: calc(var(--theme-line-height-base) * 2rem); -} diff --git a/components/Chessboard.tsx b/components/Chessboard.tsx index 3f63a2f..81d3d38 100644 --- a/components/Chessboard.tsx +++ b/components/Chessboard.tsx @@ -1,13 +1,21 @@ 'use client'; -import styles from '@components/Chessboard.module.scss'; - import * as React from 'react'; import * as Utilities from '@common/utilities'; const FILE = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']; const RANK = [8, 7, 6, 5, 4, 3, 2, 1]; +const styles = { + board: "inline-table border-collapse", + corner: "w-[1ch] h-[calc(var(--theme-line-height-base)*1rem)]", + cell: "w-[1ch] h-[calc(var(--theme-line-height-base)*1rem)] bg-[var(--theme-border-subdued)] text-center align-middle", + square: "h-[calc(var(--theme-line-height-base)*2rem)] text-center align-middle w-[3ch]", + dark: "bg-[var(--theme-focused-foreground)]", + light: "bg-[var(--theme-focused-foreground-subdued)]", + symbol: "text-[40px] leading-[calc(var(--theme-line-height-base)*2rem)]" +}; + const getPieceSymbol = (piece: string) => { const mapping: Record = { K: '♔', diff --git a/components/CodeBlock.module.scss b/components/CodeBlock.module.scss deleted file mode 100644 index 4adf570..0000000 --- a/components/CodeBlock.module.scss +++ /dev/null @@ -1,37 +0,0 @@ -.root { - display: block; - font-weight: 400; - overflow: auto; - font-family: inherit; - background: var(--theme-border-subdued); - - &::-webkit-scrollbar { - display: none; - } - - scrollbar-width: none; -} - -.line { - display: flex; - justify-content: space-between; - align-items: flex-start; -} - -.number { - display: inline-flex; - width: 3ch; - text-align: right; - padding-right: 1ch; - user-select: none; - background: var(--theme-background); - opacity: 0.5; -} - -.content { - min-width: 10%; - width: 100%; - white-space: pre; - background: var(--theme-border-subdued); - padding-left: 2ch; -} diff --git a/components/CodeBlock.tsx b/components/CodeBlock.tsx index f431cb9..9092a72 100644 --- a/components/CodeBlock.tsx +++ b/components/CodeBlock.tsx @@ -1,10 +1,15 @@ 'use client'; -import styles from '@components/CodeBlock.module.scss'; - import * as React from 'react'; import * as Utilities from '@common/utilities'; +const styles = { + root: "block font-normal overflow-auto font-inherit bg-[var(--theme-border-subdued)] scrollbar-none", + line: "flex justify-between items-start", + number: "inline-flex w-[3ch] text-right pr-[1ch] select-none bg-[var(--theme-background)] opacity-50", + content: "min-w-[10%] w-full whitespace-pre bg-[var(--theme-border-subdued)] pl-[2ch]" +}; + interface CodeBlockProps extends React.HTMLAttributes { children?: React.ReactNode; } diff --git a/components/ComboBox.module.scss b/components/ComboBox.module.scss deleted file mode 100644 index add96a7..0000000 --- a/components/ComboBox.module.scss +++ /dev/null @@ -1,3 +0,0 @@ -.root { - padding: 0; -} diff --git a/components/ComboBox.tsx b/components/ComboBox.tsx index 43c60f2..f573d08 100644 --- a/components/ComboBox.tsx +++ b/components/ComboBox.tsx @@ -1,7 +1,5 @@ 'use client'; -import styles from '@components/ComboBox.module.scss'; - import * as React from 'react'; import AlertBanner from '@components/AlertBanner'; @@ -9,6 +7,10 @@ import ButtonGroup from '@components/ButtonGroup'; import CardDouble from '@components/CardDouble'; import Input from '@components/Input'; +const styles = { + root: "p-0" +}; + interface ComboBoxProps { data: string[][]; label?: string; diff --git a/components/ContentFluid.module.scss b/components/ContentFluid.module.scss deleted file mode 100644 index 94fc1eb..0000000 --- a/components/ContentFluid.module.scss +++ /dev/null @@ -1,6 +0,0 @@ -.root { - display: block; - min-width: 10%; - width: 100%; - align-self: stretch; -} diff --git a/components/ContentFluid.tsx b/components/ContentFluid.tsx index 7218fb3..d2b76a2 100644 --- a/components/ContentFluid.tsx +++ b/components/ContentFluid.tsx @@ -1,7 +1,9 @@ -import styles from '@components/ContentFluid.module.scss'; - import * as React from 'react'; +const styles = { + root: "block min-w-[10%] w-full self-stretch" +}; + interface ContentFluidProps extends React.HTMLAttributes { children?: React.ReactNode; } diff --git a/components/DOMSnake.module.scss b/components/DOMSnake.module.scss deleted file mode 100644 index 7c4f78f..0000000 --- a/components/DOMSnake.module.scss +++ /dev/null @@ -1,27 +0,0 @@ -.container { - display: flex; - flex-direction: column; - align-items: center; - gap: 4px, -} - -.grid { - display: grid; - &:focus { - outline: 0; - box-shadow: inset 0 0 0 1px var(--theme-focused-foreground); - } -} - -.cell { - width: 100%; - height: 100%; -} - -.snake { - background-color: var(--theme-text); -} - -.food { - background-color: var(--theme-focused-foreground); -} diff --git a/components/DOMSnake.tsx b/components/DOMSnake.tsx index d552a55..86983a6 100644 --- a/components/DOMSnake.tsx +++ b/components/DOMSnake.tsx @@ -1,9 +1,16 @@ 'use client'; import { useEffect, useState, useRef } from 'react'; -import styles from './DOMSnake.module.scss'; import ActionButton from './ActionButton'; +const styles = { + container: "flex flex-col items-center gap-[4px]", + grid: "grid focus:outline-0 focus:shadow-[inset_0_0_0_1px_var(--theme-focused-foreground)]", + cell: "w-full h-full", + snake: "bg-[var(--theme-text)]", + food: "bg-[var(--theme-focused-foreground)]" +}; + interface SnakeGameProps { width?: number; height?: number; diff --git a/components/DataTable.module.scss b/components/DataTable.module.scss deleted file mode 100644 index b3ad1ae..0000000 --- a/components/DataTable.module.scss +++ /dev/null @@ -1,43 +0,0 @@ -.root { - position: relative; - width: 100%; - border-spacing: 0px; - max-width: 64ch; -} - -.body { -} - -.row { - transition: transform 0.5s ease; - border-spacing: 0px; - - &:first-child { - font-weight: 400; - } - - &:focus { - background: var(--theme-focused-foreground); - outline: 0; - } -} - -.column { - border: 0; - outline: 0; - padding-right: 1ch; - transition: background-color 0.5s ease; -} - -.changed { - animation: flash 2000ms ease; -} - -@keyframes flash { - 0% { - background-color: var(--theme-focused-foreground-subdued); - } - 100% { - background-color: transparent; - } -} diff --git a/components/DataTable.tsx b/components/DataTable.tsx index 78c8cef..65d31f9 100644 --- a/components/DataTable.tsx +++ b/components/DataTable.tsx @@ -1,7 +1,5 @@ 'use client'; -import styles from '@components/DataTable.module.scss'; - import * as React from 'react'; interface TableProps { @@ -28,6 +26,14 @@ function interpolateColor(color1: RGBAColor, color2: RGBAColor, factor: number): }; } +const styles = { + root: "relative w-full border-spacing-0 max-w-[64ch]", + body: "", + row: "transition-transform duration-500 ease-in-out border-spacing-0 first:font-normal focus:bg-[var(--theme-focused-foreground)] focus:outline-0", + column: "border-0 outline-0 pr-[1ch] transition-colors duration-500 ease-in-out", + changed: "animate-[flash_2000ms_ease]" +}; + const DataTable: React.FC = ({ data }) => { const tableRef = React.useRef(null); const prevDataRef = React.useRef(data); @@ -50,6 +56,20 @@ const DataTable: React.FC = ({ data }) => { prevDataRef.current = data; }, [data]); + React.useEffect(() => { + const style = document.createElement('style'); + style.textContent = ` + @keyframes flash { + 0% { background-color: var(--theme-focused-foreground-subdued); } + 100% { background-color: transparent; } + } + `; + document.head.appendChild(style); + return () => { + document.head.removeChild(style); + }; + }, []); + const handleKeyDown = (event: React.KeyboardEvent) => { const activeElement = document.activeElement; if (!activeElement) return; diff --git a/components/DatePicker.module.scss b/components/DatePicker.module.scss deleted file mode 100644 index 63aff23..0000000 --- a/components/DatePicker.module.scss +++ /dev/null @@ -1,62 +0,0 @@ -.root { - display: inline-block; - user-select: none; -} - -.controls { - align-items: center; - background: var(--theme-border); - display: flex; - justify-content: space-between; -} - -.button { - align-self: stretch; - background: none; - border: none; - color: var(--theme-text); - cursor: pointer; - display: inline-block; - line-height: calc(var(--theme-line-height-base) * 1em); - margin: 0; - outline: 0; - padding: 0 1ch 0 1ch; - - &:focus { - background: var(--theme-focused-foreground); - outline: 0; - } -} - -.date { - min-width: 10%; - padding: 0 1ch 0 1ch; - text-align: left; - width: 100%; -} - -.header { - background: var(--theme-border); - display: grid; - grid-template-columns: repeat(7, 1fr); - text-align: center; -} - -.days { - background: var(--theme-border-subdued); - display: grid; - grid-template-columns: repeat(7, 1fr); - grid-template-rows: repeat(6, min-content); - align-items: start; - min-height: calc(var(--theme-line-height-base) * 6em); -} - -.cell { - outline: none; - padding: 0 1ch 0 1ch; - text-align: center; - - &:focus { - background: var(--theme-focused-foreground); - } -} diff --git a/components/DatePicker.tsx b/components/DatePicker.tsx index 5cd0bfa..e36be5f 100644 --- a/components/DatePicker.tsx +++ b/components/DatePicker.tsx @@ -1,9 +1,18 @@ 'use client'; -import styles from '@components/DatePicker.module.scss'; - import * as React from 'react'; +const styles = { + root: "inline-block select-none", + controls: "items-center bg-[var(--theme-border)] flex justify-between", + button: "self-stretch bg-none border-none text-[var(--theme-text)] cursor-pointer inline-block leading-[calc(var(--theme-line-height-base)*1em)] m-0 outline-0 px-[1ch] focus:bg-[var(--theme-focused-foreground)] focus:outline-0", + date: "min-w-[10%] px-[1ch] text-left w-full", + header: "bg-[var(--theme-border)] grid grid-cols-7 text-center", + days: "bg-[var(--theme-border-subdued)] grid grid-cols-7 grid-rows-[repeat(6,min-content)] items-start min-h-[calc(var(--theme-line-height-base)*6em)]", + cell: "outline-none px-[1ch] text-center focus:bg-[var(--theme-focused-foreground)]", + dayCell: "outline-none px-[1ch] text-center" +}; + interface DatePickerProps { year?: number; month?: number; diff --git a/components/Dialog.module.scss b/components/Dialog.module.scss deleted file mode 100644 index f2a0604..0000000 --- a/components/Dialog.module.scss +++ /dev/null @@ -1,35 +0,0 @@ -.root { - display: block; - background: var(--theme-border); - box-shadow: 1ch 1ch 0 0 var(--theme-border-subdued); - font-weight: 400; - max-width: 56ch; - min-width: 24ch; - margin: 0; - padding: 0; -} - -.header { - background: var(--theme-text); - color: var(--theme-background); - text-align: center; - margin: 0; - padding: 0; - display: block; -} - -.message { - display: block; - margin: 0; - text-align: center; - padding: 0 2ch 0 2ch; -} - -.actions { - display: flex; - justify-content: space-between; - align-items: center; - max-width: 24ch; - margin: 0 auto 0 auto; - padding: 0 2ch 0 2ch; -} diff --git a/components/Dialog.tsx b/components/Dialog.tsx index 60a6e23..c948202 100644 --- a/components/Dialog.tsx +++ b/components/Dialog.tsx @@ -1,10 +1,15 @@ -import styles from '@components/Dialog.module.scss'; - import * as React from 'react'; import Block from '@components/Block'; import Button from '@components/Button'; +const styles = { + root: "block bg-[var(--theme-border)] shadow-[1ch_1ch_0_0_var(--theme-border-subdued)] font-normal max-w-[56ch] min-w-[24ch] m-0 p-0", + header: "block bg-[var(--theme-text)] text-[var(--theme-background)] text-center m-0 p-0", + message: "block m-0 text-center px-[2ch]", + actions: "flex justify-between items-center max-w-[24ch] mx-auto px-[2ch]" +}; + interface DialogProps { title?: React.ReactNode; children?: React.ReactNode; diff --git a/components/Divider.module.scss b/components/Divider.module.scss deleted file mode 100644 index 4e1cee1..0000000 --- a/components/Divider.module.scss +++ /dev/null @@ -1,25 +0,0 @@ -.gradient { - background: linear-gradient(to right, transparent, var(--theme-border), transparent); - height: calc(var(--font-size) * var(--theme-line-height-base)); - width: 100%; -} - -.divider { - align-items: center; - border: 0; - display: flex; - flex-direction: column; - flex-shrink: 0; - height: calc(var(--font-size) * var(--theme-line-height-base)); - justify-content: center; - outline: 0; - width: 100%; -} - -.line { - background: var(--theme-text); - display: block; - flex-shrink: 0; - height: 2px; - width: 100%; -} diff --git a/components/Divider.tsx b/components/Divider.tsx index bb7d06d..9c17add 100644 --- a/components/Divider.tsx +++ b/components/Divider.tsx @@ -1,7 +1,11 @@ -import styles from '@components/Divider.module.scss'; - import * as React from 'react'; +const styles = { + gradient: "bg-[linear-gradient(to_right,transparent,var(--theme-border),transparent)] h-[calc(var(--font-size)*var(--theme-line-height-base))] w-full", + divider: "flex items-center border-0 flex-col flex-shrink-0 h-[calc(var(--font-size)*var(--theme-line-height-base))] justify-center outline-0 w-full", + line: "bg-[var(--theme-text)] block flex-shrink-0 h-[2px] w-full" +}; + interface DividerProps extends React.HTMLAttributes { children?: React.ReactNode; type?: string | any; diff --git a/components/Drawer.module.scss b/components/Drawer.module.scss deleted file mode 100644 index 0ef56c0..0000000 --- a/components/Drawer.module.scss +++ /dev/null @@ -1,56 +0,0 @@ -@keyframes fadeInLeft { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.root { - align-self: stretch; - display: flex; - align-items: flex-start; - justify-content: space-between; -} - -.side { - animation: fadeInLeft 0.2s ease-out; - min-width: 10%; - width: 100%; - align-self: stretch; - min-width: 22ch; -} - -.right { - flex-shrink: 0; - align-self: stretch; - background: var(--theme-background-input); - display: flex; - align-items: center; - width: 3ch; -} - -.action { - display: inline-flex; - height: calc(var(--font-size) * var(--theme-line-height-base)); - font-size: var(--font-size); - user-select: none; - cursor: pointer; - color: var(--theme-text); - background: var(--theme-button-foreground); - flex-shrink: 0; - align-items: center; - justify-content: center; - border: 0; - outline: 0; - margin: 0; - padding: 0; - width: 100%; - - &:focus { - border: 0; - outline: 0; - background: var(--theme-focused-foreground); - } -} diff --git a/components/Drawer.tsx b/components/Drawer.tsx index ab46a14..801f49d 100644 --- a/components/Drawer.tsx +++ b/components/Drawer.tsx @@ -1,9 +1,26 @@ 'use client'; -import styles from '@components/Drawer.module.scss'; - import * as React from 'react'; +const styles = { + root: "self-stretch flex items-start justify-between", + side: "animate-[fadeInLeft_0.2s_ease-out] min-w-[22ch] w-full self-stretch", + right: "flex-shrink-0 self-stretch bg-[var(--theme-background-input)] flex items-center w-[3ch]", + action: "inline-flex h-[calc(var(--font-size)*var(--theme-line-height-base))] text-[var(--font-size)] select-none cursor-pointer text-[var(--theme-text)] bg-[var(--theme-button-foreground)] flex-shrink-0 items-center justify-center border-0 outline-0 m-0 p-0 w-full focus:border-0 focus:outline-0 focus:bg-[var(--theme-focused-foreground)]" +}; + +// Add keyframes to document head +if (typeof document !== 'undefined') { + const style = document.createElement('style'); + style.textContent = ` + @keyframes fadeInLeft { + from { opacity: 0; } + to { opacity: 1; } + } + `; + document.head.appendChild(style); +} + interface DrawerProps extends Omit, 'defaultValue'> { children?: React.ReactNode; defaultValue?: boolean; diff --git a/components/DropdownMenu.module.scss b/components/DropdownMenu.module.scss deleted file mode 100644 index ff310e1..0000000 --- a/components/DropdownMenu.module.scss +++ /dev/null @@ -1,10 +0,0 @@ -.root { - display: block; - background: var(--theme-border); - font-weight: 400; -} - -.footer { - background: var(--theme-background-modal-footer); - padding: calc(var(--font-size) * 0.5 * var(--theme-line-height-base)) 1ch calc(var(--font-size) * 0.5 * var(--theme-line-height-base)) 1ch; -} diff --git a/components/DropdownMenu.tsx b/components/DropdownMenu.tsx index e6ae87a..03cb881 100644 --- a/components/DropdownMenu.tsx +++ b/components/DropdownMenu.tsx @@ -1,5 +1,3 @@ -import styles from '@components/DropdownMenu.module.scss'; - import * as React from 'react'; import ActionButton from '@components/ActionButton'; @@ -8,6 +6,11 @@ import ModalTrigger from '@components/ModalTrigger'; import { useHotkeys } from '@modules/hotkeys'; +const styles = { + root: "block bg-[var(--theme-border)] font-normal", + footer: "bg-[var(--theme-background-modal-footer)] px-[1ch] py-[calc(var(--font-size)*0.5*var(--theme-line-height-base))]" +}; + interface DropdownMenuItemProps { children: React.ReactNode; icon?: React.ReactNode; diff --git a/components/DropdownMenuTrigger.module.scss b/components/DropdownMenuTrigger.module.scss deleted file mode 100644 index 4c57aea..0000000 --- a/components/DropdownMenuTrigger.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.root { - display: inline-block; - position: relative; -} diff --git a/components/DropdownMenuTrigger.tsx b/components/DropdownMenuTrigger.tsx index 7fb60bf..4a77e55 100644 --- a/components/DropdownMenuTrigger.tsx +++ b/components/DropdownMenuTrigger.tsx @@ -1,7 +1,5 @@ 'use client'; -import styles from '@components/DropdownMenuTrigger.module.scss'; - import * as Position from '@common/position'; import * as React from 'react'; import * as Utilities from '@common/utilities'; @@ -12,6 +10,10 @@ import OutsideElementEvent from '@components/detectors/OutsideElementEvent'; import { createPortal } from 'react-dom'; import { useHotkeys } from '@modules/hotkeys'; +const styles = { + root: "inline-block relative" +}; + interface DropdownMenuTriggerProps { children: React.ReactElement>; items: any; diff --git a/components/Grid.module.scss b/components/Grid.module.scss deleted file mode 100644 index 206e610..0000000 --- a/components/Grid.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.grid { - display: block; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; -} diff --git a/components/Grid.tsx b/components/Grid.tsx index f3a71e7..a25ccc2 100644 --- a/components/Grid.tsx +++ b/components/Grid.tsx @@ -1,7 +1,9 @@ -import styles from '@components/Grid.module.scss'; - import * as React from 'react'; +const styles = { + grid: "block px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))]" +}; + interface GridProps extends React.HTMLAttributes { children?: React.ReactNode; } diff --git a/components/HoverComponentTrigger.module.scss b/components/HoverComponentTrigger.module.scss deleted file mode 100644 index 4c57aea..0000000 --- a/components/HoverComponentTrigger.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.root { - display: inline-block; - position: relative; -} diff --git a/components/HoverComponentTrigger.tsx b/components/HoverComponentTrigger.tsx index a046b04..5dccfa0 100644 --- a/components/HoverComponentTrigger.tsx +++ b/components/HoverComponentTrigger.tsx @@ -1,7 +1,5 @@ 'use client'; -import styles from '@components/HoverComponentTrigger.module.scss'; - import * as React from 'react'; import * as Position from '@common/position'; @@ -11,6 +9,10 @@ import Tooltip from '@components/Tooltip'; import { createPortal } from 'react-dom'; +const styles = { + root: "inline-block relative" +}; + interface HoverComponentTriggerProps { children: React.ReactElement>; text: string; diff --git a/components/Indent.module.scss b/components/Indent.module.scss deleted file mode 100644 index dfeebe6..0000000 --- a/components/Indent.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.root { - display: block; - padding: 0 0 0 1ch; -} diff --git a/components/Indent.tsx b/components/Indent.tsx index 58e7601..ff9de98 100644 --- a/components/Indent.tsx +++ b/components/Indent.tsx @@ -1,7 +1,9 @@ -import styles from '@components/Indent.module.scss'; - import * as React from 'react'; +const styles = { + root: "block pl-[1ch]" +}; + interface IndentProps extends React.HTMLAttributes { children?: React.ReactNode; } diff --git a/components/Input.module.scss b/components/Input.module.scss deleted file mode 100644 index 6e8b0ab..0000000 --- a/components/Input.module.scss +++ /dev/null @@ -1,79 +0,0 @@ -.root { - position: relative; - display: block; -} - -.label { - background: var(--theme-border); - display: block; -} - -.placeholder { - font-style: italic; - color: var(--theme-overlay); -} - -.displayed { - overflow: hidden; - white-space: nowrap; - pointer-events: none; - overflow-wrap: anywhere; - background: var(--theme-background-input); - box-shadow: inset 0 0 0 2px var(--theme-border); -} - -.focused { - .block { - background: var(--theme-focused-foreground); - } - - .placeholder { - background: var(--theme-focused-foreground); - } -} - -@keyframes blink { - 50% { - opacity: 0; - } -} - -.blink { - animation: blink 1s step-start 0s infinite; -} - -.block { - display: inline-block; - min-width: 1ch; - background: var(--theme-text); - color: var(--theme-background); - height: calc(var(--font-size) * var(--theme-line-height-base)); - vertical-align: bottom; -} - -.inputContainer { - position: relative; - display: block; -} - -.hidden { - position: absolute; - top: 0; - left: 0; - width: 100%; - color: transparent; - background: transparent; - caret-color: transparent; - border: none; - outline: none; - overflow: hidden; - padding: 0; - margin: 0; - line-height: var(--theme-line-height-base); - font-size: var(--font-size); - font-family: inherit; - - &:-webkit-autofill { - -webkit-box-shadow: 0 0 0px 1000px var(--theme-focused-foreground) inset; - } -} diff --git a/components/Input.tsx b/components/Input.tsx index 3546219..c6811e4 100644 --- a/components/Input.tsx +++ b/components/Input.tsx @@ -1,9 +1,32 @@ 'use client'; import * as React from 'react'; +import clsx from 'clsx'; + import * as Utilities from '@common/utilities'; -import styles from '@components/Input.module.scss'; +const styles = { + root: "relative block", + label: "block bg-[var(--theme-border)]", + placeholder: "italic text-[var(--theme-overlay)]", + displayed: "overflow-hidden whitespace-nowrap pointer-events-none break-anywhere bg-[var(--theme-background-input)] shadow-[inset_0_0_0_2px_var(--theme-border)]", + focused: "has-[.block]:bg-[var(--theme-focused-foreground)]", + blink: "animate-[blink_1s_step-start_0s_infinite]", + block: "inline-block min-w-[1ch] bg-[var(--theme-text)] text-[var(--theme-background)] h-[calc(var(--font-size)*var(--theme-line-height-base))] align-bottom group-[.focused]:bg-[var(--theme-focused-foreground)]", + inputContainer: "relative block", + hidden: "absolute top-0 left-0 w-full text-transparent bg-transparent caret-transparent border-none outline-none overflow-hidden p-0 m-0 leading-[var(--theme-line-height-base)] text-[var(--font-size)] font-inherit [-webkit-autofill:shadow-[0_0_0px_1000px_var(--theme-focused-foreground)_inset]]" +}; + +// Add keyframes to document head +if (typeof document !== 'undefined') { + const style = document.createElement('style'); + style.textContent = ` + @keyframes blink { + 50% { opacity: 0; } + } + `; + document.head.appendChild(style); +} type InputProps = React.InputHTMLAttributes & { caretChars?: string | any; @@ -82,7 +105,7 @@ function Input({ caretChars, isBlink = true, label, placeholder, onChange, type, }; const isPlaceholderVisible = !text && placeholder; - const containerClasses = Utilities.classNames(styles.root, isFocused && styles.focused); + const containerClasses = clsx(styles.root, isFocused && 'group focused'); const maskText = (t: string) => (type === 'password' ? '•'.repeat(t.length) : t); @@ -97,9 +120,9 @@ function Input({ caretChars, isBlink = true, label, placeholder, onChange, type, )}
-
+
{beforeCaretText} - {!isPlaceholderVisible && {caretChars || ''}} + {!isPlaceholderVisible && {caretChars || ''}} {!isPlaceholderVisible && afterCaretText}
diff --git a/components/ListItem.module.scss b/components/ListItem.module.scss deleted file mode 100644 index e7732e3..0000000 --- a/components/ListItem.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.root { - padding-left: 1ch; - - &:focus { - outline: 0; - background: var(--theme-focused-foreground); - } -} \ No newline at end of file diff --git a/components/ListItem.tsx b/components/ListItem.tsx index f4da36c..33cf7c5 100644 --- a/components/ListItem.tsx +++ b/components/ListItem.tsx @@ -1,9 +1,12 @@ 'use client'; -import styles from '@components/ListItem.module.scss'; - import * as React from 'react'; import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; + +const styles = { + root: "pl-[1ch] focus:outline-0 focus:bg-[var(--theme-focused-foreground)]" +}; const ListItem = ({ children }) => { const itemRef = React.useRef(null); @@ -34,7 +37,7 @@ const ListItem = ({ children }) => { }; return ( -
  • +
  • {children}
  • ); diff --git a/components/MatrixLoader.module.scss b/components/MatrixLoader.module.scss deleted file mode 100644 index 6a2af50..0000000 --- a/components/MatrixLoader.module.scss +++ /dev/null @@ -1,11 +0,0 @@ -.container { - width: 100%; - height: auto; - position: relative; -} - -.root { - display: block; - width: 100%; - background: transparent; -} \ No newline at end of file diff --git a/components/MatrixLoader.tsx b/components/MatrixLoader.tsx index c5d3dc4..ff8fcc8 100644 --- a/components/MatrixLoader.tsx +++ b/components/MatrixLoader.tsx @@ -1,9 +1,12 @@ 'use client'; -import styles from '@components/MatrixLoader.module.scss'; - import * as React from 'react'; +const styles = { + container: "w-full h-auto relative", + root: "block w-full bg-transparent" +}; + interface MatrixLoaderProps { rows?: number; direction?: undefined | 'top-to-bottom' | 'left-to-right'; diff --git a/components/Message.module.scss b/components/Message.module.scss deleted file mode 100644 index aaadf97..0000000 --- a/components/Message.module.scss +++ /dev/null @@ -1,41 +0,0 @@ -.message { - display: flex; - align-items: flex-start; - justify-content: space-between; - margin-bottom: calc(var(--font-size) * var(--theme-line-height-base)); - - &:last-child { - margin-bottom: 0px; - } -} - -.left { - align-self: stretch; - flex-shrink: 0; - display: flex; - align-items: flex-end; - position: relative; -} - -.triangle { - display: inline-block; - width: 0; - height: 0; - border-top: calc((var(--font-size) * var(--theme-line-height-base)) / 2) solid transparent; - border-bottom: calc((var(--font-size) * var(--theme-line-height-base)) / 2) solid transparent; - border-right: 1ch solid var(--theme-border); - margin-bottom: calc((var(--font-size) * var(--theme-line-height-base)) / 2); -} - -.right { - min-width: 10%; - width: 100%; - text-align: left; -} - -.bubble { - padding: calc(8px * var(--theme-line-height-base)) 1ch calc(8px * var(--theme-line-height-base)) 1ch; - background: var(--theme-border); - display: inline-block; - box-shadow: 1ch 1ch 0 0 var(--theme-border-subdued); -} diff --git a/components/Message.tsx b/components/Message.tsx index ddbe0e3..e7eaa1f 100644 --- a/components/Message.tsx +++ b/components/Message.tsx @@ -1,4 +1,12 @@ -import styles from '@components/Message.module.scss'; +import clsx from 'clsx'; + +const styles = { + message: "flex items-start justify-between mb-[calc(var(--font-size)*var(--theme-line-height-base))] last:mb-0", + left: "self-stretch flex-shrink-0 flex items-end relative", + triangle: "inline-block w-0 h-0 border-t-[calc((var(--font-size)*var(--theme-line-height-base))/2)] border-b-[calc((var(--font-size)*var(--theme-line-height-base))/2)] border-r-[1ch] border-transparent border-r-[var(--theme-border)] mb-[calc((var(--font-size)*var(--theme-line-height-base))/2)]", + right: "min-w-[10%] w-full text-left", + bubble: "inline-block bg-[var(--theme-border)] py-[calc(8px*var(--theme-line-height-base))] px-[1ch] shadow-[1ch_1ch_0_0_var(--theme-border-subdued)]" +}; export default function Message(props) { return ( diff --git a/components/MessageViewer.module.scss b/components/MessageViewer.module.scss deleted file mode 100644 index 1916603..0000000 --- a/components/MessageViewer.module.scss +++ /dev/null @@ -1,35 +0,0 @@ -.message { - display: flex; - align-items: flex-start; - justify-content: space-between; - margin-bottom: calc(var(--font-size) * var(--theme-line-height-base)); -} - -.bubble { - display: inline-block; - background: var(--theme-focused-foreground); - padding: calc(8px * var(--theme-line-height-base)) 1ch calc(8px * var(--theme-line-height-base)) 1ch; -} - -.left { - min-width: 10%; - width: 100%; - text-align: right; -} - -.right { - align-self: stretch; - flex-shrink: 0; - display: flex; - align-items: flex-end; -} - -.triangle { - display: inline-block; - width: 0; - height: 0; - border-top: calc((var(--font-size) * var(--theme-line-height-base)) / 2) solid transparent; - border-bottom: calc((var(--font-size) * var(--theme-line-height-base)) / 2) solid transparent; - border-left: 1ch solid var(--theme-focused-foreground); - margin-bottom: calc((var(--font-size) * var(--theme-line-height-base)) / 2); -} diff --git a/components/MessageViewer.tsx b/components/MessageViewer.tsx index 2d89d37..c662959 100644 --- a/components/MessageViewer.tsx +++ b/components/MessageViewer.tsx @@ -1,4 +1,12 @@ -import styles from '@components/MessageViewer.module.scss'; +import clsx from 'clsx'; + +const styles = { + message: "flex items-start justify-between mb-[calc(var(--font-size)*var(--theme-line-height-base))]", + bubble: "inline-block bg-[var(--theme-focused-foreground)] py-[calc(8px*var(--theme-line-height-base))] px-[1ch]", + left: "min-w-[10%] w-full text-right", + right: "self-stretch flex-shrink-0 flex items-end", + triangle: "inline-block w-0 h-0 border-t-[calc((var(--font-size)*var(--theme-line-height-base))/2)] border-b-[calc((var(--font-size)*var(--theme-line-height-base))/2)] border-l-[1ch] border-transparent border-l-[var(--theme-focused-foreground)] mb-[calc((var(--font-size)*var(--theme-line-height-base))/2)]" +}; export default function MessageViewer(props) { return ( diff --git a/components/ModalStack.module.scss b/components/ModalStack.module.scss deleted file mode 100644 index 847251b..0000000 --- a/components/ModalStack.module.scss +++ /dev/null @@ -1,20 +0,0 @@ -.root { - align-items: center; - bottom: 0; - display: flex; - justify-content: center; - left: 0; - pointer-events: none; - position: fixed; - right: 0; - top: 0; - z-index: var(--z-index-page-modals); -} - -.item { - pointer-events: auto; - position: absolute; - transition: - opacity 0.2s ease, - transform 0.4s ease; -} diff --git a/components/ModalStack.tsx b/components/ModalStack.tsx index d5369f2..9fc101d 100644 --- a/components/ModalStack.tsx +++ b/components/ModalStack.tsx @@ -1,11 +1,15 @@ 'use client'; -import styles from '@components/ModalStack.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import { useModals } from '@components/page/ModalContext'; +const styles = { + root: "items-center bottom-0 flex justify-center left-0 pointer-events-none fixed right-0 top-0 z-[var(--z-index-page-modals)]", + item: "pointer-events-auto absolute transition-[opacity,transform] duration-[0.2s,0.4s] ease-[ease,ease]" +}; + interface ModalStackProps {} const ModalStack: React.FC = () => { @@ -14,7 +18,7 @@ const ModalStack: React.FC = () => { const totalModals = modalStack.length; return ( -
    +
    {modalStack.map((modalState, index) => { const { key, component: ModalComponent, props } = modalState; @@ -25,7 +29,7 @@ const ModalStack: React.FC = () => { return (
    { children?: React.ReactNode; logoHref?: string; diff --git a/components/NumberRangeSlider.module.scss b/components/NumberRangeSlider.module.scss deleted file mode 100644 index d2f7397..0000000 --- a/components/NumberRangeSlider.module.scss +++ /dev/null @@ -1,103 +0,0 @@ -.root { - display: flex; - align-items: center; - justify-content: space-between; -} - -.amount { - flex-shrink: 0; - background: var(--theme-text); - color: var(--theme-background); - font-weight: 400; - padding: 0 1ch 0 1ch; -} - -.slider { - border-radius: 0; - display: block; - margin: 0; - padding: 0; - width: 100%; - min-width: 10%; - - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - - background: var(--theme-border-subdued); - - &:focus { - background: linear-gradient(to right, transparent, var(--theme-focused-foreground)); - outline: none; - } - - &:hover { - background: linear-gradient(to right, transparent, var(--theme-focused-foreground)); - cursor: pointer; - } - - &::-webkit-slider-thumb { - -webkit-appearance: none; - appearance: none; - font-size: var(--font-size); - width: 1ch; - height: calc(var(--font-size) * var(--theme-line-height-base)); - background: var(--theme-button-foreground); - vertical-align: bottom; - cursor: pointer; - border-radius: 0; - } - - /* Customizing the track */ - &::-webkit-slider-runnable-track { - height: calc(var(--font-size) * var(--theme-line-height-base)); - background: var(--theme-border-subdued); - border-radius: 0; - } - - &::-moz-range-thumb { - -moz-appearance: none; - appearance: none; - font-size: var(--font-size); - width: 1ch; - height: calc(var(--font-size) * var(--theme-line-height-base)); - background: var(--theme-button-foreground); - vertical-align: bottom; - cursor: pointer; - border: none; - border-radius: 0; - } - - &::-moz-range-track { - height: calc(var(--font-size) * var(--theme-line-height-base)); - background: var(--theme-border-subdued); - border-radius: 0; - } - - &::-ms-thumb { - appearance: none; - font-size: var(--font-size); - width: 1ch; - height: calc(var(--font-size) * var(--theme-line-height-base)); - background: var(--theme-button-foreground); - vertical-align: bottom; - cursor: pointer; - border: none; - border-radius: 0; - } - - &::-ms-track { - height: calc(var(--font-size) * var(--theme-line-height-base)); - background: transparent; - border-color: transparent; - color: transparent; - } - - &::-ms-fill-lower { - background: var(--theme-border-subdued); - } - - &::-ms-fill-upper { - background: var(--theme-border-subdued); - } -} diff --git a/components/NumberRangeSlider.tsx b/components/NumberRangeSlider.tsx index 0d74b02..889ebe9 100644 --- a/components/NumberRangeSlider.tsx +++ b/components/NumberRangeSlider.tsx @@ -1,9 +1,25 @@ 'use client'; -import styles from '@components/NumberRangeSlider.module.scss'; - import * as React from 'react'; +const styles = { + root: "flex items-center justify-between", + amount: "flex-shrink-0 bg-[var(--theme-text)] text-[var(--theme-background)] font-normal px-[1ch]", + slider: [ + "block w-full min-w-[10%] m-0 p-0 rounded-0 appearance-none bg-[var(--theme-border-subdued)]", + "focus:bg-[linear-gradient(to_right,transparent,var(--theme-focused-foreground))] focus:outline-none", + "hover:bg-[linear-gradient(to_right,transparent,var(--theme-focused-foreground))] hover:cursor-pointer", + "[&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-[1ch] [&::-webkit-slider-thumb]:h-[calc(var(--font-size)*var(--theme-line-height-base))] [&::-webkit-slider-thumb]:bg-[var(--theme-button-foreground)] [&::-webkit-slider-thumb]:align-bottom [&::-webkit-slider-thumb]:cursor-pointer [&::-webkit-slider-thumb]:rounded-0", + "[&::-webkit-slider-runnable-track]:h-[calc(var(--font-size)*var(--theme-line-height-base))] [&::-webkit-slider-runnable-track]:bg-[var(--theme-border-subdued)] [&::-webkit-slider-runnable-track]:rounded-0", + "[&::-moz-range-thumb]:appearance-none [&::-moz-range-thumb]:w-[1ch] [&::-moz-range-thumb]:h-[calc(var(--font-size)*var(--theme-line-height-base))] [&::-moz-range-thumb]:bg-[var(--theme-button-foreground)] [&::-moz-range-thumb]:align-bottom [&::-moz-range-thumb]:cursor-pointer [&::-moz-range-thumb]:border-0 [&::-moz-range-thumb]:rounded-0", + "[&::-moz-range-track]:h-[calc(var(--font-size)*var(--theme-line-height-base))] [&::-moz-range-track]:bg-[var(--theme-border-subdued)] [&::-moz-range-track]:rounded-0", + "[&::-ms-thumb]:appearance-none [&::-ms-thumb]:w-[1ch] [&::-ms-thumb]:h-[calc(var(--font-size)*var(--theme-line-height-base))] [&::-ms-thumb]:bg-[var(--theme-button-foreground)] [&::-ms-thumb]:align-bottom [&::-ms-thumb]:cursor-pointer [&::-ms-thumb]:border-0 [&::-ms-thumb]:rounded-0", + "[&::-ms-track]:h-[calc(var(--font-size)*var(--theme-line-height-base))] [&::-ms-track]:bg-transparent [&::-ms-track]:border-transparent [&::-ms-track]:text-transparent", + "[&::-ms-fill-lower]:bg-[var(--theme-border-subdued)] [&::-ms-fill-upper]:bg-[var(--theme-border-subdued)]" + ].join(" "), + left: "" +}; + interface RangerProps { defaultValue?: number; max?: number; diff --git a/components/Popover.module.scss b/components/Popover.module.scss deleted file mode 100644 index bb971a6..0000000 --- a/components/Popover.module.scss +++ /dev/null @@ -1,7 +0,0 @@ -.root { - display: block; - background: var(--theme-border); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - font-weight: 400; -} diff --git a/components/Popover.tsx b/components/Popover.tsx index 8660b45..97d4b19 100644 --- a/components/Popover.tsx +++ b/components/Popover.tsx @@ -1,7 +1,9 @@ -import styles from '@components/Popover.module.scss'; - import * as React from 'react'; +const styles = { + root: "block bg-[var(--theme-border)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] font-normal" +}; + interface PopoverProps extends React.HTMLAttributes {} const Popover = React.forwardRef(({ style: propStyle, ...rest }, ref) => { diff --git a/components/RadioButton.module.scss b/components/RadioButton.module.scss deleted file mode 100644 index 3f41665..0000000 --- a/components/RadioButton.module.scss +++ /dev/null @@ -1,74 +0,0 @@ -.section { - display: flex; - align-items: flex-start; - justify-content: space-between; - position: relative; - - .right { - padding-bottom: calc(8px * var(--theme-line-height-base)); - box-shadow: inset 0 1px 0 0 var(--theme-border-subdued); - } - - &:last-child { - .right { - padding-bottom: 0; - } - } -} - -.figure { - display: inline-flex; - height: calc(var(--font-size) * var(--theme-line-height-base)); - cursor: pointer; - color: var(--theme-text); - background: var(--theme-button-foreground); - width: 3ch; - align-items: center; - justify-content: center; -} - -.selected { - .figure { - background: var(--theme-text); - } -} - -.dot { - display: inline-block; - width: 1ch; - height: 1ch; - background: var(--theme-background); - transform: rotate(45deg); - vertical-align: middle; -} - -.focused { - .figure { - background: var(--theme-focused-foreground); - } -} - -.relative { - flex-shrink: 0; - display: inline-block; - vertical-align: baseline; -} - -.right { - background: var(--theme-button-background); - min-width: 10%; - width: 100%; - align-self: stretch; -} - -.input { - position: absolute; - height: 1px; - width: 1px; - opacity: 0; - background: transparent; - border: 0; - outline: 0; - margin: 0; - padding: 0; -} diff --git a/components/RadioButton.tsx b/components/RadioButton.tsx index e82a012..6aa93f4 100644 --- a/components/RadioButton.tsx +++ b/components/RadioButton.tsx @@ -1,8 +1,18 @@ -import styles from '@components/RadioButton.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import * as Utilities from '@common/utilities'; +const styles = { + section: "flex items-start justify-between relative", + right: "bg-[var(--theme-button-background)] min-w-[10%] w-full self-stretch pb-[calc(8px*var(--theme-line-height-base))] shadow-[inset_0_1px_0_0_var(--theme-border-subdued)] last:pb-0", + figure: "inline-flex h-[calc(var(--font-size)*var(--theme-line-height-base))] cursor-pointer text-[var(--theme-text)] w-[3ch] items-center justify-center bg-[var(--theme-button-foreground)] group-[.selected]:bg-[var(--theme-text)] group-[.focused]:!bg-[var(--theme-focused-foreground)]", + selected: "has-[.figure]:bg-[var(--theme-text)]", + dot: "inline-block w-[1ch] h-[1ch] bg-[var(--theme-background)] rotate-45 align-middle", + focused: "has-[.figure]:bg-[var(--theme-focused-foreground)]", + relative: "flex-shrink-0 inline-block align-baseline", + input: "absolute h-[1px] w-[1px] opacity-0 bg-transparent border-0 outline-0 m-0 p-0" +}; + interface RadioButtonProps { style?: React.CSSProperties; name: string; @@ -47,10 +57,12 @@ const RadioButton: React.FC = ({ style, name, value, selected return (
    diff --git a/components/Row.module.scss b/components/Row.module.scss deleted file mode 100644 index a57b442..0000000 --- a/components/Row.module.scss +++ /dev/null @@ -1,10 +0,0 @@ -.row { - display: block; - outline: 0; - border: 0; - transition: 200ms ease background; - - &:focus { - background: var(--theme-focused-foreground); - } -} diff --git a/components/Row.tsx b/components/Row.tsx index 3964bf4..e7b6fd4 100644 --- a/components/Row.tsx +++ b/components/Row.tsx @@ -1,9 +1,11 @@ 'use client'; -import styles from '@components/Row.module.scss'; - import * as React from 'react'; +const styles = { + row: "block outline-0 border-0 transition-[background] duration-200 ease focus:bg-[var(--theme-focused-foreground)]" +}; + type RowProps = React.HTMLAttributes & { children?: React.ReactNode; }; diff --git a/components/RowEllipsis.module.scss b/components/RowEllipsis.module.scss deleted file mode 100644 index fc2b133..0000000 --- a/components/RowEllipsis.module.scss +++ /dev/null @@ -1,13 +0,0 @@ -.row { - display: block; - outline: 0; - border: 0; - transition: 200ms ease background; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - - &:focus { - background: var(--theme-focused-foreground); - } -} diff --git a/components/RowEllipsis.tsx b/components/RowEllipsis.tsx index fd044f2..d7f36d4 100644 --- a/components/RowEllipsis.tsx +++ b/components/RowEllipsis.tsx @@ -1,9 +1,11 @@ 'use client'; -import styles from '@components/RowEllipsis.module.scss'; - import * as React from 'react'; +const styles = { + row: "block outline-0 border-0 transition-[background] duration-200 ease whitespace-nowrap overflow-hidden text-ellipsis focus:bg-[var(--theme-focused-foreground)]" +}; + type RowEllipsisProps = React.HTMLAttributes & { children?: React.ReactNode; }; diff --git a/components/RowSpaceBetween.module.scss b/components/RowSpaceBetween.module.scss deleted file mode 100644 index 0e50037..0000000 --- a/components/RowSpaceBetween.module.scss +++ /dev/null @@ -1,11 +0,0 @@ -.row { - display: flex; - justify-content: space-between; - outline: 0; - border: 0; - transition: 200ms ease background; - - &:focus { - background: var(--theme-focused-foreground); - } -} diff --git a/components/RowSpaceBetween.tsx b/components/RowSpaceBetween.tsx index 8c7fcf5..eda5d30 100644 --- a/components/RowSpaceBetween.tsx +++ b/components/RowSpaceBetween.tsx @@ -1,9 +1,11 @@ 'use client'; -import styles from '@components/RowSpaceBetween.module.scss'; - import * as React from 'react'; +const styles = { + row: "flex justify-between outline-0 border-0 transition-[background] duration-200 ease focus:bg-[var(--theme-focused-foreground)]" +}; + type RowSpaceBetweenProps = React.HTMLAttributes & { children?: React.ReactNode; }; diff --git a/components/Select.module.scss b/components/Select.module.scss deleted file mode 100644 index 39c670d..0000000 --- a/components/Select.module.scss +++ /dev/null @@ -1,77 +0,0 @@ -.select { - align-items: flex-start; - cursor: default; - display: flex; - justify-content: space-between; - outline: none; - position: relative; - z-index: var(--z-index-page-select); -} - -.control { - align-self: stretch; - background: var(--theme-button-foreground); - cursor: pointer; - flex-shrink: 0; - padding: 0 1ch 0 1ch; - - &.focused { - background: var(--theme-text); - color: var(--theme-background); - } -} - -.display { - background: var(--theme-border); - border: 0; - color: var(--theme-text); - cursor: pointer; - font-family: var(--font-family-mono); - font-size: var(--font-size); - line-height: calc(var(--theme-line-height-base) * 1rem); - margin: 0; - min-width: 10%; - outline: 0; - padding: 0; - padding-left: 3ch; - text-align: left; - user-select: none; - width: 100%; - - &:focus { - background: var(--theme-focused-foreground); - border: 0; - outline: 0; - } - - &:hover { - background: var(--theme-focused-foreground); - } -} - -.menu { - background-color: var(--theme-border-subdued); - left: 3ch; - list-style-type: none; - padding: 0; - right: 0; - z-index: var(--z-index-page-select); -} - -.item { - border: 0; - cursor: pointer; - outline: 0; - padding-left: 6ch; - user-select: none; - - &:hover { - background: var(--theme-focused-foreground); - } - - &:focus { - background: var(--theme-focused-foreground); - border: 0; - outline: 0; - } -} diff --git a/components/Select.tsx b/components/Select.tsx index 776b2ae..b570f67 100644 --- a/components/Select.tsx +++ b/components/Select.tsx @@ -1,9 +1,16 @@ 'use client'; -import styles from '@components/Select.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; + +const styles = { + select: "flex items-start cursor-default justify-between outline-none relative z-[var(--z-index-page-select)]", + control: "self-stretch bg-[var(--theme-button-foreground)] cursor-pointer flex-shrink-0 px-[1ch]", + focused: "bg-[var(--theme-text)] text-[var(--theme-background)]", + display: "bg-[var(--theme-border)] border-0 text-[var(--theme-text)] cursor-pointer font-[var(--font-family-mono)] text-[var(--font-size)] leading-[calc(var(--theme-line-height-base)*1rem)] m-0 min-w-[10%] outline-0 p-0 pl-[3ch] text-left select-none w-full hover:bg-[var(--theme-focused-foreground)] focus:bg-[var(--theme-focused-foreground)] focus:border-0 focus:outline-0", + menu: "bg-[var(--theme-border-subdued)] left-[3ch] right-0 list-none p-0 z-[var(--z-index-page-select)]", + item: "border-0 cursor-pointer outline-0 pl-[6ch] select-none hover:bg-[var(--theme-focused-foreground)] focus:bg-[var(--theme-focused-foreground)] focus:border-0 focus:outline-0" +}; interface SelectProps { name: string; @@ -45,7 +52,7 @@ const Select: React.FC = ({ name, options, placeholder, defaultValu <>
    { isOpen ? handleClose() : handleOpen(); }} @@ -70,7 +77,7 @@ const Select: React.FC = ({ name, options, placeholder, defaultValu
      {options.map((option, idx) => { return ( -
    • handleSelect(option)}> +
    • handleSelect(option)}> {option}
    • ); diff --git a/components/SidebarLayout.module.scss b/components/SidebarLayout.module.scss deleted file mode 100644 index af22c25..0000000 --- a/components/SidebarLayout.module.scss +++ /dev/null @@ -1,55 +0,0 @@ -.root { - display: flex; - align-items: flex-start; - justify-content: space-between; - white-space: pre-wrap; -} - -.sidebar { - align-self: stretch; - flex-shrink: 0; - width: 20ch; -} - -.handle { - align-self: stretch; - flex-shrink: 0; - display: flex; - align-items: center; - justify-content: center; - width: 3ch; - outline: 0; - border: 0; - cursor: col-resize; - - &:hover { - .line { - background: var(--theme-focused-foreground); - } - } - - &:focus { - outline: 0; - border: 0; - - .line { - background: var(--theme-focused-foreground); - } - } -} - -.line { - align-self: stretch; - width: 2px; - background: var(--theme-text); - - &:first-child { - margin-left: 1px; - margin-right: 2px; - } -} - -.content { - min-width: 10%; - width: 100%; -} diff --git a/components/SidebarLayout.tsx b/components/SidebarLayout.tsx index b8aceec..d858ac4 100644 --- a/components/SidebarLayout.tsx +++ b/components/SidebarLayout.tsx @@ -1,8 +1,16 @@ 'use client'; -import styles from '@components/SidebarLayout.module.scss'; +import clsx from 'clsx'; import * as React from 'react'; +const styles = { + root: "flex items-start justify-between whitespace-pre-wrap", + sidebar: "self-stretch flex-shrink-0 w-[20ch]", + handle: "self-stretch flex-shrink-0 flex items-center justify-center w-[3ch] outline-0 border-0 cursor-col-resize group focus:outline-0 focus:border-0", + line: "self-stretch w-[2px] bg-[var(--theme-text)] first-of-type:ml-[1px] first-of-type:mr-[2px] group-hover:bg-[var(--theme-focused-foreground)] group-focus:bg-[var(--theme-focused-foreground)]", + content: "min-w-[10%] w-full" +}; + interface SidebarLayoutProps extends Omit, 'defaultValue'> { children?: React.ReactNode; sidebar?: React.ReactNode; @@ -39,7 +47,7 @@ const SidebarLayout: React.FC = ({ defaultSidebarWidth = 20, if (isReversed) { return ( -
      +
      {children}
       
      = ({ defaultSidebarWidth = 20, } return ( -
      +
      & { children?: React.ReactNode; }; diff --git a/components/TableColumn.module.scss b/components/TableColumn.module.scss deleted file mode 100644 index 7fd23ac..0000000 --- a/components/TableColumn.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -.root { - border: 0; - outline: 0; - margin: 0; - padding: 0; - transition: background-color 0.5s ease; - padding-left: 1ch; - font-size: var(--font-size); - flex-shrink: 0; - -webkit-text-size-adjust: 100%; - - &:first-child { - padding-left: 0px; - } -} diff --git a/components/TableColumn.tsx b/components/TableColumn.tsx index cb65165..3b0c47d 100644 --- a/components/TableColumn.tsx +++ b/components/TableColumn.tsx @@ -1,9 +1,11 @@ 'use client'; -import styles from '@components/TableColumn.module.scss'; - import * as React from 'react'; +const styles = { + root: "border-0 outline-0 m-0 p-0 pl-[1ch] text-[var(--font-size)] flex-shrink-0 [-webkit-text-size-adjust:100%] transition-[background-color] duration-500 ease first:pl-0" +}; + type TableColumnProps = React.HTMLAttributes & { children?: React.ReactNode; }; diff --git a/components/TableRow.module.scss b/components/TableRow.module.scss deleted file mode 100644 index 922c892..0000000 --- a/components/TableRow.module.scss +++ /dev/null @@ -1,15 +0,0 @@ -.root { - border: 0; - outline: 0; - margin: 0; - padding: 0; - - transition: transform 0.5s ease; - border-spacing: 0px; - -webkit-text-size-adjust: 100%; - - &:focus { - background: var(--theme-focused-foreground); - outline: 0; - } -} diff --git a/components/TableRow.tsx b/components/TableRow.tsx index 11db551..5a70274 100644 --- a/components/TableRow.tsx +++ b/components/TableRow.tsx @@ -1,9 +1,11 @@ 'use client'; -import styles from '@components/TableRow.module.scss'; - import * as React from 'react'; +const styles = { + root: "border-0 outline-0 m-0 p-0 transition-transform duration-500 ease border-spacing-0 [-webkit-text-size-adjust:100%] focus:bg-[var(--theme-focused-foreground)] focus:outline-0" +}; + type TableRowProps = React.HTMLAttributes & { children?: React.ReactNode; }; diff --git a/components/Text.module.scss b/components/Text.module.scss deleted file mode 100644 index f38473a..0000000 --- a/components/Text.module.scss +++ /dev/null @@ -1,4 +0,0 @@ -.text { - white-space: pre-wrap; - overflow-wrap: break-word; -} diff --git a/components/Text.tsx b/components/Text.tsx index 3a703bd..dc3e819 100644 --- a/components/Text.tsx +++ b/components/Text.tsx @@ -1,7 +1,9 @@ -import styles from '@components/Text.module.scss'; - import * as React from 'react'; +const styles = { + text: "whitespace-pre-wrap break-words" +}; + interface TextProps extends React.HTMLAttributes { children?: React.ReactNode; } diff --git a/components/TextArea.module.scss b/components/TextArea.module.scss deleted file mode 100644 index 5f2582d..0000000 --- a/components/TextArea.module.scss +++ /dev/null @@ -1,74 +0,0 @@ -.root { - position: relative; -} - -.placeholder { - opacity: 0.7; - font-style: italic; -} - -.displayed { - white-space: pre-wrap; - word-wrap: break-word; - pointer-events: none; - overflow-wrap: anywhere; -} - -.hidden { - white-space: pre-wrap; - word-wrap: break-word; - pointer-events: none; - overflow-wrap: anywhere; - position: absolute; - visibility: hidden; - width: 100%; - overflow: auto; -} - -.focused { - .block { - background: var(--theme-focused-foreground); - } - - .placeholder { - background: var(--theme-focused-foreground); - } -} - -@keyframes blink { - 50% { - opacity: 0; - } -} - -.blink { - animation: blink 1s step-start 0s infinite; -} - -.block { - display: inline-block; - min-width: 1ch; - background: var(--theme-text); - height: calc(var(--font-size) * var(--theme-line-height-base)); - vertical-align: bottom; -} - -.hiddenElement { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - color: transparent; - background: transparent; - caret-color: transparent; - border: none; - resize: none; - outline: none; - overflow: hidden; - padding: 0; - margin: 0; - line-height: var(--theme-line-height-base); - font-size: var(--font-size); - font-family: inherit; -} diff --git a/components/TextArea.tsx b/components/TextArea.tsx index 544dabb..6a69e48 100644 --- a/components/TextArea.tsx +++ b/components/TextArea.tsx @@ -1,9 +1,22 @@ 'use client'; -import styles from '@components/TextArea.module.scss'; - import * as React from 'react'; import * as Utilities from '@common/utilities'; +import { clsx } from 'clsx'; + +const styles = { + root: "relative", + placeholder: "opacity-70 italic", + displayed: "whitespace-pre-wrap break-words pointer-events-none break-anywhere", + hidden: "whitespace-pre-wrap break-words pointer-events-none break-anywhere absolute invisible w-full overflow-auto", + focused: "group", + blink: "!animate-[blink_1s_steps(1)_infinite]", + block: [ + "inline-block min-w-[1ch] bg-[var(--theme-text)] h-[calc(var(--font-size)*var(--theme-line-height-base))] align-bottom", + "group-[.focused]/textarea:bg-[var(--theme-focused-foreground)]" + ].join(" "), + hiddenElement: "absolute top-0 left-0 w-full h-full text-transparent bg-transparent caret-transparent border-none resize-none outline-none overflow-hidden p-0 m-0 leading-[var(--theme-line-height-base)] text-[var(--font-size)] font-inherit" +}; type TextAreaProps = React.TextareaHTMLAttributes & { autoPlay?: string; @@ -160,13 +173,19 @@ function TextArea({ autoPlay, autoPlaySpeedMS = 40, isBlink, placeholder, onChan const isPlaceholderVisible = !text && placeholder; - const containerClasses = Utilities.classNames(styles.root, isFocused && styles.focused); + const containerClasses = clsx(styles.root, isFocused && 'focused group/textarea'); return (
      -
      +
      {isPlaceholderVisible ? placeholder : text.substring(0, selectionStart)} - {!isPlaceholderVisible && } + {!isPlaceholderVisible && } {!isPlaceholderVisible && text.substring(selectionStart)}
      diff --git a/components/Tooltip.module.scss b/components/Tooltip.module.scss deleted file mode 100644 index 84f945b..0000000 --- a/components/Tooltip.module.scss +++ /dev/null @@ -1,7 +0,0 @@ -.root { - display: block; - background: var(--theme-border); - box-shadow: 0.5ch 0.5ch 0 0 var(--theme-border-subdued); - font-weight: 400; - max-width: 24ch; -} diff --git a/components/Tooltip.tsx b/components/Tooltip.tsx index da411a6..b80e3cf 100644 --- a/components/Tooltip.tsx +++ b/components/Tooltip.tsx @@ -1,7 +1,9 @@ -import styles from '@components/Tooltip.module.scss'; - import * as React from 'react'; +const styles = { + root: "block bg-[var(--theme-border)] shadow-[0.5ch_0.5ch_0_0_var(--theme-border-subdued)] font-normal max-w-[24ch]" +}; + interface TooltipProps extends React.HTMLAttributes {} const Tooltip = React.forwardRef(({ style: propStyle, ...rest }, ref) => { diff --git a/components/TreeView.module.scss b/components/TreeView.module.scss deleted file mode 100644 index 055165f..0000000 --- a/components/TreeView.module.scss +++ /dev/null @@ -1,18 +0,0 @@ -.root { - white-space: nowrap; - -webkit-text-size-adjust: 100%; -} - -.item { - cursor: pointer; - - &:focus { - outline: 0; - border: 0; - background: var(--theme-focused-foreground); - } -} - -.empty { - opacity: 0.5; -} diff --git a/components/TreeView.tsx b/components/TreeView.tsx index ad37a9c..fe12a83 100644 --- a/components/TreeView.tsx +++ b/components/TreeView.tsx @@ -1,8 +1,13 @@ 'use client'; -import styles from '@components/TreeView.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; + +const styles = { + root: "whitespace-nowrap [-webkit-text-size-adjust:100%]", + item: "cursor-pointer focus:outline-0 focus:border-0 focus:bg-[var(--theme-focused-foreground)]", + empty: "opacity-50" +}; interface TreeViewProps { children?: React.ReactNode; @@ -35,7 +40,13 @@ const TreeView: React.FC = ({ defaultValue = false, title, childr return (
      -
      +
      {prefix} {icon} {title} diff --git a/components/examples/AS400.module.scss b/components/examples/AS400.module.scss deleted file mode 100644 index c3a2af6..0000000 --- a/components/examples/AS400.module.scss +++ /dev/null @@ -1,2 +0,0 @@ -.root { -} diff --git a/components/examples/AS400.tsx b/components/examples/AS400.tsx index b95687b..1ddaa43 100644 --- a/components/examples/AS400.tsx +++ b/components/examples/AS400.tsx @@ -1,7 +1,5 @@ 'use client'; -import styles from '@components/AS400.module.scss'; - import * as React from 'react'; import Card from '@components/Card'; diff --git a/components/examples/DashboardRadar.module.scss b/components/examples/DashboardRadar.module.scss deleted file mode 100644 index 7394676..0000000 --- a/components/examples/DashboardRadar.module.scss +++ /dev/null @@ -1,64 +0,0 @@ -.customSidebar { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - flex-direction: column; - height: calc(var(--theme-line-height-base) * (var(--font-size) * 29.5)); -} - -.customTop { - min-height: 10%; - height: 100%; -} - -.customBottom { - flex-shrink: 0; - width: 100%; -} - -.root { - min-width: 56ch; -} - -.cross { - width: 9ch; - height: calc(var(--theme-line-height-base) * (var(--font-size) * 7)); - margin: calc(var(--theme-line-height-base) * (var(--font-size) * 0.5)) 0 calc(var(--theme-line-height-base) * (var(--font-size) * 0.5)) 0; - display: flex; - justify-content: space-between; - flex-direction: column; -} - -.square { - width: 4.3ch; - height: calc(var(--theme-line-height-base) * (var(--font-size) * 3.4)); -} - -.nw { - border-right: 2px solid var(--theme-text); - border-bottom: 2px solid var(--theme-text); -} - -.ne { - border-left: 2px solid var(--theme-text); - border-bottom: 2px solid var(--theme-text); -} - -.sw { - border-top: 2px solid var(--theme-text); - border-right: 2px solid var(--theme-text); -} - -.se { - border-top: 2px solid var(--theme-text); - border-left: 2px solid var(--theme-text); -} - -.customContent { - width: 100%; - display: flex; - align-items: center; - justify-content: center; - height: calc(var(--theme-line-height-base) * (var(--font-size) * 24.5)); -} diff --git a/components/examples/DashboardRadar.tsx b/components/examples/DashboardRadar.tsx index c0965c2..c8f725d 100644 --- a/components/examples/DashboardRadar.tsx +++ b/components/examples/DashboardRadar.tsx @@ -1,5 +1,3 @@ -import styles from '@components/examples/DashboardRadar.module.scss'; - import * as React from 'react'; import * as Utilities from '@common/utilities'; @@ -10,6 +8,20 @@ import RowSpaceBetween from '@components/RowSpaceBetween'; import SidebarLayout from '@components/SidebarLayout'; import Sphere from '@components/svg/Sphere'; +const styles = { + customSidebar: "flex items-center justify-between w-full flex-col h-[calc(var(--theme-line-height-base)*(var(--font-size)*29.5))]", + customTop: "min-h-[10%] h-full", + customBottom: "flex-shrink-0 w-full", + root: "min-w-[56ch]", + cross: "w-[9ch] h-[calc(var(--theme-line-height-base)*(var(--font-size)*7))] my-[calc(var(--theme-line-height-base)*(var(--font-size)*0.5))] flex justify-between flex-col", + square: "w-[4.3ch] h-[calc(var(--theme-line-height-base)*(var(--font-size)*3.4))]", + nw: "border-r-2 border-b-2 border-[var(--theme-text)]", + ne: "border-l-2 border-b-2 border-[var(--theme-text)]", + sw: "border-t-2 border-r-2 border-[var(--theme-text)]", + se: "border-t-2 border-l-2 border-[var(--theme-text)]", + customContent: "w-full flex items-center justify-center h-[calc(var(--theme-line-height-base)*(var(--font-size)*24.5))]" +}; + const RadarMarker = (props) => { return (
      diff --git a/components/examples/Denabase.module.scss b/components/examples/Denabase.module.scss deleted file mode 100644 index 009c777..0000000 --- a/components/examples/Denabase.module.scss +++ /dev/null @@ -1,108 +0,0 @@ -.root { - min-width: 68ch; - margin-top: calc(var(--theme-line-height-base) * 1rem); -} - -.dna { - min-width: 71ch; - -webkit-text-size-adjust: 100%; -} - -.tag { - width: 3ch; - height: calc(var(--theme-line-height-base) * 0.5rem); - flex-shrink: 0; - box-shadow: - inset 2px 0 0 var(--theme-text), - inset -2px 0 0 var(--theme-text), - inset 0 2px 0 var(--theme-text); -} - -.secondaryTag { - width: 3ch; - align-self: stretch; - flex-shrink: 0; - box-shadow: - inset 2px 0 0 var(--theme-text), - inset -2px 0 0 var(--theme-text), - inset 0 2px 0 var(--theme-text); -} - -.small { - width: 13ch; - flex-shrink: 0; - text-align: right; -} - -.smallWithBorder { - width: 13ch; - flex-shrink: 0; - text-align: right; - box-shadow: inset 0 2px 0 var(--theme-text); -} - -.smallSection { - width: 13ch; - flex-shrink: 0; - min-width: 10%; - text-align: right; - box-shadow: inset 0 2px 0 var(--theme-text); -} - -.large { - width: 80%; - min-width: 10%; - text-align: right; -} - -.largeWithBorder { - width: 80%; - min-width: 10%; - text-align: right; - box-shadow: - inset 0 2px 0 var(--theme-text), - inset -2px 0 0 var(--theme-text); -} - -.largeSection { - width: 80%; - min-width: 10%; - text-align: right; - box-shadow: - inset 0 2px 0 var(--theme-text), - inset -2px 0 0 var(--theme-text); -} - -.absoluteTag { - top: calc(var(--theme-line-height-base) * -0.5rem); - left: 0; - height: calc(var(--theme-line-height-base) * 0.5rem); - width: 14.2ch; - background: var(--theme-background); - position: absolute; - box-shadow: - inset 2px 0 0 var(--theme-text), - inset -2px 0 0 var(--theme-text), - inset 0 2px 0 var(--theme-text); -} - -.box { - width: 7.1ch; - flex-shrink: 0; - height: calc(var(--theme-line-height-base) * 3rem); - display: inline-flex; - align-items: center; - justify-content: center; - box-shadow: - inset -2px 0 0 var(--theme-text), - inset 0 2px 0 var(--theme-text), - inset 0 -2px 0 var(--theme-text); - - &:first-child { - box-shadow: - inset 2px 0 0 var(--theme-text), - inset -2px 0 0 var(--theme-text), - inset 0 2px 0 var(--theme-text), - inset 0 -2px 0 var(--theme-text); - } -} diff --git a/components/examples/Denabase.tsx b/components/examples/Denabase.tsx index c235d36..5462f1d 100644 --- a/components/examples/Denabase.tsx +++ b/components/examples/Denabase.tsx @@ -1,7 +1,5 @@ 'use client'; -import styles from '@components/examples/Denabase.module.scss'; - import * as React from 'react'; import ActionButton from '@components/ActionButton'; @@ -11,6 +9,21 @@ import Row from '@components/Row'; import RowSpaceBetween from '@components/RowSpaceBetween'; import SidebarLayout from '@components/SidebarLayout'; +const styles = { + root: "min-w-[68ch] mt-[calc(var(--theme-line-height-base)*1rem)]", + dna: "min-w-[71ch] [-webkit-text-size-adjust:100%]", + tag: "w-[3ch] h-[calc(var(--theme-line-height-base)*0.5rem)] flex-shrink-0 [box-shadow:inset_2px_0_0_var(--theme-text),inset_-2px_0_0_var(--theme-text),inset_0_2px_0_var(--theme-text)]", + secondaryTag: "w-[3ch] self-stretch flex-shrink-0 [box-shadow:inset_2px_0_0_var(--theme-text),inset_-2px_0_0_var(--theme-text),inset_0_2px_0_var(--theme-text)]", + small: "w-[13ch] flex-shrink-0 text-right", + smallWithBorder: "w-[13ch] flex-shrink-0 text-right [box-shadow:inset_0_2px_0_var(--theme-text)]", + smallSection: "w-[13ch] flex-shrink-0 min-w-[10%] text-right [box-shadow:inset_0_2px_0_var(--theme-text)]", + large: "w-[80%] min-w-[10%] text-right", + largeWithBorder: "w-[80%] min-w-[10%] text-right [box-shadow:inset_0_2px_0_var(--theme-text),inset_-2px_0_0_var(--theme-text)]", + largeSection: "w-[80%] min-w-[10%] text-right [box-shadow:inset_0_2px_0_var(--theme-text),inset_-2px_0_0_var(--theme-text)]", + absoluteTag: "absolute top-[calc(var(--theme-line-height-base)*-0.5rem)] left-0 h-[calc(var(--theme-line-height-base)*0.5rem)] w-[14.2ch] bg-[var(--theme-background)] [box-shadow:inset_2px_0_0_var(--theme-text),inset_-2px_0_0_var(--theme-text),inset_0_2px_0_var(--theme-text)]", + box: "w-[7.1ch] flex-shrink-0 h-[calc(var(--theme-line-height-base)*3rem)] inline-flex items-center justify-center [box-shadow:inset_-2px_0_0_var(--theme-text),inset_0_2px_0_var(--theme-text),inset_0_-2px_0_var(--theme-text)] first:[box-shadow:inset_2px_0_0_var(--theme-text),inset_-2px_0_0_var(--theme-text),inset_0_2px_0_var(--theme-text),inset_0_-2px_0_var(--theme-text)]" +}; + const Denabase = (props) => { return ( <> diff --git a/components/modals/ModalAlert.module.scss b/components/modals/ModalAlert.module.scss deleted file mode 100644 index 3b69ba1..0000000 --- a/components/modals/ModalAlert.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(88px); - } - to { - opacity: 1; - transform: translateY(0px); - } -} - -.root { - animation: fadeIn 0.3s ease-out; - background: var(--theme-background-modal); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - display: block; - font-weight: 400; - margin: 0 auto; - max-width: 64ch; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - user-select: none; - width: 100%; -} diff --git a/components/modals/ModalAlert.tsx b/components/modals/ModalAlert.tsx index 5ad1eb3..1f3f2fb 100644 --- a/components/modals/ModalAlert.tsx +++ b/components/modals/ModalAlert.tsx @@ -1,15 +1,17 @@ 'use client'; -import styles from '@components/modals/ModalAlert.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; +import * as Utilities from '@common/utilities'; import { useModals } from '@components/page/ModalContext'; - import Button from '@components/Button'; import Card from '@components/Card'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + interface ModalAlertProps { buttonText?: string | any; message: string; @@ -19,7 +21,7 @@ function ModalAlert({ message, buttonText }: ModalAlertProps) { const { close } = useModals(); return ( -
      +
      {message}
      diff --git a/components/modals/ModalCanvasPlatformer.module.scss b/components/modals/ModalCanvasPlatformer.module.scss deleted file mode 100644 index 3b69ba1..0000000 --- a/components/modals/ModalCanvasPlatformer.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(88px); - } - to { - opacity: 1; - transform: translateY(0px); - } -} - -.root { - animation: fadeIn 0.3s ease-out; - background: var(--theme-background-modal); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - display: block; - font-weight: 400; - margin: 0 auto; - max-width: 64ch; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - user-select: none; - width: 100%; -} diff --git a/components/modals/ModalCanvasPlatformer.tsx b/components/modals/ModalCanvasPlatformer.tsx index d34b476..0b606ba 100644 --- a/components/modals/ModalCanvasPlatformer.tsx +++ b/components/modals/ModalCanvasPlatformer.tsx @@ -1,9 +1,8 @@ 'use client'; -import styles from '@components/modals/ModalCanvasPlatformer.module.scss'; - import * as React from 'react'; import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; import { useModals } from '@components/page/ModalContext'; @@ -11,6 +10,10 @@ import Button from '@components/Button'; import CanvasPlatformer from '@components/CanvasPlatformer'; import Card from '@components/Card'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + interface ModalCanvasPlatformerProps { buttonText?: string | any; } @@ -19,7 +22,7 @@ function ModalCanvasPlatformer({ buttonText }: ModalCanvasPlatformerProps) { const { close } = useModals(); return ( -
      +

      diff --git a/components/modals/ModalCanvasSnake.module.scss b/components/modals/ModalCanvasSnake.module.scss deleted file mode 100644 index 3b69ba1..0000000 --- a/components/modals/ModalCanvasSnake.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(88px); - } - to { - opacity: 1; - transform: translateY(0px); - } -} - -.root { - animation: fadeIn 0.3s ease-out; - background: var(--theme-background-modal); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - display: block; - font-weight: 400; - margin: 0 auto; - max-width: 64ch; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - user-select: none; - width: 100%; -} diff --git a/components/modals/ModalCanvasSnake.tsx b/components/modals/ModalCanvasSnake.tsx index 474a050..fc06e90 100644 --- a/components/modals/ModalCanvasSnake.tsx +++ b/components/modals/ModalCanvasSnake.tsx @@ -1,16 +1,18 @@ 'use client'; -import styles from '@components/modals/ModalCanvasSnake.module.scss'; - import * as React from 'react'; -import * as Utilities from '@common/utilities'; +import clsx from 'clsx'; +import * as Utilities from '@common/utilities'; import { useModals } from '@components/page/ModalContext'; - import Button from '@components/Button'; import CanvasSnake from '@components/CanvasSnake'; import Card from '@components/Card'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + interface ModalCanvasSnakeProps { buttonText?: string | any; } @@ -19,8 +21,8 @@ function ModalCanvasSnake({ buttonText }: ModalCanvasSnakeProps) { const { close } = useModals(); return ( -
      - +
      +

      diff --git a/components/modals/ModalChess.module.scss b/components/modals/ModalChess.module.scss deleted file mode 100644 index 3b69ba1..0000000 --- a/components/modals/ModalChess.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(88px); - } - to { - opacity: 1; - transform: translateY(0px); - } -} - -.root { - animation: fadeIn 0.3s ease-out; - background: var(--theme-background-modal); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - display: block; - font-weight: 400; - margin: 0 auto; - max-width: 64ch; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - user-select: none; - width: 100%; -} diff --git a/components/modals/ModalChess.tsx b/components/modals/ModalChess.tsx index 32ed8fa..714d6f2 100644 --- a/components/modals/ModalChess.tsx +++ b/components/modals/ModalChess.tsx @@ -1,8 +1,7 @@ 'use client'; -import styles from '@components/modals/ModalChess.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import * as Utilities from '@common/utilities'; import { useHotkeys } from '@modules/hotkeys'; @@ -12,6 +11,10 @@ import Button from '@components/Button'; import CardDouble from '@components/CardDouble'; import Chessboard from '@components/Chessboard'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + interface ModalErrorProps { buttonText?: string | any; board: string[][]; @@ -24,7 +27,7 @@ function ModalChess({ board, buttonText, title }: ModalErrorProps) { useHotkeys('enter', () => close()); return ( -
      +

      diff --git a/components/modals/ModalCreateAccount.module.scss b/components/modals/ModalCreateAccount.module.scss deleted file mode 100644 index 3b69ba1..0000000 --- a/components/modals/ModalCreateAccount.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(88px); - } - to { - opacity: 1; - transform: translateY(0px); - } -} - -.root { - animation: fadeIn 0.3s ease-out; - background: var(--theme-background-modal); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - display: block; - font-weight: 400; - margin: 0 auto; - max-width: 64ch; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - user-select: none; - width: 100%; -} diff --git a/components/modals/ModalCreateAccount.tsx b/components/modals/ModalCreateAccount.tsx index 6ed806e..d6bfb7f 100644 --- a/components/modals/ModalCreateAccount.tsx +++ b/components/modals/ModalCreateAccount.tsx @@ -1,9 +1,7 @@ 'use client'; -import styles from '@components/modals/ModalAlert.module.scss'; - +import clsx from 'clsx'; import * as React from 'react'; -import * as Utilities from '@common/utilities'; import { useModals } from '@components/page/ModalContext'; @@ -13,11 +11,15 @@ import Checkbox from '@components/Checkbox'; import Input from '@components/Input'; import RadioButtonGroup from '@components/RadioButtonGroup'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + function ModalCreateAccount() { const { close } = useModals(); return ( -
      +
      Create a new MakeBelieve™ account, where anything is possible at your command line in the browser.
      diff --git a/components/modals/ModalDOMSnake.tsx b/components/modals/ModalDOMSnake.tsx index 21523e0..82ec742 100644 --- a/components/modals/ModalDOMSnake.tsx +++ b/components/modals/ModalDOMSnake.tsx @@ -1,8 +1,7 @@ 'use client'; -import styles from '@components/modals/ModalCanvasSnake.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import * as Utilities from '@common/utilities'; import { useModals } from '@components/page/ModalContext'; @@ -11,6 +10,10 @@ import Button from '@components/Button'; import Card from '@components/Card'; import DOMSnake from '@components/DOMSnake'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + interface ModalDOMSnakeProps { buttonText?: string | any; } @@ -19,7 +22,7 @@ function ModalDOMSnake({ buttonText }: ModalDOMSnakeProps) { const { close } = useModals(); return ( -
      +

      diff --git a/components/modals/ModalError.module.scss b/components/modals/ModalError.module.scss deleted file mode 100644 index 3b69ba1..0000000 --- a/components/modals/ModalError.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(88px); - } - to { - opacity: 1; - transform: translateY(0px); - } -} - -.root { - animation: fadeIn 0.3s ease-out; - background: var(--theme-background-modal); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - display: block; - font-weight: 400; - margin: 0 auto; - max-width: 64ch; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - user-select: none; - width: 100%; -} diff --git a/components/modals/ModalError.tsx b/components/modals/ModalError.tsx index 991b43a..af61b5b 100644 --- a/components/modals/ModalError.tsx +++ b/components/modals/ModalError.tsx @@ -1,8 +1,7 @@ 'use client'; -import styles from '@components/modals/ModalError.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import * as Utilities from '@common/utilities'; import { useHotkeys } from '@modules/hotkeys'; @@ -13,6 +12,10 @@ import Button from '@components/Button'; import CardDouble from '@components/CardDouble'; import Grid from '@components/Grid'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + interface ModalErrorProps { buttonText?: string | any; message: string | any; @@ -27,7 +30,7 @@ function ModalError({ message, buttonText, title }: ModalErrorProps) { useHotkeys('enter', () => close()); return ( -
      +

      {message} diff --git a/components/modals/ModalMatrixModes.module.scss b/components/modals/ModalMatrixModes.module.scss deleted file mode 100644 index 3b69ba1..0000000 --- a/components/modals/ModalMatrixModes.module.scss +++ /dev/null @@ -1,23 +0,0 @@ -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(88px); - } - to { - opacity: 1; - transform: translateY(0px); - } -} - -.root { - animation: fadeIn 0.3s ease-out; - background: var(--theme-background-modal); - box-shadow: 0 0 0 1ch var(--theme-border-subdued); - display: block; - font-weight: 400; - margin: 0 auto; - max-width: 64ch; - padding: calc(var(--font-size) * var(--theme-line-height-base)) 2ch calc(var(--font-size) * var(--theme-line-height-base)) 2ch; - user-select: none; - width: 100%; -} diff --git a/components/modals/ModalMatrixModes.tsx b/components/modals/ModalMatrixModes.tsx index 72fb8ce..a56bbf1 100644 --- a/components/modals/ModalMatrixModes.tsx +++ b/components/modals/ModalMatrixModes.tsx @@ -1,8 +1,7 @@ 'use client'; -import styles from '@components/modals/ModalMatrixModes.module.scss'; - import * as React from 'react'; +import clsx from 'clsx'; import * as Utilities from '@common/utilities'; import { useModals } from '@components/page/ModalContext'; @@ -11,6 +10,10 @@ import Button from '@components/Button'; import Card from '@components/Card'; import MatrixLoader from '@components/MatrixLoader'; +const styles = { + root: "animate-fadeIn bg-[var(--theme-background-modal)] shadow-[0_0_0_1ch_var(--theme-border-subdued)] block font-normal mx-auto max-w-[64ch] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] select-none w-full" +}; + interface ModalMatrixModesProps { buttonText?: string | any; } @@ -19,7 +22,7 @@ function ModalMatrixModes({ buttonText }: ModalMatrixModesProps) { const { close } = useModals(); return ( -
      +
      diff --git a/components/page/DefaultActionBar.module.scss b/components/page/DefaultActionBar.module.scss deleted file mode 100644 index da6ba3f..0000000 --- a/components/page/DefaultActionBar.module.scss +++ /dev/null @@ -1,6 +0,0 @@ -.root { - position: fixed; - top: 0; - left: 2ch; - z-index: 1; -} diff --git a/components/page/DefaultActionBar.tsx b/components/page/DefaultActionBar.tsx index 2bae7cb..db1aaaa 100644 --- a/components/page/DefaultActionBar.tsx +++ b/components/page/DefaultActionBar.tsx @@ -1,7 +1,5 @@ 'use client'; -import styles from '@components/page/DefaultActionBar.module.scss'; - import * as React from 'react'; import * as Utilities from '@common/utilities'; @@ -9,7 +7,10 @@ import { toggleDebugGrid } from '@components/DebugGrid'; import { useHotkeys } from '@modules/hotkeys'; import ActionBar from '@components/ActionBar'; -import ButtonGroup from '@components/ButtonGroup'; + +const styles = { + root: "fixed top-0 left-[2ch] z-[1]" +}; function isElement(target: EventTarget | null): target is Element { return target instanceof Element; diff --git a/components/page/DefaultLayout.module.scss b/components/page/DefaultLayout.module.scss deleted file mode 100755 index be47d6f..0000000 --- a/components/page/DefaultLayout.module.scss +++ /dev/null @@ -1,11 +0,0 @@ -.body { - max-width: 80ch; -} - -.pixel { - height: 1px; - left: 0; - position: absolute; - top: 0; - width: 1px; -} diff --git a/components/page/DefaultLayout.tsx b/components/page/DefaultLayout.tsx index 44c2e74..1e87c54 100755 --- a/components/page/DefaultLayout.tsx +++ b/components/page/DefaultLayout.tsx @@ -1,7 +1,10 @@ -import styles from '@components/page/DefaultLayout.module.scss'; - import * as React from 'react'; +const styles = { + body: "max-w-[80ch]", + pixel: "h-[1px] w-[1px] absolute top-0 left-0" +}; + interface DefaultLayoutProps { previewPixelSRC: string; children?: React.ReactNode; diff --git a/global.scss b/global.css old mode 100755 new mode 100644 similarity index 93% rename from global.scss rename to global.css index 2ad1816..61fc466 --- a/global.scss +++ b/global.css @@ -1,3 +1,5 @@ +@import "tailwindcss"; + @font-face { font-family: 'CommitMono-Regular'; src: url('https://intdev-global.s3.us-west-2.amazonaws.com/public/internet-dev/3fecb478-80cf-41c5-b834-8562ab0baae0.woff2') format('woff2'); @@ -48,110 +50,6 @@ src: url('https://intdev-global.s3.us-west-2.amazonaws.com/public/internet-dev/e049dfb6-9c5d-4ac4-97c2-eb6e95c61d09.woff2') format('woff2'); } -a, -abbr, -acronym, -address, -applet, -article, -aside, -audio, -b, -big, -blockquote, -body, -canvas, -caption, -center, -cite, -code, -dd, -del, -details, -dfn, -div, -dl, -dt, -embed, -em, -figure, -figcaption, -fieldset, -footer, -form, -h1, -h2, -h3, -h4, -h5, -h6, -header, -hgroup, -html, -i, -iframe, -img, -ins, -kbd, -label, -legend, -li, -mark, -menu, -nav, -object, -ol, -output, -p, -pre, -q, -ruby, -s, -samp, -section, -small, -span, -strike, -strong, -sub, -summary, -sup, -table, -tbody, -td, -tfoot, -th, -thead, -time, -tr, -tt, -u, -ul, -var, -video { - border: 0; - box-sizing: border-box; - margin: 0; - padding: 0; - vertical-align: baseline; -} - -a { - background: var(--theme-border-subdued); - color: var(--theme-text); - - &:hover { - background: var(--theme-focused-foreground); - color: var(--theme-text); - } - - &:focus { - background: var(--theme-focused-foreground); - color: var(--theme-text); - outline: 0; - } -} - ul { list-style-position: inside; list-style-type: '▪'; @@ -177,7 +75,7 @@ ol li { counter-increment: cupcake; } -ul li:before { +ul li::before { content: ' '; display: inline-block; width: 1ch; @@ -185,21 +83,36 @@ ul li:before { visibility: hidden; } -ol li:before { +ol li::before { content: counters(cupcake, '.') '. '; } +a { + background: var(--theme-border-subdued); + color: var(--theme-text); + text-decoration: underline; + + &:hover { + background: var(--theme-focused-foreground); + color: var(--theme-text); + } + + &:focus { + background: var(--theme-focused-foreground); + color: var(--theme-text); + outline: 0; + } +} + article, aside, details, figcaption, figure, footer, -header, hgroup, menu, -nav, -section { +nav { display: block; } @@ -358,9 +271,6 @@ body.font-use-sfmono-square { --font-family-mono: 'SFMonoSquare-Regular', sans-serif; } -#__next { -} - html, body { --color-black-100: rgba(0, 0, 0, 1); @@ -426,7 +336,6 @@ body { --color-gray-90: rgba(38, 38, 38, 1); --color-gray-90-6: rgba(38, 38, 38, 0.6); - --color-green-100: rgba(7, 25, 8, 1); --color-green-100: rgba(7, 25, 8, 1); --color-green-90: rgba(2, 45, 13, 1); --color-green-80: rgba(4, 67, 23, 1); @@ -514,27 +423,30 @@ body { color: var(--theme-text); font-family: var(--font-family-mono); line-height: calc(var(--theme-line-height-base) * 1rem); - font-size: var(--font-size); font-optical-sizing: auto; font-weight: 400; font-variant-numeric: tabular-nums lining-nums; +} - &::-webkit-scrollbar { - background: transparent; - height: calc(var(--theme-line-height-base) * 1rem); - width: 1ch; - } - - &::-webkit-scrollbar-track { - background: var(--theme-background); - } +html::-webkit-scrollbar, +body::-webkit-scrollbar { + background: transparent; + height: calc(var(--theme-line-height-base) * 1rem); + width: 1ch; +} - &::-webkit-scrollbar-thumb { - background: var(--theme-border); - } +html::-webkit-scrollbar-track, +body::-webkit-scrollbar-track { + background: var(--theme-background); +} - &::-webkit-scrollbar-thumb:hover { - background: var(--theme-border); - } +html::-webkit-scrollbar-thumb, +body::-webkit-scrollbar-thumb { + background: var(--theme-border); } + +html::-webkit-scrollbar-thumb:hover, +body::-webkit-scrollbar-thumb:hover { + background: var(--theme-border); +} \ No newline at end of file diff --git a/package.json b/package.json index c4dbef4..23d5f3d 100755 --- a/package.json +++ b/package.json @@ -7,20 +7,24 @@ "license": "MIT", "version": "1.1.4", "scripts": { - "dev": "next -p 10000", + "dev": "next -p 11111", "build": "next build", - "start": "PORT=10000 next start", + "start": "PORT=11111 next start", "lint": "next lint" }, "dependencies": { + "clsx": "^2.1.1", "next": "^15.1.6", + "postcss": "^8.5.2", "react": "^19.0.0", "react-dom": "^19.0.0", - "sass": "1.83.4" + "tailwindcss": "^4.0.6" }, "devDependencies": { + "@tailwindcss/postcss": "^4.0.6", "@types/node": "^22.12.0", - "@types/react": "^19.0.8", + "@types/react": "^19.0.10", + "autoprefixer": "^10.4.20", "ts-node": "^10.9.2", "typescript": "^5.7.3" } diff --git a/pages/_app.tsx b/pages/_app.tsx index 105dd10..193b767 100755 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,4 +1,4 @@ -import '@root/global.scss'; +import '@root/global.css'; import * as React from 'react'; diff --git a/postcss.config.mjs b/postcss.config.mjs new file mode 100644 index 0000000..44d2119 --- /dev/null +++ b/postcss.config.mjs @@ -0,0 +1,6 @@ +export default { + plugins: { + '@tailwindcss/postcss': {}, + autoprefixer: {}, + }, +}; \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..a1cb6d4 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,26 @@ +module.exports = { + theme: { + extend: { + keyframes: { + fadeIn: { + 'from': { + opacity: '0', + transform: 'translateY(88px)' + }, + 'to': { + opacity: '1', + transform: 'translateY(0px)' + } + }, + blink: { + '0%, 100%': { opacity: '1' }, + '50%': { opacity: '0' } + } + }, + animation: { + 'fadeIn': 'fadeIn 0.3s ease-out', + 'blink': 'blink 1s steps(1) infinite' + } + } + } +} \ No newline at end of file From 22c8607433ce3a9161bfcf3de834e3bcf3b2182f Mon Sep 17 00:00:00 2001 From: Stephen Handley Date: Mon, 17 Feb 2025 16:29:31 -0800 Subject: [PATCH 02/11] use old port --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 23d5f3d..bb14107 100755 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "license": "MIT", "version": "1.1.4", "scripts": { - "dev": "next -p 11111", + "dev": "next -p 10000", "build": "next build", - "start": "PORT=11111 next start", + "start": "PORT=10000 next start", "lint": "next lint" }, "dependencies": { From 6aa348e8db439592be66568565ed0592f8ea6e84 Mon Sep 17 00:00:00 2001 From: Stephen Handley Date: Mon, 17 Feb 2025 16:30:56 -0800 Subject: [PATCH 03/11] use old port --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 23d5f3d..bb14107 100755 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "license": "MIT", "version": "1.1.4", "scripts": { - "dev": "next -p 11111", + "dev": "next -p 10000", "build": "next build", - "start": "PORT=11111 next start", + "start": "PORT=10000 next start", "lint": "next lint" }, "dependencies": { From a77854a61abc1d8fba83fd0d49986c32804e9257 Mon Sep 17 00:00:00 2001 From: Stephen Handley Date: Mon, 17 Feb 2025 19:09:23 -0800 Subject: [PATCH 04/11] build npm package --- app/layout.tsx | 1 + app/manifest.ts | 2 +- app/page.tsx | 10 +-- components/Accordion.tsx | 4 +- components/ActionBar.tsx | 6 +- components/ActionButton.tsx | 4 +- components/ActionListItem.tsx | 4 +- components/AlertBanner.tsx | 4 +- components/Avatar.tsx | 4 +- components/Badge.tsx | 4 +- components/BarLoader.tsx | 4 +- components/BarProgress.tsx | 4 +- components/Block.tsx | 4 +- components/BlockLoader.tsx | 4 +- components/BreadCrumbs.tsx | 6 +- components/Button.tsx | 4 +- components/ButtonGroup.tsx | 4 +- components/CanvasPlatformer.tsx | 4 +- components/CanvasSnake.tsx | 4 +- components/Card.tsx | 4 +- components/CardDouble.tsx | 4 +- components/Checkbox.tsx | 4 +- components/Chessboard.tsx | 4 +- components/CodeBlock.tsx | 4 +- components/ComboBox.tsx | 4 +- components/ContentFluid.tsx | 4 +- components/DOMSnake.tsx | 6 +- components/DataTable.tsx | 4 +- components/DatePicker.tsx | 4 +- components/DebugGrid.tsx | 2 +- components/DefaultMetaTags.tsx | 4 +- components/Dialog.tsx | 4 +- components/Divider.tsx | 4 +- components/Drawer.tsx | 14 +--- components/DropdownMenu.tsx | 6 +- components/DropdownMenuTrigger.tsx | 4 +- components/Grid.tsx | 4 +- components/HoverComponentTrigger.tsx | 4 +- components/Indent.tsx | 4 +- components/Input.tsx | 4 +- components/ListItem.tsx | 2 +- components/MatrixLoader.tsx | 4 +- components/Message.tsx | 6 +- components/MessageViewer.tsx | 5 +- components/ModalStack.tsx | 4 +- components/ModalTrigger.tsx | 4 +- components/Navigation.tsx | 4 +- components/NumberRangeSlider.tsx | 4 +- components/Popover.tsx | 4 +- components/Providers.tsx | 12 ++- components/RadioButton.tsx | 4 +- components/RadioButtonGroup.tsx | 4 +- components/Row.tsx | 4 +- components/RowEllipsis.tsx | 4 +- components/RowSpaceBetween.tsx | 4 +- components/Select.tsx | 4 +- components/SidebarLayout.tsx | 4 +- components/Table.tsx | 4 +- components/TableColumn.tsx | 4 +- components/TableRow.tsx | 4 +- components/Text.tsx | 4 +- components/TextArea.tsx | 4 +- components/ThemeProvider.tsx | 30 ++++++++ components/Tooltip.tsx | 4 +- components/TreeView.tsx | 4 +- components/detectors/OutsideElementEvent.tsx | 4 +- components/examples/AS400.tsx | 4 +- components/examples/DashboardRadar.tsx | 4 +- components/examples/Denabase.tsx | 2 +- components/examples/MessagesInterface.tsx | 6 +- components/examples/UpdatingDataTable.tsx | 8 +- components/modals/ModalAlert.tsx | 4 +- components/modals/ModalCanvasPlatformer.tsx | 4 +- components/modals/ModalCanvasSnake.tsx | 4 +- components/modals/ModalChess.tsx | 4 +- components/modals/ModalCreateAccount.tsx | 2 +- components/modals/ModalDOMSnake.tsx | 4 +- components/modals/ModalError.tsx | 4 +- components/modals/ModalMatrixModes.tsx | 4 +- components/page/DefaultActionBar.tsx | 2 +- components/page/DefaultLayout.tsx | 8 +- components/page/ModalContext.tsx | 6 +- components/svg/IntDevLogo.tsx | 4 +- components/svg/Sphere.tsx | 4 +- global.css | 2 - index.ts | 81 ++++++++++++++++++++ package.json | 41 ++++++++-- pages/_app.tsx | 4 +- postcss.config.js | 1 + styles.css | 2 + tailwind.config.js | 20 ++++- tsconfig.json | 62 +++++---------- tsup.config.ts | 19 +++++ 93 files changed, 390 insertions(+), 236 deletions(-) create mode 100644 components/ThemeProvider.tsx create mode 100644 index.ts create mode 100644 postcss.config.js create mode 100644 styles.css create mode 100644 tsup.config.ts diff --git a/app/layout.tsx b/app/layout.tsx index 69e1a66..2c23666 100755 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,3 +1,4 @@ +import '../styles.css'; // This imports both Tailwind and your global styles import Providers from '@components/Providers'; export default function RootLayout({ children }: { children: React.ReactNode }) { diff --git a/app/manifest.ts b/app/manifest.ts index 6649541..a0c27b0 100755 --- a/app/manifest.ts +++ b/app/manifest.ts @@ -1,4 +1,4 @@ -import Package from '@root/package.json'; +import Package from '../package.json'; import { MetadataRoute } from 'next'; diff --git a/app/page.tsx b/app/page.tsx index 3803e55..b83aa43 100755 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,4 +1,4 @@ -import '@root/global.css'; +import '../global.css'; import * as Constants from '@common/constants'; import * as Utilities from '@common/utilities'; @@ -58,7 +58,7 @@ import ModalStack from '@components/ModalStack'; import ModalTrigger from '@components/ModalTrigger'; import Navigation from '@components/Navigation'; import NumberRangeSlider from '@components/NumberRangeSlider'; -import Package from '@root/package.json'; +import Package from '../package.json'; import RadioButtonGroup from '@components/RadioButtonGroup'; import Row from '@components/Row'; import RowSpaceBetween from '@components/RowSpaceBetween'; @@ -72,13 +72,13 @@ import Text from '@components/Text'; import TextArea from '@components/TextArea'; import TreeView from '@components/TreeView'; import UpdatingDataTable from '@components/examples/UpdatingDataTable'; -import ModalDOMSnake from '@root/components/modals/ModalDOMSnake'; +import ModalDOMSnake from '@components/modals/ModalDOMSnake'; export const dynamic = 'force-static'; // NOTE(jimmylee) // https://nextjs.org/docs/app/api-reference/functions/generate-metadata -export async function generateMetadata({ params, searchParams }) { +export async function generateMetadata({ params, searchParams }: any) { const title = Package.name; const description = Package.description; const url = 'https://sacred.computer'; @@ -126,7 +126,7 @@ export async function generateMetadata({ params, searchParams }) { // NOTE(jimmylee) // https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts -export default async function Page(props) { +export default async function Page(props: any) { return (
      diff --git a/components/Accordion.tsx b/components/Accordion.tsx index fbecd51..efa3ea8 100644 --- a/components/Accordion.tsx +++ b/components/Accordion.tsx @@ -12,13 +12,13 @@ const styles = { active: "pl-[1ch]" }; -interface AccordionProps { +export interface AccordionProps { defaultValue?: boolean; title: string; children?: React.ReactNode; } -const Accordion: React.FC = ({ defaultValue = false, title, children }) => { +export const Accordion: React.FC = ({ defaultValue = false, title, children }) => { const [show, setShow] = React.useState(defaultValue); const accordionRef = React.useRef(null); diff --git a/components/ActionBar.tsx b/components/ActionBar.tsx index fd24c20..0eef210 100644 --- a/components/ActionBar.tsx +++ b/components/ActionBar.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import ButtonGroup from '@components/ButtonGroup'; -interface ActionBarItem { +export interface ActionBarItem { hotkey?: string; onClick?: () => void; openHotkey?: string; @@ -12,7 +12,7 @@ interface ActionBarItem { items?: any; } -interface ActionBarProps { +export interface ActionBarProps { items: ActionBarItem[]; } @@ -20,7 +20,7 @@ const styles = { root: "bg-[var(--theme-background)] shadow-[inset_0_0_0_1px_var(--theme-border)]" }; -const ActionBar: React.FC = ({ items }) => { +export const ActionBar: React.FC = ({ items }) => { return (
      diff --git a/components/ActionButton.tsx b/components/ActionButton.tsx index 1abf0b9..d761fff 100644 --- a/components/ActionButton.tsx +++ b/components/ActionButton.tsx @@ -3,7 +3,7 @@ import clsx from 'clsx'; import * as Utilities from '@common/utilities'; -interface ActionButtonProps { +export interface ActionButtonProps { onClick?: () => void; hotkey?: any; children?: React.ReactNode; @@ -19,7 +19,7 @@ const styles = { selected: "bg-[var(--theme-focused-foreground)]" }; -const ActionButton = React.forwardRef(({ onClick, hotkey, children, style, rootStyle, isSelected }, ref) => { +export const ActionButton = React.forwardRef(({ onClick, hotkey, children, style, rootStyle, isSelected }, ref) => { return (
      {Utilities.isEmpty(hotkey) ? null : {hotkey}} diff --git a/components/ActionListItem.tsx b/components/ActionListItem.tsx index 78b6250..55a82cb 100644 --- a/components/ActionListItem.tsx +++ b/components/ActionListItem.tsx @@ -6,7 +6,7 @@ const styles = { text: "inline-flex items-center justify-start self-stretch bg-[var(--theme-button-background)] min-w-[10%] w-full px-[1ch] select-none" }; -interface ActionListItemProps { +export interface ActionListItemProps { style?: React.CSSProperties; icon?: React.ReactNode; children?: React.ReactNode; @@ -15,7 +15,7 @@ interface ActionListItemProps { onClick?: React.MouseEventHandler; } -const ActionListItem: React.FC = (props) => { +export const ActionListItem: React.FC = (props) => { const { href, target, onClick, children, icon, style } = props; if (href) { diff --git a/components/AlertBanner.tsx b/components/AlertBanner.tsx index 4753c29..48f04c0 100644 --- a/components/AlertBanner.tsx +++ b/components/AlertBanner.tsx @@ -5,12 +5,12 @@ const styles = { root: "block bg-[var(--theme-border)] shadow-[1ch_1ch_0_0_var(--theme-border-subdued)] px-[2ch] py-[calc(var(--font-size)*var(--theme-line-height-base))] font-normal" }; -interface AlertBannerProps { +export interface AlertBannerProps { style?: any; children?: any; } -const AlertBanner: React.FC = ({ style: propStyle, ...rest }) => { +export const AlertBanner: React.FC = ({ style: propStyle, ...rest }) => { let style: React.CSSProperties = { ...propStyle }; return
      ; diff --git a/components/Avatar.tsx b/components/Avatar.tsx index b613ea1..53dc013 100644 --- a/components/Avatar.tsx +++ b/components/Avatar.tsx @@ -9,7 +9,7 @@ const styles = { right: "min-w-[10%] w-full bg-[var(--theme-foreground)]" }; -interface AvatarProps extends Omit, 'style' | 'className' | 'children'> { +export interface AvatarProps extends Omit, 'style' | 'className' | 'children'> { src?: string; href?: string; target?: string; @@ -17,7 +17,7 @@ interface AvatarProps extends Omit, 'style' children?: React.ReactNode; } -const Avatar: React.FC = (props) => { +export const Avatar: React.FC = (props) => { const { src, style: propStyle, href, target, children, ...rest } = props; const backgroundStyle = src ? { diff --git a/components/Badge.tsx b/components/Badge.tsx index 4113d08..0302ea5 100644 --- a/components/Badge.tsx +++ b/components/Badge.tsx @@ -7,11 +7,11 @@ const styles = { root: clsx("inline-block align-top text-center font-normal m-0 outline-0 border-0 font-[var(--font-family-mono)] min-h-[calc(var(--theme-line-height-base)*var(--font-size))] uppercase transition-all duration-200 ease bg-[var(--theme-border)] px-[1ch] py-0") }; -interface BadgeProps extends React.HTMLAttributes { +export interface BadgeProps extends React.HTMLAttributes { children?: React.ReactNode; } -const Badge: React.FC = ({ children, ...rest }) => { +export const Badge: React.FC = ({ children, ...rest }) => { return ( {children} diff --git a/components/BarLoader.tsx b/components/BarLoader.tsx index 3e1184f..9d2b203 100644 --- a/components/BarLoader.tsx +++ b/components/BarLoader.tsx @@ -8,12 +8,12 @@ const styles = { bar: clsx("bg-[linear-gradient(to_right,transparent,var(--theme-text))] h-full w-0 transition-[width] duration-100 linear") }; -interface BarLoaderProps { +export interface BarLoaderProps { intervalRate?: number; progress?: number; } -const BarLoader: React.FC = ({ intervalRate, progress }) => { +export const BarLoader: React.FC = ({ intervalRate, progress }) => { const [currentProgress, setCurrentProgress] = React.useState(progress || 0); React.useEffect(() => { diff --git a/components/BarProgress.tsx b/components/BarProgress.tsx index 7ef3dde..ebad71f 100644 --- a/components/BarProgress.tsx +++ b/components/BarProgress.tsx @@ -9,13 +9,13 @@ const styles = { measure: clsx("invisible absolute pointer-events-none") }; -interface BarProgressProps { +export interface BarProgressProps { intervalRate?: number; progress?: number; fillChar?: string; } -const BarProgress: React.FC = ({ intervalRate, progress, fillChar = '░' }) => { +export const BarProgress: React.FC = ({ intervalRate, progress, fillChar = '░' }) => { const [currentProgress, setCurrentProgress] = React.useState(progress ?? 0); const [containerWidth, setContainerWidth] = React.useState(0); const [charWidth, setCharWidth] = React.useState(0); diff --git a/components/Block.tsx b/components/Block.tsx index f71e96f..874f18d 100644 --- a/components/Block.tsx +++ b/components/Block.tsx @@ -5,11 +5,11 @@ const styles = { block: clsx("inline-block w-[1ch] bg-[var(--theme-text)] h-[calc(var(--font-size)*var(--theme-line-height-base))] align-bottom flex-shrink-0") }; -interface BlockProps extends React.HTMLAttributes { +export interface BlockProps extends React.HTMLAttributes { children?: React.ReactNode; } -const Block: React.FC = ({ children, ...rest }) => { +export const Block: React.FC = ({ children, ...rest }) => { return ( {children} diff --git a/components/BlockLoader.tsx b/components/BlockLoader.tsx index 4970a81..ad3b4d3 100644 --- a/components/BlockLoader.tsx +++ b/components/BlockLoader.tsx @@ -21,11 +21,11 @@ const SEQUENCES = [ ['◐', '◓', '◑', '◒'], ]; -interface BlockLoaderProps extends Omit, 'children'> { +export interface BlockLoaderProps extends Omit, 'children'> { mode?: number; } -const BlockLoader: React.FC = ({ mode = 0 }) => { +export const BlockLoader: React.FC = ({ mode = 0 }) => { if (!SEQUENCES[mode]) { return ; } diff --git a/components/BreadCrumbs.tsx b/components/BreadCrumbs.tsx index 5fa1b86..6327782 100644 --- a/components/BreadCrumbs.tsx +++ b/components/BreadCrumbs.tsx @@ -8,16 +8,16 @@ const styles = { symbol: clsx("inline-block mx-[9px] my-0") }; -interface BreadCrumbsItem { +export interface BreadCrumbsItem { url?: string; name: string; } -interface BreadCrumbsProps { +export interface BreadCrumbsProps { items: BreadCrumbsItem[]; } -const BreadCrumbs: React.FC = ({ items }) => { +export const BreadCrumbs: React.FC = ({ items }) => { return (