@@ -33,7 +33,7 @@ export const Footer = () => {
- >
+ >)
);
}
diff --git a/app/components/Footer/package.json b/src/components/GB_Footer/package.json
similarity index 100%
rename from app/components/Footer/package.json
rename to src/components/GB_Footer/package.json
diff --git a/app/components/Footer/styles.module.scss b/src/components/GB_Footer/styles.module.scss
similarity index 100%
rename from app/components/Footer/styles.module.scss
rename to src/components/GB_Footer/styles.module.scss
diff --git a/app/components/Header/index.tsx b/src/components/GB_Header/index.tsx
similarity index 61%
rename from app/components/Header/index.tsx
rename to src/components/GB_Header/index.tsx
index 312c75e..2dc7f12 100644
--- a/app/components/Header/index.tsx
+++ b/src/components/GB_Header/index.tsx
@@ -21,41 +21,39 @@ export default class Header extends Component {
render() {
return (
-
)
+ );
}
}
diff --git a/app/components/Header/package.json b/src/components/GB_Header/package.json
similarity index 100%
rename from app/components/Header/package.json
rename to src/components/GB_Header/package.json
diff --git a/app/components/Header/styles.module.css b/src/components/GB_Header/styles.module.css
similarity index 100%
rename from app/components/Header/styles.module.css
rename to src/components/GB_Header/styles.module.css
diff --git a/app/components/Hero/index.tsx b/src/components/GB_Hero/index.tsx
similarity index 100%
rename from app/components/Hero/index.tsx
rename to src/components/GB_Hero/index.tsx
diff --git a/app/components/Hero/package.json b/src/components/GB_Hero/package.json
similarity index 100%
rename from app/components/Hero/package.json
rename to src/components/GB_Hero/package.json
diff --git a/app/components/Hero/styles.module.css b/src/components/GB_Hero/styles.module.css
similarity index 100%
rename from app/components/Hero/styles.module.css
rename to src/components/GB_Hero/styles.module.css
diff --git a/app/components/Info/About/index.tsx b/src/components/GB_Info/About/index.tsx
similarity index 100%
rename from app/components/Info/About/index.tsx
rename to src/components/GB_Info/About/index.tsx
diff --git a/app/components/Info/About/package.json b/src/components/GB_Info/About/package.json
similarity index 100%
rename from app/components/Info/About/package.json
rename to src/components/GB_Info/About/package.json
diff --git a/app/components/Info/About/styles.module.css b/src/components/GB_Info/About/styles.module.css
similarity index 100%
rename from app/components/Info/About/styles.module.css
rename to src/components/GB_Info/About/styles.module.css
diff --git a/app/components/Info/ContactUs/index.tsx b/src/components/GB_Info/ContactUs/index.tsx
similarity index 95%
rename from app/components/Info/ContactUs/index.tsx
rename to src/components/GB_Info/ContactUs/index.tsx
index 25a75b0..948387a 100644
--- a/app/components/Info/ContactUs/index.tsx
+++ b/src/components/GB_Info/ContactUs/index.tsx
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
import TypoGraphy from '@mui/material/Typography';
import PropTypes from 'prop-types' //ES6
import styles from './styles.module.css';
-import constants from '@/app/lib/constants'
+import constants from '@/src/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
diff --git a/app/components/Info/ContactUs/package.json b/src/components/GB_Info/ContactUs/package.json
similarity index 100%
rename from app/components/Info/ContactUs/package.json
rename to src/components/GB_Info/ContactUs/package.json
diff --git a/app/components/Info/ContactUs/styles.module.css b/src/components/GB_Info/ContactUs/styles.module.css
similarity index 100%
rename from app/components/Info/ContactUs/styles.module.css
rename to src/components/GB_Info/ContactUs/styles.module.css
diff --git a/app/components/Info/Copyright/index.tsx b/src/components/GB_Info/Copyright/index.tsx
similarity index 85%
rename from app/components/Info/Copyright/index.tsx
rename to src/components/GB_Info/Copyright/index.tsx
index 5ae1961..46f411d 100644
--- a/app/components/Info/Copyright/index.tsx
+++ b/src/components/GB_Info/Copyright/index.tsx
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
-import { COMPANY_NAME, COMPANY_URL } from '@/app/lib/constants';
+import { COMPANY_NAME, COMPANY_URL } from '@/src/lib/constants';
import Typography from '@mui/material/Typography';
import MuiLink from '@mui/material/Link';
import styles from './styles.module.css'
@@ -10,16 +10,15 @@ import styled from '@emotion/styled'
export default class Copyright extends Component {
render() {
return (
-
+ (
© {new Date().getFullYear()} {' '}
-
{COMPANY_NAME}
+ {COMPANY_NAME}
{' '}
All Rights Reserved.
-
-
- )
+ )
+ );
}
}
diff --git a/app/components/Info/Copyright/package.json b/src/components/GB_Info/Copyright/package.json
similarity index 100%
rename from app/components/Info/Copyright/package.json
rename to src/components/GB_Info/Copyright/package.json
diff --git a/app/components/Info/Copyright/styles.module.css b/src/components/GB_Info/Copyright/styles.module.css
similarity index 100%
rename from app/components/Info/Copyright/styles.module.css
rename to src/components/GB_Info/Copyright/styles.module.css
diff --git a/app/components/Info/Disclosure/index.tsx b/src/components/GB_Info/Disclosure/index.tsx
similarity index 96%
rename from app/components/Info/Disclosure/index.tsx
rename to src/components/GB_Info/Disclosure/index.tsx
index fa665cf..78e2aa8 100644
--- a/app/components/Info/Disclosure/index.tsx
+++ b/src/components/GB_Info/Disclosure/index.tsx
@@ -2,8 +2,8 @@ import React, { Component } from 'react'
import TypoGraphy from '@mui/material/Typography';
import PropTypes from 'prop-types' //ES6
import styles from './styles.module.css';
-import constants from '@/app/lib/constants'
-import {SITE_CONT_TYPE} from '@/app/lib/constants'
+import constants from '@/src/lib/constants'
+import {SITE_CONT_TYPE} from '@/src/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function Disclosure(props) {
diff --git a/app/components/Info/Disclosure/package.json b/src/components/GB_Info/Disclosure/package.json
similarity index 100%
rename from app/components/Info/Disclosure/package.json
rename to src/components/GB_Info/Disclosure/package.json
diff --git a/app/components/Info/Disclosure/styles.module.css b/src/components/GB_Info/Disclosure/styles.module.css
similarity index 100%
rename from app/components/Info/Disclosure/styles.module.css
rename to src/components/GB_Info/Disclosure/styles.module.css
diff --git a/app/components/Info/Faq/index.tsx b/src/components/GB_Info/Faq/index.tsx
similarity index 100%
rename from app/components/Info/Faq/index.tsx
rename to src/components/GB_Info/Faq/index.tsx
diff --git a/app/components/Info/Faq/package.json b/src/components/GB_Info/Faq/package.json
similarity index 100%
rename from app/components/Info/Faq/package.json
rename to src/components/GB_Info/Faq/package.json
diff --git a/app/components/Info/Faq/styles.module.css b/src/components/GB_Info/Faq/styles.module.css
similarity index 100%
rename from app/components/Info/Faq/styles.module.css
rename to src/components/GB_Info/Faq/styles.module.css
diff --git a/app/components/Info/PIP/index.tsx b/src/components/GB_Info/PIP/index.tsx
similarity index 96%
rename from app/components/Info/PIP/index.tsx
rename to src/components/GB_Info/PIP/index.tsx
index 2ed2a0b..6f17b00 100644
--- a/app/components/Info/PIP/index.tsx
+++ b/src/components/GB_Info/PIP/index.tsx
@@ -3,7 +3,7 @@ import Head from 'next/head';
import TypoGraphy from '@mui/material/Typography';
import PropTypes from 'prop-types' //ES6
import styles from './styles.module.css';
-import constants from '@/app/lib/constants'
+import constants from '@/src/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function PIP(props) {
diff --git a/app/components/Info/PIP/package.json b/src/components/GB_Info/PIP/package.json
similarity index 100%
rename from app/components/Info/PIP/package.json
rename to src/components/GB_Info/PIP/package.json
diff --git a/app/components/Info/PIP/styles.module.css b/src/components/GB_Info/PIP/styles.module.css
similarity index 100%
rename from app/components/Info/PIP/styles.module.css
rename to src/components/GB_Info/PIP/styles.module.css
diff --git a/app/components/Info/PrivacyPolicy/index.tsx b/src/components/GB_Info/PrivacyPolicy/index.tsx
similarity index 96%
rename from app/components/Info/PrivacyPolicy/index.tsx
rename to src/components/GB_Info/PrivacyPolicy/index.tsx
index de78f16..2f5a086 100644
--- a/app/components/Info/PrivacyPolicy/index.tsx
+++ b/src/components/GB_Info/PrivacyPolicy/index.tsx
@@ -3,7 +3,7 @@ import TypoGraphy from '@mui/material/Typography';
import Head from 'next/head';
import PropTypes from 'prop-types' //ES6
import styles from './styles.module.css';
-import constants from '@/app/lib/constants'
+import constants from '@/src/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function PrivacyPolicy(props) {
diff --git a/app/components/Info/PrivacyPolicy/package.json b/src/components/GB_Info/PrivacyPolicy/package.json
similarity index 100%
rename from app/components/Info/PrivacyPolicy/package.json
rename to src/components/GB_Info/PrivacyPolicy/package.json
diff --git a/app/components/Info/PrivacyPolicy/styles.module.css b/src/components/GB_Info/PrivacyPolicy/styles.module.css
similarity index 100%
rename from app/components/Info/PrivacyPolicy/styles.module.css
rename to src/components/GB_Info/PrivacyPolicy/styles.module.css
diff --git a/app/components/Info/TermsOfService/index.tsx b/src/components/GB_Info/TermsOfService/index.tsx
similarity index 96%
rename from app/components/Info/TermsOfService/index.tsx
rename to src/components/GB_Info/TermsOfService/index.tsx
index 68b3951..93d137f 100644
--- a/app/components/Info/TermsOfService/index.tsx
+++ b/src/components/GB_Info/TermsOfService/index.tsx
@@ -2,7 +2,7 @@ import React, { Component } from 'react'
import Head from 'next/head';
import TypoGraphy from '@mui/material/Typography';
import PropTypes from 'prop-types' //ES6
-import constants from '@/app/lib/constants'
+import constants from '@/src/lib/constants'
import { useQuery, useMutation, gql } from "@apollo/client";
export default function TermsOfService(props) {
diff --git a/app/components/Info/TermsOfService/package.json b/src/components/GB_Info/TermsOfService/package.json
similarity index 100%
rename from app/components/Info/TermsOfService/package.json
rename to src/components/GB_Info/TermsOfService/package.json
diff --git a/app/components/Info/TermsOfService/styles.module.css b/src/components/GB_Info/TermsOfService/styles.module.css
similarity index 100%
rename from app/components/Info/TermsOfService/styles.module.css
rename to src/components/GB_Info/TermsOfService/styles.module.css
diff --git a/app/components/SignIn/index.tsx b/src/components/GB_SignIn/index.tsx
similarity index 100%
rename from app/components/SignIn/index.tsx
rename to src/components/GB_SignIn/index.tsx
diff --git a/app/components/SignIn/package.json b/src/components/GB_SignIn/package.json
similarity index 100%
rename from app/components/SignIn/package.json
rename to src/components/GB_SignIn/package.json
diff --git a/app/components/SignIn/styles.module.css b/src/components/GB_SignIn/styles.module.css
similarity index 100%
rename from app/components/SignIn/styles.module.css
rename to src/components/GB_SignIn/styles.module.css
diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx
new file mode 100644
index 0000000..015a718
--- /dev/null
+++ b/src/components/Header/Header.tsx
@@ -0,0 +1,39 @@
+import { Box, Flex, Link, Heading } from "@chakra-ui/react";
+import NextLink from "next/link";
+
+const Header: React.FC = () => {
+ return (
+ <>
+
+
+
+
+
+ Ballistic Builder
+
+
+
+
+
+
+ Builder
+
+
+
+
+ Products
+
+
+
+
+ Sign In
+
+
+
+
+
+ >
+ );
+};
+
+export default Header;
\ No newline at end of file
diff --git a/src/components/Header/index.tsx b/src/components/Header/index.tsx
new file mode 100644
index 0000000..737b26d
--- /dev/null
+++ b/src/components/Header/index.tsx
@@ -0,0 +1,23 @@
+import Link from "next/link";
+
+export default function Header() {
+ {/* Header Section */ }
+ return (
+ (
+
+
+
Ballistic Builder
+
+
+ Features
+ Builder
+ Products
+ Contact
+
+
+
+
+
+
+ )
+)}
\ No newline at end of file
diff --git a/src/components/Hero/index.tsx b/src/components/Hero/index.tsx
new file mode 100644
index 0000000..425361f
--- /dev/null
+++ b/src/components/Hero/index.tsx
@@ -0,0 +1,24 @@
+import Link from "next/link";
+
+export default function Hero() {
+ {/* Hero Section */ }
+ return (
+
+
+
+
Build Your Dream Firearm
+
+ Customize every component of your firearm with ease and precision.
+
+
+
+ Get Started
+
+
+
+
+
+ )
+}
\ No newline at end of file
diff --git a/src/components/HomeContent/index.tsx b/src/components/HomeContent/index.tsx
new file mode 100644
index 0000000..100a0a9
--- /dev/null
+++ b/src/components/HomeContent/index.tsx
@@ -0,0 +1,24 @@
+import Link from "next/link";
+import Header from "../Header";
+import Hero from "../Hero";
+import FeaturesSection from "../FeaturesSection";
+import About from "../About";
+import Contact from "../Contact";
+import Footer from "../Footer ";
+
+export default function HomeContent() {
+
+ return (
+ (
+ <>
+
+
+
+
+
+
+ >
+
+ )
+ )
+}
\ No newline at end of file
diff --git a/src/components/ui/accordion.tsx b/src/components/ui/accordion.tsx
new file mode 100644
index 0000000..d8763da
--- /dev/null
+++ b/src/components/ui/accordion.tsx
@@ -0,0 +1,47 @@
+import { Accordion, HStack } from "@chakra-ui/react"
+import * as React from "react"
+import { LuChevronDown } from "react-icons/lu"
+
+interface AccordionItemTriggerProps extends Accordion.ItemTriggerProps {
+ indicatorPlacement?: "start" | "end"
+}
+
+export const AccordionItemTrigger = React.forwardRef<
+ HTMLButtonElement,
+ AccordionItemTriggerProps
+>(function AccordionItemTrigger(props, ref) {
+ const { children, indicatorPlacement = "end", ...rest } = props
+ return (
+
+ {indicatorPlacement === "start" && (
+
+
+
+ )}
+
+ {children}
+
+ {indicatorPlacement === "end" && (
+
+
+
+ )}
+
+ )
+})
+
+interface AccordionItemContentProps extends Accordion.ItemContentProps {}
+
+export const AccordionItemContent = React.forwardRef<
+ HTMLDivElement,
+ AccordionItemContentProps
+>(function AccordionItemContent(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const AccordionRoot = Accordion.Root
+export const AccordionItem = Accordion.Item
diff --git a/src/components/ui/action-bar.tsx b/src/components/ui/action-bar.tsx
new file mode 100644
index 0000000..98f798a
--- /dev/null
+++ b/src/components/ui/action-bar.tsx
@@ -0,0 +1,40 @@
+import { ActionBar, Portal } from "@chakra-ui/react"
+import { CloseButton } from "./close-button"
+import * as React from "react"
+
+interface ActionBarContentProps extends ActionBar.ContentProps {
+ portalled?: boolean
+ portalRef?: React.RefObject
+}
+
+export const ActionBarContent = React.forwardRef<
+ HTMLDivElement,
+ ActionBarContentProps
+>(function ActionBarContent(props, ref) {
+ const { children, portalled = true, portalRef, ...rest } = props
+
+ return (
+
+
+
+ {children}
+
+
+
+ )
+})
+
+export const ActionBarCloseTrigger = React.forwardRef<
+ HTMLButtonElement,
+ ActionBar.CloseTriggerProps
+>(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.tsx b/src/components/ui/alert.tsx
new file mode 100644
index 0000000..5c1cd6f
--- /dev/null
+++ b/src/components/ui/alert.tsx
@@ -0,0 +1,51 @@
+import { Alert as ChakraAlert } from "@chakra-ui/react"
+import { CloseButton } from "./close-button"
+import * as React from "react"
+
+export interface AlertProps extends Omit {
+ startElement?: React.ReactNode
+ endElement?: React.ReactNode
+ title?: React.ReactNode
+ icon?: React.ReactElement
+ closable?: boolean
+ onClose?: () => void
+}
+
+export const Alert = React.forwardRef(
+ function Alert(props, ref) {
+ const {
+ title,
+ children,
+ icon,
+ closable,
+ onClose,
+ startElement,
+ endElement,
+ ...rest
+ } = props
+ return (
+
+ {startElement || {icon} }
+ {children ? (
+
+ {title}
+ {children}
+
+ ) : (
+ {title}
+ )}
+ {endElement}
+ {closable && (
+
+ )}
+
+ )
+ },
+)
diff --git a/src/components/ui/avatar.tsx b/src/components/ui/avatar.tsx
new file mode 100644
index 0000000..cd84664
--- /dev/null
+++ b/src/components/ui/avatar.tsx
@@ -0,0 +1,74 @@
+"use client"
+
+import type { GroupProps, SlotRecipeProps } from "@chakra-ui/react"
+import { Avatar as ChakraAvatar, Group } from "@chakra-ui/react"
+import * as React from "react"
+
+type ImageProps = React.ImgHTMLAttributes
+
+export interface AvatarProps extends ChakraAvatar.RootProps {
+ name?: string
+ src?: string
+ srcSet?: string
+ loading?: ImageProps["loading"]
+ icon?: React.ReactElement
+ fallback?: React.ReactNode
+}
+
+export const Avatar = React.forwardRef(
+ function Avatar(props, ref) {
+ const { name, src, srcSet, loading, icon, fallback, children, ...rest } =
+ props
+ return (
+
+
+ {fallback}
+
+
+ {children}
+
+ )
+ },
+)
+
+interface AvatarFallbackProps extends ChakraAvatar.FallbackProps {
+ name?: string
+ icon?: React.ReactElement
+}
+
+const AvatarFallback = React.forwardRef(
+ function AvatarFallback(props, ref) {
+ const { name, icon, children, ...rest } = props
+ return (
+
+ {children}
+ {name != null && children == null && <>{getInitials(name)}>}
+ {name == null && children == null && (
+ {icon}
+ )}
+
+ )
+ },
+)
+
+function getInitials(name: string) {
+ const names = name.trim().split(" ")
+ const firstName = names[0] != null ? names[0] : ""
+ const lastName = names.length > 1 ? names[names.length - 1] : ""
+ return firstName && lastName
+ ? `${firstName.charAt(0)}${lastName.charAt(0)}`
+ : firstName.charAt(0)
+}
+
+interface AvatarGroupProps extends GroupProps, SlotRecipeProps<"avatar"> {}
+
+export const AvatarGroup = React.forwardRef(
+ function AvatarGroup(props, ref) {
+ const { size, variant, borderless, ...rest } = props
+ return (
+
+
+
+ )
+ },
+)
diff --git a/src/components/ui/blockquote.tsx b/src/components/ui/blockquote.tsx
new file mode 100644
index 0000000..166446b
--- /dev/null
+++ b/src/components/ui/blockquote.tsx
@@ -0,0 +1,31 @@
+import { Blockquote as ChakraBlockquote } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface BlockquoteProps extends ChakraBlockquote.RootProps {
+ cite?: React.ReactNode
+ citeUrl?: string
+ icon?: React.ReactNode
+ showDash?: boolean
+}
+
+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.tsx b/src/components/ui/breadcrumb.tsx
new file mode 100644
index 0000000..960e769
--- /dev/null
+++ b/src/components/ui/breadcrumb.tsx
@@ -0,0 +1,40 @@
+import { Breadcrumb, type SystemStyleObject } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface BreadcrumbRootProps extends Breadcrumb.RootProps {
+ separator?: React.ReactNode
+ separatorGap?: SystemStyleObject["gap"]
+}
+
+export const BreadcrumbRoot = React.forwardRef<
+ HTMLDivElement,
+ BreadcrumbRootProps
+>(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/button.tsx b/src/components/ui/button.tsx
new file mode 100644
index 0000000..21d5f4b
--- /dev/null
+++ b/src/components/ui/button.tsx
@@ -0,0 +1,40 @@
+import type { ButtonProps as ChakraButtonProps } from "@chakra-ui/react"
+import {
+ AbsoluteCenter,
+ Button as ChakraButton,
+ Span,
+ Spinner,
+} from "@chakra-ui/react"
+import * as React from "react"
+
+interface ButtonLoadingProps {
+ loading?: boolean
+ loadingText?: React.ReactNode
+}
+
+export interface ButtonProps extends ChakraButtonProps, ButtonLoadingProps {}
+
+export const Button = React.forwardRef(
+ function Button(props, ref) {
+ const { loading, disabled, loadingText, children, ...rest } = props
+ return (
+
+ {loading && !loadingText ? (
+ <>
+
+
+
+ {children}
+ >
+ ) : loading && loadingText ? (
+ <>
+
+ {loadingText}
+ >
+ ) : (
+ children
+ )}
+
+ )
+ },
+)
diff --git a/src/components/ui/checkbox-card.tsx b/src/components/ui/checkbox-card.tsx
new file mode 100644
index 0000000..063925b
--- /dev/null
+++ b/src/components/ui/checkbox-card.tsx
@@ -0,0 +1,58 @@
+import { CheckboxCard as ChakraCheckboxCard } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface CheckboxCardProps extends ChakraCheckboxCard.RootProps {
+ icon?: React.ReactElement
+ label?: React.ReactNode
+ description?: React.ReactNode
+ addon?: React.ReactNode
+ indicator?: React.ReactNode | null
+ indicatorPlacement?: "start" | "end" | "inside"
+ inputProps?: React.InputHTMLAttributes
+}
+
+export const CheckboxCard = React.forwardRef<
+ HTMLInputElement,
+ CheckboxCardProps
+>(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.tsx b/src/components/ui/checkbox.tsx
new file mode 100644
index 0000000..2a27c2f
--- /dev/null
+++ b/src/components/ui/checkbox.tsx
@@ -0,0 +1,25 @@
+import { Checkbox as ChakraCheckbox } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface CheckboxProps extends ChakraCheckbox.RootProps {
+ icon?: React.ReactNode
+ inputProps?: React.InputHTMLAttributes
+ rootRef?: React.Ref
+}
+
+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.tsx b/src/components/ui/clipboard.tsx
new file mode 100644
index 0000000..958cb59
--- /dev/null
+++ b/src/components/ui/clipboard.tsx
@@ -0,0 +1,108 @@
+import type { ButtonProps, InputProps } from "@chakra-ui/react"
+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<
+ HTMLDivElement,
+ ChakraClipboard.IndicatorProps
+>(function ClipboardIcon(props, ref) {
+ return (
+ } {...props} ref={ref}>
+
+
+ )
+})
+
+const ClipboardCopyText = React.forwardRef<
+ HTMLDivElement,
+ ChakraClipboard.IndicatorProps
+>(function ClipboardCopyText(props, ref) {
+ return (
+
+ Copy
+
+ )
+})
+
+export const ClipboardLabel = React.forwardRef<
+ HTMLLabelElement,
+ ChakraClipboard.LabelProps
+>(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<
+ HTMLButtonElement,
+ ButtonProps
+>(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.tsx b/src/components/ui/close-button.tsx
new file mode 100644
index 0000000..8a99007
--- /dev/null
+++ b/src/components/ui/close-button.tsx
@@ -0,0 +1,17 @@
+import type { ButtonProps as ChakraCloseButtonProps } from "@chakra-ui/react"
+import { IconButton as ChakraIconButton } from "@chakra-ui/react"
+import * as React from "react"
+import { LuX } from "react-icons/lu"
+
+export interface CloseButtonProps extends ChakraCloseButtonProps {}
+
+export const CloseButton = React.forwardRef<
+ HTMLButtonElement,
+ CloseButtonProps
+>(function CloseButton(props, ref) {
+ return (
+
+ {props.children ?? }
+
+ )
+})
diff --git a/src/components/ui/color-mode.tsx b/src/components/ui/color-mode.tsx
new file mode 100644
index 0000000..a34b968
--- /dev/null
+++ b/src/components/ui/color-mode.tsx
@@ -0,0 +1,67 @@
+"use client"
+
+import type { IconButtonProps } from "@chakra-ui/react"
+import { ClientOnly, IconButton, Skeleton } from "@chakra-ui/react"
+import { ThemeProvider, useTheme } from "next-themes"
+import type { ThemeProviderProps } from "next-themes"
+import * as React from "react"
+import { LuMoon, LuSun } from "react-icons/lu"
+
+export interface ColorModeProviderProps extends ThemeProviderProps {}
+
+export function ColorModeProvider(props: ColorModeProviderProps) {
+ return (
+
+ )
+}
+
+export function useColorMode() {
+ const { resolvedTheme, setTheme } = useTheme()
+ const toggleColorMode = () => {
+ setTheme(resolvedTheme === "light" ? "dark" : "light")
+ }
+ return {
+ colorMode: resolvedTheme,
+ setColorMode: setTheme,
+ toggleColorMode,
+ }
+}
+
+export function useColorModeValue(light: T, dark: T) {
+ const { colorMode } = useColorMode()
+ return colorMode === "light" ? light : dark
+}
+
+export function ColorModeIcon() {
+ const { colorMode } = useColorMode()
+ return colorMode === "light" ? :
+}
+
+interface ColorModeButtonProps extends Omit {}
+
+export const ColorModeButton = React.forwardRef<
+ HTMLButtonElement,
+ ColorModeButtonProps
+>(function ColorModeButton(props, ref) {
+ const { toggleColorMode } = useColorMode()
+ return (
+ }>
+
+
+
+
+ )
+})
diff --git a/src/components/ui/data-list.tsx b/src/components/ui/data-list.tsx
new file mode 100644
index 0000000..ef7cae8
--- /dev/null
+++ b/src/components/ui/data-list.tsx
@@ -0,0 +1,30 @@
+import { DataList as ChakraDataList } from "@chakra-ui/react"
+import { InfoTip } from "./toggle-tip"
+import * as React from "react"
+
+export const DataListRoot = ChakraDataList.Root
+
+interface ItemProps extends ChakraDataList.ItemProps {
+ label: React.ReactNode
+ value: React.ReactNode
+ info?: React.ReactNode
+ grow?: boolean
+}
+
+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.tsx b/src/components/ui/dialog.tsx
new file mode 100644
index 0000000..89d68a5
--- /dev/null
+++ b/src/components/ui/dialog.tsx
@@ -0,0 +1,62 @@
+import { Dialog as ChakraDialog, Portal } from "@chakra-ui/react"
+import { CloseButton } from "./close-button"
+import * as React from "react"
+
+interface DialogContentProps extends ChakraDialog.ContentProps {
+ portalled?: boolean
+ portalRef?: React.RefObject
+ backdrop?: boolean
+}
+
+export const DialogContent = React.forwardRef<
+ HTMLDivElement,
+ DialogContentProps
+>(function DialogContent(props, ref) {
+ const {
+ children,
+ portalled = true,
+ portalRef,
+ backdrop = true,
+ ...rest
+ } = props
+
+ return (
+
+ {backdrop && }
+
+
+ {children}
+
+
+
+ )
+})
+
+export const DialogCloseTrigger = React.forwardRef<
+ HTMLButtonElement,
+ ChakraDialog.CloseTriggerProps
+>(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.tsx b/src/components/ui/drawer.tsx
new file mode 100644
index 0000000..ccb96c8
--- /dev/null
+++ b/src/components/ui/drawer.tsx
@@ -0,0 +1,52 @@
+import { Drawer as ChakraDrawer, Portal } from "@chakra-ui/react"
+import { CloseButton } from "./close-button"
+import * as React from "react"
+
+interface DrawerContentProps extends ChakraDrawer.ContentProps {
+ portalled?: boolean
+ portalRef?: React.RefObject
+ offset?: ChakraDrawer.ContentProps["padding"]
+}
+
+export const DrawerContent = React.forwardRef<
+ HTMLDivElement,
+ DrawerContentProps
+>(function DrawerContent(props, ref) {
+ const { children, portalled = true, portalRef, offset, ...rest } = props
+ return (
+
+
+
+ {children}
+
+
+
+ )
+})
+
+export const DrawerCloseTrigger = React.forwardRef<
+ HTMLButtonElement,
+ ChakraDrawer.CloseTriggerProps
+>(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.tsx b/src/components/ui/empty-state.tsx
new file mode 100644
index 0000000..d643e53
--- /dev/null
+++ b/src/components/ui/empty-state.tsx
@@ -0,0 +1,34 @@
+import { EmptyState as ChakraEmptyState, VStack } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface EmptyStateProps extends ChakraEmptyState.RootProps {
+ title: string
+ description?: string
+ icon?: React.ReactNode
+}
+
+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.tsx b/src/components/ui/field.tsx
new file mode 100644
index 0000000..dd3b66f
--- /dev/null
+++ b/src/components/ui/field.tsx
@@ -0,0 +1,33 @@
+import { Field as ChakraField } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface FieldProps extends Omit {
+ label?: React.ReactNode
+ helperText?: React.ReactNode
+ errorText?: React.ReactNode
+ optionalText?: React.ReactNode
+}
+
+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-button.tsx b/src/components/ui/file-button.tsx
new file mode 100644
index 0000000..29e5220
--- /dev/null
+++ b/src/components/ui/file-button.tsx
@@ -0,0 +1,170 @@
+"use client"
+
+import type { ButtonProps, RecipeProps } from "@chakra-ui/react"
+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 interface FileUploadRootProps extends ChakraFileUpload.RootProps {
+ inputProps?: React.InputHTMLAttributes
+}
+
+export const FileUploadRoot = React.forwardRef<
+ HTMLInputElement,
+ FileUploadRootProps
+>(function FileUploadRoot(props, ref) {
+ const { children, inputProps, ...rest } = props
+ return (
+
+
+ {children}
+
+ )
+})
+
+export interface FileUploadDropzoneProps
+ extends ChakraFileUpload.DropzoneProps {
+ label: React.ReactNode
+ description?: React.ReactNode
+}
+
+export const FileUploadDropzone = React.forwardRef<
+ HTMLInputElement,
+ FileUploadDropzoneProps
+>(function FileUploadDropzone(props, ref) {
+ const { children, label, description, ...rest } = props
+ return (
+
+
+
+
+
+ {label}
+ {description && {description} }
+
+ {children}
+
+ )
+})
+
+interface VisibilityProps {
+ showSize?: boolean
+ clearable?: boolean
+}
+
+interface FileUploadItemProps extends VisibilityProps {
+ file: File
+}
+
+const FileUploadItem = React.forwardRef(
+ function FileUploadItem(props, ref) {
+ const { file, showSize, clearable } = props
+ return (
+
+
+
+
+
+
+
+ {showSize ? (
+
+
+
+
+ ) : (
+
+ )}
+
+ {clearable && (
+
+
+
+
+
+ )}
+
+ )
+ },
+)
+
+interface FileUploadListProps
+ extends VisibilityProps,
+ ChakraFileUpload.ItemGroupProps {
+ files?: File[]
+}
+
+export const FileUploadList = React.forwardRef<
+ HTMLUListElement,
+ FileUploadListProps
+>(function FileUploadList(props, ref) {
+ const { showSize, clearable, files, ...rest } = props
+
+ const fileUpload = useFileUploadContext()
+ const acceptedFiles = files ?? fileUpload.acceptedFiles
+
+ if (acceptedFiles.length === 0) return null
+
+ return (
+
+ {acceptedFiles.map((file) => (
+
+ ))}
+
+ )
+})
+
+type Assign = Omit & U
+
+interface FileInputProps extends Assign> {
+ placeholder?: React.ReactNode
+}
+
+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 (
+
+
+
+ {({ acceptedFiles }) => {
+ if (acceptedFiles.length === 1) {
+ return {acceptedFiles[0].name}
+ }
+ if (acceptedFiles.length > 1) {
+ return {acceptedFiles.length} files
+ }
+ return {placeholder}
+ }}
+
+
+
+ )
+ },
+)
+
+export const FileUploadLabel = ChakraFileUpload.Label
+export const FileUploadClearTrigger = ChakraFileUpload.ClearTrigger
+export const FileUploadTrigger = ChakraFileUpload.Trigger
diff --git a/src/components/ui/hover-card.tsx b/src/components/ui/hover-card.tsx
new file mode 100644
index 0000000..36299c1
--- /dev/null
+++ b/src/components/ui/hover-card.tsx
@@ -0,0 +1,36 @@
+import { HoverCard, Portal } from "@chakra-ui/react"
+import * as React from "react"
+
+interface HoverCardContentProps extends HoverCard.ContentProps {
+ portalled?: boolean
+ portalRef?: React.RefObject
+}
+
+export const HoverCardContent = React.forwardRef<
+ HTMLDivElement,
+ HoverCardContentProps
+>(function HoverCardContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+
+ return (
+
+
+
+
+
+ )
+})
+
+export const HoverCardArrow = React.forwardRef<
+ HTMLDivElement,
+ HoverCard.ArrowProps
+>(function HoverCardArrow(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const HoverCardRoot = HoverCard.Root
+export const HoverCardTrigger = HoverCard.Trigger
diff --git a/src/components/ui/input-group.tsx b/src/components/ui/input-group.tsx
new file mode 100644
index 0000000..1124a61
--- /dev/null
+++ b/src/components/ui/input-group.tsx
@@ -0,0 +1,50 @@
+import type { BoxProps, InputElementProps } from "@chakra-ui/react"
+import { Group, InputElement } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface InputGroupProps extends BoxProps {
+ startElementProps?: InputElementProps
+ endElementProps?: InputElementProps
+ startElement?: React.ReactNode
+ endElement?: React.ReactNode
+ children: React.ReactElement
+ startOffset?: InputElementProps["paddingStart"]
+ endOffset?: InputElementProps["paddingEnd"]
+}
+
+export const InputGroup = React.forwardRef(
+ function InputGroup(props, ref) {
+ const {
+ startElement,
+ startElementProps,
+ endElement,
+ endElementProps,
+ children,
+ startOffset = "6px",
+ endOffset = "6px",
+ ...rest
+ } = props
+
+ return (
+
+ {startElement && (
+
+ {startElement}
+
+ )}
+ {React.cloneElement(children, {
+ ...(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.tsx b/src/components/ui/link-button.tsx
new file mode 100644
index 0000000..defa1c3
--- /dev/null
+++ b/src/components/ui/link-button.tsx
@@ -0,0 +1,12 @@
+"use client"
+
+import type { HTMLChakraProps, RecipeProps } from "@chakra-ui/react"
+import { createRecipeContext } from "@chakra-ui/react"
+
+export interface LinkButtonProps
+ extends HTMLChakraProps<"a", RecipeProps<"button">> {}
+
+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.tsx b/src/components/ui/menu.tsx
new file mode 100644
index 0000000..763005b
--- /dev/null
+++ b/src/components/ui/menu.tsx
@@ -0,0 +1,110 @@
+"use client"
+
+import { AbsoluteCenter, Menu as ChakraMenu, Portal } from "@chakra-ui/react"
+import * as React from "react"
+import { LuCheck, LuChevronRight } from "react-icons/lu"
+
+interface MenuContentProps extends ChakraMenu.ContentProps {
+ portalled?: boolean
+ portalRef?: React.RefObject
+}
+
+export const MenuContent = React.forwardRef(
+ function MenuContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+ return (
+
+
+
+
+
+ )
+ },
+)
+
+export const MenuArrow = React.forwardRef<
+ HTMLDivElement,
+ ChakraMenu.ArrowProps
+>(function MenuArrow(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const MenuCheckboxItem = React.forwardRef<
+ HTMLDivElement,
+ ChakraMenu.CheckboxItemProps
+>(function MenuCheckboxItem(props, ref) {
+ return (
+
+
+
+
+ {props.children}
+
+ )
+})
+
+export const MenuRadioItem = React.forwardRef<
+ HTMLDivElement,
+ ChakraMenu.RadioItemProps
+>(function MenuRadioItem(props, ref) {
+ const { children, ...rest } = props
+ return (
+
+
+
+
+
+
+ {children}
+
+ )
+})
+
+export const MenuItemGroup = React.forwardRef<
+ HTMLDivElement,
+ ChakraMenu.ItemGroupProps
+>(function MenuItemGroup(props, ref) {
+ const { title, children, ...rest } = props
+ return (
+
+ {title && (
+
+ {title}
+
+ )}
+ {children}
+
+ )
+})
+
+export interface MenuTriggerItemProps extends ChakraMenu.ItemProps {
+ startIcon?: React.ReactNode
+}
+
+export const MenuTriggerItem = React.forwardRef<
+ HTMLDivElement,
+ MenuTriggerItemProps
+>(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.tsx b/src/components/ui/native-select.tsx
new file mode 100644
index 0000000..9e6ebf5
--- /dev/null
+++ b/src/components/ui/native-select.tsx
@@ -0,0 +1,57 @@
+"use client"
+
+import { NativeSelect as Select } from "@chakra-ui/react"
+import * as React from "react"
+
+interface NativeSelectRootProps extends Select.RootProps {
+ icon?: React.ReactNode
+}
+
+export const NativeSelectRoot = React.forwardRef<
+ HTMLDivElement,
+ NativeSelectRootProps
+>(function NativeSelect(props, ref) {
+ const { icon, children, ...rest } = props
+ return (
+
+ {children}
+ {icon}
+
+ )
+})
+
+interface NativeSelectItem {
+ value: string
+ label: string
+ disabled?: boolean
+}
+
+interface NativeSelectField extends Select.FieldProps {
+ items?: Array
+}
+
+export const NativeSelectField = React.forwardRef<
+ HTMLSelectElement,
+ NativeSelectField
+>(function NativeSelectField(props, ref) {
+ const { items: itemsProp, children, ...rest } = props
+
+ const items = React.useMemo(
+ () =>
+ itemsProp?.map((item) =>
+ typeof item === "string" ? { label: item, value: item } : item,
+ ),
+ [itemsProp],
+ )
+
+ return (
+
+ {children}
+ {items?.map((item) => (
+
+ {item.label}
+
+ ))}
+
+ )
+})
diff --git a/src/components/ui/number-input.tsx b/src/components/ui/number-input.tsx
new file mode 100644
index 0000000..7ddab85
--- /dev/null
+++ b/src/components/ui/number-input.tsx
@@ -0,0 +1,24 @@
+import { NumberInput as ChakraNumberInput } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface NumberInputProps extends ChakraNumberInput.RootProps {}
+
+export const NumberInputRoot = React.forwardRef<
+ HTMLDivElement,
+ NumberInputProps
+>(function NumberInput(props, ref) {
+ const { children, ...rest } = props
+ return (
+
+ {children}
+
+
+
+
+
+ )
+})
+
+export const NumberInputField = ChakraNumberInput.Input
+export const NumberInputScruber = ChakraNumberInput.Scrubber
+export const NumberInputLabel = ChakraNumberInput.Label
diff --git a/src/components/ui/pagination.tsx b/src/components/ui/pagination.tsx
new file mode 100644
index 0000000..8201ed8
--- /dev/null
+++ b/src/components/ui/pagination.tsx
@@ -0,0 +1,208 @@
+"use client"
+
+import type { ButtonProps, TextProps } from "@chakra-ui/react"
+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"
+
+interface ButtonVariantMap {
+ current: ButtonProps["variant"]
+ default: ButtonProps["variant"]
+ ellipsis: ButtonProps["variant"]
+}
+
+type PaginationVariant = "outline" | "solid" | "subtle"
+
+interface ButtonVariantContext {
+ size: ButtonProps["size"]
+ variantMap: ButtonVariantMap
+ getHref?: (page: number) => string
+}
+
+const [RootPropsProvider, useRootProps] = createContext({
+ name: "RootPropsProvider",
+})
+
+export interface PaginationRootProps
+ extends Omit {
+ size?: ButtonProps["size"]
+ variant?: PaginationVariant
+ getHref?: (page: number) => string
+}
+
+const variantMap: Record = {
+ 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<
+ HTMLDivElement,
+ PaginationRootProps
+>(function PaginationRoot(props, ref) {
+ const { size = "sm", variant = "outline", getHref, ...rest } = props
+ return (
+
+
+
+ )
+})
+
+export const PaginationEllipsis = React.forwardRef<
+ HTMLDivElement,
+ ChakraPagination.EllipsisProps
+>(function PaginationEllipsis(props, ref) {
+ const { size, variantMap } = useRootProps()
+ return (
+
+
+
+
+
+ )
+})
+
+export const PaginationItem = React.forwardRef<
+ HTMLButtonElement,
+ ChakraPagination.ItemProps
+>(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 (
+
+
+ {props.value}
+
+
+ )
+})
+
+export const PaginationPrevTrigger = React.forwardRef<
+ HTMLButtonElement,
+ ChakraPagination.PrevTriggerProps
+>(function PaginationPrevTrigger(props, ref) {
+ const { size, variantMap, getHref } = useRootProps()
+ const { previousPage } = usePaginationContext()
+
+ if (getHref) {
+ return (
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ )
+})
+
+export const PaginationNextTrigger = React.forwardRef<
+ HTMLButtonElement,
+ ChakraPagination.NextTriggerProps
+>(function PaginationNextTrigger(props, ref) {
+ const { size, variantMap, getHref } = useRootProps()
+ const { nextPage } = usePaginationContext()
+
+ if (getHref) {
+ return (
+
+
+
+ )
+ }
+
+ return (
+
+
+
+
+
+ )
+})
+
+export const PaginationItems = (props: React.HTMLAttributes) => {
+ return (
+
+ {({ pages }) =>
+ pages.map((page, index) => {
+ return page.type === "ellipsis" ? (
+
+ ) : (
+
+ )
+ })
+ }
+
+ )
+}
+
+interface PageTextProps extends TextProps {
+ format?: "short" | "compact" | "long"
+}
+
+export const PaginationPageText = React.forwardRef<
+ HTMLParagraphElement,
+ PageTextProps
+>(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} - ${pageRange.end} of ${count}`
+ }, [format, page, totalPages, pageRange, count])
+
+ return (
+
+ {content}
+
+ )
+})
diff --git a/src/components/ui/password-input.tsx b/src/components/ui/password-input.tsx
new file mode 100644
index 0000000..0c608a9
--- /dev/null
+++ b/src/components/ui/password-input.tsx
@@ -0,0 +1,148 @@
+"use client"
+
+import type {
+ ButtonProps,
+ GroupProps,
+ InputProps,
+ StackProps,
+} from "@chakra-ui/react"
+import {
+ Box,
+ HStack,
+ IconButton,
+ Input,
+ Stack,
+ mergeRefs,
+ useControllableState,
+} from "@chakra-ui/react"
+import * as React from "react"
+import { LuEye, LuEyeOff } from "react-icons/lu"
+import { InputGroup } from "./input-group"
+
+export interface PasswordVisibilityProps {
+ defaultVisible?: boolean
+ visible?: boolean
+ onVisibleChange?: (visible: boolean) => void
+ visibilityIcon?: { on: React.ReactNode; off: React.ReactNode }
+}
+
+export interface PasswordInputProps
+ extends InputProps,
+ PasswordVisibilityProps {
+ rootProps?: GroupProps
+}
+
+export const PasswordInput = React.forwardRef<
+ HTMLInputElement,
+ PasswordInputProps
+>(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 (
+
+ )
+ },
+)
+
+interface PasswordStrengthMeterProps extends StackProps {
+ max?: number
+ value: number
+}
+
+export const PasswordStrengthMeter = React.forwardRef<
+ HTMLDivElement,
+ PasswordStrengthMeterProps
+>(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: number) {
+ 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.tsx b/src/components/ui/pin-input.tsx
new file mode 100644
index 0000000..c969c80
--- /dev/null
+++ b/src/components/ui/pin-input.tsx
@@ -0,0 +1,27 @@
+import { PinInput as ChakraPinInput, Group } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface PinInputProps extends ChakraPinInput.RootProps {
+ rootRef?: React.Ref
+ count?: number
+ inputProps?: React.InputHTMLAttributes
+ attached?: boolean
+}
+
+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.tsx b/src/components/ui/popover.tsx
new file mode 100644
index 0000000..3320659
--- /dev/null
+++ b/src/components/ui/popover.tsx
@@ -0,0 +1,59 @@
+import { Popover as ChakraPopover, Portal } from "@chakra-ui/react"
+import { CloseButton } from "./close-button"
+import * as React from "react"
+
+interface PopoverContentProps extends ChakraPopover.ContentProps {
+ portalled?: boolean
+ portalRef?: React.RefObject
+}
+
+export const PopoverContent = React.forwardRef<
+ HTMLDivElement,
+ PopoverContentProps
+>(function PopoverContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+ return (
+
+
+
+
+
+ )
+})
+
+export const PopoverArrow = React.forwardRef<
+ HTMLDivElement,
+ ChakraPopover.ArrowProps
+>(function PopoverArrow(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const PopoverCloseTrigger = React.forwardRef<
+ HTMLButtonElement,
+ ChakraPopover.CloseTriggerProps
+>(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.tsx b/src/components/ui/progress-circle.tsx
new file mode 100644
index 0000000..2d430cb
--- /dev/null
+++ b/src/components/ui/progress-circle.tsx
@@ -0,0 +1,37 @@
+import type { SystemStyleObject } from "@chakra-ui/react"
+import {
+ AbsoluteCenter,
+ ProgressCircle as ChakraProgressCircle,
+} from "@chakra-ui/react"
+import * as React from "react"
+
+interface ProgressCircleRingProps extends ChakraProgressCircle.CircleProps {
+ trackColor?: SystemStyleObject["stroke"]
+ cap?: SystemStyleObject["strokeLinecap"]
+}
+
+export const ProgressCircleRing = React.forwardRef<
+ SVGSVGElement,
+ ProgressCircleRingProps
+>(function ProgressCircleRing(props, ref) {
+ const { trackColor, cap, color, ...rest } = props
+ return (
+
+
+
+
+ )
+})
+
+export const ProgressCircleValueText = React.forwardRef<
+ HTMLDivElement,
+ ChakraProgressCircle.ValueTextProps
+>(function ProgressCircleValueText(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export const ProgressCircleRoot = ChakraProgressCircle.Root
diff --git a/src/components/ui/progress.tsx b/src/components/ui/progress.tsx
new file mode 100644
index 0000000..9ab22d8
--- /dev/null
+++ b/src/components/ui/progress.tsx
@@ -0,0 +1,34 @@
+import { Progress as ChakraProgress } from "@chakra-ui/react"
+import { InfoTip } from "./toggle-tip"
+import * as React from "react"
+
+export const ProgressBar = React.forwardRef<
+ HTMLDivElement,
+ ChakraProgress.TrackProps
+>(function ProgressBar(props, ref) {
+ return (
+
+
+
+ )
+})
+
+export interface ProgressLabelProps extends ChakraProgress.LabelProps {
+ info?: React.ReactNode
+}
+
+export const ProgressLabel = React.forwardRef<
+ HTMLDivElement,
+ ProgressLabelProps
+>(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.tsx b/src/components/ui/prose.tsx
new file mode 100644
index 0000000..e34a37b
--- /dev/null
+++ b/src/components/ui/prose.tsx
@@ -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/provider.tsx b/src/components/ui/provider.tsx
new file mode 100644
index 0000000..fd0331b
--- /dev/null
+++ b/src/components/ui/provider.tsx
@@ -0,0 +1,15 @@
+"use client"
+
+import { ChakraProvider, defaultSystem } from "@chakra-ui/react"
+import {
+ ColorModeProvider,
+ type ColorModeProviderProps,
+} from "./color-mode"
+
+export function Provider(props: ColorModeProviderProps) {
+ return (
+
+
+
+ )
+}
diff --git a/src/components/ui/radio-card.tsx b/src/components/ui/radio-card.tsx
new file mode 100644
index 0000000..d2fef42
--- /dev/null
+++ b/src/components/ui/radio-card.tsx
@@ -0,0 +1,58 @@
+import { RadioCard } from "@chakra-ui/react"
+import * as React from "react"
+
+interface RadioCardItemProps extends RadioCard.ItemProps {
+ icon?: React.ReactElement
+ label?: React.ReactNode
+ description?: React.ReactNode
+ addon?: React.ReactNode
+ indicator?: React.ReactNode | null
+ indicatorPlacement?: "start" | "end" | "inside"
+ inputProps?: React.InputHTMLAttributes
+}
+
+export const RadioCardItem = React.forwardRef<
+ HTMLInputElement,
+ RadioCardItemProps
+>(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.tsx b/src/components/ui/radio.tsx
new file mode 100644
index 0000000..b3919d0
--- /dev/null
+++ b/src/components/ui/radio.tsx
@@ -0,0 +1,24 @@
+import { RadioGroup as ChakraRadioGroup } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface RadioProps extends ChakraRadioGroup.ItemProps {
+ rootRef?: React.Ref
+ inputProps?: React.InputHTMLAttributes
+}
+
+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.tsx b/src/components/ui/rating.tsx
new file mode 100644
index 0000000..5609f26
--- /dev/null
+++ b/src/components/ui/rating.tsx
@@ -0,0 +1,27 @@
+import { RatingGroup } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface RatingProps extends RatingGroup.RootProps {
+ icon?: React.ReactElement
+ count?: number
+ label?: React.ReactNode
+}
+
+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.tsx b/src/components/ui/segmented-control.tsx
new file mode 100644
index 0000000..aa38adf
--- /dev/null
+++ b/src/components/ui/segmented-control.tsx
@@ -0,0 +1,47 @@
+"use client"
+
+import { For, SegmentGroup } from "@chakra-ui/react"
+import * as React from "react"
+
+interface Item {
+ value: string
+ label: React.ReactNode
+ disabled?: boolean
+}
+
+export interface SegmentedControlProps extends SegmentGroup.RootProps {
+ items: Array
+}
+
+function normalize(items: Array): Item[] {
+ return items.map((item) => {
+ if (typeof item === "string") return { value: item, label: item }
+ return item
+ })
+}
+
+export const SegmentedControl = React.forwardRef<
+ HTMLDivElement,
+ SegmentedControlProps
+>(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.tsx b/src/components/ui/select.tsx
new file mode 100644
index 0000000..99d84e6
--- /dev/null
+++ b/src/components/ui/select.tsx
@@ -0,0 +1,143 @@
+"use client"
+
+import type { CollectionItem } from "@chakra-ui/react"
+import { Select as ChakraSelect, Portal } from "@chakra-ui/react"
+import { CloseButton } from "./close-button"
+import * as React from "react"
+
+interface SelectTriggerProps extends ChakraSelect.ControlProps {
+ clearable?: boolean
+}
+
+export const SelectTrigger = React.forwardRef<
+ HTMLButtonElement,
+ SelectTriggerProps
+>(function SelectTrigger(props, ref) {
+ const { children, clearable, ...rest } = props
+ return (
+
+ {children}
+
+ {clearable && }
+
+
+
+ )
+})
+
+const SelectClearTrigger = React.forwardRef<
+ HTMLButtonElement,
+ ChakraSelect.ClearTriggerProps
+>(function SelectClearTrigger(props, ref) {
+ return (
+
+
+
+ )
+})
+
+interface SelectContentProps extends ChakraSelect.ContentProps {
+ portalled?: boolean
+ portalRef?: React.RefObject
+}
+
+export const SelectContent = React.forwardRef<
+ HTMLDivElement,
+ SelectContentProps
+>(function SelectContent(props, ref) {
+ const { portalled = true, portalRef, ...rest } = props
+ return (
+
+
+
+
+
+ )
+})
+
+export const SelectItem = React.forwardRef<
+ HTMLDivElement,
+ ChakraSelect.ItemProps
+>(function SelectItem(props, ref) {
+ const { item, children, ...rest } = props
+ return (
+
+ {children}
+
+
+ )
+})
+
+interface SelectValueTextProps
+ extends Omit {
+ children?(items: CollectionItem[]): React.ReactNode
+}
+
+export const SelectValueText = React.forwardRef<
+ HTMLSpanElement,
+ SelectValueTextProps
+>(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<
+ HTMLDivElement,
+ ChakraSelect.RootProps
+>(function SelectRoot(props, ref) {
+ return (
+
+ {props.asChild ? (
+ props.children
+ ) : (
+ <>
+
+ {props.children}
+ >
+ )}
+
+ )
+}) as ChakraSelect.RootComponent
+
+interface SelectItemGroupProps extends ChakraSelect.ItemGroupProps {
+ label: React.ReactNode
+}
+
+export const SelectItemGroup = React.forwardRef<
+ HTMLDivElement,
+ SelectItemGroupProps
+>(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.tsx b/src/components/ui/skeleton.tsx
new file mode 100644
index 0000000..4f2c25b
--- /dev/null
+++ b/src/components/ui/skeleton.tsx
@@ -0,0 +1,47 @@
+import type {
+ SkeletonProps as ChakraSkeletonProps,
+ CircleProps,
+} from "@chakra-ui/react"
+import { Skeleton as ChakraSkeleton, Circle, Stack } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface SkeletonCircleProps extends ChakraSkeletonProps {
+ size?: CircleProps["size"]
+}
+
+export const SkeletonCircle = React.forwardRef<
+ HTMLDivElement,
+ SkeletonCircleProps
+>(function SkeletonCircle(props, ref) {
+ const { size, ...rest } = props
+ return (
+
+
+
+ )
+})
+
+export interface SkeletonTextProps extends ChakraSkeletonProps {
+ noOfLines?: number
+}
+
+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.tsx b/src/components/ui/slider.tsx
new file mode 100644
index 0000000..37a6dc9
--- /dev/null
+++ b/src/components/ui/slider.tsx
@@ -0,0 +1,60 @@
+import { Slider as ChakraSlider, HStack } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface SliderProps extends ChakraSlider.RootProps {
+ marks?: Array
+ label?: React.ReactNode
+ showValue?: boolean
+}
+
+export const Slider = React.forwardRef(
+ function Slider(props, ref) {
+ const { marks: marksProp, label, showValue, ...rest } = props
+ const value = props.defaultValue ?? props.value
+
+ const marks = marksProp?.map((mark) => {
+ if (typeof mark === "number") return { value: mark, label: undefined }
+ return mark
+ })
+
+ const hasMarkLabel = !!marks?.some((mark) => mark.label)
+
+ return (
+
+ {label && !showValue && (
+ {label}
+ )}
+ {label && showValue && (
+
+ {label}
+
+
+ )}
+
+
+
+
+ {value?.map((_, index) => (
+
+
+
+ ))}
+
+ {marks?.length && (
+
+ {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.tsx b/src/components/ui/stat.tsx
new file mode 100644
index 0000000..a1e60ad
--- /dev/null
+++ b/src/components/ui/stat.tsx
@@ -0,0 +1,68 @@
+import {
+ Badge,
+ type BadgeProps,
+ Stat as ChakraStat,
+ FormatNumber,
+} from "@chakra-ui/react"
+import { InfoTip } from "./toggle-tip"
+import * as React from "react"
+
+interface StatLabelProps extends ChakraStat.LabelProps {
+ info?: React.ReactNode
+}
+
+export const StatLabel = React.forwardRef(
+ function StatLabel(props, ref) {
+ const { info, children, ...rest } = props
+ return (
+
+ {children}
+ {info && {info} }
+
+ )
+ },
+)
+
+interface StatValueTextProps extends ChakraStat.ValueTextProps {
+ value?: number
+ formatOptions?: Intl.NumberFormatOptions
+}
+
+export const StatValueText = React.forwardRef<
+ HTMLDivElement,
+ StatValueTextProps
+>(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.tsx b/src/components/ui/status.tsx
new file mode 100644
index 0000000..5055463
--- /dev/null
+++ b/src/components/ui/status.tsx
@@ -0,0 +1,29 @@
+import type { ColorPalette } from "@chakra-ui/react"
+import { Status as ChakraStatus } from "@chakra-ui/react"
+import * as React from "react"
+
+type StatusValue = "success" | "error" | "warning" | "info"
+
+export interface StatusProps extends ChakraStatus.RootProps {
+ value?: StatusValue
+}
+
+const statusMap: Record = {
+ 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 = rest.colorPalette ?? statusMap[value]
+ return (
+
+
+ {children}
+
+ )
+ },
+)
diff --git a/src/components/ui/stepper-input.tsx b/src/components/ui/stepper-input.tsx
new file mode 100644
index 0000000..22d158d
--- /dev/null
+++ b/src/components/ui/stepper-input.tsx
@@ -0,0 +1,49 @@
+import { HStack, IconButton, NumberInput } from "@chakra-ui/react"
+import * as React from "react"
+import { LuMinus, LuPlus } from "react-icons/lu"
+
+export interface StepperInputProps extends NumberInput.RootProps {
+ label?: React.ReactNode
+}
+
+export const StepperInput = React.forwardRef(
+ function StepperInput(props, ref) {
+ const { label, ...rest } = props
+ return (
+
+ {label && {label} }
+
+
+
+
+
+
+ )
+ },
+)
+
+const DecrementTrigger = React.forwardRef<
+ HTMLButtonElement,
+ NumberInput.DecrementTriggerProps
+>(function DecrementTrigger(props, ref) {
+ return (
+
+
+
+
+
+ )
+})
+
+const IncrementTrigger = React.forwardRef<
+ HTMLButtonElement,
+ NumberInput.IncrementTriggerProps
+>(function IncrementTrigger(props, ref) {
+ return (
+
+
+
+
+
+ )
+})
diff --git a/src/components/ui/steps.tsx b/src/components/ui/steps.tsx
new file mode 100644
index 0000000..677c4c7
--- /dev/null
+++ b/src/components/ui/steps.tsx
@@ -0,0 +1,82 @@
+import { Box, Steps as ChakraSteps } from "@chakra-ui/react"
+import * as React from "react"
+import { LuCheck } from "react-icons/lu"
+
+interface StepInfoProps {
+ title?: React.ReactNode
+ description?: React.ReactNode
+}
+
+export interface StepsItemProps
+ extends Omit,
+ StepInfoProps {
+ completedIcon?: React.ReactNode
+ icon?: React.ReactNode
+}
+
+export const StepsItem = React.forwardRef(
+ function StepsItem(props, ref) {
+ const { title, description, completedIcon, icon, ...rest } = props
+ return (
+
+
+
+ }
+ incomplete={icon || }
+ />
+
+
+
+
+
+ )
+ },
+)
+
+const StepInfo = (props: StepInfoProps) => {
+ const { title, description } = props
+
+ if (title && description) {
+ return (
+
+ {title}
+ {description}
+
+ )
+ }
+
+ return (
+ <>
+ {title && {title} }
+ {description && (
+ {description}
+ )}
+ >
+ )
+}
+
+interface StepsIndicatorProps {
+ completedIcon: React.ReactNode
+ icon?: React.ReactNode
+}
+
+export const StepsIndicator = React.forwardRef<
+ HTMLDivElement,
+ StepsIndicatorProps
+>(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.tsx b/src/components/ui/switch.tsx
new file mode 100644
index 0000000..a677ca2
--- /dev/null
+++ b/src/components/ui/switch.tsx
@@ -0,0 +1,39 @@
+import { Switch as ChakraSwitch } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface SwitchProps extends ChakraSwitch.RootProps {
+ inputProps?: React.InputHTMLAttributes
+ rootRef?: React.Ref
+ trackLabel?: { on: React.ReactNode; off: React.ReactNode }
+ thumbLabel?: { on: React.ReactNode; off: React.ReactNode }
+}
+
+export const Switch = React.forwardRef(
+ function Switch(props, ref) {
+ const { inputProps, children, rootRef, trackLabel, thumbLabel, ...rest } =
+ props
+
+ return (
+
+
+
+
+ {thumbLabel && (
+
+ {thumbLabel?.on}
+
+ )}
+
+ {trackLabel && (
+
+ {trackLabel.on}
+
+ )}
+
+ {children != null && (
+ {children}
+ )}
+
+ )
+ },
+)
diff --git a/src/components/ui/tag.tsx b/src/components/ui/tag.tsx
new file mode 100644
index 0000000..728250f
--- /dev/null
+++ b/src/components/ui/tag.tsx
@@ -0,0 +1,39 @@
+import { Tag as ChakraTag } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface TagProps extends ChakraTag.RootProps {
+ startElement?: React.ReactNode
+ endElement?: React.ReactNode
+ onClose?: VoidFunction
+ closable?: boolean
+}
+
+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.tsx b/src/components/ui/timeline.tsx
new file mode 100644
index 0000000..678c1f6
--- /dev/null
+++ b/src/components/ui/timeline.tsx
@@ -0,0 +1,21 @@
+import { Timeline as ChakraTimeline } from "@chakra-ui/react"
+import * as React from "react"
+
+export const TimelineConnector = React.forwardRef<
+ HTMLDivElement,
+ ChakraTimeline.IndicatorProps
+>(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/toaster.tsx b/src/components/ui/toaster.tsx
new file mode 100644
index 0000000..df6c2c3
--- /dev/null
+++ b/src/components/ui/toaster.tsx
@@ -0,0 +1,43 @@
+"use client"
+
+import {
+ Toaster as ChakraToaster,
+ Portal,
+ Spinner,
+ Stack,
+ Toast,
+ createToaster,
+} from "@chakra-ui/react"
+
+export const toaster = createToaster({
+ placement: "bottom-end",
+ pauseOnPageIdle: true,
+})
+
+export const Toaster = () => {
+ return (
+
+
+ {(toast) => (
+
+ {toast.type === "loading" ? (
+
+ ) : (
+
+ )}
+
+ {toast.title && {toast.title} }
+ {toast.description && (
+ {toast.description}
+ )}
+
+ {toast.action && (
+ {toast.action.label}
+ )}
+ {toast.meta?.closable && }
+
+ )}
+
+
+ )
+}
diff --git a/src/components/ui/toggle-tip.tsx b/src/components/ui/toggle-tip.tsx
new file mode 100644
index 0000000..7dc7eae
--- /dev/null
+++ b/src/components/ui/toggle-tip.tsx
@@ -0,0 +1,70 @@
+import { Popover as ChakraPopover, IconButton, Portal } from "@chakra-ui/react"
+import * as React from "react"
+import { HiOutlineInformationCircle } from "react-icons/hi"
+
+export interface ToggleTipProps extends ChakraPopover.RootProps {
+ showArrow?: boolean
+ portalled?: boolean
+ portalRef?: React.RefObject
+ content?: React.ReactNode
+}
+
+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<
+ HTMLDivElement,
+ Partial
+>(function InfoTip(props, ref) {
+ const { children, ...rest } = props
+ return (
+
+
+
+
+
+ )
+})
diff --git a/src/components/ui/toggle.tsx b/src/components/ui/toggle.tsx
new file mode 100644
index 0000000..8b95973
--- /dev/null
+++ b/src/components/ui/toggle.tsx
@@ -0,0 +1,57 @@
+"use client"
+
+import type { ButtonProps } from "@chakra-ui/react"
+import {
+ Button,
+ Toggle as ChakraToggle,
+ useToggleContext,
+} from "@chakra-ui/react"
+import * as React from "react"
+
+interface ToggleProps extends ChakraToggle.RootProps {
+ variant?: keyof typeof variantMap
+ size?: ButtonProps["size"]
+}
+
+const variantMap = {
+ solid: { on: "solid", off: "outline" },
+ surface: { on: "surface", off: "outline" },
+ subtle: { on: "subtle", off: "ghost" },
+ ghost: { on: "subtle", off: "ghost" },
+} as const
+
+export const Toggle = React.forwardRef(
+ function Toggle(props, ref) {
+ const { variant = "subtle", size, children, ...rest } = props
+ const variantConfig = variantMap[variant]
+
+ return (
+
+
+ {children}
+
+
+ )
+ },
+)
+
+interface ToggleBaseButtonProps extends Omit {
+ variant: Record<"on" | "off", ButtonProps["variant"]>
+}
+
+const ToggleBaseButton = React.forwardRef<
+ HTMLButtonElement,
+ ToggleBaseButtonProps
+>(function ToggleBaseButton(props, ref) {
+ const toggle = useToggleContext()
+ const { variant, ...rest } = props
+ return (
+
+ )
+})
+
+export const ToggleIndicator = ChakraToggle.Indicator
diff --git a/src/components/ui/tooltip.tsx b/src/components/ui/tooltip.tsx
new file mode 100644
index 0000000..644c37c
--- /dev/null
+++ b/src/components/ui/tooltip.tsx
@@ -0,0 +1,46 @@
+import { Tooltip as ChakraTooltip, Portal } from "@chakra-ui/react"
+import * as React from "react"
+
+export interface TooltipProps extends ChakraTooltip.RootProps {
+ showArrow?: boolean
+ portalled?: boolean
+ portalRef?: React.RefObject
+ content: React.ReactNode
+ contentProps?: ChakraTooltip.ContentProps
+ disabled?: boolean
+}
+
+export const Tooltip = React.forwardRef(
+ function Tooltip(props, ref) {
+ const {
+ showArrow,
+ children,
+ disabled,
+ portalled,
+ content,
+ contentProps,
+ portalRef,
+ ...rest
+ } = props
+
+ if (disabled) return children
+
+ return (
+
+ {children}
+
+
+
+ {showArrow && (
+
+
+
+ )}
+ {content}
+
+
+
+
+ )
+ },
+)
diff --git a/src/db/schema/Brand.ts b/src/db/schema/Brand.ts
new file mode 100644
index 0000000..3a60f60
--- /dev/null
+++ b/src/db/schema/Brand.ts
@@ -0,0 +1,9 @@
+import { pgTable, integer, varchar } from "drizzle-orm/pg-core";
+import { sql } from "drizzle-orm";
+import { timestamps } from "./helpers/columns.helpers";
+
+export const brand = pgTable("brands", {
+ id: integer().primaryKey().generatedAlwaysAsIdentity({ name: "brands_id_seq", startWith: 1, increment: 1, minValue: 1, maxValue: 2147483647, cache: 1 }),
+ name: varchar({length:100}).notNull(),
+ ...timestamps
+})
\ No newline at end of file
diff --git a/app/lib/client.ts b/src/lib/client.ts
similarity index 100%
rename from app/lib/client.ts
rename to src/lib/client.ts
diff --git a/app/lib/constants.ts b/src/lib/constants.ts
similarity index 72%
rename from app/lib/constants.ts
rename to src/lib/constants.ts
index 999a6d9..3aee3fa 100644
--- a/app/lib/constants.ts
+++ b/src/lib/constants.ts
@@ -1,15 +1,15 @@
-export const APP_NAME = "The Gun Bag - Gun Builder";
-export const COMPANY_NAME = "DarkShark Technologies, LLC";
+export const APP_NAME = "Ballistic Builder";
+export const COMPANY_NAME = "Forward Group, LLC";
export const COMPANY_URL = "https://goforward.group";
-export const AUTHOR = "DarkShark Technologies, LLC";
+export const AUTHOR = "Forward Group, LLC";
export const META_KEYWORDS = "Pew Pew";
export const META_DESCRIPTION = "Pow Pow";
export default {
- APP_NAME: 'The Gun Bag - Gun Builder',
- SITE_NAME: 'Gun Builder',
- COMPANY_NAME: 'DarkShark Technologies, LLC',
+ APP_NAME: 'Ballistic Builder',
+ SITE_NAME: 'Ballistic Builder',
+ COMPANY_NAME: 'Forward Group, LLC',
COMPANY_URL: 'https://goforward.group',
- AUTHOR: 'DarkShark Technologies, LLC',
+ AUTHOR: 'Forward Group,, LLC',
META_KEYWORDS: 'Pew Pew',
META_DESCRIPTION: 'Pow Pow',
PJAM_RAINIER: 'https://api.pepperjamnetwork.com/20120402/publisher/creative/product?apiKey=17c11367569cc10dce51e6a5900d0c7c8b390c9cb2d2cecc25b3ed53a3b8649b&format=json&programIds=8713',
diff --git a/app/lib/linkList/infoLinks.js b/src/lib/linkList/infoLinks.js
similarity index 100%
rename from app/lib/linkList/infoLinks.js
rename to src/lib/linkList/infoLinks.js
diff --git a/app/lib/linkList/sectionLinks.js b/src/lib/linkList/sectionLinks.js
similarity index 89%
rename from app/lib/linkList/sectionLinks.js
rename to src/lib/linkList/sectionLinks.js
index 1842770..e21f31e 100644
--- a/app/lib/linkList/sectionLinks.js
+++ b/src/lib/linkList/sectionLinks.js
@@ -51,13 +51,13 @@ export const sectionLinks = {
}
};
-export const armoryLinks = [
- {UPPERS: {
- URL: "/products/rifleuppers",
- TEXT: "Rifle Uppers",
- TIP: "Rifle Uppers"
+export const armoryLinks = new Array(
+ {"UPPERS": {
+ "URL": "/products/rifleuppers",
+ "TEXT": "Rifle Uppers",
+ "TIP": "Rifle Uppers"
}},
- {LOWERS: {
+ {"LOWERS": {
URL: "/products/lowers",
TEXT: "Lowers",
TIP: "Lowers"
@@ -81,6 +81,7 @@ export const armoryLinks = [
URL: "/products/accessories",
TEXT: "Accessories",
TIP: "Accessories"
- }}];
+ }}
+);
export default sectionLinks;
\ No newline at end of file
diff --git a/app/lib/script.ts b/src/lib/script.ts
similarity index 100%
rename from app/lib/script.ts
rename to src/lib/script.ts
diff --git a/pages/api/products.js b/src/pages/api/products.js
similarity index 100%
rename from pages/api/products.js
rename to src/pages/api/products.js
diff --git a/src/pages/builder.js b/src/pages/builder.js
new file mode 100644
index 0000000..b59a77e
--- /dev/null
+++ b/src/pages/builder.js
@@ -0,0 +1,87 @@
+import { useState, useEffect } from "react";
+
+export default function Builder() {
+ const [products, setProducts] = useState([]); // Available products from the API
+ const [build, setBuild] = useState([]); // User's selected parts
+ const [loading, setLoading] = useState(true);
+
+ // Fetch available products on page load
+ useEffect(() => {
+ async function fetchProducts() {
+ try {
+ const response = await fetch("/api/products"); // Replace with your actual API endpoint
+ const data = await response.json();
+ setProducts(data);
+ setLoading(false);
+ } catch (error) {
+ console.error("Error fetching products:", error);
+ setLoading(false);
+ }
+ }
+ fetchProducts();
+ }, []);
+
+ // Add a product to the build
+ const addToBuild = (product) => {
+ setBuild((prevBuild) => [...prevBuild, product]);
+ };
+
+ // Remove a product from the build
+ const removeFromBuild = (productId) => {
+ setBuild((prevBuild) => prevBuild.filter((item) => item.id !== productId));
+ };
+
+ return (
+
+
+
Build Your Firearm
+
+ {/* Available Products */}
+
+
Available Products
+ {loading ? (
+
Loading products...
+ ) : (
+
+ {products.map((product) => (
+
+
{product.name}
+
{product.description}
+
${product.price}
+
addToBuild(product)}
+ >
+ Add to Build
+
+
+ ))}
+
+ )}
+
+
+ {/* Current Build */}
+
+
Current Build
+ {build.length === 0 ? (
+
No parts added yet. Start building your firearm!
+ ) : (
+
+ {build.map((item) => (
+
+ {item.name}
+ removeFromBuild(item.id)}
+ >
+ Remove
+
+
+ ))}
+
+ )}
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/pages/oldindex.js b/src/pages/oldindex.js
similarity index 80%
rename from pages/oldindex.js
rename to src/pages/oldindex.js
index 8c443e7..3f88a2e 100644
--- a/pages/oldindex.js
+++ b/src/pages/oldindex.js
@@ -2,22 +2,21 @@ import Link from "next/link";
export default function Home() {
return (
-
+ (
{/* Header Section */}
-
{/* Hero Section */}
@@ -25,14 +24,15 @@ export default function Home() {
Customize every component of your firearm with ease and precision.
-
-
+
+
Get Started
-
+
-
{/* Features Section */}
@@ -59,7 +59,6 @@ export default function Home() {
-
{/* About Section */}
@@ -71,7 +70,6 @@ export default function Home() {
-
{/* Contact Section */}
-
{/* Footer Section */}
-
+ )
);
}
\ No newline at end of file
diff --git a/app/page.tsx b/src/pages/page-orig.tsx
similarity index 76%
rename from app/page.tsx
rename to src/pages/page-orig.tsx
index 8c443e7..fc9d5a8 100644
--- a/app/page.tsx
+++ b/src/pages/page-orig.tsx
@@ -2,22 +2,21 @@ import Link from "next/link";
export default function Home() {
return (
-