diff --git a/fwt/components/Background/Background.sass b/fwt/components/Background/Background.sass
new file mode 100644
index 0000000..1e0b5bc
--- /dev/null
+++ b/fwt/components/Background/Background.sass
@@ -0,0 +1 @@
+@use '/src/styles/classes.sass'
diff --git a/fwt/components/Background/Background.tsx b/fwt/components/Background/Background.tsx
new file mode 100644
index 0000000..12e21b2
--- /dev/null
+++ b/fwt/components/Background/Background.tsx
@@ -0,0 +1,50 @@
+import './Background.sass'
+import { Show, createSignal } from 'solid-js'
+import fs from 'fs'
+import webpPath from '../../images/background.webp'
+import avifPath from '../../images/background.avif'
+import noBackground from '../../images/no-background.webp'
+
+interface Props {
+ image?: boolean
+ color?: string
+}
+
+let [imageLoaded, setImageLoaded] = createSignal(false)
+
+const checkBackground = () => {
+ if (!fs.existsSync(avifPath.src) && !fs.existsSync(webpPath.src)) {
+ setImageLoaded(true)
+ } else {
+ setImageLoaded(false)
+ }
+}
+
+export default (props: Props) => {
+ checkBackground()
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/fwt/components/Box/Box.sass b/fwt/components/Box/Box.sass
new file mode 100644
index 0000000..17165bb
--- /dev/null
+++ b/fwt/components/Box/Box.sass
@@ -0,0 +1,6 @@
+.box
+ padding: 1rem
+
+.curvedbox
+ @extend .box
+ border-radius: 8px
diff --git a/fwt/components/Box/Box.tsx b/fwt/components/Box/Box.tsx
new file mode 100644
index 0000000..dc71de3
--- /dev/null
+++ b/fwt/components/Box/Box.tsx
@@ -0,0 +1,20 @@
+import type { ImageMetadata } from 'astro'
+import './Box.sass'
+import { Show, type JSXElement, createMemo } from 'solid-js'
+
+interface Props {
+ thickness: number
+ color?: string
+ children: JSXElement
+ curved?: boolean
+}
+
+export default (props: Props) => {
+ const boxClass = createMemo(() => (props.curved ? 'curvedbox' : 'box'))
+
+ return (
+
+ )
+}
diff --git a/fwt/components/Button/Button.sass b/fwt/components/Button/Button.sass
new file mode 100644
index 0000000..329ba1d
--- /dev/null
+++ b/fwt/components/Button/Button.sass
@@ -0,0 +1,223 @@
+@use '/src/styles/variables.sass' as vars
+@use '/src/styles/fonts.sass' as fonts
+@use 'sass:color'
+
+$bulmaPrimary: rgb(0, 235, 199)
+$bulmaPrimaryText: rgb(0, 31, 26)
+$bulmaLink: rgb(92, 111, 255)
+$bulmaLinkText: rgb(245, 246, 255)
+$bulmaInfo: rgb(128, 217, 255)
+$bulmaInfoText: rgb(0, 36, 51)
+$bulmaSuccess: rgb(91, 205, 154)
+$bulmaSuccessText: rgb(10, 31, 21)
+$bulmaWarning: rgb(255, 191, 41)
+$bulmaWarningText: rgb(41, 29, 0)
+$bulmaDanger: rgb(255, 128, 153)
+$bulmaDangerText: rgb(26, 0, 5)
+$bulmaLight: rgb(255, 255, 255)
+$bulmaLightText: rgb(46, 51, 61)
+$bulmaDark: rgb(57, 63, 76)
+$bulmaDarkText: rgb(243, 244, 246)
+$bulmaText: rgb(31, 34, 41)
+$bulmaTextText: rgb(235, 236, 240)
+$bulmaGhost: rgba(0,0,0,0)
+$bulmaGhostText: rgb(66, 88, 255)
+
+$bootstrapTextLight: rgb(255, 255, 253)
+$bootstrapTextDark: rgb(0, 0, 2)
+$bootstrapTextLink: rgb(139, 185, 254)
+$bootstrapPrimary: rgb(13, 110, 253)
+$bootstrapSecondary: rgb(92, 99, 106)
+$bootstrapSuccess: rgb(21, 115, 71)
+$bootstrapDanger: rgb(187, 45, 59)
+$bootstrapWarning: rgb(255, 202, 44)
+$bootstrapInfo: rgb(49, 210, 242)
+$bootstrapLight: rgb(211, 212, 213)
+$bootstrapDark: rgb(33, 37, 41)
+
+.button
+ background-color: vars.$primaryColor
+ border: none
+ color: white
+ padding: 0.5rem 1.25rem
+ text-align: center
+ text-decoration: none
+ display: inline-block
+ font-size: 1rem
+ font-weight: 500
+ cursor: pointer
+ transition: all 0.2s ease-out
+
+ &:hover
+ background-color: color.adjust(vars.$primaryColor, $blackness: 20%)
+
+ &:active
+ transform: scale(0.95)
+
+.bu-primary
+ @extend .button
+ font-family: fonts.$Inter
+ background-color: $bulmaPrimary
+ color: $bulmaPrimaryText
+ border: none
+ font-size: 1rem
+ border-radius: 0.375rem
+ font-weight: 500
+ padding: 0.5rem 1.25rem
+ height: 2.5rem
+
+ &:hover
+ background-color: color.adjust($bulmaPrimary, $lightness: 10%)
+
+.bu-link
+ @extend .bu-primary
+ background-color: $bulmaLink
+ color: $bulmaLinkText
+
+ &:hover
+ background-color: color.adjust($bulmaLink, $lightness: 5%)
+
+.bu-info
+ @extend .bu-primary
+ background-color: $bulmaInfo
+ color: $bulmaInfoText
+
+ &:hover
+ background-color: color.adjust($bulmaInfo, $lightness: 5%)
+
+.bu-success
+ @extend .bu-primary
+ background-color: $bulmaSuccess
+ color: $bulmaSuccessText
+
+ &:hover
+ background-color: color.adjust($bulmaSuccess, $lightness: 5%)
+
+.bu-warning
+ @extend .bu-primary
+ background-color: $bulmaWarning
+ color: $bulmaWarningText
+
+ &:hover
+ background-color: color.adjust($bulmaWarning, $lightness: 5%)
+
+.bu-danger
+ @extend .bu-primary
+ background-color: $bulmaDanger
+ color: $bulmaDangerText
+
+ &:hover
+ background-color: color.adjust($bulmaDanger, $lightness: 5%)
+
+.bu-light
+ @extend .bu-primary
+ background-color: $bulmaLight
+ color: $bulmaLightText
+
+ &:hover
+ background-color: color.adjust($bulmaLight, $lightness: 5%)
+
+.bu-dark
+ @extend .bu-primary
+ background-color: $bulmaDark
+ color: $bulmaDarkText
+
+ &:hover
+ background-color: color.adjust($bulmaDark, $lightness: 5%)
+
+.bu-text
+ @extend .bu-primary
+ background-color: rgba(0,0,0,0)
+ color: $bulmaTextText
+ text-decoration: underline
+
+ &:hover
+ background-color: hsl(221,14%,14%)
+
+.bu-ghost
+ @extend .bu-primary
+ background-color: $bulmaGhost
+ color: $bulmaGhostText
+
+ &:hover
+ background-color: transparent
+ text-decoration: underline
+
+.bo-primary
+ @extend .button
+ font-family: 'Segoe UI', fonts.$Roboto
+ background-color: $bootstrapPrimary
+ color: $bootstrapTextLight
+ border: none
+ font-size: 1rem
+ border-radius: 0.375rem
+ font-weight: 400
+ padding: 0.5rem 1.25rem
+ height: 2.5rem
+ margin: 0.25rem 0.125rem
+
+ &:hover
+ background-color: color.adjust($bootstrapPrimary, $blackness: 10%)
+
+.bo-secondary
+ @extend .bo-primary
+ background-color: $bootstrapSecondary
+
+ &:hover
+ background-color: color.adjust($bootstrapSecondary, $blackness: 10%)
+
+.bo-success
+ @extend .bo-primary
+ background-color: $bootstrapSuccess
+
+ &:hover
+ background-color: color.adjust($bootstrapSuccess, $blackness: 10%)
+
+.bo-danger
+ @extend .bo-primary
+ background-color: $bootstrapDanger
+
+ &:hover
+ background-color: color.adjust($bootstrapDanger, $blackness: 10%)
+
+.bo-warning
+ @extend .bo-primary
+ background-color: $bootstrapWarning
+ color: $bootstrapTextDark
+
+ &:hover
+ background-color: color.adjust($bootstrapWarning, $lightness: 5%)
+
+.bo-info
+ @extend .bo-primary
+ background-color: $bootstrapInfo
+ color: $bootstrapTextDark
+
+ &:hover
+ background-color: color.adjust($bootstrapInfo, $lightness: 5%)
+
+.bo-light
+ @extend .bo-primary
+ background-color: $bootstrapLight
+ color: $bootstrapTextDark
+
+ &:hover
+ background-color: color.adjust($bootstrapLight, $blackness: 10%)
+
+.bo-dark
+ @extend .bo-primary
+ background-color: $bootstrapDark
+ // color: $bootstrapTextDark
+
+ &:hover
+ background-color: color.adjust($bootstrapDark, $lightness: 10%)
+
+.bo-link
+ @extend .bo-primary
+ background-color: transparent
+ color: $bootstrapTextLink
+ text-decoration: underline
+
+ &:hover
+ color: color.adjust($bootstrapTextLink, $lightness: 5%)
+ background-color: transparent
diff --git a/fwt/components/Button/Button.tsx b/fwt/components/Button/Button.tsx
new file mode 100644
index 0000000..2de125f
--- /dev/null
+++ b/fwt/components/Button/Button.tsx
@@ -0,0 +1,82 @@
+import './Button.sass'
+import { Show, Switch, Match } from 'solid-js'
+
+interface Props {
+ label?: string
+ to?: string
+ onClick?: () => void
+ edges?: 'curved' | 'rounded' | 'flat'
+ design?: 'bu-primary' | 'bu-link' | 'bu-info' | 'bu-success' | 'bu-warning' | 'bu-danger' | 'bu-dark' | 'bu-light' | 'bu-text' | 'bu-ghost' | 'bo-primary' | 'bo-secondary' | 'bo-success' | 'bo-danger' | 'bo-warning' | 'bo-info' | 'bo-light' | 'bo-dark' | 'bo-link'
+ submit?: boolean
+}
+
+const getBorderRadius = (edge: Props['edges']) => {
+ switch (edge) {
+ case 'curved':
+ return 'border-radius: 6px'
+ case 'rounded':
+ return 'border-radius: 32px'
+ case 'flat':
+ return 'border-radius: 0'
+ default:
+ return 'border-radius: 0'
+ }
+}
+
+export default (props: Props) => {
+ const borderRadius = getBorderRadius(props.edges)
+
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ >
+ )
+}
diff --git a/fwt/components/Column/Column.sass b/fwt/components/Column/Column.sass
new file mode 100644
index 0000000..b26f108
--- /dev/null
+++ b/fwt/components/Column/Column.sass
@@ -0,0 +1,39 @@
+.column-top
+ display: flex
+ flex-direction: column
+ flex-wrap: wrap
+ justify-content: flex-start
+ align-items: center
+ align-content: center
+
+.column-center
+ display: flex
+ flex-direction: column
+ flex-wrap: wrap
+ justify-content: center
+ align-items: center
+ align-content: center
+
+.column-right
+ display: flex
+ flex-direction: column
+ flex-wrap: wrap
+ justify-content: flex-end
+ align-items: center
+ align-content: center
+
+.column-split
+ display: flex
+ flex-direction: column
+ flex-wrap: wrap
+ justify-content: space-between
+ align-items: center
+ align-content: center
+
+.column-spaced
+ display: flex
+ flex-direction: column
+ flex-wrap: wrap
+ justify-content: space-around
+ align-items: center
+ align-content: center
diff --git a/fwt/components/Column/Column.tsx b/fwt/components/Column/Column.tsx
new file mode 100644
index 0000000..3f5c786
--- /dev/null
+++ b/fwt/components/Column/Column.tsx
@@ -0,0 +1,18 @@
+import type { JSXElement } from 'solid-js'
+import './Column.sass'
+
+interface Props {
+ children: JSXElement
+ content?: 'top' | 'center' | 'right' | 'split' | 'spaced'
+ gap?: number
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+ >
+ )
+}
diff --git a/fwt/components/Copyright/Copyright.tsx b/fwt/components/Copyright/Copyright.tsx
new file mode 100644
index 0000000..b8338d7
--- /dev/null
+++ b/fwt/components/Copyright/Copyright.tsx
@@ -0,0 +1,14 @@
+interface Props {
+ year: string
+ name: string
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+ Copyright © {props.year} {props.name} All Rights Reserved.
+
+ >
+ )
+}
diff --git a/fwt/components/Footer/Footer.sass b/fwt/components/Footer/Footer.sass
new file mode 100644
index 0000000..70cd207
--- /dev/null
+++ b/fwt/components/Footer/Footer.sass
@@ -0,0 +1,7 @@
+.footer
+ padding: 1rem 0
+ margin: 0 2rem
+ position: fixed
+ bottom: 0
+ width: 100%
+ opacity: 0.8
diff --git a/fwt/components/Footer/Footer.tsx b/fwt/components/Footer/Footer.tsx
new file mode 100644
index 0000000..2c47f07
--- /dev/null
+++ b/fwt/components/Footer/Footer.tsx
@@ -0,0 +1,16 @@
+import './Footer.sass'
+import type { JSXElement } from 'solid-js'
+
+interface Props {
+ children: JSXElement
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+ >
+ )
+}
diff --git a/fwt/components/Form/Form.sass b/fwt/components/Form/Form.sass
new file mode 100644
index 0000000..e69de29
diff --git a/fwt/components/Form/Form.tsx b/fwt/components/Form/Form.tsx
new file mode 100644
index 0000000..a498c76
--- /dev/null
+++ b/fwt/components/Form/Form.tsx
@@ -0,0 +1,16 @@
+import './Form.sass'
+import type { JSXElement } from 'solid-js'
+
+interface Props {
+ children: JSXElement
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+ >
+ )
+}
diff --git a/fwt/components/HTML/HTML.sass b/fwt/components/HTML/HTML.sass
new file mode 100644
index 0000000..92e9d1c
--- /dev/null
+++ b/fwt/components/HTML/HTML.sass
@@ -0,0 +1,25 @@
+@use '/src/styles/variables.sass' as vars
+@use '/src/styles/fonts.sass' as fonts
+
+.body
+ color: vars.$textColor
+
+.inter
+ @extend .body
+ font-family: fonts.$Inter
+
+.roboto
+ @extend .body
+ font-family: fonts.$Roboto
+
+.montserrat
+ @extend .body
+ font-family: fonts.$Montserrat
+
+.open-sans
+ @extend .body
+ font-family: fonts.$OpenSans
+
+.public-sans
+ @extend .body
+ font-family: fonts.$PublicSans
diff --git a/fwt/components/HTML/HTML.tsx b/fwt/components/HTML/HTML.tsx
new file mode 100644
index 0000000..ccee123
--- /dev/null
+++ b/fwt/components/HTML/HTML.tsx
@@ -0,0 +1,35 @@
+import './HTML.sass'
+import { type JSXElement, Show } from 'solid-js'
+
+interface Props {
+ title: string
+ name: string
+ description: string
+ children: JSXElement
+ font?: 'roboto' | 'inter' | 'montserrat' | 'open-sans' | 'public-sans'
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+
+
+
+
+
+
+
+
+
+
+
+ {props.title}
+
+
+ {props.children}
+
+ s
+ >
+ )
+}
diff --git a/fwt/components/Image/Image.tsx b/fwt/components/Image/Image.tsx
new file mode 100644
index 0000000..d885641
--- /dev/null
+++ b/fwt/components/Image/Image.tsx
@@ -0,0 +1,19 @@
+interface Props {
+ avif: string
+ webp: string
+ size?: number
+ alt?: string
+ radius?: number
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
diff --git a/fwt/components/Input/Input.sass b/fwt/components/Input/Input.sass
new file mode 100644
index 0000000..391937c
--- /dev/null
+++ b/fwt/components/Input/Input.sass
@@ -0,0 +1,27 @@
+.input
+ font-size: 1rem
+ padding: 0.5rem 1rem
+ width: 100%
+ border: 2px solid #ccc
+ border-radius: 4px
+ outline: none
+ transition: border-color 0.3s, box-shadow 0.3s
+
+ &:focus
+ border-color: #3377AC
+ box-shadow: 0 0 5px rgba(51, 119, 168, 0.3)
+
+ &::placeholder
+ color: #888
+ font-style: italic
+
+ &:disabled
+ background-color: #f0f0f0
+ border-color: #ddd
+
+ &--error
+ border-color: #ff4d4f
+ box-shadow: 0 0 5px rgba(255, 77, 79, 0.3)
+
+ &:focus
+ border-color: #e81123
diff --git a/fwt/components/Input/Input.tsx b/fwt/components/Input/Input.tsx
new file mode 100644
index 0000000..c0f7c97
--- /dev/null
+++ b/fwt/components/Input/Input.tsx
@@ -0,0 +1,27 @@
+import './Input.sass'
+import { createSignal } from 'solid-js'
+
+interface Props {
+ placeholder?: string
+ value?: string
+ onChange?: (value: string) => void
+}
+
+export default (props: Props) => {
+ const [inputValue, setInputValue] = createSignal(props.value || '')
+
+ const handleChange = (event: Event) => {
+ const target = event.target as HTMLInputElement
+ const newValue = target.value
+ setInputValue(newValue)
+ if (props.onChange) {
+ props.onChange(newValue)
+ }
+ }
+
+ return (
+ <>
+
+ >
+ )
+}
diff --git a/fwt/components/Link/Link.sass b/fwt/components/Link/Link.sass
new file mode 100644
index 0000000..efc3b4f
--- /dev/null
+++ b/fwt/components/Link/Link.sass
@@ -0,0 +1,3 @@
+a
+ text-decoration: none
+ color: inherit
diff --git a/fwt/components/Link/Link.tsx b/fwt/components/Link/Link.tsx
new file mode 100644
index 0000000..1e7e337
--- /dev/null
+++ b/fwt/components/Link/Link.tsx
@@ -0,0 +1,16 @@
+import './Link.sass'
+
+interface Props {
+ to: string
+ children?: any
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+ {props.children}
+
+ >
+ )
+}
diff --git a/fwt/components/Logo/Logo.tsx b/fwt/components/Logo/Logo.tsx
new file mode 100644
index 0000000..5d1af4c
--- /dev/null
+++ b/fwt/components/Logo/Logo.tsx
@@ -0,0 +1,19 @@
+import webpPath from '../../images/logo.webp'
+import avifPath from '../../images/logo.avif'
+
+interface Props {
+ size?: number
+ alt?: string
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+
+
+
+
+ >
+ )
+}
diff --git a/fwt/components/Navbar/Navbar.sass b/fwt/components/Navbar/Navbar.sass
new file mode 100644
index 0000000..edbda91
--- /dev/null
+++ b/fwt/components/Navbar/Navbar.sass
@@ -0,0 +1,7 @@
+.nav
+ position: fixed
+ top: 0
+ width: 100%
+ padding: 1rem 0
+ // margin: 5rem
+
diff --git a/fwt/components/Navbar/Navbar.tsx b/fwt/components/Navbar/Navbar.tsx
new file mode 100644
index 0000000..3b0c688
--- /dev/null
+++ b/fwt/components/Navbar/Navbar.tsx
@@ -0,0 +1,18 @@
+import './Navbar.sass'
+import { Show } from 'solid-js'
+import Row from '../Row/Row'
+
+interface Props {
+ transparent?: boolean
+ children: HTMLElement
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+ >
+ )
+}
diff --git a/fwt/components/Optimizer/OptimizeBackground.tsx b/fwt/components/Optimizer/OptimizeBackground.tsx
new file mode 100644
index 0000000..1c27caf
--- /dev/null
+++ b/fwt/components/Optimizer/OptimizeBackground.tsx
@@ -0,0 +1,17 @@
+import sharp from 'sharp'
+
+const convertBackground = async () => {
+ const inputSrc = 'src/assets/images/background.png'
+ const webpOutput = 'fwt/images/background.webp'
+ const avifOutput = 'fwt/images/background.avif'
+
+ const avifBuffer = await sharp(inputSrc).avif({ quality: 60 }).resize(1920).toBuffer()
+ await sharp(avifBuffer).toFile(avifOutput)
+
+ const webpBuffer = await sharp(inputSrc).webp({ quality: 75 }).resize(1920).toBuffer()
+ await sharp(webpBuffer).toFile(webpOutput)
+}
+
+export default () => {
+ convertBackground()
+}
diff --git a/fwt/components/Optimizer/OptimizeImage.tsx b/fwt/components/Optimizer/OptimizeImage.tsx
new file mode 100644
index 0000000..00afd77
--- /dev/null
+++ b/fwt/components/Optimizer/OptimizeImage.tsx
@@ -0,0 +1,21 @@
+import sharp from 'sharp'
+
+interface Props {
+ src: string
+ size?: number
+}
+
+const convertImage = async (props: Props) => {
+ const avifOutputPath = `fwt/images/${props.src.split('.').slice(0, -1).join('.')}.avif`
+ const webpOutputPath = `fwt/images/${props.src.split('.').slice(0, -1).join('.')}.webp`
+
+ const avifBuffer = await sharp(`src/assets/images/${props.src}`).avif({ quality: 60 }).resize(props.size).toBuffer()
+ await sharp(avifBuffer).toFile(avifOutputPath)
+
+ const webpBuffer = await sharp(`src/assets/images/${props.src}`).webp({ quality: 75 }).resize(props.size).toBuffer()
+ await sharp(webpBuffer).toFile(webpOutputPath)
+}
+
+export default (props: Props) => {
+ convertImage(props)
+}
diff --git a/fwt/components/Optimizer/OptimizeLogo.tsx b/fwt/components/Optimizer/OptimizeLogo.tsx
new file mode 100644
index 0000000..e3e8014
--- /dev/null
+++ b/fwt/components/Optimizer/OptimizeLogo.tsx
@@ -0,0 +1,21 @@
+import sharp from 'sharp'
+
+interface Props {
+ size?: number
+}
+
+const convertLogo = async (props: Props) => {
+ const inputSrc = 'src/assets/images/logo.png'
+ const webpImage = 'fwt/images/logo.webp'
+ const avifImage = 'fwt/images/logo.avif'
+
+ const avifBuffer = await sharp(inputSrc).avif({ quality: 60 }).resize(props.size).toBuffer()
+ await sharp(avifBuffer).toFile(avifImage)
+
+ const webpBuffer = await sharp(inputSrc).webp({ quality: 75 }).resize(props.size).toBuffer()
+ await sharp(webpBuffer).toFile(webpImage)
+}
+
+export default (props: Props) => {
+ convertLogo(props)
+}
diff --git a/fwt/components/Page/Page.sass b/fwt/components/Page/Page.sass
new file mode 100644
index 0000000..af99849
--- /dev/null
+++ b/fwt/components/Page/Page.sass
@@ -0,0 +1,14 @@
+.page
+ margin: 2rem
+ height: auto
+ min-height: 90vh
+
+.column
+ @extend .page
+ display: flex
+ flex-direction: column
+ align-items: center
+
+.row
+ @extend .column
+ flex-direction: row
diff --git a/fwt/components/Page/Page.tsx b/fwt/components/Page/Page.tsx
new file mode 100644
index 0000000..62d9a73
--- /dev/null
+++ b/fwt/components/Page/Page.tsx
@@ -0,0 +1,20 @@
+import './Page.sass'
+import { Show } from 'solid-js'
+
+interface Props {
+ children?: any
+ alignment?: 'row' | 'column'
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+ {props.children}
+
+
+ {props.children}
+
+ >
+ )
+}
diff --git a/fwt/components/Row/Row.sass b/fwt/components/Row/Row.sass
new file mode 100644
index 0000000..6162bbe
--- /dev/null
+++ b/fwt/components/Row/Row.sass
@@ -0,0 +1,47 @@
+.row-left
+ display: flex
+ flex-direction: row
+ flex-wrap: wrap
+ justify-content: flex-start
+ align-items: center
+ align-content: center
+
+.row-center
+ display: flex
+ flex-direction: row
+ flex-wrap: wrap
+ justify-content: center
+ align-items: center
+ align-content: center
+
+.row-right
+ display: flex
+ flex-direction: row
+ flex-wrap: wrap
+ justify-content: flex-end
+ align-items: center
+ align-content: center
+
+.row-split
+ display: flex
+ flex-direction: row
+ flex-wrap: wrap
+ justify-content: space-between
+ align-items: center
+ align-content: center
+
+.row-spaced
+ display: flex
+ flex-direction: row
+ flex-wrap: wrap
+ justify-content: space-around
+ align-items: center
+ align-content: center
+
+.row-even
+ display: flex
+ flex-direction: row
+ flex-wrap: wrap
+ justify-content: space-evenly
+ align-items: center
+ align-content: center
diff --git a/fwt/components/Row/Row.tsx b/fwt/components/Row/Row.tsx
new file mode 100644
index 0000000..5255e9c
--- /dev/null
+++ b/fwt/components/Row/Row.tsx
@@ -0,0 +1,24 @@
+import './Row.sass'
+import { Show, type JSXElement } from 'solid-js'
+
+interface Props {
+ children: JSXElement
+ content?: 'left' | 'center' | 'right' | 'split' | 'spaced' | 'even'
+ gap?: number
+}
+
+export default (props: Props) => {
+ return (
+ <>
+
+
+
+
+
+
+
+ >
+ )
+}