diff --git a/.gitignore b/.gitignore
index a547bf3..1461e83 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,6 +11,7 @@ node_modules
dist
dist-ssr
*.local
+package-lock.json
# Editor directories and files
.vscode/*
@@ -22,3 +23,6 @@ dist-ssr
*.njsproj
*.sln
*.sw?
+
+.env
+/src/pages/test.jsx
diff --git a/README.md b/README.md
index 86f5adf..5234659 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1 @@
-# React + Vite
-
-This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
-
-Currently, two official plugins are available:
-
-- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
-- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
-
-## Expanding the ESLint configuration
-
-If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
-# Frontend
+# ArchAIve Frontend
diff --git a/package-lock.json b/package-lock.json
index 76258e4..ad74479 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2683,11 +2683,10 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "version": "1.1.12",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
+ "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true,
- "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
diff --git a/package.json b/package.json
index 4056e2e..67d7a79 100644
--- a/package.json
+++ b/package.json
@@ -23,6 +23,7 @@
"redux": "^5.0.1"
},
"devDependencies": {
+ "@chakra-ui/cli": "^3.21.1",
"@eslint/js": "^9.25.0",
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
diff --git a/src/Layout.jsx b/src/Layout.jsx
index 6385412..fdb152a 100644
--- a/src/Layout.jsx
+++ b/src/Layout.jsx
@@ -1,7 +1,7 @@
import React, { useEffect } from 'react'
import { useDispatch } from 'react-redux'
import { Outlet, useNavigate } from 'react-router';
-import "./core.css";
+import Navbar from './components/Navbar';
function Layout() {
const dispatch = useDispatch();
@@ -13,6 +13,7 @@ function Layout() {
return (
+
)
diff --git a/src/assets/hp1.png b/src/assets/hp1.png
new file mode 100644
index 0000000..0180bce
Binary files /dev/null and b/src/assets/hp1.png differ
diff --git a/src/assets/hp2.png b/src/assets/hp2.png
new file mode 100644
index 0000000..1d80252
Binary files /dev/null and b/src/assets/hp2.png differ
diff --git a/src/assets/hp3.png b/src/assets/hp3.png
new file mode 100644
index 0000000..629e057
Binary files /dev/null and b/src/assets/hp3.png differ
diff --git a/src/assets/hp4.png b/src/assets/hp4.png
new file mode 100644
index 0000000..12df40b
Binary files /dev/null and b/src/assets/hp4.png differ
diff --git a/src/assets/hp5.png b/src/assets/hp5.png
new file mode 100644
index 0000000..4f54d4c
Binary files /dev/null and b/src/assets/hp5.png differ
diff --git a/src/assets/hp6.png b/src/assets/hp6.png
new file mode 100644
index 0000000..a05695a
Binary files /dev/null and b/src/assets/hp6.png differ
diff --git a/src/assets/react.svg b/src/assets/react.svg
deleted file mode 100644
index 6c87de9..0000000
--- a/src/assets/react.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx
new file mode 100644
index 0000000..fa5b3dd
--- /dev/null
+++ b/src/components/Navbar.jsx
@@ -0,0 +1,28 @@
+import React, { useState } from 'react'
+import Sidebar from './Sidebar'
+import { Avatar, Box, Button, Flex, HStack, Icon, Spacer, Text } from '@chakra-ui/react'
+import { FaHamburger } from 'react-icons/fa'
+import { FaBarsStaggered } from 'react-icons/fa6'
+
+function Navbar() {
+ const [isOpen, setIsOpen] = useState(false);
+
+ const toggleSidebar = () => {
+ setIsOpen(!isOpen);
+ }
+
+ return <>
+
+
+
+ ArchAIve
+
+
+
+
+
+ setIsOpen(e.open)} />
+ >
+}
+
+export default Navbar
\ No newline at end of file
diff --git a/src/components/Sidebar.jsx b/src/components/Sidebar.jsx
new file mode 100644
index 0000000..f464d4b
--- /dev/null
+++ b/src/components/Sidebar.jsx
@@ -0,0 +1,34 @@
+import { Button, CloseButton, Drawer, Portal, Text } from '@chakra-ui/react'
+import React, { useState } from 'react'
+
+function Sidebar({ isOpen, onOpenChange }) {
+ return (
+
+
+
+
+
+
+ Drawer Title
+
+
+
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do
+ eiusmod tempor incididunt ut labore et dolore magna aliqua.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+}
+
+export default Sidebar
\ No newline at end of file
diff --git a/src/components/ui/accordion.jsx b/src/components/ui/accordion.jsx
new file mode 100644
index 0000000..a0e86f8
--- /dev/null
+++ b/src/components/ui/accordion.jsx
@@ -0,0 +1,39 @@
+import { Accordion, HStack } from '@chakra-ui/react'
+import * as React from 'react'
+import { LuChevronDown } from 'react-icons/lu'
+
+export const AccordionItemTrigger = React.forwardRef(
+ function AccordionItemTrigger(props, ref) {
+ const { children, indicatorPlacement = 'end', ...rest } = props
+ return (
+
+ {indicatorPlacement === 'start' && (
+
+
+
+ )}
+
+ {children}
+
+ {indicatorPlacement === 'end' && (
+
+
+
+ )}
+
+ )
+ },
+)
+
+export const AccordionItemContent = React.forwardRef(
+ function AccordionItemContent(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const AccordionRoot = Accordion.Root
+export const AccordionItem = Accordion.Item
diff --git a/src/components/ui/action-bar.jsx b/src/components/ui/action-bar.jsx
new file mode 100644
index 0000000..450f11b
--- /dev/null
+++ b/src/components/ui/action-bar.jsx
@@ -0,0 +1,33 @@
+import { ActionBar, Portal } from '@chakra-ui/react'
+import { CloseButton } from './close-button'
+import * as React from 'react'
+
+export const ActionBarContent = React.forwardRef(
+ function ActionBarContent(props, ref) {
+ const { children, portalled = true, portalRef, ...rest } = props
+
+ return (
+
+
+
+ {children}
+
+
+
+ )
+ },
+)
+
+export const ActionBarCloseTrigger = React.forwardRef(
+ function ActionBarCloseTrigger(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const ActionBarRoot = ActionBar.Root
+export const ActionBarSelectionTrigger = ActionBar.SelectionTrigger
+export const ActionBarSeparator = ActionBar.Separator
diff --git a/src/components/ui/alert.jsx b/src/components/ui/alert.jsx
new file mode 100644
index 0000000..ba74303
--- /dev/null
+++ b/src/components/ui/alert.jsx
@@ -0,0 +1,20 @@
+import { Alert as ChakraAlert } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Alert = React.forwardRef(function Alert(props, ref) {
+ const { title, children, icon, startElement, endElement, ...rest } = props
+ return (
+
+ {startElement || {icon}}
+ {children ? (
+
+ {title}
+ {children}
+
+ ) : (
+ {title}
+ )}
+ {endElement}
+
+ )
+})
diff --git a/src/components/ui/avatar.jsx b/src/components/ui/avatar.jsx
new file mode 100644
index 0000000..9321b39
--- /dev/null
+++ b/src/components/ui/avatar.jsx
@@ -0,0 +1,21 @@
+import {
+ Avatar as ChakraAvatar,
+ AvatarGroup as ChakraAvatarGroup,
+} from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Avatar = React.forwardRef(function Avatar(props, ref) {
+ const { name, src, srcSet, loading, icon, fallback, children, ...rest } =
+ props
+ return (
+
+
+ {icon || fallback}
+
+
+ {children}
+
+ )
+})
+
+export const AvatarGroup = ChakraAvatarGroup
diff --git a/src/components/ui/blockquote.jsx b/src/components/ui/blockquote.jsx
new file mode 100644
index 0000000..31bbf46
--- /dev/null
+++ b/src/components/ui/blockquote.jsx
@@ -0,0 +1,22 @@
+import { Blockquote as ChakraBlockquote } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Blockquote = React.forwardRef(function Blockquote(props, ref) {
+ const { children, cite, citeUrl, showDash, icon, ...rest } = props
+
+ return (
+
+ {icon}
+
+ {children}
+
+ {cite && (
+
+ {showDash ? <>—> : null} {cite}
+
+ )}
+
+ )
+})
+
+export const BlockquoteIcon = ChakraBlockquote.Icon
diff --git a/src/components/ui/breadcrumb.jsx b/src/components/ui/breadcrumb.jsx
new file mode 100644
index 0000000..af9c4d0
--- /dev/null
+++ b/src/components/ui/breadcrumb.jsx
@@ -0,0 +1,34 @@
+import { Breadcrumb } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const BreadcrumbRoot = React.forwardRef(
+ function BreadcrumbRoot(props, ref) {
+ const { separator, separatorGap, children, ...rest } = props
+
+ const validChildren = React.Children.toArray(children).filter(
+ React.isValidElement,
+ )
+
+ return (
+
+
+ {validChildren.map((child, index) => {
+ const last = index === validChildren.length - 1
+ return (
+
+ {child}
+ {!last && (
+ {separator}
+ )}
+
+ )
+ })}
+
+
+ )
+ },
+)
+
+export const BreadcrumbLink = Breadcrumb.Link
+export const BreadcrumbCurrentLink = Breadcrumb.CurrentLink
+export const BreadcrumbEllipsis = Breadcrumb.Ellipsis
diff --git a/src/components/ui/checkbox-card.jsx b/src/components/ui/checkbox-card.jsx
new file mode 100644
index 0000000..e00ed62
--- /dev/null
+++ b/src/components/ui/checkbox-card.jsx
@@ -0,0 +1,45 @@
+import { CheckboxCard as ChakraCheckboxCard } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const CheckboxCard = React.forwardRef(function CheckboxCard(props, ref) {
+ const {
+ inputProps,
+ label,
+ description,
+ icon,
+ addon,
+ indicator = ,
+ indicatorPlacement = 'end',
+ ...rest
+ } = props
+
+ const hasContent = label || description || icon
+ const ContentWrapper = indicator ? ChakraCheckboxCard.Content : React.Fragment
+
+ return (
+
+
+
+ {indicatorPlacement === 'start' && indicator}
+ {hasContent && (
+
+ {icon}
+ {label && (
+ {label}
+ )}
+ {description && (
+
+ {description}
+
+ )}
+ {indicatorPlacement === 'inside' && indicator}
+
+ )}
+ {indicatorPlacement === 'end' && indicator}
+
+ {addon && {addon}}
+
+ )
+})
+
+export const CheckboxCardIndicator = ChakraCheckboxCard.Indicator
diff --git a/src/components/ui/checkbox.jsx b/src/components/ui/checkbox.jsx
new file mode 100644
index 0000000..78ff43a
--- /dev/null
+++ b/src/components/ui/checkbox.jsx
@@ -0,0 +1,17 @@
+import { Checkbox as ChakraCheckbox } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Checkbox = React.forwardRef(function Checkbox(props, ref) {
+ const { icon, children, inputProps, rootRef, ...rest } = props
+ return (
+
+
+
+ {icon || }
+
+ {children != null && (
+ {children}
+ )}
+
+ )
+})
diff --git a/src/components/ui/clipboard.jsx b/src/components/ui/clipboard.jsx
new file mode 100644
index 0000000..2b98420
--- /dev/null
+++ b/src/components/ui/clipboard.jsx
@@ -0,0 +1,101 @@
+import {
+ Button,
+ Clipboard as ChakraClipboard,
+ IconButton,
+ Input,
+} from '@chakra-ui/react'
+import * as React from 'react'
+import { LuCheck, LuClipboard, LuLink } from 'react-icons/lu'
+
+const ClipboardIcon = React.forwardRef(function ClipboardIcon(props, ref) {
+ return (
+ } {...props} ref={ref}>
+
+
+ )
+})
+
+const ClipboardCopyText = React.forwardRef(
+ function ClipboardCopyText(props, ref) {
+ return (
+
+ Copy
+
+ )
+ },
+)
+
+export const ClipboardLabel = React.forwardRef(
+ function ClipboardLabel(props, ref) {
+ return (
+
+ )
+ },
+)
+
+export const ClipboardButton = React.forwardRef(
+ function ClipboardButton(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const ClipboardLink = React.forwardRef(
+ function ClipboardLink(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const ClipboardIconButton = React.forwardRef(
+ function ClipboardIconButton(props, ref) {
+ return (
+
+
+
+
+
+
+ )
+ },
+)
+
+export const ClipboardInput = React.forwardRef(
+ function ClipboardInputElement(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const ClipboardRoot = ChakraClipboard.Root
diff --git a/src/components/ui/close-button.jsx b/src/components/ui/close-button.jsx
new file mode 100644
index 0000000..07d3631
--- /dev/null
+++ b/src/components/ui/close-button.jsx
@@ -0,0 +1,20 @@
+function _nullishCoalesce(lhs, rhsFn) {
+ if (lhs != null) {
+ return lhs
+ } else {
+ return rhsFn()
+ }
+}
+import { IconButton as ChakraIconButton } from '@chakra-ui/react'
+import * as React from 'react'
+import { LuX } from 'react-icons/lu'
+
+export const CloseButton = React.forwardRef(function CloseButton(props, ref) {
+ return (
+
+ {_nullishCoalesce(props.children, () => (
+
+ ))}
+
+ )
+})
diff --git a/src/components/ui/color-picker.jsx b/src/components/ui/color-picker.jsx
new file mode 100644
index 0000000..c997bb5
--- /dev/null
+++ b/src/components/ui/color-picker.jsx
@@ -0,0 +1,201 @@
+import {
+ ColorPicker as ChakraColorPicker,
+ For,
+ IconButton,
+ Portal,
+ Span,
+ Stack,
+ Text,
+ VStack,
+} from '@chakra-ui/react'
+import * as React from 'react'
+import { LuCheck, LuPipette } from 'react-icons/lu'
+
+export const ColorPickerTrigger = React.forwardRef(
+ function ColorPickerTrigger(props, ref) {
+ const { fitContent, ...rest } = props
+ return (
+
+ {props.children || }
+
+ )
+ },
+)
+
+export const ColorPickerInput = React.forwardRef(
+ function ColorHexInput(props, ref) {
+ return
+ },
+)
+
+export const ColorPickerContent = React.forwardRef(
+ function ColorPickerContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const ColorPickerInlineContent = React.forwardRef(
+ function ColorPickerInlineContent(props, ref) {
+ return (
+
+ )
+ },
+)
+
+export const ColorPickerSliders = React.forwardRef(
+ function ColorPickerSliders(props, ref) {
+ return (
+
+
+
+
+ )
+ },
+)
+
+export const ColorPickerArea = React.forwardRef(
+ function ColorPickerArea(props, ref) {
+ return (
+
+
+
+
+ )
+ },
+)
+
+export const ColorPickerEyeDropper = React.forwardRef(
+ function ColorPickerEyeDropper(props, ref) {
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const ColorPickerChannelSlider = React.forwardRef(
+ function ColorPickerSlider(props, ref) {
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const ColorPickerSwatchTrigger = React.forwardRef(
+ function ColorPickerSwatchTrigger(props, ref) {
+ const { swatchSize, children, ...rest } = props
+ return (
+
+ {children || (
+
+
+
+
+
+ )}
+
+ )
+ },
+)
+
+export const ColorPickerRoot = React.forwardRef(
+ function ColorPickerRoot(props, ref) {
+ return (
+
+ {props.children}
+
+
+ )
+ },
+)
+
+const formatMap = {
+ rgba: ['red', 'green', 'blue', 'alpha'],
+ hsla: ['hue', 'saturation', 'lightness', 'alpha'],
+ hsba: ['hue', 'saturation', 'brightness', 'alpha'],
+ hexa: ['hex', 'alpha'],
+}
+
+export const ColorPickerChannelInputs = React.forwardRef(
+ function ColorPickerChannelInputs(props, ref) {
+ const channels = formatMap[props.format]
+ return (
+
+ {channels.map((channel) => (
+
+
+
+ {channel.charAt(0).toUpperCase()}
+
+
+ ))}
+
+ )
+ },
+)
+
+export const ColorPickerChannelSliders = React.forwardRef(
+ function ColorPickerChannelSliders(props, ref) {
+ const channels = formatMap[props.format]
+ return (
+
+
+ {(channel) => (
+
+
+ {channel}
+
+
+
+ )}
+
+
+ )
+ },
+)
+
+export const ColorPickerLabel = ChakraColorPicker.Label
+export const ColorPickerControl = ChakraColorPicker.Control
+export const ColorPickerValueText = ChakraColorPicker.ValueText
+export const ColorPickerValueSwatch = ChakraColorPicker.ValueSwatch
+export const ColorPickerChannelInput = ChakraColorPicker.ChannelInput
+export const ColorPickerSwatchGroup = ChakraColorPicker.SwatchGroup
diff --git a/src/components/ui/data-list.jsx b/src/components/ui/data-list.jsx
new file mode 100644
index 0000000..8ad0000
--- /dev/null
+++ b/src/components/ui/data-list.jsx
@@ -0,0 +1,21 @@
+import { DataList as ChakraDataList } from '@chakra-ui/react'
+import { InfoTip } from './toggle-tip'
+import * as React from 'react'
+
+export const DataListRoot = ChakraDataList.Root
+
+export const DataListItem = React.forwardRef(function DataListItem(props, ref) {
+ const { label, info, value, children, grow, ...rest } = props
+ return (
+
+
+ {label}
+ {info && {info}}
+
+
+ {value}
+
+ {children}
+
+ )
+})
diff --git a/src/components/ui/dialog.jsx b/src/components/ui/dialog.jsx
new file mode 100644
index 0000000..4558ec1
--- /dev/null
+++ b/src/components/ui/dialog.jsx
@@ -0,0 +1,54 @@
+import { Dialog as ChakraDialog, Portal } from '@chakra-ui/react'
+import { CloseButton } from './close-button'
+import * as React from 'react'
+
+export const DialogContent = React.forwardRef(
+ function DialogContent(props, ref) {
+ const {
+ children,
+ portalled = true,
+ portalRef,
+ backdrop = true,
+ ...rest
+ } = props
+
+ return (
+
+ {backdrop && }
+
+
+ {children}
+
+
+
+ )
+ },
+)
+
+export const DialogCloseTrigger = React.forwardRef(
+ function DialogCloseTrigger(props, ref) {
+ return (
+
+
+ {props.children}
+
+
+ )
+ },
+)
+
+export const DialogRoot = ChakraDialog.Root
+export const DialogFooter = ChakraDialog.Footer
+export const DialogHeader = ChakraDialog.Header
+export const DialogBody = ChakraDialog.Body
+export const DialogBackdrop = ChakraDialog.Backdrop
+export const DialogTitle = ChakraDialog.Title
+export const DialogDescription = ChakraDialog.Description
+export const DialogTrigger = ChakraDialog.Trigger
+export const DialogActionTrigger = ChakraDialog.ActionTrigger
diff --git a/src/components/ui/drawer.jsx b/src/components/ui/drawer.jsx
new file mode 100644
index 0000000..6c51d29
--- /dev/null
+++ b/src/components/ui/drawer.jsx
@@ -0,0 +1,44 @@
+import { Drawer as ChakraDrawer, Portal } from '@chakra-ui/react'
+import { CloseButton } from './close-button'
+import * as React from 'react'
+
+export const DrawerContent = React.forwardRef(
+ function DrawerContent(props, ref) {
+ const { children, portalled = true, portalRef, offset, ...rest } = props
+ return (
+
+
+
+ {children}
+
+
+
+ )
+ },
+)
+
+export const DrawerCloseTrigger = React.forwardRef(
+ function DrawerCloseTrigger(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const DrawerTrigger = ChakraDrawer.Trigger
+export const DrawerRoot = ChakraDrawer.Root
+export const DrawerFooter = ChakraDrawer.Footer
+export const DrawerHeader = ChakraDrawer.Header
+export const DrawerBody = ChakraDrawer.Body
+export const DrawerBackdrop = ChakraDrawer.Backdrop
+export const DrawerDescription = ChakraDrawer.Description
+export const DrawerTitle = ChakraDrawer.Title
+export const DrawerActionTrigger = ChakraDrawer.ActionTrigger
diff --git a/src/components/ui/empty-state.jsx b/src/components/ui/empty-state.jsx
new file mode 100644
index 0000000..8e87fac
--- /dev/null
+++ b/src/components/ui/empty-state.jsx
@@ -0,0 +1,26 @@
+import { EmptyState as ChakraEmptyState, VStack } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const EmptyState = React.forwardRef(function EmptyState(props, ref) {
+ const { title, description, icon, children, ...rest } = props
+ return (
+
+
+ {icon && (
+ {icon}
+ )}
+ {description ? (
+
+ {title}
+
+ {description}
+
+
+ ) : (
+ {title}
+ )}
+ {children}
+
+
+ )
+})
diff --git a/src/components/ui/field.jsx b/src/components/ui/field.jsx
new file mode 100644
index 0000000..d890c88
--- /dev/null
+++ b/src/components/ui/field.jsx
@@ -0,0 +1,22 @@
+import { Field as ChakraField } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Field = React.forwardRef(function Field(props, ref) {
+ const { label, children, helperText, errorText, optionalText, ...rest } =
+ props
+ return (
+
+ {label && (
+
+ {label}
+
+
+ )}
+ {children}
+ {helperText && (
+ {helperText}
+ )}
+ {errorText && {errorText}}
+
+ )
+})
diff --git a/src/components/ui/file-upload.jsx b/src/components/ui/file-upload.jsx
new file mode 100644
index 0000000..6b8c8da
--- /dev/null
+++ b/src/components/ui/file-upload.jsx
@@ -0,0 +1,141 @@
+function _nullishCoalesce(lhs, rhsFn) {
+ if (lhs != null) {
+ return lhs
+ } else {
+ return rhsFn()
+ }
+}
+;('use client')
+
+import {
+ Button,
+ FileUpload as ChakraFileUpload,
+ Icon,
+ IconButton,
+ Span,
+ Text,
+ useFileUploadContext,
+ useRecipe,
+} from '@chakra-ui/react'
+import * as React from 'react'
+import { LuFile, LuUpload, LuX } from 'react-icons/lu'
+
+export const FileUploadRoot = React.forwardRef(
+ function FileUploadRoot(props, ref) {
+ const { children, inputProps, ...rest } = props
+ return (
+
+
+ {children}
+
+ )
+ },
+)
+
+export const FileUploadDropzone = React.forwardRef(
+ function FileUploadDropzone(props, ref) {
+ const { children, label, description, ...rest } = props
+ return (
+
+
+
+
+
+ {label}
+ {description && {description}}
+
+ {children}
+
+ )
+ },
+)
+
+const FileUploadItem = React.forwardRef(function FileUploadItem(props, ref) {
+ const { file, showSize, clearable } = props
+ return (
+
+
+
+
+
+
+
+ {showSize ? (
+
+
+
+
+ ) : (
+
+ )}
+
+ {clearable && (
+
+
+
+
+
+ )}
+
+ )
+})
+
+export const FileUploadList = React.forwardRef(
+ function FileUploadList(props, ref) {
+ const { showSize, clearable, files, ...rest } = props
+
+ const fileUpload = useFileUploadContext()
+ const acceptedFiles = _nullishCoalesce(
+ files,
+ () => fileUpload.acceptedFiles,
+ )
+
+ if (acceptedFiles.length === 0) return null
+
+ return (
+
+ {acceptedFiles.map((file) => (
+
+ ))}
+
+ )
+ },
+)
+
+export const FileInput = React.forwardRef(function FileInput(props, ref) {
+ const inputRecipe = useRecipe({ key: 'input' })
+ const [recipeProps, restProps] = inputRecipe.splitVariantProps(props)
+ const { placeholder = 'Select file(s)', ...rest } = restProps
+ return (
+
+
+
+ )
+})
+
+export const FileUploadLabel = ChakraFileUpload.Label
+export const FileUploadClearTrigger = ChakraFileUpload.ClearTrigger
+export const FileUploadTrigger = ChakraFileUpload.Trigger
diff --git a/src/components/ui/hover-card.jsx b/src/components/ui/hover-card.jsx
new file mode 100644
index 0000000..1dd4b18
--- /dev/null
+++ b/src/components/ui/hover-card.jsx
@@ -0,0 +1,29 @@
+import { HoverCard, Portal } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const HoverCardContent = React.forwardRef(
+ function HoverCardContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const HoverCardArrow = React.forwardRef(
+ function HoverCardArrow(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const HoverCardRoot = HoverCard.Root
+export const HoverCardTrigger = HoverCard.Trigger
diff --git a/src/components/ui/input-group.jsx b/src/components/ui/input-group.jsx
new file mode 100644
index 0000000..46d83b2
--- /dev/null
+++ b/src/components/ui/input-group.jsx
@@ -0,0 +1,39 @@
+import { Group, InputElement } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const InputGroup = React.forwardRef(function InputGroup(props, ref) {
+ const {
+ startElement,
+ startElementProps,
+ endElement,
+ endElementProps,
+ children,
+ startOffset = '6px',
+ endOffset = '6px',
+ ...rest
+ } = props
+
+ const child = React.Children.only(children)
+
+ return (
+
+ {startElement && (
+
+ {startElement}
+
+ )}
+ {React.cloneElement(child, {
+ ...(startElement && {
+ ps: `calc(var(--input-height) - ${startOffset})`,
+ }),
+ ...(endElement && { pe: `calc(var(--input-height) - ${endOffset})` }),
+ ...children.props,
+ })}
+ {endElement && (
+
+ {endElement}
+
+ )}
+
+ )
+})
diff --git a/src/components/ui/link-button.jsx b/src/components/ui/link-button.jsx
new file mode 100644
index 0000000..23ca046
--- /dev/null
+++ b/src/components/ui/link-button.jsx
@@ -0,0 +1,8 @@
+'use client'
+
+import { createRecipeContext } from '@chakra-ui/react'
+
+const { withContext } = createRecipeContext({ key: 'button' })
+
+// Replace "a" with your framework's link component
+export const LinkButton = withContext('a')
diff --git a/src/components/ui/menu.jsx b/src/components/ui/menu.jsx
new file mode 100644
index 0000000..68c1a8b
--- /dev/null
+++ b/src/components/ui/menu.jsx
@@ -0,0 +1,94 @@
+'use client'
+
+import { AbsoluteCenter, Menu as ChakraMenu, Portal } from '@chakra-ui/react'
+import * as React from 'react'
+import { LuCheck, LuChevronRight } from 'react-icons/lu'
+
+export const MenuContent = React.forwardRef(function MenuContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+ return (
+
+
+
+
+
+ )
+})
+
+export const MenuArrow = React.forwardRef(function MenuArrow(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const MenuCheckboxItem = React.forwardRef(
+ function MenuCheckboxItem(props, ref) {
+ return (
+
+
+
+
+
+
+ {props.children}
+
+ )
+ },
+)
+
+export const MenuRadioItem = React.forwardRef(
+ function MenuRadioItem(props, ref) {
+ const { children, ...rest } = props
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+ },
+)
+
+export const MenuItemGroup = React.forwardRef(
+ function MenuItemGroup(props, ref) {
+ const { title, children, ...rest } = props
+ return (
+
+ {title && (
+
+ {title}
+
+ )}
+ {children}
+
+ )
+ },
+)
+
+export const MenuTriggerItem = React.forwardRef(
+ function MenuTriggerItem(props, ref) {
+ const { startIcon, children, ...rest } = props
+ return (
+
+ {startIcon}
+ {children}
+
+
+ )
+ },
+)
+
+export const MenuRadioItemGroup = ChakraMenu.RadioItemGroup
+export const MenuContextTrigger = ChakraMenu.ContextTrigger
+export const MenuRoot = ChakraMenu.Root
+export const MenuSeparator = ChakraMenu.Separator
+
+export const MenuItem = ChakraMenu.Item
+export const MenuItemText = ChakraMenu.ItemText
+export const MenuItemCommand = ChakraMenu.ItemCommand
+export const MenuTrigger = ChakraMenu.Trigger
diff --git a/src/components/ui/native-select.jsx b/src/components/ui/native-select.jsx
new file mode 100644
index 0000000..40e099e
--- /dev/null
+++ b/src/components/ui/native-select.jsx
@@ -0,0 +1,80 @@
+function _optionalChain(ops) {
+ let lastAccessLHS = undefined
+ let value = ops[0]
+ let i = 1
+ while (i < ops.length) {
+ const op = ops[i]
+ const fn = ops[i + 1]
+ i += 2
+ if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
+ return undefined
+ }
+ if (op === 'access' || op === 'optionalAccess') {
+ lastAccessLHS = value
+ value = fn(value)
+ } else if (op === 'call' || op === 'optionalCall') {
+ value = fn((...args) => value.call(lastAccessLHS, ...args))
+ lastAccessLHS = undefined
+ }
+ }
+ return value
+}
+;('use client')
+
+import { NativeSelect as Select } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const NativeSelectRoot = React.forwardRef(
+ function NativeSelect(props, ref) {
+ const { icon, children, ...rest } = props
+ return (
+
+ {children}
+ {icon}
+
+ )
+ },
+)
+
+export const NativeSelectField = React.forwardRef(
+ function NativeSelectField(props, ref) {
+ const { items: itemsProp, children, ...rest } = props
+
+ const items = React.useMemo(
+ () =>
+ _optionalChain([
+ itemsProp,
+ 'optionalAccess',
+ (_) => _.map,
+ 'call',
+ (_2) =>
+ _2((item) =>
+ typeof item === 'string' ? { label: item, value: item } : item,
+ ),
+ ]),
+ [itemsProp],
+ )
+
+ return (
+
+ {children}
+ {_optionalChain([
+ items,
+ 'optionalAccess',
+ (_3) => _3.map,
+ 'call',
+ (_4) =>
+ _4((item) => (
+
+ )),
+ ])}
+
+ )
+ },
+)
diff --git a/src/components/ui/number-input.jsx b/src/components/ui/number-input.jsx
new file mode 100644
index 0000000..e35fe51
--- /dev/null
+++ b/src/components/ui/number-input.jsx
@@ -0,0 +1,21 @@
+import { NumberInput as ChakraNumberInput } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const NumberInputRoot = React.forwardRef(
+ function NumberInput(props, ref) {
+ const { children, ...rest } = props
+ return (
+
+ {children}
+
+
+
+
+
+ )
+ },
+)
+
+export const NumberInputField = ChakraNumberInput.Input
+export const NumberInputScrubber = ChakraNumberInput.Scrubber
+export const NumberInputLabel = ChakraNumberInput.Label
diff --git a/src/components/ui/pagination.jsx b/src/components/ui/pagination.jsx
new file mode 100644
index 0000000..e84b1f2
--- /dev/null
+++ b/src/components/ui/pagination.jsx
@@ -0,0 +1,176 @@
+'use client'
+
+import {
+ Button,
+ Pagination as ChakraPagination,
+ IconButton,
+ Text,
+ createContext,
+ usePaginationContext,
+} from '@chakra-ui/react'
+import * as React from 'react'
+import {
+ HiChevronLeft,
+ HiChevronRight,
+ HiMiniEllipsisHorizontal,
+} from 'react-icons/hi2'
+import { LinkButton } from './link-button'
+
+const [RootPropsProvider, useRootProps] = createContext({
+ name: 'RootPropsProvider',
+})
+
+const variantMap = {
+ outline: { default: 'ghost', ellipsis: 'plain', current: 'outline' },
+ solid: { default: 'outline', ellipsis: 'outline', current: 'solid' },
+ subtle: { default: 'ghost', ellipsis: 'plain', current: 'subtle' },
+}
+
+export const PaginationRoot = React.forwardRef(
+ function PaginationRoot(props, ref) {
+ const { size = 'sm', variant = 'outline', getHref, ...rest } = props
+ return (
+
+
+
+ )
+ },
+)
+
+export const PaginationEllipsis = React.forwardRef(
+ function PaginationEllipsis(props, ref) {
+ const { size, variantMap } = useRootProps()
+ return (
+
+
+
+ )
+ },
+)
+
+export const PaginationItem = React.forwardRef(
+ function PaginationItem(props, ref) {
+ const { page } = usePaginationContext()
+ const { size, variantMap, getHref } = useRootProps()
+
+ const current = page === props.value
+ const variant = current ? variantMap.current : variantMap.default
+
+ if (getHref) {
+ return (
+
+ {props.value}
+
+ )
+ }
+
+ return (
+
+
+
+ )
+ },
+)
+
+export const PaginationPrevTrigger = React.forwardRef(
+ function PaginationPrevTrigger(props, ref) {
+ const { size, variantMap, getHref } = useRootProps()
+ const { previousPage } = usePaginationContext()
+
+ if (getHref) {
+ return (
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const PaginationNextTrigger = React.forwardRef(
+ function PaginationNextTrigger(props, ref) {
+ const { size, variantMap, getHref } = useRootProps()
+ const { nextPage } = usePaginationContext()
+
+ if (getHref) {
+ return (
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const PaginationItems = (props) => {
+ return (
+
+ {({ pages }) =>
+ pages.map((page, index) => {
+ return page.type === 'ellipsis' ? (
+
+ ) : (
+
+ )
+ })
+ }
+
+ )
+}
+
+export const PaginationPageText = React.forwardRef(
+ function PaginationPageText(props, ref) {
+ const { format = 'compact', ...rest } = props
+ const { page, totalPages, pageRange, count } = usePaginationContext()
+ const content = React.useMemo(() => {
+ if (format === 'short') return `${page} / ${totalPages}`
+ if (format === 'compact') return `${page} of ${totalPages}`
+ return `${pageRange.start + 1} - ${Math.min(pageRange.end, count)} of ${count}`
+ }, [format, page, totalPages, pageRange, count])
+
+ return (
+
+ {content}
+
+ )
+ },
+)
diff --git a/src/components/ui/password-input.jsx b/src/components/ui/password-input.jsx
new file mode 100644
index 0000000..95c082b
--- /dev/null
+++ b/src/components/ui/password-input.jsx
@@ -0,0 +1,121 @@
+'use client'
+
+import {
+ Box,
+ HStack,
+ IconButton,
+ Input,
+ InputGroup,
+ Stack,
+ mergeRefs,
+ useControllableState,
+} from '@chakra-ui/react'
+import * as React from 'react'
+import { LuEye, LuEyeOff } from 'react-icons/lu'
+
+export const PasswordInput = React.forwardRef(
+ function PasswordInput(props, ref) {
+ const {
+ rootProps,
+ defaultVisible,
+ visible: visibleProp,
+ onVisibleChange,
+ visibilityIcon = { on: , off: },
+ ...rest
+ } = props
+
+ const [visible, setVisible] = useControllableState({
+ value: visibleProp,
+ defaultValue: defaultVisible || false,
+ onChange: onVisibleChange,
+ })
+
+ const inputRef = React.useRef(null)
+
+ return (
+ {
+ if (rest.disabled) return
+ if (e.button !== 0) return
+ e.preventDefault()
+ setVisible(!visible)
+ }}
+ >
+ {visible ? visibilityIcon.off : visibilityIcon.on}
+
+ }
+ {...rootProps}
+ >
+
+
+ )
+ },
+)
+
+const VisibilityTrigger = React.forwardRef(
+ function VisibilityTrigger(props, ref) {
+ return (
+
+ )
+ },
+)
+
+export const PasswordStrengthMeter = React.forwardRef(
+ function PasswordStrengthMeter(props, ref) {
+ const { max = 4, value, ...rest } = props
+
+ const percent = (value / max) * 100
+ const { label, colorPalette } = getColorPalette(percent)
+
+ return (
+
+
+ {Array.from({ length: max }).map((_, index) => (
+
+ ))}
+
+ {label && {label}}
+
+ )
+ },
+)
+
+function getColorPalette(percent) {
+ switch (true) {
+ case percent < 33:
+ return { label: 'Low', colorPalette: 'red' }
+ case percent < 66:
+ return { label: 'Medium', colorPalette: 'orange' }
+ default:
+ return { label: 'High', colorPalette: 'green' }
+ }
+}
diff --git a/src/components/ui/pin-input.jsx b/src/components/ui/pin-input.jsx
new file mode 100644
index 0000000..7f2afcd
--- /dev/null
+++ b/src/components/ui/pin-input.jsx
@@ -0,0 +1,18 @@
+import { PinInput as ChakraPinInput, Group } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const PinInput = React.forwardRef(function PinInput(props, ref) {
+ const { count = 4, inputProps, rootRef, attached, ...rest } = props
+ return (
+
+
+
+
+ {Array.from({ length: count }).map((_, index) => (
+
+ ))}
+
+
+
+ )
+})
diff --git a/src/components/ui/popover.jsx b/src/components/ui/popover.jsx
new file mode 100644
index 0000000..6449eef
--- /dev/null
+++ b/src/components/ui/popover.jsx
@@ -0,0 +1,49 @@
+import { Popover as ChakraPopover, Portal } from '@chakra-ui/react'
+import { CloseButton } from './close-button'
+import * as React from 'react'
+
+export const PopoverContent = React.forwardRef(
+ function PopoverContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const PopoverArrow = React.forwardRef(function PopoverArrow(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const PopoverCloseTrigger = React.forwardRef(
+ function PopoverCloseTrigger(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const PopoverTitle = ChakraPopover.Title
+export const PopoverDescription = ChakraPopover.Description
+export const PopoverFooter = ChakraPopover.Footer
+export const PopoverHeader = ChakraPopover.Header
+export const PopoverRoot = ChakraPopover.Root
+export const PopoverBody = ChakraPopover.Body
+export const PopoverTrigger = ChakraPopover.Trigger
diff --git a/src/components/ui/progress-circle.jsx b/src/components/ui/progress-circle.jsx
new file mode 100644
index 0000000..d709606
--- /dev/null
+++ b/src/components/ui/progress-circle.jsx
@@ -0,0 +1,29 @@
+import {
+ AbsoluteCenter,
+ ProgressCircle as ChakraProgressCircle,
+} from '@chakra-ui/react'
+import * as React from 'react'
+
+export const ProgressCircleRing = React.forwardRef(
+ function ProgressCircleRing(props, ref) {
+ const { trackColor, cap, color, ...rest } = props
+ return (
+
+
+
+
+ )
+ },
+)
+
+export const ProgressCircleValueText = React.forwardRef(
+ function ProgressCircleValueText(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const ProgressCircleRoot = ChakraProgressCircle.Root
diff --git a/src/components/ui/progress.jsx b/src/components/ui/progress.jsx
new file mode 100644
index 0000000..300c0fb
--- /dev/null
+++ b/src/components/ui/progress.jsx
@@ -0,0 +1,26 @@
+import { Progress as ChakraProgress } from '@chakra-ui/react'
+import { InfoTip } from './toggle-tip'
+import * as React from 'react'
+
+export const ProgressBar = React.forwardRef(function ProgressBar(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const ProgressLabel = React.forwardRef(
+ function ProgressLabel(props, ref) {
+ const { children, info, ...rest } = props
+ return (
+
+ {children}
+ {info && {info}}
+
+ )
+ },
+)
+
+export const ProgressRoot = ChakraProgress.Root
+export const ProgressValueText = ChakraProgress.ValueText
diff --git a/src/components/ui/prose.jsx b/src/components/ui/prose.jsx
new file mode 100644
index 0000000..c927a3f
--- /dev/null
+++ b/src/components/ui/prose.jsx
@@ -0,0 +1,264 @@
+'use client'
+
+import { chakra } from '@chakra-ui/react'
+
+export const Prose = chakra('div', {
+ base: {
+ color: 'fg.muted',
+ maxWidth: '65ch',
+ fontSize: 'sm',
+ lineHeight: '1.7em',
+ '& p': {
+ marginTop: '1em',
+ marginBottom: '1em',
+ },
+ '& blockquote': {
+ marginTop: '1.285em',
+ marginBottom: '1.285em',
+ paddingInline: '1.285em',
+ borderInlineStartWidth: '0.25em',
+ },
+ '& a': {
+ color: 'fg',
+ textDecoration: 'underline',
+ textUnderlineOffset: '3px',
+ textDecorationThickness: '2px',
+ textDecorationColor: 'border.muted',
+ fontWeight: '500',
+ },
+ '& strong': {
+ fontWeight: '600',
+ },
+ '& a strong': {
+ color: 'inherit',
+ },
+ '& h1': {
+ fontSize: '2.15em',
+ letterSpacing: '-0.02em',
+ marginTop: '0',
+ marginBottom: '0.8em',
+ lineHeight: '1.2em',
+ },
+ '& h2': {
+ fontSize: '1.4em',
+ letterSpacing: '-0.02em',
+ marginTop: '1.6em',
+ marginBottom: '0.8em',
+ lineHeight: '1.4em',
+ },
+ '& h3': {
+ fontSize: '1.285em',
+ letterSpacing: '-0.01em',
+ marginTop: '1.5em',
+ marginBottom: '0.4em',
+ lineHeight: '1.5em',
+ },
+ '& h4': {
+ marginTop: '1.4em',
+ marginBottom: '0.5em',
+ letterSpacing: '-0.01em',
+ lineHeight: '1.5em',
+ },
+ '& img': {
+ marginTop: '1.7em',
+ marginBottom: '1.7em',
+ borderRadius: 'lg',
+ boxShadow: 'inset',
+ },
+ '& picture': {
+ marginTop: '1.7em',
+ marginBottom: '1.7em',
+ },
+ '& picture > img': {
+ marginTop: '0',
+ marginBottom: '0',
+ },
+ '& video': {
+ marginTop: '1.7em',
+ marginBottom: '1.7em',
+ },
+ '& kbd': {
+ fontSize: '0.85em',
+ borderRadius: 'xs',
+ paddingTop: '0.15em',
+ paddingBottom: '0.15em',
+ paddingInlineEnd: '0.35em',
+ paddingInlineStart: '0.35em',
+ fontFamily: 'inherit',
+ color: 'fg.muted',
+ '--shadow': 'colors.border',
+ boxShadow: '0 0 0 1px var(--shadow),0 1px 0 1px var(--shadow)',
+ },
+ '& code': {
+ fontSize: '0.925em',
+ letterSpacing: '-0.01em',
+ borderRadius: 'md',
+ borderWidth: '1px',
+ padding: '0.25em',
+ },
+ '& pre code': {
+ fontSize: 'inherit',
+ letterSpacing: 'inherit',
+ borderWidth: 'inherit',
+ padding: '0',
+ },
+ '& h2 code': {
+ fontSize: '0.9em',
+ },
+ '& h3 code': {
+ fontSize: '0.8em',
+ },
+ '& pre': {
+ backgroundColor: 'bg.subtle',
+ marginTop: '1.6em',
+ marginBottom: '1.6em',
+ borderRadius: 'md',
+ fontSize: '0.9em',
+ paddingTop: '0.65em',
+ paddingBottom: '0.65em',
+ paddingInlineEnd: '1em',
+ paddingInlineStart: '1em',
+ overflowX: 'auto',
+ fontWeight: '400',
+ },
+ '& ol': {
+ marginTop: '1em',
+ marginBottom: '1em',
+ paddingInlineStart: '1.5em',
+ },
+ '& ul': {
+ marginTop: '1em',
+ marginBottom: '1em',
+ paddingInlineStart: '1.5em',
+ },
+ '& li': {
+ marginTop: '0.285em',
+ marginBottom: '0.285em',
+ },
+ '& ol > li': {
+ paddingInlineStart: '0.4em',
+ listStyleType: 'decimal',
+ '&::marker': {
+ color: 'fg.muted',
+ },
+ },
+ '& ul > li': {
+ paddingInlineStart: '0.4em',
+ listStyleType: 'disc',
+ '&::marker': {
+ color: 'fg.muted',
+ },
+ },
+ '& > ul > li p': {
+ marginTop: '0.5em',
+ marginBottom: '0.5em',
+ },
+ '& > ul > li > p:first-of-type': {
+ marginTop: '1em',
+ },
+ '& > ul > li > p:last-of-type': {
+ marginBottom: '1em',
+ },
+ '& > ol > li > p:first-of-type': {
+ marginTop: '1em',
+ },
+ '& > ol > li > p:last-of-type': {
+ marginBottom: '1em',
+ },
+ '& ul ul, ul ol, ol ul, ol ol': {
+ marginTop: '0.5em',
+ marginBottom: '0.5em',
+ },
+ '& dl': {
+ marginTop: '1em',
+ marginBottom: '1em',
+ },
+ '& dt': {
+ fontWeight: '600',
+ marginTop: '1em',
+ },
+ '& dd': {
+ marginTop: '0.285em',
+ paddingInlineStart: '1.5em',
+ },
+ '& hr': {
+ marginTop: '2.25em',
+ marginBottom: '2.25em',
+ },
+ '& :is(h1,h2,h3,h4,h5,hr) + *': {
+ marginTop: '0',
+ },
+ '& table': {
+ width: '100%',
+ tableLayout: 'auto',
+ textAlign: 'start',
+ lineHeight: '1.5em',
+ marginTop: '2em',
+ marginBottom: '2em',
+ },
+ '& thead': {
+ borderBottomWidth: '1px',
+ color: 'fg',
+ },
+ '& tbody tr': {
+ borderBottomWidth: '1px',
+ borderBottomColor: 'border',
+ },
+ '& thead th': {
+ paddingInlineEnd: '1em',
+ paddingBottom: '0.65em',
+ paddingInlineStart: '1em',
+ fontWeight: 'medium',
+ textAlign: 'start',
+ },
+ '& thead th:first-of-type': {
+ paddingInlineStart: '0',
+ },
+ '& thead th:last-of-type': {
+ paddingInlineEnd: '0',
+ },
+ '& tbody td, tfoot td': {
+ paddingTop: '0.65em',
+ paddingInlineEnd: '1em',
+ paddingBottom: '0.65em',
+ paddingInlineStart: '1em',
+ },
+ '& tbody td:first-of-type, tfoot td:first-of-type': {
+ paddingInlineStart: '0',
+ },
+ '& tbody td:last-of-type, tfoot td:last-of-type': {
+ paddingInlineEnd: '0',
+ },
+ '& figure': {
+ marginTop: '1.625em',
+ marginBottom: '1.625em',
+ },
+ '& figure > *': {
+ marginTop: '0',
+ marginBottom: '0',
+ },
+ '& figcaption': {
+ fontSize: '0.85em',
+ lineHeight: '1.25em',
+ marginTop: '0.85em',
+ color: 'fg.muted',
+ },
+ '& h1, h2, h3, h4': {
+ color: 'fg',
+ fontWeight: '600',
+ },
+ },
+ variants: {
+ size: {
+ md: {
+ fontSize: 'sm',
+ },
+ lg: {
+ fontSize: 'md',
+ },
+ },
+ },
+ defaultVariants: {
+ size: 'md',
+ },
+})
diff --git a/src/components/ui/qr-code.jsx b/src/components/ui/qr-code.jsx
new file mode 100644
index 0000000..91a20b1
--- /dev/null
+++ b/src/components/ui/qr-code.jsx
@@ -0,0 +1,15 @@
+import { QrCode as ChakraQrCode } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const QrCode = React.forwardRef(function QrCode(props, ref) {
+ const { children, fill, overlay, ...rest } = props
+ return (
+
+
+
+
+ {overlay}
+ {children && {children}}
+
+ )
+})
diff --git a/src/components/ui/radio-card.jsx b/src/components/ui/radio-card.jsx
new file mode 100644
index 0000000..a0786b3
--- /dev/null
+++ b/src/components/ui/radio-card.jsx
@@ -0,0 +1,47 @@
+import { RadioCard } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const RadioCardItem = React.forwardRef(
+ function RadioCardItem(props, ref) {
+ const {
+ inputProps,
+ label,
+ description,
+ addon,
+ icon,
+ indicator = ,
+ indicatorPlacement = 'end',
+ ...rest
+ } = props
+
+ const hasContent = label || description || icon
+ const ContentWrapper = indicator ? RadioCard.ItemContent : React.Fragment
+
+ return (
+
+
+
+ {indicatorPlacement === 'start' && indicator}
+ {hasContent && (
+
+ {icon}
+ {label && {label}}
+ {description && (
+
+ {description}
+
+ )}
+ {indicatorPlacement === 'inside' && indicator}
+
+ )}
+ {indicatorPlacement === 'end' && indicator}
+
+ {addon && {addon}}
+
+ )
+ },
+)
+
+export const RadioCardRoot = RadioCard.Root
+export const RadioCardLabel = RadioCard.Label
+export const RadioCardItemIndicator = RadioCard.ItemIndicator
diff --git a/src/components/ui/radio.jsx b/src/components/ui/radio.jsx
new file mode 100644
index 0000000..8058902
--- /dev/null
+++ b/src/components/ui/radio.jsx
@@ -0,0 +1,17 @@
+import { RadioGroup as ChakraRadioGroup } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Radio = React.forwardRef(function Radio(props, ref) {
+ const { children, inputProps, rootRef, ...rest } = props
+ return (
+
+
+
+ {children && (
+ {children}
+ )}
+
+ )
+})
+
+export const RadioGroup = ChakraRadioGroup.Root
diff --git a/src/components/ui/rating.jsx b/src/components/ui/rating.jsx
new file mode 100644
index 0000000..399c7d0
--- /dev/null
+++ b/src/components/ui/rating.jsx
@@ -0,0 +1,19 @@
+import { RatingGroup } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Rating = React.forwardRef(function Rating(props, ref) {
+ const { icon, count = 5, label, ...rest } = props
+ return (
+
+ {label && {label}}
+
+
+ {Array.from({ length: count }).map((_, index) => (
+
+
+
+ ))}
+
+
+ )
+})
diff --git a/src/components/ui/segmented-control.jsx b/src/components/ui/segmented-control.jsx
new file mode 100644
index 0000000..00ce604
--- /dev/null
+++ b/src/components/ui/segmented-control.jsx
@@ -0,0 +1,36 @@
+'use client'
+
+import { For, SegmentGroup } from '@chakra-ui/react'
+import * as React from 'react'
+
+function normalize(items) {
+ return items.map((item) => {
+ if (typeof item === 'string') return { value: item, label: item }
+ return item
+ })
+}
+
+export const SegmentedControl = React.forwardRef(
+ function SegmentedControl(props, ref) {
+ const { items, ...rest } = props
+ const data = React.useMemo(() => normalize(items), [items])
+
+ return (
+
+
+
+ {(item) => (
+
+ {item.label}
+
+
+ )}
+
+
+ )
+ },
+)
diff --git a/src/components/ui/select.jsx b/src/components/ui/select.jsx
new file mode 100644
index 0000000..ed02fe2
--- /dev/null
+++ b/src/components/ui/select.jsx
@@ -0,0 +1,113 @@
+'use client'
+
+import { Select as ChakraSelect, Portal } from '@chakra-ui/react'
+import { CloseButton } from './close-button'
+import * as React from 'react'
+
+export const SelectTrigger = React.forwardRef(
+ function SelectTrigger(props, ref) {
+ const { children, clearable, ...rest } = props
+ return (
+
+ {children}
+
+ {clearable && }
+
+
+
+ )
+ },
+)
+
+const SelectClearTrigger = React.forwardRef(
+ function SelectClearTrigger(props, ref) {
+ return (
+
+
+
+ )
+ },
+)
+
+export const SelectContent = React.forwardRef(
+ function SelectContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const SelectItem = React.forwardRef(function SelectItem(props, ref) {
+ const { item, children, ...rest } = props
+ return (
+
+ {children}
+
+
+ )
+})
+
+export const SelectValueText = React.forwardRef(
+ function SelectValueText(props, ref) {
+ const { children, ...rest } = props
+ return (
+
+
+ {(select) => {
+ const items = select.selectedItems
+ if (items.length === 0) return props.placeholder
+ if (children) return children(items)
+ if (items.length === 1)
+ return select.collection.stringifyItem(items[0])
+ return `${items.length} selected`
+ }}
+
+
+ )
+ },
+)
+
+export const SelectRoot = React.forwardRef(function SelectRoot(props, ref) {
+ return (
+
+ {props.asChild ? (
+ props.children
+ ) : (
+ <>
+
+ {props.children}
+ >
+ )}
+
+ )
+})
+
+export const SelectItemGroup = React.forwardRef(
+ function SelectItemGroup(props, ref) {
+ const { children, label, ...rest } = props
+ return (
+
+ {label}
+ {children}
+
+ )
+ },
+)
+
+export const SelectLabel = ChakraSelect.Label
+export const SelectItemText = ChakraSelect.ItemText
diff --git a/src/components/ui/skeleton.jsx b/src/components/ui/skeleton.jsx
new file mode 100644
index 0000000..8195fa1
--- /dev/null
+++ b/src/components/ui/skeleton.jsx
@@ -0,0 +1,32 @@
+import { Skeleton as ChakraSkeleton, Circle, Stack } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const SkeletonCircle = React.forwardRef(
+ function SkeletonCircle(props, ref) {
+ const { size, ...rest } = props
+ return (
+
+
+
+ )
+ },
+)
+
+export const SkeletonText = React.forwardRef(function SkeletonText(props, ref) {
+ const { noOfLines = 3, gap, ...rest } = props
+ return (
+
+ {Array.from({ length: noOfLines }).map((_, index) => (
+
+ ))}
+
+ )
+})
+
+export const Skeleton = ChakraSkeleton
diff --git a/src/components/ui/slider.jsx b/src/components/ui/slider.jsx
new file mode 100644
index 0000000..35e3659
--- /dev/null
+++ b/src/components/ui/slider.jsx
@@ -0,0 +1,107 @@
+function _nullishCoalesce(lhs, rhsFn) {
+ if (lhs != null) {
+ return lhs
+ } else {
+ return rhsFn()
+ }
+}
+function _optionalChain(ops) {
+ let lastAccessLHS = undefined
+ let value = ops[0]
+ let i = 1
+ while (i < ops.length) {
+ const op = ops[i]
+ const fn = ops[i + 1]
+ i += 2
+ if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
+ return undefined
+ }
+ if (op === 'access' || op === 'optionalAccess') {
+ lastAccessLHS = value
+ value = fn(value)
+ } else if (op === 'call' || op === 'optionalCall') {
+ value = fn((...args) => value.call(lastAccessLHS, ...args))
+ lastAccessLHS = undefined
+ }
+ }
+ return value
+}
+import { Slider as ChakraSlider, For, HStack } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Slider = React.forwardRef(function Slider(props, ref) {
+ const { marks: marksProp, label, showValue, ...rest } = props
+ const value = _nullishCoalesce(props.defaultValue, () => props.value)
+
+ const marks = _optionalChain([
+ marksProp,
+ 'optionalAccess',
+ (_2) => _2.map,
+ 'call',
+ (_3) =>
+ _3((mark) => {
+ if (typeof mark === 'number') return { value: mark, label: undefined }
+ return mark
+ }),
+ ])
+
+ const hasMarkLabel = !!_optionalChain([
+ marks,
+ 'optionalAccess',
+ (_4) => _4.some,
+ 'call',
+ (_5) => _5((mark) => mark.label),
+ ])
+
+ return (
+
+ {label && !showValue && {label}}
+ {label && showValue && (
+
+ {label}
+
+
+ )}
+
+
+
+
+
+
+
+
+ )
+})
+
+function SliderThumbs(props) {
+ const { value } = props
+ return (
+
+ {(_, index) => (
+
+
+
+ )}
+
+ )
+}
+
+const SliderMarks = React.forwardRef(function SliderMarks(props, ref) {
+ const { marks } = props
+ if (!_optionalChain([marks, 'optionalAccess', (_6) => _6.length])) return null
+
+ return (
+
+ {marks.map((mark, index) => {
+ const value = typeof mark === 'number' ? mark : mark.value
+ const label = typeof mark === 'number' ? undefined : mark.label
+ return (
+
+
+ {label}
+
+ )
+ })}
+
+ )
+})
diff --git a/src/components/ui/stat.jsx b/src/components/ui/stat.jsx
new file mode 100644
index 0000000..076a4f5
--- /dev/null
+++ b/src/components/ui/stat.jsx
@@ -0,0 +1,49 @@
+import { Badge, Stat as ChakraStat, FormatNumber } from '@chakra-ui/react'
+import { InfoTip } from './toggle-tip'
+import * as React from 'react'
+
+export const StatLabel = React.forwardRef(function StatLabel(props, ref) {
+ const { info, children, ...rest } = props
+ return (
+
+ {children}
+ {info && {info}}
+
+ )
+})
+
+export const StatValueText = React.forwardRef(
+ function StatValueText(props, ref) {
+ const { value, formatOptions, children, ...rest } = props
+ return (
+
+ {children ||
+ (value != null && )}
+
+ )
+ },
+)
+
+export const StatUpTrend = React.forwardRef(function StatUpTrend(props, ref) {
+ return (
+
+
+ {props.children}
+
+ )
+})
+
+export const StatDownTrend = React.forwardRef(
+ function StatDownTrend(props, ref) {
+ return (
+
+
+ {props.children}
+
+ )
+ },
+)
+
+export const StatRoot = ChakraStat.Root
+export const StatHelpText = ChakraStat.HelpText
+export const StatValueUnit = ChakraStat.ValueUnit
diff --git a/src/components/ui/status.jsx b/src/components/ui/status.jsx
new file mode 100644
index 0000000..32e2c5e
--- /dev/null
+++ b/src/components/ui/status.jsx
@@ -0,0 +1,30 @@
+function _nullishCoalesce(lhs, rhsFn) {
+ if (lhs != null) {
+ return lhs
+ } else {
+ return rhsFn()
+ }
+}
+import { Status as ChakraStatus } from '@chakra-ui/react'
+import * as React from 'react'
+
+const statusMap = {
+ success: 'green',
+ error: 'red',
+ warning: 'orange',
+ info: 'blue',
+}
+
+export const Status = React.forwardRef(function Status(props, ref) {
+ const { children, value = 'info', ...rest } = props
+ const colorPalette = _nullishCoalesce(
+ rest.colorPalette,
+ () => statusMap[value],
+ )
+ return (
+
+
+ {children}
+
+ )
+})
diff --git a/src/components/ui/stepper-input.jsx b/src/components/ui/stepper-input.jsx
new file mode 100644
index 0000000..2f9fb8a
--- /dev/null
+++ b/src/components/ui/stepper-input.jsx
@@ -0,0 +1,41 @@
+import { HStack, IconButton, NumberInput } from '@chakra-ui/react'
+import * as React from 'react'
+import { LuMinus, LuPlus } from 'react-icons/lu'
+
+export const StepperInput = React.forwardRef(function StepperInput(props, ref) {
+ const { label, ...rest } = props
+ return (
+
+ {label && {label}}
+
+
+
+
+
+
+ )
+})
+
+const DecrementTrigger = React.forwardRef(
+ function DecrementTrigger(props, ref) {
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+const IncrementTrigger = React.forwardRef(
+ function IncrementTrigger(props, ref) {
+ return (
+
+
+
+
+
+ )
+ },
+)
diff --git a/src/components/ui/steps.jsx b/src/components/ui/steps.jsx
new file mode 100644
index 0000000..5394f1f
--- /dev/null
+++ b/src/components/ui/steps.jsx
@@ -0,0 +1,62 @@
+import { Box, Steps as ChakraSteps } from '@chakra-ui/react'
+import * as React from 'react'
+import { LuCheck } from 'react-icons/lu'
+
+export const StepsItem = React.forwardRef(function StepsItem(props, ref) {
+ const { title, description, completedIcon, icon, ...rest } = props
+ return (
+
+
+
+ }
+ incomplete={icon || }
+ />
+
+
+
+
+
+ )
+})
+
+const StepInfo = (props) => {
+ const { title, description } = props
+
+ if (title && description) {
+ return (
+
+ {title}
+ {description}
+
+ )
+ }
+
+ return (
+ <>
+ {title && {title}}
+ {description && (
+ {description}
+ )}
+ >
+ )
+}
+
+export const StepsIndicator = React.forwardRef(
+ function StepsIndicator(props, ref) {
+ const { icon = , completedIcon } = props
+ return (
+
+
+
+ )
+ },
+)
+
+export const StepsList = ChakraSteps.List
+export const StepsRoot = ChakraSteps.Root
+export const StepsContent = ChakraSteps.Content
+export const StepsCompletedContent = ChakraSteps.CompletedContent
+
+export const StepsNextTrigger = ChakraSteps.NextTrigger
+export const StepsPrevTrigger = ChakraSteps.PrevTrigger
diff --git a/src/components/ui/switch.jsx b/src/components/ui/switch.jsx
new file mode 100644
index 0000000..252b141
--- /dev/null
+++ b/src/components/ui/switch.jsx
@@ -0,0 +1,55 @@
+function _optionalChain(ops) {
+ let lastAccessLHS = undefined
+ let value = ops[0]
+ let i = 1
+ while (i < ops.length) {
+ const op = ops[i]
+ const fn = ops[i + 1]
+ i += 2
+ if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) {
+ return undefined
+ }
+ if (op === 'access' || op === 'optionalAccess') {
+ lastAccessLHS = value
+ value = fn(value)
+ } else if (op === 'call' || op === 'optionalCall') {
+ value = fn((...args) => value.call(lastAccessLHS, ...args))
+ lastAccessLHS = undefined
+ }
+ }
+ return value
+}
+import { Switch as ChakraSwitch } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Switch = React.forwardRef(function Switch(props, ref) {
+ const { inputProps, children, rootRef, trackLabel, thumbLabel, ...rest } =
+ props
+
+ return (
+
+
+
+
+ {thumbLabel && (
+ _.off,
+ ])}
+ >
+ {_optionalChain([thumbLabel, 'optionalAccess', (_2) => _2.on])}
+
+ )}
+
+ {trackLabel && (
+
+ {trackLabel.on}
+
+ )}
+
+ {children != null && {children}}
+
+ )
+})
diff --git a/src/components/ui/tag.jsx b/src/components/ui/tag.jsx
new file mode 100644
index 0000000..95de898
--- /dev/null
+++ b/src/components/ui/tag.jsx
@@ -0,0 +1,28 @@
+import { Tag as ChakraTag } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const Tag = React.forwardRef(function Tag(props, ref) {
+ const {
+ startElement,
+ endElement,
+ onClose,
+ closable = !!onClose,
+ children,
+ ...rest
+ } = props
+
+ return (
+
+ {startElement && (
+ {startElement}
+ )}
+ {children}
+ {endElement && {endElement}}
+ {closable && (
+
+
+
+ )}
+
+ )
+})
diff --git a/src/components/ui/timeline.jsx b/src/components/ui/timeline.jsx
new file mode 100644
index 0000000..33e57eb
--- /dev/null
+++ b/src/components/ui/timeline.jsx
@@ -0,0 +1,20 @@
+import { Timeline as ChakraTimeline } from '@chakra-ui/react'
+import * as React from 'react'
+
+export const TimelineConnector = React.forwardRef(
+ function TimelineConnector(props, ref) {
+ return (
+
+
+
+
+ )
+ },
+)
+
+export const TimelineRoot = ChakraTimeline.Root
+export const TimelineContent = ChakraTimeline.Content
+export const TimelineItem = ChakraTimeline.Item
+export const TimelineIndicator = ChakraTimeline.Indicator
+export const TimelineTitle = ChakraTimeline.Title
+export const TimelineDescription = ChakraTimeline.Description
diff --git a/src/components/ui/toggle-tip.jsx b/src/components/ui/toggle-tip.jsx
new file mode 100644
index 0000000..b3ca45a
--- /dev/null
+++ b/src/components/ui/toggle-tip.jsx
@@ -0,0 +1,58 @@
+import { Popover as ChakraPopover, IconButton, Portal } from '@chakra-ui/react'
+import * as React from 'react'
+import { HiOutlineInformationCircle } from 'react-icons/hi'
+
+export const ToggleTip = React.forwardRef(function ToggleTip(props, ref) {
+ const {
+ showArrow,
+ children,
+ portalled = true,
+ content,
+ portalRef,
+ ...rest
+ } = props
+
+ return (
+
+ {children}
+
+
+
+ {showArrow && (
+
+
+
+ )}
+ {content}
+
+
+
+
+ )
+})
+
+export const InfoTip = React.forwardRef(function InfoTip(props, ref) {
+ const { children, ...rest } = props
+ return (
+
+
+
+
+
+ )
+})
diff --git a/src/components/ui/toggle.jsx b/src/components/ui/toggle.jsx
new file mode 100644
index 0000000..d3926ac
--- /dev/null
+++ b/src/components/ui/toggle.jsx
@@ -0,0 +1,44 @@
+'use client'
+
+import {
+ Button,
+ Toggle as ChakraToggle,
+ useToggleContext,
+} from '@chakra-ui/react'
+import * as React from 'react'
+
+const variantMap = {
+ solid: { on: 'solid', off: 'outline' },
+ surface: { on: 'surface', off: 'outline' },
+ subtle: { on: 'subtle', off: 'ghost' },
+ ghost: { on: 'subtle', off: 'ghost' },
+}
+
+export const Toggle = React.forwardRef(function Toggle(props, ref) {
+ const { variant = 'subtle', size, children, ...rest } = props
+ const variantConfig = variantMap[variant]
+
+ return (
+
+
+ {children}
+
+
+ )
+})
+
+const ToggleBaseButton = React.forwardRef(
+ function ToggleBaseButton(props, ref) {
+ const toggle = useToggleContext()
+ const { variant, ...rest } = props
+ return (
+
+ )
+ },
+)
+
+export const ToggleIndicator = ChakraToggle.Indicator
diff --git a/src/index.css b/src/index.css
index d69c824..465082c 100644
--- a/src/index.css
+++ b/src/index.css
@@ -1 +1,12 @@
-@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@100..900&display=swap');
\ No newline at end of file
+@import url('https://fonts.googleapis.com/css2?family=Lexend:wght@100..900&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&display=swap');
+
+/* : Use a value from 400 to 700
+ : Use a unique and descriptive class name */
+
+.pixelify-sans-text-400 {
+ font-family: "Pixelify Sans", sans-serif;
+ font-optical-sizing: auto;
+ font-weight: 400;
+ font-style: normal;
+}
\ No newline at end of file
diff --git a/src/main.jsx b/src/main.jsx
index c61b0bb..eaf4bbd 100644
--- a/src/main.jsx
+++ b/src/main.jsx
@@ -1,13 +1,17 @@
import { createRoot } from 'react-dom/client'
import './index.css'
+import "./core.css";
import { ChakraProvider, defaultSystem, Text } from "@chakra-ui/react"
import { Provider } from 'react-redux'
import { configureStore } from '@reduxjs/toolkit'
import universalReducer from './slices/UniversalState.js'
import { BrowserRouter, Route, Routes } from 'react-router'
-import Home from './pages/Home.jsx'
+import Catalogue from './pages/Catalogue.jsx'
+// import Test from './pages/test.jsx'
import Layout from './Layout.jsx'
import MainTheme from './themes/MainTheme.js'
+import Health from './pages/Health.jsx'
+import Homepage from './pages/Homepage.jsx'
const store = configureStore({
reducer: {
@@ -21,7 +25,11 @@ createRoot(document.getElementById('root')).render(
}>
- } />
+ } />
+ } />
+ } />
+
+ {/* } /> */}
diff --git a/src/pages/Catalogue.jsx b/src/pages/Catalogue.jsx
new file mode 100644
index 0000000..3429a52
--- /dev/null
+++ b/src/pages/Catalogue.jsx
@@ -0,0 +1,10 @@
+import { Button, Text, Image, VStack, HStack } from "@chakra-ui/react";
+import React, { useState } from "react";
+import { useSelector } from "react-redux";
+import server from "../networking";
+
+function Catalogue() {
+ return More coming soon!
+}
+
+export default Catalogue;
diff --git a/src/pages/Home.jsx b/src/pages/Health.jsx
similarity index 96%
rename from src/pages/Home.jsx
rename to src/pages/Health.jsx
index 1b75d2e..0364fb0 100644
--- a/src/pages/Home.jsx
+++ b/src/pages/Health.jsx
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from 'react'
import { useSelector } from 'react-redux'
import server, { JSONResponse } from "../networking";
-function Home() {
+function Health() {
const { systemVersion, systemName } = useSelector((state) => state.universal)
const [healthCheckMessage, setHealthCheckMessage] = useState("Checking...");
@@ -34,4 +34,4 @@ function Home() {
>
}
-export default Home
\ No newline at end of file
+export default Health
\ No newline at end of file
diff --git a/src/pages/Homepage.jsx b/src/pages/Homepage.jsx
new file mode 100644
index 0000000..cd6e46c
--- /dev/null
+++ b/src/pages/Homepage.jsx
@@ -0,0 +1,55 @@
+import { Box, Button, Flex, Image, Spacer, Text, VStack } from '@chakra-ui/react'
+import hp1 from '../assets/hp1.png';
+import hp2 from '../assets/hp2.png';
+import hp3 from '../assets/hp3.png';
+import hp4 from '../assets/hp4.png';
+import hp5 from '../assets/hp5.png';
+import hp6 from '../assets/hp6.png';
+
+function Homepage() {
+ const imgResponsiveSizing = { base: "150px", md: "250px" }
+ const imgColumnMinWidth = { base: "350px", md: "450px" }
+ const imgOffset = "-100px"
+
+ return
+
+
+
+
+ {/* First images column */}
+
+
+
+
+
+
+
+
+
+
+ {/* Title, subtitle, and CTA button column */}
+
+
+ Connect
with your
roots
+ The intelligent artefact digitisation platform.
+
+
+
+
+
+
+ {/* Second images column */}
+
+
+
+
+
+
+
+
+
+
+
+}
+
+export default Homepage
\ No newline at end of file
diff --git a/src/themes/MainTheme.js b/src/themes/MainTheme.js
index 60e33f1..a912f61 100644
--- a/src/themes/MainTheme.js
+++ b/src/themes/MainTheme.js
@@ -17,7 +17,7 @@ const buttonRecipe = defineRecipe({
}
}
})
-
+
const textRecipe = defineRecipe({
base: {
fontFamily: 'Lexend',